From df0e7b5f255140acf874668b7c0779c04b20997d Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 4 Sep 2022 17:51:49 -0400 Subject: [PATCH] NUMBERS duration cell number format --- bits/83_numbers.js | 245 ++++++++++++++++++++++++++++++++++-------- modules/83_numbers.js | 245 ++++++++++++++++++++++++++++++++++-------- modules/83_numbers.ts | 176 +++++++++++++++++++++++------- test_files | 2 +- 4 files changed, 545 insertions(+), 123 deletions(-) diff --git a/bits/83_numbers.js b/bits/83_numbers.js index bdafa36..e716f9f 100644 --- a/bits/83_numbers.js +++ b/bits/83_numbers.js @@ -411,37 +411,168 @@ function compress_iwa_file(buf) { } return u8concat(out); } -function parse_old_storage(buf, sst, rsst, v) { +var numbers_lut_new = function() { + return { sst: [], rsst: [], ofmt: [], nfmt: [] }; +}; +function numbers_format_cell(cell, t, flags, ofmt, nfmt) { + var _a, _b, _c, _d; + var ctype = t & 255, ver = t >> 8; + var fmt = ver >= 5 ? nfmt : ofmt; + dur: + if (flags & (ver > 4 ? 8 : 4) && cell.t == "n" && ctype == 7) { + var dstyle = ((_a = fmt[7]) == null ? void 0 : _a[0]) ? parse_varint49(fmt[7][0].data) : -1; + var dmin = ((_b = fmt[15]) == null ? void 0 : _b[0]) ? parse_varint49(fmt[15][0].data) : -1; + var dmax = ((_c = fmt[16]) == null ? void 0 : _c[0]) ? parse_varint49(fmt[16][0].data) : -1; + var auto = ((_d = fmt[40]) == null ? void 0 : _d[0]) ? parse_varint49(fmt[40][0].data) : -1; + if (dstyle == -1) + break dur; + var d = cell.v, dd = d; + autodur: + if (auto) { + if (d == 0) { + dmin = dmax = 2; + break autodur; + } + if (d >= 604800) + dmin = 1; + else if (d >= 86400) + dmin = 2; + else if (d >= 3600) + dmin = 4; + else if (d >= 60) + dmin = 8; + else if (d >= 1) + dmin = 16; + else + dmin = 32; + if (Math.floor(d) != d) + dmax = 32; + else if (d % 60) + dmax = 16; + else if (d % 3600) + dmax = 8; + else if (d % 86400) + dmax = 4; + else if (d % 604800) + dmax = 2; + if (dmax < dmin) + dmax = dmin; + } + if (dmin == -1 || dmax == -1) + break dur; + var dstr = [], zstr = []; + if (dmin == 1) { + dd = d / 604800; + if (dmax == 1) { + zstr.push('d"d"'); + } else { + dd |= 0; + d -= 604800 * dd; + } + dstr.push(dd + (dstyle == 2 ? " week" + (dd == 1 ? "" : "s") : dstyle == 1 ? "w" : "")); + } + if (dmin <= 2 && dmax >= 2) { + dd = d / 86400; + if (dmax > 2) { + dd |= 0; + d -= 86400 * dd; + } + zstr.push('d"d"'); + dstr.push(dd + (dstyle == 2 ? " day" + (dd == 1 ? "" : "s") : dstyle == 1 ? "d" : "")); + } + if (dmin <= 4 && dmax >= 4) { + dd = d / 3600; + if (dmax > 4) { + dd |= 0; + d -= 3600 * dd; + } + zstr.push((dmin >= 4 ? "[h]" : "h") + '"h"'); + dstr.push(dd + (dstyle == 2 ? " hour" + (dd == 1 ? "" : "s") : dstyle == 1 ? "h" : "")); + } + if (dmin <= 8 && dmax >= 8) { + dd = d / 60; + if (dmax > 8) { + dd |= 0; + d -= 60 * dd; + } + zstr.push((dmin >= 8 ? "[m]" : "m") + '"m"'); + if (dstyle == 0) + dstr.push((dmin == 8 && dmax == 8 || dd >= 10 ? "" : "0") + dd); + else + dstr.push(dd + (dstyle == 2 ? " minute" + (dd == 1 ? "" : "s") : dstyle == 1 ? "m" : "")); + } + if (dmin <= 16 && dmax >= 16) { + dd = d; + if (dmax > 16) { + dd |= 0; + d -= dd; + } + zstr.push((dmin >= 16 ? "[s]" : "s") + '"s"'); + if (dstyle == 0) + dstr.push((dmax == 16 && dmin == 16 || dd >= 10 ? "" : "0") + dd); + else + dstr.push(dd + (dstyle == 2 ? " second" + (dd == 1 ? "" : "s") : dstyle == 1 ? "s" : "")); + } + if (dmax >= 32) { + dd = Math.round(1e3 * d); + if (dmin < 32) + zstr.push('.000"ms"'); + if (dstyle == 0) + dstr.push((dd >= 100 ? "" : dd >= 10 ? "0" : "00") + dd); + else + dstr.push(dd + (dstyle == 2 ? " millisecond" + (dd == 1 ? "" : "s") : dstyle == 1 ? "ms" : "")); + } + cell.w = dstr.join(dstyle == 0 ? ":" : " "); + cell.z = zstr.join(dstyle == 0 ? '":"' : " "); + if (dstyle == 0) + cell.w = cell.w.replace(/:(\d\d\d)$/, ".$1"); + } +} +function parse_old_storage(buf, lut, v) { var dv = u8_to_dataview(buf); var flags = dv.getUint32(4, true); - var data_offset = (v > 1 ? 12 : 8) + popcnt(flags & (v > 1 ? 3470 : 398)) * 4; - var ridx = -1, sidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); - if (flags & 512) { - ridx = dv.getUint32(data_offset, true); - data_offset += 4; + var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); + var doff = v > 1 ? 12 : 8; + if (flags & 2) { + zidx = dv.getUint32(doff, true); + doff += 4; } - data_offset += popcnt(flags & (v > 1 ? 12288 : 4096)) * 4; + doff += popcnt(flags & (v > 1 ? 3468 : 396)) * 4; + if (flags & 512) { + ridx = dv.getUint32(doff, true); + doff += 4; + } + doff += popcnt(flags & (v > 1 ? 12288 : 4096)) * 4; if (flags & 16) { - sidx = dv.getUint32(data_offset, true); - data_offset += 4; + sidx = dv.getUint32(doff, true); + doff += 4; } if (flags & 32) { - ieee = dv.getFloat64(data_offset, true); - data_offset += 8; + ieee = dv.getFloat64(doff, true); + doff += 8; } if (flags & 64) { - dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); - data_offset += 8; + dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1e3); + doff += 8; + } + if (v > 1) { + flags = dv.getUint32(8, true) >>> 16; + if (flags & 255) { + if (zidx == -1) + zidx = dv.getUint32(doff, true); + doff += 4; + } } var ret; - switch (buf[2]) { + var t = buf[v >= 4 ? 1 : 2]; + switch (t) { case 0: return void 0; case 2: ret = { t: "n", v: ieee }; break; case 3: - ret = { t: "s", v: sst[sidx] }; + ret = { t: "s", v: lut.sst[sidx] }; break; case 5: ret = { t: "d", v: dt }; @@ -450,7 +581,7 @@ function parse_old_storage(buf, sst, rsst, v) { ret = { t: "b", v: ieee > 0 }; break; case 7: - ret = { t: "n", v: ieee / 86400 }; + ret = { t: "n", v: ieee }; break; case 8: ret = { t: "e", v: 0 }; @@ -458,7 +589,7 @@ function parse_old_storage(buf, sst, rsst, v) { case 9: { if (ridx > -1) - ret = { t: "s", v: rsst[ridx] }; + ret = { t: "s", v: lut.rsst[ridx] }; else throw new Error("Unsupported cell type ".concat(buf[subarray](0, 4))); } @@ -466,42 +597,53 @@ function parse_old_storage(buf, sst, rsst, v) { default: throw new Error("Unsupported cell type ".concat(buf[subarray](0, 4))); } + if (zidx > -1) + numbers_format_cell(ret, t | v << 8, flags, lut.ofmt[zidx], lut.nfmt[zidx]); + if (t == 7) + ret.v /= 86400; return ret; } -function parse_new_storage(buf, sst, rsst) { +function parse_new_storage(buf, lut) { var dv = u8_to_dataview(buf); var flags = dv.getUint32(8, true); - var data_offset = 12; - var ridx = -1, sidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); + var doff = 12; + var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); if (flags & 1) { - d128 = readDecimal128LE(buf, data_offset); - data_offset += 16; + d128 = readDecimal128LE(buf, doff); + doff += 16; } if (flags & 2) { - ieee = dv.getFloat64(data_offset, true); - data_offset += 8; + ieee = dv.getFloat64(doff, true); + doff += 8; } if (flags & 4) { - dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); - data_offset += 8; + dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1e3); + doff += 8; } if (flags & 8) { - sidx = dv.getUint32(data_offset, true); - data_offset += 4; + sidx = dv.getUint32(doff, true); + doff += 4; } if (flags & 16) { - ridx = dv.getUint32(data_offset, true); - data_offset += 4; + ridx = dv.getUint32(doff, true); + doff += 4; + } + doff += popcnt(flags & 8160) * 4; + if (flags & 516096) { + if (zidx == -1) + zidx = dv.getUint32(doff, true); + doff += 4; } var ret; - switch (buf[1]) { + var t = buf[1]; + switch (t) { case 0: return void 0; case 2: ret = { t: "n", v: d128 }; break; case 3: - ret = { t: "s", v: sst[sidx] }; + ret = { t: "s", v: lut.sst[sidx] }; break; case 5: ret = { t: "d", v: dt }; @@ -510,7 +652,7 @@ function parse_new_storage(buf, sst, rsst) { ret = { t: "b", v: ieee > 0 }; break; case 7: - ret = { t: "n", v: ieee / 86400 }; + ret = { t: "n", v: ieee }; break; case 8: ret = { t: "e", v: 0 }; @@ -518,7 +660,7 @@ function parse_new_storage(buf, sst, rsst) { case 9: { if (ridx > -1) - ret = { t: "s", v: rsst[ridx] }; + ret = { t: "s", v: lut.rsst[ridx] }; else throw new Error("Unsupported cell type ".concat(buf[1], " : ").concat(flags & 31, " : ").concat(buf[subarray](0, 4))); } @@ -529,6 +671,10 @@ function parse_new_storage(buf, sst, rsst) { default: throw new Error("Unsupported cell type ".concat(buf[1], " : ").concat(flags & 31, " : ").concat(buf[subarray](0, 4))); } + if (zidx > -1) + numbers_format_cell(ret, t | 5 << 8, flags >> 13, lut.ofmt[zidx], lut.nfmt[zidx]); + if (t == 7) + ret.v /= 86400; return ret; } function write_new_storage(cell, sst) { @@ -591,15 +737,16 @@ function write_old_storage(cell, sst) { dv.setUint32(4, flags, true); return out[subarray](0, l); } -function parse_cell_storage(buf, sst, rsst) { +function parse_cell_storage(buf, lut) { switch (buf[0]) { case 0: case 1: case 2: case 3: - return parse_old_storage(buf, sst, rsst, buf[0]); + case 4: + return parse_old_storage(buf, lut, buf[0]); case 5: - return parse_new_storage(buf, sst, rsst); + return parse_new_storage(buf, lut); default: throw new Error("Unsupported payload version ".concat(buf[0])); } @@ -640,6 +787,11 @@ function parse_TST_TableDataList(M, root) { }).join(""); } break; + case 2: + data[key] = parse_shallow(le[6][0].data); + break; + default: + throw type; } }); return data; @@ -704,7 +856,7 @@ function parse_TST_Tile(M, root) { }; } function parse_TST_TableModelArchive(M, root, ws) { - var _a, _b, _c; + var _a, _b, _c, _d, _e, _f; var pb = parse_shallow(root.data); var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } }; range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1; @@ -716,8 +868,15 @@ function parse_TST_TableModelArchive(M, root, ws) { ws["!ref"] = encode_range(range); var dense = Array.isArray(ws); var store = parse_shallow(pb[4][0].data); - var sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); - var rsst = ((_a = store[17]) == null ? void 0 : _a[0]) ? parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]) : []; + var lut = numbers_lut_new(); + if ((_a = store[4]) == null ? void 0 : _a[0]) + lut.sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); + if ((_b = store[11]) == null ? void 0 : _b[0]) + lut.ofmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[11][0].data)][0]); + if ((_c = store[17]) == null ? void 0 : _c[0]) + lut.rsst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]); + if ((_d = store[22]) == null ? void 0 : _d[0]) + lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]); var tile = parse_shallow(store[3][0].data); var _R = 0; tile[1].forEach(function(t) { @@ -729,7 +888,7 @@ function parse_TST_TableModelArchive(M, root, ws) { var _tile = parse_TST_Tile(M, ref2); _tile.data.forEach(function(row, R) { row.forEach(function(buf, C) { - var res = parse_cell_storage(buf, sst, rsst); + var res = parse_cell_storage(buf, lut); if (res) { if (dense) { if (!ws[_R + R]) @@ -744,12 +903,12 @@ function parse_TST_TableModelArchive(M, root, ws) { }); _R += _tile.nrows; }); - if ((_b = store[13]) == null ? void 0 : _b[0]) { + if ((_e = store[13]) == null ? void 0 : _e[0]) { var ref = M[parse_TSP_Reference(store[13][0].data)][0]; var mtype = varint_to_i32(ref.meta[1][0].data); if (mtype != 6144) throw new Error("Expected merge type 6144, found ".concat(mtype)); - ws["!merges"] = (_c = parse_shallow(ref.data)) == null ? void 0 : _c[1].map(function(pi) { + ws["!merges"] = (_f = parse_shallow(ref.data)) == null ? void 0 : _f[1].map(function(pi) { var merge = parse_shallow(pi.data); var origin = u8_to_dataview(parse_shallow(merge[1][0].data)[1][0].data), size = u8_to_dataview(parse_shallow(merge[2][0].data)[1][0].data); return { diff --git a/modules/83_numbers.js b/modules/83_numbers.js index bdafa36..e716f9f 100644 --- a/modules/83_numbers.js +++ b/modules/83_numbers.js @@ -411,37 +411,168 @@ function compress_iwa_file(buf) { } return u8concat(out); } -function parse_old_storage(buf, sst, rsst, v) { +var numbers_lut_new = function() { + return { sst: [], rsst: [], ofmt: [], nfmt: [] }; +}; +function numbers_format_cell(cell, t, flags, ofmt, nfmt) { + var _a, _b, _c, _d; + var ctype = t & 255, ver = t >> 8; + var fmt = ver >= 5 ? nfmt : ofmt; + dur: + if (flags & (ver > 4 ? 8 : 4) && cell.t == "n" && ctype == 7) { + var dstyle = ((_a = fmt[7]) == null ? void 0 : _a[0]) ? parse_varint49(fmt[7][0].data) : -1; + var dmin = ((_b = fmt[15]) == null ? void 0 : _b[0]) ? parse_varint49(fmt[15][0].data) : -1; + var dmax = ((_c = fmt[16]) == null ? void 0 : _c[0]) ? parse_varint49(fmt[16][0].data) : -1; + var auto = ((_d = fmt[40]) == null ? void 0 : _d[0]) ? parse_varint49(fmt[40][0].data) : -1; + if (dstyle == -1) + break dur; + var d = cell.v, dd = d; + autodur: + if (auto) { + if (d == 0) { + dmin = dmax = 2; + break autodur; + } + if (d >= 604800) + dmin = 1; + else if (d >= 86400) + dmin = 2; + else if (d >= 3600) + dmin = 4; + else if (d >= 60) + dmin = 8; + else if (d >= 1) + dmin = 16; + else + dmin = 32; + if (Math.floor(d) != d) + dmax = 32; + else if (d % 60) + dmax = 16; + else if (d % 3600) + dmax = 8; + else if (d % 86400) + dmax = 4; + else if (d % 604800) + dmax = 2; + if (dmax < dmin) + dmax = dmin; + } + if (dmin == -1 || dmax == -1) + break dur; + var dstr = [], zstr = []; + if (dmin == 1) { + dd = d / 604800; + if (dmax == 1) { + zstr.push('d"d"'); + } else { + dd |= 0; + d -= 604800 * dd; + } + dstr.push(dd + (dstyle == 2 ? " week" + (dd == 1 ? "" : "s") : dstyle == 1 ? "w" : "")); + } + if (dmin <= 2 && dmax >= 2) { + dd = d / 86400; + if (dmax > 2) { + dd |= 0; + d -= 86400 * dd; + } + zstr.push('d"d"'); + dstr.push(dd + (dstyle == 2 ? " day" + (dd == 1 ? "" : "s") : dstyle == 1 ? "d" : "")); + } + if (dmin <= 4 && dmax >= 4) { + dd = d / 3600; + if (dmax > 4) { + dd |= 0; + d -= 3600 * dd; + } + zstr.push((dmin >= 4 ? "[h]" : "h") + '"h"'); + dstr.push(dd + (dstyle == 2 ? " hour" + (dd == 1 ? "" : "s") : dstyle == 1 ? "h" : "")); + } + if (dmin <= 8 && dmax >= 8) { + dd = d / 60; + if (dmax > 8) { + dd |= 0; + d -= 60 * dd; + } + zstr.push((dmin >= 8 ? "[m]" : "m") + '"m"'); + if (dstyle == 0) + dstr.push((dmin == 8 && dmax == 8 || dd >= 10 ? "" : "0") + dd); + else + dstr.push(dd + (dstyle == 2 ? " minute" + (dd == 1 ? "" : "s") : dstyle == 1 ? "m" : "")); + } + if (dmin <= 16 && dmax >= 16) { + dd = d; + if (dmax > 16) { + dd |= 0; + d -= dd; + } + zstr.push((dmin >= 16 ? "[s]" : "s") + '"s"'); + if (dstyle == 0) + dstr.push((dmax == 16 && dmin == 16 || dd >= 10 ? "" : "0") + dd); + else + dstr.push(dd + (dstyle == 2 ? " second" + (dd == 1 ? "" : "s") : dstyle == 1 ? "s" : "")); + } + if (dmax >= 32) { + dd = Math.round(1e3 * d); + if (dmin < 32) + zstr.push('.000"ms"'); + if (dstyle == 0) + dstr.push((dd >= 100 ? "" : dd >= 10 ? "0" : "00") + dd); + else + dstr.push(dd + (dstyle == 2 ? " millisecond" + (dd == 1 ? "" : "s") : dstyle == 1 ? "ms" : "")); + } + cell.w = dstr.join(dstyle == 0 ? ":" : " "); + cell.z = zstr.join(dstyle == 0 ? '":"' : " "); + if (dstyle == 0) + cell.w = cell.w.replace(/:(\d\d\d)$/, ".$1"); + } +} +function parse_old_storage(buf, lut, v) { var dv = u8_to_dataview(buf); var flags = dv.getUint32(4, true); - var data_offset = (v > 1 ? 12 : 8) + popcnt(flags & (v > 1 ? 3470 : 398)) * 4; - var ridx = -1, sidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); - if (flags & 512) { - ridx = dv.getUint32(data_offset, true); - data_offset += 4; + var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); + var doff = v > 1 ? 12 : 8; + if (flags & 2) { + zidx = dv.getUint32(doff, true); + doff += 4; } - data_offset += popcnt(flags & (v > 1 ? 12288 : 4096)) * 4; + doff += popcnt(flags & (v > 1 ? 3468 : 396)) * 4; + if (flags & 512) { + ridx = dv.getUint32(doff, true); + doff += 4; + } + doff += popcnt(flags & (v > 1 ? 12288 : 4096)) * 4; if (flags & 16) { - sidx = dv.getUint32(data_offset, true); - data_offset += 4; + sidx = dv.getUint32(doff, true); + doff += 4; } if (flags & 32) { - ieee = dv.getFloat64(data_offset, true); - data_offset += 8; + ieee = dv.getFloat64(doff, true); + doff += 8; } if (flags & 64) { - dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); - data_offset += 8; + dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1e3); + doff += 8; + } + if (v > 1) { + flags = dv.getUint32(8, true) >>> 16; + if (flags & 255) { + if (zidx == -1) + zidx = dv.getUint32(doff, true); + doff += 4; + } } var ret; - switch (buf[2]) { + var t = buf[v >= 4 ? 1 : 2]; + switch (t) { case 0: return void 0; case 2: ret = { t: "n", v: ieee }; break; case 3: - ret = { t: "s", v: sst[sidx] }; + ret = { t: "s", v: lut.sst[sidx] }; break; case 5: ret = { t: "d", v: dt }; @@ -450,7 +581,7 @@ function parse_old_storage(buf, sst, rsst, v) { ret = { t: "b", v: ieee > 0 }; break; case 7: - ret = { t: "n", v: ieee / 86400 }; + ret = { t: "n", v: ieee }; break; case 8: ret = { t: "e", v: 0 }; @@ -458,7 +589,7 @@ function parse_old_storage(buf, sst, rsst, v) { case 9: { if (ridx > -1) - ret = { t: "s", v: rsst[ridx] }; + ret = { t: "s", v: lut.rsst[ridx] }; else throw new Error("Unsupported cell type ".concat(buf[subarray](0, 4))); } @@ -466,42 +597,53 @@ function parse_old_storage(buf, sst, rsst, v) { default: throw new Error("Unsupported cell type ".concat(buf[subarray](0, 4))); } + if (zidx > -1) + numbers_format_cell(ret, t | v << 8, flags, lut.ofmt[zidx], lut.nfmt[zidx]); + if (t == 7) + ret.v /= 86400; return ret; } -function parse_new_storage(buf, sst, rsst) { +function parse_new_storage(buf, lut) { var dv = u8_to_dataview(buf); var flags = dv.getUint32(8, true); - var data_offset = 12; - var ridx = -1, sidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); + var doff = 12; + var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); if (flags & 1) { - d128 = readDecimal128LE(buf, data_offset); - data_offset += 16; + d128 = readDecimal128LE(buf, doff); + doff += 16; } if (flags & 2) { - ieee = dv.getFloat64(data_offset, true); - data_offset += 8; + ieee = dv.getFloat64(doff, true); + doff += 8; } if (flags & 4) { - dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); - data_offset += 8; + dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1e3); + doff += 8; } if (flags & 8) { - sidx = dv.getUint32(data_offset, true); - data_offset += 4; + sidx = dv.getUint32(doff, true); + doff += 4; } if (flags & 16) { - ridx = dv.getUint32(data_offset, true); - data_offset += 4; + ridx = dv.getUint32(doff, true); + doff += 4; + } + doff += popcnt(flags & 8160) * 4; + if (flags & 516096) { + if (zidx == -1) + zidx = dv.getUint32(doff, true); + doff += 4; } var ret; - switch (buf[1]) { + var t = buf[1]; + switch (t) { case 0: return void 0; case 2: ret = { t: "n", v: d128 }; break; case 3: - ret = { t: "s", v: sst[sidx] }; + ret = { t: "s", v: lut.sst[sidx] }; break; case 5: ret = { t: "d", v: dt }; @@ -510,7 +652,7 @@ function parse_new_storage(buf, sst, rsst) { ret = { t: "b", v: ieee > 0 }; break; case 7: - ret = { t: "n", v: ieee / 86400 }; + ret = { t: "n", v: ieee }; break; case 8: ret = { t: "e", v: 0 }; @@ -518,7 +660,7 @@ function parse_new_storage(buf, sst, rsst) { case 9: { if (ridx > -1) - ret = { t: "s", v: rsst[ridx] }; + ret = { t: "s", v: lut.rsst[ridx] }; else throw new Error("Unsupported cell type ".concat(buf[1], " : ").concat(flags & 31, " : ").concat(buf[subarray](0, 4))); } @@ -529,6 +671,10 @@ function parse_new_storage(buf, sst, rsst) { default: throw new Error("Unsupported cell type ".concat(buf[1], " : ").concat(flags & 31, " : ").concat(buf[subarray](0, 4))); } + if (zidx > -1) + numbers_format_cell(ret, t | 5 << 8, flags >> 13, lut.ofmt[zidx], lut.nfmt[zidx]); + if (t == 7) + ret.v /= 86400; return ret; } function write_new_storage(cell, sst) { @@ -591,15 +737,16 @@ function write_old_storage(cell, sst) { dv.setUint32(4, flags, true); return out[subarray](0, l); } -function parse_cell_storage(buf, sst, rsst) { +function parse_cell_storage(buf, lut) { switch (buf[0]) { case 0: case 1: case 2: case 3: - return parse_old_storage(buf, sst, rsst, buf[0]); + case 4: + return parse_old_storage(buf, lut, buf[0]); case 5: - return parse_new_storage(buf, sst, rsst); + return parse_new_storage(buf, lut); default: throw new Error("Unsupported payload version ".concat(buf[0])); } @@ -640,6 +787,11 @@ function parse_TST_TableDataList(M, root) { }).join(""); } break; + case 2: + data[key] = parse_shallow(le[6][0].data); + break; + default: + throw type; } }); return data; @@ -704,7 +856,7 @@ function parse_TST_Tile(M, root) { }; } function parse_TST_TableModelArchive(M, root, ws) { - var _a, _b, _c; + var _a, _b, _c, _d, _e, _f; var pb = parse_shallow(root.data); var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } }; range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1; @@ -716,8 +868,15 @@ function parse_TST_TableModelArchive(M, root, ws) { ws["!ref"] = encode_range(range); var dense = Array.isArray(ws); var store = parse_shallow(pb[4][0].data); - var sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); - var rsst = ((_a = store[17]) == null ? void 0 : _a[0]) ? parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]) : []; + var lut = numbers_lut_new(); + if ((_a = store[4]) == null ? void 0 : _a[0]) + lut.sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); + if ((_b = store[11]) == null ? void 0 : _b[0]) + lut.ofmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[11][0].data)][0]); + if ((_c = store[17]) == null ? void 0 : _c[0]) + lut.rsst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]); + if ((_d = store[22]) == null ? void 0 : _d[0]) + lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]); var tile = parse_shallow(store[3][0].data); var _R = 0; tile[1].forEach(function(t) { @@ -729,7 +888,7 @@ function parse_TST_TableModelArchive(M, root, ws) { var _tile = parse_TST_Tile(M, ref2); _tile.data.forEach(function(row, R) { row.forEach(function(buf, C) { - var res = parse_cell_storage(buf, sst, rsst); + var res = parse_cell_storage(buf, lut); if (res) { if (dense) { if (!ws[_R + R]) @@ -744,12 +903,12 @@ function parse_TST_TableModelArchive(M, root, ws) { }); _R += _tile.nrows; }); - if ((_b = store[13]) == null ? void 0 : _b[0]) { + if ((_e = store[13]) == null ? void 0 : _e[0]) { var ref = M[parse_TSP_Reference(store[13][0].data)][0]; var mtype = varint_to_i32(ref.meta[1][0].data); if (mtype != 6144) throw new Error("Expected merge type 6144, found ".concat(mtype)); - ws["!merges"] = (_c = parse_shallow(ref.data)) == null ? void 0 : _c[1].map(function(pi) { + ws["!merges"] = (_f = parse_shallow(ref.data)) == null ? void 0 : _f[1].map(function(pi) { var merge = parse_shallow(pi.data); var origin = u8_to_dataview(parse_shallow(merge[1][0].data)[1][0].data), size = u8_to_dataview(parse_shallow(merge[2][0].data)[1][0].data); return { diff --git a/modules/83_numbers.ts b/modules/83_numbers.ts index 5dcfc34..c5ca1b0 100644 --- a/modules/83_numbers.ts +++ b/modules/83_numbers.ts @@ -356,75 +356,174 @@ function compress_iwa_file(buf: Uint8Array): Uint8Array { } //< ({ sst: [], rsst: [], ofmt: [], nfmt: [] }); + +function numbers_format_cell(cell: CellObject, t: number, flags: number, ofmt: ProtoMessage, nfmt: ProtoMessage): void { + var ctype = t & 0xFF, ver = t >> 8; + var fmt = ver >= 5 ? nfmt : ofmt; + dur: if((flags & (ver > 4 ? 8: 4)) && cell.t == "n" && ctype == 7) { + var dstyle = (fmt[7]?.[0]) ? parse_varint49(fmt[7][0].data) : -1; + if(dstyle == -1) break dur; + var dmin = (fmt[15]?.[0]) ? parse_varint49(fmt[15][0].data) : -1; + var dmax = (fmt[16]?.[0]) ? parse_varint49(fmt[16][0].data) : -1; + var auto = (fmt[40]?.[0]) ? parse_varint49(fmt[40][0].data) : -1; + var d: number = cell.v as number, dd = d; + autodur: if(auto) { // TODO: check if numbers reformats on load + if(d == 0) { dmin = dmax = 2; break autodur; } + if(d >= 604800) dmin = 1; + else if(d >= 86400) dmin = 2; + else if(d >= 3600) dmin = 4; + else if(d >= 60) dmin = 8; + else if(d >= 1) dmin = 16; + else dmin = 32; + if(Math.floor(d) != d) dmax = 32; + else if(d % 60) dmax = 16; + else if(d % 3600) dmax = 8; + else if(d % 86400) dmax = 4; + else if(d % 604800) dmax = 2; + if(dmax < dmin) dmax = dmin; + } + if(dmin == -1 || dmax == -1) break dur; + var dstr: string[] = [], zstr: string[] = []; + /* TODO: plurality, SSF equivalents */ + if(dmin == 1) { + dd = d / 604800; + if(dmax == 1) { zstr.push('d"d"'); } else { dd |= 0; d -= 604800 * dd; } + dstr.push(dd + (dstyle == 2 ? " week" + (dd == 1 ? "" : "s") : dstyle == 1 ? "w": "")); + } + if(dmin <= 2 && dmax >= 2) { + dd = d / 86400; + if(dmax > 2) { dd |= 0; d -= 86400 * dd; } + zstr.push("d" + '"d"'); + dstr.push(dd + (dstyle == 2 ? " day" + (dd == 1 ? "" : "s") : dstyle == 1 ? "d" : "")); + } + if(dmin <= 4 && dmax >= 4) { + dd = d / 3600; + if(dmax > 4) { dd |= 0; d -= 3600 * dd; } + zstr.push((dmin >= 4 ? "[h]" : "h") + '"h"'); + dstr.push(dd + (dstyle == 2 ? " hour" + (dd == 1 ? "" : "s") : dstyle == 1 ? "h" : "")); + } + if(dmin <= 8 && dmax >= 8) { + dd = d / 60; + if(dmax > 8) { dd |= 0; d -= 60 * dd; } + zstr.push((dmin >= 8 ? "[m]" : "m") + '"m"'); + if(dstyle == 0) dstr.push(((dmin == 8 && dmax == 8 || dd >= 10) ? "" : "0") + dd) + else dstr.push(dd + (dstyle == 2 ? " minute" + (dd == 1 ? "" : "s") : dstyle == 1 ? "m" : "")); + } + if(dmin <= 16 && dmax >= 16) { + dd = d; + if(dmax > 16) { dd |= 0; d -= dd; } + zstr.push((dmin >= 16 ? "[s]" : "s") + '"s"'); + if(dstyle == 0) dstr.push((dmax == 16 && dmin == 16 || dd >= 10 ? "" : "0") + dd) + else dstr.push(dd + (dstyle == 2 ? " second" + (dd == 1 ? "" : "s") : dstyle == 1 ? "s" : "")); + } + if(dmax >= 32) { + dd = Math.round(1000 * d); + if(dmin < 32) zstr.push(".000" + '"ms"'); + if(dstyle == 0) dstr.push((dd >= 100 ? "" : dd >= 10 ? "0" : "00") + dd) + else dstr.push(dd + (dstyle == 2 ? " millisecond" + (dd == 1 ? "" : "s") : dstyle == 1 ? "ms" : "")); + } + cell.w = dstr.join(dstyle == 0 ? ":" : " "); cell.z = zstr.join(dstyle == 0 ? '":"': " "); + if(dstyle == 0) cell.w = cell.w.replace(/:(\d\d\d)$/, ".$1"); + } +} + +/** Parse "old storage" (version 0..4) */ +function parse_old_storage(buf: Uint8Array, lut: DataLUT, v: 0|1|2|3|4): CellObject | void { var dv = u8_to_dataview(buf); var flags = dv.getUint32(4, true); - /* TODO: find the correct field position of number formats, formulae, etc */ - var data_offset = (v > 1 ? 12 : 8) + popcnt(flags & (v > 1 ? 0x0D8E : 0x018E)) * 4; + var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); + var doff = (v > 1 ? 12 : 8); + if(flags & 0x0002) { zidx = dv.getUint32(doff, true); doff += 4;} + doff += popcnt(flags & (v > 1 ? 0x0D8C : 0x018C)) * 4; - var ridx = -1, sidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); - if(flags & 0x0200) { ridx = dv.getUint32(data_offset, true); data_offset += 4; } - data_offset += popcnt(flags & (v > 1 ? 0x3000 : 0x1000)) * 4; - if(flags & 0x0010) { sidx = dv.getUint32(data_offset, true); data_offset += 4; } - if(flags & 0x0020) { ieee = dv.getFloat64(data_offset, true); data_offset += 8; } - if(flags & 0x0040) { dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1000); data_offset += 8; } + if(flags & 0x0200) { ridx = dv.getUint32(doff, true); doff += 4; } + doff += popcnt(flags & (v > 1 ? 0x3000 : 0x1000)) * 4; + if(flags & 0x0010) { sidx = dv.getUint32(doff, true); doff += 4; } + if(flags & 0x0020) { ieee = dv.getFloat64(doff, true); doff += 8; } + if(flags & 0x0040) { dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1000); doff += 8; } + + if(v > 1) { + flags = dv.getUint32(8, true) >>> 16; + /* TODO: stress test if a cell can have multiple sub-type formats */ + if(flags & 0xFF) { if(zidx == -1) zidx = dv.getUint32(doff, true); doff += 4; } + } var ret: CellObject; - switch(buf[2]) { + var t = buf[v >= 4 ? 1 : 2]; + switch(t) { case 0: return void 0; // return { t: "z" }; // blank? case 2: ret = { t: "n", v: ieee }; break; // number - case 3: ret = { t: "s", v: sst[sidx] }; break; // string + case 3: ret = { t: "s", v: lut.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 / 86400 }; break; // duration in seconds TODO: emit [hh]:[mm] style format with adjusted value + case 7: ret = { t: "n", v: ieee }; break; // duration in seconds case 8: ret = { t: "e", v: 0}; break; // "formula error" TODO: enumerate and map errors to csf equivalents case 9: { // "rich text" - if(ridx > -1) ret = { t: "s", v: rsst[ridx] }; + if(ridx > -1) ret = { t: "s", v: lut.rsst[ridx] }; else throw new Error(`Unsupported cell type ${buf[subarray](0,4)}`); } break; default: throw new Error(`Unsupported cell type ${buf[subarray](0,4)}`); } - /* TODO: Some fields appear after the cell data */ + if(zidx > -1) numbers_format_cell(ret, t | (v<<8), flags, lut.ofmt[zidx], lut.nfmt[zidx]); + if(t == 7) (ret.v as number) /= 86400; return ret; } /** Parse "new storage" (version 5) */ -function parse_new_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObject | void { +function parse_new_storage(buf: Uint8Array, lut: DataLUT): CellObject | void { var dv = u8_to_dataview(buf); var flags = dv.getUint32(8, true); /* TODO: find the correct field position of number formats, formulae, etc */ - var data_offset = 12; + var doff = 12; - var ridx = -1, sidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); + var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); - if(flags & 0x0001) { d128 = readDecimal128LE(buf, data_offset); data_offset += 16; } - if(flags & 0x0002) { ieee = dv.getFloat64(data_offset, true); data_offset += 8; } - if(flags & 0x0004) { dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1000); data_offset += 8; } - if(flags & 0x0008) { sidx = dv.getUint32(data_offset, true); data_offset += 4; } - if(flags & 0x0010) { ridx = dv.getUint32(data_offset, true); data_offset += 4; } + if(flags & 0x0001) { d128 = readDecimal128LE(buf, doff); doff += 16; } + if(flags & 0x0002) { ieee = dv.getFloat64(doff, true); doff += 8; } + if(flags & 0x0004) { dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1000); doff += 8; } + if(flags & 0x0008) { sidx = dv.getUint32(doff, true); doff += 4; } + if(flags & 0x0010) { ridx = dv.getUint32(doff, true); doff += 4; } + + doff += popcnt(flags & 0x1FE0) * 4; + + /* TODO: stress test if a cell can have multiple sub-type formats */ + if(flags & 0x7E000) { if(zidx == -1) zidx = dv.getUint32(doff, true); doff += 4; } var ret: CellObject; - switch(buf[1]) { + var t = buf[1]; + switch(t) { case 0: return void 0; // return { t: "z" }; // blank? case 2: ret = { t: "n", v: d128 }; break; // number - case 3: ret = { t: "s", v: sst[sidx] }; break; // string + case 3: ret = { t: "s", v: lut.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 / 86400 }; break; // duration in seconds TODO: emit [hh]:[mm] style format with adjusted value + case 7: ret = { t: "n", v: ieee }; 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: { // "rich text" - if(ridx > -1) ret = { t: "s", v: rsst[ridx] }; + if(ridx > -1) ret = { t: "s", v: lut.rsst[ridx] }; else throw new Error(`Unsupported cell type ${buf[1]} : ${flags & 0x1F} : ${buf[subarray](0,4)}`); } break; case 10: ret = { t: "n", v: d128 }; break; // currency default: throw new Error(`Unsupported cell type ${buf[1]} : ${flags & 0x1F} : ${buf[subarray](0,4)}`); } - /* TODO: All styling fields appear after the cell data */ + if(zidx > -1) numbers_format_cell(ret, t | (5<<8), flags >> 13, lut.ofmt[zidx], lut.nfmt[zidx] ); + if(t == 7) (ret.v as number) /= 86400; return ret; } @@ -459,11 +558,11 @@ function write_old_storage(cell: CellObject, sst: string[]): Uint8Array { return out[subarray](0, l); } //< = []; + var data: any[] = []; (entries||[]).forEach(entry => { // .TST.TableDataList.ListEntry var le = parse_shallow(entry.data); @@ -516,6 +615,8 @@ function parse_TST_TableDataList(M: MessageSpace, root: IWAMessage): string[] { data[key] = tswpsa[3].map(x => u8str(x.data)).join(""); } break; + case 2: data[key] = parse_shallow(le[6][0].data); break; + default: throw type; } }); return data; @@ -595,8 +696,11 @@ function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: Work var dense = Array.isArray(ws); // .TST.DataStore var store = parse_shallow(pb[4][0].data); - var sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); - var rsst: string[] = store[17]?.[0] ? parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]) : []; + var lut: DataLUT = numbers_lut_new(); + if(store[4]?.[0]) lut.sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); + if(store[11]?.[0]) lut.ofmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[11][0].data)][0]); + if(store[17]?.[0]) lut.rsst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]); + if(store[22]?.[0]) lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]); // .TST.TileStorage var tile = parse_shallow(store[3][0].data); @@ -611,7 +715,7 @@ function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: Work var _tile = parse_TST_Tile(M, ref); _tile.data.forEach((row, R) => { row.forEach((buf, C) => { - var res = parse_cell_storage(buf, sst, rsst); + var res = parse_cell_storage(buf, lut); if(res) { if(dense) { if(!ws[_R + R]) ws[_R + R] = []; diff --git a/test_files b/test_files index f91c73f..787cc72 160000 --- a/test_files +++ b/test_files @@ -1 +1 @@ -Subproject commit f91c73f99ccb7919b7992e720f9ba7a730071770 +Subproject commit 787cc72932acf77ac58018d60d934b65847b16a3