kordoc 4.18.2 → 4.18.4

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 (152) hide show
  1. package/dist/{-I3CP33G4.js → -DDAVBMHD.js} +11 -11
  2. package/dist/{chunk-O2DI4GHD.js → chunk-274ZPMHK.js} +2 -2
  3. package/dist/{chunk-QGFZU3JE.cjs → chunk-3WLZOJIE.cjs} +10 -8
  4. package/dist/chunk-3WLZOJIE.cjs.map +1 -0
  5. package/dist/{chunk-UZGZRGYM.cjs → chunk-3XSP7V5P.cjs} +10 -5
  6. package/dist/chunk-3XSP7V5P.cjs.map +1 -0
  7. package/dist/{chunk-GM7XIZF2.js → chunk-4IBY5LTJ.js} +2 -2
  8. package/dist/chunk-6H25SXDI.js +11 -0
  9. package/dist/chunk-6H25SXDI.js.map +1 -0
  10. package/dist/{chunk-N5DQFA7L.js → chunk-7GR2GCJF.js} +10 -5
  11. package/dist/chunk-7GR2GCJF.js.map +1 -0
  12. package/dist/{chunk-YNLW6EGU.cjs → chunk-AVIZ55NQ.cjs} +3 -3
  13. package/dist/chunk-AVIZ55NQ.cjs.map +1 -0
  14. package/dist/chunk-DC6CTQTK.js +9 -0
  15. package/dist/chunk-DC6CTQTK.js.map +1 -0
  16. package/dist/{chunk-L5RLJPI3.js → chunk-DUV7Y6IQ.js} +3 -3
  17. package/dist/{chunk-KDMAYOWH.cjs → chunk-E2644XCO.cjs} +698 -189
  18. package/dist/chunk-E2644XCO.cjs.map +1 -0
  19. package/dist/{chunk-LSOD2A6N.js → chunk-ELOPDQES.js} +2 -2
  20. package/dist/{chunk-M4P7YS2N.js → chunk-F2GDLA45.js} +81 -61
  21. package/dist/chunk-F2GDLA45.js.map +1 -0
  22. package/dist/{chunk-OBILAVWC.js → chunk-F5YVCJVF.js} +10 -5
  23. package/dist/chunk-F5YVCJVF.js.map +1 -0
  24. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  25. package/dist/{chunk-4B2EXELH.js → chunk-HRJJDNRD.js} +2 -2
  26. package/dist/{chunk-CKUIFTXJ.js → chunk-IAXGGQGD.js} +2 -2
  27. package/dist/{chunk-BL7KRE6X.js → chunk-IBQCK4F3.js} +7 -3
  28. package/dist/chunk-IBQCK4F3.js.map +1 -0
  29. package/dist/chunk-J55UQC5H.cjs.map +1 -1
  30. package/dist/{chunk-OGAYGUJF.js → chunk-KUUSP6OS.js} +581 -72
  31. package/dist/chunk-KUUSP6OS.js.map +1 -0
  32. package/dist/{chunk-LACO375L.js → chunk-LGF2IO66.js} +4 -3
  33. package/dist/chunk-LGF2IO66.js.map +1 -0
  34. package/dist/{chunk-L64QRUMK.js → chunk-MXA6YW2W.js} +582 -73
  35. package/dist/chunk-MXA6YW2W.js.map +1 -0
  36. package/dist/{chunk-OI5ZSSIC.cjs → chunk-OIUSF2VA.cjs} +16 -12
  37. package/dist/chunk-OIUSF2VA.cjs.map +1 -0
  38. package/dist/{chunk-6OKBTY72.js → chunk-QVCHFCT2.js} +2 -2
  39. package/dist/{chunk-C2CVOC5K.js → chunk-RCI7LY4N.js} +8 -4
  40. package/dist/chunk-RCI7LY4N.js.map +1 -0
  41. package/dist/{chunk-W2YYBPW5.cjs → chunk-SVNBZEL6.cjs} +3 -3
  42. package/dist/chunk-SVNBZEL6.cjs.map +1 -0
  43. package/dist/{chunk-VSY5PAJ5.js → chunk-T2BJPT6D.js} +3 -3
  44. package/dist/{chunk-VSY5PAJ5.js.map → chunk-T2BJPT6D.js.map} +1 -1
  45. package/dist/chunk-TK3FDAEE.cjs +9 -0
  46. package/dist/chunk-TK3FDAEE.cjs.map +1 -0
  47. package/dist/{chunk-F5HING4Y.js → chunk-TMJVD6FW.js} +5 -4
  48. package/dist/chunk-TMJVD6FW.js.map +1 -0
  49. package/dist/{chunk-T4MXCSBP.js → chunk-V5X4LLVM.js} +71 -47
  50. package/dist/chunk-V5X4LLVM.js.map +1 -0
  51. package/dist/{chunk-IA3UKDHA.js → chunk-VTVK2JMI.js} +3 -2
  52. package/dist/{chunk-IA3UKDHA.js.map → chunk-VTVK2JMI.js.map} +1 -1
  53. package/dist/{chunk-B2E6C2LH.js → chunk-XG4SYOZL.js} +6 -4
  54. package/dist/chunk-XG4SYOZL.js.map +1 -0
  55. package/dist/{chunk-QP7IXF7R.js → chunk-YCY2R4FM.js} +2 -2
  56. package/dist/{chunk-NZM2SSI4.js → chunk-Z2PPDQK2.js} +2 -2
  57. package/dist/chunks-5QTTAT5T.js +10 -0
  58. package/dist/cli.js +179 -119
  59. package/dist/cli.js.map +1 -1
  60. package/dist/{formula-E3N7KDDG.js → formula-7ZOZ5QJ6.js} +8 -4
  61. package/dist/{formula-E3N7KDDG.js.map → formula-7ZOZ5QJ6.js.map} +1 -1
  62. package/dist/{formula-AQZODKZF.js → formula-HQFZEXFF.js} +7 -3
  63. package/dist/{formula-AQZODKZF.js.map → formula-HQFZEXFF.js.map} +1 -1
  64. package/dist/{formula-VY4ITOMN.cjs → formula-YYJQBKEN.cjs} +13 -9
  65. package/dist/formula-YYJQBKEN.cjs.map +1 -0
  66. package/dist/{image-ocr-IMYXOHHV.js → image-ocr-4BGX2EJJ.js} +7 -6
  67. package/dist/{image-ocr-IMYXOHHV.js.map → image-ocr-4BGX2EJJ.js.map} +1 -1
  68. package/dist/{image-ocr-6LYEBMVR.cjs → image-ocr-CC26Q5KG.cjs} +16 -15
  69. package/dist/image-ocr-CC26Q5KG.cjs.map +1 -0
  70. package/dist/{image-ocr-LN3GSQPW.js → image-ocr-RK3HJVCI.js} +10 -9
  71. package/dist/{image-ocr-LN3GSQPW.js.map → image-ocr-RK3HJVCI.js.map} +1 -1
  72. package/dist/index.cjs +860 -817
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.js +141 -98
  75. package/dist/index.js.map +1 -1
  76. package/dist/mcp.js +26 -26
  77. package/dist/mcp.js.map +1 -1
  78. package/dist/{model-bundle-IHKNDLOT.js → model-bundle-VHRXG63R.js} +5 -5
  79. package/dist/{models-YXITRAMR.js → models-G3WA24SY.js} +5 -5
  80. package/dist/page-range-QHHFTL7X.cjs.map +1 -1
  81. package/dist/{parser-7KECZTTP.cjs → parser-BGORCLIU.cjs} +461 -243
  82. package/dist/parser-BGORCLIU.cjs.map +1 -0
  83. package/dist/{parser-M3T2EWUN.js → parser-GFDGAVLV.js} +255 -37
  84. package/dist/parser-GFDGAVLV.js.map +1 -0
  85. package/dist/{parser-KB4BYQBZ.js → parser-SOWTUOMK.js} +258 -40
  86. package/dist/parser-SOWTUOMK.js.map +1 -0
  87. package/dist/pdf-ocr-7IOOVR2I.js +20 -0
  88. package/dist/pdf-ocr-EJ2HNZN6.cjs +17 -0
  89. package/dist/pdf-ocr-EJ2HNZN6.cjs.map +1 -0
  90. package/dist/pdf-ocr-RACAZU3N.js +16 -0
  91. package/dist/{profile-io-GQWQR7YQ.js → profile-io-Q2T47RVH.js} +3 -3
  92. package/dist/{rasterize-Y6TVFQ3M.js → rasterize-OAVMUTE6.js} +3 -3
  93. package/dist/{redact-doc-TRPZ3HNW.js → redact-doc-ECFOVR4X.js} +11 -11
  94. package/dist/{render-GHT5HKBO.js → render-NSKWZVTD.js} +7 -7
  95. package/dist/seal-A4MG7MPQ.js +10 -0
  96. package/dist/{setup-AGSCEHDB.js → setup-REH2KZP2.js} +3 -3
  97. package/dist/visual-B56WQAGW.js +20 -0
  98. package/dist/{watch-ALSEW4GB.js → watch-JXDUZYBY.js} +13 -13
  99. package/dist/watch-JXDUZYBY.js.map +1 -0
  100. package/package.json +1 -1
  101. package/dist/chunk-B2E6C2LH.js.map +0 -1
  102. package/dist/chunk-BL7KRE6X.js.map +0 -1
  103. package/dist/chunk-C2CVOC5K.js.map +0 -1
  104. package/dist/chunk-F5HING4Y.js.map +0 -1
  105. package/dist/chunk-KDMAYOWH.cjs.map +0 -1
  106. package/dist/chunk-L64QRUMK.js.map +0 -1
  107. package/dist/chunk-LACO375L.js.map +0 -1
  108. package/dist/chunk-M4P7YS2N.js.map +0 -1
  109. package/dist/chunk-N5DQFA7L.js.map +0 -1
  110. package/dist/chunk-OBILAVWC.js.map +0 -1
  111. package/dist/chunk-OGAYGUJF.js.map +0 -1
  112. package/dist/chunk-OI5ZSSIC.cjs.map +0 -1
  113. package/dist/chunk-QGFZU3JE.cjs.map +0 -1
  114. package/dist/chunk-T4MXCSBP.js.map +0 -1
  115. package/dist/chunk-UZGZRGYM.cjs.map +0 -1
  116. package/dist/chunk-W2YYBPW5.cjs.map +0 -1
  117. package/dist/chunk-YNLW6EGU.cjs.map +0 -1
  118. package/dist/chunks-IFFRC5IQ.js +0 -10
  119. package/dist/formula-VY4ITOMN.cjs.map +0 -1
  120. package/dist/image-ocr-6LYEBMVR.cjs.map +0 -1
  121. package/dist/parser-7KECZTTP.cjs.map +0 -1
  122. package/dist/parser-KB4BYQBZ.js.map +0 -1
  123. package/dist/parser-M3T2EWUN.js.map +0 -1
  124. package/dist/pdf-ocr-4S2OAHUX.js +0 -15
  125. package/dist/pdf-ocr-IGYCZ7G2.cjs +0 -16
  126. package/dist/pdf-ocr-IGYCZ7G2.cjs.map +0 -1
  127. package/dist/pdf-ocr-YEBFWU2K.js +0 -19
  128. package/dist/seal-3YTXSABW.js +0 -10
  129. package/dist/visual-R3E35Q2K.js +0 -20
  130. package/dist/watch-ALSEW4GB.js.map +0 -1
  131. /package/dist/{-I3CP33G4.js.map → -DDAVBMHD.js.map} +0 -0
  132. /package/dist/{chunk-O2DI4GHD.js.map → chunk-274ZPMHK.js.map} +0 -0
  133. /package/dist/{chunk-GM7XIZF2.js.map → chunk-4IBY5LTJ.js.map} +0 -0
  134. /package/dist/{chunk-L5RLJPI3.js.map → chunk-DUV7Y6IQ.js.map} +0 -0
  135. /package/dist/{chunk-LSOD2A6N.js.map → chunk-ELOPDQES.js.map} +0 -0
  136. /package/dist/{chunk-4B2EXELH.js.map → chunk-HRJJDNRD.js.map} +0 -0
  137. /package/dist/{chunk-CKUIFTXJ.js.map → chunk-IAXGGQGD.js.map} +0 -0
  138. /package/dist/{chunk-6OKBTY72.js.map → chunk-QVCHFCT2.js.map} +0 -0
  139. /package/dist/{chunk-QP7IXF7R.js.map → chunk-YCY2R4FM.js.map} +0 -0
  140. /package/dist/{chunk-NZM2SSI4.js.map → chunk-Z2PPDQK2.js.map} +0 -0
  141. /package/dist/{chunks-IFFRC5IQ.js.map → chunks-5QTTAT5T.js.map} +0 -0
  142. /package/dist/{model-bundle-IHKNDLOT.js.map → model-bundle-VHRXG63R.js.map} +0 -0
  143. /package/dist/{models-YXITRAMR.js.map → models-G3WA24SY.js.map} +0 -0
  144. /package/dist/{pdf-ocr-4S2OAHUX.js.map → pdf-ocr-7IOOVR2I.js.map} +0 -0
  145. /package/dist/{pdf-ocr-YEBFWU2K.js.map → pdf-ocr-RACAZU3N.js.map} +0 -0
  146. /package/dist/{profile-io-GQWQR7YQ.js.map → profile-io-Q2T47RVH.js.map} +0 -0
  147. /package/dist/{rasterize-Y6TVFQ3M.js.map → rasterize-OAVMUTE6.js.map} +0 -0
  148. /package/dist/{redact-doc-TRPZ3HNW.js.map → redact-doc-ECFOVR4X.js.map} +0 -0
  149. /package/dist/{render-GHT5HKBO.js.map → render-NSKWZVTD.js.map} +0 -0
  150. /package/dist/{seal-3YTXSABW.js.map → seal-A4MG7MPQ.js.map} +0 -0
  151. /package/dist/{setup-AGSCEHDB.js.map → setup-REH2KZP2.js.map} +0 -0
  152. /package/dist/{visual-R3E35Q2K.js.map → visual-B56WQAGW.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  blocksToPages,
3
3
  inlineImagesIntoMarkdown
4
- } from "./chunk-O2DI4GHD.js";
4
+ } from "./chunk-274ZPMHK.js";
5
5
  import {
6
6
  parsePageRange
7
7
  } from "./chunk-V4BH5SRQ.js";
