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/README.md CHANGED
@@ -77,28 +77,30 @@ Structural nonconformance is not a diagnostic — it throws. `WpdNotAWordPerfect
77
77
 
78
78
  Every module is importable by package-relative path as well as through the barrel — `tsdown` builds one dist file per src module (`root: 'src'`, the layout `archive-codec` and `ooxml.js` also ship), and `package.json`'s `./*` exports wildcard maps each subpath onto it. The smoke suite is the guard on that advertisement: it loads each module below from the built `dist/` in both module systems.
79
79
 
80
- | Module | Exports |
81
- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
82
- | `read` | `readWpdContent` (bytes to `ContentDocument`), `readWpd` (bytes to `DocumentTree`), `ReadWpdOptions` |
83
- | `codec` | `wpdContentCodec` (`ContentCodec`), `WpdBytesSchema` |
84
- | `format` | `WPD_MEDIA_TYPE`, `WPD_FILE_EXTENSION` |
85
- | `diagnostics` | `WpdDiagnostic`, `WpdDiagnosticSink`, `WpdDiagnosticCodes`, `NOOP_WPD_DIAGNOSTIC_SINK` |
86
- | `errors` | `WpdFormatError` and its three subclasses |
87
- | `container/container` | `openWpdDocument` (container, header, packets, and document-area bounds in one), `PERFECT_OFFICE_MAIN_STREAM`, `PERFECT_OFFICE_OBJECTS_STORAGE` |
88
- | `container/header` | `readFileHeader`, `hasWordPerfectFileId`, `WPD_FILE_ID`, `WPD_PREFIX_HEADER_SIZE` |
89
- | `container/prefix` | `readPrefixPackets`, `packetByPrefixId`, `readTypefaceName`, `readGeneralWpTextBlocks`, `WPD_INDEX_RECORD_SIZE`, `PACKET_TYPE_DESIRED_FONT_DESCRIPTOR`, `PACKET_TYPE_GENERAL_WP_TEXT` |
90
- | `container/summary` | `readDocumentSummary` (the Extended Document Summary packet as a `LayoutMetadata`), `PACKET_TYPE_EXTENDED_DOCUMENT_SUMMARY` |
91
- | `stream/tokenise` | `tokeniseDocumentArea` and the four token types |
92
- | `stream/characters` | `decodeWpCharacter`, `decodeSingleByteCharacter`, `decodeWordString`, `UNMAPPED_CHARACTER` |
93
- | `stream/eol` | `eolMappingForSubfunction`, `subfunctionForSingleByteEol`, `isSingleByteEol` |
94
- | `stream/attributes` | `decodeAttributeByte`, `runAttributesFrom`, `WpdAttribute` |
95
- | `stream/units` | `pointsFromWpu`, `WPU_PER_INCH`, `POINTS_PER_INCH` |
96
- | `stream/page` | `readPageForm`, `readMarginPt`, the Page and Column group constants, and the WordPerfect default page |
97
- | `stream/style` | `styleSemanticsFor`, `readSystemStyleNumber`, `readStyleBeginBlock`, the style scope predicates, `PACKET_TYPE_NORMAL_STYLE`, and the Display Number group's paragraph-number pair |
98
- | `stream/table` | `readEmbeddedSubfunctions`, `readTableColumnWidthPt`, `readRowInformation`, `readCellInformation`, `readCellSpanning`, `readCellFill`, `CELL_FORMULA_SUBFUNCTION` |
99
- | `stream/formula` | `readTableFormula` (a New Cell Formula embedded subfunction's own tokenised formula to its own linear text) |
100
- | `stream/box` | `readBoxContent` (a box function's own override-flag walk to its content type, content prefix ID, and frame), the box content type constants |
101
- | `stream/tab` | `tabEffectFor`, `TAB_GROUP`, `WpdTabEffect` |
80
+ | Module | Exports |
81
+ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
82
+ | `read` | `readWpdContent` (bytes to `ContentDocument`), `readWpd` (bytes to `DocumentTree`), `ReadWpdOptions` |
83
+ | `codec` | `wpdContentCodec` (`ContentCodec`), `WpdBytesSchema` |
84
+ | `format` | `WPD_MEDIA_TYPE`, `WPD_FILE_EXTENSION` |
85
+ | `diagnostics` | `WpdDiagnostic`, `WpdDiagnosticSink`, `WpdDiagnosticCodes`, `NOOP_WPD_DIAGNOSTIC_SINK` |
86
+ | `errors` | `WpdFormatError` and its three subclasses |
87
+ | `container/container` | `openWpdDocument` (container, header, packets, and document-area bounds in one), `PERFECT_OFFICE_MAIN_STREAM`, `PERFECT_OFFICE_OBJECTS_STORAGE` |
88
+ | `container/header` | `readFileHeader`, `hasWordPerfectFileId`, `WPD_FILE_ID`, `WPD_PREFIX_HEADER_SIZE` |
89
+ | `container/prefix` | `readPrefixPackets`, `packetByPrefixId`, `readTypefaceName`, `readGeneralWpTextBlocks`, `WPD_INDEX_RECORD_SIZE`, `PACKET_TYPE_DESIRED_FONT_DESCRIPTOR`, `PACKET_TYPE_GENERAL_WP_TEXT` |
90
+ | `container/summary` | `readDocumentSummary` (the Extended Document Summary packet as a `LayoutMetadata`), `PACKET_TYPE_EXTENDED_DOCUMENT_SUMMARY` |
91
+ | `stream/tokenise` | `tokeniseDocumentArea` and the four token types |
92
+ | `stream/characters` | `decodeWpCharacter`, `decodeSingleByteCharacter`, `decodeWordString`, `UNMAPPED_CHARACTER` |
93
+ | `stream/eol` | `eolMappingForSubfunction`, `subfunctionForSingleByteEol`, `isSingleByteEol` |
94
+ | `stream/attributes` | `decodeAttributeByte`, `runAttributesFrom`, `WpdAttribute` |
95
+ | `stream/units` | `pointsFromWpu`, `WPU_PER_INCH`, `POINTS_PER_INCH` |
96
+ | `stream/page` | `readPageForm`, `readMarginPt`, the Page and Column group constants, and the WordPerfect default page |
97
+ | `stream/style` | `styleSemanticsFor`, `readSystemStyleNumber`, `readStyleBeginBlock`, the style scope predicates, `PACKET_TYPE_NORMAL_STYLE`, and the Display Number group's paragraph-number pair |
98
+ | `stream/table` | `readEmbeddedSubfunctions`, `readTableColumnWidthPt`, `readRowInformation`, `readCellInformation`, `readCellSpanning`, `readCellFill`, `CELL_FORMULA_SUBFUNCTION` |
99
+ | `stream/formula` | `readTableFormula` (a New Cell Formula embedded subfunction's own tokenised formula to its own linear text) |
100
+ | `stream/box` | `readBoxContent` (a box function's own override-flag walk to its content type, content prefix ID, and frame), the box content type constants |
101
+ | `stream/tab` | `tabEffectFor`, `TAB_GROUP`, `WpdTabEffect` |
102
+ | `stream/ole` | `readOleObject`, `readOleDescriptor`, `readGraphicsChildIds`, `WpdOleObject`, and the Graphics Filename child packet constants (cached file data `0x6F`, OLE Object Descriptor `0x70`, OLE Object Data `0x71`) |
103
+ | `stream/wpg` | `decodeWpgGraphic` (a WPG 2.x record stream to the shared drawing vocabulary, with the WP-text fold injected by the caller), `WpgDecode`, `WpgTextFold` |
102
104
 
103
105
  The container and stream layers are public deliberately, not by accident: a consumer inspecting a WordPerfect file — a migration audit, a forensic tool, a reader for a construct this package does not yet lift into the shared schema — needs the parsed prefix and the raw function stream, not only the document they fold into.
104
106
 
@@ -168,20 +170,22 @@ This is a bet against libwpd's _code_, not against citing its _data_: the charac
168
170
  - **Style packets** (the 0xDD group's own type-0x30 definitions), beyond their system style numbers: a style scope opened with a prefix ID resolves that packet and applies its own "beginning style text" block — font face/size/colour changes, attribute on/off — exactly as if the author had typed those codes at the point the scope opened, restoring the pre-scope formatting when the scope closes. See `src/stream/style.ts`'s own `readStyleBeginBlock`.
169
171
  - **Boxes** whose content resolves to a General WP Text packet (type 0x08): a text or linked-text box lifts into an embedded `wordprocessing` document (`ContentEmbeddedObjectBlock`), read through the identical tokeniser and fold the main document area uses; an equation box's own notation — WordPerfect's own equation-editor syntax, neither MathML nor LaTeX — is carried verbatim as `ContentFormula`'s quarantined residue (`source: { format: 'wpd', xml }`) rather than mistranslated into either. A box's real content is always named by its own function-level override (the box override-flag walk in `src/stream/box.ts`), never by its template, so a box with no content override genuinely has nothing to lift. Frame position and size are read from that same override when it states an absolute page-space offset and an explicit width/height; a box relying on its template's own inherited geometry is not lifted (see Remaining scope).
170
172
  - **Merge fields** (the Merge group's FIELD On/Off pair, 0xDE 0x4C/0x4D): tagged as a `field` construct (document-schema.js's `RunConstructExtent`/`FieldDescriptor`) on the paragraph the field sits in, `instruction` being the field's own displayed placeholder text — which stays in the run flow exactly as WordPerfect itself displays a template's own field codes, now tagged as a placeholder rather than indistinguishable prose.
173
+ - **Native OLE objects** (an image box's Graphics Filename packet children, `0x70` OLE Object Descriptor / `0x71` OLE Object Data). The descriptor's own marker states the generation: a WP7 "OLE 2.0" object's wordstring names a stream inside the compound wrapper's `PerfectOffice_OBJECTS` storage, which the container collects and the read resolves; a WP6 "OLE 1.0" object carries all of its data inline in the descriptor packet's own trailing bytes, which works in a bare file with no wrapper at all. The bytes are carried, not interpreted — a native OLE payload is an OLE server's own stream rather than a nested document package — with `readWpd` carrying one as an attachments-table entry (the identical flat/tree split note bodies take, and the entry vocabulary documents.js stamps PDF embedded files with) while flat `readWpdContent` reports it through `wpd/ole-object-dropped`. The undocumented `0x71` data packet is skipped and named rather than guessed at.
174
+ - **Watermarks** (the 0xD6 group's A/B watermark subfunctions): page furniture with a parity, not a band at a page edge. They share the header/footer function layout and narrow onto the shared furniture vocabulary the same way — odd-only or both parities the default slot, even-only the even slot (`ContentSection.watermarks`) — with the body folded through the identical nested fold a header's takes, first claimant per slot, and a slot collision reported through `wpd/header-footer-dropped` exactly as a colliding header's is.
175
+ - **WPG vector graphics** (a Graphics Filename packet's `0x6F` cached-file-data children): a WPG 2.x record stream decodes into the shared drawing vocabulary and lifts as a one-page `drawing` document (`ContentEmbeddedObjectBlock`) placed by the box's own frame. What decodes is the layered subset `src/stream/wpg.ts`'s own scope statement names: the record framing itself (Class/Type/Extension/Length with the 1/3/5-byte count fields), Start WPG (the units, precision, and extent every coordinate conversion needs), the flat pen and brush colour and pen-size attributes with their double-precision variants, Polyline (two unclosed points as the model's own line variant, more points or a closed one as a path), Rectangle (square corners as a rect, rounded corners as a path of kappa-approximated quarter-ellipses), an Arc with identical endpoint offsets (the full ellipse the specification itself defines that spelling to mean), and a Text Block with its Text Data folded through the same tokeniser and fold body text takes. Everything else a graphic carries is skipped whole and named through `wpd/wpg-records-undecoded` (see Remaining scope).
171
176
  - **Table formulas** (`WPFF_TableFormulas`): a New Cell Formula embedded subfunction's own tokenised formula decodes to its own linear text on `ContentTableCell.formula`, carried verbatim in a spreadsheet-style cell-reference spelling (`A1`, `$A$1:B3`) — the same "structure yes, formula content no" boundary `ContentSheetCell.formula` already draws elsewhere in the family. See `src/stream/formula.ts`'s own top-of-file comment for why this is a linear substitution rather than an RPN evaluation, and for the honest-or-nothing contract that aborts the whole formula rather than guessing at an undocumented code.
172
177
 
173
178
  ### Remaining scope
174
179
 
175
180
  Everything below is recognised by the tokeniser and skipped by the fold, so a document containing it still reads — losing that construct's own structure, never the surrounding text. Each is reported through the diagnostic sink rather than passed over in silence.
176
181
 
177
- - **A box whose content is a presentation, video, macro, sound, or external payload**, and a box relying on its own template's inherited geometry rather than an explicit function-level position/size override. Reported through `wpd/box-content-unresolved` and `wpd/box-frame-unresolved` respectively. An image box IS lifted when its content packet carries a whole PNG or JPEG payload: the packet's raw bytes are scanned by signature and structural walk (`src/stream/image.ts` — the chunk chain to IEND for PNG, the marker segments to EOI for JPEG), never by guessing at a container header, and the span lifts as a `ContentImageBlock` sized by the box's own frame, with an absolute-from-page-edge position carried as the image's `floatPosition`. What stays unresolved: a WPG vector graphic (a distinct binary graphics format `ContentImageBlock`'s `png`/`jpeg`/`svg`/`gif` set cannot hold as recovered, and which this package does not decode — a project on the scale of this package's own WordPerfect reader, not a wiring job) and a native OLE object (see the next bullet). A box with no function-level content override at all — relying entirely on its template's own rendering defaults — is reported through `wpd/box-dropped`, unchanged from before.
178
- - **Watermarks** (the 0xD6 group's two watermark subfunctions). Reported through `wpd/header-footer-dropped`: a watermark is neither a header nor a footer and owns no parity, so the shared page-furniture vocabulary has no slot for one.
179
- - **A second header or footer claiming a slot a first already filled.** WordPerfect's own A/B two-slot-per-kind mechanism is a shape the shared one-flow-per-slot vocabulary does not carry; the first function to claim a slot is the one lifted, and the collision is reported through `wpd/header-footer-dropped`.
182
+ - **A box whose content is a presentation, video, macro, sound, or external payload**, and a box relying on its own template's inherited geometry rather than an explicit function-level position/size override. Reported through `wpd/box-content-unresolved` and `wpd/box-frame-unresolved` respectively. An image box IS lifted when its content packet carries a whole PNG or JPEG payload the packet's raw bytes are scanned by signature and structural walk (`src/stream/image.ts` — the chunk chain to IEND for PNG, the marker segments to EOI for JPEG), never by guessing at a container header, and the span lifts as a `ContentImageBlock` sized by the box's own frame, with an absolute-from-page-edge position carried as the image's `floatPosition` when it carries a WPG vector graphic the WPG decoder reads, or when it names a native OLE object whose bytes are recovered as tree-form attachments (both under What is handled). A box with no function-level content override at all — relying entirely on its template's own rendering defaults — is reported through `wpd/box-dropped`, unchanged from before.
183
+ - **A second header, footer, or watermark claiming a slot a first already filled.** WordPerfect's own A/B two-slot-per-kind mechanism is a shape the shared one-flow-per-slot vocabulary does not carry; the first function to claim a slot is the one lifted, and the collision is reported through `wpd/header-footer-dropped`.
180
184
 
181
185
  Headers and footers themselves are LIFTED (ExaDev/documents.js#1128): a D6 function's occurrence bits narrow onto the shared furniture vocabulary's slots (`ContentSection.headers`/`footers`, `default`/`even` — odd-only and both-parities are the default slot, even-only the even slot), its body folded from the General WP Text packet its first prefix ID names. Footnotes and endnotes are anchored in the flat form (a footnote/endnote anchor construct around the reference site, `definition` naming `note-1`, `note-2`, ... in document order) and their bodies are carried by `readWpd` as definitions-table entries in the tree form — the flat `readWpdContent` reports each still-borne body through `wpd/note-dropped`, since the flat `ContentDocument` genuinely has no home for one (`rtf-codec` documents the same split for its own equivalent constructs).
182
186
 
183
- - **A box whose content is an image, presentation, video, macro, sound, or external payload**, and a box relying on its own template's inherited geometry rather than an explicit function-level position/size override. Reported through `wpd/box-content-unresolved` and `wpd/box-frame-unresolved` respectively. An image box's own content resolves to a Graphics Filename prefix packet (type 0x40) whose children carry either WPG vector graphics (a distinct binary graphics format `ContentImageBlock`'s `png`/`jpeg`/`svg`/`gif` set cannot hold as recovered, and which this package does not decode a project on the scale of this package's own WordPerfect reader, not a wiring job) or a native OLE object (see the next bullet). A box with no function-level content override at all relying entirely on its template's own rendering defaults is reported through `wpd/box-dropped`, unchanged from before.
184
- - **Embedded OLE objects**, stored under the compound file's `PerfectOffice_OBJECTS` storage and named by an image box's Graphics Filename packet's own `0x70`/`0x71` (OLE Object Descriptor / OLE Object Data) children. `archive-codec`'s compound-file reader already reaches that storage, which is how `ooxml.js` recovers a ZIP-payload embedded object — but a WordPerfect OLE object's payload is a native OLE server's own stream rather than a nested document package (`ooxml.js`'s own equivalent case, a classic OLE1 `.bin` payload with no `Package` stream, stays opaque by the identical scope boundary), so recovering one generically is a project in its own right, not a wiring job.
187
+ - **The long tail of the WPG record vocabulary.** The WPG decoder is deliberately a layered subset, not "WPG support" (see What is handled for what does decode). Everything else a WPG 2.x record stream can carry Polyspline, Polycurve, Compound Polygon, Bitmap and Bitmap Data, Text Line, Text Path, Chart and its style/data companions, Object Image, Object Capsule, the pen style/pattern and brush pattern/gradient/texture families (a non-flat pattern has no flat colour this reader could honestly approximate it with), and the page-settings records is recognised by the walk, skipped whole, and named through `wpd/wpg-records-undecoded`, so a partially-decoding graphic still lifts what did decode with the skipped types named. Any record carrying a transformation in its characterisation flags (taper, translate, skew, scale, rotate) is refused rather than decoded with the transformation dropped its geometry would be wrong, not partial. WPG 1.0-major graphics are refused outright (a separate record vocabulary the vendor pages this package builds from do not document, and misparsing one as WPG 2.x would decode rubbish rather than refuse), as are encrypted graphics.
188
+ - **Interpreting a native OLE object's payload.** The object's bytes are recovered as tree-form attachments (see What is handled), but interpreting them would mean understanding every OLE server's on-disk format the same boundary `ooxml.js` draws for a classic OLE1 `.bin` payload with no `Package` stream so they are carried opaque rather than decoded.
185
189
  - **The counter groups** (0xD8, 0xD9, 0xDB, 0xDC): setting, numbering-method, increment and decrement carry no text and change no structure this reader models, so only the Display Number group's own paragraph-number pair is read.
186
190
  - **Every merge subfunction other than FIELD** (ASSIGN, CALL, IF, FOR, CASE, and the rest of WordPerfect's own merge scripting language) and **cross-references** (0xD5). A cross-reference's displayed text survives as ordinary text; its target binding does not. Reported through `wpd/merge-code-dropped` and `wpd/cross-reference-flattened`. Unlike FIELD, these can legitimately wrap whole paragraphs of body text as control flow, which the run-scoped field construct's own one-paragraph extent cannot express regardless — a schema gap for a scripting language's control flow, not a parsing gap.
187
191
  - **WordPerfect 9-and-later "enhanced encryption"**, which throws: a different, unpublished cipher whose header word is not the standard mode's password checksum, so a `password` read option either verifies against that checksum and decrypts the standard ("original") mode or throws `WpdWrongPasswordError` naming both possible readings of the mismatch. The standard mode itself is decrypted for real (see `src/container/encryption.ts` for the cipher's two independent sources, and for the honest limit that no open-source reference implementation of the 6.x wiring exists to cross-check against a WordPerfect-produced encrypted file).
@@ -19,14 +19,20 @@ function toArrayBufferBacked(bytes) {
19
19
  function unwrapContainer(bytes) {
20
20
  if (require_container_header.hasWordPerfectFileId(bytes)) return {
21
21
  bytes,
22
- compound: false
22
+ compound: false,
23
+ oleObjectStreams: /* @__PURE__ */ new Map()
23
24
  };
