โŒ About FreshRSS

Normal view

There are new articles available, click to refresh the page.
Before yesterdayNews from the Ada programming language world

How do I read a binary file in BigEndian order to a record?

I have a binary file format that is written in BigEndian order. The files are of varying size so I can't use Sequential_IO for this, as I need to read different types.

The problem is, when using Stream_IO, I can't find a way to use BigEndian, and Scalar_Storage_Order also doesn't affect anything. Also, I'm a very fresh beginner at Ada and overall tips and suggestions to the code are very welcome.

share.adb:
with Ada.Text_IO;
with Ada.Streams.Stream_IO; use Ada.Streams.Stream_IO;
with Ada.Streams;           use Ada.Streams;

package body Share is

   procedure Read_Share (Segment_Size : Positive; Required_Shares : Positive)
   is
      --  Ceiling function
      Block_Size : constant Positive :=
        (Segment_Size + (Required_Shares - 1)) / Required_Shares;
      type Block is array (Integer range 0 .. Block_Size) of Byte;

      S               : Stream_Access;
      Share_File      : File_Type;
      My_Share_Header : Share_Header;
   begin
      Open (Share_File, In_File, "../go-tahoe/3");
      S := Stream (Share_File);
      Share_Header'Read (S, My_Share_Header);
      My_Share_Header.Block_Size := Unsigned_32 (Block_Size);
      Display_Share_Content (My_Share_Header);

      Close (Share_File);
      --  Read_Blocks (My_Share_Header, Share_File);

      --  Now My_Share contains the values read from the binary file
   end Read_Share;

   procedure Display_Share_Content (My_Share_Header : Share_Header) is
   begin
      Ada.Text_IO.Put_Line
        ("Share version: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Version));
      Ada.Text_IO.Put_Line
        ("Share Data Length: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Data_Length));
      Ada.Text_IO.Put_Line
        ("Lease Number: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Lease_number));
      Ada.Text_IO.Put_Line
        ("Share version: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Version));
      Ada.Text_IO.Put_Line
        ("Block Size: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Block_Size));
      Ada.Text_IO.Put_Line
        ("Data Size: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Data_Size));
      Ada.Text_IO.Put_Line
        ("Data offset: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Data_Offset));
      Ada.Text_IO.Put_Line
        ("Plaintext hash tree offset: " &
         Interfaces.Unsigned_32'Image
           (My_Share_Header.Plaintext_Hash_Tree_Offset));
      Ada.Text_IO.Put_Line
        ("Crypttext hash tree offset: " &
         Interfaces.Unsigned_32'Image
           (My_Share_Header.Crypttext_Hash_Tree_Offset));
      Ada.Text_IO.Put_Line
        ("Block hashes offset: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Block_Hashes_Offset));
      Ada.Text_IO.Put_Line
        ("Share hashes offset: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.Share_Hashes_Offset));
      Ada.Text_IO.Put_Line
        ("URI Extension Length and URI Extension block offset: " &
         Interfaces.Unsigned_32'Image (My_Share_Header.URI_Extension_Offset));
   end Display_Share_Content;

   procedure Read_Blocks
     (My_Share_Header : Share_Header; Share_File : File_Type)
   is
      Total_Blocks : Interfaces.Unsigned_32 := My_Share_Header.Data_Size;
   begin
      Ada.Text_IO.Put ("");

   end Read_Blocks;
end Share;

share.ads:
with Interfaces; use Interfaces;
with System;     use System;
with Ada.Streams.Stream_IO;

package Share is

   type Byte is new Interfaces.Unsigned_8;
   type Kilobyte is array (Integer range 0 .. 1_023) of Byte;
   type Kilobyte_array is array (Integer range <>) of Kilobyte;

   type Share_Header is record
      Version                    : Unsigned_32;
      Data_Length                : Unsigned_32;
      Lease_number               : Unsigned_32;
      Version_Junk               : Unsigned_32;
      --  unused as it can be calculated from the URI
      Block_Size                 : Unsigned_32;
      Data_Size                  : Unsigned_32;
      Data_Offset                : Unsigned_32;
      Plaintext_Hash_Tree_Offset : Unsigned_32;
      Crypttext_Hash_Tree_Offset : Unsigned_32;
      Block_Hashes_Offset        : Unsigned_32;
      Share_Hashes_Offset        : Unsigned_32;
      URI_Extension_Offset       : Unsigned_32;
   end record;

   for Share_Header use record
      Version at 0 range 0 .. 32;
      --  Data_Length                : Unsigned_32;
      --  Lease_number               : Unsigned_32;
      --  Version_Junk               : Unsigned_32;
      --  --  unused as it can be calculated from the URI
      --  Block_Size                 : Unsigned_32;
      --  Data_Size                  : Unsigned_32;
      --  Data_Offset                : Unsigned_32;
      --  Plaintext_Hash_Tree_Offset : Unsigned_32;
      --  Crypttext_Hash_Tree_Offset : Unsigned_32;
      --  Block_Hashes_Offset        : Unsigned_32;
      --  Share_Hashes_Offset        : Unsigned_32;
      --  URI_Extension_Offset       : Unsigned_32;
   end record;

   for Share_Header'Bit_Order use High_Order_First;
   for Share_Header'Scalar_Storage_Order use High_Order_First;

   procedure Read_Share (Segment_Size : Positive; Required_Shares : Positive);
   procedure Display_Share_Content (My_Share_Header : Share_Header);
   procedure Read_Blocks
     (My_Share_Header : Share_Header;
      Share_File      : Ada.Streams.Stream_IO.File_Type);
end Share;

Tried defining the component clauses to not much success, different bit orders, modifying the Stream_IO storage arrays.

read byte stream to record

So I am trying to read a file into a record, specified like so:

   type U32        is new Interfaces.Unsigned_32;
   type U16        is new Interfaces.Unsigned_16;
   type U8         is new Interfaces.Unsigned_8;
   type Rotation_t is range 0 .. 3             with Size => 2;
   type Tilenum_t  is new Interfaces.Unsigned_8;
   type Padding_t  is range 0 .. 7             with Size => 3;

   type Tile is record
      Tilenum :    Tilenum_t;
      XFlipped :   Boolean;
      YFlipped :   Boolean;
      Rotation :   Rotation_t;
      TriFlipped : Boolean;
      Padding :    Padding_t;
      Height :     U8;
   end record with Size => 24;

   for Tile use
   record
      --  first byte
      Tilenum    at 0 range 0 .. 7;       -- 1111 1111   0000 0000   0000 0000
      --  second byte
      XFlipped   at 0 range 8 .. 8;       -- 0000 0000   1000 0000   0000 0000
      YFlipped   at 0 range 9 .. 9;       -- 0000 0000   0100 0000   0000 0000
      Rotation   at 0 range 10 .. 11;     -- 0000 0000   0011 0000   0000 0000
      TriFlipped at 0 range 12 .. 12;     -- 0000 0000   0000 1000   0000 0000
      Padding    at 0 range 13 .. 15;     -- 0000 0000   0000 0111   0000 0000
      --  third byte
      Height     at 0 range 16 .. 23;     -- 0000 0000   0000 0000   1111 1111
   end record;
   for Tile'Bit_Order            use System.Low_Order_First;
   for Tile'Scalar_Storage_Order use System.Low_Order_First;

Note that information comes in by 3 bytes at a time. On disk, I have:

# hexdump -C
# we are only interested in second line: first one is metadata
00000000  6d 61 70 20 0a 00 00 00  65 00 00 00 50 00 00 00  |map ....e...P...|
00000010  11 00 00 11 00 00 11 00  00 11 00 00 11 00 00 11  |................|

Now, reading this file (Tile'Read (...) ) produces flipped results:

# ada reads:
Tilenum= 17 XFlipped=FALSE YFlipped=FALSE Rotation= 1 TriFlipped=FALSE Padding= 0 Height= 17
Tilenum= 0  XFlipped=FALSE YFlipped=TRUE  Rotation= 0 TriFlipped=FALSE Padding= 1 Height= 0
Tilenum= 0  XFlipped=TRUE  YFlipped=FALSE Rotation= 0 TriFlipped=TRUE  Padding= 0 Height= 0
Tilenum= 17 XFlipped=FALSE YFlipped=FALSE Rotation= 1 TriFlipped=FALSE Padding= 0 Height= 17
# same as above, in numerical form:
0x11 [b:0001 0000] 0x11
0x00 [b:0100 0001] 0x00
0x00 [b:1000 1000] 0x00
0x11 [b:0001 0000] 0x11

While I would expect the result to be:

0x11 0 0
0x11 0 0
0x11 0 0
...

I am not sure to understand why 0x11 gets split into 2 nibbles ([0001 0001]) which are being read in two different times. (I would expect bytes to be simply flipped but being kept as a whole).

I deduce I am doing something terribly wrong.

Any help?

โŒ
โŒ