xls-codec 0.0.0 → 1.0.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.
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/biff/cursor.cjs +73 -0
- package/dist/biff/cursor.d.cts +28 -0
- package/dist/biff/cursor.d.ts +28 -0
- package/dist/biff/cursor.js +72 -0
- package/dist/biff/errors.cjs +18 -0
- package/dist/biff/errors.d.cts +5 -0
- package/dist/biff/errors.d.ts +5 -0
- package/dist/biff/errors.js +17 -0
- package/dist/biff/record-types.cjs +108 -0
- package/dist/biff/record-types.d.cts +73 -0
- package/dist/biff/record-types.d.ts +73 -0
- package/dist/biff/record-types.js +73 -0
- package/dist/biff/records.cjs +40 -0
- package/dist/biff/records.d.cts +2 -0
- package/dist/biff/records.d.ts +2 -0
- package/dist/biff/records.js +38 -0
- package/dist/biff/rk.cjs +29 -0
- package/dist/biff/rk.d.cts +5 -0
- package/dist/biff/rk.d.ts +5 -0
- package/dist/biff/rk.js +28 -0
- package/dist/biff/strings.cjs +66 -0
- package/dist/biff/strings.d.cts +14 -0
- package/dist/biff/strings.d.ts +14 -0
- package/dist/biff/strings.js +63 -0
- package/dist/biff/substreams.cjs +71 -0
- package/dist/biff/substreams.d.cts +21 -0
- package/dist/biff/substreams.d.ts +21 -0
- package/dist/biff/substreams.js +69 -0
- package/dist/container.cjs +46 -0
- package/dist/container.d.cts +15 -0
- package/dist/container.d.ts +15 -0
- package/dist/container.js +44 -0
- package/dist/content.cjs +230 -0
- package/dist/content.d.cts +20 -0
- package/dist/content.d.ts +20 -0
- package/dist/content.js +228 -0
- package/dist/index.cjs +74 -0
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +15 -0
- package/dist/number-format.cjs +298 -0
- package/dist/number-format.d.cts +32 -0
- package/dist/number-format.d.ts +32 -0
- package/dist/number-format.js +296 -0
- package/dist/records-DVIqXFKk.d.cts +20 -0
- package/dist/records-DVIqXFKk.d.ts +20 -0
- package/dist/serial.cjs +62 -0
- package/dist/serial.d.cts +7 -0
- package/dist/serial.d.ts +7 -0
- package/dist/serial.js +59 -0
- package/dist/units.cjs +30 -0
- package/dist/units.d.cts +11 -0
- package/dist/units.d.ts +11 -0
- package/dist/units.js +28 -0
- package/dist/workbook/globals.cjs +106 -0
- package/dist/workbook/globals.d.cts +45 -0
- package/dist/workbook/globals.d.ts +45 -0
- package/dist/workbook/globals.js +104 -0
- package/dist/workbook/sheet.cjs +372 -0
- package/dist/workbook/sheet.d.cts +58 -0
- package/dist/workbook/sheet.d.ts +58 -0
- package/dist/workbook/sheet.js +371 -0
- package/package.json +85 -2
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region src/biff/record-types.d.ts
|
|
2
|
+
/** Marks the beginning of a substream and names its document type ([MS-XLS] 2.4.21). */
|
|
3
|
+
declare const RECORD_BOF = 2057;
|
|
4
|
+
/** Marks the end of a substream ([MS-XLS] 2.4.103). */
|
|
5
|
+
declare const RECORD_EOF = 10;
|
|
6
|
+
/** Carries the overflow of a preceding record whose data exceeds what one record can hold ([MS-XLS] 2.4.58). */
|
|
7
|
+
declare const RECORD_CONTINUE = 60;
|
|
8
|
+
/** One per sheet: its name, hidden state, type, and the stream offset of its own BOF ([MS-XLS] 2.4.28). */
|
|
9
|
+
declare const RECORD_BOUNDSHEET8 = 133;
|
|
10
|
+
/** The shared string table every LabelSst cell indexes into ([MS-XLS] 2.4.265). */
|
|
11
|
+
declare const RECORD_SST = 252;
|
|
12
|
+
/** A custom number-format code and the identifier cells reference it by ([MS-XLS] 2.4.126). */
|
|
13
|
+
declare const RECORD_FORMAT = 1054;
|
|
14
|
+
/** A cell or cell-style extended format record ([MS-XLS] 2.4.353). */
|
|
15
|
+
declare const RECORD_XF = 224;
|
|
16
|
+
/** A font definition, referenced by index from an XF ([MS-XLS] 2.4.122). */
|
|
17
|
+
declare const RECORD_FONT = 49;
|
|
18
|
+
/** Which of the two date epochs this workbook's serials count from ([MS-XLS] 2.4.77). */
|
|
19
|
+
declare const RECORD_DATE1904 = 34;
|
|
20
|
+
/** Present only in an encrypted workbook, where every record after it is ciphertext ([MS-XLS] 2.4.117). */
|
|
21
|
+
declare const RECORD_FILEPASS = 47;
|
|
22
|
+
/** The sheet's used range ([MS-XLS] 2.4.90). */
|
|
23
|
+
declare const RECORD_DIMENSIONS = 512;
|
|
24
|
+
/** A single row's height, hidden state, and formatting ([MS-XLS] 2.4.221). */
|
|
25
|
+
declare const RECORD_ROW = 520;
|
|
26
|
+
/** Column width, hidden state, and default format for a range of columns ([MS-XLS] 2.4.53). */
|
|
27
|
+
declare const RECORD_COLINFO = 125;
|
|
28
|
+
/** The sheet's default column width, in whole character widths ([MS-XLS] 2.4.89). */
|
|
29
|
+
declare const RECORD_DEFCOLWIDTH = 85;
|
|
30
|
+
/** The sheet's default row height ([MS-XLS] 2.4.87). */
|
|
31
|
+
declare const RECORD_DEFAULTROWHEIGHT = 549;
|
|
32
|
+
/** Merged cell ranges ([MS-XLS] 2.4.168). */
|
|
33
|
+
declare const RECORD_MERGECELLS = 229;
|
|
34
|
+
/** An empty cell carrying only formatting ([MS-XLS] 2.4.20). */
|
|
35
|
+
declare const RECORD_BLANK = 513;
|
|
36
|
+
/** A run of empty cells in one row ([MS-XLS] 2.4.174). */
|
|
37
|
+
declare const RECORD_MULBLANK = 190;
|
|
38
|
+
/** A cell holding an RK-encoded number ([MS-XLS] 2.4.220). */
|
|
39
|
+
declare const RECORD_RK = 638;
|
|
40
|
+
/** A run of RK-encoded numeric cells in one row ([MS-XLS] 2.4.175). */
|
|
41
|
+
declare const RECORD_MULRK = 189;
|
|
42
|
+
/** A cell holding an IEEE 754 double ([MS-XLS] 2.4.180). */
|
|
43
|
+
declare const RECORD_NUMBER = 515;
|
|
44
|
+
/** A cell holding a boolean or an error value ([MS-XLS] 2.4.24). */
|
|
45
|
+
declare const RECORD_BOOLERR = 517;
|
|
46
|
+
/** A cell holding a string by index into the shared string table ([MS-XLS] 2.4.149). */
|
|
47
|
+
declare const RECORD_LABELSST = 253;
|
|
48
|
+
/** A cell holding an inline string ([MS-XLS] 2.4.148). See the reader's own note on why BIFF8 still meets this in the wild. */
|
|
49
|
+
declare const RECORD_LABEL = 516;
|
|
50
|
+
/** A cell holding a formula, its cached result, and its parsed expression ([MS-XLS] 2.4.127). */
|
|
51
|
+
declare const RECORD_FORMULA = 6;
|
|
52
|
+
/** The string result of the Formula record preceding it ([MS-XLS] 2.4.268). */
|
|
53
|
+
declare const RECORD_STRING = 519;
|
|
54
|
+
/** The expression of an array formula, following the Formula record of its top-left cell ([MS-XLS] 2.4.4). */
|
|
55
|
+
declare const RECORD_ARRAY = 545;
|
|
56
|
+
/** A data-table definition following a Formula record ([MS-XLS] 2.4.334). */
|
|
57
|
+
declare const RECORD_TABLE = 566;
|
|
58
|
+
/** The shared expression a run of Formula records refers to ([MS-XLS] 2.4.260). */
|
|
59
|
+
declare const RECORD_SHRFMLA = 1212;
|
|
60
|
+
/** The workbook globals substream. */
|
|
61
|
+
declare const BOF_TYPE_WORKBOOK = 5;
|
|
62
|
+
/** A worksheet or dialog sheet substream. */
|
|
63
|
+
declare const BOF_TYPE_WORKSHEET = 16;
|
|
64
|
+
/** A chart sheet substream. */
|
|
65
|
+
declare const BOF_TYPE_CHART = 32;
|
|
66
|
+
/** A macro sheet substream. */
|
|
67
|
+
declare const BOF_TYPE_MACRO = 64;
|
|
68
|
+
/** The BIFF version every BOF in a BIFF8 workbook stream declares ([MS-XLS] 2.4.21: "The value MUST be 0x0600"). */
|
|
69
|
+
declare const BIFF8_VERSION = 1536;
|
|
70
|
+
/** [MS-XLS] 2.1.4: "The record size ... MUST be less than or equal to 8224." The ceiling a writer splits a record at, and the bound a reader can sanity-check a declared size against. */
|
|
71
|
+
declare const MAX_RECORD_DATA_SIZE = 8224;
|
|
72
|
+
//#endregion
|
|
73
|
+
export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, MAX_RECORD_DATA_SIZE, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOUNDSHEET8, RECORD_COLINFO, RECORD_CONTINUE, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_EOF, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_LABEL, RECORD_LABELSST, RECORD_MERGECELLS, RECORD_MULBLANK, RECORD_MULRK, RECORD_NUMBER, RECORD_RK, RECORD_ROW, RECORD_SHRFMLA, RECORD_SST, RECORD_STRING, RECORD_TABLE, RECORD_XF };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region src/biff/record-types.ts
|
|
2
|
+
/** Marks the beginning of a substream and names its document type ([MS-XLS] 2.4.21). */
|
|
3
|
+
const RECORD_BOF = 2057;
|
|
4
|
+
/** Marks the end of a substream ([MS-XLS] 2.4.103). */
|
|
5
|
+
const RECORD_EOF = 10;
|
|
6
|
+
/** Carries the overflow of a preceding record whose data exceeds what one record can hold ([MS-XLS] 2.4.58). */
|
|
7
|
+
const RECORD_CONTINUE = 60;
|
|
8
|
+
/** One per sheet: its name, hidden state, type, and the stream offset of its own BOF ([MS-XLS] 2.4.28). */
|
|
9
|
+
const RECORD_BOUNDSHEET8 = 133;
|
|
10
|
+
/** The shared string table every LabelSst cell indexes into ([MS-XLS] 2.4.265). */
|
|
11
|
+
const RECORD_SST = 252;
|
|
12
|
+
/** A custom number-format code and the identifier cells reference it by ([MS-XLS] 2.4.126). */
|
|
13
|
+
const RECORD_FORMAT = 1054;
|
|
14
|
+
/** A cell or cell-style extended format record ([MS-XLS] 2.4.353). */
|
|
15
|
+
const RECORD_XF = 224;
|
|
16
|
+
/** A font definition, referenced by index from an XF ([MS-XLS] 2.4.122). */
|
|
17
|
+
const RECORD_FONT = 49;
|
|
18
|
+
/** Which of the two date epochs this workbook's serials count from ([MS-XLS] 2.4.77). */
|
|
19
|
+
const RECORD_DATE1904 = 34;
|
|
20
|
+
/** Present only in an encrypted workbook, where every record after it is ciphertext ([MS-XLS] 2.4.117). */
|
|
21
|
+
const RECORD_FILEPASS = 47;
|
|
22
|
+
/** The sheet's used range ([MS-XLS] 2.4.90). */
|
|
23
|
+
const RECORD_DIMENSIONS = 512;
|
|
24
|
+
/** A single row's height, hidden state, and formatting ([MS-XLS] 2.4.221). */
|
|
25
|
+
const RECORD_ROW = 520;
|
|
26
|
+
/** Column width, hidden state, and default format for a range of columns ([MS-XLS] 2.4.53). */
|
|
27
|
+
const RECORD_COLINFO = 125;
|
|
28
|
+
/** The sheet's default column width, in whole character widths ([MS-XLS] 2.4.89). */
|
|
29
|
+
const RECORD_DEFCOLWIDTH = 85;
|
|
30
|
+
/** The sheet's default row height ([MS-XLS] 2.4.87). */
|
|
31
|
+
const RECORD_DEFAULTROWHEIGHT = 549;
|
|
32
|
+
/** Merged cell ranges ([MS-XLS] 2.4.168). */
|
|
33
|
+
const RECORD_MERGECELLS = 229;
|
|
34
|
+
/** An empty cell carrying only formatting ([MS-XLS] 2.4.20). */
|
|
35
|
+
const RECORD_BLANK = 513;
|
|
36
|
+
/** A run of empty cells in one row ([MS-XLS] 2.4.174). */
|
|
37
|
+
const RECORD_MULBLANK = 190;
|
|
38
|
+
/** A cell holding an RK-encoded number ([MS-XLS] 2.4.220). */
|
|
39
|
+
const RECORD_RK = 638;
|
|
40
|
+
/** A run of RK-encoded numeric cells in one row ([MS-XLS] 2.4.175). */
|
|
41
|
+
const RECORD_MULRK = 189;
|
|
42
|
+
/** A cell holding an IEEE 754 double ([MS-XLS] 2.4.180). */
|
|
43
|
+
const RECORD_NUMBER = 515;
|
|
44
|
+
/** A cell holding a boolean or an error value ([MS-XLS] 2.4.24). */
|
|
45
|
+
const RECORD_BOOLERR = 517;
|
|
46
|
+
/** A cell holding a string by index into the shared string table ([MS-XLS] 2.4.149). */
|
|
47
|
+
const RECORD_LABELSST = 253;
|
|
48
|
+
/** A cell holding an inline string ([MS-XLS] 2.4.148). See the reader's own note on why BIFF8 still meets this in the wild. */
|
|
49
|
+
const RECORD_LABEL = 516;
|
|
50
|
+
/** A cell holding a formula, its cached result, and its parsed expression ([MS-XLS] 2.4.127). */
|
|
51
|
+
const RECORD_FORMULA = 6;
|
|
52
|
+
/** The string result of the Formula record preceding it ([MS-XLS] 2.4.268). */
|
|
53
|
+
const RECORD_STRING = 519;
|
|
54
|
+
/** The expression of an array formula, following the Formula record of its top-left cell ([MS-XLS] 2.4.4). */
|
|
55
|
+
const RECORD_ARRAY = 545;
|
|
56
|
+
/** A data-table definition following a Formula record ([MS-XLS] 2.4.334). */
|
|
57
|
+
const RECORD_TABLE = 566;
|
|
58
|
+
/** The shared expression a run of Formula records refers to ([MS-XLS] 2.4.260). */
|
|
59
|
+
const RECORD_SHRFMLA = 1212;
|
|
60
|
+
/** The workbook globals substream. */
|
|
61
|
+
const BOF_TYPE_WORKBOOK = 5;
|
|
62
|
+
/** A worksheet or dialog sheet substream. */
|
|
63
|
+
const BOF_TYPE_WORKSHEET = 16;
|
|
64
|
+
/** A chart sheet substream. */
|
|
65
|
+
const BOF_TYPE_CHART = 32;
|
|
66
|
+
/** A macro sheet substream. */
|
|
67
|
+
const BOF_TYPE_MACRO = 64;
|
|
68
|
+
/** The BIFF version every BOF in a BIFF8 workbook stream declares ([MS-XLS] 2.4.21: "The value MUST be 0x0600"). */
|
|
69
|
+
const BIFF8_VERSION = 1536;
|
|
70
|
+
/** [MS-XLS] 2.1.4: "The record size ... MUST be less than or equal to 8224." The ceiling a writer splits a record at, and the bound a reader can sanity-check a declared size against. */
|
|
71
|
+
const MAX_RECORD_DATA_SIZE = 8224;
|
|
72
|
+
//#endregion
|
|
73
|
+
export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, MAX_RECORD_DATA_SIZE, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOUNDSHEET8, RECORD_COLINFO, RECORD_CONTINUE, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_EOF, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_LABEL, RECORD_LABELSST, RECORD_MERGECELLS, RECORD_MULBLANK, RECORD_MULRK, RECORD_NUMBER, RECORD_RK, RECORD_ROW, RECORD_SHRFMLA, RECORD_SST, RECORD_STRING, RECORD_TABLE, RECORD_XF };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_biff_record_types = require("./record-types.cjs");
|
|
3
|
+
//#region src/biff/records.ts
|
|
4
|
+
/** Thrown when a byte sequence cannot be read as the structure [MS-XLS] specifies, at any level from the record framing up to a record's own fields. */
|
|
5
|
+
var BiffFormatError = class extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "BiffFormatError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
/** The four-byte record header: a two-byte type followed by a two-byte size. */
|
|
12
|
+
const HEADER_SIZE = 4;
|
|
13
|
+
/**
|
|
14
|
+
* Splits a BIFF record stream into its records, in stream order.
|
|
15
|
+
*
|
|
16
|
+
* Every failure is thrown rather than tolerated, because there is no safe way to resume: a record's size field is the only thing that says where the next record begins, so a stream that stops making sense at one record makes no sense from there on, and returning the records read so far would be reporting a truncated workbook as a complete one.
|
|
17
|
+
*/
|
|
18
|
+
function readRecords(stream) {
|
|
19
|
+
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
20
|
+
const records = [];
|
|
21
|
+
let offset = 0;
|
|
22
|
+
while (offset < stream.length) {
|
|
23
|
+
if (offset + HEADER_SIZE > stream.length) throw new BiffFormatError(`record header at offset ${offset} runs past the end of the ${stream.length}-byte stream`);
|
|
24
|
+
const type = view.getUint16(offset, true);
|
|
25
|
+
const size = view.getUint16(offset + 2, true);
|
|
26
|
+
if (size > 8224) throw new BiffFormatError(`record 0x${type.toString(16)} at offset ${offset} declares ${size} bytes of data, above the ${require_biff_record_types.MAX_RECORD_DATA_SIZE}-byte maximum`);
|
|
27
|
+
const dataStart = offset + HEADER_SIZE;
|
|
28
|
+
if (dataStart + size > stream.length) throw new BiffFormatError(`record 0x${type.toString(16)} at offset ${offset} declares ${size} bytes of data, running past the end of the ${stream.length}-byte stream`);
|
|
29
|
+
records.push({
|
|
30
|
+
type,
|
|
31
|
+
data: stream.slice(dataStart, dataStart + size),
|
|
32
|
+
offset
|
|
33
|
+
});
|
|
34
|
+
offset = dataStart + size;
|
|
35
|
+
}
|
|
36
|
+
return records;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
exports.BiffFormatError = BiffFormatError;
|
|
40
|
+
exports.readRecords = readRecords;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MAX_RECORD_DATA_SIZE } from "./record-types.js";
|
|
2
|
+
//#region src/biff/records.ts
|
|
3
|
+
/** Thrown when a byte sequence cannot be read as the structure [MS-XLS] specifies, at any level from the record framing up to a record's own fields. */
|
|
4
|
+
var BiffFormatError = class extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "BiffFormatError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
/** The four-byte record header: a two-byte type followed by a two-byte size. */
|
|
11
|
+
const HEADER_SIZE = 4;
|
|
12
|
+
/**
|
|
13
|
+
* Splits a BIFF record stream into its records, in stream order.
|
|
14
|
+
*
|
|
15
|
+
* Every failure is thrown rather than tolerated, because there is no safe way to resume: a record's size field is the only thing that says where the next record begins, so a stream that stops making sense at one record makes no sense from there on, and returning the records read so far would be reporting a truncated workbook as a complete one.
|
|
16
|
+
*/
|
|
17
|
+
function readRecords(stream) {
|
|
18
|
+
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
19
|
+
const records = [];
|
|
20
|
+
let offset = 0;
|
|
21
|
+
while (offset < stream.length) {
|
|
22
|
+
if (offset + HEADER_SIZE > stream.length) throw new BiffFormatError(`record header at offset ${offset} runs past the end of the ${stream.length}-byte stream`);
|
|
23
|
+
const type = view.getUint16(offset, true);
|
|
24
|
+
const size = view.getUint16(offset + 2, true);
|
|
25
|
+
if (size > 8224) throw new BiffFormatError(`record 0x${type.toString(16)} at offset ${offset} declares ${size} bytes of data, above the ${MAX_RECORD_DATA_SIZE}-byte maximum`);
|
|
26
|
+
const dataStart = offset + HEADER_SIZE;
|
|
27
|
+
if (dataStart + size > stream.length) throw new BiffFormatError(`record 0x${type.toString(16)} at offset ${offset} declares ${size} bytes of data, running past the end of the ${stream.length}-byte stream`);
|
|
28
|
+
records.push({
|
|
29
|
+
type,
|
|
30
|
+
data: stream.slice(dataStart, dataStart + size),
|
|
31
|
+
offset
|
|
32
|
+
});
|
|
33
|
+
offset = dataStart + size;
|
|
34
|
+
}
|
|
35
|
+
return records;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { BiffFormatError, readRecords };
|
package/dist/biff/rk.cjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/biff/rk.ts
|
|
3
|
+
const FLAG_X100 = 1;
|
|
4
|
+
const FLAG_INT = 2;
|
|
5
|
+
/** The payload is a signed 30-bit integer; 2^29 is its sign bit and 2^30 the modulus to subtract. */
|
|
6
|
+
const INT_SIGN_BIT = 536870912;
|
|
7
|
+
const INT_MODULUS = 1073741824;
|
|
8
|
+
/** [MS-XLS] 2.5.217's own fX100 divisor. */
|
|
9
|
+
const X100_DIVISOR = 100;
|
|
10
|
+
/** Decodes the 32-bit word of an RkNumber ([MS-XLS] 2.5.217) into the number it stands for. */
|
|
11
|
+
function decodeRkNumber(word) {
|
|
12
|
+
const bits = word >>> 0;
|
|
13
|
+
const value = (bits & FLAG_INT) !== 0 ? decodeSignedPayload(bits) : decodeTruncatedDouble(bits);
|
|
14
|
+
return (bits & FLAG_X100) !== 0 ? value / X100_DIVISOR : value;
|
|
15
|
+
}
|
|
16
|
+
/** The payload read as a signed 30-bit integer: shifted down unsigned, then folded into its negative range from bit 29 rather than sign-extended from bit 31. */
|
|
17
|
+
function decodeSignedPayload(bits) {
|
|
18
|
+
const payload = (bits & -4) >>> 2;
|
|
19
|
+
return (payload & INT_SIGN_BIT) !== 0 ? payload - INT_MODULUS : payload;
|
|
20
|
+
}
|
|
21
|
+
/** The payload read as the high 32 bits of a double whose low 32 bits are zero, with the two flag bits (the double's own bits 32 and 33, which the spec requires be zero) cleared first. */
|
|
22
|
+
function decodeTruncatedDouble(bits) {
|
|
23
|
+
const view = /* @__PURE__ */ new DataView(/* @__PURE__ */ new ArrayBuffer(8));
|
|
24
|
+
view.setUint32(0, (bits & -4) >>> 0, false);
|
|
25
|
+
view.setUint32(4, 0, false);
|
|
26
|
+
return view.getFloat64(0, false);
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
exports.decodeRkNumber = decodeRkNumber;
|
package/dist/biff/rk.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/biff/rk.ts
|
|
2
|
+
const FLAG_X100 = 1;
|
|
3
|
+
const FLAG_INT = 2;
|
|
4
|
+
/** The payload is a signed 30-bit integer; 2^29 is its sign bit and 2^30 the modulus to subtract. */
|
|
5
|
+
const INT_SIGN_BIT = 536870912;
|
|
6
|
+
const INT_MODULUS = 1073741824;
|
|
7
|
+
/** [MS-XLS] 2.5.217's own fX100 divisor. */
|
|
8
|
+
const X100_DIVISOR = 100;
|
|
9
|
+
/** Decodes the 32-bit word of an RkNumber ([MS-XLS] 2.5.217) into the number it stands for. */
|
|
10
|
+
function decodeRkNumber(word) {
|
|
11
|
+
const bits = word >>> 0;
|
|
12
|
+
const value = (bits & FLAG_INT) !== 0 ? decodeSignedPayload(bits) : decodeTruncatedDouble(bits);
|
|
13
|
+
return (bits & FLAG_X100) !== 0 ? value / X100_DIVISOR : value;
|
|
14
|
+
}
|
|
15
|
+
/** The payload read as a signed 30-bit integer: shifted down unsigned, then folded into its negative range from bit 29 rather than sign-extended from bit 31. */
|
|
16
|
+
function decodeSignedPayload(bits) {
|
|
17
|
+
const payload = (bits & -4) >>> 2;
|
|
18
|
+
return (payload & INT_SIGN_BIT) !== 0 ? payload - INT_MODULUS : payload;
|
|
19
|
+
}
|
|
20
|
+
/** The payload read as the high 32 bits of a double whose low 32 bits are zero, with the two flag bits (the double's own bits 32 and 33, which the spec requires be zero) cleared first. */
|
|
21
|
+
function decodeTruncatedDouble(bits) {
|
|
22
|
+
const view = /* @__PURE__ */ new DataView(/* @__PURE__ */ new ArrayBuffer(8));
|
|
23
|
+
view.setUint32(0, (bits & -4) >>> 0, false);
|
|
24
|
+
view.setUint32(4, 0, false);
|
|
25
|
+
return view.getFloat64(0, false);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { decodeRkNumber };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/biff/strings.ts
|
|
3
|
+
/** Bit 0 of a string's flags byte: set when each character occupies a full two-byte UTF-16 code unit. */
|
|
4
|
+
const FLAG_HIGH_BYTE = 1;
|
|
5
|
+
/** Bit 2 of an XLUnicodeRichExtendedString's flags byte: set when phonetic (ExtRst) data trails the characters. */
|
|
6
|
+
const FLAG_EXT_ST = 4;
|
|
7
|
+
/** Bit 3 of an XLUnicodeRichExtendedString's flags byte: set when formatting runs (rgRun) trail the characters. */
|
|
8
|
+
const FLAG_RICH_ST = 8;
|
|
9
|
+
/** [MS-XLS] 2.5.132: a FormatRun is four bytes (a character index and a font index). */
|
|
10
|
+
const FORMAT_RUN_SIZE = 4;
|
|
11
|
+
/**
|
|
12
|
+
* Reads `count` characters, consuming the re-stated flag byte at every continuation boundary the run crosses.
|
|
13
|
+
*
|
|
14
|
+
* `startBlock` is the block the string's own header was read in, captured by the caller before reading cch. Comparing against that rather than against the cursor's position at entry is what makes the boundary-at-the-first-character case work: a string whose fixed fields fill their record exactly, leaving every character to the Continue, still opens that Continue with a flag byte, and a position captured after the header was read would already have settled onto the Continue and missed it.
|
|
15
|
+
*
|
|
16
|
+
* The boundary byte is consumed only when characters genuinely remain, so a string whose last character lands on the final byte of a block leaves the next block's first byte alone -- that byte belongs to whatever the record holds next, which for the SST is the following string's own cch.
|
|
17
|
+
*/
|
|
18
|
+
function readCharacters(cursor, count, initialHighByte, startBlock) {
|
|
19
|
+
let highByte = initialHighByte;
|
|
20
|
+
let block = startBlock;
|
|
21
|
+
const units = [];
|
|
22
|
+
for (let index = 0; index < count; index += 1) {
|
|
23
|
+
const currentBlock = cursor.blockPosition();
|
|
24
|
+
if (currentBlock !== block) {
|
|
25
|
+
highByte = (cursor.u8() & FLAG_HIGH_BYTE) !== 0;
|
|
26
|
+
block = currentBlock;
|
|
27
|
+
}
|
|
28
|
+
units.push(highByte ? cursor.u16() : cursor.u8());
|
|
29
|
+
}
|
|
30
|
+
const CHUNK = 4096;
|
|
31
|
+
let text = "";
|
|
32
|
+
for (let start = 0; start < units.length; start += CHUNK) text += String.fromCharCode(...units.slice(start, start + CHUNK));
|
|
33
|
+
return text;
|
|
34
|
+
}
|
|
35
|
+
/** An XLUnicodeString ([MS-XLS] 2.5.294): a two-byte character count, a flags byte, then the characters. Continuable, since the String record ([MS-XLS] 2.4.268) carrying a formula's string result is one of these and its own production admits trailing Continues. */
|
|
36
|
+
function readXLUnicodeString(cursor) {
|
|
37
|
+
const startBlock = cursor.blockPosition();
|
|
38
|
+
return readCharacters(cursor, cursor.u16(), (cursor.u8() & FLAG_HIGH_BYTE) !== 0, startBlock);
|
|
39
|
+
}
|
|
40
|
+
/** A ShortXLUnicodeString ([MS-XLS] 2.5.240): as above, with a one-byte character count. */
|
|
41
|
+
function readShortXLUnicodeString(cursor) {
|
|
42
|
+
const startBlock = cursor.blockPosition();
|
|
43
|
+
return readCharacters(cursor, cursor.u8(), (cursor.u8() & FLAG_HIGH_BYTE) !== 0, startBlock);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* An XLUnicodeRichExtendedString ([MS-XLS] 2.5.293): the SST's own element shape.
|
|
47
|
+
*
|
|
48
|
+
* Only the text is returned. A rich string's per-run font changes and an extended string's phonetic guide data are read past rather than modelled: `ContentSheetCell.runs` could carry the former, but resolving a FormatRun's font index into real run formatting needs the globals substream's Font table threaded down here, and the phonetic data has no representation in the shared schema at all. Both payloads must still be CONSUMED exactly, because the SST is a packed array -- leaving a single byte of either behind would desynchronise every string after it.
|
|
49
|
+
*/
|
|
50
|
+
function readRichExtendedString(cursor) {
|
|
51
|
+
const startBlock = cursor.blockPosition();
|
|
52
|
+
const cch = cursor.u16();
|
|
53
|
+
const flags = cursor.u8();
|
|
54
|
+
const rich = (flags & FLAG_RICH_ST) !== 0;
|
|
55
|
+
const extended = (flags & FLAG_EXT_ST) !== 0;
|
|
56
|
+
const runCount = rich ? cursor.u16() : 0;
|
|
57
|
+
const extendedSize = extended ? cursor.i32() : 0;
|
|
58
|
+
const text = readCharacters(cursor, cch, (flags & FLAG_HIGH_BYTE) !== 0, startBlock);
|
|
59
|
+
if (runCount > 0) cursor.skip(runCount * FORMAT_RUN_SIZE);
|
|
60
|
+
if (extendedSize > 0) cursor.skip(extendedSize);
|
|
61
|
+
return text;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
exports.readRichExtendedString = readRichExtendedString;
|
|
65
|
+
exports.readShortXLUnicodeString = readShortXLUnicodeString;
|
|
66
|
+
exports.readXLUnicodeString = readXLUnicodeString;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BlockCursor } from "./cursor.cjs";
|
|
2
|
+
//#region src/biff/strings.d.ts
|
|
3
|
+
/** An XLUnicodeString ([MS-XLS] 2.5.294): a two-byte character count, a flags byte, then the characters. Continuable, since the String record ([MS-XLS] 2.4.268) carrying a formula's string result is one of these and its own production admits trailing Continues. */
|
|
4
|
+
declare function readXLUnicodeString(cursor: BlockCursor): string;
|
|
5
|
+
/** A ShortXLUnicodeString ([MS-XLS] 2.5.240): as above, with a one-byte character count. */
|
|
6
|
+
declare function readShortXLUnicodeString(cursor: BlockCursor): string;
|
|
7
|
+
/**
|
|
8
|
+
* An XLUnicodeRichExtendedString ([MS-XLS] 2.5.293): the SST's own element shape.
|
|
9
|
+
*
|
|
10
|
+
* Only the text is returned. A rich string's per-run font changes and an extended string's phonetic guide data are read past rather than modelled: `ContentSheetCell.runs` could carry the former, but resolving a FormatRun's font index into real run formatting needs the globals substream's Font table threaded down here, and the phonetic data has no representation in the shared schema at all. Both payloads must still be CONSUMED exactly, because the SST is a packed array -- leaving a single byte of either behind would desynchronise every string after it.
|
|
11
|
+
*/
|
|
12
|
+
declare function readRichExtendedString(cursor: BlockCursor): string;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { readRichExtendedString, readShortXLUnicodeString, readXLUnicodeString };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BlockCursor } from "./cursor.js";
|
|
2
|
+
//#region src/biff/strings.d.ts
|
|
3
|
+
/** An XLUnicodeString ([MS-XLS] 2.5.294): a two-byte character count, a flags byte, then the characters. Continuable, since the String record ([MS-XLS] 2.4.268) carrying a formula's string result is one of these and its own production admits trailing Continues. */
|
|
4
|
+
declare function readXLUnicodeString(cursor: BlockCursor): string;
|
|
5
|
+
/** A ShortXLUnicodeString ([MS-XLS] 2.5.240): as above, with a one-byte character count. */
|
|
6
|
+
declare function readShortXLUnicodeString(cursor: BlockCursor): string;
|
|
7
|
+
/**
|
|
8
|
+
* An XLUnicodeRichExtendedString ([MS-XLS] 2.5.293): the SST's own element shape.
|
|
9
|
+
*
|
|
10
|
+
* Only the text is returned. A rich string's per-run font changes and an extended string's phonetic guide data are read past rather than modelled: `ContentSheetCell.runs` could carry the former, but resolving a FormatRun's font index into real run formatting needs the globals substream's Font table threaded down here, and the phonetic data has no representation in the shared schema at all. Both payloads must still be CONSUMED exactly, because the SST is a packed array -- leaving a single byte of either behind would desynchronise every string after it.
|
|
11
|
+
*/
|
|
12
|
+
declare function readRichExtendedString(cursor: BlockCursor): string;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { readRichExtendedString, readShortXLUnicodeString, readXLUnicodeString };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//#region src/biff/strings.ts
|
|
2
|
+
/** Bit 0 of a string's flags byte: set when each character occupies a full two-byte UTF-16 code unit. */
|
|
3
|
+
const FLAG_HIGH_BYTE = 1;
|
|
4
|
+
/** Bit 2 of an XLUnicodeRichExtendedString's flags byte: set when phonetic (ExtRst) data trails the characters. */
|
|
5
|
+
const FLAG_EXT_ST = 4;
|
|
6
|
+
/** Bit 3 of an XLUnicodeRichExtendedString's flags byte: set when formatting runs (rgRun) trail the characters. */
|
|
7
|
+
const FLAG_RICH_ST = 8;
|
|
8
|
+
/** [MS-XLS] 2.5.132: a FormatRun is four bytes (a character index and a font index). */
|
|
9
|
+
const FORMAT_RUN_SIZE = 4;
|
|
10
|
+
/**
|
|
11
|
+
* Reads `count` characters, consuming the re-stated flag byte at every continuation boundary the run crosses.
|
|
12
|
+
*
|
|
13
|
+
* `startBlock` is the block the string's own header was read in, captured by the caller before reading cch. Comparing against that rather than against the cursor's position at entry is what makes the boundary-at-the-first-character case work: a string whose fixed fields fill their record exactly, leaving every character to the Continue, still opens that Continue with a flag byte, and a position captured after the header was read would already have settled onto the Continue and missed it.
|
|
14
|
+
*
|
|
15
|
+
* The boundary byte is consumed only when characters genuinely remain, so a string whose last character lands on the final byte of a block leaves the next block's first byte alone -- that byte belongs to whatever the record holds next, which for the SST is the following string's own cch.
|
|
16
|
+
*/
|
|
17
|
+
function readCharacters(cursor, count, initialHighByte, startBlock) {
|
|
18
|
+
let highByte = initialHighByte;
|
|
19
|
+
let block = startBlock;
|
|
20
|
+
const units = [];
|
|
21
|
+
for (let index = 0; index < count; index += 1) {
|
|
22
|
+
const currentBlock = cursor.blockPosition();
|
|
23
|
+
if (currentBlock !== block) {
|
|
24
|
+
highByte = (cursor.u8() & FLAG_HIGH_BYTE) !== 0;
|
|
25
|
+
block = currentBlock;
|
|
26
|
+
}
|
|
27
|
+
units.push(highByte ? cursor.u16() : cursor.u8());
|
|
28
|
+
}
|
|
29
|
+
const CHUNK = 4096;
|
|
30
|
+
let text = "";
|
|
31
|
+
for (let start = 0; start < units.length; start += CHUNK) text += String.fromCharCode(...units.slice(start, start + CHUNK));
|
|
32
|
+
return text;
|
|
33
|
+
}
|
|
34
|
+
/** An XLUnicodeString ([MS-XLS] 2.5.294): a two-byte character count, a flags byte, then the characters. Continuable, since the String record ([MS-XLS] 2.4.268) carrying a formula's string result is one of these and its own production admits trailing Continues. */
|
|
35
|
+
function readXLUnicodeString(cursor) {
|
|
36
|
+
const startBlock = cursor.blockPosition();
|
|
37
|
+
return readCharacters(cursor, cursor.u16(), (cursor.u8() & FLAG_HIGH_BYTE) !== 0, startBlock);
|
|
38
|
+
}
|
|
39
|
+
/** A ShortXLUnicodeString ([MS-XLS] 2.5.240): as above, with a one-byte character count. */
|
|
40
|
+
function readShortXLUnicodeString(cursor) {
|
|
41
|
+
const startBlock = cursor.blockPosition();
|
|
42
|
+
return readCharacters(cursor, cursor.u8(), (cursor.u8() & FLAG_HIGH_BYTE) !== 0, startBlock);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* An XLUnicodeRichExtendedString ([MS-XLS] 2.5.293): the SST's own element shape.
|
|
46
|
+
*
|
|
47
|
+
* Only the text is returned. A rich string's per-run font changes and an extended string's phonetic guide data are read past rather than modelled: `ContentSheetCell.runs` could carry the former, but resolving a FormatRun's font index into real run formatting needs the globals substream's Font table threaded down here, and the phonetic data has no representation in the shared schema at all. Both payloads must still be CONSUMED exactly, because the SST is a packed array -- leaving a single byte of either behind would desynchronise every string after it.
|
|
48
|
+
*/
|
|
49
|
+
function readRichExtendedString(cursor) {
|
|
50
|
+
const startBlock = cursor.blockPosition();
|
|
51
|
+
const cch = cursor.u16();
|
|
52
|
+
const flags = cursor.u8();
|
|
53
|
+
const rich = (flags & FLAG_RICH_ST) !== 0;
|
|
54
|
+
const extended = (flags & FLAG_EXT_ST) !== 0;
|
|
55
|
+
const runCount = rich ? cursor.u16() : 0;
|
|
56
|
+
const extendedSize = extended ? cursor.i32() : 0;
|
|
57
|
+
const text = readCharacters(cursor, cch, (flags & FLAG_HIGH_BYTE) !== 0, startBlock);
|
|
58
|
+
if (runCount > 0) cursor.skip(runCount * FORMAT_RUN_SIZE);
|
|
59
|
+
if (extendedSize > 0) cursor.skip(extendedSize);
|
|
60
|
+
return text;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { readRichExtendedString, readShortXLUnicodeString, readXLUnicodeString };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
require("./record-types.cjs");
|
|
3
|
+
const require_biff_records = require("./records.cjs");
|
|
4
|
+
//#region src/biff/substreams.ts
|
|
5
|
+
/** Joins each record to the Continue records following it, keeping the blocks separate. */
|
|
6
|
+
function groupRecords(records) {
|
|
7
|
+
const groups = [];
|
|
8
|
+
for (const record of records) {
|
|
9
|
+
if (record.type === 60) {
|
|
10
|
+
const current = groups[groups.length - 1];
|
|
11
|
+
if (current === void 0) throw new require_biff_records.BiffFormatError("Continue record with no preceding record to continue");
|
|
12
|
+
current.blocks.push(record.data);
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
groups.push({
|
|
16
|
+
type: record.type,
|
|
17
|
+
blocks: [record.data],
|
|
18
|
+
offset: record.offset
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return groups;
|
|
22
|
+
}
|
|
23
|
+
/** The BOF record's own fixed prefix: a two-byte vers followed by a two-byte dt. */
|
|
24
|
+
const BOF_PREFIX_SIZE = 4;
|
|
25
|
+
/** Splits a grouped record sequence into its substreams, verifying each BOF declares BIFF8. */
|
|
26
|
+
function splitSubstreams(groups) {
|
|
27
|
+
const substreams = [];
|
|
28
|
+
let current;
|
|
29
|
+
for (const group of groups) {
|
|
30
|
+
if (group.type === 2057) {
|
|
31
|
+
if (current !== void 0) substreams.push({
|
|
32
|
+
...current,
|
|
33
|
+
index: substreams.length
|
|
34
|
+
});
|
|
35
|
+
current = {
|
|
36
|
+
documentType: readBofDocumentType(group),
|
|
37
|
+
records: [],
|
|
38
|
+
offset: group.offset
|
|
39
|
+
};
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (group.type === 10) {
|
|
43
|
+
if (current !== void 0) {
|
|
44
|
+
substreams.push({
|
|
45
|
+
...current,
|
|
46
|
+
index: substreams.length
|
|
47
|
+
});
|
|
48
|
+
current = void 0;
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
current?.records.push(group);
|
|
53
|
+
}
|
|
54
|
+
if (current !== void 0) substreams.push({
|
|
55
|
+
...current,
|
|
56
|
+
index: substreams.length
|
|
57
|
+
});
|
|
58
|
+
return substreams;
|
|
59
|
+
}
|
|
60
|
+
/** Reads a BOF's vers and dt ([MS-XLS] 2.4.21), rejecting anything that is not BIFF8. */
|
|
61
|
+
function readBofDocumentType(group) {
|
|
62
|
+
const data = group.blocks[0];
|
|
63
|
+
if (data === void 0 || data.length < BOF_PREFIX_SIZE) throw new require_biff_records.BiffFormatError(`BOF record carries ${data?.length ?? 0} bytes, too few for its own version and document type`);
|
|
64
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
65
|
+
const version = view.getUint16(0, true);
|
|
66
|
+
if (version !== 1536) throw new require_biff_records.BiffFormatError(`BOF declares BIFF version 0x${version.toString(16).padStart(4, "0")}; this reader implements BIFF8 (0x0600) only`);
|
|
67
|
+
return view.getUint16(2, true);
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
exports.groupRecords = groupRecords;
|
|
71
|
+
exports.splitSubstreams = splitSubstreams;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { n as BiffRecord } from "../records-DVIqXFKk.cjs";
|
|
2
|
+
//#region src/biff/substreams.d.ts
|
|
3
|
+
/** One logical record: its type, its data blocks -- the base record's, then one per Continue that followed it -- and the base record's own offset in the stream. */
|
|
4
|
+
interface RecordGroup {
|
|
5
|
+
readonly type: number;
|
|
6
|
+
readonly blocks: readonly Uint8Array<ArrayBuffer>[];
|
|
7
|
+
readonly offset: number;
|
|
8
|
+
}
|
|
9
|
+
/** One substream: the document type its BOF declared, the records between that BOF and its EOF, its ordinal position among the stream's substreams, and the stream offset of its own BOF -- which is what a BoundSheet8's lbPlyPos names. */
|
|
10
|
+
interface Substream {
|
|
11
|
+
readonly documentType: number;
|
|
12
|
+
readonly records: readonly RecordGroup[];
|
|
13
|
+
readonly index: number;
|
|
14
|
+
readonly offset: number;
|
|
15
|
+
}
|
|
16
|
+
/** Joins each record to the Continue records following it, keeping the blocks separate. */
|
|
17
|
+
declare function groupRecords(records: readonly BiffRecord[]): readonly RecordGroup[];
|
|
18
|
+
/** Splits a grouped record sequence into its substreams, verifying each BOF declares BIFF8. */
|
|
19
|
+
declare function splitSubstreams(groups: readonly RecordGroup[]): readonly Substream[];
|
|
20
|
+
//#endregion
|
|
21
|
+
export { RecordGroup, Substream, groupRecords, splitSubstreams };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { n as BiffRecord } from "../records-DVIqXFKk.js";
|
|
2
|
+
//#region src/biff/substreams.d.ts
|
|
3
|
+
/** One logical record: its type, its data blocks -- the base record's, then one per Continue that followed it -- and the base record's own offset in the stream. */
|
|
4
|
+
interface RecordGroup {
|
|
5
|
+
readonly type: number;
|
|
6
|
+
readonly blocks: readonly Uint8Array<ArrayBuffer>[];
|
|
7
|
+
readonly offset: number;
|
|
8
|
+
}
|
|
9
|
+
/** One substream: the document type its BOF declared, the records between that BOF and its EOF, its ordinal position among the stream's substreams, and the stream offset of its own BOF -- which is what a BoundSheet8's lbPlyPos names. */
|
|
10
|
+
interface Substream {
|
|
11
|
+
readonly documentType: number;
|
|
12
|
+
readonly records: readonly RecordGroup[];
|
|
13
|
+
readonly index: number;
|
|
14
|
+
readonly offset: number;
|
|
15
|
+
}
|
|
16
|
+
/** Joins each record to the Continue records following it, keeping the blocks separate. */
|
|
17
|
+
declare function groupRecords(records: readonly BiffRecord[]): readonly RecordGroup[];
|
|
18
|
+
/** Splits a grouped record sequence into its substreams, verifying each BOF declares BIFF8. */
|
|
19
|
+
declare function splitSubstreams(groups: readonly RecordGroup[]): readonly Substream[];
|
|
20
|
+
//#endregion
|
|
21
|
+
export { RecordGroup, Substream, groupRecords, splitSubstreams };
|