kordoc 4.3.0 → 4.4.0
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/NOTICE +176 -0
- package/README.md +936 -922
- package/THIRD_PARTY/apache-2.0.LICENSE +201 -0
- package/THIRD_PARTY/claw-hwp.LICENSE +21 -0
- package/THIRD_PARTY/hml-equation-parser.LICENSE +201 -0
- package/THIRD_PARTY/hml-equation-parser.txt +35 -0
- package/THIRD_PARTY/opendataloader-pdf.txt +32 -0
- package/THIRD_PARTY/pix2text.txt +17 -0
- package/THIRD_PARTY/rhwp-forms.txt +35 -0
- package/dist/{-DYHT3HWH.js → -R6NUMPRV.js} +11 -11
- package/dist/{chunk-3FFPHTXD.js → chunk-3H5X63BQ.js} +1 -1
- package/dist/chunk-3H5X63BQ.js.map +1 -0
- package/dist/{chunk-EFVAY5VE.js → chunk-5KLE3U23.js} +7 -4
- package/dist/chunk-5KLE3U23.js.map +1 -0
- package/dist/{chunk-6GBLFQMA.js → chunk-5RPYBC2Q.js} +1 -1
- package/dist/chunk-5RPYBC2Q.js.map +1 -0
- package/dist/{chunk-VXMLENCV.js → chunk-65DYCXGC.js} +4 -4
- package/dist/chunk-65DYCXGC.js.map +1 -0
- package/dist/{chunk-W34QSJFF.js → chunk-7FCNOKOR.js} +1 -1
- package/dist/chunk-7FCNOKOR.js.map +1 -0
- package/dist/{chunk-ZSL6MQVE.js → chunk-A73RMJ6B.js} +1 -1
- package/dist/chunk-A73RMJ6B.js.map +1 -0
- package/dist/{chunk-AL34DGS5.cjs → chunk-AB322K3O.cjs} +6 -6
- package/dist/chunk-AB322K3O.cjs.map +1 -0
- package/dist/chunk-DCZVOIEO.cjs.map +1 -1
- package/dist/{chunk-O5EK52TG.js → chunk-DZIXKL7E.js} +1 -1
- package/dist/chunk-DZIXKL7E.js.map +1 -0
- package/dist/{chunk-EZHW3RNQ.js → chunk-GHGZU2LQ.js} +2 -2
- package/dist/chunk-GHGZU2LQ.js.map +1 -0
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-6XPXIG57.js → chunk-GZDOWYJM.js} +2 -2
- package/dist/chunk-GZDOWYJM.js.map +1 -0
- package/dist/{chunk-JFV7QT5T.cjs → chunk-H2KMJOB6.cjs} +2 -2
- package/dist/chunk-H2KMJOB6.cjs.map +1 -0
- package/dist/{chunk-6RAYTNQT.js → chunk-HFJF477F.js} +3 -3
- package/dist/chunk-HFJF477F.js.map +1 -0
- package/dist/{chunk-SPKBIFSK.js → chunk-HNRULYUH.js} +2 -2
- package/dist/chunk-HNRULYUH.js.map +1 -0
- package/dist/chunk-MOL7MDBG.js +0 -0
- package/dist/{chunk-7MFO4TKP.js → chunk-ONS7JKVA.js} +2 -2
- package/dist/chunk-ONS7JKVA.js.map +1 -0
- package/dist/{chunk-DRQUAYNT.js → chunk-P7YPCK7C.js} +2 -2
- package/dist/chunk-P7YPCK7C.js.map +1 -0
- package/dist/{chunk-GSMPTZC7.js → chunk-QXYB74QF.js} +24 -3
- package/dist/chunk-QXYB74QF.js.map +1 -0
- package/dist/{chunk-NMWXBJ5B.js → chunk-RZURSA4N.js} +6 -4
- package/dist/chunk-RZURSA4N.js.map +1 -0
- package/dist/{chunk-LPQWKQQQ.cjs → chunk-SKM6KZUH.cjs} +9 -9
- package/dist/chunk-SKM6KZUH.cjs.map +1 -0
- package/dist/{chunk-YNJDNP44.js → chunk-UAFSPWU7.js} +1 -1
- package/dist/chunk-UAFSPWU7.js.map +1 -0
- package/dist/{chunk-AUOEZKJE.cjs → chunk-UDGPM5R5.cjs} +26 -5
- package/dist/chunk-UDGPM5R5.cjs.map +1 -0
- package/dist/{chunk-WFOQFJI4.js → chunk-V35DRUJC.js} +2 -2
- package/dist/chunk-V35DRUJC.js.map +1 -0
- package/dist/{chunk-4DBCUF3C.js → chunk-W6CUD7V3.js} +3 -3
- package/dist/chunk-W6CUD7V3.js.map +1 -0
- package/dist/{chunk-US4WFSIQ.js → chunk-XCIC7U6Y.js} +24 -3
- package/dist/chunk-XCIC7U6Y.js.map +1 -0
- package/dist/{chunk-DRZUJ2RK.js → chunk-YOZ7ZRCD.js} +366 -51
- package/dist/chunk-YOZ7ZRCD.js.map +1 -0
- package/dist/{chunk-ARXNKC5D.js → chunk-YVYU267E.js} +3 -3
- package/dist/chunk-YVYU267E.js.map +1 -0
- package/dist/{chunk-MGGU3ZRK.cjs → chunk-ZV5OKQ3Z.cjs} +1 -1
- package/dist/chunk-ZV5OKQ3Z.cjs.map +1 -0
- package/dist/chunks-QMGCI5DG.js +10 -0
- package/dist/cli.js +28 -24
- package/dist/cli.js.map +1 -1
- package/dist/{formula-IWV5IJ3Y.cjs → formula-CG4S7TWO.cjs} +8 -8
- package/dist/formula-CG4S7TWO.cjs.map +1 -0
- package/dist/{formula-7ZPC54JO.js → formula-JLYS73QL.js} +2 -2
- package/dist/formula-JLYS73QL.js.map +1 -0
- package/dist/{formula-EQRHSMYW.js → formula-LIVQSCMM.js} +2 -2
- package/dist/formula-LIVQSCMM.js.map +1 -0
- package/dist/{image-ocr-XEJFXH6M.cjs → image-ocr-F2BQA26V.cjs} +11 -11
- package/dist/image-ocr-F2BQA26V.cjs.map +1 -0
- package/dist/{image-ocr-G2LYTEUH.js → image-ocr-U2DRRFL3.js} +5 -5
- package/dist/image-ocr-U2DRRFL3.js.map +1 -0
- package/dist/{image-ocr-R44RYDBU.js → image-ocr-XC52AQDV.js} +7 -7
- package/dist/image-ocr-XC52AQDV.js.map +1 -0
- package/dist/index.cjs +858 -537
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +373 -52
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +24 -22
- package/dist/mcp.js.map +1 -1
- package/dist/{models-6VMAVZR6.js → models-6SIKLKRH.js} +3 -3
- package/dist/page-range-737B4EZW.js +0 -0
- package/dist/page-range-P7SDW6LR.cjs.map +1 -1
- package/dist/{parser-W3POOYQQ.js → parser-ESGFWWCT.js} +8 -8
- package/dist/parser-ESGFWWCT.js.map +1 -0
- package/dist/{parser-W3ZGQUCQ.cjs → parser-FFQN67O6.cjs} +25 -25
- package/dist/parser-FFQN67O6.cjs.map +1 -0
- package/dist/{parser-2G245MMN.js → parser-TFPGQWCC.js} +6 -6
- package/dist/parser-TFPGQWCC.js.map +1 -0
- package/dist/pdf-ocr-4R646OO6.js +12 -0
- package/dist/pdf-ocr-UQBZH3HE.cjs +13 -0
- package/dist/pdf-ocr-UQBZH3HE.cjs.map +1 -0
- package/dist/pdf-ocr-WE5TMRFU.js +15 -0
- package/dist/{profile-io-72R3B7KO.js → profile-io-O6BDCUJN.js} +3 -3
- package/dist/{rasterize-GNJQVURE.js → rasterize-V22VCCE7.js} +2 -2
- package/dist/rasterize-V22VCCE7.js.map +1 -0
- package/dist/{redact-W5K3ILQH.js → redact-7ILEAUTS.js} +2 -2
- package/dist/render-3BSVTTZE.js +10 -0
- package/dist/seal-6ZSEJVOD.js +10 -0
- package/dist/{setup-I4I75QJU.js → setup-GUQT5ELJ.js} +1 -1
- package/dist/setup-GUQT5ELJ.js.map +1 -0
- package/dist/{watch-2ADAJLIJ.js → watch-HGKBICED.js} +11 -11
- package/dist/watch-HGKBICED.js.map +1 -0
- package/package.json +103 -101
- package/templates//352/260/204/354/235/264/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +9 -9
- package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/204/234/354/213/235.hwpx +0 -0
- package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +24 -24
- package/dist/chunk-3FFPHTXD.js.map +0 -1
- package/dist/chunk-4DBCUF3C.js.map +0 -1
- package/dist/chunk-6GBLFQMA.js.map +0 -1
- package/dist/chunk-6RAYTNQT.js.map +0 -1
- package/dist/chunk-6XPXIG57.js.map +0 -1
- package/dist/chunk-7MFO4TKP.js.map +0 -1
- package/dist/chunk-AL34DGS5.cjs.map +0 -1
- package/dist/chunk-ARXNKC5D.js.map +0 -1
- package/dist/chunk-AUOEZKJE.cjs.map +0 -1
- package/dist/chunk-DRQUAYNT.js.map +0 -1
- package/dist/chunk-DRZUJ2RK.js.map +0 -1
- package/dist/chunk-EFVAY5VE.js.map +0 -1
- package/dist/chunk-EZHW3RNQ.js.map +0 -1
- package/dist/chunk-GSMPTZC7.js.map +0 -1
- package/dist/chunk-JFV7QT5T.cjs.map +0 -1
- package/dist/chunk-LPQWKQQQ.cjs.map +0 -1
- package/dist/chunk-MGGU3ZRK.cjs.map +0 -1
- package/dist/chunk-NMWXBJ5B.js.map +0 -1
- package/dist/chunk-O5EK52TG.js.map +0 -1
- package/dist/chunk-SPKBIFSK.js.map +0 -1
- package/dist/chunk-US4WFSIQ.js.map +0 -1
- package/dist/chunk-VXMLENCV.js.map +0 -1
- package/dist/chunk-W34QSJFF.js.map +0 -1
- package/dist/chunk-WFOQFJI4.js.map +0 -1
- package/dist/chunk-YNJDNP44.js.map +0 -1
- package/dist/chunk-ZSL6MQVE.js.map +0 -1
- package/dist/chunks-Q7T4SQGW.js +0 -10
- package/dist/formula-7ZPC54JO.js.map +0 -1
- package/dist/formula-EQRHSMYW.js.map +0 -1
- package/dist/formula-IWV5IJ3Y.cjs.map +0 -1
- package/dist/image-ocr-G2LYTEUH.js.map +0 -1
- package/dist/image-ocr-R44RYDBU.js.map +0 -1
- package/dist/image-ocr-XEJFXH6M.cjs.map +0 -1
- package/dist/parser-2G245MMN.js.map +0 -1
- package/dist/parser-W3POOYQQ.js.map +0 -1
- package/dist/parser-W3ZGQUCQ.cjs.map +0 -1
- package/dist/pdf-ocr-3GDTJSHF.js +0 -15
- package/dist/pdf-ocr-N7IU23UV.cjs +0 -13
- package/dist/pdf-ocr-N7IU23UV.cjs.map +0 -1
- package/dist/pdf-ocr-U7MEGNBZ.js +0 -12
- package/dist/rasterize-GNJQVURE.js.map +0 -1
- package/dist/render-6OW6U4L4.js +0 -10
- package/dist/seal-GTNLVBJX.js +0 -10
- package/dist/setup-I4I75QJU.js.map +0 -1
- package/dist/watch-2ADAJLIJ.js.map +0 -1
- /package/dist/{-DYHT3HWH.js.map → -R6NUMPRV.js.map} +0 -0
- /package/dist/{chunks-Q7T4SQGW.js.map → chunks-QMGCI5DG.js.map} +0 -0
- /package/dist/{models-6VMAVZR6.js.map → models-6SIKLKRH.js.map} +0 -0
- /package/dist/{pdf-ocr-3GDTJSHF.js.map → pdf-ocr-4R646OO6.js.map} +0 -0
- /package/dist/{pdf-ocr-U7MEGNBZ.js.map → pdf-ocr-WE5TMRFU.js.map} +0 -0
- /package/dist/{profile-io-72R3B7KO.js.map → profile-io-O6BDCUJN.js.map} +0 -0
- /package/dist/{redact-W5K3ILQH.js.map → redact-7ILEAUTS.js.map} +0 -0
- /package/dist/{render-6OW6U4L4.js.map → render-3BSVTTZE.js.map} +0 -0
- /package/dist/{seal-GTNLVBJX.js.map → seal-6ZSEJVOD.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
flattenLayoutTables,
|
|
9
9
|
inlineImagesIntoMarkdown,
|
|
10
10
|
mapPuaText
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XCIC7U6Y.js";
|
|
12
12
|
import {
|
|
13
13
|
parsePageRange
|
|
14
14
|
} from "./chunk-GE43BE46.js";
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
sanitizeHref,
|
|
28
28
|
stripDtd,
|
|
29
29
|
toArrayBuffer
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ONS7JKVA.js";
|
|
31
31
|
|
|
32
32
|
// src/index.ts
|
|
33
33
|
import { readFile } from "fs/promises";
|
|
@@ -406,6 +406,10 @@ function comResultToParseResult(pages, pageCount, warnings) {
|
|
|
406
406
|
};
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
+
// src/hwpx/crypto.ts
|
|
410
|
+
import { createDecipheriv, createHash, pbkdf2Sync, timingSafeEqual } from "crypto";
|
|
411
|
+
import { inflateRawSync } from "zlib";
|
|
412
|
+
|
|
409
413
|
// src/hwpx/parser-shared.ts
|
|
410
414
|
import { DOMParser } from "@xmldom/xmldom";
|
|
411
415
|
|
|
@@ -444,6 +448,9 @@ function elementChildren(parent) {
|
|
|
444
448
|
}
|
|
445
449
|
return out;
|
|
446
450
|
}
|
|
451
|
+
function isTextNode(node) {
|
|
452
|
+
return node.nodeType === 3 || node.nodeType === 4;
|
|
453
|
+
}
|
|
447
454
|
function extractTextFromNode(node, depth = 0) {
|
|
448
455
|
let result = "";
|
|
449
456
|
if (depth > MAX_XML_DEPTH) return result;
|
|
@@ -451,7 +458,7 @@ function extractTextFromNode(node, depth = 0) {
|
|
|
451
458
|
if (!children) return result;
|
|
452
459
|
for (let i = 0; i < children.length; i++) {
|
|
453
460
|
const child = children[i];
|
|
454
|
-
if (child
|
|
461
|
+
if (isTextNode(child)) result += child.textContent || "";
|
|
455
462
|
else if (child.nodeType === 1) result += extractTextFromNode(child, depth + 1);
|
|
456
463
|
}
|
|
457
464
|
return result.trim();
|
|
@@ -463,7 +470,7 @@ function rawTextContent(node, depth = 0) {
|
|
|
463
470
|
const parts = [];
|
|
464
471
|
for (let i = 0; i < children.length; i++) {
|
|
465
472
|
const child = children[i];
|
|
466
|
-
if (child
|
|
473
|
+
if (isTextNode(child)) parts.push(child.nodeValue || "");
|
|
467
474
|
else if (child.nodeType === 1) parts.push(rawTextContent(child, depth + 1));
|
|
468
475
|
}
|
|
469
476
|
return parts.join("");
|
|
@@ -502,6 +509,89 @@ function applyPageText(blocks, shared) {
|
|
|
502
509
|
}
|
|
503
510
|
}
|
|
504
511
|
|
|
512
|
+
// src/hwpx/crypto.ts
|
|
513
|
+
var MAX_ITERATION_COUNT = 1e6;
|
|
514
|
+
var AES256_CBC = "http://www.w3.org/2001/04/xmlenc#aes256-cbc";
|
|
515
|
+
var START_KEY_SHA256 = "http://www.w3.org/2000/09/xmldsig#sha256";
|
|
516
|
+
var CHECKSUM_SHA256_1K = "sha256-1k";
|
|
517
|
+
var CHECKSUM_PREFIX_BYTES = 1024;
|
|
518
|
+
var attrOf = (xml, name) => xml.match(new RegExp(`${name}="([^"]*)"`))?.[1];
|
|
519
|
+
function parseEncryptionManifest(manifestXml) {
|
|
520
|
+
const entries = [];
|
|
521
|
+
const entryRe = /<[^:>\s]*:?file-entry\b([^>]*)>([\s\S]*?)<\/[^:>\s]*:?file-entry>/g;
|
|
522
|
+
let m;
|
|
523
|
+
while ((m = entryRe.exec(manifestXml)) !== null) {
|
|
524
|
+
const [, attrs, inner] = m;
|
|
525
|
+
if (!inner.includes("encryption-data")) continue;
|
|
526
|
+
const path = attrOf(attrs, "full-path");
|
|
527
|
+
if (!path) continue;
|
|
528
|
+
const algorithm = attrOf(inner, "algorithm-name");
|
|
529
|
+
const startKey = attrOf(inner, "start-key-generation-name");
|
|
530
|
+
const checksumType = attrOf(inner, "checksum-type");
|
|
531
|
+
if (algorithm !== AES256_CBC) {
|
|
532
|
+
throw new KordocError(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWPX \uC554\uD638\uD654 \uBC29\uC2DD\uC785\uB2C8\uB2E4: ${algorithm ?? "(\uBBF8\uC0C1)"}`);
|
|
533
|
+
}
|
|
534
|
+
if (startKey !== START_KEY_SHA256) {
|
|
535
|
+
throw new KordocError(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWPX \uC2DC\uC791\uD0A4 \uC0DD\uC131 \uBC29\uC2DD\uC785\uB2C8\uB2E4: ${startKey ?? "(\uBBF8\uC0C1)"}`);
|
|
536
|
+
}
|
|
537
|
+
if (!checksumType?.endsWith(CHECKSUM_SHA256_1K)) {
|
|
538
|
+
throw new KordocError(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWPX \uCCB4\uD06C\uC12C \uBC29\uC2DD\uC785\uB2C8\uB2E4: ${checksumType ?? "(\uBBF8\uC0C1)"}`);
|
|
539
|
+
}
|
|
540
|
+
const iterations = parseInt(attrOf(inner, "iteration-count") ?? "", 10);
|
|
541
|
+
const keySize = parseInt(attrOf(inner, "key-size") ?? "", 10);
|
|
542
|
+
const iv = Buffer.from(attrOf(inner, "initialisation-vector") ?? "", "base64");
|
|
543
|
+
const salt = Buffer.from(attrOf(inner, "salt") ?? "", "base64");
|
|
544
|
+
const checksum = Buffer.from(attrOf(inner, "checksum") ?? "", "base64");
|
|
545
|
+
if (!(iterations > 0 && iterations <= MAX_ITERATION_COUNT)) {
|
|
546
|
+
throw new KordocError(`HWPX \uC554\uD638\uD654 \uBC18\uBCF5 \uD69F\uC218\uAC00 \uD5C8\uC6A9 \uBC94\uC704\uB97C \uBC97\uC5B4\uB0AC\uC2B5\uB2C8\uB2E4: ${iterations}`);
|
|
547
|
+
}
|
|
548
|
+
if (keySize !== 32 || iv.length !== 16 || salt.length === 0 || checksum.length !== 32) {
|
|
549
|
+
throw new KordocError(`HWPX \uC554\uD638\uD654 \uD30C\uB77C\uBBF8\uD130\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (${path})`);
|
|
550
|
+
}
|
|
551
|
+
entries.push({ path, checksum, iv, salt, iterations, keySize });
|
|
552
|
+
}
|
|
553
|
+
return entries;
|
|
554
|
+
}
|
|
555
|
+
function stripEncryptionData(manifestXml) {
|
|
556
|
+
return manifestXml.replace(/<([^:>\s]*:?)encryption-data\b[\s\S]*?<\/\1encryption-data>/g, "");
|
|
557
|
+
}
|
|
558
|
+
function decryptEntry(cipher, entry, startKey) {
|
|
559
|
+
if (cipher.length === 0 || cipher.length % 16 !== 0) return void 0;
|
|
560
|
+
for (const prf of ["sha1", "sha256"]) {
|
|
561
|
+
try {
|
|
562
|
+
const key = pbkdf2Sync(startKey, entry.salt, entry.iterations, entry.keySize, prf);
|
|
563
|
+
const decipher = createDecipheriv("aes-256-cbc", key, entry.iv);
|
|
564
|
+
decipher.setAutoPadding(false);
|
|
565
|
+
const raw = Buffer.concat([decipher.update(cipher), decipher.final()]);
|
|
566
|
+
const plain = inflateRawSync(raw, { maxOutputLength: MAX_DECOMPRESS_SIZE });
|
|
567
|
+
const sum = createHash("sha256").update(plain.subarray(0, Math.min(CHECKSUM_PREFIX_BYTES, plain.length))).digest();
|
|
568
|
+
if (sum.length === entry.checksum.length && timingSafeEqual(sum, entry.checksum)) return plain;
|
|
569
|
+
} catch {
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return void 0;
|
|
573
|
+
}
|
|
574
|
+
async function decryptHwpxInPlace(zip, manifestXml, password) {
|
|
575
|
+
const entries = parseEncryptionManifest(manifestXml);
|
|
576
|
+
if (entries.length === 0) return 0;
|
|
577
|
+
const startKey = createHash("sha256").update(Buffer.from(password, "utf8")).digest();
|
|
578
|
+
const decrypted = [];
|
|
579
|
+
for (const entry of entries) {
|
|
580
|
+
const file = zip.file(entry.path);
|
|
581
|
+
if (!file) {
|
|
582
|
+
throw new KordocError(`\uC554\uD638 \uBAA9\uB85D\uC5D0 \uC788\uB294 \uD30C\uC77C\uC774 \uBB38\uC11C\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4: ${entry.path}`);
|
|
583
|
+
}
|
|
584
|
+
const plain = decryptEntry(await file.async("nodebuffer"), entry, startKey);
|
|
585
|
+
if (!plain) {
|
|
586
|
+
throw new KordocError("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uAC70\uB098 \uC554\uD638\uD654 \uB370\uC774\uD130\uAC00 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
587
|
+
}
|
|
588
|
+
decrypted.push({ path: entry.path, plain });
|
|
589
|
+
}
|
|
590
|
+
for (const { path, plain } of decrypted) zip.file(path, plain);
|
|
591
|
+
zip.file("META-INF/manifest.xml", stripEncryptionData(manifestXml));
|
|
592
|
+
return decrypted.length;
|
|
593
|
+
}
|
|
594
|
+
|
|
505
595
|
// src/hwpx/styles.ts
|
|
506
596
|
function isRealStrikeShape(shape) {
|
|
507
597
|
switch (shape) {
|
|
@@ -1196,8 +1286,8 @@ function hmlToLatex(hmlEqStr) {
|
|
|
1196
1286
|
let tokens = s.split(" ");
|
|
1197
1287
|
for (let i = 0; i < tokens.length; i++) {
|
|
1198
1288
|
const t = tokens[i];
|
|
1199
|
-
if (t
|
|
1200
|
-
else if (t
|
|
1289
|
+
if (Object.hasOwn(CONVERT_MAP, t)) tokens[i] = CONVERT_MAP[t];
|
|
1290
|
+
else if (Object.hasOwn(MIDDLE_CONVERT_MAP, t)) tokens[i] = MIDDLE_CONVERT_MAP[t];
|
|
1201
1291
|
else {
|
|
1202
1292
|
const quoted = /^"(.+)"$/.exec(t);
|
|
1203
1293
|
if (quoted) tokens[i] = `\\text{${quoted[1]}}`;
|
|
@@ -2058,7 +2148,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
2058
2148
|
if (!children) return;
|
|
2059
2149
|
for (let i = 0; i < children.length; i++) {
|
|
2060
2150
|
const child = children[i];
|
|
2061
|
-
if (child.nodeType === 3) {
|
|
2151
|
+
if (child.nodeType === 3 || child.nodeType === 4) {
|
|
2062
2152
|
const t = child.textContent || "";
|
|
2063
2153
|
if (isInDeletedRange(ctx)) {
|
|
2064
2154
|
if (t && ctx && !ctx.shared.track.warned) {
|
|
@@ -2269,7 +2359,7 @@ function extractRunSpans(para2, ctx, mode, requireMixed) {
|
|
|
2269
2359
|
const tkids = rc.childNodes;
|
|
2270
2360
|
for (let k = 0; k < (tkids?.length ?? 0); k++) {
|
|
2271
2361
|
const tk = tkids[k];
|
|
2272
|
-
if (tk.nodeType === 3) text += tk.textContent || "";
|
|
2362
|
+
if (tk.nodeType === 3 || tk.nodeType === 4) text += tk.textContent || "";
|
|
2273
2363
|
else if (tk.nodeType === 1) return null;
|
|
2274
2364
|
}
|
|
2275
2365
|
} else if (rtag === "secPr" || rtag === "colPr") {
|
|
@@ -2327,7 +2417,7 @@ function gongmunDepthFromIndent(para2, left, ctx) {
|
|
|
2327
2417
|
}
|
|
2328
2418
|
|
|
2329
2419
|
// src/hwp5/record.ts
|
|
2330
|
-
import { inflateRawSync, inflateSync } from "zlib";
|
|
2420
|
+
import { inflateRawSync as inflateRawSync2, inflateSync } from "zlib";
|
|
2331
2421
|
var TAG_PARA_HEADER = 66;
|
|
2332
2422
|
var TAG_PARA_TEXT = 67;
|
|
2333
2423
|
var TAG_CHAR_SHAPE = 68;
|
|
@@ -2385,7 +2475,7 @@ function decompressStream(data) {
|
|
|
2385
2475
|
} catch {
|
|
2386
2476
|
}
|
|
2387
2477
|
}
|
|
2388
|
-
return
|
|
2478
|
+
return inflateRawSync2(data, opts);
|
|
2389
2479
|
}
|
|
2390
2480
|
function parseFileHeader(data) {
|
|
2391
2481
|
if (data.length < 40) throw new KordocError("FileHeader\uAC00 \uB108\uBB34 \uC9E7\uC2B5\uB2C8\uB2E4 (\uCD5C\uC18C 40\uBC14\uC774\uD2B8)");
|
|
@@ -2906,7 +2996,7 @@ async function extractImagesFromZip(zip, blocks, decompressed, warnings, sweepUn
|
|
|
2906
2996
|
import JSZip2 from "jszip";
|
|
2907
2997
|
|
|
2908
2998
|
// src/hwpx/zip-sections.ts
|
|
2909
|
-
import { inflateRawSync as
|
|
2999
|
+
import { inflateRawSync as inflateRawSync3 } from "zlib";
|
|
2910
3000
|
function extractFromBrokenZip(buffer) {
|
|
2911
3001
|
const data = new Uint8Array(buffer);
|
|
2912
3002
|
const view = new DataView(buffer);
|
|
@@ -2957,7 +3047,7 @@ function extractFromBrokenZip(buffer) {
|
|
|
2957
3047
|
if (method === 0) {
|
|
2958
3048
|
content = new TextDecoder().decode(fileData);
|
|
2959
3049
|
} else if (method === 8) {
|
|
2960
|
-
const decompressed =
|
|
3050
|
+
const decompressed = inflateRawSync3(Buffer.from(fileData), { maxOutputLength: MAX_DECOMPRESS_SIZE });
|
|
2961
3051
|
content = new TextDecoder().decode(decompressed);
|
|
2962
3052
|
} else {
|
|
2963
3053
|
continue;
|
|
@@ -3082,13 +3172,19 @@ async function parseHwpxDocument(buffer, options) {
|
|
|
3082
3172
|
if (manifestFile) {
|
|
3083
3173
|
const manifestXml = await manifestFile.async("text");
|
|
3084
3174
|
if (isEncryptedHwpx(manifestXml)) {
|
|
3085
|
-
if (
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3175
|
+
if (options?.password) {
|
|
3176
|
+
await decryptHwpxInPlace(zip, manifestXml, options.password);
|
|
3177
|
+
} else {
|
|
3178
|
+
if (isComFallbackAvailable() && options?.filePath) {
|
|
3179
|
+
const { pages, pageCount, warnings: warnings2 } = extractTextViaCom(options.filePath);
|
|
3180
|
+
if (pages.some((p) => p && p.trim().length > 0)) {
|
|
3181
|
+
return comResultToParseResult(pages, pageCount, warnings2);
|
|
3182
|
+
}
|
|
3089
3183
|
}
|
|
3184
|
+
throw new KordocError(
|
|
3185
|
+
"\uC554\uD638\uB85C \uBCF4\uD638\uB41C HWPX \uD30C\uC77C\uC785\uB2C8\uB2E4. password \uC635\uC158\uC5D0 \uC5F4\uAE30 \uC554\uD638\uB97C \uC9C0\uC815\uD558\uC138\uC694."
|
|
3186
|
+
);
|
|
3090
3187
|
}
|
|
3091
|
-
throw new KordocError("DRM \uC554\uD638\uD654\uB41C HWPX \uD30C\uC77C\uC785\uB2C8\uB2E4. Windows + \uD55C\uCEF4 \uC624\uD53C\uC2A4 \uC124\uCE58 \uC2DC \uC790\uB3D9 \uCD94\uCD9C\uB429\uB2C8\uB2E4.");
|
|
3092
3188
|
}
|
|
3093
3189
|
}
|
|
3094
3190
|
const decompressed = { total: 0 };
|
|
@@ -4043,11 +4139,11 @@ var WORD_ALIASES = {
|
|
|
4043
4139
|
var STRUCTURAL_FOLD = /* @__PURE__ */ new Set(["over", "root", "of"]);
|
|
4044
4140
|
function normalizeWords(input) {
|
|
4045
4141
|
return input.replace(/(?<![\\A-Za-z0-9])([A-Za-z][A-Za-z0-9]*)(?![A-Za-z0-9])/g, (word) => {
|
|
4046
|
-
if (
|
|
4142
|
+
if (Object.hasOwn(CONVERT_MAP, word) || Object.hasOwn(MIDDLE_CONVERT_MAP, word)) return word;
|
|
4047
4143
|
const lower = word.toLowerCase();
|
|
4048
4144
|
if (STRUCTURAL_FOLD.has(lower)) return lower;
|
|
4049
|
-
if (lower
|
|
4050
|
-
if (lower !== word && (
|
|
4145
|
+
if (Object.hasOwn(WORD_ALIASES, lower)) return WORD_ALIASES[lower];
|
|
4146
|
+
if (lower !== word && (Object.hasOwn(CONVERT_MAP, lower) || Object.hasOwn(MIDDLE_CONVERT_MAP, lower))) return lower;
|
|
4051
4147
|
return word;
|
|
4052
4148
|
});
|
|
4053
4149
|
}
|
|
@@ -4067,6 +4163,84 @@ function hwpEquationToLatex(equation) {
|
|
|
4067
4163
|
return hmlToLatex(s).replace(/\s+/g, " ").trim();
|
|
4068
4164
|
}
|
|
4069
4165
|
|
|
4166
|
+
// src/hwp5/pw-crypto.ts
|
|
4167
|
+
import { createCipheriv, createHash as createHash2 } from "crypto";
|
|
4168
|
+
var ENCRYPT_VERSION_OFFSET = 44;
|
|
4169
|
+
var SUPPORTED_ENCRYPT_VERSION = 4;
|
|
4170
|
+
var KEY_SEED = 236;
|
|
4171
|
+
function readEncryptVersion(fileHeader) {
|
|
4172
|
+
if (fileHeader.length < ENCRYPT_VERSION_OFFSET + 4) return 0;
|
|
4173
|
+
return (fileHeader[ENCRYPT_VERSION_OFFSET] | fileHeader[ENCRYPT_VERSION_OFFSET + 1] << 8 | fileHeader[ENCRYPT_VERSION_OFFSET + 2] << 16 | fileHeader[ENCRYPT_VERSION_OFFSET + 3] << 24) >>> 0;
|
|
4174
|
+
}
|
|
4175
|
+
function derivePasswordKey(password) {
|
|
4176
|
+
const buf = Buffer.alloc(password.length * 2);
|
|
4177
|
+
for (let i = 0; i < password.length; i++) {
|
|
4178
|
+
const prev = i === 0 ? KEY_SEED : password[i - 1];
|
|
4179
|
+
buf[i * 2] = (prev << 1 | prev >> 7) & 255;
|
|
4180
|
+
buf[i * 2 + 1] = password[i];
|
|
4181
|
+
}
|
|
4182
|
+
return createHash2("sha1").update(buf).digest().subarray(0, 16);
|
|
4183
|
+
}
|
|
4184
|
+
function padToBlock(data) {
|
|
4185
|
+
const rem = data.length % 16;
|
|
4186
|
+
if (rem === 0) return Buffer.from(data);
|
|
4187
|
+
const amount = 16 - rem;
|
|
4188
|
+
return Buffer.concat([Buffer.from(data), Buffer.alloc(amount, amount)]);
|
|
4189
|
+
}
|
|
4190
|
+
function shiftRegister(reg, feedbackBit) {
|
|
4191
|
+
for (let i = 0; i < 15; i++) {
|
|
4192
|
+
reg[i] = (reg[i] << 1 | reg[i + 1] >> 7) & 255;
|
|
4193
|
+
}
|
|
4194
|
+
reg[15] = (reg[15] << 1 | feedbackBit & 1) & 255;
|
|
4195
|
+
}
|
|
4196
|
+
function decryptAesCfb1(data, key) {
|
|
4197
|
+
const cipher = createCipheriv("aes-128-ecb", key, null);
|
|
4198
|
+
cipher.setAutoPadding(false);
|
|
4199
|
+
const register = new Uint8Array(16);
|
|
4200
|
+
const registerBuf = Buffer.alloc(16);
|
|
4201
|
+
const out = Buffer.alloc(data.length);
|
|
4202
|
+
for (let offset = 0; offset < data.length; offset += 16) {
|
|
4203
|
+
const len = Math.min(16, data.length - offset);
|
|
4204
|
+
const chunk = Buffer.alloc(16);
|
|
4205
|
+
data.copy(chunk, 0, offset, offset + len);
|
|
4206
|
+
for (let i = 0; i < 128; i++) {
|
|
4207
|
+
registerBuf.set(register);
|
|
4208
|
+
const keystreamMsb = cipher.update(registerBuf)[0];
|
|
4209
|
+
const byteIdx = i >> 3;
|
|
4210
|
+
const bitInByte = i & 7;
|
|
4211
|
+
const cipherBit = chunk[byteIdx] >> 7 - bitInByte & 1;
|
|
4212
|
+
shiftRegister(register, cipherBit);
|
|
4213
|
+
chunk[byteIdx] ^= (keystreamMsb & 128) >> bitInByte;
|
|
4214
|
+
}
|
|
4215
|
+
chunk.copy(out, offset, 0, len);
|
|
4216
|
+
}
|
|
4217
|
+
return out;
|
|
4218
|
+
}
|
|
4219
|
+
function decryptPasswordStream(raw, password) {
|
|
4220
|
+
const key = derivePasswordKey(Buffer.from(password, "utf8"));
|
|
4221
|
+
return decryptAesCfb1(padToBlock(raw), key).subarray(0, raw.length);
|
|
4222
|
+
}
|
|
4223
|
+
var TAG_DOCUMENT_PROPERTIES = 16;
|
|
4224
|
+
var TAG_ID_MAPPINGS = 17;
|
|
4225
|
+
function assertDecryptedDocInfo(data, readRecords3) {
|
|
4226
|
+
const wrong = () => new KordocError("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uAC70\uB098 \uC554\uD638\uD654 \uB370\uC774\uD130\uAC00 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
4227
|
+
let records;
|
|
4228
|
+
try {
|
|
4229
|
+
records = readRecords3(data);
|
|
4230
|
+
} catch {
|
|
4231
|
+
throw wrong();
|
|
4232
|
+
}
|
|
4233
|
+
if (records[0]?.tagId !== TAG_DOCUMENT_PROPERTIES) throw wrong();
|
|
4234
|
+
if (!records.some((r) => r.tagId === TAG_ID_MAPPINGS)) throw wrong();
|
|
4235
|
+
}
|
|
4236
|
+
function assertSupportedEncryptVersion(version) {
|
|
4237
|
+
if (version !== SUPPORTED_ENCRYPT_VERSION) {
|
|
4238
|
+
throw new KordocError(
|
|
4239
|
+
`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWP \uC554\uD638\uD654 \uBC84\uC804\uC785\uB2C8\uB2E4 (EncryptVersion=${version}, \uC9C0\uC6D0: ${SUPPORTED_ENCRYPT_VERSION})`
|
|
4240
|
+
);
|
|
4241
|
+
}
|
|
4242
|
+
}
|
|
4243
|
+
|
|
4070
4244
|
// src/hwp5/parser.ts
|
|
4071
4245
|
import { createRequire } from "module";
|
|
4072
4246
|
var require2 = createRequire(import.meta.url);
|
|
@@ -4147,27 +4321,50 @@ function parseHwp5Document(buffer, options) {
|
|
|
4147
4321
|
throw new KordocError("CFB \uCEE8\uD14C\uC774\uB108 \uD30C\uC2F1 \uC2E4\uD328 (strict \uBC0F lenient \uBAA8\uB450)");
|
|
4148
4322
|
}
|
|
4149
4323
|
}
|
|
4150
|
-
const
|
|
4324
|
+
const readRawStream = (path) => {
|
|
4151
4325
|
if (cfb) {
|
|
4152
4326
|
const entry = CFB.find(cfb, path);
|
|
4153
4327
|
return entry?.content ? Buffer.from(entry.content) : null;
|
|
4154
4328
|
}
|
|
4155
4329
|
return lenientCfb.findStream(path);
|
|
4156
4330
|
};
|
|
4157
|
-
const headerData =
|
|
4331
|
+
const headerData = readRawStream("/FileHeader");
|
|
4158
4332
|
if (!headerData) throw new KordocError("FileHeader \uC2A4\uD2B8\uB9BC \uC5C6\uC74C");
|
|
4159
4333
|
const header = parseFileHeader(headerData);
|
|
4160
4334
|
if (header.signature !== "HWP Document File") throw new KordocError("HWP \uC2DC\uADF8\uB2C8\uCC98 \uBD88\uC77C\uCE58");
|
|
4161
|
-
if (header.flags & FLAG_ENCRYPTED) throw new KordocError("\uC554\uD638\uD654\uB41C HWP\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
4162
4335
|
if (header.flags & FLAG_DRM) throw new KordocError("DRM \uBCF4\uD638\uB41C HWP\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
4336
|
+
const encrypted = (header.flags & FLAG_ENCRYPTED) !== 0;
|
|
4337
|
+
if (encrypted) {
|
|
4338
|
+
if (!options?.password) {
|
|
4339
|
+
throw new KordocError("\uC554\uD638\uB85C \uBCF4\uD638\uB41C HWP \uBB38\uC11C\uC785\uB2C8\uB2E4. password \uC635\uC158\uC5D0 \uC5F4\uAE30 \uC554\uD638\uB97C \uC9C0\uC815\uD558\uC138\uC694.");
|
|
4340
|
+
}
|
|
4341
|
+
assertSupportedEncryptVersion(readEncryptVersion(headerData));
|
|
4342
|
+
}
|
|
4343
|
+
const password = encrypted ? options.password : void 0;
|
|
4344
|
+
const findStream = (path) => {
|
|
4345
|
+
const raw = readRawStream(path);
|
|
4346
|
+
if (!raw || !password) return raw;
|
|
4347
|
+
return decryptPasswordStream(raw, password);
|
|
4348
|
+
};
|
|
4163
4349
|
const compressed = (header.flags & FLAG_COMPRESSED) !== 0;
|
|
4164
4350
|
const distribution = (header.flags & FLAG_DISTRIBUTION) !== 0;
|
|
4165
4351
|
const metadata = {
|
|
4166
4352
|
version: `${header.versionMajor}.x`
|
|
4167
4353
|
};
|
|
4168
4354
|
if (cfb) extractHwp5Metadata(cfb, metadata);
|
|
4169
|
-
|
|
4170
|
-
|
|
4355
|
+
if (encrypted) {
|
|
4356
|
+
const rawDocInfo = findStream("/DocInfo");
|
|
4357
|
+
if (!rawDocInfo) throw new KordocError("DocInfo \uC2A4\uD2B8\uB9BC \uC5C6\uC74C");
|
|
4358
|
+
let docInfoData;
|
|
4359
|
+
try {
|
|
4360
|
+
docInfoData = compressed ? decompressStream(rawDocInfo) : rawDocInfo;
|
|
4361
|
+
} catch {
|
|
4362
|
+
throw new KordocError("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uAC70\uB098 \uC554\uD638\uD654 \uB370\uC774\uD130\uAC00 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
4363
|
+
}
|
|
4364
|
+
assertDecryptedDocInfo(docInfoData, readRecords);
|
|
4365
|
+
}
|
|
4366
|
+
const docInfo = cfb && !encrypted ? parseDocInfoStream(cfb, compressed) : parseDocInfoFromStream(findStream("/DocInfo"), compressed);
|
|
4367
|
+
const sections = distribution ? cfb ? findViewTextSections(cfb, compressed) : findViewTextSectionsLenient(lenientCfb, compressed) : encrypted ? findSectionsVia(findStream) : cfb ? findSections(cfb) : findSectionsLenient(lenientCfb, compressed);
|
|
4171
4368
|
if (sections.length === 0) throw new KordocError("\uC139\uC158 \uC2A4\uD2B8\uB9BC\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
4172
4369
|
metadata.pageCount = sections.length;
|
|
4173
4370
|
const pageFilter = options?.pages ? parsePageRange(options.pages, sections.length) : null;
|
|
@@ -4335,6 +4532,15 @@ function findViewTextSections(cfb, compressed) {
|
|
|
4335
4532
|
}
|
|
4336
4533
|
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
4337
4534
|
}
|
|
4535
|
+
function findSectionsVia(read) {
|
|
4536
|
+
const sections = [];
|
|
4537
|
+
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
4538
|
+
const raw = read(`/BodyText/Section${i}`);
|
|
4539
|
+
if (!raw) break;
|
|
4540
|
+
sections.push(raw);
|
|
4541
|
+
}
|
|
4542
|
+
return sections;
|
|
4543
|
+
}
|
|
4338
4544
|
function findSections(cfb) {
|
|
4339
4545
|
const sections = [];
|
|
4340
4546
|
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
@@ -4940,7 +5146,7 @@ function hasRealStrike(attrFlags) {
|
|
|
4940
5146
|
}
|
|
4941
5147
|
|
|
4942
5148
|
// src/hwp3/parser.ts
|
|
4943
|
-
import { inflateRawSync as
|
|
5149
|
+
import { inflateRawSync as inflateRawSync5 } from "zlib";
|
|
4944
5150
|
|
|
4945
5151
|
// src/hwp3/johab-symbols.ts
|
|
4946
5152
|
var JOHAB_SYMBOLS = Object.freeze([
|
|
@@ -16848,6 +17054,23 @@ function lookupSymbol(ch) {
|
|
|
16848
17054
|
return null;
|
|
16849
17055
|
}
|
|
16850
17056
|
var JOHAB_UNMAPPED = -1;
|
|
17057
|
+
var JUNG_ARAEA = 30;
|
|
17058
|
+
var ARAEA_JAMO = 4510;
|
|
17059
|
+
function decodeAraeaSyllable(ch) {
|
|
17060
|
+
if (ch < 32768) return null;
|
|
17061
|
+
if ((ch >> 5 & 31) !== JUNG_ARAEA) return null;
|
|
17062
|
+
const cho = CHO_MAP[ch >> 10 & 31];
|
|
17063
|
+
const jong = JONG_MAP[ch & 31];
|
|
17064
|
+
if (cho === -1 || jong === -1) return null;
|
|
17065
|
+
const out = String.fromCodePoint(4352 + cho) + String.fromCodePoint(ARAEA_JAMO);
|
|
17066
|
+
return jong === 0 ? out : out + String.fromCodePoint(4519 + jong);
|
|
17067
|
+
}
|
|
17068
|
+
function decodeJohabText(ch) {
|
|
17069
|
+
const araea = decodeAraeaSyllable(ch);
|
|
17070
|
+
if (araea) return araea;
|
|
17071
|
+
const cp = decodeJohab(ch);
|
|
17072
|
+
return cp === JOHAB_UNMAPPED ? null : String.fromCodePoint(cp);
|
|
17073
|
+
}
|
|
16851
17074
|
function decodeJohab(ch) {
|
|
16852
17075
|
if (ch < 128) return ch;
|
|
16853
17076
|
if (ch >= 32768) {
|
|
@@ -16869,6 +17092,7 @@ function decodeJohab(ch) {
|
|
|
16869
17092
|
function decodeHwp3Extra(ch) {
|
|
16870
17093
|
if (ch >= 13712 && ch <= 13721) return 8544 + (ch - 13712);
|
|
16871
17094
|
if (ch >= 14055 && ch <= 14064) return 9312 + (ch - 14055);
|
|
17095
|
+
if (ch >= 14272 && ch <= 14277) return "\uD55C\uAE00\uACFC\uCEF4\uD4E8\uD130".codePointAt(ch - 14272);
|
|
16872
17096
|
switch (ch) {
|
|
16873
17097
|
case 129:
|
|
16874
17098
|
return 8220;
|
|
@@ -16903,6 +17127,9 @@ function decodeHwp3Extra(ch) {
|
|
|
16903
17127
|
case 13434:
|
|
16904
17128
|
return 9654;
|
|
16905
17129
|
// ▶
|
|
17130
|
+
case 12135:
|
|
17131
|
+
return 9656;
|
|
17132
|
+
// ▸ 표 셀 글머리표 (rhwp 16db8260 — HWP5 변환본·한컴 PDF 대조)
|
|
16906
17133
|
default:
|
|
16907
17134
|
return JOHAB_UNMAPPED;
|
|
16908
17135
|
}
|
|
@@ -16913,8 +17140,7 @@ function decodeHcharString(bytes) {
|
|
|
16913
17140
|
while (i + 1 < bytes.length) {
|
|
16914
17141
|
const ch = bytes[i] | bytes[i + 1] << 8;
|
|
16915
17142
|
if (ch === 0) break;
|
|
16916
|
-
|
|
16917
|
-
if (cp !== JOHAB_UNMAPPED) out += String.fromCodePoint(cp);
|
|
17143
|
+
out += decodeJohabText(ch) ?? "";
|
|
16918
17144
|
i += 2;
|
|
16919
17145
|
}
|
|
16920
17146
|
return out;
|
|
@@ -17019,6 +17245,87 @@ function readHeader(reader) {
|
|
|
17019
17245
|
return { compressed, encrypted, infoBlockLength, title, subject, author, date };
|
|
17020
17246
|
}
|
|
17021
17247
|
|
|
17248
|
+
// src/hwp3/crypto.ts
|
|
17249
|
+
import { createDecipheriv as createDecipheriv2 } from "crypto";
|
|
17250
|
+
import { inflateRawSync as inflateRawSync4 } from "zlib";
|
|
17251
|
+
var FIXED_HEADER_BYTES = SIGNATURE_LEN + DOC_INFO_SIZE + DOC_SUMMARY_SIZE;
|
|
17252
|
+
var PASSWORD_FLAG_OFFSET = SIGNATURE_LEN + 96;
|
|
17253
|
+
var COMPRESSION_FLAG_OFFSET = SIGNATURE_LEN + 124;
|
|
17254
|
+
var INFO_BLOCK_LENGTH_OFFSET = SIGNATURE_LEN + 126;
|
|
17255
|
+
var PASSWORD_PREFIX_BYTES = 256;
|
|
17256
|
+
var MAX_DECOMPRESSED_BYTES = 100 * 1024 * 1024;
|
|
17257
|
+
function isEncryptedHwp3(data) {
|
|
17258
|
+
if (data.length < FIXED_HEADER_BYTES) return false;
|
|
17259
|
+
return (data[PASSWORD_FLAG_OFFSET] | data[PASSWORD_FLAG_OFFSET + 1] << 8) !== 0;
|
|
17260
|
+
}
|
|
17261
|
+
function deriveDesKey(password) {
|
|
17262
|
+
const rolling = new Uint8Array(7);
|
|
17263
|
+
let index = 0;
|
|
17264
|
+
for (let i = 0; i < password.length; i++) {
|
|
17265
|
+
const unit = password.charCodeAt(i);
|
|
17266
|
+
for (const byte of [unit & 255, unit >> 8 & 255]) {
|
|
17267
|
+
const slot = index % rolling.length;
|
|
17268
|
+
const mixed = rolling[slot] ^ byte;
|
|
17269
|
+
rolling[slot] = (mixed << 1 | mixed >> 7) & 255;
|
|
17270
|
+
index++;
|
|
17271
|
+
}
|
|
17272
|
+
}
|
|
17273
|
+
const key = Buffer.alloc(8);
|
|
17274
|
+
for (let bit = 0; bit < 56; bit++) {
|
|
17275
|
+
const sourceBit = rolling[Math.floor(bit / 8)] >> 7 - bit % 8 & 1;
|
|
17276
|
+
key[Math.floor(bit / 7)] |= sourceBit << 7 - bit % 7;
|
|
17277
|
+
}
|
|
17278
|
+
return key;
|
|
17279
|
+
}
|
|
17280
|
+
function desEcbDecrypt(data, key) {
|
|
17281
|
+
const decipher = createDecipheriv2("des-ede3-ecb", Buffer.concat([key, key, key]), null);
|
|
17282
|
+
decipher.setAutoPadding(false);
|
|
17283
|
+
return Buffer.concat([decipher.update(data), decipher.final()]);
|
|
17284
|
+
}
|
|
17285
|
+
function readLayout(data) {
|
|
17286
|
+
if (data.length < FIXED_HEADER_BYTES) {
|
|
17287
|
+
throw new KordocError("HWP3 \uC554\uD638 \uBB38\uC11C: \uD5E4\uB354\uAC00 \uC798\uB838\uC2B5\uB2C8\uB2E4");
|
|
17288
|
+
}
|
|
17289
|
+
const infoBlockLength = data[INFO_BLOCK_LENGTH_OFFSET] | data[INFO_BLOCK_LENGTH_OFFSET + 1] << 8;
|
|
17290
|
+
const payloadOffset = FIXED_HEADER_BYTES + infoBlockLength;
|
|
17291
|
+
if (payloadOffset >= data.length) {
|
|
17292
|
+
throw new KordocError("HWP3 \uC554\uD638 \uBB38\uC11C: \uBCF8\uBB38\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
17293
|
+
}
|
|
17294
|
+
return { payloadOffset, compressed: data[COMPRESSION_FLAG_OFFSET] !== 0 };
|
|
17295
|
+
}
|
|
17296
|
+
function decryptHwp3Document(input, password) {
|
|
17297
|
+
const { payloadOffset, compressed } = readLayout(input);
|
|
17298
|
+
if (!compressed) {
|
|
17299
|
+
throw new KordocError("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWP3 \uC554\uD638\uD654 \uBC29\uC2DD\uC785\uB2C8\uB2E4 (\uC555\uCD95\uB418\uC9C0 \uC54A\uC740 \uC554\uD638 \uBCF8\uBB38)");
|
|
17300
|
+
}
|
|
17301
|
+
const source = Buffer.from(input);
|
|
17302
|
+
const payload = source.subarray(payloadOffset);
|
|
17303
|
+
const aligned = payload.subarray(0, payload.length - payload.length % 8);
|
|
17304
|
+
if (aligned.length === 0) {
|
|
17305
|
+
throw new KordocError("HWP3 \uC554\uD638 \uBB38\uC11C: \uBCF8\uBB38\uC774 \uB108\uBB34 \uC9E7\uC2B5\uB2C8\uB2E4");
|
|
17306
|
+
}
|
|
17307
|
+
const decrypted = desEcbDecrypt(aligned, deriveDesKey(password));
|
|
17308
|
+
let inflated;
|
|
17309
|
+
try {
|
|
17310
|
+
inflated = inflateRawSync4(decrypted, { maxOutputLength: MAX_DECOMPRESSED_BYTES });
|
|
17311
|
+
} catch (err) {
|
|
17312
|
+
if (err?.code === "ERR_BUFFER_TOO_LARGE") {
|
|
17313
|
+
throw new KordocError(
|
|
17314
|
+
`HWP3 \uC554\uD638 \uBCF8\uBB38\uC758 \uC555\uCD95 \uD574\uC81C \uACB0\uACFC\uAC00 \uCD5C\uB300 \uD5C8\uC6A9 \uD06C\uAE30(${MAX_DECOMPRESSED_BYTES / 1024 / 1024}MB)\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4`
|
|
17315
|
+
);
|
|
17316
|
+
}
|
|
17317
|
+
throw new KordocError("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uAC70\uB098 \uC554\uD638\uD654 \uB370\uC774\uD130\uAC00 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
17318
|
+
}
|
|
17319
|
+
if (inflated.length <= PASSWORD_PREFIX_BYTES) {
|
|
17320
|
+
throw new KordocError("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uAC70\uB098 \uC554\uD638\uD654 \uB370\uC774\uD130\uAC00 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
17321
|
+
}
|
|
17322
|
+
const body = inflated.subarray(PASSWORD_PREFIX_BYTES);
|
|
17323
|
+
const out = Buffer.concat([source.subarray(0, payloadOffset), body]);
|
|
17324
|
+
out.writeUInt16LE(0, PASSWORD_FLAG_OFFSET);
|
|
17325
|
+
out[COMPRESSION_FLAG_OFFSET] = 0;
|
|
17326
|
+
return out;
|
|
17327
|
+
}
|
|
17328
|
+
|
|
17022
17329
|
// src/hwp3/parser.ts
|
|
17023
17330
|
var MAX_DECOMPRESS_SIZE3 = 100 * 1024 * 1024;
|
|
17024
17331
|
var PARA_SHAPE_SIZE = 187;
|
|
@@ -17041,19 +17348,25 @@ var SIMPLE_CTRL = /* @__PURE__ */ new Map([
|
|
|
17041
17348
|
[30, { extraBytes: 2, extraHchar: 1, emit: "\xA0" }],
|
|
17042
17349
|
[31, { extraBytes: 2, extraHchar: 1, emit: " " }]
|
|
17043
17350
|
]);
|
|
17044
|
-
function parseHwp3Document(buffer,
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17351
|
+
function parseHwp3Document(buffer, options) {
|
|
17352
|
+
let source = Buffer.from(buffer);
|
|
17353
|
+
if (isEncryptedHwp3(source)) {
|
|
17354
|
+
if (!options?.password) {
|
|
17355
|
+
throw new KordocError(
|
|
17356
|
+
"\uC554\uD638\uB85C \uBCF4\uD638\uB41C HWP3 \uBB38\uC11C\uC785\uB2C8\uB2E4. password \uC635\uC158\uC5D0 \uC5F4\uAE30 \uC554\uD638\uB97C \uC9C0\uC815\uD558\uC138\uC694."
|
|
17357
|
+
);
|
|
17358
|
+
}
|
|
17359
|
+
source = decryptHwp3Document(source, options.password);
|
|
17049
17360
|
}
|
|
17361
|
+
const headReader = new Reader(source);
|
|
17362
|
+
const header = readHeader(headReader);
|
|
17050
17363
|
headReader.skip(header.infoBlockLength);
|
|
17051
17364
|
const tail = headReader.readToEnd();
|
|
17052
17365
|
let body;
|
|
17053
17366
|
const warnings = [];
|
|
17054
17367
|
if (header.compressed !== 0) {
|
|
17055
17368
|
try {
|
|
17056
|
-
body =
|
|
17369
|
+
body = inflateRawSync5(tail, { maxOutputLength: MAX_DECOMPRESS_SIZE3 });
|
|
17057
17370
|
} catch (err) {
|
|
17058
17371
|
if (err?.code === "ERR_BUFFER_TOO_LARGE") {
|
|
17059
17372
|
throw new KordocError(`HWP3 \uC555\uCD95 \uD574\uC81C \uACB0\uACFC\uAC00 \uCD5C\uB300 \uD5C8\uC6A9 \uD06C\uAE30(${MAX_DECOMPRESS_SIZE3 / 1024 / 1024}MB)\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4`);
|
|
@@ -17156,8 +17469,7 @@ function parseCharStream(reader, charCount, ctx) {
|
|
|
17156
17469
|
continue;
|
|
17157
17470
|
}
|
|
17158
17471
|
if (ch >= 32) {
|
|
17159
|
-
|
|
17160
|
-
if (cp !== JOHAB_UNMAPPED) out += String.fromCodePoint(cp);
|
|
17472
|
+
out += decodeJohabText(ch) ?? "";
|
|
17161
17473
|
continue;
|
|
17162
17474
|
}
|
|
17163
17475
|
const simple = SIMPLE_CTRL.get(ch);
|
|
@@ -17225,7 +17537,7 @@ function parseCharStream(reader, charCount, ctx) {
|
|
|
17225
17537
|
function parseTableLike(reader, ctx) {
|
|
17226
17538
|
const info = reader.readBytes(84);
|
|
17227
17539
|
const cellCount = info.readUInt16LE(80) || 1;
|
|
17228
|
-
if (cellCount >
|
|
17540
|
+
if (27 * cellCount > reader.remaining()) {
|
|
17229
17541
|
ctx.warnings.push({
|
|
17230
17542
|
code: "PARTIAL_PARSE",
|
|
17231
17543
|
message: `HWP3 \uD45C cell_count=${cellCount} \uBE44\uC815\uC0C1 \u2014 \uD45C \uBCF8\uBB38 \uCD94\uCD9C \uD3EC\uAE30`
|
|
@@ -17239,10 +17551,11 @@ function parseTableLike(reader, ctx) {
|
|
|
17239
17551
|
parseParagraphList2(reader, ctx);
|
|
17240
17552
|
return "";
|
|
17241
17553
|
}
|
|
17242
|
-
function parsePicture(reader,
|
|
17554
|
+
function parsePicture(reader, ctx) {
|
|
17243
17555
|
const info = reader.readBytes(348);
|
|
17244
17556
|
const nExt = info.readUInt32LE(0);
|
|
17245
17557
|
if (nExt > 0 && nExt < 100 * 1024 * 1024) reader.skip(nExt);
|
|
17558
|
+
parseParagraphList2(reader, ctx);
|
|
17246
17559
|
}
|
|
17247
17560
|
|
|
17248
17561
|
// src/hwp5/sentinel.ts
|
|
@@ -19951,7 +20264,9 @@ async function fillWithUniqueGuard(values, run) {
|
|
|
19951
20264
|
const first = await run(values);
|
|
19952
20265
|
const counts = /* @__PURE__ */ new Map();
|
|
19953
20266
|
for (const f of first.filled) {
|
|
19954
|
-
if (f.key
|
|
20267
|
+
if (f.key && f.source !== "clickhere") {
|
|
20268
|
+
counts.set(f.key, (counts.get(f.key) ?? 0) + 1);
|
|
20269
|
+
}
|
|
19955
20270
|
}
|
|
19956
20271
|
const isArrayValue = (normKey) => {
|
|
19957
20272
|
for (const [label, raw] of Object.entries(values)) {
|
|
@@ -20934,7 +21249,7 @@ function applySplices(xml, splices) {
|
|
|
20934
21249
|
|
|
20935
21250
|
// src/form/click-here.ts
|
|
20936
21251
|
var FIELD_BEGIN_RE = /<([A-Za-z0-9_]+:)?fieldBegin\b([^>]*?)(\/?)>/g;
|
|
20937
|
-
function
|
|
21252
|
+
function attrOf2(attrs, name) {
|
|
20938
21253
|
const m = attrs.match(new RegExp(`(?:^|\\s)${name}="([^"]*)"`));
|
|
20939
21254
|
return m ? m[1] : void 0;
|
|
20940
21255
|
}
|
|
@@ -20960,10 +21275,10 @@ function scanClickHereRegions(xml) {
|
|
|
20960
21275
|
const prefix = m[1] ?? "";
|
|
20961
21276
|
const attrs = m[2];
|
|
20962
21277
|
const selfClosed = m[3] === "/";
|
|
20963
|
-
if ((
|
|
20964
|
-
const name =
|
|
21278
|
+
if ((attrOf2(attrs, "type") ?? "").toUpperCase() !== "CLICK_HERE") continue;
|
|
21279
|
+
const name = attrOf2(attrs, "name");
|
|
20965
21280
|
if (name === void 0) continue;
|
|
20966
|
-
const id =
|
|
21281
|
+
const id = attrOf2(attrs, "id");
|
|
20967
21282
|
let beginElemEnd;
|
|
20968
21283
|
if (selfClosed) {
|
|
20969
21284
|
beginElemEnd = FIELD_BEGIN_RE.lastIndex;
|
|
@@ -20986,7 +21301,7 @@ function scanClickHereRegions(xml) {
|
|
|
20986
21301
|
let end = -1;
|
|
20987
21302
|
let fe;
|
|
20988
21303
|
while ((fe = feRe.exec(xml)) !== null) {
|
|
20989
|
-
const ref =
|
|
21304
|
+
const ref = attrOf2(fe[0], "beginIDRef");
|
|
20990
21305
|
if (id !== void 0 && ref !== void 0 && ref !== id) continue;
|
|
20991
21306
|
end = fe.index;
|
|
20992
21307
|
break;
|
|
@@ -21027,7 +21342,7 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
|
|
|
21027
21342
|
const replacement = valueXml(value, region.prefix);
|
|
21028
21343
|
const current = xml.slice(region.start, region.end);
|
|
21029
21344
|
matchedKeys.add(key);
|
|
21030
|
-
filled.push({ label: region.name, value, row: -1, col: -1, key });
|
|
21345
|
+
filled.push({ label: region.name, value, row: -1, col: -1, key, source: "clickhere" });
|
|
21031
21346
|
if (current === replacement) continue;
|
|
21032
21347
|
splices.push({ start: region.start, end: region.end, replacement });
|
|
21033
21348
|
}
|
|
@@ -21038,6 +21353,7 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
|
|
|
21038
21353
|
};
|
|
21039
21354
|
}
|
|
21040
21355
|
async function extractClickHereFields(hwpxBuffer) {
|
|
21356
|
+
precheckZipSize(hwpxBuffer);
|
|
21041
21357
|
const zip = await JSZip6.loadAsync(hwpxBuffer);
|
|
21042
21358
|
const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
|
|
21043
21359
|
const fields = [];
|
|
@@ -21266,6 +21582,7 @@ function patchZipEntries(original, replacements, additions) {
|
|
|
21266
21582
|
// src/form/filler-hwpx.ts
|
|
21267
21583
|
async function fillHwpx(hwpxBuffer, values, blockedLabels) {
|
|
21268
21584
|
const u8 = new Uint8Array(hwpxBuffer);
|
|
21585
|
+
precheckZipSize(hwpxBuffer);
|
|
21269
21586
|
const zip = await JSZip7.loadAsync(hwpxBuffer);
|
|
21270
21587
|
const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
|
|
21271
21588
|
if (sectionPaths.length === 0) {
|
|
@@ -26010,7 +26327,7 @@ function collectSites(scan) {
|
|
|
26010
26327
|
sites.sort((a, b) => a.para.start - b.para.start);
|
|
26011
26328
|
return sites;
|
|
26012
26329
|
}
|
|
26013
|
-
function
|
|
26330
|
+
function attrOf3(openTag, name) {
|
|
26014
26331
|
const m = openTag.match(new RegExp(`\\b${name}="([^"]*)"`));
|
|
26015
26332
|
return m?.[1];
|
|
26016
26333
|
}
|
|
@@ -26028,7 +26345,7 @@ function anchorRunInfo(xml, para2, anchor) {
|
|
|
26028
26345
|
const before = xml.slice(Math.max(0, para2.start), tr.contentStart);
|
|
26029
26346
|
const runOpen = [...before.matchAll(/<([A-Za-z0-9]+):run\b[^>]*>/g)].pop();
|
|
26030
26347
|
const prefix = runOpen?.[1] ?? tr.prefix ?? "hp";
|
|
26031
|
-
const charPr2 = runOpen &&
|
|
26348
|
+
const charPr2 = runOpen && attrOf3(runOpen[0], "charPrIDRef") || "0";
|
|
26032
26349
|
const close = xml.indexOf(`</${prefix}:run>`, tr.contentEnd);
|
|
26033
26350
|
if (close === -1) return null;
|
|
26034
26351
|
return { charPr: charPr2, prefix, insertAt: close + `</${prefix}:run>`.length };
|
|
@@ -26056,7 +26373,7 @@ function cellContentWidthMm(xml, cell2) {
|
|
|
26056
26373
|
const win = cellAddrWindow(xml, cell2);
|
|
26057
26374
|
const mg = win?.match(/<[A-Za-z0-9]+:cellMargin\b[^>]*>/);
|
|
26058
26375
|
if (mg) {
|
|
26059
|
-
content -= Number(
|
|
26376
|
+
content -= Number(attrOf3(mg[0], "left") ?? 0) + Number(attrOf3(mg[0], "right") ?? 0);
|
|
26060
26377
|
}
|
|
26061
26378
|
return content > 0 ? content / HU_PER_MM2 : null;
|
|
26062
26379
|
}
|
|
@@ -26090,6 +26407,7 @@ function buildFloatPicXml(itemId, sizeHu, posXHu, posYHu, ids) {
|
|
|
26090
26407
|
async function placeSealHwpx(hwpxBuffer, ops) {
|
|
26091
26408
|
if (ops.length === 0) throw new KordocError("place_seal: \uBC30\uCE58\uD560 \uB3C4\uC7A5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
26092
26409
|
const u8 = new Uint8Array(hwpxBuffer);
|
|
26410
|
+
precheckZipSize(hwpxBuffer);
|
|
26093
26411
|
const zip = await JSZip9.loadAsync(hwpxBuffer);
|
|
26094
26412
|
const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort((a, b) => Number(a.match(/(\d+)\.xml$/i)?.[1] ?? 0) - Number(b.match(/(\d+)\.xml$/i)?.[1] ?? 0));
|
|
26095
26413
|
if (sectionPaths.length === 0) throw new KordocError("HWPX\uC5D0\uC11C \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
@@ -26188,7 +26506,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
|
|
|
26188
26506
|
const anchorWMm = measureMm(op.anchor, emMm);
|
|
26189
26507
|
const sizeMm = op.sizeMm != null && Number.isFinite(op.sizeMm) && op.sizeMm > 0 ? op.sizeMm : Math.max(7, Math.min(18, lineHMm * 1.6));
|
|
26190
26508
|
const availMm = (site.cell ? cellContentWidthMm(xml, site.cell) : null) ?? bodyColumnWidthMm(xml);
|
|
26191
|
-
const paraPrId =
|
|
26509
|
+
const paraPrId = attrOf3(paraOpenTag(xml, site.para), "paraPrIDRef") ?? "0";
|
|
26192
26510
|
const align = styles?.paraAlign.get(paraPrId);
|
|
26193
26511
|
let alignShiftMm = 0;
|
|
26194
26512
|
if (align === "CENTER" || align === "RIGHT") {
|
|
@@ -27275,6 +27593,9 @@ function applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, before, a
|
|
|
27275
27593
|
const xml = ctx.scans[target.sectionIndex]?.xml;
|
|
27276
27594
|
const rawT = xml ? paraTText(target, xml) : null;
|
|
27277
27595
|
let sp;
|
|
27596
|
+
if (xml && rawT === null) {
|
|
27597
|
+
return skip("\uBE48 \uC140 \uBB38\uB2E8\uC5D0 \uC5D4\uD2F0\uD2F0\xB7\uD0DC\uADF8\uAC00 \uC788\uC5B4 \uC0BD\uC785 \uACBD\uACC4\uB97C \uD2B9\uC815\uD560 \uC218 \uC5C6\uC74C \u2014 \uC6D0\uBB38 \uC190\uC2E4 \uBC29\uC9C0\uB85C \uBBF8\uC801\uC6A9");
|
|
27598
|
+
}
|
|
27278
27599
|
if (xml && rawT !== null && rawT.length > 0 && rawT.trim() === "") {
|
|
27279
27600
|
sp = buildRangeSplices(target, xml, 0, 0, value);
|
|
27280
27601
|
if (sp === null) return skip("\uBE48 \uC140 \uACF5\uBC31 \uBCF4\uC874 \uC0BD\uC785 \uACBD\uACC4 \uBAA8\uD638 \u2014 \uC6D0\uBB38 \uC190\uC2E4 \uBC29\uC9C0\uB85C \uBBF8\uC801\uC6A9");
|
|
@@ -30000,7 +30321,7 @@ function pushTextSlots(t, chars, prId, depth) {
|
|
|
30000
30321
|
if (!kids) return;
|
|
30001
30322
|
for (let i = 0; i < kids.length; i++) {
|
|
30002
30323
|
const c = kids[i];
|
|
30003
|
-
if (c.nodeType === 3) {
|
|
30324
|
+
if (c.nodeType === 3 || c.nodeType === 4) {
|
|
30004
30325
|
for (const cp of c.textContent ?? "") {
|
|
30005
30326
|
chars.push({ ch: cp, prId });
|
|
30006
30327
|
if (cp.length === 2) chars.push({ ch: "", prId });
|
|
@@ -30741,7 +31062,7 @@ async function parse(input, options) {
|
|
|
30741
31062
|
}
|
|
30742
31063
|
async function parseImage(buffer, options) {
|
|
30743
31064
|
try {
|
|
30744
|
-
const { parseImageDocument } = await import("./image-ocr-
|
|
31065
|
+
const { parseImageDocument } = await import("./image-ocr-U2DRRFL3.js");
|
|
30745
31066
|
const { blocks, warnings } = await parseImageDocument(buffer, options);
|
|
30746
31067
|
return {
|
|
30747
31068
|
success: true,
|
|
@@ -30800,7 +31121,7 @@ async function parseHwp(buffer, options) {
|
|
|
30800
31121
|
async function parsePdf(buffer, options) {
|
|
30801
31122
|
let parsePdfDocument;
|
|
30802
31123
|
try {
|
|
30803
|
-
const mod = await import("./parser-
|
|
31124
|
+
const mod = await import("./parser-TFPGQWCC.js");
|
|
30804
31125
|
parsePdfDocument = mod.parsePdfDocument;
|
|
30805
31126
|
} catch {
|
|
30806
31127
|
return {
|