<(#)> name#escape
{ 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
( **** Error: Invalid hex following '#' name escape, using literal '#' in name.\n)
pdfformaterror
( Output may be incorrect.\n) pdfformaterror
} {
exch closefile concatstrings
exch 2 1 index length 2 sub getinterval
} ifelse
(#) search { name#escape } if concatstrings
} bind executeonly def
/num-chars-dict mark (0123456789-.) {dup} forall .dicttomark readonly 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 { % .pdftokenerror -
BXlevel 0 le {
( **** Error: Unknown operator: ') pdfformaterror
dup =string cvs pdfformaterror
(') 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, continue.
dup type /nametype eq {
//true 1 index .namestring {
//num-chars-dict exch known and
} forall { % perhaps, it's a malformed number.
PDFSTOPONERROR {//true}{
pop pop pop 0 //false
( looks like a malformed number, replacing with 0.) pdfformaterror
} ifelse
} {
//true % punt
} ifelse
} {
//true % punt
} ifelse
(\n) pdfformaterror
} 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
( Output may be incorrect.\n) pdfformaterror
} bind executeonly def
currentdict /num-chars-dict .undef
/.pdfexectoken { % .pdfexectoken ?
PDFDEBUG {
//pdfdict /PDFSTEPcount known not { //pdfdict /PDFSTEPcount 1 .forceput } executeonly if
PDFSTEP {
//pdfdict /PDFtokencount 2 copy .knownget { 1 add } { 1 } ifelse .forceput
PDFSTEPcount 1 gt {
//pdfdict /PDFSTEPcount PDFSTEPcount 1 sub .forceput
} executeonly
{
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
} executeonly
{
//pdfdict /PDFSTEPcount 1 .forceput
} executeonly ifelse % token
} {
pop /PDFSTEP //false def % EOF on stdin
} ifelse % readline
} ifelse % PDFSTEPcount > 1
} executeonly
{
dup ==only () = flush
} ifelse % PDFSTEP
} executeonly 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
} {
% Hackish fix to detect missing whitespace after "endobj". Yet another
% problem that (you guessed it!) Adobe Acrobat ignores silently
dup .namestring (endobj) anchorsearch {
( **** Error: Missing whitespace after 'endobj'.\n) pdfformaterror
( Output may be incorrect.\n) pdfformaterror
pop pop pop exch pop /endobj get exec
} {
%% First, lets try and see if this 'might' be a broken number
%% we look for 0-9 as well as '.' ',' and '-' to permit those
%% locales in which the separator is a comma, as well as negative
%% numbers. We've seena t least one tool replace '0' with '-' *sometimes*
true exch
dup length 1 sub 0 1 3 -1 roll {
1 index exch get
dup 44 lt {
pop exch pop false exch exit
}{
dup 57 gt {
pop exch pop false exch exit
}{
dup 47 eq {
pop exch pop false exch exit
}{
pop
} ifelse
} ifelse
} ifelse
} for
pop
{
%% If it looks like a number, try to deal with it as such
PDFSTOPONERROR {
dup .pdftokenerror
}{
dup {.pdftokenerror} stopped
} ifelse
{ pop
%% But if it fails, fall back to converting into a anem.
%% This will propagate through and cause different
%% fallback code to try and take care ot if.
cvlit exch pop exch pop
}{
exch pop
} ifelse
}{
%% Doesn't look like a number, convert it into a name
cvlit exch pop exch pop
} ifelse
} ifelse
} ifelse
} ifelse
} bind executeonly odef
/PDFScanRules_true << /PDFScanRules //true >> def
/PDFScanRules_null << /PDFScanRules //null >> def
/.pdfrun { % .pdfrun -
% Construct a procedure with the stack depth, file and opdict
% bound into it.
1 index cvlit % file <<>> file
count 2 sub % file <<>> file cnt
3 1 roll mark % file cnt <<>> file [
/PDFScanRules .getuserparam //null eq {
//PDFScanRules_true { setuserparams } 0 get % force PDF scanning mode
mark 7 4 roll
} {
mark 5 2 roll % file [ [ cnt <<>> file
} ifelse
{ % Stack: ..operands.. count opdict file
{ token } stopped {
dup type /filetype eq { pop } if
pop pop stop
} if {
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
} {
pop pop exit
} ifelse
}
aload pop .packtomark cvx % file [ {cnt <<>> file ... }
{ loop } 0 get 2 packedarray cvx % file [ { {cnt <<>> file ... } loop }
PDFSTOPONERROR { {exec //false} } { {stopped} } ifelse
aload pop % file [ { {cnt <<>> file ... } loop } stopped
/PDFScanRules .getuserparam //null eq {
//PDFScanRules_null { setuserparams } 0 get % reset PDF scannig mode if it was off
} if
/PDFsource PDFsource % file [ { {cnt <<>> file ... } loop } stopped /PDFsource PDFsource
{ store {
/StreamRunAborted //true store
( **** Error reading a content stream. The page may be incomplete.\n)
pdfformaterror
( Output may be incorrect.\n) pdfformaterror
} if
} aload pop % file [ { {cnt <<>> file ... } loop } stopped /PDFsource PDFsource store {...} if
.packtomark cvx % file { { {cnt <<>> file ... } loop } stopped /PDFsource PDFsource store {...} if}
/PDFsource 3 -1 roll store % {...}
exec
} bind executeonly def
% Execute a file, like .pdfrun, for a marking context.
% This temporarily rebinds LocalResources and DefaultQstate.
/.pdfruncontext { % .pdfruncontext -
/.pdfrun load LocalResources DefaultQstate
/LocalResources 7 -1 roll store
/DefaultQstate qstate store
3 .execn
/DefaultQstate exch store
/LocalResources exch store
} bind executeonly 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 pdfemptycount sub
} bind executeonly def
% Read a token, but simply return false (no token read) in the case of an
% error. This is messy because 'token' either may or may not pop its operand
% if an error occurs, and because the return values are different depending
% on whether the source is a file or a string. To avoid closing the file
% check for '{' before trying 'token'.
/token_nofail_dict mark
( ) { dup ( ) readstring pop pop } bind executeonly
(\t) 1 index
(\r) 1 index
(\n) 1 index
(\000) 1 index
({) { //null //true exit } bind executeonly
.dicttomark def
/token_nofail { % token_nofail false
% token_nofail true
% token_nofail true
dup type /filetype eq {
{ dup ( ) .peekstring not { ({) } if
//token_nofail_dict exch .knownget not {
//null 1 index { token } .internalstopped exit
} if
exec
} loop
{ % stack: source null [source]
//null ne { pop } if pop //false
} { % stack: source null ([post] token true | false)
{ 3 1 roll pop pop //true }
{ pop pop //false }
ifelse
} ifelse
} {
//null 1 index % stack: source null source
{ token } .internalstopped { % stack: source null [source]
//null ne { pop } if pop //false
} { % stack: source null ([post] token true | false)
{ 4 2 roll pop pop //true }
{ pop pop //false }
ifelse
} ifelse
} ifelse
} bind executeonly def
currentdict /token_nofail_dict .undef
% ================================ Objects ================================ %
% We keep track of PDF objects using the following PostScript variables:
%
% Generations (string): 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 (array): 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 (array): 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 (string): 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 0 array def
/Objects 0 array def
/Generations 0 string def
.currentglobal //true .setglobal
/GlobalObjects 20 dict def
.setglobal
/IsGlobal 0 string def
} bind executeonly def
% Grow the tables to a specified size.
/growPDFobjects { % growPDFobjects -
dup ObjectStream length gt {
dup ObjectStream exch array dup 3 1 roll copy pop /ObjectStream exch def
} if
dup Objects length gt {
dup Objects exch array dup 3 1 roll copy pop /Objects exch def
} if
dup Generations length gt {
dup Generations exch string dup 3 1 roll copy pop /Generations exch def
} if
dup IsGlobal length gt {
dup IsGlobal exch string dup 3 1 roll copy pop /IsGlobal exch def
} if
pop
} bind executeonly 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? { %