File Coverage

lib/File/Type/Builder.pm
Criterion Covered Total %
statement 13 80 16.2
branch 0 24 0.0
condition 0 3 0.0
subroutine 4 9 44.4
pod 4 4 100.0
total 21 120 17.5


line stmt bran cond sub pod time code
1             package File::Type::Builder;
2 1     1   611 use strict;
  1         2  
  1         39  
3 1     1   5 use warnings;
  1         2  
  1         30  
4              
5 1     1   5 use IO::File;
  1         2  
  1         1168  
6              
7             our $VERSION = "0.11";
8              
9             sub new {
10 1     1 1 781 my $class = shift;
11 1         2 my $self = {};
12 1         3 bless $self, $class;
13 1         2 return $self;
14             }
15              
16             sub parse_magic {
17 0     0 1   my $self = shift;
18 0           my $data = shift;
19 0           my $line = shift;
20              
21             # storage
22 0           my $parsed = {};
23 0           my $pattern;
24              
25             # offsets
26 0           $data =~ s/^([0-9a-fx]+)\s+//;
27 0           $parsed->{offset} = $1;
28            
29             # pattern type
30 0           $data =~ s/(byte | short | long | string | date | beshort |
31             belong | bedate | leshort | lelong | ledate)(\s+)?//x;
32 0           $parsed->{pattern_type} = $1;
33            
34 0 0         unless ($parsed->{pattern_type} =~ m/^(string|beshort|belong)/) {
35 0           return undef;
36             }
37            
38             # pattern mask, if exists; buggy?
39 0 0         if ($data =~ m/^\&/) {
40             # warn "pattern mask on line $line\n";
41 0           $data =~ s/\&([a-z0-9]+)\s+//;
42 0           $parsed->{pattern_mask} = $1;
43             }
44              
45             # handle pattern. Somewhat complex.
46 0           PARSE: while ($data =~ s/(\s*\S*\s)//) {
47             # add data to pattern. stop unless we've got significant whitespace.
48 0 0         $pattern .= $1 unless $1 =~ m/^\s+$/;
49 0 0         last PARSE unless ($pattern =~ m!\\\s$!);
50             }
51             # then tidy up
52 0 0         return undef unless defined($pattern);
53              
54 0 0         $pattern =~ s/\s*$// unless $pattern =~ m/\\\s$/;
55 0           $pattern =~ s/\\(\s)/$1/g;
56 0           $pattern =~ s/\\$//g;
57 0           $parsed->{pattern} = $pattern;
58            
59             # what's left is the MIME type
60 0           $data =~ s/^\s*(.*)$//;
61 0           $parsed->{mime_type} = $1;
62              
63             # check there's nothing undigested
64 0 0         warn "On line $line, remaining '$data'. Using anyway.\n" if length($data);
65              
66             # check we've got a mime type to return
67 0 0 0       if (!length($parsed->{mime_type})
68             || $parsed->{mime_type} !~ m!^[^/]*/[^/]*$!) {
69             # warn "On line $line, no or improper MIME type: not used\n";
70 0           return undef;
71             }
72              
73 0           return $parsed;
74             }
75              
76             sub string {
77 0     0 1   my $self = shift;
78 0           my $parsed = shift;
79              
80 0           my $escape = $self->_get_escapes();
81              
82             # build a code fragment.
83 0           my $code;
84 0           my $tab = '';
85            
86 0 0         if ($parsed->{offset}) {
87 0           $code = $self->_substr_handling($parsed->{offset}, 1024);
88 0           $tab = ' ';
89              
90             # we have to use substr to advance to the anchor
91 0           $code .= ' if (defined $substr && $substr =~ m[^';
92              
93             } else {
94             # can just anchor normally
95 0           $code = ' if ($data =~ m[^';
96             }
97              
98             # manipulate regex; use File::MMagic code
99 0           my $pattern = $parsed->{pattern};
100              
101             # quote metacharacters
102             # unless ($pattern =~ m!\\x!) {
103 0           $pattern = quotemeta($pattern);
104 0 0         $pattern =~ s/\\\\(.)/$escape->{$1}||$1/eg;
  0            
105             # }
106              
107 0           $code .= $pattern;
108              
109             # close the [] delimited regex and return mime type
110 0           $code .= ']) {';
111 0           $code .= "\n$tab return q{$parsed->{mime_type}};\n$tab }\n";
112              
113 0 0         if ($tab) {
114 0           $code .= "$tab}\n";
115             }
116            
117 0           return $code;
118             }
119              
120             sub be {
121 0     0 1   my $self = shift;
122 0           my $parsed = shift;
123 0           my $length = shift;
124              
125             # build both sides of the conditional
126 0           my $offset = $parsed->{offset};
127 0           my $pattern = $parsed->{pattern};
128              
129             # start with substr handling
130 0           my $code = $self->_substr_handling($offset, $length);
131              
132             # rhs: template
133 0           my $rhs;
134 0 0         if ($pattern =~ s/^0x//) {
135 0           $rhs = "pack('H*', '$pattern')";
136             } else {
137             # warn "Not sure what this magic is";
138 0           return undef;
139             }
140            
141             # build condition
142 0           $code .= " if ($rhs eq ".'$substr ) {';
143 0           $code .= "\n return q{$parsed->{mime_type}};\n }\n }\n";
144            
145 0           return $code;
146             }
147              
148             sub _substr_handling {
149 0     0     my $self = shift;
150 0           my ($offset, $length) = @_;
151            
152 0           my $code = ' if (length $data > '.$offset.") {\n";
153 0           $code .= ' $substr = substr($data, '.$offset.', '.$length.");\n";
154            
155 0           return $code;
156             }
157              
158             sub _get_escapes {
159 0     0     return { n => '\n',
160             r => '\r',
161             b => '\b',
162             t => '\t',
163             f => '\f',
164             x => '\x',
165             0 => '\0',
166             1 => '\1',
167             2 => '\2',
168             3 => '\3',
169             };
170             }
171              
172             1;
173              
174             __END__