1 % Copyright (C) 1994-2003 artofcode LLC. All rights reserved.
3 % This software is provided AS-IS with no warranty, either express or
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.
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.
16 % $Id: pdf_base.ps,v 1.48 2005/09/16 19:01:30 ray Exp $
18 % Basic parser for PDF reader.
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.
25 /.setlanguagelevel where { pop 2 .setlanguagelevel } if
26 .currentglobal true .setglobal
27 /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
30 % Define the name interpretation dictionary for reading values.
32 (<<) cvn { mark } bind % don't push an actual mark!
33 (>>) cvn { { .dicttomark } stopped {
34 ( **** File has an unbalanced >> \(close dictionary\).\n)
38 ([) cvn { mark } bind % ditto
40 % /true true % see .pdfexectoken below
41 % /false false % 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
48 % ------ Utilities ------ %
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
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
62 PDFfile 2 index readline pop
64 { 3 2 roll 5 -2 roll pop pop 2 index }
67 % Stack: initpos linepos line string startpos
68 PDFfile fileposition 5 index ge { exit } if
71 loop pop pop 3 -1 roll pop
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'>
78 dup .namestring (#) search {
79 name#escape cvn exch pop
85 /name#escape % <post> <(#)> <pre> name#escape <string>
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)
94 exch closefile concatstrings
95 exch 2 1 index length 2 sub getinterval
97 (#) search { name#escape } if concatstrings
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 -
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
110 token pop exch pop dup type
111 dup /integertype eq exch /realtype eq or {
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
118 % error was non-recoverable with modified scanning rules
125 { % clean up the operand stack if this was non-recoverable
126 pop pop count exch sub { pop } repeat % pop all the operands
129 /.pdfexectoken { % <count> <opdict> <exectoken> .pdfexectoken ?
131 pdfdict /PDFSTEPcount known not { pdfdict /PDFSTEPcount 1 .forceput } if
133 pdfdict /PDFtokencount 2 copy .knownget { 1 add } { 1 } ifelse .forceput
135 pdfdict /PDFSTEPcount PDFSTEPcount 1 sub .forceput
138 ( step # ) print PDFtokencount =only
139 ( ? ) print flush 1 false .outputpage
140 (%stdin) (r) file 255 string readline {
142 exch pop pdfdict /PDFSTEPcount 3 -1 roll .forceput
144 pdfdict /PDFSTEPcount 1 .forceput
147 pop /PDFSTEP false def % EOF on stdin
149 } ifelse % PDFSTEPcount > 1
151 dup ==only () = flush
155 exch pop exch pop exch pop exec
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
172 /.pdfrun { % <file> <opdict> .pdfrun -
173 % Construct a procedure with the stack depth, file and opdict
175 1 index cvlit count 2 sub 3 1 roll mark mark 5 2 roll
176 { % Stack: ..operands.. count opdict file
178 dup type /nametype eq {
183 exch pop exch pop PDFDEBUG {
185 dup ==only ( ) print flush
190 exch pop exch pop PDFDEBUG {
192 dup ==only ( ) print flush
197 (%%EOF) cvn cvx .pdfexectoken
200 aload pop .packtomark cvx
201 /loop cvx 2 packedarray cvx
202 { stopped /PDFsource } aload pop
204 { store { stop } if } aload pop .packtomark cvx
205 /PDFsource 3 -1 roll store exec
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
215 /DefaultQstate exch store
216 /LocalResources exch store
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
228 % ================================ Objects ================================ %
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).
233 /lnshift lshift neg def
234 /lsubmask 1 lshift bitshift 1 sub def
235 /lsublen lsubmask 1 add def
236 /larray { % - larray <larray>
239 /lstring { % - lstring <lstring>
242 /ltype { % <lseq> type <type>
245 /lget { % <lseq> <index> lget <value>
246 dup //lsubmask and 3 1 roll //lnshift bitshift get exch get
248 /lput { % <lseq> <index> <value> lput -
250 dup //lsubmask and 4 1 roll //lnshift bitshift get
253 /llength { % <lseq> llength <length>
254 dup length 1 sub dup //lshift bitshift
255 3 1 roll get length add
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
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
269 counttomark 2 add -1 roll % newtoplen
270 counttomark sub { dup 0 0 getinterval lsublen growto } repeat
271 dup 0 0 getinterval ] exch
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
281 /lforall { % <lseq> <proc> lforall -
282 /forall cvx 2 packedarray cvx forall
285 % We keep track of PDF objects using the following PostScript variables:
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.
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.
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
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).
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.
313 % Initialize the PDF object tables.
314 /initPDFobjects { % - initPDFobjects -
315 /ObjectStream larray def
317 /Generations lstring def
318 .currentglobal true .setglobal
319 /GlobalObjects 20 dict def
321 /IsGlobal lstring def
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
329 dup Objects llength gt {
330 dup Objects exch lgrowto /Objects exch def
332 dup Generations llength gt {
333 dup Generations exch lgrowto /Generations exch def
335 dup IsGlobal llength gt {
336 dup IsGlobal exch lgrowto /IsGlobal exch def
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
361 } { % Else object is executable but not integer
362 exch pop true % Therefore must be executable dict. (stream)
364 } { % Else object is not executable.
365 exch pop true % Therefore it must have been resolved.
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.
376 /oforce_array { % <array> oforce_array <array>
377 [ exch { oforce } forall ]
379 /oforce_elems { % <array> oforce_elems <first> ... <last>
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.
388 oforce dup null eq { pop false } { true } ifelse
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
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: )
412 ( **** Warning: wrong generation: )
414 2 index =string cvs concatstrings ( ) concatstrings % put obj #
415 1 index =string cvs concatstrings ( R\n) concatstrings % put gen #
416 pdfformaterror % Output warning message
421 /R { % <object#> <generation#> R <object>
422 /resolveR cvx 3 packedarray cvx
425 % If we encounter an object definition while reading sequentially,
426 % we just store it away and keep going.
428 valueopdict { } forall
430 .dicttomark readonly def
432 /obj { % <object#> <generation#> obj <object>
433 PDFfile objopdict .pdfrun
436 /endobj { % <object#> <generation#> <object> endobj <object>
438 % Read the xref entry if we haven't yet done so.
439 % This is only needed for generation # checking.
444 % The only global objects we bother to save are
445 % (resource) dictionaries.
446 1 index dup gcheck exch type /dicttype eq and {
447 PDFDEBUG { (%Local=>global: ) print dup == } if
448 GlobalObjects 1 index 3 index put
449 IsGlobal 1 index 1 put
451 Objects exch 2 index lput
457 % When resolving an object reference in an object stream, we stop at
458 % the end of file. Note: Objects in an object stream do not have either
459 % a starting 'obj' or and ending 'endobj'.
460 /resolveobjstreamopdict mark
461 valueopdict { } forall
462 (%%EOF) cvn { exit } bind
463 .dicttomark readonly def
465 % Note: This version of this function is not currently being used.
466 % Resolve all objects in an object stream
467 /resolveobjectstream { % <object stream #> resolveobjectstream -
468 PDFDEBUG { (%Resolving object stream: ) print } if
469 0 resolveR % Get the objectstream dict, all objstrms use 0 as the gen #
470 dup /First get % Save location of first object onto the stack
471 1 index /N get % Save number of objects onto the stack
472 2 index false resolvestream % Convert stream dict into a stream
473 /ReusableStreamDecode filter % We need to be able to position stream
474 % Objectstreams begin with list of object numbers and locations
475 % Create two arrays to hold object numbers and stream location
476 1 index array % Array for holding object number
477 2 index array % Array for holding stream object location
478 % Get the object numbers and locations.
479 0 1 5 index 1 sub { % Loop and collect obj # and locations
480 % Stack: objstreamdict First N objectstream [obj#] [loc] index
481 2 index 1 index % Setup to put obj# into object number array
482 5 index token pop put % Get stream, then get obj# and put into array
483 1 index 1 index % Setup to put object loc into location array
484 5 index token pop put % Get stream, get obj loc and put into array
485 pop % Remove loop index
487 % Create a bytestring big enough for reading any object data
488 % Scan for the size of the largest object
489 0 0 % Init max object size and previous location
490 2 index { % Loop through all object locations
491 % Stack: ... maxsize prevloc currentloc
492 dup 4 1 roll % Save copy of object location into stack
493 exch sub % Object size = currentloc - prevloc
494 .max % Determine maximum object size
495 exch % Put max size under previous location
497 pop % Remove previous location
498 .bigstring % Create bytestring based upon max obj size
499 % Move to the start of the object data
500 3 index 6 index % Get objectstream and start of first object
501 setfileposition % Move to the start of the data
502 % Read the data for all objects except the last. We do
503 % not know the size of the last object so we need to treat
504 % it as a special case.
506 dup 4 index exch get % Get our current object number
507 % Stack: objstreamdict First N objectstream [obj#] [loc]
508 % bytestring loopindex object#
509 dup resolved? { % If we already have this object
510 (yyy) = pstack (yyy) = flush xxx
511 pop pop % Remove object and object number
512 1 add 2 index exch get % Get location of next object
513 6 index add 6 index exch % Form location of next object and get stream
514 setfileposition % Move to the start of the next object data
515 } { % Else this is a new object ...
516 % We are going to create a string for reading the object
517 2 index 0 % use our working string
518 % Determine the size of the object
519 5 index 4 index 1 add get % Get location of the next object
520 6 index 5 index get % Get location of this object
521 sub % Size of object = next loc - this loc
522 getinterval % Create string for reading object
523 6 index exch readstring pop % Read object
524 /ReusableStreamDecode filter % Convert string into a stream
525 resolveobjstreamopdict .pdfrun % Get PDF object
526 Objects exch 2 index exch lput % Put object into Objects array
527 pop pop % Remove object # and loop index
530 pop pop % Remove our working string and loc array
531 % Now read the last object in the object stream. Since it
532 % is the last object, we can use the original stream and
533 % terminate when we hit the end of the stream
534 % Stack: objstreamdict First N objectstream [obj#]
535 2 index 1 sub get % Get our current object number
536 dup resolved? not { % If we do not already have this object
537 exch % Get our object stream
538 resolveobjstreamopdict .pdfrun % Get PDF object
539 Objects exch 2 index exch lput % Put object into Objects array
541 pop pop pop pop % Clear stack
544 % Resolve all objects in an object stream
545 /resolveobjectstream { % <object stream #> resolveobjectstream -
546 PDFDEBUG { (%Resolving object stream: ) print } if
547 0 resolveR % Get the objectstream dict, all objstrms use 0 as the gen #
548 dup /Type get /ObjStm ne { % Verify type is object stream
549 ( **** Incorrect Type in object stream dictionary.\n) pdfformaterror
550 /resolveobjectstream cvx /typecheck signalerror
552 dup /N get % Save number of objects onto the stack
553 1 index false resolvestream % Convert stream dict into a stream
554 /ReusableStreamDecode filter % We need to be able to position stream
555 % Objectstreams begin with list of object numbers and locations
556 1 index array % Create array for holding object number
557 % Get the object numbers
558 0 1 4 index 1 sub { % Loop and collect obj numbers
559 % Stack: objstreamdict N PDFDEBUG objectstream [obj#] loopindex
560 1 index 1 index % Setup to put obj# into object number array
561 4 index token pop put % Get stream, then get obj# and put into array
562 2 index token pop pop pop % Get stream, get obj loc and clear stack
564 % Move to the start of the object data
565 1 index 4 index /First get % Get objectstream and start of first object
566 setfileposition % Move to the start of the data
567 % We disable PDFDEBUG while reading the data stream. We will
568 % print the data later
569 PDFDEBUG /PDFDEBUG false def % Save PDFDEBUG and disable it while reading
570 % Read the data for all objects. We check to see if we get
571 % the number of objects that we expect.
572 % Stack: objstreamdict N objectstream [obj#] PDFDEBUG
573 mark 4 -1 roll % Get objectstream
574 count 5 index add % Determine stack depth with objects
575 /PDFObjectStkCount exch def
576 resolveobjstreamopdict .pdfrun % Get PDF objects
577 PDFObjectStkCount count ne { % Check stack depth
578 ( **** Incorrect object count in object stream.\n) pdfformaterror
579 /resolveobjectstream cvx /rangecheck signalerror
581 % We have the object data
582 counttomark array astore % Put objects into an array
583 exch pop % Remove mark
584 exch /PDFDEBUG exch def % Restore PDFDEBUG flag
585 % Save the objects into Objects
586 0 1 2 index length 1 sub { % Loop through all objects
587 % Stack: objstreamdict N [obj#] [objects] loopindex
588 dup 3 index exch get % Get our current object number
589 dup resolved? { % If we already have this object
590 pop pop % Remove object and object number
591 } { % Else if we do not have this object
592 PDFDEBUG { (%Resolving compressed object: [) print dup =only ( 0]) = } if
593 Objects exch 3 index % Put the object into Objects
595 PDFDEBUG { dup === flush } if
598 pop % Remove loop index
600 pop pop pop pop % Remove objstream, N, (obj#], and [objects]
603 % When resolving an object reference, we stop at the endobj or endstream.
605 valueopdict { } forall
606 /endstream { endobj exit } bind
607 /endobj { endobj exit } bind
608 % OmniForm generates PDF file with endobj missing in some
609 % objects. AR ignores this. So we have to do it too.
610 /obj { pop pop endobj exit } bind
611 .dicttomark readonly def
613 /resolveR { % <object#> <generation#> resolveR <object>
616 (%Resolving: ) print 2 copy 2 array astore ==
619 1 index resolved? { % If object has already been resolved ...
620 exch pop exch pop % then clear stack and return object
621 } { % Else if not resolved ...
622 PDFfile fileposition 3 1 roll % Save current file position
623 1 index Objects exch lget % Get location of object from xref
624 3 1 roll checkgeneration { % Verify the generation number
625 % Stack: savepos objpos obj#
626 ObjectStream 1 index lget dup 0 eq { % Check if obj in not an objstream
627 pop exch PDFoffset add PDFfile exch setfileposition
628 PDFfile token pop 2 copy ne
629 { ( **** Unrecoverable error in xref!\n) pdfformaterror
630 /resolveR cvx /rangecheck signalerror
632 if pop PDFfile token pop
633 PDFfile token pop /obj ne
634 { ( **** Unrecoverable error in xref!\n) pdfformaterror
635 /resolveR cvx /rangecheck signalerror
638 pdf_run_resolve % PDFfile resolveopdict .pdfrun
639 } { % Else the object is in an ObjectStream
640 % Process an objectstream object. We are going to resolve all
641 % of the objects in sthe stream and place them into the Objects
643 % Stack: savepos objpos obj# objectstream#
645 resolved? { % If object has already been resolved ...
646 exch pop % Remove object pos from stack.
648 pop pop null % Pop objpos and obj#, put null for object
651 } { % Else the generation number is wrong
652 % Don't cache if the generation # is wrong.
653 pop pop null % Pop objpos and obj#, put null for object
654 } ifelse % ifelse generation number is correct
655 exch PDFfile exch setfileposition % Return to original file position
659 % ================================ Streams ================================ %
661 % We represent a stream by an executable dictionary that contains,
662 % in addition to the contents of the original stream dictionary:
663 % /File - the file or string where the stream contents are stored,
664 % if the stream is not an external one.
665 % /FilePosition - iff File is a file, the position in the file
666 % where the contents start.
667 % /StreamKey - the key used to decrypt this stream, if any.
668 % We do the real work of constructing the data stream only when the
669 % contents are needed.
671 % Construct a stream. The length is not reliable in the face of
672 % different end-of-line conventions, but it's all we've got.
674 % PDF files are inconsistent about what may fall between the 'stream' keyword
675 % and the actual stream data, and it appears that no one algorithm can
676 % detect this reliably. We used to try to guess whether the file included
677 % extraneous \r and/or \n characters, but we no longer attempt to do so,
678 % especially since the PDF 1.2 specification states flatly that the only
679 % legal terminators following the 'stream' keyword are \n or \r\n, both of
680 % which are properly skipped and discarded by the token operator.
681 % Unfortunately, this doesn't account for other whitespace characters that
682 % may have preceded the EOL, such as spaces or tabs. Thus we back up one
683 % character and scan until we find the \n terminator.
684 /stream { % <dict> stream <modified_dict>
685 dup /Length oget 0 eq {
686 dup /Filter undef % don't confuse any filters that require data
688 dup /F known dup PDFsource PDFfile eq or {
690 dup /File PDFfile put
691 % make sure that we are just past the EOL \n character
692 PDFfile dup fileposition 1 sub setfileposition % back up one
693 { PDFfile read pop dup 13 eq {
694 % If there had been a \n, token would have advanced over it
695 % thus, if the terminator was \r, we have a format error!
696 ( **** Warning: stream operator not terminated by valid EOL.\n) pdfformaterror
697 pop exit % fileposition is OK (just past the \r).
700 } loop % scan past \n
701 dup /FilePosition PDFfile fileposition put
704 (%FilePosition: ) print dup /FilePosition get ==
708 % Some (bad) PDf files have invalid stream lengths. This causes problems
709 % if we reposition beyond the end of the file. So we compare the given
710 % length to number of bytes left in the file.
712 dup PDFfile bytesavailable lt { % compare to to bytes left in file
713 PDFfile fileposition % reposition to the end of stream
714 add PDFfile exch setfileposition
716 pop % bad stream length - do not reposition.
717 % This will force a length warning below
721 % We're already reading from a stream, which we can't reposition.
722 % Capture the sub-stream contents in a string.
723 dup /Length oget string PDFsource exch readstring
725 ( **** Warning: Unexpected EOF in stream!\n) pdfformaterror
726 /stream cvx /rangecheck signalerror
728 1 index exch /File exch put
730 PDFsource {token} stopped {
736 % Another case that Acrobat Reader handles -- 'endobj' without 'endstream'.
737 ( **** Warning: stream missing 'endstream'.\n) pdfformaterror
738 pop /endstream % fake a valid endstream
741 ( **** Warning: stream Length incorrect.\n) pdfformaterror
742 dup /Length undef % prevent the use of the incorrect length.
743 cvx endobj exit % exit from .pdfrun now.
751 % Contrary to the published PDF (1.3) specification, Acrobat Reader
752 % accepts abbreviated filter names everywhere, not just for in-line images,
753 % and some applications (notably htmldoc) rely on this.
754 /unabbrevfilterdict mark
755 /AHx /ASCIIHexDecode /A85 /ASCII85Decode /CCF /CCITTFaxDecode
756 /DCT /DCTDecode /Fl /FlateDecode /LZW /LZWDecode /RL /RunLengthDecode
757 .dicttomark readonly def
759 % Extract and apply filters.
760 /filterparms { % <dict> <DPkey> <Fkey> filterparms
761 % <dict> <parms> <filternames>
762 2 index exch knownoget {
763 exch 2 index exch knownoget {
764 % Both filters and parameters.
765 exch dup type /nametype eq {
767 dup type /arraytype ne { 1 array astore } if exch
770 % Filters, but no parameters.
772 dup type /nametype eq { 1 array astore } if
775 % No filters: ignore parameters, if any.
779 /filtername { % <filtername> filtername <filtername'>
780 //unabbrevfilterdict 1 index .knownget { exch pop } if
781 dup /Filter resourcestatus { pop pop } {
782 Repaired exch % this error is not the creator's fault
783 ( **** ERROR: Unable to process ) pdfformaterror
784 64 string cvs pdfformaterror
785 ( data. Page will be missing data.\n) pdfformaterror
786 /Repaired exch store % restore the previous "Repaired" state
787 % provide a filter that returns EOF (no data)
791 /applyfilters { % <parms> <source> <filternames> applyfilters <stream>
793 { filtername filter }
795 { % Stack: parms source filtername
796 2 index 0 oget dup null eq { pop } {
797 exch filtername dup /JBIG2Decode eq { exch jbig2cachectx exch } if
799 exch dup length 1 sub 1 exch getinterval exch
801 } ifelse forall exch pop
804 % JBIG2 streams have an optional 'globals' stream obj for
805 % sharing redundant data between page images. Here we resolve
806 % that stream reference (if any) and run it through the decoder,
807 % creating a special -jbig2globalctx- postscript object our
808 % JBIG2Decode filter implementation looks for in the parm dict.
809 /jbig2cachectx { % <parmdict> jbig2cachectx <parmdict>
810 dup /JBIG2Globals knownoget {
813 PDFfile fileposition 3 1 roll % resolvestream is not reentrant
814 exch true resolvestream exch .bytestring
815 .readbytestring pop .jbig2makeglobalctx
816 PDFfile 3 -1 roll setfileposition
818 /.jbig2globalctx exch put
822 % Resolve a stream dictionary to a PostScript stream.
823 % Streams with no filters require special handling:
824 % - Whether we are going to interpret the stream, or If we are just
825 % going to read data from them, we impose a SubFileDecode filter
826 % that reads just the requisite amount of data.
827 % Note that, in general, resolving a stream repositions PDFfile.
828 % Clients must save and restore the position of PDFfile themselves.
829 /resolvestream { % <streamdict> <readdata?> resolvestream <stream>
830 1 index /F knownoget {
831 % This stream is stored on an external file.
833 /FDecodeParms /FFilter filterparms
834 % Stack: readdata? file dict parms filternames
839 exch dup /FilePosition .knownget {
840 1 index /File get exch setfileposition
842 % Stack: readdata? dict
843 /DecodeParms /Filter filterparms
844 % Stack: readdata? dict parms filternames
845 2 index /File get exch
846 % Stack: readdata? dict parms file/string filternames
847 pdf_decrypt_stream % add decryption if needed
849 % All the PDF filters have EOD markers, but in this case
850 % there is no specified filter.
852 % Stack: readdata? dict file/string
853 2 index 1 index type /filetype eq or {
854 % Use length for any files or reading data from any source.
855 1 index /Length knownoget not { 0 } if
857 0 % Otherwise length of 0 for whole string
859 2 index /IDFlag known { pop } { () /SubFileDecode filter } ifelse
864 % Stack: readdata? dict file
868 % ============================ Name/number trees ============================ %
870 /nameoget { % <nametree> <key> nameoget <obj|null>
871 exch /Names exch .treeget
874 /numoget { % <numtree> <key> numoget <obj|null>
875 exch /Nums exch .treeget
878 /.treeget { % <key> <leafkey> <tree> .treeget <obj|null>
879 dup /Kids knownoget {
886 /.branchget { % <key> <leafkey> <kids> .branchget <obj|null>
890 dup length -1 bitshift 2 copy oget
891 % Stack: key leafkey kids mid kids[mid]
892 dup /Limits oget aload pop
893 % Stack: key leafkey kids mid kids[mid] min max
896 1 add 1 index length 1 index sub getinterval .branchget
900 0 exch getinterval .branchget
902 exch pop exch pop .treeget
908 /.leafget { % <key> <pairs> .leafget <obj|null>
910 dup 0 get 2 index eq { 1 oget } { pop null } ifelse
913 dup length -1 bitshift -2 and 2 copy oget
914 % Stack: key pairs mid pairs[mid]
915 3 index gt { 0 exch } { 1 index length 1 index sub } ifelse