diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index ce7ed79..0000000
--- a/.eslintignore
+++ /dev/null
@@ -1 +0,0 @@
-xlsx.js
diff --git a/.eslintrc b/.eslintrc
index f020fa2..d309370 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -2,23 +2,20 @@
"env": { "shared-node-browser":true },
"globals": {},
"parserOptions": {
- "ecmaVersion": 3
+ "ecmaVersion": 3,
},
"plugins": [ "html", "json" ],
- "extends": "eslint:recommended",
+ "!extends": "eslint:recommended",
"rules": {
- "comma-style": [ 2, "last" ],
- "comma-dangle": [ 2, "never" ],
- "curly": 0,
- "no-bitwise": 0,
- "no-console": 0,
- "no-control-regex": 0,
- "no-empty": 0,
- "no-trailing-spaces": 2,
"no-use-before-define": [ 1, {
"functions":false, "classes":true, "variables":false
}],
- "no-useless-escape": 0,
- "semi": [ 2, "always" ]
+ "no-console": 0,
+ "no-bitwise": 0,
+ "curly": 0,
+ "comma-style": [ 2, "last" ],
+ "no-trailing-spaces": 2,
+ "semi": [ 2, "always" ],
+ "comma-dangle": [ 2, "never" ]
}
}
diff --git a/.flowconfig b/.flowconfig
index 079d343..5f936d4 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -2,21 +2,21 @@
.*/node_modules/.*
.*/dist/.*
.*/tmp/.*
+.*/test.js
.*/bits/.*
.*/ctest/.*
.*/misc/.*
.*/perf/.*
.*/_book/.*
-.*/packages/.*
.*/demo/browser.js
.*/shim.js
.*/xlsx.js
-.*/xlsx.mini.js
-.*/xlsx.mini.flow.js
.*/xlsxworker.js
+.*/xlsxworker1.js
+.*/xlsxworker2.js
.*/jszip.js
.*/tests/.*
.*/demos/.*
@@ -24,10 +24,11 @@
#.*/xlsx.flow.js
[include]
xlsxworker.flow.js
+xlsxworker1.flow.js
+xlsxworker2.flow.js
xlsx.flow.js
.*/bin/.*.njs
.*/demo/browser.flow.js
-test.js
[libs]
bits/09_types.js
diff --git a/.fossaignore b/.fossaignore
deleted file mode 100644
index fc7a5d1..0000000
--- a/.fossaignore
+++ /dev/null
@@ -1,16 +0,0 @@
-bits/
-demos/
-dist/
-docbits/
-misc/
-node_modules/
-types/
-tests/
-test_files
-*.md
-
-*.json
-*.log
-*.sh
-.DS_Store
-.Trashes
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index e41a26c..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,14 +0,0 @@
-*.html linguist-documentation
-
-*.md text eol=lf
-bits/*.js text eol=lf
-test.js text eol=lf
-xlsx*.js text eol=lf
-*.flow.js text eol=lf
-
-docbits/* linguist-documentation
-dist/* linguist-generated=true binary
-xlsx.js linguist-generated=true binary
-xlsxworker.js linguist-generated=true binary
-tests/core.js linguist-generated=true binary
-tests/fixtures.js linguist-generated=true binary
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 092bd24..0000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-github: SheetJSDev
-custom: https://sheetjs.com
-open_collective: s5s
diff --git a/.github/workflows/node-4+.yml b/.github/workflows/node-4+.yml
deleted file mode 100644
index 38d4da8..0000000
--- a/.github/workflows/node-4+.yml
+++ /dev/null
@@ -1,89 +0,0 @@
-name: 'Tests: node.js'
-
-on: [pull_request, push]
-
-jobs:
- matrix:
- runs-on: ubuntu-latest
- outputs:
- latest: ${{ steps.set-matrix.outputs.requireds }}
- steps:
- - uses: ljharb/actions/node/matrix@main
- id: set-matrix
- with:
- versionsAsRoot: true
- type: 'majors'
- preset: '>=4'
-
- latest:
- needs: [matrix]
- name: 'latest majors'
- runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix:
- node-version: ${{ fromJson(needs.matrix.outputs.latest) }}
- include:
- - node-version: '14.'
- env:
- TZ: America/New_York
- - node-version: '13.'
- env:
- TZ: Europe/London
- - node-version: '12.'
- env:
- TZ: Asia/Seoul
- - node-version: '11.'
- env:
- TZ: America/Los_Angeles
- FMTS: misc
- - node-version: '10.'
- env:
- TZ: Europe/Berlin
- FMTS: misc
- - node-version: '9.'
- env:
- TZ: Asia/Kolkata
- FMTS: misc
- - node-version: '8.'
- env:
- TZ: Asia/Shanghai
- FMTS: misc
- - node-version: '7.'
- env:
- TZ: America/Cancun
- FMTS: misc
- - node-version: '6.'
- env:
- TZ: Asia/Seoul
- FMTS: misc
- - node-version: '5.'
- env:
- TZ: America/Anchorage
- FMTS: misc
- - node-version: '4.'
- env:
- TZ: America/Barbados
- FMTS: misc
- - node-version: '4.4.7' # see GH issue #1150
- env:
- TZ: Asia/Tokyo
- FMTS: misc
-
- steps:
- - uses: actions/checkout@v2
- - uses: ljharb/actions/node/install@main
- name: 'nvm install ${{ matrix.node-version }} && npm install'
- with:
- node-version: ${{ matrix.node-version }}
- - run: make init
- - run: 'cd test_files; make all; cd -'
- - run: npm run tests-only
-
- node:
- name: 'node 4+'
- needs: [latest]
- runs-on: ubuntu-latest
- steps:
- - run: 'echo tests completed'
diff --git a/.github/workflows/node-iojs.yml b/.github/workflows/node-iojs.yml
deleted file mode 100644
index f85c166..0000000
--- a/.github/workflows/node-iojs.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-name: 'Tests: node.js (io.js)'
-
-on: [pull_request, push]
-
-jobs:
- matrix:
- runs-on: ubuntu-latest
- outputs:
- latest: ${{ steps.set-matrix.outputs.requireds }}
- steps:
- - uses: ljharb/actions/node/matrix@main
- id: set-matrix
- with:
- type: 'majors'
- preset: 'iojs'
-
- latest:
- needs: [matrix]
- name: 'latest majors'
- runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix: ${{ fromJson(needs.matrix.outputs.latest) }}
-
- steps:
- - uses: actions/checkout@v2
- - uses: ljharb/actions/node/install@main
- name: 'nvm install ${{ matrix.node-version }} && npm install'
- with:
- node-version: ${{ matrix.node-version }}
- skip-ls-check: true
- - run: make init
- - run: 'cd test_files; make all; cd -'
- - run: npm run tests-only
-
- node:
- name: 'io.js'
- needs: [latest]
- runs-on: ubuntu-latest
- steps:
- - run: 'echo tests completed'
diff --git a/.github/workflows/node-pretest.yml b/.github/workflows/node-pretest.yml
deleted file mode 100644
index cc9ef8a..0000000
--- a/.github/workflows/node-pretest.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: 'Tests: pretest/posttest'
-
-on: [pull_request, push]
-
-jobs:
- pretest:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
- - uses: ljharb/actions/node/install@main
- name: 'nvm install lts/* && npm install'
- with:
- node-version: 'lts/*'
- - run: make init
- - run: 'cd test_files; make all; cd -'
- - run: npm run pretest
-
- # posttest:
- # runs-on: ubuntu-latest
-
- # steps:
- # - uses: actions/checkout@v2
- # - uses: ljharb/actions/node/install@main
- # name: 'nvm install lts/* && npm install'
- # with:
- # node-version: 'lts/*'
- # - run: make init
- # - run: 'cd test_files; make all; cd -'
- # - run: npm run posttest
diff --git a/.github/workflows/node-zero.yml b/.github/workflows/node-zero.yml
deleted file mode 100644
index 67e7a26..0000000
--- a/.github/workflows/node-zero.yml
+++ /dev/null
@@ -1,82 +0,0 @@
-name: 'Tests: node.js (0.x)'
-
-on: [pull_request, push]
-
-jobs:
- matrix:
- runs-on: ubuntu-latest
- outputs:
- stable: ${{ steps.set-matrix.outputs.requireds }}
- unstable: ${{ steps.set-matrix.outputs.optionals }}
- steps:
- - uses: ljharb/actions/node/matrix@main
- id: set-matrix
- with:
- versionsAsRoot: true
- preset: '0.x'
-
- stable:
- needs: [matrix]
- name: 'stable minors'
- runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix:
- node-version: ${{ fromJson(needs.matrix.outputs.stable) }}
- include:
- - node-version: '0.12.'
- env:
- TZ: America/Cayman
- FMTS: misc
- - node-version: '0.10.'
- env:
- TZ: Pacific/Honolulu
- FMTS: misc
- - node-version: '0.8.'
- env:
- TZ: America/Mexico_City
- FMTS: misc
-
- steps:
- - uses: actions/checkout@v2
- - uses: ljharb/actions/node/install@main
- name: 'nvm install ${{ matrix.node-version }} && npm install'
- with:
- node-version: ${{ matrix.node-version }}
- cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }}
- skip-ls-check: true
- - run: make init
- - run: 'cd test_files; make all; cd -'
- - run: npm run tests-only
-
- unstable:
- needs: [matrix, stable]
- name: 'unstable minors'
- continue-on-error: true
- if: ${{ !github.head_ref || !startsWith(github.head_ref, 'renovate') }}
- runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix:
- node-version: ${{ fromJson(needs.matrix.outputs.unstable) }}
-
- steps:
- - uses: actions/checkout@v2
- - uses: ljharb/actions/node/install@main
- name: 'nvm install ${{ matrix.node-version }} && npm install'
- with:
- node-version: ${{ matrix.node-version }}
- cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }}
- skip-ls-check: true
- - run: make init
- - run: 'cd test_files; make all; cd -'
- - run: npm run tests-only
-
- node:
- name: 'node 0.x'
- needs: [stable, unstable]
- runs-on: ubuntu-latest
- steps:
- - run: 'echo tests completed'
diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml
deleted file mode 100644
index 027aed0..0000000
--- a/.github/workflows/rebase.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-name: Automatic Rebase
-
-on: [pull_request_target]
-
-jobs:
- _:
- name: "Automatic Rebase"
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
- - uses: ljharb/rebase@master
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/require-allow-edits.yml b/.github/workflows/require-allow-edits.yml
deleted file mode 100644
index 549d7b4..0000000
--- a/.github/workflows/require-allow-edits.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-name: Require “Allow Edits”
-
-on: [pull_request_target]
-
-jobs:
- _:
- name: "Require “Allow Edits”"
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: ljharb/require-allow-edits@main
diff --git a/.gitignore b/.gitignore
index 172339d..df27b02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
node_modules
-package-lock.json
*.tgz
_book/
misc/coverage.html
@@ -10,24 +9,18 @@ tmp
*.[cC][sS][vV]
*.[dD][iIbB][fF]
*.[pP][rR][nN]
-*.[pP][mM][dD]*
-*.[pP][dD][fF]
*.[sS][lL][kK]
*.socialcalc
-*.[xX][lL][sSwWcCaAtTmM]
-*.[xX][lL][sSaAtT][xXmMbB]
+*.[xX][lL][sSwWcC]
+*.[xX][lL][sS][xXmMbB]
*.[oO][dD][sS]
*.[fF][oO][dD][sS]
*.[xX][mM][lL]
*.[uU][oO][sS]
*.[wW][kKqQbB][S1234567890]
*.[qQ][pP][wW]
-*.[bB][iI][fF][fF][23458]
-*.[rR][tT][fF]
-*.[eE][tT][hH]
*.123
*.htm
*.html
*.sheetjs
*.exe
-*.img
diff --git a/.npmignore b/.npmignore
index 2c25acc..9b5abcd 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,6 +1,4 @@
test_files/
-packages/
-.github/
tests/files/
demos/
index.html
@@ -14,32 +12,22 @@ tmp
*.[cC][sS][vV]
*.[dD][iIbB][fF]
*.[pP][rR][nN]
-*.[pP][mM][dD]*
-*.[pP][dD][fF]
*.[sS][lL][kK]
*.socialcalc
-*.[xX][lL][sSwWcCaAtTmM]
-*.[xX][lL][sSaAtT][xXmMbB]
+*.[xX][lL][sSwWcC]
+*.[xX][lL][sS][xXmMbB]
*.[oO][dD][sS]
*.[fF][oO][dD][sS]
*.[xX][mM][lL]
*.[uU][oO][sS]
*.[wW][kKqQbB][S1234567890]
*.[qQ][pP][wW]
-*.[bB][iI][fF][fF][23458]
-*.[rR][tT][fF]
-*.[eE][tT][hH]
*.123
*.htm
*.html
*.sheetjs
*.exe
-*.img
.gitignore
-.gitattributes
-.fossaignore
-.spelling
-.eslintignore
.eslintrc
.jshintrc
CONTRIBUTING.md
diff --git a/.spelling b/.spelling
deleted file mode 100644
index 6379f6e..0000000
--- a/.spelling
+++ /dev/null
@@ -1,163 +0,0 @@
-# xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com
-SheetJS
-js-xlsx
-xls
-xlsb
-xlsx
-
-# Excel-related terms
-A1-style
-AutoFilter
-ECMA-376
-FoxPro
-Multiplan
-OData
-OpenDocument
-OpenFormula
-PivotTable
-Quattro
-SpreadsheetML
-Unhide
-VBA
-Visicalc
-chartsheet
-chartsheets
-dialogsheet
-dialogsheets
-dBASE
-macrosheet
-macrosheets
-tooltip
-tooltips
-
-# Third-party
-Browserify
-CDNjs
-CommonJS
-Ethercalc
-ExtendScript
-IndexedDB
-JavaScriptCore
-LocalStorage
-NPM
-Nuxt.js
-Redis
-RequireJS
-Rollup
-SessionStorage
-SQLite
-SystemJS
-VueJS
-WebSQL
-iOS
-nodejs
-node.js
-npm
-unpkg
-webpack
-weex
-
-# Other terms
-ActiveX
-APIs
-ArrayBuffer
-Base64
-Booleans
-FileReader
-JS
-NoSQL
-README
-UTF-16
-VBScript
-XHR
-XMLHttpRequest
-bundler
-bundlers
-cleanroom
-codepage
-config
-customizable
-datagrid
-deduplication
-destructuring
-embeddable
-encodings
-filesystem
-globals
-javascript
-metadata
-natively
-pre-built
-pre-generated
-prepend
-prepended
-repo
-runtime
-serverless
-submodule
-transpiled
-utils
-commonjs
-async
-uncheck
-
- - demos/altjs/README.md
-ChakraCore
-Duktape
-Goja
-Nashorn
-QuickJS
-
- - demos/angular/README.md
-AngularJS
-
- - demos/angular2/README.md
-NativeScript
-angular-cli
-
- - demos/array/README.md
-WebGL
-WebAssembly
-dataset
-TensorFlow
-
- - demos/database/README.md
-Knex
-LowDB
-MariaDB
-MongoDB
-MySQL
-PostgreSQL
-schemaless
-schemas
-storages
-
- - demos/extendscript/README.md
-Photoshop
-minifier
-
- - demos/function/README.md
-microservice
-
- - demos/headless/README.md
-PhantomJS
-SlimerJS
-wkhtmltopdf
-
- - demos/nwjs/README.md
-NW.js
-
- - demos/react/README.md
-Next.js
-Preact
-
- - demos/server/README.md
-hapi
-
- - demos/showcase/README.md
-vscode-data-preview
-
- - demos/xhr/README.md
-axios
-superagent
-
diff --git a/.travis.yml b/.travis.yml
index 6dd4d6a..749b489 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,56 +1,37 @@
language: node_js
-dist: xenial
node_js:
- - "14"
- - "13"
- - "12"
- - "11"
- - "10"
- - "9"
- "8"
+ - "7"
+ - "6"
+# note: travis has been acting up on old versions of node
+# - "5"
+# - "4"
+# - "0.12"
+# - "0.10"
+# - "0.9"
+# - "0.8"
matrix:
include:
- - node_js: "14"
- env: TZ="America/New_York"
- - node_js: "13"
- env: TZ="Europe/London"
- - node_js: "12"
- env: TZ="Asia/Seoul"
- - node_js: "11"
- env: TZ="America/Los_Angeles" FMTS=misc
- - node_js: "10"
- env: TZ="Europe/Berlin" FMTS=misc
- - node_js: "9"
- env: TZ="Asia/Kolkata" FMTS=misc
- - node_js: "8"
- env: TZ="Asia/Shanghai" FMTS=misc
- - node_js: "7"
- env: TZ="America/Cancun" FMTS=misc
- node_js: "6"
- env: TZ="Asia/Seoul" FMTS=misc
- - node_js: "5"
- env: TZ="America/Anchorage" FMTS=misc
- - node_js: "4"
- env: TZ="America/Barbados" FMTS=misc
- # see GH issue #1150
- - node_js: "4.4.7"
- env: TZ="Asia/Tokyo" FMTS=misc
- - node_js: "0.12"
- env: TZ="America/Cayman" FMTS=misc
- - node_js: "0.10"
- env: TZ="Pacific/Honolulu" FMTS=misc
- - node_js: "0.8"
- env: TZ="America/Mexico_City" FMTS=misc
-
+ env: TZ="America/New_York"
+ - node_js: "8"
+ env: TZ="America/Los_Angeles"
+ - node_js: "6"
+ env: TZ="Europe/London"
+ - node_js: "8"
+ env: TZ="Europe/Berlin"
+ - node_js: "6"
+ env: TZ="Asia/Kolkata"
+ - node_js: "7"
+ env: TZ="Asia/Shanghai"
+ - node_js: "8"
+ env: TZ="Asia/Seoul"
before_install:
- - "npm config set strict-ssl false"
- - "./misc/node_version.sh"
+ - "npm install -g npm@4.3.0"
- "npm install -g mocha@2.x voc"
- "npm install blanket"
- - "npm install word"
+ - "npm install xlsjs"
- "npm install coveralls mocha-lcov-reporter"
-# note: jsdom 11.x expects node >= 6 but is missing engines.node
- - "npm install jsdom@11.x"
before_script:
- "make init"
- "cd test_files; make all; cd -"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b30d365..1be9d7a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,158 +4,6 @@ This log is intended to keep track of backwards-incompatible changes, including
but not limited to API changes and file location changes. Minor behavioral
changes may not be included if they are not expected to break existing code.
-## v0.17.1
-
-* `XLSB` writer uses short cell form when viable
-
-## v0.16.2
-
-* Disabled `PRN` parsing by default (better support for CSV without delimeters)
-
-## v0.16.1
-
-* skip empty custom property tags if data is absent (fixes DocSecurity issue)
-* HTML output add raw value, type, number format
-* DOM parse look for `v` / `t` / `z` attributes when determining value
-* double quotes in properties escaped using `_x0022_`
-* changed AMD structure for NetSuite and other RequireJS implementations
-- `encode_cell` and `decode_cell` do not rely on `encode_col` / `decode_col`
-
-## v0.16.0
-
-* Date handling changed
-* XLML certain tag tests are now case insensitive
-* Fixed potentially vulnerable regular expressions
-
-## v0.15.6
-
-* CFB prevent infinite loop
-* ODS empty cells marked as stub (type "z")
-* `cellStyles` option implies `sheetStubs`
-
-## v0.15.5
-
-* `sheets` parse option to specify which sheets to parse
-
-## v0.15.4
-
-* AOA utilities properly preserve number formats
-* Number formats captured in stub cells
-
-## v0.15.3
-
-* Properties and Custom Properties properly XML-encoded
-
-## v0.15.2
-
-- `sheet_get_cell` utility function
-- `sheet_to_json` explicitly support `null` as alias for default behavior
-- `encode_col` throw on negative column index
-- HTML properly handle whitespace around tags in a run
-- HTML use `id` option on write
-- Files starting with `0x09` followed by a display character are now TSV files
-- XLS parse references col/row indices mod by the correct number for BIFF ver
-- XLSX comments moved to avoid overlapping cell
-- XLSB outline level
-- AutoFilter update `_FilterDatabase` defined name on write
-- XLML skip CDATA blocks
-
-## v0.15.1 (2019-08-14)
-
-* XLSX ignore XML artifacts
-* HTML capture and persist merges
-
-## v0.15.0
-
-* `dist/xlsx.mini.min.js` mini build with XLSX read/write and some utilities
-* Removed legacy conversion utility functions
-
-## v0.14.5
-
-* XLS PtgNameX lookup
-* XLS always create stub cells for blank cells with comments
-
-
-## v0.14.4
-
-* Better treatment of `skipHidden` in CSV output
-* Ignore CLSID in XLS
-* SYLK 7-bit character encoding
-* SYLK and DBF codepage support
-
-## v0.14.3
-
-* Proper shifting of addresses in Shared Formulae
-
-## v0.14.2
-
-* Proper XML encoding of comments
-
-## v0.14.1
-
-* raw cell objects can be passed to `sheet_add_aoa`
-* `_FilterDatabase` fix for AutoFilter-related crashes
-* `stream.to_json` doesn't end up accidentally scanning to max row
-
-## 0.14.0 (2018-09-06)
-
-* `sheet_to_json` default flipped to `raw: true`
-
-## 0.13.5 (2018-08-25)
-
-* HTML output generates `
` instead of encoded newline character
-
-## 0.13.2 (2018-07-08)
-
-* Buffer.from shim replaced, will not be defined in node `<=0.12`
-
-## 0.13.0 (2018-06-01)
-
-* Library reshaped to support AMD out of the box
-
-## 0.12.11 (2018-04-27)
-
-* XLS/XLSX/XLSB range truncation (errors in `WTF` mode)
-
-## 0.12.4 (2018-03-04)
-
-* `JSZip` renamed to `JSZipSync`
-
-## 0.12.0 (2018-02-08)
-
-* Extendscript target script in NPM package
-
-## 0.11.19 (2018-02-03)
-
-* Error on empty workbook
-
-## 0.11.16 (2017-12-30)
-
-* XLS ANSI/CP separation
-* 'array' write type and ArrayBuffer processing
-
-## 0.11.6 (2017-10-16)
-
-* Semicolon-delimited files are detected
-
-## 0.11.5 (2017-09-30)
-
-* Bower main script shifted to full version
-* 'binary' / 'string' encoding
-
-## 0.11.3 (2017-08-19)
-
-* XLS cell ixfe/XF removed
-
-## 0.11.0 (2017-07-31)
-
-* Strip `require` statements from minified version
-* minifier mangler enabled
-
-## 0.10.9 (2017-07-28)
-
-* XLML/HTML resolution logic looks further into the data stream to decide type
-* Errors thrown on suspected RTF files
## 0.10.5 (2017-06-09)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b298def..e9642de 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -28,13 +28,6 @@ shared or included in a test suite (although I will ask :)
If sending email to a gmail account is problematic, the email
inbox is self-hosted.
-# Opening Pull Requests
-
-Before opening a pull request, [squash all commits into
-one](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History). If the pull
-request addresses documentation or demos, add `[ci skip]` in the body or title
-of your commit message to skip Travis checks.
-
# Pre-Contribution Checklist
Before thinking about contributing, make sure that:
@@ -67,4 +60,4 @@ Keep these in mind as you work:
Before contributions are merged, you will receive an email (at the address
associated with the git commit) and will be asked to confirm the aforementioned
-items. Ensure that the email addresses associated with the commits are valid.
+items. Ensure that the email addresses associated with the commits is valid.
diff --git a/LICENSE b/LICENSE
index 4bdda80..bf49d68 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright (C) 2012-present SheetJS LLC
+ Copyright (C) 2012-present SheetJS LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/Makefile b/Makefile
index 62c5df5..f643214 100644
--- a/Makefile
+++ b/Makefile
@@ -7,30 +7,20 @@ AUXTARGETS=
CMDS=bin/xlsx.njs
HTMLLINT=index.html
-MINITGT=xlsx.mini.js
-MINIFLOW=xlsx.mini.flow.js
-MINIDEPS=$(shell cat mini.lst)
-
-NODESMTGT=xlsx.esm.mjs
-NODESMDEPS=$(shell cat misc/esm.lst)
-ESMJSTGT=xlsx.mjs
-ESMJSDEPS=$(shell cat misc/mjs.lst)
-
-
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
DEPS=$(sort $(wildcard bits/*.js))
TARGET=$(LIB).js
FLOWTARGET=$(LIB).flow.js
FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS))
-AUXSCPTS=xlsxworker.js
-FLOWTGTS=$(TARGET) $(AUXTARGETS) $(AUXSCPTS) $(MINITGT)
-UGLIFYOPTS=--support-ie8 -m
-# CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar
+AUXSCPTS=xlsxworker1.js xlsxworker2.js xlsxworker.js
+FLOWTGTS=$(TARGET) $(AUXTARGETS) $(AUXSCPTS)
+UGLIFYOPTS=--support-ie8
+CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar
## Main Targets
.PHONY: all
-all: $(TARGET) $(AUXTARGETS) $(AUXSCPTS) $(MINITGT) $(NODESMTGT) $(ESMJSTGT) ## Build library and auxiliary scripts
+all: $(TARGET) $(AUXTARGETS) $(AUXSCPTS) ## Build library and auxiliary scripts
$(FLOWTGTS): %.js : %.flow.js
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@
@@ -38,15 +28,6 @@ $(FLOWTGTS): %.js : %.flow.js
$(FLOWTARGET): $(DEPS)
cat $^ | tr -d '\15\32' > $@
-$(MINIFLOW): $(MINIDEPS)
- cat $^ | tr -d '\15\32' > $@
-
-$(NODESMTGT): $(NODESMDEPS)
- cat $^ | tr -d '\15\32' > $@
-
-$(ESMJSTGT): $(ESMJSDEPS)
- cat $^ | tr -d '\15\32' > $@
-
bits/01_version.js: package.json
echo "$(ULIB).version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@
@@ -65,40 +46,33 @@ clean-data:
init: ## Initial setup for development
git submodule init
git submodule update
- #git submodule foreach git pull origin master
+ git submodule foreach git pull origin master
git submodule foreach make
mkdir -p tmp
-DISTHDR=misc/suppress_export.js
.PHONY: dist
dist: dist-deps $(TARGET) bower.json ## Prepare JS files for distribution
- mkdir -p dist
- <$(TARGET) sed "s/require('stream')/{}/g;s/require('....*')/undefined/g" > dist/$(TARGET)
+ cp $(TARGET) dist/
cp LICENSE dist/
- uglifyjs shim.js $(UGLIFYOPTS) -o dist/shim.min.js --preamble "$$(head -n 1 bits/00_header.js)"
- uglifyjs $(DISTHDR) dist/$(TARGET) $(UGLIFYOPTS) -o dist/$(LIB).min.js --source-map dist/$(LIB).min.map --preamble "$$(head -n 1 bits/00_header.js)"
+ uglifyjs $(UGLIFYOPTS) $(TARGET) -o dist/$(LIB).min.js --source-map dist/$(LIB).min.map --preamble "$$(head -n 1 bits/00_header.js)"
misc/strip_sourcemap.sh dist/$(LIB).min.js
- uglifyjs $(DISTHDR) $(REQS) dist/$(TARGET) $(UGLIFYOPTS) -o dist/$(LIB).core.min.js --source-map dist/$(LIB).core.min.map --preamble "$$(head -n 1 bits/00_header.js)"
+ uglifyjs $(UGLIFYOPTS) $(REQS) $(TARGET) -o dist/$(LIB).core.min.js --source-map dist/$(LIB).core.min.map --preamble "$$(head -n 1 bits/00_header.js)"
misc/strip_sourcemap.sh dist/$(LIB).core.min.js
- uglifyjs $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) $(UGLIFYOPTS) -o dist/$(LIB).full.min.js --source-map dist/$(LIB).full.min.map --preamble "$$(head -n 1 bits/00_header.js)"
- uglifyjs $(DISTHDR) $(MINITGT) $(UGLIFYOPTS) -o dist/$(LIB).mini.min.js --source-map dist/$(LIB).mini.min.map --preamble "$$(head -n 1 bits/00_header.js)"
+ uglifyjs $(UGLIFYOPTS) $(REQS) $(ADDONS) $(TARGET) $(AUXTARGETS) -o dist/$(LIB).full.min.js --source-map dist/$(LIB).full.min.map --preamble "$$(head -n 1 bits/00_header.js)"
misc/strip_sourcemap.sh dist/$(LIB).full.min.js
- misc/strip_sourcemap.sh dist/$(LIB).mini.min.js
- cat <(head -n 1 bits/00_header.js) shim.js $(DISTHDR) $(REQS) dist/$(TARGET) > dist/$(LIB).extendscript.js
+ cat <(head -n 1 bits/00_header.js) $(REQS) $(ADDONS) $(TARGET) $(AUXTARGETS) > demos/requirejs/$(LIB).full.js
.PHONY: dist-deps
dist-deps: ## Copy dependencies for distribution
- mkdir -p dist
cp node_modules/codepage/dist/cpexcel.full.js dist/cpexcel.js
cp jszip.js dist/jszip.js
.PHONY: aux
aux: $(AUXTARGETS)
-BYTEFILE=dist/xlsx.min.js dist/xlsx.{core,full,mini}.min.js dist/xlsx.extendscript.js
.PHONY: bytes
bytes: ## Display minified and gzipped file sizes
- for i in $(BYTEFILE); do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
+ for i in dist/xlsx.min.js dist/xlsx.{core,full}.min.js; do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
.PHONY: graph
graph: formats.png legend.png ## Rebuild format conversion graph
@@ -112,19 +86,13 @@ legend.png: misc/legend.dot
nexe: xlsx.exe ## Build nexe standalone executable
xlsx.exe: bin/xlsx.njs xlsx.js
- tail -n+2 $< | sed 's#\.\./#./xlsx#g' > nexe.js
- nexe -i nexe.js -o $@
- rm nexe.js
-
-.PHONY: pkg
-pkg: bin/xlsx.njs xlsx.js ## Build pkg standalone executable
- pkg $<
+ nexe -i $< -o $@ --flags
## Testing
.PHONY: test mocha
test mocha: test.js ## Run test suite
- mocha -R spec -t 30000
+ mocha -R spec -t 20000
#* To run tests for one format, make test_
#* To run the core test suite, make test_misc
@@ -147,7 +115,7 @@ ctestserv: ## Start a test server on port 8000
## Demos
-DEMOS=angular angular-new browserify requirejs rollup systemjs webpack
+DEMOS=angular browserify requirejs rollup systemjs webpack
DEMOTGTS=$(patsubst %,demo-%,$(DEMOS))
.PHONY: demos
demos: $(DEMOTGTS)
@@ -157,11 +125,6 @@ demo-angular: ## Run angular demo build
#make -C demos/angular
@echo "start a local server and go to demos/angular/angular.html"
-.PHONY: demo-angular-new
-demo-angular-new: ## Run angular 2 demo build
- make -C demos/angular2
- @echo "go to demos/angular/angular.html and run 'ng serve'"
-
.PHONY: demo-browserify
demo-browserify: ## Run browserify demo build
make -C demos/browserify
@@ -188,32 +151,28 @@ demo-systemjs: ## Run systemjs demo build
## Code Checking
-.PHONY: fullint
-fullint: lint mdlint ## Run all checks (removed: old-lint, tslint, flow)
-
.PHONY: lint
lint: $(TARGET) $(AUXTARGETS) ## Run eslint checks
- @./node_modules/.bin/eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(AUXTARGETS) $(CMDS) $(HTMLLINT) package.json bower.json
- if [ -n "$(CLOSURE-)" ] && [ -e "${CLOSURE}" ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
+ @eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(AUXTARGETS) $(CMDS) $(HTMLLINT) package.json bower.json
+ if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
.PHONY: old-lint
old-lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
- @./node_modules/.bin/jshint --show-non-errors $(TARGET) $(AUXTARGETS)
- @./node_modules/.bin/jshint --show-non-errors $(CMDS)
- @./node_modules/.bin/jshint --show-non-errors package.json bower.json test.js
- @./node_modules/.bin/jshint --show-non-errors --extract=always $(HTMLLINT)
- @./node_modules/.bin/jscs $(TARGET) $(AUXTARGETS) test.js
+ @jshint --show-non-errors $(TARGET) $(AUXTARGETS)
+ @jshint --show-non-errors $(CMDS)
+ @jshint --show-non-errors package.json bower.json
+ @jshint --show-non-errors --extract=always $(HTMLLINT)
+ @jscs $(TARGET) $(AUXTARGETS)
if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
.PHONY: tslint
tslint: $(TARGET) ## Run typescript checks
#@npm install dtslint typescript
- #@npm run-script dtslint
- ./node_modules/.bin/dtslint types
+ @npm run-script dtslint
.PHONY: flow
flow: lint ## Run flow checker
- @./node_modules/.bin/flow check --all --show-all-errors --include-warnings
+ @flow check --all --show-all-errors
.PHONY: cov
cov: misc/coverage.html ## Run coverage test
@@ -225,11 +184,11 @@ $(COVFMT): cov_%:
FMTS=$* make cov
misc/coverage.html: $(TARGET) test.js
- mocha --require blanket -R html-cov -t 30000 > $@
+ mocha --require blanket -R html-cov -t 20000 > $@
.PHONY: coveralls
coveralls: ## Coverage Test + Send to coveralls.io
- mocha --require blanket --reporter mocha-lcov-reporter -t 30000 | node ./node_modules/coveralls/bin/coveralls.js
+ mocha --require blanket --reporter mocha-lcov-reporter -t 20000 | node ./node_modules/coveralls/bin/coveralls.js
READEPS=$(sort $(wildcard docbits/*.md))
README.md: $(READEPS)
@@ -241,16 +200,8 @@ readme: README.md ## Update README Table of Contents
.PHONY: book
book: readme graph ## Update summary for documentation
- printf "# Summary\n\n- [xlsx](README.md#sheetjs-js-xlsx)\n" > misc/docs/SUMMARY.md
+ printf "# Summary\n\n- [xlsx](README.md#xlsx)\n" > misc/docs/SUMMARY.md
markdown-toc README.md | sed 's/(#/(README.md#/g'>> misc/docs/SUMMARY.md
- " > misc/docs/README.md
-
-DEMOMDS=$(sort $(wildcard demos/*/README.md))
-MDLINT=$(DEMOMDS) $(READEPS) demos/README.md
-.PHONY: mdlint
-mdlint: $(MDLINT) ## Check markdown documents
- ./node_modules/.bin/alex $^
- ./node_modules/.bin/mdspell -a -n -x -r --en-us $^
.PHONY: help
help:
diff --git a/README.md b/README.md
index 139deb8..3a61605 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# [SheetJS](https://sheetjs.com)
+# [SheetJS js-xlsx](http://sheetjs.com)
Parser and writer for various spreadsheet formats. Pure-JS cleanroom
implementation from official specifications, related documents, and test files.
@@ -6,30 +6,27 @@ Emphasis on parsing and writing robustness, cross-format feature compatibility
with a unified JS representation, and ES3/ES5 browser compatibility back to IE6.
This is the community version. We also offer a pro version with performance
-enhancements, additional features like styling, and dedicated support.
+enhancements, additional features by request, and dedicated support.
-Community Translations of this README:
+[**Pro Version**](http://sheetjs.com/pro)
-- [Simplified Chinese](https://github.com/rockboom/SheetJS-docs-zh-CN)
+[**Commercial Support**](http://sheetjs.com/support)
+[**Rendered Documentation**](https://sheetjs.gitbooks.io/docs/)
-[**Pro Version**](https://sheetjs.com/pro)
+[**In-Browser Demos**](http://sheetjs.com/demos)
-[**Commercial Support**](https://sheetjs.com/support)
+[**Source Code**](http://git.io/xlsx)
-[**Rendered Documentation**](https://docs.sheetjs.com/)
+[**Issues and Bug Reports**](https://github.com/sheetjs/js-xlsx/issues)
-[**In-Browser Demos**](https://sheetjs.com/demos)
-
-[**Source Code**](https://git.io/xlsx)
-
-[**Issues and Bug Reports**](https://github.com/sheetjs/sheetjs/issues)
+[**Other General Support Issues**](https://discourse.sheetjs.com)
[**File format support for known spreadsheet data formats:**](#file-formats)
- Graph of supported formats (click to show)
+ Graph of supported formats (click to show)
![circo graph of format support](formats.png)
@@ -37,20 +34,22 @@ Community Translations of this README:
-[**Browser Test**](https://oss.sheetjs.com/sheetjs/tests/)
+[**Browser Test**](http://oss.sheetjs.com/js-xlsx/tests/)
[![Build Status](https://saucelabs.com/browser-matrix/sheetjs.svg)](https://saucelabs.com/u/sheetjs)
-[![Build Status](https://semaphoreci.com/api/v1/sheetjs/sheetjs/branches/master/shields_badge.svg)](https://semaphoreci.com/sheetjs/sheetjs)
-[![Coverage Status](https://img.shields.io/coveralls/SheetJS/sheetjs/master.svg)](https://coveralls.io/r/SheetJS/sheetjs?branch=master)
-[![Dependencies Status](https://david-dm.org/sheetjs/sheetjs/status.svg)](https://david-dm.org/sheetjs/sheetjs)
-[![npm Downloads](https://img.shields.io/npm/dt/xlsx.svg)](https://npmjs.org/package/xlsx)
-[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/sheetjs?pixel)](https://github.com/SheetJS/sheetjs)
+[![Build Status](https://travis-ci.org/SheetJS/js-xlsx.svg?branch=master)](https://travis-ci.org/SheetJS/js-xlsx)
+[![Build Status](https://semaphoreci.com/api/v1/sheetjs/js-xlsx/branches/master/shields_badge.svg)](https://semaphoreci.com/sheetjs/js-xlsx)
+[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-xlsx/master.svg)](https://coveralls.io/r/SheetJS/js-xlsx?branch=master)
+[![Dependencies Status](https://david-dm.org/sheetjs/js-xlsx/status.svg)](https://david-dm.org/sheetjs/js-xlsx)
+[![NPM Downloads](https://img.shields.io/npm/dt/xlsx.svg)](https://npmjs.org/package/xlsx)
+[![ghit.me](https://ghit.me/badge.svg?repo=sheetjs/js-xlsx)](https://ghit.me/repo/sheetjs/js-xlsx)
+[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
## Table of Contents
- Expand to show Table of Contents
+ Expand to show Table of Contents
@@ -60,12 +59,12 @@ Community Translations of this README:
* [ECMAScript 5 Compatibility](#ecmascript-5-compatibility)
- [Philosophy](#philosophy)
- [Parsing Workbooks](#parsing-workbooks)
- * [Parsing Examples](#parsing-examples)
+ * [Complete Examples](#complete-examples)
* [Streaming Read](#streaming-read)
- [Working with the Workbook](#working-with-the-workbook)
- * [Parsing and Writing Examples](#parsing-and-writing-examples)
+ * [Complete Examples](#complete-examples-1)
- [Writing Workbooks](#writing-workbooks)
- * [Writing Examples](#writing-examples)
+ * [Complete Examples](#complete-examples-2)
* [Streaming Write](#streaming-write)
- [Interface](#interface)
* [Parsing functions](#parsing-functions)
@@ -79,13 +78,10 @@ Community Translations of this README:
* [Sheet Objects](#sheet-objects)
+ [Worksheet Object](#worksheet-object)
+ [Chartsheet Object](#chartsheet-object)
- + [Macrosheet Object](#macrosheet-object)
- + [Dialogsheet Object](#dialogsheet-object)
* [Workbook Object](#workbook-object)
+ [Workbook File Properties](#workbook-file-properties)
* [Workbook-Level Attributes](#workbook-level-attributes)
+ [Defined Names](#defined-names)
- + [Workbook Views](#workbook-views)
+ [Miscellaneous Workbook Properties](#miscellaneous-workbook-properties)
* [Document Features](#document-features)
+ [Formulae](#formulae)
@@ -95,7 +91,6 @@ Community Translations of this README:
+ [Hyperlinks](#hyperlinks)
+ [Cell Comments](#cell-comments)
+ [Sheet Visibility](#sheet-visibility)
- + [VBA and Macros](#vba-and-macros)
- [Parsing Options](#parsing-options)
* [Input Type](#input-type)
* [Guessing File Type](#guessing-file-type)
@@ -129,8 +124,6 @@ Community Translations of this README:
+ [Lotus Formatted Text (PRN)](#lotus-formatted-text-prn)
+ [Data Interchange Format (DIF)](#data-interchange-format-dif)
+ [HTML](#html)
- + [Rich Text Format (RTF)](#rich-text-format-rtf)
- + [Ethercalc Record Format (ETH)](#ethercalc-record-format-eth)
- [Testing](#testing)
* [Node](#node)
* [Browser](#browser)
@@ -155,81 +148,39 @@ In the browser, just add a script tag:
```
-
- CDN Availability (click to show)
-
-| CDN | URL |
-|-----------:|:-------------------------------------------|
-| `unpkg` | |
-| `jsDelivr` | |
-| `CDNjs` | |
-| `packd` | |
-
-`unpkg` makes the latest version available at:
-
-```html
-
-```
-
-
-
-
With [npm](https://www.npmjs.org/package/xlsx):
```bash
$ npm install xlsx
```
-With [bower](https://bower.io/search/?q=js-xlsx):
+With [bower](http://bower.io/search/?q=js-xlsx):
```bash
$ bower install js-xlsx
```
+CDNjs automatically pulls the latest version and makes all versions available at
+
+
### JS Ecosystem Demos
-The [`demos` directory](demos/) includes sample projects for:
+The `demos` directory includes sample projects for:
-**Frameworks and APIs**
-- [`angularjs`](demos/angular/)
-- [`angular 2 / 4 / 5 / 6 and ionic`](demos/angular2/)
-- [`knockout`](demos/knockout/)
-- [`meteor`](demos/meteor/)
-- [`react and react-native`](demos/react/)
-- [`vue 2.x and weex`](demos/vue/)
-- [`XMLHttpRequest and fetch`](demos/xhr/)
-- [`nodejs server`](demos/server/)
-- [`databases and key/value stores`](demos/database/)
-- [`typed arrays and math`](demos/array/)
-
-**Bundlers and Tooling**
+- [`angular`](demos/angular/)
- [`browserify`](demos/browserify/)
-- [`fusebox`](demos/fusebox/)
-- [`parcel`](demos/parcel/)
+- [`Adobe ExtendScript`](demos/extendscript/)
+- [`meteor`](demos/meteor/)
+- [`phantomjs`](demos/phantomjs/)
- [`requirejs`](demos/requirejs/)
- [`rollup`](demos/rollup/)
- [`systemjs`](demos/systemjs/)
-- [`typescript`](demos/typescript/)
-- [`webpack 2.x`](demos/webpack/)
-
-**Platforms and Integrations**
-- [`electron application`](demos/electron/)
-- [`nw.js application`](demos/nwjs/)
-- [`Chrome / Chromium extensions`](demos/chrome/)
-- [`Adobe ExtendScript`](demos/extendscript/)
-- [`Headless Browsers`](demos/headless/)
-- [`canvas-datagrid`](demos/datagrid/)
-- [`x-spreadsheet`](demos/xspreadsheet/)
-- [`Swift JSC and other engines`](demos/altjs/)
-- [`"serverless" functions`](demos/function/)
-- [`internet explorer`](demos/oldie/)
-
-Other examples are included in the [showcase](demos/showcase/).
+- [`webpack`](demos/webpack/)
### Optional Modules
- Optional features (click to show)
+ Optional features (click to show)
The node version automatically requires modules for additional features. Some
of these modules are rather large in size and are only needed in special
@@ -245,9 +196,7 @@ An appropriate version for each dependency is included in the dist/ directory.
The complete single-file version is generated at `dist/xlsx.full.min.js`
-A slimmer build with XLSX / HTML support is generated at `dist/xlsx.mini.min.js`
-
-Webpack and Browserify builds include optional modules by default. Webpack can
+Webpack and browserify builds include optional modules by default. Webpack can
be configured to remove support with `resolve.alias`:
```js
@@ -261,37 +210,31 @@ be configured to remove support with `resolve.alias`:
### ECMAScript 5 Compatibility
-Since the library uses functions like `Array#forEach`, older browsers require
-[shims to provide missing functions](https://oss.sheetjs.com/sheetjs/shim.js).
+Since xlsx.js uses ES5 functions like `Array#forEach`, older browsers require
+[Polyfills](http://git.io/QVh77g). This repo and the gh-pages branch include
+[a shim](https://github.com/SheetJS/js-xlsx/blob/master/shim.js)
-To use the shim, add the shim before the script tag that loads `xlsx.js`:
+To use the shim, add the shim before the script tag that loads xlsx.js:
```html
-
-
-
-
+
```
-The script also includes `IE_LoadFile` and `IE_SaveFile` for loading and saving
-files in Internet Explorer versions 6-9. The `xlsx.extendscript.js` script
-bundles the shim in a format suitable for Photoshop and other Adobe products.
-
## Philosophy
- Philosophy (click to show)
+ Philosophy (click to show)
Prior to SheetJS, APIs for processing spreadsheet files were format-specific.
Third-party libraries either supported one format, or they involved a separate
set of classes for each supported file type. Even though XLSB was introduced in
Excel 2007, nothing outside of SheetJS or Excel supported the format.
-To promote a format-agnostic view, SheetJS starts from a pure-JS representation
+To promote a format-agnostic view, js-xlsx starts from a pure-JS representation
that we call the ["Common Spreadsheet Format"](#common-spreadsheet-format).
-Emphasizing a uniform object representation enables new features like format
-conversion (reading an XLSX template and saving as XLS) and circumvents the mess
-of classes. By abstracting the complexities of the various formats, tools
+Emphasizing a uniform object representation enables radical features like format
+conversion (e.g. reading an XLSX template and saving as XLS) and circumvents the
+"class trap". By abstracting the complexities of the various formats, tools
need not worry about the specific file type!
A simple object representation combined with careful coding practices enables
@@ -310,10 +253,6 @@ space and open much faster! Even though an XLSX writer is available, other
format writers are available so users can take advantage of the unique
characteristics of each format.
-The primary focus of the Community Edition is correct data interchange, focused
-on extracting data from any compatible data representation and exporting data in
-various formats suitable for any third party interface.
-
## Parsing Workbooks
@@ -322,10 +261,7 @@ For parsing, the first step is to read the file. This involves acquiring the
data and feeding it into the library. Here are a few common scenarios:
- nodejs read a file (click to show)
-
-`readFile` is only available in server environments. Browsers have no API for
-reading arbitrary files given a path, so another strategy must be used.
+ nodejs read a file (click to show)
```js
if(typeof require !== 'undefined') XLSX = require('xlsx');
@@ -336,103 +272,93 @@ var workbook = XLSX.readFile('test.xlsx');
- Photoshop ExtendScript read a file (click to show)
-
-`readFile` wraps the `File` logic in Photoshop and other ExtendScript targets.
-The specified path should be an absolute path:
+ Browser read TABLE element from page (click to show)
```js
-#include "xlsx.extendscript.js"
-/* Read test.xlsx from the Documents folder */
-var workbook = XLSX.readFile(Folder.myDocuments + '/' + 'test.xlsx');
+var worksheet = XLSX.utils.table_to_book(document.getElementById('tableau'));
/* DO SOMETHING WITH workbook HERE */
```
-The [`extendscript` demo](demos/extendscript/) includes a more complex example.
-
-
-
-
- Browser read TABLE element from page (click to show)
-
-The `table_to_book` and `table_to_sheet` utility functions take a DOM TABLE
-element and iterate through the child nodes.
-
-```js
-var workbook = XLSX.utils.table_to_book(document.getElementById('tableau'));
-/* DO SOMETHING WITH workbook HERE */
-```
-
-Multiple tables on a web page can be converted to individual worksheets:
-
-```js
-/* create new workbook */
-var workbook = XLSX.utils.book_new();
-
-/* convert table 'table1' to worksheet named "Sheet1" */
-var ws1 = XLSX.utils.table_to_sheet(document.getElementById('table1'));
-XLSX.utils.book_append_sheet(workbook, ws1, "Sheet1");
-
-/* convert table 'table2' to worksheet named "Sheet2" */
-var ws2 = XLSX.utils.table_to_sheet(document.getElementById('table2'));
-XLSX.utils.book_append_sheet(workbook, ws2, "Sheet2");
-
-/* workbook now has 2 worksheets */
-```
-
-Alternatively, the HTML code can be extracted and parsed:
-
-```js
-var htmlstr = document.getElementById('tableau').outerHTML;
-var workbook = XLSX.read(htmlstr, {type:'string'});
-```
-
- Browser download file (ajax) (click to show)
+ Browser download file (ajax) (click to show)
Note: for a more complete example that works in older browsers, check the demo
-at . The [`xhr` demo](demos/xhr/)
-includes more examples with `XMLHttpRequest` and `fetch`.
+at ):
```js
-var url = "http://oss.sheetjs.com/test_files/formula_stress_test.xlsx";
+/* set up XMLHttpRequest */
+var url = "test_files/formula_stress_test_ajax.xlsx";
+var oReq = new XMLHttpRequest();
+oReq.open("GET", url, true);
+oReq.responseType = "arraybuffer";
-/* set up async GET request */
-var req = new XMLHttpRequest();
-req.open("GET", url, true);
-req.responseType = "arraybuffer";
+oReq.onload = function(e) {
+ var arraybuffer = oReq.response;
-req.onload = function(e) {
- var data = new Uint8Array(req.response);
- var workbook = XLSX.read(data, {type:"array"});
+ /* convert data to binary string */
+ var data = new Uint8Array(arraybuffer);
+ var arr = new Array();
+ for(var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
+ var bstr = arr.join("");
+
+ /* Call XLSX */
+ var workbook = XLSX.read(bstr, {type:"binary"});
/* DO SOMETHING WITH workbook HERE */
}
-req.send();
+oReq.send();
```
- Browser drag-and-drop (click to show)
+ Browser drag-and-drop (click to show)
-Drag-and-drop uses the HTML5 `FileReader` API.
+Drag-and-drop uses FileReader with readAsBinaryString or readAsArrayBuffer.
+Note: readAsBinaryString and readAsArrayBuffer may not be available in every
+browser. Use dynamic feature tests to determine which method to use.
```js
-function handleDrop(e) {
- e.stopPropagation(); e.preventDefault();
- var files = e.dataTransfer.files, f = files[0];
- var reader = new FileReader();
- reader.onload = function(e) {
- var data = new Uint8Array(e.target.result);
- var workbook = XLSX.read(data, {type: 'array'});
+/* processing array buffers, only required for readAsArrayBuffer */
+function fixdata(data) {
+ var o = "", l = 0, w = 10240;
+ for(; l
- Browser file upload form element (click to show)
-
-Data from file input elements can be processed using the same `FileReader` API
-as in the drag-and-drop example:
+ Browser file upload form element (click to show)
```js
+/* fixdata and rABS are defined in the drag and drop example */
function handleFile(e) {
- var files = e.target.files, f = files[0];
- var reader = new FileReader();
- reader.onload = function(e) {
- var data = new Uint8Array(e.target.result);
- var workbook = XLSX.read(data, {type: 'array'});
+ var files = e.target.files;
+ var i,f;
+ for (i = 0; i != files.length; ++i) {
+ f = files[i];
+ var reader = new FileReader();
+ var name = f.name;
+ reader.onload = function(e) {
+ var data = e.target.result;
- /* DO SOMETHING WITH workbook HERE */
- };
- reader.readAsArrayBuffer(f);
+ var workbook;
+ if(rABS) {
+ /* if binary string, read with type 'binary' */
+ workbook = XLSX.read(data, {type: 'binary'});
+ } else {
+ /* if array buffer, convert to base64 */
+ var arr = fixdata(data);
+ workbook = XLSX.read(btoa(arr), {type: 'base64'});
+ }
+
+ /* DO SOMETHING WITH workbook HERE */
+ };
+ reader.readAsBinaryString(f);
+ }
}
input_dom_element.addEventListener('change', handleFile, false);
```
-The [`oldie` demo](demos/oldie/) shows an IE-compatible fallback scenario.
-
-More specialized cases, including mobile app file processing, are covered in the
-[included demos](demos/)
-### Parsing Examples
+### Complete Examples
-- HTML5 File API / Base64 Text / Web Workers
+- HTML5 File API / Base64 Text / Web Workers
-Note that older versions of IE do not support HTML5 File API, so the Base64 mode
+Note that older versions of IE do not support HTML5 File API, so the base64 mode
is used for testing.
- Get Base64 encoding on OSX / Windows (click to show)
+ Get base64 encoding on OSX / Windows (click to show)
-On OSX you can get the Base64 encoding with:
+On OSX you can get the base64 encoding with:
```bash
$ certutil -encode target_file target_file.b64
@@ -493,17 +427,17 @@ On Windows XP and up you can get the Base64 encoding using `certutil`:
-- XMLHttpRequest
+- XMLHttpRequest
### Streaming Read
- Why is there no Streaming Read API? (click to show)
+ Why is there no Streaming Read API? (click to show)
The most common and interesting formats (XLS, XLSX/M, XLSB, ODS) are ultimately
ZIP or CFB containers of files. Neither format puts the directory structure at
the beginning of the file: ZIP files place the Central Directory records at the
-end of the logical file, while CFB files can place the storage info anywhere in
+end of the logical file, while CFB files can place the FAT structure anywhere in
the file! As a result, to properly handle these formats, a streaming function
would have to buffer the entire file before commencing. That belies the
expectations of streaming, so we do not provide any streaming read API.
@@ -515,21 +449,21 @@ and process the whole thing at the end. This can be done with a temporary file
or by explicitly concatenating the stream:
- Explicitly concatenating streams (click to show)
+ Explicitly concatenating streams (click to show)
```js
var fs = require('fs');
var XLSX = require('xlsx');
function process_RS(stream/*:ReadStream*/, cb/*:(wb:Workbook)=>void*/)/*:void*/{
- var buffers = [];
- stream.on('data', function(data) { buffers.push(data); });
- stream.on('end', function() {
- var buffer = Buffer.concat(buffers);
- var workbook = XLSX.read(buffer, {type:"buffer"});
+ var buffers = [];
+ stream.on('data', function(data) { buffers.push(data); });
+ stream.on('end', function() {
+ var buffer = Buffer.concat(buffers);
+ var workbook = XLSX.read(buffer, {type:"buffer"});
- /* DO SOMETHING WITH workbook IN THE CALLBACK */
- cb(workbook);
- });
+ /* DO SOMETHING WITH workbook IN THE CALLBACK */
+ cb(workbook);
+ });
}
```
@@ -538,25 +472,25 @@ More robust solutions are available using modules like `concat-stream`.
- Writing to filesystem first (click to show)
+ Writing to filesystem first (click to show)
-This example uses [`tempfile`](https://npm.im/tempfile) to generate file names:
+This example uses [`tempfile`](https://npm.im/tempfile) for filenames:
```js
var fs = require('fs'), tempfile = require('tempfile');
var XLSX = require('xlsx');
function process_RS(stream/*:ReadStream*/, cb/*:(wb:Workbook)=>void*/)/*:void*/{
- var fname = tempfile('.sheetjs');
- console.log(fname);
- var ostream = fs.createWriteStream(fname);
- stream.pipe(ostream);
- ostream.on('finish', function() {
- var workbook = XLSX.readFile(fname);
- fs.unlinkSync(fname);
+ var fname = tempfile('.sheetjs');
+ console.log(fname);
+ var ostream = fs.createWriteStream(fname);
+ stream.pipe(ostream);
+ ostream.on('finish', function() {
+ var workbook = XLSX.readFile(fname);
+ fs.unlinkSync(fname);
- /* DO SOMETHING WITH workbook IN THE CALLBACK */
- cb(workbook);
- });
+ /* DO SOMETHING WITH workbook IN THE CALLBACK */
+ cb(workbook);
+ });
}
```
@@ -567,7 +501,7 @@ function process_RS(stream/*:ReadStream*/, cb/*:(wb:Workbook)=>void*/)/*:void*/{
The full object format is described later in this README.
- Reading a specific cell (click to show)
+ Reading a specific cell (click to show)
This example extracts the value stored in cell A1 from the first worksheet:
@@ -588,50 +522,35 @@ var desired_value = (desired_cell ? desired_cell.v : undefined);
- Adding a new worksheet to a workbook (click to show)
+ Adding a new worksheet to a workbook (click to show)
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a
-sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook:
+worksheet and appends the new worksheet to the workbook:
```js
-var ws_name = "SheetJS";
+var new_ws_name = "SheetJS";
/* make worksheet */
var ws_data = [
- [ "S", "h", "e", "e", "t", "J", "S" ],
- [ 1 , 2 , 3 , 4 , 5 ]
+ [ "S", "h", "e", "e", "t", "J", "S" ],
+ [ 1 , 2 , 3 , 4 , 5 ]
];
var ws = XLSX.utils.aoa_to_sheet(ws_data);
-/* Add the worksheet to the workbook */
-XLSX.utils.book_append_sheet(wb, ws, ws_name);
+/* Add the sheet name to the list */
+wb.SheetNames.push(ws_name);
+
+/* Load the worksheet object */
+wb.Sheets[ws_name] = ws;
+
```
-
- Creating a new workbook from scratch (click to show)
-The workbook object contains a `SheetNames` array of names and a `Sheets` object
-mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function
-creates a new workbook object:
+### Complete Examples
-```js
-/* create a new blank workbook */
-var wb = XLSX.utils.book_new();
-```
-
-The new workbook is blank and contains no worksheets. The write functions will
-error if the workbook is empty.
-
-
-
-
-### Parsing and Writing Examples
-
-- read + modify + write files
-
-- node
+- node
The node version installs a command line tool `xlsx` which can read spreadsheet
files and output the contents in various formats. The source is available at
@@ -640,7 +559,6 @@ files and output the contents in various formats. The source is available at
Some helper functions in `XLSX.utils` generate different views of the sheets:
- `XLSX.utils.sheet_to_csv` generates CSV
-- `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text
- `XLSX.utils.sheet_to_html` generates HTML
- `XLSX.utils.sheet_to_json` generates an array of objects
- `XLSX.utils.sheet_to_formulae` generates a list of formulae
@@ -653,133 +571,41 @@ dissemination. The second step is to actual share the data with the end point.
Assuming `workbook` is a workbook object:
- nodejs write a file (click to show)
-
-`XLSX.writeFile` uses `fs.writeFileSync` in server environments:
+ nodejs write a file (click to show)
```js
-if(typeof require !== 'undefined') XLSX = require('xlsx');
-/* output format determined by filename */
-XLSX.writeFile(workbook, 'out.xlsb');
-/* at this point, out.xlsb is a file that you can distribute */
-```
-
-
-
-
- Photoshop ExtendScript write a file (click to show)
-
-`writeFile` wraps the `File` logic in Photoshop and other ExtendScript targets.
-The specified path should be an absolute path:
-
-```js
-#include "xlsx.extendscript.js"
/* output format determined by filename */
XLSX.writeFile(workbook, 'out.xlsx');
/* at this point, out.xlsx is a file that you can distribute */
```
-The [`extendscript` demo](demos/extendscript/) includes a more complex example.
-
- Browser add TABLE element to page (click to show)
+ Browser download file (click to show)
-The `sheet_to_html` utility function generates HTML code that can be added to
-any DOM element.
-
-```js
-var worksheet = workbook.Sheets[workbook.SheetNames[0]];
-var container = document.getElementById('tableau');
-container.innerHTML = XLSX.utils.sheet_to_html(worksheet);
-```
-
-
-
-
- Browser upload file (ajax) (click to show)
-
-A complete example using XHR is [included in the XHR demo](demos/xhr/), along
-with examples for fetch and wrapper libraries. This example assumes the server
-can handle Base64-encoded files (see the demo for a basic nodejs server):
-
-```js
-/* in this example, send a base64 string to the server */
-var wopts = { bookType:'xlsx', bookSST:false, type:'base64' };
-
-var wbout = XLSX.write(workbook,wopts);
-
-var req = new XMLHttpRequest();
-req.open("POST", "/upload", true);
-var formdata = new FormData();
-formdata.append('file', 'test.xlsx'); // <-- server expects `file` to hold name
-formdata.append('data', wbout); // <-- `data` holds the base64-encoded data
-req.send(formdata);
-```
-
-
-
-
- Browser save file (click to show)
-
-`XLSX.writeFile` wraps a few techniques for triggering a file save:
-
-- `URL` browser API creates an object URL for the file, which the library uses
- by creating a link and forcing a click. It is supported in modern browsers.
-- `msSaveBlob` is an IE10+ API for triggering a file save.
-- `IE_FileSave` uses VBScript and ActiveX to write a file in IE6+ for Windows
- XP and Windows 7. The shim must be included in the containing HTML page.
-
-There is no standard way to determine if the actual file has been downloaded.
-
-```js
-/* output format determined by filename */
-XLSX.writeFile(workbook, 'out.xlsb');
-/* at this point, out.xlsb will have been downloaded */
-```
-
-
-
-
- Browser save file (compatibility) (click to show)
-
-`XLSX.writeFile` techniques work for most modern browsers as well as older IE.
-For much older browsers, there are workarounds implemented by wrapper libraries.
-
-[`FileSaver.js`](https://github.com/eligrey/FileSaver.js/) implements `saveAs`.
-Note: `XLSX.writeFile` will automatically call `saveAs` if available.
+Note: browser generates binary blob and forces a "download" to client. This
+example uses [FileSaver.js](https://github.com/eligrey/FileSaver.js/):
```js
/* bookType can be any supported output type */
-var wopts = { bookType:'xlsx', bookSST:false, type:'array' };
+var wopts = { bookType:'xlsx', bookSST:false, type:'binary' };
var wbout = XLSX.write(workbook,wopts);
+function s2ab(s) {
+ var buf = new ArrayBuffer(s.length);
+ var view = new Uint8Array(buf);
+ for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
+ return buf;
+}
+
/* the saveAs call downloads a file on the local machine */
-saveAs(new Blob([wbout],{type:"application/octet-stream"}), "test.xlsx");
+saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "test.xlsx");
```
-
-[`Downloadify`](https://github.com/dcneiner/downloadify) uses a Flash SWF button
-to generate local files, suitable for environments where ActiveX is unavailable:
-
-```js
-Downloadify.create(id,{
- /* other options are required! read the downloadify docs for more info */
- filename: "test.xlsx",
- data: function() { return XLSX.write(wb, {bookType:"xlsx", type:'base64'}); },
- append: false,
- dataType: 'base64'
-});
-```
-
-The [`oldie` demo](demos/oldie/) shows an IE-compatible fallback scenario.
-
-The [included demos](demos/) cover mobile apps and other special deployments.
-
-### Writing Examples
+### Complete Examples
- exporting an HTML table
- generates a simple file
@@ -792,10 +618,9 @@ Stream. They are only exposed in NodeJS.
- `XLSX.stream.to_csv` is the streaming version of `XLSX.utils.sheet_to_csv`.
- `XLSX.stream.to_html` is the streaming version of `XLSX.utils.sheet_to_html`.
-- `XLSX.stream.to_json` is the streaming version of `XLSX.utils.sheet_to_json`.
- nodejs convert to CSV and write file (click to show)
+ nodejs convert to CSV and write file (click to show)
```js
var output_file_name = "out.csv";
@@ -805,22 +630,6 @@ stream.pipe(fs.createWriteStream(output_file_name));
-
- nodejs write JSON stream to screen (click to show)
-
-```js
-/* to_json returns an object-mode stream */
-var stream = XLSX.stream.to_json(worksheet, {raw:true});
-
-/* the following stream converts JS objects to text via JSON.stringify */
-var conv = new Transform({writableObjectMode:true});
-conv._transform = function(obj, e, cb){ cb(null, JSON.stringify(obj) + "\n"); };
-
-stream.pipe(conv); conv.pipe(process.stdout);
-```
-
-
-
pipes write streams to nodejs response.
## Interface
@@ -829,7 +638,7 @@ stream.pipe(conv); conv.pipe(process.stdout);
`XLSX.version` is the version of the library (added by the build script).
-`XLSX.SSF` is an embedded version of the [format library](https://git.io/ssf).
+`XLSX.SSF` is an embedded version of the [format library](http://git.io/ssf).
### Parsing functions
@@ -843,8 +652,7 @@ Parse options are described in the [Parsing Options](#parsing-options) section.
`XLSX.write(wb, write_opts)` attempts to write the workbook `wb`
-`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`.
-In browser-based environments, it will attempt to force a client-side download.
+`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`
`XLSX.writeFileAsync(filename, wb, o, cb)` attempts to write `wb` to `filename`.
If `o` is omitted, the writer will use the third argument as the callback.
@@ -855,38 +663,36 @@ Write options are described in the [Writing Options](#writing-options) section.
### Utilities
-Utilities are available in the `XLSX.utils` object and are described in the
-[Utility Functions](#utility-functions) section:
+Utilities are available in the `XLSX.utils` object:
**Importing:**
- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
- `json_to_sheet` converts an array of JS objects to a worksheet.
- `table_to_sheet` converts a DOM TABLE element to a worksheet.
-- `sheet_add_aoa` adds an array of arrays of JS data to an existing worksheet.
-- `sheet_add_json` adds an array of JS objects to an existing worksheet.
-
**Exporting:**
- `sheet_to_json` converts a worksheet object to an array of JSON objects.
- `sheet_to_csv` generates delimiter-separated-values output.
-- `sheet_to_txt` generates UTF16 formatted text.
- `sheet_to_html` generates HTML output.
- `sheet_to_formulae` generates a list of the formulae (with value fallbacks).
+These utilities are described in [Utility Functions](#utility-functions) below.
+
**Cell and cell address manipulation:**
-- `format_cell` generates the text value for a cell (using number formats).
-- `encode_row / decode_row` converts between 0-indexed rows and 1-indexed rows.
-- `encode_col / decode_col` converts between 0-indexed columns and column names.
-- `encode_cell / decode_cell` converts cell addresses.
-- `encode_range / decode_range` converts cell ranges.
+- `format_cell` generates the text value for a cell (using number formats)
+- `{en,de}code_{row,col}` convert between 0-indexed rows/cols and A1 forms.
+- `{en,de}code_cell` converts cell addresses
+- `{en,de}code_range` converts cell ranges
+
+Utilities are described in the [Utility Functions](#utility-functions) section.
## Common Spreadsheet Format
-SheetJS conforms to the Common Spreadsheet Format (CSF):
+js-xlsx conforms to the Common Spreadsheet Format (CSF):
### General Structures
@@ -896,35 +702,31 @@ represented by the object `{c:1, r:4}`.
Cell range objects are stored as `{s:S, e:E}` where `S` is the first cell and
`E` is the last cell in the range. The ranges are inclusive. For example, the
-range `A3:B7` is represented by the object `{s:{c:0, r:2}, e:{c:1, r:6}}`.
-Utility functions perform a row-major order walk traversal of a sheet range:
+range `A3:B7` is represented by the object `{s:{c:0, r:2}, e:{c:1, r:6}}`. Utils
+use the following pattern to walk each of the cells in a range:
```js
for(var R = range.s.r; R <= range.e.r; ++R) {
for(var C = range.s.c; C <= range.e.c; ++C) {
var cell_address = {c:C, r:R};
- /* if an A1-style address is needed, encode the address */
- var cell_ref = XLSX.utils.encode_cell(cell_address);
}
}
```
### Cell Object
-Cell objects are plain JS objects with keys and values following the convention:
-
| Key | Description |
| --- | ---------------------------------------------------------------------- |
| `v` | raw value (see Data Types section for more info) |
| `w` | formatted text (if applicable) |
-| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
+| `t` | cell type: `b` Boolean, `n` Number, `e` error, `s` String, `d` Date |
| `f` | cell formula encoded as an A1-style string (if applicable) |
| `F` | range of enclosing array if formula is array formula (if applicable) |
| `r` | rich text encoding (if applicable) |
| `h` | HTML rendering of the rich text (if applicable) |
| `c` | comments associated with the cell |
| `z` | number format string associated with the cell (if requested) |
-| `l` | cell hyperlink object (`.Target` holds link, `.Tooltip` is tooltip) |
+| `l` | cell hyperlink object (.Target holds link, .Tooltip is tooltip) |
| `s` | the style/theme of the cell (if applicable) |
Built-in export utilities (such as the CSV exporter) will use the `w` text if it
@@ -937,21 +739,14 @@ array range. Other cells in the range will omit the `f` field.
#### Data Types
-The raw value is stored in the `v` value property, interpreted based on the `t`
-type property. This separation allows for representation of numbers as well as
-numeric text. There are 6 valid cell types:
+The raw value is stored in the `v` field, interpreted based on the `t` field.
-| Type | Description |
-| :--: | :-------------------------------------------------------------------- |
-| `b` | Boolean: value interpreted as JS `boolean` |
-| `e` | Error: value is a numeric code and `w` property stores common name ** |
-| `n` | Number: value is a JS `number` ** |
-| `d` | Date: value is a JS `Date` object or string to be parsed as Date ** |
-| `s` | Text: value interpreted as JS `string` and written as text ** |
-| `z` | Stub: blank stub cell that is ignored by data processing utilities ** |
+Type `b` is the Boolean type. `v` is interpreted according to JS truth tables.
+
+Type `e` is the Error type. `v` holds the number and `w` holds the common name:
- Error values and interpretation (click to show)
+ Error values and interpretation (click to show)
| Value | Error Meaning |
| -----: | :-------------- |
@@ -977,22 +772,19 @@ Since JSON does not have a natural Date type, parsers are generally expected to
store ISO 8601 Date strings like you would get from `date.toISOString()`. On
the other hand, writers and exporters should be able to handle date strings and
JS Date objects. Note that Excel disregards timezone modifiers and treats all
-dates in the local timezone. The library does not correct for this error.
+dates in the local timezone. js-xlsx does not correct for this error.
-Type `s` is the String type. Values are explicitly stored as text. Excel will
-interpret these cells as "number stored as text". Generated Excel files
-automatically suppress that class of error, but other formats may elicit errors.
-
-Type `z` represents blank stub cells. They are generated in cases where cells
-have no assigned value but hold comments or other metadata. They are ignored by
-the core library data processing utility functions. By default these cells are
-not generated; the parser `sheetStubs` option must be set to `true`.
+Type `s` is the String type. `v` should be explicitly stored as a string to
+avoid possible confusion.
+Type `z` represents blank stub cells. These do not have any data or type, and
+are not processed by any of the core library functions. By default these cells
+will not be generated; the parser `sheetStubs` option must be set to `true`.
#### Dates
- Excel Date Code details (click to show)
+ Excel Date Code details (click to show)
By default, Excel stores dates as numbers with a format code that specifies date
processing. For example, the date `19-Feb-17` is stored as the number `42785`
@@ -1008,7 +800,7 @@ The default behavior for all parsers is to generate number cells. Setting
- Time Zones and Dates (click to show)
+ Time Zones and Dates (click to show)
Excel has no native concept of universal time. All times are specified in the
local time zone. Excel limitations prevent specifying true absolute dates.
@@ -1018,9 +810,10 @@ Following Excel, this library treats all dates as relative to local time zone.
- Epochs: 1900 and 1904 (click to show)
+ Epochs: 1900 and 1904 (click to show)
-Excel supports two epochs (January 1 1900 and January 1 1904).
+Excel supports two epochs (January 1 1900 and January 1 1904), see
+["1900 vs. 1904 Date System" article](http://support2.microsoft.com/kb/180162).
The workbook's epoch can be determined by examining the workbook's
`wb.Workbook.WBProps.date1904` property:
@@ -1057,7 +850,7 @@ Each key that does not start with `!` maps to a cell (using `A-1` notation)
but they are stored as raw measurements. The main properties are listed below:
- Page margin details (click to show)
+ Page margin details (click to show)
| key | description | "normal" | "wide" | "narrow" |
|----------|------------------------|:---------|:-------|:-------- |
@@ -1070,11 +863,11 @@ Each key that does not start with `!` maps to a cell (using `A-1` notation)
```js
/* Set worksheet sheet to "normal" */
-ws["!margins"]={left:0.7, right:0.7, top:0.75,bottom:0.75,header:0.3,footer:0.3}
+sheet["!margins"] = { left:0.7, right:0.7, top:0.75, bottom:0.75, header:0.3, footer:0.3 }
/* Set worksheet sheet to "wide" */
-ws["!margins"]={left:1.0, right:1.0, top:1.0, bottom:1.0, header:0.5,footer:0.5}
+sheet["!margins"] = { left:1.0, right:1.0, top:1.0, bottom:1.0, header:0.5, footer:0.5 }
/* Set worksheet sheet to "narrow" */
-ws["!margins"]={left:0.25,right:0.25,top:0.75,bottom:0.75,header:0.3,footer:0.3}
+sheet["!margins"] = { left:0.25, right:0.25, top:0.75, bottom:0.75, header:0.3, footer:0.3 }
```
@@ -1092,18 +885,10 @@ In addition to the base sheet keys, worksheets also add:
Each row object encodes properties including row height and visibility.
- `ws['!merges']`: array of range objects corresponding to the merged cells in
- the worksheet. Plain text formats do not support merge cells. CSV export
+ the worksheet. Plaintext utilities are unaware of merge cells. CSV export
will write all cells in the merge range if they exist, so be sure that only
the first cell (upper-left) in the range is set.
-- `ws['!outline']`: configure how outlines should behave. Options default to
- the default settings in Excel 2019:
-
-| key | Excel feature | default |
-|:----------|:----------------------------------------------|:--------|
-| `above` | Uncheck "Summary rows below detail" | `false` |
-| `left` | Uncheck "Summary rows to the right of detail" | `false` |
-
- `ws['!protect']`: object of write sheet protection properties. The `password`
key specifies the password for formats that support password-protected sheets
(XLSX/XLSB/XLS). The writer uses the XOR obfuscation method. The following
@@ -1111,7 +896,7 @@ In addition to the base sheet keys, worksheets also add:
sheet is locked or set to `true` to disable a feature:
- Worksheet Protection Details (click to show)
+ Worksheet Protection Details (click to show)
| key | feature (true=disabled / false=enabled) | default |
|:----------------------|:----------------------------------------|:-----------|
@@ -1148,16 +933,6 @@ Chartsheets are represented as standard sheets. They are distinguished with the
The underlying data and `!ref` refer to the cached data in the chartsheet. The
first row of the chartsheet is the underlying header.
-#### Macrosheet Object
-
-Macrosheets are represented as standard sheets. They are distinguished with the
-`!type` property set to `"macro"`.
-
-#### Dialogsheet Object
-
-Dialogsheets are represented as standard sheets. They are distinguished with the
-`!type` property set to `"dialog"`.
-
### Workbook Object
`workbook.SheetNames` is an ordered list of the sheets in the workbook
@@ -1176,21 +951,20 @@ The various file formats use different internal names for file properties. The
workbook `Props` object normalizes the names:
- File Properties (click to show)
-
-| JS Name | Excel Description |
-|:--------------|:-------------------------------|
-| `Title` | Summary tab "Title" |
-| `Subject` | Summary tab "Subject" |
-| `Author` | Summary tab "Author" |
-| `Manager` | Summary tab "Manager" |
-| `Company` | Summary tab "Company" |
-| `Category` | Summary tab "Category" |
-| `Keywords` | Summary tab "Keywords" |
-| `Comments` | Summary tab "Comments" |
-| `LastAuthor` | Statistics tab "Last saved by" |
-| `CreatedDate` | Statistics tab "Created" |
+ File Properties (click to show)
+| JS Name | Excel Description |
+|:------------|:-------------------------------|
+| Title | Summary tab "Title" |
+| Subject | Summary tab "Subject" |
+| Author | Summary tab "Author" |
+| Manager | Summary tab "Manager" |
+| Company | Summary tab "Company" |
+| Category | Summary tab "Category" |
+| Keywords | Summary tab "Keywords" |
+| Comments | Summary tab "Comments" |
+| LastAuthor | Statistics tab "Last saved by" |
+| CreatedDate | Statistics tab "Created" |
For example, to set the workbook title property:
@@ -1223,13 +997,13 @@ XLSX.write(wb, {Props:{Author:"SheetJS"}});
`wb.Workbook.Names` is an array of defined name objects which have the keys:
- Defined Name Properties (click to show)
+ Defined Name Properties (click to show)
| Key | Description |
|:----------|:-----------------------------------------------------------------|
| `Sheet` | Name scope. Sheet Index (0 = first sheet) or `null` (Workbook) |
| `Name` | Case-sensitive name. Standard rules apply ** |
-| `Ref` | A1-style Reference (`"Sheet1!$A$1:$D$20"`) |
+| `Ref` | A1-style Reference (e.g. `"Sheet1!$A$1:$D$20"`) |
| `Comment` | Comment (only applicable for XLS/XLSX/XLSB) |
@@ -1238,21 +1012,12 @@ Excel allows two sheet-scoped defined names to share the same name. However, a
sheet-scoped name cannot collide with a workbook-scope name. Workbook writers
may not enforce this constraint.
-#### Workbook Views
-
-`wb.Workbook.Views` is an array of workbook view objects which have the keys:
-
-| Key | Description |
-|:----------------|:----------------------------------------------------|
-| `RTL` | If true, display right-to-left |
-
#### Miscellaneous Workbook Properties
`wb.Workbook.WBProps` holds other workbook properties:
| Key | Description |
|:----------------|:----------------------------------------------------|
-| `CodeName` | [VBA Project Workbook Code Name](#vba-and-macros) |
| `date1904` | epoch: 0/false for 1900 system, 1/true for 1904 |
| `filterPrivacy` | Warn or strip personally identifying info on save |
@@ -1271,14 +1036,14 @@ Even though some formats store formulae with a leading equal sign, CSF formulae
do not start with `=`.
- Representation of A1=1, A2=2, A3=A1+A2 (click to show)
+ Representation of A1=1, A2=2, A3=A1+A2 (click to show)
```js
{
- "!ref": "A1:A3",
- A1: { t:'n', v:1 },
- A2: { t:'n', v:2 },
- A3: { t:'n', v:3, f:'A1+A2' }
+ "!ref": "A1:A3",
+ A1: { t:'n', v:1 },
+ A2: { t:'n', v:2 },
+ A3: { t:'n', v:3, f:'A1+A2' }
}
```
@@ -1291,14 +1056,14 @@ and other spreadsheet tools will recognize. This library will not automatically
compute formula results! For example, to compute `BESSELJ` in a worksheet:
- Formula without known value (click to show)
+ Formula without known value (click to show)
```js
{
- "!ref": "A1:A3",
- A1: { t:'n', v:3.14159 },
- A2: { t:'n', v:2 },
- A3: { t:'n', f:'BESSELJ(A1,A2)' }
+ "!ref": "A1:A3",
+ A1: { t:'n', v:3.14159 },
+ A2: { t:'n', v:2 },
+ A3: { t:'n', f:'BESSELJ(A1,A2)' }
}
```
@@ -1310,7 +1075,7 @@ of an array formula have a `F` field corresponding to the range. A single-cell
formula can be distinguished from a plain formula by the presence of `F` field.
- Array Formula examples (click to show)
+ Array Formula examples (click to show)
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
@@ -1334,7 +1099,7 @@ ignore any possible formula element `f` in cells other than the starting cell.
They are not expected to perform validation of the formulae!
- Formula Output Utility Function (click to show)
+ Formula Output Utility Function (click to show)
The `sheet_to_formulae` method generates one line per formula or array formula.
Array formulae are rendered in the form `range=formula` while plain cells are
@@ -1343,19 +1108,19 @@ prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
- Formulae File Format Details (click to show)
+ Formulae File Format Details (click to show)
| Storage Representation | Formats | Read | Write |
|:-----------------------|:-------------------------|:-----:|:-----:|
| A1-style strings | XLSX | :o: | :o: |
-| RC-style strings | XLML and plain text | :o: | :o: |
+| RC-style strings | XLML and plaintext | :o: | :o: |
| BIFF Parsed formulae | XLSB and all XLS formats | :o: | |
| OpenFormula formulae | ODS/FODS/UOS | :o: | :o: |
Since Excel prohibits named cells from colliding with names of A1 or RC style
cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
formulae have to be explicitly unwound. OpenFormula formulae can be converted
-with regular expressions.
+with regexes for the most part.
#### Column Properties
@@ -1365,26 +1130,26 @@ objects which have the following properties:
```typescript
type ColInfo = {
- /* visibility */
- hidden?: boolean; // if true, the column is hidden
+ /* visibility */
+ hidden?: boolean; // if true, the column is hidden
- /* column width is specified in one of the following ways: */
- wpx?: number; // width in screen pixels
- width?: number; // width in Excel's "Max Digit Width", width*256 is integral
- wch?: number; // width in characters
+ /* column width is specified in one of the following ways: */
+ wpx?: number; // width in screen pixels
+ width?: number; // width in Excel's "Max Digit Width", width*256 is integral
+ wch?: number; // width in characters
- /* other fields for preserving features from files */
- MDW?: number; // Excel's "Max Digit Width" unit, always integral
+ /* other fields for preserving features from files */
+ MDW?: number; // Excel's "Max Digit Width" unit, always integral
};
```
- Why are there three width types? (click to show)
+ Why are there three width types? (click to show)
There are three different width types corresponding to the three different ways
spreadsheets store column widths:
-SYLK and other plain text formats use raw character count. Contemporaneous tools
+SYLK and other plaintext formats use raw character count. Contemporaneous tools
like Visicalc and Multiplan were character based. Since the characters had the
same width, it sufficed to store a count. This tradition was continued into the
BIFF formats.
@@ -1398,15 +1163,10 @@ Max Digit Width is the width of the largest digit when rendered (generally the
"0" character is the widest). The internal width must be an integer multiple of
the the width divided by 256. ECMA-376 describes a formula for converting
between pixels and the internal width. This represents a hybrid approach.
-
-Read functions attempt to populate all three properties. Write functions will
-try to cycle specified values to the desired type. In order to avoid potential
-conflicts, manipulation should delete the other properties first. For example,
-when changing the pixel width, delete the `wch` and `width` properties.
- Implementation details (click to show)
+ Implementation details (click to show)
Given the constraints, it is possible to determine the MDW without actually
inspecting the font! The parsers guess the pixel width by converting from width
@@ -1429,22 +1189,17 @@ objects which have the following properties:
```typescript
type RowInfo = {
- /* visibility */
- hidden?: boolean; // if true, the row is hidden
+ /* visibility */
+ hidden?: boolean; // if true, the row is hidden
- /* row height is specified in one of the following ways: */
- hpx?: number; // height in screen pixels
- hpt?: number; // height in points
-
- level?: number; // 0-indexed outline / group level
+ /* row height is specified in one of the following ways: */
+ hpx?: number; // height in screen pixels
+ hpt?: number; // height in points
};
```
-Note: Excel UI displays the base outline level as `1` and the max level as `8`.
-The `level` field stores the base outline as `0` and the max level as `7`.
-
- Implementation details (click to show)
+ Implementation details (click to show)
Excel internally stores row heights in points. The default resolution is 72 DPI
or 96 PPI, so the pixel and point size should agree. For different resolutions
@@ -1470,19 +1225,19 @@ somewhere in the table. Excel convention mandates that the custom formats start
at index 164. The following example creates a custom format from scratch:
- New worksheet with custom format (click to show)
+ New worksheet with custom format (click to show)
```js
var wb = {
- SheetNames: ["Sheet1"],
- Sheets: {
- Sheet1: {
- "!ref":"A1:C1",
- A1: { t:"n", v:10000 }, // <-- General format
- B1: { t:"n", v:10000, z: "0%" }, // <-- Builtin format
- C1: { t:"n", v:10000, z: "\"T\"\ #0.00" } // <-- Custom format
- }
- }
+ SheetNames: ["Sheet1"],
+ Sheets: {
+ Sheet1: {
+ "!ref":"A1:C1",
+ A1: { t:"n", v:10000 }, // <-- General format
+ B1: { t:"n", v:10000, z: "0%" }, // <-- Builtin format
+ C1: { t:"n", v:10000, z: "\"T\"\ #0.00" } // <-- Custom format
+ }
+ }
}
```
@@ -1490,11 +1245,11 @@ var wb = {
The rules are slightly different from how Excel displays custom number formats.
In particular, literal characters must be wrapped in double quotes or preceded
by a backslash. For more info, see the Excel documentation article
-`Create or delete a custom number format` or ECMA-376 18.8.31 (Number Formats)
-
+[`Create or delete a custom number format`](https://support.office.com/en-us/article/78f2a361-936b-4c03-8772-09fab54be7f4)
+or ECMA-376 18.8.31 (Number Formats)
- Default Number Formats (click to show)
+ Default Number Formats (click to show)
The default formats are listed in ECMA-376 18.8.30:
@@ -1537,7 +1292,6 @@ sense when the producer and consumer of files are in the same locale, but that
is not always the case over the Internet. To get around this ambiguity, parse
functions accept the `dateNF` option to override the interpretation of that
specific format string.
-
#### Hyperlinks
Hyperlinks are stored in the `l` key of cell objects. The `Target` field of the
@@ -1546,28 +1300,21 @@ are stored in the `Tooltip` field and are displayed when you move your mouse
over the text.
For example, the following snippet creates a link from cell `A3` to
- with the tip `"Find us @ SheetJS.com!"`:
+ with the tip `"Find us @ SheetJS.com!"`:
```js
-ws['A3'].l = { Target:"https://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
+ws['A3'].l = { Target:"http://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
```
Note that Excel does not automatically style hyperlinks -- they will generally
be displayed as normal text.
-Links where the target is a cell or range or defined name in the same workbook
-("Internal Links") are marked with a leading hash character:
-
-```js
-ws['A2'].l = { Target:"#E2" }; /* link to cell E2 */
-```
-
#### Cell Comments
Cell comments are objects stored in the `c` array of cell objects. The actual
contents of the comment are split into blocks based on the comment author. The
`a` field of each comment object is the author of the comment and the `t` field
-is the plain text representation.
+is the plaintext representation.
For example, the following snippet appends a cell comment into cell `A1`:
@@ -1579,28 +1326,17 @@ ws.A1.c.push({a:"SheetJS", t:"I'm a little comment, short and stout!"});
Note: XLSB enforces a 54 character limit on the Author name. Names longer than
54 characters may cause issues with other formats.
-To mark a comment as normally hidden, set the `hidden` property:
-
-```js
-if(!ws.A1.c) ws.A1.c = [];
-ws.A1.c.push({a:"SheetJS", t:"This comment is visible"});
-
-if(!ws.A2.c) ws.A2.c = [];
-ws.A2.c.hidden = true;
-ws.A2.c.push({a:"SheetJS", t:"This comment will be hidden"});
-```
-
#### Sheet Visibility
Excel enables hiding sheets in the lower tab bar. The sheet data is stored in
the file but the UI does not readily make it available. Standard hidden sheets
-are revealed in the "Unhide" menu. Excel also has "very hidden" sheets which
+are revealed in the unhide menu. Excel also has "very hidden" sheets which
cannot be revealed in the menu. It is only accessible in the VB Editor!
The visibility setting is stored in the `Hidden` property of sheet props array.
- More details (click to show)
+ More details (click to show)
| Value | Definition |
|:-----:|:------------|
@@ -1608,7 +1344,7 @@ The visibility setting is stored in the `Hidden` property of sheet props array.
| 1 | Hidden |
| 2 | Very Hidden |
-With :
+With :
```js
> wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] })
@@ -1624,110 +1360,48 @@ if a sheet is visible is to check if the `Hidden` property is logical truth:
```
-#### VBA and Macros
-
-VBA Macros are stored in a special data blob that is exposed in the `vbaraw`
-property of the workbook object when the `bookVBA` option is `true`. They are
-supported in `XLSM`, `XLSB`, and `BIFF8 XLS` formats. The supported format
-writers automatically insert the data blobs if it is present in the workbook and
-associate with the worksheet names.
-
-
- Custom Code Names (click to show)
-
-The workbook code name is stored in `wb.Workbook.WBProps.CodeName`. By default,
-Excel will write `ThisWorkbook` or a translated phrase like `DieseArbeitsmappe`.
-Worksheet and Chartsheet code names are in the worksheet properties object at
-`wb.Workbook.Sheets[i].CodeName`. Macrosheets and Dialogsheets are ignored.
-
-The readers and writers preserve the code names, but they have to be manually
-set when adding a VBA blob to a different workbook.
-
-
-
-
- Macrosheets (click to show)
-
-Older versions of Excel also supported a non-VBA "macrosheet" sheet type that
-stored automation commands. These are exposed in objects with the `!type`
-property set to `"macro"`.
-
-
-
-
- Detecting macros in workbooks (click to show)
-
-The `vbaraw` field will only be set if macros are present, so testing is simple:
-
-```js
-function wb_has_macro(wb/*:workbook*/)/*:boolean*/ {
- if(!!wb.vbaraw) return true;
- const sheets = wb.SheetNames.map((n) => wb.Sheets[n]);
- return sheets.some((ws) => !!ws && ws['!type']=='macro');
-}
-```
-
-
-
## Parsing Options
The exported `read` and `readFile` functions accept an options argument:
| Option Name | Default | Description |
| :---------- | ------: | :--------------------------------------------------- |
-|`type` | | Input data encoding (see Input Type below) |
-|`raw` | false | If true, plain text parsing will not parse values ** |
-|`codepage` | | If specified, use code page when appropriate ** |
-|`cellFormula`| true | Save formulae to the .f field |
-|`cellHTML` | true | Parse rich text and save HTML to the `.h` field |
-|`cellNF` | false | Save number format string to the `.z` field |
-|`cellStyles` | false | Save style/theme info to the `.s` field |
-|`cellText` | true | Generated formatted text to the `.w` field |
-|`cellDates` | false | Store dates as type `d` (default is `n`) |
-|`dateNF` | | If specified, use the string for date code 14 ** |
-|`sheetStubs` | false | Create cell objects of type `z` for stub cells |
-|`sheetRows` | 0 | If >0, read the first `sheetRows` rows ** |
-|`bookDeps` | false | If true, parse calculation chains |
-|`bookFiles` | false | If true, add raw files to book object ** |
-|`bookProps` | false | If true, only parse enough to get book metadata ** |
-|`bookSheets` | false | If true, only parse enough to get the sheet names |
-|`bookVBA` | false | If true, copy VBA blob to `vbaraw` field ** |
-|`password` | "" | If defined and file is encrypted, use password ** |
-|`WTF` | false | If true, throw errors on unexpected file features ** |
-|`sheets` | | If specified, only parse specified sheets ** |
-|`PRN` | false | If true, allow parsing of PRN files ** |
-|`xlfn` | false | If true, preserve `_xlfn.` prefixes in formulae ** |
+| type | | Input data encoding (see Input Type below) |
+| cellFormula | true | Save formulae to the .f field |
+| cellHTML | true | Parse rich text and save HTML to the `.h` field |
+| cellNF | false | Save number format string to the `.z` field |
+| cellStyles | false | Save style/theme info to the `.s` field |
+| cellText | true | Generated formatted text to the `.w` field |
+| cellDates | false | Store dates as type `d` (default is `n`) |
+| dateNF | | If specified, use the string for date code 14 ** |
+| sheetStubs | false | Create cell objects of type `z` for stub cells |
+| sheetRows | 0 | If >0, read the first `sheetRows` rows ** |
+| bookDeps | false | If true, parse calculation chains |
+| bookFiles | false | If true, add raw files to book object ** |
+| bookProps | false | If true, only parse enough to get book metadata ** |
+| bookSheets | false | If true, only parse enough to get the sheet names |
+| bookVBA | false | If true, expose vbaProject.bin to `vbaraw` field ** |
+| password | "" | If defined and file is encrypted, use password ** |
+| WTF | false | If true, throw errors on unexpected file features ** |
- Even if `cellNF` is false, formatted text will be generated and saved to `.w`
- In some cases, sheets may be parsed even if `bookSheets` is false.
-- Excel aggressively tries to interpret values from CSV and other plain text.
- This leads to surprising behavior! The `raw` option suppresses value parsing.
- `bookSheets` and `bookProps` combine to give both sets of information
-- `Deps` will be an empty object if `bookDeps` is false
+- `Deps` will be an empty object if `bookDeps` is falsy
- `bookFiles` behavior depends on file type:
* `keys` array (paths in the ZIP) for ZIP-based formats
* `files` hash (mapping paths to objects representing the files) for ZIP
* `cfb` object for formats using CFB containers
- `sheetRows-1` rows will be generated when looking at the JSON object output
(since the header row is counted as a row when parsing the data)
-- By default all worksheets are parsed. `sheets` restricts based on input type:
- * number: zero-based index of worksheet to parse (`0` is first worksheet)
- * string: name of worksheet to parse (case insensitive)
- * array of numbers and strings to select multiple worksheets.
-- `bookVBA` merely exposes the raw VBA CFB object. It does not parse the data.
- XLSM and XLSB store the VBA CFB object in `xl/vbaProject.bin`. BIFF8 XLS mixes
- the VBA entries alongside the core Workbook entry, so the library generates a
- new XLSB-compatible blob from the XLS CFB container.
-- `codepage` is applied to BIFF2 - BIFF5 files without `CodePage` records and to
- CSV files without BOM in `type:"binary"`. BIFF8 XLS always defaults to 1200.
-- `PRN` affects parsing of text files without a common delimiter character.
+- `bookVBA` merely exposes the raw vba object. It does not parse the data.
- Currently only XOR encryption is supported. Unsupported error will be thrown
for files employing other encryption methods.
-- Newer Excel functions are serialized with the `_xlfn.` prefix, hidden from the
- user. SheetJS will strip `_xlfn.` normally. The `xlfn` option preserves them.
- WTF is mainly for development. By default, the parser will suppress read
errors on single worksheets, allowing you to read from the worksheets that do
- parse properly. Setting `WTF:true` forces those errors to be thrown.
+ parse properly. Setting `WTF:1` forces those errors to be thrown.
+
+The defaults are enumerated in bits/84\_defaults.js
### Input Type
@@ -1736,17 +1410,16 @@ tells the library how to parse the data argument:
| `type` | expected input |
|------------|-----------------------------------------------------------------|
-| `"base64"` | string: Base64 encoding of the file |
-| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
-| `"string"` | string: JS string (characters interpreted as UTF8) |
+| `"base64"` | string: base64 encoding of the file |
+| `"binary"` | string: binary string (`n`-th byte is `data.charCodeAt(n)`) |
| `"buffer"` | nodejs Buffer |
-| `"array"` | array: array of 8-bit unsigned int (byte `n` is `data[n]`) |
-| `"file"` | string: path of file that will be read (nodejs only) |
+| `"array"` | array: array of 8-bit unsigned int (`n`-th byte is `data[n]`) |
+| `"file"` | string: filename that will be read and processed (nodejs only) |
### Guessing File Type
- Implementation Details (click to show)
+ Implementation Details (click to show)
Excel and other spreadsheet tools read the first few bytes and apply other
heuristics to determine a file type. This enables file type punning: renaming
@@ -1757,42 +1430,31 @@ file but Excel will know how to handle it. This library applies similar logic:
|:-------|:--------------|:----------------------------------------------------|
| `0xD0` | CFB Container | BIFF 5/8 or password-protected XLSX/XLSB or WQ3/QPW |
| `0x09` | BIFF Stream | BIFF 2/3/4/5 |
-| `0x3C` | XML/HTML | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
-| `0x50` | ZIP Archive | XLSB or XLSX/M or ODS or UOS2 or plain text |
-| `0x49` | Plain Text | SYLK or plain text |
-| `0x54` | Plain Text | DIF or plain text |
-| `0xEF` | UTF8 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
-| `0xFF` | UTF16 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
-| `0x00` | Record Stream | Lotus WK\* or Quattro Pro or plain text |
-| `0x7B` | Plain text | RTF or plain text |
-| `0x0A` | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
-| `0x0D` | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
-| `0x20` | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
+| `0x3C` | XML/HTML | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext |
+| `0x50` | ZIP Archive | XLSB or XLSX/M or ODS or UOS2 or plaintext |
+| `0x49` | Plain Text | SYLK or plaintext |
+| `0x54` | Plain Text | DIF or plaintext |
+| `0xFE` | UTF16 Encoded | SpreadsheetML or Flat ODS or UOS1 or plaintext |
+| `0x00` | Record Stream | Lotus WK\* or Quattro Pro or plaintext |
DBF files are detected based on the first byte as well as the third and fourth
bytes (corresponding to month and day of the file date)
-Plain text format guessing follows the priority order:
+Plaintext format guessing follows the priority order:
| Format | Test |
|:-------|:--------------------------------------------------------------------|
-| XML | `
- Why are random text files valid? (click to show)
+ Why are random text files valid? (click to show)
Excel is extremely aggressive in reading files. Adding an XLS extension to any
display text file (where the only characters are ANSI display chars) tricks
@@ -1804,7 +1466,7 @@ expected number of rows or columns. Extracting the range is extremely simple:
```js
var range = XLSX.utils.decode_range(worksheet['!ref']);
-var ncols = range.e.c - range.s.c + 1, nrows = range.e.r - range.s.r + 1;
+var ncols = range.e.c - range.r.c + 1, nrows = range.e.r - range.s.r + 1;
```
@@ -1815,15 +1477,14 @@ The exported `write` and `writeFile` functions accept an options argument:
| Option Name | Default | Description |
| :---------- | -------: | :-------------------------------------------------- |
-|`type` | | Output data encoding (see Output Type below) |
-|`cellDates` | `false` | Store dates as type `d` (default is `n`) |
-|`bookSST` | `false` | Generate Shared String Table ** |
-|`bookType` | `"xlsx"` | Type of Workbook (see below for supported formats) |
-|`sheet` | `""` | Name of Worksheet for single-sheet formats ** |
-|`compression`| `false` | Use ZIP compression for ZIP-based formats ** |
-|`Props` | | Override workbook properties when writing ** |
-|`themeXLSX` | | Override theme XML when writing XLSX/XLSB/XLSM ** |
-|`ignoreEC` | `true` | Suppress "number as text" errors ** |
+| type | | Output data encoding (see Output Type below) |
+| cellDates | `false` | Store dates as type `d` (default is `n`) |
+| bookSST | `false` | Generate Shared String Table ** |
+| bookType | `"xlsx"` | Type of Workbook (see below for supported formats) |
+| sheet | `""` | Name of Worksheet for single-sheet formats ** |
+| compression | `false` | Use ZIP compression for ZIP-based formats ** |
+| Props | | Override workbook properties when writing ** |
+| themeXLSX | | Override theme XML when writing XLSX/XLSB/XLSM ** |
- `bookSST` is slower and more memory intensive, but has better compatibility
with older versions of iOS Numbers
@@ -1831,40 +1492,32 @@ The exported `write` and `writeFile` functions accept an options argument:
in this README may not be serialized.
- `cellDates` only applies to XLSX output and is not guaranteed to work with
third-party readers. Excel itself does not usually write cells with type `d`
- so non-Excel tools may ignore the data or error in the presence of dates.
+ so non-Excel tools may ignore the data or blow up in the presence of dates.
- `Props` is an object mirroring the workbook `Props` field. See the table from
the [Workbook File Properties](#workbook-file-properties) section.
- if specified, the string from `themeXLSX` will be saved as the primary theme
for XLSX/XLSB/XLSM files (to `xl/theme/theme1.xml` in the ZIP)
-- Due to a bug in the program, some features like "Text to Columns" will crash
- Excel on worksheets where error conditions are ignored. The writer will mark
- files to ignore the error by default. Set `ignoreEC` to `false` to suppress.
### Supported Output Formats
For broad compatibility with third-party tools, this library supports many
output formats. The specific file type is controlled with `bookType` option:
-| `bookType` | file ext | container | sheets | Description |
-| :--------- | -------: | :-------: | :----- |:------------------------------- |
-| `xlsx` | `.xlsx` | ZIP | multi | Excel 2007+ XML Format |
-| `xlsm` | `.xlsm` | ZIP | multi | Excel 2007+ Macro XML Format |
-| `xlsb` | `.xlsb` | ZIP | multi | Excel 2007+ Binary Format |
-| `biff8` | `.xls` | CFB | multi | Excel 97-2004 Workbook Format |
-| `biff5` | `.xls` | CFB | multi | Excel 5.0/95 Workbook Format |
-| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
-| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
-| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
-| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
-| `csv` | `.csv` | none | single | Comma Separated Values |
-| `txt` | `.txt` | none | single | UTF-16 Unicode Text (TXT) |
-| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
-| `html` | `.html` | none | single | HTML Document |
-| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
-| `dbf` | `.dbf` | none | single | dBASE II + VFP Extensions (DBF) |
-| `rtf` | `.rtf` | none | single | Rich Text Format (RTF) |
-| `prn` | `.prn` | none | single | Lotus Formatted Text |
-| `eth` | `.eth` | none | single | Ethercalc Record Format (ETH) |
+| bookType | file ext | container | sheets | Description |
+| :------- | -------: | :-------: | :----- |:--------------------------------- |
+| `xlsx` | `.xlsx` | ZIP | multi | Excel 2007+ XML Format |
+| `xlsm` | `.xlsm` | ZIP | multi | Excel 2007+ Macro XML Format |
+| `xlsb` | `.xlsb` | ZIP | multi | Excel 2007+ Binary Format |
+| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet format |
+| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
+| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
+| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
+| `csv` | `.csv` | none | single | Comma Separated Values |
+| `txt` | `.txt` | none | single | UTF-16 Unicode Text (TXT) |
+| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
+| `html` | `.html` | none | single | HTML Document |
+| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
+| `prn` | `.prn` | none | single | Lotus Formatted Text |
- `compression` only applies to formats with ZIP containers.
- Formats that only support a single sheet require a `sheet` option specifying
@@ -1879,12 +1532,11 @@ The `type` argument for `write` mirrors the `type` argument for `read`:
| `type` | output |
|------------|-----------------------------------------------------------------|
-| `"base64"` | string: Base64 encoding of the file |
-| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
-| `"string"` | string: JS string (characters interpreted as UTF8) |
+| `"base64"` | string: base64 encoding of the file |
+| `"binary"` | string: binary string (`n`-th byte is `data.charCodeAt(n)`) |
| `"buffer"` | nodejs Buffer |
-| `"array"` | ArrayBuffer, fallback array of 8-bit unsigned int |
-| `"file"` | string: path of file that will be created (nodejs only) |
+| `"file"` | string: name of file to be written (nodejs only) |
+
## Utility Functions
@@ -1912,180 +1564,41 @@ other values are stored as strings. The function takes an options argument:
| Option Name | Default | Description |
| :---------- | :------: | :-------------------------------------------------- |
-|`dateNF` | FMT 14 | Use specified date format in string output |
-|`cellDates` | false | Store dates as type `d` (default is `n`) |
-|`sheetStubs` | false | Create cell objects of type `z` for `null` values |
+| dateNF | fmt 14 | Use specified date format in string output |
+| cellDates | false | Store dates as type `d` (default is `n`) |
+| sheetStubs | false | Create cell objects of type `z` for `null` values |
- Examples (click to show)
+ Examples (click to show)
To generate the example sheet:
```js
var ws = XLSX.utils.aoa_to_sheet([
- "SheetJS".split(""),
- [1,2,3,4,5,6,7],
- [2,3,4,5,6,7,8]
+ "SheetJS".split(""),
+ [1,2,3,4,5,6,7],
+ [2,3,4,5,6,7,8]
]);
```
-`XLSX.utils.sheet_add_aoa` takes an array of arrays of JS values and updates an
-existing worksheet object. It follows the same process as `aoa_to_sheet` and
-accepts an options argument:
-
-| Option Name | Default | Description |
-| :---------- | :------: | :-------------------------------------------------- |
-|`dateNF` | FMT 14 | Use specified date format in string output |
-|`cellDates` | false | Store dates as type `d` (default is `n`) |
-|`sheetStubs` | false | Create cell objects of type `z` for `null` values |
-|`origin` | | Use specified cell as starting point (see below) |
-
-`origin` is expected to be one of:
-
-| `origin` | Description |
-| :--------------- | :-------------------------------------------------------- |
-| (cell object) | Use specified cell (cell object) |
-| (string) | Use specified cell (A1-style cell) |
-| (number >= 0) | Start from the first column at specified row (0-indexed) |
-| -1 | Append to bottom of worksheet starting on first column |
-| (default) | Start from cell A1 |
-
-
-
- Examples (click to show)
-
-Consider the worksheet:
-
-```
-XXX| A | B | C | D | E | F | G |
----+---+---+---+---+---+---+---+
- 1 | S | h | e | e | t | J | S |
- 2 | 1 | 2 | | | 5 | 6 | 7 |
- 3 | 2 | 3 | | | 6 | 7 | 8 |
- 4 | 3 | 4 | | | 7 | 8 | 9 |
- 5 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
-```
-
-This worksheet can be built up in the order `A1:G1, A2:B4, E2:G4, A5:G5`:
-
-```js
-/* Initial row */
-var ws = XLSX.utils.aoa_to_sheet([ "SheetJS".split("") ]);
-
-/* Write data starting at A2 */
-XLSX.utils.sheet_add_aoa(ws, [[1,2], [2,3], [3,4]], {origin: "A2"});
-
-/* Write data starting at E2 */
-XLSX.utils.sheet_add_aoa(ws, [[5,6,7], [6,7,8], [7,8,9]], {origin:{r:1, c:4}});
-
-/* Append row */
-XLSX.utils.sheet_add_aoa(ws, [[4,5,6,7,8,9,0]], {origin: -1});
-```
-
-
-
### Array of Objects Input
`XLSX.utils.json_to_sheet` takes an array of objects and returns a worksheet
-with automatically-generated "headers" based on the keys of the objects. The
-default column order is determined by the first appearance of the field using
-`Object.keys`, but can be overridden using the options argument:
-
-| Option Name | Default | Description |
-| :---------- | :------: | :-------------------------------------------------- |
-|`header` | | Use specified column order (default `Object.keys`) |
-|`dateNF` | FMT 14 | Use specified date format in string output |
-|`cellDates` | false | Store dates as type `d` (default is `n`) |
-|`skipHeader` | false | If true, do not include header row in output |
+with automatically-generated "headers" based on the keys of the objects.
- Examples (click to show)
+ Examples (click to show)
-The original sheet cannot be reproduced using plain objects since JS object keys
-must be unique. After replacing the second `e` and `S` with `e_1` and `S_1`:
+The original sheet cannot be reproduced because JS object keys must be unique.
+After replacing the second `e` and `S` with `e_1` and `S_1`:
```js
var ws = XLSX.utils.json_to_sheet([
- { S:1, h:2, e:3, e_1:4, t:5, J:6, S_1:7 },
- { S:2, h:3, e:4, e_1:5, t:6, J:7, S_1:8 }
-], {header:["S","h","e","e_1","t","J","S_1"]});
+ {S:1,h:2,e:3,e_1:4,t:5,J:6,S_1:7},
+ {S:2,h:3,e:4,e_1:5,t:6,J:7,S_1:8}
+]);
```
-
-Alternatively, the header row can be skipped:
-
-```js
-var ws = XLSX.utils.json_to_sheet([
- { A:"S", B:"h", C:"e", D:"e", E:"t", F:"J", G:"S" },
- { A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7 },
- { A: 2, B: 3, C: 4, D: 5, E: 6, F: 7, G: 8 }
-], {header:["A","B","C","D","E","F","G"], skipHeader:true});
-```
-
-
-
-`XLSX.utils.sheet_add_json` takes an array of objects and updates an existing
-worksheet object. It follows the same process as `json_to_sheet` and accepts
-an options argument:
-
-| Option Name | Default | Description |
-| :---------- | :------: | :-------------------------------------------------- |
-|`header` | | Use specified column order (default `Object.keys`) |
-|`dateNF` | FMT 14 | Use specified date format in string output |
-|`cellDates` | false | Store dates as type `d` (default is `n`) |
-|`skipHeader` | false | If true, do not include header row in output |
-|`origin` | | Use specified cell as starting point (see below) |
-
-`origin` is expected to be one of:
-
-| `origin` | Description |
-| :--------------- | :-------------------------------------------------------- |
-| (cell object) | Use specified cell (cell object) |
-| (string) | Use specified cell (A1-style cell) |
-| (number >= 0) | Start from the first column at specified row (0-indexed) |
-| -1 | Append to bottom of worksheet starting on first column |
-| (default) | Start from cell A1 |
-
-
-
- Examples (click to show)
-
-Consider the worksheet:
-
-```
-XXX| A | B | C | D | E | F | G |
----+---+---+---+---+---+---+---+
- 1 | S | h | e | e | t | J | S |
- 2 | 1 | 2 | | | 5 | 6 | 7 |
- 3 | 2 | 3 | | | 6 | 7 | 8 |
- 4 | 3 | 4 | | | 7 | 8 | 9 |
- 5 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
-```
-
-This worksheet can be built up in the order `A1:G1, A2:B4, E2:G4, A5:G5`:
-
-```js
-/* Initial row */
-var ws = XLSX.utils.json_to_sheet([
- { A: "S", B: "h", C: "e", D: "e", E: "t", F: "J", G: "S" }
-], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true});
-
-/* Write data starting at A2 */
-XLSX.utils.sheet_add_json(ws, [
- { A: 1, B: 2 }, { A: 2, B: 3 }, { A: 3, B: 4 }
-], {skipHeader: true, origin: "A2"});
-
-/* Write data starting at E2 */
-XLSX.utils.sheet_add_json(ws, [
- { A: 5, B: 6, C: 7 }, { A: 6, B: 7, C: 8 }, { A: 7, B: 8, C: 9 }
-], {skipHeader: true, origin: { r: 1, c: 4 }, header: [ "A", "B", "C" ]});
-
-/* Append row */
-XLSX.utils.sheet_add_json(ws, [
- { A: 4, B: 5, C: 6, D: 7, E: 8, F: 9, G: 0 }
-], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true, origin: -1});
-```
-
### HTML Table Input
@@ -2096,19 +1609,8 @@ as strings.
`XLSX.utils.table_to_book` produces a minimal workbook based on the worksheet.
-Both functions accept options arguments:
-
-| Option Name | Default | Description |
-| :---------- | :------: | :-------------------------------------------------- |
-|`raw` | | If true, every cell will hold raw strings |
-|`dateNF` | FMT 14 | Use specified date format in string output |
-|`cellDates` | false | Store dates as type `d` (default is `n`) |
-|`sheetRows` | 0 | If >0, read the first `sheetRows` rows of the table |
-|`display` | false | If true, hidden rows and cells will not be parsed |
-
-
- Examples (click to show)
+ Examples (click to show)
To generate the example sheet, start with the HTML table:
@@ -2130,56 +1632,6 @@ var wb = XLSX.utils.table_to_book(tbl);
Note: `XLSX.read` can handle HTML represented as strings.
-
-`XLSX.utils.sheet_add_dom` takes a table DOM element and updates an existing
-worksheet object. It follows the same process as `table_to_sheet` and accepts
-an options argument:
-
-| Option Name | Default | Description |
-| :---------- | :------: | :-------------------------------------------------- |
-|`raw` | | If true, every cell will hold raw strings |
-|`dateNF` | FMT 14 | Use specified date format in string output |
-|`cellDates` | false | Store dates as type `d` (default is `n`) |
-|`sheetRows` | 0 | If >0, read the first `sheetRows` rows of the table |
-|`display` | false | If true, hidden rows and cells will not be parsed |
-
-`origin` is expected to be one of:
-
-| `origin` | Description |
-| :--------------- | :-------------------------------------------------------- |
-| (cell object) | Use specified cell (cell object) |
-| (string) | Use specified cell (A1-style cell) |
-| (number >= 0) | Start from the first column at specified row (0-indexed) |
-| -1 | Append to bottom of worksheet starting on first column |
-| (default) | Start from cell A1 |
-
-
-
- Examples (click to show)
-
-A small helper function can create gap rows between tables:
-
-```js
-function create_gap_rows(ws, nrows) {
- var ref = XLSX.utils.decode_range(ws["!ref"]); // get original range
- ref.e.r += nrows; // add to ending row
- ws["!ref"] = XLSX.utils.encode_range(ref); // reassign row
-}
-
-/* first table */
-var ws = XLSX.utils.table_to_sheet(document.getElementById('table1'));
-create_gap_rows(ws, 1); // one row gap after first table
-
-/* second table */
-XLSX.utils.sheet_add_dom(ws, document.getElementById('table2'), {origin: -1});
-create_gap_rows(ws, 3); // three rows gap after second table
-
-/* third table */
-XLSX.utils.sheet_add_dom(ws, document.getElementById('table3'), {origin: -1});
-```
-
-
-
### Formulae Output
`XLSX.utils.sheet_to_formulae` generates an array of commands that represent
@@ -2188,13 +1640,13 @@ how a person would enter data into an application. Each entry is of the form
accordance with Excel.
- Examples (click to show)
+ Examples (click to show)
For the example sheet:
```js
> var o = XLSX.utils.sheet_to_formulae(ws);
-> [o[0], o[5], o[10], o[15], o[20]];
+> o.filter(function(v, i) { return i % 5 === 0; });
[ 'A1=\'S', 'F1=\'J', 'D2=4', 'B3=3', 'G3=8' ]
```
@@ -2204,23 +1656,19 @@ For the example sheet:
As an alternative to the `writeFile` CSV type, `XLSX.utils.sheet_to_csv` also
produces CSV output. The function takes an options argument:
-| Option Name | Default | Description |
-| :----------- | :------: | :------------------------------------------------- |
-|`FS` | `","` | "Field Separator" delimiter between fields |
-|`RS` | `"\n"` | "Record Separator" delimiter between rows |
-|`dateNF` | FMT 14 | Use specified date format in string output |
-|`strip` | false | Remove trailing field separators in each record ** |
-|`blankrows` | true | Include blank lines in the CSV output |
-|`skipHidden` | false | Skips hidden rows/columns in the CSV output |
-|`forceQuotes` | false | Force quotes around fields |
+| Option Name | Default | Description |
+| :---------- | :------: | :-------------------------------------------------- |
+| FS | `","` | "Field Separator" delimiter between fields |
+| RS | `"\n"` | "Record Separator" delimiter between rows |
+| dateNF | fmt 14 | Use specified date format in string output |
+| strip | false | Remove trailing field separators in each record ** |
+| blankrows | true | Include blank lines in the CSV output |
- `strip` will remove trailing commas from each line under default `FS/RS`
-- `blankrows` must be set to `false` to skip blank lines.
-- Fields containing the record or field separator will automatically be wrapped
- in double quotes; `forceQuotes` forces all cells to be wrapped in quotes.
+- blankrows must be set to `false` to skip blank lines.
- Examples (click to show)
+ Examples (click to show)
For the example sheet:
@@ -2241,10 +1689,8 @@ S:h:e:e:t:J:S|1:2:3:4:5:6:7|2:3:4:5:6:7:8|
#### UTF-16 Unicode Text
The `txt` output type uses the tab character as the field separator. If the
-`codepage` library is available (included in full distribution but not core),
-the output will be encoded in `CP1200` and the BOM will be prepended.
-
-`XLSX.utils.sheet_to_txt` takes the same arguments as `sheet_to_csv`.
+codepage library is available (included in the full distribution but not core),
+the output will be encoded in codepage `1200` and the BOM will be prepended.
### HTML Output
@@ -2253,13 +1699,12 @@ produces HTML output. The function takes an options argument:
| Option Name | Default | Description |
| :---------- | :------: | :-------------------------------------------------- |
-|`id` | | Specify the `id` attribute for the `TABLE` element |
-|`editable` | false | If true, set `contenteditable="true"` for every TD |
-|`header` | | Override header (default `html body`) |
-|`footer` | | Override footer (default `/body /html`) |
+| editable | false | If true, set `contenteditable="true"` for every TD |
+| header | | Override header (default `html body`) |
+| footer | | Override footer (default `/body /html`) |
- Examples (click to show)
+ Examples (click to show)
For the example sheet:
@@ -2276,12 +1721,12 @@ takes an options argument:
| Option Name | Default | Description |
| :---------- | :------: | :-------------------------------------------------- |
-|`raw` | `true` | Use raw values (true) or formatted strings (false) |
-|`range` | from WS | Override Range (see table below) |
-|`header` | | Control output format (see table below) |
-|`dateNF` | FMT 14 | Use specified date format in string output |
-|`defval` | | Use specified value in place of null or undefined |
-|`blankrows` | ** | Include blank lines in the output ** |
+| raw | `false` | Use raw values (true) or formatted strings (false) |
+| range | from WS | Override Range (see table below) |
+| header | | Control output format (see table below) |
+| dateNF | fmt 14 | Use specified date format in string output |
+| defval | | Use specified value in place of null or undefined |
+| blankrows | ** | Include blank lines in the output ** |
- `raw` only affects cells which have a format code (`.z`) field or a formatted
text (`.w`) field.
@@ -2296,7 +1741,7 @@ takes an options argument:
- When `header` is `1`, the default is to generate blank rows. `blankrows` must
be set to `false` to skip blank rows.
- When `header` is not `1`, the default is to skip blank rows. `blankrows` must
- be true to generate blank rows
+ be truthy to generate blank rows
`range` is expected to be one of:
@@ -2319,42 +1764,39 @@ If header is not `1`, the row object will contain the non-enumerable property
`__rowNum__` that represents the row of the sheet corresponding to the entry.
- Examples (click to show)
+ Examples (click to show)
For the example sheet:
```js
-> XLSX.utils.sheet_to_json(ws);
+> console.log(XLSX.utils.sheet_to_json(ws));
[ { S: 1, h: 2, e: 3, e_1: 4, t: 5, J: 6, S_1: 7 },
{ S: 2, h: 3, e: 4, e_1: 5, t: 6, J: 7, S_1: 8 } ]
-> XLSX.utils.sheet_to_json(ws, {header:"A"});
-[ { A: 'S', B: 'h', C: 'e', D: 'e', E: 't', F: 'J', G: 'S' },
- { A: '1', B: '2', C: '3', D: '4', E: '5', F: '6', G: '7' },
- { A: '2', B: '3', C: '4', D: '5', E: '6', F: '7', G: '8' } ]
-
-> XLSX.utils.sheet_to_json(ws, {header:["A","E","I","O","U","6","9"]});
-[ { '6': 'J', '9': 'S', A: 'S', E: 'h', I: 'e', O: 'e', U: 't' },
- { '6': '6', '9': '7', A: '1', E: '2', I: '3', O: '4', U: '5' },
- { '6': '7', '9': '8', A: '2', E: '3', I: '4', O: '5', U: '6' } ]
-
-> XLSX.utils.sheet_to_json(ws, {header:1});
+> console.log(XLSX.utils.sheet_to_json(ws, {header:1}));
[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
[ '1', '2', '3', '4', '5', '6', '7' ],
[ '2', '3', '4', '5', '6', '7', '8' ] ]
+
+> console.log(XLSX.utils.sheet_to_json(ws, {header:"A"}));
+[ { A: 'S', B: 'h', C: 'e', D: 'e', E: 't', F: 'J', G: 'S' },
+ { A: '1', B: '2', C: '3', D: '4', E: '5', F: '6', G: '7' },
+ { A: '2', B: '3', C: '4', D: '5', E: '6', F: '7', G: '8' } ]
+> console.log(XLSX.utils.sheet_to_json(ws, {header:["A","E","I","O","U","6","9"]}));
+[ { '6': 'J', '9': 'S', A: 'S', E: 'h', I: 'e', O: 'e', U: 't' },
+ { '6': '6', '9': '7', A: '1', E: '2', I: '3', O: '4', U: '5' },
+ { '6': '7', '9': '8', A: '2', E: '3', I: '4', O: '5', U: '6' } ]
```
Example showing the effect of `raw`:
```js
> ws['A2'].w = "3"; // set A2 formatted string value
-
-> XLSX.utils.sheet_to_json(ws, {header:1, raw:false});
+> console.log(XLSX.utils.sheet_to_json(ws, {header:1}));
[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
[ '3', '2', '3', '4', '5', '6', '7' ], // <-- A2 uses the formatted string
[ '2', '3', '4', '5', '6', '7', '8' ] ]
-
-> XLSX.utils.sheet_to_json(ws, {header:1});
+> console.log(XLSX.utils.sheet_to_json(ws, {header:1, raw:true}));
[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
[ 1, 2, 3, 4, 5, 6, 7 ], // <-- A2 uses the raw value
[ 2, 3, 4, 5, 6, 7, 8 ] ]
@@ -2371,8 +1813,8 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Excel 2007+ XML Formats (XLSX/XLSM) | :o: | :o: |
| Excel 2007+ Binary Format (XLSB BIFF12) | :o: | :o: |
| Excel 2003-2004 XML Format (XML "SpreadsheetML") | :o: | :o: |
-| Excel 97-2004 (XLS BIFF8) | :o: | :o: |
-| Excel 5.0/95 (XLS BIFF5) | :o: | :o: |
+| Excel 97-2004 (XLS BIFF8) | :o: | |
+| Excel 5.0/95 (XLS BIFF5) | :o: | |
| Excel 4.0 (XLS/XLW BIFF4) | :o: | |
| Excel 3.0 (XLS BIFF3) | :o: | |
| Excel 2.0/2.1 (XLS BIFF2) | :o: | :o: |
@@ -2386,35 +1828,19 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| OpenDocument Spreadsheet (ODS) | :o: | :o: |
| Flat XML ODF Spreadsheet (FODS) | :o: | :o: |
| Uniform Office Format Spreadsheet (标文通 UOS1/UOS2) | :o: | |
-| dBASE II/III/IV / Visual FoxPro (DBF) | :o: | :o: |
+| dBASE II/III/IV / Visual FoxPro (DBF) | :o: | |
| Lotus 1-2-3 (WKS/WK1/WK2/WK3/WK4/123) | :o: | |
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | :o: | |
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
| HTML Tables | :o: | :o: |
-| Rich Text Format tables (RTF) | | :o: |
-| Ethercalc Record Format (ETH) | :o: | :o: |
-
-Features not supported by a given file format will not be written. Formats with
-range limits will be silently truncated:
-
-| Format | Last Cell | Max Cols | Max Rows |
-|:------------------------------------------|:-----------|---------:|---------:|
-| Excel 2007+ XML Formats (XLSX/XLSM) | XFD1048576 | 16384 | 1048576 |
-| Excel 2007+ Binary Format (XLSB BIFF12) | XFD1048576 | 16384 | 1048576 |
-| Excel 97-2004 (XLS BIFF8) | IV65536 | 256 | 65536 |
-| Excel 5.0/95 (XLS BIFF5) | IV16384 | 256 | 16384 |
-| Excel 2.0/2.1 (XLS BIFF2) | IV16384 | 256 | 16384 |
-
-Excel 2003 SpreadsheetML range limits are governed by the version of Excel and
-are not enforced by the writer.
### Excel 2007+ XML (XLSX/XLSM)
- (click to show)
+ (click to show)
XLSX and XLSM files are ZIP containers containing a series of XML files in
-accordance with the Open Packaging Conventions (OPC). The XLSM format, almost
+accordance with the Open Packaging Conventions (OPC). The XLSM filetype, almost
identical to XLSX, is used for files containing macros.
The format is standardized in ECMA-376 and later in ISO/IEC 29500. Excel does
@@ -2426,7 +1852,7 @@ Excel deviates from the specification.
### Excel 2.0-95 (BIFF2/BIFF3/BIFF4/BIFF5)
- (click to show)
+ (click to show)
BIFF 2/3 XLS are single-sheet streams of binary records. Excel 4 introduced
the concept of a workbook (`XLW` files) but also had single-sheet `XLS` format.
@@ -2434,7 +1860,7 @@ The structure is largely similar to the Lotus 1-2-3 file formats. BIFF5/8/12
extended the format in various ways but largely stuck to the same record format.
There is no official specification for any of these formats. Excel 95 can write
-files in these formats, so record lengths and fields were determined by writing
+files in these formats, so record lengths and fields were backsolved by writing
in all of the supported formats and comparing files. Excel 2016 can generate
BIFF5 files, enabling a full suite of file tests starting from XLSX or BIFF2.
@@ -2443,7 +1869,7 @@ BIFF5 files, enabling a full suite of file tests starting from XLSX or BIFF2.
### Excel 97-2004 Binary (BIFF8)
- (click to show)
+ (click to show)
BIFF8 exclusively uses the Compound File Binary container format, splitting some
content into streams within the file. At its core, it still uses an extended
@@ -2457,11 +1883,11 @@ specifications expand on serialization of features like properties.
### Excel 2003-2004 (SpreadsheetML)
- (click to show)
+ (click to show)
Predating XLSX, SpreadsheetML files are simple XML files. There is no official
-and comprehensive specification, although MS has released documentation on the
-format. Since Excel 2016 can generate SpreadsheetML files, mapping features is
+and comprehensive specification, although MS has released whitepapers on the
+format. Since Excel 2016 can generate SpreadsheetML files, backsolving is
pretty straightforward.
@@ -2469,9 +1895,9 @@ pretty straightforward.
### Excel 2007+ Binary (XLSB, BIFF12)
- (click to show)
+ (click to show)
-Introduced in parallel with XLSX, the XLSB format combines the BIFF architecture
+Introduced in parallel with XLSX, the XLSB filetype combines BIFF architecture
with the content separation and ZIP container of XLSX. For the most part nodes
in an XLSX sub-file can be mapped to XLSB records in a corresponding sub-file.
@@ -2483,29 +1909,21 @@ specifications expand on serialization of features like properties.
### Delimiter-Separated Values (CSV/TXT)
- (click to show)
+ (click to show)
Excel CSV deviates from RFC4180 in a number of important ways. The generated
CSV files should generally work in Excel although they may not work in RFC4180
compatible readers. The parser should generally understand Excel CSV. The
writer proactively generates cells for formulae if values are unavailable.
-Excel TXT uses tab as the delimiter and code page 1200.
-
-Notes:
-
-- Like in Excel, files starting with `0x49 0x44 ("ID")` are treated as Symbolic
- Link files. Unlike Excel, if the file does not have a valid SYLK header, it
- will be proactively reinterpreted as CSV. There are some files with semicolon
- delimiter that align with a valid SYLK file. For the broadest compatibility,
- all cells with the value of `ID` are automatically wrapped in double-quotes.
+Excel TXT uses tab as the delimiter and codepage 1200.
### Other Workbook Formats
- (click to show)
+ (click to show)
Support for other formats is generally far XLS/XLSB/XLSX support, due in large
part to a lack of publicly available documentation. Test files were produced in
@@ -2517,10 +1935,10 @@ The main focus is data extraction.
#### Lotus 1-2-3 (WKS/WK1/WK2/WK3/WK4/123)
- (click to show)
+ (click to show)
The Lotus formats consist of binary records similar to the BIFF structure. Lotus
-did release a specification decades ago covering the original WK1 format. Other
+did release a whitepaper decades ago covering the original WK1 format. Other
features were deduced by producing files and comparing to Excel support.
@@ -2528,7 +1946,7 @@ features were deduced by producing files and comparing to Excel support.
#### Quattro Pro (WQ1/WQ2/WB1/WB2/WB3/QPW)
- (click to show)
+ (click to show)
The Quattro Pro formats use binary records in the same way as BIFF and Lotus.
Some of the newer formats (namely WB3 and QPW) use a CFB enclosure just like
@@ -2539,7 +1957,7 @@ BIFF8 XLS.
#### OpenDocument Spreadsheet (ODS/FODS)
- (click to show)
+ (click to show)
ODS is an XML-in-ZIP format akin to XLSX while FODS is an XML format akin to
SpreadsheetML. Both are detailed in the OASIS standard, but tools like LO/OO
@@ -2551,11 +1969,11 @@ standard, instead focusing on parts necessary to extract and store raw data.
#### Uniform Office Spreadsheet (UOS1/2)
- (click to show)
+ (click to show)
UOS is a very similar format, and it comes in 2 varieties corresponding to ODS
and FODS respectively. For the most part, the difference between the formats
-is in the names of tags and attributes.
+lies in the names of tags and attributes.
@@ -2566,23 +1984,21 @@ Many older formats supported only one worksheet:
#### dBASE and Visual FoxPro (DBF)
- (click to show)
+ (click to show)
DBF is really a typed table format: each column can only hold one data type and
each record omits type information. The parser generates a header row and
-inserts records starting at the second row of the worksheet. The writer makes
-files compatible with Visual FoxPro extensions.
+inserts records starting at the second row of the worksheet.
Multi-file extensions like external memos and tables are currently unsupported,
-limited by the general ability to read arbitrary files in the web browser. The
-reader understands DBF Level 7 extensions like DATETIME.
+limited by the general ability to read arbitrary files in the web browser.
#### Symbolic Link (SYLK)
- (click to show)
+ (click to show)
There is no real documentation. All knowledge was gathered by saving files in
various versions of Excel to deduce the meaning of fields. Notes:
@@ -2595,18 +2011,18 @@ various versions of Excel to deduce the meaning of fields. Notes:
#### Lotus Formatted Text (PRN)
- (click to show)
+ (click to show)
There is no real documentation, and in fact Excel treats PRN as an output-only
file format. Nevertheless we can guess the column widths and reverse-engineer
-the original layout. Excel's 240 character width limitation is not enforced.
+the original layout. Excel's 240-character width limitation is not enforced.
#### Data Interchange Format (DIF)
- (click to show)
+ (click to show)
There is no unified definition. Visicalc DIF differs from Lotus DIF, and both
differ from Excel DIF. Where ambiguous, the parser/writer follows the expected
@@ -2624,50 +2040,24 @@ behavior from Excel. In particular, Excel extends DIF in incompatible ways:
#### HTML
- (click to show)
+ (click to show)
Excel HTML worksheets include special metadata encoded in styles. For example,
`mso-number-format` is a localized string containing the number format. Despite
the metadata the output is valid HTML, although it does accept bare `&` symbols.
-The writer adds type metadata to the TD elements via the `t` tag. The parser
-looks for those tags and overrides the default interpretation. For example, text
-like `12345 | ` will be parsed as numbers but `12345 | ` will
-be parsed as text.
-
-#### Rich Text Format (RTF)
-
-
- (click to show)
-
-Excel RTF worksheets are stored in clipboard when copying cells or ranges from a
-worksheet. The supported codes are a subset of the Word RTF support.
-
-
-
-#### Ethercalc Record Format (ETH)
-
-
- (click to show)
-
-[Ethercalc](https://ethercalc.net/) is an open source web spreadsheet powered by
-a record format reminiscent of SYLK wrapped in a MIME multi-part message.
-
-
-
-
## Testing
### Node
- (click to show)
+ (click to show)
`make test` will run the node-based tests. By default it runs tests on files in
every supported format. To test a specific file type, set `FMTS` to the format
-you want to test. Feature-specific tests are available with `make test_misc`
+you want to test. Feature-specific tests are avaialble with `make test_misc`
```bash
$ make test_misc # run core tests
@@ -2686,12 +2076,11 @@ $ make test # run full tests
$ WTF=1 make test # enable all error messages
```
-`flow` and `eslint` checks are available:
+Flow and eslint checks are available:
```bash
$ make lint # eslint checks
$ make flow # make lint + Flow checking
-$ make tslint # check TS definitions
```
@@ -2699,7 +2088,7 @@ $ make tslint # check TS definitions
### Browser
- (click to show)
+ (click to show)
The core in-browser tests are available at `tests/index.html` within this repo.
Start a local server and navigate to that directory to run the tests.
@@ -2709,8 +2098,8 @@ Start a local server and navigate to that directory to run the tests.
`tests/fixtures.lst` file and add the paths.
To run the full in-browser tests, clone the repo for
-[`oss.sheetjs.com`](https://github.com/SheetJS/SheetJS.github.io) and replace
-the `xlsx.js` file (then open a browser window and go to `stress.html`):
+[oss.sheetjs.com](https://github.com/SheetJS/SheetJS.github.io) and replace
+the xlsx.js file (then fire up the browser and go to `stress.html`):
```bash
$ cp xlsx.js ../SheetJS.github.io
@@ -2723,25 +2112,21 @@ $ open -a Chromium.app http://localhost:8000/stress.html
### Tested Environments
- (click to show)
+ (click to show)
- - NodeJS `0.8`, `0.10`, `0.12`, `4.x`, `5.x`, `6.x`, `7.x`, `8.x`
- - IE 6/7/8/9/10/11 (IE 6-9 require shims)
- - Chrome 24+ (including Android 4.0+)
- - Safari 6+ (iOS and Desktop)
- - Edge 13+, FF 18+, and Opera 12+
+ - NodeJS 0.8, 0.9, 0.10, 0.11, 0.12, 4.x, 5.x, 6.x, 7.x
+ - IE 6/7/8/9/10/11 (IE6-9 browsers require shims for interacting with client)
+ - Chrome 24+
+ - Safari 6+
+ - FF 18+
-Tests utilize the mocha testing framework.
+Tests utilize the mocha testing framework. Travis-CI and Sauce Labs links:
+ - for XLSX module in nodejs
+ - for XLSX module in nodejs
+ - for XLS\* modules
- for XLS\* modules using Sauce Labs
-The test suite also includes tests for various time zones. To change
-the timezone locally, set the TZ environment variable:
-
-```bash
-$ env TZ="Asia/Kolkata" WTF=1 make test_misc
-```
-
### Test Files
@@ -2754,7 +2139,7 @@ available. If `make init` fails, please download the latest version of the test
files snapshot from [the repo](https://github.com/SheetJS/test_files/releases)
- Latest Snapshot (click to show)
+ Latest Snapshot (click to show)
Latest test files snapshot:
@@ -2766,10 +2151,10 @@ Latest test files snapshot:
## Contributing
Due to the precarious nature of the Open Specifications Promise, it is very
-important to ensure code is cleanroom. [Contribution Notes](CONTRIBUTING.md)
+important to ensure code is cleanroom. Consult CONTRIBUTING.md
- File organization (click to show)
+ File organization (click to show)
At a high level, the final script is a concatenation of the individual files in
the `bits` folder. Running `make` should reproduce the final output on all
@@ -2780,7 +2165,7 @@ Folders:
| folder | contents |
|:-------------|:--------------------------------------------------------------|
| `bits` | raw source files that make up the final script |
-| `docbits` | raw markdown files that make up `README.md` |
+| `docbits` | raw markdown files that make up README.md |
| `bin` | server-side bin scripts (`xlsx.njs`) |
| `dist` | dist files for web browsers and nonstandard JS environments |
| `demos` | demo projects for platforms like ExtendScript and Webpack |
@@ -2796,12 +2181,12 @@ After cloning the repo, running `make help` will display a list of commands.
### OSX/Linux
- (click to show)
+ (click to show)
-The `xlsx.js` file is constructed from the files in the `bits` subdirectory. The
+The xlsx.js file is constructed from the files in the `bits` subdirectory. The
build script (run `make`) will concatenate the individual bits to produce the
script. Before submitting a contribution, ensure that running make will produce
-the `xlsx.js` file exactly. The simplest way to test is to add the script:
+the xlsx.js file exactly. The simplest way to test is to add the script:
```bash
$ git add xlsx.js
@@ -2817,7 +2202,7 @@ version release and *should not be committed between versions*.
### Windows
- (click to show)
+ (click to show)
The included `make.cmd` script will build `xlsx.js` from the `bits` directory.
Building is as simple as:
@@ -2826,7 +2211,7 @@ Building is as simple as:
> make
```
-To prepare development environment:
+To prepare dev environment:
```cmd
> make init
@@ -2843,28 +2228,12 @@ make book -- rebuild README and summary
make help -- display this message
```
-As explained in [Test Files](#test-files), on Windows the release ZIP file must
-be downloaded and extracted. If Bash on Windows is available, it is possible
-to run the OSX/Linux workflow. The following steps prepares the environment:
-
-```bash
-# Install support programs for the build and test commands
-sudo apt-get install make git subversion mercurial
-
-# Install nodejs and NPM within the WSL
-wget -qO- https://deb.nodesource.com/setup_8.x | sudo bash
-sudo apt-get install nodejs
-
-# Install dev dependencies
-sudo npm install -g mocha voc blanket xlsjs
-```
-
### Tests
- (click to show)
+ (click to show)
The `test_misc` target (`make test_misc` on Linux/OSX / `make misc` on Windows)
runs the targeted feature tests. It should take 5-10 seconds to perform feature
@@ -2873,8 +2242,8 @@ accompanied with tests for the relevant file formats and features.
For tests involving the read side, an appropriate feature test would involve
reading an existing file and checking the resulting workbook object. If a
-parameter is involved, files should be read with different values to verify that
-the feature is working as expected.
+parameter is involved, files should be read with different values for the param
+to verify that the feature is working as expected.
For tests involving a new write feature which can already be parsed, appropriate
feature tests would involve writing a workbook with the feature and then opening
@@ -2893,31 +2262,31 @@ granted by the Apache 2.0 License are reserved by the Original Author.
## References
- OSP-covered Specifications (click to show)
+ OSP-covered Specifications (click to show)
- - `MS-CFB`: Compound File Binary File Format
- - `MS-CTXLS`: Excel Custom Toolbar Binary File Format
- - `MS-EXSPXML3`: Excel Calculation Version 2 Web Service XML Schema
- - `MS-ODATA`: Open Data Protocol (OData)
- - `MS-ODRAW`: Office Drawing Binary File Format
- - `MS-ODRAWXML`: Office Drawing Extensions to Office Open XML Structure
- - `MS-OE376`: Office Implementation Information for ECMA-376 Standards Support
- - `MS-OFFCRYPTO`: Office Document Cryptography Structure
- - `MS-OI29500`: Office Implementation Information for ISO/IEC 29500 Standards Support
- - `MS-OLEDS`: Object Linking and Embedding (OLE) Data Structures
- - `MS-OLEPS`: Object Linking and Embedding (OLE) Property Set Data Structures
- - `MS-OODF3`: Office Implementation Information for ODF 1.2 Standards Support
- - `MS-OSHARED`: Office Common Data Types and Objects Structures
- - `MS-OVBA`: Office VBA File Format Structure
- - `MS-XLDM`: Spreadsheet Data Model File Format
- - `MS-XLS`: Excel Binary File Format (.xls) Structure Specification
- - `MS-XLSB`: Excel (.xlsb) Binary File Format
- - `MS-XLSX`: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Format
- - `XLS`: Microsoft Office Excel 97-2007 Binary File Format Specification
- - `RTF`: Rich Text Format
+ - [MS-XLSB]: Excel (.xlsb) Binary File Format
+ - [MS-XLSX]: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Format
+ - [MS-OE376]: Office Implementation Information for ECMA-376 Standards Support
+ - [MS-CFB]: Compound File Binary File Format
+ - [MS-XLS]: Excel Binary File Format (.xls) Structure Specification
+ - [MS-ODATA]: Open Data Protocol (OData)
+ - [MS-OFFCRYPTO]: Office Document Cryptography Structure
+ - [MS-OLEDS]: Object Linking and Embedding (OLE) Data Structures
+ - [MS-OLEPS]: Object Linking and Embedding (OLE) Property Set Data Structures
+ - [MS-OSHARED]: Office Common Data Types and Objects Structures
+ - [MS-ODRAW]: Office Drawing Binary File Format
+ - [MS-ODRAWXML]: Office Drawing Extensions to Office Open XML Structure
+ - [MS-OVBA]: Office VBA File Format Structure
+ - [MS-CTXLS]: Excel Custom Toolbar Binary File Format
+ - [MS-XLDM]: Spreadsheet Data Model File Format
+ - [MS-EXSPXML3]: Excel Calculation Version 2 Web Service XML Schema
+ - [XLS]: Microsoft Office Excel 97-2007 Binary File Format Specification
+ - [MS-OI29500]: Office Implementation Information for ISO/IEC 29500 Standards Support
- ISO/IEC 29500:2012(E) "Information technology — Document description and processing languages — Office Open XML File Formats"
- Open Document Format for Office Applications Version 1.2 (29 September 2011)
- Worksheet File Format (From Lotus) December 1984
+
+
diff --git a/bin/xlsx.njs b/bin/xlsx.njs
index 6a264fa..82d7330 100755
--- a/bin/xlsx.njs
+++ b/bin/xlsx.njs
@@ -1,10 +1,9 @@
#!/usr/bin/env node
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* eslint-env node */
-/* vim: set ts=2 ft=javascript: */
var n = "xlsx";
+/* vim: set ts=2 ft=javascript: */
var X = require('../');
-try { X = require('../xlsx.flow'); } catch(e) {}
require('exit-on-epipe');
var fs = require('fs'), program = require('commander');
program
@@ -20,44 +19,31 @@ program
.option('-B, --xlsb', 'emit XLSB to or .xlsb')
.option('-M, --xlsm', 'emit XLSM to or .xlsm')
.option('-X, --xlsx', 'emit XLSX to or .xlsx')
- .option('-I, --xlam', 'emit XLAM to or .xlam')
.option('-Y, --ods', 'emit ODS to or .ods')
- .option('-8, --xls', 'emit XLS to or .xls (BIFF8)')
- .option('-5, --biff5','emit XLS to or .xls (BIFF5)')
- //.option('-4, --biff4','emit XLS to or .xls (BIFF4)')
- //.option('-3, --biff3','emit XLS to or .xls (BIFF3)')
.option('-2, --biff2','emit XLS to or .xls (BIFF2)')
- .option('-i, --xla', 'emit XLA to or .xla')
.option('-6, --xlml', 'emit SSML to or .xls (2003 XML)')
.option('-T, --fods', 'emit FODS to or .fods (Flat ODS)')
- .option('-S, --formulae', 'emit list of values and formulae')
- .option('-j, --json', 'emit formatted JSON (all fields text)')
- .option('-J, --raw-js', 'emit raw JS object (raw numbers)')
- .option('-A, --arrays', 'emit rows as JS objects (raw numbers)')
- .option('-H, --html', 'emit HTML to or .html')
- .option('-D, --dif', 'emit DIF to or .dif (Lotus DIF)')
- .option('-U, --dbf', 'emit DBF to or .dbf (MSVFP DBF)')
- .option('-K, --sylk', 'emit SYLK to or .slk (Excel SYLK)')
- .option('-P, --prn', 'emit PRN to or .prn (Lotus PRN)')
- .option('-E, --eth', 'emit ETH to or .eth (Ethercalc)')
- .option('-t, --txt', 'emit TXT to or .txt (UTF-8 TSV)')
- .option('-r, --rtf', 'emit RTF to or .txt (Table RTF)')
- .option('-z, --dump', 'dump internal representation as JSON')
- .option('--props', 'dump workbook properties as CSV')
+ .option('-S, --formulae', 'print formulae')
+ .option('-j, --json', 'emit formatted JSON (all fields text)')
+ .option('-J, --raw-js', 'emit raw JS object (raw numbers)')
+ .option('-A, --arrays', 'emit rows as JS objects (raw numbers)')
+ .option('-H, --html', 'emit HTML')
+ .option('-D, --dif', 'emit data interchange format (dif)')
+ .option('-K, --sylk', 'emit symbolic link (sylk)')
+ .option('-P, --prn', 'emit formatted text (prn)')
+ .option('-t, --txt', 'emit delimited text (txt)')
.option('-F, --field-sep ', 'CSV field separator', ",")
.option('-R, --row-sep ', 'CSV row separator', "\n")
.option('-n, --sheet-rows ', 'Number of rows to process (0=all rows)')
- .option('--codepage ', 'default to specified codepage when ambiguous')
- .option('--req ', 'require module before processing')
.option('--sst', 'generate shared string table for XLS* formats')
.option('--compress', 'use compression when writing XLSX/M/B and ODS')
- .option('--read', 'read but do not generate output')
- .option('--book', 'for single-sheet formats, emit a file per worksheet')
+ .option('--read-only', 'do not generate output')
.option('--all', 'parse everything; write as much as possible')
.option('--dev', 'development mode')
.option('--sparse', 'sparse mode')
+ .option('--read', 'read but do not print out contents')
.option('-q, --quiet', 'quiet mode');
program.on('--help', function() {
@@ -66,24 +52,15 @@ program.on('--help', function() {
console.log(' Web Demo: http://oss.sheetjs.com/js-'+n+'/');
});
+/* output formats, update list with full option name */
+var workbook_formats = ['xlsx', 'xlsm', 'xlsb', 'ods', 'fods'];
/* flag, bookType, default ext */
-var workbook_formats = [
- ['xlsx', 'xlsx', 'xlsx'],
- ['xlsm', 'xlsm', 'xlsm'],
- ['xlam', 'xlam', 'xlam'],
- ['xlsb', 'xlsb', 'xlsb'],
- ['xls', 'xls', 'xls'],
- ['xla', 'xla', 'xla'],
- ['biff5', 'biff5', 'xls'],
- ['ods', 'ods', 'ods'],
- ['fods', 'fods', 'fods']
-];
var wb_formats_2 = [
- ['xlml', 'xlml', 'xls']
+ ['xlml', 'xlml', 'xls']
];
program.parse(process.argv);
-var filename = '', sheetname = '';
+var filename/*:?string*/, sheetname = '';
if(program.args[0]) {
filename = program.args[0];
if(program.args[1]) sheetname = program.args[1];
@@ -95,15 +72,12 @@ if(!filename) {
console.error(n + ": must specify a filename");
process.exit(1);
}
+/*:: if(filename) { */
if(!fs.existsSync(filename)) {
console.error(n + ": " + filename + ": No such file or directory");
process.exit(2);
}
-if(program.req) program.req.split(",").forEach(function(r) {
- require((fs.existsSync(r) || fs.existsSync(r + '.js')) ? require('path').resolve(r) : r);
-});
-
var opts = {}, wb/*:?Workbook*/;
if(program.listSheets) opts.bookSheets = true;
if(program.sheetRows) opts.sheetRows = program.sheetRows;
@@ -115,20 +89,12 @@ function wb_fmt() {
opts.cellNF = true;
if(program.output) sheetname = program.output;
}
-function isfmt(m/*:string*/)/*:boolean*/ {
- if(!program.output) return false;
- var t = m.charAt(0) === "." ? m : "." + m;
- return program.output.slice(-t.length) === t;
-}
-workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
-wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
+workbook_formats.forEach(function(m) { if(program[m]) { wb_fmt(); } });
+wb_formats_2.forEach(function(m) { if(program[m[0]]) { wb_fmt(); } });
if(seen) {
} else if(program.formulae) opts.cellFormula = true;
else opts.cellFormula = false;
-var wopts = ({WTF:opts.WTF, bookSST:program.sst}/*:any*/);
-if(program.compress) wopts.compression = true;
-
if(program.all) {
opts.cellFormula = true;
opts.bookVBA = true;
@@ -137,12 +103,8 @@ if(program.all) {
opts.cellStyles = true;
opts.sheetStubs = true;
opts.cellDates = true;
- wopts.cellStyles = true;
- wopts.sheetStubs = true;
- wopts.bookVBA = true;
}
if(program.sparse) opts.dense = false; else opts.dense = true;
-if(program.codepage) opts.codepage = +program.codepage;
if(program.dev) {
opts.WTF = true;
@@ -156,37 +118,31 @@ if(program.dev) {
process.exit(3);
}
if(program.read) process.exit(0);
-if(!wb) { console.error(n + ": error parsing " + filename + ": empty workbook"); process.exit(0); }
-/*:: if(!wb) throw new Error("unreachable"); */
+
+/*:: if(wb) { */
if(program.listSheets) {
console.log((wb.SheetNames||[]).join("\n"));
process.exit(0);
}
-if(program.dump) {
- console.log(JSON.stringify(wb));
- process.exit(0);
-}
-if(program.props) {
- if(wb) dump_props(wb);
- process.exit(0);
-}
+
+var wopts = ({WTF:opts.WTF, bookSST:program.sst}/*:any*/);
+if(program.compress) wopts.compression = true;
/* full workbook formats */
-workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
- wopts.bookType = m[1];
- if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
+workbook_formats.forEach(function(m) { if(program[m]) {
+ X.writeFile(wb, sheetname || ((filename || "") + "." + m), wopts);
process.exit(0);
} });
-wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
+wb_formats_2.forEach(function(m) { if(program[m[0]]) {
wopts.bookType = m[1];
- if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
+ X.writeFile(wb, sheetname || ((filename || "") + "." + m[2]), wopts);
process.exit(0);
} });
var target_sheet = sheetname || '';
if(target_sheet === '') {
- if(+program.sheetIndex < (wb.SheetNames||[]).length) target_sheet = wb.SheetNames[+program.sheetIndex];
+ if(program.sheetIndex < (wb.SheetNames||[]).length) target_sheet = wb.SheetNames[program.sheetIndex];
else target_sheet = (wb.SheetNames||[""])[0];
}
@@ -202,84 +158,39 @@ try {
process.exit(4);
}
-if(!program.quiet && !program.book) console.error(target_sheet);
+if(program.readOnly) process.exit(0);
-/* single worksheet file formats */
+/* single worksheet formats */
[
['biff2', '.xls'],
- ['biff3', '.xls'],
- ['biff4', '.xls'],
['sylk', '.slk'],
['html', '.html'],
['prn', '.prn'],
- ['eth', '.eth'],
- ['rtf', '.rtf'],
['txt', '.txt'],
- ['dbf', '.dbf'],
['dif', '.dif']
-].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) {
- wopts.bookType = m[0];
- if(program.book) {
- /*:: if(wb == null) throw new Error("Unreachable"); */
- wb.SheetNames.forEach(function(n, i) {
- wopts.sheet = n;
- X.writeFile(wb, (program.output || sheetname || filename || "") + m[1] + "." + i, wopts);
- });
- } else X.writeFile(wb, program.output || sheetname || ((filename || "") + m[1]), wopts);
- process.exit(0);
+].forEach(function(m) { if(program[m[0]]) {
+ wopts.bookType = m[0];
+ X.writeFile(wb, sheetname || ((filename || "") + m[1]), wopts);
+ process.exit(0);
} });
-function outit(o, fn) { if(fn) fs.writeFileSync(fn, o); else console.log(o); }
-
-function doit(cb) {
- /*:: if(!wb) throw new Error("unreachable"); */
- if(program.book) wb.SheetNames.forEach(function(n, i) {
- /*:: if(!wb) throw new Error("unreachable"); */
- outit(cb(wb.Sheets[n]), (program.output || sheetname || filename) + "." + i);
- });
- else outit(cb(ws), program.output);
+var oo = "";
+var strm = false;
+if(!program.quiet) console.error(target_sheet);
+if(program.formulae) oo = X.utils.sheet_to_formulae(ws).join("\n");
+else if(program.json) oo = JSON.stringify(X.utils.sheet_to_json(ws));
+else if(program.rawJs) oo = JSON.stringify(X.utils.sheet_to_json(ws,{raw:true}));
+else if(program.arrays) oo = JSON.stringify(X.utils.sheet_to_json(ws,{raw:true, header:1}));
+else {
+ strm = true;
+ var stream = X.stream.to_csv(ws, {FS:program.fieldSep, RS:program.rowSep});
+ if(program.output) stream.pipe(fs.createWriteStream(program.output));
+ else stream.pipe(process.stdout);
}
-var jso = {};
-switch(true) {
- case program.formulae:
- doit(function(ws) { return X.utils.sheet_to_formulae(ws).join("\n"); });
- break;
-
- case program.arrays: jso.header = 1;
- /* falls through */
- case program.rawJs: jso.raw = true;
- /* falls through */
- case program.json:
- doit(function(ws) { return JSON.stringify(X.utils.sheet_to_json(ws,jso)); });
- break;
-
- default:
- if(!program.book) {
- var stream = X.stream.to_csv(ws, {FS:program.fieldSep, RS:program.rowSep});
- if(program.output) stream.pipe(fs.createWriteStream(program.output));
- else stream.pipe(process.stdout);
- } else doit(function(ws) { return X.utils.sheet_to_csv(ws,{FS:program.fieldSep, RS:program.rowSep}); });
- break;
-}
-
-function dump_props(wb/*:Workbook*/) {
- var propaoa = [];
- if(Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops));
- else {
- var Keys/*:: :Array = []*/, pi;
- if(wb.Props) {
- Keys = Object.keys(wb.Props);
- for(pi = 0; pi < Keys.length; ++pi) {
- if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
- }
- }
- if(wb.Custprops) {
- Keys = Object.keys(wb.Custprops);
- for(pi = 0; pi < Keys.length; ++pi) {
- if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
- }
- }
- }
- console.log(X.utils.sheet_to_csv(X.utils.aoa_to_sheet(propaoa)));
+if(!strm) {
+ if(program.output) fs.writeFileSync(program.output, oo);
+ else console.log(oo);
}
+/*:: } */
+/*:: } */
diff --git a/bits/00_header.js b/bits/00_header.js
index ead5056..fa858e2 100644
--- a/bits/00_header.js
+++ b/bits/00_header.js
@@ -1,6 +1,8 @@
-/*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
+/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
+/*jshint -W041 */
+/*jshint funcscope:true, eqnull:true, loopfunc:true */
/*exported XLSX */
-/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
+/*global global, exports, module, require:false, process:false, Buffer:false */
var XLSX = {};
-function make_xlsx_lib(XLSX){
+(function make_xlsx(XLSX){
diff --git a/bits/01_version.js b/bits/01_version.js
index 62f2f92..cb5bd4d 100644
--- a/bits/01_version.js
+++ b/bits/01_version.js
@@ -1 +1 @@
-XLSX.version = '0.17.1';
+XLSX.version = '0.10.5';
diff --git a/bits/02_codepage.js b/bits/02_codepage.js
index 906414b..dd94445 100644
--- a/bits/02_codepage.js
+++ b/bits/02_codepage.js
@@ -1,79 +1,30 @@
-var current_codepage = 1200, current_ansi = 1252;
+var current_codepage = 1200;
/*:: declare var cptable:any; */
-/*global cptable:true, window */
+/*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') {
- if(typeof cptable === 'undefined') {
- if(typeof global !== 'undefined') global.cptable = require('./dist/cpexcel.js');
- else if(typeof window !== 'undefined') window.cptable = require('./dist/cpexcel.js');
- }
-}
-
-var VALID_ANSI = [ 874, 932, 936, 949, 950 ];
-for(var i = 0; i <= 8; ++i) VALID_ANSI.push(1250 + i);
-/* ECMA-376 Part I 18.4.1 charset to codepage mapping */
-var CS2CP = ({
- /*::[*/0/*::]*/: 1252, /* ANSI */
- /*::[*/1/*::]*/: 65001, /* DEFAULT */
- /*::[*/2/*::]*/: 65001, /* SYMBOL */
- /*::[*/77/*::]*/: 10000, /* MAC */
- /*::[*/128/*::]*/: 932, /* SHIFTJIS */
- /*::[*/129/*::]*/: 949, /* HANGUL */
- /*::[*/130/*::]*/: 1361, /* JOHAB */
- /*::[*/134/*::]*/: 936, /* GB2312 */
- /*::[*/136/*::]*/: 950, /* CHINESEBIG5 */
- /*::[*/161/*::]*/: 1253, /* GREEK */
- /*::[*/162/*::]*/: 1254, /* TURKISH */
- /*::[*/163/*::]*/: 1258, /* VIETNAMESE */
- /*::[*/177/*::]*/: 1255, /* HEBREW */
- /*::[*/178/*::]*/: 1256, /* ARABIC */
- /*::[*/186/*::]*/: 1257, /* BALTIC */
- /*::[*/204/*::]*/: 1251, /* RUSSIAN */
- /*::[*/222/*::]*/: 874, /* THAI */
- /*::[*/238/*::]*/: 1250, /* EASTEUROPE */
- /*::[*/255/*::]*/: 1252, /* OEM */
- /*::[*/69/*::]*/: 6969 /* MISC */
-}/*:any*/);
-
-var set_ansi = function(cp/*:number*/) { if(VALID_ANSI.indexOf(cp) == -1) return; current_ansi = CS2CP[0] = cp; };
-function reset_ansi() { set_ansi(1252); }
-
-var set_cp = function(cp/*:number*/) { current_codepage = cp; set_ansi(cp); };
-function reset_cp() { set_cp(1200); reset_ansi(); }
-
-function char_codes(data/*:string*/)/*:Array*/ { var o/*:Array*/ = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; }
-
-function utf16leread(data/*:string*/)/*:string*/ {
- var o/*:Array*/ = [];
- for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i) + (data.charCodeAt(2*i+1)<<8));
- return o.join("");
-}
-function utf16beread(data/*:string*/)/*:string*/ {
- var o/*:Array*/ = [];
- for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i+1) + (data.charCodeAt(2*i)<<8));
- return o.join("");
+ if(typeof cptable === 'undefined') global.cptable = require('./dist/cpexcel.js');
}
+function reset_cp() { set_cp(1200); }
+var set_cp = function(cp) { current_codepage = cp; };
+function char_codes(data) { var o = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; }
var debom = function(data/*:string*/)/*:string*/ {
var c1 = data.charCodeAt(0), c2 = data.charCodeAt(1);
- if(c1 == 0xFF && c2 == 0xFE) return utf16leread(data.slice(2));
- if(c1 == 0xFE && c2 == 0xFF) return utf16beread(data.slice(2));
- if(c1 == 0xFEFF) return data.slice(1);
+ if(c1 == 0xFF && c2 == 0xFE) return data.substr(2);
+ if(c1 == 0xFE && c2 == 0xFF) return data.substr(2);
+ if(c1 == 0xFEFF) return data.substr(1);
return data;
};
-var _getchar = function _gc1(x/*:number*/)/*:string*/ { return String.fromCharCode(x); };
-var _getansi = function _ga1(x/*:number*/)/*:string*/ { return String.fromCharCode(x); };
+var _getchar = function _gc1(x) { return String.fromCharCode(x); };
if(typeof cptable !== 'undefined') {
- set_cp = function(cp/*:number*/) { current_codepage = cp; set_ansi(cp); };
- debom = function(data/*:string*/) {
- if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.slice(2))); }
+ set_cp = function(cp) { current_codepage = cp; };
+ debom = function(data) {
+ if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.substr(2))); }
return data;
};
- _getchar = function _gc2(x/*:number*/)/*:string*/ {
+ _getchar = function _gc2(x) {
if(current_codepage === 1200) return String.fromCharCode(x);
return cptable.utils.decode(current_codepage, [x&255,x>>8])[0];
};
- _getansi = function _ga2(x/*:number*/)/*:string*/ {
- return cptable.utils.decode(current_ansi, [x])[0];
- };
}
diff --git a/bits/04_base64.js b/bits/04_base64.js
index a334d48..7050f43 100644
--- a/bits/04_base64.js
+++ b/bits/04_base64.js
@@ -3,17 +3,15 @@ var Base64 = (function make_b64(){
return {
encode: function(input/*:string*/)/*:string*/ {
var o = "";
- var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
+ var c1, c2, c3, e1, e2, e3, e4;
for(var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
- e1 = (c1 >> 2);
-
c2 = input.charCodeAt(i++);
- e2 = ((c1 & 3) << 4) | (c2 >> 4);
-
c3 = input.charCodeAt(i++);
- e3 = ((c2 & 15) << 2) | (c3 >> 6);
- e4 = (c3 & 63);
+ e1 = c1 >> 2;
+ e2 = (c1 & 3) << 4 | c2 >> 4;
+ e3 = (c2 & 15) << 2 | c3 >> 6;
+ e4 = c3 & 63;
if (isNaN(c2)) { e3 = e4 = 64; }
else if (isNaN(c3)) { e4 = 64; }
o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
@@ -22,21 +20,20 @@ var Base64 = (function make_b64(){
},
decode: function b64_decode(input/*:string*/)/*:string*/ {
var o = "";
- var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
- input = input.replace(/[^\w\+\/\=]/g, "");
+ var c1, c2, c3;
+ var e1, e2, e3, e4;
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
for(var i = 0; i < input.length;) {
e1 = map.indexOf(input.charAt(i++));
e2 = map.indexOf(input.charAt(i++));
- c1 = (e1 << 2) | (e2 >> 4);
- o += String.fromCharCode(c1);
-
e3 = map.indexOf(input.charAt(i++));
- c2 = ((e2 & 15) << 4) | (e3 >> 2);
- if (e3 !== 64) { o += String.fromCharCode(c2); }
-
e4 = map.indexOf(input.charAt(i++));
- c3 = ((e3 & 3) << 6) | e4;
- if (e4 !== 64) { o += String.fromCharCode(c3); }
+ c1 = e1 << 2 | e2 >> 4;
+ c2 = (e2 & 15) << 4 | e3 >> 2;
+ c3 = (e3 & 3) << 6 | e4;
+ o += String.fromCharCode(c1);
+ if (e3 != 64) { o += String.fromCharCode(c2); }
+ if (e4 != 64) { o += String.fromCharCode(c3); }
}
return o;
}
diff --git a/bits/05_buf.js b/bits/05_buf.js
index f7e5692..f6334a9 100644
--- a/bits/05_buf.js
+++ b/bits/05_buf.js
@@ -1,60 +1,16 @@
-var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node);
-
-var Buffer_from = /*::(*/function(){}/*:: :any)*/;
-
-if(typeof Buffer !== 'undefined') {
- var nbfs = !Buffer.from;
- if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
- Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
- // $FlowIgnore
- if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
- // $FlowIgnore
- if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
-}
+var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && process.versions.node);
function new_raw_buf(len/*:number*/) {
/* jshint -W056 */
- return has_buf ? Buffer.alloc(len) : new Array(len);
+ return new (has_buf ? Buffer : Array)(len);
/* jshint +W056 */
}
-function new_unsafe_buf(len/*:number*/) {
- /* jshint -W056 */
- return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
- /* jshint +W056 */
-}
-
-var s2a = function s2a(s/*:string*/)/*:any*/ {
- if(has_buf) return Buffer_from(s, "binary");
- return s.split("").map(function(x/*:string*/)/*:number*/{ return x.charCodeAt(0) & 0xff; });
-};
-
-function s2ab(s/*:string*/)/*:any*/ {
- if(typeof ArrayBuffer === 'undefined') return s2a(s);
- var buf = new ArrayBuffer(s.length), view = new Uint8Array(buf);
- for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
- return buf;
-}
-
-function a2s(data/*:any*/)/*:string*/ {
- if(Array.isArray(data)) return data.map(function(c) { return String.fromCharCode(c); }).join("");
- var o/*:Array*/ = []; for(var i = 0; i < data.length; ++i) o[i] = String.fromCharCode(data[i]); return o.join("");
-}
-
-function a2u(data/*:Array*/)/*:Uint8Array*/ {
- if(typeof Uint8Array === 'undefined') throw new Error("Unsupported");
- return new Uint8Array(data);
-}
-
-function ab2a(data/*:ArrayBuffer|Uint8Array*/)/*:Array*/ {
- if(typeof ArrayBuffer == 'undefined') throw new Error("Unsupported");
- if(data instanceof ArrayBuffer) return ab2a(new Uint8Array(data));
- /*:: if(data instanceof ArrayBuffer) throw new Error("unreachable"); */
- var o = new Array(data.length);
- for(var i = 0; i < data.length; ++i) o[i] = data[i];
- return o;
+function s2a(s/*:string*/) {
+ if(has_buf) return new Buffer(s, "binary");
+ return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
}
var bconcat = function(bufs) { return [].concat.apply([], bufs); };
-var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g;
+var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/;
diff --git a/bits/10_ssf.js b/bits/10_ssf.js
index 0c8d3bf..5a00934 100644
--- a/bits/10_ssf.js
+++ b/bits/10_ssf.js
@@ -1,8 +1,8 @@
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint -W041 */
-var SSF/*:SSFModule*/ = ({}/*:any*/);
-var make_ssf = function make_ssf(SSF/*:SSFModule*/){
-SSF.version = '0.11.2';
+var SSF = {};
+var make_ssf = function make_ssf(SSF){
+SSF.version = '0.9.4';
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
@@ -13,9 +13,16 @@ function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=
var p2_32 = Math.pow(2,32);
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
-/*::
-type SSF_write_num = {(type:string, fmt:string, val:number):string};
-*/
+/* Options */
+var opts_fmt/*:Array >*/ = [
+ ["date1904", 0],
+ ["output", ""],
+ ["WTF", false]
+];
+function fixopts(o){
+ for(var y = 0; y != opts_fmt.length; ++y) if(o[opts_fmt[y][0]]===undefined) o[opts_fmt[y][0]]=opts_fmt[y][1];
+}
+SSF.opts = opts_fmt;
var days/*:Array >*/ = [
['Sun', 'Sunday'],
['Mon', 'Monday'],
@@ -69,65 +76,11 @@ function init_table(t/*:any*/) {
t[48]= '##0.0E+0';
t[49]= '@';
t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
+ t[65535]= 'General';
}
var table_fmt = {};
init_table(table_fmt);
-/* Defaults determined by systematically testing in Excel 2019 */
-
-/* These formats appear to default to other formats in the table */
-var default_map/*:Array*/ = [];
-var defi = 0;
-
-// 5 -> 37 ... 8 -> 40
-for(defi = 5; defi <= 8; ++defi) default_map[defi] = 32 + defi;
-
-// 23 -> 0 ... 26 -> 0
-for(defi = 23; defi <= 26; ++defi) default_map[defi] = 0;
-
-// 27 -> 14 ... 31 -> 14
-for(defi = 27; defi <= 31; ++defi) default_map[defi] = 14;
-// 50 -> 14 ... 58 -> 14
-for(defi = 50; defi <= 58; ++defi) default_map[defi] = 14;
-
-// 59 -> 1 ... 62 -> 4
-for(defi = 59; defi <= 62; ++defi) default_map[defi] = defi - 58;
-// 67 -> 9 ... 68 -> 10
-for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 58;
-// 72 -> 14 ... 75 -> 17
-for(defi = 72; defi <= 75; ++defi) default_map[defi] = defi - 58;
-
-// 69 -> 12 ... 71 -> 14
-for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 57;
-
-// 76 -> 20 ... 78 -> 22
-for(defi = 76; defi <= 78; ++defi) default_map[defi] = defi - 56;
-
-// 79 -> 45 ... 81 -> 47
-for(defi = 79; defi <= 81; ++defi) default_map[defi] = defi - 34;
-
-// 82 -> 0 ... 65536 -> 0 (omitted)
-
-/* These formats technically refer to Accounting formats with no equivalent */
-var default_str/*:Array*/ = [];
-
-// 5 -- Currency, 0 decimal, black negative
-default_str[5] = default_str[63] = '"$"#,##0_);\\("$"#,##0\\)';
-// 6 -- Currency, 0 decimal, red negative
-default_str[6] = default_str[64] = '"$"#,##0_);[Red]\\("$"#,##0\\)';
-// 7 -- Currency, 2 decimal, black negative
-default_str[7] = default_str[65] = '"$"#,##0.00_);\\("$"#,##0.00\\)';
-// 8 -- Currency, 2 decimal, red negative
-default_str[8] = default_str[66] = '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)';
-
-// 41 -- Accounting, 0 decimal, No Symbol
-default_str[41] = '_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)';
-// 42 -- Accounting, 0 decimal, $ Symbol
-default_str[42] = '_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)';
-// 43 -- Accounting, 2 decimal, No Symbol
-default_str[43] = '_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)';
-// 44 -- Accounting, 2 decimal, $ Symbol
-default_str[44] = '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)';
function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array*/ {
var sgn = x < 0 ? -1 : 1;
var B = x * sgn;
@@ -148,13 +101,57 @@ function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array*/
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
+function general_fmt_int(v/*:number*/)/*:string*/ { return ""+v; }
+SSF._general_int = general_fmt_int;
+var general_fmt_num = (function make_general_fmt_num() {
+var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
+function gfn2(v) {
+ var w = (v<0?12:11);
+ var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
+ o = v.toPrecision(10); if(o.length <= w) return o;
+ return v.toExponential(5);
+}
+function gfn3(v) {
+ var o = v.toFixed(11).replace(gnr1,".$1");
+ if(o.length > (v<0?12:11)) o = v.toPrecision(6);
+ return o;
+}
+function gfn4(o) {
+ for(var i = 0; i != o.length; ++i) if((o.charCodeAt(i) | 0x20) === 101) return o.replace(gnr4,".$1").replace(gnr5,"E").replace("e","E").replace(gnr6,"$10$2");
+ return o;
+}
+function gfn5(o) {
+ return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
+}
+return function general_fmt_num(v/*:number*/)/*:string*/ {
+ var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
+ if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
+ else if(Math.abs(V) <= 9) o = gfn2(v);
+ else if(V === 10) o = v.toFixed(10).substr(0,12);
+ else o = gfn3(v);
+ return gfn5(gfn4(o));
+};})();
+SSF._general_num = general_fmt_num;
+function general_fmt(v/*:any*/) {
+ switch(typeof v) {
+ case 'string': return v;
+ case 'boolean': return v ? "TRUE" : "FALSE";
+ case 'number': return (v|0) === v ? general_fmt_int(v/*, opts*/) : general_fmt_num(v/*, opts*/);
+ case 'undefined': return "";
+ case 'object': if(v == null) return "";
+ }
+ throw new Error("unsupported value in General format: " + v);
+}
+SSF._general = general_fmt;
+function fix_hijri(/*date, o*/) { return 0; }
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
- if(opts && opts.date1904) date += 1462;
+ fixopts(opts != null ? opts : (opts=[]));
+ if(opts.date1904) date += 1462;
if(out.u > 0.9999) {
out.u = 0;
if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
@@ -179,94 +176,6 @@ function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
return out;
}
SSF.parse_date_code = parse_date_code;
-var basedate = new Date(1899, 11, 31, 0, 0, 0);
-var dnthresh = basedate.getTime();
-var base1904 = new Date(1900, 2, 1, 0, 0, 0);
-function datenum_local(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
- var epoch = v.getTime();
- if(date1904) epoch -= 1461*24*60*60*1000;
- else if(v >= base1904) epoch += 24*60*60*1000;
- return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
-}
-/* The longest 32-bit integer text is "-4294967296", exactly 11 chars */
-function general_fmt_int(v/*:number*/)/*:string*/ { return v.toString(10); }
-SSF._general_int = general_fmt_int;
-
-/* ECMA-376 18.8.30 numFmt*/
-/* Note: `toPrecision` uses standard form when prec > E and E >= -6 */
-var general_fmt_num = (function make_general_fmt_num() {
- var trailing_zeroes_and_decimal = /(?:\.0*|(\.\d*[1-9])0+)$/;
- function strip_decimal(o/*:string*/)/*:string*/ {
- return (o.indexOf(".") == -1) ? o : o.replace(trailing_zeroes_and_decimal, "$1");
- }
-
- /* General Exponential always shows 2 digits exp and trims the mantissa */
- var mantissa_zeroes_and_decimal = /(?:\.0*|(\.\d*[1-9])0+)[Ee]/;
- var exp_with_single_digit = /(E[+-])(\d)$/;
- function normalize_exp(o/*:string*/)/*:string*/ {
- if(o.indexOf("E") == -1) return o;
- return o.replace(mantissa_zeroes_and_decimal,"$1E").replace(exp_with_single_digit,"$10$2");
- }
-
- /* exponent >= -9 and <= 9 */
- function small_exp(v/*:number*/)/*:string*/ {
- var w = (v<0?12:11);
- var o = strip_decimal(v.toFixed(12)); if(o.length <= w) return o;
- o = v.toPrecision(10); if(o.length <= w) return o;
- return v.toExponential(5);
- }
-
- /* exponent >= 11 or <= -10 likely exponential */
- function large_exp(v/*:number*/)/*:string*/ {
- var o = strip_decimal(v.toFixed(11));
- return (o.length > (v<0?12:11) || o === "0" || o === "-0") ? v.toPrecision(6) : o;
- }
-
- function general_fmt_num_base(v/*:number*/)/*:string*/ {
- var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
-
- if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
- else if(Math.abs(V) <= 9) o = small_exp(v);
- else if(V === 10) o = v.toFixed(10).substr(0,12);
- else o = large_exp(v);
-
- return strip_decimal(normalize_exp(o.toUpperCase()));
- }
-
- return general_fmt_num_base;
-})();
-SSF._general_num = general_fmt_num;
-
-/*
- "General" rules:
- - text is passed through ("@")
- - booleans are rendered as TRUE/FALSE
- - "up to 11 characters" displayed for numbers
- - Default date format (code 14) used for Dates
-
- TODO: technically the display depends on the width of the cell
-*/
-function general_fmt(v/*:any*/, opts/*:any*/) {
- switch(typeof v) {
- case 'string': return v;
- case 'boolean': return v ? "TRUE" : "FALSE";
- case 'number': return (v|0) === v ? v.toString(10) : general_fmt_num(v);
- case 'undefined': return "";
- case 'object':
- if(v == null) return "";
- if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
- }
- throw new Error("unsupported value in General format: " + v);
-}
-SSF._general = general_fmt;
-function fix_hijri(date/*:Date*/, o/*:[number, number, number]*/) {
- /* TODO: properly adjust y/m/d and */
- o[0] -= 581;
- var dow = date.getDay();
- if(date < 60) dow = (dow + 6) % 7;
- return dow;
-}
-//var THAI_DIGITS = "\u0E50\u0E51\u0E52\u0E53\u0E54\u0E55\u0E56\u0E57\u0E58\u0E59".split("");
/*jshint -W086 */
function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ {
var o="", ss=0, tt=0, y = val.y, out, outl = 0;
@@ -308,17 +217,23 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
default: throw 'bad minute format: ' + fmt;
} break;
case 115: /* 's' seconds */
- if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
- if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
- /*::if(!ss0) ss0 = 0; */
- if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
- else tt = ss0 === 1 ? 10 : 1;
- ss = Math.round((tt)*(val.S + val.u));
- if(ss >= 60*tt) ss = 0;
- if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
- o = pad0(ss,2 + ss0);
- if(fmt === 'ss') return o.substr(0,2);
- return "." + o.substr(2,fmt.length-1);
+ if(val.u === 0) switch(fmt) {
+ case 's': case 'ss': return pad0(val.S, fmt.length);
+ case '.0': case '.00': case '.000':
+ }
+ switch(fmt) {
+ case 's': case 'ss': case '.0': case '.00': case '.000':
+ /*::if(!ss0) ss0 = 0; */
+ if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
+ else tt = ss0 === 1 ? 10 : 1;
+ ss = Math.round((tt)*(val.S + val.u));
+ if(ss >= 60*tt) ss = 0;
+ if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
+ o = pad0(ss,2 + ss0);
+ if(fmt === 'ss') return o.substr(0,2);
+ return "." + o.substr(2,fmt.length-1);
+ default: throw 'bad second format: ' + fmt;
+ }
case 90: /* 'Z' absolute time */
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
@@ -327,20 +242,18 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
- out = y; outl = 1; break;
+ out = y; outl = 1;
}
- var outstr = outl > 0 ? pad0(out, outl) : "";
- return outstr;
+ if(outl > 0) return pad0(out, outl); else return "";
}
/*jshint +W086 */
function commaify(s/*:string*/)/*:string*/ {
- var w = 3;
- if(s.length <= w) return s;
- var j = (s.length % w), o = s.substr(0,j);
- for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
+ if(s.length <= 3) return s;
+ var j = (s.length % 3), o = s.substr(0,j);
+ for(; j!=s.length; j+=3) o+=(o.length > 0 ? "," : "") + s.substr(j,3);
return o;
}
-var write_num/*:SSF_write_num*/ = (function make_write_num(){
+var write_num = (function make_write_num(){
var pct1 = /%/g;
function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
@@ -401,9 +314,10 @@ function hashq(str/*:string*/)/*:string*/ {
}
function rnd(val/*:number*/, d/*:number*/)/*:string*/ { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
function dec(val/*:number*/, d/*:number*/)/*:number*/ {
- var _frac = val - Math.floor(val), dd = Math.pow(10,d);
- if (d < ('' + Math.round(_frac * dd)).length) return 0;
- return Math.round(_frac * dd);
+ if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
+ return 0;
+ }
+ return Math.round((val-Math.floor(val))*Math.pow(10,d));
}
function carry(val/*:number*/, d/*:number*/)/*:number*/ {
if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
@@ -411,10 +325,7 @@ function carry(val/*:number*/, d/*:number*/)/*:number*/ {
}
return 0;
}
-function flr(val/*:number*/)/*:string*/ {
- if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0));
- return ""+Math.floor(val);
-}
+function flr(val/*:number*/)/*:string*/ { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
@@ -637,13 +548,13 @@ function split_fmt(fmt/*:string*/)/*:Array*/ {
return out;
}
SSF._split = split_fmt;
-var abstime = /\[[HhMmSs\u0E0A\u0E19\u0E17]*\]/;
+var abstime = /\[[HhMmSs]*\]/;
function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
var i = 0, /*cc = 0,*/ c = "", o = "";
while(i < fmt.length) {
switch((c = fmt.charAt(i))) {
case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
- case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;){/*empty*/} ++i; break;
+ case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
case '\\': i+=2; break;
case '_': i+=2; break;
case '@': ++i; break;
@@ -653,10 +564,9 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
/* falls through */
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
- case 'A': case 'a': case '上':
+ case 'A': case 'a':
if(fmt.substr(i, 3).toUpperCase() === "A/P") return true;
if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true;
- if(fmt.substr(i, 5).toUpperCase() === "上午/下午") return true;
++i; break;
case '[':
o = c;
@@ -681,7 +591,7 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
}
SSF.is_date = fmt_is_date;
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
- var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
+ var out = [], o = "", i = 0, c = "", lst='t', q, dt, j, cc;
var hr='H';
/* Tokenize */
while(i < fmt.length) {
@@ -709,16 +619,15 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
if(v < 0) return "";
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
- o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
+ o = c; while(++i= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
- else if(fmt.substr(i,5).toUpperCase() === "上午/下午") { if(dt!=null) q.v = dt.H >= 12 ? "下午" : "上午"; q.t = 'T'; i+=5; hr='h'; }
else { q.t = "t"; ++i; }
if(dt==null && q.t === 'T') return "";
out[out.length] = q; lst = c; break;
@@ -738,30 +647,27 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
/* Numbers */
case '.':
if(dt != null) {
- o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
+ o = c; while((c=fmt.charAt(++i)) === "0") o += c;
out[out.length] = {t:'s', v:o}; break;
}
/* falls through */
case '0': case '#':
- o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1) o += c;
+ o = c; while((++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1) || (c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1)) o += c;
out[out.length] = {t:'n', v:o}; break;
case '?':
o = c; while(fmt.charAt(++i) === c) o+=c;
- out[out.length] = {t:c, v:o}; lst = c; break;
+ q={t:c, v:o}; out[out.length] = q; lst = c; break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
out[out.length] = {t:'D', v:o}; break;
case ' ': out[out.length] = {t:c, v:c}; ++i; break;
- case '$': out[out.length] = {t:'t', v:'$'}; ++i; break;
default:
if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
out[out.length] = {t:'t', v:c}; ++i; break;
}
}
-
- /* Scan for date/time parts */
var bt = 0, ss0 = 0, ssm;
for(i=out.length-1, lst='t'; i >= 0; --i) {
switch(out[i].t) {
@@ -780,7 +686,6 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
- /* time rounding depends on presence of minute / second / usec fields */
switch(bt) {
case 0: break;
case 1:
@@ -795,7 +700,6 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
break;
}
-
/* replace fields */
var nstr = "", jj;
for(i=0; i < out.length; ++i) {
@@ -806,7 +710,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
/*::if(!dt) throw "unreachable"; */
out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
out[i].t = 't'; break;
- case 'n': case '?':
+ case 'n': case '(': case '?':
jj = i+1;
while(out[jj] != null && (
(c=out[jj].t) === "?" || c === "D" ||
@@ -826,7 +730,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(nstr.length > 0) {
if(nstr.charCodeAt(0) == 40) /* '(' */ {
myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v);
- ostr = write_num('n', nstr, myv);
+ ostr = write_num('(', nstr, myv);
} else {
myv = (v<0 && flen > 1 ? -v : v);
ostr = write_num('n', nstr, myv);
@@ -841,7 +745,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
var lasti=out.length;
if(decpt === out.length && ostr.indexOf("E") === -1) {
for(i=out.length-1; i>= 0;--i) {
- if(out[i] == null || 'n?'.indexOf(out[i].t) === -1) continue;
+ if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
else if(jj < 0) out[i].v = "";
else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
@@ -853,7 +757,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
else if(decpt !== out.length && ostr.indexOf("E") === -1) {
jj = ostr.indexOf(".")-1;
for(i=decpt; i>= 0; --i) {
- if(out[i] == null || 'n?'.indexOf(out[i].t) === -1) continue;
+ if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
vv = out[i].v.substr(j+1);
for(; j>=0; --j) {
@@ -878,7 +782,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
}
}
}
- for(i=0; i-1) {
+ for(i=0; i-1) {
myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
out[i].v = write_num(out[i].t, out[i].v, myv);
out[i].t = 't';
@@ -889,7 +793,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
}
SSF._eval = eval_fmt;
var cfregex = /\[[=<>]/;
-var cfregex2 = /\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;
+var cfregex2 = /\[([=<>]*)(-?\d+\.?\d*)\]/;
function chkcond(v, rr) {
if(rr == null) return false;
var thresh = parseFloat(rr[2]);
@@ -903,7 +807,7 @@ function chkcond(v, rr) {
}
return false;
}
-function choose_fmt(f/*:string*/, v/*:any*/) {
+function choose_fmt(f/*:string*/, v) {
var fmt = split_fmt(f);
var l = fmt.length, lat = fmt[l-1].indexOf("@");
if(l<4 && lat>-1) --l;
@@ -935,42 +839,20 @@ function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
case "number":
if(fmt == 14 && o.dateNF) sfmt = o.dateNF;
else sfmt = (o.table != null ? (o.table/*:any*/) : table_fmt)[fmt];
- if(sfmt == null) sfmt = (o.table && o.table[default_map[fmt]]) || table_fmt[default_map[fmt]];
- if(sfmt == null) sfmt = default_str[fmt] || "General";
break;
}
if(isgeneral(sfmt,0)) return general_fmt(v, o);
- if(v instanceof Date) v = datenum_local(v, o.date1904);
var f = choose_fmt(sfmt, v);
if(isgeneral(f[1])) return general_fmt(v, o);
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
else if(v === "" || v == null) return "";
return eval_fmt(f[1], v, o, f[0]);
}
-function load_entry(fmt/*:string*/, idx/*:?number*/)/*:number*/ {
- if(typeof idx != 'number') {
- idx = +idx || -1;
-/*::if(typeof idx != 'number') return 0x188; */
- for(var i = 0; i < 0x0188; ++i) {
-/*::if(typeof idx != 'number') return 0x188; */
- if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
- if(table_fmt[i] == fmt) { idx = i; break; }
- }
-/*::if(typeof idx != 'number') return 0x188; */
- if(idx < 0) idx = 0x187;
- }
-/*::if(typeof idx != 'number') return 0x188; */
- table_fmt[idx] = fmt;
- return idx;
-}
-SSF.load = load_entry;
SSF._table = table_fmt;
-SSF.get_table = function get_table()/*:SSFTable*/ { return table_fmt; };
-SSF.load_table = function load_table(tbl/*:SSFTable*/)/*:void*/ {
- for(var i=0; i!=0x0188; ++i)
- if(tbl[i] !== undefined) load_entry(tbl[i], i);
-};
-SSF.init_table = init_table;
+SSF.load = function load_entry(fmt/*:string*/, idx/*:number*/) { table_fmt[idx] = fmt; };
SSF.format = format;
+SSF.get_table = function get_table() { return table_fmt; };
+SSF.load_table = function load_table(tbl/*:{[n:number]:string}*/) { for(var i=0; i!=0x0188; ++i) if(tbl[i] !== undefined) SSF.load(tbl[i], i); };
+SSF.init_table = init_table;
};
make_ssf(SSF);
diff --git a/bits/11_ssfutils.js b/bits/11_ssfutils.js
index 56d913b..a700c68 100644
--- a/bits/11_ssfutils.js
+++ b/bits/11_ssfutils.js
@@ -18,46 +18,6 @@ var XLMLFormatMap/*{[string]:string}*/ = ({
"On/Off": '"Yes";"Yes";"No";@'
}/*:any*/);
-var SSFImplicit/*{[number]:string}*/ = ({
- "5": '"$"#,##0_);\\("$"#,##0\\)',
- "6": '"$"#,##0_);[Red]\\("$"#,##0\\)',
- "7": '"$"#,##0.00_);\\("$"#,##0.00\\)',
- "8": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
- "23": 'General', "24": 'General', "25": 'General', "26": 'General',
- "27": 'm/d/yy', "28": 'm/d/yy', "29": 'm/d/yy', "30": 'm/d/yy', "31": 'm/d/yy',
- "32": 'h:mm:ss', "33": 'h:mm:ss', "34": 'h:mm:ss', "35": 'h:mm:ss',
- "36": 'm/d/yy',
- "41": '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
- "42": '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
- "43": '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
- "44": '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
- "50": 'm/d/yy', "51": 'm/d/yy', "52": 'm/d/yy', "53": 'm/d/yy', "54": 'm/d/yy',
- "55": 'm/d/yy', "56": 'm/d/yy', "57": 'm/d/yy', "58": 'm/d/yy',
- "59": '0',
- "60": '0.00',
- "61": '#,##0',
- "62": '#,##0.00',
- "63": '"$"#,##0_);\\("$"#,##0\\)',
- "64": '"$"#,##0_);[Red]\\("$"#,##0\\)',
- "65": '"$"#,##0.00_);\\("$"#,##0.00\\)',
- "66": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
- "67": '0%',
- "68": '0.00%',
- "69": '# ?/?',
- "70": '# ??/??',
- "71": 'm/d/yy',
- "72": 'm/d/yy',
- "73": 'd-mmm-yy',
- "74": 'd-mmm',
- "75": 'mmm-yy',
- "76": 'h:mm',
- "77": 'h:mm:ss',
- "78": 'm/d/yy h:mm',
- "79": 'mm:ss',
- "80": '[h]:mm:ss',
- "81": 'mmss.0'
-}/*:any*/);
-
/* dateNF parse TODO: move to SSF */
var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
function dateNF_regex(dateNF/*:string|number*/)/*:RegExp*/ {
diff --git a/bits/18_cfb.js b/bits/18_cfb.js
index 61b8b78..c5b75e1 100644
--- a/bits/18_cfb.js
+++ b/bits/18_cfb.js
@@ -12,239 +12,38 @@ declare var bconcat:any;
declare var s2a:any;
declare var chr0:any;
declare var chr1:any;
-declare var has_buf:boolean;
-declare var new_buf:any;
-declare var new_raw_buf:any;
-declare var new_unsafe_buf:any;
*/
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint eqnull:true */
-/*exported CFB */
-/*global Uint8Array:false, Uint16Array:false */
/*::
-declare var DO_NOT_EXPORT_CFB:?boolean;
-type SectorEntry = {
- name?:string;
- nodes?:Array;
- data:RawBytes;
-};
+declare var DO_NOT_EXPORT_CFB:any;
+type SectorEntry = any;
type SectorList = {
- [k:string|number]:SectorEntry;
+ (k:string|number):SectorEntry;
name:?string;
- fat_addrs:Array;
+ fat_addrs:any;
ssz:number;
}
-type CFBFiles = {[n:string]:CFBEntry};
*/
-/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
-/* vim: set ts=2: */
-/*exported CRC32 */
-var CRC32;
-(function (factory) {
- /*jshint ignore:start */
- /*eslint-disable */
- factory(CRC32 = {});
- /*eslint-enable */
- /*jshint ignore:end */
-}(function(CRC32) {
-CRC32.version = '1.2.0';
-/* see perf/crc32table.js */
-/*global Int32Array */
-function signed_crc_table()/*:any*/ {
- var c = 0, table/*:Array*/ = new Array(256);
-
- for(var n =0; n != 256; ++n){
- c = n;
- c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
- c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
- c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
- c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
- c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
- c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
- c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
- c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
- table[n] = c;
- }
-
- return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
-}
-
-var T = signed_crc_table();
-function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
- var C = seed ^ -1, L = bstr.length - 1;
- for(var i = 0; i < L;) {
- C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
- C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
- }
- if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
- return C ^ -1;
-}
-
-function crc32_buf(buf/*:Uint8Array|Array*/, seed/*:number*/)/*:number*/ {
- if(buf.length > 10000) return crc32_buf_8(buf, seed);
- var C = seed ^ -1, L = buf.length - 3;
- for(var i = 0; i < L;) {
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- }
- while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- return C ^ -1;
-}
-
-function crc32_buf_8(buf/*:Uint8Array|Array*/, seed/*:number*/)/*:number*/ {
- var C = seed ^ -1, L = buf.length - 7;
- for(var i = 0; i < L;) {
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- }
- while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
- return C ^ -1;
-}
-
-function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
- var C = seed ^ -1;
- for(var i = 0, L=str.length, c, d; i < L;) {
- c = str.charCodeAt(i++);
- if(c < 0x80) {
- C = (C>>>8) ^ T[(C ^ c)&0xFF];
- } else if(c < 0x800) {
- C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
- C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
- } else if(c >= 0xD800 && c < 0xE000) {
- c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
- C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
- C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
- C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
- C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
- } else {
- C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
- C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
- C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
- }
- }
- return C ^ -1;
-}
-CRC32.table = T;
-CRC32.bstr = crc32_bstr;
-CRC32.buf = crc32_buf;
-CRC32.str = crc32_str;
-}));
-/* [MS-CFB] v20171201 */
+/* [MS-CFB] v20130118 */
var CFB = (function _CFB(){
-var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
-exports.version = '1.1.4';
-/* [MS-CFB] 2.6.4 */
-function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
- var L = l.split("/"), R = r.split("/");
- for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {
- if((c = L[i].length - R[i].length)) return c;
- if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;
- }
- return L.length - R.length;
-}
-function dirname(p/*:string*/)/*:string*/ {
- if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1));
- var c = p.lastIndexOf("/");
- return (c === -1) ? p : p.slice(0, c+1);
-}
-
-function filename(p/*:string*/)/*:string*/ {
- if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1));
- var c = p.lastIndexOf("/");
- return (c === -1) ? p : p.slice(c+1);
-}
-/* -------------------------------------------------------------------------- */
-/* DOS Date format:
- high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
- add 1980 to stored year
- stored second should be doubled
-*/
-
-/* write JS date to buf as a DOS date */
-function write_dos_date(buf/*:CFBlob*/, date/*:Date|string*/) {
- if(typeof date === "string") date = new Date(date);
- var hms/*:number*/ = date.getHours();
- hms = hms << 6 | date.getMinutes();
- hms = hms << 5 | (date.getSeconds()>>>1);
- buf.write_shift(2, hms);
- var ymd/*:number*/ = (date.getFullYear() - 1980);
- ymd = ymd << 4 | (date.getMonth()+1);
- ymd = ymd << 5 | date.getDate();
- buf.write_shift(2, ymd);
-}
-
-/* read four bytes from buf and interpret as a DOS date */
-function parse_dos_date(buf/*:CFBlob*/)/*:Date*/ {
- var hms = buf.read_shift(2) & 0xFFFF;
- var ymd = buf.read_shift(2) & 0xFFFF;
- var val = new Date();
- var d = ymd & 0x1F; ymd >>>= 5;
- var m = ymd & 0x0F; ymd >>>= 4;
- val.setMilliseconds(0);
- val.setFullYear(ymd + 1980);
- val.setMonth(m-1);
- val.setDate(d);
- var S = hms & 0x1F; hms >>>= 5;
- var M = hms & 0x3F; hms >>>= 6;
- val.setHours(hms);
- val.setMinutes(M);
- val.setSeconds(S<<1);
- return val;
-}
-function parse_extra_field(blob/*:CFBlob*/)/*:any*/ {
- prep_blob(blob, 0);
- var o = /*::(*/{}/*:: :any)*/;
- var flags = 0;
- while(blob.l <= blob.length - 4) {
- var type = blob.read_shift(2);
- var sz = blob.read_shift(2), tgt = blob.l + sz;
- var p = {};
- switch(type) {
- /* UNIX-style Timestamps */
- case 0x5455: {
- flags = blob.read_shift(1);
- if(flags & 1) p.mtime = blob.read_shift(4);
- /* for some reason, CD flag corresponds to LFH */
- if(sz > 5) {
- if(flags & 2) p.atime = blob.read_shift(4);
- if(flags & 4) p.ctime = blob.read_shift(4);
- }
- if(p.mtime) p.mt = new Date(p.mtime*1000);
- }
- break;
- }
- blob.l = tgt;
- o[type] = p;
- }
- return o;
-}
-var fs/*:: = require('fs'); */;
-function get_fs() { return fs || (fs = require('fs')); }
-function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
-if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
-if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
-var mver = 3;
-var ssz = 512;
+var exports = {};
+exports.version = '0.11.1';
+function parse(file) {
+var mver = 3; // major version
+var ssz = 512; // sector size
var nmfs = 0; // number of mini FAT sectors
-var difat_sec_cnt = 0;
-var dir_start = 0;
-var minifat_start = 0;
-var difat_start = 0;
+var ndfs = 0; // number of DIFAT sectors
+var dir_start = 0; // first directory sector location
+var minifat_start = 0; // first mini FAT sector location
+var difat_start = 0; // first mini FAT sector location
-var fat_addrs/*:Array*/ = []; // locations of FAT sectors
+var fat_addrs = []; // locations of FAT sectors
/* [MS-CFB] 2.2 Compound File Header */
-var blob/*:CFBlob*/ = /*::(*/file.slice(0,512)/*:: :any)*/;
+var blob/*:any*/ = file.slice(0,512);
prep_blob(blob, 0);
/* major version */
@@ -252,23 +51,22 @@ var mv = check_get_mver(blob);
mver = mv[0];
switch(mver) {
case 3: ssz = 512; break; case 4: ssz = 4096; break;
- case 0: if(mv[1] == 0) return parse_zip(file, options);
- /* falls through */
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
}
/* reprocess header */
-if(ssz !== 512) { blob = /*::(*/file.slice(0,ssz)/*:: :any)*/; prep_blob(blob, 28 /* blob.l */); }
+if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }
/* Save header for final object */
-var header/*:RawBytes*/ = file.slice(0,ssz);
+var header = file.slice(0,ssz);
check_shifts(blob, mver);
// Number of Directory Sectors
-var dir_cnt/*:number*/ = blob.read_shift(4, 'i');
-if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);
+var nds = blob.read_shift(4, 'i');
+if(mver === 3 && nds !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + nds);
// Number of FAT Sectors
+//var nfs = blob.read_shift(4, 'i');
blob.l += 4;
// First Directory Sector Location
@@ -290,19 +88,19 @@ nmfs = blob.read_shift(4, 'i');
difat_start = blob.read_shift(4, 'i');
// Number of DIFAT Sectors
-difat_sec_cnt = blob.read_shift(4, 'i');
+ndfs = blob.read_shift(4, 'i');
// Grab FAT Sector Locations
-for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
+for(var q, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
q = blob.read_shift(4, 'i');
if(q<0) break;
fat_addrs[j] = q;
}
/** Break the file up into sectors */
-var sectors/*:Array*/ = sectorify(file, ssz);
+var sectors = sectorify(file, ssz);
-sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
+sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs);
/** Chains */
var sector_list/*:SectorList*/ = make_sector_list(sectors, dir_start, fat_addrs, ssz);
@@ -314,38 +112,40 @@ sector_list.fat_addrs = fat_addrs;
sector_list.ssz = ssz;
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
-var files/*:CFBFiles*/ = {}, Paths/*:Array*/ = [], FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array*/ = [];
-read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);
+var files = {}, Paths/*:any*/ = [], FileIndex = [], FullPaths = [], FullPathDir = {};
+read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex);
-build_full_paths(FileIndex, FullPaths, Paths);
-Paths.shift();
+build_full_paths(FileIndex, FullPathDir, FullPaths, Paths);
-var o = {
+var root_name = Paths.shift();
+Paths.root = root_name;
+
+/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
+var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name);
+
+return {
+ raw: {header: header, sectors: sectors},
FileIndex: FileIndex,
- FullPaths: FullPaths
+ FullPaths: FullPaths,
+ FullPathDir: FullPathDir,
+ find: find_path
};
-
-// $FlowIgnore
-if(options && options.raw) o.raw = {header: header, sectors: sectors};
-return o;
} // parse
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
-function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
- if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
+function check_get_mver(blob) {
// header signature 8
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
// clsid 16
- //blob.chk(HEADER_CLSID, 'CLSID: ');
- blob.l += 16;
+ blob.chk(HEADER_CLSID, 'CLSID: ');
// minor version 2
- var mver/*:number*/ = blob.read_shift(2, 'u');
+ var mver = blob.read_shift(2, 'u');
return [blob.read_shift(2,'u'), mver];
}
-function check_shifts(blob/*:CFBlob*/, mver/*:number*/)/*:void*/ {
+function check_shifts(blob, mver) {
var shift = 0x09;
// Byte Order
@@ -367,18 +167,18 @@ function check_shifts(blob/*:CFBlob*/, mver/*:number*/)/*:void*/ {
}
/** Break the file up into sectors */
-function sectorify(file/*:RawBytes*/, ssz/*:number*/)/*:Array*/ {
+function sectorify(file, ssz) {
var nsectors = Math.ceil(file.length/ssz)-1;
- var sectors/*:Array*/ = [];
+ var sectors = new Array(nsectors);
for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
sectors[nsectors-1] = file.slice(nsectors*ssz);
return sectors;
}
/* [MS-CFB] 2.6.4 Red-Black Tree */
-function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array*/, Paths/*:Array*/)/*:void*/ {
+function build_full_paths(FI, FPD, FP, Paths) {
var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
- var dad/*:Array*/ = [], q/*:Array*/ = [];
+ var dad = new Array(pl), q = new Array(pl);
for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
@@ -390,48 +190,53 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array*/, Paths/*:Arr
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
- if(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
- if(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
+ if(L !== -1) { dad[L] = dad[i]; q.push(L); }
+ if(R !== -1) { dad[R] = dad[i]; q.push(R); }
}
- for(i=1; i < pl; ++i) if(dad[i] === i) {
+ for(i=1; i !== pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
}
for(i=1; i < pl; ++i) {
if(FI[i].type === 0 /* unknown */) continue;
- j = i;
- if(j != dad[j]) do {
- j = dad[j];
+ j = dad[i];
+ if(j === 0) FP[i] = FP[0] + "/" + FP[i];
+ else while(j !== 0) {
FP[i] = FP[j] + "/" + FP[i];
- } while (j !== 0 && -1 !== dad[j] && j != dad[j]);
- dad[i] = -1;
+ j = dad[j];
+ }
+ dad[i] = 0;
}
FP[0] += "/";
for(i=1; i < pl; ++i) {
if(FI[i].type !== 2 /* stream */) FP[i] += "/";
+ FPD[FP[i]] = FI[i];
}
}
-function get_mfat_entry(entry/*:CFBEntry*/, payload/*:RawBytes*/, mini/*:?RawBytes*/)/*:CFBlob*/ {
- var start = entry.start, size = entry.size;
- //return (payload.slice(start*MSSZ, start*MSSZ + size)/*:any*/);
- var o = [];
- var idx = start;
- while(mini && size > 0 && idx >= 0) {
- o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));
- size -= MSSZ;
- idx = __readInt32LE(mini, idx * 4);
- }
- if(o.length === 0) return (new_buf(0)/*:any*/);
- return (bconcat(o).slice(0, entry.size)/*:any*/);
+/* [MS-CFB] 2.6.4 */
+function make_find_path(FullPaths, Paths, FileIndex, files, root_name) {
+ var UCFullPaths = new Array(FullPaths.length);
+ var UCPaths = new Array(Paths.length), i;
+ for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
+ for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
+ return function find_path(path/*:string*/) {
+ var k;
+ if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; }
+ else k = path.indexOf("/") !== -1;
+ var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!');
+ var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
+ if(w === -1) return null;
+ return k === true ? FileIndex[w] : files[Paths[w]];
+ };
}
/** Chase down the rest of the DIFAT chain to build a comprehensive list
- DIFAT chains by storing the next sector number as the last 32 bits */
-function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array*/, ssz/*:number*/, fat_addrs)/*:void*/ {
- var q/*:number*/ = ENDOFCHAIN;
+ DIFAT chains by storing the next sector number as the last 32 bytes */
+function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
+ var q;
if(idx === ENDOFCHAIN) {
if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
} else if(idx !== -1 /*FREESECT*/) {
@@ -446,10 +251,13 @@ function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array*/,
}
/** Follow the linked list of sectors for a given starting point */
-function get_sector_list(sectors/*:Array*/, start/*:number*/, fat_addrs/*:Array*/, ssz/*:number*/, chkd/*:?Array*/)/*:SectorEntry*/ {
- var buf/*:Array*/ = [], buf_chain/*:Array*/ = [];
- if(!chkd) chkd = [];
- var modulus = ssz - 1, j = 0, jj = 0;
+function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
+ var sl = sectors.length;
+ var buf, buf_chain;
+ if(!chkd) chkd = new Array(sl);
+ var modulus = ssz - 1, j, jj;
+ buf = [];
+ buf_chain = [];
for(j=start; j>=0;) {
chkd[j] = true;
buf[buf.length] = j;
@@ -464,45 +272,44 @@ function get_sector_list(sectors/*:Array*/, start/*:number*/, fat_addr
}
/** Chase down the sector linked lists */
-function make_sector_list(sectors/*:Array*/, dir_start/*:number*/, fat_addrs/*:Array*/, ssz/*:number*/)/*:SectorList*/ {
- var sl = sectors.length, sector_list/*:SectorList*/ = ([]/*:any*/);
- var chkd/*:Array*/ = [], buf/*:Array*/ = [], buf_chain/*:Array*/ = [];
- var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
+function make_sector_list(sectors, dir_start, fat_addrs, ssz/*:number*/)/*:any*/ {
+ var sl = sectors.length, sector_list = new Array(sl);
+ var chkd = new Array(sl), buf, buf_chain;
+ var modulus = ssz - 1, i, j, k, jj;
for(i=0; i < sl; ++i) {
- buf = ([]/*:Array*/);
+ buf = [];
k = (i + dir_start); if(k >= sl) k-=sl;
- if(chkd[k]) continue;
+ if(chkd[k] === true) continue;
buf_chain = [];
- var seen = [];
for(j=k; j>=0;) {
- seen[j] = true;
chkd[j] = true;
buf[buf.length] = j;
buf_chain.push(sectors[j]);
- var addr/*:number*/ = fat_addrs[Math.floor(j*4/ssz)];
+ var addr = fat_addrs[Math.floor(j*4/ssz)];
jj = ((j*4) & modulus);
if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
if(!sectors[addr]) break;
j = __readInt32LE(sectors[addr], jj);
- if(seen[j]) break;
}
- sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])}/*:SectorEntry*/);
+ sector_list[k] = {nodes: buf, data:__toBuffer([buf_chain])};
}
return sector_list;
}
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
-function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sectors/*:Array*/, Paths/*:Array*/, nmfs, files, FileIndex, mini) {
+function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex) {
+ var blob;
var minifat_store = 0, pl = (Paths.length?2:0);
var sector = sector_list[dir_start].data;
- var i = 0, namelen = 0, name;
+ var i = 0, namelen = 0, name, o, ctime, mtime;
for(; i < sector.length; i+= 128) {
- var blob/*:CFBlob*/ = /*::(*/sector.slice(i, i+128)/*:: :any)*/;
+ blob = sector.slice(i, i+128);
prep_blob(blob, 64);
namelen = blob.read_shift(2);
+ if(namelen === 0) continue;
name = __utf16le(blob,0,namelen-pl);
Paths.push(name);
- var o/*:CFBEntry*/ = ({
+ o = ({
name: name,
type: blob.read_shift(1),
color: blob.read_shift(1),
@@ -510,17 +317,18 @@ function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sector
R: blob.read_shift(4, 'i'),
C: blob.read_shift(4, 'i'),
clsid: blob.read_shift(16),
- state: blob.read_shift(4, 'i'),
- start: 0,
- size: 0
- });
- var ctime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
- if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
- var mtime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
- if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
+ state: blob.read_shift(4, 'i')
+ }/*:any*/);
+ ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
+ if(ctime !== 0) {
+ o.ctime = ctime; o.ct = read_date(blob, blob.l-8);
+ }
+ mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
+ if(mtime !== 0) {
+ o.mtime = mtime; o.mt = read_date(blob, blob.l-8);
+ }
o.start = blob.read_shift(4, 'i');
o.size = blob.read_shift(4, 'i');
- if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; }
if(o.type === 5) { /* root */
minifat_store = o.start;
if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
@@ -529,283 +337,39 @@ function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sector
o.storage = 'fat';
if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
sector_list[o.start].name = o.name;
- o.content = (sector_list[o.start].data.slice(0,o.size)/*:any*/);
+ o.content = sector_list[o.start].data.slice(0,o.size);
+ prep_blob(o.content, 0);
} else {
o.storage = 'minifat';
- if(o.size < 0) o.size = 0;
- else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
- o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
+ if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) {
+ o.content = sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size);
+ prep_blob(o.content, 0);
}
}
- if(o.content) prep_blob(o.content, 0);
files[name] = o;
FileIndex.push(o);
}
}
-function read_date(blob/*:RawBytes|CFBlob*/, offset/*:number*/)/*:Date*/ {
+function read_date(blob, offset) {
return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
}
-function read_file(filename/*:string*/, options/*:CFBReadOpts*/) {
- get_fs();
+var fs;
+function readFileSync(filename/*:string*/, options/*:any*/) {
+ if(fs === undefined) fs = require('fs');
return parse(fs.readFileSync(filename), options);
}
-function read(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) {
- switch(options && options.type || "base64") {
- case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return read_file(blob, options);
- case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64.decode(blob)), options);
- case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options);
+function readSync(blob/*:any*/, options/*:any*/) {
+ switch(options !== undefined && options.type !== undefined ? options.type : "base64") {
+ case "file": return readFileSync(blob, options);
+ case "base64": return parse(s2a(Base64.decode(blob)), options);
+ case "binary": return parse(s2a(blob), options);
}
- return parse(/*::typeof blob == 'string' ? new Buffer(blob, 'utf-8') : */blob, options);
+ return parse(blob);
}
-function init_cfb(cfb/*:CFBContainer*/, opts/*:?any*/)/*:void*/ {
- var o = opts || {}, root = o.root || "Root Entry";
- if(!cfb.FullPaths) cfb.FullPaths = [];
- if(!cfb.FileIndex) cfb.FileIndex = [];
- if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
- if(cfb.FullPaths.length === 0) {
- cfb.FullPaths[0] = root + "/";
- cfb.FileIndex[0] = ({ name: root, type: 5 }/*:any*/);
- }
- if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
- seed_cfb(cfb);
-}
-function seed_cfb(cfb/*:CFBContainer*/)/*:void*/ {
- var nm = "\u0001Sh33tJ5";
- if(CFB.find(cfb, "/" + nm)) return;
- var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
- cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }/*:any*/));
- cfb.FullPaths.push(cfb.FullPaths[0] + nm);
- rebuild_cfb(cfb);
-}
-function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
- init_cfb(cfb);
- var gc = false, s = false;
- for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
- var _file = cfb.FileIndex[i];
- switch(_file.type) {
- case 0:
- if(s) gc = true;
- else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
- break;
- case 1: case 2: case 5:
- s = true;
- if(isNaN(_file.R * _file.L * _file.C)) gc = true;
- if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
- break;
- default: gc = true; break;
- }
- }
- if(!gc && !f) return;
-
- var now = new Date(1987, 1, 19), j = 0;
- var data/*:Array<[string, CFBEntry]>*/ = [];
- for(i = 0; i < cfb.FullPaths.length; ++i) {
- if(cfb.FileIndex[i].type === 0) continue;
- data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
- }
- for(i = 0; i < data.length; ++i) {
- var dad = dirname(data[i][0]);
- s = false;
- for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
- if(!s) data.push([dad, ({
- name: filename(dad).replace("/",""),
- type: 1,
- clsid: HEADER_CLSID,
- ct: now, mt: now,
- content: null
- }/*:any*/)]);
- }
-
- data.sort(function(x,y) { return namecmp(x[0], y[0]); });
- cfb.FullPaths = []; cfb.FileIndex = [];
- for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
- for(i = 0; i < data.length; ++i) {
- var elt = cfb.FileIndex[i];
- var nm = cfb.FullPaths[i];
-
- elt.name = filename(nm).replace("/","");
- elt.L = elt.R = elt.C = -(elt.color = 1);
- elt.size = elt.content ? elt.content.length : 0;
- elt.start = 0;
- elt.clsid = (elt.clsid || HEADER_CLSID);
- if(i === 0) {
- elt.C = data.length > 1 ? 1 : -1;
- elt.size = 0;
- elt.type = 5;
- } else if(nm.slice(-1) == "/") {
- for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
- elt.C = j >= data.length ? -1 : j;
- for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
- elt.R = j >= data.length ? -1 : j;
- elt.type = 1;
- } else {
- if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
- elt.type = 2;
- }
- }
-
-}
-
-function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
- var _opts = options || {};
- rebuild_cfb(cfb);
- if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
- var L = (function(cfb/*:CFBContainer*/)/*:Array*/{
- var mini_size = 0, fat_size = 0;
- for(var i = 0; i < cfb.FileIndex.length; ++i) {
- var file = cfb.FileIndex[i];
- if(!file.content) continue;
- /*:: if(file.content == null) throw new Error("unreachable"); */
- var flen = file.content.length;
- if(flen > 0){
- if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
- else fat_size += (flen + 0x01FF) >> 9;
- }
- }
- var dir_cnt = (cfb.FullPaths.length +3) >> 2;
- var mini_cnt = (mini_size + 7) >> 3;
- var mfat_cnt = (mini_size + 0x7F) >> 7;
- var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
- var fat_cnt = (fat_base + 0x7F) >> 7;
- var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
- while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
- var L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
- cfb.FileIndex[0].size = mini_size << 6;
- L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
- return L;
- })(cfb);
- var o = new_buf(L[7] << 9);
- var i = 0, T = 0;
- {
- for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
- for(i = 0; i < 8; ++i) o.write_shift(2, 0);
- o.write_shift(2, 0x003E);
- o.write_shift(2, 0x0003);
- o.write_shift(2, 0xFFFE);
- o.write_shift(2, 0x0009);
- o.write_shift(2, 0x0006);
- for(i = 0; i < 3; ++i) o.write_shift(2, 0);
- o.write_shift(4, 0);
- o.write_shift(4, L[2]);
- o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
- o.write_shift(4, 0);
- o.write_shift(4, 1<<12);
- o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
- o.write_shift(4, L[3]);
- o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
- o.write_shift(4, L[1]);
- for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
- }
- if(L[1]) {
- for(T = 0; T < L[1]; ++T) {
- for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
- o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
- }
- }
- var chainit = function(w/*:number*/)/*:void*/ {
- for(T += w; i> 9);
- }
- chainit((L[6] + 7) >> 3);
- while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
- T = i = 0;
- for(j = 0; j < cfb.FileIndex.length; ++j) {
- file = cfb.FileIndex[j];
- if(!file.content) continue;
- /*:: if(file.content == null) throw new Error("unreachable"); */
- flen = file.content.length;
- if(!flen || flen >= 0x1000) continue;
- file.start = T;
- chainit((flen + 0x3F) >> 6);
- }
- while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
- for(i = 0; i < L[4]<<2; ++i) {
- var nm = cfb.FullPaths[i];
- if(!nm || nm.length === 0) {
- for(j = 0; j < 17; ++j) o.write_shift(4, 0);
- for(j = 0; j < 3; ++j) o.write_shift(4, -1);
- for(j = 0; j < 12; ++j) o.write_shift(4, 0);
- continue;
- }
- file = cfb.FileIndex[i];
- if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
- var _nm/*:string*/ = (i === 0 && _opts.root) || file.name;
- flen = 2*(_nm.length+1);
- o.write_shift(64, _nm, "utf16le");
- o.write_shift(2, flen);
- o.write_shift(1, file.type);
- o.write_shift(1, file.color);
- o.write_shift(-4, file.L);
- o.write_shift(-4, file.R);
- o.write_shift(-4, file.C);
- if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
- else o.write_shift(16, file.clsid, "hex");
- o.write_shift(4, file.state || 0);
- o.write_shift(4, 0); o.write_shift(4, 0);
- o.write_shift(4, 0); o.write_shift(4, 0);
- o.write_shift(4, file.start);
- o.write_shift(4, file.size); o.write_shift(4, 0);
- }
- for(i = 1; i < cfb.FileIndex.length; ++i) {
- file = cfb.FileIndex[i];
- /*:: if(!file.content) throw new Error("unreachable"); */
- if(file.size >= 0x1000) {
- o.l = (file.start+1) << 9;
- for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
- for(; j & 0x1FF; ++j) o.write_shift(1, 0);
- }
- }
- for(i = 1; i < cfb.FileIndex.length; ++i) {
- file = cfb.FileIndex[i];
- /*:: if(!file.content) throw new Error("unreachable"); */
- if(file.size > 0 && file.size < 0x1000) {
- for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
- for(; j & 0x3F; ++j) o.write_shift(1, 0);
- }
- }
- while(o.l < o.length) o.write_shift(1, 0);
- return o;
-}
-/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
-function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ {
- var UCFullPaths/*:Array*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
- var UCPaths/*:Array*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
- var k/*:boolean*/ = false;
- if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
- else k = path.indexOf("/") !== -1;
- var UCPath/*:string*/ = path.toUpperCase();
- var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
- if(w !== -1) return cfb.FileIndex[w];
-
- var m = !UCPath.match(chr1);
- UCPath = UCPath.replace(chr0,'');
- if(m) UCPath = UCPath.replace(chr1,'!');
- for(w = 0; w < UCFullPaths.length; ++w) {
- if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
- if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
- }
- return null;
-}
/** CFB Constants */
var MSSZ = 64; /* Mini Sector Size = 1<<6 */
//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
@@ -813,7 +377,6 @@ var MSSZ = 64; /* Mini Sector Size = 1<<6 */
var ENDOFCHAIN = -2;
/* 2.2 Compound File Header */
var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
-var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
var HEADER_CLSID = '00000000000000000000000000000000';
var consts = {
/* 2.1 Compund File Sector Numbers and Types */
@@ -832,648 +395,13 @@ var consts = {
EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
};
-function write_file(cfb/*:CFBContainer*/, filename/*:string*/, options/*:CFBWriteOpts*/)/*:void*/ {
- get_fs();
- var o = _write(cfb, options);
- /*:: if(typeof Buffer == 'undefined' || !Buffer.isBuffer(o) || !(o instanceof Buffer)) throw new Error("unreachable"); */
- fs.writeFileSync(filename, o);
-}
-
-function a2s(o/*:RawBytes*/)/*:string*/ {
- var out = new Array(o.length);
- for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
- return out.join("");
-}
-
-function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
- var o = _write(cfb, options);
- switch(options && options.type) {
- case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o;
- case "binary": return a2s(o);
- case "base64": return Base64.encode(a2s(o));
- }
- return o;
-}
-/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
-var _zlib;
-function use_zlib(zlib) { try {
- var InflateRaw = zlib.InflateRaw;
- var InflRaw = new InflateRaw();
- InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
- if(InflRaw.bytesRead) _zlib = zlib;
- else throw new Error("zlib does not expose bytesRead");
-} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
-
-function _inflateRawSync(payload, usz) {
- if(!_zlib) return _inflate(payload, usz);
- var InflateRaw = _zlib.InflateRaw;
- var InflRaw = new InflateRaw();
- var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
- payload.l += InflRaw.bytesRead;
- return out;
-}
-
-function _deflateRawSync(payload) {
- return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
-}
-var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
-
-/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
-var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
-
-/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
-var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
-
-function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
-
-var use_typed_arrays = typeof Uint8Array !== 'undefined';
-
-var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
-for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
-
-function bit_swap_n(n, b) {
- var rev = bitswap8[n & 0xFF];
- if(b <= 8) return rev >>> (8-b);
- rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
- if(b <= 16) return rev >>> (16-b);
- rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
- return rev >>> (24-b);
-}
-
-/* helpers for unaligned bit reads */
-function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
-function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
-function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
-function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
-function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
-
-/* works up to n = 3 * 8 + 1 = 25 */
-function read_bits_n(buf, bl, n) {
- var w = (bl&7), h = (bl>>>3), f = ((1<>> w;
- if(n < 8 - w) return v & f;
- v |= buf[h+1]<<(8-w);
- if(n < 16 - w) return v & f;
- v |= buf[h+2]<<(16-w);
- if(n < 24 - w) return v & f;
- v |= buf[h+3]<<(24-w);
- return v & f;
-}
-
-/* until ArrayBuffer#realloc is a thing, fake a realloc */
-function realloc(b, sz/*:number*/) {
- var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
- if(L >= sz) return b;
- if(has_buf) {
- var o = new_unsafe_buf(M);
- // $FlowIgnore
- if(b.copy) b.copy(o);
- else for(; i < b.length; ++i) o[i] = b[i];
- return o;
- } else if(use_typed_arrays) {
- var a = new Uint8Array(M);
- if(a.set) a.set(b);
- else for(; i < b.length; ++i) a[i] = b[i];
- return a;
- }
- b.length = M;
- return b;
-}
-
-/* zero-filled arrays for older browsers */
-function zero_fill_array(n) {
- var o = new Array(n);
- for(var i = 0; i < n; ++i) o[i] = 0;
- return o;
-}var _deflate = (function() {
-var _deflateRaw = (function() {
- return function deflateRaw(data, out) {
- var boff = 0;
- while(boff < data.length) {
- var L = Math.min(0xFFFF, data.length - boff);
- var h = boff + L == data.length;
- /* TODO: this is only type 0 stored */
- out.write_shift(1, +h);
- out.write_shift(2, L);
- out.write_shift(2, (~L) & 0xFFFF);
- while(L-- > 0) out[out.l++] = data[boff++];
- }
- return out.l;
- };
-})();
-
-return function(data) {
- var buf = new_buf(50+Math.floor(data.length*1.1));
- var off = _deflateRaw(data, buf);
- return buf.slice(0, off);
-};
-})();
-/* modified inflate function also moves original read head */
-
-/* build tree (used for literals and lengths) */
-function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
- var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
-
- var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
- for(i = 0; i < 32; ++i) bl_count[i] = 0;
-
- for(i = L; i < MAX; ++i) clens[i] = 0;
- L = clens.length;
-
- var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
-
- /* build code tree */
- for(i = 0; i < L; ++i) {
- bl_count[(w = clens[i])]++;
- if(maxlen < w) maxlen = w;
- ctree[i] = 0;
- }
- bl_count[0] = 0;
- for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
- for(i = 0; i < L; ++i) {
- ccode = clens[i];
- if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
- }
-
- /* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
- var cleni = 0;
- for(i = 0; i < L; ++i) {
- cleni = clens[i];
- if(cleni != 0) {
- ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
- for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
- cmap[ccode|(j<*/ = [];
- var i = 0;
- for(;i<32; i++) dlens.push(5);
- build_tree(dlens, fix_dmap, 32);
-
- var clens/*:Array*/ = [];
- i = 0;
- for(; i<=143; i++) clens.push(8);
- for(; i<=255; i++) clens.push(9);
- for(; i<=279; i++) clens.push(7);
- for(; i<=287; i++) clens.push(8);
- build_tree(clens, fix_lmap, 288);
-})();
-
-var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
-var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
-var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
-var dyn_len_1 = 1, dyn_len_2 = 1;
-
-/* 5.5.3 Expanding Huffman Codes */
-function dyn(data, boff/*:number*/) {
- /* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
- var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
- var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
- var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
- var w = 0;
-
- /* grab and store code lengths */
- var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
- var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
- var maxlen = 1;
- var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
- var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
- var L = clens.length; /* 19 */
- for(var i = 0; i < _HCLEN; ++i) {
- clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
- if(maxlen < w) maxlen = w;
- bl_count[w]++;
- boff += 3;
- }
-
- /* build code tree */
- var ccode = 0;
- bl_count[0] = 0;
- for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
- for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
- /* cmap[7 bits from stream] = (off&7) + (lit<<3) */
- var cleni = 0;
- for(i = 0; i < L; ++i) {
- cleni = clens[i];
- if(cleni != 0) {
- ccode = bitswap8[ctree[i]]>>(8-cleni);
- for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<*/ = [];
- maxlen = 1;
- for(; hcodes.length < _HLIT + _HDIST;) {
- ccode = dyn_cmap[read_bits_7(data, boff)];
- boff += ccode & 7;
- switch((ccode >>>= 3)) {
- case 16:
- w = 3 + read_bits_2(data, boff); boff += 2;
- ccode = hcodes[hcodes.length - 1];
- while(w-- > 0) hcodes.push(ccode);
- break;
- case 17:
- w = 3 + read_bits_3(data, boff); boff += 3;
- while(w-- > 0) hcodes.push(0);
- break;
- case 18:
- w = 11 + read_bits_7(data, boff); boff += 7;
- while(w -- > 0) hcodes.push(0);
- break;
- default:
- hcodes.push(ccode);
- if(maxlen < ccode) maxlen = ccode;
- break;
- }
- }
-
- /* build literal / length trees */
- var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
- for(i = _HLIT; i < 286; ++i) h1[i] = 0;
- for(i = _HDIST; i < 30; ++i) h2[i] = 0;
- dyn_len_1 = build_tree(h1, dyn_lmap, 286);
- dyn_len_2 = build_tree(h2, dyn_dmap, 30);
- return boff;
-}
-
-/* return [ data, bytesRead ] */
-function inflate(data, usz/*:number*/) {
- /* shortcircuit for empty buffer [0x03, 0x00] */
- if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
-
- /* bit offset */
- var boff = 0;
-
- /* header includes final bit and type bits */
- var header = 0;
-
- var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
- var woff = 0;
- var OL = outbuf.length>>>0;
- var max_len_1 = 0, max_len_2 = 0;
-
- while((header&1) == 0) {
- header = read_bits_3(data, boff); boff += 3;
- if((header >>> 1) == 0) {
- /* Stored block */
- if(boff & 7) boff += 8 - (boff&7);
- /* 2 bytes sz, 2 bytes bit inverse */
- var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
- boff += 32;
- /* push sz bytes */
- if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
- if(typeof data.copy === 'function') {
- // $FlowIgnore
- data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
- woff += sz; boff += 8*sz;
- } else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
- continue;
- } else if((header >>> 1) == 1) {
- /* Fixed Huffman */
- max_len_1 = 9; max_len_2 = 5;
- } else {
- /* Dynamic Huffman */
- boff = dyn(data, boff);
- max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
- }
- if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
- for(;;) { // while(true) is apparently out of vogue in modern JS circles
- /* ingest code and move read head */
- var bits = read_bits_n(data, boff, max_len_1);
- var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
- boff += code & 15; code >>>= 4;
- /* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
- if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
- else if(code == 256) break;
- else {
- code -= 257;
- var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
- var tgt = woff + LEN_LN[code];
- /* length extra bits */
- if(len_eb > 0) {
- tgt += read_bits_n(data, boff, len_eb);
- boff += len_eb;
- }
-
- /* dist code */
- bits = read_bits_n(data, boff, max_len_2);
- code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
- boff += code & 15; code >>>= 4;
- var dst_eb = (code < 4 ? 0 : (code-2)>>1);
- var dst = DST_LN[code];
- /* dist extra bits */
- if(dst_eb > 0) {
- dst += read_bits_n(data, boff, dst_eb);
- boff += dst_eb;
- }
-
- /* in the common case, manual byte copy is faster than TA set / Buffer copy */
- if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
- while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
- }
- }
- }
- return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
-}
-
-function _inflate(payload, usz) {
- var data = payload.slice(payload.l||0);
- var out = inflate(data, usz);
- payload.l += out[1];
- return out[0];
-}
-
-function warn_or_throw(wrn, msg) {
- if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
- else throw new Error(msg);
-}
-
-function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
- var blob/*:CFBlob*/ = /*::(*/file/*:: :any)*/;
- prep_blob(blob, 0);
-
- var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array*/ = [];
- var o = {
- FileIndex: FileIndex,
- FullPaths: FullPaths
- };
- init_cfb(o, { root: options.root });
-
- /* find end of central directory, start just after signature */
- var i = blob.length - 4;
- while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
- blob.l = i + 4;
-
- /* parse end of central directory */
- blob.l += 4;
- var fcnt = blob.read_shift(2);
- blob.l += 6;
- var start_cd = blob.read_shift(4);
-
- /* parse central directory */
- blob.l = start_cd;
-
- for(i = 0; i < fcnt; ++i) {
- /* trust local file header instead of CD entry */
- blob.l += 20;
- var csz = blob.read_shift(4);
- var usz = blob.read_shift(4);
- var namelen = blob.read_shift(2);
- var efsz = blob.read_shift(2);
- var fcsz = blob.read_shift(2);
- blob.l += 8;
- var offset = blob.read_shift(4);
- var EF = parse_extra_field(/*::(*/blob.slice(blob.l+namelen, blob.l+namelen+efsz)/*:: :any)*/);
- blob.l += namelen + efsz + fcsz;
-
- var L = blob.l;
- blob.l = offset + 4;
- parse_local_file(blob, csz, usz, o, EF);
- blob.l = L;
- }
-
- return o;
-}
-
-
-/* head starts just after local file header signature */
-function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:CFBContainer*/, EF) {
- /* [local file header] */
- blob.l += 2;
- var flags = blob.read_shift(2);
- var meth = blob.read_shift(2);
- var date = parse_dos_date(blob);
-
- if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
- var crc32 = blob.read_shift(4);
- var _csz = blob.read_shift(4);
- var _usz = blob.read_shift(4);
-
- var namelen = blob.read_shift(2);
- var efsz = blob.read_shift(2);
-
- // TODO: flags & (1<<11) // UTF8
- var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
- if(efsz) {
- var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/);
- if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
- if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
- }
- blob.l += efsz;
-
- /* [encryption header] */
-
- /* [file data] */
- var data = blob.slice(blob.l, blob.l + _csz);
- switch(meth) {
- case 8: data = _inflateRawSync(blob, _usz); break;
- case 0: break;
- default: throw new Error("Unsupported ZIP Compression method " + meth);
- }
-
- /* [data descriptor] */
- var wrn = false;
- if(flags & 8) {
- crc32 = blob.read_shift(4);
- if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
- _csz = blob.read_shift(4);
- _usz = blob.read_shift(4);
- }
-
- if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
- if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
- var _crc32 = CRC32.buf(data, 0);
- if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
- cfb_add(o, name, data, {unsafe: true, mt: date});
-}
-function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
- var _opts = options || {};
- var out = [], cdirs = [];
- var o/*:CFBlob*/ = new_buf(1);
- var method = (_opts.compression ? 8 : 0), flags = 0;
- var desc = false;
- if(desc) flags |= 8;
- var i = 0, j = 0;
-
- var start_cd = 0, fcnt = 0;
- var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
- var crcs = [];
- var sz_cd = 0;
-
- for(i = 1; i < cfb.FullPaths.length; ++i) {
- fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
- if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
- var start = start_cd;
-
- /* TODO: CP437 filename */
- var namebuf = new_buf(fp.length);
- for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
- namebuf = namebuf.slice(0, namebuf.l);
- crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
-
- var outbuf = fi.content/*::||[]*/;
- if(method == 8) outbuf = _deflateRawSync(outbuf);
-
- /* local file header */
- o = new_buf(30);
- o.write_shift(4, 0x04034b50);
- o.write_shift(2, 20);
- o.write_shift(2, flags);
- o.write_shift(2, method);
- /* TODO: last mod file time/date */
- if(fi.mt) write_dos_date(o, fi.mt);
- else o.write_shift(4, 0);
- o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
- o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
- o.write_shift(4, (flags & 8) ? 0 : /*::(*/fi.content/*::||[])*/.length);
- o.write_shift(2, namebuf.length);
- o.write_shift(2, 0);
-
- start_cd += o.length;
- out.push(o);
- start_cd += namebuf.length;
- out.push(namebuf);
-
- /* TODO: encryption header ? */
- start_cd += outbuf.length;
- out.push(outbuf);
-
- /* data descriptor */
- if(flags & 8) {
- o = new_buf(12);
- o.write_shift(-4, crcs[fcnt]);
- o.write_shift(4, outbuf.length);
- o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
- start_cd += o.l;
- out.push(o);
- }
-
- /* central directory */
- o = new_buf(46);
- o.write_shift(4, 0x02014b50);
- o.write_shift(2, 0);
- o.write_shift(2, 20);
- o.write_shift(2, flags);
- o.write_shift(2, method);
- o.write_shift(4, 0); /* TODO: last mod file time/date */
- o.write_shift(-4, crcs[fcnt]);
-
- o.write_shift(4, outbuf.length);
- o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
- o.write_shift(2, namebuf.length);
- o.write_shift(2, 0);
- o.write_shift(2, 0);
- o.write_shift(2, 0);
- o.write_shift(2, 0);
- o.write_shift(4, 0);
- o.write_shift(4, start);
-
- sz_cd += o.l;
- cdirs.push(o);
- sz_cd += namebuf.length;
- cdirs.push(namebuf);
- ++fcnt;
- }
-
- /* end of central directory */
- o = new_buf(22);
- o.write_shift(4, 0x06054b50);
- o.write_shift(2, 0);
- o.write_shift(2, 0);
- o.write_shift(2, fcnt);
- o.write_shift(2, fcnt);
- o.write_shift(4, sz_cd);
- o.write_shift(4, start_cd);
- o.write_shift(2, 0);
-
- return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
-}
-function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
- var o/*:CFBContainer*/ = ({}/*:any*/);
- init_cfb(o, opts);
- return o;
-}
-
-function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ {
- var unsafe = opts && opts.unsafe;
- if(!unsafe) init_cfb(cfb);
- var file = !unsafe && CFB.find(cfb, name);
- if(!file) {
- var fpath/*:string*/ = cfb.FullPaths[0];
- if(name.slice(0, fpath.length) == fpath) fpath = name;
- else {
- if(fpath.slice(-1) != "/") fpath += "/";
- fpath = (fpath + name).replace("//","/");
- }
- file = ({name: filename(name), type: 2}/*:any*/);
- cfb.FileIndex.push(file);
- cfb.FullPaths.push(fpath);
- if(!unsafe) CFB.utils.cfb_gc(cfb);
- }
- /*:: if(!file) throw new Error("unreachable"); */
- file.content = (content/*:any*/);
- file.size = content ? content.length : 0;
- if(opts) {
- if(opts.CLSID) file.clsid = opts.CLSID;
- if(opts.mt) file.mt = opts.mt;
- if(opts.ct) file.ct = opts.ct;
- }
- return file;
-}
-
-function cfb_del(cfb/*:CFBContainer*/, name/*:string*/)/*:boolean*/ {
- init_cfb(cfb);
- var file = CFB.find(cfb, name);
- if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
- cfb.FileIndex.splice(j, 1);
- cfb.FullPaths.splice(j, 1);
- return true;
- }
- return false;
-}
-
-function cfb_mov(cfb/*:CFBContainer*/, old_name/*:string*/, new_name/*:string*/)/*:boolean*/ {
- init_cfb(cfb);
- var file = CFB.find(cfb, old_name);
- if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
- cfb.FileIndex[j].name = filename(new_name);
- cfb.FullPaths[j] = new_name;
- return true;
- }
- return false;
-}
-
-function cfb_gc(cfb/*:CFBContainer*/)/*:void*/ { rebuild_cfb(cfb, true); }
-
-exports.find = find;
-exports.read = read;
+exports.read = readSync;
exports.parse = parse;
-exports.write = write;
-exports.writeFile = write_file;
exports.utils = {
- cfb_new: cfb_new,
- cfb_add: cfb_add,
- cfb_del: cfb_del,
- cfb_mov: cfb_mov,
- cfb_gc: cfb_gc,
ReadShift: ReadShift,
CheckField: CheckField,
prep_blob: prep_blob,
bconcat: bconcat,
- use_zlib: use_zlib,
- _deflateRaw: _deflate,
- _inflateRaw: _inflate,
consts: consts
};
diff --git a/bits/19_fsutils.js b/bits/19_fsutils.js
deleted file mode 100644
index 70dc576..0000000
--- a/bits/19_fsutils.js
+++ /dev/null
@@ -1,61 +0,0 @@
-var _fs;
-if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
-
-/* normalize data for blob ctor */
-function blobify(data) {
- if(typeof data === "string") return s2ab(data);
- if(Array.isArray(data)) return a2u(data);
- return data;
-}
-/* write or download file */
-function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
- /*global IE_SaveFile, Blob, navigator, saveAs, document, File, chrome */
- if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
- var data = (enc == "utf8") ? utf8write(payload) : payload;
- /*:: declare var IE_SaveFile: any; */
- if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
- if(typeof Blob !== 'undefined') {
- var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
- /*:: declare var navigator: any; */
- if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
- /*:: declare var saveAs: any; */
- if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
- if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
- var url = URL.createObjectURL(blob);
- /*:: declare var chrome: any; */
- if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
- if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
- return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
- }
- var a = document.createElement("a");
- if(a.download != null) {
- /*:: if(document.body == null) throw new Error("unreachable"); */
- a.download = fname; a.href = url; document.body.appendChild(a); a.click();
- /*:: if(document.body == null) throw new Error("unreachable"); */ document.body.removeChild(a);
- if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
- return url;
- }
- }
- }
- // $FlowIgnore
- if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
- // $FlowIgnore
- var out = File(fname); out.open("w"); out.encoding = "binary";
- if(Array.isArray(payload)) payload = a2s(payload);
- out.write(payload); out.close(); return payload;
- } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
- throw new Error("cannot save file " + fname);
-}
-
-/* read binary data from file */
-function read_binary(path/*:string*/) {
- if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
- // $FlowIgnore
- if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
- // $FlowIgnore
- var infile = File(path); infile.open("r"); infile.encoding = "binary";
- var data = infile.read(); infile.close();
- return data;
- } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
- throw new Error("Cannot access file " + path);
-}
diff --git a/bits/20_jsutils.js b/bits/20_jsutils.js
index f9a2db9..92c8156 100644
--- a/bits/20_jsutils.js
+++ b/bits/20_jsutils.js
@@ -1,12 +1,10 @@
-function keys(o/*:any*/)/*:Array*/ {
- var ks = Object.keys(o), o2 = [];
- for(var i = 0; i < ks.length; ++i) if(Object.prototype.hasOwnProperty.call(o, ks[i])) o2.push(ks[i]);
- return o2;
-}
+function isval(x/*:?any*/)/*:boolean*/ { return x !== undefined && x !== null; }
+
+function keys(o/*:any*/)/*:Array*/ { return Object.keys(o); }
function evert_key(obj/*:any*/, key/*:string*/)/*:EvertType*/ {
var o = ([]/*:any*/), K = keys(obj);
- for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
+ for(var i = 0; i !== K.length; ++i) o[obj[K[i]][key]] = K[i];
return o;
}
@@ -32,21 +30,15 @@ function evert_arr(obj/*:any*/)/*:EvertArrType*/ {
}
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
+var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
var epoch = v.getTime();
- if(date1904) epoch -= 1462*24*60*60*1000;
- var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
+ if(date1904) epoch += 1462*24*60*60*1000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
}
-var refdate = new Date();
-var dnthresh = basedate.getTime() + (refdate.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
-var refoffset = refdate.getTimezoneOffset();
function numdate(v/*:number*/)/*:Date*/ {
var out = new Date();
out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
- if (out.getTimezoneOffset() !== refoffset) {
- out.setTime(out.getTime() + (out.getTimezoneOffset() - refoffset) * 60000);
- }
return out;
}
@@ -59,9 +51,9 @@ function parse_isodur(s) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
- switch(m[i].slice(m[i].length-1)) {
+ switch(m[i].substr(m[i].length-1)) {
case 'Y':
- throw new Error("Unsupported ISO Duration Field: " + m[i].slice(m[i].length-1));
+ throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
@@ -80,7 +72,7 @@ function parse_isodur(s) {
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
var good_pd = good_pd_date.getFullYear() == 2017;
-/* parses a date as a local date */
+/* parses aa date as a local date */
function parseDate(str/*:string|Date*/, fixdate/*:?number*/)/*:Date*/ {
var d = new Date(str);
if(good_pd) {
@@ -96,9 +88,7 @@ function parseDate(str/*:string|Date*/, fixdate/*:?number*/)/*:Date*/ {
d.setFullYear(d.getFullYear() + 100); return d;
}
var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
- var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
- if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
- return out;
+ return new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
}
function cc2str(arr/*:Array*/)/*:string*/ {
@@ -107,29 +97,23 @@ function cc2str(arr/*:Array*/)/*:string*/ {
return o;
}
+function str2cc(str) {
+ var o = [];
+ for(var i = 0; i != str.length; ++i) o.push(str.charCodeAt(i));
+ return o;
+}
+
function dup(o/*:any*/)/*:any*/ {
if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o));
if(typeof o != 'object' || o == null) return o;
- if(o instanceof Date) return new Date(o.getTime());
var out = {};
- for(var k in o) if(Object.prototype.hasOwnProperty.call(o, k)) out[k] = dup(o[k]);
+ for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
return out;
}
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
/* TODO: stress test */
-function fuzzynum(s/*:string*/)/*:number*/ {
- var v/*:number*/ = Number(s);
- if(!isNaN(v)) return v;
- if(!/\d/.test(s)) return v;
- var wt = 1;
- var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
- if(!isNaN(v = Number(ss))) return v / wt;
- ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
- if(!isNaN(v = Number(ss))) return v / wt;
- return v;
-}
function fuzzydate(s/*:string*/)/*:Date*/ {
var o = new Date(s), n = new Date(NaN);
var y = o.getYear(), m = o.getMonth(), d = o.getDate();
@@ -137,14 +121,7 @@ function fuzzydate(s/*:string*/)/*:Date*/ {
if(y < 0 || y > 8099) return n;
if((m > 0 || d > 1) && y != 101) return o;
if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
- if(s.match(/[^-0-9:,\/\\]/)) return n;
- return o;
+ if(!s.match(/[a-zA-Z]/)) return o;
+ return n;
}
-var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
-function split_regex(str/*:string*/, re, def/*:string*/)/*:Array*/ {
- if(safe_split_regex || typeof re == "string") return str.split(re);
- var p = str.split(re), o = [p[0]];
- for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
- return o;
-}
diff --git a/bits/21_ziputils.js b/bits/21_ziputils.js
index dde3ad7..14aa2d3 100644
--- a/bits/21_ziputils.js
+++ b/bits/21_ziputils.js
@@ -4,7 +4,6 @@ function getdatastr(data)/*:?string*/ {
if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
if(data.asBinary) return debom(data.asBinary());
if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
- if(data.content && data.type) return debom(cc2str(data.content));
return null;
}
@@ -14,10 +13,9 @@ function getdatabin(data) {
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer();
if(data._data && data._data.getContent) {
var o = data._data.getContent();
- if(typeof o == "string") return char_codes(o);
+ if(typeof o == "string") return str2cc(o);
return Array.prototype.slice.call(o);
}
- if(data.content && data.type) return data.content;
return null;
}
@@ -26,7 +24,7 @@ function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getda
/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
/* OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file/*:string*/) {
- var k = zip.FullPaths || keys(zip.files);
+ var k = keys(zip.files);
var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
for(var i=0; i\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
-var tagregex=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s*[\/\?]?>/mg;
-
-if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
+var attregexg=/([^"\s?>\/]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
+var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
-function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/, skip_LC/*:?boolean*/)/*:any*/ {
+function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ {
var z = ({}/*:any*/);
var eq = 0, c = 0;
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
- if(!skip_root) z[0] = tag.slice(0, eq);
+ if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
- q = cc.slice(0,c).trim();
- while(cc.charCodeAt(c+1) == 32) ++c;
+ q = cc.substr(0,c);
quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
- v = cc.slice(c+1+quot, cc.length-quot);
+ v = cc.substring(c+1+quot, cc.length-quot);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) {
- if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
+ if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_")); // from ods
z[q] = v;
- if(!skip_LC) z[q.toLowerCase()] = v;
}
else {
- var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
- if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
+ var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
+ if(z[k] && q.substr(j-3,3) == "ext") continue; // from ods
z[k] = v;
- if(!skip_LC) z[k.toLowerCase()] = v;
}
}
return z;
@@ -48,31 +42,24 @@ var rencoding = evert(encodings);
// TODO: CP remap (need to read file version to determine OS)
var unescapexml/*:StringConv*/ = (function() {
/* 22.4.2.4 bstr (Basic String) */
- var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/ig, coderegex = /_x([\da-fA-F]{4})_/ig;
+ var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
return function unescapexml(text/*:string*/)/*:string*/ {
- var s = text + '', i = s.indexOf("-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
- var j = s.indexOf("]]>");
- return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
+ var s = text + '';
+ return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
};
})();
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
-function escapexml(text/*:string*/)/*:string*/{
+function escapexml(text/*:string*/, xml/*:?boolean*/)/*:string*/{
var s = text + '';
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
}
function escapexmltag(text/*:string*/)/*:string*/{ return escapexml(text).replace(/ /g,"_x0020_"); }
var htmlcharegex = /[\u0000-\u001f]/g;
-function escapehtml(text/*:string*/)/*:string*/{
+function escapehtml(text){
var s = text + '';
- return s.replace(decregex, function(y) { return rencoding[y]; }).replace(/\n/g, "
").replace(htmlcharegex,function(s) { return "" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + ";"; });
-}
-
-function escapexlml(text/*:string*/)/*:string*/{
- var s = text + '';
- return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
+ return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + ";"; });
}
/* TODO: handle codepages */
@@ -85,7 +72,7 @@ var xlml_unfixstr/*:StringConv*/ = (function() {
return function xlml_unfixstr(str/*:string*/)/*:string*/ { return str.replace(/(\r\n|[\r\n])/g,"\
"); };
})();
-function parsexmlbool(value/*:any*/)/*:boolean*/ {
+function parsexmlbool(value/*:any*/, tag/*:?string*/)/*:boolean*/ {
switch(value) {
case 1: case true: case '1': case 'true': case 'TRUE': return true;
/* case '0': case 'false': case 'FALSE':*/
@@ -93,13 +80,13 @@ function parsexmlbool(value/*:any*/)/*:boolean*/ {
}
}
-var utf8read/*:StringConv*/ = function utf8reada(orig/*:string*/)/*:string*/ {
+var utf8read/*:StringConv*/ = function utf8reada(orig) {
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
while (i < orig.length) {
c = orig.charCodeAt(i++);
if (c < 128) { out += String.fromCharCode(c); continue; }
d = orig.charCodeAt(i++);
- if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
+ if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
e = orig.charCodeAt(i++);
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
f = orig.charCodeAt(i++);
@@ -110,35 +97,10 @@ var utf8read/*:StringConv*/ = function utf8reada(orig/*:string*/)/*:string*/ {
return out;
};
-var utf8write/*:StringConv*/ = function(orig/*:string*/)/*:string*/ {
- var out/*:Array*/ = [], i = 0, c = 0, d = 0;
- while(i < orig.length) {
- c = orig.charCodeAt(i++);
- switch(true) {
- case c < 128: out.push(String.fromCharCode(c)); break;
- case c < 2048:
- out.push(String.fromCharCode(192 + (c >> 6)));
- out.push(String.fromCharCode(128 + (c & 63)));
- break;
- case c >= 55296 && c < 57344:
- c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
- out.push(String.fromCharCode(240 + ((d >>18) & 7)));
- out.push(String.fromCharCode(144 + ((d >>12) & 63)));
- out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
- out.push(String.fromCharCode(128 + (d & 63)));
- break;
- default:
- out.push(String.fromCharCode(224 + (c >> 12)));
- out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
- out.push(String.fromCharCode(128 + (c & 63)));
- }
- }
- return out.join("");
-};
if(has_buf) {
var utf8readb = function utf8readb(data) {
- var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
+ var out = new Buffer(2*data.length), w, i, j = 1, k = 0, ww=0, c;
for(i = 0; i < data.length; i+=j) {
j = 1;
if((c=data.charCodeAt(i)) < 128) w = c;
@@ -155,89 +117,59 @@ if(has_buf) {
};
var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
- var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
+ // $FlowIgnore
+ var utf8readc = function utf8readc(data) { return Buffer(data, 'binary').toString('utf8'); };
if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
-
- utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
}
// matches ... extracts content
var matchtag = (function() {
var mtcache/*:{[k:string]:RegExp}*/ = ({}/*:any*/);
- return function matchtag(f/*:string*/,g/*:?string*/)/*:RegExp*/ {
+ return function matchtag(f,g/*:?string*/)/*:RegExp*/ {
var t = f+"|"+(g||"");
if(mtcache[t]) return mtcache[t];
- return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)(?:\\w+:)?'+f+'>',((g||"")/*:any*/)));
- };
-})();
-
-var htmldecode/*:{(s:string):string}*/ = (function() {
- var entities/*:Array<[RegExp, string]>*/ = [
- ['nbsp', ' '], ['middot', '·'],
- ['quot', '"'], ['apos', "'"], ['gt', '>'], ['lt', '<'], ['amp', '&']
- ].map(function(x/*:[string, string]*/) { return [new RegExp('&' + x[0] + ';', "ig"), x[1]]; });
- return function htmldecode(str/*:string*/)/*:string*/ {
- var o = str
- // Remove new lines and spaces from start of content
- .replace(/^[\t\n\r ]+/, "")
- // Remove new lines and spaces from end of content
- .replace(/[\t\n\r ]+$/,"")
- // Added line which removes any white space characters after and before html tags
- .replace(/>\s+/g,">").replace(/\s+ tags with new lines
- .replace(/<\s*[bB][rR]\s*\/?>/g,"\n")
- // Strip HTML elements
- .replace(/<[^>]*>/g,"");
- for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
- return o;
+ return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([^\u2603]*)(?:\\w+:)?'+f+'>',((g||"")/*:any*/)));
};
})();
var vtregex = (function(){ var vt_cache = {};
return function vt_regex(bt) {
if(vt_cache[bt] !== undefined) return vt_cache[bt];
- return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)(?:vt:)?" + bt + ">", 'g') );
+ return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">(.*?)(?:vt:)?" + bt + ">", 'g') );
};})();
-var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*);
-function parseVector(data/*:string*/, opts)/*:Array<{v:string,t:string}>*/ {
+var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>(.*);
+function parseVector(data) {
var h = parsexmltag(data);
- var matches/*:Array*/ = data.match(vtregex(h.baseType))||[];
- var res/*:Array*/ = [];
- if(matches.length != h.size) {
- if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
- return res;
- }
- matches.forEach(function(x/*:string*/) {
+ var matches = data.match(vtregex(h.baseType))||[];
+ if(matches.length != h.size) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
+ var res = [];
+ matches.forEach(function(x) {
var v = x.replace(vtvregex,"").match(vtmregex);
- if(v) res.push({v:utf8read(v[2]), t:v[1]});
+ res.push({v:utf8read(v[2]), t:v[1]});
});
return res;
}
var wtregex = /(^\s|\s$|\n)/;
-function writetag(f/*:string*/,g/*:string*/)/*:string*/ { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '' + f + '>'; }
+function writetag(f,g) {return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '' + f + '>';}
function wxt_helper(h)/*:string*/ { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
-function writextag(f/*:string*/,g/*:?string*/,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '' + f : "/") + '>';}
+function writextag(f,g,h) { return '<' + f + (isval(h) /*:: && h */? wxt_helper(h) : "") + (isval(g) /*:: && g */? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '' + f : "/") + '>';}
function write_w3cdtf(d/*:Date*/, t/*:?boolean*/)/*:string*/ { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
-function write_vt(s, xlsx/*:?boolean*/)/*:string*/ {
+function write_vt(s) {
switch(typeof s) {
- case 'string':
- var o = writextag('vt:lpwstr', escapexml(s));
- if(xlsx) o = o.replace(/"/g, "_x0022_");
- return o;
- case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', escapexml(String(s)));
+ case 'string': return writextag('vt:lpwstr', s);
+ case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', String(s));
case 'boolean': return writextag('vt:bool',s?'true':'false');
}
if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
throw new Error("Unable to serialize " + s);
}
+var XML_HEADER = '\r\n';
var XMLNS = ({
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/',
diff --git a/bits/23_binutils.js b/bits/23_binutils.js
index e3292fc..7feaa67 100644
--- a/bits/23_binutils.js
+++ b/bits/23_binutils.js
@@ -1,92 +1,89 @@
-function read_double_le(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ {
+function read_double_le(b, idx/*:number*/)/*:number*/ {
var s = 1 - 2 * (b[idx + 7] >>> 7);
var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
var m = (b[idx+6]&0x0f);
for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
- if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
+ if(e == 0x7ff) return m == 0 ? s * Infinity : NaN;
if(e == 0) e = -1022;
else { e -= 1023; m += Math.pow(2,52); }
return s * Math.pow(2, e - 52) * m;
}
-function write_double_le(b/*:RawBytes|CFBlob*/, v/*:number*/, idx/*:number*/) {
- var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
- var av = bs ? (-v) : v;
+function write_double_le(b, v/*:number*/, idx/*:number*/) {
+ var bs = ((v < 0 || 1/v == -Infinity) ? 1 : 0) << 7, e = 0, m = 0;
+ var av = bs ? -v : v;
if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
- else if(av == 0) e = m = 0;
else {
- e = Math.floor(Math.log(av) / Math.LN2);
- m = av * Math.pow(2, 52 - e);
- if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
+ e = Math.floor(Math.log(av) * Math.LOG2E);
+ m = v * Math.pow(2, 52 - e);
+ if(e <= -1023 && (!isFinite(m) || m < Math.pow(2,52))) { e = -1022; }
else { m -= Math.pow(2,52); e+=1023; }
}
for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
- b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
+ b[idx + 6] = ((e & 0x0f) << 4) | m & 0xf;
b[idx + 7] = (e >> 4) | bs;
}
-var __toBuffer = function(bufs/*:Array >*/)/*:RawBytes*/ { var x=[],w=10240; for(var i=0;i*/=[]; for(var i=s; i*/=[]; for(var i=s; i 0 ? __utf8(b, i+4,i+4+len-1) : "";};
-var ___lpstr = __lpstr;
-var __cpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
-var ___cpstr = __cpstr;
-var __lpwstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
-var ___lpwstr = __lpwstr;
+var __toBuffer, ___toBuffer;
+__toBuffer = ___toBuffer = function toBuffer_(bufs) { var x = []; for(var i = 0; i < bufs[0].length; ++i) { x.push.apply(x, bufs[0][i]); } return x; };
+var __utf16le, ___utf16le;
+__utf16le = ___utf16le = function utf16le_(b,s,e) { var ss=[]; for(var i=s; i 0 ? __utf8(b, i+4,i+4+len-1) : "";};
+var __lpwstr, ___lpwstr;
+__lpwstr = ___lpwstr = function lpwstr_(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
var __lpp4, ___lpp4;
-__lpp4 = ___lpp4 = function lpp4_(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
-var __8lpp4 = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
-var ___8lpp4 = __8lpp4;
+__lpp4 = ___lpp4 = function lpp4_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
+var __8lpp4, ___8lpp4;
+__8lpp4 = ___8lpp4 = function lpp4_8(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
var __double, ___double;
-__double = ___double = function(b/*:RawBytes|CFBlob*/, idx/*:number*/) { return read_double_le(b, idx);};
-var is_buf = function is_buf_a(a) { return Array.isArray(a); };
+__double = ___double = function(b, idx) { return read_double_le(b, idx);};
-if(has_buf/*:: && typeof Buffer !== 'undefined'*/) {
- __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
- __hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { return Buffer.isBuffer(b)/*:: && b instanceof Buffer*/ ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
- __lpstr = function lpstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";};
- __cpstr = function cpstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___cpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";};
- __lpwstr = function lpwstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpwstr(b, i); var len = 2*b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len-1);};
- __lpp4 = function lpp4_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len);};
- __8lpp4 = function lpp4_8b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___8lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf8',i+4,i+4+len);};
- __utf8 = function utf8_b(b/*:RawBytes|CFBlob*/, s/*:number*/, e/*:number*/) { return (Buffer.isBuffer(b)/*:: && (b instanceof Buffer)*/) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
+var is_buf = function is_buf_a(a) { return Array.isArray(a); };
+if(has_buf/*:: && typeof Buffer != 'undefined'*/) {
+ __utf16le = function utf16le_b(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e); };
+ __hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
+ __lpstr = function lpstr_b(b,i) { if(!Buffer.isBuffer(b)) return ___lpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";};
+ __lpwstr = function lpwstr_b(b,i) { if(!Buffer.isBuffer(b)) return ___lpwstr(b, i); var len = 2*b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len-1);};
+ __lpp4 = function lpp4_b(b,i) { if(!Buffer.isBuffer(b)) return ___lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len);};
+ __8lpp4 = function lpp4_8b(b,i) { if(!Buffer.isBuffer(b)) return ___8lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf8',i+4,i+4+len);};
+ __utf8 = function utf8_b(b, s,e) { return b.toString('utf8',s,e); };
__toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
- __double = function double_(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(Buffer.isBuffer(b)/*::&& b instanceof Buffer*/) return b.readDoubleLE(i); return ___double(b,i); };
+ __double = function double_(b,i) { if(Buffer.isBuffer(b)/*::&& b instanceof Buffer*/) return b.readDoubleLE(i); return ___double(b,i); };
is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
}
/* from js-xls */
if(typeof cptable !== 'undefined') {
- __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
- __utf8 = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { return cptable.utils.decode(65001, b.slice(s,e)); };
- __lpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_ansi, b.slice(i+4, i+4+len-1)) : "";};
- __cpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_codepage, b.slice(i+4, i+4+len-1)) : "";};
- __lpwstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = 2*__readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len-1)) : "";};
- __lpp4 = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
- __8lpp4 = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
+ __utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)); };
+ __utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
+ __lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_codepage, b.slice(i+4, i+4+len-1)) : "";};
+ __lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len-1)) : "";};
+ __lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
+ __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
}
-var __readUInt8 = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx]; };
-var __readUInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx+1]*(1<<8))+b[idx]; };
-var __readInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
-var __readUInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
-var __readInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
-var __readInt32BE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
+var __readUInt8 = function(b, idx) { return b[idx]; };
+var __readUInt16LE = function(b, idx) { return b[idx+1]*(1<<8)+b[idx]; };
+var __readInt16LE = function(b, idx) { var u = b[idx+1]*(1<<8)+b[idx]; return (u < 0x8000) ? u : (0xffff - u + 1) * -1; };
+var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
+var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
-function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
- var o="", oI/*:: :number = 0*/, oR, oo=[], w, vv, i, loc;
+var ___unhexlify = function(s) { return s.match(/../g).map(function(x) { return parseInt(x,16);}); };
+var __unhexlify = typeof Buffer !== "undefined" ? function(s) { return Buffer.isBuffer(s) ? new Buffer(s, 'hex') : ___unhexlify(s); } : ___unhexlify;
+
+function ReadShift(size/*:number*/, t/*:?string*/) {
+ var o="", oI, oR, oo=[], w, vv, i, loc;
switch(t) {
case 'dbcs':
loc = this.l;
if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
- else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
+ else for(i = 0; i != size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
size *= 2;
break;
@@ -99,10 +96,9 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
size = 2 * size; break;
/* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
- case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
- case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
+ case 'lpstr': o = __lpstr(this, this.l); size = 5 + o.length; break;
/* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
- case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
+ case 'lpwstr': o = __lpwstr(this, this.l); size = 5 + o.length; if(o[o.length-1] == '\u0000') size += 2; break;
/* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
case 'lpp4': size = 4 + __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
/* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
@@ -117,7 +113,7 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
/* sbcs and dbcs support continue records in the SST way TODO codepages */
case 'dbcs-cont': o = ""; loc = this.l;
- for(i = 0; i < size; ++i) {
+ for(i = 0; i != size; ++i) {
if(this.lens && this.lens.indexOf(loc) !== -1) {
w = __readUInt8(this, loc);
this.l = loc + 1;
@@ -128,12 +124,6 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
loc+=2;
} o = oo.join(""); size *= 2; break;
- case 'cpstr':
- if(typeof cptable !== 'undefined') {
- o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
- break;
- }
- /* falls through */
case 'sbcs-cont': o = ""; loc = this.l;
for(i = 0; i != size; ++i) {
if(this.lens && this.lens.indexOf(loc) !== -1) {
@@ -150,61 +140,30 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
switch(size) {
case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
- case 4: case -4:
- if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
+ case 4:
+ if(t === 'i' || (this[this.l+3] & 0x80)===0) { oI = __readInt32LE(this, this.l); this.l += 4; return oI; }
else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
- case 8: case -8:
- if(t === 'f') {
- if(size == 8) oR = __double(this, this.l);
- else oR = __double([this[this.l+7],this[this.l+6],this[this.l+5],this[this.l+4],this[this.l+3],this[this.l+2],this[this.l+1],this[this.l+0]], 0);
- this.l += 8; return oR;
- } else size = 8;
+ case 8: if(t === 'f') { oR = __double(this, this.l); this.l += 8; return oR; }
/* falls through */
case 16: o = __hexlify(this, this.l, size); break;
}}
this.l+=size; return o;
}
-var __writeUInt32LE = function(b/*:RawBytes|CFBlob*/, val/*:number*/, idx/*:number*/)/*:void*/ { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); b[idx+2] = ((val >>> 16) & 0xFF); b[idx+3] = ((val >>> 24) & 0xFF); };
-var __writeInt32LE = function(b/*:RawBytes|CFBlob*/, val/*:number*/, idx/*:number*/)/*:void*/ { b[idx] = (val & 0xFF); b[idx+1] = ((val >> 8) & 0xFF); b[idx+2] = ((val >> 16) & 0xFF); b[idx+3] = ((val >> 24) & 0xFF); };
-var __writeUInt16LE = function(b/*:RawBytes|CFBlob*/, val/*:number*/, idx/*:number*/)/*:void*/ { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
+var __writeUInt16LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
+var __writeUInt32LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); b[idx+2] = ((val >>> 16) & 0xFF); b[idx+3] = ((val >>> 24) & 0xFF); };
+var __writeInt32LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >> 8) & 0xFF); b[idx+2] = ((val >> 16) & 0xFF); b[idx+3] = ((val >> 24) & 0xFF); };
-function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/ {
+function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/) {
var size = 0, i = 0;
if(f === 'dbcs') {
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
size = 2 * val.length;
} else if(f === 'sbcs') {
- if(typeof cptable !== 'undefined' && current_ansi == 874) {
- /* TODO: use tables directly, don't encode */
- /*:: if(typeof val !== "string") throw new Error("unreachable"); */
- for(i = 0; i != val.length; ++i) {
- var cppayload = cptable.utils.encode(current_ansi, val.charAt(i));
- this[this.l + i] = cppayload[0];
- }
- } else {
- /*:: if(typeof val !== 'string') throw new Error("unreachable"); */
- val = val.replace(/[^\x00-\x7F]/g, "_");
- /*:: if(typeof val !== 'string') throw new Error("unreachable"); */
- for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
- }
+ /*:: if(typeof val !== 'string') throw new Error("unreachable"); */
+ for(i = 0; i != val.length; ++i) this[this.l + i] = val.charCodeAt(i) & 0xFF;
size = val.length;
- } else if(f === 'hex') {
- for(; i < t; ++i) {
- /*:: if(typeof val !== "string") throw new Error("unreachable"); */
- this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
- } return this;
- } else if(f === 'utf16le') {
- /*:: if(typeof val !== "string") throw new Error("unreachable"); */
- var end/*:number*/ = Math.min(this.l + t, this.length);
- for(i = 0; i < Math.min(val.length, t); ++i) {
- var cc = val.charCodeAt(i);
- this[this.l++] = (cc & 0xff);
- this[this.l++] = (cc >> 8);
- }
- while(this.l < end) this[this.l++] = 0;
- return this;
} else /*:: if(typeof val === 'number') */ switch(t) {
case 1: size = 1; this[this.l] = val&0xFF; break;
case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
@@ -218,20 +177,23 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/
this.l += size; return this;
}
-function CheckField(hexstr/*:string*/, fld/*:string*/)/*:void*/ {
+function CheckField(hexstr, fld) {
var m = __hexlify(this,this.l,hexstr.length>>1);
- if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
+ if(m !== hexstr) throw fld + 'Expected ' + hexstr + ' saw ' + m;
this.l += hexstr.length>>1;
}
-function prep_blob(blob, pos/*:number*/)/*:void*/ {
+function prep_blob(blob, pos/*:number*/) {
blob.l = pos;
- blob.read_shift = /*::(*/ReadShift/*:: :any)*/;
+ blob.read_shift = ReadShift;
blob.chk = CheckField;
blob.write_shift = WriteShift;
}
-function parsenoop(blob, length/*:: :number, opts?:any */) { blob.l += length; }
+function parsenoop(blob, length/*:number*/) { blob.l += length; }
+function parsenooplog(blob, length/*:number*/) { if(typeof console != 'undefined') console.log(blob.slice(blob.l, blob.l + length)); blob.l += length; }
+
+function writenoop(blob, length/*:number*/) { blob.l += length; }
function new_buf(sz/*:number*/)/*:Block*/ {
var o = new_raw_buf(sz);
diff --git a/bits/24_hoppers.js b/bits/24_hoppers.js
index b306146..f3aa5a3 100644
--- a/bits/24_hoppers.js
+++ b/bits/24_hoppers.js
@@ -12,7 +12,7 @@ function recordhopper(data, cb/*:RecordHopperCB*/, opts/*:?any*/) {
length = tmpbyte & 0x7F;
for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
tgt = data.l + length;
- var d = (R.f||parsenoop)(data, length, opts);
+ var d = R.f(data, length, opts);
data.l = tgt;
if(cb(d, R.n, RT)) return;
}
@@ -20,24 +20,24 @@ function recordhopper(data, cb/*:RecordHopperCB*/, opts/*:?any*/) {
/* control buffer usage for fixed-length buffers */
function buf_array()/*:BufArray*/ {
- var bufs/*:Array*/ = [], blksz = has_buf ? 256 : 2048;
- var newblk = function ba_newblk(sz/*:number*/)/*:Block*/ {
+ var bufs = [], blksz = 2048;
+ var newblk = function ba_newblk(sz) {
var o/*:Block*/ = (new_buf(sz)/*:any*/);
prep_blob(o, 0);
return o;
};
- var curbuf/*:Block*/ = newblk(blksz);
+ var curbuf = newblk(blksz);
var endbuf = function ba_endbuf() {
if(!curbuf) return;
- if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
+ if(curbuf.length > curbuf.l) curbuf = curbuf.slice(0, curbuf.l);
if(curbuf.length > 0) bufs.push(curbuf);
curbuf = null;
};
- var next = function ba_next(sz/*:number*/)/*:Block*/ {
- if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
+ var next = function ba_next(sz) {
+ if(curbuf && sz < curbuf.length - curbuf.l) return curbuf;
endbuf();
return (curbuf = newblk(Math.max(sz+1, blksz)));
};
@@ -47,16 +47,16 @@ function buf_array()/*:BufArray*/ {
return __toBuffer([bufs]);
};
- var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
+ var push = function ba_push(buf) { endbuf(); curbuf = buf; next(blksz); };
return ({ next:next, push:push, end:end, _bufs:bufs }/*:any*/);
}
function write_record(ba/*:BufArray*/, type/*:string*/, payload, length/*:?number*/) {
- var t/*:number*/ = +XLSBRE[type], l;
+ var t/*:number*/ = Number(evert_RE[type]), l;
if(isNaN(t)) return; // TODO: throw something here?
if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
- l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
+ l = 1 + (t >= 0x80 ? 1 : 0) + 1 + length;
if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
var o = ba.next(l);
if(t <= 0x7F) o.write_shift(1, t);
diff --git a/bits/25_cellutils.js b/bits/25_cellutils.js
index c27e5ee..b4aaec8 100644
--- a/bits/25_cellutils.js
+++ b/bits/25_cellutils.js
@@ -5,8 +5,8 @@ function shift_cell_xls(cell/*:CellAddress*/, tgt/*:any*/, opts/*:?any*/)/*:Cell
if(out.cRel) out.c += tgt.s.c;
if(out.rRel) out.r += tgt.s.r;
} else {
- if(out.cRel) out.c += tgt.c;
- if(out.rRel) out.r += tgt.r;
+ out.c += tgt.c;
+ out.r += tgt.r;
}
if(!opts || opts.biff < 12) {
while(out.c >= 0x100) out.c -= 0x100;
@@ -22,25 +22,23 @@ function shift_range_xls(cell, range, opts) {
return out;
}
-function encode_cell_xls(c/*:CellAddress*/, biff/*:number*/)/*:string*/ {
- if(c.cRel && c.c < 0) { c = dup(c); while(c.c < 0) c.c += (biff > 8) ? 0x4000 : 0x100; }
- if(c.rRel && c.r < 0) { c = dup(c); while(c.r < 0) c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
+function encode_cell_xls(c/*:CellAddress*/)/*:string*/ {
var s = encode_cell(c);
- if(!c.cRel && c.cRel != null) s = fix_col(s);
- if(!c.rRel && c.rRel != null) s = fix_row(s);
+ if(c.cRel === 0) s = fix_col(s);
+ if(c.rRel === 0) s = fix_row(s);
return s;
}
function encode_range_xls(r, opts)/*:string*/ {
if(r.s.r == 0 && !r.s.rRel) {
- if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
+ if(r.e.r == opts.biff >= 12 ? 0xFFFFF : 0xFFFF && !r.e.rRel) {
return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
}
}
if(r.s.c == 0 && !r.s.cRel) {
- if(r.e.c == (opts.biff >= 12 ? 0x3FFF : 0xFF) && !r.e.cRel) {
+ if(r.e.c == opts.biff >= 12 ? 0xFFFF : 0xFF && !r.e.cRel) {
return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
}
}
- return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
+ return encode_cell_xls(r.s) + ":" + encode_cell_xls(r.e);
}
diff --git a/bits/26_crypto.js b/bits/26_crypto.js
index d989434..c41f62c 100644
--- a/bits/26_crypto.js
+++ b/bits/26_crypto.js
@@ -17,7 +17,7 @@ var make_offcrypto = function(O, _crypto) {
t = S[i]; S[i] = S[j]; S[j] = t;
}
// $FlowIgnore
- i = j = 0; var out = new_raw_buf(data.length);
+ i = j = 0; var out = Buffer(data.length);
for(c = 0; c != data.length; ++c) {
i = (i + 1)&255;
j = (j + S[i])%256;
diff --git a/bits/27_csfutils.js b/bits/27_csfutils.js
index e9cc2c0..fca8683 100644
--- a/bits/27_csfutils.js
+++ b/bits/27_csfutils.js
@@ -4,33 +4,16 @@ function fix_row(cstr/*:string*/)/*:string*/ { return cstr.replace(/([A-Z]|^)(\d
function unfix_row(cstr/*:string*/)/*:string*/ { return cstr.replace(/\$(\d+)$/,"$1"); }
function decode_col(colstr/*:string*/)/*:number*/ { var c = unfix_col(colstr), d = 0, i = 0; for(; i !== c.length; ++i) d = 26*d + c.charCodeAt(i) - 64; return d - 1; }
-function encode_col(col/*:number*/)/*:string*/ { if(col < 0) throw new Error("invalid column " + col); var s=""; for(++col; col; col=Math.floor((col-1)/26)) s = String.fromCharCode(((col-1)%26) + 65) + s; return s; }
+function encode_col(col/*:number*/)/*:string*/ { var s=""; for(++col; col; col=Math.floor((col-1)/26)) s = String.fromCharCode(((col-1)%26) + 65) + s; return s; }
function fix_col(cstr/*:string*/)/*:string*/ { return cstr.replace(/^([A-Z])/,"$$$1"); }
function unfix_col(cstr/*:string*/)/*:string*/ { return cstr.replace(/^\$([A-Z])/,"$1"); }
function split_cell(cstr/*:string*/)/*:Array*/ { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
-//function decode_cell(cstr/*:string*/)/*:CellAddress*/ { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
-function decode_cell(cstr/*:string*/)/*:CellAddress*/ {
- var R = 0, C = 0;
- for(var i = 0; i < cstr.length; ++i) {
- var cc = cstr.charCodeAt(i);
- if(cc >= 48 && cc <= 57) R = 10 * R + (cc - 48);
- else if(cc >= 65 && cc <= 90) C = 26 * C + (cc - 64);
- }
- return { c: C - 1, r:R - 1 };
-}
-//function encode_cell(cell/*:CellAddress*/)/*:string*/ { return encode_col(cell.c) + encode_row(cell.r); }
-function encode_cell(cell/*:CellAddress*/)/*:string*/ {
- var col = cell.c + 1;
- var s="";
- for(; col; col=((col-1)/26)|0) s = String.fromCharCode(((col-1)%26) + 65) + s;
- return s + (cell.r + 1);
-}
-function decode_range(range/*:string*/)/*:Range*/ {
- var idx = range.indexOf(":");
- if(idx == -1) return { s: decode_cell(range), e: decode_cell(range) };
- return { s: decode_cell(range.slice(0, idx)), e: decode_cell(range.slice(idx + 1)) };
-}
+function decode_cell(cstr/*:string*/)/*:CellAddress*/ { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
+function encode_cell(cell/*:CellAddress*/)/*:string*/ { return encode_col(cell.c) + encode_row(cell.r); }
+function fix_cell(cstr/*:string*/)/*:string*/ { return fix_col(fix_row(cstr)); }
+function unfix_cell(cstr/*:string*/)/*:string*/ { return unfix_col(unfix_row(cstr)); }
+function decode_range(range/*:string*/)/*:Range*/ { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
/*# if only one arg, it is assumed to be a Range. If 2 args, both are cell addresses */
function encode_range(cs/*:CellAddrSpec|Range*/,ce/*:?CellAddrSpec*/)/*:string*/ {
if(typeof ce === 'undefined' || typeof ce === 'number') {
@@ -80,15 +63,15 @@ function safe_decode_range(range/*:string*/)/*:Range*/ {
function safe_format_cell(cell/*:Cell*/, v/*:any*/) {
var q = (cell.t == 'd' && v instanceof Date);
if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
- try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0), q ? datenum(v) : v)); } catch(e) { return ''+v; }
+ try { return (cell.w = SSF.format((cell.XF||{}).ifmt||(q ? 14 : 0), q ? datenum(v) : v)); } catch(e) { return ''+v; }
}
function format_cell(cell/*:Cell*/, v/*:any*/, o/*:any*/) {
if(cell == null || cell.t == null || cell.t == 'z') return "";
if(cell.w !== undefined) return cell.w;
if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
- if(v == undefined) return safe_format_cell(cell, cell.v);
- return safe_format_cell(cell, v);
+ if(v == undefined) return safe_format_cell(cell, cell.v, o);
+ return safe_format_cell(cell, v, o);
}
function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
@@ -97,60 +80,34 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
return { SheetNames: [n], Sheets: sheets };
}
-function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
+function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
var o = opts || {};
- var dense = _ws ? Array.isArray(_ws) : o.dense;
- if(DENSE != null && dense == null) dense = DENSE;
- var ws/*:Worksheet*/ = _ws || (dense ? ([]/*:any*/) : ({}/*:any*/));
- var _R = 0, _C = 0;
- if(ws && o.origin != null) {
- if(typeof o.origin == 'number') _R = o.origin;
- else {
- var _origin/*:CellAddress*/ = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
- _R = _origin.r; _C = _origin.c;
- }
- if(!ws["!ref"]) ws["!ref"] = "A1:A1";
- }
+ if(DENSE != null && o.dense == null) o.dense = DENSE;
+ var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/);
var range/*:Range*/ = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}}/*:any*/);
- if(ws['!ref']) {
- var _range = safe_decode_range(ws['!ref']);
- range.s.c = _range.s.c;
- range.s.r = _range.s.r;
- range.e.c = Math.max(range.e.c, _range.e.c);
- range.e.r = Math.max(range.e.r, _range.e.r);
- if(_R == -1) range.e.r = _R = _range.e.r + 1;
- }
for(var R = 0; R != data.length; ++R) {
- if(!data[R]) continue;
- if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
for(var C = 0; C != data[R].length; ++C) {
if(typeof data[R][C] === 'undefined') continue;
var cell/*:Cell*/ = ({v: data[R][C] }/*:any*/);
- var __R = _R + R, __C = _C + C;
- if(range.s.r > __R) range.s.r = __R;
- if(range.s.c > __C) range.s.c = __C;
- if(range.e.r < __R) range.e.r = __R;
- if(range.e.c < __C) range.e.c = __C;
- if(data[R][C] && typeof data[R][C] === 'object' && !Array.isArray(data[R][C]) && !(data[R][C] instanceof Date)) cell = data[R][C];
- else {
- if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
- if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.sheetStubs) continue; else cell.t = 'z'; }
- else if(typeof cell.v === 'number') cell.t = 'n';
- else if(typeof cell.v === 'boolean') cell.t = 'b';
- else if(cell.v instanceof Date) {
- cell.z = o.dateNF || SSF._table[14];
- if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
- else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
- }
- else cell.t = 's';
+ if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
+ if(range.s.r > R) range.s.r = R;
+ if(range.s.c > C) range.s.c = C;
+ if(range.e.r < R) range.e.r = R;
+ if(range.e.c < C) range.e.c = C;
+ if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.cellStubs) continue; else cell.t = 'z'; }
+ else if(typeof cell.v === 'number') cell.t = 'n';
+ else if(typeof cell.v === 'boolean') cell.t = 'b';
+ else if(cell.v instanceof Date) {
+ cell.z = o.dateNF || SSF._table[14];
+ if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
+ else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
}
- if(dense) {
- if(!ws[__R]) ws[__R] = [];
- if(ws[__R][__C] && ws[__R][__C].z) cell.z = ws[__R][__C].z;
- ws[__R][__C] = cell;
+ else cell.t = 's';
+ if(o.dense) {
+ if(!ws[R]) ws[R] = [];
+ ws[R][C] = cell;
} else {
- var cell_ref = encode_cell(({c:__C,r:__R}/*:any*/));
- if(ws[cell_ref] && ws[cell_ref].z) cell.z = ws[cell_ref].z;
+ var cell_ref = encode_cell(({c:C,r:R}/*:any*/));
ws[cell_ref] = cell;
}
}
@@ -158,5 +115,4 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
return ws;
}
-function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); }
diff --git a/bits/28_binstructs.js b/bits/28_binstructs.js
index dbed6fb..4063105 100644
--- a/bits/28_binstructs.js
+++ b/bits/28_binstructs.js
@@ -1,52 +1,46 @@
function write_UInt32LE(x/*:number*/, o) {
- if (!o) o = new_buf(4);
+ if(!o) o = new_buf(4);
o.write_shift(4, x);
return o;
}
/* [MS-XLSB] 2.5.168 */
-function parse_XLWideString(data/*::, length*/)/*:string*/ {
+function parse_XLWideString(data)/*:string*/ {
var cchCharacters = data.read_shift(4);
return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, 'dbcs');
}
function write_XLWideString(data/*:string*/, o) {
- var _null = false; if (o == null) { _null = true; o = new_buf(4 + 2 * data.length); }
+ var _null = false; if(o == null) { _null = true; o = new_buf(4+2*data.length); }
o.write_shift(4, data.length);
- if (data.length > 0) o.write_shift(0, data, 'dbcs');
+ if(data.length > 0) o.write_shift(0, data, 'dbcs');
return _null ? o.slice(0, o.l) : o;
}
-/* [MS-XLSB] 2.5.91 */
-//function parse_LPWideString(data/*::, length*/)/*:string*/ {
-// var cchCharacters = data.read_shift(2);
-// return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, "utf16le");
-//}
-
/* [MS-XLSB] 2.5.143 */
-function parse_StrRun(data) {
+function parse_StrRun(data, length/*:?number*/) {
return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
}
function write_StrRun(run, o) {
- if (!o) o = new_buf(4);
+ if(!o) o = new_buf(4);
o.write_shift(2, run.ich || 0);
o.write_shift(2, run.ifnt || 0);
return o;
}
-/* [MS-XLSB] 2.5.121 */
+/* [MS-XLSB] 2.1.7.121 */
function parse_RichStr(data, length/*:number*/)/*:XLString*/ {
var start = data.l;
var flags = data.read_shift(1);
var str = parse_XLWideString(data);
var rgsStrRun = [];
var z = ({ t: str, h: str }/*:any*/);
- if ((flags & 1) !== 0) { /* fRichStr */
+ if((flags & 1) !== 0) { /* fRichStr */
/* TODO: formatted string */
var dwSizeStrRun = data.read_shift(4);
- for (var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
+ for(var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
z.r = rgsStrRun;
}
- else z.r = [{ ich: 0, ifnt: 0 }];
+ else z.r = [{ich:0, ifnt:0}];
//if((flags & 2) !== 0) { /* fExtStr */
// /* TODO: phonetic string */
//}
@@ -55,20 +49,20 @@ function parse_RichStr(data, length/*:number*/)/*:XLString*/ {
}
function write_RichStr(str/*:XLString*/, o/*:?Block*/)/*:Block*/ {
/* TODO: formatted string */
- var _null = false; if (o == null) { _null = true; o = new_buf(15 + 4 * str.t.length); }
- o.write_shift(1, 0);
+ var _null = false; if(o == null) { _null = true; o = new_buf(15+4*str.t.length); }
+ o.write_shift(1,0);
write_XLWideString(str.t, o);
return _null ? o.slice(0, o.l) : o;
}
-/* [MS-XLSB] 2.4.328 BrtCommentText (RichStr w/1 run) */
+/* [MS-XLSB] 2.4.325 BrtCommentText (RichStr w/1 run) */
var parse_BrtCommentText = parse_RichStr;
function write_BrtCommentText(str/*:XLString*/, o/*:?Block*/)/*:Block*/ {
/* TODO: formatted string */
- var _null = false; if (o == null) { _null = true; o = new_buf(23 + 4 * str.t.length); }
- o.write_shift(1, 1);
+ var _null = false; if(o == null) { _null = true; o = new_buf(23+4*str.t.length); }
+ o.write_shift(1,1);
write_XLWideString(str.t, o);
- o.write_shift(4, 1);
- write_StrRun({ ich: 0, ifnt: 0 }, o);
+ o.write_shift(4,1);
+ write_StrRun({ich:0,ifnt:0}, o);
return _null ? o.slice(0, o.l) : o;
}
@@ -76,87 +70,76 @@ function write_BrtCommentText(str/*:XLString*/, o/*:?Block*/)/*:Block*/ {
function parse_XLSBCell(data)/*:any*/ {
var col = data.read_shift(4);
var iStyleRef = data.read_shift(2);
- iStyleRef += data.read_shift(1) << 16;
- data.l++; //var fPhShow = data.read_shift(1);
- return { c: col, iStyleRef: iStyleRef };
+ iStyleRef += data.read_shift(1) <<16;
+ var fPhShow = data.read_shift(1);
+ return { c:col, iStyleRef: iStyleRef };
}
function write_XLSBCell(cell/*:any*/, o/*:?Block*/) {
- if (o == null) o = new_buf(8);
+ if(o == null) o = new_buf(8);
o.write_shift(-4, cell.c);
o.write_shift(3, cell.iStyleRef || cell.s);
o.write_shift(1, 0); /* fPhShow */
return o;
}
-/* Short XLSB Cell does not include column */
-function parse_XLSBShortCell(data)/*:any*/ {
- var iStyleRef = data.read_shift(2);
- iStyleRef += data.read_shift(1) <<16;
- data.l++; //var fPhShow = data.read_shift(1);
- return { c:-1, iStyleRef: iStyleRef };
-}
-function write_XLSBShortCell(cell/*:any*/, o/*:?Block*/) {
- if(o == null) o = new_buf(4);
- o.write_shift(3, cell.iStyleRef || cell.s);
- o.write_shift(1, 0); /* fPhShow */
- return o;
-}
/* [MS-XLSB] 2.5.21 */
var parse_XLSBCodeName = parse_XLWideString;
var write_XLSBCodeName = write_XLWideString;
/* [MS-XLSB] 2.5.166 */
-function parse_XLNullableWideString(data/*::, length*/)/*:string*/ {
+function parse_XLNullableWideString(data)/*:string*/ {
var cchCharacters = data.read_shift(4);
return cchCharacters === 0 || cchCharacters === 0xFFFFFFFF ? "" : data.read_shift(cchCharacters, 'dbcs');
}
function write_XLNullableWideString(data/*:string*/, o) {
- var _null = false; if (o == null) { _null = true; o = new_buf(127); }
+ var _null = false; if(o == null) { _null = true; o = new_buf(127); }
o.write_shift(4, data.length > 0 ? data.length : 0xFFFFFFFF);
- if (data.length > 0) o.write_shift(0, data, 'dbcs');
+ if(data.length > 0) o.write_shift(0, data, 'dbcs');
return _null ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.5.165 */
var parse_XLNameWideString = parse_XLWideString;
-//var write_XLNameWideString = write_XLWideString;
+var write_XLNameWideString = write_XLWideString;
/* [MS-XLSB] 2.5.114 */
var parse_RelID = parse_XLNullableWideString;
var write_RelID = write_XLNullableWideString;
-/* [MS-XLS] 2.5.217 ; [MS-XLSB] 2.5.122 */
+/* [MS-XLSB] 2.5.122 */
+/* [MS-XLS] 2.5.217 */
function parse_RkNumber(data)/*:number*/ {
- var b = data.slice(data.l, data.l + 4);
- var fX100 = (b[0] & 1), fInt = (b[0] & 2);
- data.l += 4;
+ var b = data.slice(data.l, data.l+4);
+ var fX100 = b[0] & 1, fInt = b[0] & 2;
+ data.l+=4;
b[0] &= 0xFC; // b[0] &= ~3;
- var RK = fInt === 0 ? __double([0, 0, 0, 0, b[0], b[1], b[2], b[3]], 0) : __readInt32LE(b, 0) >> 2;
- return fX100 ? (RK / 100) : RK;
+ var RK = fInt === 0 ? __double([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
+ return fX100 ? RK/100 : RK;
}
function write_RkNumber(data/*:number*/, o) {
- if (o == null) o = new_buf(4);
+ if(o == null) o = new_buf(4);
var fX100 = 0, fInt = 0, d100 = data * 100;
- if ((data == (data | 0)) && (data >= -(1 << 29)) && (data < (1 << 29))) { fInt = 1; }
- else if ((d100 == (d100 | 0)) && (d100 >= -(1 << 29)) && (d100 < (1 << 29))) { fInt = 1; fX100 = 1; }
- if (fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
+ if(data == (data | 0) && data >= -(1<<29) && data < (1 << 29)) { fInt = 1; }
+ else if(d100 == (d100 | 0) && d100 >= -(1<<29) && d100 < (1 << 29)) { fInt = 1; fX100 = 1; }
+ if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
else throw new Error("unsupported RkNumber " + data); // TODO
}
/* [MS-XLSB] 2.5.117 RfX */
-function parse_RfX(data /*::, length*/)/*:Range*/ {
- var cell/*:Range*/ = ({ s: {}, e: {} }/*:any*/);
+function parse_RfX(data)/*:Range*/ {
+ var cell/*:Range*/ = ({s: {}, e: {}}/*:any*/);
cell.s.r = data.read_shift(4);
cell.e.r = data.read_shift(4);
cell.s.c = data.read_shift(4);
cell.e.c = data.read_shift(4);
return cell;
}
+
function write_RfX(r/*:Range*/, o) {
- if (!o) o = new_buf(16);
+ if(!o) o = new_buf(16);
o.write_shift(4, r.s.r);
o.write_shift(4, r.e.r);
o.write_shift(4, r.s.c);
@@ -168,40 +151,32 @@ function write_RfX(r/*:Range*/, o) {
var parse_UncheckedRfX = parse_RfX;
var write_UncheckedRfX = write_RfX;
-/* [MS-XLSB] 2.5.155 UncheckedSqRfX */
-//function parse_UncheckedSqRfX(data) {
-// var cnt = data.read_shift(4);
-// var out = [];
-// for(var i = 0; i < cnt; ++i) {
-// var rng = parse_UncheckedRfX(data);
-// out.push(encode_range(rng));
-// }
-// return out.join(",");
-//}
-//function write_UncheckedSqRfX(sqrfx/*:string*/) {
-// var parts = sqrfx.split(/\s*,\s*/);
-// var o = new_buf(4); o.write_shift(4, parts.length);
-// var out = [o];
-// parts.forEach(function(rng) {
-// out.push(write_UncheckedRfX(safe_decode_range(rng)));
-// });
-// return bconcat(out);
-//}
-
-/* [MS-XLS] 2.5.342 ; [MS-XLSB] 2.5.171 */
+/* [MS-XLSB] 2.5.171 */
+/* [MS-XLS] 2.5.342 */
/* TODO: error checking, NaN and Infinity values are not valid Xnum */
-function parse_Xnum(data/*::, length*/) {
- if(data.length - data.l < 8) throw "XLS Xnum Buffer underflow";
- return data.read_shift(8, 'f');
-}
+function parse_Xnum(data, length/*:?number*/) { return data.read_shift(8, 'f'); }
function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
-/* [MS-XLSB] 2.4.324 BrtColor */
-function parse_BrtColor(data/*::, length*/) {
+/* [MS-XLSB] 2.5.198.2 */
+var BErr = {
+ /*::[*/0x00/*::]*/: "#NULL!",
+ /*::[*/0x07/*::]*/: "#DIV/0!",
+ /*::[*/0x0F/*::]*/: "#VALUE!",
+ /*::[*/0x17/*::]*/: "#REF!",
+ /*::[*/0x1D/*::]*/: "#NAME?",
+ /*::[*/0x24/*::]*/: "#NUM!",
+ /*::[*/0x2A/*::]*/: "#N/A",
+ /*::[*/0x2B/*::]*/: "#GETTING_DATA",
+ /*::[*/0xFF/*::]*/: "#WTF?"
+};
+var RBErr = evert_num(BErr);
+
+/* [MS-XLSB] 2.4.321 BrtColor */
+function parse_BrtColor(data, length/*:number*/) {
var out = {};
var d = data.read_shift(1);
- //var fValidRGB = d & 1;
+ var fValidRGB = d & 1;
var xColorType = d >>> 1;
var index = data.read_shift(1);
@@ -209,33 +184,33 @@ function parse_BrtColor(data/*::, length*/) {
var bR = data.read_shift(1);
var bG = data.read_shift(1);
var bB = data.read_shift(1);
- data.l++; //var bAlpha = data.read_shift(1);
+ var bAlpha = data.read_shift(1);
- switch (xColorType) {
+ switch(xColorType) {
case 0: out.auto = 1; break;
case 1:
out.index = index;
var icv = XLSIcv[index];
/* automatic pseudo index 81 */
- if (icv) out.rgb = rgb2Hex(icv);
+ if(icv) out.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
break;
case 2:
/* if(!fValidRGB) throw new Error("invalid"); */
- out.rgb = rgb2Hex([bR, bG, bB]);
+ out.rgb = bR.toString(16) + bG.toString(16) + bB.toString(16);
break;
case 3: out.theme = index; break;
}
- if (nTS != 0) out.tint = nTS > 0 ? nTS / 32767 : nTS / 32768;
+ if(nTS != 0) out.tint = nTS > 0 ? nTS / 32767 : nTS / 32768;
return out;
}
function write_BrtColor(color, o) {
- if (!o) o = new_buf(8);
- if (!color || color.auto) { o.write_shift(4, 0); o.write_shift(4, 0); return o; }
- if (color.index != null) {
+ if(!o) o = new_buf(8);
+ if(!color||color.auto) { o.write_shift(4, 0); o.write_shift(4, 0); return o; }
+ if(color.index) {
o.write_shift(1, 0x02);
o.write_shift(1, color.index);
- } else if (color.theme != null) {
+ } else if(color.theme) {
o.write_shift(1, 0x06);
o.write_shift(1, color.theme);
} else {
@@ -243,32 +218,31 @@ function write_BrtColor(color, o) {
o.write_shift(1, 0);
}
var nTS = color.tint || 0;
- if (nTS > 0) nTS *= 32767;
- else if (nTS < 0) nTS *= 32768;
+ if(nTS > 0) nTS *= 32767;
+ else if(nTS < 0) nTS *= 32768;
o.write_shift(2, nTS);
- if (!color.rgb || color.theme != null) {
+ if(!color.rgb) {
o.write_shift(2, 0);
o.write_shift(1, 0);
o.write_shift(1, 0);
} else {
var rgb = (color.rgb || 'FFFFFF');
- if (typeof rgb == 'number') rgb = ("000000" + rgb.toString(16)).slice(-6);
- o.write_shift(1, parseInt(rgb.slice(0, 2), 16));
- o.write_shift(1, parseInt(rgb.slice(2, 4), 16));
- o.write_shift(1, parseInt(rgb.slice(4, 6), 16));
+ o.write_shift(1, parseInt(rgb.substr(0,2),16));
+ o.write_shift(1, parseInt(rgb.substr(2,2),16));
+ o.write_shift(1, parseInt(rgb.substr(4,2),16));
o.write_shift(1, 0xFF);
}
return o;
}
/* [MS-XLSB] 2.5.52 */
-function parse_FontFlags(data/*::, length, opts*/) {
+function parse_FontFlags(data, length/*:number*/, opts) {
var d = data.read_shift(1);
data.l++;
var out = {
- fBold: d & 0x01,
+ /* fBold: d & 0x01 */
fItalic: d & 0x02,
- fUnderline: d & 0x04,
+ /* fUnderline: d & 0x04 */
fStrikeout: d & 0x08,
fOutline: d & 0x10,
fShadow: d & 0x20,
@@ -278,32 +252,16 @@ function parse_FontFlags(data/*::, length, opts*/) {
return out;
}
function write_FontFlags(font, o) {
- if (!o) o = new_buf(2);
+ if(!o) o = new_buf(2);
var grbit =
- (font.italic ? 0x02 : 0) |
- (font.strike ? 0x08 : 0) |
- (font.outline ? 0x10 : 0) |
- (font.shadow ? 0x20 : 0) |
+ (font.italic ? 0x02 : 0) |
+ (font.strike ? 0x08 : 0) |
+ (font.outline ? 0x10 : 0) |
+ (font.shadow ? 0x20 : 0) |
(font.condense ? 0x40 : 0) |
- (font.extend ? 0x80 : 0);
+ (font.extend ? 0x80 : 0);
o.write_shift(1, grbit);
o.write_shift(1, 0);
return o;
}
-/* [MS-OLEDS] 2.3.1 and 2.3.2 */
-function parse_ClipboardFormatOrString(o, w/*:number*/)/*:string*/ {
- // $FlowIgnore
- var ClipFmt = { 2: "BITMAP", 3: "METAFILEPICT", 8: "DIB", 14: "ENHMETAFILE" };
- var m/*:number*/ = o.read_shift(4);
- switch (m) {
- case 0x00000000: return "";
- case 0xffffffff: case 0xfffffffe: return ClipFmt[o.read_shift(4)] || "";
- }
- if (m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16));
- o.l -= 4;
- return o.read_shift(0, w == 1 ? "lpstr" : "lpwstr");
-}
-function parse_ClipboardFormatOrAnsiString(o) { return parse_ClipboardFormatOrString(o, 1); }
-function parse_ClipboardFormatOrUnicodeString(o) { return parse_ClipboardFormatOrString(o, 2); }
-
diff --git a/bits/29_xlsenum.js b/bits/29_xlsenum.js
index 05c431e..7cc5004 100644
--- a/bits/29_xlsenum.js
+++ b/bits/29_xlsenum.js
@@ -1,43 +1,45 @@
/* [MS-OLEPS] 2.2 PropertyType */
-//var VT_EMPTY = 0x0000;
-//var VT_NULL = 0x0001;
-var VT_I2 = 0x0002;
-var VT_I4 = 0x0003;
-//var VT_R4 = 0x0004;
-//var VT_R8 = 0x0005;
-//var VT_CY = 0x0006;
-//var VT_DATE = 0x0007;
-//var VT_BSTR = 0x0008;
-//var VT_ERROR = 0x000A;
-var VT_BOOL = 0x000B;
-var VT_VARIANT = 0x000C;
-//var VT_DECIMAL = 0x000E;
-//var VT_I1 = 0x0010;
-//var VT_UI1 = 0x0011;
-//var VT_UI2 = 0x0012;
-var VT_UI4 = 0x0013;
-//var VT_I8 = 0x0014;
-//var VT_UI8 = 0x0015;
-//var VT_INT = 0x0016;
-//var VT_UINT = 0x0017;
-var VT_LPSTR = 0x001E;
-//var VT_LPWSTR = 0x001F;
-var VT_FILETIME = 0x0040;
-var VT_BLOB = 0x0041;
-//var VT_STREAM = 0x0042;
-//var VT_STORAGE = 0x0043;
-//var VT_STREAMED_Object = 0x0044;
-//var VT_STORED_Object = 0x0045;
-//var VT_BLOB_Object = 0x0046;
-var VT_CF = 0x0047;
-//var VT_CLSID = 0x0048;
-//var VT_VERSIONED_STREAM = 0x0049;
-var VT_VECTOR = 0x1000;
-//var VT_ARRAY = 0x2000;
+{
+ //var VT_EMPTY = 0x0000;
+ //var VT_NULL = 0x0001;
+ var VT_I2 = 0x0002;
+ var VT_I4 = 0x0003;
+ //var VT_R4 = 0x0004;
+ //var VT_R8 = 0x0005;
+ //var VT_CY = 0x0006;
+ //var VT_DATE = 0x0007;
+ //var VT_BSTR = 0x0008;
+ //var VT_ERROR = 0x000A;
+ var VT_BOOL = 0x000B;
+ var VT_VARIANT = 0x000C;
+ //var VT_DECIMAL = 0x000E;
+ //var VT_I1 = 0x0010;
+ //var VT_UI1 = 0x0011;
+ //var VT_UI2 = 0x0012;
+ var VT_UI4 = 0x0013;
+ //var VT_I8 = 0x0014;
+ var VT_UI8 = 0x0015;
+ //var VT_INT = 0x0016;
+ //var VT_UINT = 0x0017;
+ var VT_LPSTR = 0x001E;
+ //var VT_LPWSTR = 0x001F;
+ var VT_FILETIME = 0x0040;
+ //var VT_BLOB = 0x0041;
+ //var VT_STREAM = 0x0042;
+ //var VT_STORAGE = 0x0043;
+ //var VT_STREAMED_Object = 0x0044;
+ //var VT_STORED_Object = 0x0045;
+ //var VT_BLOB_Object = 0x0046;
+ var VT_CF = 0x0047;
+ //var VT_CLSID = 0x0048;
+ //var VT_VERSIONED_STREAM = 0x0049;
+ var VT_VECTOR = 0x1000;
+ //var VT_ARRAY = 0x2000;
-var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
-var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
-var VT_CUSTOM = [VT_STRING, VT_USTR];
+ var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
+ var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
+ var VT_CUSTOM = [VT_STRING, VT_USTR];
+}
/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
var DocSummaryPIDDSI = {
@@ -51,17 +53,16 @@ var DocSummaryPIDDSI = {
/*::[*/0x08/*::]*/: { n: 'NoteCount', t: VT_I4 },
/*::[*/0x09/*::]*/: { n: 'HiddenCount', t: VT_I4 },
/*::[*/0x0a/*::]*/: { n: 'MultimediaClipCount', t: VT_I4 },
- /*::[*/0x0b/*::]*/: { n: 'ScaleCrop', t: VT_BOOL },
- /*::[*/0x0c/*::]*/: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
- /*::[*/0x0d/*::]*/: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
+ /*::[*/0x0b/*::]*/: { n: 'Scale', t: VT_BOOL },
+ /*::[*/0x0c/*::]*/: { n: 'HeadingPair', t: VT_VECTOR | VT_VARIANT },
+ /*::[*/0x0d/*::]*/: { n: 'DocParts', t: VT_VECTOR | VT_LPSTR },
/*::[*/0x0e/*::]*/: { n: 'Manager', t: VT_STRING },
/*::[*/0x0f/*::]*/: { n: 'Company', t: VT_STRING },
- /*::[*/0x10/*::]*/: { n: 'LinksUpToDate', t: VT_BOOL },
+ /*::[*/0x10/*::]*/: { n: 'LinksDirty', t: VT_BOOL },
/*::[*/0x11/*::]*/: { n: 'CharacterCount', t: VT_I4 },
/*::[*/0x13/*::]*/: { n: 'SharedDoc', t: VT_BOOL },
- /*::[*/0x16/*::]*/: { n: 'HyperlinksChanged', t: VT_BOOL },
+ /*::[*/0x16/*::]*/: { n: 'HLinksChanged', t: VT_BOOL },
/*::[*/0x17/*::]*/: { n: 'AppVersion', t: VT_I4, p: 'version' },
- /*::[*/0x18/*::]*/: { n: 'DigSig', t: VT_BLOB },
/*::[*/0x1A/*::]*/: { n: 'ContentType', t: VT_STRING },
/*::[*/0x1B/*::]*/: { n: 'ContentStatus', t: VT_STRING },
/*::[*/0x1C/*::]*/: { n: 'Language', t: VT_STRING },
@@ -88,8 +89,8 @@ var SummaryPIDSI = {
/*::[*/0x0F/*::]*/: { n: 'WordCount', t: VT_I4 },
/*::[*/0x10/*::]*/: { n: 'CharCount', t: VT_I4 },
/*::[*/0x11/*::]*/: { n: 'Thumbnail', t: VT_CF },
- /*::[*/0x12/*::]*/: { n: 'Application', t: VT_STRING },
- /*::[*/0x13/*::]*/: { n: 'DocSecurity', t: VT_I4 },
+ /*::[*/0x12/*::]*/: { n: 'ApplicationName', t: VT_LPSTR },
+ /*::[*/0x13/*::]*/: { n: 'DocumentSecurity', t: VT_I4 },
/*::[*/0xFF/*::]*/: {}
};
@@ -101,13 +102,10 @@ var SpecialProperties = {
};
(function() {
- for(var y in SpecialProperties) if(Object.prototype.hasOwnProperty.call(SpecialProperties, y))
+ for(var y in SpecialProperties) if(SpecialProperties.hasOwnProperty(y))
DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
})();
-var DocSummaryRE/*:{[key:string]:string}*/ = evert_key(DocSummaryPIDDSI, "n");
-var SummaryRE/*:{[key:string]:string}*/ = evert_key(SummaryPIDSI, "n");
-
/* [MS-XLS] 2.4.63 Country/Region codes */
var CountryEnum = {
/*::[*/0x0001/*::]*/: "US", // United States
@@ -185,11 +183,11 @@ var XLSFillPattern = [
'gray0625'
];
-function rgbify(arr/*:Array*/)/*:Array<[number, number, number]>*/ { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
+function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
/* [MS-XLS] 2.5.161 */
-/* [MS-XLSB] 2.5.75 Icv */
-var _XLSIcv = rgbify([
+/* [MS-XLSB] 2.5.75 */
+var XLSIcv = rgbify([
/* Color Constants */
0x000000,
0xFFFFFF,
@@ -281,18 +279,4 @@ var _XLSIcv = rgbify([
0x000000, /* 0x50 icvInfoBk ?? */
0x000000 /* 0x51 icvInfoText ?? */
]);
-var XLSIcv = dup(_XLSIcv);
-/* [MS-XLSB] 2.5.97.2 */
-var BErr = {
- /*::[*/0x00/*::]*/: "#NULL!",
- /*::[*/0x07/*::]*/: "#DIV/0!",
- /*::[*/0x0F/*::]*/: "#VALUE!",
- /*::[*/0x17/*::]*/: "#REF!",
- /*::[*/0x1D/*::]*/: "#NAME?",
- /*::[*/0x24/*::]*/: "#NUM!",
- /*::[*/0x2A/*::]*/: "#N/A",
- /*::[*/0x2B/*::]*/: "#GETTING_DATA",
- /*::[*/0xFF/*::]*/: "#WTF?"
-};
-var RBErr = evert_num(BErr);
diff --git a/bits/30_ctype.js b/bits/30_ctype.js
index 93b0120..23d6b16 100644
--- a/bits/30_ctype.js
+++ b/bits/30_ctype.js
@@ -1,7 +1,8 @@
/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
/* 12.3 Part Summary */
/* 14.2 Part Summary */
-/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
+/* [MS-XLSX] 2.1 Part Enumerations */
+/* [MS-XLSB] 2.1.7 Part Enumeration */
var ct2type/*{[string]:string}*/ = ({
/* Workbook */
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
@@ -26,18 +27,12 @@ var ct2type/*{[string]:string}*/ = ({
"application/vnd.ms-excel.pivotTable": "TODO",
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
- /* Chart Objects */
- "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
-
/* Chart Colors */
"application/vnd.ms-office.chartcolorstyle+xml": "TODO",
/* Chart Style */
"application/vnd.ms-office.chartstyle+xml": "TODO",
- /* Chart Advanced */
- "application/vnd.ms-office.chartex+xml": "TODO",
-
/* Calculation Chain */
"application/vnd.ms-excel.calcChain": "calcchains",
"application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
@@ -57,8 +52,8 @@ var ct2type/*{[string]:string}*/ = ({
"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
/* External Links */
- "application/vnd.ms-excel.externalLink": "links",
- "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
+ "application/vnd.ms-excel.externalLink": "TODO",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "TODO",
/* Metadata */
"application/vnd.ms-excel.sheetMetadata": "TODO",
@@ -128,6 +123,7 @@ var ct2type/*{[string]:string}*/ = ({
/* Drawing */
"application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
+ "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
"application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
"application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
@@ -152,7 +148,6 @@ var CT_LIST = (function(){
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
- xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
},
strs: { /* Shared Strings */
@@ -184,7 +179,7 @@ var CT_LIST = (function(){
xlsb: "application/vnd.ms-excel.styles"
}
};
- keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
+ keys(o).forEach(function(k) { if(!o[k].xlsm) o[k].xlsm = o[k].xlsx; });
keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
return o;
})();
@@ -193,17 +188,13 @@ var type2ct/*{[string]:Array}*/ = evert_arr(ct2type);
XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
-function new_ct()/*:any*/ {
- return ({
+function parse_ct(data/*:?string*/, opts) {
+ var ct = ({
workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
- rels:[], strs:[], comments:[], links:[],
+ rels:[], strs:[], comments:[],
coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
calcchains:[], vba: [], drawings: [],
TODO:[], xmlns: "" }/*:any*/);
-}
-
-function parse_ct(data/*:?string*/) {
- var ct = new_ct();
if(!data || !data.match) return ct;
var ctext = {};
(data.match(tagregex)||[]).forEach(function(x) {
@@ -236,7 +227,6 @@ var CTYPE_DEFAULTS = [
['xml', 'application/xml'],
['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
- ['data', 'application/vnd.openxmlformats-officedocument.model+data'],
/* from test files */
['bmp', 'image/bmp'],
['png', 'image/png'],
@@ -256,8 +246,6 @@ function write_ct(ct, opts)/*:string*/ {
o[o.length] = (XML_HEADER);
o[o.length] = (CTYPE_XML_ROOT);
o = o.concat(CTYPE_DEFAULTS);
-
- /* only write first instance */
var f1 = function(w) {
if(ct[w] && ct[w].length > 0) {
v = ct[w][0];
@@ -267,8 +255,6 @@ function write_ct(ct, opts)/*:string*/ {
}));
}
};
-
- /* book type-specific */
var f2 = function(w) {
(ct[w]||[]).forEach(function(v) {
o[o.length] = (writextag('Override', null, {
@@ -277,8 +263,6 @@ function write_ct(ct, opts)/*:string*/ {
}));
});
};
-
- /* standard type */
var f3 = function(t) {
(ct[t]||[]).forEach(function(v) {
o[o.length] = (writextag('Override', null, {
@@ -287,7 +271,6 @@ function write_ct(ct, opts)/*:string*/ {
}));
});
};
-
f1('workbooks');
f2('sheets');
f2('charts');
diff --git a/bits/31_rels.js b/bits/31_rels.js
index 7d731a6..195bbce 100644
--- a/bits/31_rels.js
+++ b/bits/31_rels.js
@@ -4,26 +4,21 @@ var RELS = ({
SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
- XPATH: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",
- XMISS: "http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",
- XLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",
- CXML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml",
- CXMLP: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps",
VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
}/*:any*/);
/* 9.3.3 Representing Relationships */
function get_rels_path(file/*:string*/)/*:string*/ {
var n = file.lastIndexOf("/");
- return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
+ return file.substr(0,n+1) + '_rels/' + file.substr(n+1) + ".rels";
}
function parse_rels(data/*:?string*/, currentFilePath/*:string*/) {
- var rels = {"!id":{}};
- if (!data) return rels;
+ if (!data) return data;
if (currentFilePath.charAt(0) !== '/') {
currentFilePath = '/'+currentFilePath;
}
+ var rels = {};
var hash = {};
(data.match(tagregex)||[]).forEach(function(x) {
@@ -57,16 +52,14 @@ function write_rels(rels)/*:string*/ {
return o.join("");
}
-var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
-function add_rels(rels, rId/*:number*/, f, type, relobj, targetmode/*:?string*/)/*:number*/ {
+function add_rels(rels, rId, f, type, relobj)/*:number*/ {
if(!relobj) relobj = {};
if(!rels['!id']) rels['!id'] = {};
if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
relobj.Id = 'rId' + rId;
relobj.Type = type;
relobj.Target = f;
- if(targetmode) relobj.TargetMode = targetmode;
- else if(RELS_EXTERN.indexOf(relobj.Type) > -1) relobj.TargetMode = "External";
+ if(relobj.Type == RELS.HLINK) relobj.TargetMode = "External";
if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
rels['!id'][relobj.Id] = relobj;
rels[('/' + relobj.Target).replace("//","/")] = relobj;
diff --git a/bits/32_odmanrdf.js b/bits/32_odmanrdf.js
index 1902d90..793a038 100644
--- a/bits/32_odmanrdf.js
+++ b/bits/32_odmanrdf.js
@@ -20,7 +20,7 @@ function parse_manifest(d, opts) {
}
}
-function write_manifest(manifest/*:Array >*/)/*:string*/ {
+function write_manifest(manifest/*:Array >*/, opts)/*:string*/ {
var o = [XML_HEADER];
o.push('\n');
o.push(' \n');
@@ -44,7 +44,7 @@ function write_rdf_has(base/*:string*/, file/*:string*/) {
' \n'
].join("");
}
-function write_rdf(rdf) {
+function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('\n');
for(var i = 0; i != rdf.length; ++i) {
@@ -56,9 +56,9 @@ function write_rdf(rdf) {
return o.join("");
}
/* TODO: pull properties */
-var write_meta_ods/*:{(wb:Workbook, opts:any):string}*/ = (function() {
+var write_meta_ods/*:{(wb:any, opts:any):string}*/ = (function() {
var payload = 'Sheet' + 'JS ' + XLSX.version + '';
- return function wmo(/*:: wb: Workbook, opts: any*/)/*:string*/ {
+ return function wmo(wb, opts) {
return payload;
};
})();
diff --git a/bits/33_coreprops.js b/bits/33_coreprops.js
index 8392a1c..69438fe 100644
--- a/bits/33_coreprops.js
+++ b/bits/33_coreprops.js
@@ -25,19 +25,18 @@ var CORE_PROPS_REGEX/*:Array*/ = (function() {
var r = new Array(CORE_PROPS.length);
for(var i = 0; i < CORE_PROPS.length; ++i) {
var f = CORE_PROPS[i];
- var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
- r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
+ var g = "(?:"+ f[0].substr(0,f[0].indexOf(":")) +":)"+ f[0].substr(f[0].indexOf(":")+1);
+ r[i] = new RegExp("<" + g + "[^>]*>(.*)<\/" + g + ">");
}
return r;
})();
function parse_core_props(data) {
var p = {};
- data = utf8read(data);
for(var i = 0; i < CORE_PROPS.length; ++i) {
var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
- if(cur != null && cur.length > 0) p[f[1]] = unescapexml(cur[1]);
+ if(cur != null && cur.length > 0) p[f[1]] = cur[1];
if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
}
@@ -56,7 +55,6 @@ var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
function cp_doit(f, g, h, o, p) {
if(p[f] != null || g == null || g === "") return;
p[f] = g;
- g = escapexml(g);
o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
}
diff --git a/bits/34_extprops.js b/bits/34_extprops.js
index 3f48266..a31fa79 100644
--- a/bits/34_extprops.js
+++ b/bits/34_extprops.js
@@ -17,75 +17,58 @@ var EXT_PROPS/*:Array >*/ = [
XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
RELS.EXT_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
-var PseudoPropsPairs = [
- "Worksheets", "SheetNames",
- "NamedRanges", "DefinedNames",
- "Chartsheets", "ChartNames"
-];
-function load_props_pairs(HP/*:string|Array>*/, TOP, props, opts) {
- var v = [];
- if(typeof HP == "string") v = parseVector(HP, opts);
- else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
- var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
- var idx = 0, len = 0;
- if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
- len = +(v[i+1].v);
- switch(v[i].v) {
- case "Worksheets":
- case "工作表":
- case "Листы":
- case "أوراق العمل":
- case "ワークシート":
- case "גליונות עבודה":
- case "Arbeitsblätter":
- case "Çalışma Sayfaları":
- case "Feuilles de calcul":
- case "Fogli di lavoro":
- case "Folhas de cálculo":
- case "Planilhas":
- case "Regneark":
- case "Hojas de cálculo":
- case "Werkbladen":
- props.Worksheets = len;
- props.SheetNames = parts.slice(idx, idx + len);
- break;
-
- case "Named Ranges":
- case "Rangos con nombre":
- case "名前付き一覧":
- case "Benannte Bereiche":
- case "Navngivne områder":
- props.NamedRanges = len;
- props.DefinedNames = parts.slice(idx, idx + len);
- break;
-
- case "Charts":
- case "Diagramme":
- props.Chartsheets = len;
- props.ChartNames = parts.slice(idx, idx + len);
- break;
- }
- idx += len;
- }
-}
-
-function parse_ext_props(data, p, opts) {
+function parse_ext_props(data, p) {
var q = {}; if(!p) p = {};
- data = utf8read(data);
EXT_PROPS.forEach(function(f) {
- var xml = (data.match(matchtag(f[0]))||[])[1];
switch(f[2]) {
- case "string": if(xml) p[f[1]] = unescapexml(xml); break;
- case "bool": p[f[1]] = xml === "true"; break;
+ case "string": p[f[1]] = (data.match(matchtag(f[0]))||[])[1]; break;
+ case "bool": p[f[1]] = (data.match(matchtag(f[0]))||[])[1] === "true"; break;
case "raw":
- var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
+ var cur = data.match(new RegExp("<" + f[0] + "[^>]*>(.*)<\/" + f[0] + ">"));
if(cur && cur.length > 0) q[f[1]] = cur[1];
break;
}
});
- if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
+ if(q.HeadingPairs && q.TitlesOfParts) {
+ var v = parseVector(q.HeadingPairs);
+ var parts = parseVector(q.TitlesOfParts).map(function(x) { return x.v; });
+ var idx = 0, len = 0;
+ for(var i = 0; i !== v.length; i+=2) {
+ len = +(v[i+1].v);
+ switch(v[i].v) {
+ case "Worksheets":
+ case "工作表":
+ case "Листы":
+ case "ワークシート":
+ case "גליונות עבודה":
+ case "Arbeitsblätter":
+ case "Çalışma Sayfaları":
+ case "Feuilles de calcul":
+ case "Fogli di lavoro":
+ case "Folhas de cálculo":
+ case "Planilhas":
+ case "Werkbladen":
+ p.Worksheets = len;
+ p.SheetNames = parts.slice(idx, idx + len);
+ break;
+
+ case "Named Ranges":
+ case "Benannte Bereiche":
+ p.NamedRanges = len;
+ p.DefinedNames = parts.slice(idx, idx + len);
+ break;
+
+ case "Charts":
+ case "Diagramme":
+ p.Chartsheets = len;
+ p.ChartNames = parts.slice(idx, idx + len);
+ break;
+ }
+ idx += len;
+ }
+ }
return p;
}
@@ -95,8 +78,8 @@ var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
'xmlns:vt': XMLNS.vt
});
-function write_ext_props(cp/*::, opts*/)/*:string*/ {
- var o/*:Array*/ = [], W = writextag;
+function write_ext_props(cp, opts)/*:string*/ {
+ var o = [], p = {}, W = writextag;
if(!cp) cp = {};
cp.Application = "SheetJS";
o[o.length] = (XML_HEADER);
@@ -106,7 +89,7 @@ function write_ext_props(cp/*::, opts*/)/*:string*/ {
if(cp[f[1]] === undefined) return;
var v;
switch(f[2]) {
- case 'string': v = escapexml(String(cp[f[1]])); break;
+ case 'string': v = String(cp[f[1]]); break;
case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
}
if(v !== undefined) o[o.length] = (W(f[0], v));
diff --git a/bits/35_custprops.js b/bits/35_custprops.js
index 51a7105..8efcd1f 100644
--- a/bits/35_custprops.js
+++ b/bits/35_custprops.js
@@ -11,18 +11,18 @@ function parse_cust_props(data/*:string*/, opts) {
switch(y[0]) {
case '': name = null; break;
default: if (x.indexOf('');
- var type = toks[0].slice(4), text = toks[1];
+ var type = toks[0].substring(4), text = toks[1];
/* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
switch(type) {
case 'lpstr': case 'bstr': case 'lpwstr':
p[name] = unescapexml(text);
break;
case 'bool':
- p[name] = parsexmlbool(text);
+ p[name] = parsexmlbool(text, '');
break;
case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
p[name] = parseInt(text, 10);
@@ -37,10 +37,9 @@ function parse_cust_props(data/*:string*/, opts) {
p[name] = unescapexml(text);
break;
default:
- if(type.slice(-1) == '/') break;
if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
}
- } else if(x.slice(0,2) === "") {/* empty */
+ } else if(x.substr(0,2) === "") {/* empty */
} else if(opts.WTF) throw new Error(x);
}
}
@@ -52,15 +51,16 @@ var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
'xmlns:vt': XMLNS.vt
});
-function write_cust_props(cp/*::, opts*/)/*:string*/ {
+function write_cust_props(cp, opts)/*:string*/ {
var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
if(!cp) return o.join("");
var pid = 1;
keys(cp).forEach(function custprop(k) { ++pid;
- o[o.length] = (writextag('property', write_vt(cp[k], true), {
+ // $FlowIgnore
+ o[o.length] = (writextag('property', write_vt(cp[k]), {
'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
'pid': pid,
- 'name': escapexml(k)
+ 'name': k
}));
});
if(o.length>2){ o[o.length] = ''; o[1]=o[1].replace("/>",">"); }
diff --git a/bits/36_xlsprops.js b/bits/36_xlsprops.js
index 7289aa5..02a491d 100644
--- a/bits/36_xlsprops.js
+++ b/bits/36_xlsprops.js
@@ -39,7 +39,7 @@ function xlml_set_prop(Props, tag/*:string*/, val) {
}
function xlml_write_docprops(Props, opts) {
- var o/*:Array*/ = [];
+ var o = [];
keys(XLMLDocPropsMap).map(function(m) {
for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
@@ -57,13 +57,13 @@ function xlml_write_docprops(Props, opts) {
});
return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
}
-function xlml_write_custprops(Props, Custprops/*::, opts*/) {
+function xlml_write_custprops(Props, Custprops, opts) {
var BLACKLIST = ["Worksheets","SheetNames"];
var T = 'CustomDocumentProperties';
- var o/*:Array*/ = [];
+ var o = [];
if(Props) keys(Props).forEach(function(k) {
/*:: if(!Props) return; */
- if(!Object.prototype.hasOwnProperty.call(Props, k)) return;
+ if(!Props.hasOwnProperty(k)) return;
for(var i = 0; i < CORE_PROPS.length; ++i) if(k == CORE_PROPS[i][1]) return;
for(i = 0; i < EXT_PROPS.length; ++i) if(k == EXT_PROPS[i][1]) return;
for(i = 0; i < BLACKLIST.length; ++i) if(k == BLACKLIST[i]) return;
@@ -77,8 +77,7 @@ function xlml_write_custprops(Props, Custprops/*::, opts*/) {
});
if(Custprops) keys(Custprops).forEach(function(k) {
/*:: if(!Custprops) return; */
- if(!Object.prototype.hasOwnProperty.call(Custprops, k)) return;
- if(Props && Object.prototype.hasOwnProperty.call(Props, k)) return;
+ if(!Custprops.hasOwnProperty(k)) return;
var m = Custprops[k];
var t = "string";
if(typeof m == 'number') { t = "float"; m = String(m); }
diff --git a/bits/38_xlstypes.js b/bits/38_xlstypes.js
index a0189c9..84c87dd 100644
--- a/bits/38_xlstypes.js
+++ b/bits/38_xlstypes.js
@@ -5,21 +5,11 @@ function parse_FILETIME(blob) {
var dwLowDateTime = blob.read_shift(4), dwHighDateTime = blob.read_shift(4);
return new Date(((dwHighDateTime/1e7*Math.pow(2,32) + dwLowDateTime/1e7) - 11644473600)*1000).toISOString().replace(/\.000/,"");
}
-function write_FILETIME(time/*:string|Date*/) {
- var date = (typeof time == "string") ? new Date(Date.parse(time)) : time;
- var t = date.getTime() / 1000 + 11644473600;
- var l = t % Math.pow(2,32), h = (t - l) / Math.pow(2,32);
- l *= 1e7; h *= 1e7;
- var w = (l / Math.pow(2,32)) | 0;
- if(w > 0) { l = l % Math.pow(2,32); h += w; }
- var o = new_buf(8); o.write_shift(4, l); o.write_shift(4, h); return o;
-}
/* [MS-OSHARED] 2.3.3.1.4 Lpstr */
-function parse_lpstr(blob, type, pad/*:?number*/) {
- var start = blob.l;
- var str = blob.read_shift(0, 'lpstr-cp');
- if(pad) while((blob.l - start) & 3) ++blob.l;
+function parse_lpstr(blob, type, pad) {
+ var str = blob.read_shift(0, 'lpstr');
+ if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3;
return str;
}
@@ -38,19 +28,19 @@ function parse_VtStringBase(blob, stringType, pad) {
return parse_lpstr(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); }
+function parse_VtString(blob, t, pad) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); }
+function parse_VtUnalignedString(blob, t) { if(!t) throw new Error("dafuq?"); return parse_VtStringBase(blob, t, 0); }
/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
-function parse_VtVecUnalignedLpstrValue(blob)/*:Array*/ {
+function parse_VtVecUnalignedLpstrValue(blob) {
var length = blob.read_shift(4);
- var ret/*:Array*/ = [];
- for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr-cp').replace(chr0,'');
+ var ret = [];
+ for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr');
return ret;
}
/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
-function parse_VtVecUnalignedLpstr(blob)/*:Array*/ {
+function parse_VtVecUnalignedLpstr(blob) {
return parse_VtVecUnalignedLpstrValue(blob);
}
@@ -83,7 +73,6 @@ function parse_dictionary(blob,CodePage) {
var pid = blob.read_shift(4);
var len = blob.read_shift(4);
dict[pid] = blob.read_shift(len, (CodePage === 0x4B0 ?'utf16le':'utf8')).replace(chr0,'').replace(chr1,'!');
- if(CodePage === 0x4B0 && (len % 2)) blob.l += 2;
}
if(blob.l & 3) blob.l = (blob.l>>2+1)<<2;
return dict;
@@ -93,7 +82,6 @@ function parse_dictionary(blob,CodePage) {
function parse_BLOB(blob) {
var size = blob.read_shift(4);
var bytes = blob.slice(blob.l,blob.l+size);
- blob.l += size;
if((size & 3) > 0) blob.l += (4 - (size & 3)) & 3;
return bytes;
}
@@ -104,12 +92,23 @@ function parse_ClipboardData(blob) {
var o = {};
o.Size = blob.read_shift(4);
//o.Format = blob.read_shift(4);
- blob.l += o.Size + 3 - (o.Size - 1) % 4;
+ blob.l += o.Size;
return o;
}
+/* [MS-OLEPS] 2.14 Vector and Array Property Types */
+function parse_VtVector(blob, cb) {
+ /* [MS-OLEPS] 2.14.2 VectorHeader */
+/* var Length = blob.read_shift(4);
+ var o = [];
+ for(var i = 0; i != Length; ++i) {
+ o.push(cb(blob));
+ }
+ return o;*/
+}
+
/* [MS-OLEPS] 2.15 TypedPropertyValue */
-function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ {
+function parse_TypedPropertyValue(blob, type, _opts) {
var t = blob.read_shift(2), ret, opts = _opts||{};
blob.l += 2;
if(type !== VT_VARIANT)
@@ -124,33 +123,24 @@ function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ {
case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
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 0x50 /*VT_STRING*/: return parse_VtString(blob, t, !opts.raw && 4).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);
default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + t);
}
}
-function write_TypedPropertyValue(type/*:number*/, value) {
- var o = new_buf(4), p = new_buf(4);
- o.write_shift(4, type == 0x50 ? 0x1F : type);
- switch(type) {
- case 0x03 /*VT_I4*/: p.write_shift(-4, value); break;
- case 0x05 /*VT_I4*/: p = new_buf(8); p.write_shift(8, value, 'f'); break;
- case 0x0B /*VT_BOOL*/: p.write_shift(4, value ? 0x01 : 0x00); break;
- case 0x40 /*VT_FILETIME*/: /*:: if(typeof value !== "string" && !(value instanceof Date)) throw "unreachable"; */ p = write_FILETIME(value); break;
- case 0x1F /*VT_LPWSTR*/:
- case 0x50 /*VT_STRING*/:
- /*:: if(typeof value !== "string") throw "unreachable"; */
- p = new_buf(4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
- p.write_shift(4, value.length + 1);
- p.write_shift(0, value, "dbcs");
- while(p.l != p.length) p.write_shift(1, 0);
- break;
- default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + value);
+/* [MS-OLEPS] 2.14.2 VectorHeader */
+/*function parse_VTVectorVariant(blob) {
+ var Length = blob.read_shift(4);
+
+ if(Length & 1 !== 0) throw new Error("VectorHeader Length=" + Length + " must be even");
+ var o = [];
+ for(var i = 0; i != Length; ++i) {
+ o.push(parse_TypedPropertyValue(blob, VT_VARIANT));
}
- return bconcat([o, p]);
-}
+ return o;
+}*/
/* [MS-OLEPS] 2.20 PropertySet */
function parse_PropertySet(blob, PIDSI) {
@@ -165,23 +155,22 @@ function parse_PropertySet(blob, PIDSI) {
var Offset = blob.read_shift(4);
Props[i] = [PropID, Offset + start_addr];
}
- Props.sort(function(x,y) { return x[1] - y[1]; });
var PropH = {};
for(i = 0; i != NumProps; ++i) {
if(blob.l !== Props[i][1]) {
var fail = true;
if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) {
- case 0x02 /*VT_I2*/: if(blob.l+2 === Props[i][1]) { blob.l+=2; fail = false; } break;
+ case 0x02 /*VT_I2*/: if(blob.l +2 === Props[i][1]) { blob.l+=2; fail = false; } break;
case 0x50 /*VT_STRING*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
case 0x100C /*VT_VECTOR|VT_VARIANT*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
}
- if((!PIDSI||i==0) && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
+ if(!PIDSI && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
}
if(PIDSI) {
var piddsi = PIDSI[Props[i][0]];
PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t, {raw:true});
- if(piddsi.p === 'version') PropH[piddsi.n] = String(PropH[piddsi.n] >> 16) + "." + ("0000" + String(PropH[piddsi.n] & 0xFFFF)).slice(-4);
+ if(piddsi.p === 'version') PropH[piddsi.n] = String(PropH[piddsi.n] >> 16) + "." + String(PropH[piddsi.n] & 0xFFFF);
if(piddsi.n == "CodePage") switch(PropH[piddsi.n]) {
case 0: PropH[piddsi.n] = 1252;
/* falls through */
@@ -204,12 +193,12 @@ function parse_PropertySet(blob, PIDSI) {
case 1252:
case 65000: case -536:
case 65001: case -535:
- set_cp(CodePage = (PropH[piddsi.n]>>>0) & 0xFFFF); break;
+ set_cp(CodePage = PropH[piddsi.n]); break;
default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
}
} else {
if(Props[i][0] === 0x1) {
- CodePage = PropH.CodePage = (parse_TypedPropertyValue(blob, VT_I2)/*:number*/);
+ CodePage = PropH.CodePage = parse_TypedPropertyValue(blob, VT_I2);
set_cp(CodePage);
if(Dictionary !== -1) {
var oldpos = blob.l;
@@ -226,8 +215,8 @@ function parse_PropertySet(blob, PIDSI) {
/* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
switch(blob[blob.l]) {
case 0x41 /*VT_BLOB*/: blob.l += 4; val = parse_BLOB(blob); break;
- case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
- case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
+ case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]); break;
+ case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]); break;
case 0x03 /*VT_I4*/: blob.l += 4; val = blob.read_shift(4, 'i'); break;
case 0x13 /*VT_UI4*/: blob.l += 4; val = blob.read_shift(4); break;
case 0x05 /*VT_R8*/: blob.l += 4; val = blob.read_shift(8, 'f'); break;
@@ -242,97 +231,18 @@ function parse_PropertySet(blob, PIDSI) {
blob.l = start_addr + size; /* step ahead to skip padding */
return PropH;
}
-var XLSPSSkip = [ "CodePage", "Thumbnail", "_PID_LINKBASE", "_PID_HLINKS", "SystemIdentifier", "FMTID" ].concat(PseudoPropsPairs);
-function guess_property_type(val/*:any*/)/*:number*/ {
- switch(typeof val) {
- case "boolean": return 0x0B;
- case "number": return ((val|0)==val) ? 0x03 : 0x05;
- case "string": return 0x1F;
- case "object": if(val instanceof Date) return 0x40; break;
- }
- return -1;
-}
-function write_PropertySet(entries, RE, PIDSI) {
- var hdr = new_buf(8), piao = [], prop = [];
- var sz = 8, i = 0;
-
- var pr = new_buf(8), pio = new_buf(8);
- pr.write_shift(4, 0x0002);
- pr.write_shift(4, 0x04B0);
- pio.write_shift(4, 0x0001);
- prop.push(pr); piao.push(pio);
- sz += 8 + pr.length;
-
- if(!RE) {
- pio = new_buf(8);
- pio.write_shift(4, 0);
- piao.unshift(pio);
-
- var bufs = [new_buf(4)];
- bufs[0].write_shift(4, entries.length);
- for(i = 0; i < entries.length; ++i) {
- var value = entries[i][0];
- pr = new_buf(4 + 4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
- pr.write_shift(4, i+2);
- pr.write_shift(4, value.length + 1);
- pr.write_shift(0, value, "dbcs");
- while(pr.l != pr.length) pr.write_shift(1, 0);
- bufs.push(pr);
- }
- pr = bconcat(bufs);
- prop.unshift(pr);
- sz += 8 + pr.length;
- }
-
- for(i = 0; i < entries.length; ++i) {
- if(RE && !RE[entries[i][0]]) continue;
- if(XLSPSSkip.indexOf(entries[i][0]) > -1) continue;
- if(entries[i][1] == null) continue;
-
- var val = entries[i][1], idx = 0;
- if(RE) {
- idx = +RE[entries[i][0]];
- var pinfo = (PIDSI/*:: || {}*/)[idx]/*:: || {} */;
- if(pinfo.p == "version" && typeof val == "string") {
- /*:: if(typeof val !== "string") throw "unreachable"; */
- var arr = val.split(".");
- val = ((+arr[0])<<16) + ((+arr[1])||0);
- }
- pr = write_TypedPropertyValue(pinfo.t, val);
- } else {
- var T = guess_property_type(val);
- if(T == -1) { T = 0x1F; val = String(val); }
- pr = write_TypedPropertyValue(T, val);
- }
- prop.push(pr);
-
- pio = new_buf(8);
- pio.write_shift(4, !RE ? 2+i : idx);
- piao.push(pio);
-
- sz += 8 + pr.length;
- }
-
- var w = 8 * (prop.length + 1);
- for(i = 0; i < prop.length; ++i) { piao[i].write_shift(4, w); w += prop[i].length; }
- hdr.write_shift(4, sz);
- hdr.write_shift(4, prop.length);
- return bconcat([hdr].concat(piao).concat(prop));
-}
/* [MS-OLEPS] 2.21 PropertySetStream */
-function parse_PropertySetStream(file, PIDSI, clsid) {
+function parse_PropertySetStream(file, PIDSI) {
var blob = file.content;
- if(!blob) return ({}/*:any*/);
prep_blob(blob, 0);
var NumSets, FMTID0, FMTID1, Offset0, Offset1 = 0;
blob.chk('feff', 'Byte Order: ');
- /*var vers = */blob.read_shift(2); // TODO: check version
+ var vers = blob.read_shift(2); // TODO: check version
var SystemIdentifier = blob.read_shift(4);
- var CLSID = blob.read_shift(16);
- if(CLSID !== CFB.utils.consts.HEADER_CLSID && CLSID !== clsid) throw new Error("Bad PropertySet CLSID " + CLSID);
+ blob.chk(CFB.utils.consts.HEADER_CLSID, 'CLSID: ');
NumSets = blob.read_shift(4);
if(NumSets !== 1 && NumSets !== 2) throw new Error("Unrecognized #Sets: " + NumSets);
FMTID0 = blob.read_shift(16); Offset0 = blob.read_shift(4);
@@ -347,7 +257,6 @@ function parse_PropertySetStream(file, PIDSI, clsid) {
rval.FMTID = FMTID0;
//rval.PSet0 = PSet0;
if(NumSets === 1) return rval;
- if(Offset1 - blob.l == 2) blob.l += 2;
if(blob.l !== Offset1) throw new Error("Length mismatch 2: " + blob.l + " !== " + Offset1);
var PSet1;
try { PSet1 = parse_PropertySet(blob, null); } catch(e) {/* empty */}
@@ -355,30 +264,9 @@ function parse_PropertySetStream(file, PIDSI, clsid) {
rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
return rval;
}
-function write_PropertySetStream(entries, clsid, RE, PIDSI/*:{[key:string|number]:any}*/, entries2/*:?any*/, clsid2/*:?any*/) {
- var hdr = new_buf(entries2 ? 68 : 48);
- var bufs = [hdr];
- hdr.write_shift(2, 0xFFFE);
- hdr.write_shift(2, 0x0000); /* TODO: type 1 props */
- hdr.write_shift(4, 0x32363237);
- hdr.write_shift(16, CFB.utils.consts.HEADER_CLSID, "hex");
- hdr.write_shift(4, (entries2 ? 2 : 1));
- hdr.write_shift(16, clsid, "hex");
- hdr.write_shift(4, (entries2 ? 68 : 48));
- var ps0 = write_PropertySet(entries, RE, PIDSI);
- bufs.push(ps0);
- if(entries2) {
- var ps1 = write_PropertySet(entries2, null, null);
- hdr.write_shift(16, clsid2, "hex");
- hdr.write_shift(4, 68 + ps0.length);
- bufs.push(ps1);
- }
- return bconcat(bufs);
-}
function parsenoop2(blob, length) { blob.read_shift(length); return null; }
-function writezeroes(n, o) { if(!o) o=new_buf(n); for(var j=0; j= 12 ? 2 : 1);
- var encoding = 'sbcs-cont';
+ var width = 1, encoding = 'sbcs-cont';
var cp = current_codepage;
if(opts && opts.biff >= 8) current_codepage = 1200;
if(!opts || opts.biff == 8 ) {
var fHighByte = blob.read_shift(1);
- if(fHighByte) { encoding = 'dbcs-cont'; }
+ if(fHighByte) { width = 2; encoding = 'dbcs-cont'; }
} else if(opts.biff == 12) {
- encoding = 'wstr';
+ width = 2; encoding = 'wstr';
}
- if(opts.biff >= 2 && opts.biff <= 5) encoding = 'cpstr';
var o = cch ? blob.read_shift(cch, encoding) : "";
current_codepage = cp;
return o;
@@ -431,13 +313,13 @@ function parse_XLUnicodeRichExtendedString(blob) {
var cp = current_codepage;
current_codepage = 1200;
var cch = blob.read_shift(2), flags = blob.read_shift(1);
- var /*fHighByte = flags & 0x1,*/ fExtSt = flags & 0x4, fRichSt = flags & 0x8;
+ var fHighByte = flags & 0x1, fExtSt = flags & 0x4, fRichSt = flags & 0x8;
var width = 1 + (flags & 0x1); // 0x0 -> utf8, 0x1 -> dbcs
var cRun = 0, cbExtRst;
var z = {};
if(fRichSt) cRun = blob.read_shift(2);
if(fExtSt) cbExtRst = blob.read_shift(4);
- var encoding = width == 2 ? 'dbcs-cont' : 'sbcs-cont';
+ var encoding = (flags & 0x1) ? 'dbcs-cont' : 'sbcs-cont';
var msg = cch === 0 ? "" : blob.read_shift(cch, encoding);
if(fRichSt) blob.l += 4 * cRun; //TODO: parse this
if(fExtSt) blob.l += cbExtRst; //TODO: parse this
@@ -446,27 +328,12 @@ function parse_XLUnicodeRichExtendedString(blob) {
current_codepage = cp;
return z;
}
-function write_XLUnicodeRichExtendedString(xlstr/*:: :XLString, opts*/) {
- var str = (xlstr.t||""), nfmts = 1;
-
- var hdr = new_buf(3 + (nfmts > 1 ? 2 : 0));
- hdr.write_shift(2, str.length);
- hdr.write_shift(1, (nfmts > 1 ? 0x08 : 0x00) | 0x01);
- if(nfmts > 1) hdr.write_shift(2, nfmts);
-
- var otext = new_buf(2 * str.length);
- otext.write_shift(2 * str.length, str, 'utf16le');
-
- var out = [hdr, otext];
-
- return bconcat(out);
-}
/* 2.5.296 XLUnicodeStringNoCch */
function parse_XLUnicodeStringNoCch(blob, cch, opts) {
var retval;
if(opts) {
- if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'cpstr');
+ if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'sbcs-cont');
if(opts.biff >= 12) return blob.read_shift(cch, 'dbcs-cont');
}
var fHighByte = blob.read_shift(1);
@@ -486,28 +353,14 @@ function parse_XLUnicodeString2(blob, length, opts) {
if(opts.biff > 5) return parse_XLUnicodeString(blob, length, opts);
var cch = blob.read_shift(1);
if(cch === 0) { blob.l++; return ""; }
- return blob.read_shift(cch, (opts.biff <= 4 || !blob.lens ) ? 'cpstr' : 'sbcs-cont');
-}
-/* TODO: BIFF5 and lower, codepage awareness */
-function write_XLUnicodeString(str, opts, o) {
- if(!o) o = new_buf(3 + 2 * str.length);
- o.write_shift(2, str.length);
- o.write_shift(1, 1);
- o.write_shift(31, str, 'utf16le');
- return o;
+ return blob.read_shift(cch, 'sbcs-cont');
}
/* [MS-XLS] 2.5.61 ControlInfo */
-function parse_ControlInfo(blob/*::, length, opts*/) {
- var flags = blob.read_shift(1);
- blob.l++;
- var accel = blob.read_shift(2);
- blob.l += 2;
- return [flags, accel];
-}
+var parse_ControlInfo = parsenoop;
/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
-function parse_URLMoniker(blob/*::, length, opts*/) {
+var parse_URLMoniker = function(blob/*, length, opts*/) {
var len = blob.read_shift(4), start = blob.l;
var extra = false;
if(len > 24) {
@@ -519,100 +372,63 @@ function parse_URLMoniker(blob/*::, length, opts*/) {
var url = blob.read_shift((extra?len-24:len)>>1, 'utf16le').replace(chr0,"");
if(extra) blob.l += 24;
return url;
-}
+};
/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
-function parse_FileMoniker(blob/*::, length*/) {
- blob.l += 2; //var cAnti = blob.read_shift(2);
- var ansiPath = blob.read_shift(0, 'lpstr-ansi');
- blob.l += 2; //var endServer = blob.read_shift(2);
- if(blob.read_shift(2) != 0xDEAD) throw new Error("Bad FileMoniker");
- var sz = blob.read_shift(4);
- if(sz === 0) return ansiPath.replace(/\\/g,"/");
- var bytes = blob.read_shift(4);
- if(blob.read_shift(2) != 3) throw new Error("Bad FileMoniker");
- var unicodePath = blob.read_shift(bytes>>1, 'utf16le').replace(chr0,"");
+var parse_FileMoniker = function(blob, length) {
+ var cAnti = blob.read_shift(2);
+ var ansiLength = blob.read_shift(4);
+ var ansiPath = blob.read_shift(ansiLength, 'cstr');
+ var endServer = blob.read_shift(2);
+ var versionNumber = blob.read_shift(2);
+ var cbUnicodePathSize = blob.read_shift(4);
+ if(cbUnicodePathSize === 0) return ansiPath.replace(/\\/g,"/");
+ var cbUnicodePathBytes = blob.read_shift(4);
+ var usKeyValue = blob.read_shift(2);
+ var unicodePath = blob.read_shift(cbUnicodePathBytes>>1, 'utf16le').replace(chr0,"");
return unicodePath;
-}
+};
/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
-function parse_HyperlinkMoniker(blob, length) {
+var parse_HyperlinkMoniker = function(blob, length) {
var clsid = blob.read_shift(16); length -= 16;
switch(clsid) {
case "e0c9ea79f9bace118c8200aa004ba90b": return parse_URLMoniker(blob, length);
case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
default: throw new Error("Unsupported Moniker " + clsid);
}
-}
+};
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
-function parse_HyperlinkString(blob/*::, length*/) {
+var parse_HyperlinkString = function(blob, length) {
var len = blob.read_shift(4);
- var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
+ var o = blob.read_shift(len, 'utf16le').replace(chr0, "");
return o;
-}
+};
-/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
-function parse_Hyperlink(blob, length)/*:Hyperlink*/ {
+/* [MS-OSHARED] 2.3.7.1 Hyperlink Object TODO: unify params with XLSX */
+var parse_Hyperlink = function(blob, length) {
var end = blob.l + length;
var sVer = blob.read_shift(4);
if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
var flags = blob.read_shift(2);
blob.l += 2;
- var displayName, targetFrameName, moniker, oleMoniker, Loc="", guid, fileTime;
+ var displayName, targetFrameName, moniker, oleMoniker, location, guid, fileTime;
if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
- if(flags & 0x0008) Loc = parse_HyperlinkString(blob, end - blob.l);
+ if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0020) guid = blob.read_shift(16);
- if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
+ if(flags & 0x0040) fileTime = parse_FILETIME(blob, 8);
blob.l = end;
- var target = targetFrameName||moniker||oleMoniker||"";
- if(target && Loc) target+="#"+Loc;
- if(!target) target = "#" + Loc;
- var out = ({Target:target}/*:any*/);
- if(guid) out.guid = guid;
- if(fileTime) out.time = fileTime;
- if(displayName) out.Tooltip = displayName;
- return out;
-}
-function write_Hyperlink(hl) {
- var out = new_buf(512), i = 0;
- var Target = hl.Target;
- var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
- switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
- out.write_shift(4,2); out.write_shift(4, F);
- var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
- if(F == 0x1C) {
- Target = Target.slice(1);
- out.write_shift(4, Target.length + 1);
- for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
- out.write_shift(2, 0);
- } else if(F & 0x02) {
- data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
- for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
- out.write_shift(4, 2*(Target.length + 1));
- for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
- out.write_shift(2, 0);
- } else {
- data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
- for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
- var P = 0;
- while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
- out.write_shift(2, P);
- out.write_shift(4, Target.length + 1);
- for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
- out.write_shift(1, 0);
- out.write_shift(2, 0xFFFF);
- out.write_shift(2, 0xDEAD);
- for(i = 0; i < 6; ++i) out.write_shift(4, 0);
- }
- return out.slice(0, out.l);
-}
+ var target = (targetFrameName||moniker||oleMoniker);
+ if(location) target+="#"+location;
+ return {Target: target};
+};
/* 2.5.178 LongRGBA */
-function parse_LongRGBA(blob/*::, length*/) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }
+function parse_LongRGBA(blob, length) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }
/* 2.5.177 LongRGB */
function parse_LongRGB(blob, length) { var x = parse_LongRGBA(blob, length); x[3] = 0; return x; }
diff --git a/bits/39_xlsbiff.js b/bits/39_xlsbiff.js
index 755b5de..0b70683 100644
--- a/bits/39_xlsbiff.js
+++ b/bits/39_xlsbiff.js
@@ -1,19 +1,14 @@
-/* [MS-XLS] 2.5.19 */
-function parse_XLSCell(blob/*::, length*/)/*:Cell*/ {
+/* --- MS-XLS --- */
+
+/* 2.5.19 */
+function parse_XLSCell(blob, length)/*:Cell*/ {
var rw = blob.read_shift(2); // 0-indexed
var col = blob.read_shift(2);
var ixfe = blob.read_shift(2);
return ({r:rw, c:col, ixfe:ixfe}/*:any*/);
}
-function write_XLSCell(R/*:number*/, C/*:number*/, ixfe/*:?number*/, o) {
- if(!o) o = new_buf(6);
- o.write_shift(2, R);
- o.write_shift(2, C);
- o.write_shift(2, ixfe||0);
- return o;
-}
-/* [MS-XLS] 2.5.134 */
+/* 2.5.134 */
function parse_frtHeader(blob) {
var rt = blob.read_shift(2);
var flags = blob.read_shift(2); // TODO: parse these flags
@@ -25,21 +20,24 @@ function parse_frtHeader(blob) {
function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
-/* [MS-XLS] 2.5.344 */
-function parse_XTI(blob, length, opts) {
- var w = opts.biff > 8 ? 4 : 2;
- var iSupBook = blob.read_shift(w), itabFirst = blob.read_shift(w,'i'), itabLast = blob.read_shift(w,'i');
+/* 2.5.158 */
+//var HIDEOBJENUM = ['SHOWALL', 'SHOWPLACEHOLDER', 'HIDEALL'];
+var parse_HideObjEnum = parseuint16;
+
+/* 2.5.344 */
+function parse_XTI(blob, length) {
+ var iSupBook = blob.read_shift(2), itabFirst = blob.read_shift(2,'i'), itabLast = blob.read_shift(2,'i');
return [iSupBook, itabFirst, itabLast];
}
-/* [MS-XLS] 2.5.218 */
-function parse_RkRec(blob) {
+/* 2.5.218 */
+function parse_RkRec(blob, length) {
var ixfe = blob.read_shift(2);
var RK = parse_RkNumber(blob);
return [ixfe, RK];
}
-/* [MS-XLS] 2.5.1 */
+/* 2.5.1 */
function parse_AddinUdf(blob, length, opts) {
blob.l += 4; length -= 4;
var l = blob.l + length;
@@ -51,25 +49,17 @@ function parse_AddinUdf(blob, length, opts) {
return udfName;
}
-/* [MS-XLS] 2.5.209 TODO: Check sizes */
-function parse_Ref8U(blob/*::, length*/) {
+/* 2.5.209 TODO: Check sizes */
+function parse_Ref8U(blob, length) {
var rwFirst = blob.read_shift(2);
var rwLast = blob.read_shift(2);
var colFirst = blob.read_shift(2);
var colLast = blob.read_shift(2);
return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
}
-function write_Ref8U(r/*:Range*/, o) {
- if(!o) o = new_buf(8);
- o.write_shift(2, r.s.r);
- o.write_shift(2, r.e.r);
- o.write_shift(2, r.s.c);
- o.write_shift(2, r.e.c);
- return o;
-}
-/* [MS-XLS] 2.5.211 */
-function parse_RefU(blob/*::, length*/) {
+/* 2.5.211 */
+function parse_RefU(blob, length) {
var rwFirst = blob.read_shift(2);
var rwLast = blob.read_shift(2);
var colFirst = blob.read_shift(1);
@@ -77,11 +67,11 @@ function parse_RefU(blob/*::, length*/) {
return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
}
-/* [MS-XLS] 2.5.207 */
+/* 2.5.207 */
var parse_Ref = parse_RefU;
-/* [MS-XLS] 2.5.143 */
-function parse_FtCmo(blob/*::, length*/) {
+/* 2.5.143 */
+function parse_FtCmo(blob, length) {
blob.l += 4;
var ot = blob.read_shift(2);
var id = blob.read_shift(2);
@@ -90,8 +80,8 @@ function parse_FtCmo(blob/*::, length*/) {
return [id, ot, flags];
}
-/* [MS-XLS] 2.5.149 */
-function parse_FtNts(blob) {
+/* 2.5.149 */
+function parse_FtNts(blob, length) {
var out = {};
blob.l += 4;
blob.l += 16; // GUID TODO
@@ -100,16 +90,16 @@ function parse_FtNts(blob) {
return out;
}
-/* [MS-XLS] 2.5.142 */
-function parse_FtCf(blob) {
+/* 2.5.142 */
+function parse_FtCf(blob, length) {
var out = {};
blob.l += 4;
blob.cf = blob.read_shift(2);
return out;
}
-/* [MS-XLS] 2.5.140 - 2.5.154 and friends */
-function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); }
+/* 2.5.140 - 2.5.154 and friends */
+function parse_FtSkip(blob, length) { blob.l += 2; blob.l += blob.read_shift(2); }
var FtTab = {
/*::[*/0x00/*::]*/: parse_FtSkip, /* FtEnd */
/*::[*/0x04/*::]*/: parse_FtSkip, /* FtMacro */
@@ -131,7 +121,7 @@ var FtTab = {
/*::[*/0x14/*::]*/: parse_FtSkip, /* FtCblsFmla */
/*::[*/0x15/*::]*/: parse_FtCmo
};
-function parse_FtArray(blob, length/*::, ot*/) {
+function parse_FtArray(blob, length, ot) {
var tgt = blob.l + length;
var fts = [];
while(blob.l < tgt) {
@@ -145,9 +135,12 @@ function parse_FtArray(blob, length/*::, ot*/) {
return fts;
}
+/* 2.5.129 */
+var parse_FontIndex = parseuint16;
+
/* --- 2.4 Records --- */
-/* [MS-XLS] 2.4.21 */
+/* 2.4.21 */
function parse_BOF(blob, length) {
var o = {BIFFVer:0, dt:0};
o.BIFFVer = blob.read_shift(2); length -= 2;
@@ -155,9 +148,6 @@ function parse_BOF(blob, length) {
switch(o.BIFFVer) {
case 0x0600: /* BIFF8 */
case 0x0500: /* BIFF5 */
- case 0x0400: /* BIFF4 */
- case 0x0300: /* BIFF3 */
- case 0x0200: /* BIFF2 */
case 0x0002: case 0x0007: /* BIFF2 */
break;
default: if(length > 6) throw new Error("Unexpected BIFF Ver " + o.BIFFVer);
@@ -166,67 +156,28 @@ function parse_BOF(blob, length) {
blob.read_shift(length);
return o;
}
-function write_BOF(wb/*:Workbook*/, t/*:number*/, o) {
- var h = 0x0600, w = 16;
- switch(o.bookType) {
- case 'biff8': break;
- case 'biff5': h = 0x0500; w = 8; break;
- case 'biff4': h = 0x0004; w = 6; break;
- case 'biff3': h = 0x0003; w = 6; break;
- case 'biff2': h = 0x0002; w = 4; break;
- case 'xla': break;
- default: throw new Error("unsupported BIFF version");
- }
- var out = new_buf(w);
- out.write_shift(2, h);
- out.write_shift(2, t);
- if(w > 4) out.write_shift(2, 0x7262);
- if(w > 6) out.write_shift(2, 0x07CD);
- if(w > 8) {
- out.write_shift(2, 0xC009);
- out.write_shift(2, 0x0001);
- out.write_shift(2, 0x0706);
- out.write_shift(2, 0x0000);
- }
- return out;
-}
-/* [MS-XLS] 2.4.146 */
+/* 2.4.146 */
function parse_InterfaceHdr(blob, length) {
if(length === 0) return 0x04b0;
- if((blob.read_shift(2))!==0x04b0){/* empty */}
+ var q;
+ if((q=blob.read_shift(2))!==0x04b0){/* empty */}
return 0x04b0;
}
-/* [MS-XLS] 2.4.349 */
+/* 2.4.349 */
function parse_WriteAccess(blob, length, opts) {
if(opts.enc) { blob.l += length; return ""; }
var l = blob.l;
// TODO: make sure XLUnicodeString doesnt overrun
- var UserName = parse_XLUnicodeString2(blob, 0, opts);
+ var UserName = parse_XLUnicodeString(blob, 0, opts);
blob.read_shift(length + l - blob.l);
return UserName;
}
-function write_WriteAccess(s/*:string*/, opts) {
- var b8 = !opts || opts.biff == 8;
- var o = new_buf(b8 ? 112 : 54);
- o.write_shift(opts.biff == 8 ? 2 : 1, 7);
- if(b8) o.write_shift(1, 0);
- o.write_shift(4, 0x33336853);
- o.write_shift(4, (0x00534A74 | (b8 ? 0 : 0x20000000)));
- while(o.l < o.length) o.write_shift(1, (b8 ? 0 : 32));
- return o;
-}
-/* [MS-XLS] 2.4.351 */
-function parse_WsBool(blob, length, opts) {
- var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0);
- return { fDialog: flags & 0x10 };
-}
-
-/* [MS-XLS] 2.4.28 */
+/* 2.4.28 */
function parse_BoundSheet8(blob, length, opts) {
var pos = blob.read_shift(4);
var hidden = blob.read_shift(1) & 0x03;
@@ -241,43 +192,20 @@ function parse_BoundSheet8(blob, length, opts) {
if(name.length === 0) name = "Sheet1";
return { pos:pos, hs:hidden, dt:dt, name:name };
}
-function write_BoundSheet8(data, opts) {
- var w = (!opts || opts.biff >= 8 ? 2 : 1);
- var o = new_buf(8 + w * data.name.length);
- o.write_shift(4, data.pos);
- o.write_shift(1, data.hs || 0);
- o.write_shift(1, data.dt);
- o.write_shift(1, data.name.length);
- if(opts.biff >= 8) o.write_shift(1, 1);
- o.write_shift(w * data.name.length, data.name, opts.biff < 8 ? 'sbcs' : 'utf16le');
- var out = o.slice(0, o.l);
- out.l = o.l; return out;
-}
-/* [MS-XLS] 2.4.265 TODO */
+/* 2.4.265 TODO */
function parse_SST(blob, length)/*:SST*/ {
- var end = blob.l + length;
var cnt = blob.read_shift(4);
var ucnt = blob.read_shift(4);
var strs/*:SST*/ = ([]/*:any*/);
- for(var i = 0; i != ucnt && blob.l < end; ++i) {
+ for(var i = 0; i != ucnt; ++i) {
strs.push(parse_XLUnicodeRichExtendedString(blob));
}
strs.Count = cnt; strs.Unique = ucnt;
return strs;
}
-function write_SST(sst, opts) {
- var header = new_buf(8);
- header.write_shift(4, sst.Count);
- header.write_shift(4, sst.Unique);
- var strs = [];
- for(var j = 0; j < sst.length; ++j) strs[j] = write_XLUnicodeRichExtendedString(sst[j], opts);
- var o = bconcat([header].concat(strs));
- /*::(*/o/*:: :any)*/.parts = [header.length].concat(strs.map(function(str) { return str.length; }));
- return o;
-}
-/* [MS-XLS] 2.4.107 */
+/* 2.4.107 */
function parse_ExtSST(blob, length) {
var extsst = {};
extsst.dsst = blob.read_shift(2);
@@ -286,8 +214,8 @@ function parse_ExtSST(blob, length) {
}
-/* [MS-XLS] 2.4.221 TODO: check BIFF2-4 */
-function parse_Row(blob) {
+/* 2.4.221 TODO: check BIFF2-4 */
+function parse_Row(blob, length) {
var z = ({}/*:any*/);
z.r = blob.read_shift(2);
z.c = blob.read_shift(2);
@@ -296,16 +224,14 @@ function parse_Row(blob) {
blob.l += 4; // reserved(2), unused(2)
var flags = blob.read_shift(1); // various flags
blob.l += 3; // reserved(8), ixfe(12), flags(4)
- if(flags & 0x07) z.level = flags & 0x07;
- // collapsed: flags & 0x10
if(flags & 0x20) z.hidden = true;
if(flags & 0x40) z.hpt = miyRw / 20;
return z;
}
-/* [MS-XLS] 2.4.125 */
-function parse_ForceFullCalculation(blob) {
+/* 2.4.125 */
+function parse_ForceFullCalculation(blob, length) {
var header = parse_frtHeader(blob);
if(header.type != 0x08A3) throw new Error("Invalid Future Record " + header.type);
var fullcalc = blob.read_shift(4);
@@ -313,16 +239,17 @@ function parse_ForceFullCalculation(blob) {
}
+var parse_CompressPictures = parsenoop2; /* 2.4.55 Not interesting */
-/* [MS-XLS] 2.4.215 rt */
-function parse_RecalcId(blob) {
+/* 2.4.215 rt */
+function parse_RecalcId(blob, length) {
blob.read_shift(2);
return blob.read_shift(4);
}
-/* [MS-XLS] 2.4.87 */
+/* 2.4.87 */
function parse_DefaultRowHeight(blob, length, opts) {
var f = 0;
if(!(opts && opts.biff == 2)) {
@@ -336,55 +263,22 @@ function parse_DefaultRowHeight(blob, length, opts) {
return [fl, miyRw];
}
-/* [MS-XLS] 2.4.345 TODO */
-function parse_Window1(blob) {
+/* 2.4.345 TODO */
+function parse_Window1(blob, length) {
var xWn = blob.read_shift(2), yWn = blob.read_shift(2), dxWn = blob.read_shift(2), dyWn = blob.read_shift(2);
var flags = blob.read_shift(2), iTabCur = blob.read_shift(2), iTabFirst = blob.read_shift(2);
var ctabSel = blob.read_shift(2), wTabRatio = blob.read_shift(2);
return { Pos: [xWn, yWn], Dim: [dxWn, dyWn], Flags: flags, CurTab: iTabCur,
FirstTab: iTabFirst, Selected: ctabSel, TabRatio: wTabRatio };
}
-function write_Window1(/*::opts*/) {
- var o = new_buf(18);
- o.write_shift(2, 0);
- o.write_shift(2, 0);
- o.write_shift(2, 0x7260);
- o.write_shift(2, 0x44c0);
- o.write_shift(2, 0x38);
- o.write_shift(2, 0);
- o.write_shift(2, 0);
- o.write_shift(2, 1);
- o.write_shift(2, 0x01f4);
- return o;
-}
-/* [MS-XLS] 2.4.346 TODO */
-function parse_Window2(blob, length, opts) {
- if(opts && opts.biff >= 2 && opts.biff < 5) return {};
- var f = blob.read_shift(2);
- return { RTL: f & 0x40 };
-}
-function write_Window2(view) {
- var o = new_buf(18), f = 0x6b6;
- if(view && view.RTL) f |= 0x40;
- o.write_shift(2, f);
- o.write_shift(4, 0);
- o.write_shift(4, 64);
- o.write_shift(4, 0);
- o.write_shift(4, 0);
- return o;
-}
-/* [MS-XLS] 2.4.189 TODO */
-function parse_Pane(/*blob, length, opts*/) {
-}
-
-/* [MS-XLS] 2.4.122 TODO */
+/* 2.4.122 TODO */
function parse_Font(blob, length, opts) {
var o/*:any*/ = {
dyHeight: blob.read_shift(2),
fl: blob.read_shift(2)
};
- switch((opts && opts.biff) || 8) {
+ switch(opts && opts.biff || 8) {
case 2: break;
case 3: case 4: blob.l += 2; break;
default: blob.l += 10; break;
@@ -392,35 +286,15 @@ function parse_Font(blob, length, opts) {
o.name = parse_ShortXLUnicodeString(blob, 0, opts);
return o;
}
-function write_Font(data, opts) {
- var name = data.name || "Arial";
- var b5 = (opts && (opts.biff == 5)), w = (b5 ? (15 + name.length) : (16 + 2 * name.length));
- var o = new_buf(w);
- o.write_shift(2, (data.sz || 12) * 20);
- o.write_shift(4, 0);
- o.write_shift(2, 400);
- o.write_shift(4, 0);
- o.write_shift(2, 0);
- o.write_shift(1, name.length);
- if(!b5) o.write_shift(1, 1);
- o.write_shift((b5 ? 1 : 2) * name.length, name, (b5 ? "sbcs" : "utf16le"));
- return o;
-}
-/* [MS-XLS] 2.4.149 */
-function parse_LabelSst(blob) {
+/* 2.4.149 */
+function parse_LabelSst(blob, length) {
var cell = parse_XLSCell(blob);
cell.isst = blob.read_shift(4);
return cell;
}
-function write_LabelSst(R/*:number*/, C/*:number*/, v/*:number*/, os/*:number*/ /*::, opts*/) {
- var o = new_buf(10);
- write_XLSCell(R, C, os, o);
- o.write_shift(4, v);
- return o;
-}
-/* [MS-XLS] 2.4.148 */
+/* 2.4.148 */
function parse_Label(blob, length, opts) {
var target = blob.l + length;
var cell = parse_XLSCell(blob, 6);
@@ -429,37 +303,16 @@ function parse_Label(blob, length, opts) {
cell.val = str;
return cell;
}
-function write_Label(R/*:number*/, C/*:number*/, v/*:string*/, os/*:number*/, opts) {
- var b8 = !opts || opts.biff == 8;
- var o = new_buf(6 + 2 + (+b8) + (1 + b8) * v.length);
- write_XLSCell(R, C, os, o);
- o.write_shift(2, v.length);
- if(b8) o.write_shift(1, 1);
- o.write_shift((1 + b8) * v.length, v, b8 ? 'utf16le' : 'sbcs');
- return o;
-}
-
-/* [MS-XLS] 2.4.126 Number Formats */
+/* 2.4.126 Number Formats */
function parse_Format(blob, length, opts) {
- var numFmtId = blob.read_shift(2);
+ var ifmt = blob.read_shift(2);
var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
- return [numFmtId, fmtstr];
-}
-function write_Format(i/*:number*/, f/*:string*/, opts, o) {
- var b5 = (opts && (opts.biff == 5));
- if(!o) o = new_buf(b5 ? (3 + f.length) : (5 + 2 * f.length));
- o.write_shift(2, i);
- o.write_shift((b5 ? 1 : 2), f.length);
- if(!b5) o.write_shift(1, 1);
- o.write_shift((b5 ? 1 : 2) * f.length, f, (b5 ? 'sbcs' : 'utf16le'));
- var out = (o.length > o.l) ? o.slice(0, o.l) : o;
- if(out.l == null) out.l = out.length;
- return out;
+ return [ifmt, fmtstr];
}
var parse_BIFF2Format = parse_XLUnicodeString2;
-/* [MS-XLS] 2.4.90 */
+/* 2.4.90 */
function parse_Dimensions(blob, length, opts) {
var end = blob.l + length;
var w = opts.biff == 8 || !opts.biff ? 4 : 2;
@@ -468,25 +321,15 @@ function parse_Dimensions(blob, length, opts) {
blob.l = end;
return {s: {r:r, c:c}, e: {r:R, c:C}};
}
-function write_Dimensions(range, opts) {
- var w = opts.biff == 8 || !opts.biff ? 4 : 2;
- var o = new_buf(2*w + 6);
- o.write_shift(w, range.s.r);
- o.write_shift(w, range.e.r + 1);
- o.write_shift(2, range.s.c);
- o.write_shift(2, range.e.c + 1);
- o.write_shift(2, 0);
- return o;
-}
-/* [MS-XLS] 2.4.220 */
-function parse_RK(blob) {
+/* 2.4.220 */
+function parse_RK(blob, length) {
var rw = blob.read_shift(2), col = blob.read_shift(2);
var rkrec = parse_RkRec(blob);
return {r:rw, c:col, ixfe:rkrec[0], rknum:rkrec[1]};
}
-/* [MS-XLS] 2.4.175 */
+/* 2.4.175 */
function parse_MulRk(blob, length) {
var target = blob.l + length - 2;
var rw = blob.read_shift(2), col = blob.read_shift(2);
@@ -497,7 +340,7 @@ function parse_MulRk(blob, length) {
if(rkrecs.length != lastcol - col + 1) throw new Error("MulRK length mismatch");
return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
}
-/* [MS-XLS] 2.4.174 */
+/* 2.4.174 */
function parse_MulBlank(blob, length) {
var target = blob.l + length - 2;
var rw = blob.read_shift(2), col = blob.read_shift(2);
@@ -509,7 +352,7 @@ function parse_MulBlank(blob, length) {
return {r:rw, c:col, C:lastcol, ixfe:ixfes};
}
-/* [MS-XLS] 2.5.20 2.5.249 TODO: interpret values here */
+/* 2.5.20 2.5.249 TODO: interpret values here */
function parse_CellStyleXF(blob, length, style, opts) {
var o = {};
var a = blob.read_shift(4), b = blob.read_shift(4);
@@ -550,38 +393,21 @@ function parse_CellStyleXF(blob, length, style, opts) {
o.fsxButton = (d >> 14) & 0x01;
return o;
}
-//function parse_CellXF(blob, length, opts) {return parse_CellStyleXF(blob,length,0, opts);}
-//function parse_StyleXF(blob, length, opts) {return parse_CellStyleXF(blob,length,1, opts);}
+function parse_CellXF(blob, length, opts) {return parse_CellStyleXF(blob,length,0, opts);}
+function parse_StyleXF(blob, length, opts) {return parse_CellStyleXF(blob,length,1, opts);}
-/* [MS-XLS] 2.4.353 TODO: actually do this right */
+/* 2.4.353 TODO: actually do this right */
function parse_XF(blob, length, opts) {
var o = {};
- o.ifnt = blob.read_shift(2); o.numFmtId = blob.read_shift(2); o.flags = blob.read_shift(2);
+ o.ifnt = blob.read_shift(2); o.ifmt = blob.read_shift(2); o.flags = blob.read_shift(2);
o.fStyle = (o.flags >> 2) & 0x01;
length -= 6;
o.data = parse_CellStyleXF(blob, length, o.fStyle, opts);
return o;
}
-function write_XF(data, ixfeP, opts, o) {
- var b5 = (opts && (opts.biff == 5));
- if(!o) o = new_buf(b5 ? 16 : 20);
- o.write_shift(2, 0);
- if(data.style) {
- o.write_shift(2, (data.numFmtId||0));
- o.write_shift(2, 0xFFF4);
- } else {
- o.write_shift(2, (data.numFmtId||0));
- o.write_shift(2, (ixfeP<<4));
- }
- o.write_shift(4, 0);
- o.write_shift(4, 0);
- if(!b5) o.write_shift(4, 0);
- o.write_shift(2, 0);
- return o;
-}
-/* [MS-XLS] 2.4.134 */
-function parse_Guts(blob) {
+/* 2.4.134 */
+function parse_Guts(blob, length) {
blob.l += 4;
var out = [blob.read_shift(2), blob.read_shift(2)];
if(out[0] !== 0) out[0]--;
@@ -589,15 +415,8 @@ function parse_Guts(blob) {
if(out[0] > 7 || out[1] > 7) throw new Error("Bad Gutters: " + out.join("|"));
return out;
}
-function write_Guts(guts/*:Array*/) {
- var o = new_buf(8);
- o.write_shift(4, 0);
- o.write_shift(2, guts[0] ? guts[0] + 1 : 0);
- o.write_shift(2, guts[1] ? guts[1] + 1 : 0);
- return o;
-}
-/* [MS-XLS] 2.4.24 */
+/* 2.4.24 */
function parse_BoolErr(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
if(opts.biff == 2) ++blob.l;
@@ -606,30 +425,18 @@ function parse_BoolErr(blob, length, opts) {
cell.t = (val === true || val === false) ? 'b' : 'e';
return cell;
}
-function write_BoolErr(R/*:number*/, C/*:number*/, v, os/*:number*/, opts, t/*:string*/) {
- var o = new_buf(8);
- write_XLSCell(R, C, os, o);
- write_Bes(v, t, o);
- return o;
-}
-/* [MS-XLS] 2.4.180 Number */
-function parse_Number(blob) {
+/* 2.4.180 Number */
+function parse_Number(blob, length) {
var cell = parse_XLSCell(blob, 6);
var xnum = parse_Xnum(blob, 8);
cell.val = xnum;
return cell;
}
-function write_Number(R/*:number*/, C/*:number*/, v, os/*:: :number, opts*/) {
- var o = new_buf(14);
- write_XLSCell(R, C, os, o);
- write_Xnum(v, o);
- return o;
-}
var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
-/* [MS-XLS] 2.4.271 */
+/* 2.4.271 */
function parse_SupBook(blob, length, opts) {
var end = blob.l + length;
var ctab = blob.read_shift(2);
@@ -638,13 +445,11 @@ function parse_SupBook(blob, length, opts) {
if(cch == 0x0401 || cch == 0x3A01) return [cch, ctab];
if(cch < 0x01 || cch >0xff) throw new Error("Unexpected SupBook type: "+cch);
var virtPath = parse_XLUnicodeStringNoCch(blob, cch);
- /* TODO: 2.5.277 Virtual Path */
- var rgst = [];
- while(end > blob.l) rgst.push(parse_XLUnicodeString(blob));
+ var rgst = blob.read_shift(end - blob.l);
return [cch, ctab, virtPath, rgst];
}
-/* [MS-XLS] 2.4.105 TODO */
+/* 2.4.105 TODO */
function parse_ExternName(blob, length, opts) {
var flags = blob.read_shift(2);
var body;
@@ -664,7 +469,7 @@ function parse_ExternName(blob, length, opts) {
return o;
}
-/* [MS-XLS] 2.4.150 TODO */
+/* 2.4.150 TODO */
var XLSLblBuiltIn = [
"_xlnm.Consolidate_Area",
"_xlnm.Auto_Open",
@@ -689,15 +494,14 @@ function parse_Lbl(blob, length, opts) {
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
var itab = 0;
if(!opts || opts.biff >= 5) {
- if(opts.biff != 5) blob.l += 2;
+ blob.l += 2;
itab = blob.read_shift(2);
- if(opts.biff == 5) blob.l += 2;
blob.l += 4;
}
var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
if(flags & 0x20) name = XLSLblBuiltIn[name.charCodeAt(0)];
var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen;
- var rgce = (target == blob.l || cce === 0 || !(npflen > 0)) ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
+ var rgce = target == blob.l || cce == 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
return {
chKey: chKey,
Name: name,
@@ -706,22 +510,17 @@ function parse_Lbl(blob, length, opts) {
};
}
-/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
+/* 2.4.106 TODO: verify supbook manipulation */
function parse_ExternSheet(blob, length, opts) {
- if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts);
- var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2);
- while(len-- !== 0) o.push(parse_XTI(blob, opts.biff > 8 ? 12 : 6, opts));
+ if(opts.biff < 8) return parse_ShortXLUnicodeString(blob, length, opts);
+ var o = [], target = blob.l + length, len = blob.read_shift(2);
+ while(len-- !== 0) o.push(parse_XTI(blob, 6));
// [iSupBook, itabFirst, itabLast];
- if(blob.l != target) throw new Error("Bad ExternSheet: " + blob.l + " != " + target);
+ var oo = [];
return o;
}
-function parse_BIFF5ExternSheet(blob, length, opts) {
- if(blob[blob.l + 1] == 0x03) blob[blob.l]++;
- var o = parse_ShortXLUnicodeString(blob, length, opts);
- return o.charCodeAt(0) == 0x03 ? o.slice(1) : o;
-}
-/* [MS-XLS] 2.4.176 TODO: check older biff */
+/* 2.4.176 TODO: check older biff */
function parse_NameCmt(blob, length, opts) {
if(opts.biff < 8) { blob.l += length; return; }
var cchName = blob.read_shift(2);
@@ -731,16 +530,16 @@ function parse_NameCmt(blob, length, opts) {
return [name, comment];
}
-/* [MS-XLS] 2.4.260 */
+/* 2.4.260 */
function parse_ShrFmla(blob, length, opts) {
var ref = parse_RefU(blob, 6);
blob.l++;
var cUse = blob.read_shift(1);
length -= 8;
- return [parse_SharedParsedFormula(blob, length, opts), cUse, ref];
+ return [parse_SharedParsedFormula(blob, length, opts), cUse];
}
-/* [MS-XLS] 2.4.4 TODO */
+/* 2.4.4 TODO */
function parse_Array(blob, length, opts) {
var ref = parse_Ref(blob, 6);
/* TODO: fAlwaysCalc */
@@ -752,15 +551,15 @@ function parse_Array(blob, length, opts) {
return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
}
-/* [MS-XLS] 2.4.173 */
-function parse_MTRSettings(blob) {
+/* 2.4.173 */
+function parse_MTRSettings(blob, length) {
var fMTREnabled = blob.read_shift(4) !== 0x00;
var fUserSetThreadCount = blob.read_shift(4) !== 0x00;
var cUserThreadCount = blob.read_shift(4);
return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
}
-/* [MS-XLS] 2.5.186 TODO: BIFF5 */
+/* 2.5.186 TODO: BIFF5 */
function parse_NoteSh(blob, length, opts) {
if(opts.biff < 8) return;
var row = blob.read_shift(2), col = blob.read_shift(2);
@@ -770,27 +569,21 @@ function parse_NoteSh(blob, length, opts) {
return [{r:row,c:col}, stAuthor, idObj, flags];
}
-/* [MS-XLS] 2.4.179 */
+/* 2.4.179 */
function parse_Note(blob, length, opts) {
/* TODO: Support revisions */
return parse_NoteSh(blob, length, opts);
}
-/* [MS-XLS] 2.4.168 */
-function parse_MergeCells(blob, length)/*:Array*/ {
- var merges/*:Array*/ = [];
+/* 2.4.168 */
+function parse_MergeCells(blob, length) {
+ var merges = [];
var cmcs = blob.read_shift(2);
while (cmcs--) merges.push(parse_Ref8U(blob,length));
return merges;
}
-function write_MergeCells(merges/*:Array*/) {
- var o = new_buf(2 + merges.length * 8);
- o.write_shift(2, merges.length);
- for(var i = 0; i < merges.length; ++i) write_Ref8U(merges[i], o);
- return o;
-}
-/* [MS-XLS] 2.4.181 TODO: parse all the things! */
+/* 2.4.181 TODO: parse all the things! */
function parse_Obj(blob, length, opts) {
if(opts && opts.biff < 8) return parse_BIFF5Obj(blob, length, opts);
var cmo = parse_FtCmo(blob, 22); // id, ot, flags
@@ -799,14 +592,14 @@ function parse_Obj(blob, length, opts) {
}
/* from older spec */
var parse_BIFF5OT = [];
-parse_BIFF5OT[0x08] = function(blob, length) {
+parse_BIFF5OT[0x08] = function(blob, length, opts) {
var tgt = blob.l + length;
blob.l += 10; // todo
var cf = blob.read_shift(2);
blob.l += 4;
- blob.l += 2; //var cbPictFmla = blob.read_shift(2);
+ var cbPictFmla = blob.read_shift(2);
blob.l += 2;
- blob.l += 2; //var grbit = blob.read_shift(2);
+ var grbit = blob.read_shift(2);
blob.l += 4;
var cchName = blob.read_shift(1);
blob.l += cchName; // TODO: stName
@@ -815,19 +608,19 @@ parse_BIFF5OT[0x08] = function(blob, length) {
};
function parse_BIFF5Obj(blob, length, opts) {
- blob.l += 4; //var cnt = blob.read_shift(4);
+ var cnt = blob.read_shift(4);
var ot = blob.read_shift(2);
var id = blob.read_shift(2);
var grbit = blob.read_shift(2);
- blob.l += 2; //var colL = blob.read_shift(2);
- blob.l += 2; //var dxL = blob.read_shift(2);
- blob.l += 2; //var rwT = blob.read_shift(2);
- blob.l += 2; //var dyT = blob.read_shift(2);
- blob.l += 2; //var colR = blob.read_shift(2);
- blob.l += 2; //var dxR = blob.read_shift(2);
- blob.l += 2; //var rwB = blob.read_shift(2);
- blob.l += 2; //var dyB = blob.read_shift(2);
- blob.l += 2; //var cbMacro = blob.read_shift(2);
+ var colL = blob.read_shift(2);
+ var dxL = blob.read_shift(2);
+ var rwT = blob.read_shift(2);
+ var dyT = blob.read_shift(2);
+ var colR = blob.read_shift(2);
+ var dxR = blob.read_shift(2);
+ var rwB = blob.read_shift(2);
+ var dyB = blob.read_shift(2);
+ var cbMacro = blob.read_shift(2);
blob.l += 6;
length -= 36;
var fts = [];
@@ -835,19 +628,19 @@ function parse_BIFF5Obj(blob, length, opts) {
return { cmo: [id, ot, grbit], ft:fts };
}
-/* [MS-XLS] 2.4.329 TODO: parse properly */
+/* 2.4.329 TODO: parse properly */
function parse_TxO(blob, length, opts) {
var s = blob.l;
var texts = "";
try {
blob.l += 4;
var ot = (opts.lastobj||{cmo:[0,0]}).cmo[1];
- var controlInfo; // eslint-disable-line no-unused-vars
+ var controlInfo;
if([0,5,7,11,12,14].indexOf(ot) == -1) blob.l += 6;
else controlInfo = parse_ControlInfo(blob, 6, opts);
var cchText = blob.read_shift(2);
- /*var cbRuns = */blob.read_shift(2);
- /*var ifntEmpty = */parseuint16(blob, 2);
+ var cbRuns = blob.read_shift(2);
+ var ifntEmpty = parse_FontIndex(blob, 2);
var len = blob.read_shift(2);
blob.l += len;
//var fmla = parse_ObjFmla(blob, s + length - blob.l);
@@ -864,7 +657,7 @@ try {
}
blob.l = s + length;
- /* [MS-XLS] 2.5.272 TxORuns */
+ /* 2.5.272 TxORuns */
// var rgTxoRuns = [];
// for(var j = 0; j != cbRuns/8-1; ++j) blob.l += 8;
// var cchText2 = blob.read_shift(2);
@@ -875,76 +668,50 @@ try {
} catch(e) { blob.l = s + length; return { t: texts }; }
}
-/* [MS-XLS] 2.4.140 */
-function parse_HLink(blob, length) {
+/* 2.4.140 */
+var parse_HLink = function(blob, length) {
var ref = parse_Ref8U(blob, 8);
blob.l += 16; /* CLSID */
var hlink = parse_Hyperlink(blob, length-24);
return [ref, hlink];
-}
-function write_HLink(hl) {
- var O = new_buf(24);
- var ref = decode_cell(hl[0]);
- O.write_shift(2, ref.r); O.write_shift(2, ref.r);
- O.write_shift(2, ref.c); O.write_shift(2, ref.c);
- var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
- for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
- return bconcat([O, write_Hyperlink(hl[1])]);
-}
+};
-
-/* [MS-XLS] 2.4.141 */
-function parse_HLinkTooltip(blob, length) {
+/* 2.4.141 */
+var parse_HLinkTooltip = function(blob, length) {
+ var end = blob.l + length;
blob.read_shift(2);
var ref = parse_Ref8U(blob, 8);
var wzTooltip = blob.read_shift((length-10)/2, 'dbcs-cont');
wzTooltip = wzTooltip.replace(chr0,"");
return [ref, wzTooltip];
-}
-function write_HLinkTooltip(hl) {
- var TT = hl[1].Tooltip;
- var O = new_buf(10 + 2 * (TT.length + 1));
- O.write_shift(2, 0x0800);
- var ref = decode_cell(hl[0]);
- O.write_shift(2, ref.r); O.write_shift(2, ref.r);
- O.write_shift(2, ref.c); O.write_shift(2, ref.c);
- for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
- O.write_shift(2, 0);
- return O;
-}
+};
-/* [MS-XLS] 2.4.63 */
-function parse_Country(blob)/*:[string|number, string|number]*/ {
- var o = [0,0], d;
+/* 2.4.63 */
+function parse_Country(blob, length) {
+ var o = [], d;
d = blob.read_shift(2); o[0] = CountryEnum[d] || d;
d = blob.read_shift(2); o[1] = CountryEnum[d] || d;
return o;
}
-function write_Country(o) {
- if(!o) o = new_buf(4);
- o.write_shift(2, 0x01);
- o.write_shift(2, 0x01);
- return o;
-}
-/* [MS-XLS] 2.4.50 ClrtClient */
-function parse_ClrtClient(blob) {
+/* 2.4.50 ClrtClient */
+function parse_ClrtClient(blob, length) {
var ccv = blob.read_shift(2);
var o = [];
while(ccv-->0) o.push(parse_LongRGB(blob, 8));
return o;
}
-/* [MS-XLS] 2.4.188 */
-function parse_Palette(blob) {
+/* 2.4.188 */
+function parse_Palette(blob, length) {
var ccv = blob.read_shift(2);
var o = [];
while(ccv-->0) o.push(parse_LongRGB(blob, 8));
return o;
}
-/* [MS-XLS] 2.4.354 */
-function parse_XFCRC(blob) {
+/* 2.4.354 */
+function parse_XFCRC(blob, length) {
blob.l += 2;
var o = {cxfs:0, crc:0};
o.cxfs = blob.read_shift(2);
@@ -952,7 +719,7 @@ function parse_XFCRC(blob) {
return o;
}
-/* [MS-XLS] 2.4.53 TODO: parse flags */
+/* 2.4.53 TODO: parse flags */
/* [MS-XLSB] 2.4.323 TODO: parse flags */
function parse_ColInfo(blob, length, opts) {
if(!opts.cellStyles) return parsenoop(blob, length);
@@ -963,29 +730,12 @@ function parse_ColInfo(blob, length, opts) {
var ixfe = blob.read_shift(w);
var flags = blob.read_shift(2);
if(w == 2) blob.l += 2;
- var o = ({s:colFirst, e:colLast, w:coldx, ixfe:ixfe, flags:flags}/*:any*/);
- if(opts.biff >= 5 || !opts.biff) o.level = (flags >> 8) & 0x7;
- return o;
-}
-function write_ColInfo(col, idx) {
- var o = new_buf(12);
- o.write_shift(2, idx);
- o.write_shift(2, idx);
- o.write_shift(2, col.width * 256);
- o.write_shift(2, 0);
- var f = 0;
- if(col.hidden) f |= 1;
- o.write_shift(1, f);
- f = col.level || 0;
- o.write_shift(1, f);
- o.write_shift(2, 0);
- return o;
+ return {s:colFirst, e:colLast, w:coldx, ixfe:ixfe, flags:flags};
}
-/* [MS-XLS] 2.4.257 */
-function parse_Setup(blob, length) {
+/* 2.4.257 */
+function parse_Setup(blob, length, opts) {
var o = {};
- if(length < 32) return o;
blob.l += 16;
o.header = parse_Xnum(blob, 8);
o.footer = parse_Xnum(blob, 8);
@@ -993,7 +743,7 @@ function parse_Setup(blob, length) {
return o;
}
-/* [MS-XLS] 2.4.261 */
+/* 2.4.261 */
function parse_ShtProps(blob, length, opts) {
var def = {area:false};
if(opts.biff != 5) { blob.l += length; return def; }
@@ -1002,19 +752,319 @@ function parse_ShtProps(blob, length, opts) {
return def;
}
-/* [MS-XLS] 2.4.241 */
-function write_RRTabId(n/*:number*/) {
- var out = new_buf(2 * n);
- for(var i = 0; i < n; ++i) out.write_shift(2, i+1);
- return out;
-}
+var parse_Style = parsenoop;
+var parse_StyleExt = parsenoop;
-var parse_Blank = parse_XLSCell; /* [MS-XLS] 2.4.20 Just the cell */
-var parse_Scl = parseuint16a; /* [MS-XLS] 2.4.247 num, den */
-var parse_String = parse_XLUnicodeString; /* [MS-XLS] 2.4.268 */
+var parse_Window2 = parsenoop;
+
+var parse_Backup = parsebool; /* 2.4.14 */
+var parse_Blank = parse_XLSCell; /* 2.4.20 Just the cell */
+var parse_BottomMargin = parse_Xnum; /* 2.4.27 */
+var parse_BuiltInFnGroupCount = parseuint16; /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */
+var parse_CalcCount = parseuint16; /* 2.4.31 #Iterations */
+var parse_CalcDelta = parse_Xnum; /* 2.4.32 */
+var parse_CalcIter = parsebool; /* 2.4.33 1=iterative calc */
+var parse_CalcMode = parseuint16; /* 2.4.34 0=manual, 1=auto (def), 2=table */
+var parse_CalcPrecision = parsebool; /* 2.4.35 */
+var parse_CalcRefMode = parsenoop2; /* 2.4.36 */
+var parse_CalcSaveRecalc = parsebool; /* 2.4.37 */
+var parse_CodePage = parseuint16; /* 2.4.52 */
+var parse_Compat12 = parsebool; /* 2.4.54 true = no compatibility check */
+var parse_Date1904 = parsebool; /* 2.4.77 - 1=1904,0=1900 */
+var parse_DefColWidth = parseuint16; /* 2.4.89 */
+var parse_DSF = parsenoop2; /* 2.4.94 -- MUST be ignored */
+var parse_EntExU2 = parsenoop2; /* 2.4.102 -- Explicitly says to ignore */
+var parse_EOF = parsenoop2; /* 2.4.103 */
+var parse_Excel9File = parsenoop2; /* 2.4.104 -- Optional and unused */
+var parse_FeatHdr = parsenoop2; /* 2.4.112 */
+var parse_FontX = parseuint16; /* 2.4.123 */
+var parse_Footer = parse_XLHeaderFooter; /* 2.4.124 */
+var parse_GridSet = parseuint16; /* 2.4.132, =1 */
+var parse_HCenter = parsebool; /* 2.4.135 sheet centered horizontal on print */
+var parse_Header = parse_XLHeaderFooter; /* 2.4.136 */
+var parse_HideObj = parse_HideObjEnum; /* 2.4.139 */
+var parse_InterfaceEnd = parsenoop2; /* 2.4.145 -- noop */
+var parse_LeftMargin = parse_Xnum; /* 2.4.151 */
+var parse_Mms = parsenoop2; /* 2.4.169 -- Explicitly says to ignore */
+var parse_ObjProtect = parsebool; /* 2.4.183 -- must be 1 if present */
+var parse_Password = parseuint16; /* 2.4.191 */
+var parse_PrintGrid = parsebool; /* 2.4.202 */
+var parse_PrintRowCol = parsebool; /* 2.4.203 */
+var parse_PrintSize = parseuint16; /* 2.4.204 0:3 */
+var parse_Prot4Rev = parsebool; /* 2.4.205 */
+var parse_Prot4RevPass = parseuint16; /* 2.4.206 */
+var parse_Protect = parsebool; /* 2.4.207 */
+var parse_RefreshAll = parsebool; /* 2.4.217 -- must be 0 if not template */
+var parse_RightMargin = parse_Xnum; /* 2.4.219 */
+var parse_RRTabId = parseuint16a; /* 2.4.241 */
+var parse_ScenarioProtect = parsebool; /* 2.4.245 */
+var parse_Scl = parseuint16a; /* 2.4.247 num, den */
+var parse_String = parse_XLUnicodeString; /* 2.4.268 */
+var parse_SxBool = parsebool; /* 2.4.274 */
+var parse_TopMargin = parse_Xnum; /* 2.4.328 */
+var parse_UsesELFs = parsebool; /* 2.4.337 -- should be 0 */
+var parse_VCenter = parsebool; /* 2.4.342 */
+var parse_WinProtect = parsebool; /* 2.4.347 */
+var parse_WriteProtect = parsenoop; /* 2.4.350 empty record */
+
+
+/* ---- */
+var parse_VerticalPageBreaks = parsenoop;
+var parse_HorizontalPageBreaks = parsenoop;
+var parse_Selection = parsenoop;
+var parse_Continue = parsenoop;
+var parse_Pane = parsenoop;
+var parse_Pls = parsenoop;
+var parse_DCon = parsenoop;
+var parse_DConRef = parsenoop;
+var parse_DConName = parsenoop;
+var parse_XCT = parsenoop;
+var parse_CRN = parsenoop;
+var parse_FileSharing = parsenoop;
+var parse_Uncalced = parsenoop;
+var parse_Template = parsenoop;
+var parse_Intl = parsenoop;
+var parse_WsBool = parsenoop;
+var parse_Sort = parsenoop;
+var parse_Sync = parsenoop;
+var parse_LPr = parsenoop;
+var parse_DxGCol = parsenoop;
+var parse_FnGroupName = parsenoop;
+var parse_FilterMode = parsenoop;
+var parse_AutoFilterInfo = parsenoop;
+var parse_AutoFilter = parsenoop;
+var parse_ScenMan = parsenoop;
+var parse_SCENARIO = parsenoop;
+var parse_SxView = parsenoop;
+var parse_Sxvd = parsenoop;
+var parse_SXVI = parsenoop;
+var parse_SxIvd = parsenoop;
+var parse_SXLI = parsenoop;
+var parse_SXPI = parsenoop;
+var parse_DocRoute = parsenoop;
+var parse_RecipName = parsenoop;
+var parse_SXDI = parsenoop;
+var parse_SXDB = parsenoop;
+var parse_SXFDB = parsenoop;
+var parse_SXDBB = parsenoop;
+var parse_SXNum = parsenoop;
+var parse_SxErr = parsenoop;
+var parse_SXInt = parsenoop;
+var parse_SXString = parsenoop;
+var parse_SXDtr = parsenoop;
+var parse_SxNil = parsenoop;
+var parse_SXTbl = parsenoop;
+var parse_SXTBRGIITM = parsenoop;
+var parse_SxTbpg = parsenoop;
+var parse_ObProj = parsenoop;
+var parse_SXStreamID = parsenoop;
+var parse_DBCell = parsenoop;
+var parse_SXRng = parsenoop;
+var parse_SxIsxoper = parsenoop;
+var parse_BookBool = parsenoop;
+var parse_DbOrParamQry = parsenoop;
+var parse_OleObjectSize = parsenoop;
+var parse_SXVS = parsenoop;
+var parse_BkHim = parsenoop;
+var parse_MsoDrawingGroup = parsenoop;
+var parse_MsoDrawing = parsenoop;
+var parse_MsoDrawingSelection = parsenoop;
+var parse_PhoneticInfo = parsenoop;
+var parse_SxRule = parsenoop;
+var parse_SXEx = parsenoop;
+var parse_SxFilt = parsenoop;
+var parse_SxDXF = parsenoop;
+var parse_SxItm = parsenoop;
+var parse_SxName = parsenoop;
+var parse_SxSelect = parsenoop;
+var parse_SXPair = parsenoop;
+var parse_SxFmla = parsenoop;
+var parse_SxFormat = parsenoop;
+var parse_SXVDEx = parsenoop;
+var parse_SXFormula = parsenoop;
+var parse_SXDBEx = parsenoop;
+var parse_RRDInsDel = parsenoop;
+var parse_RRDHead = parsenoop;
+var parse_RRDChgCell = parsenoop;
+var parse_RRDRenSheet = parsenoop;
+var parse_RRSort = parsenoop;
+var parse_RRDMove = parsenoop;
+var parse_RRFormat = parsenoop;
+var parse_RRAutoFmt = parsenoop;
+var parse_RRInsertSh = parsenoop;
+var parse_RRDMoveBegin = parsenoop;
+var parse_RRDMoveEnd = parsenoop;
+var parse_RRDInsDelBegin = parsenoop;
+var parse_RRDInsDelEnd = parsenoop;
+var parse_RRDConflict = parsenoop;
+var parse_RRDDefName = parsenoop;
+var parse_RRDRstEtxp = parsenoop;
+var parse_LRng = parsenoop;
+var parse_CUsr = parsenoop;
+var parse_CbUsr = parsenoop;
+var parse_UsrInfo = parsenoop;
+var parse_UsrExcl = parsenoop;
+var parse_FileLock = parsenoop;
+var parse_RRDInfo = parsenoop;
+var parse_BCUsrs = parsenoop;
+var parse_UsrChk = parsenoop;
+var parse_UserBView = parsenoop;
+var parse_UserSViewBegin = parsenoop; // overloaded
+var parse_UserSViewEnd = parsenoop;
+var parse_RRDUserView = parsenoop;
+var parse_Qsi = parsenoop;
+var parse_CondFmt = parsenoop;
+var parse_CF = parsenoop;
+var parse_DVal = parsenoop;
+var parse_DConBin = parsenoop;
+var parse_Lel = parsenoop;
+var parse_XLSCodeName = parse_XLUnicodeString;
+var parse_SXFDBType = parsenoop;
+var parse_ObNoMacros = parsenoop;
+var parse_Dv = parsenoop;
+var parse_Index = parsenoop;
+var parse_Table = parsenoop;
+var parse_BigName = parsenoop;
+var parse_ContinueBigName = parsenoop;
+var parse_WebPub = parsenoop;
+var parse_QsiSXTag = parsenoop;
+var parse_DBQueryExt = parsenoop;
+var parse_ExtString = parsenoop;
+var parse_TxtQry = parsenoop;
+var parse_Qsir = parsenoop;
+var parse_Qsif = parsenoop;
+var parse_RRDTQSIF = parsenoop;
+var parse_OleDbConn = parsenoop;
+var parse_WOpt = parsenoop;
+var parse_SXViewEx = parsenoop;
+var parse_SXTH = parsenoop;
+var parse_SXPIEx = parsenoop;
+var parse_SXVDTEx = parsenoop;
+var parse_SXViewEx9 = parsenoop;
+var parse_ContinueFrt = parsenoop;
+var parse_RealTimeData = parsenoop;
+var parse_ChartFrtInfo = parsenoop;
+var parse_FrtWrapper = parsenoop;
+var parse_StartBlock = parsenoop;
+var parse_EndBlock = parsenoop;
+var parse_StartObject = parsenoop;
+var parse_EndObject = parsenoop;
+var parse_CatLab = parsenoop;
+var parse_YMult = parsenoop;
+var parse_SXViewLink = parsenoop;
+var parse_PivotChartBits = parsenoop;
+var parse_FrtFontList = parsenoop;
+var parse_SheetExt = parsenoop;
+var parse_BookExt = parsenoop;
+var parse_SXAddl = parsenoop;
+var parse_CrErr = parsenoop;
+var parse_HFPicture = parsenoop;
+var parse_Feat = parsenoop;
+var parse_DataLabExt = parsenoop;
+var parse_DataLabExtContents = parsenoop;
+var parse_CellWatch = parsenoop;
+var parse_FeatHdr11 = parsenoop;
+var parse_Feature11 = parsenoop;
+var parse_DropDownObjIds = parsenoop;
+var parse_ContinueFrt11 = parsenoop;
+var parse_DConn = parsenoop;
+var parse_List12 = parsenoop;
+var parse_Feature12 = parsenoop;
+var parse_CondFmt12 = parsenoop;
+var parse_CF12 = parsenoop;
+var parse_CFEx = parsenoop;
+var parse_AutoFilter12 = parsenoop;
+var parse_ContinueFrt12 = parsenoop;
+var parse_MDTInfo = parsenoop;
+var parse_MDXStr = parsenoop;
+var parse_MDXTuple = parsenoop;
+var parse_MDXSet = parsenoop;
+var parse_MDXProp = parsenoop;
+var parse_MDXKPI = parsenoop;
+var parse_MDB = parsenoop;
+var parse_PLV = parsenoop;
+var parse_DXF = parsenoop;
+var parse_TableStyles = parsenoop;
+var parse_TableStyle = parsenoop;
+var parse_TableStyleElement = parsenoop;
+var parse_NamePublish = parsenoop;
+var parse_SortData = parsenoop;
+var parse_GUIDTypeLib = parsenoop;
+var parse_FnGrp12 = parsenoop;
+var parse_NameFnGrp12 = parsenoop;
+var parse_HeaderFooter = parsenoop;
+var parse_CrtLayout12 = parsenoop;
+var parse_CrtMlFrt = parsenoop;
+var parse_CrtMlFrtContinue = parsenoop;
+var parse_ShapePropsStream = parsenoop;
+var parse_TextPropsStream = parsenoop;
+var parse_RichTextStream = parsenoop;
+var parse_CrtLayout12A = parsenoop;
+var parse_Units = parsenoop;
+var parse_Chart = parsenoop;
+var parse_Series = parsenoop;
+var parse_DataFormat = parsenoop;
+var parse_LineFormat = parsenoop;
+var parse_MarkerFormat = parsenoop;
+var parse_AreaFormat = parsenoop;
+var parse_PieFormat = parsenoop;
+var parse_AttachedLabel = parsenoop;
+var parse_SeriesText = parsenoop;
+var parse_ChartFormat = parsenoop;
+var parse_Legend = parsenoop;
+var parse_SeriesList = parsenoop;
+var parse_Bar = parsenoop;
+var parse_Line = parsenoop;
+var parse_Pie = parsenoop;
+var parse_Area = parsenoop;
+var parse_Scatter = parsenoop;
+var parse_CrtLine = parsenoop;
+var parse_Axis = parsenoop;
+var parse_Tick = parsenoop;
+var parse_ValueRange = parsenoop;
+var parse_CatSerRange = parsenoop;
+var parse_AxisLine = parsenoop;
+var parse_CrtLink = parsenoop;
+var parse_DefaultText = parsenoop;
+var parse_Text = parsenoop;
+var parse_ObjectLink = parsenoop;
+var parse_Frame = parsenoop;
+var parse_Begin = parsenoop;
+var parse_End = parsenoop;
+var parse_PlotArea = parsenoop;
+var parse_Chart3d = parsenoop;
+var parse_PicF = parsenoop;
+var parse_DropBar = parsenoop;
+var parse_Radar = parsenoop;
+var parse_Surf = parsenoop;
+var parse_RadarArea = parsenoop;
+var parse_AxisParent = parsenoop;
+var parse_LegendException = parsenoop;
+var parse_SerToCrt = parsenoop;
+var parse_AxesUsed = parsenoop;
+var parse_SBaseRef = parsenoop;
+var parse_SerParent = parsenoop;
+var parse_SerAuxTrend = parsenoop;
+var parse_IFmtRecord = parsenoop;
+var parse_Pos = parsenoop;
+var parse_AlRuns = parsenoop;
+var parse_BRAI = parsenoop;
+var parse_SerAuxErrBar = parsenoop;
+var parse_SerFmt = parsenoop;
+var parse_Chart3DBarShape = parsenoop;
+var parse_Fbi = parsenoop;
+var parse_BopPop = parsenoop;
+var parse_AxcExt = parsenoop;
+var parse_Dat = parsenoop;
+var parse_PlotGrowth = parsenoop;
+var parse_SIIndex = parsenoop;
+var parse_GelFrame = parsenoop;
+var parse_BopPopCustom = parsenoop;
+var parse_Fbi2 = parsenoop;
/* --- Specific to versions before BIFF8 --- */
-function parse_ImData(blob) {
+function parse_ImData(blob, length, opts) {
+ var tgt = blob.l + length;
var cf = blob.read_shift(2);
var env = blob.read_shift(2);
var lcb = blob.read_shift(4);
@@ -1023,6 +1073,11 @@ function parse_ImData(blob) {
return o;
}
+function parse_BIFF5String(blob) {
+ var len = blob.read_shift(1);
+ return blob.read_shift(len, 'sbcs-cont');
+}
+
/* BIFF2_??? where ??? is the name from [XLS] */
function parse_BIFF2STR(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
@@ -1033,7 +1088,7 @@ function parse_BIFF2STR(blob, length, opts) {
return cell;
}
-function parse_BIFF2NUM(blob/*::, length*/) {
+function parse_BIFF2NUM(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
var num = parse_Xnum(blob, 8);
@@ -1041,14 +1096,8 @@ function parse_BIFF2NUM(blob/*::, length*/) {
cell.val = num;
return cell;
}
-function write_BIFF2NUM(r/*:number*/, c/*:number*/, val/*:number*/) {
- var out = new_buf(15);
- write_BIFF2Cell(out, r, c);
- out.write_shift(8, val, 'f');
- return out;
-}
-function parse_BIFF2INT(blob) {
+function parse_BIFF2INT(blob, length) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
var num = blob.read_shift(2);
@@ -1056,14 +1105,8 @@ function parse_BIFF2INT(blob) {
cell.val = num;
return cell;
}
-function write_BIFF2INT(r/*:number*/, c/*:number*/, val/*:number*/) {
- var out = new_buf(9);
- write_BIFF2Cell(out, r, c);
- out.write_shift(2, val);
- return out;
-}
-function parse_BIFF2STRING(blob) {
+function parse_BIFF2STRING(blob, length) {
var cch = blob.read_shift(1);
if(cch === 0) { blob.l++; return ""; }
return blob.read_shift(cch, 'sbcs-cont');
diff --git a/bits/40_harb.js b/bits/40_harb.js
index 2ede866..31e121f 100644
--- a/bits/40_harb.js
+++ b/bits/40_harb.js
@@ -35,32 +35,15 @@ var dbf_codepage_map = {
/*::[*/0x4D/*::]*/: 936, /*::[*/0x4E/*::]*/: 949,
/*::[*/0x4F/*::]*/: 950, /*::[*/0x50/*::]*/: 874,
/*::[*/0x57/*::]*/: 1252, /*::[*/0x58/*::]*/: 1252,
- /*::[*/0x59/*::]*/: 1252, /*::[*/0x6C/*::]*/: 863,
- /*::[*/0x86/*::]*/: 737, /*::[*/0x87/*::]*/: 852,
- /*::[*/0x88/*::]*/: 857, /*::[*/0xCC/*::]*/: 1257,
+ /*::[*/0x59/*::]*/: 1252,
/*::[*/0xFF/*::]*/: 16969
};
-var dbf_reverse_map = evert({
- /*::[*/0x01/*::]*/: 437, /*::[*/0x02/*::]*/: 850,
- /*::[*/0x03/*::]*/: 1252, /*::[*/0x04/*::]*/: 10000,
- /*::[*/0x64/*::]*/: 852, /*::[*/0x65/*::]*/: 866,
- /*::[*/0x66/*::]*/: 865, /*::[*/0x67/*::]*/: 861,
- /*::[*/0x68/*::]*/: 895, /*::[*/0x69/*::]*/: 620,
- /*::[*/0x6A/*::]*/: 737, /*::[*/0x6B/*::]*/: 857,
- /*::[*/0x78/*::]*/: 950, /*::[*/0x79/*::]*/: 949,
- /*::[*/0x7A/*::]*/: 936, /*::[*/0x7B/*::]*/: 932,
- /*::[*/0x7C/*::]*/: 874, /*::[*/0x7D/*::]*/: 1255,
- /*::[*/0x7E/*::]*/: 1256, /*::[*/0x96/*::]*/: 10007,
- /*::[*/0x97/*::]*/: 10029, /*::[*/0x98/*::]*/: 10006,
- /*::[*/0xC8/*::]*/: 1250, /*::[*/0xC9/*::]*/: 1251,
- /*::[*/0xCA/*::]*/: 1254, /*::[*/0xCB/*::]*/: 1253,
- /*::[*/0x00/*::]*/: 20127
-});
-var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5];
+
/* TODO: find an actual specification */
function dbf_to_aoa(buf, opts)/*:AOA*/ {
var out/*:AOA*/ = [];
+ /* TODO: browser based */
var d/*:Block*/ = (new_raw_buf(1)/*:any*/);
switch(opts.type) {
case 'base64': d = s2a(Base64.decode(buf)); break;
@@ -69,105 +52,83 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
case 'array': d = buf; break;
}
prep_blob(d, 0);
-
/* header */
var ft = d.read_shift(1);
- var memo = !!(ft & 0x88);
- var vfp = false, l7 = false;
+ var memo = false;
+ var vfp = false;
switch(ft) {
- case 0x02: break; // dBASE II
- case 0x03: break; // dBASE III
- case 0x30: vfp = true; memo = true; break; // VFP
- case 0x31: vfp = true; memo = true; break; // VFP with autoincrement
- // 0x43 dBASE IV SQL table files
- // 0x63 dBASE IV SQL system files
- case 0x83: break; // dBASE III with memo
- case 0x8B: break; // dBASE IV with memo
- case 0x8C: l7 = true; break; // dBASE Level 7 with memo
- // case 0xCB dBASE IV SQL table files with memo
- case 0xF5: break; // FoxPro 2.x with memo
- // case 0xFB FoxBASE
+ case 0x02: case 0x03: break;
+ case 0x30: vfp = true; memo = true; break;
+ case 0x31: vfp = true; break;
+ case 0x83: memo = true; break;
+ case 0x8B: memo = true; break;
+ case 0xF5: memo = true; break;
default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
}
-
- var nrow = 0, fpos = 0x0209;
+ var filedate = new Date(), nrow = 0, fpos = 0;
if(ft == 0x02) nrow = d.read_shift(2);
- d.l += 3; // dBASE II stores DDMMYY date, others use YYMMDD
+ filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));
if(ft != 0x02) nrow = d.read_shift(4);
- if(nrow > 1048576) nrow = 1e6;
+ if(ft != 0x02) fpos = d.read_shift(2);
+ var rlen = d.read_shift(2);
- if(ft != 0x02) fpos = d.read_shift(2); // header length
- var rlen = d.read_shift(2); // record length
+ var flags = 0, current_cp = 1252;
+ if(ft != 0x02) {
+ d.l+=16;
+ flags = d.read_shift(1);
+ //if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
- var /*flags = 0,*/ current_cp = opts.codepage || 1252;
- if(ft != 0x02) { // 20 reserved bytes
- d.l+=16;
- /*flags = */d.read_shift(1);
- //if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
+ /* codepage present in FoxPro */
+ if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
+ d.l+=1;
- /* codepage present in FoxPro and dBASE Level 7 */
- if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
- d.l+=1;
-
- d.l+=2;
+ d.l+=2;
}
- if(l7) d.l += 36; // Level 7: 32 byte "Language driver name", 4 byte reserved
-
-/*:: type DBFField = { name:string; len:number; type:string; } */
- var fields/*:Array*/ = [], field/*:DBFField*/ = ({}/*:any*/);
- var hend = Math.min(d.length, (ft == 0x02 ? 0x209 : (fpos - 10 - (vfp ? 264 : 0))));
- var ww = l7 ? 32 : 11;
- while(d.l < hend && d[d.l] != 0x0d) {
- field = ({}/*:any*/);
- field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
- d.l += ww;
+ var fields = [], field = {};
+ var hend = fpos - 10 - (vfp ? 264 : 0);
+ while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) {
+ field = {};
+ field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+10)).replace(/[\u0000\r\n].*$/g,"");
+ d.l += 11;
field.type = String.fromCharCode(d.read_shift(1));
- if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
+ if(ft != 0x02) field.offset = d.read_shift(4);
field.len = d.read_shift(1);
if(ft == 0x02) field.offset = d.read_shift(2);
field.dec = d.read_shift(1);
if(field.name.length) fields.push(field);
- if(ft != 0x02) d.l += l7 ? 13 : 14;
+ if(ft != 0x02) d.l += 14;
switch(field.type) {
- case 'B': // Double (VFP) / Binary (dBASE L7)
- if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
- break;
- case 'G': // General (FoxPro and dBASE L7)
- case 'P': // Picture (FoxPro and dBASE L7)
- if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
- break;
- case '+': // Autoincrement (dBASE L7 only)
- case '0': // _NullFlags (VFP only)
- case '@': // Timestamp (dBASE L7 only)
- case 'C': // Character (dBASE II)
- case 'D': // Date (dBASE III)
- case 'F': // Float (dBASE IV)
- case 'I': // Long (VFP and dBASE L7)
- case 'L': // Logical (dBASE II)
- case 'M': // Memo (dBASE III)
- case 'N': // Number (dBASE II)
- case 'O': // Double (dBASE L7 only)
- case 'T': // Datetime (VFP only)
- case 'Y': // Currency (VFP only)
- break;
+ // case 'B': break; // Binary
+ case 'C': break; // character
+ case 'D': break; // date
+ case 'F': break; // floating point
+ // case 'G': break; // General
+ case 'I': break; // long
+ case 'L': break; // boolean
+ case 'M': break; // memo
+ case 'N': break; // number
+ // case 'O': break; // double
+ // case 'P': break; // Picture
+ case 'T': break; // datetime
+ case 'Y': break; // currency
+ case '0': break; // null ?
+ case '+': break; // autoincrement
+ case '@': break; // timestamp
default: throw new Error('Unknown Field Type: ' + field.type);
}
}
-
if(d[d.l] !== 0x0D) d.l = fpos-1;
- if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
- d.l = fpos;
-
+ else if(ft == 0x02) d.l = 0x209;
+ if(ft != 0x02) {
+ if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
+ d.l = fpos;
+ }
/* data */
var R = 0, C = 0;
out[0] = [];
for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name;
while(nrow-- > 0) {
- if(d[d.l] === 0x2A) {
- // TODO: record marked as deleted -- create a hidden row?
- d.l+=rlen;
- continue;
- }
+ if(d[d.l] === 0x2A) { d.l+=rlen; continue; }
++d.l;
out[++R] = []; C = 0;
for(C = 0; C != fields.length; ++C) {
@@ -176,39 +137,32 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
var s = cptable.utils.decode(current_cp, dd);
switch(fields[C].type) {
case 'C':
- // NOTE: it is conventional to write ' / / ' for empty dates
- if(s.trim().length) out[R][C] = s.replace(/\s+$/,"");
+ out[R][C] = cptable.utils.decode(current_cp, dd);
+ out[R][C] = out[R][C].trim();
break;
case 'D':
- if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
+ if(s.length === 8) out[R][C] = new Date(+s.substr(0,4), +s.substr(4,2)-1, +s.substr(6,2));
else out[R][C] = s;
break;
case 'F': out[R][C] = parseFloat(s.trim()); break;
- case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
- case 'L': switch(s.trim().toUpperCase()) {
+ case 'I': out[R][C] = dd.read_shift(4, 'i'); break;
+ case 'L': switch(s.toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
- case '': case '?': break;
+ case ' ': case '?': out[R][C] = false; break; /* NOTE: technically unitialized */
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
- out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
+ out[R][C] = "##MEMO##" + dd.read_shift(4);
break;
- case 'N':
- s = s.replace(/\u0000/g,"").trim();
- // NOTE: dBASE II interprets " . " as 0
- if(s && s != ".") out[R][C] = +s || 0; break;
- case '@':
- // NOTE: dBASE specs appear to be incorrect
- out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400);
- break;
- case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
- case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
- case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
- case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
- /* falls through */
- case 'G': case 'P': dd.l += fields[C].len; break;
+ case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break;
+ case 'T':
+ var day = dd.read_shift(4), ms = dd.read_shift(4);
+ throw new Error(day + " | " + ms);
+ //out[R][C] = new Date(); // TODO
+ //break;
+ case 'Y': out[R][C] = dd.read(4,'i')/1e4; break;
case '0':
if(fields[C].name === '_NullFlags') break;
/* falls through */
@@ -217,7 +171,6 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
}
}
if(ft != 0x02) if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16));
- if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows);
return out;
}
@@ -232,137 +185,13 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ {
catch(e) { if(opts && opts.WTF) throw e; }
return ({SheetNames:[],Sheets:{}});
}
-
-var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
-function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
- var o = opts || {};
- if(+o.codepage >= 0) set_cp(+o.codepage);
- if(o.type == "string") throw new Error("Cannot write DBF to JS string");
- var ba = buf_array();
- var aoa/*:AOA*/ = sheet_to_json(ws, {header:1, raw:true, cellDates:true});
- var headers = aoa[0], data = aoa.slice(1);
- var i = 0, j = 0, hcnt = 0, rlen = 1;
- for(i = 0; i < headers.length; ++i) {
- if(i == null) continue;
- ++hcnt;
- if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10);
- if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|");
- if(headers.indexOf(headers[i]) !== i) for(j=0; j<1024;++j)
- if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; }
- }
- var range = safe_decode_range(ws['!ref']);
- var coltypes/*:Array*/ = [];
- for(i = 0; i <= range.e.c - range.s.c; ++i) {
- var col/*:Array*/ = [];
- for(j=0; j < data.length; ++j) {
- if(data[j][i] != null) col.push(data[j][i]);
- }
- if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; }
- var guess = '', _guess = '';
- for(j = 0; j < col.length; ++j) {
- switch(typeof col[j]) {
- /* TODO: check if L2 compat is desired */
- case 'number': _guess = 'B'; break;
- case 'string': _guess = 'C'; break;
- case 'boolean': _guess = 'L'; break;
- case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
- default: _guess = 'C';
- }
- guess = guess && guess != _guess ? 'C' : _guess;
- if(guess == 'C') break;
- }
- rlen += _RLEN[guess] || 0;
- coltypes[i] = guess;
- }
-
- var h = ba.next(32);
- h.write_shift(4, 0x13021130);
- h.write_shift(4, data.length);
- h.write_shift(2, 296 + 32 * hcnt);
- h.write_shift(2, rlen);
- for(i=0; i < 4; ++i) h.write_shift(4, 0);
- h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[/*::String(*/current_ansi/*::)*/] || 0x03)<<8));
-
- for(i = 0, j = 0; i < headers.length; ++i) {
- if(headers[i] == null) continue;
- var hf = ba.next(32);
- var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
- hf.write_shift(1, _f, "sbcs");
- hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
- hf.write_shift(4, j);
- hf.write_shift(1, _RLEN[coltypes[i]] || 0);
- hf.write_shift(1, 0);
- hf.write_shift(1, 0x02);
- hf.write_shift(4, 0);
- hf.write_shift(1, 0);
- hf.write_shift(4, 0);
- hf.write_shift(4, 0);
- j += _RLEN[coltypes[i]] || 0;
- }
-
- var hb = ba.next(264);
- hb.write_shift(4, 0x0000000D);
- for(i=0; i < 65;++i) hb.write_shift(4, 0x00000000);
- for(i=0; i < data.length; ++i) {
- var rout = ba.next(rlen);
- rout.write_shift(1, 0);
- for(j=0; j":190, "?":191, "{":223
- }/*:any*/);
- var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
- var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
- var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
- sylk_escapes["|"] = 254;
/* TODO: find an actual specification */
function sylk_to_aoa(d/*:RawData*/, opts)/*:[AOA, Worksheet]*/ {
switch(opts.type) {
@@ -374,16 +203,15 @@ var SYLK = (function() {
throw new Error("Unrecognized type " + opts.type);
}
function sylk_to_aoa_str(str/*:string*/, opts)/*:[AOA, Worksheet]*/ {
- var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr/*:AOA*/ = [];
- var formats/*:Array*/ = [];
- var next_cell_format/*:string|null*/ = null;
- var sht = {}, rowinfo/*:Array*/ = [], colinfo/*:Array*/ = [], cw/*:Array*/ = [];
+ var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = [];
+ var formats = [];
+ var next_cell_format = null;
+ var sht = {}, rowinfo = [], colinfo = [], cw = [];
var Mval = 0, j;
- if(+opts.codepage >= 0) set_cp(+opts.codepage);
for (; ri !== records.length; ++ri) {
Mval = 0;
- var rstr=records[ri].trim().replace(/\x1B([\x20-\x2F])([\x30-\x3F])/g, decode_sylk_char).replace(sylk_char_regex, sylk_char_fn);
- var record=rstr.replace(/;;/g, "\u0000").split(";").map(function(x) { return x.replace(/\u0000/g, ";"); });
+ var rstr=records[ri].trim();
+ var record=rstr.replace(/;;/g, "\u0001").split(";").map(function(x) { return x.replace(/\u0001/g, ";"); });
var RT=record[0], val;
if(rstr.length > 0) switch(RT) {
case 'ID': break; /* header */
@@ -392,89 +220,66 @@ var SYLK = (function() {
case 'O': break; /* options? */
case 'P':
if(record[1].charAt(0) == 'P')
- formats.push(rstr.slice(3).replace(/;;/g, ";"));
+ formats.push(rstr.substr(3).replace(/;;/g, ";"));
break;
case 'C':
- var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1;
for(rj=1; rj -1 && arr[_R][_C];
- if(!shrbase || !shrbase[1]) throw new Error("SYLK shared formula cannot find base");
- arr[R][C][1] = shift_formula_str(shrbase[1], {r: R - _R, c: C - _C});
- }
- break;
+ } break;
case 'F':
var F_seen = 0;
for(rj=1; rj 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
- else if(Mval === 0) rowinfo[R].hidden = true;
+ else if(Mval == 0) rowinfo[R].hidden = true;
break;
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
@@ -484,21 +289,20 @@ var SYLK = (function() {
}
if(rowinfo.length > 0) sht['!rows'] = rowinfo;
if(colinfo.length > 0) sht['!cols'] = colinfo;
- if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
return [arr, sht];
}
- function sylk_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ {
- var aoasht = sylk_to_aoa(d, opts);
+ function sylk_to_sheet(str/*:string*/, opts)/*:Worksheet*/ {
+ var aoasht = sylk_to_aoa(str, opts);
var aoa = aoasht[0], ws = aoasht[1];
var o = aoa_to_sheet(aoa, opts);
keys(ws).forEach(function(k) { o[k] = ws[k]; });
return o;
}
- function sylk_to_workbook(d/*:RawData*/, opts)/*:Workbook*/ { return sheet_to_workbook(sylk_to_sheet(d, opts), opts); }
+ function sylk_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(sylk_to_sheet(str, opts), opts); }
- function write_ws_cell_sylk(cell/*:Cell*/, ws/*:Worksheet*/, R/*:number*/, C/*:number*//*::, opts*/)/*:string*/ {
+ function write_ws_cell_sylk(cell/*:Cell*/, ws/*:Worksheet*/, R/*:number*/, C/*:number*/, opts)/*:string*/ {
var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
switch(cell.t) {
case 'n':
@@ -537,7 +341,7 @@ var SYLK = (function() {
function sheet_to_sylk(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ {
var preamble/*:Array*/ = ["ID;PWXL;N;E"], o/*:Array*/ = [];
- var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
+ var r = decode_range(ws['!ref']), cell/*:Cell*/;
var dense = Array.isArray(ws);
var RS = "\r\n";
@@ -551,7 +355,7 @@ var SYLK = (function() {
for(var C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({r:R,c:C});
cell = dense ? (ws[R]||[])[C]: ws[coord];
- if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
+ if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
o.push(write_ws_cell_sylk(cell, ws, R, C, opts));
}
}
@@ -576,7 +380,7 @@ var DIF = (function() {
throw new Error("Unrecognized type " + opts.type);
}
function dif_to_aoa_str(str/*:string*/, opts)/*:AOA*/ {
- var records = str.split('\n'), R = -1, C = -1, ri = 0, arr/*:AOA*/ = [];
+ var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
for (; ri !== records.length; ++ri) {
if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; }
if (R < 0) continue;
@@ -592,18 +396,17 @@ var DIF = (function() {
case 0:
if(data === 'TRUE') arr[R][C] = true;
else if(data === 'FALSE') arr[R][C] = false;
- else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
+ else if(+value == +value) arr[R][C] = +value;
else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
else arr[R][C] = value;
++C; break;
case 1:
- data = data.slice(1,data.length-1);
+ data = data.substr(1,data.length-2);
arr[R][C++] = data !== '' ? data : null;
break;
}
if (data === 'EOD') break;
}
- if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
return arr;
}
@@ -620,9 +423,9 @@ var DIF = (function() {
o.push(type + "," + v);
o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
};
- return function sheet_to_dif(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
+ return function sheet_to_dif(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ {
var o/*:Array*/ = [];
- var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
+ var r = decode_range(ws['!ref']), cell/*:Cell*/;
var dense = Array.isArray(ws);
push_field(o, "TABLE", 0, 1, "sheetjs");
push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
@@ -673,119 +476,17 @@ var DIF = (function() {
};
})();
-var ETH = (function() {
- function decode(s/*:string*/)/*:string*/ { return s.replace(/\\b/g,"\\").replace(/\\c/g,":").replace(/\\n/g,"\n"); }
- function encode(s/*:string*/)/*:string*/ { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); }
-
- function eth_to_aoa(str/*:string*/, opts)/*:AOA*/ {
- var records = str.split('\n'), R = -1, C = -1, ri = 0, arr/*:AOA*/ = [];
- for (; ri !== records.length; ++ri) {
- var record = records[ri].trim().split(":");
- if(record[0] !== 'cell') continue;
- var addr = decode_cell(record[1]);
- if(arr.length <= addr.r) for(R = arr.length; R <= addr.r; ++R) if(!arr[R]) arr[R] = [];
- R = addr.r; C = addr.c;
- switch(record[2]) {
- case 't': arr[R][C] = decode(record[3]); break;
- case 'v': arr[R][C] = +record[3]; break;
- case 'vtf': var _f = record[record.length - 1];
- /* falls through */
- case 'vtc':
- switch(record[3]) {
- case 'nl': arr[R][C] = +record[4] ? true : false; break;
- default: arr[R][C] = +record[4]; break;
- }
- if(record[2] == 'vtf') arr[R][C] = [arr[R][C], _f];
- }
- }
- if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
- return arr;
- }
-
- function eth_to_sheet(d/*:string*/, opts)/*:Worksheet*/ { return aoa_to_sheet(eth_to_aoa(d, opts), opts); }
- function eth_to_workbook(d/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(eth_to_sheet(d, opts), opts); }
-
- var header = [
- "socialcalc:version:1.5",
- "MIME-Version: 1.0",
- "Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave"
- ].join("\n");
-
- var sep = [
- "--SocialCalcSpreadsheetControlSave",
- "Content-type: text/plain; charset=UTF-8"
- ].join("\n") + "\n";
-
- /* TODO: the other parts */
- var meta = [
- "# SocialCalc Spreadsheet Control Save",
- "part:sheet"
- ].join("\n");
-
- var end = "--SocialCalcSpreadsheetControlSave--";
-
- function sheet_to_eth_data(ws/*:Worksheet*/)/*:string*/ {
- if(!ws || !ws['!ref']) return "";
- var o/*:Array*/ = [], oo/*:Array*/ = [], cell, coord = "";
- var r = decode_range(ws['!ref']);
- var dense = Array.isArray(ws);
- for(var R = r.s.r; R <= r.e.r; ++R) {
- for(var C = r.s.c; C <= r.e.c; ++C) {
- coord = encode_cell({r:R,c:C});
- cell = dense ? (ws[R]||[])[C] : ws[coord];
- if(!cell || cell.v == null || cell.t === 'z') continue;
- oo = ["cell", coord, 't'];
- switch(cell.t) {
- case 's': case 'str': oo.push(encode(cell.v)); break;
- case 'n':
- if(!cell.f) { oo[2]='v'; oo[3]=cell.v; }
- else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); }
- break;
- case 'b':
- oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0";
- oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE'));
- break;
- case 'd':
- var t = datenum(parseDate(cell.v));
- oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t;
- oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t);
- break;
- case 'e': continue;
- }
- o.push(oo.join(":"));
- }
- }
- o.push("sheet:c:" + (r.e.c-r.s.c+1) + ":r:" + (r.e.r-r.s.r+1) + ":tvf:1");
- o.push("valueformat:1:text-wiki");
- //o.push("copiedfrom:" + ws['!ref']); // clipboard only
- return o.join("\n");
- }
-
- function sheet_to_eth(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
- return [header, sep, meta, sep, sheet_to_eth_data(ws), end].join("\n");
- // return ["version:1.5", sheet_to_eth_data(ws)].join("\n"); // clipboard form
- }
-
- return {
- to_workbook: eth_to_workbook,
- to_sheet: eth_to_sheet,
- from_sheet: sheet_to_eth
- };
-})();
-
var PRN = (function() {
- function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/, o/*:any*/) {
- if(o.raw) arr[R][C] = data;
- else if(data === ""){/* empty */}
- else if(data === 'TRUE') arr[R][C] = true;
+ function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/) {
+ if(data === 'TRUE') arr[R][C] = true;
else if(data === 'FALSE') arr[R][C] = false;
- else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data);
+ else if(data === ""){/* empty */}
+ else if(+data == +data) arr[R][C] = +data;
else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data);
else arr[R][C] = data;
}
function prn_to_aoa_str(f/*:string*/, opts)/*:AOA*/ {
- var o = opts || {};
var arr/*:AOA*/ = ([]/*:any*/);
if(!f || f.length === 0) return arr;
var lines = f.split(/[\r\n]/);
@@ -802,52 +503,13 @@ var PRN = (function() {
arr[R] = [];
/* TODO: confirm that widths are always 10 */
var C = 0;
- set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o);
+ set_text_arr(lines[R].slice(0, start).trim(), arr, R, C);
for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C)
- set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o);
+ set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C);
}
- if(o.sheetRows) arr = arr.slice(0, o.sheetRows);
return arr;
}
- // List of accepted CSV separators
- var guess_seps = {
- /*::[*/0x2C/*::]*/: ',',
- /*::[*/0x09/*::]*/: "\t",
- /*::[*/0x3B/*::]*/: ';'
- };
-
- // CSV separator weights to be used in case of equal numbers
- var guess_sep_weights = {
- /*::[*/0x2C/*::]*/: 3,
- /*::[*/0x09/*::]*/: 2,
- /*::[*/0x3B/*::]*/: 1
- };
-
- function guess_sep(str) {
- var cnt = {}, instr = false, end = 0, cc = 0;
- for(;end < str.length;++end) {
- if((cc=str.charCodeAt(end)) == 0x22) instr = !instr;
- else if(!instr && cc in guess_seps) cnt[cc] = (cnt[cc]||0)+1;
- }
-
- cc = [];
- for(end in cnt) if ( Object.prototype.hasOwnProperty.call(cnt, end) ) {
- cc.push([ cnt[end], end ]);
- }
-
- if ( !cc.length ) {
- cnt = guess_sep_weights;
- for(end in cnt) if ( Object.prototype.hasOwnProperty.call(cnt, end) ) {
- cc.push([ cnt[end], end ]);
- }
- }
-
- cc.sort(function(a, b) { return a[0] - b[0] || guess_sep_weights[a[1]] - guess_sep_weights[b[1]]; });
-
- return guess_seps[cc.pop()[1]];
- }
-
function dsv_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
var o = opts || {};
var sep = "";
@@ -855,18 +517,9 @@ var PRN = (function() {
var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/);
var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/);
- if(str.slice(0,4) == "sep=") {
- // If the line ends in \r\n
- if(str.charCodeAt(5) == 13 && str.charCodeAt(6) == 10 ) {
- sep = str.charAt(4); str = str.slice(7);
- }
- // If line ends in \r OR \n
- else if(str.charCodeAt(5) == 13 || str.charCodeAt(5) == 10 ) {
- sep = str.charAt(4); str = str.slice(6);
- }
- else sep = guess_sep(str.slice(0,1024));
- }
- else sep = guess_sep(str.slice(0,1024));
+ /* known sep */
+ if(str.substr(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.substr(6); }
+ else if(str.substr(0,1024).indexOf("\t") == -1) sep = ","; else sep = "\t";
var R = 0, C = 0, v = 0;
var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0;
str = str.replace(/\r\n/mg, "\n");
@@ -874,40 +527,32 @@ var PRN = (function() {
function finish_cell() {
var s = str.slice(start, end);
var cell = ({}/*:any*/);
- if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
- if(s.length === 0) cell.t = 'z';
- else if(o.raw) { cell.t = 's'; cell.v = s; }
- else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
- else if(s.charCodeAt(0) == 0x3D) {
- if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
- else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
- else { cell.t = 's'; cell.v = s; } }
+ if(s.charCodeAt(0) == 0x3D) { cell.t = 'n'; cell.f = s.substr(1); }
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
- else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
+ else if(!isNaN(v = +s)) { cell.t = 'n'; cell.w = s; cell.v = v; }
else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
cell.z = o.dateNF || SSF._table[14];
var k = 0;
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
- if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
- if(!o.cellNF) delete cell.z;
+ cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
} else {
cell.t = 's';
+ if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
cell.v = s;
}
- if(cell.t == 'z'){}
- else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
+ if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
else ws[encode_cell({c:C,r:R})] = cell;
start = end+1;
if(range.e.c < C) range.e.c = C;
if(range.e.r < R) range.e.r = R;
- if(cc == sepcc) ++C; else { C = 0; ++R; if(o.sheetRows && o.sheetRows <= R) return true; }
+ if(cc == sepcc) ++C; else { C = 0; ++R; }
}
- outer: for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
+ for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
case 0x22: instr = !instr; break;
- case sepcc: case 0x0a: case 0x0d: if(!instr && finish_cell()) break outer; break;
+ case sepcc: case 0x0a: case 0x0d: if(!instr) finish_cell(); break;
default: break;
}
if(end - start > 0) finish_cell();
@@ -917,47 +562,39 @@ var PRN = (function() {
}
function prn_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
- if(!(opts && opts.PRN)) return dsv_to_sheet_str(str, opts);
- if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
- if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
+ if(str.substr(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
+ if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0) return dsv_to_sheet_str(str, opts);
return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
}
function prn_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ {
- var str = "", bytes = opts.type == 'string' ? [0,0,0,0] : firstbyte(d, opts);
+ var str = "", bytes = firstbyte(d, opts);
switch(opts.type) {
case 'base64': str = Base64.decode(d); break;
case 'binary': str = d; break;
- case 'buffer':
- if(opts.codepage == 65001) str = d.toString('utf8');
- else if(opts.codepage && typeof cptable !== 'undefined') str = cptable.utils.decode(opts.codepage, d);
- else str = d.toString('binary');
- break;
+ case 'buffer': str = d.toString('binary'); break;
case 'array': str = cc2str(d); break;
- case 'string': str = d; break;
default: throw new Error("Unrecognized type " + opts.type);
}
- if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3));
- else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage) str = cptable.utils.decode(opts.codepage, cptable.utils.encode(28591,str));
- if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts);
+ if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
return prn_to_sheet_str(str, opts);
}
- function prn_to_workbook(d/*:RawData*/, opts)/*:Workbook*/ { return sheet_to_workbook(prn_to_sheet(d, opts), opts); }
+ function prn_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(prn_to_sheet(str, opts), opts); }
- function sheet_to_prn(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
+ function sheet_to_prn(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ {
var o/*:Array*/ = [];
- var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
+ var r = decode_range(ws['!ref']), cell/*:Cell*/;
var dense = Array.isArray(ws);
for(var R = r.s.r; R <= r.e.r; ++R) {
- var oo/*:Array*/ = [];
+ var oo = [];
for(var C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({r:R,c:C});
cell = dense ? (ws[R]||[])[C] : ws[coord];
if(!cell || cell.v == null) { oo.push(" "); continue; }
- var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
+ var w = (cell.w || (format_cell(cell), cell.w) || "").substr(0,10);
while(w.length < 10) w += " ";
- oo.push(w + (C === 0 ? " " : ""));
+ oo.push(w + (C == 0 ? " " : ""));
}
o.push(oo.join(""));
}
diff --git a/bits/41_lotus.js b/bits/41_lotus.js
index 7842146..6b3aa56 100644
--- a/bits/41_lotus.js
+++ b/bits/41_lotus.js
@@ -8,7 +8,7 @@ var WK_ = (function() {
var R = Enum[RT] || Enum[0xFF];
var length = data.read_shift(2);
var tgt = data.l + length;
- var d = (R.f||parsenoop)(data, length, opts);
+ var d = R.f(data, length, opts);
data.l = tgt;
if(cb(d, R.n, RT)) return;
}
@@ -24,7 +24,7 @@ var WK_ = (function() {
throw "Unsupported type " + opts.type;
}
- function lotus_to_workbook_buf(d, opts)/*:Workbook*/ {
+ function lotus_to_workbook_buf(d,opts)/*:Workbook*/ {
if(!d) return d;
var o = opts || {};
if(DENSE != null && o.dense == null) o.dense = DENSE;
@@ -32,7 +32,6 @@ var WK_ = (function() {
var sheets = {}, snames = [n];
var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
- var sheetRows = o.sheetRows || 0;
if(d[2] == 0x02) o.Enum = WK1Enum;
else if(d[2] == 0x1a) o.Enum = WK3Enum;
@@ -46,7 +45,7 @@ var WK_ = (function() {
break;
case 0x06: refguess = val; break; /* RANGE */
case 0x0F: /* LABEL */
- if(!o.qpro) val[1].v = val[1].v.slice(1);
+ if(!o.qpro) val[1].v = val[1].v.substr(1);
/* falls through */
case 0x0D: /* INTEGER */
case 0x0E: /* NUMBER */
@@ -64,7 +63,7 @@ var WK_ = (function() {
break;
} else switch(RT) {
case 0x16: /* LABEL16 */
- val[1].v = val[1].v.slice(1);
+ val[1].v = val[1].v.substr(1);
/* falls through */
case 0x17: /* NUMBER17 */
case 0x18: /* NUMBER18 */
@@ -80,11 +79,7 @@ var WK_ = (function() {
sidx = val[3]; n = "Sheet" + (sidx + 1);
snames.push(n);
}
- if(sheetRows > 0 && val[0].r >= sheetRows) break;
- if(o.dense) {
- if(!s[val[0].r]) s[val[0].r] = [];
- s[val[0].r][val[0].c] = val[1];
- } else s[encode_cell(val[0])] = val[1];
+ s[encode_cell(val[0])] = val[1];
if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
break;
@@ -97,7 +92,7 @@ var WK_ = (function() {
return { SheetNames: snames, Sheets:sheets };
}
- function parse_RANGE(blob) {
+ function parse_RANGE(blob, length) {
var o = {s:{c:0,r:0},e:{c:0,r:0}};
o.s.c = blob.read_shift(2);
o.s.r = blob.read_shift(2);
@@ -161,7 +156,7 @@ var WK_ = (function() {
return o;
}
- function parse_cell_3(blob/*::, length*/) {
+ function parse_cell_3(blob, length) {
var o = [{c:0,r:0}, {t:'n',v:0}, 0];
o[0].r = blob.read_shift(2); o[3] = blob[blob.l++]; o[0].c = blob[blob.l++];
return o;
@@ -200,7 +195,7 @@ var WK_ = (function() {
var e = blob.read_shift(2);
if(e == 0xFFFF) { o[1].v = 0; return o; }
var s = e & 0x8000; e = (e&0x7FFF) - 16446;
- o[1].v = (s*2 - 1) * ((e > 0 ? (v2 << e) : (v2 >>> -e)) + (e > -32 ? (v1 << (e + 32)) : (v1 >>> -(e + 32))));
+ o[1].v = ((e > 0 ? (v2 << e) : (v2 >>> -e)) + (e > -32 ? (v1 << (e + 32)) : (v1 >>> -(e + 32))));
return o;
}
@@ -232,95 +227,95 @@ var WK_ = (function() {
var WK1Enum = {
/*::[*/0x0000/*::]*/: { n:"BOF", f:parseuint16 },
- /*::[*/0x0001/*::]*/: { n:"EOF" },
- /*::[*/0x0002/*::]*/: { n:"CALCMODE" },
- /*::[*/0x0003/*::]*/: { n:"CALCORDER" },
- /*::[*/0x0004/*::]*/: { n:"SPLIT" },
- /*::[*/0x0005/*::]*/: { n:"SYNC" },
+ /*::[*/0x0001/*::]*/: { n:"EOF", f:parsenoop },
+ /*::[*/0x0002/*::]*/: { n:"CALCMODE", f:parsenoop },
+ /*::[*/0x0003/*::]*/: { n:"CALCORDER", f:parsenoop },
+ /*::[*/0x0004/*::]*/: { n:"SPLIT", f:parsenoop },
+ /*::[*/0x0005/*::]*/: { n:"SYNC", f:parsenoop },
/*::[*/0x0006/*::]*/: { n:"RANGE", f:parse_RANGE },
- /*::[*/0x0007/*::]*/: { n:"WINDOW1" },
- /*::[*/0x0008/*::]*/: { n:"COLW1" },
- /*::[*/0x0009/*::]*/: { n:"WINTWO" },
- /*::[*/0x000A/*::]*/: { n:"COLW2" },
- /*::[*/0x000B/*::]*/: { n:"NAME" },
- /*::[*/0x000C/*::]*/: { n:"BLANK" },
+ /*::[*/0x0007/*::]*/: { n:"WINDOW1", f:parsenoop },
+ /*::[*/0x0008/*::]*/: { n:"COLW1", f:parsenoop },
+ /*::[*/0x0009/*::]*/: { n:"WINTWO", f:parsenoop },
+ /*::[*/0x000A/*::]*/: { n:"COLW2", f:parsenoop },
+ /*::[*/0x000B/*::]*/: { n:"NAME", f:parsenoop },
+ /*::[*/0x000C/*::]*/: { n:"BLANK", f:parsenoop },
/*::[*/0x000D/*::]*/: { n:"INTEGER", f:parse_INTEGER },
/*::[*/0x000E/*::]*/: { n:"NUMBER", f:parse_NUMBER },
/*::[*/0x000F/*::]*/: { n:"LABEL", f:parse_LABEL },
/*::[*/0x0010/*::]*/: { n:"FORMULA", f:parse_FORMULA },
- /*::[*/0x0018/*::]*/: { n:"TABLE" },
- /*::[*/0x0019/*::]*/: { n:"ORANGE" },
- /*::[*/0x001A/*::]*/: { n:"PRANGE" },
- /*::[*/0x001B/*::]*/: { n:"SRANGE" },
- /*::[*/0x001C/*::]*/: { n:"FRANGE" },
- /*::[*/0x001D/*::]*/: { n:"KRANGE1" },
- /*::[*/0x0020/*::]*/: { n:"HRANGE" },
- /*::[*/0x0023/*::]*/: { n:"KRANGE2" },
- /*::[*/0x0024/*::]*/: { n:"PROTEC" },
- /*::[*/0x0025/*::]*/: { n:"FOOTER" },
- /*::[*/0x0026/*::]*/: { n:"HEADER" },
- /*::[*/0x0027/*::]*/: { n:"SETUP" },
- /*::[*/0x0028/*::]*/: { n:"MARGINS" },
- /*::[*/0x0029/*::]*/: { n:"LABELFMT" },
- /*::[*/0x002A/*::]*/: { n:"TITLES" },
- /*::[*/0x002B/*::]*/: { n:"SHEETJS" },
- /*::[*/0x002D/*::]*/: { n:"GRAPH" },
- /*::[*/0x002E/*::]*/: { n:"NGRAPH" },
- /*::[*/0x002F/*::]*/: { n:"CALCCOUNT" },
- /*::[*/0x0030/*::]*/: { n:"UNFORMATTED" },
- /*::[*/0x0031/*::]*/: { n:"CURSORW12" },
- /*::[*/0x0032/*::]*/: { n:"WINDOW" },
+ /*::[*/0x0018/*::]*/: { n:"TABLE", f:parsenoop },
+ /*::[*/0x0019/*::]*/: { n:"ORANGE", f:parsenoop },
+ /*::[*/0x001A/*::]*/: { n:"PRANGE", f:parsenoop },
+ /*::[*/0x001B/*::]*/: { n:"SRANGE", f:parsenoop },
+ /*::[*/0x001C/*::]*/: { n:"FRANGE", f:parsenoop },
+ /*::[*/0x001D/*::]*/: { n:"KRANGE1", f:parsenoop },
+ /*::[*/0x0020/*::]*/: { n:"HRANGE", f:parsenoop },
+ /*::[*/0x0023/*::]*/: { n:"KRANGE2", f:parsenoop },
+ /*::[*/0x0024/*::]*/: { n:"PROTEC", f:parsenoop },
+ /*::[*/0x0025/*::]*/: { n:"FOOTER", f:parsenoop },
+ /*::[*/0x0026/*::]*/: { n:"HEADER", f:parsenoop },
+ /*::[*/0x0027/*::]*/: { n:"SETUP", f:parsenoop },
+ /*::[*/0x0028/*::]*/: { n:"MARGINS", f:parsenoop },
+ /*::[*/0x0029/*::]*/: { n:"LABELFMT", f:parsenoop },
+ /*::[*/0x002A/*::]*/: { n:"TITLES", f:parsenoop },
+ /*::[*/0x002B/*::]*/: { n:"SHEETJS", f:parsenoop },
+ /*::[*/0x002D/*::]*/: { n:"GRAPH", f:parsenoop },
+ /*::[*/0x002E/*::]*/: { n:"NGRAPH", f:parsenoop },
+ /*::[*/0x002F/*::]*/: { n:"CALCCOUNT", f:parsenoop },
+ /*::[*/0x0030/*::]*/: { n:"UNFORMATTED", f:parsenoop },
+ /*::[*/0x0031/*::]*/: { n:"CURSORW12", f:parsenoop },
+ /*::[*/0x0032/*::]*/: { n:"WINDOW", f:parsenoop },
/*::[*/0x0033/*::]*/: { n:"STRING", f:parse_LABEL },
- /*::[*/0x0037/*::]*/: { n:"PASSWORD" },
- /*::[*/0x0038/*::]*/: { n:"LOCKED" },
- /*::[*/0x003C/*::]*/: { n:"QUERY" },
- /*::[*/0x003D/*::]*/: { n:"QUERYNAME" },
- /*::[*/0x003E/*::]*/: { n:"PRINT" },
- /*::[*/0x003F/*::]*/: { n:"PRINTNAME" },
- /*::[*/0x0040/*::]*/: { n:"GRAPH2" },
- /*::[*/0x0041/*::]*/: { n:"GRAPHNAME" },
- /*::[*/0x0042/*::]*/: { n:"ZOOM" },
- /*::[*/0x0043/*::]*/: { n:"SYMSPLIT" },
- /*::[*/0x0044/*::]*/: { n:"NSROWS" },
- /*::[*/0x0045/*::]*/: { n:"NSCOLS" },
- /*::[*/0x0046/*::]*/: { n:"RULER" },
- /*::[*/0x0047/*::]*/: { n:"NNAME" },
- /*::[*/0x0048/*::]*/: { n:"ACOMM" },
- /*::[*/0x0049/*::]*/: { n:"AMACRO" },
- /*::[*/0x004A/*::]*/: { n:"PARSE" },
+ /*::[*/0x0037/*::]*/: { n:"PASSWORD", f:parsenoop },
+ /*::[*/0x0038/*::]*/: { n:"LOCKED", f:parsenoop },
+ /*::[*/0x003C/*::]*/: { n:"QUERY", f:parsenoop },
+ /*::[*/0x003D/*::]*/: { n:"QUERYNAME", f:parsenoop },
+ /*::[*/0x003E/*::]*/: { n:"PRINT", f:parsenoop },
+ /*::[*/0x003F/*::]*/: { n:"PRINTNAME", f:parsenoop },
+ /*::[*/0x0040/*::]*/: { n:"GRAPH2", f:parsenoop },
+ /*::[*/0x0041/*::]*/: { n:"GRAPHNAME", f:parsenoop },
+ /*::[*/0x0042/*::]*/: { n:"ZOOM", f:parsenoop },
+ /*::[*/0x0043/*::]*/: { n:"SYMSPLIT", f:parsenoop },
+ /*::[*/0x0044/*::]*/: { n:"NSROWS", f:parsenoop },
+ /*::[*/0x0045/*::]*/: { n:"NSCOLS", f:parsenoop },
+ /*::[*/0x0046/*::]*/: { n:"RULER", f:parsenoop },
+ /*::[*/0x0047/*::]*/: { n:"NNAME", f:parsenoop },
+ /*::[*/0x0048/*::]*/: { n:"ACOMM", f:parsenoop },
+ /*::[*/0x0049/*::]*/: { n:"AMACRO", f:parsenoop },
+ /*::[*/0x004A/*::]*/: { n:"PARSE", f:parsenoop },
/*::[*/0x00FF/*::]*/: { n:"", f:parsenoop }
};
var WK3Enum = {
- /*::[*/0x0000/*::]*/: { n:"BOF" },
- /*::[*/0x0001/*::]*/: { n:"EOF" },
- /*::[*/0x0003/*::]*/: { n:"??" },
- /*::[*/0x0004/*::]*/: { n:"??" },
- /*::[*/0x0005/*::]*/: { n:"??" },
- /*::[*/0x0006/*::]*/: { n:"??" },
- /*::[*/0x0007/*::]*/: { n:"??" },
- /*::[*/0x0009/*::]*/: { n:"??" },
- /*::[*/0x000a/*::]*/: { n:"??" },
- /*::[*/0x000b/*::]*/: { n:"??" },
- /*::[*/0x000c/*::]*/: { n:"??" },
- /*::[*/0x000e/*::]*/: { n:"??" },
- /*::[*/0x000f/*::]*/: { n:"??" },
- /*::[*/0x0010/*::]*/: { n:"??" },
- /*::[*/0x0011/*::]*/: { n:"??" },
- /*::[*/0x0012/*::]*/: { n:"??" },
- /*::[*/0x0013/*::]*/: { n:"??" },
- /*::[*/0x0015/*::]*/: { n:"??" },
+ /*::[*/0x0000/*::]*/: { n:"BOF", f:parsenoop },
+ /*::[*/0x0001/*::]*/: { n:"EOF", f:parsenoop },
+ /*::[*/0x0003/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0004/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0005/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0006/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0007/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0009/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x000a/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x000b/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x000c/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x000e/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x000f/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0010/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0011/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0012/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0013/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0015/*::]*/: { n:"??", f:parsenoop },
/*::[*/0x0016/*::]*/: { n:"LABEL16", f:parse_LABEL_16},
/*::[*/0x0017/*::]*/: { n:"NUMBER17", f:parse_NUMBER_17 },
/*::[*/0x0018/*::]*/: { n:"NUMBER18", f:parse_NUMBER_18 },
/*::[*/0x0019/*::]*/: { n:"FORMULA19", f:parse_FORMULA_19},
- /*::[*/0x001a/*::]*/: { n:"??" },
- /*::[*/0x001b/*::]*/: { n:"??" },
- /*::[*/0x001c/*::]*/: { n:"??" },
- /*::[*/0x001d/*::]*/: { n:"??" },
- /*::[*/0x001e/*::]*/: { n:"??" },
- /*::[*/0x001f/*::]*/: { n:"??" },
- /*::[*/0x0021/*::]*/: { n:"??" },
+ /*::[*/0x001a/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x001b/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x001c/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x001d/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x001e/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x001f/*::]*/: { n:"??", f:parsenoop },
+ /*::[*/0x0021/*::]*/: { n:"??", f:parsenoop },
/*::[*/0x0025/*::]*/: { n:"NUMBER25", f:parse_NUMBER_25 },
/*::[*/0x0027/*::]*/: { n:"NUMBER27", f:parse_NUMBER_27 },
/*::[*/0x0028/*::]*/: { n:"FORMULA28", f:parse_FORMULA_28 },
diff --git a/bits/42_sstxml.js b/bits/42_sstxml.js
index 2ef5453..778356b 100644
--- a/bits/42_sstxml.js
+++ b/bits/42_sstxml.js
@@ -1,136 +1,132 @@
-/* 18.4.7 rPr CT_RPrElt */
-function parse_rpr(rpr) {
- var font = {}, m = rpr.match(tagregex), i = 0;
- var pass = false;
- if(m) for(;i!=m.length; ++i) {
- var y = parsexmltag(m[i]);
- switch(y[0].replace(/\w*:/g,"")) {
- /* 18.8.12 condense CT_BooleanProperty */
- /* ** not required . */
- case '':
- case '': font.shadow = 1; break;
- case '': break;
-
- /* 18.4.1 charset CT_IntProperty TODO */
- case '':
- case '': font.outline = 1; break;
- case '': break;
-
- /* 18.4.5 rFont CT_FontName */
- case '':
- case '': font.strike = 1; break;
- case '': break;
-
- /* 18.4.13 u CT_UnderlineProperty */
- case '':
- case '': font.u = 1; break;
- case '': break;
-
- /* 18.8.2 b */
- case '':
- case '': font.b = 1; break;
- case '': break;
-
- /* 18.8.26 i */
- case '':
- case '': font.i = 1; break;
- case '': break;
-
- /* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
- case '': case '': break;
- case '': pass = false; break;
- default:
- if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
- }
- }
- return font;
-}
-
-var parse_rs = (function() {
- var tregex = matchtag("t"), rpregex = matchtag("rPr");
- /* 18.4.4 r CT_RElt */
- function parse_r(r) {
- /* 18.4.12 t ST_Xstring */
- var t = r.match(tregex)/*, cp = 65001*/;
- if(!t) return {t:"s", v:""};
-
- var o/*:Cell*/ = ({t:'s', v:unescapexml(t[1])}/*:any*/);
- var rpr = r.match(rpregex);
- if(rpr) o.s = parse_rpr(rpr[1]);
- return o;
- }
- var rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/;
- return function parse_rs(rs) {
- return rs.replace(rregex,"").split(rend).map(parse_r).filter(function(r) { return r.v; });
- };
-})();
-
+/* 18.4.1 charset to codepage mapping */
+var CS2CP = ({
+ /*::[*/0/*::]*/: 1252, /* ANSI */
+ /*::[*/1/*::]*/: 65001, /* DEFAULT */
+ /*::[*/2/*::]*/: 65001, /* SYMBOL */
+ /*::[*/77/*::]*/: 10000, /* MAC */
+ /*::[*/128/*::]*/: 932, /* SHIFTJIS */
+ /*::[*/129/*::]*/: 949, /* HANGUL */
+ /*::[*/130/*::]*/: 1361, /* JOHAB */
+ /*::[*/134/*::]*/: 936, /* GB2312 */
+ /*::[*/136/*::]*/: 950, /* CHINESEBIG5 */
+ /*::[*/161/*::]*/: 1253, /* GREEK */
+ /*::[*/162/*::]*/: 1254, /* TURKISH */
+ /*::[*/163/*::]*/: 1258, /* VIETNAMESE */
+ /*::[*/177/*::]*/: 1255, /* HEBREW */
+ /*::[*/178/*::]*/: 1256, /* ARABIC */
+ /*::[*/186/*::]*/: 1257, /* BALTIC */
+ /*::[*/204/*::]*/: 1251, /* RUSSIAN */
+ /*::[*/222/*::]*/: 874, /* THAI */
+ /*::[*/238/*::]*/: 1250, /* EASTEUROPE */
+ /*::[*/255/*::]*/: 1252, /* OEM */
+ /*::[*/69/*::]*/: 6969 /* MISC */
+}/*:any*/);
/* Parse a list of tags */
-var rs_to_html = (function parse_rs_factory() {
- var nlregex = /(\r\n|\n)/g;
- function parse_rpr2(font, intro, outro) {
- var style/*:Array*/ = [];
+var parse_rs = (function parse_rs_factory() {
+ var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g;
+ /* 18.4.7 rPr CT_RPrElt */
+ var parse_rpr = function parse_rpr(rpr, intro, outro) {
+ var font = {}, cp = 65001, align = "";
+ var m = rpr.match(tagregex), i = 0;
+ if(m) for(;i!=m.length; ++i) {
+ var y = parsexmltag(m[i]);
+ switch(y[0].replace(/\w*:/g,"")) {
+ /* 18.8.12 condense CT_BooleanProperty */
+ /* ** not required . */
+ case '':
+ case '': font.shadow = 1; break;
+ case '': break;
+
+ /* 18.4.1 charset CT_IntProperty TODO */
+ case '':
+ case '': font.outline = 1; break;
+ case '': break;
+
+ /* 18.4.5 rFont CT_FontName */
+ case '':
+ case '': font.strike = 1; break;
+ case '': break;
+
+ /* 18.4.13 u CT_UnderlineProperty */
+ case '':
+ case '': font.u = 1; break;
+ case '': break;
+
+ /* 18.8.2 b */
+ case '':
+ case '': font.b = 1; break;
+ case '': break;
+
+ /* 18.8.26 i */
+ case '':
+ case '': font.i = 1; break;
+ case '': break;
+
+ /* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
+ case '');
@@ -139,50 +135,52 @@ var rs_to_html = (function parse_rs_factory() {
if(font.i) { intro.push(""); outro.push(""); }
if(font.strike) { intro.push(""); outro.push(""); }
- var align = font.valign || "";
- if(align == "superscript" || align == "super") align = "sup";
+ if(align == "superscript") align = "sup";
else if(align == "subscript") align = "sub";
if(align != "") { intro.push("<" + align + ">"); outro.push("" + align + ">"); }
outro.push("");
- return font;
- }
+ return cp;
+ };
/* 18.4.4 r CT_RElt */
- function r_to_html(r) {
- var terms/*:[Array, string, Array]*/ = [[],r.v,[]];
- if(!r.v) return "";
+ function parse_r(r) {
+ var terms = [[],"",[]];
+ /* 18.4.12 t ST_Xstring */
+ var t = r.match(tregex), cp = 65001;
+ if(!isval(t)/*:: || !t*/) return "";
+ terms[1] = t[1];
- if(r.s) parse_rpr2(r.s, terms[0], terms[2]);
+ var rpr = r.match(rpregex);
+ if(isval(rpr)/*:: && rpr*/) cp = parse_rpr(rpr[1], terms[0], terms[2]);
return terms[0].join("") + terms[1].replace(nlregex,'
') + terms[2].join("");
}
-
return function parse_rs(rs) {
- return rs.map(r_to_html).join("");
+ return rs.replace(rregex,"").split(rend).map(parse_r).join("");
};
})();
/* 18.4.8 si CT_Rst */
var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
-var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
+var sirphregex = /<(?:\w+:)?rPh.*?>(.*?)<\/(?:\w+:)?rPh>/g;
function parse_si(x, opts) {
var html = opts ? opts.cellHTML : true;
var z = {};
- if(!x) return { t: "" };
- //var y;
+ if(!x) return null;
+ var y;
/* 18.4.12 t ST_Xstring (Plaintext String) */
// TODO: is whitespace actually valid here?
if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
- z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
+ z.t = utf8read(unescapexml(x.substr(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]));
z.r = utf8read(x);
if(html) z.h = escapehtml(z.t);
}
/* 18.4.4 r CT_RElt (Rich Text Run) */
- else if((/*y = */x.match(sirregex))) {
+ else if((y = x.match(sirregex))) {
z.r = utf8read(x);
- z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
- if(html) z.h = rs_to_html(parse_rs(z.r));
+ z.t = utf8read(unescapexml((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
+ if(html) z.h = parse_rs(z.r);
}
/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
/* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
@@ -198,7 +196,7 @@ function parse_sst_xml(data/*:string*/, opts)/*:SST*/ {
if(!data) return s;
/* 18.4.9 sst CT_Sst */
var sst = data.match(sstr0);
- if(sst) {
+ if(isval(sst)/*:: && sst*/) {
ss = sst[2].replace(sstr1,"").split(sstr2);
for(var i = 0; i != ss.length; ++i) {
var o = parse_si(ss[i].trim(), opts);
diff --git a/bits/43_sstbin.js b/bits/43_sstbin.js
index ce0d463..7904ad4 100644
--- a/bits/43_sstbin.js
+++ b/bits/43_sstbin.js
@@ -1,5 +1,5 @@
-/* [MS-XLSB] 2.4.221 BrtBeginSst */
-function parse_BrtBeginSst(data) {
+/* [MS-XLSB] 2.4.219 BrtBeginSst */
+function parse_BrtBeginSst(data, length) {
return [data.read_shift(4), data.read_shift(4)];
}
@@ -39,7 +39,7 @@ function write_BrtBeginSst(sst, o) {
var write_BrtSSTItem = write_RichStr;
-function write_sst_bin(sst/*::, opts*/) {
+function write_sst_bin(sst, opts) {
var ba = buf_array();
write_record(ba, "BrtBeginSst", write_BrtBeginSst(sst));
for(var i = 0; i < sst.length; ++i) write_record(ba, "BrtSSTItem", write_BrtSSTItem(sst[i]));
diff --git a/bits/44_offcrypto.js b/bits/44_offcrypto.js
index c471042..4823fa5 100644
--- a/bits/44_offcrypto.js
+++ b/bits/44_offcrypto.js
@@ -1,6 +1,6 @@
function _JS2ANSI(str/*:string*/)/*:Array*/ {
- if(typeof cptable !== 'undefined') return cptable.utils.encode(current_ansi, str);
- var o/*:Array*/ = [], oo = str.split("");
+ if(typeof cptable !== 'undefined') return cptable.utils.encode(1252, str);
+ var o = [], oo = str.split("");
for(var i = 0; i < oo.length; ++i) o[i] = oo[i].charCodeAt(0);
return o;
}
@@ -16,7 +16,7 @@ function parse_CRYPTOVersion(blob, length/*:?number*/) {
}
/* [MS-OFFCRYPTO] 2.1.5 DataSpaceVersionInfo */
-function parse_DataSpaceVersionInfo(blob) {
+function parse_DataSpaceVersionInfo(blob, length) {
var o = {};
o.id = blob.read_shift(0, 'lpp4');
o.R = parse_CRYPTOVersion(blob, 4);
@@ -31,17 +31,21 @@ function parse_DataSpaceMapEntry(blob) {
var end = blob.l + len - 4;
var o = {};
var cnt = blob.read_shift(4);
- var comps/*:Array<{t:number, v:string}>*/ = [];
- /* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */
- while(cnt-- > 0) comps.push({ t: blob.read_shift(4), v: blob.read_shift(0, 'lpp4') });
+ var comps = [];
+ while(cnt-- > 0) {
+ /* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */
+ var rc = {};
+ rc.t = blob.read_shift(4);
+ rc.v = blob.read_shift(0, 'lpp4');
+ comps.push(rc);
+ }
o.name = blob.read_shift(0, 'lpp4');
o.comps = comps;
- if(blob.l != end) throw new Error("Bad DataSpaceMapEntry: " + blob.l + " != " + end);
return o;
}
/* [MS-OFFCRYPTO] 2.1.6 DataSpaceMap */
-function parse_DataSpaceMap(blob) {
+function parse_DataSpaceMap(blob, length) {
var o = [];
blob.l += 4; // must be 0x8
var cnt = blob.read_shift(4);
@@ -50,8 +54,8 @@ function parse_DataSpaceMap(blob) {
}
/* [MS-OFFCRYPTO] 2.1.7 DataSpaceDefinition */
-function parse_DataSpaceDefinition(blob)/*:Array*/ {
- var o/*:Array*/ = [];
+function parse_DataSpaceDefinition(blob, length) {
+ var o = [];
blob.l += 4; // must be 0x8
var cnt = blob.read_shift(4);
while(cnt-- > 0) o.push(blob.read_shift(0, 'lpp4'));
@@ -59,11 +63,13 @@ function parse_DataSpaceDefinition(blob)/*:Array*/ {
}
/* [MS-OFFCRYPTO] 2.1.8 DataSpaceDefinition */
-function parse_TransformInfoHeader(blob) {
+function parse_TransformInfoHeader(blob, length) {
var o = {};
- /*var len = */blob.read_shift(4);
+ var len = blob.read_shift(4);
+ var tgt = blob.l + len - 4;
blob.l += 4; // must be 0x1
o.id = blob.read_shift(0, 'lpp4');
+ // tgt == len
o.name = blob.read_shift(0, 'lpp4');
o.R = parse_CRYPTOVersion(blob, 4);
o.U = parse_CRYPTOVersion(blob, 4);
@@ -71,7 +77,7 @@ function parse_TransformInfoHeader(blob) {
return o;
}
-function parse_Primary(blob) {
+function parse_Primary(blob, length) {
/* [MS-OFFCRYPTO] 2.2.6 IRMDSTransformInfo */
var hdr = parse_TransformInfoHeader(blob);
/* [MS-OFFCRYPTO] 2.1.9 EncryptionTransformInfo */
@@ -101,76 +107,57 @@ function parse_EncryptionHeader(blob, length/*:number*/) {
o.KeySize = blob.read_shift(4);
o.ProviderType = blob.read_shift(4);
blob.l += 8;
- o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
+ o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le').slice(0,-1);
blob.l = tgt;
return o;
}
/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
function parse_EncryptionVerifier(blob, length/*:number*/) {
- var o = {}, tgt = blob.l + length;
+ var o = {};
blob.l += 4; // SaltSize must be 0x10
o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
- /*var sz = */blob.read_shift(4);
- o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
+ var sz = blob.read_shift(4);
+ o.VerifierHash = blob.slice(blob.l, blob.l + sz); blob.l += sz;
return o;
}
/* [MS-OFFCRYPTO] 2.3.4.* EncryptionInfo Stream */
-function parse_EncryptionInfo(blob) {
+function parse_EncryptionInfo(blob, length) {
var vers = parse_CRYPTOVersion(blob);
switch(vers.Minor) {
- case 0x02: return [vers.Minor, parse_EncInfoStd(blob, vers)];
- case 0x03: return [vers.Minor, parse_EncInfoExt(blob, vers)];
- case 0x04: return [vers.Minor, parse_EncInfoAgl(blob, vers)];
+ case 0x02: return parse_EncInfoStd(blob, vers);
+ case 0x03: return parse_EncInfoExt(blob, vers);
+ case 0x04: return parse_EncInfoAgl(blob, vers);
}
- throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
+ throw new Error("ECMA-376 Encryped file unrecognized Version: " + vers.Minor);
}
/* [MS-OFFCRYPTO] 2.3.4.5 EncryptionInfo Stream (Standard Encryption) */
-function parse_EncInfoStd(blob/*::, vers*/) {
+function parse_EncInfoStd(blob, vers) {
var flags = blob.read_shift(4);
if((flags & 0x3F) != 0x24) throw new Error("EncryptionInfo mismatch");
var sz = blob.read_shift(4);
- //var tgt = blob.l + sz;
+ var tgt = blob.l + sz;
var hdr = parse_EncryptionHeader(blob, sz);
var verifier = parse_EncryptionVerifier(blob, blob.length - blob.l);
return { t:"Std", h:hdr, v:verifier };
}
/* [MS-OFFCRYPTO] 2.3.4.6 EncryptionInfo Stream (Extensible Encryption) */
-function parse_EncInfoExt(/*::blob, vers*/) { throw new Error("File is password-protected: ECMA-376 Extensible"); }
+function parse_EncInfoExt(blob, vers) { throw new Error("File is password-protected: ECMA-376 Extensible"); }
/* [MS-OFFCRYPTO] 2.3.4.10 EncryptionInfo Stream (Agile Encryption) */
-function parse_EncInfoAgl(blob/*::, vers*/) {
- var KeyData = ["saltSize","blockSize","keyBits","hashSize","cipherAlgorithm","cipherChaining","hashAlgorithm","saltValue"];
- blob.l+=4;
- var xml = blob.read_shift(blob.length - blob.l, 'utf8');
- var o = {};
- xml.replace(tagregex, function xml_agile(x) {
- var y/*:any*/ = parsexmltag(x);
- switch(strip_ns(y[0])) {
- case '': break;
- case '': case '': break;
+function parse_EncInfoAgl(blob, vers) { throw new Error("File is password-protected: ECMA-376 Agile"); }
+
+
- case '': break;
- case ' 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major);
+ if(vers.Minor != 2) throw 'unrecognized minor version code: ' + vers.Minor;
+ if(vers.Major > 4 || vers.Major < 2) throw 'unrecognized major version code: ' + vers.Major;
o.Flags = blob.read_shift(4); length -= 4;
var sz = blob.read_shift(4); length -= 4;
o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz;
@@ -178,9 +165,9 @@ function parse_RC4CryptoHeader(blob, length/*:number*/) {
return o;
}
/* [MS-OFFCRYPTO] 2.3.6.1 RC4 Encryption Header */
-function parse_RC4Header(blob/*::, length*/) {
+function parse_RC4Header(blob, length/*:number*/) {
var o = {};
- var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4);
+ var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4;
if(vers.Major != 1 || vers.Minor != 1) throw 'unrecognized version code ' + vers.Major + ' : ' + vers.Minor;
o.Salt = blob.read_shift(16);
o.EncryptedVerifier = blob.read_shift(16);
@@ -295,7 +282,7 @@ function parse_XORObfuscation(blob, length, opts, out) {
var o = ({ key: parseuint16(blob), verificationBytes: parseuint16(blob) }/*:any*/);
if(opts.password) o.verifier = crypto_CreatePasswordVerifier_Method1(opts.password);
out.valid = o.verificationBytes === o.verifier;
- if(out.valid) out.insitu = crypto_MakeXorDecryptor(opts.password);
+ if(out.valid) out.insitu_decrypt = crypto_MakeXorDecryptor(opts.password);
return o;
}
@@ -307,9 +294,9 @@ function parse_FilePassHeader(blob, length/*:number*/, oo) {
return o;
}
function parse_FilePass(blob, length/*:number*/, opts) {
- var o = ({ Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }/*:any*/); /* wEncryptionType */
+ var o = { Type: blob.read_shift(2) }; /* wEncryptionType */
if(o.Type) parse_FilePassHeader(blob, length-2, o);
- else parse_XORObfuscation(blob, opts.biff >= 8 ? length : length - 2, opts, o);
+ else parse_XORObfuscation(blob, length-2, opts, o);
return o;
}
diff --git a/bits/45_rtf.js b/bits/45_rtf.js
deleted file mode 100644
index 74d70ba..0000000
--- a/bits/45_rtf.js
+++ /dev/null
@@ -1,52 +0,0 @@
-var RTF = (function() {
- function rtf_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ {
- switch(opts.type) {
- case 'base64': return rtf_to_sheet_str(Base64.decode(d), opts);
- case 'binary': return rtf_to_sheet_str(d, opts);
- case 'buffer': return rtf_to_sheet_str(d.toString('binary'), opts);
- case 'array': return rtf_to_sheet_str(cc2str(d), opts);
- }
- throw new Error("Unrecognized type " + opts.type);
- }
-
- function rtf_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
- var o = opts || {};
- var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/);
- var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/);
-
- // TODO: parse
- if(!str.match(/\\trowd/)) throw new Error("RTF missing table");
-
- ws['!ref'] = encode_range(range);
- return ws;
- }
-
- function rtf_to_workbook(d/*:RawData*/, opts)/*:Workbook*/ { return sheet_to_workbook(rtf_to_sheet(d, opts), opts); }
-
- /* TODO: this is a stub */
- function sheet_to_rtf(ws/*:Worksheet*//*::, opts*/)/*:string*/ {
- var o = ["{\\rtf1\\ansi"];
- var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
- var dense = Array.isArray(ws);
- for(var R = r.s.r; R <= r.e.r; ++R) {
- o.push("\\trowd\\trautofit1");
- for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
- o.push("\\pard\\intbl");
- for(C = r.s.c; C <= r.e.c; ++C) {
- var coord = encode_cell({r:R,c:C});
- cell = dense ? (ws[R]||[])[C]: ws[coord];
- if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
- o.push(" " + (cell.w || (format_cell(cell), cell.w)));
- o.push("\\cell");
- }
- o.push("\\pard\\intbl\\row");
- }
- return o.join("") + "}";
- }
-
- return {
- to_workbook: rtf_to_workbook,
- to_sheet: rtf_to_sheet,
- from_sheet: sheet_to_rtf
- };
-})();
diff --git a/bits/46_stycommon.js b/bits/45_styutils.js
similarity index 91%
rename from bits/46_stycommon.js
rename to bits/45_styutils.js
index 7da2307..7d86890 100644
--- a/bits/46_stycommon.js
+++ b/bits/45_styutils.js
@@ -1,10 +1,10 @@
function hex2RGB(h) {
- var o = h.slice(h[0]==="#"?1:0).slice(0,6);
- return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
+ var o = h.substr(h[0]==="#"?1:0,6);
+ return [parseInt(o.substr(0,2),16),parseInt(o.substr(2,2),16),parseInt(o.substr(4,2),16)];
}
function rgb2Hex(rgb) {
for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
- return o.toString(16).toUpperCase().slice(1);
+ return o.toString(16).toUpperCase().substr(1);
}
function rgb2HSL(rgb) {
@@ -55,8 +55,8 @@ var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
-//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
-//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
+function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
+function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
/* XLSX/XLSB/XLS specify width in units of MDW */
function find_mdw_colw(collw) {
@@ -65,7 +65,7 @@ function find_mdw_colw(collw) {
MDW = _MDW;
}
/* XLML specifies width in terms of pixels */
-/*function find_mdw_wpx(wpx) {
+function find_mdw_wpx(wpx) {
var delta = Infinity, guess = 0, _MDW = MIN_MDW;
for(MDW=MIN_MDW; MDW': case '': break;
/* 18.8.4 border CT_Border */
- case '': case '':
- border = /*::(*/{}/*:: :any)*/;
- if(y.diagonalUp) border.diagonalUp = parsexmlbool(y.diagonalUp);
- if(y.diagonalDown) border.diagonalDown = parsexmlbool(y.diagonalDown);
+ case '':
+ border = {};
+ if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; }
+ if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; }
styles.Borders.push(border);
break;
case '': break;
/* note: not in spec, appears to be CT_BorderPr */
- case '': break;
- case '': break;
+ case '': break;
case '': break;
/* note: not in spec, appears to be CT_BorderPr */
- case '': break;
- case '': break;
+ case '': break;
case '': break;
/* 18.8.43 top CT_BorderPr */
- case '': break;
- case '': break;
+ case '': break;
case '': break;
/* 18.8.6 bottom CT_BorderPr */
- case '': break;
- case '': break;
+ case '': break;
case '': break;
/* 18.8.13 diagonal CT_BorderPr */
- case '': case '': break;
+ case '': break;
case '': break;
/* 18.8.25 horizontal CT_BorderPr */
- case '': case '': break;
+ case '': break;
case '': break;
/* 18.8.44 vertical CT_BorderPr */
- case '': case '': break;
+ case '': break;
case '': break;
/* 18.8.37 start CT_BorderPr */
- case '': case '': break;
+ case '': break;
case '': break;
/* 18.8.16 end CT_BorderPr */
- case '': case '': break;
+ case '': break;
case '': break;
/* 18.8.? color CT_Color */
- case '':
- break;
- case '': case '': break;
+ case '': break;
+ case '': break;
- /* 18.2.10 extLst CT_ExtensionList ? */
- case '': case '': break;
- case '': pass = false; break;
- default: if(opts && opts.WTF) {
- if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
- }
+ default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in borders');
}
});
}
@@ -77,20 +65,17 @@ function parse_borders(t, styles, themes, opts) {
function parse_fills(t, styles, themes, opts) {
styles.Fills = [];
var fill = {};
- var pass = false;
- (t[0].match(tagregex)||[]).forEach(function(x) {
+ t[0].match(tagregex).forEach(function(x) {
var y = parsexmltag(x);
- switch(strip_ns(y[0])) {
+ switch(y[0]) {
case '': case '': break;
/* 18.8.20 fill CT_Fill */
- case '': case '':
- fill = {}; styles.Fills.push(fill); break;
- case '': break;
+ case '': break;
+ case '': styles.Fills.push(fill); fill = {}; break;
/* 18.8.24 gradientFill CT_GradientFill */
case '': break;
- case '': styles.Fills.push(fill); fill = {}; break;
/* 18.8.32 patternFill CT_PatternFill */
@@ -116,7 +101,7 @@ function parse_fills(t, styles, themes, opts) {
if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
/* Excel uses ARGB strings */
- if(y.rgb != null) fill.fgColor.rgb = y.rgb.slice(-6);
+ if(y.rgb) fill.fgColor.rgb = y.rgb.slice(-6);
break;
case '': case '': break;
@@ -128,13 +113,7 @@ function parse_fills(t, styles, themes, opts) {
case '': break;
case '': break;
- /* 18.2.10 extLst CT_ExtensionList ? */
- case '': case '': break;
- case '': pass = false; break;
- default: if(opts && opts.WTF) {
- if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
- }
+ default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in fills');
}
});
}
@@ -143,10 +122,9 @@ function parse_fills(t, styles, themes, opts) {
function parse_fonts(t, styles, themes, opts) {
styles.Fonts = [];
var font = {};
- var pass = false;
- (t[0].match(tagregex)||[]).forEach(function(x) {
+ t[0].match(tagregex).forEach(function(x) {
var y = parsexmltag(x);
- switch(strip_ns(y[0])) {
+ switch (y[0]) {
case '': case '': break;
/* 18.8.22 font CT_Font */
@@ -157,7 +135,7 @@ function parse_fonts(t, styles, themes, opts) {
break;
/* 18.8.29 name CT_FontName */
- case '': case '': break;
/* 18.8.2 b CT_BooleanProperty */
@@ -226,7 +204,7 @@ function parse_fonts(t, styles, themes, opts) {
if(!font.color) font.color = {};
if(y.auto) font.color.auto = parsexmlbool(y.auto);
- if(y.rgb) font.color.rgb = y.rgb.slice(-6);
+ if(y.rgb) font.color.rgb = y.rgb;
else if(y.indexed) {
font.color.index = parseInt(y.indexed, 10);
var icv = XLSIcv[font.color.index];
@@ -244,17 +222,7 @@ function parse_fonts(t, styles, themes, opts) {
break;
case '': case '': break;
- /* note: sometimes mc:AlternateContent appears bare */
- case '': pass = false; break;
-
- /* 18.2.10 extLst CT_ExtensionList ? */
- case '': case '': break;
- case '': pass = false; break;
- default: if(opts && opts.WTF) {
- if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
- }
+ default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in fonts');
}
});
}
@@ -268,18 +236,11 @@ function parse_numFmts(t, styles, opts) {
if(!m) return;
for(i=0; i < m.length; ++i) {
var y = parsexmltag(m[i]);
- switch(strip_ns(y[0])) {
+ switch(y[0]) {
case '': case '': case '': break;
case '0) {
- if(j > 0x188) {
- for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
- styles.NumberFmt[j] = f;
- }
- SSF.load(f,j);
- }
+ styles.NumberFmt[j] = f; if(j>0) SSF.load(f,j);
} break;
case '': break;
default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
@@ -287,7 +248,7 @@ function parse_numFmts(t, styles, opts) {
}
}
-function write_numFmts(NF/*:{[n:number|string]:string}*//*::, opts*/) {
+function write_numFmts(NF/*:{[n:number]:string}*/, opts) {
var o = [""];
[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])}));
@@ -304,23 +265,19 @@ var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "
function parse_cellXfs(t, styles, opts) {
styles.CellXf = [];
var xf;
- var pass = false;
- (t[0].match(tagregex)||[]).forEach(function(x) {
+ t[0].match(tagregex).forEach(function(x) {
var y = parsexmltag(x), i = 0;
- switch(strip_ns(y[0])) {
+ switch(y[0]) {
case '': case '': case '': break;
/* 18.8.45 xf CT_Xf */
- case '':
+ case ' 0x188) {
- for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
- }
+ xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]], "");
styles.CellXf.push(xf); break;
case '': break;
@@ -331,37 +288,26 @@ function parse_cellXfs(t, styles, opts) {
if(y.horizontal) alignment.horizontal = y.horizontal;
if(y.textRotation != null) alignment.textRotation = y.textRotation;
if(y.indent) alignment.indent = y.indent;
- if(y.wrapText) alignment.wrapText = parsexmlbool(y.wrapText);
+ if(y.wrapText) alignment.wrapText = y.wrapText;
xf.alignment = alignment;
break;
case '': break;
/* 18.8.33 protection CT_CellProtection */
- case '': case '': break;
-
- /* note: sometimes mc:AlternateContent appears bare */
- case '': pass = false; break;
+ case '': case '': break;
/* 18.2.10 extLst CT_ExtensionList ? */
- case '': case '': break;
- case '': pass = false; break;
- default: if(opts && opts.WTF) {
- if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
- }
+ case '': break;
+ case '*/ = [];
+ var o = [];
o[o.length] = (writextag('cellXfs',null));
- cellXfs.forEach(function(c) {
- o[o.length] = (writextag('xf', null, c));
- });
+ cellXfs.forEach(function(c) { o[o.length] = (writextag('xf', null, c)); });
o[o.length] = ("");
if(o.length === 2) return "";
o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
@@ -370,16 +316,15 @@ function write_cellXfs(cellXfs)/*:string*/ {
/* 18.8 Styles CT_Stylesheet*/
var parse_sty_xml= (function make_pstyx() {
-var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
-var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
-var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
-var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
-var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
+var numFmtRegex = /]*)>.*<\/numFmts>/;
+var cellXfRegex = /]*)>.*<\/cellXfs>/;
+var fillsRegex = /]*)>.*<\/fills>/;
+var fontsRegex = /]*)>.*<\/fonts>/;
+var bordersRegex = /]*)>.*<\/borders>/;
return function parse_sty_xml(data, themes, opts) {
var styles = {};
if(!data) return styles;
- data = data.replace(//mg,"").replace(//gm,"");
/* 18.8.39 styleSheet CT_Stylesheet */
var t;
@@ -396,11 +341,11 @@ return function parse_sty_xml(data, themes, opts) {
if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
/* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
- /* 18.8.8 cellStyles CT_CellStyles ? */
/* 18.8.10 cellXfs CT_CellXfs ? */
if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
+ /* 18.8.8 cellStyles CT_CellStyles ? */
/* 18.8.15 dxfs CT_Dxfs ? */
/* 18.8.42 tableStyles CT_TableStyles ? */
/* 18.8.11 colors CT_Colors ? */
diff --git a/bits/48_stybin.js b/bits/48_stybin.js
index fe49578..d6f9a57 100644
--- a/bits/48_stybin.js
+++ b/bits/48_stybin.js
@@ -1,31 +1,29 @@
-/* [MS-XLSB] 2.4.657 BrtFmt */
+/* [MS-XLSB] 2.4.651 BrtFmt */
function parse_BrtFmt(data, length/*:number*/) {
- var numFmtId = data.read_shift(2);
+ var ifmt = data.read_shift(2);
var stFmtCode = parse_XLWideString(data,length-2);
- return [numFmtId, stFmtCode];
+ return [ifmt, stFmtCode];
}
function write_BrtFmt(i/*:number*/, f/*:string*/, o) {
if(!o) o = new_buf(6 + 4 * f.length);
o.write_shift(2, i);
write_XLWideString(f, o);
- var out = (o.length > o.l) ? o.slice(0, o.l) : o;
- if(o.l == null) o.l = o.length;
- return out;
+ return o.length > o.l ? o.slice(0, o.l) : o;
}
-/* [MS-XLSB] 2.4.659 BrtFont TODO */
+/* [MS-XLSB] 2.4.653 BrtFont TODO */
function parse_BrtFont(data, length/*:number*/, opts) {
var out = ({}/*:any*/);
out.sz = data.read_shift(2) / 20;
var grbit = parse_FontFlags(data, 2, opts);
- if(grbit.fItalic) out.italic = 1;
if(grbit.fCondense) out.condense = 1;
if(grbit.fExtend) out.extend = 1;
if(grbit.fShadow) out.shadow = 1;
if(grbit.fOutline) out.outline = 1;
if(grbit.fStrikeout) out.strike = 1;
+ if(grbit.fItalic) out.italic = 1;
var bls = data.read_shift(2);
if(bls === 0x02BC) out.bold = 1;
@@ -58,7 +56,7 @@ function parse_BrtFont(data, length/*:number*/, opts) {
return out;
}
-function write_BrtFont(font/*:any*/, o) {
+function write_BrtFont(font, o) {
if(!o) o = new_buf(25+4*32);
o.write_shift(2, font.sz * 20);
write_FontFlags(font, o);
@@ -80,7 +78,7 @@ function write_BrtFont(font/*:any*/, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
-/* [MS-XLSB] 2.4.650 BrtFill */
+/* [MS-XLSB] 2.4.644 BrtFill */
var XLSBFillPTNames = [
"none",
"solid",
@@ -104,7 +102,6 @@ var XLSBFillPTNames = [
];
var rev_XLSBFillPTNames/*:EvertNumType*/ = (evert(XLSBFillPTNames)/*:any*/);
/* TODO: gradient fill representation */
-var parse_BrtFill = parsenoop;
function write_BrtFill(fill, o) {
if(!o) o = new_buf(4*3 + 8*7 + 16*1);
var fls/*:number*/ = rev_XLSBFillPTNames[fill.patternType];
@@ -134,13 +131,12 @@ function write_BrtFill(fill, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
-/* [MS-XLSB] 2.4.824 BrtXF */
+/* [MS-XLSB] 2.4.816 BrtXF */
function parse_BrtXF(data, length/*:number*/) {
- var tgt = data.l + length;
var ixfeParent = data.read_shift(2);
var ifmt = data.read_shift(2);
- data.l = tgt;
- return {ixfe:ixfeParent, numFmtId:ifmt };
+ parsenoop(data, length-4);
+ return {ixfe:ixfeParent, ifmt:ifmt };
}
function write_BrtXF(data, ixfeP, o) {
if(!o) o = new_buf(16);
@@ -151,8 +147,7 @@ function write_BrtXF(data, ixfeP, o) {
o.write_shift(2, 0); /* ixBorder */
o.write_shift(1, 0); /* trot */
o.write_shift(1, 0); /* indent */
- var flow = 0;
- o.write_shift(1, flow); /* flags */
+ o.write_shift(1, 0); /* flags */
o.write_shift(1, 0); /* flags */
o.write_shift(1, 0); /* xfGrbitAtr */
o.write_shift(1, 0);
@@ -168,8 +163,7 @@ function write_Blxf(data, o) {
o.write_shift(4, 0); /* color */
return o;
}
-/* [MS-XLSB] 2.4.302 BrtBorder TODO */
-var parse_BrtBorder = parsenoop;
+/* [MS-XLSB] 2.4.299 BrtBorder TODO */
function write_BrtBorder(border, o) {
if(!o) o = new_buf(51);
o.write_shift(1, 0); /* diagonal */
@@ -181,7 +175,7 @@ function write_BrtBorder(border, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
-/* [MS-XLSB] 2.4.763 BrtStyle TODO */
+/* [MS-XLSB] 2.4.755 BrtStyle TODO */
function write_BrtStyle(style, o) {
if(!o) o = new_buf(12+4*10);
o.write_shift(4, style.xfId);
@@ -192,7 +186,7 @@ function write_BrtStyle(style, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
-/* [MS-XLSB] 2.4.272 BrtBeginTableStyles */
+/* [MS-XLSB] 2.4.269 BrtBeginTableStyles */
function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) {
var o = new_buf(4+256*2*4);
o.write_shift(4, cnt);
@@ -209,7 +203,7 @@ function parse_sty_bin(data, themes, opts) {
styles.CellXf = [];
styles.Fonts = [];
- var state/*:Array*/ = [];
+ var state = [];
var pass = false;
recordhopper(data, function hopper_sty(val, R_n, RT) {
switch(RT) {
@@ -223,10 +217,8 @@ function parse_sty_bin(data, themes, opts) {
}
break;
case 0x0401: /* 'BrtKnownFonts' */ break;
- case 0x002D: /* 'BrtFill' */
- break;
- case 0x002E: /* 'BrtBorder' */
- break;
+ case 0x002D: /* 'BrtFill' */ break;
+ case 0x002E: /* 'BrtBorder' */ break;
case 0x002F: /* 'BrtXF' */
if(state[state.length - 1] == "BrtBeginCellXFs") {
styles.CellXf.push(val);
@@ -243,7 +235,7 @@ function parse_sty_bin(data, themes, opts) {
case 0x046A: /* 'BrtSlicerStyleElement' */
case 0x0200: /* 'BrtTableStyleElement' */
case 0x082F: /* 'BrtTimelineStyleElement' */
- case 0x0C00: /* 'BrtUid' */
+ /* case 'BrtUid' */
break;
case 0x0023: /* 'BrtFRTBegin' */
@@ -251,14 +243,14 @@ function parse_sty_bin(data, themes, opts) {
case 0x0024: /* 'BrtFRTEnd' */
pass = false; break;
case 0x0025: /* 'BrtACBegin' */
- state.push(R_n); pass = true; break;
+ state.push(R_n); break;
case 0x0026: /* 'BrtACEnd' */
- state.pop(); pass = false; break;
+ state.pop(); break;
default:
if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
else if((R_n||"").indexOf("End") > 0) state.pop();
- else if(!pass || (opts.WTF && state[state.length-1] != "BrtACBegin")) throw new Error("Unexpected record " + RT + " " + R_n);
+ else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
}
});
return styles;
@@ -267,21 +259,21 @@ function parse_sty_bin(data, themes, opts) {
function write_FMTS_bin(ba, NF/*:?SSFTable*/) {
if(!NF) return;
var cnt = 0;
- [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
+ [[5,8],[23,26],[41,44],[/*63*/57,/*66],[164,*/392]].forEach(function(r) {
/*:: if(!NF) return; */
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) ++cnt;
});
if(cnt == 0) return;
write_record(ba, "BrtBeginFmts", write_UInt32LE(cnt));
- [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
+ [[5,8],[23,26],[41,44],[/*63*/57,/*66],[164,*/392]].forEach(function(r) {
/*:: if(!NF) return; */
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_record(ba, "BrtFmt", write_BrtFmt(i, NF[i]));
});
write_record(ba, "BrtEndFmts");
}
-function write_FONTS_bin(ba/*::, data*/) {
+function write_FONTS_bin(ba, data) {
var cnt = 1;
if(cnt == 0) return;
@@ -297,7 +289,7 @@ function write_FONTS_bin(ba/*::, data*/) {
write_record(ba, "BrtEndFonts");
}
-function write_FILLS_bin(ba/*::, data*/) {
+function write_FILLS_bin(ba, data) {
var cnt = 2;
if(cnt == 0) return;
@@ -308,7 +300,7 @@ function write_FILLS_bin(ba/*::, data*/) {
write_record(ba, "BrtEndFills");
}
-function write_BORDERS_bin(ba/*::, data*/) {
+function write_BORDERS_bin(ba, data) {
var cnt = 1;
if(cnt == 0) return;
@@ -318,14 +310,14 @@ function write_BORDERS_bin(ba/*::, data*/) {
write_record(ba, "BrtEndBorders");
}
-function write_CELLSTYLEXFS_bin(ba/*::, data*/) {
+function write_CELLSTYLEXFS_bin(ba, data) {
var cnt = 1;
write_record(ba, "BrtBeginCellStyleXFs", write_UInt32LE(cnt));
write_record(ba, "BrtXF", write_BrtXF({
- numFmtId: 0,
- fontId: 0,
- fillId: 0,
- borderId: 0
+ numFmtId:0,
+ fontId:0,
+ fillId:0,
+ borderId:0
}, 0xFFFF));
/* 1*65430(BrtXF *FRT) */
write_record(ba, "BrtEndCellStyleXFs");
@@ -338,10 +330,10 @@ function write_CELLXFS_bin(ba, data) {
write_record(ba, "BrtEndCellXFs");
}
-function write_STYLES_bin(ba/*::, data*/) {
+function write_STYLES_bin(ba, data) {
var cnt = 1;
- write_record(ba, "BrtBeginStyles", write_UInt32LE(cnt));
+ write_record(ba, "BrtBeginStyles", write_UInt32LE(1));
write_record(ba, "BrtStyle", write_BrtStyle({
xfId:0,
builtinId:0,
@@ -351,7 +343,7 @@ function write_STYLES_bin(ba/*::, data*/) {
write_record(ba, "BrtEndStyles");
}
-function write_DXFS_bin(ba/*::, data*/) {
+function write_DXFS_bin(ba, data) {
var cnt = 0;
write_record(ba, "BrtBeginDXFs", write_UInt32LE(cnt));
@@ -359,7 +351,7 @@ function write_DXFS_bin(ba/*::, data*/) {
write_record(ba, "BrtEndDXFs");
}
-function write_TABLESTYLES_bin(ba/*::, data*/) {
+function write_TABLESTYLES_bin(ba, data) {
var cnt = 0;
write_record(ba, "BrtBeginTableStyles", write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4"));
@@ -367,7 +359,7 @@ function write_TABLESTYLES_bin(ba/*::, data*/) {
write_record(ba, "BrtEndTableStyles");
}
-function write_COLORPALETTE_bin(/*::ba, data*/) {
+function write_COLORPALETTE_bin(ba, data) {
return;
/* BrtBeginColorPalette [INDEXEDCOLORS] [MRUCOLORS] BrtEndColorPalette */
}
diff --git a/bits/49_theme.js b/bits/49_theme.js
index d3847e9..4590dff 100644
--- a/bits/49_theme.js
+++ b/bits/49_theme.js
@@ -1,12 +1,5 @@
RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
-/* Even though theme layout is dk1 lt1 dk2 lt2, true order is lt1 dk1 lt2 dk2 */
-var XLSXThemeClrScheme = [
- '', '', '', '',
- '', '', '',
- '', '', '',
- '', ''
-];
/* 20.1.6.2 clrScheme CT_ColorScheme */
function parse_clrScheme(t, themes, opts) {
themes.themeElements.clrScheme = [];
@@ -49,11 +42,11 @@ function parse_clrScheme(t, themes, opts) {
case '': case '':
case '': case '':
case '': case '':
- if (y[0].charAt(1) === '/') {
- themes.themeElements.clrScheme[XLSXThemeClrScheme.indexOf(y[0])] = color;
+ if (y[0][1] === '/') {
+ themes.themeElements.clrScheme.push(color);
color = {};
} else {
- color.name = y[0].slice(3, y[0].length - 1);
+ color.name = y[0].substring(3, y[0].length - 1);
}
break;
@@ -63,14 +56,14 @@ function parse_clrScheme(t, themes, opts) {
}
/* 20.1.4.1.18 fontScheme CT_FontScheme */
-function parse_fontScheme(/*::t, themes, opts*/) { }
+function parse_fontScheme(t, themes, opts) { }
/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
-function parse_fmtScheme(/*::t, themes, opts*/) { }
+function parse_fmtScheme(t, themes, opts) { }
-var clrsregex = /]*)>[\s\S]*<\/a:clrScheme>/;
-var fntsregex = /]*)>[\s\S]*<\/a:fontScheme>/;
-var fmtsregex = /]*)>[\s\S]*<\/a:fmtScheme>/;
+var clrsregex = /]*)>[^\u2603]*<\/a:clrScheme>/;
+var fntsregex = /]*)>[^\u2603]*<\/a:fontScheme>/;
+var fmtsregex = /]*)>[^\u2603]*<\/a:fmtScheme>/;
/* 20.1.6.10 themeElements CT_BaseStyles */
function parse_themeElements(data, themes, opts) {
@@ -91,7 +84,7 @@ function parse_themeElements(data, themes, opts) {
});
}
-var themeltregex = /]*)>[\s\S]*<\/a:themeElements>/;
+var themeltregex = /]*)>[^\u2603]*<\/a:themeElements>/;
/* 14.2.7 Theme Part */
function parse_theme_xml(data/*:string*/, opts) {
@@ -104,13 +97,12 @@ function parse_theme_xml(data/*:string*/, opts) {
/* themeElements CT_BaseStyles */
if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
parse_themeElements(t[0], themes, opts);
- themes.raw = data;
+
return themes;
}
function write_theme(Themes, opts)/*:string*/ {
if(opts && opts.themeXLSX) return opts.themeXLSX;
- if(Themes && typeof Themes.raw == "string") return Themes.raw;
var o = [XML_HEADER];
o[o.length] = '';
o[o.length] = '';
diff --git a/bits/50_styxls.js b/bits/50_styxls.js
index 102f2b8..5125c1b 100644
--- a/bits/50_styxls.js
+++ b/bits/50_styxls.js
@@ -1,22 +1,15 @@
/* [MS-XLS] 2.4.326 TODO: payload is a zip file */
function parse_Theme(blob, length, opts) {
- var end = blob.l + length;
var dwThemeVersion = blob.read_shift(4);
if(dwThemeVersion === 124226) return;
- if(!opts.cellStyles || !jszip) { blob.l = end; return; }
- var data = blob.slice(blob.l);
- blob.l = end;
- var zip; try { zip = new jszip(data); } catch(e) { return; }
- var themeXML = getzipstr(zip, "theme/theme/theme1.xml", true);
- if(!themeXML) return;
- return parse_theme_xml(themeXML, opts);
+ blob.l += length-4;
}
/* 2.5.49 */
-function parse_ColorTheme(blob/*::, length*/) { return blob.read_shift(4); }
+function parse_ColorTheme(blob, length) { return blob.read_shift(4); }
/* 2.5.155 */
-function parse_FullColorExt(blob/*::, length*/) {
+function parse_FullColorExt(blob, length) {
var o = {};
o.xclrType = blob.read_shift(2);
o.nTintShade = blob.read_shift(2);
@@ -41,17 +34,17 @@ function parse_XFExtGradient(blob, length) {
return parsenoop(blob, length);
}
-/* [MS-XLS] 2.5.108 */
-function parse_ExtProp(blob/*::, length*/)/*:Array*/ {
+/* 2.5.108 */
+function parse_ExtProp(blob, length) {
var extType = blob.read_shift(2);
- var cb = blob.read_shift(2) - 4;
+ var cb = blob.read_shift(2);
var o = [extType];
switch(extType) {
case 0x04: case 0x05: case 0x07: case 0x08:
case 0x09: case 0x0A: case 0x0B: case 0x0D:
o[1] = parse_FullColorExt(blob, cb); break;
case 0x06: o[1] = parse_XFExtGradient(blob, cb); break;
- case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 1 ? 1 : 2); break;
+ case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 5 ? 1 : 2); break;
default: throw new Error("Unrecognized ExtProp type: " + extType + " " + cb);
}
return o;
@@ -64,7 +57,7 @@ function parse_XFExt(blob, length) {
var ixfe = blob.read_shift(2);
blob.l += 2;
var cexts = blob.read_shift(2);
- var ext/*:AOA*/ = [];
+ var ext = [];
while(cexts-- > 0) ext.push(parse_ExtProp(blob, end-blob.l));
return {ixfe:ixfe, ext:ext};
}
@@ -81,8 +74,7 @@ function update_xfext(xf, xfext) {
case 0x09: break; /* left cell border color */
case 0x0a: break; /* right cell border color */
case 0x0b: break; /* diagonal cell border color */
- case 0x0d: /* text color */
- break;
+ case 0x0d: break; /* text color */
case 0x0e: break; /* font scheme */
case 0x0f: break; /* indentation level */
}
diff --git a/bits/52_ccxml.js b/bits/52_ccxml.js
new file mode 100644
index 0000000..b7fee49
--- /dev/null
+++ b/bits/52_ccxml.js
@@ -0,0 +1,19 @@
+/* 18.6 Calculation Chain */
+function parse_cc_xml(data, opts) {
+ var d = [];
+ if(!data) return d;
+ var l = 0, i = 1;
+ (data.match(tagregex)||[]).forEach(function(x) {
+ var y = parsexmltag(x);
+ switch(y[0]) {
+ case '': case '': break;
+ /* 18.6.1 c CT_CalcCell 1 */
+ case '*/ {
- var d = [];
- if(!data) return d;
- var i = 1;
- (data.match(tagregex)||[]).forEach(function(x) {
- var y = parsexmltag(x);
- switch(y[0]) {
- case '': case '': break;
- /* 18.6.1 c CT_CalcCell 1 */
- case ' 0){/* empty */}
- else if((R_n||"").indexOf("End") > 0){/* empty */}
- else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
- }
- }, opts);
-}
diff --git a/bits/54_drawing.js b/bits/54_drawing.js
index 6ac7447..9499f90 100644
--- a/bits/54_drawing.js
+++ b/bits/54_drawing.js
@@ -1,8 +1,6 @@
-/* 20.5 DrawingML - SpreadsheetML Drawing */
RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
-
-/* 20.5.2.35 wsDr CT_Drawing */
+/* 20.5 DrawingML - SpreadsheetML Drawing */
function parse_drawing(data, rels/*:any*/) {
if(!data) return "??";
/*
diff --git a/bits/55_vml.js b/bits/55_vml.js
index 224960a..e0bd896 100644
--- a/bits/55_vml.js
+++ b/bits/55_vml.js
@@ -1,6 +1,6 @@
/* L.5.5.2 SpreadsheetML Comments + VML Schema */
var _shapeid = 1024;
-function write_comments_vml(rId/*:number*/, comments) {
+function write_comments_vml(rId, comments) {
var csize = [21600, 21600];
/* L.5.2.1.2 Path Attribute */
var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
@@ -14,40 +14,31 @@ function write_comments_vml(rId/*:number*/, comments) {
];
while(_shapeid < rId * 1000) _shapeid += 1000;
- comments.forEach(function(x) {
- var c = decode_cell(x[0]);
- var fillopts = /*::(*/{'color2':"#BEFF82", 'type':"gradient"}/*:: :any)*/;
- if(fillopts.type == "gradient") fillopts.angle = "-180";
- var fillparm = fillopts.type == "gradient" ? writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}) : null;
- var fillxml = writextag('v:fill', fillparm, fillopts);
-
- var shadata = ({on:"t", 'obscured':"t"}/*:any*/);
- ++_shapeid;
-
- o = o.concat([
+ comments.map(function(x) { return decode_cell(x[0]); }).forEach(function(c,i) { o = o.concat([
'',
- fillxml,
- writextag("v:shadow", null, shadata),
+ writextag('v:fill', writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}), {'color2':"#BEFF82", 'angle':"-180", 'type':"gradient"}),
+ writextag("v:shadow", null, {on:"t", 'obscured':"t"}),
writextag("v:path", null, {'o:connecttype':"none"}),
'',
'',
'',
'',
/* Part 4 19.4.2.3 Anchor (Anchor) */
- writetag('x:Anchor', [c.c+1, 0, c.r+1, 0, c.c+3, 20, c.r+5, 20].join(",")),
+ writetag('x:Anchor', [c.c, 0, c.r, 0, c.c+3, 100, c.r+5, 100].join(",")),
writetag('x:AutoFill', "False"),
writetag('x:Row', String(c.r)),
writetag('x:Column', String(c.c)),
- x[1].hidden ? '' : '',
+ '',
'',
''
]); });
o.push('');
return o.join("");
}
+
diff --git a/bits/56_cmntcommon.js b/bits/56_cmntcommon.js
index 0c369ca..4931e96 100644
--- a/bits/56_cmntcommon.js
+++ b/bits/56_cmntcommon.js
@@ -1,29 +1,48 @@
RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
-function sheet_insert_comments(sheet, comments/*:Array*/) {
+function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
+ for(var i = 0; i != dirComments.length; ++i) {
+ var canonicalpath=dirComments[i];
+ var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
+ if(!comments || !comments.length) continue;
+ // find the sheets targeted by these comments
+ var sheetNames = keys(sheets);
+ for(var j = 0; j != sheetNames.length; ++j) {
+ var sheetName = sheetNames[j];
+ var rels = sheetRels[sheetName];
+ if(rels) {
+ var rel = rels[canonicalpath];
+ if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
+ }
+ }
+ }
+}
+
+function insertCommentsIntoSheet(sheetName, sheet, comments) {
var dense = Array.isArray(sheet);
- var cell/*:Cell*/;
+ var cell, r;
comments.forEach(function(comment) {
- var r = decode_cell(comment.ref);
if(dense) {
+ r = decode_cell(comment.ref);
if(!sheet[r.r]) sheet[r.r] = [];
cell = sheet[r.r][r.c];
} else cell = sheet[comment.ref];
if (!cell) {
- cell = ({t:"z"}/*:any*/);
+ cell = {};
if(dense) sheet[r.r][r.c] = cell;
else sheet[comment.ref] = cell;
var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
- if(range.s.r > r.r) range.s.r = r.r;
- if(range.e.r < r.r) range.e.r = r.r;
- if(range.s.c > r.c) range.s.c = r.c;
- if(range.e.c < r.c) range.e.c = r.c;
+ var thisCell = decode_cell(comment.ref);
+ if(range.s.r > thisCell.r) range.s.r = thisCell.r;
+ if(range.e.r < thisCell.r) range.e.r = thisCell.r;
+ if(range.s.c > thisCell.c) range.s.c = thisCell.c;
+ if(range.e.c < thisCell.c) range.e.c = thisCell.c;
var encoded = encode_range(range);
if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
}
if (!cell.c) cell.c = [];
- var o/*:Comment*/ = ({a: comment.author, t: comment.t, r: comment.r});
+ var o = ({a: comment.author, t: comment.t, r: comment.r}/*:any*/);
if(comment.h) o.h = comment.h;
cell.c.push(o);
});
diff --git a/bits/57_cmntxml.js b/bits/57_cmntxml.js
index 04eeefa..57fa917 100644
--- a/bits/57_cmntxml.js
+++ b/bits/57_cmntxml.js
@@ -1,29 +1,29 @@
/* 18.7 Comments */
-function parse_comments_xml(data/*:string*/, opts)/*:Array*/ {
+function parse_comments_xml(data/*:string*/, opts)/*:Array*/ {
/* 18.7.6 CT_Comments */
if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
- var authors/*:Array*/ = [];
- var commentList/*:Array*/ = [];
- var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
+ var authors = [];
+ var commentList = [];
+ var authtag = data.match(/<(?:\w+:)?authors>([^\u2603]*)<\/(?:\w+:)?authors>/);
if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
if(x === "" || x.trim() === "") return;
var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
if(a) authors.push(a[1]);
});
- var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
- if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
+ var cmnttag = data.match(/<(?:\w+:)?commentList>([^\u2603]*)<\/(?:\w+:)?commentList>/);
+ if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x, index) {
if(x === "" || x.trim() === "") return;
var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
if(!cm) return;
var y = parsexmltag(cm[0]);
- var comment/*:RawComment*/ = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid }/*:any*/);
+ var comment/*:Comment*/ = ({ author: y.authorId && authors[y.authorId] ? authors[y.authorId] : "sheetjsghost", ref: y.ref, guid: y.guid }/*:any*/);
var cell = decode_cell(y.ref);
if(opts.sheetRows && opts.sheetRows <= cell.r) return;
- var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
+ var textMatch = x.match(/<(?:\w+:)?text>([^\u2603]*)<\/(?:\w+:)?text>/);
var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
comment.r = rt.r;
if(rt.r == "") rt.t = rt.h = "";
- comment.t = (rt.t||"").replace(/\r\n/g,"\n").replace(/\r/g,"\n");
+ comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
if(opts.cellHTML) comment.h = rt.h;
commentList.push(comment);
});
@@ -31,23 +31,25 @@ function parse_comments_xml(data/*:string*/, opts)/*:Array*/ {
}
var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
-function write_comments_xml(data/*::, opts*/) {
+function write_comments_xml(data, opts) {
var o = [XML_HEADER, CMNT_XML_ROOT];
- var iauthor/*:Array*/ = [];
+ var iauthor = [];
o.push("");
- data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
- if(iauthor.indexOf(a) > -1) return;
- iauthor.push(a);
- o.push("" + a + "");
- }); });
+ data.map(function(x) { return x[1]; }).forEach(function(comment) {
+ comment.map(function(x) { return escapexml(x.a); }).forEach(function(a) {
+ if(iauthor.indexOf(a) > -1) return;
+ iauthor.push(a);
+ o.push("" + a + "");
+ });
+ });
o.push("");
o.push("");
data.forEach(function(d) {
d[1].forEach(function(c) {
/* 18.7.3 CT_Comment */
o.push('');
- o.push(writetag("t", c.t == null ? "" : escapexml(c.t)));
+ o.push(writetag("t", c.t == null ? "" : c.t));
o.push('');
});
});
diff --git a/bits/58_cmntbin.js b/bits/58_cmntbin.js
index d72933f..82ca18a 100644
--- a/bits/58_cmntbin.js
+++ b/bits/58_cmntbin.js
@@ -1,5 +1,5 @@
/* [MS-XLSB] 2.4.28 BrtBeginComment */
-function parse_BrtBeginComment(data) {
+function parse_BrtBeginComment(data, length) {
var out = {};
out.iauthor = data.read_shift(4);
var rfx = parse_UncheckedRfX(data, 16);
@@ -19,14 +19,13 @@ function write_BrtBeginComment(data, o) {
return o;
}
-/* [MS-XLSB] 2.4.327 BrtCommentAuthor */
+/* [MS-XLSB] 2.4.324 BrtCommentAuthor */
var parse_BrtCommentAuthor = parse_XLWideString;
-function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); }
/* [MS-XLSB] 2.1.7.8 Comments */
-function parse_comments_bin(data, opts)/*:Array*/ {
- var out/*:Array*/ = [];
- var authors/*:Array