File Coverage

blib/lib/Text/PDF/Dict.pm
Criterion Covered Total %
statement 75 156 48.0
branch 24 84 28.5
condition 15 33 45.4
subroutine 9 10 90.0
pod 5 5 100.0
total 128 288 44.4


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