]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/ghostscript/pdf_main.ps
merge
[plan9front.git] / sys / lib / ghostscript / pdf_main.ps
1 %    Copyright (C) 1994, 2000 Aladdin Enterprises.  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_main.ps,v 1.100 2005/09/23 18:21:23 ray Exp $
17 % pdf_main.ps
18 % PDF file- and page-level operations.
19
20 /.setlanguagelevel where { pop 2 .setlanguagelevel } if
21 .currentglobal true .setglobal
22 /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
23 pdfdict begin
24
25 % Patch in an obsolete variable used by some third-party software.
26 /#? false def
27
28 /NoVerifyXref true def
29
30 % Test whether the current output device handles pdfmark.
31 /.writepdfmarkdict 1 dict dup /pdfmark null put readonly def
32 /.writepdfmarks {       % - .writepdfmarks <bool>
33   currentdevice //.writepdfmarkdict .getdeviceparams
34   mark eq { false } { pop pop true } ifelse
35   systemdict /DOPDFMARKS known or 
36 } bind def
37
38 % For simplicity, we use a single interpretation dictionary for all
39 % PDF graphics execution, even though this is too liberal.
40 /pdfopdict mark
41   objopdict { } forall
42   drawopdict { } forall
43   /endstream { exit } bind
44   (%%EOF) cvn { exit } bind             % for filters
45         % PDF 1.1 operators
46   /BX { /BXlevel BXlevel 1 add store } bind
47   /EX { /BXlevel BXlevel 1 sub store } bind
48   /PS { cvx exec } bind
49         % PDF 1.2 operators
50   /BMC { pop } bind
51   /BDC { pop pop } bind
52   /EMC { }
53   /MP { pop } bind
54   /DP { pop pop } bind
55 .dicttomark readonly def
56
57 % ======================== Main program ======================== %
58
59 end                     % pdfdict
60 userdict begin
61
62 /defaultfontname /Times-Roman def
63
64 % Make sure the registered encodings are loaded, so we don't run the risk
65 % that some of the indices for their names will overflow the packed
66 % representation.  (Yes, this is a hack.)
67 SymbolEncoding pop
68 DingbatsEncoding pop
69
70 % Redefine 'run' so it recognizes PDF files.
71 systemdict begin
72 /.runps /run load def
73 /run {
74   dup type /filetype ne { (r) file } if
75   % skip leading whitespace characters (actually anything less than or equal to <sp>)
76   { dup ( ) .peekstring not { false exit } if
77     dup 0 get 32 le { pop dup read pop pop } { true exit } ifelse
78   } loop
79   {
80     (%) eq {
81       dup (     ) .peekstring {
82         (%PDF-) eq {
83             dup (%stdin) (r) file eq {
84               % Copy PDF from stdin to temporary file then run it.
85               null (w+) //systemdict /.tempfile get exec exch 3 1 roll
86               % stack: tempname stdin tempfile
87               64000 string
88               {
89                 % stack: tempname stdin tempfile string
90                 2 index 1 index readstring
91                 exch 3 index exch writestring
92                 not { exit } if
93               }
94               loop
95               pop exch closefile
96               % stack: tempname tempfile
97               dup 0 setfileposition
98               dup runpdf
99               closefile deletefile
100             } {
101               runpdf
102             } ifelse
103           } {
104             cvx .runps % doesn't start with %PDF-
105           } ifelse
106         } {
107           pop cvx .runps % didn't read 5 characters
108         } ifelse
109     } {
110       cvx .runps % didn't start with %
111     } ifelse
112   } {
113     pop closefile % file was empty
114   } ifelse
115 } bind odef
116 currentdict /runpdfstring .undef
117
118
119 /runpdfbegin {          % <file> runpdf -
120    userdict begin
121         % It turns out that the PDF interpreter uses memory more
122         % effectively if it is run under at least one level of save.
123         % This is counter-intuitive, and we don't understand why it happens,
124         % but the improvement is significant.
125    /PDFTopSave save def
126    0 setobjectformat
127    /Page# null def
128    /Page null def
129    /DSCPageCount 0 def
130    /PDFSave null def
131    GS_PDF_ProcSet begin
132    pdfdict begin
133    pdfopen begin
134    Trailer /Root oget /Pages oget /CropBox knownoget
135     { oforce_array normrect mark /CropBox 3 -1 roll /PAGES pdfmark
136     }
137    if
138    /FirstPage where 
139     { pop FirstPage dup pdfpagecount gt
140       { (\nRequested FirstPage is greater than the number of pages in the file: ) print
141         pdfpagecount = flush
142       } if
143     } {
144       1
145     } ifelse
146    /LastPage where { pop LastPage pdfpagecount .min } { pdfpagecount } ifelse
147    1 index 1 index gt
148     { (   No pages will be processed \(FirstPage > LastPage\).) = flush }
149     { QUIET not
150       { (Processing pages ) print 1 index =only ( through ) print dup =only
151         (.) = flush
152       }
153      if
154     }
155    ifelse
156 } bind def
157
158 /dopdfpages {   % firstpage# lastpage# dopdfpages -
159   << /PDFScanRules true >> setuserparams        % set scanning rules for PDF vs. PS
160   1 exch
161     { dup /Page# exch store
162       QUIET not { (Page ) print dup == flush } if
163       pdfgetpage pdfshowpage
164     } for
165   << /PDFScanRules null >> setuserparams        % restore scanning rules for PS
166 } bind def
167
168 /runpdfend {
169    Repaired { printrepaired } if
170    currentdict pdfclose
171    end                  % temporary dict
172    end                  % pdfdict
173    end                  % GS_PDF_ProcSet
174    PDFTopSave restore
175    end                  % userdict
176 } bind def
177
178 /runpdf {               % <file> runpdf -
179   runpdfbegin
180   dopdfpages
181   runpdfend
182 } bind def
183
184 end                     % systemdict
185 % Redefine the procedure that the C code uses for running piped input.
186 % It is OK to use { (%stdin) run } here, because a startjob cannot occur.
187 /.runstdin {
188   { (%stdin) run } execute0
189 } bind def
190
191 end                     % userdict
192 pdfdict begin
193
194 % ======================== File parsing ======================== %
195
196 % Read the cross-reference and trailer sections.
197
198 /traileropdict mark
199   (<<) cvn { mark } bind
200   (>>) cvn { { .dicttomark } stopped {
201               (   **** File has unbalanced >> in trailer.\n) pdfformaterror
202              } if } bind
203   ([) cvn { mark } bind         % ditto
204   (]) cvn dup load
205 %  /true true           % see .pdfexectoken in pdf_base.ps
206 %  /false false         % ibid.
207 %  /null null           % ibid.
208   /R { /resolveR cvx 3 packedarray cvx } bind   % see Objects below
209   /startxref /exit load
210 .dicttomark readonly def
211
212 % Because of EOL conversion, lines with fixed contents might be followed
213 % by one or more blanks.
214 /lineeq                 % <filestr> <conststr> lineeq <bool>
215  { anchorsearch
216     { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
217     { pop false }
218    ifelse
219  } bind def
220 /linene { lineeq not } bind def
221
222  %  Read original version (pre PDF 1.5) of the xref table.
223  %  Note:  The position is the location of 'xref'.  The current PDFfile
224  %  position is just after the 'XREF'.
225 /readorigxref           % <pos> readorigxref <trailerdict>
226  {
227    pop                          % We do not need the position.
228    0                            % Initialize xref table error counter
229    { PDFfile token pop          % first object # or trailer
230      dup /trailer eq { pop exit } if
231      PDFfile pdfstring readline pop
232      token pop                  % entry count
233      % remaining must be whitespace only (otherwise this xref Size was invalid.
234      exch dup length 0 ne {
235        false 1 index { 32 gt { pop true exit } if } forall {
236          (   **** Warning: xref subsection header has extra characters.\n)
237          pdfformaterror
238          /setxrefentry cvx /syntaxerror signalerror
239        } if
240      } if
241      pop                        % remove last
242                 % This section might be adding new objects:
243                 % ensure that Objects and Generations are big enough.
244                 % stack: <err count> <first obj> <entry count>
245      2 copy add growPDFobjects
246      {                          % stack: <err count> <obj num>
247                 % Read xref line
248        PDFfile 20 string readstring pop  % always read 20 chars.
249        token pop                % object position
250        exch token pop           % generation #
251        exch token pop           % n or f
252        exch                     % stack: <err count> <obj#> <loc> <gen#> <tag> <remainder of line>
253        dup length 0 ne {
254          % check to make sure trailing garbage is just white space
255          dup { 32 gt { 5 -1 roll 1 add 5 1 roll } if } forall   % bump error count on garbage
256        } if
257        pop                      % Stack: <err count> <obj#> <loc> <gen#> <tag>
258        dup /n eq {              % xref line tag is /n
259          pop                    % pop dup of line tag
260          Objects 3 index lget null eq { % later update might have set it
261            0 3 1 roll           % Set ObjectStream object number = 0
262            setxrefentry         % Save xref entry
263            3 -1 roll pop        % Remove ObjectStream object onumber
264          } if
265        }
266        {                        % xref line tag was not /n
267          /f ne                  % verify that the tag was /f
268          { /setxrefentry cvx /syntaxerror signalerror
269          } if
270        } ifelse
271        pop pop                  % pop <obj location> and <gen num>
272        % stack: <err count> <obj num>
273        1 add                    % increment object number
274      } repeat
275      pop                        % pop <obj #>
276    } loop
277    0 ne {
278      (   **** Warning:  length of some xref entries is not equal to 20 bytes.\n)
279      pdfformaterror
280    } if
281    PDFfile traileropdict .pdfrun
282  } bind def
283
284  % This dicitonary is used to read the xref dictionary.  It should work for
285  % reading any dictionary.  dictlevelcount must contain 0.
286 /xrefopdict mark
287   (<<) cvn { /dictlevelcount dictlevelcount 1 add def mark } bind
288   (>>) cvn { .dicttomark /dictlevelcount dictlevelcount 1 sub def
289              dictlevelcount 0 eq { exit} if } bind
290   ([) cvn { mark } bind         % ditto
291   (]) cvn dup load
292 %  /true true           % see .pdfexectoken in pdf_base.ps
293 %  /false false         % ibid.
294 %  /null null           % ibid.
295   /R { /resolveR cvx 3 packedarray cvx } bind   % see Objects below
296 .dicttomark readonly def
297
298 % Get a variable length positive integer value from a stream.  A value
299 % of zero is returned if the count is zero.
300 /getintn {      % <stream> <count> getintn int
301   0 exch { 256 mul 1 index read pop add } repeat
302   exch pop                      % Discard stream
303 } bind def
304
305 % This array contains handlers for processing the different types of
306 % entries in the XRef stream.
307 % Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
308 %        <field 2> <field 3>
309 % The handlers leave the stack unchanged.
310 /xref15entryhandlers [
311   {     % XRef entry type 0 - free or f type xref entry
312 %    (free ) print
313 %    (obj num: ) print 2 index pdfstring cvs print ( ) print
314 %    (loc: ) print 1 index pdfstring cvs print ( ) print
315 %    (gen: ) print dup === flush
316   } bind                % Do nothing for free xref entries
317         % XRef entry type 1 - normal or n type xref entry
318   {     % field 2 = obj loc, field 3 = gen num
319 %    (normal ) print
320 %    (obj num: ) print 2 index pdfstring cvs print ( ) print
321 %    (loc: ) print 1 index pdfstring cvs print ( ) print
322 %    (gen: ) print dup === flush
323     0 3 1 roll                  % set stream number = 0
324     setxrefentry
325     3 -1 roll pop               % remove stream number
326   } bind
327         % XRef entry type 2 - compressed object type xref entry
328   {     % field 2 = object stream num, field 3 = index into object stream
329 %    (Compressed objects: ) print
330 %    (obj num: ) print 2 index pdfstring cvs print ( ) print
331 %    (field 2: ) print 1 index pdfstring cvs print ( ) print
332 %    (field 3: ) print dup === flush
333     0 setxrefentry pop          % set generation number = 0
334   } bind
335 ] def
336
337  %  Read the PDF 1.5 version of the xref table.
338  %  Note:  The position is the location of the start of the dictionary object
339  %  In PDF 1.5, the XRef dictionary also serves as the trailer dictionary
340 /readpdf15xref          % <pos> readpdf15xref <trailerdict>
341  {
342    PDFfile exch setfileposition         % move to start of object
343         % Get object number, revision, and 'obj' and discard
344    PDFfile token pop pop
345    PDFfile token pop pop
346    PDFfile token pop pop
347         % Get the XRef dicitionary
348    /dictlevelcount 0 def PDFfile xrefopdict .pdfrun
349         % Verify that we have an XRef dictionary
350    dup /Type get /XRef ne {
351      /readpdf15xref cvx /syntaxerror signalerror
352    } if
353         % Ensure that we we have room in the objects array, etc.
354    dup /Size get growPDFobjects
355         % Create a stream for the XRef data
356    PDFfile token pop pop                % Skip over 'stream'
357    dup stream false resolvestream
358         % Stack: <XRefdict> <xref stream>
359         % The Index array defines the ranges of object numbers in the
360         % XRef stream.  Each value pair is consists of starting object
361         % number and the count of consecutive objects.
362         % Get the Index array, if present
363    1 index /Index .knownget not {       % If no Index array ...
364      [ 0 3 index /Size get ]            % Default = [ 0 Size ]
365    } if
366         % Loop through the Index array
367    0 2 2 index length 1 sub {
368         % Get start and end of object range
369      2 copy get                         % Start of the range
370      dup 3 index 3 index 1 add get      % Number of entries in range
371         % Loop through the range of object numbers
372      add 1 sub 1 exch {                 % Form end of range, set increment = 1
373         % Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
374         % Get xref parameters.  Note:  The number of bytes for each parameter
375         % is defined by the entries in the W array.
376        4 index /W get aload pop         % Get W array values
377         % The first field indicates type of entry.  Get first field value.
378         % If the num. of bytes for field 1 is 0 then default field value is 1
379        3 -1 roll dup 0 eq { pop 1 } { 6 index exch getintn } ifelse
380         % Get the handler for the xref entry type.  We will execute the
381         % handler after we get the other two field values.
382        xref15entryhandlers exch get
383        3 -1 roll 6 index exch getintn   % Get second field
384        3 -1 roll 6 index exch getintn   % Get third field
385        3 -1 roll exec                   % Execute Xref entry handler
386        pop pop pop                      % Remove field values and obj num
387      } for                              % Loop through Xref entries
388      pop                                % Remove Index array pair loc
389    } for                                % Loop through Index array entries
390    pop pop                              % Remove Index array and xref stream
391  } bind def
392
393 % Read the cross-reference table.
394 % <pos> is the position either from the startxref statement or the /Prev
395 % entry in the prior trailer dictionary.
396 /readxref               % <pos> readxref <trailerdict>
397  {
398    PDFoffset add PDFfile exch setfileposition
399                 % In some PDF files, this position actually points to
400                 % white space before the xref line.  Skip over this here.
401    {
402      PDFfile fileposition PDFfile read pop 32 gt { exit } if pop
403    } loop
404    dup          % Make copy of the file position (before last char was read).
405    PDFfile exch setfileposition
406                 % The PDF specification says that the 'xref' must be on a line
407                 % by itself. The code here formerly used readline and linene to
408                 % check this. However, Acrobat Reader only requires the line to
409                 % begin with 'xref', and there are enough applications producing
410                 % non-compliant PDF files that we have to do this too.
411    PDFfile pdfstring 0 4 getinterval readstring pop
412    (xref) eq
413    { readorigxref }     % 'xref' -> original xref table
414    { readpdf15xref }    % otherwise assume PDF 1.5 xref stream
415    ifelse
416  } bind def
417
418 % Open a PDF file and read the header, trailer, and cross-reference.
419 /pdfopen {              % <file> pdfopen <dict>
420         % Color space substitution in PDF is handled somewhat differently
421         % than in PostScript. A given device color space will be substituted
422         % if the corresponding "Default..." entry exists in the Page's
423         % Resource dictionary (which might be inhereted); there is no
424         % UseCIEColor to enable/disable color mapping.
425         %
426         % This behavior is achieved by always setting UseCIEColor to true
427         % in the page device dictionary. If the value of this parameter was
428         % originally false (i.e.: the output device does not perform color
429         % space substitution by default), the instances DefaultGray,
430         % DefaultRGB, and DefaultCMYK of the (local) ColorSpace category
431         % are redefined to be DeviceGray, DeviceRGB, and DeviceCMYK,
432         % respectively. This is not done if UseCIEColor is true by default,
433         % as in that case color substitution is presumably desired even
434         % if the file does not request it.
435    currentpagedevice /UseCIEColor .knownget dup { pop } if not
436     { .currentglobal false .setglobal
437       /DefaultGray { /DeviceGray } cvlit /ColorSpace defineresource pop
438       /DefaultRGB { /DeviceRGB } cvlit /ColorSpace defineresource pop
439       /DefaultCMYK { /DeviceCMYK } cvlit /ColorSpace defineresource pop
440       .setglobal
441     }
442    if
443   pdfopenfile begin
444   pdfopencache
445   .writepdfmarks {
446         % Copy bookmarks (outline) to the output.
447     Trailer /Root oget /Outlines knownoget {
448       /First knownoget {
449         { dup writeoutline /Next knownoget not { exit } if } loop
450       } if
451     } if
452   } if          % end .writepdfmarks
453   currentdict end
454 } bind def
455
456 % Verify that each entry in the xref table is pointing at an object with
457 % the correct object number and generation number.
458 /verify_xref                            % - verify_xref -
459 { 1 1 Objects llength 1 sub             % stack: 1 1 <number of objects - 1>
460   {     % Check if the object is free (i.e. not used).  The values in
461         % Generations is the generation number plus 1.  If the value in
462         % Generations is zero then the object is free.
463     Generations 1 index lget            % Get the genration number
464     0 ne {                              % Skip if object number is free
465       ObjectStream 1 index lget         % Check if object is in objectstream
466       0 eq {    % We only check objects not in an objectstream
467         {       % Use stop context since we may get an error if object is invalid
468           dup Objects exch lget         % Get the object location
469           PDFoffset add PDFfile exch setfileposition
470           true                          % Stack:  <obj num> <true>
471           PDFfile token pop             % Read object number from file
472           2 index eq {                  % Verify object number
473             PDFfile token pop           % Read generation number from file
474             Generations 3 index         % Get specified generaton number
475             lget 1 sub                  % Gen numbs are stored with 1 added.
476             eq {                        % Verify generation number
477               PDFfile token pop /obj eq { % Verify 'obj' text
478                 pop false               % We have valid object, do not rebuild
479               } if
480             } if
481           } if
482         } .internalstopped
483         { true } if                     % If we stop then we need to rebuild
484         { 
485           (   **** Warning:  File has an invalid xref entry:  )
486           pdfformaterror
487           pdfstring cvs pdfformaterror
488           (.  Rebuilding xref table.\n) pdfformaterror
489           search_objects
490           exit
491         } if                            % If the entry is invalid
492       } if                              % If not in an object stream
493     } if                                % If object entry is not free
494     pop                                 % Remove object number
495   } for
496 } bind odef
497
498 /pdfopencache {         % - pdfopencache -
499         % Create and initialize some caches.
500   /PageCount pdfpagecount def
501   /PageNumbers PageCount 65534 .min dict def
502   /PageIndex PageCount 65534 .min array def
503 } bind def
504
505 /pdfopenfile {          % <file> pdfopenfile <dict>
506    pdfdict readonly pop         % can't do it any earlier than this
507    15 dict begin
508    /LocalResources 0 dict def
509    /DefaultQstate //null def    % establish binding
510    /Printed where { pop } {
511                 % Guess whether the output device is a printer.
512      /Printed currentpagedevice /OutputFile known def
513    } ifelse
514    /PSLevel1 where { pop } { /PSLevel1 false def } ifelse
515    % NB: PDFfile is used outside of the PDF code to determine that a
516    % PDF job is being processed; to not change or hide this key.
517    cvlit /PDFfile exch def
518    /PDFsource PDFfile def
519    /Repaired false def
520    currentglobal true .setglobal globaldict begin
521    /TTFWarnList 0 dict def /UndefProcList 0 dict def
522    end .setglobal
523    PDFfile dup 0 setfileposition pdfstring readstring 
524    not {/pdfopen cvx /syntaxerror signalerror} if
525    (%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
526    length /PDFoffset exch def pop
527    % some badly formed PDF's (Visioneer) have something other than EOL
528    % after the version number. If we get an error, shorten the string
529    % and try again.
530    false exch           % error encountered
531    { { cvr } stopped
532      { exch pop true exch 0 1 index length 1 sub dup 0 eq
533        { pop 0 exit } if        % exit if string now empty
534        getinterval              % trim character from right end and retry
535      }
536      { exch {
537          (   **** Warning: PDF version number not followed by EOL.\n)
538          pdfformaterror
539        }
540        if exit
541      }
542      ifelse
543    } loop
544
545    /PDFversion exch def
546         % Read the last cross-reference table.
547    count /pdfemptycount exch def
548    /Trailer << >> def           % Initialize to an emptry dict.
549    { initPDFobjects findxref readxref } .internalstopped {
550      recover_xref_data          % Read failed.  Attempt to recover xref data.
551      search_trailer             % Search for the primary trailer
552    } {
553      /Trailer exch def          % Save trailer dict after first xref table
554         % Read any previous cross-reference tables.  When we are done,
555         % verify that the entries in the xref tables are valid if NoVerifyXref
556         % is not defined.
557      Trailer
558      { /Prev knownoget not {    % If no previous xref table then ...
559          /NoVerifyXref where { pop } { verify_xref } ifelse exit
560        } if
561        { readxref } .internalstopped {
562          recover_xref_data      % Read failed.  Attempt to recover xref data.
563          exit                   % Exit loop since recover gets all obj data.
564        } if                     % If readxref stopped
565        % The PDF spec. says that each trailer dict should contain the required
566        % entries.  However we have seen a PDF file that only has a Prev entry in
567        % the initial trailer dict.  Acrobat complains but it accepts these files.
568        % To work with these files, we are copying any entries which we find in
569        % a previous trailer dict which are not present in the initial dict.
570        dup {
571          Trailer 2 index known {
572            pop pop              % discard if key already present
573          } {
574            Trailer 3 1 roll put % add key if not present
575          } ifelse
576        } forall
577      } loop                     % Loop to previous trailer
578    } ifelse                     % Ifelse readxref stopped
579    Trailer /Encrypt knownoget {
580      pop
581      pdf_process_Encrypt        % signal error
582    } if
583    currentdict end
584  } bind def
585
586 % Look for [\r\n]%%EO from the current position of the file.
587 % Return the position of %%EO if found or -1 .
588 /findeof {  % <file> find_eof <file> <position>
589   -1 exch
590   {
591     dup bytesavailable 4 lt { exit } if
592     dup 0 (%%EO) /SubFileDecode filter flushfile
593     dup dup fileposition 5 sub setfileposition
594     dup 5 string readstring not { pop exit } if
595     dup (\r%%EO) eq exch (\n%%EO) eq or {
596       dup fileposition 4 sub
597       3 1 roll exch pop
598     } if
599   } loop
600   exch
601 } bind def
602
603 % Skip backward over the %%EOF at the end of the PDF file, and read
604 % the preceding startxref line.  The PDF specification unambiguously
605 % requires that the %%EOF appear on a line by itself, and that the
606 % startxref and the following position value appear on separate lines;
607 % however, some applications truncate the %%EOF to %%EO, and/or put the
608 % startxref and the following value on the same line.
609 % There seems to be no limit on the amount of garbage that can be
610 % appended to the PDF file. Current record (60K) belongs to
611 % PDF-Out (v 2.0 - 35). We start the search for %%EO from the last 1024
612 % bytes and continue from the beginning of the file.
613 /findxref {             % - findxref <xrefpos>
614   PDFfile dup dup dup 0 setfileposition bytesavailable
615   dup /PDFfilelen exch def
616         % Find the last %%EOF string (within 1024 bytes)
617   1024 sub PDFoffset .max
618   setfileposition findeof                  % search the last 1024 bytes
619   dup 0 le {
620     pop
621     dup PDFoffset setfileposition findeof  % search from the beginnibg
622     dup 0 le {
623        (   **** Error: Cannot find a %%EOF marker anywhere in the file.\n)
624        pdfformaterror
625        /findxref cvx /syntaxerror signalerror
626     } if
627   } if
628   dup 3 1 roll setfileposition
629         % Stack: eofpos
630         % Check for whether this is, in fact, a valid PDF file.
631   dup PDFfilelen exch sub dup dup 7 gt exch 5 lt or {
632     pop true
633   } {
634     string PDFfile exch readstring pop
635     dup (%%EOF\n) eq exch dup (%%EOF\r) eq
636     exch dup (%%EOF\r\n) eq exch (%%EOF) eq or or or not
637   } ifelse {
638     (   **** Warning: File has a corrupted %%EOF marker, or garbage after %%EOF.\n)
639     pdfformaterror
640   } if
641   PDFfile exch setfileposition
642         % Now read the startxref and xref start position.
643   prevline token not { null } if dup type /integertype eq {
644     exch pop cvi                % xref start position
645     exch PDFfile exch setfileposition
646     prevline dup (startxref) linene {
647       % startxref not on a line by itself.  We have found PDF from
648       % www.verypdf.com in which the startxref was on the same line as
649       % the end of trailer dictionary.  Check for this.  Note:  This
650       % violates the spec.
651       dup (startxref) search {
652         % found startxref - print warning
653         pop pop pop                     % clear strings from search
654         (   **** Warning: format of the startxref line in this file is invalid.\n)
655         pdfformaterror
656       } {                               % no startxref - we have a problem.
657         /findxref cvx /syntaxerror signalerror
658       } ifelse
659     } if
660     pop pop
661   } {   % else, this file has 'startxref #####' format
662     (startxref) ne { /findxref cvx /syntaxerror signalerror } if
663     cvi         % xref start position
664     (   **** Warning: format of the startxref line in this file is invalid.\n)
665     pdfformaterror
666     exch PDFfile exch setfileposition
667   } ifelse
668 } bind def
669 /stderrfile (%stderr) (w) file def
670 /stderrprint {                % <string> stderrprint -
671   //stderrfile dup 3 -1 roll writestring flushfile
672 } bind def
673 /pdfformaterror {       % <string> pdfformaterror -
674   stderrprint
675   /Repaired true store
676 } bind def
677
678 /knownoget_safe
679 { 2 copy knownoget { 3 1 roll pop pop //true } { pop pop //false } ifelse
680 } odef
681
682 /printProducer {
683   Trailer /Info { knownoget_safe } stopped { pop pop false } if {
684     /Producer knownoget not { null } if
685   } {
686     null
687   } ifelse
688   dup null eq {
689     pop
690   } {
691     (   **** The file was produced by: \n   **** >>>> ) stderrprint
692         % Handle a Unicode Producer.
693     (\376\377) anchorsearch {
694       pop dup length 2 idiv string 0 1 2 index length 1 sub {
695                 % Stack: origstr newstr i
696         1 index exch 3 index 1 index 2 mul 1 add get put
697       } for exch pop
698     } if
699     stderrprint
700     ( <<<<\n) stderrprint
701   } ifelse
702 } bind def
703 % The TTFWarnList is the list of all TrueType fonts that were not embedded.
704 % The UndefProcList collects noisy warnings.
705 % This gets rid of many multiple warnings from pdf_font.ps
706 /printCollectedWarnings {
707    TTFWarnList length 0 gt {
708       (\n   **** Warning: Fonts with Subtype = /TrueType should be embedded.\n)
709       stderrprint
710       (                 The following fonts were not embedded:\n)
711       stderrprint
712       [ TTFWarnList { pop .namestring (\t\t\t) exch concatstrings (\n) concatstrings } forall ] 
713       { lt } .sort { stderrprint } forall
714    } if
715    UndefProcList length 0 gt {
716       (\n   **** Embedded font uses undefined procedure\(s\):  ) stderrprint
717       UndefProcList {
718          exch .namestring stderrprint ( ) stderrprint
719          =string cvs stderrprint ( times, ) stderrprint
720       } forall 
721       (\n) stderrprint
722    } if
723 } bind def
724 /printrepaired {
725    printCollectedWarnings
726    (\n   **** This file had errors that were repaired or ignored.\n)
727   stderrprint
728   printProducer
729   (   **** Please notify the author of the software that produced this\n)
730   stderrprint
731   (   **** file that it does not conform to Adobe's published PDF\n)
732   stderrprint
733   (   **** specification.\n\n)
734   stderrprint
735 } bind def
736
737 % Write the outline structure for a file.  Uses linkdest (below).
738 % omit links to pages that don't exist.
739 /writeoutline           % <outlinedict> writeoutline -
740  { mark
741    0 2 index /First knownoget
742     { { exch 1 add exch /Next knownoget not { exit } if } loop }
743    if
744                 % stack: dict mark count
745    dup 0 eq
746     { pop 1 index }
747     { 2 index /Count knownoget { 0 lt { neg } if } if
748       /Count exch 3 index
749     }
750    ifelse { linkdest } stopped 
751     {
752       cleartomark       % ignore this link
753       (   **** Warning: Outline has invalid link that was discarded.\n)
754       pdfformaterror
755     } {
756       /Title oget /Title exch /OUT pdfmark
757     }
758    ifelse
759    /First knownoget
760     { { dup writeoutline /Next knownoget not { exit } if } loop }
761    if
762  } bind def
763
764 % Close a PDF file.
765 /pdfclose               % <dict> pdfclose -
766  { begin
767    PDFfile closefile
768    end
769  } bind def
770
771 % ======================== Page accessing ======================== %
772
773 % Get a (possibly inherited) attribute of a page.
774 /pget                   % <pagedict> <key> pget <value> -true-
775                         % <pagedict> <key> pget -false-
776  { 2 copy knownoget
777     { exch pop exch pop true
778     }
779     { exch /Parent knownoget
780        { exch pget }
781        { pop false }
782       ifelse
783     }
784    ifelse
785  } bind def
786
787 % Get the value of a resource on a given page.
788 /rget {                 % <resname> <pagedict> <restype> rget <value> -true-
789                         % <resname> <pagedict> <restype> rget -false-
790   LocalResources 1 index knownoget {
791      3 index knownoget
792   } {
793     false
794   } ifelse {
795     exch pop exch pop exch pop true
796   } {
797     exch /Resources pget {
798       exch knownoget { exch knownoget } { pop false } ifelse
799     } {
800       pop pop false
801     } ifelse
802   } ifelse
803 } bind def
804
805 % Get the total number of pages in the document.
806 /pdfpagecount           % - pdfpagecount <int>
807  { Trailer /Root oget /Pages oget /Count oget
808  } bind def
809
810 % Find the N'th page of the document by iterating through the Pages tree.
811 % The first page is numbered 1.
812 /pdffindpageref {               % <int> pdffindpage <objref>
813   dup Trailer /Root oget /Pages get
814     {           % We should be able to tell when we reach a leaf
815                 % by finding a Type unequal to /Pages.  Unfortunately,
816                 % some files distributed by Adobe lack the Type key
817                 % in some of the Pages nodes!  Instead, we check for Kids.
818       dup oforce /Kids knownoget not { exit } if
819       exch pop null
820       0 1 3 index length 1 sub {
821          2 index exch get
822          dup oforce dup /Kids known { /Count oget } { pop 1 } ifelse
823                 % Stack: index kids null noderef count
824          dup 5 index ge { pop exch pop exit } if
825          5 -1 roll exch sub 4 1 roll pop
826       } for exch pop
827                 % Stack: index null|noderef
828       dup null eq { pop pop 1 null exit } if
829     } loop
830                 % Stack: index countleft noderef
831    1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
832    exch pop
833    PageIndex 2 index 1 sub 65533 .min 2 index oforce put
834    PageNumbers 1 index oforce 3 index dup 65534 le
835     { put }
836     { pop pop pop }     % don't store more than 65534 pagenumbers
837    ifelse
838    exch pop
839 } bind def
840 /pdffindpage {          % <int> pdffindpage <pagedict>
841   pdffindpageref oforce
842 } bind def
843
844 % Find the N'th page of the document.
845 % The first page is numbered 1.
846 /pdfgetpage             % <int> pdfgetpage <pagedict>
847  { PageIndex 1 index 1 sub dup 65533 lt
848     { get }
849     { pop pop null }
850    ifelse
851    dup null ne
852     { exch pop oforce }
853     { pop pdffindpage }
854    ifelse
855  } bind def
856
857 % Find the page number of a page object (inverse of pdfgetpage).
858 /pdfpagenumber          % <pagedict> pdfpagenumber <int>
859  {      % We use the simplest and stupidest of all possible algorithms....
860    PageNumbers 1 index .knownget
861     { exch pop
862     }
863     { 1 1 PageCount 1 add       % will give a rangecheck if not found
864        { dup pdfgetpage oforce 2 index eq { exit } if pop
865        }
866       for exch pop
867     }
868    ifelse
869  } bind def
870
871 % Arrange the four elements that define a rectangle into a 'normal' order.
872 /normrect_elems   % <x1> <y1> <x2> <y2> normrect_elems <llx> <lly> <urx> <ury>
873 {
874     exch 4 1 roll                       % <x2> <x1> <y1> <y2>
875     2 copy gt { exch } if               % <x2> <x1> <lly> <ury>
876     4 2 roll 2 copy lt { exch } if      % <lly> <ury> <urx> <llx>
877     4 1 roll exch                       % <llx> <lly> <urx> <ury>
878 } bind def
879
880 % Arrange a rectangle into a 'normal' order.  I.e the lower left corner
881 % followed by the upper right corner.
882 /normrect       % <rect> normrect <rect>
883 {
884     aload pop normrect_elems 4 array astore
885 } bind def
886
887 /boxrect                % <llx> <lly> <urx> <ury> boxrect <x> <y> <w> <h>
888  { exch 3 index sub exch 2 index sub
889  } bind def
890 /resolvedest {          % <name|string|other> resolvedest <other|null>
891   dup type /nametype eq {
892     Trailer /Root oget /Dests knownoget {
893       exch knownoget not { null } if
894     } {
895       pop null
896     } ifelse
897   } {
898     dup type /stringtype eq {
899       Trailer /Root oget /Names knownoget {
900         /Dests knownoget {
901           exch nameoget
902         } {
903           pop null
904         } ifelse
905       } {
906         pop null
907       } ifelse
908     } if
909   } ifelse
910 } bind def
911 /linkdest {             % <link|outline> linkdest
912                         %   ([/Page <n>] /View <view> | ) <link|outline>
913   dup /Dest knownoget
914     { resolvedest
915       dup type /dicttype eq { /D knownoget not { null } if } if
916       dup null eq
917        { pop }
918        { dup 0 oget
919          dup type /dicttype eq {
920            dup /Type knownoget {
921              /Page eq {
922                pdfpagenumber
923              } if
924            } if
925          } if
926          dup type /integertype ne 
927            { pop }
928            { /Page exch 4 -2 roll }
929          ifelse
930          dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
931        }
932       ifelse
933     }
934    if
935 } bind def
936 % <pagedict> mark ... -proc- -
937 /namedactions 8 dict dup begin
938   /FirstPage {
939     /Page 1 3 -1 roll
940   } def
941   /LastPage {
942     counttomark 2 add index pdfpagecount /Page exch 3 -1 roll
943   } def
944   /NextPage {
945     counttomark 2 add index pdfpagenumber 1 add /Page exch 3 -1 roll
946   } def
947   /PrevPage {
948     counttomark 2 add index pdfpagenumber 1 sub /Page exch 3 -1 roll
949   } def
950 end readonly def
951 % <pagedict> <annotdict> -proc- -
952 /annottypes 5 dict dup begin
953   /Text {
954     mark exch
955      { /Rect /Open /Contents }
956      { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
957     forall pop /ANN pdfmark
958   } bind def
959   /Link {
960     mark exch
961     dup /C knownoget { /Color exch 3 -1 roll } if
962      { /Rect /Border }
963      { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
964     forall dup /A knownoget {
965       dup /URI known {
966         /A mark 3 2 roll    % <<>> /A [ <<action>>
967         { oforce } forall
968         .dicttomark
969         3 2 roll
970       } {
971         dup /D knownoget {
972           exch pop exch dup length dict copy dup /Dest 4 -1 roll put
973         } {
974           /N knownoget {                % Assume /S /Named
975              namedactions exch .knownget { exec } if
976           } if
977         } ifelse
978       } ifelse
979     } if
980     linkdest pop /LNK pdfmark
981   } bind def
982 end readonly def
983
984 % **** The following procedure should not be changed to allow clients
985 % **** to directly interface with the constituent procedures. GSview
986 % **** and some Artifex customers rely on the pdfshowpage_init,
987 % **** pdfshowpage_setpage, pdfshowpage_finish so all logic should be
988 % **** implemented in one of those three procedures.
989 /pdfshowpage            % <pagedict> pdfshowpage -
990  { dup /Page exch store
991    pdfshowpage_init 
992    pdfshowpage_setpage 
993    pdfshowpage_finish
994  } bind def
995
996 /pdfpagecontents        % <pagedict> pdfpagecontents <contents>
997  { } bind def
998
999 /pdfshowpage_init       % <pagedict> pdfshowpage_init <pagedict>
1000  { /DSCPageCount DSCPageCount 1 add store
1001  } bind def
1002
1003 /.pdfshowpage_Install { % <pagedict> [<prevproc>] .pdfshowpage_Install -
1004   exch
1005         % We would like to clip to the CropBox here, but the subsequent
1006         % initgraphics would override it.  Instead, we have to handle it
1007         % in graphicsbeginpage.
1008   dup /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
1009     dup /CropBox pget pop
1010   } {
1011     dup /MediaBox pget pop      % There has to be a MediaBox
1012   } ifelse
1013   % stack: [<prevproc>] <pagedict> <Crop|Media Box>
1014   exch pop oforce_array normrect                % done with the pagedict
1015   systemdict /PDFFitPage known {
1016     PDFDEBUG { (Fiting PDF to imageable area of the page.) = flush } if
1017     currentpagedevice /.HWMargins get aload pop
1018     currentpagedevice /PageSize get aload pop
1019     3 -1 roll sub 3 1 roll exch sub exch
1020     % stack: [<prevproc>] <pagedict> <Crop|Media Box> Xmin Ymin Xmax Ymax
1021     PDFDEBUG { (    Translate up by [ ) print 3 index =print (, ) print 2 index =print ( ]) = flush } if
1022     3 index 3 index translate           % move origin up to imageable area
1023     2 index sub exch 3 index sub exch 4 2 roll pop pop
1024             % stack: [Box] XImageable YImageable
1025     2 index aload pop 2 index sub exch 3 index sub exch 4 2 roll pop pop
1026             % stack: [Box] XImageable YImageable XBox YBox
1027     3 -1 roll exch div 3 1 roll div .min
1028     PDFDEBUG { (    Scale by ) print dup = flush } if
1029     dup scale
1030   } if
1031   % Now translate to the origin given in the Crop|Media Box
1032   dup 0 get neg exch 1 get neg translate
1033   0 get
1034   exec
1035 } bind def
1036
1037 /pdfshowpage_setpage {  % <pagedict> pdfshowpage_setpage <pagedict>
1038   5 dict begin          % for setpagedevice
1039         % Stack: pagedict
1040   % UseCIEColor is always true for PDF; see the comment in runpdf above
1041   /UseCIEColor true def
1042   currentpagedevice /Orientation 2 index /Rotate pget not { 0 } if 90 idiv
1043         % Rotate specifies *clockwise* rotation!
1044     neg 3 and def
1045         % Stack: pagedict currentpagedict
1046   1 index /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
1047                         % Set the page size.
1048     1 index /CropBox pget pop oforce_elems normrect_elems boxrect
1049     2 array astore /PageSize exch def pop pop
1050   } {
1051     1 index /MediaBox pget {
1052                         % Set the page size.
1053       oforce_elems normrect_elems boxrect
1054       2 array astore /PageSize exch def pop pop
1055     } if
1056   } ifelse
1057   % Don't change the page size if we are going to fit the PDF to the page
1058   systemdict /PDFFitPage known { currentdict /PageSize undef } if
1059   % Let the device know if we will be using PDF 1.4 transparency.
1060   % The clist logic may need to adjust the size of bands.
1061   1 index pageusestransparency /PageUsesTransparency exch def
1062   dup /Install .knownget {
1063                         % Don't let the Install procedure get more deeply
1064                         % nested after every page.
1065       dup type dup /arraytype eq exch /packedarraytype eq or {
1066         dup length 4 eq {
1067           dup 2 get /.pdfshowpage_Install load eq {
1068             1 get 0 get % previous procedure
1069           } if
1070         } if
1071       } if
1072   } {
1073     { }
1074   } ifelse 1 array astore
1075   2 index exch /.pdfshowpage_Install load /exec load
1076   4 packedarray cvx
1077         % Stack: pagedict currentpagedict installproc
1078   /Install exch def
1079         % Stack: pagedict currentpagedict
1080   pop currentdict end setpagedevice
1081 } bind def
1082
1083 /pdfshowpage_finish {   % <pagedict> pdfshowpage_finish -
1084    save /PDFSave exch store
1085    /PDFdictstackcount countdictstack store
1086    (before exec) VMDEBUG
1087
1088    % set up color space substitution (this must be inside the page save)
1089    pdfshowpage_setcspacesub
1090
1091   .writepdfmarks {
1092
1093         % Copy the crop box.
1094     dup /CropBox knownoget {
1095       oforce_array normrect
1096
1097         % .pdfshowpage_Install translates the origin -
1098         % do same here with the CropBox.
1099
1100       1 index /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
1101         1 index /CropBox pget pop
1102       } {
1103         1 index /MediaBox pget pop      % There has to be a MediaBox
1104       } ifelse
1105       oforce_array normrect
1106       dup 0 get exch 1 get   % [] tx ty
1107       2 index 0 get 2 index sub 3 index exch 0 exch put
1108       2 index 2 get 2 index sub 3 index exch 2 exch put
1109       2 index 1 get 1 index sub 3 index exch 1 exch put
1110       2 index 3 get 1 index sub 3 index exch 3 exch put
1111       pop pop
1112
1113         % If the page has been rotated, rotate the CropBox.
1114       mark /CropBox 3 -1 roll
1115       3 index /Rotate pget {
1116         90 idiv 1 and 0 ne {
1117           aload pop 4 -2 roll exch 4 2 roll exch 4 array astore
1118         } if
1119       } if
1120       /PAGE pdfmark
1121     } if
1122
1123         % Copy annotations and links.
1124     dup /Annots knownoget {
1125       0 1 2 index length 1 sub
1126        { 1 index exch oget
1127          dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
1128        }
1129       for pop
1130     } if
1131
1132   } if          % end .writepdfmarks
1133
1134         % Display the actual page contents.
1135    6 dict begin
1136    /BXlevel 0 def
1137    /BGDefault currentblackgeneration def
1138    /UCRDefault currentundercolorremoval def
1139         %****** DOESN'T HANDLE COLOR TRANSFER YET ******
1140    /TRDefault currenttransfer def
1141   matrix currentmatrix 2 dict
1142   2 index /CropBox knownoget {
1143     oforce_elems normrect_elems boxrect
1144     4 array astore 1 index /ClipRect 3 -1 roll put
1145   } if
1146   dictbeginpage setmatrix
1147   /DefaultQstate qstate store
1148
1149   dup             % for showing annotations below
1150   count 1 sub /pdfemptycount exch store
1151         % If the page uses any transparency features, show it within
1152         % a transparency group.
1153   dup pageusestransparency dup /PDFusingtransparency exch def {
1154     % Show the page within a PDF 1.4 device filter.
1155     0 .pushpdf14devicefilter {
1156       /DefaultQstate qstate store               % device has changed -- reset DefaultQstate
1157       % If the page has a Group, enclose contents in transparency group.
1158       % (Adobe Tech Note 5407, sec 9.2)
1159       dup /Group knownoget {
1160         1 index /CropBox knownoget not {
1161           1 index /MediaBox pget pop
1162         } if oforce_array normrect .beginformgroup {
1163           showpagecontents
1164         } stopped {
1165           .discardtransparencygroup stop
1166         } if .endtransparencygroup
1167       } {
1168         showpagecontents
1169       } ifelse
1170     } stopped {
1171       % todo: discard
1172       .poppdf14devicefilter 
1173       /DefaultQstate qstate store       % device has changed -- reset DefaultQstate
1174       stop
1175     } if .poppdf14devicefilter
1176     /DefaultQstate qstate store % device has changed -- reset DefaultQstate
1177   } {
1178     showpagecontents
1179   } ifelse
1180   % check for extra garbage on the ostack and clean it up
1181   count pdfemptycount sub dup 0 ne {
1182     (   **** File did not complete the page properly and may be damaged.\n)
1183     pdfformaterror
1184     { pop } repeat
1185   } {
1186     pop
1187   } ifelse
1188   % todo: mixing drawing ops outside the device filter could cause
1189   % problems, for example with the pnga device.
1190   /Annots knownoget { { oforce drawannot } forall } if
1191   endpage
1192   end                   % scratch dict
1193   % Some PDF files don't have matching q/Q (gsave/grestore) so we need
1194   % to clean up any left over dicts from the dictstack
1195   countdictstack PDFdictstackcount sub dup 0 ne { 
1196     (   **** Warning: File has imbalanced q/Q operators \(too many q's\)\n)
1197     pdfformaterror
1198     { end } repeat
1199   } {
1200     pop
1201   } ifelse
1202   (after exec) VMDEBUG
1203   Repaired              % pass Repaired state around the restore
1204   PDFSave restore
1205   /Repaired exch def
1206 } bind def
1207 /showpagecontents {     % <pagedict> showpagecontents -
1208   gsave         % preserve gstate for Annotations later
1209   /Contents knownoget not { 0 array } if
1210   dup type /arraytype ne { 1 array astore } if {
1211     oforce false resolvestream pdfopdict .pdfrun
1212   } forall
1213   grestore
1214 } bind def
1215 /processcolorspace {    % - processcolorspace <colorspace>
1216         % The following is per the PLRM3.
1217   currentdevice 1 dict dup /ProcessColorModel dup put .getdeviceparams
1218   exch pop exch pop
1219   dup type /nametype ne { cvn } if
1220   dup { setcolorspace } .internalstopped { pop /DeviceRGB } if
1221 } bind def
1222
1223 % ------ Transparency support ------ %
1224
1225 % Define minimum PDF version for checking for transparency features.
1226 % Transparency is a 1.4 feature however we have seen files that claimed
1227 % to be PDF 1.3 with transparency features.
1228 /PDFtransparencyversion 1.3 def
1229
1230 % Determine whether a page might invoke any transparency features:
1231 %       - Non-default BM, ca, CA, or SMask in an ExtGState
1232 %       - Image XObject with SMask
1233 % Note: we deliberately don't check to see whether a Group is defined,
1234 % because Adobe Illustrator 10 (and possibly other applications) define
1235 % a page-level group whether transparency is actually used or not.
1236 % Ignoring the presence of Group is justified because, in the absence
1237 % of any other transparency features, they have no effect.
1238 /pageusestransparency {         % <pagedict> pageusestransparency <bool>
1239   PDFversion PDFtransparencyversion lt NOTRANSPARENCY or {
1240     pop false
1241   } {
1242     false exch {
1243       4 dict 1 index resourceusestransparency { pop not exit } if
1244       /Parent knownoget not { exit } if
1245     } loop
1246   } ifelse
1247 } bind def
1248
1249 % Check the Resources of a page or Form. Check for loops in the resource chain.
1250 /resourceusestransparency {     % <dict> <dict> resourceusestransparency <bool>
1251   {     % Use loop to provide an exitable context.
1252     /Resources knownoget not { 0 dict } if
1253     2 copy known {
1254       (   **** File has circular references in resource dictionaries.\n)
1255       pdfformaterror
1256       pop false exit
1257     } if
1258     2 copy dup put
1259     dup /ExtGState knownoget {
1260       false exch {
1261         exch pop oforce
1262         dup /BM knownoget { dup /Normal ne exch /Compatible ne and
1263                             { pop not exit } if
1264                           } if
1265         dup /ca knownoget { 1 ne { pop not exit } if } if
1266         dup /CA knownoget { 1 ne { pop not exit } if } if
1267         dup /SMask knownoget { /None ne { pop not exit } if } if
1268         pop
1269       } forall { pop true exit } if
1270     } if
1271     dup /XObject knownoget {
1272       false exch {
1273         exch pop oforce dup /Subtype get
1274         dup /Image eq { 1 index /SMask known { pop pop not exit } if } if
1275         /Form eq {
1276           3 index exch resourceusestransparency { not exit } if
1277         } {
1278           pop
1279         } ifelse
1280       } forall { pop true exit } if
1281     } if
1282     pop false exit
1283   } loop
1284   exch pop
1285 } bind def
1286
1287 % ------ ColorSpace substitution support ------ %
1288
1289 %
1290 %  <pagedict>   pdfshowpage_setcspacesub   <pagedict>
1291 %
1292 % Set up color space substitution for a page. Invocations of this procedure
1293 % must be bracketed by the save/restore operation for the page, to avoid
1294 % unintended effects on other pages.
1295 %
1296 % If any color space substitution is used, and the current color space is a
1297 % device dependent color space, make sure the current color space is updated.
1298 % There is an optimization in the setcolorspace pseudo-operator that does
1299 % nothing if both the current and operand color spaces are the same. For
1300 % PostScript this optimization is disabled if the UseCIEColor page device
1301 % parameter is true. This is not the case for PDF, as performance suffers
1302 % significantly on some PDF files if color spaces are set repeatedly. Hence,
1303 % if color space substitution is to be used, and the current color space
1304 % is a device dependent color space, we must make sure to "transition" the
1305 % current color space.
1306 %
1307 /pdfshowpage_setcspacesub
1308   {
1309     false
1310       { /DefaultGray /DefaultRGB /DefaultCMYK }
1311       {
1312         dup 3 index /ColorSpace //rget exec
1313           { resolvecolorspace /ColorSpace defineresource pop }
1314           { pop }
1315         ifelse
1316       }
1317     forall
1318
1319     % if using color space substitution, "transition" the current color space
1320       {
1321         currentcolorspace dup length 1 eq   % always an array
1322           {
1323             0 get
1324             dup /DeviceGray eq 1 index /DeviceRGB eq or 1 index /DeviceCMYK or
1325               { /Pattern setcolorspace setcolorspace }
1326               { pop }
1327             ifelse
1328           }
1329           { pop }
1330         if
1331       }
1332     if
1333   }
1334 bind def
1335
1336
1337
1338 end                     % pdfdict
1339 .setglobal