我有一个以 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存储数组。
您可能需要使用
gnatbind
开关 -xdr
。请参阅GNAT RM 6.32:
[面向流的属性]的默认实现基于直接二进制表示,因此依赖于目标和字节序。为了解决这个问题,GNAT 还提供了流属性 Read 和 Write 的替代实现,它使用标量类型的目标无关的 XDR 标准表示。这个 XDR 替代方案可以通过活页夹开关 -xdr 启用。
(XDR 本质上是大端)
一种方法是将数据作为一堆字节获取,然后使用 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;
有两点注释:
warning: scalar storage order specified for "Header" does not apply to component
。这些警告是无害的(行为是我们所期望的),但有点令人讨厌。不知道如何以正确的方式删除它们。