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=-2.9 required=5.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=unavailable autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,ea4b92bb88a43e50 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2001-06-23 12:32:03 PST Path: archiver1.google.com!newsfeed.google.com!newsfeed.stanford.edu!news-spur1.maxwell.syr.edu!news.maxwell.syr.edu!newsfeed00.sul.t-online.de!t-online.de!grolier!freenix!enst!enst.fr!not-for-mail From: "David C. Hoos, Sr." Newsgroups: comp.lang.ada Subject: Re: Ada records and byte order Date: Sat, 23 Jun 2001 14:30:51 -0500 Organization: ENST, France Sender: comp.lang.ada-admin@ada.eu.org Message-ID: References: Reply-To: comp.lang.ada@ada.eu.org NNTP-Posting-Host: marvin.enst.fr Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_03BA_01C0FBF1.1AA27B40" X-Trace: avanie.enst.fr 993324722 91698 137.194.161.2 (23 Jun 2001 19:32:02 GMT) X-Complaints-To: usenet@enst.fr NNTP-Posting-Date: Sat, 23 Jun 2001 19:32:02 +0000 (UTC) Cc: "Karl Ran" , "Carbonne Damien" To: Return-Path: X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.50.4522.1200 X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4522.1200 Errors-To: comp.lang.ada-admin@ada.eu.org X-BeenThere: comp.lang.ada@ada.eu.org X-Mailman-Version: 2.0.4 Precedence: bulk List-Help: List-Post: List-Subscribe: , List-Id: comp.lang.ada mail<->news gateway List-Unsubscribe: , List-Archive: Errors-To: comp.lang.ada-admin@ada.eu.org X-BeenThere: comp.lang.ada@ada.eu.org Xref: archiver1.google.com comp.lang.ada:9063 Date: 2001-06-23T14:30:51-05:00 This is a multi-part message in MIME format. ------=_NextPart_000_03BA_01C0FBF1.1AA27B40 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit The problem is that on a little-endian machine, your 12-bit record component indicated by the bits bbbb bbbb bbbb are not contiguous in memory if read from the file stream by ordinary means. Ada Stream_IO provides a means of dealing with this problem, but it has the added complication that when parts of two or more record components occupy the same byte, the default stream attributes cannot be used, because that byte will be written or read more than once (i.e., once for each component that occupies it). To see why this is true, refer to LRM 95 13.13.2 (9), viz.: For elementary types, the representation in terms of stream elements is implementation defined. For composite types, the Write or Read attribute for each component is called in a canonical order. The canonical order of components is last dimension varying fastest for an array, and positional aggregate order for a record. Bounds are not included in the stream if T is an array type. If T is a discriminated type, discriminants are included only if they have defaults. If T is a tagged type, the tag is not included. Given all of this, I have written a small demonstration program that will write out a file such as you describe. Normally, of course, the types would be declared in their own package, and the stream-oriented attributes would be implemented in the body of that package, but I have combined them all here to keep things to a single file. The source code for the demonstration program is attached. I do not have access to a big-endian machine today, so this program has only been tested on a little-endian machine. Hoe this helps to understand the problem. There have been many questions of similar nature on this newsgroup, so I thought I'd seize upon a real example, and show how I've been solving this kind of problem. If anyone has a better way to do it, I'm all ears. ----- Original Message ----- From: "Karl Ran" Newsgroups: comp.lang.ada To: Sent: June 23, 2001 5:15 AM Subject: Ada records and byte order > Hi there, > > I've a question about Ada records: > > I have to read a binary file from disk which was written by another program. > > The record size is fixed: 3 bytes > The file structure looks like this: > > > |byte 1 | |byte 2 | |byte 3 | |byte 4... > aaaa.aaaa.bbbb.bbbb.bbbb.cccc | aaaa.a..... > M L M L M L > S S S S S S > B B B B B B > > a: 8 bits > b: 12 bits > c: 4 bits > > Here is the code ... > > procedure test is > > subtype BYTE is Integer range 0 .. 2 ** 8 - 1; > subtype WORD12 is integer range 0 .. 2 ** 12 - 1; > subtype WORD4 is integer range 0 .. 2 ** 4 - 1; > > type My_rec is > record > A : BYTE; > B : WORD12; > C : WORD4; > end record; > > for My_rec use > record > A at 0 range 0 .. 7; > B at 1 range 0 .. 11; > C at 2 range 0 .. 3; > end record; > > Abc : My_Rec; > > begin > Abc.b := 16#123#; > ... > end test; > > ... which fails to compile whith GNAT on a (low-endian) i386: > test.adb:31:10: component "C" overlaps "B" at line 30 > > Is there an Ada like (TM) solution for this kind of (byte order) problem? > > > Thanks, > Karl > _______________________________________________ > comp.lang.ada mailing list > comp.lang.ada@ada.eu.org > http://ada.eu.org/mailman/listinfo/comp.lang.ada > ------=_NextPart_000_03BA_01C0FBF1.1AA27B40 Content-Type: application/octet-stream; name="ran.adb" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ran.adb" with Ada.Text_IO; with Ada.Streams.Stream_IO; with System; procedure Ran is type Unsigned_4 is mod 2 **4; for Unsigned_4'Size use 4; type Unsigned_8 is mod 2 ** 8; for Unsigned_8'Size use 8; type Unsigned_12 is mod 2 ** 12; for Unsigned_12'Size use 12; -- Because a single byte is occupied by Both part of B and all of C, -- We combine them into a record so we can define stream-oriented -- attributes such that they can be read and written from/to a stream -- properly, regardless of machine endianness. type B_And_C is record B : Unsigned_12; C : Unsigned_4; end record; -- Use this representation clause on a little-endian machine. for B_And_C use record at mod 1; B at 0 range 4 .. 15; C at 0 range 0 .. 3; end record; -- Use this representation clause on a big-endian machine. -- for B_and_C use -- record at mod 1; -- B at 0 range 0 .. 11; -- C at 0 range 12 .. 15; -- end record; for B_And_C'Size use 16; -- We now procedd to declare the stream-orientd attributes procedure B_And_C_Read (Stream : access Ada.Streams.Root_Stream_Type'Class; Item : out B_And_C); procedure B_And_C_Write (Stream : access Ada.Streams.Root_Stream_Type'Class; Item : in B_And_C); for B_And_C'Read use B_And_C_Read; for B_And_C'Write use B_And_C_Write; type My_Record is record A : Unsigned_8; BC : B_And_C; end record; type Byte_Array is array (Positive range <>) of Unsigned_8; -- This procedure reverses the oder of the bytes in its argument. procedure Swap (The_Bytes : in out Byte_Array) is Temp : Unsigned_8; begin for B in 1 .. The_Bytes'Last / 2 loop Temp := The_Bytes (B); The_Bytes (B) := The_Bytes (The_Bytes'Last - B + 1); The_Bytes (The_Bytes'Last - B + 1) := Temp; end loop; end Swap; -- These porocedures implement the stream-oriented attributes. procedure B_And_C_Read (Stream : access Ada.Streams.Root_Stream_Type'Class; Item : out B_And_C) is The_Bytes : Byte_Array (1 .. Item'Size / Unsigned_8'Size); for The_Bytes'Address use Item'Address; use type System.Bit_Order; begin Byte_Array'Read (Stream, The_Bytes); if System.Default_Bit_Order = System.Low_Order_First then Swap (The_Bytes); end if; end B_And_C_Read; procedure B_And_C_Write (Stream : access Ada.Streams.Root_Stream_Type'Class; Item : in B_And_C) is The_Bytes : Byte_Array (1 .. Item'Size / Unsigned_8'Size); for The_Bytes'Address use Item'Address; use type System.Bit_Order; begin if System.Default_Bit_Order = System.Low_Order_First then Swap (The_Bytes); end if; Byte_Array'Write (Stream, The_Bytes); end B_And_C_Write; -- Define the object with all six nybbles unique, so we can -- demonstrate that they appear in correct order in the file. Item : My_Record := (16#9A#, (16#B0D#, 16#C#)); File : Ada.Streams.Stream_IO.File_Type; Stream : Ada.Streams.Stream_IO.Stream_Access; begin Ada.Streams.Stream_IO.Create (Name => "ran.dat", File => File, Mode => Ada.Streams.Stream_IO.Out_File); -- Associate a stream with the opened/created file Stream := Ada.Streams.Stream_IO.Stream (File); for I in 1 .. 4 loop My_Record'Write (Stream, Item); end loop; Ada.Streams.Stream_IO.Close (File); end Ran; ------=_NextPart_000_03BA_01C0FBF1.1AA27B40--