xls-codec 4.10.0 → 4.11.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.
@@ -0,0 +1,545 @@
1
+ import { errorCodeOf } from "./errors.js";
2
+ import { BiffWriteError } from "./write-errors.js";
3
+ import { FTAB_FIXED_ARITY, FTAB_IFTAB_BY_NAME } from "./ptg-functions.js";
4
+ import { writeShortXLUnicodeString } from "./string-writer.js";
5
+ import { columnLettersToIndex } from "document-schema.js";
6
+ //#region src/biff/ptg-writer.ts
7
+ const PTG_ADD = 3;
8
+ const PTG_SUB = 4;
9
+ const PTG_MUL = 5;
10
+ const PTG_DIV = 6;
11
+ const PTG_POWER = 7;
12
+ const PTG_CONCAT = 8;
13
+ const PTG_LT = 9;
14
+ const PTG_LE = 10;
15
+ const PTG_EQ = 11;
16
+ const PTG_GE = 12;
17
+ const PTG_GT = 13;
18
+ const PTG_NE = 14;
19
+ const PTG_UPLUS = 18;
20
+ const PTG_UMINUS = 19;
21
+ const PTG_PERCENT = 20;
22
+ const PTG_PAREN = 21;
23
+ const PTG_MISSARG = 22;
24
+ const PTG_STR = 23;
25
+ const PTG_ERR = 28;
26
+ const PTG_BOOL = 29;
27
+ const PTG_INT = 30;
28
+ const PTG_NUM = 31;
29
+ /** The "value" class of the reference/function token family -- see biff/ptg.ts's own top comment for why REF/VALUE/ARRAY share one on-disk field layout and this writer, like every other real minimal BIFF8 writer, does not need to distinguish them for an ordinary (non-array) formula. */
30
+ const PTG_REF_VALUE = 68;
31
+ const PTG_AREA_VALUE = 69;
32
+ const PTG_FUNC_VALUE = 65;
33
+ const PTG_FUNCVAR_VALUE = 66;
34
+ const COLUMN_RELATIVE_BIT = 16384;
35
+ const ROW_RELATIVE_BIT = 32768;
36
+ /** BIFF8's own 16-bit row index and 8-bit column index ceilings ([MS-XLS] 2.4.221's Rw structure and 2.4.53's Col256U structure) -- the identical grid workbook/sheet-writer.ts's own checkedCellPosition enforces for a cell record's own row/column. */
37
+ const MAX_ROW_INDEX = 65535;
38
+ const MAX_COLUMN_INDEX = 255;
39
+ /** PtgInt's own ceiling ([MS-XLS] 2.5.198.28): an unsigned 16-bit integer. A plain non-negative integer literal above this, or one carrying a decimal point or exponent in its own source text, is written as PtgNum instead, so the reader's own String(cursor.u16())/String(cursor.f64()) reconstructs the identical text. */
40
+ const PTG_INT_MAX = 65535;
41
+ var RgceBuilder = class {
42
+ parts = [];
43
+ push(...bytes) {
44
+ this.parts.push(bytes);
45
+ return this;
46
+ }
47
+ u16(value) {
48
+ const bits = value & 65535;
49
+ return this.push(bits & 255, bits >>> 8 & 255);
50
+ }
51
+ f64(value) {
52
+ const buffer = /* @__PURE__ */ new ArrayBuffer(8);
53
+ new DataView(buffer).setFloat64(0, value, true);
54
+ return this.push(...new Uint8Array(buffer));
55
+ }
56
+ concat(bytes) {
57
+ this.parts.push(Array.from(bytes));
58
+ return this;
59
+ }
60
+ build() {
61
+ const flat = this.parts.flat();
62
+ return new Uint8Array(flat);
63
+ }
64
+ };
65
+ const NUMBER_RE = /^[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/;
66
+ const WORD_RE = /^[A-Za-z][A-Za-z0-9_.]*/;
67
+ const ERROR_RE = /^#[A-Za-z0-9/?!_]+/;
68
+ const OPERATORS = [
69
+ "<=",
70
+ ">=",
71
+ "<>",
72
+ "+",
73
+ "-",
74
+ "*",
75
+ "/",
76
+ "^",
77
+ "&",
78
+ "<",
79
+ ">",
80
+ "=",
81
+ "%"
82
+ ];
83
+ function tokenize(text) {
84
+ const tokens = [];
85
+ let index = 0;
86
+ while (index < text.length) {
87
+ const char = text[index];
88
+ if (char === " " || char === " " || char === "\n" || char === "\r") {
89
+ index += 1;
90
+ continue;
91
+ }
92
+ if (char === "$") {
93
+ tokens.push({
94
+ type: "dollar",
95
+ text: "$"
96
+ });
97
+ index += 1;
98
+ continue;
99
+ }
100
+ if (char === ":") {
101
+ tokens.push({
102
+ type: "colon",
103
+ text: ":"
104
+ });
105
+ index += 1;
106
+ continue;
107
+ }
108
+ if (char === ",") {
109
+ tokens.push({
110
+ type: "comma",
111
+ text: ","
112
+ });
113
+ index += 1;
114
+ continue;
115
+ }
116
+ if (char === "(") {
117
+ tokens.push({
118
+ type: "lparen",
119
+ text: "("
120
+ });
121
+ index += 1;
122
+ continue;
123
+ }
124
+ if (char === ")") {
125
+ tokens.push({
126
+ type: "rparen",
127
+ text: ")"
128
+ });
129
+ index += 1;
130
+ continue;
131
+ }
132
+ if (char === "\"") {
133
+ let value = "";
134
+ let cursor = index + 1;
135
+ for (;;) {
136
+ if (cursor >= text.length) throw new BiffWriteError(`formula text ${JSON.stringify(text)} carries an unterminated string literal starting at offset ${index}`);
137
+ const current = text.charAt(cursor);
138
+ if (current === "\"") {
139
+ if (text.charAt(cursor + 1) === "\"") {
140
+ value += "\"";
141
+ cursor += 2;
142
+ continue;
143
+ }
144
+ cursor += 1;
145
+ break;
146
+ }
147
+ value += current;
148
+ cursor += 1;
149
+ }
150
+ tokens.push({
151
+ type: "string",
152
+ text: value
153
+ });
154
+ index = cursor;
155
+ continue;
156
+ }
157
+ if (char === "#") {
158
+ const match = ERROR_RE.exec(text.slice(index));
159
+ if (match?.[0] === void 0) throw new BiffWriteError(`formula text ${JSON.stringify(text)} carries an unrecognised error literal starting at offset ${index}`);
160
+ tokens.push({
161
+ type: "error",
162
+ text: match[0]
163
+ });
164
+ index += match[0].length;
165
+ continue;
166
+ }
167
+ const numberMatch = NUMBER_RE.exec(text.slice(index));
168
+ if (numberMatch?.[0] !== void 0) {
169
+ tokens.push({
170
+ type: "number",
171
+ text: numberMatch[0]
172
+ });
173
+ index += numberMatch[0].length;
174
+ continue;
175
+ }
176
+ const wordMatch = WORD_RE.exec(text.slice(index));
177
+ if (wordMatch?.[0] !== void 0) {
178
+ tokens.push({
179
+ type: "word",
180
+ text: wordMatch[0]
181
+ });
182
+ index += wordMatch[0].length;
183
+ continue;
184
+ }
185
+ const op = OPERATORS.find((candidate) => text.startsWith(candidate, index));
186
+ if (op !== void 0) {
187
+ tokens.push({
188
+ type: "op",
189
+ text: op
190
+ });
191
+ index += op.length;
192
+ continue;
193
+ }
194
+ throw new BiffWriteError(`formula text ${JSON.stringify(text)} carries an unrecognised character ${JSON.stringify(char)} at offset ${index}`);
195
+ }
196
+ tokens.push({
197
+ type: "eof",
198
+ text: ""
199
+ });
200
+ return tokens;
201
+ }
202
+ var FormulaParser = class {
203
+ tokens;
204
+ position = 0;
205
+ sourceText;
206
+ constructor(tokens, sourceText) {
207
+ this.tokens = tokens;
208
+ this.sourceText = sourceText;
209
+ }
210
+ peek(offset = 0) {
211
+ const token = this.tokens[this.position + offset];
212
+ if (token === void 0) throw new BiffWriteError(`internal error: formula token stream for ${JSON.stringify(this.sourceText)} ran past its own end`);
213
+ return token;
214
+ }
215
+ advance() {
216
+ const token = this.peek();
217
+ this.position += 1;
218
+ return token;
219
+ }
220
+ expect(type) {
221
+ const token = this.peek();
222
+ if (token.type !== type) throw new BiffWriteError(`formula text ${JSON.stringify(this.sourceText)} expected a ${type} but found ${JSON.stringify(token.text)}`);
223
+ return this.advance();
224
+ }
225
+ parseFormula() {
226
+ const node = this.parseComparison();
227
+ this.expect("eof");
228
+ return node;
229
+ }
230
+ parseComparison() {
231
+ let node = this.parseConcat();
232
+ for (;;) {
233
+ const token = this.peek();
234
+ const opcode = this.comparisonOpcode(token);
235
+ if (opcode === void 0) return node;
236
+ this.advance();
237
+ const right = this.parseConcat();
238
+ node = {
239
+ kind: "binary",
240
+ opcode,
241
+ left: node,
242
+ right
243
+ };
244
+ }
245
+ }
246
+ comparisonOpcode(token) {
247
+ if (token.type !== "op") return void 0;
248
+ switch (token.text) {
249
+ case "<": return PTG_LT;
250
+ case "<=": return PTG_LE;
251
+ case "=": return PTG_EQ;
252
+ case ">=": return PTG_GE;
253
+ case ">": return PTG_GT;
254
+ case "<>": return PTG_NE;
255
+ default: return;
256
+ }
257
+ }
258
+ parseConcat() {
259
+ let node = this.parseAdditive();
260
+ while (this.peek().type === "op" && this.peek().text === "&") {
261
+ this.advance();
262
+ const right = this.parseAdditive();
263
+ node = {
264
+ kind: "binary",
265
+ opcode: PTG_CONCAT,
266
+ left: node,
267
+ right
268
+ };
269
+ }
270
+ return node;
271
+ }
272
+ parseAdditive() {
273
+ let node = this.parseMultiplicative();
274
+ for (;;) {
275
+ const token = this.peek();
276
+ if (token.type !== "op" || token.text !== "+" && token.text !== "-") return node;
277
+ this.advance();
278
+ const right = this.parseMultiplicative();
279
+ node = {
280
+ kind: "binary",
281
+ opcode: token.text === "+" ? PTG_ADD : PTG_SUB,
282
+ left: node,
283
+ right
284
+ };
285
+ }
286
+ }
287
+ parseMultiplicative() {
288
+ let node = this.parsePower();
289
+ for (;;) {
290
+ const token = this.peek();
291
+ if (token.type !== "op" || token.text !== "*" && token.text !== "/") return node;
292
+ this.advance();
293
+ const right = this.parsePower();
294
+ node = {
295
+ kind: "binary",
296
+ opcode: token.text === "*" ? PTG_MUL : PTG_DIV,
297
+ left: node,
298
+ right
299
+ };
300
+ }
301
+ }
302
+ parsePower() {
303
+ let node = this.parsePercent();
304
+ while (this.peek().type === "op" && this.peek().text === "^") {
305
+ this.advance();
306
+ const right = this.parsePercent();
307
+ node = {
308
+ kind: "binary",
309
+ opcode: PTG_POWER,
310
+ left: node,
311
+ right
312
+ };
313
+ }
314
+ return node;
315
+ }
316
+ parsePercent() {
317
+ let node = this.parseUnary();
318
+ while (this.peek().type === "op" && this.peek().text === "%") {
319
+ this.advance();
320
+ node = {
321
+ kind: "percent",
322
+ operand: node
323
+ };
324
+ }
325
+ return node;
326
+ }
327
+ parseUnary() {
328
+ const token = this.peek();
329
+ if (token.type === "op" && (token.text === "+" || token.text === "-")) {
330
+ this.advance();
331
+ const operand = this.parseUnary();
332
+ return {
333
+ kind: "unary",
334
+ opcode: token.text === "+" ? PTG_UPLUS : PTG_UMINUS,
335
+ operand
336
+ };
337
+ }
338
+ return this.parsePrimary();
339
+ }
340
+ parsePrimary() {
341
+ const token = this.peek();
342
+ if (token.type === "number") {
343
+ this.advance();
344
+ return this.numberNode(token.text);
345
+ }
346
+ if (token.type === "string") {
347
+ this.advance();
348
+ return {
349
+ kind: "str",
350
+ value: token.text
351
+ };
352
+ }
353
+ if (token.type === "error") {
354
+ this.advance();
355
+ const code = errorCodeOf(token.text);
356
+ if (code === void 0) throw new BiffWriteError(`formula text ${JSON.stringify(this.sourceText)} carries error literal ${token.text}, which is not one of the eight error values [MS-XLS] 2.5.10 defines`);
357
+ return {
358
+ kind: "err",
359
+ code
360
+ };
361
+ }
362
+ if (token.type === "lparen") {
363
+ this.advance();
364
+ const inner = this.parseComparison();
365
+ this.expect("rparen");
366
+ return {
367
+ kind: "paren",
368
+ inner
369
+ };
370
+ }
371
+ if (token.type === "dollar") return this.parseRefOrArea();
372
+ if (token.type === "word") {
373
+ if (this.peek(1).type === "lparen") return this.parseCall();
374
+ if (token.text === "TRUE" || token.text === "FALSE") {
375
+ this.advance();
376
+ return {
377
+ kind: "bool",
378
+ value: token.text === "TRUE"
379
+ };
380
+ }
381
+ return this.parseRefOrArea();
382
+ }
383
+ throw new BiffWriteError(`formula text ${JSON.stringify(this.sourceText)} carries an unexpected token ${JSON.stringify(token.text)}`);
384
+ }
385
+ numberNode(text) {
386
+ const value = Number.parseFloat(text);
387
+ if (/^[0-9]+$/.test(text) && Number.isInteger(value) && value >= 0 && value <= PTG_INT_MAX) return {
388
+ kind: "int",
389
+ value
390
+ };
391
+ return {
392
+ kind: "num",
393
+ value
394
+ };
395
+ }
396
+ parseCall() {
397
+ const nameToken = this.expect("word");
398
+ this.expect("lparen");
399
+ const args = [];
400
+ if (this.peek().type !== "rparen") {
401
+ args.push(this.parseArgument());
402
+ while (this.peek().type === "comma") {
403
+ this.advance();
404
+ args.push(this.parseArgument());
405
+ }
406
+ }
407
+ this.expect("rparen");
408
+ const iftab = FTAB_IFTAB_BY_NAME.get(nameToken.text);
409
+ if (iftab === void 0) throw new BiffWriteError(`formula text ${JSON.stringify(this.sourceText)} calls ${nameToken.text}(), which is not one of the built-in functions [MS-XLS] 2.5.198.17's own Ftab enumerates`);
410
+ const fixedArity = FTAB_FIXED_ARITY.get(iftab);
411
+ if (fixedArity !== void 0 && fixedArity !== args.length) throw new BiffWriteError(`formula text ${JSON.stringify(this.sourceText)} calls ${nameToken.text}() with ${args.length} argument(s), but [MS-XLS]'s own Ftab grammar fixes its arity at ${fixedArity}`);
412
+ return {
413
+ kind: "call",
414
+ iftab,
415
+ variable: fixedArity === void 0,
416
+ args
417
+ };
418
+ }
419
+ parseArgument() {
420
+ const token = this.peek();
421
+ if (token.type === "comma" || token.type === "rparen") return { kind: "missarg" };
422
+ return this.parseComparison();
423
+ }
424
+ parseRefOrArea() {
425
+ const start = this.parseCellPoint();
426
+ if (this.peek().type === "colon") {
427
+ this.advance();
428
+ return {
429
+ kind: "area",
430
+ start,
431
+ end: this.parseCellPoint()
432
+ };
433
+ }
434
+ return {
435
+ kind: "ref",
436
+ point: start
437
+ };
438
+ }
439
+ /** One cell reference's own point, per its own leading `$` (column-absolute) and, for a column-only word, a trailing `$` (row-absolute) -- see this module's own top comment for why a plain (non-`$`-prefixed) reference always lexes as one combined letters-then-digits word token, while a `$`-separated one splits across a dollar/word/dollar/number sequence instead. */
440
+ parseCellPoint() {
441
+ let columnAbsolute = false;
442
+ if (this.peek().type === "dollar") {
443
+ this.advance();
444
+ columnAbsolute = true;
445
+ }
446
+ const word = this.expect("word");
447
+ const combined = /^([A-Za-z]{1,3})([0-9]+)$/.exec(word.text);
448
+ let columnLetters;
449
+ let rowDigits;
450
+ let rowAbsolute = false;
451
+ if (combined?.[1] !== void 0 && combined[2] !== void 0) {
452
+ columnLetters = combined[1];
453
+ rowDigits = combined[2];
454
+ } else {
455
+ if (!/^[A-Za-z]{1,3}$/.test(word.text)) throw new BiffWriteError(`formula text ${JSON.stringify(this.sourceText)} carries ${JSON.stringify(word.text)}, which is not a valid cell reference`);
456
+ columnLetters = word.text;
457
+ if (this.peek().type === "dollar") {
458
+ this.advance();
459
+ rowAbsolute = true;
460
+ }
461
+ const rowToken = this.expect("number");
462
+ if (!/^[0-9]+$/.test(rowToken.text)) throw new BiffWriteError(`formula text ${JSON.stringify(this.sourceText)} carries ${JSON.stringify(word.text + rowToken.text)}, which is not a valid cell reference`);
463
+ rowDigits = rowToken.text;
464
+ }
465
+ const column = columnLettersToIndex(columnLetters);
466
+ const row = Number.parseInt(rowDigits, 10) - 1;
467
+ if (column === void 0 || column > MAX_COLUMN_INDEX || row < 0 || row > MAX_ROW_INDEX) throw new BiffWriteError(`formula text ${JSON.stringify(this.sourceText)} references ${columnLetters}${rowDigits}, which is outside BIFF8's own grid (rows 1-65536, columns A-IV)`);
468
+ return {
469
+ row,
470
+ column,
471
+ columnAbsolute,
472
+ rowAbsolute
473
+ };
474
+ }
475
+ };
476
+ function columnField(point) {
477
+ return point.column | (point.columnAbsolute ? 0 : COLUMN_RELATIVE_BIT) | (point.rowAbsolute ? 0 : ROW_RELATIVE_BIT);
478
+ }
479
+ function compileNode(builder, node) {
480
+ switch (node.kind) {
481
+ case "int":
482
+ builder.push(PTG_INT).u16(node.value);
483
+ return;
484
+ case "num":
485
+ builder.push(PTG_NUM).f64(node.value);
486
+ return;
487
+ case "str":
488
+ builder.push(PTG_STR).concat(writeShortXLUnicodeString(node.value));
489
+ return;
490
+ case "bool":
491
+ builder.push(PTG_BOOL, node.value ? 1 : 0);
492
+ return;
493
+ case "err":
494
+ builder.push(PTG_ERR, node.code);
495
+ return;
496
+ case "missarg":
497
+ builder.push(PTG_MISSARG);
498
+ return;
499
+ case "ref":
500
+ builder.push(PTG_REF_VALUE).u16(node.point.row).u16(columnField(node.point));
501
+ return;
502
+ case "area":
503
+ builder.push(PTG_AREA_VALUE).u16(node.start.row).u16(node.end.row).u16(columnField(node.start)).u16(columnField(node.end));
504
+ return;
505
+ case "binary":
506
+ compileNode(builder, node.left);
507
+ compileNode(builder, node.right);
508
+ builder.push(node.opcode);
509
+ return;
510
+ case "unary":
511
+ compileNode(builder, node.operand);
512
+ builder.push(node.opcode);
513
+ return;
514
+ case "percent":
515
+ compileNode(builder, node.operand);
516
+ builder.push(PTG_PERCENT);
517
+ return;
518
+ case "paren":
519
+ compileNode(builder, node.inner);
520
+ builder.push(PTG_PAREN);
521
+ return;
522
+ case "call":
523
+ for (const arg of node.args) compileNode(builder, arg);
524
+ if (node.variable) {
525
+ if (node.args.length > 255) throw new BiffWriteError(`a function call with ${node.args.length} arguments cannot be written: PtgFuncVar's own cparams field ([MS-XLS] 2.5.198.25) is a single byte, so it cannot exceed 255`);
526
+ builder.push(PTG_FUNCVAR_VALUE, node.args.length).u16(node.iftab);
527
+ } else builder.push(PTG_FUNC_VALUE).u16(node.iftab);
528
+ return;
529
+ }
530
+ }
531
+ /** [MS-XLS] 2.5.198.3's own cce ceiling: a two-byte length field, so rgce itself can never exceed this regardless of the 8224-byte whole-record limit biff/record-writer.ts already enforces. */
532
+ const MAX_RGCE_LENGTH = 65535;
533
+ /**
534
+ * Compiles same-sheet formula text into a Formula record's own rgce token stream -- the write-side counterpart of biff/ptg.ts's parseFormulaText, scoped to the subset this module's own top comment describes. Throws BiffWriteError, naming the construct, for anything outside that scope rather than emitting a token stream this package's own reader could not read back.
535
+ */
536
+ function compileFormulaText(text) {
537
+ const node = new FormulaParser(tokenize(text), text).parseFormula();
538
+ const builder = new RgceBuilder();
539
+ compileNode(builder, node);
540
+ const rgce = builder.build();
541
+ if (rgce.length > MAX_RGCE_LENGTH) throw new BiffWriteError(`formula text ${JSON.stringify(text)} compiles to ${rgce.length} bytes of rgce, above the ${MAX_RGCE_LENGTH}-byte ceiling its own cce field can hold`);
542
+ return rgce;
543
+ }
544
+ //#endregion
545
+ export { compileFormulaText };
@@ -42,6 +42,11 @@ function writeShortXLUnicodeString(text) {
42
42
  const { highByte, units } = encodeCharacters(text);
43
43
  return new require_biff_builder.RecordBuilder().u8(cch).u8(highByte ? FLAG_HIGH_BYTE : 0).bytes(units).build();
44
44
  }
45
+ /** An XLUnicodeStringNoCch ([MS-XLS] 2.5.296): a flags byte then the characters, with no character-count field of its own -- the containing structure states the count separately (a TxO record's own cchText, for the comment/text-box text a Continue record following it carries). */
46
+ function writeXLUnicodeStringNoCch(text) {
47
+ const { highByte, units } = encodeCharacters(text);
48
+ return new require_biff_builder.RecordBuilder().u8(highByte ? FLAG_HIGH_BYTE : 0).bytes(units).build();
49
+ }
45
50
  /**
46
51
  * An XLUnicodeRichExtendedString ([MS-XLS] 2.5.293): the SST's own element shape.
47
52
  *
@@ -56,3 +61,4 @@ function writeRichExtendedString(text) {
56
61
  exports.writeRichExtendedString = writeRichExtendedString;
57
62
  exports.writeShortXLUnicodeString = writeShortXLUnicodeString;
58
63
  exports.writeXLUnicodeString = writeXLUnicodeString;
64
+ exports.writeXLUnicodeStringNoCch = writeXLUnicodeStringNoCch;
@@ -3,6 +3,8 @@
3
3
  declare function writeXLUnicodeString(text: string): Uint8Array<ArrayBuffer>;
4
4
  /** A ShortXLUnicodeString ([MS-XLS] 2.5.240): as above, with a one-byte character count. */
5
5
  declare function writeShortXLUnicodeString(text: string): Uint8Array<ArrayBuffer>;
6
+ /** An XLUnicodeStringNoCch ([MS-XLS] 2.5.296): a flags byte then the characters, with no character-count field of its own -- the containing structure states the count separately (a TxO record's own cchText, for the comment/text-box text a Continue record following it carries). */
7
+ declare function writeXLUnicodeStringNoCch(text: string): Uint8Array<ArrayBuffer>;
6
8
  /**
7
9
  * An XLUnicodeRichExtendedString ([MS-XLS] 2.5.293): the SST's own element shape.
8
10
  *
@@ -10,4 +12,4 @@ declare function writeShortXLUnicodeString(text: string): Uint8Array<ArrayBuffer
10
12
  */
11
13
  declare function writeRichExtendedString(text: string): Uint8Array<ArrayBuffer>;
12
14
  //#endregion
13
- export { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString };
15
+ export { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString, writeXLUnicodeStringNoCch };
@@ -3,6 +3,8 @@
3
3
  declare function writeXLUnicodeString(text: string): Uint8Array<ArrayBuffer>;
4
4
  /** A ShortXLUnicodeString ([MS-XLS] 2.5.240): as above, with a one-byte character count. */
5
5
  declare function writeShortXLUnicodeString(text: string): Uint8Array<ArrayBuffer>;
6
+ /** An XLUnicodeStringNoCch ([MS-XLS] 2.5.296): a flags byte then the characters, with no character-count field of its own -- the containing structure states the count separately (a TxO record's own cchText, for the comment/text-box text a Continue record following it carries). */
7
+ declare function writeXLUnicodeStringNoCch(text: string): Uint8Array<ArrayBuffer>;
6
8
  /**
7
9
  * An XLUnicodeRichExtendedString ([MS-XLS] 2.5.293): the SST's own element shape.
8
10
  *
@@ -10,4 +12,4 @@ declare function writeShortXLUnicodeString(text: string): Uint8Array<ArrayBuffer
10
12
  */
11
13
  declare function writeRichExtendedString(text: string): Uint8Array<ArrayBuffer>;
12
14
  //#endregion
13
- export { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString };
15
+ export { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString, writeXLUnicodeStringNoCch };
@@ -41,6 +41,11 @@ function writeShortXLUnicodeString(text) {
41
41
  const { highByte, units } = encodeCharacters(text);
42
42
  return new RecordBuilder().u8(cch).u8(highByte ? FLAG_HIGH_BYTE : 0).bytes(units).build();
43
43
  }
44
+ /** An XLUnicodeStringNoCch ([MS-XLS] 2.5.296): a flags byte then the characters, with no character-count field of its own -- the containing structure states the count separately (a TxO record's own cchText, for the comment/text-box text a Continue record following it carries). */
45
+ function writeXLUnicodeStringNoCch(text) {
46
+ const { highByte, units } = encodeCharacters(text);
47
+ return new RecordBuilder().u8(highByte ? FLAG_HIGH_BYTE : 0).bytes(units).build();
48
+ }
44
49
  /**
45
50
  * An XLUnicodeRichExtendedString ([MS-XLS] 2.5.293): the SST's own element shape.
46
51
  *
@@ -52,4 +57,4 @@ function writeRichExtendedString(text) {
52
57
  return new RecordBuilder().u16(cch).u8(highByte ? FLAG_HIGH_BYTE : 0).bytes(units).build();
53
58
  }
54
59
  //#endregion
55
- export { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString };
60
+ export { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString, writeXLUnicodeStringNoCch };
package/dist/index.cjs CHANGED
@@ -155,6 +155,7 @@ exports.writeShortXLUnicodeString = require_biff_string_writer.writeShortXLUnico
155
155
  exports.writeStyleRecord = require_biff_xf_writer.writeStyleRecord;
156
156
  exports.writeStyleXfRecord = require_biff_xf_writer.writeStyleXfRecord;
157
157
  exports.writeXLUnicodeString = require_biff_string_writer.writeXLUnicodeString;
158
+ exports.writeXLUnicodeStringNoCch = require_biff_string_writer.writeXLUnicodeStringNoCch;
158
159
  exports.writeXls = require_write.writeXls;
159
160
  exports.writeXlsContent = require_write.writeXlsContent;
160
161
  var excel_number_format = require("excel-number-format");
package/dist/index.d.cts CHANGED
@@ -6,7 +6,7 @@ import { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_T
6
6
  import { concatRecords, writeRecord } from "./biff/record-writer.cjs";
7
7
  import { i as readRecords, n as BiffRecord, r as HEADER_SIZE, t as BiffFormatError } from "./records-G82UEVq8.cjs";
8
8
  import { decodeRkNumber } from "./biff/rk.cjs";
9
- import { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString } from "./biff/string-writer.cjs";
9
+ import { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString, writeXLUnicodeStringNoCch } from "./biff/string-writer.cjs";
10
10
  import { readRichExtendedString, readShortXLUnicodeString, readXLUnicodeString, readXLUnicodeStringNoCch } from "./biff/strings.cjs";
11
11
  import { a as splitSubstreams, i as recordByteLength, n as Substream, r as groupRecords, t as RecordGroup } from "./substreams-XDNgDvRJ.cjs";
12
12
  import { BiffWriteError } from "./biff/write-errors.cjs";
@@ -22,4 +22,4 @@ import { RawCell, RawCellValue, RawColumn, RawPrintSettings, RawRange, RawRow, R
22
22
  import { SheetWriteContext, buildWorksheetSubstream } from "./workbook/sheet-writer.cjs";
23
23
  import { writeXls, writeXlsContent } from "./write.cjs";
24
24
  export * from "excel-number-format";
25
- export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, BiffFormatError, BiffRecord, BiffWriteError, BlockCursor, CellFormat, CellXfPlanEntry, DEFAULT_COLUMN_WIDTH_CHARS, DEFAULT_ROW_HEIGHT_PT, GENERAL_CELL_XF_INDEX, HEADER_SIZE, MAX_RECORD_DATA_SIZE, RECORD_AI, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_CFEX, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MSODRAWING, RECORD_MSODRAWINGGROUP, RECORD_MSODRAWINGSELECTION, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SERIES, RECORD_SERIESTEXT, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SIINDEX, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF, RawCell, RawCellValue, RawColumn, RawPrintSettings, RawRange, RawRow, RawSheet, RecordBuilder, RecordGroup, SUMMARY_INFORMATION_STREAM, SheetEntry, SheetWriteContext, Substream, WorkbookGlobals, WorkbookGlobalsBuild, WorkbookGlobalsPlan, WorkbookStreams, XlsContentDocument, buildWorkbookGlobals, buildWorksheetSubstream, columnWidthToPoints, concatRecords, decodeRkNumber, errorCodeOf, errorTextOf, formatCodeOf, groupRecords, inchesToPoints, isXlsFile, isoDateTimeToSerial, isoDateToSerial, isoTimeToSerial, layoutMetadataToSummaryInformation, millimetresToPoints, pointsToColumnWidth, pointsToInches, pointsToTwips, readRecords, readRichExtendedString, readSheetRecords, readShortXLUnicodeString, readWorkbookGlobals, readWorkbookStreams, readXLUnicodeString, readXLUnicodeStringNoCch, readXls, readXlsContent, recordByteLength, serialToIsoDate, serialToIsoDateTime, serialToIsoTime, splitSubstreams, twipsToPoints, writeBofData, writeCellXfRecord, writeFontRecord, writeFormatRecord, writePaletteRecord, writeRecord, writeRichExtendedString, writeShortXLUnicodeString, writeStyleRecord, writeStyleXfRecord, writeXLUnicodeString, writeXls, writeXlsContent };
25
+ export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, BiffFormatError, BiffRecord, BiffWriteError, BlockCursor, CellFormat, CellXfPlanEntry, DEFAULT_COLUMN_WIDTH_CHARS, DEFAULT_ROW_HEIGHT_PT, GENERAL_CELL_XF_INDEX, HEADER_SIZE, MAX_RECORD_DATA_SIZE, RECORD_AI, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_CFEX, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MSODRAWING, RECORD_MSODRAWINGGROUP, RECORD_MSODRAWINGSELECTION, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SERIES, RECORD_SERIESTEXT, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SIINDEX, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF, RawCell, RawCellValue, RawColumn, RawPrintSettings, RawRange, RawRow, RawSheet, RecordBuilder, RecordGroup, SUMMARY_INFORMATION_STREAM, SheetEntry, SheetWriteContext, Substream, WorkbookGlobals, WorkbookGlobalsBuild, WorkbookGlobalsPlan, WorkbookStreams, XlsContentDocument, buildWorkbookGlobals, buildWorksheetSubstream, columnWidthToPoints, concatRecords, decodeRkNumber, errorCodeOf, errorTextOf, formatCodeOf, groupRecords, inchesToPoints, isXlsFile, isoDateTimeToSerial, isoDateToSerial, isoTimeToSerial, layoutMetadataToSummaryInformation, millimetresToPoints, pointsToColumnWidth, pointsToInches, pointsToTwips, readRecords, readRichExtendedString, readSheetRecords, readShortXLUnicodeString, readWorkbookGlobals, readWorkbookStreams, readXLUnicodeString, readXLUnicodeStringNoCch, readXls, readXlsContent, recordByteLength, serialToIsoDate, serialToIsoDateTime, serialToIsoTime, splitSubstreams, twipsToPoints, writeBofData, writeCellXfRecord, writeFontRecord, writeFormatRecord, writePaletteRecord, writeRecord, writeRichExtendedString, writeShortXLUnicodeString, writeStyleRecord, writeStyleXfRecord, writeXLUnicodeString, writeXLUnicodeStringNoCch, writeXls, writeXlsContent };
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_T
6
6
  import { concatRecords, writeRecord } from "./biff/record-writer.js";
7
7
  import { i as readRecords, n as BiffRecord, r as HEADER_SIZE, t as BiffFormatError } from "./records-G82UEVq8.js";
8
8
  import { decodeRkNumber } from "./biff/rk.js";
9
- import { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString } from "./biff/string-writer.js";
9
+ import { writeRichExtendedString, writeShortXLUnicodeString, writeXLUnicodeString, writeXLUnicodeStringNoCch } from "./biff/string-writer.js";
10
10
  import { readRichExtendedString, readShortXLUnicodeString, readXLUnicodeString, readXLUnicodeStringNoCch } from "./biff/strings.js";
11
11
  import { a as splitSubstreams, i as recordByteLength, n as Substream, r as groupRecords, t as RecordGroup } from "./substreams-CgTHx5kX.js";
12
12
  import { BiffWriteError } from "./biff/write-errors.js";
@@ -22,4 +22,4 @@ import { RawCell, RawCellValue, RawColumn, RawPrintSettings, RawRange, RawRow, R
22
22
  import { SheetWriteContext, buildWorksheetSubstream } from "./workbook/sheet-writer.js";
23
23
  import { writeXls, writeXlsContent } from "./write.js";
24
24
  export * from "excel-number-format";
25
- export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, BiffFormatError, BiffRecord, BiffWriteError, BlockCursor, CellFormat, CellXfPlanEntry, DEFAULT_COLUMN_WIDTH_CHARS, DEFAULT_ROW_HEIGHT_PT, GENERAL_CELL_XF_INDEX, HEADER_SIZE, MAX_RECORD_DATA_SIZE, RECORD_AI, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_CFEX, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MSODRAWING, RECORD_MSODRAWINGGROUP, RECORD_MSODRAWINGSELECTION, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SERIES, RECORD_SERIESTEXT, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SIINDEX, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF, RawCell, RawCellValue, RawColumn, RawPrintSettings, RawRange, RawRow, RawSheet, RecordBuilder, RecordGroup, SUMMARY_INFORMATION_STREAM, SheetEntry, SheetWriteContext, Substream, WorkbookGlobals, WorkbookGlobalsBuild, WorkbookGlobalsPlan, WorkbookStreams, XlsContentDocument, buildWorkbookGlobals, buildWorksheetSubstream, columnWidthToPoints, concatRecords, decodeRkNumber, errorCodeOf, errorTextOf, formatCodeOf, groupRecords, inchesToPoints, isXlsFile, isoDateTimeToSerial, isoDateToSerial, isoTimeToSerial, layoutMetadataToSummaryInformation, millimetresToPoints, pointsToColumnWidth, pointsToInches, pointsToTwips, readRecords, readRichExtendedString, readSheetRecords, readShortXLUnicodeString, readWorkbookGlobals, readWorkbookStreams, readXLUnicodeString, readXLUnicodeStringNoCch, readXls, readXlsContent, recordByteLength, serialToIsoDate, serialToIsoDateTime, serialToIsoTime, splitSubstreams, twipsToPoints, writeBofData, writeCellXfRecord, writeFontRecord, writeFormatRecord, writePaletteRecord, writeRecord, writeRichExtendedString, writeShortXLUnicodeString, writeStyleRecord, writeStyleXfRecord, writeXLUnicodeString, writeXls, writeXlsContent };
25
+ export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, BiffFormatError, BiffRecord, BiffWriteError, BlockCursor, CellFormat, CellXfPlanEntry, DEFAULT_COLUMN_WIDTH_CHARS, DEFAULT_ROW_HEIGHT_PT, GENERAL_CELL_XF_INDEX, HEADER_SIZE, MAX_RECORD_DATA_SIZE, RECORD_AI, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_CFEX, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MSODRAWING, RECORD_MSODRAWINGGROUP, RECORD_MSODRAWINGSELECTION, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SERIES, RECORD_SERIESTEXT, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SIINDEX, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF, RawCell, RawCellValue, RawColumn, RawPrintSettings, RawRange, RawRow, RawSheet, RecordBuilder, RecordGroup, SUMMARY_INFORMATION_STREAM, SheetEntry, SheetWriteContext, Substream, WorkbookGlobals, WorkbookGlobalsBuild, WorkbookGlobalsPlan, WorkbookStreams, XlsContentDocument, buildWorkbookGlobals, buildWorksheetSubstream, columnWidthToPoints, concatRecords, decodeRkNumber, errorCodeOf, errorTextOf, formatCodeOf, groupRecords, inchesToPoints, isXlsFile, isoDateTimeToSerial, isoDateToSerial, isoTimeToSerial, layoutMetadataToSummaryInformation, millimetresToPoints, pointsToColumnWidth, pointsToInches, pointsToTwips, readRecords, readRichExtendedString, readSheetRecords, readShortXLUnicodeString, readWorkbookGlobals, readWorkbookStreams, readXLUnicodeString, readXLUnicodeStringNoCch, readXls, readXlsContent, recordByteLength, serialToIsoDate, serialToIsoDateTime, serialToIsoTime, splitSubstreams, twipsToPoints, writeBofData, writeCellXfRecord, writeFontRecord, writeFormatRecord, writePaletteRecord, writeRecord, writeRichExtendedString, writeShortXLUnicodeString, writeStyleRecord, writeStyleXfRecord, writeXLUnicodeString, writeXLUnicodeStringNoCch, writeXls, writeXlsContent };