24
25
  if ((0, archive_codec.isCompoundFile)(bytes)) {
25
- const main = (0, archive_codec.readCompoundFile)(bytes).find((stream) => stream.path === PERFECT_OFFICE_MAIN_STREAM);
26
+ const streams = (0, archive_codec.readCompoundFile)(bytes);
27
+ const main = streams.find((stream) => stream.path === PERFECT_OFFICE_MAIN_STREAM);
26
28
  if (main === void 0) throw new require_errors.WpdNotAWordPerfectFileError(`This OLE compound file carries no ${PERFECT_OFFICE_MAIN_STREAM} stream, so it holds no WordPerfect document.`);
29
+ const objectsPrefix = `${PERFECT_OFFICE_OBJECTS_STORAGE}/`;
30
+ const oleObjectStreams = /* @__PURE__ */ new Map();
31
+ for (const stream of streams) if (stream.path.startsWith(objectsPrefix)) oleObjectStreams.set(stream.path.slice(objectsPrefix.length), stream.bytes);
27
32
  return {
28
33
  bytes: main.bytes,
29
- compound: true
34
+ compound: true,
35
+ oleObjectStreams
30
36
  };
31
37
  }
32
38
  throw new require_errors.WpdNotAWordPerfectFileError("These bytes are neither a WordPerfect file (which opens with the file ID FF 57 50 43) nor an OLE compound file that could contain one.");
