wpd-codec 3.4.5 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -27
- package/dist/container/container.cjs +12 -5
- package/dist/container/container.d.cts +2 -1
- package/dist/container/container.d.ts +2 -1
- package/dist/container/container.js +12 -5
- package/dist/container/encryption.d.cts +1 -1
- package/dist/container/encryption.d.ts +1 -1
- package/dist/container/header.d.cts +1 -19
- package/dist/container/header.d.ts +1 -19
- package/dist/container/prefix.d.cts +1 -1
- package/dist/container/prefix.d.ts +1 -1
- package/dist/{diagnostics-DhO7mgqJ.d.cts → diagnostics-fHTFHZ-d.d.cts} +2 -0
- package/dist/{diagnostics-DhO7mgqJ.d.ts → diagnostics-fHTFHZ-d.d.ts} +2 -0
- package/dist/diagnostics.cjs +2 -0
- package/dist/diagnostics.d.cts +1 -1
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.js +2 -0
- package/dist/header-Ca8QZVe3.d.cts +20 -0
- package/dist/header-Ca8QZVe3.d.ts +20 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/read.cjs +85 -14
- package/dist/read.d.cts +1 -1
- package/dist/read.d.ts +1 -1
- package/dist/read.js +85 -14
- package/dist/stream/furniture.cjs +1 -2
- package/dist/stream/furniture.d.cts +2 -2
- package/dist/stream/furniture.d.ts +2 -2
- package/dist/stream/furniture.js +1 -2
- package/dist/stream/ole.cjs +71 -0
- package/dist/stream/ole.d.cts +22 -0
- package/dist/stream/ole.d.ts +22 -0
- package/dist/stream/ole.js +64 -0
- package/dist/stream/wpg.cjs +620 -0
- package/dist/stream/wpg.d.cts +18 -0
- package/dist/stream/wpg.d.ts +18 -0
- package/dist/stream/wpg.js +619 -0
- package/package.json +3 -3
package/dist/read.cjs
CHANGED
|
@@ -15,7 +15,9 @@ const require_stream_table = require("./stream/table.cjs");
|
|
|
15
15
|
const require_stream_box = require("./stream/box.cjs");
|
|
16
16
|
const require_stream_formula = require("./stream/formula.cjs");
|
|
17
17
|
const require_stream_image = require("./stream/image.cjs");
|
|
18
|
+
const require_stream_ole = require("./stream/ole.cjs");
|
|
18
19
|
const require_stream_tab = require("./stream/tab.cjs");
|
|
20
|
+
const require_stream_wpg = require("./stream/wpg.cjs");
|
|
19
21
|
const require_stream_tokenise = require("./stream/tokenise.cjs");
|
|
20
22
|
let document_schema_js = require("document-schema.js");
|
|
21
23
|
//#region src/read.ts
|
|
@@ -437,10 +439,6 @@ function applyCharacterGroup(state, token, container, sink) {
|
|
|
437
439
|
function applyHeaderFooterGroup(state, token, container, sink) {
|
|
438
440
|
const claim = require_stream_furniture.readFurnitureClaim(token.subgroup, token.nonDeletable);
|
|
439
441
|
if (claim === "none") return;
|
|
440
|
-
if (claim === "watermark") {
|
|
441
|
-
reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a watermark, which is neither a header nor a footer and owns no parity -- the shared page-furniture vocabulary has no slot for one.");
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
442
|
const slotKey = `${claim.kind}:${claim.slot}`;
|
|
445
443
|
if (state.furnitureFilled.has(slotKey)) {
|
|
446
444
|
reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.HeaderFooterDropped, `This document declares a second ${claim.kind} for the ${claim.slot} slot -- WordPerfect's own A/B two-slot-per-kind mechanism, which the shared one-flow-per-slot page-furniture vocabulary does not carry; the first ${claim.kind} to claim the slot is the one lifted.`);
|
|
@@ -449,19 +447,19 @@ function applyHeaderFooterGroup(state, token, container, sink) {
|
|
|
449
447
|
const blocks = furnitureBodyBlocks(state, token, container, sink);
|
|
450
448
|
if (blocks === void 0) return;
|
|
451
449
|
state.furnitureFilled.add(slotKey);
|
|
452
|
-
const furniture = claim.kind === "header" ? state.headers : state.footers;
|
|
450
|
+
const furniture = claim.kind === "header" ? state.headers : claim.kind === "footer" ? state.footers : state.watermarks;
|
|
453
451
|
furniture[claim.slot] = blocks;
|
|
454
452
|
}
|
|
455
453
|
function furnitureBodyBlocks(state, token, container, sink) {
|
|
456
454
|
const prefixId = token.prefixIds[0];
|
|
457
455
|
const packet = prefixId === void 0 ? void 0 : require_container_prefix.packetByPrefixId(container.packets, prefixId);
|
|
458
456
|
if (packet?.packetType !== 8) {
|
|
459
|
-
reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a header or
|
|
457
|
+
reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a header, footer, or watermark whose body packet this reader could not resolve; it was not lifted.");
|
|
460
458
|
return;
|
|
461
459
|
}
|
|
462
460
|
const textBlocks = require_container_prefix.readGeneralWpTextBlocks(packet.bytes);
|
|
463
461
|
if (textBlocks === void 0) {
|
|
464
|
-
reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a header or
|
|
462
|
+
reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a header, footer, or watermark whose body packet this reader could not read; it was not lifted.");
|
|
465
463
|
return;
|
|
466
464
|
}
|
|
467
465
|
return foldTokens(require_stream_tokenise.tokeniseDocumentArea(textBlocks, 0, textBlocks.length), container, sink).blocks;
|
|
@@ -546,6 +544,16 @@ function applyMergeGroup(state, token, sink) {
|
|
|
546
544
|
function plainTextOf(blocks) {
|
|
547
545
|
return blocks.filter((block) => block.kind === "paragraph").map((paragraph) => paragraph.runs.map((run) => run.text).join("")).join("\n");
|
|
548
546
|
}
|
|
547
|
+
function decodeBoxWpg(container, graphicsPacket, sink) {
|
|
548
|
+
const childIds = require_stream_ole.readGraphicsChildIds(graphicsPacket);
|
|
549
|
+
if (childIds === void 0) return;
|
|
550
|
+
for (const childId of childIds) {
|
|
551
|
+
const child = require_container_prefix.packetByPrefixId(container.packets, childId);
|
|
552
|
+
if (child?.packetType !== 111) continue;
|
|
553
|
+
const decoded = require_stream_wpg.decodeWpgGraphic(child.bytes, { foldTextData: (documentArea) => foldTokens(require_stream_tokenise.tokeniseDocumentArea(documentArea, 0, documentArea.length), container, sink).blocks });
|
|
554
|
+
if (decoded !== void 0) return decoded;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
549
557
|
function applyBoxGroup(state, token, container, sink) {
|
|
550
558
|
const boxContent = require_stream_box.readBoxContent(token.nonDeletable, token.prefixIds);
|
|
551
559
|
if (boxContent === void 0) {
|
|
@@ -556,6 +564,50 @@ function applyBoxGroup(state, token, container, sink) {
|
|
|
556
564
|
const imagePacket = require_container_prefix.packetByPrefixId(container.packets, boxContent.contentPrefixId);
|
|
557
565
|
const payload = imagePacket === void 0 ? void 0 : require_stream_image.scanImagePayload(imagePacket.bytes);
|
|
558
566
|
if (payload === void 0) {
|
|
567
|
+
const ole = imagePacket?.packetType === 64 ? require_stream_ole.readOleObject(container.packets, imagePacket, container.oleObjectStreams) : void 0;
|
|
568
|
+
if (ole !== void 0) {
|
|
569
|
+
state.oleObjects.push(ole);
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const wpg = imagePacket?.packetType === 64 ? decodeBoxWpg(container, imagePacket, sink) : void 0;
|
|
573
|
+
if (wpg !== void 0) {
|
|
574
|
+
if (wpg.status === "refused") {
|
|
575
|
+
sink({
|
|
576
|
+
code: require_diagnostics.WpdDiagnosticCodes.WpgRecordsUndecoded,
|
|
577
|
+
message: wpg.reason === "wpg1" ? "This document embeds a WPG 1.0 vector graphic, whose type-and-length record vocabulary predates the framed WPG 2.x stream this reader decodes, so it was not lifted." : wpg.reason === "encrypted" ? "This document embeds an encrypted WPG vector graphic, which this reader does not decrypt, so it was not lifted." : "This document embeds a WPG graphic whose record stream this reader could not walk (no well-formed Start WPG record), so it was not lifted."
|
|
578
|
+
});
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (boxContent.frame === void 0) {
|
|
582
|
+
reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.BoxFrameUnresolved, "This document contains a box whose content this reader could read, but whose function-level override states no width and height this reader can trust, so its content was not lifted.");
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (wpg.skippedRecords.length > 0) sink({
|
|
586
|
+
code: require_diagnostics.WpdDiagnosticCodes.WpgRecordsUndecoded,
|
|
587
|
+
message: `This document embeds a WPG vector graphic that partially decoded; the following record types were skipped: ${wpg.skippedRecords.join(", ")}.`
|
|
588
|
+
});
|
|
589
|
+
flushParagraphIfContent(state, sink);
|
|
590
|
+
targetBlocks(state).push({
|
|
591
|
+
kind: "embeddedObject",
|
|
592
|
+
objectKind: "drawing",
|
|
593
|
+
frame: {
|
|
594
|
+
xPt: boxContent.frame.xPt,
|
|
595
|
+
yPt: boxContent.frame.yPt,
|
|
596
|
+
widthPt: boxContent.frame.widthPt,
|
|
597
|
+
heightPt: boxContent.frame.heightPt
|
|
598
|
+
},
|
|
599
|
+
document: {
|
|
600
|
+
kind: "drawing",
|
|
601
|
+
metadata: {},
|
|
602
|
+
pages: [{
|
|
603
|
+
size: wpg.sizePt,
|
|
604
|
+
shapes: [...wpg.shapes],
|
|
605
|
+
vectors: [...wpg.vectors]
|
|
606
|
+
}]
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
559
611
|
reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.BoxContentUnresolved, "This document contains an image box whose content packet carries no decodable PNG or JPEG payload -- a WPG graphic or other image spelling this reader does not decode.");
|
|
560
612
|
return;
|
|
561
613
|
}
|
|
@@ -788,9 +840,11 @@ function foldTokens(tokens, container, sink) {
|
|
|
788
840
|
openMergeFieldStartRun: void 0,
|
|
789
841
|
headers: {},
|
|
790
842
|
footers: {},
|
|
843
|
+
watermarks: {},
|
|
791
844
|
furnitureFilled: /* @__PURE__ */ new Set(),
|
|
792
845
|
openNote: void 0,
|
|
793
|
-
notes: []
|
|
846
|
+
notes: [],
|
|
847
|
+
oleObjects: []
|
|
794
848
|
};
|
|
795
849
|
for (const token of tokens) applyToken(state, token, container, sink);
|
|
796
850
|
flushRun(state);
|
|
@@ -804,7 +858,9 @@ function foldTokens(tokens, container, sink) {
|
|
|
804
858
|
page: state.page,
|
|
805
859
|
headers: state.headers,
|
|
806
860
|
footers: state.footers,
|
|
807
|
-
|
|
861
|
+
watermarks: state.watermarks,
|
|
862
|
+
notes: state.notes,
|
|
863
|
+
oleObjects: state.oleObjects
|
|
808
864
|
};
|
|
809
865
|
}
|
|
810
866
|
function readMetadata(container) {
|
|
@@ -814,11 +870,15 @@ function readMetadata(container) {
|
|
|
814
870
|
function readWpdContent(bytes, options = {}) {
|
|
815
871
|
const sink = options.sink ?? require_diagnostics.NOOP_WPD_DIAGNOSTIC_SINK;
|
|
816
872
|
const container = require_container_container.openWpdDocument(bytes, { password: options.password });
|
|
817
|
-
const { blocks, page, headers, footers, notes } = foldTokens(require_stream_tokenise.tokeniseDocumentArea(container.bytes, container.documentAreaOffset, container.documentAreaEnd), container, sink);
|
|
873
|
+
const { blocks, page, headers, footers, watermarks, notes, oleObjects } = foldTokens(require_stream_tokenise.tokeniseDocumentArea(container.bytes, container.documentAreaOffset, container.documentAreaEnd), container, sink);
|
|
818
874
|
for (const note of notes) sink({
|
|
819
875
|
code: require_diagnostics.WpdDiagnosticCodes.NoteDropped,
|
|
820
876
|
message: `This document contains a ${note.anchorType} whose body the flat ContentDocument has no home for; its reference anchor survives and readWpd lifts the body into the tree form's definitions table.`
|
|
821
877
|
});
|
|
878
|
+
for (const oleObject of oleObjects) sink({
|
|
879
|
+
code: require_diagnostics.WpdDiagnosticCodes.OleObjectDropped,
|
|
880
|
+
message: `This document embeds a native OLE object ('${oleObject.name}') whose bytes the flat ContentDocument has no home for; readWpd lifts them into the tree form's attachments table.`
|
|
881
|
+
});
|
|
822
882
|
return {
|
|
823
883
|
kind: "wordprocessing",
|
|
824
884
|
metadata: readMetadata(container),
|
|
@@ -835,13 +895,14 @@ function readWpdContent(bytes, options = {}) {
|
|
|
835
895
|
},
|
|
836
896
|
...Object.keys(headers).length > 0 ? { headers } : {},
|
|
837
897
|
...Object.keys(footers).length > 0 ? { footers } : {},
|
|
898
|
+
...Object.keys(watermarks).length > 0 ? { watermarks } : {},
|
|
838
899
|
blocks
|
|
839
900
|
}]
|
|
840
901
|
};
|
|
841
902
|
}
|
|
842
903
|
function readWpd(bytes, options = {}) {
|
|
843
904
|
const container = require_container_container.openWpdDocument(bytes, { password: options.password });
|
|
844
|
-
const { notes, ...flatRest } = foldTokens(require_stream_tokenise.tokeniseDocumentArea(container.bytes, container.documentAreaOffset, container.documentAreaEnd), container, options.sink ?? require_diagnostics.NOOP_WPD_DIAGNOSTIC_SINK);
|
|
905
|
+
const { notes, oleObjects, ...flatRest } = foldTokens(require_stream_tokenise.tokeniseDocumentArea(container.bytes, container.documentAreaOffset, container.documentAreaEnd), container, options.sink ?? require_diagnostics.NOOP_WPD_DIAGNOSTIC_SINK);
|
|
845
906
|
const document = {
|
|
846
907
|
kind: "wordprocessing",
|
|
847
908
|
metadata: readMetadata(container),
|
|
@@ -858,22 +919,32 @@ function readWpd(bytes, options = {}) {
|
|
|
858
919
|
},
|
|
859
920
|
...Object.keys(flatRest.headers).length > 0 ? { headers: flatRest.headers } : {},
|
|
860
921
|
...Object.keys(flatRest.footers).length > 0 ? { footers: flatRest.footers } : {},
|
|
922
|
+
...Object.keys(flatRest.watermarks).length > 0 ? { watermarks: flatRest.watermarks } : {},
|
|
861
923
|
blocks: flatRest.blocks
|
|
862
924
|
}]
|
|
863
925
|
};
|
|
864
926
|
const assembled = (0, document_schema_js.assembleTree)(document);
|
|
865
|
-
|
|
927
|
+
const attachments = Object.fromEntries(oleObjects.map((oleObject) => [oleObject.name, {
|
|
928
|
+
kind: "attachment",
|
|
929
|
+
name: oleObject.name,
|
|
930
|
+
base64: require_bytes_base64.bytesToBase64(oleObject.bytes)
|
|
931
|
+
}]));
|
|
866
932
|
const definitions = Object.fromEntries(notes.map((note, index) => [`note-${index + 1}`, {
|
|
867
933
|
kind: note.anchorType,
|
|
868
934
|
marker: note.marker,
|
|
869
935
|
blocks: note.blocks
|
|
870
936
|
}]));
|
|
937
|
+
if (Object.keys(attachments).length === 0 && notes.length === 0) return assembled;
|
|
871
938
|
return {
|
|
872
939
|
...assembled,
|
|
873
|
-
|
|
940
|
+
...Object.keys(attachments).length > 0 ? { attachments: {
|
|
941
|
+
...assembled.attachments,
|
|
942
|
+
...attachments
|
|
943
|
+
} } : {},
|
|
944
|
+
...notes.length > 0 ? { definitions: {
|
|
874
945
|
...assembled.definitions,
|
|
875
946
|
...definitions
|
|
876
|
-
}
|
|
947
|
+
} } : {}
|
|
877
948
|
};
|
|
878
949
|
}
|
|
879
950
|
//#endregion
|
package/dist/read.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as WpdDiagnosticSink } from "./diagnostics-
|
|
1
|
+
import { i as WpdDiagnosticSink } from "./diagnostics-fHTFHZ-d.cjs";
|
|
2
2
|
import { ContentBlock, ContentDocument, DocumentTree } from "document-schema.js";
|
|
3
3
|
//#region src/read.d.ts
|
|
4
4
|
interface ReadWpdOptions {
|
package/dist/read.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as WpdDiagnosticSink } from "./diagnostics-
|
|
1
|
+
import { i as WpdDiagnosticSink } from "./diagnostics-fHTFHZ-d.js";
|
|
2
2
|
import { ContentBlock, ContentDocument, DocumentTree } from "document-schema.js";
|
|
3
3
|
//#region src/read.d.ts
|
|
4
4
|
interface ReadWpdOptions {
|
package/dist/read.js
CHANGED
|
@@ -14,7 +14,9 @@ import { findEmbeddedSubfunction, readCellFill, readCellInformation, readCellSpa
|
|
|
14
14
|
import { readBoxContent } from "./stream/box.js";
|
|
15
15
|
import { readTableFormula } from "./stream/formula.js";
|
|
16
16
|
import { scanImagePayload } from "./stream/image.js";
|
|
17
|
+
import { readGraphicsChildIds, readOleObject } from "./stream/ole.js";
|
|
17
18
|
import { tabEffectFor } from "./stream/tab.js";
|
|
19
|
+
import { decodeWpgGraphic } from "./stream/wpg.js";
|
|
18
20
|
import { tokeniseDocumentArea } from "./stream/tokenise.js";
|
|
19
21
|
import { assembleTree } from "document-schema.js";
|
|
20
22
|
//#region src/read.ts
|
|
@@ -436,10 +438,6 @@ function applyCharacterGroup(state, token, container, sink) {
|
|
|
436
438
|
function applyHeaderFooterGroup(state, token, container, sink) {
|
|
437
439
|
const claim = readFurnitureClaim(token.subgroup, token.nonDeletable);
|
|
438
440
|
if (claim === "none") return;
|
|
439
|
-
if (claim === "watermark") {
|
|
440
|
-
reportOnce(state, sink, WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a watermark, which is neither a header nor a footer and owns no parity -- the shared page-furniture vocabulary has no slot for one.");
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
441
|
const slotKey = `${claim.kind}:${claim.slot}`;
|
|
444
442
|
if (state.furnitureFilled.has(slotKey)) {
|
|
445
443
|
reportOnce(state, sink, WpdDiagnosticCodes.HeaderFooterDropped, `This document declares a second ${claim.kind} for the ${claim.slot} slot -- WordPerfect's own A/B two-slot-per-kind mechanism, which the shared one-flow-per-slot page-furniture vocabulary does not carry; the first ${claim.kind} to claim the slot is the one lifted.`);
|
|
@@ -448,19 +446,19 @@ function applyHeaderFooterGroup(state, token, container, sink) {
|
|
|
448
446
|
const blocks = furnitureBodyBlocks(state, token, container, sink);
|
|
449
447
|
if (blocks === void 0) return;
|
|
450
448
|
state.furnitureFilled.add(slotKey);
|
|
451
|
-
const furniture = claim.kind === "header" ? state.headers : state.footers;
|
|
449
|
+
const furniture = claim.kind === "header" ? state.headers : claim.kind === "footer" ? state.footers : state.watermarks;
|
|
452
450
|
furniture[claim.slot] = blocks;
|
|
453
451
|
}
|
|
454
452
|
function furnitureBodyBlocks(state, token, container, sink) {
|
|
455
453
|
const prefixId = token.prefixIds[0];
|
|
456
454
|
const packet = prefixId === void 0 ? void 0 : packetByPrefixId(container.packets, prefixId);
|
|
457
455
|
if (packet?.packetType !== 8) {
|
|
458
|
-
reportOnce(state, sink, WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a header or
|
|
456
|
+
reportOnce(state, sink, WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a header, footer, or watermark whose body packet this reader could not resolve; it was not lifted.");
|
|
459
457
|
return;
|
|
460
458
|
}
|
|
461
459
|
const textBlocks = readGeneralWpTextBlocks(packet.bytes);
|
|
462
460
|
if (textBlocks === void 0) {
|
|
463
|
-
reportOnce(state, sink, WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a header or
|
|
461
|
+
reportOnce(state, sink, WpdDiagnosticCodes.HeaderFooterDropped, "This document declares a header, footer, or watermark whose body packet this reader could not read; it was not lifted.");
|
|
464
462
|
return;
|
|
465
463
|
}
|
|
466
464
|
return foldTokens(tokeniseDocumentArea(textBlocks, 0, textBlocks.length), container, sink).blocks;
|
|
@@ -545,6 +543,16 @@ function applyMergeGroup(state, token, sink) {
|
|
|
545
543
|
function plainTextOf(blocks) {
|
|
546
544
|
return blocks.filter((block) => block.kind === "paragraph").map((paragraph) => paragraph.runs.map((run) => run.text).join("")).join("\n");
|
|
547
545
|
}
|
|
546
|
+
function decodeBoxWpg(container, graphicsPacket, sink) {
|
|
547
|
+
const childIds = readGraphicsChildIds(graphicsPacket);
|
|
548
|
+
if (childIds === void 0) return;
|
|
549
|
+
for (const childId of childIds) {
|
|
550
|
+
const child = packetByPrefixId(container.packets, childId);
|
|
551
|
+
if (child?.packetType !== 111) continue;
|
|
552
|
+
const decoded = decodeWpgGraphic(child.bytes, { foldTextData: (documentArea) => foldTokens(tokeniseDocumentArea(documentArea, 0, documentArea.length), container, sink).blocks });
|
|
553
|
+
if (decoded !== void 0) return decoded;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
548
556
|
function applyBoxGroup(state, token, container, sink) {
|
|
549
557
|
const boxContent = readBoxContent(token.nonDeletable, token.prefixIds);
|
|
550
558
|
if (boxContent === void 0) {
|
|
@@ -555,6 +563,50 @@ function applyBoxGroup(state, token, container, sink) {
|
|
|
555
563
|
const imagePacket = packetByPrefixId(container.packets, boxContent.contentPrefixId);
|
|
556
564
|
const payload = imagePacket === void 0 ? void 0 : scanImagePayload(imagePacket.bytes);
|
|
557
565
|
if (payload === void 0) {
|
|
566
|
+
const ole = imagePacket?.packetType === 64 ? readOleObject(container.packets, imagePacket, container.oleObjectStreams) : void 0;
|
|
567
|
+
if (ole !== void 0) {
|
|
568
|
+
state.oleObjects.push(ole);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
const wpg = imagePacket?.packetType === 64 ? decodeBoxWpg(container, imagePacket, sink) : void 0;
|
|
572
|
+
if (wpg !== void 0) {
|
|
573
|
+
if (wpg.status === "refused") {
|
|
574
|
+
sink({
|
|
575
|
+
code: WpdDiagnosticCodes.WpgRecordsUndecoded,
|
|
576
|
+
message: wpg.reason === "wpg1" ? "This document embeds a WPG 1.0 vector graphic, whose type-and-length record vocabulary predates the framed WPG 2.x stream this reader decodes, so it was not lifted." : wpg.reason === "encrypted" ? "This document embeds an encrypted WPG vector graphic, which this reader does not decrypt, so it was not lifted." : "This document embeds a WPG graphic whose record stream this reader could not walk (no well-formed Start WPG record), so it was not lifted."
|
|
577
|
+
});
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (boxContent.frame === void 0) {
|
|
581
|
+
reportOnce(state, sink, WpdDiagnosticCodes.BoxFrameUnresolved, "This document contains a box whose content this reader could read, but whose function-level override states no width and height this reader can trust, so its content was not lifted.");
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (wpg.skippedRecords.length > 0) sink({
|
|
585
|
+
code: WpdDiagnosticCodes.WpgRecordsUndecoded,
|
|
586
|
+
message: `This document embeds a WPG vector graphic that partially decoded; the following record types were skipped: ${wpg.skippedRecords.join(", ")}.`
|
|
587
|
+
});
|
|
588
|
+
flushParagraphIfContent(state, sink);
|
|
589
|
+
targetBlocks(state).push({
|
|
590
|
+
kind: "embeddedObject",
|
|
591
|
+
objectKind: "drawing",
|
|
592
|
+
frame: {
|
|
593
|
+
xPt: boxContent.frame.xPt,
|
|
594
|
+
yPt: boxContent.frame.yPt,
|
|
595
|
+
widthPt: boxContent.frame.widthPt,
|
|
596
|
+
heightPt: boxContent.frame.heightPt
|
|
597
|
+
},
|
|
598
|
+
document: {
|
|
599
|
+
kind: "drawing",
|
|
600
|
+
metadata: {},
|
|
601
|
+
pages: [{
|
|
602
|
+
size: wpg.sizePt,
|
|
603
|
+
shapes: [...wpg.shapes],
|
|
604
|
+
vectors: [...wpg.vectors]
|
|
605
|
+
}]
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
558
610
|
reportOnce(state, sink, WpdDiagnosticCodes.BoxContentUnresolved, "This document contains an image box whose content packet carries no decodable PNG or JPEG payload -- a WPG graphic or other image spelling this reader does not decode.");
|
|
559
611
|
return;
|
|
560
612
|
}
|
|
@@ -787,9 +839,11 @@ function foldTokens(tokens, container, sink) {
|
|
|
787
839
|
openMergeFieldStartRun: void 0,
|
|
788
840
|
headers: {},
|
|
789
841
|
footers: {},
|
|
842
|
+
watermarks: {},
|
|
790
843
|
furnitureFilled: /* @__PURE__ */ new Set(),
|
|
791
844
|
openNote: void 0,
|
|
792
|
-
notes: []
|
|
845
|
+
notes: [],
|
|
846
|
+
oleObjects: []
|
|
793
847
|
};
|
|
794
848
|
for (const token of tokens) applyToken(state, token, container, sink);
|
|
795
849
|
flushRun(state);
|
|
@@ -803,7 +857,9 @@ function foldTokens(tokens, container, sink) {
|
|
|
803
857
|
page: state.page,
|
|
804
858
|
headers: state.headers,
|
|
805
859
|
footers: state.footers,
|
|
806
|
-
|
|
860
|
+
watermarks: state.watermarks,
|
|
861
|
+
notes: state.notes,
|
|
862
|
+
oleObjects: state.oleObjects
|
|
807
863
|
};
|
|
808
864
|
}
|
|
809
865
|
function readMetadata(container) {
|
|
@@ -813,11 +869,15 @@ function readMetadata(container) {
|
|
|
813
869
|
function readWpdContent(bytes, options = {}) {
|
|
814
870
|
const sink = options.sink ?? NOOP_WPD_DIAGNOSTIC_SINK;
|
|
815
871
|
const container = openWpdDocument(bytes, { password: options.password });
|
|
816
|
-
const { blocks, page, headers, footers, notes } = foldTokens(tokeniseDocumentArea(container.bytes, container.documentAreaOffset, container.documentAreaEnd), container, sink);
|
|
872
|
+
const { blocks, page, headers, footers, watermarks, notes, oleObjects } = foldTokens(tokeniseDocumentArea(container.bytes, container.documentAreaOffset, container.documentAreaEnd), container, sink);
|
|
817
873
|
for (const note of notes) sink({
|
|
818
874
|
code: WpdDiagnosticCodes.NoteDropped,
|
|
819
875
|
message: `This document contains a ${note.anchorType} whose body the flat ContentDocument has no home for; its reference anchor survives and readWpd lifts the body into the tree form's definitions table.`
|
|
820
876
|
});
|
|
877
|
+
for (const oleObject of oleObjects) sink({
|
|
878
|
+
code: WpdDiagnosticCodes.OleObjectDropped,
|
|
879
|
+
message: `This document embeds a native OLE object ('${oleObject.name}') whose bytes the flat ContentDocument has no home for; readWpd lifts them into the tree form's attachments table.`
|
|
880
|
+
});
|
|
821
881
|
return {
|
|
822
882
|
kind: "wordprocessing",
|
|
823
883
|
metadata: readMetadata(container),
|
|
@@ -834,13 +894,14 @@ function readWpdContent(bytes, options = {}) {
|
|
|
834
894
|
},
|
|
835
895
|
...Object.keys(headers).length > 0 ? { headers } : {},
|
|
836
896
|
...Object.keys(footers).length > 0 ? { footers } : {},
|
|
897
|
+
...Object.keys(watermarks).length > 0 ? { watermarks } : {},
|
|
837
898
|
blocks
|
|
838
899
|
}]
|
|
839
900
|
};
|
|
840
901
|
}
|
|
841
902
|
function readWpd(bytes, options = {}) {
|
|
842
903
|
const container = openWpdDocument(bytes, { password: options.password });
|
|
843
|
-
const { notes, ...flatRest } = foldTokens(tokeniseDocumentArea(container.bytes, container.documentAreaOffset, container.documentAreaEnd), container, options.sink ?? NOOP_WPD_DIAGNOSTIC_SINK);
|
|
904
|
+
const { notes, oleObjects, ...flatRest } = foldTokens(tokeniseDocumentArea(container.bytes, container.documentAreaOffset, container.documentAreaEnd), container, options.sink ?? NOOP_WPD_DIAGNOSTIC_SINK);
|
|
844
905
|
const document = {
|
|
845
906
|
kind: "wordprocessing",
|
|
846
907
|
metadata: readMetadata(container),
|
|
@@ -857,22 +918,32 @@ function readWpd(bytes, options = {}) {
|
|
|
857
918
|
},
|
|
858
919
|
...Object.keys(flatRest.headers).length > 0 ? { headers: flatRest.headers } : {},
|
|
859
920
|
...Object.keys(flatRest.footers).length > 0 ? { footers: flatRest.footers } : {},
|
|
921
|
+
...Object.keys(flatRest.watermarks).length > 0 ? { watermarks: flatRest.watermarks } : {},
|
|
860
922
|
blocks: flatRest.blocks
|
|
861
923
|
}]
|
|
862
924
|
};
|
|
863
925
|
const assembled = assembleTree(document);
|
|
864
|
-
|
|
926
|
+
const attachments = Object.fromEntries(oleObjects.map((oleObject) => [oleObject.name, {
|
|
927
|
+
kind: "attachment",
|
|
928
|
+
name: oleObject.name,
|
|
929
|
+
base64: bytesToBase64(oleObject.bytes)
|
|
930
|
+
}]));
|
|
865
931
|
const definitions = Object.fromEntries(notes.map((note, index) => [`note-${index + 1}`, {
|
|
866
932
|
kind: note.anchorType,
|
|
867
933
|
marker: note.marker,
|
|
868
934
|
blocks: note.blocks
|
|
869
935
|
}]));
|
|
936
|
+
if (Object.keys(attachments).length === 0 && notes.length === 0) return assembled;
|
|
870
937
|
return {
|
|
871
938
|
...assembled,
|
|
872
|
-
|
|
939
|
+
...Object.keys(attachments).length > 0 ? { attachments: {
|
|
940
|
+
...assembled.attachments,
|
|
941
|
+
...attachments
|
|
942
|
+
} } : {},
|
|
943
|
+
...notes.length > 0 ? { definitions: {
|
|
873
944
|
...assembled.definitions,
|
|
874
945
|
...definitions
|
|
875
|
-
}
|
|
946
|
+
} } : {}
|
|
876
947
|
};
|
|
877
948
|
}
|
|
878
949
|
//#endregion
|
|
@@ -10,8 +10,7 @@ const WATERMARK_B = 5;
|
|
|
10
10
|
const OCCURS_ON_ODD = 1;
|
|
11
11
|
const OCCURS_ON_EVEN = 2;
|
|
12
12
|
function readFurnitureClaim(subgroup, nonDeletable) {
|
|
13
|
-
|
|
14
|
-
const kind = subgroup === 0 || subgroup === 1 ? "header" : subgroup === 2 || subgroup === 3 ? "footer" : void 0;
|
|
13
|
+
const kind = subgroup === 0 || subgroup === 1 ? "header" : subgroup === 2 || subgroup === 3 ? "footer" : subgroup === 4 || subgroup === 5 ? "watermark" : void 0;
|
|
15
14
|
if (kind === void 0) return "none";
|
|
16
15
|
const occurrence = nonDeletable[0] ?? 0;
|
|
17
16
|
const odd = (occurrence & OCCURS_ON_ODD) !== 0;
|
|
@@ -7,9 +7,9 @@ declare const FOOTER_B = 3;
|
|
|
7
7
|
declare const WATERMARK_A = 4;
|
|
8
8
|
declare const WATERMARK_B = 5;
|
|
9
9
|
interface WpdFurnitureClaim {
|
|
10
|
-
readonly kind: "header" | "footer";
|
|
10
|
+
readonly kind: "header" | "footer" | "watermark";
|
|
11
11
|
readonly slot: "default" | "even";
|
|
12
12
|
}
|
|
13
|
-
declare function readFurnitureClaim(subgroup: number, nonDeletable: Uint8Array): WpdFurnitureClaim | "
|
|
13
|
+
declare function readFurnitureClaim(subgroup: number, nonDeletable: Uint8Array): WpdFurnitureClaim | "none";
|
|
14
14
|
//#endregion
|
|
15
15
|
export { FOOTER_A, FOOTER_B, HEADER_A, HEADER_B, HEADER_FOOTER_GROUP, WATERMARK_A, WATERMARK_B, WpdFurnitureClaim, readFurnitureClaim };
|
|
@@ -7,9 +7,9 @@ declare const FOOTER_B = 3;
|
|
|
7
7
|
declare const WATERMARK_A = 4;
|
|
8
8
|
declare const WATERMARK_B = 5;
|
|
9
9
|
interface WpdFurnitureClaim {
|
|
10
|
-
readonly kind: "header" | "footer";
|
|
10
|
+
readonly kind: "header" | "footer" | "watermark";
|
|
11
11
|
readonly slot: "default" | "even";
|
|
12
12
|
}
|
|
13
|
-
declare function readFurnitureClaim(subgroup: number, nonDeletable: Uint8Array): WpdFurnitureClaim | "
|
|
13
|
+
declare function readFurnitureClaim(subgroup: number, nonDeletable: Uint8Array): WpdFurnitureClaim | "none";
|
|
14
14
|
//#endregion
|
|
15
15
|
export { FOOTER_A, FOOTER_B, HEADER_A, HEADER_B, HEADER_FOOTER_GROUP, WATERMARK_A, WATERMARK_B, WpdFurnitureClaim, readFurnitureClaim };
|
package/dist/stream/furniture.js
CHANGED
|
@@ -9,8 +9,7 @@ const WATERMARK_B = 5;
|
|
|
9
9
|
const OCCURS_ON_ODD = 1;
|
|
10
10
|
const OCCURS_ON_EVEN = 2;
|
|
11
11
|
function readFurnitureClaim(subgroup, nonDeletable) {
|
|
12
|
-
|
|
13
|
-
const kind = subgroup === 0 || subgroup === 1 ? "header" : subgroup === 2 || subgroup === 3 ? "footer" : void 0;
|
|
12
|
+
const kind = subgroup === 0 || subgroup === 1 ? "header" : subgroup === 2 || subgroup === 3 ? "footer" : subgroup === 4 || subgroup === 5 ? "watermark" : void 0;
|
|
14
13
|
if (kind === void 0) return "none";
|
|
15
14
|
const occurrence = nonDeletable[0] ?? 0;
|
|
16
15
|
const odd = (occurrence & OCCURS_ON_ODD) !== 0;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_bytes_view = require("../bytes/view.cjs");
|
|
3
|
+
const require_stream_characters = require("./characters.cjs");
|
|
4
|
+
const require_container_prefix = require("../container/prefix.cjs");
|
|
5
|
+
//#region src/stream/ole.ts
|
|
6
|
+
const PACKET_TYPE_GRAPHICS_FILENAME = 64;
|
|
7
|
+
const PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA = 111;
|
|
8
|
+
const PACKET_TYPE_OLE_OBJECT_DESCRIPTOR = 112;
|
|
9
|
+
const PACKET_TYPE_OLE_OBJECT_DATA = 113;
|
|
10
|
+
const PACKET_FLAG_CHILD_IDS = 1;
|
|
11
|
+
const OLE2_MARKER = "WPWin7.0/OLE 2.0 Prefix Information Marker";
|
|
12
|
+
const OLE1_MARKER = "WPWin6.0/OLE 1.0 Prefix Information Marker";
|
|
13
|
+
function readGraphicsChildIds(packet) {
|
|
14
|
+
if ((packet.flags & PACKET_FLAG_CHILD_IDS) === 0) return;
|
|
15
|
+
if (packet.bytes.length < 2) return;
|
|
16
|
+
const count = require_bytes_view.uint16At(packet.bytes, 0);
|
|
17
|
+
if (2 + count * 2 > packet.bytes.length) return;
|
|
18
|
+
const childIds = [];
|
|
19
|
+
for (let index = 0; index < count; index += 1) childIds.push(require_bytes_view.uint16At(packet.bytes, 2 + index * 2));
|
|
20
|
+
return childIds;
|
|
21
|
+
}
|
|
22
|
+
function readOleDescriptor(bytes) {
|
|
23
|
+
const payloadOffset = 64;
|
|
24
|
+
if (bytes.length < payloadOffset) return;
|
|
25
|
+
let marker = "";
|
|
26
|
+
for (let index = 0; index < 42; index += 1) marker += String.fromCharCode(require_bytes_view.byteAt(bytes, index));
|
|
27
|
+
if (marker === OLE2_MARKER) {
|
|
28
|
+
const { text } = require_stream_characters.decodeWordString(bytes, payloadOffset, (bytes.length - payloadOffset) / 2);
|
|
29
|
+
if (text.length === 0) return;
|
|
30
|
+
return {
|
|
31
|
+
ole2: true,
|
|
32
|
+
streamName: text
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (marker === OLE1_MARKER) return {
|
|
36
|
+
ole2: false,
|
|
37
|
+
objectNumber: require_bytes_view.uint32At(bytes, 60)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function readOleObject(packets, graphicsPacket, oleObjectStreams) {
|
|
41
|
+
const childIds = readGraphicsChildIds(graphicsPacket);
|
|
42
|
+
if (childIds === void 0) return;
|
|
43
|
+
for (const childId of childIds) {
|
|
44
|
+
const child = require_container_prefix.packetByPrefixId(packets, childId);
|
|
45
|
+
if (child?.packetType !== 112) continue;
|
|
46
|
+
const descriptor = readOleDescriptor(child.bytes);
|
|
47
|
+
if (descriptor === void 0) return;
|
|
48
|
+
const payloadOffset = 64;
|
|
49
|
+
if (descriptor.ole2) {
|
|
50
|
+
const streamBytes = oleObjectStreams.get(descriptor.streamName);
|
|
51
|
+
if (streamBytes === void 0) return;
|
|
52
|
+
return {
|
|
53
|
+
name: descriptor.streamName,
|
|
54
|
+
bytes: streamBytes
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (child.bytes.length <= payloadOffset) return;
|
|
58
|
+
return {
|
|
59
|
+
name: `ole1-${String(descriptor.objectNumber)}`,
|
|
60
|
+
bytes: child.bytes.subarray(payloadOffset)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
exports.PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA = PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA;
|
|
66
|
+
exports.PACKET_TYPE_GRAPHICS_FILENAME = PACKET_TYPE_GRAPHICS_FILENAME;
|
|
67
|
+
exports.PACKET_TYPE_OLE_OBJECT_DATA = PACKET_TYPE_OLE_OBJECT_DATA;
|
|
68
|
+
exports.PACKET_TYPE_OLE_OBJECT_DESCRIPTOR = PACKET_TYPE_OLE_OBJECT_DESCRIPTOR;
|
|
69
|
+
exports.readGraphicsChildIds = readGraphicsChildIds;
|
|
70
|
+
exports.readOleDescriptor = readOleDescriptor;
|
|
71
|
+
exports.readOleObject = readOleObject;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WpdPrefixPacket } from "../container/prefix.cjs";
|
|
2
|
+
//#region src/stream/ole.d.ts
|
|
3
|
+
declare const PACKET_TYPE_GRAPHICS_FILENAME = 64;
|
|
4
|
+
declare const PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA = 111;
|
|
5
|
+
declare const PACKET_TYPE_OLE_OBJECT_DESCRIPTOR = 112;
|
|
6
|
+
declare const PACKET_TYPE_OLE_OBJECT_DATA = 113;
|
|
7
|
+
type WpdOleDescriptor = {
|
|
8
|
+
readonly ole2: true;
|
|
9
|
+
readonly streamName: string;
|
|
10
|
+
} | {
|
|
11
|
+
readonly ole2: false;
|
|
12
|
+
readonly objectNumber: number;
|
|
13
|
+
};
|
|
14
|
+
interface WpdOleObject {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly bytes: Uint8Array;
|
|
17
|
+
}
|
|
18
|
+
declare function readGraphicsChildIds(packet: WpdPrefixPacket): number[] | undefined;
|
|
19
|
+
declare function readOleDescriptor(bytes: Uint8Array): WpdOleDescriptor | undefined;
|
|
20
|
+
declare function readOleObject(packets: readonly WpdPrefixPacket[], graphicsPacket: WpdPrefixPacket, oleObjectStreams: ReadonlyMap<string, Uint8Array>): WpdOleObject | undefined;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA, PACKET_TYPE_GRAPHICS_FILENAME, PACKET_TYPE_OLE_OBJECT_DATA, PACKET_TYPE_OLE_OBJECT_DESCRIPTOR, WpdOleDescriptor, WpdOleObject, readGraphicsChildIds, readOleDescriptor, readOleObject };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WpdPrefixPacket } from "../container/prefix.js";
|
|
2
|
+
//#region src/stream/ole.d.ts
|
|
3
|
+
declare const PACKET_TYPE_GRAPHICS_FILENAME = 64;
|
|
4
|
+
declare const PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA = 111;
|
|
5
|
+
declare const PACKET_TYPE_OLE_OBJECT_DESCRIPTOR = 112;
|
|
6
|
+
declare const PACKET_TYPE_OLE_OBJECT_DATA = 113;
|
|
7
|
+
type WpdOleDescriptor = {
|
|
8
|
+
readonly ole2: true;
|
|
9
|
+
readonly streamName: string;
|
|
10
|
+
} | {
|
|
11
|
+
readonly ole2: false;
|
|
12
|
+
readonly objectNumber: number;
|
|
13
|
+
};
|
|
14
|
+
interface WpdOleObject {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly bytes: Uint8Array;
|
|
17
|
+
}
|
|
18
|
+
declare function readGraphicsChildIds(packet: WpdPrefixPacket): number[] | undefined;
|
|
19
|
+
declare function readOleDescriptor(bytes: Uint8Array): WpdOleDescriptor | undefined;
|
|
20
|
+
declare function readOleObject(packets: readonly WpdPrefixPacket[], graphicsPacket: WpdPrefixPacket, oleObjectStreams: ReadonlyMap<string, Uint8Array>): WpdOleObject | undefined;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA, PACKET_TYPE_GRAPHICS_FILENAME, PACKET_TYPE_OLE_OBJECT_DATA, PACKET_TYPE_OLE_OBJECT_DESCRIPTOR, WpdOleDescriptor, WpdOleObject, readGraphicsChildIds, readOleDescriptor, readOleObject };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { byteAt, uint16At, uint32At } from "../bytes/view.js";
|
|
2
|
+
import { decodeWordString } from "./characters.js";
|
|
3
|
+
import { packetByPrefixId } from "../container/prefix.js";
|
|
4
|
+
//#region src/stream/ole.ts
|
|
5
|
+
const PACKET_TYPE_GRAPHICS_FILENAME = 64;
|
|
6
|
+
const PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA = 111;
|
|
7
|
+
const PACKET_TYPE_OLE_OBJECT_DESCRIPTOR = 112;
|
|
8
|
+
const PACKET_TYPE_OLE_OBJECT_DATA = 113;
|
|
9
|
+
const PACKET_FLAG_CHILD_IDS = 1;
|
|
10
|
+
const OLE2_MARKER = "WPWin7.0/OLE 2.0 Prefix Information Marker";
|
|
11
|
+
const OLE1_MARKER = "WPWin6.0/OLE 1.0 Prefix Information Marker";
|
|
12
|
+
function readGraphicsChildIds(packet) {
|
|
13
|
+
if ((packet.flags & PACKET_FLAG_CHILD_IDS) === 0) return;
|
|
14
|
+
if (packet.bytes.length < 2) return;
|
|
15
|
+
const count = uint16At(packet.bytes, 0);
|
|
16
|
+
if (2 + count * 2 > packet.bytes.length) return;
|
|
17
|
+
const childIds = [];
|
|
18
|
+
for (let index = 0; index < count; index += 1) childIds.push(uint16At(packet.bytes, 2 + index * 2));
|
|
19
|
+
return childIds;
|
|
20
|
+
}
|
|
21
|
+
function readOleDescriptor(bytes) {
|
|
22
|
+
const payloadOffset = 64;
|
|
23
|
+
if (bytes.length < payloadOffset) return;
|
|
24
|
+
let marker = "";
|
|
25
|
+
for (let index = 0; index < 42; index += 1) marker += String.fromCharCode(byteAt(bytes, index));
|
|
26
|
+
if (marker === OLE2_MARKER) {
|
|
27
|
+
const { text } = decodeWordString(bytes, payloadOffset, (bytes.length - payloadOffset) / 2);
|
|
28
|
+
if (text.length === 0) return;
|
|
29
|
+
return {
|
|
30
|
+
ole2: true,
|
|
31
|
+
streamName: text
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (marker === OLE1_MARKER) return {
|
|
35
|
+
ole2: false,
|
|
36
|
+
objectNumber: uint32At(bytes, 60)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function readOleObject(packets, graphicsPacket, oleObjectStreams) {
|
|
40
|
+
const childIds = readGraphicsChildIds(graphicsPacket);
|
|
41
|
+
if (childIds === void 0) return;
|
|
42
|
+
for (const childId of childIds) {
|
|
43
|
+
const child = packetByPrefixId(packets, childId);
|
|
44
|
+
if (child?.packetType !== 112) continue;
|
|
45
|
+
const descriptor = readOleDescriptor(child.bytes);
|
|
46
|
+
if (descriptor === void 0) return;
|
|
47
|
+
const payloadOffset = 64;
|
|
48
|
+
if (descriptor.ole2) {
|
|
49
|
+
const streamBytes = oleObjectStreams.get(descriptor.streamName);
|
|
50
|
+
if (streamBytes === void 0) return;
|
|
51
|
+
return {
|
|
52
|
+
name: descriptor.streamName,
|
|
53
|
+
bytes: streamBytes
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (child.bytes.length <= payloadOffset) return;
|
|
57
|
+
return {
|
|
58
|
+
name: `ole1-${String(descriptor.objectNumber)}`,
|
|
59
|
+
bytes: child.bytes.subarray(payloadOffset)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { PACKET_TYPE_GRAPHICS_CACHED_FILE_DATA, PACKET_TYPE_GRAPHICS_FILENAME, PACKET_TYPE_OLE_OBJECT_DATA, PACKET_TYPE_OLE_OBJECT_DESCRIPTOR, readGraphicsChildIds, readOleDescriptor, readOleObject };
|