| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
package Convert::Binary::C; |
|
26
|
|
|
|
|
|
|
|
|
27
|
61
|
|
|
61
|
|
954
|
use strict; |
|
|
61
|
|
|
|
|
1673
|
|
|
|
61
|
|
|
|
|
1836
|
|
|
28
|
61
|
|
|
61
|
|
1064
|
use DynaLoader; |
|
|
61
|
|
|
|
|
2793
|
|
|
|
61
|
|
|
|
|
1716
|
|
|
29
|
61
|
|
|
61
|
|
1353
|
use Carp; |
|
|
61
|
|
|
|
|
546
|
|
|
|
61
|
|
|
|
|
1109
|
|
|
30
|
61
|
|
|
61
|
|
919
|
use vars qw( @ISA $VERSION $XS_VERSION $AUTOLOAD ); |
|
|
61
|
|
|
|
|
614
|
|
|
|
61
|
|
|
|
|
3554
|
|
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
@ISA = qw(DynaLoader); |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
$VERSION = do { my @r = '$Snapshot: /Convert-Binary-C/0.67 $' =~ /(\d+\.\d+(?:_\d+)?)/; @r ? $r[0] : '9.99' }; |
|
35
|
|
|
|
|
|
|
$XS_VERSION = $VERSION; |
|
36
|
|
|
|
|
|
|
$VERSION = eval $VERSION; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
bootstrap Convert::Binary::C $XS_VERSION; |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub AUTOLOAD |
|
44
|
|
|
|
|
|
|
{ |
|
45
|
6200
|
|
|
6200
|
|
11589590
|
my $self = shift; |
|
46
|
6200
|
|
|
|
|
74657
|
my $opt = $AUTOLOAD; |
|
47
|
6200
|
50
|
|
|
|
303279
|
ref $self or croak "$self is not an object"; |
|
48
|
6200
|
|
|
|
|
159911
|
$opt =~ s/.*://; |
|
49
|
6200
|
100
|
|
|
|
178656
|
$opt =~ /^[A-Z]/ or croak "Invalid method $opt called"; |
|
50
|
6199
|
100
|
|
|
|
135261
|
@_ <= 1 or croak "$opt cannot take more than one argument"; |
|
51
|
6198
|
100
|
100
|
|
|
80659
|
unless (@_ or defined wantarray) { |
|
52
|
21
|
|
|
|
|
279
|
carp "Useless use of $opt in void context"; |
|
53
|
21
|
|
|
|
|
580
|
return; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
6177
|
|
|
|
|
66729
|
my @warn; |
|
56
|
|
|
|
|
|
|
{ |
|
57
|
6177
|
|
|
4
|
|
62913
|
local $SIG{__WARN__} = sub { push @warn, $_[0] }; |
|
|
6177
|
|
|
|
|
213388
|
|
|
|
4
|
|
|
|
|
51
|
|
|
58
|
6177
|
|
|
|
|
129738
|
$opt = eval { $self->configure( $opt, @_ ) }; |
|
|
6177
|
|
|
|
|
157486
|
|
|
59
|
|
|
|
|
|
|
} |
|
60
|
6177
|
|
|
|
|
242186
|
for my $w (@warn) { |
|
61
|
4
|
|
|
|
|
83
|
$w =~ s/\s+at.*?C\.pm.*//s; |
|
62
|
4
|
|
|
|
|
54
|
carp $w; |
|
63
|
|
|
|
|
|
|
} |
|
64
|
6177
|
100
|
|
|
|
75689
|
if ($@) { |
|
65
|
198
|
|
|
|
|
3458
|
$@ =~ s/\s+at.*?C\.pm.*//s; |
|
66
|
198
|
|
|
|
|
2448
|
croak $@; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
5979
|
|
|
|
|
87570
|
$opt; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
1; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
__END__ |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head1 NAME |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Convert::Binary::C - Binary Data Conversion using C Types |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head2 Simple |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
use Convert::Binary::C; |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
#--------------------------------------------- |
|
86
|
|
|
|
|
|
|
# Create a new object and parse embedded code |
|
87
|
|
|
|
|
|
|
#--------------------------------------------- |
|
88
|
|
|
|
|
|
|
my $c = Convert::Binary::C->new->parse(<<ENDC); |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
enum Month { JAN, FEB, MAR, APR, MAY, JUN, |
|
91
|
|
|
|
|
|
|
JUL, AUG, SEP, OCT, NOV, DEC }; |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
struct Date { |
|
94
|
|
|
|
|
|
|
int year; |
|
95
|
|
|
|
|
|
|
enum Month month; |
|
96
|
|
|
|
|
|
|
int day; |
|
97
|
|
|
|
|
|
|
}; |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
ENDC |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
#----------------------------------------------- |
|
102
|
|
|
|
|
|
|
# Pack Perl data structure into a binary string |
|
103
|
|
|
|
|
|
|
#----------------------------------------------- |
|
104
|
|
|
|
|
|
|
my $date = { year => 2002, month => 'DEC', day => 24 }; |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $packed = $c->pack('Date', $date); |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head2 Advanced |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
use Convert::Binary::C; |
|
111
|
|
|
|
|
|
|
use Data::Dumper; |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
#--------------------- |
|
114
|
|
|
|
|
|
|
# Create a new object |
|
115
|
|
|
|
|
|
|
#--------------------- |
|
116
|
|
|
|
|
|
|
my $c = new Convert::Binary::C ByteOrder => 'BigEndian'; |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
#--------------------------------------------------- |
|
119
|
|
|
|
|
|
|
# Add include paths and global preprocessor defines |
|
120
|
|
|
|
|
|
|
#--------------------------------------------------- |
|
121
|
|
|
|
|
|
|
$c->Include('/usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.6/include', |
|
122
|
|
|
|
|
|
|
'/usr/include') |
|
123
|
|
|
|
|
|
|
->Define(qw( __USE_POSIX __USE_ISOC99=1 )); |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
#---------------------------------- |
|
126
|
|
|
|
|
|
|
# Parse the 'time.h' header file |
|
127
|
|
|
|
|
|
|
#---------------------------------- |
|
128
|
|
|
|
|
|
|
$c->parse_file('time.h'); |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
#--------------------------------------- |
|
131
|
|
|
|
|
|
|
# See which files the object depends on |
|
132
|
|
|
|
|
|
|
#--------------------------------------- |
|
133
|
|
|
|
|
|
|
print Dumper([$c->dependencies]); |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
#----------------------------------------------------------- |
|
136
|
|
|
|
|
|
|
# See if struct timespec is defined and dump its definition |
|
137
|
|
|
|
|
|
|
#----------------------------------------------------------- |
|
138
|
|
|
|
|
|
|
if ($c->def('struct timespec')) { |
|
139
|
|
|
|
|
|
|
print Dumper($c->struct('timespec')); |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
#------------------------------- |
|
143
|
|
|
|
|
|
|
# Create some binary dummy data |
|
144
|
|
|
|
|
|
|
#------------------------------- |
|
145
|
|
|
|
|
|
|
my $data = "binary_test_string"; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
#-------------------------------------------------------- |
|
148
|
|
|
|
|
|
|
# Unpack $data according to 'struct timespec' definition |
|
149
|
|
|
|
|
|
|
#-------------------------------------------------------- |
|
150
|
|
|
|
|
|
|
if (length($data) >= $c->sizeof('timespec')) { |
|
151
|
|
|
|
|
|
|
my $perl = $c->unpack('timespec', $data); |
|
152
|
|
|
|
|
|
|
print Dumper($perl); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
#-------------------------------------------------------- |
|
156
|
|
|
|
|
|
|
# See which member lies at offset 5 of 'struct timespec' |
|
157
|
|
|
|
|
|
|
#-------------------------------------------------------- |
|
158
|
|
|
|
|
|
|
my $member = $c->member('timespec', 5); |
|
159
|
|
|
|
|
|
|
print "member('timespec', 5) = '$member'\n"; |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Convert::Binary::C is a preprocessor and parser for C type |
|
164
|
|
|
|
|
|
|
definitions. It is highly configurable and supports |
|
165
|
|
|
|
|
|
|
arbitrarily complex data structures. Its object-oriented |
|
166
|
|
|
|
|
|
|
interface has L<C<pack>|/"pack"> and L<C<unpack>|/"unpack"> methods |
|
167
|
|
|
|
|
|
|
that act as replacements for |
|
168
|
|
|
|
|
|
|
Perl's L<C<pack>|perlfunc/"pack"> and L<C<unpack>|perlfunc/"unpack"> and |
|
169
|
|
|
|
|
|
|
allow to use C types instead of a string representation |
|
170
|
|
|
|
|
|
|
of the data structure for conversion of binary data from and |
|
171
|
|
|
|
|
|
|
to Perl's complex data structures. |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Actually, what Convert::Binary::C does is not very different |
|
174
|
|
|
|
|
|
|
from what a C compiler does, just that it doesn't compile the |
|
175
|
|
|
|
|
|
|
source code into an object file or executable, but only parses |
|
176
|
|
|
|
|
|
|
the code and allows Perl to use the enumerations, structs, unions |
|
177
|
|
|
|
|
|
|
and typedefs that have been defined within your C source for binary |
|
178
|
|
|
|
|
|
|
data conversion, similar to |
|
179
|
|
|
|
|
|
|
Perl's L<C<pack>|perlfunc/"pack"> and L<C<unpack>|perlfunc/"unpack">. |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Beyond that, the module offers a lot of convenience methods |
|
182
|
|
|
|
|
|
|
to retrieve information about the C types that have been parsed. |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=head2 Background and History |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
In late 2000 I wrote a real-time debugging interface for an |
|
187
|
|
|
|
|
|
|
embedded medical device that allowed me to send out data from |
|
188
|
|
|
|
|
|
|
that device over its integrated Ethernet adapter. |
|
189
|
|
|
|
|
|
|
The interface was C<printf()>-like, so you could easily send |
|
190
|
|
|
|
|
|
|
out strings or numbers. But you could also send out what I |
|
191
|
|
|
|
|
|
|
called I<arbitrary data>, which was intended for arbitrary |
|
192
|
|
|
|
|
|
|
blocks of the device's memory. |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
Another part of this real-time debugger was a Perl application |
|
195
|
|
|
|
|
|
|
running on my workstation that gathered all the messages that |
|
196
|
|
|
|
|
|
|
were sent out from the embedded device. It printed all the |
|
197
|
|
|
|
|
|
|
strings and numbers, and hex-dumped the arbitrary data. |
|
198
|
|
|
|
|
|
|
However, manually parsing a couple of 300 byte hex-dumps of a |
|
199
|
|
|
|
|
|
|
complex C structure is not only frustrating, but also error-prone |
|
200
|
|
|
|
|
|
|
and time consuming. |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
Using L<C<unpack>|perlfunc/"unpack"> to retrieve the contents |
|
203
|
|
|
|
|
|
|
of a C structure works fine for small structures and if you |
|
204
|
|
|
|
|
|
|
don't have to deal with struct member alignment. But otherwise, |
|
205
|
|
|
|
|
|
|
maintaining such code can be as awful as deciphering hex-dumps. |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
As I didn't find anything to solve my problem on the CPAN, |
|
208
|
|
|
|
|
|
|
I wrote a little module that translated simple C structs |
|
209
|
|
|
|
|
|
|
into L<C<unpack>|perlfunc/"unpack"> strings. It worked, but |
|
210
|
|
|
|
|
|
|
it was slow. And since it couldn't deal with struct member |
|
211
|
|
|
|
|
|
|
alignment, I soon found myself adding padding bytes everywhere. |
|
212
|
|
|
|
|
|
|
So again, I had to maintain two sources, and changing one of |
|
213
|
|
|
|
|
|
|
them forced me to touch the other one. |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
All in all, this little module seemed to make my task a bit |
|
216
|
|
|
|
|
|
|
easier, but it was far from being what I was thinking of: |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=over 2 |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=item * |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
A module that could directly use the source I've been coding |
|
223
|
|
|
|
|
|
|
for the embedded device without any modifications. |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=item * |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
A module that could be configured to match the properties |
|
228
|
|
|
|
|
|
|
of the different compilers and target platforms I was using. |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item * |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
A module that was fast enough to decode a great amount of |
|
233
|
|
|
|
|
|
|
binary data even on my slow workstation. |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=back |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
I didn't know how to accomplish these tasks until I read something |
|
238
|
|
|
|
|
|
|
about XS. At least, it seemed as if it could solve my performance |
|
239
|
|
|
|
|
|
|
problems. However, writing a C parser in C isn't easier than it is |
|
240
|
|
|
|
|
|
|
in Perl. But writing a C preprocessor from scratch is even worse. |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
Fortunately enough, after a few weeks of searching I found both, |
|
243
|
|
|
|
|
|
|
a lean, open-source C preprocessor library, and a reusable YACC |
|
244
|
|
|
|
|
|
|
grammar for ANSI-C. That was the beginning of the development of |
|
245
|
|
|
|
|
|
|
Convert::Binary::C in late 2001. |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Now, I'm successfully using the module in my embedded environment |
|
248
|
|
|
|
|
|
|
since long before it appeared on CPAN. From my point of view, it |
|
249
|
|
|
|
|
|
|
is exactly what I had in mind. It's fast, flexible, easy to use |
|
250
|
|
|
|
|
|
|
and portable. It doesn't require external programs or other Perl |
|
251
|
|
|
|
|
|
|
modules. |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head2 About this document |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
This document describes how to use Convert::Binary::C. A lot of |
|
256
|
|
|
|
|
|
|
different features are presented, and the example code sometimes |
|
257
|
|
|
|
|
|
|
uses Perl's more advanced language elements. If your experience |
|
258
|
|
|
|
|
|
|
with Perl is rather limited, you should know how to use Perl's |
|
259
|
|
|
|
|
|
|
very good documentation system. |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
To look up one of the manpages, use the L<C<perldoc>|perldoc> command. |
|
262
|
|
|
|
|
|
|
For example, |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
perldoc perl |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
will show you Perl's main manpage. To look up a specific Perl |
|
267
|
|
|
|
|
|
|
function, use C<perldoc -f>: |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
perldoc -f map |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
gives you more information about the L<C<map>|perlfunc/"map"> function. |
|
272
|
|
|
|
|
|
|
You can also search the FAQ using C<perldoc -q>: |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
perldoc -q array |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
will give you everything you ever wanted to know about Perl |
|
277
|
|
|
|
|
|
|
arrays. But now, let's go on with some real stuff! |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=head2 Why use Convert::Binary::C? |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
Say you want to pack (or unpack) data according to the following |
|
282
|
|
|
|
|
|
|
C structure: |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
struct foo { |
|
285
|
|
|
|
|
|
|
char ary[3]; |
|
286
|
|
|
|
|
|
|
unsigned short baz; |
|
287
|
|
|
|
|
|
|
int bar; |
|
288
|
|
|
|
|
|
|
}; |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
You could of course use |
|
291
|
|
|
|
|
|
|
Perl's L<C<pack>|perlfunc/"pack"> and L<C<unpack>|perlfunc/"unpack"> functions: |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
@ary = (1, 2, 3); |
|
294
|
|
|
|
|
|
|
$baz = 40000; |
|
295
|
|
|
|
|
|
|
$bar = -4711; |
|
296
|
|
|
|
|
|
|
$binary = pack 'c3 S i', @ary, $baz, $bar; |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
But this implies that the struct members are byte aligned. If |
|
299
|
|
|
|
|
|
|
they were long aligned (which is the default for most compilers), |
|
300
|
|
|
|
|
|
|
you'd have to write |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
$binary = pack 'c3 x S x2 i', @ary, $baz, $bar; |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
which doesn't really increase readability. |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Now imagine that you need to pack the data for a completely |
|
307
|
|
|
|
|
|
|
different architecture with different byte order. You would |
|
308
|
|
|
|
|
|
|
look into the L<C<pack>|perlfunc/"pack"> manpage again and |
|
309
|
|
|
|
|
|
|
perhaps come up with this: |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
$binary = pack 'c3 x n x2 N', @ary, $baz, $bar; |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
However, if you try to unpack C<$foo> again, your signed values |
|
314
|
|
|
|
|
|
|
have turned into unsigned ones. |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
All this can still be managed with Perl. But imagine your |
|
317
|
|
|
|
|
|
|
structures get more complex? Imagine you need to support |
|
318
|
|
|
|
|
|
|
different platforms? Imagine you need to make changes to |
|
319
|
|
|
|
|
|
|
the structures? You'll not only have to change the C source |
|
320
|
|
|
|
|
|
|
but also dozens of L<C<pack>|perlfunc/"pack"> strings in |
|
321
|
|
|
|
|
|
|
your Perl code. This is no fun. And Perl should be fun. |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
Now, wouldn't it be great if you could just read in the C |
|
324
|
|
|
|
|
|
|
source you've already written and use all the types defined |
|
325
|
|
|
|
|
|
|
there for packing and unpacking? That's what Convert::Binary::C |
|
326
|
|
|
|
|
|
|
does. |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=head2 Creating a Convert::Binary::C object |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
To use Convert::Binary::C just say |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
use Convert::Binary::C; |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
to load the module. Its interface is completely object |
|
335
|
|
|
|
|
|
|
oriented, so it doesn't export any functions. |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
Next, you need to create a new Convert::Binary::C object. This |
|
338
|
|
|
|
|
|
|
can be done by either |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
$c = Convert::Binary::C->new; |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
or |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
$c = new Convert::Binary::C; |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
You can optionally pass configuration options to |
|
347
|
|
|
|
|
|
|
the L<constructor|/"new"> as described in the next section. |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=head2 Configuring the object |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
To configure a Convert::Binary::C object, you can either call |
|
352
|
|
|
|
|
|
|
the L<C<configure>|/"configure"> method or directly pass the configuration |
|
353
|
|
|
|
|
|
|
options to the L<constructor|/"new">. If you want to change byte order |
|
354
|
|
|
|
|
|
|
and alignment, you can use |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
$c->configure(ByteOrder => 'LittleEndian', |
|
357
|
|
|
|
|
|
|
Alignment => 2); |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
or you can change the construction code to |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
$c = new Convert::Binary::C ByteOrder => 'LittleEndian', |
|
362
|
|
|
|
|
|
|
Alignment => 2; |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
Either way, the object will now know that it should use |
|
365
|
|
|
|
|
|
|
little endian (Intel) byte order and 2-byte struct member |
|
366
|
|
|
|
|
|
|
alignment for packing and unpacking. |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
Alternatively, you can use the option names as names of |
|
369
|
|
|
|
|
|
|
methods to configure the object, like: |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
$c->ByteOrder('LittleEndian'); |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
You can also retrieve information about the current |
|
374
|
|
|
|
|
|
|
configuration of a Convert::Binary::C object. For details, |
|
375
|
|
|
|
|
|
|
see the section about the L<C<configure>|/"configure"> method. |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head2 Parsing C code |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Convert::Binary::C allows two ways of parsing C source. Either |
|
380
|
|
|
|
|
|
|
by parsing external C header or C source files: |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
$c->parse_file('header.h'); |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
Or by parsing C code embedded in your script: |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
$c->parse(<<'CCODE'); |
|
387
|
|
|
|
|
|
|
struct foo { |
|
388
|
|
|
|
|
|
|
char ary[3]; |
|
389
|
|
|
|
|
|
|
unsigned short baz; |
|
390
|
|
|
|
|
|
|
int bar; |
|
391
|
|
|
|
|
|
|
}; |
|
392
|
|
|
|
|
|
|
CCODE |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
Now the object C<$c> will know everything about C<struct foo>. |
|
395
|
|
|
|
|
|
|
The example above uses a so-called here-document. It allows to |
|
396
|
|
|
|
|
|
|
easily embed multi-line strings in your code. You can find more |
|
397
|
|
|
|
|
|
|
about here-documents in L<perldata> or L<perlop>. |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
Since the L<C<parse>|/"parse"> and L<C<parse_file>|/"parse_file"> methods |
|
400
|
|
|
|
|
|
|
throw an exception when a parse error occurs, you usually want to catch |
|
401
|
|
|
|
|
|
|
these in an C<eval> block: |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
eval { $c->parse_file('header.h') }; |
|
404
|
|
|
|
|
|
|
if ($@) { |
|
405
|
|
|
|
|
|
|
# handle error appropriately |
|
406
|
|
|
|
|
|
|
} |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
Perl's special C<$@> variable will contain an empty string (which |
|
409
|
|
|
|
|
|
|
evaluates to a false value in boolean context) on success or |
|
410
|
|
|
|
|
|
|
an error string on failure. |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
As another feature, L<C<parse>|/"parse"> and L<C<parse_file>|/"parse_file"> return |
|
413
|
|
|
|
|
|
|
a reference to their object on success, just like L<C<configure>|/"configure"> does |
|
414
|
|
|
|
|
|
|
when you're configuring the object. This will allow you to write constructs |
|
415
|
|
|
|
|
|
|
like this: |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
my $c = eval { |
|
418
|
|
|
|
|
|
|
Convert::Binary::C->new(Include => ['/usr/include']) |
|
419
|
|
|
|
|
|
|
->parse_file('header.h') |
|
420
|
|
|
|
|
|
|
}; |
|
421
|
|
|
|
|
|
|
if ($@) { |
|
422
|
|
|
|
|
|
|
# handle error appropriately |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
=head2 Packing and unpacking |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
Convert::Binary::C has two methods, L<C<pack>|/"pack"> and L<C<unpack>|/"unpack">, |
|
428
|
|
|
|
|
|
|
that act similar to the functions of same denominator in Perl. |
|
429
|
|
|
|
|
|
|
To perform the packing described in the example above, |
|
430
|
|
|
|
|
|
|
you could write: |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
$data = { |
|
433
|
|
|
|
|
|
|
ary => [1, 2, 3], |
|
434
|
|
|
|
|
|
|
baz => 40000, |
|
435
|
|
|
|
|
|
|
bar => -4711, |
|
436
|
|
|
|
|
|
|
}; |
|
437
|
|
|
|
|
|
|
$binary = $c->pack('foo', $data); |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Unpacking will work exactly the same way, just that |
|
440
|
|
|
|
|
|
|
the L<C<unpack>|/"unpack"> method will take a byte string as its input |
|
441
|
|
|
|
|
|
|
and will return a reference to a (possibly very complex) |
|
442
|
|
|
|
|
|
|
Perl data structure. |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
$binary = get_data_from_memory(); |
|
445
|
|
|
|
|
|
|
$data = $c->unpack('foo', $binary); |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
You can now easily access all of the values: |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
print "foo.ary[1] = $data->{ary}[1]\n"; |
|
450
|
|
|