| 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
|
|
10013
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
24
|
|
|
126
|
1
|
|
|
1
|
|
2
|
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
|
|
|
|
|
88
|
|
|
128
|
|
|
|
|
|
|
# no warnings qw(uninitialized); |
|
129
|
|
|
|
|
|
|
|
|
130
|
1
|
|
|
1
|
|
416
|
use IO::File; |
|
|
1
|
|
|
|
|
6402
|
|
|
|
1
|
|
|
|
|
84
|
|
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# Now for the basic PDF types |
|
133
|
1
|
|
|
1
|
|
365
|
use Text::PDF::Utils; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
83
|
|
|
134
|
|
|
|
|
|
|
|
|
135
|
1
|
|
|
1
|
|
6
|
use Text::PDF::Array; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
26
|
|
|
136
|
1
|
|
|
1
|
|
5
|
use Text::PDF::Bool; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
25
|
|
|
137
|
1
|
|
|
1
|
|
6
|
use Text::PDF::Dict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
22
|
|
|
138
|
1
|
|
|
1
|
|
3
|
use Text::PDF::Name; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
13
|
|
|
139
|
1
|
|
|
1
|
|
3
|
use Text::PDF::Number; |
|
|
1
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
|
11
|
|
|
140
|
1
|
|
|
1
|
|
2
|
use Text::PDF::Objind; |
|
|
1
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
|
10
|
|
|
141
|
1
|
|
|
1
|
|
2
|
use Text::PDF::String; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
10
|
|
|
142
|
1
|
|
|
1
|
|
324
|
use Text::PDF::Page; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
20
|
|
|
143
|
1
|
|
|
1
|
|
3
|
use Text::PDF::Pages; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
11
|
|
|
144
|
1
|
|
|
1
|
|
335
|
use Text::PDF::Null; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
107
|
|
|
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
|
|
|
|
|
3
|
foreach $type (keys %types) |
|
192
|
|
|
|
|
|
|
{ |
|
193
|
2
|
|
|
|
|
2
|
$t = $types{$type}; |
|
194
|
2
|
|
|
|
|
5
|
$t =~ s|::|/|og; |
|
195
|
2
|
|
|
|
|
3889
|
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
|
360
|
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
|
|
|
|
|
2
|
$self->{'Root'} = $root; |
|
220
|
1
|
|
|
|
|
2
|
$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
|
239
|
my ($class, $fname, $update) = @_; |
|
239
|
1
|
|
|
|
|
1
|
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
|
|
|
4
|
$fh = IO::File->new(($update ? "+" : "") . "<$fname") || return undef; |
|
251
|
1
|
|
|
|
|
47
|
$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
|
|
|
|
55
|
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
|
|
|
|
|
4
|
{ $self->{' Version'} = $1; } |
|
266
|
|
|
|
|
|
|
|
|
267
|
1
|
|
|
|
|
8
|
$fh->seek(0, 2); # go to end of file |
|
268
|
1
|
|
|
|
|
7
|
$end = $fh->tell(); |
|
269
|
1
|
|
|
|
|
4
|
$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
|
|
|
|
46
|
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
|
|
|
|
|
4
|
$tdict = $self->readxrtr($xpos, $self); |
|
278
|
1
|
|
|
|
|
1
|
foreach $k (keys %{$tdict}) |
|
|
1
|
|
|
|
|
3
|
|
|
279
|
5
|
|
|
|
|
6
|
{ $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
|
5
|
|
|
5
|
1
|
11
|
my ($self, $force) = @_; |
|
311
|
5
|
|
|
|
|
5
|
my (@tofree); |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# first, close the input file if it is still open |
|
314
|
5
|
|
|
|
|
14
|
close($self->{' INFILE'}); |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# delete stuff that we know we can, here |
|
317
|
|
|
|
|
|
|
|
|
318
|
5
|
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
|
5
|
|
|
|
|
5
|
{ @tofree = map { delete $self->{$_} } keys %{$self}; } |
|
|
26
|
|
|
|
|
30
|
|
|
|
5
|
|
|
|
|
13
|
|
|
329
|
|
|
|
|
|
|
|
|
330
|
5
|
|
|
|
|
13
|
while (my $item = shift @tofree) |
|
331
|
|
|
|
|
|
|
{ |
|
332
|
31
|
|
|
|
|
26
|
my $ref = ref($item); |
|
333
|
31
|
100
|
|
|
|
124
|
if (UNIVERSAL::can($item, 'release')) |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
334
|
8
|
|
|
|
|
13
|
{ $item->release($force); } |
|
335
|
|
|
|
|
|
|
elsif ($ref eq 'ARRAY') |
|
336
|
4
|
|
|
|
|
4
|
{ push( @tofree, @{$item} ); } |
|
|
4
|
|
|
|
|
9
|
|
|
337
|
|
|
|
|
|
|
elsif (UNIVERSAL::isa($ref, 'HASH')) |
|
338
|
0
|
|
|
|
|
0
|
{ release($item, $force); } |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# check that everything has gone - it better had! |
|
342
|
5
|
|
|
|
|
3
|
foreach my $key (keys %{$self}) |
|
|
5
|
|
|
|
|
12
|
|
|
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
|
|
|
|
|
2
|
$self->create_file($fname); |
|
400
|
1
|
|
|
|
|
3
|
$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
|
|
|
6
|
$fh = IO::File->new(">$fname") || die "Unable to open $fname for writing"; |
|
424
|
1
|
|
|
|
|
122
|
binmode $fh; |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
1
|
|
|
|
|
2
|
$self->{' OUTFILE'} = $fh; |
|
428
|
1
|
|
50
|
|
|
10
|
$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
|
1
|
my ($self) = @_; |
|
443
|
1
|
|
|
|
|
1
|
my ($fh, $tdict, $t); |
|
444
|
|
|
|
|
|
|
|
|
445
|
1
|
|
|
|
|
4
|
$tdict = PDFDict(); |
|
446
|
1
|
50
|
|
|
|
3
|
$tdict->{'Info'} = $self->{'Info'} if defined $self->{'Info'}; |
|
447
|
1
|
50
|
33
|
|
|
5
|
$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
|
|
|
4
|
$tdict->{'Size'} = $self->{'Size'} || PDFNum(1); |
|
454
|
1
|
50
|
|
|
|
2
|
$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
|
|
|
|
|
4
|
$self->out_trailer($tdict, $self->{' update'}); |
|
465
|
1
|
|
|
|
|
30
|
close($self->{' OUTFILE'}); |
|
466
|
|
|
|
|
|
|
MacPerl::SetFileInfo("CARO", "TEXT", $self->{' fname'}) |
|
467
|
1
|
50
|
33
|
|
|
16
|
if ($^O eq "MacOS" && !ref($self->{' fname'})); |
|
468
|
1
|
|
|
|
|
13
|
$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
|
188
|
my ($self, $str, %opts) = @_; |
|
485
|
6
|
|
|
|
|
8
|
my ($fh) = $self->{' INFILE'}; |
|
486
|
6
|
|
|
|
|
3
|
my ($res, $key, $value, $k); |
|
487
|
|
|
|
|
|
|
|
|
488
|
6
|
|
|
|
|
8
|
$str = update($fh, $str); |
|
489
|
|
|
|
|
|
|
|
|
490
|
6
|
100
|
|
|
|
169
|
if ($str =~ m/^<
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
{ |
|
492
|
2
|
|
|
|
|
4
|
$str = substr ($str, 2); |
|
493
|
2
|
|
|
|
|
3
|
$str = update($fh, $str); |
|
494
|
2
|
|
|
|
|
4
|
$res = PDFDict(); |
|
495
|
|
|
|
|
|
|
|
|
496
|
2
|
|
|
|
|
5
|
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
|
|
|
|
|
24
|
($value, $str) = $self->readval($str, %opts); |
|
502
|
3
|
|
|
|
|
5
|
$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
|
|
|
|
|
3
|
$str = update($fh, $str); |
|
508
|
|
|
|
|
|
|
# streams can't be followed by a lone carriage-return. |
|
509
|
2
|
100
|
66
|
|
|
9
|
if (($str =~ s/^stream(?:(?:\015\012)|\012)//o) |
|
510
|
|
|
|
|
|
|
&& ($res->{'Length'}->val != 0)) # stream |
|
511
|
|
|
|
|
|
|
{ |
|
512
|
1
|
|
|
|
|
2
|
$k = $res->{'Length'}->val; |
|
513
|
1
|
|
|
|
|
2
|
$res->{' streamsrc'} = $fh; |
|
514
|
1
|
|
|
|
|
3
|
$res->{' streamloc'} = $fh->tell - length($str); |
|
515
|
1
|
50
|
|
|
|
6
|
unless ($opts{'nostreams'}) |
|
516
|
|
|
|
|
|
|
{ |
|
517
|
1
|
50
|
|
|
|
3
|
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
|
|
|
|
|
1
|
$res->{' stream'} = $value; |
|
526
|
1
|
|
|
|
|
1
|
$res->{' nofilt'} = 1; |
|
527
|
1
|
|
|
|
|
2
|
$str = update($fh, $str); |
|
528
|
1
|
|
|
|
|
5
|
$str =~ s/^endstream//o; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
} |
|
531
|
|
|
|
|
|
|
|
|
532
|
2
|
50
|
33
|
|
|
6
|
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
|
|
|
|
|
3
|
$k = $1; |
|
542
|
1
|
|
|
|
|
1
|
$value = $2; |
|
543
|
1
|
|
|
|
|
17
|
$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
|
|
|
|
|
7
|
$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
|
|
|
|
|
2
|
$k = $1; |
|
559
|
1
|
|
|
|
|
1
|
$value = $2; |
|
560
|
1
|
|
|
|
|
23
|
$str =~ s/^([0-9]+)$ws_char+([0-9]+)$ws_char+obj//so; |
|
561
|
1
|
|
|
|
|
4
|
($obj, $str) = $self->readval($str, %opts, 'objnum' => $k, 'objgen' => $value); |
|
562
|
1
|
50
|
|
|
|
5
|
if ($res = $self->test_obj($k, $value)) |
|
563
|
0
|
|
|
|
|
0
|
{ $res->merge($obj); } |
|
564
|
|
|
|
|
|
|
else |
|
565
|
|
|
|
|
|
|
{ |
|
566
|
1
|
|
|
|
|
1
|
$res = $obj; |
|
567
|
1
|
|
|
|
|
2
|
$self->add_obj($res, $k, $value); |
|
568
|
1
|
|
|
|
|
2
|
$res->{' realised'} = 1; |
|
569
|
|
|
|
|
|
|
} |
|
570
|
1
|
|
|
|
|
1
|
$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
|
|
|
|
|
5
|
$value = $1; |
|
646
|
2
|
|
|
|
|
5
|
$str =~ s/^([+-.0-9]+)//o; |
|
647
|
2
|
|
|
|
|
16
|
$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
|
|
|
|
|
23
|
$str =~ s/^$ws_char*//os; |
|
658
|
6
|
|
|
|
|
16
|
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
|
11
|
my ($self, $base) = @_; |
|
712
|
5
|
|
|
|
|
3
|
my ($res); |
|
713
|
5
|
|
|
|
|
5
|
my ($tdict, $i, $ni, $ng); |
|
714
|
|
|
|
|
|
|
|
|
715
|
5
|
50
|
|
|
|
18
|
return $base if ($base->is_obj($self)); |
|
716
|
5
|
50
|
33
|
|
|
11
|
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
|
|
|
|
|
6
|
$tdict = $self; |
|
734
|
5
|
|
|
|
|
10
|
while (defined $tdict) |
|
735
|
|
|
|
|
|
|
{ |
|
736
|
5
|
50
|
|
|
|
12
|
$i = $tdict->{' xref'}{defined($i)?$i:''}[0]; |
|
737
|
5
|
|
33
|
|
|
8
|
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
|
|
|
|
|
10
|
$tdict = $tdict->{' prev'}; |
|
759
|
|
|
|
|
|
|
} |
|
760
|
|
|
|
|
|
|
|
|
761
|
5
|
|
|
|
|
5
|
$i = $self->{' maxobj'}++; |
|
762
|
5
|
50
|
|
|
|
7
|
if (defined $base) |
|
763
|
|
|
|
|
|
|
{ |
|
764
|
5
|
|
|
|
|
7
|
$self->add_obj($base, $i, 0); |
|
765
|
5
|
|
|
|
|
8
|
$self->out_obj($base); |
|
766
|
5
|
|
|
|
|
9
|
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
|
13
|
my ($self, $obj) = @_; |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
# don't add objects that aren't real objects! |
|
789
|
10
|
50
|
|
|
|
15
|
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
|
|
|
|
|
4
|
push( @{$self->{' outlist'}}, $obj ); |
|
|
5
|
|
|
|
|
8
|
|
|
798
|
5
|
|
|
|
|
8
|
$self->{' outlist_cache'}{$obj->uid}++; |
|
799
|
|
|
|
|
|
|
} |
|
800
|
10
|
|
|
|
|
12
|
$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
|
|
|
|
|
1
|
my ($n, $fh, $objind, $i, $j); |
|
857
|
0
|
|
|
|
|
0
|
my ($objnum, $objgen); |
|
858
|
|
|
|
|
|
|
|
|
859
|
1
|
50
|
|
|
|
3
|
return unless defined($fh = $self->{' OUTFILE'}); |
|
860
|
1
|
|
|
|
|
37
|
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
|
|
|
|
|
2
|
foreach $objind (@objs) |
|
864
|
|
|
|
|
|
|
{ |
|
865
|
5
|
50
|
|
|
|
14
|
next unless $objind->is_obj($self); |
|
866
|
5
|
|
|
|
|
5
|
$j = -1; |
|
867
|
5
|
|
|
|
|
6
|
for ($i = 0; $i < scalar @{$self->{' outlist'}}; $i++) |
|
|
5
|
|
|
|
|
12
|
|
|
868
|
|
|
|
|
|
|
{ |
|
869
|
5
|
50
|
|
|
|
11
|
if ($self->{' outlist'}[$i] eq $objind) |
|
870
|
|
|
|
|
|
|
{ |
|
871
|
5
|
|
|
|
|
4
|
$j = $i; |
|
872
|
5
|
|
|
|
|
7
|
last; |
|
873
|
|
|
|
|
|
|
} |
|
874
|
|
|
|
|
|
|
} |
|
875
|
5
|
50
|
|
|
|
7
|
next if ($j < 0); |
|
876
|
5
|
|
|
|
|
2
|
splice(@{$self->{' outlist'}}, $j, 1); |
|
|
5
|
|
|
|
|
10
|
|
|
877
|
5
|
|
|
|
|
8
|
delete $self->{' outlist_cache'}{$objind->uid}; |
|
878
|
5
|
50
|
|
|
|
5
|
next if grep {$_ eq $objind} @{$self->{' free'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
5
|
|
|
|
|
9
|
|
|
879
|
|
|
|
|
|
|
|
|
880
|
5
|
|
|
|
|
15
|
$self->{' locs'}{$objind->uid} = $fh->tell; |
|
881
|
5
|
|
|
|
|
6
|
($objnum, $objgen) = @{$self->{' objects'}{$objind->uid}}[0..1]; |
|
|
5
|
|
|
|
|
6
|
|
|
882
|
5
|
|
|
|
|
10
|
$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
|
|
|
|
|
3
|
push( @{$self->{' printed'}}, $objind ); |
|
|
5
|
|
|
|
|
8
|
|
|
891
|
5
|
|
|
|
|
11
|
$self->{' printed_cache'}{$objind}++; |
|
892
|
|
|
|
|
|
|
} |
|
893
|
|
|
|
|
|
|
} |
|
894
|
1
|
|
|
|
|
1
|
$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
|
189
|
my ($self, $num, $gen) = @_; |
|
967
|
1
|
|
|
|
|
1
|
my ($tdict, $ref); |
|
968
|
|
|
|
|
|
|
|
|
969
|
1
|
|
|
|
|
1
|
$tdict = $self; |
|
970
|
1
|
|
|
|
|
3
|
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
|
|
|
|
4
|
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
|
15
|
my ($fh, $str) = @_; |
|
998
|
|
|
|
|
|
|
|
|
999
|
15
|
|
|
|
|
38
|
$str =~ s/^$ws_char*//o; |
|
1000
|
15
|
|
66
|
|
|
73
|
while ($str !~ m/$cr/o && !$fh->eof) |
|
1001
|
|
|
|
|
|
|
{ |
|
1002
|
2
|
|
|
|
|
21
|
$fh->read($str, 255, length($str)); |
|
1003
|
2
|
|
|
|
|
24
|
$str =~ s/^$ws_char*//so; |
|
1004
|
2
|
|
|
|
|
12
|
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
|
|
|
|
|
25
|
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
|
8
|
{ $_[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
|
11
|
my ($self, $obj, $num, $gen) = @_; |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
7
|
|
|
|
|
18
|
$self->{' objcache'}{$num, $gen} = $obj; |
|
1037
|
7
|
|
|
|
|
21
|
$self->{' objects'}{$obj->uid} = [$num, $gen]; |
|
1038
|
7
|
|
|
|
|
6
|
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
|
5
|
my ($self, $xpos) = @_; |
|
1061
|
1
|
|
|
|
|
2
|
my ($tdict, $xlist, $buf, $xmin, $xnum, $fh, $xdiff); |
|
1062
|
|
|
|
|
|
|
|
|
1063
|
1
|
|
|
|
|
2
|
$fh = $self->{' INFILE'}; |
|
1064
|
1
|
|
|
|
|
2
|
$fh->seek($xpos, 0); |
|
1065
|
1
|
|
|
|
|
7
|
$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
|
|
|
|
|
17
|
$buf =~ s/^xref$cr//oi; |
|
1069
|
|
|
|
|
|
|
|
|
1070
|
1
|
|
|
|
|
2
|
$xlist = {}; |
|
1071
|
1
|
|
|
|
|
28
|
while ($buf =~ m/^([0-9]+)$ws_char+([0-9]+)$cr(.*?)$/so) |
|
1072
|
|
|
|
|
|
|
{ |
|
1073
|
1
|
|
|
|
|
3
|
$xmin = $1; |
|
1074
|
1
|
|
|
|
|
2
|
$xnum = $2; |
|
1075
|
1
|
|
|
|
|
2
|
$buf = $3; |
|
1076
|
1
|
|
|
|
|
1
|
$xdiff = length($buf); |
|
1077
|
|
|
|
|
|
|
|
|
1078
|
1
|
|
|
|
|
5
|
$fh->read($buf, 20 * $xnum - $xdiff + 15, $xdiff); |
|
1079
|
1
|
|
66
|
|
|
47
|
while ($xnum-- > 0 && $buf =~ s/^0*([0-9]*)$ws_char+0*([0-9]+)$ws_char+([nf])$cr//o) |
|
1080
|
6
|
|
|
|
|
41
|
{ $xlist->{$xmin++} = [$1, $2, $3]; } |
|
1081
|
|
|
|
|
|
|
} |
|
1082
|
|
|
|
|
|
|
|
|
1083
|
1
|
50
|
|
|
|
17
|
if ($buf !~ /^trailer$cr/oi) |
|
1084
|
0
|
|
|
|
|
0
|
{ die "Malformed trailer in PDF file $self->{' fname'} at " . ($fh->tell - length($buf)); } |
|
1085
|
|
|
|
|
|
|
|
|
1086
|
1
|
|
|
|
|
19
|
$buf =~ s/^trailer$cr//oi; |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
1
|
|
|
|
|
4
|
($tdict, $buf) = $self->readval($buf); |
|
1089
|
1
|
|
|
|
|
3
|
$tdict->{' loc'} = $xpos; |
|
1090
|
1
|
|
|
|
|
2
|
$tdict->{' xref'} = $xlist; |
|
1091
|
1
|
50
|
|
|
|
8
|
$self->{' maxobj'} = $xmin if $xmin > $self->{' maxobj'}; |
|
1092
|
|
|
|
|
|
|
$tdict->{' prev'} = $self->readxrtr($tdict->{'Prev'}->val) |
|
1093
|
1
|
50
|
33
|
|
|
4
|
if (defined $tdict->{'Prev'} && $tdict->{'Prev'}->val != 0); |
|
1094
|
1
|
|
|
|
|
3
|
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
|
|
|
|
|
1
|
my ($objind, $j, $i, $iend, @xreflist, $first, $k, $xref, $tloc, @freelist); |
|
1110
|
0
|
|
|
|
|
0
|
my (%locs, $size); |
|
1111
|
1
|
|
|
|
|
1
|
my ($fh) = $self->{' OUTFILE'}; |
|
1112
|
|
|
|
|
|
|
|
|
1113
|
1
|
|
|
|
|
2
|
while (@{$self->{' outlist'}}) |
|
|
2
|
|
|
|
|
6
|
|
|
1114
|
1
|
|
|
|
|
3
|
{ $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
|
|
|
|
|
4
|
$tdict->{'Size'} = PDFNum($self->{' maxobj'}); |
|
1133
|
|
|
|
|
|
|
|
|
1134
|
1
|
|
|
|
|
5
|
$tloc = $fh->tell; |
|
1135
|
1
|
|
|
|
|
4
|
$fh->print("xref\n"); |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
@xreflist = sort {$self->{' objects'}{$a->uid}[0] <=> |
|
1138
|
8
|
|
|
|
|
18
|
$self->{' objects'}{$b->uid}[0]} |
|
1139
|
1
|
|
|
|
|
3
|
(@{$self->{' printed'}}, @{$self->{' free'}}); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
1140
|
|
|
|
|
|
|
|
|
1141
|
1
|
50
|
|
|
|
3
|
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
|
|
|
|
|
4
|
$k = $xreflist[$j]; |
|
1148
|
5
|
|
|
|
|
7
|
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
|
|
|
|
|
4
|
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
|
|
|
|
|
2
|
$self->{' objects'}{$b->uid}[0]} @{$self->{' free'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
|
2
|
|
|
1164
|
|
|
|
|
|
|
|
|
1165
|
1
|
|
|
|
|
1
|
$j = 0; $first = -1; $k = 0; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
2
|
|
|
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
|
|
|
13
|
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
|
|
|
|
|
4
|
for ($j = $first; $j < $i; $j++) |
|
1182
|
|
|
|
|
|
|
{ |
|
1183
|
5
|
|
|
|
|
15
|
$xref = $xreflist[$j]; |
|
1184
|
5
|
50
|
33
|
|
|
11
|
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
|
|
|
|
|
9
|
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
|
|
|
|
|
9
|
{ $j++; } |
|
1203
|
|
|
|
|
|
|
} |
|
1204
|
1
|
|
|
|
|
2
|
$fh->print("trailer\n"); |
|
1205
|
1
|
|
|
|
|
4
|
$tdict->outobjdeep($fh, $self); |
|
1206
|
1
|
|
|
|
|
4
|
$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
|
|
3
|
my ($class) = @_; |
|
1219
|
2
|
|
|
|
|
3
|
my ($self) = {}; |
|
1220
|
|
|
|
|
|
|
|
|
1221
|
2
|
|
|
|
|
3
|
bless $self, $class; |
|
1222
|
2
|
|
|
|
|
7
|
$self->{' outlist'} = []; |
|
1223
|
2
|
|
|
|
|
2
|
$self->{' outlist_cache'} = {}; # A cache of whats in the 'outlist' |
|
1224
|
2
|
|
|
|
|
3
|
$self->{' maxobj'} = 1; |
|
1225
|
2
|
|
|
|
|
3
|
$self->{' objcache'} = {}; |
|
1226
|
2
|
|
|
|
|
3
|
$self->{' objects'} = {}; |
|
1227
|
2
|
|
|
|
|
3
|
$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
|
|
|
|
|
|
|
|