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
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
sanitizeHref,
|
|
24
24
|
stripDtd,
|
|
25
25
|
toArrayBuffer
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-O5P6EG5L.js";
|
|
27
27
|
import {
|
|
28
28
|
parsePageRange
|
|
29
29
|
} from "./chunk-MOL7MDBG.js";
|
|
@@ -579,9 +579,9 @@ function createSectionShared() {
|
|
|
579
579
|
}
|
|
580
580
|
function createXmlParser(warnings) {
|
|
581
581
|
return new DOMParser({
|
|
582
|
-
onError(level,
|
|
583
|
-
if (level === "fatalError") throw new KordocError(`XML \uD30C\uC2F1 \uC2E4\uD328: ${
|
|
584
|
-
warnings?.push({ code: "MALFORMED_XML", message: `XML ${level === "warn" ? "\uACBD\uACE0" : "\uC624\uB958"}: ${
|
|
582
|
+
onError(level, msg2) {
|
|
583
|
+
if (level === "fatalError") throw new KordocError(`XML \uD30C\uC2F1 \uC2E4\uD328: ${msg2}`);
|
|
584
|
+
warnings?.push({ code: "MALFORMED_XML", message: `XML ${level === "warn" ? "\uACBD\uACE0" : "\uC624\uB958"}: ${msg2}` });
|
|
585
585
|
}
|
|
586
586
|
});
|
|
587
587
|
}
|
|
@@ -16283,8 +16283,8 @@ function parseHwp3Document(buffer, _options) {
|
|
|
16283
16283
|
try {
|
|
16284
16284
|
body = inflateRawSync3(tail);
|
|
16285
16285
|
} catch (err) {
|
|
16286
|
-
const
|
|
16287
|
-
throw new Error(`HWP3 \uC555\uCD95 \uD574\uC81C \uC2E4\uD328: ${
|
|
16286
|
+
const msg2 = err instanceof Error ? err.message : String(err);
|
|
16287
|
+
throw new Error(`HWP3 \uC555\uCD95 \uD574\uC81C \uC2E4\uD328: ${msg2}`);
|
|
16288
16288
|
}
|
|
16289
16289
|
} else {
|
|
16290
16290
|
body = tail;
|
|
@@ -18216,8 +18216,8 @@ function parseHwpmlDocument(buffer, options) {
|
|
|
18216
18216
|
const xml = stripDtd(normalized);
|
|
18217
18217
|
const warnings = [];
|
|
18218
18218
|
const parser = new DOMParser4({
|
|
18219
|
-
onError: (_level,
|
|
18220
|
-
warnings.push({ message: `HWPML XML \uD30C\uC2F1 \uACBD\uACE0: ${
|
|
18219
|
+
onError: (_level, msg2) => {
|
|
18220
|
+
warnings.push({ message: `HWPML XML \uD30C\uC2F1 \uACBD\uACE0: ${msg2}`, code: "MALFORMED_XML" });
|
|
18221
18221
|
}
|
|
18222
18222
|
});
|
|
18223
18223
|
const doc = parser.parseFromString(xml, "text/xml");
|
|
@@ -21247,6 +21247,838 @@ function sectionPathsFromManifest(xml) {
|
|
|
21247
21247
|
return Array.from(idToHref.entries()).filter(([id]) => isSectionId(id)).sort((a, b) => a[0].localeCompare(b[0])).map(([, href]) => href);
|
|
21248
21248
|
}
|
|
21249
21249
|
|
|
21250
|
+
// src/roundtrip/hwp5-patch.ts
|
|
21251
|
+
import { deflateRawSync as deflateRawSync2 } from "zlib";
|
|
21252
|
+
import { createRequire as createRequire2 } from "module";
|
|
21253
|
+
|
|
21254
|
+
// src/roundtrip/ole-surgeon.ts
|
|
21255
|
+
var SECTOR = 512;
|
|
21256
|
+
var MINI_SECTOR = 64;
|
|
21257
|
+
var MINI_CUTOFF = 4096;
|
|
21258
|
+
var FREESECT = 4294967295;
|
|
21259
|
+
var ENDOFCHAIN = 4294967294;
|
|
21260
|
+
var FATSECT = 4294967293;
|
|
21261
|
+
var OleSurgeonError = class extends Error {
|
|
21262
|
+
};
|
|
21263
|
+
function replaceOleStream(file, path, newData) {
|
|
21264
|
+
const surgeon = new Surgeon(file);
|
|
21265
|
+
surgeon.replace(path, newData);
|
|
21266
|
+
return surgeon.finish();
|
|
21267
|
+
}
|
|
21268
|
+
var Surgeon = class {
|
|
21269
|
+
buf;
|
|
21270
|
+
fat = [];
|
|
21271
|
+
/** FAT 배열을 구성하는 섹터 번호들 (DIFAT 순서) */
|
|
21272
|
+
fatSectors = [];
|
|
21273
|
+
miniFat = [];
|
|
21274
|
+
miniFatSectors = [];
|
|
21275
|
+
dirSectors = [];
|
|
21276
|
+
entries = [];
|
|
21277
|
+
constructor(file) {
|
|
21278
|
+
if (file.length < SECTOR || file.readUInt32LE(0) !== 3759263696) {
|
|
21279
|
+
throw new OleSurgeonError("OLE \uC2DC\uADF8\uB2C8\uCC98\uAC00 \uC544\uB2D9\uB2C8\uB2E4");
|
|
21280
|
+
}
|
|
21281
|
+
if (file.readUInt16LE(26) !== 3 || file.readUInt16LE(30) !== 9) {
|
|
21282
|
+
throw new OleSurgeonError("CFB v3(512B \uC139\uD130)\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4");
|
|
21283
|
+
}
|
|
21284
|
+
const padded = Math.ceil((file.length - SECTOR) / SECTOR) * SECTOR + SECTOR;
|
|
21285
|
+
this.buf = Buffer.alloc(padded);
|
|
21286
|
+
file.copy(this.buf);
|
|
21287
|
+
this.loadFat();
|
|
21288
|
+
this.loadMiniFat();
|
|
21289
|
+
this.loadDirectory();
|
|
21290
|
+
}
|
|
21291
|
+
// ── 로드 ──
|
|
21292
|
+
loadFat() {
|
|
21293
|
+
const difat = [];
|
|
21294
|
+
for (let i = 0; i < 109; i++) difat.push(this.buf.readUInt32LE(76 + i * 4));
|
|
21295
|
+
let difatSector = this.buf.readUInt32LE(68);
|
|
21296
|
+
let guard = 0;
|
|
21297
|
+
while (difatSector !== ENDOFCHAIN && difatSector !== FREESECT && guard++ < 1e6) {
|
|
21298
|
+
const off = this.sectorOffset(difatSector);
|
|
21299
|
+
for (let i = 0; i < 127; i++) difat.push(this.buf.readUInt32LE(off + i * 4));
|
|
21300
|
+
difatSector = this.buf.readUInt32LE(off + 127 * 4);
|
|
21301
|
+
}
|
|
21302
|
+
this.fatSectors = difat.filter((s) => s !== FREESECT);
|
|
21303
|
+
for (const s of this.fatSectors) {
|
|
21304
|
+
const off = this.sectorOffset(s);
|
|
21305
|
+
for (let i = 0; i < 128; i++) this.fat.push(this.buf.readUInt32LE(off + i * 4));
|
|
21306
|
+
}
|
|
21307
|
+
}
|
|
21308
|
+
loadMiniFat() {
|
|
21309
|
+
const start = this.buf.readUInt32LE(60);
|
|
21310
|
+
this.miniFatSectors = start === ENDOFCHAIN || start === FREESECT ? [] : this.chain(start);
|
|
21311
|
+
for (const s of this.miniFatSectors) {
|
|
21312
|
+
const off = this.sectorOffset(s);
|
|
21313
|
+
for (let i = 0; i < 128; i++) this.miniFat.push(this.buf.readUInt32LE(off + i * 4));
|
|
21314
|
+
}
|
|
21315
|
+
}
|
|
21316
|
+
loadDirectory() {
|
|
21317
|
+
this.dirSectors = this.chain(this.buf.readUInt32LE(48));
|
|
21318
|
+
for (let si = 0; si < this.dirSectors.length; si++) {
|
|
21319
|
+
const off = this.sectorOffset(this.dirSectors[si]);
|
|
21320
|
+
for (let i = 0; i < 4; i++) {
|
|
21321
|
+
const e = off + i * 128;
|
|
21322
|
+
const nameLen = this.buf.readUInt16LE(e + 64);
|
|
21323
|
+
const name = nameLen >= 2 ? this.buf.subarray(e, e + nameLen - 2).toString("utf16le") : "";
|
|
21324
|
+
this.entries.push({
|
|
21325
|
+
index: si * 4 + i,
|
|
21326
|
+
name,
|
|
21327
|
+
type: this.buf[e + 66],
|
|
21328
|
+
left: this.buf.readInt32LE(e + 68),
|
|
21329
|
+
right: this.buf.readInt32LE(e + 72),
|
|
21330
|
+
child: this.buf.readInt32LE(e + 76),
|
|
21331
|
+
start: this.buf.readUInt32LE(e + 116),
|
|
21332
|
+
size: this.buf.readUInt32LE(e + 120)
|
|
21333
|
+
});
|
|
21334
|
+
}
|
|
21335
|
+
}
|
|
21336
|
+
}
|
|
21337
|
+
// ── 헬퍼 ──
|
|
21338
|
+
sectorOffset(n) {
|
|
21339
|
+
const off = SECTOR + n * SECTOR;
|
|
21340
|
+
if (n >= 4294967290 || off + SECTOR > this.buf.length) throw new OleSurgeonError(`\uC139\uD130 \uBC94\uC704 \uCD08\uACFC: ${n}`);
|
|
21341
|
+
return off;
|
|
21342
|
+
}
|
|
21343
|
+
chain(start) {
|
|
21344
|
+
const out = [];
|
|
21345
|
+
let s = start;
|
|
21346
|
+
while (s !== ENDOFCHAIN) {
|
|
21347
|
+
if (s === FREESECT || s >= this.fat.length || out.length > this.fat.length) {
|
|
21348
|
+
throw new OleSurgeonError("FAT \uCCB4\uC778 \uC190\uC0C1");
|
|
21349
|
+
}
|
|
21350
|
+
out.push(s);
|
|
21351
|
+
s = this.fat[s];
|
|
21352
|
+
}
|
|
21353
|
+
return out;
|
|
21354
|
+
}
|
|
21355
|
+
miniChain(start) {
|
|
21356
|
+
const out = [];
|
|
21357
|
+
let s = start;
|
|
21358
|
+
while (s !== ENDOFCHAIN) {
|
|
21359
|
+
if (s === FREESECT || s >= this.miniFat.length || out.length > this.miniFat.length) {
|
|
21360
|
+
throw new OleSurgeonError("miniFAT \uCCB4\uC778 \uC190\uC0C1");
|
|
21361
|
+
}
|
|
21362
|
+
out.push(s);
|
|
21363
|
+
s = this.miniFat[s];
|
|
21364
|
+
}
|
|
21365
|
+
return out;
|
|
21366
|
+
}
|
|
21367
|
+
/** 디렉토리 트리에서 경로 해석 (형제 = L/R 이진 트리, 자식 = child) */
|
|
21368
|
+
findEntry(path) {
|
|
21369
|
+
const parts = path.replace(/^\//, "").split("/");
|
|
21370
|
+
let scope = this.entries[0]?.child ?? -1;
|
|
21371
|
+
let current;
|
|
21372
|
+
for (const part of parts) {
|
|
21373
|
+
const search = (idx) => {
|
|
21374
|
+
if (idx < 0 || idx >= this.entries.length) return void 0;
|
|
21375
|
+
const e = this.entries[idx];
|
|
21376
|
+
return search(e.left) ?? (e.name === part ? e : void 0) ?? search(e.right);
|
|
21377
|
+
};
|
|
21378
|
+
current = search(scope);
|
|
21379
|
+
if (!current) throw new OleSurgeonError(`\uC2A4\uD2B8\uB9BC \uC5C6\uC74C: ${path}`);
|
|
21380
|
+
scope = current.child;
|
|
21381
|
+
}
|
|
21382
|
+
if (!current || current.type !== 2) throw new OleSurgeonError(`\uC2A4\uD2B8\uB9BC\uC774 \uC544\uB2D8: ${path}`);
|
|
21383
|
+
return current;
|
|
21384
|
+
}
|
|
21385
|
+
rootEntry() {
|
|
21386
|
+
return this.entries[0];
|
|
21387
|
+
}
|
|
21388
|
+
// ── 할당 ──
|
|
21389
|
+
/**
|
|
21390
|
+
* FAT에서 빈 섹터 n개 확보 (부족하면 파일 끝에 추가) — 섹터 번호 목록 반환.
|
|
21391
|
+
* 확보 즉시 ENDOFCHAIN으로 마킹해 같은 수술 내 중복 할당을 방지한다 (체인 링크는
|
|
21392
|
+
* 호출자가 덮어씀).
|
|
21393
|
+
*/
|
|
21394
|
+
allocSectors(n) {
|
|
21395
|
+
const out = [];
|
|
21396
|
+
for (let i = 0; i < this.fat.length && out.length < n; i++) {
|
|
21397
|
+
if (this.fat[i] !== FREESECT) continue;
|
|
21398
|
+
if (SECTOR + (i + 1) * SECTOR > this.buf.length) continue;
|
|
21399
|
+
this.fat[i] = ENDOFCHAIN;
|
|
21400
|
+
out.push(i);
|
|
21401
|
+
}
|
|
21402
|
+
while (out.length < n) {
|
|
21403
|
+
this.ensureFatCapacity((this.buf.length - SECTOR) / SECTOR + 2);
|
|
21404
|
+
const idx = (this.buf.length - SECTOR) / SECTOR;
|
|
21405
|
+
this.buf = Buffer.concat([this.buf, Buffer.alloc(SECTOR)]);
|
|
21406
|
+
this.fat[idx] = ENDOFCHAIN;
|
|
21407
|
+
out.push(idx);
|
|
21408
|
+
}
|
|
21409
|
+
return out;
|
|
21410
|
+
}
|
|
21411
|
+
/** FAT 배열이 sectorCount개 엔트리를 담도록 확장 (FAT 섹터 추가 + DIFAT 갱신) */
|
|
21412
|
+
ensureFatCapacity(sectorCount) {
|
|
21413
|
+
while (this.fat.length < sectorCount) {
|
|
21414
|
+
const idx = (this.buf.length - SECTOR) / SECTOR;
|
|
21415
|
+
this.buf = Buffer.concat([this.buf, Buffer.alloc(SECTOR)]);
|
|
21416
|
+
for (let i = 0; i < 128; i++) this.fat.push(FREESECT);
|
|
21417
|
+
this.fat[idx] = FATSECT;
|
|
21418
|
+
this.fatSectors.push(idx);
|
|
21419
|
+
const slot = this.fatSectors.length - 1;
|
|
21420
|
+
if (slot >= 109) throw new OleSurgeonError("DIFAT \uCCB4\uC778 \uD655\uC7A5\uC740 \uBBF8\uC9C0\uC6D0 (7MB \uCD08\uACFC \uCEE8\uD14C\uC774\uB108 \uC131\uC7A5)");
|
|
21421
|
+
this.buf.writeUInt32LE(idx, 76 + slot * 4);
|
|
21422
|
+
this.buf.writeUInt32LE(this.fatSectors.length, 44);
|
|
21423
|
+
}
|
|
21424
|
+
}
|
|
21425
|
+
/** miniFAT에서 빈 미니섹터 n개 확보 (mini stream 용량/miniFAT 확장 포함) */
|
|
21426
|
+
allocMiniSectors(n) {
|
|
21427
|
+
const root = this.rootEntry();
|
|
21428
|
+
const rootChain = root.start === ENDOFCHAIN || root.size === 0 ? [] : this.chain(root.start);
|
|
21429
|
+
let capacity = rootChain.length * (SECTOR / MINI_SECTOR);
|
|
21430
|
+
const out = [];
|
|
21431
|
+
for (let i = 0; i < Math.min(this.miniFat.length, capacity) && out.length < n; i++) {
|
|
21432
|
+
if (this.miniFat[i] === FREESECT) {
|
|
21433
|
+
this.miniFat[i] = ENDOFCHAIN;
|
|
21434
|
+
out.push(i);
|
|
21435
|
+
}
|
|
21436
|
+
}
|
|
21437
|
+
let nextIdx = capacity;
|
|
21438
|
+
while (out.length < n) {
|
|
21439
|
+
if (nextIdx >= this.miniFat.length) {
|
|
21440
|
+
const [s] = this.allocSectors(1);
|
|
21441
|
+
if (this.miniFatSectors.length > 0) this.fat[this.miniFatSectors[this.miniFatSectors.length - 1]] = s;
|
|
21442
|
+
else this.buf.writeUInt32LE(s, 60);
|
|
21443
|
+
this.miniFatSectors.push(s);
|
|
21444
|
+
this.buf.writeUInt32LE(this.miniFatSectors.length, 64);
|
|
21445
|
+
for (let i = 0; i < 128; i++) this.miniFat.push(FREESECT);
|
|
21446
|
+
}
|
|
21447
|
+
if (nextIdx >= capacity) {
|
|
21448
|
+
const [s] = this.allocSectors(1);
|
|
21449
|
+
if (rootChain.length > 0) this.fat[rootChain[rootChain.length - 1]] = s;
|
|
21450
|
+
else {
|
|
21451
|
+
root.start = s;
|
|
21452
|
+
}
|
|
21453
|
+
rootChain.push(s);
|
|
21454
|
+
capacity = rootChain.length * (SECTOR / MINI_SECTOR);
|
|
21455
|
+
root.size = Math.max(root.size, rootChain.length * SECTOR);
|
|
21456
|
+
this.writeDirEntry(root);
|
|
21457
|
+
}
|
|
21458
|
+
this.miniFat[nextIdx] = ENDOFCHAIN;
|
|
21459
|
+
out.push(nextIdx);
|
|
21460
|
+
nextIdx++;
|
|
21461
|
+
}
|
|
21462
|
+
return out;
|
|
21463
|
+
}
|
|
21464
|
+
// ── 기록 ──
|
|
21465
|
+
writeDirEntry(e) {
|
|
21466
|
+
const sector = this.dirSectors[Math.floor(e.index / 4)];
|
|
21467
|
+
const off = this.sectorOffset(sector) + e.index % 4 * 128;
|
|
21468
|
+
this.buf.writeUInt32LE(e.start, off + 116);
|
|
21469
|
+
this.buf.writeUInt32LE(e.size, off + 120);
|
|
21470
|
+
}
|
|
21471
|
+
flushFat() {
|
|
21472
|
+
for (let i = 0; i < this.fatSectors.length; i++) {
|
|
21473
|
+
const off = this.sectorOffset(this.fatSectors[i]);
|
|
21474
|
+
for (let j = 0; j < 128; j++) {
|
|
21475
|
+
const idx = i * 128 + j;
|
|
21476
|
+
this.buf.writeUInt32LE(idx < this.fat.length ? this.fat[idx] : FREESECT, off + j * 4);
|
|
21477
|
+
}
|
|
21478
|
+
}
|
|
21479
|
+
for (let i = 0; i < this.miniFatSectors.length; i++) {
|
|
21480
|
+
const off = this.sectorOffset(this.miniFatSectors[i]);
|
|
21481
|
+
for (let j = 0; j < 128; j++) {
|
|
21482
|
+
const idx = i * 128 + j;
|
|
21483
|
+
this.buf.writeUInt32LE(idx < this.miniFat.length ? this.miniFat[idx] : FREESECT, off + j * 4);
|
|
21484
|
+
}
|
|
21485
|
+
}
|
|
21486
|
+
}
|
|
21487
|
+
/** 미니섹터 k의 파일 내 바이트 오프셋 (root 체인 경유) */
|
|
21488
|
+
miniOffset(k, rootChain) {
|
|
21489
|
+
const within = k * MINI_SECTOR;
|
|
21490
|
+
const sec = rootChain[Math.floor(within / SECTOR)];
|
|
21491
|
+
if (sec === void 0) throw new OleSurgeonError("mini stream \uBC94\uC704 \uCD08\uACFC");
|
|
21492
|
+
return this.sectorOffset(sec) + within % SECTOR;
|
|
21493
|
+
}
|
|
21494
|
+
// ── 메인 ──
|
|
21495
|
+
replace(path, newData) {
|
|
21496
|
+
const entry = this.findEntry(path);
|
|
21497
|
+
if (entry.size > 0 && entry.start !== ENDOFCHAIN) {
|
|
21498
|
+
if (entry.size < MINI_CUTOFF) {
|
|
21499
|
+
for (const s of this.miniChain(entry.start)) this.miniFat[s] = FREESECT;
|
|
21500
|
+
} else {
|
|
21501
|
+
for (const s of this.chain(entry.start)) this.fat[s] = FREESECT;
|
|
21502
|
+
}
|
|
21503
|
+
}
|
|
21504
|
+
if (newData.length < MINI_CUTOFF) {
|
|
21505
|
+
const count = Math.ceil(newData.length / MINI_SECTOR) || 1;
|
|
21506
|
+
const sectors = this.allocMiniSectors(count);
|
|
21507
|
+
const rootChain = this.chain(this.rootEntry().start);
|
|
21508
|
+
for (let i = 0; i < sectors.length; i++) {
|
|
21509
|
+
this.miniFat[sectors[i]] = i + 1 < sectors.length ? sectors[i + 1] : ENDOFCHAIN;
|
|
21510
|
+
const off = this.miniOffset(sectors[i], rootChain);
|
|
21511
|
+
this.buf.fill(0, off, off + MINI_SECTOR);
|
|
21512
|
+
newData.copy(this.buf, off, i * MINI_SECTOR, Math.min((i + 1) * MINI_SECTOR, newData.length));
|
|
21513
|
+
}
|
|
21514
|
+
entry.start = sectors[0];
|
|
21515
|
+
} else {
|
|
21516
|
+
const count = Math.ceil(newData.length / SECTOR);
|
|
21517
|
+
const sectors = this.allocSectors(count);
|
|
21518
|
+
for (let i = 0; i < sectors.length; i++) {
|
|
21519
|
+
this.fat[sectors[i]] = i + 1 < sectors.length ? sectors[i + 1] : ENDOFCHAIN;
|
|
21520
|
+
const off = this.sectorOffset(sectors[i]);
|
|
21521
|
+
this.buf.fill(0, off, off + SECTOR);
|
|
21522
|
+
newData.copy(this.buf, off, i * SECTOR, Math.min((i + 1) * SECTOR, newData.length));
|
|
21523
|
+
}
|
|
21524
|
+
entry.start = sectors[0];
|
|
21525
|
+
}
|
|
21526
|
+
entry.size = newData.length;
|
|
21527
|
+
this.writeDirEntry(entry);
|
|
21528
|
+
}
|
|
21529
|
+
finish() {
|
|
21530
|
+
this.flushFat();
|
|
21531
|
+
return this.buf;
|
|
21532
|
+
}
|
|
21533
|
+
};
|
|
21534
|
+
|
|
21535
|
+
// src/roundtrip/hwp5-patch.ts
|
|
21536
|
+
var require3 = createRequire2(import.meta.url);
|
|
21537
|
+
var CFB2 = require3("cfb");
|
|
21538
|
+
var TAG_PARA_LINE_SEG = 69;
|
|
21539
|
+
function cid2(s) {
|
|
21540
|
+
return (s.charCodeAt(0) << 24 | s.charCodeAt(1) << 16 | s.charCodeAt(2) << 8 | s.charCodeAt(3)) >>> 0;
|
|
21541
|
+
}
|
|
21542
|
+
var CTRL_TBL2 = cid2("tbl ");
|
|
21543
|
+
var CTRL_GSO2 = cid2("gso ");
|
|
21544
|
+
function swap322(id) {
|
|
21545
|
+
return ((id & 255) << 24 | (id >>> 8 & 255) << 16 | (id >>> 16 & 255) << 8 | id >>> 24 & 255) >>> 0;
|
|
21546
|
+
}
|
|
21547
|
+
function isCtrl(rec, id) {
|
|
21548
|
+
if (rec.tagId !== TAG_CTRL_HEADER || rec.data.length < 4) return false;
|
|
21549
|
+
const raw = rec.data.readUInt32LE(0);
|
|
21550
|
+
return raw === id || swap322(raw) === id;
|
|
21551
|
+
}
|
|
21552
|
+
function readRecordsStrict(stream) {
|
|
21553
|
+
const recs = [];
|
|
21554
|
+
let off = 0;
|
|
21555
|
+
while (off < stream.length) {
|
|
21556
|
+
if (off + 4 > stream.length) return null;
|
|
21557
|
+
const h = stream.readUInt32LE(off);
|
|
21558
|
+
off += 4;
|
|
21559
|
+
const tagId = h & 1023;
|
|
21560
|
+
const level = h >>> 10 & 1023;
|
|
21561
|
+
let size = h >>> 20 & 4095;
|
|
21562
|
+
if (size === 4095) {
|
|
21563
|
+
if (off + 4 > stream.length) return null;
|
|
21564
|
+
size = stream.readUInt32LE(off);
|
|
21565
|
+
off += 4;
|
|
21566
|
+
}
|
|
21567
|
+
if (off + size > stream.length) return null;
|
|
21568
|
+
recs.push({ tagId, level, data: stream.subarray(off, off + size) });
|
|
21569
|
+
off += size;
|
|
21570
|
+
}
|
|
21571
|
+
return recs;
|
|
21572
|
+
}
|
|
21573
|
+
function serializeRecords(recs, repl) {
|
|
21574
|
+
const parts = [];
|
|
21575
|
+
for (let i = 0; i < recs.length; i++) {
|
|
21576
|
+
const data = repl?.get(i) ?? recs[i].data;
|
|
21577
|
+
const ext = data.length >= 4095;
|
|
21578
|
+
const header = Buffer.alloc(ext ? 8 : 4);
|
|
21579
|
+
header.writeUInt32LE((recs[i].tagId & 1023 | (recs[i].level & 1023) << 10 | (ext ? 4095 : data.length) << 20) >>> 0, 0);
|
|
21580
|
+
if (ext) header.writeUInt32LE(data.length, 4);
|
|
21581
|
+
parts.push(header, data);
|
|
21582
|
+
}
|
|
21583
|
+
return Buffer.concat(parts);
|
|
21584
|
+
}
|
|
21585
|
+
function scanSection(stream, sectionIndex, compressed) {
|
|
21586
|
+
const records = readRecordsStrict(stream);
|
|
21587
|
+
if (!records) return { records: [], safe: false, paras: [], tables: [], compressed, repl: /* @__PURE__ */ new Map() };
|
|
21588
|
+
const safe = serializeRecords(records).equals(stream);
|
|
21589
|
+
const parent = new Int32Array(records.length).fill(-1);
|
|
21590
|
+
const stack = [];
|
|
21591
|
+
for (let i = 0; i < records.length; i++) {
|
|
21592
|
+
while (stack.length > 0 && records[stack[stack.length - 1]].level >= records[i].level) stack.pop();
|
|
21593
|
+
parent[i] = stack.length > 0 ? stack[stack.length - 1] : -1;
|
|
21594
|
+
stack.push(i);
|
|
21595
|
+
}
|
|
21596
|
+
const ancestorCtrl = (i, id) => {
|
|
21597
|
+
for (let p = parent[i]; p >= 0; p = parent[p]) if (isCtrl(records[p], id)) return true;
|
|
21598
|
+
return false;
|
|
21599
|
+
};
|
|
21600
|
+
const paras = [];
|
|
21601
|
+
const parasByHeader = /* @__PURE__ */ new Map();
|
|
21602
|
+
for (let i = 0; i < records.length; i++) {
|
|
21603
|
+
const rec = records[i];
|
|
21604
|
+
if (rec.tagId !== TAG_PARA_HEADER || rec.data.length < 18) continue;
|
|
21605
|
+
let textIdx = -1;
|
|
21606
|
+
let charShapeIdx = -1;
|
|
21607
|
+
let lineSegIdx = -1;
|
|
21608
|
+
const state = createParaTextState();
|
|
21609
|
+
for (let j = i + 1; j < records.length && records[j].level > rec.level; j++) {
|
|
21610
|
+
if (records[j].level !== rec.level + 1) continue;
|
|
21611
|
+
const t = records[j].tagId;
|
|
21612
|
+
if (t === TAG_PARA_TEXT) {
|
|
21613
|
+
textIdx = textIdx === -1 ? j : -2;
|
|
21614
|
+
appendParaText(state, records[j].data);
|
|
21615
|
+
} else if (t === TAG_CHAR_SHAPE && charShapeIdx === -1) charShapeIdx = j;
|
|
21616
|
+
else if (t === TAG_PARA_LINE_SEG && lineSegIdx === -1) lineSegIdx = j;
|
|
21617
|
+
}
|
|
21618
|
+
let ctrlSeen = false, nonGso = false;
|
|
21619
|
+
for (let a = parent[i]; a >= 0; a = parent[a]) {
|
|
21620
|
+
if (records[a].tagId === TAG_CTRL_HEADER) {
|
|
21621
|
+
ctrlSeen = true;
|
|
21622
|
+
if (!isCtrl(records[a], CTRL_GSO2)) nonGso = true;
|
|
21623
|
+
}
|
|
21624
|
+
}
|
|
21625
|
+
const kind = !ctrlSeen || !nonGso ? "body" : "other";
|
|
21626
|
+
const para = {
|
|
21627
|
+
sectionIndex,
|
|
21628
|
+
headerIdx: i,
|
|
21629
|
+
kind,
|
|
21630
|
+
textIdx,
|
|
21631
|
+
charShapeIdx,
|
|
21632
|
+
lineSegIdx,
|
|
21633
|
+
rangeTagCount: rec.data.readUInt16LE(14),
|
|
21634
|
+
ctrlMask: rec.data.readUInt32LE(4),
|
|
21635
|
+
nCharsRaw: rec.data.readUInt32LE(0),
|
|
21636
|
+
rawText: state.text
|
|
21637
|
+
};
|
|
21638
|
+
paras.push(para);
|
|
21639
|
+
parasByHeader.set(i, para);
|
|
21640
|
+
}
|
|
21641
|
+
const tables = [];
|
|
21642
|
+
for (let i = 0; i < records.length; i++) {
|
|
21643
|
+
if (!isCtrl(records[i], CTRL_TBL2) || ancestorCtrl(i, CTRL_TBL2)) continue;
|
|
21644
|
+
const ctrlLevel = records[i].level;
|
|
21645
|
+
let rows = 0, cols = 0, tableIdx = -1;
|
|
21646
|
+
for (let j2 = i + 1; j2 < records.length && records[j2].level > ctrlLevel; j2++) {
|
|
21647
|
+
if (records[j2].level === ctrlLevel + 1 && records[j2].tagId === TAG_TABLE && records[j2].data.length >= 8) {
|
|
21648
|
+
rows = records[j2].data.readUInt16LE(4);
|
|
21649
|
+
cols = records[j2].data.readUInt16LE(6);
|
|
21650
|
+
tableIdx = j2;
|
|
21651
|
+
break;
|
|
21652
|
+
}
|
|
21653
|
+
}
|
|
21654
|
+
if (tableIdx < 0 || rows === 0 || cols === 0) continue;
|
|
21655
|
+
const cells = /* @__PURE__ */ new Map();
|
|
21656
|
+
let j = tableIdx + 1;
|
|
21657
|
+
while (j < records.length && records[j].level > ctrlLevel) {
|
|
21658
|
+
if (records[j].tagId !== TAG_LIST_HEADER) {
|
|
21659
|
+
j++;
|
|
21660
|
+
continue;
|
|
21661
|
+
}
|
|
21662
|
+
const lh = records[j];
|
|
21663
|
+
const cellLevel = lh.level;
|
|
21664
|
+
const cellParas = [];
|
|
21665
|
+
let k = j + 1;
|
|
21666
|
+
while (k < records.length) {
|
|
21667
|
+
const r = records[k];
|
|
21668
|
+
if (r.level < cellLevel) break;
|
|
21669
|
+
if (r.level === cellLevel && (r.tagId === TAG_LIST_HEADER || r.tagId === TAG_TABLE)) break;
|
|
21670
|
+
if (r.level === cellLevel && r.tagId === TAG_PARA_HEADER) {
|
|
21671
|
+
const cp = parasByHeader.get(k);
|
|
21672
|
+
if (cp) {
|
|
21673
|
+
cp.kind = "cell";
|
|
21674
|
+
cellParas.push(cp);
|
|
21675
|
+
}
|
|
21676
|
+
}
|
|
21677
|
+
k++;
|
|
21678
|
+
}
|
|
21679
|
+
if (lh.data.length >= 16) {
|
|
21680
|
+
cells.set(`${lh.data.readUInt16LE(10)},${lh.data.readUInt16LE(8)}`, { paras: cellParas });
|
|
21681
|
+
}
|
|
21682
|
+
j = k;
|
|
21683
|
+
}
|
|
21684
|
+
tables.push({ sectionIndex, rows, cols, cells });
|
|
21685
|
+
}
|
|
21686
|
+
return { records, safe, paras, tables, compressed, repl: /* @__PURE__ */ new Map() };
|
|
21687
|
+
}
|
|
21688
|
+
async function patchHwp(original, editedMarkdown, options) {
|
|
21689
|
+
const skipped = [];
|
|
21690
|
+
let applied = 0;
|
|
21691
|
+
const originalBuf = Buffer.from(original.buffer, original.byteOffset, original.byteLength);
|
|
21692
|
+
let cfb;
|
|
21693
|
+
try {
|
|
21694
|
+
cfb = CFB2.parse(originalBuf);
|
|
21695
|
+
} catch (err) {
|
|
21696
|
+
return fail(`CFB \uCEE8\uD14C\uC774\uB108 \uD30C\uC2F1 \uC2E4\uD328: ${msg(err)}`);
|
|
21697
|
+
}
|
|
21698
|
+
const fhEntry = CFB2.find(cfb, "/FileHeader");
|
|
21699
|
+
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");
|
|
21700
|
+
let flags;
|
|
21701
|
+
try {
|
|
21702
|
+
flags = parseFileHeader(Buffer.from(fhEntry.content)).flags;
|
|
21703
|
+
} catch (err) {
|
|
21704
|
+
return fail(`FileHeader \uD30C\uC2F1 \uC2E4\uD328: ${msg(err)}`);
|
|
21705
|
+
}
|
|
21706
|
+
if (flags & (FLAG_ENCRYPTED | FLAG_DISTRIBUTION | FLAG_DRM)) {
|
|
21707
|
+
return fail("\uC554\uD638\uD654/\uBC30\uD3EC\uC6A9/DRM \uBB38\uC11C\uB294 \uD328\uCE58\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
21708
|
+
}
|
|
21709
|
+
const compressed = (flags & FLAG_COMPRESSED) !== 0;
|
|
21710
|
+
let origBlocks;
|
|
21711
|
+
try {
|
|
21712
|
+
origBlocks = parseHwp5Document(originalBuf).blocks;
|
|
21713
|
+
} catch (err) {
|
|
21714
|
+
return fail(`\uC6D0\uBCF8 HWP \uD30C\uC2F1 \uC2E4\uD328: ${msg(err)}`);
|
|
21715
|
+
}
|
|
21716
|
+
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]));
|
|
21717
|
+
if (sectionPaths.length === 0) return fail("BodyText \uC139\uC158 \uC2A4\uD2B8\uB9BC\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
21718
|
+
const scans = [];
|
|
21719
|
+
for (let i = 0; i < sectionPaths.length; i++) {
|
|
21720
|
+
const entry = CFB2.find(cfb, sectionPaths[i]);
|
|
21721
|
+
if (!entry?.content) return fail(`\uC139\uC158 \uC2A4\uD2B8\uB9BC \uC77D\uAE30 \uC2E4\uD328: ${sectionPaths[i]}`);
|
|
21722
|
+
let stream;
|
|
21723
|
+
try {
|
|
21724
|
+
stream = compressed ? decompressStream(Buffer.from(entry.content)) : Buffer.from(entry.content);
|
|
21725
|
+
} catch (err) {
|
|
21726
|
+
return fail(`\uC139\uC158 \uC555\uCD95 \uD574\uC81C \uC2E4\uD328: ${msg(err)}`);
|
|
21727
|
+
}
|
|
21728
|
+
scans.push(scanSection(stream, i, compressed));
|
|
21729
|
+
}
|
|
21730
|
+
const origUnits = buildOrigUnits(origBlocks);
|
|
21731
|
+
const editedUnits = splitMarkdownUnits(editedMarkdown);
|
|
21732
|
+
const pairs = alignUnits(origUnits.map((u) => u.raw), editedUnits.map((u) => u.raw));
|
|
21733
|
+
const paraMap = resolveParaMappings(origBlocks, scans);
|
|
21734
|
+
const scanTables = scans.flatMap((s) => s.tables);
|
|
21735
|
+
const obTableOrdinals = /* @__PURE__ */ new Map();
|
|
21736
|
+
{
|
|
21737
|
+
let ordinal = 0;
|
|
21738
|
+
for (let i = 0; i < origBlocks.length; i++) {
|
|
21739
|
+
if (origBlocks[i].type === "table" && origBlocks[i].table) obTableOrdinals.set(i, ordinal++);
|
|
21740
|
+
}
|
|
21741
|
+
}
|
|
21742
|
+
for (const [oi, ei] of pairs) {
|
|
21743
|
+
if (oi !== null && ei !== null) {
|
|
21744
|
+
const orig = origUnits[oi];
|
|
21745
|
+
const edited = editedUnits[ei];
|
|
21746
|
+
if (orig.raw === edited.raw) continue;
|
|
21747
|
+
applied += handleModified(orig, edited, {
|
|
21748
|
+
origBlocks,
|
|
21749
|
+
paraMap,
|
|
21750
|
+
scans,
|
|
21751
|
+
scanTables,
|
|
21752
|
+
obTableOrdinals,
|
|
21753
|
+
skipped
|
|
21754
|
+
});
|
|
21755
|
+
} else if (oi !== null) {
|
|
21756
|
+
skipped.push({ reason: "\uBE14\uB85D \uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0 (v1) \u2014 \uC6D0\uBCF8 \uC720\uC9C0", before: summarize(origUnits[oi].raw) });
|
|
21757
|
+
} else if (ei !== null) {
|
|
21758
|
+
skipped.push({ reason: "\uBE14\uB85D \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)", after: summarize(editedUnits[ei].raw) });
|
|
21759
|
+
}
|
|
21760
|
+
}
|
|
21761
|
+
let data;
|
|
21762
|
+
const dirty = scans.some((s) => s.repl.size > 0);
|
|
21763
|
+
if (!dirty) {
|
|
21764
|
+
data = new Uint8Array(original);
|
|
21765
|
+
} else {
|
|
21766
|
+
try {
|
|
21767
|
+
let out = originalBuf;
|
|
21768
|
+
for (let i = 0; i < scans.length; i++) {
|
|
21769
|
+
if (scans[i].repl.size === 0) continue;
|
|
21770
|
+
const newStream = serializeRecords(scans[i].records, scans[i].repl);
|
|
21771
|
+
const content = compressed ? deflateRawSync2(newStream) : newStream;
|
|
21772
|
+
out = replaceOleStream(out, sectionPaths[i], content);
|
|
21773
|
+
}
|
|
21774
|
+
data = new Uint8Array(out);
|
|
21775
|
+
} catch (err) {
|
|
21776
|
+
return { success: false, applied: 0, skipped, error: `HWP \uC139\uD130 \uC218\uC220 \uC2E4\uD328: ${msg(err)}` };
|
|
21777
|
+
}
|
|
21778
|
+
}
|
|
21779
|
+
let verification;
|
|
21780
|
+
if (options?.verify !== false) {
|
|
21781
|
+
try {
|
|
21782
|
+
const reparsed = parseHwp5Document(Buffer.from(data));
|
|
21783
|
+
verification = diffUnitLists(splitMarkdownUnits(reparsed.markdown), editedUnits);
|
|
21784
|
+
} catch (err) {
|
|
21785
|
+
return { success: false, applied, skipped, error: `\uD328\uCE58\uBCF8 \uC7AC\uD30C\uC2F1 \uC2E4\uD328 \u2014 \uD328\uCE58 \uC911\uB2E8: ${msg(err)}` };
|
|
21786
|
+
}
|
|
21787
|
+
}
|
|
21788
|
+
return { success: true, data, applied, skipped, verification };
|
|
21789
|
+
function fail(error) {
|
|
21790
|
+
return { success: false, applied: 0, skipped, error };
|
|
21791
|
+
}
|
|
21792
|
+
}
|
|
21793
|
+
function msg(err) {
|
|
21794
|
+
return err instanceof Error ? err.message : String(err);
|
|
21795
|
+
}
|
|
21796
|
+
function resolveParaMappings(blocks, scans) {
|
|
21797
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
21798
|
+
for (const scan of scans) {
|
|
21799
|
+
for (const para of scan.paras) {
|
|
21800
|
+
if (para.kind === "other") continue;
|
|
21801
|
+
const key = normForMatch(para.rawText);
|
|
21802
|
+
if (!key) continue;
|
|
21803
|
+
let list = buckets.get(key);
|
|
21804
|
+
if (!list) buckets.set(key, list = []);
|
|
21805
|
+
list.push(para);
|
|
21806
|
+
}
|
|
21807
|
+
}
|
|
21808
|
+
const usable = (list) => list.length === 1 || list.every((p) => p.kind === "body");
|
|
21809
|
+
const counters = /* @__PURE__ */ new Map();
|
|
21810
|
+
const result = /* @__PURE__ */ new Map();
|
|
21811
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
21812
|
+
const b = blocks[i];
|
|
21813
|
+
if (b.type !== "paragraph" && b.type !== "heading" || !b.text) continue;
|
|
21814
|
+
let key = normForMatch(b.text);
|
|
21815
|
+
let prefixStripped = false;
|
|
21816
|
+
if (!buckets.has(key)) {
|
|
21817
|
+
const sp = b.text.indexOf(" ");
|
|
21818
|
+
if (sp > 0) {
|
|
21819
|
+
const alt = normForMatch(b.text.slice(sp + 1));
|
|
21820
|
+
if (alt && buckets.has(alt)) {
|
|
21821
|
+
key = alt;
|
|
21822
|
+
prefixStripped = true;
|
|
21823
|
+
}
|
|
21824
|
+
}
|
|
21825
|
+
}
|
|
21826
|
+
const list = buckets.get(key);
|
|
21827
|
+
if (!list || !usable(list)) {
|
|
21828
|
+
result.set(i, {});
|
|
21829
|
+
continue;
|
|
21830
|
+
}
|
|
21831
|
+
const occ = counters.get(key) ?? 0;
|
|
21832
|
+
counters.set(key, occ + 1);
|
|
21833
|
+
result.set(i, occ < list.length ? { para: list[occ], prefixStripped } : {});
|
|
21834
|
+
}
|
|
21835
|
+
return result;
|
|
21836
|
+
}
|
|
21837
|
+
function handleModified(orig, edited, ctx) {
|
|
21838
|
+
const block = ctx.origBlocks[orig.blockIdx];
|
|
21839
|
+
const skip = (reason) => {
|
|
21840
|
+
ctx.skipped.push({ reason, before: summarize(orig.raw), after: summarize(edited.raw) });
|
|
21841
|
+
return 0;
|
|
21842
|
+
};
|
|
21843
|
+
if (orig.role === "caption") return skip("\uD45C \uCEA1\uC158 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
21844
|
+
if (orig.kind === "separator" || orig.kind === "image") return skip("\uC774\uBBF8\uC9C0/\uAD6C\uBD84\uC120 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
21845
|
+
if (!block) return skip("\uBE14\uB85D \uB9E4\uD551 \uC2E4\uD328");
|
|
21846
|
+
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)");
|
|
21847
|
+
if (block.type === "table" && block.table) {
|
|
21848
|
+
if (orig.kind !== edited.kind) return skip("\uD45C \u2194 \uBE44\uD45C \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0 (\uD45C \uAD6C\uC870 \uBCC0\uACBD)");
|
|
21849
|
+
if (ctx.obTableOrdinals.size !== ctx.scanTables.length) return skip("\uD45C \uAC1C\uC218 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
21850
|
+
const ordinal = ctx.obTableOrdinals.get(orig.blockIdx);
|
|
21851
|
+
const scanTable = ordinal !== void 0 ? ctx.scanTables[ordinal] : void 0;
|
|
21852
|
+
if (!scanTable) return skip("\uD45C \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328");
|
|
21853
|
+
if (orig.kind === "gfm-table") return patchGfmCells(scanTable, orig, edited, ctx, skip);
|
|
21854
|
+
if (orig.kind === "html-table") return skip("HTML \uD45C(\uBCD1\uD569/\uC904\uBC14\uAFC8 \uC140) \uC218\uC815\uC740 HWP5 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
21855
|
+
return patchTextChunk5(block.table, scanTable, orig, edited, ctx, skip);
|
|
21856
|
+
}
|
|
21857
|
+
if ((block.type === "paragraph" || block.type === "heading") && orig.kind === "text" && edited.kind === "text") {
|
|
21858
|
+
return patchParagraph(block, orig, edited, ctx, skip);
|
|
21859
|
+
}
|
|
21860
|
+
return skip("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBE14\uB85D \uC720\uD615 \uBCC0\uACBD");
|
|
21861
|
+
}
|
|
21862
|
+
function patchParagraph(block, orig, edited, ctx, skip) {
|
|
21863
|
+
const mapping = ctx.paraMap.get(orig.blockIdx);
|
|
21864
|
+
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)");
|
|
21865
|
+
if (block.text && block.text.includes("\n")) {
|
|
21866
|
+
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)");
|
|
21867
|
+
}
|
|
21868
|
+
let newPlain = textUnitToPlain(edited.raw, block);
|
|
21869
|
+
if (block.footnoteText) {
|
|
21870
|
+
const noteMatch = newPlain.match(/\s*\(주: ([\s\S]*)\)$/);
|
|
21871
|
+
if (noteMatch) {
|
|
21872
|
+
newPlain = newPlain.slice(0, noteMatch.index).trimEnd();
|
|
21873
|
+
if (normForMatch(noteMatch[1]) !== normForMatch(block.footnoteText)) {
|
|
21874
|
+
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] });
|
|
21875
|
+
}
|
|
21876
|
+
} else {
|
|
21877
|
+
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})` });
|
|
21878
|
+
}
|
|
21879
|
+
}
|
|
21880
|
+
if (mapping.prefixStripped) {
|
|
21881
|
+
const origPrefix = block.text.split(" ", 1)[0];
|
|
21882
|
+
const sp = newPlain.indexOf(" ");
|
|
21883
|
+
const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
|
|
21884
|
+
if (newFirst === origPrefix || /^(?:[0-90-9a-zA-Z가-힣]{1,6}[.)\]:]|[([][0-90-9a-zA-Z가-힣]{1,6}[)\]][.:]?|[ⅰ-ⅹⅠ-Ⅹ①-⑮][.)\]:]?)$/u.test(newFirst)) {
|
|
21885
|
+
newPlain = sp > 0 ? newPlain.slice(sp + 1) : "";
|
|
21886
|
+
} else {
|
|
21887
|
+
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) });
|
|
21888
|
+
}
|
|
21889
|
+
}
|
|
21890
|
+
const origPlain = textUnitToPlain(orig.raw, block);
|
|
21891
|
+
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");
|
|
21892
|
+
if (sanitizeText(newPlain) !== newPlain) {
|
|
21893
|
+
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");
|
|
21894
|
+
}
|
|
21895
|
+
return stageParaPatch(ctx.scans[mapping.para.sectionIndex], mapping.para, newPlain, skip);
|
|
21896
|
+
}
|
|
21897
|
+
function patchGfmCells(scanTable, orig, edited, ctx, skip) {
|
|
21898
|
+
const origRows = parseGfmTable(orig.lines);
|
|
21899
|
+
const editedRows = parseGfmTable(edited.lines);
|
|
21900
|
+
if (origRows.length !== editedRows.length || origRows.some((r, i) => r.length !== editedRows[i].length)) {
|
|
21901
|
+
return skip("\uD45C \uAD6C\uC870 \uBCC0\uACBD(\uD589/\uC5F4 \uC218)\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
21902
|
+
}
|
|
21903
|
+
let applied = 0;
|
|
21904
|
+
for (let r = 0; r < origRows.length; r++) {
|
|
21905
|
+
for (let c = 0; c < origRows[r].length; c++) {
|
|
21906
|
+
if (origRows[r][c] === editedRows[r][c]) continue;
|
|
21907
|
+
const cellSkip = (reason) => {
|
|
21908
|
+
ctx.skipped.push({ reason, before: summarize(origRows[r][c]), after: summarize(editedRows[r][c]) });
|
|
21909
|
+
return 0;
|
|
21910
|
+
};
|
|
21911
|
+
const before = gfmCellToPlain(origRows[r][c]);
|
|
21912
|
+
const after = gfmCellToPlain(editedRows[r][c]);
|
|
21913
|
+
if (before === null || after === null) {
|
|
21914
|
+
cellSkip("\uC11C\uC2DD/\uB9C1\uD06C/\uC774\uBBF8\uC9C0 \uD3EC\uD568 \uC140 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
21915
|
+
continue;
|
|
21916
|
+
}
|
|
21917
|
+
if (after.includes("\n")) {
|
|
21918
|
+
cellSkip("\uC140 \uB0B4 \uC904\uBC14\uAFC8 \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
21919
|
+
continue;
|
|
21920
|
+
}
|
|
21921
|
+
const cell = scanTable.cells.get(`${r},${c}`);
|
|
21922
|
+
if (!cell) {
|
|
21923
|
+
cellSkip("\uBCD1\uD569 \uC601\uC5ED \uC140 \u2014 \uC575\uCEE4 \uC140\uC774 \uC544\uB2C8\uBBC0\uB85C \uBBF8\uC9C0\uC6D0");
|
|
21924
|
+
continue;
|
|
21925
|
+
}
|
|
21926
|
+
if (cell.paras.length !== 1) {
|
|
21927
|
+
cellSkip("\uBCF5\uC218 \uBB38\uB2E8 \uC140 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
21928
|
+
continue;
|
|
21929
|
+
}
|
|
21930
|
+
const para = cell.paras[0];
|
|
21931
|
+
if (normForMatch(para.rawText) !== normForMatch(before)) {
|
|
21932
|
+
cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
21933
|
+
continue;
|
|
21934
|
+
}
|
|
21935
|
+
if (sanitizeText(after) !== after) {
|
|
21936
|
+
cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
21937
|
+
continue;
|
|
21938
|
+
}
|
|
21939
|
+
applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
|
|
21940
|
+
}
|
|
21941
|
+
}
|
|
21942
|
+
return applied;
|
|
21943
|
+
}
|
|
21944
|
+
function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
|
|
21945
|
+
if (table.rows === 1 && table.cols === 1) {
|
|
21946
|
+
const content = sanitizeText(table.cells[0][0].text);
|
|
21947
|
+
const replicaLines = content.split(/\n/).map((line) => {
|
|
21948
|
+
const t = line.trim();
|
|
21949
|
+
if (!t) return "";
|
|
21950
|
+
if (/^\d+\.\s/.test(t)) return `**${escapeGfm(t)}**`;
|
|
21951
|
+
return escapeGfm(t);
|
|
21952
|
+
}).filter(Boolean);
|
|
21953
|
+
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");
|
|
21954
|
+
if (extractCellTokens(orig.raw) !== extractCellTokens(edited.raw)) return skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
21955
|
+
const newLines = edited.lines.map((l) => {
|
|
21956
|
+
const m = l.match(/^\*\*([\s\S]*)\*\*$/);
|
|
21957
|
+
const unwrap = m && /^\d+\.\s/.test(unescapeGfm(m[1]));
|
|
21958
|
+
return stripCellTokens(unescapeGfm(unwrap ? m[1] : l)).trim();
|
|
21959
|
+
}).filter(Boolean);
|
|
21960
|
+
return applyCellEdit5(table, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
|
|
21961
|
+
}
|
|
21962
|
+
if (table.cols === 1 && table.rows >= 2) {
|
|
21963
|
+
const replica = [];
|
|
21964
|
+
for (let r = 0; r < table.rows; r++) {
|
|
21965
|
+
const line = escapeGfm(sanitizeText(table.cells[r][0].text)).replace(/\n/g, " ");
|
|
21966
|
+
if (line) replica.push({ line, gridR: r });
|
|
21967
|
+
}
|
|
21968
|
+
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");
|
|
21969
|
+
if (edited.lines.length !== replica.length) return skip("\uD45C \uD589 \uCD94\uAC00/\uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0 (\uD45C \uAD6C\uC870 \uBCC0\uACBD)");
|
|
21970
|
+
let applied = 0;
|
|
21971
|
+
for (let i = 0; i < replica.length; i++) {
|
|
21972
|
+
if (replica[i].line === edited.lines[i]) continue;
|
|
21973
|
+
if (extractCellTokens(replica[i].line) !== extractCellTokens(edited.lines[i])) {
|
|
21974
|
+
skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
21975
|
+
continue;
|
|
21976
|
+
}
|
|
21977
|
+
const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean);
|
|
21978
|
+
applied += applyCellEdit5(table, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
|
|
21979
|
+
}
|
|
21980
|
+
return applied;
|
|
21981
|
+
}
|
|
21982
|
+
return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
|
|
21983
|
+
}
|
|
21984
|
+
function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
|
|
21985
|
+
const skip = (reason) => {
|
|
21986
|
+
ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) });
|
|
21987
|
+
return 0;
|
|
21988
|
+
};
|
|
21989
|
+
const cell = scanTable.cells.get(`${gridR},${gridC}`);
|
|
21990
|
+
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)");
|
|
21991
|
+
const irCell = table.cells[gridR]?.[gridC];
|
|
21992
|
+
const scanJoined = cell.paras.map((p) => p.rawText).filter((t) => normForMatch(t)).join("\n");
|
|
21993
|
+
if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
|
|
21994
|
+
if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
|
|
21995
|
+
const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
|
|
21996
|
+
const flatJoined = flatBlocks.map((b) => b.text ?? "").join("\n");
|
|
21997
|
+
if (normForMatch(scanJoined) !== normForMatch(flatJoined)) {
|
|
21998
|
+
return skip("\uC140 \uCF58\uD150\uCE20 \uAD6C\uC870 \uBCF5\uC7A1 (\uC911\uCCA9\uD45C/\uAE00\uC0C1\uC790) \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
21999
|
+
}
|
|
22000
|
+
}
|
|
22001
|
+
}
|
|
22002
|
+
const nonEmpty = cell.paras.filter((p) => normForMatch(p.rawText) !== "");
|
|
22003
|
+
if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
|
|
22004
|
+
return skip("\uC140 \uC904 \uACBD\uACC4 \uB9E4\uD551 \uBAA8\uD638 (\uBB38\uB2E8 \uB0B4 \uC904\uBC14\uAFC8) \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22005
|
+
}
|
|
22006
|
+
const unstable = newLines.find((l) => sanitizeText(l) !== l);
|
|
22007
|
+
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");
|
|
22008
|
+
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");
|
|
22009
|
+
const assigned = [];
|
|
22010
|
+
for (let i = 0; i < nonEmpty.length; i++) {
|
|
22011
|
+
if (i < newLines.length) {
|
|
22012
|
+
assigned.push(i === nonEmpty.length - 1 && newLines.length > nonEmpty.length ? newLines.slice(i).join(" ") : newLines[i]);
|
|
22013
|
+
} else {
|
|
22014
|
+
assigned.push("");
|
|
22015
|
+
}
|
|
22016
|
+
}
|
|
22017
|
+
if (newLines.length > nonEmpty.length) {
|
|
22018
|
+
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) });
|
|
22019
|
+
}
|
|
22020
|
+
let staged = 0;
|
|
22021
|
+
for (let i = 0; i < nonEmpty.length; i++) {
|
|
22022
|
+
if (assigned[i] === nonEmpty[i].rawText || normForMatch(assigned[i]) === normForMatch(nonEmpty[i].rawText)) continue;
|
|
22023
|
+
staged += stageParaPatch(ctx.scans[nonEmpty[i].sectionIndex], nonEmpty[i], assigned[i], skip);
|
|
22024
|
+
}
|
|
22025
|
+
return staged > 0 ? 1 : 0;
|
|
22026
|
+
}
|
|
22027
|
+
function gfmCellToPlain(md2) {
|
|
22028
|
+
let t = md2.trim();
|
|
22029
|
+
const bold = t.match(/^\*\*([\s\S]+)\*\*$/);
|
|
22030
|
+
if (bold) t = bold[1];
|
|
22031
|
+
if (/[*`]|!\[|\]\(|<(?!br\s*\/?>)/i.test(t)) return null;
|
|
22032
|
+
return unescapeGfm(unescapeGfmCell(t));
|
|
22033
|
+
}
|
|
22034
|
+
var PARA_BREAK = Buffer.from([13, 0]);
|
|
22035
|
+
function stageParaPatch(scan, para, newPlain, skip) {
|
|
22036
|
+
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");
|
|
22037
|
+
if (para.textIdx === -1) return skip("\uBE48 \uBB38\uB2E8 \uD14D\uC2A4\uD2B8 \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22038
|
+
if (para.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22039
|
+
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)");
|
|
22040
|
+
if (para.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
22041
|
+
if (para.charShapeIdx < 0 || para.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22042
|
+
if (scan.repl.has(para.headerIdx)) return skip("\uB3D9\uC77C \uBB38\uB2E8 \uC911\uBCF5 \uC218\uC815 \u2014 \uCCAB \uC218\uC815\uB9CC \uC801\uC6A9");
|
|
22043
|
+
if (/[\u0000-\u001f]/.test(newPlain)) return skip("\uC0C8 \uD14D\uC2A4\uD2B8\uC5D0 \uC81C\uC5B4\uBB38\uC790 \uD3EC\uD568 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22044
|
+
const records = scan.records;
|
|
22045
|
+
const headerRec = records[para.headerIdx];
|
|
22046
|
+
const textRec = records[para.textIdx];
|
|
22047
|
+
const charShapeRec = records[para.charShapeIdx];
|
|
22048
|
+
const lineSegRec = records[para.lineSegIdx];
|
|
22049
|
+
if (charShapeRec.data.length < 8 || lineSegRec.data.length < 36) {
|
|
22050
|
+
return skip("CHAR_SHAPE/LINE_SEG \uB808\uCF54\uB4DC \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22051
|
+
}
|
|
22052
|
+
const hadBreak = textRec.data.length >= 2 && textRec.data.readUInt16LE(textRec.data.length - 2) === 13;
|
|
22053
|
+
const expect = hadBreak ? Buffer.concat([Buffer.from(para.rawText, "utf16le"), PARA_BREAK]) : Buffer.from(para.rawText, "utf16le");
|
|
22054
|
+
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");
|
|
22055
|
+
const lead = para.rawText.match(/^\s*/)[0];
|
|
22056
|
+
const trail = para.rawText.match(/\s*$/)[0];
|
|
22057
|
+
const newRaw = para.rawText.trim() === para.rawText ? newPlain : lead + newPlain + trail;
|
|
22058
|
+
const newText = hadBreak ? Buffer.concat([Buffer.from(newRaw, "utf16le"), PARA_BREAK]) : Buffer.from(newRaw, "utf16le");
|
|
22059
|
+
scan.repl.set(para.textIdx, newText);
|
|
22060
|
+
const newHeader = Buffer.from(headerRec.data);
|
|
22061
|
+
const nChars = newRaw.length + (hadBreak ? 1 : 0);
|
|
22062
|
+
newHeader.writeUInt32LE((para.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
|
|
22063
|
+
if (charShapeRec.data.length > 8) {
|
|
22064
|
+
newHeader.writeUInt16LE(1, 12);
|
|
22065
|
+
scan.repl.set(para.charShapeIdx, Buffer.from(charShapeRec.data.subarray(0, 8)));
|
|
22066
|
+
}
|
|
22067
|
+
const csData = scan.repl.get(para.charShapeIdx) ?? Buffer.from(charShapeRec.data);
|
|
22068
|
+
if (csData.readUInt32LE(0) !== 0) {
|
|
22069
|
+
csData.writeUInt32LE(0, 0);
|
|
22070
|
+
scan.repl.set(para.charShapeIdx, csData);
|
|
22071
|
+
}
|
|
22072
|
+
if (lineSegRec.data.length > 36 || lineSegRec.data.readUInt32LE(0) !== 0) {
|
|
22073
|
+
const seg = Buffer.from(lineSegRec.data.subarray(0, 36));
|
|
22074
|
+
seg.writeUInt32LE(0, 0);
|
|
22075
|
+
newHeader.writeUInt16LE(1, 16);
|
|
22076
|
+
scan.repl.set(para.lineSegIdx, seg);
|
|
22077
|
+
}
|
|
22078
|
+
scan.repl.set(para.headerIdx, newHeader);
|
|
22079
|
+
return 1;
|
|
22080
|
+
}
|
|
22081
|
+
|
|
21250
22082
|
// src/print/renderer.ts
|
|
21251
22083
|
import { existsSync } from "fs";
|
|
21252
22084
|
import MarkdownIt from "markdown-it";
|
|
@@ -21409,8 +22241,8 @@ async function parse(input, options) {
|
|
|
21409
22241
|
const buf = await readFile(input);
|
|
21410
22242
|
buffer = toArrayBuffer(buf);
|
|
21411
22243
|
} catch (err) {
|
|
21412
|
-
const
|
|
21413
|
-
return { success: false, fileType: "unknown", error:
|
|
22244
|
+
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}`;
|
|
22245
|
+
return { success: false, fileType: "unknown", error: msg2, code: "PARSE_ERROR" };
|
|
21414
22246
|
}
|
|
21415
22247
|
} else if (Buffer.isBuffer(input)) {
|
|
21416
22248
|
buffer = toArrayBuffer(input);
|
|
@@ -21487,7 +22319,7 @@ async function parseHwp(buffer, options) {
|
|
|
21487
22319
|
async function parsePdf(buffer, options) {
|
|
21488
22320
|
let parsePdfDocument;
|
|
21489
22321
|
try {
|
|
21490
|
-
const mod = await import("./parser-
|
|
22322
|
+
const mod = await import("./parser-3N6FZSKU.js");
|
|
21491
22323
|
parsePdfDocument = mod.parsePdfDocument;
|
|
21492
22324
|
} catch {
|
|
21493
22325
|
return {
|
|
@@ -21588,6 +22420,7 @@ export {
|
|
|
21588
22420
|
compare,
|
|
21589
22421
|
diffBlocks,
|
|
21590
22422
|
patchHwpx,
|
|
22423
|
+
patchHwp,
|
|
21591
22424
|
renderHtml,
|
|
21592
22425
|
markdownToPdf,
|
|
21593
22426
|
blocksToPdf,
|
|
@@ -21602,4 +22435,4 @@ export {
|
|
|
21602
22435
|
parseHwpml,
|
|
21603
22436
|
fillForm
|
|
21604
22437
|
};
|
|
21605
|
-
//# sourceMappingURL=chunk-
|
|
22438
|
+
//# sourceMappingURL=chunk-X7VQVMXQ.js.map
|