JavaScriptCore C demo
This commit is contained in:
parent
922b84e1e3
commit
671729b289
@ -37,7 +37,7 @@
|
||||
</Style>
|
||||
</Styles>
|
||||
<Worksheet ss:Name="Engines">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="16" x:FullColumns="1"
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="17" x:FullColumns="1"
|
||||
x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Column ss:Index="3" ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
@ -91,6 +91,16 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">JSC</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C++</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Jint</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C#</Data></Cell>
|
||||
|
@ -409,7 +409,7 @@ This demo was tested in the following environments:
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `2.1.1` | 2024-03-15 |
|
||||
| `win10-x64` | `2.1.1` | 2024-03-24 |
|
||||
| `linux-x64` | `2.1.1` | 2024-03-29 |
|
||||
| `linux-x64` | `2.1.1` | 2024-04-25 |
|
||||
:::
|
||||
|
||||
1) [Download and extract PhantomJS](https://phantomjs.org/download.html)
|
||||
|
@ -5,60 +5,171 @@ pagination_next: solutions/input
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
iOS and MacOS ship with the JavaScriptCore framework for running JS code from
|
||||
Swift and Objective-C. Hybrid function invocation is tricky, but explicit data
|
||||
passing is straightforward. The demo shows a standalone Swift sample for MacOS.
|
||||
[JavaScriptCore](https://developer.apple.com/documentation/javascriptcore) (JSC)
|
||||
is the JavaScript engine powering the Safari web browser.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses JSC and SheetJS to read and write spreadsheets. We'll explore how
|
||||
to load SheetJS in a JSC context and process spreadsheets and structured data
|
||||
from C++ and Swift programs.
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
||||
can be parsed and evaluated in a JSC context.
|
||||
|
||||
:::danger Platform Limitations
|
||||
|
||||
JavaScriptCore is primarily deployed in MacOS and iOS applications. There is
|
||||
some experimental support through the Bun runtime, but apps intending to support
|
||||
Windows / Linux / Android should try to embed [V8](/docs/demos/engines/v8).
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
<Tabs groupId="jsclang">
|
||||
<TabItem value="swift" label="Swift">
|
||||
|
||||
Binary strings can be passed back and forth using `String.Encoding.isoLatin1`.
|
||||
|
||||
_Initialize JavaScriptCore_
|
||||
The SheetJS `read` method[^1], with the `"binary"` type, can parse binary strings.
|
||||
|
||||
JSC does not provide a `global` variable. It can be created in one line:
|
||||
The `write` method[^2], with the `"binary"` type, can create binary strings.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cpp" label="C++">
|
||||
|
||||
JSC provides a few special methods for working with `Uint8Array` objects:
|
||||
|
||||
- `JSObjectMakeTypedArrayWithBytesNoCopy`[^3] creates a typed array from a
|
||||
pointer and size. It uses the memory address directly (no copy).
|
||||
|
||||
- `JSObjectGetTypedArrayLength`[^4] and `JSObjectGetTypedArrayBytesPtr`[^5] can
|
||||
return a pointer and size pair from a `Uint8Array` in the JSC engine.
|
||||
|
||||
The SheetJS `read` method[^6] can process `Uint8Array` objects.
|
||||
|
||||
The `write` method[^7], with the `"buffer"` type, creates `Uint8Array` data.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Initialize JSC
|
||||
|
||||
<Tabs groupId="jsclang">
|
||||
<TabItem value="swift" label="Swift">
|
||||
|
||||
A JSC context can be created with the `JSContext` function:
|
||||
|
||||
```swift
|
||||
var context: JSContext!
|
||||
do {
|
||||
context = JSContext();
|
||||
context.exceptionHandler = { _, X in if let e = X { print(e.toString()!); }; };
|
||||
} catch { print(error.localizedDescription); }
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cpp" label="C++">
|
||||
|
||||
A JSC context can be created with the `JSGlobalContextCreate` function:
|
||||
|
||||
```cpp
|
||||
JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
JSC does not provide a `global` variable. It can be created in one line:
|
||||
|
||||
<Tabs groupId="jsclang">
|
||||
<TabItem value="swift" label="Swift">
|
||||
|
||||
```swift
|
||||
do {
|
||||
// highlight-next-line
|
||||
context.evaluateScript("var global = (function(){ return this; }).call(null);");
|
||||
} catch { print(error.localizedDescription); }
|
||||
```
|
||||
|
||||
_Load SheetJS Scripts_
|
||||
</TabItem>
|
||||
<TabItem value="cpp" label="C++">
|
||||
|
||||
```cpp
|
||||
#define DOIT(cmd) \
|
||||
JSStringRef script = JSStringCreateWithUTF8CString(cmd); \
|
||||
JSValueRef result = JSEvaluateScript(ctx, script, NULL, NULL, 0, NULL); \
|
||||
JSStringRelease(script);
|
||||
|
||||
{ DOIT("var global = (function(){ return this; }).call(null);") }
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Load SheetJS Scripts
|
||||
|
||||
The main library can be loaded by reading the scripts from the file system and
|
||||
evaluating in the JSC context:
|
||||
|
||||
<Tabs groupId="jsclang">
|
||||
<TabItem value="swift" label="Swift">
|
||||
|
||||
```swift
|
||||
let src = try String(contentsOfFile: "xlsx.full.min.js");
|
||||
context.evaluateScript(src);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cpp" label="C++">
|
||||
|
||||
```cpp
|
||||
/* load library */
|
||||
{
|
||||
size_t sz = 0; char *file = read_file("xlsx.full.min.js", &sz);
|
||||
DOIT(file);
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
To confirm the library is loaded, `XLSX.version` can be inspected:
|
||||
|
||||
<Tabs groupId="jsclang">
|
||||
<TabItem value="swift" label="Swift">
|
||||
|
||||
```swift
|
||||
let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
|
||||
if let ver = XLSX.objectForKeyedSubscript("version") { print(ver.toString()); }
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cpp" label="C++">
|
||||
|
||||
```cpp
|
||||
#define JS_STR_TO_C \
|
||||
JSStringRef str = JSValueToStringCopy(ctx, result, NULL); \
|
||||
size_t sz = JSStringGetMaximumUTF8CStringSize(str); \
|
||||
char *buf = (char *)malloc(sz); \
|
||||
JSStringGetUTF8CString(str, buf, sz); \
|
||||
|
||||
/* get version string */
|
||||
{
|
||||
DOIT("XLSX.version")
|
||||
|
||||
JS_STR_TO_C
|
||||
|
||||
printf("SheetJS library version %s\n", buf);
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Reading Files
|
||||
|
||||
<Tabs groupId="jsclang">
|
||||
<TabItem value="swift" label="Swift">
|
||||
|
||||
`String(contentsOf:encoding:)` reads from a path and returns an encoded string:
|
||||
|
||||
```swift
|
||||
@ -104,8 +215,41 @@ For broad compatibility with Swift versions, the demo uses the String method.
|
||||
|
||||
</details>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cpp" label="C++">
|
||||
|
||||
There are a few steps for loading data into the JSC engine:
|
||||
|
||||
A) The file must be read into a `char*` buffer (using standard C methods)
|
||||
|
||||
```cpp
|
||||
size_t sz; char *file = read_file(argv[1], &sz);
|
||||
```
|
||||
|
||||
B) The typed array must be created with `JSObjectMakeTypedArrayWithBytesNoCopy`
|
||||
|
||||
```cpp
|
||||
JSValueRef u8 = JSObjectMakeTypedArrayWithBytesNoCopy(ctx, kJSTypedArrayTypeUint8Array, file, sz, NULL, NULL, NULL);
|
||||
```
|
||||
|
||||
C) The typed array must be bound to a variable in the global scope:
|
||||
|
||||
```cpp
|
||||
/* assign to `global.buf` */
|
||||
JSObjectRef global = JSContextGetGlobalObject(ctx);
|
||||
JSStringRef key = JSStringCreateWithUTF8CString("buf");
|
||||
JSObjectSetProperty(ctx, global, key, u8, 0, NULL);
|
||||
JSStringRelease(key);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Writing Files
|
||||
|
||||
<Tabs groupId="jsclang">
|
||||
<TabItem value="swift" label="Swift">
|
||||
|
||||
When writing to binary string in JavaScriptCore, the result should be stored in
|
||||
a variable and converted to string in Swift:
|
||||
|
||||
@ -126,8 +270,41 @@ let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx");
|
||||
try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cpp" label="C++">
|
||||
|
||||
The SheetJS `write` method with type `"buffer"` will return a `Uint8Array` object:
|
||||
|
||||
```cpp
|
||||
DOIT("XLSX.write(wb, {type:'buffer', bookType:'xlsb'});")
|
||||
JSObjectRef u8 = JSValueToObject(ctx, result, NULL);
|
||||
```
|
||||
|
||||
Given the result object, `JSObjectGetTypedArrayLength` pulls the length into C:
|
||||
|
||||
```cpp
|
||||
size_t sz = JSObjectGetTypedArrayLength(ctx, u8, NULL);
|
||||
```
|
||||
|
||||
`JSObjectGetTypedArrayBytesPtr` returns a pointer to the result buffer:
|
||||
|
||||
```cpp
|
||||
char *buf = (char *)JSObjectGetTypedArrayBytesPtr(ctx, u8, NULL);
|
||||
```
|
||||
|
||||
The data can be written to file using standard C methods:
|
||||
|
||||
```cpp
|
||||
FILE *f = fopen("sheetjsw.xlsb", "wb"); fwrite(buf, 1, sz, f); fclose(f);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Complete Example
|
||||
|
||||
### Swift
|
||||
|
||||
:::note pass
|
||||
|
||||
This demo was tested in the following environments:
|
||||
@ -200,3 +377,162 @@ swiftc SheetJSCore.swift main.swift -o SheetJSwift
|
||||
|
||||
If successful, a CSV will be printed to console. The script also tries to write
|
||||
to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers.
|
||||
|
||||
### C++
|
||||
|
||||
:::note pass
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Architecture | Version | Date |
|
||||
|:-------------|:-----------------|:-----------|
|
||||
| `darwin-x64` | `7618.1.15.14.7` | 2024-04-24 |
|
||||
| `linux-x64` | `7618.1.15.14.7` | 2024-04-24 |
|
||||
|
||||
:::
|
||||
|
||||
0) Install dependencies
|
||||
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
On the Steam Deck, a few dependencies must be installed before building JSC:
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu base-devel cmake ruby icu glibc linux-api-headers
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
1) Create a project folder:
|
||||
|
||||
```bash
|
||||
mkdir sheetjs-jsc
|
||||
cd sheetjs-jsc
|
||||
```
|
||||
|
||||
2) Download and extract the WebKit snapshot:
|
||||
|
||||
```bash
|
||||
curl -LO https://codeload.github.com/WebKit/WebKit/zip/refs/tags/WebKit-7618.1.15.14.7
|
||||
mv WebKit-7618.1.15.14.7 WebKit.zip
|
||||
unzip WebKit.zip
|
||||
```
|
||||
|
||||
3) Build JavaScriptCore:
|
||||
|
||||
<Tabs groupId="triple">
|
||||
<TabItem value="darwin-x64" label="MacOS">
|
||||
|
||||
```bash
|
||||
cd WebKit-WebKit-7618.1.15.14.7
|
||||
Tools/Scripts/build-webkit --jsc-only --cmakeargs="-DENABLE_STATIC_JSC=ON"
|
||||
cd ..
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
|
||||
When this demo was tested on macOS, the build failed with the error message
|
||||
|
||||
```
|
||||
Source/WTF/wtf/text/ASCIILiteral.h:65:34: error: use of undeclared identifier 'NSString'
|
||||
WTF_EXPORT_PRIVATE RetainPtr<NSString> createNSString() const;
|
||||
^
|
||||
1 error generated.
|
||||
```
|
||||
|
||||
The referenced header file must be patched to declare `NSString`:
|
||||
|
||||
```objc title="Source/WTF/wtf/text/ASCIILiteral.h (add highlighted lines)"
|
||||
#include <wtf/text/SuperFastHash.h>
|
||||
|
||||
// highlight-start
|
||||
#ifdef __OBJC__
|
||||
@class NSString;
|
||||
#endif
|
||||
// highlight-end
|
||||
|
||||
namespace WTF {
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="linux-x64" label="Linux">
|
||||
|
||||
```bash
|
||||
cd WebKit-WebKit-7618.1.15.14.7
|
||||
env CFLAGS="-Wno-error=dangling-reference -Wno-dangling-reference" CXXFLAGS="-Wno-error=dangling-reference -Wno-dangling-reference" Tools/Scripts/build-webkit --jsc-only --cmakeargs="-Wno-error -DENABLE_STATIC_JSC=ON -DUSE_THIN_ARCHIVES=OFF -DCMAKE_C_FLAGS="-Wno-error -Wno-dangling-reference" -DCMAKE_CXX_FLAGS=-Wno-error -Wno-dangling-reference" --make-args="-j1 -Wno-error -Wno-error=dangling-reference" -j1
|
||||
cd ..
|
||||
```
|
||||
|
||||
:::danger pass
|
||||
|
||||
When this was last tested on the Steam Deck, the build ran for 24 minutes!
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
4) Create a symbolic link to the `Release` folder in the source tree:
|
||||
|
||||
```bash
|
||||
ln -s WebKit-WebKit-7618.1.15.14.7/WebKitBuild/JSCOnly/Release/ .
|
||||
```
|
||||
|
||||
5) Download [`sheetjs-jsc.c`](pathname:///jsc/sheetjs-jsc.c):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/jsc/sheetjs-jsc.c
|
||||
```
|
||||
|
||||
6) Compile the program:
|
||||
|
||||
<Tabs groupId="triple">
|
||||
<TabItem value="darwin-x64" label="MacOS">
|
||||
|
||||
```bash
|
||||
g++ -o sheetjs-jsc sheetjs-jsc.c -IRelease/JavaScriptCore/Headers -LRelease/lib -lbmalloc -licucore -lWTF -lJavaScriptCore -IRelease/JavaScriptCore/Headers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="linux-x64" label="Linux">
|
||||
|
||||
```bash
|
||||
g++ -o sheetjs-jsc sheetjs-jsc.c -IRelease/JavaScriptCore/Headers -LRelease/lib -lJavaScriptCore -lWTF -lbmalloc -licui18n -licuuc -latomic -IRelease/JavaScriptCore/Headers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
7) Download the SheetJS Standalone script and the test file. Save both files in
|
||||
the project directory:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
|
||||
curl -LO https://sheetjs.com/pres.numbers`}
|
||||
</CodeBlock>
|
||||
|
||||
8) Run the program:
|
||||
|
||||
```bash
|
||||
./sheetjs-jsc pres.numbers
|
||||
```
|
||||
|
||||
If successful, a CSV will be printed to console. The script also tries to write
|
||||
to `sheetjsw.xlsb`, which can be opened in a spreadsheet editor.
|
||||
|
||||
[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^3]: See [`JSObjectMakeTypedArrayWithBytesNoCopy`](https://developer.apple.com/documentation/javascriptcore/jsobjectmaketypedarraywithbytesnocopy(_:_:_:_:_:_:_:)/) in the JavaScriptCore documentation.
|
||||
[^4]: See [`JSObjectGetTypedArrayLength`](https://developer.apple.com/documentation/javascriptcore/jsobjectgettypedarraylength(_:_:_:)/) in the JavaScriptCore documentation.
|
||||
[^5]: See [`JSObjectGetTypedArrayBytesPtr`](
|
||||
https://developer.apple.com/documentation/javascriptcore/jsobjectgettypedarraybytesptr(_:_:_:)/) in the JavaScriptCore documentation.
|
||||
[^6]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^7]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
@ -117,7 +117,7 @@ The estimate can be recovered from the array:
|
||||
var estimate = int + num / den;
|
||||
```
|
||||
|
||||
If `mixed` is `false`, then `int = 0` and `0` ≤ `|num|` < `den` ≤ `D`
|
||||
If `mixed` is `false`, then `int = 0` and `0` < `den` ≤ `D`
|
||||
|
||||
If `mixed` is `true`, then `0` ≤ `num` < `den` ≤ `D`
|
||||
|
||||
|
112
docz/static/jsc/sheetjs-jsc.c
Normal file
112
docz/static/jsc/sheetjs-jsc.c
Normal file
@ -0,0 +1,112 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <JavaScriptCore/JavaScript.h>
|
||||
|
||||
/* simple wrapper to read the entire script file */
|
||||
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(buf, 1, fsize, f);
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define JS_STR_TO_C \
|
||||
JSStringRef str = JSValueToStringCopy(ctx, result, NULL); \
|
||||
size_t sz = JSStringGetMaximumUTF8CStringSize(str); \
|
||||
char *buf = (char *)malloc(sz); \
|
||||
JSStringGetUTF8CString(str, buf, sz); \
|
||||
|
||||
#define DOIT(cmd) \
|
||||
JSStringRef script = JSStringCreateWithUTF8CString(cmd); \
|
||||
JSValueRef result = JSEvaluateScript(ctx, script, NULL, NULL, 0, NULL); \
|
||||
JSStringRelease(script);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int res = 0;
|
||||
size_t sz = 0;
|
||||
char *file = NULL;
|
||||
|
||||
/* initialize */
|
||||
JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);
|
||||
/* JSC does not expose a standard "global" by default */
|
||||
{ DOIT("var global = (function(){ return this; }).call(null);") }
|
||||
|
||||
/* load library */
|
||||
{
|
||||
file = read_file("xlsx.full.min.js", &sz);
|
||||
DOIT(file);
|
||||
free(file);
|
||||
}
|
||||
|
||||
/* get version string */
|
||||
{
|
||||
DOIT("XLSX.version")
|
||||
|
||||
if(!JSValueIsString(ctx, result)) {
|
||||
printf("Could not get SheetJS version.\n");
|
||||
res = 1; goto cleanup;
|
||||
}
|
||||
|
||||
JS_STR_TO_C
|
||||
|
||||
printf("SheetJS library version %s\n", buf);
|
||||
free(buf);
|
||||
JSStringRelease(str);
|
||||
}
|
||||
|
||||
/* read file */
|
||||
file = read_file(argv[1], &sz);
|
||||
{
|
||||
/* push data to JSC */
|
||||
JSValueRef u8 = JSObjectMakeTypedArrayWithBytesNoCopy(ctx, kJSTypedArrayTypeUint8Array, file, sz, NULL, NULL, NULL);
|
||||
|
||||
/* assign to `global.buf` */
|
||||
JSObjectRef global = JSContextGetGlobalObject(ctx);
|
||||
JSStringRef key = JSStringCreateWithUTF8CString("buf");
|
||||
JSObjectSetProperty(ctx, global, key, u8, 0, NULL);
|
||||
JSStringRelease(key);
|
||||
}
|
||||
|
||||
/* parse workbook and print CSV */
|
||||
{
|
||||
DOIT(
|
||||
"var wb = XLSX.read(global.buf);"
|
||||
"var ws = wb.Sheets[wb.SheetNames[0]];"
|
||||
"XLSX.utils.sheet_to_csv(ws)"
|
||||
)
|
||||
|
||||
if(!JSValueIsString(ctx, result)) {
|
||||
printf("Could not generate CSV.\n");
|
||||
res = 2; goto cleanup;
|
||||
}
|
||||
|
||||
JS_STR_TO_C
|
||||
|
||||
printf("%s\n", buf);
|
||||
free(buf);
|
||||
JSStringRelease(str);
|
||||
}
|
||||
|
||||
/* write file */
|
||||
{
|
||||
DOIT("XLSX.write(wb, {type:'buffer', bookType:'xlsb'});")
|
||||
|
||||
/* pull Uint8Array data back to C */
|
||||
JSObjectRef u8 = JSValueToObject(ctx, result, NULL);
|
||||
size_t sz = JSObjectGetTypedArrayLength(ctx, u8, NULL);
|
||||
char *buf = (char *)JSObjectGetTypedArrayBytesPtr(ctx, u8, NULL);
|
||||
|
||||
/* save file */
|
||||
FILE *f = fopen("sheetjsw.xlsb", "wb"); fwrite(buf, 1, sz, f); fclose(f);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
// Release the JavaScript context
|
||||
JSGlobalContextRelease(ctx);
|
||||
if(file) free(file);
|
||||
|
||||
return res;
|
||||
}
|
Loading…
Reference in New Issue
Block a user