diff --git a/bits/04_base64.js b/bits/04_base64.js index 637bee2..0164e3f 100644 --- a/bits/04_base64.js +++ b/bits/04_base64.js @@ -48,7 +48,9 @@ function Base64_encode_pass(input) { function Base64_decode(input) { var o = ""; var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; - input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/, "").replace(/[^\w\+\/\=]/g, ""); + input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64,/, '') + .replace(/[^\w\+\/\=]/g, ""); + for (var i = 0; i < input.length; ) { e1 = Base64_map.indexOf(input.charAt(i++)); e2 = Base64_map.indexOf(input.charAt(i++)); diff --git a/demos/README.md b/demos/README.md index 1243a17..c700643 100644 --- a/demos/README.md +++ b/demos/README.md @@ -51,7 +51,7 @@ can be installed with Bash on Windows or with `cygwin`. - [`SalesForce Lightning Web Components`](https://docs.sheetjs.com/docs/getting-started/demos/salesforce) - [`Excel JavaScript API`](https://docs.sheetjs.com/docs/getting-started/demos/excel) - [`Headless Automation`](https://docs.sheetjs.com/docs/getting-started/demos/headless) -- [`Swift JSC and Other JavaScript Engines`](https://docs.sheetjs.com/docs/getting-started/demos/engines) +- [`Swift JSC and Other JavaScript Engines`](altjs/) - [`"serverless" functions`](function/) - [`Databases and Structured Data Stores`](https://docs.sheetjs.com/docs/getting-started/demos/database) - [`NoSQL, K/V, and Unstructured Data Stores`](https://docs.sheetjs.com/docs/getting-started/demos/nosql) @@ -68,7 +68,9 @@ can be installed with Bash on Windows or with `cygwin`. - [`swc`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#swc) - [`systemjs`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#systemjs) - [`vite`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#vite) -- [`webpack`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#webpack) +- [`webpack 2.x`](webpack/) - [`wmr`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#wmr) +Other examples are included in the [showcase](demos/showcase/). + [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/altjs/.gitignore b/demos/altjs/.gitignore new file mode 100644 index 0000000..6626d47 --- /dev/null +++ b/demos/altjs/.gitignore @@ -0,0 +1,10 @@ +sheetjs.* +SheetJSSwift +duk* +*.class +*.jar +rhino +shim.min.js +xlsx.*.js +payload.js +goja diff --git a/demos/altjs/.swiftlint.yml b/demos/altjs/.swiftlint.yml new file mode 100644 index 0000000..11856f9 --- /dev/null +++ b/demos/altjs/.swiftlint.yml @@ -0,0 +1,3 @@ +disabled_rules: + - trailing_semicolon + - identifier_name diff --git a/demos/altjs/Makefile b/demos/altjs/Makefile new file mode 100644 index 0000000..7fc69e0 --- /dev/null +++ b/demos/altjs/Makefile @@ -0,0 +1,60 @@ +.PHONY: all +all: duktape nashorn rhinojs swift goja + +.PHONY: base +base: + if [ ! -e sheetjs.xlsx ]; then node ../../tests/write.js; fi + if [ ! -e xlsx.full.min.js ]; then cp ../../dist/xlsx.full.min.js .; fi + if [ ! -e shim.min.js ]; then cp ../../dist/shim.min.js .; fi + +.PHONY: duk +duk: base + bash ./duktape.sh + gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm + +.PHONY: duktape +duktape: duk ## duktape demo + for ext in xlsx xlsb biff8.xls xml.xls; do ./sheetjs.duk sheetjs.$$ext; done + +.PHONY: nashorn +nashorn: base ## nashorn demo + jjs nashorn.js + +.PHONY: swift +swift: base ## swift demo + swiftc SheetJSCore.swift main.swift -o SheetJSSwift + ./SheetJSSwift + +.PHONY: goja +goja: base ## goja demo + go build goja.go + for ext in xlsx xlsb biff8.xls xml.xls; do ./goja sheetjs.$$ext; done + +.PHONY: chakra +chakra: base ## Chakra demo + node -pe "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('sheetjs.xlsx').toString('base64') + '\";')" + cat global.js xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js + chakra ./xlsx.chakra.js + +.PHONY: rhinojs ## rhino demo +rhinojs: base SheetJSRhino.class + for ext in xlsx xlsb biff8.xls xml.xls; do java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.$$ext; done + +RHDEPS=$(filter-out SheetJSRhino.class,$(patsubst %.java,%.class,$(wildcard com/sheetjs/*.java))) +$(RHDEPS): %.class: %.java rhino.jar + javac -cp .:SheetJS.jar:rhino.jar $*.java + +SheetJSRhino.class: $(RHDEPS) + jar -cf SheetJS.jar $^ xlsx.full.min.js + javac -cp .:SheetJS.jar:rhino.jar SheetJSRhino.java + +rhino.jar: + if [ ! -e rhino ]; then git clone --depth=1 https://github.com/mozilla/rhino; fi + #if [ ! -e rhino/build/rhino*/js.jar ]; then cd rhino; ant jar; fi + #cp rhino/build/rhino*/js.jar rhino.jar + if [ ! -e rhino/buildGradle/libs/rhino-[0-1]*.jar ]; then cd rhino; ./gradlew jar; fi + cp rhino/buildGradle/libs/rhino-[0-9]*.jar rhino.jar + +.PHONY: clean +clean: + rm SheetJS.jar *.class com/sheetjs/*.class diff --git a/demos/altjs/README.md b/demos/altjs/README.md index 0ba063a..55de233 100644 --- a/demos/altjs/README.md +++ b/demos/altjs/README.md @@ -1,7 +1,186 @@ # Other JS Engines and Deployments -[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/engines) -includes more detailed instructions and more JS engines. +There are many JS engines and deployments outside of web browsers. NodeJS is the +most popular deployment, but there are many others for special use cases. Some +optimize for low overhead and others optimize for ease of embedding within other +applications. Since it was designed for ES3 engines, the library can be used in +those settings! This demo tries to demonstrate a few alternative deployments. +Some engines provide no default global object. To create a global reference: + +```js +var global = (function(){ return this; }).call(null); +``` + + +## Swift + JavaScriptCore + +iOS and OSX ship with the JavaScriptCore framework for running JS scripts from +Swift and Objective-C. Hybrid function invocation is tricky, but explicit data +passing is straightforward. The demo shows a standalone example for OSX. For +playgrounds, the library should be copied to shared playground data directory +(usually `~/Documents/Shared Playground Data`): + +```swift +/* This only works in a playground, see SheetJSCore.swift for standalone use */ +import JavaScriptCore; +import PlaygroundSupport; + +/* build path variable for the library */ +let shared_dir = PlaygroundSupport.playgroundSharedDataDirectory; +let lib_path = shared_dir.appendingPathComponent("xlsx.full.min.js"); + +/* prepare JS context */ +var context: JSContext! = JSContext(); +var src = "var global = (function(){ return this; }).call(null);"; +context.evaluateScript(src); + +/* load library */ +var lib = try? String(contentsOf: lib_path); +context.evaluateScript(lib); +let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX"); + +/* to verify the library was loaded, get the version string */ +let XLSXversion: JSValue! = XLSX.objectForKeyedSubscript("version") +var version = XLSXversion.toString(); +``` + +Binary strings can be passed back and forth using `String.Encoding.isoLatin1`: + +```swift +/* parse sheetjs.xls */ +let file_path = shared_dir.appendingPathComponent("sheetjs.xls"); +let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1); +context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)); +src = "var wb = XLSX.read(payload, {type:'binary'});"; +context.evaluateScript(src); + +/* write to sheetjsw.xlsx */ +let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx"); +src = "var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})"; +context.evaluateScript(src); +let outvalue: JSValue! = context.objectForKeyedSubscript("out"); +var out: String! = outvalue.toString(); +try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1); +``` + + +## Nashorn + +Nashorn ships with Java 8. It includes a command-line tool `jjs` for running JS +scripts. It is somewhat limited but does offer access to the full Java runtime. + +The `load` function in `jjs` can load the minified source directly: + +```js +var global = (function(){ return this; }).call(null); +load('xlsx.full.min.js'); +``` + +The Java `nio` API provides the `Files.readAllBytes` method to read a file into +a byte array. To use in `XLSX.read`, the demo copies the bytes into a plain JS +array and calls `XLSX.read` with type `"array"`. + + +## Rhino + +[Rhino](http://www.mozilla.org/rhino) is an ES3+ engine written in Java. The +`SheetJSRhino` class and `com.sheetjs` package show a complete JAR deployment, +including the full XLSX source. + +Due to code generation errors, optimization must be turned off: + +```java +Context context = Context.enter(); +context.setOptimizationLevel(-1); +``` + + +## ChakraCore + +ChakraCore is an embeddable JS engine written in C++. The library and binary +distributions include a command-line tool `chakra` for running JS scripts. + +The simplest way to interact with the engine is to pass Base64 strings. The make +target builds a very simple payload with the data. + + +## Duktape + +[Duktape](http://duktape.org/) is an embeddable JS engine written in C. The +amalgamation makes integration extremely simple! It supports `Buffer` natively +but should be sliced before processing: + +```C +/* parse a C char array as a workbook object */ +duk_push_external_buffer(ctx); +duk_config_buffer(ctx, -1, buf, len); +duk_put_global_string(ctx, "buf"); +duk_eval_string_noresult("workbook = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); + +/* write a workbook object to a C char array */ +duk_eval_string(ctx, "XLSX.write(workbook, {type:'array', bookType:'xlsx'})"); +duk_size_t sz; +char *buf = (char *)duk_get_buffer_data(ctx, -1, sz); +duk_pop(ctx); +``` + + +## QuickJS + +QuickJS is an embeddable JS engine written in C. It provides a separate set of +functions for interacting with the filesystem and the global object. It can run +the browser dist build. + +The `global` object is available as `std.global`. To make it visible to the +loader, create a reference to itself: + +```js +std.global.global = std.global; +std.loadScript("xlsx.full.min.js"); +``` + +The filesystem interaction mirrors POSIX, including separate allocations: + +```js +/* read file */ +var rh = std.open(filename, "rb"); rh.seek(0, std.SEEK_END); +var sz = rh.tell(); rh.seek(); +var ab = new ArrayBuffer(sz); rh.read(ab, 0, sz); rh.close(); +var wb = XLSX.read(ab, {type: 'array'}); + +/* write file */ +var ab = XLSX.write(wb, {type: 'array'}); +var wh = std.open("sheetjs.qjs.xlsx", "wb"); +wh.write(out, 0, ab.byteLength); wh.close(); +``` + + +## Goja + +Goja is a pure Go implementation of ECMAScript 5. `[]byte` should be converted +to a binary string in the engine: + +```go +/* read file */ +data, _ := ioutil.ReadFile("sheetjs.xlsx") + +/* load into engine */ +vm.Set("buf", data) + +/* convert to binary string */ +_, _ = vm.RunString("var bstr = ''; for(var i = 0; i < buf.length; ++i) bstr += String.fromCharCode(buf[i]);") + +/* parse */ +wb, _ = vm.RunString("wb = XLSX.read(bstr, {type:'binary', cellNF:true});") +``` + +On the write side, `"base64"` strings can be decoded in Go: + +```go +b64str, _ := vm.RunString("XLSX.write(wb, {type:'base64', bookType:'xlsx'})") +buf, _ := base64.StdEncoding.DecodeString(b64str.String()) +_ = ioutil.WriteFile("sheetjs.xlsx", buf, 0644) +``` [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/altjs/SJSPlayground.swift b/demos/altjs/SJSPlayground.swift new file mode 100644 index 0000000..e95cde5 --- /dev/null +++ b/demos/altjs/SJSPlayground.swift @@ -0,0 +1,37 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* This only works in a playground, see SheetJSCore.swift for standalone use */ +import JavaScriptCore; +import PlaygroundSupport; + +/* build path variable for the library */ +let shared_dir = PlaygroundSupport.playgroundSharedDataDirectory; +let lib_path = shared_dir.appendingPathComponent("xlsx.full.min.js"); + +/* prepare JS context */ +var context: JSContext! = JSContext(); +var src = "var global = (function(){ return this; }).call(null);"; +context.evaluateScript(src); + +/* load library */ +var lib = try? String(contentsOf: lib_path); +context.evaluateScript(lib); +let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX"); + +/* to verify the library was loaded, get the version string */ +let XLSXversion: JSValue! = XLSX.objectForKeyedSubscript("version") +var version = XLSXversion.toString(); + +/* parse sheetjs.xls */ +let file_path = shared_dir.appendingPathComponent("sheetjs.xls"); +let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1); +context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)!); +src = "var wb = XLSX.read(payload, {type:'binary'});"; +context.evaluateScript(src); + +/* write to sheetjsw.xlsx */ +let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx"); +src = "var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})"; +context.evaluateScript(src); +let outvalue: JSValue! = context.objectForKeyedSubscript("out"); +var out: String! = outvalue.toString(); +try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1); diff --git a/demos/altjs/SheetJSCore.swift b/demos/altjs/SheetJSCore.swift new file mode 100755 index 0000000..4f56647 --- /dev/null +++ b/demos/altjs/SheetJSCore.swift @@ -0,0 +1,96 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +import JavaScriptCore; + +enum SJSError: Error { + case badJSContext; + case badJSWorkbook; + case badJSWorksheet; +}; + +class SJSWorksheet { + var context: JSContext!; + var wb: JSValue; var ws: JSValue; + var idx: Int32; + + func toCSV() throws -> String { + let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX"); + let utils: JSValue! = XLSX.objectForKeyedSubscript("utils"); + let sheet_to_csv: JSValue! = utils.objectForKeyedSubscript("sheet_to_csv"); + return sheet_to_csv.call(withArguments: [ws]).toString(); + } + + init(ctx: JSContext, workbook: JSValue, worksheet: JSValue, idx: Int32) throws { + self.context = ctx; self.wb = workbook; self.ws = worksheet; self.idx = idx; + } +} + +class SJSWorkbook { + var context: JSContext!; + var wb: JSValue; var SheetNames: JSValue; var Sheets: JSValue; + + func getSheetAtIndex(idx: Int32) throws -> SJSWorksheet { + let SheetName: String = SheetNames.atIndex(Int(idx)).toString(); + let ws: JSValue! = Sheets.objectForKeyedSubscript(SheetName); + return try SJSWorksheet(ctx: context, workbook: wb, worksheet: ws, idx: idx); + } + + func writeBStr(bookType: String = "xlsx") throws -> String { + let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX"); + context.evaluateScript(String(format: "var writeopts = {type:'binary', bookType:'%@'}", bookType)); + let writeopts: JSValue = context.objectForKeyedSubscript("writeopts"); + let writefunc: JSValue = XLSX.objectForKeyedSubscript("write"); + return writefunc.call(withArguments: [wb, writeopts]).toString(); + } + + init(ctx: JSContext, wb: JSValue) throws { + self.context = ctx; + self.wb = wb; + self.SheetNames = wb.objectForKeyedSubscript("SheetNames"); + self.Sheets = wb.objectForKeyedSubscript("Sheets"); + } +} + +class SheetJSCore { + var context: JSContext!; + var XLSX: JSValue!; + + func init_context() throws -> JSContext { + var context: JSContext! + do { + context = JSContext(); + context.exceptionHandler = { _, X in if let e = X { print(e.toString()!); }; }; + context.evaluateScript("var global = (function(){ return this; }).call(null);"); + context.evaluateScript("if(typeof wbs == 'undefined') wbs = [];"); + let src = try String(contentsOfFile: "xlsx.full.min.js"); + context.evaluateScript(src); + if context != nil { return context!; } + } catch { print(error.localizedDescription); } + throw SJSError.badJSContext; + } + + func version() throws -> String { + if let version = XLSX.objectForKeyedSubscript("version") { return version.toString(); } + throw SJSError.badJSContext; + } + + func readFile(file: String) throws -> SJSWorkbook { + let data: String! = try String(contentsOfFile: file, encoding: String.Encoding.isoLatin1); + return try readBStr(data: data); + } + + func readBStr(data: String) throws -> SJSWorkbook { + context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)); + context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});"); + let wb: JSValue! = context.objectForKeyedSubscript("wb"); + if wb == nil { throw SJSError.badJSWorkbook; } + return try SJSWorkbook(ctx: context, wb: wb); + } + + init() throws { + do { + self.context = try init_context(); + self.XLSX = self.context.objectForKeyedSubscript("XLSX"); + if self.XLSX == nil { throw SJSError.badJSContext; } + } catch { print(error.localizedDescription); } + } +} diff --git a/demos/altjs/SheetJSRhino.java b/demos/altjs/SheetJSRhino.java new file mode 100644 index 0000000..75bf980 --- /dev/null +++ b/demos/altjs/SheetJSRhino.java @@ -0,0 +1,31 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +import com.sheetjs.SheetJS; +import com.sheetjs.SheetJSFile; +import com.sheetjs.SheetJSSheet; + +public class SheetJSRhino { + public static void main(String args[]) throws Exception { + try { + SheetJS sjs = new SheetJS(); + + /* open file */ + SheetJSFile xl = sjs.read_file(args[0]); + + /* get sheetnames */ + String[] sheetnames = xl.get_sheet_names(); + System.err.println(sheetnames[0]); + + /* convert to CSV */ + SheetJSSheet sheet = xl.get_sheet(0); + String csv = sheet.get_csv(); + + System.out.println(csv); + + } catch(Exception e) { + throw e; + } finally { + SheetJS.close(); + } + } +} diff --git a/demos/altjs/chakra.js b/demos/altjs/chakra.js new file mode 100644 index 0000000..7f9f8c1 --- /dev/null +++ b/demos/altjs/chakra.js @@ -0,0 +1,3 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +var wb = XLSX.read(payload, {type:'base64'}); +console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); diff --git a/demos/altjs/com/sheetjs/JSHelper.java b/demos/altjs/com/sheetjs/JSHelper.java new file mode 100644 index 0000000..c8dcec0 --- /dev/null +++ b/demos/altjs/com/sheetjs/JSHelper.java @@ -0,0 +1,51 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +package com.sheetjs; + +import java.lang.Integer; +import java.lang.StringBuilder; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.NativeArray; +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.Scriptable; + +public class JSHelper { + static String read_file(String file) throws IOException { + byte[] b = Files.readAllBytes(Paths.get(file)); + System.out.println(b.length); + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < b.length; ++i) sb.append(Character.toString((char)(b[i] < 0 ? b[i] + 256 : b[i]))); + return sb.toString(); + } + + static Object get_object(String path, Object base) throws ObjectNotFoundException { + int idx = path.indexOf("."); + Scriptable b = (Scriptable)base; + if(idx == -1) return b.get(path, b); + Object o = b.get(path.substring(0,idx), b); + if(o == Scriptable.NOT_FOUND) throw new ObjectNotFoundException("not found: |" + path.substring(0,idx) + "|" + Integer.toString(idx)); + return get_object(path.substring(idx+1), (NativeObject)o); + } + + static Object[] get_array(String path, Object base) throws ObjectNotFoundException { + NativeArray arr = (NativeArray)get_object(path, base); + Object[] out = new Object[(int)arr.getLength()]; + int idx; + for(Object o : arr.getIds()) out[idx = (Integer)o] = arr.get(idx, arr); + return out; + } + + static String[] get_string_array(String path, Object base) throws ObjectNotFoundException { + NativeArray arr = (NativeArray)get_object(path, base); + String[] out = new String[(int)arr.getLength()]; + int idx; + for(Object o : arr.getIds()) out[idx = (Integer)o] = arr.get(idx, arr).toString(); + return out; + } + + public static void close() { Context.exit(); } + +} diff --git a/demos/altjs/com/sheetjs/ObjectNotFoundException.java b/demos/altjs/com/sheetjs/ObjectNotFoundException.java new file mode 100644 index 0000000..1116922 --- /dev/null +++ b/demos/altjs/com/sheetjs/ObjectNotFoundException.java @@ -0,0 +1,10 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +package com.sheetjs; + +import java.lang.Exception; + +public class ObjectNotFoundException extends Exception { + public ObjectNotFoundException() {} + public ObjectNotFoundException(String message) { super(message); } +} diff --git a/demos/altjs/com/sheetjs/SheetJS.java b/demos/altjs/com/sheetjs/SheetJS.java new file mode 100644 index 0000000..01def4b --- /dev/null +++ b/demos/altjs/com/sheetjs/SheetJS.java @@ -0,0 +1,58 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +package com.sheetjs; + +import java.lang.Integer; +import java.util.Scanner; +import java.io.IOException; +import java.io.File; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.Scriptable; + +public class SheetJS { + public Scriptable scope; + public Context cx; + public NativeObject nXLSX; + + public SheetJS() throws Exception { + this.cx = Context.enter(); + this.scope = this.cx.initStandardObjects(); + + /* boilerplate */ + cx.setOptimizationLevel(-1); + String s = "var global = (function(){ return this; }).call(null);"; + cx.evaluateString(scope, s, "", 1, null); + + /* eval library */ + s = new Scanner(SheetJS.class.getResourceAsStream("/xlsx.full.min.js")).useDelimiter("\\Z").next(); + //s = new Scanner(new File("xlsx.full.min.js")).useDelimiter("\\Z").next(); + cx.evaluateString(scope, s, "", 1, null); + + /* grab XLSX variable */ + Object XLSX = scope.get("XLSX", scope); + if(XLSX == Scriptable.NOT_FOUND) throw new Exception("XLSX not found"); + this.nXLSX = (NativeObject)XLSX; + } + + public SheetJSFile read_file(String filename) throws IOException, ObjectNotFoundException { + /* open file */ + String d = JSHelper.read_file(filename); + + /* options argument */ + NativeObject q = (NativeObject)this.cx.evaluateString(this.scope, "q = {'type':'binary', 'WTF':1};", "", 2, null); + + /* set up function arguments */ + Object args[] = {d, q}; + + /* call read -> wb workbook */ + Function readfunc = (Function)JSHelper.get_object("XLSX.read",this.scope); + NativeObject wb = (NativeObject)readfunc.call(this.cx, this.scope, this.nXLSX, args); + + return new SheetJSFile(wb, this); + } + + public static void close() { JSHelper.close(); } +} + diff --git a/demos/altjs/com/sheetjs/SheetJSFile.java b/demos/altjs/com/sheetjs/SheetJSFile.java new file mode 100644 index 0000000..dcc0e08 --- /dev/null +++ b/demos/altjs/com/sheetjs/SheetJSFile.java @@ -0,0 +1,24 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +package com.sheetjs; + +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.Function; + +public class SheetJSFile { + public NativeObject wb; + public SheetJS sheetjs; + public SheetJSFile() {} + public SheetJSFile(NativeObject wb, SheetJS sheetjs) { this.wb = wb; this.sheetjs = sheetjs; } + public String[] get_sheet_names() { + try { + return JSHelper.get_string_array("SheetNames", this.wb); + } catch(ObjectNotFoundException e) { + return null; + } + } + public SheetJSSheet get_sheet(int idx) throws ObjectNotFoundException { + return new SheetJSSheet(this, idx); + } +} + diff --git a/demos/altjs/com/sheetjs/SheetJSSheet.java b/demos/altjs/com/sheetjs/SheetJSSheet.java new file mode 100644 index 0000000..a99ab03 --- /dev/null +++ b/demos/altjs/com/sheetjs/SheetJSSheet.java @@ -0,0 +1,29 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +package com.sheetjs; + +import org.mozilla.javascript.Function; +import org.mozilla.javascript.NativeObject; + +public class SheetJSSheet { + public NativeObject ws; + public SheetJSFile wb; + public SheetJSSheet(SheetJSFile wb, int idx) throws ObjectNotFoundException { + this.wb = wb; + this.ws = (NativeObject)JSHelper.get_object("Sheets." + wb.get_sheet_names()[idx],wb.wb); + } + public String get_range() throws ObjectNotFoundException { + return JSHelper.get_object("!ref",this.ws).toString(); + } + public String get_string_value(String address) throws ObjectNotFoundException { + return JSHelper.get_object(address + ".v",this.ws).toString(); + } + + public String get_csv() throws ObjectNotFoundException { + Function csvify = (Function)JSHelper.get_object("XLSX.utils.sheet_to_csv",this.wb.sheetjs.scope); + Object csvArgs[] = {this.ws}; + Object csv = csvify.call(this.wb.sheetjs.cx, this.wb.sheetjs.scope, this.wb.sheetjs.scope, csvArgs); + return csv.toString(); + } +} + diff --git a/demos/altjs/duktape.sh b/demos/altjs/duktape.sh new file mode 100755 index 0000000..d0b5f81 --- /dev/null +++ b/demos/altjs/duktape.sh @@ -0,0 +1,16 @@ +#!/bin/bash +DUKTAPE_VER=2.6.0 +if [ ! -e duktape-$DUKTAPE_VER ]; then + if [ ! -e duktape-$DUKTAPE_VER.tar ]; then + if [ ! -e duktape-$DUKTAPE_VER.tar.xz ]; then + curl -O https://duktape.org/duktape-$DUKTAPE_VER.tar.xz + fi + xz -d duktape-$DUKTAPE_VER.tar.xz + fi + tar -xf duktape-$DUKTAPE_VER.tar +fi + +for f in duktape.{c,h} duk_config.h; do + cp duktape-$DUKTAPE_VER/src/$f . +done + diff --git a/demos/altjs/global.js b/demos/altjs/global.js new file mode 100644 index 0000000..00bae5d --- /dev/null +++ b/demos/altjs/global.js @@ -0,0 +1,3 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +var global = (function(){ return this; }).call(null); + diff --git a/demos/altjs/goja.go b/demos/altjs/goja.go new file mode 100644 index 0000000..6b29202 --- /dev/null +++ b/demos/altjs/goja.go @@ -0,0 +1,71 @@ +package main + +import ( + b64 "encoding/base64" + "fmt" + "os" + "io/ioutil" + "github.com/dop251/goja" +) + +func safe_run_file(vm *goja.Runtime, file string) { + data, err := ioutil.ReadFile(file) + if err != nil { panic(err) } + src := string(data) + _, err = vm.RunString(src) + if err != nil { panic(err) } +} + +func eval_string(vm *goja.Runtime, cmd string) goja.Value { + v, err := vm.RunString(cmd) + if err != nil { panic(err) } + return v +} + +func write_type(vm *goja.Runtime, t string) { + /* due to some wonkiness with array passing, use base64 */ + b64str := eval_string(vm, "XLSX.write(wb, {type:'base64', bookType:'" + t + "'})") + buf, err := b64.StdEncoding.DecodeString(b64str.String()); + if err != nil { panic(err) } + err = ioutil.WriteFile("sheetjsg." + t, buf, 0644) + if err != nil { panic(err) } +} + +func main() { + vm := goja.New() + + /* initialize */ + eval_string(vm, "if(typeof global == 'undefined') global = (function(){ return this; }).call(null);") + + /* load library */ + safe_run_file(vm, "shim.min.js") + safe_run_file(vm, "xlsx.full.min.js") + + /* get version string */ + v := eval_string(vm, "XLSX.version") + fmt.Printf("SheetJS library version %s\n", v) + + /* read file */ + data, err := ioutil.ReadFile(os.Args[1]) + if err != nil { panic(err) } + vm.Set("buf", data) + fmt.Printf("Loaded file %s\n", os.Args[1]) + + /* parse workbook */ + eval_string(vm, "var bstr = ''; for(var i = 0; i < buf.length; ++i) bstr += String.fromCharCode(buf[i]);") + eval_string(vm, "wb = XLSX.read(bstr, {type:'binary', cellNF:true});") + eval_string(vm, "ws = wb.Sheets[wb.SheetNames[0]]") + + /* print CSV */ + csv := eval_string(vm, "XLSX.utils.sheet_to_csv(ws)") + fmt.Printf("%s\n", csv) + + /* change cell A1 to 3 */ + eval_string(vm, "ws['A1'].v = 3; delete ws['A1'].w;") + + /* write file */ + //write_type(vm, "xlsb") + //write_type(vm, "xlsx") + write_type(vm, "xls") + write_type(vm, "csv") +} diff --git a/demos/altjs/main.swift b/demos/altjs/main.swift new file mode 100755 index 0000000..24b278a --- /dev/null +++ b/demos/altjs/main.swift @@ -0,0 +1,21 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ + +let sheetjs = try SheetJSCore(); + +try print(sheetjs.version()); + +let filenames: [[String]] = [ + ["xlsx", "xlsx"], + ["xlsb", "xlsb"], + ["biff8.xls", "xls"], + ["xml.xls", "xlml"] +]; + +for fn in filenames { + let wb: SJSWorkbook = try sheetjs.readFile(file: "sheetjs." + fn[0]); + let ws: SJSWorksheet = try wb.getSheetAtIndex(idx: 0); + let csv: String = try ws.toCSV(); + print(csv); + let wbout: String = try wb.writeBStr(bookType: fn[1]); + try wbout.write(toFile: "sheetjsswift." + fn[0], atomically: false, encoding: String.Encoding.isoLatin1); +} diff --git a/demos/altjs/nashorn.js b/demos/altjs/nashorn.js new file mode 100644 index 0000000..a17fa13 --- /dev/null +++ b/demos/altjs/nashorn.js @@ -0,0 +1,36 @@ +#!/usr/bin/env jjs +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ + +/* load module */ +var global = (function(){ return this; }).call(null); +load('xlsx.full.min.js'); + +/* helper to convert byte array to plain JS array */ +function b2a(b) { + var out = new Array(b.length); + for(var i = 0; i < out.length; i++) out[i] = (b[i] < 0 ? b[i] + 256 : b[i]); + return out; +} + +function process_file(path) { + java.lang.System.out.println(path); + + /* read file */ + var path = java.nio.file.Paths.get(path); + var bytes = java.nio.file.Files.readAllBytes(path); + var u8a = b2a(bytes); + + /* read data */ + var wb = XLSX.read(u8a, {type:"array"}); + + /* get first worksheet as an array of arrays */ + var ws = wb.Sheets[wb.SheetNames[0]]; + var js = XLSX.utils.sheet_to_json(ws, {header:1}); + + /* print out every line */ + js.forEach(function(l) { java.lang.System.out.println(JSON.stringify(l)); }); +} + +process_file('sheetjs.xlsx'); +process_file('sheetjs.xlsb'); +process_file('sheetjs.biff8.xls'); diff --git a/demos/altjs/qjs.js b/demos/altjs/qjs.js new file mode 100755 index 0000000..0e8ca6d --- /dev/null +++ b/demos/altjs/qjs.js @@ -0,0 +1,25 @@ +#!/usr/bin/env qjs +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* load XLSX */ +std.global.global = std.global; +std.loadScript("xlsx.full.min.js"); + +/* read contents of file */ +var rh = std.open("sheetjs.xlsx", "rb"); +rh.seek(0, std.SEEK_END); +var sz = rh.tell(); +var ab = new ArrayBuffer(sz); +rh.seek(); +rh.read(ab, 0, sz); +rh.close(); + +/* parse file */ +var wb = XLSX.read(ab, {type: 'array'}); + +/* write array */ +var out = XLSX.write(wb, {type: 'array'}); + +/* write contents to file */ +var wh = std.open("sheetjs.qjs.xlsx", "wb"); +wh.write(out, 0, out.byteLength); +wh.close(); diff --git a/demos/altjs/sheetjs.duk.c b/demos/altjs/sheetjs.duk.c new file mode 100644 index 0000000..23f6c5d --- /dev/null +++ b/demos/altjs/sheetjs.duk.c @@ -0,0 +1,110 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +#include +#include +#include +#include "duktape.h" + +#define FAIL_LOAD { \ + duk_push_undefined(ctx); \ + perror("Error in load_file"); \ + return 1; \ +} + +static char *read_file(const char *filename, size_t *sz) { + FILE *f = fopen(filename, "rb"); + if(!f) return NULL; + long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); } + char *buf = (char *)malloc(fsize * sizeof(char)); + *sz = fread((void *) buf, 1, fsize, f); + fclose(f); + return buf; +} + +static duk_int_t eval_file(duk_context *ctx, const char *filename) { + size_t len; char *buf = read_file(filename, &len); + if(!buf) FAIL_LOAD + + duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len); + duk_int_t retval = duk_peval(ctx); + duk_pop(ctx); + return retval; +} + +static duk_int_t load_file(duk_context *ctx, const char *filename, const char *var) { + size_t len; char *buf = read_file(filename, &len); + if(!buf) FAIL_LOAD + + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, buf, len); + duk_put_global_string(ctx, var); + return 0; +} + +static duk_int_t save_file(duk_context *ctx, const char *filename, const char *var) { + duk_get_global_string(ctx, var); + duk_size_t sz; + char *buf = (char *)duk_get_buffer_data(ctx, -1, &sz); + + if(!buf) return 1; + FILE *f = fopen(filename, "wb"); fwrite(buf, 1, sz, f); fclose(f); + return 0; +} + +#define FAIL(cmd) { \ + printf("error in %s: %s\n", cmd, duk_safe_to_string(ctx, -1)); \ + duk_destroy_heap(ctx); \ + return res; \ +} + +#define DOIT(cmd) duk_eval_string_noresult(ctx, cmd); +int main(int argc, char *argv[]) { + duk_int_t res = 0; + + /* initialize */ + duk_context *ctx = duk_create_heap_default(); + /* duktape does not expose a standard "global" by default */ + DOIT("var global = (function(){ return this; }).call(null);"); + + /* load library */ + res = eval_file(ctx, "shim.min.js"); + if(res != 0) FAIL("shim load") + res = eval_file(ctx, "xlsx.full.min.js"); + if(res != 0) FAIL("library load") + + /* get version string */ + duk_eval_string(ctx, "XLSX.version"); + printf("SheetJS library version %s\n", duk_get_string(ctx, -1)); + duk_pop(ctx); + + /* read file */ + res = load_file(ctx, argv[1], "buf"); + if(res != 0) FAIL("file load") + printf("Loaded file %s\n", argv[1]); + + /* parse workbook */ + DOIT("wb = XLSX.read(buf, {type:'buffer', cellNF:true});"); + DOIT("ws = wb.Sheets[wb.SheetNames[0]]"); + + /* print CSV */ + duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)"); + printf("%s\n", duk_get_string(ctx, -1)); + duk_pop(ctx); + + /* change cell A1 to 3 */ + DOIT("ws['A1'].v = 3; delete ws['A1'].w;"); + + /* write file */ +#define WRITE_TYPE(BOOKTYPE) \ + DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'" BOOKTYPE "'}));");\ + res = save_file(ctx, "sheetjsw." BOOKTYPE, "newbuf");\ + if(res != 0) FAIL("save sheetjsw." BOOKTYPE) + + WRITE_TYPE("xlsb") + WRITE_TYPE("xlsx") + WRITE_TYPE("xls") + WRITE_TYPE("csv") + + /* cleanup */ + duk_destroy_heap(ctx); + return res; +} diff --git a/demos/showcase/README.md b/demos/showcase/README.md new file mode 100644 index 0000000..a42bf93 --- /dev/null +++ b/demos/showcase/README.md @@ -0,0 +1,14 @@ +# Showcase + +Many use cases are too complex to summarize in a short demo. The listed open +source projects use SheetJS libraries in clever deployments. + +### vscode-data-preview + +**Deployment**: Visual Studio Code Extension + +**Website**: + +**Repository**: + +**Notes**: Demonstrates reading and writing files. diff --git a/demos/webpack/.gitignore b/demos/webpack/.gitignore new file mode 100644 index 0000000..9278674 --- /dev/null +++ b/demos/webpack/.gitignore @@ -0,0 +1,3 @@ +main.js +main.min.js +*.out.js diff --git a/demos/webpack/Makefile b/demos/webpack/Makefile new file mode 100644 index 0000000..90946ca --- /dev/null +++ b/demos/webpack/Makefile @@ -0,0 +1,15 @@ +TOOL=webpack +WPOPTS=--display-modules --display-reasons --profile --mode=development +.PHONY: all +all: main.min.js core.out.js full.out.js app.out.js + +main.min.js: main.out.js + uglifyjs $< > $@ + +.PHONY: main.out.js core.out.js full.out.js +main.out.js core.out.js full.out.js: %.out.js: %.js + webpack $< --output-filename $@ $(WPOPTS) + +.PHONY: app.out.js +app.out.js: webpack.app.js app.js appworker.js + webpack --config $< $(WPOPTS) diff --git a/demos/webpack/README.md b/demos/webpack/README.md index b99ce27..eab47a8 100644 --- a/demos/webpack/README.md +++ b/demos/webpack/README.md @@ -1,6 +1,110 @@ # Webpack -[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/bundler#webpack) -reflects the new default behavior to use the ESM build. +This library is built with some dynamic logic to determine if it is invoked in a +script tag or in nodejs. Webpack does not understand those feature tests, so by +default it will do some strange things. + +## Basic Usage + +`webpack.app.js` demonstrates bundling an entire app script in a bundle. For +basic projects requiring the module from the npm package, it is sufficient to +suppress the node shims: + +```js +/* webpack config for app.out.js */ +{ + /* entry point app.js */ + entry: './app.js', + + /* write to app.out.js */ + output: { path:__dirname, filename: './app.out.js' }, + + /* suppress node shims */ + node: { + process: false, + Buffer: false + } +} +``` + +## Suppressing the Node shims + +The library properly guards against accidental leakage of node features in the +browser but webpack disregards those. The config should explicitly suppress: + +```js + node: { + process: false, + Buffer: false + } +``` + +## Omitting optional dependencies + +The `codepage` is needed in certain special cases, including files generated by +non-US-English versions of Excel, but may not be needed. To reduce build size, +the module can be omitted by aliasing the dependency: + +```js + resolve: { + alias: { "./dist/cpexcel.js": "" } + }, +``` + +Alternatively, bundling the `xlsx.core.min.js` script always omits dependencies. + +## Bower and minified versions + +Webpack may show a message like "This seems to be a pre-built javascript file" +when processing minified files (like the default Bower script). The message is +harmless. To suppress the message, set `module.noParse` in the webpack config: + +```js + module: { + noParse: [ + /xlsx.core.min.js/, + /xlsx.full.min.js/ + ] + } +``` + +## Other Demos + +This demo also attempts to demonstrate bundling of the library as well as the +core and full distribution versions. `app.js` is the common app code (it will +not be bundled). The individual bundles merely wrap and reflect `XLSX`. The +app code uses the bundles with script tag inclusion in the main HTML files. The +worker scripts use the bundles with `importScripts` references. + +| required script | HTML page | entry | worker script | +|----------------:|------------:|----------:|----------------:| +| main `xlsx` lib | `main.html` | `main.js` | `mainworker.js` | +| `xlsx.core.min` | `core.html` | `core.js` | `coreworker.js` | +| `xlsx.full.min` | `full.html` | `full.js` | `fullworker.js` | + +The entry points in the demo merely require and re-export the library: + +```js +/* main.js */ +var XLSX = require('../../'); +console.log("it works!"); +module.exports = XLSX; +``` + +The main advantage of reflecting the library is deduplication: the library code +is only downloaded once. The basic example builds a separate worker script and +eventually ships the library twice. + +### Reflecting the XLSX variable + +This library will not assign to `module.exports` if it is run in the browser. To +convince webpack, the demo webpack config sets `output`: + +```js + output: { + libraryTarget: 'var', + library: 'XLSX' + } +``` [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/webpack/app.js b/demos/webpack/app.js new file mode 100644 index 0000000..9eef9bf --- /dev/null +++ b/demos/webpack/app.js @@ -0,0 +1,147 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/*jshint browser:true */ +/*global XLSX */ +var X = typeof require !== "undefined" && require('../../') || XLSX; + +var global_wb; + +var process_wb = (function() { + var OUT = document.getElementById('out'); + var HTMLOUT = document.getElementById('htmlout'); + + var get_format = (function() { + var radios = document.getElementsByName( "format" ); + return function() { + for(var i = 0; i < radios.length; ++i) if(radios[i].checked || radios.length === 1) return radios[i].value; + }; + })(); + + var to_json = function to_json(workbook) { + var result = {}; + workbook.SheetNames.forEach(function(sheetName) { + var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName]); + if(roa.length) result[sheetName] = roa; + }); + return JSON.stringify(result, 2, 2); + }; + + var to_csv = function to_csv(workbook) { + var result = []; + workbook.SheetNames.forEach(function(sheetName) { + var csv = X.utils.sheet_to_csv(workbook.Sheets[sheetName]); + if(csv.length){ + result.push("SHEET: " + sheetName); + result.push(""); + result.push(csv); + } + }); + return result.join("\n"); + }; + + var to_fmla = function to_fmla(workbook) { + var result = []; + workbook.SheetNames.forEach(function(sheetName) { + var formulae = X.utils.get_formulae(workbook.Sheets[sheetName]); + if(formulae.length){ + result.push("SHEET: " + sheetName); + result.push(""); + result.push(formulae.join("\n")); + } + }); + return result.join("\n"); + }; + + var to_html = function to_html(workbook) { + HTMLOUT.innerHTML = ""; + workbook.SheetNames.forEach(function(sheetName) { + var htmlstr = X.write(workbook, {sheet:sheetName, type:'string', bookType:'html'}); + HTMLOUT.innerHTML += htmlstr; + }); + return ""; + }; + + return function process_wb(wb) { + global_wb = wb; + var output = ""; + switch(get_format()) { + case "form": output = to_fmla(wb); break; + case "html": output = to_html(wb); break; + case "json": output = to_json(wb); break; + default: output = to_csv(wb); + } + if(OUT.innerText === undefined) OUT.textContent = output; + else OUT.innerText = output; + if(typeof console !== 'undefined') console.log("output", new Date()); + }; +})(); + +var setfmt = window.setfmt = function setfmt() { if(global_wb) process_wb(global_wb); }; + +var b64it = window.b64it = (function() { + var tarea = document.getElementById('b64data'); + return function b64it() { + if(typeof console !== 'undefined') console.log("onload", new Date()); + var wb = X.read(tarea.value, {type:'base64', WTF:false}); + process_wb(wb); + }; +})(); + +var do_file = (function() { + var use_worker = typeof Worker !== 'undefined'; + var domwork = document.getElementsByName("useworker")[0]; + if(!use_worker) domwork.disabled = !(domwork.checked = false); + + var xw = function xw(data, cb) { + var worker = new Worker(XW.worker); + worker.onmessage = function(e) { + switch(e.data.t) { + case 'ready': break; + case 'e': console.error(e.data.d); break; + case XW.msg: cb(JSON.parse(e.data.d)); break; + } + }; + worker.postMessage({d:data,b:'array'}); + }; + + return function do_file(files) { + use_worker = domwork.checked; + var f = files[0]; + var reader = new FileReader(); + reader.onload = function(e) { + if(typeof console !== 'undefined') console.log("onload", new Date(), use_worker); + var data = e.target.result; + data = new Uint8Array(data); + if(use_worker) xw(data, process_wb); + else process_wb(X.read(data, {type: 'array'})); + }; + reader.readAsArrayBuffer(f); + }; +})(); + +(function() { + var drop = document.getElementById('drop'); + if(!drop.addEventListener) return; + + function handleDrop(e) { + e.stopPropagation(); + e.preventDefault(); + do_file(e.dataTransfer.files); + } + + function handleDragover(e) { + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; + } + + drop.addEventListener('dragenter', handleDragover, false); + drop.addEventListener('dragover', handleDragover, false); + drop.addEventListener('drop', handleDrop, false); +})(); + +(function() { + var xlf = document.getElementById('xlf'); + if(!xlf.addEventListener) return; + function handleFile(e) { do_file(e.target.files); } + xlf.addEventListener('change', handleFile, false); +})(); diff --git a/demos/webpack/appworker.js b/demos/webpack/appworker.js new file mode 100644 index 0000000..17cac10 --- /dev/null +++ b/demos/webpack/appworker.js @@ -0,0 +1,11 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +var XLSX = require('../../'); +postMessage({t:"ready"}); + +onmessage = function (evt) { + var v; + try { + v = XLSX.read(evt.data.d, {type: evt.data.b}); +postMessage({t:"xlsx", d:JSON.stringify(v)}); + } catch(e) { postMessage({t:"e",d:e.stack||e}); } +}; diff --git a/demos/webpack/core.html b/demos/webpack/core.html new file mode 100644 index 0000000..6456899 --- /dev/null +++ b/demos/webpack/core.html @@ -0,0 +1,59 @@ + + + + + + +SheetJS Live Demo + + + +
+SheetJS Data Preview Live Demo
+(Base64 text works back to IE6; drag and drop works back to IE10)
+
+Source Code Repo
+Issues?  Something look weird?  Click here and report an issue
+Output Format: 
+
Drop a spreadsheet file here to see sheet data
+ ... or click here to select a file + + +
+Advanced Demo Options: +Use Web Workers: (when available) +
+

+
+
+ + + + + diff --git a/demos/webpack/core.js b/demos/webpack/core.js new file mode 100644 index 0000000..39042f7 --- /dev/null +++ b/demos/webpack/core.js @@ -0,0 +1,4 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +var XLSX = require('./xlsx.core.min'); +console.log("it works!"); +module.exports = XLSX; diff --git a/demos/webpack/coreworker.js b/demos/webpack/coreworker.js new file mode 100644 index 0000000..b17e861 --- /dev/null +++ b/demos/webpack/coreworker.js @@ -0,0 +1,11 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +importScripts('core.out.js'); +postMessage({t:"ready"}); + +onmessage = function (evt) { + var v; + try { + v = XLSX.read(evt.data.d, {type: evt.data.b}); +postMessage({t:"xlsx", d:JSON.stringify(v)}); + } catch(e) { postMessage({t:"e",d:e.stack||e}); } +}; diff --git a/demos/webpack/full.html b/demos/webpack/full.html new file mode 100644 index 0000000..96ea066 --- /dev/null +++ b/demos/webpack/full.html @@ -0,0 +1,59 @@ + + + + + + +SheetJS Live Demo + + + +
+SheetJS Data Preview Live Demo
+(Base64 text works back to IE6; drag and drop works back to IE10)
+
+Source Code Repo
+Issues?  Something look weird?  Click here and report an issue
+Output Format: 
+
Drop a spreadsheet file here to see sheet data
+ ... or click here to select a file + + +
+Advanced Demo Options: +Use Web Workers: (when available) +
+

+
+
+ + + + + diff --git a/demos/webpack/full.js b/demos/webpack/full.js new file mode 100644 index 0000000..142687f --- /dev/null +++ b/demos/webpack/full.js @@ -0,0 +1,4 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +var XLSX = require('./xlsx.full.min'); +console.log("it works!"); +module.exports = XLSX; diff --git a/demos/webpack/fullworker.js b/demos/webpack/fullworker.js new file mode 100644 index 0000000..52cf9b9 --- /dev/null +++ b/demos/webpack/fullworker.js @@ -0,0 +1,11 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +importScripts('full.out.js'); +postMessage({t:"ready"}); + +onmessage = function (evt) { + var v; + try { + v = XLSX.read(evt.data.d, {type: evt.data.b}); +postMessage({t:"xlsx", d:JSON.stringify(v)}); + } catch(e) { postMessage({t:"e",d:e.stack||e}); } +}; diff --git a/demos/webpack/main.html b/demos/webpack/main.html new file mode 100644 index 0000000..5baade7 --- /dev/null +++ b/demos/webpack/main.html @@ -0,0 +1,59 @@ + + + + + + +SheetJS Live Demo + + + +
+SheetJS Data Preview Live Demo
+(Base64 text works back to IE6; drag and drop works back to IE10)
+
+Source Code Repo
+Issues?  Something look weird?  Click here and report an issue
+Output Format: 
+
Drop a spreadsheet file here to see sheet data
+ ... or click here to select a file + + +
+Advanced Demo Options: +Use Web Workers: (when available) +
+

+
+
+ + + + + diff --git a/demos/webpack/mainworker.js b/demos/webpack/mainworker.js new file mode 100644 index 0000000..2749ad5 --- /dev/null +++ b/demos/webpack/mainworker.js @@ -0,0 +1,11 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +importScripts('main.min.js'); +postMessage({t:"ready"}); + +onmessage = function (evt) { + var v; + try { + v = XLSX.read(evt.data.d, {type: evt.data.b}); +postMessage({t:"xlsx", d:JSON.stringify(v)}); + } catch(e) { postMessage({t:"e",d:e.stack||e}); } +}; diff --git a/demos/webpack/src/index.js b/demos/webpack/src/index.js new file mode 100644 index 0000000..57c9cf5 --- /dev/null +++ b/demos/webpack/src/index.js @@ -0,0 +1,4 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +var XLSX = require('../../'); +console.log("it works!"); +module.exports = XLSX; diff --git a/demos/webpack/webpack.app.js b/demos/webpack/webpack.app.js new file mode 100644 index 0000000..d45b8c5 --- /dev/null +++ b/demos/webpack/webpack.app.js @@ -0,0 +1,25 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +var commonops = { + /* suppress node shims */ + node: { + process: false, + Buffer: false + } +} + +/* app.out.js */ +var app_config = Object.assign({ + entry: './app.js', + output: { path:__dirname, filename: './app.out.js' } +}, commonops); + +/* appworker.out.js */ +var appworker_config = Object.assign({ + entry: './appworker.js', + output: { path:__dirname, filename: './appworker.out.js' } +}, commonops); + +module.exports = [ + app_config, + appworker_config +] diff --git a/demos/webpack/webpack.config.js b/demos/webpack/webpack.config.js new file mode 100644 index 0000000..5a4fe0e --- /dev/null +++ b/demos/webpack/webpack.config.js @@ -0,0 +1,27 @@ +/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +module.exports = { + /* ensure that the XLSX variable is exported */ + output: { + path: __dirname, + libraryTarget: 'var', + library: 'XLSX' + }, + /* module.noParse needed for bower */ + module: { + noParse: [ + /xlsx.core.min.js/, + /xlsx.full.min.js/ + ] + }, + /* Uncomment the next block to suppress codepage */ + /* + resolve: { + alias: { "./dist/cpexcel.js": "" } + }, + */ + /* suppress node shims */ + node: { + process: false, + Buffer: false + } +}; diff --git a/demos/webpack/xlsx.core.min.js b/demos/webpack/xlsx.core.min.js new file mode 120000 index 0000000..383ccb8 --- /dev/null +++ b/demos/webpack/xlsx.core.min.js @@ -0,0 +1 @@ +../../dist/xlsx.core.min.js \ No newline at end of file diff --git a/demos/webpack/xlsx.full.min.js b/demos/webpack/xlsx.full.min.js new file mode 120000 index 0000000..dbca48d --- /dev/null +++ b/demos/webpack/xlsx.full.min.js @@ -0,0 +1 @@ +../../dist/xlsx.full.min.js \ No newline at end of file diff --git a/modules/04_base64.js b/modules/04_base64.js index 637bee2..fdd658a 100644 --- a/modules/04_base64.js +++ b/modules/04_base64.js @@ -48,7 +48,9 @@ function Base64_encode_pass(input) { function Base64_decode(input) { var o = ""; var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; - input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/, "").replace(/[^\w\+\/\=]/g, ""); + input = input.replace(/^data:.+\/.+;base64\,/,'') + .replace(/[^\w\+\/\=]/g, "") + for (var i = 0; i < input.length; ) { e1 = Base64_map.indexOf(input.charAt(i++)); e2 = Base64_map.indexOf(input.charAt(i++)); diff --git a/modules/04_base64.ts b/modules/04_base64.ts index 10bfc37..adbd40a 100644 --- a/modules/04_base64.ts +++ b/modules/04_base64.ts @@ -40,7 +40,7 @@ function Base64_encode_pass(input: string): string { function Base64_decode(input: string): string { var o = ""; var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; - input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/,'') + input = input.replace(/^data:.+\/.+;base64\,/,'') .replace(/[^\w\+\/\=]/g, "") for(var i = 0; i < input.length;) { e1 = Base64_map.indexOf(input.charAt(i++)); diff --git a/test.js b/test.js index e62ff2e..74208ba 100644 --- a/test.js +++ b/test.js @@ -688,21 +688,42 @@ describe('input formats', function() { it('should read base64 strings', function() { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'base64'), {type: 'base64'}); }); }); + it('handles base64 within data URI scheme (gh-2762)', function() { - var data = 'TmFtZXMNCkhhZmV6DQpTYW0NCg=='; + // Arrange + var fileInBase64 = 'TmFtZXMNCkhhZmV6DQpTYW0NCg=='; + var fileInBase64WithDataURIScheme = 'data:text/csv;base64,TmFtZXMNCkhhZmV6DQpTYW0NCg=='; - var wb0 = X.read(data, { type: 'base64' }); // raw base64 string - var wb1 = X.read('data:;base64,' + data, { type: 'base64' }); // data URI, no media type - var wb2 = X.read('data:text/csv;base64,' + data, { type: 'base64' }); // data URI, CSV type - var wb3 = X.read('data:application/vnd.ms-excel;base64,' + data, { type: 'base64' }); // data URI, Excel + // Act + var workBookFromRawBase64 = X.read(fileInBase64, { type: 'base64' }); + var workBookFromBase64WithinDataURI = X.read(fileInBase64WithDataURIScheme, { type: 'base64' }); - [wb0, wb1, wb2, wb3].forEach(function(wb) { - var ws = wb.Sheets.Sheet1; - assert.equal(ws["!ref"], "A1:A3"); - assert.equal(get_cell(ws, "A1").v, "Names"); - assert.equal(get_cell(ws, "A2").v, "Hafez"); - assert.equal(get_cell(ws, "A3").v, "Sam"); - }); + var jsonSheet1 = X.utils.sheet_to_json(workBookFromRawBase64.Sheets.Sheet1); + var jsonSheet2 = X.utils.sheet_to_json(workBookFromBase64WithinDataURI.Sheets.Sheet1); + + // Assert + assert.equal( + JSON.stringify(jsonSheet1), + JSON.stringify(jsonSheet2) + ); + }); + it('handles base64 where data URI has no media type (gh-2762)', function() { + // Arrange + var fileInBase64 = 'TmFtZXMNCkhhZmV6DQpTYW0NCg=='; + var fileInBase64WithDataURIScheme = 'data:;base64,TmFtZXMNCkhhZmV6DQpTYW0NCg=='; + + // Act + var workBookFromRawBase64 = X.read(fileInBase64, { type: 'base64' }); + var workBookFromBase64WithinDataURI = X.read(fileInBase64WithDataURIScheme, { type: 'base64' }); + + var jsonSheet1 = X.utils.sheet_to_json(workBookFromRawBase64.Sheets.Sheet1); + var jsonSheet2 = X.utils.sheet_to_json(workBookFromBase64WithinDataURI.Sheets.Sheet1); + + // Assert + assert.equal( + JSON.stringify(jsonSheet1), + JSON.stringify(jsonSheet2) + ); }); if(typeof Uint8Array !== 'undefined') it('should read array', function() { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'}); diff --git a/test.mjs b/test.mjs index 8b2a2dc..1e7e914 100644 --- a/test.mjs +++ b/test.mjs @@ -685,22 +685,6 @@ describe('input formats', function() { it('should read base64 strings', function() { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'base64'), {type: 'base64'}); }); }); - it('handles base64 within data URI scheme (gh-2762)', function() { - var data = 'TmFtZXMNCkhhZmV6DQpTYW0NCg=='; - - var wb0 = X.read(data, { type: 'base64' }); // raw base64 string - var wb1 = X.read('data:;base64,' + data, { type: 'base64' }); // data URI, no media type - var wb2 = X.read('data:text/csv;base64,' + data, { type: 'base64' }); // data URI, CSV type - var wb3 = X.read('data:application/vnd.ms-excel;base64,' + data, { type: 'base64' }); // data URI, Excel - - [wb0, wb1, wb2, wb3].forEach(function(wb) { - var ws = wb.Sheets.Sheet1; - assert.equal(ws["!ref"], "A1:A3"); - assert.equal(get_cell(ws, "A1").v, "Names"); - assert.equal(get_cell(ws, "A2").v, "Hafez"); - assert.equal(get_cell(ws, "A3").v, "Sam"); - }); - }); if(typeof Uint8Array !== 'undefined') it('should read array', function() { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'}); }); }); @@ -1400,7 +1384,7 @@ describe('parse features', function() { }); describe('data types formats', function() {[ - ['xlsx', paths.dtfxlsx] + ['xlsx', paths.dtfxlsx], ].forEach(function(m) { it(m[0], function() { var wb = X.read(fs.readFileSync(m[1]), {type: TYPE, cellDates: true}); var ws = wb.Sheets[wb.SheetNames[0]]; @@ -2203,7 +2187,7 @@ describe('CSV', function() { var aoa = [ ["3a", "3 a", "3 a-1"], ["3b", "3 b", "3 b-1"], - ["3p", "3 P", "3 p-1"] + ["3p", "3 P", "3 p-1"], ] var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { diff --git a/test.mts b/test.mts index f57df05..1f25456 100644 --- a/test.mts +++ b/test.mts @@ -702,22 +702,6 @@ describe('input formats', function() { it('should read base64 strings', function() { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'base64'), {type: 'base64'}); }); }); - it('handles base64 within data URI scheme (gh-2762)', function() { - var data = 'TmFtZXMNCkhhZmV6DQpTYW0NCg=='; - - var wb0 = X.read(data, { type: 'base64' }); // raw base64 string - var wb1 = X.read('data:;base64,' + data, { type: 'base64' }); // data URI, no media type - var wb2 = X.read('data:text/csv;base64,' + data, { type: 'base64' }); // data URI, CSV type - var wb3 = X.read('data:application/vnd.ms-excel;base64,' + data, { type: 'base64' }); // data URI, Excel - - [wb0, wb1, wb2, wb3].forEach(function(wb) { - var ws = wb.Sheets.Sheet1; - assert.equal(ws["!ref"], "A1:A3"); - assert.equal(get_cell(ws, "A1").v, "Names"); - assert.equal(get_cell(ws, "A2").v, "Hafez"); - assert.equal(get_cell(ws, "A3").v, "Sam"); - }); - }); if(typeof Uint8Array !== 'undefined') it('should read array', function() { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'}); }); }); diff --git a/test.ts b/test.ts index b050ab4..0d8de53 100644 --- a/test.ts +++ b/test.ts @@ -702,22 +702,6 @@ Deno.test('input formats', async function(t) { await t.step('should read base64 strings', async function(t) { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'base64'), {type: 'base64'}); }); }); - await t.step('handles base64 within data URI scheme (gh-2762)', async function(t) { - var data = 'TmFtZXMNCkhhZmV6DQpTYW0NCg=='; - - var wb0 = X.read(data, { type: 'base64' }); // raw base64 string - var wb1 = X.read('data:;base64,' + data, { type: 'base64' }); // data URI, no media type - var wb2 = X.read('data:text/csv;base64,' + data, { type: 'base64' }); // data URI, CSV type - var wb3 = X.read('data:application/vnd.ms-excel;base64,' + data, { type: 'base64' }); // data URI, Excel - - [wb0, wb1, wb2, wb3].forEach(function(wb) { - var ws = wb.Sheets.Sheet1; - assert.equal(ws["!ref"], "A1:A3"); - assert.equal(get_cell(ws, "A1").v, "Names"); - assert.equal(get_cell(ws, "A2").v, "Hafez"); - assert.equal(get_cell(ws, "A3").v, "Sam"); - }); - }); if(typeof Uint8Array !== 'undefined') await t.step('should read array', async function(t) { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'}); }); }); diff --git a/testnocp.ts b/testnocp.ts index 43c706a..f8b155d 100644 --- a/testnocp.ts +++ b/testnocp.ts @@ -701,22 +701,6 @@ Deno.test('input formats', async function(t) { await t.step('should read base64 strings', async function(t) { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'base64'), {type: 'base64'}); }); }); - await t.step('handles base64 within data URI scheme (gh-2762)', async function(t) { - var data = 'TmFtZXMNCkhhZmV6DQpTYW0NCg=='; - - var wb0 = X.read(data, { type: 'base64' }); // raw base64 string - var wb1 = X.read('data:;base64,' + data, { type: 'base64' }); // data URI, no media type - var wb2 = X.read('data:text/csv;base64,' + data, { type: 'base64' }); // data URI, CSV type - var wb3 = X.read('data:application/vnd.ms-excel;base64,' + data, { type: 'base64' }); // data URI, Excel - - [wb0, wb1, wb2, wb3].forEach(function(wb) { - var ws = wb.Sheets.Sheet1; - assert.equal(ws["!ref"], "A1:A3"); - assert.equal(get_cell(ws, "A1").v, "Names"); - assert.equal(get_cell(ws, "A2").v, "Hafez"); - assert.equal(get_cell(ws, "A3").v, "Sam"); - }); - }); if(typeof Uint8Array !== 'undefined') await t.step('should read array', async function(t) { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'}); }); }); diff --git a/tests/core.js b/tests/core.js index e432438..c697cc8 100644 --- a/tests/core.js +++ b/tests/core.js @@ -688,22 +688,6 @@ describe('input formats', function() { it('should read base64 strings', function() { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'base64'), {type: 'base64'}); }); }); - it('handles base64 within data URI scheme (gh-2762)', function() { - var data = 'TmFtZXMNCkhhZmV6DQpTYW0NCg=='; - - var wb0 = X.read(data, { type: 'base64' }); // raw base64 string - var wb1 = X.read('data:;base64,' + data, { type: 'base64' }); // data URI, no media type - var wb2 = X.read('data:text/csv;base64,' + data, { type: 'base64' }); // data URI, CSV type - var wb3 = X.read('data:application/vnd.ms-excel;base64,' + data, { type: 'base64' }); // data URI, Excel - - [wb0, wb1, wb2, wb3].forEach(function(wb) { - var ws = wb.Sheets.Sheet1; - assert.equal(ws["!ref"], "A1:A3"); - assert.equal(get_cell(ws, "A1").v, "Names"); - assert.equal(get_cell(ws, "A2").v, "Hafez"); - assert.equal(get_cell(ws, "A3").v, "Sam"); - }); - }); if(typeof Uint8Array !== 'undefined') it('should read array', function() { artifax.forEach(function(p) { X.read(fs.readFileSync(p, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'}); }); }); @@ -1409,7 +1393,7 @@ describe('parse features', function() { }); describe('data types formats', function() {[ - ['xlsx', paths.dtfxlsx] + ['xlsx', paths.dtfxlsx], ].forEach(function(m) { it(m[0], function() { var wb = X.read(fs.readFileSync(m[1]), {type: TYPE, cellDates: true}); var ws = wb.Sheets[wb.SheetNames[0]]; @@ -2216,7 +2200,7 @@ describe('CSV', function() { var aoa = [ ["3a", "3 a", "3 a-1"], ["3b", "3 b", "3 b-1"], - ["3p", "3 P", "3 p-1"] + ["3p", "3 P", "3 p-1"], ] var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { diff --git a/xlsx.flow.js b/xlsx.flow.js index 20b30d1..9f9aef5 100644 --- a/xlsx.flow.js +++ b/xlsx.flow.js @@ -133,7 +133,7 @@ function Base64_encode_pass(input) { function Base64_decode(input) { var o = ""; var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; - input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/, "").replace(/[^\w\+\/\=]/g, ""); + input = input.replace(/[^\w\+\/\=]/g, ""); for (var i = 0; i < input.length; ) { e1 = Base64_map.indexOf(input.charAt(i++)); e2 = Base64_map.indexOf(input.charAt(i++)); @@ -19310,7 +19310,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { if(RecordType === 0 && last_RT === 0x000a /* EOF */) break; var length = (blob.l === blob.length ? 0 : blob.read_shift(2)); var R = XLSRecordEnum[RecordType]; - if(file_depth == 0 && [0x0009, 0x0209, 0x0409, 0x0809].indexOf(RecordType) == -1 /* BOF */) break; //console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length); //if(!R) console.log(blob.slice(blob.l, blob.l + length)); if(R && R.f) { diff --git a/xlsx.js b/xlsx.js index ea3ae67..d277b1f 100644 --- a/xlsx.js +++ b/xlsx.js @@ -132,7 +132,7 @@ function Base64_encode_pass(input) { function Base64_decode(input) { var o = ""; var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; - input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/, "").replace(/[^\w\+\/\=]/g, ""); + input = input.replace(/[^\w\+\/\=]/g, ""); for (var i = 0; i < input.length; ) { e1 = Base64_map.indexOf(input.charAt(i++)); e2 = Base64_map.indexOf(input.charAt(i++)); @@ -19204,7 +19204,6 @@ function parse_workbook(blob, options) { if(RecordType === 0 && last_RT === 0x000a /* EOF */) break; var length = (blob.l === blob.length ? 0 : blob.read_shift(2)); var R = XLSRecordEnum[RecordType]; - if(file_depth == 0 && [0x0009, 0x0209, 0x0409, 0x0809].indexOf(RecordType) == -1 /* BOF */) break; //console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length); //if(!R) console.log(blob.slice(blob.l, blob.l + length)); if(R && R.f) { diff --git a/xlsx.mjs b/xlsx.mjs index 51b5adb..80894bd 100644 --- a/xlsx.mjs +++ b/xlsx.mjs @@ -132,7 +132,7 @@ function Base64_encode_pass(input) { function Base64_decode(input) { var o = ""; var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; - input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/, "").replace(/[^\w\+\/\=]/g, ""); + input = input.replace(/[^\w\+\/\=]/g, ""); for (var i = 0; i < input.length; ) { e1 = Base64_map.indexOf(input.charAt(i++)); e2 = Base64_map.indexOf(input.charAt(i++)); @@ -19305,7 +19305,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { if(RecordType === 0 && last_RT === 0x000a /* EOF */) break; var length = (blob.l === blob.length ? 0 : blob.read_shift(2)); var R = XLSRecordEnum[RecordType]; - if(file_depth == 0 && [0x0009, 0x0209, 0x0409, 0x0809].indexOf(RecordType) == -1 /* BOF */) break; //console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length); //if(!R) console.log(blob.slice(blob.l, blob.l + length)); if(R && R.f) {