Skip to content

Commit

Permalink
XLS Unicode Property Lists [ci skip]
Browse files Browse the repository at this point in the history
  • Loading branch information
SheetJSDev committed Oct 3, 2021
1 parent a376a6c commit b98a402
Show file tree
Hide file tree
Showing 75 changed files with 1,529 additions and 312 deletions.
34 changes: 20 additions & 14 deletions bits/38_xlstypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ function parse_VtStringBase(blob, stringType, pad) {
function parse_VtString(blob, t/*:number*/, pad/*:?boolean*/) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); }
function parse_VtUnalignedString(blob, t/*:number*/) { if(!t) throw new Error("VtUnalignedString must have positive length"); return parse_VtStringBase(blob, t, 0); }

/* [MS-OSHARED] 2.3.3.1.7 VtVecLpwstrValue */
function parse_VtVecLpwstrValue(blob)/*:Array<string>*/ {
var length = blob.read_shift(4);
var ret/*:Array<string>*/ = [];
for(var i = 0; i != length; ++i) {
var start = blob.l;
ret[i] = blob.read_shift(0, 'lpwstr').replace(chr0,'');
if((blob.l - start) & 0x02) blob.l += 2;
}
return ret;
}

/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
function parse_VtVecUnalignedLpstrValue(blob)/*:Array<string>*/ {
var length = blob.read_shift(4);
Expand All @@ -49,14 +61,12 @@ function parse_VtVecUnalignedLpstrValue(blob)/*:Array<string>*/ {
return ret;
}

/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
function parse_VtVecUnalignedLpstr(blob)/*:Array<string>*/ {
return parse_VtVecUnalignedLpstrValue(blob);
}

/* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */
function parse_VtHeadingPair(blob) {
var start = blob.l;
var headingString = parse_TypedPropertyValue(blob, VT_USTR);
if(blob[blob.l] == 0x00 && blob[blob.l+1] == 0x00 && ((blob.l - start) & 0x02)) blob.l += 2;
var headerParts = parse_TypedPropertyValue(blob, VT_I4);
return [headingString, headerParts];
}
Expand All @@ -65,16 +75,10 @@ function parse_VtHeadingPair(blob) {
function parse_VtVecHeadingPairValue(blob) {
var cElements = blob.read_shift(4);
var out = [];
for(var i = 0; i != cElements / 2; ++i) out.push(parse_VtHeadingPair(blob));
for(var i = 0; i < cElements / 2; ++i) out.push(parse_VtHeadingPair(blob));
return out;
}

/* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */
function parse_VtVecHeadingPair(blob) {
// NOTE: When invoked, wType & padding were already consumed
return parse_VtVecHeadingPairValue(blob);
}

/* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */
function parse_dictionary(blob,CodePage) {
var cnt = blob.read_shift(4);
Expand Down Expand Up @@ -113,7 +117,7 @@ function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ {
var t = blob.read_shift(2), ret, opts = _opts||{};
blob.l += 2;
if(type !== VT_VARIANT)
if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t);
if(t !== type && VT_CUSTOM.indexOf(type)===-1 && !((type & 0xFFFE) == 0x101E && (t & 0xFFFE) == 0x101E)) throw new Error('Expected type ' + type + ' saw ' + t);
switch(type === VT_VARIANT ? t : type) {
case 0x02 /*VT_I2*/: ret = blob.read_shift(2, 'i'); if(!opts.raw) blob.l += 2; return ret;
case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
Expand All @@ -126,8 +130,10 @@ function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ {
case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
case 0x50 /*VT_STRING*/: return parse_VtString(blob, t, !opts.raw).replace(chr0,'');
case 0x51 /*VT_USTR*/: return parse_VtUnalignedString(blob, t/*, 4*/).replace(chr0,'');
case 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPair(blob);
case 0x101E /*VT_LPSTR*/: return parse_VtVecUnalignedLpstr(blob);
case 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPairValue(blob);
case 0x101E /*VT_VECTOR|VT_LPSTR*/:
case 0x101F /*VT_VECTOR|VT_LPWSTR*/:
return t == 0x101F ? parse_VtVecLpwstrValue(blob) : parse_VtVecUnalignedLpstrValue(blob);
default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + t);
}
}
Expand Down
2 changes: 1 addition & 1 deletion demos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ can be installed with Bash on Windows or with `cygwin`.

**Frameworks and APIs**
- [`angularjs`](angular/)
- [`angular 2 / 4 / 5 / 6 and ionic`](angular2/)
- [`angular and ionic`](angular2/)
- [`knockout`](knockout/)
- [`meteor`](meteor/)
- [`react and react-native`](react/)
Expand Down
1 change: 1 addition & 0 deletions demos/altjs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ rhino
shim.min.js
xlsx.*.js
payload.js
goja
1 change: 0 additions & 1 deletion demos/altjs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ swift: base ## swift demo

.PHONY: goja
goja: base ## goja demo
if [ ! -e xlsx.core.min.js ]; then cp ../../dist/xlsx.core.min.js .; fi
go build goja.go
for ext in xlsx xlsb biff8.xls xml.xls; do ./goja sheetjs.$$ext; done

Expand Down
12 changes: 6 additions & 6 deletions demos/altjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Binary strings can be passed back and forth using `String.Encoding.isoLatin1`:
/* 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)!);
context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol));
src = "var wb = XLSX.read(payload, {type:'binary'});";
context.evaluateScript(src);

Expand Down Expand Up @@ -108,14 +108,15 @@ 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:
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, {type:'buffer'});");
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'})");
Expand Down Expand Up @@ -157,9 +158,8 @@ wh.write(out, 0, ab.byteLength); wh.close();

## Goja

Goja is a pure Go implementation of ECMAScript 5. As of this writing, there are
some issues with processing Unicode data, but the `xlsx.core.min.js` script can
be processed. `[]byte` should be transformed to a binary string in the engine:
Goja is a pure Go implementation of ECMAScript 5. `[]byte` should be converted
to a binary string in the engine:

```go
/* read file */
Expand Down
12 changes: 6 additions & 6 deletions demos/altjs/SheetJSCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ enum SJSError: Error {

class SJSWorksheet {
var context: JSContext!;
var wb: JSValue!; var ws: JSValue!;
var wb: JSValue; var ws: JSValue;
var idx: Int32;

func toCSV() throws -> String {
Expand All @@ -26,7 +26,7 @@ class SJSWorksheet {

class SJSWorkbook {
var context: JSContext!;
var wb: JSValue!; var SheetNames: JSValue!; var Sheets: JSValue!;
var wb: JSValue; var SheetNames: JSValue; var Sheets: JSValue;

func getSheetAtIndex(idx: Int32) throws -> SJSWorksheet {
let SheetName: String = SheetNames.atIndex(Int(idx)).toString();
Expand All @@ -37,8 +37,8 @@ class SJSWorkbook {
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");
let writeopts: JSValue = context.objectForKeyedSubscript("writeopts");
let writefunc: JSValue = XLSX.objectForKeyedSubscript("write");
return writefunc.call(withArguments: [wb, writeopts]).toString();
}

Expand All @@ -58,7 +58,7 @@ class SheetJSCore {
var context: JSContext!
do {
context = JSContext();
context.exceptionHandler = { ctx, X in if let e = X { print(e.toString()); }; };
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");
Expand All @@ -79,7 +79,7 @@ class SheetJSCore {
}

func readBStr(data: String) throws -> SJSWorkbook {
context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)!);
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; }
Expand Down
2 changes: 1 addition & 1 deletion demos/altjs/duktape.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
DUKTAPE_VER=2.2.0
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
Expand Down
2 changes: 1 addition & 1 deletion demos/altjs/goja.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func main() {

/* load library */
safe_run_file(vm, "shim.min.js")
safe_run_file(vm, "xlsx.core.min.js")
safe_run_file(vm, "xlsx.full.min.js")

/* get version string */
v := eval_string(vm, "XLSX.version")
Expand Down
10 changes: 6 additions & 4 deletions demos/angular/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ into web pages with script tags:
Strictly speaking, there should be no need for an Angular demo! You can proceed
as you would with any other browser-friendly library.

This demo uses AngularJS 1.5.0.


## Array of Objects

Expand Down Expand Up @@ -87,13 +89,13 @@ function SheetJSImportDirective() {

reader.onload = function (e) {
/* read workbook */
var bstr = e.target.result;
var workbook = XLSX.read(bstr, {type:'binary'});
var ab = e.target.result;
var workbook = XLSX.read(ab);

/* DO SOMETHING WITH workbook HERE */
};

reader.readAsBinaryString(changeEvent.target.files[0]);
reader.readAsArrayBuffer(changeEvent.target.files[0]);
});
}
};
Expand Down Expand Up @@ -133,7 +135,7 @@ directive for a HTML File Input control. It also includes a sample service for
export which adds an item to the export menu.

The demo `SheetJSImportDirective` follows the prescription from the README for
File input controls using `readAsBinaryString`, converting to a suitable
File input controls using `readAsArrayBuffer`, converting to a suitable
representation and updating the scope.

`SheetJSExportService` exposes export functions for `XLSB` and `XLSX`. Other
Expand Down
8 changes: 4 additions & 4 deletions demos/angular/SheetJS-angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ function SheetJSImportDirective() {

reader.onload = function(e) {
/* read workbook */
var bstr = e.target.result;
var wb = XLSX.read(bstr, {type:'binary'});
var ab = e.target.result;
var wb = XLSX.read(ab);

/* grab first sheet */
var wsname = wb.SheetNames[0];
Expand All @@ -78,7 +78,7 @@ function SheetJSImportDirective() {
data[r-1] = {};
for(i = 0; i < aoa[r].length; ++i) {
if(aoa[r][i] == null) continue;
data[r-1][aoa[0][i]] = aoa[r][i]
data[r-1][aoa[0][i]] = aoa[r][i];
}
}

Expand All @@ -89,7 +89,7 @@ function SheetJSImportDirective() {
});
};

reader.readAsBinaryString(changeEvent.target.files[0]);
reader.readAsArrayBuffer(changeEvent.target.files[0]);
});
}
};
Expand Down
4 changes: 2 additions & 2 deletions demos/angular/grid.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-animate.js"></script>

<!-- ui-grid -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.0/ui-grid.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.0/ui-grid.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.11.0/ui-grid.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.11.0/ui-grid.css"/>

<!-- SheetJS js-xlsx library -->
<script src="shim.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion demos/angular/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<head>
<title>SheetJS + AngularJS</title>
<!-- Angular -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>

<!-- SheetJS js-xlsx library -->
<script src="shim.js"></script>
Expand Down
6 changes: 6 additions & 0 deletions demos/angular2/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended"
]
}
1 change: 1 addition & 0 deletions demos/angular2/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.*-ng* linguist-generated=true binary
3 changes: 3 additions & 0 deletions demos/angular2/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ dist
hooks
SheetJSIonic
SheetJSNS
angular.json
tsconfig.app.json
src/polyfills.ts
26 changes: 17 additions & 9 deletions demos/angular2/Makefile
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
.PHONY: all
all: angular5

