File Coverage

blib/lib/PDF/API3/Compat/API2/Basic/PDF/Dict.pm
Criterion Covered Total %
statement 21 203 10.3
branch 1 94 1.0
condition 0 59 0.0
subroutine 7 12 58.3
pod 4 5 80.0
total 33 373 8.8


line stmt bran cond sub pod time code
1             #=======================================================================
2             # ____ ____ _____ _ ____ ___ ____
3             # | _ \| _ \| ___| _ _ / \ | _ \_ _| |___ \
4             # | |_) | | | | |_ (_) (_) / _ \ | |_) | | __) |
5             # | __/| |_| | _| _ _ / ___ \| __/| | / __/
6             # |_| |____/|_| (_) (_) /_/ \_\_| |___| |_____|
7             #
8             # A Perl Module Chain to faciliate the Creation and Modification
9             # of High-Quality "Portable Document Format (PDF)" Files.
10             #
11             #=======================================================================
12             #
13             # THIS IS A REUSED PERL MODULE, FOR PROPER LICENCING TERMS SEE BELOW:
14             #
15             #
16             # Copyright Martin Hosken
17             #
18             # No warranty or expression of effectiveness, least of all regarding
19             # anyone's safety, is implied in this software or documentation.
20             #
21             # This specific module is licensed under the Perl Artistic License.
22             #
23             #
24             # $Id: Dict.pm,v 2.1 2008/11/04 23:54:51 areibens Exp $
25             #
26             #=======================================================================
27             package PDF::API3::Compat::API2::Basic::PDF::Dict;
28            
29 1     1   5 use strict;
  1         2  
  1         34  
30 1     1   5 use vars qw(@ISA $mincache $tempbase $cr);
  1         2  
  1         77  
31 1     1   6 no warnings qw[ deprecated recursion uninitialized ];
  1         2  
  1         39  
32            
33 1     1   697 use PDF::API3::Compat::API2::Basic::PDF::Objind;
  1         2  
  1         46  
34             @ISA = qw(PDF::API3::Compat::API2::Basic::PDF::Objind);
35            
36             $cr = '(?:\015|\012|(?:\015\012))';
37            
38 1     1   705 use PDF::API3::Compat::API2::Basic::PDF::Filter;
  1         5  
  1         58  
39 1     1   1233 use PDF::API3::Compat::API2::Basic::PDF::Name;
  1         2  
  1         60  
