File Coverage

blib/lib/Text/PDF/Dict.pm
Criterion Covered Total %
statement 77 158 48.7
branch 24 84 28.5
condition 15 33 45.4
subroutine 9 10 90.0
pod 5 5 100.0
total 130 290 44.8


line stmt bran cond sub pod time code
1             package Text::PDF::Dict;
2              
3 1     1   3 use strict;
  1         1  
  1         27  
4 1     1   2 use vars qw(@ISA $mincache $tempbase $cr);
  1         1  
  1         42  
5             # no warnings qw(uninitialized);
6              
7 1     1   3 use Text::PDF::Objind;
  1         1  
  1         28  
8             @ISA = qw(Text::PDF::Objind);
9              
10             $cr = '(?:\015|\012|(?:\015\012))';
11              
12 1     1   496 use Text::PDF::Filter;
  1         2  
  1         51  
13              
14             BEGIN
15             {
16 1 50 0 1   110 my $temp_dir = -d '/tmp' ? '/tmp' : $ENV{TMP} || $ENV{TEMP};
17 1         10 $tempbase = sprintf("%s/%d-%d-0000", $temp_dir, $$, time());
18 1         1214 $mincache = 32768;
19             }
20              
21             =head1 NAME
22              
23             Text::PDF::Dict - PDF Dictionaries and Streams. Inherits from L
24              
25             =head1 INSTANCE VARIABLES
26              
27             There are various special instance variables which are used to look after,
28             particularly, streams. Each begins with a space:
29              
30             =over
31              
32             =item stream
33              
34             Holds the stream contents for output
35              
36             =item streamfile
37              
38             Holds the stream contents in an external file rather than in memory. This is
39             not the same as a PDF file stream. The data is stored in its unfiltered form.
40              
41             =item streamloc
42              
43             If both ' stream' and ' streamfile' are empty, this indicates where in the
44             source PDF the stream starts.
45              
46             =back
47              
48             =head1 METHODS
49              
50             =cut
51              
52             sub new
53             {
54 10     10 1 11 my ($class, @opts) = @_;
55 10         10 my ($self);
56              
57 10 50       13 $class = ref $class if ref $class;
58 10         25 $self = $class->SUPER::new(@_);
59 10         21 $self->{' realised'} = 1;
60 10         16 return $self;
61             }
62            
63              
64             =head2 $d->outobjdeep($fh)
65              
66             Outputs the contents of the dictionary to a PDF file. This is a recursive call.
67              
68             It also outputs a stream if the dictionary has a stream element. If this occurs
69             then this method will calculate the length of the stream and insert it into the
70             stream's dictionary.
71              
72             =cut
73              
74             sub outobjdeep
75             {
76 8     8 1 17 my ($self, $fh, $pdf, %opts) = @_;
77 8         7 my ($key, $val, $f, @filts);
78 0         0 my ($loc, $str, %specs, $len);
79              
80 8 50 66     43 if (defined $self->{' stream'} or defined $self->{' streamfile'} or defined $self->{' streamloc'})
      66        
81             {
82 1 50 33     6 if ($self->{'Filter'} || !defined $self->{' stream'})
83             {
84 0 0       0 $self->{'Length'} = Text::PDF::Number->new(0) unless (defined $self->{'Length'});
85 0 0       0 $pdf->new_obj($self->{'Length'}) unless ($self->{'Length'}->is_obj($pdf));
86             # $pdf->out_obj($self->{'Length'});
87             }
88             else
89             {
90 1 50       28 $self->{'Length'} = Text::PDF::Number->new(length($self->{' stream'}) + ($self->{' stream'} =~ m/$cr$/o ? 0 : 1));
91             }
92             }
93              
94 8         14 $fh->print("<<\n");
95 8         26 foreach ('Type', 'Subtype')
96             {
97 16         27 $specs{$_} = 1;
98 16 100       25 if (defined $self->{$_})
99             {
100 5         11 $fh->print("/$_ ");
101 5         26 $self->{$_}->outobj($fh, $pdf, %opts);
102 5         29 $fh->print("\n");
103             }
104             }
105 8         11 foreach $key (sort {$a cmp $b} keys %{$self})
  56         47  
  8         27  
106             {
107 39 100 66     125 next if ($key =~ m/^[\s\-]/o || $specs{$key});
108 15         16 $val = $self->{$key};
109 15 50       24 next if ($val eq '');
110 15         25 $key = Text::PDF::Name::string_to_name ($key, $pdf);
111 15         30 $fh->print("/$key ");
112 15         74 $val->outobj($fh, $pdf, %opts);
113 15         70 $fh->print("\n");
114             }
115 8         24 $fh->print('>>');
116              
117             #now handle the stream (if any)
118 8 50 33     31 if (defined $self->{' streamloc'} && !defined $self->{' stream'})
119             { # read a stream if infile
120 0         0 $loc = $fh->tell;
121 0         0 $self->read_stream;
122 0         0 $fh->seek($loc, 0);
123             }
124              
125 8 50 66     49 if (!$self->{' nofilt'}
      33        
      66        
126             && (defined $self->{' stream'} || defined $self->{' streamfile'})
127             && defined $self->{'Filter'})
128             {
129 0         0 my ($hasflate) = -1;
130 0         0 my ($temp, $i, $temp1, @filtlist);
131            
132 0 0       0 if (ref($self->{'Filter'}) eq 'Text::PDF::Name')
133 0         0 { push(@filtlist, $self->{'Filter'}->val); }
134             else
135             {
136 0         0 for ($i = 0; $i < scalar @{$self->{'Filter'}{' val'}}; $i++)
  0         0  
137 0         0 { push (@filtlist, $self->{'Filter'}{' val'}[$i]->val); }
138             }
139 0         0 foreach $temp (@filtlist)
140             {
141 0 0       0 if ($temp eq 'LZWDecode') # hack to get around LZW patent
    0          
142             {
143 0 0       0 if ($hasflate < -1)
144             {
145 0         0 $hasflate = $i;
146 0         0 next;
147             }
148 0         0 $temp = 'FlateDecode';
149 0         0 $self->{'Filter'}{' val'}[$i]{'val'} = $temp; # !!!
150             } elsif ($temp eq 'FlateDecode')
151 0         0 { $hasflate = -2; }
152 0         0 $temp1 = "Text::PDF::$temp";
153 0         0 push (@filts, $temp1->new);
154             }
155 0 0       0 splice(@{$self->{'Filter'}{' val'}}, $hasflate, 1) if ($hasflate > -1);
  0         0  
156             }
157              
158 8 100       27 if (defined $self->{' stream'})
    50          
159             {
160 1         7 $fh->print("\nstream\n");
161 1         5 $loc = $fh->tell;
162 1         4 $str = $self->{' stream'};
163 1 50       24 unless ($self->{' nofilt'})
164             {
165 1         3 foreach $f (reverse @filts)
166 0         0 { $str = $f->outfilt($str, 1); }
167             }
168 1         2 $fh->print($str);
169 1 50       6 if (@filts > 0)
170             {
171 0         0 $len = $fh->tell - $loc + 1;
172 0 0       0 if ($self->{'Length'}{'val'} != $len)
173             {
174 0         0 $self->{'Length'}{'val'} = $len;
175 0 0       0 $pdf->out_obj($self->{'Length'}) if ($self->{'Length'}->is_obj($pdf));
176             }
177             }
178 1 50       21 $fh->print("\n") unless ($str =~ m/$cr$/o);
179 1         6 $fh->print("endstream");
180             # $self->{'Length'}->outobjdeep($fh);
181             } elsif (defined $self->{' streamfile'})
182             {
183 0 0       0 open(DICTFH, $self->{' streamfile'}) || die "Unable to open $self->{' streamfile'}";
184 0         0 binmode DICTFH;
185 0         0 $fh->print("\nstream\n");
186 0         0 $loc = $fh->tell;
187 0         0 while (read(DICTFH, $str, 4096))
188             {
189 0 0       0 unless ($self->{' nofilt'})
190             {
191 0         0 foreach $f (reverse @filts)
192 0         0 { $str = $f->outfilt($str, 0); }
193             }
194 0         0 $fh->print($str);
195             }
196 0         0 close(DICTFH);
197 0 0       0 unless ($self->{' nofilt'})
198             {
199 0         0 $str = '';
200 0         0 foreach $f (reverse @filts)
201 0         0 { $str = $f->outfilt($str, 1); }
202 0         0 $fh->print($str);
203             }
204            
205 0         0 $len = $fh->tell - $loc + 1;
206 0 0       0 if ($self->{'Length'}{'val'} != $len)
207             {
208 0         0 $self->{'Length'}{'val'} = $len;
209 0 0       0 $pdf->out_obj($self->{'Length'}) if ($self->{'Length'}->is_obj($pdf));
210             }
211            
212 0 0       0 $fh->print("\n") unless ($str =~ m/$cr$/o);
213 0         0 $fh->print("endstream\n");
214             # $self->{'Length'}->outobjdeep($fh);
215             }
216             }
217              
218              
219             =head2 $d->read_stream($force_memory)
220              
221             Reads in a stream from a PDF file. If the stream is greater than
222             C (defaults to 32768) bytes to be stored, then
223             the default action is to create a file for it somewhere and to use that
224             file as a data cache. If $force_memory is set, this caching will not
225             occur and the data will all be stored in the $self->{' stream'}
226             variable.
227              
228             =cut
229              
230             sub read_stream
231             {
232 1     1 1 223 my ($self, $force_memory) = @_;
233 1         2 my ($fh) = $self->{' streamsrc'};
234 1         1 my (@filts, $f, $last, $i, $dat);
235 1         4 my ($len) = $self->{'Length'}->val;
236              
237 1         1 $self->{' stream'} = '';
238              
239 1 50       3 if (defined $self->{'Filter'})
240             {
241 0         0 foreach $f ($self->{'Filter'}->elementsof)
242             {
243 0         0 my ($temp) = "Text::PDF::" . $f->val;
244 0         0 push(@filts, $temp->new());
245             }
246             }
247              
248 1         2 $last = 0;
249 1 50       7 if (defined $self->{' streamfile'})
250             {
251 0         0 unlink ($self->{' streamfile'});
252 0         0 $self->{' streamfile'} = undef;
253             }
254 1         4 seek ($fh, $self->{' streamloc'}, 0);
255 1         3 for ($i = 0; $i < $len; $i += 4096)
256             {
257 1 50       3 if ($i + 4096 > $len)
258             {
259 1         2 $last = 1;
260 1         6 read($fh, $dat, $len - $i);
261             }
262             else
263 0         0 { read($fh, $dat, 4096); }
264              
265 1         2 foreach $f (@filts)
266 0         0 { $dat = $f->infilt($dat, $last); }
267 1 50 33     4 if (!$force_memory && !defined $self->{' streamfile'} && ((length($self->{' stream'}) * 2) > $mincache))
      33        
268             {
269 0 0       0 open (DICTFH, ">$tempbase") || next;
270 0         0 binmode DICTFH;
271 0         0 $self->{' streamfile'} = $tempbase;
272 0         0 $tempbase =~ s/-(\d+)$/"-" . ($1 + 1)/oe; # prepare for next use
  0         0  
273 0         0 print DICTFH $self->{' stream'};
274 0         0 undef $self->{' stream'};
275             }
276 1 50       4 if (defined $self->{' streamfile'})
277 0         0 { print DICTFH $dat; }
278             else
279 1         3 { $self->{' stream'} .= $dat; }
280             }
281            
282 1 50       3 close DICTFH if (defined $self->{' streamfile'});
283 1         1 $self->{' nofilt'} = 0;
284 1         3 $self;
285             }
286            
287             =head2 $d->val
288              
289             Returns the dictionary, which is itself.
290              
291             =cut
292              
293             sub val
294 1     1 1 2 { $_[0]; }
295              
296              
297             =head2 $d->copy($inpdf, $res, $unique, $outpdf, %opts)
298              
299             Copies an object. See Text::PDF::Objind::Copy() for details
300              
301             =cut
302              
303             sub copy
304             {
305 0     0 1   my ($self, $inpdf, $res, $unique, $outpdf, %opts) = @_;
306 0           my ($k, $path);
307              
308 0           $res = $self->SUPER::copy($inpdf, $res, $unique, $outpdf, %opts);
309 0           $path = delete $opts{'path'};
310 0           foreach $k (keys %$self)
311             {
312 0 0         next if $self->dont_copy($k);
313 0 0         next if defined $res->{$k};
314 0 0         if (UNIVERSAL::can($self->{$k}, "is_obj"))
315             {
316 0 0         if (grep {"$path/$k" =~ m|$_|} @{$opts{'clip'}})
  0            
  0            
317 0           { $res->{$k} = $self->{$k}; }
318             else
319 0 0         { $res->{$k} = $self->{$k}->realise->copy($inpdf, undef, $unique ? $unique + 1 : 0,
320             $outpdf, %opts, 'path' => "$path/$k"); }
321             }
322             else
323 0           { $res->{$k} = $self->{$k}; }
324             }
325 0           $res;
326             }
327              
328             1;