@@ -31,7 +31,7 @@ import {
31
31
  tidyScriptTags,
32
32
  unframeLayoutTables,
33
33
  wrapScript
34
- } from "./chunk-B2E6C2LH.js";
34
+ } from "./chunk-XG4SYOZL.js";
35
35
  import {
36
36
  KordocError,
37
37
  OPTIONAL_DEP_INSTALL_HINT,
@@ -41,6 +41,7 @@ import {
41
41
  escapeHtml,
42
42
  isPathTraversal,
43
43
  normalizeSectionHref,
44
+ partExtension,
44
45
  precheckZipSize,
45
46
  sanitizeError,
46
47
  sanitizeHref,
@@ -48,7 +49,7 @@ import {
48
49
  toArrayBuffer,
49
50
  unescapeHtml,
50
51
  unzipLimitBytes
51
- } from "./chunk-N5DQFA7L.js";
52
+ } from "./chunk-7GR2GCJF.js";
52
53
 
53
54
  // src/plain-markdown.ts
54
55
  function toPlainMarkdown(md2) {
@@ -585,7 +586,8 @@ function createSectionShared() {
585
586
  numState: /* @__PURE__ */ new Map(),
586
587
  pageText: { headers: [], footers: [] },
587
588
  track: { deleteDepth: 0, warned: false, deletedObjects: /* @__PURE__ */ new WeakSet(), deletedImageRefs: /* @__PURE__ */ new Set() },
588
- pageState: { base: 0, allUsable: true }
589
+ pageState: { base: 0, allUsable: true },
590
+ tocTexts: /* @__PURE__ */ new Set()
589
591
  };
590
592
  }
591
593
  function createXmlParser(warnings) {
@@ -937,7 +939,7 @@ function parseParaHeadings(doc, map) {
937
939
  if (map.size > 0) break;
938
940
  }
939
941
  }
940
- function detectHwpxHeadings(blocks, styleMap) {
942
+ function detectHwpxHeadings(blocks, styleMap, tocTexts) {
941
943
  if (blocks.some((b) => b.type === "heading")) return;
942
944
  let baseFontSize = 0;
943
945
  const sizeFreq = /* @__PURE__ */ new Map();
@@ -954,7 +956,7 @@ function detectHwpxHeadings(blocks, styleMap) {
954
956
  }
955
957
  }
956
958
  for (const block of blocks) {
957
- if (block.type !== "paragraph" || !block.text || TOC_ENTRY_BLOCKS.has(block)) continue;
959
+ if (block.type !== "paragraph" || !block.text || TOC_ENTRY_BLOCKS.has(block) || tocTexts?.has(block.text.trim())) continue;
958
960
  const text = block.text.trim();
959
961
  if (text.length === 0 || text.length > 200 || /^\d+$/.test(text)) continue;
960
962
  let level = 0;
@@ -2121,13 +2123,13 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
2121
2123
  }
2122
2124
  if (tableCtx) tableStack.push(tableCtx);
2123
2125
  const newTable = { rows: [], currentRow: [], cell: null, sourceId: el.getAttribute("id") ?? void 0 };
2124
- walkSection(el, blocks, newTable, tableStack, ctx, depth + 1);
2126
+ inIndependentDeletionStory(ctx.shared.track, () => walkSection(el, blocks, newTable, tableStack, ctx, depth + 1));
2125
2127
  tableCtx = completeTable(newTable, tableStack, blocks, ctx);
2126
2128
  break;
2127
2129
  }
2128
2130
  // 표/도표 캡션 — IRTable.caption으로 보존 (v3.0, 기존 무음 드롭 수정)
2129
2131
  case "caption": {
2130
- const cap = collectSubListContent(el, ctx);
2132
+ const cap = inIndependentDeletionStory(ctx.shared.track, () => collectSubListContent(el, ctx));
2131
2133
  if (cap.text) {
2132
2134
  if (tableCtx) {
2133
2135
  tableCtx.caption = (tableCtx.caption ? tableCtx.caption + "\n" : "") + cap.text;
@@ -2187,6 +2189,9 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
2187
2189
  if (text) {
2188
2190
  if (ph?.prefix) text = ph.prefix + " " + text;
2189
2191
  headingLevel = tocEntry ? void 0 : ph?.headingLevel;
2192
+ if (tocEntry) {
2193
+ for (const line of text.split("\n")) if (line.trim()) ctx.shared.tocTexts.add(line.trim());
2194
+ }
2190
2195
  }
2191
2196
  if (segments) {
2192
2197
  const cell2 = tableCtx?.cell ?? null;
@@ -2272,6 +2277,15 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
2272
2277
  if (spanMode !== "foreign" && el.getAttribute("paraPrIDRef") === KORDOC_PARA_QUOTE) block.quote = true;
2273
2278
  }
2274
2279
  if (!headingLevel && !block.spans && placeholderSpans) block.spans = withPrefixSpan(placeholderSpans, ph?.prefix);
2280
+ if (headingLevel && placeholderSpans) {
2281
+ const shown = withPrefixSpan(placeholderSpans.filter((s) => !s.placeholder), ph?.prefix).map((s) => s.text).join("").trim();
2282
+ if (shown) block.text = shown;
2283
+ else {
2284
+ block.type = "paragraph";
2285
+ delete block.level;
2286
+ block.spans = withPrefixSpan(placeholderSpans, ph?.prefix);
2287
+ }
2288
+ }
2275
2289
  blocks.push(block);
2276
2290
  } else {
2277
2291
  blocks.push({ type: "paragraph", text, pageNumber: ctx.page });
@@ -2513,10 +2527,10 @@ function walkParagraphChildren(node, blocks, tableCtx, tableStack, ctx, depth =
2513
2527
  }
2514
2528
  if (tableCtx) tableStack.push(tableCtx);
2515
2529
  const newTable = { rows: [], currentRow: [], cell: null, inline: isInlineTbl(el), sourceId: el.getAttribute("id") ?? void 0 };
2516
- walkSection(el, blocks, newTable, tableStack, ctx, d + 1);
2530
+ inIndependentDeletionStory(ctx.shared.track, () => walkSection(el, blocks, newTable, tableStack, ctx, d + 1));
2517
2531
  tableCtx = completeTable(newTable, tableStack, blocks, ctx);
2518
2532
  } else if (localTag === "caption" && !inShape) {
2519
- const cap = collectSubListContent(el, ctx);
2533
+ const cap = inIndependentDeletionStory(ctx.shared.track, () => collectSubListContent(el, ctx));
2520
2534
  if (cap.text) {
2521
2535
  if (tableCtx?.cell) mergeBlocksIntoCell(tableCtx.cell, [{ type: "paragraph", text: cap.text, pageNumber: ctx.page }]);
2522
2536
  else if (tableCtx) {
@@ -2712,7 +2726,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
2712
2726
  // 아니므로 방출하지 않는다
2713
2727
  case "header":
2714
2728
  case "footer": {
2715
- if (!ctx) break;
2729
+ if (!ctx || isInDeletedRange(ctx)) break;
2716
2730
  const t = collectSubListText(k, ctx);
2717
2731
  if (t && hasPageAutoNum(k) && !/\p{L}/u.test(t)) break;
2718
2732
  if (t) {
@@ -2834,9 +2848,10 @@ function extractParagraphInfo(para2, styleMap, ctx) {
2834
2848
  if (isInlineTbl(child)) text += "";
2835
2849
  break;
2836
2850
  // 양식 선택 상자·라디오 단추 — 한컴이 그리는 상자 기호와 캡션 글 (종전엔 통째로 빠졌다: form-002 "원천기술형"·서울 결재 "부분공개")
2851
+ // 지운 구간의 양식 단추·수식은 글처럼 내지 않는다 (최종본)
2837
2852
  case "checkBtn":
2838
2853
  case "radioBtn":
2839
- text += formButtonText(child, tag === "radioBtn");
2854
+ if (!isInDeletedRange(ctx)) text += formButtonText(child, tag === "radioBtn");
2840
2855
  break;
2841
2856
  // 하이퍼링크
2842
2857
  case "hyperlink": {
@@ -2906,6 +2921,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
2906
2921
  // 스크립트가 담겨 있음. hml-equation-parser 로 LaTeX 변환 후 `$...$`
2907
2922
  // 로 래핑. 실패/빈 스크립트면 무시 (대체 텍스트 누출 방지).
2908
2923
  case "equation": {
2924
+ if (isInDeletedRange(ctx)) break;
2909
2925
  const script = findChildByLocalName(child, "script");
2910
2926
  const raw = script ? extractTextFromNode(script) : "";
2911
2927
  if (raw.trim()) {
@@ -3453,7 +3469,7 @@ function resolveImageBlocks(binDataMap, blocks, warnings, sweepUnreferenced) {
3453
3469
  resolveImageSentinels(blocks, renamed);
3454
3470
  return images;
3455
3471
  }
3456
- function collectHwp5BinData(fileIndex) {
3472
+ function collectHwp5BinData(fileIndex, readStream) {
3457
3473
  const binDataMap = /* @__PURE__ */ new Map();
3458
3474
  if (fileIndex) {
3459
3475
  for (const entry of fileIndex) {
@@ -3461,35 +3477,37 @@ function collectHwp5BinData(fileIndex) {
3461
3477
  const match = entry.name.match(BIN_ENTRY_RE);
3462
3478
  if (!match) continue;
3463
3479
  const idx = parseInt(match[1], 16);
3464
- const data = normalizeBinPayload(Buffer.from(entry.content));
3480
+ const raw = readStream ? readStream(`/BinData/${entry.name}`) : Buffer.from(entry.content);
3481
+ if (!raw) continue;
3482
+ const data = normalizeBinPayload(raw);
3465
3483
  binDataMap.set(idx, { data, name: entry.name });
3466
3484
  }
3467
3485
  }
3468
3486
  return binDataMap;
3469
3487
  }
3470
- function collectHwp5BinDataLenient(lcfb) {
3488
+ function collectHwp5BinDataLenient(lcfb, readStream = lcfb.findStream) {
3471
3489
  const binDataMap = /* @__PURE__ */ new Map();
3472
3490
  const binRe = /^BIN([0-9A-Fa-f]{4,8})(?:\.|$)/;
3473
3491
  for (const e of lcfb.entries()) {
3474
3492
  const match = e.name.match(binRe);
3475
3493
  if (!match) continue;
3476
3494
  const idx = parseInt(match[1], 16);
3477
- const raw = lcfb.findStream(e.name);
3495
+ const raw = readStream(e.name);
3478
3496
  if (!raw) continue;
3479
3497
  binDataMap.set(idx, { data: normalizeBinPayload(raw), name: e.name });
3480
3498
  }
3481
3499
  return binDataMap;
3482
3500
  }
3483
- function extractHwp5Images(fileIndex, blocks, warnings, sweepUnreferenced) {
3484
- const binDataMap = collectHwp5BinData(fileIndex);
3501
+ function extractHwp5Images(fileIndex, blocks, warnings, sweepUnreferenced, readStream) {
3502
+ const binDataMap = collectHwp5BinData(fileIndex, readStream);
3485
3503
  if (binDataMap.size === 0) {
3486
3504
  resolveImageSentinels(blocks, /* @__PURE__ */ new Map());
3487
3505
  return [];
3488
3506
  }
3489
3507
  return resolveImageBlocks(binDataMap, blocks, warnings, sweepUnreferenced);
3490
3508
  }
3491
- function extractHwp5ImagesLenient(lcfb, blocks, warnings, sweepUnreferenced) {
3492
- const binDataMap = collectHwp5BinDataLenient(lcfb);
3509
+ function extractHwp5ImagesLenient(lcfb, blocks, warnings, sweepUnreferenced, readStream) {
3510
+ const binDataMap = collectHwp5BinDataLenient(lcfb, readStream);
3493
3511
  if (binDataMap.size === 0) {
3494
3512
  resolveImageSentinels(blocks, /* @__PURE__ */ new Map());
3495
3513
  return [];
@@ -3746,8 +3764,11 @@ async function resolveSectionPaths(zip) {
3746
3764
  function parseSectionPathsFromManifest(xml) {
3747
3765
  const parser = createXmlParser();
3748
3766
  const doc = parser.parseFromString(stripDtd(xml), "text/xml");
3749
- const items = doc.getElementsByTagName("opf:item");
3750
- const spine = doc.getElementsByTagName("opf:itemref");
3767
+ const opf = "http://www.idpf.org/2007/opf/";
3768
+ const namespacedItems = doc.getElementsByTagNameNS(opf, "item");
3769
+ const namespacedSpine = doc.getElementsByTagNameNS(opf, "itemref");
3770
+ const items = namespacedItems.length ? namespacedItems : doc.getElementsByTagName("opf:item");
3771
+ const spine = namespacedSpine.length ? namespacedSpine : doc.getElementsByTagName("opf:itemref");
3751
3772
  const idToHref = /* @__PURE__ */ new Map();
3752
3773
  for (let i = 0; i < items.length; i++) {
3753
3774
  const item = items[i];
@@ -3954,7 +3975,7 @@ async function parseHwpxDocument(buffer, options) {
3954
3975
  applyPageText(blocks, shared);
3955
3976
  const images = await extractImagesFromZip(zip, blocks, decompressed, warnings, !options?.pages, shared.track.deletedImageRefs);
3956
3977
  const shown = options?.layoutTables === "keep" ? blocks : unframeLayoutTables(blocks, !!options?.keepTrailingEmptyCols);
3957
- detectHwpxHeadings(shown, styleMap);
3978
+ detectHwpxHeadings(shown, styleMap, shared.tocTexts);
3958
3979
  const outline = shown.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
3959
3980
  const markdown = blocksToMarkdown(shown);
3960
3981
  return { markdown, blocks: shown, metadata, outline: outline.length > 0 ? outline : void 0, warnings: warnings.length > 0 ? warnings : void 0, images: images.length > 0 ? images : void 0 };
@@ -5361,6 +5382,7 @@ function createHwp5DocState() {
5361
5382
  outlineNumberingId: 0,
5362
5383
  autoCounters: /* @__PURE__ */ new Map(),
5363
5384
  headerTexts: /* @__PURE__ */ new Set(),
5385
+ tocTexts: /* @__PURE__ */ new Set(),
5364
5386
  headerBlocks: [],
5365
5387
  footerBlocks: []
5366
5388
  };
@@ -5506,6 +5528,12 @@ function parseParagraph(records, start, end, ctx) {
5506
5528
  if (bullet && bullet.char !== "\uFFFF") headMarker = bullet.char;
5507
5529
  }
5508
5530
  }
5531
+ if (toc.tocEntry) {
5532
+ for (const line of text.split("\n")) if (line.trim()) {
5533
+ ctx.doc.tocTexts.add(line.trim());
5534
+ if (headMarker) ctx.doc.tocTexts.add(`${headMarker} ${line.trim()}`);
5535
+ }
5536
+ }
5509
5537
  return emitParagraphBlocks({
5510
5538
  text,
5511
5539
  headMarker,
@@ -5970,7 +5998,7 @@ function readHwp5DocInfoRecords(c) {
5970
5998
  }
5971
5999
  }
5972
6000
  function readHwp5SectionStreams(c) {
5973
- return c.distribution ? c.cfb ? findViewTextSections(c.cfb, c.compressed) : findViewTextSectionsLenient(c.lenientCfb, c.compressed) : c.encrypted ? findSectionsVia(c.findStream) : c.cfb ? findSections(c.cfb) : findSectionsLenient(c.lenientCfb, c.compressed);
6001
+ return c.distribution ? c.cfb ? findViewTextSections(c.cfb, c.compressed) : findViewTextSectionsLenient(c.lenientCfb, c.compressed) : c.encrypted ? findSectionsVia(c.findStream) : c.cfb ? findSections(c.cfb) : findSectionsLenient(c.lenientCfb);
5974
6002
  }
5975
6003
  function readHwp5SectionRecords(c, sections, warnings) {
5976
6004
  const out = [];
@@ -5990,7 +6018,8 @@ function readHwp5SectionRecords(c, sections, warnings) {
5990
6018
  return out;
5991
6019
  }
5992
6020
  function readHwp5BinData(c) {
5993
- return c.cfb ? collectHwp5BinData(c.cfb.FileIndex) : collectHwp5BinDataLenient(c.lenientCfb);
6021
+ const readStream = c.encrypted ? c.findStream : void 0;
6022
+ return c.cfb ? collectHwp5BinData(c.cfb.FileIndex, readStream) : collectHwp5BinDataLenient(c.lenientCfb, readStream);
5994
6023
  }
5995
6024
  function parseHwp5Document(buffer, options) {
5996
6025
  const c = openHwp5Container(buffer, options);
@@ -6055,7 +6084,7 @@ function parseHwp5Document(buffer, options) {
6055
6084
  bodyBlocks = bodyBlocks.filter((b) => b.pageNumber != null && pageFilter.has(b.pageNumber));
6056
6085
  }
6057
6086
  const blocks = [...doc.headerBlocks, ...bodyBlocks, ...doc.footerBlocks];
6058
- const images = cfb ? extractHwp5Images(cfb.FileIndex, blocks, warnings, !pageFilter) : extractHwp5ImagesLenient(lenientCfb, blocks, warnings, !pageFilter);
6087
+ const images = cfb ? extractHwp5Images(cfb.FileIndex, blocks, warnings, !pageFilter, encrypted ? findStream : void 0) : extractHwp5ImagesLenient(lenientCfb, blocks, warnings, !pageFilter, encrypted ? findStream : void 0);
6059
6088
  let flatBlocks = flattenLayoutTables(blocks);
6060
6089
  if (options?.layoutTables !== "keep") flatBlocks = unframeLayoutTables(flatBlocks, !!options?.keepTrailingEmptyCols);
6061
6090
  if (options?.dedupeRunningHeaders) {
@@ -6065,7 +6094,7 @@ function parseHwp5Document(buffer, options) {
6065
6094
  flatBlocks = deduped;
6066
6095
  }
6067
6096
  if (docInfo) {
6068
- detectHwp5Headings(flatBlocks, docInfo);
6097
+ detectHwp5Headings(flatBlocks, docInfo, doc.tocTexts);
6069
6098
  }
6070
6099
  const outline = flatBlocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
6071
6100
  let markdown = blocksToMarkdown(flatBlocks);
@@ -6098,7 +6127,7 @@ function parseDocInfoFromStream(raw, compressed) {
6098
6127
  return null;
6099
6128
  }
6100
6129
  }
6101
- function detectHwp5Headings(blocks, docInfo) {
6130
+ function detectHwp5Headings(blocks, docInfo, tocTexts) {
6102
6131
  let baseFontSize = 0;
6103
6132
  const sizeFreq = /* @__PURE__ */ new Map();
6104
6133
  for (const b of blocks) {
@@ -6128,7 +6157,7 @@ function detectHwp5Headings(blocks, docInfo) {
6128
6157
  if (baseFontSize <= 0) return;
6129
6158
  for (const block of blocks) {
6130
6159
  if (block.type === "heading") continue;
6131
- if (block.type !== "paragraph" || !block.text || TOC_ENTRY_BLOCKS.has(block)) continue;
6160
+ if (block.type !== "paragraph" || !block.text || TOC_ENTRY_BLOCKS.has(block) || tocTexts?.has(block.text.trim())) continue;
6132
6161
  const text = block.text.trim();
6133
6162
  if (text.length === 0 || text.length > 200) continue;
6134
6163
  if (/^\d+$/.test(text)) continue;
@@ -6262,16 +6291,15 @@ function findSections(cfb) {
6262
6291
  }
6263
6292
  return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
6264
6293
  }
6265
- function findSectionsLenient(lcfb, compressed) {
6294
+ function findSectionsLenient(lcfb) {
6266
6295
  const sections = [];
6267
- let totalDecompressed = 0;
6296
+ let totalBytes = 0;
6268
6297
  for (let i = 0; i < MAX_SECTIONS; i++) {
6269
6298
  const raw = lcfb.findStream(`/BodyText/Section${i}`) ?? lcfb.findStream(`Section${i}`);
6270
6299
  if (!raw) break;
6271
- const content = compressed ? decompressStream(raw) : raw;
6272
- totalDecompressed += content.length;
6273
- if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
6274
- sections.push({ idx: i, content });
6300
+ totalBytes += raw.length;
6301
+ if (totalBytes > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
6302
+ sections.push({ idx: i, content: raw });
6275
6303
  }
6276
6304
  if (sections.length === 0) {
6277
6305
  for (const e of lcfb.entries()) {
@@ -6280,10 +6308,9 @@ function findSectionsLenient(lcfb, compressed) {
6280
6308
  const idx = parseInt(e.name.replace("Section", ""), 10) || 0;
6281
6309
  const raw = lcfb.findStream(e.name);
6282
6310
  if (raw) {
6283
- const content = compressed ? decompressStream(raw) : raw;
6284
- totalDecompressed += content.length;
6285
- if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
6286
- sections.push({ idx, content });
6311
+ totalBytes += raw.length;
6312
+ if (totalBytes > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
6313
+ sections.push({ idx, content: raw });
6287
6314
  }
6288
6315
  }
6289
6316
  }
@@ -19387,7 +19414,7 @@ function collectRichText(root) {
19387
19414
  const el = children[i];
19388
19415
  const local = el.localName || el.tagName?.replace(/^[^:]+:/, "") || "";
19389
19416
  if (local === "rPh") continue;
19390
- if (local === "t") out += escapeLiteralTags(el.textContent ?? "");
19417
+ if (local === "t") out += escapeLiteralTags(escapeLiteralDollar(el.textContent ?? ""));
19391
19418
  else walk(el);
19392
19419
  }
19393
19420
  };
@@ -20011,14 +20038,14 @@ function extractSheetCells(records, bofIndex, sst, convertNum) {
20011
20038
  const h = readCellHeader(rec.data);
20012
20039
  if (h && rec.data.length >= 10) {
20013
20040
  const isst = rec.data.readUInt32LE(6);
20014
- cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(sst[isst] ?? "") });
20041
+ cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(escapeLiteralDollar(sst[isst] ?? "")) });
20015
20042
  }
20016
20043
  break;
20017
20044
  }
20018
20045
  case OP_LABEL: {
20019
20046
  const h = readCellHeader(rec.data);
20020
20047
  if (h) {
20021
- cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(decodeLabelString(rec.data)) });
20048
+ cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(escapeLiteralDollar(decodeLabelString(rec.data))) });
20022
20049
  }
20023
20050
  break;
20024
20051
  }
@@ -20034,7 +20061,7 @@ function extractSheetCells(records, bofIndex, sst, convertNum) {
20034
20061
  cells.push({
20035
20062
  row: h.row,
20036
20063
  col: h.col,
20037
- value: escapeLiteralTags(decodeFormulaStringRecord(next.data))
20064
+ value: escapeLiteralTags(escapeLiteralDollar(decodeFormulaStringRecord(next.data)))
20038
20065
  });
20039
20066
  i = j;
20040
20067
  } else {
@@ -20746,6 +20773,7 @@ function isDisplayMath(el) {
20746
20773
  // src/docx/parser.ts
20747
20774
  var MAX_DECOMPRESS_SIZE5 = unzipLimitBytes(100 * 1024 * 1024);
20748
20775
  var MEDIA_PART_RE = /^word\/(?:media|embeddings)\//;
20776
+ var NEVER_READ_RE = /^word\/(?:embeddings\/.*|media\/.+\.(?:mp4|m4v|mov|avi|wmv|mpe?g|mkv|webm|mp3|wav|m4a|wma|aac|ogg|flac|mid|bin))$/i;
20749
20777
  function matchesLocal(el, localName3) {
20750
20778
  return el.localName === localName3 || (el.tagName?.endsWith(`:${localName3}`) ?? false);
20751
20779
  }
@@ -20937,7 +20965,7 @@ function parseFootnotes(xml) {
20937
20965
  const runs = findElements(p, "r");
20938
20966
  for (const r of runs) {
20939
20967
  const tElements = getChildElements(r, "t");
20940
- for (const t of tElements) texts.push(escapeLiteralTags(t.textContent ?? ""));
20968
+ for (const t of tElements) texts.push(escapeLiteralTags(escapeLiteralDollar(t.textContent ?? "")));
20941
20969
  }
20942
20970
  }
20943
20971
  notes.set(id, texts.join("").trim());
@@ -20968,7 +20996,7 @@ function collectOmmlRoots(p) {
20968
20996
  function extractRun(r) {
20969
20997
  let text = "";
20970
20998
  for (const el of effectiveChildElements(r)) {
20971
- if (matchesLocal(el, "t")) text += escapeLiteralTags(el.textContent ?? "");
20999
+ if (matchesLocal(el, "t")) text += escapeLiteralTags(escapeLiteralDollar(el.textContent ?? ""));
20972
21000
  else if (matchesLocal(el, "br") || matchesLocal(el, "cr")) text += "\n";
20973
21001
  else if (matchesLocal(el, "tab")) text += " ";
20974
21002
  else if (matchesLocal(el, "sym")) text += symbolChar(getAttr(el, "font"), getAttr(el, "char"));
@@ -21264,7 +21292,7 @@ async function buildImageMap(zip, rels, doc, warnings, readBytes) {
21264
21292
  let data = null;
21265
21293
  if (readBytes) data = await imgFile.async("uint8array");
21266
21294
  imgIdx++;
21267
- const ext = imgPath.split(".").pop()?.toLowerCase() ?? "png";
21295
+ const ext = partExtension(imgPath);
21268
21296
  const mimeMap = {
21269
21297
  png: "image/png",
21270
21298
  jpg: "image/jpeg",
@@ -21363,7 +21391,7 @@ async function parseHeaderFooterBlocks(zip, doc, rels, kind, styles, numbering,
21363
21391
  }
21364
21392
  async function parseDocxDocument(buffer, options) {
21365
21393
  const readImages = options?.images !== false;
21366
- precheckZipSize(buffer, MAX_DECOMPRESS_SIZE5, void 0, { re: MEDIA_PART_RE, skip: !readImages });
21394
+ precheckZipSize(buffer, MAX_DECOMPRESS_SIZE5, void 0, { re: MEDIA_PART_RE, skip: !readImages, never: NEVER_READ_RE });
21367
21395
  const zip = await JSZip5.loadAsync(buffer);
21368
21396
  const warnings = [];
21369
21397
  const docFile = zip.file("word/document.xml");
@@ -21484,6 +21512,7 @@ import JSZip6 from "jszip";
21484
21512
  import { DOMParser as DOMParser4 } from "@xmldom/xmldom";
21485
21513
  var MAX_DECOMPRESS_SIZE6 = unzipLimitBytes(100 * 1024 * 1024);
21486
21514
  var MEDIA_PART_RE2 = /^ppt\/(?:media|embeddings)\//;
21515
+ var NEVER_READ_RE2 = /^ppt\/(?:embeddings\/.*|media\/.+\.(?:mp4|m4v|mov|avi|wmv|mpe?g|mkv|webm|mp3|wav|m4a|wma|aac|ogg|flac|mid|bin))$/i;
21487
21516
  var MAX_ZIP_ENTRIES2 = 1e4;
21488
21517
  var MAX_SLIDES = 2e3;
21489
21518
  var SKIP_PLACEHOLDERS = /* @__PURE__ */ new Set(["sldNum", "dt", "ftr", "hdr", "sldImg"]);
@@ -21580,12 +21609,14 @@ function paragraphText(p) {
21580
21609
  const name = localName(child);
21581
21610
  if (name === "r" || name === "fld") {
21582
21611
  const t = findChildByLocalName(child, "t");
21583
- if (t) text += escapeLiteralTags(escapeLiteralDollar(rawTextContent(t)));
21612
+ const rPr = findChildByLocalName(child, "rPr");
21613
+ const baseline = Number(rPr ? getAttr2(rPr, "baseline") ?? 0 : 0);
21614
+ if (t) text += wrapScript(escapeLiteralTags(escapeLiteralDollar(rawTextContent(t))), baseline > 0 ? "sup" : baseline < 0 ? "sub" : null);
21584
21615
  } else if (name === "br") {
21585
21616
  text += " ";
21586
21617
  }
21587
21618
  }
21588
- return text.replace(/\s+/g, " ").trim();
21619
+ return tidyScriptTags(text.replace(/\s+/g, " ").trim());
21589
21620
  }
21590
21621
  function bodyParagraphs(txBody) {
21591
21622
  const out = [];
@@ -21659,7 +21690,7 @@ async function pictureBlock(pic, ctx) {
21659
21690
  if (!filename) {
21660
21691
  const file = ctx.zip.file(rel.target);
21661
21692
  if (!file) return null;
21662
- const ext = rel.target.split(".").pop()?.toLowerCase() ?? "png";
21693
+ const ext = partExtension(rel.target);
21663
21694
  filename = `image_${String(ctx.imageNames.size + 1).padStart(3, "0")}.${ext}`;
21664
21695
  try {
21665
21696
  if (ctx.options?.images !== false) {
@@ -21737,7 +21768,7 @@ async function notesText(zip, rels) {
21737
21768
  return texts.join(" ");
21738
21769
  }
21739
21770
  async function parsePptxDocument(buffer, options) {
21740
- precheckZipSize(buffer, MAX_DECOMPRESS_SIZE6, MAX_ZIP_ENTRIES2, { re: MEDIA_PART_RE2, skip: options?.images === false });
21771
+ precheckZipSize(buffer, MAX_DECOMPRESS_SIZE6, MAX_ZIP_ENTRIES2, { re: MEDIA_PART_RE2, skip: options?.images === false, never: NEVER_READ_RE2 });
21741
21772
  const zip = await JSZip6.loadAsync(buffer);
21742
21773
  if (!zip.file("ppt/presentation.xml")) {
21743
21774
  throw new KordocError("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 PPTX \uD30C\uC77C: ppt/presentation.xml\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
@@ -21747,8 +21778,10 @@ async function parsePptxDocument(buffer, options) {
21747
21778
  const imageNames = /* @__PURE__ */ new Map();
21748
21779
  const images = [];
21749
21780
  const slides = await slideParts(zip);
21781
+ const pageFilter = options?.pages ? parsePageRange(options.pages, slides.length) : null;
21750
21782
  for (let i = 0; i < slides.length; i++) {
21751
21783
  const page = i + 1;
21784
+ if (pageFilter && !pageFilter.has(page)) continue;
21752
21785
  const root = parseXml3(await zip.file(slides[i]).async("text")).documentElement;
21753
21786
  if (getAttr2(root, "show") === "0") {
21754
21787
  warnings.push({ page, code: "HIDDEN_TEXT_FILTERED", message: `PPTX \uC228\uAE34 \uC2AC\uB77C\uC774\uB4DC ${page}\uCABD\uC744 \uAC74\uB108\uB701\uB2C8\uB2E4` });
@@ -28647,7 +28680,7 @@ function sanitizeText(text) {
28647
28680
  return result;
28648
28681
  }
28649
28682
  function normForMatch(text) {
28650
- return sanitizeText(text.replace(/\\\$/g, "$")).replace(/\s+/g, " ").trim();
28683
+ return sanitizeText(text.replace(/\\\$/g, "$").replace(/\\(?=<\/?(?:u|sup|sub)>)/g, "")).replace(/\s+/g, " ").trim();
28651
28684
  }
28652
28685
  function unescapeGfm(text) {
28653
28686
  return text.replace(/\\([~*_`|#<$\\])/g, "$1");
@@ -29279,6 +29312,7 @@ var ImageRegistry = class {
29279
29312
  supplied;
29280
29313
  byUrl = /* @__PURE__ */ new Map();
29281
29314
  ids = /* @__PURE__ */ new Set();
29315
+ names = /* @__PURE__ */ new Set();
29282
29316
  parts = [];
29283
29317
  picSeq = 0;
29284
29318
  binSeq = 0;
@@ -29299,8 +29333,12 @@ var ImageRegistry = class {
29299
29333
  let n = 1;
29300
29334
  while (this.ids.has(itemId)) itemId = `${m[1].replace(/[^A-Za-z0-9_]/g, "_")}_${n++}`;
29301
29335
  this.ids.add(itemId);
29336
+ let name = `BinData/${url}`;
29337
+ let suffix = 1;
29338
+ while (this.names.has(name)) name = `BinData/${m[1]}_${suffix++}.${m[2]}`;
29339
+ this.names.add(name);
29302
29340
  part = {
29303
- name: `BinData/${url}`,
29341
+ name,
29304
29342
  itemId,
29305
29343
  mime,
29306
29344
  data: m[2].toLowerCase() === "bmp" ? PLACEHOLDER_BMP : PLACEHOLDER_PNG
@@ -29329,8 +29367,9 @@ var ImageRegistry = class {
29329
29367
  const base = safe && !url.includes("..") ? safe[1] : `image${++this.binSeq}`;
29330
29368
  let itemId = base.replace(/[^A-Za-z0-9_]/g, "_");
29331
29369
  let n = 1;
29332
- while (this.ids.has(itemId)) itemId = `${base.replace(/[^A-Za-z0-9_]/g, "_")}_${n++}`;
29370
+ while (this.ids.has(itemId) || this.names.has(`BinData/${itemId}.${sniffed.ext}`)) itemId = `${base.replace(/[^A-Za-z0-9_]/g, "_")}_${n++}`;
29333
29371
  this.ids.add(itemId);
29372
+ this.names.add(`BinData/${itemId}.${sniffed.ext}`);
29334
29373
  const dim = probeImageSize(bytes);
29335
29374
  let wHU, hHU;
29336
29375
  if (dim && dim.w > 0 && dim.h > 0) {
@@ -34306,30 +34345,11 @@ async function resolveSectionEntryNames(zip) {
34306
34345
  const f = zip.file(mp);
34307
34346
  if (!f) continue;
34308
34347
  const xml = await f.async("text");
34309
- const paths = sectionPathsFromManifest(xml).filter((p) => zip.file(p) !== null);
34348
+ const paths = parseSectionPathsFromManifest(xml).filter((p) => zip.file(p) !== null);
34310
34349
  if (paths.length > 0) return paths;
34311
34350
  }
34312
34351
  return Object.keys(zip.files).filter((n) => /[Ss]ection\d+\.xml$/.test(n)).sort(compareSectionPaths);
34313
34352
  }
34314
- function sectionPathsFromManifest(xml) {
34315
- const attr = (tag, name) => {
34316
- const m = tag.match(new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`));
34317
- return m ? m[1] ?? m[2] : "";
34318
- };
34319
- const idToHref = /* @__PURE__ */ new Map();
34320
- for (const m of xml.matchAll(/<opf:item(\s(?:"[^"]*"|'[^']*'|[^>"'])*?)\/?>/g)) {
34321
- const id = attr(m[1], "id");
34322
- const href = normalizeSectionHref(attr(m[1], "href"));
34323
- if (id && href) idToHref.set(id, href);
34324
- }
34325
- const ordered = [];
34326
- for (const m of xml.matchAll(/<opf:itemref(\s(?:"[^"]*"|'[^']*'|[^>"'])*?)\/?>/g)) {
34327
- const href = idToHref.get(attr(m[1], "idref"));
34328
- if (href) ordered.push(href);
34329
- }
34330
- if (ordered.length > 0) return ordered;
34331
- return Array.from(idToHref.values()).sort(compareSectionPaths);
34332
- }
34333
34353
 
34334
34354
  // src/roundtrip/hwp5-patch.ts
34335
34355
  import { deflateRawSync as deflateRawSync2 } from "zlib";
@@ -35555,6 +35575,10 @@ async function patchHwpx(original, editedMarkdown, options) {
35555
35575
  const parsed = await parseHwpxDocument(u8ToArrayBuffer(original), { layoutTables: "keep" });
35556
35576
  origBlocks = parsed.blocks;
35557
35577
  const visual = await parseHwpxDocument(u8ToArrayBuffer(original));
35578
+ if (parsed.markdown !== visual.markdown && editedMarkdown === visual.markdown) {
35579
+ const verification2 = options?.verify === false ? void 0 : diffUnitLists(splitMarkdownUnits(visual.markdown), splitMarkdownUnits(editedMarkdown));
35580
+ return { success: true, data: new Uint8Array(original), applied: 0, skipped, verification: verification2 };
35581
+ }
35558
35582
  if (editedFromVisual(parsed.markdown, visual.markdown, editedMarkdown)) return { success: false, applied: 0, skipped, error: LAYOUT_MODE_MISMATCH };
35559
35583
  } catch (err) {
35560
35584
  return { success: false, applied: 0, skipped, error: `\uC6D0\uBCF8 HWPX \uD30C\uC2F1 \uC2E4\uD328: ${err instanceof Error ? err.message : String(err)}` };
@@ -39192,7 +39216,7 @@ var CHAR_CTRL_1SLOT = /* @__PURE__ */ new Set(["lineBreak", "hyphen", "nbSpace",
39192
39216
  function pushFillers(chars, n, prId) {
39193
39217
  for (let i = 0; i < n; i++) chars.push({ ch: "", prId });
39194
39218
  }
39195
- function pushTextSlots(t, chars, prId, depth) {
39219
+ function pushTextSlots(t, chars, prId, depth, del = { deleted: 0 }) {
39196
39220
  if (depth > 32) return;
39197
39221
  const kids = t.childNodes;
39198
39222
  if (!kids) return;
@@ -39200,19 +39224,24 @@ function pushTextSlots(t, chars, prId, depth) {
39200
39224
  const c = kids[i];
39201
39225
  if (c.nodeType === 3 || c.nodeType === 4) {
39202
39226
  for (const cp of c.textContent ?? "") {
39203
- chars.push({ ch: cp, prId });
39227
+ chars.push({ ch: del.deleted ? "" : cp, prId });
39204
39228
  if (cp.length === 2) chars.push({ ch: "", prId });
39205
39229
  }
39206
39230
  } else if (c.nodeType === 1) {
39207
39231
  const el = c;
39208
39232
  const tag = ln(el);
39209
- if (tag === "tab") {
39210
- chars.push({ ch: "", prId, tab: true, tabW: num2(el, "width") });
39211
- pushFillers(chars, 7, prId);
39233
+ if (tag === "deleteBegin" || tag === "deleteEnd") {
39234
+ del.deleted = deletionDelta(el, del.deleted);
39235
+ } else if (tag === "tab") {
39236
+ if (del.deleted) pushFillers(chars, 8, prId);
39237
+ else {
39238
+ chars.push({ ch: "", prId, tab: true, tabW: num2(el, "width") });
39239
+ pushFillers(chars, 7, prId);
39240
+ }
39212
39241
  } else if (CHAR_CTRL_1SLOT.has(tag)) {
39213
- chars.push(tag === "nbSpace" ? { ch: " ", prId, nb: true } : { ch: tag === "fwSpace" ? " " : "", prId });
39242
+ chars.push(del.deleted ? { ch: "", prId } : tag === "nbSpace" ? { ch: " ", prId, nb: true } : { ch: tag === "fwSpace" ? " " : "", prId });
39214
39243
  } else {
39215
- pushTextSlots(el, chars, prId, depth + 1);
39244
+ pushTextSlots(el, chars, prId, depth + 1, del);
39216
39245
  }
39217
39246
  }
39218
39247
  }
@@ -39237,7 +39266,7 @@ function prepareDeletedRanges(root, depth = 0) {
39237
39266
  deletedStarts.set(p, deleted);
39238
39267
  const scan = (el, xmlDepth) => {
39239
39268
  if (xmlDepth > 64) return;
39240
- if (ln(el) === "ctrl") for (const ch of elements(el)) scan(ch, xmlDepth + 1);
39269
+ if (ln(el) === "ctrl" || ln(el) === "t") for (const ch of elements(el)) scan(ch, xmlDepth + 1);
39241
39270
  else {
39242
39271
  if (ln(el) === "deleteBegin" || ln(el) === "deleteEnd") deleted = deletionDelta(el, deleted);
39243
39272
  deletedControls.set(el, deleted > 0);
@@ -39269,9 +39298,9 @@ function buildPara(p) {
39269
39298
  for (const ch of elements(runEl)) {
39270
39299
  const cn = ln(ch);
39271
39300
  if (cn === "t") {
39272
- const start = chars.length;
39273
- pushTextSlots(ch, chars, prId, 0);
39274
- if (deleted) for (let i = start; i < chars.length; i++) chars[i] = { ch: "", prId };
39301
+ const del = { deleted };
39302
+ pushTextSlots(ch, chars, prId, 0, del);
39303
+ deleted = del.deleted;
39275
39304
  } else if (OBJ_TAGS.has(cn)) {
39276
39305
  const sz = findChildByLocalName(ch, "sz");
39277
39306
  const pos = findChildByLocalName(ch, "pos");
@@ -39793,14 +39822,15 @@ function shapeGeometry(o, boxX, boxY, defs, images, warn, local = false) {
39793
39822
  const color = esc(line?.getAttribute("color") || "#000000");
39794
39823
  const strokeW = style === "NONE" ? 0 : Math.max(0.2, num2(line, "width", 33) / 100 * 2.834645);
39795
39824
  const dash = /DASH|DOT/.test(style) ? ` stroke-dasharray="${style.includes("DOT") ? "1,1.5" : "3,1.5"}"` : "";
39796
- const stroke = strokeW ? ` stroke="${color}" stroke-width="${strokeW.toFixed(2)}"${dash}` : "";
39825
+ const keepWidth = local ? ` vector-effect="non-scaling-stroke"` : "";
39826
+ const stroke = strokeW ? ` stroke="${color}" stroke-width="${strokeW.toFixed(2)}"${dash}${keepWidth}` : "";
39797
39827
  const fill = ` fill="${shapeFill(el, defs, images, warn)}"`;
39798
39828
  let svg = "";
39799
39829
  if (o.tag === "rect") svg = `<rect x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}"${fill}${stroke}/>`;
39800
39830
  else if (o.tag === "ellipse") svg = `<ellipse cx="${pt(x + w / 2)}" cy="${pt(y + h / 2)}" rx="${pt(w / 2)}" ry="${pt(h / 2)}"${fill}${stroke}/>`;
39801
39831
  else if (o.tag === "line") {
39802
39832
  const s = findChildByLocalName(el, "startPt"), e = findChildByLocalName(el, "endPt");
39803
- svg = `<line x1="${pt(x + num2(s, "x") * sx)}" y1="${pt(y + num2(s, "y") * sy)}" x2="${pt(x + num2(e, "x") * sx)}" y2="${pt(y + num2(e, "y") * sy)}" stroke="${color}" stroke-width="${(strokeW || 0.3).toFixed(2)}"${dash}/>`;
39833
+ svg = `<line x1="${pt(x + num2(s, "x") * sx)}" y1="${pt(y + num2(s, "y") * sy)}" x2="${pt(x + num2(e, "x") * sx)}" y2="${pt(y + num2(e, "y") * sy)}" stroke="${color}" stroke-width="${(strokeW || 0.3).toFixed(2)}"${dash}${keepWidth}/>`;
39804
39834
  } else if (o.tag === "polygon" || o.tag === "curv") {
39805
39835
  const pts = elements(el).filter((c) => ln(c) === "pt").map((c) => `${pt(x + num2(c, "x") * sx)},${pt(y + num2(c, "y") * sy)}`);
39806
39836
  if (pts.length >= 2) svg = `<polygon points="${pts.join(" ")}"${fill}${stroke}/>`;
@@ -40156,15 +40186,15 @@ function drawGroupByMatrix(o, x, y, baseV, areaW, ctx, depth) {
40156
40186
  emit(ctx, `<g transform="matrix(${m.slice(0, 4).map((v) => Math.round(v * 1e6) / 1e6).join(" ")} ${pt2(m[4])} ${pt2(m[5])})">`);
40157
40187
  const sub = { el: leaf, tag, index: 0, inline: true, width: w, height: h, omL: 0, omR: 0 };
40158
40188
  if (tag === "pic") drawPicFrame(leaf, 0, 0, w, h, "", ctx);
40159
- else if (SHAPE_TAGS.has(tag)) drawShape(sub, 0, 0, ctx, depth + 1, true);
40189
+ else if (SHAPE_TAGS.has(tag)) drawShape(sub, 0, 0, ctx, depth + 1, [Math.hypot(m[0], m[1]) || 1, Math.hypot(m[2], m[3]) || 1]);
40160
40190
  else drawObject(sub, 0, 0, baseV, areaW, ctx, depth + 1);
40161
40191
  emit(ctx, "</g>");
40162
40192
  ctx.regionRotations.pop();
40163
40193
  }
40164
40194
  return true;
40165
40195
  }
40166
- function drawShape(o, x, y, ctx, depth, local = false) {
40167
- const geometry = shapeGeometry(o, x, y, ctx.defs, ctx.images, (key, msg2) => warnOnce(ctx, key, msg2), local);
40196
+ function drawShape(o, x, y, ctx, depth, groupScale) {
40197
+ const geometry = shapeGeometry(o, x, y, ctx.defs, ctx.images, (key, msg2) => warnOnce(ctx, key, msg2), !!groupScale);
40168
40198
  const b = geometry;
40169
40199
  if (geometry.rotation) ctx.regionRotations.push(geometry.rotation);
40170
40200
  ctx.stats.shapes++;
@@ -40176,7 +40206,17 @@ function drawShape(o, x, y, ctx, depth, local = false) {
40176
40206
  const dt = findChildByLocalName(o.el, "drawText");
40177
40207
  const sub = dt ? findChildByLocalName(dt, "subList") : null;
40178
40208
  if (sub) {
40179
- for (const p of elements(sub)) if (ln(p) === "p") drawPara(p, x, y, geometry.w, ctx, depth + 1);
40209
+ const [sx, sy] = groupScale ?? [1, 1];
40210
+ const unscale = sx !== 1 || sy !== 1;
40211
+ if (unscale) {
40212
+ emit(ctx, `<g transform="scale(${1 / sx} ${1 / sy})">`);
40213
+ ctx.regionRotations.push([1 / sx, 0, 0, 1 / sy, 0, 0]);
40214
+ }
40215
+ for (const p of elements(sub)) if (ln(p) === "p") drawPara(p, geometry.x * sx, geometry.y * sy, geometry.w * sx, ctx, depth + 1);
40216
+ if (unscale) {
40217
+ ctx.regionRotations.pop();
40218
+ emit(ctx, "</g>");
40219
+ }
40180
40220
  }
40181
40221
  if (geometry.rotation) ctx.regionRotations.pop();
40182
40222
  if (geometry.transform) emit(ctx, "</g>");
@@ -41440,7 +41480,7 @@ async function parse(input, options) {
41440
41480
  buffer = toArrayBuffer(buf);
41441
41481
  } catch (err) {
41442
41482
  const msg2 = err instanceof Error && "code" in err && err.code === "ENOENT" ? `\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}` : `\uD30C\uC77C \uC77D\uAE30 \uC2E4\uD328: ${input}`;
41443
- return { success: false, fileType: "unknown", error: msg2, code: "PARSE_ERROR" };
41483
+ return { success: false, fileType: "unknown", error: msg2, code: classifyError(err) };
41444
41484
  }
41445
41485
  } else if (Buffer.isBuffer(input)) {
41446
41486
  buffer = toArrayBuffer(input);
@@ -41458,9 +41498,12 @@ async function parse(input, options) {
41458
41498
  }
41459
41499
  if (result.success && opts?.classifyTables) classifyTableTree(result.blocks);
41460
41500
  let out = result;
41461
- if (result.success && !result.pages) {
41462
- const pages = blocksToPages(result.blocks);
41463
- if (pages) out = { ...result, pages };
41501
+ if (result.success && opts?.pages && result.pageCount && parsePageRange(opts.pages, result.pageCount).size === 0) {
41502
+ out = { ...result, warnings: [...result.warnings ?? [], { code: "PARTIAL_PARSE", message: `\uC694\uCCAD\uD55C \uCABD \uBC94\uC704(${opts.pages})\uAC00 \uBB38\uC11C \uCABD(1~${result.pageCount})\uACFC \uACB9\uCE58\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` }] };
41503
+ }
41504
+ if (out.success && !out.pages) {
41505
+ const pages = blocksToPages(out.blocks);
41506
+ if (pages) out = { ...out, pages };
41464
41507
  }
41465
41508
  if (out.success && opts?.plain) {
41466
41509
  out = { ...out, markdown: toPlainMarkdown(out.markdown), ...out.pages ? { pages: out.pages.map((p) => ({ ...p, markdown: toPlainMarkdown(p.markdown) })) } : {} };
@@ -41512,7 +41555,7 @@ function scriptsOff(r, off) {
41512
41555
  }
41513
41556
  async function parseImage(buffer, options) {
41514
41557
  try {
41515
- const { parseImageDocument } = await import("./image-ocr-IMYXOHHV.js");
41558
+ const { parseImageDocument } = await import("./image-ocr-4BGX2EJJ.js");
41516
41559
  const { blocks, warnings } = await parseImageDocument(buffer, options);
41517
41560
  stripScriptTags({ blocks });
41518
41561
  return {
@@ -41572,7 +41615,7 @@ async function parseHwp(buffer, options) {
41572
41615
  async function parsePdf(buffer, options) {
41573
41616
  let parsePdfDocument;
41574
41617
  try {
41575
- const mod = await import("./parser-M3T2EWUN.js");
41618
+ const mod = await import("./parser-GFDGAVLV.js");
41576
41619
  parsePdfDocument = mod.parsePdfDocument;
41577
41620
  } catch {
41578
41621
  return {
@@ -41617,7 +41660,7 @@ async function parseDocx(buffer, options) {
41617
41660
  async function parsePptx(buffer, options) {
41618
41661
  try {
41619
41662
  const { markdown, blocks, metadata, outline, warnings, images } = await parsePptxDocument(buffer, options);
41620
- return { success: true, fileType: "pptx", markdown, blocks, metadata, outline, warnings, images: images?.length ? images : void 0, pageCount: metadata?.pageCount };
41663
+ return scriptsOff({ success: true, fileType: "pptx", markdown, blocks, metadata, outline, warnings, images: images?.length ? images : void 0, pageCount: metadata?.pageCount }, options?.scriptTags === false);
41621
41664
  } catch (err) {
41622
41665
  return { success: false, fileType: "pptx", error: sanitizeError(err), code: classifyError(err) };
41623
41666
  }