2022-08-08 06:59:57 +00:00
|
|
|
---
|
|
|
|
title: JavaScript Engines
|
2023-02-13 04:07:25 +00:00
|
|
|
pagination_prev: demos/cli
|
|
|
|
pagination_next: demos/clipboard
|
2022-08-08 06:59:57 +00:00
|
|
|
---
|
|
|
|
|
|
|
|
import current from '/version.js';
|
|
|
|
import Tabs from '@theme/Tabs';
|
|
|
|
import TabItem from '@theme/TabItem';
|
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
Browser vendors and other organizations have built "JavaScript engines". They
|
|
|
|
are independent software libraries that are capable of running JS scripts.
|
|
|
|
|
2022-08-08 06:59:57 +00:00
|
|
|
The most popular JavaScript engine is V8. Designed for embedding in software,
|
2022-08-25 08:22:28 +00:00
|
|
|
it powers Chrome, NodeJS, UXP, Deno and many other platforms.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2022-08-25 08:22:28 +00:00
|
|
|
There are many other JS engines with different design goals. Some are designed
|
2022-08-08 06:59:57 +00:00
|
|
|
for low-power or low-memory environments. Others aim for interoperability with
|
2022-08-25 08:22:28 +00:00
|
|
|
specific programming languages or environments. Typically they support ES3 and
|
|
|
|
are capable of running SheetJS code.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
This demo showcases a number of JS engines and language bindings.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
## General Caveats
|
|
|
|
|
|
|
|
Common browser and NodeJS APIs are often missing from light-weight JS engines.
|
|
|
|
|
|
|
|
**Global**
|
|
|
|
|
|
|
|
Some engines do not provide `globalThis` or `global` or `window`. A `global`
|
|
|
|
variable can be exposed in one line that should be run in the JS engine:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var global = (function(){ return this; }).call(null);
|
|
|
|
```
|
|
|
|
|
|
|
|
**Console**
|
|
|
|
|
|
|
|
Some engines do not provide a `console` object. `console.log` can be shimmed
|
|
|
|
using the engine functionality. For example, `hermes` provides `print()`:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var console = { log: function(x) { print(x); } };
|
|
|
|
```
|
|
|
|
|
|
|
|
**Binary Data**
|
|
|
|
|
2022-08-25 08:22:28 +00:00
|
|
|
Some engines do not provide easy ways to exchange binary data. For example, it
|
|
|
|
is common to pass null-terminated arrays, which would truncate XLSX, XLS, and
|
|
|
|
other exports. APIs that accept pointers without length should be avoided.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
Base64 strings are safe for passing between JS and native code, but they should
|
|
|
|
only be used when there is no safe way to pass `ArrayBuffer` or `Uint8Array`.
|
|
|
|
|
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
## Engines
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
This list is sorted in alphabetical order.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
### Duktape
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
Duktape is an embeddable JS engine written in C. It has been ported to a number
|
|
|
|
of exotic architectures and operating systems.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
This demo has been moved [to a dedicated page](/docs/demos/engines/duktape).
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
### Goja
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
Goja is a pure Go implementation of ECMAScript 5. It supports the standalone
|
|
|
|
scripts out of the box.
|
|
|
|
|
|
|
|
**Reading data**
|
|
|
|
|
|
|
|
Files can be read into `[]byte`:
|
|
|
|
|
|
|
|
```go
|
|
|
|
/* read file */
|
|
|
|
data, _ := ioutil.ReadFile("sheetjs.xlsx")
|
|
|
|
```
|
|
|
|
|
|
|
|
`[]byte` should be converted to an `ArrayBuffer` from Go:
|
|
|
|
|
|
|
|
```go
|
|
|
|
/* load into engine */
|
|
|
|
vm.Set("buf", vm.ToValue(vm.NewArrayBuffer(data)))
|
|
|
|
|
|
|
|
/* parse */
|
|
|
|
wb, _ = vm.RunString("wb = XLSX.read(buf, {type:'buffer'});")
|
|
|
|
```
|
|
|
|
|
|
|
|
**Writing data**
|
|
|
|
|
|
|
|
`"base64"` strings can be decoded in Go:
|
|
|
|
|
|
|
|
```go
|
2022-08-25 08:22:28 +00:00
|
|
|
/* write to Base64 string */
|
2022-08-08 06:59:57 +00:00
|
|
|
b64str, _ := vm.RunString("XLSX.write(wb, {type:'base64', bookType:'xlsx'})")
|
|
|
|
|
|
|
|
/* pull data back into Go and write to file */
|
|
|
|
buf, _ := base64.StdEncoding.DecodeString(b64str.String())
|
|
|
|
_ = ioutil.WriteFile("sheetjs.xlsx", buf, 0644)
|
|
|
|
```
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
0) Install Go
|
|
|
|
|
|
|
|
1) Create a `go.mod` file and install dependencies:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
go mod init SheetGoja
|
|
|
|
go get github.com/dop251/goja
|
|
|
|
```
|
|
|
|
|
|
|
|
2) Download the standalone script and the shim:
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
3) Save the following code to `SheetGoja.go`:
|
|
|
|
|
|
|
|
```go title="SheetGoja.go"
|
|
|
|
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) {
|
|
|
|
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", vm.ToValue(vm.NewArrayBuffer(data)))
|
|
|
|
fmt.Printf("Loaded file %s\n", os.Args[1])
|
|
|
|
|
|
|
|
/* parse workbook */
|
|
|
|
eval_string(vm, "wb = XLSX.read(buf, {type:'buffer'});")
|
|
|
|
fmt.Printf("Parsed %s\n", os.Args[1])
|
|
|
|
eval_string(vm, "ws = wb.Sheets[wb.SheetNames[0]]")
|
|
|
|
fmt.Printf("Grabbed %s\n", os.Args[1])
|
|
|
|
|
|
|
|
/* print CSV */
|
|
|
|
csv := eval_string(vm, "XLSX.utils.sheet_to_csv(ws)")
|
|
|
|
fmt.Printf("%s\n", csv)
|
|
|
|
|
|
|
|
/* write file */
|
|
|
|
write_type(vm, "csv")
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
4) Build `SheetGoja`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
go build SheetGoja.go
|
|
|
|
```
|
|
|
|
|
|
|
|
For testing, download <https://sheetjs.com/pres.numbers> and run
|
|
|
|
|
|
|
|
```bash
|
|
|
|
./SheetGoja pres.numbers
|
|
|
|
```
|
|
|
|
|
|
|
|
This will print the contents as a CSV to screen AND write to `sheetjsg.csv`
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
### Hermes
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
Hermes is an embeddable JS engine for React Native. The library and binary
|
|
|
|
distributions include a command-line tool `hermes` 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.
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
|
|
|
The official release includes the `hermes` standalone tool. While applications
|
|
|
|
should link against the official libraries, the standalone tool is useful for
|
|
|
|
verifying functionality.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
Due to limitations of the standalone binary, this demo will encode a test file
|
|
|
|
as a Base64 string and directly add it to an amalgamated script.
|
|
|
|
|
|
|
|
0) Install the `hermes` command line tool
|
|
|
|
|
|
|
|
1) Download the standalone script, shim, and test file:
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
|
|
|
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
2) Bundle the test file and create `payload.js`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')"
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Create support scripts:
|
|
|
|
|
|
|
|
- `global.js` creates a `global` variable and defines a fake `console`:
|
|
|
|
|
|
|
|
```js title="global.js"
|
|
|
|
var global = (function(){ return this; }).call(null);
|
|
|
|
var console = { log: function(x) { print(x); } };
|
|
|
|
```
|
|
|
|
|
|
|
|
- `hermes.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
|
|
|
|
|
|
|
|
```js title="hermes.js"
|
2022-10-20 18:47:20 +00:00
|
|
|
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
2022-08-08 06:59:57 +00:00
|
|
|
var wb = XLSX.read(payload, {type:'base64'});
|
|
|
|
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
|
|
|
```
|
|
|
|
|
|
|
|
4) Create the amalgamation `xlsx.hermes.js`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cat global.js xlsx.full.min.js payload.js hermes.js > xlsx.hermes.js
|
|
|
|
```
|
|
|
|
|
|
|
|
The final script defines `global` before loading the standalone library. Once
|
2022-08-25 08:22:28 +00:00
|
|
|
ready, it will read the bundled test data and print the contents as CSV.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
5) Run the script using the Hermes standalone binary:
|
|
|
|
|
2022-08-18 08:41:34 +00:00
|
|
|
```bash
|
2022-08-08 06:59:57 +00:00
|
|
|
hermes xlsx.hermes.js
|
|
|
|
```
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
### JavaScriptCore
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2022-08-23 03:20:02 +00:00
|
|
|
iOS and MacOS ship with the JavaScriptCore framework for running JS code from
|
2023-02-13 04:07:25 +00:00
|
|
|
Swift and Objective-C.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
This demo has been moved [to a dedicated page](/docs/demos/engines/jsc).
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
### JerryScript
|
2022-08-18 08:41:34 +00:00
|
|
|
|
|
|
|
JerryScript is a lightweight JavaScript engine designed for use in low-memory
|
|
|
|
environments like microcontrollers. As part of the build suite, the project
|
|
|
|
generates a C library and a standalone CLI tool.
|
|
|
|
|
|
|
|
The simplest way to interact with the engine is to pass Base64 strings.
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
|
|
|
While applications should link against the official libraries, the standalone tool
|
|
|
|
is useful for verifying functionality.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
:::caution
|
|
|
|
|
|
|
|
This demo requires a much larger heap size than is normally used in JerryScript
|
|
|
|
deployments! In local testing, the following sizes were needed:
|
|
|
|
|
|
|
|
- 8192 (8M) for <https://sheetjs.com/pres.xlsx>
|
|
|
|
- 65536 (64M) for <https://sheetjs.com/pres.numbers>
|
|
|
|
|
|
|
|
This works on a Raspberry Pi.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
Due to limitations of the standalone binary, this demo will encode a test file
|
|
|
|
as a Base64 string and directly add it to an amalgamated script.
|
|
|
|
|
|
|
|
0) Build the library and command line tool with required options:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git
|
|
|
|
cd jerryscript
|
|
|
|
python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON
|
|
|
|
```
|
|
|
|
|
|
|
|
1) Download the standalone script, shim, and test file:
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
|
|
|
<li><a href="https://sheetjs.com/pres.xlsx">pres.xlsx</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
2) Bundle the test file and create `payload.js`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.xlsx').toString('base64') + '\";')"
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Create support scripts:
|
|
|
|
|
|
|
|
- `global.js` creates a `global` variable and defines a fake `console`:
|
|
|
|
|
|
|
|
```js title="global.js"
|
|
|
|
var global = (function(){ return this; }).call(null);
|
|
|
|
var console = { log: function(x) { print(x); } };
|
|
|
|
```
|
|
|
|
|
|
|
|
- `jerry.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
|
|
|
|
|
|
|
|
```js title="jerry.js"
|
2022-10-20 18:47:20 +00:00
|
|
|
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
2022-08-18 08:41:34 +00:00
|
|
|
var wb = XLSX.read(payload, {type:'base64'});
|
|
|
|
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
|
|
|
```
|
|
|
|
|
|
|
|
4) Create the amalgamation `xlsx.jerry.js`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cat global.js xlsx.full.min.js payload.js jerry.js > xlsx.jerry.js
|
|
|
|
```
|
|
|
|
|
|
|
|
The final script defines `global` before loading the standalone library. Once
|
2022-08-25 08:22:28 +00:00
|
|
|
ready, it will read the bundled test data and print the contents as CSV.
|
2022-08-18 08:41:34 +00:00
|
|
|
|
|
|
|
5) Run the script using the `jerry` standalone binary:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
build/bin/jerry xlsx.jerry.js; echo $?
|
|
|
|
```
|
|
|
|
|
|
|
|
</details>
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
|
|
|
|
### QuickJS
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
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 standalone browser scripts.
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
0) Ensure `quickjs` command line utility is installed
|
|
|
|
|
|
|
|
1) Download the standalone script, the shim and the test file:
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
|
|
|
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
2) Save the following script to `SheetJSQuick.js`:
|
|
|
|
|
2022-11-13 20:45:13 +00:00
|
|
|
```js title="SheetJSQuick.js"
|
2022-10-20 18:47:20 +00:00
|
|
|
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
2022-08-08 06:59:57 +00:00
|
|
|
/* load XLSX */
|
|
|
|
import * as std from "std";
|
|
|
|
globalThis.global = globalThis;
|
|
|
|
std.loadScript("xlsx.full.min.js");
|
|
|
|
|
|
|
|
/* read contents of file */
|
|
|
|
var rh = std.open("pres.numbers", "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 */
|
2022-11-13 20:45:13 +00:00
|
|
|
var wb = XLSX.read(ab);
|
2022-08-08 06:59:57 +00:00
|
|
|
|
2022-11-13 20:45:13 +00:00
|
|
|
/* write XLSX */
|
|
|
|
var out = XLSX.write(wb, {bookType: "xlsx", type: "array"});
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
/* write contents to file */
|
|
|
|
var wh = std.open("SheetJSQuick.xlsx", "wb");
|
|
|
|
wh.write(out, 0, out.byteLength);
|
|
|
|
wh.close();
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Test the program:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
quickjs SheetJSQuick.js
|
|
|
|
```
|
|
|
|
|
|
|
|
If successful, the script will generate `SheetJSQuick.xlsx`.
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
|
2023-02-13 04:07:25 +00:00
|
|
|
### Rhino
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
Rhino is an ES3+ engine 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);
|
|
|
|
```
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
0) Download the appropriate Rhino build and rename to `rhino.jar`
|
|
|
|
|
|
|
|
1) Download [`SheetJSRhino.zip`](pathname:///rhino/SheetJSRhino.zip) and unzip
|
|
|
|
|
|
|
|
2) Save the following code to `SheetJSRhino.java`:
|
|
|
|
|
|
|
|
```java title="SheetJSRhino.java"
|
2022-10-20 18:47:20 +00:00
|
|
|
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
2022-08-08 06:59:57 +00:00
|
|
|
/* 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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Assemble `SheetJS.jar` from the demo code:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
javac -cp .:rhino.jar SheetJSRhino.java
|
|
|
|
jar -cf SheetJS.jar SheetJSRhino.class com/sheetjs/*.class
|
|
|
|
```
|
|
|
|
|
|
|
|
4) Download <https://sheetjs.com/pres.xlsx> and test:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino pres.xlsx
|
|
|
|
```
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
## Legacy Engines
|
|
|
|
|
|
|
|
:::warning
|
|
|
|
|
|
|
|
These examples were written when the engines were maintained. New projects
|
|
|
|
should not use these engines. The demos are included for legacy deployments.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
### ChakraCore
|
|
|
|
|
|
|
|
:::caution
|
|
|
|
|
|
|
|
ChakraCore was an open source JavaScript engine released by Microsoft. It was a
|
|
|
|
fork of the Chakra engine that powered Internet Explorer. When Microsoft Edge
|
|
|
|
switched to become a fork of Chromium, Microsoft stopped providing support.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
|
|
|
The official release includes the `ch` standalone binary. While applications
|
|
|
|
should link against the official libraries, the standalone tool is useful for
|
|
|
|
verifying functionality.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
Due to limitations of the standalone binary, this demo will encode a test file
|
|
|
|
as a Base64 string and directly add it to an amalgamated script.
|
|
|
|
|
|
|
|
0) Download and extract the ChakraCore release ZIP. Copy the binary (`bin/ch`)
|
|
|
|
to your project folder.
|
|
|
|
|
|
|
|
1) Download the standalone script, shim, and test file:
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
|
|
|
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
2) Bundle the test file and create `payload.js`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')"
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Create support scripts:
|
|
|
|
|
|
|
|
- `global.js` creates a `global` variable:
|
|
|
|
|
|
|
|
```js title="global.js"
|
|
|
|
var global = (function(){ return this; }).call(null);
|
|
|
|
```
|
|
|
|
|
|
|
|
- `chakra.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
|
|
|
|
|
|
|
|
```js title="chakra.js"
|
2022-10-20 18:47:20 +00:00
|
|
|
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
2022-08-08 06:59:57 +00:00
|
|
|
var wb = XLSX.read(payload, {type:'base64'});
|
|
|
|
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
|
|
|
```
|
|
|
|
|
|
|
|
4) Create the amalgamation `xlsx.chakra.js`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cat global.js xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js
|
|
|
|
```
|
|
|
|
|
|
|
|
The final script defines `global` before loading the standalone library. Once
|
2022-08-25 08:22:28 +00:00
|
|
|
ready, it will read the bundled test data and print the contents as CSV.
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
5) Run the script using the ChakraCore standalone binary:
|
|
|
|
|
|
|
|
```
|
|
|
|
./ch xlsx.chakra.js
|
|
|
|
```
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
|
|
|
|
### Nashorn
|
|
|
|
|
|
|
|
:::caution
|
|
|
|
|
|
|
|
Nashorn shipped with Java 8. It was deprecated in Java 11 and was officially
|
|
|
|
removed in JDK 15. New Java applications should use [Rhino](#rhino).
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
|
|
|
|
Nashorn ships with Java. 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);
|
2022-11-13 20:45:13 +00:00
|
|
|
load('shim.min.js');
|
2022-08-08 06:59:57 +00:00
|
|
|
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"`.
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
0) Ensure `jjs` is available on system path
|
|
|
|
|
|
|
|
1) Download the standalone script, the shim and the test file:
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
|
|
|
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
2) Save the following script to `SheetJSNashorn.js`:
|
|
|
|
|
|
|
|
```js title="SheetJSNashorn.js"
|
2022-10-20 18:47:20 +00:00
|
|
|
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
/* load module */
|
|
|
|
var global = (function(){ return this; }).call(null);
|
2022-11-13 20:45:13 +00:00
|
|
|
load('shim.min.js');
|
2022-08-08 06:59:57 +00:00
|
|
|
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 */
|
2022-11-13 20:45:13 +00:00
|
|
|
var wb = XLSX.read(u8a);
|
2022-08-08 06:59:57 +00:00
|
|
|
|
|
|
|
/* 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('pres.numbers');
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Test the script:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
jjs SheetJSNashorn.js
|
|
|
|
```
|
|
|
|
|
|
|
|
It will print out the first worksheet contents.
|
|
|
|
|
|
|
|
</details>
|