forked from sheetjs/docs.sheetjs.com
		
	
		
			
	
	
		
			233 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			233 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|  | --- | ||
|  | title: C++ + ChakraCore | ||
|  | pagination_prev: demos/bigdata/index | ||
|  | pagination_next: solutions/input | ||
|  | --- | ||
|  | 
 | ||
|  | ChakraCore is an embeddable JS engine written in C++. | ||
|  | 
 | ||
|  | The [Standalone scripts](/docs/getting-started/installation/standalone) can be | ||
|  | parsed and evaluated in a ChakraCore context. | ||
|  | 
 | ||
|  | ## Integration Details
 | ||
|  | 
 | ||
|  | _Initialize ChakraCore_ | ||
|  | 
 | ||
|  | ChakraCore provides a `global` object through `JsGetGlobalObject`: | ||
|  | 
 | ||
|  | ```cpp | ||
|  | /* initialize */ | ||
|  | JsRuntimeHandle runtime; | ||
|  | JsContextRef context; | ||
|  | size_t cookie = 0; | ||
|  | JsCreateRuntime(JsRuntimeAttributeNone, nullptr, &runtime); | ||
|  | JsCreateContext(runtime, &context); | ||
|  | JsSetCurrentContext(context); | ||
|  | 
 | ||
|  | /* obtain reference to global object */ | ||
|  | JsValueRef global; | ||
|  | JsGetGlobalObject(&global); | ||
|  | 
 | ||
|  | /* DO WORK HERE */ | ||
|  | 
 | ||
|  | /* cleanup */ | ||
|  | JsSetCurrentContext(JS_INVALID_REFERENCE); | ||
|  | JsDisposeRuntime(runtime); | ||
|  | ``` | ||
|  | 
 | ||
|  | :::note | ||
|  | 
 | ||
|  | Cleanup and validation code is omitted from the discussion.  The integration | ||
|  | example shows structured validation and controlled memory usage. | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | _Load SheetJS Scripts_ | ||
|  | 
 | ||
|  | The main library can be loaded by reading the script from the file system and | ||
|  | evaluating in the ChakraCore context: | ||
|  | 
 | ||
|  | ```cpp | ||
|  | 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; | ||
|  | } | ||
|  | 
 | ||
|  | #define EVAL_FILE(path) {\
 | ||
|  |   JsValueRef filename; \ | ||
|  |   JsValueRef result; \ | ||
|  |   JsCreateString(path, strlen(path), &filename); \ | ||
|  |   size_t len; const char* script = read_file(path, &len);\ | ||
|  |   JsValueRef src;\ | ||
|  |   JsCreateExternalArrayBuffer((void*)script, len, nullptr, nullptr, &src);\ | ||
|  |   JsRun(src, cookie++, filename, JsParseScriptAttributeNone, &result); \ | ||
|  | } | ||
|  | 
 | ||
|  | // ... | ||
|  |   /* load library */ | ||
|  |   EVAL_FILE("shim.min.js") | ||
|  |   EVAL_FILE("xlsx.full.min.js") | ||
|  | ``` | ||
|  | 
 | ||
|  | ### Reading Files
 | ||
|  | 
 | ||
|  | `JsCreateExternalArrayBuffer` can generate an `ArrayBuffer` from a C byte array: | ||
|  | 
 | ||
|  | ```cpp | ||
|  | /* read file */ | ||
|  | size_t len; char *buf = read_file(argv[1], &len); | ||
|  | 
 | ||
|  | /* load data into array buffer */ | ||
|  | JsValueRef ab; | ||
|  | JsCreateExternalArrayBuffer((void*)buf, len, nullptr, nullptr, &ab); | ||
|  | ``` | ||
|  | 
 | ||
|  | After pushing the data, it is easiest to store properties on `globalThis`: | ||
|  | 
 | ||
