xls-codec 4.14.0 → 4.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +37 -19
  2. package/dist/biff/record-writer.cjs +18 -0
  3. package/dist/biff/record-writer.d.cts +7 -1
  4. package/dist/biff/record-writer.d.ts +7 -1
  5. package/dist/biff/record-writer.js +18 -1
  6. package/dist/container.cjs +9 -1
  7. package/dist/container.d.cts +2 -0
  8. package/dist/container.d.ts +2 -0
  9. package/dist/container.js +9 -1
  10. package/dist/content.cjs +6 -5
  11. package/dist/content.js +6 -5
  12. package/dist/drawing/escher-constants.cjs +6 -0
  13. package/dist/drawing/escher-constants.d.cts +5 -1
  14. package/dist/drawing/escher-constants.d.ts +5 -1
  15. package/dist/drawing/escher-constants.js +5 -1
  16. package/dist/drawing/escher-writer.cjs +107 -0
  17. package/dist/drawing/escher-writer.d.cts +32 -0
  18. package/dist/drawing/escher-writer.d.ts +32 -0
  19. package/dist/drawing/escher-writer.js +105 -0
  20. package/dist/drawing/md4.cjs +146 -0
  21. package/dist/drawing/md4.d.cts +7 -0
  22. package/dist/drawing/md4.d.ts +7 -0
  23. package/dist/drawing/md4.js +145 -0
  24. package/dist/drawing-writer-Blm_NUSZ.d.cts +19 -0
  25. package/dist/drawing-writer-Blm_NUSZ.d.ts +19 -0
  26. package/dist/index.cjs +1 -0
  27. package/dist/index.d.cts +2 -2
  28. package/dist/index.d.ts +2 -2
  29. package/dist/index.js +2 -2
  30. package/dist/workbook/comments.cjs +26 -0
  31. package/dist/workbook/comments.d.cts +7 -1
  32. package/dist/workbook/comments.d.ts +7 -1
  33. package/dist/workbook/comments.js +26 -1
  34. package/dist/workbook/conditional-format-write.cjs +307 -18
  35. package/dist/workbook/conditional-format-write.js +307 -18
  36. package/dist/workbook/drawing-writer.cjs +253 -0
  37. package/dist/workbook/drawing-writer.d.cts +2 -0
  38. package/dist/workbook/drawing-writer.d.ts +2 -0
  39. package/dist/workbook/drawing-writer.js +252 -0
  40. package/dist/workbook/drawing.cjs +24 -3
  41. package/dist/workbook/drawing.d.cts +2 -0
  42. package/dist/workbook/drawing.d.ts +2 -0
  43. package/dist/workbook/drawing.js +25 -4
  44. package/dist/workbook/embedded-object.cjs +43 -0
  45. package/dist/workbook/embedded-object.d.cts +8 -0
  46. package/dist/workbook/embedded-object.d.ts +8 -0
  47. package/dist/workbook/embedded-object.js +41 -0
  48. package/dist/workbook/globals-writer.cjs +1 -0
  49. package/dist/workbook/globals-writer.d.cts +2 -0
  50. package/dist/workbook/globals-writer.d.ts +2 -0
  51. package/dist/workbook/globals-writer.js +2 -1
  52. package/dist/workbook/sheet-writer.cjs +4 -3
  53. package/dist/workbook/sheet-writer.d.cts +3 -2
  54. package/dist/workbook/sheet-writer.d.ts +3 -2
  55. package/dist/workbook/sheet-writer.js +4 -3
  56. package/dist/write.cjs +17 -7
  57. package/dist/write.js +17 -7
  58. package/package.json +5 -5
