指向性メモ::2007-01-29

ページ情報
制作日
2007-01-29T10:21:13+09:00
最終更新日
2007-01-29T20:50:53+09:00

Adaでファイルの内容をLittleEndian32BitIntegerで読み込む

Created:
2007-01-29T10:21:13+09:00

所用でファイルから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_Elementmod型なので計算する際は型変換する必要があるのだが、どうしてもコードが冗長っぽくなってしまう。もうちょっとこう、ビット演算ぽい感じで簡単にできないものだろうか。うーむ。

それにしても、T'Attribute(..., Item : T)な定義を使うべきかで悩む。ドット記法が出来るようになった時代としては、そちらに統一したい感じもするが……。

Comments
3
Trackbacks
0
PermaLink
http://yudai.arielworks.com/memo/2007/01/29/102113

Adaでpack的なことをする場合

Created:
2007-01-29T20:50:53+09:00

AdaでByte列から特定の型を得たい場合、Unchecked_Conversionで変換する方法があり得る。

ただし、この方法では、バイト列の順は意識されない。Intelのアーキテクチャならば恐らくメモリ上ではLittle Endianで表現されているが、入力側のファイルなどがLittle Endianである保証はない。今回扱いたいTFFフォーマットの場合、最初の2byteで指定されたエンディアンで読み込む必要がある。

Tiffのリビジョン6以前ならば、定義された型がSHORT(16bit unsigined integer)、LONG(32bit unsgined integer)にASCII(7bit unsigned integer, null terminated)、BYTE(8bit unsigned integer)、Rational(two LONG)と単純なので、前回の記事の方法でもまだ何とかなる。気持ちが悪いところといえば、ASCIIのNULL終端を捨てるのにビットシフトしたいところだが、しょうがなく2で割るぐらいだ。

しかし、リビジョン6以降のTIFFでは既存の型全てにSigned型が追加されている。いわゆる2の補数で表現されているので、1bit目が1か0かで場合分けして、負の場合は2#10000000_...#から値を引くのだが、これがなかなかめんどくさい(もしかしたらもっと簡単にできるのだろうか)。さらに、FloatとDoubleも加わるので、IEEEに準拠した展開をしないといけない。

比較的よくある操作だと思うので、何か既に解決策がありそうなものだが、どうしたものだろうか。

Comments
0
Trackbacks
0
PermaLink
http://yudai.arielworks.com/memo/2007/01/29/205053
連絡先、リンク、転載や複製などについては『サイト案内』をご覧ください。Powered by HIMMEL

I ♥ Validator