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.js CHANGED
@@ -1423,6 +1423,17 @@ function decodeGrid(tbl, ctx) {
1423
1423
  const headerRow = tblAttr.repeatHeader === "1";
1424
1424
  const gridProps = { headerRow: headerRow || void 0 };
1425
1425
  if (borderFill?.stroke) gridProps.defaultStroke = borderFill.stroke;
1426
+ const posAttr = tbl?.["hp:pos"]?.[0]?._attr ?? {};
1427
+ if (posAttr.horzAlign) {
1428
+ const alignMap = {
1429
+ LEFT: "left",
1430
+ RIGHT: "right",
1431
+ CENTER: "center",
1432
+ JUSTIFY: "justify"
1433
+ };
1434
+ const a = alignMap[posAttr.horzAlign];
1435
+ if (a) gridProps.align = a;
1436
+ }
1426
1437
  const rowArr = getTag(tbl, "hp:tr", "hp:ROW");
1427
1438
  for (const row of rowArr) {
1428
1439
  const cells = getTag(row, "hp:tc", "hp:CELL");
@@ -1505,16 +1516,15 @@ function decodeGrid(tbl, ctx) {
1505
1516
  };
1506
1517
  cellProps.va = vaMap[subAttr.vertAlign];
1507
1518
  }
1508
- const HWPX_DEFAULT_MARGIN_LR = 360;
1509
- const HWPX_DEFAULT_MARGIN_TB = 141;
1510
- const mL = Number(subAttr.marginLeft ?? HWPX_DEFAULT_MARGIN_LR);
1511
- const mR = Number(subAttr.marginRight ?? HWPX_DEFAULT_MARGIN_LR);
1512
- const mT = Number(subAttr.marginTop ?? HWPX_DEFAULT_MARGIN_TB);
1513
- const mB = Number(subAttr.marginBottom ?? HWPX_DEFAULT_MARGIN_TB);
1514
- if (mL !== HWPX_DEFAULT_MARGIN_LR) cellProps.padL = Metric.hwpToPt(mL);
1515
- if (mR !== HWPX_DEFAULT_MARGIN_LR) cellProps.padR = Metric.hwpToPt(mR);
1516
- if (mT !== HWPX_DEFAULT_MARGIN_TB) cellProps.padT = Metric.hwpToPt(mT);
1517
- if (mB !== HWPX_DEFAULT_MARGIN_TB) cellProps.padB = Metric.hwpToPt(mB);
1519
+ const cellMarginAttr = cell?.["hp:cellMargin"]?.[0]?._attr ?? {};
1520
+ const mL = cellMarginAttr.left !== void 0 ? Number(cellMarginAttr.left) : -1;
1521
+ const mR = cellMarginAttr.right !== void 0 ? Number(cellMarginAttr.right) : -1;
1522
+ const mT = cellMarginAttr.top !== void 0 ? Number(cellMarginAttr.top) : -1;
1523
+ const mB = cellMarginAttr.bottom !== void 0 ? Number(cellMarginAttr.bottom) : -1;
1524
+ if (mL >= 0) cellProps.padL = Metric.hwpToPt(mL);
1525
+ if (mR >= 0) cellProps.padR = Metric.hwpToPt(mR);
1526
+ if (mT >= 0) cellProps.padT = Metric.hwpToPt(mT);
1527
+ if (mB >= 0) cellProps.padB = Metric.hwpToPt(mB);
1518
1528
  const cellSpan = cell?.["hp:cellSpan"]?.[0]?._attr ?? {};
1519
1529
  const cs = Number(cellSpan.colSpan ?? ca.ColSpan ?? 1);
1520
1530
  const rs = Number(cellSpan.rowSpan ?? ca.RowSpan ?? 1);
@@ -1774,6 +1784,9 @@ var CTRL_IMAGE = 1768777504;
1774
1784
  var CTRL_OBJ = 1868720672;
1775
1785
  var CTRL_FIG = 1718183712;
1776
1786
  var CTRL_GSO = 1735618336;
1787
+ var CTRL_HEAD = 1751474532;
1788
+ var CTRL_FOOT = 1718579060;
1789
+ var CTRL_ATNO = 1635020399;
1777
1790
  function parseRecords(data) {
1778
1791
  const out = [];
1779
1792
  let off = 0;
@@ -1851,19 +1864,29 @@ function parseCharShape(d) {
1851
1864
  textColor: d.length >= 56 ? colorRef(d, 52) : "000000"
1852
1865
  };
1853
1866
  }
1854
- var ALIGN_TBL = { 0: "justify", 1: "left", 2: "right", 3: "center", 4: "justify" };
1867
+ var ALIGN_TBL = { 0: "justify", 1: "left", 2: "right", 3: "center", 4: "distribute", 5: "distribute_space" };
1855
1868
  function parseParaShape(d) {
1856
- if (d.length < 4) return { align: "left", spaceBefore: 0, spaceAfter: 0, lineSpacing: 160, leftMargin: 0, indent: 0 };
1869
+ if (d.length < 4) return { align: "left", spaceBefore: 0, spaceAfter: 0, lineSpacing: 160, lineSpacingType: 0, leftMargin: 0, rightMargin: 0, indent: 0 };
1857
1870
  const attr = BinaryKit.readU32LE(d, 0);
1871
+ const lineSpacingType = attr & 3;
1872
+ const align = ALIGN_TBL[attr >> 2 & 7] ?? "left";
1873
+ const vVal = attr >> 18 & 3;
1874
+ const verAlign = vVal === 1 ? "top" : vVal === 2 ? "center" : vVal === 3 ? "bottom" : "baseline";
1875
+ const lineWrap = "break";
1858
1876
  return {
1859
- align: ALIGN_TBL[attr >> 2 & 7] ?? "left",
1877
+ align,
1878
+ lineSpacingType,
1860
1879
  leftMargin: d.length >= 8 ? i32(d, 4) : 0,
1861
- // offset 4: leftMargin (들여쓰기)
1880
+ // offset 4: 문단 몸체 왼쪽 여백 (HWPUNIT)
1881
+ rightMargin: d.length >= 12 ? i32(d, 8) : 0,
1882
+ // offset 8: 문단 몸체 오른쪽 여백 (HWPUNIT)
1862
1883
  indent: d.length >= 16 ? i32(d, 12) : 0,
1863
- // offset 12: first-line indent
1884
+ // offset 12: 줄 들여쓰기 (HWPUNIT)
1864
1885
  spaceBefore: d.length >= 20 ? i32(d, 16) : 0,
1865
1886
  spaceAfter: d.length >= 24 ? i32(d, 20) : 0,
1866
- lineSpacing: d.length >= 28 ? i32(d, 24) : 160
1887
+ lineSpacing: d.length >= 28 ? i32(d, 24) : 160,
1888
+ verAlign,
1889
+ lineWrap
1867
1890
  };
1868
1891
  }
1869
1892
  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];
