File Coverage

blib/lib/Mac/Macbinary.pm
Criterion Covered Total %
statement 63 64 98.4
branch 7 10 70.0
condition 3 6 50.0
subroutine 12 12 100.0
pod 1 1 100.0
total 86 93 92.4


line stmt bran cond sub pod time code
1             package Mac::Macbinary;
2              
3 6     6   103846 use strict;
  6         54  
  6         405  
4 6     6   39 use vars qw($VERSION $AUTOLOAD);
  6         14  
  6         566  
5             $VERSION = 0.06;
6              
7 6     6   36 use Carp ();
  6         33  
  6         4888  
8              
9             sub new {
10 5     5 1 262 my($class, $thingy, $attr) = @_;
11 5         30 my $self = bless {
12             validate => $attr->{validate},
13             }, $class;
14              
15 5         28 my $fh = _make_handle($thingy);
16 5         26 $self->_parse_handle($fh);
17 5         72 return $self;
18             }
19              
20             sub _parse_handle {
21 5     5   14 my $self = shift;
22 5         9 my($fh) = @_;
23              
24 5         186 read $fh, my ($header), 128;
25 5         122 $self->{header} = Mac::Macbinary::Header->new($header, {
26             validate => $self->{validate},
27             });
28 5         61 read $fh, $self->{data}, $self->header->dflen;
29              
30 5         34 my $resourceoffset = 128 - (($self->header->dflen) % 128);
31 5         24 read $fh, my($tmp), $resourceoffset;
32 5         55 read $fh, $self->{resource}, $self->header->rflen;
33              
34 5         14 return $self;
35             }
36              
37             sub _make_handle($) {
38 5     5   14 my $thingy = shift;
39              
40 5 100 66     153 if (! ref($thingy) && -f $thingy) {
41 3         4239 require FileHandle;
42 3 50       69463 my $fh = FileHandle->new($thingy) or Carp::croak "$thingy: $!";
43 3         373 return $fh;
44             } else {
45             # tries to read it
46 2         5 eval {
47 2         57 read $thingy, my($tmp), 0;
48             };
49 2 50       10 if ($@) {
50 0         0 Carp::croak "Can't read $thingy!";
51             }
52 2         7 return $thingy;
53             }
54             }
55              
56             sub AUTOLOAD {
57 20     20   72 my $self = shift;
58 20         84 $AUTOLOAD =~ s/.*://o;
59 20         152 return $self->{$AUTOLOAD};
60             }
61              
62              
63             package Mac::Macbinary::Header;
64              
65 6     6   59 use vars qw($AUTOLOAD);
  6         18  
  6         5412  
66              
67             sub new {
68 5     5   21 my($class, $h, $attr) = @_;
69 5         18 my $self = bless { }, $class;
70 5 100       42 if ($attr->{validate}) {
71 1 50       5 $self->_validate_header($h)
72             or Carp::croak "Macbinary validation failed.";
73             }
74 5         24 $self->_parse_header($h);
75 5         15 return $self;
76             }
77              
78             sub _validate_header {
79 1     1   1 my $self = shift;
80 1         2 my($h) = @_;
81              
82             # stolen from Mac::Conversions
83             #
84             # Use a crude heuristic to decide whether or not a file is MacBinary. The
85             # first byte of any MacBinary file must be zero. The second has to be
86             # <= 63 according to the MacBinary II standard. The 122nd and 123rd
87             # each have to be >= 129. This has about a 1/8000 chance of failing on
88             # random bytes. This seems to be all that mcvert does. Unfortunately
89             # we can't also check the checksum because the standard software (Stuffit
90             # Deluxe, etc.) doesn't seem to checksum.
91            
92 1         14 my($zero,
93             $namelength,
94             $filename,
95             $type,
96             $creator,
97             $highflag,
98             $dum1,
99             $dum2,
100             $dum3,
101             $datalength,
102             $reslength,
103             $dum4,
104             $dum5,
105             $dum6,
106             $lowflag,
107             $dum7,
108             $dum8,
109             $version_this,
110             $version_needed,
111             $crc) = unpack("CCA63a4a4CxNnCxNNNNnCx14NnCCN", $h);
112              
113 1   33     17 return (!$zero && (($namelength - 1)< 63)
114             && $version_this >= 129 && $version_needed >= 129);
115             }
116              
117             sub _parse_header {
118 5     5   13 my $self = shift;
119 5         13 my($h) = @_;
120              
121 5         63 $self->{name} = unpack("A*", substr($h, 2, 63));
122 5         23 $self->{type} = unpack("A*", substr($h, 65, 4));
123 5         21 $self->{creator} = unpack("A*", substr($h, 69, 4));
124 5         24 $self->{flags} = unpack("C", substr($h, 73, 1));
125 5         18 $self->{location} = unpack("C", substr($h, 80, 6));
126 5         20 $self->{dflen} = unpack("N", substr($h, 83, 4));
127 5         17 $self->{rflen} = unpack("N", substr($h, 87, 4));
128 5         20 $self->{cdate} = unpack("N", substr($h, 91, 4));
129 5         19 $self->{mdate} = unpack("N", substr($h, 95, 4));
130              
131 5         13 return $self;
132             }
133              
134              
135             sub AUTOLOAD {
136 17     17   26 my $self = shift;
137 17         65 $AUTOLOAD =~ s/.*://o;
138 17         69 return $self->{$AUTOLOAD};
139             }
140              
141             1;
142             __END__