@@ -37,7 +43,7 @@ function documentAreaEnd(bytes, header) {
37
43
  return bytes.length;
38
44
  }
39
45
  function openWpdDocument(input, options = {}) {
40
- const { bytes: wrapped, compound } = unwrapContainer(toArrayBufferBacked(input));
46
+ const { bytes: wrapped, compound, oleObjectStreams } = unwrapContainer(toArrayBufferBacked(input));
41
47
  const header = require_container_header.readFileHeader(wrapped, options);
42
48
  const suppliedPassword = options.password === "" ? void 0 : options.password;
43
49
  const bytes = header.encryption !== 0 && suppliedPassword !== void 0 ? require_container_encryption.decryptWpdDocument(wrapped, header, suppliedPassword) : wrapped;
@@ -47,7 +53,8 @@ function openWpdDocument(input, options = {}) {
47
53
  bytes,
48
54
  documentAreaOffset: header.documentAreaOffset,
49
55
  documentAreaEnd: documentAreaEnd(bytes, header),
50
- compound
56
+ compound,
57
+ oleObjectStreams
51
58
  };
52
59
  }
53
60
  //#endregion
@@ -1,4 +1,4 @@
1
- import { ReadWpdHeaderOptions, WpdFileHeader } from "./header.cjs";
1
+ import { i as WpdFileHeader, t as ReadWpdHeaderOptions } from "../header-Ca8QZVe3.cjs";
2
2
  import { WpdPrefixPacket } from "./prefix.cjs";
