line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::PDF::File; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Text::PDF::File - Holds the trailers and cross-reference tables for a PDF file |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
$p = Text::PDF::File->open("filename.pdf", 1); |
10
|
|
|
|
|
|
|
$p->new_obj($obj_ref); |
11
|
|
|
|
|
|
|
$p->free_obj($obj_ref); |
12
|
|
|
|
|
|
|
$p->append_file; |
13
|
|
|
|
|
|
|
$p->close_file; |
14
|
|
|
|
|
|
|
$p->release; # IMPORTANT! |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 DESCRIPTION |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
This class keeps track of the directory aspects of a PDF file. There are two |
19
|
|
|
|
|
|
|
parts to the directory: the main directory object which is the parent to all |
20
|
|
|
|
|
|
|
other objects and a chain of cross-reference tables and corresponding trailer |
21
|
|
|
|
|
|
|
dictionaries starting with the main directory object. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 INSTANCE VARIABLES |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
Within this class hierarchy, rather than making everything visible via methods, |
26
|
|
|
|
|
|
|
which would be a lot of work, there are various instance variables which are |
27
|
|
|
|
|
|
|
accessible via associative array referencing. To distinguish instance variables |
28
|
|
|
|
|
|
|
from content variables (which may come from the PDF content itself), each such |
29
|
|
|
|
|
|
|
variable will start with a space. |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
Variables which do not start with a space directly reflect elements in a PDF |
32
|
|
|
|
|
|
|
dictionary. In the case of a Text::PDF::File, the elements reflect those in the |
33
|
|
|
|
|
|
|
trailer dictionary. |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
Since some variables are not designed for class users to access, variables are |
36
|
|
|
|
|
|
|
marked in the documentation with (R) to indicate that such an entry should only |
37
|
|
|
|
|
|
|
be used as read-only information. (P) indicates that the information is private |
38
|
|
|
|
|
|
|
and not designed for user use at all, but is included in the documentation for |
39
|
|
|
|
|
|
|
completeness and to ensure that nobody else tries to use it. |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=over |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=item newroot |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
This variable allows the user to create a new root entry to occur in the trailer |
46
|
|
|
|
|
|
|
dictionary which is output when the file is written or appended. If you wish to |
47
|
|
|
|
|
|
|
over-ride the root element in the dictionary you have, use this entry to indicate |
48
|
|
|
|
|
|
|
that without losing the current Root entry. Notice that newroot should point to |
49
|
|
|
|
|
|
|
a PDF level object and not just to a dictionary which does not have object status. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=item INFILE (R) |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
Contains the filehandle used to read this information into this PDF directory. Is |
54
|
|
|
|
|
|
|
an IO object. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=item fname (R) |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
This is the filename which is reflected by INFILE, or the original IO object passed |
59
|
|
|
|
|
|
|
in. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=item update (R) |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
This indicates that the read file has been opened for update and that at some |
64
|
|
|
|
|
|
|
point, $p->appendfile() can be called to update the file with the changes that |
65
|
|
|
|
|
|
|
have been made to the memory representation. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=item maxobj (R) |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
Contains the first useable object number above any that have already appeared |
70
|
|
|
|
|
|
|
in the file so far. |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=item outlist (P) |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
This is a list of Objind which are to be output when the next appendfile or outfile |
75
|
|
|
|
|
|
|
occurs. |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=item firstfree (P) |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
Contains the first free object in the free object list. Free objects are removed |
80
|
|
|
|
|
|
|
from the front of the list and added to the end. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=item lastfree (P) |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
Contains the last free object in the free list. It may be the same as the firstfree |
85
|
|
|
|
|
|
|
if there is only one free object. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=item objcache (P) |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
All objects are held in the cache to ensure that a system only has one occurrence of |
90
|
|
|
|
|
|
|
each object. In effect, the objind class acts as a container type class to hold the |
91
|
|
|
|
|
|
|
PDF object structure and it would be unfortunate if there were two identical |
92
|
|
|
|
|
|
|
place-holders floating around a system. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=item epos (P) |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
The end location of the read-file. |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=back |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
Each trailer dictionary contains a number of private instance variables which |
101
|
|
|
|
|
|
|
hold the chain together. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=over |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=item loc (P) |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
Contains the location of the start of the cross-reference table preceding the |
108
|
|
|
|
|
|
|
trailer. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item xref (P) |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
Contains an anonymous array of each cross-reference table entry. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=item prev (P) |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
A reference to the previous table. Note this differs from the Prev entry which |
117
|
|
|
|
|
|
|
is in PDF which contains the location of the previous cross-reference table. |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=back |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head1 METHODS |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=cut |
124
|
|
|
|
|
|
|
|
125
|
1
|
|
|
1
|
|
9919
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
24
|
|
126
|
1
|
|
|
1
|
|
3
|
no strict "refs"; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
22
|
|
127
|
1
|
|
|
1
|
|
2
|
use vars qw($cr $irreg_char $reg_char $ws_char $delim_char %types $VERSION); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
72
|
|
128
|
|
|
|
|
|
|
# no warnings qw(uninitialized); |
129
|
|
|
|
|
|
|
|
130
|
1
|
|
|
1
|
|
393
|
use IO::File; |
|
1
|
|
|
|
|
6261
|
|
|
1
|
|
|
|
|
103
|
|
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# Now for the basic PDF types |
133
|
1
|
|
|
1
|
|
314
|
use Text::PDF::Utils; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
63
|
|
134
|
|
|
|
|
|
|
|
135
|
1
|
|
|
1
|
|
4
|
use Text::PDF::Array; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
14
|
|
136
|
1
|
|
|
1
|
|
3
|
use Text::PDF::Bool; |
|
1
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
14
|
|
137
|
1
|
|
|
1
|
|
3
|
use Text::PDF::Dict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
12
|
|
138
|
1
|
|
|
1
|
|
3
|
use Text::PDF::Name; |
|
1
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
11
|
|
139
|
1
|
|
|
1
|
|
3
|
use Text::PDF::Number; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
10
|
|
140
|
1
|
|
|
1
|
|
3
|
use Text::PDF::Objind; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
9
|
|
141
|
1
|
|
|
1
|
|
3
|
use Text::PDF::String; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
10
|
|
142
|
1
|
|
|
1
|
|
310
|
use Text::PDF::Page; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
21
|
|
143
|
1
|
|
|
1
|
|
4
|
use Text::PDF::Pages; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
11
|
|
144
|
1
|
|
|
1
|
|
295
|
use Text::PDF::Null; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
103
|
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# VERSION now taken from Text::PDF.pm |
147
|
|
|
|
|
|
|
#$VERSION = "0.27"; # MJPH 15-MAY-2006 Fix minor bug in Pages.pm |
148
|
|
|
|
|
|
|
#$VERSION = "0.26"; # MJPH 19-MAY-2005 Get a release out! |
149
|
|
|
|
|
|
|
#$VERSION = "0.25"; # MJPH 20-JAN-2003 fix realised in read_obj x y R, fix Text::PDF::Pages::add_page |
150
|
|
|
|
|
|
|
#$VERSION = "0.24"; # MJPH 28-AUG-2002 out_obj may call new_obj |
151
|
|
|
|
|
|
|
#$VERSION = "0.23"; # MJPH 14-AUG-2002 Fix MANIFEST |
152
|
|
|
|
|
|
|
#$VERSION = "0.22"; # MJPH 26-JUL-2002 Add Text::PDF::File::copy, tidy up update(), sort out out_trailer |
153
|
|
|
|
|
|
|
# Fix to not remove string final CRs when reading dictionaries |
154
|
|
|
|
|
|
|
#$VERSION = "0.21"; # GJ 8-JUN-2002 Tidy up regexps, add Text::PDF::Null |
155
|
|
|
|
|
|
|
#$VERSION = "0.20"; # MJPH 27-APR-2002 $trailer->{'Size'} becomes max num objects, fix line end problem, |
156
|
|
|
|
|
|
|
# remove warnings, update release code |
157
|
|
|
|
|
|
|
#$VERSION = "0.19"; # MJPH 5-FEB-2002 fix hex keys and ASCII85 filter |
158
|
|
|
|
|
|
|
#$VERSION = "0.18"; # MJPH 1-DEC-2001 add encryption hooks |
159
|
|
|
|
|
|
|
#$VERSION = "0.17"; # GST 18-JUL-2001 Handle \) in strings and tidy up endobj handling, no uninitialized warnings |
160
|
|
|
|
|
|
|
#$VERSION = "0.16"; # GST 18-JUL-2001 Major performance tweaks |
161
|
|
|
|
|
|
|
#$VERSION = "0.15"; # GST 30-MAY-2001 Memory leaks fixed |
162
|
|
|
|
|
|
|
#$VERSION = "0.14"; # MJPH 2-MAY-2001 More little bug fixes, added read_objnum |
163
|
|
|
|
|
|
|
#$VERSION = "0.13"; # MJPH 23-MAR-2001 General bug fix release |
164
|
|
|
|
|
|
|
#$VERSION = "0.12"; # MJPH 29-JUL-2000 Add font subsetting, random page insertion |
165
|
|
|
|
|
|
|
#$VERSION = "0.11"; # MJPH 18-JUL-2000 Add pdfstamp.plx and more debugging |
166
|
|
|
|
|
|
|
#$VERSION = "0.10"; # MJPH 27-JUN-2000 Tidy up some bugs - names |
167
|
|
|
|
|
|
|
#$VERSION = "0.09"; # MJPH 31-MAR-2000 Copy trailer dictionary properly |
168
|
|
|
|
|
|
|
#$VERSION = "0.08"; # MJPH 07-FEB-2000 Add null element |
169
|
|
|
|
|
|
|
#$VERSION = "0.07"; # MJPH 01-DEC-1999 Debug for pdfbklt |
170
|
|
|
|
|
|
|
#$VERSION = "0.06"; # MJPH 11-SEP-1999 Sort out unixisms |
171
|
|
|
|
|
|
|
#$VERSION = "0.05"; # MJPH 9-SEP-1999 Add ship_out |
172
|
|
|
|
|
|
|
#$VERSION = "0.04"; # MJPH 14-JUL-1999 Correct paths for tarball release |
173
|
|
|
|
|
|
|
#$VERSION = "0.03"; # MJPH 14-JUL-1999 Correct paths for tarball release |
174
|
|
|
|
|
|
|
#$VERSION = "0.02"; # MJPH 30-JUN-1999 Transfer from old library |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
BEGIN |
177
|
|
|
|
|
|
|
{ |
178
|
1
|
|
|
1
|
|
1
|
my ($t, $type); |
179
|
|
|
|
|
|
|
|
180
|
1
|
|
|
|
|
1
|
$ws_char = '[ \t\r\n\f\0]'; |
181
|
1
|
|
|
|
|
1
|
$delim_char = '[][<>{}()/%]'; |
182
|
1
|
|
|
|
|
1
|
$reg_char = '[^][<>{}()/% \t\r\n\f\0]'; |
183
|
1
|
|
|
|
|
1
|
$irreg_char = '[][<>{}()/% \t\r\n\f\0]'; |
184
|
1
|
|
|
|
|
2
|
$cr = "$ws_char*(?:\015|\012|(?:\015\012))"; |
185
|
|
|
|
|
|
|
|
186
|
1
|
|
|
|
|
3
|
%types = ( |
187
|
|
|
|
|
|
|
'Page' => 'Text::PDF::Page', |
188
|
|
|
|
|
|
|
'Pages' => 'Text::PDF::Pages' |
189
|
|
|
|
|
|
|
); |
190
|
|
|
|
|
|
|
|
191
|
1
|
|
|
|
|
2
|
foreach $type (keys %types) |
192
|
|
|
|
|
|
|
{ |
193
|
2
|
|
|
|
|
4
|
$t = $types{$type}; |
194
|
2
|
|
|
|
|
4
|
$t =~ s|::|/|og; |
195
|
2
|
|
|
|
|
3724
|
require "$t.pm"; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 Text::PDF::File->new |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
Creates a new, empty file object which can act as the host to other PDF objects. |
203
|
|
|
|
|
|
|
Since there is no file associated with this object, it is assumed that the |
204
|
|
|
|
|
|
|
object is created in readiness for creating a new PDF file. |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=cut |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub new |
209
|
|
|
|
|
|
|
{ |
210
|
1
|
|
|
1
|
1
|
327
|
my ($class, $root) = @_; |
211
|
1
|
|
|
|
|
4
|
my ($self) = $class->_new; |
212
|
|
|
|
|
|
|
|
213
|
1
|
50
|
|
|
|
3
|
unless ($root) |
214
|
|
|
|
|
|
|
{ |
215
|
1
|
|
|
|
|
4
|
$root = PDFDict(); |
216
|
1
|
|
|
|
|
3
|
$root->{'Type'} = PDFName("Catalog"); |
217
|
|
|
|
|
|
|
} |
218
|
1
|
|
|
|
|
3
|
$self->new_obj($root); |
219
|
1
|
|
|
|
|
3
|
$self->{'Root'} = $root; |
220
|
1
|
|
|
|
|
3
|
$self; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head2 $p = Text::PDF::File->open($filename, $update) |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
Opens the file and reads all the trailers and cross reference tables to build |
227
|
|
|
|
|
|
|
a complete directory of objects. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
$update specifies whether this file is being opened for updating and editing, |
230
|
|
|
|
|
|
|
or simply to be read. |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
$filename may be an IO object |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=cut |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub open |
237
|
|
|
|
|
|
|
{ |
238
|
1
|
|
|
1
|
1
|
323
|
my ($class, $fname, $update) = @_; |
239
|
1
|
|
|
|
|
2
|
my ($self, $buf, $xpos, $end, $tdict, $k); |
240
|
0
|
|
|
|
|
0
|
my ($fh); |
241
|
|
|
|
|
|
|
|
242
|
1
|
|
|
|
|
2
|
$self = $class->_new; |
243
|
1
|
50
|
|
|
|
3
|
if (ref $fname) |
244
|
|
|
|
|
|
|
{ |
245
|
0
|
|
|
|
|
0
|
$self->{' INFILE'} = $fname; |
246
|
0
|
|
|
|
|
0
|
$fh = $fname; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
else |
249
|
|
|
|
|
|
|
{ |
250
|
1
|
|
50
|
|
|
5
|
$fh = IO::File->new(($update ? "+" : "") . "<$fname") || return undef; |
251
|
1
|
|
|
|
|
48
|
$self->{' INFILE'} = $fh; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
1
|
|
|
|
|
2
|
binmode $fh; |
255
|
1
|
50
|
|
|
|
3
|
if ($update) |
256
|
|
|
|
|
|
|
{ |
257
|
0
|
|
|
|
|
0
|
$self->{' update'} = 1; |
258
|
0
|
|
|
|
|
0
|
$self->{' OUTFILE'} = $fh; |
259
|
0
|
|
|
|
|
0
|
$self->{' fname'} = $fname; |
260
|
|
|
|
|
|
|
} |
261
|
1
|
|
|
|
|
7
|
$fh->read($buf, 255); |
262
|
1
|
50
|
|
|
|
61
|
if ($buf !~ m/^\%pdf\-1\.(\d)\s*$cr/moi) |
263
|
0
|
|
|
|
|
0
|
{ die "$fname not a PDF file version 1.x"; } |
264
|
|
|
|
|
|
|
else |
265
|
1
|
|
|
|
|
6
|
{ $self->{' Version'} = $1; } |
266
|
|
|
|
|
|
|
|
267
|
1
|
|
|
|
|
12
|
$fh->seek(0, 2); # go to end of file |
268
|
1
|
|
|
|
|
10
|
$end = $fh->tell(); |
269
|
1
|
|
|
|
|
5
|
$self->{' epos'} = $end; |
270
|
1
|
50
|
|
|
|
4
|
if (!$fh->seek(($end > 1024 ? $end - 1024 : 0, 0))) |
|
|
50
|
|
|
|
|
|
271
|
0
|
|
|
|
|
0
|
{ die "Seek failed when reading PDF file $fname"; } |
272
|
1
|
|
|
|
|
7
|
$fh->read($buf, 1024); |
273
|
1
|
50
|
|
|
|
48
|
if ($buf !~ m/startxref$cr([0-9]+)$cr\%\%eof.*?$/oi) |
274
|
0
|
|
|
|
|
0
|
{ die "Malformed PDF file $fname"; } |
275
|
1
|
|
|
|
|
2
|
$xpos = $1; |
276
|
|
|
|
|
|
|
|
277
|
1
|
|
|
|
|
3
|
$tdict = $self->readxrtr($xpos, $self); |
278
|
1
|
|
|
|
|
1
|
foreach $k (keys %{$tdict}) |
|
1
|
|
|
|
|
4
|
|
279
|
5
|
|
|
|
|
5
|
{ $self->{$k} = $tdict->{$k}; } |
280
|
1
|
|
|
|
|
5
|
return $self; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=head2 $p->release() |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
Releases ALL of the memory used by the PDF document and all of its component |
286
|
|
|
|
|
|
|
objects. After calling this method, do B expect to have anything left in |
287
|
|
|
|
|
|
|
the C object (so if you need to save, be sure to do it before |
288
|
|
|
|
|
|
|
calling this method). |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
B, that it is important that you call this method on any |
291
|
|
|
|
|
|
|
C object when you wish to destruct it and free up its memory. |
292
|
|
|
|
|
|
|
Internally, PDF files have an enormous number of cross-references and this |
293
|
|
|
|
|
|
|
causes circular references within the internal data structures. Calling |
294
|
|
|
|
|
|
|
'C' forces a brute-force cleanup of the data structures, freeing up |
295
|
|
|
|
|
|
|
all of the memory. Once you've called this method, though, don't expect to be |
296
|
|
|
|
|
|
|
able to do anything else with the C object; it'll have B |
297
|
|
|
|
|
|
|
internal state whatsoever. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
B As part of the brute-force cleanup done here, this method |
300
|
|
|
|
|
|
|
will throw a warning message whenever unexpected key values are found within |
301
|
|
|
|
|
|
|
the C object. This is done to help ensure that any unexpected |
302
|
|
|
|
|
|
|
and unfreed values are brought to your attention so that you can bug us to keep |
303
|
|
|
|
|
|
|
the module updated properly; otherwise the potential for memory leaks due to |
304
|
|
|
|
|
|
|
dangling circular references will exist. |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=cut |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub release |
309
|
|
|
|
|
|
|
{ |
310
|
4
|
|
|
4
|
1
|
11
|
my ($self, $force) = @_; |
311
|
4
|
|
|
|
|
4
|
my (@tofree); |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# first, close the input file if it is still open |
314
|
4
|
|
|
|
|
18
|
close($self->{' INFILE'}); |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# delete stuff that we know we can, here |
317
|
|
|
|
|
|
|
|
318
|
4
|
50
|
|
|
|
8
|
if ($force) |
319
|
|
|
|
|
|
|
{ |
320
|
0
|
|
|
|
|
0
|
foreach my $key (keys %{$self}) |
|
0
|
|
|
|
|
0
|
|
321
|
|
|
|
|
|
|
{ |
322
|
0
|
|
|
|
|
0
|
push(@tofree,$self->{$key}); |
323
|
0
|
|
|
|
|
0
|
$self->{$key}=undef; |
324
|
0
|
|
|
|
|
0
|
delete($self->{$key}); |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
else |
328
|
4
|
|
|
|
|
3
|
{ @tofree = map { delete $self->{$_} } keys %{$self}; } |
|
26
|
|
|
|
|
25
|
|
|
4
|
|
|
|
|
13
|
|
329
|
|
|
|
|
|
|
|
330
|
4
|
|
|
|
|
11
|
while (my $item = shift @tofree) |
331
|
|
|
|
|
|
|
{ |
332
|
31
|
|
|
|
|
28
|
my $ref = ref($item); |
333
|
31
|
100
|
|
|
|
124
|
if (UNIVERSAL::can($item, 'release')) |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
334
|
8
|
|
|
|
|
14
|
{ $item->release($force); } |
335
|
|
|
|
|
|
|
elsif ($ref eq 'ARRAY') |
336
|
4
|
|
|
|
|
3
|
{ push( @tofree, @{$item} ); } |
|
4
|
|
|
|
|
8
|
|
337
|
|
|
|
|
|
|
elsif (UNIVERSAL::isa($ref, 'HASH')) |
338
|
0
|
|
|
|
|
0
|
{ release($item, $force); } |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# check that everything has gone - it better had! |
342
|
4
|
|
|
|
|
4
|
foreach my $key (keys %{$self}) |
|
4
|
|
|
|
|
10
|
|
343
|
0
|
|
|
|
|
0
|
{ warn ref($self) . " still has '$key' key left after release.\n"; } |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=head2 $p->append_file() |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
Appends the objects for output to the read file and then appends the appropriate tale. |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=cut |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
sub append_file |
353
|
|
|
|
|
|
|
{ |
354
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
355
|
0
|
|
|
|
|
0
|
my ($tdict, $fh, $t); |
356
|
|
|
|
|
|
|
|
357
|
0
|
0
|
|
|
|
0
|
return undef unless ($self->{' update'}); |
358
|
|
|
|
|
|
|
|
359
|
0
|
|
|
|
|
0
|
$fh = $self->{' INFILE'}; |
360
|
0
|
0
|
|
|
|
0
|
if ($self->{' version'} > $self->{' Version'}) |
361
|
|
|
|
|
|
|
{ |
362
|
0
|
|
|
|
|
0
|
$fh->seek(0,0); |
363
|
0
|
|
|
|
|
0
|
$fh->print("%PDF-1.$self->{' version'}\n"); |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
0
|
|
|
|
|
0
|
$tdict = PDFDict(); |
367
|
0
|
|
|
|
|
0
|
$tdict->{'Prev'} = PDFNum($self->{' loc'}); |
368
|
0
|
|
|
|
|
0
|
$tdict->{'Info'} = $self->{'Info'}; |
369
|
0
|
0
|
|
|
|
0
|
if (defined $self->{' newroot'}) |
370
|
0
|
|
|
|
|
0
|
{ $tdict->{'Root'} = $self->{' newroot'}; } |
371
|
|
|
|
|
|
|
else |
372
|
0
|
|
|
|
|
0
|
{ $tdict->{'Root'} = $self->{'Root'}; } |
373
|
0
|
|
|
|
|
0
|
$tdict->{'Size'} = $self->{'Size'}; |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# added v0.09 |
376
|
0
|
|
|
|
|
0
|
foreach $t (grep ($_ !~ m/^[\s\-]/o, keys %$self)) |
377
|
0
|
0
|
|
|
|
0
|
{ $tdict->{$t} = $self->{$t} unless defined $tdict->{$t}; } |
378
|
|
|
|
|
|
|
|
379
|
0
|
|
|
|
|
0
|
$fh->seek($self->{' epos'}, 0); |
380
|
0
|
|
|
|
|
0
|
$self->out_trailer($tdict, $self->{' update'}); |
381
|
0
|
|
|
|
|
0
|
close($self->{' OUTFILE'}); |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head2 $p->out_file($fname) |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
Writes a PDF file to a file of the given filename based on the current list of |
388
|
|
|
|
|
|
|
objects to be output. It creates the trailer dictionary based on information |
389
|
|
|
|
|
|
|
in $self. |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
$fname may be an IO object; |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=cut |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub out_file |
396
|
|
|
|
|
|
|
{ |
397
|
1
|
|
|
1
|
1
|
4
|
my ($self, $fname) = @_; |
398
|
|
|
|
|
|
|
|
399
|
1
|
|
|
|
|
4
|
$self->create_file($fname); |
400
|
1
|
|
|
|
|
2
|
$self->close_file; |
401
|
1
|
|
|
|
|
2
|
$self; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=head2 $p->create_file($fname) |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
Creates a new output file (no check is made of an existing open file) of |
408
|
|
|
|
|
|
|
the given filename or IO object. Note, make sure that $p->{' version'} is set |
409
|
|
|
|
|
|
|
correctly before calling this function. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=cut |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
sub create_file |
414
|
|
|
|
|
|
|
{ |
415
|
1
|
|
|
1
|
1
|
1
|
my ($self, $fname) = @_; |
416
|
1
|
|
|
|
|
1
|
my ($fh); |
417
|
|
|
|
|
|
|
|
418
|
1
|
|
|
|
|
2
|
$self->{' fname'} = $fname; |
419
|
1
|
50
|
|
|
|
2
|
if (ref $fname) |
420
|
0
|
|
|
|
|
0
|
{ $fh = $fname; } |
421
|
|
|
|
|
|
|
else |
422
|
|
|
|
|
|
|
{ |
423
|
1
|
|
50
|
|
|
7
|
$fh = IO::File->new(">$fname") || die "Unable to open $fname for writing"; |
424
|
1
|
|
|
|
|
126
|
binmode $fh; |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
|
427
|
1
|
|
|
|
|
2
|
$self->{' OUTFILE'} = $fh; |
428
|
1
|
|
50
|
|
|
11
|
$fh->print('%PDF-1.' . ($self->{' version'} || '2') . "\n"); |
429
|
1
|
|
|
|
|
12
|
$fh->print("%Ç쏢\n"); # and some binary stuff in a comment |
430
|
1
|
|
|
|
|
3
|
$self; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=head2 $p->close_file |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
Closes up the open file for output by outputting the trailer etc. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=cut |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
sub close_file |
441
|
|
|
|
|
|
|
{ |
442
|
1
|
|
|
1
|
1
|
2
|
my ($self) = @_; |
443
|
1
|
|
|
|
|
1
|
my ($fh, $tdict, $t); |
444
|
|
|
|
|
|
|
|
445
|
1
|
|
|
|
|
2
|
$tdict = PDFDict(); |
446
|
1
|
50
|
|
|
|
3
|
$tdict->{'Info'} = $self->{'Info'} if defined $self->{'Info'}; |
447
|
1
|
50
|
33
|
|
|
7
|
$tdict->{'Root'} = (defined $self->{' newroot'} and $self->{' newroot'} ne "") ? $self->{' newroot'} : $self->{'Root'}; |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
# remove all freed objects from the outlist, AND the outlist_cache if not updating |
450
|
|
|
|
|
|
|
# NO! Don't do that thing! In fact, let out_trailer do the opposite! |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
|
453
|
1
|
|
33
|
|
|
3
|
$tdict->{'Size'} = $self->{'Size'} || PDFNum(1); |
454
|
1
|
50
|
|
|
|
6
|
$tdict->{'Prev'} = PDFNum($self->{' loc'}) if ($self->{' loc'}); |
455
|
1
|
50
|
|
|
|
3
|
if ($self->{' update'}) |
456
|
|
|
|
|
|
|
{ |
457
|
0
|
|
|
|
|
0
|
foreach $t (grep ($_ !~ m/^[\s\-]/o, keys %$self)) |
458
|
0
|
0
|
|
|
|
0
|
{ $tdict->{$t} = $self->{$t} unless defined $tdict->{$t}; } |
459
|
|
|
|
|
|
|
|
460
|
0
|
|
|
|
|
0
|
$fh = $self->{' INFILE'}; |
461
|
0
|
|
|
|
|
0
|
$fh->seek($self->{' epos'}, 0); |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
1
|
|
|
|
|
7
|
$self->out_trailer($tdict, $self->{' update'}); |
465
|
1
|
|
|
|
|
22
|
close($self->{' OUTFILE'}); |
466
|
|
|
|
|
|
|
MacPerl::SetFileInfo("CARO", "TEXT", $self->{' fname'}) |
467
|
1
|
50
|
33
|
|
|
7
|
if ($^O eq "MacOS" && !ref($self->{' fname'})); |
468
|
1
|
|
|
|
|
8
|
$self; |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=head2 ($value, $str) = $p->readval($str, %opts) |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
Reads a PDF value from the current position in the file. If $str is too short |
474
|
|
|
|
|
|
|
then read some more from the current location in the file until the whole object |
475
|
|
|
|
|
|
|
is read. This is a recursive call which may slurp in a whole big stream (unprocessed). |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
Returns the recursive data structure read and also the current $str that has been |
478
|
|
|
|
|
|
|
read from the file. |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=cut |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub readval |
483
|
|
|
|
|
|
|
{ |
484
|
6
|
|
|
6
|
1
|
296
|
my ($self, $str, %opts) = @_; |
485
|
6
|
|
|
|
|
13
|
my ($fh) = $self->{' INFILE'}; |
486
|
6
|
|
|
|
|
3
|
my ($res, $key, $value, $k); |
487
|
|
|
|
|
|
|
|
488
|
6
|
|
|
|
|
9
|
$str = update($fh, $str); |
489
|
|
|
|
|
|
|
|
490
|
6
|
100
|
|
|
|
136
|
if ($str =~ m/^<
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
491
|
|
|
|
|
|
|
{ |
492
|
2
|
|
|
|
|
4
|
$str = substr ($str, 2); |
493
|
2
|
|
|
|
|
4
|
$str = update($fh, $str); |
494
|
2
|
|
|
|
|
7
|
$res = PDFDict(); |
495
|
|
|
|
|
|
|
|
496
|
2
|
|
|
|
|
6
|
while ($str !~ m/^>>/o) |
497
|
|
|
|
|
|
|
{ |
498
|
3
|
50
|
|
|
|
26
|
if ($str =~ s|^/($reg_char+)||o) |
499
|
|
|
|
|
|
|
{ |
500
|
3
|
|
|
|
|
8
|
$k = Text::PDF::Name::name_to_string ($1, $self); |
501
|
3
|
|
|
|
|
32
|
($value, $str) = $self->readval($str, %opts); |
502
|
3
|
|
|
|
|
6
|
$res->{$k} = $value; |
503
|
|
|
|
|
|
|
} |
504
|
3
|
|
|
|
|
5
|
$str = update($fh, $str); # thanks gareth.jones@stud.man.ac.uk |
505
|
|
|
|
|
|
|
} |
506
|
2
|
|
|
|
|
4
|
$str =~ s/^>>//o; |
507
|
2
|
|
|
|
|
4
|
$str = update($fh, $str); |
508
|
|
|
|
|
|
|
# streams can't be followed by a lone carriage-return. |
509
|
2
|
100
|
66
|
|
|
13
|
if (($str =~ s/^stream(?:(?:\015\012)|\012)//o) |
510
|
|
|
|
|
|
|
&& ($res->{'Length'}->val != 0)) # stream |
511
|
|
|
|
|
|
|
{ |
512
|
1
|
|
|
|
|
3
|
$k = $res->{'Length'}->val; |
513
|
1
|
|
|
|
|
2
|
$res->{' streamsrc'} = $fh; |
514
|
1
|
|
|
|
|
4
|
$res->{' streamloc'} = $fh->tell - length($str); |
515
|
1
|
50
|
|
|
|
6
|
unless ($opts{'nostreams'}) |
516
|
|
|
|
|
|
|
{ |
517
|
1
|
50
|
|
|
|
4
|
if ($k > length($str)) |
518
|
|
|
|
|
|
|
{ |
519
|
0
|
|
|
|
|
0
|
$value = $str; |
520
|
0
|
|
|
|
|
0
|
$k -= length($str); |
521
|
0
|
|
|
|
|
0
|
read ($fh, $str, $k + 11); # slurp the whole stream! |
522
|
|
|
|
|
|
|
} else |
523
|
1
|
|
|
|
|
1
|
{ $value = ''; } |
524
|
1
|
|
|
|
|
3
|
$value .= substr($str, 0, $k); |
525
|
1
|
|
|
|
|
2
|
$res->{' stream'} = $value; |
526
|
1
|
|
|
|
|
1
|
$res->{' nofilt'} = 1; |
527
|
1
|
|
|
|
|
2
|
$str = update($fh, $str); |
528
|
1
|
|
|
|
|
2
|
$str =~ s/^endstream//o; |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
|
532
|
2
|
50
|
33
|
|
|
10
|
if (defined $res->{'Type'} && defined $types{$res->{'Type'}->val}) |
533
|
|
|
|
|
|
|
{ |
534
|
0
|
|
|
|
|
0
|
bless $res, $types{$res->{'Type'}->val}; |
535
|
0
|
|
|
|
|
0
|
$res->init($self); |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
# gdj: FIXME: if any of the ws chars were crs, then the whole |
538
|
|
|
|
|
|
|
# string might not have been read. |
539
|
|
|
|
|
|
|
} elsif ($str =~ m/^([0-9]+)$ws_char+([0-9]+)$ws_char+R/so) # objind |
540
|
|
|
|
|
|
|
{ |
541
|
1
|
|
|
|
|
4
|
$k = $1; |
542
|
1
|
|
|
|
|
2
|
$value = $2; |
543
|
1
|
|
|
|
|
24
|
$str =~ s/^([0-9]+)$ws_char+([0-9]+)$ws_char+R//so; |
544
|
1
|
50
|
|
|
|
3
|
unless ($res = $self->test_obj($k, $value)) |
545
|
|
|
|
|
|
|
{ |
546
|
1
|
|
|
|
|
5
|
$res = Text::PDF::Objind->new(); |
547
|
1
|
|
|
|
|
5
|
$res->{' objnum'} = $k; |
548
|
1
|
|
|
|
|
2
|
$res->{' objgen'} = $value; |
549
|
1
|
|
|
|
|
1
|
$res->{' realised'} = 0; |
550
|
1
|
|
|
|
|
2
|
$res->{' parent'} = $self; |
551
|
1
|
|
|
|
|
2
|
$self->add_obj($res, $k, $value); |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
# gdj: FIXME: if any of the ws chars were crs, then the whole |
554
|
|
|
|
|
|
|
# string might not have been read. |
555
|
|
|
|
|
|
|
} elsif ($str =~ m/^([0-9]+)$ws_char+([0-9]+)$ws_char+obj/so) # object data |
556
|
|
|
|
|
|
|
{ |
557
|
1
|
|
|
|
|
2
|
my ($obj); |
558
|
1
|
|
|
|
|
3
|
$k = $1; |
559
|
1
|
|
|
|
|
3
|
$value = $2; |
560
|
1
|
|
|
|
|
28
|
$str =~ s/^([0-9]+)$ws_char+([0-9]+)$ws_char+obj//so; |
561
|
1
|
|
|
|
|
5
|
($obj, $str) = $self->readval($str, %opts, 'objnum' => $k, 'objgen' => $value); |
562
|
1
|
50
|
|
|
|
3
|
if ($res = $self->test_obj($k, $value)) |
563
|
0
|
|
|
|
|
0
|
{ $res->merge($obj); } |
564
|
|
|
|
|
|
|
else |
565
|
|
|
|
|
|
|
{ |
566
|
1
|
|
|
|
|
1
|
$res = $obj; |
567
|
1
|
|
|
|
|
9
|
$self->add_obj($res, $k, $value); |
568
|
1
|
|
|
|
|
1
|
$res->{' realised'} = 1; |
569
|
|
|
|
|
|
|
} |
570
|
1
|
|
|
|
|
2
|
$str = update($fh, $str); # thanks to kundrat@kundrat.sk |
571
|
1
|
|
|
|
|
2
|
$str =~ s/^endobj//o; |
572
|
|
|
|
|
|
|
} elsif ($str =~ m|^/($reg_char+)|so) # name |
573
|
|
|
|
|
|
|
{ |
574
|
|
|
|
|
|
|
# " <- Fix colourization |
575
|
0
|
|
|
|
|
0
|
$value = $1; |
576
|
0
|
|
|
|
|
0
|
$str =~ s|^/($reg_char+)||so; |
577
|
0
|
|
|
|
|
0
|
$res = Text::PDF::Name->from_pdf($value, $self); |
578
|
|
|
|
|
|
|
} elsif ($str =~ m/^\(/o) # literal string |
579
|
|
|
|
|
|
|
{ |
580
|
0
|
|
|
|
|
0
|
$str =~ s/^\(//o; |
581
|
|
|
|
|
|
|
# We now need to find an unbalanced, unescaped right-paren. |
582
|
|
|
|
|
|
|
# This can't be done with regexps. |
583
|
0
|
|
|
|
|
0
|
my ($value) = ""; |
584
|
|
|
|
|
|
|
# The current level of nesting, when this reaches 0 we have finished. |
585
|
0
|
|
|
|
|
0
|
my ($nested) = 1; |
586
|
0
|
|
|
|
|
0
|
while (1) { |
587
|
|
|
|
|
|
|
# Remove everything up to the first (possibly escaped) paren. |
588
|
0
|
|
|
|
|
0
|
$str =~ /^((?:[^\\()]|\\[^()])*)(.*)/so; |
589
|
0
|
|
|
|
|
0
|
$value .= $1; |
590
|
0
|
|
|
|
|
0
|
$str = $2; |
591
|
|
|
|
|
|
|
|
592
|
0
|
0
|
|
|
|
0
|
if ($str =~ /^(\\[()])/o) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# An escaped paren. This would be tricky to do with |
594
|
|
|
|
|
|
|
# the regexp above (it's very difficult to be certain |
595
|
|
|
|
|
|
|
# that all cases are covered so I think it's better to |
596
|
|
|
|
|
|
|
# deal with them explicitly). |
597
|
0
|
|
|
|
|
0
|
$str = substr ($str, 2); |
598
|
0
|
|
|
|
|
0
|
$value = $value . $1; |
599
|
|
|
|
|
|
|
} elsif ($str =~ /^\)/o) { |
600
|
|
|
|
|
|
|
# Right paren |
601
|
0
|
|
|
|
|
0
|
$nested--; |
602
|
0
|
|
|
|
|
0
|
$str = substr ($str, 1); |
603
|
0
|
0
|
|
|
|
0
|
if ($nested == 0) |
604
|
0
|
|
|
|
|
0
|
{ last; } |
605
|
0
|
|
|
|
|
0
|
$value = $value . ')'; |
606
|
|
|
|
|
|
|
} elsif ($str =~ /^\(/o) { |
607
|
|
|
|
|
|
|
# Left paren |
608
|
0
|
|
|
|
|
0
|
$nested++; |
609
|
0
|
|
|
|
|
0
|
$str = substr ($str, 1); |
610
|
0
|
|
|
|
|
0
|
$value = $value . '('; |
611
|
|
|
|
|
|
|
} else { |
612
|
|
|
|
|
|
|
# No parens, we must read more. We don't use update |
613
|
|
|
|
|
|
|
# because we don't want to remove whitespace or |
614
|
|
|
|
|
|
|
# comments. |
615
|
0
|
0
|
|
|
|
0
|
$fh->read($str, 255, length($str)) or die "Unterminated string."; |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
|
619
|
0
|
|
|
|
|
0
|
$res = Text::PDF::String->from_pdf($value); |
620
|
|
|
|
|
|
|
} elsif ($str =~ m/^
|
621
|
|
|
|
|
|
|
{ |
622
|
0
|
|
|
|
|
0
|
$str =~ s/^/o; |
623
|
0
|
|
|
|
|
0
|
$fh->read($str, 255, length($str)) while (0 > index( $str, '>' )); |
624
|
0
|
|
|
|
|
0
|
($value, $str) = ($str =~ /^(.*?)>(.*?)$/so); |
625
|
0
|
|
|
|
|
0
|
$res = Text::PDF::String->from_pdf("<" . $value . ">"); |
626
|
|
|
|
|
|
|
} elsif ($str =~ m/^\[/o) # array |
627
|
|
|
|
|
|
|
{ |
628
|
0
|
|
|
|
|
0
|
$str =~ s/^\[//o; |
629
|
0
|
|
|
|
|
0
|
$str = update($fh, $str); |
630
|
0
|
|
|
|
|
0
|
$res = PDFArray(); |
631
|
0
|
|
|
|
|
0
|
while ($str !~ m/^\]/o) |
632
|
|
|
|
|
|
|
{ |
633
|
0
|
|
|
|
|
0
|
($value, $str) = $self->readval($str, %opts); |
634
|
0
|
|
|
|
|
0
|
$res->add_elements($value); |
635
|
0
|
|
|
|
|
0
|
$str = update($fh, $str); |
636
|
|
|
|
|
|
|
} |
637
|
0
|
|
|
|
|
0
|
$str =~ s/^\]//o; |
638
|
|
|
|
|
|
|
} elsif ($str =~ m/^(true|false)$irreg_char/o) # boolean |
639
|
|
|
|
|
|
|
{ |
640
|
0
|
|
|
|
|
0
|
$value = $1; |
641
|
0
|
|
|
|
|
0
|
$str =~ s/^(?:true|false)//o; |
642
|
0
|
|
|
|
|
0
|
$res = Text::PDF::Bool->from_pdf($value); |
643
|
|
|
|
|
|
|
} elsif ($str =~ m/^([+-.0-9]+)$irreg_char/o) # number |
644
|
|
|
|
|
|
|
{ |
645
|
2
|
|
|
|
|
4
|
$value = $1; |
646
|
2
|
|
|
|
|
5
|
$str =~ s/^([+-.0-9]+)//o; |
647
|
2
|
|
|
|
|
11
|
$res = Text::PDF::Number->from_pdf($value); |
648
|
|
|
|
|
|
|
} elsif ($str =~ m/^null$irreg_char/o) |
649
|
|
|
|
|
|
|
{ |
650
|
0
|
|
|
|
|
0
|
$str =~ s/^null//o; |
651
|
0
|
|
|
|
|
0
|
$res = Text::PDF::Null->new; |
652
|
|
|
|
|
|
|
} else |
653
|
|
|
|
|
|
|
{ |
654
|
0
|
|
|
|
|
0
|
die "Can't parse `$str' near " . ($fh->tell()) . " length " . length($str) . "."; |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
|
657
|
6
|
|
|
|
|
27
|
$str =~ s/^$ws_char*//os; |
658
|
6
|
|
|
|
|
15
|
return ($res, $str); |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=head2 $ref = $p->read_obj($objind, %opts) |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
Given an indirect object reference, locate it and read the object returning |
665
|
|
|
|
|
|
|
the read in object. |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=cut |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
sub read_obj |
670
|
|
|
|
|
|
|
{ |
671
|
0
|
|
|
0
|
1
|
0
|
my ($self, $objind, %opts) = @_; |
672
|
0
|
|
|
|
|
0
|
my ($loc, $res, $str, $oldloc); |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
# return ($objind) if $self->{' objects'}{$objind->uid}; |
675
|
0
|
|
0
|
|
|
0
|
$res = $self->read_objnum($objind->{' objnum'}, $objind->{' objgen'}, %opts) || return undef; |
676
|
0
|
0
|
|
|
|
0
|
$objind->merge($res) unless ($objind eq $res); |
677
|
0
|
|
|
|
|
0
|
return $objind; |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=head2 $ref = $p->read_objnum($num, $gen, %opts) |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
Returns a fully read object of given number and generation in this file |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
=cut |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
sub read_objnum |
688
|
|
|
|
|
|
|
{ |
689
|
0
|
|
|
0
|
1
|
0
|
my ($self, $num, $gen, %opts) = @_; |
690
|
0
|
|
|
|
|
0
|
my ($res, $loc, $str, $oldloc); |
691
|
|
|
|
|
|
|
|
692
|
0
|
|
0
|
|
|
0
|
$loc = $self->locate_obj($num, $gen) || return undef; |
693
|
0
|
|
|
|
|
0
|
$oldloc = $self->{' INFILE'}->tell; |
694
|
0
|
|
|
|
|
0
|
$self->{' INFILE'}->seek($loc, 0); |
695
|
0
|
|
|
|
|
0
|
($res, $str) = $self->readval('', %opts, 'objnum' => $num, 'objgen' => $gen); |
696
|
0
|
|
|
|
|
0
|
$self->{' INFILE'}->seek($oldloc, 0); |
697
|
0
|
|
|
|
|
0
|
$res; |
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=head2 $objind = $p->new_obj($obj) |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
Creates a new, free object reference based on free space in the cross reference chain. |
704
|
|
|
|
|
|
|
If nothing free then thinks up a new number. If $obj then turns that object into this |
705
|
|
|
|
|
|
|
new object rather than returning a new object. |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
=cut |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
sub new_obj |
710
|
|
|
|
|
|
|
{ |
711
|
5
|
|
|
5
|
1
|
6
|
my ($self, $base) = @_; |
712
|
5
|
|
|
|
|
1
|
my ($res); |
713
|
5
|
|
|
|
|
5
|
my ($tdict, $i, $ni, $ng); |
714
|
|
|
|
|
|
|
|
715
|
5
|
50
|
|
|
|
26
|
return $base if ($base->is_obj($self)); |
716
|
5
|
50
|
33
|
|
|
12
|
if (defined $self->{' free'} and scalar @{$self->{' free'}} > 0) |
|
0
|
|
|
|
|
0
|
|
717
|
|
|
|
|
|
|
{ |
718
|
0
|
|
|
|
|
0
|
$res = shift(@{$self->{' free'}}); |
|
0
|
|
|
|
|
0
|
|
719
|
0
|
0
|
|
|
|
0
|
if (defined $base) |
720
|
|
|
|
|
|
|
{ |
721
|
0
|
|
|
|
|
0
|
my ($num, $gen) = @{$self->{' objects'}{$res->uid}}; |
|
0
|
|
|
|
|
0
|
|
722
|
0
|
|
|
|
|
0
|
$self->remove_obj($res); |
723
|
0
|
|
|
|
|
0
|
$self->add_obj($base, $num, $gen); |
724
|
0
|
|
|
|
|
0
|
return $self->out_obj($base); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
else |
727
|
|
|
|
|
|
|
{ |
728
|
0
|
|
|
|
|
0
|
$self->{' objects'}{$res->uid}[2] = 0; |
729
|
0
|
|
|
|
|
0
|
return $res; |
730
|
|
|
|
|
|
|
} |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
|
733
|
5
|
|
|
|
|
2
|
$tdict = $self; |
734
|
5
|
|
|
|
|
11
|
while (defined $tdict) |
735
|
|
|
|
|
|
|
{ |
736
|
5
|
50
|
|
|
|
12
|
$i = $tdict->{' xref'}{defined($i)?$i:''}[0]; |
737
|
5
|
|
33
|
|
|
7
|
while (defined $i and $i != 0) |
738
|
|
|
|
|
|
|
{ |
739
|
0
|
|
|
|
|
0
|
($ni, $ng) = @{$tdict->{' xref'}{$i}}; |
|
0
|
|
|
|
|
0
|
|
740
|
0
|
0
|
|
|
|
0
|
if (!defined $self->locate_obj($i, $ng)) |
741
|
|
|
|
|
|
|
{ |
742
|
0
|
0
|
|
|
|
0
|
if (defined $base) |
743
|
|
|
|
|
|
|
{ |
744
|
0
|
|
|
|
|
0
|
$self->add_obj($base, $i, $ng); |
745
|
0
|
|
|
|
|
0
|
return $base; |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
else |
748
|
|
|
|
|
|
|
{ |
749
|
0
|
|
0
|
|
|
0
|
$res = $self->test_obj($i, $ng) |
750
|
|
|
|
|
|
|
|| $self->add_obj(Text::PDF::Objind->new(), $i, $ng); |
751
|
0
|
|
|
|
|
0
|
$tdict->{' xref'}{$i}[0] = $tdict->{' xref'}{$i}[0]; |
752
|
0
|
|
|
|
|
0
|
$self->out_obj($res); |
753
|
0
|
|
|
|
|
0
|
return $res; |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
} |
756
|
0
|
|
|
|
|
0
|
$i = $ni; |
757
|
|
|
|
|
|
|
} |
758
|
5
|
|
|
|
|
11
|
$tdict = $tdict->{' prev'}; |
759
|
|
|
|
|
|
|
} |
760
|
|
|
|
|
|
|
|
761
|
5
|
|
|
|
|
6
|
$i = $self->{' maxobj'}++; |
762
|
5
|
50
|
|
|
|
6
|
if (defined $base) |
763
|
|
|
|
|
|
|
{ |
764
|
5
|
|
|
|
|
9
|
$self->add_obj($base, $i, 0); |
765
|
5
|
|
|
|
|
11
|
$self->out_obj($base); |
766
|
5
|
|
|
|
|
8
|
return $base; |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
else |
769
|
|
|
|
|
|
|
{ |
770
|
0
|
|
|
|
|
0
|
$res = $self->add_obj(Text::PDF::Objind->new(), $i, 0); |
771
|
0
|
|
|
|
|
0
|
$self->out_obj($res); |
772
|
0
|
|
|
|
|
0
|
return $res; |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
} |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
=head2 $p->out_obj($objind) |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
Indicates that the given object reference should appear in the output xref |
780
|
|
|
|
|
|
|
table whether with data or freed. |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=cut |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
sub out_obj |
785
|
|
|
|
|
|
|
{ |
786
|
10
|
|
|
10
|
1
|
7
|
my ($self, $obj) = @_; |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
# don't add objects that aren't real objects! |
789
|
10
|
50
|
|
|
|
16
|
if (!defined $self->{' objects'}{$obj->uid}) |
|
|
100
|
|
|
|
|
|
790
|
0
|
|
|
|
|
0
|
{ return $self->new_obj($obj); } |
791
|
|
|
|
|
|
|
# This is why we've been keeping the outlist CACHE around; to speed |
792
|
|
|
|
|
|
|
# up this method by orders of magnitude (it saves up from having to |
793
|
|
|
|
|
|
|
# grep the full outlist each time through as we'll just do a lookup |
794
|
|
|
|
|
|
|
# in the hash) (which is super-fast). |
795
|
|
|
|
|
|
|
elsif (!exists $self->{' outlist_cache'}{$obj->uid}) |
796
|
|
|
|
|
|
|
{ |
797
|
5
|
|
|
|
|
3
|
push( @{$self->{' outlist'}}, $obj ); |
|
5
|
|
|
|
|
9
|
|
798
|
5
|
|
|
|
|
7
|
$self->{' outlist_cache'}{$obj->uid}++; |
799
|
|
|
|
|
|
|
} |
800
|
10
|
|
|
|
|
17
|
$obj; |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
=head2 $p->free_obj($objind) |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
Marks an object reference for output as being freed. |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
=cut |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
sub free_obj |
811
|
|
|
|
|
|
|
{ |
812
|
0
|
|
|
0
|
1
|
0
|
my ($self, $obj) = @_; |
813
|
|
|
|
|
|
|
|
814
|
0
|
|
|
|
|
0
|
push(@{$self->{' free'}}, $obj); |
|
0
|
|
|
|
|
0
|
|
815
|
0
|
|
|
|
|
0
|
$self->{' objects'}{$obj->uid}[2] = 1; |
816
|
0
|
|
|
|
|
0
|
$self->out_obj($obj); |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
=head2 $p->remove_obj($objind) |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
Removes the object from all places where we might remember it |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
=cut |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
sub remove_obj |
827
|
|
|
|
|
|
|
{ |
828
|
0
|
|
|
0
|
1
|
0
|
my ($self, $objind) = @_; |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
# who says it has to be fast |
831
|
0
|
|
|
|
|
0
|
delete $self->{' objects'}{$objind->uid}; |
832
|
0
|
|
|
|
|
0
|
delete $self->{' outlist_cache'}{$objind->uid}; |
833
|
0
|
|
|
|
|
0
|
delete $self->{' printed_cache'}{$objind}; |
834
|
0
|
|
|
|
|
0
|
@{$self->{' outlist'}} = grep($_ ne $objind, @{$self->{' outlist'}}); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
835
|
0
|
|
|
|
|
0
|
@{$self->{' printed'}} = grep($_ ne $objind, @{$self->{' printed'}}); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
836
|
|
|
|
|
|
|
$self->{' objcache'}{$objind->{' objnum'}, $objind->{' objgen'}} = undef |
837
|
0
|
0
|
|
|
|
0
|
if ($self->{' objcache'}{$objind->{' objnum'}, $objind->{' objgen'}} eq $objind); |
838
|
0
|
|
|
|
|
0
|
$self; |
839
|
|
|
|
|
|
|
} |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
=head2 $p->ship_out(@objects) |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
Ships the given objects (or all objects for output if @objects is empty) to |
845
|
|
|
|
|
|
|
the currently open output file (assuming there is one). Freed objects are not |
846
|
|
|
|
|
|
|
shipped, and once an object is shipped it is switched such that this file |
847
|
|
|
|
|
|
|
becomes its source and it will not be shipped again unless out_obj is called |
848
|
|
|
|
|
|
|
again. Notice that a shipped out object can be re-output or even freed, but |
849
|
|
|
|
|
|
|
that it will not cause the data already output to be changed. |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
=cut |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
sub ship_out |
854
|
|
|
|
|
|
|
{ |
855
|
1
|
|
|
1
|
1
|
2
|
my ($self, @objs) = @_; |
856
|
1
|
|
|
|
|
2
|
my ($n, $fh, $objind, $i, $j); |
857
|
0
|
|
|
|
|
0
|
my ($objnum, $objgen); |
858
|
|
|
|
|
|
|
|
859
|
1
|
50
|
|
|
|
5
|
return unless defined($fh = $self->{' OUTFILE'}); |
860
|
1
|
|
|
|
|
45
|
seek($fh, 0, 2); # go to the end of the file |
861
|
|
|
|
|
|
|
|
862
|
1
|
50
|
|
|
|
4
|
@objs = @{$self->{' outlist'}} unless (scalar @objs > 0); |
|
1
|
|
|
|
|
3
|
|
863
|
1
|
|
|
|
|
3
|
foreach $objind (@objs) |
864
|
|
|
|
|
|
|
{ |
865
|
5
|
50
|
|
|
|
10
|
next unless $objind->is_obj($self); |
866
|
5
|
|
|
|
|
6
|
$j = -1; |
867
|
5
|
|
|
|
|
5
|
for ($i = 0; $i < scalar @{$self->{' outlist'}}; $i++) |
|
5
|
|
|
|
|
15
|
|
868
|
|
|
|
|
|
|
{ |
869
|
5
|
50
|
|
|
|
13
|
if ($self->{' outlist'}[$i] eq $objind) |
870
|
|
|
|
|
|
|
{ |
871
|
5
|
|
|
|
|
5
|
$j = $i; |
872
|
5
|
|
|
|
|
4
|
last; |
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
} |
875
|
5
|
50
|
|
|
|
9
|
next if ($j < 0); |
876
|
5
|
|
|
|
|
3
|
splice(@{$self->{' outlist'}}, $j, 1); |
|
5
|
|
|
|
|
9
|
|
877
|
5
|
|
|
|
|
377
|
delete $self->{' outlist_cache'}{$objind->uid}; |
878
|
5
|
50
|
|
|
|
3
|
next if grep {$_ eq $objind} @{$self->{' free'}}; |
|
0
|
|
|
|
|
0
|
|
|
5
|
|
|
|
|
11
|
|
879
|
|
|
|
|
|
|
|
880
|
5
|
|
|
|
|
17
|
$self->{' locs'}{$objind->uid} = $fh->tell; |
881
|
5
|
|
|
|
|
6
|
($objnum, $objgen) = @{$self->{' objects'}{$objind->uid}}[0..1]; |
|
5
|
|
|
|
|
8
|
|
882
|
5
|
|
|
|
|
11
|
$fh->printf("%d %d obj\n", $objnum, $objgen); |
883
|
5
|
|
|
|
|
41
|
$objind->outobjdeep($fh, $self, 'objnum' => $objnum, 'objgen' => $objgen); |
884
|
5
|
|
|
|
|
12
|
$fh->print("\nendobj\n"); |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
# Note that we've output this obj, not forgetting to update the cache |
887
|
|
|
|
|
|
|
# of whats printed. |
888
|
5
|
50
|
|
|
|
22
|
unless (exists $self->{' printed_cache'}{$objind}) |
889
|
|
|
|
|
|
|
{ |
890
|
5
|
|
|
|
|
4
|
push( @{$self->{' printed'}}, $objind ); |
|
5
|
|
|
|
|
8
|
|
891
|
5
|
|
|
|
|
14
|
$self->{' printed_cache'}{$objind}++; |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
} |
894
|
1
|
|
|
|
|
2
|
$self; |
895
|
|
|
|
|
|
|
} |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
=head2 $p->copy($outpdf, \&filter) |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
Iterates over every object in the file reading the object, calling filter with the object |
900
|
|
|
|
|
|
|
and outputting the result. if filter is not defined, then just copies input to output. |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
=cut |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
sub copy |
905
|
|
|
|
|
|
|
{ |
906
|
0
|
|
|
0
|
1
|
0
|
my ($self, $out, $filt) = @_; |
907
|
0
|
|
|
|
|
0
|
my ($tdict, $i, $nl, $ng, $nt, $res, $obj, $minl, $mini, $ming); |
908
|
|
|
|
|
|
|
|
909
|
0
|
|
|
|
|
0
|
foreach $i (grep (!m/^[\s\-]/o, keys %{$self})) |
|
0
|
|
|
|
|
0
|
|
910
|
0
|
0
|
|
|
|
0
|
{ $out->{$i} = $self->{$i} unless defined $out->{$i}; } |
911
|
|
|
|
|
|
|
|
912
|
0
|
|
|
|
|
0
|
$tdict = $self; |
913
|
0
|
|
|
|
|
0
|
while (defined $tdict) |
914
|
|
|
|
|
|
|
{ |
915
|
0
|
|
|
|
|
0
|
foreach $i (sort {$a <=> $b} keys %{$tdict->{' xref'}}) |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
916
|
|
|
|
|
|
|
{ |
917
|
0
|
|
|
|
|
0
|
($nl, $ng, $nt) = @{$tdict->{' xref'}{$i}}; |
|
0
|
|
|
|
|
0
|
|
918
|
0
|
0
|
|
|
|
0
|
next unless $nt eq 'n'; |
919
|
|
|
|
|
|
|
|
920
|
0
|
0
|
0
|
|
|
0
|
if ($nl < $minl || $mini == 0) |
921
|
|
|
|
|
|
|
{ |
922
|
0
|
|
|
|
|
0
|
$mini = $i; |
923
|
0
|
|
|
|
|
0
|
$ming = $ng; |
924
|
0
|
|
|
|
|
0
|
$minl = $nl; |
925
|
|
|
|
|
|
|
} |
926
|
0
|
0
|
|
|
|
0
|
unless ($obj = $self->test_obj($i, $ng)) |
927
|
|
|
|
|
|
|
{ |
928
|
0
|
|
|
|
|
0
|
$obj = Text::PDF::Objind->new(); |
929
|
0
|
|
|
|
|
0
|
$obj->{' objnum'} = $i; |
930
|
0
|
|
|
|
|
0
|
$obj->{' objgen'} = $ng; |
931
|
0
|
|
|
|
|
0
|
$self->add_obj($obj, $i, $ng); |
932
|
0
|
|
|
|
|
0
|
$obj->{' parent'} = $self; |
933
|
0
|
|
|
|
|
0
|
$obj->{' realised'} = 0; |
934
|
|
|
|
|
|
|
} |
935
|
0
|
|
|
|
|
0
|
$obj->realise; |
936
|
0
|
0
|
|
|
|
0
|
$res = defined $filt ? &{$filt}($obj) : $obj; |
|
0
|
|
|
|
|
0
|
|
937
|
0
|
0
|
0
|
|
|
0
|
$out->new_obj($res) unless (!$res || $res->is_obj($out)); |
938
|
|
|
|
|
|
|
} |
939
|
0
|
|
|
|
|
0
|
$tdict = $tdict->{' prev'}; |
940
|
|
|
|
|
|
|
} |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
# test for linearized and remove it from output |
943
|
0
|
|
|
|
|
0
|
$obj = $self->test_obj($mini, $ming); |
944
|
0
|
0
|
0
|
|
|
0
|
if ($obj->isa('Text::PDF::Dict') && $obj->{'Linearized'}) |
945
|
0
|
|
|
|
|
0
|
{ $out->free_obj($obj); } |
946
|
|
|
|
|
|
|
|
947
|
0
|
|
|
|
|
0
|
$self; |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
=head1 PRIVATE METHODS & FUNCTIONS |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
The following methods and functions are considered private to this class. This |
954
|
|
|
|
|
|
|
does not mean you cannot use them if you have a need, just that they aren't really |
955
|
|
|
|
|
|
|
designed for users of this class. |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
=head2 $offset = $p->locate_obj($num, $gen) |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
Returns a file offset to the object asked for by following the chain of cross |
960
|
|
|
|
|
|
|
reference tables until it finds the one you want. |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
=cut |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
sub locate_obj |
965
|
|
|
|
|
|
|
{ |
966
|
1
|
|
|
1
|
1
|
307
|
my ($self, $num, $gen) = @_; |
967
|
1
|
|
|
|
|
1
|
my ($tdict, $ref); |
968
|
|
|
|
|
|
|
|
969
|
1
|
|
|
|
|
1
|
$tdict = $self; |
970
|
1
|
|
|
|
|
4
|
while (defined $tdict) |
971
|
|
|
|
|
|
|
{ |
972
|
1
|
50
|
|
|
|
4
|
if (ref $tdict->{' xref'}{$num}) |
973
|
|
|
|
|
|
|
{ |
974
|
1
|
|
|
|
|
2
|
$ref = $tdict->{' xref'}{$num}; |
975
|
1
|
50
|
|
|
|
3
|
if ($ref->[1] == $gen) |
976
|
|
|
|
|
|
|
{ |
977
|
1
|
50
|
|
|
|
5
|
return $ref->[0] if ($ref->[2] eq "n"); |
978
|
0
|
|
|
|
|
0
|
return undef; # if $ref->[2] eq "f" |
979
|
|
|
|
|
|
|
} |
980
|
|
|
|
|
|
|
} |
981
|
0
|
|
|
|
|
0
|
$tdict = $tdict->{' prev'} |
982
|
|
|
|
|
|
|
} |
983
|
0
|
|
|
|
|
0
|
return undef; |
984
|
|
|
|
|
|
|
} |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
=head2 update($fh, $str) |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
Keeps reading $fh for more data to ensure that $str has at least a line full |
990
|
|
|
|
|
|
|
for C to work on. At this point we also take the opportunity to ignore |
991
|
|
|
|
|
|
|
comments. |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
=cut |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
sub update |
996
|
|
|
|
|
|
|
{ |
997
|
15
|
|
|
15
|
1
|
16
|
my ($fh, $str) = @_; |
998
|
|
|
|
|
|
|
|
999
|
15
|
|
|
|
|
45
|
$str =~ s/^$ws_char*//o; |
1000
|
15
|
|
66
|
|
|
73
|
while ($str !~ m/$cr/o && !$fh->eof) |
1001
|
|
|
|
|
|
|
{ |
1002
|
2
|
|
|
|
|
20
|
$fh->read($str, 255, length($str)); |
1003
|
2
|
|
|
|
|
35
|
$str =~ s/^$ws_char*//so; |
1004
|
2
|
|
|
|
|
16
|
while ($str =~ m/^\%/o) |
1005
|
|
|
|
|
|
|
{ |
1006
|
0
|
|
0
|
|
|
0
|
$fh->read($str, 255, length($str)) while ($str !~ m/$cr/o && !$fh->eof); |
1007
|
0
|
|
|
|
|
0
|
$str =~ s/^\%(.*)$cr$ws_char*//so; |
1008
|
|
|
|
|
|
|
} |
1009
|
|
|
|
|
|
|
} |
1010
|
|
|
|
|
|
|
|
1011
|
15
|
|
|
|
|
31
|
return $str; |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
=head2 $objind = $p->test_obj($num, $gen) |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
Tests the cache to see whether an object reference (which may or may not have |
1018
|
|
|
|
|
|
|
been getobj()ed) has been cached. Returns it if it has. |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
=cut |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
sub test_obj |
1023
|
2
|
|
|
2
|
1
|
10
|
{ $_[0]->{' objcache'}{$_[1], $_[2]}; } |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
=head2 $p->add_obj($objind) |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
Adds the given object to the internal object cache. |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
=cut |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
sub add_obj |
1033
|
|
|
|
|
|
|
{ |
1034
|
7
|
|
|
7
|
1
|
8
|
my ($self, $obj, $num, $gen) = @_; |
1035
|
|
|
|
|
|
|
|
1036
|
7
|
|
|
|
|
15
|
$self->{' objcache'}{$num, $gen} = $obj; |
1037
|
7
|
|
|
|
|
21
|
$self->{' objects'}{$obj->uid} = [$num, $gen]; |
1038
|
7
|
|
|
|
|
8
|
return $obj; |
1039
|
|
|
|
|
|
|
} |
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
=head2 $tdict = $p->readxrtr($xpos) |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
Recursive function which reads each of the cross-reference and trailer tables |
1045
|
|
|
|
|
|
|
in turn until there are no more. |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
Returns a dictionary corresponding to the trailer chain. Each trailer also |
1048
|
|
|
|
|
|
|
includes the corresponding cross-reference table. |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
The structure of the xref private element in a trailer dictionary is of an |
1051
|
|
|
|
|
|
|
anonymous hash of cross reference elements by object number. Each element |
1052
|
|
|
|
|
|
|
consists of an array of 3 elements corresponding to the three elements read |
1053
|
|
|
|
|
|
|
in [location, generation number, free or used]. See the PDF Specification |
1054
|
|
|
|
|
|
|
for details. |
1055
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
=cut |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
sub readxrtr |
1059
|
|
|
|
|
|
|
{ |
1060
|
1
|
|
|
1
|
1
|
2
|
my ($self, $xpos) = @_; |
1061
|
1
|
|
|
|
|
1
|
my ($tdict, $xlist, $buf, $xmin, $xnum, $fh, $xdiff); |
1062
|
|
|
|
|
|
|
|
1063
|
1
|
|
|
|
|
2
|
$fh = $self->{' INFILE'}; |
1064
|
1
|
|
|
|
|
6
|
$fh->seek($xpos, 0); |
1065
|
1
|
|
|
|
|
6
|
$fh->read($buf, 22); |
1066
|
1
|
50
|
|
|
|
24
|
if ($buf !~ m/^xref$cr/oi) |
1067
|
0
|
|
|
|
|
0
|
{ die "Malformed xref in PDF file $self->{' fname'}"; } |
1068
|
1
|
|
|
|
|
14
|
$buf =~ s/^xref$cr//oi; |
1069
|
|
|
|
|
|
|
|
1070
|
1
|
|
|
|
|
2
|
$xlist = {}; |
1071
|
1
|
|
|
|
|
31
|
while ($buf =~ m/^([0-9]+)$ws_char+([0-9]+)$cr(.*?)$/so) |
1072
|
|
|
|
|
|
|
{ |
1073
|
1
|
|
|
|
|
2
|
$xmin = $1; |
1074
|
1
|
|
|
|
|
2
|
$xnum = $2; |
1075
|
1
|
|
|
|
|
2
|
$buf = $3; |
1076
|
1
|
|
|
|
|
2
|
$xdiff = length($buf); |
1077
|
|
|
|
|
|
|
|
1078
|
1
|
|
|
|
|
4
|
$fh->read($buf, 20 * $xnum - $xdiff + 15, $xdiff); |
1079
|
1
|
|
66
|
|
|
48
|
while ($xnum-- > 0 && $buf =~ s/^0*([0-9]*)$ws_char+0*([0-9]+)$ws_char+([nf])$cr//o) |
1080
|
6
|
|
|
|
|
40
|
{ $xlist->{$xmin++} = [$1, $2, $3]; } |
1081
|
|
|
|
|
|
|
} |
1082
|
|
|
|
|
|
|
|
1083
|
1
|
50
|
|
|
|
18
|
if ($buf !~ /^trailer$cr/oi) |
1084
|
0
|
|
|
|
|
0
|
{ die "Malformed trailer in PDF file $self->{' fname'} at " . ($fh->tell - length($buf)); } |
1085
|
|
|
|
|
|
|
|
1086
|
1
|
|
|
|
|
13
|
$buf =~ s/^trailer$cr//oi; |
1087
|
|
|
|
|
|
|
|
1088
|
1
|
|
|
|
|
5
|
($tdict, $buf) = $self->readval($buf); |
1089
|
1
|
|
|
|
|
3
|
$tdict->{' loc'} = $xpos; |
1090
|
1
|
|
|
|
|
2
|
$tdict->{' xref'} = $xlist; |
1091
|
1
|
50
|
|
|
|
4
|
$self->{' maxobj'} = $xmin if $xmin > $self->{' maxobj'}; |
1092
|
|
|
|
|
|
|
$tdict->{' prev'} = $self->readxrtr($tdict->{'Prev'}->val) |
1093
|
1
|
50
|
33
|
|
|
3
|
if (defined $tdict->{'Prev'} && $tdict->{'Prev'}->val != 0); |
1094
|
1
|
|
|
|
|
2
|
return $tdict; |
1095
|
|
|
|
|
|
|
} |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=head2 $p->out_trailer($tdict) |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
Outputs the body and trailer for a PDF file by outputting all the objects in |
1101
|
|
|
|
|
|
|
the ' outlist' and then outputting a xref table for those objects and any |
1102
|
|
|
|
|
|
|
freed ones. It then outputs the trailing dictionary and the trailer code. |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
=cut |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
sub out_trailer |
1107
|
|
|
|
|
|
|
{ |
1108
|
1
|
|
|
1
|
1
|
3
|
my ($self, $tdict, $update) = @_; |
1109
|
1
|
|
|
|
|
2
|
my ($objind, $j, $i, $iend, @xreflist, $first, $k, $xref, $tloc, @freelist); |
1110
|
0
|
|
|
|
|
0
|
my (%locs, $size); |
1111
|
1
|
|
|
|
|
3
|
my ($fh) = $self->{' OUTFILE'}; |
1112
|
|
|
|
|
|
|
|
1113
|
1
|
|
|
|
|
2
|
while (@{$self->{' outlist'}}) |
|
2
|
|
|
|
|
6
|
|
1114
|
1
|
|
|
|
|
4
|
{ $self->ship_out; } |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
# foreach $objind (@{$self->{' outlist'}}) |
1117
|
|
|
|
|
|
|
# { |
1118
|
|
|
|
|
|
|
# next if ($self->{' objects'}{$objind->uid}[2]); |
1119
|
|
|
|
|
|
|
# $locs{$objind->uid} = $fh->tell; |
1120
|
|
|
|
|
|
|
# $fh->printf("%d %d obj\n", @{$self->{' objects'}{$objind->uid}}[0..1]); |
1121
|
|
|
|
|
|
|
# $objind->outobjdeep($fh, $self); |
1122
|
|
|
|
|
|
|
# $fh->print("\nendobj\n"); |
1123
|
|
|
|
|
|
|
# } |
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
# $size = @{$self->{' printed'}} + @{$self->{' free'}}; |
1126
|
|
|
|
|
|
|
# $tdict->{'Size'} = PDFNum($tdict->{'Size'}->val + $size); |
1127
|
|
|
|
|
|
|
# PDFSpec 1.3 says for /Size: (Required) Total number of entries in the file’s |
1128
|
|
|
|
|
|
|
# cross-reference table, including the original table and all updates. Which |
1129
|
|
|
|
|
|
|
# is what the previous two lines implement. |
1130
|
|
|
|
|
|
|
# But this seems to make Acrobat croak on saving so we try the following from |
1131
|
|
|
|
|
|
|
# basil.duval@epfl.ch |
1132
|
1
|
|
|
|
|
3
|
$tdict->{'Size'} = PDFNum($self->{' maxobj'}); |
1133
|
|
|
|
|
|
|
|
1134
|
1
|
|
|
|
|
3
|
$tloc = $fh->tell; |
1135
|
1
|
|
|
|
|
4
|
$fh->print("xref\n"); |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
@xreflist = sort {$self->{' objects'}{$a->uid}[0] <=> |
1138
|
8
|
|
|
|
|
13
|
$self->{' objects'}{$b->uid}[0]} |
1139
|
1
|
|
|
|
|
3
|
(@{$self->{' printed'}}, @{$self->{' free'}}); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
4
|
|
1140
|
|
|
|
|
|
|
|
1141
|
1
|
50
|
|
|
|
4
|
unless ($update) |
1142
|
|
|
|
|
|
|
{ |
1143
|
1
|
|
|
|
|
1
|
$i = 1; |
1144
|
1
|
|
|
|
|
4
|
for ($j = 0; $j < @xreflist; $j++) |
1145
|
|
|
|
|
|
|
{ |
1146
|
5
|
|
|
|
|
3
|
my (@inserts); |
1147
|
5
|
|
|
|
|
3
|
$k = $xreflist[$j]; |
1148
|
5
|
|
|
|
|
12
|
while ($i < $self->{' objects'}{$k->uid}[0]) |
1149
|
|
|
|
|
|
|
{ |
1150
|
0
|
|
|
|
|
0
|
my ($n) = Text::PDF::Objind->new(); |
1151
|
0
|
|
|
|
|
0
|
$self->add_obj($n, $i, 0); |
1152
|
0
|
|
|
|
|
0
|
$self->free_obj($n); |
1153
|
0
|
|
|
|
|
0
|
push(@inserts, $n); |
1154
|
0
|
|
|
|
|
0
|
$i++; |
1155
|
|
|
|
|
|
|
} |
1156
|
5
|
|
|
|
|
3
|
splice(@xreflist, $j, 0, @inserts); |
1157
|
5
|
|
|
|
|
5
|
$j += @inserts; |
1158
|
5
|
|
|
|
|
8
|
$i++; |
1159
|
|
|
|
|
|
|
} |
1160
|
|
|
|
|
|
|
} |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
@freelist = sort {$self->{' objects'}{$a->uid}[0] <=> |
1163
|
1
|
|
|
|
|
1
|
$self->{' objects'}{$b->uid}[0]} @{$self->{' free'}}; |
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
2
|
|
1164
|
|
|
|
|
|
|
|
1165
|
1
|
|
|
|
|
1
|
$j = 0; $first = -1; $k = 0; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1
|
|
1166
|
1
|
|
|
|
|
4
|
for ($i = 0; $i <= $#xreflist + 1; $i++) |
1167
|
|
|
|
|
|
|
{ |
1168
|
|
|
|
|
|
|
# if ($i == 0) |
1169
|
|
|
|
|
|
|
# { |
1170
|
|
|
|
|
|
|
# $first = $i; $j = $xreflist[0]->{' objnum'}; |
1171
|
|
|
|
|
|
|
# $fh->printf("0 1\n%010d 65535 f \n", $ff); |
1172
|
|
|
|
|
|
|
# } |
1173
|
6
|
100
|
66
|
|
|
15
|
if ($i > $#xreflist || $self->{' objects'}{$xreflist[$i]->uid}[0] != $j + 1) |
1174
|
|
|
|
|
|
|
{ |
1175
|
1
|
50
|
|
|
|
6
|
$fh->print(($first == -1 ? "0 " : "$self->{' objects'}{$xreflist[$first]->uid}[0] ") . ($i - $first) . "\n"); |
1176
|
1
|
50
|
|
|
|
5
|
if ($first == -1) |
1177
|
|
|
|
|
|
|
{ |
1178
|
1
|
50
|
|
|
|
4
|
$fh->printf("%010d 65535 f \n", defined $freelist[$k] ? $self->{' objects'}{$freelist[$k]->uid}[0] : 0); |
1179
|
1
|
|
|
|
|
6
|
$first = 0; |
1180
|
|
|
|
|
|
|
} |
1181
|
1
|
|
|
|
|
3
|
for ($j = $first; $j < $i; $j++) |
1182
|
|
|
|
|
|
|
{ |
1183
|
5
|
|
|
|
|
15
|
$xref = $xreflist[$j]; |
1184
|
5
|
50
|
33
|
|
|
10
|
if (defined $freelist[$k] && defined $xref && "$freelist[$k]" eq "$xref") |
|
|
|
33
|
|
|
|
|
1185
|
|
|
|
|
|
|
{ |
1186
|
0
|
|
|
|
|
0
|
$k++; |
1187
|
|
|
|
|
|
|
$fh->print(pack("A10AA5A4", |
1188
|
|
|
|
|
|
|
sprintf("%010d", (defined $freelist[$k] ? |
1189
|
|
|
|
|
|
|
$self->{' objects'}{$freelist[$k]->uid}[0] : 0)), " ", |
1190
|
0
|
0
|
|
|
|
0
|
sprintf("%05d", $self->{' objects'}{$xref->uid}[1] + 1), |
1191
|
|
|
|
|
|
|
" f \n")); |
1192
|
|
|
|
|
|
|
} else |
1193
|
|
|
|
|
|
|
{ |
1194
|
|
|
|
|
|
|
$fh->print(pack("A10AA5A4", sprintf("%010d", $self->{' locs'}{$xref->uid}), " ", |
1195
|
5
|
|
|
|
|
10
|
sprintf("%05d", $self->{' objects'}{$xref->uid}[1]), |
1196
|
|
|
|
|
|
|
" n \n")); |
1197
|
|
|
|
|
|
|
} |
1198
|
|
|
|
|
|
|
} |
1199
|
1
|
|
|
|
|
4
|
$first = $i; |
1200
|
1
|
50
|
|
|
|
4
|
$j = $self->{' objects'}{$xreflist[$i]->uid}[0] if ($i < scalar @xreflist); |
1201
|
|
|
|
|
|
|
} else |
1202
|
5
|
|
|
|
|
7
|
{ $j++; } |
1203
|
|
|
|
|
|
|
} |
1204
|
1
|
|
|
|
|
7
|
$fh->print("trailer\n"); |
1205
|
1
|
|
|
|
|
5
|
$tdict->outobjdeep($fh, $self); |
1206
|
1
|
|
|
|
|
5
|
$fh->print("\nstartxref\n$tloc\n" . '%%EOF' . "\n"); |
1207
|
|
|
|
|
|
|
} |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
=head2 Text::PDF::File->_new |
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
Creates a very empty PDF file object (used by new and open) |
1213
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
=cut |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
sub _new |
1217
|
|
|
|
|
|
|
{ |
1218
|
2
|
|
|
2
|
|
2
|
my ($class) = @_; |
1219
|
2
|
|
|
|
|
3
|
my ($self) = {}; |
1220
|
|
|
|
|
|
|
|
1221
|
2
|
|
|
|
|
2
|
bless $self, $class; |
1222
|
2
|
|
|
|
|
6
|
$self->{' outlist'} = []; |
1223
|
2
|
|
|
|
|
3
|
$self->{' outlist_cache'} = {}; # A cache of whats in the 'outlist' |
1224
|
2
|
|
|
|
|
4
|
$self->{' maxobj'} = 1; |
1225
|
2
|
|
|
|
|
4
|
$self->{' objcache'} = {}; |
1226
|
2
|
|
|
|
|
3
|
$self->{' objects'} = {}; |
1227
|
2
|
|
|
|
|
2
|
$self; |
1228
|
|
|
|
|
|
|
} |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
1; |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
=head1 AUTHOR |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
Martin Hosken Martin_Hosken@sil.org |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
Copyright Martin Hosken 1999 and onwards |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
No warranty or expression of effectiveness, least of all regarding anyone's |
1239
|
|
|
|
|
|
|
safety, is implied in this software or documentation. |
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
=head2 Licensing |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
This Perl Text::PDF module is licensed under the Perl Artistic License. |
1244
|
|
|
|
|
|
|
|