Convert::Binary::C で C 構造体をバイナリ変換 (固定長配列)
C の固定長配列をバイナリ変換する。
ヘッダファイル
fixed_array.h
#ifndef _FIXED_ARRAY_H_ #define _FIXED_ARRAY_H_ typedef unsigned char u_char; typedef unsigned short u_short; typedef unsigned int u_int; typedef unsigned long u_long; #pragma pack(1) struct sub_t { u_char sub_member; }; struct top_t { u_char char_array[3]; u_short short_array[3]; u_int int_array[3]; char string[5]; struct sub_t sub_array[3]; }; #pragma pack #endif /* _FIXED_ARRAY_H_ */
変換前のデータ
配列で表現する。
my %test_data = ( char_array => [ 0x01, 0x02, 0x03 ], short_array => [ 0x04, 0x05, 0x06 ], int_array => [ 0x07, 0x08, 0x09 ], string => "test", sub_array => [ { sub_member => 1 }, { sub_member => 2 }, { sub_member => 3 }, ], );
文字列
文字列は tag メソッドを使って明示的に示す必要がある。
$c->tag('top_t.string', Format => 'String');
pack
my $packed = $c->pack( 'top_t', \%test_data ); print hexdump( data => $packed );
0x0000 : 01 02 03 00 04 00 05 00 06 00 00 00 07 00 00 00 : ................ 0x0010 : 08 00 00 00 09 74 65 73 74 00 01 02 03 : .....test....
unpack
my $unpacked = $c->unpack( 'top_t', $packed ); print Dumper($unpacked);
$VAR1 = { 'int_array' => [ 7, 8, 9 ], 'sub_array' => [ { 'sub_member' => 1 }, { 'sub_member' => 2 }, { 'sub_member' => 3 } ], 'char_array' => [ 1, 2, 3 ], 'string' => 'test', 'short_array' => [ 4, 5, 6 ] };
テストコード
#!/usr/bin/perl use strict; use warnings; use Carp; use Convert::Binary::C; use Data::Dumper; use Data::Hexdumper; my $c = Convert::Binary::C->new(); $c->configure( ByteOrder => 'BigEndian' ); $c->parse_file('./fixed_array.h'); # tagging string format to top_t.string string $c->tag('top_t.string', Format => 'String'); # data my %test_data = ( char_array => [ 0x01, 0x02, 0x03 ], short_array => [ 0x04, 0x05, 0x06 ], int_array => [ 0x07, 0x08, 0x09 ], string => "test", sub_array => [ { sub_member => 1 }, { sub_member => 2 }, { sub_member => 3 }, ], ); # pack my $packed = $c->pack( 'top_t', \%test_data ); print '--- pack', $/; print hexdump( data => $packed ); # unpack my $unpacked = $c->unpack( 'top_t', $packed ); print '--- unpack', $/; print Dumper($unpacked); # offset, type, size print '--- offset, type, size', $/; print "type : ", $c->typeof('top_t.char_array[1]'), $/; print "size : ", $c->sizeof('top_t.char_array'), $/; print "offset : ", $c->offsetof( 'top_t', 'char_array[1]' ), $/; # member print '--- member method', $/; for my $offset ( 0 .. 10 ) { print "\$c->member('top_t', $offset)"; my $member = eval { $c->member( 'top_t', $offset ) }; print $@ ? "\n exception: $@" : " => '$member'\n"; }
--- pack 0x0000 : 01 02 03 00 04 00 05 00 06 00 00 00 07 00 00 00 : ................ 0x0010 : 08 00 00 00 09 74 65 73 74 00 01 02 03 : .....test.... --- unpack $VAR1 = { 'int_array' => [ 7, 8, 9 ], 'sub_array' => [ { 'sub_member' => 1 }, { 'sub_member' => 2 }, { 'sub_member' => 3 } ], 'char_array' => [ 1, 2, 3 ], 'string' => 'test', 'short_array' => [ 4, 5, 6 ] }; --- offset, type, size type : u_char size : 3 offset : 1 --- member method $c->member('top_t', 0) => '.char_array[0]' $c->member('top_t', 1) => '.char_array[1]' $c->member('top_t', 2) => '.char_array[2]' $c->member('top_t', 3) => '.short_array[0]' $c->member('top_t', 4) => '.short_array[0]+1' $c->member('top_t', 5) => '.short_array[1]' $c->member('top_t', 6) => '.short_array[1]+1' $c->member('top_t', 7) => '.short_array[2]' $c->member('top_t', 8) => '.short_array[2]+1' $c->member('top_t', 9) => '.int_array[0]' $c->member('top_t', 10) => '.int_array[0]+1'