kordoc 3.0.0 → 3.0.1
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/README.md +10 -1
- package/dist/{-K5SLEFZD.js → -5BWAV4ZY.js} +5 -3
- package/dist/{chunk-3WRJQQIO.cjs → chunk-NBJB6TJB.cjs} +2 -2
- package/dist/{chunk-3WRJQQIO.cjs.map → chunk-NBJB6TJB.cjs.map} +1 -1
- package/dist/{chunk-SA2PERJ5.js → chunk-O5P6EG5L.js} +2 -2
- package/dist/{chunk-NHXKJWR7.js → chunk-X3SCCO5Q.js} +2 -2
- package/dist/{chunk-326STEDU.js → chunk-X7VQVMXQ.js} +845 -12
- package/dist/chunk-X7VQVMXQ.js.map +1 -0
- package/dist/cli.js +9 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +964 -131
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +844 -11
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +3 -3
- package/dist/{parser-AU2NLC44.js → parser-3N6FZSKU.js} +2 -2
- package/dist/{parser-5KHU732L.cjs → parser-5FZJVLQL.cjs} +14 -14
- package/dist/{parser-5KHU732L.cjs.map → parser-5FZJVLQL.cjs.map} +1 -1
- package/dist/{parser-4IVYHKSL.js → parser-LZH7ZELV.js} +2 -2
- package/dist/{watch-5DDN4BUI.js → watch-4FMRS7QU.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-326STEDU.js.map +0 -1
- /package/dist/{-K5SLEFZD.js.map → -5BWAV4ZY.js.map} +0 -0
- /package/dist/{chunk-SA2PERJ5.js.map → chunk-O5P6EG5L.js.map} +0 -0
- /package/dist/{chunk-NHXKJWR7.js.map → chunk-X3SCCO5Q.js.map} +0 -0
- /package/dist/{parser-AU2NLC44.js.map → parser-3N6FZSKU.js.map} +0 -0
- /package/dist/{parser-4IVYHKSL.js.map → parser-LZH7ZELV.js.map} +0 -0
- /package/dist/{watch-5DDN4BUI.js.map → watch-4FMRS7QU.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
sanitizeHref,
|
|
18
18
|
stripDtd,
|
|
19
19
|
toArrayBuffer
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-X3SCCO5Q.js";
|
|
21
21
|
import {
|
|
22
22
|
parsePageRange
|
|
23
23
|
} from "./chunk-SBVRCJFH.js";
|
|
@@ -824,9 +824,9 @@ function createSectionShared() {
|
|
|
824
824
|
}
|
|
825
825
|
function createXmlParser(warnings) {
|
|
826
826
|
return new DOMParser({
|
|
827
|
-
onError(level,
|
|
828
|
-
if (level === "fatalError") throw new KordocError(`XML \uD30C\uC2F1 \uC2E4\uD328: ${
|
|
829
|
-
warnings?.push({ code: "MALFORMED_XML", message: `XML ${level === "warn" ? "\uACBD\uACE0" : "\uC624\uB958"}: ${
|
|
827
|
+
onError(level, msg2) {
|
|
828
|
+
if (level === "fatalError") throw new KordocError(`XML \uD30C\uC2F1 \uC2E4\uD328: ${msg2}`);
|
|
829
|
+
warnings?.push({ code: "MALFORMED_XML", message: `XML ${level === "warn" ? "\uACBD\uACE0" : "\uC624\uB958"}: ${msg2}` });
|
|
830
830
|
}
|
|
831
831
|
});
|
|
832
832
|
}
|
|
@@ -16501,8 +16501,8 @@ function parseHwp3Document(buffer, _options) {
|
|
|
16501
16501
|
try {
|
|
16502
16502
|
body = inflateRawSync3(tail);
|
|
16503
16503
|
} catch (err) {
|
|
16504
|
-
const
|
|
16505
|
-
throw new Error(`HWP3 \uC555\uCD95 \uD574\uC81C \uC2E4\uD328: ${
|
|
16504
|
+
const msg2 = err instanceof Error ? err.message : String(err);
|
|
16505
|
+
throw new Error(`HWP3 \uC555\uCD95 \uD574\uC81C \uC2E4\uD328: ${msg2}`);
|
|
16506
16506
|
}
|
|
16507
16507
|
} else {
|
|
16508
16508
|
body = tail;
|
|
@@ -18434,8 +18434,8 @@ function parseHwpmlDocument(buffer, options) {
|
|
|
18434
18434
|
const xml = stripDtd(normalized);
|
|
18435
18435
|
const warnings = [];
|
|
18436
18436
|
const parser = new DOMParser4({
|
|
18437
|
-
onError: (_level,
|
|
18438
|
-
warnings.push({ message: `HWPML XML \uD30C\uC2F1 \uACBD\uACE0: ${
|
|
18437
|
+
onError: (_level, msg2) => {
|
|
18438
|
+
warnings.push({ message: `HWPML XML \uD30C\uC2F1 \uACBD\uACE0: ${msg2}`, code: "MALFORMED_XML" });
|
|
18439
18439
|
}
|
|
18440
18440
|
});
|
|
18441
18441
|
const doc = parser.parseFromString(xml, "text/xml");
|
|
@@ -21465,6 +21465,838 @@ function sectionPathsFromManifest(xml) {
|
|
|
21465
21465
|
return Array.from(idToHref.entries()).filter(([id]) => isSectionId(id)).sort((a, b) => a[0].localeCompare(b[0])).map(([, href]) => href);
|
|
21466
21466
|
}
|
|
21467
21467
|
|
|
21468
|
+
// src/roundtrip/hwp5-patch.ts
|
|
21469
|
+
import { deflateRawSync as deflateRawSync2 } from "zlib";
|
|
21470
|
+
import { createRequire as createRequire2 } from "module";
|
|
21471
|
+
|
|
21472
|
+
// src/roundtrip/ole-surgeon.ts
|
|
21473
|
+
var SECTOR = 512;
|
|
21474
|
+
var MINI_SECTOR = 64;
|
|
21475
|
+
var MINI_CUTOFF = 4096;
|
|
21476
|
+
var FREESECT = 4294967295;
|
|
21477
|
+
var ENDOFCHAIN = 4294967294;
|
|
21478
|
+
var FATSECT = 4294967293;
|
|
21479
|
+
var OleSurgeonError = class extends Error {
|
|
21480
|
+
};
|
|
21481
|
+
function replaceOleStream(file, path, newData) {
|
|
21482
|
+
const surgeon = new Surgeon(file);
|
|
21483
|
+
surgeon.replace(path, newData);
|
|
21484
|
+
return surgeon.finish();
|
|
21485
|
+
}
|
|
21486
|
+
var Surgeon = class {
|
|
21487
|
+
buf;
|
|
21488
|
+
fat = [];
|
|
21489
|
+
/** FAT 배열을 구성하는 섹터 번호들 (DIFAT 순서) */
|
|
21490
|
+
fatSectors = [];
|
|
21491
|
+
miniFat = [];
|
|
21492
|
+
miniFatSectors = [];
|
|
21493
|
+
dirSectors = [];
|
|
21494
|
+
entries = [];
|
|
21495
|
+
constructor(file) {
|
|
21496
|
+
if (file.length < SECTOR || file.readUInt32LE(0) !== 3759263696) {
|
|
21497
|
+
throw new OleSurgeonError("OLE \uC2DC\uADF8\uB2C8\uCC98\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
21498
|
+
}
|
|
21499
|
+
if (file.readUInt16LE(26) !== 3 || file.readUInt16LE(30) !== 9) {
|
|
21500
|
+
throw new OleSurgeonError("CFB v3(512B \uC139\uD130)\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4");
|
|
21501
|
+
}
|
|
21502
|
+
const padded = Math.ceil((file.length - SECTOR) / SECTOR) * SECTOR + SECTOR;
|
|
21503
|
+
this.buf = Buffer.alloc(padded);
|
|
21504
|
+
file.copy(this.buf);
|
|
21505
|
+
this.loadFat();
|
|
21506
|
+
this.loadMiniFat();
|
|
21507
|
+
this.loadDirectory();
|
|
21508
|
+
}
|
|
21509
|
+
// ── 로드 ──
|
|
21510
|
+
loadFat() {
|
|
21511
|
+
const difat = [];
|
|
21512
|
+
for (let i = 0; i < 109; i++) difat.push(this.buf.readUInt32LE(76 + i * 4));
|
|
21513
|
+
let difatSector = this.buf.readUInt32LE(68);
|
|
21514
|
+
let guard = 0;
|
|
21515
|
+
while (difatSector !== ENDOFCHAIN && difatSector !== FREESECT && guard++ < 1e6) {
|
|
21516
|
+
const off = this.sectorOffset(difatSector);
|
|
21517
|
+
for (let i = 0; i < 127; i++) difat.push(this.buf.readUInt32LE(off + i * 4));
|
|
21518
|
+
difatSector = this.buf.readUInt32LE(off + 127 * 4);
|
|
21519
|
+
}
|
|
21520
|
+
this.fatSectors = difat.filter((s) => s !== FREESECT);
|
|
21521
|
+
for (const s of this.fatSectors) {
|
|
21522
|
+
const off = this.sectorOffset(s);
|
|
21523
|
+
for (let i = 0; i < 128; i++) this.fat.push(this.buf.readUInt32LE(off + i * 4));
|
|
21524
|
+
}
|
|
21525
|
+
}
|
|
21526
|
+
loadMiniFat() {
|
|
21527
|
+
const start = this.buf.readUInt32LE(60);
|
|
21528
|
+
this.miniFatSectors = start === ENDOFCHAIN || start === FREESECT ? [] : this.chain(start);
|
|
21529
|
+
for (const s of this.miniFatSectors) {
|
|
21530
|
+
const off = this.sectorOffset(s);
|
|
21531
|
+
for (let i = 0; i < 128; i++) this.miniFat.push(this.buf.readUInt32LE(off + i * 4));
|
|
21532
|
+
}
|
|
21533
|
+
}
|
|
21534
|
+
loadDirectory() {
|
|
21535
|
+
this.dirSectors = this.chain(this.buf.readUInt32LE(48));
|
|
21536
|
+
for (let si = 0; si < this.dirSectors.length; si++) {
|
|
21537
|
+
const off = this.sectorOffset(this.dirSectors[si]);
|
|
21538
|
+
for (let i = 0; i < 4; i++) {
|
|
21539
|
+
const e = off + i * 128;
|
|
21540
|
+
const nameLen = this.buf.readUInt16LE(e + 64);
|
|
21541
|
+
const name = nameLen >= 2 ? this.buf.subarray(e, e + nameLen - 2).toString("utf16le") : "";
|
|
21542
|
+
this.entries.push({
|
|
21543
|
+
index: si * 4 + i,
|
|
21544
|
+
name,
|
|
21545
|
+
type: this.buf[e + 66],
|
|
21546
|
+
left: this.buf.readInt32LE(e + 68),
|
|
21547
|
+
right: this.buf.readInt32LE(e + 72),
|
|
21548
|
+
child: this.buf.readInt32LE(e + 76),
|
|
21549
|
+
start: this.buf.readUInt32LE(e + 116),
|
|
21550
|
+
size: this.buf.readUInt32LE(e + 120)
|
|
21551
|
+
});
|
|
21552
|
+
}
|
|
21553
|
+
}
|
|
21554
|
+
}
|
|
21555
|
+
// ── 헬퍼 ──
|
|
21556
|
+
sectorOffset(n) {
|
|
21557
|
+
const off = SECTOR + n * SECTOR;
|
|
21558
|
+
if (n >= 4294967290 || off + SECTOR > this.buf.length) throw new OleSurgeonError(`\uC139\uD130 \uBC94\uC704 \uCD08\uACFC: ${n}`);
|
|
21559
|
+
return off;
|
|
21560
|
+
}
|
|
21561
|
+
chain(start) {
|
|
21562
|
+
const out = [];
|
|
21563
|
+
let s = start;
|
|
21564
|
+
while (s !== ENDOFCHAIN) {
|
|
21565
|
+
if (s === FREESECT || s >= this.fat.length || out.length > this.fat.length) {
|
|
21566
|
+
throw new OleSurgeonError("FAT \uCCB4\uC778 \uC190\uC0C1");
|
|
21567
|
+
}
|
|
21568
|
+
out.push(s);
|
|
21569
|
+
s = this.fat[s];
|
|
21570
|
+
}
|
|
21571
|
+
return out;
|
|
21572
|
+
}
|
|
21573
|
+
miniChain(start) {
|
|
21574
|
+
const out = [];
|
|
21575
|
+
let s = start;
|
|
21576
|
+
while (s !== ENDOFCHAIN) {
|
|
21577
|
+
if (s === FREESECT || s >= this.miniFat.length || out.length > this.miniFat.length) {
|
|
21578
|
+
throw new OleSurgeonError("miniFAT \uCCB4\uC778 \uC190\uC0C1");
|
|
21579
|
+
}
|
|
21580
|
+
out.push(s);
|
|
21581
|
+
s = this.miniFat[s];
|
|
21582
|
+
}
|
|
21583
|
+
return out;
|
|
21584
|
+
}
|
|
21585
|
+
/** 디렉토리 트리에서 경로 해석 (형제 = L/R 이진 트리, 자식 = child) */
|
|
21586
|
+
findEntry(path) {
|
|
21587
|
+
const parts = path.replace(/^\//, "").split("/");
|
|
21588
|
+
let scope = this.entries[0]?.child ?? -1;
|
|
21589
|
+
let current;
|
|
21590
|
+
for (const part of parts) {
|
|
21591
|
+
const search = (idx) => {
|
|
21592
|
+
if (idx < 0 || idx >= this.entries.length) return void 0;
|
|
21593
|
+
const e = this.entries[idx];
|
|
21594
|
+
return search(e.left) ?? (e.name === part ? e : void 0) ?? search(e.right);
|
|
21595
|
+
};
|
|
21596
|
+
current = search(scope);
|
|
21597
|
+
if (!current) throw new OleSurgeonError(`\uC2A4\uD2B8\uB9BC \uC5C6\uC74C: ${path}`);
|
|
21598
|
+
scope = current.child;
|
|
21599
|
+
}
|
|
21600
|
+
if (!current || current.type !== 2) throw new OleSurgeonError(`\uC2A4\uD2B8\uB9BC\uC774 \uC544\uB2D8: ${path}`);
|
|
21601
|
+
return current;
|
|
21602
|
+
}
|
|
21603
|
+
rootEntry() {
|
|
21604
|
+
return this.entries[0];
|
|
21605
|
+
}
|
|
21606
|
+
// ── 할당 ──
|
|
21607
|
+
/**
|
|
21608
|
+
* FAT에서 빈 섹터 n개 확보 (부족하면 파일 끝에 추가) — 섹터 번호 목록 반환.
|
|
21609
|
+
* 확보 즉시 ENDOFCHAIN으로 마킹해 같은 수술 내 중복 할당을 방지한다 (체인 링크는
|
|
21610
|
+
* 호출자가 덮어씀).
|
|
21611
|
+
*/
|
|
21612
|
+
allocSectors(n) {
|
|
21613
|
+
const out = [];
|
|
21614
|
+
for (let i = 0; i < this.fat.length && out.length < n; i++) {
|
|
21615
|
+
if (this.fat[i] !== FREESECT) continue;
|
|
21616
|
+
if (SECTOR + (i + 1) * SECTOR > this.buf.length) continue;
|
|
21617
|
+
this.fat[i] = ENDOFCHAIN;
|
|
21618
|
+
out.push(i);
|
|
21619
|
+
}
|
|
21620
|
+
while (out.length < n) {
|
|
21621
|
+
this.ensureFatCapacity((this.buf.length - SECTOR) / SECTOR + 2);
|
|
21622
|
+
const idx = (this.buf.length - SECTOR) / SECTOR;
|
|
21623
|
+
this.buf = Buffer.concat([this.buf, Buffer.alloc(SECTOR)]);
|
|
21624
|
+
this.fat[idx] = ENDOFCHAIN;
|
|
21625
|
+
out.push(idx);
|
|
21626
|
+
}
|
|
21627
|
+
return out;
|
|
21628
|
+
}
|
|
21629
|
+
/** FAT 배열이 sectorCount개 엔트리를 담도록 확장 (FAT 섹터 추가 + DIFAT 갱신) */
|
|
21630
|
+
ensureFatCapacity(sectorCount) {
|
|
21631
|
+
while (this.fat.length < sectorCount) {
|
|
21632
|
+
const idx = (this.buf.length - SECTOR) / SECTOR;
|
|
21633
|
+
this.buf = Buffer.concat([this.buf, Buffer.alloc(SECTOR)]);
|
|
21634
|
+
for (let i = 0; i < 128; i++) this.fat.push(FREESECT);
|
|
21635
|
+
this.fat[idx] = FATSECT;
|
|
21636
|
+
this.fatSectors.push(idx);
|
|
21637
|
+
const slot = this.fatSectors.length - 1;
|
|
21638
|
+
if (slot >= 109) throw new OleSurgeonError("DIFAT \uCCB4\uC778 \uD655\uC7A5\uC740 \uBBF8\uC9C0\uC6D0 (7MB \uCD08\uACFC \uCEE8\uD14C\uC774\uB108 \uC131\uC7A5)");
|
|
21639
|
+
this.buf.writeUInt32LE(idx, 76 + slot * 4);
|
|
21640
|
+
this.buf.writeUInt32LE(this.fatSectors.length, 44);
|
|
21641
|
+
}
|
|
21642
|
+
}
|
|
21643
|
+
/** miniFAT에서 빈 미니섹터 n개 확보 (mini stream 용량/miniFAT 확장 포함) */
|
|
21644
|
+
allocMiniSectors(n) {
|
|
21645
|
+
const root = this.rootEntry();
|
|
21646
|
+
const rootChain = root.start === ENDOFCHAIN || root.size === 0 ? [] : this.chain(root.start);
|
|
21647
|
+
let capacity = rootChain.length * (SECTOR / MINI_SECTOR);
|
|
21648
|
+
const out = [];
|
|
21649
|
+
for (let i = 0; i < Math.min(this.miniFat.length, capacity) && out.length < n; i++) {
|
|
21650
|
+
if (this.miniFat[i] === FREESECT) {
|
|
21651
|
+
this.miniFat[i] = ENDOFCHAIN;
|
|
21652
|
+
out.push(i);
|
|
21653
|
+
}
|
|
21654
|
+
}
|
|
21655
|
+
let nextIdx = capacity;
|
|
21656
|
+
while (out.length < n) {
|
|
21657
|
+
if (nextIdx >= this.miniFat.length) {
|
|
21658
|
+
const [s] = this.allocSectors(1);
|
|
21659
|
+
if (this.miniFatSectors.length > 0) this.fat[this.miniFatSectors[this.miniFatSectors.length - 1]] = s;
|
|
21660
|
+
else this.buf.writeUInt32LE(s, 60);
|
|
21661
|
+
this.miniFatSectors.push(s);
|
|
21662
|
+
this.buf.writeUInt32LE(this.miniFatSectors.length, 64);
|
|
21663
|
+
for (let i = 0; i < 128; i++) this.miniFat.push(FREESECT);
|
|
21664
|
+
}
|
|
21665
|
+
if (nextIdx >= capacity) {
|
|
21666
|
+
const [s] = this.allocSectors(1);
|
|
21667
|
+
if (rootChain.length > 0) this.fat[rootChain[rootChain.length - 1]] = s;
|
|
21668
|
+
else {
|
|
21669
|
+
root.start = s;
|
|
21670
|
+
}
|
|
21671
|
+
rootChain.push(s);
|
|
21672
|
+
capacity = rootChain.length * (SECTOR / MINI_SECTOR);
|
|
21673
|
+
root.size = Math.max(root.size, rootChain.length * SECTOR);
|
|
21674
|
+
this.writeDirEntry(root);
|
|
21675
|
+
}
|
|
21676
|
+
this.miniFat[nextIdx] = ENDOFCHAIN;
|
|
21677
|
+
out.push(nextIdx);
|
|
21678
|
+
nextIdx++;
|
|
21679
|
+
}
|
|
21680
|
+
return out;
|
|
21681
|
+
}
|
|
21682
|
+
// ── 기록 ──
|
|
21683
|
+
writeDirEntry(e) {
|
|
21684
|
+
const sector = this.dirSectors[Math.floor(e.index / 4)];
|
|
21685
|
+
const off = this.sectorOffset(sector) + e.index % 4 * 128;
|
|
21686
|
+
this.buf.writeUInt32LE(e.start, off + 116);
|
|
21687
|
+
this.buf.writeUInt32LE(e.size, off + 120);
|
|
21688
|
+
}
|
|
21689
|
+
flushFat() {
|
|
21690
|
+
for (let i = 0; i < this.fatSectors.length; i++) {
|
|
21691
|
+
const off = this.sectorOffset(this.fatSectors[i]);
|
|
21692
|
+
for (let j = 0; j < 128; j++) {
|
|
21693
|
+
const idx = i * 128 + j;
|
|
21694
|
+
this.buf.writeUInt32LE(idx < this.fat.length ? this.fat[idx] : FREESECT, off + j * 4);
|
|
21695
|
+
}
|
|
21696
|
+
}
|
|
21697
|
+
for (let i = 0; i < this.miniFatSectors.length; i++) {
|
|
21698
|
+
const off = this.sectorOffset(this.miniFatSectors[i]);
|
|
21699
|
+
for (let j = 0; j < 128; j++) {
|
|
21700
|
+
const idx = i * 128 + j;
|
|
21701
|
+
this.buf.writeUInt32LE(idx < this.miniFat.length ? this.miniFat[idx] : FREESECT, off + j * 4);
|
|
21702
|
+
}
|
|
21703
|
+
}
|
|
21704
|
+
}
|
|
21705
|
+
/** 미니섹터 k의 파일 내 바이트 오프셋 (root 체인 경유) */
|
|
21706
|
+
miniOffset(k, rootChain) {
|
|
21707
|
+
const within = k * MINI_SECTOR;
|
|
21708
|
+
const sec = rootChain[Math.floor(within / SECTOR)];
|
|
21709
|
+
if (sec === void 0) throw new OleSurgeonError("mini stream \uBC94\uC704 \uCD08\uACFC");
|
|
21710
|
+
return this.sectorOffset(sec) + within % SECTOR;
|
|
21711
|
+
}
|
|
21712
|
+
// ── 메인 ──
|
|
21713
|
+
replace(path, newData) {
|
|
21714
|
+
const entry = this.findEntry(path);
|
|
21715
|
+
if (entry.size > 0 && entry.start !== ENDOFCHAIN) {
|
|
21716
|
+
if (entry.size < MINI_CUTOFF) {
|
|
21717
|
+
for (const s of this.miniChain(entry.start)) this.miniFat[s] = FREESECT;
|
|
21718
|
+
} else {
|
|
21719
|
+
for (const s of this.chain(entry.start)) this.fat[s] = FREESECT;
|
|
21720
|
+
}
|
|
21721
|
+
}
|
|
21722
|
+
if (newData.length < MINI_CUTOFF) {
|
|
21723
|
+
const count = Math.ceil(newData.length / MINI_SECTOR) || 1;
|
|
21724
|
+
const sectors = this.allocMiniSectors(count);
|
|
21725
|
+
const rootChain = this.chain(this.rootEntry().start);
|
|
21726
|
+
for (let i = 0; i < sectors.length; i++) {
|
|
21727
|
+
this.miniFat[sectors[i]] = i + 1 < sectors.length ? sectors[i + 1] : ENDOFCHAIN;
|
|
21728
|
+
const off = this.miniOffset(sectors[i], rootChain);
|
|
21729
|
+
this.buf.fill(0, off, off + MINI_SECTOR);
|
|
21730
|
+
newData.copy(this.buf, off, i * MINI_SECTOR, Math.min((i + 1) * MINI_SECTOR, newData.length));
|
|
21731
|
+
}
|
|
21732
|
+
entry.start = sectors[0];
|
|
21733
|
+
} else {
|
|
21734
|
+
const count = Math.ceil(newData.length / SECTOR);
|
|
21735
|
+
const sectors = this.allocSectors(count);
|
|
21736
|
+
for (let i = 0; i < sectors.length; i++) {
|
|
21737
|
+
this.fat[sectors[i]] = i + 1 < sectors.length ? sectors[i + 1] : ENDOFCHAIN;
|
|
21738
|
+
const off = this.sectorOffset(sectors[i]);
|
|
21739
|
+
this.buf.fill(0, off, off + SECTOR);
|
|
21740
|
+
newData.copy(this.buf, off, i * SECTOR, Math.min((i + 1) * SECTOR, newData.length));
|
|
21741
|
+
}
|
|
21742
|
+
entry.start = sectors[0];
|
|
21743
|
+
}
|
|
21744
|
+
entry.size = newData.length;
|
|
21745
|
+
this.writeDirEntry(entry);
|
|
21746
|
+
}
|
|
21747
|
+
finish() {
|
|
21748
|
+
this.flushFat();
|
|
21749
|
+
return this.buf;
|
|
21750
|
+
}
|
|
21751
|
+
};
|
|
21752
|
+
|
|
21753
|
+
// src/roundtrip/hwp5-patch.ts
|
|
21754
|
+
var require3 = createRequire2(import.meta.url);
|
|
21755
|
+
var CFB2 = require3("cfb");
|
|
21756
|
+
var TAG_PARA_LINE_SEG = 69;
|
|
21757
|
+
function cid2(s) {
|
|
21758
|
+
return (s.charCodeAt(0) << 24 | s.charCodeAt(1) << 16 | s.charCodeAt(2) << 8 | s.charCodeAt(3)) >>> 0;
|
|
21759
|
+
}
|
|
21760
|
+
var CTRL_TBL2 = cid2("tbl ");
|
|
21761
|
+
var CTRL_GSO2 = cid2("gso ");
|
|
21762
|
+
function swap322(id) {
|
|
21763
|
+
return ((id & 255) << 24 | (id >>> 8 & 255) << 16 | (id >>> 16 & 255) << 8 | id >>> 24 & 255) >>> 0;
|
|
21764
|
+
}
|
|
21765
|
+
function isCtrl(rec, id) {
|
|
21766
|
+
if (rec.tagId !== TAG_CTRL_HEADER || rec.data.length < 4) return false;
|
|
21767
|
+
const raw = rec.data.readUInt32LE(0);
|
|
21768
|
+
return raw === id || swap322(raw) === id;
|
|
21769
|
+
}
|
|
21770
|
+
function readRecordsStrict(stream) {
|
|
21771
|
+
const recs = [];
|
|
21772
|
+
let off = 0;
|
|
21773
|
+
while (off < stream.length) {
|
|
21774
|
+
if (off + 4 > stream.length) return null;
|
|
21775
|
+
const h = stream.readUInt32LE(off);
|
|
21776
|
+
off += 4;
|
|
21777
|
+
const tagId = h & 1023;
|
|
21778
|
+
const level = h >>> 10 & 1023;
|
|
21779
|
+
let size = h >>> 20 & 4095;
|
|
21780
|
+
if (size === 4095) {
|
|
21781
|
+
if (off + 4 > stream.length) return null;
|
|
21782
|
+
size = stream.readUInt32LE(off);
|
|
21783
|
+
off += 4;
|
|
21784
|
+
}
|
|
21785
|
+
if (off + size > stream.length) return null;
|
|
21786
|
+
recs.push({ tagId, level, data: stream.subarray(off, off + size) });
|
|
21787
|
+
off += size;
|
|
21788
|
+
}
|
|
21789
|
+
return recs;
|
|
21790
|
+
}
|
|
21791
|
+
function serializeRecords(recs, repl) {
|
|
21792
|
+
const parts = [];
|
|
21793
|
+
for (let i = 0; i < recs.length; i++) {
|
|
21794
|
+
const data = repl?.get(i) ?? recs[i].data;
|
|
21795
|
+
const ext = data.length >= 4095;
|
|
21796
|
+
const header = Buffer.alloc(ext ? 8 : 4);
|
|
21797
|
+
header.writeUInt32LE((recs[i].tagId & 1023 | (recs[i].level & 1023) << 10 | (ext ? 4095 : data.length) << 20) >>> 0, 0);
|
|
21798
|
+
if (ext) header.writeUInt32LE(data.length, 4);
|
|
21799
|
+
parts.push(header, data);
|
|
21800
|
+
}
|
|
21801
|
+
return Buffer.concat(parts);
|
|
21802
|
+
}
|
|
21803
|
+
function scanSection(stream, sectionIndex, compressed) {
|
|
21804
|
+
const records = readRecordsStrict(stream);
|
|
21805
|
+
if (!records) return { records: [], safe: false, paras: [], tables: [], compressed, repl: /* @__PURE__ */ new Map() };
|
|
21806
|
+
const safe = serializeRecords(records).equals(stream);
|
|
21807
|
+
const parent = new Int32Array(records.length).fill(-1);
|
|
21808
|
+
const stack = [];
|
|
21809
|
+
for (let i = 0; i < records.length; i++) {
|
|
21810
|
+
while (stack.length > 0 && records[stack[stack.length - 1]].level >= records[i].level) stack.pop();
|
|
21811
|
+
parent[i] = stack.length > 0 ? stack[stack.length - 1] : -1;
|
|
21812
|
+
stack.push(i);
|
|
21813
|
+
}
|
|
21814
|
+
const ancestorCtrl = (i, id) => {
|
|
21815
|
+
for (let p = parent[i]; p >= 0; p = parent[p]) if (isCtrl(records[p], id)) return true;
|
|
21816
|
+
return false;
|
|
21817
|
+
};
|
|
21818
|
+
const paras = [];
|
|
21819
|
+
const parasByHeader = /* @__PURE__ */ new Map();
|
|
21820
|
+
for (let i = 0; i < records.length; i++) {
|
|
21821
|
+
const rec = records[i];
|
|
21822
|
+
if (rec.tagId !== TAG_PARA_HEADER || rec.data.length < 18) continue;
|
|
21823
|
+
let textIdx = -1;
|
|
21824
|
+
let charShapeIdx = -1;
|
|
21825
|
+
let lineSegIdx = -1;
|
|
21826
|
+
const state = createParaTextState();
|
|
21827
|
+
for (let j = i + 1; j < records.length && records[j].level > rec.level; j++) {
|
|
21828
|
+
if (records[j].level !== rec.level + 1) continue;
|
|
21829
|
+
const t = records[j].tagId;
|
|
21830
|
+
if (t === TAG_PARA_TEXT) {
|
|
21831
|
+
textIdx = textIdx === -1 ? j : -2;
|
|
21832
|
+
appendParaText(state, records[j].data);
|
|
21833
|
+
} else if (t === TAG_CHAR_SHAPE && charShapeIdx === -1) charShapeIdx = j;
|
|
21834
|
+
else if (t === TAG_PARA_LINE_SEG && lineSegIdx === -1) lineSegIdx = j;
|
|
21835
|
+
}
|
|
21836
|
+
let ctrlSeen = false, nonGso = false;
|
|
21837
|
+
for (let a = parent[i]; a >= 0; a = parent[a]) {
|
|
21838
|
+
if (records[a].tagId === TAG_CTRL_HEADER) {
|
|
21839
|
+
ctrlSeen = true;
|
|
21840
|
+
if (!isCtrl(records[a], CTRL_GSO2)) nonGso = true;
|
|
21841
|
+
}
|
|
21842
|
+
}
|
|
21843
|
+
const kind = !ctrlSeen || !nonGso ? "body" : "other";
|
|
21844
|
+
const para = {
|
|
21845
|
+
sectionIndex,
|
|
21846
|
+
headerIdx: i,
|
|
21847
|
+
kind,
|
|
21848
|
+
textIdx,
|
|
21849
|
+
charShapeIdx,
|
|
21850
|
+
lineSegIdx,
|
|
21851
|
+
rangeTagCount: rec.data.readUInt16LE(14),
|
|
21852
|
+
ctrlMask: rec.data.readUInt32LE(4),
|
|
21853
|
+
nCharsRaw: rec.data.readUInt32LE(0),
|
|
21854
|
+
rawText: state.text
|
|
21855
|
+
};
|
|
21856
|
+
paras.push(para);
|
|
21857
|
+
parasByHeader.set(i, para);
|
|
21858
|
+
}
|
|
21859
|
+
const tables = [];
|
|
21860
|
+
for (let i = 0; i < records.length; i++) {
|
|
21861
|
+
if (!isCtrl(records[i], CTRL_TBL2) || ancestorCtrl(i, CTRL_TBL2)) continue;
|
|
21862
|
+
const ctrlLevel = records[i].level;
|
|
21863
|
+
let rows = 0, cols = 0, tableIdx = -1;
|
|
21864
|
+
for (let j2 = i + 1; j2 < records.length && records[j2].level > ctrlLevel; j2++) {
|
|
21865
|
+
if (records[j2].level === ctrlLevel + 1 && records[j2].tagId === TAG_TABLE && records[j2].data.length >= 8) {
|
|
21866
|
+
rows = records[j2].data.readUInt16LE(4);
|
|
21867
|
+
cols = records[j2].data.readUInt16LE(6);
|
|
21868
|
+
tableIdx = j2;
|
|
21869
|
+
break;
|
|
21870
|
+
}
|
|
21871
|
+
}
|
|
21872
|
+
if (tableIdx < 0 || rows === 0 || cols === 0) continue;
|
|
21873
|
+
const cells = /* @__PURE__ */ new Map();
|
|
21874
|
+
let j = tableIdx + 1;
|
|
21875
|
+
while (j < records.length && records[j].level > ctrlLevel) {
|
|
21876
|
+
if (records[j].tagId !== TAG_LIST_HEADER) {
|
|
21877
|
+
j++;
|
|
21878
|
+
continue;
|
|
21879
|
+
}
|
|
21880
|
+
const lh = records[j];
|
|
21881
|
+
const cellLevel = lh.level;
|
|
21882
|
+
const cellParas = [];
|
|
21883
|
+
let k = j + 1;
|
|
21884
|
+
while (k < records.length) {
|
|
21885
|
+
const r = records[k];
|
|
21886
|
+
if (r.level < cellLevel) break;
|
|
21887
|
+
if (r.level === cellLevel && (r.tagId === TAG_LIST_HEADER || r.tagId === TAG_TABLE)) break;
|
|
21888
|
+
if (r.level === cellLevel && r.tagId === TAG_PARA_HEADER) {
|
|
21889
|
+
const cp = parasByHeader.get(k);
|
|
21890
|
+
if (cp) {
|
|
21891
|
+
cp.kind = "cell";
|
|
21892
|
+
cellParas.push(cp);
|
|
21893
|
+
}
|
|
21894
|
+
}
|
|
21895
|
+
k++;
|
|
21896
|
+
}
|
|
21897
|
+
if (lh.data.length >= 16) {
|
|
21898
|
+
cells.set(`${lh.data.readUInt16LE(10)},${lh.data.readUInt16LE(8)}`, { paras: cellParas });
|
|
21899
|
+
}
|
|
21900
|
+
j = k;
|
|
21901
|
+
}
|
|
21902
|
+
tables.push({ sectionIndex, rows, cols, cells });
|
|
21903
|
+
}
|
|
21904
|
+
return { records, safe, paras, tables, compressed, repl: /* @__PURE__ */ new Map() };
|
|
21905
|
+
}
|
|
21906
|
+
async function patchHwp(original, editedMarkdown, options) {
|
|
21907
|
+
const skipped = [];
|
|
21908
|
+
let applied = 0;
|
|
21909
|
+
const originalBuf = Buffer.from(original.buffer, original.byteOffset, original.byteLength);
|
|
21910
|
+
let cfb;
|
|
21911
|
+
try {
|
|
21912
|
+
cfb = CFB2.parse(originalBuf);
|
|
21913
|
+
} catch (err) {
|
|
21914
|
+
return fail(`CFB \uCEE8\uD14C\uC774\uB108 \uD30C\uC2F1 \uC2E4\uD328: ${msg(err)}`);
|
|
21915
|
+
}
|
|
21916
|
+
const fhEntry = CFB2.find(cfb, "/FileHeader");
|
|
21917
|
+
if (!fhEntry?.content) return fail("FileHeader \uC2A4\uD2B8\uB9BC\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 HWP 5.x \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4");
|
|
21918
|
+
let flags;
|
|
21919
|
+
try {
|
|
21920
|
+
flags = parseFileHeader(Buffer.from(fhEntry.content)).flags;
|
|
21921
|
+
} catch (err) {
|
|
21922
|
+
return fail(`FileHeader \uD30C\uC2F1 \uC2E4\uD328: ${msg(err)}`);
|
|
21923
|
+
}
|
|
21924
|
+
if (flags & (FLAG_ENCRYPTED | FLAG_DISTRIBUTION | FLAG_DRM)) {
|
|
21925
|
+
return fail("\uC554\uD638\uD654/\uBC30\uD3EC\uC6A9/DRM \uBB38\uC11C\uB294 \uD328\uCE58\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
21926
|
+
}
|
|
21927
|
+
const compressed = (flags & FLAG_COMPRESSED) !== 0;
|
|
21928
|
+
let origBlocks;
|
|
21929
|
+
try {
|
|
21930
|
+
origBlocks = parseHwp5Document(originalBuf).blocks;
|
|
21931
|
+
} catch (err) {
|
|
21932
|
+
return fail(`\uC6D0\uBCF8 HWP \uD30C\uC2F1 \uC2E4\uD328: ${msg(err)}`);
|
|
21933
|
+
}
|
|
21934
|
+
const sectionPaths = cfb.FullPaths.map((p) => p.replace(/^Root Entry/, "")).filter((p) => /^\/BodyText\/Section\d+$/.test(p)).sort((a, b) => Number(a.match(/\d+$/)[0]) - Number(b.match(/\d+$/)[0]));
|
|
21935
|
+
if (sectionPaths.length === 0) return fail("BodyText \uC139\uC158 \uC2A4\uD2B8\uB9BC\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
21936
|
+
const scans = [];
|
|
21937
|
+
for (let i = 0; i < sectionPaths.length; i++) {
|
|
21938
|
+
const entry = CFB2.find(cfb, sectionPaths[i]);
|
|
21939
|
+
if (!entry?.content) return fail(`\uC139\uC158 \uC2A4\uD2B8\uB9BC \uC77D\uAE30 \uC2E4\uD328: ${sectionPaths[i]}`);
|
|
21940
|
+
let stream;
|
|
21941
|
+
try {
|
|
21942
|
+
stream = compressed ? decompressStream(Buffer.from(entry.content)) : Buffer.from(entry.content);
|
|
21943
|
+
} catch (err) {
|
|
21944
|
+
return fail(`\uC139\uC158 \uC555\uCD95 \uD574\uC81C \uC2E4\uD328: ${msg(err)}`);
|
|
21945
|
+
}
|
|
21946
|
+
scans.push(scanSection(stream, i, compressed));
|
|
21947
|
+
}
|
|
21948
|
+
const origUnits = buildOrigUnits(origBlocks);
|
|
21949
|
+
const editedUnits = splitMarkdownUnits(editedMarkdown);
|
|
21950
|
+
const pairs = alignUnits(origUnits.map((u) => u.raw), editedUnits.map((u) => u.raw));
|
|
21951
|
+
const paraMap = resolveParaMappings(origBlocks, scans);
|
|
21952
|
+
const scanTables = scans.flatMap((s) => s.tables);
|
|
21953
|
+
const obTableOrdinals = /* @__PURE__ */ new Map();
|
|
21954
|
+
{
|
|
21955
|
+
let ordinal = 0;
|
|
21956
|
+
for (let i = 0; i < origBlocks.length; i++) {
|
|
21957
|
+
if (origBlocks[i].type === "table" && origBlocks[i].table) obTableOrdinals.set(i, ordinal++);
|
|
21958
|
+
}
|
|
21959
|
+
}
|
|
21960
|
+
for (const [oi, ei] of pairs) {
|
|
21961
|
+
if (oi !== null && ei !== null) {
|
|
21962
|
+
const orig = origUnits[oi];
|
|
21963
|
+
const edited = editedUnits[ei];
|
|
21964
|
+
if (orig.raw === edited.raw) continue;
|
|
21965
|
+
applied += handleModified(orig, edited, {
|
|
21966
|
+
origBlocks,
|
|
21967
|
+
paraMap,
|
|
21968
|
+
scans,
|
|
21969
|
+
scanTables,
|
|
21970
|
+
obTableOrdinals,
|
|
21971
|
+
skipped
|
|
21972
|
+
});
|
|
21973
|
+
} else if (oi !== null) {
|
|
21974
|
+
skipped.push({ reason: "\uBE14\uB85D \uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0 (v1) \u2014 \uC6D0\uBCF8 \uC720\uC9C0", before: summarize(origUnits[oi].raw) });
|
|
21975
|
+
} else if (ei !== null) {
|
|
21976
|
+
skipped.push({ reason: "\uBE14\uB85D \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)", after: summarize(editedUnits[ei].raw) });
|
|
21977
|
+
}
|
|
21978
|
+
}
|
|
21979
|
+
let data;
|
|
21980
|
+
const dirty = scans.some((s) => s.repl.size > 0);
|
|
21981
|
+
if (!dirty) {
|
|
21982
|
+
data = new Uint8Array(original);
|
|
21983
|
+
} else {
|
|
21984
|
+
try {
|
|
21985
|
+
let out = originalBuf;
|
|
21986
|
+
for (let i = 0; i < scans.length; i++) {
|
|
21987
|
+
if (scans[i].repl.size === 0) continue;
|
|
21988
|
+
const newStream = serializeRecords(scans[i].records, scans[i].repl);
|
|
21989
|
+
const content = compressed ? deflateRawSync2(newStream) : newStream;
|
|
21990
|
+
out = replaceOleStream(out, sectionPaths[i], content);
|
|
21991
|
+
}
|
|
21992
|
+
data = new Uint8Array(out);
|
|
21993
|
+
} catch (err) {
|
|
21994
|
+
return { success: false, applied: 0, skipped, error: `HWP \uC139\uD130 \uC218\uC220 \uC2E4\uD328: ${msg(err)}` };
|
|
21995
|
+
}
|
|
21996
|
+
}
|
|
21997
|
+
let verification;
|
|
21998
|
+
if (options?.verify !== false) {
|
|
21999
|
+
try {
|
|
22000
|
+
const reparsed = parseHwp5Document(Buffer.from(data));
|
|
22001
|
+
verification = diffUnitLists(splitMarkdownUnits(reparsed.markdown), editedUnits);
|
|
22002
|
+
} catch (err) {
|
|
22003
|
+
return { success: false, applied, skipped, error: `\uD328\uCE58\uBCF8 \uC7AC\uD30C\uC2F1 \uC2E4\uD328 \u2014 \uD328\uCE58 \uC911\uB2E8: ${msg(err)}` };
|
|
22004
|
+
}
|
|
22005
|
+
}
|
|
22006
|
+
return { success: true, data, applied, skipped, verification };
|
|
22007
|
+
function fail(error) {
|
|
22008
|
+
return { success: false, applied: 0, skipped, error };
|
|
22009
|
+
}
|
|
22010
|
+
}
|
|
22011
|
+
function msg(err) {
|
|
22012
|
+
return err instanceof Error ? err.message : String(err);
|
|
22013
|
+
}
|
|
22014
|
+
function resolveParaMappings(blocks, scans) {
|
|
22015
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
22016
|
+
for (const scan of scans) {
|
|
22017
|
+
for (const para of scan.paras) {
|
|
22018
|
+
if (para.kind === "other") continue;
|
|
22019
|
+
const key = normForMatch(para.rawText);
|
|
22020
|
+
if (!key) continue;
|
|
22021
|
+
let list = buckets.get(key);
|
|
22022
|
+
if (!list) buckets.set(key, list = []);
|
|
22023
|
+
list.push(para);
|
|
22024
|
+
}
|
|
22025
|
+
}
|
|
22026
|
+
const usable = (list) => list.length === 1 || list.every((p) => p.kind === "body");
|
|
22027
|
+
const counters = /* @__PURE__ */ new Map();
|
|
22028
|
+
const result = /* @__PURE__ */ new Map();
|
|
22029
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
22030
|
+
const b = blocks[i];
|
|
22031
|
+
if (b.type !== "paragraph" && b.type !== "heading" || !b.text) continue;
|
|
22032
|
+
let key = normForMatch(b.text);
|
|
22033
|
+
let prefixStripped = false;
|
|
22034
|
+
if (!buckets.has(key)) {
|
|
22035
|
+
const sp = b.text.indexOf(" ");
|
|
22036
|
+
if (sp > 0) {
|
|
22037
|
+
const alt = normForMatch(b.text.slice(sp + 1));
|
|
22038
|
+
if (alt && buckets.has(alt)) {
|
|
22039
|
+
key = alt;
|
|
22040
|
+
prefixStripped = true;
|
|
22041
|
+
}
|
|
22042
|
+
}
|
|
22043
|
+
}
|
|
22044
|
+
const list = buckets.get(key);
|
|
22045
|
+
if (!list || !usable(list)) {
|
|
22046
|
+
result.set(i, {});
|
|
22047
|
+
continue;
|
|
22048
|
+
}
|
|
22049
|
+
const occ = counters.get(key) ?? 0;
|
|
22050
|
+
counters.set(key, occ + 1);
|
|
22051
|
+
result.set(i, occ < list.length ? { para: list[occ], prefixStripped } : {});
|
|
22052
|
+
}
|
|
22053
|
+
return result;
|
|
22054
|
+
}
|
|
22055
|
+
function handleModified(orig, edited, ctx) {
|
|
22056
|
+
const block = ctx.origBlocks[orig.blockIdx];
|
|
22057
|
+
const skip = (reason) => {
|
|
22058
|
+
ctx.skipped.push({ reason, before: summarize(orig.raw), after: summarize(edited.raw) });
|
|
22059
|
+
return 0;
|
|
22060
|
+
};
|
|
22061
|
+
if (orig.role === "caption") return skip("\uD45C \uCEA1\uC158 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22062
|
+
if (orig.kind === "separator" || orig.kind === "image") return skip("\uC774\uBBF8\uC9C0/\uAD6C\uBD84\uC120 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
22063
|
+
if (!block) return skip("\uBE14\uB85D \uB9E4\uD551 \uC2E4\uD328");
|
|
22064
|
+
if (orig.fragment) return skip("\uBB38\uB2E8 \uBD84\uC808(\uAC15\uC81C \uC904\uBC14\uAFC8/\uBCD1\uD569 \uC720\uB2DB) \u2014 \uBD80\uBD84 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22065
|
+
if (block.type === "table" && block.table) {
|
|
22066
|
+
if (orig.kind !== edited.kind) return skip("\uD45C \u2194 \uBE44\uD45C \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0 (\uD45C \uAD6C\uC870 \uBCC0\uACBD)");
|
|
22067
|
+
if (ctx.obTableOrdinals.size !== ctx.scanTables.length) return skip("\uD45C \uAC1C\uC218 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
22068
|
+
const ordinal = ctx.obTableOrdinals.get(orig.blockIdx);
|
|
22069
|
+
const scanTable = ordinal !== void 0 ? ctx.scanTables[ordinal] : void 0;
|
|
22070
|
+
if (!scanTable) return skip("\uD45C \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328");
|
|
22071
|
+
if (orig.kind === "gfm-table") return patchGfmCells(scanTable, orig, edited, ctx, skip);
|
|
22072
|
+
if (orig.kind === "html-table") return skip("HTML \uD45C(\uBCD1\uD569/\uC904\uBC14\uAFC8 \uC140) \uC218\uC815\uC740 HWP5 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22073
|
+
return patchTextChunk5(block.table, scanTable, orig, edited, ctx, skip);
|
|
22074
|
+
}
|
|
22075
|
+
if ((block.type === "paragraph" || block.type === "heading") && orig.kind === "text" && edited.kind === "text") {
|
|
22076
|
+
return patchParagraph(block, orig, edited, ctx, skip);
|
|
22077
|
+
}
|
|
22078
|
+
return skip("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBE14\uB85D \uC720\uD615 \uBCC0\uACBD");
|
|
22079
|
+
}
|
|
22080
|
+
function patchParagraph(block, orig, edited, ctx, skip) {
|
|
22081
|
+
const mapping = ctx.paraMap.get(orig.blockIdx);
|
|
22082
|
+
if (!mapping?.para) return skip("\uBB38\uB2E8 \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328 (\uBA38\uB9AC\uB9D0/\uAE00\uC0C1\uC790/\uCEA1\uC158 \uC601\uC5ED\uC774\uAC70\uB098 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58)");
|
|
22083
|
+
if (block.text && block.text.includes("\n")) {
|
|
22084
|
+
return skip("\uBB38\uB2E8 \uB0B4 \uAC15\uC81C \uC904\uBC14\uAFC8 \uD3EC\uD568 \u2014 \uC218\uC815 \uC2DC \uC904\uBC14\uAFC8 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22085
|
+
}
|
|
22086
|
+
let newPlain = textUnitToPlain(edited.raw, block);
|
|
22087
|
+
if (block.footnoteText) {
|
|
22088
|
+
const noteMatch = newPlain.match(/\s*\(주: ([\s\S]*)\)$/);
|
|
22089
|
+
if (noteMatch) {
|
|
22090
|
+
newPlain = newPlain.slice(0, noteMatch.index).trimEnd();
|
|
22091
|
+
if (normForMatch(noteMatch[1]) !== normForMatch(block.footnoteText)) {
|
|
22092
|
+
ctx.skipped.push({ reason: "\uAC01\uC8FC \uD14D\uC2A4\uD2B8 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 \u2014 \uBCF8\uBB38\uB9CC \uC801\uC6A9", before: block.footnoteText, after: noteMatch[1] });
|
|
22093
|
+
}
|
|
22094
|
+
} else {
|
|
22095
|
+
ctx.skipped.push({ reason: "\uAC01\uC8FC \uD45C\uAE30 \uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0 \u2014 \uAC01\uC8FC \uC720\uC9C0, \uBCF8\uBB38\uB9CC \uC801\uC6A9", before: `(\uC8FC: ${block.footnoteText})` });
|
|
22096
|
+
}
|
|
22097
|
+
}
|
|
22098
|
+
if (mapping.prefixStripped) {
|
|
22099
|
+
const origPrefix = block.text.split(" ", 1)[0];
|
|
22100
|
+
const sp = newPlain.indexOf(" ");
|
|
22101
|
+
const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
|
|
22102
|
+
if (newFirst === origPrefix || /^(?:[0-90-9a-zA-Z가-힣]{1,6}[.)\]:]|[([][0-90-9a-zA-Z가-힣]{1,6}[)\]][.:]?|[ⅰ-ⅹⅠ-Ⅹ①-⑮][.)\]:]?)$/u.test(newFirst)) {
|
|
22103
|
+
newPlain = sp > 0 ? newPlain.slice(sp + 1) : "";
|
|
22104
|
+
} else {
|
|
22105
|
+
ctx.skipped.push({ reason: "\uC790\uB3D9\uBC88\uD638 \uC811\uB450 \uC2DD\uBCC4 \uC2E4\uD328 \u2014 \uBC88\uD638 \uD3EC\uD568 \uD14D\uC2A4\uD2B8\uB85C \uC801\uC6A9 (\uBDF0\uC5B4\uC5D0\uC11C \uC911\uBCF5 \uD45C\uC2DC \uAC00\uB2A5)", after: summarize(newPlain) });
|
|
22106
|
+
}
|
|
22107
|
+
}
|
|
22108
|
+
const origPlain = textUnitToPlain(orig.raw, block);
|
|
22109
|
+
if (newPlain === origPlain) return skip("\uD14D\uC2A4\uD2B8 \uC678 \uBCC0\uACBD(\uD5E4\uB529 \uB808\uBCA8/\uC11C\uC2DD)\uB9CC \uAC10\uC9C0 \u2014 \uC2A4\uD0C0\uC77C \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
22110
|
+
if (sanitizeText(newPlain) !== newPlain) {
|
|
22111
|
+
return skip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uD328\uCE58 \uC2DC \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
|
|
22112
|
+
}
|
|
22113
|
+
return stageParaPatch(ctx.scans[mapping.para.sectionIndex], mapping.para, newPlain, skip);
|
|
22114
|
+
}
|
|
22115
|
+
function patchGfmCells(scanTable, orig, edited, ctx, skip) {
|
|
22116
|
+
const origRows = parseGfmTable(orig.lines);
|
|
22117
|
+
const editedRows = parseGfmTable(edited.lines);
|
|
22118
|
+
if (origRows.length !== editedRows.length || origRows.some((r, i) => r.length !== editedRows[i].length)) {
|
|
22119
|
+
return skip("\uD45C \uAD6C\uC870 \uBCC0\uACBD(\uD589/\uC5F4 \uC218)\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22120
|
+
}
|
|
22121
|
+
let applied = 0;
|
|
22122
|
+
for (let r = 0; r < origRows.length; r++) {
|
|
22123
|
+
for (let c = 0; c < origRows[r].length; c++) {
|
|
22124
|
+
if (origRows[r][c] === editedRows[r][c]) continue;
|
|
22125
|
+
const cellSkip = (reason) => {
|
|
22126
|
+
ctx.skipped.push({ reason, before: summarize(origRows[r][c]), after: summarize(editedRows[r][c]) });
|
|
22127
|
+
return 0;
|
|
22128
|
+
};
|
|
22129
|
+
const before = gfmCellToPlain(origRows[r][c]);
|
|
22130
|
+
const after = gfmCellToPlain(editedRows[r][c]);
|
|
22131
|
+
if (before === null || after === null) {
|
|
22132
|
+
cellSkip("\uC11C\uC2DD/\uB9C1\uD06C/\uC774\uBBF8\uC9C0 \uD3EC\uD568 \uC140 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22133
|
+
continue;
|
|
22134
|
+
}
|
|
22135
|
+
if (after.includes("\n")) {
|
|
22136
|
+
cellSkip("\uC140 \uB0B4 \uC904\uBC14\uAFC8 \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22137
|
+
continue;
|
|
22138
|
+
}
|
|
22139
|
+
const cell = scanTable.cells.get(`${r},${c}`);
|
|
22140
|
+
if (!cell) {
|
|
22141
|
+
cellSkip("\uBCD1\uD569 \uC601\uC5ED \uC140 \u2014 \uC575\uCEE4 \uC140\uC774 \uC544\uB2C8\uBBC0\uB85C \uBBF8\uC9C0\uC6D0");
|
|
22142
|
+
continue;
|
|
22143
|
+
}
|
|
22144
|
+
if (cell.paras.length !== 1) {
|
|
22145
|
+
cellSkip("\uBCF5\uC218 \uBB38\uB2E8 \uC140 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22146
|
+
continue;
|
|
22147
|
+
}
|
|
22148
|
+
const para = cell.paras[0];
|
|
22149
|
+
if (normForMatch(para.rawText) !== normForMatch(before)) {
|
|
22150
|
+
cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
22151
|
+
continue;
|
|
22152
|
+
}
|
|
22153
|
+
if (sanitizeText(after) !== after) {
|
|
22154
|
+
cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22155
|
+
continue;
|
|
22156
|
+
}
|
|
22157
|
+
applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
|
|
22158
|
+
}
|
|
22159
|
+
}
|
|
22160
|
+
return applied;
|
|
22161
|
+
}
|
|
22162
|
+
function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
|
|
22163
|
+
if (table.rows === 1 && table.cols === 1) {
|
|
22164
|
+
const content = sanitizeText(table.cells[0][0].text);
|
|
22165
|
+
const replicaLines = content.split(/\n/).map((line) => {
|
|
22166
|
+
const t = line.trim();
|
|
22167
|
+
if (!t) return "";
|
|
22168
|
+
if (/^\d+\.\s/.test(t)) return `**${escapeGfm(t)}**`;
|
|
22169
|
+
return escapeGfm(t);
|
|
22170
|
+
}).filter(Boolean);
|
|
22171
|
+
if (replicaLines.join("\n") !== orig.lines.join("\n")) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
22172
|
+
if (extractCellTokens(orig.raw) !== extractCellTokens(edited.raw)) return skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
22173
|
+
const newLines = edited.lines.map((l) => {
|
|
22174
|
+
const m = l.match(/^\*\*([\s\S]*)\*\*$/);
|
|
22175
|
+
const unwrap = m && /^\d+\.\s/.test(unescapeGfm(m[1]));
|
|
22176
|
+
return stripCellTokens(unescapeGfm(unwrap ? m[1] : l)).trim();
|
|
22177
|
+
}).filter(Boolean);
|
|
22178
|
+
return applyCellEdit5(table, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
|
|
22179
|
+
}
|
|
22180
|
+
if (table.cols === 1 && table.rows >= 2) {
|
|
22181
|
+
const replica = [];
|
|
22182
|
+
for (let r = 0; r < table.rows; r++) {
|
|
22183
|
+
const line = escapeGfm(sanitizeText(table.cells[r][0].text)).replace(/\n/g, " ");
|
|
22184
|
+
if (line) replica.push({ line, gridR: r });
|
|
22185
|
+
}
|
|
22186
|
+
if (replica.map((x) => x.line).join("\n") !== orig.lines.join("\n")) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
22187
|
+
if (edited.lines.length !== replica.length) return skip("\uD45C \uD589 \uCD94\uAC00/\uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0 (\uD45C \uAD6C\uC870 \uBCC0\uACBD)");
|
|
22188
|
+
let applied = 0;
|
|
22189
|
+
for (let i = 0; i < replica.length; i++) {
|
|
22190
|
+
if (replica[i].line === edited.lines[i]) continue;
|
|
22191
|
+
if (extractCellTokens(replica[i].line) !== extractCellTokens(edited.lines[i])) {
|
|
22192
|
+
skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
22193
|
+
continue;
|
|
22194
|
+
}
|
|
22195
|
+
const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean);
|
|
22196
|
+
applied += applyCellEdit5(table, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
|
|
22197
|
+
}
|
|
22198
|
+
return applied;
|
|
22199
|
+
}
|
|
22200
|
+
return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
|
|
22201
|
+
}
|
|
22202
|
+
function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
|
|
22203
|
+
const skip = (reason) => {
|
|
22204
|
+
ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) });
|
|
22205
|
+
return 0;
|
|
22206
|
+
};
|
|
22207
|
+
const cell = scanTable.cells.get(`${gridR},${gridC}`);
|
|
22208
|
+
if (!cell) return skip("\uC140 \uC88C\uD45C \uB9E4\uD551 \uC2E4\uD328 (\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58)");
|
|
22209
|
+
const irCell = table.cells[gridR]?.[gridC];
|
|
22210
|
+
const scanJoined = cell.paras.map((p) => p.rawText).filter((t) => normForMatch(t)).join("\n");
|
|
22211
|
+
if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
|
|
22212
|
+
if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
|
|
22213
|
+
const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
|
|
22214
|
+
const flatJoined = flatBlocks.map((b) => b.text ?? "").join("\n");
|
|
22215
|
+
if (normForMatch(scanJoined) !== normForMatch(flatJoined)) {
|
|
22216
|
+
return skip("\uC140 \uCF58\uD150\uCE20 \uAD6C\uC870 \uBCF5\uC7A1 (\uC911\uCCA9\uD45C/\uAE00\uC0C1\uC790) \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
22217
|
+
}
|
|
22218
|
+
}
|
|
22219
|
+
}
|
|
22220
|
+
const nonEmpty = cell.paras.filter((p) => normForMatch(p.rawText) !== "");
|
|
22221
|
+
if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
|
|
22222
|
+
return skip("\uC140 \uC904 \uACBD\uACC4 \uB9E4\uD551 \uBAA8\uD638 (\uBB38\uB2E8 \uB0B4 \uC904\uBC14\uAFC8) \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22223
|
+
}
|
|
22224
|
+
const unstable = newLines.find((l) => sanitizeText(l) !== l);
|
|
22225
|
+
if (unstable !== void 0) return skip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uD328\uCE58 \uC2DC \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
|
|
22226
|
+
if (nonEmpty.length === 0) return skip("\uBE48 \uC140 \uD14D\uC2A4\uD2B8 \uCC44\uC6B0\uAE30\uB294 HWP5 \uBBF8\uC9C0\uC6D0 (v1) \u2014 \uBB38\uB2E8 \uC0DD\uC131 \uD544\uC694");
|
|
22227
|
+
const assigned = [];
|
|
22228
|
+
for (let i = 0; i < nonEmpty.length; i++) {
|
|
22229
|
+
if (i < newLines.length) {
|
|
22230
|
+
assigned.push(i === nonEmpty.length - 1 && newLines.length > nonEmpty.length ? newLines.slice(i).join(" ") : newLines[i]);
|
|
22231
|
+
} else {
|
|
22232
|
+
assigned.push("");
|
|
22233
|
+
}
|
|
22234
|
+
}
|
|
22235
|
+
if (newLines.length > nonEmpty.length) {
|
|
22236
|
+
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uCD94\uAC00\uB294 \uBB38\uB2E8 \uC0DD\uC131 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uBCD1\uD569 \uC801\uC6A9", after: summarize(after) });
|
|
22237
|
+
}
|
|
22238
|
+
let staged = 0;
|
|
22239
|
+
for (let i = 0; i < nonEmpty.length; i++) {
|
|
22240
|
+
if (assigned[i] === nonEmpty[i].rawText || normForMatch(assigned[i]) === normForMatch(nonEmpty[i].rawText)) continue;
|
|
22241
|
+
staged += stageParaPatch(ctx.scans[nonEmpty[i].sectionIndex], nonEmpty[i], assigned[i], skip);
|
|
22242
|
+
}
|
|
22243
|
+
return staged > 0 ? 1 : 0;
|
|
22244
|
+
}
|
|
22245
|
+
function gfmCellToPlain(md2) {
|
|
22246
|
+
let t = md2.trim();
|
|
22247
|
+
const bold = t.match(/^\*\*([\s\S]+)\*\*$/);
|
|
22248
|
+
if (bold) t = bold[1];
|
|
22249
|
+
if (/[*`]|!\[|\]\(|<(?!br\s*\/?>)/i.test(t)) return null;
|
|
22250
|
+
return unescapeGfm(unescapeGfmCell(t));
|
|
22251
|
+
}
|
|
22252
|
+
var PARA_BREAK = Buffer.from([13, 0]);
|
|
22253
|
+
function stageParaPatch(scan, para, newPlain, skip) {
|
|
22254
|
+
if (!scan.safe) return skip("\uC139\uC158 \uB808\uCF54\uB4DC \uC7AC\uC9C1\uB82C\uD654 \uBD88\uC77C\uCE58 \u2014 \uC548\uC804\uC744 \uC704\uD574 \uC774 \uC139\uC158\uC740 \uBBF8\uC9C0\uC6D0");
|
|
22255
|
+
if (para.textIdx === -1) return skip("\uBE48 \uBB38\uB2E8 \uD14D\uC2A4\uD2B8 \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22256
|
+
if (para.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22257
|
+
if (para.ctrlMask !== 0) return skip("\uCEE8\uD2B8\uB864 \uBB38\uC790 \uD3EC\uD568 \uBB38\uB2E8(\uD0ED/\uAC1C\uCCB4/\uD544\uB4DC/\uD2B9\uC218\uACF5\uBC31) \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22258
|
+
if (para.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22259
|
+
if (para.charShapeIdx < 0 || para.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22260
|
+
if (scan.repl.has(para.headerIdx)) return skip("\uB3D9\uC77C \uBB38\uB2E8 \uC911\uBCF5 \uC218\uC815 \u2014 \uCCAB \uC218\uC815\uB9CC \uC801\uC6A9");
|
|
22261
|
+
if (/[\u0000-\u001f]/.test(newPlain)) return skip("\uC0C8 \uD14D\uC2A4\uD2B8\uC5D0 \uC81C\uC5B4\uBB38\uC790 \uD3EC\uD568 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22262
|
+
const records = scan.records;
|
|
22263
|
+
const headerRec = records[para.headerIdx];
|
|
22264
|
+
const textRec = records[para.textIdx];
|
|
22265
|
+
const charShapeRec = records[para.charShapeIdx];
|
|
22266
|
+
const lineSegRec = records[para.lineSegIdx];
|
|
22267
|
+
if (charShapeRec.data.length < 8 || lineSegRec.data.length < 36) {
|
|
22268
|
+
return skip("CHAR_SHAPE/LINE_SEG \uB808\uCF54\uB4DC \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22269
|
+
}
|
|
22270
|
+
const hadBreak = textRec.data.length >= 2 && textRec.data.readUInt16LE(textRec.data.length - 2) === 13;
|
|
22271
|
+
const expect = hadBreak ? Buffer.concat([Buffer.from(para.rawText, "utf16le"), PARA_BREAK]) : Buffer.from(para.rawText, "utf16le");
|
|
22272
|
+
if (!expect.equals(textRec.data)) return skip("PARA_TEXT \uC7AC\uAD6C\uC131 \uBD88\uC77C\uCE58 \u2014 \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
|
|
22273
|
+
const lead = para.rawText.match(/^\s*/)[0];
|
|
22274
|
+
const trail = para.rawText.match(/\s*$/)[0];
|
|
22275
|
+
const newRaw = para.rawText.trim() === para.rawText ? newPlain : lead + newPlain + trail;
|
|
22276
|
+
const newText = hadBreak ? Buffer.concat([Buffer.from(newRaw, "utf16le"), PARA_BREAK]) : Buffer.from(newRaw, "utf16le");
|
|
22277
|
+
scan.repl.set(para.textIdx, newText);
|
|
22278
|
+
const newHeader = Buffer.from(headerRec.data);
|
|
22279
|
+
const nChars = newRaw.length + (hadBreak ? 1 : 0);
|
|
22280
|
+
newHeader.writeUInt32LE((para.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
|
|
22281
|
+
if (charShapeRec.data.length > 8) {
|
|
22282
|
+
newHeader.writeUInt16LE(1, 12);
|
|
22283
|
+
scan.repl.set(para.charShapeIdx, Buffer.from(charShapeRec.data.subarray(0, 8)));
|
|
22284
|
+
}
|
|
22285
|
+
const csData = scan.repl.get(para.charShapeIdx) ?? Buffer.from(charShapeRec.data);
|
|
22286
|
+
if (csData.readUInt32LE(0) !== 0) {
|
|
22287
|
+
csData.writeUInt32LE(0, 0);
|
|
22288
|
+
scan.repl.set(para.charShapeIdx, csData);
|
|
22289
|
+
}
|
|
22290
|
+
if (lineSegRec.data.length > 36 || lineSegRec.data.readUInt32LE(0) !== 0) {
|
|
22291
|
+
const seg = Buffer.from(lineSegRec.data.subarray(0, 36));
|
|
22292
|
+
seg.writeUInt32LE(0, 0);
|
|
22293
|
+
newHeader.writeUInt16LE(1, 16);
|
|
22294
|
+
scan.repl.set(para.lineSegIdx, seg);
|
|
22295
|
+
}
|
|
22296
|
+
scan.repl.set(para.headerIdx, newHeader);
|
|
22297
|
+
return 1;
|
|
22298
|
+
}
|
|
22299
|
+
|
|
21468
22300
|
// src/print/renderer.ts
|
|
21469
22301
|
import { existsSync } from "fs";
|
|
21470
22302
|
import MarkdownIt from "markdown-it";
|
|
@@ -21627,8 +22459,8 @@ async function parse(input, options) {
|
|
|
21627
22459
|
const buf = await readFile(input);
|
|
21628
22460
|
buffer = toArrayBuffer(buf);
|
|
21629
22461
|
} catch (err) {
|
|
21630
|
-
const
|
|
21631
|
-
return { success: false, fileType: "unknown", error:
|
|
22462
|
+
const msg2 = err instanceof Error && "code" in err && err.code === "ENOENT" ? `\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}` : `\uD30C\uC77C \uC77D\uAE30 \uC2E4\uD328: ${input}`;
|
|
22463
|
+
return { success: false, fileType: "unknown", error: msg2, code: "PARSE_ERROR" };
|
|
21632
22464
|
}
|
|
21633
22465
|
} else if (Buffer.isBuffer(input)) {
|
|
21634
22466
|
buffer = toArrayBuffer(input);
|
|
@@ -21705,7 +22537,7 @@ async function parseHwp(buffer, options) {
|
|
|
21705
22537
|
async function parsePdf(buffer, options) {
|
|
21706
22538
|
let parsePdfDocument;
|
|
21707
22539
|
try {
|
|
21708
|
-
const mod = await import("./parser-
|
|
22540
|
+
const mod = await import("./parser-LZH7ZELV.js");
|
|
21709
22541
|
parsePdfDocument = mod.parsePdfDocument;
|
|
21710
22542
|
} catch {
|
|
21711
22543
|
return {
|
|
@@ -21823,6 +22655,7 @@ export {
|
|
|
21823
22655
|
parsePdf,
|
|
21824
22656
|
parseXls,
|
|
21825
22657
|
parseXlsx,
|
|
22658
|
+
patchHwp,
|
|
21826
22659
|
patchHwpx,
|
|
21827
22660
|
renderHtml
|
|
21828
22661
|
};
|