File Coverage

blib/lib/Data/ParseBinary.pm
Criterion Covered Total %
statement 179 193 92.7
branch 29 30 96.6
condition 24 33 72.7
subroutine 89 103 86.4
pod 35 60 58.3
total 356 419 84.9


line stmt bran cond sub pod time code
1             package Data::ParseBinary;
2 5     5   79552 use strict;
  5         15  
  5         212  
3 5     5   28 use warnings;
  5         8  
  5         170  
4 5     5   23 no warnings 'once';
  5         10  
  5         242  
5            
6             our $VERSION = 0.31;
7            
8 5     5   2914 use Data::ParseBinary::Core;
  5         35  
  5         156  
9 5     5   9310 use Data::ParseBinary::Adapters;
  5         14  
  5         138  
10 5     5   3077 use Data::ParseBinary::Streams;
  5         14  
  5         145  
11 5     5   3269 use Data::ParseBinary::Stream::String;
  5         14  
  5         125  
12 5     5   8981 use Data::ParseBinary::Stream::Wrapper;
  5         14  
  5         151  
13 5     5   3613 use Data::ParseBinary::Stream::Bit;
  5         14  
  5         114  
14 5     5   2828 use Data::ParseBinary::Stream::StringBuffer;
  5         12  
  5         116  
15 5     5   2705 use Data::ParseBinary::Stream::File;
  5         14  
  5         124  
16 5     5   3327 use Data::ParseBinary::Constructs;
  5         18  
  5         256  
17 5     5   66 use Config;
  5         11  
  5         2195907  
