922 lines · 33.6 KB · Text
RawDownload
%    Copyright (C) 1994-2003 artofcode LLC.  All rights reserved.% % This software is provided AS-IS with no warranty, either express or% implied.% % This software is distributed under license and may not be copied,% modified or distributed except as expressly authorized under the terms% of the license contained in the file LICENSE in this distribution.% % For more information about licensing, please refer to% http://www.ghostscript.com/licensing/. For information on% commercial licensing, go to http://www.artifex.com/licensing/ or% contact Artifex Software, Inc., 101 Lucas Valley Road #110,% San Rafael, CA  94903, U.S.A., +1(415)492-9861. % $Id: pdf_base.ps,v 1.48 2005/09/16 19:01:30 ray Exp $% pdf_base.ps% Basic parser for PDF reader. % This handles basic parsing of the file (including the trailer% and cross-reference table), as well as objects, object references,% streams, and name/number trees; it doesn't include any facilities for% making marks on the page. /.setlanguagelevel where { pop 2 .setlanguagelevel } if.currentglobal true .setglobal/pdfdict where { pop } { /pdfdict 100 dict def } ifelsepdfdict begin % Define the name interpretation dictionary for reading values./valueopdict mark  (<<) cvn { mark } bind	% don't push an actual mark!  (>>) cvn { { .dicttomark } stopped {      (   **** File has an unbalanced >> \(close dictionary\).\n)      pdfformaterror    } if  } bind  ([) cvn { mark } bind		% ditto  (]) cvn dup load%  /true true		% see .pdfexectoken below%  /false false		% ibid.%  /null null		% ibid.  /F dup cvx		% see Objects section below  /R dup cvx		% see Objects section below  /stream dup cvx	% see Streams section below.dicttomark readonly def % ------ Utilities ------ % % Define a scratch string.  The PDF language definition says that% no line in a PDF file can exceed 255 characters./pdfstring 255 string def % Read the previous line of a file.  If we aren't at a line boundary,% read the line containing the current position.% Skip any blank lines./prevline		% - prevline <startpos> <substring> { PDFfile fileposition dup () pdfstring   2 index 257 sub 0 .max PDFfile exch setfileposition    {		% Stack: initpos linepos line string      PDFfile fileposition      PDFfile 2 index readline pop      dup length 0 gt       { 3 2 roll 5 -2 roll pop pop 2 index }       { pop }      ifelse		% Stack: initpos linepos line string startpos      PDFfile fileposition 5 index ge { exit } if      pop    }   loop pop pop 3 -1 roll pop } bind def % Handle the PDF 1.2 #nn escape convention when reading from a file.% This should eventually be done in C./.pdffixname {			% <execname> .pdffixname <execname'>  PDFversion 1.2 ge {    dup .namestring (#) search {      name#escape cvn exch pop    } {      pop    } ifelse  } if} bind def/name#escape			% <post> <(#)> <pre> name#escape <string>{ exch pop  1 index 2 () /SubFileDecode filter dup (x) readhexstring		% Stack: post pre stream char t/f  not {	% tolerate, but complain about bad syntax    pop closefile (#) concatstrings exch    (   **** Warning: Invalid hex following '#' name escape, using literal '#' in name.\n)    pdfformaterror  } {    exch closefile concatstrings    exch 2 1 index length 2 sub getinterval  } ifelse  (#) search { name#escape } if concatstrings} bind def % Execute a file, interpreting its executable names in a given% dictionary.  The name procedures may do whatever they want% to the operand stack./.pdftokenerror {		% <count> <opdict> <errtoken> .pdftokenerror -  BXlevel 0 le {    (   **** Unknown operator: ') pdfformaterror    dup =string cvs pdfformaterror     % Attempt a retry scan of the element after changing to PDFScanInvNum    << /PDFScanInvNum true >> setuserparams    =string cvs    token pop exch pop dup type    dup /integertype eq exch /realtype eq or {      exch pop exch pop      (', processed as number, value: ) pdfformaterror      dup =string cvs pdfformaterror (\n) pdfformaterror     << /PDFScanInvNum null >> setuserparams    % reset to default scanning rules      false 	% suppress any stack cleanup    } {      % error was non-recoverable with modified scanning rules    ('\n) pdfformaterror      true    } ifelse  } {    true  } ifelse  { % clean up the operand stack if this was non-recoverable  pop pop count exch sub { pop } repeat	% pop all the operands  } if} bind def/.pdfexectoken {		% <count> <opdict> <exectoken> .pdfexectoken ?  PDFDEBUG {    pdfdict /PDFSTEPcount known not { pdfdict /PDFSTEPcount 1 .forceput } if    PDFSTEP {      pdfdict /PDFtokencount 2 copy .knownget { 1 add } { 1 } ifelse .forceput      PDFSTEPcount 1 gt {	pdfdict /PDFSTEPcount PDFSTEPcount 1 sub .forceput      } {        dup ==only        (    step # ) print PDFtokencount =only 	( ? ) print flush 1 false .outputpage	(%stdin) (r) file 255 string readline {	  token {            exch pop pdfdict /PDFSTEPcount 3 -1 roll .forceput	  } {	    pdfdict /PDFSTEPcount 1 .forceput	  } ifelse % token	} {	  pop /PDFSTEP false def	 % EOF on stdin	} ifelse % readline      } ifelse % PDFSTEPcount > 1    } {      dup ==only () = flush    } ifelse % PDFSTEP  } if % PDFDEBUG  2 copy .knownget {    exch pop exch pop exch pop exec  } {		% Normally, true, false, and null would appear in opdict		% and be treated as "operators".  However, there is a		% special fast case in the PostScript interpreter for names		% that are defined in, and only in, systemdict and/or		% userdict: putting these three names in the PDF dictionaries		% destroys this property for them, slowing down their		% interpretation in all PostScript code.  Therefore, we		% check for them explicitly here instead.    dup dup dup /true eq exch /false eq or exch /null eq or {      exch pop exch pop //systemdict exch get    } {      .pdftokenerror    } ifelse  } ifelse} bind def/.pdfrun {			% <file> <opdict> .pdfrun -	% Construct a procedure with the stack depth, file and opdict	% bound into it.  1 index cvlit count 2 sub 3 1 roll mark mark 5 2 roll  {	% Stack: ..operands.. count opdict file    token {      dup type /nametype eq {	dup xcheck {	  .pdfexectoken	} {	  .pdffixname	  exch pop exch pop PDFDEBUG {            PDFSTEPcount 1 le {              dup ==only ( ) print flush            } if          } if	} ifelse      } {	exch pop exch pop PDFDEBUG {          PDFSTEPcount 1 le {            dup ==only ( ) print flush          } if        } if      } ifelse    } {      (%%EOF) cvn cvx .pdfexectoken    } ifelse  }  aload pop .packtomark cvx  /loop cvx 2 packedarray cvx  { stopped /PDFsource } aload pop  PDFsource  { store { stop } if } aload pop .packtomark cvx  /PDFsource 3 -1 roll store exec} bind def % Execute a file, like .pdfrun, for a marking context.% This temporarily rebinds LocalResources and DefaultQstate./.pdfruncontext {		% <resdict> <file> <opdict> .pdfruncontext -  /.pdfrun load LocalResources DefaultQstate  /LocalResources 7 -1 roll store  /DefaultQstate qstate store  3 .execn  /DefaultQstate exch store  /LocalResources exch store} bind def % Get the depth of the PDF operand stack.  The caller sets pdfemptycount% before calling .pdfrun or .pdfruncontext.  It is initially set by% pdf_main, and is also set by any routine which changes the operand% stack depth (currently .pdfpaintproc, although there are other callers% of .pdfrun{context} which have not been checked for opstack depth./.pdfcount {		% - .pdfcount <count>  count pdfemptycount sub} bind def % ================================ Objects ================================ % % Since we may have more than 64K objects, we have to use a 2-D array to% hold them (and the parallel Generations structure)./lshift 9 def/lnshift lshift neg def/lsubmask 1 lshift bitshift 1 sub def/lsublen lsubmask 1 add def/larray {	% - larray <larray>  [ [] ]} bind def/lstring {	% - lstring <lstring>  [ () ]} bind def/ltype {	% <lseq> type <type>  0 get type} bind def/lget {		% <lseq> <index> lget <value>  dup //lsubmask and 3 1 roll //lnshift bitshift get exch get} bind def/lput {		% <lseq> <index> <value> lput -  3 1 roll  dup //lsubmask and 4 1 roll //lnshift bitshift get  3 1 roll put} bind def/llength {	% <lseq> llength <length>  dup length 1 sub dup //lshift bitshift  3 1 roll get length add} bind def% lgrowto assumes newlength > llength(lseq)/growto {	% <string/array> <length> growto <string'/array'>  1 index type /stringtype eq { string } { array } ifelse  2 copy copy pop exch pop} bind def/lgrowto {	% <lseq> <newlength> lgrowto <lseq'>    dup //lsubmask add //lnshift bitshift dup 3 index length gt {	% Add more sub-arrays.  Start by completing the last existing one.		% Stack: lseq newlen newtoplen    3 -1 roll dup llength 1 sub //lsubmask or 1 add lgrowto		% Stack: newlen newtoplen lseq    [ exch aload pop    counttomark 2 add -1 roll		% newtoplen    counttomark sub { dup 0 0 getinterval lsublen growto } repeat    dup 0 0 getinterval ] exch  } {    pop  } ifelse	% Expand the last sub-array.  1 sub //lsubmask and 1 add  exch dup dup length 1 sub 2 copy		% Stack: newsublen lseq lseq len-1 lseq len-1  get 5 -1 roll growto put} bind def/lforall {	% <lseq> <proc> lforall -  /forall cvx 2 packedarray cvx forall} bind def % We keep track of PDF objects using the following PostScript variables:%%	Generations (lstring): Generations[N] holds 1+ the current%	    generation number for object number N.  (As far as we can tell,%	    this is needed only for error checking.)  For free objects,%	    Generations[N] is 0.%%	Objects (larray): If object N is loaded, Objects[N] is the actual%	    object; otherwise, Objects[N] is an executable integer giving%	    the file offset of the object's location in the file.  If%	    ObjectStream[N] is non-zero then Objects[N] contains the index%	    into the object stream instead of the file offset of the object.%%	ObjectStream (larray): If object N is in an object stream then%	    ObjectStream[N] holds the object number of the object stream.%	    Otherwise ObjectStream[N] contains 0.  If ObjectStream[N]%	    is non-zero then Objects[N] contains  the index into the object%	    stream.%%	GlobalObjects (dictionary): If object N has been resolved in%	    global VM, GlobalObjects[N] is the same as Objects[N]%	    (except that GlobalObjects itself is stored in global VM,%	    so the entry will not be deleted at the end of the page).%%	IsGlobal (lstring): IsGlobal[N] = 1 iff object N was resolved in%	    global VM.  This is an accelerator to avoid having to do a%	    dictionary lookup in GlobalObjects when resolving every object. % Initialize the PDF object tables./initPDFobjects {		% - initPDFobjects -  /ObjectStream larray def  /Objects larray def  /Generations lstring def  .currentglobal true .setglobal  /GlobalObjects 20 dict def  .setglobal  /IsGlobal lstring def} bind def % Grow the tables to a specified size./growPDFobjects {		% <minsize> growPDFobjects -  dup ObjectStream llength gt {    dup ObjectStream exch lgrowto /ObjectStream exch def  } if  dup Objects llength gt {    dup Objects exch lgrowto /Objects exch def  } if  dup Generations llength gt {    dup Generations exch lgrowto /Generations exch def  } if  dup IsGlobal llength gt {    dup IsGlobal exch lgrowto /IsGlobal exch def  } if  pop} bind def % We represent an unresolved object reference by a procedure of the form% {obj# gen# resolveR}.  This is not a possible PDF object, because PDF has% no way to represent procedures.  Since PDF in fact has no way to represent% any PostScript object that doesn't evaluate to itself, we can 'force'% a possibly indirect object painlessly with 'exec'.% Note that since we represent streams by executable dictionaries% (see below), we need both an xcheck and a type check to determine% whether an object has been resolved./resolved? {		% <object#> resolved? <value> true			% <object#> resolved? false  Objects 1 index lget dup xcheck {	% Check if executable    dup type /integertype eq {		% Check if an integer		% Check whether the object is in GlobalObjects.      pop IsGlobal 1 index lget 0 eq {	% 0 --> Not in GlabalObjects	pop false			% The object is not resolved      } {				% The object is in GlobalObjects		% Update Objects from GlobalObjects	PDFDEBUG { (%Global=>local: ) print dup == } if	GlobalObjects 1 index get dup Objects 4 1 roll lput true      } ifelse    } {				% Else object is executable but not integer      exch pop true		% Therefore must be executable dict. (stream)    } ifelse  } {				% Else object is not executable.    exch pop true		% Therefore it must have been resolved.  } ifelse} bind def/oforce /exec load def/oget {		% <array> <index> oget <object>		% <dict> <key> oget <object>		% Before release 6.20, this procedure stored the resolved		% object back into the referring slot.  In order to support		% PDF linearization, we no longer do this.  get oforce} bind def/oforce_array { % <array> oforce_array <array>  [ exch { oforce } forall ]} bind def/oforce_elems { % <array> oforce_elems <first> ... <last>  { oforce } forall} bind def% A null value in a dictionary is equivalent to an omitted key;% we must check for this specially./knownoget {	% <dict> <key> knownoget <value> true		% <dict> <key> knownoget false		% See oget above regarding this procedure.  .knownget {    oforce dup null eq { pop false } { true } ifelse  } {    false  } ifelse} bind def % PDF 1.1 defines a 'foreign file reference', but not its meaning.% Per the specification, we convert these to nulls./F {		% <file#> <object#> <generation#> F <object>		% Some PDF 1.1 files use F as a synonym for f!   .pdfcount 3 lt { f } { pop pop pop null } ifelse} bind def % Verify the generation number for a specified object% Note:  The values in Generations is the generation number plus 1.% If the value in Generations is zero then the object is free./checkgeneration {  % <object#> <generation#> checkgeneration <object#> <OK>  Generations 2 index lget 1 sub 1 index eq {	% If generation # match ...    pop true					% Then return true  } {					% Else not a match ...    QUIET not {				% Create warning message if not QUIET      Generations 2 index lget 0 eq {	% Check if object is free ...	(   **** Warning: reference to free object: )      } {	(   **** Warning: wrong generation: )      } ifelse      2 index =string cvs concatstrings ( ) concatstrings	% put obj #      exch =string cvs concatstrings ( R\n) concatstrings	% put gen #      pdfformaterror			% Output warning message    } {					% Else QUIET ...      pop				% Pop generation umber    } ifelse false			% Return false if gen # not match  } ifelse} bind def/R {		% <object#> <generation#> R <object>  /resolveR cvx 3 packedarray cvx} bind def % If we encounter an object definition while reading sequentially,% we just store it away and keep going./objopdict mark  valueopdict { } forall  /endobj dup cvx.dicttomark readonly def /obj {			% <object#> <generation#> obj <object>  PDFfile objopdict .pdfrun} bind def /endobj {		% <object#> <generation#> <object> endobj <object>  3 1 roll		% Read the xref entry if we haven't yet done so.		% This is only needed for generation # checking.  1 index resolved? {    pop  } if  checkgeneration {		% The only global objects we bother to save are		% (resource) dictionaries.    1 index dup gcheck exch type /dicttype eq and {      PDFDEBUG { (%Local=>global: ) print dup == } if      GlobalObjects 1 index 3 index put      IsGlobal 1 index 1 put    } if    Objects exch 2 index lput  } {    pop pop null  } ifelse} bind def % When resolving an object reference in an object stream, we stop at% the end of file.  Note:  Objects in an object stream do not have either% a starting 'obj' or and ending 'endobj'./resolveobjstreamopdict mark  valueopdict { } forall  (%%EOF) cvn { exit } bind.dicttomark readonly def % Note: This version of this function is not currently being used.% Resolve all objects in an object stream/resolveobjectstream {		% <object stream #> resolveobjectstream -  PDFDEBUG { (%Resolving object stream: ) print } if  0 resolveR	% Get the objectstream dict, all objstrms use 0 as the gen #  dup /First get		% Save location of first object onto the stack  1 index /N get		% Save number of objects onto the stack  2 index false resolvestream	% Convert stream dict into a stream  /ReusableStreamDecode filter	% We need to be able to position stream		% Objectstreams begin with list of object numbers and locations		% Create two arrays to hold object numbers and stream location  1 index array			% Array for holding object number  2 index array			% Array for holding stream object location		% Get the object numbers and locations.  0 1 5 index 1 sub {		% Loop and collect obj # and locations		% Stack: objstreamdict First N objectstream [obj#] [loc] index    2 index 1 index 		% Setup to put obj# into object number array    5 index token pop put	% Get stream, then get obj# and put into array    1 index 1 index 		% Setup to put object loc into location array    5 index token pop put	% Get stream, get obj loc and put into array    pop				% Remove loop index  } for  		% Create a bytestring big enough for reading any object data  		% Scan for the size of the largest object  0 0				% Init max object size and previous location  2 index {			% Loop through all object locations				% Stack:  ... maxsize prevloc currentloc    dup 4 1 roll		% Save copy of object location into stack    exch sub				% Object size = currentloc - prevloc    .max			% Determine maximum object size    exch			% Put max size under previous location  } forall  pop				% Remove previous location  .bigstring			% Create bytestring based upon max obj size		% Move to the start of the object data

Lines 1–500 of 922.