reamkit 1.13.0 → 1.15.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 +34 -8
- package/dist/esm/core/converter/facade.d.ts +8 -1
- package/dist/esm/core/converter/facade.js +34 -8
- package/dist/esm/core/converter/ream.d.ts +1 -0
- package/dist/esm/core/converter/ream.js +13 -8
- package/dist/esm/core/document-model/types.d.ts +2 -0
- package/dist/esm/core/ir/features.d.ts +1 -0
- package/dist/esm/core/ir/features.js +1 -0
- package/dist/esm/core/ir/sheet.d.ts +42 -3
- package/dist/esm/core/ole/cfb.d.ts +19 -0
- package/dist/esm/core/ole/cfb.js +158 -0
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +81 -1
- package/dist/esm/excel/activex-parser.d.ts +9 -0
- package/dist/esm/excel/activex-parser.js +188 -0
- package/dist/esm/excel/comments-parser.d.ts +4 -0
- package/dist/esm/excel/comments-parser.js +104 -0
- package/dist/esm/excel/conditional-format.d.ts +5 -3
- package/dist/esm/excel/conditional-format.js +248 -12
- package/dist/esm/excel/form-control-parser.d.ts +6 -0
- package/dist/esm/excel/form-control-parser.js +29 -0
- package/dist/esm/excel/formula/context.d.ts +11 -0
- package/dist/esm/excel/formula/dates.d.ts +11 -0
- package/dist/esm/excel/formula/dates.js +46 -0
- package/dist/esm/excel/formula/eval.d.ts +11 -0
- package/dist/esm/excel/formula/eval.js +196 -0
- package/dist/esm/excel/formula/functions.d.ts +7 -0
- package/dist/esm/excel/formula/functions.js +1359 -0
- package/dist/esm/excel/formula/index.d.ts +14 -0
- package/dist/esm/excel/formula/index.js +17 -0
- package/dist/esm/excel/formula/lexer.d.ts +8 -0
- package/dist/esm/excel/formula/lexer.js +163 -0
- package/dist/esm/excel/formula/parser.d.ts +57 -0
- package/dist/esm/excel/formula/parser.js +274 -0
- package/dist/esm/excel/formula/value.d.ts +52 -0
- package/dist/esm/excel/formula/value.js +102 -0
- package/dist/esm/excel/header-footer.d.ts +2 -0
- package/dist/esm/excel/header-footer.js +127 -0
- package/dist/esm/excel/index.d.ts +1 -1
- package/dist/esm/excel/number-format.d.ts +2 -0
- package/dist/esm/excel/number-format.js +5 -1
- package/dist/esm/excel/print-model.d.ts +7 -2
- package/dist/esm/excel/print-model.js +123 -16
- package/dist/esm/excel/shared-strings-parser.d.ts +6 -1
- package/dist/esm/excel/shared-strings-parser.js +91 -12
- package/dist/esm/excel/sheet-drawing.d.ts +13 -1
- package/dist/esm/excel/sheet-drawing.js +47 -14
- package/dist/esm/excel/sheet-shape-parser.d.ts +4 -0
- package/dist/esm/excel/sheet-shape-parser.js +96 -0
- package/dist/esm/excel/sheet-to-flow.d.ts +4 -1
- package/dist/esm/excel/sheet-to-flow.js +170 -3
- package/dist/esm/excel/styles-parser.js +37 -0
- package/dist/esm/excel/worksheet-parser.js +191 -1
- package/dist/esm/excel/xls/biff-chart.d.ts +8 -0
- package/dist/esm/excel/xls/biff-chart.js +121 -0
- package/dist/esm/excel/xls/biff-reader.d.ts +4 -0
- package/dist/esm/excel/xls/biff-reader.js +1418 -0
- package/dist/esm/excel/xls/biff-styles.d.ts +8 -0
- package/dist/esm/excel/xls/biff-styles.js +299 -0
- package/dist/esm/excel/xls/escher.d.ts +24 -0
- package/dist/esm/excel/xls/escher.js +171 -0
- package/dist/esm/excel/xls/xls-reader.d.ts +3 -0
- package/dist/esm/excel/xls/xls-reader.js +30 -0
- package/dist/esm/excel/xlsx-reader.d.ts +2 -1
- package/dist/esm/excel/xlsx-reader.js +134 -16
- package/dist/esm/excel/xlsx-to-pdf.d.ts +1 -0
- package/dist/esm/excel/xlsx-to-pdf.js +2 -2
- package/dist/esm/excel/xlsx-writer.js +12 -2
- package/dist/esm/layout/styled-layout.js +29 -0
- package/dist/esm/pptx/ppt/ppt-reader.d.ts +4 -0
- package/dist/esm/pptx/ppt/ppt-reader.js +337 -0
- package/dist/esm/pptx/ppt/ppt-text.d.ts +69 -0
- package/dist/esm/pptx/ppt/ppt-text.js +756 -0
- package/dist/esm/pptx/slide-parser.d.ts +4 -2
- package/dist/esm/pptx/slide-parser.js +1 -1
- package/dist/esm/word/doc/doc-reader.d.ts +4 -0
- package/dist/esm/word/doc/doc-reader.js +421 -0
- package/dist/esm/word/doc/doc-text.d.ts +79 -0
- package/dist/esm/word/doc/doc-text.js +706 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1418 @@
|
|
|
1
|
+
import { pt } from "../../core/ir/units.js";
|
|
2
|
+
import { ResourceStore } from "../../core/ir/resources.js";
|
|
3
|
+
import { openCfb } from "../../core/ole/cfb.js";
|
|
4
|
+
import { parseBiffChart } from "./biff-chart.js";
|
|
5
|
+
import { buildBiffPalette, parseBiffStyles } from "./biff-styles.js";
|
|
6
|
+
import { parseBlipStore, parseSheetPictures, parseSheetShapes } from "./escher.js";
|
|
7
|
+
//#region src/excel/xls/biff-reader.ts
|
|
8
|
+
var REC = {
|
|
9
|
+
BOF: 2057,
|
|
10
|
+
EOF: 10,
|
|
11
|
+
BOUNDSHEET8: 133,
|
|
12
|
+
SST: 252,
|
|
13
|
+
CONTINUE: 60,
|
|
14
|
+
DATEMODE: 34,
|
|
15
|
+
DIMENSIONS: 512,
|
|
16
|
+
NUMBER: 515,
|
|
17
|
+
RK: 638,
|
|
18
|
+
MULRK: 189,
|
|
19
|
+
LABELSST: 253,
|
|
20
|
+
LABEL: 516,
|
|
21
|
+
RSTRING: 214,
|
|
22
|
+
BOOLERR: 517,
|
|
23
|
+
FORMULA: 6,
|
|
24
|
+
STRING: 519,
|
|
25
|
+
MERGECELLS: 229,
|
|
26
|
+
COLINFO: 125,
|
|
27
|
+
ROW: 520,
|
|
28
|
+
WINDOW2: 574,
|
|
29
|
+
PANE: 65,
|
|
30
|
+
MSODRAWINGGROUP: 235,
|
|
31
|
+
MSODRAWING: 236,
|
|
32
|
+
TXO: 438,
|
|
33
|
+
HLINK: 440,
|
|
34
|
+
NAME: 24,
|
|
35
|
+
SETUP: 161,
|
|
36
|
+
WSBOOL: 129,
|
|
37
|
+
PRINTGRIDLINES: 43,
|
|
38
|
+
HCENTER: 131,
|
|
39
|
+
VCENTER: 132,
|
|
40
|
+
LEFTMARGIN: 38,
|
|
41
|
+
RIGHTMARGIN: 39,
|
|
42
|
+
TOPMARGIN: 40,
|
|
43
|
+
BOTTOMMARGIN: 41,
|
|
44
|
+
HEADER: 20,
|
|
45
|
+
FOOTER: 21,
|
|
46
|
+
HPAGEBREAK: 27,
|
|
47
|
+
VPAGEBREAK: 26,
|
|
48
|
+
NOTE: 28,
|
|
49
|
+
OBJ: 93,
|
|
50
|
+
DV: 446,
|
|
51
|
+
CONDFMT: 432,
|
|
52
|
+
CF: 433,
|
|
53
|
+
CONDFMT12: 2169,
|
|
54
|
+
CF12: 2170
|
|
55
|
+
};
|
|
56
|
+
var MAX_SHEETS = 4096;
|
|
57
|
+
var MAX_CELLS = 1 << 22;
|
|
58
|
+
var MAX_STRINGS = 1 << 21;
|
|
59
|
+
var MAX_ROW_HEIGHTS = 1 << 20;
|
|
60
|
+
function readXlsToSheetDoc(xls) {
|
|
61
|
+
const cfb = openCfb(xls);
|
|
62
|
+
const wb = cfb.readStream("Workbook") ?? cfb.readStream("Book");
|
|
63
|
+
if (!wb) throw new Error("not an .xls: no Workbook/Book stream");
|
|
64
|
+
const view = new DataView(wb.buffer, wb.byteOffset, wb.byteLength);
|
|
65
|
+
const globals = readSubstream(wb, view, 0);
|
|
66
|
+
if (globals.length === 0 || globals[0].type !== REC.BOF) throw new Error(".xls: missing workbook globals BOF");
|
|
67
|
+
if (globals[0].data.length >= 2 && readU16(globals[0].data, 0) !== 1536) throw new Error(".xls: only BIFF8 (Excel 97-2003) is supported — re-save as .xlsx");
|
|
68
|
+
let date1904 = false;
|
|
69
|
+
const boundSheets = [];
|
|
70
|
+
let sharedStrings = [];
|
|
71
|
+
const lblRecords = [];
|
|
72
|
+
for (let i = 0; i < globals.length; i++) {
|
|
73
|
+
const rec = globals[i];
|
|
74
|
+
switch (rec.type) {
|
|
75
|
+
case REC.NAME:
|
|
76
|
+
lblRecords.push(rec.data);
|
|
77
|
+
break;
|
|
78
|
+
case REC.DATEMODE:
|
|
79
|
+
date1904 = rec.data.length >= 2 && readU16(rec.data, 0) === 1;
|
|
80
|
+
break;
|
|
81
|
+
case REC.BOUNDSHEET8:
|
|
82
|
+
if (boundSheets.length < MAX_SHEETS) boundSheets.push(parseBoundSheet(rec.data));
|
|
83
|
+
break;
|
|
84
|
+
case REC.SST: {
|
|
85
|
+
const blocks = [rec.data];
|
|
86
|
+
while (i + 1 < globals.length && globals[i + 1].type === REC.CONTINUE) blocks.push(globals[++i].data);
|
|
87
|
+
sharedStrings = readSst(blocks);
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const resources = new ResourceStore();
|
|
93
|
+
const blips = parseBlipStore(gatherDrawing(globals, REC.MSODRAWINGGROUP));
|
|
94
|
+
const chartData = /* @__PURE__ */ new Map();
|
|
95
|
+
const dxfs = [];
|
|
96
|
+
const cfColor = buildBiffPalette(globals);
|
|
97
|
+
const sheets = [];
|
|
98
|
+
for (const bs of boundSheets) {
|
|
99
|
+
if (bs.type !== 0) continue;
|
|
100
|
+
if (bs.offset + 4 > wb.length) continue;
|
|
101
|
+
const { grid, images, charts, shapes, hyperlinks, comments } = readSheet(wb, view, bs.offset, blips, resources, sharedStrings, chartData, dxfs, cfColor);
|
|
102
|
+
sheets.push({
|
|
103
|
+
name: bs.name,
|
|
104
|
+
grid,
|
|
105
|
+
...images.length > 0 ? { images } : {},
|
|
106
|
+
...charts.length > 0 ? { charts } : {},
|
|
107
|
+
...shapes.length > 0 ? { shapes } : {},
|
|
108
|
+
...hyperlinks.length > 0 ? { hyperlinks } : {},
|
|
109
|
+
...comments.length > 0 ? { comments } : {}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (sheets.length === 0) throw new Error(".xls has no worksheets");
|
|
113
|
+
const baseStyles = parseBiffStyles(globals);
|
|
114
|
+
return {
|
|
115
|
+
kind: "sheet",
|
|
116
|
+
sheets,
|
|
117
|
+
styles: dxfs.length > 0 ? {
|
|
118
|
+
...baseStyles,
|
|
119
|
+
dxfs
|
|
120
|
+
} : baseStyles,
|
|
121
|
+
sharedStrings,
|
|
122
|
+
definedNames: buildDefinedNames(lblRecords, boundSheets),
|
|
123
|
+
date1904,
|
|
124
|
+
resources,
|
|
125
|
+
...chartData.size > 0 ? { chartData } : {}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function gatherDrawing(recs, type) {
|
|
129
|
+
const parts = [];
|
|
130
|
+
let inside = false;
|
|
131
|
+
for (const rec of recs) if (rec.type === type) {
|
|
132
|
+
parts.push(rec.data);
|
|
133
|
+
inside = true;
|
|
134
|
+
} else if (rec.type === REC.CONTINUE && inside) parts.push(rec.data);
|
|
135
|
+
else inside = false;
|
|
136
|
+
return concatBytes(parts);
|
|
137
|
+
}
|
|
138
|
+
function concatBytes(parts) {
|
|
139
|
+
const total = parts.reduce((n, p) => n + p.length, 0);
|
|
140
|
+
const out = new Uint8Array(total);
|
|
141
|
+
let off = 0;
|
|
142
|
+
for (const p of parts) {
|
|
143
|
+
out.set(p, off);
|
|
144
|
+
off += p.length;
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
function readSubstream(wb, view, start) {
|
|
149
|
+
const out = [];
|
|
150
|
+
let p = start;
|
|
151
|
+
let depth = 0;
|
|
152
|
+
while (p + 4 <= wb.length) {
|
|
153
|
+
const type = view.getUint16(p, true);
|
|
154
|
+
const len = view.getUint16(p + 2, true);
|
|
155
|
+
const dataStart = p + 4;
|
|
156
|
+
if (dataStart + len > wb.length) break;
|
|
157
|
+
out.push({
|
|
158
|
+
type,
|
|
159
|
+
data: wb.subarray(dataStart, dataStart + len)
|
|
160
|
+
});
|
|
161
|
+
p = dataStart + len;
|
|
162
|
+
if (type === REC.BOF) depth++;
|
|
163
|
+
else if (type === REC.EOF && --depth <= 0) break;
|
|
164
|
+
if (out.length > 1e6) break;
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
}
|
|
168
|
+
function parseBoundSheet(data) {
|
|
169
|
+
const offset = readU32(data, 0);
|
|
170
|
+
const type = data[5] ?? 0;
|
|
171
|
+
return {
|
|
172
|
+
name: readShortString(data, 6),
|
|
173
|
+
offset,
|
|
174
|
+
type
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function readSheet(wb, view, start, blips, resources, sharedStrings, chartData, dxfs, cfColor) {
|
|
178
|
+
const records = readSubstream(wb, view, start);
|
|
179
|
+
const cells = [];
|
|
180
|
+
const merges = [];
|
|
181
|
+
const columns = [];
|
|
182
|
+
const hyperlinks = [];
|
|
183
|
+
const rowHeights = [];
|
|
184
|
+
let frozen = false;
|
|
185
|
+
let paneSplit;
|
|
186
|
+
let maxRow = -1;
|
|
187
|
+
let maxColumn = -1;
|
|
188
|
+
const add = (cell) => {
|
|
189
|
+
if (cells.length >= MAX_CELLS) return;
|
|
190
|
+
cells.push(cell);
|
|
191
|
+
if (cell.row > maxRow) maxRow = cell.row;
|
|
192
|
+
if (cell.column > maxColumn) maxColumn = cell.column;
|
|
193
|
+
};
|
|
194
|
+
for (let i = 0; i < records.length; i++) {
|
|
195
|
+
const rec = records[i];
|
|
196
|
+
const d = rec.data;
|
|
197
|
+
switch (rec.type) {
|
|
198
|
+
case REC.NUMBER:
|
|
199
|
+
add(numCell(readU16(d, 0), readU16(d, 2), readU16(d, 4), String(readF64(d, 6))));
|
|
200
|
+
break;
|
|
201
|
+
case REC.RK:
|
|
202
|
+
add(numCell(readU16(d, 0), readU16(d, 2), readU16(d, 4), String(decodeRk(readU32(d, 6)))));
|
|
203
|
+
break;
|
|
204
|
+
case REC.MULRK: {
|
|
205
|
+
const row = readU16(d, 0);
|
|
206
|
+
const colFirst = readU16(d, 2);
|
|
207
|
+
const count = Math.floor((d.length - 6) / 6);
|
|
208
|
+
for (let k = 0; k < count; k++) {
|
|
209
|
+
const ixfe = readU16(d, 4 + k * 6);
|
|
210
|
+
const rk = readU32(d, 4 + k * 6 + 2);
|
|
211
|
+
add(numCell(row, colFirst + k, ixfe, String(decodeRk(rk))));
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
case REC.LABELSST: {
|
|
216
|
+
const isst = readU32(d, 6);
|
|
217
|
+
add({
|
|
218
|
+
column: readU16(d, 2),
|
|
219
|
+
row: readU16(d, 0),
|
|
220
|
+
type: "s",
|
|
221
|
+
rawValue: String(isst),
|
|
222
|
+
styleIndex: readU16(d, 4)
|
|
223
|
+
});
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
case REC.LABEL:
|
|
227
|
+
case REC.RSTRING:
|
|
228
|
+
add(strCell(readU16(d, 0), readU16(d, 2), readU16(d, 4), readXlString(d, 6)));
|
|
229
|
+
break;
|
|
230
|
+
case REC.BOOLERR: {
|
|
231
|
+
const row = readU16(d, 0);
|
|
232
|
+
const col = readU16(d, 2);
|
|
233
|
+
const styleIndex = readU16(d, 4);
|
|
234
|
+
const val = d[6] ?? 0;
|
|
235
|
+
add((d[7] ?? 0) !== 0 ? {
|
|
236
|
+
column: col,
|
|
237
|
+
row,
|
|
238
|
+
type: "e",
|
|
239
|
+
rawValue: errorText(val),
|
|
240
|
+
styleIndex
|
|
241
|
+
} : {
|
|
242
|
+
column: col,
|
|
243
|
+
row,
|
|
244
|
+
type: "b",
|
|
245
|
+
rawValue: val ? "1" : "0",
|
|
246
|
+
styleIndex
|
|
247
|
+
});
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
case REC.FORMULA: {
|
|
251
|
+
const cell = formulaCell(d, records[i + 1]);
|
|
252
|
+
if (cell) add(cell);
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
case REC.MERGECELLS: {
|
|
256
|
+
const cmcs = readU16(d, 0);
|
|
257
|
+
for (let k = 0; k < cmcs; k++) {
|
|
258
|
+
const o = 2 + k * 8;
|
|
259
|
+
if (o + 8 > d.length) break;
|
|
260
|
+
merges.push({
|
|
261
|
+
startRow: readU16(d, o),
|
|
262
|
+
endRow: readU16(d, o + 2),
|
|
263
|
+
startColumn: readU16(d, o + 4),
|
|
264
|
+
endColumn: readU16(d, o + 6)
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
case REC.COLINFO: {
|
|
270
|
+
const colFirst = readU16(d, 0);
|
|
271
|
+
const colLast = readU16(d, 2);
|
|
272
|
+
const widthChars = readU16(d, 4) / 256;
|
|
273
|
+
columns.push({
|
|
274
|
+
min: colFirst + 1,
|
|
275
|
+
max: colLast + 1,
|
|
276
|
+
widthChars
|
|
277
|
+
});
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
case REC.ROW:
|
|
281
|
+
if (d.length >= 14 && rowHeights.length < MAX_ROW_HEIGHTS) {
|
|
282
|
+
if ((readU16(d, 12) & 64) !== 0) rowHeights.push({
|
|
283
|
+
row: readU16(d, 0),
|
|
284
|
+
heightPt: (readU16(d, 6) & 32767) / 20,
|
|
285
|
+
customHeight: true
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
break;
|
|
289
|
+
case REC.WINDOW2:
|
|
290
|
+
if (d.length >= 2) frozen = (readU16(d, 0) & 8) !== 0;
|
|
291
|
+
break;
|
|
292
|
+
case REC.PANE:
|
|
293
|
+
if (d.length >= 4) paneSplit = {
|
|
294
|
+
cols: readU16(d, 0),
|
|
295
|
+
rows: readU16(d, 2)
|
|
296
|
+
};
|
|
297
|
+
break;
|
|
298
|
+
case REC.HLINK: {
|
|
299
|
+
const link = parseHlink(d);
|
|
300
|
+
if (link) hyperlinks.push(link);
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const dataValidations = parseDataValidations(records);
|
|
306
|
+
const conditionalFormats = [...parseConditionalFormats(records, dxfs, cfColor), ...parseConditionalFormats12(records, cfColor)];
|
|
307
|
+
const pane = frozen && paneSplit && (paneSplit.rows > 0 || paneSplit.cols > 0) ? {
|
|
308
|
+
frozenRows: paneSplit.rows,
|
|
309
|
+
frozenCols: paneSplit.cols
|
|
310
|
+
} : void 0;
|
|
311
|
+
const grid = {
|
|
312
|
+
cells,
|
|
313
|
+
maxRow,
|
|
314
|
+
maxColumn,
|
|
315
|
+
columns,
|
|
316
|
+
merges,
|
|
317
|
+
rowHeights,
|
|
318
|
+
...parsePrintModel(records),
|
|
319
|
+
...dataValidations.length > 0 ? { dataValidations } : {},
|
|
320
|
+
...conditionalFormats.length > 0 ? { conditionalFormats } : {},
|
|
321
|
+
...pane ? { pane } : {}
|
|
322
|
+
};
|
|
323
|
+
const drawing = gatherDrawing(records, REC.MSODRAWING);
|
|
324
|
+
const images = drawing.length > 0 && blips.length > 0 ? buildImages(drawing, blips, resources) : [];
|
|
325
|
+
const charts = [];
|
|
326
|
+
for (let i = 0; i < records.length; i++) {
|
|
327
|
+
if (records[i].type !== REC.BOF || readU16(records[i].data, 2) !== 32) continue;
|
|
328
|
+
let depth = 0;
|
|
329
|
+
const sub = [];
|
|
330
|
+
let j = i;
|
|
331
|
+
for (; j < records.length; j++) {
|
|
332
|
+
sub.push(records[j]);
|
|
333
|
+
if (records[j].type === REC.BOF) depth++;
|
|
334
|
+
else if (records[j].type === REC.EOF && --depth <= 0) break;
|
|
335
|
+
}
|
|
336
|
+
i = j;
|
|
337
|
+
const chart = parseBiffChart(sub, cells, sharedStrings);
|
|
338
|
+
if (chart) {
|
|
339
|
+
const path = `xls-chart-${chartData.size}`;
|
|
340
|
+
chartData.set(path, chart);
|
|
341
|
+
charts.push({
|
|
342
|
+
chartPartPath: path,
|
|
343
|
+
widthPt: 360,
|
|
344
|
+
heightPt: 240
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
grid,
|
|
350
|
+
images,
|
|
351
|
+
charts,
|
|
352
|
+
shapes: drawing.length > 0 ? buildShapes(parseSheetShapes(drawing), gatherTxoTexts(records)) : [],
|
|
353
|
+
hyperlinks,
|
|
354
|
+
comments: parseComments(records)
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
var HLINK_HAS_MONIKER = 1;
|
|
358
|
+
var HLINK_HAS_DISPLAY_NAME = 16;
|
|
359
|
+
var HLINK_HAS_FRAME_NAME = 128;
|
|
360
|
+
var HLINK_MONIKER_AS_STR = 256;
|
|
361
|
+
var URL_MONIKER_CLSID = [
|
|
362
|
+
224,
|
|
363
|
+
201,
|
|
364
|
+
234,
|
|
365
|
+
121,
|
|
366
|
+
249,
|
|
367
|
+
186,
|
|
368
|
+
206,
|
|
369
|
+
17,
|
|
370
|
+
140,
|
|
371
|
+
130,
|
|
372
|
+
0,
|
|
373
|
+
170,
|
|
374
|
+
0,
|
|
375
|
+
75,
|
|
376
|
+
169,
|
|
377
|
+
11
|
|
378
|
+
];
|
|
379
|
+
function parseHlink(d) {
|
|
380
|
+
if (d.length < 32) return void 0;
|
|
381
|
+
const ref = {
|
|
382
|
+
startRow: readU16(d, 0),
|
|
383
|
+
endRow: readU16(d, 2),
|
|
384
|
+
startColumn: readU16(d, 4),
|
|
385
|
+
endColumn: readU16(d, 6)
|
|
386
|
+
};
|
|
387
|
+
if (readU32(d, 24) !== 2) return void 0;
|
|
388
|
+
const flags = readU32(d, 28);
|
|
389
|
+
let off = 32;
|
|
390
|
+
if (flags & HLINK_HAS_DISPLAY_NAME) off = skipHlinkString(d, off);
|
|
391
|
+
if (flags & HLINK_HAS_FRAME_NAME) off = skipHlinkString(d, off);
|
|
392
|
+
if ((flags & HLINK_HAS_MONIKER) === 0) return void 0;
|
|
393
|
+
if (flags & HLINK_MONIKER_AS_STR) {
|
|
394
|
+
const s = readHlinkString(d, off);
|
|
395
|
+
return s && isAbsoluteUrl(s.value) ? {
|
|
396
|
+
ref,
|
|
397
|
+
url: s.value
|
|
398
|
+
} : void 0;
|
|
399
|
+
}
|
|
400
|
+
if (off + 16 > d.length || !clsidEquals(d, off, URL_MONIKER_CLSID)) return void 0;
|
|
401
|
+
const url = readUrlMonikerUrl(d, off + 16);
|
|
402
|
+
return url ? {
|
|
403
|
+
ref,
|
|
404
|
+
url
|
|
405
|
+
} : void 0;
|
|
406
|
+
}
|
|
407
|
+
function readHlinkString(d, off) {
|
|
408
|
+
if (off + 4 > d.length) return void 0;
|
|
409
|
+
const bytes = readU32(d, off) * 2;
|
|
410
|
+
const start = off + 4;
|
|
411
|
+
if (start + bytes > d.length) return void 0;
|
|
412
|
+
return {
|
|
413
|
+
value: stripNul(decodeUtf16Le(d, start, bytes)),
|
|
414
|
+
next: start + bytes
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
function skipHlinkString(d, off) {
|
|
418
|
+
return readHlinkString(d, off)?.next ?? d.length;
|
|
419
|
+
}
|
|
420
|
+
function readUrlMonikerUrl(d, off) {
|
|
421
|
+
if (off + 4 > d.length) return void 0;
|
|
422
|
+
let s = "";
|
|
423
|
+
for (let i = off + 4; i + 1 < d.length; i += 2) {
|
|
424
|
+
const c = d[i] | d[i + 1] << 8;
|
|
425
|
+
if (c === 0) break;
|
|
426
|
+
s += String.fromCharCode(c);
|
|
427
|
+
}
|
|
428
|
+
return s.length > 0 ? s : void 0;
|
|
429
|
+
}
|
|
430
|
+
function decodeUtf16Le(d, off, bytes) {
|
|
431
|
+
let s = "";
|
|
432
|
+
for (let i = 0; i + 1 < bytes; i += 2) s += String.fromCharCode(d[off + i] | d[off + i + 1] << 8);
|
|
433
|
+
return s;
|
|
434
|
+
}
|
|
435
|
+
function stripNul(s) {
|
|
436
|
+
for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 0) return s.slice(0, i);
|
|
437
|
+
return s;
|
|
438
|
+
}
|
|
439
|
+
function isAbsoluteUrl(s) {
|
|
440
|
+
return /^[a-z][a-z0-9+.-]*:\/\//i.test(s);
|
|
441
|
+
}
|
|
442
|
+
function clsidEquals(d, off, clsid) {
|
|
443
|
+
for (let i = 0; i < 16; i++) if (d[off + i] !== clsid[i]) return false;
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
function parsePrintModel(records) {
|
|
447
|
+
let paperSize;
|
|
448
|
+
let orientation;
|
|
449
|
+
let scale;
|
|
450
|
+
let fitToWidth;
|
|
451
|
+
let fitToHeight;
|
|
452
|
+
let fitToPage;
|
|
453
|
+
let gridLines;
|
|
454
|
+
let horizontalCentered;
|
|
455
|
+
let verticalCentered;
|
|
456
|
+
let left;
|
|
457
|
+
let right;
|
|
458
|
+
let top;
|
|
459
|
+
let bottom;
|
|
460
|
+
let headerMargin;
|
|
461
|
+
let footerMargin;
|
|
462
|
+
let oddHeader;
|
|
463
|
+
let oddFooter;
|
|
464
|
+
let rowBreaks;
|
|
465
|
+
let colBreaks;
|
|
466
|
+
for (const r of records) {
|
|
467
|
+
const d = r.data;
|
|
468
|
+
switch (r.type) {
|
|
469
|
+
case REC.SETUP: {
|
|
470
|
+
if (d.length < 12) break;
|
|
471
|
+
const grbit = readU16(d, 10);
|
|
472
|
+
if ((grbit & 4) === 0 && (grbit & 64) === 0) orientation = (grbit & 2) !== 0 ? "portrait" : "landscape";
|
|
473
|
+
const sc = readU16(d, 2);
|
|
474
|
+
if (sc >= 10 && sc <= 400) scale = sc;
|
|
475
|
+
const ps = readU16(d, 0);
|
|
476
|
+
if ((grbit & 4) === 0 && ps > 0) paperSize = ps;
|
|
477
|
+
fitToWidth = readU16(d, 6);
|
|
478
|
+
fitToHeight = readU16(d, 8);
|
|
479
|
+
if (d.length >= 32) {
|
|
480
|
+
headerMargin = readF64(d, 16);
|
|
481
|
+
footerMargin = readF64(d, 24);
|
|
482
|
+
}
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
case REC.WSBOOL:
|
|
486
|
+
if (d.length >= 2) fitToPage = (readU16(d, 0) & 256) !== 0;
|
|
487
|
+
break;
|
|
488
|
+
case REC.PRINTGRIDLINES:
|
|
489
|
+
if (d.length >= 2) gridLines = (readU16(d, 0) & 1) !== 0;
|
|
490
|
+
break;
|
|
491
|
+
case REC.HCENTER:
|
|
492
|
+
if (d.length >= 2) horizontalCentered = readU16(d, 0) !== 0;
|
|
493
|
+
break;
|
|
494
|
+
case REC.VCENTER:
|
|
495
|
+
if (d.length >= 2) verticalCentered = readU16(d, 0) !== 0;
|
|
496
|
+
break;
|
|
497
|
+
case REC.LEFTMARGIN:
|
|
498
|
+
if (d.length >= 8) left = readF64(d, 0);
|
|
499
|
+
break;
|
|
500
|
+
case REC.RIGHTMARGIN:
|
|
501
|
+
if (d.length >= 8) right = readF64(d, 0);
|
|
502
|
+
break;
|
|
503
|
+
case REC.TOPMARGIN:
|
|
504
|
+
if (d.length >= 8) top = readF64(d, 0);
|
|
505
|
+
break;
|
|
506
|
+
case REC.BOTTOMMARGIN:
|
|
507
|
+
if (d.length >= 8) bottom = readF64(d, 0);
|
|
508
|
+
break;
|
|
509
|
+
case REC.HEADER: {
|
|
510
|
+
const s = readXlString(d, 0);
|
|
511
|
+
if (s.length > 0) oddHeader = s;
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
case REC.FOOTER: {
|
|
515
|
+
const s = readXlString(d, 0);
|
|
516
|
+
if (s.length > 0) oddFooter = s;
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
case REC.HPAGEBREAK:
|
|
520
|
+
rowBreaks = parseBreaks(d);
|
|
521
|
+
break;
|
|
522
|
+
case REC.VPAGEBREAK:
|
|
523
|
+
colBreaks = parseBreaks(d);
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const pageSetup = {
|
|
528
|
+
...paperSize !== void 0 ? { paperSize } : {},
|
|
529
|
+
...orientation !== void 0 ? { orientation } : {},
|
|
530
|
+
...scale !== void 0 ? { scale } : {},
|
|
531
|
+
...fitToWidth !== void 0 ? { fitToWidth } : {},
|
|
532
|
+
...fitToHeight !== void 0 ? { fitToHeight } : {}
|
|
533
|
+
};
|
|
534
|
+
const printOptions = {
|
|
535
|
+
...gridLines !== void 0 ? { gridLines } : {},
|
|
536
|
+
...horizontalCentered !== void 0 ? { horizontalCentered } : {},
|
|
537
|
+
...verticalCentered !== void 0 ? { verticalCentered } : {}
|
|
538
|
+
};
|
|
539
|
+
const pageMargins = left !== void 0 && right !== void 0 && top !== void 0 && bottom !== void 0 ? {
|
|
540
|
+
leftInches: left,
|
|
541
|
+
rightInches: right,
|
|
542
|
+
topInches: top,
|
|
543
|
+
bottomInches: bottom,
|
|
544
|
+
...headerMargin !== void 0 ? { headerInches: headerMargin } : {},
|
|
545
|
+
...footerMargin !== void 0 ? { footerInches: footerMargin } : {}
|
|
546
|
+
} : void 0;
|
|
547
|
+
const headerFooter = {
|
|
548
|
+
...oddHeader !== void 0 ? { oddHeader } : {},
|
|
549
|
+
...oddFooter !== void 0 ? { oddFooter } : {}
|
|
550
|
+
};
|
|
551
|
+
return {
|
|
552
|
+
...Object.keys(pageSetup).length > 0 ? { pageSetup } : {},
|
|
553
|
+
...fitToPage !== void 0 ? { fitToPage } : {},
|
|
554
|
+
...Object.keys(printOptions).length > 0 ? { printOptions } : {},
|
|
555
|
+
...pageMargins ? { pageMargins } : {},
|
|
556
|
+
...Object.keys(headerFooter).length > 0 ? { headerFooter } : {},
|
|
557
|
+
...rowBreaks && rowBreaks.length > 0 ? { rowBreaks } : {},
|
|
558
|
+
...colBreaks && colBreaks.length > 0 ? { colBreaks } : {}
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function parseBreaks(d) {
|
|
562
|
+
const count = readU16(d, 0);
|
|
563
|
+
const out = [];
|
|
564
|
+
for (let k = 0; k < count && 2 + k * 6 + 2 <= d.length; k++) out.push(readU16(d, 2 + k * 6));
|
|
565
|
+
return out;
|
|
566
|
+
}
|
|
567
|
+
var BUILTIN_NAMES = new Map([[6, "_xlnm.Print_Area"], [7, "_xlnm.Print_Titles"]]);
|
|
568
|
+
function buildDefinedNames(lblRecords, boundSheets) {
|
|
569
|
+
const wsIndex = [];
|
|
570
|
+
let ws = 0;
|
|
571
|
+
for (const bs of boundSheets) wsIndex.push(bs.type === 0 ? ws++ : void 0);
|
|
572
|
+
const out = [];
|
|
573
|
+
for (const d of lblRecords) {
|
|
574
|
+
const dn = parseLbl(d, wsIndex);
|
|
575
|
+
if (dn) out.push(dn);
|
|
576
|
+
}
|
|
577
|
+
return out;
|
|
578
|
+
}
|
|
579
|
+
function parseLbl(d, wsIndex) {
|
|
580
|
+
if (d.length < 15) return void 0;
|
|
581
|
+
const builtin = (readU16(d, 0) & 32) !== 0;
|
|
582
|
+
const cch = d[3];
|
|
583
|
+
const cce = readU16(d, 4);
|
|
584
|
+
const itab = readU16(d, 8);
|
|
585
|
+
const highByte = (d[14] & 1) !== 0;
|
|
586
|
+
const nameBytes = cch * (highByte ? 2 : 1);
|
|
587
|
+
let name;
|
|
588
|
+
if (builtin) {
|
|
589
|
+
const id = highByte ? readU16(d, 15) : d[15] ?? 255;
|
|
590
|
+
const mapped = BUILTIN_NAMES.get(id);
|
|
591
|
+
if (mapped === void 0) return void 0;
|
|
592
|
+
name = mapped;
|
|
593
|
+
} else {
|
|
594
|
+
name = decodeChars(d, 15, cch, highByte);
|
|
595
|
+
if (name.length === 0) return void 0;
|
|
596
|
+
}
|
|
597
|
+
const rgceOff = 15 + nameBytes;
|
|
598
|
+
const value = formatNameValue(d.subarray(rgceOff, Math.min(d.length, rgceOff + cce)));
|
|
599
|
+
if (value === void 0) return void 0;
|
|
600
|
+
if (itab > 0) {
|
|
601
|
+
const localSheetId = wsIndex[itab - 1];
|
|
602
|
+
if (localSheetId === void 0) return void 0;
|
|
603
|
+
return {
|
|
604
|
+
name,
|
|
605
|
+
value,
|
|
606
|
+
localSheetId
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
name,
|
|
611
|
+
value
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
function formatNameValue(rgce) {
|
|
615
|
+
const areas = extractNameAreas(rgce);
|
|
616
|
+
return areas ? areas.map(formatArea).join(",") : void 0;
|
|
617
|
+
}
|
|
618
|
+
function extractNameAreas(rgce) {
|
|
619
|
+
const areas = [];
|
|
620
|
+
let off = 0;
|
|
621
|
+
while (off < rgce.length) {
|
|
622
|
+
const ptg = rgce[off];
|
|
623
|
+
const base = ptg & 31;
|
|
624
|
+
if (ptg >= 32 && base === 5) {
|
|
625
|
+
if (off + 9 > rgce.length) return void 0;
|
|
626
|
+
areas.push(readArea(rgce, off + 1));
|
|
627
|
+
off += 9;
|
|
628
|
+
} else if (ptg >= 32 && base === 27) {
|
|
629
|
+
if (off + 11 > rgce.length) return void 0;
|
|
630
|
+
areas.push(readArea(rgce, off + 3));
|
|
631
|
+
off += 11;
|
|
632
|
+
} else if (ptg >= 32 && base === 4) {
|
|
633
|
+
if (off + 5 > rgce.length) return void 0;
|
|
634
|
+
areas.push(readCell(rgce, off + 1));
|
|
635
|
+
off += 5;
|
|
636
|
+
} else if (ptg >= 32 && base === 26) {
|
|
637
|
+
if (off + 7 > rgce.length) return void 0;
|
|
638
|
+
areas.push(readCell(rgce, off + 3));
|
|
639
|
+
off += 7;
|
|
640
|
+
} else if (ptg >= 32 && base === 9) off += 3;
|
|
641
|
+
else if (ptg >= 32 && base === 6) off += 7;
|
|
642
|
+
else if (ptg === 16 || ptg === 15 || ptg === 17 || ptg === 21) off += 1;
|
|
643
|
+
else return;
|
|
644
|
+
}
|
|
645
|
+
return areas.length > 0 ? areas : void 0;
|
|
646
|
+
}
|
|
647
|
+
function readArea(d, off) {
|
|
648
|
+
return {
|
|
649
|
+
r0: readU16(d, off),
|
|
650
|
+
r1: readU16(d, off + 2),
|
|
651
|
+
c0: readU16(d, off + 4) & 16383,
|
|
652
|
+
c1: readU16(d, off + 6) & 16383
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
function readCell(d, off) {
|
|
656
|
+
const r = readU16(d, off);
|
|
657
|
+
const c = readU16(d, off + 2) & 16383;
|
|
658
|
+
return {
|
|
659
|
+
r0: r,
|
|
660
|
+
r1: r,
|
|
661
|
+
c0: c,
|
|
662
|
+
c1: c
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
function formatArea(a) {
|
|
666
|
+
const fullWidth = a.c0 === 0 && a.c1 >= 255;
|
|
667
|
+
const fullHeight = a.r0 === 0 && a.r1 >= 65535;
|
|
668
|
+
if (fullWidth && !fullHeight) return `${a.r0 + 1}:${a.r1 + 1}`;
|
|
669
|
+
if (fullHeight && !fullWidth) return `${colLetters(a.c0)}:${colLetters(a.c1)}`;
|
|
670
|
+
const tl = `${colLetters(a.c0)}${a.r0 + 1}`;
|
|
671
|
+
return a.r0 === a.r1 && a.c0 === a.c1 ? tl : `${tl}:${colLetters(a.c1)}${a.r1 + 1}`;
|
|
672
|
+
}
|
|
673
|
+
function colLetters(c) {
|
|
674
|
+
let n = c + 1;
|
|
675
|
+
let s = "";
|
|
676
|
+
while (n > 0) {
|
|
677
|
+
n--;
|
|
678
|
+
s = String.fromCharCode(65 + n % 26) + s;
|
|
679
|
+
n = Math.floor(n / 26);
|
|
680
|
+
}
|
|
681
|
+
return s;
|
|
682
|
+
}
|
|
683
|
+
var DV_TYPES = [
|
|
684
|
+
"none",
|
|
685
|
+
"whole",
|
|
686
|
+
"decimal",
|
|
687
|
+
"list",
|
|
688
|
+
"date",
|
|
689
|
+
"time",
|
|
690
|
+
"textLength",
|
|
691
|
+
"custom"
|
|
692
|
+
];
|
|
693
|
+
var DV_OPERATORS = [
|
|
694
|
+
"between",
|
|
695
|
+
"notBetween",
|
|
696
|
+
"equal",
|
|
697
|
+
"notEqual",
|
|
698
|
+
"greaterThan",
|
|
699
|
+
"lessThan",
|
|
700
|
+
"greaterThanOrEqual",
|
|
701
|
+
"lessThanOrEqual"
|
|
702
|
+
];
|
|
703
|
+
var DV_OPERATOR_TYPES = new Set([
|
|
704
|
+
"whole",
|
|
705
|
+
"decimal",
|
|
706
|
+
"date",
|
|
707
|
+
"time",
|
|
708
|
+
"textLength"
|
|
709
|
+
]);
|
|
710
|
+
function parseDataValidations(records) {
|
|
711
|
+
const out = [];
|
|
712
|
+
for (const r of records) if (r.type === REC.DV) {
|
|
713
|
+
const dv = parseDv(r.data);
|
|
714
|
+
if (dv) out.push(dv);
|
|
715
|
+
}
|
|
716
|
+
return out;
|
|
717
|
+
}
|
|
718
|
+
function parseDv(d) {
|
|
719
|
+
if (d.length < 4) return void 0;
|
|
720
|
+
const flags = readU32(d, 0);
|
|
721
|
+
const type = DV_TYPES[flags & 15];
|
|
722
|
+
if (type === void 0) return void 0;
|
|
723
|
+
const operator = DV_OPERATORS[flags >> 20 & 15];
|
|
724
|
+
let off = 4;
|
|
725
|
+
const promptTitle = readXlStringEnd(d, off);
|
|
726
|
+
off = promptTitle.next;
|
|
727
|
+
const errorTitle = readXlStringEnd(d, off);
|
|
728
|
+
off = errorTitle.next;
|
|
729
|
+
const prompt = readXlStringEnd(d, off);
|
|
730
|
+
off = prompt.next;
|
|
731
|
+
const error = readXlStringEnd(d, off);
|
|
732
|
+
off = error.next;
|
|
733
|
+
if (off + 4 > d.length) return void 0;
|
|
734
|
+
const cce1 = readU16(d, off);
|
|
735
|
+
off += 4;
|
|
736
|
+
const rgce1 = d.subarray(off, Math.min(d.length, off + cce1));
|
|
737
|
+
off += cce1;
|
|
738
|
+
if (off + 4 > d.length) return void 0;
|
|
739
|
+
const cce2 = readU16(d, off);
|
|
740
|
+
off += 4 + cce2;
|
|
741
|
+
if (off + 2 > d.length) return void 0;
|
|
742
|
+
const cref = readU16(d, off);
|
|
743
|
+
off += 2;
|
|
744
|
+
const ranges = [];
|
|
745
|
+
for (let k = 0; k < cref && off + 8 <= d.length; k++) {
|
|
746
|
+
ranges.push({
|
|
747
|
+
startRow: readU16(d, off),
|
|
748
|
+
endRow: readU16(d, off + 2),
|
|
749
|
+
startColumn: readU16(d, off + 4),
|
|
750
|
+
endColumn: readU16(d, off + 6)
|
|
751
|
+
});
|
|
752
|
+
off += 8;
|
|
753
|
+
}
|
|
754
|
+
if (ranges.length === 0) return void 0;
|
|
755
|
+
const formula1 = type === "list" ? extractListSource(rgce1) : void 0;
|
|
756
|
+
return {
|
|
757
|
+
type,
|
|
758
|
+
ranges,
|
|
759
|
+
...operator !== void 0 && DV_OPERATOR_TYPES.has(type) ? { operator } : {},
|
|
760
|
+
...(flags & 256) !== 0 ? { allowBlank: true } : {},
|
|
761
|
+
showDropDown: (flags & 512) !== 0,
|
|
762
|
+
...(flags & 262144) !== 0 ? { showInputMessage: true } : {},
|
|
763
|
+
...(flags & 524288) !== 0 ? { showErrorMessage: true } : {},
|
|
764
|
+
...promptTitle.value ? { promptTitle: promptTitle.value } : {},
|
|
765
|
+
...errorTitle.value ? { errorTitle: errorTitle.value } : {},
|
|
766
|
+
...prompt.value ? { prompt: prompt.value } : {},
|
|
767
|
+
...error.value ? { error: error.value } : {},
|
|
768
|
+
...formula1 ? { formula1 } : {}
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
function extractListSource(rgce) {
|
|
772
|
+
if (rgce.length >= 3 && rgce[0] === 23) {
|
|
773
|
+
const cch = rgce[1];
|
|
774
|
+
return `"${decodeChars(rgce, 3, cch, (rgce[2] & 1) !== 0)}"`;
|
|
775
|
+
}
|
|
776
|
+
const areas = extractNameAreas(rgce);
|
|
777
|
+
return areas ? areas.map(formatArea).join(",") : void 0;
|
|
778
|
+
}
|
|
779
|
+
function readXlStringEnd(d, off) {
|
|
780
|
+
if (off + 3 > d.length) return {
|
|
781
|
+
value: "",
|
|
782
|
+
next: d.length
|
|
783
|
+
};
|
|
784
|
+
const cch = readU16(d, off);
|
|
785
|
+
const flags = d[off + 2];
|
|
786
|
+
const high = (flags & 1) !== 0;
|
|
787
|
+
let p = off + 3;
|
|
788
|
+
if ((flags & 8) !== 0) p += 2;
|
|
789
|
+
if ((flags & 4) !== 0) p += 4;
|
|
790
|
+
return {
|
|
791
|
+
value: decodeChars(d, p, cch, high),
|
|
792
|
+
next: p + cch * (high ? 2 : 1)
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
var CF_OPERATORS = [
|
|
796
|
+
void 0,
|
|
797
|
+
"between",
|
|
798
|
+
"notBetween",
|
|
799
|
+
"equal",
|
|
800
|
+
"notEqual",
|
|
801
|
+
"greaterThan",
|
|
802
|
+
"lessThan",
|
|
803
|
+
"greaterThanOrEqual",
|
|
804
|
+
"lessThanOrEqual"
|
|
805
|
+
];
|
|
806
|
+
var DXF_FONT = 67108864;
|
|
807
|
+
var DXF_ALIGN = 134217728;
|
|
808
|
+
var DXF_BORDER = 268435456;
|
|
809
|
+
var DXF_PATTERN = 536870912;
|
|
810
|
+
var DXF_PROT = 1073741824;
|
|
811
|
+
function parseConditionalFormats(records, dxfs, color) {
|
|
812
|
+
const out = [];
|
|
813
|
+
for (let i = 0; i < records.length; i++) {
|
|
814
|
+
if (records[i].type !== REC.CONDFMT) continue;
|
|
815
|
+
const head = records[i].data;
|
|
816
|
+
if (head.length < 14) continue;
|
|
817
|
+
const ccf = readU16(head, 0);
|
|
818
|
+
const cref = readU16(head, 12);
|
|
819
|
+
const ranges = [];
|
|
820
|
+
for (let k = 0; k < cref && 14 + k * 8 + 8 <= head.length; k++) {
|
|
821
|
+
const o = 14 + k * 8;
|
|
822
|
+
ranges.push({
|
|
823
|
+
startRow: readU16(head, o),
|
|
824
|
+
endRow: readU16(head, o + 2),
|
|
825
|
+
startColumn: readU16(head, o + 4),
|
|
826
|
+
endColumn: readU16(head, o + 6)
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
const rules = [];
|
|
830
|
+
let priority = 1;
|
|
831
|
+
for (let j = i + 1; j < records.length && rules.length < ccf; j++) {
|
|
832
|
+
if (records[j].type !== REC.CF) break;
|
|
833
|
+
const rule = parseCfRule(records[j].data, dxfs, color, priority++);
|
|
834
|
+
if (rule) rules.push(rule);
|
|
835
|
+
}
|
|
836
|
+
if (ranges.length > 0 && rules.length > 0) out.push({
|
|
837
|
+
ranges,
|
|
838
|
+
rules
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
return out;
|
|
842
|
+
}
|
|
843
|
+
function parseCfRule(d, dxfs, color, priority) {
|
|
844
|
+
if (d.length < 6) return void 0;
|
|
845
|
+
const ct = d[0];
|
|
846
|
+
if (ct !== 1 && ct !== 2) return void 0;
|
|
847
|
+
const cce1 = readU16(d, 2);
|
|
848
|
+
const cce2 = readU16(d, 4);
|
|
849
|
+
const rgce1Start = d.length - cce2 - cce1;
|
|
850
|
+
if (rgce1Start < 6) return void 0;
|
|
851
|
+
const dxfId = dxfs.length;
|
|
852
|
+
dxfs.push(parseCfDxf(d, rgce1Start, color));
|
|
853
|
+
if (ct === 2) return {
|
|
854
|
+
type: "expression",
|
|
855
|
+
priority,
|
|
856
|
+
formula: "(formula)",
|
|
857
|
+
dxfId
|
|
858
|
+
};
|
|
859
|
+
const operator = CF_OPERATORS[d[1]];
|
|
860
|
+
if (operator === void 0) return void 0;
|
|
861
|
+
const formulas = [];
|
|
862
|
+
const f1 = cfConstant(d.subarray(rgce1Start, d.length - cce2));
|
|
863
|
+
if (f1 !== void 0) formulas.push(f1);
|
|
864
|
+
if (cce2 > 0) {
|
|
865
|
+
const f2 = cfConstant(d.subarray(d.length - cce2));
|
|
866
|
+
if (f2 !== void 0) formulas.push(f2);
|
|
867
|
+
}
|
|
868
|
+
return {
|
|
869
|
+
type: "cellIs",
|
|
870
|
+
priority,
|
|
871
|
+
operator,
|
|
872
|
+
formulas,
|
|
873
|
+
dxfId
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
function parseCfDxf(d, rgce1Start, color) {
|
|
877
|
+
const dxf = {};
|
|
878
|
+
if (rgce1Start < 12) return dxf;
|
|
879
|
+
const options = readU32(d, 6);
|
|
880
|
+
let p = 12;
|
|
881
|
+
const fontAt = (options & DXF_FONT) !== 0 ? p : -1;
|
|
882
|
+
if (options & DXF_FONT) p += 118;
|
|
883
|
+
if (options & DXF_ALIGN) p += 8;
|
|
884
|
+
if (options & DXF_BORDER) p += 8;
|
|
885
|
+
const patAt = (options & DXF_PATTERN) !== 0 ? p : -1;
|
|
886
|
+
if (options & DXF_PATTERN) p += 4;
|
|
887
|
+
if (options & DXF_PROT) p += 2;
|
|
888
|
+
if (p !== rgce1Start) return dxf;
|
|
889
|
+
if (patAt >= 0 && patAt + 4 <= d.length) {
|
|
890
|
+
const pat = readU32(d, patAt);
|
|
891
|
+
const hex = color(pat >> 16 & 127) ?? color(pat >> 23 & 127);
|
|
892
|
+
if (hex) dxf.fill = {
|
|
893
|
+
patternType: "solid",
|
|
894
|
+
fgColorHex: hex
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
if (fontAt >= 0 && fontAt + 84 <= d.length) {
|
|
898
|
+
const icvFore = readU32(d, fontAt + 80) | 0;
|
|
899
|
+
if (icvFore >= 0) {
|
|
900
|
+
const hex = color(icvFore);
|
|
901
|
+
if (hex) dxf.font = { colorHex: hex };
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return dxf;
|
|
905
|
+
}
|
|
906
|
+
function cfConstant(rgce) {
|
|
907
|
+
if (rgce.length < 1) return void 0;
|
|
908
|
+
const ptg = rgce[0];
|
|
909
|
+
if (ptg === 30 && rgce.length >= 3) return String(readU16(rgce, 1));
|
|
910
|
+
if (ptg === 31 && rgce.length >= 9) return String(readF64(rgce, 1));
|
|
911
|
+
if (ptg === 23 && rgce.length >= 3) return `"${decodeChars(rgce, 3, rgce[1], (rgce[2] & 1) !== 0)}"`;
|
|
912
|
+
}
|
|
913
|
+
var FTR_HEADER = 12;
|
|
914
|
+
var CF12_COLOR_SCALE = 3;
|
|
915
|
+
var CF12_DATA_BAR = 4;
|
|
916
|
+
var CF12_ICON_SET = 6;
|
|
917
|
+
var CF12_ICON_REVERSED = 4;
|
|
918
|
+
var CF12_ICON_SETS = [
|
|
919
|
+
"3Arrows",
|
|
920
|
+
"3ArrowsGray",
|
|
921
|
+
"3Flags",
|
|
922
|
+
"3TrafficLights1",
|
|
923
|
+
"3TrafficLights2",
|
|
924
|
+
"3Signs",
|
|
925
|
+
"3Symbols",
|
|
926
|
+
"3Symbols2",
|
|
927
|
+
"4Arrows",
|
|
928
|
+
"4ArrowsGray",
|
|
929
|
+
"4RedToBlack",
|
|
930
|
+
"4Rating",
|
|
931
|
+
"4TrafficLights",
|
|
932
|
+
"5Arrows",
|
|
933
|
+
"5ArrowsGray",
|
|
934
|
+
"5Rating",
|
|
935
|
+
"5Quarters"
|
|
936
|
+
];
|
|
937
|
+
var CF12_CFVO_TYPES = [
|
|
938
|
+
void 0,
|
|
939
|
+
"num",
|
|
940
|
+
"min",
|
|
941
|
+
"max",
|
|
942
|
+
"percent",
|
|
943
|
+
"percentile",
|
|
944
|
+
void 0,
|
|
945
|
+
"formula"
|
|
946
|
+
];
|
|
947
|
+
var u8 = (c) => c.d[c.p++] ?? 0;
|
|
948
|
+
var u16At = (c) => {
|
|
949
|
+
const v = readU16(c.d, c.p);
|
|
950
|
+
c.p += 2;
|
|
951
|
+
return v;
|
|
952
|
+
};
|
|
953
|
+
var i32At = (c) => {
|
|
954
|
+
const v = readU32(c.d, c.p) | 0;
|
|
955
|
+
c.p += 4;
|
|
956
|
+
return v;
|
|
957
|
+
};
|
|
958
|
+
var f64At = (c) => {
|
|
959
|
+
const v = readF64(c.d, c.p);
|
|
960
|
+
c.p += 8;
|
|
961
|
+
return v;
|
|
962
|
+
};
|
|
963
|
+
function rgbToHex(r, g, b) {
|
|
964
|
+
return (r.toString(16).padStart(2, "0") + g.toString(16).padStart(2, "0") + b.toString(16).padStart(2, "0")).toUpperCase();
|
|
965
|
+
}
|
|
966
|
+
function readExtColor(c, color) {
|
|
967
|
+
if (c.p + 16 > c.d.length) return void 0;
|
|
968
|
+
const xclrType = i32At(c);
|
|
969
|
+
let hex;
|
|
970
|
+
if (xclrType === 1) hex = color(i32At(c));
|
|
971
|
+
else if (xclrType === 2) {
|
|
972
|
+
hex = rgbToHex(c.d[c.p] ?? 0, c.d[c.p + 1] ?? 0, c.d[c.p + 2] ?? 0);
|
|
973
|
+
c.p += 4;
|
|
974
|
+
} else c.p += 4;
|
|
975
|
+
c.p += 8;
|
|
976
|
+
return hex;
|
|
977
|
+
}
|
|
978
|
+
function readCfvo(c, trailer) {
|
|
979
|
+
if (c.p + 3 > c.d.length) return void 0;
|
|
980
|
+
const typeId = u8(c);
|
|
981
|
+
const cce = u16At(c);
|
|
982
|
+
c.p += cce;
|
|
983
|
+
let val;
|
|
984
|
+
if (cce === 0 && typeId !== 2 && typeId !== 3) val = String(f64At(c));
|
|
985
|
+
c.p += trailer;
|
|
986
|
+
const type = CF12_CFVO_TYPES[typeId];
|
|
987
|
+
if (type === void 0 || c.p > c.d.length) return void 0;
|
|
988
|
+
return val !== void 0 ? {
|
|
989
|
+
type,
|
|
990
|
+
val
|
|
991
|
+
} : { type };
|
|
992
|
+
}
|
|
993
|
+
function readColorScale(c, priority, color) {
|
|
994
|
+
c.p += 3;
|
|
995
|
+
const numI = u8(c);
|
|
996
|
+
const numG = u8(c);
|
|
997
|
+
c.p += 1;
|
|
998
|
+
if (numI < 2 || numI > 3 || numI !== numG) return void 0;
|
|
999
|
+
const cfvos = [];
|
|
1000
|
+
for (let k = 0; k < numI; k++) {
|
|
1001
|
+
const v = readCfvo(c, 8);
|
|
1002
|
+
if (!v) return void 0;
|
|
1003
|
+
cfvos.push(v);
|
|
1004
|
+
}
|
|
1005
|
+
const colorsHex = [];
|
|
1006
|
+
for (let k = 0; k < numG; k++) {
|
|
1007
|
+
c.p += 8;
|
|
1008
|
+
const hex = readExtColor(c, color);
|
|
1009
|
+
if (!hex) return void 0;
|
|
1010
|
+
colorsHex.push(hex);
|
|
1011
|
+
}
|
|
1012
|
+
if (c.p > c.d.length) return void 0;
|
|
1013
|
+
return {
|
|
1014
|
+
type: "colorScale",
|
|
1015
|
+
priority,
|
|
1016
|
+
cfvos,
|
|
1017
|
+
colorsHex
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
function readDataBar(c, priority, color) {
|
|
1021
|
+
c.p += 4;
|
|
1022
|
+
const minLength = u8(c);
|
|
1023
|
+
const maxLength = u8(c);
|
|
1024
|
+
const colorHex = readExtColor(c, color);
|
|
1025
|
+
if (!colorHex) return void 0;
|
|
1026
|
+
const lo = readCfvo(c, 0);
|
|
1027
|
+
const hi = readCfvo(c, 0);
|
|
1028
|
+
if (!lo || !hi) return void 0;
|
|
1029
|
+
return {
|
|
1030
|
+
type: "dataBar",
|
|
1031
|
+
priority,
|
|
1032
|
+
cfvos: [lo, hi],
|
|
1033
|
+
colorHex,
|
|
1034
|
+
minLength,
|
|
1035
|
+
maxLength
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
function readIconSet(c, priority) {
|
|
1039
|
+
c.p += 3;
|
|
1040
|
+
const num = u8(c);
|
|
1041
|
+
const setId = u8(c);
|
|
1042
|
+
const options = u8(c);
|
|
1043
|
+
const iconSet = CF12_ICON_SETS[setId];
|
|
1044
|
+
if (iconSet === void 0 || num < 3 || num > 5) return void 0;
|
|
1045
|
+
const cfvos = [];
|
|
1046
|
+
for (let k = 0; k < num; k++) {
|
|
1047
|
+
const v = readCfvo(c, 5);
|
|
1048
|
+
if (!v) return void 0;
|
|
1049
|
+
cfvos.push(v);
|
|
1050
|
+
}
|
|
1051
|
+
const reverse = (options & CF12_ICON_REVERSED) !== 0;
|
|
1052
|
+
return {
|
|
1053
|
+
type: "iconSet",
|
|
1054
|
+
priority,
|
|
1055
|
+
iconSet,
|
|
1056
|
+
cfvos,
|
|
1057
|
+
...reverse ? { reverse } : {}
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
function parseCf12Rule(d, color) {
|
|
1061
|
+
if (d.length < FTR_HEADER + 16) return void 0;
|
|
1062
|
+
const c = {
|
|
1063
|
+
d,
|
|
1064
|
+
p: FTR_HEADER
|
|
1065
|
+
};
|
|
1066
|
+
const ct = u8(c);
|
|
1067
|
+
c.p += 1;
|
|
1068
|
+
const cce1 = u16At(c);
|
|
1069
|
+
const cce2 = u16At(c);
|
|
1070
|
+
const extLen = i32At(c);
|
|
1071
|
+
c.p += extLen === 0 ? 2 : extLen;
|
|
1072
|
+
c.p += cce1 + cce2;
|
|
1073
|
+
const scaleLen = u16At(c);
|
|
1074
|
+
c.p += scaleLen;
|
|
1075
|
+
c.p += 1;
|
|
1076
|
+
const priority = u16At(c);
|
|
1077
|
+
c.p += 2;
|
|
1078
|
+
const tplLen = u8(c);
|
|
1079
|
+
c.p += tplLen;
|
|
1080
|
+
if (c.p > d.length) return void 0;
|
|
1081
|
+
if (ct === CF12_COLOR_SCALE) return readColorScale(c, priority, color);
|
|
1082
|
+
if (ct === CF12_DATA_BAR) return readDataBar(c, priority, color);
|
|
1083
|
+
if (ct === CF12_ICON_SET) return readIconSet(c, priority);
|
|
1084
|
+
}
|
|
1085
|
+
function parseConditionalFormats12(records, color) {
|
|
1086
|
+
const out = [];
|
|
1087
|
+
for (let i = 0; i < records.length; i++) {
|
|
1088
|
+
if (records[i].type !== REC.CONDFMT12) continue;
|
|
1089
|
+
const head = records[i].data;
|
|
1090
|
+
if (head.length < FTR_HEADER + 14) continue;
|
|
1091
|
+
const numcf = readU16(head, FTR_HEADER);
|
|
1092
|
+
const cref = readU16(head, FTR_HEADER + 12);
|
|
1093
|
+
const ranges = [];
|
|
1094
|
+
for (let k = 0; k < cref && FTR_HEADER + 14 + k * 8 + 8 <= head.length; k++) {
|
|
1095
|
+
const o = FTR_HEADER + 14 + k * 8;
|
|
1096
|
+
ranges.push({
|
|
1097
|
+
startRow: readU16(head, o),
|
|
1098
|
+
endRow: readU16(head, o + 2),
|
|
1099
|
+
startColumn: readU16(head, o + 4),
|
|
1100
|
+
endColumn: readU16(head, o + 6)
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
const rules = [];
|
|
1104
|
+
let seen = 0;
|
|
1105
|
+
for (let j = i + 1; j < records.length && seen < numcf; j++) {
|
|
1106
|
+
if (records[j].type !== REC.CF12) break;
|
|
1107
|
+
seen++;
|
|
1108
|
+
const rule = parseCf12Rule(records[j].data, color);
|
|
1109
|
+
if (rule) rules.push(rule);
|
|
1110
|
+
}
|
|
1111
|
+
if (ranges.length > 0 && rules.length > 0) out.push({
|
|
1112
|
+
ranges,
|
|
1113
|
+
rules
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
return out;
|
|
1117
|
+
}
|
|
1118
|
+
function gatherTxoTexts(recs) {
|
|
1119
|
+
const out = [];
|
|
1120
|
+
for (let i = 0; i < recs.length; i++) {
|
|
1121
|
+
if (recs[i].type !== REC.TXO) continue;
|
|
1122
|
+
const cch = readU16(recs[i].data, 10);
|
|
1123
|
+
const next = recs[i + 1];
|
|
1124
|
+
if (cch > 0 && next && next.type === REC.CONTINUE && next.data.length > 0) out.push(decodeChars(next.data, 1, cch, (next.data[0] & 1) !== 0));
|
|
1125
|
+
else out.push("");
|
|
1126
|
+
}
|
|
1127
|
+
return out;
|
|
1128
|
+
}
|
|
1129
|
+
function parseComments(records) {
|
|
1130
|
+
const textByObj = /* @__PURE__ */ new Map();
|
|
1131
|
+
let pendingObjId;
|
|
1132
|
+
const notes = [];
|
|
1133
|
+
for (let i = 0; i < records.length; i++) {
|
|
1134
|
+
const r = records[i];
|
|
1135
|
+
const d = r.data;
|
|
1136
|
+
if (r.type === REC.OBJ) pendingObjId = d.length >= 8 && readU16(d, 0) === 21 && readU16(d, 4) === 25 ? readU16(d, 6) : void 0;
|
|
1137
|
+
else if (r.type === REC.TXO && pendingObjId !== void 0) {
|
|
1138
|
+
const cch = readU16(d, 10);
|
|
1139
|
+
const next = records[i + 1];
|
|
1140
|
+
textByObj.set(pendingObjId, cch > 0 && next && next.type === REC.CONTINUE && next.data.length > 0 ? decodeChars(next.data, 1, cch, (next.data[0] & 1) !== 0) : "");
|
|
1141
|
+
pendingObjId = void 0;
|
|
1142
|
+
} else if (r.type === REC.NOTE && d.length >= 11) {
|
|
1143
|
+
const cchAuthor = readU16(d, 8);
|
|
1144
|
+
notes.push({
|
|
1145
|
+
rw: readU16(d, 0),
|
|
1146
|
+
col: readU16(d, 2),
|
|
1147
|
+
idObj: readU16(d, 6),
|
|
1148
|
+
author: decodeChars(d, 11, cchAuthor, (d[10] & 1) !== 0)
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
const out = [];
|
|
1153
|
+
for (const n of notes) {
|
|
1154
|
+
const text = textByObj.get(n.idObj) ?? "";
|
|
1155
|
+
if (text.length === 0) continue;
|
|
1156
|
+
out.push({
|
|
1157
|
+
ref: `${colLetters(n.col)}${n.rw + 1}`,
|
|
1158
|
+
...n.author.length > 0 ? { author: n.author } : {},
|
|
1159
|
+
text,
|
|
1160
|
+
threaded: false
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
return out;
|
|
1164
|
+
}
|
|
1165
|
+
function buildShapes(escherShapes, txoTexts) {
|
|
1166
|
+
const out = [];
|
|
1167
|
+
let textIdx = 0;
|
|
1168
|
+
for (const s of escherShapes) {
|
|
1169
|
+
const text = s.hasText ? txoTexts[textIdx++] ?? "" : "";
|
|
1170
|
+
const { widthPt, heightPt } = anchorSize(s.anchor);
|
|
1171
|
+
out.push({
|
|
1172
|
+
width: pt(widthPt),
|
|
1173
|
+
height: pt(heightPt),
|
|
1174
|
+
geometry: {
|
|
1175
|
+
kind: "preset",
|
|
1176
|
+
preset: shapePreset(s.shapeType)
|
|
1177
|
+
},
|
|
1178
|
+
fill: s.fillColorHex ? {
|
|
1179
|
+
kind: "solid",
|
|
1180
|
+
colorHex: s.fillColorHex
|
|
1181
|
+
} : { kind: "none" },
|
|
1182
|
+
...s.lineColorHex ? { line: { colorHex: s.lineColorHex } } : {},
|
|
1183
|
+
...text.length > 0 ? { text: { content: [{
|
|
1184
|
+
kind: "paragraph",
|
|
1185
|
+
paragraph: {
|
|
1186
|
+
properties: {},
|
|
1187
|
+
runs: [{
|
|
1188
|
+
text,
|
|
1189
|
+
properties: {}
|
|
1190
|
+
}]
|
|
1191
|
+
}
|
|
1192
|
+
}] } } : {},
|
|
1193
|
+
paragraphProperties: {}
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
return out;
|
|
1197
|
+
}
|
|
1198
|
+
function shapePreset(type) {
|
|
1199
|
+
switch (type) {
|
|
1200
|
+
case 1: return "rect";
|
|
1201
|
+
case 2: return "roundRect";
|
|
1202
|
+
case 3: return "ellipse";
|
|
1203
|
+
case 4: return "diamond";
|
|
1204
|
+
case 5: return "triangle";
|
|
1205
|
+
case 6: return "rtTriangle";
|
|
1206
|
+
case 7: return "parallelogram";
|
|
1207
|
+
case 8: return "trapezoid";
|
|
1208
|
+
case 9: return "hexagon";
|
|
1209
|
+
case 20: return "line";
|
|
1210
|
+
default: return "rect";
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
function buildImages(drawing, blips, resources) {
|
|
1214
|
+
const out = [];
|
|
1215
|
+
for (const pic of parseSheetPictures(drawing)) {
|
|
1216
|
+
const bytes = blips[pic.blipIndex - 1];
|
|
1217
|
+
if (!bytes) continue;
|
|
1218
|
+
const { widthPt, heightPt } = anchorSize(pic.anchor);
|
|
1219
|
+
out.push({
|
|
1220
|
+
resourceId: resources.put(bytes),
|
|
1221
|
+
widthPt,
|
|
1222
|
+
heightPt
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
return out;
|
|
1226
|
+
}
|
|
1227
|
+
function anchorSize(anchor) {
|
|
1228
|
+
if (!anchor) return {
|
|
1229
|
+
widthPt: 96,
|
|
1230
|
+
heightPt: 72
|
|
1231
|
+
};
|
|
1232
|
+
const DEFAULT_COL_PT = 48;
|
|
1233
|
+
const DEFAULT_ROW_PT = 15;
|
|
1234
|
+
const cols = anchor.col2 + anchor.dx2 / 1024 - (anchor.col1 + anchor.dx1 / 1024);
|
|
1235
|
+
const rows = anchor.row2 + anchor.dy2 / 1024 - (anchor.row1 + anchor.dy1 / 1024);
|
|
1236
|
+
return {
|
|
1237
|
+
widthPt: Math.max(8, cols * DEFAULT_COL_PT),
|
|
1238
|
+
heightPt: Math.max(8, rows * DEFAULT_ROW_PT)
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
function numCell(row, column, style, rawValue) {
|
|
1242
|
+
return {
|
|
1243
|
+
column,
|
|
1244
|
+
row,
|
|
1245
|
+
type: "n",
|
|
1246
|
+
rawValue,
|
|
1247
|
+
styleIndex: style
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
function strCell(row, column, style, text) {
|
|
1251
|
+
return {
|
|
1252
|
+
column,
|
|
1253
|
+
row,
|
|
1254
|
+
type: "inlineStr",
|
|
1255
|
+
rawValue: "",
|
|
1256
|
+
inlineText: text,
|
|
1257
|
+
styleIndex: style
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
function formulaCell(d, next) {
|
|
1261
|
+
const row = readU16(d, 0);
|
|
1262
|
+
const col = readU16(d, 2);
|
|
1263
|
+
const style = readU16(d, 4);
|
|
1264
|
+
if (d.length >= 14 && readU16(d, 12) === 65535) {
|
|
1265
|
+
const kind = d[6] ?? 0;
|
|
1266
|
+
if (kind === 0) return strCell(row, col, style, next && next.type === REC.STRING ? readXlString(next.data, 0) : "");
|
|
1267
|
+
if (kind === 1) return {
|
|
1268
|
+
column: col,
|
|
1269
|
+
row,
|
|
1270
|
+
type: "b",
|
|
1271
|
+
rawValue: d[8] ? "1" : "0",
|
|
1272
|
+
styleIndex: style
|
|
1273
|
+
};
|
|
1274
|
+
if (kind === 2) return {
|
|
1275
|
+
column: col,
|
|
1276
|
+
row,
|
|
1277
|
+
type: "e",
|
|
1278
|
+
rawValue: errorText(d[8] ?? 0),
|
|
1279
|
+
styleIndex: style
|
|
1280
|
+
};
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
return numCell(row, col, style, String(readF64(d, 6)));
|
|
1284
|
+
}
|
|
1285
|
+
function decodeRk(rk) {
|
|
1286
|
+
const div100 = (rk & 1) !== 0;
|
|
1287
|
+
let value;
|
|
1288
|
+
if ((rk & 2) !== 0) value = rk >> 2;
|
|
1289
|
+
else {
|
|
1290
|
+
const dv = /* @__PURE__ */ new DataView(/* @__PURE__ */ new ArrayBuffer(8));
|
|
1291
|
+
dv.setUint32(0, 0, true);
|
|
1292
|
+
dv.setUint32(4, rk & 4294967292, true);
|
|
1293
|
+
value = dv.getFloat64(0, true);
|
|
1294
|
+
}
|
|
1295
|
+
return div100 ? value / 100 : value;
|
|
1296
|
+
}
|
|
1297
|
+
function errorText(code) {
|
|
1298
|
+
switch (code) {
|
|
1299
|
+
case 0: return "#NULL!";
|
|
1300
|
+
case 7: return "#DIV/0!";
|
|
1301
|
+
case 15: return "#VALUE!";
|
|
1302
|
+
case 23: return "#REF!";
|
|
1303
|
+
case 29: return "#NAME?";
|
|
1304
|
+
case 36: return "#NUM!";
|
|
1305
|
+
case 42: return "#N/A";
|
|
1306
|
+
default: return "#VALUE!";
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
function readShortString(d, off) {
|
|
1310
|
+
if (off >= d.length) return "";
|
|
1311
|
+
const cch = d[off];
|
|
1312
|
+
const highByte = (d[off + 1] & 1) !== 0;
|
|
1313
|
+
return decodeChars(d, off + 2, cch, highByte);
|
|
1314
|
+
}
|
|
1315
|
+
function readXlString(d, off) {
|
|
1316
|
+
if (off + 3 > d.length) return "";
|
|
1317
|
+
const cch = readU16(d, off);
|
|
1318
|
+
const flags = d[off + 2];
|
|
1319
|
+
const highByte = (flags & 1) !== 0;
|
|
1320
|
+
const rich = (flags & 8) !== 0;
|
|
1321
|
+
const phonetic = (flags & 4) !== 0;
|
|
1322
|
+
let p = off + 3;
|
|
1323
|
+
if (rich) p += 2;
|
|
1324
|
+
if (phonetic) p += 4;
|
|
1325
|
+
return decodeChars(d, p, cch, highByte);
|
|
1326
|
+
}
|
|
1327
|
+
function decodeChars(d, off, cch, highByte) {
|
|
1328
|
+
let s = "";
|
|
1329
|
+
if (highByte) for (let i = 0; i < cch && off + i * 2 + 1 < d.length; i++) s += String.fromCharCode(d[off + i * 2] | d[off + i * 2 + 1] << 8);
|
|
1330
|
+
else for (let i = 0; i < cch && off + i < d.length; i++) s += String.fromCharCode(d[off + i]);
|
|
1331
|
+
return s;
|
|
1332
|
+
}
|
|
1333
|
+
function readSst(blocks) {
|
|
1334
|
+
const r = new SstReader(blocks);
|
|
1335
|
+
r.u32();
|
|
1336
|
+
const cstUnique = Math.min(r.u32(), MAX_STRINGS);
|
|
1337
|
+
const out = [];
|
|
1338
|
+
for (let i = 0; i < cstUnique && !r.atEnd(); i++) out.push(r.readString());
|
|
1339
|
+
return out;
|
|
1340
|
+
}
|
|
1341
|
+
var SstReader = class {
|
|
1342
|
+
bi = 0;
|
|
1343
|
+
off = 0;
|
|
1344
|
+
constructor(blocks) {
|
|
1345
|
+
this.blocks = blocks;
|
|
1346
|
+
}
|
|
1347
|
+
atEnd() {
|
|
1348
|
+
this.settle();
|
|
1349
|
+
return this.bi >= this.blocks.length;
|
|
1350
|
+
}
|
|
1351
|
+
settle() {
|
|
1352
|
+
while (this.bi < this.blocks.length && this.off >= this.blocks[this.bi].length) {
|
|
1353
|
+
this.bi++;
|
|
1354
|
+
this.off = 0;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
byte() {
|
|
1358
|
+
this.settle();
|
|
1359
|
+
if (this.bi >= this.blocks.length) return 0;
|
|
1360
|
+
return this.blocks[this.bi][this.off++];
|
|
1361
|
+
}
|
|
1362
|
+
u16() {
|
|
1363
|
+
return this.byte() | this.byte() << 8;
|
|
1364
|
+
}
|
|
1365
|
+
u32() {
|
|
1366
|
+
return (this.u16() | this.u16() << 16) >>> 0;
|
|
1367
|
+
}
|
|
1368
|
+
skip(n) {
|
|
1369
|
+
let left = n;
|
|
1370
|
+
while (left > 0) {
|
|
1371
|
+
this.settle();
|
|
1372
|
+
if (this.bi >= this.blocks.length) return;
|
|
1373
|
+
const take = Math.min(left, this.blocks[this.bi].length - this.off);
|
|
1374
|
+
this.off += take;
|
|
1375
|
+
left -= take;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
readString() {
|
|
1379
|
+
const cch = this.u16();
|
|
1380
|
+
const flags = this.byte();
|
|
1381
|
+
let highByte = (flags & 1) !== 0;
|
|
1382
|
+
const rich = (flags & 8) !== 0;
|
|
1383
|
+
const phonetic = (flags & 4) !== 0;
|
|
1384
|
+
const cRun = rich ? this.u16() : 0;
|
|
1385
|
+
const cbExtRst = phonetic ? this.u32() : 0;
|
|
1386
|
+
let s = "";
|
|
1387
|
+
for (let i = 0; i < cch; i++) {
|
|
1388
|
+
if (this.off >= this.blocks[this.bi].length) {
|
|
1389
|
+
this.bi++;
|
|
1390
|
+
this.off = 0;
|
|
1391
|
+
if (this.bi >= this.blocks.length) break;
|
|
1392
|
+
highByte = (this.blocks[this.bi][this.off++] & 1) !== 0;
|
|
1393
|
+
}
|
|
1394
|
+
const block = this.blocks[this.bi];
|
|
1395
|
+
if (highByte) {
|
|
1396
|
+
s += String.fromCharCode(block[this.off] | block[this.off + 1] << 8);
|
|
1397
|
+
this.off += 2;
|
|
1398
|
+
} else {
|
|
1399
|
+
s += String.fromCharCode(block[this.off]);
|
|
1400
|
+
this.off += 1;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
this.skip(cRun * 4 + cbExtRst);
|
|
1404
|
+
return s;
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
function readU16(d, off) {
|
|
1408
|
+
return (d[off] ?? 0) | (d[off + 1] ?? 0) << 8;
|
|
1409
|
+
}
|
|
1410
|
+
function readU32(d, off) {
|
|
1411
|
+
return ((d[off] ?? 0) | (d[off + 1] ?? 0) << 8 | (d[off + 2] ?? 0) << 16 | (d[off + 3] ?? 0) << 24) >>> 0;
|
|
1412
|
+
}
|
|
1413
|
+
function readF64(d, off) {
|
|
1414
|
+
if (off + 8 > d.length) return 0;
|
|
1415
|
+
return new DataView(d.buffer, d.byteOffset + off, 8).getFloat64(0, true);
|
|
1416
|
+
}
|
|
1417
|
+
//#endregion
|
|
1418
|
+
export { readXlsToSheetDoc };
|