1
Fork 0

version bump 0.18.5: basic NUMBERS write

This commit is contained in:
SheetJS 2022-03-24 09:59:49 -04:00
parent e69ecd42a6
commit 0400a87e62
38 changed files with 5844 additions and 2029 deletions

View File

@ -4,7 +4,20 @@ This log is intended to keep track of backwards-incompatible changes, including
but not limited to API changes and file location changes. Minor behavioral
changes may not be included if they are not expected to break existing code.
## v0.18.5
* Enabled `sideEffects: false` in package.json
* Basic NUMBERS write support
## v0.18.4
* CSV output omits trailing record separator
* Properly terminate NodeJS Streams
* DBF preserve column types on import and use when applicable on export
## v0.18.3
* Removed references to `require` and `process` in browser builds
## v0.18.2

View File

@ -95,6 +95,8 @@ dist: dist-deps $(TARGET) bower.json ## Prepare JS files for distribution
misc/strip_sourcemap.sh dist/$(LIB).mini.min.js
@# extendscript
cat <(head -n 1 bits/00_header.js) shim.js $(DISTHDR) $(REQS) dist/$(TARGET) > dist/$(LIB).extendscript.js
@# zahl
cp modules/xlsx.zahl.js modules/xlsx.zahl.mjs dist/
@#
rm dist/$(TARGET) dist/$(MINITGT)

View File

@ -1764,6 +1764,61 @@ stream.pipe(conv); conv.pipe(process.stdout);
</details>
<details>
<summary><b>Exporting NUMBERS files</b> (click to show)</summary>
The NUMBERS writer requires a fairly large base. The supplementary `xlsx.zahl`
scripts provide support. `xlsx.zahl.js` is designed for standalone and NodeJS
use, while `xlsx.zahl.mjs` is suitable for ESM.
_Browser_
```html
<meta charset="utf8">
<script src="xlsx.full.min.js"></script>
<script src="xlsx.zahl.js"></script>
<script>
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textport.numbers", {numbers: XLSX_ZAHL, compression: true});
</script>
```
_Node_
```js
var XLSX = require("./xlsx.flow");
var XLSX_ZAHL = require("./dist/xlsx.zahl");
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textport.numbers", {numbers: XLSX_ZAHL, compression: true});
```
_Deno_
```ts
import * as XLSX from './xlsx.mjs';
import XLSX_ZAHL from './dist/xlsx.zahl.mjs';
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textports.numbers", {numbers: XLSX_ZAHL, compression: true});
```
</details>
<https://github.com/sheetjs/sheetaki> pipes write streams to nodejs response.
### Generating JSON and JS Data
@ -3366,6 +3421,7 @@ The exported `write` and `writeFile` functions accept an options argument:
|`Props` | | Override workbook properties when writing ** |
|`themeXLSX` | | Override theme XML when writing XLSX/XLSB/XLSM ** |
|`ignoreEC` | `true` | Suppress "number as text" errors ** |
|`numbers` | | Payload for NUMBERS export ** |
- `bookSST` is slower and more memory intensive, but has better compatibility
with older versions of iOS Numbers
@ -3381,6 +3437,8 @@ The exported `write` and `writeFile` functions accept an options argument:
- Due to a bug in the program, some features like "Text to Columns" will crash
Excel on worksheets where error conditions are ignored. The writer will mark
files to ignore the error by default. Set `ignoreEC` to `false` to suppress.
- Due to the size of the data, the NUMBERS data is not included by default. The
included `xlsx.zahl.js` and `xlsx.zahl.mjs` scripts include the data.
### Supported Output Formats
@ -3398,6 +3456,7 @@ output formats. The specific file type is controlled with `bookType` option:
| `biff3` | `.xls` | none | single | Excel 3.0 Worksheet Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
| `numbers` |`.numbers`| ZIP | single | Numbers 3.0+ Spreadsheet |
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
| `wk3` | `.wk3` | none | multi | Lotus Workbook (WK3) |
@ -3950,7 +4009,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Lotus Formatted Text (PRN) | ✔ | ✔ |
| UTF-16 Unicode Text (TXT) | ✔ | ✔ |
| **Other Workbook/Worksheet Formats** |:-----:|:-----:|
| Numbers 3.0+ / iWork 2013+ Spreadsheet (NUMBERS) | ✔ | |
| Numbers 3.0+ / iWork 2013+ Spreadsheet (NUMBERS) | ✔ | |
| OpenDocument Spreadsheet (ODS) | ✔ | ✔ |
| Flat XML ODF Spreadsheet (FODS) | ✔ | ✔ |
| Uniform Office Format Spreadsheet (标文通 UOS1/UOS2) | ✔ | |
@ -4099,6 +4158,8 @@ The parser focuses on extracting raw data from tables. Numbers technically
supports multiple tables in a logical worksheet, including custom titles. This
parser will generate one worksheet per Numbers table.
The writer currently exports a small range from the first worksheet.
- **OpenDocument Spreadsheet (ODS/FODS)**
ODS is an XML-in-ZIP format akin to XLSX while FODS is an XML format akin to

View File

@ -44,6 +44,7 @@ program
.option('-6, --xlml', 'emit SSML to <sheetname> or <file>.xls (2003 XML)')
.option('-T, --fods', 'emit FODS to <sheetname> or <file>.fods (Flat ODS)')
.option('--wk3', 'emit WK3 to <sheetname> or <file>.txt (Lotus WK3)')
.option('--numbers', 'emit NUMBERS to <sheetname> or <file>.numbers')
.option('-S, --formulae', 'emit list of values and formulae')
.option('-j, --json', 'emit formatted JSON (all fields text)')
@ -90,6 +91,7 @@ var workbook_formats = [
['xls', 'xls', 'xls'],
['xla', 'xla', 'xla'],
['biff5', 'biff5', 'xls'],
['numbers', 'numbers', 'numbers'],
['ods', 'ods', 'ods'],
['fods', 'fods', 'fods'],
['wk3', 'wk3', 'wk3']
@ -192,6 +194,10 @@ if(program.props) {
/* full workbook formats */
workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
wopts.bookType = m[1];
if(wopts.bookType == "numbers") try {
var XLSX_ZAHL = require("../dist/xlsx.zahl");
wopts.numbers = XLSX_ZAHL;
} catch(e) {}
if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
process.exit(0);
} });

View File

@ -1 +1 @@
XLSX.version = '0.18.4';
XLSX.version = '0.18.5';

View File

