comp.lang.ada
 help / color / mirror / Atom feed
From: Georg Bauhaus <rm.dash-bauhaus@futureapps.de>
Subject: Re: Representation clauses for base-64 encoding
Date: Thu, 22 Dec 2011 23:18:56 +0100
Date: 2011-12-22T23:18:56+01:00	[thread overview]
Message-ID: <4ef3acd0$0$6642$9b4e6d93@newsspool2.arcor-online.net> (raw)
In-Reply-To: <slrnjf6kup.1lme.lithiumcat@sigil.instinctive.eu>

On 22.12.11 17:00, Natasha Kerensikova wrote:

> However here representation is not used as a notion, only as a tool:
> using explicit shifts and masks, it is possible to write portable Ada
> that performs the correct split of 3 octets on any platform.
>
> The previous argument was that representation clauses allow more
> readable code, which I'm inclined to believe. But is it really necessary
> to give up portability for the sake of readability?

There is middle ground, I think, insofar as it is possible
to extract bits in Ada without thinking about shifts and masks,
or logical operations.

Given a stream chopped into octets, the goal is to extract slices
of 6 consecutive bits and represent these using the characters
from a Base 64 encoding table. Leave the how-to of extraction to
the compiler, just say which bits. This does not use representation
clauses for extraction, and not shifts or mask either.  Without claiming
originality, completeness, enough subtypes, portability of bit indexing
of bits in a single octet, or sufficient code quality, the following might
illustrate the convenience of arrays of packed Booleans (guaranteed by
the LRM to have desirable properties):


package B64 is
    --
    --  prints characters representing sequences of octets in
    --  base 64 encoding. The octets come in via `Add`.
    --
    pragma Elaborate_Body(B64);

    type Repertoire is (    'A',   'B',   'C',   'D',   'E',   'F',   'G',
       'H',   'I',   'J',   'K',   'L',   'M',   'N',   'O',   'P',   'Q',
       'R',   'S',   'T',   'U',   'V',   'W',   'X',   'Y',   'Z',   'a',
       'b',   'c',   'd',   'e',   'f',   'g',   'h',   'i',   'j',   'k',
       'l',   'm',   'n',   'o',   'p',   'q',   'r',   's',   't',   'u',
       'v',   'w',   'x',   'y',   'z',   '0',   '1',   '2',   '3',   '4',
       '5',   '6',   '7',   '8',   '9',   '+',   '/' );
    for Repertoire'Size use 6;

    Pad : constant Character := '=';

    subtype Bit_Index is Natural range 0..23;

    type Bit_String is array(Bit_Index range <>) of Boolean;
    pragma Pack(Bit_String);

    subtype Octet is Bit_String(Bit_Index range 0..7);

    procedure Add(Bits : Octet);
                    -- Take 6 bits and write a corresponding Base 64 character.
                    -- Uses bits from this `Bits`, and bits from last time `Add`
                    -- was called; saves bits for later use.


    procedure Finish;
                                  -- handle any left over bits and finish output


end B64;

with Ada.Text_IO;
with Ada.Unchecked_Conversion;

package body B64 is
    
    subtype Base_64_Digit is Bit_String(Bit_Index range 0..5);
    subtype Word is Bit_String(Bit_Index range 0..15);
    function To_B64 is new Ada.Unchecked_Conversion(
          Base_64_Digit, Repertoire);

    procedure Write_64(C : Repertoire) is
       Position : Natural;
    begin
       case C is
          when 'A'..'Z' =>
             Position := Character'Pos('A') + Repertoire'Pos(C);
          when 'a'..'z' =>
             Position := Character'Pos('a')
             + (Repertoire'Pos(C) - Repertoire'Pos('a'));
          when '0'..'9' =>
             Position := Character'Pos('0')
             + (Repertoire'Pos(C) - Repertoire'Pos('0'));
          when '+' =>
             Position := Character'Pos('+');
          when '/' =>
             Position := Character'Pos('/');
       end case;

       Ada.Text_IO.Put(Character'Val(Position));
    end Write_64;


    --
    --  state information
    --


    type Selection is mod 4;
                        -- one of the four groups of 6 bits in a full bit string


    Scratch           : Word := (others => False);
                                 -- buffer storing left over bits for future use

    Position_In_Group : Selection := Selection'First;

    procedure Add(Bits : Octet) is
       Six_Pack : Base_64_Digit;
                                        -- six bits ready to be processed
    begin
       case Position_In_Group is
          when 0 =>
             Six_Pack := Base_64_Digit(Bits(2..7));
             Write_64(To_B64(Six_Pack));
             Scratch(8..15) := Bits;
             Position_In_Group := Selection'Succ(Position_In_Group);

          when 1 =>
             Scratch(4..7) := Bits(4..7);
             Six_Pack := Base_64_Digit(Scratch(4..9));
             Write_64(To_B64(Six_Pack));
             Scratch(8..15) := Bits;
             Position_In_Group := Selection'Succ(Position_In_Group);

          when 2 =>
                                  -- 4 bits left in `Scratch` plus 8 from `Bits`
                                  -- is worth two output characters

             Scratch(6..7) := Bits(6..7);
             Six_Pack := Base_64_Digit(Scratch(6..11));
             Write_64(To_B64(Six_Pack));
             Position_In_Group := Selection'Succ(Position_In_Group);
             Six_Pack := Base_64_Digit(Bits(0..5));
             Write_64(To_B64(Six_Pack));
             Scratch(8..15) := (others => False);
             Position_In_Group := Selection'Succ(Position_In_Group);

          when 3 =>
                                   -- this won't happen, see comment on case `2`
             raise Program_Error;

       end case;
    end Add;

    procedure Finish is
    begin
       Ada.Text_IO.Put("NOT DONE");
       Ada.Text_IO.Flush;
    end Finish;


end B64;



  reply	other threads:[~2011-12-22 22:18 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-12-22  9:41 Representation clauses for base-64 encoding Natasha Kerensikova
2011-12-22 11:20 ` Niklas Holsti
2011-12-23  1:30   ` Randy Brukardt
2011-12-26  8:33     ` Niklas Holsti
2011-12-28  0:09       ` Randy Brukardt
2011-12-22 11:37 ` Georg Bauhaus
2011-12-22 12:24   ` Niklas Holsti
2011-12-22 15:09     ` Georg Bauhaus
2011-12-22 16:00       ` Natasha Kerensikova
2011-12-22 22:18         ` Georg Bauhaus [this message]
2011-12-25 10:17           ` Niklas Holsti
2011-12-27 11:23             ` Georg Bauhaus
2011-12-27 19:37               ` Niklas Holsti
2011-12-27 20:49                 ` Robert A Duff
2011-12-27 23:47                   ` Niklas Holsti
2011-12-29  0:50                     ` Robert A Duff
2011-12-30 20:54                       ` anon
2011-12-30 20:56                       ` Niklas Holsti
2011-12-23  1:42     ` Randy Brukardt
2011-12-28  8:59       ` Niklas Holsti
2011-12-29  5:41         ` Randy Brukardt
2011-12-29 10:10           ` Dmitry A. Kazakov
2011-12-23  1:33 ` Randy Brukardt
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox