如何将 BigEndian 顺序的二进制文件读取到记录中?

问题描述 投票:0回答:2

我有一个以 BigEndian 顺序编写的二进制文件格式。这些文件的大小各不相同,因此我无法为此使用 Sequential_IO,因为我需要读取不同的类型。

问题是,当使用Stream_IO时,我找不到使用BigEndian的方法,并且Scalar_Storage_Order也不会影响任何东西。另外,我是 Ada 的新手,非常欢迎对代码的整体提示和建议。

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;

尝试定义组件子句但不太成功,不同的位顺序,修改Stream_IO存储数组。

binary ada endianness
2个回答
0
投票

您可能需要使用

gnatbind
开关
-xdr
。请参阅GNAT RM 6.32

[面向流的属性]的默认实现基于直接二进制表示,因此依赖于目标和字节序。为了解决这个问题,GNAT 还提供了流属性 Read 和 Write 的替代实现,它使用标量类型的目标无关的 XDR 标准表示。这个 XDR 替代方案可以通过活页夹开关 -xdr 启用。

(XDR 本质上是大端)


0
投票

一种方法是将数据作为一堆字节获取,然后使用 Ada.Unchecked_Conversion 将它们转换为记录,前提是您使用 Scalar_Storage_Order 子句。

with Ada.Unchecked_Conversion;
with Ada.Text_IO;
with Interfaces;
with System;

procedure BE_Test is

  subtype U8  is Interfaces.Unsigned_8;
  subtype U32 is Interfaces.Unsigned_32;

  type Buffer is array (Natural range <>) of U8;

  type Header is record
    Version    : U32;
    Signature  : String (1 .. 4);
    Code       : Buffer (1 .. 4);
  end record;

  for Header use record
    Version    at 0 range 0 .. 31;
    Signature  at 4 range 0 .. 31;
    Code       at 8 range 0 .. 31;
  end record;

  for Header'Bit_Order use System.High_Order_First;
  for Header'Scalar_Storage_Order use System.High_Order_First;

  function Convert is new Ada.Unchecked_Conversion (Buffer, Header);

  h : Header;
  
  use Ada.Text_IO;
  
begin
  --  16#01020304# = 16909060
  --  16909060 (as big endian), then "ABCD", then 11 12 13 14
  h := Convert ((1, 2, 3, 4, 65, 66, 67, 68, 11, 12, 13, 14));
  Put_Line (h.Version'Image);
  Put_Line (h.Signature);
  for i in h.Code'Range loop
    Put_Line (h.Code (i)'Image);
  end loop;
end;

有两点注释:

  • Scalar_Storage_Order 仅限 GNAT
  • GNAT 对记录中的数组发出警告(上例中的签名、代码):
    warning: scalar storage order specified for "Header" does not apply to component
    。这些警告是无害的(行为是我们所期望的),但有点令人讨厌。不知道如何以正确的方式删除它们。
© www.soinside.com 2019 - 2024. All rights reserved.