Convert::Binary::C で C 構造体をバイナリ変換 (入れ子になった構造体)
入れ子になった C 構造体をバイナリ変換する。
ヘッダファイル
sub_struct.h
#ifndef SUB_STRUCT_H #define SUB_STRUCT_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_member1; u_char sub_member2; }; struct top_t { u_char top_member1; u_char top_member2; struct sub_t sub; }; #pragma pack #endif
変換前のデータ
ハッシュのハッシュで表現する。
# data my %test_data = ( top_member1 => '0x12', # 18 top_member2 => '0x34', # 53 sub => { sub_member1 => '0x56', # 86 sub_member2 => '0x78', # 120 }, );
pack
my $packed = $c->pack( 'top_t', \%test_data ); print hexdump( data => $packed );
出力
0x0000 : 12 34 56 78 : .4Vx
unpack
my $unpacked = $c->unpack( 'top_t', $packed ); print Dumper($unpacked);
出力
$VAR1 = { 'top_member1' => 18, 'sub' => { 'sub_member1' => 86, 'sub_member2' => 120 }, 'top_member2' => 52 };
テストコード
#!/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('./sub_struct.h'); # data my %test_data = ( top_member1 => '0x12', # 18 top_member2 => '0x34', # 53 sub => { sub_member1 => '0x56', # 86 sub_member2 => '0x78', # 120 }, ); # 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 sub print_info { my ( $struct_name, $c, $packed_ref, $base_offset ) = @_; if ( !defined $base_offset ) { $base_offset = 0; } while ( my ( $member, $value ) = each %$packed_ref ) { my $absolute_name = $struct_name . '.' . $member; print "--- member $member", $/; print "absolute : $absolute_name\n"; print "type : ", $c->typeof($absolute_name), $/; print "size : ", $c->sizeof($absolute_name), $/; my $offset = $c->offsetof( $struct_name, $member ) + $base_offset; print "offset : ", $offset, $/; if ( ref($value) eq 'HASH' ) { # sub struct print_info( $absolute_name, $c, $value, $offset ); } else { print "value : $value", $/; } } } print '--- each member info', $/; print_info( 'top_t', $c, $unpacked ); # member print '--- member method', $/; for my $offset ( 0 .. $c->sizeof('top_t') - 1 ) { print "\$c->member('top_t', $offset)"; my $member = eval { $c->member( 'top_t', $offset ) }; print $@ ? "\n exception: $@" : " => '$member'\n"; }
出力
--- pack 0x0000 : 12 34 56 78 : .4Vx --- unpack $VAR1 = { 'top_member1' => 18, 'sub' => { 'sub_member1' => 86, 'sub_member2' => 120 }, 'top_member2' => 52 }; --- each member info --- member top_member1 absolute : top_t.top_member1 type : u_char size : 1 offset : 0 value : 18 --- member sub absolute : top_t.sub type : struct sub_t size : 2 offset : 2 --- member sub_member1 absolute : top_t.sub.sub_member1 type : u_char size : 1 offset : 2 value : 86 --- member sub_member2 absolute : top_t.sub.sub_member2 type : u_char size : 1 offset : 3 value : 120 --- member top_member2 absolute : top_t.top_member2 type : u_char size : 1 offset : 1 value : 52 --- member method $c->member('top_t', 0) => '.top_member1' $c->member('top_t', 1) => '.top_member2' $c->member('top_t', 2) => '.sub.sub_member1' $c->member('top_t', 3) => '.sub.sub_member2'