% Copyright (C) 1994, 2000 Aladdin Enterprises. 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_main.ps,v 1.100 2005/09/23 18:21:23 ray Exp $% pdf_main.ps% PDF file- and page-level operations. /.setlanguagelevel where { pop 2 .setlanguagelevel } if.currentglobal true .setglobal/pdfdict where { pop } { /pdfdict 100 dict def } ifelsepdfdict begin % Patch in an obsolete variable used by some third-party software./#? false def % Test whether the current output device handles pdfmark./.writepdfmarkdict 1 dict dup /pdfmark null put readonly def/.writepdfmarks { % - .writepdfmarks <bool> currentdevice //.writepdfmarkdict .getdeviceparams mark eq { false } { pop pop true } ifelse systemdict /DOPDFMARKS known or } bind def % For simplicity, we use a single interpretation dictionary for all% PDF graphics execution, even though this is too liberal./pdfopdict mark objopdict { } forall drawopdict { } forall /endstream { exit } bind (%%EOF) cvn { exit } bind % for filters % PDF 1.1 operators /BX { /BXlevel BXlevel 1 add store } bind /EX { /BXlevel BXlevel 1 sub store } bind /PS { cvx exec } bind % PDF 1.2 operators /BMC { pop } bind /BDC { pop pop } bind /EMC { } /MP { pop } bind /DP { pop pop } bind.dicttomark readonly def % ======================== Main program ======================== % end % pdfdictuserdict begin /defaultfontname /Times-Roman def % Make sure the registered encodings are loaded, so we don't run the risk% that some of the indices for their names will overflow the packed% representation. (Yes, this is a hack.)SymbolEncoding popDingbatsEncoding pop % Redefine 'run' so it recognizes PDF files.systemdict begin/.runps /run load def/run { dup type /filetype ne { (r) file } if % skip leading whitespace characters (actually anything less than or equal to <sp>) { dup ( ) .peekstring not { false exit } if dup 0 get 32 le { pop dup read pop pop } { true exit } ifelse } loop { (%) eq { dup ( ) .peekstring { (%PDF-) eq { dup (%stdin) (r) file eq { % Copy PDF from stdin to temporary file then run it. null (w+) //systemdict /.tempfile get exec exch 3 1 roll % stack: tempname stdin tempfile 64000 string { % stack: tempname stdin tempfile string 2 index 1 index readstring exch 3 index exch writestring not { exit } if } loop pop exch closefile % stack: tempname tempfile dup 0 setfileposition dup runpdf closefile deletefile } { runpdf } ifelse } { cvx .runps % doesn't start with %PDF- } ifelse } { pop cvx .runps % didn't read 5 characters } ifelse } { cvx .runps % didn't start with % } ifelse } { pop closefile % file was empty } ifelse} bind odefcurrentdict /runpdfstring .undef /runpdfbegin { % <file> runpdf - userdict begin % It turns out that the PDF interpreter uses memory more % effectively if it is run under at least one level of save. % This is counter-intuitive, and we don't understand why it happens, % but the improvement is significant. /PDFTopSave save def 0 setobjectformat /Page# null def /Page null def /DSCPageCount 0 def /PDFSave null def GS_PDF_ProcSet begin pdfdict begin pdfopen begin Trailer /Root oget /Pages oget /CropBox knownoget { oforce_array normrect mark /CropBox 3 -1 roll /PAGES pdfmark } if /FirstPage where { pop FirstPage dup pdfpagecount gt { (\nRequested FirstPage is greater than the number of pages in the file: ) print pdfpagecount = flush } if } { 1 } ifelse /LastPage where { pop LastPage pdfpagecount .min } { pdfpagecount } ifelse 1 index 1 index gt { ( No pages will be processed \(FirstPage > LastPage\).) = flush } { QUIET not { (Processing pages ) print 1 index =only ( through ) print dup =only (.) = flush } if } ifelse} bind def /dopdfpages { % firstpage# lastpage# dopdfpages - << /PDFScanRules true >> setuserparams % set scanning rules for PDF vs. PS 1 exch { dup /Page# exch store QUIET not { (Page ) print dup == flush } if pdfgetpage pdfshowpage } for << /PDFScanRules null >> setuserparams % restore scanning rules for PS} bind def /runpdfend { Repaired { printrepaired } if currentdict pdfclose end % temporary dict end % pdfdict end % GS_PDF_ProcSet PDFTopSave restore end % userdict} bind def /runpdf { % <file> runpdf - runpdfbegin dopdfpages runpdfend} bind def end % systemdict% Redefine the procedure that the C code uses for running piped input.% It is OK to use { (%stdin) run } here, because a startjob cannot occur./.runstdin { { (%stdin) run } execute0} bind def end % userdictpdfdict begin % ======================== File parsing ======================== % % Read the cross-reference and trailer sections. /traileropdict mark (<<) cvn { mark } bind (>>) cvn { { .dicttomark } stopped { ( **** File has unbalanced >> in trailer.\n) pdfformaterror } if } bind ([) cvn { mark } bind % ditto (]) cvn dup load% /true true % see .pdfexectoken in pdf_base.ps% /false false % ibid.% /null null % ibid. /R { /resolveR cvx 3 packedarray cvx } bind % see Objects below /startxref /exit load.dicttomark readonly def % Because of EOL conversion, lines with fixed contents might be followed% by one or more blanks./lineeq % <filestr> <conststr> lineeq <bool> { anchorsearch { pop { ( ) anchorsearch not { () eq exit } if pop } loop } { pop false } ifelse } bind def/linene { lineeq not } bind def % Read original version (pre PDF 1.5) of the xref table. % Note: The position is the location of 'xref'. The current PDFfile % position is just after the 'XREF'./readorigxref % <pos> readorigxref <trailerdict> { pop % We do not need the position. 0 % Initialize xref table error counter { PDFfile token pop % first object # or trailer dup /trailer eq { pop exit } if PDFfile pdfstring readline pop token pop % entry count % remaining must be whitespace only (otherwise this xref Size was invalid. exch dup length 0 ne { false 1 index { 32 gt { pop true exit } if } forall { ( **** Warning: xref subsection header has extra characters.\n) pdfformaterror /setxrefentry cvx /syntaxerror signalerror } if } if pop % remove last % This section might be adding new objects: % ensure that Objects and Generations are big enough. % stack: <err count> <first obj> <entry count> 2 copy add growPDFobjects { % stack: <err count> <obj num> % Read xref line PDFfile 20 string readstring pop % always read 20 chars. token pop % object position exch token pop % generation # exch token pop % n or f exch % stack: <err count> <obj#> <loc> <gen#> <tag> <remainder of line> dup length 0 ne { % check to make sure trailing garbage is just white space dup { 32 gt { 5 -1 roll 1 add 5 1 roll } if } forall % bump error count on garbage } if pop % Stack: <err count> <obj#> <loc> <gen#> <tag> dup /n eq { % xref line tag is /n pop % pop dup of line tag Objects 3 index lget null eq { % later update might have set it 0 3 1 roll % Set ObjectStream object number = 0 setxrefentry % Save xref entry 3 -1 roll pop % Remove ObjectStream object onumber } if } { % xref line tag was not /n /f ne % verify that the tag was /f { /setxrefentry cvx /syntaxerror signalerror } if } ifelse pop pop % pop <obj location> and <gen num> % stack: <err count> <obj num> 1 add % increment object number } repeat pop % pop <obj #> } loop 0 ne { ( **** Warning: length of some xref entries is not equal to 20 bytes.\n) pdfformaterror } if PDFfile traileropdict .pdfrun } bind def % This dicitonary is used to read the xref dictionary. It should work for % reading any dictionary. dictlevelcount must contain 0./xrefopdict mark (<<) cvn { /dictlevelcount dictlevelcount 1 add def mark } bind (>>) cvn { .dicttomark /dictlevelcount dictlevelcount 1 sub def dictlevelcount 0 eq { exit} if } bind ([) cvn { mark } bind % ditto (]) cvn dup load% /true true % see .pdfexectoken in pdf_base.ps% /false false % ibid.% /null null % ibid. /R { /resolveR cvx 3 packedarray cvx } bind % see Objects below.dicttomark readonly def % Get a variable length positive integer value from a stream. A value% of zero is returned if the count is zero./getintn { % <stream> <count> getintn int 0 exch { 256 mul 1 index read pop add } repeat exch pop % Discard stream} bind def % This array contains handlers for processing the different types of% entries in the XRef stream.% Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>% <field 2> <field 3>% The handlers leave the stack unchanged./xref15entryhandlers [ { % XRef entry type 0 - free or f type xref entry% (free ) print% (obj num: ) print 2 index pdfstring cvs print ( ) print% (loc: ) print 1 index pdfstring cvs print ( ) print% (gen: ) print dup === flush } bind % Do nothing for free xref entries % XRef entry type 1 - normal or n type xref entry { % field 2 = obj loc, field 3 = gen num% (normal ) print% (obj num: ) print 2 index pdfstring cvs print ( ) print% (loc: ) print 1 index pdfstring cvs print ( ) print% (gen: ) print dup === flush 0 3 1 roll % set stream number = 0 setxrefentry 3 -1 roll pop % remove stream number } bind % XRef entry type 2 - compressed object type xref entry { % field 2 = object stream num, field 3 = index into object stream% (Compressed objects: ) print% (obj num: ) print 2 index pdfstring cvs print ( ) print% (field 2: ) print 1 index pdfstring cvs print ( ) print% (field 3: ) print dup === flush 0 setxrefentry pop % set generation number = 0 } bind] def % Read the PDF 1.5 version of the xref table. % Note: The position is the location of the start of the dictionary object % In PDF 1.5, the XRef dictionary also serves as the trailer dictionary/readpdf15xref % <pos> readpdf15xref <trailerdict> { PDFfile exch setfileposition % move to start of object % Get object number, revision, and 'obj' and discard PDFfile token pop pop PDFfile token pop pop PDFfile token pop pop % Get the XRef dicitionary /dictlevelcount 0 def PDFfile xrefopdict .pdfrun % Verify that we have an XRef dictionary dup /Type get /XRef ne { /readpdf15xref cvx /syntaxerror signalerror } if % Ensure that we we have room in the objects array, etc. dup /Size get growPDFobjects % Create a stream for the XRef data PDFfile token pop pop % Skip over 'stream' dup stream false resolvestream % Stack: <XRefdict> <xref stream> % The Index array defines the ranges of object numbers in the % XRef stream. Each value pair is consists of starting object % number and the count of consecutive objects. % Get the Index array, if present 1 index /Index .knownget not { % If no Index array ... [ 0 3 index /Size get ] % Default = [ 0 Size ] } if % Loop through the Index array 0 2 2 index length 1 sub { % Get start and end of object range 2 copy get % Start of the range dup 3 index 3 index 1 add get % Number of entries in range % Loop through the range of object numbers add 1 sub 1 exch { % Form end of range, set increment = 1 % Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num> % Get xref parameters. Note: The number of bytes for each parameter % is defined by the entries in the W array. 4 index /W get aload pop % Get W array values % The first field indicates type of entry. Get first field value. % If the num. of bytes for field 1 is 0 then default field value is 1 3 -1 roll dup 0 eq { pop 1 } { 6 index exch getintn } ifelse % Get the handler for the xref entry type. We will execute the % handler after we get the other two field values. xref15entryhandlers exch get 3 -1 roll 6 index exch getintn % Get second field 3 -1 roll 6 index exch getintn % Get third field 3 -1 roll exec % Execute Xref entry handler pop pop pop % Remove field values and obj num } for % Loop through Xref entries pop % Remove Index array pair loc } for % Loop through Index array entries pop pop % Remove Index array and xref stream } bind def % Read the cross-reference table.% <pos> is the position either from the startxref statement or the /Prev% entry in the prior trailer dictionary./readxref % <pos> readxref <trailerdict> { PDFoffset add PDFfile exch setfileposition % In some PDF files, this position actually points to % white space before the xref line. Skip over this here. { PDFfile fileposition PDFfile read pop 32 gt { exit } if pop } loop dup % Make copy of the file position (before last char was read). PDFfile exch setfileposition % The PDF specification says that the 'xref' must be on a line % by itself. The code here formerly used readline and linene to % check this. However, Acrobat Reader only requires the line to % begin with 'xref', and there are enough applications producing % non-compliant PDF files that we have to do this too. PDFfile pdfstring 0 4 getinterval readstring pop (xref) eq { readorigxref } % 'xref' -> original xref table { readpdf15xref } % otherwise assume PDF 1.5 xref stream ifelse } bind def % Open a PDF file and read the header, trailer, and cross-reference./pdfopen { % <file> pdfopen <dict> % Color space substitution in PDF is handled somewhat differently % than in PostScript. A given device color space will be substituted % if the corresponding "Default..." entry exists in the Page's % Resource dictionary (which might be inhereted); there is no % UseCIEColor to enable/disable color mapping. % % This behavior is achieved by always setting UseCIEColor to true % in the page device dictionary. If the value of this parameter was % originally false (i.e.: the output device does not perform color % space substitution by default), the instances DefaultGray, % DefaultRGB, and DefaultCMYK of the (local) ColorSpace category % are redefined to be DeviceGray, DeviceRGB, and DeviceCMYK, % respectively. This is not done if UseCIEColor is true by default, % as in that case color substitution is presumably desired even % if the file does not request it. currentpagedevice /UseCIEColor .knownget dup { pop } if not { .currentglobal false .setglobal /DefaultGray { /DeviceGray } cvlit /ColorSpace defineresource pop /DefaultRGB { /DeviceRGB } cvlit /ColorSpace defineresource pop /DefaultCMYK { /DeviceCMYK } cvlit /ColorSpace defineresource pop .setglobal } if pdfopenfile begin pdfopencache .writepdfmarks { % Copy bookmarks (outline) to the output. Trailer /Root oget /Outlines knownoget { /First knownoget { { dup writeoutline /Next knownoget not { exit } if } loop } if } if } if % end .writepdfmarks currentdict end} bind def % Verify that each entry in the xref table is pointing at an object with% the correct object number and generation number./verify_xref % - verify_xref -{ 1 1 Objects llength 1 sub % stack: 1 1 <number of objects - 1> { % Check if the object is free (i.e. not used). The values in % Generations is the generation number plus 1. If the value in % Generations is zero then the object is free. Generations 1 index lget % Get the genration number 0 ne { % Skip if object number is free ObjectStream 1 index lget % Check if object is in objectstream 0 eq { % We only check objects not in an objectstream { % Use stop context since we may get an error if object is invalid dup Objects exch lget % Get the object location PDFoffset add PDFfile exch setfileposition true % Stack: <obj num> <true> PDFfile token pop % Read object number from file 2 index eq { % Verify object number PDFfile token pop % Read generation number from file Generations 3 index % Get specified generaton number lget 1 sub % Gen numbs are stored with 1 added. eq { % Verify generation number PDFfile token pop /obj eq { % Verify 'obj' text pop false % We have valid object, do not rebuild } if } if } if } .internalstopped { true } if % If we stop then we need to rebuild { ( **** Warning: File has an invalid xref entry: ) pdfformaterror pdfstring cvs pdfformaterror (. Rebuilding xref table.\n) pdfformaterror search_objects exit } if % If the entry is invalid } if % If not in an object stream } if % If object entry is not free pop % Remove object number } for} bind odef /pdfopencache { % - pdfopencache - % Create and initialize some caches. /PageCount pdfpagecount def /PageNumbers PageCount 65534 .min dict def /PageIndex PageCount 65534 .min array defLines 1–500 of 1337. Load more
% Copyright (C) 1994, 2000 Aladdin Enterprises. 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_main.ps,v 1.100 2005/09/23 18:21:23 ray Exp $ % pdf_main.ps % PDF file- and page-level operations. /.setlanguagelevel where { pop 2 .setlanguagelevel } if .currentglobal true .setglobal /pdfdict where { pop } { /pdfdict 100 dict def } ifelse pdfdict begin % Patch in an obsolete variable used by some third-party software. /#? false def % Test whether the current output device handles pdfmark. /.writepdfmarkdict 1 dict dup /pdfmark null put readonly def /.writepdfmarks { % - .writepdfmarks <bool> currentdevice //.writepdfmarkdict .getdeviceparams mark eq { false } { pop pop true } ifelse systemdict /DOPDFMARKS known or } bind def % For simplicity, we use a single interpretation dictionary for all % PDF graphics execution, even though this is too liberal. /pdfopdict mark objopdict { } forall drawopdict { } forall /endstream { exit } bind (%%EOF) cvn { exit } bind % for filters % PDF 1.1 operators /BX { /BXlevel BXlevel 1 add store } bind /EX { /BXlevel BXlevel 1 sub store } bind /PS { cvx exec } bind % PDF 1.2 operators /BMC { pop } bind /BDC { pop pop } bind /EMC { } /MP { pop } bind /DP { pop pop } bind .dicttomark readonly def % ======================== Main program ======================== % end % pdfdict userdict begin /defaultfontname /Times-Roman def % Make sure the registered encodings are loaded, so we don't run the risk % that some of the indices for their names will overflow the packed % representation. (Yes, this is a hack.) SymbolEncoding pop DingbatsEncoding pop % Redefine 'run' so it recognizes PDF files. systemdict begin /.runps /run load def /run { dup type /filetype ne { (r) file } if % skip leading whitespace characters (actually anything less than or equal to <sp>) { dup ( ) .peekstring not { false exit } if dup 0 get 32 le { pop dup read pop pop } { true exit } ifelse } loop { (%) eq { dup ( ) .peekstring { (%PDF-) eq { dup (%stdin) (r) file eq { % Copy PDF from stdin to temporary file then run it. null (w+) //systemdict /.tempfile get exec exch 3 1 roll % stack: tempname stdin tempfile 64000 string { % stack: tempname stdin tempfile string 2 index 1 index readstring exch 3 index exch writestring not { exit } if } loop pop exch closefile % stack: tempname tempfile dup 0 setfileposition dup runpdf closefile deletefile } { runpdf } ifelse } { cvx .runps % doesn't start with %PDF- } ifelse } { pop cvx .runps % didn't read 5 characters } ifelse } { cvx .runps % didn't start with % } ifelse } { pop closefile % file was empty } ifelse } bind odef currentdict /runpdfstring .undef /runpdfbegin { % <file> runpdf - userdict begin % It turns out that the PDF interpreter uses memory more % effectively if it is run under at least one level of save. % This is counter-intuitive, and we don't understand why it happens, % but the improvement is significant. /PDFTopSave save def 0 setobjectformat /Page# null def /Page null def /DSCPageCount 0 def /PDFSave null def GS_PDF_ProcSet begin pdfdict begin pdfopen begin Trailer /Root oget /Pages oget /CropBox knownoget { oforce_array normrect mark /CropBox 3 -1 roll /PAGES pdfmark } if /FirstPage where { pop FirstPage dup pdfpagecount gt { (\nRequested FirstPage is greater than the number of pages in the file: ) print pdfpagecount = flush } if } { 1 } ifelse /LastPage where { pop LastPage pdfpagecount .min } { pdfpagecount } ifelse 1 index 1 index gt { ( No pages will be processed \(FirstPage > LastPage\).) = flush } { QUIET not { (Processing pages ) print 1 index =only ( through ) print dup =only (.) = flush } if } ifelse } bind def /dopdfpages { % firstpage# lastpage# dopdfpages - << /PDFScanRules true >> setuserparams % set scanning rules for PDF vs. PS 1 exch { dup /Page# exch store QUIET not { (Page ) print dup == flush } if pdfgetpage pdfshowpage } for << /PDFScanRules null >> setuserparams % restore scanning rules for PS } bind def /runpdfend { Repaired { printrepaired } if currentdict pdfclose end % temporary dict end % pdfdict end % GS_PDF_ProcSet PDFTopSave restore end % userdict } bind def /runpdf { % <file> runpdf - runpdfbegin dopdfpages runpdfend } bind def end % systemdict % Redefine the procedure that the C code uses for running piped input. % It is OK to use { (%stdin) run } here, because a startjob cannot occur. /.runstdin { { (%stdin) run } execute0 } bind def end % userdict pdfdict begin % ======================== File parsing ======================== % % Read the cross-reference and trailer sections. /traileropdict mark (<<) cvn { mark } bind (>>) cvn { { .dicttomark } stopped { ( **** File has unbalanced >> in trailer.\n) pdfformaterror } if } bind ([) cvn { mark } bind % ditto (]) cvn dup load % /true true % see .pdfexectoken in pdf_base.ps % /false false % ibid. % /null null % ibid. /R { /resolveR cvx 3 packedarray cvx } bind % see Objects below /startxref /exit load .dicttomark readonly def % Because of EOL conversion, lines with fixed contents might be followed % by one or more blanks. /lineeq % <filestr> <conststr> lineeq <bool> { anchorsearch { pop { ( ) anchorsearch not { () eq exit } if pop } loop } { pop false } ifelse } bind def /linene { lineeq not } bind def % Read original version (pre PDF 1.5) of the xref table. % Note: The position is the location of 'xref'. The current PDFfile % position is just after the 'XREF'. /readorigxref % <pos> readorigxref <trailerdict> { pop % We do not need the position. 0 % Initialize xref table error counter { PDFfile token pop % first object # or trailer dup /trailer eq { pop exit } if PDFfile pdfstring readline pop token pop % entry count % remaining must be whitespace only (otherwise this xref Size was invalid. exch dup length 0 ne { false 1 index { 32 gt { pop true exit } if } forall { ( **** Warning: xref subsection header has extra characters.\n) pdfformaterror /setxrefentry cvx /syntaxerror signalerror } if } if pop % remove last % This section might be adding new objects: % ensure that Objects and Generations are big enough. % stack: <err count> <first obj> <entry count> 2 copy add growPDFobjects { % stack: <err count> <obj num> % Read xref line PDFfile 20 string readstring pop % always read 20 chars. token pop % object position exch token pop % generation # exch token pop % n or f exch % stack: <err count> <obj#> <loc> <gen#> <tag> <remainder of line> dup length 0 ne { % check to make sure trailing garbage is just white space dup { 32 gt { 5 -1 roll 1 add 5 1 roll } if } forall % bump error count on garbage } if pop % Stack: <err count> <obj#> <loc> <gen#> <tag> dup /n eq { % xref line tag is /n pop % pop dup of line tag Objects 3 index lget null eq { % later update might have set it 0 3 1 roll % Set ObjectStream object number = 0 setxrefentry % Save xref entry 3 -1 roll pop % Remove ObjectStream object onumber } if } { % xref line tag was not /n /f ne % verify that the tag was /f { /setxrefentry cvx /syntaxerror signalerror } if } ifelse pop pop % pop <obj location> and <gen num> % stack: <err count> <obj num> 1 add % increment object number } repeat pop % pop <obj #> } loop 0 ne { ( **** Warning: length of some xref entries is not equal to 20 bytes.\n) pdfformaterror } if PDFfile traileropdict .pdfrun } bind def % This dicitonary is used to read the xref dictionary. It should work for % reading any dictionary. dictlevelcount must contain 0. /xrefopdict mark (<<) cvn { /dictlevelcount dictlevelcount 1 add def mark } bind (>>) cvn { .dicttomark /dictlevelcount dictlevelcount 1 sub def dictlevelcount 0 eq { exit} if } bind ([) cvn { mark } bind % ditto (]) cvn dup load % /true true % see .pdfexectoken in pdf_base.ps % /false false % ibid. % /null null % ibid. /R { /resolveR cvx 3 packedarray cvx } bind % see Objects below .dicttomark readonly def % Get a variable length positive integer value from a stream. A value % of zero is returned if the count is zero. /getintn { % <stream> <count> getintn int 0 exch { 256 mul 1 index read pop add } repeat exch pop % Discard stream } bind def % This array contains handlers for processing the different types of % entries in the XRef stream. % Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num> % <field 2> <field 3> % The handlers leave the stack unchanged. /xref15entryhandlers [ { % XRef entry type 0 - free or f type xref entry % (free ) print % (obj num: ) print 2 index pdfstring cvs print ( ) print % (loc: ) print 1 index pdfstring cvs print ( ) print % (gen: ) print dup === flush } bind % Do nothing for free xref entries % XRef entry type 1 - normal or n type xref entry { % field 2 = obj loc, field 3 = gen num % (normal ) print % (obj num: ) print 2 index pdfstring cvs print ( ) print % (loc: ) print 1 index pdfstring cvs print ( ) print % (gen: ) print dup === flush 0 3 1 roll % set stream number = 0 setxrefentry 3 -1 roll pop % remove stream number } bind % XRef entry type 2 - compressed object type xref entry { % field 2 = object stream num, field 3 = index into object stream % (Compressed objects: ) print % (obj num: ) print 2 index pdfstring cvs print ( ) print % (field 2: ) print 1 index pdfstring cvs print ( ) print % (field 3: ) print dup === flush 0 setxrefentry pop % set generation number = 0 } bind ] def % Read the PDF 1.5 version of the xref table. % Note: The position is the location of the start of the dictionary object % In PDF 1.5, the XRef dictionary also serves as the trailer dictionary /readpdf15xref % <pos> readpdf15xref <trailerdict> { PDFfile exch setfileposition % move to start of object % Get object number, revision, and 'obj' and discard PDFfile token pop pop PDFfile token pop pop PDFfile token pop pop % Get the XRef dicitionary /dictlevelcount 0 def PDFfile xrefopdict .pdfrun % Verify that we have an XRef dictionary dup /Type get /XRef ne { /readpdf15xref cvx /syntaxerror signalerror } if % Ensure that we we have room in the objects array, etc. dup /Size get growPDFobjects % Create a stream for the XRef data PDFfile token pop pop % Skip over 'stream' dup stream false resolvestream % Stack: <XRefdict> <xref stream> % The Index array defines the ranges of object numbers in the % XRef stream. Each value pair is consists of starting object % number and the count of consecutive objects. % Get the Index array, if present 1 index /Index .knownget not { % If no Index array ... [ 0 3 index /Size get ] % Default = [ 0 Size ] } if % Loop through the Index array 0 2 2 index length 1 sub { % Get start and end of object range 2 copy get % Start of the range dup 3 index 3 index 1 add get % Number of entries in range % Loop through the range of object numbers add 1 sub 1 exch { % Form end of range, set increment = 1 % Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num> % Get xref parameters. Note: The number of bytes for each parameter % is defined by the entries in the W array. 4 index /W get aload pop % Get W array values % The first field indicates type of entry. Get first field value. % If the num. of bytes for field 1 is 0 then default field value is 1 3 -1 roll dup 0 eq { pop 1 } { 6 index exch getintn } ifelse % Get the handler for the xref entry type. We will execute the % handler after we get the other two field values. xref15entryhandlers exch get 3 -1 roll 6 index exch getintn % Get second field 3 -1 roll 6 index exch getintn % Get third field 3 -1 roll exec % Execute Xref entry handler pop pop pop % Remove field values and obj num } for % Loop through Xref entries pop % Remove Index array pair loc } for % Loop through Index array entries pop pop % Remove Index array and xref stream } bind def % Read the cross-reference table. % <pos> is the position either from the startxref statement or the /Prev % entry in the prior trailer dictionary. /readxref % <pos> readxref <trailerdict> { PDFoffset add PDFfile exch setfileposition % In some PDF files, this position actually points to % white space before the xref line. Skip over this here. { PDFfile fileposition PDFfile read pop 32 gt { exit } if pop } loop dup % Make copy of the file position (before last char was read). PDFfile exch setfileposition % The PDF specification says that the 'xref' must be on a line % by itself. The code here formerly used readline and linene to % check this. However, Acrobat Reader only requires the line to % begin with 'xref', and there are enough applications producing % non-compliant PDF files that we have to do this too. PDFfile pdfstring 0 4 getinterval readstring pop (xref) eq { readorigxref } % 'xref' -> original xref table { readpdf15xref } % otherwise assume PDF 1.5 xref stream ifelse } bind def % Open a PDF file and read the header, trailer, and cross-reference. /pdfopen { % <file> pdfopen <dict> % Color space substitution in PDF is handled somewhat differently % than in PostScript. A given device color space will be substituted % if the corresponding "Default..." entry exists in the Page's % Resource dictionary (which might be inhereted); there is no % UseCIEColor to enable/disable color mapping. % % This behavior is achieved by always setting UseCIEColor to true % in the page device dictionary. If the value of this parameter was % originally false (i.e.: the output device does not perform color % space substitution by default), the instances DefaultGray, % DefaultRGB, and DefaultCMYK of the (local) ColorSpace category % are redefined to be DeviceGray, DeviceRGB, and DeviceCMYK, % respectively. This is not done if UseCIEColor is true by default, % as in that case color substitution is presumably desired even % if the file does not request it. currentpagedevice /UseCIEColor .knownget dup { pop } if not { .currentglobal false .setglobal /DefaultGray { /DeviceGray } cvlit /ColorSpace defineresource pop /DefaultRGB { /DeviceRGB } cvlit /ColorSpace defineresource pop /DefaultCMYK { /DeviceCMYK } cvlit /ColorSpace defineresource pop .setglobal } if pdfopenfile begin pdfopencache .writepdfmarks { % Copy bookmarks (outline) to the output. Trailer /Root oget /Outlines knownoget { /First knownoget { { dup writeoutline /Next knownoget not { exit } if } loop } if } if } if % end .writepdfmarks currentdict end } bind def % Verify that each entry in the xref table is pointing at an object with % the correct object number and generation number. /verify_xref % - verify_xref - { 1 1 Objects llength 1 sub % stack: 1 1 <number of objects - 1> { % Check if the object is free (i.e. not used). The values in % Generations is the generation number plus 1. If the value in % Generations is zero then the object is free. Generations 1 index lget % Get the genration number 0 ne { % Skip if object number is free ObjectStream 1 index lget % Check if object is in objectstream 0 eq { % We only check objects not in an objectstream { % Use stop context since we may get an error if object is invalid dup Objects exch lget % Get the object location PDFoffset add PDFfile exch setfileposition true % Stack: <obj num> <true> PDFfile token pop % Read object number from file 2 index eq { % Verify object number PDFfile token pop % Read generation number from file Generations 3 index % Get specified generaton number lget 1 sub % Gen numbs are stored with 1 added. eq { % Verify generation number PDFfile token pop /obj eq { % Verify 'obj' text pop false % We have valid object, do not rebuild } if } if } if } .internalstopped { true } if % If we stop then we need to rebuild { ( **** Warning: File has an invalid xref entry: ) pdfformaterror pdfstring cvs pdfformaterror (. Rebuilding xref table.\n) pdfformaterror search_objects exit } if % If the entry is invalid } if % If not in an object stream } if % If object entry is not free pop % Remove object number } for } bind odef /pdfopencache { % - pdfopencache - % Create and initialize some caches. /PageCount pdfpagecount def /PageNumbers PageCount 65534 .min dict def /PageIndex PageCount 65534 .min array def