@@ -0,0 +1,107 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_biff_builder = require("../biff/builder.cjs");
3
+ const require_biff_write_errors = require("../biff/write-errors.cjs");
4
+ const require_drawing_escher_constants = require("./escher-constants.cjs");
5
+ const require_drawing_md4 = require("./md4.cjs");
6
+ //#region src/drawing/escher-writer.ts
7
+ /** One Escher atom's own bytes: header plus `data` verbatim. */
8
+ function escherAtom(recVer, recInstance, recType, data) {
9
+ return new require_biff_builder.RecordBuilder().u16(recVer & 15 | (recInstance & 4095) << 4).u16(recType).u32(data.length).bytes(data).build();
10
+ }
11
+ /** One Escher container's own bytes: header (recVer 0xF, [MS-ODRAW] 2.2.1's container marker, in the verInstance word's low nibble) plus its children concatenated -- recLen is then the children's total size with their own headers included, exactly what the format defines. `recInstance` is the verInstance word's upper 12 bits, which every container this writer states pins to 0x000 except the Blip Store, whose own page requires the count of BSE children. */
12
+ function escherContainer(recType, recInstance, children) {
13
+ const body = children.reduce((sum, child) => sum + child.length, 0);
14
+ const builder = new require_biff_builder.RecordBuilder().u16(15 | (recInstance & 4095) << 4).u16(recType).u32(body);
15
+ for (const child of children) builder.bytes(child);
16
+ return builder.build();
17
+ }
18
+ const MSOBLIP_JPEG = 5;
19
+ const MSOBLIP_PNG = 6;
20
+ const BLIP_PNG_RECTYPE = 61470;
21
+ const BLIP_JPEG_RECTYPE = 61469;
22
+ const BLIP_PNG_INSTANCE_ONE_UID = 1760;
23
+ const BLIP_JPEG_INSTANCE_ONE_UID = 1130;
24
+ /** rgbUid's own fixed size: [MS-ODRAW]'s FBSE and Blip records each open with one 16-byte MD4 digest of the image data. */
25
+ const UID_SIZE = 16;
26
+ function blipFormatFields(format) {
27
+ if (format === "png") return {
28
+ msoBlip: MSOBLIP_PNG,
29
+ recType: BLIP_PNG_RECTYPE,
30
+ recInstance: BLIP_PNG_INSTANCE_ONE_UID
31
+ };
32
+ return {
33
+ msoBlip: MSOBLIP_JPEG,
34
+ recType: BLIP_JPEG_RECTYPE,
35
+ recInstance: BLIP_JPEG_INSTANCE_ONE_UID
36
+ };
37
+ }
38
+ /** One OfficeArtBlipPNG/JPEG record ([MS-ODRAW] 2.2.28/2.2.27): one rgbUid (the MD4 of the file bytes -- a digest of the UNCOMPRESSED blip data per 2.2.28's own field text, which for PNG and JPEG is the file bytes themselves), the tag byte, then the literal file bytes. The tag byte is 0xFF, "internal resource tag" -- the value real producers write for data embedded in the record. */
39
+ function writeBlipRecord(format, uidBytes, fileBytes) {
40
+ const fields = blipFormatFields(format);
41
+ return escherAtom(0, fields.recInstance, fields.recType, new require_biff_builder.RecordBuilder().bytes(uidBytes).u8(255).bytes(fileBytes).build());
42
+ }
43
+ /** One OfficeArtFBSE ([MS-ODRAW] 2.2.24.1, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/2f2d7f5e-d5c4-4cb7-b230-59b3fe8f10d6): the blip's type pair, its rgbUid, a tag, the embedded blip record's own total size, the reference count, a foDelay this writer always states as "not in a delay stream" alongside an inline embeddedBlip (which [MS-ODRAW] says makes foDelay ignored), the name-length byte (0 -- no name), and the embedded blip record itself. recLen's own rule -- "the size of nameData plus size plus 36" for an embedded blip -- falls out of the fixed fields plus the blip record's length. */
44
+ function writeBseRecord(blip) {
45
+ const fields = blipFormatFields(blip.format);
46
+ const uidBytes = hexToBytes(require_drawing_md4.md4(blip.fileBytes));
47
+ if (uidBytes.length !== UID_SIZE) throw new require_biff_write_errors.BiffWriteError(`internal error: md4 produced a ${uidBytes.length}-byte digest, not the ${UID_SIZE} bytes rgbUid ([MS-ODRAW]'s own FBSE/Blip field) requires`);
48
+ const embedded = writeBlipRecord(blip.format, uidBytes, blip.fileBytes);
49
+ const fixed = new require_biff_builder.RecordBuilder().u8(fields.msoBlip).u8(fields.msoBlip).bytes(uidBytes).u16(255).u32(embedded.length).u32(blip.referenceCount).u32(0).u8(0).u8(0).u8(0).u8(0);
50
+ return escherAtom(2, fields.msoBlip, require_drawing_escher_constants.ESCHER_BSE, new require_biff_builder.RecordBuilder().bytes(fixed.build()).bytes(embedded).build());
51
+ }
52
+ function hexToBytes(hex) {
53
+ const out = new Uint8Array(hex.length / 2);
54
+ for (let index = 0; index < out.length; index += 1) out[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
55
+ return out;
56
+ }
57
+ /**
58
+ * The workbook-wide OfficeArtDggContainer ([MS-ODRAW] 2.2.12, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/dd7133b6-ed10-4bcb-be29-67b0544f884f): a FDGGBlock (the FDGG atom plus one OfficeArtIDCL per drawing, cidcl = drawing count + 1 per 2.2.14's own field definition) followed by the Blip Store when the workbook carries any image. The DggContainer's own optional children this writer has no data for -- drawingPrimaryOptions, colorMRU, splitColors -- are omitted, which the container's own production permits.
59
+ */
60
+ function writeDrawingGroupBytes(blips, drawings) {
61
+ const spidMax = drawings.reduce((max, drawing) => Math.max(max, drawing.lastSpid), 0);
62
+ const cspSaved = drawings.reduce((sum, drawing) => sum + drawing.shapeCount, 0);
63
+ const fdgg = new require_biff_builder.RecordBuilder().u32(spidMax).u32(drawings.length + 1).u32(cspSaved).u32(drawings.length);
64
+ for (const drawing of drawings) fdgg.u32(drawing.drawingId).u32(drawing.lastSpid);
65
+ const children = [escherAtom(0, 0, 61446, fdgg.build())];
66
+ if (blips.length > 0) children.push(escherContainer(require_drawing_escher_constants.ESCHER_BSTORE_CONTAINER, blips.length, blips.map((blip) => writeBseRecord(blip))));
67
+ return escherContainer(require_drawing_escher_constants.ESCHER_DGG_CONTAINER, 0, children);
68
+ }
69
+ const FSP_FLAG_OLE_SHAPE = 16;
70
+ /** OfficeArtFSP ([MS-ODRAW] 2.2.40, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/8a7e7be3-0582-4461-9400-29d7eda8497d): recVer 0x2, recInstance carrying the shape's own MSOSPT type, then spid and the flags word. Every shape this writer states is a picture frame (MSOSPT 0x4B) -- a picture because it holds an image, an OLE object because [MS-ODRAW]'s own model hosts one through the picture machinery with fOleShape set. */
71
+ function writeFspRecord(spid, flags, shapeType) {
72
+ return escherAtom(2, shapeType, require_drawing_escher_constants.ESCHER_SP, new require_biff_builder.RecordBuilder().u32(spid).u32(flags >>> 0).build());
73
+ }
74
+ /** OfficeArtFOPT ([MS-ODRAW] 2.2.9): recVer 0x3, recInstance carrying the property count, then that many 6-byte FOPTE entries (opid, op). The one property this writer states is `pib` -- the picture's own 1-based Blip Store index, opid 0x0104 with fComplex clear. */
75
+ function writePibOptRecord(blipIndex) {
76
+ return escherAtom(3, 1, require_drawing_escher_constants.ESCHER_OPT, new require_biff_builder.RecordBuilder().u16(260).u32(blipIndex).build());
77
+ }
78
+ /** OfficeArtClientAnchorSheet ([MS-XLS] 2.5.193): recVer 0, recLen 18, a flags word (fMove and fSize both set -- the shape moves and sizes with its cells, the behaviour an image anchored to cells means), then the corner-cell-plus-fractional-offset pair -- eight u16 fields, 18 bytes total (2 for flags + 8*2), matching the record's own declared recLen and drawing/shapes.ts's own readClientAnchor, which reads each of dxL/dyT/dxR/dyB as a 2-byte i16, not a 4-byte i32. dxL/dxR are 1/1024ths of their column's own width, dyT/dyB 1/256ths of their row's own height, both always non-negative in this writer's own range (0-1023, 0-255), so the identical bit pattern u16 writes here is what i16 reads back unchanged. */
79
+ function writeClientAnchorRecord(anchor) {
80
+ return escherAtom(0, 0, require_drawing_escher_constants.ESCHER_CLIENT_ANCHOR, new require_biff_builder.RecordBuilder().u16(3).u16(anchor.colL).u16(anchor.dxL).u16(anchor.rwT).u16(anchor.dyT).u16(anchor.colR).u16(anchor.dxR).u16(anchor.rwB).u16(anchor.dyB).build());
81
+ }
82
+ /** OfficeArtClientData: an empty atom (recLen 0) whose presence is what tells a reader that the next BIFF record after the MsoDrawing is this shape's own Obj record -- see [MS-XLS] MsoDrawing's own prose, cited on ESCHER_CLIENT_DATA above. */
83
+ function writeClientDataRecord() {
84
+ return escherAtom(0, 0, require_drawing_escher_constants.ESCHER_CLIENT_DATA, /* @__PURE__ */ new Uint8Array(0));
85
+ }
86
+ /** One shape's own SpContainer ([MS-ODRAW] 2.2.14, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/16194cb9-b4b0-476c-9678-a6ac1f06b034): shapeProp (the FSP), then shapePrimaryOptions only for a picture (the pib property table), then the clientAnchor and the clientData -- the reader's own SpContainer walk reads exactly these atoms and no others. */
87
+ function writeShapeContainer(spid, entry) {
88
+ const children = [writeFspRecord(spid, (entry.oleShape ? FSP_FLAG_OLE_SHAPE : 0) | 2560, 75)];
89
+ if (entry.blipIndex !== void 0) children.push(writePibOptRecord(entry.blipIndex));
90
+ children.push(writeClientAnchorRecord(entry.anchor), writeClientDataRecord());
91
+ return escherContainer(require_drawing_escher_constants.ESCHER_SP_CONTAINER, 0, children);
92
+ }
93
+ /**
94
+ * One worksheet's own OfficeArtDgContainer: the FDG atom (recInstance carrying the drawing identifier, csp counting the patriarch alongside every real shape, spidCur the last shape id this drawing allocated), then the one SpgrContainer holding the patriarch -- an SpContainer whose FSPGR states the all-zero coordinate rectangle and whose FSP carries fGroup|fPatriarch -- followed by one SpContainer per real shape in document order, the order the sheet's Obj records then pair with 1:1. `spidBase` is the first unallocated shape id of the whole drawing group (1024 for the first sheet carrying shapes, Excel's own convention): the patriarch takes it, the real shapes take the following ids, and the caller continues allocating from the returned drawing's own lastSpid.
95
+ *
96
+ * The DgContainer's own further optional children (a SolverContainer, deleted shapes) are omitted: this writer states no solver rules and no deleted shapes, which the container's own production permits.
97
+ */
98
+ function writeSheetDrawingBytes(drawingId, spidBase, entries) {
99
+ const lastSpid = spidBase + entries.length;
100
+ const fdg = escherAtom(0, drawingId, 61448, new require_biff_builder.RecordBuilder().u32(entries.length + 1).u32(lastSpid).build());
101
+ const patriarch = escherContainer(require_drawing_escher_constants.ESCHER_SP_CONTAINER, 0, [escherAtom(0, 0, require_drawing_escher_constants.ESCHER_FSPGR, /* @__PURE__ */ new Uint8Array(16)), writeFspRecord(spidBase, 5, 0)]);
102
+ const spgr = escherContainer(require_drawing_escher_constants.ESCHER_SPGR_CONTAINER, 0, [patriarch, ...entries.map((entry, index) => writeShapeContainer(spidBase + index + 1, entry))]);
103
+ return escherContainer(require_drawing_escher_constants.ESCHER_DG_CONTAINER, 0, [fdg, spgr]);
104
+ }
105
+ //#endregion
106
+ exports.writeDrawingGroupBytes = writeDrawingGroupBytes;
107
+ exports.writeSheetDrawingBytes = writeSheetDrawingBytes;
@@ -0,0 +1,32 @@
1
+ import { ShapeAnchor } from "./shapes.cjs";
2
+ //#region src/drawing/escher-writer.d.ts
3
+ /** One distinct image the workbook's sheets share: its decoded bytes, and how many picture shapes reference it (the FBSE's own cRef, which [MS-ODRAW] defines as the number of references to the BLIP). */
4
+ interface StoredBlip {
5
+ readonly format: "png" | "jpeg";
6
+ readonly fileBytes: Uint8Array<ArrayBuffer>;
7
+ readonly referenceCount: number;
8
+ }
9
+ /** One drawing's own contribution to the drawing group's shape-id state: the drawing identifier its FDG and IDCL both name, and the last shape identifier it allocated. */
10
+ interface DrawingIdBlock {
11
+ readonly drawingId: number;
12
+ readonly lastSpid: number;
13
+ readonly shapeCount: number;
14
+ }
15
+ /**
16
+ * The workbook-wide OfficeArtDggContainer ([MS-ODRAW] 2.2.12, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/dd7133b6-ed10-4bcb-be29-67b0544f884f): a FDGGBlock (the FDGG atom plus one OfficeArtIDCL per drawing, cidcl = drawing count + 1 per 2.2.14's own field definition) followed by the Blip Store when the workbook carries any image. The DggContainer's own optional children this writer has no data for -- drawingPrimaryOptions, colorMRU, splitColors -- are omitted, which the container's own production permits.
17
+ */
18
+ declare function writeDrawingGroupBytes(blips: readonly StoredBlip[], drawings: readonly DrawingIdBlock[]): Uint8Array<ArrayBuffer>;
19
+ /** One real (non-patriarch) shape this writer places on a sheet: its anchor, its 1-based Blip Store reference when it is a picture, and whether it hosts an embedded OLE object (which sets FSP's own fOleShape and takes no pib). */
20
+ interface SheetShapeEntry {
21
+ readonly anchor: ShapeAnchor;
22
+ readonly blipIndex: number | undefined;
23
+ readonly oleShape: boolean;
24
+ }
25
+ /**
26
+ * One worksheet's own OfficeArtDgContainer: the FDG atom (recInstance carrying the drawing identifier, csp counting the patriarch alongside every real shape, spidCur the last shape id this drawing allocated), then the one SpgrContainer holding the patriarch -- an SpContainer whose FSPGR states the all-zero coordinate rectangle and whose FSP carries fGroup|fPatriarch -- followed by one SpContainer per real shape in document order, the order the sheet's Obj records then pair with 1:1. `spidBase` is the first unallocated shape id of the whole drawing group (1024 for the first sheet carrying shapes, Excel's own convention): the patriarch takes it, the real shapes take the following ids, and the caller continues allocating from the returned drawing's own lastSpid.
27
+ *
28
+ * The DgContainer's own further optional children (a SolverContainer, deleted shapes) are omitted: this writer states no solver rules and no deleted shapes, which the container's own production permits.
29
+ */
30
+ declare function writeSheetDrawingBytes(drawingId: number, spidBase: number, entries: readonly SheetShapeEntry[]): Uint8Array<ArrayBuffer>;
31
+ //#endregion
32
+ export { DrawingIdBlock, SheetShapeEntry, StoredBlip, writeDrawingGroupBytes, writeSheetDrawingBytes };
@@ -0,0 +1,32 @@
1
+ import { ShapeAnchor } from "./shapes.js";
2
+ //#region src/drawing/escher-writer.d.ts
3
+ /** One distinct image the workbook's sheets share: its decoded bytes, and how many picture shapes reference it (the FBSE's own cRef, which [MS-ODRAW] defines as the number of references to the BLIP). */
4
+ interface StoredBlip {
5
+ readonly format: "png" | "jpeg";
6
+ readonly fileBytes: Uint8Array<ArrayBuffer>;
7
+ readonly referenceCount: number;
8
+ }
9
+ /** One drawing's own contribution to the drawing group's shape-id state: the drawing identifier its FDG and IDCL both name, and the last shape identifier it allocated. */
10
+ interface DrawingIdBlock {
11
+ readonly drawingId: number;
12
+ readonly lastSpid: number;
13
+ readonly shapeCount: number;
14
+ }
15
+ /**
16
+ * The workbook-wide OfficeArtDggContainer ([MS-ODRAW] 2.2.12, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/dd7133b6-ed10-4bcb-be29-67b0544f884f): a FDGGBlock (the FDGG atom plus one OfficeArtIDCL per drawing, cidcl = drawing count + 1 per 2.2.14's own field definition) followed by the Blip Store when the workbook carries any image. The DggContainer's own optional children this writer has no data for -- drawingPrimaryOptions, colorMRU, splitColors -- are omitted, which the container's own production permits.
17
+ */
18
+ declare function writeDrawingGroupBytes(blips: readonly StoredBlip[], drawings: readonly DrawingIdBlock[]): Uint8Array<ArrayBuffer>;
19
+ /** One real (non-patriarch) shape this writer places on a sheet: its anchor, its 1-based Blip Store reference when it is a picture, and whether it hosts an embedded OLE object (which sets FSP's own fOleShape and takes no pib). */
20
+ interface SheetShapeEntry {
21
+ readonly anchor: ShapeAnchor;
22
+ readonly blipIndex: number | undefined;
23
+ readonly oleShape: boolean;
24
+ }
25
+ /**
26
+ * One worksheet's own OfficeArtDgContainer: the FDG atom (recInstance carrying the drawing identifier, csp counting the patriarch alongside every real shape, spidCur the last shape id this drawing allocated), then the one SpgrContainer holding the patriarch -- an SpContainer whose FSPGR states the all-zero coordinate rectangle and whose FSP carries fGroup|fPatriarch -- followed by one SpContainer per real shape in document order, the order the sheet's Obj records then pair with 1:1. `spidBase` is the first unallocated shape id of the whole drawing group (1024 for the first sheet carrying shapes, Excel's own convention): the patriarch takes it, the real shapes take the following ids, and the caller continues allocating from the returned drawing's own lastSpid.
27
+ *
28
+ * The DgContainer's own further optional children (a SolverContainer, deleted shapes) are omitted: this writer states no solver rules and no deleted shapes, which the container's own production permits.
29
+ */
30
+ declare function writeSheetDrawingBytes(drawingId: number, spidBase: number, entries: readonly SheetShapeEntry[]): Uint8Array<ArrayBuffer>;
31
+ //#endregion
32
+ export { DrawingIdBlock, SheetShapeEntry, StoredBlip, writeDrawingGroupBytes, writeSheetDrawingBytes };
@@ -0,0 +1,105 @@
1
+ import { RecordBuilder } from "../biff/builder.js";
2
+ import { BiffWriteError } from "../biff/write-errors.js";
3
+ import { ESCHER_BSE, ESCHER_BSTORE_CONTAINER, ESCHER_CLIENT_ANCHOR, ESCHER_CLIENT_DATA, ESCHER_DGG_CONTAINER, ESCHER_DG_CONTAINER, ESCHER_FSPGR, ESCHER_OPT, ESCHER_SP, ESCHER_SPGR_CONTAINER, ESCHER_SP_CONTAINER } from "./escher-constants.js";
4
+ import { md4 } from "./md4.js";
5
+ //#region src/drawing/escher-writer.ts
6
+ /** One Escher atom's own bytes: header plus `data` verbatim. */
7
+ function escherAtom(recVer, recInstance, recType, data) {
8
+ return new RecordBuilder().u16(recVer & 15 | (recInstance & 4095) << 4).u16(recType).u32(data.length).bytes(data).build();
9
+ }
10
+ /** One Escher container's own bytes: header (recVer 0xF, [MS-ODRAW] 2.2.1's container marker, in the verInstance word's low nibble) plus its children concatenated -- recLen is then the children's total size with their own headers included, exactly what the format defines. `recInstance` is the verInstance word's upper 12 bits, which every container this writer states pins to 0x000 except the Blip Store, whose own page requires the count of BSE children. */
11
+ function escherContainer(recType, recInstance, children) {
12
+ const body = children.reduce((sum, child) => sum + child.length, 0);
13
+ const builder = new RecordBuilder().u16(15 | (recInstance & 4095) << 4).u16(recType).u32(body);
14
+ for (const child of children) builder.bytes(child);
15
+ return builder.build();
16
+ }
17
+ const MSOBLIP_JPEG = 5;
18
+ const MSOBLIP_PNG = 6;
19
+ const BLIP_PNG_RECTYPE = 61470;
20
+ const BLIP_JPEG_RECTYPE = 61469;
21
+ const BLIP_PNG_INSTANCE_ONE_UID = 1760;
22
+ const BLIP_JPEG_INSTANCE_ONE_UID = 1130;
23
+ /** rgbUid's own fixed size: [MS-ODRAW]'s FBSE and Blip records each open with one 16-byte MD4 digest of the image data. */
24
+ const UID_SIZE = 16;
25
+ function blipFormatFields(format) {
26
+ if (format === "png") return {
27
+ msoBlip: MSOBLIP_PNG,
28
+ recType: BLIP_PNG_RECTYPE,
29
+ recInstance: BLIP_PNG_INSTANCE_ONE_UID
30
+ };
31
+ return {
32
+ msoBlip: MSOBLIP_JPEG,
33
+ recType: BLIP_JPEG_RECTYPE,
34
+ recInstance: BLIP_JPEG_INSTANCE_ONE_UID
35
+ };
36
+ }
37
+ /** One OfficeArtBlipPNG/JPEG record ([MS-ODRAW] 2.2.28/2.2.27): one rgbUid (the MD4 of the file bytes -- a digest of the UNCOMPRESSED blip data per 2.2.28's own field text, which for PNG and JPEG is the file bytes themselves), the tag byte, then the literal file bytes. The tag byte is 0xFF, "internal resource tag" -- the value real producers write for data embedded in the record. */
38
+ function writeBlipRecord(format, uidBytes, fileBytes) {
39
+ const fields = blipFormatFields(format);
40
+ return escherAtom(0, fields.recInstance, fields.recType, new RecordBuilder().bytes(uidBytes).u8(255).bytes(fileBytes).build());
41
+ }
42
+ /** One OfficeArtFBSE ([MS-ODRAW] 2.2.24.1, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/2f2d7f5e-d5c4-4cb7-b230-59b3fe8f10d6): the blip's type pair, its rgbUid, a tag, the embedded blip record's own total size, the reference count, a foDelay this writer always states as "not in a delay stream" alongside an inline embeddedBlip (which [MS-ODRAW] says makes foDelay ignored), the name-length byte (0 -- no name), and the embedded blip record itself. recLen's own rule -- "the size of nameData plus size plus 36" for an embedded blip -- falls out of the fixed fields plus the blip record's length. */
43
+ function writeBseRecord(blip) {
44
+ const fields = blipFormatFields(blip.format);
45
+ const uidBytes = hexToBytes(md4(blip.fileBytes));
46
+ if (uidBytes.length !== UID_SIZE) throw new BiffWriteError(`internal error: md4 produced a ${uidBytes.length}-byte digest, not the ${UID_SIZE} bytes rgbUid ([MS-ODRAW]'s own FBSE/Blip field) requires`);
47
+ const embedded = writeBlipRecord(blip.format, uidBytes, blip.fileBytes);
48
+ const fixed = new RecordBuilder().u8(fields.msoBlip).u8(fields.msoBlip).bytes(uidBytes).u16(255).u32(embedded.length).u32(blip.referenceCount).u32(0).u8(0).u8(0).u8(0).u8(0);
49
+ return escherAtom(2, fields.msoBlip, ESCHER_BSE, new RecordBuilder().bytes(fixed.build()).bytes(embedded).build());
50
+ }
51
+ function hexToBytes(hex) {
52
+ const out = new Uint8Array(hex.length / 2);
53
+ for (let index = 0; index < out.length; index += 1) out[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
54
+ return out;
55
+ }
56
+ /**
57
+ * The workbook-wide OfficeArtDggContainer ([MS-ODRAW] 2.2.12, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/dd7133b6-ed10-4bcb-be29-67b0544f884f): a FDGGBlock (the FDGG atom plus one OfficeArtIDCL per drawing, cidcl = drawing count + 1 per 2.2.14's own field definition) followed by the Blip Store when the workbook carries any image. The DggContainer's own optional children this writer has no data for -- drawingPrimaryOptions, colorMRU, splitColors -- are omitted, which the container's own production permits.
58
+ */
59
+ function writeDrawingGroupBytes(blips, drawings) {
60
+ const spidMax = drawings.reduce((max, drawing) => Math.max(max, drawing.lastSpid), 0);
61
+ const cspSaved = drawings.reduce((sum, drawing) => sum + drawing.shapeCount, 0);
62
+ const fdgg = new RecordBuilder().u32(spidMax).u32(drawings.length + 1).u32(cspSaved).u32(drawings.length);
63
+ for (const drawing of drawings) fdgg.u32(drawing.drawingId).u32(drawing.lastSpid);
64
+ const children = [escherAtom(0, 0, 61446, fdgg.build())];
65
+ if (blips.length > 0) children.push(escherContainer(ESCHER_BSTORE_CONTAINER, blips.length, blips.map((blip) => writeBseRecord(blip))));
66
+ return escherContainer(ESCHER_DGG_CONTAINER, 0, children);
67
+ }
68
+ const FSP_FLAG_OLE_SHAPE = 16;
69
+ /** OfficeArtFSP ([MS-ODRAW] 2.2.40, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/8a7e7be3-0582-4461-9400-29d7eda8497d): recVer 0x2, recInstance carrying the shape's own MSOSPT type, then spid and the flags word. Every shape this writer states is a picture frame (MSOSPT 0x4B) -- a picture because it holds an image, an OLE object because [MS-ODRAW]'s own model hosts one through the picture machinery with fOleShape set. */
70
+ function writeFspRecord(spid, flags, shapeType) {
71
+ return escherAtom(2, shapeType, ESCHER_SP, new RecordBuilder().u32(spid).u32(flags >>> 0).build());
72
+ }
73
+ /** OfficeArtFOPT ([MS-ODRAW] 2.2.9): recVer 0x3, recInstance carrying the property count, then that many 6-byte FOPTE entries (opid, op). The one property this writer states is `pib` -- the picture's own 1-based Blip Store index, opid 0x0104 with fComplex clear. */
74
+ function writePibOptRecord(blipIndex) {
75
+ return escherAtom(3, 1, ESCHER_OPT, new RecordBuilder().u16(260).u32(blipIndex).build());
76
+ }
77
+ /** OfficeArtClientAnchorSheet ([MS-XLS] 2.5.193): recVer 0, recLen 18, a flags word (fMove and fSize both set -- the shape moves and sizes with its cells, the behaviour an image anchored to cells means), then the corner-cell-plus-fractional-offset pair -- eight u16 fields, 18 bytes total (2 for flags + 8*2), matching the record's own declared recLen and drawing/shapes.ts's own readClientAnchor, which reads each of dxL/dyT/dxR/dyB as a 2-byte i16, not a 4-byte i32. dxL/dxR are 1/1024ths of their column's own width, dyT/dyB 1/256ths of their row's own height, both always non-negative in this writer's own range (0-1023, 0-255), so the identical bit pattern u16 writes here is what i16 reads back unchanged. */
78
+ function writeClientAnchorRecord(anchor) {
79
+ return escherAtom(0, 0, ESCHER_CLIENT_ANCHOR, new RecordBuilder().u16(3).u16(anchor.colL).u16(anchor.dxL).u16(anchor.rwT).u16(anchor.dyT).u16(anchor.colR).u16(anchor.dxR).u16(anchor.rwB).u16(anchor.dyB).build());
80
+ }
81
+ /** OfficeArtClientData: an empty atom (recLen 0) whose presence is what tells a reader that the next BIFF record after the MsoDrawing is this shape's own Obj record -- see [MS-XLS] MsoDrawing's own prose, cited on ESCHER_CLIENT_DATA above. */
82
+ function writeClientDataRecord() {
83
+ return escherAtom(0, 0, ESCHER_CLIENT_DATA, /* @__PURE__ */ new Uint8Array(0));
84
+ }
85
+ /** One shape's own SpContainer ([MS-ODRAW] 2.2.14, https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/16194cb9-b4b0-476c-9678-a6ac1f06b034): shapeProp (the FSP), then shapePrimaryOptions only for a picture (the pib property table), then the clientAnchor and the clientData -- the reader's own SpContainer walk reads exactly these atoms and no others. */
86
+ function writeShapeContainer(spid, entry) {
87
+ const children = [writeFspRecord(spid, (entry.oleShape ? FSP_FLAG_OLE_SHAPE : 0) | 2560, 75)];
88
+ if (entry.blipIndex !== void 0) children.push(writePibOptRecord(entry.blipIndex));
89
+ children.push(writeClientAnchorRecord(entry.anchor), writeClientDataRecord());
90
+ return escherContainer(ESCHER_SP_CONTAINER, 0, children);
91
+ }
92
+ /**
93
+ * One worksheet's own OfficeArtDgContainer: the FDG atom (recInstance carrying the drawing identifier, csp counting the patriarch alongside every real shape, spidCur the last shape id this drawing allocated), then the one SpgrContainer holding the patriarch -- an SpContainer whose FSPGR states the all-zero coordinate rectangle and whose FSP carries fGroup|fPatriarch -- followed by one SpContainer per real shape in document order, the order the sheet's Obj records then pair with 1:1. `spidBase` is the first unallocated shape id of the whole drawing group (1024 for the first sheet carrying shapes, Excel's own convention): the patriarch takes it, the real shapes take the following ids, and the caller continues allocating from the returned drawing's own lastSpid.
94
+ *
95
+ * The DgContainer's own further optional children (a SolverContainer, deleted shapes) are omitted: this writer states no solver rules and no deleted shapes, which the container's own production permits.
96
+ */
97
+ function writeSheetDrawingBytes(drawingId, spidBase, entries) {
98
+ const lastSpid = spidBase + entries.length;
99
+ const fdg = escherAtom(0, drawingId, 61448, new RecordBuilder().u32(entries.length + 1).u32(lastSpid).build());
100
+ const patriarch = escherContainer(ESCHER_SP_CONTAINER, 0, [escherAtom(0, 0, ESCHER_FSPGR, /* @__PURE__ */ new Uint8Array(16)), writeFspRecord(spidBase, 5, 0)]);
101
+ const spgr = escherContainer(ESCHER_SPGR_CONTAINER, 0, [patriarch, ...entries.map((entry, index) => writeShapeContainer(spidBase + index + 1, entry))]);
102
+ return escherContainer(ESCHER_DG_CONTAINER, 0, [fdg, spgr]);
103
+ }
104
+ //#endregion
105
+ export { writeDrawingGroupBytes, writeSheetDrawingBytes };
@@ -0,0 +1,146 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/drawing/md4.ts
3
+ /** RFC 1320 3.3's own round constants: "0x5A827999" and "0x6ED9EBA1", the integer parts the spec spells out for rounds 2 and 3. */
4
+ const ROUND_2_CONSTANT = 1518500249;
5
+ const ROUND_3_CONSTANT = 1859775393;
6
+ /** RFC 1320 2.2: "Let A = 0x67452301, B = 0xefcdab89, C = 0x98badcfe, D = 0x10325476". */
7
+ const INITIAL_A = 1732584193;
8
+ const INITIAL_B = 4023233417;
9
+ const INITIAL_C = 2562383102;
10
+ const INITIAL_D = 271733878;
11
+ const BLOCK_SIZE = 64;
12
+ /** The three auxiliary functions of RFC 1320 2.2, each a bit-selection over x/y/z -- G and H are MD4's own, not MD5's similarly-named ones. */
13
+ function f(x, y, z) {
14
+ return x & y | ~x & z;
15
+ }
16
+ function g(x, y, z) {
17
+ return x & y | x & z | y & z;
18
+ }
19
+ function h(x, y, z) {
20
+ return x ^ y ^ z;
21
+ }
22
+ /** A 32-bit rotate left; the final >>> 0 keeps the result unsigned where << would sign it. */
23
+ function rotateLeft(x, count) {
24
+ return (x << count | x >>> 32 - count) >>> 0;
25
+ }
26
+ /** The padding of RFC 1320 3.1: the message, a single 1 bit, zeros, then the 64-bit little-endian bit length, filling the final block(s) to a 64-byte multiple. */
27
+ function padMessage(message) {
28
+ const bitLength = message.length * 8;
29
+ const paddedLength = Math.ceil((message.length + 1 + 8) / BLOCK_SIZE) * BLOCK_SIZE;
30
+ const out = new Uint8Array(paddedLength);
31
+ out.set(message);
32
+ out[message.length] = 128;
33
+ const view = new DataView(out.buffer);
34
+ view.setUint32(paddedLength - 8, bitLength >>> 0, true);
35
+ view.setUint32(paddedLength - 4, Math.floor(bitLength / 4294967296), true);
36
+ return out;
37
+ }
38
+ /** RFC 1320 A.3's register rotation, restated once: after an operation updates the frame's first register, the frame rotates right so the next operation's target is first again -- exactly the ABCD/DABC/CDAB/BCDA cycling the printed schedule shows. */
39
+ function rotateRegisters(frame, updated) {
40
+ return [
41
+ frame[3],
42
+ updated,
43
+ frame[1],
44
+ frame[2]
45
+ ];
46
+ }
47
+ /**
48
+ * The MD4 digest of `message`, as 32 lowercase hex characters -- the digest bytes in order, which RFC 1320 3.5 states begin with the LOW-order byte of A ("beginning with the low-order byte of A, and ending with the high-order byte of D"), so each register is emitted little-endian rather than as a big-endian hex word.
49
+ */
50
+ function md4(message) {
51
+ const padded = padMessage(message);
52
+ const view = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
53
+ let a = INITIAL_A;
54
+ let b = INITIAL_B;
55
+ let c = INITIAL_C;
56
+ let d = INITIAL_D;
57
+ for (let offset = 0; offset < padded.length; offset += BLOCK_SIZE) {
58
+ const x = [];
59
+ for (let index = 0; index < 16; index += 1) x.push(view.getUint32(offset + index * 4, true));
60
+ const savedA = a;
61
+ const savedB = b;
62
+ const savedC = c;
63
+ const savedD = d;
64
+ const op = (kind, index, rotation, roundConstant) => {
65
+ const word = x[index];
66
+ if (word === void 0) throw new Error(`internal error: MD4 block word ${index} is missing -- x is always filled with all 16 words above before any operation reads it`);
67
+ const updated = rotateLeft(a + kind(b, c, d) + word + roundConstant >>> 0, rotation);
68
+ [a, b, c, d] = rotateRegisters([
69
+ a,
70
+ b,
71
+ c,
72
+ d
73
+ ], updated);
74
+ };
75
+ const ff = (index, rotation) => {
76
+ op(f, index, rotation, 0);
77
+ };
78
+ const gg = (index, rotation) => {
79
+ op(g, index, rotation, ROUND_2_CONSTANT);
80
+ };
81
+ const hh = (index, rotation) => {
82
+ op(h, index, rotation, ROUND_3_CONSTANT);
83
+ };
84
+ ff(0, 3);
85
+ ff(1, 7);
86
+ ff(2, 11);
87
+ ff(3, 19);
88
+ ff(4, 3);
89
+ ff(5, 7);
90
+ ff(6, 11);
91
+ ff(7, 19);
92
+ ff(8, 3);
93
+ ff(9, 7);
94
+ ff(10, 11);
95
+ ff(11, 19);
96
+ ff(12, 3);
97
+ ff(13, 7);
98
+ ff(14, 11);
99
+ ff(15, 19);
100
+ gg(0, 3);
101
+ gg(4, 5);
102
+ gg(8, 9);
103
+ gg(12, 13);
104
+ gg(1, 3);
105
+ gg(5, 5);
106
+ gg(9, 9);
107
+ gg(13, 13);
108
+ gg(2, 3);
109
+ gg(6, 5);
110
+ gg(10, 9);
111
+ gg(14, 13);
112
+ gg(3, 3);
113
+ gg(7, 5);
114
+ gg(11, 9);
115
+ gg(15, 13);
116
+ hh(0, 3);
117
+ hh(8, 9);
118
+ hh(4, 11);
119
+ hh(12, 15);
120
+ hh(2, 3);
121
+ hh(10, 9);
122
+ hh(6, 11);
123
+ hh(14, 15);
124
+ hh(1, 3);
125
+ hh(9, 9);
126
+ hh(5, 11);
127
+ hh(13, 15);
128
+ hh(3, 3);
129
+ hh(11, 9);
130
+ hh(7, 11);
131
+ hh(15, 15);
132
+ a = a + savedA >>> 0;
133
+ b = b + savedB >>> 0;
134
+ c = c + savedC >>> 0;
135
+ d = d + savedD >>> 0;
136
+ }
137
+ const out = /* @__PURE__ */ new Uint8Array(16);
138
+ const outView = new DataView(out.buffer);
139
+ outView.setUint32(0, a >>> 0, true);
140
+ outView.setUint32(4, b >>> 0, true);
141
+ outView.setUint32(8, c >>> 0, true);
142
+ outView.setUint32(12, d >>> 0, true);
143
+ return Array.from(out, (byte) => byte.toString(16).padStart(2, "0")).join("");
144
+ }
145
+ //#endregion
146
+ exports.md4 = md4;
@@ -0,0 +1,7 @@
1
+ //#region src/drawing/md4.d.ts
2
+ /**
3
+ * The MD4 digest of `message`, as 32 lowercase hex characters -- the digest bytes in order, which RFC 1320 3.5 states begin with the LOW-order byte of A ("beginning with the low-order byte of A, and ending with the high-order byte of D"), so each register is emitted little-endian rather than as a big-endian hex word.
4
+ */
5
+ declare function md4(message: Uint8Array<ArrayBuffer>): string;
6
+ //#endregion
7
+ export { md4 };
@@ -0,0 +1,7 @@
1
+ //#region src/drawing/md4.d.ts
2
+ /**
3
+ * The MD4 digest of `message`, as 32 lowercase hex characters -- the digest bytes in order, which RFC 1320 3.5 states begin with the LOW-order byte of A ("beginning with the low-order byte of A, and ending with the high-order byte of D"), so each register is emitted little-endian rather than as a big-endian hex word.
4
+ */
5
+ declare function md4(message: Uint8Array<ArrayBuffer>): string;
6
+ //#endregion
7
+ export { md4 };
@@ -0,0 +1,145 @@
1
+ //#region src/drawing/md4.ts
2
+ /** RFC 1320 3.3's own round constants: "0x5A827999" and "0x6ED9EBA1", the integer parts the spec spells out for rounds 2 and 3. */
3
+ const ROUND_2_CONSTANT = 1518500249;
4
+ const ROUND_3_CONSTANT = 1859775393;
5
+ /** RFC 1320 2.2: "Let A = 0x67452301, B = 0xefcdab89, C = 0x98badcfe, D = 0x10325476". */
6
+ const INITIAL_A = 1732584193;
7
+ const INITIAL_B = 4023233417;
8
+ const INITIAL_C = 2562383102;
9
+ const INITIAL_D = 271733878;
10
+ const BLOCK_SIZE = 64;
11
+ /** The three auxiliary functions of RFC 1320 2.2, each a bit-selection over x/y/z -- G and H are MD4's own, not MD5's similarly-named ones. */
12
+ function f(x, y, z) {
13
+ return x & y | ~x & z;
14
+ }
15
+ function g(x, y, z) {
16
+ return x & y | x & z | y & z;
17
+ }
18
+ function h(x, y, z) {
19
+ return x ^ y ^ z;
20
+ }
21
+ /** A 32-bit rotate left; the final >>> 0 keeps the result unsigned where << would sign it. */
22
+ function rotateLeft(x, count) {
23
+ return (x << count | x >>> 32 - count) >>> 0;
24
+ }
25
+ /** The padding of RFC 1320 3.1: the message, a single 1 bit, zeros, then the 64-bit little-endian bit length, filling the final block(s) to a 64-byte multiple. */
26
+ function padMessage(message) {
27
+ const bitLength = message.length * 8;
28
+ const paddedLength = Math.ceil((message.length + 1 + 8) / BLOCK_SIZE) * BLOCK_SIZE;
29
+ const out = new Uint8Array(paddedLength);
30
+ out.set(message);
31
+ out[message.length] = 128;
32
+ const view = new DataView(out.buffer);
33
+ view.setUint32(paddedLength - 8, bitLength >>> 0, true);
34
+ view.setUint32(paddedLength - 4, Math.floor(bitLength / 4294967296), true);
35
+ return out;
36
+ }
37
+ /** RFC 1320 A.3's register rotation, restated once: after an operation updates the frame's first register, the frame rotates right so the next operation's target is first again -- exactly the ABCD/DABC/CDAB/BCDA cycling the printed schedule shows. */
38
+ function rotateRegisters(frame, updated) {
39
+ return [
40
+ frame[3],
41
+ updated,
42
+ frame[1],
43
+ frame[2]
44
+ ];
45
+ }
46
+ /**
47
+ * The MD4 digest of `message`, as 32 lowercase hex characters -- the digest bytes in order, which RFC 1320 3.5 states begin with the LOW-order byte of A ("beginning with the low-order byte of A, and ending with the high-order byte of D"), so each register is emitted little-endian rather than as a big-endian hex word.
48
+ */
49
+ function md4(message) {
50
+ const padded = padMessage(message);
51
+ const view = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
52
+ let a = INITIAL_A;
53
+ let b = INITIAL_B;
54
+ let c = INITIAL_C;
55
+ let d = INITIAL_D;
56
+ for (let offset = 0; offset < padded.length; offset += BLOCK_SIZE) {
57
+ const x = [];
58
+ for (let index = 0; index < 16; index += 1) x.push(view.getUint32(offset + index * 4, true));
59
+ const savedA = a;
60
+ const savedB = b;
61
+ const savedC = c;
62
+ const savedD = d;
63
+ const op = (kind, index, rotation, roundConstant) => {
64
+ const word = x[index];
65
+ if (word === void 0) throw new Error(`internal error: MD4 block word ${index} is missing -- x is always filled with all 16 words above before any operation reads it`);
66
+ const updated = rotateLeft(a + kind(b, c, d) + word + roundConstant >>> 0, rotation);
67
+ [a, b, c, d] = rotateRegisters([
68
+ a,
69
+ b,
70
+ c,
71
+ d
72
+ ], updated);
73
+ };
74
+ const ff = (index, rotation) => {
75
+ op(f, index, rotation, 0);
76
+ };
77
+ const gg = (index, rotation) => {
78
+ op(g, index, rotation, ROUND_2_CONSTANT);
79
+ };
80
+ const hh = (index, rotation) => {
81
+ op(h, index, rotation, ROUND_3_CONSTANT);
82
+ };
83
+ ff(0, 3);
84
+ ff(1, 7);
85
+ ff(2, 11);
86
+ ff(3, 19);
87
+ ff(4, 3);
88
+ ff(5, 7);
89
+ ff(6, 11);
90
+ ff(7, 19);
91
+ ff(8, 3);
92
+ ff(9, 7);
93
+ ff(10, 11);
94
+ ff(11, 19);
95
+ ff(12, 3);
96
+ ff(13, 7);
97
+ ff(14, 11);
98
+ ff(15, 19);
99
+ gg(0, 3);
100
+ gg(4, 5);
101
+ gg(8, 9);
102
+ gg(12, 13);
103
+ gg(1, 3);
104
+ gg(5, 5);
105
+ gg(9, 9);
106
+ gg(13, 13);
107
+ gg(2, 3);
108
+ gg(6, 5);
109
+ gg(10, 9);
110
+ gg(14, 13);
111
+ gg(3, 3);
112
+ gg(7, 5);
113
+ gg(11, 9);
114
+ gg(15, 13);
115
+ hh(0, 3);
116
+ hh(8, 9);
117
+ hh(4, 11);
118
+ hh(12, 15);
119
+ hh(2, 3);
120
+ hh(10, 9);
121
+ hh(6, 11);
122
+ hh(14, 15);
123
+ hh(1, 3);
124
+ hh(9, 9);
125
+ hh(5, 11);
126
+ hh(13, 15);
127
+ hh(3, 3);
128
+ hh(11, 9);
129
+ hh(7, 11);
130
+ hh(15, 15);
131
+ a = a + savedA >>> 0;
132
+ b = b + savedB >>> 0;
133
+ c = c + savedC >>> 0;
134
+ d = d + savedD >>> 0;
135
+ }
136
+ const out = /* @__PURE__ */ new Uint8Array(16);
137
+ const outView = new DataView(out.buffer);
138
+ outView.setUint32(0, a >>> 0, true);
139
+ outView.setUint32(4, b >>> 0, true);
140
+ outView.setUint32(8, c >>> 0, true);
141
+ outView.setUint32(12, d >>> 0, true);
142
+ return Array.from(out, (byte) => byte.toString(16).padStart(2, "0")).join("");
143
+ }
144
+ //#endregion
145
+ export { md4 };
@@ -0,0 +1,19 @@
1
+ import { ContentSheet } from "document-schema.js";
2
+ //#region src/workbook/drawing-writer.d.ts
3
+ /** One sheet's own drawing records, positioned into the worksheet substream's OBJECTS section by sheet-writer.ts. Empty arrays when the sheet carries no shapes at all -- a sheet with nothing to draw writes no MsoDrawing and no Obj, staying as minimal as it always was. */
4
+ interface SheetDrawingWrite {
5
+ readonly msoDrawingRecords: readonly Uint8Array<ArrayBuffer>[];
6
+ readonly objRecords: readonly Uint8Array<ArrayBuffer>[];
7
+ }
8
+ /** The workbook-wide drawing plan: the drawing-group Escher bytes the globals substream's MsoDrawingGroup record carries (undefined when no sheet carries shapes, in which case no such record is written at all), one drawing write per sheet, and the Embedding Storage streams the outer compound file carries beside the Workbook stream. */
9
+ interface DrawingWritePlan {
10
+ readonly drawingGroupBytes: Uint8Array<ArrayBuffer> | undefined;
11
+ readonly sheetDrawings: readonly SheetDrawingWrite[];
12
+ readonly embeddingStreams: readonly {
13
+ readonly path: string;
14
+ readonly bytes: Uint8Array<ArrayBuffer>;
15
+ }[];
16
+ }
17
+ declare function buildDrawingWritePlan(sheets: readonly ContentSheet[]): DrawingWritePlan;
18
+ //#endregion
19
+ export { SheetDrawingWrite as n, buildDrawingWritePlan as r, DrawingWritePlan as t };
@@ -0,0 +1,19 @@
1
+ import { ContentSheet } from "document-schema.js";
2
+ //#region src/workbook/drawing-writer.d.ts
3
+ /** One sheet's own drawing records, positioned into the worksheet substream's OBJECTS section by sheet-writer.ts. Empty arrays when the sheet carries no shapes at all -- a sheet with nothing to draw writes no MsoDrawing and no Obj, staying as minimal as it always was. */
4
+ interface SheetDrawingWrite {
5
+ readonly msoDrawingRecords: readonly Uint8Array<ArrayBuffer>[];
6
+ readonly objRecords: readonly Uint8Array<ArrayBuffer>[];
7
+ }
8
+ /** The workbook-wide drawing plan: the drawing-group Escher bytes the globals substream's MsoDrawingGroup record carries (undefined when no sheet carries shapes, in which case no such record is written at all), one drawing write per sheet, and the Embedding Storage streams the outer compound file carries beside the Workbook stream. */
9
+ interface DrawingWritePlan {
10
+ readonly drawingGroupBytes: Uint8Array<ArrayBuffer> | undefined;
11
+ readonly sheetDrawings: readonly SheetDrawingWrite[];
12
+ readonly embeddingStreams: readonly {
13
+ readonly path: string;
14
+ readonly bytes: Uint8Array<ArrayBuffer>;
15
+ }[];
16
+ }
17
+ declare function buildDrawingWritePlan(sheets: readonly ContentSheet[]): DrawingWritePlan;
18
+ //#endregion
19
+ export { SheetDrawingWrite as n, buildDrawingWritePlan as r, DrawingWritePlan as t };
package/dist/index.cjs CHANGED
@@ -149,6 +149,7 @@ exports.writeCellXfRecord = require_biff_xf_writer.writeCellXfRecord;
149
149
  exports.writeFormatRecord = require_biff_xf_writer.writeFormatRecord;
150
150
  exports.writePaletteRecord = require_biff_xf_writer.writePaletteRecord;
151
151
  exports.writeRecord = require_biff_record_writer.writeRecord;
152
+ exports.writeRecordChain = require_biff_record_writer.writeRecordChain;
152
153
  exports.writeRichExtendedString = require_biff_string_writer.writeRichExtendedString;
153
154
  exports.writeShortXLUnicodeString = require_biff_string_writer.writeShortXLUnicodeString;
154
155
  exports.writeStyleRecord = require_biff_xf_writer.writeStyleRecord;