File Coverage

blib/lib/Data/ParseBinary/Adapters.pm
Criterion Covered Total %
statement 152 208 73.0
branch 39 82 47.5
condition 15 28 53.5
subroutine 33 39 84.6
pod n/a
total 239 357 66.9


line stmt bran cond sub pod time code
1 5     5   101 use strict;
  5         10  
  5         187  
2 5     5   23 use warnings;
  5         9  
  5         143  
3 5     5   22 use Data::ParseBinary::Core;
  5         10  
  5         15161  
4            
5             package Data::ParseBinary::Enum;
6             our @ISA = qw{Data::ParseBinary::Adapter};
7             # TODO: implement as macro in terms of SymmetricMapping (macro)
8             # that is implemented as MappingAdapter
9            
10             sub _init {
11 29     29   85 my ($self, @params) = @_;
12 29         46 my $decode = {};
13 29         39 my $encode = {};
14 29         44 $self->{have_default} = 0;
15 29         43 $self->{default_action} = undef;
16 29         70 while (@params) {
17 223         241 my $key = shift @params;
18 223         223 my $value = shift @params;
19 223 100       407 if ($key eq '_default_') {
20 14         28 $self->{have_default} = 1;
21 14         19 $self->{default_action} = $value;
22 14 100       37 if (ref $value) {
    50          
23 13 50       42 if ($value != $Data::ParseBinary::BaseConstruct::DefaultPass) {
24 0         0 die "Enum Error: got invalid value as default";
25             }
26             } elsif (exists $encode->{$value}) {
27 0         0 die "Enum Error: $value should not be defined as regular case";
28             } else {
29 1         3 $self->{default_value} = shift @params;
30             }
31 14         39 next;
32             }
33 209         407 $encode->{$key} = $value;
34 209         541 $decode->{$value} = $key;
35             }
36 29         50 $self->{encode} = $encode;
37 29         87 $self->{decode} = $decode;
38             }
39            
40             sub _decode {
41 133     133   211 my ($self, $value) = @_;
42 133 100       411 if (exists $self->{decode}->{$value}) {
43 78         263 return $self->{decode}->{$value};
44             }
45 55 100       138 if ($self->{have_default}) {
46 54 100 66     326 if (ref($self->{default_action}) and $self->{default_action} == $Data::ParseBinary::BaseConstruct::DefaultPass) {
47 53         192 return $value;
48             }
49 1         5 return $self->{default_action};
50             }
51 1         16 die "Enum: unrecognized value $value, and no default defined";
52             }
53            
54             sub _encode {
55 126     126   195 my ($self, $tvalue) = @_;
56 126 100       379 if (exists $self->{encode}->{$tvalue}) {
57 72         726 return $self->{encode}->{$tvalue};
58             }
59 54 50       129 if ($self->{have_default}) {
60 54 100 66     278 if (ref($self->{default_action}) and $self->{default_action} == $Data::ParseBinary::BaseConstruct::DefaultPass) {
61 53         171 return $tvalue;
62             }
63 1         4 return $self->{default_value};
64             }
65 0         0 die "Enum: unrecognized value $tvalue";
66             }
67            
68             package Data::ParseBinary::FlagsEnum;
69             our @ISA = qw{Data::ParseBinary::Adapter};
70            
71             sub _init {
72 4     4   24 my ($self, @mapping) = @_;
73 4         5 my @pairs;
74 4 50       16 die "FlagsEnum: Mapping should be even" if @mapping % 2 == 1;
75 4         12 while (@mapping) {
76 74         75 my $name = shift @mapping;
77 74         66 my $value = shift @mapping;
78 74         181 push @pairs, [$name, $value];
79             }
80 4         14 $self->{pairs} = \@pairs;
81             }
82            
83             sub _decode {
84 15     15   24 my ($self, $value) = @_;
85 15         24 my $hash = {};
86 15         23 foreach my $rec (@{ $self->{pairs} }) {
  15         81  
87 435 100       847 $hash->{$rec->[0]} = 1 if $value & $rec->[1];
88             }
89 15         45 return $hash;
90             }
91            
92             sub _encode {
93 2     2   5 my ($self, $tvalue) = @_;
94 2         4 my $value = 0;
95 2         3 foreach my $rec (@{ $self->{pairs} }) {
  2         6  
96 30 100 66     95 if (exists $tvalue->{$rec->[0]} and $tvalue->{$rec->[0]}) {
97 2         3 $value |= $rec->[1];
98             }
99             }
100 2         6 return $value;
101             }
102            
103             package Data::ParseBinary::ExtractingAdapter;
104             our @ISA = qw{Data::ParseBinary::Adapter};
105            
106             sub _init {
107 5     5   86 my ($self, $sub_name) = @_;
108 5         14 $self->{sub_name} = $sub_name;
109             }
110            
111             sub _decode {
112 29     29   46 my ($self, $value) = @_;
113 29         83 return $value->{$self->{sub_name}};
114             }
115            
116             sub _encode {
117 29     29   43 my ($self, $tvalue) = @_;
118 29         117 return {$self->{sub_name} => $tvalue};
119             }
120            
121             package Data::ParseBinary::IndexingAdapter;
122             our @ISA = qw{Data::ParseBinary::Adapter};
123            
124             sub _init {
125 0     0   0 my ($self, $index) = @_;
126 0   0     0 $self->{index} = $index || 0;
127             }
128            
129             sub _decode {
130 0     0   0 my ($self, $value) = @_;
131 0         0 return $value->[$self->{index}];
132             }
133            
134             sub _encode {
135 0     0   0 my ($self, $tvalue) = @_;
136 0         0 return [ ('') x $self->{index}, $tvalue ];
137             }
138            
139             package Data::ParseBinary::JoinAdapter;
140             our @ISA = qw{Data::ParseBinary::Adapter};
141            
142             sub _decode {
143 40     40   59 my ($self, $value) = @_;
144 40         163 return join '', @$value;
145             }
146            
147             sub _encode {
148 37     37   62 my ($self, $tvalue) = @_;
149 37         306 return [split '', $tvalue];
150             }
151            
152             package Data::ParseBinary::ConstAdapter;
153             our @ISA = qw{Data::ParseBinary::Adapter};
154            
155             sub _init {
156 16     16   23 my ($self, $value) = @_;
157 16         45 $self->{value} = $value;
158             }
159            
160             sub _decode {
161 31     31   54 my ($self, $value) = @_;
162 31 100       123 if (not $value eq $self->{value}) {
163 8         89 die "Const Error: expected $self->{value} got $value";
164             }
165 23         77 return $value;
166             }
167            
168             sub _encode {
169 24     24   47 my ($self, $tvalue) = @_;
170 24 100       70 if (not defined $self->_get_name()) {
171             # if we don't have a name, then just use the value
172 3         14 return $self->{value};
173             }
174 21 100 100     107 if (defined $tvalue and $tvalue eq $self->{value}) {
175 14         54 return $self->{value};
176             }
177 7 100       86 die "Const Error: expected $self->{value} got ". (defined $tvalue ? $tvalue : "undef");
178             }
179            
180            
181             package Data::ParseBinary::LengthValueAdapter;
182             our @ISA = qw{Data::ParseBinary::Adapter};
183            
184             sub _decode {
185 3     3   7 my ($self, $value) = @_;
186 3         9 return $value->[1];
187             }
188            
189             sub _encode {
190 3     3   16 my ($self, $tvalue) = @_;
191 3         11 return [length($tvalue), $tvalue];
192             }
193            
194             package Data::ParseBinary::PaddedStringAdapter;
195             our @ISA = qw{Data::ParseBinary::Adapter};
196            
197             sub _init {
198 4     4   13 my ($self, %params) = @_;
199 4 50       16 if (not defined $params{length}) {
200 0         0 die "PaddedStringAdapter: you must specify length";
201             }
202 4         11 $self->{length} = $params{length};
203 4         8 $self->{encoding} = $params{encoding};
204 4 50       18 $self->{padchar} = defined $params{padchar} ? $params{padchar} : "\x00";
205 4   100     34 $self->{paddir} = $params{paddir} || "right";
206 4   50     23 $self->{trimdir} = $params{trimdir} || "right";
207 4 50       23 if (not grep($_ eq $self->{paddir}, qw{right left center})) {
208 0         0 die "PaddedStringAdapter: paddir should be one of {right left center}";
209             }
210 4 50       29 if (not grep($_ eq $self->{trimdir}, qw{right left})) {
211 0         0 die "PaddedStringAdapter: trimdir should be one of {right left}";
212             }
213             }
214            
215             sub _decode {
216 11     11   23 my ($self, $value) = @_;
217 11         15 my $tvalue = $value;
218 11         25 my $char = $self->{padchar};
219 11 50 33     46 if ($self->{paddir} eq 'right' or $self->{paddir} eq 'center') {
    0 0        
220 11         193 $tvalue =~ s/$char*\z//;
221             } elsif ($self->{paddir} eq 'left' or $self->{paddir} eq 'center') {
222 0         0 $tvalue =~ s/\A$char*//;
223             }
224 11         34 return $tvalue;
225             }
226            
227             sub _encode {
228 2     2   5 my ($self, $tvalue) = @_;
229 2         4 my $value = $tvalue;
230            
231 2 50       24 if (length($value) < $self->{length}) {
232 2         5 my $add = $self->{length} - length($value);
233 2         5 my $char = $self->{padchar};
234 2 50       11 if ($self->{paddir} eq 'right') {
    0          
    0          
235 2         7 $value .= $char x $add;
236             } elsif ($self->{paddir} eq 'left') {
237 0         0 $value = ($char x $add) . $value;
238             } elsif ($self->{paddir} eq 'center') {
239 0         0 my $add_left = $add / 2;
240 0 0       0 my $add_right = $add_left + ($add % 2 == 0 ? 0 : 1);
241 0         0 $value = ($char x $add_left) . $value . ($char x $add_right);
242             }
243             }
244 2 50       11 if (length($value) > $self->{length}) {
245 0         0 my $remove = length($value) - $self->{length};
246 0 0       0 if ($self->{trimdir} eq 'right') {
    0          
247 0         0 substr($value, $self->{length}, $remove, '');
248             } elsif ($self->{trimdir} eq 'left') {
249 0         0 substr($value, 0, $remove, '');
250             }
251             }
252 2         8 return $value;
253             }
254            
255             #package Data::ParseBinary::StringAdapter;
256             #our @ISA = qw{Data::ParseBinary::Adapter};
257             #
258             #sub _init {
259             # my ($self, $encoding) = @_;
260             # $self->{encoding} = $encoding;
261             #}
262             #
263             #sub _decode {
264             # my ($self, $value) = @_;
265             # my $tvalue;
266             # if ($self->{encoding}) {
267             # die "TODO: Should implement different encodings";
268             # } else {
269             # $tvalue = $value;
270             # }
271             # return $tvalue;
272             #}
273             #
274             #sub _encode {
275             # my ($self, $tvalue) = @_;
276             # my $value;
277             # if ($self->{encoding}) {
278             # die "TODO: Should implement different encodings";
279             # } else {
280             # $value = $tvalue;
281             # }
282             # return $value;
283             #}
284            
285             package Data::ParseBinary::CStringAdapter;
286             our @ISA = qw{Data::ParseBinary::Adapter};
287            
288             sub _init {
289 11     11   19 my ($self, $terminators) = @_;
290 11         171 $self->{regex} = qr/[$terminators]*\z/;
291 11         51 $self->{terminator} = substr($terminators, 0, 1);
292             }
293            
294             sub _decode {
295 29     29   50 my ($self, $value) = @_;
296 29         292 $value =~ s/$self->{regex}//;
297 29         85 return $value;
298             }
299            
300             sub _encode {
301 27     27   46 my ($self, $tvalue) = @_;
302 27         240 return $tvalue . $self->{terminator};
303             }
304            
305             package Data::ParseBinary::LamdaValidator;
306             our @ISA = qw{Data::ParseBinary::Validator};
307            
308             sub _init {
309 8     8   15 my ($self, @params) = @_;
310 8         23 $self->{coderef} = shift @params;
311             }
312            
313             sub _validate {
314 8     8   14 my ($self, $value) = @_;
315 8         20 return $self->{coderef}->($value);
316             }
317            
318             package Data::ParseBinary::FirstUnitAndTheRestAdapter;
319             our @ISA = qw{Data::ParseBinary::Adapter};
320             # this adapter move from a length of bytes, to one unit and the rest
321             # as an array
322            
323             sub _init {
324 5     5   10 my ($self, $unit_length, $first_name, $the_rest) = @_;
325 5   50     21 $first_name ||= 'FirstUnit';
326 5   50     19 $the_rest ||= 'TheRest';
327 5         11 $self->{unit_length} = $unit_length;
328 5         8 $self->{first_name} = $first_name;
329 5         14 $self->{the_rest} = $the_rest;
330             }
331            
332             sub _decode {
333 17     17   24 my ($self, $value) = @_;
334 17         30 $value = join('', $value->{$self->{first_name}}, @{ $value->{$self->{the_rest}} } );
  17         42  
335 17         43 return $value;
336             }
337            
338             sub _encode {
339 17     17   25 my ($self, $tvalue) = @_;
340 17         28 my $u_len = $self->{unit_length};
341 17 50       49 die "Length of input should be dividable by unit_length" unless length($tvalue) % $u_len == 0;
342 17         163 my @units = map substr($tvalue, $_*$u_len, $u_len), 0..(length($tvalue) / $u_len - 1);
343 17         34 my $first = shift @units;
344 17         70 my $value = { $self->{first_name} => $first, $self->{the_rest} => \@units };
345 17         51 return $value;
346             }
347            
348             package Data::ParseBinary::CharacterEncodingAdapter;
349             our @ISA = qw{Data::ParseBinary::Adapter};
350            
351             sub _init {
352 9     9   16 my ($self, $encoding) = @_;
353 9         21 $self->{encoding} = $encoding;
354 9         104 require Encode;
355             }
356            
357             sub _decode {
358 23     23   33 my ($self, $octets) = @_;
359 23         74 my $string = Encode::decode($self->{encoding}, $octets);
360 23         636 return $string;
361             }
362            
363             sub _encode {
364 23     23   37 my ($self, $string) = @_;
365 23         73 my $octets = Encode::encode($self->{encoding}, $string);
366 23         134984 return $octets;
367             }
368            
369             package Data::ParseBinary::ExtendedNumberAdapter;
370             our @ISA = qw{Data::ParseBinary::Adapter};
371            
372             sub _init {
373 0     0     my ($self, $is_signed, $is_bigendian) = @_;
374 0           $self->{is_signed} = $is_signed;
375 0           $self->{is_bigendian} = $is_bigendian;
376 0           require Math::BigInt;
377             }
378            
379             sub _decode {
380 0     0     my ($self, $value) = @_;
381 0 0         if (not $self->{is_bigendian}) {
382 0           $value = join '', reverse split '', $value;
383             }
384 0           my $is_negative;
385 0 0         if ($self->{is_signed}) {
386 0           my $first_char = ord($value);
387 0 0         if ($first_char > 127) {
388 0           $value = ~$value;
389 0           $is_negative = 1;
390             }
391             }
392            
393 0           my $hexed = unpack "H*", $value;
394 0           my $number = Math::BigInt->new("0x$hexed");
395 0 0         if ($is_negative) {
396 0           $number->binc()->bneg();
397             }
398 0           return $number;
399             }
400            
401             sub _encode {
402 0     0     my ($self, $number) = @_;
403 0           $number = Math::BigInt->new($number);
404            
405 0           my $is_negative;
406 0 0         if ($self->{is_signed}) {
407 0 0         if ($number->sign() eq '-') {
408 0           $is_negative = 1;
409 0           $number->binc()->babs();
410             }
411             } else {
412 0 0         if ($number->sign() eq '-') {
413 0           die "Was given a negative number for unsigned integer";
414             }
415             }
416            
417 0           my $hexed = $number->as_hex();
418 0           substr($hexed, 0, 2, '');
419 0           my $packed = pack "H*", ("0"x(16-length($hexed))).$hexed;
420 0 0         if ($is_negative) {
421 0           $packed = ~$packed;
422             }
423 0 0         if (not $self->{is_bigendian}) {
424 0           $packed = join '', reverse split '', $packed;
425             }
426 0           return $packed;
427             }
428            
429            
430            
431             1;