18            
19             our $DefaultPass = Data::ParseBinary::NullConstruct->create();
20             $Data::ParseBinary::BaseConstruct::DefaultPass = $DefaultPass;
21             our $print_debug_info = undef;
22            
23             my $support_64_bit_int;
24             eval { my $x = pack "Q", 5 };
25             if ( $@ ) {
26             $support_64_bit_int = 0;
27             require Math::BigInt;
28             } else {
29             $support_64_bit_int = 1
30             }
31             $@ = '';
32            
33 44     44 0 179 sub UBInt16 { return Data::ParseBinary::Primitive->create($_[0], 2, "n") }
34 30     30 0 94 sub UBInt32 { return Data::ParseBinary::Primitive->create($_[0], 4, "N") }
35 54     54 0 165 sub ULInt16 { return Data::ParseBinary::Primitive->create($_[0], 2, "v") }
36 79     79 0 228 sub ULInt32 { return Data::ParseBinary::Primitive->create($_[0], 4, "V") }
37 0     0 0 0 sub UNInt32 { return Data::ParseBinary::Primitive->create($_[0], 4, "L") }
38 0     0 0 0 sub UNInt16 { return Data::ParseBinary::Primitive->create($_[0], 2, "S") }
39 124     124 0 11294 sub UNInt8 { return Data::ParseBinary::Primitive->create($_[0], 1, "C") }
40 0     0 0 0 sub SNInt32 { return Data::ParseBinary::Primitive->create($_[0], 4, "l") }
41 0     0 0 0 sub SNInt16 { return Data::ParseBinary::Primitive->create($_[0], 2, "s") }
42 0     0 0 0 sub SNInt8 { return Data::ParseBinary::Primitive->create($_[0], 1, "c") }
43 0     0 0 0 sub NFloat32{ return Data::ParseBinary::Primitive->create($_[0], 4, "f") }
44 0     0 0 0 sub NFloat64{ return Data::ParseBinary::Primitive->create($_[0], 8, "d") };
45             *SBInt8 = \&SNInt8;
46             *SLInt8 = \&SNInt8;
47             *Byte = \&UNInt8;
48             *UBInt8 = \&UNInt8;
49             *ULInt8 = \&UNInt8;
50            
51             my $create_64_classes = sub {
52             my ($name, $is_signed, $is_be) = @_;
53             return Data::ParseBinary::ExtendedNumberAdapter->create(Field($name, 8), $is_signed, $is_be);
54             };
55            
56             if ($support_64_bit_int) {
57 0     0   0 *UNInt64 = sub { return Data::ParseBinary::Primitive->create($_[0], 8, "Q") };
58 0     0   0 *SNInt64 = sub { return Data::ParseBinary::Primitive->create($_[0], 8, "q") };
59             }
60            
61             if ($^V ge v5.10.0) {
62 1     1   6 *SBInt16 = sub { return Data::ParseBinary::Primitive->create($_[0], 2, "s>") };
63 8     8   30 *SLInt16 = sub { return Data::ParseBinary::Primitive->create($_[0], 2, "s<") };
64 0     0   0 *SBInt32 = sub { return Data::ParseBinary::Primitive->create($_[0], 4, "l>") };
65 0     0   0 *SLInt32 = sub { return Data::ParseBinary::Primitive->create($_[0], 4, "l<") };
66 2     2   10 *BFloat32= sub { return Data::ParseBinary::Primitive->create($_[0], 4, "f>") };
67 1     1   7 *LFloat32= sub { return Data::ParseBinary::Primitive->create($_[0], 4, "f<") };
68             if ($support_64_bit_int) {
69 1     1   25 *SBInt64 = sub { return Data::ParseBinary::Primitive->create($_[0], 8, "q>") };
70 1     1   7 *SLInt64 = sub { return Data::ParseBinary::Primitive->create($_[0], 8, "q<") };
71 1     1   8 *UBInt64 = sub { return Data::ParseBinary::Primitive->create($_[0], 8, "Q>") };
72 6     6   999 *ULInt64 = sub { return Data::ParseBinary::Primitive->create($_[0], 8, "Q<") };
73             } else {
74             *SBInt64 = sub { $create_64_classes->($_[0], 1, 1) };
75             *SLInt64 = sub { $create_64_classes->($_[0], 1, 0) };
76             *UBInt64 = sub { $create_64_classes->($_[0], 0, 1) };
77             *ULInt64 = sub { $create_64_classes->($_[0], 0, 0) };
78             }
79 0     0   0 *BFloat64= sub { return Data::ParseBinary::Primitive->create($_[0], 8, "d>") };
80 2     2   10 *LFloat64= sub { return Data::ParseBinary::Primitive->create($_[0], 8, "d<") };
81             } else {
82             my ($primitive_class, $reversed_class);
83             if (pack('s', -31337) eq "\x85\x97") {
84             $primitive_class = 'Data::ParseBinary::Primitive';
85             $reversed_class = 'Data::ParseBinary::ReveresedPrimitive';
86             } else {
87             $reversed_class = 'Data::ParseBinary::Primitive';
88             $primitive_class = 'Data::ParseBinary::ReveresedPrimitive';
89             }
90             *SBInt16 = sub { return $primitive_class->create($_[0], 2, "s") };
91             *SLInt16 = sub { return $reversed_class->create($_[0], 2, "s") };
92             *SBInt32 = sub { return $primitive_class->create($_[0], 4, "l") };
93             *SLInt32 = sub { return $reversed_class->create($_[0], 4, "l") };
94             *BFloat32= sub { return $primitive_class->create($_[0], 4, "f") };
95             *LFloat32= sub { return $reversed_class->create($_[0], 4, "f") };
96             if ($support_64_bit_int) {
97             *SBInt64 = sub { return $primitive_class->create($_[0], 8, "q") };
98             *SLInt64 = sub { return $reversed_class->create($_[0], 8, "q") };
99             *UBInt64 = sub { return $primitive_class->create($_[0], 8, "Q") };
100             *ULInt64 = sub { return $reversed_class->create($_[0], 8, "Q") };
101             } else {
102             *SBInt64 = sub { $create_64_classes->($_[0], 1, 1) };
103             *SLInt64 = sub { $create_64_classes->($_[0], 1, 0) };
104             *UBInt64 = sub { $create_64_classes->($_[0], 0, 1) };
105             *ULInt64 = sub { $create_64_classes->($_[0], 0, 0) };
106             }
107             *BFloat64= sub { return $primitive_class->create($_[0], 8, "d") };
108             *LFloat64= sub { return $reversed_class->create($_[0], 8, "d") };
109             }
110            
111 102     102 1 401 sub Struct { return Data::ParseBinary::Struct->create(@_) }
112 8     8 1 58 sub Sequence{ return Data::ParseBinary::Sequence->create(@_) };
113             sub Array {
114 40     40 1 63 my ($count, $sub) = @_;
115 40 100 66     308 if ($count and ref($count) and UNIVERSAL::isa($count, "CODE")) {
      66        
116 30         135 return Data::ParseBinary::MetaArray->create($count, $sub);
117             } else {
118 10     41   71 return Data::ParseBinary::MetaArray->create(sub {$count}, $sub);
  41         117  
119             }
120             }
121            
122 2     2 0 14 sub GreedyRange { return Data::ParseBinary::Range->create(1, undef, $_[0]); }
123 1     1 0 9 sub OptionalGreedyRange { return Data::ParseBinary::Range->create(0, undef, $_[0]); }
124 0     0 0 0 sub Range { return Data::ParseBinary::Range->create(@_) };
125 30     30 1 716 sub Padding { return Data::ParseBinary::Padding->create($_[0]) }
126 12     12 0 66 sub Flag { return Data::ParseBinary::BitField->create($_[0], 1) }
127 2     2 1 17 sub Bit { return Data::ParseBinary::BitField->create($_[0], 1) }
128 4     4 0 17 sub Nibble { return Data::ParseBinary::BitField->create($_[0], 4) }
129 2     2 0 10 sub Octet { return Data::ParseBinary::BitField->create($_[0], 8) }
130 10     10 0 452 sub BitField { return Data::ParseBinary::BitField->create(@_) }
131 1     1 1 7 sub ReversedBitField { return Data::ParseBinary::ReversedBitField->create(@_) }
132            
133 9     9 0 59 sub ConditionalRestream { return Data::ParseBinary::ConditionalRestream->create(@_) }
134             sub BitStruct {
135 7     7 1 21 my ($name, @subcons) = @_;
136 7         21 my $subcon = Struct($name, @subcons);
137 7     35   52 return ConditionalRestream($subcon, "Bit", sub { not $_->stream->isBitStream() });
  35         97  
138             }
139             sub ReversedBitStruct {
140 2     2 1 5 my ($name, @subcons) = @_;
141 2         9 my $subcon = Struct($name, @subcons);
142 2     4   12 return ConditionalRestream($subcon, "ReversedBit", sub { not $_->stream->isBitStream() });
  4         13  
143             }
144 29     29 1 134 sub Enum { return Data::ParseBinary::Enum->create(@_) }
145             sub OneOf {
146 4     4 1 8 my ($subcon, $list) = @_;
147             my $code = sub {
148 4     4   42 return grep $_ == $_[0], @$list;
149 4         14 };
150 4         25 return Data::ParseBinary::LamdaValidator->create($subcon, $code);
151             }
152             sub NoneOf {
153 4     4 1 8 my ($subcon, $list) = @_;
154             my $code = sub {
155 4     4   16 my @res = grep $_ == $_[0], @$list;
156 4         18 return @res == 0;
157 4         18 };
158 4         17 return Data::ParseBinary::LamdaValidator->create($subcon, $code);
159             }
160             sub Field {
161 60     60 1 112 my ($name, $len) = @_;
162 60 100 66     445 if ($len and ref($len) and UNIVERSAL::isa($len, "CODE")) {
      66        
163 14         75 return Data::ParseBinary::MetaField->create($name, $len);
164             } else {
165 46         225 return Data::ParseBinary::StaticField->create($name, $len);
166             }
167             }
168             *Bytes = \&Field;
169 12     12 1 70 sub RepeatUntil (&$) { return Data::ParseBinary::RepeatUntil->create(@_) }
170            
171             sub Char {
172 29     29 1 34439 my ($name, $encoding) = @_;
173            
174             # if we don't have encoding - a char is simply one byte
175 29 100       100 return Field($name, 1) unless $encoding;
176            
177 14 100 100     178 if ( ( $encoding eq "UTF-32LE" ) or ( $encoding eq "UTF-32BE" ) ) {
    100 100        
    100 66        
    100          
178 2         6 my $subcon = Field($name, 4);
179 2         9 return Data::ParseBinary::CharacterEncodingAdapter->create($subcon, $encoding);
180             } elsif ( ( $encoding eq "UTF-16LE" ) or ( $encoding eq "UTF-16BE" ) ) {
181 2 100       8 my $place = $encoding eq "UTF-16LE" ? 1 : 0;
182             my $subcon = Struct($name,
183             Field("FirstUnit", 2),
184 8 100 66 8   24 Array( sub { my $ch = substr($_->ctx->{FirstUnit}, $place, 1); return ( ( ($ch ge "\xD8" ) and ($ch le "\xDB") ) ? 1 : 0 ) },
  8         50  
185 2         22 Field("TheRest", 2)
186             )
187             );
188 2         14 my $assambled = Data::ParseBinary::FirstUnitAndTheRestAdapter->create($subcon, 2);
189 2         12 return Data::ParseBinary::CharacterEncodingAdapter->create($assambled, $encoding);
190             } elsif ( ( $encoding eq "utf8" ) or ( $encoding eq "UTF-8" ) ) {
191             my $subcon = Struct($name,
192             Field("FirstUnit", 1),
193 26   100 26   65 Array( sub { my $ch = $_->ctx->{FirstUnit}; return scalar(grep { $ch ge $_ } "\xC0", "\xE0", "\xF0" ) || 0 },
  26         52  
194 3         12 Field("TheRest", 1)
195             )
196             );
197 3         30 my $assambled = Data::ParseBinary::FirstUnitAndTheRestAdapter->create($subcon, 1);
198 3         19 return Data::ParseBinary::CharacterEncodingAdapter->create($assambled, $encoding);
199             } elsif ( $encoding =~ /^(?:utf|ucs)/i ) {
200 6         1103 die "Unrecognized UTF format: $encoding";
201             } else {
202             # this is a single-byte encoding
203 1         6 return Data::ParseBinary::CharacterEncodingAdapter->create(Field($name, 1), $encoding);
204             }
205             }
206            
207             sub PaddedString {
208 4     4 1 13 my ($name, $length, %params) = @_;
209 4         14 my $subcon = Data::ParseBinary::PaddedStringAdapter->create(Field($name, $length), length => $length, %params);
210 4 100       23 return $subcon unless $params{encoding};
211 1         9 return Data::ParseBinary::CharacterEncodingAdapter->create($subcon, $params{encoding});
212             };
213             sub String {
214 8     8 1 22 my ($name, $length, %params) = @_;
215 8 100       27 if (defined $params{padchar}) {
216             #this is a padded string
217 3         12 return PaddedString($name, $length, %params);
218             }
219 5         23 return Data::ParseBinary::JoinAdapter->create(
220             Array($length, Char($name, $params{encoding})),
221             );
222             }
223 3     3 0 30 sub LengthValueAdapter { return Data::ParseBinary::LengthValueAdapter->create(@_) }
224             sub PascalString {
225 3     3 1 9 my ($name, $length_field_type, $encoding) = @_;
226 3   100     35 $length_field_type ||= \&UBInt8;
227 3         6 my $length_field;
228             {
229 5     5   57 no strict 'refs';
  5         19  
  5         8262  
  3         5  
230 3         18 $length_field = &$length_field_type('length');
231             }
232 3 100       11 if (not $encoding) {
233             return LengthValueAdapter(
234             Sequence($name,
235             $length_field,
236 2     2   16 Field("data", sub { $_->ctx->[0] }),
  2         6  
237             )
238             );
239             } else {
240             return LengthValueAdapter(
241             Sequence($name,
242             $length_field,
243             Data::ParseBinary::JoinAdapter->create(
244 1     2   7 Array(sub { $_->ctx->[0] }, Char("data", $encoding)),
  2         9  
245             ),
246             )
247             );
248             }
249             }
250            
251             sub CString {
252 11     11 1 29 my ($name, %params) = @_;
253 11         31 my ($terminators, $encoding, $char_field) = @params{qw{terminators encoding char_field}};
254 11 100       39 $terminators = "\x00" unless defined $terminators;
255 11   33     51 $char_field ||= Char($name, $encoding);
256 11         39 my @t_list = split '', $terminators;
257             return Data::ParseBinary::CStringAdapter->create(
258             Data::ParseBinary::JoinAdapter->create(
259 11     420   82 RepeatUntil(sub { my $obj = $_->obj; grep($obj eq $_, @t_list) } ,$char_field)),
  420         961  
  420         2603  
260             $terminators
261             );
262             }
263            
264            
265 20     20 1 94 sub Switch { return Data::ParseBinary::Switch->create(@_) }
266 16     16 1 75 sub Pointer { return Data::ParseBinary::Pointer->create(@_) }
267 1     1 0 9 sub LazyBound { return Data::ParseBinary::LazyBound->create(@_) }
268 32     32 1 118 sub Value { return Data::ParseBinary::Value->create(@_) }
269 14     14 1 18 sub Anchor { my $name = shift; return Value($name, sub { $_->stream->tell } ) }
  14     124   49  
  124         333  
