hwpkit-dev 0.0.3 → 0.0.5

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.
package/dist/index.mjs CHANGED
@@ -1353,6 +1353,17 @@ function decodeGrid(tbl, ctx) {
1353
1353
  const headerRow = tblAttr.repeatHeader === "1";
1354
1354
  const gridProps = { headerRow: headerRow || void 0 };
1355
1355
  if (borderFill?.stroke) gridProps.defaultStroke = borderFill.stroke;
1356
+ const posAttr = tbl?.["hp:pos"]?.[0]?._attr ?? {};
1357
+ if (posAttr.horzAlign) {
1358
+ const alignMap = {
1359
+ LEFT: "left",
1360
+ RIGHT: "right",
1361
+ CENTER: "center",
1362
+ JUSTIFY: "justify"
1363
+ };
1364
+ const a = alignMap[posAttr.horzAlign];
1365
+ if (a) gridProps.align = a;
1366
+ }
1356
1367
  const rowArr = getTag(tbl, "hp:tr", "hp:ROW");
1357
1368
  for (const row of rowArr) {
1358
1369
  const cells = getTag(row, "hp:tc", "hp:CELL");
@@ -1435,16 +1446,15 @@ function decodeGrid(tbl, ctx) {
1435
1446
  };
1436
1447
  cellProps.va = vaMap[subAttr.vertAlign];
1437
1448
  }
1438
- const HWPX_DEFAULT_MARGIN_LR = 360;
1439
- const HWPX_DEFAULT_MARGIN_TB = 141;
1440
- const mL = Number(subAttr.marginLeft ?? HWPX_DEFAULT_MARGIN_LR);
1441
- const mR = Number(subAttr.marginRight ?? HWPX_DEFAULT_MARGIN_LR);
1442
- const mT = Number(subAttr.marginTop ?? HWPX_DEFAULT_MARGIN_TB);
1443
- const mB = Number(subAttr.marginBottom ?? HWPX_DEFAULT_MARGIN_TB);
1444
- if (mL !== HWPX_DEFAULT_MARGIN_LR) cellProps.padL = Metric.hwpToPt(mL);
1445
- if (mR !== HWPX_DEFAULT_MARGIN_LR) cellProps.padR = Metric.hwpToPt(mR);
1446
- if (mT !== HWPX_DEFAULT_MARGIN_TB) cellProps.padT = Metric.hwpToPt(mT);
1447
- if (mB !== HWPX_DEFAULT_MARGIN_TB) cellProps.padB = Metric.hwpToPt(mB);
1449
+ const cellMarginAttr = cell?.["hp:cellMargin"]?.[0]?._attr ?? {};
1450
+ const mL = cellMarginAttr.left !== void 0 ? Number(cellMarginAttr.left) : -1;
1451
+ const mR = cellMarginAttr.right !== void 0 ? Number(cellMarginAttr.right) : -1;
1452
+ const mT = cellMarginAttr.top !== void 0 ? Number(cellMarginAttr.top) : -1;
1453
+ const mB = cellMarginAttr.bottom !== void 0 ? Number(cellMarginAttr.bottom) : -1;
1454
+ if (mL >= 0) cellProps.padL = Metric.hwpToPt(mL);
1455
+ if (mR >= 0) cellProps.padR = Metric.hwpToPt(mR);
1456
+ if (mT >= 0) cellProps.padT = Metric.hwpToPt(mT);
1457
+ if (mB >= 0) cellProps.padB = Metric.hwpToPt(mB);
1448
1458
  const cellSpan = cell?.["hp:cellSpan"]?.[0]?._attr ?? {};
1449
1459
  const cs = Number(cellSpan.colSpan ?? ca.ColSpan ?? 1);
1450
1460
  const rs = Number(cellSpan.rowSpan ?? ca.RowSpan ?? 1);
@@ -1704,6 +1714,9 @@ var CTRL_IMAGE = 1768777504;
1704
1714
  var CTRL_OBJ = 1868720672;
1705
1715
  var CTRL_FIG = 1718183712;
1706
1716
  var CTRL_GSO = 1735618336;
1717
+ var CTRL_HEAD = 1751474532;
1718
+ var CTRL_FOOT = 1718579060;
1719
+ var CTRL_ATNO = 1635020399;
1707
1720
  function parseRecords(data) {
1708
1721
  const out = [];
1709
1722
  let off = 0;
@@ -1781,19 +1794,29 @@ function parseCharShape(d) {
1781
1794
  textColor: d.length >= 56 ? colorRef(d, 52) : "000000"
1782
1795
  };
1783
1796
  }
1784
- var ALIGN_TBL = { 0: "justify", 1: "left", 2: "right", 3: "center", 4: "justify" };
1797
+ var ALIGN_TBL = { 0: "justify", 1: "left", 2: "right", 3: "center", 4: "distribute", 5: "distribute_space" };
1785
1798
  function parseParaShape(d) {
1786
- if (d.length < 4) return { align: "left", spaceBefore: 0, spaceAfter: 0, lineSpacing: 160, leftMargin: 0, indent: 0 };
1799
+ if (d.length < 4) return { align: "left", spaceBefore: 0, spaceAfter: 0, lineSpacing: 160, lineSpacingType: 0, leftMargin: 0, rightMargin: 0, indent: 0 };
1787
1800
  const attr = BinaryKit.readU32LE(d, 0);
1801
+ const lineSpacingType = attr & 3;
1802
+ const align = ALIGN_TBL[attr >> 2 & 7] ?? "left";
1803
+ const vVal = attr >> 18 & 3;
1804
+ const verAlign = vVal === 1 ? "top" : vVal === 2 ? "center" : vVal === 3 ? "bottom" : "baseline";
1805
+ const lineWrap = "break";
1788
1806
  return {
1789
- align: ALIGN_TBL[attr >> 2 & 7] ?? "left",
1807
+ align,
1808
+ lineSpacingType,
1790
1809
  leftMargin: d.length >= 8 ? i32(d, 4) : 0,
1791
- // offset 4: leftMargin (들여쓰기)
1810
+ // offset 4: 문단 몸체 왼쪽 여백 (HWPUNIT)
1811
+ rightMargin: d.length >= 12 ? i32(d, 8) : 0,
1812
+ // offset 8: 문단 몸체 오른쪽 여백 (HWPUNIT)
1792
1813
  indent: d.length >= 16 ? i32(d, 12) : 0,
1793
- // offset 12: first-line indent
1814
+ // offset 12: 줄 들여쓰기 (HWPUNIT)
1794
1815
  spaceBefore: d.length >= 20 ? i32(d, 16) : 0,
1795
1816
  spaceAfter: d.length >= 24 ? i32(d, 20) : 0,
1796
- lineSpacing: d.length >= 28 ? i32(d, 24) : 160
1817
+ lineSpacing: d.length >= 28 ? i32(d, 24) : 160,
1818
+ verAlign,
1819
+ lineWrap
1797
1820
  };
1798
1821
  }
1799
1822
  var BORDER_W_PT = [0.28, 0.34, 0.43, 0.57, 0.71, 0.85, 1.13, 1.42, 1.7, 1.98, 2.84, 4.25, 5.67, 8.5, 11.34, 14.17];
@@ -1849,6 +1872,8 @@ function parseParagraphGroup(recs, start, di, shield, gsoCtx) {
1849
1872
  const hdr = recs[start];
1850
1873
  const lv = hdr.level;
1851
1874
  const psId = hdr.data.length >= 10 ? BinaryKit.readU16LE(hdr.data, 8) : 0;
1875
+ const hwpStyleId = hdr.data.length >= 11 ? hdr.data[10] : 0;
1876
+ const divideSort = hdr.data.length >= 12 ? hdr.data[11] : 0;
1852
1877
  const ps = di.paraShapes[psId];
1853
1878
  let text = null;
1854
1879
  let csPairs = [];
@@ -1866,23 +1891,48 @@ function parseParagraphGroup(recs, start, di, shield, gsoCtx) {
1866
1891
  } else if (r.tag === TAG_CTRL_HEADER && r.level === lv + 1) {
1867
1892
  if (r.data.length >= 4) {
1868
1893
  const ctrlId = BinaryKit.readU32LE(r.data, 0);
1869
- const MAX_HWP = 1e6;
1870
- const rawW = r.data.length >= 24 ? BinaryKit.readU32LE(r.data, 16) : 0;
1871
- const rawH = r.data.length >= 28 ? BinaryKit.readU32LE(r.data, 20) : 0;
1872
- const wPt = rawW > 0 && rawW < MAX_HWP ? Metric.hwpToPt(rawW) : 0;
1873
- const hPt = rawH > 0 && rawH < MAX_HWP ? Metric.hwpToPt(rawH) : 0;
1874
- const imgId = ctrlId === CTRL_GSO ? gsoCtx.count++ : r.data.length >= 6 ? BinaryKit.readU16LE(r.data, 4) : 0;
1875
- ctrlHeaders.push({ ctrlId, imgId, wPt, hPt });
1876
- if (ctrlId === CTRL_TABLE) {
1877
- const tr = shield.guard(
1878
- () => parseTableCtrl(recs, i, di, shield, gsoCtx),
1879
- { grid: null, next: skipKids(recs, i) },
1880
- `hwp:tbl@${i}`
1881
- );
1882
- if (tr.grid) grids.push(tr.grid);
1883
- i = tr.next;
1894
+ if (ctrlId === CTRL_HEAD || ctrlId === CTRL_FOOT) {
1895
+ const ctrlLv = r.level;
1896
+ const hfParas = [];
1897
+ let j = i + 1;
1898
+ while (j < recs.length && recs[j].level > ctrlLv) {
1899
+ if (recs[j].tag === TAG_PARA_HEADER) {
1900
+ const pr = shield.guard(
1901
+ () => parseParagraphGroup(recs, j, di, shield, gsoCtx),
1902
+ { nodes: [], next: j + 1 },
1903
+ `hwp:hf@${j}`
1904
+ );
1905
+ hfParas.push(...pr.nodes.filter((n) => n.tag === "para"));
1906
+ j = pr.next;
1907
+ } else {
1908
+ j++;
1909
+ }
1910
+ }
1911
+ if (hfParas.length > 0) {
1912
+ const key = ctrlId === CTRL_HEAD ? "headers" : "footers";
1913
+ if (!gsoCtx[key]) gsoCtx[key] = hfParas;
1914
+ }
1915
+ i = j;
1884
1916
  } else {
1885
- i = skipKids(recs, i);
1917
+ const MAX_HWP = 1e6;
1918
+ const rawW = r.data.length >= 24 ? BinaryKit.readU32LE(r.data, 16) : 0;
1919
+ const rawH = r.data.length >= 28 ? BinaryKit.readU32LE(r.data, 20) : 0;
1920
+ const wPt = rawW > 0 && rawW < MAX_HWP ? Metric.hwpToPt(rawW) : 0;
1921
+ const hPt = rawH > 0 && rawH < MAX_HWP ? Metric.hwpToPt(rawH) : 0;
1922
+ const atnoType = ctrlId === CTRL_ATNO && r.data.length >= 8 ? BinaryKit.readU32LE(r.data, 4) & 15 : void 0;
1923
+ const imgId = ctrlId === CTRL_GSO ? gsoCtx.count++ : r.data.length >= 6 ? BinaryKit.readU16LE(r.data, 4) : 0;
1924
+ ctrlHeaders.push({ ctrlId, imgId, wPt, hPt, atnoType });
1925
+ if (ctrlId === CTRL_TABLE) {
1926
+ const tr = shield.guard(
1927
+ () => parseTableCtrl(recs, i, di, shield, gsoCtx),
1928
+ { grid: null, next: skipKids(recs, i) },
1929
+ `hwp:tbl@${i}`
1930
+ );
1931
+ if (tr.grid) grids.push(tr.grid);
1932
+ i = tr.next;
1933
+ } else {
1934
+ i = skipKids(recs, i);
1935
+ }
1886
1936
  }
1887
1937
  } else {
1888
1938
  i = skipKids(recs, i);
@@ -1892,13 +1942,35 @@ function parseParagraphGroup(recs, start, di, shield, gsoCtx) {
1892
1942
  }
1893
1943
  }
1894
1944
  const nodes = [];
1895
- if (text && (text.chars.length > 0 || text.controls.length > 0)) {
1945
+ {
1896
1946
  const paraContent = [];
1897
- if (text.chars.length > 0) {
1898
- const spans = resolveCharShapes(text.chars, csPairs, di);
1899
- paraContent.push(...spans);
1947
+ const atnoCtrls = [];
1948
+ if (text && text.controls.length > 0) {
1949
+ for (let ci = 0; ci < text.controls.length; ci++) {
1950
+ const ch = ctrlHeaders[ci];
1951
+ if (ch && ch.ctrlId === CTRL_ATNO)
1952
+ atnoCtrls.push({ pos: text.controls[ci].pos, type: ch.atnoType ?? 0 });
1953
+ }
1954
+ atnoCtrls.sort((a, b) => a.pos - b.pos);
1955
+ }
1956
+ if (text && text.chars.length > 0) {
1957
+ if (atnoCtrls.length > 0) {
1958
+ let k = 0;
1959
+ for (const ac of atnoCtrls) {
1960
+ const seg = [];
1961
+ while (k < text.chars.length && text.chars[k].pos < ac.pos) seg.push(text.chars[k++]);
1962
+ if (seg.length > 0) paraContent.push(...resolveCharShapes(seg, csPairs, di));
1963
+ paraContent.push(buildPageNum(ac.type === 0 ? "decimal" : "total"));
1964
+ }
1965
+ const rest = text.chars.slice(k);
1966
+ if (rest.length > 0) paraContent.push(...resolveCharShapes(rest, csPairs, di));
1967
+ } else {
1968
+ paraContent.push(...resolveCharShapes(text.chars, csPairs, di));
1969
+ }
1970
+ } else if (atnoCtrls.length > 0) {
1971
+ for (const ac of atnoCtrls) paraContent.push(buildPageNum(ac.type === 0 ? "decimal" : "total"));
1900
1972
  }
1901
- if (text.controls.length > 0) {
1973
+ if (text && text.controls.length > 0) {
1902
1974
  for (let ci = 0; ci < text.controls.length; ci++) {
1903
1975
  const ch = ctrlHeaders[ci];
1904
1976
  if (!ch) continue;
@@ -1908,11 +1980,15 @@ function parseParagraphGroup(recs, start, di, shield, gsoCtx) {
1908
1980
  paraContent.push(buildSpan(`__EXT_${ch.imgId}${dimStr}__`));
1909
1981
  }
1910
1982
  }
1911
- if (paraContent.length > 0) {
1912
- nodes.push(buildPara(paraContent, buildParaProps(ps)));
1983
+ if (divideSort & 4) {
1984
+ nodes.push(buildPara([{ tag: "span", props: {}, kids: [buildPb()] }]));
1913
1985
  }
1986
+ nodes.push(...grids);
1987
+ nodes.push(buildPara(
1988
+ paraContent.length > 0 ? paraContent : [buildSpan("")],
1989
+ buildParaProps(ps, hwpStyleId)
1990
+ ));
1914
1991
  }
1915
- nodes.push(...grids);
1916
1992
  return { nodes, next: i };
1917
1993
  }
1918
1994
  function skipKids(recs, idx) {
@@ -1921,7 +1997,7 @@ function skipKids(recs, idx) {
1921
1997
  while (i < recs.length && recs[i].level > lv) i++;
1922
1998
  return i;
1923
1999
  }
1924
- var EXT_CTRL = /* @__PURE__ */ new Set([2, 3, 11, 12, 14, 15]);
2000
+ var EXT_CTRL = /* @__PURE__ */ new Set([2, 3, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]);
1925
2001
  var INL_CTRL = /* @__PURE__ */ new Set([4, 5, 6, 7, 8]);
1926
2002
  function decodeParaText(d) {
1927
2003
  const chars = [];
@@ -2219,6 +2295,8 @@ function parseCellRec(d, tag, recs, cStart, cEnd, di, shield, seqIdx, colCnt, gs
2219
2295
  const hdr = recs[k];
2220
2296
  const lv = hdr.level;
2221
2297
  const psId = hdr.data.length >= 10 ? BinaryKit.readU16LE(hdr.data, 8) : 0;
2298
+ const cellStyleId = hdr.data.length >= 11 ? hdr.data[10] : 0;
2299
+ const cellDivide = hdr.data.length >= 12 ? hdr.data[11] : 0;
2222
2300
  const ps = di.paraShapes[psId];
2223
2301
  let txt = null;
2224
2302
  let csp = [];
@@ -2270,7 +2348,8 @@ function parseCellRec(d, tag, recs, cStart, cEnd, di, shield, seqIdx, colCnt, gs
2270
2348
  }
2271
2349
  }
2272
2350
  const kids = paraContent.length > 0 ? paraContent : [buildSpan("")];
2273
- const items = [buildPara(kids, buildParaProps(ps)), ...innerGrids];
2351
+ const items = [...innerGrids, buildPara(kids, buildParaProps(ps, cellStyleId))];
2352
+ if (cellDivide & 4) items.unshift(buildPara([{ tag: "span", props: {}, kids: [buildPb()] }]));
2274
2353
  return { items, next: j };
2275
2354
  },
2276
2355
  { items: [buildPara([buildSpan("")])], next: k + 1 },
@@ -2323,6 +2402,8 @@ function parsePageDef(d) {
2323
2402
  const mr = BinaryKit.readU32LE(d, 12);
2324
2403
  const mt = BinaryKit.readU32LE(d, 16);
2325
2404
  const mb = BinaryKit.readU32LE(d, 20);
2405
+ const header = d.length >= 28 ? BinaryKit.readU32LE(d, 24) : 0;
2406
+ const footer = d.length >= 32 ? BinaryKit.readU32LE(d, 28) : 0;
2326
2407
  const at = d.length >= 40 ? BinaryKit.readU32LE(d, 36) : 0;
2327
2408
  return {
2328
2409
  wPt: Metric.hwpToPt(w),
@@ -2331,6 +2412,8 @@ function parsePageDef(d) {
2331
2412
  mr: Metric.hwpToPt(mr),
2332
2413
  mt: Metric.hwpToPt(mt),
2333
2414
  mb: Metric.hwpToPt(mb),
2415
+ headerPt: header > 0 ? Metric.hwpToPt(header) : void 0,
2416
+ footerPt: footer > 0 ? Metric.hwpToPt(footer) : void 0,
2334
2417
  orient: at & 1 ? "landscape" : "portrait"
2335
2418
  };
2336
2419
  }
@@ -2361,16 +2444,24 @@ function strokeFromBF(bfId, di) {
2361
2444
  const b = bf.borders[0];
2362
2445
  return { kind: BORDER_KIND[b.type] ?? "solid", pt: b.widthPt, color: b.color };
2363
2446
  }
2364
- function buildParaProps(ps) {
2365
- if (!ps) return {};
2366
- const p = {};
2447
+ function buildParaProps(ps, hwpStyleId) {
2448
+ const p = hwpStyleId !== void 0 ? { hwpStyleId } : {};
2449
+ if (!ps) return p;
2367
2450
  if (ps.align && ps.align !== "left") p.align = ps.align;
2368
2451
  if (ps.spaceBefore > 0) p.spaceBefore = Metric.hwpToPt(ps.spaceBefore);
2369
2452
  if (ps.spaceAfter > 0) p.spaceAfter = Metric.hwpToPt(ps.spaceAfter);
2370
- if (ps.lineSpacing > 0 && ps.lineSpacing !== 160) p.lineHeight = ps.lineSpacing / 100;
2453
+ if (ps.lineSpacingType === 1) {
2454
+ if (ps.lineSpacing > 0) p.lineHeightFixed = Metric.hwpToPt(ps.lineSpacing);
2455
+ } else {
2456
+ if (ps.lineSpacing > 0) p.lineHeight = ps.lineSpacing / 100;
2457
+ }
2371
2458
  const leftMarginPt = Math.max(0, Metric.hwpToPt(ps.leftMargin));
2372
2459
  if (leftMarginPt > 0) p.leftMargin = leftMarginPt;
2460
+ const rightMarginPt = Math.max(0, Metric.hwpToPt(ps.rightMargin));
2461
+ if (rightMarginPt > 0) p.indentRightPt = rightMarginPt;
2373
2462
  if (ps.indent !== 0) p.firstLineIndentPt = Metric.hwpToPt(ps.indent);
2463
+ if (ps.verAlign && ps.verAlign !== "baseline") p.verAlign = ps.verAlign;
2464
+ if (ps.lineWrap && ps.lineWrap !== "break") p.lineWrap = ps.lineWrap;
2374
2465
  return p;
2375
2466
  }
2376
2467
  var HwpScanner = class {
@@ -2438,7 +2529,10 @@ var HwpScanner = class {
2438
2529
  }
2439
2530
  warns.push(...shield.flush());
2440
2531
  const content = allContent.length > 0 ? allContent : [buildPara([buildSpan("")])];
2441
- return succeed(buildRoot({}, [buildSheet(content, pageDims)]), warns);
2532
+ return succeed(buildRoot({}, [buildSheet(content, pageDims, {
2533
+ headers: gsoCtx.headers ? { default: gsoCtx.headers } : void 0,
2534
+ footers: gsoCtx.footers ? { default: gsoCtx.footers } : void 0
2535
+ })]), warns);
2442
2536
  } catch (e) {
2443
2537
  warns.push(...shield.flush());
2444
2538
  return fail(`HWP decode error: ${e?.message ?? String(e)}`, warns);
@@ -4409,6 +4503,27 @@ var KIND_MAP = {
4409
4503
  dash_dot: "DASH_DOT",
4410
4504
  dash_dot_dot: "DASH_DOT_DOT"
4411
4505
  };
4506
+ function quantizeBorderWidth(pt) {
4507
+ const mm = pt * 0.3528;
4508
+ const standardWidths = [0.1, 0.12, 0.15, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 1, 1.5, 2, 3, 4, 5];
4509
+ let closest = standardWidths[0];
4510
+ let minDiff = Math.abs(mm - closest);
4511
+ for (let i = 1; i < standardWidths.length; i++) {
4512
+ const diff = Math.abs(mm - standardWidths[i]);
4513
+ if (diff < minDiff) {
4514
+ minDiff = diff;
4515
+ closest = standardWidths[i];
4516
+ }
4517
+ }
4518
+ let str = closest.toFixed(2);
4519
+ if (str.endsWith("0")) {
4520
+ str = str.slice(0, -1);
4521
+ }
4522
+ if (str.endsWith(".0")) {
4523
+ str = str.slice(0, -2);
4524
+ }
4525
+ return `${str} mm`;
4526
+ }
4412
4527
  var BorderFillBank = class {
4413
4528
  constructor() {
4414
4529
  this.fills = [];
@@ -4421,7 +4536,7 @@ var BorderFillBank = class {
4421
4536
  }
4422
4537
  _strokeXml(tag, s) {
4423
4538
  const type = s && s.kind !== "none" ? KIND_MAP[s.kind] ?? "SOLID" : "NONE";
4424
- const w = s && s.kind !== "none" ? `${(s.pt * 0.3528).toFixed(2)} mm` : "0.12 mm";
4539
+ const w = s && s.kind !== "none" ? quantizeBorderWidth(s.pt) : "0.12 mm";
4425
4540
  const c = s ? s.color.startsWith("#") ? s.color : `#${s.color}` : "#000000";
4426
4541
  return `<hh:${tag} type="${type}" width="${w}" color="${c}"/>`;
4427
4542
  }
@@ -4498,7 +4613,7 @@ function charPrKey(p) {
4498
4613
  return `${p.b ? 1 : 0}|${p.i ? 1 : 0}|${p.u ? 1 : 0}|${p.s ? 1 : 0}|${p.pt ?? 10}|${p.color ?? "000000"}|${p.font ?? ""}|${p.bg ?? ""}`;
4499
4614
  }
4500
4615
  function paraPrKey(p) {
4501
- return `${p.align ?? "left"}|${p.listOrd ?? ""}|${p.listLv ?? 0}|${p.indentPt ?? 0}|${p.firstLineIndentPt ?? 0}|${p.spaceBefore ?? 0}|${p.spaceAfter ?? 0}|${p.lineHeight ?? 0}|${p.styleId ?? ""}`;
4616
+ return `${p.align ?? "left"}|${p.verAlign ?? "baseline"}|${p.lineWrap ?? "break"}|${p.listOrd ?? ""}|${p.listLv ?? 0}|${p.indentPt ?? 0}|${p.leftMargin ?? 0}|${p.indentRightPt ?? 0}|${p.firstLineIndentPt ?? 0}|${p.spaceBefore ?? 0}|${p.spaceAfter ?? 0}|${p.lineHeight ?? 0}|${p.lineHeightFixed ?? 0}|${p.styleId ?? ""}`;
4502
4617
  }
4503
4618
  function registerCharPr(props, ctx) {
4504
4619
  const key = charPrKey(props);
@@ -4522,20 +4637,45 @@ function registerCharPr(props, ctx) {
4522
4637
  ctx.charPrMap.set(key, id);
4523
4638
  return id;
4524
4639
  }
4640
+ var ALIGN_MAP2 = {
4641
+ left: "LEFT",
4642
+ center: "CENTER",
4643
+ right: "RIGHT",
4644
+ justify: "JUSTIFY",
4645
+ distribute: "DISTRIBUTE",
4646
+ distribute_space: "DISTRIBUTE_SPACE"
4647
+ };
4648
+ var V_ALIGN_MAP = {
4649
+ baseline: "BASELINE",
4650
+ top: "TOP",
4651
+ center: "CENTER",
4652
+ bottom: "BOTTOM"
4653
+ };
4654
+ var LINE_WRAP_MAP = {
4655
+ break: "BREAK",
4656
+ squeeze: "SQUEEZE",
4657
+ keep: "KEEP"
4658
+ };
4525
4659
  function registerParaPr(props, ctx) {
4526
4660
  const key = paraPrKey(props);
4527
4661
  const existing = ctx.paraPrMap.get(key);
4528
4662
  if (existing !== void 0) return existing;
4529
4663
  const id = ctx.paraPrs.length;
4664
+ const alignStr = props.align ? ALIGN_MAP2[props.align] ?? "LEFT" : "LEFT";
4665
+ const verAlignStr = props.verAlign ? V_ALIGN_MAP[props.verAlign] ?? "BASELINE" : "BASELINE";
4666
+ const lineWrapStr = props.lineWrap ? LINE_WRAP_MAP[props.lineWrap] ?? "BREAK" : "BREAK";
4530
4667
  const def = {
4531
4668
  id,
4532
- align: (props.align ?? "left").toUpperCase(),
4533
- leftHwp: Metric.ptToHwp(props.indentPt ?? 0),
4669
+ align: alignStr,
4670
+ verAlign: verAlignStr,
4671
+ lineWrap: lineWrapStr,
4672
+ leftHwp: Metric.ptToHwp(props.leftMargin ?? 0),
4534
4673
  rightHwp: Metric.ptToHwp(props.indentRightPt ?? 0),
4535
4674
  intentHwp: Metric.ptToHwp(props.firstLineIndentPt ?? 0),
4536
4675
  prevHwp: Metric.ptToHwp(props.spaceBefore ?? 0),
4537
4676
  nextHwp: Metric.ptToHwp(props.spaceAfter ?? 0),
4538
- lineSpacing: props.lineHeight ? Math.round(props.lineHeight * 100) : 160
4677
+ lineSpacing: props.lineHeightFixed ? 0 : props.lineHeight ? Math.round(props.lineHeight * 100) : 160,
4678
+ lineSpacingFixed: props.lineHeightFixed ? Metric.ptToHwp(props.lineHeightFixed) : void 0
4539
4679
  };
4540
4680
  if (props.listOrd !== void 0) {
4541
4681
  def.listType = props.listOrd ? "DIGIT" : "BULLET";
@@ -4640,8 +4780,8 @@ var HwpxEncoder = class extends BaseEncoder {
4640
4780
  try {
4641
4781
  const sheet = doc.kids[0];
4642
4782
  const dims = normalizeDims(sheet?.dims ?? A4);
4643
- const safeML = dims.ml > 0 ? dims.ml : 70.87;
4644
- const safeMR = dims.mr > 0 ? dims.mr : 70.87;
4783
+ const safeML = dims.ml !== void 0 && dims.ml >= 0 ? dims.ml : 70.87;
4784
+ const safeMR = dims.mr !== void 0 && dims.mr >= 0 ? dims.mr : 70.87;
4645
4785
  const availableWidth = Math.round(
4646
4786
  Metric.ptToHwp(dims.wPt) - Metric.ptToHwp(safeML) - Metric.ptToHwp(safeMR)
4647
4787
  );
@@ -4697,9 +4837,9 @@ var HwpxEncoder = class extends BaseEncoder {
4697
4837
  mime: "application/xml"
4698
4838
  },
4699
4839
  {
4700
- name: "META-INF/container.rdf",
4701
- data: this.stringToBytes(CONTAINER_RDF),
4702
- mime: "application/rdf+xml"
4840
+ name: "META-INF/manifest.xml",
4841
+ data: this.stringToBytes(MANIFEST_XML),
4842
+ mime: "application/xml"
4703
4843
  },
4704
4844
  {
4705
4845
  name: "Contents/content.hpf",
@@ -4738,9 +4878,9 @@ var HwpxEncoder = class extends BaseEncoder {
4738
4878
  }
4739
4879
  }
4740
4880
  };
4741
- var VERSION_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hv:HCFVersion xmlns:hv="http://www.owpml.org/owpml/2024/version" targetApplication="WORDPROCESSING" major="5" minor="1" micro="0" buildNumber="1" os="1" xmlVersion="1.4" application="Hancom Office Hangul" appVersion="11, 0, 0, 0"/>`;
4742
- var CONTAINER_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><ocf:container xmlns:ocf="urn:oasis:names:tc:opendocument:xmlns:container" xmlns:hpf="http://www.hancom.co.kr/schema/2011/hpf"><ocf:rootfiles><ocf:rootfile full-path="Contents/content.hpf" media-type="application/hwpml-package+xml"/><ocf:rootfile full-path="Preview/PrvText.txt" media-type="text/plain"/><ocf:rootfile full-path="META-INF/container.rdf" media-type="application/rdf+xml"/></ocf:rootfiles></ocf:container>`;
4743
- var CONTAINER_RDF = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about=""><ns0:hasPart xmlns:ns0="http://www.hancom.co.kr/hwpml/2016/meta/pkg#" rdf:resource="Contents/header.xml"/></rdf:Description><rdf:Description rdf:about="Contents/header.xml"><rdf:type rdf:resource="http://www.hancom.co.kr/hwpml/2016/meta/pkg#HeaderFile"/></rdf:Description><rdf:Description rdf:about=""><ns0:hasPart xmlns:ns0="http://www.hancom.co.kr/hwpml/2016/meta/pkg#" rdf:resource="Contents/section0.xml"/></rdf:Description><rdf:Description rdf:about="Contents/section0.xml"><rdf:type rdf:resource="http://www.hancom.co.kr/hwpml/2016/meta/pkg#SectionFile"/></rdf:Description><rdf:Description rdf:about=""><rdf:type rdf:resource="http://www.hancom.co.kr/hwpml/2016/meta/pkg#Document"/></rdf:Description></rdf:RDF>`;
4881
+ var VERSION_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hv:HCFVersion xmlns:hv="http://www.hancom.co.kr/hwpml/2011/version" tagetApplication="WORDPROCESSOR" major="5" minor="0" micro="5" buildNumber="0" os="1" xmlVersion="1.4" application="Hancom Office Hangul" appVersion="9, 6, 1, 10097"/>`;
4882
+ var CONTAINER_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><ocf:container xmlns:ocf="urn:oasis:names:tc:opendocument:xmlns:container" xmlns:hpf="http://www.hancom.co.kr/schema/2011/hpf"><ocf:rootfiles><ocf:rootfile full-path="Contents/content.hpf" media-type="application/hwpml-package+xml"/><ocf:rootfile full-path="Preview/PrvText.txt" media-type="text/plain"/></ocf:rootfiles></ocf:container>`;
4883
+ var MANIFEST_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><odf:manifest xmlns:odf="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"/>`;
4744
4884
  function buildContentHpf(ctx, meta) {
4745
4885
  const title = esc(meta?.title ?? "");
4746
4886
  const creator = esc(meta?.author ?? "text");
@@ -4766,6 +4906,18 @@ function buildNumberingsXml() {
4766
4906
  function buildBulletsXml() {
4767
4907
  return `<hh:bullets itemCnt="1"><hh:bullet id="1" charPrIDRef="0" start="1" numFormat="BULLET"><hh:paraHead level="1" numChar="&#x2022;"/><hh:paraHead level="2" numChar="&#x2022;"/><hh:paraHead level="3" numChar="&#x2022;"/></hh:bullet></hh:bullets>`;
4768
4908
  }
4909
+ function buildHeaderSecPrListXml(dims) {
4910
+ const wHwp = Metric.ptToHwp(dims.wPt);
4911
+ const hHwp = Metric.ptToHwp(dims.hPt);
4912
+ const ml = Metric.ptToHwp(dims.ml);
4913
+ const mr = Metric.ptToHwp(dims.mr);
4914
+ const mt = Metric.ptToHwp(dims.mt);
4915
+ const mb = Metric.ptToHwp(dims.mb);
4916
+ const headerZone = dims.headerPt !== void 0 && dims.headerPt > 0 ? Metric.ptToHwp(dims.headerPt) : 0;
4917
+ const footerZone = dims.footerPt !== void 0 && dims.footerPt > 0 ? Metric.ptToHwp(dims.footerPt) : 0;
4918
+ const pageBorderFill = `<hh:pageBorderFill type="BOTH" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hh:offset left="1417" right="1417" top="1417" bottom="1417"/></hh:pageBorderFill><hh:pageBorderFill type="EVEN" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hh:offset left="1417" right="1417" top="1417" bottom="1417"/></hh:pageBorderFill><hh:pageBorderFill type="ODD" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hh:offset left="1417" right="1417" top="1417" bottom="1417"/></hh:pageBorderFill>`;
4919
+ return `<hh:secPrList itemCnt="1"><hh:secPr id="0" textDirection="HORIZONTAL" spaceColumns="1134" tabStop="8000" outlineShapeIDRef="0" memoShapeIDRef="0" textVerticalWidthHead="0" masterPageCnt="0"><hh:grid lineGrid="0" charGrid="0" wonggojiFormat="0"/><hh:startNum pageStartsOn="BOTH" page="0" pic="0" tbl="0" equation="0"/><hh:visibility hideFirstHeader="0" hideFirstFooter="0" hideFirstMasterPage="0" border="SHOW_ALL" fill="SHOW_ALL" hideFirstPageNum="0" hideFirstEmptyLine="0" showLineNumber="0"/><hh:lineNumberShape restartType="0" countBy="0" distance="0" startNumber="0"/><hh:pagePr landscape="WIDELY" width="${wHwp}" height="${hHwp}" gutterType="LEFT_ONLY"><hh:margin header="${headerZone}" footer="${footerZone}" gutter="0" left="${ml}" right="${mr}" top="${mt}" bottom="${mb}"/></hh:pagePr><hh:colPr id="" type="NEWSPAPER" layout="LEFT" colCount="1" sameSz="1" sameGap="0"/><hh:footNotePr><hh:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar="" supscript="1"/><hh:noteLine length="-1" type="SOLID" width="0.25 mm" color="#000000"/><hh:noteSpacing betweenNotes="283" belowLine="0" aboveLine="1000"/><hh:numbering type="CONTINUOUS" newNum="1"/><hh:placement place="EACH_COLUMN" beneathText="0"/></hh:footNotePr><hh:endNotePr><hh:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar="" supscript="1"/><hh:noteLine length="-1" type="SOLID" width="0.25 mm" color="#000000"/><hh:noteSpacing betweenNotes="0" belowLine="0" aboveLine="1000"/><hh:numbering type="CONTINUOUS" newNum="1"/><hh:placement place="END_OF_DOCUMENT" beneathText="0"/></hh:endNotePr>` + pageBorderFill + `</hh:secPr></hh:secPrList>`;
4920
+ }
4769
4921
  function buildHeaderXml(dims, meta, ctx) {
4770
4922
  const fontFacesXml = ctx.fontBank.toXml();
4771
4923
  let charPrXml = "";
@@ -4779,51 +4931,17 @@ function buildHeaderXml(dims, meta, ctx) {
4779
4931
  }
4780
4932
  let paraPrXml = "";
4781
4933
  for (const pp of ctx.paraPrs) {
4782
- paraPrXml += `<hh:paraPr id="${pp.id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="0" suppressLineNumbers="0" checked="0"><hh:align horizontal="${pp.align}" vertical="BASELINE"/><hh:heading type="NONE" idRef="0" level="0"/><hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="BREAK_WORD" widowOrphan="0" keepWithNext="0" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/><hh:autoSpacing eAsianEng="0" eAsianNum="0"/><hh:margin><hc:intent value="${pp.intentHwp}" unit="HWPUNIT"/><hc:left value="${pp.leftHwp}" unit="HWPUNIT"/><hc:right value="${pp.rightHwp}" unit="HWPUNIT"/><hc:prev value="${pp.prevHwp}" unit="HWPUNIT"/><hc:next value="${pp.nextHwp}" unit="HWPUNIT"/></hh:margin><hh:lineSpacing type="PERCENT" value="${pp.lineSpacing}" unit="HWPUNIT"/><hh:border borderFillIDRef="1" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/></hh:paraPr>`;
4934
+ const ver = pp.verAlign ?? "BASELINE";
4935
+ const wrap = pp.lineWrap ?? "BREAK";
4936
+ const lsType = pp.lineSpacingFixed !== void 0 ? "FIXED" : "PERCENT";
4937
+ const lsValue = pp.lineSpacingFixed !== void 0 ? pp.lineSpacingFixed : pp.lineSpacing;
4938
+ paraPrXml += `<hh:paraPr id="${pp.id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="0" suppressLineNumbers="0" checked="0"><hh:align horizontal="${pp.align}" vertical="${ver}"/><hh:heading type="NONE" idRef="0" level="0"/><hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="KEEP_WORD" widowOrphan="0" keepWithNext="0" keepLines="0" pageBreakBefore="0" lineWrap="${wrap}"/><hh:autoSpacing eAsianEng="0" eAsianNum="0"/><hh:margin><hc:intent value="${pp.intentHwp}" unit="HWPUNIT"/><hc:left value="${pp.leftHwp}" unit="HWPUNIT"/><hc:right value="${pp.rightHwp}" unit="HWPUNIT"/><hc:prev value="${pp.prevHwp}" unit="HWPUNIT"/><hc:next value="${pp.nextHwp}" unit="HWPUNIT"/></hh:margin><hh:lineSpacing type="${lsType}" value="${lsValue}" unit="HWPUNIT"/><hh:border borderFillIDRef="1" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/></hh:paraPr>`;
4783
4939
  }
4784
4940
  const borderFillXml = ctx.borderFillBank.toXml();
4785
4941
  const stylesXml2 = `<hh:styles itemCnt="${ctx.hwpxStyles.length}">` + ctx.hwpxStyles.map(
4786
4942
  (s) => `<hh:style id="${s.id}" type="PARA" name="${esc(s.name)}" engName="${esc(s.engName)}" paraPrIDRef="${s.paraPrIDRef}" charPrIDRef="${s.charPrIDRef}" nextStyleIDRef="0" langID="1042" lockForm="0"/>`
4787
4943
  ).join("") + `</hh:styles>`;
4788
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hh:head ${NS} version="1.2" secCnt="1"><hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/><hh:refList>` + fontFacesXml + borderFillXml + `<hh:charProperties itemCnt="${ctx.charPrs.length}">${charPrXml}</hh:charProperties><hh:tabProperties itemCnt="1"><hh:tabPr id="0" autoTabLeft="0" autoTabRight="0"/></hh:tabProperties>` + buildNumberingsXml() + buildBulletsXml() + `<hh:paraProperties itemCnt="${ctx.paraPrs.length}">${paraPrXml}</hh:paraProperties>` + stylesXml2 + `</hh:refList><hh:compatibleDocument targetProgram="MS_WORD">
4789
- <hh:layoutCompatibility>
4790
- <hh:applyFontWeightToBold />
4791
- <hh:useInnerUnderline />
4792
- <hh:useLowercaseStrikeout />
4793
- <hh:extendLineheightToOffset />
4794
- <hh:treatQuotationAsLatin />
4795
- <hh:doNotAlignWhitespaceOnRight />
4796
- <hh:doNotAdjustWordInJustify />
4797
- <hh:baseCharUnitOnEAsian />
4798
- <hh:baseCharUnitOfIndentOnFirstChar />
4799
- <hh:adjustLineheightToFont />
4800
- <hh:adjustBaselineInFixedLinespacing />
4801
- <hh:applyPrevspacingBeneathObject />
4802
- <hh:applyNextspacingOfLastPara />
4803
- <hh:adjustParaBorderfillToSpacing />
4804
- <hh:connectParaBorderfillOfEqualBorder />
4805
- <hh:adjustParaBorderOffsetWithBorder />
4806
- <hh:extendLineheightToParaBorderOffset />
4807
- <hh:applyParaBorderToOutside />
4808
- <hh:applyMinColumnWidthTo1mm />
4809
- <hh:applyTabPosBasedOnSegment />
4810
- <hh:breakTabOverLine />
4811
- <hh:adjustVertPosOfLine />
4812
- <hh:doNotAlignLastForbidden />
4813
- <hh:adjustMarginFromAdjustLineheight />
4814
- <hh:baseLineSpacingOnLineGrid />
4815
- <hh:applyCharSpacingToCharGrid />
4816
- <hh:doNotApplyGridInHeaderFooter />
4817
- <hh:applyExtendHeaderFooterEachSection />
4818
- <hh:doNotApplyLinegridAtNoLinespacing />
4819
- <hh:doNotAdjustEmptyAnchorLine />
4820
- <hh:overlapBothAllowOverlap />
4821
- <hh:extendVertLimitToPageMargins />
4822
- <hh:doNotHoldAnchorOfTable />
4823
- <hh:doNotFormattingAtBeneathAnchor />
4824
- <hh:adjustBaselineOfObjectToBottom />
4825
- </hh:layoutCompatibility>
4826
- </hh:compatibleDocument><hh:docOption><hh:linkinfo path="" pageInherit="0" footnoteInherit="0"/></hh:docOption><hh:trackchageConfig flags="56"/></hh:head>`;
4944
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hh:head ${NS} version="1.2" secCnt="1"><hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/><hh:refList>` + fontFacesXml + borderFillXml + `<hh:charProperties itemCnt="${ctx.charPrs.length}">${charPrXml}</hh:charProperties><hh:tabProperties itemCnt="1"><hh:tabPr id="0" autoTabLeft="0" autoTabRight="0"/></hh:tabProperties>` + buildNumberingsXml() + buildBulletsXml() + `<hh:paraProperties itemCnt="${ctx.paraPrs.length}">${paraPrXml}</hh:paraProperties>` + stylesXml2 + `</hh:refList>` + buildHeaderSecPrListXml(dims) + `<hh:compatibleDocument targetProgram="HWP201X"><hh:layoutCompatibility/></hh:compatibleDocument><hh:docOption><hh:linkinfo path="" pageInherit="0" footnoteInherit="0"/></hh:docOption><hh:trackchageConfig flags="56"/></hh:head>`;
4827
4945
  }
4828
4946
  function buildHeaderFooterRunXml(sheet, dims, ctx) {
4829
4947
  const headers = sheet.headers || {};
@@ -4833,12 +4951,13 @@ function buildHeaderFooterRunXml(sheet, dims, ctx) {
4833
4951
  const availW = ctx.availableWidth;
4834
4952
  const mtHwp = Metric.ptToHwp(dims.mt);
4835
4953
  const mbHwp = Metric.ptToHwp(dims.mb);
4836
- const headerZoneH = dims.headerPt ? Math.max(100, mtHwp - Metric.ptToHwp(dims.headerPt)) : 3600;
4837
- const footerZoneH = dims.footerPt ? Math.max(100, mbHwp - Metric.ptToHwp(dims.footerPt)) : 3600;
4954
+ const headerZoneH = dims.headerPt ? Metric.ptToHwp(dims.headerPt) : 4252;
4955
+ const footerZoneH = dims.footerPt ? Metric.ptToHwp(dims.footerPt) : 4252;
4838
4956
  let inner = "";
4839
4957
  const hideFirst = !!(headers.first || footers.first);
4840
4958
  inner += `<hp:ctrl><hp:pageHiding hideHeader="${hideFirst ? 1 : 0}" hideFooter="${hideFirst ? 1 : 0}" hideMasterPage="0" hideBorder="0" hideFill="0" hidePageNum="0"/></hp:ctrl>`;
4841
4959
  for (const [type, paras] of Object.entries(headers)) {
4960
+ if (!Array.isArray(paras) || paras.length === 0) continue;
4842
4961
  const applyPageType = type === "even" ? "EVEN" : type === "default" || type === "first" ? "BOTH" : "ODD";
4843
4962
  const savedId = ctx.nextElementId;
4844
4963
  ctx.nextElementId = 0;
@@ -4847,6 +4966,7 @@ function buildHeaderFooterRunXml(sheet, dims, ctx) {
4847
4966
  inner += `<hp:ctrl><hp:header id="1" applyPageType="${applyPageType}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="TOP" linkListIDRef="0" linkListNextIDRef="0" textWidth="${availW}" textHeight="${headerZoneH}" hasTextRef="0" hasNumRef="0">` + parasXml + `</hp:subList></hp:header></hp:ctrl>`;
4848
4967
  }
4849
4968
  for (const [type, paras] of Object.entries(footers)) {
4969
+ if (!Array.isArray(paras) || paras.length === 0) continue;
4850
4970
  const applyPageType = type === "even" ? "EVEN" : type === "default" || type === "first" ? "BOTH" : "ODD";
4851
4971
  const savedId = ctx.nextElementId;
4852
4972
  ctx.nextElementId = 0;
@@ -4870,10 +4990,10 @@ function buildSectionXml(sheet, dims, ctx) {
4870
4990
  for (let i = 0; i < kids.length; i++) {
4871
4991
  const kid = kids[i];
4872
4992
  const isFirst = i === 0;
4873
- const curSecPr = isFirst ? secPrXml : "";
4993
+ const curSecPr = "";
4874
4994
  const curHfRun = isFirst ? hfRunXml : "";
4875
4995
  if (kid.tag === "para") {
4876
- const { xml, nextVertPos } = encodeParaPositioned(
4996
+ const { xml, nextVertPos, hasPageBreak } = encodeParaPositioned(
4877
4997
  kid,
4878
4998
  ctx,
4879
4999
  vertPos,
@@ -4884,7 +5004,7 @@ function buildSectionXml(sheet, dims, ctx) {
4884
5004
  contentXml += xml;
4885
5005
  vertPos = nextVertPos;
4886
5006
  } else if (kid.tag === "grid") {
4887
- const { xml, nextVertPos } = encodeGridPositioned(
5007
+ const { xml, nextVertPos, hasPageBreak } = encodeGridPositioned(
4888
5008
  kid,
4889
5009
  ctx,
4890
5010
  vertPos,
@@ -4899,9 +5019,9 @@ function buildSectionXml(sheet, dims, ctx) {
4899
5019
  const fs = 1e3;
4900
5020
  const vs = 1600;
4901
5021
  const { xml: linesegXml } = buildLinesegarray(" ", 0, fs, vs / (fs / 100), availWidth);
4902
- contentXml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0" paraTcId="0">` + secPrXml + hfRunXml + `<hp:run charPrIDRef="0" charTcId="0"><hp:t xml:space="preserve"> </hp:t></hp:run>` + linesegXml + `</hp:p>`;
5022
+ contentXml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0" paraTcId="0">` + hfRunXml + `<hp:run charPrIDRef="0" charTcId="0"><hp:t xml:space="preserve"> </hp:t></hp:run>` + linesegXml + `</hp:p>`;
4903
5023
  }
4904
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hs:sec ${NS} xmlns:hwpunitchar="http://www.hancom.co.kr/hwpml/2016/HwpUnitChar">${contentXml}</hs:sec>`;
5024
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hs:sec ${NS} xmlns:hwpunitchar="http://www.hancom.co.kr/hwpml/2016/HwpUnitChar">${secPrXml}${contentXml}</hs:sec>`;
4905
5025
  }
4906
5026
  function buildSecPrXml(dims) {
4907
5027
  const wHwp = Metric.ptToHwp(dims.wPt);
@@ -4910,24 +5030,62 @@ function buildSecPrXml(dims) {
4910
5030
  const mr = Metric.ptToHwp(dims.mr);
4911
5031
  const mt = Metric.ptToHwp(dims.mt);
4912
5032
  const mb = Metric.ptToHwp(dims.mb);
4913
- const headerZone = dims.headerPt ? Math.max(0, mt - Metric.ptToHwp(dims.headerPt)) : 0;
4914
- const footerZone = dims.footerPt ? Math.max(0, mb - Metric.ptToHwp(dims.footerPt)) : 0;
5033
+ const headerZone = dims.headerPt ? Metric.ptToHwp(dims.headerPt) : 0;
5034
+ const footerZone = dims.footerPt ? Metric.ptToHwp(dims.footerPt) : 0;
4915
5035
  const pageBorderFill = `<hp:pageBorderFill type="BOTH" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hp:offset left="1417" right="1417" top="1417" bottom="1417"/></hp:pageBorderFill><hp:pageBorderFill type="EVEN" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hp:offset left="1417" right="1417" top="1417" bottom="1417"/></hp:pageBorderFill><hp:pageBorderFill type="ODD" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hp:offset left="1417" right="1417" top="1417" bottom="1417"/></hp:pageBorderFill>`;
4916
- return `<hp:secPr id="0" textDirection="HORIZONTAL" spaceColumns="1134" tabStop="8000" outlineShapeIDRef="0" memoShapeIDRef="0" textVerticalWidthHead="0" masterPageCnt="0"><hp:grid lineGrid="0" charGrid="0" wonggojiFormat="0"/><hp:startNum pageStartsOn="BOTH" page="0" pic="0" tbl="0" equation="0"/><hp:visibility hideFirstHeader="0" hideFirstFooter="0" hideFirstMasterPage="0" border="SHOW_ALL" fill="SHOW_ALL" hideFirstPageNum="0" hideFirstEmptyLine="0" showLineNumber="0"/><hp:lineNumberShape restartType="0" countBy="0" distance="0" startNumber="0"/><hp:pagePr landscape="${dims.wPt >= dims.hPt ? "WIDELY" : "NARROWLY"}" width="${wHwp}" height="${hHwp}" gutterType="LEFT_ONLY"><hp:margin header="${headerZone}" footer="${footerZone}" gutter="0" left="${ml}" right="${mr}" top="${mt}" bottom="${mb}"/></hp:pagePr><hp:colPr id="" type="NEWSPAPER" layout="LEFT" colCount="1" sameSz="1" sameGap="0"/><hp:footNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar="" supscript="1"/><hp:noteLine length="-1" type="SOLID" width="0.25 mm" color="#000000"/><hp:noteSpacing betweenNotes="283" belowLine="0" aboveLine="1000"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="EACH_COLUMN" beneathText="0"/></hp:footNotePr><hp:endNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar="" supscript="1"/><hp:noteLine length="-1" type="SOLID" width="0.25 mm" color="#000000"/><hp:noteSpacing betweenNotes="0" belowLine="0" aboveLine="1000"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="END_OF_DOCUMENT" beneathText="0"/></hp:endNotePr>` + pageBorderFill + `</hp:secPr>`;
5036
+ return `<hp:secPr id="0" textDirection="HORIZONTAL" spaceColumns="1134" tabStop="8000" outlineShapeIDRef="0" memoShapeIDRef="0" textVerticalWidthHead="0" masterPageCnt="0"><hp:grid lineGrid="0" charGrid="0" wonggojiFormat="0"/><hp:startNum pageStartsOn="BOTH" page="0" pic="0" tbl="0" equation="0"/><hp:visibility hideFirstHeader="0" hideFirstFooter="0" hideFirstMasterPage="0" border="SHOW_ALL" fill="SHOW_ALL" hideFirstPageNum="0" hideFirstEmptyLine="0" showLineNumber="0"/><hp:lineNumberShape restartType="0" countBy="0" distance="0" startNumber="0"/><hp:pagePr landscape="WIDELY" width="${wHwp}" height="${hHwp}" gutterType="LEFT_ONLY"><hp:margin header="${headerZone}" footer="${footerZone}" gutter="0" left="${ml}" right="${mr}" top="${mt}" bottom="${mb}"/></hp:pagePr><hp:colPr id="" type="NEWSPAPER" layout="LEFT" colCount="1" sameSz="1" sameGap="0"/><hp:footNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar="" supscript="1"/><hp:noteLine length="-1" type="SOLID" width="0.25 mm" color="#000000"/><hp:noteSpacing betweenNotes="283" belowLine="0" aboveLine="1000"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="EACH_COLUMN" beneathText="0"/></hp:footNotePr><hp:endNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar="" supscript="1"/><hp:noteLine length="-1" type="SOLID" width="0.25 mm" color="#000000"/><hp:noteSpacing betweenNotes="0" belowLine="0" aboveLine="1000"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="END_OF_DOCUMENT" beneathText="0"/></hp:endNotePr>` + pageBorderFill + `</hp:secPr>`;
4917
5037
  }
4918
5038
  function buildLinesegarray(text, vertPosStart, fontSize, lineSpacingPct, horzSize) {
4919
5039
  const vertsizeLine = Math.round(fontSize * lineSpacingPct / 100);
4920
5040
  const spacing = vertsizeLine - fontSize;
4921
5041
  const baseline = Math.round(fontSize * 0.83);
4922
- const isKorean = /[\uAC00-\uD7A3\u3131-\u318E]/.test(text);
4923
- const charW = isKorean ? fontSize : Math.round(fontSize * 0.47);
4924
- const charsPerLine = Math.max(1, Math.floor(horzSize / charW));
4925
- const lineCount = text.length === 0 ? 1 : Math.ceil(text.length / charsPerLine);
5042
+ if (text.length === 0) {
5043
+ const xml = `<hp:linesegarray><hp:lineseg textpos="0" vertpos="${vertPosStart}" vertsize="${vertsizeLine}" textheight="${fontSize}" baseline="${baseline}" spacing="${spacing}" horzpos="0" horzsize="${horzSize}" flags="${LINESEG_FLAGS_FIRST}"/></hp:linesegarray>`;
5044
+ return { xml, totalHeight: vertsizeLine };
5045
+ }
5046
+ const lines = [];
5047
+ let currentLineWidth = 0;
5048
+ let lineStartIdx = 0;
5049
+ for (let i = 0; i < text.length; i++) {
5050
+ const charCode = text.charCodeAt(i);
5051
+ if (charCode === 10 || charCode === 13) {
5052
+ lines.push({ startPos: lineStartIdx, width: currentLineWidth });
5053
+ lineStartIdx = i + 1;
5054
+ currentLineWidth = 0;
5055
+ continue;
5056
+ }
5057
+ let charW = fontSize * 0.55;
5058
+ if (charCode >= 44032 && charCode <= 55203) {
5059
+ charW = fontSize;
5060
+ } else if (charCode >= 12592 && charCode <= 12687) {
5061
+ charW = fontSize;
5062
+ } else if (charCode >= 19968 && charCode <= 40959) {
5063
+ charW = fontSize;
5064
+ } else if (charCode >= 65 && charCode <= 90) {
5065
+ charW = fontSize * 0.65;
5066
+ } else if (charCode === 32) {
5067
+ charW = fontSize * 0.32;
5068
+ } else if (charCode > 255) {
5069
+ charW = fontSize;
5070
+ } else {
5071
+ charW = fontSize * 0.42;
5072
+ }
5073
+ if (currentLineWidth + charW > horzSize && i > lineStartIdx) {
5074
+ lines.push({ startPos: lineStartIdx, width: currentLineWidth });
5075
+ lineStartIdx = i;
5076
+ currentLineWidth = charW;
5077
+ } else {
5078
+ currentLineWidth += charW;
5079
+ }
5080
+ }
5081
+ lines.push({ startPos: lineStartIdx, width: currentLineWidth });
5082
+ const lineCount = lines.length;
4926
5083
  const linesegParts = [];
4927
5084
  for (let i = 0; i < lineCount; i++) {
4928
5085
  const flags = i === 0 ? LINESEG_FLAGS_FIRST : LINESEG_FLAGS_OTHER;
5086
+ const textpos = lines[i].startPos;
4929
5087
  linesegParts.push(
4930
- `<hp:lineseg textpos="${i * charsPerLine}" vertpos="${vertPosStart + i * vertsizeLine}" vertsize="${vertsizeLine}" textheight="${fontSize}" baseline="${baseline}" spacing="${spacing}" horzpos="0" horzsize="${horzSize}" flags="${flags}"/>`
5088
+ `<hp:lineseg textpos="${textpos}" vertpos="${vertPosStart + i * vertsizeLine}" vertsize="${vertsizeLine}" textheight="${fontSize}" baseline="${baseline}" spacing="${spacing}" horzpos="0" horzsize="${horzSize}" flags="${flags}"/>`
4931
5089
  );
4932
5090
  }
4933
5091
  return {
@@ -4940,7 +5098,13 @@ function extractParaText(para) {
4940
5098
  const walk = (kids) => {
4941
5099
  for (const k of kids) {
4942
5100
  if (k.tag === "span") {
4943
- for (const c of k.kids) if (c.tag === "txt") text += c.content;
5101
+ for (const c of k.kids) {
5102
+ if (c.tag === "txt") {
5103
+ text += c.content;
5104
+ } else if (c.tag === "br") {
5105
+ text += "\n";
5106
+ }
5107
+ }
4944
5108
  } else if (k.tag === "link") {
4945
5109
  walk(k.kids);
4946
5110
  }
@@ -4999,7 +5163,7 @@ function encodeParaPositioned(para, ctx, vertPos, secPr = "", availWidth, hfRun
4999
5163
  (k) => k.tag === "span" && k.kids.some((c) => c.tag === "pb")
5000
5164
  );
5001
5165
  const xml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="${paraPrId}" styleIDRef="${styleIDRef}" pageBreak="${hasPageBreak ? 1 : 0}" columnBreak="0" merged="0" paraTcId="0">` + secPr + hfRun + runsXml + linesegXml + `</hp:p>`;
5002
- return { xml, nextVertPos: vertPos + totalHeight };
5166
+ return { xml, nextVertPos: vertPos + totalHeight, hasPageBreak };
5003
5167
  }
5004
5168
  function encodeTablePara(para, grid, ctx, vertPos, secPr, hfRun) {
5005
5169
  const paraPrId = ctx.paraPrMap.get(paraPrKey(para.props)) ?? 0;
@@ -5009,8 +5173,12 @@ function encodeTablePara(para, grid, ctx, vertPos, secPr, hfRun) {
5009
5173
  const baseline = 850;
5010
5174
  const spacing = Math.max(0, totalHeight - fontSize);
5011
5175
  const linesegXml = `<hp:linesegarray><hp:lineseg textpos="0" vertpos="${vertPos}" vertsize="${totalHeight}" textheight="${fontSize}" baseline="${baseline}" spacing="${spacing}" horzpos="0" horzsize="${ctx.availableWidth}" flags="1441792"/></hp:linesegarray>`;
5012
- const xml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="${paraPrId}" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0" paraTcId="0">` + secPr + gridXml + hfRun + linesegXml + `</hp:p>`;
5013
- return { xml, nextVertPos: vertPos + totalHeight };
5176
+ const hasPageBreak = para.kids.some(
5177
+ (k) => k.tag === "span" && k.kids.some((c) => c.tag === "pb")
5178
+ );
5179
+ const runId = ctx.nextElementId++;
5180
+ const xml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="${paraPrId}" styleIDRef="0" pageBreak="${hasPageBreak ? 1 : 0}" columnBreak="0" merged="0" paraTcId="0">` + secPr + `<hp:run id="${runId}" charPrIDRef="0" charTcId="0">` + gridXml + `</hp:run>` + hfRun + linesegXml + `</hp:p>`;
5181
+ return { xml, nextVertPos: vertPos + totalHeight, hasPageBreak };
5014
5182
  }
5015
5183
  function encodeCodeBlockPositioned(para, ctx, vertPos, secPr, fontSize, spacing, vertSize) {
5016
5184
  const codeBfId = ctx.borderFillBank.addUniform(
@@ -5031,7 +5199,7 @@ function encodeCodeBlockPositioned(para, ctx, vertPos, secPr, fontSize, spacing,
5031
5199
  ctx.availableWidth
5032
5200
  );
5033
5201
  const xml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="0" styleIDRef="0" paraTcId="0">` + secPr + `<hp:run charPrIDRef="0" charTcId="0"><hp:tbl id="${ctx.nextElementId++}" zOrder="0" numberingType="TABLE" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" pageBreak="NONE" rowCnt="1" colCnt="1" cellSpacing="0" borderFillIDRef="${codeBfId}" noAdjust="0"><hp:sz width="${cellW}" widthRelTo="ABSOLUTE" height="0" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="1" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="138" right="138" top="138" bottom="138"/><hp:inMargin left="138" right="138" top="138" bottom="138"/><hp:tr><hp:tc name="" header="0" hasMargin="1" protect="0" editable="0" dirty="0" borderFillIDRef="${codeBfId}"><hp:subList id="${subListId}" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="CENTER" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">` + innerXml + `</hp:subList><hp:cellAddr colAddr="0" rowAddr="0"/><hp:cellSpan colSpan="1" rowSpan="1"/><hp:cellSz width="${cellW}" height="0"/><hp:cellMargin left="283" right="283" top="141" bottom="141"/></hp:tc></hp:tr></hp:tbl><hp:t xml:space="preserve"> </hp:t></hp:run>` + linesegXml + `</hp:p>`;
5034
- return { xml, nextVertPos: vertPos + totalHeight };
5202
+ return { xml, nextVertPos: vertPos + totalHeight, hasPageBreak: false };
5035
5203
  }
5036
5204
  function encodeParaKids(kids, ctx) {
5037
5205
  let xml = "";
@@ -5080,8 +5248,7 @@ function encodeRunInner(span) {
5080
5248
  const content = esc(kid.content);
5081
5249
  if (content) xml += `<hp:t xml:space="preserve">${content}</hp:t>`;
5082
5250
  } else if (kid.tag === "br") {
5083
- xml += `<hp:t xml:space="preserve">
5084
- </hp:t>`;
5251
+ xml += `<hp:br/>`;
5085
5252
  } else if (kid.tag === "pagenum") {
5086
5253
  const fmt = kid.format === "roman" ? "ROMAN_LOWER" : kid.format === "romanCaps" ? "ROMAN_UPPER" : "DIGIT";
5087
5254
  xml += `<hp:pageNum pageStartsOn="BOTH" formatType="${fmt}"/>`;
@@ -5162,8 +5329,9 @@ function encodeGridPositioned(grid, ctx, vertPos, secPr = "", hfRun = "") {
5162
5329
  const baseline = Math.round(fontSize * 0.83);
5163
5330
  const spacing = Math.max(0, totalHeight - fontSize);
5164
5331
  const linesegXml = `<hp:linesegarray><hp:lineseg textpos="0" vertpos="${vertPos}" vertsize="${totalHeight}" textheight="${fontSize}" baseline="${baseline}" spacing="${spacing}" horzpos="0" horzsize="${ctx.availableWidth}" flags="${LINESEG_FLAGS_FIRST}"/></hp:linesegarray>`;
5165
- const xml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0" paraTcId="0">` + secPr + hfRun + gridXml + linesegXml + `</hp:p>`;
5166
- return { xml, nextVertPos: vertPos + totalHeight };
5332
+ const runId = ctx.nextElementId++;
5333
+ const xml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0" paraTcId="0">` + secPr + hfRun + `<hp:run id="${runId}" charPrIDRef="0" charTcId="0">` + gridXml + `</hp:run>` + linesegXml + `</hp:p>`;
5334
+ return { xml, nextVertPos: vertPos + totalHeight, hasPageBreak: false };
5167
5335
  }
5168
5336
  function buildGridXml(grid, ctx) {
5169
5337
  const rowCount = grid.kids.length;
@@ -5551,6 +5719,40 @@ function stylesXml() {
5551
5719
  </w:pPr></w:pPrDefault>
5552
5720
  </w:docDefaults>
5553
5721
  <w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/></w:style>
5722
+ <w:style w:type="paragraph" w:styleId="0"><w:name w:val="\uBC14\uD0D5\uAE00"/><w:basedOn w:val="Normal"/></w:style>
5723
+ <w:style w:type="paragraph" w:styleId="1"><w:name w:val="\uBCF8\uBB38"/><w:basedOn w:val="Normal"/></w:style>
5724
+ <w:style w:type="paragraph" w:styleId="2"><w:name w:val="\uAC1C\uC694 1"/><w:basedOn w:val="Normal"/></w:style>
5725
+ <w:style w:type="paragraph" w:styleId="3"><w:name w:val="\uAC1C\uC694 2"/><w:basedOn w:val="Normal"/></w:style>
5726
+ <w:style w:type="paragraph" w:styleId="4"><w:name w:val="\uAC1C\uC694 3"/><w:basedOn w:val="Normal"/></w:style>
5727
+ <w:style w:type="paragraph" w:styleId="5"><w:name w:val="\uAC1C\uC694 4"/><w:basedOn w:val="Normal"/></w:style>
5728
+ <w:style w:type="paragraph" w:styleId="6"><w:name w:val="\uAC1C\uC694 5"/><w:basedOn w:val="Normal"/></w:style>
5729
+ <w:style w:type="paragraph" w:styleId="7"><w:name w:val="\uAC1C\uC694 6"/><w:basedOn w:val="Normal"/></w:style>
5730
+ <w:style w:type="paragraph" w:styleId="8"><w:name w:val="\uAC1C\uC694 7"/><w:basedOn w:val="Normal"/></w:style>
5731
+ <w:style w:type="paragraph" w:styleId="9"><w:name w:val="\uAC1C\uC694 8"/><w:basedOn w:val="Normal"/></w:style>
5732
+ <w:style w:type="paragraph" w:styleId="10"><w:name w:val="\uAC1C\uC694 9"/><w:basedOn w:val="Normal"/></w:style>
5733
+ <w:style w:type="paragraph" w:styleId="11"><w:name w:val="\uAC1C\uC694 10"/><w:basedOn w:val="Normal"/></w:style>
5734
+ <w:style w:type="paragraph" w:styleId="12"><w:name w:val="\uCABD \uBC88\uD638"/><w:basedOn w:val="Normal"/></w:style>
5735
+ <w:style w:type="paragraph" w:styleId="13"><w:name w:val="\uBA38\uB9AC\uB9D0"/><w:basedOn w:val="Normal"/></w:style>
5736
+ <w:style w:type="paragraph" w:styleId="14"><w:name w:val="\uAC01\uC8FC"/><w:basedOn w:val="Normal"/></w:style>
5737
+ <w:style w:type="paragraph" w:styleId="15"><w:name w:val="\uBBF8\uC8FC"/><w:basedOn w:val="Normal"/></w:style>
5738
+ <w:style w:type="paragraph" w:styleId="16"><w:name w:val="\uBA54\uBAA8"/><w:basedOn w:val="Normal"/></w:style>
5739
+ <w:style w:type="paragraph" w:styleId="17"><w:name w:val="\uCC28\uB840 \uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5740
+ <w:style w:type="paragraph" w:styleId="18"><w:name w:val="\uCC28\uB840 1"/><w:basedOn w:val="Normal"/></w:style>
5741
+ <w:style w:type="paragraph" w:styleId="19"><w:name w:val="\uCC28\uB840 2"/><w:basedOn w:val="Normal"/></w:style>
5742
+ <w:style w:type="paragraph" w:styleId="20"><w:name w:val="\uCC28\uB840 3"/><w:basedOn w:val="Normal"/></w:style>
5743
+ <w:style w:type="paragraph" w:styleId="21"><w:name w:val="\uBCF8\uBB38 \uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5744
+ <w:style w:type="paragraph" w:styleId="22"><w:name w:val="\uADF8\uB9BC"/><w:basedOn w:val="Normal"/></w:style>
5745
+ <w:style w:type="paragraph" w:styleId="23"><w:name w:val="\uD45C"/><w:basedOn w:val="Normal"/></w:style>
5746
+ <w:style w:type="paragraph" w:styleId="24"><w:name w:val="\uC218\uC2DD"/><w:basedOn w:val="Normal"/></w:style>
5747
+ <w:style w:type="paragraph" w:styleId="25"><w:name w:val="\uC778\uC6A9\uBB38"/><w:basedOn w:val="Normal"/></w:style>
5748
+ <w:style w:type="paragraph" w:styleId="26"><w:name w:val="\uB0A0\uC9DC"/><w:basedOn w:val="Normal"/></w:style>
5749
+ <w:style w:type="paragraph" w:styleId="27"><w:name w:val="\uBC1C\uC2E0\uBA85\uC758"/><w:basedOn w:val="Normal"/></w:style>
5750
+ <w:style w:type="paragraph" w:styleId="28"><w:name w:val="\uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5751
+ <w:style w:type="paragraph" w:styleId="29"><w:name w:val="\uBD80\uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5752
+ <w:style w:type="paragraph" w:styleId="30"><w:name w:val="\uBB38\uB2E8 \uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5753
+ <w:style w:type="paragraph" w:styleId="31"><w:name w:val="MEMO"/><w:basedOn w:val="Normal"/></w:style>
5754
+ <w:style w:type="paragraph" w:styleId="32"><w:name w:val="\uAC1C\uC694"/><w:basedOn w:val="Normal"/></w:style>
5755
+ <w:style w:type="paragraph" w:styleId="33"><w:name w:val="\uD45C \uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5554
5756
  <w:style w:type="paragraph" w:styleId="Heading1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:pPr><w:keepNext/><w:outlineLvl w:val="0"/></w:pPr><w:rPr><w:b/><w:sz w:val="44"/><w:szCs w:val="44"/></w:rPr></w:style>
5555
5757
  <w:style w:type="paragraph" w:styleId="Heading2"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:pPr><w:keepNext/><w:outlineLvl w:val="1"/></w:pPr><w:rPr><w:b/><w:sz w:val="36"/><w:szCs w:val="36"/></w:rPr></w:style>
5556
5758
  <w:style w:type="paragraph" w:styleId="Heading3"><w:name w:val="heading 3"/><w:basedOn w:val="Normal"/><w:pPr><w:keepNext/><w:outlineLvl w:val="2"/></w:pPr><w:rPr><w:b/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr></w:style>
@@ -5640,7 +5842,12 @@ function encodeContent(node, ctx, dims) {
5640
5842
  }
5641
5843
  function encodeParaInner(para, ctx) {
5642
5844
  const align = para.props.align ?? "left";
5643
- const headStyle = para.props.heading ? `<w:pStyle w:val="Heading${para.props.heading}"/>` : "";
5845
+ let headStyle = "";
5846
+ if (para.props.hwpStyleId !== void 0) {
5847
+ headStyle = `<w:pStyle w:val="${para.props.hwpStyleId}"/>`;
5848
+ } else if (para.props.heading) {
5849
+ headStyle = `<w:pStyle w:val="Heading${para.props.heading}"/>`;
5850
+ }
5644
5851
  let numPr = "";
5645
5852
  if (para.props.listOrd !== void 0) {
5646
5853
  const numId = para.props.listOrd ? 2 : 1;
@@ -5679,6 +5886,10 @@ function encodeParaInner(para, ctx) {
5679
5886
  const runs = para.kids.map((k) => {
5680
5887
  if (k.tag === "span") return encodeRun(k, ctx);
5681
5888
  if (k.tag === "img") return encodeImage2(k, ctx);
5889
+ if (k.tag === "pagenum") {
5890
+ const instr = k.format === "total" ? " NUMPAGES " : " PAGE ";
5891
+ return `<w:r><w:fldChar w:fldCharType="begin"/></w:r><w:r><w:instrText>${instr}</w:instrText></w:r><w:r><w:fldChar w:fldCharType="separate"/></w:r><w:r><w:t>1</w:t></w:r><w:r><w:fldChar w:fldCharType="end"/></w:r>`;
5892
+ }
5682
5893
  return "";
5683
5894
  }).join("");
5684
5895
  return ` <w:p>
@@ -5715,8 +5926,9 @@ function encodeRun(span, _ctx) {
5715
5926
  );
5716
5927
  }
5717
5928
  } else if (kid.tag === "pagenum") {
5929
+ const instr = kid.format === "total" ? " NUMPAGES " : " PAGE ";
5718
5930
  parts.push(
5719
- `<w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="begin"/></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:instrText> PAGE </w:instrText></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="separate"/></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:t>1</w:t></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="end"/></w:r>`
5931
+ `<w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="begin"/></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:instrText>${instr}</w:instrText></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="separate"/></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:t>1</w:t></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="end"/></w:r>`
5720
5932
  );
5721
5933
  } else if (kid.tag === "br") {
5722
5934
  parts.push(`<w:r><w:br/></w:r>`);
@@ -6506,10 +6718,11 @@ var BufWriter = class {
6506
6718
  };
6507
6719
  function mkRec(tag, level, data) {
6508
6720
  const sz = data.length;
6509
- const enc = Math.min(sz, 4095);
6510
- const hdr = enc << 20 | (level & 1023) << 10 | tag & 1023;
6721
+ const isLarge = sz >= 4095;
6722
+ const enc = isLarge ? 4095 : sz;
6723
+ const hdr = ((enc & 4095) * 1048576 | (level & 1023) << 10 | tag & 1023) >>> 0;
6511
6724
  const w = new BufWriter().u32(hdr);
6512
- if (enc >= 4095) w.u32(sz);
6725
+ if (isLarge) w.u32(sz);
6513
6726
  w.bytes(data);
6514
6727
  return w.build();
6515
6728
  }
@@ -6824,7 +7037,7 @@ function buildDocInfoStream(bank, images = []) {
6824
7037
  return concatU8(chunks);
6825
7038
  }
6826
7039
  function mkPageDef(dims) {
6827
- return new BufWriter().u32(Metric.ptToHwp(dims.wPt)).u32(Metric.ptToHwp(dims.hPt)).u32(Metric.ptToHwp(dims.ml)).u32(Metric.ptToHwp(dims.mr)).u32(Metric.ptToHwp(dims.mt)).u32(Metric.ptToHwp(dims.mb)).zeros(12).u32(dims.orient === "landscape" ? 1 : 0).build();
7040
+ return new BufWriter().u32(Metric.ptToHwp(dims.wPt)).u32(Metric.ptToHwp(dims.hPt)).u32(Metric.ptToHwp(dims.ml)).u32(Metric.ptToHwp(dims.mr)).u32(Metric.ptToHwp(dims.mt)).u32(Metric.ptToHwp(dims.mb)).u32(dims.headerPt ? Metric.ptToHwp(dims.headerPt) : 0).u32(dims.footerPt ? Metric.ptToHwp(dims.footerPt) : 0).u32(0).u32(dims.orient === "landscape" ? 1 : 0).build();
6828
7041
  }
6829
7042
  function mkParaHeader(nchars, ctrlMask, psId, csCount, lineAlignCount = 0, instanceId = 0) {
6830
7043
  return new BufWriter().u32(nchars).u32(ctrlMask).u16(psId).u8(0).u8(0).u16(csCount).u16(0).u16(lineAlignCount).u32(instanceId).u16(0).build();
@@ -7025,7 +7238,7 @@ function encodePara3(para, bank, lv, instanceId, availWidthHwp, mask = 0, vertPo
7025
7238
  ];
7026
7239
  }
7027
7240
  function mkTableCtrl(wHwp, hHwp, instanceId, align = "left") {
7028
- const alignFlags = { left: 0, center: 1, right: 2, justify: 3 }[align] ?? 0;
7241
+ const alignFlags = { left: 0, center: 1, right: 2, justify: 3, distribute: 0, distribute_space: 0 }[align] ?? 0;
7029
7242
  return new BufWriter().u32(CTRL_TABLE2).u32(136978961).i32(0).i32(0).u32(wHwp).u32(hHwp).i32(7).u16(140).u16(140).u16(140).u16(140).u32(instanceId).i32(alignFlags).u16(0).build();
7030
7243
  }
7031
7244
  function mkTableRecord(rowCnt, colCnt, rowHwp, bfId) {
@@ -7116,7 +7329,7 @@ function encodeGrid4(grid, bank, lv, idGen, availWidthHwp) {
7116
7329
  const cellWidthHwp = Metric.ptToHwp(cwPt[c] ?? defColPt);
7117
7330
  for (const para of paras) {
7118
7331
  records.push(
7119
- ...encodePara3(para, bank, lv + 2, idGen(), cellWidthHwp)
7332
+ ...encodePara3(para, bank, lv + 1, idGen(), cellWidthHwp)
7120
7333
  );
7121
7334
  }
7122
7335
  }
@@ -7358,6 +7571,7 @@ function buildHwpFileHeader() {
7358
7571
  }
7359
7572
  function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = []) {
7360
7573
  const SS = 512;
7574
+ const MSS = 64;
7361
7575
  const ENDOFCHAIN = 4294967294;
7362
7576
  const FREESECT = 4294967295;
7363
7577
  const FATSECT = 4294967293;
@@ -7366,71 +7580,150 @@ function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = [])
7366
7580
  `FileHeader \uD06C\uAE30 \uBD80\uC871: ${fileHeaderData.length} (\uCD5C\uC18C 256)`
7367
7581
  );
7368
7582
  }
7369
- function padSector(d) {
7370
- const n = Math.ceil(Math.max(d.length, 1) / SS) * SS;
7371
- if (d.length === n) return d;
7583
+ const streams = [];
7584
+ streams.push({
7585
+ name: "FileHeader",
7586
+ data: fileHeaderData,
7587
+ dirIdx: 1,
7588
+ isMini: fileHeaderData.length < 4096
7589
+ });
7590
+ streams.push({
7591
+ name: "DocInfo",
7592
+ data: docInfoData,
7593
+ dirIdx: 2,
7594
+ isMini: docInfoData.length < 4096
7595
+ });
7596
+ streams.push({
7597
+ name: "Section0",
7598
+ data: section0Data,
7599
+ dirIdx: 4,
7600
+ isMini: section0Data.length < 4096
7601
+ });
7602
+ for (let i = 0; i < binImages.length; i++) {
7603
+ const img = binImages[i];
7604
+ const name = `BIN${String(img.id).padStart(4, "0")}.${img.ext}`;
7605
+ streams.push({
7606
+ name,
7607
+ data: img.data,
7608
+ dirIdx: 6 + i,
7609
+ isMini: img.data.length < 4096
7610
+ });
7611
+ }
7612
+ const miniStreams = streams.filter((s) => s.isMini);
7613
+ const miniSectorList = [];
7614
+ let miniStreamDataLength = 0;
7615
+ for (const s of miniStreams) {
7616
+ const startSec = miniStreamDataLength / MSS;
7617
+ s.startSec = startSec;
7618
+ const len = s.data.length;
7619
+ const numMiniSecs = Math.ceil(len / MSS);
7620
+ for (let i = 0; i < numMiniSecs; i++) {
7621
+ const curSec2 = startSec + i;
7622
+ const nextSec = i === numMiniSecs - 1 ? ENDOFCHAIN : curSec2 + 1;
7623
+ while (miniSectorList.length <= curSec2) {
7624
+ miniSectorList.push(FREESECT);
7625
+ }
7626
+ miniSectorList[curSec2] = nextSec;
7627
+ }
7628
+ miniStreamDataLength += numMiniSecs * MSS;
7629
+ }
7630
+ const miniStreamData = new Uint8Array(miniStreamDataLength);
7631
+ let miniStreamOffset = 0;
7632
+ for (const s of miniStreams) {
7633
+ miniStreamData.set(s.data, miniStreamOffset);
7634
+ miniStreamOffset += Math.ceil(s.data.length / MSS) * MSS;
7635
+ }
7636
+ const regularStreams = streams.filter((s) => !s.isMini);
7637
+ const regPads = regularStreams.map((s) => {
7638
+ const len = s.data.length;
7639
+ const n = Math.ceil(Math.max(len, 1) / SS) * SS;
7372
7640
  const out2 = new Uint8Array(n);
7373
- out2.set(d);
7641
+ out2.set(s.data);
7374
7642
  return out2;
7375
- }
7376
- const fhPad = padSector(fileHeaderData);
7377
- const diPad = padSector(docInfoData);
7378
- const s0Pad = padSector(section0Data);
7379
- const imgPads = binImages.map((img) => padSector(img.data));
7380
- const fhN = fhPad.length / SS;
7381
- const diN = diPad.length / SS;
7382
- const s0N = s0Pad.length / SS;
7383
- const imgNs = imgPads.map((p) => p.length / SS);
7384
- const totalImgN = imgNs.reduce((s, n) => s + n, 0);
7643
+ });
7644
+ const regNs = regPads.map((p) => p.length / SS);
7385
7645
  const numDirEntries = 5 + (binImages.length > 0 ? 1 + binImages.length : 0);
7386
- const dirN = Math.max(2, Math.ceil(numDirEntries / 4));
7646
+ const dirN = Math.max(1, Math.ceil(numDirEntries * 128 / SS));
7647
+ const miniFatN = Math.ceil(miniSectorList.length / 128);
7648
+ const miniStreamN = Math.ceil(miniStreamData.length / SS);
7649
+ const totalRegStreamN = regNs.reduce((a, b) => a + b, 0);
7650
+ const neededDataSec = dirN + miniFatN + miniStreamN + totalRegStreamN;
7387
7651
  let fatN = 1;
7388
7652
  for (let iter = 0; iter < 10; iter++) {
7389
- const total = fatN + dirN + fhN + diN + s0N + totalImgN;
7390
- const needed = Math.ceil(total / 128);
7391
- if (needed <= fatN) break;
7392
- fatN = needed;
7393
- }
7394
- const dir1Sec = fatN;
7395
- const fhSec = dir1Sec + dirN;
7396
- const diSec = fhSec + fhN;
7397
- const s0Sec = diSec + diN;
7398
- const imgSecs = [];
7399
- let curSec = s0Sec + s0N;
7400
- for (const n of imgNs) {
7401
- imgSecs.push(curSec);
7402
- curSec += n;
7403
- }
7404
- const totalSec = curSec;
7653
+ const totalSec2 = fatN + neededDataSec;
7654
+ const neededFat = Math.ceil(totalSec2 / 128);
7655
+ if (neededFat <= fatN) break;
7656
+ fatN = neededFat;
7657
+ }
7658
+ const totalSec = fatN + neededDataSec;
7659
+ const dirStartSec = fatN;
7660
+ const miniFatStartSec = dirStartSec + dirN;
7661
+ const miniStreamStartSec = miniFatStartSec + miniFatN;
7662
+ let curSec = miniStreamStartSec + miniStreamN;
7663
+ for (let i = 0; i < regularStreams.length; i++) {
7664
+ regularStreams[i].startSec = curSec;
7665
+ curSec += regNs[i];
7666
+ }
7405
7667
  const fatBuf = new Uint8Array(fatN * SS).fill(255);
7406
7668
  const setFat = (i, v) => {
7407
- fatBuf[i * 4] = v & 255;
7408
- fatBuf[i * 4 + 1] = v >>> 8 & 255;
7409
- fatBuf[i * 4 + 2] = v >>> 16 & 255;
7410
- fatBuf[i * 4 + 3] = v >>> 24 & 255;
7669
+ const off = i * 4;
7670
+ fatBuf[off] = v & 255;
7671
+ fatBuf[off + 1] = v >>> 8 & 255;
7672
+ fatBuf[off + 2] = v >>> 16 & 255;
7673
+ fatBuf[off + 3] = v >>> 24 & 255;
7411
7674
  };
7412
- for (let i = 0; i < fatN; i++) setFat(i, FATSECT);
7413
- for (let i = 0; i < dirN; i++)
7414
- setFat(dir1Sec + i, i + 1 < dirN ? dir1Sec + i + 1 : ENDOFCHAIN);
7415
- for (let i = 0; i < fhN; i++)
7416
- setFat(fhSec + i, i + 1 < fhN ? fhSec + i + 1 : ENDOFCHAIN);
7417
- for (let i = 0; i < diN; i++)
7418
- setFat(diSec + i, i + 1 < diN ? diSec + i + 1 : ENDOFCHAIN);
7419
- for (let i = 0; i < s0N; i++)
7420
- setFat(s0Sec + i, i + 1 < s0N ? s0Sec + i + 1 : ENDOFCHAIN);
7421
- for (let ii = 0; ii < imgNs.length; ii++) {
7422
- const start = imgSecs[ii];
7423
- const n = imgNs[ii];
7424
- for (let i = 0; i < n; i++)
7425
- setFat(start + i, i + 1 < n ? start + i + 1 : ENDOFCHAIN);
7675
+ for (let i = 0; i < fatN; i++) {
7676
+ setFat(i, FATSECT);
7677
+ }
7678
+ for (let i = 0; i < dirN; i++) {
7679
+ setFat(
7680
+ dirStartSec + i,
7681
+ i + 1 < dirN ? dirStartSec + i + 1 : ENDOFCHAIN
7682
+ );
7683
+ }
7684
+ if (miniFatN > 0) {
7685
+ for (let i = 0; i < miniFatN; i++) {
7686
+ setFat(
7687
+ miniFatStartSec + i,
7688
+ i + 1 < miniFatN ? miniFatStartSec + i + 1 : ENDOFCHAIN
7689
+ );
7690
+ }
7691
+ }
7692
+ if (miniStreamN > 0) {
7693
+ for (let i = 0; i < miniStreamN; i++) {
7694
+ setFat(
7695
+ miniStreamStartSec + i,
7696
+ i + 1 < miniStreamN ? miniStreamStartSec + i + 1 : ENDOFCHAIN
7697
+ );
7698
+ }
7699
+ }
7700
+ for (let i = 0; i < regularStreams.length; i++) {
7701
+ const s = regularStreams[i];
7702
+ const n = regNs[i];
7703
+ const start = s.startSec;
7704
+ for (let j = 0; j < n; j++) {
7705
+ setFat(start + j, j + 1 < n ? start + j + 1 : ENDOFCHAIN);
7706
+ }
7707
+ }
7708
+ const miniFatBuf = new Uint8Array(miniFatN * SS).fill(255);
7709
+ const setMiniFat = (i, v) => {
7710
+ const off = i * 4;
7711
+ miniFatBuf[off] = v & 255;
7712
+ miniFatBuf[off + 1] = v >>> 8 & 255;
7713
+ miniFatBuf[off + 2] = v >>> 16 & 255;
7714
+ miniFatBuf[off + 3] = v >>> 24 & 255;
7715
+ };
7716
+ for (let i = 0; i < miniSectorList.length; i++) {
7717
+ setMiniFat(i, miniSectorList[i]);
7426
7718
  }
7427
7719
  const dirBuf = new Uint8Array(dirN * SS);
7428
7720
  const dv = new DataView(dirBuf.buffer);
7429
7721
  function writeDirEntry(idx, name, type, left, right, child, startSec, size) {
7430
7722
  const base = idx * 128;
7431
7723
  const nl = name.length;
7432
- for (let i = 0; i < nl; i++)
7724
+ for (let i = 0; i < nl; i++) {
7433
7725
  dv.setUint16(base + i * 2, name.charCodeAt(i), true);
7726
+ }
7434
7727
  dv.setUint16(base + 64, (nl + 1) * 2, true);
7435
7728
  dirBuf[base + 66] = type;
7436
7729
  dirBuf[base + 67] = 1;
@@ -7446,35 +7739,20 @@ function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = [])
7446
7739
  dv.setInt32(base + 72, -1, true);
7447
7740
  dv.setInt32(base + 76, -1, true);
7448
7741
  }
7449
- if (binImages.length > 0) {
7450
- writeDirEntry(0, "Root Entry", 5, -1, -1, 1, ENDOFCHAIN, 0);
7451
- writeDirEntry(1, "FileHeader", 2, -1, 2, -1, fhSec, fileHeaderData.length);
7452
- writeDirEntry(2, "DocInfo", 2, -1, 3, -1, diSec, docInfoData.length);
7453
- writeDirEntry(3, "BodyText", 1, -1, 5, 4, ENDOFCHAIN, 0);
7454
- writeDirEntry(4, "Section0", 2, -1, -1, -1, s0Sec, section0Data.length);
7455
- writeDirEntry(5, "BinData", 1, -1, -1, 6, ENDOFCHAIN, 0);
7456
- for (let ii = 0; ii < binImages.length; ii++) {
7457
- const img = binImages[ii];
7458
- const streamName = `BIN${String(img.id).padStart(4, "0")}.${img.ext}`;
7459
- const sibling = ii + 1 < binImages.length ? 7 + ii : -1;
7460
- writeDirEntry(
7461
- 6 + ii,
7462
- streamName,
7463
- 2,
7464
- -1,
7465
- sibling,
7466
- -1,
7467
- imgSecs[ii],
7468
- img.data.length
7469
- );
7470
- }
7471
- } else {
7472
- writeDirEntry(0, "Root Entry", 5, -1, -1, 1, ENDOFCHAIN, 0);
7473
- writeDirEntry(1, "FileHeader", 2, -1, 2, -1, fhSec, fileHeaderData.length);
7474
- writeDirEntry(2, "DocInfo", 2, -1, 3, -1, diSec, docInfoData.length);
7475
- writeDirEntry(3, "BodyText", 1, -1, -1, 4, ENDOFCHAIN, 0);
7476
- writeDirEntry(4, "Section0", 2, -1, -1, -1, s0Sec, section0Data.length);
7742
+ const streamMap = /* @__PURE__ */ new Map();
7743
+ for (const s of streams) {
7744
+ streamMap.set(s.dirIdx, s);
7477
7745
  }
7746
+ writeDirEntry(
7747
+ 0,
7748
+ "Root Entry",
7749
+ 5,
7750
+ -1,
7751
+ -1,
7752
+ 3,
7753
+ miniStreamStartSec,
7754
+ miniStreamData.length
7755
+ );
7478
7756
  const HWP_CLSID = [
7479
7757
  32,
7480
7758
  233,
@@ -7493,7 +7771,61 @@ function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = [])
7493
7771
  155,
7494
7772
  113
7495
7773
  ];
7496
- for (let i = 0; i < 16; i++) dirBuf[80 + i] = HWP_CLSID[i];
7774
+ for (let i = 0; i < 16; i++) {
7775
+ dirBuf[0 * 128 + 80 + i] = HWP_CLSID[i];
7776
+ }
7777
+ const fhStream = streamMap.get(1);
7778
+ writeDirEntry(
7779
+ 1,
7780
+ "FileHeader",
7781
+ 2,
7782
+ -1,
7783
+ -1,
7784
+ -1,
7785
+ fhStream.startSec,
7786
+ fhStream.data.length
7787
+ );
7788
+ const diStream = streamMap.get(2);
7789
+ const docInfoLeft = binImages.length > 0 ? 5 : -1;
7790
+ writeDirEntry(
7791
+ 2,
7792
+ "DocInfo",
7793
+ 2,
7794
+ docInfoLeft,
7795
+ -1,
7796
+ -1,
7797
+ diStream.startSec,
7798
+ diStream.data.length
7799
+ );
7800
+ writeDirEntry(3, "BodyText", 1, 2, 1, 4, ENDOFCHAIN, 0);
7801
+ const s0Stream = streamMap.get(4);
7802
+ writeDirEntry(
7803
+ 4,
7804
+ "Section0",
7805
+ 2,
7806
+ -1,
7807
+ -1,
7808
+ -1,
7809
+ s0Stream.startSec,
7810
+ s0Stream.data.length
7811
+ );
7812
+ if (binImages.length > 0) {
7813
+ writeDirEntry(5, "BinData", 1, -1, -1, 6, ENDOFCHAIN, 0);
7814
+ for (let i = 0; i < binImages.length; i++) {
7815
+ const imgStream = streamMap.get(6 + i);
7816
+ const sibling = i + 1 < binImages.length ? 7 + i : -1;
7817
+ writeDirEntry(
7818
+ 6 + i,
7819
+ imgStream.name,
7820
+ 2,
7821
+ -1,
7822
+ sibling,
7823
+ -1,
7824
+ imgStream.startSec,
7825
+ imgStream.data.length
7826
+ );
7827
+ }
7828
+ }
7497
7829
  const hdr = new Uint8Array(SS);
7498
7830
  const hdv = new DataView(hdr.buffer);
7499
7831
  const MAGIC = [208, 207, 17, 224, 161, 177, 26, 225];
@@ -7502,32 +7834,43 @@ function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = [])
7502
7834
  });
7503
7835
  hdv.setUint16(24, 62, true);
7504
7836
  hdv.setUint16(26, 3, true);
7505
- hdv.setUint16(28, 254, true);
7837
+ hdv.setUint16(28, 65534, true);
7506
7838
  hdv.setUint16(30, 9, true);
7507
7839
  hdv.setUint16(32, 6, true);
7508
- hdv.setUint32(40, fatN, true);
7509
- hdv.setUint32(44, dir1Sec, true);
7510
- hdv.setUint32(48, 0, true);
7511
- hdv.setUint32(52, 4096, true);
7512
- hdv.setUint32(56, ENDOFCHAIN, true);
7513
- hdv.setUint32(60, 0, true);
7514
- hdv.setUint32(64, ENDOFCHAIN, true);
7515
- hdv.setUint32(68, 0, true);
7840
+ hdv.setUint32(40, 0, true);
7841
+ hdv.setUint32(44, fatN, true);
7842
+ hdv.setUint32(48, dirStartSec, true);
7843
+ hdv.setUint32(52, 0, true);
7844
+ hdv.setUint32(56, 4096, true);
7845
+ hdv.setUint32(60, miniFatN > 0 ? miniFatStartSec : ENDOFCHAIN, true);
7846
+ hdv.setUint32(64, miniFatN, true);
7847
+ hdv.setUint32(68, ENDOFCHAIN, true);
7516
7848
  hdv.setUint32(72, 0, true);
7517
7849
  for (let i = 0; i < 109; i++) {
7518
7850
  hdv.setUint32(76 + i * 4, i < fatN ? i : FREESECT, true);
7519
7851
  }
7520
7852
  const out = new Uint8Array(SS + totalSec * SS);
7521
- out.set(hdr, 0);
7522
- for (let i = 0; i < fatN; i++)
7523
- out.set(fatBuf.subarray(i * SS, (i + 1) * SS), SS + i * SS);
7524
- for (let i = 0; i < dirN; i++)
7525
- out.set(dirBuf.subarray(i * SS, (i + 1) * SS), SS + (dir1Sec + i) * SS);
7526
- out.set(fhPad, SS + fhSec * SS);
7527
- out.set(diPad, SS + diSec * SS);
7528
- out.set(s0Pad, SS + s0Sec * SS);
7529
- for (let ii = 0; ii < imgPads.length; ii++)
7530
- out.set(imgPads[ii], SS + imgSecs[ii] * SS);
7853
+ let outOff = 0;
7854
+ out.set(hdr, outOff);
7855
+ outOff += SS;
7856
+ out.set(fatBuf, outOff);
7857
+ outOff += fatN * SS;
7858
+ out.set(dirBuf, outOff);
7859
+ outOff += dirN * SS;
7860
+ if (miniFatN > 0) {
7861
+ out.set(miniFatBuf, outOff);
7862
+ outOff += miniFatN * SS;
7863
+ }
7864
+ if (miniStreamN > 0) {
7865
+ const miniStreamPad = new Uint8Array(miniStreamN * SS);
7866
+ miniStreamPad.set(miniStreamData);
7867
+ out.set(miniStreamPad, outOff);
7868
+ outOff += miniStreamN * SS;
7869
+ }
7870
+ for (let i = 0; i < regularStreams.length; i++) {
7871
+ out.set(regPads[i], outOff);
7872
+ outOff += regNs[i] * SS;
7873
+ }
7531
7874
  return out;
7532
7875
  }
7533
7876
  function concatU8(arrays) {