40            
41             BEGIN
42             {
43 1 50 0 1   27 my $temp_dir = -d '/tmp' ? '/tmp' : $ENV{TMP} || $ENV{TEMP};
44 1         19 $tempbase = sprintf("%s/%d-%d-0000", $temp_dir, $$, time());
45 1         2159 $mincache = 32768;
46             }
47            
48             =head1 NAME
49            
50             PDF::API3::Compat::API2::Basic::PDF::Dict - PDF Dictionaries and Streams. Inherits from L
51            
52             =head1 INSTANCE VARIABLES
53            
54             There are various special instance variables which are used to look after,
55             particularly, streams. Each begins with a space:
56            
57             =item stream
58            
59             Holds the stream contents for output
60            
61             =item streamfile
62            
63             Holds the stream contents in an external file rather than in memory. This is
64             not the same as a PDF file stream. The data is stored in its unfiltered form.
65            
66             =item streamloc
67            
68             If both ' stream' and ' streamfile' are empty, this indicates where in the
69             source PDF the stream starts.
70            
71             =head1 METHODS
72            
73             =cut
74            
75             sub new
76             {
77 0     0 1   my ($class, @opts) = @_;
78 0           my ($self);
79            
80 0 0         $class = ref $class if ref $class;
81 0           $self = $class->SUPER::new(@_);
82 0           $self->{' realised'} = 1;
83 0           return $self;
84             }
85            
86            
87             =head2 $d->outobjdeep($fh)
88            
89             Outputs the contents of the dictionary to a PDF file. This is a recursive call.
90            
91             It also outputs a stream if the dictionary has a stream element. If this occurs
92             then this method will calculate the length of the stream and insert it into the
93             stream's dictionary.
94            
95             =cut
96            
97             sub outobjdeep
98             {
99 0     0 1   my ($self, $fh, $pdf, %opts) = @_;
100 0           my ($key, $val, $f, @filts);
101 0           my ($loc, $str, %specs, $len);
102            
103 0 0 0       if (defined $self->{' stream'} or defined $self->{' streamfile'} or defined $self->{' streamloc'})
      0        
104             {
105 0 0 0       if($self->{'Filter'} && $self->{' nofilt'})
    0 0        
106             {
107 0   0       $self->{Length}||= PDF::API3::Compat::API2::Basic::PDF::Number->new(length($self->{' stream'}));
108             }
109             elsif($self->{'Filter'} || !defined $self->{' stream'})
110             {
111 0 0         $self->{'Length'} = PDF::API3::Compat::API2::Basic::PDF::Number->new(0) unless (defined $self->{'Length'});
112 0 0         $pdf->new_obj($self->{'Length'}) unless ($self->{'Length'}->is_obj($pdf));
113             }
114             else
115             {
116 0           $self->{'Length'} = PDF::API3::Compat::API2::Basic::PDF::Number->new(length($self->{' stream'}));
117             ## $self->{'Length'} = PDF::API3::Compat::API2::Basic::PDF::Number->new(length($self->{' stream'}) + 1);
118             ## this old code seams to burp acro6, lets see what breaks next -- fredo
119             }
120             }
121            
122 0           $fh->print("<< ");
123 0           foreach ('Type', 'Subtype')
124             {
125 0           $specs{$_} = 1;
126 0 0         if (defined $self->{$_})
127             {
128 0           $fh->print('/'.PDF::API3::Compat::API2::Basic::PDF::Name::string_to_name($_).' ');
129 0           $self->{$_}->outobj($fh, $pdf, %opts);
130 0           $fh->print(" ");
131             }
132             }
133 0           while (($key, $val) = each %{$self})
  0            
134             {
135 0 0 0       next if ($key =~ m/^[\s\-]/o || $specs{$key});
136 0 0 0       next if (($val || '') eq '');
137 0           $key = PDF::API3::Compat::API2::Basic::PDF::Name::string_to_name ($key, $pdf);
138 0           $fh->print("/$key ");
139 0           $val->outobj($fh, $pdf, %opts);
140 0           $fh->print(" ");
141             }
142 0           $fh->print('>>');
143            
144             #now handle the stream (if any)
145 0 0 0       if (defined $self->{' streamloc'} && !defined $self->{' stream'})
146             { # read a stream if infile
147 0           $loc = $fh->tell;
148 0           $self->read_stream;
149 0           $fh->seek($loc, 0);
150             }
151            
152 0 0 0       if (!$self->{' nofilt'}
      0        
      0        
153             && (defined $self->{' stream'} || defined $self->{' streamfile'})
154             && defined $self->{'Filter'})
155             {
156 0           my ($hasflate) = -1;
157 0           my ($temp, $i, $temp1);
158            
159 0           for ($i = 0; $i < scalar @{$self->{'Filter'}{' val'}}; $i++)
  0            
160             {
161 0           $temp = $self->{'Filter'}{' val'}[$i]->val;
162 0 0         if ($temp eq 'LZWDecode') # hack to get around LZW patent
    0          
163             {
164 0 0         if ($hasflate < -1)
165             {
166 0           $hasflate = $i;
167 0           next;
168             }
169 0           $temp = 'FlateDecode';
170 0           $self->{'Filter'}{' val'}[$i]{'val'} = $temp; # !!!
171             } elsif ($temp eq 'FlateDecode')
172 0           { $hasflate = -2; }
173 0           $temp1 = "PDF::API3::Compat::API2::Basic::PDF::$temp";
174 0           push (@filts, $temp1->new);
175             }
176 0 0         splice(@{$self->{'Filter'}{' val'}}, $hasflate, 1) if ($hasflate > -1);
  0            
177             }
178            
179 0 0         if (defined $self->{' stream'}) {
    0          
180            
181 0           $fh->print(" stream\n");
182 0           $loc = $fh->tell;
183 0           $str = $self->{' stream'};
184 0 0         unless ($self->{' nofilt'})
185             {
186 0           foreach $f (reverse @filts)
187 0           { $str = $f->outfilt($str, 1); }
188             }
189 0           $fh->print($str);
190             ## $fh->print("\n"); # newline goes into endstream
191            
192             } elsif (defined $self->{' streamfile'}) {
193            
194 0 0         open(DICTFH, $self->{' streamfile'}) || die "Unable to open $self->{' streamfile'}";
195 0           binmode(DICTFH,':raw');
196            
197 0           $fh->print(" stream\n");
198 0           $loc = $fh->tell;
199 0           while (read(DICTFH, $str, 4096))
200             {
201 0 0         unless ($self->{' nofilt'})
202             {
203 0           foreach $f (reverse @filts)
204 0           { $str = $f->outfilt($str, 0); }
205             }
206 0           $fh->print($str);
207             }
208 0           close(DICTFH);
209 0 0         unless ($self->{' nofilt'})
210             {
211 0           $str = '';
212 0           foreach $f (reverse @filts)
213 0           { $str = $f->outfilt($str, 1); }
214 0           $fh->print($str);
215             }
216             ## $fh->print("\n"); # newline goes into endstream
217             }
218            
219 0 0 0       if (defined $self->{' stream'} or defined $self->{' streamfile'})
220             {
221 0           $len = $fh->tell - $loc;
222 0 0         if ($self->{'Length'}{'val'} != $len)
223             {
224 0           $self->{'Length'}{'val'} = $len;
225 0 0         $pdf->out_obj($self->{'Length'}) if ($self->{'Length'}->is_obj($pdf));
226             }
227            
228 0           $fh->print("\nendstream"); # next is endobj which has the final cr
229             }
230            
231             }
232            
233             sub outxmldeep
234             {
235 0     0 0   my ($self, $fh, $pdf, %opts) = @_;
236 0           my ($key, $val, $f, @filts);
237 0           my ($loc, $str, %specs, $len);
238            
239 0           $opts{-xmlfh}->print("\n");
240 0           foreach ('Type', 'Subtype')
241             {
242 0           $specs{$_} = 1;
243 0 0         if (defined $self->{$_})
244             {
245 0           $opts{-xmlfh}->print("");
246 0           $self->{$_}->outxml($fh, $pdf, %opts);
247 0           $opts{-xmlfh}->print("\n");
248             }
249             }
250 0           while (($key, $val) = each %{$self})
  0            
251             {
252 0 0 0       next if ($key =~ m/^[\s\-]/o || $specs{$key});
253 0 0         next if ($val eq '');
254 0           $key = PDF::API3::Compat::API2::Basic::PDF::Name::string_to_name ($key, $pdf);
255 0           $opts{-xmlfh}->print("");
256 0           $val->outxml($fh, $pdf, %opts);
257 0           $opts{-xmlfh}->print("\n");
258             }
259 0           $opts{-xmlfh}->print("\n");
260            
261             #now handle the stream (if any)
262 0 0 0       if (defined $self->{' streamloc'} && !defined $self->{' stream'})
263             { # read a stream if infile
264 0           $loc = $fh->tell;
265 0           $self->read_stream;
266 0           $fh->seek($loc, 0);
267             }
268            
269 0 0 0       if (!$self->{' nofilt'}
      0        
      0        
270             && (defined $self->{' stream'} || defined $self->{' streamfile'})
271             && defined $self->{'Filter'})
272             {
273 0           my ($hasflate) = -1;
274 0           my ($temp, $i, $temp1);
275            
276 0           for ($i = 0; $i < scalar @{$self->{'Filter'}{' val'}}; $i++)
  0            
277             {
278 0           $temp = $self->{'Filter'}{' val'}[$i]->val;
279 0 0         if ($temp eq 'LZWDecode') # hack to get around LZW patent
    0          
280             {
281 0 0         if ($hasflate < -1)
282             {
283 0           $hasflate = $i;
284 0           next;
285             }
286 0           $temp = 'FlateDecode';
287 0           $self->{'Filter'}{' val'}[$i]{'val'} = $temp; # !!!
288             } elsif ($temp eq 'FlateDecode')
289 0           { $hasflate = -2; }
290 0           $temp1 = "PDF::API3::Compat::API2::Basic::PDF::$temp";
291 0           push (@filts, $temp1->new);
292             }
293 0 0         splice(@{$self->{'Filter'}{' val'}}, $hasflate, 1) if ($hasflate > -1);
  0            
294             }
295            
296 0 0         if (defined $self->{' stream'})
    0          
297             {
298 0           $opts{-xmlfh}->print("\n");
299 0           $loc = $fh->tell;
300 0           $str = $self->{' stream'};
301 0 0         if ($self->{' nofilt'})
302             {
303 0           foreach $f (@filts)
304 0           { $str = $f->infilt($str, 1); }
305             }
306 0           $opts{-xmlfh}->print($str);
307 0           $opts{-xmlfh}->print("\n");
308             } elsif (defined $self->{' streamfile'})
309             {
310 0           my $DICTFH;
311 0 0         open($DICTFH, $self->{' streamfile'}) || die "Unable to open $self->{' streamfile'}";
312 0           binmode($DICTFH,':raw');
313 0           $opts{-xmlfh}->print("\n");
314 0           while (read($DICTFH, $str, 4096))
315             {
316 0 0         if ($self->{' nofilt'})
317             {
318 0           foreach $f (@filts)
319 0           { $str = $f->infilt($str, 0); }
320             }
321 0           $opts{-xmlfh}->print($str);
322             }
323 0           close($DICTFH);
324 0 0         if ($self->{' nofilt'})
325             {
326 0           $str = '';
327 0           foreach $f (@filts)
328 0           { $str = $f->infilt($str, 1); }
329 0           $opts{-xmlfh}->print($str);
330             }
331            
332 0           $opts{-xmlfh}->print("\n");
333             }
334             }
335            
336            
337             =head2 $d->read_stream($force_memory)
338            
339             Reads in a stream from a PDF file. If the stream is greater than
340             C (defaults to 32768) bytes to be stored, then
341             the default action is to create a file for it somewhere and to use that
342             file as a data cache. If $force_memory is set, this caching will not
343             occur and the data will all be stored in the $self->{' stream'}
344             variable.
345            
346             =cut
347            
348             sub read_stream
349             {
350 0     0 1   my ($self, $force_memory) = @_;
351 0           my ($fh) = $self->{' streamsrc'};
352 0           my (@filts, $f, $last, $i, $dat);
353 0           my ($len) = $self->{'Length'}->val;
354            
355 0           $self->{' stream'} = '';
356            
357 0 0         if (defined $self->{'Filter'})
358             {
359 0           foreach $f ($self->{'Filter'}->elementsof)
360             {
361 0           my ($temp) = "PDF::API3::Compat::API2::Basic::PDF::" . $f->val;
362 0           push(@filts, $temp->new());
363             }
364             }
365            
366 0           $last = 0;
367 0 0         if (defined $self->{' streamfile'})
368             {
369 0           unlink ($self->{' streamfile'});
370 0           $self->{' streamfile'} = undef;
371             }
372 0           seek ($fh, $self->{' streamloc'}, 0);
373 0           for ($i = 0; $i < $len; $i += 4096)
374             {
375 0 0         if ($i + 4096 > $len)
376             {
377 0           $last = 1;
378 0           read($fh, $dat, $len - $i);
379             }
380             else
381 0           { read($fh, $dat, 4096); }
382            
383 0           foreach $f (@filts)
384 0           { $dat = $f->infilt($dat, $last); }
385 0 0 0       if (!$force_memory && !defined $self->{' streamfile'} && ((length($dat) * 2) > $mincache))
      0        
386             {
387 0 0         open (DICTFH, ">$tempbase") || next;
388 0           binmode(DICTFH,':raw');
389 0           $self->{' streamfile'} = $tempbase;
390 0           $tempbase =~ s/-(\d+)$/"-" . ($1 + 1)/oe; # prepare for next use
  0            
391 0           print DICTFH $self->{' stream'};
392 0           undef $self->{' stream'};
393             }
394 0 0         if (defined $self->{' streamfile'})
395 0           { print DICTFH $dat; }
396             else
397 0           { $self->{' stream'} .= $dat; }
398             }
399            
400 0 0         close DICTFH if (defined $self->{' streamfile'});
401 0           $self->{' nofilt'} = 0;
402 0           $self;
403             }
404            
405             =head2 $d->val
406            
407             Returns the dictionary, which is itself.
408            
409             =cut
410            
411             sub val
412 0     0 1   { $_[0]; }
413            
414            
415