@@ -1919,6 +1942,8 @@ function parseParagraphGroup(recs, start, di, shield, gsoCtx) {
1919
1942
  const hdr = recs[start];
1920
1943
  const lv = hdr.level;
1921
1944
  const psId = hdr.data.length >= 10 ? BinaryKit.readU16LE(hdr.data, 8) : 0;
1945
+ const hwpStyleId = hdr.data.length >= 11 ? hdr.data[10] : 0;
1946
+ const divideSort = hdr.data.length >= 12 ? hdr.data[11] : 0;
1922
1947
  const ps = di.paraShapes[psId];
1923
1948
  let text = null;
1924
1949
  let csPairs = [];
@@ -1936,23 +1961,48 @@ function parseParagraphGroup(recs, start, di, shield, gsoCtx) {
1936
1961
  } else if (r.tag === TAG_CTRL_HEADER && r.level === lv + 1) {
1937
1962
  if (r.data.length >= 4) {
1938
1963
  const ctrlId = BinaryKit.readU32LE(r.data, 0);
1939
- const MAX_HWP = 1e6;
1940
- const rawW = r.data.length >= 24 ? BinaryKit.readU32LE(r.data, 16) : 0;
1941
- const rawH = r.data.length >= 28 ? BinaryKit.readU32LE(r.data, 20) : 0;
1942
- const wPt = rawW > 0 && rawW < MAX_HWP ? Metric.hwpToPt(rawW) : 0;
1943
- const hPt = rawH > 0 && rawH < MAX_HWP ? Metric.hwpToPt(rawH) : 0;
1944
- const imgId = ctrlId === CTRL_GSO ? gsoCtx.count++ : r.data.length >= 6 ? BinaryKit.readU16LE(r.data, 4) : 0;
1945
- ctrlHeaders.push({ ctrlId, imgId, wPt, hPt });
1946
- if (ctrlId === CTRL_TABLE) {
1947
- const tr = shield.guard(
1948
- () => parseTableCtrl(recs, i, di, shield, gsoCtx),
1949
- { grid: null, next: skipKids(recs, i) },
1950
- `hwp:tbl@${i}`
1951
- );
1952
- if (tr.grid) grids.push(tr.grid);
1953
- i = tr.next;
1964
+ if (ctrlId === CTRL_HEAD || ctrlId === CTRL_FOOT) {
1965
+ const ctrlLv = r.level;
1966
+ const hfParas = [];
1967
+ let j = i + 1;
1968
+ while (j < recs.length && recs[j].level > ctrlLv) {
1969
+ if (recs[j].tag === TAG_PARA_HEADER) {
1970
+ const pr = shield.guard(
1971
+ () => parseParagraphGroup(recs, j, di, shield, gsoCtx),
1972
+ { nodes: [], next: j + 1 },
1973
+ `hwp:hf@${j}`
1974
+ );
1975
+ hfParas.push(...pr.nodes.filter((n) => n.tag === "para"));
1976
+ j = pr.next;
1977
+ } else {
1978
+ j++;
1979
+ }
1980
+ }
1981
+ if (hfParas.length > 0) {
1982
+ const key = ctrlId === CTRL_HEAD ? "headers" : "footers";
1983
+ if (!gsoCtx[key]) gsoCtx[key] = hfParas;
1984
+ }
1985
+ i = j;
1954
1986
  } else {
1955
- i = skipKids(recs, i);
1987
+ const MAX_HWP = 1e6;
1988
+ const rawW = r.data.length >= 24 ? BinaryKit.readU32LE(r.data, 16) : 0;
1989
+ const rawH = r.data.length >= 28 ? BinaryKit.readU32LE(r.data, 20) : 0;
1990
+ const wPt = rawW > 0 && rawW < MAX_HWP ? Metric.hwpToPt(rawW) : 0;
1991
+ const hPt = rawH > 0 && rawH < MAX_HWP ? Metric.hwpToPt(rawH) : 0;
1992
+ const atnoType = ctrlId === CTRL_ATNO && r.data.length >= 8 ? BinaryKit.readU32LE(r.data, 4) & 15 : void 0;
1993
+ const imgId = ctrlId === CTRL_GSO ? gsoCtx.count++ : r.data.length >= 6 ? BinaryKit.readU16LE(r.data, 4) : 0;
1994
+ ctrlHeaders.push({ ctrlId, imgId, wPt, hPt, atnoType });
1995
+ if (ctrlId === CTRL_TABLE) {
1996
+ const tr = shield.guard(
1997
+ () => parseTableCtrl(recs, i, di, shield, gsoCtx),
1998
+ { grid: null, next: skipKids(recs, i) },
1999
+ `hwp:tbl@${i}`
2000
+ );
2001
+ if (tr.grid) grids.push(tr.grid);
2002
+ i = tr.next;
2003
+ } else {
2004
+ i = skipKids(recs, i);
2005
+ }
1956
2006
  }
1957
2007
  } else {
1958
2008
  i = skipKids(recs, i);
@@ -1962,13 +2012,35 @@ function parseParagraphGroup(recs, start, di, shield, gsoCtx) {
1962
2012
  }
1963
2013
  }
1964
2014
  const nodes = [];
1965
- if (text && (text.chars.length > 0 || text.controls.length > 0)) {
2015
+ {
1966
2016
  const paraContent = [];
1967
- if (text.chars.length > 0) {
1968
- const spans = resolveCharShapes(text.chars, csPairs, di);
1969
- paraContent.push(...spans);
2017
+ const atnoCtrls = [];
2018
+ if (text && text.controls.length > 0) {
2019
+ for (let ci = 0; ci < text.controls.length; ci++) {
2020
+ const ch = ctrlHeaders[ci];
2021
+ if (ch && ch.ctrlId === CTRL_ATNO)
2022
+ atnoCtrls.push({ pos: text.controls[ci].pos, type: ch.atnoType ?? 0 });
2023
+ }
2024
+ atnoCtrls.sort((a, b) => a.pos - b.pos);
2025
+ }
2026
+ if (text && text.chars.length > 0) {
2027
+ if (atnoCtrls.length > 0) {
2028
+ let k = 0;
2029
+ for (const ac of atnoCtrls) {
2030
+ const seg = [];
2031
+ while (k < text.chars.length && text.chars[k].pos < ac.pos) seg.push(text.chars[k++]);
2032
+ if (seg.length > 0) paraContent.push(...resolveCharShapes(seg, csPairs, di));
2033
+ paraContent.push(buildPageNum(ac.type === 0 ? "decimal" : "total"));
2034
+ }
2035
+ const rest = text.chars.slice(k);
2036
+ if (rest.length > 0) paraContent.push(...resolveCharShapes(rest, csPairs, di));
2037
+ } else {
2038
+ paraContent.push(...resolveCharShapes(text.chars, csPairs, di));
2039
+ }
2040
+ } else if (atnoCtrls.length > 0) {
2041
+ for (const ac of atnoCtrls) paraContent.push(buildPageNum(ac.type === 0 ? "decimal" : "total"));
1970
2042
  }
1971
- if (text.controls.length > 0) {
2043
+ if (text && text.controls.length > 0) {
1972
2044
  for (let ci = 0; ci < text.controls.length; ci++) {
1973
2045
  const ch = ctrlHeaders[ci];
1974
2046
  if (!ch) continue;
@@ -1978,11 +2050,15 @@ function parseParagraphGroup(recs, start, di, shield, gsoCtx) {
1978
2050
  paraContent.push(buildSpan(`__EXT_${ch.imgId}${dimStr}__`));
1979
2051
  }
1980
2052
  }
1981
- if (paraContent.length > 0) {
1982
- nodes.push(buildPara(paraContent, buildParaProps(ps)));
2053
+ if (divideSort & 4) {
2054
+ nodes.push(buildPara([{ tag: "span", props: {}, kids: [buildPb()] }]));
1983
2055
  }
2056
+ nodes.push(...grids);
2057
+ nodes.push(buildPara(
2058
+ paraContent.length > 0 ? paraContent : [buildSpan("")],
2059
+ buildParaProps(ps, hwpStyleId)
2060
+ ));
1984
2061
  }
1985
- nodes.push(...grids);
1986
2062
  return { nodes, next: i };
1987
2063
  }
1988
2064
  function skipKids(recs, idx) {
@@ -1991,7 +2067,7 @@ function skipKids(recs, idx) {
1991
2067
  while (i < recs.length && recs[i].level > lv) i++;
1992
2068
  return i;
1993
2069
  }
1994
- var EXT_CTRL = /* @__PURE__ */ new Set([2, 3, 11, 12, 14, 15]);
2070
+ var EXT_CTRL = /* @__PURE__ */ new Set([2, 3, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]);
1995
2071
  var INL_CTRL = /* @__PURE__ */ new Set([4, 5, 6, 7, 8]);
1996
2072
  function decodeParaText(d) {
1997
2073
  const chars = [];
@@ -2289,6 +2365,8 @@ function parseCellRec(d, tag, recs, cStart, cEnd, di, shield, seqIdx, colCnt, gs
2289
2365
  const hdr = recs[k];
2290
2366
  const lv = hdr.level;
2291
2367
  const psId = hdr.data.length >= 10 ? BinaryKit.readU16LE(hdr.data, 8) : 0;
2368
+ const cellStyleId = hdr.data.length >= 11 ? hdr.data[10] : 0;
2369
+ const cellDivide = hdr.data.length >= 12 ? hdr.data[11] : 0;
2292
2370
  const ps = di.paraShapes[psId];
2293
2371
  let txt = null;
2294
2372
  let csp = [];
@@ -2340,7 +2418,8 @@ function parseCellRec(d, tag, recs, cStart, cEnd, di, shield, seqIdx, colCnt, gs
2340
2418
  }
2341
2419
  }
2342
2420
  const kids = paraContent.length > 0 ? paraContent : [buildSpan("")];
2343
- const items = [buildPara(kids, buildParaProps(ps)), ...innerGrids];
2421
+ const items = [...innerGrids, buildPara(kids, buildParaProps(ps, cellStyleId))];
2422
+ if (cellDivide & 4) items.unshift(buildPara([{ tag: "span", props: {}, kids: [buildPb()] }]));
2344
2423
  return { items, next: j };
2345
2424
  },
2346
2425
  { items: [buildPara([buildSpan("")])], next: k + 1 },
@@ -2393,6 +2472,8 @@ function parsePageDef(d) {
2393
2472
  const mr = BinaryKit.readU32LE(d, 12);
2394
2473
  const mt = BinaryKit.readU32LE(d, 16);
2395
2474
  const mb = BinaryKit.readU32LE(d, 20);
2475
+ const header = d.length >= 28 ? BinaryKit.readU32LE(d, 24) : 0;
2476
+ const footer = d.length >= 32 ? BinaryKit.readU32LE(d, 28) : 0;
2396
2477
  const at = d.length >= 40 ? BinaryKit.readU32LE(d, 36) : 0;
2397
2478
  return {
2398
2479
  wPt: Metric.hwpToPt(w),
@@ -2401,6 +2482,8 @@ function parsePageDef(d) {
2401
2482
  mr: Metric.hwpToPt(mr),
2402
2483
  mt: Metric.hwpToPt(mt),
2403
2484
  mb: Metric.hwpToPt(mb),
2485
+ headerPt: header > 0 ? Metric.hwpToPt(header) : void 0,
2486
+ footerPt: footer > 0 ? Metric.hwpToPt(footer) : void 0,
2404
2487
  orient: at & 1 ? "landscape" : "portrait"
2405
2488
  };
2406
2489
  }
@@ -2431,16 +2514,24 @@ function strokeFromBF(bfId, di) {
2431
2514
  const b = bf.borders[0];
2432
2515
  return { kind: BORDER_KIND[b.type] ?? "solid", pt: b.widthPt, color: b.color };
2433
2516
  }
2434
- function buildParaProps(ps) {
2435
- if (!ps) return {};
2436
- const p = {};
2517
+ function buildParaProps(ps, hwpStyleId) {
2518
+ const p = hwpStyleId !== void 0 ? { hwpStyleId } : {};
2519
+ if (!ps) return p;
2437
2520
  if (ps.align && ps.align !== "left") p.align = ps.align;
2438
2521
  if (ps.spaceBefore > 0) p.spaceBefore = Metric.hwpToPt(ps.spaceBefore);
2439
2522
  if (ps.spaceAfter > 0) p.spaceAfter = Metric.hwpToPt(ps.spaceAfter);
2440
- if (ps.lineSpacing > 0 && ps.lineSpacing !== 160) p.lineHeight = ps.lineSpacing / 100;
2523
+ if (ps.lineSpacingType === 1) {
2524
+ if (ps.lineSpacing > 0) p.lineHeightFixed = Metric.hwpToPt(ps.lineSpacing);
2525
+ } else {
2526
+ if (ps.lineSpacing > 0) p.lineHeight = ps.lineSpacing / 100;
2527
+ }
2441
2528
  const leftMarginPt = Math.max(0, Metric.hwpToPt(ps.leftMargin));
2442
2529
  if (leftMarginPt > 0) p.leftMargin = leftMarginPt;
2530
+ const rightMarginPt = Math.max(0, Metric.hwpToPt(ps.rightMargin));
2531
+ if (rightMarginPt > 0) p.indentRightPt = rightMarginPt;
2443
2532
  if (ps.indent !== 0) p.firstLineIndentPt = Metric.hwpToPt(ps.indent);
2533
+ if (ps.verAlign && ps.verAlign !== "baseline") p.verAlign = ps.verAlign;
2534
+ if (ps.lineWrap && ps.lineWrap !== "break") p.lineWrap = ps.lineWrap;
2444
2535
  return p;
2445
2536
  }
2446
2537
  var HwpScanner = class {
@@ -2508,7 +2599,10 @@ var HwpScanner = class {
2508
2599
  }
2509
2600
  warns.push(...shield.flush());
2510
2601
  const content = allContent.length > 0 ? allContent : [buildPara([buildSpan("")])];
2511
- return succeed(buildRoot({}, [buildSheet(content, pageDims)]), warns);
2602
+ return succeed(buildRoot({}, [buildSheet(content, pageDims, {
2603
+ headers: gsoCtx.headers ? { default: gsoCtx.headers } : void 0,
2604
+ footers: gsoCtx.footers ? { default: gsoCtx.footers } : void 0
2605
+ })]), warns);
2512
2606
  } catch (e) {
2513
2607
  warns.push(...shield.flush());
2514
2608
  return fail(`HWP decode error: ${e?.message ?? String(e)}`, warns);
@@ -4479,6 +4573,27 @@ var KIND_MAP = {
4479
4573
  dash_dot: "DASH_DOT",
4480
4574
  dash_dot_dot: "DASH_DOT_DOT"
4481
4575
  };
4576
+ function quantizeBorderWidth(pt) {
4577
+ const mm = pt * 0.3528;
4578
+ 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];
4579
+ let closest = standardWidths[0];
4580
+ let minDiff = Math.abs(mm - closest);
4581
+ for (let i = 1; i < standardWidths.length; i++) {
4582
+ const diff = Math.abs(mm - standardWidths[i]);
4583
+ if (diff < minDiff) {
4584
+ minDiff = diff;
4585
+ closest = standardWidths[i];
4586
+ }
4587
+ }
4588
+ let str = closest.toFixed(2);
4589
+ if (str.endsWith("0")) {
4590
+ str = str.slice(0, -1);
4591
+ }
4592
+ if (str.endsWith(".0")) {
4593
+ str = str.slice(0, -2);
4594
+ }
4595
+ return `${str} mm`;
4596
+ }
4482
4597
  var BorderFillBank = class {
4483
4598
  constructor() {
4484
4599
  this.fills = [];
@@ -4491,7 +4606,7 @@ var BorderFillBank = class {
4491
4606
  }
4492
4607
  _strokeXml(tag, s) {
4493
4608
  const type = s && s.kind !== "none" ? KIND_MAP[s.kind] ?? "SOLID" : "NONE";
4494
- const w = s && s.kind !== "none" ? `${(s.pt * 0.3528).toFixed(2)} mm` : "0.12 mm";
4609
+ const w = s && s.kind !== "none" ? quantizeBorderWidth(s.pt) : "0.12 mm";
4495
4610
  const c = s ? s.color.startsWith("#") ? s.color : `#${s.color}` : "#000000";
4496
4611
  return `<hh:${tag} type="${type}" width="${w}" color="${c}"/>`;
4497
4612
  }
@@ -4568,7 +4683,7 @@ function charPrKey(p) {
4568
4683
  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 ?? ""}`;
4569
4684
  }
4570
4685
  function paraPrKey(p) {
4571
- 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 ?? ""}`;
4686
+ 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 ?? ""}`;
4572
4687
  }
4573
4688
  function registerCharPr(props, ctx) {
4574
4689
  const key = charPrKey(props);
@@ -4592,20 +4707,45 @@ function registerCharPr(props, ctx) {
4592
4707
  ctx.charPrMap.set(key, id);
4593
4708
  return id;
4594
4709
  }
4710
+ var ALIGN_MAP2 = {
4711
+ left: "LEFT",
4712
+ center: "CENTER",
4713
+ right: "RIGHT",
4714
+ justify: "JUSTIFY",
4715
+ distribute: "DISTRIBUTE",
4716
+ distribute_space: "DISTRIBUTE_SPACE"
4717
+ };
4718
+ var V_ALIGN_MAP = {
4719
+ baseline: "BASELINE",
4720
+ top: "TOP",
4721
+ center: "CENTER",
4722
+ bottom: "BOTTOM"
4723
+ };
4724
+ var LINE_WRAP_MAP = {
4725
+ break: "BREAK",
4726
+ squeeze: "SQUEEZE",
4727
+ keep: "KEEP"
4728
+ };
4595
4729
  function registerParaPr(props, ctx) {
4596
4730
  const key = paraPrKey(props);
4597
4731
  const existing = ctx.paraPrMap.get(key);
4598
4732
  if (existing !== void 0) return existing;
4599
4733
  const id = ctx.paraPrs.length;
4734
+ const alignStr = props.align ? ALIGN_MAP2[props.align] ?? "LEFT" : "LEFT";
4735
+ const verAlignStr = props.verAlign ? V_ALIGN_MAP[props.verAlign] ?? "BASELINE" : "BASELINE";
4736
+ const lineWrapStr = props.lineWrap ? LINE_WRAP_MAP[props.lineWrap] ?? "BREAK" : "BREAK";
4600
4737
  const def = {
4601
4738
  id,
4602
- align: (props.align ?? "left").toUpperCase(),
4603
- leftHwp: Metric.ptToHwp(props.indentPt ?? 0),
4739
+ align: alignStr,
4740
+ verAlign: verAlignStr,
4741
+ lineWrap: lineWrapStr,
4742
+ leftHwp: Metric.ptToHwp(props.leftMargin ?? 0),
4604
4743
  rightHwp: Metric.ptToHwp(props.indentRightPt ?? 0),
4605
4744
  intentHwp: Metric.ptToHwp(props.firstLineIndentPt ?? 0),
4606
4745
  prevHwp: Metric.ptToHwp(props.spaceBefore ?? 0),
4607
4746
  nextHwp: Metric.ptToHwp(props.spaceAfter ?? 0),
4608
- lineSpacing: props.lineHeight ? Math.round(props.lineHeight * 100) : 160
4747
+ lineSpacing: props.lineHeightFixed ? 0 : props.lineHeight ? Math.round(props.lineHeight * 100) : 160,
4748
+ lineSpacingFixed: props.lineHeightFixed ? Metric.ptToHwp(props.lineHeightFixed) : void 0
4609
4749
  };
4610
4750
  if (props.listOrd !== void 0) {
4611
4751
  def.listType = props.listOrd ? "DIGIT" : "BULLET";
@@ -4710,8 +4850,8 @@ var HwpxEncoder = class extends BaseEncoder {
4710
4850
  try {
4711
4851
  const sheet = doc.kids[0];
4712
4852
  const dims = normalizeDims(sheet?.dims ?? A4);
4713
- const safeML = dims.ml > 0 ? dims.ml : 70.87;
4714
- const safeMR = dims.mr > 0 ? dims.mr : 70.87;
4853
+ const safeML = dims.ml !== void 0 && dims.ml >= 0 ? dims.ml : 70.87;
4854
+ const safeMR = dims.mr !== void 0 && dims.mr >= 0 ? dims.mr : 70.87;
4715
4855
  const availableWidth = Math.round(
4716
4856
  Metric.ptToHwp(dims.wPt) - Metric.ptToHwp(safeML) - Metric.ptToHwp(safeMR)
4717
4857
  );
@@ -4767,9 +4907,9 @@ var HwpxEncoder = class extends BaseEncoder {
4767
4907
  mime: "application/xml"
4768
4908
  },
4769
4909
  {
4770
- name: "META-INF/container.rdf",
4771
- data: this.stringToBytes(CONTAINER_RDF),
4772
- mime: "application/rdf+xml"
4910
+ name: "META-INF/manifest.xml",
4911
+ data: this.stringToBytes(MANIFEST_XML),
4912
+ mime: "application/xml"
4773
4913
  },
4774
4914
  {
4775
4915
  name: "Contents/content.hpf",
@@ -4808,9 +4948,9 @@ var HwpxEncoder = class extends BaseEncoder {
4808
4948
  }
4809
4949
  }
4810
4950
  };
4811
- 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"/>`;
4812
- 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>`;
4813
- 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>`;
4951
+ 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"/>`;
4952
+ 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>`;
4953
+ 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"/>`;
4814
4954
  function buildContentHpf(ctx, meta) {
4815
4955
  const title = esc(meta?.title ?? "");
4816
4956
  const creator = esc(meta?.author ?? "text");
@@ -4836,6 +4976,18 @@ function buildNumberingsXml() {
4836
4976
  function buildBulletsXml() {
4837
4977
  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>`;
4838
4978
  }
4979
+ function buildHeaderSecPrListXml(dims) {
4980
+ const wHwp = Metric.ptToHwp(dims.wPt);
4981
+ const hHwp = Metric.ptToHwp(dims.hPt);
4982
+ const ml = Metric.ptToHwp(dims.ml);
4983
+ const mr = Metric.ptToHwp(dims.mr);
4984
+ const mt = Metric.ptToHwp(dims.mt);
4985
+ const mb = Metric.ptToHwp(dims.mb);
4986
+ const headerZone = dims.headerPt !== void 0 && dims.headerPt > 0 ? Metric.ptToHwp(dims.headerPt) : 0;
4987
+ const footerZone = dims.footerPt !== void 0 && dims.footerPt > 0 ? Metric.ptToHwp(dims.footerPt) : 0;
4988
+ 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>`;
4989
+ 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>`;
4990
+ }
4839
4991
  function buildHeaderXml(dims, meta, ctx) {
4840
4992
  const fontFacesXml = ctx.fontBank.toXml();
4841
4993
  let charPrXml = "";
@@ -4849,51 +5001,17 @@ function buildHeaderXml(dims, meta, ctx) {
4849
5001
  }
4850
5002
  let paraPrXml = "";
4851
5003
  for (const pp of ctx.paraPrs) {
4852
- 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>`;
5004
+ const ver = pp.verAlign ?? "BASELINE";
5005
+ const wrap = pp.lineWrap ?? "BREAK";
5006
+ const lsType = pp.lineSpacingFixed !== void 0 ? "FIXED" : "PERCENT";
5007
+ const lsValue = pp.lineSpacingFixed !== void 0 ? pp.lineSpacingFixed : pp.lineSpacing;
5008
+ 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>`;
4853
5009
  }
4854
5010
  const borderFillXml = ctx.borderFillBank.toXml();
4855
5011
  const stylesXml2 = `<hh:styles itemCnt="${ctx.hwpxStyles.length}">` + ctx.hwpxStyles.map(
4856
5012
  (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"/>`
4857
5013
  ).join("") + `</hh:styles>`;
4858
- 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">
4859
- <hh:layoutCompatibility>
4860
- <hh:applyFontWeightToBold />
4861
- <hh:useInnerUnderline />
4862
- <hh:useLowercaseStrikeout />
4863
- <hh:extendLineheightToOffset />
4864
- <hh:treatQuotationAsLatin />
4865
- <hh:doNotAlignWhitespaceOnRight />
4866
- <hh:doNotAdjustWordInJustify />
4867
- <hh:baseCharUnitOnEAsian />
4868
- <hh:baseCharUnitOfIndentOnFirstChar />
4869
- <hh:adjustLineheightToFont />
4870
- <hh:adjustBaselineInFixedLinespacing />
4871
- <hh:applyPrevspacingBeneathObject />
4872
- <hh:applyNextspacingOfLastPara />
4873
- <hh:adjustParaBorderfillToSpacing />
4874
- <hh:connectParaBorderfillOfEqualBorder />
4875
- <hh:adjustParaBorderOffsetWithBorder />
4876
- <hh:extendLineheightToParaBorderOffset />
4877
- <hh:applyParaBorderToOutside />
4878
- <hh:applyMinColumnWidthTo1mm />
4879
- <hh:applyTabPosBasedOnSegment />
4880
- <hh:breakTabOverLine />
4881
- <hh:adjustVertPosOfLine />
4882
- <hh:doNotAlignLastForbidden />
4883
- <hh:adjustMarginFromAdjustLineheight />
4884
- <hh:baseLineSpacingOnLineGrid />
4885
- <hh:applyCharSpacingToCharGrid />
4886
- <hh:doNotApplyGridInHeaderFooter />
4887
- <hh:applyExtendHeaderFooterEachSection />
4888
- <hh:doNotApplyLinegridAtNoLinespacing />
4889
- <hh:doNotAdjustEmptyAnchorLine />
4890
- <hh:overlapBothAllowOverlap />
4891
- <hh:extendVertLimitToPageMargins />
4892
- <hh:doNotHoldAnchorOfTable />
4893
- <hh:doNotFormattingAtBeneathAnchor />
4894
- <hh:adjustBaselineOfObjectToBottom />
4895
- </hh:layoutCompatibility>
4896
- </hh:compatibleDocument><hh:docOption><hh:linkinfo path="" pageInherit="0" footnoteInherit="0"/></hh:docOption><hh:trackchageConfig flags="56"/></hh:head>`;
5014
+ 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>`;
4897
5015
  }
4898
5016
  function buildHeaderFooterRunXml(sheet, dims, ctx) {
4899
5017
  const headers = sheet.headers || {};
@@ -4903,12 +5021,13 @@ function buildHeaderFooterRunXml(sheet, dims, ctx) {
4903
5021
  const availW = ctx.availableWidth;
4904
5022
  const mtHwp = Metric.ptToHwp(dims.mt);
4905
5023
  const mbHwp = Metric.ptToHwp(dims.mb);
4906
- const headerZoneH = dims.headerPt ? Math.max(100, mtHwp - Metric.ptToHwp(dims.headerPt)) : 3600;
4907
- const footerZoneH = dims.footerPt ? Math.max(100, mbHwp - Metric.ptToHwp(dims.footerPt)) : 3600;
5024
+ const headerZoneH = dims.headerPt ? Metric.ptToHwp(dims.headerPt) : 4252;
5025
+ const footerZoneH = dims.footerPt ? Metric.ptToHwp(dims.footerPt) : 4252;
4908
5026
  let inner = "";
4909
5027
  const hideFirst = !!(headers.first || footers.first);
4910
5028
  inner += `<hp:ctrl><hp:pageHiding hideHeader="${hideFirst ? 1 : 0}" hideFooter="${hideFirst ? 1 : 0}" hideMasterPage="0" hideBorder="0" hideFill="0" hidePageNum="0"/></hp:ctrl>`;
4911
5029
  for (const [type, paras] of Object.entries(headers)) {
5030
+ if (!Array.isArray(paras) || paras.length === 0) continue;
4912
5031
  const applyPageType = type === "even" ? "EVEN" : type === "default" || type === "first" ? "BOTH" : "ODD";
4913
5032
  const savedId = ctx.nextElementId;
4914
5033
  ctx.nextElementId = 0;
@@ -4917,6 +5036,7 @@ function buildHeaderFooterRunXml(sheet, dims, ctx) {
4917
5036
  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>`;
4918
5037
  }
4919
5038
  for (const [type, paras] of Object.entries(footers)) {
5039
+ if (!Array.isArray(paras) || paras.length === 0) continue;
4920
5040
  const applyPageType = type === "even" ? "EVEN" : type === "default" || type === "first" ? "BOTH" : "ODD";
4921
5041
  const savedId = ctx.nextElementId;
4922
5042
  ctx.nextElementId = 0;
@@ -4940,10 +5060,10 @@ function buildSectionXml(sheet, dims, ctx) {
4940
5060
  for (let i = 0; i < kids.length; i++) {
4941
5061
  const kid = kids[i];
4942
5062
  const isFirst = i === 0;
4943
- const curSecPr = isFirst ? secPrXml : "";
5063
+ const curSecPr = "";
4944
5064
  const curHfRun = isFirst ? hfRunXml : "";
4945
5065
  if (kid.tag === "para") {
4946
- const { xml, nextVertPos } = encodeParaPositioned(
5066
+ const { xml, nextVertPos, hasPageBreak } = encodeParaPositioned(
4947
5067
  kid,
4948
5068
  ctx,
4949
5069
  vertPos,
@@ -4954,7 +5074,7 @@ function buildSectionXml(sheet, dims, ctx) {
4954
5074
  contentXml += xml;
4955
5075
  vertPos = nextVertPos;
4956
5076
  } else if (kid.tag === "grid") {
4957
- const { xml, nextVertPos } = encodeGridPositioned(
5077
+ const { xml, nextVertPos, hasPageBreak } = encodeGridPositioned(
4958
5078
  kid,
4959
5079
  ctx,
4960
5080
  vertPos,
@@ -4969,9 +5089,9 @@ function buildSectionXml(sheet, dims, ctx) {
4969
5089
  const fs = 1e3;
4970
5090
  const vs = 1600;
4971
5091
  const { xml: linesegXml } = buildLinesegarray(" ", 0, fs, vs / (fs / 100), availWidth);
4972
- 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>`;
5092
+ 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>`;
4973
5093
  }
4974
- 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>`;
5094
+ 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>`;
4975
5095
  }
4976
5096
  function buildSecPrXml(dims) {
4977
5097
  const wHwp = Metric.ptToHwp(dims.wPt);
@@ -4980,24 +5100,62 @@ function buildSecPrXml(dims) {
4980
5100
  const mr = Metric.ptToHwp(dims.mr);
4981
5101
  const mt = Metric.ptToHwp(dims.mt);
4982
5102
  const mb = Metric.ptToHwp(dims.mb);
4983
- const headerZone = dims.headerPt ? Math.max(0, mt - Metric.ptToHwp(dims.headerPt)) : 0;
4984
- const footerZone = dims.footerPt ? Math.max(0, mb - Metric.ptToHwp(dims.footerPt)) : 0;
5103
+ const headerZone = dims.headerPt ? Metric.ptToHwp(dims.headerPt) : 0;
5104
+ const footerZone = dims.footerPt ? Metric.ptToHwp(dims.footerPt) : 0;
4985
5105
  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>`;
4986
- 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>`;
5106
+ 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>`;
4987
5107
  }
4988
5108
  function buildLinesegarray(text, vertPosStart, fontSize, lineSpacingPct, horzSize) {
4989
5109
  const vertsizeLine = Math.round(fontSize * lineSpacingPct / 100);
4990
5110
  const spacing = vertsizeLine - fontSize;
4991
5111
  const baseline = Math.round(fontSize * 0.83);
4992
- const isKorean = /[\uAC00-\uD7A3\u3131-\u318E]/.test(text);
4993
- const charW = isKorean ? fontSize : Math.round(fontSize * 0.47);
4994
- const charsPerLine = Math.max(1, Math.floor(horzSize / charW));
4995
- const lineCount = text.length === 0 ? 1 : Math.ceil(text.length / charsPerLine);
5112
+ if (text.length === 0) {
5113
+ 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>`;
5114
+ return { xml, totalHeight: vertsizeLine };
5115
+ }
5116
+ const lines = [];
5117
+ let currentLineWidth = 0;
5118
+ let lineStartIdx = 0;
5119
+ for (let i = 0; i < text.length; i++) {
5120
+ const charCode = text.charCodeAt(i);
5121
+ if (charCode === 10 || charCode === 13) {
5122
+ lines.push({ startPos: lineStartIdx, width: currentLineWidth });
5123
+ lineStartIdx = i + 1;
5124
+ currentLineWidth = 0;
5125
+ continue;
5126
+ }
5127
+ let charW = fontSize * 0.55;
5128
+ if (charCode >= 44032 && charCode <= 55203) {
5129
+ charW = fontSize;
5130
+ } else if (charCode >= 12592 && charCode <= 12687) {
5131
+ charW = fontSize;
5132
+ } else if (charCode >= 19968 && charCode <= 40959) {
5133
+ charW = fontSize;
5134
+ } else if (charCode >= 65 && charCode <= 90) {
5135
+ charW = fontSize * 0.65;
5136
+ } else if (charCode === 32) {
5137
+ charW = fontSize * 0.32;
5138
+ } else if (charCode > 255) {
5139
+ charW = fontSize;
5140
+ } else {
5141
+ charW = fontSize * 0.42;
5142
+ }
5143
+ if (currentLineWidth + charW > horzSize && i > lineStartIdx) {
5144
+ lines.push({ startPos: lineStartIdx, width: currentLineWidth });
5145
+ lineStartIdx = i;
5146
+ currentLineWidth = charW;
5147
+ } else {
5148
+ currentLineWidth += charW;
5149
+ }
5150
+ }
5151
+ lines.push({ startPos: lineStartIdx, width: currentLineWidth });
5152
+ const lineCount = lines.length;
4996
5153
  const linesegParts = [];
4997
5154
  for (let i = 0; i < lineCount; i++) {
4998
5155
  const flags = i === 0 ? LINESEG_FLAGS_FIRST : LINESEG_FLAGS_OTHER;
5156
+ const textpos = lines[i].startPos;
4999
5157
  linesegParts.push(
5000
- `<hp:lineseg textpos="${i * charsPerLine}" vertpos="${vertPosStart + i * vertsizeLine}" vertsize="${vertsizeLine}" textheight="${fontSize}" baseline="${baseline}" spacing="${spacing}" horzpos="0" horzsize="${horzSize}" flags="${flags}"/>`
5158
+ `<hp:lineseg textpos="${textpos}" vertpos="${vertPosStart + i * vertsizeLine}" vertsize="${vertsizeLine}" textheight="${fontSize}" baseline="${baseline}" spacing="${spacing}" horzpos="0" horzsize="${horzSize}" flags="${flags}"/>`
5001
5159
  );
5002
5160
  }
5003
5161
  return {
@@ -5010,7 +5168,13 @@ function extractParaText(para) {
5010
5168
  const walk = (kids) => {
5011
5169
  for (const k of kids) {
5012
5170
  if (k.tag === "span") {
5013
- for (const c of k.kids) if (c.tag === "txt") text += c.content;
5171
+ for (const c of k.kids) {
5172
+ if (c.tag === "txt") {
5173
+ text += c.content;
5174
+ } else if (c.tag === "br") {
5175
+ text += "\n";
5176
+ }
5177
+ }
5014
5178
  } else if (k.tag === "link") {
5015
5179
  walk(k.kids);
5016
5180
  }
@@ -5069,7 +5233,7 @@ function encodeParaPositioned(para, ctx, vertPos, secPr = "", availWidth, hfRun
5069
5233
  (k) => k.tag === "span" && k.kids.some((c) => c.tag === "pb")
5070
5234
  );
5071
5235
  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>`;
5072
- return { xml, nextVertPos: vertPos + totalHeight };
5236
+ return { xml, nextVertPos: vertPos + totalHeight, hasPageBreak };
5073
5237
  }
5074
5238
  function encodeTablePara(para, grid, ctx, vertPos, secPr, hfRun) {
5075
5239
  const paraPrId = ctx.paraPrMap.get(paraPrKey(para.props)) ?? 0;
@@ -5079,8 +5243,12 @@ function encodeTablePara(para, grid, ctx, vertPos, secPr, hfRun) {
5079
5243
  const baseline = 850;
5080
5244
  const spacing = Math.max(0, totalHeight - fontSize);
5081
5245
  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>`;
5082
- 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>`;
5083
- return { xml, nextVertPos: vertPos + totalHeight };
5246
+ const hasPageBreak = para.kids.some(
5247
+ (k) => k.tag === "span" && k.kids.some((c) => c.tag === "pb")
5248
+ );
5249
+ const runId = ctx.nextElementId++;
5250
+ 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>`;
5251
+ return { xml, nextVertPos: vertPos + totalHeight, hasPageBreak };
5084
5252
  }
5085
5253
  function encodeCodeBlockPositioned(para, ctx, vertPos, secPr, fontSize, spacing, vertSize) {
5086
5254
  const codeBfId = ctx.borderFillBank.addUniform(
@@ -5101,7 +5269,7 @@ function encodeCodeBlockPositioned(para, ctx, vertPos, secPr, fontSize, spacing,
5101
5269
  ctx.availableWidth
5102
5270
  );
5103
5271
  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>`;
5104
- return { xml, nextVertPos: vertPos + totalHeight };
5272
+ return { xml, nextVertPos: vertPos + totalHeight, hasPageBreak: false };
5105
5273
  }
5106
5274
  function encodeParaKids(kids, ctx) {
5107
5275
  let xml = "";
@@ -5150,8 +5318,7 @@ function encodeRunInner(span) {
5150
5318
  const content = esc(kid.content);
5151
5319
  if (content) xml += `<hp:t xml:space="preserve">${content}</hp:t>`;
5152
5320
  } else if (kid.tag === "br") {
5153
- xml += `<hp:t xml:space="preserve">
5154
- </hp:t>`;
5321
+ xml += `<hp:br/>`;
5155
5322
  } else if (kid.tag === "pagenum") {
5156
5323
  const fmt = kid.format === "roman" ? "ROMAN_LOWER" : kid.format === "romanCaps" ? "ROMAN_UPPER" : "DIGIT";
5157
5324
  xml += `<hp:pageNum pageStartsOn="BOTH" formatType="${fmt}"/>`;
@@ -5232,8 +5399,9 @@ function encodeGridPositioned(grid, ctx, vertPos, secPr = "", hfRun = "") {
5232
5399
  const baseline = Math.round(fontSize * 0.83);
5233
5400
  const spacing = Math.max(0, totalHeight - fontSize);
5234
5401
  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>`;
5235
- 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>`;
5236
- return { xml, nextVertPos: vertPos + totalHeight };
5402
+ const runId = ctx.nextElementId++;
5403
+ 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>`;
5404
+ return { xml, nextVertPos: vertPos + totalHeight, hasPageBreak: false };
5237
5405
  }
5238
5406
  function buildGridXml(grid, ctx) {
5239
5407
  const rowCount = grid.kids.length;
@@ -5621,6 +5789,40 @@ function stylesXml() {
5621
5789
  </w:pPr></w:pPrDefault>
5622
5790
  </w:docDefaults>
5623
5791
  <w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/></w:style>
5792
+ <w:style w:type="paragraph" w:styleId="0"><w:name w:val="\uBC14\uD0D5\uAE00"/><w:basedOn w:val="Normal"/></w:style>
5793
+ <w:style w:type="paragraph" w:styleId="1"><w:name w:val="\uBCF8\uBB38"/><w:basedOn w:val="Normal"/></w:style>
5794
+ <w:style w:type="paragraph" w:styleId="2"><w:name w:val="\uAC1C\uC694 1"/><w:basedOn w:val="Normal"/></w:style>
5795
+ <w:style w:type="paragraph" w:styleId="3"><w:name w:val="\uAC1C\uC694 2"/><w:basedOn w:val="Normal"/></w:style>
5796
+ <w:style w:type="paragraph" w:styleId="4"><w:name w:val="\uAC1C\uC694 3"/><w:basedOn w:val="Normal"/></w:style>
5797
+ <w:style w:type="paragraph" w:styleId="5"><w:name w:val="\uAC1C\uC694 4"/><w:basedOn w:val="Normal"/></w:style>
5798
+ <w:style w:type="paragraph" w:styleId="6"><w:name w:val="\uAC1C\uC694 5"/><w:basedOn w:val="Normal"/></w:style>
5799
+ <w:style w:type="paragraph" w:styleId="7"><w:name w:val="\uAC1C\uC694 6"/><w:basedOn w:val="Normal"/></w:style>
5800
+ <w:style w:type="paragraph" w:styleId="8"><w:name w:val="\uAC1C\uC694 7"/><w:basedOn w:val="Normal"/></w:style>
5801
+ <w:style w:type="paragraph" w:styleId="9"><w:name w:val="\uAC1C\uC694 8"/><w:basedOn w:val="Normal"/></w:style>
5802
+ <w:style w:type="paragraph" w:styleId="10"><w:name w:val="\uAC1C\uC694 9"/><w:basedOn w:val="Normal"/></w:style>
5803
+ <w:style w:type="paragraph" w:styleId="11"><w:name w:val="\uAC1C\uC694 10"/><w:basedOn w:val="Normal"/></w:style>
5804
+ <w:style w:type="paragraph" w:styleId="12"><w:name w:val="\uCABD \uBC88\uD638"/><w:basedOn w:val="Normal"/></w:style>
5805
+ <w:style w:type="paragraph" w:styleId="13"><w:name w:val="\uBA38\uB9AC\uB9D0"/><w:basedOn w:val="Normal"/></w:style>
5806
+ <w:style w:type="paragraph" w:styleId="14"><w:name w:val="\uAC01\uC8FC"/><w:basedOn w:val="Normal"/></w:style>
5807
+ <w:style w:type="paragraph" w:styleId="15"><w:name w:val="\uBBF8\uC8FC"/><w:basedOn w:val="Normal"/></w:style>
5808
+ <w:style w:type="paragraph" w:styleId="16"><w:name w:val="\uBA54\uBAA8"/><w:basedOn w:val="Normal"/></w:style>
5809
+ <w:style w:type="paragraph" w:styleId="17"><w:name w:val="\uCC28\uB840 \uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5810
+ <w:style w:type="paragraph" w:styleId="18"><w:name w:val="\uCC28\uB840 1"/><w:basedOn w:val="Normal"/></w:style>
5811
+ <w:style w:type="paragraph" w:styleId="19"><w:name w:val="\uCC28\uB840 2"/><w:basedOn w:val="Normal"/></w:style>
5812
+ <w:style w:type="paragraph" w:styleId="20"><w:name w:val="\uCC28\uB840 3"/><w:basedOn w:val="Normal"/></w:style>
5813
+ <w:style w:type="paragraph" w:styleId="21"><w:name w:val="\uBCF8\uBB38 \uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5814
+ <w:style w:type="paragraph" w:styleId="22"><w:name w:val="\uADF8\uB9BC"/><w:basedOn w:val="Normal"/></w:style>
5815
+ <w:style w:type="paragraph" w:styleId="23"><w:name w:val="\uD45C"/><w:basedOn w:val="Normal"/></w:style>
5816
+ <w:style w:type="paragraph" w:styleId="24"><w:name w:val="\uC218\uC2DD"/><w:basedOn w:val="Normal"/></w:style>
5817
+ <w:style w:type="paragraph" w:styleId="25"><w:name w:val="\uC778\uC6A9\uBB38"/><w:basedOn w:val="Normal"/></w:style>
5818
+ <w:style w:type="paragraph" w:styleId="26"><w:name w:val="\uB0A0\uC9DC"/><w:basedOn w:val="Normal"/></w:style>
5819
+ <w:style w:type="paragraph" w:styleId="27"><w:name w:val="\uBC1C\uC2E0\uBA85\uC758"/><w:basedOn w:val="Normal"/></w:style>
5820
+ <w:style w:type="paragraph" w:styleId="28"><w:name w:val="\uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5821
+ <w:style w:type="paragraph" w:styleId="29"><w:name w:val="\uBD80\uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5822
+ <w:style w:type="paragraph" w:styleId="30"><w:name w:val="\uBB38\uB2E8 \uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5823
+ <w:style w:type="paragraph" w:styleId="31"><w:name w:val="MEMO"/><w:basedOn w:val="Normal"/></w:style>
5824
+ <w:style w:type="paragraph" w:styleId="32"><w:name w:val="\uAC1C\uC694"/><w:basedOn w:val="Normal"/></w:style>
5825
+ <w:style w:type="paragraph" w:styleId="33"><w:name w:val="\uD45C \uC81C\uBAA9"/><w:basedOn w:val="Normal"/></w:style>
5624
5826
  <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>
5625
5827
  <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>
5626
5828
  <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>
@@ -5710,7 +5912,12 @@ function encodeContent(node, ctx, dims) {
5710
5912
  }
5711
5913
  function encodeParaInner(para, ctx) {
5712
5914
  const align = para.props.align ?? "left";
5713
- const headStyle = para.props.heading ? `<w:pStyle w:val="Heading${para.props.heading}"/>` : "";
5915
+ let headStyle = "";
5916
+ if (para.props.hwpStyleId !== void 0) {
5917
+ headStyle = `<w:pStyle w:val="${para.props.hwpStyleId}"/>`;
5918
+ } else if (para.props.heading) {
5919
+ headStyle = `<w:pStyle w:val="Heading${para.props.heading}"/>`;
5920
+ }
5714
5921
  let numPr = "";
5715
5922
  if (para.props.listOrd !== void 0) {
5716
5923
  const numId = para.props.listOrd ? 2 : 1;
@@ -5749,6 +5956,10 @@ function encodeParaInner(para, ctx) {
5749
5956
  const runs = para.kids.map((k) => {
5750
5957
  if (k.tag === "span") return encodeRun(k, ctx);
5751
5958
  if (k.tag === "img") return encodeImage2(k, ctx);
5959
+ if (k.tag === "pagenum") {
5960
+ const instr = k.format === "total" ? " NUMPAGES " : " PAGE ";
5961
+ 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>`;
5962
+ }
5752
5963
  return "";
5753
5964
  }).join("");
5754
5965
  return ` <w:p>
@@ -5785,8 +5996,9 @@ function encodeRun(span, _ctx) {
5785
5996
  );
5786
5997
  }
5787
5998
  } else if (kid.tag === "pagenum") {
5999
+ const instr = kid.format === "total" ? " NUMPAGES " : " PAGE ";
5788
6000
  parts.push(
5789
- `<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>`
6001
+ `<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>`
5790
6002
  );
5791
6003
  } else if (kid.tag === "br") {
5792
6004
  parts.push(`<w:r><w:br/></w:r>`);
@@ -6576,10 +6788,11 @@ var BufWriter = class {
6576
6788
  };
6577
6789
  function mkRec(tag, level, data) {
6578
6790
  const sz = data.length;
6579
- const enc = Math.min(sz, 4095);
6580
- const hdr = enc << 20 | (level & 1023) << 10 | tag & 1023;
6791
+ const isLarge = sz >= 4095;
6792
+ const enc = isLarge ? 4095 : sz;
6793
+ const hdr = ((enc & 4095) * 1048576 | (level & 1023) << 10 | tag & 1023) >>> 0;
6581
6794
  const w = new BufWriter().u32(hdr);
6582
- if (enc >= 4095) w.u32(sz);
6795
+ if (isLarge) w.u32(sz);
6583
6796
  w.bytes(data);
6584
6797
  return w.build();
6585
6798
  }
@@ -6894,7 +7107,7 @@ function buildDocInfoStream(bank, images = []) {
6894
7107
  return concatU8(chunks);
6895
7108
  }
6896
7109
  function mkPageDef(dims) {
6897
- 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();
7110
+ 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();
6898
7111
  }
6899
7112
  function mkParaHeader(nchars, ctrlMask, psId, csCount, lineAlignCount = 0, instanceId = 0) {
6900
7113
  return new BufWriter().u32(nchars).u32(ctrlMask).u16(psId).u8(0).u8(0).u16(csCount).u16(0).u16(lineAlignCount).u32(instanceId).u16(0).build();
@@ -7095,7 +7308,7 @@ function encodePara3(para, bank, lv, instanceId, availWidthHwp, mask = 0, vertPo
7095
7308
  ];
7096
7309
  }
7097
7310
  function mkTableCtrl(wHwp, hHwp, instanceId, align = "left") {
7098
- const alignFlags = { left: 0, center: 1, right: 2, justify: 3 }[align] ?? 0;
7311
+ const alignFlags = { left: 0, center: 1, right: 2, justify: 3, distribute: 0, distribute_space: 0 }[align] ?? 0;
7099
7312
  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();
7100
7313
  }
7101
7314
  function mkTableRecord(rowCnt, colCnt, rowHwp, bfId) {
@@ -7186,7 +7399,7 @@ function encodeGrid4(grid, bank, lv, idGen, availWidthHwp) {
7186
7399
  const cellWidthHwp = Metric.ptToHwp(cwPt[c] ?? defColPt);
7187
7400
  for (const para of paras) {
7188
7401
  records.push(
7189
- ...encodePara3(para, bank, lv + 2, idGen(), cellWidthHwp)
7402
+ ...encodePara3(para, bank, lv + 1, idGen(), cellWidthHwp)
7190
7403
  );
7191
7404
  }
7192
7405
  }
@@ -7428,6 +7641,7 @@ function buildHwpFileHeader() {
7428
7641
  }
7429
7642
  function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = []) {
7430
7643
  const SS = 512;
7644
+ const MSS = 64;
7431
7645
  const ENDOFCHAIN = 4294967294;
7432
7646
  const FREESECT = 4294967295;
7433
7647
  const FATSECT = 4294967293;
@@ -7436,71 +7650,150 @@ function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = [])
7436
7650
  `FileHeader \uD06C\uAE30 \uBD80\uC871: ${fileHeaderData.length} (\uCD5C\uC18C 256)`
7437
7651
  );
7438
7652
  }
7439
- function padSector(d) {
7440
- const n = Math.ceil(Math.max(d.length, 1) / SS) * SS;
7441
- if (d.length === n) return d;
7653
+ const streams = [];
7654
+ streams.push({
7655
+ name: "FileHeader",
7656
+ data: fileHeaderData,
7657
+ dirIdx: 1,
7658
+ isMini: fileHeaderData.length < 4096
7659
+ });
7660
+ streams.push({
7661
+ name: "DocInfo",
7662
+ data: docInfoData,
7663
+ dirIdx: 2,
7664
+ isMini: docInfoData.length < 4096
7665
+ });
7666
+ streams.push({
7667
+ name: "Section0",
7668
+ data: section0Data,
7669
+ dirIdx: 4,
7670
+ isMini: section0Data.length < 4096
7671
+ });
7672
+ for (let i = 0; i < binImages.length; i++) {
7673
+ const img = binImages[i];
7674
+ const name = `BIN${String(img.id).padStart(4, "0")}.${img.ext}`;
7675
+ streams.push({
7676
+ name,
7677
+ data: img.data,
7678
+ dirIdx: 6 + i,
7679
+ isMini: img.data.length < 4096
7680
+ });
7681
+ }
7682
+ const miniStreams = streams.filter((s) => s.isMini);
7683
+ const miniSectorList = [];
7684
+ let miniStreamDataLength = 0;
7685
+ for (const s of miniStreams) {
7686
+ const startSec = miniStreamDataLength / MSS;
7687
+ s.startSec = startSec;
7688
+ const len = s.data.length;
7689
+ const numMiniSecs = Math.ceil(len / MSS);
7690
+ for (let i = 0; i < numMiniSecs; i++) {
7691
+ const curSec2 = startSec + i;
7692
+ const nextSec = i === numMiniSecs - 1 ? ENDOFCHAIN : curSec2 + 1;
7693
+ while (miniSectorList.length <= curSec2) {
7694
+ miniSectorList.push(FREESECT);
7695
+ }
7696
+ miniSectorList[curSec2] = nextSec;
7697
+ }
7698
+ miniStreamDataLength += numMiniSecs * MSS;
7699
+ }
7700
+ const miniStreamData = new Uint8Array(miniStreamDataLength);
7701
+ let miniStreamOffset = 0;
7702
+ for (const s of miniStreams) {
7703
+ miniStreamData.set(s.data, miniStreamOffset);
7704
+ miniStreamOffset += Math.ceil(s.data.length / MSS) * MSS;
7705
+ }
7706
+ const regularStreams = streams.filter((s) => !s.isMini);
7707
+ const regPads = regularStreams.map((s) => {
7708
+ const len = s.data.length;
7709
+ const n = Math.ceil(Math.max(len, 1) / SS) * SS;
7442
7710
  const out2 = new Uint8Array(n);
7443
- out2.set(d);
7711
+ out2.set(s.data);
7444
7712
  return out2;
7445
- }
7446
- const fhPad = padSector(fileHeaderData);
7447
- const diPad = padSector(docInfoData);
7448
- const s0Pad = padSector(section0Data);
7449
- const imgPads = binImages.map((img) => padSector(img.data));
7450
- const fhN = fhPad.length / SS;
7451
- const diN = diPad.length / SS;
7452
- const s0N = s0Pad.length / SS;
7453
- const imgNs = imgPads.map((p) => p.length / SS);
7454
- const totalImgN = imgNs.reduce((s, n) => s + n, 0);
7713
+ });
7714
+ const regNs = regPads.map((p) => p.length / SS);
7455
7715
  const numDirEntries = 5 + (binImages.length > 0 ? 1 + binImages.length : 0);
7456
- const dirN = Math.max(2, Math.ceil(numDirEntries / 4));
7716
+ const dirN = Math.max(1, Math.ceil(numDirEntries * 128 / SS));
7717
+ const miniFatN = Math.ceil(miniSectorList.length / 128);
7718
+ const miniStreamN = Math.ceil(miniStreamData.length / SS);
7719
+ const totalRegStreamN = regNs.reduce((a, b) => a + b, 0);
7720
+ const neededDataSec = dirN + miniFatN + miniStreamN + totalRegStreamN;
7457
7721
  let fatN = 1;
7458
7722
  for (let iter = 0; iter < 10; iter++) {
7459
- const total = fatN + dirN + fhN + diN + s0N + totalImgN;
7460
- const needed = Math.ceil(total / 128);
7461
- if (needed <= fatN) break;
7462
- fatN = needed;
7463
- }
7464
- const dir1Sec = fatN;
7465
- const fhSec = dir1Sec + dirN;
7466
- const diSec = fhSec + fhN;
7467
- const s0Sec = diSec + diN;
7468
- const imgSecs = [];
7469
- let curSec = s0Sec + s0N;
7470
- for (const n of imgNs) {
7471
- imgSecs.push(curSec);
7472
- curSec += n;
7473
- }
7474
- const totalSec = curSec;
7723
+ const totalSec2 = fatN + neededDataSec;
7724
+ const neededFat = Math.ceil(totalSec2 / 128);
7725
+ if (neededFat <= fatN) break;
7726
+ fatN = neededFat;
7727
+ }
7728
+ const totalSec = fatN + neededDataSec;
7729
+ const dirStartSec = fatN;
7730
+ const miniFatStartSec = dirStartSec + dirN;
7731
+ const miniStreamStartSec = miniFatStartSec + miniFatN;
7732
+ let curSec = miniStreamStartSec + miniStreamN;
7733
+ for (let i = 0; i < regularStreams.length; i++) {
7734
+ regularStreams[i].startSec = curSec;
7735
+ curSec += regNs[i];
7736
+ }
7475
7737
  const fatBuf = new Uint8Array(fatN * SS).fill(255);
7476
7738
  const setFat = (i, v) => {
7477
- fatBuf[i * 4] = v & 255;
7478
- fatBuf[i * 4 + 1] = v >>> 8 & 255;
7479
- fatBuf[i * 4 + 2] = v >>> 16 & 255;
7480
- fatBuf[i * 4 + 3] = v >>> 24 & 255;
7739
+ const off = i * 4;
7740
+ fatBuf[off] = v & 255;
7741
+ fatBuf[off + 1] = v >>> 8 & 255;
7742
+ fatBuf[off + 2] = v >>> 16 & 255;
7743
+ fatBuf[off + 3] = v >>> 24 & 255;
7481
7744
  };
7482
- for (let i = 0; i < fatN; i++) setFat(i, FATSECT);
7483
- for (let i = 0; i < dirN; i++)
7484
- setFat(dir1Sec + i, i + 1 < dirN ? dir1Sec + i + 1 : ENDOFCHAIN);
7485
- for (let i = 0; i < fhN; i++)
7486
- setFat(fhSec + i, i + 1 < fhN ? fhSec + i + 1 : ENDOFCHAIN);
7487
- for (let i = 0; i < diN; i++)
7488
- setFat(diSec + i, i + 1 < diN ? diSec + i + 1 : ENDOFCHAIN);
7489
- for (let i = 0; i < s0N; i++)
7490
- setFat(s0Sec + i, i + 1 < s0N ? s0Sec + i + 1 : ENDOFCHAIN);
7491
- for (let ii = 0; ii < imgNs.length; ii++) {
7492
- const start = imgSecs[ii];
7493
- const n = imgNs[ii];
7494
- for (let i = 0; i < n; i++)
7495
- setFat(start + i, i + 1 < n ? start + i + 1 : ENDOFCHAIN);
7745
+ for (let i = 0; i < fatN; i++) {
7746
+ setFat(i, FATSECT);
7747
+ }
7748
+ for (let i = 0; i < dirN; i++) {
7749
+ setFat(
7750
+ dirStartSec + i,
7751
+ i + 1 < dirN ? dirStartSec + i + 1 : ENDOFCHAIN
7752
+ );
7753
+ }
7754
+ if (miniFatN > 0) {
7755
+ for (let i = 0; i < miniFatN; i++) {
7756
+ setFat(
7757
+ miniFatStartSec + i,
7758
+ i + 1 < miniFatN ? miniFatStartSec + i + 1 : ENDOFCHAIN
7759
+ );
7760
+ }
7761
+ }
7762
+ if (miniStreamN > 0) {
7763
+ for (let i = 0; i < miniStreamN; i++) {
7764
+ setFat(
7765
+ miniStreamStartSec + i,
7766
+ i + 1 < miniStreamN ? miniStreamStartSec + i + 1 : ENDOFCHAIN
7767
+ );
7768
+ }
7769
+ }
7770
+ for (let i = 0; i < regularStreams.length; i++) {
7771
+ const s = regularStreams[i];
7772
+ const n = regNs[i];
7773
+ const start = s.startSec;
7774
+ for (let j = 0; j < n; j++) {
7775
+ setFat(start + j, j + 1 < n ? start + j + 1 : ENDOFCHAIN);
7776
+ }
7777
+ }
7778
+ const miniFatBuf = new Uint8Array(miniFatN * SS).fill(255);
7779
+ const setMiniFat = (i, v) => {
7780
+ const off = i * 4;
7781
+ miniFatBuf[off] = v & 255;
7782
+ miniFatBuf[off + 1] = v >>> 8 & 255;
7783
+ miniFatBuf[off + 2] = v >>> 16 & 255;
7784
+ miniFatBuf[off + 3] = v >>> 24 & 255;
7785
+ };
7786
+ for (let i = 0; i < miniSectorList.length; i++) {
7787
+ setMiniFat(i, miniSectorList[i]);
7496
7788
  }
7497
7789
  const dirBuf = new Uint8Array(dirN * SS);
7498
7790
  const dv = new DataView(dirBuf.buffer);
7499
7791
  function writeDirEntry(idx, name, type, left, right, child, startSec, size) {
7500
7792
  const base = idx * 128;
7501
7793
  const nl = name.length;
7502
- for (let i = 0; i < nl; i++)
7794
+ for (let i = 0; i < nl; i++) {
7503
7795
  dv.setUint16(base + i * 2, name.charCodeAt(i), true);
7796
+ }
7504
7797
  dv.setUint16(base + 64, (nl + 1) * 2, true);
7505
7798
  dirBuf[base + 66] = type;
7506
7799
  dirBuf[base + 67] = 1;
@@ -7516,35 +7809,20 @@ function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = [])
7516
7809
  dv.setInt32(base + 72, -1, true);
7517
7810
  dv.setInt32(base + 76, -1, true);
7518
7811
  }
7519
- if (binImages.length > 0) {
7520
- writeDirEntry(0, "Root Entry", 5, -1, -1, 1, ENDOFCHAIN, 0);
7521
- writeDirEntry(1, "FileHeader", 2, -1, 2, -1, fhSec, fileHeaderData.length);
7522
- writeDirEntry(2, "DocInfo", 2, -1, 3, -1, diSec, docInfoData.length);
7523
- writeDirEntry(3, "BodyText", 1, -1, 5, 4, ENDOFCHAIN, 0);
7524
- writeDirEntry(4, "Section0", 2, -1, -1, -1, s0Sec, section0Data.length);
7525
- writeDirEntry(5, "BinData", 1, -1, -1, 6, ENDOFCHAIN, 0);
7526
- for (let ii = 0; ii < binImages.length; ii++) {
7527
- const img = binImages[ii];
7528
- const streamName = `BIN${String(img.id).padStart(4, "0")}.${img.ext}`;
7529
- const sibling = ii + 1 < binImages.length ? 7 + ii : -1;
7530
- writeDirEntry(
7531
- 6 + ii,
7532
- streamName,
7533
- 2,
7534
- -1,
7535
- sibling,
7536
- -1,
7537
- imgSecs[ii],
7538
- img.data.length
7539
- );
7540
- }
7541
- } else {
7542
- writeDirEntry(0, "Root Entry", 5, -1, -1, 1, ENDOFCHAIN, 0);
7543
- writeDirEntry(1, "FileHeader", 2, -1, 2, -1, fhSec, fileHeaderData.length);
7544
- writeDirEntry(2, "DocInfo", 2, -1, 3, -1, diSec, docInfoData.length);
7545
- writeDirEntry(3, "BodyText", 1, -1, -1, 4, ENDOFCHAIN, 0);
7546
- writeDirEntry(4, "Section0", 2, -1, -1, -1, s0Sec, section0Data.length);
7812
+ const streamMap = /* @__PURE__ */ new Map();
7813
+ for (const s of streams) {
7814
+ streamMap.set(s.dirIdx, s);
7547
7815
  }
7816
+ writeDirEntry(
7817
+ 0,
7818
+ "Root Entry",
7819
+ 5,
7820
+ -1,
7821
+ -1,
7822
+ 3,
7823
+ miniStreamStartSec,
7824
+ miniStreamData.length
7825
+ );
7548
7826
  const HWP_CLSID = [
7549
7827
  32,
7550
7828
  233,
@@ -7563,7 +7841,61 @@ function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = [])
7563
7841
  155,
7564
7842
  113
7565
7843
  ];
7566
- for (let i = 0; i < 16; i++) dirBuf[80 + i] = HWP_CLSID[i];
7844
+ for (let i = 0; i < 16; i++) {
7845
+ dirBuf[0 * 128 + 80 + i] = HWP_CLSID[i];
7846
+ }
7847
+ const fhStream = streamMap.get(1);
7848
+ writeDirEntry(
7849
+ 1,
7850
+ "FileHeader",
7851
+ 2,
7852
+ -1,
7853
+ -1,
7854
+ -1,
7855
+ fhStream.startSec,
7856
+ fhStream.data.length
7857
+ );
7858
+ const diStream = streamMap.get(2);
7859
+ const docInfoLeft = binImages.length > 0 ? 5 : -1;
7860
+ writeDirEntry(
7861
+ 2,
7862
+ "DocInfo",
7863
+ 2,
7864
+ docInfoLeft,
7865
+ -1,
7866
+ -1,
7867
+ diStream.startSec,
7868
+ diStream.data.length
7869
+ );
7870
+ writeDirEntry(3, "BodyText", 1, 2, 1, 4, ENDOFCHAIN, 0);
7871
+ const s0Stream = streamMap.get(4);
7872
+ writeDirEntry(
7873
+ 4,
7874
+ "Section0",
7875
+ 2,
7876
+ -1,
7877
+ -1,
7878
+ -1,
7879
+ s0Stream.startSec,
7880
+ s0Stream.data.length
7881
+ );
7882
+ if (binImages.length > 0) {
7883
+ writeDirEntry(5, "BinData", 1, -1, -1, 6, ENDOFCHAIN, 0);
7884
+ for (let i = 0; i < binImages.length; i++) {
7885
+ const imgStream = streamMap.get(6 + i);
7886
+ const sibling = i + 1 < binImages.length ? 7 + i : -1;
7887
+ writeDirEntry(
7888
+ 6 + i,
7889
+ imgStream.name,
7890
+ 2,
7891
+ -1,
7892
+ sibling,
7893
+ -1,
7894
+ imgStream.startSec,
7895
+ imgStream.data.length
7896
+ );
7897
+ }
7898
+ }
7567
7899
  const hdr = new Uint8Array(SS);
7568
7900
  const hdv = new DataView(hdr.buffer);
7569
7901
  const MAGIC = [208, 207, 17, 224, 161, 177, 26, 225];
@@ -7572,32 +7904,43 @@ function buildHwpOle2(fileHeaderData, docInfoData, section0Data, binImages = [])
7572
7904
  });
7573
7905
  hdv.setUint16(24, 62, true);
7574
7906
  hdv.setUint16(26, 3, true);
7575
- hdv.setUint16(28, 254, true);
7907
+ hdv.setUint16(28, 65534, true);
7576
7908
  hdv.setUint16(30, 9, true);
7577
7909
  hdv.setUint16(32, 6, true);
7578
- hdv.setUint32(40, fatN, true);
7579
- hdv.setUint32(44, dir1Sec, true);
7580
- hdv.setUint32(48, 0, true);
7581
- hdv.setUint32(52, 4096, true);
7582
- hdv.setUint32(56, ENDOFCHAIN, true);
7583
- hdv.setUint32(60, 0, true);
7584
- hdv.setUint32(64, ENDOFCHAIN, true);
7585
- hdv.setUint32(68, 0, true);
7910
+ hdv.setUint32(40, 0, true);
7911
+ hdv.setUint32(44, fatN, true);
7912
+ hdv.setUint32(48, dirStartSec, true);
7913
+ hdv.setUint32(52, 0, true);
7914
+ hdv.setUint32(56, 4096, true);
7915
+ hdv.setUint32(60, miniFatN > 0 ? miniFatStartSec : ENDOFCHAIN, true);
7916
+ hdv.setUint32(64, miniFatN, true);
7917
+ hdv.setUint32(68, ENDOFCHAIN, true);
7586
7918
  hdv.setUint32(72, 0, true);
7587
7919
  for (let i = 0; i < 109; i++) {
7588
7920
  hdv.setUint32(76 + i * 4, i < fatN ? i : FREESECT, true);
7589
7921
  }
7590
7922
  const out = new Uint8Array(SS + totalSec * SS);
7591
- out.set(hdr, 0);
7592
- for (let i = 0; i < fatN; i++)
7593
- out.set(fatBuf.subarray(i * SS, (i + 1) * SS), SS + i * SS);
7594
- for (let i = 0; i < dirN; i++)
7595
- out.set(dirBuf.subarray(i * SS, (i + 1) * SS), SS + (dir1Sec + i) * SS);
7596
- out.set(fhPad, SS + fhSec * SS);
7597
- out.set(diPad, SS + diSec * SS);
7598
- out.set(s0Pad, SS + s0Sec * SS);
7599
- for (let ii = 0; ii < imgPads.length; ii++)
7600
- out.set(imgPads[ii], SS + imgSecs[ii] * SS);
7923
+ let outOff = 0;
7924
+ out.set(hdr, outOff);
7925
+ outOff += SS;
7926
+ out.set(fatBuf, outOff);
7927
+ outOff += fatN * SS;
7928
+ out.set(dirBuf, outOff);
7929
+ outOff += dirN * SS;
7930
+ if (miniFatN > 0) {
7931
+ out.set(miniFatBuf, outOff);
7932
+ outOff += miniFatN * SS;
7933
+ }
7934
+ if (miniStreamN > 0) {
7935
+ const miniStreamPad = new Uint8Array(miniStreamN * SS);
7936
+ miniStreamPad.set(miniStreamData);
7937
+ out.set(miniStreamPad, outOff);
7938
+ outOff += miniStreamN * SS;
7939
+ }
7940
+ for (let i = 0; i < regularStreams.length; i++) {
7941
+ out.set(regPads[i], outOff);
7942
+ outOff += regNs[i] * SS;
7943
+ }
7601
7944
  return out;
7602
7945
  }
7603
7946
  function concatU8(arrays) {