henesyinit from p9fd787fda5 years agoHistory
614 lines · 19.1 KB · Text
RawDownload
%    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.% % This file is part of Aladdin Ghostscript.% % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author% or distributor accepts any responsibility for the consequences of using it,% or for whether it serves any particular purpose or works at all, unless he% or she says so in writing.  Refer to the Aladdin Ghostscript Free Public% License (the "License") for full details.% % Every copy of Aladdin Ghostscript must include a copy of the License,% normally in a plain ASCII text file named PUBLIC.  The License grants you% the right to copy, modify and redistribute Aladdin Ghostscript, but only% under certain conditions described in the License.  Among other things, the% License requires that the copyright notice and this notice be preserved on% all copies. % $Id: pdf_base.ps,v 1.2 2000/03/10 03:58:14 lpd 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 load  ([) cvn { mark } bind		% ditto  (]) cvn dup load  /true true  /false false  /null null  /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 % Read a token from a file, recognizing the PDF 1.2 #nn escape convention.% This should be done in C!/.pdftoken {			% <file> .pdftoken <obj> -true-				% <file> .pdftoken -false-  token {    dup type /nametype eq {      dup xcheck {	true      } {	PDFversion 1.2 ge {	  dup .namestring (#) search {	    name#escape cvn exch pop	  } {	    pop	  } ifelse	} if true      } ifelse    } {      true    } ifelse  } {    false  } ifelse} 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 { /.pdftoken cvx /syntaxerror signalerror } if  exch closefile concatstrings  exch 2 1 index length 2 sub getinterval  (#) 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./.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    .pdftoken not { (%%EOF) cvn cvx } if    dup xcheck {      DEBUG { dup == flush } if      2 copy .knownget {	exch pop exch pop exch pop exec      } {	BXlevel 0 le {	  (%stderr) (w) file	  dup (****************Unknown operator: ) writestring	  dup 2 index .writecvs dup (\n) writestring flushfile	} if pop pop	count exch sub { pop } repeat	% pop all the operands      } ifelse    } {      exch pop exch pop DEBUG { dup ==only ( ) print flush } if    } 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./.pdfruncontext {		% <resdict> <file> <opdict> .pdfruncontext -  /.pdfrun load /LocalResources LocalResources /store load  /LocalResources 8 -1 roll store 4 .execn} bind def % Get the depth of the PDF operand stack.  The main program (pdf_main.ps)% sets pdfemptycount before calling .pdfrun./.pdfcount {		% - .pdfcount <count>  count pdfemptycount sub} bind def % ------ File reading ------ % % Read the cross-reference entry for an (unresolved) object.% The caller must save and restore the PDFfile position if desired.% For invalid (free) objects, we return 0./readxrefentry		% <object#> readxrefentry <objpos> { dup Objects exch lget   PDFfile exch setfileposition   PDFfile token pop		% object position   PDFfile token pop		% generation #   PDFfile token pop		% n or f   dup /n eq    { pop 1 add dup 255 gt       { Generations ltype /stringtype eq	  {		% Convert Generations from a string to an array.	    larray Generations llength lgrowto dup	    0 1 2 index llength 1 sub	     { Generations 1 index lget lput dup	     }	    for pop /Generations exch store	  }	 if       }      if    }    { /f eq       { pop 0 }       { /readxrefentry cvx /syntaxerror signalerror }      ifelse    }   ifelse		% Stack: obj# objpos 1+gen#   Generations 4 -1 roll 3 -1 roll lput } 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 % 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 entry in the cross-reference%	    table.%%	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 -  /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 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./unresolved? {		% <object#> unresolved? <bool>  Objects 1 index lget dup xcheck exch type /integertype eq and {    IsGlobal 1 index lget 0 eq {      pop true    } {		% Update Objects from GlobalObjects      DEBUG { (%Global=>local: ) print dup == } if      Objects exch GlobalObjects 1 index get lput false    } ifelse  } {    pop false  } ifelse} bind def/oforce /exec load def/oget {		% <array> <index> oget <object>		% <dict> <key> oget <object>  2 copy get dup xcheck {    exec dup 4 1 roll put  } {    exch pop exch pop  } ifelse} bind def% A null value in a dictionary is equivalent to an omitted key;% we must check for this specially./knownoget {  2 copy .knownget {    dup xcheck {      exec dup 4 1 roll put    } {      exch pop exch pop    } ifelse    dup null eq { pop false } { true } ifelse  } {    pop pop 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 /checkgeneration {  % <object#> <generation#> checkgeneration <object#> <OK>  Generations 2 index lget 1 sub 1 index eq {    pop true  } {    Generations 2 index lget 0 eq {      (Warning: reference to free object: )    } {      (Warning: wrong generation: )    } ifelse print 1 index =only ( ) print =only ( R) = false  } ifelse} bind def/R {		% <object#> <generation#> R <object>  1 index unresolved?    { /resolveR cvx 3 packedarray cvx }    { checkgeneration { Objects exch lget } { pop null } ifelse }   ifelse} 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 unresolved? {    PDFfile fileposition    2 index readxrefentry pop    PDFoffset add PDFfile exch setfileposition  } if  checkgeneration {		% The only global objects we bother to save are		% (resource) dictionaries.    1 index dup gcheck exch type /dicttype eq and {      DEBUG { (%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, we stop at the endobj./resolveopdict mark  valueopdict { } forall  /endobj { endobj exit } bind.dicttomark readonly def/resolveR		% <object#> <generation#> resolveR <object> { DEBUG { (%Resolving: ) print 2 copy 2 array astore == } if   1 index unresolved?    { PDFfile fileposition 3 1 roll      1 index readxrefentry      3 1 roll checkgeneration       {		% Stack: savepos objpos obj#	 exch PDFoffset add PDFfile exch setfileposition	 PDFfile token pop 2 copy ne	  { (xref error!) = /resolveR cvx /rangecheck signalerror	  }	 if pop PDFfile token pop	 PDFfile token pop /obj ne	  { (xref error!) = /resolveR cvx /rangecheck signalerror	  }	 if	 pdf_run_resolve	% PDFfile resolveopdict .pdfrun       }       {		% Don't cache if the generation # is wrong.	 pop pop null       }      ifelse exch PDFfile exch setfileposition    }    { pop Objects exch lget    }   ifelse } bind def       % ================================ Streams ================================ % % We represent a stream by an executable dictionary that contains,% in addition to the contents of the original stream dictionary:%	/File - the file or string where the stream contents are stored,%	  if the stream is not an external one.%	/FilePosition - iff File is a file, the position in the file%	  where the contents start.%	/StreamKey - the key used to decrypt this stream, if any.% We do the real work of constructing the data stream only when the% contents are needed. % Construct a stream.  The length is not reliable in the face of% different end-of-line conventions, but it's all we've got.%% PDF files are inconsistent about what may fall between the 'stream' keyword% and the actual stream data, and it appears that no one algorithm can% detect this reliably.  We used to try to guess whether the file included% extraneous \r and/or \n characters, but we no longer attempt to do so,% especially since the PDF 1.2 specification states flatly that the only% legal terminators following the 'stream' keyword are \n or \r\n, both of% which are properly skipped and discarded by the token operator./stream {	% <dict> stream <modified_dict>  dup /F known dup PDFsource PDFfile eq or {    not {      dup /File PDFfile put      dup /FilePosition PDFfile fileposition put      DEBUG { (%FilePosition: ) print dup /FilePosition get == } if    } if    PDFfile fileposition 1 index /Length oget add      PDFfile exch setfileposition  } {    pop	% We're already reading from a stream, which we can't reposition.	% Capture the sub-stream contents in a string.    dup /Length oget string PDFsource exch readstring    not {      (Unexpected EOF in stream!) =      /stream cvx /rangecheck signalerror    } if    1 index exch /File exch put  } ifelse  PDFsource token pop    /endstream ne { /stream cvx /syntaxerror signalerror } if  cvx} bind def/endstream {  exit} bind def % Contrary to the published PDF (1.3) specification, Acrobat Reader% accepts abbreviated filter names everywhere, not just for in-line images,% and some applications (notably htmldoc) rely on this./unabbrevfilterdict mark  /AHx /ASCIIHexDecode  /A85 /ASCII85Decode  /CCF /CCITTFaxDecode  /DCT /DCTDecode  /Fl /FlateDecode  /LZW /LZWDecode  /RL /RunLengthDecode.dicttomark readonly def % Extract and apply filters./filterparms {		% <dict> <DPkey> <Fkey> filterparms			%   <dict> <parms> <filternames>  2 index exch .knownget {    exch 2 index exch .knownget {		% Both filters and parameters.      exch dup type /nametype eq {	1 array astore exch 1 array astore exch      } if    } {		% Filters, but no parameters.      null exch      dup type /nametype eq { 1 array astore } if    } ifelse  } {		% No filters: ignore parameters, if any.    pop null { }  } ifelse} bind def/filtername {		% <filtername> filtername <filtername'>  //unabbrevfilterdict 1 index .knownget { exch pop } if} bind def

Lines 1–500 of 614.