270 1     1 1 366 sub Terminator { return Data::ParseBinary::Terminator->create() }
271            
272             sub IfThenElse {
273 11     11 1 18 my ($name, $predicate, $then_subcon, $else_subcon) = @_;
274 36 100   36   93 return Switch($name, sub { &$predicate ? 1 : 0 },
275             {
276 11         80 1 => $then_subcon,
277             0 => $else_subcon,
278             }
279             )
280             }
281            
282             sub If {
283 4     4 1 9 my ($predicate, $subcon, $elsevalue) = @_;
284             return IfThenElse($subcon->_get_name(),
285             $predicate,
286             $subcon,
287 6     6   22 Value("elsevalue", sub { $elsevalue })
288 4         18 )
289             }
290 2     2 1 15 sub Peek { Data::ParseBinary::Peek->create(@_) }
291 16     16 1 96 sub Const { Data::ParseBinary::ConstAdapter->create(@_) }
292             sub Alias {
293 11     11 1 16 my ($newname, $oldname) = @_;
294 11     11   50 return Value($newname, sub { $_->ctx->{$oldname}});
  11         43  
295             }
296            
297 1     1 1 10 sub Union { Data::ParseBinary::Union->create(@_) }
298 0     0 1 0 sub RoughUnion { Data::ParseBinary::RoughUnion->create(@_) }
299            
300             *CreateStreamReader = \&Data::ParseBinary::Stream::Reader::CreateStreamReader;
301             *CreateStreamWriter = \&Data::ParseBinary::Stream::Writer::CreateStreamWriter;
302 5     5 0 38 sub ExtractingAdapter { Data::ParseBinary::ExtractingAdapter->create(@_) };
303            
304             sub Aligned {
305 5     5 1 10 my ($subcon, $modulus) = @_;
306 5   50     11 $modulus ||= 4;
307 5 50       14 die "Aligned should be more then 2" if $modulus < 2;
308 5         25 my $sub_name = $subcon->_get_name();
309             my $s = ExtractingAdapter(
310             Struct($sub_name,
311             Anchor("Aligned_before"),
312             $subcon,
313             Anchor("Aligned_after"),
314 58     58   159 Padding(sub { ($modulus - (($_->ctx->{Aligned_after} - $_->ctx->{Aligned_before}) % $modulus)) % $modulus })
315 5         15 ),
316             $sub_name);
317 5         15 return $s;
318             }
319            
320             sub Restream {
321 3     3 0 7 my ($subcon, $stream_name) = @_;
322 3         21 return Data::ParseBinary::Restream->create($subcon, $stream_name);
323             }
324             sub Bitwise {
325 3     3 1 6 my ($subcon) = @_;
326 3         10 return Restream($subcon, "Bit");
327             }
328            
329             sub Magic {
330 5     5 1 11 my ($data) = @_;
331 5         24 return Const(Field(undef, length($data)), $data);
332             }
333            
334 3     3 0 20 sub Select { Data::ParseBinary::Select->create(@_) }
335            
336             sub Optional {
337 1     1 1 2 my $subcon = shift;
338 1         8 return Select($subcon, $DefaultPass);
339             }
340            
341 4     4 1 38 sub FlagsEnum { Data::ParseBinary::FlagsEnum->create(@_) }
342            
343             require Exporter;
344             our @ISA = qw(Exporter);
345             our @EXPORT = qw(
346             UBInt8
347             ULInt8
348             SBInt8
349             SLInt8
350             Byte
351             UBInt16
352             ULInt16
353             SBInt16
354             SLInt16
355             UBInt32
356             ULInt32
357             SBInt32
358             SLInt32
359             BFloat32
360             LFloat32
361             UBInt64
362             ULInt64
363             SBInt64
364             SLInt64
365             BFloat64
366             LFloat64
367            
368             Struct
369             Sequence
370            
371             Padding
372            
373             Flag
374             Bit
375             Nibble
376             Octet
377             BitField
378             BitStruct
379             ReversedBitField
380             ReversedBitStruct
381            
382             Enum
383             $DefaultPass
384             OneOf
385             NoneOf
386             Array
387             RepeatUntil
388             Field
389             Bytes
390             Switch
391             Pointer
392             Anchor
393            
394             Char
395             String
396             PascalString
397             CString
398             PaddedString
399            
400             LazyBound
401             Value
402             IfThenElse
403             If
404             Peek
405             Const
406             Terminator
407             Alias
408             Union
409             RoughUnion
410            
411             CreateStreamReader
412             CreateStreamWriter
413            
414             Aligned
415             ExtractingAdapter
416             Restream
417             Bitwise
418             Magic
419            
420             Select
421             FlagsEnum
422             );
423            
424             our @Neturals_depricated = qw{
425             UNInt8
426             SNInt8
427             UNInt16
428             SNInt16
429             UNInt32
430             SNInt32
431             UNInt64
432             SNInt64
433             NFloat32
434             NFloat64
435             };
436             our @EXPORT_OK = (@Neturals_depricated, qw{
437             Range
438             GreedyRange
439             OptionalGreedyRange
440             Optional
441             });
442             our %EXPORT_TAGS = ( NATURALS => \ @Neturals_depricated, all => [ @EXPORT_OK, @EXPORT ]);
443            
444             1;
445            
446             __END__