@poe-platform/safe-bash 0.1.811 → 0.1.813

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/dist/audio-ast/id3-source.d.ts +27 -0
  2. package/dist/audio-ast/index.d.ts +5 -0
  3. package/dist/audio-ast/index.js +1001 -596
  4. package/dist/audio-ast/mp3-source.d.ts +18 -0
  5. package/dist/audio-ast/ogg-source.d.ts +25 -0
  6. package/dist/audio-ast/ogg-stream-source.d.ts +22 -0
  7. package/dist/audio-ast/vorbis.d.ts +14 -0
  8. package/dist/image-ast/index.js +139 -9
  9. package/dist/mp4-ast/containers/adapters.d.ts +7 -0
  10. package/dist/office-xml/retained-xml-document.d.ts +8 -0
  11. package/dist/pdf-ast/ast.d.ts +2 -0
  12. package/dist/pdf-ast/content/dictionary-cursor.d.ts +15 -0
  13. package/dist/pdf-ast/content/range-operator-parser.d.ts +4 -0
  14. package/dist/pdf-ast/content/stored-dictionary.d.ts +10 -0
  15. package/dist/pdf-ast/cos/lexer.d.ts +8 -5
  16. package/dist/pdf-ast/cos/object-reader.d.ts +4 -3
  17. package/dist/pdf-ast/cos/range-parser.d.ts +4 -0
  18. package/dist/pdf-ast/cos/retained-objects.d.ts +1 -0
  19. package/dist/pdf-ast/cos/retained-writer.d.ts +1 -0
  20. package/dist/pdf-ast/cos/value-parser.d.ts +32 -2
  21. package/dist/pdf-ast/edit/retained-append-attachments.d.ts +13 -0
  22. package/dist/pdf-ast/edit/retained-bookmarks.d.ts +13 -0
  23. package/dist/pdf-ast/edit/retained-graph.d.ts +6 -0
  24. package/dist/pdf-ast/edit/retained-save.d.ts +2 -0
  25. package/dist/pdf-ast/edit/retained-stamps.d.ts +9 -0
  26. package/dist/pdf-ast/extract/retained-form-field-details.d.ts +20 -0
  27. package/dist/pdf-ast/extract/retained-form-fields.d.ts +17 -4
  28. package/dist/pdf-ast/fonts/resolve.d.ts +3 -1
  29. package/dist/pdf-ast/index.d.ts +4 -1
  30. package/dist/pdf-ast/index.js +2127 -975
  31. package/dist/pdf-ast/retained-document.d.ts +4 -0
  32. package/dist/safe-bash/audio-ast.browser.js +7 -1
  33. package/dist/safe-bash/chunks/{chunk-HHSOUC3Z.js → chunk-HPQE675Q.js} +1 -1
  34. package/dist/safe-bash/chunks/{chunk-BUYRKFW2.js → chunk-I6ECNJMR.js} +1 -1
  35. package/dist/safe-bash/chunks/{pdftk-WRYEP3CA.js → pdftk-Y2TX74LY.js} +2 -1
  36. package/dist/safe-bash/command-chunks/biff-4ALVARRF-7SRX6R6N.js +5192 -0
  37. package/dist/safe-bash/command-chunks/{chunk-EHSM5ZQS.js → chunk-2DGJOOXM.js} +8 -8
  38. package/dist/safe-bash/command-chunks/{chunk-Q6S57NOQ.js → chunk-2E2H7MBH.js} +7 -7
  39. package/dist/safe-bash/command-chunks/{chunk-MMBZTYXO.js → chunk-2PQRZDNR.js} +221 -0
  40. package/dist/safe-bash/command-chunks/{chunk-5OO2P27R.js → chunk-2V6FOLXV.js} +78 -25
  41. package/dist/safe-bash/command-chunks/{chunk-56NYSX65.js → chunk-2Z3WRRFT.js} +9 -9
  42. package/dist/safe-bash/command-chunks/chunk-3D24WDND.js +63 -0
  43. package/dist/safe-bash/command-chunks/{chunk-47NEG4UO.js → chunk-3JST2Q7G.js} +219 -43
  44. package/dist/safe-bash/command-chunks/{chunk-WGG6G2KG.js → chunk-3LJAXFH5.js} +7 -7
  45. package/dist/safe-bash/command-chunks/{chunk-AHA6IWAJ.js → chunk-3TYDSGAH.js} +6 -6
  46. package/dist/safe-bash/command-chunks/{chunk-YSMNXMAO.js → chunk-3Y4XZB24.js} +4 -4
  47. package/dist/safe-bash/command-chunks/{chunk-ZIIO6GRY.js → chunk-4PBNMKAT.js} +7 -7
  48. package/dist/safe-bash/command-chunks/{chunk-JFYWVQ4V.js → chunk-4Z6W5EOC.js} +8 -8
  49. package/dist/safe-bash/command-chunks/{chunk-GEM47B2P.js → chunk-57DDYKE5.js} +7 -7
  50. package/dist/safe-bash/command-chunks/{chunk-HARUYHH7.js → chunk-5HUICAWD.js} +1 -1
  51. package/dist/safe-bash/command-chunks/{chunk-4CKFNXRN.js → chunk-5IFRAI7Y.js} +1 -1
  52. package/dist/safe-bash/command-chunks/{chunk-RHYJVTJO.js → chunk-5KGEZ3RW.js} +2 -2
  53. package/dist/safe-bash/command-chunks/{chunk-A5FZBR7X.js → chunk-5MFDRSGG.js} +4 -4
  54. package/dist/safe-bash/command-chunks/{chunk-7GKKMNL6.js → chunk-5P6I2T63.js} +8 -8
  55. package/dist/safe-bash/command-chunks/{chunk-6M6TM5Z5.js → chunk-5VQVZPP3.js} +3 -3
  56. package/dist/safe-bash/command-chunks/{chunk-MIRL7HTF.js → chunk-6244HYJY.js} +1 -1
  57. package/dist/safe-bash/command-chunks/chunk-63EMPQ7Z.js +115 -0
  58. package/dist/safe-bash/command-chunks/{chunk-XRVKWGVQ.js → chunk-6CY5BHBS.js} +6 -6
  59. package/dist/safe-bash/command-chunks/{chunk-XVP6V5K3.js → chunk-6IWE7PTK.js} +6 -6
  60. package/dist/safe-bash/command-chunks/{chunk-6QBMND4A.js → chunk-6SRHWVEB.js} +1 -1
  61. package/dist/safe-bash/command-chunks/chunk-6ZHQB453.js +35 -0
  62. package/dist/safe-bash/command-chunks/chunk-73NYFNAS.js +173 -0
  63. package/dist/safe-bash/command-chunks/{chunk-VU3EQF7F.js → chunk-7NXTEWPR.js} +229 -75
  64. package/dist/safe-bash/command-chunks/{chunk-554Z6IKP.js → chunk-7PRL6RJ6.js} +2 -2
  65. package/dist/safe-bash/command-chunks/{chunk-SDTPO2VV.js → chunk-7PZHWMK6.js} +7 -7
  66. package/dist/safe-bash/command-chunks/{chunk-XZ2FWFNV.js → chunk-7QZ2HP2F.js} +6 -6
  67. package/dist/safe-bash/command-chunks/{chunk-OEJM666F.js → chunk-7UC2Q6Z6.js} +5 -5
  68. package/dist/safe-bash/command-chunks/{chunk-COKYZUBW.js → chunk-AJI55RS7.js} +1 -1
  69. package/dist/safe-bash/command-chunks/{chunk-2VCKUNDZ.js → chunk-B2C3UPJS.js} +27 -17
  70. package/dist/safe-bash/command-chunks/{chunk-WXRYDALR.js → chunk-BBAB7LC4.js} +4 -4
  71. package/dist/safe-bash/command-chunks/{chunk-QYMEASQ6.js → chunk-BEHUSUOY.js} +4 -4
  72. package/dist/safe-bash/command-chunks/{chunk-Z2JW6M2D.js → chunk-BK7ISUJL.js} +3 -3
  73. package/dist/safe-bash/command-chunks/{chunk-33YCKZZX.js → chunk-C5KLFZGT.js} +6 -6
  74. package/dist/safe-bash/command-chunks/{chunk-TVH4JORU.js → chunk-C5QDEB3I.js} +3 -3
  75. package/dist/safe-bash/command-chunks/{chunk-N4R2SHSS.js → chunk-CCZZVCHX.js} +2 -2
  76. package/dist/safe-bash/command-chunks/{chunk-2VLAXKTS.js → chunk-CTDC4LJT.js} +121 -85
  77. package/dist/safe-bash/command-chunks/{chunk-S6R3IB36.js → chunk-D55REQA3.js} +1 -1
  78. package/dist/safe-bash/command-chunks/{chunk-Y4EYCZFT.js → chunk-D6WJY6QO.js} +10 -10
  79. package/dist/safe-bash/command-chunks/{chunk-2CORNDGF.js → chunk-DBLHCJJU.js} +2 -2
  80. package/dist/safe-bash/command-chunks/{chunk-SPW4GW4Z.js → chunk-DFI7QF3M.js} +2 -2
  81. package/dist/safe-bash/command-chunks/{chunk-456PHA3L.js → chunk-DMCI6T6N.js} +1 -1
  82. package/dist/safe-bash/command-chunks/{chunk-TW73OXPR.js → chunk-EJTNVXWF.js} +6 -6
  83. package/dist/safe-bash/command-chunks/{chunk-QD7ZRDUN.js → chunk-ET2VPDUA.js} +1 -1
  84. package/dist/safe-bash/command-chunks/{chunk-5LI2DLNZ.js → chunk-EXOQGXEU.js} +26 -26
  85. package/dist/safe-bash/command-chunks/{chunk-CRV2Q3PB.js → chunk-EZ4NQIPL.js} +1 -1
  86. package/dist/safe-bash/command-chunks/chunk-FWKLBDMK.js +0 -0
  87. package/dist/safe-bash/command-chunks/{chunk-22MOB45U.js → chunk-FWPVQGYK.js} +6 -6
  88. package/dist/safe-bash/command-chunks/{chunk-QC5RMGSA.js → chunk-G3RUXKVY.js} +3 -3
  89. package/dist/safe-bash/command-chunks/{chunk-JYUJAF4L.js → chunk-G7NENPYV.js} +4 -0
  90. package/dist/safe-bash/command-chunks/{chunk-KCOJA7EM.js → chunk-GKILM4HZ.js} +7 -7
  91. package/dist/safe-bash/command-chunks/{chunk-HTVIYLVB.js → chunk-GNXTMSYN.js} +4 -4
  92. package/dist/safe-bash/command-chunks/{chunk-D2ASPM7R.js → chunk-GOBUDKZ3.js} +3 -3
  93. package/dist/safe-bash/command-chunks/{chunk-RNSKXOG3.js → chunk-GVWVRPG6.js} +6 -6
  94. package/dist/safe-bash/command-chunks/{chunk-ZHRGYR7B.js → chunk-HCKYUQ3L.js} +7 -7
  95. package/dist/safe-bash/command-chunks/{chunk-AGLK7OJR.js → chunk-HDSIIQBS.js} +1 -1
  96. package/dist/safe-bash/command-chunks/{chunk-DM2CPMB4.js → chunk-HKOMXGJS.js} +2 -2
  97. package/dist/safe-bash/command-chunks/{chunk-IT7TAC3F.js → chunk-HVW53ARH.js} +16 -16
  98. package/dist/safe-bash/command-chunks/{chunk-M7QE2MN7.js → chunk-I4GMCWAT.js} +6 -6
  99. package/dist/safe-bash/command-chunks/{chunk-5MB64DWR.js → chunk-IHSOOSNC.js} +9 -9
  100. package/dist/safe-bash/command-chunks/{chunk-LCZDBW55.js → chunk-JAHJWVGF.js} +5 -5
  101. package/dist/safe-bash/command-chunks/{chunk-MOZD7RUY.js → chunk-JORIVUPM.js} +27 -11
  102. package/dist/safe-bash/command-chunks/{chunk-PMAM4N33.js → chunk-JUJHYPYL.js} +9 -9
  103. package/dist/safe-bash/command-chunks/{chunk-ENT3IV2G.js → chunk-KBUBSMCQ.js} +12 -12
  104. package/dist/safe-bash/command-chunks/{chunk-ZXR6LXV5.js → chunk-KCE5D4Z4.js} +48 -4
  105. package/dist/safe-bash/command-chunks/{chunk-FIIAYCWS.js → chunk-KZ5ODST6.js} +2 -2
  106. package/dist/safe-bash/command-chunks/{chunk-PNGDJA6M.js → chunk-LD7BONZY.js} +2 -2
  107. package/dist/safe-bash/command-chunks/{chunk-KJ4XXZIL.js → chunk-M3Z5PU2M.js} +582 -59
  108. package/dist/safe-bash/command-chunks/{chunk-LXLLA4PM.js → chunk-MKX4JAZ6.js} +17 -17
  109. package/dist/safe-bash/command-chunks/{chunk-RQIQ75W5.js → chunk-MNHBQBF6.js} +5 -5
  110. package/dist/safe-bash/command-chunks/{chunk-A2CLZMQZ.js → chunk-MPKY37QR.js} +1 -1
  111. package/dist/safe-bash/command-chunks/{chunk-K5GB2YMN.js → chunk-MUUWBZIC.js} +10 -10
  112. package/dist/safe-bash/command-chunks/{chunk-JOCFI7TG.js → chunk-N32GSM3J.js} +1 -1
  113. package/dist/safe-bash/command-chunks/{chunk-EUT24Y5Z.js → chunk-NKTULXVD.js} +8 -8
  114. package/dist/safe-bash/command-chunks/{chunk-5HPU7D36.js → chunk-NMPED6L5.js} +4 -4
  115. package/dist/safe-bash/command-chunks/{chunk-QZZ73J2O.js → chunk-NPFHUS4X.js} +6 -6
  116. package/dist/safe-bash/command-chunks/{chunk-X7FA7ZD5.js → chunk-O675URF4.js} +8 -8
  117. package/dist/safe-bash/command-chunks/{chunk-R6EGGK5M.js → chunk-P7EL2FWW.js} +7 -7
  118. package/dist/safe-bash/command-chunks/{chunk-YS25EI54.js → chunk-PCCFLPUQ.js} +2 -2
  119. package/dist/safe-bash/command-chunks/{chunk-RRL3Y562.js → chunk-PI6MOMHA.js} +11 -11
  120. package/dist/safe-bash/command-chunks/{chunk-26VCZHLJ.js → chunk-PIOQBOEK.js} +1 -1
  121. package/dist/safe-bash/command-chunks/chunk-PK36TVXB.js +175 -0
  122. package/dist/safe-bash/command-chunks/{chunk-72C3TZ2U.js → chunk-PKLJRB7W.js} +264 -129
  123. package/dist/safe-bash/command-chunks/{chunk-6CCQI6XZ.js → chunk-PSCOXGCA.js} +12 -12
  124. package/dist/safe-bash/command-chunks/{chunk-XPD636C4.js → chunk-PVGZMLC6.js} +3 -3
  125. package/dist/safe-bash/command-chunks/{chunk-JQVHUSDD.js → chunk-PXWS3Q7L.js} +5 -5
  126. package/dist/safe-bash/command-chunks/{chunk-HDJVJTCK.js → chunk-QFF5KBOM.js} +9 -9
  127. package/dist/safe-bash/command-chunks/{chunk-MPUHH2KR.js → chunk-QM2HZJSJ.js} +3 -3
  128. package/dist/safe-bash/command-chunks/{chunk-UAXSE3XE.js → chunk-R2BMZAHG.js} +5 -5
  129. package/dist/safe-bash/command-chunks/{chunk-KB7DUBVL.js → chunk-RGOQKIG6.js} +5 -5
  130. package/dist/safe-bash/command-chunks/{chunk-D2KZ66W4.js → chunk-RLCQ7BN3.js} +187 -39
  131. package/dist/safe-bash/command-chunks/{chunk-B5LDP7AA.js → chunk-S2N2V5U4.js} +2 -2
  132. package/dist/safe-bash/command-chunks/{chunk-OA75SGN2.js → chunk-SGPCXAG7.js} +7 -7
  133. package/dist/safe-bash/command-chunks/{chunk-Z5QOVRVH.js → chunk-SU26FZLJ.js} +1 -1
  134. package/dist/safe-bash/command-chunks/{chunk-QUM3SYAJ.js → chunk-SYSX46IV.js} +3 -3
  135. package/dist/safe-bash/command-chunks/chunk-T3E5RV3U.js +737 -0
  136. package/dist/safe-bash/command-chunks/{chunk-YORJDX4V.js → chunk-T5ERNELL.js} +4 -4
  137. package/dist/safe-bash/command-chunks/{chunk-KL3OIBKB.js → chunk-T6C5QP7T.js} +6495 -6343
  138. package/dist/safe-bash/command-chunks/{chunk-ATTWQVR2.js → chunk-TKRLZIFI.js} +17 -17
  139. package/dist/safe-bash/command-chunks/{chunk-ZMHEGDU2.js → chunk-TODWFDYB.js} +2 -2
  140. package/dist/safe-bash/command-chunks/{chunk-YSY6R6AS.js → chunk-TQEB4DH4.js} +703 -102
  141. package/dist/safe-bash/command-chunks/{chunk-36XGIPOG.js → chunk-U5TWQFZY.js} +1 -1
  142. package/dist/safe-bash/command-chunks/{chunk-APEWTWCC.js → chunk-UAF4IX5H.js} +6 -6
  143. package/dist/safe-bash/command-chunks/{chunk-6VPQ3CDZ.js → chunk-V37D6AHO.js} +5 -5
  144. package/dist/safe-bash/command-chunks/{chunk-RID6VYS3.js → chunk-V6XBEYPC.js} +8 -8
  145. package/dist/safe-bash/command-chunks/{chunk-WJCN2IXI.js → chunk-VQOINPVF.js} +2 -2
  146. package/dist/safe-bash/command-chunks/{chunk-W5YSINXC.js → chunk-VVWXY6IA.js} +6 -6
  147. package/dist/safe-bash/command-chunks/{chunk-HKATEVAP.js → chunk-WPVBUVFK.js} +6 -6
  148. package/dist/safe-bash/command-chunks/{chunk-UYWSIIUX.js → chunk-X53AEG36.js} +7 -7
  149. package/dist/safe-bash/command-chunks/{chunk-L5MCW6CM.js → chunk-X64XGIXZ.js} +9 -155
  150. package/dist/safe-bash/command-chunks/{chunk-Q73EMLLZ.js → chunk-X6RHJ6YN.js} +84 -5
  151. package/dist/safe-bash/command-chunks/{chunk-7PVHO47B.js → chunk-XG6UWQV5.js} +6 -6
  152. package/dist/safe-bash/command-chunks/{chunk-NQDIT667.js → chunk-XIDGHIGB.js} +5 -5
  153. package/dist/safe-bash/command-chunks/{chunk-DPR5CYQV.js → chunk-XITDDJFT.js} +2 -0
  154. package/dist/safe-bash/command-chunks/{chunk-CV7M2QJU.js → chunk-XLYIVBAR.js} +7 -7
  155. package/dist/safe-bash/command-chunks/{chunk-WVMHRNXZ.js → chunk-YUXTK3XA.js} +3 -3
  156. package/dist/safe-bash/command-chunks/{chunk-SPLOIABU.js → chunk-YXD6VGVG.js} +3 -3
  157. package/dist/safe-bash/command-chunks/{chunk-2ZFLMWOX.js → chunk-Z5BIM5B7.js} +1 -1
  158. package/dist/safe-bash/command-chunks/chunk-ZYLGNIGA.js +156 -0
  159. package/dist/safe-bash/command-chunks/{command-engine-BEWABZ75.js → command-engine-X3OLN7N6.js} +206 -86
  160. package/dist/safe-bash/command-chunks/{engine-AXXFTGCL-QBQNBI6K.js → engine-XUCIFZ7V-LJFGZM6O.js} +1 -1
  161. package/dist/safe-bash/command-chunks/paradox-4FCZE53D-LQPGVMEL.js +365 -0
  162. package/dist/safe-bash/commands/pandoc/index.browser.js +1 -1
  163. package/dist/safe-bash/full-core.browser.js +2 -2
  164. package/dist/safe-bash/plugins/index.browser.js +2 -2
  165. package/dist/safe-bash-command-apply-patch/apply.js +4 -4
  166. package/dist/safe-bash-command-apply-patch/index.js +4 -4
  167. package/dist/safe-bash-command-apply-patch/matcher.js +2 -2
  168. package/dist/safe-bash-command-apply-patch/parser.js +2 -2
  169. package/dist/safe-bash-command-apply-patch/shared.d.ts +2 -0
  170. package/dist/safe-bash-command-apply-patch/shared.js +1 -1
  171. package/dist/safe-bash-command-diff/diff.js +1 -1
  172. package/dist/safe-bash-command-diff/index.js +1 -1
  173. package/dist/safe-bash-command-ffmpeg/index.js +1 -1
  174. package/dist/safe-bash-command-ffprobe/index.js +2 -2
  175. package/dist/safe-bash-command-ffprobe/media.d.ts +3 -1
  176. package/dist/safe-bash-command-ffprobe/media.js +2 -2
  177. package/dist/safe-bash-command-html-to-markdown/budget.js +2 -1
  178. package/dist/safe-bash-command-html-to-markdown/entities.js +4 -3
  179. package/dist/safe-bash-command-html-to-markdown/index.js +564 -110
  180. package/dist/safe-bash-command-html-to-markdown/input.js +6 -5
  181. package/dist/safe-bash-command-html-to-markdown/options.js +2 -1
  182. package/dist/safe-bash-command-html-to-markdown/parser.js +5 -4
  183. package/dist/safe-bash-command-html-to-markdown/render.js +6 -5
  184. package/dist/safe-bash-command-html-to-markdown/text.js +3 -2
  185. package/dist/safe-bash-command-htmlq/index.js +361 -37
  186. package/dist/safe-bash-command-htmlq/tree.d.ts +3 -2
  187. package/dist/safe-bash-command-pandoc/command.js +7 -7
  188. package/dist/safe-bash-command-pandoc/index.js +55 -55
  189. package/dist/safe-bash-command-patch/index.js +6 -6
  190. package/dist/safe-bash-command-patch/patch-envelope.js +53 -3
  191. package/dist/safe-bash-command-patch/patch-formats.d.ts +2 -2
  192. package/dist/safe-bash-command-patch/patch-formats.js +2 -2
  193. package/dist/safe-bash-command-patch/patch-gnu-reject.d.ts +2 -1
  194. package/dist/safe-bash-command-patch/patch-gnu-reject.js +4 -3
  195. package/dist/safe-bash-command-patch/patch-publication.js +2 -1
  196. package/dist/safe-bash-command-patch/patch.js +6 -6
  197. package/dist/safe-bash-command-patch/unified.d.ts +10 -2
  198. package/dist/safe-bash-command-patch/unified.js +1 -1
  199. package/dist/safe-bash-command-pdftk/index.d.ts +6 -2
  200. package/dist/safe-bash-command-pdftk/index.js +835 -243
  201. package/dist/safe-bash-command-pptx/command-engine.d.ts +15 -3
  202. package/dist/safe-bash-command-pptx/engine.d.ts +2 -2
  203. package/dist/safe-bash-command-pptx/engine.js +1 -1
  204. package/dist/safe-bash-command-pptx/index.js +9 -2
  205. package/dist/safe-bash-command-soffice/index.js +1 -1
  206. package/dist/safe-bash-command-ssconvert/index.js +2 -2
  207. package/dist/safe-bash-command-xmllint/index.js +22 -31
  208. package/dist/safe-bash-diff-engine/document.d.ts +2 -1
  209. package/dist/safe-bash-diff-engine/document.js +7 -4
  210. package/dist/safe-bash-presentation-engine/accessibility.js +31 -30
  211. package/dist/safe-bash-presentation-engine/animation-editing.js +16 -15
  212. package/dist/safe-bash-presentation-engine/animations.js +16 -15
  213. package/dist/safe-bash-presentation-engine/backgrounds.js +17 -16
  214. package/dist/safe-bash-presentation-engine/bytes.js +3 -3
  215. package/dist/safe-bash-presentation-engine/chart-editing.js +34 -33
  216. package/dist/safe-bash-presentation-engine/chart-object-operations.js +25 -24
  217. package/dist/safe-bash-presentation-engine/charts.js +31 -30
  218. package/dist/safe-bash-presentation-engine/command-placeholder.js +59 -55
  219. package/dist/safe-bash-presentation-engine/comments.js +17 -16
  220. package/dist/safe-bash-presentation-engine/connector-operations.js +32 -31
  221. package/dist/safe-bash-presentation-engine/connectors.js +29 -28
  222. package/dist/safe-bash-presentation-engine/content-types.js +4 -4
  223. package/dist/safe-bash-presentation-engine/creation.js +6 -6
  224. package/dist/safe-bash-presentation-engine/diff.js +32 -31
  225. package/dist/safe-bash-presentation-engine/drawing-enums.d.ts +10 -10
  226. package/dist/safe-bash-presentation-engine/drawing-format.js +20 -19
  227. package/dist/safe-bash-presentation-engine/drawing-operations.js +31 -30
  228. package/dist/safe-bash-presentation-engine/drawing-schema.js +21 -20
  229. package/dist/safe-bash-presentation-engine/equations.js +17 -16
  230. package/dist/safe-bash-presentation-engine/errors.js +2 -2
  231. package/dist/safe-bash-presentation-engine/fields.js +17 -16
  232. package/dist/safe-bash-presentation-engine/font-metrics.js +3 -3
  233. package/dist/safe-bash-presentation-engine/image-extraction.js +20 -19
  234. package/dist/safe-bash-presentation-engine/image-formatting.js +32 -31
  235. package/dist/safe-bash-presentation-engine/image-insertion.js +18 -17
  236. package/dist/safe-bash-presentation-engine/image-replacement.js +21 -20
  237. package/dist/safe-bash-presentation-engine/image-value.js +4 -4
  238. package/dist/safe-bash-presentation-engine/images.js +19 -18
  239. package/dist/safe-bash-presentation-engine/index.d.ts +6 -2
  240. package/dist/safe-bash-presentation-engine/index.js +112 -97
  241. package/dist/safe-bash-presentation-engine/layouts.js +16 -15
  242. package/dist/safe-bash-presentation-engine/length.js +3 -3
  243. package/dist/safe-bash-presentation-engine/links.js +16 -15
  244. package/dist/safe-bash-presentation-engine/masters.js +15 -14
  245. package/dist/safe-bash-presentation-engine/media-editing.js +24 -23
  246. package/dist/safe-bash-presentation-engine/media-extraction.js +17 -16
  247. package/dist/safe-bash-presentation-engine/media.js +16 -15
  248. package/dist/safe-bash-presentation-engine/memberships.js +15 -14
  249. package/dist/safe-bash-presentation-engine/notes.js +16 -15
  250. package/dist/safe-bash-presentation-engine/ole-enum.js +4 -4
  251. package/dist/safe-bash-presentation-engine/ole-insertion.js +20 -19
  252. package/dist/safe-bash-presentation-engine/opaque-objects.js +9 -9
  253. package/dist/safe-bash-presentation-engine/package-reader.js +5 -5
  254. package/dist/safe-bash-presentation-engine/package-tools.d.ts +3 -0
  255. package/dist/safe-bash-presentation-engine/package-tools.js +27 -17
  256. package/dist/safe-bash-presentation-engine/package-uri.js +3 -3
  257. package/dist/safe-bash-presentation-engine/package-writer.js +4 -4
  258. package/dist/safe-bash-presentation-engine/presentation-model.js +58 -54
  259. package/dist/safe-bash-presentation-engine/presentation-settings.js +14 -13
  260. package/dist/safe-bash-presentation-engine/properties.js +16 -15
  261. package/dist/safe-bash-presentation-engine/relationships.js +4 -4
  262. package/dist/safe-bash-presentation-engine/resource-limits.js +1 -1
  263. package/dist/safe-bash-presentation-engine/retained-archive-staging.d.ts +19 -0
  264. package/dist/safe-bash-presentation-engine/retained-extraction-output.d.ts +18 -0
  265. package/dist/safe-bash-presentation-engine/retained-inspection.js +14 -12
  266. package/dist/safe-bash-presentation-engine/retained-package-extraction.d.ts +22 -0
  267. package/dist/safe-bash-presentation-engine/retained-package-packing.d.ts +19 -0
  268. package/dist/safe-bash-presentation-engine/retained-package.d.ts +2 -0
  269. package/dist/safe-bash-presentation-engine/retained-package.js +6 -4
  270. package/dist/safe-bash-presentation-engine/retained-slide-publication.d.ts +24 -0
  271. package/dist/safe-bash-presentation-engine/retained-text.js +19 -17
  272. package/dist/safe-bash-presentation-engine/retained-xml-parts.d.ts +5 -1
  273. package/dist/safe-bash-presentation-engine/retained-xml-publication.d.ts +18 -0
  274. package/dist/safe-bash-presentation-engine/retained-xml-replacement.d.ts +13 -0
  275. package/dist/safe-bash-presentation-engine/sanitize.js +17 -16
  276. package/dist/safe-bash-presentation-engine/selectors.js +10 -10
  277. package/dist/safe-bash-presentation-engine/shape-groups.js +31 -30
  278. package/dist/safe-bash-presentation-engine/shape-operations.js +30 -29
  279. package/dist/safe-bash-presentation-engine/shape-path-operations.js +32 -31
  280. package/dist/safe-bash-presentation-engine/shape-paths.js +16 -15
  281. package/dist/safe-bash-presentation-engine/shape-presets.js +3 -3
  282. package/dist/safe-bash-presentation-engine/shape-selection.js +31 -30
  283. package/dist/safe-bash-presentation-engine/shape-transforms.js +18 -17
  284. package/dist/safe-bash-presentation-engine/shapes.d.ts +1 -1
  285. package/dist/safe-bash-presentation-engine/shapes.js +27 -26
  286. package/dist/safe-bash-presentation-engine/slide-copy.js +17 -16
  287. package/dist/safe-bash-presentation-engine/slide-import.js +18 -17
  288. package/dist/safe-bash-presentation-engine/slide-merge-split.js +20 -19
  289. package/dist/safe-bash-presentation-engine/slide-model.js +43 -42
  290. package/dist/safe-bash-presentation-engine/slide-removal.js +18 -17
  291. package/dist/safe-bash-presentation-engine/slide-transfer-budget.js +9 -9
  292. package/dist/safe-bash-presentation-engine/slides.d.ts +1 -0
  293. package/dist/safe-bash-presentation-engine/slides.js +23 -17
  294. package/dist/safe-bash-presentation-engine/table-operations.js +33 -32
  295. package/dist/safe-bash-presentation-engine/table-spans.js +32 -31
  296. package/dist/safe-bash-presentation-engine/tables.js +31 -30
  297. package/dist/safe-bash-presentation-engine/tags.js +16 -15
  298. package/dist/safe-bash-presentation-engine/template-bindings.js +33 -32
  299. package/dist/safe-bash-presentation-engine/template-repeat.js +40 -39
  300. package/dist/safe-bash-presentation-engine/text-fitting.js +27 -26
  301. package/dist/safe-bash-presentation-engine/text-frames.js +27 -26
  302. package/dist/safe-bash-presentation-engine/text-paragraphs.js +27 -26
  303. package/dist/safe-bash-presentation-engine/text-reading.js +11 -11
  304. package/dist/safe-bash-presentation-engine/text-replacement.js +17 -16
  305. package/dist/safe-bash-presentation-engine/text-runs.js +20 -19
  306. package/dist/safe-bash-presentation-engine/themes.js +16 -15
  307. package/dist/safe-bash-presentation-engine/transitions.js +16 -15
  308. package/dist/safe-bash-presentation-engine/validation.js +10 -9
  309. package/dist/safe-bash-presentation-engine/xml-parts.d.ts +2 -0
  310. package/dist/safe-bash-presentation-engine/xml-parts.js +23 -15
  311. package/dist/safe-bash-presentation-engine/xml-view.js +3 -3
  312. package/dist/safe-bash-presentation-engine/xml.js +3 -3
  313. package/dist/safe-bash-regex-engine/index.js +1 -1
  314. package/dist/safe-bash-regex-engine/python-glob.js +1 -1
  315. package/dist/safe-bash-regex-engine/text/regex.d.ts +19 -0
  316. package/dist/safe-bash-regex-engine/text/regex.js +1 -1
  317. package/dist/safe-bash-xml-engine/document.js +3 -3
  318. package/dist/safe-bash-xml-engine/evaluate.js +1 -1
  319. package/dist/safe-bash-xml-engine/index.d.ts +1 -0
  320. package/dist/safe-bash-xml-engine/index.js +8 -4
  321. package/dist/safe-bash-xml-engine/query.js +2 -2
  322. package/dist/safe-bash-xml-engine/recovery.d.ts +10 -0
  323. package/dist/safe-bash-xml-engine/stored-document.d.ts +1 -1
  324. package/dist/safe-bash-xml-engine/stored-document.js +1 -1
  325. package/dist/safe-bash-xml-engine/stored-evaluate.js +1 -1
  326. package/dist/spreadsheet-engine/formulas/functions/python-printf.js +56 -33
  327. package/dist/spreadsheet-format-xls/biff-encrypted-properties.d.ts +2 -2
  328. package/dist/spreadsheet-format-xls/biff-encrypted-properties.js +86 -24
  329. package/dist/spreadsheet-format-xls/biff-metadata.d.ts +1 -0
  330. package/dist/spreadsheet-format-xls/biff-metadata.js +2 -2
  331. package/dist/spreadsheet-format-xls/biff-properties-merge.d.ts +6 -2
  332. package/dist/spreadsheet-format-xls/biff-properties-merge.js +413 -296
  333. package/dist/spreadsheet-format-xls/biff-properties-write.js +40 -23
  334. package/dist/spreadsheet-format-xls/biff-properties.js +3 -68
  335. package/dist/spreadsheet-format-xls/biff-property-index.d.ts +23 -0
  336. package/dist/spreadsheet-format-xls/biff-property-index.js +93 -0
  337. package/dist/spreadsheet-format-xls/biff-property-name.d.ts +4 -0
  338. package/dist/spreadsheet-format-xls/biff-property-name.js +114 -0
  339. package/dist/spreadsheet-format-xls/biff-property-text.d.ts +6 -0
  340. package/dist/spreadsheet-format-xls/biff-property-text.js +68 -0
  341. package/dist/spreadsheet-format-xls/biff-property-transcode.d.ts +5 -0
  342. package/dist/spreadsheet-format-xls/biff-property-transcode.js +45 -0
  343. package/dist/spreadsheet-format-xls/biff-write-metadata.js +10 -1
  344. package/package.json +6 -3
  345. package/dist/safe-bash/command-chunks/biff-3EFLKBAH-NYWZOYQS.js +0 -4942
  346. package/dist/safe-bash/command-chunks/chunk-5Q22ZLNC.js +0 -127
  347. package/dist/safe-bash/command-chunks/chunk-JKLOBSMP.js +0 -56
  348. package/dist/safe-bash/command-chunks/chunk-JYTESTBS.js +0 -99
  349. package/dist/safe-bash/command-chunks/chunk-WH3TIOTS.js +0 -326
  350. package/dist/safe-bash/command-chunks/paradox-ZWWXYY4J-JYOSWSBL.js +0 -362
  351. package/dist/spreadsheet-format-xls/biff-properties-layout.js +0 -56
