pdf_base.ps 34 KB

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