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,8 @@
|
|
|
1
|
+
import { XlsxStyles } from '../../core/spreadsheet-model/index.js';
|
|
2
|
+
interface BiffRec {
|
|
3
|
+
readonly type: number;
|
|
4
|
+
readonly data: Uint8Array;
|
|
5
|
+
}
|
|
6
|
+
export declare function buildBiffPalette(records: ReadonlyArray<BiffRec>): (icv: number) => string | undefined;
|
|
7
|
+
export declare function parseBiffStyles(records: ReadonlyArray<BiffRec>): XlsxStyles;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
//#region src/excel/xls/biff-styles.ts
|
|
2
|
+
var REC_FONT = 49;
|
|
3
|
+
var REC_FORMAT = 1054;
|
|
4
|
+
var REC_XF = 224;
|
|
5
|
+
var REC_PALETTE = 146;
|
|
6
|
+
var FILL_PATTERNS = [
|
|
7
|
+
"none",
|
|
8
|
+
"solid",
|
|
9
|
+
"mediumGray",
|
|
10
|
+
"darkGray",
|
|
11
|
+
"lightGray",
|
|
12
|
+
"darkHorizontal",
|
|
13
|
+
"darkVertical",
|
|
14
|
+
"darkDown",
|
|
15
|
+
"darkUp",
|
|
16
|
+
"darkGrid",
|
|
17
|
+
"darkTrellis",
|
|
18
|
+
"lightHorizontal",
|
|
19
|
+
"lightVertical",
|
|
20
|
+
"lightDown",
|
|
21
|
+
"lightUp",
|
|
22
|
+
"lightGrid",
|
|
23
|
+
"lightTrellis",
|
|
24
|
+
"gray125",
|
|
25
|
+
"gray0625"
|
|
26
|
+
];
|
|
27
|
+
var BORDER_STYLES = [
|
|
28
|
+
"none",
|
|
29
|
+
"thin",
|
|
30
|
+
"medium",
|
|
31
|
+
"dashed",
|
|
32
|
+
"dotted",
|
|
33
|
+
"thick",
|
|
34
|
+
"double",
|
|
35
|
+
"hair",
|
|
36
|
+
"mediumDashed",
|
|
37
|
+
"dashDot",
|
|
38
|
+
"mediumDashDot",
|
|
39
|
+
"dashDotDot",
|
|
40
|
+
"mediumDashDotDot",
|
|
41
|
+
"slantDashDot"
|
|
42
|
+
];
|
|
43
|
+
var HALIGN = [
|
|
44
|
+
void 0,
|
|
45
|
+
"left",
|
|
46
|
+
"center",
|
|
47
|
+
"right",
|
|
48
|
+
"fill",
|
|
49
|
+
"justify",
|
|
50
|
+
"centerContinuous",
|
|
51
|
+
"distributed"
|
|
52
|
+
];
|
|
53
|
+
var VALIGN = [
|
|
54
|
+
"top",
|
|
55
|
+
"center",
|
|
56
|
+
"bottom",
|
|
57
|
+
"justify",
|
|
58
|
+
"distributed"
|
|
59
|
+
];
|
|
60
|
+
var PALETTE56 = [
|
|
61
|
+
"000000",
|
|
62
|
+
"FFFFFF",
|
|
63
|
+
"FF0000",
|
|
64
|
+
"00FF00",
|
|
65
|
+
"0000FF",
|
|
66
|
+
"FFFF00",
|
|
67
|
+
"FF00FF",
|
|
68
|
+
"00FFFF",
|
|
69
|
+
"800000",
|
|
70
|
+
"008000",
|
|
71
|
+
"000080",
|
|
72
|
+
"808000",
|
|
73
|
+
"800080",
|
|
74
|
+
"008080",
|
|
75
|
+
"C0C0C0",
|
|
76
|
+
"808080",
|
|
77
|
+
"9999FF",
|
|
78
|
+
"993366",
|
|
79
|
+
"FFFFCC",
|
|
80
|
+
"CCFFFF",
|
|
81
|
+
"660066",
|
|
82
|
+
"FF8080",
|
|
83
|
+
"0066CC",
|
|
84
|
+
"CCCCFF",
|
|
85
|
+
"000080",
|
|
86
|
+
"FF00FF",
|
|
87
|
+
"FFFF00",
|
|
88
|
+
"00FFFF",
|
|
89
|
+
"800080",
|
|
90
|
+
"800000",
|
|
91
|
+
"008080",
|
|
92
|
+
"0000FF",
|
|
93
|
+
"00CCFF",
|
|
94
|
+
"CCFFFF",
|
|
95
|
+
"CCFFCC",
|
|
96
|
+
"FFFF99",
|
|
97
|
+
"99CCFF",
|
|
98
|
+
"FF99CC",
|
|
99
|
+
"CC99FF",
|
|
100
|
+
"FFCC99",
|
|
101
|
+
"3366FF",
|
|
102
|
+
"33CCCC",
|
|
103
|
+
"99CC00",
|
|
104
|
+
"FFCC00",
|
|
105
|
+
"FF9900",
|
|
106
|
+
"FF6600",
|
|
107
|
+
"666699",
|
|
108
|
+
"969696",
|
|
109
|
+
"003366",
|
|
110
|
+
"339966",
|
|
111
|
+
"003300",
|
|
112
|
+
"333300",
|
|
113
|
+
"993300",
|
|
114
|
+
"993366",
|
|
115
|
+
"333399",
|
|
116
|
+
"333333"
|
|
117
|
+
];
|
|
118
|
+
function buildBiffPalette(records) {
|
|
119
|
+
const palette = [...PALETTE56.slice(0, 8), ...PALETTE56];
|
|
120
|
+
for (const rec of records) if (rec.type === REC_PALETTE) applyPalette(rec.data, palette);
|
|
121
|
+
return (icv) => {
|
|
122
|
+
if (icv === 32767 || icv === 64 || icv === 65) return void 0;
|
|
123
|
+
const rgb = palette[icv];
|
|
124
|
+
return rgb ? `FF${rgb}` : void 0;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function parseBiffStyles(records) {
|
|
128
|
+
const color = buildBiffPalette(records);
|
|
129
|
+
const fonts = [];
|
|
130
|
+
let fontIdx = 0;
|
|
131
|
+
const numFmts = /* @__PURE__ */ new Map();
|
|
132
|
+
const fills = [{ patternType: "none" }, { patternType: "gray125" }];
|
|
133
|
+
const fillIds = /* @__PURE__ */ new Map();
|
|
134
|
+
const borders = [{}];
|
|
135
|
+
const borderIds = /* @__PURE__ */ new Map();
|
|
136
|
+
const cellXfs = [];
|
|
137
|
+
const internFill = (fill) => {
|
|
138
|
+
if (!fill || !fill.patternType || fill.patternType === "none") return 0;
|
|
139
|
+
const key = `${fill.patternType}|${fill.fgColorHex ?? ""}|${fill.bgColorHex ?? ""}`;
|
|
140
|
+
let id = fillIds.get(key);
|
|
141
|
+
if (id === void 0) {
|
|
142
|
+
id = fills.length;
|
|
143
|
+
fills.push(fill);
|
|
144
|
+
fillIds.set(key, id);
|
|
145
|
+
}
|
|
146
|
+
return id;
|
|
147
|
+
};
|
|
148
|
+
const internBorder = (border) => {
|
|
149
|
+
if (!border || Object.keys(border).length === 0) return 0;
|
|
150
|
+
const key = JSON.stringify(border);
|
|
151
|
+
let id = borderIds.get(key);
|
|
152
|
+
if (id === void 0) {
|
|
153
|
+
id = borders.length;
|
|
154
|
+
borders.push(border);
|
|
155
|
+
borderIds.set(key, id);
|
|
156
|
+
}
|
|
157
|
+
return id;
|
|
158
|
+
};
|
|
159
|
+
for (const rec of records) {
|
|
160
|
+
const d = rec.data;
|
|
161
|
+
if (rec.type === REC_FONT) {
|
|
162
|
+
const id = fontIdx < 4 ? fontIdx : fontIdx + 1;
|
|
163
|
+
while (fonts.length < id) fonts.push({});
|
|
164
|
+
fonts[id] = parseFont(d, color);
|
|
165
|
+
fontIdx++;
|
|
166
|
+
} else if (rec.type === REC_FORMAT) {
|
|
167
|
+
const ifmt = u16(d, 0);
|
|
168
|
+
const code = readXlUnicode(d, 2);
|
|
169
|
+
if (code) numFmts.set(ifmt, code);
|
|
170
|
+
} else if (rec.type === REC_XF) cellXfs.push(parseXf(d, color, internFill, internBorder));
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
numFmts,
|
|
174
|
+
fonts,
|
|
175
|
+
fills,
|
|
176
|
+
borders,
|
|
177
|
+
cellXfs
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function parseFont(d, color) {
|
|
181
|
+
const twips = u16(d, 0);
|
|
182
|
+
const grbit = u16(d, 2);
|
|
183
|
+
const icv = u16(d, 4);
|
|
184
|
+
const bls = u16(d, 6);
|
|
185
|
+
const uls = d[10] ?? 0;
|
|
186
|
+
const name = readShortUnicode(d, 14);
|
|
187
|
+
const out = {};
|
|
188
|
+
if (twips > 0) out.sizePt = twips / 20;
|
|
189
|
+
if (bls >= 700) out.bold = true;
|
|
190
|
+
if ((grbit & 2) !== 0) out.italic = true;
|
|
191
|
+
if (uls !== 0) out.underline = true;
|
|
192
|
+
const c = color(icv);
|
|
193
|
+
if (c) out.colorHex = c;
|
|
194
|
+
if (name) out.name = name;
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
function parseXf(d, color, internFill, internBorder) {
|
|
198
|
+
const fontId = u16(d, 0);
|
|
199
|
+
const numFmtId = u16(d, 2);
|
|
200
|
+
const align1 = d[6] ?? 0;
|
|
201
|
+
const rotation = d[7] ?? 0;
|
|
202
|
+
const indentByte = d[8] ?? 0;
|
|
203
|
+
const alignment = {};
|
|
204
|
+
const h = HALIGN[align1 & 7];
|
|
205
|
+
if (h) alignment.horizontal = h;
|
|
206
|
+
const v = VALIGN[align1 >> 4 & 7];
|
|
207
|
+
if (v && v !== "bottom") alignment.vertical = v;
|
|
208
|
+
if ((align1 & 8) !== 0) alignment.wrapText = true;
|
|
209
|
+
const indent = indentByte & 15;
|
|
210
|
+
if (indent > 0) alignment.indent = indent;
|
|
211
|
+
if ((indentByte & 16) !== 0) alignment.shrinkToFit = true;
|
|
212
|
+
if (rotation > 0 && rotation !== 255) alignment.textRotation = rotation;
|
|
213
|
+
else if (rotation === 255) alignment.textRotation = 255;
|
|
214
|
+
const brd1 = u16(d, 10);
|
|
215
|
+
const brd2 = u32(d, 12);
|
|
216
|
+
const brd3 = u32(d, 16);
|
|
217
|
+
const edge = (style, icv) => {
|
|
218
|
+
const name = BORDER_STYLES[style];
|
|
219
|
+
if (!name || name === "none") return void 0;
|
|
220
|
+
const c = color(icv);
|
|
221
|
+
return c ? {
|
|
222
|
+
style: name,
|
|
223
|
+
colorHex: c
|
|
224
|
+
} : { style: name };
|
|
225
|
+
};
|
|
226
|
+
const border = {};
|
|
227
|
+
const left = edge(brd1 & 15, brd2 & 127);
|
|
228
|
+
const right = edge(brd1 >> 4 & 15, brd2 >> 7 & 127);
|
|
229
|
+
const top = edge(brd1 >> 8 & 15, brd2 >> 16 & 127);
|
|
230
|
+
const bottom = edge(brd1 >> 12 & 15, brd2 >> 23 & 127);
|
|
231
|
+
if (left) border.left = left;
|
|
232
|
+
if (right) border.right = right;
|
|
233
|
+
if (top) border.top = top;
|
|
234
|
+
if (bottom) border.bottom = bottom;
|
|
235
|
+
const patternType = FILL_PATTERNS[brd3 >> 26 & 63];
|
|
236
|
+
let fill;
|
|
237
|
+
if (patternType && patternType !== "none") {
|
|
238
|
+
const fg = color(brd3 & 127);
|
|
239
|
+
const bg = color(brd3 >> 7 & 127);
|
|
240
|
+
fill = {
|
|
241
|
+
patternType,
|
|
242
|
+
...fg ? { fgColorHex: fg } : {},
|
|
243
|
+
...bg ? { bgColorHex: bg } : {}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const fillId = internFill(fill);
|
|
247
|
+
const borderId = internBorder(Object.keys(border).length > 0 ? border : void 0);
|
|
248
|
+
return {
|
|
249
|
+
numFmtId,
|
|
250
|
+
fontId,
|
|
251
|
+
fillId,
|
|
252
|
+
borderId,
|
|
253
|
+
...numFmtId > 0 ? { applyNumberFormat: true } : {},
|
|
254
|
+
...fillId > 1 ? { applyFill: true } : {},
|
|
255
|
+
...borderId > 0 ? { applyBorder: true } : {},
|
|
256
|
+
...Object.keys(alignment).length > 0 ? {
|
|
257
|
+
applyAlignment: true,
|
|
258
|
+
alignment
|
|
259
|
+
} : {}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function applyPalette(d, palette) {
|
|
263
|
+
const count = u16(d, 0);
|
|
264
|
+
for (let i = 0; i < count; i++) {
|
|
265
|
+
const o = 2 + i * 4;
|
|
266
|
+
if (o + 3 > d.length) break;
|
|
267
|
+
const hex = `${hex2(d[o])}${hex2(d[o + 1])}${hex2(d[o + 2])}`;
|
|
268
|
+
if (8 + i < palette.length) palette[8 + i] = hex;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function readShortUnicode(d, off) {
|
|
272
|
+
if (off >= d.length) return "";
|
|
273
|
+
const cch = d[off];
|
|
274
|
+
const high = (d[off + 1] & 1) !== 0;
|
|
275
|
+
return decodeChars(d, off + 2, cch, high);
|
|
276
|
+
}
|
|
277
|
+
function readXlUnicode(d, off) {
|
|
278
|
+
if (off + 3 > d.length) return "";
|
|
279
|
+
const cch = u16(d, off);
|
|
280
|
+
const high = (d[off + 2] & 1) !== 0;
|
|
281
|
+
return decodeChars(d, off + 3, cch, high);
|
|
282
|
+
}
|
|
283
|
+
function decodeChars(d, off, cch, high) {
|
|
284
|
+
let s = "";
|
|
285
|
+
if (high) 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);
|
|
286
|
+
else for (let i = 0; i < cch && off + i < d.length; i++) s += String.fromCharCode(d[off + i]);
|
|
287
|
+
return s;
|
|
288
|
+
}
|
|
289
|
+
function hex2(n) {
|
|
290
|
+
return n.toString(16).padStart(2, "0").toUpperCase();
|
|
291
|
+
}
|
|
292
|
+
function u16(d, off) {
|
|
293
|
+
return (d[off] ?? 0) | (d[off + 1] ?? 0) << 8;
|
|
294
|
+
}
|
|
295
|
+
function u32(d, off) {
|
|
296
|
+
return ((d[off] ?? 0) | (d[off + 1] ?? 0) << 8 | (d[off + 2] ?? 0) << 16 | (d[off + 3] ?? 0) << 24) >>> 0;
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
299
|
+
export { buildBiffPalette, parseBiffStyles };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface EscherPicture {
|
|
2
|
+
readonly blipIndex: number;
|
|
3
|
+
readonly anchor?: EscherAnchor;
|
|
4
|
+
}
|
|
5
|
+
export interface EscherAnchor {
|
|
6
|
+
readonly col1: number;
|
|
7
|
+
readonly row1: number;
|
|
8
|
+
readonly col2: number;
|
|
9
|
+
readonly row2: number;
|
|
10
|
+
readonly dx1: number;
|
|
11
|
+
readonly dy1: number;
|
|
12
|
+
readonly dx2: number;
|
|
13
|
+
readonly dy2: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function parseBlipStore(msoDrawingGroup: Uint8Array): Array<Uint8Array | undefined>;
|
|
16
|
+
export declare function parseSheetPictures(msoDrawing: Uint8Array): Array<EscherPicture>;
|
|
17
|
+
export interface EscherShape {
|
|
18
|
+
readonly shapeType: number;
|
|
19
|
+
readonly hasText: boolean;
|
|
20
|
+
readonly anchor?: EscherAnchor;
|
|
21
|
+
readonly fillColorHex?: string;
|
|
22
|
+
readonly lineColorHex?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function parseSheetShapes(msoDrawing: Uint8Array): Array<EscherShape>;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
//#region src/excel/xls/escher.ts
|
|
2
|
+
var FBT_BSTORE_CONTAINER = 61441;
|
|
3
|
+
var FBT_BSE = 61447;
|
|
4
|
+
var FBT_SP_CONTAINER = 61444;
|
|
5
|
+
var FBT_OPT = 61451;
|
|
6
|
+
var FBT_CLIENT_ANCHOR = 61456;
|
|
7
|
+
var PROP_PIB = 260;
|
|
8
|
+
var MAX_DEPTH = 24;
|
|
9
|
+
function* records(d) {
|
|
10
|
+
let off = 0;
|
|
11
|
+
while (off + 8 <= d.length) {
|
|
12
|
+
const verInstance = u16(d, off);
|
|
13
|
+
const type = u16(d, off + 2);
|
|
14
|
+
const len = u32(d, off + 4);
|
|
15
|
+
const start = off + 8;
|
|
16
|
+
const end = Math.min(d.length, start + len);
|
|
17
|
+
yield {
|
|
18
|
+
type,
|
|
19
|
+
instance: verInstance >> 4,
|
|
20
|
+
isContainer: (verInstance & 15) === 15,
|
|
21
|
+
data: d.subarray(start, end)
|
|
22
|
+
};
|
|
23
|
+
if (end <= off) break;
|
|
24
|
+
off = end;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function parseBlipStore(msoDrawingGroup) {
|
|
28
|
+
const store = findContainer(msoDrawingGroup, FBT_BSTORE_CONTAINER, 0);
|
|
29
|
+
if (!store) return [];
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const r of records(store)) if (r.type === FBT_BSE) out.push(findImageBytes(r.data));
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
function findContainer(d, type, depth) {
|
|
35
|
+
if (depth > MAX_DEPTH) return void 0;
|
|
36
|
+
for (const r of records(d)) {
|
|
37
|
+
if (r.type === type) return r.data;
|
|
38
|
+
if (r.isContainer) {
|
|
39
|
+
const found = findContainer(r.data, type, depth + 1);
|
|
40
|
+
if (found) return found;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function parseSheetPictures(msoDrawing) {
|
|
45
|
+
const out = [];
|
|
46
|
+
collectPictures(msoDrawing, out, 0);
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
function collectPictures(d, out, depth) {
|
|
50
|
+
if (depth > MAX_DEPTH) return;
|
|
51
|
+
for (const r of records(d)) if (r.type === FBT_SP_CONTAINER) {
|
|
52
|
+
let blipIndex;
|
|
53
|
+
let anchor;
|
|
54
|
+
for (const child of records(r.data)) if (child.type === FBT_OPT) blipIndex = optProperty(child.data, child.instance, PROP_PIB);
|
|
55
|
+
else if (child.type === FBT_CLIENT_ANCHOR) anchor = parseAnchor(child.data);
|
|
56
|
+
if (blipIndex !== void 0 && blipIndex > 0) out.push({
|
|
57
|
+
blipIndex,
|
|
58
|
+
...anchor ? { anchor } : {}
|
|
59
|
+
});
|
|
60
|
+
} else if (r.isContainer) collectPictures(r.data, out, depth + 1);
|
|
61
|
+
}
|
|
62
|
+
var FBT_SP = 61450;
|
|
63
|
+
var FBT_CLIENT_TEXTBOX = 61453;
|
|
64
|
+
var PROP_FILL_COLOR = 385;
|
|
65
|
+
var PROP_LINE_COLOR = 448;
|
|
66
|
+
function parseSheetShapes(msoDrawing) {
|
|
67
|
+
const out = [];
|
|
68
|
+
collectShapes(msoDrawing, out, 0);
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
function collectShapes(d, out, depth) {
|
|
72
|
+
if (depth > MAX_DEPTH) return;
|
|
73
|
+
for (const r of records(d)) if (r.type === FBT_SP_CONTAINER) {
|
|
74
|
+
let shapeType = 0;
|
|
75
|
+
let hasText = false;
|
|
76
|
+
let pib;
|
|
77
|
+
let anchor;
|
|
78
|
+
let fill;
|
|
79
|
+
let line;
|
|
80
|
+
for (const child of records(r.data)) if (child.type === FBT_SP) shapeType = child.instance;
|
|
81
|
+
else if (child.type === FBT_OPT) {
|
|
82
|
+
pib = optProperty(child.data, child.instance, PROP_PIB);
|
|
83
|
+
fill = optColor(child.data, child.instance, PROP_FILL_COLOR);
|
|
84
|
+
line = optColor(child.data, child.instance, PROP_LINE_COLOR);
|
|
85
|
+
} else if (child.type === FBT_CLIENT_ANCHOR) anchor = parseAnchor(child.data);
|
|
86
|
+
else if (child.type === FBT_CLIENT_TEXTBOX) hasText = true;
|
|
87
|
+
if (pib === void 0 && shapeType !== 0) out.push({
|
|
88
|
+
shapeType,
|
|
89
|
+
hasText,
|
|
90
|
+
...anchor ? { anchor } : {},
|
|
91
|
+
...fill ? { fillColorHex: fill } : {},
|
|
92
|
+
...line ? { lineColorHex: line } : {}
|
|
93
|
+
});
|
|
94
|
+
} else if (r.isContainer) collectShapes(r.data, out, depth + 1);
|
|
95
|
+
}
|
|
96
|
+
function optColor(d, count, wantId) {
|
|
97
|
+
const v = optProperty(d, count, wantId);
|
|
98
|
+
if (v === void 0 || v >>> 24 !== 0) return void 0;
|
|
99
|
+
return `${hex2(v & 255)}${hex2(v >> 8 & 255)}${hex2(v >> 16 & 255)}`;
|
|
100
|
+
}
|
|
101
|
+
function hex2(n) {
|
|
102
|
+
return n.toString(16).padStart(2, "0").toUpperCase();
|
|
103
|
+
}
|
|
104
|
+
function optProperty(d, count, wantId) {
|
|
105
|
+
for (let i = 0; i < count && i * 6 + 6 <= d.length; i++) {
|
|
106
|
+
const id = u16(d, i * 6);
|
|
107
|
+
if ((id & 16383) === wantId && (id & 32768) === 0) return u32(d, i * 6 + 2);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function parseAnchor(d) {
|
|
111
|
+
if (d.length < 18) return void 0;
|
|
112
|
+
return {
|
|
113
|
+
col1: u16(d, 2),
|
|
114
|
+
dx1: u16(d, 4),
|
|
115
|
+
row1: u16(d, 6),
|
|
116
|
+
dy1: u16(d, 8),
|
|
117
|
+
col2: u16(d, 10),
|
|
118
|
+
dx2: u16(d, 12),
|
|
119
|
+
row2: u16(d, 14),
|
|
120
|
+
dy2: u16(d, 16)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
var MAGICS = [
|
|
124
|
+
[
|
|
125
|
+
137,
|
|
126
|
+
80,
|
|
127
|
+
78,
|
|
128
|
+
71
|
|
129
|
+
],
|
|
130
|
+
[
|
|
131
|
+
255,
|
|
132
|
+
216,
|
|
133
|
+
255
|
|
134
|
+
],
|
|
135
|
+
[
|
|
136
|
+
71,
|
|
137
|
+
73,
|
|
138
|
+
70,
|
|
139
|
+
56
|
|
140
|
+
],
|
|
141
|
+
[66, 77],
|
|
142
|
+
[
|
|
143
|
+
73,
|
|
144
|
+
73,
|
|
145
|
+
42,
|
|
146
|
+
0
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
77,
|
|
150
|
+
77,
|
|
151
|
+
0,
|
|
152
|
+
42
|
|
153
|
+
]
|
|
154
|
+
];
|
|
155
|
+
function findImageBytes(bse) {
|
|
156
|
+
const limit = Math.min(bse.length, 80);
|
|
157
|
+
for (let off = 0; off < limit; off++) for (const magic of MAGICS) if (matches(bse, off, magic)) return bse.subarray(off);
|
|
158
|
+
}
|
|
159
|
+
function matches(d, off, magic) {
|
|
160
|
+
if (off + magic.length > d.length) return false;
|
|
161
|
+
for (let i = 0; i < magic.length; i++) if (d[off + i] !== magic[i]) return false;
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
function u16(d, off) {
|
|
165
|
+
return (d[off] ?? 0) | (d[off + 1] ?? 0) << 8;
|
|
166
|
+
}
|
|
167
|
+
function u32(d, off) {
|
|
168
|
+
return ((d[off] ?? 0) | (d[off + 1] ?? 0) << 8 | (d[off + 2] ?? 0) << 16 | (d[off + 3] ?? 0) << 24) >>> 0;
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
export { parseBlipStore, parseSheetPictures, parseSheetShapes };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { FEATURES } from "../../core/ir/features.js";
|
|
2
|
+
import { isCfb, openCfb } from "../../core/ole/cfb.js";
|
|
3
|
+
import { readXlsToSheetDoc } from "./biff-reader.js";
|
|
4
|
+
//#region src/excel/xls/xls-reader.ts
|
|
5
|
+
function looksLikeXls(bytes) {
|
|
6
|
+
if (!isCfb(bytes)) return false;
|
|
7
|
+
try {
|
|
8
|
+
const cfb = openCfb(bytes);
|
|
9
|
+
return cfb.hasStream("Workbook") || cfb.hasStream("Book");
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
var XLS_LOSSES = [{
|
|
15
|
+
severity: "degraded",
|
|
16
|
+
feature: FEATURES.cellFormatting,
|
|
17
|
+
detail: "legacy .xls Excel tables / autofilter are not read; the sheet’s cell data, styling, images, charts, drawing shapes, conditional formatting, comments, hyperlinks, data validation, defined names, the page-setup print model, frozen panes and custom row heights are"
|
|
18
|
+
}];
|
|
19
|
+
var xlsReader = {
|
|
20
|
+
id: "xls",
|
|
21
|
+
produces: "sheet",
|
|
22
|
+
supports: new Set([FEATURES.text, FEATURES.tables]),
|
|
23
|
+
sniff: looksLikeXls,
|
|
24
|
+
read: (bytes) => ({
|
|
25
|
+
doc: readXlsToSheetDoc(bytes),
|
|
26
|
+
losses: XLS_LOSSES
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { xlsReader };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DocumentReader, ReadResult } from '../core/ir/adapters.js';
|
|
2
2
|
import { FlowDoc } from '../core/ir/flow.js';
|
|
3
3
|
import { SheetDoc } from '../core/ir/sheet.js';
|
|
4
|
-
|
|
4
|
+
import { ProjectSheetOptions } from './sheet-to-flow.js';
|
|
5
|
+
export declare function readXlsx(xlsx: Uint8Array, options?: ProjectSheetOptions): ReadResult<FlowDoc>;
|
|
5
6
|
export declare function readXlsxToSheetDoc(xlsx: Uint8Array): SheetDoc;
|
|
6
7
|
export declare const xlsxReader: DocumentReader<SheetDoc>;
|