File Coverage

blib/lib/Parse/Binary/Iterative.pm
Criterion Covered Total %
statement 18 18 100.0
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 24 24 100.0


line stmt bran cond sub pod time code
1             package Parse::Binary::Iterative;
2 1     1   19185 use 5.006;
  1         5  
  1         40  
3 1     1   4 use strict;
  1         1  
  1         35  
4 1     1   4 no strict 'refs';
  1         6  
  1         29  
5 1     1   5 use warnings;
  1         1  
  1         35  
6 1     1   5 use Carp;
  1         2  
  1         112  
7             our $VERSION = '1.00';
8 1     1   4 use base qw(Class::Data::Inheritable Class::Accessor);
  1         1  
  1         1725  
9             use UNIVERSAL::require;
10              
11             __PACKAGE__->mk_accessors("parent");
12             __PACKAGE__->mk_classdata($_) for ("FORMAT", "init_done");
13             __PACKAGE__->init_done(0);
14             __PACKAGE__->FORMAT([ Data => "a*" ]);
15              
16             sub new {
17             my ($class, $data) = @_;
18             $class->_init();
19             my $self = bless { }, $class;
20              
21             # Now call all the readers in turn
22             my @format = @{$class->FORMAT};
23             while (my ($key, $val) = splice(@format, 0, 2)) {
24             my $method = "read_$key";
25             $self->$method($data);
26             }
27             return $self;
28             }
29              
30             sub _init {
31             my $class = shift;
32             return if $class->init_done();
33             $class->init_done(1);
34             my @format = @{$class->FORMAT};
35             while (my ($key, $val) = splice(@format, 0, 2)) {
36             $class->mk_ro_accessors($key);
37             $class->mk_reader($key, $val);
38             }
39             }
40              
41             sub mk_reader {
42             my ($class, $key, $pattern) = @_;
43            
44             *{"${class}::read_".$key} = sub {
45             my ($self, $data) = @_;
46             my @things;
47             if (ref $pattern) { # XXX We need to do stuff with @$pattern
48             if (@{$pattern} == 2 and ref $pattern->[1] eq "CODE") {
49             my $p1 = $pattern->[0];
50             @things = $pattern->[1]->(
51             unpack($p1, $class->_extract($p1, $data))
52             );
53             } else {
54             my $key_class = $key;
55             $key_class =~ s/_/::/g; $key_class->require;
56             @things = $key_class->new($data);
57             $_->parent($self) for @things;
58             }
59             } else {
60             @things = unpack($pattern, $class->_extract($pattern, $data))
61             }
62             $self->{$key} = @things == 1 ? $things[0] : \@things;
63             }
64             }
65              
66             sub _extract {
67             my ($self, $pattern, $data) = @_;
68             if ($pattern =~ /\*/) { local $/; my $x = <$data>; return $x };
69              
70             my $len = length(pack($pattern, 0));
71             if (ref $data eq "SCALAR") {
72             return substr($$data, 0, $len, "");
73             } elsif (ref $data eq "GLOB" or UNIVERSAL::isa($data, "IO::Handle")) {
74             my $buf;
75             croak "Run out of data!" if !read(*$data, $buf, $len) == $len;
76             return $buf;
77             } else {
78             croak "Can't read from data handle, don't know what it is";
79             }
80             }
81             1;
82             __END__