3
3
  //#region src/container/container.d.ts
4
4
  declare const PERFECT_OFFICE_MAIN_STREAM = "PerfectOffice_MAIN";
@@ -10,6 +10,7 @@ interface WpdDocumentContainer {
10
10
  readonly documentAreaOffset: number;
11
11
  readonly documentAreaEnd: number;
12
12
  readonly compound: boolean;
13
+ readonly oleObjectStreams: ReadonlyMap<string, Uint8Array<ArrayBuffer>>;
13
14
  }
14
15
  declare function openWpdDocument(input: Uint8Array, options?: ReadWpdHeaderOptions): WpdDocumentContainer;
15
16
  //#endregion
@@ -1,4 +1,4 @@
1
- import { ReadWpdHeaderOptions, WpdFileHeader } from "./header.js";
1
+ import { i as WpdFileHeader, t as ReadWpdHeaderOptions } from "../header-Ca8QZVe3.js";
2
2
  import { WpdPrefixPacket } from "./prefix.js";
3
3
  //#region src/container/container.d.ts
4
4
  declare const PERFECT_OFFICE_MAIN_STREAM = "PerfectOffice_MAIN";
@@ -10,6 +10,7 @@ interface WpdDocumentContainer {
10
10
  readonly documentAreaOffset: number;
11
11
  readonly documentAreaEnd: number;
12
12
  readonly compound: boolean;
13
+ readonly oleObjectStreams: ReadonlyMap<string, Uint8Array<ArrayBuffer>>;
13
14
  }
