doc-codec 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -25
- package/dist/base64.cjs +48 -0
- package/dist/base64.d.cts +5 -0
- package/dist/base64.d.ts +5 -0
- package/dist/base64.js +46 -0
- package/dist/data-stream-BLCj4-V1.d.cts +11 -0
- package/dist/data-stream-BLCj4-V1.d.ts +11 -0
- package/dist/data-stream.cjs +25 -0
- package/dist/data-stream.d.cts +2 -0
- package/dist/data-stream.d.ts +2 -0
- package/dist/data-stream.js +24 -0
- package/dist/index.cjs +5 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/pictures-write.cjs +85 -0
- package/dist/pictures-write.d.cts +12 -0
- package/dist/pictures-write.d.ts +12 -0
- package/dist/pictures-write.js +84 -0
- package/dist/pictures.cjs +3 -16
- package/dist/pictures.js +3 -16
- package/dist/prop/sep-write.cjs +16 -9
- package/dist/prop/sep-write.d.cts +2 -2
- package/dist/prop/sep-write.d.ts +2 -2
- package/dist/prop/sep-write.js +16 -9
- package/dist/table/write.cjs +28 -3
- package/dist/table/write.d.cts +2 -2
- package/dist/table/write.d.ts +2 -2
- package/dist/table/write.js +28 -3
- package/dist/{write-SN_aIwyF.d.ts → write-CMB3qF4i.d.cts} +9 -3
- package/dist/{write-SN_aIwyF.d.cts → write-t4rFgnA-.d.ts} +9 -3
- package/dist/write.cjs +65 -17
- package/dist/write.d.cts +1 -1
- package/dist/write.d.ts +1 -1
- package/dist/write.js +66 -18
- package/package.json +1 -1
package/dist/write.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_errors = require("./errors.cjs");
|
|
3
|
+
const require_data_stream = require("./data-stream.cjs");
|
|
3
4
|
const require_detect = require("./detect.cjs");
|
|
4
5
|
require("./prop/fkp.cjs");
|
|
5
6
|
const require_style_stsh = require("./style/stsh.cjs");
|
|
@@ -22,16 +23,22 @@ const TEXT_FC = 1024;
|
|
|
22
23
|
const BYTES_PER_CHARACTER = 2;
|
|
23
24
|
function writeDocContent(document, options = {}) {
|
|
24
25
|
if (document.kind !== "wordprocessing") throw new require_errors.DocUnsupportedError(`doc-codec writes wordprocessing documents only; got a '${document.kind}' document`);
|
|
25
|
-
if (document.sections.length
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
properties: {},
|
|
32
|
-
extraGrpprl: [],
|
|
33
|
-
terminator: 13
|
|
26
|
+
if (document.sections.length === 0) throw new require_errors.DocFormatError("a wordprocessing document must carry at least one section");
|
|
27
|
+
const dataStream = new require_data_stream.DataStreamBuilder();
|
|
28
|
+
const sectionParagraphLists = document.sections.map((section, index) => {
|
|
29
|
+
const paragraphs = require_table_write.flattenSectionBlocks(section.blocks, dataStream, options.onWarning);
|
|
30
|
+
closeSection(paragraphs, index === document.sections.length - 1 ? 13 : 12);
|
|
31
|
+
return paragraphs;
|
|
34
32
|
});
|
|
33
|
+
const sectionStartIndices = [];
|
|
34
|
+
{
|
|
35
|
+
let runningIndex = 0;
|
|
36
|
+
for (const paragraphs of sectionParagraphLists) {
|
|
37
|
+
sectionStartIndices.push(runningIndex);
|
|
38
|
+
runningIndex += paragraphs.length;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const writeParagraphs = sectionParagraphLists.flat();
|
|
35
42
|
const FIRST_NON_HEADING_ISTD = 10;
|
|
36
43
|
const MAX_HEADING_ISTD = 9;
|
|
37
44
|
const styleNames = /* @__PURE__ */ new Map();
|
|
@@ -72,9 +79,9 @@ function writeDocContent(document, options = {}) {
|
|
|
72
79
|
};
|
|
73
80
|
const numberingTables = require_list_numbering_write.buildNumberingTables(listUsage.definitions);
|
|
74
81
|
const formatted = writeParagraphs.map((entry) => ({
|
|
75
|
-
runs: entry.runs.map((
|
|
76
|
-
text: run.text,
|
|
77
|
-
grpprl: require_prop_chp_write.encodeCharacterGrpprl(run, fontIndexOf)
|
|
82
|
+
runs: entry.runs.map((writeRun) => ({
|
|
83
|
+
text: writeRun.run.text,
|
|
84
|
+
grpprl: [...require_prop_chp_write.encodeCharacterGrpprl(writeRun.run, fontIndexOf), ...writeRun.extraGrpprl]
|
|
78
85
|
})),
|
|
79
86
|
grpprl: [...require_prop_pap_write.encodeParagraphGrpprl(entry.properties, ilfoOf), ...entry.extraGrpprl]
|
|
80
87
|
}));
|
|
@@ -132,9 +139,20 @@ function writeDocContent(document, options = {}) {
|
|
|
132
139
|
};
|
|
133
140
|
});
|
|
134
141
|
const papxPages = require_prop_fkp_write.buildPapxPages(papxParagraphSpecs, textFcLim);
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
const
|
|
142
|
+
const sepxPageStart = (papxPageStart + papxPages.length) * 512;
|
|
143
|
+
const sepxList = document.sections.map((section) => require_prop_sep_write.buildSepx(require_prop_sep_write.encodeSectionGrpprl(section)));
|
|
144
|
+
const fcSepxList = [];
|
|
145
|
+
{
|
|
146
|
+
let sepxCursor = sepxPageStart;
|
|
147
|
+
for (const sepx of sepxList) {
|
|
148
|
+
fcSepxList.push(sepxCursor);
|
|
149
|
+
sepxCursor += sepx.length;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const lastFcSepx = fcSepxList[fcSepxList.length - 1];
|
|
153
|
+
const lastSepx = sepxList[sepxList.length - 1];
|
|
154
|
+
if (lastFcSepx === void 0 || lastSepx === void 0) throw new require_errors.DocFormatError("internal defect: writeDocContent built an empty section list despite the earlier at-least-one-section guard");
|
|
155
|
+
const wordDocument = new Uint8Array(lastFcSepx + lastSepx.length);
|
|
138
156
|
const wordView = new DataView(wordDocument.buffer);
|
|
139
157
|
for (let index = 0; index < text.length; index += 1) wordView.setUint16(characterFc(index), text.charCodeAt(index), true);
|
|
140
158
|
chpxPages.forEach((page, index) => {
|
|
@@ -143,13 +161,22 @@ function writeDocContent(document, options = {}) {
|
|
|
143
161
|
papxPages.forEach((page, index) => {
|
|
144
162
|
wordDocument.set(page, (papxPageStart + index) * 512);
|
|
145
163
|
});
|
|
146
|
-
|
|
164
|
+
sepxList.forEach((sepx, index) => {
|
|
165
|
+
const fcSepx = fcSepxList[index];
|
|
166
|
+
if (fcSepx === void 0) throw new require_errors.DocFormatError(`internal defect: writeDocContent lost section ${String(index)}'s own Sepx placement`);
|
|
167
|
+
wordDocument.set(sepx, fcSepx);
|
|
168
|
+
});
|
|
169
|
+
const sectionStartCps = sectionStartIndices.map((paragraphIndex, index) => {
|
|
170
|
+
const startCp = paragraphStarts[paragraphIndex];
|
|
171
|
+
if (startCp === void 0) throw new require_errors.DocFormatError(`internal defect: writeDocContent lost section ${String(index)}'s own start CP`);
|
|
172
|
+
return startCp;
|
|
173
|
+
});
|
|
147
174
|
const clx = require_text_piece_table_write.buildTextClx(text.length, TEXT_FC);
|
|
148
175
|
const chpxBinTable = require_prop_fkp_write.buildPropertyBinTable([...chpxPages.map(require_prop_fkp_write.firstFcOfPage), textFcLim], chpxPages.map((_, index) => chpxPageStart + index));
|
|
149
176
|
const papxBinTable = require_prop_fkp_write.buildPropertyBinTable([...papxPages.map(require_prop_fkp_write.firstFcOfPage), textFcLim], papxPages.map((_, index) => papxPageStart + index));
|
|
150
177
|
const stsh = require_style_stsh.buildStshForStyles(styleNames);
|
|
151
178
|
const fontTable = fontNames.length > 0 ? require_style_fonts.buildFontTable(fontNames) : void 0;
|
|
152
|
-
const plcfSed = require_prop_sep_write.buildPlcfSed(text.length,
|
|
179
|
+
const plcfSed = require_prop_sep_write.buildPlcfSed(sectionStartCps, text.length, fcSepxList);
|
|
153
180
|
let cursor = 0;
|
|
154
181
|
const place = (bytes) => {
|
|
155
182
|
const offset = cursor;
|
|
@@ -207,11 +234,32 @@ function writeDocContent(document, options = {}) {
|
|
|
207
234
|
path: require_detect.SUMMARY_INFORMATION_STREAM,
|
|
208
235
|
bytes: (0, archive_codec.writeSummaryInformationStream)(require_metadata.layoutMetadataToSummaryInformation(document.metadata))
|
|
209
236
|
});
|
|
237
|
+
const dataStreamBytes = dataStream.build();
|
|
238
|
+
if (dataStreamBytes.length > 0) streams.push({
|
|
239
|
+
path: require_detect.DATA_STREAM,
|
|
240
|
+
bytes: dataStreamBytes
|
|
241
|
+
});
|
|
210
242
|
return (0, archive_codec.writeCompoundFile)(streams);
|
|
211
243
|
}
|
|
212
244
|
function sameGrpprl(a, b) {
|
|
213
245
|
if (a === void 0 || b === void 0) return a === b;
|
|
214
246
|
return a.length === b.length && a.every((byte, index) => byte === b[index]);
|
|
215
247
|
}
|
|
248
|
+
function closeSection(paragraphs, terminator) {
|
|
249
|
+
if (paragraphs[paragraphs.length - 1]?.terminator !== 13) paragraphs.push({
|
|
250
|
+
runs: [],
|
|
251
|
+
properties: {},
|
|
252
|
+
extraGrpprl: [],
|
|
253
|
+
terminator: 13
|
|
254
|
+
});
|
|
255
|
+
if (terminator === 13) return;
|
|
256
|
+
const index = paragraphs.length - 1;
|
|
257
|
+
const target = paragraphs[index];
|
|
258
|
+
if (target === void 0) throw new require_errors.DocFormatError("internal defect: closeSection lost its own just-ensured trailing paragraph");
|
|
259
|
+
paragraphs[index] = {
|
|
260
|
+
...target,
|
|
261
|
+
terminator
|
|
262
|
+
};
|
|
263
|
+
}
|
|
216
264
|
//#endregion
|
|
217
265
|
exports.writeDocContent = writeDocContent;
|
package/dist/write.d.cts
CHANGED
package/dist/write.d.ts
CHANGED
package/dist/write.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DocFormatError, DocUnsupportedError } from "./errors.js";
|
|
2
|
-
import {
|
|
2
|
+
import { DataStreamBuilder } from "./data-stream.js";
|
|
3
|
+
import { DATA_STREAM, SUMMARY_INFORMATION_STREAM, WORD_DOCUMENT_STREAM } from "./detect.js";
|
|
3
4
|
import "./prop/fkp.js";
|
|
4
5
|
import { buildStshForStyles } from "./style/stsh.js";
|
|
5
6
|
import "./text/special.js";
|
|
@@ -21,16 +22,22 @@ const TEXT_FC = 1024;
|
|
|
21
22
|
const BYTES_PER_CHARACTER = 2;
|
|
22
23
|
function writeDocContent(document, options = {}) {
|
|
23
24
|
if (document.kind !== "wordprocessing") throw new DocUnsupportedError(`doc-codec writes wordprocessing documents only; got a '${document.kind}' document`);
|
|
24
|
-
if (document.sections.length
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
properties: {},
|
|
31
|
-
extraGrpprl: [],
|
|
32
|
-
terminator: 13
|
|
25
|
+
if (document.sections.length === 0) throw new DocFormatError("a wordprocessing document must carry at least one section");
|
|
26
|
+
const dataStream = new DataStreamBuilder();
|
|
27
|
+
const sectionParagraphLists = document.sections.map((section, index) => {
|
|
28
|
+
const paragraphs = flattenSectionBlocks(section.blocks, dataStream, options.onWarning);
|
|
29
|
+
closeSection(paragraphs, index === document.sections.length - 1 ? 13 : 12);
|
|
30
|
+
return paragraphs;
|
|
33
31
|
});
|
|
32
|
+
const sectionStartIndices = [];
|
|
33
|
+
{
|
|
34
|
+
let runningIndex = 0;
|
|
35
|
+
for (const paragraphs of sectionParagraphLists) {
|
|
36
|
+
sectionStartIndices.push(runningIndex);
|
|
37
|
+
runningIndex += paragraphs.length;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const writeParagraphs = sectionParagraphLists.flat();
|
|
34
41
|
const FIRST_NON_HEADING_ISTD = 10;
|
|
35
42
|
const MAX_HEADING_ISTD = 9;
|
|
36
43
|
const styleNames = /* @__PURE__ */ new Map();
|
|
@@ -71,9 +78,9 @@ function writeDocContent(document, options = {}) {
|
|
|
71
78
|
};
|
|
72
79
|
const numberingTables = buildNumberingTables(listUsage.definitions);
|
|
73
80
|
const formatted = writeParagraphs.map((entry) => ({
|
|
74
|
-
runs: entry.runs.map((
|
|
75
|
-
text: run.text,
|
|
76
|
-
grpprl: encodeCharacterGrpprl(run, fontIndexOf)
|
|
81
|
+
runs: entry.runs.map((writeRun) => ({
|
|
82
|
+
text: writeRun.run.text,
|
|
83
|
+
grpprl: [...encodeCharacterGrpprl(writeRun.run, fontIndexOf), ...writeRun.extraGrpprl]
|
|
77
84
|
})),
|
|
78
85
|
grpprl: [...encodeParagraphGrpprl(entry.properties, ilfoOf), ...entry.extraGrpprl]
|
|
79
86
|
}));
|
|
@@ -131,9 +138,20 @@ function writeDocContent(document, options = {}) {
|
|
|
131
138
|
};
|
|
132
139
|
});
|
|
133
140
|
const papxPages = buildPapxPages(papxParagraphSpecs, textFcLim);
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
const
|
|
141
|
+
const sepxPageStart = (papxPageStart + papxPages.length) * 512;
|
|
142
|
+
const sepxList = document.sections.map((section) => buildSepx(encodeSectionGrpprl(section)));
|
|
143
|
+
const fcSepxList = [];
|
|
144
|
+
{
|
|
145
|
+
let sepxCursor = sepxPageStart;
|
|
146
|
+
for (const sepx of sepxList) {
|
|
147
|
+
fcSepxList.push(sepxCursor);
|
|
148
|
+
sepxCursor += sepx.length;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const lastFcSepx = fcSepxList[fcSepxList.length - 1];
|
|
152
|
+
const lastSepx = sepxList[sepxList.length - 1];
|
|
153
|
+
if (lastFcSepx === void 0 || lastSepx === void 0) throw new DocFormatError("internal defect: writeDocContent built an empty section list despite the earlier at-least-one-section guard");
|
|
154
|
+
const wordDocument = new Uint8Array(lastFcSepx + lastSepx.length);
|
|
137
155
|
const wordView = new DataView(wordDocument.buffer);
|
|
138
156
|
for (let index = 0; index < text.length; index += 1) wordView.setUint16(characterFc(index), text.charCodeAt(index), true);
|
|
139
157
|
chpxPages.forEach((page, index) => {
|
|
@@ -142,13 +160,22 @@ function writeDocContent(document, options = {}) {
|
|
|
142
160
|
papxPages.forEach((page, index) => {
|
|
143
161
|
wordDocument.set(page, (papxPageStart + index) * 512);
|
|
144
162
|
});
|
|
145
|
-
|
|
163
|
+
sepxList.forEach((sepx, index) => {
|
|
164
|
+
const fcSepx = fcSepxList[index];
|
|
165
|
+
if (fcSepx === void 0) throw new DocFormatError(`internal defect: writeDocContent lost section ${String(index)}'s own Sepx placement`);
|
|
166
|
+
wordDocument.set(sepx, fcSepx);
|
|
167
|
+
});
|
|
168
|
+
const sectionStartCps = sectionStartIndices.map((paragraphIndex, index) => {
|
|
169
|
+
const startCp = paragraphStarts[paragraphIndex];
|
|
170
|
+
if (startCp === void 0) throw new DocFormatError(`internal defect: writeDocContent lost section ${String(index)}'s own start CP`);
|
|
171
|
+
return startCp;
|
|
172
|
+
});
|
|
146
173
|
const clx = buildTextClx(text.length, TEXT_FC);
|
|
147
174
|
const chpxBinTable = buildPropertyBinTable([...chpxPages.map(firstFcOfPage), textFcLim], chpxPages.map((_, index) => chpxPageStart + index));
|
|
148
175
|
const papxBinTable = buildPropertyBinTable([...papxPages.map(firstFcOfPage), textFcLim], papxPages.map((_, index) => papxPageStart + index));
|
|
149
176
|
const stsh = buildStshForStyles(styleNames);
|
|
150
177
|
const fontTable = fontNames.length > 0 ? buildFontTable(fontNames) : void 0;
|
|
151
|
-
const plcfSed = buildPlcfSed(text.length,
|
|
178
|
+
const plcfSed = buildPlcfSed(sectionStartCps, text.length, fcSepxList);
|
|
152
179
|
let cursor = 0;
|
|
153
180
|
const place = (bytes) => {
|
|
154
181
|
const offset = cursor;
|
|
@@ -206,11 +233,32 @@ function writeDocContent(document, options = {}) {
|
|
|
206
233
|
path: SUMMARY_INFORMATION_STREAM,
|
|
207
234
|
bytes: writeSummaryInformationStream(layoutMetadataToSummaryInformation$1(document.metadata))
|
|
208
235
|
});
|
|
236
|
+
const dataStreamBytes = dataStream.build();
|
|
237
|
+
if (dataStreamBytes.length > 0) streams.push({
|
|
238
|
+
path: DATA_STREAM,
|
|
239
|
+
bytes: dataStreamBytes
|
|
240
|
+
});
|
|
209
241
|
return writeCompoundFile(streams);
|
|
210
242
|
}
|
|
211
243
|
function sameGrpprl(a, b) {
|
|
212
244
|
if (a === void 0 || b === void 0) return a === b;
|
|
213
245
|
return a.length === b.length && a.every((byte, index) => byte === b[index]);
|
|
214
246
|
}
|
|
247
|
+
function closeSection(paragraphs, terminator) {
|
|
248
|
+
if (paragraphs[paragraphs.length - 1]?.terminator !== 13) paragraphs.push({
|
|
249
|
+
runs: [],
|
|
250
|
+
properties: {},
|
|
251
|
+
extraGrpprl: [],
|
|
252
|
+
terminator: 13
|
|
253
|
+
});
|
|
254
|
+
if (terminator === 13) return;
|
|
255
|
+
const index = paragraphs.length - 1;
|
|
256
|
+
const target = paragraphs[index];
|
|
257
|
+
if (target === void 0) throw new DocFormatError("internal defect: closeSection lost its own just-ensured trailing paragraph");
|
|
258
|
+
paragraphs[index] = {
|
|
259
|
+
...target,
|
|
260
|
+
terminator
|
|
261
|
+
};
|
|
262
|
+
}
|
|
215
263
|
//#endregion
|
|
216
264
|
export { writeDocContent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doc-codec",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "A hand-written reader for the Word Binary File Format ([MS-DOC], .doc) against the shared document-schema.js content pivot: FIB parsing, piece-table text reconstruction, and CHPX/PAPX formatting exceptions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|