home *** CD-ROM | disk | FTP | other *** search
/ jppd.dyndns.org / jppd.dyndns.org.tar / jppd.dyndns.org / QUERYPRO / Actualizar / Impressora_PDF / converter.exe / GPLGS / pdf_base.ps < prev    next >
Text File  |  2004-09-01  |  26KB  |  706 lines

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