2 |
- |
1 |
% Copyright (C) 1994-2003 artofcode LLC. All rights reserved.
|
|
|
2 |
%
|
|
|
3 |
% This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
% implied.
|
|
|
5 |
%
|
|
|
6 |
% This software is distributed under license and may not be copied,
|
|
|
7 |
% modified or distributed except as expressly authorized under the terms
|
|
|
8 |
% of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
%
|
|
|
10 |
% For more information about licensing, please refer to
|
|
|
11 |
% http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
% commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
|
|
|
16 |
% $Id: pdf_base.ps,v 1.48 2005/09/16 19:01:30 ray Exp $
|
|
|
17 |
% pdf_base.ps
|
|
|
18 |
% Basic parser for PDF reader.
|
|
|
19 |
|
|
|
20 |
% This handles basic parsing of the file (including the trailer
|
|
|
21 |
% and cross-reference table), as well as objects, object references,
|
|
|
22 |
% streams, and name/number trees; it doesn't include any facilities for
|
|
|
23 |
% making marks on the page.
|
|
|
24 |
|
|
|
25 |
/.setlanguagelevel where { pop 2 .setlanguagelevel } if
|
|
|
26 |
.currentglobal true .setglobal
|
|
|
27 |
/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
|
|
|
28 |
pdfdict begin
|
|
|
29 |
|
|
|
30 |
% Define the name interpretation dictionary for reading values.
|
|
|
31 |
/valueopdict mark
|
|
|
32 |
(<<) cvn { mark } bind % don't push an actual mark!
|
|
|
33 |
(>>) cvn { { .dicttomark } stopped {
|
|
|
34 |
( **** File has an unbalanced >> \(close dictionary\).\n)
|
|
|
35 |
pdfformaterror
|
|
|
36 |
} if
|
|
|
37 |
} bind
|
|
|
38 |
([) cvn { mark } bind % ditto
|
|
|
39 |
(]) cvn dup load
|
|
|
40 |
% /true true % see .pdfexectoken below
|
|
|
41 |
% /false false % ibid.
|
|
|
42 |
% /null null % ibid.
|
|
|
43 |
/F dup cvx % see Objects section below
|
|
|
44 |
/R dup cvx % see Objects section below
|
|
|
45 |
/stream dup cvx % see Streams section below
|
|
|
46 |
.dicttomark readonly def
|
|
|
47 |
|
|
|
48 |
% ------ Utilities ------ %
|
|
|
49 |
|
|
|
50 |
% Define a scratch string. The PDF language definition says that
|
|
|
51 |
% no line in a PDF file can exceed 255 characters.
|
|
|
52 |
/pdfstring 255 string def
|
|
|
53 |
|
|
|
54 |
% Read the previous line of a file. If we aren't at a line boundary,
|
|
|
55 |
% read the line containing the current position.
|
|
|
56 |
% Skip any blank lines.
|
|
|
57 |
/prevline % - prevline <startpos> <substring>
|
|
|
58 |
{ PDFfile fileposition dup () pdfstring
|
|
|
59 |
2 index 257 sub 0 .max PDFfile exch setfileposition
|
|
|
60 |
{ % Stack: initpos linepos line string
|
|
|
61 |
PDFfile fileposition
|
|
|
62 |
PDFfile 2 index readline pop
|
|
|
63 |
dup length 0 gt
|
|
|
64 |
{ 3 2 roll 5 -2 roll pop pop 2 index }
|
|
|
65 |
{ pop }
|
|
|
66 |
ifelse
|
|
|
67 |
% Stack: initpos linepos line string startpos
|
|
|
68 |
PDFfile fileposition 5 index ge { exit } if
|
|
|
69 |
pop
|
|
|
70 |
}
|
|
|
71 |
loop pop pop 3 -1 roll pop
|
|
|
72 |
} bind def
|
|
|
73 |
|
|
|
74 |
% Handle the PDF 1.2 #nn escape convention when reading from a file.
|
|
|
75 |
% This should eventually be done in C.
|
|
|
76 |
/.pdffixname { % <execname> .pdffixname <execname'>
|
|
|
77 |
PDFversion 1.2 ge {
|
|
|
78 |
dup .namestring (#) search {
|
|
|
79 |
name#escape cvn exch pop
|
|
|
80 |
} {
|
|
|
81 |
pop
|
|
|
82 |
} ifelse
|
|
|
83 |
} if
|
|
|
84 |
} bind def
|
|
|
85 |
/name#escape % <post> <(#)> <pre> name#escape <string>
|
|
|
86 |
{ exch pop
|
|
|
87 |
1 index 2 () /SubFileDecode filter dup (x) readhexstring
|
|
|
88 |
% Stack: post pre stream char t/f
|
|
|
89 |
not { % tolerate, but complain about bad syntax
|
|
|
90 |
pop closefile (#) concatstrings exch
|
|
|
91 |
( **** Warning: Invalid hex following '#' name escape, using literal '#' in name.\n)
|
|
|
92 |
pdfformaterror
|
|
|
93 |
} {
|
|
|
94 |
exch closefile concatstrings
|
|
|
95 |
exch 2 1 index length 2 sub getinterval
|
|
|
96 |
} ifelse
|
|
|
97 |
(#) search { name#escape } if concatstrings
|
|
|
98 |
} bind def
|
|
|
99 |
|
|
|
100 |
% Execute a file, interpreting its executable names in a given
|
|
|
101 |
% dictionary. The name procedures may do whatever they want
|
|
|
102 |
% to the operand stack.
|
|
|
103 |
/.pdftokenerror { % <count> <opdict> <errtoken> .pdftokenerror -
|
|
|
104 |
BXlevel 0 le {
|
|
|
105 |
( **** Unknown operator: ') pdfformaterror
|
|
|
106 |
dup =string cvs pdfformaterror
|
|
|
107 |
% Attempt a retry scan of the element after changing to PDFScanInvNum
|
|
|
108 |
<< /PDFScanInvNum true >> setuserparams
|
|
|
109 |
=string cvs
|
|
|
110 |
token pop exch pop dup type
|
|
|
111 |
dup /integertype eq exch /realtype eq or {
|
|
|
112 |
exch pop exch pop
|
|
|
113 |
(', processed as number, value: ) pdfformaterror
|
|
|
114 |
dup =string cvs pdfformaterror (\n) pdfformaterror
|
|
|
115 |
<< /PDFScanInvNum null >> setuserparams % reset to default scanning rules
|
|
|
116 |
false % suppress any stack cleanup
|
|
|
117 |
} {
|
|
|
118 |
% error was non-recoverable with modified scanning rules
|
|
|
119 |
('\n) pdfformaterror
|
|
|
120 |
true
|
|
|
121 |
} ifelse
|
|
|
122 |
} {
|
|
|
123 |
true
|
|
|
124 |
} ifelse
|
|
|
125 |
{ % clean up the operand stack if this was non-recoverable
|
|
|
126 |
pop pop count exch sub { pop } repeat % pop all the operands
|
|
|
127 |
} if
|
|
|
128 |
} bind def
|
|
|
129 |
/.pdfexectoken { % <count> <opdict> <exectoken> .pdfexectoken ?
|
|
|
130 |
PDFDEBUG {
|
|
|
131 |
pdfdict /PDFSTEPcount known not { pdfdict /PDFSTEPcount 1 .forceput } if
|
|
|
132 |
PDFSTEP {
|
|
|
133 |
pdfdict /PDFtokencount 2 copy .knownget { 1 add } { 1 } ifelse .forceput
|
|
|
134 |
PDFSTEPcount 1 gt {
|
|
|
135 |
pdfdict /PDFSTEPcount PDFSTEPcount 1 sub .forceput
|
|
|
136 |
} {
|
|
|
137 |
dup ==only
|
|
|
138 |
( step # ) print PDFtokencount =only
|
|
|
139 |
( ? ) print flush 1 false .outputpage
|
|
|
140 |
(%stdin) (r) file 255 string readline {
|
|
|
141 |
token {
|
|
|
142 |
exch pop pdfdict /PDFSTEPcount 3 -1 roll .forceput
|
|
|
143 |
} {
|
|
|
144 |
pdfdict /PDFSTEPcount 1 .forceput
|
|
|
145 |
} ifelse % token
|
|
|
146 |
} {
|
|
|
147 |
pop /PDFSTEP false def % EOF on stdin
|
|
|
148 |
} ifelse % readline
|
|
|
149 |
} ifelse % PDFSTEPcount > 1
|
|
|
150 |
} {
|
|
|
151 |
dup ==only () = flush
|
|
|
152 |
} ifelse % PDFSTEP
|
|
|
153 |
} if % PDFDEBUG
|
|
|
154 |
2 copy .knownget {
|
|
|
155 |
exch pop exch pop exch pop exec
|
|
|
156 |
} {
|
|
|
157 |
% Normally, true, false, and null would appear in opdict
|
|
|
158 |
% and be treated as "operators". However, there is a
|
|
|
159 |
% special fast case in the PostScript interpreter for names
|
|
|
160 |
% that are defined in, and only in, systemdict and/or
|
|
|
161 |
% userdict: putting these three names in the PDF dictionaries
|
|
|
162 |
% destroys this property for them, slowing down their
|
|
|
163 |
% interpretation in all PostScript code. Therefore, we
|
|
|
164 |
% check for them explicitly here instead.
|
|
|
165 |
dup dup dup /true eq exch /false eq or exch /null eq or {
|
|
|
166 |
exch pop exch pop //systemdict exch get
|
|
|
167 |
} {
|
|
|
168 |
.pdftokenerror
|
|
|
169 |
} ifelse
|
|
|
170 |
} ifelse
|
|
|
171 |
} bind def
|
|
|
172 |
/.pdfrun { % <file> <opdict> .pdfrun -
|
|
|
173 |
% Construct a procedure with the stack depth, file and opdict
|
|
|
174 |
% bound into it.
|
|
|
175 |
1 index cvlit count 2 sub 3 1 roll mark mark 5 2 roll
|
|
|
176 |
{ % Stack: ..operands.. count opdict file
|
|
|
177 |
token {
|
|
|
178 |
dup type /nametype eq {
|
|
|
179 |
dup xcheck {
|
|
|
180 |
.pdfexectoken
|
|
|
181 |
} {
|
|
|
182 |
.pdffixname
|
|
|
183 |
exch pop exch pop PDFDEBUG {
|
|
|
184 |
PDFSTEPcount 1 le {
|
|
|
185 |
dup ==only ( ) print flush
|
|
|
186 |
} if
|
|
|
187 |
} if
|
|
|
188 |
} ifelse
|
|
|
189 |
} {
|
|
|
190 |
exch pop exch pop PDFDEBUG {
|
|
|
191 |
PDFSTEPcount 1 le {
|
|
|
192 |
dup ==only ( ) print flush
|
|
|
193 |
} if
|
|
|
194 |
} if
|
|
|
195 |
} ifelse
|
|
|
196 |
} {
|
|
|
197 |
(%%EOF) cvn cvx .pdfexectoken
|
|
|
198 |
} ifelse
|
|
|
199 |
}
|
|
|
200 |
aload pop .packtomark cvx
|
|
|
201 |
/loop cvx 2 packedarray cvx
|
|
|
202 |
{ stopped /PDFsource } aload pop
|
|
|
203 |
PDFsource
|
|
|
204 |
{ store { stop } if } aload pop .packtomark cvx
|
|
|
205 |
/PDFsource 3 -1 roll store exec
|
|
|
206 |
} bind def
|
|
|
207 |
|
|
|
208 |
% Execute a file, like .pdfrun, for a marking context.
|
|
|
209 |
% This temporarily rebinds LocalResources and DefaultQstate.
|
|
|
210 |
/.pdfruncontext { % <resdict> <file> <opdict> .pdfruncontext -
|
|
|
211 |
/.pdfrun load LocalResources DefaultQstate
|
|
|
212 |
/LocalResources 7 -1 roll store
|
|
|
213 |
/DefaultQstate qstate store
|
|
|
214 |
3 .execn
|
|
|
215 |
/DefaultQstate exch store
|
|
|
216 |
/LocalResources exch store
|
|
|
217 |
} bind def
|
|
|
218 |
|
|
|
219 |
% Get the depth of the PDF operand stack. The caller sets pdfemptycount
|
|
|
220 |
% before calling .pdfrun or .pdfruncontext. It is initially set by
|
|
|
221 |
% pdf_main, and is also set by any routine which changes the operand
|
|
|
222 |
% stack depth (currently .pdfpaintproc, although there are other callers
|
|
|
223 |
% of .pdfrun{context} which have not been checked for opstack depth.
|
|
|
224 |
/.pdfcount { % - .pdfcount <count>
|
|
|
225 |
count pdfemptycount sub
|
|
|
226 |
} bind def
|
|
|
227 |
|
|
|
228 |
% ================================ Objects ================================ %
|
|
|
229 |
|
|
|
230 |
% Since we may have more than 64K objects, we have to use a 2-D array to
|
|
|
231 |
% hold them (and the parallel Generations structure).
|
|
|
232 |
/lshift 9 def
|
|
|
233 |
/lnshift lshift neg def
|
|
|
234 |
/lsubmask 1 lshift bitshift 1 sub def
|
|
|
235 |
/lsublen lsubmask 1 add def
|
|
|
236 |
/larray { % - larray <larray>
|
|
|
237 |
[ [] ]
|
|
|
238 |
} bind def
|
|
|
239 |
/lstring { % - lstring <lstring>
|
|
|
240 |
[ () ]
|
|
|
241 |
} bind def
|
|
|
242 |
/ltype { % <lseq> type <type>
|
|
|
243 |
|
|
|
244 |
} bind def
|
|
|
245 |
/lget { % <lseq> <index> lget <value>
|
|
|
246 |
dup //lsubmask and 3 1 roll //lnshift bitshift get exch get
|
|
|
247 |
} bind def
|
|
|
248 |
/lput { % <lseq> <index> <value> lput -
|
|
|
249 |
3 1 roll
|
|
|
250 |
dup //lsubmask and 4 1 roll //lnshift bitshift get
|
|
|
251 |
3 1 roll put
|
|
|
252 |
} bind def
|
|
|
253 |
/llength { % <lseq> llength <length>
|
|
|
254 |
dup length 1 sub dup //lshift bitshift
|
|
|
255 |
3 1 roll get length add
|
|
|
256 |
} bind def
|
|
|
257 |
% lgrowto assumes newlength > llength(lseq)
|
|
|
258 |
/growto { % <string/array> <length> growto <string'/array'>
|
|
|
259 |
1 index type /stringtype eq { string } { array } ifelse
|
|
|
260 |
2 copy copy pop exch pop
|
|
|
261 |
} bind def
|
|
|
262 |
/lgrowto { % <lseq> <newlength> lgrowto <lseq'>
|
|
|
263 |
dup //lsubmask add //lnshift bitshift dup 3 index length gt {
|
|
|
264 |
% Add more sub-arrays. Start by completing the last existing one.
|
|
|
265 |
% Stack: lseq newlen newtoplen
|
|
|
266 |
3 -1 roll dup llength 1 sub //lsubmask or 1 add lgrowto
|
|
|
267 |
% Stack: newlen newtoplen lseq
|
|
|
268 |
[ exch aload pop
|
|
|
269 |
counttomark 2 add -1 roll % newtoplen
|
|
|
270 |
counttomark sub { dup 0 0 getinterval lsublen growto } repeat
|
|
|
271 |
dup 0 0 getinterval ] exch
|
|
|
272 |
} {
|
|
|
273 |
pop
|
|
|
274 |
} ifelse
|
|
|
275 |
% Expand the last sub-array.
|
|
|
276 |
1 sub //lsubmask and 1 add
|
|
|
277 |
exch dup dup length 1 sub 2 copy
|
|
|
278 |
% Stack: newsublen lseq lseq len-1 lseq len-1
|
|
|
279 |
get 5 -1 roll growto put
|
|
|
280 |
} bind def
|
|
|
281 |
/lforall { % <lseq> <proc> lforall -
|
|
|
282 |
/forall cvx 2 packedarray cvx forall
|
|
|
283 |
} bind def
|
|
|
284 |
|
|
|
285 |
% We keep track of PDF objects using the following PostScript variables:
|
|
|
286 |
%
|
|
|
287 |
% Generations (lstring): Generations[N] holds 1+ the current
|
|
|
288 |
% generation number for object number N. (As far as we can tell,
|
|
|
289 |
% this is needed only for error checking.) For free objects,
|
|
|
290 |
% Generations[N] is 0.
|
|
|
291 |
%
|
|
|
292 |
% Objects (larray): If object N is loaded, Objects[N] is the actual
|
|
|
293 |
% object; otherwise, Objects[N] is an executable integer giving
|
|
|
294 |
% the file offset of the object's location in the file. If
|
|
|
295 |
% ObjectStream[N] is non-zero then Objects[N] contains the index
|
|
|
296 |
% into the object stream instead of the file offset of the object.
|
|
|
297 |
%
|
|
|
298 |
% ObjectStream (larray): If object N is in an object stream then
|
|
|
299 |
% ObjectStream[N] holds the object number of the object stream.
|
|
|
300 |
% Otherwise ObjectStream[N] contains 0. If ObjectStream[N]
|
|
|
301 |
% is non-zero then Objects[N] contains the index into the object
|
|
|
302 |
% stream.
|
|
|
303 |
%
|
|
|
304 |
% GlobalObjects (dictionary): If object N has been resolved in
|
|
|
305 |
% global VM, GlobalObjects[N] is the same as Objects[N]
|
|
|
306 |
% (except that GlobalObjects itself is stored in global VM,
|
|
|
307 |
% so the entry will not be deleted at the end of the page).
|
|
|
308 |
%
|
|
|
309 |
% IsGlobal (lstring): IsGlobal[N] = 1 iff object N was resolved in
|
|
|
310 |
% global VM. This is an accelerator to avoid having to do a
|
|
|
311 |
% dictionary lookup in GlobalObjects when resolving every object.
|
|
|
312 |
|
|
|
313 |
% Initialize the PDF object tables.
|
|
|
314 |
/initPDFobjects { % - initPDFobjects -
|
|
|
315 |
/ObjectStream larray def
|
|
|
316 |
/Objects larray def
|
|
|
317 |
/Generations lstring def
|
|
|
318 |
.currentglobal true .setglobal
|
|
|
319 |
/GlobalObjects 20 dict def
|
|
|
320 |
.setglobal
|
|
|
321 |
/IsGlobal lstring def
|
|
|
322 |
} bind def
|
|
|
323 |
|
|
|
324 |
% Grow the tables to a specified size.
|
|
|
325 |
/growPDFobjects { % <minsize> growPDFobjects -
|
|
|
326 |
dup ObjectStream llength gt {
|
|
|
327 |
dup ObjectStream exch lgrowto /ObjectStream exch def
|
|
|
328 |
} if
|
|
|
329 |
dup Objects llength gt {
|
|
|
330 |
dup Objects exch lgrowto /Objects exch def
|
|
|
331 |
} if
|
|
|
332 |
dup Generations llength gt {
|
|
|
333 |
dup Generations exch lgrowto /Generations exch def
|
|
|
334 |
} if
|
|
|
335 |
dup IsGlobal llength gt {
|
|
|
336 |
dup IsGlobal exch lgrowto /IsGlobal exch def
|
|
|
337 |
} if
|
|
|
338 |
pop
|
|
|
339 |
} bind def
|
|
|
340 |
|
|
|
341 |
% We represent an unresolved object reference by a procedure of the form
|
|
|
342 |
% {obj# gen# resolveR}. This is not a possible PDF object, because PDF has
|
|
|
343 |
% no way to represent procedures. Since PDF in fact has no way to represent
|
|
|
344 |
% any PostScript object that doesn't evaluate to itself, we can 'force'
|
|
|
345 |
% a possibly indirect object painlessly with 'exec'.
|
|
|
346 |
% Note that since we represent streams by executable dictionaries
|
|
|
347 |
% (see below), we need both an xcheck and a type check to determine
|
|
|
348 |
% whether an object has been resolved.
|
|
|
349 |
/resolved? { % <object#> resolved? <value> true
|
|
|
350 |
% <object#> resolved? false
|
|
|
351 |
Objects 1 index lget dup xcheck { % Check if executable
|
|
|
352 |
dup type /integertype eq { % Check if an integer
|
|
|
353 |
% Check whether the object is in GlobalObjects.
|
|
|
354 |
pop IsGlobal 1 index lget 0 eq { % 0 --> Not in GlabalObjects
|
|
|
355 |
pop false % The object is not resolved
|
|
|
356 |
} { % The object is in GlobalObjects
|
|
|
357 |
% Update Objects from GlobalObjects
|
|
|
358 |
PDFDEBUG { (%Global=>local: ) print dup == } if
|
|
|
359 |
GlobalObjects 1 index get dup Objects 4 1 roll lput true
|
|
|
360 |
} ifelse
|
|
|
361 |
} { % Else object is executable but not integer
|
|
|
362 |
exch pop true % Therefore must be executable dict. (stream)
|
|
|
363 |
} ifelse
|
|
|
364 |
} { % Else object is not executable.
|
|
|
365 |
exch pop true % Therefore it must have been resolved.
|
|
|
366 |
} ifelse
|
|
|
367 |
} bind def
|
|
|
368 |
/oforce /exec load def
|
|
|
369 |
/oget { % <array> <index> oget <object>
|
|
|
370 |
% <dict> <key> oget <object>
|
|
|
371 |
% Before release 6.20, this procedure stored the resolved
|
|
|
372 |
% object back into the referring slot. In order to support
|
|
|
373 |
% PDF linearization, we no longer do this.
|
|
|
374 |
get oforce
|
|
|
375 |
} bind def
|
|
|
376 |
/oforce_array { % <array> oforce_array <array>
|
|
|
377 |
[ exch { oforce } forall ]
|
|
|
378 |
} bind def
|
|
|
379 |
/oforce_elems { % <array> oforce_elems <first> ... <last>
|
|
|
380 |
{ oforce } forall
|
|
|
381 |
} bind def
|
|
|
382 |
% A null value in a dictionary is equivalent to an omitted key;
|
|
|
383 |
% we must check for this specially.
|
|
|
384 |
/knownoget { % <dict> <key> knownoget <value> true
|
|
|
385 |
% <dict> <key> knownoget false
|
|
|
386 |
% See oget above regarding this procedure.
|
|
|
387 |
.knownget {
|
|
|
388 |
oforce dup null eq { pop false } { true } ifelse
|
|
|
389 |
} {
|
|
|
390 |
false
|
|
|
391 |
} ifelse
|
|
|
392 |
} bind def
|
|
|
393 |
|
|
|
394 |
% PDF 1.1 defines a 'foreign file reference', but not its meaning.
|
|
|
395 |
% Per the specification, we convert these to nulls.
|
|
|
396 |
/F { % <file#> <object#> <generation#> F <object>
|
|
|
397 |
% Some PDF 1.1 files use F as a synonym for f!
|
|
|
398 |
.pdfcount 3 lt { f } { pop pop pop null } ifelse
|
|
|
399 |
} bind def
|
|
|
400 |
|
|
|
401 |
% Verify the generation number for a specified object
|
|
|
402 |
% Note: The values in Generations is the generation number plus 1.
|
|
|
403 |
% If the value in Generations is zero then the object is free.
|
|
|
404 |
/checkgeneration { % <object#> <generation#> checkgeneration <object#> <OK>
|
|
|
405 |
Generations 2 index lget 1 sub 1 index eq { % If generation # match ...
|
|
|
406 |
pop true % Then return true
|
|
|
407 |
} { % Else not a match ...
|
|
|
408 |
QUIET not { % Create warning message if not QUIET
|
|
|
409 |
Generations 2 index lget 0 eq { % Check if object is free ...
|
|
|
410 |
( **** Warning: reference to free object: )
|
|
|
411 |
} {
|
|
|
412 |
( **** Warning: wrong generation: )
|
|
|
413 |
} ifelse
|
|
|
414 |
2 index =string cvs concatstrings ( ) concatstrings % put obj #
|
|
|
415 |
exch =string cvs concatstrings ( R\n) concatstrings % put gen #
|
|
|
416 |
pdfformaterror % Output warning message
|
|
|
417 |
} { % Else QUIET ...
|
|
|
418 |
pop % Pop generation umber
|
|
|
419 |
} ifelse false % Return false if gen # not match
|
|
|
420 |
} ifelse
|
|
|
421 |
} bind def
|
|
|
422 |
/R { % <object#> <generation#> R <object>
|
|
|
423 |
/resolveR cvx 3 packedarray cvx
|
|
|
424 |
} bind def
|
|
|
425 |
|
|
|
426 |
% If we encounter an object definition while reading sequentially,
|
|
|
427 |
% we just store it away and keep going.
|
|
|
428 |
/objopdict mark
|
|
|
429 |
valueopdict { } forall
|
|
|
430 |
/endobj dup cvx
|
|
|
431 |
.dicttomark readonly def
|
|
|
432 |
|
|
|
433 |
/obj { % <object#> <generation#> obj <object>
|
|
|
434 |
PDFfile objopdict .pdfrun
|
|
|
435 |
} bind def
|
|
|
436 |
|
|
|
437 |
/endobj { % <object#> <generation#> <object> endobj <object>
|
|
|
438 |
3 1 roll
|
|
|
439 |
% Read the xref entry if we haven't yet done so.
|
|
|
440 |
% This is only needed for generation # checking.
|
|
|
441 |
1 index resolved? {
|
|
|
442 |
pop
|
|
|
443 |
} if
|
|
|
444 |
checkgeneration {
|
|
|
445 |
% The only global objects we bother to save are
|
|
|
446 |
% (resource) dictionaries.
|
|
|
447 |
1 index dup gcheck exch type /dicttype eq and {
|
|
|
448 |
PDFDEBUG { (%Local=>global: ) print dup == } if
|
|
|
449 |
GlobalObjects 1 index 3 index put
|
|
|
450 |
IsGlobal 1 index 1 put
|
|
|
451 |
} if
|
|
|
452 |
Objects exch 2 index lput
|
|
|
453 |
} {
|
|
|
454 |
pop pop null
|
|
|
455 |
} ifelse
|
|
|
456 |
} bind def
|
|
|
457 |
|
|
|
458 |
% When resolving an object reference in an object stream, we stop at
|
|
|
459 |
% the end of file. Note: Objects in an object stream do not have either
|
|
|
460 |
% a starting 'obj' or and ending 'endobj'.
|
|
|
461 |
/resolveobjstreamopdict mark
|
|
|
462 |
valueopdict { } forall
|
|
|
463 |
(%%EOF) cvn { exit } bind
|
|
|
464 |
.dicttomark readonly def
|
|
|
465 |
|
|
|
466 |
% Note: This version of this function is not currently being used.
|
|
|
467 |
% Resolve all objects in an object stream
|
|
|
468 |
/resolveobjectstream { % <object stream #> resolveobjectstream -
|
|
|
469 |
PDFDEBUG { (%Resolving object stream: ) print } if
|
|
|
470 |
|
|
|
471 |
dup /First get % Save location of first object onto the stack
|
|
|
472 |
1 index /N get % Save number of objects onto the stack
|
|
|
473 |
2 index false resolvestream % Convert stream dict into a stream
|
|
|
474 |
/ReusableStreamDecode filter % We need to be able to position stream
|
|
|
475 |
% Objectstreams begin with list of object numbers and locations
|
|
|
476 |
% Create two arrays to hold object numbers and stream location
|
|
|
477 |
1 index array % Array for holding object number
|
|
|
478 |
2 index array % Array for holding stream object location
|
|
|
479 |
% Get the object numbers and locations.
|
|
|
480 |
|
|
|
481 |
% Stack: objstreamdict First N objectstream [obj#] [loc] index
|
|
|
482 |
2 index 1 index % Setup to put obj# into object number array
|
|
|
483 |
5 index token pop put % Get stream, then get obj# and put into array
|
|
|
484 |
1 index 1 index % Setup to put object loc into location array
|
|
|
485 |
5 index token pop put % Get stream, get obj loc and put into array
|
|
|
486 |
pop % Remove loop index
|
|
|
487 |
} for
|
|
|
488 |
% Create a bytestring big enough for reading any object data
|
|
|
489 |
% Scan for the size of the largest object
|
|
|
490 |
|
|
|
491 |
2 index { % Loop through all object locations
|
|
|
492 |
% Stack: ... maxsize prevloc currentloc
|
|
|
493 |
dup 4 1 roll % Save copy of object location into stack
|
|
|
494 |
exch sub % Object size = currentloc - prevloc
|
|
|
495 |
.max % Determine maximum object size
|
|
|
496 |
exch % Put max size under previous location
|
|
|
497 |
} forall
|
|
|
498 |
pop % Remove previous location
|
|
|
499 |
.bigstring % Create bytestring based upon max obj size
|
|
|
500 |
% Move to the start of the object data
|
|
|
501 |
3 index 6 index % Get objectstream and start of first object
|
|
|
502 |
setfileposition % Move to the start of the data
|
|
|
503 |
% Read the data for all objects except the last. We do
|
|
|
504 |
% not know the size of the last object so we need to treat
|
|
|
505 |
% it as a special case.
|
|
|
506 |
|
|
|
507 |
dup 4 index exch get % Get our current object number
|
|
|
508 |
% Stack: objstreamdict First N objectstream [obj#] [loc]
|
|
|
509 |
% bytestring loopindex object#
|
|
|
510 |
dup resolved? { % If we already have this object
|
|
|
511 |
(yyy) = pstack (yyy) = flush xxx
|
|
|
512 |
pop pop % Remove object and object number
|
|
|
513 |
1 add 2 index exch get % Get location of next object
|
|
|
514 |
6 index add 6 index exch % Form location of next object and get stream
|
|
|
515 |
setfileposition % Move to the start of the next object data
|
|
|
516 |
} { % Else this is a new object ...
|
|
|
517 |
% We are going to create a string for reading the object
|
|
|
518 |
2 index 0 % use our working string
|
|
|
519 |
% Determine the size of the object
|
|
|
520 |
5 index 4 index 1 add get % Get location of the next object
|
|
|
521 |
6 index 5 index get % Get location of this object
|
|
|
522 |
sub % Size of object = next loc - this loc
|
|
|
523 |
getinterval % Create string for reading object
|
|
|
524 |
6 index exch readstring pop % Read object
|
|
|
525 |
/ReusableStreamDecode filter % Convert string into a stream
|
|
|
526 |
resolveobjstreamopdict .pdfrun % Get PDF object
|
|
|
527 |
Objects exch 2 index exch lput % Put object into Objects array
|
|
|
528 |
pop pop % Remove object # and loop index
|
|
|
529 |
} ifelse
|
|
|
530 |
} for
|
|
|
531 |
pop pop % Remove our working string and loc array
|
|
|
532 |
% Now read the last object in the object stream. Since it
|
|
|
533 |
% is the last object, we can use the original stream and
|
|
|
534 |
% terminate when we hit the end of the stream
|
|
|
535 |
% Stack: objstreamdict First N objectstream [obj#]
|
|
|
536 |
2 index 1 sub get % Get our current object number
|
|
|
537 |
dup resolved? not { % If we do not already have this object
|
|
|
538 |
exch % Get our object stream
|
|
|
539 |
resolveobjstreamopdict .pdfrun % Get PDF object
|
|
|
540 |
Objects exch 2 index exch lput % Put object into Objects array
|
|
|
541 |
} if
|
|
|
542 |
pop pop pop pop % Clear stack
|
|
|
543 |
} bind def
|
|
|
544 |
|
|
|
545 |
% Resolve all objects in an object stream
|
|
|
546 |
/resolveobjectstream { % <object stream #> resolveobjectstream -
|
|
|
547 |
PDFDEBUG { (%Resolving object stream: ) print } if
|
|
|
548 |
|
|
|
549 |
dup /Type get /ObjStm ne { % Verify type is object stream
|
|
|
550 |
( **** Incorrect Type in object stream dictionary.\n) pdfformaterror
|
|
|
551 |
/resolveobjectstream cvx /typecheck signalerror
|
|
|
552 |
} if
|
|
|
553 |
dup /N get % Save number of objects onto the stack
|
|
|
554 |
1 index false resolvestream % Convert stream dict into a stream
|
|
|
555 |
/ReusableStreamDecode filter % We need to be able to position stream
|
|
|
556 |
% Objectstreams begin with list of object numbers and locations
|
|
|
557 |
1 index array % Create array for holding object number
|
|
|
558 |
% Get the object numbers
|
|
|
559 |
|
|
|
560 |
% Stack: objstreamdict N PDFDEBUG objectstream [obj#] loopindex
|
|
|
561 |
1 index 1 index % Setup to put obj# into object number array
|
|
|
562 |
4 index token pop put % Get stream, then get obj# and put into array
|
|
|
563 |
2 index token pop pop pop % Get stream, get obj loc and clear stack
|
|
|
564 |
} for
|
|
|
565 |
% Move to the start of the object data
|
|
|
566 |
1 index 4 index /First get % Get objectstream and start of first object
|
|
|
567 |
setfileposition % Move to the start of the data
|
|
|
568 |
% We disable PDFDEBUG while reading the data stream. We will
|
|
|
569 |
% print the data later
|
|
|
570 |
PDFDEBUG /PDFDEBUG false def % Save PDFDEBUG and disable it while reading
|
|
|
571 |
% Read the data for all objects. We check to see if we get
|
|
|
572 |
% the number of objects that we expect.
|
|
|
573 |
% Stack: objstreamdict N objectstream [obj#] PDFDEBUG
|
|
|
574 |
mark 4 -1 roll % Get objectstream
|
|
|
575 |
count 5 index add % Determine stack depth with objects
|
|
|
576 |
/PDFObjectStkCount exch def
|
|
|
577 |
resolveobjstreamopdict .pdfrun % Get PDF objects
|
|
|
578 |
PDFObjectStkCount count ne { % Check stack depth
|
|
|
579 |
( **** Incorrect object count in object stream.\n) pdfformaterror
|
|
|
580 |
/resolveobjectstream cvx /rangecheck signalerror
|
|
|
581 |
} if
|
|
|
582 |
% We have the object data
|
|
|
583 |
counttomark array astore % Put objects into an array
|
|
|
584 |
exch pop % Remove mark
|
|
|
585 |
exch /PDFDEBUG exch def % Restore PDFDEBUG flag
|
|
|
586 |
% Save the objects into Objects
|
|
|
587 |
|
|
|
588 |
% Stack: objstreamdict N [obj#] [objects] loopindex
|
|
|
589 |
dup 3 index exch get % Get our current object number
|
|
|
590 |
dup resolved? { % If we already have this object
|
|
|
591 |
pop pop % Remove object and object number
|
|
|
592 |
} { % Else if we do not have this object
|
|
|
593 |
PDFDEBUG { (%Resolving compressed object: [) print dup =only ( 0]) = } if
|
|
|
594 |
Objects exch 3 index % Put the object into Objects
|
|
|
595 |
3 index get
|
|
|
596 |
PDFDEBUG { dup === flush } if
|
|
|
597 |
lput
|
|
|
598 |
} ifelse
|
|
|
599 |
pop % Remove loop index
|
|
|
600 |
} for
|
|
|
601 |
pop pop pop pop % Remove objstream, N, (obj#], and [objects]
|
|
|
602 |
} bind def
|
|
|
603 |
|
|
|
604 |
% When resolving an object reference, we stop at the endobj or endstream.
|
|
|
605 |
/resolveopdict mark
|
|
|
606 |
valueopdict { } forall
|
|
|
607 |
/endstream { endobj exit } bind
|
|
|
608 |
/endobj { endobj exit } bind
|
|
|
609 |
% OmniForm generates PDF file with endobj missing in some
|
|
|
610 |
% objects. AR ignores this. So we have to do it too.
|
|
|
611 |
/obj { pop pop endobj exit } bind
|
|
|
612 |
.dicttomark readonly def
|
|
|
613 |
|
|
|
614 |
/resolveR { % <object#> <generation#> resolveR <object>
|
|
|
615 |
PDFDEBUG {
|
|
|
616 |
PDFSTEPcount 1 le {
|
|
|
617 |
(%Resolving: ) print 2 copy 2 array astore ==
|
|
|
618 |
} if
|
|
|
619 |
} if
|
|
|
620 |
1 index resolved? { % If object has already been resolved ...
|
|
|
621 |
exch pop exch pop % then clear stack and return object
|
|
|
622 |
} { % Else if not resolved ...
|
|
|
623 |
PDFfile fileposition 3 1 roll % Save current file position
|
|
|
624 |
1 index Objects exch lget % Get location of object from xref
|
|
|
625 |
3 1 roll checkgeneration { % Verify the generation number
|
|
|
626 |
% Stack: savepos objpos obj#
|
|
|
627 |
ObjectStream 1 index lget dup 0 eq { % Check if obj in not an objstream
|
|
|
628 |
pop exch PDFoffset add PDFfile exch setfileposition
|
|
|
629 |
PDFfile token pop 2 copy ne
|
|
|
630 |
{ ( **** Unrecoverable error in xref!\n) pdfformaterror
|
|
|
631 |
/resolveR cvx /rangecheck signalerror
|
|
|
632 |
}
|
|
|
633 |
if pop PDFfile token pop
|
|
|
634 |
PDFfile token pop /obj ne
|
|
|
635 |
{ ( **** Unrecoverable error in xref!\n) pdfformaterror
|
|
|
636 |
/resolveR cvx /rangecheck signalerror
|
|
|
637 |
}
|
|
|
638 |
if
|
|
|
639 |
pdf_run_resolve % PDFfile resolveopdict .pdfrun
|
|
|
640 |
} { % Else the object is in an ObjectStream
|
|
|
641 |
% Process an objectstream object. We are going to resolve all
|
|
|
642 |
% of the objects in sthe stream and place them into the Objects
|
|
|
643 |
% array.
|
|
|
644 |
% Stack: savepos objpos obj# objectstream#
|
|
|
645 |
resolveobjectstream
|
|
|
646 |
resolved? { % If object has already been resolved ...
|
|
|
647 |
exch pop % Remove object pos from stack.
|
|
|
648 |
} {
|
|
|
649 |
pop pop null % Pop objpos and obj#, put null for object
|
|
|
650 |
} ifelse
|
|
|
651 |
} ifelse
|
|
|
652 |
} { % Else the generation number is wrong
|
|
|
653 |
% Don't cache if the generation # is wrong.
|
|
|
654 |
pop pop null % Pop objpos and obj#, put null for object
|
|
|
655 |
} ifelse % ifelse generation number is correct
|
|
|
656 |
exch PDFfile exch setfileposition % Return to original file position
|
|
|
657 |
} ifelse
|
|
|
658 |
} bind def
|
|
|
659 |
|
|
|
660 |
% ================================ Streams ================================ %
|
|
|
661 |
|
|
|
662 |
% We represent a stream by an executable dictionary that contains,
|
|
|
663 |
% in addition to the contents of the original stream dictionary:
|
|
|
664 |
% /File - the file or string where the stream contents are stored,
|
|
|
665 |
% if the stream is not an external one.
|
|
|
666 |
% /FilePosition - iff File is a file, the position in the file
|
|
|
667 |
% where the contents start.
|
|
|
668 |
% /StreamKey - the key used to decrypt this stream, if any.
|
|
|
669 |
% We do the real work of constructing the data stream only when the
|
|
|
670 |
% contents are needed.
|
|
|
671 |
|
|
|
672 |
% Construct a stream. The length is not reliable in the face of
|
|
|
673 |
% different end-of-line conventions, but it's all we've got.
|
|
|
674 |
%
|
|
|
675 |
% PDF files are inconsistent about what may fall between the 'stream' keyword
|
|
|
676 |
% and the actual stream data, and it appears that no one algorithm can
|
|
|
677 |
% detect this reliably. We used to try to guess whether the file included
|
|
|
678 |
% extraneous \r and/or \n characters, but we no longer attempt to do so,
|
|
|
679 |
% especially since the PDF 1.2 specification states flatly that the only
|
|
|
680 |
% legal terminators following the 'stream' keyword are \n or \r\n, both of
|
|
|
681 |
% which are properly skipped and discarded by the token operator.
|
|
|
682 |
% Unfortunately, this doesn't account for other whitespace characters that
|
|
|
683 |
% may have preceded the EOL, such as spaces or tabs. Thus we back up one
|
|
|
684 |
% character and scan until we find the \n terminator.
|
|
|
685 |
/stream { % <dict> stream <modified_dict>
|
|
|
686 |
dup /Length oget 0 eq {
|
|
|
687 |
dup /Filter undef % don't confuse any filters that require data
|
|
|
688 |
} if
|
|
|
689 |
dup /F known dup PDFsource PDFfile eq or {
|
|
|
690 |
not {
|
|
|
691 |
dup /File PDFfile put
|
|
|
692 |
% make sure that we are just past the EOL \n character
|
|
|
693 |
PDFfile dup fileposition 1 sub setfileposition % back up one
|
|
|
694 |
{ PDFfile read pop dup 13 eq {
|
|
|
695 |
% If there had been a \n, token would have advanced over it
|
|
|
696 |
% thus, if the terminator was \r, we have a format error!
|
|
|
697 |
( **** Warning: stream operator not terminated by valid EOL.\n) pdfformaterror
|
|
|
698 |
pop exit % fileposition is OK (just past the \r).
|
|
|
699 |
} if
|
|
|
700 |
10 eq { exit } if
|
|
|
701 |
} loop % scan past \n
|
|
|
702 |
dup /FilePosition PDFfile fileposition put
|
|
|
703 |
PDFDEBUG {
|
|
|
704 |
PDFSTEPcount 1 le {
|
|
|
705 |
(%FilePosition: ) print dup /FilePosition get ==
|
|
|
706 |
} if
|
|
|
707 |
} if
|
|
|
708 |
} if
|
|
|
709 |
% Some (bad) PDf files have invalid stream lengths. This causes problems
|
|
|
710 |
% if we reposition beyond the end of the file. So we compare the given
|
|
|
711 |
% length to number of bytes left in the file.
|
|
|
712 |
dup /Length oget
|
|
|
713 |
dup PDFfile bytesavailable lt { % compare to to bytes left in file
|
|
|
714 |
PDFfile fileposition % reposition to the end of stream
|
|
|
715 |
add PDFfile exch setfileposition
|
|
|
716 |
} {
|
|
|
717 |
pop % bad stream length - do not reposition.
|
|
|
718 |
% This will force a length warning below
|
|
|
719 |
} ifelse
|
|
|
720 |
} {
|
|
|
721 |
pop
|
|
|
722 |
% We're already reading from a stream, which we can't reposition.
|
|
|
723 |
% Capture the sub-stream contents in a string.
|
|
|
724 |
dup /Length oget string PDFsource exch readstring
|
|
|
725 |
not {
|
|
|
726 |
( **** Warning: Unexpected EOF in stream!\n) pdfformaterror
|
|
|
727 |
/stream cvx /rangecheck signalerror
|
|
|
728 |
} if
|
|
|
729 |
1 index exch /File exch put
|
|
|
730 |
} ifelse
|
|
|
731 |
PDFsource {token} stopped {
|
|
|
732 |
pop null
|
|
|
733 |
} {
|
|
|
734 |
not { null } if
|
|
|
735 |
} ifelse
|
|
|
736 |
dup /endobj eq {
|
|
|
737 |
% Another case that Acrobat Reader handles -- 'endobj' without 'endstream'.
|
|
|
738 |
( **** Warning: stream missing 'endstream'.\n) pdfformaterror
|
|
|
739 |
pop /endstream % fake a valid endstream
|
|
|
740 |
} if
|
|
|
741 |
/endstream ne {
|
|
|
742 |
( **** Warning: stream Length incorrect.\n) pdfformaterror
|
|
|
743 |
dup /Length undef % prevent the use of the incorrect length.
|
|
|
744 |
cvx endobj exit % exit from .pdfrun now.
|
|
|
745 |
} if
|
|
|
746 |
cvx
|
|
|
747 |
} bind def
|
|
|
748 |
/endstream {
|
|
|
749 |
exit
|
|
|
750 |
} bind def
|
|
|
751 |
|
|
|
752 |
% Contrary to the published PDF (1.3) specification, Acrobat Reader
|
|
|
753 |
% accepts abbreviated filter names everywhere, not just for in-line images,
|
|
|
754 |
% and some applications (notably htmldoc) rely on this.
|
|
|
755 |
/unabbrevfilterdict mark
|
|
|
756 |
/AHx /ASCIIHexDecode /A85 /ASCII85Decode /CCF /CCITTFaxDecode
|
|
|
757 |
/DCT /DCTDecode /Fl /FlateDecode /LZW /LZWDecode /RL /RunLengthDecode
|
|
|
758 |
.dicttomark readonly def
|
|
|
759 |
|
|
|
760 |
% Extract and apply filters.
|
|
|
761 |
/filterparms { % <dict> <DPkey> <Fkey> filterparms
|
|
|
762 |
% <dict> <parms> <filternames>
|
|
|
763 |
2 index exch knownoget {
|
|
|
764 |
exch 2 index exch knownoget {
|
|
|
765 |
% Both filters and parameters.
|
|
|
766 |
exch dup type /nametype eq {
|
|
|
767 |
1 array astore exch
|
|
|
768 |
dup type /arraytype ne { 1 array astore } if exch
|
|
|
769 |
} if
|
|
|
770 |
} {
|
|
|
771 |
% Filters, but no parameters.
|
|
|
772 |
null exch
|
|
|
773 |
dup type /nametype eq { 1 array astore } if
|
|
|
774 |
} ifelse
|
|
|
775 |
} {
|
|
|
776 |
% No filters: ignore parameters, if any.
|
|
|
777 |
pop null { }
|
|
|
778 |
} ifelse
|
|
|
779 |
} bind def
|
|
|
780 |
/filtername { % <filtername> filtername <filtername'>
|
|
|
781 |
//unabbrevfilterdict 1 index .knownget { exch pop } if
|
|
|
782 |
dup /Filter resourcestatus { pop pop } {
|
|
|
783 |
Repaired exch % this error is not the creator's fault
|
|
|
784 |
( **** ERROR: Unable to process ) pdfformaterror
|
|
|
785 |
64 string cvs pdfformaterror
|
|
|
786 |
( data. Page will be missing data.\n) pdfformaterror
|
|
|
787 |
/Repaired exch store % restore the previous "Repaired" state
|
|
|
788 |
% provide a filter that returns EOF (no data)
|
|
|
789 |
/.EOFDecode
|
|
|
790 |
} ifelse
|
|
|
791 |
} bind def
|
|
|
792 |
/applyfilters { % <parms> <source> <filternames> applyfilters <stream>
|
|
|
793 |
2 index null eq {
|
|
|
794 |
{ filtername filter }
|
|
|
795 |
} {
|
|
|
796 |
{ % Stack: parms source filtername
|
|
|
797 |
2 index 0 oget dup null eq { pop } {
|
|
|
798 |
exch filtername dup /JBIG2Decode eq { exch jbig2cachectx exch } if
|
|
|
799 |
} ifelse filter
|
|
|
800 |
exch dup length 1 sub 1 exch getinterval exch
|
|
|
801 |
}
|
|
|
802 |
} ifelse forall exch pop
|
|
|
803 |
} bind def
|
|
|
804 |
|
|
|
805 |
% JBIG2 streams have an optional 'globals' stream obj for
|
|
|
806 |
% sharing redundant data between page images. Here we resolve
|
|
|
807 |
% that stream reference (if any) and run it through the decoder,
|
|
|
808 |
% creating a special -jbig2globalctx- postscript object our
|
|
|
809 |
% JBIG2Decode filter implementation looks for in the parm dict.
|
|
|
810 |
/jbig2cachectx { % <parmdict> jbig2cachectx <parmdict>
|
|
|
811 |
dup /JBIG2Globals knownoget {
|
|
|
812 |
dup /Length oget
|
|
|
813 |
% make global ctx
|
|
|
814 |
PDFfile fileposition 3 1 roll % resolvestream is not reentrant
|
|
|
815 |
exch true resolvestream exch .bytestring
|
|
|
816 |
.readbytestring pop .jbig2makeglobalctx
|
|
|
817 |
PDFfile 3 -1 roll setfileposition
|
|
|
818 |
1 index exch
|
|
|
819 |
/.jbig2globalctx exch put
|
|
|
820 |
} if
|
|
|
821 |
} bind def
|
|
|
822 |
|
|
|
823 |
% Resolve a stream dictionary to a PostScript stream.
|
|
|
824 |
% Streams with no filters require special handling:
|
|
|
825 |
% - Whether we are going to interpret the stream, or If we are just
|
|
|
826 |
% going to read data from them, we impose a SubFileDecode filter
|
|
|
827 |
% that reads just the requisite amount of data.
|
|
|
828 |
% Note that, in general, resolving a stream repositions PDFfile.
|
|
|
829 |
% Clients must save and restore the position of PDFfile themselves.
|
|
|
830 |
/resolvestream { % <streamdict> <readdata?> resolvestream <stream>
|
|
|
831 |
1 index /F knownoget {
|
|
|
832 |
% This stream is stored on an external file.
|
|
|
833 |
(r) file 3 -1 roll
|
|
|
834 |
/FDecodeParms /FFilter filterparms
|
|
|
835 |
% Stack: readdata? file dict parms filternames
|
|
|
836 |
4 -1 roll exch
|
|
|
837 |
pdf_decrypt_stream
|
|
|
838 |
applyfilters
|
|
|
839 |
} {
|
|
|
840 |
exch dup /FilePosition .knownget {
|
|
|
841 |
1 index /File get exch setfileposition
|
|
|
842 |
} if
|
|
|
843 |
% Stack: readdata? dict
|
|
|
844 |
/DecodeParms /Filter filterparms
|
|
|
845 |
% Stack: readdata? dict parms filternames
|
|
|
846 |
2 index /File get exch
|
|
|
847 |
% Stack: readdata? dict parms file/string filternames
|
|
|
848 |
pdf_decrypt_stream % add decryption if needed
|
|
|
849 |
dup length 0 eq {
|
|
|
850 |
% All the PDF filters have EOD markers, but in this case
|
|
|
851 |
% there is no specified filter.
|
|
|
852 |
pop exch pop
|
|
|
853 |
% Stack: readdata? dict file/string
|
|
|
854 |
2 index 1 index type /filetype eq or {
|
|
|
855 |
% Use length for any files or reading data from any source.
|
|
|
856 |
1 index /Length knownoget not { 0 } if
|
|
|
857 |
} {
|
|
|
858 |
|
|
|
859 |
} ifelse
|
|
|
860 |
2 index /IDFlag known { pop } { () /SubFileDecode filter } ifelse
|
|
|
861 |
} {
|
|
|
862 |
applyfilters
|
|
|
863 |
} ifelse
|
|
|
864 |
} ifelse
|
|
|
865 |
% Stack: readdata? dict file
|
|
|
866 |
exch pop exch pop
|
|
|
867 |
} bind def
|
|
|
868 |
|
|
|
869 |
% ============================ Name/number trees ============================ %
|
|
|
870 |
|
|
|
871 |
/nameoget { % <nametree> <key> nameoget <obj|null>
|
|
|
872 |
exch /Names exch .treeget
|
|
|
873 |
} bind def
|
|
|
874 |
|
|
|
875 |
/numoget { % <numtree> <key> numoget <obj|null>
|
|
|
876 |
exch /Nums exch .treeget
|
|
|
877 |
} bind def
|
|
|
878 |
|
|
|
879 |
/.treeget { % <key> <leafkey> <tree> .treeget <obj|null>
|
|
|
880 |
dup /Kids knownoget {
|
|
|
881 |
exch pop .branchget
|
|
|
882 |
} {
|
|
|
883 |
exch get .leafget
|
|
|
884 |
} ifelse
|
|
|
885 |
} bind def
|
|
|
886 |
|
|
|
887 |
/.branchget { % <key> <leafkey> <kids> .branchget <obj|null>
|
|
|
888 |
dup length 0 eq {
|
|
|
889 |
pop pop pop null
|
|
|
890 |
} {
|
|
|
891 |
dup length -1 bitshift 2 copy oget
|
|
|
892 |
% Stack: key leafkey kids mid kids[mid]
|
|
|
893 |
dup /Limits oget aload pop
|
|
|
894 |
% Stack: key leafkey kids mid kids[mid] min max
|
|
|
895 |
6 index lt {
|
|
|
896 |
pop pop
|
|
|
897 |
1 add 1 index length 1 index sub getinterval .branchget
|
|
|
898 |
} {
|
|
|
899 |
5 index gt {
|
|
|
900 |
pop
|
|
|
901 |
|
|
|
902 |
} {
|
|
|
903 |
exch pop exch pop .treeget
|
|
|
904 |
} ifelse
|
|
|
905 |
} ifelse
|
|
|
906 |
} ifelse
|
|
|
907 |
} bind def
|
|
|
908 |
|
|
|
909 |
/.leafget { % <key> <pairs> .leafget <obj|null>
|
|
|
910 |
dup length 2 eq {
|
|
|
911 |
dup 0 get 2 index eq { 1 oget } { pop null } ifelse
|
|
|
912 |
exch pop
|
|
|
913 |
} {
|
|
|
914 |
dup length -1 bitshift -2 and 2 copy oget
|
|
|
915 |
% Stack: key pairs mid pairs[mid]
|
|
|
916 |
3 index gt { 0 exch } { 1 index length 1 index sub } ifelse
|
|
|
917 |
getinterval .leafget
|
|
|
918 |
} ifelse
|
|
|
919 |
} bind def
|
|
|
920 |
|
|
|
921 |
end % pdfdict
|
|
|
922 |
.setglobal
|