* Base64-Encoding @ 2007-10-15 14:12 Stefan Bellon 2007-10-15 14:46 ` Base64-Encoding Jacob Sparre Andersen ` (2 more replies) 0 siblings, 3 replies; 17+ messages in thread From: Stefan Bellon @ 2007-10-15 14:12 UTC (permalink / raw) Hi all, I've been looking through the previous postings of the group and found two major threads where this topic has already been discussed. But the proposed solutions were all different to what I was thinking about. I have thought about the following: package body Base64 is type Six_Bits is mod 2**6; for Six_Bits'Size use 6; type Six_Bits_Array is array (Natural range <>) of Six_Bits; for Six_Bits_Array'Alignment use 1; -- To overlay over String type. for Six_Bits_Array'Component_Size use Six_Bits'Size; pragma Pack (Six_Bits_Array); Base64_Chars : constant array (Six_Bits) of Character := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; function Encode (Data : in String) return String is Padded_Length : constant Natural := ((Data'Length + 2) / 3) * 3; -- Pad input data to 3-Byte boundary. Base64_Length : constant Natural := Padded_Length / 3 * 4; -- Number of six-bit tokens necessary (including padding). Six_Bits_Length : constant Natural := (Data'Length * 4 + 2) / 3; -- Number of six-bit tokens necessary (without padding). Padded_Data : String (1 .. Padded_Length) := (others => ASCII.NUL); -- Padded input data. Base64_Data : Six_Bits_Array (1 .. Base64_Length); for Base64_Data'Address use Padded_Data'Address; -- Overlay array of six-bit tokens over the padded input data. Result : String (1 .. Base64_Length) := (others => '='); -- Output buffer, initialized with '=' tokens for unfilled -- end-markers. begin Padded_Data (1 .. Data'Length) := Data; -- Initialize data into padded-data (can't be done with aggregate -- in elaboration part, sadly). -- Do the actual encoding ... for I in 1 .. Six_Bits_Length loop Result (I) := Base64_Chars (Base64_Data (I)); end loop; return Result; end Encode; end Base64; However it looks like this solution has a problem with endianness, in a way that the wrong 6 bits of the Bytes are used in the conversion. Is there an easy way to fix this (as I think the rest would be pretty neat) or is this way of trying to do it, doomed to fail anyway? -- Stefan Bellon ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 14:12 Base64-Encoding Stefan Bellon @ 2007-10-15 14:46 ` Jacob Sparre Andersen 2007-10-15 14:54 ` Base64-Encoding Stefan Bellon 2007-10-15 18:24 ` Base64-Encoding Adam Beneschan 2007-10-19 2:43 ` Base64-Encoding anon 2 siblings, 1 reply; 17+ messages in thread From: Jacob Sparre Andersen @ 2007-10-15 14:46 UTC (permalink / raw) Stefan Bellon wrote: > Padded_Data : String (1 .. Padded_Length) := (others => ASCII.NUL); > -- Padded input data. [...] > begin > Padded_Data (1 .. Data'Length) := Data; > -- Initialize data into padded-data (can't be done with aggregate > -- in elaboration part, sadly). Why? I may have missed something obvious, but I would have thought that Padded_Data : String (1 .. Padded_Length) := Data & (others => ASCII.NUL); would work fine. > However it looks like this solution has a problem with endianness, > in a way that the wrong 6 bits of the Bytes are used in the > conversion. :-( > Is there an easy way to fix this (as I think the rest would be > pretty neat) or is this way of trying to do it, doomed to fail > anyway? Is it a problem that section 13.5.3 (Bit Ordering) can handle? Greetings, Jacob -- �When in Rome; burn it� -- Diziet Sma ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 14:46 ` Base64-Encoding Jacob Sparre Andersen @ 2007-10-15 14:54 ` Stefan Bellon 2007-10-15 15:14 ` Base64-Encoding Jacob Sparre Andersen 2007-10-15 15:40 ` Base64-Encoding Jean-Pierre Rosen 0 siblings, 2 replies; 17+ messages in thread From: Stefan Bellon @ 2007-10-15 14:54 UTC (permalink / raw) On Mon, 15 Oct, Jacob Sparre Andersen wrote: > Stefan Bellon wrote: > > > Padded_Data : String (1 .. Padded_Length) := (others => > > ASCII.NUL); -- Padded input data. > [...] > > begin > > Padded_Data (1 .. Data'Length) := Data; > > -- Initialize data into padded-data (can't be done with > > aggregate -- in elaboration part, sadly). > > Why? I may have missed something obvious, but I would have thought > that > > Padded_Data : String (1 .. Padded_Length) := Data & (others => > ASCII.NUL); > > would work fine. This results in: error: "others" choice not allowed here > > However it looks like this solution has a problem with endianness, > > in a way that the wrong 6 bits of the Bytes are used in the > > conversion. > > :-( > > > Is there an easy way to fix this (as I think the rest would be > > pretty neat) or is this way of trying to do it, doomed to fail > > anyway? > > Is it a problem that section 13.5.3 (Bit Ordering) can handle? I hoped for this as well, but it looks like the attribute Bit_Order is only defined for record types. This is what 13.5.3 says and indeed GNAT refuses to accept a 'Bit_Order on Six_Bits or the array thereof. -- Stefan Bellon ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 14:54 ` Base64-Encoding Stefan Bellon @ 2007-10-15 15:14 ` Jacob Sparre Andersen 2007-10-15 15:37 ` Base64-Encoding Robert A Duff 2007-10-15 15:40 ` Base64-Encoding Jean-Pierre Rosen 1 sibling, 1 reply; 17+ messages in thread From: Jacob Sparre Andersen @ 2007-10-15 15:14 UTC (permalink / raw) Stefan Bellon wrote: > On Mon, 15 Oct, Jacob Sparre Andersen wrote: >> Padded_Data : String (1 .. Padded_Length) := Data & (others => >> ASCII.NUL); >> >> would work fine. > > This results in: > > error: "others" choice not allowed here I can't figure out why, but here's something which does work: Padded_Data : String (1 .. Padded_Length) := Data & (Data'Length + 1 .. Padded_Length => ASCII.NUL); > I hoped for this as well, but it looks like the attribute Bit_Order is > only defined for record types. This is what 13.5.3 says and indeed GNAT > refuses to accept a 'Bit_Order on Six_Bits or the array thereof. Doesn't that simply mean that you have to make "Base64_Data" an array of Base64_Block, where Base64_Block is declared like this: type Base64_Block is record A, B, C, D : Six_Bits; end record; This way you will be allowed bit ordering on the Base64_Block, which hopefully will solve your problem. Greetings, Jacob -- Adlai Stevenson said it all when, at an event during the 1956 Presidential campaign, a woman shouted, "You have the vote of every thinking person!" Stevenson shouted back, "That's not enough, madam, we need a majority!" ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 15:14 ` Base64-Encoding Jacob Sparre Andersen @ 2007-10-15 15:37 ` Robert A Duff 0 siblings, 0 replies; 17+ messages in thread From: Robert A Duff @ 2007-10-15 15:37 UTC (permalink / raw) Jacob Sparre Andersen <sparre@nbi.dk> writes: > Stefan Bellon wrote: >> On Mon, 15 Oct, Jacob Sparre Andersen wrote: > >>> Padded_Data : String (1 .. Padded_Length) := Data & (others => >>> ASCII.NUL); >>> >>> would work fine. >> >> This results in: >> >> error: "others" choice not allowed here > > I can't figure out why, ... Because Ada allows "others" only when the context determines the bounds of the array: X : String (1..10) := (others => '*'); -- OK, bounds of others come from X Y : String := (1..10 => '*'); -- OK, bounds of Y come from aggregate Z : String := (others => '*'); -- Illegal (what is Z'Length?) The right-hand parameter of the "&" function is of subtype String, which is unconstrained, so you can't pass an others-aggregate to it. I suppose the language COULD have been defined to allow it, by special-casing the predefined "&". Allow one (but not both) parameters of "&" to have others, but only if the "&" operator appears in an appropriate context: A : String := "Hello"; function F(X : Integer) return String; B : String (1..100) := A & (others => '*') & F(123); -- Illegal. Requiring the generated code to calculate the bounds of others as B'First + A'Length .. B'Last - <result-of-F>'Length. Yuck -- that works for "&", but not for user-defined functions. Sounds like a complicated rule, for little benefit, since as you point out, it's not that hard to calculate the bounds explicitly: >... but here's something which does work: > > Padded_Data : String (1 .. Padded_Length) := > Data & (Data'Length + 1 .. Padded_Length => ASCII.NUL); - Bob ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 14:54 ` Base64-Encoding Stefan Bellon 2007-10-15 15:14 ` Base64-Encoding Jacob Sparre Andersen @ 2007-10-15 15:40 ` Jean-Pierre Rosen 2007-10-15 16:39 ` Base64-Encoding Stefan Bellon 1 sibling, 1 reply; 17+ messages in thread From: Jean-Pierre Rosen @ 2007-10-15 15:40 UTC (permalink / raw) Stefan Bellon a �crit : > On Mon, 15 Oct, Jacob Sparre Andersen wrote: > >> Stefan Bellon wrote: >> >>> Padded_Data : String (1 .. Padded_Length) := (others => >>> ASCII.NUL); -- Padded input data. >> [...] >>> begin >>> Padded_Data (1 .. Data'Length) := Data; >>> -- Initialize data into padded-data (can't be done with >>> aggregate -- in elaboration part, sadly). >> Why? I may have missed something obvious, but I would have thought >> that >> >> Padded_Data : String (1 .. Padded_Length) := Data & (others => >> ASCII.NUL); >> >> would work fine. > > This results in: > > error: "others" choice not allowed here How many elements are covered byt "others" cannot be determined in this context, but this should work: Padded_Data : String (1 .. Padded_Length) := Data & (Data'Length+1 .. Padded_Length => ASCII.NUL); > I hoped for this as well, but it looks like the attribute Bit_Order is > only defined for record types. This is what 13.5.3 says and indeed GNAT > refuses to accept a 'Bit_Order on Six_Bits or the array thereof. Bit_Order is about bit numbering, it has nothing to do with endianness -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 15:40 ` Base64-Encoding Jean-Pierre Rosen @ 2007-10-15 16:39 ` Stefan Bellon 2007-10-16 10:42 ` Base64-Encoding Stephen Leake 0 siblings, 1 reply; 17+ messages in thread From: Stefan Bellon @ 2007-10-15 16:39 UTC (permalink / raw) On Mon, 15 Oct, Jean-Pierre Rosen wrote: > Stefan Bellon a écrit : > > I hoped for this as well, but it looks like the attribute Bit_Order > > is only defined for record types. This is what 13.5.3 says and > > indeed GNAT refuses to accept a 'Bit_Order on Six_Bits or the array > > thereof. > > Bit_Order is about bit numbering, it has nothing to do with endianness Ok, bad wording on my part. Let my try to explain what I mean. The German Wikipedia page for Base64 has a nice coloured illustration: http://de.wikipedia.org/wiki/Base64 My basic idea is to define an array of Six_Bits and "overlay" this at the same address as the String with the usual 8-bit Character encoding. Then iterate over the Six_Bits' array and use the values (which are mod 2**6) to index the Base64_Chars array and build the result buffer. However, when the 1st Byte contains the value Character'Pos('0') = 48, I hoped that the first Six_Bits element in the array contained the first 6 bits and thus has a value of 48 / 4 = 12. But this is not the case. It has the value 48 as well. In the case of Character'Pos('A') = 65, the usual bit value is 2#01000001#, so I had assumed the first Six_Bits element had the value 16 and the second Six_Bits element had the value 16 as well (assuming 0-padding). Data(1) __65__ / \ 010000010000... 010000010000 \____/\____/ 16 16 B64(1) B64(2) But in fact, both Six_Bits elements have the value 1. The fact, that I get 1 in both cases, leads me to the conclusion, that the Six_Bits_Array overlays differently: Data(1) __65__ / \ ...000001000001 000001000001 \____/\____/ 1 1 B64(2) B64(1) When I test this now with two consecutive bytes, I had expected to get: Data(1) Data(2) _129__ _126__ / \/ \ 100000010111111000... \____/\____/\____/ 32 23 56 B64(1) B64(2) B64(3) But what I am seeing is this: B64(1..3) = (1, 58, 7) = (2#000001#, 2#111010#, 2#000111#) But this only makes sense, if the bits are in complete reverse order: 7 58 1 000111 111010 000001 Therefore I assume that when overlaying the array of 6-bit elements over an array of 8-bit elements, I have to specify some kind of bit ordering, which however is not possible with 'Bit_Order. What am I missing here? -- Stefan Bellon ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 16:39 ` Base64-Encoding Stefan Bellon @ 2007-10-16 10:42 ` Stephen Leake 2007-10-17 14:07 ` Base64-Encoding Stefan Bellon 0 siblings, 1 reply; 17+ messages in thread From: Stephen Leake @ 2007-10-16 10:42 UTC (permalink / raw) Stefan Bellon <sbellon@sbellon.de> writes: > Ok, bad wording on my part. Let my try to explain what I mean. > > The German Wikipedia page for Base64 has a nice coloured illustration: > http://de.wikipedia.org/wiki/Base64 In English: http://en.wikipedia.org/wiki/Base64 Not quite the same illustration, but the same idea. > My basic idea is to define an array of Six_Bits and "overlay" this at > the same address as the String with the usual 8-bit Character encoding. I think Adam is correct that this is non-portable. The GNAT Ada compiler has special code for each case of packed arrays. For Six_Bits_Array, see the package System.Pack_06 (in file s-pack06.adb). It defines: for Cluster use record E0 at 0 range 0 * Bits .. 0 * Bits + Bits - 1; E1 at 0 range 1 * Bits .. 1 * Bits + Bits - 1; E2 at 0 range 2 * Bits .. 2 * Bits + Bits - 1; E3 at 0 range 3 * Bits .. 3 * Bits + Bits - 1; E4 at 0 range 4 * Bits .. 4 * Bits + Bits - 1; E5 at 0 range 5 * Bits .. 5 * Bits + Bits - 1; E6 at 0 range 6 * Bits .. 6 * Bits + Bits - 1; E7 at 0 range 7 * Bits .. 7 * Bits + Bits - 1; end record; where Bits is 6. There is no Bit_Order pragma on this, so it is in native bit order; apparently little-endian in your case (x86). So Base64_Data (0) has bits 0 .. 5 of Data (0), Base64_Data (1) has bits 6, 7 of Data (0) and bits 0 .. 3 of Data (1), etc. In effect, the bytes in Data are reversed in groups of 6. Not easy to draw :(. AdaCore does not implement Bit_Order for machine sizes greater than 1 (last I checked; a couple years ago). If they did, and applied bit_order to this record, it would be endian-independent, and work the way you expect. It would also break any current code, so they probably never will. But you could at least code it yourself in a cleaner endian-independent way. So ask them to! -- -- Stephe ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-16 10:42 ` Base64-Encoding Stephen Leake @ 2007-10-17 14:07 ` Stefan Bellon 2007-10-17 15:09 ` Base64-Encoding Adam Beneschan 0 siblings, 1 reply; 17+ messages in thread From: Stefan Bellon @ 2007-10-17 14:07 UTC (permalink / raw) On Tue, 16 Oct, Stephen Leake wrote: > Stefan Bellon <sbellon@sbellon.de> writes: > > My basic idea is to define an array of Six_Bits and "overlay" this > > at the same address as the String with the usual 8-bit Character > > encoding. > > I think Adam is correct that this is non-portable. Thanks a lot to you (and Adam as well!) for your detailed and very informative replies. > AdaCore does not implement Bit_Order for machine sizes greater than 1 > (last I checked; a couple years ago). If they did, and applied > bit_order to this record, it would be endian-independent, and work the > way you expect. Yes, I am not forced to exactly do it this way. In fact, there have been discussions in this group explaining how to do it in several other ways. I was just wondering because my idea initially looked like such an elegant way. ;-) -- Stefan Bellon ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-17 14:07 ` Base64-Encoding Stefan Bellon @ 2007-10-17 15:09 ` Adam Beneschan 2007-10-17 18:15 ` Base64-Encoding Larry Kilgallen 0 siblings, 1 reply; 17+ messages in thread From: Adam Beneschan @ 2007-10-17 15:09 UTC (permalink / raw) On Oct 17, 7:07 am, Stefan Bellon <sbel...@sbellon.de> wrote: > Yes, I am not forced to exactly do it this way. In fact, there have > been discussions in this group explaining how to do it in several other > ways. I was just wondering because my idea initially looked like such an > elegant way. ;-) It does seem like it would have been nice, and maybe it could be argued that some sort of standard representation clause or pragma should be added to give more control over how packed array elements are stored. The problem is that it would have to work not only for big- and little-endian machines, but also on machines that are not byte-addressable---there are still a few of those around. -- Adam ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-17 15:09 ` Base64-Encoding Adam Beneschan @ 2007-10-17 18:15 ` Larry Kilgallen 0 siblings, 0 replies; 17+ messages in thread From: Larry Kilgallen @ 2007-10-17 18:15 UTC (permalink / raw) In article <1192633784.534337.221490@e34g2000pro.googlegroups.com>, Adam Beneschan <adam@irvine.com> writes: > On Oct 17, 7:07 am, Stefan Bellon <sbel...@sbellon.de> wrote: > >> Yes, I am not forced to exactly do it this way. In fact, there have >> been discussions in this group explaining how to do it in several other >> ways. I was just wondering because my idea initially looked like such an >> elegant way. ;-) > > It does seem like it would have been nice, and maybe it could be > argued that some sort of standard representation clause or pragma > should be added to give more control over how packed array elements > are stored. The problem is that it would have to work not only for > big- and little-endian machines, but also on machines that are not > byte-addressable---there are still a few of those around. The value of a standardized pragma to solve a problem that is specific to particular architectures is questionable. In fact, it might be a bad idea to have a standardized pragma since those porting to another architecture might presume that no changes were required. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 14:12 Base64-Encoding Stefan Bellon 2007-10-15 14:46 ` Base64-Encoding Jacob Sparre Andersen @ 2007-10-15 18:24 ` Adam Beneschan 2007-10-19 2:43 ` Base64-Encoding anon 2 siblings, 0 replies; 17+ messages in thread From: Adam Beneschan @ 2007-10-15 18:24 UTC (permalink / raw) On Oct 15, 7:12 am, Stefan Bellon <sbel...@sbellon.de> wrote: > Hi all, > > I've been looking through the previous postings of the group and found > two major threads where this topic has already been discussed. But the > proposed solutions were all different to what I was thinking about. I > have thought about the following: > > package body Base64 is > > type Six_Bits is mod 2**6; > for Six_Bits'Size use 6; > > type Six_Bits_Array is array (Natural range <>) of Six_Bits; > for Six_Bits_Array'Alignment use 1; -- To overlay over String type. > for Six_Bits_Array'Component_Size use Six_Bits'Size; > pragma Pack (Six_Bits_Array); > > Base64_Chars : constant array (Six_Bits) of Character := > "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; > > function Encode > (Data : in String) > return String > is > Padded_Length : constant Natural := ((Data'Length + 2) / 3) * 3; > -- Pad input data to 3-Byte boundary. > > Base64_Length : constant Natural := Padded_Length / 3 * 4; > -- Number of six-bit tokens necessary (including padding). > > Six_Bits_Length : constant Natural := (Data'Length * 4 + 2) / 3; > -- Number of six-bit tokens necessary (without padding). > > Padded_Data : String (1 .. Padded_Length) := (others => ASCII.NUL); > -- Padded input data. > > Base64_Data : Six_Bits_Array (1 .. Base64_Length); > for Base64_Data'Address use Padded_Data'Address; > -- Overlay array of six-bit tokens over the padded input data. > > Result : String (1 .. Base64_Length) := (others => '='); > -- Output buffer, initialized with '=' tokens for unfilled > -- end-markers. > begin > Padded_Data (1 .. Data'Length) := Data; > -- Initialize data into padded-data (can't be done with aggregate > -- in elaboration part, sadly). > > -- Do the actual encoding ... > for I in 1 .. Six_Bits_Length loop > Result (I) := Base64_Chars (Base64_Data (I)); > end loop; > > return Result; > end Encode; > > end Base64; > > However it looks like this solution has a problem with endianness, in a > way that the wrong 6 bits of the Bytes are used in the conversion. > > Is there an easy way to fix this (as I think the rest would be pretty > neat) or is this way of trying to do it, doomed to fail anyway? I vote for "doomed"---if your intent is to write portable code. The problem is that Ada doesn't give you enough control over the representation of an array to solve the problem the way you'd like to. You're hoping for a representation of an array of 6-bit integers, such that the first array element is contained in the upper 6 bits of the first byte, the second array element is such that the two high bits of the element are the lower 2 bits of the first byte and the remaning four bits are the lower 4 bits of the second byte, etc. I don't think there's a way in Ada to specify an array representation that precisely. From what I can tell, if it's more convenient for an implementation to store the first element in the low-order bits of the *third* byte (let's say it can load three bytes as an integer containing four array elements and then perform register shift instructions to get the desired element), it is free to do so and there's no Ada-defined pragma or representation clause to prevent it from doing so. If it were me, I'd just do the shifting and masking operations myself. You may be able to get somewhere by defining a record containing four 6-bit integers and taking up three bytes, and using a record representation clause to specify the exact locations of those four integers. You'd probably even be able to do this in a way that's endianness-independent---I haven't tried it. Of course, you'd have to perform your operation on the four components of those records separately; you can't put them into an array. -- Adam ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-15 14:12 Base64-Encoding Stefan Bellon 2007-10-15 14:46 ` Base64-Encoding Jacob Sparre Andersen 2007-10-15 18:24 ` Base64-Encoding Adam Beneschan @ 2007-10-19 2:43 ` anon 2007-10-19 4:33 ` Base64-Encoding anon 2007-10-19 6:59 ` Base64-Encoding Stefan Bellon 2 siblings, 2 replies; 17+ messages in thread From: anon @ 2007-10-19 2:43 UTC (permalink / raw) with Interfaces ; use Interfaces ; with System ; use System ; with Ada.Unchecked_Conversion ; package b64 is -- -- Uses the system default on endian -- type Six_Bits is new Integer range mod 2**6 ; -- or use 0 .. 63 ; -- -- base64_descriptor is a record that insures the endian is set -- by the program ( in this case "little-endian format" ) in -- architectures that have switchable endianness. -- Such as ARM, PowerPC (but not the PPC970/G5), DEC Alpha, SPARC V9, -- MIPS, PA-RISC and IA64 -- type base64_descriptor is record Unused : Unsigned_8 range 0..3 ; Bit_5 : Unsigned_8 range 0..1 ; Bit_4 : Unsigned_8 range 0..1 ; Bit_3 : Unsigned_8 range 0..1 ; Bit_2 : Unsigned_8 range 0..1 ; Bit_1 : Unsigned_8 range 0..1 ; Bit_0 : Unsigned_8 range 0..1 ; end record ; -- -- set bit order -- for base64_descriptor use record Unused at 0 range 6..7 ; Bit_5 at 0 range 5..5 ; Bit_4 at 0 range 4..4 ; Bit_3 at 0 range 3..3 ; Bit_2 at 0 range 2..2 ; Bit_1 at 0 range 1..1 ; Bit_0 at 0 range 0..0 ; end record ; -- -- or you could use the following statement which -- forces endian to little-endian format -- for base64_descriptor'Bit_Order use Low_Order_First ; -- -- insure 1 byte usage for base64_descriptor ; -- pragma pack ( base64_descriptor ) ; function To_Base64 is new Ada.Unchecked_Conversion ( Source => Unsigned_8, Target => base64_descriptor ) ; function From_Base64 is new Ada.Unchecked_Conversion ( Target => Unsigned_8, Source => base64_descriptor ) ; end ; In 2001 Tom Moran created a Ada BASE64 package which is archived at http://www.adapower.com/index.php?Command=Class&ClassID=Algorithms&CID=257 have a look at it. I a quick look it kind of suggest that the endian for Six_Bits is not important. In <20071015161229.3f439230@cube.tz.axivion.com>, Stefan Bellon <sbellon@sbellon.de> writes: >Hi all, > >I've been looking through the previous postings of the group and found >two major threads where this topic has already been discussed. But the >proposed solutions were all different to what I was thinking about. I >have thought about the following: > > >package body Base64 is > > type Six_Bits is mod 2**6; > for Six_Bits'Size use 6; > > type Six_Bits_Array is array (Natural range <>) of Six_Bits; > for Six_Bits_Array'Alignment use 1; -- To overlay over String type. > for Six_Bits_Array'Component_Size use Six_Bits'Size; > pragma Pack (Six_Bits_Array); > > Base64_Chars : constant array (Six_Bits) of Character := > "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; > > function Encode > (Data : in String) > return String > is > Padded_Length : constant Natural := ((Data'Length + 2) / 3) * 3; > -- Pad input data to 3-Byte boundary. > > Base64_Length : constant Natural := Padded_Length / 3 * 4; > -- Number of six-bit tokens necessary (including padding). > > Six_Bits_Length : constant Natural := (Data'Length * 4 + 2) / 3; > -- Number of six-bit tokens necessary (without padding). > > Padded_Data : String (1 .. Padded_Length) := (others => ASCII.NUL); > -- Padded input data. > > Base64_Data : Six_Bits_Array (1 .. Base64_Length); > for Base64_Data'Address use Padded_Data'Address; > -- Overlay array of six-bit tokens over the padded input data. > > Result : String (1 .. Base64_Length) := (others => '='); > -- Output buffer, initialized with '=' tokens for unfilled > -- end-markers. > begin > Padded_Data (1 .. Data'Length) := Data; > -- Initialize data into padded-data (can't be done with aggregate > -- in elaboration part, sadly). > > -- Do the actual encoding ... > for I in 1 .. Six_Bits_Length loop > Result (I) := Base64_Chars (Base64_Data (I)); > end loop; > > return Result; > end Encode; > >end Base64; > > >However it looks like this solution has a problem with endianness, in a >way that the wrong 6 bits of the Bytes are used in the conversion. > >Is there an easy way to fix this (as I think the rest would be pretty >neat) or is this way of trying to do it, doomed to fail anyway? > >-- >Stefan Bellon ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-19 2:43 ` Base64-Encoding anon @ 2007-10-19 4:33 ` anon 2007-10-19 7:35 ` Base64-Encoding Jean-Pierre Rosen 2007-10-19 6:59 ` Base64-Encoding Stefan Bellon 1 sibling, 1 reply; 17+ messages in thread From: anon @ 2007-10-19 4:33 UTC (permalink / raw) that should say type Six_Bits is new Integer mod 2**6 ; -- or use range 0 .. 63 ; In <eRURi.236438$ax1.167125@bgtnsc05-news.ops.worldnet.att.net>, anon@anon.org (anon) writes: >with Interfaces ; >use Interfaces ; >with System ; >use System ; >with Ada.Unchecked_Conversion ; > >package b64 is > > -- > -- Uses the system default on endian > -- > > type Six_Bits is new Integer range mod 2**6 ; -- or use 0 .. 63 ; > > > -- > -- base64_descriptor is a record that insures the endian is set > -- by the program ( in this case "little-endian format" ) in > -- architectures that have switchable endianness. > -- Such as ARM, PowerPC (but not the PPC970/G5), DEC Alpha, SPARC V9, > -- MIPS, PA-RISC and IA64 > -- > type base64_descriptor is record > Unused : Unsigned_8 range 0..3 ; > Bit_5 : Unsigned_8 range 0..1 ; > Bit_4 : Unsigned_8 range 0..1 ; > Bit_3 : Unsigned_8 range 0..1 ; > Bit_2 : Unsigned_8 range 0..1 ; > Bit_1 : Unsigned_8 range 0..1 ; > Bit_0 : Unsigned_8 range 0..1 ; > end record ; > -- > -- set bit order > -- > for base64_descriptor use record > Unused at 0 range 6..7 ; > Bit_5 at 0 range 5..5 ; > Bit_4 at 0 range 4..4 ; > Bit_3 at 0 range 3..3 ; > Bit_2 at 0 range 2..2 ; > Bit_1 at 0 range 1..1 ; > Bit_0 at 0 range 0..0 ; > end record ; > > -- > -- or you could use the following statement which > -- forces endian to little-endian format > -- > for base64_descriptor'Bit_Order use Low_Order_First ; > > -- > -- insure 1 byte usage for base64_descriptor ; > -- > pragma pack ( base64_descriptor ) ; > > > > function To_Base64 is new Ada.Unchecked_Conversion > ( Source => Unsigned_8, > Target => base64_descriptor ) ; > > function From_Base64 is new Ada.Unchecked_Conversion > ( Target => Unsigned_8, > Source => base64_descriptor ) ; > > >end ; > >In 2001 Tom Moran created a Ada BASE64 package which is archived at > >http://www.adapower.com/index.php?Command=Class&ClassID=Algorithms&CID=257 > >have a look at it. I a quick look it kind of suggest that the endian for >Six_Bits is not important. > > >In <20071015161229.3f439230@cube.tz.axivion.com>, Stefan Bellon <sbellon@sbellon.de> writes: >>Hi all, >> >>I've been looking through the previous postings of the group and found >>two major threads where this topic has already been discussed. But the >>proposed solutions were all different to what I was thinking about. I >>have thought about the following: >> >> >>package body Base64 is >> >> type Six_Bits is mod 2**6; >> for Six_Bits'Size use 6; >> >> type Six_Bits_Array is array (Natural range <>) of Six_Bits; >> for Six_Bits_Array'Alignment use 1; -- To overlay over String type. >> for Six_Bits_Array'Component_Size use Six_Bits'Size; >> pragma Pack (Six_Bits_Array); >> >> Base64_Chars : constant array (Six_Bits) of Character := >> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; >> >> function Encode >> (Data : in String) >> return String >> is >> Padded_Length : constant Natural := ((Data'Length + 2) / 3) * 3; >> -- Pad input data to 3-Byte boundary. >> >> Base64_Length : constant Natural := Padded_Length / 3 * 4; >> -- Number of six-bit tokens necessary (including padding). >> >> Six_Bits_Length : constant Natural := (Data'Length * 4 + 2) / 3; >> -- Number of six-bit tokens necessary (without padding). >> >> Padded_Data : String (1 .. Padded_Length) := (others => ASCII.NUL); >> -- Padded input data. >> >> Base64_Data : Six_Bits_Array (1 .. Base64_Length); >> for Base64_Data'Address use Padded_Data'Address; >> -- Overlay array of six-bit tokens over the padded input data. >> >> Result : String (1 .. Base64_Length) := (others => '='); >> -- Output buffer, initialized with '=' tokens for unfilled >> -- end-markers. >> begin >> Padded_Data (1 .. Data'Length) := Data; >> -- Initialize data into padded-data (can't be done with aggregate >> -- in elaboration part, sadly). >> >> -- Do the actual encoding ... >> for I in 1 .. Six_Bits_Length loop >> Result (I) := Base64_Chars (Base64_Data (I)); >> end loop; >> >> return Result; >> end Encode; >> >>end Base64; >> >> >>However it looks like this solution has a problem with endianness, in a >>way that the wrong 6 bits of the Bytes are used in the conversion. >> >>Is there an easy way to fix this (as I think the rest would be pretty >>neat) or is this way of trying to do it, doomed to fail anyway? >> >>-- >>Stefan Bellon > ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-19 4:33 ` Base64-Encoding anon @ 2007-10-19 7:35 ` Jean-Pierre Rosen 0 siblings, 0 replies; 17+ messages in thread From: Jean-Pierre Rosen @ 2007-10-19 7:35 UTC (permalink / raw) anon a �crit : > that should say > > type Six_Bits is new Integer mod 2**6 ; -- or use range 0 .. 63 ; > Missed again! Should be: type Six_Bits is mod 2**6; Please get rid of references to Integer! They buy you nothing but trouble... -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-19 2:43 ` Base64-Encoding anon 2007-10-19 4:33 ` Base64-Encoding anon @ 2007-10-19 6:59 ` Stefan Bellon 2007-10-19 19:40 ` Base64-Encoding anon 1 sibling, 1 reply; 17+ messages in thread From: Stefan Bellon @ 2007-10-19 6:59 UTC (permalink / raw) On Fr, 19 Okt, anon wrote: > function To_Base64 is new Ada.Unchecked_Conversion > ( Source => Unsigned_8, > Target => base64_descriptor ) ; > > function From_Base64 is new Ada.Unchecked_Conversion > ( Target => Unsigned_8, > Source => base64_descriptor ) ; But this only converts one whole byte (aka Unsigned_8) into a Six_Bits by ignoring the two top-bits. This does not help with my original idea of overlaying a packed array of 6-bit elements over an array of 8-bit characters and then looping over the 6-bit elements to do the conversion in a simple loop, character by character. > In 2001 Tom Moran created a Ada BASE64 package which is archived at > > http://www.adapower.com/index.php?Command=Class&ClassID=Algorithms&CID=257 > > have a look at it. I a quick look it kind of suggest that the endian > for Six_Bits is not important. Yes, I know this package. But it handles three bytes in the original in one go and always encodes three bytes into four 6-bits. As I mentioned in my first posting, I am aware of the solutions to do the actual conversion that exist (and already have been discussed a few times here in the group). I was just wondering whether my idea of overlaying the two arrays could be easily "fixed" so that it works. But thanks for your ideas! -- Stefan Bellon ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Base64-Encoding 2007-10-19 6:59 ` Base64-Encoding Stefan Bellon @ 2007-10-19 19:40 ` anon 0 siblings, 0 replies; 17+ messages in thread From: anon @ 2007-10-19 19:40 UTC (permalink / raw) In my last post I answer about ENDIAN. Now for two algorithms to convert data to Base64: -- -------------------------------------------------------- -- Base64.ads -- -- -- For conversion -- The use of a 4 byte array is faster since the CPUs -- of today normally use 8-bits (quarter word) and -- actually have quarter word storage instructions. -- -- -- The usage of packed record requires extra -- code to be added to perform the record packing -- which will require more cpu cycles. -- -- Exception would be if your working on a older -- system like the 1108 9-bit "Univac" (now called -- "Unisys" ) of the 1970s which had 3-bits, 6-bits -- and 9-bits access instructions. -- package Base64 is -- -------------------------- -- -- TYPE: Base 64 Basics Types -- -- -------------------------- -- -- -- build the 6 bit -- type Bit_6 is mod 2 ** 6 ; -- -- Base_64 String Array -- type Base64_String is new String ( 1..4 ) ; -- --------------------------------------- -- -- TYPE: Base 64 Basics using 4 byte array -- -- --------------------------------------- -- -- -- packed Bit_6 into 4 bytes -- type Base64_Array is array ( 0 .. 3 ) of Bit_6 ; -- ----------------------------------------- -- -- TYPE: Base 64 Basics using 3 byte records -- -- ----------------------------------------- -- -- -- packed Bit_6 into 3 bytes -- -- ------------------------------ -- -- TYPE: Base 64 Conversion Types -- -- ------------------------------ -- -- -- Base_64_Descriptor is used in converting 8 bit -- characters to 6 bits ; -- type Base_64_Descriptor is record Value_3 : Bit_6 ; Value_2 : Bit_6 ; Value_1 : Bit_6 ; Value_0 : Bit_6 ; end record ; -- -- insure 3 byte usage for Character_Descriptor ; -- pragma pack ( Base_64_Descriptor ) ; -- ------------------------------- -- -- TYPE: Data Conversion Functions -- -- ------------------------------- -- -- -- 4 byte version -- function Coding ( B_String : Base64_String ) return Base64_Array ; function Coding ( B_Array : Base64_Array ) return Base64_String ; -- -- 3 byte version -- function Coding ( B_String : Base64_String ) return Base_64_Descriptor ; function Coding ( B_Array : Base_64_Descriptor ) return Base64_String ; -- -- Obtain conversion character -- function Base64_Character ( C : Character ) return Character ; end Base64 ; -- -------------------------------------------------------- -- Base64.adb -- with Interfaces ; use Interfaces ; with Ada.Unchecked_Conversion ; package body Base64 is -- -- Base_64 Character Set ; -- Characters : array ( Character range ASCII.Nul .. '?' ) of Character := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" & "abcdefghijklmnopqrstuvwxyz" & "0123456789+/" ; -- ------------------------------ -- -- TYPE: Base 64 Conversion Types -- -- ------------------------------ -- -- -- Character_Descriptor is used in converting 8 bit -- characters to 6 bits ; -- type Character_Descriptor is record unused : Unsigned_8 range 0..3 ; Value : Bit_6 ; end record ; -- -- set bit order -- for Character_Descriptor use record unused at 0 range 6..7 ; Value at 0 range 0..5 ; end record ; -- -- insure 1 byte usage for Character_Descriptor ; -- pragma pack ( Character_Descriptor ) ; -- ------------------------------- -- -- TYPE: Data Conversion Functions -- -- ------------------------------- -- function Char_8_To_Char_6 is new Ada.Unchecked_Conversion ( Character, Character_Descriptor ) ; function Char_6_To_Char_8 is new Ada.Unchecked_Conversion ( Character_Descriptor, Character ) ; -- -------------- -- -- 4 byte version -- -- -------------- -- function Coding ( B_String : Base64_String ) return Base64_Array is Temp : Base64_Array ; Work : Character_Descriptor ; begin -- Coding Work := Char_8_To_Char_6 ( B_String ( 4 ) ) ; Temp ( 3 ) := Work.Value ; Work := Char_8_To_Char_6 ( B_String ( 3 ) ) ; Temp ( 2 ) := Work.Value ; Work := Char_8_To_Char_6 ( B_String ( 2 ) ) ; Temp ( 1 ) := Work.Value ; Work := Char_8_To_Char_6 ( B_String ( 1 ) ) ; Temp ( 0 ) := Work.Value ; return Temp ; end Coding ; function Coding ( B_Array : Base64_Array ) return Base64_String is Temp : Base64_String ; Work : Character_Descriptor ; begin -- Coding Work.unused := 0 ; -- to insure value of conversion ; Work.Value := B_Array ( 3 ) ; Temp ( 4 ) := Char_6_To_Char_8 ( Work ) ; Work.Value := B_Array ( 2 ) ; Temp ( 3 ) := Char_6_To_Char_8 ( Work ) ; Work.Value := B_Array ( 1 ) ; Temp ( 2 ) := Char_6_To_Char_8 ( Work ) ; Work.Value := B_Array ( 0 ) ; Temp ( 1 ) := Char_6_To_Char_8 ( Work ) ; return Temp ; end Coding ; -- -------------- -- -- 3 byte version -- -- -------------- -- function Coding ( B_String : Base64_String ) return Base_64_Descriptor is Temp : Base_64_Descriptor ; Work : Character_Descriptor ; begin -- Coding Work := Char_8_To_Char_6 ( B_String ( 4 ) ) ; Temp.Value_3 := Work.Value ; Work := Char_8_To_Char_6 ( B_String ( 3 ) ) ; Temp.Value_2 := Work.Value ; Work := Char_8_To_Char_6 ( B_String ( 2 ) ) ; Temp.Value_1 := Work.Value ; Work := Char_8_To_Char_6 ( B_String ( 1 ) ) ; Temp.Value_0 := Work.Value ; return Temp ; end Coding ; function Coding ( B_Array : Base_64_Descriptor ) return Base64_String is Temp : Base64_String ; Work : Character_Descriptor ; begin -- Coding Work.unused := 0 ; -- to insure value of conversion ; Work.Value := B_Array.Value_3 ; Temp ( 4 ) := Char_6_To_Char_8 ( Work ) ; Work.Value := B_Array.Value_2 ; Temp ( 3 ) := Char_6_To_Char_8 ( Work ) ; Work.Value := B_Array.Value_1 ; Temp ( 2 ) := Char_6_To_Char_8 ( Work ) ; Work.Value := B_Array.Value_0 ; Temp ( 1 ) := Char_6_To_Char_8 ( Work ) ; return Temp ; end Coding ; -- -- Obtain conversion 8-bit character -- function Base64_Character ( C : Character ) return Character is begin -- Base64_Character return Characters ( C ) ; end Base64_Character ; end Base64 ; -- -------------------------------------------------------- -- Test64.adb -- Test program -- with Base64 ; with Ada.Text_IO ; with Ada.Integer_Text_IO ; use Ada.Text_IO ; use Ada.Integer_Text_IO ; procedure test64 is a : Base64.Base64_String := "1234"; b : Base64.Base_64_Descriptor ; c : Base64.base_64_Descriptor := ( 10, 20, 30, 40 ) ; d : Base64.base64_Array := ( 00, 01, 02, 03 ) ; e : Base64.Base64_String ; f : Base64.base64_Array ; begin -- -- Test using 4 byte array -- Put ( d'size ) ; New_Line ; Put ( e'size ) ; New_Line ; e := Base64.Coding ( d ) ; f := Base64.Coding ( e ) ; Put ( "Data : " ) ; Put ( Base64.Base64_Character ( e ( 1 ) ) ) ; Put ( Base64.Base64_Character ( e ( 2 ) ) ) ; Put ( Base64.Base64_Character ( e ( 3 ) ) ) ; Put ( Base64.Base64_Character ( e ( 4 ) ) ) ; New_Line ; b := Base64.Coding ( a ) ; Put ( a'size ) ; New_Line ; Put ( b'size ) ; -- 24 aka 3 byte pack record New_Line ; -- -- Test using packed 3 byte record -- a := Base64.Coding ( c ) ; Put ( "Data : " ) ; Put ( Base64.Base64_Character ( a ( 1 ) ) ) ; Put ( Base64.Base64_Character ( a ( 2 ) ) ) ; Put ( Base64.Base64_Character ( a ( 3 ) ) ) ; Put ( Base64.Base64_Character ( a ( 4 ) ) ) ; New_Line ; end Test64 ; In <20071019085934.7c1a525f@cube.tz.axivion.com>, Stefan Bellon <sbellon@sbellon.de> writes: >On Fr, 19 Okt, anon wrote: > >> function To_Base64 is new Ada.Unchecked_Conversion >> ( Source => Unsigned_8, >> Target => base64_descriptor ) ; >> >> function From_Base64 is new Ada.Unchecked_Conversion >> ( Target => Unsigned_8, >> Source => base64_descriptor ) ; > >But this only converts one whole byte (aka Unsigned_8) into a Six_Bits >by ignoring the two top-bits. This does not help with my original idea >of overlaying a packed array of 6-bit elements over an array of 8-bit >characters and then looping over the 6-bit elements to do the >conversion in a simple loop, character by character. > >> In 2001 Tom Moran created a Ada BASE64 package which is archived at >> >> http://www.adapower.com/index.php?Command=Class&ClassID=Algorithms&CID=257 >> >> have a look at it. I a quick look it kind of suggest that the endian >> for Six_Bits is not important. > >Yes, I know this package. But it handles three bytes in the original in >one go and always encodes three bytes into four 6-bits. > >As I mentioned in my first posting, I am aware of the solutions to do >the actual conversion that exist (and already have been discussed a >few times here in the group). I was just wondering whether my idea >of overlaying the two arrays could be easily "fixed" so that it works. > >But thanks for your ideas! > >-- >Stefan Bellon ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2007-10-19 19:40 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-10-15 14:12 Base64-Encoding Stefan Bellon 2007-10-15 14:46 ` Base64-Encoding Jacob Sparre Andersen 2007-10-15 14:54 ` Base64-Encoding Stefan Bellon 2007-10-15 15:14 ` Base64-Encoding Jacob Sparre Andersen 2007-10-15 15:37 ` Base64-Encoding Robert A Duff 2007-10-15 15:40 ` Base64-Encoding Jean-Pierre Rosen 2007-10-15 16:39 ` Base64-Encoding Stefan Bellon 2007-10-16 10:42 ` Base64-Encoding Stephen Leake 2007-10-17 14:07 ` Base64-Encoding Stefan Bellon 2007-10-17 15:09 ` Base64-Encoding Adam Beneschan 2007-10-17 18:15 ` Base64-Encoding Larry Kilgallen 2007-10-15 18:24 ` Base64-Encoding Adam Beneschan 2007-10-19 2:43 ` Base64-Encoding anon 2007-10-19 4:33 ` Base64-Encoding anon 2007-10-19 7:35 ` Base64-Encoding Jean-Pierre Rosen 2007-10-19 6:59 ` Base64-Encoding Stefan Bellon 2007-10-19 19:40 ` Base64-Encoding anon
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox