kordoc 4.3.1 → 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/{-RH6BEVTT.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-HZU7Y22R.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-SA22NK56.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-5F5UCACZ.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-CD5X6UG5.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-VQB5P5KJ.cjs → chunk-H2KMJOB6.cjs} +2 -2
- package/dist/chunk-H2KMJOB6.cjs.map +1 -0
- package/dist/{chunk-YDCD4AV4.js → chunk-HFJF477F.js} +3 -3
- package/dist/chunk-HFJF477F.js.map +1 -0
- package/dist/{chunk-ZYYTU7NY.js → chunk-HNRULYUH.js} +2 -2
- package/dist/chunk-HNRULYUH.js.map +1 -0
- package/dist/chunk-MOL7MDBG.js +0 -0
- package/dist/{chunk-LEC2HG7A.js → chunk-ONS7JKVA.js} +2 -2
- package/dist/chunk-ONS7JKVA.js.map +1 -0
- package/dist/{chunk-ZJ75YDW7.js → chunk-P7YPCK7C.js} +2 -2
- package/dist/chunk-P7YPCK7C.js.map +1 -0
- package/dist/{chunk-BPJSTJBN.js → chunk-QXYB74QF.js} +24 -3
- package/dist/chunk-QXYB74QF.js.map +1 -0
- package/dist/{chunk-BYEQDLZS.js → chunk-RZURSA4N.js} +6 -4
- package/dist/chunk-RZURSA4N.js.map +1 -0
- package/dist/{chunk-7DZPPUQD.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-ZMKTKJZN.cjs → chunk-UDGPM5R5.cjs} +26 -5
- package/dist/chunk-UDGPM5R5.cjs.map +1 -0
- package/dist/{chunk-GTPEKBN6.js → chunk-V35DRUJC.js} +2 -2
- package/dist/chunk-V35DRUJC.js.map +1 -0
- package/dist/{chunk-HPRK67YB.js → chunk-W6CUD7V3.js} +3 -3
- package/dist/chunk-W6CUD7V3.js.map +1 -0
- package/dist/{chunk-FUXDD36A.js → chunk-XCIC7U6Y.js} +24 -3
- package/dist/chunk-XCIC7U6Y.js.map +1 -0
- package/dist/{chunk-RO4Y4BFI.js → chunk-YOZ7ZRCD.js} +366 -51
- package/dist/chunk-YOZ7ZRCD.js.map +1 -0
- package/dist/{chunk-PV3NVBGL.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-MGVXT6XD.cjs → image-ocr-F2BQA26V.cjs} +11 -11
- package/dist/image-ocr-F2BQA26V.cjs.map +1 -0
- package/dist/{image-ocr-6MO4FXJK.js → image-ocr-U2DRRFL3.js} +5 -5
- package/dist/image-ocr-U2DRRFL3.js.map +1 -0
- package/dist/{image-ocr-TWUU2RNG.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-VR2BTUT7.js → parser-ESGFWWCT.js} +8 -8
- package/dist/parser-ESGFWWCT.js.map +1 -0
- package/dist/{parser-JFGLN4DA.cjs → parser-FFQN67O6.cjs} +25 -25
- package/dist/parser-FFQN67O6.cjs.map +1 -0
- package/dist/{parser-YA7HSSPK.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-QPIMGVO3.js → profile-io-O6BDCUJN.js} +3 -3
- package/dist/{rasterize-AFYGNKXG.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-D3JJEOAB.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/230/210/354/213/234/352/260/222.json +24 -24
- package/dist/chunk-3FFPHTXD.js.map +0 -1
- package/dist/chunk-5F5UCACZ.cjs.map +0 -1
- package/dist/chunk-6GBLFQMA.js.map +0 -1
- package/dist/chunk-6XPXIG57.js.map +0 -1
- package/dist/chunk-7DZPPUQD.cjs.map +0 -1
- package/dist/chunk-BPJSTJBN.js.map +0 -1
- package/dist/chunk-BYEQDLZS.js.map +0 -1
- package/dist/chunk-CD5X6UG5.js.map +0 -1
- package/dist/chunk-FUXDD36A.js.map +0 -1
- package/dist/chunk-GTPEKBN6.js.map +0 -1
- package/dist/chunk-HPRK67YB.js.map +0 -1
- package/dist/chunk-HZU7Y22R.js.map +0 -1
- package/dist/chunk-LEC2HG7A.js.map +0 -1
- package/dist/chunk-MGGU3ZRK.cjs.map +0 -1
- package/dist/chunk-O5EK52TG.js.map +0 -1
- package/dist/chunk-PV3NVBGL.js.map +0 -1
- package/dist/chunk-RO4Y4BFI.js.map +0 -1
- package/dist/chunk-SA22NK56.js.map +0 -1
- package/dist/chunk-VQB5P5KJ.cjs.map +0 -1
- package/dist/chunk-W34QSJFF.js.map +0 -1
- package/dist/chunk-YDCD4AV4.js.map +0 -1
- package/dist/chunk-YNJDNP44.js.map +0 -1
- package/dist/chunk-ZJ75YDW7.js.map +0 -1
- package/dist/chunk-ZMKTKJZN.cjs.map +0 -1
- package/dist/chunk-ZSL6MQVE.js.map +0 -1
- package/dist/chunk-ZYYTU7NY.js.map +0 -1
- package/dist/chunks-JEYQWXIZ.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-6MO4FXJK.js.map +0 -1
- package/dist/image-ocr-MGVXT6XD.cjs.map +0 -1
- package/dist/image-ocr-TWUU2RNG.js.map +0 -1
- package/dist/parser-JFGLN4DA.cjs.map +0 -1
- package/dist/parser-VR2BTUT7.js.map +0 -1
- package/dist/parser-YA7HSSPK.js.map +0 -1
- package/dist/pdf-ocr-4LISPZEM.cjs +0 -13
- package/dist/pdf-ocr-4LISPZEM.cjs.map +0 -1
- package/dist/pdf-ocr-AIWB2QCS.js +0 -12
- package/dist/pdf-ocr-QMOKUMC2.js +0 -15
- package/dist/rasterize-AFYGNKXG.js.map +0 -1
- package/dist/render-PSPTMZIZ.js +0 -10
- package/dist/seal-4XBJ7ISE.js +0 -10
- package/dist/setup-I4I75QJU.js.map +0 -1
- package/dist/watch-D3JJEOAB.js.map +0 -1
- /package/dist/{-RH6BEVTT.js.map → -R6NUMPRV.js.map} +0 -0
- /package/dist/{chunks-JEYQWXIZ.js.map → chunks-QMGCI5DG.js.map} +0 -0
- /package/dist/{models-6VMAVZR6.js.map → models-6SIKLKRH.js.map} +0 -0
- /package/dist/{pdf-ocr-AIWB2QCS.js.map → pdf-ocr-4R646OO6.js.map} +0 -0
- /package/dist/{pdf-ocr-QMOKUMC2.js.map → pdf-ocr-WE5TMRFU.js.map} +0 -0
- /package/dist/{profile-io-QPIMGVO3.js.map → profile-io-O6BDCUJN.js.map} +0 -0
- /package/dist/{redact-W5K3ILQH.js.map → redact-7ILEAUTS.js.map} +0 -0
- /package/dist/{render-PSPTMZIZ.js.map → render-3BSVTTZE.js.map} +0 -0
- /package/dist/{seal-4XBJ7ISE.js.map → seal-6ZSEJVOD.js.map} +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
inlineImagesIntoMarkdown
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-7FCNOKOR.js";
|
|
5
5
|
import {
|
|
6
6
|
HEADING_RATIO_H1,
|
|
7
7
|
HEADING_RATIO_H2,
|
|
8
8
|
HEADING_RATIO_H3
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-A73RMJ6B.js";
|
|
10
10
|
import {
|
|
11
11
|
parsePageRange
|
|
12
12
|
} from "./chunk-MOL7MDBG.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
paraTextPureT,
|
|
23
23
|
patchZipEntries,
|
|
24
24
|
scanSectionXml
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-RZURSA4N.js";
|
|
26
26
|
import {
|
|
27
27
|
MAX_COLS,
|
|
28
28
|
MAX_ROWS,
|
|
@@ -32,14 +32,14 @@ import {
|
|
|
32
32
|
dedupeRunningHeaders,
|
|
33
33
|
flattenLayoutTables,
|
|
34
34
|
mapPuaText
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-QXYB74QF.js";
|
|
36
36
|
import {
|
|
37
37
|
SPACE_EM_FIXED,
|
|
38
38
|
charWidthEm1000,
|
|
39
39
|
fitRatioForFewerLines,
|
|
40
40
|
measureTextWidth,
|
|
41
41
|
simulateWrap
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-65DYCXGC.js";
|
|
43
43
|
import {
|
|
44
44
|
MAX_DECOMPRESS_SIZE,
|
|
45
45
|
MAX_XML_DEPTH,
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
findChildByLocalName,
|
|
56
56
|
localName,
|
|
57
57
|
rawTextContent
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-5KLE3U23.js";
|
|
59
59
|
import {
|
|
60
60
|
KordocError,
|
|
61
61
|
classifyError,
|
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
sanitizeHref,
|
|
68
68
|
stripDtd,
|
|
69
69
|
toArrayBuffer
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-P7YPCK7C.js";
|
|
71
71
|
|
|
72
72
|
// src/index.ts
|
|
73
73
|
import { readFile } from "fs/promises";
|
|
@@ -446,6 +446,91 @@ function comResultToParseResult(pages, pageCount, warnings) {
|
|
|
446
446
|
};
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
+
// src/hwpx/crypto.ts
|
|
450
|
+
import { createDecipheriv, createHash, pbkdf2Sync, timingSafeEqual } from "crypto";
|
|
451
|
+
import { inflateRawSync } from "zlib";
|
|
452
|
+
var MAX_ITERATION_COUNT = 1e6;
|
|
453
|
+
var AES256_CBC = "http://www.w3.org/2001/04/xmlenc#aes256-cbc";
|
|
454
|
+
var START_KEY_SHA256 = "http://www.w3.org/2000/09/xmldsig#sha256";
|
|
455
|
+
var CHECKSUM_SHA256_1K = "sha256-1k";
|
|
456
|
+
var CHECKSUM_PREFIX_BYTES = 1024;
|
|
457
|
+
var attrOf = (xml, name) => xml.match(new RegExp(`${name}="([^"]*)"`))?.[1];
|
|
458
|
+
function parseEncryptionManifest(manifestXml) {
|
|
459
|
+
const entries = [];
|
|
460
|
+
const entryRe = /<[^:>\s]*:?file-entry\b([^>]*)>([\s\S]*?)<\/[^:>\s]*:?file-entry>/g;
|
|
461
|
+
let m;
|
|
462
|
+
while ((m = entryRe.exec(manifestXml)) !== null) {
|
|
463
|
+
const [, attrs, inner] = m;
|
|
464
|
+
if (!inner.includes("encryption-data")) continue;
|
|
465
|
+
const path = attrOf(attrs, "full-path");
|
|
466
|
+
if (!path) continue;
|
|
467
|
+
const algorithm = attrOf(inner, "algorithm-name");
|
|
468
|
+
const startKey = attrOf(inner, "start-key-generation-name");
|
|
469
|
+
const checksumType = attrOf(inner, "checksum-type");
|
|
470
|
+
if (algorithm !== AES256_CBC) {
|
|
471
|
+
throw new KordocError(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWPX \uC554\uD638\uD654 \uBC29\uC2DD\uC785\uB2C8\uB2E4: ${algorithm ?? "(\uBBF8\uC0C1)"}`);
|
|
472
|
+
}
|
|
473
|
+
if (startKey !== START_KEY_SHA256) {
|
|
474
|
+
throw new KordocError(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWPX \uC2DC\uC791\uD0A4 \uC0DD\uC131 \uBC29\uC2DD\uC785\uB2C8\uB2E4: ${startKey ?? "(\uBBF8\uC0C1)"}`);
|
|
475
|
+
}
|
|
476
|
+
if (!checksumType?.endsWith(CHECKSUM_SHA256_1K)) {
|
|
477
|
+
throw new KordocError(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWPX \uCCB4\uD06C\uC12C \uBC29\uC2DD\uC785\uB2C8\uB2E4: ${checksumType ?? "(\uBBF8\uC0C1)"}`);
|
|
478
|
+
}
|
|
479
|
+
const iterations = parseInt(attrOf(inner, "iteration-count") ?? "", 10);
|
|
480
|
+
const keySize = parseInt(attrOf(inner, "key-size") ?? "", 10);
|
|
481
|
+
const iv = Buffer.from(attrOf(inner, "initialisation-vector") ?? "", "base64");
|
|
482
|
+
const salt = Buffer.from(attrOf(inner, "salt") ?? "", "base64");
|
|
483
|
+
const checksum = Buffer.from(attrOf(inner, "checksum") ?? "", "base64");
|
|
484
|
+
if (!(iterations > 0 && iterations <= MAX_ITERATION_COUNT)) {
|
|
485
|
+
throw new KordocError(`HWPX \uC554\uD638\uD654 \uBC18\uBCF5 \uD69F\uC218\uAC00 \uD5C8\uC6A9 \uBC94\uC704\uB97C \uBC97\uC5B4\uB0AC\uC2B5\uB2C8\uB2E4: ${iterations}`);
|
|
486
|
+
}
|
|
487
|
+
if (keySize !== 32 || iv.length !== 16 || salt.length === 0 || checksum.length !== 32) {
|
|
488
|
+
throw new KordocError(`HWPX \uC554\uD638\uD654 \uD30C\uB77C\uBBF8\uD130\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (${path})`);
|
|
489
|
+
}
|
|
490
|
+
entries.push({ path, checksum, iv, salt, iterations, keySize });
|
|
491
|
+
}
|
|
492
|
+
return entries;
|
|
493
|
+
}
|
|
494
|
+
function stripEncryptionData(manifestXml) {
|
|
495
|
+
return manifestXml.replace(/<([^:>\s]*:?)encryption-data\b[\s\S]*?<\/\1encryption-data>/g, "");
|
|
496
|
+
}
|
|
497
|
+
function decryptEntry(cipher, entry, startKey) {
|
|
498
|
+
if (cipher.length === 0 || cipher.length % 16 !== 0) return void 0;
|
|
499
|
+
for (const prf of ["sha1", "sha256"]) {
|
|
500
|
+
try {
|
|
501
|
+
const key = pbkdf2Sync(startKey, entry.salt, entry.iterations, entry.keySize, prf);
|
|
502
|
+
const decipher = createDecipheriv("aes-256-cbc", key, entry.iv);
|
|
503
|
+
decipher.setAutoPadding(false);
|
|
504
|
+
const raw = Buffer.concat([decipher.update(cipher), decipher.final()]);
|
|
505
|
+
const plain = inflateRawSync(raw, { maxOutputLength: MAX_DECOMPRESS_SIZE });
|
|
506
|
+
const sum = createHash("sha256").update(plain.subarray(0, Math.min(CHECKSUM_PREFIX_BYTES, plain.length))).digest();
|
|
507
|
+
if (sum.length === entry.checksum.length && timingSafeEqual(sum, entry.checksum)) return plain;
|
|
508
|
+
} catch {
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return void 0;
|
|
512
|
+
}
|
|
513
|
+
async function decryptHwpxInPlace(zip, manifestXml, password) {
|
|
514
|
+
const entries = parseEncryptionManifest(manifestXml);
|
|
515
|
+
if (entries.length === 0) return 0;
|
|
516
|
+
const startKey = createHash("sha256").update(Buffer.from(password, "utf8")).digest();
|
|
517
|
+
const decrypted = [];
|
|
518
|
+
for (const entry of entries) {
|
|
519
|
+
const file = zip.file(entry.path);
|
|
520
|
+
if (!file) {
|
|
521
|
+
throw new KordocError(`\uC554\uD638 \uBAA9\uB85D\uC5D0 \uC788\uB294 \uD30C\uC77C\uC774 \uBB38\uC11C\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4: ${entry.path}`);
|
|
522
|
+
}
|
|
523
|
+
const plain = decryptEntry(await file.async("nodebuffer"), entry, startKey);
|
|
524
|
+
if (!plain) {
|
|
525
|
+
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.");
|
|
526
|
+
}
|
|
527
|
+
decrypted.push({ path: entry.path, plain });
|
|
528
|
+
}
|
|
529
|
+
for (const { path, plain } of decrypted) zip.file(path, plain);
|
|
530
|
+
zip.file("META-INF/manifest.xml", stripEncryptionData(manifestXml));
|
|
531
|
+
return decrypted.length;
|
|
532
|
+
}
|
|
533
|
+
|
|
449
534
|
// src/hwpx/styles.ts
|
|
450
535
|
function isRealStrikeShape(shape) {
|
|
451
536
|
switch (shape) {
|
|
@@ -1140,8 +1225,8 @@ function hmlToLatex(hmlEqStr) {
|
|
|
1140
1225
|
let tokens = s.split(" ");
|
|
1141
1226
|
for (let i = 0; i < tokens.length; i++) {
|
|
1142
1227
|
const t = tokens[i];
|
|
1143
|
-
if (t
|
|
1144
|
-
else if (t
|
|
1228
|
+
if (Object.hasOwn(CONVERT_MAP, t)) tokens[i] = CONVERT_MAP[t];
|
|
1229
|
+
else if (Object.hasOwn(MIDDLE_CONVERT_MAP, t)) tokens[i] = MIDDLE_CONVERT_MAP[t];
|
|
1145
1230
|
else {
|
|
1146
1231
|
const quoted = /^"(.+)"$/.exec(t);
|
|
1147
1232
|
if (quoted) tokens[i] = `\\text{${quoted[1]}}`;
|
|
@@ -2002,7 +2087,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
2002
2087
|
if (!children) return;
|
|
2003
2088
|
for (let i = 0; i < children.length; i++) {
|
|
2004
2089
|
const child = children[i];
|
|
2005
|
-
if (child.nodeType === 3) {
|
|
2090
|
+
if (child.nodeType === 3 || child.nodeType === 4) {
|
|
2006
2091
|
const t = child.textContent || "";
|
|
2007
2092
|
if (isInDeletedRange(ctx)) {
|
|
2008
2093
|
if (t && ctx && !ctx.shared.track.warned) {
|
|
@@ -2213,7 +2298,7 @@ function extractRunSpans(para2, ctx, mode, requireMixed) {
|
|
|
2213
2298
|
const tkids = rc.childNodes;
|
|
2214
2299
|
for (let k = 0; k < (tkids?.length ?? 0); k++) {
|
|
2215
2300
|
const tk = tkids[k];
|
|
2216
|
-
if (tk.nodeType === 3) text += tk.textContent || "";
|
|
2301
|
+
if (tk.nodeType === 3 || tk.nodeType === 4) text += tk.textContent || "";
|
|
2217
2302
|
else if (tk.nodeType === 1) return null;
|
|
2218
2303
|
}
|
|
2219
2304
|
} else if (rtag === "secPr" || rtag === "colPr") {
|
|
@@ -2271,7 +2356,7 @@ function gongmunDepthFromIndent(para2, left, ctx) {
|
|
|
2271
2356
|
}
|
|
2272
2357
|
|
|
2273
2358
|
// src/hwp5/record.ts
|
|
2274
|
-
import { inflateRawSync, inflateSync } from "zlib";
|
|
2359
|
+
import { inflateRawSync as inflateRawSync2, inflateSync } from "zlib";
|
|
2275
2360
|
var TAG_PARA_HEADER = 66;
|
|
2276
2361
|
var TAG_PARA_TEXT = 67;
|
|
2277
2362
|
var TAG_CHAR_SHAPE = 68;
|
|
@@ -2329,7 +2414,7 @@ function decompressStream(data) {
|
|
|
2329
2414
|
} catch {
|
|
2330
2415
|
}
|
|
2331
2416
|
}
|
|
2332
|
-
return
|
|
2417
|
+
return inflateRawSync2(data, opts);
|
|
2333
2418
|
}
|
|
2334
2419
|
function parseFileHeader(data) {
|
|
2335
2420
|
if (data.length < 40) throw new KordocError("FileHeader\uAC00 \uB108\uBB34 \uC9E7\uC2B5\uB2C8\uB2E4 (\uCD5C\uC18C 40\uBC14\uC774\uD2B8)");
|
|
@@ -2850,7 +2935,7 @@ async function extractImagesFromZip(zip, blocks, decompressed, warnings, sweepUn
|
|
|
2850
2935
|
import JSZip2 from "jszip";
|
|
2851
2936
|
|
|
2852
2937
|
// src/hwpx/zip-sections.ts
|
|
2853
|
-
import { inflateRawSync as
|
|
2938
|
+
import { inflateRawSync as inflateRawSync3 } from "zlib";
|
|
2854
2939
|
function extractFromBrokenZip(buffer) {
|
|
2855
2940
|
const data = new Uint8Array(buffer);
|
|
2856
2941
|
const view = new DataView(buffer);
|
|
@@ -2901,7 +2986,7 @@ function extractFromBrokenZip(buffer) {
|
|
|
2901
2986
|
if (method === 0) {
|
|
2902
2987
|
content = new TextDecoder().decode(fileData);
|
|
2903
2988
|
} else if (method === 8) {
|
|
2904
|
-
const decompressed =
|
|
2989
|
+
const decompressed = inflateRawSync3(Buffer.from(fileData), { maxOutputLength: MAX_DECOMPRESS_SIZE });
|
|
2905
2990
|
content = new TextDecoder().decode(decompressed);
|
|
2906
2991
|
} else {
|
|
2907
2992
|
continue;
|
|
@@ -3039,13 +3124,19 @@ async function parseHwpxDocument(buffer, options) {
|
|
|
3039
3124
|
if (manifestFile) {
|
|
3040
3125
|
const manifestXml = await manifestFile.async("text");
|
|
3041
3126
|
if (isEncryptedHwpx(manifestXml)) {
|
|
3042
|
-
if (
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3127
|
+
if (options?.password) {
|
|
3128
|
+
await decryptHwpxInPlace(zip, manifestXml, options.password);
|
|
3129
|
+
} else {
|
|
3130
|
+
if (isComFallbackAvailable() && options?.filePath) {
|
|
3131
|
+
const { pages, pageCount, warnings: warnings2 } = extractTextViaCom(options.filePath);
|
|
3132
|
+
if (pages.some((p) => p && p.trim().length > 0)) {
|
|
3133
|
+
return comResultToParseResult(pages, pageCount, warnings2);
|
|
3134
|
+
}
|
|
3046
3135
|
}
|
|
3136
|
+
throw new KordocError(
|
|
3137
|
+
"\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."
|
|
3138
|
+
);
|
|
3047
3139
|
}
|
|
3048
|
-
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.");
|
|
3049
3140
|
}
|
|
3050
3141
|
}
|
|
3051
3142
|
const decompressed = { total: 0 };
|
|
@@ -4000,11 +4091,11 @@ var WORD_ALIASES = {
|
|
|
4000
4091
|
var STRUCTURAL_FOLD = /* @__PURE__ */ new Set(["over", "root", "of"]);
|
|
4001
4092
|
function normalizeWords(input) {
|
|
4002
4093
|
return input.replace(/(?<![\\A-Za-z0-9])([A-Za-z][A-Za-z0-9]*)(?![A-Za-z0-9])/g, (word) => {
|
|
4003
|
-
if (
|
|
4094
|
+
if (Object.hasOwn(CONVERT_MAP, word) || Object.hasOwn(MIDDLE_CONVERT_MAP, word)) return word;
|
|
4004
4095
|
const lower = word.toLowerCase();
|
|
4005
4096
|
if (STRUCTURAL_FOLD.has(lower)) return lower;
|
|
4006
|
-
if (lower
|
|
4007
|
-
if (lower !== word && (
|
|
4097
|
+
if (Object.hasOwn(WORD_ALIASES, lower)) return WORD_ALIASES[lower];
|
|
4098
|
+
if (lower !== word && (Object.hasOwn(CONVERT_MAP, lower) || Object.hasOwn(MIDDLE_CONVERT_MAP, lower))) return lower;
|
|
4008
4099
|
return word;
|
|
4009
4100
|
});
|
|
4010
4101
|
}
|
|
@@ -4024,6 +4115,84 @@ function hwpEquationToLatex(equation) {
|
|
|
4024
4115
|
return hmlToLatex(s).replace(/\s+/g, " ").trim();
|
|
4025
4116
|
}
|
|
4026
4117
|
|
|
4118
|
+
// src/hwp5/pw-crypto.ts
|
|
4119
|
+
import { createCipheriv, createHash as createHash2 } from "crypto";
|
|
4120
|
+
var ENCRYPT_VERSION_OFFSET = 44;
|
|
4121
|
+
var SUPPORTED_ENCRYPT_VERSION = 4;
|
|
4122
|
+
var KEY_SEED = 236;
|
|
4123
|
+
function readEncryptVersion(fileHeader) {
|
|
4124
|
+
if (fileHeader.length < ENCRYPT_VERSION_OFFSET + 4) return 0;
|
|
4125
|
+
return (fileHeader[ENCRYPT_VERSION_OFFSET] | fileHeader[ENCRYPT_VERSION_OFFSET + 1] << 8 | fileHeader[ENCRYPT_VERSION_OFFSET + 2] << 16 | fileHeader[ENCRYPT_VERSION_OFFSET + 3] << 24) >>> 0;
|
|
4126
|
+
}
|
|
4127
|
+
function derivePasswordKey(password) {
|
|
4128
|
+
const buf = Buffer.alloc(password.length * 2);
|
|
4129
|
+
for (let i = 0; i < password.length; i++) {
|
|
4130
|
+
const prev = i === 0 ? KEY_SEED : password[i - 1];
|
|
4131
|
+
buf[i * 2] = (prev << 1 | prev >> 7) & 255;
|
|
4132
|
+
buf[i * 2 + 1] = password[i];
|
|
4133
|
+
}
|
|
4134
|
+
return createHash2("sha1").update(buf).digest().subarray(0, 16);
|
|
4135
|
+
}
|
|
4136
|
+
function padToBlock(data) {
|
|
4137
|
+
const rem = data.length % 16;
|
|
4138
|
+
if (rem === 0) return Buffer.from(data);
|
|
4139
|
+
const amount = 16 - rem;
|
|
4140
|
+
return Buffer.concat([Buffer.from(data), Buffer.alloc(amount, amount)]);
|
|
4141
|
+
}
|
|
4142
|
+
function shiftRegister(reg, feedbackBit) {
|
|
4143
|
+
for (let i = 0; i < 15; i++) {
|
|
4144
|
+
reg[i] = (reg[i] << 1 | reg[i + 1] >> 7) & 255;
|
|
4145
|
+
}
|
|
4146
|
+
reg[15] = (reg[15] << 1 | feedbackBit & 1) & 255;
|
|
4147
|
+
}
|
|
4148
|
+
function decryptAesCfb1(data, key) {
|
|
4149
|
+
const cipher = createCipheriv("aes-128-ecb", key, null);
|
|
4150
|
+
cipher.setAutoPadding(false);
|
|
4151
|
+
const register = new Uint8Array(16);
|
|
4152
|
+
const registerBuf = Buffer.alloc(16);
|
|
4153
|
+
const out = Buffer.alloc(data.length);
|
|
4154
|
+
for (let offset = 0; offset < data.length; offset += 16) {
|
|
4155
|
+
const len = Math.min(16, data.length - offset);
|
|
4156
|
+
const chunk = Buffer.alloc(16);
|
|
4157
|
+
data.copy(chunk, 0, offset, offset + len);
|
|
4158
|
+
for (let i = 0; i < 128; i++) {
|
|
4159
|
+
registerBuf.set(register);
|
|
4160
|
+
const keystreamMsb = cipher.update(registerBuf)[0];
|
|
4161
|
+
const byteIdx = i >> 3;
|
|
4162
|
+
const bitInByte = i & 7;
|
|
4163
|
+
const cipherBit = chunk[byteIdx] >> 7 - bitInByte & 1;
|
|
4164
|
+
shiftRegister(register, cipherBit);
|
|
4165
|
+
chunk[byteIdx] ^= (keystreamMsb & 128) >> bitInByte;
|
|
4166
|
+
}
|
|
4167
|
+
chunk.copy(out, offset, 0, len);
|
|
4168
|
+
}
|
|
4169
|
+
return out;
|
|
4170
|
+
}
|
|
4171
|
+
function decryptPasswordStream(raw, password) {
|
|
4172
|
+
const key = derivePasswordKey(Buffer.from(password, "utf8"));
|
|
4173
|
+
return decryptAesCfb1(padToBlock(raw), key).subarray(0, raw.length);
|
|
4174
|
+
}
|
|
4175
|
+
var TAG_DOCUMENT_PROPERTIES = 16;
|
|
4176
|
+
var TAG_ID_MAPPINGS = 17;
|
|
4177
|
+
function assertDecryptedDocInfo(data, readRecords3) {
|
|
4178
|
+
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.");
|
|
4179
|
+
let records;
|
|
4180
|
+
try {
|
|
4181
|
+
records = readRecords3(data);
|
|
4182
|
+
} catch {
|
|
4183
|
+
throw wrong();
|
|
4184
|
+
}
|
|
4185
|
+
if (records[0]?.tagId !== TAG_DOCUMENT_PROPERTIES) throw wrong();
|
|
4186
|
+
if (!records.some((r) => r.tagId === TAG_ID_MAPPINGS)) throw wrong();
|
|
4187
|
+
}
|
|
4188
|
+
function assertSupportedEncryptVersion(version) {
|
|
4189
|
+
if (version !== SUPPORTED_ENCRYPT_VERSION) {
|
|
4190
|
+
throw new KordocError(
|
|
4191
|
+
`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HWP \uC554\uD638\uD654 \uBC84\uC804\uC785\uB2C8\uB2E4 (EncryptVersion=${version}, \uC9C0\uC6D0: ${SUPPORTED_ENCRYPT_VERSION})`
|
|
4192
|
+
);
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4027
4196
|
// src/hwp5/parser.ts
|
|
4028
4197
|
import { createRequire } from "module";
|
|
4029
4198
|
var require2 = createRequire(import.meta.url);
|
|
@@ -4104,27 +4273,50 @@ function parseHwp5Document(buffer, options) {
|
|
|
4104
4273
|
throw new KordocError("CFB \uCEE8\uD14C\uC774\uB108 \uD30C\uC2F1 \uC2E4\uD328 (strict \uBC0F lenient \uBAA8\uB450)");
|
|
4105
4274
|
}
|
|
4106
4275
|
}
|
|
4107
|
-
const
|
|
4276
|
+
const readRawStream = (path) => {
|
|
4108
4277
|
if (cfb) {
|
|
4109
4278
|
const entry = CFB.find(cfb, path);
|
|
4110
4279
|
return entry?.content ? Buffer.from(entry.content) : null;
|
|
4111
4280
|
}
|
|
4112
4281
|
return lenientCfb.findStream(path);
|
|
4113
4282
|
};
|
|
4114
|
-
const headerData =
|
|
4283
|
+
const headerData = readRawStream("/FileHeader");
|
|
4115
4284
|
if (!headerData) throw new KordocError("FileHeader \uC2A4\uD2B8\uB9BC \uC5C6\uC74C");
|
|
4116
4285
|
const header = parseFileHeader(headerData);
|
|
4117
4286
|
if (header.signature !== "HWP Document File") throw new KordocError("HWP \uC2DC\uADF8\uB2C8\uCC98 \uBD88\uC77C\uCE58");
|
|
4118
|
-
if (header.flags & FLAG_ENCRYPTED) throw new KordocError("\uC554\uD638\uD654\uB41C HWP\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
4119
4287
|
if (header.flags & FLAG_DRM) throw new KordocError("DRM \uBCF4\uD638\uB41C HWP\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
4288
|
+
const encrypted = (header.flags & FLAG_ENCRYPTED) !== 0;
|
|
4289
|
+
if (encrypted) {
|
|
4290
|
+
if (!options?.password) {
|
|
4291
|
+
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.");
|
|
4292
|
+
}
|
|
4293
|
+
assertSupportedEncryptVersion(readEncryptVersion(headerData));
|
|
4294
|
+
}
|
|
4295
|
+
const password = encrypted ? options.password : void 0;
|
|
4296
|
+
const findStream = (path) => {
|
|
4297
|
+
const raw = readRawStream(path);
|
|
4298
|
+
if (!raw || !password) return raw;
|
|
4299
|
+
return decryptPasswordStream(raw, password);
|
|
4300
|
+
};
|
|
4120
4301
|
const compressed = (header.flags & FLAG_COMPRESSED) !== 0;
|
|
4121
4302
|
const distribution = (header.flags & FLAG_DISTRIBUTION) !== 0;
|
|
4122
4303
|
const metadata = {
|
|
4123
4304
|
version: `${header.versionMajor}.x`
|
|
4124
4305
|
};
|
|
4125
4306
|
if (cfb) extractHwp5Metadata(cfb, metadata);
|
|
4126
|
-
|
|
4127
|
-
|
|
4307
|
+
if (encrypted) {
|
|
4308
|
+
const rawDocInfo = findStream("/DocInfo");
|
|
4309
|
+
if (!rawDocInfo) throw new KordocError("DocInfo \uC2A4\uD2B8\uB9BC \uC5C6\uC74C");
|
|
4310
|
+
let docInfoData;
|
|
4311
|
+
try {
|
|
4312
|
+
docInfoData = compressed ? decompressStream(rawDocInfo) : rawDocInfo;
|
|
4313
|
+
} catch {
|
|
4314
|
+
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.");
|
|
4315
|
+
}
|
|
4316
|
+
assertDecryptedDocInfo(docInfoData, readRecords);
|
|
4317
|
+
}
|
|
4318
|
+
const docInfo = cfb && !encrypted ? parseDocInfoStream(cfb, compressed) : parseDocInfoFromStream(findStream("/DocInfo"), compressed);
|
|
4319
|
+
const sections = distribution ? cfb ? findViewTextSections(cfb, compressed) : findViewTextSectionsLenient(lenientCfb, compressed) : encrypted ? findSectionsVia(findStream) : cfb ? findSections(cfb) : findSectionsLenient(lenientCfb, compressed);
|
|
4128
4320
|
if (sections.length === 0) throw new KordocError("\uC139\uC158 \uC2A4\uD2B8\uB9BC\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
4129
4321
|
metadata.pageCount = sections.length;
|
|
4130
4322
|
const pageFilter = options?.pages ? parsePageRange(options.pages, sections.length) : null;
|
|
@@ -4306,6 +4498,15 @@ function findViewTextSections(cfb, compressed) {
|
|
|
4306
4498
|
}
|
|
4307
4499
|
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
4308
4500
|
}
|
|
4501
|
+
function findSectionsVia(read) {
|
|
4502
|
+
const sections = [];
|
|
4503
|
+
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
4504
|
+
const raw = read(`/BodyText/Section${i}`);
|
|
4505
|
+
if (!raw) break;
|
|
4506
|
+
sections.push(raw);
|
|
4507
|
+
}
|
|
4508
|
+
return sections;
|
|
4509
|
+
}
|
|
4309
4510
|
function findSections(cfb) {
|
|
4310
4511
|
const sections = [];
|
|
4311
4512
|
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
@@ -4911,7 +5112,7 @@ function hasRealStrike(attrFlags) {
|
|
|
4911
5112
|
}
|
|
4912
5113
|
|
|
4913
5114
|
// src/hwp3/parser.ts
|
|
4914
|
-
import { inflateRawSync as
|
|
5115
|
+
import { inflateRawSync as inflateRawSync5 } from "zlib";
|
|
4915
5116
|
|
|
4916
5117
|
// src/hwp3/johab-symbols.ts
|
|
4917
5118
|
var JOHAB_SYMBOLS = Object.freeze([
|
|
@@ -16819,6 +17020,23 @@ function lookupSymbol(ch) {
|
|
|
16819
17020
|
return null;
|
|
16820
17021
|
}
|
|
16821
17022
|
var JOHAB_UNMAPPED = -1;
|
|
17023
|
+
var JUNG_ARAEA = 30;
|
|
17024
|
+
var ARAEA_JAMO = 4510;
|
|
17025
|
+
function decodeAraeaSyllable(ch) {
|
|
17026
|
+
if (ch < 32768) return null;
|
|
17027
|
+
if ((ch >> 5 & 31) !== JUNG_ARAEA) return null;
|
|
17028
|
+
const cho = CHO_MAP[ch >> 10 & 31];
|
|
17029
|
+
const jong = JONG_MAP[ch & 31];
|
|
17030
|
+
if (cho === -1 || jong === -1) return null;
|
|
17031
|
+
const out = String.fromCodePoint(4352 + cho) + String.fromCodePoint(ARAEA_JAMO);
|
|
17032
|
+
return jong === 0 ? out : out + String.fromCodePoint(4519 + jong);
|
|
17033
|
+
}
|
|
17034
|
+
function decodeJohabText(ch) {
|
|
17035
|
+
const araea = decodeAraeaSyllable(ch);
|
|
17036
|
+
if (araea) return araea;
|
|
17037
|
+
const cp = decodeJohab(ch);
|
|
17038
|
+
return cp === JOHAB_UNMAPPED ? null : String.fromCodePoint(cp);
|
|
17039
|
+
}
|
|
16822
17040
|
function decodeJohab(ch) {
|
|
16823
17041
|
if (ch < 128) return ch;
|
|
16824
17042
|
if (ch >= 32768) {
|
|
@@ -16840,6 +17058,7 @@ function decodeJohab(ch) {
|
|
|
16840
17058
|
function decodeHwp3Extra(ch) {
|
|
16841
17059
|
if (ch >= 13712 && ch <= 13721) return 8544 + (ch - 13712);
|
|
16842
17060
|
if (ch >= 14055 && ch <= 14064) return 9312 + (ch - 14055);
|
|
17061
|
+
if (ch >= 14272 && ch <= 14277) return "\uD55C\uAE00\uACFC\uCEF4\uD4E8\uD130".codePointAt(ch - 14272);
|
|
16843
17062
|
switch (ch) {
|
|
16844
17063
|
case 129:
|
|
16845
17064
|
return 8220;
|
|
@@ -16874,6 +17093,9 @@ function decodeHwp3Extra(ch) {
|
|
|
16874
17093
|
case 13434:
|
|
16875
17094
|
return 9654;
|
|
16876
17095
|
// ▶
|
|
17096
|
+
case 12135:
|
|
17097
|
+
return 9656;
|
|
17098
|
+
// ▸ 표 셀 글머리표 (rhwp 16db8260 — HWP5 변환본·한컴 PDF 대조)
|
|
16877
17099
|
default:
|
|
16878
17100
|
return JOHAB_UNMAPPED;
|
|
16879
17101
|
}
|
|
@@ -16884,8 +17106,7 @@ function decodeHcharString(bytes) {
|
|
|
16884
17106
|
while (i + 1 < bytes.length) {
|
|
16885
17107
|
const ch = bytes[i] | bytes[i + 1] << 8;
|
|
16886
17108
|
if (ch === 0) break;
|
|
16887
|
-
|
|
16888
|
-
if (cp !== JOHAB_UNMAPPED) out += String.fromCodePoint(cp);
|
|
17109
|
+
out += decodeJohabText(ch) ?? "";
|
|
16889
17110
|
i += 2;
|
|
16890
17111
|
}
|
|
16891
17112
|
return out;
|
|
@@ -16990,6 +17211,87 @@ function readHeader(reader) {
|
|
|
16990
17211
|
return { compressed, encrypted, infoBlockLength, title, subject, author, date };
|
|
16991
17212
|
}
|
|
16992
17213
|
|
|
17214
|
+
// src/hwp3/crypto.ts
|
|
17215
|
+
import { createDecipheriv as createDecipheriv2 } from "crypto";
|
|
17216
|
+
import { inflateRawSync as inflateRawSync4 } from "zlib";
|
|
17217
|
+
var FIXED_HEADER_BYTES = SIGNATURE_LEN + DOC_INFO_SIZE + DOC_SUMMARY_SIZE;
|
|
17218
|
+
var PASSWORD_FLAG_OFFSET = SIGNATURE_LEN + 96;
|
|
17219
|
+
var COMPRESSION_FLAG_OFFSET = SIGNATURE_LEN + 124;
|
|
17220
|
+
var INFO_BLOCK_LENGTH_OFFSET = SIGNATURE_LEN + 126;
|
|
17221
|
+
var PASSWORD_PREFIX_BYTES = 256;
|
|
17222
|
+
var MAX_DECOMPRESSED_BYTES = 100 * 1024 * 1024;
|
|
17223
|
+
function isEncryptedHwp3(data) {
|
|
17224
|
+
if (data.length < FIXED_HEADER_BYTES) return false;
|
|
17225
|
+
return (data[PASSWORD_FLAG_OFFSET] | data[PASSWORD_FLAG_OFFSET + 1] << 8) !== 0;
|
|
17226
|
+
}
|
|
17227
|
+
function deriveDesKey(password) {
|
|
17228
|
+
const rolling = new Uint8Array(7);
|
|
17229
|
+
let index = 0;
|
|
17230
|
+
for (let i = 0; i < password.length; i++) {
|
|
17231
|
+
const unit = password.charCodeAt(i);
|
|
17232
|
+
for (const byte of [unit & 255, unit >> 8 & 255]) {
|
|
17233
|
+
const slot = index % rolling.length;
|
|
17234
|
+
const mixed = rolling[slot] ^ byte;
|
|
17235
|
+
rolling[slot] = (mixed << 1 | mixed >> 7) & 255;
|
|
17236
|
+
index++;
|
|
17237
|
+
}
|
|
17238
|
+
}
|
|
17239
|
+
const key = Buffer.alloc(8);
|
|
17240
|
+
for (let bit = 0; bit < 56; bit++) {
|
|
17241
|
+
const sourceBit = rolling[Math.floor(bit / 8)] >> 7 - bit % 8 & 1;
|
|
17242
|
+
key[Math.floor(bit / 7)] |= sourceBit << 7 - bit % 7;
|
|
17243
|
+
}
|
|
17244
|
+
return key;
|
|
17245
|
+
}
|
|
17246
|
+
function desEcbDecrypt(data, key) {
|
|
17247
|
+
const decipher = createDecipheriv2("des-ede3-ecb", Buffer.concat([key, key, key]), null);
|
|
17248
|
+
decipher.setAutoPadding(false);
|
|
17249
|
+
return Buffer.concat([decipher.update(data), decipher.final()]);
|
|
17250
|
+
}
|
|
17251
|
+
function readLayout(data) {
|
|
17252
|
+
if (data.length < FIXED_HEADER_BYTES) {
|
|
17253
|
+
throw new KordocError("HWP3 \uC554\uD638 \uBB38\uC11C: \uD5E4\uB354\uAC00 \uC798\uB838\uC2B5\uB2C8\uB2E4");
|
|
17254
|
+
}
|
|
17255
|
+
const infoBlockLength = data[INFO_BLOCK_LENGTH_OFFSET] | data[INFO_BLOCK_LENGTH_OFFSET + 1] << 8;
|
|
17256
|
+
const payloadOffset = FIXED_HEADER_BYTES + infoBlockLength;
|
|
17257
|
+
if (payloadOffset >= data.length) {
|
|
17258
|
+
throw new KordocError("HWP3 \uC554\uD638 \uBB38\uC11C: \uBCF8\uBB38\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
17259
|
+
}
|
|
17260
|
+
return { payloadOffset, compressed: data[COMPRESSION_FLAG_OFFSET] !== 0 };
|
|
17261
|
+
}
|
|
17262
|
+
function decryptHwp3Document(input, password) {
|
|
17263
|
+
const { payloadOffset, compressed } = readLayout(input);
|
|
17264
|
+
if (!compressed) {
|
|
17265
|
+
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)");
|
|
17266
|
+
}
|
|
17267
|
+
const source = Buffer.from(input);
|
|
17268
|
+
const payload = source.subarray(payloadOffset);
|
|
17269
|
+
const aligned = payload.subarray(0, payload.length - payload.length % 8);
|
|
17270
|
+
if (aligned.length === 0) {
|
|
17271
|
+
throw new KordocError("HWP3 \uC554\uD638 \uBB38\uC11C: \uBCF8\uBB38\uC774 \uB108\uBB34 \uC9E7\uC2B5\uB2C8\uB2E4");
|
|
17272
|
+
}
|
|
17273
|
+
const decrypted = desEcbDecrypt(aligned, deriveDesKey(password));
|
|
17274
|
+
let inflated;
|
|
17275
|
+
try {
|
|
17276
|
+
inflated = inflateRawSync4(decrypted, { maxOutputLength: MAX_DECOMPRESSED_BYTES });
|
|
17277
|
+
} catch (err) {
|
|
17278
|
+
if (err?.code === "ERR_BUFFER_TOO_LARGE") {
|
|
17279
|
+
throw new KordocError(
|
|
17280
|
+
`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`
|
|
17281
|
+
);
|
|
17282
|
+
}
|
|
17283
|
+
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.");
|
|
17284
|
+
}
|
|
17285
|
+
if (inflated.length <= PASSWORD_PREFIX_BYTES) {
|
|
17286
|
+
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.");
|
|
17287
|
+
}
|
|
17288
|
+
const body = inflated.subarray(PASSWORD_PREFIX_BYTES);
|
|
17289
|
+
const out = Buffer.concat([source.subarray(0, payloadOffset), body]);
|
|
17290
|
+
out.writeUInt16LE(0, PASSWORD_FLAG_OFFSET);
|
|
17291
|
+
out[COMPRESSION_FLAG_OFFSET] = 0;
|
|
17292
|
+
return out;
|
|
17293
|
+
}
|
|
17294
|
+
|
|
16993
17295
|
// src/hwp3/parser.ts
|
|
16994
17296
|
var MAX_DECOMPRESS_SIZE3 = 100 * 1024 * 1024;
|
|
16995
17297
|
var PARA_SHAPE_SIZE = 187;
|
|
@@ -17012,19 +17314,25 @@ var SIMPLE_CTRL = /* @__PURE__ */ new Map([
|
|
|
17012
17314
|
[30, { extraBytes: 2, extraHchar: 1, emit: "\xA0" }],
|
|
17013
17315
|
[31, { extraBytes: 2, extraHchar: 1, emit: " " }]
|
|
17014
17316
|
]);
|
|
17015
|
-
function parseHwp3Document(buffer,
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17317
|
+
function parseHwp3Document(buffer, options) {
|
|
17318
|
+
let source = Buffer.from(buffer);
|
|
17319
|
+
if (isEncryptedHwp3(source)) {
|
|
17320
|
+
if (!options?.password) {
|
|
17321
|
+
throw new KordocError(
|
|
17322
|
+
"\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."
|
|
17323
|
+
);
|
|
17324
|
+
}
|
|
17325
|
+
source = decryptHwp3Document(source, options.password);
|
|
17020
17326
|
}
|
|
17327
|
+
const headReader = new Reader(source);
|
|
17328
|
+
const header = readHeader(headReader);
|
|
17021
17329
|
headReader.skip(header.infoBlockLength);
|
|
17022
17330
|
const tail = headReader.readToEnd();
|
|
17023
17331
|
let body;
|
|
17024
17332
|
const warnings = [];
|
|
17025
17333
|
if (header.compressed !== 0) {
|
|
17026
17334
|
try {
|
|
17027
|
-
body =
|
|
17335
|
+
body = inflateRawSync5(tail, { maxOutputLength: MAX_DECOMPRESS_SIZE3 });
|
|
17028
17336
|
} catch (err) {
|
|
17029
17337
|
if (err?.code === "ERR_BUFFER_TOO_LARGE") {
|
|
17030
17338
|
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`);
|
|
@@ -17127,8 +17435,7 @@ function parseCharStream(reader, charCount, ctx) {
|
|
|
17127
17435
|
continue;
|
|
17128
17436
|
}
|
|
17129
17437
|
if (ch >= 32) {
|
|
17130
|
-
|
|
17131
|
-
if (cp !== JOHAB_UNMAPPED) out += String.fromCodePoint(cp);
|
|
17438
|
+
out += decodeJohabText(ch) ?? "";
|
|
17132
17439
|
continue;
|
|
17133
17440
|
}
|
|
17134
17441
|
const simple = SIMPLE_CTRL.get(ch);
|
|
@@ -17196,7 +17503,7 @@ function parseCharStream(reader, charCount, ctx) {
|
|
|
17196
17503
|
function parseTableLike(reader, ctx) {
|
|
17197
17504
|
const info = reader.readBytes(84);
|
|
17198
17505
|
const cellCount = info.readUInt16LE(80) || 1;
|
|
17199
|
-
if (cellCount >
|
|
17506
|
+
if (27 * cellCount > reader.remaining()) {
|
|
17200
17507
|
ctx.warnings.push({
|
|
17201
17508
|
code: "PARTIAL_PARSE",
|
|
17202
17509
|
message: `HWP3 \uD45C cell_count=${cellCount} \uBE44\uC815\uC0C1 \u2014 \uD45C \uBCF8\uBB38 \uCD94\uCD9C \uD3EC\uAE30`
|
|
@@ -17210,10 +17517,11 @@ function parseTableLike(reader, ctx) {
|
|
|
17210
17517
|
parseParagraphList2(reader, ctx);
|
|
17211
17518
|
return "";
|
|
17212
17519
|
}
|
|
17213
|
-
function parsePicture(reader,
|
|
17520
|
+
function parsePicture(reader, ctx) {
|
|
17214
17521
|
const info = reader.readBytes(348);
|
|
17215
17522
|
const nExt = info.readUInt32LE(0);
|
|
17216
17523
|
if (nExt > 0 && nExt < 100 * 1024 * 1024) reader.skip(nExt);
|
|
17524
|
+
parseParagraphList2(reader, ctx);
|
|
17217
17525
|
}
|
|
17218
17526
|
|
|
17219
17527
|
// src/hwp5/sentinel.ts
|
|
@@ -19922,7 +20230,9 @@ async function fillWithUniqueGuard(values, run) {
|
|
|
19922
20230
|
const first = await run(values);
|
|
19923
20231
|
const counts = /* @__PURE__ */ new Map();
|
|
19924
20232
|
for (const f of first.filled) {
|
|
19925
|
-
if (f.key
|
|
20233
|
+
if (f.key && f.source !== "clickhere") {
|
|
20234
|
+
counts.set(f.key, (counts.get(f.key) ?? 0) + 1);
|
|
20235
|
+
}
|
|
19926
20236
|
}
|
|
19927
20237
|
const isArrayValue = (normKey) => {
|
|
19928
20238
|
for (const [label, raw] of Object.entries(values)) {
|
|
@@ -20383,7 +20693,7 @@ import JSZip7 from "jszip";
|
|
|
20383
20693
|
// src/form/click-here.ts
|
|
20384
20694
|
import JSZip6 from "jszip";
|
|
20385
20695
|
var FIELD_BEGIN_RE = /<([A-Za-z0-9_]+:)?fieldBegin\b([^>]*?)(\/?)>/g;
|
|
20386
|
-
function
|
|
20696
|
+
function attrOf2(attrs, name) {
|
|
20387
20697
|
const m = attrs.match(new RegExp(`(?:^|\\s)${name}="([^"]*)"`));
|
|
20388
20698
|
return m ? m[1] : void 0;
|
|
20389
20699
|
}
|
|
@@ -20409,10 +20719,10 @@ function scanClickHereRegions(xml) {
|
|
|
20409
20719
|
const prefix = m[1] ?? "";
|
|
20410
20720
|
const attrs = m[2];
|
|
20411
20721
|
const selfClosed = m[3] === "/";
|
|
20412
|
-
if ((
|
|
20413
|
-
const name =
|
|
20722
|
+
if ((attrOf2(attrs, "type") ?? "").toUpperCase() !== "CLICK_HERE") continue;
|
|
20723
|
+
const name = attrOf2(attrs, "name");
|
|
20414
20724
|
if (name === void 0) continue;
|
|
20415
|
-
const id =
|
|
20725
|
+
const id = attrOf2(attrs, "id");
|
|
20416
20726
|
let beginElemEnd;
|
|
20417
20727
|
if (selfClosed) {
|
|
20418
20728
|
beginElemEnd = FIELD_BEGIN_RE.lastIndex;
|
|
@@ -20435,7 +20745,7 @@ function scanClickHereRegions(xml) {
|
|
|
20435
20745
|
let end = -1;
|
|
20436
20746
|
let fe;
|
|
20437
20747
|
while ((fe = feRe.exec(xml)) !== null) {
|
|
20438
|
-
const ref =
|
|
20748
|
+
const ref = attrOf2(fe[0], "beginIDRef");
|
|
20439
20749
|
if (id !== void 0 && ref !== void 0 && ref !== id) continue;
|
|
20440
20750
|
end = fe.index;
|
|
20441
20751
|
break;
|
|
@@ -20476,7 +20786,7 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
|
|
|
20476
20786
|
const replacement = valueXml(value, region.prefix);
|
|
20477
20787
|
const current = xml.slice(region.start, region.end);
|
|
20478
20788
|
matchedKeys.add(key);
|
|
20479
|
-
filled.push({ label: region.name, value, row: -1, col: -1, key });
|
|
20789
|
+
filled.push({ label: region.name, value, row: -1, col: -1, key, source: "clickhere" });
|
|
20480
20790
|
if (current === replacement) continue;
|
|
20481
20791
|
splices.push({ start: region.start, end: region.end, replacement });
|
|
20482
20792
|
}
|
|
@@ -20487,6 +20797,7 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
|
|
|
20487
20797
|
};
|
|
20488
20798
|
}
|
|
20489
20799
|
async function extractClickHereFields(hwpxBuffer) {
|
|
20800
|
+
precheckZipSize(hwpxBuffer);
|
|
20490
20801
|
const zip = await JSZip6.loadAsync(hwpxBuffer);
|
|
20491
20802
|
const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
|
|
20492
20803
|
const fields = [];
|
|
@@ -20507,6 +20818,7 @@ async function extractClickHereFields(hwpxBuffer) {
|
|
|
20507
20818
|
// src/form/filler-hwpx.ts
|
|
20508
20819
|
async function fillHwpx(hwpxBuffer, values, blockedLabels) {
|
|
20509
20820
|
const u8 = new Uint8Array(hwpxBuffer);
|
|
20821
|
+
precheckZipSize(hwpxBuffer);
|
|
20510
20822
|
const zip = await JSZip7.loadAsync(hwpxBuffer);
|
|
20511
20823
|
const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
|
|
20512
20824
|
if (sectionPaths.length === 0) {
|
|
@@ -25770,6 +26082,9 @@ function applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, before, a
|
|
|
25770
26082
|
const xml = ctx.scans[target.sectionIndex]?.xml;
|
|
25771
26083
|
const rawT = xml ? paraTText(target, xml) : null;
|
|
25772
26084
|
let sp;
|
|
26085
|
+
if (xml && rawT === null) {
|
|
26086
|
+
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");
|
|
26087
|
+
}
|
|
25773
26088
|
if (xml && rawT !== null && rawT.length > 0 && rawT.trim() === "") {
|
|
25774
26089
|
sp = buildRangeSplices(target, xml, 0, 0, value);
|
|
25775
26090
|
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");
|
|
@@ -28012,7 +28327,7 @@ async function parse(input, options) {
|
|
|
28012
28327
|
}
|
|
28013
28328
|
async function parseImage(buffer, options) {
|
|
28014
28329
|
try {
|
|
28015
|
-
const { parseImageDocument } = await import("./image-ocr-
|
|
28330
|
+
const { parseImageDocument } = await import("./image-ocr-XC52AQDV.js");
|
|
28016
28331
|
const { blocks, warnings } = await parseImageDocument(buffer, options);
|
|
28017
28332
|
return {
|
|
28018
28333
|
success: true,
|
|
@@ -28071,7 +28386,7 @@ async function parseHwp(buffer, options) {
|
|
|
28071
28386
|
async function parsePdf(buffer, options) {
|
|
28072
28387
|
let parsePdfDocument;
|
|
28073
28388
|
try {
|
|
28074
|
-
const mod = await import("./parser-
|
|
28389
|
+
const mod = await import("./parser-ESGFWWCT.js");
|
|
28075
28390
|
parsePdfDocument = mod.parsePdfDocument;
|
|
28076
28391
|
} catch {
|
|
28077
28392
|
return {
|
|
@@ -28217,4 +28532,4 @@ export {
|
|
|
28217
28532
|
parseHwpml,
|
|
28218
28533
|
fillForm
|
|
28219
28534
|
};
|
|
28220
|
-
//# sourceMappingURL=chunk-
|
|
28535
|
+
//# sourceMappingURL=chunk-YOZ7ZRCD.js.map
|