.PHONY: angular2 angular4 angular5
angular2 angular4 angular5:
cp package.json-$@ package.json
.PHONY: ng2 ng4 ng5 ng6 ng7 ng8 ng9 ng10 ng11 ng12
ng2 ng4 ng5 ng6 ng7 ng8 ng9 ng10 ng11 ng12:
rm -f angular.json tsconfig.app.json src/polyfills.ts
cp versions/package.json-$@ package.json
if [ -e versions/angular.json-$@ ]; then cp versions/angular.json-$@ angular.json; fi
if [ -e versions/tsconfig.app.json-$@ ]; then cp versions/tsconfig.app.json-$@ tsconfig.app.json; fi
if [ -e versions/polyfills.ts-$@ ]; then cp versions/polyfills.ts-$@ src/polyfills.ts; fi
rm -rf node_modules
npm install
if [ ! -e node_modules ]; then mkdir node_modules; fi
if [ ! -e node_modules/xlsx ]; then cd node_modules; ln -s ../../../ xlsx; cd -; fi
npm run build

.PHONY: all
all:
for i in 2 4 5 6 7 8 9 10 11 12; do make ng$$i; done

.PHONY: ionic
ionic:
bash ./ionic.sh

.PHONY: ios android browser
ios android browser: ionic
ios browser: ionic
cd SheetJSIonic; ionic cordova emulate $@ </dev/null; cd -
android: ionic
cd SheetJSIonic; ionic cordova prepare $@ </dev/null; ionic cordova emulate $@ </dev/null; cd -


.PHONY: nativescript
nativescript:
bash ./nscript.sh

.PHONY: ns-ios ns-android
ns-ios: nativescript
cd SheetJSNS; tns run ios; cd -
cd SheetJSNS; ns run ios; cd -
ns-android: nativescript
cd SheetJSNS; tns run android; cd -
cd SheetJSNS; ns run android; cd -

Loading

0 comments on commit b98a402

Please sign in to comment.