File Coverage

blib/lib/Data/ParseBinary/Constructs.pm
Criterion Covered Total %
statement 427 508 84.0
branch 74 124 59.6
condition 32 83 38.5
subroutine 71 88 80.6
pod n/a
total 604 803 75.2


line stmt bran cond sub pod time code
1             package Data::ParseBinary::RoughUnion;
2 5     5   27 use strict;
  5         10  
  5         156  
3 5     5   28 use warnings;
  5         11  
  5         37395  
4             our @ISA = qw{Data::ParseBinary::BaseConstruct};
5            
6             sub create {
7 1     1   4 my ($class, $name, @subcons) = @_;
8 1         9 my $self = $class->SUPER::create($name);
9 1         12 $self->{subcons} = \@subcons;
10 1         30 return $self;
11             }
12            
13             sub _parse {
14 1     1   2 my ($self, $parser, $stream) = @_;
15 1         2 my $hash = {};
16 1         3 $parser->push_ctx($hash);
17 1         11 my $w_stream = Data::ParseBinary::Stream::StringBufferReader->new($stream);
18 1         12 $parser->push_stream($w_stream);
19 1         9 my $pos = $w_stream->tell();
20 1         2 foreach my $sub (@{ $self->{subcons} }) {
  1         4  
21 2         6 my $name = $sub->_get_name();
22 2         5 my $value = $parser->_parse($sub);
23 2         8 $w_stream->seek($pos);
24 2 50       4 next unless defined $name;
25 2         6 $hash->{$name} = $value;
26             }
27 1         5 $w_stream->ReadBytes($self->{size});
28 1         4 $parser->pop_ctx();
29 1         2 return $hash;
30             }
31            
32             sub _union_build {
33 2     2   5 my ($self, $parser, $string_stream, $data) = @_;
34 2         3 my $field_found = 0;
35 2         7 my $pos = $string_stream->tell();
36 2         3 foreach my $sub (@{ $self->{subcons} }) {
  2         5  
37 4         17 my $name = $sub->_get_name();
38 4 100 66     25 next unless exists $data->{$name} and defined $data->{$name};
39 2         6 $parser->_build($sub, $data->{$name});
40 2         7 $string_stream->seek($pos);
41 2         4 $field_found = 1;
42             }
43 2         6 return $field_found;
44             }
45            
46             sub _build {
47 0     0   0 my ($self, $parser, $stream, $data) = @_;
48 0         0 my $s_stream = Data::ParseBinary::Stream::StringWriter->new();
49 0         0 $parser->push_stream($s_stream);
50 0         0 my $field_found = $self->_union_build($parser, $s_stream, $data);
51 0 0       0 die "Union build error: not found any data" unless $field_found;
52 0         0 $parser->pop_stream();
53 0         0 $stream->WriteBytes($s_stream->Flush());
54             }
55            
56             package Data::ParseBinary::Union;
57             our @ISA = qw{Data::ParseBinary::RoughUnion};
58            
59             sub create {
60 1     1   5 my ($class, $name, @subcons) = @_;
61 1         11 my $self = $class->SUPER::create($name, @subcons);
62 1         6 my $size = $subcons[0]->_size_of();
63 1         3 foreach my $sub (@subcons) {
64 2         7 my $temp_size = $sub->_size_of();
65 2 50       8 $size = $temp_size if $temp_size > $size;
66             }
67 1         4 $self->{size} = $size;
68 1         4 return $self;
69             }
70            
71             sub _build {
72 2     2   5 my ($self, $parser, $stream, $data) = @_;
73 2         10 my $s_stream = Data::ParseBinary::Stream::StringWriter->new();
74 2         8 $parser->push_stream($s_stream);
75 2         17 my $field_found = $self->_union_build($parser, $s_stream, $data);
76 2 50       6 die "Union build error: not found any data" unless $field_found;
77 2         7 $parser->pop_stream();
78 2         7 my $string = $s_stream->Flush();
79 2 100       8 if ($self->{size} > length($string)) {
80 1         6 $string .= "\0" x ( $self->{size} - length($string) );
81             }
82 2         6 $stream->WriteBytes($string);
83             }
84            
85             sub _size_of {
86 0     0   0 my ($self, $context) = @_;
87 0         0 return $self->{size};
88             }
89            
90             package Data::ParseBinary::Select;
91             our @ISA = qw{Data::ParseBinary::BaseConstruct};
92            
93             sub create {
94 3     3   8 my ($class, @subconstructs) = @_;
95 3 50       15 die "Empty Struct is illigal" unless @subconstructs;
96 3         26 my $self = $class->SUPER::create(undef);
97 3         13 $self->{subs} = \@subconstructs;
98 3         12 return $self;
99             }
100            
101             sub _parse {
102 7     7   14 my ($self, $parser, $stream) = @_;
103 7         26 my $orig_pos = $stream->tell();
104 7         25 my $upper_hash = $parser->ctx();
105 7         14 foreach my $sub (@{ $self->{subs} }) {
  7         16  
106 12         45 $stream->seek($orig_pos);
107 12         18 my $hash = {};
108 12         32 $parser->push_ctx($hash);
109 12         36 $parser->eval_enter();
110 12         46 my $name = $sub->_get_name();
111 12         15 my $value;
112 12         25 eval {
113 12         35 $value = $parser->_parse($sub);
114             };
115 12         37 $parser->eval_leave();
116 12         36 $parser->pop_ctx();
117 12 100       39 next if $@;
118 6 100       25 $hash->{$name} = $value if defined $name;
119 6         30 while (my ($key, $val) = each %$hash) {
120 5         23 $upper_hash->{$key} = $val;
121             }
122 6         24 return;
123             }
124 1         9 die "Problem with Select: no matching option";
125             }
126            
127            
128             sub _build {
129 7     7   17 my ($self, $parser, $stream, $data) = @_;
130 7         21 my $upper_hash = $parser->ctx();
131 7         13 foreach my $sub (@{ $self->{subs} }) {
  7         20  
132 12         69 my $hash = { %$upper_hash };
133 12         52 my $inter_stream = Data::ParseBinary::Stream::StringWriter->new();
134 12         44 $parser->push_ctx($hash);
135 12         34 $parser->push_stream($inter_stream);
136 12         34 $parser->eval_enter();
137 12         37 my $name = $sub->_get_name();
138 12         20 eval {
139 12 100       106 $parser->_build($sub, defined $name? $hash->{$name} : undef);
140             };
141 12         46 $parser->eval_leave();
142 12         33 $parser->pop_stream();
143 12         33 $parser->pop_ctx();
144 12 100       51 next if $@;
145 6         1162 %$upper_hash = %$hash;
146 6         30 $stream->WriteBytes($inter_stream->Flush());
147 6         33 return;
148             }
149 1         8 die "Problem with Select: no matching option";
150             }
151            
152             package Data::ParseBinary::Restream;
153             our @ISA = qw{Data::ParseBinary::WrappingConstruct};
154            
155             sub create {
156 12     12   24 my ($class, $subcon, $stream_name) = @_;
157 12         69 my $self = $class->SUPER::create($subcon);
158 12         26 $self->{stream_name} = $stream_name;
159 12         28 return $self;
160             }
161            
162             sub _parse {
163 31     31   44 my ($self, $parser, $stream) = @_;
164 31         94 my $sub_stream = Data::ParseBinary::Stream::Reader::CreateStreamReader($self->{stream_name} => $stream);
165 31         81 $parser->push_stream($sub_stream);
166 31         107 return $parser->_parse($self->{subcon});
167             }
168            
169             sub _build {
170 29     29   55 my ($self, $parser, $stream, $data) = @_;
171 29         114 my $sub_stream = Data::ParseBinary::Stream::Writer::CreateStreamWriter($self->{stream_name} => Wrap => $stream);
172 29         88 $parser->push_stream($sub_stream);
173 29         96 $parser->_build($self->{subcon}, $data);
174             }
175            
176             package Data::ParseBinary::ConditionalRestream;
177             our @ISA = qw{Data::ParseBinary::Restream};
178            
179             sub create {
180 9     9   29 my ($class, $subcon, $stream_name, $condition) = @_;
181 9         47 my $self = $class->SUPER::create($subcon, $stream_name);
182 9         19 $self->{condition} = $condition;
183 9         39 return $self;
184             }
185            
186             sub _parse {
187 19     19   34 my ($self, $parser, $stream) = @_;
188 19 100       58 if ($parser->runCodeRef($self->{condition})) {
189 16         60 return $self->SUPER::_parse($parser, $stream);
190             } else {
191 3         10 return $parser->_parse($self->{subcon});
192             }
193             }
194            
195             sub _build {
196 20     20   40 my ($self, $parser, $stream, $data) = @_;
197 20 100       68 if ($parser->runCodeRef($self->{condition})) {
198 14         59 $self->SUPER::_build($parser, $stream, $data);
199             } else {
200 6         15 $parser->_build($self->{subcon}, $data);
201             }
202             }
203            
204             package Data::ParseBinary::TunnelAdapter;
205             our @ISA = qw{Data::ParseBinary::WrappingConstruct};
206            
207             sub create {
208 0     0   0 my ($class, $subcon, $inner_subcon) = @_;
209 0         0 my $self = $class->SUPER::create($subcon);
210 0         0 $self->{inner_subcon} = $inner_subcon;
211 0         0 return $self;
212             }
213            
214             sub _parse {
215 0     0   0 my ($self, $parser, $stream) = @_;
216 0         0 my $inter = $parser->_parse($self->{subcon});
217 0         0 my $inter_stream = Data::ParseBinary::StringStreamReader->new($inter);
218 0         0 return $parser->_parse($self->{inner_subcon});
219             }
220            
221             sub _build {
222 0     0   0 my ($self, $parser, $stream, $data) = @_;
223 0         0 my $inter_stream = Data::ParseBinary::Stream::StringWriter->new();
224 0         0 $parser->push_stream($inter_stream);
225 0         0 $parser->_build($self->{inner_subcon}, $data);
226 0         0 $parser->pop_stream();
227 0         0 $parser->_build($self->{subcon}, $inter_stream->Flush());
228             }
229            
230             package Data::ParseBinary::Peek;
231             our @ISA = qw{Data::ParseBinary::WrappingConstruct};
232            
233             sub create {
234 2     2   4 my ($class, $subcon, $distance) = @_;
235 2         13 my $self = $class->SUPER::create($subcon);
236 2   100     11 $self->{distance} = $distance || 0;
237 2         10 return $self;
238             }
239            
240             sub _parse {
241 2     2   3 my ($self, $parser, $stream) = @_;
242 2         8 my $pos = $stream->tell();
243 2         6 my $distance = $parser->runCodeRef($self->{distance});
244 2         7 $stream->seek($pos + $distance);
245 2         7 my $res = $parser->_parse($self->{subcon});
246 2         5 $stream->seek($pos);
247 2         5 return $res;
248             }
249            
250             sub _build {
251 2     2   6 my ($self, $parser, $stream, $data) = @_;
252             # does nothing
253             }
254            
255             sub _size_of {
256 0     0   0 my ($self, $context) = @_;
257             # the construct size is 0
258 0         0 return 0;
259             }
260            
261             package Data::ParseBinary::Value;
262             our @ISA = qw{Data::ParseBinary::BaseConstruct};
263            
264             sub create {
265 32     32   45 my ($class, $name, $func) = @_;
266 32         98 my $self = $class->SUPER::create($name);
267 32         74 $self->{func} = $func;
268 32         177 return $self;
269             }
270            
271             sub _parse {
272 78     78   113 my ($self, $parser, $stream) = @_;
273 78         229 return $parser->runCodeRef($self->{func});
274             }
275            
276             sub _build {
277 73     73   292 my ($self, $parser, $stream, $data) = @_;
278 73         213 $parser->ctx->{$self->_get_name()} = $parser->runCodeRef($self->{func});
279             }
280            
281             sub _size_of {
282 0     0   0 my ($self, $context) = @_;
283             # the construct size is 0
284 0         0 return 0;
285             }
286            
287             package Data::ParseBinary::LazyBound;
288             our @ISA = qw{Data::ParseBinary::BaseConstruct};
289            
290             sub create {
291 1     1   3 my ($class, $name, $boundfunc) = @_;
292 1         23 my $self = $class->SUPER::create($name);
293 1         10 $self->{bound} = undef;
294 1         2 $self->{boundfunc} = $boundfunc;
295 1         10 return $self;
296             }
297            
298             sub _parse {
299 3     3   6 my ($self, $parser, $stream) = @_;
300 3         12 return $parser->_parse($parser->runCodeRef($self->{boundfunc}));
301             }
302            
303             sub _build {
304 3     3   6 my ($self, $parser, $stream, $data) = @_;
305 3         10 return $parser->_build($parser->runCodeRef($self->{boundfunc}), $data);
306             }
307            
308             package Data::ParseBinary::Terminator;
309             our @ISA = qw{Data::ParseBinary::BaseConstruct};
310            
311             sub _parse {
312 2     2   3 my ($self, $parser, $stream) = @_;
313 2         3 eval { $stream->ReadBytes(1) };
  2         8  
314 2 100       15 if (not $@) {
315 1         10 die "Terminator expected end of stream";
316             }
317 1         5 return;
318             }
319            
320             sub _build {
321 1     1   3 my ($self, $parser, $stream, $data) = @_;
322 1         3 return;
323             }
324            
325             sub _size_of {
326 0     0   0 my ($self, $context) = @_;
327             # the construct size is 0
328 0         0 return 0;
329             }
330            
331             package Data::ParseBinary::NullConstruct;
332             our @ISA = qw{Data::ParseBinary::BaseConstruct};
333            
334             sub _parse {
335 3     3   7 my ($self, $parser, $stream) = @_;
336 3         8 return;
337             }
338            
339             sub _build {
340 3     3   10 my ($self, $parser, $stream, $data) = @_;
341 3         9 return;
342             }
343            
344             sub _size_of {
345 0     0   0 my ($self, $context) = @_;
346             # the construct size is 0
347 0         0 return 0;
348             }
349            
350             package Data::ParseBinary::Pointer;
351             our @ISA = qw{Data::ParseBinary::BaseConstruct};
352            
353             sub create {
354 16     16   24 my ($class, $posfunc, $subcon) = @_;
355 16         69 my $self = $class->SUPER::create($subcon->_get_name());
356 16         45 $self->{subcon} = $subcon;
357 16         26 $self->{posfunc} = $posfunc;
358 16         87 return $self;
359             }
360            
361             sub _parse {
362 92     92   131 my ($self, $parser, $stream) = @_;
363 92         256 my $newpos = $parser->runCodeRef($self->{posfunc});
364 92         304 my $origpos = $stream->tell();
365 92         252 $stream->seek($newpos);
366 92         269 my $value = $parser->_parse($self->{subcon});
367 92         282 $stream->seek($origpos);
368 92         236 return $value;
369             }
370            
371             sub _build {
372 63     63   147 my ($self, $parser, $stream, $data) = @_;
373 63         624 my $newpos = $parser->runCodeRef($self->{posfunc});
374 63         688 my $origpos = $stream->tell();
375 63         226 $stream->seek($newpos);
376 63         203 $parser->_build($self->{subcon}, $data);
377 63         276 $stream->seek($origpos);
378             }
379            
380             sub _size_of {
381 0     0   0 my ($self, $context) = @_;
382             # the construct size is 0
383 0         0 return 0;
384             }
385            
386             package Data::ParseBinary::Switch;
387             our @ISA = qw{Data::ParseBinary::BaseConstruct};
388            
389             sub create {
390 20     20   52 my ($class, $name, $keyfunc, $cases, %params) = @_;
391 20 50 33     173 die "Switch expects code ref as keyfunc"
      33        
392             unless $keyfunc and ref($keyfunc) and UNIVERSAL::isa($keyfunc, "CODE");
393 20 50 33     172 die "Switch expects hash-ref as a list of cases"
      33        
394             unless $cases and ref($cases) and UNIVERSAL::isa($cases, "HASH");
395 20         80 my $self = $class->SUPER::create($name);
396 20         52 $self->{keyfunc} = $keyfunc;
397 20         25 $self->{cases} = $cases;
398 20         38 $self->{default} = $params{default};
399 20 100 100     83 $self->{default} = Data::ParseBinary::NullConstruct->create() if $self->{default} and $self->{default} == $Data::ParseBinary::BaseConstruct::DefaultPass;
400 20         99 return $self;
401             }
402            
403             sub _getCont {
404 78     78   115 my ($self, $parser) = @_;
405 78         216 my $key = $parser->runCodeRef($self->{keyfunc});
406 78 100       445 if (exists $self->{cases}->{$key}) {
407 74         189 return $self->{cases}->{$key};
408             }
409 4 50       13 if (defined $self->{default}) {
410 4         10 return $self->{default};
411             }
412 0         0 die "Error at Switch: got un-declared value, and no default was defined";
413             }
414            
415             sub _parse {
416 45     45   66 my ($self, $parser, $stream) = @_;
417 45         107 my $value = $self->_getCont($parser);
418 45 50       98 return unless defined $value;
419 45         161 return $parser->_parse($value);
420             }
421            
422             sub _build {
423 33     33   600 my ($self, $parser, $stream, $data) = @_;
424 33         85 my $value = $self->_getCont($parser);
425 33 50       90 return unless defined $value;
426 33         296 return $parser->_build($value, $data);
427             }
428            
429             sub _size_of {
430 0     0   0 my ($self, $context) = @_;
431 0         0 my $size = -1;
432 0         0 foreach my $subcon (values %{ $self->{cases} }) {
  0         0  
433 0         0 my $sub_size = $subcon->_size_of($context);
434 0 0       0 if ($size == -1) {
435 0         0 $size = $sub_size;
436             } else {
437 0 0       0 die "This Switch have dynamic size" unless $size == $sub_size;
438             }
439             }
440 0 0       0 if ($self->{default}) {
441 0         0 my $sub_size = $self->{default}->_size_of($context);
442 0 0       0 die "This Switch have dynamic size" unless $size == $sub_size;
443             }
444 0         0 return $size;
445             }
446            
447             package Data::ParseBinary::StaticField;
448             our @ISA = qw{Data::ParseBinary::BaseConstruct};
449            
450             sub create {
451 46     46   77 my ($class, $name, $len) = @_;
452 46         211 my $self = $class->SUPER::create($name);
453 46         110 $self->{len} = $len;
454 46         285 return $self;
455             }
456            
457             sub _parse {
458 318     318   427 my ($self, $parser, $stream) = @_;
459 318         961 my $data = $stream->ReadBytes($self->{len});
460 318         808 return $data;
461             }
462            
463             sub _build {
464 285     285   463 my ($self, $parser, $stream, $data) = @_;
465 285 50 33     1683 die "Invalid Value" unless defined $data and not ref $data;
466 285         939 $stream->WriteBytes($data);
467             }
468            
469             sub _size_of {
470 0     0   0 my ($self, $context) = @_;
471 0         0 return $self->{len};
472             }
473            
474             package Data::ParseBinary::MetaField;
475             our @ISA = qw{Data::ParseBinary::BaseConstruct};
476            
477             sub create {
478 14     14   25 my ($class, $name, $coderef) = @_;
479 14 50 33     81 die "MetaField $name: must have a coderef" unless ref($coderef) and UNIVERSAL::isa($coderef, "CODE");
480 14         53 my $self = $class->SUPER::create($name);
481 14         39 $self->{code} = $coderef;
482 14         74 return $self;
483             }
484            
485             sub _parse {
486 62     62   221 my ($self, $parser, $stream) = @_;
487 62         218 my $len = $parser->runCodeRef($self->{code});
488 62         181 my $data = $stream->ReadBytes($len);
489 62         430 return $data;
490             }
491            
492             sub _build {
493 50     50   112445 my ($self, $parser, $stream, $data) = @_;
494 50 50 33     258 die "Invalid Value" unless defined $data and not ref $data;
495 50         176 $stream->WriteBytes($data);
496             }
497            
498             package Data::ParseBinary::BitField;
499             our @ISA = qw{Data::ParseBinary::BaseConstruct};
500            
501             sub create {
502 30     30   58 my ($class, $name, $length) = @_;
503 30         127 my $self = $class->SUPER::create($name);
504 30         75 $self->{length} = $length;
505 30         168 return $self;
506             }
507            
508             sub _parse {
509 125     125   165 my ($self, $parser, $stream) = @_;
510 125         327 my $data = $stream->ReadBits($self->{length});
511 125         226 my $pad_len = 32 - $self->{length};
512 125         378 my $parsed = unpack "N", pack "B32", ('0' x $pad_len) . $data;
513 125         321 return $parsed;
514             }
515            
516             sub _build {
517 126     126   182 my ($self, $parser, $stream, $data) = @_;
518 126         395 my $binaryString = unpack("B32", pack "N", $data);
519 126         293 my $string = substr($binaryString, -$self->{length}, $self->{length});
520 126         349 $stream->WriteBits($string);
521             }
522            
523             package Data::ParseBinary::ReversedBitField;
524             our @ISA = qw{Data::ParseBinary::BaseConstruct};
525            
526             sub create {
527 1     1   3 my ($class, $name, $length) = @_;
528 1         8 my $self = $class->SUPER::create($name);
529 1         19 $self->{length} = $length;
530 1         6 return $self;
531             }
532            
533             sub _parse {
534 1     1   3 my ($self, $parser, $stream) = @_;
535 1         5 my $data = $stream->ReadBits($self->{length});
536 1         4 $data = join '', reverse split '', $data;
537 1         3 my $pad_len = 32 - $self->{length};
538 1         5 my $parsed = unpack "N", pack "B32", ('0' x $pad_len) . $data;
539 1         3 return $parsed;
540             }
541            
542             sub _build {
543 1     1   3 my ($self, $parser, $stream, $data) = @_;
544 1         11 my $binaryString = unpack("B32", pack "N", $data);
545 1         3 my $string = substr($binaryString, -$self->{length}, $self->{length});
546 1         5 $string = join '', reverse split '', $string;
547 1         5 $stream->WriteBits($string);
548             }
549            
550             package Data::ParseBinary::Padding;
551             our @ISA = qw{Data::ParseBinary::BaseConstruct};
552            
553             sub create {
554 30     30   41 my ($class, $count) = @_;
555 30         109 my $self = $class->SUPER::create(undef);
556 30         72 $self->{count_code} = $count;
557 30         136 return $self;
558             }
559            
560             sub _parse {
561 453     453   685 my ($self, $parser, $stream) = @_;
562 453 100       1165 if ($stream->isBitStream()) {
563 16         44 $stream->ReadBits($parser->runCodeRef($self->{count_code}));
564             } else {
565 437         1265 $stream->ReadBytes($parser->runCodeRef($self->{count_code}));
566             }
567             }
568            
569             sub _build {
570 385     385   650 my ($self, $parser, $stream, $data) = @_;
571 385 100       1042 if ($stream->isBitStream()) {
572 18         54 $stream->WriteBits("0" x $parser->runCodeRef($self->{count_code}));
573             } else {
574 367         1057 $stream->WriteBytes("\0" x $parser->runCodeRef($self->{count_code}));
575             }
576             }
577            
578             package Data::ParseBinary::RepeatUntil;
579             our @ISA = qw{Data::ParseBinary::BaseConstruct};
580            
581             sub create {
582 12     12   21 my ($class, $coderef, $sub) = @_;
583 12 50 33     57 die "Empty MetaArray is illigal" unless $sub and $coderef;
584 12 50 33     129 die "MetaArray must have a sub-construct" unless ref $sub and UNIVERSAL::isa($sub, "Data::ParseBinary::BaseConstruct");
585 12 50 33     65 die "MetaArray must have a length code ref" unless ref $coderef and UNIVERSAL::isa($coderef, "CODE");
586 12         53 my $name =$sub->_get_name();
587 12         67 my $self = $class->SUPER::create($name);
588 12         44 $self->{sub} = $sub;
589 12         31 $self->{len_code} = $coderef;
590 12         59 return $self;
591             }
592            
593             sub _shouldStop {
594 434     434   945 my ($self, $parser, $value) = @_;
595 434         998 $parser->set_obj($value);
596 434         1061 my $ret = $parser->runCodeRef($self->{len_code});
597 434         1519 $parser->set_obj(undef);
598 434         1288 return $ret;
599             }
600            
601             sub _parse {
602 30     30   46 my ($self, $parser, $stream) = @_;
603 30         51 my $list = [];
604 30         97 $parser->push_ctx($list);
605 30         40 while (1) {
606 223         601 my $value = $parser->_parse($self->{sub});
607 223         405 push @$list, $value;
608 223 100       438 last if $self->_shouldStop($parser, $value);
609             }
610 30         92 $parser->pop_ctx();
611 30         72 return $list;
612             }
613            
614             sub _build {
615 28     28   60 my ($self, $parser, $stream, $data) = @_;
616 28 50 33     279 die "Invalid Sequence Value" unless defined $data and ref $data and UNIVERSAL::isa($data, "ARRAY");
      33        
617            
618 28         95 $parser->push_ctx($data);
619 28         62 for my $item (@$data) {
620 211         618 $parser->_build($self->{sub}, $item);
621 211 100       646 last if $self->_shouldStop($parser, $item);
622             }
623 28         85 $parser->pop_ctx();
624             }
625            
626             package Data::ParseBinary::MetaArray;
627             our @ISA = qw{Data::ParseBinary::BaseConstruct};
628            
629             sub create {
630 40     40   57 my ($class, $coderef, $sub) = @_;
631 40 50 33     171 die "Empty MetaArray is illigal" unless $sub and $coderef;
632 40 50 33     252 die "MetaArray must have a sub-construct" unless ref $sub and UNIVERSAL::isa($sub, "Data::ParseBinary::BaseConstruct");
633 40 50 33     208 die "MetaArray must have a length code ref" unless ref $coderef and UNIVERSAL::isa($coderef, "CODE");
634 40         138 my $name =$sub->_get_name();
635 40         161 my $self = $class->SUPER::create($name);
636 40         98 $self->{sub} = $sub;
637 40         67 $self->{len_code} = $coderef;
638 40         215 return $self;
639             }
640            
641             sub _parse {
642 166     166   243 my ($self, $parser, $stream) = @_;
643 166         516 my $len = $parser->runCodeRef($self->{len_code});
644 166         402 my $list = [];
645 166         441 $parser->push_ctx($list);
646 166         389 for my $ix (1..$len) {
647 1110         3277 my $value = $parser->_parse($self->{sub});
648 1109         2361 push @$list, $value;
649             }
650 165         471 $parser->pop_ctx();
651 165         408 return $list;
652             }
653            
654             sub _build {
655 137     137   217 my ($self, $parser, $stream, $data) = @_;
656 137 50 33     1020 die "Invalid Sequence Value" unless defined $data and ref $data and UNIVERSAL::isa($data, "ARRAY");
      33        
657 137         411 my $len = $parser->runCodeRef($self->{len_code});
658            
659 137 100       343 die "Invalid Sequence Length (length param is $len, actual input is ".scalar(@$data).")" if @$data != $len;
660 136         358 $parser->push_ctx($data);
661 136         277 for my $item (@$data) {
662 992         3006 $parser->_build($self->{sub}, $item);
663             }
664 136         397 $parser->pop_ctx();
665             }
666            
667             package Data::ParseBinary::Range;
668             our @ISA = qw{Data::ParseBinary::BaseConstruct};
669            
670             sub create {
671 3     3   5 my ($class, $min, $max, $sub) = @_;
672 3 50       12 die "Empty Struct is illigal" unless $sub;
673 3 50 33     21 die "Repeater must have a sub-construct" unless ref $sub and UNIVERSAL::isa($sub, "Data::ParseBinary::BaseConstruct");
674 3         8 my $name =$sub->_get_name();
675 3         32 my $self = $class->SUPER::create($name);
676 3         9 $self->{sub} = $sub;
677 3         5 $self->{max} = $max;
678 3         7 $self->{min} = $min;
679 3         10 return $self;
680             }
681            
682             sub _parse {
683 3     3   7 my ($self, $parser, $stream) = @_;
684 3         6 my $list = [];
685 3         12 $parser->push_ctx($list);
686 3         7 my $max = $self->{max};
687 3 50       10 if (defined $max) {
688 0         0 for my $ix (1..$max) {
689 0         0 my $value;
690 0         0 eval {
691 0         0 $value = $parser->_parse($self->{sub});
692             };
693 0 0       0 if ($@) {
694 0 0       0 die $@ if $ix <= $self->{min};
695 0         0 last;
696             }
697 0         0 push @$list, $value;
698             }
699             } else {
700 3         7 my $ix = 0;
701 3         4 while (1) {
702 88         105 $ix++;
703 88         116 my $value;
704 88         114 eval {
705 88         263 $value = $parser->_parse($self->{sub});
706             };
707 88 100       191 if ($@) {
708 3 50       15 die $@ if $ix <= $self->{min};
709 3         8 last;
710             }
711 85         157 push @$list, $value;
712             }
713             }
714 3         12 $parser->pop_ctx();
715 3         10 return $list;
716             }
717            
718             sub _build {
719 3     3   10 my ($self, $parser, $stream, $data) = @_;
720 3 50 33     42 die "Invalid Sequence Value" unless defined $data and ref $data and UNIVERSAL::isa($data, "ARRAY");
      33        
721 3 50       13 die "Invalid Sequence Length (min)" if @$data < $self->{min};
722 3 50 33     16 die "Invalid Sequence Length (max)" if defined $self->{max} and @$data > $self->{max};
723 3         11 $parser->push_ctx($data);
724 3         8 for my $item (@$data) {
725 85         266 $parser->_build($self->{sub}, $item);
726             }
727 3         13 $parser->pop_ctx();
728             }
729            
730             package Data::ParseBinary::Sequence;
731             our @ISA = qw{Data::ParseBinary::BaseConstruct};
732            
733             sub create {
734 8     8   24 my ($class, $name, @subconstructs) = @_;
735 8 50       46 die "Empty Struct is illigal" unless @subconstructs;
736 8         54 my $self = $class->SUPER::create($name);
737 8         37 $self->{subs} = \@subconstructs;
738 8         49 return $self;
739             }
740            
741             sub _parse {
742 63     63   94 my ($self, $parser, $stream) = @_;
743 63         109 my $list = [];
744 63         177 $parser->push_ctx($list);
745 63         100 foreach my $sub (@{ $self->{subs} }) {
  63         144  
746 161         512 my $name = $sub->_get_name();
747 161         484 my $value = $parser->_parse($sub);
748 160 50       346 next unless defined $name;
749 160         413 push @$list, $value;
750             }
751 62         193 $parser->pop_ctx();
752 62         236 return $list;
753             }
754            
755            
756             sub _build {
757 63     63   108 my ($self, $parser, $stream, $data) = @_;
758 63         78 my $subs_count = @{ $self->{subs} };
  63         117  
759 63 50 33     618 die "Invalid Sequence Value" unless defined $data and ref $data and UNIVERSAL::isa($data, "ARRAY");
      33        
760 63 50       162 die "Invalid Sequence Length" if @$data > $subs_count;
761 63         214 $parser->push_ctx($data);
762 63         177 for my $ix (0..$#$data) {
763 162         294 my $sub = $self->{subs}->[$ix];
764 162         472 my $name = $sub->_get_name();
765 162 50       527 if (defined $name) {
766 162 50       441 die "Invalid Sequence Length" if $ix >= $subs_count;
767 162         498 $parser->_build($sub, $data->[$ix]);
768             } else {
769 0         0 $parser->_build($sub, undef);
770 0         0 redo;
771             }
772             }
773 63         218 $parser->pop_ctx();
774             }
775            
776             sub _size_of {
777 0     0   0 my ($self, $context) = @_;
778 0         0 my $size = 0;
779 0         0 foreach my $sub (@{ $self->{subs} }) {
  0         0  
780 0         0 $size += $sub->_size_of($context);
781             }
782 0         0 return $size;
783             }
784            
785             package Data::ParseBinary::Struct;
786             our @ISA = qw{Data::ParseBinary::BaseConstruct};
787            
788             sub create {
789 102     102   262 my ($class, $name, @subconstructs) = @_;
790 102 50       228 die "Empty Struct is illigal" unless @subconstructs;
791 102         341 my $self = $class->SUPER::create($name);
792 102         217 $self->{subs} = \@subconstructs;
793 102         2070 return $self;
794             }
795            
796            
797             sub _parse {
798 666     666   1007 my ($self, $parser, $stream) = @_;
799 666         1101 my $hash = {};
800 666         2114 $parser->push_ctx($hash);
801 666         799 foreach my $sub (@{ $self->{subs} }) {
  666         1532  
802 4344         11590 my $name = $sub->_get_name();
803 4344         11551 my $value = $parser->_parse($sub);
804 4339 100       9918 next unless defined $name;
805 3874         10838 $hash->{$name} = $value;
806             }
807 661         2284 $parser->pop_ctx();
808 661         1789 return $hash;
809             }
810            
811             sub _build {
812 551     551   829 my ($self, $parser, $stream, $data) = @_;
813 551 50 33     3983 die "Invalid Struct Value" unless defined $data and ref $data and UNIVERSAL::isa($data, "HASH");
      33        
814 551         1676 $parser->push_ctx($data);
815 551         710 foreach my $sub (@{ $self->{subs} }) {
  551         1172  
816 2804         7179 my $name = $sub->_get_name();
817 2804 100       11164 $parser->_build($sub, defined $name? $data->{$name} : undef);
818             }
819 550         1697 $parser->pop_ctx();
820             }
821            
822             sub _size_of {
823 0     0   0 my ($self, $context) = @_;
824 0         0 my $size = 0;
825 0         0 foreach my $sub (@{ $self->{subs} }) {
  0         0  
826 0         0 $size += $sub->_size_of($context);
827             }
828 0         0 return $size;
829             }
830            
831             package Data::ParseBinary::Primitive;
832             our @ISA = qw{Data::ParseBinary::BaseConstruct};
833            
834             sub create {
835 354     354   661 my ($class, $name, $sizeof, $pack_param) = @_;
836 354         1050 my $self = $class->SUPER::create($name);
837 354         612 $self->{sizeof} = $sizeof;
838 354         500 $self->{pack_param} = $pack_param;
839 354         1595 return $self;
840             }
841            
842             sub _parse {
843 4100     4100   5767 my ($self, $parser, $stream) = @_;
844 4100         11442 my $data = $stream->ReadBytes($self->{sizeof});
845 4095         8984 my $number = unpack $self->{pack_param}, $data;
846 4095         11040 return $number;
847             }
848            
849             sub _build {
850 2669     2669   3917 my ($self, $parser, $stream, $data) = @_;
851 2669 50       4962 die "Invalid Primitive Value" unless defined $data;
852             # FIXME and not ref $data;
853 2669         5339 my $string = pack $self->{pack_param}, $data;
854 2669         8011 $stream->WriteBytes($string);
855             }
856            
857             sub _size_of {
858 3     3   6 my ($self, $context) = @_;
859 3         8 return $self->{sizeof};
860             }
861            
862             package Data::ParseBinary::ReveresedPrimitive;
863             our @ISA = qw{Data::ParseBinary::Primitive};
864            
865             sub _parse {
866 0     0     my ($self, $parser, $stream) = @_;
867 0           my $data = $stream->ReadBytes($self->{sizeof});
868 0           my $r_data = join '', reverse split '', $data;
869 0           my $number = unpack $self->{pack_param}, $r_data;
870 0           return $number;
871             }
872            
873             sub _build {
874 0     0     my ($self, $parser, $stream, $data) = @_;
875 0           my $string = pack $self->{pack_param}, $data;
876 0           my $r_string = join '', reverse split '', $string;
877 0           $stream->WriteBytes($r_string);
878             }
879            
880             sub _size_of {
881 0     0     my ($self, $context) = @_;
882 0           return $self->{sizeof};
883             }
884            
885             1;