@ -5,6 +5,19 @@ function u8_to_dataview(array) {
function u8str(u8) {
return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8));
}
function stru8(str) {
return typeof TextEncoder != "undefined" ? new TextEncoder().encode(str) : s2a(utf8write(str));
}
function u8contains(body, search) {
outer:
for (var L = 0; L <= body.length - search.length; ++L) {
for (var j = 0; j < search.length; ++j)
if (body[L + j] != search[j])
continue outer;
return true;
}
return false;
}
function u8concat(u8a) {
var len = u8a.reduce(function(acc, x) {
return acc + x.length;
@ -29,6 +42,15 @@ function readDecimal128LE(buf, offset) {
mantissa = mantissa * 256 + buf[j];
return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176);
}
function writeDecimal128LE(buf, offset, value) {
var exp = Math.floor(value == 0 ? 0 : Math.LOG10E * Math.log(Math.abs(value))) + 6176 - 20;
var mantissa = value / Math.pow(10, exp - 6176);
buf[offset + 15] |= exp >> 7;
buf[offset + 14] |= (exp & 127) << 1;
for (var i = 0; mantissa >= 1; ++i, mantissa /= 256)
buf[offset + i] = mantissa & 255;
buf[offset + 15] |= value >= 0 ? 0 : 128;
}
function parse_varint49(buf, ptr) {
var l = ptr ? ptr[0] : 0;
var usz = buf[l] & 127;
@ -154,7 +176,7 @@ function parse_shallow(buf) {
default:
throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off));
}
var v = { offset: off, data: res, type: type };
var v = { data: res, type: type };
if (out[num] == null)
out[num] = [v];
else
@ -166,6 +188,8 @@ function write_shallow(proto) {
var out = [];
proto.forEach(function(field, idx) {
field.forEach(function(item) {
if (!item.data)
return;
out.push(write_varint49(idx * 8 + item.type));
if (item.type == 2)
out.push(write_varint49(item.data.length));
@ -175,21 +199,12 @@ function write_shallow(proto) {
return u8concat(out);
}
function mappa(data, cb) {
if (!data)
return [];
return data.map(function(d) {
var _a;
try {
return cb(d.data);
} catch (e) {
var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/);
if (m)
e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset));
throw e;
}
});
return (data == null ? void 0 : data.map(function(d) {
return cb(d.data);
})) || [];
}
function parse_iwa_file(buf) {
var _a;
var out = [], ptr = [0];
while (ptr[0] < buf.length) {
var len = parse_varint49(buf, ptr);
@ -208,10 +223,35 @@ function parse_iwa_file(buf) {
});
ptr[0] += fl;
});
if ((_a = ai[3]) == null ? void 0 : _a[0])
res.merge = varint_to_i32(ai[3][0].data) >>> 0 > 0;
out.push(res);
}
return out;
}
function write_iwa_file(ias) {
var bufs = [];
ias.forEach(function(ia) {
var ai = [];
ai[1] = [{ data: write_varint49(ia.id), type: 0 }];
ai[2] = [];
if (ia.merge != null)
ai[3] = [{ data: write_varint49(+!!ia.merge), type: 0 }];
var midata = [];
ia.messages.forEach(function(mi) {
midata.push(mi.data);
mi.meta[3] = [{ type: 0, data: write_varint49(mi.data.length) }];
ai[2].push({ data: write_shallow(mi.meta), type: 2 });
});
var aipayload = write_shallow(ai);
bufs.push(write_varint49(aipayload.length));
bufs.push(aipayload);
midata.forEach(function(mid) {
return bufs.push(mid);
});
});
return u8concat(bufs);
}
function parse_snappy_chunk(type, buf) {
if (type != 0)
throw new Error("Unexpected Snappy chunk type ".concat(type));
@ -366,7 +406,7 @@ function parse_old_storage(buf, sst, rsst, v) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -388,7 +428,7 @@ function parse_old_storage(buf, sst, rsst, v) {
}
return ret;
}
function parse_storage(buf, sst, rsst) {
function parse_new_storage(buf, sst, rsst) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(8, true);
var data_offset = 12;
@ -430,7 +470,7 @@ function parse_storage(buf, sst, rsst) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -451,6 +491,66 @@ function parse_storage(buf, sst, rsst) {
}
return ret;
}
function write_new_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 5;
switch (cell.t) {
case "n":
out[1] = 2;
writeDecimal128LE(out, l, cell.v);
flags |= 1;
l += 16;
break;
case "b":
out[1] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 2;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[1] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 8;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(8, flags, true);
return out.slice(0, l);
}
function write_old_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 3;
switch (cell.t) {
case "n":
out[2] = 2;
dv.setFloat64(l, cell.v, true);
flags |= 32;
l += 8;
break;
case "b":
out[2] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 32;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[2] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 16;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(4, flags, true);
return out.slice(0, l);
}
function parse_cell_storage(buf, sst, rsst) {
switch (buf[0]) {
case 0:
@ -459,7 +559,7 @@ function parse_cell_storage(buf, sst, rsst) {
case 3:
return parse_old_storage(buf, sst, rsst, buf[0]);
case 5:
return parse_storage(buf, sst, rsst);
return parse_new_storage(buf, sst, rsst);
default:
throw new Error("Unsupported payload version ".concat(buf[0]));
}
@ -468,6 +568,11 @@ function parse_TSP_Reference(buf) {
var pb = parse_shallow(buf);
return parse_varint49(pb[1][0].data);
}
function write_TSP_Reference(idx) {
var out = [];
out[1] = [{ type: 0, data: write_varint49(idx) }];
return write_shallow(out);
}
function parse_TST_TableDataList(M, root) {
var pb = parse_shallow(root.data);
var type = varint_to_i32(pb[1][0].data);
@ -526,7 +631,8 @@ function parse_TST_TileRowInfo(u8, type) {
var cells = [];
for (C = 0; C < offsets.length - 1; ++C)
cells[offsets[C][0]] = used_storage.subarray(offsets[C][1] * width, offsets[C + 1][1] * width);
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
if (offsets.length >= 1)
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
return { R: R, cells: cells };
}
function parse_TST_Tile(M, root) {
@ -632,7 +738,7 @@ function parse_TN_DocumentArchive(M, root) {
}
function parse_numbers_iwa(cfb) {
var _a, _b, _c, _d;
var out = {}, indices = [];
var M = {}, indices = [];
cfb.FullPaths.forEach(function(p) {
if (p.match(/\.iwpv2/))
throw new Error("Unsupported password protection");
@ -653,16 +759,16 @@ function parse_numbers_iwa(cfb) {
return console.log("## " + (e.message || e));
}
packets.forEach(function(packet) {
out[packet.id] = packet.messages;
M[packet.id] = packet.messages;
indices.push(packet.id);
});
});
if (!indices.length)
throw new Error("File has no messages");
var docroot = ((_d = (_c = (_b = (_a = out == null ? void 0 : out[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(out[1][0].meta[1][0].data) == 1 && out[1][0];
var docroot = ((_d = (_c = (_b = (_a = M == null ? void 0 : M[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(M[1][0].meta[1][0].data) == 1 && M[1][0];
if (!docroot)
indices.forEach(function(idx) {
out[idx].forEach(function(iwam) {
M[idx].forEach(function(iwam) {
var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0;
if (mtype == 1) {
if (!docroot)
@ -674,5 +780,323 @@ function parse_numbers_iwa(cfb) {
});
if (!docroot)
throw new Error("Cannot find Document root");
return parse_TN_DocumentArchive(out, docroot);
return parse_TN_DocumentArchive(M, docroot);
}
function write_tile_row(tri, data, SST) {
var _a, _b, _c, _d;
if (!((_a = tri[6]) == null ? void 0 : _a[0]) || !((_b = tri[7]) == null ? void 0 : _b[0]))
throw "Mutation only works on post-BNC storages!";
var wide_offsets = ((_d = (_c = tri[8]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && varint_to_i32(tri[8][0].data) > 0 || false;
if (wide_offsets)
throw "Math only works with normal offsets";
var cnt = 0;
var dv = u8_to_dataview(tri[7][0].data), last_offset = 0, cell_storage = [];
var _dv = u8_to_dataview(tri[4][0].data), _last_offset = 0, _cell_storage = [];
for (var C = 0; C < data.length; ++C) {
if (data[C] == null) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535);
continue;
}
dv.setUint16(C * 2, last_offset, true);
_dv.setUint16(C * 2, _last_offset, true);
var celload, _celload;
switch (typeof data[C]) {
case "string":
celload = write_new_storage({ t: "s", v: data[C] }, SST);
_celload = write_old_storage({ t: "s", v: data[C] }, SST);
break;
case "number":
celload = write_new_storage({ t: "n", v: data[C] }, SST);
_celload = write_old_storage({ t: "n", v: data[C] }, SST);
break;
case "boolean":
celload = write_new_storage({ t: "b", v: data[C] }, SST);
_celload = write_old_storage({ t: "b", v: data[C] }, SST);
break;
default:
throw new Error("Unsupported value " + data[C]);
}
cell_storage.push(celload);
last_offset += celload.length;
_cell_storage.push(_celload);
_last_offset += _celload.length;
++cnt;
}
tri[2][0].data = write_varint49(cnt);
for (; C < tri[7][0].data.length / 2; ++C) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535, true);
}
tri[6][0].data = u8concat(cell_storage);
tri[3][0].data = u8concat(_cell_storage);
return cnt;
}
function write_numbers_iwa(wb, opts) {
if (!opts || !opts.numbers)
throw new Error("Must pass a `numbers` option -- check the README");
var ws = wb.Sheets[wb.SheetNames[0]];
if (wb.SheetNames.length > 1)
console.error("The Numbers writer currently writes only the first table");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
if (range.e.c > 9) {
trunc = true;
range.e.c = 9;
}
if (range.e.r > 49) {
trunc = true;
range.e.r = 49;
}
if (trunc)
console.error("The Numbers writer is currently limited to ".concat(encode_range(range)));
var data = sheet_to_json(ws, { range: range, header: 1 });
var SST = ["~Sh33tJ5~"];
data.forEach(function(row) {
return row.forEach(function(cell) {
if (typeof cell == "string")
SST.push(cell);
});
});
var dependents = {};
var indices = [];
var cfb = CFB.read(opts.numbers, { type: "base64" });
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (fi.type != 2)
return;
if (!fi.name.match(/\.iwa/))
return;
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content);
var x2 = parse_iwa_file(raw1);
x2.forEach(function(packet2) {
indices.push(packet2.id);
dependents[packet2.id] = { deps: [], location: fp, type: varint_to_i32(packet2.messages[0].meta[1][0].data) };
});
});
indices.sort(function(x2, y2) {
return x2 - y2;
});
var indices_varint = indices.filter(function(x2) {
return x2 > 1;
}).map(function(x2) {
return [x2, write_varint49(x2)];
});
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (!fi.name.match(/\.iwa/))
return;
var x2 = parse_iwa_file(decompress_iwa_file(fi.content));
x2.forEach(function(ia) {
ia.messages.forEach(function(m) {
indices_varint.forEach(function(ivi) {
if (ia.messages.some(function(mess) {
return varint_to_i32(mess.meta[1][0].data) != 11006 && u8contains(mess.data, ivi[1]);
})) {
dependents[ivi[0]].deps.push(ia.id);
}
});
});
});
});
function get_unique_msgid() {
for (var i = 927262; i < 2e6; ++i)
if (!dependents[i])
return i;
throw new Error("Too many messages");
}
var entry = CFB.find(cfb, dependents[1].location);
var x = parse_iwa_file(decompress_iwa_file(entry.content));
var docroot;
for (var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if (packet.id == 1)
docroot = packet;
}
var sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[1][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
var pb = parse_shallow(docroot.messages[0].data);
{
pb[6][0].data = write_varint49(range.e.r + 1);
pb[7][0].data = write_varint49(range.e.c + 1);
var cruidsref = parse_TSP_Reference(pb[46][0].data);
var oldbucket = CFB.find(cfb, dependents[cruidsref].location);
var _x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
for (var j = 0; j < _x.length; ++j) {
if (_x[j].id == cruidsref)
break;
}
if (_x[j].id != cruidsref)
throw "Bad ColumnRowUIDMapArchive";
var cruids = parse_shallow(_x[j].messages[0].data);
cruids[1] = [];
cruids[2] = [], cruids[3] = [];
for (var C = 0; C <= range.e.c; ++C) {
var uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(C + 420690) }];
cruids[1].push({ type: 2, data: write_shallow(uuid) });
cruids[2].push({ type: 0, data: write_varint49(C) });
cruids[3].push({ type: 0, data: write_varint49(C) });
}
cruids[4] = [];
cruids[5] = [], cruids[6] = [];
for (var R = 0; R <= range.e.r; ++R) {
uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(R + 726270) }];
cruids[4].push({ type: 2, data: write_shallow(uuid) });
cruids[5].push({ type: 0, data: write_varint49(R) });
cruids[6].push({ type: 0, data: write_varint49(R) });
}
_x[j].messages[0].data = write_shallow(cruids);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
delete pb[46];
var store = parse_shallow(pb[4][0].data);
{
store[7][0].data = write_varint49(range.e.r + 1);
var row_headers = parse_shallow(store[1][0].data);
var row_header_ref = parse_TSP_Reference(row_headers[2][0].data);
oldbucket = CFB.find(cfb, dependents[row_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != row_header_ref)
throw "Bad HeaderStorageBucket";
var base_bucket = parse_shallow(_x[0].messages[0].data);
for (R = 0; R < data.length; ++R) {
var _bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(R);
_bucket[4][0].data = write_varint49(data[R].length);
base_bucket[2][R] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var col_header_ref = parse_TSP_Reference(store[2][0].data);
oldbucket = CFB.find(cfb, dependents[col_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != col_header_ref)
throw "Bad HeaderStorageBucket";
base_bucket = parse_shallow(_x[0].messages[0].data);
for (C = 0; C <= range.e.c; ++C) {
_bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(C);
_bucket[4][0].data = write_varint49(range.e.r + 1);
base_bucket[2][C] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var sstref = parse_TSP_Reference(store[4][0].data);
(function() {
var sentry = CFB.find(cfb, dependents[sstref].location);
var sx = parse_iwa_file(decompress_iwa_file(sentry.content));
var sstroot;
for (var sxi = 0; sxi < sx.length; ++sxi) {
var packet2 = sx[sxi];
if (packet2.id == sstref)
sstroot = packet2;
}
var sstdata = parse_shallow(sstroot.messages[0].data);
{
sstdata[3] = [];
var newsst = [];
SST.forEach(function(str, i) {
newsst[1] = [{ type: 0, data: write_varint49(i) }];
newsst[2] = [{ type: 0, data: write_varint49(1) }];
newsst[3] = [{ type: 2, data: stru8(str) }];
sstdata[3].push({ type: 2, data: write_shallow(newsst) });
});
}
sstroot.messages[0].data = write_shallow(sstdata);
var sy = write_iwa_file(sx);
var raw32 = compress_iwa_file(sy);
sentry.content = raw32;
sentry.size = sentry.content.length;
})();
var tile = parse_shallow(store[3][0].data);
{
var t = tile[1][0];
delete tile[2];
var tl = parse_shallow(t.data);
{
var tileref = parse_TSP_Reference(tl[2][0].data);
(function() {
var tentry = CFB.find(cfb, dependents[tileref].location);
var tx = parse_iwa_file(decompress_iwa_file(tentry.content));
var tileroot;
for (var sxi = 0; sxi < tx.length; ++sxi) {
var packet2 = tx[sxi];
if (packet2.id == tileref)
tileroot = packet2;
}
var tiledata = parse_shallow(tileroot.messages[0].data);
{
delete tiledata[6];
delete tile[7];
var rowload = new Uint8Array(tiledata[5][0].data);
tiledata[5] = [];
var cnt = 0;
for (var R2 = 0; R2 <= range.e.r; ++R2) {
var tilerow = parse_shallow(rowload);
cnt += write_tile_row(tilerow, data[R2], SST);
tilerow[1][0].data = write_varint49(R2);
tiledata[5].push({ data: write_shallow(tilerow), type: 2 });
}
tiledata[1] = [{ type: 0, data: write_varint49(range.e.c + 1) }];
tiledata[2] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
tiledata[3] = [{ type: 0, data: write_varint49(cnt) }];
tiledata[4] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
}
tileroot.messages[0].data = write_shallow(tiledata);
var ty = write_iwa_file(tx);
var raw32 = compress_iwa_file(ty);
tentry.content = raw32;
tentry.size = tentry.content.length;
})();
}
t.data = write_shallow(tl);
}
store[3][0].data = write_shallow(tile);
}
pb[4][0].data = write_shallow(store);
}
docroot.messages[0].data = write_shallow(pb);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
entry.content = raw3;
entry.size = entry.content.length;
return cfb;
}

View File

@ -1,5 +1,6 @@
function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
if(opts.bookType == "ods") return write_ods(wb, opts);
if(opts.bookType == "numbers") return write_numbers_iwa(wb, opts);
if(opts.bookType == "xlsb") return write_zip_xlsxb(wb, opts);
return write_zip_xlsx(wb, opts);
}

View File

@ -149,6 +149,7 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
case 'xlsm':
case 'xlam':
case 'xlsb':
case 'numbers':
case 'ods': return write_zip_type(wb, o);
default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
}

28
dist/xlsx.core.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.core.min.map generated vendored

File diff suppressed because one or more lines are too long

2056
dist/xlsx.extendscript.js generated vendored

File diff suppressed because it is too large Load Diff

30
dist/xlsx.full.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.full.min.map generated vendored

File diff suppressed because one or more lines are too long

16
dist/xlsx.mini.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.mini.min.map generated vendored

File diff suppressed because one or more lines are too long

4
dist/xlsx.zahl.js generated vendored Normal file

File diff suppressed because one or more lines are too long

2
dist/xlsx.zahl.mjs generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -258,5 +258,60 @@ stream.pipe(conv); conv.pipe(process.stdout);
</details>
<details>
<summary><b>Exporting NUMBERS files</b> (click to show)</summary>
The NUMBERS writer requires a fairly large base. The supplementary `xlsx.zahl`
scripts provide support. `xlsx.zahl.js` is designed for standalone and NodeJS
use, while `xlsx.zahl.mjs` is suitable for ESM.
_Browser_
```html
<meta charset="utf8">
<script src="xlsx.full.min.js"></script>
<script src="xlsx.zahl.js"></script>
<script>
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textport.numbers", {numbers: XLSX_ZAHL, compression: true});
</script>
```
_Node_
```js
var XLSX = require("./xlsx.flow");
var XLSX_ZAHL = require("./dist/xlsx.zahl");
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textport.numbers", {numbers: XLSX_ZAHL, compression: true});
```
_Deno_
```ts
import * as XLSX from './xlsx.mjs';
import XLSX_ZAHL from './dist/xlsx.zahl.mjs';
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textports.numbers", {numbers: XLSX_ZAHL, compression: true});
```
</details>
<https://github.com/sheetjs/sheetaki> pipes write streams to nodejs response.

View File

@ -13,6 +13,7 @@ The exported `write` and `writeFile` functions accept an options argument:
|`Props` | | Override workbook properties when writing ** |
|`themeXLSX` | | Override theme XML when writing XLSX/XLSB/XLSM ** |
|`ignoreEC` | `true` | Suppress "number as text" errors ** |
|`numbers` | | Payload for NUMBERS export ** |
- `bookSST` is slower and more memory intensive, but has better compatibility
with older versions of iOS Numbers
@ -28,6 +29,8 @@ The exported `write` and `writeFile` functions accept an options argument:
- Due to a bug in the program, some features like "Text to Columns" will crash
Excel on worksheets where error conditions are ignored. The writer will mark
files to ignore the error by default. Set `ignoreEC` to `false` to suppress.
- Due to the size of the data, the NUMBERS data is not included by default. The
included `xlsx.zahl.js` and `xlsx.zahl.mjs` scripts include the data.
### Supported Output Formats
@ -45,6 +48,7 @@ output formats. The specific file type is controlled with `bookType` option:
| `biff3` | `.xls` | none | single | Excel 3.0 Worksheet Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
| `numbers` |`.numbers`| ZIP | single | Numbers 3.0+ Spreadsheet |
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
| `wk3` | `.wk3` | none | multi | Lotus Workbook (WK3) |

View File

@ -20,7 +20,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Lotus Formatted Text (PRN) | ✔ | ✔ |
| UTF-16 Unicode Text (TXT) | ✔ | ✔ |
| **Other Workbook/Worksheet Formats** |:-----:|:-----:|
| Numbers 3.0+ / iWork 2013+ Spreadsheet (NUMBERS) | ✔ | |
| Numbers 3.0+ / iWork 2013+ Spreadsheet (NUMBERS) | ✔ | |
| OpenDocument Spreadsheet (ODS) | ✔ | ✔ |
| Flat XML ODF Spreadsheet (FODS) | ✔ | ✔ |
| Uniform Office Format Spreadsheet (标文通 UOS1/UOS2) | ✔ | |
@ -169,6 +169,8 @@ The parser focuses on extracting raw data from tables. Numbers technically
supports multiple tables in a logical worksheet, including custom titles. This
parser will generate one worksheet per Numbers table.
The writer currently exports a small range from the first worksheet.
- **OpenDocument Spreadsheet (ODS/FODS)**
ODS is an XML-in-ZIP format akin to XLSX while FODS is an XML format akin to

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 204 KiB

View File

@ -1656,6 +1656,58 @@ stream.pipe(conv); conv.pipe(process.stdout);
```
The NUMBERS writer requires a fairly large base. The supplementary `xlsx.zahl`
scripts provide support. `xlsx.zahl.js` is designed for standalone and NodeJS
use, while `xlsx.zahl.mjs` is suitable for ESM.
_Browser_
```html
<meta charset="utf8">
<script src="xlsx.full.min.js"></script>
<script src="xlsx.zahl.js"></script>
<script>
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textport.numbers", {numbers: XLSX_ZAHL, compression: true});
</script>
```
_Node_
```js
var XLSX = require("./xlsx.flow");
var XLSX_ZAHL = require("./dist/xlsx.zahl");
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textport.numbers", {numbers: XLSX_ZAHL, compression: true});
```
_Deno_
```ts
import * as XLSX from './xlsx.mjs';
import XLSX_ZAHL from './dist/xlsx.zahl.mjs';
var wb = XLSX.utils.book_new(); var ws = XLSX.utils.aoa_to_sheet([
["SheetJS", "<3","ிிள்"],
[72,,"Arbeitsblätter"],
[,62,"数据"],
[true,false,],
]); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "textports.numbers", {numbers: XLSX_ZAHL, compression: true});
```
<https://github.com/sheetjs/sheetaki> pipes write streams to nodejs response.
### Generating JSON and JS Data
@ -3171,6 +3223,7 @@ The exported `write` and `writeFile` functions accept an options argument:
|`Props` | | Override workbook properties when writing ** |
|`themeXLSX` | | Override theme XML when writing XLSX/XLSB/XLSM ** |
|`ignoreEC` | `true` | Suppress "number as text" errors ** |
|`numbers` | | Payload for NUMBERS export ** |
- `bookSST` is slower and more memory intensive, but has better compatibility
with older versions of iOS Numbers
@ -3186,6 +3239,8 @@ The exported `write` and `writeFile` functions accept an options argument:
- Due to a bug in the program, some features like "Text to Columns" will crash
Excel on worksheets where error conditions are ignored. The writer will mark
files to ignore the error by default. Set `ignoreEC` to `false` to suppress.
- Due to the size of the data, the NUMBERS data is not included by default. The
included `xlsx.zahl.js` and `xlsx.zahl.mjs` scripts include the data.
### Supported Output Formats
@ -3203,6 +3258,7 @@ output formats. The specific file type is controlled with `bookType` option:
| `biff3` | `.xls` | none | single | Excel 3.0 Worksheet Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
| `numbers` |`.numbers`| ZIP | single | Numbers 3.0+ Spreadsheet |
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
| `wk3` | `.wk3` | none | multi | Lotus Workbook (WK3) |
@ -3725,7 +3781,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Lotus Formatted Text (PRN) | ✔ | ✔ |
| UTF-16 Unicode Text (TXT) | ✔ | ✔ |
| **Other Workbook/Worksheet Formats** |:-----:|:-----:|
| Numbers 3.0+ / iWork 2013+ Spreadsheet (NUMBERS) | ✔ | |
| Numbers 3.0+ / iWork 2013+ Spreadsheet (NUMBERS) | ✔ | |
| OpenDocument Spreadsheet (ODS) | ✔ | ✔ |
| Flat XML ODF Spreadsheet (FODS) | ✔ | ✔ |
| Uniform Office Format Spreadsheet (标文通 UOS1/UOS2) | ✔ | |
@ -3872,6 +3928,8 @@ The parser focuses on extracting raw data from tables. Numbers technically
supports multiple tables in a logical worksheet, including custom titles. This
parser will generate one worksheet per Numbers table.
The writer currently exports a small range from the first worksheet.
- **OpenDocument Spreadsheet (ODS/FODS)**
ODS is an XML-in-ZIP format akin to XLSX while FODS is an XML format akin to

View File

@ -65,6 +65,7 @@ digraph G {
123 -> csf
qpw -> csf
nums -> csf
csf -> nums
}
subgraph WORKSHEET {
edge [color=aquamarine4];

2
modules/.gitignore vendored
View File

@ -5,3 +5,5 @@ test_files
*.[Jj][Pp][Gg]
*.[Pp][Ll][Ii][Ss][Tt]
DocumentIdentifier
xlsx.zahl.*
src/numbers.ts

View File

@ -5,6 +5,19 @@ function u8_to_dataview(array) {
function u8str(u8) {
return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8));
}
function stru8(str) {
return typeof TextEncoder != "undefined" ? new TextEncoder().encode(str) : s2a(utf8write(str));
}
function u8contains(body, search) {
outer:
for (var L = 0; L <= body.length - search.length; ++L) {
for (var j = 0; j < search.length; ++j)
if (body[L + j] != search[j])
continue outer;
return true;
}
return false;
}
function u8concat(u8a) {
var len = u8a.reduce(function(acc, x) {
return acc + x.length;
@ -29,6 +42,15 @@ function readDecimal128LE(buf, offset) {
mantissa = mantissa * 256 + buf[j];
return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176);
}
function writeDecimal128LE(buf, offset, value) {
var exp = Math.floor(value == 0 ? 0 : Math.LOG10E * Math.log(Math.abs(value))) + 6176 - 20;
var mantissa = value / Math.pow(10, exp - 6176);
buf[offset + 15] |= exp >> 7;
buf[offset + 14] |= (exp & 127) << 1;
for (var i = 0; mantissa >= 1; ++i, mantissa /= 256)
buf[offset + i] = mantissa & 255;
buf[offset + 15] |= value >= 0 ? 0 : 128;
}
function parse_varint49(buf, ptr) {
var l = ptr ? ptr[0] : 0;
var usz = buf[l] & 127;
@ -154,7 +176,7 @@ function parse_shallow(buf) {
default:
throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off));
}
var v = { offset: off, data: res, type: type };
var v = { data: res, type: type };
if (out[num] == null)
out[num] = [v];
else
@ -166,6 +188,8 @@ function write_shallow(proto) {
var out = [];
proto.forEach(function(field, idx) {
field.forEach(function(item) {
if (!item.data)
return;
out.push(write_varint49(idx * 8 + item.type));
if (item.type == 2)
out.push(write_varint49(item.data.length));
@ -175,21 +199,12 @@ function write_shallow(proto) {
return u8concat(out);
}
function mappa(data, cb) {
if (!data)
return [];
return data.map(function(d) {
var _a;
try {
return cb(d.data);
} catch (e) {
var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/);
if (m)
e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset));
throw e;
}
});
return (data == null ? void 0 : data.map(function(d) {
return cb(d.data);
})) || [];
}
function parse_iwa_file(buf) {
var _a;
var out = [], ptr = [0];
while (ptr[0] < buf.length) {
var len = parse_varint49(buf, ptr);
@ -208,10 +223,35 @@ function parse_iwa_file(buf) {
});
ptr[0] += fl;
});
if ((_a = ai[3]) == null ? void 0 : _a[0])
res.merge = varint_to_i32(ai[3][0].data) >>> 0 > 0;
out.push(res);
}
return out;
}
function write_iwa_file(ias) {
var bufs = [];
ias.forEach(function(ia) {
var ai = [];
ai[1] = [{ data: write_varint49(ia.id), type: 0 }];
ai[2] = [];
if (ia.merge != null)
ai[3] = [{ data: write_varint49(+!!ia.merge), type: 0 }];
var midata = [];
ia.messages.forEach(function(mi) {
midata.push(mi.data);
mi.meta[3] = [{ type: 0, data: write_varint49(mi.data.length) }];
ai[2].push({ data: write_shallow(mi.meta), type: 2 });
});
var aipayload = write_shallow(ai);
bufs.push(write_varint49(aipayload.length));
bufs.push(aipayload);
midata.forEach(function(mid) {
return bufs.push(mid);
});
});
return u8concat(bufs);
}
function parse_snappy_chunk(type, buf) {
if (type != 0)
throw new Error("Unexpected Snappy chunk type ".concat(type));
@ -366,7 +406,7 @@ function parse_old_storage(buf, sst, rsst, v) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -388,7 +428,7 @@ function parse_old_storage(buf, sst, rsst, v) {
}
return ret;
}
function parse_storage(buf, sst, rsst) {
function parse_new_storage(buf, sst, rsst) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(8, true);
var data_offset = 12;
@ -430,7 +470,7 @@ function parse_storage(buf, sst, rsst) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -451,6 +491,66 @@ function parse_storage(buf, sst, rsst) {
}
return ret;
}
function write_new_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 5;
switch (cell.t) {
case "n":
out[1] = 2;
writeDecimal128LE(out, l, cell.v);
flags |= 1;
l += 16;
break;
case "b":
out[1] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 2;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[1] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 8;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(8, flags, true);
return out.slice(0, l);
}
function write_old_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 3;
switch (cell.t) {
case "n":
out[2] = 2;
dv.setFloat64(l, cell.v, true);
flags |= 32;
l += 8;
break;
case "b":
out[2] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 32;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[2] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 16;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(4, flags, true);
return out.slice(0, l);
}
function parse_cell_storage(buf, sst, rsst) {
switch (buf[0]) {
case 0:
@ -459,7 +559,7 @@ function parse_cell_storage(buf, sst, rsst) {
case 3:
return parse_old_storage(buf, sst, rsst, buf[0]);
case 5:
return parse_storage(buf, sst, rsst);
return parse_new_storage(buf, sst, rsst);
default:
throw new Error("Unsupported payload version ".concat(buf[0]));
}
@ -468,6 +568,11 @@ function parse_TSP_Reference(buf) {
var pb = parse_shallow(buf);
return parse_varint49(pb[1][0].data);
}
function write_TSP_Reference(idx) {
var out = [];
out[1] = [{ type: 0, data: write_varint49(idx) }];
return write_shallow(out);
}
function parse_TST_TableDataList(M, root) {
var pb = parse_shallow(root.data);
var type = varint_to_i32(pb[1][0].data);
@ -526,7 +631,8 @@ function parse_TST_TileRowInfo(u8, type) {
var cells = [];
for (C = 0; C < offsets.length - 1; ++C)
cells[offsets[C][0]] = used_storage.subarray(offsets[C][1] * width, offsets[C + 1][1] * width);
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
if (offsets.length >= 1)
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
return { R: R, cells: cells };
}
function parse_TST_Tile(M, root) {
@ -632,7 +738,7 @@ function parse_TN_DocumentArchive(M, root) {
}
function parse_numbers_iwa(cfb) {
var _a, _b, _c, _d;
var out = {}, indices = [];
var M = {}, indices = [];
cfb.FullPaths.forEach(function(p) {
if (p.match(/\.iwpv2/))
throw new Error("Unsupported password protection");
@ -653,16 +759,16 @@ function parse_numbers_iwa(cfb) {
return console.log("## " + (e.message || e));
}
packets.forEach(function(packet) {
out[packet.id] = packet.messages;
M[packet.id] = packet.messages;
indices.push(packet.id);
});
});
if (!indices.length)
throw new Error("File has no messages");
var docroot = ((_d = (_c = (_b = (_a = out == null ? void 0 : out[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(out[1][0].meta[1][0].data) == 1 && out[1][0];
var docroot = ((_d = (_c = (_b = (_a = M == null ? void 0 : M[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(M[1][0].meta[1][0].data) == 1 && M[1][0];
if (!docroot)
indices.forEach(function(idx) {
out[idx].forEach(function(iwam) {
M[idx].forEach(function(iwam) {
var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0;
if (mtype == 1) {
if (!docroot)
@ -674,5 +780,323 @@ function parse_numbers_iwa(cfb) {
});
if (!docroot)
throw new Error("Cannot find Document root");
return parse_TN_DocumentArchive(out, docroot);
return parse_TN_DocumentArchive(M, docroot);
}
function write_tile_row(tri, data, SST) {
var _a, _b, _c, _d;
if (!((_a = tri[6]) == null ? void 0 : _a[0]) || !((_b = tri[7]) == null ? void 0 : _b[0]))
throw "Mutation only works on post-BNC storages!";
var wide_offsets = ((_d = (_c = tri[8]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && varint_to_i32(tri[8][0].data) > 0 || false;
if (wide_offsets)
throw "Math only works with normal offsets";
var cnt = 0;
var dv = u8_to_dataview(tri[7][0].data), last_offset = 0, cell_storage = [];
var _dv = u8_to_dataview(tri[4][0].data), _last_offset = 0, _cell_storage = [];
for (var C = 0; C < data.length; ++C) {
if (data[C] == null) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535);
continue;
}
dv.setUint16(C * 2, last_offset, true);
_dv.setUint16(C * 2, _last_offset, true);
var celload, _celload;
switch (typeof data[C]) {
case "string":
celload = write_new_storage({ t: "s", v: data[C] }, SST);
_celload = write_old_storage({ t: "s", v: data[C] }, SST);
break;
case "number":
celload = write_new_storage({ t: "n", v: data[C] }, SST);
_celload = write_old_storage({ t: "n", v: data[C] }, SST);
break;
case "boolean":
celload = write_new_storage({ t: "b", v: data[C] }, SST);
_celload = write_old_storage({ t: "b", v: data[C] }, SST);
break;
default:
throw new Error("Unsupported value " + data[C]);
}
cell_storage.push(celload);
last_offset += celload.length;
_cell_storage.push(_celload);
_last_offset += _celload.length;
++cnt;
}
tri[2][0].data = write_varint49(cnt);
for (; C < tri[7][0].data.length / 2; ++C) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535, true);
}
tri[6][0].data = u8concat(cell_storage);
tri[3][0].data = u8concat(_cell_storage);
return cnt;
}
function write_numbers_iwa(wb, opts) {
if (!opts || !opts.numbers)
throw new Error("Must pass a `numbers` option -- check the README");
var ws = wb.Sheets[wb.SheetNames[0]];
if (wb.SheetNames.length > 1)
console.error("The Numbers writer currently writes only the first table");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
if (range.e.c > 9) {
trunc = true;
range.e.c = 9;
}
if (range.e.r > 49) {
trunc = true;
range.e.r = 49;
}
if (trunc)
console.error("The Numbers writer is currently limited to ".concat(encode_range(range)));
var data = sheet_to_json(ws, { range: range, header: 1 });
var SST = ["~Sh33tJ5~"];
data.forEach(function(row) {
return row.forEach(function(cell) {
if (typeof cell == "string")
SST.push(cell);
});
});
var dependents = {};
var indices = [];
var cfb = CFB.read(opts.numbers, { type: "base64" });
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (fi.type != 2)
return;
if (!fi.name.match(/\.iwa/))
return;
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content);
var x2 = parse_iwa_file(raw1);
x2.forEach(function(packet2) {
indices.push(packet2.id);
dependents[packet2.id] = { deps: [], location: fp, type: varint_to_i32(packet2.messages[0].meta[1][0].data) };
});
});
indices.sort(function(x2, y2) {
return x2 - y2;
});
var indices_varint = indices.filter(function(x2) {
return x2 > 1;
}).map(function(x2) {
return [x2, write_varint49(x2)];
});
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (!fi.name.match(/\.iwa/))
return;
var x2 = parse_iwa_file(decompress_iwa_file(fi.content));
x2.forEach(function(ia) {
ia.messages.forEach(function(m) {
indices_varint.forEach(function(ivi) {
if (ia.messages.some(function(mess) {
return varint_to_i32(mess.meta[1][0].data) != 11006 && u8contains(mess.data, ivi[1]);
})) {
dependents[ivi[0]].deps.push(ia.id);
}
});
});
});
});
function get_unique_msgid() {
for (var i = 927262; i < 2e6; ++i)
if (!dependents[i])
return i;
throw new Error("Too many messages");
}
var entry = CFB.find(cfb, dependents[1].location);
var x = parse_iwa_file(decompress_iwa_file(entry.content));
var docroot;
for (var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if (packet.id == 1)
docroot = packet;
}
var sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[1][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
var pb = parse_shallow(docroot.messages[0].data);
{
pb[6][0].data = write_varint49(range.e.r + 1);
pb[7][0].data = write_varint49(range.e.c + 1);
var cruidsref = parse_TSP_Reference(pb[46][0].data);
var oldbucket = CFB.find(cfb, dependents[cruidsref].location);
var _x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
for (var j = 0; j < _x.length; ++j) {
if (_x[j].id == cruidsref)
break;
}
if (_x[j].id != cruidsref)
throw "Bad ColumnRowUIDMapArchive";
var cruids = parse_shallow(_x[j].messages[0].data);
cruids[1] = [];
cruids[2] = [], cruids[3] = [];
for (var C = 0; C <= range.e.c; ++C) {
var uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(C + 420690) }];
cruids[1].push({ type: 2, data: write_shallow(uuid) });
cruids[2].push({ type: 0, data: write_varint49(C) });
cruids[3].push({ type: 0, data: write_varint49(C) });
}
cruids[4] = [];
cruids[5] = [], cruids[6] = [];
for (var R = 0; R <= range.e.r; ++R) {
uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(R + 726270) }];
cruids[4].push({ type: 2, data: write_shallow(uuid) });
cruids[5].push({ type: 0, data: write_varint49(R) });
cruids[6].push({ type: 0, data: write_varint49(R) });
}
_x[j].messages[0].data = write_shallow(cruids);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
delete pb[46];
var store = parse_shallow(pb[4][0].data);
{
store[7][0].data = write_varint49(range.e.r + 1);
var row_headers = parse_shallow(store[1][0].data);
var row_header_ref = parse_TSP_Reference(row_headers[2][0].data);
oldbucket = CFB.find(cfb, dependents[row_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != row_header_ref)
throw "Bad HeaderStorageBucket";
var base_bucket = parse_shallow(_x[0].messages[0].data);
for (R = 0; R < data.length; ++R) {
var _bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(R);
_bucket[4][0].data = write_varint49(data[R].length);
base_bucket[2][R] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var col_header_ref = parse_TSP_Reference(store[2][0].data);
oldbucket = CFB.find(cfb, dependents[col_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != col_header_ref)
throw "Bad HeaderStorageBucket";
base_bucket = parse_shallow(_x[0].messages[0].data);
for (C = 0; C <= range.e.c; ++C) {
_bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(C);
_bucket[4][0].data = write_varint49(range.e.r + 1);
base_bucket[2][C] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var sstref = parse_TSP_Reference(store[4][0].data);
(function() {
var sentry = CFB.find(cfb, dependents[sstref].location);
var sx = parse_iwa_file(decompress_iwa_file(sentry.content));
var sstroot;
for (var sxi = 0; sxi < sx.length; ++sxi) {
var packet2 = sx[sxi];
if (packet2.id == sstref)
sstroot = packet2;
}
var sstdata = parse_shallow(sstroot.messages[0].data);
{
sstdata[3] = [];
var newsst = [];
SST.forEach(function(str, i) {
newsst[1] = [{ type: 0, data: write_varint49(i) }];
newsst[2] = [{ type: 0, data: write_varint49(1) }];
newsst[3] = [{ type: 2, data: stru8(str) }];
sstdata[3].push({ type: 2, data: write_shallow(newsst) });
});
}
sstroot.messages[0].data = write_shallow(sstdata);
var sy = write_iwa_file(sx);
var raw32 = compress_iwa_file(sy);
sentry.content = raw32;
sentry.size = sentry.content.length;
})();
var tile = parse_shallow(store[3][0].data);
{
var t = tile[1][0];
delete tile[2];
var tl = parse_shallow(t.data);
{
var tileref = parse_TSP_Reference(tl[2][0].data);
(function() {
var tentry = CFB.find(cfb, dependents[tileref].location);
var tx = parse_iwa_file(decompress_iwa_file(tentry.content));
var tileroot;
for (var sxi = 0; sxi < tx.length; ++sxi) {
var packet2 = tx[sxi];
if (packet2.id == tileref)
tileroot = packet2;
}
var tiledata = parse_shallow(tileroot.messages[0].data);
{
delete tiledata[6];
delete tile[7];
var rowload = new Uint8Array(tiledata[5][0].data);
tiledata[5] = [];
var cnt = 0;
for (var R2 = 0; R2 <= range.e.r; ++R2) {
var tilerow = parse_shallow(rowload);
cnt += write_tile_row(tilerow, data[R2], SST);
tilerow[1][0].data = write_varint49(R2);
tiledata[5].push({ data: write_shallow(tilerow), type: 2 });
}
tiledata[1] = [{ type: 0, data: write_varint49(range.e.c + 1) }];
tiledata[2] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
tiledata[3] = [{ type: 0, data: write_varint49(cnt) }];
tiledata[4] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
}
tileroot.messages[0].data = write_shallow(tiledata);
var ty = write_iwa_file(tx);
var raw32 = compress_iwa_file(ty);
tentry.content = raw32;
tentry.size = tentry.content.length;
})();
}
t.data = write_shallow(tl);
}
store[3][0].data = write_shallow(tile);
}
pb[4][0].data = write_shallow(store);
}
docroot.messages[0].data = write_shallow(pb);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
entry.content = raw3;
entry.size = entry.content.length;
return cfb;
}

View File

@ -2,7 +2,7 @@
/// <reference path="src/types.ts"/>
/* these are type imports and do not show up in the generated JS */
import { CFB$Container } from 'cfb';
import { CFB$Container, CFB$Entry } from 'cfb';
import { WorkBook, WorkSheet, Range, CellObject } from '../';
import type { utils } from "../";
@ -10,12 +10,28 @@ declare var encode_cell: typeof utils.encode_cell;
declare var encode_range: typeof utils.encode_range;
declare var book_new: typeof utils.book_new;
declare var book_append_sheet: typeof utils.book_append_sheet;
declare var sheet_to_json: typeof utils.sheet_to_json;
declare var decode_range: typeof utils.decode_range;
import * as _CFB from 'cfb';
declare var CFB: typeof _CFB;
//<<import { utils } from "../../";
//<<const { encode_cell, encode_range, book_new, book_append_sheet } = utils;
function u8_to_dataview(array: Uint8Array): DataView { return new DataView(array.buffer, array.byteOffset, array.byteLength); }
//<<export { u8_to_dataview };
function u8str(u8: Uint8Array): string { return /* Buffer.isBuffer(u8) ? u8.toString() :*/ typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8)); }
function stru8(str: string): Uint8Array { return typeof TextEncoder != "undefined" ? new TextEncoder().encode(str) : s2a(utf8write(str)) as Uint8Array; }
//<<export { u8str, stru8 };
function u8contains(body: Uint8Array, search: Uint8Array): boolean {
outer: for(var L = 0; L <= body.length - search.length; ++L) {
for(var j = 0; j < search.length; ++j) if(body[L+j] != search[j]) continue outer;
return true;
}
return false;
}
//<<export { u8contains }
/** Concatenate Uint8Arrays */
function u8concat(u8a: Uint8Array[]): Uint8Array {
@ -41,6 +57,17 @@ function readDecimal128LE(buf: Uint8Array, offset: number): number {
for(var j = offset + 13; j >= offset; --j) mantissa = mantissa * 256 + buf[j];
return ((buf[offset+15] & 0x80) ? -mantissa : mantissa) * Math.pow(10, exp - 0x1820);
}
/** Write a 128-bit decimal to the modern cell storage */
function writeDecimal128LE(buf: Uint8Array, offset: number, value: number): void {
// TODO: something more correct than this
var exp = Math.floor(value == 0 ? 0 : /*Math.log10*/Math.LOG10E * Math.log(Math.abs(value))) + 0x1820 - 20;
var mantissa = (value / Math.pow(10, exp - 0x1820));
buf[offset+15] |= exp >> 7;
buf[offset+14] |= (exp & 0x7F) << 1;
for(var i = 0; mantissa >= 1; ++i, mantissa /= 256) buf[offset + i] = mantissa & 0xFF;
buf[offset+15] |= (value >= 0 ? 0 : 0x80);
}
type Ptr = [number];
@ -78,6 +105,7 @@ function write_varint49(v: number): Uint8Array {
}
return usz.slice(0, L);
}
//<<export { parse_varint49, write_varint49 };
/** Parse a 32-bit signed integer from the raw varint */
function varint_to_i32(buf: Uint8Array): number {
@ -93,7 +121,6 @@ function varint_to_i32(buf: Uint8Array): number {
//<<export { varint_to_i32 };
interface ProtoItem {
offset?: number;
data: Uint8Array;
type: number;
}
@ -122,7 +149,7 @@ function parse_shallow(buf: Uint8Array): ProtoMessage {
case 4: // End group
default: throw new Error(`PB Type ${type} for Field ${num} at offset ${off}`);
}
var v: ProtoItem = { offset: off, data: res, type };
var v: ProtoItem = { data: res, type };
if(out[num] == null) out[num] = [v];
else out[num].push(v);
}
@ -133,6 +160,7 @@ function write_shallow(proto: ProtoMessage): Uint8Array {
var out: Uint8Array[] = [];
proto.forEach((field, idx) => {
field.forEach(item => {
if(!item.data) return;
out.push(write_varint49(idx * 8 + item.type));
if(item.type == 2) out.push(write_varint49(item.data.length));
out.push(item.data);
@ -144,14 +172,7 @@ function write_shallow(proto: ProtoMessage): Uint8Array {
/** Map over each entry in a repeated (or single-value) field */
function mappa<U>(data: ProtoField, cb:(Uint8Array) => U): U[] {
if(!data) return [];
return data.map((d) => { try {
return cb(d.data);
} catch(e) {
var m = e.message?.match(/at offset (\d+)/);
if(m) e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset));
throw e;
}});
return data?.map(d => cb(d.data)) || [];
}
@ -162,6 +183,7 @@ interface IWAMessage {
}
interface IWAArchiveInfo {
id?: number;
merge?: boolean;
messages?: IWAMessage[];
}
/** Extract all messages from a IWA file */
@ -187,11 +209,34 @@ function parse_iwa_file(buf: Uint8Array): IWAArchiveInfo[] {
});
ptr[0] += fl;
});
if(ai[3]?.[0]) res.merge = (varint_to_i32(ai[3][0].data) >>> 0) > 0;
out.push(res);
}
return out;
}
//<<export { parse_iwa_file };
function write_iwa_file(ias: IWAArchiveInfo[]): Uint8Array {
var bufs: Uint8Array[] = [];
ias.forEach(ia => {
var ai: ProtoMessage = [];
ai[1] = [{data: write_varint49(ia.id), type: 0}];
ai[2] = [];
if(ia.merge != null) ai[3] = [ { data: write_varint49(+!!ia.merge), type: 0 } ];
var midata: Uint8Array[] = [];
ia.messages.forEach(mi => {
midata.push(mi.data);
mi.meta[3] = [ { type: 0, data: write_varint49(mi.data.length) } ];
ai[2].push({data: write_shallow(mi.meta), type: 2});
});
var aipayload = write_shallow(ai);
bufs.push(write_varint49(aipayload.length));
bufs.push(aipayload);
midata.forEach(mid => bufs.push(mid));
});
return u8concat(bufs);
}
//<<export { IWAMessage, IWAArchiveInfo, parse_iwa_file, write_iwa_file };
/** Decompress a snappy chunk */
function parse_snappy_chunk(type: number, buf: Uint8Array): Uint8Array {
@ -308,7 +353,7 @@ function parse_old_storage(buf: Uint8Array, sst: string[], rsst: string[], v: 0|
case 3: ret = { t: "s", v: sst[sidx] }; break; // string
case 5: ret = { t: "d", v: dt }; break; // date-time
case 6: ret = { t: "b", v: ieee > 0 }; break; // boolean
case 7: ret = { t: "n", v: ieee }; break; // duration in seconds TODO: emit [hh]:[mm] style format with adjusted value
case 7: ret = { t: "n", v: ieee / 86400 }; break; // duration in seconds TODO: emit [hh]:[mm] style format with adjusted value
case 8: ret = { t: "e", v: 0}; break; // "formula error" TODO: enumerate and map errors to csf equivalents
case 9: { // "automatic"?
if(ridx > -1) ret = { t: "s", v: rsst[ridx] };
@ -323,7 +368,8 @@ function parse_old_storage(buf: Uint8Array, sst: string[], rsst: string[], v: 0|
return ret;
}
function parse_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObject {
/** Parse "new storage" (version 5) */
function parse_new_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObject {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(8, true);
@ -345,7 +391,7 @@ function parse_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObje
case 3: ret = { t: "s", v: sst[sidx] }; break; // string
case 5: ret = { t: "d", v: dt }; break; // date-time
case 6: ret = { t: "b", v: ieee > 0 }; break; // boolean
case 7: ret = { t: "n", v: ieee }; break; // duration in seconds TODO: emit [hh]:[mm] style format with adjusted value
case 7: ret = { t: "n", v: ieee / 86400 }; break; // duration in seconds TODO: emit [hh]:[mm] style format with adjusted value
case 8: ret = { t: "e", v: 0}; break; // "formula error" TODO: enumerate and map errors to csf equivalents
case 9: { // "automatic"?
if(ridx > -1) ret = { t: "s", v: rsst[ridx] };
@ -358,12 +404,40 @@ function parse_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObje
return ret;
}
function write_new_storage(cell: CellObject, sst: string[]): Uint8Array {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 5;
switch(cell.t) {
case "n": out[1] = 2; writeDecimal128LE(out, l, cell.v as number); flags |= 1; l += 16; break;
case "b": out[1] = 6; dv.setFloat64(l, cell.v ? 1 : 0, true); flags |= 2; l += 8; break;
case "s":
if(sst.indexOf(cell.v as string) == -1) throw new Error(`Value ${cell.v} missing from SST!`);
out[1] = 3; dv.setUint32(l, sst.indexOf(cell.v as string), true); flags |= 8; l += 4; break;
default: throw "unsupported cell type " + cell.t;
}
dv.setUint32(8, flags, true);
return out.slice(0, l);
}
function write_old_storage(cell: CellObject, sst: string[]): Uint8Array {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 3;
switch(cell.t) {
case "n": out[2] = 2; dv.setFloat64(l, cell.v as number, true); flags |= 0x20; l += 8; break;
case "b": out[2] = 6; dv.setFloat64(l, cell.v ? 1 : 0, true); flags |= 0x20; l += 8; break;
case "s":
if(sst.indexOf(cell.v as string) == -1) throw new Error(`Value ${cell.v} missing from SST!`);
out[2] = 3; dv.setUint32(l, sst.indexOf(cell.v as string), true); flags |= 0x10; l += 4; break;
default: throw "unsupported cell type " + cell.t;
}
dv.setUint32(4, flags, true);
return out.slice(0, l);
}
//<<export { write_new_storage, write_old_storage };
function parse_cell_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObject {
switch(buf[0]) {
case 0: case 1:
case 2: case 3: return parse_old_storage(buf, sst, rsst, buf[0]);
case 5: return parse_storage(buf, sst, rsst);
case 5: return parse_new_storage(buf, sst, rsst);
default: throw new Error(`Unsupported payload version ${buf[0]}`);
}
}
@ -378,6 +452,12 @@ function parse_TSP_Reference(buf: Uint8Array): number {
var pb = parse_shallow(buf);
return parse_varint49(pb[1][0].data);
}
function write_TSP_Reference(idx: number): Uint8Array {
var out: ProtoMessage = [];
out[1] = [ { type: 0, data: write_varint49(idx) } ];
return write_shallow(out)
}
//<<export { parse_TSP_Reference, write_TSP_Reference };
type MessageSpace = {[id: number]: IWAMessage[]};
@ -446,7 +526,7 @@ function parse_TST_TileRowInfo(u8: Uint8Array, type: TileStorageType): TileRowIn
var cells: Uint8Array[] = [];
for(C = 0; C < offsets.length - 1; ++C) cells[offsets[C][0]] = used_storage.subarray(offsets[C][1] * width, offsets[C+1][1] * width);
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
if(offsets.length >= 1) cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
return { R, cells };
}
@ -472,7 +552,7 @@ function parse_TST_Tile(M: MessageSpace, root: IWAMessage): TileInfo {
};
}
/** .TST.TableModelArchive */
/** .TST.TableModelArchive (6001) */
function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: WorkSheet) {
var pb = parse_shallow(root.data);
var range: Range = { s: {r:0, c:0}, e: {r:0, c:0} };
@ -509,7 +589,7 @@ function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: Work
});
}
/** .TST.TableInfoArchive */
/** .TST.TableInfoArchive (6000) */
function parse_TST_TableInfoArchive(M: MessageSpace, root: IWAMessage): WorkSheet {
var pb = parse_shallow(root.data);
var out: WorkSheet = { "!ref": "A1" };
@ -524,7 +604,7 @@ interface NSheet {
name: string;
sheets: WorkSheet[];
}
/** .TN.SheetArchive */
/** .TN.SheetArchive (2) */
function parse_TN_SheetArchive(M: MessageSpace, root: IWAMessage): NSheet {
var pb = parse_shallow(root.data);
var out: NSheet = {
@ -570,7 +650,7 @@ function parse_TN_DocumentArchive(M: MessageSpace, root: IWAMessage): WorkBook {
/** Parse NUMBERS file */
function parse_numbers_iwa(cfb: CFB$Container): WorkBook {
var out: MessageSpace = {}, indices: number[] = [];
var M: MessageSpace = {}, indices: number[] = [];
cfb.FullPaths.forEach(p => { if(p.match(/\.iwpv2/)) throw new Error(`Unsupported password protection`); });
/* collect entire message space */
@ -580,14 +660,14 @@ function parse_numbers_iwa(cfb: CFB$Container): WorkBook {
try { o = decompress_iwa_file(s.content as Uint8Array); } catch(e) { return console.log("?? " + s.content.length + " " + (e.message || e)); }
var packets: IWAArchiveInfo[];
try { packets = parse_iwa_file(o); } catch(e) { return console.log("## " + (e.message || e)); }
packets.forEach(packet => { out[packet.id] = packet.messages; indices.push(packet.id); });
packets.forEach(packet => { M[packet.id] = packet.messages; indices.push(packet.id); });
});
if(!indices.length) throw new Error("File has no messages");
/* find document root */
var docroot: IWAMessage = out?.[1]?.[0]?.meta?.[1]?.[0].data && varint_to_i32(out[1][0].meta[1][0].data) == 1 && out[1][0];
var docroot: IWAMessage = M?.[1]?.[0]?.meta?.[1]?.[0].data && varint_to_i32(M[1][0].meta[1][0].data) == 1 && M[1][0];
if(!docroot) indices.forEach((idx) => {
out[idx].forEach((iwam) => {
M[idx].forEach((iwam) => {
var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0;
if(mtype == 1) {
if(!docroot) docroot = iwam;
@ -596,7 +676,310 @@ function parse_numbers_iwa(cfb: CFB$Container): WorkBook {
});
});
if(!docroot) throw new Error("Cannot find Document root");
return parse_TN_DocumentArchive(out, docroot);
return parse_TN_DocumentArchive(M, docroot);
}
//<<export { parse_numbers_iwa };
interface DependentInfo {
deps: number[];
location: string;
type: number;
}
function write_tile_row(tri: ProtoMessage, data: any[], SST: string[]): number {
if(!tri[6]?.[0] || !tri[7]?.[0]) throw "Mutation only works on post-BNC storages!";
var wide_offsets = tri[8]?.[0]?.data && varint_to_i32(tri[8][0].data) > 0 || false;
if(wide_offsets) throw "Math only works with normal offsets";
var cnt = 0;
var dv = u8_to_dataview(tri[7][0].data), last_offset = 0, cell_storage: Uint8Array[] = [];
var _dv = u8_to_dataview(tri[4][0].data), _last_offset = 0, _cell_storage: Uint8Array[] = [];
for(var C = 0; C < data.length; ++C) {
if(data[C] == null) { dv.setUint16(C*2, 0xFFFF, true); _dv.setUint16(C*2, 0xFFFF); continue; }
dv.setUint16(C*2, last_offset, true);
_dv.setUint16(C*2, _last_offset, true);
var celload: Uint8Array, _celload: Uint8Array;
switch(typeof data[C]) {
case "string":
celload = write_new_storage({t: "s", v: data[C]}, SST);
_celload = write_old_storage({t: "s", v: data[C]}, SST);
break;
case "number":
celload = write_new_storage({t: "n", v: data[C]}, SST);
_celload = write_old_storage({t: "n", v: data[C]}, SST);
break;
case "boolean":
celload = write_new_storage({t: "b", v: data[C]}, SST);
_celload = write_old_storage({t: "b", v: data[C]}, SST);
break;
default: throw new Error("Unsupported value " + data[C]);
}
cell_storage.push(celload); last_offset += celload.length;
_cell_storage.push(_celload); _last_offset += _celload.length;
++cnt;
}
tri[2][0].data = write_varint49(cnt);
for(; C < tri[7][0].data.length/2; ++C) {
dv.setUint16(C*2, 0xFFFF, true);
_dv.setUint16(C*2, 0xFFFF, true);
}
tri[6][0].data = u8concat(cell_storage);
tri[3][0].data = u8concat(_cell_storage);
return cnt;
}
function write_numbers_iwa(wb: WorkBook, opts: any): CFB$Container {
if(!opts || !opts.numbers) throw new Error("Must pass a `numbers` option -- check the README");
/* TODO: support multiple worksheets, larger ranges, more data types, etc */
var ws = wb.Sheets[wb.SheetNames[0]];
if(wb.SheetNames.length > 1) console.error("The Numbers writer currently writes only the first table");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
if(range.e.c > 9) { trunc = true; range.e.c = 9; }
if(range.e.r > 49) { trunc = true; range.e.r = 49; }
if(trunc) console.error(`The Numbers writer is currently limited to ${encode_range(range)}`);
var data = sheet_to_json<any>(ws, { range, header: 1 });
var SST = ["~Sh33tJ5~"];
data.forEach(row => row.forEach(cell => { if(typeof cell == "string") SST.push(cell); }))
var dependents: {[x:number]: DependentInfo} = {};
var indices: number[] = [];
var cfb: CFB$Container = CFB.read(opts.numbers, { type: "base64" });
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(fi.type != 2) return;
if(!fi.name.match(/\.iwa/)) return;
/* Reframe .iwa files */
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content as Uint8Array);
var x = parse_iwa_file(raw1);
x.forEach(packet => {
indices.push(packet.id);
dependents[packet.id] = { deps: [], location: fp, type: varint_to_i32(packet.messages[0].meta[1][0].data) };
});
});
indices.sort((x,y) => x-y);
var indices_varint: Array<[number, Uint8Array]> = indices.filter(x => x > 1).map(x => [x, write_varint49(x)] );
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(!fi.name.match(/\.iwa/)) return;
var x = parse_iwa_file(decompress_iwa_file(fi.content as Uint8Array));
x.forEach(ia => {
ia.messages.forEach(m => {
indices_varint.forEach(ivi => {
if(ia.messages.some(mess => varint_to_i32(mess.meta[1][0].data) != 11006 && u8contains(mess.data, ivi[1]))) {
dependents[ivi[0]].deps.push(ia.id);
}
})
});
});
});
function get_unique_msgid() {
for(var i = 927262; i < 2000000; ++i) if(!dependents[i]) return i;
throw new Error("Too many messages");
}
/* .TN.DocumentArchive */
var entry = CFB.find(cfb, dependents[1].location);
var x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
var docroot: IWAArchiveInfo;
for(var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == 1) docroot = packet;
}
/* .TN.SheetArchive */
var sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[1][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
/* .TST.TableInfoArchive */
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
/* .TST.TableModelArchive */
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
var pb = parse_shallow(docroot.messages[0].data);
{
pb[6][0].data = write_varint49(range.e.r + 1);
pb[7][0].data = write_varint49(range.e.c + 1);
// pb[22] = [ { type: 0, data: write_varint49(1) } ]; // enables table display
var cruidsref = parse_TSP_Reference(pb[46][0].data);
var oldbucket = CFB.find(cfb, dependents[cruidsref].location);
var _x = parse_iwa_file(decompress_iwa_file(oldbucket.content as Uint8Array));
{
for(var j = 0; j < _x.length; ++j) {
if(_x[j].id == cruidsref) break;
}
if(_x[j].id != cruidsref) throw "Bad ColumnRowUIDMapArchive";
var cruids = parse_shallow(_x[j].messages[0].data);
cruids[1] = []; cruids[2] = [], cruids[3] = [];
for(var C = 0; C <= range.e.c; ++C) {
var uuid: ProtoMessage = [];
uuid[1] = uuid[2] = [ { type: 0, data: write_varint49(C + 420690) } ]
cruids[1].push({type: 2, data: write_shallow(uuid)})
cruids[2].push({type: 0, data: write_varint49(C)});
cruids[3].push({type: 0, data: write_varint49(C)});
}
cruids[4] = []; cruids[5] = [], cruids[6] = [];
for(var R = 0; R <= range.e.r; ++R) {
uuid = [];
uuid[1] = uuid[2] = [ { type: 0, data: write_varint49(R + 726270)} ];
cruids[4].push({type: 2, data: write_shallow(uuid)})
cruids[5].push({type: 0, data: write_varint49(R)});
cruids[6].push({type: 0, data: write_varint49(R)});
}
_x[j].messages[0].data = write_shallow(cruids);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x)); oldbucket.size = oldbucket.content.length;
delete pb[46];
var store = parse_shallow(pb[4][0].data);
{
store[7][0].data = write_varint49(range.e.r + 1);
var row_headers = parse_shallow(store[1][0].data);
var row_header_ref = parse_TSP_Reference(row_headers[2][0].data);
oldbucket = CFB.find(cfb, dependents[row_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content as Uint8Array));
{
if(_x[0].id != row_header_ref) throw "Bad HeaderStorageBucket";
var base_bucket = parse_shallow(_x[0].messages[0].data);
for(R = 0; R < data.length; ++R) {
var _bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(R);
_bucket[4][0].data = write_varint49(data[R].length);
base_bucket[2][R] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x)); oldbucket.size = oldbucket.content.length;
var col_header_ref = parse_TSP_Reference(store[2][0].data);
oldbucket = CFB.find(cfb, dependents[col_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content as Uint8Array));
{
if(_x[0].id != col_header_ref) throw "Bad HeaderStorageBucket";
base_bucket = parse_shallow(_x[0].messages[0].data);
for(C = 0; C <= range.e.c; ++C) {
_bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(C);
_bucket[4][0].data = write_varint49(range.e.r + 1);
base_bucket[2][C] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x)); oldbucket.size = oldbucket.content.length;
/* ref to string table */
var sstref = parse_TSP_Reference(store[4][0].data);
(() => {
var sentry = CFB.find(cfb, dependents[sstref].location);
var sx = parse_iwa_file(decompress_iwa_file(sentry.content as Uint8Array));
var sstroot: IWAArchiveInfo;
for(var sxi = 0; sxi < sx.length; ++sxi) {
var packet = sx[sxi];
if(packet.id == sstref) sstroot = packet;
}
var sstdata = parse_shallow(sstroot.messages[0].data);
{
sstdata[3] = [];
var newsst: ProtoMessage = [];
SST.forEach((str, i) => {
newsst[1] = [ { type: 0, data: write_varint49(i) } ];
newsst[2] = [ { type: 0, data: write_varint49(1) } ];
newsst[3] = [ { type: 2, data: stru8(str) } ];
sstdata[3].push({type: 2, data: write_shallow(newsst)});
});
}
sstroot.messages[0].data = write_shallow(sstdata);
var sy = write_iwa_file(sx);
var raw3 = compress_iwa_file(sy);
sentry.content = raw3; sentry.size = sentry.content.length;
})();
var tile = parse_shallow(store[3][0].data); // TileStorage
{
var t = tile[1][0];
delete tile[2];
var tl = parse_shallow(t.data); // first Tile
{
var tileref = parse_TSP_Reference(tl[2][0].data);
(() => {
var tentry = CFB.find(cfb, dependents[tileref].location);
var tx = parse_iwa_file(decompress_iwa_file(tentry.content as Uint8Array));
var tileroot: IWAArchiveInfo;
for(var sxi = 0; sxi < tx.length; ++sxi) {
var packet = tx[sxi];
if(packet.id == tileref) tileroot = packet;
}
// .TST.Tile
var tiledata = parse_shallow(tileroot.messages[0].data);
{
delete tiledata[6]; delete tile[7];
var rowload = new Uint8Array(tiledata[5][0].data);
tiledata[5] = [];
var cnt = 0;
for(var R = 0; R <= range.e.r; ++R) {
var tilerow = parse_shallow(rowload);
cnt += write_tile_row(tilerow, data[R], SST);
tilerow[1][0].data = write_varint49(R);
tiledata[5].push({data: write_shallow(tilerow), type: 2});
}
tiledata[1] = [{type: 0, data: write_varint49(range.e.c + 1)}];
tiledata[2] = [{type: 0, data: write_varint49(range.e.r + 1)}];
tiledata[3] = [{type: 0, data: write_varint49(cnt)}];
tiledata[4] = [{type: 0, data: write_varint49(range.e.r + 1)}];
}
tileroot.messages[0].data = write_shallow(tiledata);
var ty = write_iwa_file(tx);
var raw3 = compress_iwa_file(ty);
tentry.content = raw3; tentry.size = tentry.content.length;
//throw dependents[tileref];
})();
}
t.data = write_shallow(tl);
}
store[3][0].data = write_shallow(tile);
}
pb[4][0].data = write_shallow(store);
}
docroot.messages[0].data = write_shallow(pb);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
entry.content = raw3; entry.size = entry.content.length;
return cfb;
}

View File

@ -6,13 +6,16 @@ ENTRIES=$(subst .ts,.js,$(TSFILES))
BAREJS=04_base64.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js 83_numbers.js
.PHONY: all
all: $(ENTRIES)
all: $(ENTRIES) xlsx.zahl.js
xlsx.zahl.js: test.numbers reframe.node.js
bash -c ./reframe.sh
$(BAREJS): %.js: %.ts $(LIBFILES)
npx esbuild $< --outfile=$@ --platform=browser --target=es5
%.node.js: %.node.ts $(LIBFILES) src/numbers.ts
npx esbuild $< --bundle --external:xlsx --outfile=$@ --minify --platform=node
npx esbuild $< --bundle --external:xlsx --outfile=$@ --platform=node
sed -i '' 's/ts-node/node/g' $@
%.js: %.ts $(LIBFILES)

View File

@ -1,13 +1,22 @@
/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
import { decompress_iwa_file, compress_iwa_file, u8concat } from "./src/numbers";
import { read, writeFile, utils, find, CFB$Entry } from 'cfb';
import { decompress_iwa_file, compress_iwa_file, u8concat, parse_iwa_file, write_iwa_file, varint_to_i32, parse_shallow, write_shallow, u8str, stru8, IWAArchiveInfo, parse_TSP_Reference, write_varint49, u8contains, u8_to_dataview, write_new_storage } from "./src/numbers";
import { read, writeFile, utils, find, CFB$Entry, CFB$Container } from 'cfb';
var f = process.argv[2]; var o = process.argv[3];
var cfb = read(f, {type: "file"});
var FI = cfb.FileIndex;
var bufs = [], mode = 0;
FI.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var nuevo = utils.cfb_new();
interface DependentInfo {
deps: number[];
location: string;
type: number;
}
var dependents: {[x:number]: DependentInfo} = {};
var indices: number[] = [];
/* First Pass: reframe, clean up junk, collect message space */
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
/* blank all plist files */
if(fi.name.match(/\.plist/)) {
@ -17,6 +26,7 @@ FI.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a
]);
utils.cfb_add(nuevo, row[1], fi.content);
return;
}
@ -26,28 +36,596 @@ FI.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row
if(!fi.name.match(/\.iwa/)) {
if(fi.name.match(/Sh33tJ5/)) return;
console.error(`Removing file ${fi.name}`);
utils.cfb_del(cfb, fp);
return;
}
/* Reframe .iwa files */
console.error(`Reframing iwa ${fi.name} (${fi.size})`);
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content as Uint8Array);
var new_content = compress_iwa_file(raw1);
var raw2 = decompress_iwa_file(new_content);
for(var i = 0; i < raw1.length; ++i) if(raw1[i] != raw2[i]) throw new Error(`${fi.name} did not properly roundtrip`);
bufs.push(raw1);
switch(mode) {
case 1: utils.cfb_del(cfb, fp); break;
/* falls through */
case 0: fi.content = new_content; break;
var x = parse_iwa_file(raw2);
x.forEach(ia => {
ia.messages.forEach(m => {
delete m.meta[2];
delete m.meta[4];
delete m.meta[5]; // extremely slow open if deleted
for(var j = 6; j < m.meta.length; ++j) delete m.meta[j];
});
});
x.forEach(packet => {
indices.push(packet.id);
dependents[packet.id] = { deps: [], location: fp, type: varint_to_i32(packet.messages[0].meta[1][0].data) };
});
var y = write_iwa_file(x);
for(var i = 0; i < raw1.length; ++i) if(y[i] != raw1[i]) { console.log(fi.name, i, raw1[i], y[i]); break; }
var raw3 = compress_iwa_file(y);
fi.content = raw3; fi.size = fi.content.length;
// utils.cfb_add(nuevo, row[1], fi.content);
});
indices.sort((x,y) => x-y);
var indices_varint: Array<[number, Uint8Array]> = indices.filter(x => x > 1).map(x => [x, write_varint49(x)] );
/* Second pass: build dependency map */
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(!fi?.name?.match(/\.iwa/)) return;
var x = parse_iwa_file(decompress_iwa_file(fi.content as Uint8Array));
x.forEach(ia => {
ia.messages.forEach(m => {
indices_varint.forEach(([i, vi]) => {
if(ia.messages.some(mess => varint_to_i32(mess.meta[1][0].data) != 11006 && u8contains(mess.data, vi))) {
dependents[i].deps.push(ia.id);
}
})
});
});
});
var deletables = [];
function delete_message(id: number, cfb: CFB$Container) {
var dep = dependents[id];
if(dep?.deps?.length > 0) return console.error(`Message ${id} has dependents ${dep.deps}`);
//delete dependents[id];
indices = indices.filter(x => x != id);
/* TODO: this really should be a forward map */
indices.map(i => dependents[i]).filter(x => x).forEach(dep => {
dep.deps = dep.deps.filter(x => x != id);
});
if(deletables.indexOf(id) == -1) deletables.push(id);
}
function gc(cfb: CFB$Container) {
deletables.forEach(id => {
var dep = dependents[id];
var entry = find(cfb, dep.location);
var x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
/* remove packet */
console.log(`Removing packet ${id} ${dependents[id]?.type || "NaN"}`);
for(var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == id) { x.splice(xi,1); --xi; }
}
delete dependents[id];
entry.content = compress_iwa_file(write_iwa_file(x));
entry.size = entry.content.length;
});
deletables = [];
}
function delete_ref(dmeta: ReturnType<typeof parse_shallow>, j: number, me: number) {
if(!dmeta) return;
if(dmeta[j]) dmeta[j].forEach(pi => {
var target = parse_TSP_Reference(pi.data);
dependents[target].deps = dependents[target].deps.filter(x => x != me);
if(dependents[target].deps.length == 0) delete_message(target, cfb);
});
delete dmeta[j];
}
function shake() {
var done = false;
while(!done) {
done = true;
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(fi.name.match(/\.plist/)) return;
if(!fi.name.match(/\.iwa/)) return;
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content as Uint8Array);
var x = parse_iwa_file(raw1);
(()=>{
for(var i = 0; i < x.length; ++i) {
var w = x[i];
var type = varint_to_i32(w.messages[0].meta[1][0].data);
if(w.id > 10000 && (!dependents[w.id] || !dependents[w.id]?.deps?.length)) {
console.log(`Deleting orphan ${fp} ${w.id}`);
delete_message(w.id, cfb);
done = false;
}
}
})();
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
//fi.content = raw3;
});
gc(cfb);
}
}
/* Third pass: trim messages */
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(!fi?.name?.match(/\.iwa/)) return;
var x = parse_iwa_file(decompress_iwa_file(fi.content as Uint8Array));
trim(x, fi);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
fi.content = raw3;
});
gc(cfb);
shake();
function mutate_row(tri: ReturnType<typeof parse_shallow>) {
if(!tri[6]?.[0] || !tri[7]?.[0]) throw "Mutation only works on post-BNC storages!";
var wide_offsets = tri[8]?.[0]?.data && varint_to_i32(tri[8][0].data) > 0 || false;
if(wide_offsets) throw "Math only works with normal offsets";
var dv = u8_to_dataview(tri[7][0].data);
var old_sz = 0, sz = 0;
for(var i = 0; i < tri[7][0].data.length / 2; ++i) {
sz = dv.getUint16(i*2, true);
if(sz < 65535) old_sz = sz;
if(old_sz) break;
}
if(!old_sz) old_sz = sz = tri[6][0].data.length;
var start = 0,
preamble = tri[6][0].data.slice(0, start),
intramble = tri[6][0].data.slice(start, old_sz),
postamble = tri[6][0].data.slice(old_sz);
var sst = []; sst[69] = "SheetJS";
//intramble = write_new_storage({t:"n", v:12345}, sst);
//intramble = write_new_storage({t:"b", v:false}, sst);
intramble = write_new_storage({t:"s", v:"SheetJS"}, sst);
tri[6][0].data = u8concat([preamble, intramble, postamble]);
var delta = intramble.length - old_sz;
for(var i = 0; i < tri[7][0].data.length / 2; ++i) {
sz = dv.getUint16(i*2, true);
if(sz < 65535 && sz > start) dv.setUint16(i*2, sz + delta, true);
}
}
/* Find first sheet -> first table -> add "SheetJS" to data store and set cell A1 */
(function() {
var entry = find(cfb, dependents[1].location);
var x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
var docroot: IWAArchiveInfo;
for(var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == 1) docroot = packet;
}
var sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[1][0].data);
entry = find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
var pb = parse_shallow(docroot.messages[0].data);
{
var store = parse_shallow(pb[4][0].data);
{
/* ref to string table */
var sstref = parse_TSP_Reference(store[4][0].data);
(() => {
var sentry = find(cfb, dependents[sstref].location);
var sx = parse_iwa_file(decompress_iwa_file(sentry.content as Uint8Array));
var sstroot: IWAArchiveInfo;
for(var sxi = 0; sxi < sx.length; ++sxi) {
var packet = sx[sxi];
if(packet.id == sstref) sstroot = packet;
}
var sstdata = parse_shallow(sstroot.messages[0].data);
{
if(!sstdata[3]) sstdata[3] = [];
var newsst: ReturnType<typeof parse_shallow> = [];
newsst[1] = [ { type: 0, data: write_varint49(69) } ];
newsst[2] = [ { type: 0, data: write_varint49(1) } ];
newsst[3] = [ { type: 2, data: stru8("SheetJS") } ];
sstdata[3].push({type: 2, data: write_shallow(newsst)});
}
sstroot.messages[0].data = write_shallow(sstdata);
var sy = write_iwa_file(sx);
var raw3 = compress_iwa_file(sy);
sentry.content = raw3; sentry.size = sentry.content.length;
})();
var tile = parse_shallow(store[3][0].data); // TileStorage
{
var t = tile[1][0];
delete tile[2];
var tl = parse_shallow(t.data); // first Tile
{
var tileref = parse_TSP_Reference(tl[2][0].data);
(() => {
var tentry = find(cfb, dependents[tileref].location);
var tx = parse_iwa_file(decompress_iwa_file(tentry.content as Uint8Array));
var tileroot: IWAArchiveInfo;
for(var sxi = 0; sxi < tx.length; ++sxi) {
var packet = tx[sxi];
if(packet.id == tileref) tileroot = packet;
}
// .TST.Tile
var tiledata = parse_shallow(tileroot.messages[0].data);
{
tiledata[5].forEach((row, R) => {
var tilerow = parse_shallow(row.data);
if(R == 0) mutate_row(tilerow);
row.data = write_shallow(tilerow);
})
}
tileroot.messages[0].data = write_shallow(tiledata);
var ty = write_iwa_file(tx);
var raw3 = compress_iwa_file(ty);
tentry.content = raw3; tentry.size = tentry.content.length;
//throw dependents[tileref];
})();
}
t.data = write_shallow(tl);
}
store[3][0].data = write_shallow(tile);
}
pb[4][0].data = write_shallow(store);
}
docroot.messages[0].data = write_shallow(pb);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
entry.content = raw3; entry.size = entry.content.length;
})();
//console.log(indices.map(i => [i, dependents[i]]).filter(([i, dep]) => dep?.deps && (dep.deps.length == 0 || dep.deps.length == 1 && dep.deps[0] == 1)));
/* Last pass: fix metadata and commit to new file */
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(!fi?.name?.match(/\.iwa/)) return;
var x = parse_iwa_file(decompress_iwa_file(fi.content as Uint8Array));
if(fi.name.match(/^Metadata.iwa$/)) {
x.forEach((w: IWAArchiveInfo) => {
var type = varint_to_i32(w.messages[0].meta[1][0].data);
if(type != 11006) return;
var package_metadata = parse_shallow(w.messages[0].data);
[3,11].forEach(x => {
if(!package_metadata[x]) return;
for(var pmj = 0; pmj < package_metadata[x].length; ++pmj) {
var ci = package_metadata[x][pmj];
var comp = parse_shallow(ci.data);
var compid = varint_to_i32(comp[1][0].data);
if(!dependents[compid]) {
console.log(`Removing ${compid} (${u8str(comp[2][0].data)} -> ${comp[3]?.[0] && u8str(comp[3][0].data) || ""}) from metadata`);
package_metadata[x].splice(pmj, 1);
--pmj; continue;
}
[13, 14, 15].forEach(j => delete comp[j]);
ci.data = write_shallow(comp);
}
});
[2, 4, 6, 8, 9].forEach(j => delete package_metadata[j]);
w.messages[0].data = write_shallow(package_metadata);
});
}
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
fi.content = raw3;
if(x.length == 0) {
console.log(`Deleting ${fi.name} (no messages)`);
return;
}
if(fi.name.match(/^Metadata.iwa$/)) {
console.error(`Reframing iwa ${fi.name} (${fi.size} -> ${fi.content.length})`);
fi.size = fi.content.length;
utils.cfb_add(nuevo, row[1], fi.content);
} else {
console.error(`Reframing iwa ${fi.name} (${fi.size} -> ${fi.content.length})`);
fi.size = fi.content.length;
utils.cfb_add(nuevo, row[1], fi.content);
}
});
if(mode == 1) {
var res = compress_iwa_file(u8concat(bufs));
console.error(`Adding iwa Document.iwa (${res.length})`);
utils.cfb_add(cfb, "/Index/Document.iwa", res);
writeFile(nuevo, o, { fileType: "zip", compression: true });
function process_root(dmeta: ReturnType<typeof parse_shallow>, id: number) {
var tsa = parse_shallow(dmeta[8][0].data);
{
var tsk = parse_shallow(tsa[1][0].data);
{
[7, 8, 14].forEach(j => delete_ref(tsk, j, id)); // annotation_author_storage
[4, 9, 10, 11, 12, 15, 16, 17].forEach(j => delete tsk[j]);
}
tsa[1][0].data = write_shallow(tsk);
[5, 6, 7, 10, 11, 12, 13].forEach(j => delete_ref(tsa, j, 1));
[3, 8, 9, 14, 15, 16].forEach(j => delete tsa[j]);
}
dmeta[8][0].data = write_shallow(tsa);
}
writeFile(cfb, o, {fileType: "zip"});
function process_sheet(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 20, 21, 23, 24].forEach(j => delete dmeta[j]);
[15, 16, 17, 18, 19, 22].forEach(j => delete_ref(dmeta, j, id));
}
function process_TST_TableInfoArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[7, 8, 9, 10, 14, 16].forEach(j => delete dmeta[j]);
[3, 4, 5, 6, 15, 17].forEach(j => delete_ref(dmeta, j, id));
}
function process_TST_TableModelArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[90, 91, 92].forEach(j => delete dmeta[j]);
[34, 35, 38, 49].forEach(j => delete_ref(dmeta, j, id));
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69].forEach(j => delete_ref(dmeta, j, id));
[70].forEach(j => delete dmeta[j]);
[71, 72, 73, 74, 75, 76, 77, 78, 79, 80].forEach(j => delete_ref(dmeta, j, id));
[85, 86, 87, 88, 89].forEach(j => delete_ref(dmeta, j, id));
var store = parse_shallow(dmeta[4][0].data);
{ // .TST.DataStore
[12, 13, 15, 16, 17, 18, 19, 20, 21, 22].forEach(j => delete_ref(store, j, id));
var tiles = parse_shallow(store[3][0].data);
{ // .TST.TileStorage
//console.log(parse_TSP_Reference(parse_shallow(tiles[1][0].data)[2][0].data));
}
store[3][0].data = write_shallow(tiles);
// 4 -> sst
// 17 -> rsst
}
dmeta[4][0].data = write_shallow(store);
}
function process_TN_ThemeArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[2].forEach(j => delete_ref(dmeta, j, id));
var tssta = parse_shallow(dmeta[1][0].data);
{
//Object.keys(tssta).filter(x => +x >= 100).forEach(j => delete tssta[j]);
}
dmeta[1][0].data = write_shallow(tssta);
}
function process_TSS_StylesheetArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[7, 8, 9, 10, 11, 12].forEach(j => {
if(!dmeta[j]) return;
var vstyle = parse_shallow(dmeta[j][0].data);
delete_ref(vstyle, 1, id);
if(vstyle[2]) vstyle[2].forEach(ised => {
var ise = parse_shallow(ised.data);
delete_ref(ise, 2, id);
})
if(vstyle[3]) vstyle[3].forEach(sced => {
var sce = parse_shallow(sced.data);
delete_ref(sce, 2, id);
delete_ref(sce, 1, id);
})
delete dmeta[j];
});
dmeta[4] = [{data: write_varint49(0), type: 0}];
[3].forEach(j => delete_ref(dmeta, j, id));
dmeta[5]?.forEach(pi => {
var sce = parse_shallow(pi.data);
delete_ref(sce, 1, id);
delete_ref(sce, 2, id);
}); delete dmeta[5];
var deleted_styles = [];
if(dmeta[2]) for(var pij = 0; pij < dmeta[2].length; ++pij) {
var ise = parse_shallow(dmeta[2][pij].data);
var sname = u8str(ise[1][0].data);
if(sname.match(/_\d*$/) || sname.match(/^(captions|chart|image|movie|stickyComment)/) || sname.match(/evel[2-5]|pivot|liststyle/) ) {
var deletedid = parse_TSP_Reference(ise[2][0].data);
console.log(`Deleting style ${sname} [${deletedid}]`);
deleted_styles.push(deletedid);
delete_ref(ise, 2, id);
dmeta[2].splice(pij,1);
--pij; continue;
} else console.log(`Keeping style ${sname}`)
}
if(dmeta[1]) for(var sj = 0; sj < dmeta[1].length; ++sj) {
var dsid = parse_TSP_Reference(dmeta[1][sj].data);
if(deleted_styles.indexOf(dsid) > -1) {
//console.log(`Really deleting style ${dsid}`);
dependents[dsid].deps = dependents[dsid].deps.filter(x => x != id);
if(dependents[dsid].deps.length == 0) delete_message(dsid, cfb);
dmeta[1].splice(sj, 1); --sj; continue;
}
}
[6].forEach(j => delete dmeta[j]);
}
function process_TSCE_CalculationEngineArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[3, 12, 14, 15].forEach(j => delete_ref(dmeta, j, id));
[1, 4, 5, 6, 7, 9, 10, 11, 13, 16, 17, 18].forEach(i => delete dmeta[i]);
var dta = parse_shallow(dmeta[2][0].data);
delete dta[5]; delete dta[2]; delete dta[4];
delete dta[1]; delete dta[3]; delete_ref(dta, 6, id);
dmeta[2][0].data = write_shallow(dta);
}
function trim(x: IWAArchiveInfo[], fi: CFB$Entry) {
for(var i = 0; i < x.length; ++i) {
var w = x[i];
var type = varint_to_i32(w.messages[0].meta[1][0].data);
var dmeta = parse_shallow(w.messages[0].data);
switch(type) {
case 222: // .TSK.CustomFormatListArchive
case 601: // .TSA.FunctionBrowserStateArchive
x.splice(i, 1); --i; continue;
case 3047: break; // .TSD.GuideStorageArchive
case 205: {
} break; // .TSK.TreeNode
case 1: { // .TN.DocumentArchive
process_root(dmeta, w.id);
} break;
case 2: { // .TN.SheetArchive
process_sheet(dmeta, w.id);
} break;
case 6000: { // .TST.TableInfoArchive
process_TST_TableInfoArchive(dmeta, w.id);
} break;
case 6001: { // .TST.TableModelArchive
process_TST_TableModelArchive(dmeta, w.id)
} break;
case 401: { // .TSS.StylesheetArchive
process_TSS_StylesheetArchive(dmeta, w.id);
break;
}
case 11011: { // .TSP.DocumentMetadata
[1, 3].forEach(i => delete dmeta[i]);
} break;
case 6002: {
//process_TST_Tile(dmeta, w.id);
} break; // .TST.Tile
case 6005: break; // .TST.TableDataList
case 6006: break; // .TST.HeaderStorageBucket
case 2001: break; // .TSWP.StorageArchive
case 12009: process_TN_ThemeArchive(dmeta, w.id); break; // .TN.ThemeArchive
case 3097: break; // .TSD.StandinCaptionArchive
case 4000: process_TSCE_CalculationEngineArchive(dmeta, w.id); break; // .TSCE.CalculationEngineArchive
case 4003: break; // .TSCE.NamedReferenceManagerArchive
case 4004: break; // .TSCE.TrackedReferenceStoreArchive
case 4008: { // .TSCE.FormulaOwnerDependenciesArchive
[11].forEach(j => delete_ref(dmeta, j, w.id));
[3].forEach(i => delete dmeta[i]);
} break;
case 4009: { // .TSCE.CellRecordTileArchive
delete dmeta[4];
} break;
case 6267: { // .TST.ColumnRowUIDMapArchive
// console.log("CRUIDMA", dmeta[1]?.[0], dmeta[2]?.[0], dmeta[3]?.[0]);
//[1,2,3,4,5,6].forEach(j => delete dmeta[j]); break;
} break;
case 6366: break; // .TST.HeaderNameMgrArchive
case 6204: break; // .TST.HiddenStateFormulaOwnerArchive
case 6220: break; // .TST.FilterSetArchive
case 6305: break; // .TST.StrokeSidecarArchive
case 6316: break; // .TST.SummaryModelArchive
case 6317: break; // .TST.SummaryCellVendorArchive
case 6318: break; // .TST.CategoryOrderArchive
case 6372: break; // .TST.CategoryOwnerRefArchive
case 6373: break; // .TST.GroupByArchive
case 2043: [2,3,4].forEach(j => delete dmeta[j]); break; // .TSWP.NumberAttachmentArchive
case 5020: // .TSCH.ChartStylePreset
//[1,2,3,4,5,6].forEach(j => delete_ref(dmeta, j, w.id)); // some part of this is required to auto-save
Object.keys(dmeta).filter(x => +x >= 10000).forEach(j => delete dmeta[j]);
break;
case 5022: // .TSCH.ChartStyleArchive
case 5024: // .TSCH.LegendStyleArchive
case 5026: // .TSCH.ChartAxisStyleArchive
case 5028: // .TSCH.ChartSeriesStyleArchive
case 5030: // .TSCH.ReferenceLineStyleArchive
Object.keys(dmeta).filter(x => +x >= 10000).forEach(j => delete dmeta[j]);
break;
case 2021: break;
case 2022: [10,11,12].forEach(j => delete dmeta[j]); break; // .TSWP.ParagraphStyleArchive
case 2023: [10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25].forEach(j => delete dmeta[j]); break; // .TSWP.ListStyleArchive
case 3016: [10,11].forEach(j => delete dmeta[j]); break; // .TSD.MediaStyleArchive
case 2025: /* [10,11].forEach(j => delete dmeta[j]); */ break; // .TSWP.ShapeStyleArchive
case 6003: /* [10,11].forEach(j => delete dmeta[j]); */ break; // .TST.TableStyleArchive
case 6004: /* [10,11].forEach(j => delete dmeta[j]); */ break; // .TST.CellStyleArchive
case 10024: [10,11,12].forEach(j => delete dmeta[j]); break; // .TN.DropCapStyleArchive
case 12050: /* [2,3].forEach(j => delete dmeta[j]); */ break; // .TN.SheetStyleArchive
case 3045: break; // .TSD.CanvasSelectionArchive
case 6008: {
[1].forEach(j => delete dmeta[j]);
[2].forEach(j => delete_ref(dmeta, j, w.id));
// deleting 3 -> -[TSWPLayoutManager initWithStorage:owner:] /Library/Caches/com.apple.xbs/Sources/iWorkDependenciesMacOS/iWorkDependenciesMacOS-7032.0.145/shared/text/TSWPLayoutManager.mm:82 Cannot initialize with a nil storage.
} break; // .TST.TableStylePresetArchive
case 6247: {
[ 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 ].forEach(j => delete_ref(dmeta, j, w.id));
} break; // .TST.TableStyleNetworkArchive
case 210: { // .TSK.ViewStateArchive
[2, 3].forEach(i => delete dmeta[i]);
} break;
case 12026: { // .TN.UIStateArchive
delete dmeta[13];
} break;
case 219: delete dmeta[1]; break; // .DocumentSelectionArchive
case 12028: break; // .TN.SheetSelectionArchive
case 3061: { // .TSD.DrawableSelectionArchive
[3].forEach(j => delete_ref(dmeta, j, w.id));
} break;
case 3091: { // .TSD.FreehandDrawingToolkitUIState
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].forEach(i => delete dmeta[i]);
} break;
/* Metadata.iwa */
case 11006: { // .TSP.PackageMetadata
[10].forEach(j => delete_ref(dmeta, j, w.id));
} break;
case 11014: // .TSP.DataMetadata
[1].forEach(j => delete dmeta[j]);
break;
case 11015: // .TSP.DataMetadataMap
dmeta?.[1]?.forEach((r, idx) => {
var ddmeta = parse_shallow(r.data);
[2].forEach(j => delete_ref(ddmeta, j, w.id));
});
delete dmeta[1];
dmeta.length = 0;
break;
/* AnnotationAuthorStorage.iwa */
case 213: break; // TSK.AnnotationAuthorStorageArchive
default:
console.log("!!", fi.name, type, w.id, w.messages.length);
}
w.messages[0].data = write_shallow(dmeta);
}
}

22
modules/reframe.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
set -eo pipefail
INF=${1:-test.numbers}
OUTF=${2:-reframed.numbers}
make reframe.node.js
node reframe.node.js "$INF" "$OUTF"
# cat-numbers "$OUTF"
chmod a+w "$OUTF"
sleep 0.1
# open "$OUTF"
unzip -l "$OUTF"
base64 "$OUTF" > xlsx.zahl.js
sed -i.bak 's/^/var XLSX_ZAHL_PAYLOAD = "/g;s/$/";/g' xlsx.zahl.js
cp xlsx.zahl.js xlsx.zahl.mjs
cat >> xlsx.zahl.js <<EOF
if(typeof module !== "undefined") module.exports = XLSX_ZAHL_PAYLOAD;
else if(typeof global !== "undefined") global.XLSX_ZAHL_PAYLOAD = XLSX_ZAHL_PAYLOAD;
else if(typeof window !== "undefined") window.XLSX_ZAHL_PAYLOAD = XLSX_ZAHL_PAYLOAD;
EOF
cat >> xlsx.zahl.mjs <<EOF
export default XLSX_ZAHL_PAYLOAD;
EOF

View File

@ -42,7 +42,10 @@ declare function write_XLWideString(data: string, o?: WritableData): RawData;
declare function writeuint16(x: number): RawData;
declare function utf8read(x: string): string;
declare function utf8write(x: string): string;
declare function a2s(a: RawData): string;
declare function s2a(s: string): RawData;
interface ParseXLMetaOptions {
WTF?: number|boolean;

BIN
modules/test.numbers Executable file

Binary file not shown.

View File

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.18.4",
"version": "0.18.5",
"author": "sheetjs",
"description": "SheetJS Spreadsheet data parser and writer",
"keywords": [

3
types/index.d.ts vendored
View File

@ -260,6 +260,9 @@ export interface WritingOptions extends CommonOptions, SheetOption {
/** Override workbook properties on save */
Props?: Properties;
/** Base64 encoding of NUMBERS base for exports */
numbers?: string;
}
/** Workbook Object */

View File

@ -4,7 +4,7 @@
/*global exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false */
var XLSX = {};
function make_xlsx_lib(XLSX){
XLSX.version = '0.18.4';
XLSX.version = '0.18.5';
var current_codepage = 1200, current_ansi = 1252;
/*:: declare var cptable:any; */
/*global cptable:true, window */
@ -22000,6 +22000,19 @@ function u8_to_dataview(array) {
function u8str(u8) {
return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8));
}
function stru8(str) {
return typeof TextEncoder != "undefined" ? new TextEncoder().encode(str) : s2a(utf8write(str));
}
function u8contains(body, search) {
outer:
for (var L = 0; L <= body.length - search.length; ++L) {
for (var j = 0; j < search.length; ++j)
if (body[L + j] != search[j])
continue outer;
return true;
}
return false;
}
function u8concat(u8a) {
var len = u8a.reduce(function(acc, x) {
return acc + x.length;
@ -22024,6 +22037,15 @@ function readDecimal128LE(buf, offset) {
mantissa = mantissa * 256 + buf[j];
return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176);
}
function writeDecimal128LE(buf, offset, value) {
var exp = Math.floor(value == 0 ? 0 : Math.LOG10E * Math.log(Math.abs(value))) + 6176 - 20;
var mantissa = value / Math.pow(10, exp - 6176);
buf[offset + 15] |= exp >> 7;
buf[offset + 14] |= (exp & 127) << 1;
for (var i = 0; mantissa >= 1; ++i, mantissa /= 256)
buf[offset + i] = mantissa & 255;
buf[offset + 15] |= value >= 0 ? 0 : 128;
}
function parse_varint49(buf, ptr) {
var l = ptr ? ptr[0] : 0;
var usz = buf[l] & 127;
@ -22149,7 +22171,7 @@ function parse_shallow(buf) {
default:
throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off));
}
var v = { offset: off, data: res, type: type };
var v = { data: res, type: type };
if (out[num] == null)
out[num] = [v];
else
@ -22161,6 +22183,8 @@ function write_shallow(proto) {
var out = [];
proto.forEach(function(field, idx) {
field.forEach(function(item) {
if (!item.data)
return;
out.push(write_varint49(idx * 8 + item.type));
if (item.type == 2)
out.push(write_varint49(item.data.length));
@ -22170,21 +22194,12 @@ function write_shallow(proto) {
return u8concat(out);
}
function mappa(data, cb) {
if (!data)
return [];
return data.map(function(d) {
var _a;
try {
return cb(d.data);
} catch (e) {
var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/);
if (m)
e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset));
throw e;
}
});
return (data == null ? void 0 : data.map(function(d) {
return cb(d.data);
})) || [];
}
function parse_iwa_file(buf) {
var _a;
var out = [], ptr = [0];
while (ptr[0] < buf.length) {
var len = parse_varint49(buf, ptr);
@ -22203,10 +22218,35 @@ function parse_iwa_file(buf) {
});
ptr[0] += fl;
});
if ((_a = ai[3]) == null ? void 0 : _a[0])
res.merge = varint_to_i32(ai[3][0].data) >>> 0 > 0;
out.push(res);
}
return out;
}
function write_iwa_file(ias) {
var bufs = [];
ias.forEach(function(ia) {
var ai = [];
ai[1] = [{ data: write_varint49(ia.id), type: 0 }];
ai[2] = [];
if (ia.merge != null)
ai[3] = [{ data: write_varint49(+!!ia.merge), type: 0 }];
var midata = [];
ia.messages.forEach(function(mi) {
midata.push(mi.data);
mi.meta[3] = [{ type: 0, data: write_varint49(mi.data.length) }];
ai[2].push({ data: write_shallow(mi.meta), type: 2 });
});
var aipayload = write_shallow(ai);
bufs.push(write_varint49(aipayload.length));
bufs.push(aipayload);
midata.forEach(function(mid) {
return bufs.push(mid);
});
});
return u8concat(bufs);
}
function parse_snappy_chunk(type, buf) {
if (type != 0)
throw new Error("Unexpected Snappy chunk type ".concat(type));
@ -22361,7 +22401,7 @@ function parse_old_storage(buf, sst, rsst, v) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -22383,7 +22423,7 @@ function parse_old_storage(buf, sst, rsst, v) {
}
return ret;
}
function parse_storage(buf, sst, rsst) {
function parse_new_storage(buf, sst, rsst) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(8, true);
var data_offset = 12;
@ -22425,7 +22465,7 @@ function parse_storage(buf, sst, rsst) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -22446,6 +22486,66 @@ function parse_storage(buf, sst, rsst) {
}
return ret;
}
function write_new_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 5;
switch (cell.t) {
case "n":
out[1] = 2;
writeDecimal128LE(out, l, cell.v);
flags |= 1;
l += 16;
break;
case "b":
out[1] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 2;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[1] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 8;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(8, flags, true);
return out.slice(0, l);
}
function write_old_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 3;
switch (cell.t) {
case "n":
out[2] = 2;
dv.setFloat64(l, cell.v, true);
flags |= 32;
l += 8;
break;
case "b":
out[2] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 32;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[2] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 16;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(4, flags, true);
return out.slice(0, l);
}
function parse_cell_storage(buf, sst, rsst) {
switch (buf[0]) {
case 0:
@ -22454,7 +22554,7 @@ function parse_cell_storage(buf, sst, rsst) {
case 3:
return parse_old_storage(buf, sst, rsst, buf[0]);
case 5:
return parse_storage(buf, sst, rsst);
return parse_new_storage(buf, sst, rsst);
default:
throw new Error("Unsupported payload version ".concat(buf[0]));
}
@ -22463,6 +22563,11 @@ function parse_TSP_Reference(buf) {
var pb = parse_shallow(buf);
return parse_varint49(pb[1][0].data);
}
function write_TSP_Reference(idx) {
var out = [];
out[1] = [{ type: 0, data: write_varint49(idx) }];
return write_shallow(out);
}
function parse_TST_TableDataList(M, root) {
var pb = parse_shallow(root.data);
var type = varint_to_i32(pb[1][0].data);
@ -22521,7 +22626,8 @@ function parse_TST_TileRowInfo(u8, type) {
var cells = [];
for (C = 0; C < offsets.length - 1; ++C)
cells[offsets[C][0]] = used_storage.subarray(offsets[C][1] * width, offsets[C + 1][1] * width);
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
if (offsets.length >= 1)
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
return { R: R, cells: cells };
}
function parse_TST_Tile(M, root) {
@ -22627,7 +22733,7 @@ function parse_TN_DocumentArchive(M, root) {
}
function parse_numbers_iwa(cfb) {
var _a, _b, _c, _d;
var out = {}, indices = [];
var M = {}, indices = [];
cfb.FullPaths.forEach(function(p) {
if (p.match(/\.iwpv2/))
throw new Error("Unsupported password protection");
@ -22648,16 +22754,16 @@ function parse_numbers_iwa(cfb) {
return console.log("## " + (e.message || e));
}
packets.forEach(function(packet) {
out[packet.id] = packet.messages;
M[packet.id] = packet.messages;
indices.push(packet.id);
});
});
if (!indices.length)
throw new Error("File has no messages");
var docroot = ((_d = (_c = (_b = (_a = out == null ? void 0 : out[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(out[1][0].meta[1][0].data) == 1 && out[1][0];
var docroot = ((_d = (_c = (_b = (_a = M == null ? void 0 : M[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(M[1][0].meta[1][0].data) == 1 && M[1][0];
if (!docroot)
indices.forEach(function(idx) {
out[idx].forEach(function(iwam) {
M[idx].forEach(function(iwam) {
var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0;
if (mtype == 1) {
if (!docroot)
@ -22669,7 +22775,325 @@ function parse_numbers_iwa(cfb) {
});
if (!docroot)
throw new Error("Cannot find Document root");
return parse_TN_DocumentArchive(out, docroot);
return parse_TN_DocumentArchive(M, docroot);
}
function write_tile_row(tri, data, SST) {
var _a, _b, _c, _d;
if (!((_a = tri[6]) == null ? void 0 : _a[0]) || !((_b = tri[7]) == null ? void 0 : _b[0]))
throw "Mutation only works on post-BNC storages!";
var wide_offsets = ((_d = (_c = tri[8]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && varint_to_i32(tri[8][0].data) > 0 || false;
if (wide_offsets)
throw "Math only works with normal offsets";
var cnt = 0;
var dv = u8_to_dataview(tri[7][0].data), last_offset = 0, cell_storage = [];
var _dv = u8_to_dataview(tri[4][0].data), _last_offset = 0, _cell_storage = [];
for (var C = 0; C < data.length; ++C) {
if (data[C] == null) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535);
continue;
}
dv.setUint16(C * 2, last_offset, true);
_dv.setUint16(C * 2, _last_offset, true);
var celload, _celload;
switch (typeof data[C]) {
case "string":
celload = write_new_storage({ t: "s", v: data[C] }, SST);
_celload = write_old_storage({ t: "s", v: data[C] }, SST);
break;
case "number":
celload = write_new_storage({ t: "n", v: data[C] }, SST);
_celload = write_old_storage({ t: "n", v: data[C] }, SST);
break;
case "boolean":
celload = write_new_storage({ t: "b", v: data[C] }, SST);
_celload = write_old_storage({ t: "b", v: data[C] }, SST);
break;
default:
throw new Error("Unsupported value " + data[C]);
}
cell_storage.push(celload);
last_offset += celload.length;
_cell_storage.push(_celload);
_last_offset += _celload.length;
++cnt;
}
tri[2][0].data = write_varint49(cnt);
for (; C < tri[7][0].data.length / 2; ++C) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535, true);
}
tri[6][0].data = u8concat(cell_storage);
tri[3][0].data = u8concat(_cell_storage);
return cnt;
}
function write_numbers_iwa(wb, opts) {
if (!opts || !opts.numbers)
throw new Error("Must pass a `numbers` option -- check the README");
var ws = wb.Sheets[wb.SheetNames[0]];
if (wb.SheetNames.length > 1)
console.error("The Numbers writer currently writes only the first table");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
if (range.e.c > 9) {
trunc = true;
range.e.c = 9;
}
if (range.e.r > 49) {
trunc = true;
range.e.r = 49;
}
if (trunc)
console.error("The Numbers writer is currently limited to ".concat(encode_range(range)));
var data = sheet_to_json(ws, { range: range, header: 1 });
var SST = ["~Sh33tJ5~"];
data.forEach(function(row) {
return row.forEach(function(cell) {
if (typeof cell == "string")
SST.push(cell);
});
});
var dependents = {};
var indices = [];
var cfb = CFB.read(opts.numbers, { type: "base64" });
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (fi.type != 2)
return;
if (!fi.name.match(/\.iwa/))
return;
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content);
var x2 = parse_iwa_file(raw1);
x2.forEach(function(packet2) {
indices.push(packet2.id);
dependents[packet2.id] = { deps: [], location: fp, type: varint_to_i32(packet2.messages[0].meta[1][0].data) };
});
});
indices.sort(function(x2, y2) {
return x2 - y2;
});
var indices_varint = indices.filter(function(x2) {
return x2 > 1;
}).map(function(x2) {
return [x2, write_varint49(x2)];
});
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (!fi.name.match(/\.iwa/))
return;
var x2 = parse_iwa_file(decompress_iwa_file(fi.content));
x2.forEach(function(ia) {
ia.messages.forEach(function(m) {
indices_varint.forEach(function(ivi) {
if (ia.messages.some(function(mess) {
return varint_to_i32(mess.meta[1][0].data) != 11006 && u8contains(mess.data, ivi[1]);
})) {
dependents[ivi[0]].deps.push(ia.id);
}
});
});
});
});
function get_unique_msgid() {
for (var i = 927262; i < 2e6; ++i)
if (!dependents[i])
return i;
throw new Error("Too many messages");
}
var entry = CFB.find(cfb, dependents[1].location);
var x = parse_iwa_file(decompress_iwa_file(entry.content));
var docroot;
for (var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if (packet.id == 1)
docroot = packet;
}
var sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[1][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
var pb = parse_shallow(docroot.messages[0].data);
{
pb[6][0].data = write_varint49(range.e.r + 1);
pb[7][0].data = write_varint49(range.e.c + 1);
var cruidsref = parse_TSP_Reference(pb[46][0].data);
var oldbucket = CFB.find(cfb, dependents[cruidsref].location);
var _x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
for (var j = 0; j < _x.length; ++j) {
if (_x[j].id == cruidsref)
break;
}
if (_x[j].id != cruidsref)
throw "Bad ColumnRowUIDMapArchive";
var cruids = parse_shallow(_x[j].messages[0].data);
cruids[1] = [];
cruids[2] = [], cruids[3] = [];
for (var C = 0; C <= range.e.c; ++C) {
var uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(C + 420690) }];
cruids[1].push({ type: 2, data: write_shallow(uuid) });
cruids[2].push({ type: 0, data: write_varint49(C) });
cruids[3].push({ type: 0, data: write_varint49(C) });
}
cruids[4] = [];
cruids[5] = [], cruids[6] = [];
for (var R = 0; R <= range.e.r; ++R) {
uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(R + 726270) }];
cruids[4].push({ type: 2, data: write_shallow(uuid) });
cruids[5].push({ type: 0, data: write_varint49(R) });
cruids[6].push({ type: 0, data: write_varint49(R) });
}
_x[j].messages[0].data = write_shallow(cruids);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
delete pb[46];
var store = parse_shallow(pb[4][0].data);
{
store[7][0].data = write_varint49(range.e.r + 1);
var row_headers = parse_shallow(store[1][0].data);
var row_header_ref = parse_TSP_Reference(row_headers[2][0].data);
oldbucket = CFB.find(cfb, dependents[row_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != row_header_ref)
throw "Bad HeaderStorageBucket";
var base_bucket = parse_shallow(_x[0].messages[0].data);
for (R = 0; R < data.length; ++R) {
var _bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(R);
_bucket[4][0].data = write_varint49(data[R].length);
base_bucket[2][R] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var col_header_ref = parse_TSP_Reference(store[2][0].data);
oldbucket = CFB.find(cfb, dependents[col_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != col_header_ref)
throw "Bad HeaderStorageBucket";
base_bucket = parse_shallow(_x[0].messages[0].data);
for (C = 0; C <= range.e.c; ++C) {
_bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(C);
_bucket[4][0].data = write_varint49(range.e.r + 1);
base_bucket[2][C] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var sstref = parse_TSP_Reference(store[4][0].data);
(function() {
var sentry = CFB.find(cfb, dependents[sstref].location);
var sx = parse_iwa_file(decompress_iwa_file(sentry.content));
var sstroot;
for (var sxi = 0; sxi < sx.length; ++sxi) {
var packet2 = sx[sxi];
if (packet2.id == sstref)
sstroot = packet2;
}
var sstdata = parse_shallow(sstroot.messages[0].data);
{
sstdata[3] = [];
var newsst = [];
SST.forEach(function(str, i) {
newsst[1] = [{ type: 0, data: write_varint49(i) }];
newsst[2] = [{ type: 0, data: write_varint49(1) }];
newsst[3] = [{ type: 2, data: stru8(str) }];
sstdata[3].push({ type: 2, data: write_shallow(newsst) });
});
}
sstroot.messages[0].data = write_shallow(sstdata);
var sy = write_iwa_file(sx);
var raw32 = compress_iwa_file(sy);
sentry.content = raw32;
sentry.size = sentry.content.length;
})();
var tile = parse_shallow(store[3][0].data);
{
var t = tile[1][0];
delete tile[2];
var tl = parse_shallow(t.data);
{
var tileref = parse_TSP_Reference(tl[2][0].data);
(function() {
var tentry = CFB.find(cfb, dependents[tileref].location);
var tx = parse_iwa_file(decompress_iwa_file(tentry.content));
var tileroot;
for (var sxi = 0; sxi < tx.length; ++sxi) {
var packet2 = tx[sxi];
if (packet2.id == tileref)
tileroot = packet2;
}
var tiledata = parse_shallow(tileroot.messages[0].data);
{
delete tiledata[6];
delete tile[7];
var rowload = new Uint8Array(tiledata[5][0].data);
tiledata[5] = [];
var cnt = 0;
for (var R2 = 0; R2 <= range.e.r; ++R2) {
var tilerow = parse_shallow(rowload);
cnt += write_tile_row(tilerow, data[R2], SST);
tilerow[1][0].data = write_varint49(R2);
tiledata[5].push({ data: write_shallow(tilerow), type: 2 });
}
tiledata[1] = [{ type: 0, data: write_varint49(range.e.c + 1) }];
tiledata[2] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
tiledata[3] = [{ type: 0, data: write_varint49(cnt) }];
tiledata[4] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
}
tileroot.messages[0].data = write_shallow(tiledata);
var ty = write_iwa_file(tx);
var raw32 = compress_iwa_file(ty);
tentry.content = raw32;
tentry.size = tentry.content.length;
})();
}
t.data = write_shallow(tl);
}
store[3][0].data = write_shallow(tile);
}
pb[4][0].data = write_shallow(store);
}
docroot.messages[0].data = write_shallow(pb);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
entry.content = raw3;
entry.size = entry.content.length;
return cfb;
}
function fix_opts_func(defaults/*:Array<Array<any> >*/)/*:{(o:any):void}*/ {
return function fix_opts(opts) {
@ -23010,6 +23434,7 @@ function parse_xlsxcfb(cfb, _opts/*:?ParseOpts*/)/*:Workbook*/ {
function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
if(opts.bookType == "ods") return write_ods(wb, opts);
if(opts.bookType == "numbers") return write_numbers_iwa(wb, opts);
if(opts.bookType == "xlsb") return write_zip_xlsxb(wb, opts);
return write_zip_xlsx(wb, opts);
}
@ -23578,6 +24003,7 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
case 'xlsm':
case 'xlam':
case 'xlsb':
case 'numbers':
case 'ods': return write_zip_type(wb, o);
default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
}

476
xlsx.js generated
View File

@ -4,7 +4,7 @@
/*global exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false */
var XLSX = {};
function make_xlsx_lib(XLSX){
XLSX.version = '0.18.4';
XLSX.version = '0.18.5';
var current_codepage = 1200, current_ansi = 1252;
/*global cptable:true, window */
var $cptable;
@ -21889,6 +21889,19 @@ function u8_to_dataview(array) {
function u8str(u8) {
return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8));
}
function stru8(str) {
return typeof TextEncoder != "undefined" ? new TextEncoder().encode(str) : s2a(utf8write(str));
}
function u8contains(body, search) {
outer:
for (var L = 0; L <= body.length - search.length; ++L) {
for (var j = 0; j < search.length; ++j)
if (body[L + j] != search[j])
continue outer;
return true;
}
return false;
}
function u8concat(u8a) {
var len = u8a.reduce(function(acc, x) {
return acc + x.length;
@ -21913,6 +21926,15 @@ function readDecimal128LE(buf, offset) {
mantissa = mantissa * 256 + buf[j];
return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176);
}
function writeDecimal128LE(buf, offset, value) {
var exp = Math.floor(value == 0 ? 0 : Math.LOG10E * Math.log(Math.abs(value))) + 6176 - 20;
var mantissa = value / Math.pow(10, exp - 6176);
buf[offset + 15] |= exp >> 7;
buf[offset + 14] |= (exp & 127) << 1;
for (var i = 0; mantissa >= 1; ++i, mantissa /= 256)
buf[offset + i] = mantissa & 255;
buf[offset + 15] |= value >= 0 ? 0 : 128;
}
function parse_varint49(buf, ptr) {
var l = ptr ? ptr[0] : 0;
var usz = buf[l] & 127;
@ -22038,7 +22060,7 @@ function parse_shallow(buf) {
default:
throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off));
}
var v = { offset: off, data: res, type: type };
var v = { data: res, type: type };
if (out[num] == null)
out[num] = [v];
else
@ -22050,6 +22072,8 @@ function write_shallow(proto) {
var out = [];
proto.forEach(function(field, idx) {
field.forEach(function(item) {
if (!item.data)
return;
out.push(write_varint49(idx * 8 + item.type));
if (item.type == 2)
out.push(write_varint49(item.data.length));
@ -22059,21 +22083,12 @@ function write_shallow(proto) {
return u8concat(out);
}
function mappa(data, cb) {
if (!data)
return [];
return data.map(function(d) {
var _a;
try {
return cb(d.data);
} catch (e) {
var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/);
if (m)
e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset));
throw e;
}
});
return (data == null ? void 0 : data.map(function(d) {
return cb(d.data);
})) || [];
}
function parse_iwa_file(buf) {
var _a;
var out = [], ptr = [0];
while (ptr[0] < buf.length) {
var len = parse_varint49(buf, ptr);
@ -22092,10 +22107,35 @@ function parse_iwa_file(buf) {
});
ptr[0] += fl;
});
if ((_a = ai[3]) == null ? void 0 : _a[0])
res.merge = varint_to_i32(ai[3][0].data) >>> 0 > 0;
out.push(res);
}
return out;
}
function write_iwa_file(ias) {
var bufs = [];
ias.forEach(function(ia) {
var ai = [];
ai[1] = [{ data: write_varint49(ia.id), type: 0 }];
ai[2] = [];
if (ia.merge != null)
ai[3] = [{ data: write_varint49(+!!ia.merge), type: 0 }];
var midata = [];
ia.messages.forEach(function(mi) {
midata.push(mi.data);
mi.meta[3] = [{ type: 0, data: write_varint49(mi.data.length) }];
ai[2].push({ data: write_shallow(mi.meta), type: 2 });
});
var aipayload = write_shallow(ai);
bufs.push(write_varint49(aipayload.length));
bufs.push(aipayload);
midata.forEach(function(mid) {
return bufs.push(mid);
});
});
return u8concat(bufs);
}
function parse_snappy_chunk(type, buf) {
if (type != 0)
throw new Error("Unexpected Snappy chunk type ".concat(type));
@ -22250,7 +22290,7 @@ function parse_old_storage(buf, sst, rsst, v) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -22272,7 +22312,7 @@ function parse_old_storage(buf, sst, rsst, v) {
}
return ret;
}
function parse_storage(buf, sst, rsst) {
function parse_new_storage(buf, sst, rsst) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(8, true);
var data_offset = 12;
@ -22314,7 +22354,7 @@ function parse_storage(buf, sst, rsst) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -22335,6 +22375,66 @@ function parse_storage(buf, sst, rsst) {
}
return ret;
}
function write_new_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 5;
switch (cell.t) {
case "n":
out[1] = 2;
writeDecimal128LE(out, l, cell.v);
flags |= 1;
l += 16;
break;
case "b":
out[1] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 2;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[1] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 8;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(8, flags, true);
return out.slice(0, l);
}
function write_old_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 3;
switch (cell.t) {
case "n":
out[2] = 2;
dv.setFloat64(l, cell.v, true);
flags |= 32;
l += 8;
break;
case "b":
out[2] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 32;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[2] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 16;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(4, flags, true);
return out.slice(0, l);
}
function parse_cell_storage(buf, sst, rsst) {
switch (buf[0]) {
case 0:
@ -22343,7 +22443,7 @@ function parse_cell_storage(buf, sst, rsst) {
case 3:
return parse_old_storage(buf, sst, rsst, buf[0]);
case 5:
return parse_storage(buf, sst, rsst);
return parse_new_storage(buf, sst, rsst);
default:
throw new Error("Unsupported payload version ".concat(buf[0]));
}
@ -22352,6 +22452,11 @@ function parse_TSP_Reference(buf) {
var pb = parse_shallow(buf);
return parse_varint49(pb[1][0].data);
}
function write_TSP_Reference(idx) {
var out = [];
out[1] = [{ type: 0, data: write_varint49(idx) }];
return write_shallow(out);
}
function parse_TST_TableDataList(M, root) {
var pb = parse_shallow(root.data);
var type = varint_to_i32(pb[1][0].data);
@ -22410,7 +22515,8 @@ function parse_TST_TileRowInfo(u8, type) {
var cells = [];
for (C = 0; C < offsets.length - 1; ++C)
cells[offsets[C][0]] = used_storage.subarray(offsets[C][1] * width, offsets[C + 1][1] * width);
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
if (offsets.length >= 1)
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
return { R: R, cells: cells };
}
function parse_TST_Tile(M, root) {
@ -22516,7 +22622,7 @@ function parse_TN_DocumentArchive(M, root) {
}
function parse_numbers_iwa(cfb) {
var _a, _b, _c, _d;
var out = {}, indices = [];
var M = {}, indices = [];
cfb.FullPaths.forEach(function(p) {
if (p.match(/\.iwpv2/))
throw new Error("Unsupported password protection");
@ -22537,16 +22643,16 @@ function parse_numbers_iwa(cfb) {
return console.log("## " + (e.message || e));
}
packets.forEach(function(packet) {
out[packet.id] = packet.messages;
M[packet.id] = packet.messages;
indices.push(packet.id);
});
});
if (!indices.length)
throw new Error("File has no messages");
var docroot = ((_d = (_c = (_b = (_a = out == null ? void 0 : out[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(out[1][0].meta[1][0].data) == 1 && out[1][0];
var docroot = ((_d = (_c = (_b = (_a = M == null ? void 0 : M[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(M[1][0].meta[1][0].data) == 1 && M[1][0];
if (!docroot)
indices.forEach(function(idx) {
out[idx].forEach(function(iwam) {
M[idx].forEach(function(iwam) {
var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0;
if (mtype == 1) {
if (!docroot)
@ -22558,7 +22664,325 @@ function parse_numbers_iwa(cfb) {
});
if (!docroot)
throw new Error("Cannot find Document root");
return parse_TN_DocumentArchive(out, docroot);
return parse_TN_DocumentArchive(M, docroot);
}
function write_tile_row(tri, data, SST) {
var _a, _b, _c, _d;
if (!((_a = tri[6]) == null ? void 0 : _a[0]) || !((_b = tri[7]) == null ? void 0 : _b[0]))
throw "Mutation only works on post-BNC storages!";
var wide_offsets = ((_d = (_c = tri[8]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && varint_to_i32(tri[8][0].data) > 0 || false;
if (wide_offsets)
throw "Math only works with normal offsets";
var cnt = 0;
var dv = u8_to_dataview(tri[7][0].data), last_offset = 0, cell_storage = [];
var _dv = u8_to_dataview(tri[4][0].data), _last_offset = 0, _cell_storage = [];
for (var C = 0; C < data.length; ++C) {
if (data[C] == null) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535);
continue;
}
dv.setUint16(C * 2, last_offset, true);
_dv.setUint16(C * 2, _last_offset, true);
var celload, _celload;
switch (typeof data[C]) {
case "string":
celload = write_new_storage({ t: "s", v: data[C] }, SST);
_celload = write_old_storage({ t: "s", v: data[C] }, SST);
break;
case "number":
celload = write_new_storage({ t: "n", v: data[C] }, SST);
_celload = write_old_storage({ t: "n", v: data[C] }, SST);
break;
case "boolean":
celload = write_new_storage({ t: "b", v: data[C] }, SST);
_celload = write_old_storage({ t: "b", v: data[C] }, SST);
break;
default:
throw new Error("Unsupported value " + data[C]);
}
cell_storage.push(celload);
last_offset += celload.length;
_cell_storage.push(_celload);
_last_offset += _celload.length;
++cnt;
}
tri[2][0].data = write_varint49(cnt);
for (; C < tri[7][0].data.length / 2; ++C) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535, true);
}
tri[6][0].data = u8concat(cell_storage);
tri[3][0].data = u8concat(_cell_storage);
return cnt;
}
function write_numbers_iwa(wb, opts) {
if (!opts || !opts.numbers)
throw new Error("Must pass a `numbers` option -- check the README");
var ws = wb.Sheets[wb.SheetNames[0]];
if (wb.SheetNames.length > 1)
console.error("The Numbers writer currently writes only the first table");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
if (range.e.c > 9) {
trunc = true;
range.e.c = 9;
}
if (range.e.r > 49) {
trunc = true;
range.e.r = 49;
}
if (trunc)
console.error("The Numbers writer is currently limited to ".concat(encode_range(range)));
var data = sheet_to_json(ws, { range: range, header: 1 });
var SST = ["~Sh33tJ5~"];
data.forEach(function(row) {
return row.forEach(function(cell) {
if (typeof cell == "string")
SST.push(cell);
});
});
var dependents = {};
var indices = [];
var cfb = CFB.read(opts.numbers, { type: "base64" });
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (fi.type != 2)
return;
if (!fi.name.match(/\.iwa/))
return;
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content);
var x2 = parse_iwa_file(raw1);
x2.forEach(function(packet2) {
indices.push(packet2.id);
dependents[packet2.id] = { deps: [], location: fp, type: varint_to_i32(packet2.messages[0].meta[1][0].data) };
});
});
indices.sort(function(x2, y2) {
return x2 - y2;
});
var indices_varint = indices.filter(function(x2) {
return x2 > 1;
}).map(function(x2) {
return [x2, write_varint49(x2)];
});
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (!fi.name.match(/\.iwa/))
return;
var x2 = parse_iwa_file(decompress_iwa_file(fi.content));
x2.forEach(function(ia) {
ia.messages.forEach(function(m) {
indices_varint.forEach(function(ivi) {
if (ia.messages.some(function(mess) {
return varint_to_i32(mess.meta[1][0].data) != 11006 && u8contains(mess.data, ivi[1]);
})) {
dependents[ivi[0]].deps.push(ia.id);
}
});
});
});
});
function get_unique_msgid() {
for (var i = 927262; i < 2e6; ++i)
if (!dependents[i])
return i;
throw new Error("Too many messages");
}
var entry = CFB.find(cfb, dependents[1].location);
var x = parse_iwa_file(decompress_iwa_file(entry.content));
var docroot;
for (var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if (packet.id == 1)
docroot = packet;
}
var sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[1][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
var pb = parse_shallow(docroot.messages[0].data);
{
pb[6][0].data = write_varint49(range.e.r + 1);
pb[7][0].data = write_varint49(range.e.c + 1);
var cruidsref = parse_TSP_Reference(pb[46][0].data);
var oldbucket = CFB.find(cfb, dependents[cruidsref].location);
var _x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
for (var j = 0; j < _x.length; ++j) {
if (_x[j].id == cruidsref)
break;
}
if (_x[j].id != cruidsref)
throw "Bad ColumnRowUIDMapArchive";
var cruids = parse_shallow(_x[j].messages[0].data);
cruids[1] = [];
cruids[2] = [], cruids[3] = [];
for (var C = 0; C <= range.e.c; ++C) {
var uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(C + 420690) }];
cruids[1].push({ type: 2, data: write_shallow(uuid) });
cruids[2].push({ type: 0, data: write_varint49(C) });
cruids[3].push({ type: 0, data: write_varint49(C) });
}
cruids[4] = [];
cruids[5] = [], cruids[6] = [];
for (var R = 0; R <= range.e.r; ++R) {
uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(R + 726270) }];
cruids[4].push({ type: 2, data: write_shallow(uuid) });
cruids[5].push({ type: 0, data: write_varint49(R) });
cruids[6].push({ type: 0, data: write_varint49(R) });
}
_x[j].messages[0].data = write_shallow(cruids);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
delete pb[46];
var store = parse_shallow(pb[4][0].data);
{
store[7][0].data = write_varint49(range.e.r + 1);
var row_headers = parse_shallow(store[1][0].data);
var row_header_ref = parse_TSP_Reference(row_headers[2][0].data);
oldbucket = CFB.find(cfb, dependents[row_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != row_header_ref)
throw "Bad HeaderStorageBucket";
var base_bucket = parse_shallow(_x[0].messages[0].data);
for (R = 0; R < data.length; ++R) {
var _bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(R);
_bucket[4][0].data = write_varint49(data[R].length);
base_bucket[2][R] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var col_header_ref = parse_TSP_Reference(store[2][0].data);
oldbucket = CFB.find(cfb, dependents[col_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != col_header_ref)
throw "Bad HeaderStorageBucket";
base_bucket = parse_shallow(_x[0].messages[0].data);
for (C = 0; C <= range.e.c; ++C) {
_bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(C);
_bucket[4][0].data = write_varint49(range.e.r + 1);
base_bucket[2][C] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var sstref = parse_TSP_Reference(store[4][0].data);
(function() {
var sentry = CFB.find(cfb, dependents[sstref].location);
var sx = parse_iwa_file(decompress_iwa_file(sentry.content));
var sstroot;
for (var sxi = 0; sxi < sx.length; ++sxi) {
var packet2 = sx[sxi];
if (packet2.id == sstref)
sstroot = packet2;
}
var sstdata = parse_shallow(sstroot.messages[0].data);
{
sstdata[3] = [];
var newsst = [];
SST.forEach(function(str, i) {
newsst[1] = [{ type: 0, data: write_varint49(i) }];
newsst[2] = [{ type: 0, data: write_varint49(1) }];
newsst[3] = [{ type: 2, data: stru8(str) }];
sstdata[3].push({ type: 2, data: write_shallow(newsst) });
});
}
sstroot.messages[0].data = write_shallow(sstdata);
var sy = write_iwa_file(sx);
var raw32 = compress_iwa_file(sy);
sentry.content = raw32;
sentry.size = sentry.content.length;
})();
var tile = parse_shallow(store[3][0].data);
{
var t = tile[1][0];
delete tile[2];
var tl = parse_shallow(t.data);
{
var tileref = parse_TSP_Reference(tl[2][0].data);
(function() {
var tentry = CFB.find(cfb, dependents[tileref].location);
var tx = parse_iwa_file(decompress_iwa_file(tentry.content));
var tileroot;
for (var sxi = 0; sxi < tx.length; ++sxi) {
var packet2 = tx[sxi];
if (packet2.id == tileref)
tileroot = packet2;
}
var tiledata = parse_shallow(tileroot.messages[0].data);
{
delete tiledata[6];
delete tile[7];
var rowload = new Uint8Array(tiledata[5][0].data);
tiledata[5] = [];
var cnt = 0;
for (var R2 = 0; R2 <= range.e.r; ++R2) {
var tilerow = parse_shallow(rowload);
cnt += write_tile_row(tilerow, data[R2], SST);
tilerow[1][0].data = write_varint49(R2);
tiledata[5].push({ data: write_shallow(tilerow), type: 2 });
}
tiledata[1] = [{ type: 0, data: write_varint49(range.e.c + 1) }];
tiledata[2] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
tiledata[3] = [{ type: 0, data: write_varint49(cnt) }];
tiledata[4] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
}
tileroot.messages[0].data = write_shallow(tiledata);
var ty = write_iwa_file(tx);
var raw32 = compress_iwa_file(ty);
tentry.content = raw32;
tentry.size = tentry.content.length;
})();
}
t.data = write_shallow(tl);
}
store[3][0].data = write_shallow(tile);
}
pb[4][0].data = write_shallow(store);
}
docroot.messages[0].data = write_shallow(pb);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
entry.content = raw3;
entry.size = entry.content.length;
return cfb;
}
function fix_opts_func(defaults) {
return function fix_opts(opts) {
@ -22897,6 +23321,7 @@ if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std7
function write_zip(wb, opts) {
if(opts.bookType == "ods") return write_ods(wb, opts);
if(opts.bookType == "numbers") return write_numbers_iwa(wb, opts);
if(opts.bookType == "xlsb") return write_zip_xlsxb(wb, opts);
return write_zip_xlsx(wb, opts);
}
@ -23462,6 +23887,7 @@ function writeSync(wb, opts) {
case 'xlsm':
case 'xlam':
case 'xlsb':
case 'numbers':
case 'ods': return write_zip_type(wb, o);
default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

476
xlsx.mjs generated
View File

@ -3,7 +3,7 @@
/*exported XLSX */
/*global process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false */
var XLSX = {};
XLSX.version = '0.18.4';
XLSX.version = '0.18.5';
var current_codepage = 1200, current_ansi = 1252;
var VALID_ANSI = [ 874, 932, 936, 949, 950, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 10000 ];
@ -21998,6 +21998,19 @@ function u8_to_dataview(array) {
function u8str(u8) {
return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8));
}
function stru8(str) {
return typeof TextEncoder != "undefined" ? new TextEncoder().encode(str) : s2a(utf8write(str));
}
function u8contains(body, search) {
outer:
for (var L = 0; L <= body.length - search.length; ++L) {
for (var j = 0; j < search.length; ++j)
if (body[L + j] != search[j])
continue outer;
return true;
}
return false;
}
function u8concat(u8a) {
var len = u8a.reduce(function(acc, x) {
return acc + x.length;
@ -22022,6 +22035,15 @@ function readDecimal128LE(buf, offset) {
mantissa = mantissa * 256 + buf[j];
return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176);
}
function writeDecimal128LE(buf, offset, value) {
var exp = Math.floor(value == 0 ? 0 : Math.LOG10E * Math.log(Math.abs(value))) + 6176 - 20;
var mantissa = value / Math.pow(10, exp - 6176);
buf[offset + 15] |= exp >> 7;
buf[offset + 14] |= (exp & 127) << 1;
for (var i = 0; mantissa >= 1; ++i, mantissa /= 256)
buf[offset + i] = mantissa & 255;
buf[offset + 15] |= value >= 0 ? 0 : 128;
}
function parse_varint49(buf, ptr) {
var l = ptr ? ptr[0] : 0;
var usz = buf[l] & 127;
@ -22147,7 +22169,7 @@ function parse_shallow(buf) {
default:
throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off));
}
var v = { offset: off, data: res, type: type };
var v = { data: res, type: type };
if (out[num] == null)
out[num] = [v];
else
@ -22159,6 +22181,8 @@ function write_shallow(proto) {
var out = [];
proto.forEach(function(field, idx) {
field.forEach(function(item) {
if (!item.data)
return;
out.push(write_varint49(idx * 8 + item.type));
if (item.type == 2)
out.push(write_varint49(item.data.length));
@ -22168,21 +22192,12 @@ function write_shallow(proto) {
return u8concat(out);
}
function mappa(data, cb) {
if (!data)
return [];
return data.map(function(d) {
var _a;
try {
return cb(d.data);
} catch (e) {
var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/);
if (m)
e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset));
throw e;
}
});
return (data == null ? void 0 : data.map(function(d) {
return cb(d.data);
})) || [];
}
function parse_iwa_file(buf) {
var _a;
var out = [], ptr = [0];
while (ptr[0] < buf.length) {
var len = parse_varint49(buf, ptr);
@ -22201,10 +22216,35 @@ function parse_iwa_file(buf) {
});
ptr[0] += fl;
});
if ((_a = ai[3]) == null ? void 0 : _a[0])
res.merge = varint_to_i32(ai[3][0].data) >>> 0 > 0;
out.push(res);
}
return out;
}
function write_iwa_file(ias) {
var bufs = [];
ias.forEach(function(ia) {
var ai = [];
ai[1] = [{ data: write_varint49(ia.id), type: 0 }];
ai[2] = [];
if (ia.merge != null)
ai[3] = [{ data: write_varint49(+!!ia.merge), type: 0 }];
var midata = [];
ia.messages.forEach(function(mi) {
midata.push(mi.data);
mi.meta[3] = [{ type: 0, data: write_varint49(mi.data.length) }];
ai[2].push({ data: write_shallow(mi.meta), type: 2 });
});
var aipayload = write_shallow(ai);
bufs.push(write_varint49(aipayload.length));
bufs.push(aipayload);
midata.forEach(function(mid) {
return bufs.push(mid);
});
});
return u8concat(bufs);
}
function parse_snappy_chunk(type, buf) {
if (type != 0)
throw new Error("Unexpected Snappy chunk type ".concat(type));
@ -22359,7 +22399,7 @@ function parse_old_storage(buf, sst, rsst, v) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -22381,7 +22421,7 @@ function parse_old_storage(buf, sst, rsst, v) {
}
return ret;
}
function parse_storage(buf, sst, rsst) {
function parse_new_storage(buf, sst, rsst) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(8, true);
var data_offset = 12;
@ -22423,7 +22463,7 @@ function parse_storage(buf, sst, rsst) {
ret = { t: "b", v: ieee > 0 };
break;
case 7:
ret = { t: "n", v: ieee };
ret = { t: "n", v: ieee / 86400 };
break;
case 8:
ret = { t: "e", v: 0 };
@ -22444,6 +22484,66 @@ function parse_storage(buf, sst, rsst) {
}
return ret;
}
function write_new_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 5;
switch (cell.t) {
case "n":
out[1] = 2;
writeDecimal128LE(out, l, cell.v);
flags |= 1;
l += 16;
break;
case "b":
out[1] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 2;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[1] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 8;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(8, flags, true);
return out.slice(0, l);
}
function write_old_storage(cell, sst) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
out[0] = 3;
switch (cell.t) {
case "n":
out[2] = 2;
dv.setFloat64(l, cell.v, true);
flags |= 32;
l += 8;
break;
case "b":
out[2] = 6;
dv.setFloat64(l, cell.v ? 1 : 0, true);
flags |= 32;
l += 8;
break;
case "s":
if (sst.indexOf(cell.v) == -1)
throw new Error("Value ".concat(cell.v, " missing from SST!"));
out[2] = 3;
dv.setUint32(l, sst.indexOf(cell.v), true);
flags |= 16;
l += 4;
break;
default:
throw "unsupported cell type " + cell.t;
}
dv.setUint32(4, flags, true);
return out.slice(0, l);
}
function parse_cell_storage(buf, sst, rsst) {
switch (buf[0]) {
case 0:
@ -22452,7 +22552,7 @@ function parse_cell_storage(buf, sst, rsst) {
case 3:
return parse_old_storage(buf, sst, rsst, buf[0]);
case 5:
return parse_storage(buf, sst, rsst);
return parse_new_storage(buf, sst, rsst);
default:
throw new Error("Unsupported payload version ".concat(buf[0]));
}
@ -22461,6 +22561,11 @@ function parse_TSP_Reference(buf) {
var pb = parse_shallow(buf);
return parse_varint49(pb[1][0].data);
}
function write_TSP_Reference(idx) {
var out = [];
out[1] = [{ type: 0, data: write_varint49(idx) }];
return write_shallow(out);
}
function parse_TST_TableDataList(M, root) {
var pb = parse_shallow(root.data);
var type = varint_to_i32(pb[1][0].data);
@ -22519,7 +22624,8 @@ function parse_TST_TileRowInfo(u8, type) {
var cells = [];
for (C = 0; C < offsets.length - 1; ++C)
cells[offsets[C][0]] = used_storage.subarray(offsets[C][1] * width, offsets[C + 1][1] * width);
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
if (offsets.length >= 1)
cells[offsets[offsets.length - 1][0]] = used_storage.subarray(offsets[offsets.length - 1][1] * width);
return { R: R, cells: cells };
}
function parse_TST_Tile(M, root) {
@ -22625,7 +22731,7 @@ function parse_TN_DocumentArchive(M, root) {
}
function parse_numbers_iwa(cfb) {
var _a, _b, _c, _d;
var out = {}, indices = [];
var M = {}, indices = [];
cfb.FullPaths.forEach(function(p) {
if (p.match(/\.iwpv2/))
throw new Error("Unsupported password protection");
@ -22646,16 +22752,16 @@ function parse_numbers_iwa(cfb) {
return console.log("## " + (e.message || e));
}
packets.forEach(function(packet) {
out[packet.id] = packet.messages;
M[packet.id] = packet.messages;
indices.push(packet.id);
});
});
if (!indices.length)
throw new Error("File has no messages");
var docroot = ((_d = (_c = (_b = (_a = out == null ? void 0 : out[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(out[1][0].meta[1][0].data) == 1 && out[1][0];
var docroot = ((_d = (_c = (_b = (_a = M == null ? void 0 : M[1]) == null ? void 0 : _a[0]) == null ? void 0 : _b.meta) == null ? void 0 : _c[1]) == null ? void 0 : _d[0].data) && varint_to_i32(M[1][0].meta[1][0].data) == 1 && M[1][0];
if (!docroot)
indices.forEach(function(idx) {
out[idx].forEach(function(iwam) {
M[idx].forEach(function(iwam) {
var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0;
if (mtype == 1) {
if (!docroot)
@ -22667,7 +22773,325 @@ function parse_numbers_iwa(cfb) {
});
if (!docroot)
throw new Error("Cannot find Document root");
return parse_TN_DocumentArchive(out, docroot);
return parse_TN_DocumentArchive(M, docroot);
}
function write_tile_row(tri, data, SST) {
var _a, _b, _c, _d;
if (!((_a = tri[6]) == null ? void 0 : _a[0]) || !((_b = tri[7]) == null ? void 0 : _b[0]))
throw "Mutation only works on post-BNC storages!";
var wide_offsets = ((_d = (_c = tri[8]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && varint_to_i32(tri[8][0].data) > 0 || false;
if (wide_offsets)
throw "Math only works with normal offsets";
var cnt = 0;
var dv = u8_to_dataview(tri[7][0].data), last_offset = 0, cell_storage = [];
var _dv = u8_to_dataview(tri[4][0].data), _last_offset = 0, _cell_storage = [];
for (var C = 0; C < data.length; ++C) {
if (data[C] == null) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535);
continue;
}
dv.setUint16(C * 2, last_offset, true);
_dv.setUint16(C * 2, _last_offset, true);
var celload, _celload;
switch (typeof data[C]) {
case "string":
celload = write_new_storage({ t: "s", v: data[C] }, SST);
_celload = write_old_storage({ t: "s", v: data[C] }, SST);
break;
case "number":
celload = write_new_storage({ t: "n", v: data[C] }, SST);
_celload = write_old_storage({ t: "n", v: data[C] }, SST);
break;
case "boolean":
celload = write_new_storage({ t: "b", v: data[C] }, SST);
_celload = write_old_storage({ t: "b", v: data[C] }, SST);
break;
default:
throw new Error("Unsupported value " + data[C]);
}
cell_storage.push(celload);
last_offset += celload.length;
_cell_storage.push(_celload);
_last_offset += _celload.length;
++cnt;
}
tri[2][0].data = write_varint49(cnt);
for (; C < tri[7][0].data.length / 2; ++C) {
dv.setUint16(C * 2, 65535, true);
_dv.setUint16(C * 2, 65535, true);
}
tri[6][0].data = u8concat(cell_storage);
tri[3][0].data = u8concat(_cell_storage);
return cnt;
}
function write_numbers_iwa(wb, opts) {
if (!opts || !opts.numbers)
throw new Error("Must pass a `numbers` option -- check the README");
var ws = wb.Sheets[wb.SheetNames[0]];
if (wb.SheetNames.length > 1)
console.error("The Numbers writer currently writes only the first table");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
if (range.e.c > 9) {
trunc = true;
range.e.c = 9;
}
if (range.e.r > 49) {
trunc = true;
range.e.r = 49;
}
if (trunc)
console.error("The Numbers writer is currently limited to ".concat(encode_range(range)));
var data = sheet_to_json(ws, { range: range, header: 1 });
var SST = ["~Sh33tJ5~"];
data.forEach(function(row) {
return row.forEach(function(cell) {
if (typeof cell == "string")
SST.push(cell);
});
});
var dependents = {};
var indices = [];
var cfb = CFB.read(opts.numbers, { type: "base64" });
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (fi.type != 2)
return;
if (!fi.name.match(/\.iwa/))
return;
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content);
var x2 = parse_iwa_file(raw1);
x2.forEach(function(packet2) {
indices.push(packet2.id);
dependents[packet2.id] = { deps: [], location: fp, type: varint_to_i32(packet2.messages[0].meta[1][0].data) };
});
});
indices.sort(function(x2, y2) {
return x2 - y2;
});
var indices_varint = indices.filter(function(x2) {
return x2 > 1;
}).map(function(x2) {
return [x2, write_varint49(x2)];
});
cfb.FileIndex.map(function(fi, idx) {
return [fi, cfb.FullPaths[idx]];
}).forEach(function(row) {
var fi = row[0], fp = row[1];
if (!fi.name.match(/\.iwa/))
return;
var x2 = parse_iwa_file(decompress_iwa_file(fi.content));
x2.forEach(function(ia) {
ia.messages.forEach(function(m) {
indices_varint.forEach(function(ivi) {
if (ia.messages.some(function(mess) {
return varint_to_i32(mess.meta[1][0].data) != 11006 && u8contains(mess.data, ivi[1]);
})) {
dependents[ivi[0]].deps.push(ia.id);
}
});
});
});
});
function get_unique_msgid() {
for (var i = 927262; i < 2e6; ++i)
if (!dependents[i])
return i;
throw new Error("Too many messages");
}
var entry = CFB.find(cfb, dependents[1].location);
var x = parse_iwa_file(decompress_iwa_file(entry.content));
var docroot;
for (var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if (packet.id == 1)
docroot = packet;
}
var sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[1][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = CFB.find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content));
for (xi = 0; xi < x.length; ++xi) {
packet = x[xi];
if (packet.id == sheetrootref)
docroot = packet;
}
var pb = parse_shallow(docroot.messages[0].data);
{
pb[6][0].data = write_varint49(range.e.r + 1);
pb[7][0].data = write_varint49(range.e.c + 1);
var cruidsref = parse_TSP_Reference(pb[46][0].data);
var oldbucket = CFB.find(cfb, dependents[cruidsref].location);
var _x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
for (var j = 0; j < _x.length; ++j) {
if (_x[j].id == cruidsref)
break;
}
if (_x[j].id != cruidsref)
throw "Bad ColumnRowUIDMapArchive";
var cruids = parse_shallow(_x[j].messages[0].data);
cruids[1] = [];
cruids[2] = [], cruids[3] = [];
for (var C = 0; C <= range.e.c; ++C) {
var uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(C + 420690) }];
cruids[1].push({ type: 2, data: write_shallow(uuid) });
cruids[2].push({ type: 0, data: write_varint49(C) });
cruids[3].push({ type: 0, data: write_varint49(C) });
}
cruids[4] = [];
cruids[5] = [], cruids[6] = [];
for (var R = 0; R <= range.e.r; ++R) {
uuid = [];
uuid[1] = uuid[2] = [{ type: 0, data: write_varint49(R + 726270) }];
cruids[4].push({ type: 2, data: write_shallow(uuid) });
cruids[5].push({ type: 0, data: write_varint49(R) });
cruids[6].push({ type: 0, data: write_varint49(R) });
}
_x[j].messages[0].data = write_shallow(cruids);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
delete pb[46];
var store = parse_shallow(pb[4][0].data);
{
store[7][0].data = write_varint49(range.e.r + 1);
var row_headers = parse_shallow(store[1][0].data);
var row_header_ref = parse_TSP_Reference(row_headers[2][0].data);
oldbucket = CFB.find(cfb, dependents[row_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != row_header_ref)
throw "Bad HeaderStorageBucket";
var base_bucket = parse_shallow(_x[0].messages[0].data);
for (R = 0; R < data.length; ++R) {
var _bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(R);
_bucket[4][0].data = write_varint49(data[R].length);
base_bucket[2][R] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var col_header_ref = parse_TSP_Reference(store[2][0].data);
oldbucket = CFB.find(cfb, dependents[col_header_ref].location);
_x = parse_iwa_file(decompress_iwa_file(oldbucket.content));
{
if (_x[0].id != col_header_ref)
throw "Bad HeaderStorageBucket";
base_bucket = parse_shallow(_x[0].messages[0].data);
for (C = 0; C <= range.e.c; ++C) {
_bucket = parse_shallow(base_bucket[2][0].data);
_bucket[1][0].data = write_varint49(C);
_bucket[4][0].data = write_varint49(range.e.r + 1);
base_bucket[2][C] = { type: base_bucket[2][0].type, data: write_shallow(_bucket) };
}
_x[0].messages[0].data = write_shallow(base_bucket);
}
oldbucket.content = compress_iwa_file(write_iwa_file(_x));
oldbucket.size = oldbucket.content.length;
var sstref = parse_TSP_Reference(store[4][0].data);
(function() {
var sentry = CFB.find(cfb, dependents[sstref].location);
var sx = parse_iwa_file(decompress_iwa_file(sentry.content));
var sstroot;
for (var sxi = 0; sxi < sx.length; ++sxi) {
var packet2 = sx[sxi];
if (packet2.id == sstref)
sstroot = packet2;
}
var sstdata = parse_shallow(sstroot.messages[0].data);
{
sstdata[3] = [];
var newsst = [];
SST.forEach(function(str, i) {
newsst[1] = [{ type: 0, data: write_varint49(i) }];
newsst[2] = [{ type: 0, data: write_varint49(1) }];
newsst[3] = [{ type: 2, data: stru8(str) }];
sstdata[3].push({ type: 2, data: write_shallow(newsst) });
});
}
sstroot.messages[0].data = write_shallow(sstdata);
var sy = write_iwa_file(sx);
var raw32 = compress_iwa_file(sy);
sentry.content = raw32;
sentry.size = sentry.content.length;
})();
var tile = parse_shallow(store[3][0].data);
{
var t = tile[1][0];
delete tile[2];
var tl = parse_shallow(t.data);
{
var tileref = parse_TSP_Reference(tl[2][0].data);
(function() {
var tentry = CFB.find(cfb, dependents[tileref].location);
var tx = parse_iwa_file(decompress_iwa_file(tentry.content));
var tileroot;
for (var sxi = 0; sxi < tx.length; ++sxi) {
var packet2 = tx[sxi];
if (packet2.id == tileref)
tileroot = packet2;
}
var tiledata = parse_shallow(tileroot.messages[0].data);
{
delete tiledata[6];
delete tile[7];
var rowload = new Uint8Array(tiledata[5][0].data);
tiledata[5] = [];
var cnt = 0;
for (var R2 = 0; R2 <= range.e.r; ++R2) {
var tilerow = parse_shallow(rowload);
cnt += write_tile_row(tilerow, data[R2], SST);
tilerow[1][0].data = write_varint49(R2);
tiledata[5].push({ data: write_shallow(tilerow), type: 2 });
}
tiledata[1] = [{ type: 0, data: write_varint49(range.e.c + 1) }];
tiledata[2] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
tiledata[3] = [{ type: 0, data: write_varint49(cnt) }];
tiledata[4] = [{ type: 0, data: write_varint49(range.e.r + 1) }];
}
tileroot.messages[0].data = write_shallow(tiledata);
var ty = write_iwa_file(tx);
var raw32 = compress_iwa_file(ty);
tentry.content = raw32;
tentry.size = tentry.content.length;
})();
}
t.data = write_shallow(tl);
}
store[3][0].data = write_shallow(tile);
}
pb[4][0].data = write_shallow(store);
}
docroot.messages[0].data = write_shallow(pb);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
entry.content = raw3;
entry.size = entry.content.length;
return cfb;
}
function fix_opts_func(defaults/*:Array<Array<any> >*/)/*:{(o:any):void}*/ {
return function fix_opts(opts) {
@ -23008,6 +23432,7 @@ function parse_xlsxcfb(cfb, _opts/*:?ParseOpts*/)/*:Workbook*/ {
function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
if(opts.bookType == "ods") return write_ods(wb, opts);
if(opts.bookType == "numbers") return write_numbers_iwa(wb, opts);
if(opts.bookType == "xlsb") return write_zip_xlsxb(wb, opts);
return write_zip_xlsx(wb, opts);
}
@ -23576,6 +24001,7 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
case 'xlsm':
case 'xlam':
case 'xlsb':
case 'numbers':
case 'ods': return write_zip_type(wb, o);
default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
}