diff --git a/bits/32_odmanrdf.js b/bits/32_odmanrdf.js index 0865a68..85b2ab9 100644 --- a/bits/32_odmanrdf.js +++ b/bits/32_odmanrdf.js @@ -1,62 +1,61 @@ -/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */ -/* Part 3 Section 4 Manifest File */ var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet"; function parse_manifest(d, opts) { - var str = xlml_normalize(d); - var Rn; - var FEtag; - while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { - case 'manifest': break; // 4.2 <manifest:manifest> - case 'file-entry': // 4.3 <manifest:file-entry> - FEtag = parsexmltag(Rn[0], false); - if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet"); - break; - case 'encryption-data': // 4.4 <manifest:encryption-data> - case 'algorithm': // 4.5 <manifest:algorithm> - case 'start-key-generation': // 4.6 <manifest:start-key-generation> - case 'key-derivation': // 4.7 <manifest:key-derivation> - throw new Error("Unsupported ODS Encryption"); - default: if(opts && opts.WTF) throw Rn; - } + var str = xlml_normalize(d); + var Rn; + var FEtag; + while (Rn = xlmlregex.exec(str)) + switch (Rn[3]) { + case "manifest": + break; + case "file-entry": + FEtag = parsexmltag(Rn[0], false); + if (FEtag.path == "/" && FEtag.type !== CT_ODS) + throw new Error("This OpenDocument is not a spreadsheet"); + break; + case "encryption-data": + case "algorithm": + case "start-key-generation": + case "key-derivation": + throw new Error("Unsupported ODS Encryption"); + default: + if (opts && opts.WTF) + throw Rn; + } } - -function write_manifest(manifest/*:Array<Array<string> >*/)/*:string*/ { - var o = [XML_HEADER]; - o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n'); - o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n'); - for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n'); - o.push('</manifest:manifest>'); - return o.join(""); +function write_manifest(manifest) { + var o = [XML_HEADER]; + o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n'); + o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n'); + for (var i = 0; i < manifest.length; ++i) + o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n'); + o.push("</manifest:manifest>"); + return o.join(""); } - -/* Part 3 Section 6 Metadata Manifest File */ -function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) { - return [ - ' <rdf:Description rdf:about="' + file + '">\n', - ' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n', - ' </rdf:Description>\n' - ].join(""); +function write_rdf_type(file, res, tag) { + return [ + ' <rdf:Description rdf:about="' + file + '">\n', + ' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + "#" + res + '"/>\n', + " </rdf:Description>\n" + ].join(""); } -function write_rdf_has(base/*:string*/, file/*:string*/) { - return [ - ' <rdf:Description rdf:about="' + base + '">\n', - ' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n', - ' </rdf:Description>\n' - ].join(""); +function write_rdf_has(base, file) { + return [ + ' <rdf:Description rdf:about="' + base + '">\n', + ' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n', + " </rdf:Description>\n" + ].join(""); } function write_rdf(rdf) { - var o = [XML_HEADER]; - o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n'); - for(var i = 0; i != rdf.length; ++i) { - o.push(write_rdf_type(rdf[i][0], rdf[i][1])); - o.push(write_rdf_has("",rdf[i][0])); - } - o.push(write_rdf_type("","Document", "pkg")); - o.push('</rdf:RDF>'); - return o.join(""); + var o = [XML_HEADER]; + o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n'); + for (var i = 0; i != rdf.length; ++i) { + o.push(write_rdf_type(rdf[i][0], rdf[i][1])); + o.push(write_rdf_has("", rdf[i][0])); + } + o.push(write_rdf_type("", "Document", "pkg")); + o.push("</rdf:RDF>"); + return o.join(""); } -/* TODO: pull properties */ -function write_meta_ods(/*:: wb: Workbook, opts: any*/)/*:string*/ { - return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>'; +function write_meta_ods(wb, opts) { + return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>SheetJS ' + XLSX.version + "</meta:generator></office:meta></office:document-meta>"; } - diff --git a/bits/79_html.js b/bits/79_html.js index 4406332..4f66387 100644 --- a/bits/79_html.js +++ b/bits/79_html.js @@ -83,7 +83,7 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT sp["data-t"] = cell && cell.t || 'z'; if(cell.v != null) sp["data-v"] = cell.v; if(cell.z != null) sp["data-z"] = cell.z; - if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + cell.l.Target +'">' + w + '</a>'; + if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + escapehtml(cell.l.Target) +'">' + w + '</a>'; } sp.id = (o.id || "sjs") + "-" + coord; oo.push(writextag('td', w, sp)); diff --git a/modules/32_odmanrdf.js b/modules/32_odmanrdf.js new file mode 100644 index 0000000..85b2ab9 --- /dev/null +++ b/modules/32_odmanrdf.js @@ -0,0 +1,61 @@ +var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet"; +function parse_manifest(d, opts) { + var str = xlml_normalize(d); + var Rn; + var FEtag; + while (Rn = xlmlregex.exec(str)) + switch (Rn[3]) { + case "manifest": + break; + case "file-entry": + FEtag = parsexmltag(Rn[0], false); + if (FEtag.path == "/" && FEtag.type !== CT_ODS) + throw new Error("This OpenDocument is not a spreadsheet"); + break; + case "encryption-data": + case "algorithm": + case "start-key-generation": + case "key-derivation": + throw new Error("Unsupported ODS Encryption"); + default: + if (opts && opts.WTF) + throw Rn; + } +} +function write_manifest(manifest) { + var o = [XML_HEADER]; + o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n'); + o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n'); + for (var i = 0; i < manifest.length; ++i) + o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n'); + o.push("</manifest:manifest>"); + return o.join(""); +} +function write_rdf_type(file, res, tag) { + return [ + ' <rdf:Description rdf:about="' + file + '">\n', + ' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + "#" + res + '"/>\n', + " </rdf:Description>\n" + ].join(""); +} +function write_rdf_has(base, file) { + return [ + ' <rdf:Description rdf:about="' + base + '">\n', + ' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n', + " </rdf:Description>\n" + ].join(""); +} +function write_rdf(rdf) { + var o = [XML_HEADER]; + o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n'); + for (var i = 0; i != rdf.length; ++i) { + o.push(write_rdf_type(rdf[i][0], rdf[i][1])); + o.push(write_rdf_has("", rdf[i][0])); + } + o.push(write_rdf_type("", "Document", "pkg")); + o.push("</rdf:RDF>"); + return o.join(""); +} +function write_meta_ods(wb, opts) { + return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>SheetJS ' + XLSX.version + "</meta:generator></office:meta></office:document-meta>"; +} diff --git a/modules/32_odmanrdf.ts b/modules/32_odmanrdf.ts new file mode 100644 index 0000000..83552be --- /dev/null +++ b/modules/32_odmanrdf.ts @@ -0,0 +1,73 @@ +/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */ + +import { WorkBook, ParsingOptions } from '../'; +import * as _XLSX from '../'; +declare var XLSX: typeof _XLSX; + +type RawData = any; +declare var XML_HEADER: string; +declare var xlmlregex: RegExp; +declare function parsexmltag(tag: string, skip_root?: boolean, skip_LC?: boolean): any; +declare function xlml_normalize(d: RawData): string; +type RDF = [string, string][]; + +/* Part 3 Section 4 Manifest File */ +var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet"; +function parse_manifest(d: RawData, opts?: ParsingOptions) { + var str = xlml_normalize(d); + var Rn: RegExpExecArray | null; + var FEtag; + while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { + case 'manifest': break; // 4.2 <manifest:manifest> + case 'file-entry': // 4.3 <manifest:file-entry> + FEtag = parsexmltag(Rn[0], false); + if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet"); + break; + case 'encryption-data': // 4.4 <manifest:encryption-data> + case 'algorithm': // 4.5 <manifest:algorithm> + case 'start-key-generation': // 4.6 <manifest:start-key-generation> + case 'key-derivation': // 4.7 <manifest:key-derivation> + throw new Error("Unsupported ODS Encryption"); + default: if(opts && opts.WTF) throw Rn; + } +} + +function write_manifest(manifest: RDF): string { + var o = [XML_HEADER]; + o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n'); + o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n'); + for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n'); + o.push('</manifest:manifest>'); + return o.join(""); +} + +/* Part 3 Section 6 Metadata Manifest File */ +function write_rdf_type(file: string, res: string, tag?: string): string { + return [ + ' <rdf:Description rdf:about="' + file + '">\n', + ' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n', + ' </rdf:Description>\n' + ].join(""); +} +function write_rdf_has(base: string, file: string): string { + return [ + ' <rdf:Description rdf:about="' + base + '">\n', + ' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n', + ' </rdf:Description>\n' + ].join(""); +} +function write_rdf(rdf: RDF): string { + var o: string[] = [XML_HEADER]; + o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n'); + for(var i = 0; i != rdf.length; ++i) { + o.push(write_rdf_type(rdf[i][0], rdf[i][1])); + o.push(write_rdf_has("",rdf[i][0])); + } + o.push(write_rdf_type("","Document", "pkg")); + o.push('</rdf:RDF>'); + return o.join(""); +} +/* TODO: pull properties */ +function write_meta_ods(wb?: WorkBook, opts?: any): string { + return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>'; +} \ No newline at end of file diff --git a/modules/45_rtf.ts b/modules/45_rtf.ts index 71ee5c7..449a238 100644 --- a/modules/45_rtf.ts +++ b/modules/45_rtf.ts @@ -1,5 +1,6 @@ -import { WorkBook, WorkSheet, Range, CellObject, DenseSheet, SparseSheet } from '../'; +import { WorkBook, WorkSheet, Range, CellObject, DenseSheet, SparseSheet, ParsingOptions, WritingOptions } from '../'; import type { utils } from "../"; +type RawData = any; declare var encode_cell: typeof utils.encode_cell; declare var encode_range: typeof utils.encode_range; @@ -12,7 +13,7 @@ declare var has_buf: boolean; declare function Base64_decode(s: string): string; declare function fuzzynum(s: string): number; -function rtf_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ { +function rtf_to_sheet(d: RawData, opts: ParsingOptions): WorkSheet { switch(opts.type) { case 'base64': return rtf_to_sheet_str(Base64_decode(d), opts); case 'binary': return rtf_to_sheet_str(d, opts); @@ -23,7 +24,7 @@ function rtf_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ { } /* TODO: this is a stub */ -function rtf_to_sheet_str(str: string, opts)/*:Worksheet*/ { +function rtf_to_sheet_str(str: string, opts: ParsingOptions): WorkSheet { var o = opts || {}; // ESBuild issue 2375 var ws: WorkSheet = {} as WorkSheet; @@ -71,14 +72,14 @@ function rtf_to_sheet_str(str: string, opts)/*:Worksheet*/ { return ws; } -function rtf_to_workbook(d/*:RawData*/, opts): WorkBook { +function rtf_to_workbook(d: RawData, opts: ParsingOptions): WorkBook { var wb: WorkBook = sheet_to_workbook(rtf_to_sheet(d, opts), opts); wb.bookType = "rtf"; return wb; } /* TODO: this is a stub */ -function sheet_to_rtf(ws: WorkSheet, opts): string { +function sheet_to_rtf(ws: WorkSheet, opts: WritingOptions): string { var o: string[] = ["{\\rtf1\\ansi"]; if(!ws["!ref"]) return o[0] + "}"; var r = safe_decode_range(ws['!ref']), cell: CellObject; diff --git a/modules/83_numbers.ts b/modules/83_numbers.ts index 68b250c..d260418 100644 --- a/modules/83_numbers.ts +++ b/modules/83_numbers.ts @@ -214,7 +214,7 @@ function write_shallow(proto: ProtoMessage): Uint8Array { //<<export { parse_shallow, write_shallow }; /** Map over each entry in a repeated (or single-value) field */ -function mappa<U>(data: ProtoField, cb:(Uint8Array) => U): U[] { +function mappa<U>(data: ProtoField, cb: (u: Uint8Array) => U): U[] { return data?.map(d => cb(d.data)) || []; } @@ -874,9 +874,9 @@ function parse_numbers_iwa(cfb: CFB$Container, opts?: ParsingOptions ): WorkBook if(!s.name.match(/\.iwa$/)) return; if(s.content[0] != 0) return; // TODO: this should test if the iwa follows the framing format var o: Uint8Array; - try { o = decompress_iwa_file(s.content as Uint8Array); } catch(e) { return console.log("?? " + s.content.length + " " + (e.message || e)); } + try { o = decompress_iwa_file(s.content as Uint8Array); } catch(e: any) { return console.log("?? " + s.content.length + " " + ((e as Error).message || e)); } var packets: IWAArchiveInfo[]; - try { packets = parse_iwa_file(o); } catch(e) { return console.log("## " + (e.message || e)); } + try { packets = parse_iwa_file(o); } catch(e: any) { return console.log("## " + ((e as Error).message || e)); } packets.forEach(packet => { M[packet.id] = packet.messages; indices.push(packet.id); }); }); if(!indices.length) throw new Error("File has no messages"); diff --git a/modules/Makefile b/modules/Makefile index ebabc3a..9f0a623 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -4,11 +4,15 @@ TSFILES=$(wildcard *.ts) ENTRIES=$(subst .ts,.js,$(TSFILES)) CC=esbuild@0.14.14 -BAREJS=04_base64.js 45_rtf.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js 83_numbers.js +BAREJS=04_base64.js 32_odmanrdf.js 45_rtf.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js 83_numbers.js .PHONY: all all: bits xlsx.zahl.js +.PHONY: lint +lint: $(filter-out $(wildcard *.node.ts),$(TSFILES)) + tsc --strict --noEmit $^ + .PHONY: bits bits: $(ENTRIES) diff --git a/modules/reframe.sh b/modules/reframe.sh index aad3caf..02a1328 100755 --- a/modules/reframe.sh +++ b/modules/reframe.sh @@ -2,12 +2,13 @@ set -eo pipefail INF=${1:-test.numbers} OUTF=${2:-reframed.numbers} +chmod a+w "$OUTF" cp "$INF" "$OUTF" chmod a-w "$OUTF" sleep 0.1 # open "$OUTF" unzip -l "$OUTF" -base64 "$OUTF" | tr -d '\n' > xlsx.zahl.js +(base64 "$OUTF" || base64 -i "$OUTF") | tr -d '\n' > xlsx.zahl.js sed -i.bak 's/^/var XLSX_ZAHL_PAYLOAD = "/g;s/$/";\n/g' xlsx.zahl.js cp xlsx.zahl.js xlsx.zahl.mjs cat >> xlsx.zahl.js <<EOF