Convert::Binary::C で C 構造体をバイナリ変換 (可変長配列)

C の可変長配列をバイナリ変換する。tag で dimension (配列長)を指定する。

ヘッダファイル

variable_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 top_t {
    u_char count;
    char   data[1];
};

#pragma pack

変換前のデータ

# data
my %test_data = (
    count => 3,
    data  => [ 0x0A, 0x0B, 0x0C ],
);

dimension を直接指定

$c->tag( 'top_t.data', Dimension => 3 );

dimension をメンバで決定

$c->tag( 'top_t.data', Dimension => 'count' );

dimension を関数で決定

$c->tag(
    'top_t.data',
    Dimension => sub {
        my $m = shift;
        return $m->{count};
    }
);

pack

my $packed = $c->pack( 'top_t', \%test_data );
print hexdump( data => $packed );
  0x0000 : 03 0A 0B 0C                                     : ....

unpack

my $unpacked = $c->unpack( 'top_t', $packed );
print Dumper($unpacked);
$VAR1 = {
          'count' => 3,
          'data' => [
                      10,
                      11,
                      12
                    ]
        };

テストコード

#!/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('./variable_array.h');

# data
my %test_data = (
    count => 3,
    data  => [ 0x0A, 0x0B, 0x0C ],
);

### dimension を直接指定
print q{### $c->tag('top_t.data', Dimension => 3)}, $/;
$c->tag( 'top_t.data', Dimension => 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);
}
$c->untag( 'top_t.data', 'Dimension' );

### dimension をメンバで決定
print q{### $c->tag('top_t.data', Dimension => 'count')}, $/;
$c->tag( 'top_t.data', Dimension => 'count' );
{

    # 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);
}
$c->untag( 'top_t.data', 'Dimension' );

### dimension を関数で決定
print q{### $c->tag('top_t.data', Dimension => sub)}, $/;
$c->tag(
    'top_t.data',
    Dimension => sub {
        my $m = shift;
        return $m->{count};
    }
);
{

    # 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);
}
$c->untag( 'top_t.data', 'Dimension' );
### $c->tag('top_t.data', Dimension => 3)
--- pack
  0x0000 : 03 0A 0B 0C                                     : ....
--- unpack
$VAR1 = {
          'count' => 3,
          'data' => [
                      10,
                      11,
                      12
                    ]
        };
### $c->tag('top_t.data', Dimension => 'count')
--- pack
  0x0000 : 03 0A 0B 0C                                     : ....
--- unpack
$VAR1 = {
          'count' => 3,
          'data' => [
                      10,
                      11,
                      12
                    ]
        };
### $c->tag('top_t.data', Dimension => sub)
--- pack
  0x0000 : 03 0A 0B 0C                                     : ....
--- unpack
$VAR1 = {
          'count' => 3,
          'data' => [
                      10,
                      11,
                      12
                    ]
        };