|  | ```cpp | ||
|  | /* assign to the `buf` global variable */ | ||
|  | JsValueRef buf_str; JsCreateString("buf", strlen("buf"), &buf_str); | ||
|  | JsObjectSetProperty(global, buf_str, ab, true); | ||
|  | 
 | ||
|  | /* call globalThis.wb = XLSX.read(ab) */ | ||
|  | const char* script_str ="globalThis.wb = XLSX.read(buf);" | ||
|  | 
 | ||
|  | JsValueRef script; | ||
|  | JsCreateExternalArrayBuffer((void*)script_str, (size_t)strlen(script_str), nullptr, nullptr, &script); | ||
|  | JsRun(script, cookie++, fname, JsParseScriptAttributeNone, &result); | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Complete Example
 | ||
|  | 
 | ||
|  | The "Integration Example" covers a traditional integration in a C application, | ||
|  | while the "CLI Test" demonstrates other concepts using the `ch` CLI tool. | ||
|  | 
 | ||
|  | ### Integration Example
 | ||
|  | 
 | ||
|  | :::note | ||
|  | 
 | ||
|  | This demo was last tested on 2023 April 09 against ChakraCore commit `c3ead3f` | ||
|  | on a Intel Mac. `gcc -v` printed: | ||
|  | 
 | ||
|  | ``` | ||
|  | Apple clang version 14.0.0 (clang-1400.0.29.202) | ||
|  | Target: x86_64-apple-darwin21.6.0 | ||
|  | ``` | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | 0) Build ChakraCore: | ||
|  | 
 | ||
|  | ```bash | ||
|  | git clone https://github.com/Microsoft/ChakraCore | ||
|  | cd ChakraCore | ||
|  | git checkout c3ead3f | ||
|  | ./build.sh --static --icu=/usr/local/opt/icu4c/include --test-build -j=8 | ||
|  | cd .. | ||
|  | ``` | ||
|  | 
 | ||
|  | 1) Download the source file and Makefile: | ||
|  | 
 | ||
|  | - [`sheetjs.ch.cpp`](pathname:///chakra/sheetjs.ch.cpp) | ||
|  | - [`Makefile`](pathname:///chakra/Makefile) | ||
|  | 
 | ||
|  | ```bash | ||
|  | curl -LO https://docs.sheetjs.com/chakra/sheetjs.ch.c | ||
|  | curl -LO https://docs.sheetjs.com/chakra/Makefile | ||
|  | ``` | ||
|  | 
 | ||
|  | 2) Build the sample application: | ||
|  | 
 | ||
|  | ```bash | ||
|  | make | ||
|  | ``` | ||
|  | 
 | ||
|  | This program tries to parse the file specified by the first argument | ||
|  | 
 | ||
|  | 4) Download the standalone script, shim script, 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> | ||
|  | 
 | ||
|  | ```bash | ||
|  | curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js | ||
|  | curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js | ||
|  | curl -LO https://sheetjs.com/pres.numbers | ||
|  | ``` | ||
|  | 
 | ||
|  | 5) Run the test program: | ||
|  | 
 | ||
|  | ``` | ||
|  | ./sheetjs.ch pres.numbers | ||
|  | ``` | ||
|  | 
 | ||
|  | If successful, the program will print the contents of the first sheet as CSV. | ||
|  | 
 | ||
|  | 
 | ||
|  | ### CLI Test
 | ||
|  | 
 | ||
|  | :::note | ||
|  | 
 | ||
|  | This demo was last tested on 2023 April 09 against `ch` `1.13.0.0-beta`. | ||
|  | The command line tool was built against commit `c3ead3f`. | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | Due to limitations of the `ch` 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" | ||
|  | 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 | ||
|  | ready, it will read the bundled test data and print the contents as CSV. | ||
|  | 
 | ||
|  | 5) Run the script using the ChakraCore standalone binary: | ||
|  | 
 | ||
|  | ``` | ||
|  | ./ch xlsx.chakra.js | ||
|  | ``` |