File Coverage

blib/lib/Data/ParseBinary/Core.pm
Criterion Covered Total %
statement 163 212 76.8
branch 24 32 75.0
condition 9 10 90.0
subroutine 32 44 72.7
pod n/a
total 228 298 76.5


line stmt bran cond sub pod time code
1 5     5   24 use strict;
  5         8  
  5         150  
2 5     5   23 use warnings;
  5         9  
  5         178  
3            
4             package Data::ParseBinary::BaseConstruct;
5 5     5   24 use Carp qw{confess};
  5         15  
  5         1476556  
6            
7             our $DefaultPass;
8             my $HOOK_BEFORE_ACTION = "HOOK_BEFORE_ACTION";
9             my $HOOK_AFTER_ACTION = "HOOK_AFTER_ACTION";
10             my $OBJECT_STACK = "OBJECT_STACK";
11            
12             sub create {
13 852     852   1069 my ($class, $name) = @_;
14 852         3621 return bless { Name => $name }, $class;
15             }
16            
17             sub _get_name {
18 7832     7832   11501 my $self = shift;
19 7832         22104 return $self->{Name};
20             }
21            
22             sub parse {
23 138     138   3048 my ($self, $data) = @_;
24 138         455 my $stream = Data::ParseBinary::Stream::Reader::CreateStreamReader($data);
25 138         597 my $parser = Data::ParseBinary::Parser->new();
26 138 50       381 if (defined $Data::ParseBinary::print_debug_info) {
27 0         0 my $tab = 0;
28             my $before = sub {
29 0     0   0 my ($loc_parser, $construct) = @_;
30 0         0 print " " x $tab, "Parsing ", $construct->_pretty_name(), "\n";
31 0         0 $tab += 3;
32 0         0 };
33             my $after = sub {
34 0     0   0 $tab -= 3;
35 0         0 };
36 0         0 $parser->{$HOOK_BEFORE_ACTION} = [$before];
37 0         0 $parser->{$HOOK_AFTER_ACTION} = [$after];
38             }
39 138         317 $parser->push_stream($stream);
40 138         200 my $results;
41 138         199 eval {
42 138         371 $results = $parser->_parse($self);
43             };
44 138 100       1056 return $results unless $@;
45 9         38 confess $parser->_informative_exception($@);
46             }
47            
48             sub _parse {
49 0     0   0 my ($self, $parser, $stream) = @_;
50 0         0 die "Bad Shmuel: sub __parse was not implemented for " . ref($self);
51             }
52            
53             sub build {
54 127     127   2501 my ($self, $data, $source_stream) = @_;
55 127         511 my $stream = Data::ParseBinary::Stream::Writer::CreateStreamWriter($source_stream);
56 127         471 my $parser = Data::ParseBinary::Parser->new();
57 127 50       351 if (defined $Data::ParseBinary::print_debug_info) {
58 0         0 my $tab = 0;
59             my $before = sub {
60 0     0   0 my ($loc_parser, $construct, $data) = @_;
61 0         0 print " " x $tab, "Building ", _pretty_name($construct), "\n";
62 0         0 $tab += 3;
63 0         0 };
64             my $after = sub {
65 0     0   0 $tab -= 3;
66 0         0 };
67 0         0 $parser->{$HOOK_BEFORE_ACTION} = [$before];
68 0         0 $parser->{$HOOK_AFTER_ACTION} = [$after];
69             }
70 127         338 $parser->push_stream($stream);
71 127         211 eval {
72 127         466 $parser->_build($self, $data);
73             };
74 127 100       324 confess $parser->_informative_exception($@) if $@;
75 122         421 return $stream->Flush();
76             }
77            
78             sub _pretty_name {
79 18     18   36 my ($self) = @_;
80 18         52 my $name = $self->_get_name();
81 18         32 my $type = ref $self;
82 18         60 $type =~ s/^Data::ParseBinary:://;
83 18   100     61 $name ||= "";
84 18         61 return "$type $name";
85             }
86            
87             sub _build {
88 0     0   0 my ($self, $parser, $stream, $data) = @_;
89 0         0 die "Bad Shmuel: sub _build was not implemented for " . ref($self);
90             }
91            
92             sub _size_of {
93 0     0   0 my ($self, $context) = @_;
94 0         0 die "This Construct (".ref($self).") does not know his own size";
95             }
96            
97             package Data::ParseBinary::WrappingConstruct;
98             our @ISA = qw{Data::ParseBinary::BaseConstruct};
99            
100             sub create {
101 132     132   162 my ($class, $subcon) = @_;
102 132         305 my $self = $class->SUPER::create($subcon->_get_name());
103 132         498 $self->{subcon} = $subcon;
104 132         214 return $self;
105             }
106            
107             sub subcon {
108 0     0   0 my $self = shift;
109 0         0 return $self->{subcon};
110             }
111            
112             sub _parse {
113 631     631   1172 my ($self, $parser, $stream) = @_;
114 631         1508 return $parser->_parse($self->{subcon});
115             }
116            
117             sub _build {
118 396     396   608 my ($self, $parser, $stream, $data) = @_;
119 396         1434 return $parser->_build($self->{subcon}, $data);
120             }
121            
122             sub _size_of {
123 0     0   0 my ($self, $context) = @_;
124 0         0 return $self->{subcon}->_size_of($context);
125             }
126            
127             package Data::ParseBinary::Adapter;
128             our @ISA = qw{Data::ParseBinary::WrappingConstruct};
129            
130             sub create {
131 118     118   289 my ($class, $subcon, @params) = @_;
132 118         319 my $self = $class->SUPER::create($subcon);
133 118         404 $self->_init(@params);
134 118         540 return $self;
135             }
136            
137             sub _init {
138 26     26   52 my ($self, @params) = @_;
139             }
140            
141             sub _parse {
142 631     631   2045 my ($self, $parser, $stream) = @_;
143 631         1466 my $value = $self->SUPER::_parse($parser, $stream);
144 630         2133 my $tvalue = $self->_decode($value);
145 619         2026 return $tvalue;
146             }
147            
148             sub _build {
149 405     405   656 my ($self, $parser, $stream, $data) = @_;
150 405         1849 my $value = $self->_encode($data);
151 396         1989 $self->SUPER::_build($parser, $stream, $value);
152             }
153            
154             sub _decode {
155 0     0   0 my ($self, $value) = @_;
156 0         0 die "An Adapter class should override the _decode sub";
157             #my $tvalue = transform($value);
158             #return $tvalue;
159             }
160            
161             sub _encode {
162 0     0   0 my ($self, $tvalue) = @_;
163 0         0 die "An Adapter class should override the _decode sub";
164             #my $value = transform($tvalue);
165             #return $value;
166             }
167            
168             package Data::ParseBinary::Validator;
169             our @ISA = qw{Data::ParseBinary::Adapter};
170            
171             sub _decode {
172 4     4   7 my ($self, $value) = @_;
173 4 100       15 die "Validator error at " . $self->_get_name() unless $self->_validate($value);
174 2         5 return $value;
175             }
176            
177             sub _encode {
178 4     4   8 my ($self, $tvalue) = @_;
179 4 100       10 die "Validator error at " . $self->_get_name() unless $self->_validate($tvalue);
180 2         5 return $tvalue;
181             }
182            
183             sub _validate {
184 0     0   0 my ($self, $value) = @_;
185 0         0 die "An Validator class should override the _validate sub";
186             }
187            
188             package Data::ParseBinary::Parser;
189            
190             my $EVALS = 'EVAL_MARKER';
191            
192             sub new {
193 265     265   363 my ($class) = @_;
194 265         1943 return bless {ctx=>[], obj=>undef, $EVALS=>[], $OBJECT_STACK=>[] }, $class;
195             }
196            
197             sub obj {
198 434     434   821 my $self = shift;
199 434         1836 return $self->{obj};
200             }
201            
202             sub set_obj {
203 868     868   1348 my ($self, $new_obj) = @_;
204 868         2834 $self->{obj} = $new_obj;
205             }
206            
207             sub ctx {
208 844     844   1405 my ($self, $level) = @_;
209 844   100     2926 $level ||= 0;
210 844 50       963 die "Parser: ctx level $level does not exists" if $level >= scalar @{ $self->{ctx} };
  844         2290  
211 844         3659 return $self->{ctx}->[$level];
212             }
213            
214             sub push_ctx {
215 1734     1734   2481 my ($self, $new_ctx) = @_;
216 1734         6298 unshift @{ $self->{ctx} }, $new_ctx;
  1734         5387  
217             }
218            
219             sub pop_ctx {
220 1726     1726   2367 my $self = shift;
221 1726         1842 return shift @{ $self->{ctx} };
  1726         4634  
222             }
223            
224             sub push_stream {
225 340     340   462 my ($self, $new_stream) = @_;
226 340         403 unshift @{ $self->{streams} }, $new_stream;
  340         1123  
227             }
228            
229             sub pop_stream {
230 14     14   19 my $self = shift;
231 14         20 return shift @{ $self->{streams} };
  14         36  
232             }
233            
234             sub stream {
235 165     165   208 my $self = shift;
236 165         618 return $self->{streams}->[0];
237             }
238            
239             sub eval_enter {
240 24     24   33 my ($self) = @_;
241 24         26 my $streams_count = @{ $self->{streams} };
  24         44  
242 24         31 my $objects_count = @{ $self->{$OBJECT_STACK} };
  24         39  
243 24         73 my $eval_rec = { stream_count => $streams_count, objects_count => $objects_count };
244 24         27 push @{ $self->{$EVALS} }, $eval_rec;
  24         74  
245             }
246            
247             sub eval_leave {
248 24     24   29 my ($self) = @_;
249 24         26 my $eval_rec = pop @{ $self->{$EVALS} };
  24         49  
250 24         38 my $streams_count = $eval_rec->{stream_count};
251 24 50       23 if ($streams_count < @{ $self->{streams} }) {
  24         72  
252 0         0 splice( @{ $self->{streams} }, 0, @{ $self->{streams} } - $streams_count, ());
  0         0  
  0         0  
253             }
254 24         37 my $objects_count = $eval_rec->{objects_count};
255 24 100       26 if ($objects_count < @{ $self->{$OBJECT_STACK} }) {
  24         84  
256 12         22 splice( @{ $self->{$OBJECT_STACK} }, $objects_count, @{ $self->{$OBJECT_STACK} } - $objects_count, ());
  12         26  
  12         53  
257             }
258             }
259            
260             sub _build {
261 4925     4925   7964 my ($self, $construct, $data) = @_;
262 4925         6450 my $streams_count = @{ $self->{streams} };
  4925         9462  
263 4925         5650 push @{ $self->{$OBJECT_STACK} }, $construct;
  4925         9227  
264 4925 50       13389 if (exists $self->{$HOOK_BEFORE_ACTION}) {
265 0         0 foreach my $hba ( @{ $self->{$HOOK_BEFORE_ACTION} } ) {
  0         0  
266 0         0 $hba->($self, $construct, $data);
267             }
268             }
269            
270 4925         18972 $construct->_build($self, $self->{streams}->[0], $data);
271            
272 4913 50       12096 if (exists $self->{$HOOK_AFTER_ACTION}) {
273 0         0 foreach my $hba ( @{ $self->{$HOOK_AFTER_ACTION} } ) {
  0         0  
274 0         0 $hba->($self, $construct, undef);
275             }
276             }
277 4913         5776 pop @{ $self->{$OBJECT_STACK} };
  4913         8656  
278 4913 100       5849 if ($streams_count < @{ $self->{streams} }) {
  4913         20731  
279 29         41 splice( @{ $self->{streams} }, 0, @{ $self->{streams} } - $streams_count, ());
  29         134  
  29         137  
280             }
281             }
282            
283             sub _parse {
284 6885     6885   9333 my ($self, $construct) = @_;
285 6885         9442 my $streams_count = @{ $self->{streams} };
  6885         11843  
286 6885         8515 push @{ $self->{$OBJECT_STACK} }, $construct;
  6885         182729  
287 6885 50       17285 if (exists $self->{$HOOK_BEFORE_ACTION}) {
288 0         0 foreach my $hba ( @{ $self->{$HOOK_BEFORE_ACTION} } ) {
  0         0  
289 0         0 $hba->($self, $construct, undef);
290             }
291             }
292            
293 6885         21325 my $data = $construct->_parse($self, $self->{streams}->[0]);
294            
295 6859 50       25423 if (exists $self->{$HOOK_AFTER_ACTION}) {
296 0         0 foreach my $hba ( @{ $self->{$HOOK_AFTER_ACTION} } ) {
  0         0  
297 0         0 $hba->($self, $construct, $data);
298             }
299             }
300 6859         7231 pop @{ $self->{$OBJECT_STACK} };
  6859         13602  
301 6859 100       8259 if ($streams_count < @{ $self->{streams} }) {
  6859         16242  
302 32         45 splice( @{ $self->{streams} }, 0, @{ $self->{streams} } - $streams_count, ());
  32         64  
  32         72  
303             }
304 6859         18191 return $data;
305             }
306            
307             sub _informative_exception {
308 14     14   29 my ($self, $msg) = @_;
309 14         96 $msg =~ s/ at (.*)//;
310 14         43 my $ex = "Got Exception $msg\n";
311 14         125 $ex .= "Streams location:\n";
312 14         21 my $ix = 1;
313 14         19 foreach my $stream ( @{ $self->{streams} } ) {
  14         35  
314 14         27 my $stream_ref = ref $stream;
315 14         52 $stream_ref =~ s/^Data\:\:ParseBinary\:\:Stream\:\://;
316 14         95 $ex .= "$ix: Stream " . $stream_ref . " in byte #" . $stream->tell() . "\n";
317 14         43 $ix++;
318             }
319 14         27 $ex .= "Constructs Stack:\n";
320 14         23 $ix = 1;
321 14         21 foreach my $object (reverse @{ $self->{$OBJECT_STACK} }) {
  14         35  
322 18         116 $ex .= "$ix: " . $object->_pretty_name() . "\n";
323 18         38 $ix++;
324             }
325 14         2857 return $ex;
326             }
327            
328             sub runCodeRef {
329 2068     2068   2976 my ($self, $coderef) = @_;
330 2068 100 100     15327 if (not ($coderef and ref($coderef) and UNIVERSAL::isa($coderef, "CODE"))) {
      66        
331 776         3320 return $coderef;
332             }
333 1292         1947 local $_ = $self;
334 1292         4451 return $coderef->();
335             }
336            
337             1;