Ada语言中Tile'Read读取字节流至记录时出现异常求助
自定义Ada记录类型读取文件异常排查
类型定义
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;
磁盘数据
数据以3字节为一组存储,磁盘十六进制dump结果(仅关注第二行数据):
# 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 |................|
异常读取结果
使用Tile'Read (...)读取后得到不符合预期的翻转结果:
# 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
预期结果
0x11 0 0 0x11 0 0 0x11 0 0 ...
问题分析与解决
问题核心是位序设置与磁盘数据的实际存储位序不匹配:
- 当前设置
Tile'Bit_Order use System.Low_Order_First,会让Ada将每个字节内的位从最低位开始解析,但磁盘中字节的位序是标准的高序位在前(High_Order_First)。 - 以磁盘中的
0x11(二进制00010001)为例,Low_Order_First会将其视为10001000,导致原本的位被反转拆分,映射到错误的字段中。
修复方案
- 调整位序设置
将类型定义末尾的位序改为System.High_Order_First,匹配磁盘数据的字节内位序:
for Tile'Bit_Order use System.High_Order_First; for Tile'Scalar_Storage_Order use System.Low_Order_First;
- 手动解析数据(可选)
如果需要完全控制解析逻辑,可以绕过Ada自动序列化,手动读取字节并解析位:
procedure Read_Tile (File : in out Ada.Streams.Stream_IO.File_Type; Result : out Tile) is Buffer : array (1..3) of U8; begin U8'Read (Ada.Streams.Stream_IO.Stream (File), Buffer(1)); U8'Read (Ada.Streams.Stream_IO.Stream (File), Buffer(2)); U8'Read (Ada.Streams.Stream_IO.Stream (File), Buffer(3)); Result.Tilenum := Tilenum_t(Buffer(1)); Result.XFlipped := (Buffer(2) and 16#80#) /= 0; Result.YFlipped := (Buffer(2) and 16#40#) /= 0; Result.Rotation := Rotation_t(Shift_Right(Buffer(2) and 16#30#, 4)); Result.TriFlipped := (Buffer(2) and 16#08#) /= 0; Result.Padding := Padding_t(Buffer(2) and 16#07#); Result.Height := Buffer(3); end Read_Tile;
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

