wpd-codec 3.4.6 → 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.
Files changed (38) hide show
  1. package/README.md +31 -27
  2. package/dist/container/container.cjs +12 -5
  3. package/dist/container/container.d.cts +2 -1
  4. package/dist/container/container.d.ts +2 -1
  5. package/dist/container/container.js +12 -5
  6. package/dist/container/encryption.d.cts +1 -1
  7. package/dist/container/encryption.d.ts +1 -1
  8. package/dist/container/header.d.cts +1 -19
  9. package/dist/container/header.d.ts +1 -19
  10. package/dist/container/prefix.d.cts +1 -1
  11. package/dist/container/prefix.d.ts +1 -1
  12. package/dist/{diagnostics-DhO7mgqJ.d.cts → diagnostics-fHTFHZ-d.d.cts} +2 -0
  13. package/dist/{diagnostics-DhO7mgqJ.d.ts → diagnostics-fHTFHZ-d.d.ts} +2 -0
  14. package/dist/diagnostics.cjs +2 -0
  15. package/dist/diagnostics.d.cts +1 -1
  16. package/dist/diagnostics.d.ts +1 -1
  17. package/dist/diagnostics.js +2 -0
  18. package/dist/header-Ca8QZVe3.d.cts +20 -0
  19. package/dist/header-Ca8QZVe3.d.ts +20 -0
  20. package/dist/index.d.cts +2 -2
  21. package/dist/index.d.ts +2 -2
  22. package/dist/read.cjs +85 -14
  23. package/dist/read.d.cts +1 -1
  24. package/dist/read.d.ts +1 -1
  25. package/dist/read.js +85 -14
  26. package/dist/stream/furniture.cjs +1 -2
  27. package/dist/stream/furniture.d.cts +2 -2
  28. package/dist/stream/furniture.d.ts +2 -2
  29. package/dist/stream/furniture.js +1 -2
  30. package/dist/stream/ole.cjs +71 -0
  31. package/dist/stream/ole.d.cts +22 -0
  32. package/dist/stream/ole.d.ts +22 -0
  33. package/dist/stream/ole.js +64 -0
  34. package/dist/stream/wpg.cjs +620 -0
  35. package/dist/stream/wpg.d.cts +18 -0
  36. package/dist/stream/wpg.d.ts +18 -0
  37. package/dist/stream/wpg.js +619 -0
  38. 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 footer whose body packet this reader could not resolve; it was not lifted.");
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 footer whose body packet this reader could not read; it was not lifted.");
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
- notes: state.notes
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
- if (notes.length === 0) return assembled;
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
- definitions: {
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-DhO7mgqJ.cjs";
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-DhO7mgqJ.js";
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 footer whose body packet this reader could not resolve; it was not lifted.");
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 footer whose body packet this reader could not read; it was not lifted.");
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
- notes: state.notes
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
- if (notes.length === 0) return assembled;
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
- definitions: {
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
- if (subgroup === 4 || subgroup === 5) return "watermark";
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 | "watermark" | "none";
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 | "watermark" | "none";
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 };
@@ -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
- if (subgroup === 4 || subgroup === 5) return "watermark";
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 };