kordoc 4.24.28 → 4.24.29

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 (177) hide show
  1. package/README.md +4 -4
  2. package/dist/{-R5BXEKN7.js → -YTEYPQVO.js} +21 -21
  3. package/dist/{chunk-AZE46MS5.js → chunk-2C5YWTFM.js} +129 -65
  4. package/dist/chunk-2C5YWTFM.js.map +1 -0
  5. package/dist/{chunk-FWVOXMFA.js → chunk-2GULNG4H.js} +2 -2
  6. package/dist/{chunk-3WWMQS26.cjs → chunk-2XDEZVXR.cjs} +3 -3
  7. package/dist/{chunk-3WWMQS26.cjs.map → chunk-2XDEZVXR.cjs.map} +1 -1
  8. package/dist/{chunk-2MZ73PTH.cjs → chunk-3LX3Z2IU.cjs} +77 -77
  9. package/dist/{chunk-2MZ73PTH.cjs.map → chunk-3LX3Z2IU.cjs.map} +1 -1
  10. package/dist/{chunk-6EC4PI6I.js → chunk-43ZKYBLE.js} +3 -3
  11. package/dist/{chunk-BWUC36DH.js → chunk-5ESCSCHK.js} +3 -3
  12. package/dist/{chunk-EW4RSALL.js → chunk-5WGI3CM7.js} +2 -2
  13. package/dist/{chunk-PNW4B5W5.js → chunk-5WTDJEBF.js} +193 -127
  14. package/dist/chunk-5WTDJEBF.js.map +1 -0
  15. package/dist/{chunk-KW2ZZ2YM.js → chunk-6ZLZSD4K.js} +15 -15
  16. package/dist/{chunk-WKWEETPH.js → chunk-AVVS4LUN.js} +6 -6
  17. package/dist/{chunk-PUJKIYSL.js → chunk-C76347JP.js} +10 -10
  18. package/dist/{chunk-LGJYCCIK.js → chunk-D2XW3ZPA.js} +3 -3
  19. package/dist/{chunk-PIFI3L4K.cjs → chunk-E3RHMA4S.cjs} +3 -3
  20. package/dist/{chunk-PIFI3L4K.cjs.map → chunk-E3RHMA4S.cjs.map} +1 -1
  21. package/dist/{chunk-K6Z6LKX4.js → chunk-EESZHYQI.js} +3 -3
  22. package/dist/{chunk-24XMCOWF.js → chunk-EOCAXPJK.js} +2 -2
  23. package/dist/{chunk-RSCXIVO4.js → chunk-EPFU32FJ.js} +5 -5
  24. package/dist/{chunk-NXX3ZNCD.js → chunk-EVOVHP7N.js} +2 -2
  25. package/dist/{chunk-W5FIJEBK.cjs → chunk-GOM2JGBN.cjs} +2 -2
  26. package/dist/{chunk-W5FIJEBK.cjs.map → chunk-GOM2JGBN.cjs.map} +1 -1
  27. package/dist/{chunk-H77XXKSA.js → chunk-J4BY3FPL.js} +2 -2
  28. package/dist/{chunk-XOIAIDR2.js → chunk-KDJQRKIG.js} +2 -2
  29. package/dist/{chunk-263KNYS6.js → chunk-L5QXYOFG.js} +2 -2
  30. package/dist/{chunk-E2HUJHVO.cjs → chunk-MHQUXIAN.cjs} +25 -25
  31. package/dist/{chunk-E2HUJHVO.cjs.map → chunk-MHQUXIAN.cjs.map} +1 -1
  32. package/dist/{chunk-W7OSON66.js → chunk-N3BE55JM.js} +4 -4
  33. package/dist/{chunk-7YTK74IH.cjs → chunk-N3TSKOKM.cjs} +183 -119
  34. package/dist/chunk-N3TSKOKM.cjs.map +1 -0
  35. package/dist/{chunk-IGHD2274.cjs → chunk-NXAZ3MK2.cjs} +6 -6
  36. package/dist/{chunk-IGHD2274.cjs.map → chunk-NXAZ3MK2.cjs.map} +1 -1
  37. package/dist/{chunk-2LYNOQQO.js → chunk-NXCCI36U.js} +2 -2
  38. package/dist/{chunk-XZ5BYEHI.js → chunk-O4YVSQM6.js} +190 -124
  39. package/dist/chunk-O4YVSQM6.js.map +1 -0
  40. package/dist/{chunk-X323YP65.js → chunk-O7VUAKBI.js} +2 -2
  41. package/dist/{chunk-7D3YXOZB.js → chunk-PID5JXOD.js} +2 -2
  42. package/dist/{chunk-L2E7FKSR.js → chunk-PKDOIMVL.js} +5 -3
  43. package/dist/{chunk-L2E7FKSR.js.map → chunk-PKDOIMVL.js.map} +1 -1
  44. package/dist/{chunk-ZOMGHI3B.js → chunk-QLOBJB2U.js} +2 -2
  45. package/dist/{chunk-KNJFLPCP.js → chunk-ST2UWIBG.js} +22 -9
  46. package/dist/chunk-ST2UWIBG.js.map +1 -0
  47. package/dist/{chunk-Z35AEUSH.js → chunk-UGGF6IJE.js} +760 -711
  48. package/dist/chunk-UGGF6IJE.js.map +1 -0
  49. package/dist/{chunk-O57FU2GJ.js → chunk-UXOY3ZSD.js} +2 -2
  50. package/dist/{chunk-GEJLVYIV.js → chunk-UZPJUNWR.js} +2 -2
  51. package/dist/{chunk-5NALEQEL.js → chunk-W2AYHPSA.js} +113 -63
  52. package/dist/chunk-W2AYHPSA.js.map +1 -0
  53. package/dist/{chunk-HATKKA2U.js → chunk-X6BBJLB4.js} +2 -2
  54. package/dist/{chunk-NVYIWJ5U.js → chunk-XNBHWXMW.js} +2 -2
  55. package/dist/{chunk-GEMWP24J.js → chunk-XUAR22CX.js} +2 -2
  56. package/dist/{chunk-JAAUNU4D.cjs → chunk-YXZWHSS7.cjs} +330 -264
  57. package/dist/chunk-YXZWHSS7.cjs.map +1 -0
  58. package/dist/{chunk-QXA6TBIT.js → chunk-YZA2BV7Q.js} +2 -2
  59. package/dist/{chunk-GLUA5OVR.js → chunk-ZKCK6QJA.js} +4 -4
  60. package/dist/{chunk-H7M6SO2O.js → chunk-ZMDYHLXJ.js} +2 -2
  61. package/dist/chunks-BETX5XAL.js +11 -0
  62. package/dist/cli.js +43 -43
  63. package/dist/{formula-TOVULTIT.js → formula-3GNA32DY.js} +3 -3
  64. package/dist/{formula-QJSZPODL.cjs → formula-XIE3WLFC.cjs} +9 -9
  65. package/dist/{formula-QJSZPODL.cjs.map → formula-XIE3WLFC.cjs.map} +1 -1
  66. package/dist/{formula-MF3OTYTH.js → formula-XL3CHOWQ.js} +4 -4
  67. package/dist/generator-7WYFZTA4.js +17 -0
  68. package/dist/generator-HR2PEYUQ.js +10 -0
  69. package/dist/generator-WF6B6PSQ.cjs +11 -0
  70. package/dist/{generator-2YABZHQ4.cjs.map → generator-WF6B6PSQ.cjs.map} +1 -1
  71. package/dist/{image-ocr-INZPDSJH.js → image-ocr-5XVAC6GR.js} +6 -6
  72. package/dist/{image-ocr-4YJU3TJG.cjs → image-ocr-CSF647B2.cjs} +17 -17
  73. package/dist/{image-ocr-4YJU3TJG.cjs.map → image-ocr-CSF647B2.cjs.map} +1 -1
  74. package/dist/{image-ocr-LJ3WXDKU.js → image-ocr-VFC3Q4FM.js} +9 -9
  75. package/dist/index.cjs +2033 -1984
  76. package/dist/index.cjs.map +1 -1
  77. package/dist/index.js +489 -440
  78. package/dist/index.js.map +1 -1
  79. package/dist/mcp.js +36 -36
  80. package/dist/memo-4LM7X6VB.js +17 -0
  81. package/dist/{model-bundle-PXUYQSHW.js → model-bundle-MCBVBVU7.js} +5 -5
  82. package/dist/{models-SBKYVIBF.js → models-ON7Z7IEP.js} +5 -5
  83. package/dist/{parse-worker-v2-LRC5HCT6.js → parse-worker-v2-POVKDQF5.js} +22 -22
  84. package/dist/{parser-H3C7RXWN.cjs → parser-2GSL7OHD.cjs} +157 -157
  85. package/dist/{parser-H3C7RXWN.cjs.map → parser-2GSL7OHD.cjs.map} +1 -1
  86. package/dist/{parser-OXELKPM7.js → parser-QMELSN43.js} +9 -9
  87. package/dist/{parser-ARQ34S4N.js → parser-Z4JFZXTE.js} +12 -12
  88. package/dist/{pdf-ocr-ZQHLCBSN.js → pdf-ocr-ALFFH3IC.js} +9 -9
  89. package/dist/{pdf-ocr-TTLDKJSL.js → pdf-ocr-FB5SXBC6.js} +6 -6
  90. package/dist/pdf-ocr-KICQ4Z6K.cjs +36 -0
  91. package/dist/{pdf-ocr-O5VNFKRB.cjs.map → pdf-ocr-KICQ4Z6K.cjs.map} +1 -1
  92. package/dist/{profile-io-QIFJ3WF3.js → profile-io-A5DGKHHA.js} +3 -3
  93. package/dist/{rasterize-EJUDQZTP.js → rasterize-MZXDLTQ4.js} +3 -3
  94. package/dist/{redact-doc-6JMEZOGL.js → redact-doc-35SXJXNS.js} +21 -21
  95. package/dist/{render-SV47YGRO.js → render-HUNWBMBQ.js} +12 -12
  96. package/dist/{rewrite-fallback-QZV4FRPE.js → rewrite-fallback-EWZ2A7FV.js} +13 -13
  97. package/dist/seal-IEPV2HCZ.js +16 -0
  98. package/dist/{setup-FQ22XI2R.js → setup-TWETT62G.js} +3 -3
  99. package/dist/to-hwpx-F34ECNAQ.cjs +16 -0
  100. package/dist/{to-hwpx-GEI76GUY.cjs.map → to-hwpx-F34ECNAQ.cjs.map} +1 -1
  101. package/dist/{to-hwpx-BTJOOZAD.js → to-hwpx-VUXMHSHY.js} +7 -7
  102. package/dist/{to-hwpx-3EVHIIRR.js → to-hwpx-XSXRNYWN.js} +4 -4
  103. package/dist/visual-3QIRJEEB.js +37 -0
  104. package/dist/{watch-CF76OEMZ.js → watch-NHVTKLJW.js} +22 -22
  105. package/package.json +1 -1
  106. package/dist/chunk-5NALEQEL.js.map +0 -1
  107. package/dist/chunk-7YTK74IH.cjs.map +0 -1
  108. package/dist/chunk-AZE46MS5.js.map +0 -1
  109. package/dist/chunk-JAAUNU4D.cjs.map +0 -1
  110. package/dist/chunk-KNJFLPCP.js.map +0 -1
  111. package/dist/chunk-PNW4B5W5.js.map +0 -1
  112. package/dist/chunk-XZ5BYEHI.js.map +0 -1
  113. package/dist/chunk-Z35AEUSH.js.map +0 -1
  114. package/dist/chunks-DFHM4S4R.js +0 -11
  115. package/dist/generator-2YABZHQ4.cjs +0 -11
  116. package/dist/generator-SH3TOHPH.js +0 -17
  117. package/dist/generator-SST2TDKE.js +0 -10
  118. package/dist/memo-DBSP7EDT.js +0 -17
  119. package/dist/pdf-ocr-O5VNFKRB.cjs +0 -36
  120. package/dist/seal-Z4E7DZ75.js +0 -16
  121. package/dist/to-hwpx-GEI76GUY.cjs +0 -16
  122. package/dist/visual-GGB2DRCT.js +0 -37
  123. /package/dist/{-R5BXEKN7.js.map → -YTEYPQVO.js.map} +0 -0
  124. /package/dist/{chunk-FWVOXMFA.js.map → chunk-2GULNG4H.js.map} +0 -0
  125. /package/dist/{chunk-6EC4PI6I.js.map → chunk-43ZKYBLE.js.map} +0 -0
  126. /package/dist/{chunk-BWUC36DH.js.map → chunk-5ESCSCHK.js.map} +0 -0
  127. /package/dist/{chunk-EW4RSALL.js.map → chunk-5WGI3CM7.js.map} +0 -0
  128. /package/dist/{chunk-KW2ZZ2YM.js.map → chunk-6ZLZSD4K.js.map} +0 -0
  129. /package/dist/{chunk-WKWEETPH.js.map → chunk-AVVS4LUN.js.map} +0 -0
  130. /package/dist/{chunk-PUJKIYSL.js.map → chunk-C76347JP.js.map} +0 -0
  131. /package/dist/{chunk-LGJYCCIK.js.map → chunk-D2XW3ZPA.js.map} +0 -0
  132. /package/dist/{chunk-K6Z6LKX4.js.map → chunk-EESZHYQI.js.map} +0 -0
  133. /package/dist/{chunk-24XMCOWF.js.map → chunk-EOCAXPJK.js.map} +0 -0
  134. /package/dist/{chunk-RSCXIVO4.js.map → chunk-EPFU32FJ.js.map} +0 -0
  135. /package/dist/{chunk-NXX3ZNCD.js.map → chunk-EVOVHP7N.js.map} +0 -0
  136. /package/dist/{chunk-H77XXKSA.js.map → chunk-J4BY3FPL.js.map} +0 -0
  137. /package/dist/{chunk-XOIAIDR2.js.map → chunk-KDJQRKIG.js.map} +0 -0
  138. /package/dist/{chunk-263KNYS6.js.map → chunk-L5QXYOFG.js.map} +0 -0
  139. /package/dist/{chunk-W7OSON66.js.map → chunk-N3BE55JM.js.map} +0 -0
  140. /package/dist/{chunk-2LYNOQQO.js.map → chunk-NXCCI36U.js.map} +0 -0
  141. /package/dist/{chunk-X323YP65.js.map → chunk-O7VUAKBI.js.map} +0 -0
  142. /package/dist/{chunk-7D3YXOZB.js.map → chunk-PID5JXOD.js.map} +0 -0
  143. /package/dist/{chunk-ZOMGHI3B.js.map → chunk-QLOBJB2U.js.map} +0 -0
  144. /package/dist/{chunk-O57FU2GJ.js.map → chunk-UXOY3ZSD.js.map} +0 -0
  145. /package/dist/{chunk-GEJLVYIV.js.map → chunk-UZPJUNWR.js.map} +0 -0
  146. /package/dist/{chunk-HATKKA2U.js.map → chunk-X6BBJLB4.js.map} +0 -0
  147. /package/dist/{chunk-NVYIWJ5U.js.map → chunk-XNBHWXMW.js.map} +0 -0
  148. /package/dist/{chunk-GEMWP24J.js.map → chunk-XUAR22CX.js.map} +0 -0
  149. /package/dist/{chunk-QXA6TBIT.js.map → chunk-YZA2BV7Q.js.map} +0 -0
  150. /package/dist/{chunk-GLUA5OVR.js.map → chunk-ZKCK6QJA.js.map} +0 -0
  151. /package/dist/{chunk-H7M6SO2O.js.map → chunk-ZMDYHLXJ.js.map} +0 -0
  152. /package/dist/{chunks-DFHM4S4R.js.map → chunks-BETX5XAL.js.map} +0 -0
  153. /package/dist/{formula-TOVULTIT.js.map → formula-3GNA32DY.js.map} +0 -0
  154. /package/dist/{formula-MF3OTYTH.js.map → formula-XL3CHOWQ.js.map} +0 -0
  155. /package/dist/{generator-SH3TOHPH.js.map → generator-7WYFZTA4.js.map} +0 -0
  156. /package/dist/{generator-SST2TDKE.js.map → generator-HR2PEYUQ.js.map} +0 -0
  157. /package/dist/{image-ocr-INZPDSJH.js.map → image-ocr-5XVAC6GR.js.map} +0 -0
  158. /package/dist/{image-ocr-LJ3WXDKU.js.map → image-ocr-VFC3Q4FM.js.map} +0 -0
  159. /package/dist/{memo-DBSP7EDT.js.map → memo-4LM7X6VB.js.map} +0 -0
  160. /package/dist/{model-bundle-PXUYQSHW.js.map → model-bundle-MCBVBVU7.js.map} +0 -0
  161. /package/dist/{models-SBKYVIBF.js.map → models-ON7Z7IEP.js.map} +0 -0
  162. /package/dist/{parse-worker-v2-LRC5HCT6.js.map → parse-worker-v2-POVKDQF5.js.map} +0 -0
  163. /package/dist/{parser-OXELKPM7.js.map → parser-QMELSN43.js.map} +0 -0
  164. /package/dist/{parser-ARQ34S4N.js.map → parser-Z4JFZXTE.js.map} +0 -0
  165. /package/dist/{pdf-ocr-TTLDKJSL.js.map → pdf-ocr-ALFFH3IC.js.map} +0 -0
  166. /package/dist/{pdf-ocr-ZQHLCBSN.js.map → pdf-ocr-FB5SXBC6.js.map} +0 -0
  167. /package/dist/{profile-io-QIFJ3WF3.js.map → profile-io-A5DGKHHA.js.map} +0 -0
  168. /package/dist/{rasterize-EJUDQZTP.js.map → rasterize-MZXDLTQ4.js.map} +0 -0
  169. /package/dist/{redact-doc-6JMEZOGL.js.map → redact-doc-35SXJXNS.js.map} +0 -0
  170. /package/dist/{render-SV47YGRO.js.map → render-HUNWBMBQ.js.map} +0 -0
  171. /package/dist/{rewrite-fallback-QZV4FRPE.js.map → rewrite-fallback-EWZ2A7FV.js.map} +0 -0
  172. /package/dist/{seal-Z4E7DZ75.js.map → seal-IEPV2HCZ.js.map} +0 -0
  173. /package/dist/{setup-FQ22XI2R.js.map → setup-TWETT62G.js.map} +0 -0
  174. /package/dist/{to-hwpx-3EVHIIRR.js.map → to-hwpx-VUXMHSHY.js.map} +0 -0
  175. /package/dist/{to-hwpx-BTJOOZAD.js.map → to-hwpx-XSXRNYWN.js.map} +0 -0
  176. /package/dist/{visual-GGB2DRCT.js.map → visual-3QIRJEEB.js.map} +0 -0
  177. /package/dist/{watch-CF76OEMZ.js.map → watch-NHVTKLJW.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hwp5/to-hwpx/index.ts","../src/hwp5/record.ts","../src/hwp5/images.ts","../src/hwp5/aes.ts","../src/hwp5/crypto.ts","../src/hwp5/pw-crypto.ts","../src/hwp5/page-boundary.ts","../src/hwp5/table-ids.ts","../src/hwp5/numbering.ts","../src/hwp5/equation.ts","../src/hwp5/ir-assemble.ts","../src/hwp5/body.ts","../src/hwp5/parser.ts","../src/memo-notes.ts","../src/hwp5/to-hwpx/util.ts","../src/hwp5/to-hwpx/header.ts","../src/hwp5/to-hwpx/fields.ts","../src/hwp5/to-hwpx/shapes.ts","../src/hwp5/to-hwpx/notes.ts","../src/hwp5/to-hwpx/controls.ts","../src/hwp5/to-hwpx/section.ts"],"sourcesContent":["/**\n * HWP 5.x → HWPX 변환 — 서식 그대로 옮긴다.\n *\n * 문서 모델이 같은 두 직렬화(이진 레코드 ↔ OWPML XML)라 값을 1:1 로 옮긴다: DocInfo → header.xml, BodyText 섹션 → sectionN.xml,\n * BinData 스토리지 → BinData/imageN.확장자, 요약 정보·미리보기 글 → content.hpf·Preview. 한글이 같은 문서를 .hwpx 로 저장한 짝을\n * 정답으로 속성 단위 일치를 잰다(bench/hwp2hwpx.mjs). 암호 문서는 password 로 연다. 배포용 문서(작성자가 복사·편집을 막은 문서)는\n * 변환하지 않는다.\n */\n\nimport JSZip from \"jszip\"\nimport { createRequire } from \"module\"\nimport { openHwp5Container, readHwp5DocInfoRecords, readHwp5SectionStreams, readHwp5SectionRecords, readHwp5BinData } from \"../parser.js\"\nimport { decompressStream, readRecords } from \"../record.js\"\nimport { recordTree, Cur, el, esc, type Rec } from \"./util.js\"\nimport { headerXml, docProps, paraShapeIds, XML_DECL, NS } from \"./header.js\"\nimport { sectionXml } from \"./section.js\"\nimport type { ConvertContext } from \"./controls.js\"\nimport { VERSION, KordocError } from \"../../utils.js\"\n\nexport interface HwpToHwpxOptions {\n /** 암호 문서의 열기 암호 */\n password?: string\n}\n\nconst require = createRequire(import.meta.url)\nconst CFB: { read(d: Buffer, o: { type: \"buffer\" }): unknown; find(c: unknown, p: string): { content?: Buffer | Uint8Array } | null } = require(\"cfb\")\n\nconst TAG_BIN_DATA = 0x12\nconst TAG_MEMO_SHAPE = 0x5c\n\n/** BIN_DATA 항목 → 패키지 이름·미디어 형식 (스토리지 id 순서) */\nfunction binItems(docInfo: Rec[]): Array<{ index: number; storageId: number; ext: string; ole: boolean }> {\n const out: Array<{ index: number; storageId: number; ext: string; ole: boolean }> = []\n docInfo.filter(r => r.tagId === TAG_BIN_DATA).forEach((r, i) => {\n const c = new Cur(r.data)\n const a = c.u16()\n const type = a & 0x0f\n if (type === 0) return // 연결 그림 — 파일 밖\n const storageId = c.u16()\n const ext = type === 1 ? c.str() : \"OLE\"\n out.push({ index: i + 1, storageId, ext, ole: type === 2 })\n })\n return out\n}\n\n/** OLE 스토리지(4바이트 길이 머리 + 복합 문서)의 OOXML 차트 스트림 — 한글이 차트 개체를 저장할 때 함께 넣는다 */\nfunction oleChartXml(data: Buffer | undefined): Buffer | null {\n if (!data || data.length < 12) return null\n try {\n const cfb = CFB.read(data.subarray(4), { type: \"buffer\" })\n const e = CFB.find(cfb, \"OOXMLChartContents\")\n return e?.content?.length ? Buffer.from(e.content) : null\n } catch {\n return null\n }\n}\n\n/** 스크립트 스트림(길이 u32 + UTF-16 글이 머리·본문 순으로) → headerScripts.js · sourceScripts.js */\nfunction scriptParts(data: Buffer | null): [Buffer, Buffer] | null {\n if (!data || data.length < 8) return null\n const parts: Buffer[] = []\n let o = 0\n for (let i = 0; i < 2; i++) {\n if (o + 4 > data.length) return null\n const n = data.readUInt32LE(o) * 2\n o += 4\n if (o + n > data.length) return null\n parts.push(data.subarray(o, o + n))\n o += n\n }\n return [parts[0], parts[1]]\n}\n\n/** 메모 확장(MemoExtended 스트림의 0x65 기록: 개수 u32 + 메모 id·부모 id u32 쌍) → Contents/memoExtended.xml, 없으면 null */\nfunction memoExtendedXml(raw: Buffer | null, compressed: boolean): string | null {\n if (!raw) return null\n let rec: Rec | undefined\n try { rec = readRecords(compressed ? decompressStream(raw) : raw).find(r => r.tagId === 0x65) } catch { return null }\n if (!rec || rec.data.length < 4) return null\n const c = new Cur(rec.data)\n const memos: string[] = []\n for (let n = c.u32(); n > 0 && c.rest >= 8; n--) memos.push(el(\"he:memo\", [[\"id\", c.u32()], [\"parentId\", c.u32()]]))\n return memos.length ? XML_DECL + `<he:memosEx xmlns:he=\"http://www.hancom.co.kr/hwpml/2021/extended\">${memos.join(\"\")}</he:memosEx>` : null\n}\n\n/** 한글이 테두리 0번 참조를 메우려고 1번에 끼우는 빈 테두리 */\nconst EMPTY_BORDER_FILL = '<hh:borderFill id=\"1\" threeD=\"0\" shadow=\"0\" centerLine=\"NONE\" breakCellSeparateLine=\"0\">'\n + '<hh:slash type=\"NONE\" Crooked=\"0\" isCounter=\"0\"/><hh:backSlash type=\"NONE\" Crooked=\"0\" isCounter=\"0\"/>'\n + [\"left\", \"right\", \"top\", \"bottom\"].map(s => `<hh:${s}Border type=\"NONE\" width=\"0.1 mm\" color=\"#000000\"/>`).join(\"\")\n + '<hh:diagonal type=\"SOLID\" width=\"0.1 mm\" color=\"#000000\"/></hh:borderFill>'\n\n/**\n * 없는 테두리 0번(테두리는 1번부터)을 가리키는 문서 — 한글이 아닌 도구로 쓴 HWP 다. 한글처럼 빈 테두리를 1번에 끼우고 기존 번호와\n * 모든 참조를 하나씩 민다(0 → 1)\n */\nfunction shiftZeroBorderFill(parts: Map<string, string>): Map<string, string> {\n if (![...parts.values()].some(x => x.includes('borderFillIDRef=\"0\"'))) return parts\n const out = new Map<string, string>()\n for (const [name, xml] of parts) {\n let x = xml.replace(/borderFillIDRef=\"(\\d+)\"/g, (_, n: string) => `borderFillIDRef=\"${Number(n) + 1}\"`)\n if (name === \"Contents/header.xml\") {\n x = x.replace(/<hh:borderFill id=\"(\\d+)\"/g, (_, n: string) => `<hh:borderFill id=\"${Number(n) + 1}\"`)\n x = x.includes(\"<hh:borderFills \")\n ? x.replace(/<hh:borderFills itemCnt=\"(\\d+)\">/, (_, n: string) => `<hh:borderFills itemCnt=\"${Number(n) + 1}\">${EMPTY_BORDER_FILL}`)\n : x.replace(\"</hh:fontfaces>\", `</hh:fontfaces><hh:borderFills itemCnt=\"1\">${EMPTY_BORDER_FILL}</hh:borderFills>`)\n }\n out.set(name, x)\n }\n return out\n}\n\nconst V13_DEFAULT_SCRIPT = \"function OnDocument_New()\\r\\n{\\r\\n\\t//todo : \\r\\n}\\r\\n\\r\\n\"\n\nexport async function hwpToHwpx(input: Uint8Array | ArrayBuffer, options?: HwpToHwpxOptions): Promise<Uint8Array> {\n const buffer = Buffer.from(input instanceof ArrayBuffer ? new Uint8Array(input) : input)\n const c = openHwp5Container(buffer, options)\n // 배포용 문서는 작성자가 복사·편집을 막은 문서다 — 편집 가능한 HWPX 로 풀어 주지 않는다\n if (c.distribution) throw new KordocError(\"배포용(읽기 전용) HWP 문서는 HWPX 로 변환하지 않습니다 — 작성자가 복사·편집을 막은 문서입니다\")\n const docInfo = (readHwp5DocInfoRecords(c) ?? []) as Rec[]\n const sections = readHwp5SectionRecords(c, readHwp5SectionStreams(c), c.warnings)\n const bins = readHwp5BinData(c)\n\n const linkDoc = c.findStream(\"/DocOptions/_LinkDoc\")\n const link = { path: \"\", pageInherit: 0, footnoteInherit: 0 }\n if (linkDoc && linkDoc.length >= 520) {\n const path = linkDoc.toString(\"utf16le\", 0, 520).replace(/\\u0000[\\s\\S]*$/, \"\")\n link.path = path\n link.pageInherit = linkDoc.readUInt32LE(520) & 1\n link.footnoteInherit = linkDoc.length >= 524 ? linkDoc.readUInt32LE(520) >>> 1 & 1 : 0\n }\n\n const items = binItems(docInfo)\n const charts: Array<{ name: string; xml: Buffer }> = []\n const chartByBin = new Map<number, string | null>()\n // BinData 이름 — 한글처럼 처음 참조한 차례로 번호를 매긴다(header 의 그림 채우기 → 본문). OLE 스토리지는 차트든 아니든 oleN, 그 밖은 imageN\n const refs = new Map<number, { id: string; kind: \"image\" | \"ole\" }>()\n const refer = (binId: number, kind: \"image\" | \"ole\"): string => {\n let r = refs.get(binId)\n if (!r) refs.set(binId, (r = { id: `${kind}${refs.size + 1}`, kind }))\n return r.id\n }\n const ctx: ConvertContext = {\n memoShapes: docInfo.filter(r => r.tagId === TAG_MEMO_SHAPE).length,\n paraIds: paraShapeIds(docInfo),\n fields: { stack: [] },\n masterPages: [],\n tailMasters: [],\n memos: new Map(),\n linkedParas: new Map(),\n chartOf(binId) {\n if (chartByBin.has(binId)) return chartByBin.get(binId)!\n const item = items.find(b => b.index === binId)\n const xml = item?.ole ? oleChartXml(bins.get(item.storageId)?.data) : null\n const name = xml ? `Chart/chart${charts.length + 1}.xml` : null\n if (xml && name) charts.push({ name, xml })\n chartByBin.set(binId, name)\n return name\n },\n binRef: binId => refer(binId, \"image\"),\n oleRef: binId => refer(binId, \"ole\"),\n }\n\n const zip = new JSZip()\n zip.file(\"mimetype\", \"application/hwp+zip\", { compression: \"STORE\" })\n zip.file(\"version.xml\", XML_DECL + el(\"hv:HCFVersion\", [[\"xmlns:hv\", \"http://www.hancom.co.kr/hwpml/2011/version\"], [\"tagetApplication\", \"WORDPROCESSOR\"],\n [\"major\", 5], [\"minor\", 1], [\"micro\", 1], [\"buildNumber\", 0], [\"os\", 1], [\"xmlVersion\", \"1.5\"], [\"application\", \"kordoc\"], [\"appVersion\", VERSION]]),\n { compression: \"STORE\" })\n const parts = new Map<string, string>([[\"Contents/header.xml\", headerXml(docInfo, link, ctx.binRef, sections.length)]])\n\n const sectionNames: string[] = []\n const sectionItems: string[] = []\n sections.forEach((recs, i) => {\n const name = `Contents/section${i}.xml`\n const mp0 = ctx.masterPages.length\n parts.set(name, sectionXml(recordTree((recs ?? []) as Rec[]), ctx))\n // 구역의 바탕쪽은 매니페스트에서 그 구역 앞에 둔다(한글 저장 꼴)\n for (let k = mp0; k < ctx.masterPages.length; k++) {\n parts.set(`Contents/masterpage${k}.xml`, ctx.masterPages[k])\n sectionItems.push(el(\"opf:item\", [[\"id\", `masterpage${k}`], [\"href\", `Contents/masterpage${k}.xml`], [\"media-type\", \"application/xml\"]]))\n }\n sectionNames.push(name)\n sectionItems.push(el(\"opf:item\", [[\"id\", `section${i}`], [\"href\", name], [\"media-type\", \"application/xml\"]]))\n })\n for (const [name, xml] of shiftZeroBorderFill(parts)) zip.file(name, xml)\n // 참조 차례로 BinData — 확장자는 스토리지 이름(BIN0001.jpg)을 따른다. 참조 없는 항목은 뒤에 붙인다\n for (const b of items) if (!refs.has(b.index)) refer(b.index, b.ole ? \"ole\" : \"image\")\n const manifest: string[] = [el(\"opf:item\", [[\"id\", \"header\"], [\"href\", \"Contents/header.xml\"], [\"media-type\", \"application/xml\"]])]\n const memoEx = memoExtendedXml(c.findStream(\"/MemoExtended\"), c.compressed)\n if (memoEx) {\n zip.file(\"Contents/memoExtended.xml\", memoEx)\n manifest.push(el(\"opf:item\", [[\"id\", \"memoextended\"], [\"href\", \"Contents/memoExtended.xml\"], [\"media-type\", \"application/xml\"]]))\n }\n for (const [binId, r] of refs) {\n const b = items.find(x => x.index === binId)\n const data = b && bins.get(b.storageId)\n if (!b || !data) continue\n const ext = r.kind === \"ole\" ? \"ole\" : (/\\.([^.]+)$/.exec(data.name)?.[1] ?? b.ext)\n const name = `BinData/${r.id}.${ext}`\n zip.file(name, data.data, /^(png|jpe?g|gif)$/i.test(ext) ? { compression: \"STORE\" } : undefined)\n manifest.push(el(\"opf:item\", [[\"id\", r.id], [\"href\", name],\n [\"media-type\", r.kind === \"ole\" ? \"application/ole\" : `image/${ext.toLowerCase()}`], [\"isEmbeded\", r.kind === \"ole\" ? 0 : 1]]))\n }\n manifest.push(...sectionItems)\n for (const ch of charts) zip.file(ch.name, ch.xml)\n const scripts = scriptParts((() => {\n const raw = c.findStream(\"/Scripts/DefaultJScript\")\n if (!raw) return null\n try { return c.compressed ? decompressStream(raw) : raw } catch { return null }\n })())\n // 한글 2024 기본 스크립트(끝 빈 줄 하나 더)는 한글이 HWPX 에 옮기지 않는다\n if (scripts && scripts[1].length && scripts[1].toString(\"utf16le\") !== V13_DEFAULT_SCRIPT) {\n zip.file(\"Scripts/headerScripts.js\", scripts[0])\n zip.file(\"Scripts/sourceScripts.js\", scripts[1])\n const js = \"application/x-javascript ;charset=utf-16\"\n manifest.push(el(\"opf:item\", [[\"id\", \"headersc\"], [\"href\", \"Scripts/headerScripts.js\"], [\"media-type\", js]]),\n el(\"opf:item\", [[\"id\", \"sourcesc\"], [\"href\", \"Scripts/sourceScripts.js\"], [\"media-type\", js]]))\n }\n manifest.push(el(\"opf:item\", [[\"id\", \"settings\"], [\"href\", \"settings.xml\"], [\"media-type\", \"application/xml\"]]))\n\n const prvText = c.findStream(\"/PrvText\")\n zip.file(\"Preview/PrvText.txt\", prvText ? prvText.toString(\"utf16le\").replace(/\\u0000+$/, \"\") : \"\")\n const prvImage = c.findStream(\"/PrvImage\")\n if (prvImage && prvImage.subarray(0, 4).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47]))) zip.file(\"Preview/PrvImage.png\", prvImage, { compression: \"STORE\" })\n\n const caret = docProps(docInfo).caret\n zip.file(\"settings.xml\", XML_DECL + '<ha:HWPApplicationSetting xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\" '\n + 'xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\">'\n + el(\"ha:CaretPosition\", [[\"listIDRef\", caret[0]], [\"paraIDRef\", caret[1]], [\"pos\", caret[2]]]) + \"</ha:HWPApplicationSetting>\")\n\n const rdfPart = (name: string, type: string): string => '<rdf:Description rdf:about=\"\"><ns0:hasPart xmlns:ns0=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#\" '\n + `rdf:resource=\"${name}\"/></rdf:Description><rdf:Description rdf:about=\"${name}\"><rdf:type rdf:resource=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#${type}\"/></rdf:Description>`\n zip.file(\"META-INF/container.rdf\", XML_DECL + '<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">' + rdfPart(\"Contents/header.xml\", \"HeaderFile\")\n + sectionNames.map(n => rdfPart(n, \"SectionFile\")).join(\"\")\n + '<rdf:Description rdf:about=\"\"><rdf:type rdf:resource=\"http://www.hancom.co.kr/hwpml/2016/meta/pkg#Document\"/></rdf:Description></rdf:RDF>')\n zip.file(\"META-INF/container.xml\", XML_DECL + '<ocf:container xmlns:ocf=\"urn:oasis:names:tc:opendocument:xmlns:container\" xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\">'\n + '<ocf:rootfiles><ocf:rootfile full-path=\"Contents/content.hpf\" media-type=\"application/hwpml-package+xml\"/>'\n + '<ocf:rootfile full-path=\"Preview/PrvText.txt\" media-type=\"text/plain\"/><ocf:rootfile full-path=\"META-INF/container.rdf\" media-type=\"application/rdf+xml\"/>'\n + \"</ocf:rootfiles></ocf:container>\")\n zip.file(\"META-INF/manifest.xml\", XML_DECL + '<odf:manifest xmlns:odf=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"/>')\n zip.file(\"Contents/content.hpf\", XML_DECL + `<opf:package ${NS} version=\"\" unique-identifier=\"\" id=\"\">`\n + `<opf:metadata><opf:title>${esc(\"\")}</opf:title><opf:language>ko</opf:language></opf:metadata>`\n + `<opf:manifest>${manifest.join(\"\")}</opf:manifest><opf:spine>`\n + el(\"opf:itemref\", [[\"idref\", \"header\"], [\"linear\", \"yes\"]]) + sectionNames.map((_, i) => el(\"opf:itemref\", [[\"idref\", `section${i}`], [\"linear\", \"yes\"]])).join(\"\")\n + \"</opf:spine></opf:package>\")\n\n return zip.generateAsync({ type: \"uint8array\", compression: \"DEFLATE\" })\n}\n\nexport interface ConvertToHwpxResult {\n data: Uint8Array\n /** preserve: 서식 그대로(HWP 5.x), content: 글·표만 옮겨 kordoc 기본 서식으로(HWP 3.x 등) */\n mode: \"preserve\" | \"content\"\n warnings: string[]\n}\n\n/**\n * 한글 문서 → HWPX. HWP 5.x 는 서식 그대로(hwpToHwpx), 서식 보존 변환이 없는 형식(HWP 3.x·HWPML)은 글·표를 옮겨 kordoc 기본\n * 서식으로 쓰고 그 사실을 경고로 남긴다. HWPX 는 그대로 돌려준다\n */\nexport async function convertToHwpx(input: Uint8Array | ArrayBuffer, options?: HwpToHwpxOptions): Promise<ConvertToHwpxResult> {\n const bytes = input instanceof ArrayBuffer ? new Uint8Array(input) : input\n const ab = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer\n const { detectFormat } = await import(\"../../detect.js\")\n const format = detectFormat(ab)\n if (format === \"hwp\") return { data: await hwpToHwpx(bytes, options), mode: \"preserve\", warnings: [] }\n if (format === \"hwpx\") return { data: bytes, mode: \"preserve\", warnings: [\"이미 HWPX 문서입니다 — 그대로 둡니다\"] }\n if (format !== \"hwp3\" && format !== \"hwpml\") throw new KordocError(`HWP 문서가 아닙니다 (${format})`)\n const { parse } = await import(\"../../index.js\")\n const { markdownToHwpx } = await import(\"../../hwpx/generator.js\")\n const parsed = await parse(ab, { password: options?.password })\n if (!parsed.success) throw new KordocError(parsed.error ?? \"문서를 읽지 못했습니다\")\n return {\n data: new Uint8Array(await markdownToHwpx(parsed.markdown)),\n mode: \"content\",\n warnings: [`${format === \"hwp3\" ? \"HWP 3.x\" : \"HWPML\"} 문서는 서식 그대로 옮기는 변환을 지원하지 않아 글·표만 kordoc 기본 서식으로 옮겼습니다`],\n }\n}\n","/** HWP 5.x 레코드 리더, UTF-16LE 텍스트 추출, 스트림 압축해제 */\n\nimport type { ScriptKind } from \"../script-tags.js\"\nimport { inflateRawSync, inflateSync } from \"zlib\"\nimport { KordocError } from \"../utils.js\"\nimport { TOC_LEADER } from \"../toc-entry.js\"\nimport type { Edges } from \"../table/layout-frames.js\"\n\n// ─── 레코드 태그 상수 ────────────────────────────────\n\nexport const TAG_PARA_HEADER = 0x0042\nexport const TAG_PARA_TEXT = 0x0043\nexport const TAG_CHAR_SHAPE = 0x0044\nexport const TAG_PARA_SHAPE = 0x0045\n/** 0x45의 스펙상 정체 — 본문 문단의 줄 조판 정보(HWPTAG_BEGIN+53). TAG_PARA_SHAPE는 역사적 오명 */\nexport const TAG_PARA_LINE_SEG = 0x0045\nexport const TAG_CTRL_HEADER = 0x0047\nexport const TAG_LIST_HEADER = 0x0048\n/** 구역 끝 메모 목록 — 메모 번호 DWORD, 뒤 LIST_HEADER·문단이 메모 글 (#180) */\nexport const TAG_MEMO_LIST = 0x005d\nexport const TAG_TABLE = 0x004d\nexport const TAG_SHAPE_COMPONENT = 0x004c // HWPTAG_BEGIN + 60\nexport const TAG_SHAPE_COMPONENT_PICTURE = 0x0055 // HWPTAG_BEGIN + 69\nexport const TAG_SHAPE_COMPONENT_CONTAINER = 0x0056 // HWPTAG_BEGIN + 70\nexport const TAG_CTRL_DATA = 0x0057 // HWPTAG_BEGIN + 71\nexport const TAG_EQEDIT = 0x0058\n\n// DocInfo 태그 (스타일 정보 해석용) — HWPTAG_BEGIN(0x0010) 기준\nexport const TAG_ID_MAPPINGS = 0x0011 // HWPTAG_BEGIN + 1\nexport const TAG_BORDER_FILL = 0x0014 // HWPTAG_BEGIN + 4\nexport const TAG_BIN_DATA = 0x0012 // HWPTAG_BEGIN + 2\nexport const TAG_FACE_NAME = 0x0013 // HWPTAG_BEGIN + 3\nexport const TAG_DOC_CHAR_SHAPE = 0x0015 // HWPTAG_BEGIN + 5\nexport const TAG_NUMBERING = 0x0017 // HWPTAG_BEGIN + 7\nexport const TAG_BULLET = 0x0018 // HWPTAG_BEGIN + 8\nexport const TAG_DOC_PARA_SHAPE = 0x0019 // HWPTAG_BEGIN + 9\nexport const TAG_DOC_STYLE = 0x001a // HWPTAG_BEGIN + 10\n\n// 특수 문자 코드 (UTF-16LE) — HWP 5.0 바이너리 스펙 + rhwp 검증\n// 3가지 카테고리: char(2바이트), inline(16바이트), extended(16바이트)\n// char: 0, 13, 24-31 — 제어문자만, 확장 데이터 없음\n// inline: 4-9, 19-20 — 제어문자(2) + 확장(14) = 16바이트\n// extended: 1-3, 10-12, 14-18, 21-23 — 제어문자(2) + 확장(14) = 16바이트\nconst CHAR_LINE = 0x0000 // char: 줄바꿈\nconst CHAR_SECTION_BREAK = 0x000a // char: 강제 줄 나눔(line break, 2바이트). 구역/단 정의는 코드2(extended)라 혼동 주의\nconst CHAR_PARA = 0x000d // char: 문단 끝\nconst CHAR_TAB = 0x0009 // inline: 탭\nconst CHAR_HYPHEN = 0x0018 // char: 하이픈 (스펙 코드 24 — pyhwp HYPHEN, hwp3 SIMPLE_CTRL 24/25와 동일)\nconst CHAR_NBSP = 0x001e // char: 묶음 빈칸(비분리 공백, 스펙 코드 30 — pyhwp NONBREAK_SPACE)\nconst CHAR_FIXED_WIDTH = 0x001f // char: 고정폭 빈칸 (스펙 코드 31 — pyhwp FIXWIDTH_SPACE). 25~29(0x19~0x1d)는 예약\n\n// FileHeader 플래그\nexport const FLAG_COMPRESSED = 1 << 0\nexport const FLAG_ENCRYPTED = 1 << 1\nexport const FLAG_DISTRIBUTION = 1 << 2\nexport const FLAG_DRM = 1 << 4\n/** 변경 내용 추적 문서 — 한컴은 이 비트가 서 있으면 BodyText(지금 내용)가 아니라 ViewText(지운 글까지 표시한 사본)를 그린다 */\nexport const FLAG_TRACK_CHANGES = 1 << 14\n\n// ─── 레코드 구조 ─────────────────────────────────────\n\nexport interface HwpRecord {\n tagId: number\n level: number\n size: number\n data: Buffer\n}\n\nexport interface HwpFileHeader {\n signature: string\n versionMajor: number\n flags: number\n}\n\n// ─── 레코드 리더 ─────────────────────────────────────\n\n/** 최대 레코드 수 — 비정상 파일에 의한 메모리 폭주 방지 */\nconst MAX_RECORDS = 500_000\n\nexport function readRecords(data: Buffer): HwpRecord[] {\n const records: HwpRecord[] = []\n let offset = 0\n\n while (offset + 4 <= data.length && records.length < MAX_RECORDS) {\n const header = data.readUInt32LE(offset)\n offset += 4\n\n const tagId = header & 0x3ff\n const level = (header >> 10) & 0x3ff\n let size = (header >> 20) & 0xfff\n\n // 확장 크기\n if (size === 0xfff) {\n if (offset + 4 > data.length) break\n size = data.readUInt32LE(offset)\n offset += 4\n }\n\n if (offset + size > data.length) break\n records.push({ tagId, level, size, data: data.subarray(offset, offset + size) })\n offset += size\n }\n\n return records\n}\n\n// ─── 스트림 압축 해제 ────────────────────────────────\n\n/** 압축 해제 최대 크기 (100MB) — decompression bomb 방지 */\nconst MAX_DECOMPRESS_SIZE = 100 * 1024 * 1024\n\nexport function decompressStream(data: Buffer): Buffer {\n const opts = { maxOutputLength: MAX_DECOMPRESS_SIZE }\n if (data.length >= 2 && data[0] === 0x78) {\n try { return inflateSync(data, opts) } catch { /* fallback to raw */ }\n }\n return inflateRawSync(data, opts)\n}\n\n// ─── FileHeader 파싱 ─────────────────────────────────\n\nexport function parseFileHeader(data: Buffer): HwpFileHeader {\n if (data.length < 40) throw new KordocError(\"FileHeader가 너무 짧습니다 (최소 40바이트)\")\n const sig = data.subarray(0, 32).toString(\"utf8\").replace(/\\0+$/, \"\")\n return {\n signature: sig,\n versionMajor: data[35],\n flags: data.readUInt32LE(36),\n }\n}\n\n// ─── 스타일 정보 구조 ────────────────────────────────\n\n/** DocInfo에서 추출한 문단 모양 (PARA_SHAPE) */\nexport interface HwpParaShape {\n /** 문단 머리 종류 (attr1 bits 23-24): 0=없음, 1=개요, 2=번호, 3=글머리표 */\n headType: number\n /** 문단 수준 (attr1 bits 25-27): 0-6 → 1-7수준 */\n paraLevel: number\n /** 번호/글머리표 ID (1-based) — headType=2면 numbering, 3이면 bullet 인덱스 */\n numberingId: number\n}\n\n/** DocInfo BIN_DATA 항목 — binDataId(1-based 레코드 순서) → BinData 스토리지 매핑 */\nexport interface HwpBinDataItem {\n /** 0=link(외부 파일), 1=embedding, 2=storage */\n kind: \"link\" | \"embed\" | \"storage\"\n /** BinData 스토리지 엔트리 번호 — 스트림명 \"BIN%04X.ext\" (16진) */\n storageId: number\n /** 확장자 (예: \"jpg\") */\n extension: string\n}\n\n/** DocInfo NUMBERING — 문단 번호 정의 (7수준) */\nexport interface HwpNumbering {\n /** 수준별(0-6) 번호 형식 문자열 (예: \"^1.\") — ^N은 N수준 번호로 치환 */\n levelFormats: string[]\n /** 수준별 번호 모양 코드 (HWP 표 43: 0=숫자, 1=원숫자, 8=가나다, 12=일이삼, 13=一二三 등) */\n numberFormats: number[]\n /** 수준별 시작 번호 (5.0.2.5+, 기본 1) */\n startNumbers: number[]\n}\n\n/** DocInfo BULLET — 글머리표 문자 */\nexport interface HwpBullet {\n /** 글머리표 문자 (PUA 가능 — 출력 시 mapPuaText로 정규화됨), U+FFFF=이미지 글머리표 */\n char: string\n}\n\n/** DocInfo에서 추출한 글자 모양 (CHAR_SHAPE) */\nexport interface HwpCharShape {\n /** 글꼴 크기 (단위: 0.1pt, 예: 100 = 10pt) */\n fontSize: number\n /**\n * 속성 플래그 (HWP5 바이너리 스펙 1.1 기준):\n * bit 0 = italic, bit 1 = bold, bit 2 = underline, bit 3 = outline\n * 검증 완료: 공식 스펙 + pyhwp/hwp.js 등 오픈소스 파서와 일치 (v1.7)\n */\n attrFlags: number\n}\n\n/** DocInfo에서 추출한 스타일 */\nexport interface HwpStyle {\n name: string\n /** 한글 이름 (UTF-16LE) */\n nameKo: string\n /** 연결된 charShape 인덱스 */\n charShapeId: number\n /** 연결된 paraShape 인덱스 */\n paraShapeId: number\n /** 스타일 타입: 0=paragraph, 1=character */\n type: number\n}\n\n/** DocInfo 파싱 결과 */\nexport interface HwpDocInfo {\n charShapes: HwpCharShape[]\n paraShapes: HwpParaShape[]\n styles: HwpStyle[]\n /** BIN_DATA 항목 (1-based binDataId → binData[id-1]) */\n binData: HwpBinDataItem[]\n /** NUMBERING 정의 (1-based numberingId → numberings[id-1]) */\n numberings: HwpNumbering[]\n /** BULLET 정의 (1-based bulletId → bullets[id-1]) */\n bullets: HwpBullet[]\n /** BORDER_FILL 의 보이는 변 (1-based borderFillId → borderEdges[id-1]) — 보이지 않는 틀 표 풀기 (v4.17.0) */\n borderEdges: Edges[]\n}\n\n/** length-prefixed UTF-16LE 문자열 읽기 (HWP WCHAR 배열) */\nfunction readHwpString(data: Buffer, offset: number): { value: string; next: number } {\n if (offset + 2 > data.length) return { value: \"\", next: data.length }\n const len = data.readUInt16LE(offset)\n const start = offset + 2\n const end = start + len * 2\n if (len === 0 || end > data.length) return { value: \"\", next: start }\n return { value: data.subarray(start, end).toString(\"utf16le\"), next: end }\n}\n\n/** FILETIME(1601년부터 100ns) → 한글처럼 지역 시각에 Z 를 붙인 꼴 (메모 만든 시각 — HWPX CreateDateTime 과 같은 꼴) */\nexport function fileTimeText(low: number, high: number): string {\n const d = new Date(Number((BigInt(high) * 2n ** 32n + BigInt(low)) / 10000n) - 11644473600000)\n const p2 = (n: number): string => String(n).padStart(2, \"0\")\n return `${d.getFullYear()}-${p2(d.getMonth() + 1)}-${p2(d.getDate())}T${p2(d.getHours())}:${p2(d.getMinutes())}:${p2(d.getSeconds())}Z`\n}\n\n/** DocInfo 레코드들에서 스타일 정보 추출 */\nexport function parseDocInfo(records: HwpRecord[]): HwpDocInfo {\n const charShapes: HwpCharShape[] = []\n const paraShapes: HwpParaShape[] = []\n const styles: HwpStyle[] = []\n const binData: HwpBinDataItem[] = []\n const numberings: HwpNumbering[] = []\n const bullets: HwpBullet[] = []\n const borderEdges: Edges[] = []\n\n for (const rec of records) {\n // BORDER_FILL — 속성 u16@0 · 변 4개(왼/오/위/아래) @2+6k = 종류 u8(0 없음) · 굵기 u8 · COLORREF u32 (render/hwp5-scene 과 같은 해독).\n // 흰 선(0xFFFFFF)은 흰 바탕에 안 보인다\n if (rec.tagId === TAG_BORDER_FILL) {\n const seen = (k: number): boolean => {\n const o = 2 + 6 * k\n return rec.data.length >= o + 6 && rec.data[o] !== 0 && (rec.data.readUInt32LE(o + 2) & 0xffffff) !== 0xffffff\n }\n borderEdges.push({ l: seen(0), r: seen(1), t: seen(2), b: seen(3) })\n }\n\n // PARA_SHAPE — 문단 모양 (rhwp doc_info.rs parse_para_shape)\n // attr1(u32@0) 비트 팩: bits 23-24 = 머리 종류, bits 25-27 = 문단 수준\n // numberingId: u16@30 (attr1 4 + 여백/간격 i32*6 = 24 + tabDefId 2 → offset 30)\n if (rec.tagId === TAG_DOC_PARA_SHAPE && rec.data.length >= 4) {\n const attr1 = rec.data.readUInt32LE(0)\n const headType = (attr1 >>> 23) & 0x03\n const paraLevel = (attr1 >>> 25) & 0x07\n const numberingId = rec.data.length >= 32 ? rec.data.readUInt16LE(30) : 0\n paraShapes.push({ headType, paraLevel, numberingId })\n }\n\n // BIN_DATA — binDataId(레코드 순서 1-based) → 스토리지 ID(16진)/확장자 매핑\n // (rhwp doc_info.rs parse_bin_data: attr u16 → type/compression/status)\n if (rec.tagId === TAG_BIN_DATA && rec.data.length >= 2) {\n const attr = rec.data.readUInt16LE(0)\n const typeBits = attr & 0x000f\n if (typeBits === 0) {\n // link: absPath + relPath (외부 파일 — 스토리지 없음)\n binData.push({ kind: \"link\", storageId: 0, extension: \"\" })\n } else {\n const storageId = rec.data.length >= 4 ? rec.data.readUInt16LE(2) : 0\n const { value: extension } = readHwpString(rec.data, 4)\n binData.push({ kind: typeBits === 2 ? \"storage\" : \"embed\", storageId, extension })\n }\n }\n\n // NUMBERING — 문단 번호 정의 (rhwp doc_info.rs parse_numbering, HWP 표 40/41)\n if (rec.tagId === TAG_NUMBERING && rec.data.length >= 14) {\n const levelFormats: string[] = []\n const numberFormats: number[] = []\n const startNumbers: number[] = [1, 1, 1, 1, 1, 1, 1]\n let offset = 0\n for (let level = 0; level < 7; level++) {\n if (offset + 12 > rec.data.length) {\n levelFormats.push(\"\")\n numberFormats.push(0)\n continue\n }\n // 문단 머리 정보(12B): attr(u32) + widthAdjust(i16) + textDistance(i16) + charShapeId(u32)\n const attr = rec.data.readUInt32LE(offset)\n numberFormats.push((attr >>> 5) & 0x0f)\n offset += 12\n // 번호 형식 문자열 (가변)\n const { value, next } = readHwpString(rec.data, offset)\n levelFormats.push(value)\n offset = next\n }\n // 시작 번호 (u16) + 수준별 시작 번호 (5.0.2.5+, u32×7)\n let baseStart = 1\n if (offset + 2 <= rec.data.length) {\n baseStart = rec.data.readUInt16LE(offset) || 1\n offset += 2\n }\n for (let level = 0; level < 7; level++) {\n if (offset + 4 <= rec.data.length) {\n startNumbers[level] = rec.data.readUInt32LE(offset) || 1\n offset += 4\n } else {\n startNumbers[level] = baseStart\n }\n }\n numberings.push({ levelFormats, numberFormats, startNumbers })\n }\n\n // BULLET — 글머리표 (rhwp doc_info.rs parse_bullet, HWP 표 44)\n // 머리 정보(12B) 다음 WCHAR가 글머리표 문자\n if (rec.tagId === TAG_BULLET && rec.data.length >= 14) {\n const code = rec.data.readUInt16LE(12)\n bullets.push({ char: code > 0 ? String.fromCharCode(code) : \"•\" })\n }\n\n if (rec.tagId === TAG_DOC_CHAR_SHAPE && rec.data.length >= 18) {\n // HWP5 CHAR_SHAPE 구조 (바이너리 스펙 1.1 기준):\n // faceId: 7개 언어 * u16 = 14바이트 (offset 0-13)\n // ratio: 7개 언어 * u8 = 7바이트 (offset 14-20)\n // spacing: 7개 언어 * s8 = 7바이트 (offset 21-27)\n // relSize: 7개 언어 * u8 = 7바이트 (offset 28-34)\n // charOffset: 7개 언어 * s8 = 7바이트 (offset 35-41)\n // baseSize: u32 at offset 42 (단위: 0.1pt)\n // attrFlags: u32 at offset 46 (bit0=italic, bit1=bold) — 공식 스펙 검증 완료\n if (rec.data.length >= 50) {\n const fontSize = rec.data.readUInt32LE(42) // 단위: 0.1pt\n const attrFlags = rec.data.readUInt32LE(46)\n charShapes.push({ fontSize, attrFlags })\n } else {\n // 짧은 레코드 — 스타일 정보 없음\n charShapes.push({ fontSize: 0, attrFlags: 0 })\n }\n }\n\n if (rec.tagId === TAG_DOC_STYLE && rec.data.length >= 8) {\n try {\n // STYLE 구조: nameLen(u16) + name(UTF-16LE) + nameKoLen(u16) + nameKo(UTF-16LE)\n // + type(u8) + nextStyleId(u16) + langId(s16) + paraShapeId(u16) + charShapeId(u16)\n let offset = 0\n const nameLen = rec.data.readUInt16LE(offset); offset += 2\n const nameBytes = nameLen * 2\n const name = nameBytes > 0 && offset + nameBytes <= rec.data.length\n ? rec.data.subarray(offset, offset + nameBytes).toString(\"utf16le\")\n : \"\"\n offset += nameBytes\n\n let nameKo = \"\"\n if (offset + 2 <= rec.data.length) {\n const nameKoLen = rec.data.readUInt16LE(offset); offset += 2\n const nameKoBytes = nameKoLen * 2\n if (nameKoBytes > 0 && offset + nameKoBytes <= rec.data.length) {\n nameKo = rec.data.subarray(offset, offset + nameKoBytes).toString(\"utf16le\")\n }\n offset += nameKoBytes\n }\n\n // type(u8) + nextStyleId(u8) + langId(s16) + paraShapeId(u16) + charShapeId(u16)\n // 주의: nextStyleId는 스펙상 BYTE — 2바이트 스킵하면 paraShapeId가 256배수로 깨짐 (off-by-one 버그 수정)\n const type = offset < rec.data.length ? rec.data.readUInt8(offset) : 0; offset += 1\n offset += 1 // nextStyleId (BYTE)\n offset += 2 // langId\n const paraShapeId = offset + 2 <= rec.data.length ? rec.data.readUInt16LE(offset) : 0; offset += 2\n const charShapeId = offset + 2 <= rec.data.length ? rec.data.readUInt16LE(offset) : 0\n\n styles.push({ name, nameKo, charShapeId, paraShapeId, type })\n } catch {\n // 파싱 실패 — 스킵\n }\n }\n }\n\n return { charShapes, paraShapes, styles, binData, numberings, bullets, borderEdges }\n}\n\n// ─── UTF-16LE 텍스트 추출 (21가지 제어문자 처리) ─────\n\nexport type InlineControlResolver = (ctrlId: string) => string | null | undefined\n\n/**\n * 확장 컨트롤(CTRL_HEADER 보유) 기반 인라인 치환 콜백.\n * - ctrlIdx: 문단 내 확장 컨트롤 등장 순서 (0-based, CTRL_HEADER 자식 레코드 순서와 1:1)\n * - ctrlId: u32 정규화 ID — 파일의 LE DWORD를 그대로 읽은 값 (\"tbl \" → 0x74626c20)\n * 인라인 컨트롤(4-9, 19-20 — CTRL_HEADER 없음)은 ctrlIdx = -1로 호출된다.\n */\nexport type IndexedControlResolver = (ctrlIdx: number, ctrlId: number) => string | null | undefined\n\n/** FIELD_BEGIN(0x03)/FIELD_END(0x04) 스택 페어링으로 복원한 필드 anchor 범위 */\nexport interface HwpFieldRange {\n /** state.text 기준 시작 인덱스 */\n start: number\n /** state.text 기준 끝 인덱스 (exclusive) */\n end: number\n /** FIELD_BEGIN 컨트롤의 확장 컨트롤 인덱스 (CTRL_HEADER 순서) */\n ctrlIdx: number\n}\n\n/** 문단 단위 PARA_TEXT 누적 상태 — 여러 PARA_TEXT 레코드에 걸친 컨트롤 인덱스/필드 스택 유지 */\nexport interface ParaTextState {\n text: string\n ctrlIdx: number\n fieldStack: Array<{ start: number; ctrlIdx: number }>\n fieldRanges: HwpFieldRange[]\n /** 레코드 끝 상위 서로게이트 반쪽과 □ 로 낸 자리 — 다음 레코드 첫 하위 반쪽과 한 글자로 되돌린다 */\n loneHigh?: number\n loneHighAt?: number\n /** 리터럴 \"$\"·\"<\" 를 LITERAL_DOLLAR_MARK·LITERAL_LT_MARK 한 글자로 — 본문 파서만 켠다. 필드 범위가 글자 위치라\n * 두 글자 \"\\$\" 를 바로 넣지 않고, 필드 처리 뒤 본문 파서가 \"\\$\" 로 바꾼다(escapeLiteralDollar 규약) */\n dollarMark?: boolean\n /** 채움 탭을 TOC_LEADER 표지로 — 본문 파서만 켜고 문단 글을 다 모은 뒤 takeTocLeaders 로 보통 탭이 된다 */\n tocLeaders?: boolean\n /** 글자 위치(문단 WCHAR 순번)의 첨자 종류 — 문단 글자 모양(PARA_CHAR_SHAPE) 위치표로 본문 파서가 채운다.\n * 있으면 첨자 글자를 <sup>·<sub> 로 감싼다(제어 문자·개체 자리에서는 닫는다) */\n scriptAt?: (pos: number) => ScriptKind | null\n /** 지금 열린 첨자 태그 */\n script?: ScriptKind | null\n /** 글자 위치(문단 WCHAR 순번)의 강조 키(굵게·기울임·취소선·밑줄 비트) — 있으면 보이는 글자마다 키가 바뀌는 자리를\n * emphRuns 에 [state.text 위치, 키] 로 적는다(본문 파서가 인라인 강조 span 을 만든다) */\n emphAt?: (pos: number) => number\n emphRuns?: Array<[number, number]>\n /** 앞 PARA_TEXT 레코드까지의 WCHAR 수 — 글자 모양 위치는 문단 전체 기준 */\n wpos?: number\n}\n\n/** 리터럴 \"$\" 표지 (dollarMark) — 유니코드 비문자라 문서 글에 나오지 않는다 */\nexport const LITERAL_DOLLAR_MARK = \"\\uFDD0\"\n/** 리터럴 \"<\" 표지 (dollarMark 와 함께) — 첨자 태그(scriptAt)와 원문 글자 \"<sub>\" 를 가른다 (#122, escapeLiteralTags) */\nexport const LITERAL_LT_MARK = \"\\uFDD1\"\nconst LITERAL_LT_TAG = /\\uFDD1(?=\\/?(?:u|sup|sub)>)/g\n\n/** 필드 처리 뒤 리터럴 \"<\" 표지를 글로 — 태그 모양(\"<sub>\"·\"</sup>\"·\"<u>\")이면 \\<, 아니면 < (escapeLiteralTags 규약) */\nexport function resolveLiteralLt(text: string): string {\n return text.includes(LITERAL_LT_MARK) ? text.replace(LITERAL_LT_TAG, \"\\\\<\").replaceAll(LITERAL_LT_MARK, \"<\") : text\n}\n\nexport function createParaTextState(): ParaTextState {\n return { text: \"\", ctrlIdx: 0, fieldStack: [], fieldRanges: [] }\n}\n\nexport function extractText(data: Buffer): string {\n return extractTextWithControls(data)\n}\n\n/** 레거시 인터페이스 — ctrlId를 on-disk 바이트 순서 ASCII 문자열로 받는 resolver */\nexport function extractTextWithControls(data: Buffer, resolveControl?: InlineControlResolver): string {\n const state = createParaTextState()\n appendParaText(state, data, resolveControl\n ? (_idx, id) => resolveControl(ctrlIdToDiskAscii(id))\n : undefined)\n return state.text\n}\n\n/** u32 컨트롤 ID → on-disk 바이트 순서 ASCII (LE 저장이므로 역순 문자열, 예: 0x74626c20 → \" lbt\") */\nfunction ctrlIdToDiskAscii(id: number): string {\n return String.fromCharCode(id & 0xff, (id >>> 8) & 0xff, (id >>> 16) & 0xff, (id >>> 24) & 0xff)\n}\n\n/** 한컴 PUA-A 접힘 영역 — HWP5 WCHAR 의 U+A000~U+A48C(이 글자 음절) ↔ U+F0000~U+F048C. 관찰 범위만 (v4.12.2) */\nconst HANCOM_FOLDED_PUA_START = 0xa000\nconst HANCOM_FOLDED_PUA_END = 0xa48c\nconst HANCOM_FOLDED_PUA_SHIFT = 0xf0000 - 0xa000\n\n/** 확장 전용 컨트롤 문자 (CTRL_HEADER 자식 레코드 1개와 대응) — rhwp is_extended_only_ctrl_char */\nexport function isExtendedOnlyCtrlChar(ch: number): boolean {\n return (ch >= 1 && ch <= 3) || (ch >= 11 && ch <= 12) || (ch >= 14 && ch <= 18) || (ch >= 21 && ch <= 23)\n}\n\n/**\n * PARA_TEXT 레코드 1개를 상태에 누적.\n * 텍스트 추출 + 확장 컨트롤 인라인 치환 + FIELD_BEGIN/END 범위 추적을 동시에 수행한다.\n */\nexport function appendParaText(state: ParaTextState, data: Buffer, resolveControl?: IndexedControlResolver): void {\n let result = \"\"\n let i = 0\n const wbase = state.wpos ?? 0\n // 첨자 태그 전환 — 보이는 글자 앞에서 그 자리 글자 모양대로 열고, 제어 문자 앞에서는 닫는다\n const setScript = (want: ScriptKind | null): void => {\n const cur = state.script ?? null\n if (cur === want) return\n if (cur) result += `</${cur}>`\n if (want) result += `<${want}>`\n state.script = want\n }\n // 앞 레코드 끝의 상위 반쪽(□ 로 냈다)과 이 레코드 첫 하위 반쪽은 한 글자 — 문단 글이 여러 레코드로 나뉜 자리\n if (state.loneHighAt !== undefined) {\n const lo = data.length >= 2 ? data.readUInt16LE(0) : 0\n if (lo >= 0xdc00 && lo <= 0xdfff && state.loneHighAt === state.text.length - 1) {\n state.text = state.text.slice(0, -1) + String.fromCharCode(state.loneHigh!, lo)\n i = 2\n }\n state.loneHighAt = undefined\n }\n // 필드 범위는 state.text 기준 인덱스로 기록\n const base = state.text.length\n\n const resolveAt = (byteOffset: number, extended: boolean): void => {\n const ctrlId = data.readUInt32LE(byteOffset)\n const idx = extended ? state.ctrlIdx : -1\n const replacement = resolveControl?.(idx, ctrlId)\n if (replacement) result += replacement\n if (extended) state.ctrlIdx++\n }\n\n while (i + 1 < data.length) {\n const ch = data.readUInt16LE(i)\n // 첨자 태그는 강조 경계를 사이에 두고 닫고 연다 — 닫는 태그는 앞 강조 span, 여는 태그는 새 span 에 들어야 span 마다 태그 짝이\n // 맞는다(종전엔 닫는 태그가 경계 뒤로 가 \"확충<sup>*</sup> 및\" 의 강조가 문단째 버려졌다)\n const script = state.scriptAt ? (ch >= 0x0020 ? state.scriptAt(wbase + i / 2) : null) : undefined\n if (script !== undefined && state.script && state.script !== script) setScript(null)\n if (state.emphAt && ch >= 0x0020) {\n const key = state.emphAt(wbase + i / 2), runs = (state.emphRuns ??= [])\n if (runs.length === 0 || runs[runs.length - 1][1] !== key) runs.push([base + result.length, key])\n }\n if (script !== undefined) setScript(script)\n i += 2\n\n switch (ch) {\n // ── char 타입 (2바이트만, 확장 데이터 없음) ──\n case CHAR_LINE: result += \"\\n\"; break\n case CHAR_SECTION_BREAK: { // 강제 줄 나눔(char 2바이트). 단, 뒤에 0x000b 수식 래퍼가 오는 경우만 확장 처리\n // 일부 HWP5 문서는 수식 placeholder를 0x000a + 0x000b + ctrlId + payload + 0x000b로 저장한다.\n if (i + 16 <= data.length && data.readUInt16LE(i) === 0x000b) {\n resolveAt(i + 2, true)\n i += 16\n break\n }\n // bare 0x000a = char 타입 줄바꿈(2바이트, 확장 데이터 없음) — 뒤 14바이트 소비 금지(줄마다 7글자 증발 버그).\n result += \"\\n\"\n break\n }\n case CHAR_PARA: break // 문단 끝\n // 하이픈(24)은 한컴이 그리지 않는다 — 한컴 PDF·rhwp export-hwpx 모두 \"60g/㎡\"(licbyl2 17855137,\n // 전 코퍼스 유일 출현). 실렌더가 진실이므로 방출하지 않는다 (v4.12.3, 종전 \"-\")\n case CHAR_HYPHEN: break\n case CHAR_NBSP: result += \"\\u00a0\"; break // 진짜 NBSP\n case CHAR_FIXED_WIDTH: result += \" \"; break // 고정폭 공백\n\n // ── inline 타입 (2바이트 + 14바이트 확장) ──\n // 확장 u16[7] 중 [2] 의 하위 바이트 = 채움 모양(0 없음·3 점선 …), 상위 = 탭 종류+1 (rhwp tab_extended 실측).\n // 채움 탭도 보통 탭 — 채움선은 글이 아니고 뒤 글(목차 쪽 번호 등)은 남긴다 (HWPX section-walker \"tab\" 과 같은 정책)\n // 본문 파서(tocLeaders)는 목차 항목 판정까지 채움 탭을 TOC_LEADER 표지로 받는다 (#121)\n case CHAR_TAB:\n result += state.tocLeaders && i + 6 <= data.length && (data.readUInt16LE(i + 4) & 0xff) !== 0 ? TOC_LEADER : \"\\t\"\n if (i + 14 <= data.length) i += 14\n break\n\n default:\n if (ch >= 0x0001 && ch <= 0x001f) {\n // rhwp 기준 3-카테고리 분류:\n // extended(1-3, 11-12, 14-18, 21-23) + inline(4-9, 19-20) → 14바이트 스킵\n // char(24-31) → 스킵 없음 (24,30,31은 switch에서 처리, 25-29는 예약 — 출력 없이 통과)\n const isExtended = isExtendedOnlyCtrlChar(ch)\n const isInline = (ch >= 4 && ch <= 9) || (ch >= 19 && ch <= 20)\n if ((isExtended || isInline) && i + 14 <= data.length) {\n if (ch === 0x0003) {\n // FIELD_BEGIN: anchor 시작 위치 + 컨트롤 인덱스 push\n state.fieldStack.push({ start: base + result.length, ctrlIdx: state.ctrlIdx })\n } else if (ch === 0x0004) {\n // FIELD_END: 스택 페어링 → anchor 범위 확정\n const open = state.fieldStack.pop()\n if (open) {\n state.fieldRanges.push({ start: open.start, end: base + result.length, ctrlIdx: open.ctrlIdx })\n }\n }\n resolveAt(i, isExtended)\n i += 14\n }\n } else if (ch >= 0x0020) {\n // HWP5 문자는 2바이트 WCHAR 라 한컴 Supplementary PUA-A(U+F0000대) 기호를 담을 수 없다 —\n // 한컴은 U+A000 + (code − 0xF0000) 으로 접어 저장한다(이 글자 음절 블록, 한국어 문서에는\n // 안 나온다). 결재란 \"(인)\"(F012B)이 A12B 로 들어 있는 법령 별지서식 실측 — rhwp export-hwpx\n // 도 같은 자리를 F012B→\"(인)\" 으로 복원한다. 펴서 mapPuaText(pua.ts) 표에 넘기고, 매핑 없는\n // 코드는 종전 PUA-A 정책(sanitizeText 제거)을 따른다 (v4.12.2)\n if (ch >= HANCOM_FOLDED_PUA_START && ch <= HANCOM_FOLDED_PUA_END) {\n result += String.fromCodePoint(ch + HANCOM_FOLDED_PUA_SHIFT)\n break\n }\n // UTF-16 surrogate pair 처리 (BMP 외 문자: 이모지, CJK 확장 등)\n if (ch >= 0xd800 && ch <= 0xdbff && i + 1 < data.length) {\n const lo = data.readUInt16LE(i)\n if (lo >= 0xdc00 && lo <= 0xdfff) {\n i += 2\n const codePoint = ((ch - 0xd800) << 10) + (lo - 0xdc00) + 0x10000\n result += String.fromCodePoint(codePoint)\n break\n }\n }\n // 짝 없는 서로게이트 반쪽 — 한글은 같은 자리를 □ 로 보여 주고 HWPX 로 저장할 때도 □ 를 쓴다. 반쪽을 그대로 내면\n // JSON 에 \\udfda 로 남고 UTF-8 로 쓰면 U+FFFD 가 된다 (rhwp cff474c8d #6873, 한글 HWPX 정본 대조). 레코드 끝의 상위 반쪽은\n // 자리를 남겨 다음 PARA_TEXT 레코드가 하위 반쪽으로 시작하면 한 글자로 되돌린다\n if (ch >= 0xd800 && ch <= 0xdfff) {\n result += \"\\u25a1\"\n if (ch <= 0xdbff && i >= data.length) { state.loneHigh = ch; state.loneHighAt = base + result.length - 1 }\n break\n }\n result += !state.dollarMark ? String.fromCharCode(ch) : ch === 0x24 ? LITERAL_DOLLAR_MARK : ch === 0x3c ? LITERAL_LT_MARK : String.fromCharCode(ch)\n }\n break\n }\n }\n\n if (state.scriptAt) setScript(null)\n state.wpos = wbase + Math.floor(data.length / 2)\n state.text += result\n}\n\n/** HWP5 EQEDIT(0x58) 레코드에서 한글 수식 스크립트 원문 추출 */\nexport function extractEquationText(data: Buffer): string | null {\n if (data.length < 6) return null\n\n const scriptLength = data.readUInt16LE(4)\n const scriptStart = 6\n const scriptEnd = scriptStart + scriptLength * 2\n if (scriptLength <= 0 || scriptEnd > data.length) return null\n\n const equation = data.subarray(scriptStart, scriptEnd).toString(\"utf16le\").replace(/\\0+/g, \"\").trim()\n return equation || null\n}\n","/**\n * HWP5 BinData 이미지 추출.\n *\n * - DocInfo BIN_DATA의 binDataId(1-based) → storage_id 매핑은 parser.ts(pictureToImageBlock)에서 수행\n * - 이 모듈은 BinData 스토리지 엔트리(\"BIN%04X.ext\" — storage_id는 16진!)를 storageId 키로 수집하고\n * 블록 트리(셀 내부 blocks 포함)의 image 블록과 매칭해 ExtractedImage로 변환한다.\n */\n\nimport { decompressStream } from \"./record.js\"\nimport type { LenientCfbContainer } from \"./cfb-lenient.js\"\nimport type { ExtractedImage, IRBlock, ParseWarning } from \"../types.js\"\n\n/** CFB FileIndex 엔트리 (cfb 모듈 호환 최소 형태) */\nexport interface BinCfbEntry { name?: string; content?: Buffer | Uint8Array }\n\n/** MIME 타입 매직바이트 판별 */\nexport function detectImageMime(data: Buffer | Uint8Array): string | null {\n if (data.length < 4) return null\n if (data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47) return \"image/png\"\n if (data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff) return \"image/jpeg\"\n if (data[0] === 0x47 && data[1] === 0x49 && data[2] === 0x46) return \"image/gif\"\n if (data[0] === 0x42 && data[1] === 0x4d) return \"image/bmp\"\n if (data[0] === 0xd7 && data[1] === 0xcd && data[2] === 0xc6 && data[3] === 0x9a) return \"image/wmf\"\n // 배치 헤더 없는 표준 WMF — mtType 1(메모리)·2(디스크) + mtHeaderSize 9워드. 한컴 BinData 의 .wmf 는 대개 이 꼴\n // (법령 서식 BIN0001.wmf 실측 01 00 09 00 00 03). 종전엔 \"알 수 없는 형식\"이라 셀에 [이미지: …] 글이 박혔다\n if ((data[0] === 0x01 || data[0] === 0x02) && data[1] === 0x00 && data[2] === 0x09 && data[3] === 0x00) return \"image/wmf\"\n if (data[0] === 0x01 && data[1] === 0x00 && data[2] === 0x00 && data[3] === 0x00) return \"image/emf\"\n // TIFF — 리틀(II*\\0)·빅(MM\\0*) 엔디언 (행정업무편람 BIN016C.TIF 실측)\n if ((data[0] === 0x49 && data[1] === 0x49 && data[2] === 0x2a && data[3] === 0x00) || (data[0] === 0x4d && data[1] === 0x4d && data[2] === 0x00 && data[3] === 0x2a)) return \"image/tiff\"\n return null\n}\n\n/** MIME → 추출 파일 확장자 (HWPX images.ts mimeToExt 와 같은 표) */\nfunction mimeExt(mime: string): string {\n if (mime.includes(\"jpeg\")) return \"jpg\"\n if (mime.includes(\"png\")) return \"png\"\n if (mime.includes(\"gif\")) return \"gif\"\n if (mime.includes(\"bmp\")) return \"bmp\"\n if (mime.includes(\"tiff\")) return \"tif\"\n if (mime.includes(\"wmf\")) return \"wmf\"\n if (mime.includes(\"emf\")) return \"emf\"\n return \"bin\"\n}\n\n/**\n * BinData 페이로드 정규화 — 항목별 압축 플래그가 문서 압축 플래그와 다를 수 있으므로\n * 매직바이트가 안 보이면 압축 해제를 시도하고, 실패하면 원본 유지.\n */\nfunction normalizeBinPayload(data: Buffer): Buffer {\n if (detectImageMime(data)) return data\n try {\n const inflated = decompressStream(data)\n if (inflated.length > 0) return inflated\n } catch { /* 비압축 데이터 */ }\n return data\n}\n\n/** BinData 스토리지 엔트리명 — \"BIN%04X.ext\" (storage_id는 16진!) */\nconst BIN_ENTRY_RE = /(?:^|\\/)BIN([0-9A-Fa-f]{4,8})(?:\\.[^./\\\\]*)?$/\n\n/** 블록 트리 재귀 깊이 상한 — hwpx collectImageBlocks(MAX_XML_DEPTH)와 동일 값.\n * 손상/악성 문서의 자기참조·초심층 트리 스택 오버플로 방지 */\nconst MAX_BLOCK_DEPTH = 200\n\n/** 블록 트리(셀 내부 blocks 포함)에서 image 블록 수집.\n * hwpx 쪽과 안전장치 합집합: depth 가드 + children 순회 (둘 다 수행) */\nfunction collectImageBlocks(blocks: IRBlock[], out: IRBlock[], depth = 0): void {\n if (depth > MAX_BLOCK_DEPTH) return\n for (const b of blocks) {\n if (b.type === \"image\") out.push(b)\n if (b.table) {\n for (const row of b.table.cells) {\n for (const cell of row) {\n if (cell.blocks) collectImageBlocks(cell.blocks, out, depth + 1)\n }\n }\n }\n if (b.children) collectImageBlocks(b.children, out, depth + 1)\n }\n}\n\n/**\n * 이미지 sentinel(\"![image](hwp5bin:ID)\")을 추출된 파일명으로 치환 — 표 셀 텍스트, 그리고 머리말·각주·캡션처럼\n * 표를 평문으로 편 글(ir-assemble tableFlatText)에도 남으므로 블록 트리 전체(문단 글·각주·캡션·셀)를 훑는다.\n * 파일명이 없으면(BinData 없음·페이지 필터로 스윕 안 함) \"[이미지]\"\n */\nconst IMAGE_SENTINEL_RE = /!\\[image\\]\\(hwp5bin:(\\d+)\\)/g\nfunction resolveImageSentinels(blocks: IRBlock[], renamed: Map<number, string>, depth = 0): void {\n if (depth > MAX_BLOCK_DEPTH) return\n const fix = (s: string): string => s.includes(\"hwp5bin:\")\n ? s.replace(IMAGE_SENTINEL_RE, (_m, idStr: string) => {\n const filename = renamed.get(Number(idStr))\n return filename ? `![image](${filename})` : \"[이미지]\"\n })\n : s\n for (const b of blocks) {\n if (b.text) b.text = fix(b.text)\n if (b.footnoteText) b.footnoteText = fix(b.footnoteText)\n if (b.table) {\n if (b.table.caption) b.table.caption = fix(b.table.caption)\n for (const row of b.table.cells) {\n for (const cell of row) {\n cell.text = fix(cell.text)\n if (cell.blocks) resolveImageSentinels(cell.blocks, renamed, depth + 1)\n }\n }\n }\n if (b.children) resolveImageSentinels(b.children, renamed, depth + 1)\n if (b.footnoteBlocks) resolveImageSentinels(b.footnoteBlocks, renamed, depth + 1)\n }\n}\n\n/** binDataMap 기반 이미지 블록 해결 — strict/lenient·HWP3 공용 */\nexport function resolveImageBlocks(\n binDataMap: Map<number, { data: Buffer; name: string }>,\n blocks: IRBlock[],\n warnings: ParseWarning[],\n sweepUnreferenced?: boolean,\n): ExtractedImage[] {\n const imageBlocks: IRBlock[] = []\n collectImageBlocks(blocks, imageBlocks)\n\n const images: ExtractedImage[] = []\n const renamed = new Map<number, string>()\n // 같은 BinData를 참조하는 개체가 수천 개일 수 있다(도형 반복 등) — storageId당\n // 1회만 변환·추출하고 데이터 버퍼를 공유한다 (블록마다 복사하면 메모리 폭발)\n const resolved = new Map<number, { filename: string; data: Uint8Array; mime: string } | null>()\n let imageIndex = 0\n\n for (const block of imageBlocks) {\n if (!block.text) continue\n const storageId = parseInt(block.text, 10)\n if (isNaN(storageId)) continue\n\n let img = resolved.get(storageId)\n if (img === undefined) {\n const bin = binDataMap.get(storageId)\n if (!bin) {\n warnings.push({ page: block.pageNumber, message: `BinData ${storageId} 없음`, code: \"SKIPPED_IMAGE\" })\n resolved.set(storageId, null)\n } else {\n const mime = detectImageMime(bin.data)\n if (!mime) {\n warnings.push({ page: block.pageNumber, message: `BinData ${storageId}: 알 수 없는 이미지 형식`, code: \"SKIPPED_IMAGE\" })\n resolved.set(storageId, null)\n } else {\n imageIndex++\n const ext = mimeExt(mime)\n img = { filename: `image_${String(imageIndex).padStart(3, \"0\")}.${ext}`, data: new Uint8Array(bin.data), mime }\n resolved.set(storageId, img)\n images.push({ filename: img.filename, data: img.data, mimeType: img.mime, source: bin.name })\n renamed.set(storageId, img.filename)\n }\n }\n img = resolved.get(storageId)\n }\n\n if (!img) {\n const bin = binDataMap.get(storageId)\n block.type = \"paragraph\"\n block.text = bin ? `[이미지: ${bin.name}]` : `[이미지: BinData ${storageId}]`\n continue\n }\n block.text = img.filename\n block.imageData = { data: img.data, mimeType: img.mime, filename: binDataMap.get(storageId)!.name }\n }\n\n // 본문 미참조 BinData 이미지 스윕 — pic 컨트롤이 닿지 않는 이미지(셀 배경 등)를\n // 문서 끝에 image 블록으로 보강한다. 이미지가 아닌 스트림(OLE 등)은 건너뛴다.\n if (sweepUnreferenced) {\n for (const [storageId, bin] of [...binDataMap.entries()].sort((a, b) => a[0] - b[0])) {\n if (resolved.has(storageId)) continue\n const mime = detectImageMime(bin.data)\n if (!mime) continue\n imageIndex++\n const ext = mimeExt(mime)\n const filename = `image_${String(imageIndex).padStart(3, \"0\")}.${ext}`\n const data = new Uint8Array(bin.data)\n images.push({ filename, data, mimeType: mime, source: bin.name })\n blocks.push({ type: \"image\", text: filename, imageData: { data, mimeType: mime, filename: bin.name } })\n // 머리말·각주 안 표를 편 글의 sentinel 도 이 파일을 가리킨다 (본문 image 블록이 없던 그림)\n renamed.set(storageId, filename)\n }\n }\n\n resolveImageSentinels(blocks, renamed)\n return images\n}\n\n/** BinData 스토리지의 모든 파일을 FileIndex 순회로 수집 — 엔트리명은 \"BIN%04X.ext\" 16진.\n * 파서(이미지 추출)와 렌더 어댑터(#75 HWP5)가 공유한다 */\nexport function collectHwp5BinData(fileIndex: BinCfbEntry[] | undefined, readStream?: (path: string) => Buffer | null): Map<number, { data: Buffer; name: string }> {\n const binDataMap = new Map<number, { data: Buffer; name: string }>()\n if (fileIndex) {\n for (const entry of fileIndex) {\n if (!entry?.name || !entry.content) continue\n const match = entry.name.match(BIN_ENTRY_RE)\n if (!match) continue\n const idx = parseInt(match[1], 16)\n const raw = readStream ? readStream(`/BinData/${entry.name}`) : Buffer.from(entry.content)\n if (!raw) continue\n const data = normalizeBinPayload(raw)\n binDataMap.set(idx, { data, name: entry.name })\n }\n }\n return binDataMap\n}\n\n/** Lenient CFB: BinData 엔트리 수집 — 엔트리명 \"BIN%04X.ext\" 16진 */\nexport function collectHwp5BinDataLenient(lcfb: LenientCfbContainer, readStream = lcfb.findStream): Map<number, { data: Buffer; name: string }> {\n const binDataMap = new Map<number, { data: Buffer; name: string }>()\n const binRe = /^BIN([0-9A-Fa-f]{4,8})(?:\\.|$)/\n for (const e of lcfb.entries()) {\n const match = e.name.match(binRe)\n if (!match) continue\n const idx = parseInt(match[1], 16)\n // 경로로 찾는다 — 맨 이름은 같은 이름이 둘이면 고르지 않는다 (cfb-lenient findEntryByPath)\n const raw = readStream(`/BinData/${e.name}`) ?? readStream(e.name)\n if (!raw) continue\n binDataMap.set(idx, { data: normalizeBinPayload(raw), name: e.name })\n }\n return binDataMap\n}\n\n/** OLE2 BinData 스토리지(FileIndex)에서 이미지 추출, blocks의 image 블록과 매핑 */\nexport function extractHwp5Images(\n fileIndex: BinCfbEntry[] | undefined,\n blocks: IRBlock[],\n warnings: ParseWarning[],\n sweepUnreferenced?: boolean,\n readStream?: (path: string) => Buffer | null,\n): ExtractedImage[] {\n const binDataMap = collectHwp5BinData(fileIndex, readStream)\n\n if (binDataMap.size === 0) {\n // 이미지 블록이 있는데 BinData가 없으면 sentinel 정리만 수행\n resolveImageSentinels(blocks, new Map())\n return []\n }\n return resolveImageBlocks(binDataMap, blocks, warnings, sweepUnreferenced)\n}\n\n/** Lenient CFB: BinData 이미지 추출 */\nexport function extractHwp5ImagesLenient(\n lcfb: LenientCfbContainer,\n blocks: IRBlock[],\n warnings: ParseWarning[],\n sweepUnreferenced?: boolean,\n readStream?: (path: string) => Buffer | null,\n): ExtractedImage[] {\n const binDataMap = collectHwp5BinDataLenient(lcfb, readStream)\n if (binDataMap.size === 0) {\n resolveImageSentinels(blocks, new Map())\n return []\n }\n return resolveImageBlocks(binDataMap, blocks, warnings, sweepUnreferenced)\n}\n","/**\n * AES-128 ECB 순수 JS 구현 — 배포용 HWP 복호화 전용.\n * 외부 의존성 없음 (kordoc 제로 네이티브 의존성 원칙 유지).\n * 참조: rhwp (MIT) src/parser/crypto.rs + FIPS-197 (AES 표준)\n */\n\n// ── S-Box & 역 S-Box ──\n\nconst S_BOX = new Uint8Array([\n 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,\n 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,\n 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,\n 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,\n 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,\n 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,\n 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,\n 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,\n 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,\n 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,\n 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,\n 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,\n 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,\n 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,\n 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,\n 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,\n])\n\nconst INV_S_BOX = new Uint8Array([\n 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,\n 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,\n 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,\n 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,\n 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,\n 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,\n 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,\n 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,\n 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,\n 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,\n 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,\n 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,\n 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,\n 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,\n 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,\n 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d,\n])\n\n// ── RCON (라운드 상수) ──\n\nconst RCON = new Uint8Array([0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36])\n\n// ── GF(2^8) 곱셈 ──\n\nfunction gmul(a: number, b: number): number {\n let p = 0\n for (let i = 0; i < 8; i++) {\n if (b & 1) p ^= a\n const hi = a & 0x80\n a = (a << 1) & 0xff\n if (hi) a ^= 0x1b\n b >>= 1\n }\n return p\n}\n\n// ── 키 확장 (AES-128: 4 words → 44 words) ──\n\nfunction expandKey(key: Uint8Array): Uint32Array {\n const w = new Uint32Array(44)\n\n // 첫 4 words: 원본 키\n for (let i = 0; i < 4; i++) {\n w[i] = (key[4 * i] << 24) | (key[4 * i + 1] << 16) | (key[4 * i + 2] << 8) | key[4 * i + 3]\n }\n\n for (let i = 4; i < 44; i++) {\n let temp = w[i - 1]\n if (i % 4 === 0) {\n // RotWord + SubWord + RCON\n temp = ((temp << 8) | (temp >>> 24)) >>> 0\n temp = (S_BOX[(temp >>> 24) & 0xff] << 24) |\n (S_BOX[(temp >>> 16) & 0xff] << 16) |\n (S_BOX[(temp >>> 8) & 0xff] << 8) |\n S_BOX[temp & 0xff]\n temp = (temp ^ (RCON[i / 4 - 1] << 24)) >>> 0\n }\n w[i] = (w[i - 4] ^ temp) >>> 0\n }\n\n return w\n}\n\n// ── AES-128 단일 블록 복호화 (16바이트) ──\n\nfunction decryptBlock(block: Uint8Array, roundKeys: Uint32Array): Uint8Array {\n // state를 4x4 column-major 배열로 로드\n const s = new Uint8Array(16)\n for (let i = 0; i < 16; i++) s[i] = block[i]\n\n // AddRoundKey (round 10)\n addRoundKey(s, roundKeys, 10)\n\n // Rounds 9 → 1\n for (let round = 9; round >= 1; round--) {\n invShiftRows(s)\n invSubBytes(s)\n addRoundKey(s, roundKeys, round)\n invMixColumns(s)\n }\n\n // Final round (round 0)\n invShiftRows(s)\n invSubBytes(s)\n addRoundKey(s, roundKeys, 0)\n\n return s\n}\n\nfunction addRoundKey(s: Uint8Array, w: Uint32Array, round: number): void {\n const base = round * 4\n for (let c = 0; c < 4; c++) {\n const k = w[base + c]\n s[c * 4] ^= (k >>> 24) & 0xff\n s[c * 4 + 1] ^= (k >>> 16) & 0xff\n s[c * 4 + 2] ^= (k >>> 8) & 0xff\n s[c * 4 + 3] ^= k & 0xff\n }\n}\n\nfunction invSubBytes(s: Uint8Array): void {\n for (let i = 0; i < 16; i++) s[i] = INV_S_BOX[s[i]]\n}\n\nfunction invShiftRows(s: Uint8Array): void {\n // Row 0: no shift\n // Row 1: shift right 1\n let t = s[13]; s[13] = s[9]; s[9] = s[5]; s[5] = s[1]; s[1] = t\n // Row 2: shift right 2\n t = s[2]; s[2] = s[10]; s[10] = t\n t = s[6]; s[6] = s[14]; s[14] = t\n // Row 3: shift right 3 (= left 1)\n t = s[3]; s[3] = s[7]; s[7] = s[11]; s[11] = s[15]; s[15] = t\n}\n\nfunction invMixColumns(s: Uint8Array): void {\n for (let c = 0; c < 4; c++) {\n const i = c * 4\n const a0 = s[i], a1 = s[i + 1], a2 = s[i + 2], a3 = s[i + 3]\n s[i] = gmul(a0, 0x0e) ^ gmul(a1, 0x0b) ^ gmul(a2, 0x0d) ^ gmul(a3, 0x09)\n s[i + 1] = gmul(a0, 0x09) ^ gmul(a1, 0x0e) ^ gmul(a2, 0x0b) ^ gmul(a3, 0x0d)\n s[i + 2] = gmul(a0, 0x0d) ^ gmul(a1, 0x09) ^ gmul(a2, 0x0e) ^ gmul(a3, 0x0b)\n s[i + 3] = gmul(a0, 0x0b) ^ gmul(a1, 0x0d) ^ gmul(a2, 0x09) ^ gmul(a3, 0x0e)\n }\n}\n\n// ── 공개 API ──\n\n/** AES-128 ECB 복호화. data 길이는 16의 배수여야 함. */\nexport function aes128EcbDecrypt(data: Uint8Array, key: Uint8Array): Uint8Array {\n if (key.length !== 16) throw new Error(\"AES-128 키는 16바이트여야 합니다\")\n if (data.length % 16 !== 0) throw new Error(\"AES ECB 입력은 16바이트의 배수여야 합니다\")\n\n const roundKeys = expandKey(key)\n const out = new Uint8Array(data.length)\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const block = data.subarray(offset, offset + 16)\n const decrypted = decryptBlock(block, roundKeys)\n out.set(decrypted, offset)\n }\n\n return out\n}\n","/**\n * HWP 배포용(distribution) 문서 복호화.\n *\n * 배포용 HWP는 ViewText/Section{N} 스트림에 암호화된 본문을 저장.\n * 첫 레코드(HWPTAG_DISTRIBUTE_DOC_DATA)의 256바이트 payload에서 AES 키를 추출한 뒤\n * 나머지 데이터를 AES-128 ECB로 복호화.\n *\n * 알고리즘 참조: rhwp (MIT) src/parser/crypto.rs\n * 포맷 참조: HWP 5.0 바이너리 스펙 — 배포용 문서 구조\n */\n\nimport { aes128EcbDecrypt } from \"./aes.js\"\nimport { decompressStream } from \"./record.js\"\n\n// ── MSVC LCG (Linear Congruential Generator) ──\n\n/** MSVC CRT rand() 호환 LCG */\nclass MsvcLcg {\n private seed: number\n\n constructor(seed: number) {\n this.seed = seed >>> 0 // u32로 강제\n }\n\n /** 0 ~ 0x7FFF 범위 난수 반환 (MSVC rand() 호환) */\n rand(): number {\n // MSVC LCG: seed = seed * 214013 + 2531011\n // JS에서 32bit 정수 오버플로우를 정확히 재현하기 위해 Math.imul 사용\n this.seed = (Math.imul(this.seed, 214013) + 2531011) >>> 0\n return (this.seed >>> 16) & 0x7fff\n }\n}\n\n// ── 배포용 문서 256바이트 payload 복호화 ──\n\n/**\n * DISTRIBUTE_DOC_DATA 레코드의 256바이트 payload를 LCG+XOR로 복호화.\n *\n * 구조:\n * - bytes[0..4]: LCG seed (u32 LE)\n * - bytes[4..256]: XOR 암호화된 데이터\n *\n * XOR 규칙: LCG에서 키 바이트를 뽑고, n = (lcg.rand() & 0xF) + 1 바이트마다 키 교체\n */\nfunction decryptDistributePayload(payload: Uint8Array): Uint8Array {\n if (payload.length < 256) throw new Error(\"배포용 payload가 256바이트 미만입니다\")\n\n const seed = (payload[0] | (payload[1] << 8) | (payload[2] << 16) | (payload[3] << 24)) >>> 0\n const lcg = new MsvcLcg(seed)\n\n const result = new Uint8Array(payload.subarray(0, 256)) // 원본 복사\n\n // rhwp 호환: i=0부터 시작하여 n 카운터를 소비하되, i<4는 XOR 스킵 (seed 보존)\n // i=4부터 시작하면 LCG 시퀀스가 어긋남 — i=0~3에서도 n을 소비해야 정확함\n let i = 0\n let n = 0\n let key = 0\n\n while (i < 256) {\n if (n === 0) {\n key = lcg.rand() & 0xff\n n = (lcg.rand() & 0x0f) + 1\n }\n if (i >= 4) {\n result[i] ^= key\n }\n i++\n n--\n }\n\n return result\n}\n\n// ── AES 키 추출 ──\n\n/**\n * 복호화된 256바이트 payload에서 AES-128 키(16바이트) 추출.\n * offset = 4 + (decrypted[0] & 0x0F)\n */\nfunction extractAesKey(decryptedPayload: Uint8Array): Uint8Array {\n const offset = 4 + (decryptedPayload[0] & 0x0f)\n if (offset + 16 > decryptedPayload.length) {\n throw new Error(\"AES 키 추출 실패: 오프셋이 payload 범위를 초과합니다\")\n }\n return decryptedPayload.slice(offset, offset + 16)\n}\n\n// ── 레코드 헤더 파싱 ──\n\n/** HWP 레코드 헤더에서 tag_id와 size 추출 */\nfunction parseRecordHeader(data: Uint8Array, offset: number): { tagId: number; size: number; headerSize: number } {\n if (offset + 4 > data.length) throw new Error(\"레코드 헤더 파싱 실패: 데이터 부족\")\n\n const header = (data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24)) >>> 0\n const tagId = header & 0x3ff\n let size = (header >>> 20) & 0xfff\n let headerSize = 4\n\n if (size === 0xfff) {\n if (offset + 8 > data.length) throw new Error(\"확장 레코드 크기 파싱 실패: 데이터 부족\")\n size = (data[offset + 4] | (data[offset + 5] << 8) | (data[offset + 6] << 16) | (data[offset + 7] << 24)) >>> 0\n headerSize = 8\n }\n\n return { tagId, size, headerSize }\n}\n\n// ── 공개 API ──\n\n/** HWPTAG_DISTRIBUTE_DOC_DATA 태그 ID (HWPTAG_BEGIN + 12 = 0x10 + 12 = 0x1C = 28) */\nconst TAG_DISTRIBUTE_DOC_DATA = 0x10 + 12 // = 28\n\n/**\n * ViewText 스트림을 복호화하여 일반 BodyText 레코드 데이터로 변환.\n *\n * @param viewTextRaw ViewText/Section{N} 스트림의 원본 바이트\n * @param compressed FileHeader의 compressed 플래그\n * @returns 복호화된 레코드 데이터 (readRecords()로 파싱 가능)\n */\nexport function decryptViewText(viewTextRaw: Buffer, compressed: boolean): Buffer {\n const data = new Uint8Array(viewTextRaw)\n\n // 1. 첫 레코드 파싱 (DISTRIBUTE_DOC_DATA)\n const rec = parseRecordHeader(data, 0)\n if (rec.tagId !== TAG_DISTRIBUTE_DOC_DATA) {\n throw new Error(`배포용 문서의 첫 레코드가 DISTRIBUTE_DOC_DATA(${TAG_DISTRIBUTE_DOC_DATA})가 아닙니다 (실제: ${rec.tagId})`)\n }\n\n const payloadStart = rec.headerSize\n const payloadEnd = payloadStart + rec.size\n if (payloadEnd > data.length || rec.size < 256) {\n throw new Error(\"배포용 payload가 유효하지 않습니다\")\n }\n\n // 2. 256바이트 payload 복호화 (LCG + XOR)\n const payload = data.subarray(payloadStart, payloadStart + 256)\n const decryptedPayload = decryptDistributePayload(payload)\n\n // 3. AES-128 키 추출\n const aesKey = extractAesKey(decryptedPayload)\n\n // 4. 나머지 데이터를 AES-128 ECB 복호화\n const encryptedStart = payloadEnd\n const encryptedData = data.subarray(encryptedStart)\n\n if (encryptedData.length === 0) {\n throw new Error(\"배포용 문서에 암호화된 본문 데이터가 없습니다\")\n }\n\n // AES ECB는 16바이트 블록 단위 — 패딩 처리\n const alignedLen = encryptedData.length - (encryptedData.length % 16)\n if (alignedLen === 0) {\n throw new Error(\"암호화된 데이터가 너무 짧습니다 (16바이트 미만)\")\n }\n\n const alignedData = encryptedData.subarray(0, alignedLen)\n const decrypted = aes128EcbDecrypt(alignedData, aesKey)\n\n // 5. 압축 해제 (compressed 플래그가 설정된 경우)\n if (compressed) {\n try {\n return decompressStream(Buffer.from(decrypted))\n } catch {\n // 압축이 아닐 수도 있음 — 그대로 반환\n return Buffer.from(decrypted)\n }\n }\n\n return Buffer.from(decrypted)\n}\n\n// 테스트용 내부 함수 export\nexport { MsvcLcg as _MsvcLcg, decryptDistributePayload as _decryptDistributePayload, extractAesKey as _extractAesKey }\n","/**\n * 비밀번호로 보호된 HWP5 문서 복호화 (EncryptVersion 4).\n *\n * 배포용(ViewText) 문서와는 완전히 다른 방식이다 — 이쪽은 사용자가 지정한 열기 암호로\n * `DocInfo`·`BodyText/Section*`·`BinData/*`·`Scripts/*` 스트림을 각각 복호한다.\n *\n * 키 = SHA-1(인터리브(비밀번호))[0..16]\n * 본문 = AES-128 **비트 단위 CFB**(CFB-1) 복호 — IV 0, 레지스터는 스트림 전역\n *\n * CFB-1 이라 16바이트마다 AES 블록 연산을 128회 수행한다(바이트당 8회). 표준 AES 대비\n * 128배 연산량이라, 블록 암호기 객체를 스트림당 하나만 만들어 재사용한다.\n *\n * 알고리즘 참조: rhwp (MIT) src/parser/crypto.rs — 원 출처는 volexity/hwp-extract\n * (BSD-3-Clause) 의 encrypt.py.\n */\n\nimport { createCipheriv, createHash } from \"crypto\"\nimport { KordocError } from \"../utils.js\"\n\n/** FileHeader 의 EncryptVersion(u32 LE) 위치 */\nconst ENCRYPT_VERSION_OFFSET = 44\n/** 우리가 아는 유일한 비밀번호 암호화 버전 */\nconst SUPPORTED_ENCRYPT_VERSION = 4\n/** 키 유도 인터리브의 첫 \"이전 바이트\" 시드 */\nconst KEY_SEED = 236\n\n/** FileHeader 에서 EncryptVersion 을 읽는다. 짧으면 0. */\nexport function readEncryptVersion(fileHeader: Uint8Array): number {\n if (fileHeader.length < ENCRYPT_VERSION_OFFSET + 4) return 0\n return (\n (fileHeader[ENCRYPT_VERSION_OFFSET] |\n (fileHeader[ENCRYPT_VERSION_OFFSET + 1] << 8) |\n (fileHeader[ENCRYPT_VERSION_OFFSET + 2] << 16) |\n (fileHeader[ENCRYPT_VERSION_OFFSET + 3] << 24)) >>>\n 0\n )\n}\n\n/**\n * 비밀번호 → AES-128 키 16바이트.\n *\n * 각 비밀번호 바이트 앞에 \"이전 바이트를 1비트 왼쪽 회전한 값\"을 끼워 넣어 길이 2배의\n * 버퍼를 만들고, 그 SHA-1 다이제스트 앞 16바이트를 키로 쓴다. 첫 바이트의 \"이전 값\"은\n * 시드 상수 236.\n */\nexport function derivePasswordKey(password: Uint8Array): Buffer {\n const buf = Buffer.alloc(password.length * 2)\n for (let i = 0; i < password.length; i++) {\n const prev = i === 0 ? KEY_SEED : password[i - 1]\n buf[i * 2] = ((prev << 1) | (prev >> 7)) & 0xff // ROL 1\n buf[i * 2 + 1] = password[i]\n }\n return createHash(\"sha1\").update(buf).digest().subarray(0, 16)\n}\n\n/** 16바이트 배수로 패드. 이미 배수면 그대로(참조 구현과 동일). */\nfunction padToBlock(data: Uint8Array): Buffer {\n const rem = data.length % 16\n if (rem === 0) return Buffer.from(data)\n const amount = 16 - rem\n return Buffer.concat([Buffer.from(data), Buffer.alloc(amount, amount)])\n}\n\n/** 128비트 레지스터를 1비트 왼쪽 시프트하고 최하위 비트에 feedback 을 넣는다 */\nfunction shiftRegister(reg: Uint8Array, feedbackBit: number): void {\n for (let i = 0; i < 15; i++) {\n reg[i] = ((reg[i] << 1) | (reg[i + 1] >> 7)) & 0xff\n }\n reg[15] = ((reg[15] << 1) | (feedbackBit & 1)) & 0xff\n}\n\n/**\n * AES-128 비트 단위 CFB 복호.\n *\n * 복호에도 AES 는 **암호화 방향**을 쓴다(CFB 의 정의). 레지스터는 블록마다 리셋하지 않고\n * 스트림 전체에서 이어진다. IV 는 0.\n */\nfunction decryptAesCfb1(data: Buffer, key: Buffer): Buffer {\n // ECB 는 블록 간 체이닝이 없어 Cipher 객체 하나를 계속 재사용해도 안전하다.\n // 매 블록 새로 만들면 128배 호출이라 감당이 안 된다.\n const cipher = createCipheriv(\"aes-128-ecb\", key, null)\n cipher.setAutoPadding(false)\n\n const register = new Uint8Array(16)\n const registerBuf = Buffer.alloc(16)\n const out = Buffer.alloc(data.length)\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const len = Math.min(16, data.length - offset)\n const chunk = Buffer.alloc(16)\n data.copy(chunk, 0, offset, offset + len)\n\n for (let i = 0; i < 128; i++) {\n registerBuf.set(register)\n const keystreamMsb = cipher.update(registerBuf)[0]\n\n const byteIdx = i >> 3\n const bitInByte = i & 7\n // 되먹임은 **암호문** 비트 — XOR 로 평문이 되기 전 값을 넣어야 한다\n const cipherBit = (chunk[byteIdx] >> (7 - bitInByte)) & 1\n shiftRegister(register, cipherBit)\n\n chunk[byteIdx] ^= (keystreamMsb & 0x80) >> bitInByte\n }\n\n chunk.copy(out, offset, 0, len)\n }\n\n return out\n}\n\n/**\n * 암호 스트림 복호 (압축 해제는 하지 않음).\n * CFB 는 길이를 보존하므로 정렬용으로 덧붙인 패딩은 결과에서 잘라낸다.\n */\nexport function decryptPasswordStream(raw: Uint8Array, password: string): Buffer {\n const key = derivePasswordKey(Buffer.from(password, \"utf8\"))\n return decryptAesCfb1(padToBlock(raw), key).subarray(0, raw.length)\n}\n\n/** DocInfo 선두에 반드시 오는 레코드 (HWPTAG_BEGIN + 0 / + 1) */\nconst TAG_DOCUMENT_PROPERTIES = 0x0010\nconst TAG_ID_MAPPINGS = 0x0011\n\n/**\n * 복호한 DocInfo 가 실제 HWP 문서인지 확인한다.\n *\n * 비밀번호가 틀리면 복호 결과가 난수인데, 파서의 DocInfo·섹션 경로는 실패를 경고로\n * 흡수하도록 되어 있어 **\"성공했는데 내용이 쓰레기\"** 인 결과가 나온다. 압축 문서는\n * inflate 가 곧 무결성 검사지만 비압축 문서는 그것도 없으므로, DocInfo 가 반드시\n * 갖는 선두 레코드 두 종으로 확인한다.\n *\n * @param readRecords 레코드 리더 (순환 import 회피용 주입)\n */\nexport function assertDecryptedDocInfo(\n data: Buffer,\n readRecords: (buf: Buffer) => Array<{ tagId: number }>,\n): void {\n const wrong = () =>\n new KordocError(\"비밀번호가 일치하지 않거나 암호화 데이터가 손상되었습니다.\")\n let records: Array<{ tagId: number }>\n try {\n records = readRecords(data)\n } catch {\n throw wrong()\n }\n if (records[0]?.tagId !== TAG_DOCUMENT_PROPERTIES) throw wrong()\n if (!records.some(r => r.tagId === TAG_ID_MAPPINGS)) throw wrong()\n}\n\n/** EncryptVersion 을 검사하고 미지원이면 던진다 */\nexport function assertSupportedEncryptVersion(version: number): void {\n if (version !== SUPPORTED_ENCRYPT_VERSION) {\n // 구버전(1~3)을 같은 알고리즘으로 풀면 결과가 쓰레기인데도 \"비밀번호 오답\"으로\n // 보고돼 사용자가 암호를 계속 다시 입력하게 된다 — 방식이 다르다고 분명히 알린다.\n throw new KordocError(\n `지원하지 않는 HWP 암호화 버전입니다 (EncryptVersion=${version}, 지원: ${SUPPORTED_ENCRYPT_VERSION})`,\n )\n }\n}\n","/**\n * HWP 5.x 실제 페이지 경계 복원 (#66) — PARA_LINE_SEG(0x45) 조판 캐시로\n * 섹션 내 top-level 문단별 실제 페이지 배정을 계산한다.\n *\n * 알고리즘은 hwpx/page-boundary.ts와 동일한 신호 4종 (그쪽 헤더 주석 참조).\n * HWP5 매핑 (bench/corpus/pairs hwp↔hwpx 10쌍 전수 일치로 검증):\n * - lineseg → PARA_LINE_SEG 36바이트 엔트리 (v=+4 i32, h=+24 i32; 태그 +32의\n * bit0 \"페이지 첫 줄\"은 저장본에서 항상 0 — 못 씀)\n * - pageBreak → PARA_HEADER 데이터 offset 11(문단 나눔 종류)의 bit2(쪽 나누기)\n * - top 문단 → PARA_HEADER level 0, 그 lineseg는 level 1\n * - 표 셀 → CTRL_HEADER('tbl ') level 1 → LIST_HEADER level 2(셀 주소\n * col u16@8·row u16@10) → 셀 직접 문단은 같은 level 2, lineseg level 3\n * (중첩 표는 level 4/5라 자연 배제)\n */\n\nimport type { HwpRecord } from \"./record.js\"\nimport { TAG_PARA_HEADER, TAG_PARA_LINE_SEG, TAG_CTRL_HEADER, TAG_LIST_HEADER } from \"./record.js\"\n\n/** 이 값 이상에서 시작하는 역행은 페이지 상단 리셋이 아니다 (신호 4 판별, HWPUNIT) */\nconst MIDPAGE_V = 2000\n\n/** \"tbl \" 컨트롤 ID — LE 저장(\" lbt\")을 readUInt32LE로 읽은 BE 상수 (parser.ts CTRL_TBL과 동일) */\nconst CTRL_ID_TBL = 0x74626c20\n\n/** 섹션 페이지 감지 결과 */\nexport interface Hwp5SectionPageDetect {\n /** top-level 문단 순번(등장 순서) → 섹션 내 0-based 페이지 (문단 시작 위치 기준) */\n pageAtPara: number[]\n /** 섹션이 차지하는 페이지 수 (≥1) */\n pages: number\n /** 조판 캐시 신뢰 가능 여부 — top-level 문단 전부가 LINE_SEG를 가질 때만 true */\n usable: boolean\n}\n\n/** 표 컨트롤 범위의 내부 페이지 나눔 수 — 행별 max(셀 직접 문단 흐름 리셋) 합산 */\nfunction tableIntraBreaks(records: HwpRecord[], start: number, end: number): number {\n const rowMax = new Map<number, number>()\n let curRow = -1\n let prevV = Number.NEGATIVE_INFINITY\n let resets = 0\n const flush = () => {\n if (curRow >= 0) rowMax.set(curRow, Math.max(rowMax.get(curRow) ?? 0, resets))\n resets = 0\n prevV = Number.NEGATIVE_INFINITY\n }\n for (let i = start; i < end; i++) {\n const rec = records[i]\n if (rec.tagId === TAG_LIST_HEADER && rec.level === 2 && rec.data.length >= 12) {\n flush()\n curRow = rec.data.readUInt16LE(10)\n } else if (rec.tagId === TAG_PARA_LINE_SEG && rec.level === 3 && curRow >= 0) {\n for (let off = 0; off + 36 <= rec.data.length; off += 36) {\n const v = rec.data.readInt32LE(off + 4)\n if (v < prevV) resets++\n prevV = v\n }\n }\n }\n flush()\n let sum = 0\n for (const v of rowMax.values()) sum += v\n return sum\n}\n\n/**\n * 섹션 레코드에서 top-level 문단별 페이지 배정을 계산한다.\n * 반환 pageAtPara의 인덱스는 parseParagraphList가 만나는 top-level 문단 순서와 같다.\n */\nexport function detectHwp5SectionPages(records: HwpRecord[]): Hwp5SectionPageDetect {\n const pageAtPara: number[] = []\n let cur = 0\n let prevV = Number.NEGATIVE_INFINITY\n let prevH = Number.NEGATIVE_INFINITY\n let first = true\n let suppressMidReset = false\n let parasWithSegs = 0\n\n let i = 0\n while (i < records.length) {\n const rec = records[i]\n if (rec.tagId !== TAG_PARA_HEADER || rec.level !== 0) {\n i++\n continue\n }\n let j = i + 1\n while (j < records.length && records[j].level > 0) j++\n\n // 문단 나눔 종류(offset 11): bit0 구역, bit1 다단, bit2 쪽, bit3 단\n const divideSort = rec.data.length >= 12 ? rec.data.readUInt8(11) : 0\n const explicit = (divideSort & 0x04) !== 0\n let brokeByExplicit = false\n if (explicit && !first) {\n cur++\n brokeByExplicit = true\n suppressMidReset = false\n }\n\n let paraFirst = true\n let startPage = cur\n let hadSegs = false\n let intraAdd = 0\n for (let k = i + 1; k < j; k++) {\n const r = records[k]\n if (r.tagId === TAG_PARA_LINE_SEG && r.level === 1) {\n hadSegs = true\n for (let off = 0; off + 36 <= r.data.length; off += 36) {\n const v = r.data.readInt32LE(off + 4)\n const h = r.data.readInt32LE(off + 24)\n // HWPX 쪽 다단 예외(colCount>1일 때 h 우측 점프 배제)는 여기선 미적용 —\n // pairs 10쌍에서 HWPX와 결과 동일 검증. 다단 HWP5에서 어긋나면 그쪽 규칙 이식\n const brk = v < prevV || (paraFirst && v === prevV && h <= prevH)\n if (brk && !(paraFirst && brokeByExplicit)) {\n if (paraFirst && suppressMidReset && v >= MIDPAGE_V) {\n // 신호 4: 분할 표 꼬리 아래 재개 — 같은 경계\n } else {\n cur++\n }\n }\n if (paraFirst) {\n suppressMidReset = false\n startPage = cur\n }\n paraFirst = false\n prevV = v\n prevH = h\n }\n }\n // 신호 3: top-level 표(CTRL_HEADER 'tbl ', level 1)의 내부 분할\n if (r.tagId === TAG_CTRL_HEADER && r.level === 1 && r.data.length >= 4\n && r.data.readUInt32LE(0) === CTRL_ID_TBL) {\n let ce = k + 1\n while (ce < j && records[ce].level > 1) ce++\n intraAdd += tableIntraBreaks(records, k + 1, ce)\n k = ce - 1\n }\n }\n if (hadSegs) parasWithSegs++\n pageAtPara.push(startPage)\n first = false\n if (intraAdd > 0) {\n cur += intraAdd\n suppressMidReset = true\n }\n i = j\n }\n\n return {\n pageAtPara,\n pages: cur + 1,\n usable: pageAtPara.length > 0 && parasWithSegs === pageAtPara.length,\n }\n}\n","/**\n * HWP5 표 순번 (#75 Task 7 · #76 조인 키) — 섹션 레코드에서 표 컨트롤(CTRL_HEADER 'tbl ')을 문서(레코드) 순서로\n * 번호 매긴다. 파서(IRTable.sourceId)와 렌더 어댑터(RenderRegion.sourceId)가 **같은 프리패스**로 키를 얻어야\n * 중첩 표·머리말 안 표·깊이 상한으로 한쪽만 건너뛰는 개체가 있어도 번호가 어긋나지 않는다.\n * HWPX 의 `hp:tbl id` 에 해당하며, 형식은 `t{전역 1-based 순번}` (여러 구역은 base 누적).\n */\n\nimport { TAG_CTRL_HEADER, type HwpRecord } from \"./record.js\"\n\n/** \"tbl \" — LE 저장(\" lbt\")을 readUInt32LE 로 읽은 BE 상수 (parser.ts CTRL_TBL 과 동일) */\nconst CTRL_ID_TBL = 0x74626c20\n\nfunction swap32(id: number): number {\n return (((id & 0xff) << 24) | (((id >>> 8) & 0xff) << 16) | (((id >>> 16) & 0xff) << 8) | ((id >>> 24) & 0xff)) >>> 0\n}\n\nexport function isHwp5TableCtrl(rec: HwpRecord): boolean {\n if (rec.tagId !== TAG_CTRL_HEADER || rec.data.length < 4) return false\n const id = rec.data.readUInt32LE(0)\n return id === CTRL_ID_TBL || swap32(id) === CTRL_ID_TBL\n}\n\n/** 레코드 인덱스(CTRL_HEADER 위치) → sourceId. count 는 이 섹션의 표 수(다음 섹션 base 로 누적) */\nexport function indexHwp5Tables(records: HwpRecord[], base = 0): { ids: Map<number, string>; count: number } {\n const ids = new Map<number, string>()\n let n = 0\n for (let i = 0; i < records.length; i++) {\n if (isHwp5TableCtrl(records[i])) { n++; ids.set(i, `t${base + n}`) }\n }\n return { ids, count: n }\n}\n","/**\n * HWP5 문단번호/글머리표 — 7수준 카운터 상태기계 + ^N 형식 치환 + 번호 포맷터.\n *\n * 출처: rhwp (MIT) renderer/layout.rs NumberingState::advance,\n * renderer/layout/utils.rs expand_numbering_format, renderer/mod.rs format_number.\n */\n\nimport type { HwpNumbering } from \"./record.js\"\nimport { hangulOrdinal, circledNumber, circledHangul, romanNumeral } from \"../shared/numbering.js\"\n\n// ─── 7수준 카운터 상태기계 ───────────────────────────\n\n/**\n * 문단 번호 카운터 (수준별 1-7).\n * HWP 동작:\n * - 같은 numberingId 연속 = \"앞 번호 이어\" (카운터 유지)\n * - 다른 id (히스토리 있음) = \"이전 번호 이어\" (히스토리 복원)\n * - 다른 id (히스토리 없음) = 상위 수준 상속 + 현재 수준 이하 리셋\n */\nexport class NumberingState {\n private currentId = 0\n private counters: number[] = [0, 0, 0, 0, 0, 0, 0]\n private history = new Map<number, number[]>()\n\n /** 번호 문단 처리: 카운터 갱신 후 수준별 카운터 스냅샷 반환 */\n advance(numberingId: number, level: number): number[] {\n const lv = Math.min(Math.max(level, 0), 6)\n\n if (this.currentId !== numberingId) {\n if (this.currentId !== 0) this.history.set(this.currentId, [...this.counters])\n const saved = this.history.get(numberingId)\n if (saved) {\n this.counters = [...saved]\n } else {\n const prev = this.counters\n this.counters = [0, 0, 0, 0, 0, 0, 0]\n for (let i = 0; i < lv; i++) this.counters[i] = prev[i]\n }\n this.currentId = numberingId\n }\n\n this.counters[lv]++\n for (let i = lv + 1; i < 7; i++) this.counters[i] = 0\n return [...this.counters]\n }\n}\n\n// ─── 번호 포맷터 ─────────────────────────────────────\n\nexport type NumFmt =\n | \"digit\" | \"circled\" | \"romanUpper\" | \"romanLower\" | \"latinUpper\" | \"latinLower\"\n | \"ganada\" | \"circledGanada\" | \"jamo\" | \"circledJamo\" | \"hangulNum\" | \"hanjaNum\"\n\n/** HWP 표 43 (문단 머리 번호 형식 코드) → NumFmt */\nfunction headFormatToNumFmt(code: number): NumFmt {\n switch (code) {\n case 1: return \"circled\"\n case 2: return \"romanUpper\"\n case 3: return \"romanLower\"\n case 4: return \"latinUpper\"\n case 5: return \"latinLower\"\n case 8: return \"ganada\"\n case 9: return \"circledGanada\"\n case 10: return \"jamo\"\n case 11: return \"circledJamo\"\n case 12: return \"hangulNum\"\n case 13: return \"hanjaNum\"\n default: return \"digit\"\n }\n}\n\n/** HWP 표 134 (자동번호/쪽번호 모양 코드) → NumFmt */\nexport function shapeFormatToNumFmt(code: number): NumFmt {\n switch (code) {\n case 1: return \"circled\"\n case 2: return \"romanUpper\"\n case 3: return \"romanLower\"\n case 4: return \"latinUpper\"\n case 5: return \"latinLower\"\n case 6: return \"ganada\"\n case 7: return \"hangulNum\"\n case 8: return \"hanjaNum\"\n default: return \"digit\"\n }\n}\n\nconst JAMO = \"ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ\"\nconst CIRCLED_JAMO = \"㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭\"\n\nfunction fromTable(n: number, table: string): string {\n return n >= 1 && n <= table.length ? table[n - 1] : String(n)\n}\n\nfunction formatLatin(n: number, upper: boolean): string {\n if (n <= 0) return \"\"\n let result = \"\"\n let num = n\n while (num > 0) {\n num--\n result = String.fromCharCode((upper ? 65 : 97) + (num % 26)) + result\n num = Math.floor(num / 26)\n }\n return result\n}\n\n/** 한글/한자 숫자 (일이삼 / 一二三) — 만 단위까지 */\nfunction formatEastAsianNumber(n: number, digits: string[], units: string[], zero: string): string {\n if (n === 0) return zero\n if (n < 0 || n > 99999) return String(n)\n let result = \"\"\n let num = n\n let unit = 0\n while (num > 0) {\n const d = num % 10\n if (d > 0) {\n const digitStr = d === 1 && unit > 0 ? \"\" : digits[d]\n result = digitStr + units[unit] + result\n }\n num = Math.floor(num / 10)\n unit++\n }\n return result\n}\n\nconst HANGUL_DIGITS = [\"\", \"일\", \"이\", \"삼\", \"사\", \"오\", \"육\", \"칠\", \"팔\", \"구\"]\nconst HANGUL_UNITS = [\"\", \"십\", \"백\", \"천\", \"만\"]\nconst HANJA_DIGITS = [\"\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\", \"七\", \"八\", \"九\"]\nconst HANJA_UNITS = [\"\", \"十\", \"百\", \"千\", \"萬\"]\n\n/** 번호 → 문자열 (rhwp format_number 포팅 — 시퀀스 폴백은 shared/numbering 정본 규칙) */\nexport function formatNumber(n: number, fmt: NumFmt): string {\n switch (fmt) {\n case \"circled\": return n >= 1 ? circledNumber(n - 1) : String(n)\n case \"romanUpper\": return romanNumeral(n, true)\n case \"romanLower\": return romanNumeral(n, false)\n case \"latinUpper\": return formatLatin(n, true) || String(n)\n case \"latinLower\": return formatLatin(n, false) || String(n)\n case \"ganada\": return n >= 1 ? hangulOrdinal(n - 1) : String(n)\n case \"circledGanada\": return n >= 1 ? circledHangul(n - 1) : String(n)\n case \"jamo\": return fromTable(n, JAMO)\n case \"circledJamo\": return fromTable(n, CIRCLED_JAMO)\n case \"hangulNum\": return formatEastAsianNumber(n, HANGUL_DIGITS, HANGUL_UNITS, \"영\")\n case \"hanjaNum\": return formatEastAsianNumber(n, HANJA_DIGITS, HANJA_UNITS, \"零\")\n default: return String(n)\n }\n}\n\n// ─── ^N 형식 치환 ────────────────────────────────────\n\n/**\n * 번호 형식 문자열의 `^1`~`^7` 제어코드를 실제 번호로 치환.\n * (rhwp expand_numbering_format 포팅 — 시작번호 보정: counter>0이면 (start-1)+counter)\n */\nexport function expandNumberingFormat(formatStr: string, counters: number[], numbering: HwpNumbering): string {\n let result = \"\"\n let i = 0\n while (i < formatStr.length) {\n const ch = formatStr[i]\n if (ch === \"^\" && i + 1 < formatStr.length && formatStr[i + 1] >= \"1\" && formatStr[i + 1] <= \"7\") {\n const levelRef = formatStr.charCodeAt(i + 1) - 48 // '1'..'7' → 1..7\n const idx = levelRef - 1\n const counterVal = counters[idx] ?? 0\n const start = numbering.startNumbers[idx] ?? 1\n const num = counterVal > 0 ? start - 1 + counterVal : start\n result += formatNumber(num, headFormatToNumFmt(numbering.numberFormats[idx] ?? 0))\n i += 2\n continue\n }\n // 레벨 숫자가 아닌 글자(공백·기호) 앞의 ^ 는 한컴이 그리지 않는다 — HWPX para-heading 과 같은 규칙\n // (\"^ □\" → \"□\", 정책브리핑 156775690 한컴 PDF). 문자·숫자 앞은 근거가 없어 그대로 둔다\n if (ch === \"^\" && !/[\\p{L}\\p{N}]/u.test(formatStr[i + 1] ?? \"\")) {\n i++\n continue\n }\n result += ch\n i++\n }\n return result\n}\n","/**\n * HWP5 수식 레코드(EQEDIT) 스크립트 → LaTeX.\n *\n * HWP5의 EQEDIT 레코드도 HWPX <hp:script>와 같은 한컴 EqEdit 언어라\n * 구조 변환(분수·근호·행렬·액센트·토큰 매핑)은 hwpx/equation.ts(hmlToLatex)를\n * 정본으로 재사용한다. 이 모듈은 HWP5 실문서에서 관측되는 표기 편차\n * (소문자 예약어·붙여쓴 첨자·유니코드 연산자·글꼴 지시자)를 정본 토크나이저가\n * 인식할 수 있는 형태로 정규화하는 호환 프리패스만 담당한다.\n */\n\nimport { CONVERT_MAP, MIDDLE_CONVERT_MAP, hmlToLatex } from \"../hwpx/equation.js\"\n\n/**\n * 정본 CONVERT_MAP에 (해당 표기로는) 없는 hwp5 지원 어휘 → LaTeX 직접 치환.\n * 키는 소문자 — 대소문자 무관 매칭(구 hwp5 동작 보존). 정본에 정확히 있는\n * 토큰(IN, GEQ, ALPHA 등)이 우선이라 여기까지 오지 않는다.\n */\nconst WORD_ALIASES: Record<string, string> = {\n // 삼각/로그 함수 — 정본 맵 부재\n sin: \"\\\\sin\", cos: \"\\\\cos\", tan: \"\\\\tan\", sec: \"\\\\sec\", csc: \"\\\\csc\", cot: \"\\\\cot\",\n log: \"\\\\log\", ln: \"\\\\ln\",\n // 연산자·관계 기호 (정본은 대문자 키만 보유)\n divide: \"\\\\div\", div: \"\\\\div\",\n le: \"\\\\leq\", ge: \"\\\\geq\", geq: \"\\\\geq\", deg: \"^\\\\circ\",\n rarrow: \"\\\\rightarrow\", lrarrow: \"\\\\leftrightarrow\",\n rightarrow: \"\\\\rightarrow\", leftarrow: \"\\\\leftarrow\",\n in: \"\\\\in\", notin: \"\\\\notin\", emptyset: \"\\\\emptyset\",\n subset: \"\\\\subset\", nsubset: \"\\\\nsubseteq\",\n cup: \"\\\\cup\", cap: \"\\\\cap\", smallinter: \"\\\\cap\", smallsum: \"\\\\sum\",\n sim: \"\\\\sim\", circ: \"\\\\circ\", bot: \"\\\\perp\",\n partial: \"\\\\partial\", nabla: \"\\\\nabla\",\n angle: \"\\\\angle\", triangle: \"\\\\triangle\",\n inf: \"\\\\infty\",\n left: \"\\\\left\", right: \"\\\\right\",\n // 글꼴 지시자 — 제거\n rm: \"\", it: \"\",\n}\n\n/** 구조 예약어 — hmlToLatex가 소문자만 인식하므로 대소문자 무관 입력을 접는다 */\nconst STRUCTURAL_FOLD = new Set([\"over\", \"root\", \"of\"])\n\n/** 어절 단위 사전 정규화 — 정본 키 우선, 없으면 소문자 별칭/정본 키로 폴드 */\nfunction normalizeWords(input: string): string {\n return input.replace(/(?<![\\\\A-Za-z0-9])([A-Za-z][A-Za-z0-9]*)(?![A-Za-z0-9])/g, word => {\n // hasOwn 필수 — `in`은 Object.prototype 키에도 걸린다 (hwpx/equation.ts 동일 주석 참조)\n if (Object.hasOwn(CONVERT_MAP, word) || Object.hasOwn(MIDDLE_CONVERT_MAP, word)) return word\n const lower = word.toLowerCase()\n if (STRUCTURAL_FOLD.has(lower)) return lower\n if (Object.hasOwn(WORD_ALIASES, lower)) return WORD_ALIASES[lower]\n if (lower !== word && (Object.hasOwn(CONVERT_MAP, lower) || Object.hasOwn(MIDDLE_CONVERT_MAP, lower))) return lower\n return word\n })\n}\n\n/** 첨자 정규화 — 공백 제거 후 미괄호 인자를 중괄호로 감싸고, 정본 토큰화용으로 분리 */\nfunction normalizeScripts(input: string): string {\n return input\n .replace(/\\s*\\^\\s*/g, \"^\")\n .replace(/\\s*_\\s*/g, \"_\")\n .replace(/\\^(?!\\{)([^\\s{}_^]+)/g, \"^{$1}\")\n .replace(/_(?!\\{)([^\\s{}_^]+)/g, \"_{$1}\")\n // \"sum_{k}\"가 통짜 토큰으로 남지 않게 ^/_를 독립 토큰으로 분리 (LaTeX 의미 동일)\n .replace(/([_^])/g, \" $1 \")\n}\n\n/** 붙여쓴/유니코드 연산자 → LaTeX (정본 토큰 맵은 공백 분리 토큰만 인식) */\nfunction normalizeOperators(input: string): string {\n return input\n .replace(/\\+-/g, \" \\\\pm \")\n .replace(/-\\+/g, \" \\\\mp \")\n .replace(/\\/\\//g, \" \\\\parallel \")\n .replace(/!=/g, \" \\\\neq \")\n .replace(/<=/g, \" \\\\leq \")\n .replace(/>=/g, \" \\\\geq \")\n .replace(/==/g, \" \\\\equiv \")\n .replace(/△/g, \" \\\\triangle \")\n .replace(/□/g, \" \\\\square \")\n .replace(/‧/g, \" \\\\cdot \")\n}\n\nexport function hwpEquationToLatex(equation: string): string {\n let s = equation.replace(/\\0/g, \"\").replace(/\\s+/g, \" \").trim()\n if (!s) return \"\"\n\n s = normalizeScripts(s)\n s = normalizeOperators(s)\n s = normalizeWords(s)\n // 미괄호 근호 지수(\"root n of {x}\") — 정본 replaceRootOf는 중괄호 그룹만 인식\n s = s.replace(/\\broot\\s+(?!\\{)(\\S+)\\s+of(?![A-Za-z0-9])/gi, \"root { $1 } of\")\n\n return hmlToLatex(s).replace(/\\s+/g, \" \").trim()\n}\n","/**\n * 문단·셀 IR 조립 — HWP5(body.ts)·HWP3(hwp3/parser.ts) 공용.\n *\n * 두 바이너리 파서가 레코드/문자 스트림에서 뽑은 문단 글·개체 블록·좌표 셀을 HWPX 파서와 같은 IR 모양으로\n * 조립한다: 글자처럼 취급 표 앞뒤 글 분할(#49/#50), 셀 평탄화 줄 모델(#52), 머리말·각주 안 표 평탄화,\n * 좌표 셀 → builder 직접 배치(후행 빈 열 트림 계약)와 손상 표(겹친 앵커) 정리.\n */\n\nimport { buildTable, captionedText, convertTableToText, MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\nimport type { CellContext, IRBlock, IRTable, IRSpan, InlineStyle } from \"../types.js\"\nimport { CELL_EDGES, type Edges } from \"../table/layout-frames.js\"\nimport { TOC_ENTRY_BLOCKS } from \"../toc-entry.js\"\n\n/** 글자처럼 취급 표 자리 표지 — 문단 글을 표 앞뒤로 나눈다 (HWPX section-walker 와 같은 문자) */\nexport const INLINE_TABLE_MARK = \"\\x1E\"\n\n/**\n * 셀 평탄화에서 앞 줄에 공백으로 잇는 블록 — 글자처럼 취급 표와 그 뒤 조각은 한 줄이다\n * (HWPX completeTable/flush 의 lineOpen 규칙 #52). emitParagraphBlocks 가 표시하고 cellTextFromBlocks 가 읽는다\n */\nconst INLINE_JOIN = new WeakSet<IRBlock>()\n\n/** 문단에 딸린 개체 (컨트롤 순서) */\nexport interface ParaObject {\n /** 개체 파생 블록 (표·그림·글상자) */\n blocks: IRBlock[]\n /** 표 개체 — 앞 글 조각을 먼저 내보낸다 */\n table: boolean\n /** 글자처럼 취급 표 — 문단 글에 INLINE_TABLE_MARK 자리가 있다 */\n inline: boolean\n}\n\nexport interface ParaEmitInput {\n /** 필드 편집·리더 절단을 마친 문단 글 (INLINE_TABLE_MARK 포함 가능) */\n text: string\n headMarker: string | null\n /** 개요 제목 수준 (0 = 본문) */\n headingLevel: number\n /** 목차 항목(채움 탭 + 쪽 번호 줄) — 글자 크기·\"제N장\" 제목 추정에서 뺀다 (#121) */\n tocEntry?: boolean\n style?: InlineStyle\n /** 각주/미주 (\"1) 내용\") */\n footnotes: string[]\n /** 주석 안에 표가 있을 때 주석 본문 구조 블록 — IRBlock.footnoteBlocks 로 (#149, HWP5) */\n footnoteBlocks?: IRBlock[]\n objects: ParaObject[]\n pageNumber?: number\n /** 인라인 강조 span (굵게·기울임·취소선·밑줄) — 글이 한 문단 블록으로만 나갈 때 붙인다(HWPX run-spans 대칭) */\n spans?: IRSpan[]\n}\n\n/** 문단 1개 → [문단 블록(들), 개체 블록] */\nexport function emitParagraphBlocks(p: ParaEmitInput): IRBlock[] {\n const { headMarker, style, footnotes, footnoteBlocks, objects, pageNumber } = p\n const blocks: IRBlock[] = []\n // 취소선·밑줄 문단(법령 개정문 삭제·개정 표시 등)은 ~~…~~ / <u>…</u> 로 방출 —\n // 대표(최빈) 스타일 기준이라 문단 전체가 그어진 경우만 잡는다 (부분 서식은 미지원)\n const decorate = (t: string): string => {\n let deco = style?.strike ? `~~${t}~~` : t\n if (style?.underline) deco = `<u>${deco}</u>`\n return deco\n }\n\n if (p.text.includes(INLINE_TABLE_MARK)) {\n // 글자처럼 취급 표가 있는 문단 — 표 앞 조각을 표 직전에 방출해 원문 순서를 지킨다(HWPX walkParagraphChildren\n // onTbl 대칭: 떠 있는 표도 앞 조각을 먼저 내고, 그리기 개체는 조각을 당기지 않는다). 조각은 본문 문단\n // (개요 제목 승격 없음 — HWPX 와 같다), 문단 머리표는 첫 글 조각에, 스타일·각주는 첫 블록에\n const segments = p.text.split(INLINE_TABLE_MARK)\n let segIdx = 0\n let first = true\n let lineOpen = false\n let markerPending = !!headMarker\n const flush = (): void => {\n if (segIdx >= segments.length) return\n const s = segments[segIdx++].replace(/\\$\\$/g, \"$ $\").trim()\n if (!s) return\n let t = decorate(s)\n if (markerPending) { t = `${headMarker} ${t}`; markerPending = false }\n const block: IRBlock = { type: \"paragraph\", text: t, pageNumber }\n if (first) {\n if (style) block.style = style\n if (footnotes.length > 0) block.footnoteText = footnotes.join(\"; \")\n if (footnoteBlocks) block.footnoteBlocks = footnoteBlocks\n first = false\n }\n if (lineOpen) INLINE_JOIN.add(block)\n lineOpen = true\n blocks.push(block)\n }\n for (const obj of objects) {\n if (obj.table) {\n flush()\n if (obj.inline && lineOpen) for (const b of obj.blocks) INLINE_JOIN.add(b)\n lineOpen = obj.inline\n }\n blocks.push(...obj.blocks)\n }\n while (segIdx < segments.length) flush()\n // 글 조각이 하나도 없는 각주 anchor — 각주 내용 자체를 문단으로 보존 (아래 단일 문단 경로와 같다)\n if (first && footnotes.length > 0) blocks.unshift({ type: \"paragraph\", text: `(주: ${footnotes.join(\"; \")})`, pageNumber })\n return blocks\n }\n\n const trimmed = p.text.replace(/\\$\\$/g, \"$ $\").trim()\n if (trimmed) {\n const block: IRBlock = {\n type: p.headingLevel > 0 ? \"heading\" : \"paragraph\",\n text: headMarker ? `${headMarker} ${trimmed}` : trimmed,\n pageNumber,\n }\n if (p.headingLevel > 0) block.level = p.headingLevel\n else if (p.spans) block.spans = headMarker ? [{ text: `${headMarker} ` }, ...p.spans] : p.spans\n if (p.tocEntry) TOC_ENTRY_BLOCKS.add(block)\n if (style) {\n block.style = style\n // 강조 span 이 붙은 문단은 span 이 취소선·밑줄을 담는다 — 글에 표지를 구우면 칸 글(중첩 표 칸 등 글로 그리는 경로)에 표지가\n // 남는다(HWPX 는 글이 평문)\n if ((style.strike || style.underline) && !block.spans) block.text = headMarker ? `${headMarker} ${decorate(trimmed)}` : decorate(trimmed)\n }\n if (footnotes.length > 0) block.footnoteText = footnotes.join(\"; \")\n if (footnoteBlocks) block.footnoteBlocks = footnoteBlocks\n blocks.push(block)\n } else if (footnotes.length > 0) {\n // 본문 없는 각주 anchor — 각주 내용 자체를 문단으로 보존\n blocks.push({ type: \"paragraph\", text: `(주: ${footnotes.join(\"; \")})`, pageNumber })\n }\n for (const obj of objects) blocks.push(...obj.blocks)\n return blocks\n}\n\n// ─── 평문 평탄화 ─────────────────────────────────────\n\n/**\n * 표 → 평문 — 셀은 \" / \", 행은 줄바꿈(convertTableToText), 캡션은 먼저(표 아래 캡션은 뒤). HWPX completeTable·buildSubListTable 과 같은 모양.\n * 셀 이미지 sentinel(\"![image](hwp5bin:N)\")은 남긴다 — images.ts 가 블록 트리 전체에서 추출 파일명으로 편다\n * (HWPX 도 머리말 표 이미지 셀을 \"![image](…)\" 로 남긴다). 종전엔 머리말·각주의 표를 건너뛰어 표 글이 통째로 사라졌다\n */\nexport function tableFlatText(table: IRTable): string {\n const flat = convertTableToText(table.cells)\n return table.caption ? captionedText(flat, table.caption, table.captionBelow) : flat\n}\n\n/** 블록 리스트 → 평문 (각주 인라인 포함, 표는 평탄화, 이미지는 제외) — 머리말·각주·캡션용 */\nexport function blocksPlainText(blocks: IRBlock[], sep: string): string {\n const parts: string[] = []\n for (const b of blocks) {\n if (b.type === \"image\") continue\n if (b.type === \"table\") {\n const flat = b.table ? tableFlatText(b.table) : \"\"\n if (flat) parts.push(flat)\n continue\n }\n if (b.text) {\n let t = b.text\n if (b.footnoteText) t += ` (주: ${b.footnoteText})`\n parts.push(t)\n }\n }\n return parts.join(sep).trim()\n}\n\n/**\n * 셀 문단 블록 → 하위 호환 셀 텍스트 (문단 평탄화 + 이미지 표지 + 중첩표 평문).\n * 글자처럼 취급 표와 그 뒤 조각은 앞 줄에 공백으로 잇는다(INLINE_JOIN). 셀 문단의 각주는 문단 글에 접어 넣는다 —\n * HWPX 셀 블록과 같은 IR(블록 text 에 \"(주: …)\"); footnoteText 로 따로 두면 병합 셀 HTML 경로(blocks 직렬화)가\n * 각주를 버렸다. hasStructure = 셀에 blocks 를 달 구조(이미지·중첩표)가 있는가\n */\nexport function cellTextFromBlocks(blocks: IRBlock[]): { text: string; hasStructure: boolean } {\n let text = \"\"\n const add = (part: string, b: IRBlock): void => { text += (text ? (INLINE_JOIN.has(b) ? \" \" : \"\\n\") : \"\") + part }\n let hasStructure = false\n for (const b of blocks) {\n if (b.type === \"image\" && b.text) {\n add(`![image](hwp5bin:${b.text})`, b)\n hasStructure = true\n } else if (b.type === \"table\" && b.table) {\n // flattenLayoutTables 경유 시를 위한 평문 — 구조는 blocks가 보존\n const flat = tableFlatText(b.table)\n if (flat) add(flat, b)\n hasStructure = true\n } else if (b.text) {\n if (b.footnoteText) {\n b.text += ` (주: ${b.footnoteText})`\n delete b.footnoteText\n delete b.footnoteBlocks\n delete b.spans // 접은 각주 글은 span 에 없다 — 평문 경로로\n }\n add(b.text, b)\n // 칸 문단은 HWPX 외래 문서처럼 혼합 가드 — 칸 전체가 굵게·기울임이면(머리 행·라벨 열의 구조 서식) 표지를 달지 않는다.\n // 남은 강조 span 이 있는 칸은 블록째 남긴다(칸 마크다운에 강조 표지)\n if (b.spans && !b.spans.some(s => s.strike || s.underline) && !b.spans.some(s => !(s.bold || s.italic))) delete b.spans\n if (b.spans?.length) hasStructure = true\n }\n }\n return { text, hasStructure }\n}\n\n// ─── 좌표 셀 → IRTable ──────────────────────────────\n\n/** 좌표를 가진 셀 (HWP5 LIST_HEADER colAddr/rowAddr, HWP3 셀 기하에서 복원한 좌표) */\nexport interface AddressedCell extends CellContext {\n blocks?: IRBlock[]\n isHeader?: boolean\n /** 칸의 보이는 변 (셀 borderFillId → DocInfo BORDER_FILL) — IR 칸의 CELL_EDGES 로 */\n edges?: Edges\n}\n\n/**\n * 좌표 셀 겹침 정리 (손상 파일) — 먼저 나온 셀이 칸을 차지한다. 앵커가 앞 셀 영역에 떨어진 셀은 글·구조를\n * 앞 셀에 이어 붙이고(한컴은 겹쳐 그릴 뿐 글을 버리지 않는다), 앞 셀 영역을 덮는 병합은 겹치지 않을 때까지\n * 줄인다. builder 직접 배치는 뒤 셀이 앞 앵커를 덮어써 글이 사라진다. 정상 표는 입력 그대로(같은 객체) 통과\n */\nfunction resolveCellOverlaps<T extends AddressedCell>(cells: T[], rows: number, cols: number): T[] {\n const owner = new Map<number, T>()\n const out: T[] = []\n for (const cell of cells) {\n const r0 = cell.rowAddr ?? 0, c0 = cell.colAddr ?? 0\n const hit = owner.get(r0 * cols + c0)\n if (hit) {\n if (cell.blocks?.length) {\n hit.blocks = [...(hit.blocks ?? (hit.text ? [{ type: \"paragraph\" as const, text: hit.text }] : [])), ...cell.blocks]\n }\n if (cell.text.trim()) hit.text = hit.text.trim() ? `${hit.text}\\n${cell.text}` : cell.text\n continue\n }\n // 첫 행에서 먼저 차지된 열 앞까지, 그 폭으로 먼저 차지된 행 앞까지 줄인다(표 안 칸만 한 번씩 훑는다).\n // 겹침이 없으면 span 을 건드리지 않는다 — 표 밖으로 뻗은 span 도 종전대로 builder 에 맡긴다\n const csIn = Math.max(1, Math.min(cell.colSpan, cols - c0))\n let cs = cell.colSpan\n for (let c = c0 + 1; c < c0 + csIn; c++) if (owner.has(r0 * cols + c)) { cs = c - c0; break }\n const rsIn = Math.max(1, Math.min(cell.rowSpan, rows - r0))\n let rs = cell.rowSpan\n scan: for (let r = r0 + 1; r < r0 + rsIn; r++) {\n for (let c = c0; c < c0 + Math.min(cs, csIn); c++) if (owner.has(r * cols + c)) { rs = r - r0; break scan }\n }\n const placed = cs === cell.colSpan && rs === cell.rowSpan ? cell : { ...cell, colSpan: cs, rowSpan: rs }\n for (let r = r0; r < Math.min(r0 + rs, rows); r++) for (let c = c0; c < Math.min(c0 + cs, cols); c++) owner.set(r * cols + c, placed)\n out.push(placed)\n }\n return out\n}\n\n/**\n * 좌표 셀 → IRTable — HWPX(table-build.ts)와 같은 builder 직접 배치(buildTableDirect)를 태워 표 계약\n * (후행 빈 열 트림 + 잘린 열에 걸친 span 절단, keepAnchoredEmptyCols 면 앵커 열 보존)을 맞춘다. HWP5 종전 경로는\n * 자체 그리드를 그대로 IRTable 로 내 빈 입력란 열이 남았다 — 같은 문서 HWPX 보다 1~9열 넓음(서식 표 300+ 실측).\n * 행 묶음은 rowAddr 기준(HWPX <tr> 과 같은 경계), 셀 blocks·제목 셀은 좌표로 재부착.\n * 손상 레코드(행·열 0, 표 밖 앵커)는 표를 버리지 않고 셀 좌표까지 넓힌다 — 글 손실 금지\n */\nexport function buildAddressedTable(cells: AddressedCell[], rows: number, cols: number, keepAnchoredEmptyCols?: boolean): IRTable | null {\n for (const c of cells) {\n rows = Math.max(rows, Math.min((c.rowAddr ?? 0) + 1, MAX_ROWS))\n cols = Math.max(cols, Math.min((c.colAddr ?? 0) + 1, MAX_COLS))\n }\n const placed = resolveCellOverlaps(cells, rows, cols)\n const byRow: AddressedCell[][] = Array.from({ length: rows }, () => [])\n for (const c of placed) {\n const r = c.rowAddr ?? 0\n if (r < rows && (c.colAddr ?? 0) < cols) byRow[r].push(c)\n }\n const table = buildTable(byRow, { keepAnchoredEmptyCols })\n if (table.rows === 0) return null\n for (const c of placed) {\n // 보이는 변은 글 대조 없이 좌표 자리 칸에 — 빈 칸도 테두리를 가진다\n if (c.edges) {\n const at = table.cells[c.rowAddr ?? 0]?.[c.colAddr ?? 0]\n if (at) CELL_EDGES.set(at, c.edges)\n }\n if (!c.blocks?.length && !c.isHeader) continue\n const target = table.cells[c.rowAddr ?? 0]?.[c.colAddr ?? 0]\n // 겹친 앵커로 합쳐진 셀·잘린 열의 앵커는 텍스트가 달라 붙지 않는다\n if (!target || target.text !== c.text.trim()) continue\n if (c.blocks?.length) target.blocks = c.blocks\n if (c.isHeader) target.isHeader = true\n }\n return table\n}\n","/** HWP 5.x 본문 파서 — 섹션 레코드 → 문단 리스트·컨트롤 디스패치(표·그리기 개체·수식·각주·머리말·필드) → IRBlock */\n\nimport { tidyScriptTags, type ScriptKind } from \"../script-tags.js\"\nimport {\n extractEquationText, createParaTextState, appendParaText, LITERAL_DOLLAR_MARK, LITERAL_LT_MARK, resolveLiteralLt, TAG_PARA_HEADER, TAG_PARA_TEXT, TAG_CHAR_SHAPE,\n TAG_CTRL_HEADER, TAG_LIST_HEADER, TAG_TABLE, TAG_EQEDIT, TAG_SHAPE_COMPONENT, TAG_SHAPE_COMPONENT_CONTAINER,\n TAG_SHAPE_COMPONENT_PICTURE, TAG_MEMO_LIST, fileTimeText, extractText, type HwpRecord, type HwpDocInfo, type IndexedControlResolver, type ParaTextState,\n} from \"./record.js\"\nimport { NumberingState, expandNumberingFormat, formatNumber, shapeFormatToNumFmt } from \"./numbering.js\"\nimport { hwpEquationToLatex } from \"./equation.js\"\nimport { buildTable, flattenLayoutTables, markNonLayoutTable, MAX_COLS, MAX_ROWS } from \"../table/builder.js\"\nimport {\n INLINE_TABLE_MARK, blocksPlainText, buildAddressedTable, cellTextFromBlocks, emitParagraphBlocks,\n} from \"./ir-assemble.js\"\nimport type { CellContext, IRBlock, IRTable, IRSpan, MemoNote, ParseOptions, ParseWarning, InlineStyle } from \"../types.js\"\nimport type { Edges } from \"../table/layout-frames.js\"\nimport { sanitizeHref } from \"../utils.js\"\nimport { takeTocLeaders } from \"../toc-entry.js\"\nimport { composeText } from \"../shared/pua.js\"\n\n/** 중첩표/글상자 재귀 깊이 상한 — 표 \"중첩 단계\" 기준.\n * 실무 문서 중첩은 2~3단이라 8이면 충분하며, 바이너리 파싱 비용상\n * filler/소스맵(16)보다 보수적으로 둔다. hwpx MAX_XML_DEPTH(200)는\n * XML 요소 깊이라 좌표계가 다름 — 상수 통일 대상 아님 */\nconst MAX_NEST_DEPTH = 8\n\n// ─── 컨트롤 ID (u32 LE 정규화) ───────────────────────\n// HWP는 ctrl_id를 DWORD(LE)로 저장한다. \"tbl \"은 파일에 [0x20,0x6c,0x62,0x74](\" lbt\")로\n// 기록되므로, readUInt32LE로 읽으면 BE 문자열 상수 0x74626c20과 일치한다 (rhwp tags.rs 방식).\n\n/** 4바이트 ASCII 문자열 → u32 컨트롤 ID 상수 (\"tbl \" → 0x74626c20) */\nfunction cid(s: string): number {\n return ((s.charCodeAt(0) << 24) | (s.charCodeAt(1) << 16) | (s.charCodeAt(2) << 8) | s.charCodeAt(3)) >>> 0\n}\n\nconst CTRL_TBL = cid(\"tbl \") // 표\nconst CTRL_GSO = cid(\"gso \") // 그리기 개체 (그림/글상자)\nconst CTRL_EQED = cid(\"eqed\") // 수식\nconst CTRL_HEAD = cid(\"head\") // 머리말\nconst CTRL_FOOT = cid(\"foot\") // 꼬리말\nconst CTRL_FN = cid(\"fn \") // 각주\nconst CTRL_EN = cid(\"en \") // 미주\nconst CTRL_ATNO = cid(\"atno\") // 자동 번호\nconst CTRL_NWNO = cid(\"nwno\") // 새 번호\nconst CTRL_PGNP = cid(\"pgnp\") // 쪽 번호 위치\nconst CTRL_PGHD = cid(\"pghd\") // 감추기\nconst CTRL_IDXM = cid(\"idxm\") // 찾아보기 표식\nconst CTRL_BOKM = cid(\"bokm\") // 책갈피\nconst CTRL_TCPS = cid(\"tcps\") // 글자 겹침\nconst CTRL_TDUT = cid(\"tdut\") // 덧말\nconst CTRL_TCMT = cid(\"tcmt\") // 숨은 설명\nconst CTRL_SECD = cid(\"secd\") // 구역 정의\nconst CTRL_COLD = cid(\"cold\") // 단 정의\nconst CTRL_FORM = cid(\"form\") // 양식 개체\nconst CTRL_OLE = cid(\"ole \") // OLE 개체\nconst FIELD_HLK = cid(\"%hlk\") // 필드: 하이퍼링크\nconst FIELD_CLK = cid(\"%clk\") // 필드: 누름틀\nconst FIELD_UNK = cid(\"%unk\") // 필드: 그 밖(메모 \"MEMO/…\" 명령)\n/**\n * HWPX run-spans 가 강조를 내지 않는 문단의 컨트롤 — run 자식이 되는 개체(표·그리기·수식·양식·OLE·글자 겹침·덧말)와 글을 담은 ctrl:\n * 찾아보기 표식·필드('%' 로 시작)는 열쇠·매개변수 글을 늘 담고, 각주·미주·머리말·꼬리말·숨은 설명은 안쪽 문단에 글이 있을 때만\n */\nconst NO_SPAN_CTRLS = new Set([cid(\"tbl \"), cid(\"gso \"), cid(\"eqed\"), cid(\"form\"), cid(\"ole \"), cid(\"tcps\"), cid(\"tdut\"), cid(\"idxm\")])\nconst TEXT_CTRLS = new Set([cid(\"fn \"), cid(\"en \"), cid(\"head\"), cid(\"foot\"), cid(\"tcmt\")])\nconst isFieldCtrl = (id: number): boolean => id >>> 24 === 0x25\n\nconst KNOWN_CTRL_IDS = new Set([\n CTRL_TBL, CTRL_GSO, CTRL_EQED, CTRL_HEAD, CTRL_FOOT, CTRL_FN, CTRL_EN,\n CTRL_ATNO, CTRL_NWNO, CTRL_PGNP, CTRL_PGHD, CTRL_IDXM, CTRL_BOKM,\n CTRL_TCPS, CTRL_TDUT, CTRL_TCMT, CTRL_SECD, CTRL_COLD, CTRL_FORM, CTRL_OLE,\n])\n\n/** 필드 컨트롤 여부 (첫 바이트 '%') */\nfunction isFieldCtrlId(id: number): boolean {\n return (id >>> 24) === 0x25\n}\n\n/** 바이트 순서 뒤집기 — 비표준 작성기의 BE 저장 ctrl_id 방어 */\nfunction swap32(id: number): number {\n return (((id & 0xff) << 24) | (((id >>> 8) & 0xff) << 16) | (((id >>> 16) & 0xff) << 8) | ((id >>> 24) & 0xff)) >>> 0\n}\n\n/** LE로 읽은 ctrl_id를 정규화 — 알려진 ID/필드가 아니고 스왑하면 일치할 때만 스왑 */\nfunction normalizeCtrlId(raw: number): number {\n if (KNOWN_CTRL_IDS.has(raw) || isFieldCtrlId(raw)) return raw\n const sw = swap32(raw)\n if (KNOWN_CTRL_IDS.has(sw) || isFieldCtrlId(sw)) return sw\n return raw\n}\n\n// ─── 수식 ────────────────────────────────────────────\n\nfunction formatEquationForMarkdown(equation: string): string {\n const normalized = hwpEquationToLatex(equation)\n if (!normalized) return \"\"\n return `$${normalized.replace(/\\$/g, \"\\\\$\")}$`\n}\n\n/** 컨트롤 자식 레코드 범위에서 EQEDIT 수식 추출 */\nfunction extractEquationFromSlice(records: HwpRecord[], start: number, end: number): string | null {\n for (let i = start; i < end; i++) {\n if (records[i].tagId !== TAG_EQEDIT) continue\n const equation = extractEquationText(records[i].data)\n return equation ? formatEquationForMarkdown(equation) : null\n }\n return null\n}\n\n// ─── 본문 파싱 (문단 리스트 + 컨트롤 디스패치) ───────\n\n/** 문서 전역 파싱 상태 — 섹션 간 유지 (번호 카운터, 머리말/꼬리말 등) */\nexport interface Hwp5DocState {\n numbering: NumberingState\n /** 구역 정의(secd)의 개요 번호 ID */\n outlineNumberingId: number\n /** 자동 번호 종류(0=쪽,1=각주,2=미주,3=그림,4=표,5=수식)별 다음 번호 */\n autoCounters: Map<number, number>\n headerTexts: Set<string>\n /** 목차 항목 글 — 표 칸에서 풀려 나온 문단도 제목 추정에서 뺀다 (#121, HWPX SectionShared.tocTexts 와 같은 구실) */\n tocTexts: Set<string>\n headerBlocks: IRBlock[]\n footerBlocks: IRBlock[]\n /** 표 후행 빈 열(앵커 있는 입력란) 보존 — ParseOptions.keepTrailingEmptyCols (#47) */\n keepTrailingEmptyCols?: boolean\n /** 미기입 누름틀 안내문도 본문에 — ParseOptions.includeFieldPlaceholders (#92) */\n includeFieldPlaceholders?: boolean\n /** 메모 (#180) — 붙은 글은 문단을 읽을 때, 메모 글은 구역 끝 메모 목록에서 채운다 */\n memos: MemoNote[]\n}\n\nexport function createHwp5DocState(): Hwp5DocState {\n return {\n numbering: new NumberingState(),\n outlineNumberingId: 0,\n autoCounters: new Map(),\n headerTexts: new Set(),\n tocTexts: new Set(),\n headerBlocks: [],\n footerBlocks: [],\n memos: [],\n }\n}\n\ninterface Hwp5Ctx {\n docInfo: HwpDocInfo | null\n warnings: ParseWarning[]\n sectionNum: number\n doc: Hwp5DocState\n depth: number\n /** 현재 페이지 (#66) — layout 모드에서 top-level 문단마다 갱신, 셀/중첩은 호스트 상속.\n * 섹션 근사 모드에선 sectionNum 고정 */\n page: number\n /** 프리패스 페이지 맵 — base: 이전 섹션 누적 페이지, pageAtPara: top-level 문단 순번별 페이지 */\n pageMap?: { base: number; pageAtPara: number[] }\n /** 지금까지 만난 top-level 문단 수 (pageAtPara 인덱스) */\n topOrdinal: number\n /** 표 CTRL_HEADER 레코드 인덱스 → sourceId (table-ids.ts 프리패스, 렌더 region 조인 키 #76) */\n tableIds?: Map<number, string>\n /** 글상자 바로 안 문단 — HWPX drawText 문단처럼 강조 span 없이 평문 (글상자 안 표 칸은 칸 경로라 다시 끈다) */\n plainText?: boolean\n}\n\n/** 섹션 레코드 → IRBlock[] (테스트에서 직접 사용 가능하도록 export) */\nexport function parseSection(\n records: HwpRecord[],\n docInfo: HwpDocInfo | null,\n warnings: ParseWarning[],\n sectionNum: number,\n doc?: Hwp5DocState,\n pageMap?: { base: number; pageAtPara: number[] },\n tableIds?: Map<number, string>,\n): IRBlock[] {\n const ctx: Hwp5Ctx = {\n docInfo, warnings, sectionNum, doc: doc ?? createHwp5DocState(), depth: 0,\n page: pageMap ? pageMap.base + 1 : sectionNum, pageMap, topOrdinal: 0, tableIds,\n }\n const memoStart = ctx.doc.memos.length\n const blocks = parseParagraphList(records, 0, records.length, ctx)\n if (ctx.doc.memos.length > memoStart) fillMemoTexts(records, ctx.doc.memos.slice(memoStart), ctx)\n return blocks\n}\n\n/**\n * 메모 글 — 구역 마지막 문단 밑의 메모 목록(MEMO_LIST 번호 → 크기 없는 LIST_HEADER → 문단들)에서 번호로 찾아 채운다 (#180,\n * HWP→HWPX 변환기 sectionXml 과 같은 읽기)\n */\nfunction fillMemoTexts(records: HwpRecord[], memos: MemoNote[], ctx: Hwp5Ctx): void {\n const texts = new Map<number, string>()\n for (let i = 0; i < records.length; i++) {\n if (records[i].tagId !== TAG_MEMO_LIST || records[i].data.length < 4) continue\n const num = records[i].data.readUInt32LE(0), level = records[i].level\n let k = i + 1\n if (records[k]?.tagId !== TAG_LIST_HEADER || records[k].level !== level) continue\n // 메모 문단마다 PARA_TEXT 글만 (문단 머리 번호를 풀지 않는다: 본문 번호 카운터를 건드리지 않게)\n const paras: string[] = []\n for (k++; k < records.length && records[k].level >= level && records[k].tagId !== TAG_MEMO_LIST; k++) {\n if (records[k].tagId !== TAG_PARA_HEADER || records[k].level !== level) continue\n let t = \"\"\n for (let e = k + 1; e < records.length && records[e].level > level; e++) if (records[e].tagId === TAG_PARA_TEXT) t += extractText(records[e].data)\n t = t.replace(/[\\u0000-\\u0008\\u000b-\\u001f]/g, \"\").replace(/[ \\t]+/g, \" \").trim()\n if (t) paras.push(t)\n }\n texts.set(num, paras.join(\"\\n\"))\n }\n for (const m of memos) if (m.number !== undefined && texts.has(m.number)) m.text = texts.get(m.number)!\n}\n\n/**\n * 레코드 범위에서 문단 리스트 파싱 (rhwp body_text.rs parse_paragraph_list 패턴).\n * 표 셀/글상자/머리말/각주 내부에서도 동일하게 재귀 사용된다.\n */\nfunction parseParagraphList(records: HwpRecord[], start: number, end: number, ctx: Hwp5Ctx): IRBlock[] {\n const blocks: IRBlock[] = []\n let i = start\n while (i < end) {\n if (records[i].tagId === TAG_PARA_HEADER) {\n const baseLevel = records[i].level\n // 실제 페이지 갱신 (#66) — 프리패스의 top-level 문단 열거와 같은 순서(level 0)\n if (baseLevel === 0 && ctx.depth === 0 && ctx.pageMap) {\n const pg = ctx.pageMap.pageAtPara[ctx.topOrdinal]\n if (pg !== undefined) ctx.page = ctx.pageMap.base + pg + 1\n ctx.topOrdinal++\n }\n let j = i + 1\n while (j < end && records[j].level > baseLevel) j++\n blocks.push(...parseParagraph(records, i, j, ctx))\n i = j\n } else {\n i++\n }\n }\n return blocks\n}\n\n/** 문단 내 CTRL_HEADER 1개의 파싱 상태 */\ninterface ParsedCtrl {\n /** 정규화된 컨트롤 ID (u32, BE 문자열 상수와 비교 가능) */\n id: number\n /** LE로 읽은 원본 ID — PARA_TEXT 인라인 컨트롤과의 대조용 */\n idRaw: number\n /** CTRL_HEADER 레코드 데이터 (ctrl_id 4바이트 포함) */\n data: Buffer\n childStart: number\n childEnd: number\n /** 인라인 치환 텍스트 (수식/자동번호/각주 마커) */\n inlineText?: string\n /** 문단 뒤에 붙는 블록 (표/이미지/글상자) */\n afterBlocks?: IRBlock[]\n /** 각주/미주 내용 (\"1) 내용\" 형식) */\n footnote?: string\n /** 각주/미주 본문 블록(머리 번호 포함, 그림 제외) — 주석 안 표를 IRBlock.footnoteBlocks 로 (#149) */\n noteBlocks?: IRBlock[]\n /** 주석 본문에 표가 있는가 */\n noteHasTable?: boolean\n /** 하이퍼링크 URL (%hlk) */\n href?: string\n /** 미기입 누름틀(%clk, 속성 bit 15 = 0)의 안내문 — 본문 run 에 같은 글이 있으면 값이 아니다 */\n guide?: string\n /** 메모('%unk' 필드 \"MEMO/모양/번호/시각 하위/상위/작성자/\") — 메모 글은 구역 끝 목록 (#180) */\n memo?: Pick<MemoNote, \"number\" | \"author\" | \"createdAt\">\n /** resolver 중복 매칭 방지 */\n resolved?: boolean\n}\n\n/** 문단 1개 파싱 → [문단 블록?, ...컨트롤 파생 블록] */\nfunction parseParagraph(records: HwpRecord[], start: number, end: number, ctx: Hwp5Ctx): IRBlock[] {\n const header = records[start]\n const baseLevel = header.level\n const paraShapeId = header.data.length >= 10 ? header.data.readUInt16LE(8) : -1\n\n const textRecords: Buffer[] = []\n const charShapeIds: number[] = []\n /** 글자 모양 위치표 [WCHAR 위치, charShapeId] — 첨자 판정 */\n const charShapeRuns: Array<[number, number]> = []\n const ctrls: ParsedCtrl[] = []\n\n let i = start + 1\n while (i < end) {\n const rec = records[i]\n\n if (rec.tagId === TAG_CTRL_HEADER && rec.level === baseLevel + 1 && rec.data.length >= 4) {\n // 컨트롤 자식 레코드 범위 수집 (rhwp parse_paragraph 패턴)\n const childStart = i + 1\n let j = childStart\n while (j < end && records[j].level > baseLevel + 1) j++\n const idRaw = rec.data.readUInt32LE(0)\n ctrls.push({ id: normalizeCtrlId(idRaw), idRaw, data: rec.data, childStart, childEnd: j })\n i = j\n continue\n }\n\n if (rec.tagId === TAG_PARA_TEXT && rec.level === baseLevel + 1) {\n textRecords.push(rec.data)\n } else if (rec.tagId === TAG_CHAR_SHAPE && rec.level === baseLevel + 1 && rec.data.length >= 8) {\n // 구조: [position(u32) + charShapeId(u32)] * N\n for (let offset = 0; offset + 7 < rec.data.length; offset += 8) {\n charShapeIds.push(rec.data.readUInt32LE(offset + 4))\n charShapeRuns.push([rec.data.readUInt32LE(offset), rec.data.readUInt32LE(offset + 4)])\n }\n }\n i++\n }\n\n // 컨트롤별 효과 계산 (인라인 치환/파생 블록/각주/링크)\n for (const ctrl of ctrls) {\n applyCtrlEffect(ctrl, records, ctx)\n // 글자처럼 취급 표는 문단 글 흐름 안의 자리 — 표지를 심어 앞뒤 글을 나눈다 (#49/#50 HWPX 대칭)\n if (ctrl.id === CTRL_TBL && ctrl.afterBlocks && ctrl.data.length >= 8 && (ctrl.data.readUInt32LE(4) & 1)) {\n ctrl.inlineText = INLINE_TABLE_MARK\n }\n }\n\n // 텍스트 렌더링 — 확장 컨트롤 인덱스 ↔ CTRL_HEADER 순서 매핑\n const state = createParaTextState()\n state.dollarMark = true\n state.tocLeaders = true\n state.scriptAt = scriptLookup(charShapeRuns, ctx.docInfo)\n state.emphAt = emphasisLookup(charShapeRuns, ctx.docInfo)\n let inlined = false\n const resolver: IndexedControlResolver = (idx, id) => {\n let ctrl = idx >= 0 && idx < ctrls.length ? ctrls[idx] : undefined\n if (!ctrl || (ctrl.idRaw !== id && ctrl.id !== id)) {\n ctrl = ctrls.find(c => !c.resolved && (c.idRaw === id || c.id === id))\n }\n if (!ctrl) return null\n ctrl.resolved = true\n if (ctrl.inlineText) inlined = true\n return ctrl.inlineText ?? null\n }\n for (const data of textRecords) {\n appendParaText(state, data, resolver)\n }\n\n // FIELD_BEGIN/END 범위 — 시작 위치 내림차순으로 안전하게 치환. 하이퍼링크는 [anchor](url),\n // 미기입 누름틀의 안내문 run 은 지운다(한컴은 화면에만 흐리게 보이고 인쇄하지 않는다 — PDF 실측)\n let text = state.text\n let fieldsApplied = false\n const memoAnchors: Array<NonNullable<ParsedCtrl[\"memo\"]> & { raw: string }> = []\n if (state.fieldRanges.length > 0) {\n const ranges = [...state.fieldRanges].sort((a, b) => b.start - a.start)\n const applied: Array<[number, number]> = []\n for (const r of ranges) {\n const ctrl = ctrls[r.ctrlIdx]\n if (!ctrl || r.end <= r.start) continue\n // 메모 — 글은 그대로 두고 붙은 글만 적는다 (#180)\n if (ctrl.memo) { memoAnchors.push({ ...ctrl.memo, raw: text.slice(r.start, r.end) }); continue }\n if (applied.some(([s, e]) => r.start < e && r.end > s)) continue\n const anchor = text.slice(r.start, r.end)\n if (ctrl.guide !== undefined) {\n if (ctx.doc.includeFieldPlaceholders) continue\n const plain = anchor.replaceAll(LITERAL_DOLLAR_MARK, \"$\").replaceAll(LITERAL_LT_MARK, \"<\") // 안내문 원문과 맞댄다\n if (isClickHereGuideText(plain, ctrl.guide)) {\n text = text.slice(0, r.start) + text.slice(r.end)\n applied.push([r.start, r.end])\n }\n continue\n }\n if (!ctrl.href) continue\n const href = sanitizeHref(ctrl.href)\n if (!href) continue\n if (!anchor.trim() || anchor.includes(INLINE_TABLE_MARK)) continue\n text = text.slice(0, r.start) + `[${anchor}](${href})` + text.slice(r.end)\n applied.push([r.start, r.end])\n }\n fieldsApplied = applied.length > 0\n }\n // 리터럴 $ → \\$ (필드 위치를 다 쓴 뒤라 이제 두 글자로 늘려도 된다, escapeLiteralDollar 규약)\n if (text.includes(LITERAL_DOLLAR_MARK)) text = text.replaceAll(LITERAL_DOLLAR_MARK, \"\\\\$\")\n text = resolveLiteralLt(text)\n // 글자마다 여닫은 첨자 태그 정리 — HWPX section-walker 와 같은 꼴로\n text = tidyScriptTags(text)\n // 목차 항목(채움 탭 + 쪽 번호 줄) 판정 — 채움 탭 표지는 여기서 보통 탭이 된다 (#121, HWPX 와 같은 규칙)\n const toc = takeTocLeaders(text)\n text = toc.text\n // 인라인 강조 span — HWPX run-spans 와 같은 문단만: 개체·글 담은 컨트롤(필드·각주 등)·강제 줄바꿈이 든 문단은 평문 경로(HWPX 는\n // 그런 문단에서 강조를 내지 않는다), 링크·누름틀 안내문·목차 문단은 글 위치가 어긋나 평문 경로\n const holdsText = (c: ParsedCtrl): boolean => {\n for (let k = c.childStart; k < c.childEnd; k++) {\n if (records[k].tagId !== TAG_PARA_TEXT) continue\n const st = createParaTextState()\n appendParaText(st, records[k].data)\n if (st.text.trim()) return true\n }\n return false\n }\n const noSpan = ctx.plainText || inlined || fieldsApplied || toc.tocEntry || text.includes(\"\\n\")\n || ctrls.some(c => NO_SPAN_CTRLS.has(c.id) || isFieldCtrl(c.id) || (TEXT_CTRLS.has(c.id) && holdsText(c)))\n const spans = !noSpan ? emphasisSpans(state, text) : undefined\n if (memoAnchors.length) {\n const plain = (t: string): string => resolveLiteralLt(t.replaceAll(LITERAL_DOLLAR_MARK, \"$\")).replace(/\\\\</g, \"<\").replace(/[ \\t]+/g, \" \").trim()\n const paragraph = plain(text.replaceAll(INLINE_TABLE_MARK, \"\"))\n for (const { raw, ...memo } of memoAnchors.reverse()) {\n const anchor = plain(raw.replaceAll(INLINE_TABLE_MARK, \"\"))\n ctx.doc.memos.push({ text: \"\", ...memo, anchor, paragraph, offset: Math.max(0, paragraph.indexOf(anchor)) })\n }\n }\n\n // 문단번호/글머리표/개요 처리 (DocInfo PARA_SHAPE headType)\n let headingLevel = 0\n let headMarker: string | null = null\n const ps = ctx.docInfo && paraShapeId >= 0 && paraShapeId < ctx.docInfo.paraShapes.length\n ? ctx.docInfo.paraShapes[paraShapeId]\n : null\n if (ps && ps.headType > 0) {\n if (ps.headType === 1) {\n // 개요 — paraLevel 0-6 → heading 1-6 (개요 7수준은 H6로 클램프). 목차 항목은 개요 문단 모양을 빌려도 제목이 아니다\n if (!toc.tocEntry) headingLevel = Math.min(ps.paraLevel + 1, 6)\n }\n if (ps.headType === 1 || ps.headType === 2) {\n // 개요/번호 → NUMBERING 카운터 전진 + ^N 치환\n const nid = ps.numberingId || (ps.headType === 1 ? ctx.doc.outlineNumberingId : 0)\n const numbering = nid >= 1 ? ctx.docInfo?.numberings[nid - 1] : undefined\n if (numbering) {\n const counters = ctx.doc.numbering.advance(nid, ps.paraLevel)\n const fmt = numbering.levelFormats[Math.min(ps.paraLevel, 6)]\n if (fmt) {\n const headText = expandNumberingFormat(fmt, counters, numbering)\n if (headText) headMarker = headText\n }\n }\n } else if (ps.headType === 3) {\n // 글머리표 — U+FFFF는 이미지 글머리표 (문자 렌더링 불가)\n const bullet = ps.numberingId >= 1 ? ctx.docInfo?.bullets[ps.numberingId - 1] : undefined\n if (bullet && bullet.char !== \"￿\") headMarker = bullet.char\n }\n }\n\n if (toc.tocEntry) for (const line of text.split(\"\\n\")) if (line.trim()) {\n ctx.doc.tocTexts.add(line.trim())\n if (headMarker) ctx.doc.tocTexts.add(`${headMarker} ${line.trim()}`)\n }\n return emitParagraphBlocks({\n text,\n headMarker,\n headingLevel,\n tocEntry: toc.tocEntry,\n style: ctx.docInfo && charShapeIds.length > 0 ? resolveCharStyle(charShapeIds, ctx.docInfo) : undefined,\n footnotes: ctrls.filter(c => c.footnote).map(c => c.footnote!),\n footnoteBlocks: ctrls.some(c => c.noteHasTable) ? ctrls.flatMap(c => c.footnote ? c.noteBlocks ?? [] : []) : undefined,\n // 컨트롤 파생 블록 (표/이미지/글상자) — 컨트롤 순서대로\n objects: ctrls.filter(c => c.afterBlocks).map(c => ({ blocks: c.afterBlocks!, table: c.id === CTRL_TBL, inline: c.inlineText === INLINE_TABLE_MARK })),\n pageNumber: ctx.page,\n spans,\n })\n}\n\n/** 컨트롤 종류별 디스패치 (rhwp control.rs parse_control 대응) */\nfunction applyCtrlEffect(ctrl: ParsedCtrl, records: HwpRecord[], ctx: Hwp5Ctx): void {\n switch (ctrl.id) {\n case CTRL_TBL: {\n const table = parseTableControl(ctrl, records, ctx)\n if (table) ctrl.afterBlocks = [{ type: \"table\", table, pageNumber: ctx.page }]\n return\n }\n case CTRL_GSO: {\n const blocks = parseGsoControl(ctrl, records, ctx)\n if (blocks.length > 0) ctrl.afterBlocks = blocks\n return\n }\n case CTRL_EQED: {\n const eq = extractEquationFromSlice(records, ctrl.childStart, ctrl.childEnd)\n if (eq) ctrl.inlineText = eq\n return\n }\n case CTRL_FN:\n case CTRL_EN: {\n applyNoteEffect(ctrl, records, ctx, ctrl.id === CTRL_FN ? 1 : 2)\n return\n }\n case CTRL_HEAD:\n case CTRL_FOOT: {\n applyHeaderFooterEffect(ctrl, records, ctx, ctrl.id === CTRL_HEAD)\n return\n }\n case CTRL_ATNO: {\n // 자동 번호 (표 144): attr(u32) + number(u16) + 사용자기호 + 앞장식 + 뒤장식 (WCHAR)\n if (ctrl.data.length >= 8) {\n const attr = ctrl.data.readUInt32LE(4)\n const type = attr & 0x0f\n const format = (attr >>> 4) & 0xff\n const num = ctx.doc.autoCounters.get(type) ?? 1\n ctx.doc.autoCounters.set(type, num + 1)\n const prefix = ctrl.data.length >= 14 ? wcharAt(ctrl.data, 12) : \"\"\n const suffix = ctrl.data.length >= 16 ? wcharAt(ctrl.data, 14) : \"\"\n ctrl.inlineText = `${prefix}${formatNumber(num, shapeFormatToNumFmt(format))}${suffix}`\n }\n return\n }\n case CTRL_NWNO: {\n // 새 번호 지정 — 해당 종류의 카운터를 재설정 (표시 없음)\n if (ctrl.data.length >= 10) {\n const attr = ctrl.data.readUInt32LE(4)\n const type = attr & 0x0f\n const num = ctrl.data.readUInt16LE(8)\n if (num > 0) ctx.doc.autoCounters.set(type, num)\n }\n return\n }\n case CTRL_SECD: {\n // 구역 정의 — 개요 번호 ID (ctrl_id 4 + flags 4 + 간격 2*3 + tab 4 = offset 18)\n if (ctrl.data.length >= 20) {\n ctx.doc.outlineNumberingId = ctrl.data.readUInt16LE(18)\n }\n return\n }\n case CTRL_OLE: {\n ctx.warnings.push({ page: ctx.page, message: \"스킵된 OLE 개체\", code: \"SKIPPED_OLE\" })\n return\n }\n // 글자 겹침 — ctrl id 뒤 글자 수(WORD)·겹친 글자(WCHAR[n])·테두리 종류(BYTE, 0 = 없음). 종전엔 건너뛰어 법령 서식 원 번호(⑯·⑰)가 빠졌다\n case CTRL_TCPS: {\n const d = ctrl.data, n = d.length >= 6 ? d.readUInt16LE(4) : 0\n if (n > 0 && d.length >= 6 + 2 * n) ctrl.inlineText = composeText(d.toString(\"utf16le\", 6, 6 + 2 * n), (d[6 + 2 * n] ?? 0) !== 0)\n return\n }\n // 숨은 설명/단 정의/쪽번호 위치/감추기/찾아보기/책갈피/덧말 — 본문 텍스트 없음 또는 의도적 스킵\n case CTRL_TCMT:\n case CTRL_COLD:\n case CTRL_PGNP:\n case CTRL_PGHD:\n case CTRL_IDXM:\n case CTRL_BOKM:\n case CTRL_TDUT:\n case CTRL_FORM:\n return\n default: {\n if (isFieldCtrlId(ctrl.id)) {\n applyFieldEffect(ctrl)\n return\n }\n // 알 수 없는 컨트롤 — LIST_HEADER 문단 리스트가 있으면 텍스트 보존 (정보손실 방지)\n const blocks = parseListHeaderParagraphs(ctrl, records, ctx)\n if (blocks.length > 0) ctrl.afterBlocks = blocks\n }\n }\n}\n\n/** WCHAR 1글자 읽기 (0이면 빈 문자열) */\nfunction wcharAt(data: Buffer, offset: number): string {\n const code = data.readUInt16LE(offset)\n return code > 0 ? String.fromCharCode(code) : \"\"\n}\n\n/** 컨트롤 자식에서 첫 LIST_HEADER 이후의 문단 리스트 파싱 (rhwp find_list_header_paragraphs) */\nfunction parseListHeaderParagraphs(ctrl: ParsedCtrl, records: HwpRecord[], ctx: Hwp5Ctx): IRBlock[] {\n if (ctx.depth >= MAX_NEST_DEPTH) return []\n for (let i = ctrl.childStart; i < ctrl.childEnd; i++) {\n if (records[i].tagId === TAG_LIST_HEADER) {\n return parseParagraphList(records, i + 1, ctrl.childEnd, { ...ctx, depth: ctx.depth + 1 })\n }\n }\n return []\n}\n\n/** 각주('fn ')/미주('en ') — 번호 + 장식문자 + 내용 (rhwp parse_footnote_control) */\nfunction applyNoteEffect(ctrl: ParsedCtrl, records: HwpRecord[], ctx: Hwp5Ctx, autoType: number): void {\n // ctrl 데이터: ctrl_id(4) + number(u32) + before(WCHAR) + after(WCHAR) + numberShape(u32)\n // 번호는 각주 내용 안의 atno(자동번호)가 같은 카운터를 소비하므로 peek만 하고,\n // 내용 파싱 후 카운터가 안 움직였으면(atno 없음) 직접 전진시킨다 (rhwp assign_auto_numbers 정합)\n const num = ctx.doc.autoCounters.get(autoType) ?? 1\n\n let before = \"\"\n let after = \"\"\n let shape = 0\n if (ctrl.data.length >= 12) {\n before = wcharAt(ctrl.data, 8)\n after = wcharAt(ctrl.data, 10)\n }\n if (ctrl.data.length >= 16) {\n shape = ctrl.data.readUInt32LE(12) & 0xff\n }\n const formatted = formatNumber(num, shapeFormatToNumFmt(shape))\n const marker = before || after ? `${before}${formatted}${after}` : `${formatted})`\n\n const blocks = parseListHeaderParagraphs(ctrl, records, ctx)\n const content = blocksPlainText(blocks, \" \")\n if ((ctx.doc.autoCounters.get(autoType) ?? 1) <= num) {\n ctx.doc.autoCounters.set(autoType, num + 1)\n }\n ctrl.inlineText = marker\n // 각주 내용 첫머리의 atno가 이미 같은 마커를 생성했으면 중복 방지\n if (content) ctrl.footnote = content.startsWith(marker) ? content : `${marker} ${content}`\n // 주석 본문 구조 — HWPX collectSubListContent 와 같은 모양(글·표, 그림 제외, 머리 번호는 footnote 와 같게) (#149)\n if (content) {\n const kept = blocks.filter(b => b.type !== \"image\")\n ctrl.noteBlocks = content.startsWith(marker) ? kept : [{ type: \"paragraph\", text: marker, pageNumber: ctx.page }, ...kept]\n ctrl.noteHasTable = kept.some(b => b.type === \"table\" && b.table)\n }\n}\n\n/** 머리말('head')/꼬리말('foot') — 문서당 1회, 동일 텍스트 중복 제거 */\nfunction applyHeaderFooterEffect(ctrl: ParsedCtrl, records: HwpRecord[], ctx: Hwp5Ctx, isHeader: boolean): void {\n const text = blocksPlainText(parseListHeaderParagraphs(ctrl, records, ctx), \"\\n\")\n if (!text) return\n const key = (isHeader ? \"h:\" : \"f:\") + text\n if (ctx.doc.headerTexts.has(key)) return\n ctx.doc.headerTexts.add(key)\n const block: IRBlock = { type: \"paragraph\", text, pageNumber: ctx.page }\n if (isHeader) ctx.doc.headerBlocks.push(block)\n else ctx.doc.footerBlocks.push(block)\n}\n\n/** 필드 컨트롤(%hlk/%clk 등) — command 파싱 (rhwp parse_field_control, 표 154) */\nfunction applyFieldEffect(ctrl: ParsedCtrl): void {\n if (ctrl.id === FIELD_HLK) {\n const command = parseFieldCommand(ctrl.data)\n if (command) {\n const url = hyperlinkUrlFromCommand(command)\n if (url) ctrl.href = url\n }\n } else if (ctrl.id === FIELD_CLK) {\n // 누름틀 — 속성 bit 15(내용 수정됨)가 꺼진 미기입 필드는 한컴이 안내문(command Direction)을 본문 run 으로\n // 저장해 두고 화면에만 흐리게 그린다(인쇄·PDF 에 없음). 같은 글이면 값이 아니므로 parseParagraph 가 지운다\n // (rhwp clear_initial_field_texts 와 같은 이중 조건 — 수정됨 비트 + 안내문 일치)\n const guide = unfilledClickHereGuide(ctrl.data)\n if (guide) ctrl.guide = guide\n } else if (ctrl.id === FIELD_UNK) {\n const command = parseFieldCommand(ctrl.data)\n if (command?.startsWith(\"MEMO/\")) {\n const [, , num = \"\", low = \"0\", high = \"0\", author = \"\"] = command.split(\"/\")\n const memo: NonNullable<ParsedCtrl[\"memo\"]> = {}\n if (/^\\d+$/.test(num)) memo.number = Number(num)\n if (author) memo.author = author\n if (Number(low) || Number(high)) memo.createdAt = fileTimeText(Number(low) >>> 0, Number(high) >>> 0)\n ctrl.memo = memo\n }\n }\n // 그 밖의 필드: anchor 텍스트는 PARA_TEXT에 있으므로 그대로 보존됨\n}\n\n/** 미기입 누름틀(%clk, 속성 bit 15 = 0)이면 그 안내문, 아니면 undefined — patch 소스맵도 이 규칙으로 안내문을 뺀다 */\nexport function unfilledClickHereGuide(ctrlData: Buffer): string | undefined {\n if (ctrlData.length < 8 || normalizeCtrlId(ctrlData.readUInt32LE(0)) !== FIELD_CLK || ctrlData.readUInt32LE(4) & (1 << 15)) return undefined\n const command = parseFieldCommand(ctrlData)\n return command ? clickHereGuide(command) : undefined\n}\n\n/** 누름틀 값 자리 글이 안내문 그대로인가 (끝 공백 차이는 같다고 본다) */\nexport function isClickHereGuideText(text: string, guide: string): boolean {\n return text === guide || text.trimEnd() === guide\n}\n\n/** 누름틀 command 의 안내문 — `Direction:wstring:<N>:` 뒤 N자 (UTF-16) */\nfunction clickHereGuide(command: string): string | undefined {\n const m = /Direction:wstring:(\\d+):/.exec(command)\n if (!m) return undefined\n const start = m.index + m[0].length\n return command.slice(start, start + Number(m[1])) || undefined\n}\n\n/** 필드 CTRL_HEADER 데이터에서 command 추출 — ctrl_id(4) + 속성(4) + 기타(1) + len(u16) + UTF-16LE */\nfunction parseFieldCommand(data: Buffer): string | null {\n if (data.length < 11) return null\n const cmdLen = data.readUInt16LE(9)\n if (cmdLen === 0) return null\n const start = 11\n const end = start + cmdLen * 2\n if (end > data.length) return null\n return data.subarray(start, end).toString(\"utf16le\").replace(/\\0+$/, \"\")\n}\n\n/** %hlk command에서 URL 추출 — 첫 ';' 구분 토큰 ('\\;' 이스케이프 존중). mailto/책갈피(#) 포함 */\nfunction hyperlinkUrlFromCommand(command: string): string | null {\n let url = \"\"\n for (let i = 0; i < command.length; i++) {\n const c = command[i]\n if (c === \"\\\\\" && i + 1 < command.length) {\n url += command[i + 1]\n i++\n continue\n }\n if (c === \";\") break\n url += c\n }\n url = url.trim()\n return url.length > 0 && url.length < 2000 ? url : null\n}\n\n// ─── 표 파싱 ─────────────────────────────────────────\n\n/** HWP5 셀 — CellContext + 중첩 구조 */\ninterface Hwp5Cell extends CellContext {\n blocks?: IRBlock[]\n isHeader?: boolean\n /** 칸의 보이는 변 (LIST_HEADER borderFillId u16@32 → DocInfo BORDER_FILL) */\n edges?: Edges\n /** 칸 높이가 A4 용지보다 크다 — 여러 쪽에 걸친 칸 */\n pageSpanning?: boolean\n}\n\n/** A4 용지 높이 (HWPUNIT, 297mm) — 이보다 높은 칸은 한 쪽에 들어갈 수 없다 */\nconst A4_HEIGHT = 84188\n\n/** 레이아웃 표 해체(flattenLayoutTables)는 여러 쪽에 걸친 칸이 있는 본문 상자만 — 나머지 표는 같은 문서의 HWPX 처럼 표로 둔다.\n * 보도자료 본문 전체를 9쪽짜리 3×1 상자에 담은 문서(rhwp issue3637)는 표로 두면 문서가 거대한 HTML 칸 하나가 된다 */\nfunction keepUnlessPageSpanning(table: IRTable, cells: Hwp5Cell[]): void {\n if (!cells.some(c => c.pageSpanning)) markNonLayoutTable(table)\n}\n\n/**\n * 표 컨트롤 파싱 (rhwp parse_table_control).\n * HWPTAG_TABLE 레코드 '이전'의 LIST_HEADER는 캡션, '이후'는 셀.\n */\nfunction parseTableControl(ctrl: ParsedCtrl, records: HwpRecord[], ctx: Hwp5Ctx): IRTable | null {\n if (ctx.depth >= MAX_NEST_DEPTH) return null\n const { childStart, childEnd } = ctrl\n // sourceId — CTRL_HEADER 레코드 인덱스(childStart − 1)로 프리패스 순번을 찾는다 (렌더 어댑터와 같은 키)\n const sourceId = ctx.tableIds?.get(childStart - 1)\n\n // HWPTAG_TABLE 레코드에서 행/열 수 — 직계 자식 레벨(CTRL_HEADER + 1)의 것만. 캡션 문단 안 표는 자기 TABLE\n // 레코드를 바깥 TABLE 보다 먼저 방출하므로 첫 TABLE 을 집으면 행/열이 그 표 것이 되고 캡션이 잘린다\n // (rhwp #3528 — 저장 순서 CTRL_HEADER → 캡션 LIST_HEADER·문단 → TABLE → 셀). hwp5-patch 스캔과 같은 규칙\n const directLevel = records[childStart - 1].level + 1\n let rows = 0\n let cols = 0\n let tableIdx = -1\n for (let i = childStart; i < childEnd; i++) {\n if (records[i].tagId === TAG_TABLE && records[i].level === directLevel && records[i].data.length >= 8) {\n rows = Math.min(records[i].data.readUInt16LE(4), MAX_ROWS)\n cols = Math.min(records[i].data.readUInt16LE(6), MAX_COLS)\n tableIdx = i\n break\n }\n }\n if (tableIdx < 0) return null\n\n // 캡션: TABLE 레코드 이전의 LIST_HEADER — 문단 리스트 머리 8바이트 뒤 캡션 속성의 낮은 두 비트가 방향(0 왼쪽·1 오른쪽·2 위·3 아래,\n // 같은 문서 HWPX 의 hp:caption side 와 일치)\n let caption: string | undefined\n let captionBelow = false\n for (let i = childStart; i < tableIdx; i++) {\n if (records[i].tagId === TAG_LIST_HEADER) {\n const capBlocks = parseParagraphList(records, i + 1, tableIdx, { ...ctx, depth: ctx.depth + 1 })\n const capText = blocksPlainText(capBlocks, \" \")\n if (capText) caption = capText\n captionBelow = records[i].data.length >= 12 && (records[i].data.readUInt32LE(8) & 3) === 3\n break\n }\n }\n\n // 셀: TABLE 레코드 이후의 LIST_HEADER\n const cells: Hwp5Cell[] = []\n let i = tableIdx + 1\n while (i < childEnd) {\n const rec = records[i]\n if (rec.tagId === TAG_LIST_HEADER) {\n const cellLevel = rec.level\n let j = i + 1\n while (j < childEnd) {\n const r = records[j]\n if (r.level < cellLevel) break\n if (r.level === cellLevel && (r.tagId === TAG_LIST_HEADER || r.tagId === TAG_TABLE)) break\n j++\n }\n cells.push(parseCell(records, i, j, ctx))\n i = j\n continue\n }\n i++\n }\n\n if (cells.length === 0) return null\n\n // colAddr/rowAddr 절대 좌표 — builder 직접 배치로 HWPX 와 같은 표 계약(후행 빈 열 트림 등, ir-assemble.ts)\n if (cells.some(c => c.colAddr !== undefined && c.rowAddr !== undefined)) {\n const table = buildAddressedTable(cells, rows, cols, ctx.doc.keepTrailingEmptyCols)\n if (!table) return null\n if (caption) table.caption = caption\n if (caption && captionBelow) table.captionBelow = true\n if (sourceId) table.sourceId = sourceId\n keepUnlessPageSpanning(table, cells)\n return table\n }\n\n // 좌표 없는 셀 + 행·열 0 손상 레코드 — 셀마다 한 행으로 (글 손실 금지)\n if (rows === 0 || cols === 0) { rows = Math.min(cells.length, MAX_ROWS); cols = 1 }\n const cellRows = arrangeCells(rows, cols, cells)\n const table = buildTable(cellRows, { keepAnchoredEmptyCols: ctx.doc.keepTrailingEmptyCols })\n if (caption && table.rows > 0) table.caption = caption\n if (caption && captionBelow && table.rows > 0) table.captionBelow = true\n if (sourceId && table.rows > 0) table.sourceId = sourceId\n keepUnlessPageSpanning(table, cells)\n return table.rows > 0 ? table : null\n}\n\n/**\n * 표 셀 파싱 (rhwp parse_cell) — LIST_HEADER 구조:\n * paraCount(u16) + listAttr(u32) + widthRef(u16) + colAddr(u16) + rowAddr(u16) + colSpan(u16) + rowSpan(u16)\n * offset: 0 2 6 8 10 12 14\n * widthRef bit 2 = 제목 셀(is_header).\n * 셀 내부 문단 리스트는 재귀 파싱 — 중첩표는 IRCell.blocks에 IRBlock(type:'table')로 보존.\n */\nfunction parseCell(records: HwpRecord[], lhIdx: number, end: number, ctx: Hwp5Ctx): Hwp5Cell {\n const rec = records[lhIdx]\n let colSpan = 1\n let rowSpan = 1\n let colAddr: number | undefined\n let rowAddr: number | undefined\n let isHeader = false\n if (rec.data.length >= 16) {\n isHeader = (rec.data.readUInt16LE(6) & 0x04) !== 0\n colAddr = rec.data.readUInt16LE(8)\n rowAddr = rec.data.readUInt16LE(10)\n const cs = rec.data.readUInt16LE(12)\n const rs = rec.data.readUInt16LE(14)\n if (cs > 0) colSpan = Math.min(cs, MAX_COLS)\n if (rs > 0) rowSpan = Math.min(rs, MAX_ROWS)\n }\n\n const blocks = ctx.depth < MAX_NEST_DEPTH\n ? parseParagraphList(records, lhIdx + 1, end, { ...ctx, depth: ctx.depth + 1, plainText: false })\n : []\n\n // 하위 호환 텍스트: 문단 평탄화 + 이미지 sentinel + 중첩표 평문 (각주는 문단 글에 접힌다)\n const { text, hasStructure } = cellTextFromBlocks(blocks)\n const cell: Hwp5Cell = { text, colSpan, rowSpan, colAddr, rowAddr }\n if (hasStructure && blocks.length > 0) cell.blocks = blocks\n if (isHeader) cell.isHeader = true\n if (rec.data.length >= 24 && rec.data.readUInt32LE(20) > A4_HEIGHT) cell.pageSpanning = true\n if (rec.data.length >= 34) {\n const borderFillId = rec.data.readUInt16LE(32)\n const definitions = ctx.docInfo?.borderEdges\n // 1-based 목록이 확인되면 0은 선 없음이다. 정의가 없는 파일은 미상으로 유지한다.\n const edges = borderFillId === 0 && definitions?.length\n ? { t: false, b: false, l: false, r: false }\n : definitions?.[borderFillId - 1]\n if (edges) cell.edges = edges\n }\n return cell\n}\n\n/** colAddr 없는 셀(짧은 LIST_HEADER)의 순차 배치 폴백 — 좌표가 있으면 parseTableControl 이 builder 직접 배치 */\nfunction arrangeCells(rows: number, cols: number, cells: Hwp5Cell[]): Hwp5Cell[][] {\n const grid: (Hwp5Cell | null)[][] = Array.from({ length: rows }, () => Array(cols).fill(null))\n let cellIdx = 0\n for (let r = 0; r < rows && cellIdx < cells.length; r++) {\n for (let c = 0; c < cols && cellIdx < cells.length; c++) {\n if (grid[r][c] !== null) continue\n const cell = cells[cellIdx++]\n grid[r][c] = cell\n\n for (let dr = 0; dr < cell.rowSpan; dr++) {\n for (let dc = 0; dc < cell.colSpan; dc++) {\n if (dr === 0 && dc === 0) continue\n if (r + dr < rows && c + dc < cols)\n grid[r + dr][c + dc] = { text: \"\", colSpan: 1, rowSpan: 1 }\n }\n }\n }\n }\n return grid.map(row => row.map(c => c || { text: \"\", colSpan: 1, rowSpan: 1 }))\n}\n\n// ─── 그리기 개체(GSO) 파싱 ───────────────────────────\n\n/**\n * GSO 컨트롤 파싱 (rhwp parse_gso_control).\n * - SHAPE_COMPONENT '이전' LIST_HEADER = 캡션\n * - SHAPE_COMPONENT '이후' 첫 LIST_HEADER = 글상자 문단 리스트\n * - SHAPE_COMPONENT_PICTURE 레코드 → binDataId(고정 오프셋 71) → 이미지 블록\n */\nfunction parseGsoControl(ctrl: ParsedCtrl, records: HwpRecord[], ctx: Hwp5Ctx): IRBlock[] {\n if (ctx.depth >= MAX_NEST_DEPTH) return []\n const { childStart, childEnd } = ctrl\n const blocks: IRBlock[] = []\n\n // 첫 SHAPE_COMPONENT(_CONTAINER) 위치\n let scIdx = -1\n for (let i = childStart; i < childEnd; i++) {\n const t = records[i].tagId\n if (t === TAG_SHAPE_COMPONENT || t === TAG_SHAPE_COMPONENT_CONTAINER) {\n scIdx = i\n break\n }\n }\n\n // 캡션: SHAPE_COMPONENT 이전의 LIST_HEADER\n if (scIdx > childStart) {\n for (let i = childStart; i < scIdx; i++) {\n if (records[i].tagId === TAG_LIST_HEADER) {\n blocks.push(...parseParagraphList(records, i + 1, scIdx, { ...ctx, depth: ctx.depth + 1 }))\n break\n }\n }\n }\n\n // 글상자: SHAPE_COMPONENT 이후 첫 LIST_HEADER부터 끝까지\n const scanStart = scIdx >= 0 ? scIdx + 1 : childStart\n let textListIdx = -1\n for (let i = scanStart; i < childEnd; i++) {\n if (records[i].tagId === TAG_LIST_HEADER) {\n textListIdx = i\n break\n }\n }\n\n // 그림: 글상자 리스트 이전 구간에서 SHAPE_COMPONENT_PICTURE 스캔\n // (글상자 내부의 중첩 gso 그림은 문단 리스트 재귀에서 처리되므로 이중 집계 없음)\n const picEnd = textListIdx >= 0 ? textListIdx : childEnd\n for (let i = scanStart; i < picEnd; i++) {\n if (records[i].tagId === TAG_SHAPE_COMPONENT_PICTURE) {\n const img = pictureToImageBlock(records[i].data, ctx)\n if (img) blocks.push(img)\n }\n }\n\n if (textListIdx >= 0) {\n blocks.push(...parseParagraphList(records, textListIdx + 1, childEnd, { ...ctx, depth: ctx.depth + 1, plainText: true }))\n }\n\n return blocks\n}\n\n/**\n * SHAPE_COMPONENT_PICTURE → 이미지 블록.\n * rhwp parse_picture(shape.rs)의 고정 레이아웃:\n * borderColor(4) + borderWidth(4) + borderAttr(4) + 꼭짓점 x4/y4(32) + crop(16)\n * + padding(8) + 밝기(1)/대비(1)/효과(1) = 71 → binDataId(u16 @71)\n * binDataId는 DocInfo BIN_DATA 1-based 인덱스 → storage_id로 변환 (스트림명 BIN%04X 16진).\n */\nfunction pictureToImageBlock(data: Buffer, ctx: Hwp5Ctx): IRBlock | null {\n if (data.length < 73) return null\n const binDataId = data.readUInt16LE(71)\n if (binDataId === 0) return null\n\n const item = ctx.docInfo?.binData[binDataId - 1]\n if (item?.kind === \"link\") {\n ctx.warnings.push({ page: ctx.page, message: `외부 연결 이미지 (binDataId ${binDataId})`, code: \"SKIPPED_IMAGE\" })\n return null\n }\n // DocInfo BIN_DATA가 없으면 binDataId == storageId 관례에 폴백\n const storageId = item && item.storageId > 0 ? item.storageId : binDataId\n return { type: \"image\", text: String(storageId), pageNumber: ctx.page }\n}\n\n// ─── 스타일 ──────────────────────────────────────────\n\n/**\n * 글자 위치 → 첨자 종류. CharShape attr bit 15 = 위 첨자, bit 16 = 아래 첨자(HWP5 스펙 표 35 — 계량법 별표\n * \"10⁴ m²\" 의 위첨자 글자 모양 id 가 HWPX supscript charPr id 와 같음을 실측). 첨자 글자 모양이 없으면 undefined\n */\nfunction scriptLookup(runs: Array<[number, number]>, docInfo: HwpDocInfo | null): ((pos: number) => ScriptKind | null) | undefined {\n if (!docInfo || !runs.length) return undefined\n const kindOf = (id: number): ScriptKind | null => {\n const f = docInfo.charShapes[id]?.attrFlags ?? 0\n return f & (1 << 15) ? \"sup\" : f & (1 << 16) ? \"sub\" : null\n }\n if (!runs.some(([, id]) => kindOf(id))) return undefined\n let k = -1 // 글자 위치는 늘어나는 순서로 묻는다 — 커서를 앞으로만(되돌아가면 처음부터)\n return (pos) => {\n if (k >= 0 && runs[k][0] > pos) k = -1\n while (k + 1 < runs.length && runs[k + 1][0] <= pos) k++\n return k >= 0 ? kindOf(runs[k][1]) : null\n }\n}\n\nconst EMPH_BOLD = 1, EMPH_ITALIC = 2, EMPH_STRIKE = 4, EMPH_UNDERLINE = 8\n\n/**\n * 글자 위치 → 강조 키(굵게·기울임·취소선·밑줄 비트). 판정은 HWPX 글자 모양(styles.ts)과 같다 — 굵게 bit 1·기울임 bit 0,\n * 취소선은 모양까지(hasRealStrike), 밑줄은 글자 아래만(hasRealUnderline). 강조 글자 모양이 없으면 undefined\n */\nfunction emphasisLookup(runs: Array<[number, number]>, docInfo: HwpDocInfo | null): ((pos: number) => number) | undefined {\n if (!docInfo || !runs.length) return undefined\n const keyOf = (id: number): number => {\n const f = docInfo.charShapes[id]?.attrFlags ?? 0\n return (f & 0x02 ? EMPH_BOLD : 0) | (f & 0x01 ? EMPH_ITALIC : 0) | (hasRealStrike(f) ? EMPH_STRIKE : 0) | (hasRealUnderline(f) ? EMPH_UNDERLINE : 0)\n }\n if (!runs.some(([, id]) => keyOf(id))) return undefined\n let k = -1 // 글자 위치는 늘어나는 순서로 묻는다 — 커서를 앞으로만(되돌아가면 처음부터)\n return (pos) => {\n if (k >= 0 && runs[k][0] > pos) k = -1\n while (k + 1 < runs.length && runs[k + 1][0] <= pos) k++\n return k >= 0 ? keyOf(runs[k][1]) : 0\n }\n}\n\n/**\n * 강조 키가 바뀐 자리(emphRuns)로 문단 글을 span 으로 나눈다 — 문단 글과 같은 정리(리터럴 표지·첨자 태그)를 span 마다 하고,\n * 이은 글이 문단 글과 같을 때만(HWPX run-spans 무결성 가드와 같다). 강조 span 이 없거나 첨자 태그가 span 경계에 걸리면 undefined\n */\nfunction emphasisSpans(state: ParaTextState, text: string): IRSpan[] | undefined {\n const runs = state.emphRuns\n if (!runs?.some(([, key]) => key)) return undefined\n const spans: Array<IRSpan & { key: number }> = []\n for (let r = 0; r < runs.length; r++) {\n const end = r + 1 < runs.length ? runs[r + 1][0] : state.text.length\n const raw = state.text.slice(r === 0 ? 0 : runs[r][0], end) // 첫 키 앞 글(제어 문자 자리)은 첫 span 에\n const t = tidyScriptTags(resolveLiteralLt(raw.replaceAll(LITERAL_DOLLAR_MARK, \"\\\\$\")))\n if (!t) continue\n const key = runs[r][1], last = spans[spans.length - 1]\n if (last && last.key === key) { last.text += t; continue }\n spans.push({ text: t, key })\n }\n const flat = (s: string): string => s.replace(/[ \\t]+/g, \" \").trim()\n if (flat(spans.map(s => s.text).join(\"\")) !== flat(text)) return undefined\n const tagsPaired = (s: string): boolean => [\"sup\", \"sub\"].every(t => (s.split(`<${t}>`).length) === (s.split(`</${t}>`).length))\n if (!spans.every(s => tagsPaired(s.text))) return undefined\n return spans.map(({ text: t, key }) => {\n const span: IRSpan = { text: t }\n if (key & EMPH_BOLD) span.bold = true\n if (key & EMPH_ITALIC) span.italic = true\n if (key & EMPH_STRIKE) span.strike = true\n if (key & EMPH_UNDERLINE) span.underline = true\n return span\n })\n}\n\n/** CHAR_SHAPE ID 배열에서 대표 스타일 결정 (최빈값) */\nfunction resolveCharStyle(charShapeIds: number[], docInfo: HwpDocInfo): InlineStyle | undefined {\n if (charShapeIds.length === 0 || docInfo.charShapes.length === 0) return undefined\n\n // 가장 많이 나타나는 charShapeId 사용\n const freq = new Map<number, number>()\n let maxCount = 0, dominantId = charShapeIds[0]\n for (const id of charShapeIds) {\n const count = (freq.get(id) || 0) + 1\n freq.set(id, count)\n if (count > maxCount) { maxCount = count; dominantId = id }\n }\n\n const cs = docInfo.charShapes[dominantId]\n if (!cs) return undefined\n\n const style: InlineStyle = {}\n if (cs.fontSize > 0) style.fontSize = cs.fontSize / 10 // 0.1pt → pt\n if (cs.attrFlags & 0x01) style.italic = true\n if (cs.attrFlags & 0x02) style.bold = true\n if (hasRealStrike(cs.attrFlags)) style.strike = true\n if (hasRealUnderline(cs.attrFlags)) style.underline = true\n\n return (style.fontSize || style.bold || style.italic || style.strike || style.underline) ? style : undefined\n}\n\n/**\n * CharShape attr 의 취소선 판정 — 비트(18-20)만 믿으면 안 된다: 한컴은 취소선 없는\n * 문자에도 1을 기본값으로 넣는다. 진짜 판별자는 취소선 모양(bit 26-29)이며, 취소선이\n * 없으면 표 27 선 종류(0~12)가 아닌 placeholder(15 등)가 들어온다. 알 수 없는 값은\n * fail-closed 로 no-strike (rhwp 0a967e0d, HWPX isRealStrikeShape 와 같은 원리).\n */\nexport function hasRealStrike(attrFlags: number): boolean {\n const strikeBits = (attrFlags >> 18) & 0x07\n const shapeId = (attrFlags >> 26) & 0x0f\n return strikeBits !== 0 && shapeId <= 12\n}\n\n/**\n * CharShape attr 의 밑줄 판정 — bit 2-3 밑줄 종류 (0=없음, 1=글자 아래, 3=글자 위;\n * rhwp doc_info 직렬화와 동일 레이아웃). 취소선과 달리 종류 비트 자체가 판별자다\n * (HWPX 실측: 밑줄 없는 charPr 는 type=\"NONE\"=비트 0). BOTTOM(1)만 인정 —\n * 윗줄(3)·미지 값은 fail-closed.\n */\nexport function hasRealUnderline(attrFlags: number): boolean {\n return ((attrFlags >> 2) & 0x03) === 1\n}\n","/** HWP 5.x 바이너리 파서 — OLE2 컨테이너 → 섹션 → Markdown */\n\nimport {\n readRecords, decompressStream, parseFileHeader, parseDocInfo, FLAG_COMPRESSED, FLAG_ENCRYPTED,\n FLAG_DISTRIBUTION, FLAG_DRM, type HwpRecord, type HwpDocInfo, type HwpFileHeader,\n} from \"./record.js\"\nimport { extractHwp5Images, extractHwp5ImagesLenient, collectHwp5BinData, collectHwp5BinDataLenient } from \"./images.js\"\nimport { inlineImagesIntoMarkdown } from \"../image/transcode.js\"\nimport { decryptViewText } from \"./crypto.js\"\nimport { parseLenientCfb, type LenientCfbContainer } from \"./cfb-lenient.js\"\nimport { blocksToMarkdown, flattenLayoutTables, dedupeRunningHeaders } from \"../table/builder.js\"\nimport { unframeLayoutTables } from \"../table/layout-frames.js\"\nimport type { IRBlock, DocumentMetadata, InternalParseResult, ParseOptions, ParseWarning, OutlineItem } from \"../types.js\"\nimport { HEADING_RATIO_H1, HEADING_RATIO_H2, HEADING_RATIO_H3 } from \"../types.js\"\nimport { assertDecryptedDocInfo, assertSupportedEncryptVersion, decryptPasswordStream, readEncryptVersion } from \"./pw-crypto.js\"\nimport { KordocError } from \"../utils.js\"\nimport { TOC_ENTRY_BLOCKS } from \"../toc-entry.js\"\nimport { parsePageRange } from \"../page-range.js\"\nimport { detectHwp5SectionPages, type Hwp5SectionPageDetect } from \"./page-boundary.js\"\nimport { indexHwp5Tables } from \"./table-ids.js\"\nimport { parseSection, createHwp5DocState } from \"./body.js\"\n\nexport { parseSection, createHwp5DocState, hasRealStrike, hasRealUnderline, type Hwp5DocState } from \"./body.js\"\n\nimport { createRequire } from \"module\"\nimport { locateMemoBlocks } from \"../memo-notes.js\"\nconst require = createRequire(import.meta.url)\nconst CFB: CfbModule = require(\"cfb\")\n\ninterface CfbEntry { name?: string; content?: Buffer | Uint8Array }\ninterface CfbContainer { FileIndex?: CfbEntry[] }\ninterface CfbModule {\n parse(data: Buffer): CfbContainer\n find(cfb: CfbContainer, path: string): CfbEntry | null\n}\n\n/** 최대 섹션 수 — 비정상 파일에 의한 무한 루프 방지 */\nconst MAX_SECTIONS = 100\n/** 누적 압축 해제 최대 크기 (100MB) */\nconst MAX_TOTAL_DECOMPRESS = 100 * 1024 * 1024\n\n/**\n * 열린 HWP5 컨테이너 — 파서와 렌더 어댑터(#75 Task 7)가 공유하는 스트림 접근 계층.\n * strict CFB → lenient 폴백, DRM 거부, 암호 문서 복호(findStream 에 내장), 압축·배포용 플래그.\n */\nexport interface Hwp5Container {\n cfb: CfbContainer | null\n lenientCfb: LenientCfbContainer | null\n header: HwpFileHeader\n compressed: boolean\n distribution: boolean\n encrypted: boolean\n /** 스트림 읽기 — 암호 문서는 복호를 거친다 */\n findStream: (path: string) => Buffer | null\n warnings: ParseWarning[]\n}\n\nexport function openHwp5Container(buffer: Buffer, options?: Pick<ParseOptions, \"password\">): Hwp5Container {\n // CFB 파싱: strict 먼저, 실패 시 lenient 폴백\n let cfb: CfbContainer | null = null\n let lenientCfb: LenientCfbContainer | null = null\n const warnings: ParseWarning[] = []\n\n try {\n cfb = CFB.parse(buffer)\n } catch {\n try {\n lenientCfb = parseLenientCfb(buffer)\n warnings.push({ message: \"손상된 CFB 컨테이너 — lenient 모드로 복구\", code: \"LENIENT_CFB_RECOVERY\" })\n } catch {\n throw new KordocError(\"CFB 컨테이너 파싱 실패 (strict 및 lenient 모두)\")\n }\n }\n\n // CFB 래퍼: strict/lenient 통합 인터페이스\n const readRawStream = (path: string): Buffer | null => {\n if (cfb) {\n const entry = CFB.find(cfb, path)\n return entry?.content ? Buffer.from(entry.content) : null\n }\n return lenientCfb!.findStream(path)\n }\n\n const headerData = readRawStream(\"/FileHeader\")\n if (!headerData) throw new KordocError(\"FileHeader 스트림 없음\")\n const header = parseFileHeader(headerData)\n if (header.signature !== \"HWP Document File\") throw new KordocError(\"HWP 시그니처 불일치\")\n if (header.flags & FLAG_DRM) throw new KordocError(\"DRM 보호된 HWP는 지원하지 않습니다\")\n\n // 비밀번호 암호 문서 — FileHeader 외 모든 스트림이 AES-CFB 로 암호화되어 있다.\n // 복호를 findStream 래퍼에 끼워 넣어 이후 경로가 평문 문서와 같아지게 한다.\n const encrypted = (header.flags & FLAG_ENCRYPTED) !== 0\n if (encrypted) {\n if (!options?.password) {\n throw new KordocError(\"암호로 보호된 HWP 문서입니다. password 옵션에 열기 암호를 지정하세요.\")\n }\n assertSupportedEncryptVersion(readEncryptVersion(headerData))\n }\n const password = encrypted ? options!.password! : undefined\n const findStream = (path: string): Buffer | null => {\n const raw = readRawStream(path)\n if (!raw || !password) return raw\n return decryptPasswordStream(raw, password)\n }\n\n const compressed = (header.flags & FLAG_COMPRESSED) !== 0\n const distribution = (header.flags & FLAG_DISTRIBUTION) !== 0\n\n // 암호 문서는 여기서 비밀번호를 검증한다 — DocInfo·섹션 파싱은 실패를 경고로 흡수해서,\n // 오답으로 나온 난수 데이터가 \"성공했는데 내용이 쓰레기\"인 결과로 흘러가기 때문이다.\n if (encrypted) {\n const rawDocInfo = findStream(\"/DocInfo\")\n if (!rawDocInfo) throw new KordocError(\"DocInfo 스트림 없음\")\n let docInfoData: Buffer\n try {\n docInfoData = compressed ? decompressStream(rawDocInfo) : rawDocInfo\n } catch {\n throw new KordocError(\"비밀번호가 일치하지 않거나 암호화 데이터가 손상되었습니다.\")\n }\n assertDecryptedDocInfo(docInfoData, readRecords)\n }\n\n return { cfb, lenientCfb, header, compressed, distribution, encrypted, findStream, warnings }\n}\n\n/** DocInfo 원시 레코드 (best-effort) — 렌더 어댑터가 FACE_NAME·BORDER_FILL 등 파서가 안 쓰는 레코드를 읽는다 */\nexport function readHwp5DocInfoRecords(c: Hwp5Container): HwpRecord[] | null {\n try {\n const raw = c.findStream(\"/DocInfo\")\n if (!raw) return null\n return readRecords(c.compressed ? decompressStream(raw) : raw)\n } catch {\n return null\n }\n}\n\n/** 섹션 원시 스트림 — 배포용은 복호+압축해제 완료, 그 외는 readHwp5SectionRecords 가 압축을 푼다 */\nexport function readHwp5SectionStreams(c: Hwp5Container): Buffer[] {\n return c.distribution\n ? (c.cfb ? findViewTextSections(c.cfb, c.compressed) : findViewTextSectionsLenient(c.lenientCfb!, c.compressed))\n : c.encrypted\n ? findSectionsVia(c.findStream)\n : (c.cfb ? findSections(c.cfb) : findSectionsLenient(c.lenientCfb!))\n}\n\n/** 섹션 스트림 → 레코드 (누적 압축해제 상한). 실패한 섹션은 null + PARTIAL_PARSE 경고 */\nexport function readHwp5SectionRecords(c: Hwp5Container, sections: Buffer[], warnings: ParseWarning[]): (HwpRecord[] | null)[] {\n const out: (HwpRecord[] | null)[] = []\n let totalDecompressed = 0\n for (let si = 0; si < sections.length; si++) {\n try {\n // 배포용 문서는 findViewTextSections에서 이미 복호화+압축해제 완료\n const data = (!c.distribution && c.compressed) ? decompressStream(Buffer.from(sections[si])) : Buffer.from(sections[si])\n totalDecompressed += data.length\n if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError(\"총 압축 해제 크기 초과 (decompression bomb 의심)\")\n out.push(readRecords(data))\n } catch (secErr) {\n if (secErr instanceof KordocError) throw secErr\n out.push(null)\n warnings.push({ page: si + 1, message: `섹션 ${si + 1} 파싱 실패: ${secErr instanceof Error ? secErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n }\n }\n return out\n}\n\n/** BinData 스토리지 — storageId(16진 BIN%04X) → 바이트(항목별 압축 정규화) */\nexport function readHwp5BinData(c: Hwp5Container): Map<number, { data: Buffer; name: string }> {\n const readStream = c.encrypted ? c.findStream : undefined\n return c.cfb ? collectHwp5BinData(c.cfb.FileIndex, readStream) : collectHwp5BinDataLenient(c.lenientCfb!, readStream)\n}\n\nexport function parseHwp5Document(buffer: Buffer, options?: ParseOptions): InternalParseResult {\n const c = openHwp5Container(buffer, options)\n const { cfb, lenientCfb, compressed, encrypted, findStream, warnings } = c\n\n const metadata: DocumentMetadata = {\n version: `${c.header.versionMajor}.x`,\n }\n if (cfb) extractHwp5Metadata(cfb, metadata)\n\n // DocInfo 파싱 (스타일 정보 추출)\n // 암호 문서는 복호를 거치는 findStream 경로로 — cfb 직접 접근은 암호문을 읽는다\n const docInfo = cfb && !encrypted\n ? parseDocInfoStream(cfb, compressed)\n : parseDocInfoFromStream(findStream(\"/DocInfo\"), compressed)\n\n const sections = readHwp5SectionStreams(c)\n if (sections.length === 0) throw new KordocError(\"섹션 스트림을 찾을 수 없습니다\")\n\n // (#66) 1단계: 섹션 레코드 확보 + 실제 페이지 프리패스 — 조판 캐시(PARA_LINE_SEG)가\n // 전 섹션에서 신뢰 가능하면 layout 모드(실제 페이지), 아니면 종전 섹션 근사.\n const sectionRecords = readHwp5SectionRecords(c, sections, warnings)\n const sectionDetects: (Hwp5SectionPageDetect | null)[] = sectionRecords.map(r => r ? detectHwp5SectionPages(r) : null)\n // 표 순번(sourceId) 프리패스 — 렌더 어댑터(#75)와 같은 규칙(table-ids.ts)\n const sectionTableIds: Map<number, string>[] = []\n {\n let base = 0\n for (const r of sectionRecords) {\n const ix = indexHwp5Tables(r ?? [], base)\n sectionTableIds.push(ix.ids)\n base += ix.count\n }\n }\n\n const layoutPages = sectionDetects.length > 0 && sectionDetects.every(d => d != null && d.usable)\n metadata.pageMode = layoutPages ? \"layout\" : \"section\"\n metadata.pageCount = layoutPages\n ? Math.max(sectionDetects.reduce((sum, d) => sum + (d?.pages ?? 0), 0), 1)\n : sections.length\n const pageFilter = options?.pages ? parsePageRange(options.pages, metadata.pageCount) : null\n if (pageFilter && !layoutPages) {\n warnings.push({ code: \"PAGE_BOUNDARY_APPROXIMATE\", message: \"조판 캐시가 없어 pages 필터를 섹션 단위 근사로 적용했습니다\" })\n }\n\n // 2단계: 본문 파싱 — layout 모드는 전 섹션 파싱 후 블록 단위 필터,\n // 섹션 근사는 종전(v4.7.2까지)처럼 섹션 스킵\n let bodyBlocks: IRBlock[] = []\n const doc = createHwp5DocState()\n doc.keepTrailingEmptyCols = options?.keepTrailingEmptyCols\n doc.includeFieldPlaceholders = options?.includeFieldPlaceholders\n let parsedSections = 0\n let pageBase = 0\n for (let si = 0; si < sections.length; si++) {\n const records = sectionRecords[si]\n if (!records) continue\n const detect = sectionDetects[si]!\n if (!layoutPages && pageFilter && !pageFilter.has(si + 1)) continue\n try {\n const sectionBlocks = parseSection(records, docInfo, warnings, si + 1, doc,\n layoutPages ? { base: pageBase, pageAtPara: detect.pageAtPara } : undefined, sectionTableIds[si])\n bodyBlocks.push(...sectionBlocks)\n parsedSections++\n options?.onProgress?.(parsedSections, sections.length)\n } catch (secErr) {\n if (secErr instanceof KordocError) throw secErr\n warnings.push({ page: si + 1, message: `섹션 ${si + 1} 파싱 실패: ${secErr instanceof Error ? secErr.message : \"알 수 없는 오류\"}`, code: \"PARTIAL_PARSE\" })\n } finally {\n pageBase += detect.pages\n }\n }\n\n // layout 모드 페이지 필터 — 실제 페이지 기준 블록 필터링\n if (pageFilter && layoutPages) {\n bodyBlocks = bodyBlocks.filter(b => b.pageNumber != null && pageFilter.has(b.pageNumber))\n }\n\n // 머리말은 문서 맨 앞, 꼬리말은 맨 뒤에 1회 출력\n const blocks: IRBlock[] = [...doc.headerBlocks, ...bodyBlocks, ...doc.footerBlocks]\n\n // BinData에서 이미지 추출 — 전체 파싱 시 본문 미참조 BinData 이미지도 스윕\n const images = cfb\n ? extractHwp5Images(cfb.FileIndex, blocks, warnings, !pageFilter, encrypted ? findStream : undefined)\n : extractHwp5ImagesLenient(lenientCfb!, blocks, warnings, !pageFilter, encrypted ? findStream : undefined)\n\n // 레이아웃 테이블 해체 (heading 감지 전에 수행하여 해체된 텍스트도 heading 감지 대상). 칸 테두리가 보이는 표는 풀지 않는다 —\n // 종전엔 3행 이하·글 많은 표를 테두리와 상관없이 풀어 같은 문서의 HWPX 표 118개가 사라지고 틀 안 중첩표가 바깥 단부터 풀렸다\n let flatBlocks = flattenLayoutTables(blocks)\n // 보이지 않는 틀 표 풀기 (v4.17.0) — 칸 테두리로 선 없는 틀은 글로, 칸으로 조립한 분수는 수식으로\n if (options?.layoutTables !== \"keep\") flatBlocks = unframeLayoutTables(flatBlocks, !!options?.keepTrailingEmptyCols)\n // 페이지 레이아웃 표의 반복 러닝 헤더 중복 제거 — opt-in (기본 off).\n // 위치 정보가 없는 HWP5 특성상 정당한 번호매김 반복(붙임별 재번호)까지 오삭제할 수\n // 있어 옵션이 켜졌을 때만 수행하고, 실제 제거가 있으면 경고로 가시화한다.\n if (options?.dedupeRunningHeaders) {\n const deduped = dedupeRunningHeaders(flatBlocks)\n const removed = flatBlocks.length - deduped.length\n if (removed > 0) warnings.push({ message: `반복 러닝 헤더 ${removed}개 제거`, code: \"HIDDEN_TEXT_FILTERED\" })\n flatBlocks = deduped\n }\n\n // 스타일 기반 헤딩 감지\n if (docInfo) {\n detectHwp5Headings(flatBlocks, docInfo, doc.tocTexts)\n }\n\n // outline 구축\n const outline: OutlineItem[] = flatBlocks\n .filter(b => b.type === \"heading\" && b.level && b.text)\n .map(b => ({ level: b.level!, text: b.text!, pageNumber: b.pageNumber }))\n\n let markdown = blocksToMarkdown(flatBlocks, { tableFormat: options?.tableFormat })\n // 이미지 인라인 옵션 — BMP→PNG 압축 후 base64 data URI 로 치환 (AI 에이전트 자체 완결형 마크다운)\n if (options?.inlineImages && options.images !== false && images.length > 0) {\n try {\n markdown = inlineImagesIntoMarkdown(markdown, images, { compress: true })\n } catch (inlineErr) {\n // 설계 계약상 bmpToPng 는 실패 시 null 을 반환하지만, 극단 입력·Node 버전차로 할당이\n // throw 하면 전체 파싱이 죽지 않도록 원본(비인라인) 마크다운을 유지하고 경고만 남긴다.\n warnings.push({ message: `이미지 인라인 실패 — 원본 파일 참조로 폴백: ${inlineErr instanceof Error ? inlineErr.message : \"알 수 없는 오류\"}`, code: \"SKIPPED_IMAGE\" })\n }\n }\n const memos = doc.memos.length ? locateMemoBlocks(flatBlocks, doc.memos) : undefined\n return { markdown, blocks: flatBlocks, metadata, outline: outline.length > 0 ? outline : undefined, warnings: warnings.length > 0 ? warnings : undefined, images: images.length > 0 ? images : undefined, memos }\n}\n\n/** DocInfo 스트림 파싱 (best-effort) */\nfunction parseDocInfoStream(cfb: CfbContainer, compressed: boolean): HwpDocInfo | null {\n try {\n const entry = CFB.find(cfb, \"/DocInfo\")\n if (!entry?.content) return null\n const data = compressed ? decompressStream(Buffer.from(entry.content)) : Buffer.from(entry.content)\n const records = readRecords(data)\n return parseDocInfo(records)\n } catch {\n return null\n }\n}\n\n/** DocInfo — Buffer에서 직접 파싱 (lenient용) */\nfunction parseDocInfoFromStream(raw: Buffer | null, compressed: boolean): HwpDocInfo | null {\n if (!raw) return null\n try {\n const data = compressed ? decompressStream(raw) : raw\n return parseDocInfo(readRecords(data))\n } catch {\n return null\n }\n}\n\n/** 스타일 기반 헤딩 감지 — 큰 폰트 + 짧은 텍스트 → heading */\nfunction detectHwp5Headings(blocks: IRBlock[], docInfo: HwpDocInfo, tocTexts?: Set<string>): void {\n // 기본(본문) 폰트 크기 = 블록 폰트 크기의 텍스트 길이 가중 최빈값.\n // 공문서는 바탕글(10pt)과 다른 크기(13-14pt)로 본문을 쓰는 경우가 많아\n // 바탕글 스타일을 기준으로 삼으면 본문 전체가 헤딩으로 오검출된다 (실증: 보도자료 24/24).\n let baseFontSize = 0\n const sizeFreq = new Map<number, number>()\n for (const b of blocks) {\n if (b.style?.fontSize && b.text) {\n sizeFreq.set(b.style.fontSize, (sizeFreq.get(b.style.fontSize) || 0) + b.text.length)\n }\n }\n let maxWeight = 0\n for (const [size, weight] of sizeFreq) {\n if (weight > maxWeight) { maxWeight = weight; baseFontSize = size }\n }\n\n // 블록 스타일이 전혀 없으면 \"바탕글\", \"본문\" 등 본문 스타일로 폴백\n if (baseFontSize === 0) {\n for (const style of docInfo.styles) {\n const name = (style.nameKo || style.name).toLowerCase()\n if (name.includes(\"바탕\") || name.includes(\"본문\") || name === \"normal\" || name === \"body\") {\n const cs = docInfo.charShapes[style.charShapeId]\n // cs.fontSize는 0.1pt 단위 → pt로 변환 (블록의 style.fontSize와 동일 단위)\n if (cs?.fontSize > 0) { baseFontSize = cs.fontSize / 10; break }\n }\n }\n }\n\n if (baseFontSize <= 0) return\n\n for (const block of blocks) {\n // 개요 수준(outlineLevel)으로 이미 heading이 된 블록은 스킵\n if (block.type === \"heading\") continue\n if (block.type !== \"paragraph\" || !block.text || TOC_ENTRY_BLOCKS.has(block) || tocTexts?.has(block.text.trim())) continue\n const text = block.text.trim()\n if (text.length === 0 || text.length > 200) continue\n if (/^\\d+$/.test(text)) continue\n\n let level = 0\n\n // 폰트 크기 비율 기반 헤딩 감지 (스타일 정보가 있을 때만)\n if (block.style?.fontSize && baseFontSize > 0) {\n const ratio = block.style.fontSize / baseFontSize\n if (ratio >= HEADING_RATIO_H1) level = 1\n else if (ratio >= HEADING_RATIO_H2) level = 2\n else if (ratio >= HEADING_RATIO_H3) level = 3\n }\n\n // \"제N장/절/편\" 패턴 → H2, \"제N조\" 패턴 → H3 (스타일 유무 무관)\n if (/^제\\d+[장절편]\\s/.test(text) && text.length <= 50) {\n if (level === 0) level = 2\n } else if (/^제\\d+(조의?\\d*)\\s*[\\((]/.test(text) && text.length <= 80) {\n if (level === 0) level = 3\n }\n\n if (level > 0) {\n block.type = \"heading\"\n block.level = level\n delete block.spans // 제목은 강조 표지 없이 (HWPX 와 같다)\n }\n }\n}\n\n// ─── 메타데이터 추출 (best-effort) ───────────────────\n\nconst VT_I2 = 0x02, VT_LPSTR = 0x1e, VT_LPWSTR = 0x1f, VT_FILETIME = 0x40\n/** VT_LPSTR 코드 페이지 → TextDecoder 레이블 (1250~1258 은 windows-N) */\nconst CODE_PAGE_LABELS: Record<number, string> = { 949: \"euc-kr\", 932: \"shift_jis\", 936: \"gbk\", 950: \"big5\", 65001: \"utf-8\" }\n\n/**\n * OLE2 SummaryInformation 스트림에서 제목/작성자/설명/키워드/날짜 추출.\n * HWP5는 \\005HwpSummaryInformation 또는 \\005SummaryInformation에 저장.\n * OLE2 Property Set 포맷의 간이 파싱 — 실패 시 조용히 무시.\n * 한컴 HwpSummaryInformation(FMTID 9FA2B660-1061-11D4-B4C6-006097C09D8C)은 코드 페이지 속성 없이 문자열을 전부\n * VT_LPWSTR 로 쓴다(코퍼스 1,435건 전부) — 종전엔 VT_LPSTR 만 읽어 제목·지은이가 한 번도 안 나왔다.\n */\nfunction extractHwp5Metadata(cfb: CfbContainer, metadata: DocumentMetadata): void {\n try {\n // HWP 전용 SummaryInformation 먼저, 없으면 표준 OLE2\n const summaryEntry =\n CFB.find(cfb, \"/\\x05HwpSummaryInformation\") ||\n CFB.find(cfb, \"/\\x05SummaryInformation\")\n if (!summaryEntry?.content) return\n\n const data = Buffer.from(summaryEntry.content)\n if (data.length < 48) return\n\n // OLE2 Property Set Header: byte order(2) + version(2) + OS(4) + CLSID(16) + numSets(4) = 28\n // Then FMTID(16) + offset(4)\n const numSets = data.readUInt32LE(24)\n if (numSets === 0) return\n\n const setOffset = data.readUInt32LE(44)\n if (setOffset >= data.length - 8) return\n\n // Property Set: size(4) + numProperties(4) + [propertyId(4) + offset(4)] * N\n const numProps = data.readUInt32LE(setOffset + 4)\n if (numProps === 0 || numProps > 100) return\n\n // 속성 ID → 값 위치(type 4바이트부터). 코드 페이지(1)가 문자열 뒤에 올 수 있어 표를 먼저 모은다\n const props = new Map<number, number>()\n for (let i = 0; i < numProps; i++) {\n const entryOffset = setOffset + 8 + i * 8\n if (entryOffset + 8 > data.length) break\n const propOffset = setOffset + data.readUInt32LE(entryOffset + 4)\n if (propOffset + 8 <= data.length) props.set(data.readUInt32LE(entryOffset), propOffset)\n }\n const cpAt = props.get(1) // PID_CODEPAGE (VT_I2) — VT_LPSTR 해석용\n const codePage = cpAt !== undefined && data.readUInt32LE(cpAt) === VT_I2 ? data.readUInt16LE(cpAt + 4) : 0\n const text = (id: number) => { const at = props.get(id); return at === undefined ? undefined : readPropString(data, at, codePage) }\n const time = (id: number) => { const at = props.get(id); return at === undefined ? undefined : readPropFileTime(data, at) }\n\n // SummaryInformation 번호(한컴 FMTID 도 같음): 2 제목·3 주제·4 지은이·5 키워드·6 설명·12 만든 날짜·13 마지막 저장.\n // HWPX 짝 content.hpf 의 opf:title·subject·creator·keyword·description·CreatedDate 와 같은 값(한컴 저장 쌍 209건 실측).\n // 설명이 비면 주제 — HWPX metadata.ts(description → subject)·PDF(Subject) 와 같은 자리\n const title = text(2), author = text(4), description = text(6) || text(3)\n if (title) metadata.title = title\n if (author) metadata.author = author\n if (description) metadata.description = description\n const keywords = text(5)?.split(/[,;]/).map(k => k.trim()).filter(Boolean)\n if (keywords?.length) metadata.keywords = keywords\n const createdAt = time(12), modifiedAt = time(13)\n if (createdAt) metadata.createdAt = createdAt\n if (modifiedAt) metadata.modifiedAt = modifiedAt\n } catch {\n // best-effort — 실패 시 조용히 무시\n }\n}\n\n/**\n * 문자열 속성 값 (at = type 위치). VT_LPWSTR: 글자 수(UTF-16 단위, NUL 포함) + UTF-16LE,\n * VT_LPSTR: 바이트 수(NUL 포함) + 코드 페이지 문자열(1200 = UTF-16LE, 없음·모름 = UTF-8 — 종전 동작).\n * 값 뒤 4바이트 정렬 패딩은 오프셋 표로 찾으므로 무관\n */\nfunction readPropString(data: Buffer, at: number, codePage: number): string | undefined {\n const type = data.readUInt32LE(at)\n const unit = type === VT_LPWSTR ? 2 : type === VT_LPSTR ? 1 : 0\n const count = data.readUInt32LE(at + 4)\n if (!unit || count === 0 || count > 10000 || at + 8 + count * unit > data.length) return undefined\n const bytes = data.subarray(at + 8, at + 8 + count * unit)\n let s: string\n if (unit === 2 || codePage === 1200) s = bytes.toString(\"utf16le\")\n else {\n const label = CODE_PAGE_LABELS[codePage] ?? (codePage >= 1250 && codePage <= 1258 ? `windows-${codePage}` : \"utf-8\")\n try { s = new TextDecoder(label).decode(bytes) } catch { s = bytes.toString(\"utf8\") } // ICU 없는 Node — 레이블 미지원\n }\n const nul = s.indexOf(\"\\0\")\n return (nul >= 0 ? s.slice(0, nul) : s).trim() || undefined\n}\n\n/** VT_FILETIME — 1601-01-01 UTC 부터 100ns 단위 u64 → ISO 8601 초 단위(content.hpf CreatedDate 꼴). 0(미기록)은 undefined */\nfunction readPropFileTime(data: Buffer, at: number): string | undefined {\n if (data.readUInt32LE(at) !== VT_FILETIME || at + 12 > data.length) return undefined\n const ticks = data.readBigUInt64LE(at + 4)\n if (ticks === 0n) return undefined\n // 초로 먼저 나눠 정수 연산 — u64 를 double 로 옮기면 정각 값이 1초 앞당겨질 수 있다\n return new Date((Number(ticks / 10000000n) - 11644473600) * 1000).toISOString().replace(\".000Z\", \"Z\")\n}\n\n/** 메타데이터만 추출 (전체 파싱 없이) — MCP parse_metadata용 */\nexport function extractHwp5MetadataOnly(buffer: Buffer): DocumentMetadata {\n const cfb = CFB.parse(buffer)\n const headerEntry = CFB.find(cfb, \"/FileHeader\")\n if (!headerEntry?.content) throw new KordocError(\"FileHeader 스트림 없음\")\n const header = parseFileHeader(Buffer.from(headerEntry.content))\n if (header.signature !== \"HWP Document File\") throw new KordocError(\"HWP 시그니처 불일치\")\n\n const metadata: DocumentMetadata = {\n version: `${header.versionMajor}.x`,\n }\n extractHwp5Metadata(cfb, metadata)\n\n const sections = findSections(cfb)\n metadata.pageCount = sections.length\n\n return metadata\n}\n\n/** 배포용 문서: ViewText/Section{N} 스트림을 복호화하여 반환 */\nfunction findViewTextSections(cfb: CfbContainer, compressed: boolean): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const entry = CFB.find(cfb, `/ViewText/Section${i}`)\n if (!entry?.content) break\n try {\n const decrypted = decryptViewText(Buffer.from(entry.content), compressed)\n sections.push({ idx: i, content: decrypted })\n } catch {\n // 복호화 실패 시 해당 섹션 스킵\n break\n }\n }\n\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n/** 스트림 리더로 BodyText 섹션 수집 — 압축 해제는 호출부가 맡는다(findSections와 같은 계약) */\nfunction findSectionsVia(read: (path: string) => Buffer | null): Buffer[] {\n const sections: Buffer[] = []\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const raw = read(`/BodyText/Section${i}`)\n if (!raw) break\n sections.push(raw)\n }\n return sections\n}\n\nfunction findSections(cfb: CfbContainer): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const entry = CFB.find(cfb, `/BodyText/Section${i}`)\n if (!entry?.content) break\n sections.push({ idx: i, content: Buffer.from(entry.content) })\n }\n\n if (sections.length === 0 && cfb.FileIndex) {\n for (const entry of cfb.FileIndex) {\n if (sections.length >= MAX_SECTIONS) break\n if (entry.name?.startsWith(\"Section\") && entry.content) {\n const idx = parseInt(entry.name.replace(\"Section\", \"\"), 10) || 0\n sections.push({ idx, content: Buffer.from(entry.content) })\n }\n }\n }\n\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n/** Lenient CFB: raw BodyText streams — readHwp5SectionRecords applies decompression once. */\nfunction findSectionsLenient(lcfb: LenientCfbContainer): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n let totalBytes = 0\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const raw = lcfb.findStream(`/BodyText/Section${i}`) ?? lcfb.findStream(`Section${i}`)\n if (!raw) break\n totalBytes += raw.length\n if (totalBytes > MAX_TOTAL_DECOMPRESS) throw new KordocError(\"총 압축 해제 크기 초과 (decompression bomb 의심)\")\n sections.push({ idx: i, content: raw })\n }\n if (sections.length === 0) {\n // fallback: 이름에 \"Section\" 포함된 스트림\n for (const e of lcfb.entries()) {\n if (sections.length >= MAX_SECTIONS) break\n if (e.name.startsWith(\"Section\")) {\n const idx = parseInt(e.name.replace(\"Section\", \"\"), 10) || 0\n const raw = lcfb.findStream(e.name)\n if (raw) {\n totalBytes += raw.length\n if (totalBytes > MAX_TOTAL_DECOMPRESS) throw new KordocError(\"총 압축 해제 크기 초과 (decompression bomb 의심)\")\n sections.push({ idx, content: raw })\n }\n }\n }\n }\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n\n/** Lenient CFB: ViewText/Section{N} 복호화 — 누적 크기 추적 */\nfunction findViewTextSectionsLenient(lcfb: LenientCfbContainer, compressed: boolean): Buffer[] {\n const sections: Array<{ idx: number; content: Buffer }> = []\n let totalDecompressed = 0\n for (let i = 0; i < MAX_SECTIONS; i++) {\n const raw = lcfb.findStream(`/ViewText/Section${i}`) ?? lcfb.findStream(`Section${i}`)\n if (!raw) break\n try {\n const content = decryptViewText(raw, compressed)\n totalDecompressed += content.length\n if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError(\"총 압축 해제 크기 초과 (decompression bomb 의심)\")\n sections.push({ idx: i, content })\n } catch { break }\n }\n return sections.sort((a, b) => a.idx - b.idx).map(s => s.content)\n}\n","/**\n * 메모(한글 \"메모 넣기\") 결과 손질 (#180) — 메모가 붙은 블록 순번 찾기와 마크다운 끝 \"메모\" 절. HWPX·HWP5 파서가 같이 쓴다.\n * 메모는 본문 마크다운에 섞지 않는다(채점·patch 소스맵 불변) — 끝 절은 `memos` 옵션을 켰을 때만\n */\n\nimport type { IRBlock, MemoNote } from \"./types.js\"\nimport { escapeGfm, sanitizeText } from \"./table/builder.js\"\n\nconst squash = (s: string): string => sanitizeText(s).replace(/\\s+/g, \"\")\n\n/** 블록 글 — 표는 칸 글까지 (칸 안 메모를 그 표 블록에 붙이려고) */\nfunction blockText(b: IRBlock): string {\n if (b.type !== \"table\" || !b.table) return b.text ?? \"\"\n return b.table.cells.flat().map(c => c?.text ?? \"\").join(\"\\n\")\n}\n\n/** 메모마다 붙은 문단이 든 블록 순번 — 문서 순서라 앞 메모의 블록부터 찾고, 없으면 처음부터. 칸 차례는 MemoNote 순서로 맞춘다 */\nexport function locateMemoBlocks(blocks: IRBlock[], memos: MemoNote[]): MemoNote[] {\n const keys = blocks.map(b => squash(blockText(b)))\n let from = 0\n return memos.map(m => {\n const k = squash(m.paragraph)\n let i = k ? keys.findIndex((t, j) => j >= from && t.includes(k)) : -1\n if (k && i < 0) i = keys.findIndex(t => t.includes(k))\n if (i >= 0) from = i\n const out: MemoNote = { text: m.text, anchor: m.anchor, paragraph: m.paragraph, offset: m.offset }\n if (i >= 0) out.blockIndex = i\n if (m.author !== undefined) out.author = m.author\n if (m.createdAt !== undefined) out.createdAt = m.createdAt\n if (m.number !== undefined) out.number = m.number\n return out\n })\n}\n\n/** 마크다운 끝 \"메모\" 절 — 메모마다 작성자·시각, 붙은 글, 메모 글 */\nexport function memosMarkdown(memos: MemoNote[]): string {\n const one = (s: string): string => escapeGfm(sanitizeText(s.replace(/\\s*\\n\\s*/g, \" / \")))\n const lines = memos.map((m, i) => {\n const when = m.createdAt?.replace(\"T\", \" \").replace(/(:\\d\\d)?Z?$/, \"\")\n const who = [m.author, when].filter(Boolean).join(\", \")\n return `${i + 1}. ${who ? `(${one(who)}) ` : \"\"}「${one(m.anchor)}」 — ${one(m.text)}`\n })\n return `\\n\\n---\\n\\n**메모**\\n\\n${lines.join(\"\\n\")}\\n`\n}\n","/**\n * HWP 5.x → HWPX 변환 공용 — 레코드 커서·레코드 트리·XML 조각·색·열거 이름.\n *\n * 열거 이름과 값 대응은 공개 HWP 5.0 문서 형식과 OWPML(KS X 6101)을 따르고, 같은 문서를 한글이 .hwp·.hwpx 로 함께 저장한\n * 짝(bench/hwp2hwpx.mjs 정답 짝)에서 대조해 맞춘 것이다.\n */\n\nexport interface Rec { tagId: number; level: number; data: Buffer }\n\n/** 레코드와 자식(바로 아래 수준의 뒤따르는 레코드) */\nexport interface RecNode { rec: Rec; kids: RecNode[] }\n\n/** 평평한 레코드 열을 수준으로 트리로 — 자식은 부모보다 수준이 1 깊은 뒤따르는 레코드 */\nexport function recordTree(recs: Rec[]): RecNode[] {\n const top: RecNode[] = []\n const stack: RecNode[] = []\n for (const rec of recs) {\n const node: RecNode = { rec, kids: [] }\n while (stack.length && stack[stack.length - 1].rec.level >= rec.level) stack.pop()\n if (stack.length) stack[stack.length - 1].kids.push(node)\n else top.push(node)\n stack.push(node)\n }\n return top\n}\n\n/** 레코드 데이터 순차 읽기 — 짧은(옛 판) 레코드는 모자란 필드를 0 으로 읽는다 */\nexport class Cur {\n constructor(readonly d: Buffer, public o = 0) {}\n get rest(): number { return this.d.length - this.o }\n u8(): number { const v = this.o < this.d.length ? this.d[this.o] : 0; this.o += 1; return v }\n i8(): number { const v = this.u8(); return v > 127 ? v - 256 : v }\n u16(): number { const v = this.o + 2 <= this.d.length ? this.d.readUInt16LE(this.o) : 0; this.o += 2; return v }\n i16(): number { const v = this.u16(); return v > 32767 ? v - 65536 : v }\n u32(): number { const v = this.o + 4 <= this.d.length ? this.d.readUInt32LE(this.o) : 0; this.o += 4; return v }\n i32(): number { return this.u32() | 0 }\n /** WORD 글자 수 + UTF-16LE 글 */\n str(): string {\n const n = this.u16()\n const s = this.d.toString(\"utf16le\", Math.min(this.o, this.d.length), Math.min(this.d.length, this.o + n * 2))\n this.o += n * 2\n return s\n }\n skip(n: number): this { this.o += n; return this }\n}\n\nconst ESC: Record<string, string> = { \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", \"\\\"\": \"&quot;\" }\nconst XML_FORBIDDEN = /[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\ufffe\\uffff]/g\n/** XML 속성 값 — XML 이 허용하지 않는 제어 문자는 뺀다 */\nexport function esc(s: string): string {\n return s.replace(XML_FORBIDDEN, \"\").replace(/[&<>\"]/g, c => ESC[c])\n}\n/** 글 마디 — 한글처럼 따옴표는 그대로 둔다 */\nexport function escText(s: string): string {\n return s.replace(XML_FORBIDDEN, \"\").replace(/[&<>]/g, c => ESC[c])\n}\n\n/** 속성 목록 → ` a=\"1\" b=\"x\"` (값 그대로 이스케이프) */\nexport function attrs(list: Array<[string, string | number]>): string {\n let s = \"\"\n for (const [k, v] of list) s += ` ${k}=\"${typeof v === \"number\" ? v : esc(v)}\"`\n return s\n}\n\n/** 요소 하나 — 내용이 없으면(undefined) 빈 요소 */\nexport function el(name: string, list: Array<[string, string | number]>, inner?: string): string {\n return inner === undefined ? `<${name}${attrs(list)}/>` : `<${name}${attrs(list)}>${inner}</${name}>`\n}\n\nconst hex2 = (n: number): string => n.toString(16).toUpperCase().padStart(2, \"0\")\n/** COLORREF(0xAABBGGRR) → \"#RRGGBB\" (투명도 바이트가 있으면 \"#AARRGGBB\"), 0xFFFFFFFF → \"none\" */\nexport function color(c: number): string {\n c >>>= 0\n if (c === 0xffffffff) return \"none\"\n const a = c >>> 24\n return \"#\" + (a ? hex2(a) : \"\") + hex2(c & 0xff) + hex2((c >>> 8) & 0xff) + hex2((c >>> 16) & 0xff)\n}\n\n/** 0/1 플래그 */\nexport const bit = (v: number, n: number): number => (v >>> n) & 1\n/** 비트 구간 값 */\nexport const bits = (v: number, from: number, width: number): number => (v >>> from) & ((1 << width) - 1)\n/** 열거 이름 — 범위 밖이면 첫 값 */\nexport const pick = (names: readonly string[], i: number): string => names[i] ?? names[0]\n\n/** 테두리 선 종류 (BORDER_FILL 4변·대각선, 문단 테두리) — 0 은 없음 */\nexport const BORDER_TYPES = [\"NONE\", \"SOLID\", \"DOT\", \"DASH\", \"DASH_DOT\", \"DASH_DOT_DOT\", \"LONG_DASH\", \"CIRCLE\", \"DOUBLE_SLIM\",\n \"SLIM_THICK\", \"THICK_SLIM\", \"SLIM_THICK_SLIM\", \"WAVE\", \"DOUBLE_WAVE\", \"THICK_3D\", \"THICK_3D_REVERSE\", \"3D\", \"3D_REVERSE\"] as const\n/** 밑줄·취소선·구분선 모양 — 0 은 실선 */\nexport const LINE_SHAPES = BORDER_TYPES.slice(1)\n/** 테두리 선 굵기 */\nexport const BORDER_WIDTHS = [\"0.1 mm\", \"0.12 mm\", \"0.15 mm\", \"0.2 mm\", \"0.25 mm\", \"0.3 mm\", \"0.4 mm\", \"0.5 mm\", \"0.6 mm\", \"0.7 mm\",\n \"1.0 mm\", \"1.5 mm\", \"2.0 mm\", \"3.0 mm\", \"4.0 mm\", \"5.0 mm\"] as const\n/** 번호 모양 */\nexport const NUM_FORMATS = [\"DIGIT\", \"CIRCLED_DIGIT\", \"ROMAN_CAPITAL\", \"ROMAN_SMALL\", \"LATIN_CAPITAL\", \"LATIN_SMALL\", \"CIRCLED_LATIN_CAPITAL\",\n \"CIRCLED_LATIN_SMALL\", \"HANGUL_SYLLABLE\", \"CIRCLED_HANGUL_SYLLABLE\", \"HANGUL_JAMO\", \"CIRCLED_HANGUL_JAMO\", \"HANGUL_PHONETIC\",\n \"IDEOGRAPH\", \"CIRCLED_IDEOGRAPH\", \"DECAGON_CIRCLE\", \"DECAGON_CIRCLE_HANJA\"] as const\n\nexport type Param = number | string | number[] | ParamSet\nexport interface ParamSet { [id: number]: Param }\n\n/** 매개변수 묶음(CTRL_DATA) — 묶음 id(WORD)·항목 수(DWORD), 항목마다 id(WORD)·종류(WORD)·값. 묶음 안 묶음(0x8000)·배열(0x8001: 개수 WORD·0·종류+값)은 펼친다 */\nexport function readParamSet(d: Buffer, at: { o: number }): ParamSet {\n const set: ParamSet = {}\n if (at.o + 6 > d.length) return set\n const n = d.readUInt32LE(at.o + 2)\n at.o += 6\n for (let i = 0; i < n && at.o + 4 <= d.length; i++) {\n const id = d.readUInt16LE(at.o), type = d.readUInt16LE(at.o + 2)\n at.o += 4\n if (type === 0x8000) set[id] = readParamSet(d, at)\n else if (type === 0x8001) {\n const cnt = d.readUInt16LE(at.o), arr: number[] = []\n at.o += 4\n for (let j = 0; j < cnt && at.o + 6 <= d.length; j++, at.o += 6) arr.push(d.readUInt32LE(at.o + 2))\n set[id] = arr\n } else if (type === 0x8002) { set[id] = d.readUInt16LE(at.o); at.o += 2 }\n else if (type === 1) {\n const n = d.readUInt16LE(at.o)\n set[id] = d.toString(\"utf16le\", at.o + 2, Math.min(d.length, at.o + 2 + n * 2))\n at.o += 2 + n * 2\n }\n else { set[id] = d.readInt32LE(at.o); at.o += 4 }\n }\n return set\n}\n\n/** 묶음 안 묶음(SET) 하나 — 없으면 null */\nexport function subSet(set: ParamSet | undefined, id: number): ParamSet | null {\n const v = set?.[id]\n return v && typeof v === \"object\" && !Array.isArray(v) ? v : null\n}\n","/**\n * HWP 5.x DocInfo → HWPX Contents/header.xml.\n *\n * DocInfo 레코드(글꼴·테두리/배경·글자 모양·탭·번호·글머리표·문단 모양·스타일·메모 모양·호환 설정)를 id 순서 그대로 옮긴다.\n * 한글 2022 이상(xml 1.5) 꼴로 쓴다 — 단위가 바뀐 값(문단 여백·탭 위치)은 hp:switch 의 HwpUnitChar 갈래에 HWPUNIT, 기본 갈래에\n * 레코드 값을 둔다(레코드는 HWPUNIT 의 2배로 적혀 있다).\n */\n\nimport { Cur, type Rec, el, escText, color, bit, bits, pick, BORDER_TYPES, BORDER_WIDTHS, LINE_SHAPES, NUM_FORMATS } from \"./util.js\"\n\nexport const NS = 'xmlns:ha=\"http://www.hancom.co.kr/hwpml/2011/app\" xmlns:hp=\"http://www.hancom.co.kr/hwpml/2011/paragraph\" '\n + 'xmlns:hp10=\"http://www.hancom.co.kr/hwpml/2016/paragraph\" xmlns:hs=\"http://www.hancom.co.kr/hwpml/2011/section\" '\n + 'xmlns:hc=\"http://www.hancom.co.kr/hwpml/2011/core\" xmlns:hh=\"http://www.hancom.co.kr/hwpml/2011/head\" '\n + 'xmlns:hhs=\"http://www.hancom.co.kr/hwpml/2011/history\" xmlns:hm=\"http://www.hancom.co.kr/hwpml/2011/master-page\" '\n + 'xmlns:hpf=\"http://www.hancom.co.kr/schema/2011/hpf\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" '\n + 'xmlns:opf=\"http://www.idpf.org/2007/opf/\" xmlns:ooxmlchart=\"http://www.hancom.co.kr/hwpml/2016/ooxmlchart\" '\n + 'xmlns:hwpunitchar=\"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\" xmlns:epub=\"http://www.idpf.org/2007/ops\" '\n + 'xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"'\nexport const XML_DECL = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>'\n/** 단위가 바뀐 값의 HWPUNIT 갈래 */\nexport const UNIT_CASE = \"http://www.hancom.co.kr/hwpml/2016/HwpUnitChar\"\n/** case(HWPUNIT, 레코드 값의 절반)·default(레코드 값) 두 갈래 */\nexport function unitSwitch(caseXml: string, defaultXml: string): string {\n return `<hp:switch><hp:case hp:required-namespace=\"${UNIT_CASE}\">${caseXml}</hp:case><hp:default>${defaultXml}</hp:default></hp:switch>`\n}\n\nconst TAG = {\n DOCUMENT_PROPERTIES: 0x10, ID_MAPPINGS: 0x11, BIN_DATA: 0x12, FACE_NAME: 0x13, BORDER_FILL: 0x14, CHAR_SHAPE: 0x15, TAB_DEF: 0x16,\n NUMBERING: 0x17, BULLET: 0x18, PARA_SHAPE: 0x19, STYLE: 0x1a, COMPATIBLE_DOCUMENT: 0x1e, LAYOUT_COMPATIBILITY: 0x1f,\n TRACKCHANGE: 0x20, MEMO_SHAPE: 0x5c, TRACK_CHANGE: 0x60, TRACK_CHANGE_AUTHOR: 0x61,\n} as const\n\nconst LANGS = [\"HANGUL\", \"LATIN\", \"HANJA\", \"JAPANESE\", \"OTHER\", \"SYMBOL\", \"USER\"] as const\nconst LANG_ATTRS = [\"hangul\", \"latin\", \"hanja\", \"japanese\", \"other\", \"symbol\", \"user\"] as const\nconst FONT_TYPES = [\"REP\", \"TTF\", \"HFT\"] as const\nconst FONT_FAMILIES = [\"FCAT_UNKNOWN\", \"FCAT_MYUNGJO\", \"FCAT_GOTHIC\", \"FCAT_SSERIF\", \"FCAT_BRUSHSCRIPT\", \"FCAT_DECORATIVE\",\n \"FCAT_NONRECTMJ\", \"FCAT_NONRECTGT\"] as const\nconst SLASH_TYPES = [\"NONE\", \"NONE\", \"CENTER\", \"CENTER_BELOW\", \"NONE\", \"NONE\", \"CENTER_ABOVE\", \"ALL\"] as const\nconst UNDERLINE_TYPES = [\"NONE\", \"BOTTOM\", \"CENTER\", \"TOP\"] as const\nconst OUTLINE_TYPES = [\"NONE\", \"SOLID\", \"DOT\", \"BOLD\", \"DASH\", \"DASH_DOT\", \"DASH_DOT_DOT\"] as const\nconst SHADOW_TYPES = [\"NONE\", \"DROP\", \"CONTINUOUS\"] as const\nconst SYM_MARKS = [\"NONE\", \"DOT_ABOVE\", \"RING_ABOVE\", \"TILDE\", \"CARON\", \"SIDE\", \"COLON\", \"GRAVE_ACCENT\", \"ACUTE_ACCENT\", \"CIRCUMFLEX\",\n \"MACRON\", \"HOOK_ABOVE\", \"DOT_BELOW\"] as const\nconst TAB_TYPES = [\"LEFT\", \"RIGHT\", \"CENTER\", \"DECIMAL\"] as const\nconst HEAD_ALIGNS = [\"LEFT\", \"CENTER\", \"RIGHT\"] as const\nconst PARA_ALIGNS = [\"JUSTIFY\", \"LEFT\", \"RIGHT\", \"CENTER\", \"DISTRIBUTE\", \"DISTRIBUTE_SPACE\"] as const\nconst VERT_ALIGNS = [\"BASELINE\", \"TOP\", \"CENTER\", \"BOTTOM\"] as const\nconst HEADING_TYPES = [\"NONE\", \"OUTLINE\", \"NUMBER\", \"BULLET\"] as const\nconst LATIN_BREAKS = [\"KEEP_WORD\", \"HYPHENATION\", \"BREAK_WORD\"] as const\nconst LINE_WRAPS = [\"BREAK\", \"SQUEEZE\", \"KEEP\"] as const\nconst LINE_SPACINGS = [\"PERCENT\", \"FIXED\", \"BETWEEN_LINES\", \"AT_LEAST\"] as const\nexport const GRADATIONS = [\"LINEAR\", \"LINEAR\", \"RADIAL\", \"CONICAL\", \"SQUARE\"] as const\nconst IMG_MODES = [\"TILE\", \"TILE_HORZ_TOP\", \"TILE_HORZ_BOTTOM\", \"TILE_VERT_LEFT\", \"TILE_VERT_RIGHT\", \"TOTAL\", \"CENTER\", \"CENTER_TOP\",\n \"CENTER_BOTTOM\", \"LEFT_CENTER\", \"LEFT_TOP\", \"LEFT_BOTTOM\", \"RIGHT_CENTER\", \"RIGHT_TOP\", \"RIGHT_BOTTOM\", \"ZOOM\"] as const\nconst IMG_EFFECTS = [\"REAL_PIC\", \"GRAY_SCALE\", \"BLACK_WHITE\", \"PATTERN8x8\"] as const\nconst TARGET_PROGRAMS = [\"HWP201X\", \"HWP200X\", \"MS_WORD\"] as const\nconst MEMO_TYPES = [\"NOMAL\", \"USER_INSERT\", \"USER_DELETE\", \"USER_UPDATE\"] as const\n\n/** BinData 순번 → 패키지 항목 id (한글처럼 처음 참조한 차례로 image1, image2 … 를 매긴다) */\nexport type BinRef = (binId: number) => string\n\n/** 그림 채우기의 그림 — 밝기·명암·효과·BinData id */\nexport function imgXml(c: Cur, alpha: number, ref: BinRef): string {\n // 그림 개체(SHAPE_COMPONENT_PICTURE)와 같이 명암이 먼저다 — 쪽 배경 워터마크(밝기 50·명암 -15)로 확인\n const contrast = c.i8(), bright = c.i8(), effect = c.u8(), id = c.u16()\n return el(\"hc:img\", [[\"binaryItemIDRef\", id ? ref(id) : \"\"], [\"bright\", bright], [\"contrast\", contrast],\n [\"effect\", pick(IMG_EFFECTS, effect)], [\"alpha\", alpha]])\n}\n\n/**\n * 채우기 정보(BORDER_FILL·도형 공용) → hc:fillBrush. 레코드: 채우기 종류 u32(1 면색·2 그림·4 그러데이션) 뒤에 종류별 정보,\n * 추가 정보 길이 u32 와 추가 정보(그러데이션 번짐 중심), 끝에 종류별 투명도 바이트\n */\nexport function fillBrushXml(c: Cur, ref: BinRef): string {\n const type = c.u32()\n // 채우기가 없어도 추가 채우기 속성 길이(DWORD)는 있다 — 그 뒤 그림자·인스턴스 id 가 밀리지 않게 넘긴다\n if (!type) { c.skip(c.u32()); return \"\" }\n let win = \"\", grad = \"\", img = \"\"\n let winFace = 0, winHatch = 0, hatchStyle = -1\n if (type & 1) { winFace = c.u32(); winHatch = c.u32(); hatchStyle = c.i32() }\n let gradAttrs: Array<[string, string | number]> = [], gradColors: number[] = []\n if (type & 4) {\n // 공개 명세는 INT16 들이라 적었지만 실제 저장은 유형 BYTE, 각도·중심·번짐·색 수 INT32 다\n const gtype = c.u8(), angle = c.i32(), cx = c.i32(), cy = c.i32(), step = c.i32(), num = c.i32()\n const n = Math.max(0, num)\n if (n > 2) c.skip(4 * n)\n for (let i = 0; i < n; i++) gradColors.push(c.u32())\n gradAttrs = [[\"type\", pick(GRADATIONS, gtype)], [\"angle\", angle], [\"centerX\", cx], [\"centerY\", cy], [\"step\", step], [\"colorNum\", n]]\n }\n let imgMode = 0, imgStart = -1\n if (type & 2) { imgMode = c.u8(); imgStart = c.o; c.skip(5) }\n const extra = c.u32()\n let stepCenter = 50\n if (extra && type & 4) stepCenter = c.d[c.o] ?? 50\n c.skip(extra)\n const winAlpha = type & 1 ? c.u8() : 0\n const gradAlpha = type & 4 ? c.u8() : 0\n const imgAlpha = type & 2 ? c.u8() : 0\n if (type & 1) {\n win = el(\"hc:winBrush\", [[\"faceColor\", color(winFace)], [\"hatchColor\", color(winHatch)],\n ...(hatchStyle >= 0 ? [[\"hatchStyle\", pick(HATCHES, hatchStyle)] as [string, string]] : []), [\"alpha\", winAlpha]])\n }\n if (type & 4) {\n grad = el(\"hc:gradation\", [...gradAttrs, [\"stepCenter\", stepCenter], [\"alpha\", gradAlpha]],\n gradColors.map(v => el(\"hc:color\", [[\"value\", color(v)]])).join(\"\"))\n }\n if (type & 2) {\n const ic = new Cur(c.d, imgStart)\n img = el(\"hc:imgBrush\", [[\"mode\", pick(IMG_MODES, imgMode)]], imgXml(ic, imgAlpha, ref))\n }\n return `<hc:fillBrush>${win}${grad}${img}</hc:fillBrush>`\n}\nconst HATCHES = [\"HORIZONTAL\", \"VERTICAL\", \"BACK_SLASH\", \"SLASH\", \"CROSS\", \"CROSS_DIAGONAL\"] as const\n\nfunction fontFaces(recs: Rec[], counts: number[]): string {\n let k = 0\n let out = \"\"\n LANGS.forEach((lang, li) => {\n const n = counts[li] ?? 0\n let fonts = \"\"\n for (let id = 0; id < n; id++) {\n const r = recs[k++]\n if (!r) break\n const c = new Cur(r.data)\n const flags = c.u8()\n const face = c.str()\n let inner = \"\"\n if (flags & 0x80) {\n const t = c.u8()\n const alt = c.str()\n inner += el(\"hh:substFont\", [[\"face\", alt], [\"type\", pick(FONT_TYPES, t)], [\"isEmbedded\", 0], [\"binaryItemIDRef\", \"\"]])\n }\n if (flags & 0x40) {\n const p = [...c.d.subarray(c.o, c.o + 10)]\n c.skip(10)\n if (p[0] !== 0xff) {\n // 한글 기본 글꼴은 설치된 글꼴의 굵기로 고쳐 쓴다(옛 판 글꼴로 저장된 8 → 6)\n const weight = face === \"함초롬바탕\" || face === \"함초롬돋움\" ? 6 : p[2]\n inner += el(\"hh:typeInfo\", [[\"familyType\", FONT_FAMILIES[p[0]] ?? \"FCAT_UNKNOWN\"], [\"weight\", weight], [\"proportion\", p[3]],\n [\"contrast\", p[4]], [\"strokeVariation\", p[5]], [\"armStyle\", p[6]], [\"letterform\", p[7]], [\"midline\", p[8]], [\"xHeight\", p[9]]])\n }\n }\n fonts += el(\"hh:font\", [[\"id\", id], [\"face\", face], [\"type\", pick(FONT_TYPES, flags & 3)], [\"isEmbedded\", 0]], inner || undefined)\n }\n out += el(\"hh:fontface\", [[\"lang\", lang], [\"fontCnt\", n]], fonts)\n })\n return el(\"hh:fontfaces\", [[\"itemCnt\", LANGS.length]], out)\n}\n\nfunction borderFill(r: Rec, id: number, ref: BinRef): string {\n const c = new Cur(r.data)\n const a = c.u16()\n const side = (): Array<[string, string | number]> => {\n const type = c.u8(), width = c.u8(), col = c.u32()\n return [[\"type\", pick(BORDER_TYPES, type)], [\"width\", pick(BORDER_WIDTHS, width)], [\"color\", color(col)]]\n }\n const left = side(), right = side(), top = side(), bottom = side()\n const dType = c.u8(), dWidth = c.u8(), dColor = c.u32()\n const slash = bits(a, 2, 3), back = bits(a, 5, 3)\n // 꺾은선은 / 대각선만 두 비트 값 그대로 — 비트 10 은 한글이 셀 나눔선(breakCellSeparateLine)으로 쓰고 \\ 대각선 꺾은선은 0 으로 적는다\n let inner = el(\"hh:slash\", [[\"type\", pick(SLASH_TYPES, slash)], [\"Crooked\", bits(a, 8, 2)], [\"isCounter\", bit(a, 11)]])\n + el(\"hh:backSlash\", [[\"type\", pick(SLASH_TYPES, back)], [\"Crooked\", 0], [\"isCounter\", bit(a, 12)]])\n + el(\"hh:leftBorder\", left) + el(\"hh:rightBorder\", right) + el(\"hh:topBorder\", top) + el(\"hh:bottomBorder\", bottom)\n if (dType) inner += el(\"hh:diagonal\", [[\"type\", pick(BORDER_TYPES, dType)], [\"width\", pick(BORDER_WIDTHS, dWidth)], [\"color\", color(dColor)]])\n inner += fillBrushXml(c, ref)\n return el(\"hh:borderFill\", [[\"id\", id], [\"threeD\", bit(a, 0)], [\"shadow\", bit(a, 1)], [\"centerLine\", bit(a, 13) ? \"VERTICAL\" : \"NONE\"],\n [\"breakCellSeparateLine\", bit(a, 10)]], inner)\n}\n\nfunction charPr(r: Rec, id: number): string {\n const c = new Cur(r.data)\n const lang = (read: () => number): Array<[string, number]> => LANG_ATTRS.map(k => [k, read()])\n const fontRef = lang(() => c.u16())\n const ratio = lang(() => c.u8())\n const spacing = lang(() => c.i8())\n const relSz = lang(() => c.u8())\n const offset = lang(() => c.i8())\n const height = c.i32()\n const a = c.u32()\n const shadowX = c.i8(), shadowY = c.i8()\n const textColor = c.u32(), underColor = c.u32(), shadeColor = c.u32(), shadowColor = c.u32()\n const borderFillId = r.data.length >= 70 ? c.u16() : 0\n const strikeColor = r.data.length >= 74 ? c.u32() : 0\n // 밑줄 종류 2(가운데)는 한글이 취소선으로 다뤄 밑줄 없음·실선·검정으로 쓴다. 취소선 비트가 서면 저장된 모양을 그대로 쓴다\n const underType = bits(a, 2, 2)\n let inner = el(\"hh:fontRef\", fontRef) + el(\"hh:ratio\", ratio) + el(\"hh:spacing\", spacing) + el(\"hh:relSz\", relSz) + el(\"hh:offset\", offset)\n if (bit(a, 0)) inner += \"<hh:italic/>\"\n if (bit(a, 1)) inner += \"<hh:bold/>\"\n inner += el(\"hh:underline\", [[\"type\", underType === 2 ? \"NONE\" : pick(UNDERLINE_TYPES, underType)],\n [\"shape\", underType === 2 ? \"SOLID\" : pick(LINE_SHAPES, bits(a, 4, 4))], [\"color\", underType === 2 ? \"#000000\" : color(underColor)]])\n inner += el(\"hh:strikeout\", [[\"shape\", bits(a, 18, 3) ? pick(LINE_SHAPES, bits(a, 26, 4)) : \"NONE\"], [\"color\", color(strikeColor)]])\n inner += el(\"hh:outline\", [[\"type\", pick(OUTLINE_TYPES, bits(a, 8, 3))]])\n inner += el(\"hh:shadow\", [[\"type\", pick(SHADOW_TYPES, bits(a, 11, 2))], [\"color\", color(shadowColor)], [\"offsetX\", shadowX], [\"offsetY\", shadowY]])\n if (bit(a, 13)) inner += \"<hh:emboss/>\"\n if (bit(a, 14)) inner += \"<hh:engrave/>\"\n if (bit(a, 15)) inner += \"<hh:supscript/>\"\n if (bit(a, 16)) inner += \"<hh:subscript/>\"\n return el(\"hh:charPr\", [[\"id\", id], [\"height\", height], [\"textColor\", color(textColor)], [\"shadeColor\", color(shadeColor)],\n [\"useFontSpace\", bit(a, 25)], [\"useKerning\", bit(a, 30)], [\"symMark\", pick(SYM_MARKS, bits(a, 21, 4))], [\"borderFillIDRef\", borderFillId]], inner)\n}\n\nfunction tabPr(r: Rec, id: number): string {\n const c = new Cur(r.data)\n const a = c.u32()\n const n = c.i32()\n let inner = \"\"\n for (let i = 0; i < n && c.rest >= 8; i++) {\n const pos = c.i32(), type = c.u8(), leader = c.u8()\n c.skip(2)\n const common: Array<[string, string | number]> = [[\"type\", pick(TAB_TYPES, type)], [\"leader\", pick(BORDER_TYPES, leader)]]\n inner += unitSwitch(el(\"hh:tabItem\", [[\"pos\", Math.trunc(pos / 2)], ...common, [\"unit\", pos % 2 ? \"CHAR\" : \"HWPUNIT\"]]), el(\"hh:tabItem\", [[\"pos\", pos], ...common]))\n }\n return el(\"hh:tabPr\", [[\"id\", id], [\"autoTabLeft\", bit(a, 0)], [\"autoTabRight\", bit(a, 1)]], inner || undefined)\n}\n\n/** 문단 머리 정보 12바이트(속성·너비 보정·본문과의 거리·글자 모양) → paraHead 속성 */\nfunction paraHeadAttrs(c: Cur): Array<[string, string | number]> {\n const a = c.u32(), widthAdjust = c.i16(), textOffset = c.i16(), charShape = c.u32()\n return [[\"align\", pick(HEAD_ALIGNS, bits(a, 0, 2))], [\"useInstWidth\", bit(a, 2)], [\"autoIndent\", bit(a, 3)], [\"widthAdjust\", widthAdjust],\n [\"textOffsetType\", bit(a, 4) ? \"HWPUNIT\" : \"PERCENT\"], [\"textOffset\", textOffset], [\"numFormat\", pick(NUM_FORMATS, bits(a, 5, 4))],\n [\"charPrIDRef\", charShape], [\"checkable\", bit(a, 5)]]\n}\n\nfunction numbering(r: Rec, id: number): string {\n const c = new Cur(r.data)\n const heads: Array<{ attrs: Array<[string, string | number]>; fmt: string }> = []\n for (let lv = 0; lv < 7; lv++) heads.push({ attrs: paraHeadAttrs(c), fmt: c.str() })\n const start = c.u16()\n const starts = heads.map(() => (c.rest >= 4 ? c.u32() : 1))\n // 수준 8~10 (한글 2018 이상) — 머리 정보 셋·형식 문자열 셋·시작 번호 셋. 없는 판은 한글이 빈 기본값(번호 1·DIGIT·글자 모양 0)으로 채운다\n if (c.rest >= 3 * 14 + 12) {\n const ext = [0, 1, 2].map(() => ({ attrs: paraHeadAttrs(c), fmt: c.str() }))\n for (const e of ext) heads.push(e)\n for (let i = 0; i < 3; i++) starts.push(c.u32())\n } else {\n for (let i = 0; i < 3; i++) { heads.push({ attrs: paraHeadAttrs(new Cur(Buffer.alloc(12))), fmt: \"\" }); starts.push(1) }\n }\n const inner = heads.map((h, i) => el(\"hh:paraHead\", [[\"start\", starts[i] ?? 1], [\"level\", i + 1], ...h.attrs], h.fmt ? escText(h.fmt) : undefined)).join(\"\")\n return el(\"hh:numbering\", [[\"id\", id], [\"start\", start]], inner)\n}\n\nfunction bullet(r: Rec, id: number): string {\n const c = new Cur(r.data)\n const head = paraHeadAttrs(c)\n const ch = String.fromCharCode(c.u16())\n const imageId = c.i32()\n // 체크 글자는 기록 끝 두 바이트 — 그림 글머리 정보가 4바이트인 24바이트 기록과 5바이트인 25바이트 기록이 있다\n const checked = r.data.length >= 24 ? r.data.readUInt16LE(r.data.length - 2) : 0\n let inner = el(\"hh:paraHead\", [[\"level\", 0], ...head])\n if (imageId) inner = el(\"hc:img\", []) + inner\n // 체크 글자가 비었거나 공백이면 한글은 checkedChar 를 쓰지 않는다\n return el(\"hh:bullet\", [[\"id\", id], [\"char\", ch], ...(checked > 0x20 ? [[\"checkedChar\", String.fromCharCode(checked)] as [string, string]] : []),\n [\"useImage\", imageId ? 1 : 0]], inner)\n}\n\nfunction paraPr(r: Rec, id: number): string {\n const c = new Cur(r.data)\n const a1 = c.u32()\n const left = c.i32(), right = c.i32(), indent = c.i32(), prev = c.i32(), next = c.i32()\n const oldSpacing = c.i32()\n const tabDef = c.u16(), headId = c.u16(), borderFillId = c.u16()\n const off = [c.i16(), c.i16(), c.i16(), c.i16()]\n const a2 = c.u32()\n const hasNew = r.data.length >= 54\n const a3 = hasNew ? c.u32() : 0\n const spacing = hasNew ? c.u32() : oldSpacing\n const spType = hasNew ? bits(a3, 0, 5) : bits(a1, 0, 2)\n // 제목 수준 전체 값(0~9) — 3비트 칸(bits 25-27)은 7 이상을 못 담는다. 8수준 이상은 한글 2016 문단 이름공간 갈래에만 적는다\n const level = r.data.length >= 58 ? c.u32() : bits(a1, 25, 3)\n const headType = pick(HEADING_TYPES, bits(a1, 23, 2))\n const heading = level >= 7\n ? `<hp:switch><hp:case hp:required-namespace=\"http://www.hancom.co.kr/hwpml/2016/paragraph\">${el(\"hh:heading\", [[\"type\", headType], [\"idRef\", headId], [\"level\", level]])}</hp:case>`\n + `<hp:default>${el(\"hh:heading\", [[\"type\", \"NONE\"], [\"idRef\", 0], [\"level\", 0]])}</hp:default></hp:switch>`\n : el(\"hh:heading\", [[\"type\", headType], [\"idRef\", headId], [\"level\", level]])\n // HwpUnitChar 갈래는 값의 절반 — 반으로 안 나뉘는 홀수 값은 한글이 글자 단위(CHAR)로 적는다\n const margins = (div: number): string => {\n const m = (tag: string, x: number): string => el(tag, [[\"value\", div === 1 ? x : Math.trunc(x / div)], [\"unit\", div !== 1 && x % 2 ? \"CHAR\" : \"HWPUNIT\"]])\n return \"<hh:margin>\" + m(\"hc:intent\", indent) + m(\"hc:left\", left) + m(\"hc:right\", right) + m(\"hc:prev\", prev) + m(\"hc:next\", next) + \"</hh:margin>\"\n }\n const lineSpacing = (div: number): string => el(\"hh:lineSpacing\", [[\"type\", pick(LINE_SPACINGS, spType)],\n [\"value\", spType === 0 || div === 1 ? spacing : Math.trunc(spacing / div)], [\"unit\", \"HWPUNIT\"]])\n const inner = el(\"hh:align\", [[\"horizontal\", pick(PARA_ALIGNS, bits(a1, 2, 3))], [\"vertical\", pick(VERT_ALIGNS, bits(a1, 20, 2))]])\n + heading\n + el(\"hh:breakSetting\", [[\"breakLatinWord\", pick(LATIN_BREAKS, bits(a1, 5, 2))], [\"breakNonLatinWord\", bit(a1, 7) ? \"KEEP_WORD\" : \"BREAK_WORD\"],\n [\"widowOrphan\", bit(a1, 16)], [\"keepWithNext\", bit(a1, 17)], [\"keepLines\", bit(a1, 18)], [\"pageBreakBefore\", bit(a1, 19)],\n [\"lineWrap\", pick(LINE_WRAPS, bits(a2, 0, 2))]])\n + el(\"hh:autoSpacing\", [[\"eAsianEng\", bit(a2, 4)], [\"eAsianNum\", bit(a2, 5)]])\n + unitSwitch(margins(2) + lineSpacing(2), margins(1) + lineSpacing(1))\n + el(\"hh:border\", [[\"borderFillIDRef\", borderFillId], [\"offsetLeft\", off[0]], [\"offsetRight\", off[1]], [\"offsetTop\", off[2]],\n [\"offsetBottom\", off[3]], [\"connect\", bit(a1, 28)], [\"ignoreMargin\", bit(a1, 29)]])\n // 글 방향은 한글 2024 꼴로 적는다 — 속성2 비트 3 이 켜진 문단 모양은 LTR, 나머지는 AUTO(한글 2022 는 이 속성을 쓰지 않는다)\n return el(\"hh:paraPr\", [[\"id\", id], [\"tabPrIDRef\", tabDef], [\"condense\", bits(a1, 9, 7)], [\"fontLineHeight\", bit(a1, 22)],\n [\"snapToGrid\", bit(a1, 8)], [\"suppressLineNumbers\", bit(a2, 2)], [\"checked\", 0], [\"textDir\", bit(a2, 3) ? \"LTR\" : \"AUTO\"]], inner)\n}\n\nfunction style(r: Rec, id: number, paraIds: number[]): string {\n const c = new Cur(r.data)\n const name = c.str(), engName = c.str()\n const a = c.u8(), nextId = c.u8(), langId = c.i16(), paraShape = c.u16(), charShape = c.u16()\n return el(\"hh:style\", [[\"id\", id], [\"type\", bits(a, 0, 2) === 1 ? \"CHAR\" : \"PARA\"], [\"name\", name], [\"engName\", engName],\n [\"paraPrIDRef\", paraIds[paraShape] ?? paraShape], [\"charPrIDRef\", charShape], [\"nextStyleIDRef\", nextId], [\"langID\", langId], [\"lockForm\", bit(a, 2)]])\n}\n\nfunction memoPr(r: Rec, id: number): string {\n const c = new Cur(r.data)\n const width = c.u32(), lineWidth = c.u8(), lineType = c.u8(), lineColor = c.u32(), fillColor = c.u32(), activeColor = c.u32(), type = c.u16()\n return el(\"hh:memoPr\", [[\"id\", id], [\"width\", width], [\"lineWidth\", lineWidth], [\"lineType\", pick(BORDER_TYPES, lineType)],\n [\"lineColor\", color(lineColor)], [\"fillColor\", color(fillColor)], [\"activeColor\", color(activeColor)], [\"memoType\", pick(MEMO_TYPES, type)]])\n}\n\n/** 문서 속성(구역 수·시작 번호·캐럿 위치) */\nexport interface DocProps { secCnt: number; begin: number[]; caret: [number, number, number] }\n\nexport function docProps(recs: Rec[]): DocProps {\n const r = recs.find(x => x.tagId === TAG.DOCUMENT_PROPERTIES)\n const c = new Cur(r?.data ?? Buffer.alloc(0))\n const secCnt = c.u16()\n const begin = [c.u16(), c.u16(), c.u16(), c.u16(), c.u16(), c.u16()]\n return { secCnt, begin, caret: [c.u32(), c.u32(), c.u32()] }\n}\n\n/** ID_MAPPINGS 의 목록별 개수 칸 */\nconst SLOT: Record<number, number> = { [TAG.BORDER_FILL]: 8, [TAG.CHAR_SHAPE]: 9, [TAG.TAB_DEF]: 10, [TAG.NUMBERING]: 11, [TAG.BULLET]: 12,\n [TAG.PARA_SHAPE]: 13, [TAG.STYLE]: 14, [TAG.MEMO_SHAPE]: 15 }\n\nfunction idCounts(recs: Rec[]): number[] {\n const idm = new Cur(recs.find(r => r.tagId === TAG.ID_MAPPINGS)?.data ?? Buffer.alloc(0))\n const counts: number[] = []\n while (idm.rest >= 4) counts.push(idm.i32())\n return counts\n}\n\n/** DocInfo 목록 하나 — 길이는 ID_MAPPINGS 가 정한다(그 뒤에 남은 레코드는 쓰지 않는다) */\nfunction recordsOf(recs: Rec[], counts: number[], tag: number): Rec[] {\n const all = recs.filter(r => r.tagId === tag)\n const n = counts[SLOT[tag] ?? -1]\n return n !== undefined && n >= 0 ? all.slice(0, n) : all\n}\n\n/** 문단 모양 번호 → paraPr id. 기록 바이트가 같은 문단 모양은 한글처럼 처음 것 하나로 합친다(글자 모양·테두리는 합치지 않는다) */\nexport function paraShapeIds(recs: Rec[]): number[] {\n const seen = new Map<string, number>()\n return recordsOf(recs, idCounts(recs), TAG.PARA_SHAPE).map(r => {\n const k = r.data.toString(\"hex\")\n if (!seen.has(k)) seen.set(k, seen.size)\n return seen.get(k)!\n })\n}\n\n/** DocInfo 레코드 → header.xml. secCnt 는 실제로 쓰는 구역 수(다르면 한글이 열기를 거부한다) */\nexport function headerXml(recs: Rec[], linkInfo: { path: string; pageInherit: number; footnoteInherit: number }, ref: BinRef, secCnt: number): string {\n const props = docProps(recs)\n const counts = idCounts(recs)\n const of = (tag: number): Rec[] => recordsOf(recs, counts, tag)\n const paraIds = paraShapeIds(recs)\n const list = (name: string, items: string[]): string => (items.length ? el(name, [[\"itemCnt\", items.length]], items.join(\"\")) : \"\")\n\n const [bPage, bFoot, bEnd, bPic, bTbl, bEq] = props.begin\n let refList = fontFaces(of(TAG.FACE_NAME), counts.slice(1, 8))\n refList += list(\"hh:borderFills\", of(TAG.BORDER_FILL).map((r, i) => borderFill(r, i + 1, ref)))\n refList += list(\"hh:charProperties\", of(TAG.CHAR_SHAPE).map((r, i) => charPr(r, i)))\n refList += list(\"hh:tabProperties\", of(TAG.TAB_DEF).map((r, i) => tabPr(r, i)))\n refList += list(\"hh:numberings\", of(TAG.NUMBERING).map((r, i) => numbering(r, i + 1)))\n refList += list(\"hh:bullets\", of(TAG.BULLET).map((r, i) => bullet(r, i + 1)))\n refList += list(\"hh:paraProperties\", of(TAG.PARA_SHAPE).flatMap((r, i) => (paraIds.indexOf(paraIds[i]) === i ? [paraPr(r, paraIds[i])] : [])))\n refList += list(\"hh:styles\", of(TAG.STYLE).map((r, i) => style(r, i, paraIds)))\n refList += list(\"hh:memoProperties\", of(TAG.MEMO_SHAPE).map((r, i) => memoPr(r, i + 1)))\n\n const compat = new Cur(recs.find(r => r.tagId === TAG.COMPATIBLE_DOCUMENT)?.data ?? Buffer.alloc(0)).u32()\n const track = new Cur(recs.find(r => r.tagId === TAG.TRACKCHANGE)?.data ?? Buffer.alloc(0)).u32()\n return XML_DECL + `<hh:head ${NS} version=\"1.5\" secCnt=\"${secCnt}\">`\n + el(\"hh:beginNum\", [[\"page\", bPage], [\"footnote\", bFoot], [\"endnote\", bEnd], [\"pic\", bPic], [\"tbl\", bTbl], [\"equation\", bEq]])\n + `<hh:refList>${refList}</hh:refList>`\n + el(\"hh:compatibleDocument\", [[\"targetProgram\", pick(TARGET_PROGRAMS, compat)]], \"<hh:layoutCompatibility/>\")\n + el(\"hh:docOption\", [], el(\"hh:linkinfo\", [[\"path\", linkInfo.path], [\"pageInherit\", linkInfo.pageInherit], [\"footnoteInherit\", linkInfo.footnoteInherit]]))\n + el(\"hh:trackchageConfig\", [[\"flags\", track]])\n + \"</hh:head>\"\n}\n","/**\n * HWP 5.x 필드 컨트롤('%clk' 누름틀·'%hlk' 하이퍼링크·'%usr' 사용자 정보·'%fmu' 계산식·'%bmk' 책갈피 …) → hp:fieldBegin / hp:fieldEnd.\n *\n * CTRL_HEADER: 컨트롤 id · 속성 u32(bit0 양식 모드에서 편집 가능, bit15 내용 고침) · 기타 속성 u8(=Prop) · 명령 문자열 · 필드 id u32.\n * 이름은 CTRL_DATA 매개변수 묶음의 문자열 항목. fieldid 는 컨트롤 id 4바이트를 u32 로 읽은 값('%clk' → 627272811).\n * 매개변수는 명령을 종류별로 풀어 쓴다 — 누름틀 안내문·도움말, 하이퍼링크 경로·종류, 계산식·결과 형식·마지막 값.\n */\n\nimport { Cur, type RecNode, el, escText } from \"./util.js\"\nimport { fileTimeText as fileTime } from \"../record.js\"\nimport { TAG, paragraphsXml } from \"./section.js\"\nimport { subListAttrs, type ConvertContext } from \"./controls.js\"\n\nconst FIELD_TYPES: Record<string, string> = {\n \"%clk\": \"CLICK_HERE\", \"%hlk\": \"HYPERLINK\", \"%usr\": \"USER_INFO\", \"%fmu\": \"FORMULA\", \"%bmk\": \"BOOKMARK\", \"%dte\": \"DATE\", \"%ddt\": \"DOC_DATE\",\n \"%pat\": \"PATH\", \"%mmg\": \"MAILMERGE\", \"%xrf\": \"CROSSREF\", \"%smr\": \"SUMMERY\", \"%prv\": \"PRIVATE_INFO\", \"%toc\": \"TABLEOFCONTENTS\",\n \"%%me\": \"MEMO\", \"%cpr\": \"PRIVATE_INFO\", \"%unk\": \"UNKNOWN\",\n}\nconst LINK_CATEGORIES = [\"HWPHYPERLINK_TYPE_HWP\", \"HWPHYPERLINK_TYPE_URL\", \"HWPHYPERLINK_TYPE_EMAIL\", \"HWPHYPERLINK_TYPE_EX\"] as const\nconst LINK_TARGETS = [\"HWPHYPERLINK_TARGET_BOOKMARK\", \"HWPHYPERLINK_TARGET_OUTLINE\", \"HWPHYPERLINK_TARGET_TABLE\",\n \"HWPHYPERLINK_TARGET_FIGURE\", \"HWPHYPERLINK_TARGET_EQUATION\", \"HWPHYPERLINK_TARGET_HYPERLINK\"] as const\nconst LINK_OPENS = [\"HWPHYPERLINK_JUMP_CURRENTTAB\", \"HWPHYPERLINK_JUMP_NEWTAB\", \"HWPHYPERLINK_JUMP_NEWWINDOW\", \"HWPHYPERLINK_JUMP_DONTCARE\"] as const\n\n/** CTRL_DATA 매개변수 묶음의 첫 문자열 항목 — 필드 이름 */\nfunction ctrlDataName(node: RecNode): string {\n const cd = node.kids.find(k => k.rec.tagId === TAG.CTRL_DATA)\n if (!cd || cd.rec.data.length < 12) return \"\"\n const d = cd.rec.data\n const n = d.readUInt16LE(10)\n return d.length >= 12 + n * 2 ? d.toString(\"utf16le\", 12, 12 + n * 2) : \"\"\n}\n\nconst str = (name: string, v: string, preserve = false): string =>\n `<hp:stringParam name=\"${name}\"${preserve ? ' xml:space=\"preserve\"' : \"\"}>${escText(v)}</hp:stringParam>`\n\n/** \"Key:wstring:N:값\" 꼴에서 값 N 글자 */\nfunction wstringValue(command: string, key: string): string {\n const m = new RegExp(`${key}:wstring:(\\\\d+):`).exec(command)\n return m ? command.slice(m.index + m[0].length, m.index + m[0].length + Number(m[1])) : \"\"\n}\n\nfunction params(type: string, prop: number, command: string): string {\n const items: string[] = [`<hp:integerParam name=\"Prop\">${prop}</hp:integerParam>`]\n const preserve = /^\\s|\\s$/.test(command)\n if (type === \"BOOKMARK\") return `<hp:parameters cnt=\"1\" name=\"\">${items[0]}</hp:parameters>`\n items.push(str(\"Command\", command, preserve))\n // 명령에 없는 안내문(Direction)·빈 경로(Path)는 한글이 매개변수째 뺀다\n if (type === \"CLICK_HERE\") {\n if (/Direction:wstring:/.test(command)) items.push(str(\"Direction\", wstringValue(command, \"Direction\")))\n const help = wstringValue(command, \"HelpState\")\n if (help) items.push(str(\"HelpState\", help))\n } else if (type === \"HYPERLINK\") {\n const parts = command.split(/(?<!\\\\);/)\n if (parts[0]) items.push(str(\"Path\", parts[0].replace(/\\\\(.)/g, \"$1\")))\n items.push(str(\"Category\", LINK_CATEGORIES[Number(parts[1])] ?? LINK_CATEGORIES[1]))\n items.push(str(\"TargetType\", LINK_TARGETS[Number(parts[2])] ?? LINK_TARGETS[0]))\n items.push(str(\"DocOpenType\", LINK_OPENS[Number(parts[3])] ?? LINK_OPENS[0]))\n } else if (type === \"USER_INFO\") {\n items.push(str(\"Category\", command))\n } else if (type === \"FORMULA\") {\n const [formula, rest = \"\"] = command.split(\"??\")\n const [format, last = \"\"] = rest.split(\";;\")\n items.push(str(\"Formula\", formula), str(\"ResultFormat\", format), str(\"LastResult\", last))\n }\n return `<hp:parameters cnt=\"${items.length}\" name=\"\">${items.join(\"\")}</hp:parameters>`\n}\n\nexport interface FieldState { stack: Array<{ id: number; fieldid: number }> }\n\n\n/**\n * 메모 — HWP 는 '%unk' 필드에 \"MEMO/모양/번호/생성 시각 하위/상위/작성자/\" 명령을 두고 글은 구역 끝 메모 목록에 둔다. HWPX 는 MEMO 필드\n * ('%%me') 매개변수와 subList 로 쓴다\n */\nfunction memoFieldXml(id: number, a: number, prop: number, command: string, ctx: ConvertContext): string {\n const [, shape = \"\", num = \"0\", low = \"0\", high = \"0\", author = \"\"] = command.split(\"/\")\n const n = Number(num) || 0\n const items = [`<hp:integerParam name=\"Prop\">${prop}</hp:integerParam>`, str(\"Command\", command), str(\"ID\", `memo${n}`),\n `<hp:integerParam name=\"Number\">${n}</hp:integerParam>`, str(\"Author\", author), str(\"MemoShapeIDRef\", shape),\n str(\"CreateDateTime\", fileTime(Number(low) >>> 0, Number(high) >>> 0))]\n const g = ctx.memos.get(n)\n return el(\"hp:fieldBegin\", [[\"id\", id], [\"type\", \"MEMO\"], [\"name\", \"\"], [\"editable\", a & 1], [\"dirty\", (a >>> 15) & 1], [\"zorder\", n],\n [\"fieldid\", 0x25256d65]], `<hp:parameters cnt=\"${items.length}\" name=\"\">${items.join(\"\")}</hp:parameters>`\n + (g ? el(\"hp:subList\", subListAttrs(g.head.rec.data), paragraphsXml(g.paras, ctx)) : \"\"))\n}\n\n/** 필드 시작 컨트롤 → hp:ctrl/hp:fieldBegin, 열린 필드에 쌓는다 */\nexport function fieldBeginXml(node: RecNode, kind: string, ctx: ConvertContext): string {\n const state = ctx.fields\n const c = new Cur(node.rec.data, 4)\n const a = c.u32(), prop = c.u8(), command = c.str(), id = c.u32()\n if (kind === \"%unk\" && command.startsWith(\"MEMO/\")) {\n state.stack.push({ id, fieldid: 0x25256d65 })\n return \"<hp:ctrl>\" + memoFieldXml(id, a, prop, command, ctx) + \"</hp:ctrl>\"\n }\n const fieldid = node.rec.data.readUInt32LE(0)\n state.stack.push({ id, fieldid })\n const type = FIELD_TYPES[kind] ?? \"UNKNOWN\"\n return \"<hp:ctrl>\" + el(\"hp:fieldBegin\", [[\"id\", id], [\"type\", type], [\"name\", ctrlDataName(node)], [\"editable\", a & 1],\n [\"dirty\", (a >>> 15) & 1], [\"zorder\", -1], [\"fieldid\", fieldid]], params(type, prop, command)) + \"</hp:ctrl>\"\n}\n\n/** 필드 끝(인라인 컨트롤 4) — 가장 안쪽 열린 필드와 짝 */\nexport function fieldEndXml(state: FieldState): string {\n const f = state.stack.pop()\n return f ? \"<hp:ctrl>\" + el(\"hp:fieldEnd\", [[\"beginIDRef\", f.id], [\"fieldid\", f.fieldid]]) + \"</hp:ctrl>\" : \"\"\n}\n","/**\n * HWP 5.x 그리기 개체('gso ') → hp:pic · hp:rect · hp:ellipse · hp:arc · hp:polygon · hp:curve · hp:line · hp:connectLine · hp:container.\n *\n * CTRL_HEADER(개체 공통 속성) 아래 SHAPE_COMPONENT 가 개체 요소(위치·크기·뒤집기·회전·변환 행렬, 그리기 개체는 선·채우기·그림자)를\n * 담고, 그 자식이 개체별 레코드(PICTURE·RECTANGLE …)와 글상자(LIST_HEADER + 문단)다. 묶음($con) 안 자식은 SHAPE_COMPONENT 가\n * 개체 공통 속성 없이 이어져 id·zOrder 가 0 이고 sz·pos 가 없다. 수는 한글 저장 꼴대로 쓴다 — 좌표·크기는 부호 없는 32비트,\n * 변환 행렬은 단정밀도로 줄여 소수 여섯째 자리까지.\n */\n\nimport { Cur, type RecNode, readParamSet, subSet, el, escText, color, pick, bit, bits, BORDER_TYPES } from \"./util.js\"\nimport { fillBrushXml } from \"./header.js\"\nimport { TAG, paragraphsXml } from \"./section.js\"\nimport { type ConvertContext, type ObjCommon, readObjCommon, objHeadAttrs, objPlacementXml, subListAttrs, listGroups, captionXml } from \"./controls.js\"\n\nconst TAG_SHAPE = {\n LINE: 0x4e, RECTANGLE: 0x4f, ELLIPSE: 0x50, ARC: 0x51, POLYGON: 0x52, CURVE: 0x53, OLE: 0x54, PICTURE: 0x55, CONTAINER: 0x56,\n} as const\n\nconst TAG_CTRL_DATA = 0x57\nconst u32 = (v: number): number => v >>> 0\n/** 배정밀도 값 그대로 소수 여섯째 자리, 끝 0 은 지운다 */\nexport function num6(v: number): string {\n const s = v.toFixed(6).replace(/\\.?0+$/, \"\")\n return s === \"-0\" ? \"0\" : s\n}\n\n/** 개체 요소(SHAPE_COMPONENT) 앞부분 */\ninterface Component {\n kind: string\n offsetX: number; offsetY: number; groupLevel: number\n orgW: number; orgH: number; curW: number; curH: number\n flip: number; angle: number; cx: number; cy: number\n rendering: string\n /** 행렬 뒤 — 그리기 개체의 선·채우기·그림자 */\n rest: Cur\n}\n\nfunction readComponent(node: RecNode): Component {\n const d = node.rec.data\n const two = d.length >= 8 && d.readUInt32LE(0) === d.readUInt32LE(4)\n const kind = d.length >= 4 ? String.fromCharCode(d[3], d[2], d[1], d[0]) : \"\"\n const c = new Cur(d, two ? 8 : 4)\n const offsetX = c.i32(), offsetY = c.i32(), groupLevel = c.u16()\n c.u16()\n const orgW = c.u32(), orgH = c.u32(), curW = c.u32(), curH = c.u32(), flip = c.u32()\n const angle = c.i16(), cx = c.i32(), cy = c.i32()\n const n = c.u16()\n const matrix = (name: string): string => {\n const v: number[] = []\n for (let i = 0; i < 6; i++) { v.push(c.o + 8 <= d.length ? d.readDoubleLE(c.o) : 0); c.o += 8 }\n return el(name, v.map((x, i) => [`e${i + 1}`, num6(x)]))\n }\n let rendering = matrix(\"hc:transMatrix\")\n for (let i = 0; i < n; i++) rendering += matrix(\"hc:scaMatrix\") + matrix(\"hc:rotMatrix\")\n return { kind, offsetX, offsetY, groupLevel, orgW, orgH, curW, curH, flip, angle, cx, cy, rendering: `<hp:renderingInfo>${rendering}</hp:renderingInfo>`, rest: c }\n}\n\n/** offset · orgSz · curSz(원래 크기와 같은 축은 0) · flip · rotationInfo · renderingInfo */\nfunction componentHeadXml(k: Component): string {\n return el(\"hp:offset\", [[\"x\", u32(k.offsetX)], [\"y\", u32(k.offsetY)]]) + el(\"hp:orgSz\", [[\"width\", k.orgW], [\"height\", k.orgH]])\n + el(\"hp:curSz\", [[\"width\", k.curW === k.orgW ? 0 : k.curW], [\"height\", k.curH === k.orgH ? 0 : k.curH]]) + el(\"hp:flip\", [[\"horizontal\", bit(k.flip, 0)], [\"vertical\", bit(k.flip, 1)]])\n + el(\"hp:rotationInfo\", [[\"angle\", k.angle], [\"centerX\", k.cx], [\"centerY\", k.cy], [\"rotateimage\", bit(k.flip, 19)]]) + k.rendering\n}\n\nconst ARROW_STYLES = [\"NORMAL\", \"ARROW\", \"SPEAR\", \"CONCAVE_ARROW\", \"EMPTY_DIAMOND\", \"EMPTY_CIRCLE\", \"EMPTY_BOX\", \"FILLED_DIAMOND\",\n \"FILLED_CIRCLE\", \"FILLED_BOX\"] as const\nconst ARROW_SIZES = [\"SMALL_SMALL\", \"SMALL_MEDIUM\", \"SMALL_LARGE\", \"MEDIUM_SMALL\", \"MEDIUM_MEDIUM\", \"MEDIUM_LARGE\", \"LARGE_SMALL\",\n \"LARGE_MEDIUM\", \"LARGE_LARGE\"] as const\nconst OUTLINE_STYLES = [\"NORMAL\", \"OUTER\", \"INNER\"] as const\nconst END_CAPS = [\"ROUND\", \"FLAT\"] as const\nconst SHADOW_TYPES = [\"NONE\", \"PARELLEL_LEFTTOP\", \"PARELLEL_RIGHTTOP\", \"PARELLEL_LEFTBOTTOM\", \"PARELLEL_RIGHTBOTTOM\", \"SHEAR_LEFTTOP\",\n \"SHEAR_RIGHTTOP\", \"SHEAR_LEFTBOTTOM\", \"SHEAR_RIGHTBOTTOM\", \"SHEAR_LEFTTOP\", \"SHEAR_RIGHTTOP\"] as const\n\n/** 선 — 색·굵기·속성(종류·끝 모양·화살표) */\nfunction lineShapeXml(lineColor: number, width: number, a: number, outline: number): string {\n return el(\"hp:lineShape\", [[\"color\", color(lineColor)], [\"width\", width], [\"style\", pick(BORDER_TYPES, bits(a, 0, 6))],\n [\"endCap\", pick(END_CAPS, bits(a, 6, 4))], [\"headStyle\", pick(ARROW_STYLES, bits(a, 10, 6))], [\"tailStyle\", pick(ARROW_STYLES, bits(a, 16, 6))],\n [\"headfill\", bit(a, 30)], [\"tailfill\", bit(a, 31)], [\"headSz\", pick(ARROW_SIZES, bits(a, 22, 4))], [\"tailSz\", pick(ARROW_SIZES, bits(a, 26, 4))],\n [\"outlineStyle\", pick(OUTLINE_STYLES, outline)], [\"alpha\", 0]])\n}\n\n/** 그리기 개체 공통 — 선(lineShape) · 채우기(fillBrush) · 그림자(shadow), 그 뒤 인스턴스 id */\nfunction drawingStyle(k: Component, ctx: ConvertContext): { xml: string; instId: number } {\n const c = k.rest\n const lineColor = c.u32(), width = c.i32(), a = c.u32(), outline = c.u8()\n const line = lineShapeXml(lineColor, width, a, outline)\n const fill = fillBrushXml(c, ctx.binRef)\n const sType = c.u32(), sColor = c.u32(), sx = c.i32(), sy = c.i32()\n const instId = c.u32()\n c.u8()\n const sAlpha = c.u8()\n const shadow = el(\"hp:shadow\", [[\"type\", pick(SHADOW_TYPES, sType)], [\"color\", color(sColor)], [\"offsetX\", sx], [\"offsetY\", sy], [\"alpha\", sAlpha]])\n return { xml: line + fill + shadow, instId }\n}\n\n/** 글상자 — SHAPE_COMPONENT 자식 LIST_HEADER(목록 머리·글 여백·마지막 줄 폭·이름) 와 뒤따르는 문단 */\nfunction drawTextXml(comp: RecNode, ctx: ConvertContext): string {\n const g = listGroups(comp.kids)[0]\n if (!g) return \"\"\n const c = new Cur(g.head.rec.data, 8)\n const l = c.i16(), r = c.i16(), t = c.i16(), b = c.i16()\n const lastWidth = c.u32()\n // 글상자 연결(제 목록 id·다음 id) — 사슬의 글은 sectionXml 이 줄 나눔 정보대로 나눠 두었다. 이름 칸은 한글 저장본에서 늘 비어 있다\n const listId = c.u32()\n const paras = (listId && ctx.linkedParas.get(listId)) || g.paras\n return el(\"hp:drawText\", [[\"lastWidth\", lastWidth], [\"name\", \"\"], [\"editable\", 0]],\n el(\"hp:subList\", subListAttrs(g.head.rec.data), paragraphsXml(paras, ctx))\n + el(\"hp:textMargin\", [[\"left\", l], [\"right\", r], [\"top\", t], [\"bottom\", b]]))\n}\n\nconst ELLIPSE_ARC = [\"NORMAL\", \"PIE\", \"CHORD\"] as const\nconst pt = (name: string, c: Cur): string => el(name, [[\"x\", c.i32()], [\"y\", c.i32()]])\n\n/** 개체 하이퍼링크 — 개체 요소 아래 CTRL_DATA 매개변수 묶음(0x26f 안 문자열 0x265) */\nfunction shapeHref(comp: RecNode): string {\n const cd = comp.kids.find(x => x.rec.tagId === TAG_CTRL_DATA)\n const v = cd ? subSet(readParamSet(cd.rec.data, { o: 0 }), 0x26f)?.[0x265] : undefined\n // HWP 하이퍼링크 문자열의 \\: 이스케이프는 한글이 HWPX href 에 풀어 쓴다\n return typeof v === \"string\" ? v.replace(/\\\\:/g, \":\") : \"\"\n}\n\n/** 개체 하나 — 개체 공통 속성(o)이 없으면 묶음 안 자식 */\nfunction shapeXml(comp: RecNode, o: ObjCommon | null, description: string, ctx: ConvertContext, caption: string): string {\n const k = readComponent(comp)\n const sub = (tag: number): Cur => new Cur(comp.kids.find(x => x.rec.tagId === tag)?.rec.data ?? Buffer.alloc(0))\n const head: Array<[string, string | number]> = o ? objHeadAttrs(o)\n : [[\"id\", 0], [\"zOrder\", 0], [\"numberingType\", \"NONE\"], [\"textWrap\", \"TOP_AND_BOTTOM\"], [\"textFlow\", \"BOTH_SIDES\"], [\"lock\", 0], [\"dropcapstyle\", \"None\"]]\n const comment = o && description ? `<hp:shapeComment>${escText(description)}</hp:shapeComment>` : \"\"\n // 개체 설명은 캡션 앞에 둔다(한글 순서)\n const tail = o ? objPlacementXml(o) + comment + caption : comment\n const common = componentHeadXml(k)\n const href = shapeHref(comp)\n\n if (k.kind === \"$pic\") {\n const p = sub(TAG_SHAPE.PICTURE)\n const borderColor = p.u32(), borderWidth = p.i32(), borderAttr = p.u32()\n // 테두리 선이 있을 때만(선 종류 ≠ 없음) 한글이 lineShape 를 쓴다\n const border = bits(borderAttr, 0, 6) ? lineShapeXml(borderColor, borderWidth, borderAttr, 0) : \"\"\n const xs: number[] = [], ys: number[] = []\n for (let i = 0; i < 4; i++) { xs.push(p.i32()); ys.push(p.i32()) }\n const cl = p.i32(), ct = p.i32(), cr = p.i32(), cb = p.i32()\n const m = [p.i16(), p.i16(), p.i16(), p.i16()]\n const contrast = p.i8(), bright = p.i8(), effect = p.u8(), binId = p.u16()\n p.u8()\n const instId = p.u32()\n p.skip(4)\n const dimW = p.u32(), dimH = p.u32()\n const alpha = p.rest >= 1 ? p.d[p.d.length - 1] : 0\n const img = el(\"hc:img\", [[\"binaryItemIDRef\", binId ? ctx.binRef(binId) : \"\"], [\"bright\", bright], [\"contrast\", contrast],\n [\"effect\", pick([\"REAL_PIC\", \"GRAY_SCALE\", \"BLACK_WHITE\", \"PATTERN8x8\"], effect)], [\"alpha\", alpha]])\n const rect = `<hp:imgRect>${[0, 1, 2, 3].map(i => el(`hc:pt${i}`, [[\"x\", xs[i]], [\"y\", ys[i]]])).join(\"\")}</hp:imgRect>`\n return el(\"hp:pic\", [...head, [\"href\", href], [\"groupLevel\", k.groupLevel], [\"instid\", instId], [\"reverse\", 0]],\n common + img + border + rect + el(\"hp:imgClip\", [[\"left\", cl], [\"right\", cr], [\"top\", ct], [\"bottom\", cb]])\n + el(\"hp:inMargin\", [[\"left\", m[0]], [\"right\", m[1]], [\"top\", m[2]], [\"bottom\", m[3]]]) + el(\"hp:imgDim\", [[\"dimwidth\", dimW], [\"dimheight\", dimH]])\n + \"<hp:effects/>\" + tail)\n }\n\n if (k.kind === \"$ole\") return oleXml(comp, k, head, common, o, caption, comment, ctx)\n\n if (k.kind === \"$con\") {\n const kids = comp.kids.filter(x => x.rec.tagId === TAG.SHAPE_COMPONENT).map(x => shapeXml(x, null, \"\", ctx, \"\")).join(\"\")\n // 행렬 뒤 자식 수(WORD)·자식 컨트롤 ID 목록, 그 뒤 인스턴스 id\n k.rest.skip(4 * k.rest.u16())\n const instId = k.rest.rest >= 4 ? k.rest.u32() : 0\n return el(\"hp:container\", [...head, [\"href\", href], [\"groupLevel\", k.groupLevel], [\"instid\", instId]], common + kids + tail)\n }\n\n const s = drawingStyle(k, ctx)\n const text = drawTextXml(comp, ctx)\n const ref: Array<[string, string | number]> = [[\"href\", href], [\"groupLevel\", k.groupLevel], [\"instid\", s.instId]]\n switch (k.kind) {\n case \"$rec\": {\n const r = sub(TAG_SHAPE.RECTANGLE)\n const ratio = r.u8()\n const pts = [0, 1, 2, 3].map(i => pt(`hc:pt${i}`, r)).join(\"\")\n return el(\"hp:rect\", [...head, ...ref, [\"ratio\", ratio]], common + s.xml + text + pts + tail)\n }\n case \"$ell\": {\n const r = sub(TAG_SHAPE.ELLIPSE)\n const a = r.u32()\n const pts = [\"hc:center\", \"hc:ax1\", \"hc:ax2\", \"hc:start1\", \"hc:end1\", \"hc:start2\", \"hc:end2\"].map(n => pt(n, r)).join(\"\")\n return el(\"hp:ellipse\", [...head, ...ref, [\"intervalDirty\", bit(a, 0)], [\"hasArcPr\", bit(a, 1)], [\"arcType\", pick(ELLIPSE_ARC, bits(a, 2, 8))]],\n common + s.xml + text + pts + tail)\n }\n case \"$arc\": {\n const r = sub(TAG_SHAPE.ARC)\n const type = r.u8()\n const pts = [\"hc:center\", \"hc:ax1\", \"hc:ax2\"].map(n => pt(n, r)).join(\"\")\n return el(\"hp:arc\", [...head, ...ref, [\"type\", pick(ELLIPSE_ARC, type)]], common + s.xml + text + pts + tail)\n }\n case \"$pol\": {\n const r = sub(TAG_SHAPE.POLYGON)\n const n = r.i32()\n let pts = \"\"\n for (let i = 0; i < n && r.rest >= 8; i++) pts += pt(\"hc:pt\", r)\n return el(\"hp:polygon\", [...head, ...ref], common + s.xml + text + pts + tail)\n }\n case \"$cur\": {\n const r = sub(TAG_SHAPE.CURVE)\n const n = r.i32()\n const ps: Array<[number, number]> = []\n for (let i = 0; i < n && r.rest >= 8; i++) ps.push([r.i32(), r.i32()])\n const types = ps.slice(1).map(() => r.u8())\n const segs = types.map((t, i) => el(\"hp:seg\", [[\"type\", t ? \"CURVE\" : \"LINE\"], [\"x1\", ps[i][0]], [\"y1\", ps[i][1]], [\"x2\", ps[i + 1][0]], [\"y2\", ps[i + 1][1]]])).join(\"\")\n return el(\"hp:curve\", [...head, ...ref], common + s.xml + text + segs + tail)\n }\n case \"$col\": {\n // 연결선 — 시작·끝 점, 종류, 이어진 개체(id·연결점 번호), 꺾임 점(x·y·종류 WORD)\n const r = sub(TAG_SHAPE.LINE)\n const sx = r.i32(), sy = r.i32(), ex = r.i32(), ey = r.i32(), type = r.u32()\n const ends = [r.u32(), r.u32(), r.u32(), r.u32()]\n const n = r.u32()\n let cps = \"\"\n for (let i = 0; i < n && r.rest >= 10; i++) cps += el(\"hp:point\", [[\"x\", r.i32()], [\"y\", r.i32()], [\"type\", r.u16()]])\n return el(\"hp:connectLine\", [...head, ...ref, [\"type\", pick(CONNECT_TYPES, type)]], common + s.xml\n + el(\"hp:startPt\", [[\"x\", sx], [\"y\", sy], [\"subjectIDRef\", ends[0]], [\"subjectIdx\", ends[1]]])\n + el(\"hp:endPt\", [[\"x\", ex], [\"y\", ey], [\"subjectIDRef\", ends[2]], [\"subjectIdx\", ends[3]]])\n + `<hp:controlPoints>${cps}</hp:controlPoints>` + tail)\n }\n case \"$lin\": {\n const r = sub(TAG_SHAPE.LINE)\n const sp = pt(\"hc:startPt\", r), ep = pt(\"hc:endPt\", r)\n const rev = r.u16()\n return el(\"hp:line\", [...head, ...ref, [\"isReverseHV\", rev ? 1 : 0]], common + s.xml + sp + ep + tail)\n }\n default:\n return \"\"\n }\n}\n\nconst CONNECT_TYPES = [\"STRAIGHT_NOARROW\", \"STRAIGHT_ONEWAY\", \"STRAIGHT_BOTH\", \"STROKE_NOARROW\", \"STROKE_ONEWAY\", \"STROKE_BOTH\",\n \"ARC_NOARROW\", \"ARC_ONEWAY\", \"ARC_BOTH\"] as const\n\nconst OLE_ASPECTS: Record<number, string> = { 1: \"CONTENT\", 2: \"THUMBNAIL\", 4: \"ICON\", 8: \"DOCPRINT\" }\nconst OLE_TYPES = [\"UNKNOWN\", \"EMBEDDED\", \"LINK\", \"STATIC\", \"EQUATION\"] as const\nconst CHART_NS = \"http://www.hancom.co.kr/hwpml/2016/ooxmlchart\"\n\n/**\n * OLE 개체 — 속성(그리기 방식·모니커·기준선·개체 종류)·크기·BinData id·테두리. 차트 OLE(스토리지에 OOXML 차트 스트림이 있음)는\n * 한글처럼 hp:switch 의 차트 갈래(Chart/chartN.xml)와 OLE 기본 갈래로 쓴다\n */\nfunction oleXml(comp: RecNode, k: Component, head: Array<[string, string | number]>, common: string, o: ObjCommon | null, caption: string,\n comment: string, ctx: ConvertContext): string {\n const r = new Cur(comp.kids.find(x => x.rec.tagId === TAG_SHAPE.OLE)?.rec.data ?? Buffer.alloc(0))\n const a = r.u32(), ex = r.i32(), ey = r.i32(), binId = r.u16()\n const lineColor = r.u32(), lineWidth = r.i32(), la = r.u32()\n const instId = r.rest >= 4 ? r.u32() : 0\n const line = el(\"hp:lineShape\", [[\"color\", color(lineColor)], [\"width\", lineWidth], [\"style\", pick(BORDER_TYPES, bits(la, 0, 6))],\n [\"endCap\", pick(END_CAPS, bits(la, 6, 4))], [\"headStyle\", pick(ARROW_STYLES, bits(la, 10, 6))], [\"tailStyle\", pick(ARROW_STYLES, bits(la, 16, 6))],\n [\"headfill\", bit(la, 30)], [\"tailfill\", bit(la, 31)], [\"headSz\", pick(ARROW_SIZES, bits(la, 22, 4))], [\"tailSz\", pick(ARROW_SIZES, bits(la, 26, 4))],\n [\"outlineStyle\", \"NORMAL\"], [\"alpha\", 0]])\n const chart = o ? ctx.chartOf(binId) : null\n // 차트의 OLE 기본 갈래는 조판 전 꼴로 쓴다 — 캡션 마지막 줄 폭 0xFFFFFFFF, 줄 나눔 정보 없음. 조판된 캡션은 차트 갈래에 둔다\n const oleCaption = chart ? caption.replace(/ lastWidth=\"\\d+\"/, ' lastWidth=\"4294967295\"').replace(/<hp:linesegarray>[\\s\\S]*?<\\/hp:linesegarray>/g, \"\") : caption\n const ole = el(\"hp:ole\", [...head, [\"href\", shapeHref(comp)], [\"groupLevel\", k.groupLevel], [\"instid\", instId], [\"objectType\", pick(OLE_TYPES, bits(a, 16, 6))],\n [\"binaryItemIDRef\", ctx.oleRef(binId)], [\"hasMoniker\", bit(a, 8)], [\"drawAspect\", OLE_ASPECTS[bits(a, 0, 8)] ?? \"CONTENT\"],\n [\"eqBaseLine\", bits(a, 9, 7)]],\n common + el(\"hc:extent\", [[\"x\", ex], [\"y\", ey]]) + line + (o ? objPlacementXml(o) + oleCaption : \"\") + comment)\n if (!chart) return ole\n const chartEl = el(\"hp:chart\", [...head, [\"chartIDRef\", chart]], objPlacementXml(o!) + caption)\n return `<hp:switch><hp:case hp:required-namespace=\"${CHART_NS}\">${chartEl}</hp:case><hp:default>${ole}</hp:default></hp:switch>`\n}\n\n/** 'gso ' 컨트롤 → 개체 요소 */\nexport function gsoXml(node: RecNode, ctx: ConvertContext): string {\n const o = readObjCommon(node)\n const c = new Cur(node.rec.data, 4 + 4 * 6 + 2 * 4 + 4)\n c.i32()\n const description = c.rest >= 2 ? c.str() : \"\"\n const comp = node.kids.find(k => k.rec.tagId === TAG.SHAPE_COMPONENT)\n if (!comp) return \"\"\n const capIdx = node.kids.indexOf(comp)\n const cap = listGroups(node.kids.slice(0, capIdx))[0]\n return shapeXml(comp, o, description, ctx, cap ? captionXml(cap, ctx) : \"\")\n}\n","/**\n * HWP 5.x 나머지 컨트롤 → HWPX: 머리말·꼬리말('head'·'foot'), 각주·미주('fn '·'en '), 자동 번호('atno'), 새 번호('nwno'),\n * 쪽 번호 위치('pgnp'), 감추기('pghd'), 쪽 번호 제어('pgct'), 책갈피('bokm'), 찾아보기 표시('idxm'), 글자 겹치기('tcps'),\n * 덧말('tdut'), 수식('eqed'), 양식 개체('form'), 숨은 설명('tcmt').\n *\n * 컨트롤 데이터는 CTRL_HEADER 의 컨트롤 id(4바이트) 뒤에 온다. 글을 담는 컨트롤(머리말·각주 …)은 자식 LIST_HEADER 와 뒤따르는\n * 형제 문단을 hp:subList 로 쓴다.\n */\n\nimport { Cur, type RecNode, el, escText, color, pick, bit, bits, readParamSet, NUM_FORMATS } from \"./util.js\"\nimport { paragraphsXml } from \"./section.js\"\nimport { composeDigits } from \"../../shared/pua.js\"\nimport { type ConvertContext, type CtrlXml, readObjCommon, objHeadAttrs, objPlacementXml, subListAttrs, listGroups, captionXml } from \"./controls.js\"\n\nconst NUM_TYPES = [\"PAGE\", \"FOOTNOTE\", \"ENDNOTE\", \"PICTURE\", \"TABLE\", \"EQUATION\", \"TOTAL_PAGE\"] as const\nconst PAGE_APPLY = [\"BOTH\", \"EVEN\", \"ODD\"] as const\nconst PAGE_NUM_POS = [\"NONE\", \"TOP_LEFT\", \"TOP_CENTER\", \"TOP_RIGHT\", \"BOTTOM_LEFT\", \"BOTTOM_CENTER\", \"BOTTOM_RIGHT\", \"OUTSIDE_TOP\",\n \"OUTSIDE_BOTTOM\", \"INSIDE_TOP\", \"INSIDE_BOTTOM\"] as const\nconst PAGE_STARTS = [\"BOTH\", \"EVEN\", \"ODD\"] as const\nconst COMPOSE_CIRCLES = [\"CHAR\", \"SHAPE_CIRCLE\", \"SHAPE_REVERSAL_CIRCLE\", \"SHAPE_RECTANGLE\", \"SHAPE_REVERSAL_RECTANGLE\", \"SHAPE_TRIANGLE\",\n \"SHAPE_REVERSAL_TIRANGLE\", \"SHAPE_LIGHT\", \"SHAPE_RHOMBUS\", \"SHAPE_REVERSAL_RHOMBUS\", \"SHAPE_ROUNDED_RECTANGLE\",\n \"SHAPE_EMPTY_CIRCULATE_TRIANGLE\", \"SHAPE_THIN_CIRCULATE_TRIANGLE\", \"SHAPE_THICK_CIRCULATE_TRIANGLE\"] as const\nconst DUTMAL_POS = [\"TOP\", \"BOTTOM\", \"CENTER\"] as const\nconst DUTMAL_ALIGN = [\"JUSTIFY\", \"LEFT\", \"RIGHT\", \"CENTER\", \"DISTRIBUTE\", \"DISTRIBUTE_SPACE\"] as const\n\nconst data = (node: RecNode): Cur => new Cur(node.rec.data, 4)\nconst ch = (code: number): string => (code ? String.fromCharCode(code) : \"\")\nconst ctrl = (xml: string): CtrlXml => ({ xml: `<hp:ctrl>${xml}</hp:ctrl>`, obj: false })\n\n/** 글 목록(LIST_HEADER + 문단) → hp:subList. 머리말·꼬리말은 목록 머리에 글 너비·높이·참조 표시가 더 있다 */\nfunction subListXml(node: RecNode, ctx: ConvertContext, sized: boolean): string {\n const g = listGroups(node.kids)[0]\n if (!g) return \"\"\n let extra: Array<[string, string | number]> | undefined\n if (sized) {\n const c = new Cur(g.head.rec.data, 8)\n const w = c.u32(), h = c.u32(), textRef = c.u8(), numRef = c.u8()\n extra = [[\"textWidth\", w], [\"textHeight\", h], [\"hasTextRef\", textRef], [\"hasNumRef\", numRef]]\n }\n const list = subListAttrs(g.head.rec.data)\n if (extra) for (const [k, v] of extra) { const i = list.findIndex(([n]) => n === k); if (i >= 0) list[i] = [k, v] }\n return el(\"hp:subList\", list, paragraphsXml(g.paras, ctx))\n}\n\n/** 확장 컨트롤 id → 요소 (모르는 컨트롤은 null) */\nexport function otherControlXml(id: string, node: RecNode, ctx: ConvertContext): CtrlXml | null {\n switch (id) {\n case \"head\":\n case \"foot\": {\n // 속성 뒤 일련번호가 HWPX id 다\n const c = data(node)\n const a = c.u32(), serial = c.u32()\n return ctrl(el(id === \"head\" ? \"hp:header\" : \"hp:footer\", [[\"id\", serial], [\"applyPageType\", pick(PAGE_APPLY, bits(a, 0, 2))]],\n subListXml(node, ctx, true)))\n }\n case \"fn \":\n case \"en \": {\n const c = data(node)\n // 번호 칸 위 16비트는 사용자 기호, 장식 문자 뒤 u32 는 한글이 flag 로 옮긴다 — 둘 다 0 이면 쓰지 않는다\n const num = c.u32(), prefix = c.u16(), suffix = c.u16()\n const flag = c.u32()\n const instId = c.u32()\n const attrs: Array<[string, string | number]> = [...(flag ? [[\"flag\", flag] as [string, number]] : []), [\"number\", num & 0xffff]]\n if (num >>> 16) attrs.push([\"userChar\", num >>> 16])\n if (id === \"en \" || prefix) attrs.push([\"prefixChar\", prefix])\n attrs.push([\"suffixChar\", suffix], [\"instId\", instId])\n return ctrl(el(id === \"fn \" ? \"hp:footNote\" : \"hp:endNote\", attrs, subListXml(node, ctx, false)))\n }\n case \"atno\": {\n const c = data(node)\n const a = c.u32(), num = c.u16(), user = c.u16(), prefix = c.u16(), suffix = c.u16()\n return ctrl(el(\"hp:autoNum\", [[\"num\", num], [\"numType\", pick(NUM_TYPES, bits(a, 0, 4))]],\n el(\"hp:autoNumFormat\", [[\"type\", pick(NUM_FORMATS, bits(a, 4, 8))], [\"userChar\", ch(user)], [\"prefixChar\", ch(prefix)],\n [\"suffixChar\", ch(suffix)], [\"supscript\", bit(a, 12)]])))\n }\n case \"nwno\": {\n const c = data(node)\n const a = c.u32(), num = c.u16()\n return ctrl(el(\"hp:newNum\", [[\"num\", num], [\"numType\", pick(NUM_TYPES, bits(a, 0, 4))]]))\n }\n case \"pgnp\": {\n const c = data(node)\n const a = c.u32()\n c.u16(); c.u16(); c.u16()\n const side = c.u16()\n return ctrl(el(\"hp:pageNum\", [[\"pos\", pick(PAGE_NUM_POS, bits(a, 8, 4))], [\"formatType\", pick(NUM_FORMATS, bits(a, 0, 8))], [\"sideChar\", ch(side)]]))\n }\n case \"pghd\": {\n const a = data(node).u32()\n return ctrl(el(\"hp:pageHiding\", [[\"hideHeader\", bit(a, 0)], [\"hideFooter\", bit(a, 1)], [\"hideMasterPage\", bit(a, 2)],\n [\"hideBorder\", bit(a, 3)], [\"hideFill\", bit(a, 4)], [\"hidePageNum\", bit(a, 5)]]))\n }\n case \"pgct\":\n return ctrl(el(\"hp:pageNumCtrl\", [[\"pageStartsOn\", pick(PAGE_STARTS, bits(data(node).u32(), 0, 2))]]))\n case \"bokm\": {\n // 이름은 CTRL_DATA 매개변수 묶음의 문자열 항목(0x4000)\n const cd = node.kids.find(k => k.rec.tagId === TAG_CTRL_DATA)\n const name = cd ? readParamSet(cd.rec.data, { o: 0 })[0x4000] : undefined\n return ctrl(el(\"hp:bookmark\", [[\"name\", typeof name === \"string\" ? name : \"\"]]))\n }\n case \"idxm\": {\n const c = data(node)\n const first = c.str(), second = c.rest >= 2 ? c.str() : \"\"\n return ctrl(el(\"hp:indexmark\", [], `<hp:firstKey>${escText(first)}</hp:firstKey>` + (second ? `<hp:secondKey>${escText(second)}</hp:secondKey>` : \"\")))\n }\n case \"tcps\": {\n const c = data(node)\n const text = c.str()\n const circle = c.u8(), size = c.i8(), expansion = c.u8(), n = c.u8()\n const ids: number[] = []\n for (let i = 0; i < n && c.rest >= 4; i++) ids.push(c.u32())\n // 도형(원·네모 …) 겹치기의 원 숫자·번호 조각은 HWPX 에선 맨 숫자 (composeDigits, #178)\n return { obj: false, xml: el(\"hp:compose\", [[\"circleType\", pick(COMPOSE_CIRCLES, circle)], [\"charSz\", size],\n [\"composeType\", expansion ? \"OVERLAP\" : \"SPREAD\"], [\"charPrCnt\", ids.length], [\"composeText\", circle ? composeDigits(text) : text]],\n ids.map(i => el(\"hp:charPr\", [[\"prIDRef\", i]])).join(\"\")) }\n }\n case \"tdut\": {\n const c = data(node)\n const main = c.str(), sub = c.str()\n const pos = c.u32(), ratio = c.u32(), option = c.u32(), style = c.u32(), align = c.u32()\n return { obj: false, xml: el(\"hp:dutmal\", [[\"posType\", pick(DUTMAL_POS, pos)], [\"szRatio\", ratio], [\"option\", option],\n [\"styleIDRef\", style], [\"align\", pick(DUTMAL_ALIGN, align)]], `<hp:mainText>${escText(main)}</hp:mainText><hp:subText>${escText(sub)}</hp:subText>`) }\n }\n case \"eqed\":\n return { obj: true, xml: equationXml(node, ctx) }\n case \"form\":\n return formXml(node)\n case \"tcmt\":\n // 숨은 설명 — 인쇄되지 않는 글 목록\n return ctrl(el(\"hp:hiddenComment\", [], subListXml(node, ctx, false)))\n default:\n return null\n }\n}\n\nconst TAG_FORM_OBJECT = 0x5b\nconst TAG_CTRL_DATA = 0x57\nconst FORM_KINDS: Record<string, string> = { \"tbp+\": \"hp:btn\", \"tbc+\": \"hp:checkBtn\", \"tbr+\": \"hp:radioBtn\", \"boc+\": \"hp:comboBox\", \"tde+\": \"hp:edit\" }\nconst BUTTON_VALUES = [\"UNCHECKED\", \"CHECKED\", \"INDETERMINATE\"] as const\nconst SCROLL_BARS = [\"NONE\", \"HORIZONTAL\", \"VERTICAL\", \"BOTH\"] as const\nconst TAB_KEYS = [\"NEXT_OBJECT\", \"INSERT_TAB\"] as const\nconst TEXT_ALIGNS = [\"LEFT\", \"CENTER\", \"RIGHT\"] as const\n\n/** 양식 개체 속성 문자열 — \"키:종류:값\" 을 빈칸으로 잇는다. wstring 은 \"키:wstring:글자 수:값\", set 은 \"키:set:길이:\" 뒤에 안쪽 항목이 이어진다 */\nfunction formProps(s: string): Map<string, string> {\n const out = new Map<string, string>()\n let i = 0\n const word = (): string => {\n const j = s.indexOf(\":\", i)\n const w = j < 0 ? s.slice(i) : s.slice(i, j)\n i = j < 0 ? s.length : j + 1\n return w\n }\n while (i < s.length) {\n while (s[i] === \" \") i++\n if (i >= s.length) break\n const key = word(), type = word()\n if (type === \"set\") { word(); continue }\n if (type === \"wstring\") {\n const n = Number(word())\n out.set(key, s.slice(i, i + n))\n i += n\n continue\n }\n const j = s.indexOf(\" \", i) < 0 ? s.length : s.indexOf(\" \", i)\n out.set(key, s.slice(i, j))\n i = j\n }\n return out\n}\n\n/** 'form' 양식 개체 — 개체 공통 속성(크기·배치) + FORM_OBJECT(종류 id, 글자 수 WORD@12, 속성 문자열@14). 단추·선택 상자·라디오·콤보·입력 칸 */\nfunction formXml(node: RecNode): CtrlXml | null {\n const rec = node.kids.find(k => k.rec.tagId === TAG_FORM_OBJECT)?.rec.data\n const tag = rec && rec.length >= 14 ? FORM_KINDS[rec.toString(\"latin1\", 0, 4)] : undefined\n if (!rec || !tag) return null\n const p = formProps(rec.toString(\"utf16le\", 14, 14 + rec.readUInt16LE(12) * 2))\n const s = (k: string): string => p.get(k) ?? \"\"\n const n = (k: string): number => Number(p.get(k) ?? 0) || 0\n let own: Array<[string, string | number]>, inner = \"\"\n if (tag === \"hp:comboBox\") {\n // 한글은 콤보 상자의 보이는 글을 목록 항목 하나로 쓴다\n own = [[\"listBoxRows\", n(\"ListBoxRows\")], [\"listBoxWidth\", n(\"ListBoxWidth\")], [\"editEnable\", n(\"EditEnable\")], [\"selectedValue\", \"\"]]\n inner = el(\"hp:listItem\", [[\"displayText\", \"\"], [\"value\", s(\"Text\")]])\n } else if (tag === \"hp:edit\") {\n own = [[\"multiLine\", n(\"MultiLine\")], [\"passwordChar\", s(\"PasswordChar\")], [\"maxLength\", n(\"MaxLength\")], [\"scrollBars\", pick(SCROLL_BARS, n(\"ScrollBars\"))],\n [\"tabKeyBehavior\", pick(TAB_KEYS, n(\"TabKeyBehavior\"))], [\"numOnly\", n(\"Number\")], [\"readOnly\", n(\"ReadOnly\")], [\"alignText\", pick(TEXT_ALIGNS, n(\"AlignText\"))]]\n inner = s(\"Text\") ? `<hp:text>${escText(s(\"Text\"))}</hp:text>` : \"<hp:text/>\"\n } else {\n own = [[\"caption\", s(\"Caption\")], [\"value\", pick(BUTTON_VALUES, n(\"Value\"))], [\"radioGroupName\", s(\"RadioGroupName\")], [\"triState\", n(\"TriState\")],\n [\"backStyle\", n(\"BackStyle\") ? \"OPAQUE\" : \"TRANSPARENT\"]]\n }\n return { obj: true, xml: el(tag, [...own, [\"name\", s(\"Name\")], [\"foreColor\", color(n(\"ForeColor\"))], [\"backColor\", color(n(\"BackColor\"))], [\"groupName\", s(\"GroupName\")],\n [\"tabStop\", n(\"TabStop\")], [\"editable\", n(\"Editable\")], [\"tabOrder\", n(\"TabOrder\")], [\"enabled\", n(\"Enabled\")], [\"borderTypeIDRef\", n(\"BorderType\")],\n [\"drawFrame\", n(\"DrawFrame\")], [\"printable\", n(\"Printable\")], [\"command\", s(\"Command\")]],\n el(\"hp:formCharPr\", [[\"charPrIDRef\", n(\"CharShapeID\")], [\"followContext\", n(\"FollowContext\")], [\"autoSz\", n(\"AutoSize\")], [\"wordWrap\", n(\"WordWrap\")]])\n + inner + objPlacementXml(readObjCommon(node))) }\n}\n\n/** 수식 — 개체 공통 속성 + EQEDIT(속성·스크립트·기준 크기·색·기준선·판·글꼴) */\nfunction equationXml(node: RecNode, ctx: ConvertContext): string {\n const o = readObjCommon(node)\n const desc = new Cur(node.rec.data, 44)\n const description = desc.rest >= 2 ? desc.str() : \"\"\n const eq = node.kids.find(k => k.rec.tagId === 0x58)\n const c = new Cur(eq?.rec.data ?? Buffer.alloc(0))\n const a = c.u32(), script = c.str(), baseUnit = c.u32(), textColor = c.u32(), baseLine = c.i16()\n c.u16()\n const version = c.rest >= 2 ? c.str() : \"\", font = c.rest >= 2 ? c.str() : \"\"\n const capIdx = node.kids.findIndex(k => k.rec.tagId === 0x58)\n const cap = listGroups(capIdx >= 0 ? node.kids.slice(0, capIdx) : [])[0]\n return el(\"hp:equation\", [...objHeadAttrs(o), [\"version\", version], [\"baseLine\", baseLine], [\"textColor\", color(textColor)], [\"baseUnit\", baseUnit],\n [\"lineMode\", bit(a, 0) ? \"LINE\" : \"CHAR\"], [\"font\", font]],\n objPlacementXml(o) + (cap ? captionXml(cap, ctx) : \"\") + (description ? `<hp:shapeComment>${escText(description)}</hp:shapeComment>` : \"\")\n + `<hp:script${/^\\s|\\s$/.test(script) ? ' xml:space=\"preserve\"' : \"\"}>${escText(script)}</hp:script>`)\n}\n","/**\n * HWP 5.x 확장 컨트롤(CTRL_HEADER) → HWPX 요소. 구역·단 정의, 표, 개체 공통 위치·크기, 그리고 컨트롤별 모듈로 나눈다.\n */\n\nimport { Cur, type RecNode, el, pick, bit, bits, readParamSet, subSet } from \"./util.js\"\nimport { TAG, ctrlId, paragraphsXml, secPrXml, colPrXml } from \"./section.js\"\nimport { fieldBeginXml, type FieldState } from \"./fields.js\"\nimport { gsoXml } from \"./shapes.js\"\nimport { otherControlXml } from \"./notes.js\"\n\n/** 변환 중 문서 전체가 함께 쓰는 상태 */\nexport interface ConvertContext {\n /** DocInfo 메모 모양 수 — 구역 정의 memoShapeIDRef */\n memoShapes: number\n /** 문단 모양 번호 → paraPr id(같은 문단 모양을 합친 번호) */\n paraIds: number[]\n /** 열린 필드 — 필드 끝 컨트롤이 짝을 찾는다 */\n fields: FieldState\n /** 바탕쪽 파트(masterpageN.xml 내용) — 구역 정의를 만나는 차례로 쌓는다 */\n masterPages: string[]\n /** 지금 구역의 확장 바탕쪽(구역 끝 LIST_HEADER 묶음) — 구역 정의가 기본 바탕쪽 뒤에 쓴다 */\n tailMasters: Array<{ head: RecNode; paras: RecNode[] }>\n /** 연결된 글상자의 제 몫 문단(목록 id → 문단) — 사슬 머리에 모인 글을 줄 나눔 정보대로 나눈 것 */\n linkedParas: Map<number, RecNode[]>\n /** 지금 구역의 메모 글(구역 끝 MEMO_LIST 번호 → LIST_HEADER 묶음) — 메모 필드가 제 번호 글을 subList 로 쓴다 */\n memos: Map<number, { head: RecNode; paras: RecNode[] }>\n /** 차트 OLE(BIN_DATA 순번) → 차트 파트 경로, 차트가 아니면 null */\n chartOf(binId: number): string | null\n /** 그림 BinData 참조 이름 */\n binRef(binId: number): string\n /** OLE BinData 참조 이름(oleN) */\n oleRef(binId: number): string\n}\n\n/** obj: run 안에서 뒤에 글 자리(hp:t)를 여는 개체, def: 구역·단 정의(뒤 내용은 새 run) */\nexport interface CtrlXml { xml: string; obj: boolean; def?: boolean }\n\n/** 확장 컨트롤 하나 → 요소. obj 는 run 안에서 뒤에 글 자리(hp:t)를 여는 개체(표·그림·도형·수식) */\nexport function controlXml(node: RecNode, ctx: ConvertContext): CtrlXml | null {\n const id = ctrlId(node)\n if (id.startsWith(\"%\")) return { xml: fieldBeginXml(node, id, ctx), obj: false }\n switch (id) {\n case \"secd\": return { xml: secPrXml(node, ctx), obj: false, def: true }\n case \"cold\": return { xml: colPrXml(node), obj: false, def: true }\n case \"tbl \": return { xml: tableXml(node, ctx), obj: true }\n case \"gso \": return { xml: gsoXml(node, ctx), obj: true }\n default: return otherControlXml(id, node, ctx)\n }\n}\n\n// ─── 개체 공통 ───────────────────────────────────────\n\nconst VERT_RELS = [\"PAPER\", \"PAGE\", \"PARA\"] as const\nconst HORZ_RELS = [\"PAPER\", \"PAGE\", \"COLUMN\", \"PARA\"] as const\nconst VERT_ALIGNS = [\"TOP\", \"CENTER\", \"BOTTOM\", \"INSIDE\", \"OUTSIDE\"] as const\nconst HORZ_ALIGNS = [\"LEFT\", \"CENTER\", \"RIGHT\", \"INSIDE\", \"OUTSIDE\"] as const\nconst WIDTH_RELS = [\"PAPER\", \"PAGE\", \"COLUMN\", \"PARA\", \"ABSOLUTE\"] as const\nconst HEIGHT_RELS = [\"PAPER\", \"PAGE\", \"ABSOLUTE\"] as const\nconst TEXT_WRAPS = [\"SQUARE\", \"TOP_AND_BOTTOM\", \"BEHIND_TEXT\", \"IN_FRONT_OF_TEXT\"] as const\nconst TEXT_FLOWS = [\"BOTH_SIDES\", \"LEFT_ONLY\", \"RIGHT_ONLY\", \"LARGEST_ONLY\"] as const\nconst NUMBERING_TYPES = [\"NONE\", \"PICTURE\", \"TABLE\", \"EQUATION\"] as const\n\n/** 개체 공통 속성(CTRL_HEADER 의 컨트롤 id 뒤) */\nexport interface ObjCommon {\n attr: number; vertOffset: number; horzOffset: number; width: number; height: number; zOrder: number\n margin: [number, number, number, number]; instanceId: number\n /** 쪽 나눔 방지 — 개체와 조판 부호를 같은 쪽에 둔다(holdAnchorAndSO) */\n keepWithAnchor: number\n}\n\nexport function readObjCommon(node: RecNode): ObjCommon {\n const c = new Cur(node.rec.data, 4)\n const attr = c.u32(), vertOffset = c.i32(), horzOffset = c.i32(), width = c.u32(), height = c.u32(), zOrder = c.i32()\n const margin: [number, number, number, number] = [c.i16(), c.i16(), c.i16(), c.i16()]\n const instanceId = c.u32()\n return { attr, vertOffset, horzOffset, width, height, zOrder, margin, instanceId, keepWithAnchor: c.i32() & 1 }\n}\n\n/** 개체 요소의 앞 속성 — id·zOrder·번호 종류·배치 */\nexport function objHeadAttrs(o: ObjCommon): Array<[string, string | number]> {\n return [[\"id\", o.instanceId], [\"zOrder\", o.zOrder], [\"numberingType\", pick(NUMBERING_TYPES, bits(o.attr, 26, 2))],\n [\"textWrap\", pick(TEXT_WRAPS, bits(o.attr, 21, 3))], [\"textFlow\", pick(TEXT_FLOWS, bits(o.attr, 24, 2))], [\"lock\", bit(o.attr, 30)], [\"dropcapstyle\", \"None\"]]\n}\n\n/** hp:sz · hp:pos · hp:outMargin */\nexport function objPlacementXml(o: ObjCommon): string {\n const a = o.attr\n return el(\"hp:sz\", [[\"width\", o.width], [\"widthRelTo\", pick(WIDTH_RELS, bits(a, 15, 3))], [\"height\", o.height],\n [\"heightRelTo\", pick(HEIGHT_RELS, bits(a, 18, 2))], [\"protect\", bit(a, 20)]])\n + el(\"hp:pos\", [[\"treatAsChar\", bit(a, 0)], [\"affectLSpacing\", bit(a, 2)], [\"flowWithText\", bit(a, 13)], [\"allowOverlap\", bit(a, 14)],\n [\"holdAnchorAndSO\", o.keepWithAnchor], [\"vertRelTo\", pick(VERT_RELS, bits(a, 3, 2))], [\"horzRelTo\", pick(HORZ_RELS, bits(a, 8, 2))],\n [\"vertAlign\", pick(VERT_ALIGNS, bits(a, 5, 3))], [\"horzAlign\", pick(HORZ_ALIGNS, bits(a, 10, 3))], [\"vertOffset\", o.vertOffset >>> 0],\n [\"horzOffset\", o.horzOffset >>> 0]])\n + el(\"hp:outMargin\", [[\"left\", o.margin[0]], [\"right\", o.margin[1]], [\"top\", o.margin[2]], [\"bottom\", o.margin[3]]])\n}\n\n/** 라벨 용지(표 매개변수 묶음 0x242) — 위·왼쪽 여백, 칸 폭·높이·간격, 칸 수, 용지 방향·크기 */\nfunction labelXml(data: RecNode | undefined): string {\n const s = data ? subSet(readParamSet(data.rec.data, { o: 0 }), 0x242) : null\n if (!s) return \"\"\n const v = (id: number): number => (typeof s[id] === \"number\" ? (s[id] as number) : 0)\n return el(\"hp:label\", [[\"topmargin\", v(0x4000)], [\"leftmargin\", v(0x4001)], [\"boxwidth\", v(0x4002)], [\"boxlength\", v(0x4003)],\n [\"boxmarginhor\", v(0x4004)], [\"boxmarginver\", v(0x4005)], [\"labelcols\", v(0x4006)], [\"labelrows\", v(0x4007)],\n [\"landscape\", v(0x4008) ? \"NARROWLY\" : \"WIDELY\"], [\"pagewidth\", v(0x4009)], [\"pageheight\", v(0x400a)]])\n}\n\n// ─── 문단 목록 머리(LIST_HEADER) ───────────────────\n\nconst TEXT_DIRS = [\"HORIZONTAL\", \"VERTICAL\", \"VERTICALALL\"] as const\nconst LINE_WRAPS = [\"BREAK\", \"SQUEEZE\", \"KEEP\"] as const\nconst LIST_VALIGNS = [\"TOP\", \"CENTER\", \"BOTTOM\"] as const\n\n/** LIST_HEADER 의 공통 속성 → hp:subList 속성 (속성 비트는 u32 의 위쪽 16비트에 있다) */\nexport function subListAttrs(data: Buffer, extra: Array<[string, string | number]> = []): Array<[string, string | number]> {\n const a = data.length >= 6 ? data.readUInt32LE(2) >>> 16 : 0\n return [[\"id\", \"\"], [\"textDirection\", pick(TEXT_DIRS, bits(a, 0, 3))], [\"lineWrap\", pick(LINE_WRAPS, bits(a, 3, 2))],\n [\"vertAlign\", pick(LIST_VALIGNS, bits(a, 5, 2))], [\"linkListIDRef\", 0], [\"linkListNextIDRef\", 0], [\"textWidth\", 0], [\"textHeight\", 0],\n [\"hasTextRef\", 0], [\"hasNumRef\", 0], ...extra]\n}\n\n/** LIST_HEADER 와 뒤따르는 형제 문단 묶음으로 가른다 (칸·캡션은 문단이 LIST_HEADER 의 형제다) */\nexport function listGroups(kids: RecNode[]): Array<{ head: RecNode; paras: RecNode[] }> {\n const out: Array<{ head: RecNode; paras: RecNode[] }> = []\n for (const k of kids) {\n if (k.rec.tagId === TAG.LIST_HEADER) out.push({ head: k, paras: [] })\n else if (k.rec.tagId === TAG.PARA_HEADER && out.length) out[out.length - 1].paras.push(k)\n }\n return out\n}\n\n// ─── 표 ──────────────────────────────────────────────\n\nconst PAGE_BREAKS = [\"NONE\", \"TABLE\", \"CELL\"] as const\nconst CAPTION_SIDES = [\"LEFT\", \"RIGHT\", \"TOP\", \"BOTTOM\"] as const\n\n/** 캡션 LIST_HEADER(목록 머리 뒤 캡션 속성·폭·간격·마지막 줄 폭) → hp:caption */\nexport function captionXml(g: { head: RecNode; paras: RecNode[] }, ctx: ConvertContext): string {\n const c = new Cur(g.head.rec.data, 8)\n const a = c.u32(), width = c.u32(), gap = c.i16(), lastWidth = c.u32()\n return el(\"hp:caption\", [[\"side\", pick(CAPTION_SIDES, bits(a, 0, 2))], [\"fullSz\", bit(a, 2)], [\"width\", width], [\"gap\", gap], [\"lastWidth\", lastWidth]],\n el(\"hp:subList\", subListAttrs(g.head.rec.data), paragraphsXml(g.paras, ctx)))\n}\n\nfunction tableXml(node: RecNode, ctx: ConvertContext): string {\n const o = readObjCommon(node)\n const tIdx = node.kids.findIndex(k => k.rec.tagId === TAG.TABLE)\n const t = new Cur(tIdx >= 0 ? node.kids[tIdx].rec.data : Buffer.alloc(0))\n const ta = t.u32(), rows = t.u16(), cols = t.u16(), spacing = t.i16()\n const inMargin = [t.i16(), t.i16(), t.i16(), t.i16()]\n t.skip(2 * rows)\n const borderFill = t.u16()\n const zones = t.u16()\n let zoneXml = \"\"\n for (let i = 0; i < zones && t.rest >= 10; i++) {\n const sr = t.u16(), sc = t.u16(), er = t.u16(), ec = t.u16(), bf = t.u16()\n zoneXml += el(\"hp:cellzone\", [[\"startRowAddr\", sr], [\"startColAddr\", sc], [\"endRowAddr\", er], [\"endColAddr\", ec], [\"borderFillIDRef\", bf]])\n }\n const before = tIdx >= 0 ? node.kids.slice(0, tIdx) : []\n const caption = listGroups(before)[0]\n const cells = listGroups(tIdx >= 0 ? node.kids.slice(tIdx + 1) : node.kids)\n const rowsXml: string[] = []\n for (const g of cells) {\n const d = g.head.rec.data\n const c = new Cur(d, 6)\n const flags = c.u16()\n const col = c.u16(), row = c.u16(), cs = c.u16(), rs = c.u16(), w = c.u32(), hgt = c.u32()\n const m = [c.i16(), c.i16(), c.i16(), c.i16()]\n const bf = c.u16()\n let name = \"\"\n if (d.length >= 34 + 17) {\n const n = d.readUInt16LE(34 + 15)\n if (n && d.length >= 34 + 17 + n * 2) name = d.toString(\"utf16le\", 34 + 17, 34 + 17 + n * 2)\n }\n const tc = el(\"hp:tc\", [[\"name\", name], [\"header\", bit(flags, 2)], [\"hasMargin\", bit(flags, 0)], [\"protect\", bit(flags, 1)],\n [\"editable\", bit(flags, 3)], [\"dirty\", 0], [\"borderFillIDRef\", bf]],\n el(\"hp:subList\", subListAttrs(d), paragraphsXml(g.paras, ctx))\n + el(\"hp:cellAddr\", [[\"colAddr\", col], [\"rowAddr\", row]]) + el(\"hp:cellSpan\", [[\"colSpan\", cs], [\"rowSpan\", rs]])\n + el(\"hp:cellSz\", [[\"width\", w], [\"height\", hgt]]) + el(\"hp:cellMargin\", [[\"left\", m[0] >>> 0], [\"right\", m[1] >>> 0], [\"top\", m[2] >>> 0], [\"bottom\", m[3] >>> 0]]))\n while (rowsXml.length <= row) rowsXml.push(\"\")\n rowsXml[row] += tc\n }\n const inner = objPlacementXml(o) + (caption ? captionXml(caption, ctx) : \"\")\n + el(\"hp:inMargin\", [[\"left\", inMargin[0]], [\"right\", inMargin[1]], [\"top\", inMargin[2]], [\"bottom\", inMargin[3]]])\n + (zoneXml ? `<hp:cellzoneList>${zoneXml}</hp:cellzoneList>` : \"\")\n + rowsXml.filter(Boolean).map(r => `<hp:tr>${r}</hp:tr>`).join(\"\")\n + labelXml(node.kids.find(k => k.rec.tagId === TAG.CTRL_DATA))\n return el(\"hp:tbl\", [...objHeadAttrs(o), [\"pageBreak\", pick(PAGE_BREAKS, bits(ta, 0, 2))], [\"repeatHeader\", bit(ta, 2)],\n [\"rowCnt\", rows], [\"colCnt\", cols], [\"cellSpacing\", spacing], [\"borderFillIDRef\", borderFill], [\"noAdjust\", bit(ta, 3)]], inner)\n}\n","/**\n * HWP 5.x BodyText 섹션 → HWPX Contents/sectionN.xml.\n *\n * 문단(PARA_HEADER)마다 글(PARA_TEXT)을 글자 모양 구간(PARA_CHAR_SHAPE)으로 run 에 나누고, 확장 컨트롤 글자(8 WCHAR)는 순서대로 자식\n * CTRL_HEADER 를 하나씩 받아 그 자리에 요소로 쓴다. 인라인 컨트롤(탭·필드 끝·제목 차례)과 글자 컨트롤(줄바꿈·묶음/고정폭 빈칸·\n * 하이픈)은 hp:t 안 요소, 개체(표·그림·도형·수식)는 hp:t 와 같은 run 의 형제다. 줄 나눔 정보(PARA_LINE_SEG)는 hp:linesegarray.\n */\n\nimport { Cur, type RecNode, el, escText, color, bit, bits, pick, readParamSet, subSet, type Param, BORDER_TYPES, BORDER_WIDTHS, NUM_FORMATS } from \"./util.js\"\nimport { XML_DECL, NS, GRADATIONS } from \"./header.js\"\nimport { controlXml, listGroups, subListAttrs, type ConvertContext } from \"./controls.js\"\nimport { fieldEndXml } from \"./fields.js\"\n\nexport const TAG = {\n PARA_HEADER: 0x42, PARA_TEXT: 0x43, PARA_CHAR_SHAPE: 0x44, PARA_LINE_SEG: 0x45, PARA_RANGE_TAG: 0x46, CTRL_HEADER: 0x47,\n LIST_HEADER: 0x48, PAGE_DEF: 0x49, FOOTNOTE_SHAPE: 0x4a, PAGE_BORDER_FILL: 0x4b, SHAPE_COMPONENT: 0x4c, TABLE: 0x4d,\n CTRL_DATA: 0x57, MEMO_LIST: 0x5d,\n} as const\n\n/** 1 WCHAR 글자 컨트롤 */\nconst CHAR_CTRL = new Set([0, 10, 13, 24, 25, 26, 27, 28, 29, 30, 31])\n/** 8 WCHAR 인라인 컨트롤 (자식 레코드 없음) */\nconst INLINE_CTRL = new Set([4, 5, 6, 7, 8, 9, 19, 20])\n\nexport function ctrlId(node: RecNode): string {\n const d = node.rec.data\n return d.length >= 4 ? String.fromCharCode(d[3], d[2], d[1], d[0]) : \"\"\n}\n\n/** 문단 목록(섹션 최상위·칸·글상자·머리말 등) */\nexport function paragraphsXml(nodes: RecNode[], ctx: ConvertContext): string {\n let out = \"\"\n for (const n of nodes) if (n.rec.tagId === TAG.PARA_HEADER) out += paragraphXml(n, ctx)\n return out\n}\n\n/** 글 토큰 — 글자, 인라인 요소(hp:t 안), 개체·컨트롤 요소(run 형제). cs 는 글자 스타일(영역 태그 종류 1) — 같은 run 안에서도 hp:t 를 따로 연다 */\ntype Tok = { pos: number; t: \"text\"; s: string; cs?: number } | { pos: number; t: \"inline\"; xml: string; mark?: boolean; cs?: number }\n | { pos: number; t: \"ctrl\"; xml: string; obj: boolean; def?: boolean }\n\nfunction paragraphXml(p: RecNode, ctx: ConvertContext): string {\n const h = new Cur(p.rec.data)\n const nChars = h.u32() & 0x7fffffff\n h.u32() // 컨트롤 마스크\n const paraShape = h.u16(), styleId = h.u8(), breaks = h.u8()\n h.skip(6)\n const instanceId = p.rec.data.length >= 22 ? h.u32() : 0\n const merged = p.rec.data.length >= 24 ? h.u16() : 0\n\n const texts = p.kids.filter(k => k.rec.tagId === TAG.PARA_TEXT)\n const text = texts.length ? Buffer.concat(texts.map(k => k.rec.data)) : Buffer.alloc(0)\n const csNode = p.kids.find(k => k.rec.tagId === TAG.PARA_CHAR_SHAPE)\n const runs: Array<[number, number]> = []\n // 같은 글자 모양이 잇달아 오는 경계는 한글이 run 하나로 합쳐 저장한다 — 문단 끝(CR) 자리에서 시작하는 구간은 빈 run 으로 남긴다\n const crPos = text.length / 2 - 1\n if (csNode) for (const c = new Cur(csNode.rec.data); c.rest >= 8;) {\n const pos = c.u32(), id = c.u32()\n if (!runs.length || runs[runs.length - 1][1] !== id || pos >= crPos) runs.push([pos, id])\n }\n if (!runs.length) runs.push([0, 0])\n const ctrls = p.kids.filter(k => k.rec.tagId === TAG.CTRL_HEADER)\n const ranges = rangeTags(p.kids.find(k => k.rec.tagId === TAG.PARA_RANGE_TAG))\n const toks = tokenize(text, ctrls, ctx, new Set([...runs.map(r => r[0]), ...ranges.styles.flatMap(r => [r[0], r[1]])]), ranges.marks)\n for (const k of toks) if (k.t !== \"ctrl\") k.cs = ranges.styles.find(r => k.pos >= r[0] && k.pos < r[1])?.[2]\n\n const units = text.length / 2\n const hasCtrl = toks.some(t => t.t === \"ctrl\")\n let body = \"\"\n for (let i = 0; i < runs.length; i++) {\n const from = runs[i][0], to = i + 1 < runs.length ? runs[i + 1][0] : Math.max(units, nChars)\n let seg = toks.filter(t => t.pos >= from && t.pos < to)\n // 문단 끝(CR)만 담은 run — 문단에 개체·컨트롤이 있으면 빈 글 마디를 둔다(없으면 빈 run)\n if (!seg.length && i > 0 && from >= crPos && hasCtrl) seg = [{ pos: from, t: \"text\", s: \"\" }]\n body += runXml(runs[i][1], seg)\n }\n\n const ls = p.kids.find(k => k.rec.tagId === TAG.PARA_LINE_SEG)\n if (ls) {\n let segs = \"\"\n for (const c = new Cur(ls.rec.data); c.rest >= 36;) {\n segs += el(\"hp:lineseg\", [[\"textpos\", c.u32()], [\"vertpos\", c.i32()], [\"vertsize\", c.i32()], [\"textheight\", c.i32()],\n [\"baseline\", c.i32()], [\"spacing\", c.i32()], [\"horzpos\", c.i32()], [\"horzsize\", c.i32()], [\"flags\", c.u32()]])\n }\n body += `<hp:linesegarray>${segs}</hp:linesegarray>`\n }\n return el(\"hp:p\", [[\"id\", instanceId], [\"paraPrIDRef\", ctx.paraIds[paraShape] ?? paraShape], [\"styleIDRef\", styleId], [\"pageBreak\", bit(breaks, 2)],\n [\"columnBreak\", bit(breaks, 3)], [\"merged\", merged]], body)\n}\n\n/**\n * 영역 태그(PARA_RANGE_TAG: 시작·끝 위치, 종류 상위 8비트·데이터 하위 24비트) — 형광펜(종류 2, 데이터는 색)은 글자 위치마다 그 글자\n * 앞에 둘 인라인 요소로, 글자 스타일(종류 1, 데이터는 스타일 번호)은 [시작, 끝, 번호] 로\n */\nfunction rangeTags(node: RecNode | undefined): { marks: Map<number, string[]>; styles: Array<[number, number, number]> } {\n const marks = new Map<number, string[]>(), styles: Array<[number, number, number]> = []\n if (!node) return { marks, styles }\n const add = (pos: number, xml: string, first: boolean): void => {\n const list = marks.get(pos) ?? []\n if (first) list.unshift(xml); else list.push(xml)\n marks.set(pos, list)\n }\n for (const c = new Cur(node.rec.data); c.rest >= 12;) {\n const start = c.u32(), end = c.u32(), tag = c.u32()\n if (end <= start) continue\n if (tag >>> 24 === 1) styles.push([start, end, tag & 0xffffff])\n if (tag >>> 24 !== 2) continue\n add(start, el(\"hp:markpenBegin\", [[\"color\", color(tag & 0xffffff)]]), false)\n add(end, \"<hp:markpenEnd/>\", true) // 같은 자리에서는 앞 영역을 닫고 연다\n }\n return { marks, styles }\n}\n\n/** 글 → 토큰. 글은 글자 모양 구간 경계(cuts)에서 끊는다 */\nfunction tokenize(text: Buffer, ctrls: RecNode[], ctx: ConvertContext, cuts: Set<number>, marks: Map<number, string[]>): Tok[] {\n const toks: Tok[] = []\n const n = text.length / 2\n let ci = 0\n let buf = \"\", bufPos = 0\n const flush = (): void => { if (buf) toks.push({ pos: bufPos, t: \"text\", s: buf }); buf = \"\" }\n for (let i = 0; i < n;) {\n const c = text.readUInt16LE(i * 2)\n if (cuts.has(i)) flush()\n const mk = marks.get(i)\n if (mk) { flush(); for (const xml of mk) toks.push({ pos: i, t: \"inline\", xml, mark: true }) }\n if (c >= 32) {\n if (!buf) bufPos = i\n buf += String.fromCharCode(c)\n i++\n continue\n }\n flush()\n if (CHAR_CTRL.has(c)) {\n if (c === 10) toks.push({ pos: i, t: \"inline\", xml: \"<hp:lineBreak/>\" })\n else if (c === 24) toks.push({ pos: i, t: \"inline\", xml: \"<hp:hypen/>\" }) // 한글 저장 이름 그대로(hypen)\n else if (c === 30) toks.push({ pos: i, t: \"inline\", xml: \"<hp:nbSpace/>\" })\n else if (c === 31) toks.push({ pos: i, t: \"inline\", xml: \"<hp:fwSpace/>\" })\n i++\n continue\n }\n const data = text.subarray(i * 2 + 2, i * 2 + 14)\n if (INLINE_CTRL.has(c)) {\n if (c === 9) {\n const d = new Cur(data)\n const width = d.u32(), leader = d.u8(), type = d.u8()\n toks.push({ pos: i, t: \"inline\", xml: el(\"hp:tab\", [[\"width\", width], [\"leader\", leader], [\"type\", type]]) })\n } else if (c === 4) {\n toks.push({ pos: i, t: \"ctrl\", obj: false, xml: fieldEndXml(ctx.fields) })\n } else if (c === 8) {\n toks.push({ pos: i, t: \"inline\", xml: el(\"hp:titleMark\", [[\"ignore\", 1]]) })\n }\n i += 8\n continue\n }\n // 확장 컨트롤 — 자식 CTRL_HEADER 를 순서대로 하나\n const node = ctrls[ci++]\n if (node) {\n const r = controlXml(node, ctx)\n if (r) toks.push({ pos: i, t: \"ctrl\", obj: r.obj, xml: r.xml, def: r.def })\n }\n i += 8\n }\n flush()\n // 글 끝 너머에서 닫히는 영역은 마지막 글자 자리에서 닫는다(짝이 깨지지 않게)\n for (const [pos, list] of marks) if (pos >= n) for (const xml of list) toks.push({ pos: Math.max(0, n - 1), t: \"inline\", xml, mark: true })\n // 컨트롤 뒤 글 자리 — 바로 뒤(8 WCHAR 다음)에 아무것도 없으면(문단 끝) 빈 글을 둔다. 그 자리가 다음 글자 모양 구간이면 빈 hp:t 도\n // 다음 run 에 든다. 개체가 잇달아 오면(수식 둘) 사이에 빈 글이 없다\n for (let k = toks.length - 1; k >= 0; k--) {\n const o = toks[k]\n if (o.t === \"ctrl\" && toks[k + 1]?.pos !== o.pos + 8) toks.splice(k + 1, 0, { pos: o.pos + 8, t: \"text\", s: \"\" })\n }\n return toks\n}\n\n/**\n * run 하나 — 글·인라인 요소는 hp:t 로 묶는다(개체 뒤 빈 글은 tokenize 가 넣는다). 구역·단 정의는 제 run 에 두고\n * 뒤따르는 내용은 같은 글자 모양의 새 run 에서 시작한다(한글 2022 이상 저장 꼴)\n */\nfunction runXml(charShape: number, toks: Tok[]): string {\n const open = `<hp:run charPrIDRef=\"${charShape}\">`\n if (!toks.length) return el(\"hp:run\", [[\"charPrIDRef\", charShape]])\n let out = \"\", t: string | null = null, tcs: number | undefined\n const closeT = (): void => {\n if (t !== null) { const a = tcs === undefined ? \"\" : ` charStyleIDRef=\"${tcs}\"`; out += t ? `<hp:t${a}>${t}</hp:t>` : `<hp:t${a}/>` }\n t = null\n }\n toks.forEach((k, i) => {\n if (k.t !== \"ctrl\" && t !== null && k.cs !== tcs) closeT()\n if (k.t !== \"ctrl\" && t === null) tcs = k.cs\n if (k.t === \"text\") t = (t ?? \"\") + escText(k.s)\n // 영역 표시(형광펜) 바로 뒤가 개체면 글 마디 밖, run 바로 아래에 둔다\n else if (k.t === \"inline\" && k.mark && toks[i + 1]?.t === \"ctrl\") { closeT(); out += k.xml }\n else if (k.t === \"inline\") t = (t ?? \"\") + k.xml\n else {\n closeT()\n out += k.xml\n const next = toks[i + 1]\n if (k.def && !(next?.t === \"ctrl\" && next.def)) out += \"</hp:run>\" + open\n }\n })\n closeT()\n // 정의 뒤 내용이 없으면 같은 글자 모양의 빈 run 이 남는다\n return (open + out + \"</hp:run>\").replace(`${open}</hp:run>`, el(\"hp:run\", [[\"charPrIDRef\", charShape]]))\n}\n\n/** 섹션 레코드 트리 → sectionN.xml */\nexport function sectionXml(top: RecNode[], ctx: ConvertContext): string {\n // 확장 바탕쪽(마지막 쪽·임의 쪽)은 구역 끝 — 마지막 문단 뒤 수준 1 LIST_HEADER 와 문단(트리에선 그 문단의 자식)이다. 글 폭·높이가\n // 0 인 묶음은 바탕쪽이 아니다(메모 글)\n const last = top.filter(n => n.rec.tagId === TAG.PARA_HEADER).at(-1)\n ctx.tailMasters = last ? listGroups(last.kids).filter(g => g.head.rec.data.length >= 20 && (g.head.rec.data.readUInt32LE(8) || g.head.rec.data.readUInt32LE(12))) : []\n ctx.linkedParas = splitLinkedBoxes(top)\n // 메모 글 — 구역 끝 MEMO_LIST(번호 DWORD) 뒤 LIST_HEADER(크기 정보 없음) 와 문단\n ctx.memos = new Map()\n let memo = -1\n for (const k of last?.kids ?? []) {\n if (k.rec.tagId === TAG.MEMO_LIST) memo = k.rec.data.length >= 4 ? k.rec.data.readUInt32LE(0) : -1\n else if (k.rec.tagId === TAG.LIST_HEADER) { if (memo >= 0 && k.rec.data.length < 20) ctx.memos.set(memo, { head: k, paras: [] }); else memo = -1 }\n else if (k.rec.tagId === TAG.PARA_HEADER && memo >= 0) ctx.memos.get(memo)?.paras.push(k)\n }\n return XML_DECL + `<hs:sec ${NS}>` + paragraphsXml(top, ctx) + \"</hs:sec>\"\n}\n\n// ─── 구역·단 정의 ────────────────────────────────────\n\nconst NOTE_PLACES = [\"EACH_COLUMN\", \"MERGED_COLUMN\", \"RIGHT_MOST_COLUMN\"] as const\nconst END_PLACES = [\"END_OF_DOCUMENT\", \"END_OF_SECTION\"] as const\nconst NOTE_NUMBERING = [\"CONTINUOUS\", \"ON_SECTION\", \"ON_PAGE\"] as const\nconst PAGE_STARTS = [\"BOTH\", \"EVEN\", \"ODD\"] as const\nconst GUTTERS = [\"LEFT_ONLY\", \"LEFT_RIGHT\", \"TOP_BOTTOM\"] as const\nconst FILL_AREAS = [\"PAPER\", \"PAGE\", \"BORDER\"] as const\nconst PAGE_BORDER_TYPES = [\"BOTH\", \"EVEN\", \"ODD\"] as const\nconst COL_TYPES = [\"NEWSPAPER\", \"BALANCED_NEWSPAPER\", \"PARALLEL\"] as const\nconst COL_LAYOUTS = [\"LEFT\", \"RIGHT\", \"MIRROR\"] as const\n\nconst ch = (code: number): string => (code ? String.fromCharCode(code) : \"\")\n\nfunction notePrXml(name: string, data: Buffer, endNote: boolean): string {\n const c = new Cur(data)\n const a = c.u32()\n const user = c.u16(), prefix = c.u16(), suffix = c.u16(), start = c.u16()\n const length = c.i32()\n const above = c.i16(), below = c.i16(), between = c.i16()\n const lineType = c.u8(), lineWidth = c.u8(), lineColor = c.u32()\n return el(name, [], el(\"hp:autoNumFormat\", [[\"type\", pick(NUM_FORMATS, bits(a, 0, 8))], [\"userChar\", ch(user)], [\"prefixChar\", ch(prefix)],\n [\"suffixChar\", ch(suffix)], [\"supscript\", bit(a, 12)]])\n + el(\"hp:noteLine\", [[\"length\", length], [\"type\", pick(BORDER_TYPES, lineType)], [\"width\", pick(BORDER_WIDTHS, lineWidth)], [\"color\", color(lineColor)]])\n + el(\"hp:noteSpacing\", [[\"betweenNotes\", between], [\"belowLine\", below], [\"aboveLine\", above]])\n + el(\"hp:numbering\", [[\"type\", pick(NOTE_NUMBERING, bits(a, 10, 2))], [\"newNum\", start]])\n + el(\"hp:placement\", [[\"place\", endNote ? pick(END_PLACES, bits(a, 8, 2)) : pick(NOTE_PLACES, bits(a, 8, 2))], [\"beneathText\", bit(a, 13)]]))\n}\n\n/** 'secd' 구역 정의 → hp:secPr */\nexport function secPrXml(node: RecNode, ctx: ConvertContext): string {\n const c = new Cur(node.rec.data, 4)\n const a = c.u32()\n const spaceColumns = c.i16(), lineGrid = c.i16(), charGrid = c.i16()\n const tabStop = c.u32()\n const outline = c.u16(), page = c.u16(), pic = c.u16(), tbl = c.u16(), eq = c.u16()\n let inner = el(\"hp:grid\", [[\"lineGrid\", lineGrid], [\"charGrid\", charGrid], [\"wonggojiFormat\", bit(a, 22)]])\n + el(\"hp:startNum\", [[\"pageStartsOn\", pick(PAGE_STARTS, bits(a, 20, 2))], [\"page\", page], [\"pic\", pic], [\"tbl\", tbl], [\"equation\", eq]])\n + el(\"hp:visibility\", [[\"hideFirstHeader\", bit(a, 0)], [\"hideFirstFooter\", bit(a, 1)], [\"hideFirstMasterPage\", bit(a, 2)],\n [\"border\", bit(a, 3) ? \"HIDE_FIRST\" : bit(a, 8) ? \"SHOW_FIRST\" : \"SHOW_ALL\"], [\"fill\", bit(a, 4) ? \"HIDE_FIRST\" : bit(a, 9) ? \"SHOW_FIRST\" : \"SHOW_ALL\"],\n [\"hideFirstPageNum\", bit(a, 5)], [\"hideFirstEmptyLine\", bit(a, 19)], [\"showLineNumber\", bit(a, 6)]])\n + el(\"hp:lineNumberShape\", [[\"restartType\", 0], [\"countBy\", 0], [\"distance\", 0], [\"startNumber\", 0]])\n let notes = 0, borders = 0\n // 바탕쪽 — 구역 정의 자식 LIST_HEADER 와 뒤따르는 문단. 종류는 구역 속성 비트 29(양쪽)·30(짝수)·31(홀수) 중 선 것의 차례로 놓인다\n const kinds = MASTER_KINDS.filter((_, i) => bit(a, 29 + i))\n const masters = listGroups(node.kids).map((g, i) => masterPageRef(g, kinds[i] ?? \"BOTH\", 0, ctx))\n // 확장 바탕쪽 — 확장 값이 3 이면 마지막 쪽, 그보다 크면 (값 − 3) 쪽 임의 쪽 (한글 저장 짝·한글 PDF 로 확인)\n for (const g of ctx.tailMasters) {\n const ext = g.head.rec.data.readUInt16LE(18)\n masters.push(ext > 3 ? masterPageRef(g, \"OPTIONAL_PAGE\", ext - 3, ctx) : masterPageRef(g, \"LAST_PAGE\", 0, ctx))\n }\n ctx.tailMasters = []\n for (const k of node.kids) {\n const d = k.rec.data\n if (k.rec.tagId === TAG.PAGE_DEF) {\n const p = new Cur(d)\n const w = p.u32(), hgt = p.u32(), l = p.u32(), r = p.u32(), t = p.u32(), b = p.u32(), hd = p.u32(), ft = p.u32(), g = p.u32(), pa = p.u32()\n inner += el(\"hp:pagePr\", [[\"landscape\", bit(pa, 0) ? \"NARROWLY\" : \"WIDELY\"], [\"width\", w], [\"height\", hgt], [\"gutterType\", pick(GUTTERS, bits(pa, 1, 2))]],\n el(\"hp:margin\", [[\"header\", hd], [\"footer\", ft], [\"gutter\", g], [\"left\", l], [\"right\", r], [\"top\", t], [\"bottom\", b]]))\n } else if (k.rec.tagId === TAG.FOOTNOTE_SHAPE) {\n inner += notePrXml(notes ? \"hp:endNotePr\" : \"hp:footNotePr\", d, notes > 0)\n notes++\n } else if (k.rec.tagId === TAG.PAGE_BORDER_FILL) {\n const p = new Cur(d)\n const pa = p.u32(), l = p.i16(), r = p.i16(), t = p.i16(), b = p.i16(), id = p.u16()\n inner += el(\"hp:pageBorderFill\", [[\"type\", pick(PAGE_BORDER_TYPES, borders)], [\"borderFillIDRef\", id], [\"textBorder\", bit(pa, 0) ? \"PAPER\" : \"CONTENT\"],\n [\"headerInside\", bit(pa, 1)], [\"footerInside\", bit(pa, 2)], [\"fillArea\", pick(FILL_AREAS, bits(pa, 3, 2))]],\n el(\"hp:offset\", [[\"left\", l], [\"right\", r], [\"top\", t], [\"bottom\", b]]))\n borders++\n }\n }\n const data = node.kids.find(k => k.rec.tagId === TAG.CTRL_DATA)\n // 메모 모양 번호는 구역 정의 34바이트 자리(u32). 그보다 짧은 옛 판은 메모 모양이 있으면 1\n const memoShape = node.rec.data.length >= 38 ? node.rec.data.readUInt32LE(34) : ctx.memoShapes ? 1 : 0\n return el(\"hp:secPr\", [[\"id\", \"\"], [\"textDirection\", bits(a, 16, 3) ? \"VERTICAL\" : \"HORIZONTAL\"], [\"spaceColumns\", spaceColumns],\n [\"tabStop\", tabStop], [\"tabStopVal\", Math.trunc(tabStop / 2)], [\"tabStopUnit\", tabStop % 2 ? \"CHAR\" : \"HWPUNIT\"], [\"outlineShapeIDRef\", outline],\n [\"memoShapeIDRef\", memoShape], [\"textVerticalWidthHead\", 0], [\"masterPageCnt\", masters.length]],\n inner + masters.join(\"\") + (data ? presentationXml(data.rec.data) : \"\"))\n}\n\n/**\n * 구역 정의 매개변수 묶음의 프레젠테이션(쪽 전환) 설정 → hp:presentation. 한글이 이 묶음을 두는 문서는 기본값(효과 없음·문서 전체·\n * 그러데이션 배경)이다 — 그 밖의 효과·적용 범위·채우기는 이름 대응을 모르므로 쓰지 않는다\n */\nfunction presentationXml(data: Buffer): string {\n const p = subSet(readParamSet(data, { o: 0 }), 0x219)\n const fill = subSet(p ?? undefined, 0x266)\n if (!p || !fill || p[0x4000] || p[0x4005] || fill[0x4001] !== 4) return \"\"\n const num = (v: Param | undefined): number => (typeof v === \"number\" ? v : 0)\n const colors = Array.isArray(fill[0x4008]) ? fill[0x4008].slice(0, num(fill[0x4007])) : []\n return el(\"hp:presentation\", [[\"effect\", \"none\"], [\"soundIDRef\", \"\"], [\"invertText\", num(p[0x4002])], [\"autoshow\", num(p[0x4003])],\n [\"showtime\", num(p[0x4004])], [\"applyto\", \"WholeDoc\"]],\n `<hc:fillBrush>${el(\"hc:gradation\", [[\"type\", pick(GRADATIONS, num(fill[0x4002]))], [\"angle\", num(fill[0x4003])], [\"centerX\", num(fill[0x4004])],\n [\"centerY\", num(fill[0x4005])], [\"step\", num(fill[0x4006])], [\"colorNum\", colors.length], [\"stepCenter\", num(fill[0x400a])], [\"alpha\", 0]],\n colors.map(v => el(\"hc:color\", [[\"value\", color(v)]])).join(\"\"))}</hc:fillBrush>`)\n}\n\nconst MASTER_KINDS = [\"BOTH\", \"EVEN\", \"ODD\"] as const\n\n/**\n * 연결된 글상자 — HWP 는 사슬의 글을 첫 글상자(목록 머리 @20 제 id·@24 다음 id)에 모두 두고 줄 나눔 정보로 다음 글상자에 흘린다.\n * 한글은 HWPX 의 연결 글상자에서 이 흐름을 다시 짜지 않아 다음 글상자가 비어 보인다(한글 화면 대조) — 문단을 줄 위치가 처음으로\n * 되돌아가는 곳에서 끊어 사슬 차례대로 제 글상자에 나눠 담는다. 연결 표시는 쓰지 않는다\n */\nfunction splitLinkedBoxes(top: RecNode[]): Map<number, RecNode[]> {\n const boxes = new Map<number, { next: number; paras: RecNode[] }>()\n const walk = (nodes: RecNode[]): void => {\n for (const n of nodes) {\n if (n.rec.tagId === TAG.SHAPE_COMPONENT) {\n const g = listGroups(n.kids)[0]\n const d = g?.head.rec.data\n if (g && d && d.length >= 28 && d.readUInt32LE(20)) boxes.set(d.readUInt32LE(20), { next: d.readUInt32LE(24), paras: g.paras })\n }\n walk(n.kids)\n }\n }\n walk(top)\n const out = new Map<number, RecNode[]>()\n const nexts = new Set([...boxes.values()].map(b => b.next))\n const vpos = (p: RecNode, last: boolean): number => {\n const ls = p.kids.find(k => k.rec.tagId === TAG.PARA_LINE_SEG)?.rec.data\n if (!ls || ls.length < 36) return -1\n return ls.readInt32LE((last ? Math.floor(ls.length / 36) - 1 : 0) * 36 + 4)\n }\n for (const [id, head] of boxes) {\n if (nexts.has(id) || !head.next) continue\n const chain = [id]\n for (let n = head.next; n && boxes.has(n) && !chain.includes(n); n = boxes.get(n)!.next) chain.push(n)\n let k = 0\n const parts: RecNode[][] = [[]]\n head.paras.forEach((p, i) => {\n if (i > 0 && k + 1 < chain.length && vpos(p, false) >= 0 && vpos(p, false) < vpos(head.paras[i - 1], true)) { k++; parts.push([]) }\n parts[k].push(p)\n })\n if (parts.length < 2) continue\n chain.forEach((cid, i) => { if (parts[i]?.length) out.set(cid, parts[i]) })\n }\n return out\n}\n\n/** 바탕쪽 하나 → masterpageN.xml(ctx.masterPages 에 쌓음), 구역 정의에 둘 참조. LIST_HEADER 목록 머리 뒤 글 폭·높이·글/번호 참조 */\nfunction masterPageRef(g: { head: RecNode; paras: RecNode[] }, kind: string, pageNumber: number, ctx: ConvertContext): string {\n const d = g.head.rec.data\n const c = new Cur(d, 8)\n const size: Record<string, number> = { textWidth: c.u32(), textHeight: c.u32(), hasTextRef: c.u8(), hasNumRef: c.u8() }\n const id = `masterpage${ctx.masterPages.length}`\n // 겹치기(pageDuplicate)는 확장 값 비트로 알 수 없다 — 한글 저장본은 확장 값 3·7 에서도 0 이다\n ctx.masterPages.push(XML_DECL + `<masterPage ${NS} id=\"${id}\" type=\"${kind}\" pageNumber=\"${pageNumber}\" pageDuplicate=\"0\" pageFront=\"0\">`\n + el(\"hp:subList\", subListAttrs(d).map(([k, v]) => [k, size[k] ?? v]), paragraphsXml(g.paras, ctx)) + \"</masterPage>\")\n return el(\"hp:masterPage\", [[\"idRef\", id]])\n}\n\n/** 'cold' 단 정의 → hp:ctrl/hp:colPr */\nexport function colPrXml(node: RecNode): string {\n const c = new Cur(node.rec.data, 4)\n const a = c.u16()\n const count = bits(a, 2, 8), same = bit(a, 12)\n let gap = 0\n const sizes: Array<[number, number]> = []\n if (!same && count > 1) {\n c.u16()\n for (let i = 0; i < count; i++) sizes.push([c.i16(), c.i16()])\n } else {\n gap = c.i16()\n c.u16()\n }\n const lineType = c.u8(), lineWidth = c.u8(), lineColor = c.u32()\n let inner = \"\"\n if (lineType) inner += el(\"hp:colLine\", [[\"type\", pick(BORDER_TYPES, lineType)], [\"width\", pick(BORDER_WIDTHS, lineWidth)], [\"color\", color(lineColor)]])\n for (const [w, g] of sizes) inner += el(\"hp:colSz\", [[\"width\", w], [\"gap\", g]])\n return \"<hp:ctrl>\" + el(\"hp:colPr\", [[\"id\", \"\"], [\"type\", pick(COL_TYPES, bits(a, 0, 2))], [\"layout\", pick(COL_LAYOUTS, bits(a, 10, 2))],\n [\"colCount\", count], [\"sameSz\", same], [\"sameGap\", gap]], inner || undefined) + \"</hp:ctrl>\"\n}\n\n"],"mappings":"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EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC7E,CAAC;AAED,IAAM,YAAY,IAAI,WAAW;AAAA,EAC/B;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAC3E;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC7E,CAAC;AAID,IAAM,OAAO,IAAI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","names":["createRequire","data","ch","ctrlId","data","data","data","data","TAG_ID_MAPPINGS","readRecords","CTRL_ID_TBL","numbering","ch","style","swap32","ctrl","data","numbering","bullet","i","table","style","require","data","style","n","ch","TAG","SHADOW_TYPES","TAG","attrs","TAG_CTRL_DATA","style","VERT_ALIGNS","data","LINE_WRAPS","TAG","borderFill","TAG","data","PAGE_STARTS","ch","cid","require","createRequire","CFB","TAG_BIN_DATA","data","ch"]}