Adaでファイルの内容をLittleEndian32BitIntegerで読み込む
所用でファイルから32bitもしくは16bitの整数をLittleEndian固定で読み込む必要があったのだが、意外と面倒だった。
with Ada.Streams.Stream_IO, Ada.Text_IO, Ada.Integer_Text_IO;
use type Ada.Streams.Stream_Element;
procedure Sample is
type Little_Endian_Unsigned_32bit is mod ((2**8)**4);
type Little_Endian_Unsigned_16bit is mod ((2**8)**2);
procedure Little_Endian_Unsigned_32bit_Read(Stream : access Ada.Streams.Root_Stream_Type'Class; Item : out Little_Endian_Unsigned_32bit'Base);
for Little_Endian_Unsigned_32bit'Read use Little_Endian_Unsigned_32bit_Read;
procedure Little_Endian_Unsigned_16bit_Read(Stream : access Ada.Streams.Root_Stream_Type'Class; Item : out Little_Endian_Unsigned_16bit'Base);
for Little_Endian_Unsigned_16bit'Read use Little_Endian_Unsigned_16bit_Read;
procedure Little_Endian_Unsigned_32bit_Read(Stream : access Ada.Streams.Root_Stream_Type'Class; Item : out Little_Endian_Unsigned_32bit'Base) is
Element_Array : Ada.Streams.Stream_Element_Array(1..4);
Last : Ada.Streams.Stream_Element_Offset;
begin
Stream.Read(Item => Element_Array, Last => Last);
Item := (Little_Endian_Unsigned_32bit(Element_Array(1)) * ((2**8)**0))
+ (Little_Endian_Unsigned_32bit(Element_Array(2)) * ((2**8)**1))
+ (Little_Endian_Unsigned_32bit(Element_Array(3)) * ((2**8)**2))
+ (Little_Endian_Unsigned_32bit(Element_Array(4)) * ((2**8)*3));
end Little_Endian_Unsigned_32bit_Read;
procedure Little_Endian_Unsigned_16bit_Read(Stream : access Ada.Streams.Root_Stream_Type'Class; Item : out Little_Endian_Unsigned_16bit'Base) is
Element_Array : Ada.Streams.Stream_Element_Array(1..2);
Last : Ada.Streams.Stream_Element_Offset;
begin
Stream.Read(Item => Element_Array, Last => Last);
Item := (Little_Endian_Unsigned_16bit(Element_Array(1)) * ((2**8)**0))
+ (Little_Endian_Unsigned_16bit(Element_Array(2)) * ((2**8)**1));
end Little_Endian_Unsigned_16bit_Read;
Raw_File : Ada.Streams.Stream_IO.File_Type;
Raw_File_Stream : Ada.Streams.Stream_IO.Stream_Access;
Buffer_32bit : Little_Endian_Unsigned_32bit;
Buffer_16bit : Little_Endian_Unsigned_16bit;
begin
-- ファイルを開く
Ada.Streams.Stream_IO.Open(File => Raw_File,
Mode => Ada.Streams.Stream_IO.In_File,
Name => "path/to/file/_MG_8912.CR2");
Raw_File_Stream := Ada.Streams.Stream_IO.Stream(Raw_File);
Little_Endian_Unsigned_32bit'Read(Raw_File_Stream, Buffer_32bit);
Ada.Integer_Text_IO.Put(Integer(Buffer_32bit));
Ada.Text_IO.New_Line;
Little_Endian_Unsigned_16bit'Read(Raw_File_Stream, Buffer_16bit);
Ada.Integer_Text_IO.Put(Integer(Buffer_16bit));
Ada.Text_IO.New_Line;
end Sample;
Adaには標準でpack関数がない(というか、見つからなかった)ので(この場合unpackだが)、LittleEndian固定でバイト列を読み出す関数を自作する必要があった。が、バイト列の計算部分が今一綺麗にならない。Ada.Streams.Stream_Element
はmod
型なので計算する際は型変換する必要があるのだが、どうしてもコードが冗長っぽくなってしまう。もうちょっとこう、ビット演算ぽい感じで簡単にできないものだろうか。うーむ。
それにしても、T'Attribute(..., Item : T)
な定義を使うべきかで悩む。ドット記法が出来るようになった時代としては、そちらに統一したい感じもするが……。