From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: *** X-Spam-Status: No, score=3.3 required=5.0 tests=BAYES_00,FILL_THIS_FORM_LOAN, FORGED_MUA_MOZILLA autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: 103376,d778a4f52acd9d43 X-Google-NewGroupId: yes X-Google-Attributes: gida07f3367d7,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Received: by 10.204.156.205 with SMTP id y13mr525307bkw.3.1324592337862; Thu, 22 Dec 2011 14:18:57 -0800 (PST) Path: jh9ni42310bkb.0!nntp.google.com!news2.google.com!goblin2!goblin.stu.neva.ru!news.internetdienste.de!noris.net!newsfeed.arcor.de!newsspool3.arcor-online.net!news.arcor.de.POSTED!not-for-mail Date: Thu, 22 Dec 2011 23:18:56 +0100 From: Georg Bauhaus User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:8.0) Gecko/20111105 Thunderbird/8.0 MIME-Version: 1.0 Newsgroups: comp.lang.ada Subject: Re: Representation clauses for base-64 encoding References: <4ef31672$0$6574$9b4e6d93@newsspool3.arcor-online.net> <9lgls6FticU1@mid.individual.net> <4ef34839$0$7623$9b4e6d93@newsspool1.arcor-online.net> In-Reply-To: Message-ID: <4ef3acd0$0$6642$9b4e6d93@newsspool2.arcor-online.net> Organization: Arcor NNTP-Posting-Date: 22 Dec 2011 23:18:56 CET NNTP-Posting-Host: a8338a5b.newsspool2.arcor-online.net X-Trace: DXC=33L4DcWLfY>U`5g[@c]@J1A9EHlD;3Yc24Fo<]lROoR18kFejV8F35^f:j1li4kg1JjNQ@G3= X-Complaints-To: usenet-abuse@arcor.de Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Date: 2011-12-22T23:18:56+01:00 List-Id: 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;