@@ -26870,6 +26870,7 @@ function cosStream(dataOrDict, optionsOrData = {}, span) {
26870
26870
  };
26871
26871
  }
26872
26872
  function dictGet(dict, key) {
26873
+ if (dict.storedEntries) throw new TypeError("Stored dictionary requires asynchronous access");
26873
26874
  for (let i = dict.entries.length - 1; i >= 0; i--) {
26874
26875
  if (dict.entries[i].key.decoded === key) {
26875
26876
  return dict.entries[i].value;
@@ -26878,6 +26879,7 @@ function dictGet(dict, key) {
26878
26879
  return void 0;
26879
26880
  }
26880
26881
  function dictSet(dict, key, value) {
26882
+ if (dict.storedEntries) throw new TypeError("Stored dictionary requires asynchronous access");
26881
26883
  for (let i = dict.entries.length - 1; i >= 0; i--) {
26882
26884
  if (dict.entries[i].key.decoded === key) {
26883
26885
  dict.entries[i] = { key: cosName(key), value };
@@ -26887,6 +26889,7 @@ function dictSet(dict, key, value) {
26887
26889
  dict.entries.push({ key: cosName(key), value });
26888
26890
  }
26889
26891
  function dictDelete(dict, key) {
26892
+ if (dict.storedEntries) throw new TypeError("Stored dictionary requires asynchronous access");
26890
26893
  for (let i = dict.entries.length - 1; i >= 0; i--) {
26891
26894
  if (dict.entries[i].key.decoded === key) {
26892
26895
  dict.entries.splice(i, 1);
@@ -27536,6 +27539,60 @@ function getStandardFontOutlines(name, options = {}) {
27536
27539
  return font;
27537
27540
  }
27538
27541
 
27542
+ // packages/pdf-ast/src/cos/compact-number.ts
27543
+ var CompactPdfNumber = class {
27544
+ original = "";
27545
+ sign = "";
27546
+ digits = "";
27547
+ significant = 0;
27548
+ fractional = 0;
27549
+ decimal = false;
27550
+ exponent = false;
27551
+ exponentNegative = false;
27552
+ power = 0n;
27553
+ sticky = false;
27554
+ append(character) {
27555
+ const text = String.fromCharCode(character);
27556
+ if (this.original !== void 0) this.original = this.original.length < 2048 ? this.original + text : void 0;
27557
+ if (character === 69 || character === 101) {
27558
+ this.exponent = true;
27559
+ return;
27560
+ }
27561
+ if (character === 43 || character === 45) {
27562
+ if (this.exponent) this.exponentNegative = character === 45;
27563
+ else this.sign = text;
27564
+ return;
27565
+ }
27566
+ if (character === 46) {
27567
+ this.decimal = true;
27568
+ return;
27569
+ }
27570
+ const digit2 = character - 48;
27571
+ if (this.exponent) {
27572
+ const maximum10 = 2n * BigInt(Number.MAX_SAFE_INTEGER);
27573
+ if (this.power < maximum10) {
27574
+ this.power = this.power * 10n + BigInt(digit2);
27575
+ if (this.power > maximum10) this.power = maximum10;
27576
+ }
27577
+ return;
27578
+ }
27579
+ if (this.decimal) this.fractional++;
27580
+ if (!this.significant && digit2 === 0) return;
27581
+ this.significant++;
27582
+ if (this.digits.length < 2048) this.digits += text;
27583
+ else if (digit2 !== 0) this.sticky = true;
27584
+ }
27585
+ get spelling() {
27586
+ if (this.original !== void 0) return this.original;
27587
+ const digits = (this.digits || "0") + (this.sticky ? "1" : "");
27588
+ const power = (this.exponentNegative ? -this.power : this.power) + BigInt(this.significant - this.digits.length - this.fractional) - (this.sticky ? 1n : 0n);
27589
+ return `${this.sign}${digits}e${power}`;
27590
+ }
27591
+ get shortened() {
27592
+ return this.original === void 0;
27593
+ }
27594
+ };
27595
+
27539
27596
  // packages/pdf-ast/src/cos/lexer.ts
27540
27597
  function isPdfWhitespace(byte3) {
27541
27598
  return byte3 === 0 || byte3 === 9 || byte3 === 10 || byte3 === 12 || byte3 === 13 || byte3 === 32;
@@ -27594,23 +27651,29 @@ var StringOutput = class {
27594
27651
  }
27595
27652
  };
27596
27653
  var CosLexerState = class {
27597
- constructor(bytes, start = 0, end = bytes.length, maxTokenBytes = Infinity, knownCommands, onTokenAllocation, stringMode = "buffer") {
27654
+ constructor(bytes, start = 0, end = bytes.length, maxTokenBytes = Infinity, knownCommands, onTokenAllocation, stringMode = "buffer", compactNumbers = false, compactKeywords = false) {
27598
27655
  this.knownCommands = knownCommands;
27599
27656
  this.onTokenAllocation = onTokenAllocation;
27600
27657
  this.stringMode = stringMode;
27658
+ this.compactNumbers = compactNumbers;
27601
27659
  this.window = bytes;
27602
27660
  this.pos = start;
27603
27661
  this.end = end;
27604
27662
  this.maxTokenBytes = maxTokenBytes;
27663
+ let keywordLimit = compactKeywords ? 64 : Infinity;
27664
+ if (compactKeywords) for (const command of knownCommands ?? []) keywordLimit = Math.max(keywordLimit, command.length);
27665
+ this.keywordLimit = keywordLimit;
27605
27666
  }
27606
27667
  knownCommands;
27607
27668
  onTokenAllocation;
27608
27669
  stringMode;
27670
+ compactNumbers;
27609
27671
  window;
27610
27672
  windowStart = 0;
27611
27673
  pos;
27612
27674
  end;
27613
27675
  maxTokenBytes;
27676
+ keywordLimit;
27614
27677
  *byte(position) {
27615
27678
  if (position < 0 || position >= this.end) return void 0;
27616
27679
  if (position < this.windowStart || position >= this.windowStart + this.window.length) {
@@ -27694,14 +27757,17 @@ var CosLexerState = class {
27694
27757
  this.pos++;
27695
27758
  return { kind: "keyword", value: String.fromCharCode(b), span: { start, end: this.pos } };
27696
27759
  }
27697
- let raw = "";
27760
+ let raw = "", truncated = false;
27698
27761
  while (this.pos < this.end) {
27699
- const cur = yield* this.byte(this.pos);
27762
+ const cur = this.window[this.pos - this.windowStart] ?? (yield* this.byte(this.pos));
27700
27763
  if (isPdfWhitespace(cur) || isPdfDelimiter(cur)) break;
27701
- this.onTokenAllocation?.(32);
27702
- const next = raw + String.fromCharCode(cur);
27703
- if (this.knownCommands?.has(raw) && !this.knownCommands.has(next)) break;
27704
- raw = next;
27764
+ if (!truncated) {
27765
+ this.onTokenAllocation?.(32);
27766
+ const next = raw + String.fromCharCode(cur);
27767
+ if (this.knownCommands?.has(raw) && !this.knownCommands.has(next)) break;
27768
+ if (next.length > this.keywordLimit) truncated = true;
27769
+ else raw = next;
27770
+ }
27705
27771
  this.pos++;
27706
27772
  if (this.pos - start > this.maxTokenBytes) {
27707
27773
  throw new PdfError("E_LIMIT", "PDF token exceeds maximum byte length");
@@ -27711,13 +27777,18 @@ var CosLexerState = class {
27711
27777
  if (raw === "true") return { kind: "boolean", value: true, span };
27712
27778
  if (raw === "false") return { kind: "boolean", value: false, span };
27713
27779
  if (raw === "null") return { kind: "null", span };
27714
- return { kind: "keyword", value: raw, span };
27780
+ return { kind: "keyword", value: truncated ? raw + "\u2026" : raw, ...truncated ? { truncated: true } : {}, span };
27715
27781
  }
27716
27782
  *readNumber() {
27717
27783
  const start = this.pos;
27784
+ const compact = this.compactNumbers ? new CompactPdfNumber() : void 0;
27785
+ if (compact) this.onTokenAllocation?.(16384);
27718
27786
  const advance = (character) => {
27719
- this.onTokenAllocation?.(32);
27720
- if (character !== void 0) normalized += String.fromCharCode(character);
27787
+ if (!compact) this.onTokenAllocation?.(32);
27788
+ if (character !== void 0) {
27789
+ if (compact) compact.append(character);
27790
+ else normalized += String.fromCharCode(character);
27791
+ }
27721
27792
  this.pos++;
27722
27793
  if (this.pos - start > this.maxTokenBytes) {
27723
27794
  throw new PdfError("E_LIMIT", "PDF token exceeds maximum byte length");
@@ -27751,7 +27822,7 @@ var CosLexerState = class {
27751
27822
  throw new PdfError("E_PARSE", "Invalid PDF number prefix");
27752
27823
  }
27753
27824
  while (this.pos < this.end) {
27754
- const b = yield* this.byte(this.pos);
27825
+ const b = this.window[this.pos - this.windowStart] ?? (yield* this.byte(this.pos));
27755
27826
  if (b >= 48 && b <= 57) {
27756
27827
  advance(b);
27757
27828
  } else if (b === 46 && !decimal) {
@@ -27776,6 +27847,7 @@ var CosLexerState = class {
27776
27847
  }
27777
27848
  }
27778
27849
  }
27850
+ if (compact) normalized = compact.spelling;
27779
27851
  const value = Number(normalized);
27780
27852
  if (!Number.isFinite(value)) {
27781
27853
  throw new PdfError("E_CAPABILITY", `Non-finite PDF number: ${normalized}`);
@@ -27783,7 +27855,7 @@ var CosLexerState = class {
27783
27855
  return {
27784
27856
  kind: "number",
27785
27857
  value,
27786
- raw: exponent ? formatPdfNumber(value) : normalized,
27858
+ raw: exponent ? formatPdfNumber(value) : compact?.shortened ? `${Object.is(value, -0) ? "-0" : formatPdfNumber(value)}${decimal && Number.isInteger(value) ? ".0" : ""}` : normalized,
27787
27859
  isInteger: Number.isInteger(value) && !decimal && !exponent,
27788
27860
  span: { start, end: this.pos }
27789
27861
  };
@@ -27962,7 +28034,9 @@ var CosRangeLexer = class {
27962
28034
  maximum10,
27963
28035
  options.knownCommands,
27964
28036
  options.onTokenAllocation,
27965
- options.stringStorage ? "count" : "buffer"
28037
+ options.stringStorage ? "count" : "buffer",
28038
+ options.compactNumbers,
28039
+ options.compactKeywords
27966
28040
  );
27967
28041
  this.onBackingError = options.onBackingError;
27968
28042
  this.onTokenAllocation = options.onTokenAllocation;
@@ -28156,28 +28230,41 @@ function* parseValueSteps(lexer, maxDepth, repair = false, maxNodes = Infinity,
28156
28230
  if (nodes >= maxNodes) throw new PdfError("E_LIMIT", "PDF value node limit exceeded");
28157
28231
  nodes++;
28158
28232
  };
28233
+ const residentDepth = 32;
28159
28234
  const stack = [];
28160
- function matchesStoredPath() {
28235
+ let current, depth = 0;
28236
+ const pathLength = (options.storedArrayPaths ?? []).reduce((length, path) => Math.max(length, path.length - 1), 0);
28237
+ function matchesStoredPath(parent) {
28161
28238
  return options.storedArrayPaths?.some((path) => {
28162
- const prefix = options.arrayPathPrefix ?? [], length = prefix.length + stack.length;
28239
+ const length = parent.path.length + 1;
28163
28240
  if (!path.length || path.length > length) return false;
28164
28241
  for (let i = 0; i < path.length; i++) {
28165
28242
  const at = length - path.length + i;
28166
- let key;
28167
- if (at < prefix.length) key = prefix[at];
28168
- else {
28169
- const parent = stack[at - prefix.length];
28170
- if (parent.kind !== "dict") return false;
28171
- key = parent.key?.decoded;
28172
- }
28173
- if (key === void 0 || path[i] !== "*" && path[i] !== key) return false;
28243
+ const key = at === parent.path.length ? parent.kind === "dict" ? parent.key?.decoded : void 0 : parent.path[at];
28244
+ if (key == null || path[i] !== "*" && path[i] !== key) return false;
28174
28245
  }
28175
28246
  return true;
28176
28247
  }) ?? false;
28177
28248
  }
28249
+ function ancestorPath(parent) {
28250
+ if (!pathLength) return [];
28251
+ return parent ? [...parent.path, parent.kind === "dict" ? parent.key?.decoded ?? null : null].slice(-pathLength) : options.arrayPathPrefix?.slice(-pathLength) ?? [];
28252
+ }
28253
+ function* push(container) {
28254
+ if (current) {
28255
+ if (options.containerStorage && depth > residentDepth) yield { kind: "container-push", container: current };
28256
+ else stack.push(current);
28257
+ }
28258
+ current = container;
28259
+ depth++;
28260
+ }
28261
+ function* pop() {
28262
+ depth--;
28263
+ current = options.containerStorage && depth > residentDepth ? yield { kind: "container-pop" } : stack.pop();
28264
+ }
28178
28265
  while (true) {
28179
28266
  if (++work % 16 === 0) yield;
28180
- const parent = stack.at(-1);
28267
+ const parent = current;
28181
28268
  lexer.setStringStorage?.(options.stringStorage && (parent?.kind === "dict" && parent.key && options.storedStringKeys?.includes(parent.key.decoded) || !parent && options.storeRootString) ? options.stringStorage : void 0);
28182
28269
  const tok = yield "token";
28183
28270
  if (!tok) {
@@ -28190,12 +28277,12 @@ function* parseValueSteps(lexer, maxDepth, repair = false, maxNodes = Infinity,
28190
28277
  }
28191
28278
  let node;
28192
28279
  if (parent?.kind === "array" && tok.kind === "array-end") {
28193
- stack.pop();
28280
+ yield* pop();
28194
28281
  node = { kind: "array", items: parent.items, ...parent.storedItems ? { storedItems: parent.storedItems } : {}, span: { start: parent.start, end: tok.span.end } };
28195
28282
  } else if (parent?.kind === "dict" && !parent.key) {
28196
28283
  if (tok.kind === "dict-end") {
28197
- stack.pop();
28198
- node = yield { kind: "dict", entries: parent.entries, span: { start: parent.start, end: tok.span.end } };
28284
+ yield* pop();
28285
+ node = yield { kind: "dict", entries: parent.entries, ...parent.storedEntries ? { storedEntries: parent.storedEntries } : {}, span: { start: parent.start, end: tok.span.end } };
28199
28286
  } else if (tok.kind === "name") {
28200
28287
  charge();
28201
28288
  parent.key = { kind: "name", rawBytes: tok.rawBytes, decoded: tok.decoded, span: tok.span };
@@ -28209,11 +28296,12 @@ function* parseValueSteps(lexer, maxDepth, repair = false, maxNodes = Infinity,
28209
28296
  throw new PdfError("E_PARSE", `Missing value for dictionary key /${parent.key.decoded}`);
28210
28297
  }
28211
28298
  charge();
28212
- if (stack.length > maxDepth) throw new PdfError("E_LIMIT", "PDF syntax nesting limit exceeded");
28299
+ if (depth > maxDepth) throw new PdfError("E_LIMIT", "PDF syntax nesting limit exceeded");
28213
28300
  if (tok.kind === "array-start") {
28214
- const backed = options.arrayStorage && (parent?.kind === "array" && parent.storedItems || parent?.kind === "dict" && (options.storedArrayKeys?.includes(parent.key.decoded) || matchesStoredPath()) || !parent && options.storeRootArray);
28215
- stack.push({
28301
+ const backed = options.arrayStorage && (parent?.kind === "array" && parent.storedItems || parent?.kind === "dict" && (options.storedArrayKeys?.includes(parent.key.decoded) || matchesStoredPath(parent)) || !parent && options.storeRootArray);
28302
+ yield* push({
28216
28303
  kind: "array",
28304
+ path: ancestorPath(parent),
28217
28305
  start: tok.span.start,
28218
28306
  items: [],
28219
28307
  tail: -1,
@@ -28222,12 +28310,20 @@ function* parseValueSteps(lexer, maxDepth, repair = false, maxNodes = Infinity,
28222
28310
  continue;
28223
28311
  }
28224
28312
  if (tok.kind === "dict-start") {
28225
- stack.push({ kind: "dict", start: tok.span.start, entries: [] });
28313
+ const backed = options.dictionaryStorage && (parent?.kind === "dict" && options.storedDictionaryKeys?.includes(parent.key.decoded) || !parent && options.storeRootDictionary);
28314
+ yield* push({
28315
+ kind: "dict",
28316
+ path: ancestorPath(parent),
28317
+ start: tok.span.start,
28318
+ entries: [],
28319
+ tail: -1,
28320
+ ...backed ? { storedEntries: { storage: options.dictionaryStorage, position: -1, length: 0 } } : {}
28321
+ });
28226
28322
  continue;
28227
28323
  }
28228
28324
  node = yield* parseLeafFromToken(tok, lexer);
28229
28325
  }
28230
- const container = stack.at(-1);
28326
+ const container = current;
28231
28327
  if (!container) return node;
28232
28328
  if (container.kind === "array") {
28233
28329
  if (container.storedItems) {
@@ -28236,7 +28332,12 @@ function* parseValueSteps(lexer, maxDepth, repair = false, maxNodes = Infinity,
28236
28332
  container.tail = position;
28237
28333
  } else container.items.push(node);
28238
28334
  } else {
28239
- container.entries.push({ key: container.key, value: node });
28335
+ const entry = { key: container.key, value: node };
28336
+ if (container.storedEntries) {
28337
+ const position = yield { kind: "dictionary-append", entry, previous: container.tail };
28338
+ container.storedEntries = { ...container.storedEntries, position: container.tail === -1 ? position : container.storedEntries.position, length: container.storedEntries.length + 1 };
28339
+ container.tail = position;
28340
+ } else container.entries.push(entry);
28240
28341
  delete container.key;
28241
28342
  }
28242
28343
  }
@@ -28308,6 +28409,442 @@ function assertDecodedByteBudget(byteLength, maxBytes = Infinity) {
28308
28409
  }
28309
28410
  }
28310
28411
 
28412
+ // packages/pdf-ast/src/cos/object-index.ts
28413
+ import { listenForAbort } from "@poe-platform/safe-fs/contracts";
28414
+ var recordBytes = 32;
28415
+ function integer(value, name) {
28416
+ if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`Invalid ${name}`);
28417
+ return value;
28418
+ }
28419
+ function budget(value, name) {
28420
+ return value === void 0 || value === Infinity ? Infinity : integer(value, name);
28421
+ }
28422
+ function fields(entry) {
28423
+ const key = integer(entry.objectNumber, "PDF object number");
28424
+ if (entry.type === "free") return [key, integer(entry.nextFreeObjectNumber ?? 0, "free object number"), integer(entry.generationNumber ?? 0, "generation number"), 0];
28425
+ if (entry.type === "uncompressed") return [key, integer(entry.offset, "object offset"), integer(entry.generationNumber ?? 0, "generation number"), 1];
28426
+ if (entry.type === "compressed") return [key, integer(entry.objectStreamNumber, "object stream number"), integer(entry.indexInStream ?? entry.indexInObjectStream, "object stream index"), 2];
28427
+ throw new PdfError("E_PARSE", "Invalid PDF cross-reference entry type");
28428
+ }
28429
+ function decode(bytes, offset = 0) {
28430
+ const view = new DataView(bytes.buffer, bytes.byteOffset + offset, recordBytes);
28431
+ const objectNumber = view.getFloat64(0);
28432
+ const first = view.getFloat64(8);
28433
+ const second = view.getFloat64(16);
28434
+ const type = view.getFloat64(24);
28435
+ if (type === 0) return { objectNumber, type: "free", nextFreeObjectNumber: first, generationNumber: second };
28436
+ if (type === 1) return { objectNumber, type: "uncompressed", offset: first, generationNumber: second };
28437
+ if (type === 2) return { objectNumber, type: "compressed", objectStreamNumber: first, indexInStream: second };
28438
+ throw new PdfError("E_PARSE", "Invalid staged PDF index record");
28439
+ }
28440
+ async function* encode2(entries, chunkBytes) {
28441
+ let bytes = new Uint8Array(chunkBytes);
28442
+ let offset = 0;
28443
+ for await (const entry of entries) {
28444
+ const view = new DataView(bytes.buffer, offset, recordBytes);
28445
+ const values = fields(entry);
28446
+ for (let i = 0; i < values.length; i++) view.setFloat64(i * 8, values[i]);
28447
+ offset += recordBytes;
28448
+ if (offset === bytes.length) {
28449
+ yield bytes;
28450
+ bytes = new Uint8Array(chunkBytes);
28451
+ offset = 0;
28452
+ }
28453
+ }
28454
+ if (offset) yield bytes.subarray(0, offset);
28455
+ }
28456
+ async function* records(source, signal) {
28457
+ for await (const bytes of source.stream(0, source.size, signal)) {
28458
+ if (bytes.length % recordBytes !== 0) throw new PdfError("E_PARSE", "Truncated staged PDF index");
28459
+ for (let offset = 0; offset < bytes.length; offset += recordBytes) {
28460
+ signal?.throwIfAborted();
28461
+ yield decode(bytes, offset);
28462
+ }
28463
+ }
28464
+ }
28465
+ async function* merge(first, second, duplicate, signal) {
28466
+ const left = records(first, signal);
28467
+ const right = records(second, signal);
28468
+ try {
28469
+ let a = await left.next();
28470
+ let b = await right.next();
28471
+ let turns = 0;
28472
+ while (!a.done || !b.done) {
28473
+ signal?.throwIfAborted();
28474
+ if (!a.done && (b.done || a.value.objectNumber <= b.value.objectNumber)) {
28475
+ const equal2 = !b.done && a.value.objectNumber === b.value.objectNumber;
28476
+ yield equal2 && duplicate === "last" && !b.done ? b.value : a.value;
28477
+ if (equal2) b = await right.next();
28478
+ a = await left.next();
28479
+ } else if (!b.done) {
28480
+ yield b.value;
28481
+ b = await right.next();
28482
+ }
28483
+ if (++turns % 1024 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
28484
+ }
28485
+ } finally {
28486
+ await left.return(void 0);
28487
+ await right.return(void 0);
28488
+ }
28489
+ }
28490
+ var PdfObjectIndex = class _PdfObjectIndex {
28491
+ constructor(source, signal) {
28492
+ this.source = source;
28493
+ this.signal = signal;
28494
+ }
28495
+ source;
28496
+ signal;
28497
+ closing;
28498
+ get size() {
28499
+ return this.source.size / recordBytes;
28500
+ }
28501
+ static async build(input, storage, options = {}) {
28502
+ const duplicate = options.duplicate ?? "first";
28503
+ if (duplicate !== "first" && duplicate !== "last") throw new RangeError("Invalid PDF index duplicate policy");
28504
+ const runEntries = integer(options.runEntries ?? 2048, "runEntries");
28505
+ const chunkBytes = integer(options.chunkBytes ?? 64 * 1024, "chunkBytes");
28506
+ const cacheBytes = integer(options.cacheBytes ?? 256 * 1024, "cacheBytes");
28507
+ if (!runEntries || chunkBytes < recordBytes || chunkBytes % recordBytes !== 0 || cacheBytes < chunkBytes) throw new RangeError("Invalid PDF index batch/cache sizes");
28508
+ const maxEntries = budget(options.maxEntries, "maxEntries");
28509
+ const maxStagingBytes = budget(options.maxStagingBytes, "maxStagingBytes");
28510
+ const { signal } = options;
28511
+ signal?.throwIfAborted();
28512
+ const owned = /* @__PURE__ */ new Set();
28513
+ const levels = [];
28514
+ let stagedBytes = 0;
28515
+ let admitted = 0;
28516
+ let batch = [];
28517
+ const dispose = async (source) => {
28518
+ try {
28519
+ await source.close();
28520
+ } finally {
28521
+ owned.delete(source);
28522
+ stagedBytes -= source.size;
28523
+ }
28524
+ };
28525
+ const stage = async (entries) => {
28526
+ let reserved = 0;
28527
+ async function* chunks() {
28528
+ for await (const bytes of encode2(entries, chunkBytes)) {
28529
+ signal?.throwIfAborted();
28530
+ if (bytes.length > Math.min(maxStagingBytes, Number.MAX_SAFE_INTEGER) - stagedBytes) throw new PdfError("E_LIMIT", "PDF index staging byte limit exceeded");
28531
+ stagedBytes += bytes.length;
28532
+ reserved += bytes.length;
28533
+ yield bytes;
28534
+ }
28535
+ }
28536
+ try {
28537
+ const source = await PdfFileSource.fromStream(storage.fs, storage.directory, chunks(), { chunkBytes, cacheBytes, ...signal ? { signal } : {} });
28538
+ owned.add(source);
28539
+ return source;
28540
+ } catch (error) {
28541
+ stagedBytes -= reserved;
28542
+ throw error;
28543
+ }
28544
+ };
28545
+ const flush = async () => {
28546
+ if (duplicate === "last") batch.reverse();
28547
+ batch.sort((a, b) => a.objectNumber - b.objectNumber);
28548
+ const sorted = batch;
28549
+ batch = [];
28550
+ function* unique() {
28551
+ let previous = -1;
28552
+ for (const entry of sorted) if (entry.objectNumber !== previous) {
28553
+ previous = entry.objectNumber;
28554
+ yield entry;
28555
+ }
28556
+ }
28557
+ let run = await stage(unique());
28558
+ let level = 0;
28559
+ while (levels[level]) {
28560
+ const earlier = levels[level];
28561
+ const combined = await stage(merge(earlier, run, duplicate, signal));
28562
+ await dispose(earlier);
28563
+ await dispose(run);
28564
+ levels[level++] = void 0;
28565
+ run = combined;
28566
+ }
28567
+ levels[level] = run;
28568
+ };
28569
+ const iterator = Symbol.asyncIterator in input ? input[Symbol.asyncIterator]() : input[Symbol.iterator]();
28570
+ let ended = false;
28571
+ const next = async () => {
28572
+ signal?.throwIfAborted();
28573
+ if (!signal) return iterator.next();
28574
+ let dispose2 = () => {
28575
+ };
28576
+ const cancelled = new Promise((ignored, reject) => {
28577
+ dispose2 = listenForAbort(signal, () => reject(signal.reason));
28578
+ });
28579
+ const pending = Promise.resolve().then(() => {
28580
+ signal.throwIfAborted();
28581
+ return iterator.next();
28582
+ });
28583
+ try {
28584
+ return await Promise.race([pending, cancelled]);
28585
+ } finally {
28586
+ dispose2();
28587
+ }
28588
+ };
28589
+ try {
28590
+ while (true) {
28591
+ const step = await next();
28592
+ signal?.throwIfAborted();
28593
+ if (step.done) {
28594
+ ended = true;
28595
+ break;
28596
+ }
28597
+ if (admitted >= Math.min(maxEntries, Number.MAX_SAFE_INTEGER)) throw new PdfError("E_LIMIT", "PDF index entry limit exceeded");
28598
+ admitted++;
28599
+ const values = fields(step.value);
28600
+ const entry = step.value.type === "compressed" ? { objectNumber: values[0], type: "compressed", objectStreamNumber: values[1], indexInStream: values[2] } : step.value.type === "free" ? { objectNumber: values[0], type: "free", nextFreeObjectNumber: values[1], generationNumber: values[2] } : { objectNumber: values[0], type: "uncompressed", offset: values[1], generationNumber: values[2] };
28601
+ batch.push(entry);
28602
+ if (batch.length === runEntries) await flush();
28603
+ if (admitted % 1024 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
28604
+ }
28605
+ if (batch.length) await flush();
28606
+ let result;
28607
+ for (let level = levels.length - 1; level >= 0; level--) {
28608
+ const run = levels[level];
28609
+ if (!run) continue;
28610
+ if (!result) result = run;
28611
+ else {
28612
+ const combined = await stage(merge(result, run, duplicate, signal));
28613
+ await dispose(result);
28614
+ await dispose(run);
28615
+ result = combined;
28616
+ }
28617
+ }
28618
+ result ??= await stage([]);
28619
+ signal?.throwIfAborted();
28620
+ owned.delete(result);
28621
+ return new _PdfObjectIndex(result, signal);
28622
+ } catch (error) {
28623
+ for (const source of owned) {
28624
+ try {
28625
+ await source.close();
28626
+ } catch {
28627
+ }
28628
+ }
28629
+ throw error;
28630
+ } finally {
28631
+ if (!ended) {
28632
+ try {
28633
+ const returning = iterator.return?.();
28634
+ if (returning) {
28635
+ if (signal?.aborted) void Promise.resolve(returning).catch(() => {
28636
+ });
28637
+ else await returning;
28638
+ }
28639
+ } catch {
28640
+ }
28641
+ }
28642
+ }
28643
+ }
28644
+ async get(objectNumber, signal) {
28645
+ integer(objectNumber, "PDF object number");
28646
+ this.assertOpen(signal);
28647
+ let low = 0;
28648
+ let high = this.size;
28649
+ while (low < high) {
28650
+ const middle = low + Math.floor((high - low) / 2);
28651
+ const entry = decode(await this.source.read(middle * recordBytes, recordBytes, signal));
28652
+ this.assertOpen(signal);
28653
+ if (entry.objectNumber === objectNumber) return entry;
28654
+ if (entry.objectNumber < objectNumber) low = middle + 1;
28655
+ else high = middle;
28656
+ }
28657
+ return void 0;
28658
+ }
28659
+ assertOpen(signal) {
28660
+ this.signal?.throwIfAborted();
28661
+ signal?.throwIfAborted();
28662
+ if (this.closing) throw new PdfError("E_CAPABILITY", "PDF object index is closed");
28663
+ }
28664
+ async *entries(signal) {
28665
+ this.assertOpen(signal);
28666
+ for await (const entry of records(this.source, signal)) {
28667
+ this.assertOpen(signal);
28668
+ yield entry;
28669
+ }
28670
+ }
28671
+ close() {
28672
+ this.closing ??= this.source.close();
28673
+ return this.closing;
28674
+ }
28675
+ };
28676
+
28677
+ // packages/pdf-ast/src/cos/name-index.ts
28678
+ var PdfNameIndex = class {
28679
+ constructor(storage, maximum10 = Infinity, signal) {
28680
+ this.storage = storage;
28681
+ this.maximum = maximum10;
28682
+ this.signal = signal;
28683
+ const limit10 = typeof maximum10 === "function" ? maximum10() : maximum10;
28684
+ if (limit10 !== Infinity && (!Number.isSafeInteger(limit10) || limit10 < 0)) throw new RangeError("Invalid name staging limit");
28685
+ }
28686
+ storage;
28687
+ maximum;
28688
+ signal;
28689
+ tail = /* @__PURE__ */ new Map();
28690
+ hot = /* @__PURE__ */ new Map();
28691
+ levels = [];
28692
+ nextNode = 2;
28693
+ nextName = 0;
28694
+ closed = false;
28695
+ get stagedBytes() {
28696
+ return this.levels.reduce((sum, index2) => sum + (index2?.size ?? 0) * 32, 0);
28697
+ }
28698
+ async get(edge) {
28699
+ if (this.tail.has(edge)) return this.tail.get(edge);
28700
+ if (this.hot.has(edge)) return this.hot.get(edge);
28701
+ for (const level of this.levels) {
28702
+ const entry = await level?.get(edge, this.signal);
28703
+ if (entry) {
28704
+ if (this.hot.size < 256) this.hot.set(edge, entry.offset);
28705
+ return entry.offset;
28706
+ }
28707
+ }
28708
+ return void 0;
28709
+ }
28710
+ async insert(edge, node) {
28711
+ this.tail.set(edge, node);
28712
+ if (this.hot.size < 256) this.hot.set(edge, node);
28713
+ if (this.tail.size < 64) return;
28714
+ let level = 0;
28715
+ while (this.levels[level]) level++;
28716
+ const inputs = this.levels.slice(0, level);
28717
+ const tail = this.tail;
28718
+ const signal = this.signal;
28719
+ async function* rows() {
28720
+ for (const [objectNumber, offset] of tail) yield { objectNumber, offset, type: "uncompressed" };
28721
+ for (const index2 of inputs) yield* index2.entries(signal);
28722
+ }
28723
+ const limit10 = typeof this.maximum === "function" ? this.maximum() : this.maximum;
28724
+ const remaining = Math.min(limit10, Number.MAX_SAFE_INTEGER) - this.stagedBytes;
28725
+ if (remaining < 0) throw new PdfError("E_LIMIT", "PDF name staging byte limit exceeded");
28726
+ const combined = await PdfObjectIndex.build(rows(), this.storage, {
28727
+ runEntries: 64,
28728
+ chunkBytes: 2048,
28729
+ cacheBytes: 2048,
28730
+ maxStagingBytes: remaining,
28731
+ ...signal ? { signal } : {}
28732
+ });
28733
+ try {
28734
+ for (let i = 0; i < level; i++) {
28735
+ await this.levels[i].close();
28736
+ this.levels[i] = void 0;
28737
+ }
28738
+ this.levels[level] = combined;
28739
+ this.tail.clear();
28740
+ } catch (error) {
28741
+ try {
28742
+ await combined.close();
28743
+ } catch {
28744
+ }
28745
+ throw error;
28746
+ }
28747
+ }
28748
+ async intern(value) {
28749
+ if (this.closed) throw new PdfError("E_CAPABILITY", "PDF name index is closed");
28750
+ this.signal?.throwIfAborted();
28751
+ let node = 1, newPath = false;
28752
+ const units = typeof value === "string" ? (function* () {
28753
+ for (let i = 0; i < value.length; i++) yield value.charCodeAt(i);
28754
+ })() : value;
28755
+ let work = 0;
28756
+ for await (const code of units) {
28757
+ this.signal?.throwIfAborted();
28758
+ if (!Number.isInteger(code) || code < 0 || code > 65535) throw new RangeError("Invalid PDF name code unit");
28759
+ if (++work % 512 === 0) {
28760
+ await new Promise((resolve2) => setTimeout(resolve2, 0));
28761
+ this.signal?.throwIfAborted();
28762
+ }
28763
+ for (const unit of [code & 255, code >>> 8]) {
28764
+ const edge = node * 257 + unit + 1;
28765
+ let child = newPath ? void 0 : await this.get(edge);
28766
+ if (child === void 0) {
28767
+ if (this.nextNode > Math.floor(Number.MAX_SAFE_INTEGER / 257) - 1) throw new PdfError("E_LIMIT", "PDF name index address limit exceeded");
28768
+ child = this.nextNode++;
28769
+ await this.insert(edge, child);
28770
+ newPath = true;
28771
+ }
28772
+ node = child;
28773
+ }
28774
+ }
28775
+ const terminal = node * 257;
28776
+ const existing = newPath ? void 0 : await this.get(terminal);
28777
+ if (existing !== void 0) return { index: existing, added: false };
28778
+ const index2 = this.nextName++;
28779
+ await this.insert(terminal, index2);
28780
+ return { index: index2, added: true };
28781
+ }
28782
+ async close() {
28783
+ if (this.closed) return;
28784
+ this.closed = true;
28785
+ const results = await Promise.allSettled(this.levels.map((index2) => index2?.close()));
28786
+ this.tail.clear();
28787
+ this.hot.clear();
28788
+ this.levels.length = 0;
28789
+ for (const result of results) if (result.status === "rejected") throw result.reason;
28790
+ }
28791
+ };
28792
+
28793
+ // packages/pdf-ast/src/content/stored-dictionary.ts
28794
+ async function* readPdfDictionaryEntries(dict, signal) {
28795
+ signal?.throwIfAborted();
28796
+ if (dict.storedEntries) yield* readStoredItems(dict.storedEntries, signal);
28797
+ else for (const entry of dict.entries) {
28798
+ signal?.throwIfAborted();
28799
+ yield entry;
28800
+ }
28801
+ }
28802
+ async function readPdfDictionaryValue(dict, key, signal) {
28803
+ let value;
28804
+ for await (const entry of readPdfDictionaryEntries(dict, signal)) if (entry.key.decoded === key) value = entry.value;
28805
+ return value;
28806
+ }
28807
+ async function mergePdfResourceDictionaries(destination, source, indexStorage, signal) {
28808
+ const storage = destination.storedEntries?.storage ?? source?.storedEntries?.storage;
28809
+ if (!storage) throw new TypeError("Resource merge requires caller-backed entries");
28810
+ const names = new PdfNameIndex(indexStorage, Infinity, signal);
28811
+ let index2, failed = false;
28812
+ async function* rows() {
28813
+ for (const [dict, replace] of [[destination, true], [source, false]]) {
28814
+ if (!dict) continue;
28815
+ for await (const entry of readPdfDictionaryEntries(dict, signal)) {
28816
+ const name = await names.intern(entry.key.decoded);
28817
+ if (!replace && !name.added) continue;
28818
+ const position = await writeStoredRecord(storage, entry, -1, signal);
28819
+ yield { objectNumber: name.index, type: "uncompressed", offset: position };
28820
+ }
28821
+ }
28822
+ }
28823
+ try {
28824
+ index2 = await PdfObjectIndex.build(rows(), indexStorage, { duplicate: "last", runEntries: 64, chunkBytes: 2048, cacheBytes: 2048, ...signal ? { signal } : {} });
28825
+ let position = -1, previous = -1, length = 0;
28826
+ const link2 = new Uint8Array(8), view = new DataView(link2.buffer);
28827
+ for await (const row of index2.entries(signal)) {
28828
+ if (previous !== -1) {
28829
+ view.setFloat64(0, row.offset, true);
28830
+ await storage.write(previous, link2, signal ? { signal } : void 0);
28831
+ signal?.throwIfAborted();
28832
+ } else position = row.offset;
28833
+ previous = row.offset;
28834
+ length++;
28835
+ }
28836
+ return { kind: "dict", entries: [], storedEntries: { storage, position, length } };
28837
+ } catch (error) {
28838
+ failed = true;
28839
+ throw error;
28840
+ } finally {
28841
+ const results = await Promise.allSettled([index2?.close(), names.close()]);
28842
+ if (!failed) {
28843
+ for (const result of results) if (result.status === "rejected") await Promise.reject(result.reason);
28844
+ }
28845
+ }
28846
+ }
28847
+
28311
28848
  // packages/pdf-ast/src/cos/security.ts
28312
28849
  import { readBytes as readBytes11 } from "@poe-platform/safe-fs/contracts";
28313
28850
 
@@ -30361,9 +30898,23 @@ async function decryptPdfObjectStrings(state, objectNumber, generationNumber, va
30361
30898
  }
30362
30899
  if (node.kind === "dict") {
30363
30900
  const entries = [];
30364
- const signature = isSignatureDictionary(node);
30365
- for (const entry of node.entries) entries.push({ key: entry.key, value: signature && entry.key.decoded === "Contents" ? entry.value : await transform(entry.value) });
30366
- return { ...node, entries };
30901
+ let signatureDict = node;
30902
+ if (node.storedEntries) {
30903
+ signatureDict = { kind: "dict", entries: [] };
30904
+ for await (const entry of readPdfDictionaryEntries(node, options.signal)) {
30905
+ if (["Type", "FT", "ByteRange", "Filter"].includes(entry.key.decoded)) dictSet(signatureDict, entry.key.decoded, entry.value);
30906
+ }
30907
+ }
30908
+ const signature = isSignatureDictionary(signatureDict);
30909
+ let position = -1, tail = -1;
30910
+ for await (const entry of readPdfDictionaryEntries(node, options.signal)) {
30911
+ const transformed = { key: entry.key, value: signature && entry.key.decoded === "Contents" ? entry.value : await transform(entry.value) };
30912
+ if (node.storedEntries) {
30913
+ tail = await appendStoredRecord(node.storedEntries.storage, transformed, tail, options.signal);
30914
+ if (position === -1) position = tail;
30915
+ } else entries.push(transformed);
30916
+ }
30917
+ return { ...node, entries, ...node.storedEntries ? { storedEntries: { ...node.storedEntries, position } } : {} };
30367
30918
  }
30368
30919
  return drainWorkAsync(transformNodeStringsAndStreamsSteps(node, (bytes) => decryptPdfBuffer(state, objectNumber, generationNumber, bytes)), options.signal);
30369
30920
  }
@@ -30819,7 +31370,7 @@ function* parseNodeFromLexerSteps(lexer, bytes, maxDepth, repair = false) {
30819
31370
  yield;
30820
31371
  step = work.next();
30821
31372
  } else {
30822
- if (step.value !== "token" && step.value.kind === "array-append") throw new TypeError("Stored arrays require asynchronous parsing");
31373
+ if (step.value !== "token" && step.value.kind !== "dict") throw new TypeError("Stored values require asynchronous parsing");
30823
31374
  step = work.next(step.value === "token" ? lexer.nextToken() : parseDictionaryStream(step.value, lexer, bytes));
30824
31375
  }
30825
31376
  }
@@ -31514,7 +32065,7 @@ function* sampledVertices(size, domain, encode3, inputs, sampleCount) {
31514
32065
  function* resolveNode(node, arrayKey) {
31515
32066
  if (!node) return void 0;
31516
32067
  const result = yield { kind: "resolve", node, ...arrayKey ? { arrayKey } : {} };
31517
- if (typeof result === "number" || typeof result === "boolean" || result?.kind === "annotation-page-frame") throw new TypeError("Expected a PDF annotation object");
32068
+ if (typeof result === "number" || typeof result === "boolean" || result?.kind === "annotation-frame") throw new TypeError("Expected a PDF annotation object");
31518
32069
  return result;
31519
32070
  }
31520
32071
  function* resolveDict(node) {
@@ -31525,15 +32076,7 @@ function* resolveArray(node, arrayKey) {
31525
32076
  const result = yield* resolveNode(node, arrayKey);
31526
32077
  return result?.kind === "array" ? result : void 0;
31527
32078
  }
31528
- function* visitChildren(array, visit) {
31529
- const cursor = new PdfArrayCursor(array);
31530
- for (let step = yield* cursor.next(); !step.done; step = yield* cursor.next()) {
31531
- const found = yield* visit(step.value);
31532
- if (found !== void 0) return found;
31533
- }
31534
- return void 0;
31535
- }
31536
- function* extractPageAnnotationSteps(pageDict, root, maxDepth = Infinity) {
32079
+ function* extractPageAnnotationSteps(pageDict, root) {
31537
32080
  const annotsArr = yield* resolveArray(dictGet(pageDict, "Annots"), "Annots");
31538
32081
  if (!annotsArr) return;
31539
32082
  function* resolveDestToPageNum(destNode, depth = 0) {
@@ -31565,35 +32108,8 @@ function* extractPageAnnotationSteps(pageDict, root, maxDepth = Infinity) {
31565
32108
  }
31566
32109
  const namesDict = yield* resolveDict(dictGet(catalog, "Names"));
31567
32110
  const destsTree = namesDict ? dictGet(namesDict, "Dests") : void 0;
31568
- const active = /* @__PURE__ */ new Set();
31569
- function* searchNameTree(node, depth2 = 0) {
31570
- if (!node) return void 0;
31571
- if (depth2 > maxDepth) throw new PdfError("E_LIMIT", "PDF annotation name-tree depth limit exceeded");
31572
- const identity = node.kind === "ref" ? `${node.objectNumber}:${node.generationNumber}` : node;
31573
- if (active.has(identity)) return void 0;
31574
- active.add(identity);
31575
- try {
31576
- const treeDict = yield* resolveDict(node);
31577
- if (!treeDict) return void 0;
31578
- const namesArr = yield* resolveArray(dictGet(treeDict, "Names"));
31579
- if (namesArr) {
31580
- for (let i = 0; i + 1 < namesArr.items.length; i += 2) {
31581
- const kNode = yield* resolveNode(namesArr.items[i]);
31582
- const kStr = kNode?.kind === "string" ? decodePdfString(kNode) : kNode?.kind === "name" ? kNode.decoded : "";
31583
- if (kStr === destName) return namesArr.items[i + 1];
31584
- }
31585
- }
31586
- const kidsArr = yield* resolveArray(dictGet(treeDict, "Kids"), "Kids");
31587
- if (kidsArr) {
31588
- const found = yield* visitChildren(kidsArr, (kid) => searchNameTree(kid, depth2 + 1));
31589
- if (found) return found;
31590
- }
31591
- return void 0;
31592
- } finally {
31593
- active.delete(identity);
31594
- }
31595
- }
31596
- const treeFound = yield* searchNameTree(destsTree);
32111
+ const treeFound = yield { kind: "named-destination", node: destsTree, name: destName };
32112
+ if (typeof treeFound === "number" || typeof treeFound === "boolean" || treeFound?.kind === "annotation-frame") throw new TypeError("Expected a named destination object");
31597
32113
  if (treeFound) return yield* resolveDestToPageNum(treeFound, depth + 1);
31598
32114
  }
31599
32115
  }
@@ -31646,9 +32162,9 @@ function* annotationPageNumberSteps(root, reference, maxDepth = Infinity) {
31646
32162
  while (true) {
31647
32163
  if (!node) {
31648
32164
  if (!cursor) {
31649
- const frame = yield { kind: "pop-page-frame" };
32165
+ const frame = yield { kind: "pop-traversal-frame" };
31650
32166
  if (frame === void 0) return void 0;
31651
- if (typeof frame !== "object" || frame.kind !== "annotation-page-frame") throw new TypeError("Expected an annotation page frame");
32167
+ if (typeof frame !== "object" || frame.kind !== "annotation-frame") throw new TypeError("Expected an annotation page frame");
31652
32168
  cursor = new PdfArrayCursor(frame.cursor.array, frame.cursor);
31653
32169
  cursorDepth = frame.depth;
31654
32170
  }
@@ -31670,7 +32186,7 @@ function* annotationPageNumberSteps(root, reference, maxDepth = Infinity) {
31670
32186
  const type = yield* resolveNode(dictGet(dict, "Type"));
31671
32187
  const kids = yield* resolveArray(dictGet(dict, "Kids"), "Kids");
31672
32188
  if (kids && (type?.kind !== "name" || type.decoded !== "Page")) {
31673
- if (cursor) yield { kind: "push-page-frame", frame: { kind: "annotation-page-frame", cursor: cursor.snapshot(), depth: cursorDepth } };
32189
+ if (cursor) yield { kind: "push-traversal-frame", frame: { kind: "annotation-frame", cursor: cursor.snapshot(), depth: cursorDepth } };
31674
32190
  cursor = new PdfArrayCursor(kids);
31675
32191
  cursorDepth = depth + 1;
31676
32192
  } else {
@@ -31679,6 +32195,83 @@ function* annotationPageNumberSteps(root, reference, maxDepth = Infinity) {
31679
32195
  }
31680
32196
  }
31681
32197
  }
32198
+ function* annotationNameDestinationSteps(first, name, maxDepth = Infinity) {
32199
+ let node = first, depth = 0, cursor, cursorDepth = 0, identity;
32200
+ while (true) {
32201
+ if (!node) {
32202
+ if (!cursor) {
32203
+ const frame = yield { kind: "pop-traversal-frame" };
32204
+ if (frame === void 0) return void 0;
32205
+ if (typeof frame !== "object" || frame.kind !== "annotation-frame" || frame.identity === void 0) throw new TypeError("Expected an annotation name frame");
32206
+ cursor = new PdfArrayCursor(frame.cursor.array, frame.cursor);
32207
+ cursorDepth = frame.depth;
32208
+ identity = frame.identity;
32209
+ }
32210
+ const step = yield* cursor.next();
32211
+ if (step.done) {
32212
+ yield { kind: "leave-name-node", identity };
32213
+ cursor = void 0;
32214
+ continue;
32215
+ }
32216
+ node = step.value;
32217
+ depth = cursorDepth;
32218
+ if (!node) continue;
32219
+ }
32220
+ const current = node;
32221
+ node = void 0;
32222
+ if (depth > maxDepth) throw new PdfError("E_LIMIT", "PDF annotation name-tree depth limit exceeded");
32223
+ const entered = yield { kind: "enter-name-node", node: current };
32224
+ if (entered === void 0) continue;
32225
+ if (typeof entered !== "number") throw new TypeError("Expected an annotation node identity");
32226
+ const dict = yield* resolveDict(current);
32227
+ if (dict) {
32228
+ const names = yield* resolveArray(dictGet(dict, "Names"));
32229
+ if (names) for (let i = 0; i + 1 < names.items.length; i += 2) {
32230
+ const key = yield* resolveNode(names.items[i]);
32231
+ const decoded = key?.kind === "string" ? decodePdfString(key) : key?.kind === "name" ? key.decoded : "";
32232
+ if (decoded === name) return names.items[i + 1];
32233
+ }
32234
+ const kids = yield* resolveArray(dictGet(dict, "Kids"), "Kids");
32235
+ if (kids) {
32236
+ if (cursor) yield { kind: "push-traversal-frame", frame: { kind: "annotation-frame", cursor: cursor.snapshot(), depth: cursorDepth, identity } };
32237
+ cursor = new PdfArrayCursor(kids);
32238
+ cursorDepth = depth + 1;
32239
+ identity = entered;
32240
+ continue;
32241
+ }
32242
+ }
32243
+ yield { kind: "leave-name-node", identity: entered };
32244
+ }
32245
+ }
32246
+
32247
+ // packages/pdf-ast/src/content/dictionary-cursor.ts
32248
+ var PdfDictionaryCursor = class {
32249
+ constructor(dict) {
32250
+ this.dict = dict;
32251
+ this.length = dict.storedEntries?.length ?? dict.entries.length;
32252
+ if (!Number.isSafeInteger(this.length) || this.length < 0) throw new RangeError("Invalid stored dictionary length");
32253
+ this.position = dict.storedEntries?.position ?? -1;
32254
+ }
32255
+ dict;
32256
+ index = 0;
32257
+ position;
32258
+ length;
32259
+ *next() {
32260
+ if (this.index === this.length) {
32261
+ if (this.dict.storedEntries && this.position !== -1) throw new Error("Invalid stored dictionary terminator");
32262
+ return { done: true, value: void 0 };
32263
+ }
32264
+ let entry = this.dict.entries[this.index];
32265
+ if (this.dict.storedEntries) {
32266
+ const reply = yield { kind: "dictionary-entry", entries: this.dict.storedEntries, position: this.position };
32267
+ if (reply?.kind !== "array" || reply.items[0]?.kind !== "name" || !reply.items[1] || reply.items[2]?.kind !== "number") throw new TypeError("Expected a PDF dictionary record");
32268
+ entry = { key: reply.items[0], value: reply.items[1] };
32269
+ this.position = reply.items[2].value;
32270
+ }
32271
+ this.index++;
32272
+ return { done: false, value: entry };
32273
+ }
32274
+ };
31682
32275
 
31683
32276
  // packages/pdf-ast/src/fonts/stored-widths.ts
31684
32277
  import { IntegerTable } from "@poe-platform/safe-fs/storage";
@@ -32666,13 +33259,13 @@ function embedTrueTypeFontInCos(doc, font, usedGlyphs) {
32666
33259
  }
32667
33260
 
32668
33261
  // packages/pdf-ast/src/fonts/resolve.ts
32669
- function* resolve(node, storeRootArray = false) {
32670
- const value = yield { kind: "resolve", node, storeRootArray };
33262
+ function* resolve(node, storeRootArray = false, storeRootDictionary = false) {
33263
+ const value = yield { kind: "resolve", node, storeRootArray, storeRootDictionary };
32671
33264
  if (value && !("kind" in value)) throw new TypeError("Font lookup returned stream bytes instead of a COS value");
32672
33265
  return value;
32673
33266
  }
32674
- function* resolveDict2(node) {
32675
- const value = yield* resolve(node);
33267
+ function* resolveDict2(node, backed = false) {
33268
+ const value = yield* resolve(node, false, backed);
32676
33269
  return value?.kind === "dict" ? value : value?.kind === "stream" ? value.dict : void 0;
32677
33270
  }
32678
33271
  function* resolveArray2(node, backed = false) {
@@ -32705,287 +33298,288 @@ function* resolvePageFontsSteps(rootRef, resourcesDict, selectedName, options =
32705
33298
  const catalog = yield* resolveDict2(rootRef);
32706
33299
  const acroForm = catalog ? yield* resolveDict2(dictGet(catalog, "AcroForm")) : void 0;
32707
33300
  const drDict = acroForm ? yield* resolveDict2(dictGet(acroForm, "DR")) : void 0;
32708
- const drFontDict = drDict ? yield* resolveDict2(dictGet(drDict, "Font")) : void 0;
32709
- const pageFontDict = resourcesDict ? yield* resolveDict2(dictGet(resourcesDict, "Font")) : void 0;
32710
- function* entries() {
32711
- if (drFontDict)
32712
- yield* drFontDict.entries;
32713
- if (pageFontDict)
32714
- yield* pageFontDict.entries;
32715
- }
32716
- for (const entry of entries()) {
32717
- const fName = entry.key.decoded;
32718
- if (selectedName !== void 0 && fName !== selectedName)
32719
- continue;
32720
- const fObj = yield* resolveDict2(entry.value);
32721
- if (!fObj)
32722
- continue;
32723
- allocation.admit(1024);
32724
- const subtypeNode = yield* resolve(dictGet(fObj, "Subtype"));
32725
- const subtype = subtypeNode?.kind === "name" ? subtypeNode.decoded : "Type1";
32726
- const baseFontNode = yield* resolve(dictGet(fObj, "BaseFont"));
32727
- const baseFont = baseFontNode?.kind === "name" ? baseFontNode.decoded : "Helvetica";
32728
- let cmap;
32729
- let storedCMap;
32730
- const toUniNode = yield* resolve(dictGet(fObj, "ToUnicode"));
32731
- if (toUniNode?.kind === "stream") {
32732
- try {
32733
- const value = yield { kind: "decode", stream: toUniNode, purpose: "unicode-cmap" };
32734
- if (value instanceof Uint8Array) cmap = parseToUnicodeCMap(value, allocationOptions);
32735
- else if (value && "storedCMap" in value) storedCMap = value;
32736
- else if (value && "iterateBytes" in value) cmap = value;
32737
- else throw new TypeError("Font decoder did not return a Unicode CMap");
32738
- } catch (error) {
32739
- allocation.rethrowAllocationFailure(error);
32740
- if (error instanceof PdfError && error.code === "E_LIMIT")
32741
- throw error;
33301
+ const drFontDict = drDict ? yield* resolveDict2(dictGet(drDict, "Font"), true) : void 0;
33302
+ const pageFontDict = resourcesDict ? yield* resolveDict2(dictGet(resourcesDict, "Font"), true) : void 0;
33303
+ for (const dictionary of [drFontDict, pageFontDict]) {
33304
+ if (!dictionary) continue;
33305
+ const cursor = new PdfDictionaryCursor(dictionary);
33306
+ for (; ; ) {
33307
+ const item = yield* cursor.next();
33308
+ if (item.done) break;
33309
+ const entry = item.value;
33310
+ const fName = entry.key.decoded;
33311
+ if (selectedName !== void 0 && fName !== selectedName)
33312
+ continue;
33313
+ const fObj = yield* resolveDict2(entry.value);
33314
+ if (!fObj)
33315
+ continue;
33316
+ allocation.admit(1024);
33317
+ const subtypeNode = yield* resolve(dictGet(fObj, "Subtype"));
33318
+ const subtype = subtypeNode?.kind === "name" ? subtypeNode.decoded : "Type1";
33319
+ const baseFontNode = yield* resolve(dictGet(fObj, "BaseFont"));
33320
+ const baseFont = baseFontNode?.kind === "name" ? baseFontNode.decoded : "Helvetica";
33321
+ let cmap;
33322
+ let storedCMap;
33323
+ const toUniNode = yield* resolve(dictGet(fObj, "ToUnicode"));
33324
+ if (toUniNode?.kind === "stream") {
33325
+ try {
33326
+ const value = yield { kind: "decode", stream: toUniNode, purpose: "unicode-cmap" };
33327
+ if (value instanceof Uint8Array) cmap = parseToUnicodeCMap(value, allocationOptions);
33328
+ else if (value && "storedCMap" in value) storedCMap = value;
33329
+ else if (value && "iterateBytes" in value) cmap = value;
33330
+ else throw new TypeError("Font decoder did not return a Unicode CMap");
33331
+ } catch (error) {
33332
+ allocation.rethrowAllocationFailure(error);
33333
+ if (error instanceof PdfError && error.code === "E_LIMIT")
33334
+ throw error;
33335
+ }
32742
33336
  }
32743
- }
32744
- const encNode = yield* resolve(dictGet(fObj, "Encoding"));
32745
- if (encNode?.kind === "dict") {
32746
- const diffRef = dictGet(encNode, "Differences");
32747
- if (diffRef?.kind === "ref") {
32748
- const resolvedDiff = yield* resolve(diffRef, true);
32749
- if (resolvedDiff?.kind === "array") {
32750
- dictSet(encNode, "Differences", resolvedDiff);
32751
- }
32752
- }
32753
- }
32754
- const differenceArray = encNode?.kind === "dict" ? dictGet(encNode, "Differences") : void 0;
32755
- let storedEncoding;
32756
- if (options.resourceStorage && differenceArray?.kind === "array") {
32757
- const value = yield { kind: "font-encoding", array: differenceArray };
32758
- if (!value || !("storedEncoding" in value)) throw new TypeError("Expected stored font encoding");
32759
- storedEncoding = value;
32760
- }
32761
- allocation.admit(32768 + (!storedEncoding && differenceArray?.kind === "array" ? differenceArray.items.length * 128 : 0));
32762
- const differences = storedEncoding ? /* @__PURE__ */ new Map() : buildFontEncodingDifferencesMap(encNode);
32763
- const glyphNames = storedEncoding ? /* @__PURE__ */ new Map() : buildFontEncodingGlyphNamesMap(encNode);
32764
- function* glyphName(code) {
32765
- if (!storedEncoding) return glyphNames.get(code);
32766
- const result = yield { kind: "font-label", lookup: storedEncoding.glyphName, code };
32767
- return result && "kind" in result && result.kind === "name" ? result.decoded : void 0;
32768
- }
32769
- const widths = options.resourceStorage ? new StoredFontWidths(options.resourceStorage, { ...allocationOptions, ...options.signal ? { signal: options.signal } : {} }) : new FontWidths(allocation);
32770
- function* setWidth(first, width, last = first) {
32771
- if (widths instanceof StoredFontWidths) yield { kind: "font-width-set", widths, first, width, last };
32772
- else widths.set(first, width, last);
32773
- }
32774
- let defaultWidth = 556;
32775
- const isTwoByteCid = subtype === "Type0";
32776
- let fontMatrix;
32777
- let charProcs;
32778
- let fontResources;
32779
- if (subtype === "Type3") {
32780
- const fmArr = yield* resolveArray2(dictGet(fObj, "FontMatrix"));
32781
- if (fmArr && fmArr.items.length >= 6) {
32782
- const mn = function* (idx, fb = 0) {
32783
- const r = yield* resolve(fmArr.items[idx]);
32784
- return r?.kind === "number" ? r.value : fb;
32785
- };
32786
- fontMatrix = [yield* mn(0, 1e-3), yield* mn(1, 0), yield* mn(2, 0), yield* mn(3, 1e-3), yield* mn(4, 0), yield* mn(5, 0)];
32787
- } else {
32788
- fontMatrix = [1e-3, 0, 0, 1e-3, 0, 0];
32789
- }
32790
- charProcs = yield* resolveDict2(dictGet(fObj, "CharProcs"));
32791
- fontResources = yield* resolveDict2(dictGet(fObj, "Resources"));
32792
- }
32793
- const type3Scale1000 = subtype === "Type3" && fontMatrix ? Math.hypot(fontMatrix[0], fontMatrix[1]) * 1e3 : 1;
32794
- if (subtype === "Type0") {
32795
- const descArr = yield* resolveArray2(dictGet(fObj, "DescendantFonts"));
32796
- const cidDict = descArr && descArr.items[0] ? yield* resolveDict2(descArr.items[0]) : void 0;
32797
- if (cidDict) {
32798
- const dwNode = yield* resolve(dictGet(cidDict, "DW"));
32799
- if (dwNode?.kind === "number")
32800
- defaultWidth = dwNode.value;
32801
- const wArr = yield* resolveArray2(dictGet(cidDict, "W"), true);
32802
- if (wArr) {
32803
- const cursor = arrayCursor(wArr);
32804
- while (cursor.remaining) {
32805
- const first = yield* resolve(yield* cursor.next(), true);
32806
- const second = yield* resolve(yield* cursor.next(), true);
32807
- if (first?.kind === "number" && second?.kind === "array") {
32808
- const nested = arrayCursor(second);
32809
- for (let k = 0; nested.remaining; k++) {
32810
- const wItem = yield* resolve(yield* nested.next());
32811
- if (wItem?.kind === "number") {
32812
- yield* setWidth(first.value + k, wItem.value);
32813
- }
32814
- }
32815
- } else if (first?.kind === "number" && second?.kind === "number") {
32816
- const third = yield* resolve(yield* cursor.next(), true);
32817
- if (third?.kind === "number") {
32818
- if (!Number.isSafeInteger(first.value) || !Number.isSafeInteger(second.value))
32819
- throw new PdfError("E_LIMIT", "Unsafe PDF font width range");
32820
- yield* setWidth(first.value, third.value, second.value);
32821
- }
32822
- }
33337
+ const encNode = yield* resolve(dictGet(fObj, "Encoding"));
33338
+ if (encNode?.kind === "dict") {
33339
+ const diffRef = dictGet(encNode, "Differences");
33340
+ if (diffRef?.kind === "ref") {
33341
+ const resolvedDiff = yield* resolve(diffRef, true);
33342
+ if (resolvedDiff?.kind === "array") {
33343
+ dictSet(encNode, "Differences", resolvedDiff);
32823
33344
  }
32824
33345
  }
32825
33346
  }
32826
- } else {
32827
- const firstCharNode = yield* resolve(dictGet(fObj, "FirstChar"));
32828
- const widthsArr = yield* resolveArray2(dictGet(fObj, "Widths"), true);
32829
- if (widthsArr) {
32830
- const descriptor = yield* resolveDict2(dictGet(fObj, "FontDescriptor"));
32831
- const missingWidth = descriptor ? yield* resolve(dictGet(descriptor, "MissingWidth")) : void 0;
32832
- defaultWidth = (missingWidth?.kind === "number" ? missingWidth.value : 0) * type3Scale1000;
32833
- const firstChar = firstCharNode?.kind === "number" ? firstCharNode.value : 0;
32834
- const cursor = arrayCursor(widthsArr);
32835
- for (let k = 0; cursor.remaining; k++) {
32836
- const wItem = yield* resolve(yield* cursor.next());
32837
- if (wItem?.kind === "number") {
32838
- yield* setWidth(firstChar + k, wItem.value * type3Scale1000);
33347
+ const differenceArray = encNode?.kind === "dict" ? dictGet(encNode, "Differences") : void 0;
33348
+ let storedEncoding;
33349
+ if (options.resourceStorage && differenceArray?.kind === "array") {
33350
+ const value = yield { kind: "font-encoding", array: differenceArray };
33351
+ if (!value || !("storedEncoding" in value)) throw new TypeError("Expected stored font encoding");
33352
+ storedEncoding = value;
33353
+ }
33354
+ allocation.admit(32768 + (!storedEncoding && differenceArray?.kind === "array" ? differenceArray.items.length * 128 : 0));
33355
+ const differences = storedEncoding ? /* @__PURE__ */ new Map() : buildFontEncodingDifferencesMap(encNode);
33356
+ const glyphNames = storedEncoding ? /* @__PURE__ */ new Map() : buildFontEncodingGlyphNamesMap(encNode);
33357
+ function* glyphName(code) {
33358
+ if (!storedEncoding) return glyphNames.get(code);
33359
+ const result = yield { kind: "font-label", lookup: storedEncoding.glyphName, code };
33360
+ return result && "kind" in result && result.kind === "name" ? result.decoded : void 0;
33361
+ }
33362
+ const widths = options.resourceStorage ? new StoredFontWidths(options.resourceStorage, { ...allocationOptions, ...options.signal ? { signal: options.signal } : {} }) : new FontWidths(allocation);
33363
+ function* setWidth(first, width, last = first) {
33364
+ if (widths instanceof StoredFontWidths) yield { kind: "font-width-set", widths, first, width, last };
33365
+ else widths.set(first, width, last);
33366
+ }
33367
+ let defaultWidth = 556;
33368
+ const isTwoByteCid = subtype === "Type0";
33369
+ let fontMatrix;
33370
+ let charProcs;
33371
+ let fontResources;
33372
+ if (subtype === "Type3") {
33373
+ const fmArr = yield* resolveArray2(dictGet(fObj, "FontMatrix"));
33374
+ if (fmArr && fmArr.items.length >= 6) {
33375
+ const mn = function* (idx, fb = 0) {
33376
+ const r = yield* resolve(fmArr.items[idx]);
33377
+ return r?.kind === "number" ? r.value : fb;
33378
+ };
33379
+ fontMatrix = [yield* mn(0, 1e-3), yield* mn(1, 0), yield* mn(2, 0), yield* mn(3, 1e-3), yield* mn(4, 0), yield* mn(5, 0)];
33380
+ } else {
33381
+ fontMatrix = [1e-3, 0, 0, 1e-3, 0, 0];
33382
+ }
33383
+ charProcs = yield* resolveDict2(dictGet(fObj, "CharProcs"));
33384
+ fontResources = yield* resolveDict2(dictGet(fObj, "Resources"));
33385
+ }
33386
+ const type3Scale1000 = subtype === "Type3" && fontMatrix ? Math.hypot(fontMatrix[0], fontMatrix[1]) * 1e3 : 1;
33387
+ if (subtype === "Type0") {
33388
+ const descArr = yield* resolveArray2(dictGet(fObj, "DescendantFonts"));
33389
+ const cidDict = descArr && descArr.items[0] ? yield* resolveDict2(descArr.items[0]) : void 0;
33390
+ if (cidDict) {
33391
+ const dwNode = yield* resolve(dictGet(cidDict, "DW"));
33392
+ if (dwNode?.kind === "number")
33393
+ defaultWidth = dwNode.value;
33394
+ const wArr = yield* resolveArray2(dictGet(cidDict, "W"), true);
33395
+ if (wArr) {
33396
+ const cursor2 = arrayCursor(wArr);
33397
+ while (cursor2.remaining) {
33398
+ const first = yield* resolve(yield* cursor2.next(), true);
33399
+ const second = yield* resolve(yield* cursor2.next(), true);
33400
+ if (first?.kind === "number" && second?.kind === "array") {
33401
+ const nested = arrayCursor(second);
33402
+ for (let k = 0; nested.remaining; k++) {
33403
+ const wItem = yield* resolve(yield* nested.next());
33404
+ if (wItem?.kind === "number") {
33405
+ yield* setWidth(first.value + k, wItem.value);
33406
+ }
33407
+ }
33408
+ } else if (first?.kind === "number" && second?.kind === "number") {
33409
+ const third = yield* resolve(yield* cursor2.next(), true);
33410
+ if (third?.kind === "number") {
33411
+ if (!Number.isSafeInteger(first.value) || !Number.isSafeInteger(second.value))
33412
+ throw new PdfError("E_LIMIT", "Unsafe PDF font width range");
33413
+ yield* setWidth(first.value, third.value, second.value);
33414
+ }
33415
+ }
33416
+ }
32839
33417
  }
32840
33418
  }
32841
33419
  } else {
32842
- const stdMetrics = STANDARD_14_FONTS[normalizeStandard14FontName(baseFont)];
32843
- defaultWidth = stdMetrics.defaultWidth;
32844
- if (widths instanceof StoredFontWidths) widths.setDefaults(stdMetrics.widthsByCode);
32845
- else for (const [codeStr, wVal] of Object.entries(stdMetrics.widthsByCode)) {
32846
- yield* setWidth(Number(codeStr), wVal);
32847
- }
32848
- }
32849
- }
32850
- let embeddedCff;
32851
- let storedTrueType;
32852
- let embeddedTrueType;
32853
- let simpleToGid;
32854
- const fDescDirect = yield* resolveDict2(dictGet(fObj, "FontDescriptor"));
32855
- const descArrForTt = subtype === "Type0" ? yield* resolveArray2(dictGet(fObj, "DescendantFonts")) : void 0;
32856
- const cidDictForTt = descArrForTt && descArrForTt.items[0] ? yield* resolveDict2(descArrForTt.items[0]) : void 0;
32857
- const fDesc = fDescDirect ?? (cidDictForTt ? yield* resolveDict2(dictGet(cidDictForTt, "FontDescriptor")) : void 0);
32858
- let cidToGid;
32859
- let storedCidToGid;
32860
- const cidMap = cidDictForTt ? yield* resolve(dictGet(cidDictForTt, "CIDToGIDMap")) : void 0;
32861
- if (cidMap?.kind === "stream") {
32862
- const bytes = yield { kind: "decode", stream: cidMap, purpose: "cid-map" };
32863
- if (bytes && "byteLength" in bytes && "storage" in bytes) storedCidToGid = bytes;
32864
- else if (bytes instanceof Uint8Array) {
32865
- allocation.admit(Math.ceil(bytes.length / 2) * 2);
32866
- cidToGid = new Uint16Array(Math.ceil(bytes.length / 2));
32867
- for (let i = 0; i < bytes.length; i += 2)
32868
- cidToGid[i / 2] = bytes[i] << 8 | (bytes[i + 1] ?? 0);
32869
- } else throw new TypeError("Font decoder did not return CID map bytes");
32870
- }
32871
- if (fDesc) {
32872
- const type1Program = yield* resolve(dictGet(fDesc, "FontFile"));
32873
- const program = (yield* resolve(dictGet(fDesc, "FontFile2"))) ?? (yield* resolve(dictGet(fDesc, "FontFile3"))) ?? type1Program;
32874
- if (program?.kind === "stream") {
32875
- const programType = yield* resolve(dictGet(program.dict, "Subtype"));
32876
- const baseEncoding = encNode?.kind === "dict" ? yield* resolve(dictGet(encNode, "BaseEncoding")) : encNode;
32877
- if (program === type1Program) {
32878
- const length1 = yield* resolve(dictGet(program.dict, "Length1"));
32879
- const length2 = yield* resolve(dictGet(program.dict, "Length2"));
32880
- const flags = yield* resolve(dictGet(fDesc, "Flags"));
32881
- const type1Properties = {
32882
- length1: length1?.kind === "number" ? length1.value : 0,
32883
- length2: length2?.kind === "number" ? length2.value : 0,
32884
- flags: flags?.kind === "number" ? flags.value : 0,
32885
- fontMatrix: [1e-3, 0, 0, 1e-3, 0, 0],
32886
- bbox: [0, 0, 0, 0],
32887
- baseEncodingName: baseEncoding?.kind === "name" ? baseEncoding.decoded : void 0,
32888
- differences: glyphNames,
32889
- overridableEncoding: true,
32890
- widths: widths instanceof FontWidths ? widths.createType1View() : {},
32891
- composite: subtype === "Type0",
32892
- cMap: { charCodeOf: (cid) => cid }
32893
- };
32894
- const decoded = yield { kind: "decode", stream: program, purpose: "type1", type1Properties, ...storedEncoding ? { storedEncoding } : {} };
32895
- if (decoded && "storedCff" in decoded) embeddedCff = decoded;
32896
- else if (decoded instanceof Uint8Array) embeddedCff = parseEmbeddedType1Font(decoded, type1Properties, allocationOptions);
32897
- else throw new TypeError("Font decoder did not return a Type1 font");
32898
- } else if (programType?.kind === "name" && (programType.decoded === "Type1C" || programType.decoded === "CIDFontType0C")) {
32899
- const encodingName = baseEncoding?.kind === "name" ? baseEncoding.decoded : void 0;
32900
- const decoded = yield { kind: "decode", stream: program, purpose: "cff", encodingName, differences: glyphNames, ...storedEncoding ? { storedEncoding } : {} };
32901
- if (decoded && "storedCff" in decoded) embeddedCff = decoded;
32902
- else if (decoded instanceof Uint8Array) embeddedCff = parseEmbeddedCffFont(decoded, encodingName, glyphNames, allocationOptions);
32903
- else throw new TypeError("Font decoder did not return a CFF font");
33420
+ const firstCharNode = yield* resolve(dictGet(fObj, "FirstChar"));
33421
+ const widthsArr = yield* resolveArray2(dictGet(fObj, "Widths"), true);
33422
+ if (widthsArr) {
33423
+ const descriptor = yield* resolveDict2(dictGet(fObj, "FontDescriptor"));
33424
+ const missingWidth = descriptor ? yield* resolve(dictGet(descriptor, "MissingWidth")) : void 0;
33425
+ defaultWidth = (missingWidth?.kind === "number" ? missingWidth.value : 0) * type3Scale1000;
33426
+ const firstChar = firstCharNode?.kind === "number" ? firstCharNode.value : 0;
33427
+ const cursor2 = arrayCursor(widthsArr);
33428
+ for (let k = 0; cursor2.remaining; k++) {
33429
+ const wItem = yield* resolve(yield* cursor2.next());
33430
+ if (wItem?.kind === "number") {
33431
+ yield* setWidth(firstChar + k, wItem.value * type3Scale1000);
33432
+ }
33433
+ }
32904
33434
  } else {
32905
- const decoded = yield { kind: "decode", stream: program, purpose: "truetype" };
32906
- if (decoded && "getGlyphId" in decoded) storedTrueType = decoded;
32907
- else if (decoded instanceof Uint8Array) embeddedTrueType = parseTrueTypeFont(decoded, allocationOptions);
32908
- else throw new TypeError("Font decoder did not return a TrueType font");
32909
- if (storedTrueType && subtype !== "Type0" && (storedTrueType.isSymbolicCmap || !storedTrueType.hasCmap)) {
32910
- simpleToGid = /* @__PURE__ */ new Map();
32911
- const encoding = baseEncoding?.kind === "name" ? getEncoding(baseEncoding.decoded) : void 0;
32912
- for (let code = 0; code < 256; code++) {
32913
- let result;
32914
- if (storedTrueType.isSymbolicCmap) {
32915
- result = yield { kind: "truetype-map", font: storedTrueType, code: 61440 + code };
32916
- if (result && "kind" in result && result.kind === "number" && result.value === 0) result = yield { kind: "truetype-map", font: storedTrueType, code };
32917
- } else {
33435
+ const stdMetrics = STANDARD_14_FONTS[normalizeStandard14FontName(baseFont)];
33436
+ defaultWidth = stdMetrics.defaultWidth;
33437
+ if (widths instanceof StoredFontWidths) widths.setDefaults(stdMetrics.widthsByCode);
33438
+ else for (const [codeStr, wVal] of Object.entries(stdMetrics.widthsByCode)) {
33439
+ yield* setWidth(Number(codeStr), wVal);
33440
+ }
33441
+ }
33442
+ }
33443
+ let embeddedCff;
33444
+ let storedTrueType;
33445
+ let embeddedTrueType;
33446
+ let simpleToGid;
33447
+ const fDescDirect = yield* resolveDict2(dictGet(fObj, "FontDescriptor"));
33448
+ const descArrForTt = subtype === "Type0" ? yield* resolveArray2(dictGet(fObj, "DescendantFonts")) : void 0;
33449
+ const cidDictForTt = descArrForTt && descArrForTt.items[0] ? yield* resolveDict2(descArrForTt.items[0]) : void 0;
33450
+ const fDesc = fDescDirect ?? (cidDictForTt ? yield* resolveDict2(dictGet(cidDictForTt, "FontDescriptor")) : void 0);
33451
+ let cidToGid;
33452
+ let storedCidToGid;
33453
+ const cidMap = cidDictForTt ? yield* resolve(dictGet(cidDictForTt, "CIDToGIDMap")) : void 0;
33454
+ if (cidMap?.kind === "stream") {
33455
+ const bytes = yield { kind: "decode", stream: cidMap, purpose: "cid-map" };
33456
+ if (bytes && "byteLength" in bytes && "storage" in bytes) storedCidToGid = bytes;
33457
+ else if (bytes instanceof Uint8Array) {
33458
+ allocation.admit(Math.ceil(bytes.length / 2) * 2);
33459
+ cidToGid = new Uint16Array(Math.ceil(bytes.length / 2));
33460
+ for (let i = 0; i < bytes.length; i += 2)
33461
+ cidToGid[i / 2] = bytes[i] << 8 | (bytes[i + 1] ?? 0);
33462
+ } else throw new TypeError("Font decoder did not return CID map bytes");
33463
+ }
33464
+ if (fDesc) {
33465
+ const type1Program = yield* resolve(dictGet(fDesc, "FontFile"));
33466
+ const program = (yield* resolve(dictGet(fDesc, "FontFile2"))) ?? (yield* resolve(dictGet(fDesc, "FontFile3"))) ?? type1Program;
33467
+ if (program?.kind === "stream") {
33468
+ const programType = yield* resolve(dictGet(program.dict, "Subtype"));
33469
+ const baseEncoding = encNode?.kind === "dict" ? yield* resolve(dictGet(encNode, "BaseEncoding")) : encNode;
33470
+ if (program === type1Program) {
33471
+ const length1 = yield* resolve(dictGet(program.dict, "Length1"));
33472
+ const length2 = yield* resolve(dictGet(program.dict, "Length2"));
33473
+ const flags = yield* resolve(dictGet(fDesc, "Flags"));
33474
+ const type1Properties = {
33475
+ length1: length1?.kind === "number" ? length1.value : 0,
33476
+ length2: length2?.kind === "number" ? length2.value : 0,
33477
+ flags: flags?.kind === "number" ? flags.value : 0,
33478
+ fontMatrix: [1e-3, 0, 0, 1e-3, 0, 0],
33479
+ bbox: [0, 0, 0, 0],
33480
+ baseEncodingName: baseEncoding?.kind === "name" ? baseEncoding.decoded : void 0,
33481
+ differences: glyphNames,
33482
+ overridableEncoding: true,
33483
+ widths: widths instanceof FontWidths ? widths.createType1View() : {},
33484
+ composite: subtype === "Type0",
33485
+ cMap: { charCodeOf: (cid) => cid }
33486
+ };
33487
+ const decoded = yield { kind: "decode", stream: program, purpose: "type1", type1Properties, ...storedEncoding ? { storedEncoding } : {} };
33488
+ if (decoded && "storedCff" in decoded) embeddedCff = decoded;
33489
+ else if (decoded instanceof Uint8Array) embeddedCff = parseEmbeddedType1Font(decoded, type1Properties, allocationOptions);
33490
+ else throw new TypeError("Font decoder did not return a Type1 font");
33491
+ } else if (programType?.kind === "name" && (programType.decoded === "Type1C" || programType.decoded === "CIDFontType0C")) {
33492
+ const encodingName = baseEncoding?.kind === "name" ? baseEncoding.decoded : void 0;
33493
+ const decoded = yield { kind: "decode", stream: program, purpose: "cff", encodingName, differences: glyphNames, ...storedEncoding ? { storedEncoding } : {} };
33494
+ if (decoded && "storedCff" in decoded) embeddedCff = decoded;
33495
+ else if (decoded instanceof Uint8Array) embeddedCff = parseEmbeddedCffFont(decoded, encodingName, glyphNames, allocationOptions);
33496
+ else throw new TypeError("Font decoder did not return a CFF font");
33497
+ } else {
33498
+ const decoded = yield { kind: "decode", stream: program, purpose: "truetype" };
33499
+ if (decoded && "getGlyphId" in decoded) storedTrueType = decoded;
33500
+ else if (decoded instanceof Uint8Array) embeddedTrueType = parseTrueTypeFont(decoded, allocationOptions);
33501
+ else throw new TypeError("Font decoder did not return a TrueType font");
33502
+ if (storedTrueType && subtype !== "Type0" && (storedTrueType.isSymbolicCmap || !storedTrueType.hasCmap)) {
33503
+ simpleToGid = /* @__PURE__ */ new Map();
33504
+ const encoding = baseEncoding?.kind === "name" ? getEncoding(baseEncoding.decoded) : void 0;
33505
+ for (let code = 0; code < 256; code++) {
33506
+ let result;
33507
+ if (storedTrueType.isSymbolicCmap) {
33508
+ result = yield { kind: "truetype-map", font: storedTrueType, code: 61440 + code };
33509
+ if (result && "kind" in result && result.kind === "number" && result.value === 0) result = yield { kind: "truetype-map", font: storedTrueType, code };
33510
+ } else {
33511
+ const name = (yield* glyphName(code)) || encoding?.[code];
33512
+ if (!name) continue;
33513
+ result = yield { kind: "truetype-map", font: storedTrueType, name };
33514
+ }
33515
+ if (!result || !("kind" in result) || result.kind !== "number") throw new TypeError("Expected TrueType glyph ID");
33516
+ if (result.value > 0) simpleToGid.set(code, result.value);
33517
+ }
33518
+ }
33519
+ if (subtype !== "Type0" && embeddedTrueType?.isSymbolicCmap) {
33520
+ simpleToGid = /* @__PURE__ */ new Map();
33521
+ for (let code = 0; code < 256; code++) {
33522
+ const gid = embeddedTrueType.getGlyphId(61440 + code) || embeddedTrueType.getGlyphId(code);
33523
+ if (gid > 0)
33524
+ simpleToGid.set(code, gid);
33525
+ }
33526
+ } else if (subtype !== "Type0" && embeddedTrueType && !embeddedTrueType.hasCmap) {
33527
+ simpleToGid = /* @__PURE__ */ new Map();
33528
+ const encoding = baseEncoding?.kind === "name" ? getEncoding(baseEncoding.decoded) : void 0;
33529
+ for (let code = 0; code < 256; code++) {
32918
33530
  const name = (yield* glyphName(code)) || encoding?.[code];
32919
- if (!name) continue;
32920
- result = yield { kind: "truetype-map", font: storedTrueType, name };
33531
+ const gid = name ? embeddedTrueType.glyphNames.indexOf(name) : -1;
33532
+ if (gid > 0)
33533
+ simpleToGid.set(code, gid);
32921
33534
  }
32922
- if (!result || !("kind" in result) || result.kind !== "number") throw new TypeError("Expected TrueType glyph ID");
32923
- if (result.value > 0) simpleToGid.set(code, result.value);
32924
33535
  }
32925
33536
  }
32926
- if (subtype !== "Type0" && embeddedTrueType?.isSymbolicCmap) {
32927
- simpleToGid = /* @__PURE__ */ new Map();
32928
- for (let code = 0; code < 256; code++) {
32929
- const gid = embeddedTrueType.getGlyphId(61440 + code) || embeddedTrueType.getGlyphId(code);
32930
- if (gid > 0)
32931
- simpleToGid.set(code, gid);
32932
- }
32933
- } else if (subtype !== "Type0" && embeddedTrueType && !embeddedTrueType.hasCmap) {
32934
- simpleToGid = /* @__PURE__ */ new Map();
32935
- const encoding = baseEncoding?.kind === "name" ? getEncoding(baseEncoding.decoded) : void 0;
32936
- for (let code = 0; code < 256; code++) {
32937
- const name = (yield* glyphName(code)) || encoding?.[code];
32938
- const gid = name ? embeddedTrueType.glyphNames.indexOf(name) : -1;
32939
- if (gid > 0)
32940
- simpleToGid.set(code, gid);
32941
- }
33537
+ for (const [code, unicode] of embeddedCff?.unicodeByCode ?? []) {
33538
+ if (!differences.has(code))
33539
+ differences.set(code, unicode);
32942
33540
  }
32943
33541
  }
32944
- for (const [code, unicode] of embeddedCff?.unicodeByCode ?? []) {
32945
- if (!differences.has(code))
32946
- differences.set(code, unicode);
32947
- }
32948
- }
32949
- }
32950
- const standardOutlines = !embeddedTrueType && !storedTrueType && !embeddedCff && subtype !== "Type3" ? getStandardFontOutlines(baseFont, options.onAllocation ? allocationOptions : {}) : void 0;
32951
- for (const [code, unicode] of standardOutlines?.defaultUnicode ?? []) {
32952
- if (!differences.has(code))
32953
- differences.set(code, unicode);
32954
- }
32955
- let encodingCMap;
32956
- let storedEncodingCMap;
32957
- if (subtype === "Type0" && encNode?.kind === "stream") {
32958
- const value = yield { kind: "decode", stream: encNode, purpose: "encoding-cmap" };
32959
- if (value instanceof Uint8Array) encodingCMap = parseCharacterCMap(value, allocationOptions);
32960
- else if (value && "storedCMap" in value) storedEncodingCMap = value;
32961
- else if (value && "lookup" in value) encodingCMap = value;
32962
- else throw new TypeError("Font decoder did not return an encoding CMap");
32963
- }
32964
- fonts.set(fName, {
32965
- name: fName,
32966
- baseFont,
32967
- subtype,
32968
- isTwoByteCid,
32969
- cmap,
32970
- encodingCMap,
32971
- storedCMap,
32972
- storedEncodingCMap,
32973
- differences,
32974
- glyphNames,
32975
- widths,
32976
- defaultWidth,
32977
- fontMatrix,
32978
- charProcs,
32979
- fontResources,
32980
- embeddedTrueType,
32981
- storedTrueType,
32982
- cidToGid,
32983
- storedCidToGid,
32984
- ...storedEncoding ? { storedEncoding } : {},
32985
- simpleToGid,
32986
- embeddedCff,
32987
- standardOutlines
32988
- });
33542
+ }
33543
+ const standardOutlines = !embeddedTrueType && !storedTrueType && !embeddedCff && subtype !== "Type3" ? getStandardFontOutlines(baseFont, options.onAllocation ? allocationOptions : {}) : void 0;
33544
+ for (const [code, unicode] of standardOutlines?.defaultUnicode ?? []) {
33545
+ if (!differences.has(code))
33546
+ differences.set(code, unicode);
33547
+ }
33548
+ let encodingCMap;
33549
+ let storedEncodingCMap;
33550
+ if (subtype === "Type0" && encNode?.kind === "stream") {
33551
+ const value = yield { kind: "decode", stream: encNode, purpose: "encoding-cmap" };
33552
+ if (value instanceof Uint8Array) encodingCMap = parseCharacterCMap(value, allocationOptions);
33553
+ else if (value && "storedCMap" in value) storedEncodingCMap = value;
33554
+ else if (value && "lookup" in value) encodingCMap = value;
33555
+ else throw new TypeError("Font decoder did not return an encoding CMap");
33556
+ }
33557
+ fonts.set(fName, {
33558
+ name: fName,
33559
+ baseFont,
33560
+ subtype,
33561
+ isTwoByteCid,
33562
+ cmap,
33563
+ encodingCMap,
33564
+ storedCMap,
33565
+ storedEncodingCMap,
33566
+ differences,
33567
+ glyphNames,
33568
+ widths,
33569
+ defaultWidth,
33570
+ fontMatrix,
33571
+ charProcs,
33572
+ fontResources,
33573
+ embeddedTrueType,
33574
+ storedTrueType,
33575
+ cidToGid,
33576
+ storedCidToGid,
33577
+ ...storedEncoding ? { storedEncoding } : {},
33578
+ simpleToGid,
33579
+ embeddedCff,
33580
+ standardOutlines
33581
+ });
33582
+ }
32989
33583
  }
32990
33584
  return fonts;
32991
33585
  }
@@ -32996,7 +33590,7 @@ function resolvePageFonts(doc, resourcesDict, selectedName) {
32996
33590
  while (!step.done) {
32997
33591
  let value;
32998
33592
  try {
32999
- if (step.value.kind === "font-encoding" || step.value.kind === "font-label" || step.value.kind === "array-item" || step.value.kind === "truetype-map" || step.value.kind === "font-width-set") throw new TypeError("Stored font requires asynchronous evaluation");
33593
+ if (step.value.kind === "dictionary-entry" || step.value.kind === "font-encoding" || step.value.kind === "font-label" || step.value.kind === "array-item" || step.value.kind === "truetype-map" || step.value.kind === "font-width-set") throw new TypeError("Stored font requires asynchronous evaluation");
33000
33594
  value = step.value.kind === "resolve" ? doc.resolve(step.value.node) : doc.decodeStream(step.value.stream);
33001
33595
  } catch (error) {
33002
33596
  step = steps.throw(error);
@@ -43943,10 +44537,10 @@ function extractPageAnnotations(cosDoc, pageDict) {
43943
44537
  while (!step2.done) {
43944
44538
  const request = step2.value;
43945
44539
  if (request.kind === "resolve") step2 = work2.next(cosDoc.resolve(request.node));
43946
- else if (request.kind === "push-page-frame") {
44540
+ else if (request.kind === "push-traversal-frame") {
43947
44541
  frames.push(request.frame);
43948
44542
  step2 = work2.next();
43949
- } else if (request.kind === "pop-page-frame") step2 = work2.next(frames.pop());
44543
+ } else if (request.kind === "pop-traversal-frame") step2 = work2.next(frames.pop());
43950
44544
  else if (request.kind === "visit-page") {
43951
44545
  const number = request.reference.objectNumber, added = !visited.has(number);
43952
44546
  visited.add(number);
@@ -43955,6 +44549,36 @@ function extractPageAnnotations(cosDoc, pageDict) {
43955
44549
  }
43956
44550
  return step2.value;
43957
44551
  }
44552
+ function namedDestination(node, name) {
44553
+ const identities = /* @__PURE__ */ new Map(), active = /* @__PURE__ */ new Set(), frames = [];
44554
+ const work2 = annotationNameDestinationSteps(node, name);
44555
+ let step2 = work2.next();
44556
+ while (!step2.done) {
44557
+ const request = step2.value;
44558
+ if (request.kind === "resolve") step2 = work2.next(cosDoc.resolve(request.node));
44559
+ else if (request.kind === "push-traversal-frame") {
44560
+ frames.push(request.frame);
44561
+ step2 = work2.next();
44562
+ } else if (request.kind === "pop-traversal-frame") step2 = work2.next(frames.pop());
44563
+ else if (request.kind === "enter-name-node") {
44564
+ const node2 = request.node, key = node2.kind === "ref" ? `${node2.objectNumber}:${node2.generationNumber}` : node2;
44565
+ let id = identities.get(key);
44566
+ if (id === void 0) {
44567
+ id = identities.size;
44568
+ identities.set(key, id);
44569
+ }
44570
+ if (active.has(id)) step2 = work2.next();
44571
+ else {
44572
+ active.add(id);
44573
+ step2 = work2.next(id);
44574
+ }
44575
+ } else if (request.kind === "leave-name-node") {
44576
+ active.delete(request.identity);
44577
+ step2 = work2.next();
44578
+ } else throw new TypeError("Unexpected annotation name lookup request");
44579
+ }
44580
+ return step2.value;
44581
+ }
43958
44582
  const output = [];
43959
44583
  const work = extractPageAnnotationSteps(pageDict, cosDoc.rootRef);
43960
44584
  let step = work.next();
@@ -43965,6 +44589,7 @@ function extractPageAnnotations(cosDoc, pageDict) {
43965
44589
  step = work.next();
43966
44590
  } else if (request.kind === "resolve") step = work.next(cosDoc.resolve(request.node));
43967
44591
  else if (request.kind === "page-number") step = work.next(pageNumber(request.reference));
44592
+ else if (request.kind === "named-destination") step = work.next(namedDestination(request.node, request.name));
43968
44593
  else throw new TypeError("Unexpected annotation request");
43969
44594
  }
43970
44595
  return output;
@@ -44006,8 +44631,8 @@ function* preparePageAppearanceSteps(pageDict, pageRes, evalResourcesDict, hideA
44006
44631
  const sub = yield* resolveDict3(entry.value, [entry.key.decoded]);
44007
44632
  if (sub) {
44008
44633
  onAllocation?.(64 + sub.entries.length * 64);
44009
- const clonedSub = cosDict({});
44010
- for (const se of sub.entries) dictSet(clonedSub, se.key.decoded, se.value);
44634
+ const clonedSub = sub.storedEntries ? yield { kind: "dictionary-merge", destination: sub } : cosDict({});
44635
+ if (!sub.storedEntries) for (const se of sub.entries) dictSet(clonedSub, se.key.decoded, se.value);
44011
44636
  dictSet(evalResourcesDict, entry.key.decoded, clonedSub);
44012
44637
  } else {
44013
44638
  dictSet(evalResourcesDict, entry.key.decoded, entry.value);
@@ -44060,6 +44685,11 @@ function* preparePageAppearanceSteps(pageDict, pageRes, evalResourcesDict, hideA
44060
44685
  dstSub = cosDict({});
44061
44686
  dictSet(evalResourcesDict, subKey, dstSub);
44062
44687
  }
44688
+ if (srcSub.storedEntries || dstSub.storedEntries) {
44689
+ const merged = yield { kind: "dictionary-merge", destination: dstSub, source: srcSub };
44690
+ dictSet(evalResourcesDict, subKey, merged);
44691
+ continue;
44692
+ }
44063
44693
  for (const se of srcSub.entries) {
44064
44694
  if (!dictGet(dstSub, se.key.decoded)) {
44065
44695
  onAllocation?.(64);
@@ -45812,7 +46442,7 @@ var PdfPage = class {
45812
46442
  const request = step.value;
45813
46443
  if (request.kind === "resolve" || request.kind === "catalog") {
45814
46444
  step = work.next(this.cosDoc.resolve(request.kind === "catalog" ? this.cosDoc.rootRef : request.node));
45815
- } else if (request.kind === "array-reference" || request.kind === "array-item") throw new TypeError("Stored visibility requires asynchronous evaluation");
46445
+ } else if (request.kind === "dictionary-merge" || request.kind === "array-reference" || request.kind === "array-item") throw new TypeError("Stored visibility requires asynchronous evaluation");
45816
46446
  else if (request.kind === "appearance-content") {
45817
46447
  appearance = parseContentStream(this.cosDoc.decodeStream(request.stream));
45818
46448
  step = work.next(appearance.length > 0);
@@ -48089,7 +48719,7 @@ async function renderRetainedPagePixels(page2, storage, options = {}) {
48089
48719
  }
48090
48720
 
48091
48721
  // packages/pdf-ast/src/cos/range-parser.ts
48092
- import { listenForAbort } from "@poe-platform/safe-fs/contracts";
48722
+ import { listenForAbort as listenForAbort2 } from "@poe-platform/safe-fs/contracts";
48093
48723
  function limit(value, name) {
48094
48724
  const result = value ?? Infinity;
48095
48725
  if (result !== Infinity && (!Number.isSafeInteger(result) || result < 0)) throw new RangeError(`Invalid ${name}`);
@@ -48141,7 +48771,7 @@ async function resolveStreamLength(entry, options) {
48141
48771
  let dispose = () => {
48142
48772
  };
48143
48773
  const cancelled = new Promise((ignored, reject) => {
48144
- dispose = listenForAbort(signal, () => reject(signal.reason));
48774
+ dispose = listenForAbort2(signal, () => reject(signal.reason));
48145
48775
  });
48146
48776
  const pending = Promise.resolve().then(() => {
48147
48777
  signal.throwIfAborted();
@@ -48156,6 +48786,7 @@ async function resolveStreamLength(entry, options) {
48156
48786
  async function readValue(lexer, depth, nodes, options) {
48157
48787
  const { signal } = options;
48158
48788
  const work = parseValueSteps(lexer, depth, options.recovery === "repair", nodes, options);
48789
+ const containers = options.containerStorage ? new StoredMetadataStack(options.containerStorage, signal) : void 0;
48159
48790
  let value;
48160
48791
  let turns = 0;
48161
48792
  try {
@@ -48163,15 +48794,25 @@ async function readValue(lexer, depth, nodes, options) {
48163
48794
  while (!step.done) {
48164
48795
  signal?.throwIfAborted();
48165
48796
  const request = step.value;
48166
- if (request && request !== "token" && request.kind === "array-append") {
48797
+ if (request && request !== "token" && (request.kind === "array-append" || request.kind === "dictionary-append")) {
48167
48798
  let position;
48168
48799
  try {
48169
- position = await appendStoredRecord(options.arrayStorage, request.node, request.previous, signal);
48800
+ position = await appendStoredRecord(request.kind === "array-append" ? options.arrayStorage : options.dictionaryStorage, request.kind === "array-append" ? request.node : request.entry, request.previous, signal);
48170
48801
  } catch (error) {
48171
48802
  options.onBackingError?.(error);
48172
48803
  throw error;
48173
48804
  }
48174
48805
  step = work.next(position);
48806
+ } else if (request && request !== "token" && (request.kind === "container-push" || request.kind === "container-pop")) {
48807
+ let container;
48808
+ try {
48809
+ if (request.kind === "container-push") await containers.push(request.container);
48810
+ else container = await containers.pop();
48811
+ } catch (error) {
48812
+ options.onBackingError?.(error);
48813
+ throw error;
48814
+ }
48815
+ step = work.next(container);
48175
48816
  } else step = request === void 0 ? work.next() : work.next(request === "token" ? await lexer.nextToken() : request);
48176
48817
  if (++turns % 64 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
48177
48818
  }
@@ -48186,7 +48827,7 @@ async function parseCosRangeValue(source, offset, options = {}) {
48186
48827
  const depth = limit(options.maxRecursionDepth, "maxRecursionDepth");
48187
48828
  const nodes = limit(options.maxNodes, "maxNodes");
48188
48829
  const maxTokenBytes = limit(options.maxTokenBytes, "maxTokenBytes");
48189
- const lexer = new CosRangeLexer(source, { ...options.onBackingError ? { onBackingError: options.onBackingError } : {}, start: offset, ...options.end === void 0 ? {} : { end: options.end }, maxTokenBytes, ...options.signal ? { signal: options.signal } : {} });
48830
+ const lexer = new CosRangeLexer(source, { compactNumbers: options.compactNumbers ?? false, compactKeywords: options.compactKeywords ?? false, ...options.onBackingError ? { onBackingError: options.onBackingError } : {}, start: offset, ...options.end === void 0 ? {} : { end: options.end }, maxTokenBytes, ...options.signal ? { signal: options.signal } : {} });
48190
48831
  return { value: await readValue(lexer, depth, nodes, options), offset: lexer.offset };
48191
48832
  }
48192
48833
  async function parseCosRangeObject(source, offset, options = {}) {
@@ -48195,7 +48836,7 @@ async function parseCosRangeObject(source, offset, options = {}) {
48195
48836
  const tokenBytes = limit(options.maxTokenBytes, "maxTokenBytes");
48196
48837
  const { signal } = options;
48197
48838
  signal?.throwIfAborted();
48198
- const lexer = new CosRangeLexer(source, { ...options.onBackingError ? { onBackingError: options.onBackingError } : {}, start: offset, maxTokenBytes: tokenBytes, ...signal ? { signal } : {} });
48839
+ const lexer = new CosRangeLexer(source, { compactNumbers: options.compactNumbers ?? false, compactKeywords: options.compactKeywords ?? false, ...options.onBackingError ? { onBackingError: options.onBackingError } : {}, start: offset, maxTokenBytes: tokenBytes, ...signal ? { signal } : {} });
48199
48840
  const object = await lexer.nextToken();
48200
48841
  const generation = await lexer.nextToken();
48201
48842
  const keyword = await lexer.nextToken();
@@ -48304,7 +48945,7 @@ async function* scanCosRangeObjects(source, options = {}) {
48304
48945
 
48305
48946
  // packages/pdf-ast/src/cos/range-xref.ts
48306
48947
  import { readBytes as readBytes12 } from "@poe-platform/safe-fs/contracts";
48307
- function budget(value, name) {
48948
+ function budget2(value, name) {
48308
48949
  if (value === void 0 || value === Infinity) return Infinity;
48309
48950
  if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`Invalid ${name}`);
48310
48951
  return value;
@@ -48363,12 +49004,12 @@ var DecodedFields = class {
48363
49004
  }
48364
49005
  };
48365
49006
  async function* readCosXrefRevision(source, offset, options = {}) {
48366
- const maximum10 = budget(options.maxEntries, "maxEntries");
48367
- const maxDecoded = budget(options.maxDecodedBytes, "maxDecodedBytes");
49007
+ const maximum10 = budget2(options.maxEntries, "maxEntries");
49008
+ const maxDecoded = budget2(options.maxDecodedBytes, "maxDecodedBytes");
48368
49009
  const { signal } = options;
48369
49010
  signal?.throwIfAborted();
48370
49011
  if (!Number.isSafeInteger(offset) || offset < 0 || offset >= source.size) throw new PdfError("E_PARSE", `Invalid xref offset: ${offset}`);
48371
- const lexer = new CosRangeLexer(source, { start: offset, ...signal ? { signal } : {}, ...options.maxTokenBytes === void 0 ? {} : { maxTokenBytes: options.maxTokenBytes } });
49012
+ const lexer = new CosRangeLexer(source, { compactNumbers: options.compactNumbers ?? false, compactKeywords: options.compactKeywords ?? false, start: offset, ...signal ? { signal } : {}, ...options.maxTokenBytes === void 0 ? {} : { maxTokenBytes: options.maxTokenBytes } });
48372
49013
  const first = await lexer.nextToken();
48373
49014
  let admitted = 0;
48374
49015
  const admit2 = (count) => {
@@ -48483,271 +49124,6 @@ async function* readCosXrefRevision(source, offset, options = {}) {
48483
49124
  }
48484
49125
  }
48485
49126
 
48486
- // packages/pdf-ast/src/cos/object-index.ts
48487
- import { listenForAbort as listenForAbort2 } from "@poe-platform/safe-fs/contracts";
48488
- var recordBytes = 32;
48489
- function integer(value, name) {
48490
- if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`Invalid ${name}`);
48491
- return value;
48492
- }
48493
- function budget2(value, name) {
48494
- return value === void 0 || value === Infinity ? Infinity : integer(value, name);
48495
- }
48496
- function fields(entry) {
48497
- const key = integer(entry.objectNumber, "PDF object number");
48498
- if (entry.type === "free") return [key, integer(entry.nextFreeObjectNumber ?? 0, "free object number"), integer(entry.generationNumber ?? 0, "generation number"), 0];
48499
- if (entry.type === "uncompressed") return [key, integer(entry.offset, "object offset"), integer(entry.generationNumber ?? 0, "generation number"), 1];
48500
- if (entry.type === "compressed") return [key, integer(entry.objectStreamNumber, "object stream number"), integer(entry.indexInStream ?? entry.indexInObjectStream, "object stream index"), 2];
48501
- throw new PdfError("E_PARSE", "Invalid PDF cross-reference entry type");
48502
- }
48503
- function decode(bytes, offset = 0) {
48504
- const view = new DataView(bytes.buffer, bytes.byteOffset + offset, recordBytes);
48505
- const objectNumber = view.getFloat64(0);
48506
- const first = view.getFloat64(8);
48507
- const second = view.getFloat64(16);
48508
- const type = view.getFloat64(24);
48509
- if (type === 0) return { objectNumber, type: "free", nextFreeObjectNumber: first, generationNumber: second };
48510
- if (type === 1) return { objectNumber, type: "uncompressed", offset: first, generationNumber: second };
48511
- if (type === 2) return { objectNumber, type: "compressed", objectStreamNumber: first, indexInStream: second };
48512
- throw new PdfError("E_PARSE", "Invalid staged PDF index record");
48513
- }
48514
- async function* encode2(entries, chunkBytes) {
48515
- let bytes = new Uint8Array(chunkBytes);
48516
- let offset = 0;
48517
- for await (const entry of entries) {
48518
- const view = new DataView(bytes.buffer, offset, recordBytes);
48519
- const values = fields(entry);
48520
- for (let i = 0; i < values.length; i++) view.setFloat64(i * 8, values[i]);
48521
- offset += recordBytes;
48522
- if (offset === bytes.length) {
48523
- yield bytes;
48524
- bytes = new Uint8Array(chunkBytes);
48525
- offset = 0;
48526
- }
48527
- }
48528
- if (offset) yield bytes.subarray(0, offset);
48529
- }
48530
- async function* records(source, signal) {
48531
- for await (const bytes of source.stream(0, source.size, signal)) {
48532
- if (bytes.length % recordBytes !== 0) throw new PdfError("E_PARSE", "Truncated staged PDF index");
48533
- for (let offset = 0; offset < bytes.length; offset += recordBytes) {
48534
- signal?.throwIfAborted();
48535
- yield decode(bytes, offset);
48536
- }
48537
- }
48538
- }
48539
- async function* merge(first, second, duplicate, signal) {
48540
- const left = records(first, signal);
48541
- const right = records(second, signal);
48542
- try {
48543
- let a = await left.next();
48544
- let b = await right.next();
48545
- let turns = 0;
48546
- while (!a.done || !b.done) {
48547
- signal?.throwIfAborted();
48548
- if (!a.done && (b.done || a.value.objectNumber <= b.value.objectNumber)) {
48549
- const equal2 = !b.done && a.value.objectNumber === b.value.objectNumber;
48550
- yield equal2 && duplicate === "last" && !b.done ? b.value : a.value;
48551
- if (equal2) b = await right.next();
48552
- a = await left.next();
48553
- } else if (!b.done) {
48554
- yield b.value;
48555
- b = await right.next();
48556
- }
48557
- if (++turns % 1024 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
48558
- }
48559
- } finally {
48560
- await left.return(void 0);
48561
- await right.return(void 0);
48562
- }
48563
- }
48564
- var PdfObjectIndex = class _PdfObjectIndex {
48565
- constructor(source, signal) {
48566
- this.source = source;
48567
- this.signal = signal;
48568
- }
48569
- source;
48570
- signal;
48571
- closing;
48572
- get size() {
48573
- return this.source.size / recordBytes;
48574
- }
48575
- static async build(input, storage, options = {}) {
48576
- const duplicate = options.duplicate ?? "first";
48577
- if (duplicate !== "first" && duplicate !== "last") throw new RangeError("Invalid PDF index duplicate policy");
48578
- const runEntries = integer(options.runEntries ?? 2048, "runEntries");
48579
- const chunkBytes = integer(options.chunkBytes ?? 64 * 1024, "chunkBytes");
48580
- const cacheBytes = integer(options.cacheBytes ?? 256 * 1024, "cacheBytes");
48581
- if (!runEntries || chunkBytes < recordBytes || chunkBytes % recordBytes !== 0 || cacheBytes < chunkBytes) throw new RangeError("Invalid PDF index batch/cache sizes");
48582
- const maxEntries = budget2(options.maxEntries, "maxEntries");
48583
- const maxStagingBytes = budget2(options.maxStagingBytes, "maxStagingBytes");
48584
- const { signal } = options;
48585
- signal?.throwIfAborted();
48586
- const owned = /* @__PURE__ */ new Set();
48587
- const levels = [];
48588
- let stagedBytes = 0;
48589
- let admitted = 0;
48590
- let batch = [];
48591
- const dispose = async (source) => {
48592
- try {
48593
- await source.close();
48594
- } finally {
48595
- owned.delete(source);
48596
- stagedBytes -= source.size;
48597
- }
48598
- };
48599
- const stage = async (entries) => {
48600
- let reserved = 0;
48601
- async function* chunks() {
48602
- for await (const bytes of encode2(entries, chunkBytes)) {
48603
- signal?.throwIfAborted();
48604
- if (bytes.length > Math.min(maxStagingBytes, Number.MAX_SAFE_INTEGER) - stagedBytes) throw new PdfError("E_LIMIT", "PDF index staging byte limit exceeded");
48605
- stagedBytes += bytes.length;
48606
- reserved += bytes.length;
48607
- yield bytes;
48608
- }
48609
- }
48610
- try {
48611
- const source = await PdfFileSource.fromStream(storage.fs, storage.directory, chunks(), { chunkBytes, cacheBytes, ...signal ? { signal } : {} });
48612
- owned.add(source);
48613
- return source;
48614
- } catch (error) {
48615
- stagedBytes -= reserved;
48616
- throw error;
48617
- }
48618
- };
48619
- const flush = async () => {
48620
- if (duplicate === "last") batch.reverse();
48621
- batch.sort((a, b) => a.objectNumber - b.objectNumber);
48622
- const sorted = batch;
48623
- batch = [];
48624
- function* unique() {
48625
- let previous = -1;
48626
- for (const entry of sorted) if (entry.objectNumber !== previous) {
48627
- previous = entry.objectNumber;
48628
- yield entry;
48629
- }
48630
- }
48631
- let run = await stage(unique());
48632
- let level = 0;
48633
- while (levels[level]) {
48634
- const earlier = levels[level];
48635
- const combined = await stage(merge(earlier, run, duplicate, signal));
48636
- await dispose(earlier);
48637
- await dispose(run);
48638
- levels[level++] = void 0;
48639
- run = combined;
48640
- }
48641
- levels[level] = run;
48642
- };
48643
- const iterator = Symbol.asyncIterator in input ? input[Symbol.asyncIterator]() : input[Symbol.iterator]();
48644
- let ended = false;
48645
- const next = async () => {
48646
- signal?.throwIfAborted();
48647
- if (!signal) return iterator.next();
48648
- let dispose2 = () => {
48649
- };
48650
- const cancelled = new Promise((ignored, reject) => {
48651
- dispose2 = listenForAbort2(signal, () => reject(signal.reason));
48652
- });
48653
- const pending = Promise.resolve().then(() => {
48654
- signal.throwIfAborted();
48655
- return iterator.next();
48656
- });
48657
- try {
48658
- return await Promise.race([pending, cancelled]);
48659
- } finally {
48660
- dispose2();
48661
- }
48662
- };
48663
- try {
48664
- while (true) {
48665
- const step = await next();
48666
- signal?.throwIfAborted();
48667
- if (step.done) {
48668
- ended = true;
48669
- break;
48670
- }
48671
- if (admitted >= Math.min(maxEntries, Number.MAX_SAFE_INTEGER)) throw new PdfError("E_LIMIT", "PDF index entry limit exceeded");
48672
- admitted++;
48673
- const values = fields(step.value);
48674
- const entry = step.value.type === "compressed" ? { objectNumber: values[0], type: "compressed", objectStreamNumber: values[1], indexInStream: values[2] } : step.value.type === "free" ? { objectNumber: values[0], type: "free", nextFreeObjectNumber: values[1], generationNumber: values[2] } : { objectNumber: values[0], type: "uncompressed", offset: values[1], generationNumber: values[2] };
48675
- batch.push(entry);
48676
- if (batch.length === runEntries) await flush();
48677
- if (admitted % 1024 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
48678
- }
48679
- if (batch.length) await flush();
48680
- let result;
48681
- for (let level = levels.length - 1; level >= 0; level--) {
48682
- const run = levels[level];
48683
- if (!run) continue;
48684
- if (!result) result = run;
48685
- else {
48686
- const combined = await stage(merge(result, run, duplicate, signal));
48687
- await dispose(result);
48688
- await dispose(run);
48689
- result = combined;
48690
- }
48691
- }
48692
- result ??= await stage([]);
48693
- signal?.throwIfAborted();
48694
- owned.delete(result);
48695
- return new _PdfObjectIndex(result, signal);
48696
- } catch (error) {
48697
- for (const source of owned) {
48698
- try {
48699
- await source.close();
48700
- } catch {
48701
- }
48702
- }
48703
- throw error;
48704
- } finally {
48705
- if (!ended) {
48706
- try {
48707
- const returning = iterator.return?.();
48708
- if (returning) {
48709
- if (signal?.aborted) void Promise.resolve(returning).catch(() => {
48710
- });
48711
- else await returning;
48712
- }
48713
- } catch {
48714
- }
48715
- }
48716
- }
48717
- }
48718
- async get(objectNumber, signal) {
48719
- integer(objectNumber, "PDF object number");
48720
- this.assertOpen(signal);
48721
- let low = 0;
48722
- let high = this.size;
48723
- while (low < high) {
48724
- const middle = low + Math.floor((high - low) / 2);
48725
- const entry = decode(await this.source.read(middle * recordBytes, recordBytes, signal));
48726
- this.assertOpen(signal);
48727
- if (entry.objectNumber === objectNumber) return entry;
48728
- if (entry.objectNumber < objectNumber) low = middle + 1;
48729
- else high = middle;
48730
- }
48731
- return void 0;
48732
- }
48733
- assertOpen(signal) {
48734
- this.signal?.throwIfAborted();
48735
- signal?.throwIfAborted();
48736
- if (this.closing) throw new PdfError("E_CAPABILITY", "PDF object index is closed");
48737
- }
48738
- async *entries(signal) {
48739
- this.assertOpen(signal);
48740
- for await (const entry of records(this.source, signal)) {
48741
- this.assertOpen(signal);
48742
- yield entry;
48743
- }
48744
- }
48745
- close() {
48746
- this.closing ??= this.source.close();
48747
- return this.closing;
48748
- }
48749
- };
48750
-
48751
49127
  // packages/pdf-ast/src/cos/cross-reference.ts
48752
49128
  var marker = new TextEncoder().encode("startxref");
48753
49129
  async function header(source, signal) {
@@ -48782,6 +49158,8 @@ async function findPdfStartXref(source, options = {}) {
48782
49158
  if (!matched) continue;
48783
49159
  const lexer = new CosRangeLexer(source, {
48784
49160
  start: start + i + marker.length,
49161
+ compactNumbers: options.compactNumbers ?? false,
49162
+ compactKeywords: options.compactKeywords ?? false,
48785
49163
  ...options.maxTokenBytes === void 0 ? {} : { maxTokenBytes: options.maxTokenBytes },
48786
49164
  ...options.signal ? { signal: options.signal } : {}
48787
49165
  });
@@ -48923,8 +49301,23 @@ async function resolvePdfStreamDictionary(dict, lookup, active, options) {
48923
49301
  }
48924
49302
  if (node.kind === "array") {
48925
49303
  const items = [];
48926
- for (const item of node.items) items.push(await resolve2(item, depth + 1));
48927
- return { ...node, items };
49304
+ const { storedItems, ...ordinary } = node;
49305
+ if (storedItems) {
49306
+ const reader = readStoredItems(storedItems, options.signal);
49307
+ try {
49308
+ for (; ; ) {
49309
+ const item = await reader.next().catch((error) => {
49310
+ options.onBackingError?.(error);
49311
+ throw error;
49312
+ });
49313
+ if (item.done) break;
49314
+ items.push(await resolve2(item.value, depth + 1));
49315
+ }
49316
+ } finally {
49317
+ await reader.return();
49318
+ }
49319
+ } else for (const item of node.items) items.push(await resolve2(item, depth + 1));
49320
+ return { ...ordinary, items };
48928
49321
  }
48929
49322
  if (node.kind === "dict") {
48930
49323
  const entries2 = [];
@@ -49147,6 +49540,9 @@ var PdfObjectReader = class {
49147
49540
  index;
49148
49541
  storage;
49149
49542
  streams = /* @__PURE__ */ new Map();
49543
+ // Recursive length/object-stream lookups share one failure identity so an
49544
+ // outer recovery pass cannot mistake a caller-storage error for PDF syntax.
49545
+ backingFailures = /* @__PURE__ */ new WeakMap();
49150
49546
  repairedOffsets = /* @__PURE__ */ new Map();
49151
49547
  options;
49152
49548
  capacity;
@@ -49176,7 +49572,10 @@ var PdfObjectReader = class {
49176
49572
  const object2 = await this.load(objectNumber, generationNumber, /* @__PURE__ */ new Set());
49177
49573
  if (object2?.value.kind !== "dict" || !object2.stream) throw new PdfError("E_PARSE", "Expected an indexed PDF stream");
49178
49574
  const active = /* @__PURE__ */ new Set([objectNumber]);
49179
- return { object: object2, dict: await resolvePdfStreamDictionary(object2.value, (ref) => this.load(ref.objectNumber, ref.generationNumber, active), active, this.options) };
49575
+ return { object: object2, dict: await resolvePdfStreamDictionary(object2.value, (ref) => this.load(ref.objectNumber, ref.generationNumber, active), active, { ...this.options, onBackingError: (error) => {
49576
+ this.backingFailures.set(active, { error });
49577
+ this.options.onBackingError?.(error);
49578
+ } }) };
49180
49579
  });
49181
49580
  const span = object.stream;
49182
49581
  const input = () => this.source.stream(span.start, span.end - span.start, this.options.signal);
@@ -49184,13 +49583,17 @@ var PdfObjectReader = class {
49184
49583
  const decodeOptions = { ...this.options, stopBeforeImageCodec: options.stopBeforeImageCodec ?? false, raw: options.raw ?? false };
49185
49584
  yield* security ? decodePdfEncryptedStreamChunks(security, objectNumber, generationNumber, dict, input, decodeOptions) : decodePdfStreamChunks(dict, input, decodeOptions);
49186
49585
  }
49187
- async load(objectNumber, generationNumber, active, arrays = {}) {
49586
+ async load(objectNumber, generationNumber, active, arrays = this.options.valueArrays ?? {}) {
49188
49587
  this.options.signal?.throwIfAborted();
49189
49588
  if (active.has(objectNumber)) throw new PdfError("E_PARSE", "PDF indirect object cycle");
49190
49589
  if (active.size >= this.options.maxRecursionDepth) throw new PdfError("E_LIMIT", "PDF object resolution depth limit exceeded");
49191
49590
  const entry = await this.index.get(objectNumber, this.options.signal);
49192
49591
  if (!entry || entry.type === "free" || generationNumber !== (entry.generationNumber ?? 0)) return void 0;
49193
49592
  active.add(objectNumber);
49593
+ const onBackingError = (error) => {
49594
+ this.backingFailures.set(active, { error });
49595
+ this.options.onBackingError?.(error);
49596
+ };
49194
49597
  try {
49195
49598
  if (entry.type === "compressed") {
49196
49599
  const container = entry.objectStreamNumber;
@@ -49203,15 +49606,11 @@ var PdfObjectReader = class {
49203
49606
  if (row.number !== objectNumber) throw new PdfError("E_PARSE", "Compressed object identity does not match xref");
49204
49607
  const end = ordinal + 1 === stream.count ? stream.data.size : stream.first + (await this.headerRow(stream.header, ordinal + 1)).offset;
49205
49608
  const start = stream.first + row.offset;
49206
- const parsed = await parseCosRangeValue(stream.data, start, { ...this.options, ...arrays, end });
49609
+ const parsed = await parseCosRangeValue(stream.data, start, { ...this.options, ...arrays, end, onBackingError });
49207
49610
  if (!parsed.value) throw new PdfError("E_PARSE", "Empty compressed object");
49208
49611
  return { objectNumber, generationNumber, value: parsed.value, span: { start, end: parsed.offset } };
49209
49612
  }
49210
49613
  let object;
49211
- let backingFailure;
49212
- const onBackingError = (error) => {
49213
- backingFailure = { error };
49214
- };
49215
49614
  try {
49216
49615
  object = await parseCosRangeObject(this.source, this.repairedOffsets.get(objectNumber) ?? entry.offset, {
49217
49616
  ...this.options,
@@ -49225,10 +49624,11 @@ var PdfObjectReader = class {
49225
49624
  if (object.objectNumber !== objectNumber || object.generationNumber !== generationNumber) throw new PdfError("E_PARSE", "Indirect object identity does not match xref");
49226
49625
  } catch (error) {
49227
49626
  this.options.signal?.throwIfAborted();
49627
+ const backingFailure = this.backingFailures.get(active);
49228
49628
  if (backingFailure && Object.is(backingFailure.error, error)) throw error;
49229
49629
  if (this.options.recovery !== "repair" || !(error instanceof PdfError) || error.code !== "E_PARSE") throw error;
49230
49630
  let recovered;
49231
- for await (const event of scanCosRangeObjects(this.source, { ...this.options, ...arrays })) {
49631
+ for await (const event of scanCosRangeObjects(this.source, { ...this.options, ...arrays, onBackingError })) {
49232
49632
  if (event.kind === "object" && event.object.objectNumber === objectNumber && event.object.generationNumber === generationNumber) recovered = event.object;
49233
49633
  }
49234
49634
  if (!recovered) throw error;
@@ -49294,7 +49694,10 @@ var PdfObjectReader = class {
49294
49694
  active.add(number);
49295
49695
  let dict;
49296
49696
  try {
49297
- dict = await resolvePdfStreamDictionary(object.value, (ref) => this.load(ref.objectNumber, ref.generationNumber, active), active, this.options);
49697
+ dict = await resolvePdfStreamDictionary(object.value, (ref) => this.load(ref.objectNumber, ref.generationNumber, active), active, { ...this.options, onBackingError: (error) => {
49698
+ this.backingFailures.set(active, { error });
49699
+ this.options.onBackingError?.(error);
49700
+ } });
49298
49701
  } finally {
49299
49702
  active.delete(number);
49300
49703
  }
@@ -49380,14 +49783,33 @@ var PdfObjectReader = class {
49380
49783
  }
49381
49784
  };
49382
49785
  async function openPdfObjectReader(source, storage, options = {}) {
49383
- const xrefOptions = { maxNodes: 65536, maxTokenBytes: 1048576, maxRecursionDepth: 100, ...options, ...options.xref };
49786
+ let backingFailure;
49787
+ const callerBackingError = options.onBackingError;
49788
+ const xrefBackingError = options.xref?.onBackingError;
49789
+ const onBackingError = (error) => {
49790
+ backingFailure = { error };
49791
+ callerBackingError?.(error);
49792
+ };
49793
+ options = { ...options, onBackingError };
49794
+ const canRepair = (error) => !(backingFailure && Object.is(backingFailure.error, error)) && error instanceof PdfError && error.code === "E_PARSE";
49795
+ const xrefOptions = {
49796
+ maxNodes: 65536,
49797
+ maxTokenBytes: 1048576,
49798
+ maxRecursionDepth: 100,
49799
+ ...options,
49800
+ ...options.xref,
49801
+ onBackingError(error) {
49802
+ onBackingError(error);
49803
+ if (xrefBackingError !== callerBackingError) xrefBackingError?.(error);
49804
+ }
49805
+ };
49384
49806
  let crossReference;
49385
49807
  let repaired = false;
49386
49808
  try {
49387
49809
  crossReference = await openPdfCrossReference(source, storage, xrefOptions);
49388
49810
  } catch (error) {
49389
49811
  options.signal?.throwIfAborted();
49390
- if (options.recovery !== "repair" || !(error instanceof PdfError) || error.code !== "E_PARSE") throw error;
49812
+ if (options.recovery !== "repair" || !canRepair(error)) throw error;
49391
49813
  crossReference = await recoverPdfReferences(source, storage, xrefOptions);
49392
49814
  repaired = true;
49393
49815
  }
@@ -49402,7 +49824,7 @@ async function openPdfObjectReader(source, storage, options = {}) {
49402
49824
  const pages = root?.value.kind === "dict" && !root.stream ? dictGet(root.value, "Pages") : void 0;
49403
49825
  valid = pages?.kind === "ref" || pages?.kind === "dict";
49404
49826
  } catch (error) {
49405
- if (!(error instanceof PdfError) || error.code !== "E_PARSE") throw error;
49827
+ if (!canRepair(error)) throw error;
49406
49828
  }
49407
49829
  if (!valid) {
49408
49830
  await reader.close();
@@ -49465,7 +49887,7 @@ async function openPdfObjectReader(source, storage, options = {}) {
49465
49887
  try {
49466
49888
  yield* currentReader.objectStreamEntries(object.objectNumber, object.generationNumber);
49467
49889
  } catch (error) {
49468
- if (!(error instanceof PdfError) || error.code !== "E_PARSE") throw error;
49890
+ if (!canRepair(error)) throw error;
49469
49891
  }
49470
49892
  }
49471
49893
  }
@@ -49488,7 +49910,7 @@ async function openPdfObjectReader(source, storage, options = {}) {
49488
49910
  try {
49489
49911
  object = await reader.get(entry.objectNumber, entry.generationNumber ?? 0);
49490
49912
  } catch (error) {
49491
- if (error instanceof PdfError && error.code === "E_PARSE") continue;
49913
+ if (canRepair(error)) continue;
49492
49914
  throw error;
49493
49915
  }
49494
49916
  if (object?.value.kind !== "dict") continue;
@@ -49642,7 +50064,7 @@ async function* parseContentRangeOperators(source, storage, options = {}) {
49642
50064
  }
49643
50065
  if (!Number.isSafeInteger(limits.chunkBytes) || limits.chunkBytes < 8) throw new RangeError("chunkBytes must be at least 8");
49644
50066
  const { signal } = options;
49645
- const lexer = new CosRangeLexer(source, { maxTokenBytes: limits.maxTokenBytes, knownCommands: PDF_KNOWN_COMMANDS, ...options.pathStorage ? { stringStorage: options.pathStorage } : {}, ...signal ? { signal } : {} });
50067
+ const lexer = new CosRangeLexer(source, { compactNumbers: options.compactNumbers ?? false, compactKeywords: options.compactKeywords ?? false, maxTokenBytes: limits.maxTokenBytes, knownCommands: PDF_KNOWN_COMMANDS, ...options.pathStorage ? { stringStorage: options.pathStorage } : {}, ...signal ? { signal } : {} });
49646
50068
  const stack = new PdfOperandStack(storage, limits);
49647
50069
  const backedStack = options.pathStorage ? new StoredMetadataStack(options.pathStorage, signal) : void 0;
49648
50070
  const operands = backedStack ?? stack;
@@ -54528,7 +54950,7 @@ async function resolveRetainedFont(document2, storage, resources, name, options
54528
54950
  }
54529
54951
  let value;
54530
54952
  if (step.value.kind === "resolve") {
54531
- const retained = await document2.lookup(step.value.node, options.resourceStorage ? { arrayStorage: options.resourceStorage, storedArrayKeys: ["Widths", "W", "Differences"], storeRootArray: step.value.storeRootArray ?? false } : {});
54953
+ const retained = await document2.lookup(step.value.node, options.resourceStorage ? { dictionaryStorage: options.resourceStorage, storedDictionaryKeys: ["Font"], storeRootDictionary: step.value.storeRootDictionary ?? false, arrayStorage: options.resourceStorage, storedArrayKeys: ["Widths", "W", "Differences"], storeRootArray: step.value.storeRootArray ?? false } : {});
54532
54954
  value = retained?.value;
54533
54955
  if (retained?.stream) {
54534
54956
  if (retained.value.kind !== "dict" || !retained.reference) throw new PdfError("E_PARSE", "Font stream has no retained identity");
@@ -54537,6 +54959,9 @@ async function resolveRetainedFont(document2, storage, resources, name, options
54537
54959
  identities.set(stream, retained.reference);
54538
54960
  value = stream;
54539
54961
  }
54962
+ } else if (step.value.kind === "dictionary-entry") {
54963
+ const record = await readStoredRecord(step.value.entries.storage, step.value.position, signal);
54964
+ value = cosArray([record.value.key, record.value.value, cosNumber(record.next)]);
54540
54965
  } else if (step.value.kind === "font-encoding") {
54541
54966
  const array = step.value.array;
54542
54967
  value = await StoredFontEncoding.create(() => array.storedItems ? readStoredItems(array.storedItems, signal) : array.items, options.resourceStorage, { onAllocation: (bytes) => allocation.admit(bytes), ...signal ? { signal } : {} });
@@ -57082,8 +57507,8 @@ function resolveDestinationPageIndex(doc, destOrActionNode) {
57082
57507
  return void 0;
57083
57508
  }
57084
57509
 
57085
- // packages/pdf-ast/src/retained-document.ts
57086
- import { PagedStorage as PagedStorage8 } from "@poe-platform/safe-fs/storage";
57510
+ // packages/pdf-ast/src/extract/retained-form-fields.ts
57511
+ import { IntegerTable as IntegerTable4, PagedStorage as PagedStorage6 } from "@poe-platform/safe-fs/storage";
57087
57512
 
57088
57513
  // packages/pdf-ast/src/cos/mutable-object-store.ts
57089
57514
  import { IntegerTable as IntegerTable3, PagedStorage as PagedStorage5 } from "@poe-platform/safe-fs/storage";
@@ -57613,6 +58038,290 @@ var PdfMutableObjectStore = class {
57613
58038
  }
57614
58039
  };
57615
58040
 
58041
+ // packages/pdf-ast/src/extract/retained-form-fields.ts
58042
+ async function inheritedRetainedFieldEntry(document2, storage, dict, key, options) {
58043
+ const seen = new PdfReferenceSet(storage, options.maxStagingBytes, options.signal);
58044
+ let current = dict, depth = 0, failed = false;
58045
+ try {
58046
+ while (current) {
58047
+ options.signal?.throwIfAborted();
58048
+ if (++depth > (options.maxDepth ?? document2.depthLimit)) throw new PdfError("E_LIMIT", "PDF form field depth limit exceeded");
58049
+ if (depth % 64 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
58050
+ const value = dictGet(current, key);
58051
+ if (value !== void 0) return (await document2.lookup(value))?.value;
58052
+ const parent = dictGet(current, "Parent");
58053
+ if (parent?.kind === "ref" && !await seen.add(parent.objectNumber)) return;
58054
+ const found = await document2.lookup(parent);
58055
+ current = !found?.stream && found?.value.kind === "dict" ? found.value : void 0;
58056
+ }
58057
+ } catch (error) {
58058
+ failed = true;
58059
+ throw error;
58060
+ } finally {
58061
+ await seen.close().catch((error) => {
58062
+ if (!failed) throw error;
58063
+ });
58064
+ }
58065
+ }
58066
+ async function* walkRetainedFieldEntries(document2, storage, options = {}) {
58067
+ const signal = options.signal ?? new AbortController().signal, maxDepth = options.maxDepth ?? document2.depthLimit;
58068
+ signal.throwIfAborted();
58069
+ const frames = new PdfMutableObjectStore(storage, { signal, ...options.maxStagingBytes === void 0 ? {} : { maxStagingBytes: options.maxStagingBytes } });
58070
+ const backing = new PagedStorage6({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), active = new IntegerTable4(backing, 64);
58071
+ let pending = 0, work = 0, failed = false;
58072
+ async function checkpoint(depth = 0) {
58073
+ signal.throwIfAborted();
58074
+ if (depth > maxDepth) throw new PdfError("E_LIMIT", "PDF form field depth limit exceeded");
58075
+ if (++work % 64 === 0) await new Promise((resolve3) => setTimeout(resolve3, 0));
58076
+ signal.throwIfAborted();
58077
+ }
58078
+ async function resolve2(node) {
58079
+ const found = await document2.lookup(node);
58080
+ return found?.stream ? void 0 : found?.value;
58081
+ }
58082
+ async function push(node, prefix, ft, depth, flags = 0, justification = 0, maxLength) {
58083
+ await frames.set({ objectNumber: ++pending, generationNumber: 0, value: cosArray([node, cosString(prefix), cosString(ft), cosNumber(depth), cosNumber(flags), cosNumber(justification), maxLength === void 0 ? cosNull() : cosNumber(maxLength)]) });
58084
+ }
58085
+ try {
58086
+ const root = await resolve2(document2.crossReference.rootRef), form = root?.kind === "dict" ? await resolve2(dictGet(root, "AcroForm")) : void 0;
58087
+ const fields2 = form?.kind === "dict" ? await resolve2(dictGet(form, "Fields")) : void 0;
58088
+ if (fields2?.kind !== "array") return;
58089
+ for (let i = fields2.items.length - 1; i >= 0; i--) {
58090
+ await checkpoint();
58091
+ await push(fields2.items[i], "", "", 0);
58092
+ }
58093
+ while (pending) {
58094
+ const frame = (await frames.get(pending--)).value;
58095
+ if (frame.kind !== "array") throw new PdfError("E_PARSE", "Invalid form traversal frame");
58096
+ const [node, prefixNode, ftNode, depthNode, flagsNode, qNode, maxNode] = frame.items;
58097
+ if (frame.items.length === 1 && node?.kind === "number") {
58098
+ await active.set(BigInt(node.value), 0n);
58099
+ continue;
58100
+ }
58101
+ if (!node || prefixNode?.kind !== "string" || ftNode?.kind !== "string" || depthNode?.kind !== "number") throw new PdfError("E_PARSE", "Invalid form traversal frame");
58102
+ await checkpoint(depthNode.value);
58103
+ if (node.kind === "ref") {
58104
+ if (await active.get(BigInt(node.objectNumber)) === 1n) continue;
58105
+ await active.set(BigInt(node.objectNumber), 1n);
58106
+ await frames.set({ objectNumber: ++pending, generationNumber: 0, value: cosArray([cosNumber(node.objectNumber)]) });
58107
+ }
58108
+ const dict = await resolve2(node);
58109
+ if (dict?.kind !== "dict") continue;
58110
+ const named = await resolve2(dictGet(dict, "T")), ownFt = await resolve2(dictGet(dict, "FT"));
58111
+ const partial = named?.kind === "string" ? decodePdfString(named) : named?.kind === "name" ? named.decoded : "", prefix = decodePdfString(prefixNode);
58112
+ const name = prefix && partial ? `${prefix}.${partial}` : partial || prefix, ft = ownFt?.kind === "name" ? ownFt.decoded : decodePdfString(ftNode);
58113
+ const ownFlags = await resolve2(dictGet(dict, "Ff")), ownQ = await resolve2(dictGet(dict, "Q")), ownMax = await resolve2(dictGet(dict, "MaxLen"));
58114
+ const flags = ownFlags?.kind === "number" ? ownFlags.value : flagsNode?.kind === "number" ? flagsNode.value : 0;
58115
+ const justification = ownQ?.kind === "number" ? ownQ.value : qNode?.kind === "number" ? qNode.value : 0;
58116
+ const maxLength = ownMax?.kind === "number" ? ownMax.value : maxNode?.kind === "number" ? maxNode.value : void 0;
58117
+ const kids = await resolve2(dictGet(dict, "Kids"));
58118
+ if (kids?.kind === "array" && kids.items.length) {
58119
+ let namedKids = false;
58120
+ for (const kid of kids.items) {
58121
+ await checkpoint();
58122
+ const value = await resolve2(kid);
58123
+ if (value?.kind === "dict" && dictGet(value, "T")) {
58124
+ namedKids = true;
58125
+ break;
58126
+ }
58127
+ }
58128
+ if (namedKids || !ft || !name) {
58129
+ for (let i = kids.items.length - 1; i >= 0; i--) {
58130
+ await checkpoint();
58131
+ await push(kids.items[i], name, ft, depthNode.value + 1, flags, justification, maxLength);
58132
+ }
58133
+ continue;
58134
+ }
58135
+ }
58136
+ if (!name) continue;
58137
+ yield { name, dict, ft, flags, justification, maxLength };
58138
+ }
58139
+ } catch (error) {
58140
+ failed = true;
58141
+ throw error;
58142
+ } finally {
58143
+ const results = await Promise.allSettled([frames.close(), backing.close()]);
58144
+ if (!failed) {
58145
+ for (const result of results) if (result.status === "rejected") await Promise.reject(result.reason);
58146
+ }
58147
+ }
58148
+ }
58149
+ async function* walkRetainedFormFields(document2, storage, options = {}) {
58150
+ let work = 0;
58151
+ async function resolve2(node) {
58152
+ if (++work % 64 === 0) await new Promise((resolve3) => setTimeout(resolve3, 0));
58153
+ const found = await document2.lookup(node);
58154
+ return found?.stream ? void 0 : found?.value;
58155
+ }
58156
+ for await (const { name, dict, ft } of walkRetainedFieldEntries(document2, storage, options)) {
58157
+ const value = await inheritedRetainedFieldEntry(document2, storage, dict, "V", options);
58158
+ if (ft === "Btn") {
58159
+ yield { name, type: "checkbox", value: value?.kind === "name" ? value.decoded !== "Off" : value?.kind === "boolean" ? value.value : false };
58160
+ continue;
58161
+ }
58162
+ let text = value?.kind === "string" ? decodePdfString(value) : value?.kind === "name" ? value.decoded : "";
58163
+ if (value?.kind === "array") {
58164
+ let first = true;
58165
+ for (const item of value.items) {
58166
+ options.signal?.throwIfAborted();
58167
+ const found = await resolve2(item);
58168
+ if (found?.kind === "string" || found?.kind === "name") {
58169
+ text += `${first ? "" : ", "}${found.kind === "string" ? decodePdfString(found) : found.decoded}`;
58170
+ first = false;
58171
+ }
58172
+ }
58173
+ }
58174
+ yield { name, type: ft === "Tx" ? "text" : ft === "Ch" ? "choice" : "unknown", value: text };
58175
+ }
58176
+ }
58177
+
58178
+ // packages/pdf-ast/src/extract/retained-form-field-details.ts
58179
+ async function* walkRetainedFormFieldDetails(document2, storage, options = {}) {
58180
+ let work = 0;
58181
+ async function checkpoint() {
58182
+ options.signal?.throwIfAborted();
58183
+ if (++work % 64 === 0) await new Promise((resolve3) => setTimeout(resolve3, 0));
58184
+ options.signal?.throwIfAborted();
58185
+ }
58186
+ async function resolve2(node) {
58187
+ await checkpoint();
58188
+ const found = await document2.lookup(node);
58189
+ return found?.stream ? void 0 : found?.value;
58190
+ }
58191
+ const text = (node) => node?.kind === "string" ? decodePdfString(node) : node?.kind === "name" ? node.decoded : void 0;
58192
+ for await (const entry of walkRetainedFieldEntries(document2, storage, options)) {
58193
+ let owned2 = function(producer) {
58194
+ async function* visit() {
58195
+ assertActive();
58196
+ readers.add(reader);
58197
+ try {
58198
+ for await (const value2 of producer()) {
58199
+ assertActive();
58200
+ yield value2;
58201
+ }
58202
+ } finally {
58203
+ readers.delete(reader);
58204
+ }
58205
+ }
58206
+ const reader = visit();
58207
+ return reader;
58208
+ };
58209
+ var owned = owned2;
58210
+ const { dict, ft } = entry;
58211
+ let active = true;
58212
+ const readers = /* @__PURE__ */ new Set();
58213
+ const assertActive = () => {
58214
+ options.signal?.throwIfAborted();
58215
+ if (!active) throw new PdfError("E_CAPABILITY", "Retained form field is no longer active");
58216
+ };
58217
+ async function* stateOptions() {
58218
+ const seen = new PdfNameIndex(storage, options.maxStagingBytes, options.signal);
58219
+ let count = 0, failed2 = false;
58220
+ async function* unique(value2) {
58221
+ assertActive();
58222
+ if (value2 && (await seen.intern(value2)).added) {
58223
+ count++;
58224
+ yield value2;
58225
+ }
58226
+ }
58227
+ async function* appearances(field2) {
58228
+ const appearance = await resolve2(dictGet(field2, "AP"));
58229
+ const normal = appearance?.kind === "dict" ? await resolve2(dictGet(appearance, "N")) : void 0;
58230
+ if (normal?.kind === "dict") for (const pair of normal.entries) {
58231
+ await checkpoint();
58232
+ yield* unique(pair.key.decoded);
58233
+ }
58234
+ }
58235
+ try {
58236
+ if (ft === "Btn") {
58237
+ yield* unique("Off");
58238
+ yield* appearances(dict);
58239
+ const kids = await resolve2(dictGet(dict, "Kids"));
58240
+ if (kids?.kind === "array") for (const kid of kids.items) {
58241
+ const field2 = await resolve2(kid);
58242
+ if (field2?.kind === "dict") yield* appearances(field2);
58243
+ }
58244
+ if (count === 1) yield* unique("Yes");
58245
+ }
58246
+ const choices = await inheritedRetainedFieldEntry(document2, storage, dict, "Opt", options);
58247
+ if (choices?.kind === "array") for (const item of choices.items) {
58248
+ let value2 = await resolve2(item);
58249
+ if (value2?.kind === "array" && value2.items.length) value2 = await resolve2(value2.items[value2.items.length - 1]);
58250
+ yield* unique(text(value2));
58251
+ }
58252
+ } catch (error) {
58253
+ failed2 = true;
58254
+ throw error;
58255
+ } finally {
58256
+ await seen.close().catch((error) => {
58257
+ if (!failed2) throw error;
58258
+ });
58259
+ }
58260
+ }
58261
+ const value = await inheritedRetainedFieldEntry(document2, storage, dict, "V", options);
58262
+ const defaultValue = text(await inheritedRetainedFieldEntry(document2, storage, dict, "DV", options));
58263
+ const altName = text(await inheritedRetainedFieldEntry(document2, storage, dict, "TU", options));
58264
+ const checked = ft === "Btn" ? value?.kind === "name" ? value.decoded !== "Off" : value?.kind === "boolean" ? value.value : false : void 0;
58265
+ let stateValue;
58266
+ if (ft === "Btn") {
58267
+ stateValue = value?.kind === "name" ? value.decoded : checked ? "Yes" : "Off";
58268
+ if (checked && value?.kind !== "name") {
58269
+ for await (const option of stateOptions()) if (option !== "Off") {
58270
+ stateValue = option;
58271
+ break;
58272
+ }
58273
+ }
58274
+ }
58275
+ async function* values() {
58276
+ if (stateValue !== void 0) {
58277
+ yield stateValue;
58278
+ return;
58279
+ }
58280
+ if (value?.kind !== "array") {
58281
+ yield text(value) ?? "";
58282
+ return;
58283
+ }
58284
+ let any = false;
58285
+ for (const item of value.items) {
58286
+ const selected = text(await resolve2(item));
58287
+ if (selected !== void 0) {
58288
+ any = true;
58289
+ yield selected;
58290
+ }
58291
+ }
58292
+ if (!any) yield "";
58293
+ }
58294
+ let failed = false;
58295
+ try {
58296
+ yield {
58297
+ name: entry.name,
58298
+ type: ft === "Btn" ? "checkbox" : ft === "Ch" ? "choice" : ft === "Tx" ? "text" : "unknown",
58299
+ flags: entry.flags,
58300
+ justification: entry.justification === 1 ? "Centered" : entry.justification === 2 ? "Right" : "Left",
58301
+ maxLength: entry.maxLength,
58302
+ altName,
58303
+ defaultValue,
58304
+ checked,
58305
+ stateValue,
58306
+ values: () => owned2(values),
58307
+ options: () => owned2(stateOptions)
58308
+ };
58309
+ } catch (error) {
58310
+ failed = true;
58311
+ throw error;
58312
+ } finally {
58313
+ active = false;
58314
+ const results = await Promise.allSettled([...readers].map((reader) => reader.return()));
58315
+ if (!failed) {
58316
+ for (const result of results) if (result.status === "rejected") await Promise.reject(result.reason);
58317
+ }
58318
+ }
58319
+ }
58320
+ }
58321
+
58322
+ // packages/pdf-ast/src/retained-document.ts
58323
+ import { IntegerTable as IntegerTable5, PagedStorage as PagedStorage8 } from "@poe-platform/safe-fs/storage";
58324
+
57616
58325
  // packages/pdf-ast/src/edit/retained-merge-outlines.ts
57617
58326
  var PdfMergeOutlines = class {
57618
58327
  constructor(storage, signal, maxDepth = Infinity) {
@@ -57820,127 +58529,6 @@ async function* walkRetainedPageLabels(document2, storage, options = {}) {
57820
58529
  }
57821
58530
  }
57822
58531
 
57823
- // packages/pdf-ast/src/extract/retained-form-fields.ts
57824
- import { IntegerTable as IntegerTable4, PagedStorage as PagedStorage6 } from "@poe-platform/safe-fs/storage";
57825
- async function* walkRetainedFormFields(document2, storage, options = {}) {
57826
- const signal = options.signal ?? new AbortController().signal, maxDepth = options.maxDepth ?? document2.depthLimit;
57827
- signal.throwIfAborted();
57828
- const frames = new PdfMutableObjectStore(storage, { signal, ...options.maxStagingBytes === void 0 ? {} : { maxStagingBytes: options.maxStagingBytes } });
57829
- const backing = new PagedStorage6({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), active = new IntegerTable4(backing, 64);
57830
- let pending = 0, work = 0, failed = false;
57831
- async function checkpoint(depth = 0) {
57832
- signal.throwIfAborted();
57833
- if (depth > maxDepth) throw new PdfError("E_LIMIT", "PDF form field depth limit exceeded");
57834
- if (++work % 64 === 0) await new Promise((resolve3) => setTimeout(resolve3, 0));
57835
- signal.throwIfAborted();
57836
- }
57837
- async function resolve2(node) {
57838
- const found = await document2.lookup(node);
57839
- return found?.stream ? void 0 : found?.value;
57840
- }
57841
- async function push(node, prefix, ft, depth) {
57842
- await frames.set({ objectNumber: ++pending, generationNumber: 0, value: cosArray([node, cosString(prefix), cosString(ft), cosNumber(depth)]) });
57843
- }
57844
- async function inheritedValue(dict) {
57845
- const seen = new PdfReferenceSet(storage, options.maxStagingBytes, signal);
57846
- let current = dict, depth = 0, failed2 = false;
57847
- try {
57848
- while (current) {
57849
- await checkpoint(++depth);
57850
- const value = dictGet(current, "V");
57851
- if (value !== void 0) return await resolve2(value);
57852
- const parent = dictGet(current, "Parent");
57853
- if (parent?.kind === "ref" && !await seen.add(parent.objectNumber)) return;
57854
- const found = await resolve2(parent);
57855
- current = found?.kind === "dict" ? found : void 0;
57856
- }
57857
- } catch (error) {
57858
- failed2 = true;
57859
- throw error;
57860
- } finally {
57861
- await seen.close().catch((error) => {
57862
- if (!failed2) throw error;
57863
- });
57864
- }
57865
- }
57866
- try {
57867
- const root = await resolve2(document2.crossReference.rootRef), form = root?.kind === "dict" ? await resolve2(dictGet(root, "AcroForm")) : void 0;
57868
- const fields2 = form?.kind === "dict" ? await resolve2(dictGet(form, "Fields")) : void 0;
57869
- if (fields2?.kind !== "array") return;
57870
- for (let i = fields2.items.length - 1; i >= 0; i--) {
57871
- await checkpoint();
57872
- await push(fields2.items[i], "", "", 0);
57873
- }
57874
- while (pending) {
57875
- const frame = (await frames.get(pending--)).value;
57876
- if (frame.kind !== "array") throw new PdfError("E_PARSE", "Invalid form traversal frame");
57877
- const [node, prefixNode, ftNode, depthNode] = frame.items;
57878
- if (frame.items.length === 1 && node?.kind === "number") {
57879
- await active.set(BigInt(node.value), 0n);
57880
- continue;
57881
- }
57882
- if (!node || prefixNode?.kind !== "string" || ftNode?.kind !== "string" || depthNode?.kind !== "number") throw new PdfError("E_PARSE", "Invalid form traversal frame");
57883
- await checkpoint(depthNode.value);
57884
- if (node.kind === "ref") {
57885
- if (await active.get(BigInt(node.objectNumber)) === 1n) continue;
57886
- await active.set(BigInt(node.objectNumber), 1n);
57887
- await frames.set({ objectNumber: ++pending, generationNumber: 0, value: cosArray([cosNumber(node.objectNumber)]) });
57888
- }
57889
- const dict = await resolve2(node);
57890
- if (dict?.kind !== "dict") continue;
57891
- const named = await resolve2(dictGet(dict, "T")), ownFt = await resolve2(dictGet(dict, "FT"));
57892
- const partial = named?.kind === "string" ? decodePdfString(named) : named?.kind === "name" ? named.decoded : "", prefix = decodePdfString(prefixNode);
57893
- const name = prefix && partial ? `${prefix}.${partial}` : partial || prefix, ft = ownFt?.kind === "name" ? ownFt.decoded : decodePdfString(ftNode);
57894
- const kids = await resolve2(dictGet(dict, "Kids"));
57895
- if (kids?.kind === "array" && kids.items.length) {
57896
- let namedKids = false;
57897
- for (const kid of kids.items) {
57898
- await checkpoint();
57899
- const value2 = await resolve2(kid);
57900
- if (value2?.kind === "dict" && dictGet(value2, "T")) {
57901
- namedKids = true;
57902
- break;
57903
- }
57904
- }
57905
- if (namedKids || !ft || !name) {
57906
- for (let i = kids.items.length - 1; i >= 0; i--) {
57907
- await checkpoint();
57908
- await push(kids.items[i], name, ft, depthNode.value + 1);
57909
- }
57910
- continue;
57911
- }
57912
- }
57913
- if (!name) continue;
57914
- const value = await inheritedValue(dict);
57915
- if (ft === "Btn") {
57916
- yield { name, type: "checkbox", value: value?.kind === "name" ? value.decoded !== "Off" : value?.kind === "boolean" ? value.value : false };
57917
- continue;
57918
- }
57919
- let text = value?.kind === "string" ? decodePdfString(value) : value?.kind === "name" ? value.decoded : "";
57920
- if (value?.kind === "array") {
57921
- let first = true;
57922
- for (const item of value.items) {
57923
- await checkpoint();
57924
- const found = await resolve2(item);
57925
- if (found?.kind === "string" || found?.kind === "name") {
57926
- text += `${first ? "" : ", "}${found.kind === "string" ? decodePdfString(found) : found.decoded}`;
57927
- first = false;
57928
- }
57929
- }
57930
- }
57931
- yield { name, type: ft === "Tx" ? "text" : ft === "Ch" ? "choice" : "unknown", value: text };
57932
- }
57933
- } catch (error) {
57934
- failed = true;
57935
- throw error;
57936
- } finally {
57937
- const results = await Promise.allSettled([frames.close(), backing.close()]);
57938
- if (!failed) {
57939
- for (const result of results) if (result.status === "rejected") await Promise.reject(result.reason);
57940
- }
57941
- }
57942
- }
57943
-
57944
58532
  // packages/pdf-ast/src/cos/stored-object-reader.ts
57945
58533
  async function openStoredPdfObjectReader(store, storage, options) {
57946
58534
  let maximum10 = 0, closed = false;
@@ -58661,6 +59249,7 @@ async function prepareRetainedPageContent(document2, page2, pageResources, stora
58661
59249
  const request = step.value;
58662
59250
  let result;
58663
59251
  if (request.kind === "resolve" || request.kind === "catalog") result = await resolve2(request.kind === "catalog" ? document2.crossReference.rootRef : request.node, request.kind === "resolve" ? request.arrayPathPrefix : void 0);
59252
+ else if (request.kind === "dictionary-merge") result = await mergePdfResourceDictionaries(request.destination, request.source, storage, options.signal);
58664
59253
  else if (request.kind === "array-reference") result = cosBool(await memberships.has(request.items, request.objectNumber));
58665
59254
  else if (request.kind === "array-item") {
58666
59255
  const record = await readStoredRecord(request.items.storage, request.position, options.signal);
@@ -58712,124 +59301,6 @@ async function prepareRetainedPageContent(document2, page2, pageResources, stora
58712
59301
 
58713
59302
  // packages/pdf-ast/src/staged-outputs.ts
58714
59303
  import { listenForAbort as listenForAbort3 } from "@poe-platform/safe-fs/contracts";
58715
-
58716
- // packages/pdf-ast/src/cos/name-index.ts
58717
- var PdfNameIndex = class {
58718
- constructor(storage, maximum10 = Infinity, signal) {
58719
- this.storage = storage;
58720
- this.maximum = maximum10;
58721
- this.signal = signal;
58722
- const limit10 = typeof maximum10 === "function" ? maximum10() : maximum10;
58723
- if (limit10 !== Infinity && (!Number.isSafeInteger(limit10) || limit10 < 0)) throw new RangeError("Invalid name staging limit");
58724
- }
58725
- storage;
58726
- maximum;
58727
- signal;
58728
- tail = /* @__PURE__ */ new Map();
58729
- hot = /* @__PURE__ */ new Map();
58730
- levels = [];
58731
- nextNode = 2;
58732
- nextName = 0;
58733
- closed = false;
58734
- get stagedBytes() {
58735
- return this.levels.reduce((sum, index2) => sum + (index2?.size ?? 0) * 32, 0);
58736
- }
58737
- async get(edge) {
58738
- if (this.tail.has(edge)) return this.tail.get(edge);
58739
- if (this.hot.has(edge)) return this.hot.get(edge);
58740
- for (const level of this.levels) {
58741
- const entry = await level?.get(edge, this.signal);
58742
- if (entry) {
58743
- if (this.hot.size < 256) this.hot.set(edge, entry.offset);
58744
- return entry.offset;
58745
- }
58746
- }
58747
- return void 0;
58748
- }
58749
- async insert(edge, node) {
58750
- this.tail.set(edge, node);
58751
- if (this.hot.size < 256) this.hot.set(edge, node);
58752
- if (this.tail.size < 64) return;
58753
- let level = 0;
58754
- while (this.levels[level]) level++;
58755
- const inputs = this.levels.slice(0, level);
58756
- const tail = this.tail;
58757
- const signal = this.signal;
58758
- async function* rows() {
58759
- for (const [objectNumber, offset] of tail) yield { objectNumber, offset, type: "uncompressed" };
58760
- for (const index2 of inputs) yield* index2.entries(signal);
58761
- }
58762
- const limit10 = typeof this.maximum === "function" ? this.maximum() : this.maximum;
58763
- const remaining = Math.min(limit10, Number.MAX_SAFE_INTEGER) - this.stagedBytes;
58764
- if (remaining < 0) throw new PdfError("E_LIMIT", "PDF name staging byte limit exceeded");
58765
- const combined = await PdfObjectIndex.build(rows(), this.storage, {
58766
- runEntries: 64,
58767
- chunkBytes: 2048,
58768
- cacheBytes: 2048,
58769
- maxStagingBytes: remaining,
58770
- ...signal ? { signal } : {}
58771
- });
58772
- try {
58773
- for (let i = 0; i < level; i++) {
58774
- await this.levels[i].close();
58775
- this.levels[i] = void 0;
58776
- }
58777
- this.levels[level] = combined;
58778
- this.tail.clear();
58779
- } catch (error) {
58780
- try {
58781
- await combined.close();
58782
- } catch {
58783
- }
58784
- throw error;
58785
- }
58786
- }
58787
- async intern(value) {
58788
- if (this.closed) throw new PdfError("E_CAPABILITY", "PDF name index is closed");
58789
- this.signal?.throwIfAborted();
58790
- let node = 1, newPath = false;
58791
- const units = typeof value === "string" ? (function* () {
58792
- for (let i = 0; i < value.length; i++) yield value.charCodeAt(i);
58793
- })() : value;
58794
- let work = 0;
58795
- for await (const code of units) {
58796
- this.signal?.throwIfAborted();
58797
- if (!Number.isInteger(code) || code < 0 || code > 65535) throw new RangeError("Invalid PDF name code unit");
58798
- if (++work % 512 === 0) {
58799
- await new Promise((resolve2) => setTimeout(resolve2, 0));
58800
- this.signal?.throwIfAborted();
58801
- }
58802
- for (const unit of [code & 255, code >>> 8]) {
58803
- const edge = node * 257 + unit + 1;
58804
- let child = newPath ? void 0 : await this.get(edge);
58805
- if (child === void 0) {
58806
- if (this.nextNode > Math.floor(Number.MAX_SAFE_INTEGER / 257) - 1) throw new PdfError("E_LIMIT", "PDF name index address limit exceeded");
58807
- child = this.nextNode++;
58808
- await this.insert(edge, child);
58809
- newPath = true;
58810
- }
58811
- node = child;
58812
- }
58813
- }
58814
- const terminal = node * 257;
58815
- const existing = newPath ? void 0 : await this.get(terminal);
58816
- if (existing !== void 0) return { index: existing, added: false };
58817
- const index2 = this.nextName++;
58818
- await this.insert(terminal, index2);
58819
- return { index: index2, added: true };
58820
- }
58821
- async close() {
58822
- if (this.closed) return;
58823
- this.closed = true;
58824
- const results = await Promise.allSettled(this.levels.map((index2) => index2?.close()));
58825
- this.tail.clear();
58826
- this.hot.clear();
58827
- this.levels.length = 0;
58828
- for (const result of results) if (result.status === "rejected") throw result.reason;
58829
- }
58830
- };
58831
-
58832
- // packages/pdf-ast/src/staged-outputs.ts
58833
59304
  function maximum7(value, fallback) {
58834
59305
  const result = value ?? fallback;
58835
59306
  if (result !== Infinity && (!Number.isSafeInteger(result) || result < 0)) throw new RangeError("Invalid PDF output limit");
@@ -59935,6 +60406,7 @@ var PdfRetainedDocument = class _PdfRetainedDocument {
59935
60406
  if (arrayPathPrefix) arrays = {
59936
60407
  ...arrays,
59937
60408
  arrayPathPrefix,
60409
+ ...arrayPathPrefix.length && arrays.storedDictionaryKeys?.includes(arrayPathPrefix[arrayPathPrefix.length - 1]) ? { storeRootDictionary: true } : {},
59938
60410
  ...arrayPathPrefix.length && arrays.storedArrayKeys?.includes(arrayPathPrefix[arrayPathPrefix.length - 1]) ? { storeRootArray: true } : {},
59939
60411
  ...arrayPathPrefix.length && arrays.storedStringKeys?.includes(arrayPathPrefix[arrayPathPrefix.length - 1]) ? { storeRootString: true } : {}
59940
60412
  };
@@ -60032,10 +60504,10 @@ var PdfRetainedDocument = class _PdfRetainedDocument {
60032
60504
  step = work.next(resolved?.stream && resolved.value.kind === "dict" ? { kind: "stream", dict: resolved.value, rawBytes: new Uint8Array() } : resolved?.value);
60033
60505
  } else if (request.kind === "array-item") {
60034
60506
  step = work.next(await this.readArrayItem(request.items, request.position));
60035
- } else if (request.kind === "push-page-frame") {
60507
+ } else if (request.kind === "push-traversal-frame") {
60036
60508
  await frames.push(request.frame);
60037
60509
  step = work.next();
60038
- } else if (request.kind === "pop-page-frame") step = work.next(await frames.pop());
60510
+ } else if (request.kind === "pop-traversal-frame") step = work.next(await frames.pop());
60039
60511
  else if (request.kind === "visit-page") step = work.next(await visited.add(request.reference.objectNumber));
60040
60512
  else throw new TypeError("Unexpected annotation page lookup request");
60041
60513
  }
@@ -60050,6 +60522,123 @@ var PdfRetainedDocument = class _PdfRetainedDocument {
60050
60522
  });
60051
60523
  }
60052
60524
  }
60525
+ /** Resolve a named annotation destination with caller-backed path state. */
60526
+ async annotationNamedDestination(node, name) {
60527
+ this.assertOpen();
60528
+ const storage = new PdfStagingStorage(this.storage, this.options.maxTraversalStagingBytes);
60529
+ let names;
60530
+ const flags = this.options.valueArrays?.arrayStorage;
60531
+ const pending = [];
60532
+ const signal = this.options.signal;
60533
+ async function initialize() {
60534
+ while (pending.length) {
60535
+ const { at, length } = pending.shift();
60536
+ signal?.throwIfAborted();
60537
+ await flags.write(at, new Uint8Array(length), signal ? { signal } : void 0);
60538
+ signal?.throwIfAborted();
60539
+ }
60540
+ }
60541
+ const indexStorage = flags ? {
60542
+ allocate(length) {
60543
+ const at = flags.allocate(length);
60544
+ pending.push({ at, length });
60545
+ return at;
60546
+ },
60547
+ async read(at, length) {
60548
+ await initialize();
60549
+ signal?.throwIfAborted();
60550
+ const bytes = await flags.read(at, length, signal ? { signal } : void 0);
60551
+ signal?.throwIfAborted();
60552
+ return bytes.slice();
60553
+ },
60554
+ async write(at, bytes) {
60555
+ await initialize();
60556
+ signal?.throwIfAborted();
60557
+ await flags.write(at, bytes, signal ? { signal } : void 0);
60558
+ signal?.throwIfAborted();
60559
+ }
60560
+ } : void 0;
60561
+ const references = indexStorage ? new IntegerTable5(indexStorage, 64) : void 0;
60562
+ const unusualReferences = indexStorage ? new IntegerTable5(indexStorage, 64) : void 0;
60563
+ const backing = this.options.valueArrays?.storedArrayKeys?.includes("Kids") ? flags : void 0;
60564
+ const frames = backing ? new StoredMetadataStack(backing, this.options.signal) : [];
60565
+ const buffered = /* @__PURE__ */ new Map(), active = /* @__PURE__ */ new Set();
60566
+ const direct = /* @__PURE__ */ new WeakMap();
60567
+ let failed = false;
60568
+ const work = annotationNameDestinationSteps(node, name, this.depthLimit);
60569
+ try {
60570
+ let step = work.next(), turns = 0;
60571
+ while (!step.done) {
60572
+ if (++turns % 256 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
60573
+ this.assertOpen();
60574
+ const request = step.value;
60575
+ let result;
60576
+ if (request.kind === "resolve") {
60577
+ const resolved = await this.lookup(request.node, void 0, request.arrayKey ? [request.arrayKey] : void 0);
60578
+ result = resolved?.stream && resolved.value.kind === "dict" ? { kind: "stream", dict: resolved.value, rawBytes: new Uint8Array() } : resolved?.value;
60579
+ } else if (request.kind === "array-item") result = await this.readArrayItem(request.items, request.position);
60580
+ else if (request.kind === "push-traversal-frame") await frames.push(request.frame);
60581
+ else if (request.kind === "pop-traversal-frame") result = await frames.pop();
60582
+ else if (request.kind === "enter-name-node") {
60583
+ const node2 = request.node;
60584
+ if (!flags) {
60585
+ const key = node2.kind === "ref" ? `${node2.objectNumber}:${node2.generationNumber}` : node2;
60586
+ let id2 = buffered.get(key);
60587
+ if (id2 === void 0) {
60588
+ id2 = buffered.size;
60589
+ buffered.set(key, id2);
60590
+ }
60591
+ if (!active.has(id2)) {
60592
+ active.add(id2);
60593
+ result = id2;
60594
+ }
60595
+ step = work.next(result);
60596
+ continue;
60597
+ }
60598
+ let id = node2.kind === "ref" ? void 0 : direct.get(node2);
60599
+ if (node2.kind === "ref") {
60600
+ const packed = Number.isSafeInteger(node2.objectNumber) && node2.objectNumber >= 0 && node2.objectNumber <= 281474976710655 && Number.isInteger(node2.generationNumber) && node2.generationNumber >= 0 && node2.generationNumber <= 65535;
60601
+ let key;
60602
+ const table = packed ? references : unusualReferences;
60603
+ if (packed) key = BigInt(node2.objectNumber) << 16n | BigInt(node2.generationNumber);
60604
+ else {
60605
+ names ??= new PdfNameIndex(storage, Infinity, this.options.signal);
60606
+ key = BigInt((await names.intern(`${node2.objectNumber}:${node2.generationNumber}`)).index);
60607
+ }
60608
+ const found = await table.get(key);
60609
+ if (found !== void 0) id = Number(found);
60610
+ else {
60611
+ id = flags.allocate(1);
60612
+ await flags.write(id, Uint8Array.of(0), signal ? { signal } : void 0);
60613
+ await table.set(key, BigInt(id));
60614
+ }
60615
+ } else if (id === void 0) {
60616
+ id = flags.allocate(1);
60617
+ await flags.write(id, Uint8Array.of(0), signal ? { signal } : void 0);
60618
+ direct.set(node2, id);
60619
+ }
60620
+ if ((await flags.read(id, 1, signal ? { signal } : void 0))[0] === 0) {
60621
+ await flags.write(id, Uint8Array.of(1), signal ? { signal } : void 0);
60622
+ result = id;
60623
+ }
60624
+ } else if (request.kind === "leave-name-node") {
60625
+ if (flags) await flags.write(request.identity, Uint8Array.of(0), signal ? { signal } : void 0);
60626
+ else active.delete(request.identity);
60627
+ } else throw new TypeError("Unexpected annotation name lookup request");
60628
+ step = work.next(result);
60629
+ }
60630
+ return step.value;
60631
+ } catch (error) {
60632
+ failed = true;
60633
+ throw error;
60634
+ } finally {
60635
+ work.return(void 0);
60636
+ const results = await Promise.allSettled([names?.close()]);
60637
+ if (!failed) {
60638
+ for (const result of results) if (result.status === "rejected") await Promise.reject(result.reason);
60639
+ }
60640
+ }
60641
+ }
60053
60642
  pages() {
60054
60643
  async function* visit(doc) {
60055
60644
  doc.assertOpen();
@@ -60259,6 +60848,23 @@ var PdfRetainedDocument = class _PdfRetainedDocument {
60259
60848
  const work = visit(this);
60260
60849
  return work;
60261
60850
  }
60851
+ formFieldDetails() {
60852
+ async function* visit(doc) {
60853
+ doc.assertOpen();
60854
+ doc.walks.add(work);
60855
+ try {
60856
+ yield* walkRetainedFormFieldDetails(doc, doc.storage, {
60857
+ maxDepth: doc.depthLimit,
60858
+ ...doc.options.maxTraversalStagingBytes === void 0 ? {} : { maxStagingBytes: doc.options.maxTraversalStagingBytes },
60859
+ ...doc.options.signal ? { signal: doc.options.signal } : {}
60860
+ });
60861
+ } finally {
60862
+ doc.walks.delete(work);
60863
+ }
60864
+ }
60865
+ const work = visit(this);
60866
+ return work;
60867
+ }
60262
60868
  attachments() {
60263
60869
  async function* visit(doc) {
60264
60870
  doc.assertOpen();
@@ -60458,7 +61064,7 @@ var PdfRetainedPage = class {
60458
61064
  /** Pull one annotation at a time. Destination page lookup uses the document's
60459
61065
  * caller-backed traversal index, without retaining a document-wide page map. */
60460
61066
  async *annotations() {
60461
- const work = extractPageAnnotationSteps(this.dict, this.document.crossReference.rootRef, this.document.depthLimit);
61067
+ const work = extractPageAnnotationSteps(this.dict, this.document.crossReference.rootRef);
60462
61068
  try {
60463
61069
  let step = work.next(), turns = 0;
60464
61070
  while (!step.done) {
@@ -60472,6 +61078,7 @@ var PdfRetainedPage = class {
60472
61078
  } else if (request.kind === "array-item") {
60473
61079
  result = await this.document.readArrayItem(request.items, request.position);
60474
61080
  } else if (request.kind === "page-number") result = await this.document.annotationPageNumber(request.reference);
61081
+ else if (request.kind === "named-destination") result = await this.document.annotationNamedDestination(request.node, request.name);
60475
61082
  else throw new TypeError("Unexpected annotation request");
60476
61083
  step = work.next(result);
60477
61084
  }
@@ -60901,7 +61508,7 @@ var PdfMergeAttachments = class {
60901
61508
  };
60902
61509
 
60903
61510
  // packages/pdf-ast/src/edit/retained-page-copy.ts
60904
- import { IntegerTable as IntegerTable5, PagedStorage as PagedStorage10 } from "@poe-platform/safe-fs/storage";
61511
+ import { IntegerTable as IntegerTable6, PagedStorage as PagedStorage10 } from "@poe-platform/safe-fs/storage";
60905
61512
  async function createRetainedPageCopy(input, indicesOrStorage, storageOrOptions, singleOptions = {}) {
60906
61513
  const single = "pages" in input;
60907
61514
  const storage = single ? storageOrOptions : indicesOrStorage;
@@ -60915,7 +61522,7 @@ async function createRetainedPageCopy(input, indicesOrStorage, storageOrOptions,
60915
61522
  const attachments = options.includeAttachments ? new PdfMergeAttachments(storage, signal) : void 0;
60916
61523
  const labels = options.includePageLabels ? new PdfMergeLabels(storage, signal, maximumDepth) : void 0;
60917
61524
  const outlines = options.includeOutlines ? new PdfMergeOutlines(storage, signal, maximumDepth) : void 0;
60918
- const pageReferences = outlines ? new IntegerTable5(lists, 64) : void 0;
61525
+ const pageReferences = outlines ? new IntegerTable6(lists, 64) : void 0;
60919
61526
  const catalog = cosDict({ Type: cosName("Catalog"), Pages: cosRef(2) });
60920
61527
  const pages = { first: 0, last: 0, count: 0 }, formFields = { first: 0, last: 0, count: 0 };
60921
61528
  let mayLinearize = false;
@@ -60965,7 +61572,7 @@ async function createRetainedPageCopy(input, indicesOrStorage, storageOrOptions,
60965
61572
  async function append(document2, pageIndices, resourceState) {
60966
61573
  const backing = new PagedStorage10({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
60967
61574
  const sourcePages = new PdfMutableObjectStore(storage, { maxRecursionDepth: maximumDepth, signal });
60968
- const memo = new IntegerTable5(backing, 64), wanted = new IntegerTable5(backing, 64), sourceReferences = new IntegerTable5(backing, 64);
61575
+ const memo = new IntegerTable6(backing, 64), wanted = new IntegerTable6(backing, 64), sourceReferences = new IntegerTable6(backing, 64);
60969
61576
  let firstSelection = 0, lastSelection = 0, sourceFailed = false;
60970
61577
  async function* selections() {
60971
61578
  let position = firstSelection;
@@ -61173,7 +61780,7 @@ async function createRetainedPageCopy(input, indicesOrStorage, storageOrOptions,
61173
61780
  }
61174
61781
  if (fields2?.kind === "array" && acro?.kind === "dict") {
61175
61782
  let addedFields = false;
61176
- const rootNumbers = new IntegerTable5(backing, 64);
61783
+ const rootNumbers = new IntegerTable6(backing, 64);
61177
61784
  for (const field2 of fields2.items) {
61178
61785
  if (!await hasCloned(field2)) continue;
61179
61786
  const cloned = await clone(field2);
@@ -61323,6 +61930,26 @@ async function* retainedCosObjects(document2, storage, options = {}) {
61323
61930
  yield identity;
61324
61931
  continue;
61325
61932
  }
61933
+ if (options.streamMode && options.streamMode !== "preserve" && object.value.kind === "dict") {
61934
+ const activeSignal = signal ?? new AbortController().signal;
61935
+ const input = document2.objects.decodeStream(entry.objectNumber, generationNumber);
61936
+ const staged2 = options.streamMode === "compress" ? await stageDeflatedPdf(input, storage, activeSignal, maxStreamBytes) : await PdfFileSource.fromStream(storage.fs, storage.directory, input, { signal: activeSignal, maxInputBytes: maxStreamBytes });
61937
+ let failed2 = false;
61938
+ try {
61939
+ const value = { ...object.value, entries: object.value.entries.filter((item) => item.key.decoded !== "Filter" && item.key.decoded !== "DecodeParms") };
61940
+ if (options.streamMode === "compress") dictSet(value, "Filter", cosName("FlateDecode"));
61941
+ dictSet(value, "Length", cosNumber(staged2.size));
61942
+ yield { ...identity, value, stream: { decoded: true, length: staged2.size, chunks: staged2.stream(0, staged2.size, activeSignal) } };
61943
+ } catch (error) {
61944
+ failed2 = true;
61945
+ throw error;
61946
+ } finally {
61947
+ await staged2.close().catch((error) => {
61948
+ if (!failed2) throw error;
61949
+ });
61950
+ }
61951
+ continue;
61952
+ }
61326
61953
  if (options.normalizeContent && object.decoded && object.value.kind === "dict") {
61327
61954
  const decoded2 = await PdfFileSource.fromStream(storage.fs, storage.directory, document2.objects.decodeStream(entry.objectNumber, generationNumber), { ...signal ? { signal } : {}, maxInputBytes: maxStreamBytes });
61328
61955
  let failed2 = false;
@@ -61380,10 +62007,10 @@ async function* retainedCosObjects(document2, storage, options = {}) {
61380
62007
  }
61381
62008
 
61382
62009
  // packages/pdf-ast/src/cos/retained-object-streams.ts
61383
- import { IntegerTable as IntegerTable6, PagedStorage as PagedStorage11 } from "@poe-platform/safe-fs/storage";
62010
+ import { IntegerTable as IntegerTable7, PagedStorage as PagedStorage11 } from "@poe-platform/safe-fs/storage";
61384
62011
  async function* serializeRetainedObjectStreams(store, storage, options, objects, fallback) {
61385
62012
  const signal = options.signal ?? new AbortController().signal;
61386
- const backing = new PagedStorage11({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), packed = new IntegerTable6(backing);
62013
+ const backing = new PagedStorage11({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), packed = new IntegerTable7(backing);
61387
62014
  let count = 0, highest = 0, failed = false, compressed;
61388
62015
  try {
61389
62016
  for await (const identity of store.identities()) {
@@ -61541,7 +62168,7 @@ async function* saveRetainedDocumentChunks(document2, storage, options = {}) {
61541
62168
  }
61542
62169
  }
61543
62170
  try {
61544
- for await (const object of retainedCosObjects(document2, storage, { ...options.normalizeContent ? { normalizeContent: true } : {}, ...options.maxObjects === void 0 ? {} : { maxObjects: options.maxObjects }, ...options.maxOutputBytes === void 0 ? {} : { maxStreamBytes: options.maxOutputBytes }, signal })) {
62171
+ for await (const object of retainedCosObjects(document2, storage, { ...options.streamMode ? { streamMode: options.streamMode } : {}, ...options.normalizeContent ? { normalizeContent: true } : {}, ...options.maxObjects === void 0 ? {} : { maxObjects: options.maxObjects }, ...options.maxOutputBytes === void 0 ? {} : { maxStreamBytes: options.maxOutputBytes }, signal })) {
61545
62172
  if (!object.stream && object.value.kind === "dict" && dictGet(object.value, "Linearized") !== void 0) mayLinearize = true;
61546
62173
  await objects.set(object);
61547
62174
  }
@@ -61653,8 +62280,208 @@ async function* saveRetainedDocumentChunks(document2, storage, options = {}) {
61653
62280
  }
61654
62281
  }
61655
62282
 
62283
+ // packages/pdf-ast/src/edit/retained-bookmarks.ts
62284
+ import { PagedStorage as PagedStorage13 } from "@poe-platform/safe-fs/storage";
62285
+ async function setRetainedBookmarks(store, storage, root, pageCount, pageReference, bookmarks, signal, maxDepth = Infinity) {
62286
+ if (!pageCount) return;
62287
+ const catalog = await store.get(root.objectNumber);
62288
+ if (catalog?.value.kind !== "dict") return;
62289
+ const frames = new PagedStorage13({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
62290
+ const base = frames.allocate(0);
62291
+ let depth = 0, capacity = 0, failed = false, work = 0;
62292
+ async function write(index2, frame) {
62293
+ if (index2 >= capacity) {
62294
+ frames.allocate(24);
62295
+ capacity++;
62296
+ }
62297
+ const bytes = new Uint8Array(24), view = new DataView(bytes.buffer);
62298
+ view.setFloat64(0, frame.number);
62299
+ view.setFloat64(8, frame.last);
62300
+ view.setFloat64(16, frame.count);
62301
+ await frames.write(base + index2 * 24, bytes);
62302
+ }
62303
+ async function read(index2) {
62304
+ const bytes = await frames.read(base + index2 * 24, 24), view = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
62305
+ return { number: view.getFloat64(0), last: view.getFloat64(8), count: view.getFloat64(16) };
62306
+ }
62307
+ try {
62308
+ for await (const bookmark of bookmarks) {
62309
+ signal.throwIfAborted();
62310
+ if (++work % 64 === 0) {
62311
+ await new Promise((resolve2) => setTimeout(resolve2, 0));
62312
+ signal.throwIfAborted();
62313
+ }
62314
+ if (!Number.isSafeInteger(bookmark.level) || !Number.isSafeInteger(bookmark.pageNumber)) throw new RangeError("Bookmark level and page number must be safe integers");
62315
+ if (!depth) {
62316
+ const outlines = await store.allocate(cosDict({ Type: cosName("Outlines") }));
62317
+ dictSet(catalog.value, "Outlines", outlines);
62318
+ await store.set(catalog);
62319
+ await write(0, { number: outlines.objectNumber, last: 0, count: 0 });
62320
+ depth = 1;
62321
+ }
62322
+ const target = Math.max(1, bookmark.level);
62323
+ depth = Math.min(depth, target);
62324
+ while (depth < target) {
62325
+ const parent2 = await read(depth - 1);
62326
+ if (!parent2.last) break;
62327
+ if (depth >= maxDepth) throw new PdfError("E_LIMIT", "PDF bookmark depth limit exceeded");
62328
+ await write(depth, { number: parent2.last, last: 0, count: 0 });
62329
+ depth++;
62330
+ }
62331
+ const frame = await read(depth - 1), parent = await store.get(frame.number);
62332
+ if (parent.value.kind !== "dict") throw new PdfError("E_PARSE", "Expected outline parent dictionary");
62333
+ const page2 = await pageReference(Math.max(0, Math.min(pageCount - 1, bookmark.pageNumber - 1)));
62334
+ const value = cosDict({ Title: cosString(bookmark.title), Parent: cosRef(frame.number), Dest: cosArray([page2, cosName("XYZ"), { kind: "null" }, { kind: "null" }, { kind: "null" }]) });
62335
+ const item = await store.allocate(value);
62336
+ if (frame.last) {
62337
+ const previous = await store.get(frame.last);
62338
+ if (previous.value.kind !== "dict") throw new PdfError("E_PARSE", "Expected outline sibling dictionary");
62339
+ dictSet(previous.value, "Next", item);
62340
+ await store.set(previous);
62341
+ dictSet(value, "Prev", cosRef(frame.last));
62342
+ await store.set({ objectNumber: item.objectNumber, generationNumber: item.generationNumber, value });
62343
+ } else dictSet(parent.value, "First", item);
62344
+ dictSet(parent.value, "Last", item);
62345
+ dictSet(parent.value, "Count", cosNumber(++frame.count));
62346
+ await store.set(parent);
62347
+ frame.last = item.objectNumber;
62348
+ await write(depth - 1, frame);
62349
+ }
62350
+ } catch (error) {
62351
+ failed = true;
62352
+ throw error;
62353
+ } finally {
62354
+ await frames.close().catch((error) => {
62355
+ if (!failed) throw error;
62356
+ });
62357
+ }
62358
+ }
62359
+
62360
+ // packages/pdf-ast/src/edit/retained-append-attachments.ts
62361
+ async function appendRetainedAttachments(document2, target, storage, attachments, options = {}) {
62362
+ const signal = options.signal ?? new AbortController().signal, appended = new PdfMutableObjectStore(storage, { signal });
62363
+ let failed = false, count = 0;
62364
+ async function resolve2(node) {
62365
+ const found = await document2.lookup(node);
62366
+ return found?.stream ? void 0 : found;
62367
+ }
62368
+ async function save(reference, value) {
62369
+ await target.set({ objectNumber: reference.objectNumber, generationNumber: reference.generationNumber, value });
62370
+ }
62371
+ try {
62372
+ const root = await resolve2(document2.crossReference.rootRef);
62373
+ if (root?.value.kind !== "dict" || !root.reference) return;
62374
+ let owner = root;
62375
+ let names = await resolve2(dictGet(root.value, "Names"));
62376
+ if (names?.value.kind !== "dict") {
62377
+ const value = cosDict({}), reference = await target.allocate(value);
62378
+ names = { value, reference };
62379
+ dictSet(root.value, "Names", reference);
62380
+ await save(root.reference, root.value);
62381
+ }
62382
+ if (names.value.kind !== "dict") throw new Error("Invalid attachment names");
62383
+ if (names.reference) owner = names;
62384
+ let tree = await resolve2(dictGet(names.value, "EmbeddedFiles"));
62385
+ if (tree?.value.kind !== "dict") {
62386
+ const value = cosDict({ Names: cosArray([]) }), reference = await target.allocate(value);
62387
+ tree = { value, reference };
62388
+ dictSet(names.value, "EmbeddedFiles", reference);
62389
+ await save(owner.reference, owner.value);
62390
+ }
62391
+ if (tree.value.kind !== "dict") throw new Error("Invalid attachment tree");
62392
+ if (tree.reference) owner = tree;
62393
+ const existing = await resolve2(dictGet(tree.value, "Names")), namesMarker = cosArray([]);
62394
+ if (existing?.value.kind === "array" && existing.reference) owner = { value: namesMarker, reference: existing.reference };
62395
+ else dictSet(tree.value, "Names", namesMarker);
62396
+ let pageOwner, previousAnnots;
62397
+ const annotsMarker = cosArray([]);
62398
+ if (options.pageIndex !== void 0) for await (const page2 of document2.pages()) {
62399
+ if (page2.index !== options.pageIndex) continue;
62400
+ if (page2.reference) {
62401
+ const annots = await resolve2(dictGet(page2.dict, "Annots"));
62402
+ previousAnnots = annots?.value.kind === "array" ? annots.value : void 0;
62403
+ if (annots?.value.kind === "array" && annots.reference) pageOwner = { value: annotsMarker, reference: annots.reference };
62404
+ else {
62405
+ dictSet(page2.dict, "Annots", annotsMarker);
62406
+ pageOwner = { value: page2.dict, reference: page2.reference };
62407
+ }
62408
+ }
62409
+ break;
62410
+ }
62411
+ for await (const attachment of attachments) {
62412
+ signal.throwIfAborted();
62413
+ const compressed = await stageDeflatedPdf(attachment.chunks, storage, signal);
62414
+ let itemFailed = false;
62415
+ try {
62416
+ const embedded = await target.allocate();
62417
+ await target.set({ objectNumber: embedded.objectNumber, generationNumber: 0, value: cosDict({ Type: cosName("EmbeddedFile"), Filter: cosName("FlateDecode"), Length: cosNumber(compressed.size) }), stream: { decoded: true, length: compressed.size, chunks: compressed.stream(0, compressed.size, signal) } });
62418
+ const reference = await target.allocate(cosDict({ Type: cosName("Filespec"), F: cosString(attachment.filename), UF: cosString(attachment.filename), EF: cosDict({ F: embedded }) }));
62419
+ let annotation;
62420
+ if (pageOwner) annotation = await target.allocate(cosDict({ Type: cosName("Annot"), Subtype: cosName("FileAttachment"), Name: cosName("PushPin"), Contents: cosString(attachment.filename), FS: reference, Rect: cosArray([20, 20, 40, 40].map((value) => cosNumber(value))) }));
62421
+ await appended.set({ objectNumber: ++count, generationNumber: 0, value: cosArray([cosString(attachment.filename), reference, ...annotation ? [annotation] : []]) });
62422
+ } catch (error) {
62423
+ itemFailed = true;
62424
+ throw error;
62425
+ } finally {
62426
+ await compressed.close().catch((error) => {
62427
+ if (!itemFailed) throw error;
62428
+ });
62429
+ }
62430
+ }
62431
+ const encoder = new TextEncoder();
62432
+ async function* serialized(node) {
62433
+ signal.throwIfAborted();
62434
+ if (node === namesMarker || node === annotsMarker) {
62435
+ yield encoder.encode("[ ");
62436
+ const old = node === namesMarker ? existing?.value : previousAnnots;
62437
+ if (old?.kind === "array") for (const item of old.items) {
62438
+ yield* serializeCosNodeChunks(item, { signal });
62439
+ yield encoder.encode(" ");
62440
+ }
62441
+ for await (const pair of appended.objects()) {
62442
+ if (pair.value.kind !== "array") throw new Error("Invalid attachment pair");
62443
+ const items = node === namesMarker ? pair.value.items.slice(0, 2) : pair.value.items.slice(2);
62444
+ for (const item of items) {
62445
+ yield* serializeCosNodeChunks(item, { signal });
62446
+ yield encoder.encode(" ");
62447
+ }
62448
+ }
62449
+ yield encoder.encode("]");
62450
+ } else if (node.kind === "dict") {
62451
+ yield encoder.encode("<<\n");
62452
+ for (const entry of node.entries) {
62453
+ yield* serializeCosNodeChunks(entry.key, { signal });
62454
+ yield encoder.encode(" ");
62455
+ yield* serialized(entry.value);
62456
+ yield encoder.encode("\n");
62457
+ }
62458
+ yield encoder.encode(">>");
62459
+ } else if (node.kind === "array") {
62460
+ yield encoder.encode("[ ");
62461
+ for (const item of node.items) {
62462
+ yield* serialized(item);
62463
+ yield encoder.encode(" ");
62464
+ }
62465
+ yield encoder.encode("]");
62466
+ } else yield* serializeCosNodeChunks(node, { signal });
62467
+ }
62468
+ for (const edited of [owner, ...pageOwner && count ? [pageOwner] : []]) {
62469
+ let length = 0;
62470
+ for await (const bytes of serialized(edited.value)) length += bytes.length;
62471
+ await target.setSerializedValue({ objectNumber: edited.reference.objectNumber, generationNumber: edited.reference.generationNumber, body: { length, chunks: serialized(edited.value) } });
62472
+ }
62473
+ } catch (error) {
62474
+ failed = true;
62475
+ throw error;
62476
+ } finally {
62477
+ await appended.close().catch((error) => {
62478
+ if (!failed) throw error;
62479
+ });
62480
+ }
62481
+ }
62482
+
61656
62483
  // packages/pdf-ast/src/edit/retained-form-appearances.ts
61657
- import { IntegerTable as IntegerTable7, PagedStorage as PagedStorage13 } from "@poe-platform/safe-fs/storage";
62484
+ import { IntegerTable as IntegerTable8, PagedStorage as PagedStorage14 } from "@poe-platform/safe-fs/storage";
61658
62485
 
61659
62486
  // packages/pdf-ast/src/edit/form-appearance-chunks.ts
61660
62487
  function* serializeFormAppearanceChunks(text, options) {
@@ -61742,7 +62569,7 @@ function* operators(text, options) {
61742
62569
  // packages/pdf-ast/src/edit/retained-form-appearances.ts
61743
62570
  async function generateRetainedFormAppearances(document2, store, storage, signal) {
61744
62571
  if (!document2.crossReference.rootRef) return;
61745
- const backing = new PagedStorage13({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), active = new IntegerTable7(backing);
62572
+ const backing = new PagedStorage14({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), active = new IntegerTable8(backing);
61746
62573
  let head = -1, failed = false, work = 0;
61747
62574
  let defaultAppearance;
61748
62575
  async function checkpoint(depth = 0) {
@@ -61949,17 +62776,17 @@ async function generateRetainedFormAppearances(document2, store, storage, signal
61949
62776
  }
61950
62777
 
61951
62778
  // packages/pdf-ast/src/edit/retained-flatten-annotations.ts
61952
- import { IntegerTable as IntegerTable9, PagedStorage as PagedStorage17 } from "@poe-platform/safe-fs/storage";
62779
+ import { IntegerTable as IntegerTable10, PagedStorage as PagedStorage18 } from "@poe-platform/safe-fs/storage";
61953
62780
 
61954
62781
  // packages/pdf-ast/src/edit/retained-content-edit.ts
61955
- import { IntegerTable as IntegerTable8, PagedStorage as PagedStorage14 } from "@poe-platform/safe-fs/storage";
62782
+ import { IntegerTable as IntegerTable9, PagedStorage as PagedStorage15 } from "@poe-platform/safe-fs/storage";
61956
62783
  var RetainedContentEditor = class _RetainedContentEditor {
61957
62784
  constructor(store, storage, signal) {
61958
62785
  this.store = store;
61959
62786
  this.storage = storage;
61960
62787
  this.signal = signal;
61961
- this.backing = new PagedStorage14({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
61962
- this.counts = new IntegerTable8(this.backing);
62788
+ this.backing = new PagedStorage15({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
62789
+ this.counts = new IntegerTable9(this.backing);
61963
62790
  this.identities = new PdfNameIndex(storage, Infinity, signal);
61964
62791
  }
61965
62792
  store;
@@ -61999,6 +62826,12 @@ var RetainedContentEditor = class _RetainedContentEditor {
61999
62826
  await this.count(value, 1n);
62000
62827
  await this.store.set({ objectNumber: reference.objectNumber, generationNumber: reference.generationNumber, value, ...stream ? { stream } : {} });
62001
62828
  }
62829
+ async setSerialized(reference, body, values) {
62830
+ const old = await this.store.get(reference.objectNumber);
62831
+ if (old) await this.count(old.value, -1n);
62832
+ for await (const node of values) await this.count(node, 1n);
62833
+ await this.store.setSerializedValue({ objectNumber: reference.objectNumber, generationNumber: reference.generationNumber, body });
62834
+ }
62002
62835
  async replace(page2, chunks, compress = true) {
62003
62836
  const source = compress ? await stageDeflatedPdf(chunks, this.storage, this.signal) : await PdfFileSource.fromStream(this.storage.fs, this.storage.directory, chunks, { signal: this.signal });
62004
62837
  let failed = false;
@@ -62024,14 +62857,14 @@ var RetainedContentEditor = class _RetainedContentEditor {
62024
62857
  };
62025
62858
 
62026
62859
  // packages/pdf-ast/src/edit/retained-name-replacement.ts
62027
- import { PagedStorage as PagedStorage15 } from "@poe-platform/safe-fs/storage";
62860
+ import { PagedStorage as PagedStorage16 } from "@poe-platform/safe-fs/storage";
62028
62861
  async function* replaceRetainedPdfName(input, oldName, newName, storage, options = {}) {
62029
62862
  const chunkBytes = options.chunkBytes ?? 16384, maximum10 = options.maxOutputBytes ?? Infinity;
62030
62863
  if (!Number.isSafeInteger(chunkBytes) || chunkBytes < 1) throw new RangeError("Invalid name replacement chunk size");
62031
62864
  if (maximum10 !== Infinity && (!Number.isSafeInteger(maximum10) || maximum10 < 0)) throw new RangeError("Invalid name replacement output limit");
62032
62865
  const signal = options.signal ?? new AbortController().signal;
62033
62866
  signal.throwIfAborted();
62034
- const table = new PagedStorage15({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), length = oldName.length + 1;
62867
+ const table = new PagedStorage16({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), length = oldName.length + 1;
62035
62868
  const base = table.allocate(length * 8), record = new Uint8Array(8), view = new DataView(record.buffer);
62036
62869
  const pattern = (at) => at ? oldName.charCodeAt(at - 1) : 47;
62037
62870
  let buffer = new Uint8Array(chunkBytes), used = 0, total = 0, work = 0, failed = false;
@@ -62109,10 +62942,10 @@ async function* replaceRetainedPdfName(input, oldName, newName, storage, options
62109
62942
  }
62110
62943
 
62111
62944
  // packages/pdf-ast/src/edit/retained-draw-text.ts
62112
- import { PagedStorage as PagedStorage16 } from "@poe-platform/safe-fs/storage";
62945
+ import { PagedStorage as PagedStorage17 } from "@poe-platform/safe-fs/storage";
62113
62946
  async function drawRetainedAnnotationText(page2, editor, storage, text, x, y, isolated, font, signal) {
62114
62947
  const source = await PdfFileSource.fromStream(storage.fs, storage.directory, page2.streamContents(), { signal });
62115
- const backing = new PagedStorage16({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
62948
+ const backing = new PagedStorage17({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
62116
62949
  let failed = false;
62117
62950
  try {
62118
62951
  const name = await font(), position = backing.allocate(text.length);
@@ -62188,7 +63021,7 @@ async function flattenRetainedAnnotations(document2, store, storage, mode, signa
62188
63021
  for await (const page2 of document2.pages()) {
62189
63022
  const annotations = await array(dictGet(page2.dict, "Annots"));
62190
63023
  if (!annotations) continue;
62191
- const survivorStorage = new PagedStorage17({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
63024
+ const survivorStorage = new PagedStorage18({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
62192
63025
  const survivorBase = survivorStorage.allocate(0);
62193
63026
  let pageFailed = false;
62194
63027
  try {
@@ -62274,7 +63107,7 @@ async function flattenRetainedAnnotations(document2, store, storage, mode, signa
62274
63107
  }
62275
63108
  if (normal?.stream && normal.reference && normal.value.kind === "dict") {
62276
63109
  let content = await PdfFileSource.fromStream(storage.fs, storage.directory, document2.objects.decodeStream(normal.reference.objectNumber, normal.reference.generationNumber), { signal });
62277
- const backing = new PagedStorage17({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), renames = new IntegerTable9(backing), names = new PdfNameIndex(storage, Infinity, signal);
63110
+ const backing = new PagedStorage18({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), renames = new IntegerTable10(backing), names = new PdfNameIndex(storage, Infinity, signal);
62278
63111
  let appearanceFailed = false, count = 0;
62279
63112
  try {
62280
63113
  if (content.size) {
@@ -62392,8 +63225,294 @@ q ${scaleX} 0 0 ${scaleY} ${tx} ${ty} cm${matSuffix}
62392
63225
  }
62393
63226
  }
62394
63227
 
63228
+ // packages/pdf-ast/src/edit/retained-name-map.ts
63229
+ import { PagedStorage as PagedStorage19 } from "@poe-platform/safe-fs/storage";
63230
+ async function* replaceRetainedPdfNames(input, names, storage, options = {}) {
63231
+ const signal = options.signal ?? new AbortController().signal, size = options.chunkBytes ?? 16384;
63232
+ if (!Number.isSafeInteger(size) || size < 1) throw new RangeError("Invalid name replacement chunk size");
63233
+ const trie = new PagedStorage19({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), pending = new PagedStorage19({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
63234
+ const root = trie.allocate(40), prefixBase = pending.allocate(0);
63235
+ let output = new Uint8Array(size), used = 0, failed = false, work = 0;
63236
+ const body = (byte3) => byte3 >= 48 && byte3 <= 57 || byte3 >= 65 && byte3 <= 90 || byte3 >= 97 && byte3 <= 122 || [95, 46, 43, 45].includes(byte3);
63237
+ async function checkpoint() {
63238
+ signal.throwIfAborted();
63239
+ if (++work % 16384 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
63240
+ }
63241
+ async function get(at) {
63242
+ const bytes = await trie.read(at, 40);
63243
+ return new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
63244
+ }
63245
+ async function put(at, row) {
63246
+ await trie.write(at, new Uint8Array(row.buffer, row.byteOffset, row.byteLength));
63247
+ }
63248
+ async function child(at, byte3, create) {
63249
+ const parent = await get(at);
63250
+ let current = parent.getFloat64(0);
63251
+ while (current) {
63252
+ const row2 = await get(current);
63253
+ if (row2.getFloat64(16) === byte3) return current;
63254
+ current = row2.getFloat64(8);
63255
+ }
63256
+ if (!create) return;
63257
+ const next = trie.allocate(40), row = new DataView(new ArrayBuffer(40));
63258
+ row.setFloat64(8, parent.getFloat64(0));
63259
+ row.setFloat64(16, byte3);
63260
+ await put(next, row);
63261
+ parent.setFloat64(0, next);
63262
+ await put(at, parent);
63263
+ return next;
63264
+ }
63265
+ function emit(byte3) {
63266
+ output[used++] = byte3;
63267
+ if (used === size) {
63268
+ const full = output;
63269
+ output = new Uint8Array(size);
63270
+ used = 0;
63271
+ return full;
63272
+ }
63273
+ }
63274
+ async function* replay(store, start, length) {
63275
+ for (let at = 0; at < length; at += size) for (const byte3 of await store.read(start + at, Math.min(size, length - at))) {
63276
+ await checkpoint();
63277
+ const full = emit(byte3);
63278
+ if (full) yield full;
63279
+ }
63280
+ }
63281
+ try {
63282
+ for await (const [name, replacement] of names) {
63283
+ let node2 = root, valid = true;
63284
+ for (let i = 0; i < name.length; i++) {
63285
+ await checkpoint();
63286
+ if (!body(name.charCodeAt(i))) {
63287
+ valid = false;
63288
+ break;
63289
+ }
63290
+ node2 = await child(node2, name.charCodeAt(i), true);
63291
+ }
63292
+ if (!valid) continue;
63293
+ const start = trie.allocate(replacement.length), row = await get(node2);
63294
+ row.setFloat64(24, start + 1);
63295
+ row.setFloat64(32, replacement.length);
63296
+ await put(node2, row);
63297
+ for (let at = 0; at < replacement.length; at += size) {
63298
+ const bytes = new Uint8Array(Math.min(size, replacement.length - at));
63299
+ for (let i = 0; i < bytes.length; i++) bytes[i] = replacement.charCodeAt(at + i);
63300
+ await trie.write(start + at, bytes);
63301
+ }
63302
+ }
63303
+ let matching = false, node = root, length = 0, capacity = 0, buffered = 0;
63304
+ const prefix = new Uint8Array(size);
63305
+ async function flushPrefix() {
63306
+ if (buffered) {
63307
+ if (length > capacity) {
63308
+ pending.allocate(length - capacity);
63309
+ capacity = length;
63310
+ }
63311
+ await pending.write(prefixBase + length - buffered, prefix.subarray(0, buffered));
63312
+ buffered = 0;
63313
+ }
63314
+ }
63315
+ async function* finish() {
63316
+ await flushPrefix();
63317
+ const row = await get(node), replacement = row.getFloat64(24);
63318
+ const slash = emit(47);
63319
+ if (slash) yield slash;
63320
+ if (replacement) yield* replay(trie, replacement - 1, row.getFloat64(32));
63321
+ else yield* replay(pending, prefixBase, length);
63322
+ matching = false;
63323
+ }
63324
+ for await (const bytes of input) for (const byte3 of bytes) {
63325
+ await checkpoint();
63326
+ if (matching && body(byte3)) {
63327
+ const next = await child(node, byte3, false);
63328
+ if (next !== void 0) {
63329
+ node = next;
63330
+ prefix[buffered++] = byte3;
63331
+ length++;
63332
+ if (buffered === size) await flushPrefix();
63333
+ continue;
63334
+ }
63335
+ await flushPrefix();
63336
+ const slash = emit(47);
63337
+ if (slash) yield slash;
63338
+ yield* replay(pending, prefixBase, length);
63339
+ matching = false;
63340
+ } else if (matching) yield* finish();
63341
+ if (byte3 === 47) {
63342
+ matching = true;
63343
+ node = root;
63344
+ length = 0;
63345
+ buffered = 0;
63346
+ } else {
63347
+ const full = emit(byte3);
63348
+ if (full) yield full;
63349
+ }
63350
+ }
63351
+ if (matching) yield* finish();
63352
+ if (used) yield output.subarray(0, used);
63353
+ } catch (error) {
63354
+ failed = true;
63355
+ throw error;
63356
+ } finally {
63357
+ const results = await Promise.allSettled([trie.close(), pending.close()]);
63358
+ if (!failed) {
63359
+ for (const result of results) if (result.status === "rejected") await Promise.reject(result.reason);
63360
+ }
63361
+ }
63362
+ }
63363
+
63364
+ // packages/pdf-ast/src/edit/retained-preserve-stamp.ts
63365
+ async function preserveRetainedStamp(document2, source, page2, other, store, editor, storage, clone, mode, signal) {
63366
+ const renames = new PdfMutableObjectStore(storage, { signal }), additions = new PdfMutableObjectStore(storage, { signal });
63367
+ let addedCount = 0, count = 0, failed = false, work = 0;
63368
+ const owners = /* @__PURE__ */ new Map();
63369
+ const key = (ref) => `${ref.objectNumber}:${ref.generationNumber}`;
63370
+ if (page2.reference) owners.set(key(page2.reference), { reference: page2.reference, value: page2.dict });
63371
+ async function checkpoint() {
63372
+ signal.throwIfAborted();
63373
+ if (++work % 64 === 0) await new Promise((resolve2) => setTimeout(resolve2, 0));
63374
+ }
63375
+ async function dictionary(node) {
63376
+ const cached = node?.kind === "ref" ? owners.get(key(node)) : void 0;
63377
+ if (cached) return cached;
63378
+ const found = await document2.lookup(node);
63379
+ if (found?.stream || found?.value.kind !== "dict") return;
63380
+ const result = { ...found, value: found.value };
63381
+ if (result.reference) owners.set(key(result.reference), { reference: result.reference, value: result.value });
63382
+ return result;
63383
+ }
63384
+ async function stream(chunks) {
63385
+ const staged = await PdfFileSource.fromStream(storage.fs, storage.directory, chunks, { signal });
63386
+ let failed2 = false;
63387
+ try {
63388
+ const reference = await store.allocate();
63389
+ await editor.set(reference, cosDict({ Length: cosNumber(staged.size) }), { decoded: true, length: staged.size, chunks: staged.stream(0, staged.size, signal) });
63390
+ return reference;
63391
+ } catch (error) {
63392
+ failed2 = true;
63393
+ throw error;
63394
+ } finally {
63395
+ await staged.close().catch((error) => {
63396
+ if (!failed2) throw error;
63397
+ });
63398
+ }
63399
+ }
63400
+ async function* mappings() {
63401
+ for await (const object of renames.objects()) if (object.value.kind === "array" && object.value.items[0]?.kind === "string" && object.value.items[1]?.kind === "string") {
63402
+ const [name, replacement] = object.value.items;
63403
+ yield [decodePdfString(name), decodePdfString(replacement)];
63404
+ }
63405
+ }
63406
+ try {
63407
+ const dstAttributes = await page2.attributes(), srcAttributes = await other.attributes();
63408
+ let resources = await dictionary(dictGet(page2.dict, "Resources"));
63409
+ if (!resources) {
63410
+ const entries = [];
63411
+ for (const entry of dstAttributes.resources.entries) {
63412
+ const sub = await document2.lookup(entry.value);
63413
+ entries.push({ key: { ...entry.key }, value: sub?.value.kind === "dict" && !sub.stream ? cosDict(Object.fromEntries(sub.value.entries.map((item) => [item.key.decoded, item.value]))) : entry.value });
63414
+ }
63415
+ resources = { value: { kind: "dict", entries } };
63416
+ dictSet(page2.dict, "Resources", resources.value);
63417
+ }
63418
+ for (const category of ["Font", "XObject", "ExtGState", "ColorSpace", "Pattern", "Shading", "Properties"]) {
63419
+ const src = await source.lookup(dictGet(srcAttributes.resources, category));
63420
+ if (src?.stream || src?.value.kind !== "dict") continue;
63421
+ let dst = await dictionary(dictGet(resources.value, category));
63422
+ if (!dst) {
63423
+ dst = { value: cosDict({}) };
63424
+ dictSet(resources.value, category, dst.value);
63425
+ }
63426
+ for (const entry of src.value.entries) {
63427
+ await checkpoint();
63428
+ const value = await clone(entry.value), original = entry.key.decoded;
63429
+ let name = original;
63430
+ if (dictGet(dst.value, original)) {
63431
+ name = `Ov_${page2.index}_${original}`;
63432
+ let suffix = 1;
63433
+ while (dictGet(dst.value, name)) {
63434
+ await checkpoint();
63435
+ name = `Ov_${page2.index}_${suffix++}_${original}`;
63436
+ }
63437
+ await renames.set({ objectNumber: ++count, generationNumber: 0, value: cosArray([cosString(original), cosString(name)]) });
63438
+ }
63439
+ dictSet(dst.value, name, value);
63440
+ }
63441
+ }
63442
+ for (const owner of owners.values()) await editor.set(owner.reference, owner.value);
63443
+ const contents = dictGet(other.dict, "Contents");
63444
+ if (!contents) return;
63445
+ const resolved = await source.lookup(contents), nodes = resolved?.value.kind === "array" && !resolved.stream ? resolved.value.items : [contents];
63446
+ for (const node of nodes) {
63447
+ await checkpoint();
63448
+ const found = await source.lookup(node);
63449
+ const added = found?.stream && found.reference && count ? await stream(replaceRetainedPdfNames(source.objects.decodeStream(found.reference.objectNumber, found.reference.generationNumber), mappings(), storage, { signal })) : await clone(node);
63450
+ await additions.set({ objectNumber: ++addedCount, generationNumber: 0, value: added });
63451
+ }
63452
+ if (!addedCount) return;
63453
+ const previous = dictGet(page2.dict, "Contents"), resolvedPrevious = previous && await document2.lookup(previous);
63454
+ const before = resolvedPrevious?.value.kind === "array" && !resolvedPrevious.stream ? resolvedPrevious.value.items : previous ? [previous] : [];
63455
+ const encoder = new TextEncoder();
63456
+ async function* text(value) {
63457
+ yield encoder.encode(value);
63458
+ }
63459
+ const openTarget = await stream(text("q\n")), openSource = await stream(text(retainedStampTransform(dstAttributes, srcAttributes))), close = await stream(text("\nQ\n"));
63460
+ const marker2 = cosArray([]);
63461
+ dictSet(page2.dict, "Contents", marker2);
63462
+ async function* contentNodes() {
63463
+ for (const overlay of mode === "underlay" ? [true, false] : [false, true]) {
63464
+ yield overlay ? openSource : openTarget;
63465
+ if (overlay) {
63466
+ for await (const object of additions.objects()) {
63467
+ await checkpoint();
63468
+ yield object.value;
63469
+ }
63470
+ } else for (const node of before) {
63471
+ await checkpoint();
63472
+ yield node;
63473
+ }
63474
+ yield close;
63475
+ }
63476
+ }
63477
+ async function* body() {
63478
+ yield encoder.encode("<<\n");
63479
+ for (const entry of page2.dict.entries) {
63480
+ yield* serializeCosNodeChunks(entry.key, { signal });
63481
+ yield encoder.encode(" ");
63482
+ if (entry.value === marker2) {
63483
+ yield encoder.encode("[ ");
63484
+ for await (const node of contentNodes()) {
63485
+ yield* serializeCosNodeChunks(node, { signal });
63486
+ yield encoder.encode(" ");
63487
+ }
63488
+ yield encoder.encode("]");
63489
+ } else yield* serializeCosNodeChunks(entry.value, { signal });
63490
+ yield encoder.encode("\n");
63491
+ }
63492
+ yield encoder.encode(">>");
63493
+ }
63494
+ async function* values() {
63495
+ yield page2.dict;
63496
+ yield* contentNodes();
63497
+ }
63498
+ if (page2.reference) {
63499
+ let length = 0;
63500
+ for await (const bytes of body()) length += bytes.length;
63501
+ await editor.setSerialized(page2.reference, { length, chunks: body() }, values());
63502
+ }
63503
+ } catch (error) {
63504
+ failed = true;
63505
+ throw error;
63506
+ } finally {
63507
+ const results = await Promise.allSettled([renames.close(), additions.close()]);
63508
+ if (!failed) {
63509
+ for (const result of results) if (result.status === "rejected") await Promise.reject(result.reason);
63510
+ }
63511
+ }
63512
+ }
63513
+
62395
63514
  // packages/pdf-ast/src/edit/retained-stamps.ts
62396
- import { IntegerTable as IntegerTable10, PagedStorage as PagedStorage18 } from "@poe-platform/safe-fs/storage";
63515
+ import { IntegerTable as IntegerTable11, PagedStorage as PagedStorage20 } from "@poe-platform/safe-fs/storage";
62397
63516
  async function stampRetainedPages(document2, store, storage, getPage, stamps, signal) {
62398
63517
  const editor = await RetainedContentEditor.open(store, storage, signal);
62399
63518
  let counter = 1, failed = false, work = 0;
@@ -62404,7 +63523,7 @@ async function stampRetainedPages(document2, store, storage, getPage, stamps, si
62404
63523
  try {
62405
63524
  for await (const stamp of stamps) {
62406
63525
  const source = await editRetainedDocument(stamp.source, storage, { signal });
62407
- const backing = new PagedStorage18({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), memo = new IntegerTable10(backing);
63526
+ const backing = new PagedStorage20({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), memo = new IntegerTable11(backing);
62408
63527
  let stampFailed = false;
62409
63528
  async function clone(node, depth = 0) {
62410
63529
  await checkpoint();
@@ -62414,7 +63533,12 @@ async function stampRetainedPages(document2, store, storage, getPage, stamps, si
62414
63533
  if (found !== void 0) return cosRef(Number(found));
62415
63534
  const identity = await source.document.crossReference.index.get(node.objectNumber, signal);
62416
63535
  const object = identity ? await source.document.objects.get(node.objectNumber, identity.generationNumber ?? 0) : void 0;
62417
- if (!object) return { kind: "null" };
63536
+ if (!object) {
63537
+ if (!stamp.preserveStreams) return { kind: "null" };
63538
+ const reference2 = await store.allocate(cosDict({}));
63539
+ await memo.set(BigInt(node.objectNumber), BigInt(reference2.objectNumber));
63540
+ return reference2;
63541
+ }
62418
63542
  const reference = await store.allocate({ kind: "null" });
62419
63543
  await memo.set(BigInt(node.objectNumber), BigInt(reference.objectNumber));
62420
63544
  const value = await clone(object.value, depth + 1);
@@ -62433,6 +63557,11 @@ async function stampRetainedPages(document2, store, storage, getPage, stamps, si
62433
63557
  if (node.kind === "dict") {
62434
63558
  const entries = [];
62435
63559
  for (const entry of node.entries) if (entry.key.decoded !== "Parent") entries.push({ key: { ...entry.key }, value: await clone(entry.value, depth + 1) });
63560
+ if (stamp.preserveStreams) {
63561
+ const dict = cosDict({});
63562
+ for (const entry of entries) dictSet(dict, entry.key.decoded, entry.value);
63563
+ return dict;
63564
+ }
62436
63565
  return { kind: "dict", entries };
62437
63566
  }
62438
63567
  return node;
@@ -62441,6 +63570,10 @@ async function stampRetainedPages(document2, store, storage, getPage, stamps, si
62441
63570
  for await (const pair of stamp.pages) {
62442
63571
  await checkpoint();
62443
63572
  const page2 = await getPage(pair.targetIndex), other = await source.getPage(pair.sourceIndex);
63573
+ if (stamp.preserveStreams) {
63574
+ await preserveRetainedStamp(document2, source.document, page2, other, store, editor, storage, clone, stamp.mode, signal);
63575
+ continue;
63576
+ }
62444
63577
  const target = await PdfFileSource.fromStream(storage.fs, storage.directory, page2.streamContents(), { signal });
62445
63578
  let content, pageFailed = false;
62446
63579
  try {
@@ -62494,43 +63627,7 @@ async function stampRetainedPages(document2, store, storage, getPage, stamps, si
62494
63627
  }
62495
63628
  }
62496
63629
  for (const owner of owners.values()) await editor.set(owner.reference, owner.value);
62497
- const dstSize = { width: Math.abs(dstAttributes.mediaBox[2] - dstAttributes.mediaBox[0]), height: Math.abs(dstAttributes.mediaBox[3] - dstAttributes.mediaBox[1]) };
62498
- const srcSize = { width: Math.abs(srcAttributes.mediaBox[2] - srcAttributes.mediaBox[0]), height: Math.abs(srcAttributes.mediaBox[3] - srcAttributes.mediaBox[1]) };
62499
- const rotDiff = ((dstAttributes.rotation - srcAttributes.rotation) % 360 + 360) % 360;
62500
- let stampOpenStr = "q\n";
62501
- if (srcSize.width > 0 && srcSize.height > 0) {
62502
- const fmt6 = (n) => Number(n.toFixed(6));
62503
- const fmt4 = (n) => Number(n.toFixed(4));
62504
- if (rotDiff === 90) {
62505
- const s = Math.min(dstSize.height / srcSize.width, dstSize.width / srcSize.height);
62506
- const ox = (dstSize.height - srcSize.width * s) / 2;
62507
- const oy = (dstSize.width - srcSize.height * s) / 2;
62508
- stampOpenStr = `q
62509
- 0 ${fmt6(s)} ${fmt6(-s)} 0 ${fmt4(dstSize.width - oy)} ${fmt4(ox)} cm
62510
- `;
62511
- } else if (rotDiff === 180) {
62512
- const s = Math.min(dstSize.width / srcSize.width, dstSize.height / srcSize.height);
62513
- const ox = (dstSize.width - srcSize.width * s) / 2;
62514
- const oy = (dstSize.height - srcSize.height * s) / 2;
62515
- stampOpenStr = `q
62516
- ${fmt6(-s)} 0 0 ${fmt6(-s)} ${fmt4(dstSize.width - ox)} ${fmt4(dstSize.height - oy)} cm
62517
- `;
62518
- } else if (rotDiff === 270) {
62519
- const s = Math.min(dstSize.height / srcSize.width, dstSize.width / srcSize.height);
62520
- const ox = (dstSize.height - srcSize.width * s) / 2;
62521
- const oy = (dstSize.width - srcSize.height * s) / 2;
62522
- stampOpenStr = `q
62523
- 0 ${fmt6(-s)} ${fmt6(s)} 0 ${fmt4(oy)} ${fmt4(dstSize.height - ox)} cm
62524
- `;
62525
- } else if (Math.abs(srcSize.width - dstSize.width) > 0.5 || Math.abs(srcSize.height - dstSize.height) > 0.5) {
62526
- const s = Math.min(dstSize.width / srcSize.width, dstSize.height / srcSize.height);
62527
- const tx = (dstSize.width - srcSize.width * s) / 2;
62528
- const ty = (dstSize.height - srcSize.height * s) / 2;
62529
- stampOpenStr = `q
62530
- ${fmt6(s)} 0 0 ${fmt6(s)} ${fmt4(tx)} ${fmt4(ty)} cm
62531
- `;
62532
- }
62533
- }
63630
+ const stampOpenStr = retainedStampTransform(dstAttributes, srcAttributes);
62534
63631
  const encoder = new TextEncoder(), stamped = content;
62535
63632
  async function* contents() {
62536
63633
  for (const isStamp of stamp.mode === "underlay" ? [true, false] : [false, true]) {
@@ -62570,14 +63667,54 @@ ${fmt6(s)} 0 0 ${fmt6(s)} ${fmt4(tx)} ${fmt4(ty)} cm
62570
63667
  });
62571
63668
  }
62572
63669
  }
63670
+ function retainedStampTransform(dstAttributes, srcAttributes) {
63671
+ const dstSize = { width: Math.abs(dstAttributes.mediaBox[2] - dstAttributes.mediaBox[0]), height: Math.abs(dstAttributes.mediaBox[3] - dstAttributes.mediaBox[1]) };
63672
+ const srcSize = { width: Math.abs(srcAttributes.mediaBox[2] - srcAttributes.mediaBox[0]), height: Math.abs(srcAttributes.mediaBox[3] - srcAttributes.mediaBox[1]) };
63673
+ const rotDiff = ((dstAttributes.rotation - srcAttributes.rotation) % 360 + 360) % 360;
63674
+ let stampOpenStr = "q\n";
63675
+ if (srcSize.width > 0 && srcSize.height > 0) {
63676
+ const fmt6 = (n) => Number(n.toFixed(6));
63677
+ const fmt4 = (n) => Number(n.toFixed(4));
63678
+ if (rotDiff === 90) {
63679
+ const s = Math.min(dstSize.height / srcSize.width, dstSize.width / srcSize.height);
63680
+ const ox = (dstSize.height - srcSize.width * s) / 2;
63681
+ const oy = (dstSize.width - srcSize.height * s) / 2;
63682
+ stampOpenStr = `q
63683
+ 0 ${fmt6(s)} ${fmt6(-s)} 0 ${fmt4(dstSize.width - oy)} ${fmt4(ox)} cm
63684
+ `;
63685
+ } else if (rotDiff === 180) {
63686
+ const s = Math.min(dstSize.width / srcSize.width, dstSize.height / srcSize.height);
63687
+ const ox = (dstSize.width - srcSize.width * s) / 2;
63688
+ const oy = (dstSize.height - srcSize.height * s) / 2;
63689
+ stampOpenStr = `q
63690
+ ${fmt6(-s)} 0 0 ${fmt6(-s)} ${fmt4(dstSize.width - ox)} ${fmt4(dstSize.height - oy)} cm
63691
+ `;
63692
+ } else if (rotDiff === 270) {
63693
+ const s = Math.min(dstSize.height / srcSize.width, dstSize.width / srcSize.height);
63694
+ const ox = (dstSize.height - srcSize.width * s) / 2;
63695
+ const oy = (dstSize.width - srcSize.height * s) / 2;
63696
+ stampOpenStr = `q
63697
+ 0 ${fmt6(-s)} ${fmt6(s)} 0 ${fmt4(oy)} ${fmt4(dstSize.height - ox)} cm
63698
+ `;
63699
+ } else if (Math.abs(srcSize.width - dstSize.width) > 0.5 || Math.abs(srcSize.height - dstSize.height) > 0.5) {
63700
+ const s = Math.min(dstSize.width / srcSize.width, dstSize.height / srcSize.height);
63701
+ const tx = (dstSize.width - srcSize.width * s) / 2;
63702
+ const ty = (dstSize.height - srcSize.height * s) / 2;
63703
+ stampOpenStr = `q
63704
+ ${fmt6(s)} 0 0 ${fmt6(s)} ${fmt4(tx)} ${fmt4(ty)} cm
63705
+ `;
63706
+ }
63707
+ }
63708
+ return stampOpenStr;
63709
+ }
62573
63710
 
62574
63711
  // packages/pdf-ast/src/edit/retained-inline-images.ts
62575
- import { PagedStorage as PagedStorage19 } from "@poe-platform/safe-fs/storage";
63712
+ import { PagedStorage as PagedStorage21 } from "@poe-platform/safe-fs/storage";
62576
63713
  async function externalizeRetainedInlineImages(document2, store, storage, options, signal) {
62577
63714
  const minimum = options.minBytes ?? 1024;
62578
63715
  if (!Number.isSafeInteger(minimum) || minimum < 0) throw new RangeError("Invalid inline-image minimum size");
62579
63716
  const editor = await RetainedContentEditor.open(store, storage, signal);
62580
- const paths = new PagedStorage19({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
63717
+ const paths = new PagedStorage21({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
62581
63718
  const keys = { BPC: "BitsPerComponent", CS: "ColorSpace", D: "Decode", DP: "DecodeParms", F: "Filter", H: "Height", IM: "ImageMask", I: "Interpolate", W: "Width" };
62582
63719
  const colors = { G: "DeviceGray", RGB: "DeviceRGB", CMYK: "DeviceCMYK", I: "Indexed" };
62583
63720
  const filters = { AHx: "ASCIIHexDecode", A85: "ASCII85Decode", LZW: "LZWDecode", Fl: "FlateDecode", RL: "RunLengthDecode", CCF: "CCITTFaxDecode", DCT: "DCTDecode" };
@@ -62669,7 +63806,7 @@ async function externalizeRetainedInlineImages(document2, store, storage, option
62669
63806
  }
62670
63807
 
62671
63808
  // packages/pdf-ast/src/edit/retained-resource-pruning.ts
62672
- import { IntegerTable as IntegerTable11, PagedStorage as PagedStorage20 } from "@poe-platform/safe-fs/storage";
63809
+ import { IntegerTable as IntegerTable12, PagedStorage as PagedStorage22 } from "@poe-platform/safe-fs/storage";
62673
63810
  async function collectNames(input, names, found, signal) {
62674
63811
  const iterator = input[Symbol.asyncIterator](), pending = [];
62675
63812
  let chunk = new Uint8Array(), at = 0, ended = false, changed = false, work = 0, failed = false;
@@ -62751,7 +63888,7 @@ async function pruneRetainedResources(document2, store, storage, signal) {
62751
63888
  return { ...found2, value: same(page2.reference) ? page2.dict : same(resources?.reference) ? resources.value : found2.value };
62752
63889
  }
62753
63890
  const names = new PdfNameIndex(storage, Infinity, signal), visitedNames = new PdfNameIndex(storage, Infinity, signal);
62754
- const backing = new PagedStorage20({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), found = new IntegerTable11(backing);
63891
+ const backing = new PagedStorage22({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), found = new IntegerTable12(backing);
62755
63892
  let failed = false;
62756
63893
  try {
62757
63894
  const referenced = async (name) => await found.get(BigInt((await names.intern(name)).index)) !== void 0;
@@ -62881,7 +64018,7 @@ async function flattenRetainedRotations(document2, store, storage, signal) {
62881
64018
  }
62882
64019
 
62883
64020
  // packages/pdf-ast/src/edit/retained-attachment-edits.ts
62884
- import { IntegerTable as IntegerTable12, PagedStorage as PagedStorage21 } from "@poe-platform/safe-fs/storage";
64021
+ import { IntegerTable as IntegerTable13, PagedStorage as PagedStorage23 } from "@poe-platform/safe-fs/storage";
62885
64022
  var PdfDuplicateAttachment = class extends PdfError {
62886
64023
  constructor(key) {
62887
64024
  super("E_CAPABILITY", `Duplicate attachment key: ${key}`);
@@ -62892,7 +64029,7 @@ var PdfDuplicateAttachment = class extends PdfError {
62892
64029
  async function editRetainedAttachments(document2, target, storage, remove, additions, signal, preserveTree = false) {
62893
64030
  const pairs = new PdfMutableObjectStore(storage, { signal });
62894
64031
  const names = new PdfNameIndex(storage, Infinity, signal), removed = new PdfNameIndex(storage, Infinity, signal);
62895
- const backing = new PagedStorage21({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), first = new IntegerTable12(backing), removals = new IntegerTable12(backing);
64032
+ const backing = new PagedStorage23({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4), first = new IntegerTable13(backing), removals = new IntegerTable13(backing);
62896
64033
  let failed = false, count = 0, work = 0;
62897
64034
  async function checkpoint() {
62898
64035
  signal.throwIfAborted();
@@ -63094,13 +64231,13 @@ async function* retainedAttachmentNameTokens(document2, storage, root, signal, r
63094
64231
  }
63095
64232
 
63096
64233
  // packages/pdf-ast/src/edit/retained-graph.ts
63097
- import { PagedStorage as PagedStorage22 } from "@poe-platform/safe-fs/storage";
64234
+ import { PagedStorage as PagedStorage24 } from "@poe-platform/safe-fs/storage";
63098
64235
  async function editRetainedDocument(source, storage, options = {}) {
63099
64236
  if (options.maxPages !== void 0 && options.maxPages !== Infinity && (!Number.isSafeInteger(options.maxPages) || options.maxPages < 0)) throw new RangeError("Invalid page limit");
63100
64237
  if (options.maxRecursionDepth !== void 0 && options.maxRecursionDepth !== Infinity && (!Number.isSafeInteger(options.maxRecursionDepth) || options.maxRecursionDepth < 1)) throw new RangeError("Invalid edit depth");
63101
64238
  const signal = options.signal ?? new AbortController().signal;
63102
64239
  const store = new PdfMutableObjectStore(storage, { ...options, signal });
63103
- const pages = new PagedStorage22({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
64240
+ const pages = new PagedStorage24({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
63104
64241
  const base = pages.allocate(0);
63105
64242
  let count = 0, document2;
63106
64243
  let closing;
@@ -63207,6 +64344,10 @@ async function editRetainedDocument(source, storage, options = {}) {
63207
64344
  }
63208
64345
  }
63209
64346
  } else if (options.removePageLabels) await removeRoot(["PageLabels"]);
64347
+ if (options.bookmarks) {
64348
+ await setRetainedBookmarks(store, storage, source.crossReference.rootRef, count, reference, options.bookmarks, signal, options.maxRecursionDepth);
64349
+ addedObjects = true;
64350
+ }
63210
64351
  if (options.generateAppearances && !options.removeAcroform) {
63211
64352
  await generateRetainedFormAppearances(document2, store, storage, signal);
63212
64353
  addedObjects = true;
@@ -63252,6 +64393,15 @@ async function editRetainedDocument(source, storage, options = {}) {
63252
64393
  await editRetainedAttachments(document2, store, storage, options.removeAttachments ?? [], options.attachments ?? [], signal);
63253
64394
  addedObjects = true;
63254
64395
  }
64396
+ if (options.appendAttachments) {
64397
+ if (options.attachmentPageIndex !== void 0 && (!Number.isSafeInteger(options.attachmentPageIndex) || options.attachmentPageIndex < 0 || options.attachmentPageIndex >= count)) throw new RangeError("Attachment page index out of bounds");
64398
+ if (addedObjects) {
64399
+ await document2.close();
64400
+ document2 = await PdfRetainedDocument.openStore(store, storage, { ...configured, ...infoRef ? { infoRef } : {} });
64401
+ }
64402
+ await appendRetainedAttachments(document2, store, storage, options.appendAttachments, { signal, ...options.attachmentPageIndex !== void 0 ? { pageIndex: options.attachmentPageIndex } : {} });
64403
+ addedObjects = true;
64404
+ }
63255
64405
  if (addedObjects || infoRef !== source.crossReference.infoRef) {
63256
64406
  await document2.close();
63257
64407
  document2 = await PdfRetainedDocument.openStore(store, storage, { ...configured, ...infoRef ? { infoRef } : {} });
@@ -63309,10 +64459,10 @@ async function* copyRetainedAttachments(document2, storage, options = {}) {
63309
64459
  }
63310
64460
 
63311
64461
  // packages/pdf-ast/src/cos/retained-object-order.ts
63312
- import { IntegerTable as IntegerTable13, PagedStorage as PagedStorage23 } from "@poe-platform/safe-fs/storage";
64462
+ import { IntegerTable as IntegerTable14, PagedStorage as PagedStorage25 } from "@poe-platform/safe-fs/storage";
63313
64463
  async function* retainedObjectOrder(document2, source, storage, signal) {
63314
- const backing = new PagedStorage23({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
63315
- const seen = new IntegerTable13(backing), streams = new IntegerTable13(backing);
64464
+ const backing = new PagedStorage25({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
64465
+ const seen = new IntegerTable14(backing), streams = new IntegerTable14(backing);
63316
64466
  let failed = false, work = 0;
63317
64467
  async function candidate(number) {
63318
64468
  signal.throwIfAborted();
@@ -63326,7 +64476,7 @@ async function* retainedObjectOrder(document2, source, storage, signal) {
63326
64476
  try {
63327
64477
  if (document2.crossReference.revisionCount) {
63328
64478
  for (const kind of ["uncompressed", "compressed"]) {
63329
- const revisions = new IntegerTable13(backing);
64479
+ const revisions = new IntegerTable14(backing);
63330
64480
  let offset = document2.crossReference.xrefOffset;
63331
64481
  while (offset !== void 0 && await revisions.get(BigInt(offset)) === void 0) {
63332
64482
  await revisions.set(BigInt(offset), 1n);
@@ -63448,14 +64598,14 @@ async function* encryptRetainedPdfChunks(source, storage, options = {}) {
63448
64598
  }
63449
64599
 
63450
64600
  // packages/pdf-ast/src/cos/qpdf-json-values.ts
63451
- import { IntegerTable as IntegerTable14, PagedStorage as PagedStorage24 } from "@poe-platform/safe-fs/storage";
64601
+ import { IntegerTable as IntegerTable15, PagedStorage as PagedStorage26 } from "@poe-platform/safe-fs/storage";
63452
64602
  var QpdfJsonValues = class _QpdfJsonValues {
63453
64603
  constructor(tree, storage, signal) {
63454
64604
  this.tree = tree;
63455
64605
  this.signal = signal;
63456
- this.scratch = new PagedStorage24({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
63457
- this.first = new IntegerTable14(this.scratch, 64);
63458
- this.next = new IntegerTable14(this.scratch, 64);
64606
+ this.scratch = new PagedStorage26({ fs: storage.fs, cwd: storage.directory, env: {}, signal }, 4);
64607
+ this.first = new IntegerTable15(this.scratch, 64);
64608
+ this.next = new IntegerTable15(this.scratch, 64);
63459
64609
  }
63460
64610
  tree;
63461
64611
  signal;
@@ -63553,7 +64703,7 @@ var QpdfJsonValues = class _QpdfJsonValues {
63553
64703
  await this.cooperate();
63554
64704
  const header2 = await this.tree.describe(position);
63555
64705
  if (header2.kind === "object") {
63556
- const hashes = new IntegerTable14(this.scratch, 64);
64706
+ const hashes = new IntegerTable15(this.scratch, 64);
63557
64707
  let head = 0, tail = 0;
63558
64708
  for await (const { key } of order.entries(position)) {
63559
64709
  let hash2 = 0;
@@ -63846,19 +64996,19 @@ var QpdfJsonValues = class _QpdfJsonValues {
63846
64996
  };
63847
64997
 
63848
64998
  // packages/pdf-ast/src/cos/qpdf-json-document.ts
63849
- import { IntegerTable as IntegerTable15, PagedStorage as PagedStorage25 } from "@poe-platform/safe-fs/storage";
64999
+ import { IntegerTable as IntegerTable16, PagedStorage as PagedStorage27 } from "@poe-platform/safe-fs/storage";
63850
65000
  var QpdfJsonDocument = class _QpdfJsonDocument {
63851
65001
  constructor(storage, options = {}) {
63852
65002
  this.storage = storage;
63853
65003
  this.signal = options.signal ? AbortSignal.any([options.signal, this.controller.signal]) : this.controller.signal;
63854
65004
  this.store = new PdfMutableObjectStore(storage, { signal: this.signal });
63855
- this.backing = new PagedStorage25(
65005
+ this.backing = new PagedStorage27(
63856
65006
  { fs: storage.fs, cwd: storage.directory, env: {}, signal: this.signal },
63857
65007
  4
63858
65008
  );
63859
- this.positions = new IntegerTable15(this.backing, 64);
63860
- this.order = new IntegerTable15(this.backing, 64);
63861
- this.catalogs = new IntegerTable15(this.backing, 64);
65009
+ this.positions = new IntegerTable16(this.backing, 64);
65010
+ this.order = new IntegerTable16(this.backing, 64);
65011
+ this.catalogs = new IntegerTable16(this.backing, 64);
63862
65012
  }
63863
65013
  storage;
63864
65014
  rootRef;
@@ -63921,7 +65071,7 @@ var QpdfJsonDocument = class _QpdfJsonDocument {
63921
65071
  env: {},
63922
65072
  signal: this.signal
63923
65073
  };
63924
- const tape = new PagedStorage25(context, 4), scratch = new PagedStorage25(context, 4);
65074
+ const tape = new PagedStorage27(context, 4), scratch = new PagedStorage27(context, 4);
63925
65075
  let values, failed = false, work = 0;
63926
65076
  const cooperate = async (units = 1) => {
63927
65077
  this.signal.throwIfAborted();
@@ -64338,6 +65488,8 @@ export {
64338
65488
  rc4Transform,
64339
65489
  readCMapCharacters,
64340
65490
  readCosXrefRevision,
65491
+ readPdfDictionaryEntries,
65492
+ readPdfDictionaryValue,
64341
65493
  readStoredItems,
64342
65494
  redactPageContentAst,
64343
65495
  renderDisplayListToBitmap,