14
15
  declare function openWpdDocument(input: Uint8Array, options?: ReadWpdHeaderOptions): WpdDocumentContainer;
15
16
  //#endregion
@@ -18,14 +18,20 @@ function toArrayBufferBacked(bytes) {
18
18
  function unwrapContainer(bytes) {
19
19
  if (hasWordPerfectFileId(bytes)) return {
20
20
  bytes,
21
- compound: false
21
+ compound: false,
22
+ oleObjectStreams: /* @__PURE__ */ new Map()
22
23
  };
23
24
  if (isCompoundFile(bytes)) {
24
- const main = readCompoundFile(bytes).find((stream) => stream.path === PERFECT_OFFICE_MAIN_STREAM);
25
+ const streams = readCompoundFile(bytes);
26
+ const main = streams.find((stream) => stream.path === PERFECT_OFFICE_MAIN_STREAM);
25
27
  if (main === void 0) throw new WpdNotAWordPerfectFileError(`This OLE compound file carries no ${PERFECT_OFFICE_MAIN_STREAM} stream, so it holds no WordPerfect document.`);
28
+ const objectsPrefix = `${PERFECT_OFFICE_OBJECTS_STORAGE}/`;
29
+ const oleObjectStreams = /* @__PURE__ */ new Map();
30
+ for (const stream of streams) if (stream.path.startsWith(objectsPrefix)) oleObjectStreams.set(stream.path.slice(objectsPrefix.length), stream.bytes);
26
31
  return {
27
32
  bytes: main.bytes,
28
- compound: true
33
+ compound: true,
34
+ oleObjectStreams
29
35
  };
30
36
  }
31
37
  throw new WpdNotAWordPerfectFileError("These bytes are neither a WordPerfect file (which opens with the file ID FF 57 50 43) nor an OLE compound file that could contain one.");
@@ -36,7 +42,7 @@ function documentAreaEnd(bytes, header) {
36
42
  return bytes.length;
37
43
  }
38
44
  function openWpdDocument(input, options = {}) {
39
- const { bytes: wrapped, compound } = unwrapContainer(toArrayBufferBacked(input));
45
+ const { bytes: wrapped, compound, oleObjectStreams } = unwrapContainer(toArrayBufferBacked(input));
40
46
  const header = readFileHeader(wrapped, options);
41
47
  const suppliedPassword = options.password === "" ? void 0 : options.password;
42
48
  const bytes = header.encryption !== 0 && suppliedPassword !== void 0 ? decryptWpdDocument(wrapped, header, suppliedPassword) : wrapped;
@@ -46,7 +52,8 @@ function openWpdDocument(input, options = {}) {
46
52
  bytes,
47
53
  documentAreaOffset: header.documentAreaOffset,
48
54
  documentAreaEnd: documentAreaEnd(bytes, header),
49
- compound
55
+ compound,
56
+ oleObjectStreams
50
57
  };
51
58
  }
52
59
  //#endregion
@@ -1,4 +1,4 @@
1
- import { WpdFileHeader } from "./header.cjs";
1
+ import { i as WpdFileHeader } from "../header-Ca8QZVe3.cjs";
2
2
  //#region src/container/encryption.d.ts
3
3
  declare function normaliseWpdPassword(password: string): number[];
4
4
  declare function wpdPasswordChecksum16(normalised: readonly number[]): number;
@@ -1,4 +1,4 @@
1
- import { WpdFileHeader } from "./header.js";
1
+ import { i as WpdFileHeader } from "../header-Ca8QZVe3.js";
2
2
  //#region src/container/encryption.d.ts
3
3
  declare function normaliseWpdPassword(password: string): number[];
4
4
  declare function wpdPasswordChecksum16(normalised: readonly number[]): number;
@@ -1,20 +1,2 @@
1
- //#region src/container/header.d.ts
2
- declare const WPD_FILE_ID: readonly number[];
3
- declare const WPD_PREFIX_HEADER_SIZE = 512;
4
- interface ReadWpdHeaderOptions {
5
- readonly password?: string;
6
- }
7
- interface WpdFileHeader {
8
- readonly documentAreaOffset: number;
9
- readonly productType: number;
10
- readonly fileType: number;
11
- readonly majorVersion: number;
12
- readonly minorVersion: number;
13
- readonly indexAreaOffset: number;
14
- readonly fileSize: number;
15
- readonly encryption: number;
16
- }
17
- declare function hasWordPerfectFileId(bytes: Uint8Array): boolean;
18
- declare function readFileHeader(bytes: Uint8Array, options?: ReadWpdHeaderOptions): WpdFileHeader;
19
- //#endregion
1
+ import { a as hasWordPerfectFileId, i as WpdFileHeader, n as WPD_FILE_ID, o as readFileHeader, r as WPD_PREFIX_HEADER_SIZE, t as ReadWpdHeaderOptions } from "../header-Ca8QZVe3.cjs";
20
2
  export { ReadWpdHeaderOptions, WPD_FILE_ID, WPD_PREFIX_HEADER_SIZE, WpdFileHeader, hasWordPerfectFileId, readFileHeader };
@@ -1,20 +1,2 @@
1
- //#region src/container/header.d.ts
2
- declare const WPD_FILE_ID: readonly number[];
3
- declare const WPD_PREFIX_HEADER_SIZE = 512;
4
- interface ReadWpdHeaderOptions {
5
- readonly password?: string;
6
- }
7
- interface WpdFileHeader {
8
- readonly documentAreaOffset: number;
9
- readonly productType: number;
10
- readonly fileType: number;
11
- readonly majorVersion: number;
12
- readonly minorVersion: number;
13
- readonly indexAreaOffset: number;
14
- readonly fileSize: number;
15
- readonly encryption: number;
16
- }
17
- declare function hasWordPerfectFileId(bytes: Uint8Array): boolean;
18
- declare function readFileHeader(bytes: Uint8Array, options?: ReadWpdHeaderOptions): WpdFileHeader;
19
- //#endregion
1
+ import { a as hasWordPerfectFileId, i as WpdFileHeader, n as WPD_FILE_ID, o as readFileHeader, r as WPD_PREFIX_HEADER_SIZE, t as ReadWpdHeaderOptions } from "../header-Ca8QZVe3.js";
20
2
  export { ReadWpdHeaderOptions, WPD_FILE_ID, WPD_PREFIX_HEADER_SIZE, WpdFileHeader, hasWordPerfectFileId, readFileHeader };
@@ -1,4 +1,4 @@
1
- import { WpdFileHeader } from "./header.cjs";
1
+ import { i as WpdFileHeader } from "../header-Ca8QZVe3.cjs";
2
2
  //#region src/container/prefix.d.ts
3
3
  declare const WPD_INDEX_RECORD_SIZE = 14;
4
4
  declare const PACKET_TYPE_DESIRED_FONT_DESCRIPTOR = 85;
@@ -1,4 +1,4 @@
1
- import { WpdFileHeader } from "./header.js";
1
+ import { i as WpdFileHeader } from "../header-Ca8QZVe3.js";
2
2
  //#region src/container/prefix.d.ts
3
3
  declare const WPD_INDEX_RECORD_SIZE = 14;
4
4
  declare const PACKET_TYPE_DESIRED_FONT_DESCRIPTOR = 85;
@@ -18,12 +18,14 @@ declare const WpdDiagnosticCodes: {
18
18
  readonly NoteDropped: "wpd/note-dropped";
19
19
  readonly NoteSpansParagraphs: "wpd/note-spans-paragraphs";
20
20
  readonly HeaderFooterDropped: "wpd/header-footer-dropped";
21
+ readonly OleObjectDropped: "wpd/ole-object-dropped";
21
22
  readonly CrossReferenceFlattened: "wpd/cross-reference-flattened";
22
23
  readonly MergeCodeDropped: "wpd/merge-code-dropped";
23
24
  readonly TableFormulaUnresolved: "wpd/table-formula-unresolved";
24
25
  readonly StyleResolutionDepthExceeded: "wpd/style-resolution-depth-exceeded";
25
26
  readonly MergeFieldSpansParagraphs: "wpd/merge-field-spans-paragraphs";
26
27
  readonly BoxContentUnresolved: "wpd/box-content-unresolved";
28
+ readonly WpgRecordsUndecoded: "wpd/wpg-records-undecoded";
27
29
  readonly BoxFrameUnresolved: "wpd/box-frame-unresolved";
28
30
  };
29
31
  declare const NOOP_WPD_DIAGNOSTIC_SINK: WpdDiagnosticSink;
@@ -18,12 +18,14 @@ declare const WpdDiagnosticCodes: {
18
18
  readonly NoteDropped: "wpd/note-dropped";
19
19
  readonly NoteSpansParagraphs: "wpd/note-spans-paragraphs";
20
20
  readonly HeaderFooterDropped: "wpd/header-footer-dropped";
21
+ readonly OleObjectDropped: "wpd/ole-object-dropped";
21
22
  readonly CrossReferenceFlattened: "wpd/cross-reference-flattened";
22
23
  readonly MergeCodeDropped: "wpd/merge-code-dropped";
23
24
  readonly TableFormulaUnresolved: "wpd/table-formula-unresolved";
24
25
  readonly StyleResolutionDepthExceeded: "wpd/style-resolution-depth-exceeded";
25
26
  readonly MergeFieldSpansParagraphs: "wpd/merge-field-spans-paragraphs";
26
27
  readonly BoxContentUnresolved: "wpd/box-content-unresolved";
28
+ readonly WpgRecordsUndecoded: "wpd/wpg-records-undecoded";
27
29
  readonly BoxFrameUnresolved: "wpd/box-frame-unresolved";
28
30
  };
29
31
  declare const NOOP_WPD_DIAGNOSTIC_SINK: WpdDiagnosticSink;
@@ -14,12 +14,14 @@ const WpdDiagnosticCodes = {
14
14
  NoteDropped: "wpd/note-dropped",
15
15
  NoteSpansParagraphs: "wpd/note-spans-paragraphs",
16
16
  HeaderFooterDropped: "wpd/header-footer-dropped",
17
+ OleObjectDropped: "wpd/ole-object-dropped",
17
18
  CrossReferenceFlattened: "wpd/cross-reference-flattened",
18
19
  MergeCodeDropped: "wpd/merge-code-dropped",
19
20
  TableFormulaUnresolved: "wpd/table-formula-unresolved",
20
21
  StyleResolutionDepthExceeded: "wpd/style-resolution-depth-exceeded",
21
22
  MergeFieldSpansParagraphs: "wpd/merge-field-spans-paragraphs",
22
23
  BoxContentUnresolved: "wpd/box-content-unresolved",
24
+ WpgRecordsUndecoded: "wpd/wpg-records-undecoded",
23
25
  BoxFrameUnresolved: "wpd/box-frame-unresolved"
24
26
  };
25
27
  const NOOP_WPD_DIAGNOSTIC_SINK = () => {};
@@ -1,2 +1,2 @@
1
- import { i as WpdDiagnosticSink, n as WpdDiagnostic, r as WpdDiagnosticCodes, t as NOOP_WPD_DIAGNOSTIC_SINK } from "./diagnostics-DhO7mgqJ.cjs";
1
+ import { i as WpdDiagnosticSink, n as WpdDiagnostic, r as WpdDiagnosticCodes, t as NOOP_WPD_DIAGNOSTIC_SINK } from "./diagnostics-fHTFHZ-d.cjs";
2
2
  export { NOOP_WPD_DIAGNOSTIC_SINK, WpdDiagnostic, WpdDiagnosticCodes, WpdDiagnosticSink };
@@ -1,2 +1,2 @@
1
- import { i as WpdDiagnosticSink, n as WpdDiagnostic, r as WpdDiagnosticCodes, t as NOOP_WPD_DIAGNOSTIC_SINK } from "./diagnostics-DhO7mgqJ.js";
1
+ import { i as WpdDiagnosticSink, n as WpdDiagnostic, r as WpdDiagnosticCodes, t as NOOP_WPD_DIAGNOSTIC_SINK } from "./diagnostics-fHTFHZ-d.js";
2
2
  export { NOOP_WPD_DIAGNOSTIC_SINK, WpdDiagnostic, WpdDiagnosticCodes, WpdDiagnosticSink };
@@ -13,12 +13,14 @@ const WpdDiagnosticCodes = {
13
13
  NoteDropped: "wpd/note-dropped",
14
14
  NoteSpansParagraphs: "wpd/note-spans-paragraphs",
15
15
  HeaderFooterDropped: "wpd/header-footer-dropped",
16
+ OleObjectDropped: "wpd/ole-object-dropped",
16
17
  CrossReferenceFlattened: "wpd/cross-reference-flattened",
17
18
  MergeCodeDropped: "wpd/merge-code-dropped",
18
19
  TableFormulaUnresolved: "wpd/table-formula-unresolved",
19
20
  StyleResolutionDepthExceeded: "wpd/style-resolution-depth-exceeded",
20
21
  MergeFieldSpansParagraphs: "wpd/merge-field-spans-paragraphs",
21
22
  BoxContentUnresolved: "wpd/box-content-unresolved",
23
+ WpgRecordsUndecoded: "wpd/wpg-records-undecoded",
22
24
  BoxFrameUnresolved: "wpd/box-frame-unresolved"
23
25
  };
24
26
  const NOOP_WPD_DIAGNOSTIC_SINK = () => {};
@@ -0,0 +1,20 @@
1
+ //#region src/container/header.d.ts
2
+ declare const WPD_FILE_ID: readonly number[];
3
+ declare const WPD_PREFIX_HEADER_SIZE = 512;
4
+ interface ReadWpdHeaderOptions {
5
+ readonly password?: string;
6
+ }
7
+ interface WpdFileHeader {
8
+ readonly documentAreaOffset: number;
9
+ readonly productType: number;
10
+ readonly fileType: number;
11
+ readonly majorVersion: number;
12
+ readonly minorVersion: number;
13
+ readonly indexAreaOffset: number;
14
+ readonly fileSize: number;
15
+ readonly encryption: number;
16
+ }
17
+ declare function hasWordPerfectFileId(bytes: Uint8Array): boolean;
18
+ declare function readFileHeader(bytes: Uint8Array, options?: ReadWpdHeaderOptions): WpdFileHeader;
19
+ //#endregion
20
+ export { hasWordPerfectFileId as a, WpdFileHeader as i, WPD_FILE_ID as n, readFileHeader as o, WPD_PREFIX_HEADER_SIZE as r, ReadWpdHeaderOptions as t };
@@ -0,0 +1,20 @@
1
+ //#region src/container/header.d.ts
2
+ declare const WPD_FILE_ID: readonly number[];
3
+ declare const WPD_PREFIX_HEADER_SIZE = 512;
4
+ interface ReadWpdHeaderOptions {
5
+ readonly password?: string;
6
+ }
7
+ interface WpdFileHeader {
8
+ readonly documentAreaOffset: number;
9
+ readonly productType: number;
10
+ readonly fileType: number;
11
+ readonly majorVersion: number;
12
+ readonly minorVersion: number;
13
+ readonly indexAreaOffset: number;
14
+ readonly fileSize: number;
15
+ readonly encryption: number;
16
+ }
17
+ declare function hasWordPerfectFileId(bytes: Uint8Array): boolean;
18
+ declare function readFileHeader(bytes: Uint8Array, options?: ReadWpdHeaderOptions): WpdFileHeader;
19
+ //#endregion
20
+ export { hasWordPerfectFileId as a, WpdFileHeader as i, WPD_FILE_ID as n, readFileHeader as o, WPD_PREFIX_HEADER_SIZE as r, ReadWpdHeaderOptions as t };
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { i as WpdDiagnosticSink, n as WpdDiagnostic, r as WpdDiagnosticCodes, t as NOOP_WPD_DIAGNOSTIC_SINK } from "./diagnostics-DhO7mgqJ.cjs";
1
+ import { i as WpdDiagnosticSink, n as WpdDiagnostic, r as WpdDiagnosticCodes, t as NOOP_WPD_DIAGNOSTIC_SINK } from "./diagnostics-fHTFHZ-d.cjs";
2
2
  import { ReadWpdOptions, readWpd, readWpdContent } from "./read.cjs";
3
3
  import { WpdBytesSchema, wpdContentCodec } from "./codec.cjs";
4
- import { WPD_FILE_ID, WPD_PREFIX_HEADER_SIZE, WpdFileHeader, hasWordPerfectFileId, readFileHeader } from "./container/header.cjs";
4
+ import { a as hasWordPerfectFileId, i as WpdFileHeader, n as WPD_FILE_ID, o as readFileHeader, r as WPD_PREFIX_HEADER_SIZE } from "./header-Ca8QZVe3.cjs";
5
5
  import { PACKET_TYPE_DESIRED_FONT_DESCRIPTOR, WPD_INDEX_RECORD_SIZE, WpdPrefixPacket, packetByPrefixId, readPrefixPackets, readTypefaceName } from "./container/prefix.cjs";
6
6
  import { PERFECT_OFFICE_MAIN_STREAM, PERFECT_OFFICE_OBJECTS_STORAGE, WpdDocumentContainer, openWpdDocument } from "./container/container.cjs";
7
7
  import { PACKET_TYPE_EXTENDED_DOCUMENT_SUMMARY, readDocumentSummary } from "./container/summary.cjs";
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { i as WpdDiagnosticSink, n as WpdDiagnostic, r as WpdDiagnosticCodes, t as NOOP_WPD_DIAGNOSTIC_SINK } from "./diagnostics-DhO7mgqJ.js";
1
+ import { i as WpdDiagnosticSink, n as WpdDiagnostic, r as WpdDiagnosticCodes, t as NOOP_WPD_DIAGNOSTIC_SINK } from "./diagnostics-fHTFHZ-d.js";
2
2
  import { ReadWpdOptions, readWpd, readWpdContent } from "./read.js";
3
3
  import { WpdBytesSchema, wpdContentCodec } from "./codec.js";
4
- import { WPD_FILE_ID, WPD_PREFIX_HEADER_SIZE, WpdFileHeader, hasWordPerfectFileId, readFileHeader } from "./container/header.js";
4
+ import { a as hasWordPerfectFileId, i as WpdFileHeader, n as WPD_FILE_ID, o as readFileHeader, r as WPD_PREFIX_HEADER_SIZE } from "./header-Ca8QZVe3.js";
5
5
  import { PACKET_TYPE_DESIRED_FONT_DESCRIPTOR, WPD_INDEX_RECORD_SIZE, WpdPrefixPacket, packetByPrefixId, readPrefixPackets, readTypefaceName } from "./container/prefix.js";
6
6
  import { PERFECT_OFFICE_MAIN_STREAM, PERFECT_OFFICE_OBJECTS_STORAGE, WpdDocumentContainer, openWpdDocument } from "./container/container.js";
7
7
  import { PACKET_TYPE_EXTENDED_DOCUMENT_SUMMARY, readDocumentSummary } from "./container/summary.js";