forked from sheetjs/sheetjs
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			master
			...
			nandanv270
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 79a49b61f5 | ||
|  | 0a169a78d2 | 
							
								
								
									
										12
									
								
								.eslintmjs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										12
									
								
								.eslintmjs
									
									
									
									
									
								
							| @ -1,12 +0,0 @@ | ||||
| { | ||||
|   "parserOptions": { | ||||
|     "sourceType": "module", | ||||
|     "ecmaVersion": 2020 | ||||
|   }, | ||||
|   "plugins": [ | ||||
|     "tree-shaking" | ||||
|   ], | ||||
|   "rules": { | ||||
|     "tree-shaking/no-side-effects-in-initialization": 2 | ||||
|   } | ||||
| } | ||||
| @ -11,10 +11,8 @@ | ||||
| 		"comma-dangle": [ 2, "never" ], | ||||
| 		"curly": 0, | ||||
| 		"no-bitwise": 0, | ||||
| 		"no-cond-assign": 1, | ||||
| 		"no-console": 0, | ||||
| 		"no-control-regex": 0, | ||||
| 		"no-unused-vars": 1, | ||||
| 		"no-empty": 0, | ||||
| 		"no-trailing-spaces": 2, | ||||
| 		"no-use-before-define": [ 1, { | ||||
|  | ||||
| @ -17,6 +17,7 @@ | ||||
| .*/xlsx.mini.js | ||||
| .*/xlsx.mini.flow.js | ||||
| .*/xlsxworker.js | ||||
| .*/jszip.js | ||||
| .*/tests/.* | ||||
| .*/demos/.* | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										16
									
								
								.fossaignore
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								.fossaignore
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| bits/ | ||||
| demos/ | ||||
| dist/ | ||||
| docbits/ | ||||
| misc/ | ||||
| node_modules/ | ||||
| types/ | ||||
| tests/ | ||||
| test_files | ||||
| *.md | ||||
| 
 | ||||
| *.json | ||||
| *.log | ||||
| *.sh | ||||
| .DS_Store | ||||
| .Trashes | ||||
							
								
								
									
										4
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										4
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,4 @@ | ||||
| *.*s        linguist-documentation | ||||
| *.html      linguist-documentation | ||||
| 
 | ||||
| *.md        text eol=lf | ||||
| @ -8,10 +9,7 @@ xlsx*.js    text eol=lf | ||||
| 
 | ||||
| docbits/*         linguist-documentation | ||||
| dist/*            linguist-generated=true binary | ||||
| *.mjs             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 | ||||
| 
 | ||||
| test.mjs    lingust-generated=false binary=false text eol=lf | ||||
|  | ||||
							
								
								
									
										20
									
								
								.github/workflows/bun.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										20
									
								
								.github/workflows/bun.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,20 +0,0 @@ | ||||
| name: 'Tests: Bun' | ||||
| 
 | ||||
| on: [pull_request, push] | ||||
| 
 | ||||
| jobs: | ||||
|   # misc test | ||||
|   misc: | ||||
|     name: 'misc (with codepage)' | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|       - uses: antongolub/action-setup-bun@v1 | ||||
|       - uses: ljharb/actions/node/install@main | ||||
|         with: | ||||
|           node-version: '16.' | ||||
|       - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 | ||||
|       - run: sudo chmod a+x /usr/bin/rooster | ||||
|       - run: make init | ||||
|       - run: 'cd test_files; make all; cd -' | ||||
|       - run: 'env FMTS=misc bun hotcross.mjs' | ||||
							
								
								
									
										39
									
								
								.github/workflows/deno.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										39
									
								
								.github/workflows/deno.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,39 +0,0 @@ | ||||
| name: 'Tests: deno 1.x' | ||||
| 
 | ||||
| on: [pull_request, push] | ||||
| 
 | ||||
| jobs: | ||||
|   # full test | ||||
|   full: | ||||
|     name: 'full (with codepage)' | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|       - uses: denoland/setup-deno@main | ||||
|         with: | ||||
|           deno-version: v1.x | ||||
|       - uses: ljharb/actions/node/install@main | ||||
|         with: | ||||
|           node-version: '16.' | ||||
|       - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 | ||||
|       - run: sudo chmod a+x /usr/bin/rooster | ||||
|       - run: make init | ||||
|       - run: 'cd test_files; make all; cd -' | ||||
|       - run: deno test --allow-env --allow-read --allow-write --config misc/test.deno.jsonc test.ts | ||||
|   # full test (no codepage) | ||||
|   fullnocp: | ||||
|     name: 'full (no codepage)' | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|       - uses: denoland/setup-deno@main | ||||
|         with: | ||||
|           deno-version: v1.x | ||||
|       - uses: ljharb/actions/node/install@main | ||||
|         with: | ||||
|           node-version: '16.' | ||||
|       - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 | ||||
|       - run: sudo chmod a+x /usr/bin/rooster | ||||
|       - run: make init | ||||
|       - run: 'cd test_files; make all; cd -' | ||||
|       - run: deno test --allow-env --allow-read --allow-write --config misc/test.deno.jsonc testnocp.ts | ||||
							
								
								
									
										3
									
								
								.github/workflows/node-4+.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								.github/workflows/node-4+.yml
									
									
									
									
										vendored
									
									
								
							| @ -77,12 +77,9 @@ jobs: | ||||
|         name: 'nvm install ${{ matrix.node-version }} && npm install' | ||||
|         with: | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|       - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 | ||||
|       - run: sudo chmod a+x /usr/bin/rooster | ||||
|       - run: make init | ||||
|       - run: 'cd test_files; make all; cd -' | ||||
|       - run: npm run tests-only | ||||
|       - run: 'cd packages/ssf; npm install; npm run tests-only; cd -' | ||||
| 
 | ||||
|   node: | ||||
|     name: 'node 4+' | ||||
|  | ||||
							
								
								
									
										3
									
								
								.github/workflows/node-iojs.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								.github/workflows/node-iojs.yml
									
									
									
									
										vendored
									
									
								
							| @ -30,12 +30,9 @@ jobs: | ||||
|         with: | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|           skip-ls-check: true | ||||
|       - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 | ||||
|       - run: sudo chmod a+x /usr/bin/rooster | ||||
|       - run: make init | ||||
|       - run: 'cd test_files; make all; cd -' | ||||
|       - run: npm run tests-only | ||||
|       #- run: 'cd packages/ssf; npm run tests-only; cd -' | ||||
| 
 | ||||
|   node: | ||||
|     name: 'io.js' | ||||
|  | ||||
							
								
								
									
										2
									
								
								.github/workflows/node-pretest.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								.github/workflows/node-pretest.yml
									
									
									
									
										vendored
									
									
								
							| @ -12,8 +12,6 @@ jobs: | ||||
|         name: 'nvm install lts/* && npm install' | ||||
|         with: | ||||
|           node-version: 'lts/*' | ||||
|       - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 | ||||
|       - run: sudo chmod a+x /usr/bin/rooster | ||||
|       - run: make init | ||||
|       - run: 'cd test_files; make all; cd -' | ||||
|       - run: npm run pretest | ||||
|  | ||||
							
								
								
									
										54
									
								
								.github/workflows/node-zero.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										54
									
								
								.github/workflows/node-zero.yml
									
									
									
									
										vendored
									
									
								
							| @ -7,7 +7,7 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     outputs: | ||||
|       stable: ${{ steps.set-matrix.outputs.requireds }} | ||||
| #      unstable: ${{ steps.set-matrix.outputs.optionals }} | ||||
|       unstable: ${{ steps.set-matrix.outputs.optionals }} | ||||
|     steps: | ||||
|       - uses: ljharb/actions/node/matrix@main | ||||
|         id: set-matrix | ||||
| @ -46,43 +46,37 @@ jobs: | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|           cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }} | ||||
|           skip-ls-check: true | ||||
|       - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 | ||||
|       - run: sudo chmod a+x /usr/bin/rooster | ||||
|       - run: make init | ||||
|       - run: 'cd test_files; make all; cd -' | ||||
|       - run: npm run tests-only | ||||
|       #- run: 'cd packages/ssf; npm run tests-only; cd -' | ||||
| 
 | ||||
| #  unstable: | ||||
| #    needs: [matrix, stable] | ||||
| #    name: 'unstable minors' | ||||
| #    continue-on-error: true | ||||
| #    if: ${{ !github.head_ref || !startsWith(github.head_ref, 'renovate') }} | ||||
| #    runs-on: ubuntu-latest | ||||
|   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: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 | ||||
| #      - run: sudo chmod a+x /usr/bin/rooster | ||||
| #      - run: make init | ||||
| #      - run: 'cd test_files; make all; cd -' | ||||
| #      - run: npm run tests-only | ||||
|     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] | ||||
|     needs: [stable] | ||||
|     needs: [stable, unstable] | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - run: 'echo tests completed' | ||||
|  | ||||
							
								
								
									
										12
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										12
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -4,7 +4,6 @@ package-lock.json | ||||
| _book/ | ||||
| misc/coverage.html | ||||
| misc/prof.js | ||||
| misc/*.[sS][vV][gG] | ||||
| v8.log | ||||
| tmp | ||||
| *.[tT][xX][tT] | ||||
| @ -14,25 +13,18 @@ tmp | ||||
| *.[pP][mM][dD]* | ||||
| *.[pP][dD][fF] | ||||
| *.[sS][lL][kK] | ||||
| *.[sS][yY][lL][kK] | ||||
| *.socialcalc | ||||
| *.[xX][lL][sSwWcCaAtTmMrR] | ||||
| *.[xX][lL][sSwWcCaAtTmM] | ||||
| *.[xX][lL][sSaAtT][xXmMbB] | ||||
| *.[oO][dD][sS] | ||||
| *.[fF][oO][dD][sS] | ||||
| *.[xX][mM][lL] | ||||
| *.[xX][lL][mM][lL] | ||||
| *.[uU][oO][sS] | ||||
| *.[wW][kKqQbB][sS1234567890] | ||||
| *.[wW][kKqQbB][S1234567890] | ||||
| *.[qQ][pP][wW] | ||||
| *.[fF][mM][3tT] | ||||
| *.[bB][iI][fF][fF][23458] | ||||
| *.[rR][tT][fF] | ||||
| *.[eE][tT] | ||||
| *.[eE][tT][hH] | ||||
| *.[nN][uU][mM][bB][eE][rR][sS] | ||||
| *.[mM][oO][dD] | ||||
| *.[dD][tT][aA] | ||||
| *.123 | ||||
| *.htm | ||||
| *.html | ||||
|  | ||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -0,0 +1,3 @@ | ||||
| [submodule "test_files"] | ||||
| 	path = test_files | ||||
| 	url = https://github.com/SheetJS/test_files | ||||
							
								
								
									
										18
									
								
								.npmignore
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										18
									
								
								.npmignore
									
									
									
									
									
								
							| @ -1,5 +1,4 @@ | ||||
| test_files/ | ||||
| modules/ | ||||
| packages/ | ||||
| .github/ | ||||
| tests/files/ | ||||
| @ -8,10 +7,8 @@ index.html | ||||
| misc/ | ||||
| node_modules | ||||
| *.tgz | ||||
| *.jsx | ||||
| _book | ||||
| book.json | ||||
| v8.log | ||||
| tmp | ||||
| *.[tT][xX][tT] | ||||
| *.[cC][sS][vV] | ||||
| @ -20,24 +17,18 @@ tmp | ||||
| *.[pP][mM][dD]* | ||||
| *.[pP][dD][fF] | ||||
| *.[sS][lL][kK] | ||||
| *.[sS][yY][lL][kK] | ||||
| *.socialcalc | ||||
| *.[xX][lL][sSwWcCaAtTmMrR] | ||||
| *.[xX][lL][sSwWcCaAtTmM] | ||||
| *.[xX][lL][sSaAtT][xXmMbB] | ||||
| *.[oO][dD][sS] | ||||
| *.[fF][oO][dD][sS] | ||||
| *.[xX][mM][lL] | ||||
| *.[xX][lL][mM][lL] | ||||
| *.[uU][oO][sS] | ||||
| *.[wW][kKqQbB][S1234567890] | ||||
| *.[qQ][pP][wW] | ||||
| *.[fF][mM][3tT] | ||||
| *.[bB][iI][fF][fF][23458] | ||||
| *.[rR][tT][fF] | ||||
| *.[eE][tT] | ||||
| *.[eE][tT][hH] | ||||
| *.[nN][uU][mM][bB][eE][rR][sS] | ||||
| *.[mM][oO][dD] | ||||
| *.123 | ||||
| *.htm | ||||
| *.html | ||||
| @ -50,9 +41,7 @@ tmp | ||||
| .spelling | ||||
| .eslintignore | ||||
| .eslintrc | ||||
| .eslintmjs | ||||
| .jshintrc | ||||
| xlsx.mini.js | ||||
| CONTRIBUTING.md | ||||
| Makefile | ||||
| make.cmd | ||||
| @ -61,11 +50,6 @@ make.cmd | ||||
| xlsworker.js | ||||
| shim.js | ||||
| test.js | ||||
| test.mjs | ||||
| test.ts | ||||
| test.mts | ||||
| testnocp.ts | ||||
| testbun.mjs | ||||
| .jscs.json | ||||
| .gitmodules | ||||
| .travis.yml | ||||
|  | ||||
							
								
								
									
										33
									
								
								.spelling
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										33
									
								
								.spelling
									
									
									
									
									
								
							| @ -1,6 +1,5 @@ | ||||
| # xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com | ||||
| SheetJS | ||||
| sheetjs | ||||
| js-xlsx | ||||
| xls | ||||
| xlsb | ||||
| @ -16,7 +15,6 @@ OData | ||||
| OpenDocument | ||||
| OpenFormula | ||||
| PivotTable | ||||
| PivotTables | ||||
| Quattro | ||||
| SpreadsheetML | ||||
| Unhide | ||||
| @ -36,48 +34,29 @@ tooltips | ||||
| Browserify | ||||
| CDNjs | ||||
| CommonJS | ||||
| Deno | ||||
| Ethercalc | ||||
| ExtendScript | ||||
| InDesign | ||||
| IndexedDB | ||||
| JavaScriptCore | ||||
| LocalStorage | ||||
| NestJS | ||||
| NPM | ||||
| Nuxt | ||||
| PhantomJS | ||||
| Photoshop | ||||
| Nuxt.js | ||||
| Redis | ||||
| RequireJS | ||||
| Rollup | ||||
| SessionStorage | ||||
| SQLite | ||||
| SystemJS | ||||
| Vite | ||||
| VueJS | ||||
| WebKit | ||||
| WebSQL | ||||
| WK_ | ||||
| iOS | ||||
| iWork | ||||
| nodejs | ||||
| node.js | ||||
| npm | ||||
| unpkg | ||||
| webpack | ||||
| weex | ||||
| 
 | ||||
| # Other terms | ||||
| 1.x | ||||
| 2.x | ||||
| 3.x | ||||
| 4.x | ||||
| 5.x | ||||
| 6.x | ||||
| 7.x | ||||
| 8.x | ||||
| 9.x | ||||
| ActiveX | ||||
| APIs | ||||
| ArrayBuffer | ||||
| @ -87,7 +66,6 @@ FileReader | ||||
| JS | ||||
| NoSQL | ||||
| README | ||||
| UTF-8 | ||||
| UTF-16 | ||||
| VBScript | ||||
| XHR | ||||
| @ -95,36 +73,30 @@ XMLHttpRequest | ||||
| bundler | ||||
| bundlers | ||||
| cleanroom | ||||
| codepage | ||||
| config | ||||
| customizable | ||||
| datagrid | ||||
| dataset | ||||
| deduplication | ||||
| destructuring | ||||
| embeddable | ||||
| encodings | ||||
| filesystem | ||||
| globals | ||||
| javascript | ||||
| lifecycle | ||||
| metadata | ||||
| natively | ||||
| pre-built | ||||
| pre-generated | ||||
| prepend | ||||
| prepended | ||||
| programmatically | ||||
| repo | ||||
| runtime | ||||
| serverless | ||||
| submodule | ||||
| transpiled | ||||
| utils | ||||
| node.js | ||||
| commonjs | ||||
| async | ||||
| uncheck | ||||
| vendoring | ||||
| 
 | ||||
|  - demos/altjs/README.md | ||||
| ChakraCore | ||||
| @ -159,7 +131,6 @@ storages | ||||
| 
 | ||||
|  - demos/extendscript/README.md | ||||
| Photoshop | ||||
| InDesign | ||||
| minifier | ||||
| 
 | ||||
|  - demos/function/README.md | ||||
|  | ||||
							
								
								
									
										155
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										155
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @ -4,161 +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. | ||||
| 
 | ||||
| * Sheet Visibility for ODS / FODS (h/t @edemaine) | ||||
| * HTML DOM ingress support formulae (`data-f`) | ||||
| * Proper handling of XLSX encoded entities (h/t @inreoh) | ||||
| 
 | ||||
| ## v0.20.3 | ||||
| 
 | ||||
| * Correct parsing of NUMBERS and ODS merge cells (h/t @s-ashwin) | ||||
| * More precise treatment of infinite and NaN values | ||||
| * XLML Streaming Write | ||||
| * Parse `Int8Array` objects (for compatibility with JS engines in Java) | ||||
| * CSV Export only quote leading ID (h/t @lako12) | ||||
| 
 | ||||
| ## v0.20.2 | ||||
| 
 | ||||
| * Reworked parsing methods to avoid slow regexes (CVE-2024-22363) | ||||
| * HTML properly encode data-v attribute | ||||
| * SYLK read and write error cells | ||||
| 
 | ||||
| ## v0.20.1 | ||||
| 
 | ||||
| * `init` use packaged test files to work around GitHub breaking changes | ||||
| * SSF date code rounding to 15 decimal digits (h/t @davidtamaki) | ||||
| * `sheet_to_json` force UTC interpretation for formatted strings (h/t @Blanay) | ||||
| * QPW extract result of string formula | ||||
| * XLSX parse non-compliant merge cell expressions | ||||
| * NUMBERS correctly handle rows omitted from official exports | ||||
| * DBF parse empty logical field (h/t @Roman91) | ||||
| * `dense` option added to types | ||||
| * package.json add mini and core scripts to export map (h/t @stof) | ||||
| 
 | ||||
| ## v0.20.0 | ||||
| 
 | ||||
| * Use UTC interpretation of Date objects for date cells (potentially breaking) | ||||
| * API functions support UTC and local time value interpretations | ||||
| * Export `NaN` values to `#NUM!` and infinite values to `#DIV/0!` | ||||
| 
 | ||||
| ## v0.19.3 | ||||
| 
 | ||||
| * XLSX Ensure comment address is valid (h/t @slonser) | ||||
| * Enforce Excel worksheet name restrictions | ||||
| * Fixed "Prototype Pollution" vulnerability (CVE-2023-30533) | ||||
| 
 | ||||
| ## v0.19.2 | ||||
| 
 | ||||
| * XLSX proper decoding of hyperlinks (h/t @tw-yaxu) | ||||
| * XLSX ignore unexpected attributes in rich text (h/t @colin4) | ||||
| * `sheet_to_json` type fix (h/t @chsdwn) | ||||
| 
 | ||||
| ## v0.19.1 | ||||
| 
 | ||||
| * Fixed types issue in strict mode (h/t @younes-io) | ||||
| * Numbers 12.2 parsing skip ActivityStream.iwa | ||||
| 
 | ||||
| ## v0.19.0 | ||||
| 
 | ||||
| * XLSX export hyperlinks compatible with google sheets (h/t Evan Bovie) | ||||
| * NUMBERS export multiple sheets, full worksheet range | ||||
| * formalized `dense` mode | ||||
| 
 | ||||
| ## v0.18.12 | ||||
| 
 | ||||
| * `package.json` added types in `exports` structure | ||||
| * uncapped NUMBERS single-sheet single-table export | ||||
| * DBF export records using supported codepages | ||||
| 
 | ||||
| ## v0.18.11 | ||||
| 
 | ||||
| * Base64 input ignore data URI wrapper | ||||
| * Parse ZIP files that use ZIP64 extended information field | ||||
| * More precise handling of time-only values | ||||
| * Threaded Comment fallback text for older Excel | ||||
| 
 | ||||
| ## v0.18.10 | ||||
| 
 | ||||
| * `exports` field in package.json to satiate ViteJS and newer tooling | ||||
| * JSC (Safari / Bun) perf, see <https://bugs.webkit.org/show_bug.cgi?id=243148> | ||||
| * workbook `bookType` property to denote the origin format when parsed from file | ||||
| * XLSX force export of stub cells with number formats when `sheetStubs` is set | ||||
| 
 | ||||
| ## v0.18.9 | ||||
| 
 | ||||
| * XLSX / ODS write defined names | ||||
| * sync defined names to AutoFilter setting on export | ||||
| * 1904 date system setting properly roundtripped | ||||
| * ODS read/write number formats | ||||
| 
 | ||||
| ## v0.18.8 | ||||
| 
 | ||||
| * Plaintext parsing of dateless meridien time values (`1:23:45 PM`) | ||||
| * Legacy format (SYLK / WK# / Multiplan) minutiae | ||||
| 
 | ||||
| ## v0.18.7 | ||||
| 
 | ||||
| * Normalized handling of `\r` and `\n` newline characters | ||||
| 
 | ||||
| ## v0.18.6 | ||||
| 
 | ||||
| * Removed all npm dependencies | ||||
| * Auto-correct bad Google Sheets format `d.m` | ||||
| * NUMBERS write merge cells, cells up to column "ALL" | ||||
| 
 | ||||
| ## v0.18.5 | ||||
| 
 | ||||
| * Enabled `sideEffects: false` in package.json | ||||
| * Basic NUMBERS write support | ||||
| 
 | ||||
| ## v0.18.4 | ||||
| 
 | ||||
| * CSV output omits trailing record separator | ||||
| * Properly terminate NodeJS Streams | ||||
| * DBF preserve column types on import and use when applicable on export | ||||
| 
 | ||||
| ## v0.18.3 | ||||
| 
 | ||||
| * Removed references to `require` and `process` in browser builds | ||||
| 
 | ||||
| ## v0.18.2 | ||||
| 
 | ||||
| * Hotfix for unicode processing of XLSX exports | ||||
| 
 | ||||
| ## v0.18.1 | ||||
| 
 | ||||
| * Removed Node ESM build script and folded into standard ESM build | ||||
| * Removed undocumented aliases including `make_formulae` and `get_formulae` | ||||
| 
 | ||||
| ## v0.18.0 | ||||
| 
 | ||||
| * Browser scripts only expose `XLSX` variable | ||||
| * Module no longer ships with `dist/jszip.js` browser script | ||||
| 
 | ||||
| ## v0.17.4 | ||||
| 
 | ||||
| * CLI script moved to `xlsx-cli` package | ||||
| 
 | ||||
| ## v0.17.3 | ||||
| 
 | ||||
| * `window.XLSX` explicit assignment to satiate LWC | ||||
| * CSV Proper formatting of errors | ||||
| * HTML emit data-\* attributes | ||||
| 
 | ||||
| ## v0.17.2 | ||||
| 
 | ||||
| * Browser and Node optional ESM support | ||||
| * DSV correct handling of bare quotes (h/t @bgamrat) | ||||
| 
 | ||||
| ## v0.17.1 | ||||
| 
 | ||||
| * `XLSB` writer uses short cell form when viable | ||||
| 
 | ||||
| ## 0.17.0: | ||||
| 
 | ||||
| * mini build includes ODS parse/write support | ||||
| * DBF explicitly cap worksheet to 1<<20 rows | ||||
| * XLS throw errors on truncated records | ||||
| 
 | ||||
| ## v0.16.2 | ||||
| 
 | ||||
| * Disabled `PRN` parsing by default (better support for CSV without delimeters) | ||||
|  | ||||
| @ -4,17 +4,17 @@ The SheetJS Libraries should be free and clear to use in your projects.  In | ||||
| order to maintain that, every contributor must be vigilant. | ||||
| 
 | ||||
| There have been many projects in the past that have been very lax regarding | ||||
| licensing. We are of the opinion that those are ticking timebombs and that no | ||||
| commercial product should depend on them. | ||||
| licensing, and we are of the opinion that those are ticking timebombs and that | ||||
| no commercial product should depend on them. | ||||
| 
 | ||||
| 
 | ||||
| # Required Reading | ||||
| 
 | ||||
| These are pretty short reads and emphasize the importance of proper licensing: | ||||
| 
 | ||||
| - https://github.com/jazzband/tablib/issues/114 (discussion of other tools) | ||||
| - https://github.com/kennethreitz/tablib/issues/114 (discussion of other tools) | ||||
| 
 | ||||
| - https://web.archive.org/web/20120615223756/http://www.codinghorror.com/blog/2007/04/pick-a-license-any-license.html | ||||
| - http://www.codinghorror.com/blog/2007/04/pick-a-license-any-license.html | ||||
| 
 | ||||
| 
 | ||||
| # Raising Issues | ||||
| @ -30,9 +30,10 @@ inbox is self-hosted. | ||||
| 
 | ||||
| # Opening Pull Requests | ||||
| 
 | ||||
| [Squash commits](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) | ||||
| before opening a pull request, If the pull request addresses documentation or | ||||
| demos, add `[ci skip]` in the body or title of the commit message to skip tests. | ||||
| 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 | ||||
| 
 | ||||
| @ -56,8 +57,8 @@ issue.  If it is a particularly high-priority issue, please drop an email to | ||||
| Keep these in mind as you work: | ||||
| 
 | ||||
| - Your contributions are your original work.  Take note of any resources you | ||||
|   consult in the process. Be extra careful not to use unlicensed code on the | ||||
|   Internet or code generated by a large language model or other AI tool. | ||||
|   consult in the process (and be extra careful not to use unlicensed code on | ||||
|   the internet. | ||||
| 
 | ||||
| - You are working on your own time.  Unless they explicitly grant permission, | ||||
|   your employer may be the ultimate owner of your IP | ||||
|  | ||||
							
								
								
									
										194
									
								
								Makefile
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										194
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| SHELL=/bin/bash | ||||
| LIB=xlsx | ||||
| FMT=xlsx xlsm xlsb ods xls xml misc full | ||||
| REQS= | ||||
| REQS=jszip.js | ||||
| ADDONS=dist/cpexcel.js | ||||
| AUXTARGETS= | ||||
| CMDS=bin/xlsx.njs | ||||
| @ -9,28 +9,22 @@ HTMLLINT=index.html | ||||
| 
 | ||||
| MINITGT=xlsx.mini.js | ||||
| MINIFLOW=xlsx.mini.flow.js | ||||
| MINIDEPS=$(shell cat misc/mini.lst) | ||||
| 
 | ||||
| ESMJSTGT=xlsx.mjs | ||||
| ESMJSDEPS=$(shell cat misc/mjs.lst) | ||||
| 
 | ||||
| MINIDEPS=$(shell cat mini.lst) | ||||
| 
 | ||||
| ULIB=$(shell echo $(LIB) | tr a-z A-Z) | ||||
| DEPS=$(sort $(wildcard bits/*.js)) | ||||
| TSBITS=$(patsubst modules/%,bits/%,$(wildcard modules/[0-9][0-9]_*.js)) | ||||
| MTSBITS=$(patsubst modules/%,misc/%,$(wildcard modules/[0-9][0-9]_*.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 | ||||
| # CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar
 | ||||
| 
 | ||||
| ## Main Targets
 | ||||
| 
 | ||||
| .PHONY: all | ||||
| all: $(TARGET) $(AUXTARGETS) $(AUXSCPTS) $(MINITGT) $(ESMJSTGT) ## Build library and auxiliary scripts
 | ||||
| all: $(TARGET) $(AUXTARGETS) $(AUXSCPTS) $(MINITGT) ## 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,""))' > $@ | ||||
| @ -41,25 +35,15 @@ $(FLOWTARGET): $(DEPS) | ||||
| $(MINIFLOW): $(MINIDEPS) | ||||
| 	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}'`"';" > $@ | ||||
| 
 | ||||
| #bits/18_cfb.js: node_modules/cfb/xlscfb.flow.js
 | ||||
| #	cp $^ $@
 | ||||
| 
 | ||||
| $(TSBITS): bits/%: modules/% | ||||
| bits/18_cfb.js: node_modules/cfb/xlscfb.flow.js | ||||
| 	cp $^ $@ | ||||
| 
 | ||||
| $(MTSBITS): misc/%: modules/% | ||||
| 	cp $^ $@ | ||||
| 
 | ||||
| 
 | ||||
| .PHONY: clean | ||||
| clean: ## Remove targets and build artifacts
 | ||||
| 	rm -f $(TARGET) $(FLOWTARGET) $(ESMJSTGT) $(MINITGT) $(MINIFLOW) | ||||
| 	rm -f $(TARGET) $(FLOWTARGET) | ||||
| 
 | ||||
| .PHONY: clean-data | ||||
| clean-data: | ||||
| @ -67,57 +51,50 @@ clean-data: | ||||
| 
 | ||||
| .PHONY: init | ||||
| init: ## Initial setup for development
 | ||||
| 	rm -rf test_files | ||||
| 	if [ ! -e test_files.zip ]; then curl -LO https://test-files.sheetjs.com/test_files.zip; fi | ||||
| 	unzip test_files.zip | ||||
| 	git submodule init | ||||
| 	git submodule update | ||||
| 	#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 LICENSE dist/ | ||||
| 	uglifyjs shim.js $(UGLIFYOPTS) -o dist/shim.min.js --preamble "$$(head -n 1 bits/00_header.js)" | ||||
| 	@# | ||||
| 	<$(TARGET) sed "s/require('.*')/undefined/g;s/ process / undefined /g;s/process.versions/({})/g" > dist/$(TARGET) | ||||
| 	<$(MINITGT) sed "s/require('.*')/undefined/g;s/ process / undefined /g;s/process.versions/({})/g" > dist/$(MINITGT) | ||||
| 	@# core | ||||
| 	uglifyjs $(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 $(DISTHDR) dist/$(TARGET) $(UGLIFYOPTS) -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)" | ||||
| 	misc/strip_sourcemap.sh dist/$(LIB).core.min.js | ||||
| 	@# full | ||||
| 	#cat <(head -n 1 bits/00_header.js) $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) > dist/$(LIB).full.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)" | ||||
| 	misc/strip_sourcemap.sh dist/$(LIB).full.min.js | ||||
| 	@# mini | ||||
| 	uglifyjs dist/$(MINITGT) $(UGLIFYOPTS) -o dist/$(LIB).mini.min.js --source-map dist/$(LIB).mini.min.map --preamble "$$(head -n 1 bits/00_header.js)" | ||||
| 	misc/strip_sourcemap.sh dist/$(LIB).mini.min.js | ||||
| 	@# extendscript | ||||
| 	cat <(printf '\xEF\xBB\xBF') <(head -n 1 bits/00_header.js) shim.js $(DISTHDR) $(REQS) dist/$(TARGET) > dist/$(LIB).extendscript.js | ||||
| 	@# zahl | ||||
| 	cp modules/xlsx.zahl.js modules/xlsx.zahl.mjs dist/ | ||||
| 	@# | ||||
| 	rm dist/$(TARGET) dist/$(MINITGT) | ||||
| 	cat <(head -n 1 bits/00_header.js) shim.js $(DISTHDR) $(REQS) dist/$(TARGET) > dist/$(LIB).extendscript.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) | ||||
| 
 | ||||
| BYTEFILEC=dist/xlsx.{full,core,mini}.min.js xlsx.mjs | ||||
| BYTEFILER=dist/xlsx.extendscript.js | ||||
| 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 $(BYTEFILEC); do npx printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done | ||||
| 	@for i in $(BYTEFILER); do npx printj "%-30s %7d" $$i $$(wc -c < $$i); done | ||||
| 	@npx printj "%-30s         %10d" "treeshake" "$$(npx -y esbuild@0.14.14 --bundle misc/import.js | wc -c)" | ||||
| 	for i in $(BYTEFILE); 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
 | ||||
| formats.png: formats.dot | ||||
| 	circo -Tpng -o$@ $< | ||||
| legend.png: misc/legend.dot | ||||
| 	dot -Tpng -o$@ $< | ||||
| 
 | ||||
| .PHONY: git | ||||
| git: ## show version string
 | ||||
| 	@echo "$$(node -pe 'require("./package.json").version')" | ||||
| 
 | ||||
| .PHONY: nexe | ||||
| nexe: xlsx.exe ## Build nexe standalone executable
 | ||||
| @ -139,60 +116,11 @@ test mocha: test.js ## Run test suite | ||||
| 
 | ||||
| #*                      To run tests for one format, make test_<fmt>
 | ||||
| #*                      To run the core test suite, make test_misc
 | ||||
| 
 | ||||
| .PHONY: testdot | ||||
| testdot: test.js ## Run test suite using dot reporter
 | ||||
| 	mocha -R dot -t 30000 | ||||
| 
 | ||||
| .PHONY: test-esm | ||||
| test-esm: test.mjs ## Run Node ESM test suite
 | ||||
| 	npx -y mocha@9 -R spec -t 30000 $< | ||||
| 
 | ||||
| test.ts: test.mts | ||||
| 	node -pe 'var data = fs.readFileSync("'$<'", "utf8"); data.split("\n").map(function(l) { return l.replace(/^describe\((.*?)function\(\)/, "Deno.test($$1async function(t)").replace(/\b(?:it|describe)\((.*?)function\(\)/g, "await t.step($$1async function(t)").replace("assert.ok", "assert.assert"); }).join("\n")' > $@ | ||||
| 
 | ||||
| .PHONY: test-bun | ||||
| test-bun: test.test.mjs ## Run Bun test suite
 | ||||
| 	bun test $< | ||||
| 
 | ||||
| .PHONY: test-deno | ||||
| test-deno: test.ts ## Run Deno test suite
 | ||||
| 	deno test --check --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $< | ||||
| 
 | ||||
| .PHONY: test-denocp | ||||
| test-denocp: testnocp.ts ## Run Deno test suite (without codepage)
 | ||||
| 	deno test --check --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $< | ||||
| 
 | ||||
| TESTFMT=$(patsubst %,test_%,$(FMT)) | ||||
| .PHONY: $(TESTFMT) | ||||
| $(TESTFMT): test_%: | ||||
| 	FMTS=$* make test | ||||
| 
 | ||||
| TESTFMT=$(patsubst %,testdot_%,$(FMT)) | ||||
| .PHONY: $(TESTFMT) | ||||
| $(TESTFMT): testdot_%: | ||||
| 	FMTS=$* make testdot | ||||
| 
 | ||||
| TESTESMFMT=$(patsubst %,test-esm_%,$(FMT)) | ||||
| .PHONY: $(TESTESMFMT) | ||||
| $(TESTESMFMT): test-esm_%: | ||||
| 	FMTS=$* make test-esm | ||||
| 
 | ||||
| TESTDENOFMT=$(patsubst %,test-deno_%,$(FMT)) | ||||
| .PHONY: $(TESTDENOFMT) | ||||
| $(TESTDENOFMT): test-deno_%: | ||||
| 	FMTS=$* make test-deno | ||||
| 
 | ||||
| TESTDENOCPFMT=$(patsubst %,test-denocp_%,$(FMT)) | ||||
| .PHONY: $(TESTDENOCPFMT) | ||||
| $(TESTDENOCPFMT): test-denocp_%: | ||||
| 	FMTS=$* make test-denocp | ||||
| 
 | ||||
| TESTBUNFMT=$(patsubst %,test-bun_%,$(FMT)) | ||||
| .PHONY: $(TESTBUNFMT) | ||||
| $(TESTBUNFMT): test-bun_%: | ||||
| 	FMTS=$* make test-bun | ||||
| 
 | ||||
| .PHONY: travis | ||||
| travis: ## Run test suite with minimal output
 | ||||
| 	mocha -R dot -t 30000 | ||||
| @ -203,7 +131,48 @@ ctest: ## Build browser test fixtures | ||||
| 
 | ||||
| .PHONY: ctestserv | ||||
| ctestserv: ## Start a test server on port 8000
 | ||||
| 	@cd tests && python -mSimpleHTTPServer || python3 -mhttp.server || npx -y http-server -p 8000 . | ||||
| 	@cd tests && python -mSimpleHTTPServer | ||||
| 
 | ||||
| ## Demos
 | ||||
| 
 | ||||
| DEMOS=angular angular-new browserify requirejs rollup systemjs webpack | ||||
| DEMOTGTS=$(patsubst %,demo-%,$(DEMOS)) | ||||
| .PHONY: demos | ||||
| demos: $(DEMOTGTS) | ||||
| 
 | ||||
| .PHONY: demo-angular | ||||
| 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 | ||||
| 	@echo "start a local server and go to demos/browserify/browserify.html" | ||||
| 
 | ||||
| .PHONY: demo-webpack | ||||
| demo-webpack: ## Run webpack demo build
 | ||||
| 	make -C demos/webpack | ||||
| 	@echo "start a local server and go to demos/webpack/webpack.html" | ||||
| 
 | ||||
| .PHONY: demo-requirejs | ||||
| demo-requirejs: ## Run requirejs demo build
 | ||||
| 	make -C demos/requirejs | ||||
| 	@echo "start a local server and go to demos/requirejs/requirejs.html" | ||||
| 
 | ||||
| .PHONY: demo-rollup | ||||
| demo-rollup: ## Run rollup demo build
 | ||||
| 	make -C demos/rollup | ||||
| 	@echo "start a local server and go to demos/rollup/rollup.html" | ||||
| 
 | ||||
| .PHONY: demo-systemjs | ||||
| demo-systemjs: ## Run systemjs demo build
 | ||||
| 	make -C demos/systemjs | ||||
| 
 | ||||
| ## Code Checking
 | ||||
| 
 | ||||
| @ -212,17 +181,17 @@ 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 $(FLOWTARGET) $(AUXTARGETS) $(CMDS) $(HTMLLINT) package.json bower.json | ||||
| 	@if [ -x "$(CLOSURE)" ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi | ||||
| 	@./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 | ||||
| 
 | ||||
| .PHONY: old-lint | ||||
| old-lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
 | ||||
| 	@./node_modules/.bin/jscs $(TARGET) $(AUXTARGETS) test.js | ||||
| 	@./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) | ||||
| 	@if [ -x "$(CLOSURE)" ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi | ||||
| 	@./node_modules/.bin/jscs $(TARGET) $(AUXTARGETS) test.js | ||||
| 	if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi | ||||
| 
 | ||||
| .PHONY: tslint | ||||
| tslint: $(TARGET) ## Run typescript checks
 | ||||
| @ -234,10 +203,6 @@ tslint: $(TARGET) ## Run typescript checks | ||||
| flow: lint ## Run flow checker
 | ||||
| 	@./node_modules/.bin/flow check --all --show-all-errors --include-warnings | ||||
| 
 | ||||
| .PHONY: mjslint | ||||
| mjslint: $(ESMJSTGT) ## Lint the ESM build
 | ||||
| 	@npx eslint -c .eslintmjs $< | ||||
| 
 | ||||
| .PHONY: cov | ||||
| cov: misc/coverage.html ## Run coverage test
 | ||||
| 
 | ||||
| @ -254,7 +219,22 @@ misc/coverage.html: $(TARGET) test.js | ||||
| coveralls: ## Coverage Test + Send to coveralls.io
 | ||||
| 	mocha --require blanket --reporter mocha-lcov-reporter -t 30000 | node ./node_modules/coveralls/bin/coveralls.js | ||||
| 
 | ||||
| MDLINT=README.md | ||||
| READEPS=$(sort $(wildcard docbits/*.md)) | ||||
| README.md: $(READEPS) | ||||
| 	awk 'FNR==1{p=0}/#/{p=1}p' $^ | tr -d '\15\32' > $@ | ||||
| 
 | ||||
| .PHONY: readme | ||||
| readme: README.md ## Update README Table of Contents
 | ||||
| 	markdown-toc -i README.md | ||||
| 
 | ||||
| .PHONY: book | ||||
| book: readme graph ## Update summary for documentation
 | ||||
| 	printf "# Summary\n\n- [xlsx](README.md#sheetjs-js-xlsx)\n" > misc/docs/SUMMARY.md | ||||
| 	markdown-toc README.md | sed 's/(#/(README.md#/g'>> misc/docs/SUMMARY.md | ||||
| 	<README.md grep -vE "(details|summary)>" > 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 $^ | ||||
|  | ||||
							
								
								
									
										37
									
								
								bin/xlsx.njs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										37
									
								
								bin/xlsx.njs
									
									
									
									
									
								
							| @ -5,21 +5,8 @@ | ||||
| var n = "xlsx"; | ||||
| var X = require('../'); | ||||
| try { X = require('../xlsx.flow'); } catch(e) {} | ||||
| try { require('exit-on-epipe'); } catch(e) {} | ||||
| var fs = require('fs'), program; | ||||
| try { program = require('commander'); } catch(e) { | ||||
| 	[ | ||||
| 		"The `xlsx` command line tool is deprecated in favor of `xlsx-cli`.", | ||||
| 		"", | ||||
| 		"For new versions of node, we recommend using `npx`:", | ||||
| 		"    $ npx xlsx-cli --help", | ||||
| 		"", | ||||
| 		"For older versions of node, explicitly install `xlsx-cli` globally:", | ||||
| 		"    $ npm i -g xlsx-cli", | ||||
| 		"    $ xlsx-cli --help" | ||||
| 	].forEach(function(m) { console.error(m); }); | ||||
| 	process.exit(1); | ||||
| } | ||||
| require('exit-on-epipe'); | ||||
| var fs = require('fs'), program = require('commander'); | ||||
| program | ||||
| 	.version(X.version) | ||||
| 	.usage('[options] <file> [sheetname]') | ||||
| @ -37,14 +24,12 @@ program | ||||
| 	.option('-Y, --ods',  'emit ODS  to <sheetname> or <file>.ods') | ||||
| 	.option('-8, --xls',  'emit XLS  to <sheetname> or <file>.xls (BIFF8)') | ||||
| 	.option('-5, --biff5','emit XLS  to <sheetname> or <file>.xls (BIFF5)') | ||||
| 	.option('-4, --biff4','emit XLS  to <sheetname> or <file>.xls (BIFF4)') | ||||
| 	.option('-3, --biff3','emit XLS  to <sheetname> or <file>.xls (BIFF3)') | ||||
| 	//.option('-4, --biff4','emit XLS  to <sheetname> or <file>.xls (BIFF4)') | ||||
| 	//.option('-3, --biff3','emit XLS  to <sheetname> or <file>.xls (BIFF3)') | ||||
| 	.option('-2, --biff2','emit XLS  to <sheetname> or <file>.xls (BIFF2)') | ||||
| 	.option('-i, --xla',  'emit XLA to <sheetname> or <file>.xla') | ||||
| 	.option('-6, --xlml', 'emit SSML to <sheetname> or <file>.xls (2003 XML)') | ||||
| 	.option('-T, --fods', 'emit FODS to <sheetname> or <file>.fods (Flat ODS)') | ||||
| 	.option('--wk3',      'emit WK3  to <sheetname> or <file>.txt (Lotus WK3)') | ||||
| 	.option('--numbers',  'emit NUMBERS to <sheetname> or <file>.numbers') | ||||
| 
 | ||||
| 	.option('-S, --formulae', 'emit list of values and formulae') | ||||
| 	.option('-j, --json',     'emit formatted JSON (all fields text)') | ||||
| @ -58,7 +43,6 @@ program | ||||
| 	.option('-E, --eth',  'emit ETH  to <sheetname> or <file>.eth (Ethercalc)') | ||||
| 	.option('-t, --txt',  'emit TXT  to <sheetname> or <file>.txt (UTF-8 TSV)') | ||||
| 	.option('-r, --rtf',  'emit RTF  to <sheetname> or <file>.txt (Table RTF)') | ||||
| 	.option('--wk1',      'emit WK1  to <sheetname> or <file>.txt (Lotus WK1)') | ||||
| 	.option('-z, --dump', 'dump internal representation as JSON') | ||||
| 	.option('--props',    'dump workbook properties as CSV') | ||||
| 
 | ||||
| @ -91,10 +75,8 @@ var workbook_formats = [ | ||||
| 	['xls',     'xls',  'xls'], | ||||
| 	['xla',     'xla',  'xla'], | ||||
| 	['biff5', 'biff5',  'xls'], | ||||
| 	['numbers', 'numbers', 'numbers'], | ||||
| 	['ods',     'ods',  'ods'], | ||||
| 	['fods',   'fods', 'fods'], | ||||
| 	['wk3',     'wk3',  'wk3'] | ||||
| 	['fods',   'fods', 'fods'] | ||||
| ]; | ||||
| var wb_formats_2 = [ | ||||
| 	['xlml',   'xlml', 'xls'] | ||||
| @ -131,7 +113,6 @@ function wb_fmt() { | ||||
| 	seen = true; | ||||
| 	opts.cellFormula = true; | ||||
| 	opts.cellNF = true; | ||||
| 	opts.xlfn = true; | ||||
| 	if(program.output) sheetname = program.output; | ||||
| } | ||||
| function isfmt(m/*:string*/)/*:boolean*/ { | ||||
| @ -156,7 +137,6 @@ if(program.all) { | ||||
| 	opts.cellStyles = true; | ||||
| 	opts.sheetStubs = true; | ||||
| 	opts.cellDates = true; | ||||
| 	wopts.cellFormula = true; | ||||
| 	wopts.cellStyles = true; | ||||
| 	wopts.sheetStubs = true; | ||||
| 	wopts.bookVBA = true; | ||||
| @ -194,10 +174,6 @@ if(program.props) { | ||||
| /* full workbook formats */ | ||||
| workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { | ||||
| 		wopts.bookType = m[1]; | ||||
| 		if(wopts.bookType == "numbers") try { | ||||
| 			var XLSX_ZAHL = require("../dist/xlsx.zahl"); | ||||
| 			wopts.numbers = XLSX_ZAHL; | ||||
| 		} catch(e) {} | ||||
| 		if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts); | ||||
| 		process.exit(0); | ||||
| } }); | ||||
| @ -240,7 +216,6 @@ if(!program.quiet && !program.book) console.error(target_sheet); | ||||
| 	['rtf', '.rtf'], | ||||
| 	['txt', '.txt'], | ||||
| 	['dbf', '.dbf'], | ||||
| 	['wk1', '.wk1'], | ||||
| 	['dif', '.dif'] | ||||
| ].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) { | ||||
| 	wopts.bookType = m[0]; | ||||
| @ -281,7 +256,7 @@ switch(true) { | ||||
| 
 | ||||
| 	default: | ||||
| 		if(!program.book) { | ||||
| 			var stream = X.stream.to_csv(ws, {FS:program.fieldSep||",", RS:program.rowSep||"\n"}); | ||||
| 			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}); }); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| /*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /* vim: set ts=2: */ | ||||
| /*exported XLSX */ | ||||
| /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Set:false, Float32Array:false */ | ||||
| /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ | ||||
| var XLSX = {}; | ||||
| function make_xlsx_lib(XLSX){ | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| XLSX.version = '0.20.3'; | ||||
| XLSX.version = '0.17.0'; | ||||
|  | ||||
| @ -1,31 +1,37 @@ | ||||
| var current_codepage = 1200, current_ansi = 1252; | ||||
| /*:: declare var cptable:any; */ | ||||
| /*global cptable:true, window */ | ||||
| var $cptable; | ||||
| 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, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 10000 ]; | ||||
| 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 */ | ||||
| 	/*::[*/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; }; | ||||
| @ -41,11 +47,6 @@ function utf16leread(data/*:string*/)/*:string*/ { | ||||
| 	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 utf16lereadu(data/*:Uint8Array*/)/*:string*/ { | ||||
| 	var o/*:Array<string>*/ = []; | ||||
| 	for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data[2*i] + (data[2*i+1]<<8)); | ||||
| 	return o.join(""); | ||||
| } | ||||
| function utf16beread(data/*:string*/)/*:string*/ { | ||||
| 	var o/*:Array<string>*/ = []; | ||||
| 	for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i+1) + (data.charCodeAt(2*i)<<8)); | ||||
| @ -62,20 +63,17 @@ var debom = function(data/*:string*/)/*:string*/ { | ||||
| 
 | ||||
| var _getchar = function _gc1(x/*:number*/)/*:string*/ { return String.fromCharCode(x); }; | ||||
| var _getansi = function _ga1(x/*:number*/)/*:string*/ { return String.fromCharCode(x); }; | ||||
| 
 | ||||
| function set_cptable(cptable) { | ||||
| 	$cptable = cptable; | ||||
| 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))); } | ||||
| 		if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.slice(2))); } | ||||
| 		return data; | ||||
| 	}; | ||||
| 	_getchar = function _gc2(x/*:number*/)/*:string*/ { | ||||
| 		if(current_codepage === 1200) return String.fromCharCode(x); | ||||
| 		return $cptable.utils.decode(current_codepage, [x&255,x>>8])[0]; | ||||
| 		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]; | ||||
| 		return cptable.utils.decode(current_ansi, [x])[0]; | ||||
| 	}; | ||||
| 	cpdoit(); | ||||
| } | ||||
|  | ||||
| @ -1,94 +1,44 @@ | ||||
| var Base64_map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | ||||
| function Base64_encode(input) { | ||||
|   var o = ""; | ||||
|   var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; | ||||
|   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; | ||||
|     if (isNaN(c2)) { | ||||
|       e3 = e4 = 64; | ||||
|     } else if (isNaN(c3)) { | ||||
|       e4 = 64; | ||||
|     } | ||||
|     o += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function Base64_encode_pass(input) { | ||||
|   var o = ""; | ||||
|   var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; | ||||
|   for (var i = 0; i < input.length; ) { | ||||
|     c1 = input.charCodeAt(i++); | ||||
|     if (c1 > 255) | ||||
|       c1 = 95; | ||||
|     e1 = c1 >> 2; | ||||
|     c2 = input.charCodeAt(i++); | ||||
|     if (c2 > 255) | ||||
|       c2 = 95; | ||||
|     e2 = (c1 & 3) << 4 | c2 >> 4; | ||||
|     c3 = input.charCodeAt(i++); | ||||
|     if (c3 > 255) | ||||
|       c3 = 95; | ||||
|     e3 = (c2 & 15) << 2 | c3 >> 6; | ||||
|     e4 = c3 & 63; | ||||
|     if (isNaN(c2)) { | ||||
|       e3 = e4 = 64; | ||||
|     } else if (isNaN(c3)) { | ||||
|       e4 = 64; | ||||
|     } | ||||
|     o += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function Base64_encode_arr(input) { | ||||
|   var o = ""; | ||||
|   var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; | ||||
|   for (var i = 0; i < input.length; ) { | ||||
|     c1 = input[i++]; | ||||
|     e1 = c1 >> 2; | ||||
|     c2 = input[i++]; | ||||
|     e2 = (c1 & 3) << 4 | c2 >> 4; | ||||
|     c3 = input[i++]; | ||||
|     e3 = (c2 & 15) << 2 | c3 >> 6; | ||||
|     e4 = c3 & 63; | ||||
|     if (isNaN(c2)) { | ||||
|       e3 = e4 = 64; | ||||
|     } else if (isNaN(c3)) { | ||||
|       e4 = 64; | ||||
|     } | ||||
|     o += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function Base64_decode(input) { | ||||
|   var o = ""; | ||||
|   var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; | ||||
|   if (input.slice(0, 5) == "data:") { | ||||
|     var i = input.slice(0, 1024).indexOf(";base64,"); | ||||
|     if (i > -1) | ||||
|       input = input.slice(i + 8); | ||||
|   } | ||||
|   input = input.replace(/[^\w\+\/\=]/g, ""); | ||||
|   for (var i = 0; i < input.length; ) { | ||||
|     e1 = Base64_map.indexOf(input.charAt(i++)); | ||||
|     e2 = Base64_map.indexOf(input.charAt(i++)); | ||||
|     c1 = e1 << 2 | e2 >> 4; | ||||
|     o += String.fromCharCode(c1); | ||||
|     e3 = Base64_map.indexOf(input.charAt(i++)); | ||||
|     c2 = (e2 & 15) << 4 | e3 >> 2; | ||||
|     if (e3 !== 64) { | ||||
|       o += String.fromCharCode(c2); | ||||
|     } | ||||
|     e4 = Base64_map.indexOf(input.charAt(i++)); | ||||
|     c3 = (e3 & 3) << 6 | e4; | ||||
|     if (e4 !== 64) { | ||||
|       o += String.fromCharCode(c3); | ||||
|     } | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| var Base64 = (function make_b64(){ | ||||
| 	var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | ||||
| 	return { | ||||
| 		encode: function(input/*:string*/)/*:string*/ { | ||||
| 			var o = ""; | ||||
| 			var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; | ||||
| 			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); | ||||
| 				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); | ||||
| 			} | ||||
| 			return o; | ||||
| 		}, | ||||
| 		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, ""); | ||||
| 			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); } | ||||
| 			} | ||||
| 			return o; | ||||
| 		} | ||||
| 	}; | ||||
| })(); | ||||
|  | ||||
| @ -1,33 +1,26 @@ | ||||
| var has_buf = /*#__PURE__*/(function() { return typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node; })(); | ||||
| var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node); | ||||
| 
 | ||||
| var Buffer_from = /*#__PURE__*/(function() { | ||||
| 	if(typeof Buffer !== 'undefined') { | ||||
| 		var nbfs = !Buffer.from; | ||||
| 		if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; } | ||||
| 		return nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer); | ||||
| 	} | ||||
| 	return function() {}; | ||||
| })(); | ||||
| var buf_utf16le = /*#__PURE__*/(function() { | ||||
| 	if(typeof Buffer === 'undefined') return false; | ||||
| 	var x = Buffer_from([65,0]); | ||||
| 	if(!x) return false; | ||||
| 	var o = x.toString("utf16le"); | ||||
| 	return o.length == 1; | ||||
| })(); | ||||
| 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); }; | ||||
| } | ||||
| 
 | ||||
| function new_raw_buf(len/*:number*/) { | ||||
| 	/* jshint -W056 */ | ||||
| 	if(has_buf) return Buffer.alloc ? Buffer.alloc(len) : new Buffer(len); | ||||
| 	return typeof Uint8Array != "undefined" ? new Uint8Array(len) : new Array(len); | ||||
| 	return has_buf ? Buffer.alloc(len) : new Array(len); | ||||
| 	/* jshint +W056 */ | ||||
| } | ||||
| 
 | ||||
| function new_unsafe_buf(len/*:number*/) { | ||||
| 	/* jshint -W056 */ | ||||
| 	if(has_buf) return Buffer.allocUnsafe ? Buffer.allocUnsafe(len) : new Buffer(len); | ||||
| 	return typeof Uint8Array != "undefined" ? new Uint8Array(len) : new Array(len); | ||||
| 	return has_buf ? Buffer.allocUnsafe(len) : new Array(len); | ||||
| 	/* jshint +W056 */ | ||||
| } | ||||
| 
 | ||||
| @ -62,53 +55,6 @@ function ab2a(data/*:ArrayBuffer|Uint8Array*/)/*:Array<number>*/ { | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| var bconcat = has_buf ? function(bufs) { return Buffer.concat(bufs.map(function(buf) { return Buffer.isBuffer(buf) ? buf : Buffer_from(buf); })); } : function(bufs) { | ||||
| 	if(typeof Uint8Array !== "undefined") { | ||||
| 		var i = 0, maxlen = 0; | ||||
| 		for(i = 0; i < bufs.length; ++i) maxlen += bufs[i].length; | ||||
| 		var o = new Uint8Array(maxlen); | ||||
| 		var len = 0; | ||||
| 		for(i = 0, maxlen = 0; i < bufs.length; maxlen += len, ++i) { | ||||
| 			len = bufs[i].length; | ||||
| 			if(bufs[i] instanceof Uint8Array) o.set(bufs[i], maxlen); | ||||
| 			else if(typeof bufs[i] == "string") o.set(new Uint8Array(s2a(bufs[i])), maxlen); | ||||
| 			else o.set(new Uint8Array(bufs[i]), maxlen); | ||||
| 		} | ||||
| 		return o; | ||||
| 	} | ||||
| 	return [].concat.apply([], bufs.map(function(buf) { return Array.isArray(buf) ? buf : [].slice.call(buf); })); | ||||
| }; | ||||
| 
 | ||||
| function utf8decode(content/*:string*/) { | ||||
| 	var out = [], widx = 0, L = content.length + 250; | ||||
| 	var o = new_raw_buf(content.length + 255); | ||||
| 	for(var ridx = 0; ridx < content.length; ++ridx) { | ||||
| 		var c = content.charCodeAt(ridx); | ||||
| 		if(c < 0x80) o[widx++] = c; | ||||
| 		else if(c < 0x800) { | ||||
| 			o[widx++] = (192|((c>>6)&31)); | ||||
| 			o[widx++] = (128|(c&63)); | ||||
| 		} else if(c >= 0xD800 && c < 0xE000) { | ||||
| 			c = (c&1023)+64; | ||||
| 			var d = content.charCodeAt(++ridx)&1023; | ||||
| 			o[widx++] = (240|((c>>8)&7)); | ||||
| 			o[widx++] = (128|((c>>2)&63)); | ||||
| 			o[widx++] = (128|((d>>6)&15)|((c&3)<<4)); | ||||
| 			o[widx++] = (128|(d&63)); | ||||
| 		} else { | ||||
| 			o[widx++] = (224|((c>>12)&15)); | ||||
| 			o[widx++] = (128|((c>>6)&63)); | ||||
| 			o[widx++] = (128|(c&63)); | ||||
| 		} | ||||
| 		if(widx > L) { | ||||
| 			out.push(o.slice(0, widx)); | ||||
| 			widx = 0; | ||||
| 			o = new_raw_buf(65535); | ||||
| 			L = 65530; | ||||
| 		} | ||||
| 	} | ||||
| 	out.push(o.slice(0, widx)); | ||||
| 	return bconcat(out); | ||||
| } | ||||
| var bconcat = function(bufs) { return [].concat.apply([], bufs); }; | ||||
| 
 | ||||
| var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g; | ||||
|  | ||||
| @ -15,4 +15,5 @@ type EvertArrType = {[string]:Array<string>}; | ||||
| 
 | ||||
| type StringConv = {(string):string}; | ||||
| 
 | ||||
| type WriteObjStrFactory = {from_sheet(ws:Worksheet, o:any, wb:?Workbook):string}; | ||||
| */ | ||||
|  | ||||
							
								
								
									
										372
									
								
								bits/10_ssf.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										372
									
								
								bits/10_ssf.js
									
									
									
									
									
								
							| @ -1,15 +1,21 @@ | ||||
| /* 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'; | ||||
| 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;} | ||||
| function pad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;} | ||||
| function rpad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);} | ||||
| function pad0r1(v/*:any*/,d/*:number*/)/*:string*/{var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| var p2_32 = /*#__PURE__*/Math.pow(2,32); | ||||
| 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); } | ||||
| /* yes, in 2022 this is still faster than string compare */ | ||||
| function SSF_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; } | ||||
| 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}; | ||||
| */ | ||||
| var days/*:Array<Array<string> >*/ = [ | ||||
| 	['Sun', 'Sunday'], | ||||
| 	['Mon', 'Monday'], | ||||
| @ -33,8 +39,7 @@ var months/*:Array<Array<string> >*/ = [ | ||||
| 	['N', 'Nov', 'November'], | ||||
| 	['D', 'Dec', 'December'] | ||||
| ]; | ||||
| function SSF_init_table(t/*:any*/) { | ||||
| 	if(!t) t = {}; | ||||
| function init_table(t/*:any*/) { | ||||
| 	t[0]=  'General'; | ||||
| 	t[1]=  '0'; | ||||
| 	t[2]=  '0.00'; | ||||
| @ -64,96 +69,66 @@ function SSF_init_table(t/*:any*/) { | ||||
| 	t[48]= '##0.0E+0'; | ||||
| 	t[49]= '@'; | ||||
| 	t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "'; | ||||
| 	return t; | ||||
| } | ||||
| /* repeated to satiate webpack */ | ||||
| var table_fmt = { | ||||
| 	0:  'General', | ||||
| 	1:  '0', | ||||
| 	2:  '0.00', | ||||
| 	3:  '#,##0', | ||||
| 	4:  '#,##0.00', | ||||
| 	9:  '0%', | ||||
| 	10: '0.00%', | ||||
| 	11: '0.00E+00', | ||||
| 	12: '# ?/?', | ||||
| 	13: '# ??/??', | ||||
| 	14: 'm/d/yy', | ||||
| 	15: 'd-mmm-yy', | ||||
| 	16: 'd-mmm', | ||||
| 	17: 'mmm-yy', | ||||
| 	18: 'h:mm AM/PM', | ||||
| 	19: 'h:mm:ss AM/PM', | ||||
| 	20: 'h:mm', | ||||
| 	21: 'h:mm:ss', | ||||
| 	22: 'm/d/yy h:mm', | ||||
| 	37: '#,##0 ;(#,##0)', | ||||
| 	38: '#,##0 ;[Red](#,##0)', | ||||
| 	39: '#,##0.00;(#,##0.00)', | ||||
| 	40: '#,##0.00;[Red](#,##0.00)', | ||||
| 	45: 'mm:ss', | ||||
| 	46: '[h]:mm:ss', | ||||
| 	47: 'mmss.0', | ||||
| 	48: '##0.0E+0', | ||||
| 	49: '@', | ||||
| 	56: '"上午/下午 "hh"時"mm"分"ss"秒 "' | ||||
| }; | ||||
| 
 | ||||
| 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 SSF_default_map = { | ||||
| 	5:  37, 6:  38, 7:  39, 8:  40,         //  5 -> 37 ...  8 -> 40
 | ||||
| var default_map/*:Array<number>*/ = []; | ||||
| var defi = 0; | ||||
| 
 | ||||
| 	23:  0, 24:  0, 25:  0, 26:  0,         // 23 ->  0 ... 26 ->  0
 | ||||
| //  5 -> 37 ...  8 -> 40
 | ||||
| for(defi = 5; defi <= 8; ++defi) default_map[defi] = 32 + defi; | ||||
| 
 | ||||
| 	27: 14, 28: 14, 29: 14, 30: 14, 31: 14, // 27 -> 14 ... 31 -> 14
 | ||||
| // 23 ->  0 ... 26 ->  0
 | ||||
| for(defi = 23; defi <= 26; ++defi) default_map[defi] = 0; | ||||
| 
 | ||||
| 	50: 14, 51: 14, 52: 14, 53: 14, 54: 14, // 50 -> 14 ... 58 -> 14
 | ||||
| 	55: 14, 56: 14, 57: 14, 58: 14, | ||||
| 	59:  1, 60:  2, 61:  3, 62:  4,         // 59 ->  1 ... 62 ->  4
 | ||||
| // 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; | ||||
| 
 | ||||
| 	67:  9, 68: 10,                         // 67 ->  9 ... 68 -> 10
 | ||||
| 	69: 12, 70: 13, 71: 14,                 // 69 -> 12 ... 71 -> 14
 | ||||
| 	72: 14, 73: 15, 74: 16, 75: 17,         // 72 -> 14 ... 75 -> 17
 | ||||
| 	76: 20, 77: 21, 78: 22,                 // 76 -> 20 ... 78 -> 22
 | ||||
| 	79: 45, 80: 46, 81: 47,                 // 79 -> 45 ... 81 -> 47
 | ||||
| 	82: 0                                   // 82 ->  0 ... 65536 -> 0 (omitted)
 | ||||
| }; | ||||
| // 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 SSF_default_str = { | ||||
| 	//  5 -- Currency,   0 decimal, black negative
 | ||||
| 	5:  '"$"#,##0_);\\("$"#,##0\\)', | ||||
| 	63: '"$"#,##0_);\\("$"#,##0\\)', | ||||
| var default_str/*:Array<string>*/ = []; | ||||
| 
 | ||||
| 	//  6 -- Currency,   0 decimal, red   negative
 | ||||
| 	6:  '"$"#,##0_);[Red]\\("$"#,##0\\)', | ||||
| 	64: '"$"#,##0_);[Red]\\("$"#,##0\\)', | ||||
| //  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\\)'; | ||||
| 
 | ||||
| 	//  7 -- Currency,   2 decimal, black negative
 | ||||
| 	7:  '"$"#,##0.00_);\\("$"#,##0.00\\)', | ||||
| 	65: '"$"#,##0.00_);\\("$"#,##0.00\\)', | ||||
| 
 | ||||
| 	//  8 -- Currency,   2 decimal, red   negative
 | ||||
| 	8:  '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)', | ||||
| 	66: '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)', | ||||
| 
 | ||||
| 	// 41 -- Accounting, 0 decimal, No Symbol
 | ||||
| 	41: '_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)', | ||||
| 
 | ||||
| 	// 42 -- Accounting, 0 decimal, $  Symbol
 | ||||
| 	42: '_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)', | ||||
| 
 | ||||
| 	// 43 -- Accounting, 2 decimal, No Symbol
 | ||||
| 	43: '_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)', | ||||
| 
 | ||||
| 	// 44 -- Accounting, 2 decimal, $  Symbol
 | ||||
| 	44: '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)' | ||||
| }; | ||||
| 
 | ||||
| function SSF_frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/ { | ||||
| // 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<number>*/ { | ||||
| 	var sgn = x < 0 ? -1 : 1; | ||||
| 	var B = x * sgn; | ||||
| 	var P_2 = 0, P_1 = 1, P = 0; | ||||
| @ -173,20 +148,8 @@ function SSF_frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number | ||||
| 	var q = Math.floor(sgn * P/Q); | ||||
| 	return [q, sgn*P - q*Q, Q]; | ||||
| } | ||||
| function SSF_normalize_xl_unsafe(v/*:number*/)/*:number*/ { | ||||
| 	var s = v.toPrecision(16); | ||||
| 	if(s.indexOf("e") > -1) { | ||||
| 		var m = s.slice(0, s.indexOf("e")); | ||||
| 		m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15)); | ||||
| 		return m + s.slice(s.indexOf("e")); | ||||
| 	} | ||||
| 	var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15)); | ||||
| 	return Number(n); | ||||
| } | ||||
| 
 | ||||
| function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) { | ||||
| function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) { | ||||
| 	if(v > 2958465 || v < 0) return null; | ||||
| 	v = SSF_normalize_xl_unsafe(v); | ||||
| 	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}; | ||||
| @ -206,7 +169,7 @@ function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) { | ||||
| 		dout = [d.getFullYear(), d.getMonth()+1,d.getDate()]; | ||||
| 		dow = d.getDay(); | ||||
| 		if(date < 60) dow = (dow + 6) % 7; | ||||
| 		if(b2) dow = SSF_fix_hijri(d, dout); | ||||
| 		if(b2) dow = fix_hijri(d, dout); | ||||
| 	} | ||||
| 	out.y = dout[0]; out.m = dout[1]; out.d = dout[2]; | ||||
| 	out.S = time % 60; time = Math.floor(time / 60); | ||||
| @ -215,45 +178,64 @@ function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) { | ||||
| 	out.q = dow; | ||||
| 	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 */ | ||||
| /* exponent >= -9 and <= 9 */ | ||||
| function SSF_strip_decimal(o/*:string*/)/*:string*/ { | ||||
| 	return (o.indexOf(".") == -1) ? o : o.replace(/(?:\.0*|(\.\d*[1-9])0+)$/, "$1"); | ||||
| } | ||||
| 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 */ | ||||
| function SSF_normalize_exp(o/*:string*/)/*:string*/ { | ||||
| 	if(o.indexOf("E") == -1) return o; | ||||
| 	return o.replace(/(?:\.0*|(\.\d*[1-9])0+)[Ee]/,"$1E").replace(/(E[+-])(\d)$/,"$10$2"); | ||||
| } | ||||
| 	/* 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 SSF_small_exp(v/*:number*/)/*:string*/ { | ||||
| 	var w = (v<0?12:11); | ||||
| 	var o = SSF_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 >= -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 SSF_large_exp(v/*:number*/)/*:string*/ { | ||||
| 	var o = SSF_strip_decimal(v.toFixed(11)); | ||||
| 	return (o.length > (v<0?12:11) || o === "0" || o === "-0") ? v.toPrecision(6) : o; | ||||
| } | ||||
| 	/* 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 SSF_general_num(v/*:number*/)/*:string*/ { | ||||
| 	if(!isFinite(v)) return isNaN(v) ? "#NUM!" : "#DIV/0!"; | ||||
| 	var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), 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 = SSF_small_exp(v); | ||||
| 	else if(V === 10) o = v.toFixed(10).substr(0,12); | ||||
| 	else o = SSF_large_exp(v); | ||||
| 		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 SSF_strip_decimal(SSF_normalize_exp(o.toUpperCase())); | ||||
| } | ||||
| 		return strip_decimal(normalize_exp(o.toUpperCase())); | ||||
| 	} | ||||
| 
 | ||||
| 	return general_fmt_num_base; | ||||
| })(); | ||||
| SSF._general_num = general_fmt_num; | ||||
| 
 | ||||
| /* | ||||
| 	"General" rules: | ||||
| @ -262,23 +244,22 @@ function SSF_general_num(v/*:number*/)/*:string*/ { | ||||
| 	- "up to 11 characters" displayed for numbers | ||||
| 	- Default date format (code 14) used for Dates | ||||
| 
 | ||||
| 	The longest 32-bit integer text is "-2147483648", exactly 11 chars | ||||
| 	TODO: technically the display depends on the width of the cell | ||||
| */ | ||||
| function SSF_general(v/*:any*/, opts/*:any*/) { | ||||
| 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) : SSF_general_num(v); | ||||
| 		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 SSF_format(14, datenum(v, opts && opts.date1904), opts); | ||||
| 			if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts); | ||||
| 	} | ||||
| 	throw new Error("unsupported value in General format: " + v); | ||||
| } | ||||
| 
 | ||||
| function SSF_fix_hijri(date/*:Date*/, o/*:[number, number, number]*/) { | ||||
| 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(); | ||||
| @ -286,7 +267,8 @@ function SSF_fix_hijri(date/*:Date*/, o/*:[number, number, number]*/) { | ||||
|   return dow; | ||||
| } | ||||
| //var THAI_DIGITS = "\u0E50\u0E51\u0E52\u0E53\u0E54\u0E55\u0E56\u0E57\u0E58\u0E59".split("");
 | ||||
| function SSF_write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ { | ||||
| /*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; | ||||
| 	switch(type) { | ||||
| 		case 98: /* 'b' buddhist year */ | ||||
| @ -341,7 +323,7 @@ function SSF_write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/* | ||||
| 		switch(fmt) { | ||||
| 			case '[h]': case '[hh]': out = val.D*24+val.H; break; | ||||
| 			case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break; | ||||
| 			case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break; | ||||
| 			case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break; | ||||
| 			default: throw 'bad abstime format: ' + fmt; | ||||
| 		} outl = fmt.length === 3 ? 1 : 2; break; | ||||
| 		case 101: /* 'e' era */ | ||||
| @ -350,9 +332,6 @@ function SSF_write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/* | ||||
| 	var outstr = outl > 0 ? pad0(out, outl) : ""; | ||||
| 	return outstr; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*jshint -W086 */ | ||||
| /*jshint +W086 */ | ||||
| function commaify(s/*:string*/)/*:string*/ { | ||||
| 	var w = 3; | ||||
| @ -361,18 +340,17 @@ function commaify(s/*:string*/)/*:string*/ { | ||||
| 	for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w); | ||||
| 	return o; | ||||
| } | ||||
| var write_num/*:SSF_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; | ||||
| 	return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul); | ||||
| } | ||||
| 
 | ||||
| function write_num_cm(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{ | ||||
| 	var idx = fmt.length - 1; | ||||
| 	while(fmt.charCodeAt(idx-1) === 44) --idx; | ||||
| 	return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx))); | ||||
| } | ||||
| 
 | ||||
| function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{ | ||||
| 	var o/*:string*/; | ||||
| 	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1; | ||||
| @ -409,7 +387,7 @@ function write_num_f2(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:s | ||||
| 	return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length); | ||||
| } | ||||
| var dec1 = /^#*0*\.([0#]+)/; | ||||
| var closeparen = /\)[^)]*[0#]/; | ||||
| var closeparen = /\).*[0#]/; | ||||
| var phone = /\(###\) ###\\?-####/; | ||||
| function hashq(str/*:string*/)/*:string*/ { | ||||
| 	var o = "", cc; | ||||
| @ -481,7 +459,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string | ||||
| 	var oa = ""; | ||||
| 	if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) { | ||||
| 		ri = Math.min(/*::String(*/r[4]/*::)*/.length,7); | ||||
| 		ff = SSF_frac(aval, Math.pow(10,ri)-1, false); | ||||
| 		ff = frac(aval, Math.pow(10,ri)-1, false); | ||||
| 		o = "" + sign; | ||||
| 		oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]); | ||||
| 		if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0"; | ||||
| @ -493,7 +471,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string | ||||
| 	} | ||||
| 	if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) { | ||||
| 		ri = Math.min(Math.max(r[1].length, r[4].length),7); | ||||
| 		ff = SSF_frac(aval, Math.pow(10,ri)-1, true); | ||||
| 		ff = frac(aval, Math.pow(10,ri)-1, true); | ||||
| 		return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length)); | ||||
| 	} | ||||
| 	if((r = fmt.match(/^[#0?]+$/))) { | ||||
| @ -601,7 +579,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string | ||||
| 	var oa = ""; | ||||
| 	if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) { | ||||
| 		ri = Math.min(/*::String(*/r[4]/*::)*/.length,7); | ||||
| 		ff = SSF_frac(aval, Math.pow(10,ri)-1, false); | ||||
| 		ff = frac(aval, Math.pow(10,ri)-1, false); | ||||
| 		o = "" + sign; | ||||
| 		oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]); | ||||
| 		if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0"; | ||||
| @ -613,7 +591,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string | ||||
| 	} | ||||
| 	if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) { | ||||
| 		ri = Math.min(Math.max(r[1].length, r[4].length),7); | ||||
| 		ff = SSF_frac(aval, Math.pow(10,ri)-1, true); | ||||
| 		ff = frac(aval, Math.pow(10,ri)-1, true); | ||||
| 		return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length)); | ||||
| 	} | ||||
| 	if((r = fmt.match(/^[#0?]+$/))) { | ||||
| @ -639,10 +617,10 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string | ||||
| 	} | ||||
| 	throw new Error("unsupported format |" + fmt + "|"); | ||||
| } | ||||
| function write_num(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ { | ||||
| return function write_num(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ { | ||||
| 	return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val); | ||||
| } | ||||
| function SSF_split_fmt(fmt/*:string*/)/*:Array<string>*/ { | ||||
| };})(); | ||||
| function split_fmt(fmt/*:string*/)/*:Array<string>*/ { | ||||
| 	var out/*:Array<string>*/ = []; | ||||
| 	var in_str = false/*, cc*/; | ||||
| 	for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) { | ||||
| @ -658,13 +636,13 @@ function SSF_split_fmt(fmt/*:string*/)/*:Array<string>*/ { | ||||
| 	if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string "); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| var SSF_abstime = /\[[HhMmSs\u0E0A\u0E19\u0E17]*\]/; | ||||
| SSF._split = split_fmt; | ||||
| var abstime = /\[[HhMmSs\u0E0A\u0E19\u0E17]*\]/; | ||||
| 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(SSF_isgeneral(fmt, i)) i+= 6; i++; break; | ||||
| 			case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break; | ||||
| 			case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;){/*empty*/} ++i; break; | ||||
| 			case '\\': i+=2; break; | ||||
| 			case '_': i+=2; break; | ||||
| @ -683,7 +661,7 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ { | ||||
| 			case '[': | ||||
| 				o = c; | ||||
| 				while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i); | ||||
| 				if(o.match(SSF_abstime)) return true; | ||||
| 				if(o.match(abstime)) return true; | ||||
| 				break; | ||||
| 			case '.': | ||||
| 				/* falls through */ | ||||
| @ -701,7 +679,7 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ { | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| 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 hr='H'; | ||||
| @ -709,7 +687,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 	while(i < fmt.length) { | ||||
| 		switch((c = fmt.charAt(i))) { | ||||
| 			case 'G': /* General */ | ||||
| 				if(!SSF_isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt); | ||||
| 				if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt); | ||||
| 				out[out.length] = {t:'G', v:'General'}; i+=7; break; | ||||
| 			case '"': /* Literal text */ | ||||
| 				for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc); | ||||
| @ -721,7 +699,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				out[out.length] = {t:'T', v:v}; ++i; break; | ||||
| 			case 'B': case 'b': | ||||
| 				if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") { | ||||
| 					if(dt==null) { dt=SSF_parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; } | ||||
| 					if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; } | ||||
| 					out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break; | ||||
| 				} | ||||
| 				/* falls through */ | ||||
| @ -730,15 +708,15 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				/* falls through */ | ||||
| 			case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': | ||||
| 				if(v < 0) return ""; | ||||
| 				if(dt==null) { dt=SSF_parse_date_code(v, opts); if(dt==null) 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; | ||||
| 				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; | ||||
| 				if(c === 'h') c = hr; | ||||
| 				out[out.length] = {t:c, v:o}; lst = c; break; | ||||
| 			case 'A': case 'a': case '上': | ||||
| 				var q={t:c, v:c}; | ||||
| 				if(dt==null) dt=SSF_parse_date_code(v, opts); | ||||
| 				if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? fmt.charAt(i+2) : c; q.t = 'T'; hr='h';i+=3;} | ||||
| 				if(dt==null) dt=parse_date_code(v, opts); | ||||
| 				if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 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; } | ||||
| @ -748,8 +726,8 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				o = c; | ||||
| 				while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i); | ||||
| 				if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|'; | ||||
| 				if(o.match(SSF_abstime)) { | ||||
| 					if(dt==null) { dt=SSF_parse_date_code(v, opts); if(dt==null) return ""; } | ||||
| 				if(o.match(abstime)) { | ||||
| 					if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; } | ||||
| 					out[out.length] = {t:'Z', v:o.toLowerCase()}; | ||||
| 					lst = o.charAt(1); | ||||
| 				} else if(o.indexOf("$") > -1) { | ||||
| @ -789,11 +767,10 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 		switch(out[i].t) { | ||||
| 			case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break; | ||||
| 			case 's': | ||||
| 				if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;} | ||||
| 				if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1); | ||||
| 				if(bt < 3) bt = 3; | ||||
| 			/* falls through */ | ||||
| 			case 'd': case 'y': case 'e': lst=out[i].t; break; | ||||
| 			case 'M': lst=out[i].t; if(bt < 2) bt = 2; break; | ||||
| 			case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break; | ||||
| 			case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break; | ||||
| 			case 'X': /*if(out[i].v === "B2");*/ | ||||
| 				break; | ||||
| @ -803,29 +780,19 @@ 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 */ | ||||
| 	var _dt; | ||||
| 	switch(bt) { | ||||
| 		case 0: break; | ||||
| 		case 1: | ||||
| 		case 2: | ||||
| 		case 3: | ||||
| 			/*::if(!dt) break;*/ | ||||
| 			if(dt.u >= 0.5) { dt.u = 0; ++dt.S; } | ||||
| 			if(dt.S >=  60) { dt.S = 0; ++dt.M; } | ||||
| 			if(dt.M >=  60) { dt.M = 0; ++dt.H; } | ||||
| 			if(dt.H >=  24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; } | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			switch(ss0) { | ||||
| 				case 1: dt.u = Math.round(dt.u * 10)/10; break; | ||||
| 				case 2: dt.u = Math.round(dt.u * 100)/100; break; | ||||
| 				case 3: dt.u = Math.round(dt.u * 1000)/1000; break; | ||||
| 			} | ||||
| 			if(dt.u >=   1) { dt.u = 0; ++dt.S; } | ||||
| 		case 2: | ||||
| 			/*::if(!dt) break;*/ | ||||
| 			if(dt.u >= 0.5) { dt.u = 0; ++dt.S; } | ||||
| 			if(dt.S >=  60) { dt.S = 0; ++dt.M; } | ||||
| 			if(dt.M >=  60) { dt.M = 0; ++dt.H; } | ||||
| 			if(dt.H >=  24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; } | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| @ -837,7 +804,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 			case 'X': out[i].v = ""; out[i].t = ";"; break; | ||||
| 			case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z': | ||||
| 				/*::if(!dt) throw "unreachable"; */ | ||||
| 				out[i].v = SSF_write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0); | ||||
| 				out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0); | ||||
| 				out[i].t = 't'; break; | ||||
| 			case 'n': case '?': | ||||
| 				jj = i+1; | ||||
| @ -852,7 +819,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 				} | ||||
| 				nstr += out[i].v; | ||||
| 				i = jj-1; break; | ||||
| 			case 'G': out[i].t = 't'; out[i].v = SSF_general(v,opts); break; | ||||
| 			case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break; | ||||
| 		} | ||||
| 	} | ||||
| 	var vv = "", myv, ostr; | ||||
| @ -920,7 +887,8 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { | ||||
| 	for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v; | ||||
| 	return retval; | ||||
| } | ||||
| 
 | ||||
| SSF._eval = eval_fmt; | ||||
| var cfregex = /\[[=<>]/; | ||||
| var cfregex2 = /\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/; | ||||
| function chkcond(v, rr) { | ||||
| 	if(rr == null) return false; | ||||
| @ -936,13 +904,11 @@ function chkcond(v, rr) { | ||||
| 	return false; | ||||
| } | ||||
| function choose_fmt(f/*:string*/, v/*:any*/) { | ||||
| 	var fmt = SSF_split_fmt(f); | ||||
| 	var fmt = split_fmt(f); | ||||
| 	var l = fmt.length, lat = fmt[l-1].indexOf("@"); | ||||
| 	if(l<4 && lat>-1) --l; | ||||
| 	if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|"); | ||||
| 	if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"]; | ||||
| 	/* NOTE: most spreadsheet software do not support NaN or infinities */ | ||||
| 	if(typeof v === "number" && !isFinite(v)) v = 0; | ||||
| 	switch(fmt.length) { | ||||
| 		case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break; | ||||
| 		case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break; | ||||
| @ -951,14 +917,14 @@ function choose_fmt(f/*:string*/, v/*:any*/) { | ||||
| 	} | ||||
| 	var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2]; | ||||
| 	if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff]; | ||||
| 	if(fmt[0].match(/\[[=<>]/) != null || fmt[1].match(/\[[=<>]/) != null) { | ||||
| 	if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) { | ||||
| 		var m1 = fmt[0].match(cfregex2); | ||||
| 		var m2 = fmt[1].match(cfregex2); | ||||
| 		return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]]; | ||||
| 	} | ||||
| 	return [l, ff]; | ||||
| } | ||||
| function SSF_format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) { | ||||
| function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) { | ||||
| 	if(o == null) o = {}; | ||||
| 	var sfmt = ""; | ||||
| 	switch(typeof fmt) { | ||||
| @ -969,21 +935,19 @@ function SSF_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[SSF_default_map[fmt]]) || table_fmt[SSF_default_map[fmt]]; | ||||
| 			if(sfmt == null) sfmt = SSF_default_str[fmt] || "General"; | ||||
| 			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(SSF_isgeneral(sfmt,0)) return SSF_general(v, o); | ||||
| 	if(v instanceof Date) v = datenum(v, o.date1904); | ||||
| 	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(SSF_isgeneral(f[1])) return SSF_general(v, o); | ||||
| 	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 ""; | ||||
| 	else if(isNaN(v) && f[1].indexOf("0") > -1) return "#NUM!"; | ||||
| 	else if(!isFinite(v) && f[1].indexOf("0") > -1) return "#DIV/0!"; | ||||
| 	return eval_fmt(f[1], v, o, f[0]); | ||||
| } | ||||
| function SSF_load(fmt/*:string*/, idx/*:?number*/)/*:number*/ { | ||||
| function load_entry(fmt/*:string*/, idx/*:?number*/)/*:number*/ { | ||||
| 	if(typeof idx != 'number') { | ||||
| 		idx = +idx || -1; | ||||
| /*::if(typeof idx != 'number') return 0x188; */ | ||||
| @ -999,22 +963,14 @@ function SSF_load(fmt/*:string*/, idx/*:?number*/)/*:number*/ { | ||||
| 	table_fmt[idx] = fmt; | ||||
| 	return idx; | ||||
| } | ||||
| function SSF_load_table(tbl/*:SSFTable*/)/*:void*/ { | ||||
| 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) SSF_load(tbl[i], i); | ||||
| } | ||||
| 
 | ||||
| function make_ssf() { | ||||
| 	table_fmt = SSF_init_table(); | ||||
| } | ||||
| 
 | ||||
| var SSF = { | ||||
| 	format: SSF_format, | ||||
| 	load: SSF_load, | ||||
| 	_table: table_fmt, | ||||
| 	load_table: SSF_load_table, | ||||
| 	parse_date_code: SSF_parse_date_code, | ||||
| 	is_date: fmt_is_date, | ||||
| 	get_table: function get_table() { return SSF._table = table_fmt; } | ||||
| 		if(tbl[i] !== undefined) load_entry(tbl[i], i); | ||||
| }; | ||||
| 
 | ||||
| SSF.init_table = init_table; | ||||
| SSF.format = format; | ||||
| }; | ||||
| make_ssf(SSF); | ||||
|  | ||||
| @ -1,3 +1,23 @@ | ||||
| /* map from xlml named formats to SSF TODO: localize */ | ||||
| var XLMLFormatMap/*{[string]:string}*/ = ({ | ||||
| 	"General Number": "General", | ||||
| 	"General Date": SSF._table[22], | ||||
| 	"Long Date": "dddd, mmmm dd, yyyy", | ||||
| 	"Medium Date": SSF._table[15], | ||||
| 	"Short Date": SSF._table[14], | ||||
| 	"Long Time": SSF._table[19], | ||||
| 	"Medium Time": SSF._table[18], | ||||
| 	"Short Time": SSF._table[20], | ||||
| 	"Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)', | ||||
| 	"Fixed": SSF._table[2], | ||||
| 	"Standard": SSF._table[4], | ||||
| 	"Percent": SSF._table[10], | ||||
| 	"Scientific": SSF._table[11], | ||||
| 	"Yes/No": '"Yes";"Yes";"No";@', | ||||
| 	"True/False": '"True";"True";"False";@', | ||||
| 	"On/Off": '"Yes";"Yes";"No";@' | ||||
| }/*:any*/); | ||||
| 
 | ||||
| var SSFImplicit/*{[number]:string}*/ = ({ | ||||
| 	"5": '"$"#,##0_);\\("$"#,##0\\)', | ||||
| 	"6": '"$"#,##0_);[Red]\\("$"#,##0\\)', | ||||
| @ -41,9 +61,8 @@ var SSFImplicit/*{[number]:string}*/ = ({ | ||||
| /* dateNF parse TODO: move to SSF */ | ||||
| var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g; | ||||
| function dateNF_regex(dateNF/*:string|number*/)/*:RegExp*/ { | ||||
| 	var fmt = typeof dateNF == "number" ? table_fmt[dateNF] : dateNF; | ||||
| 	var fmt = typeof dateNF == "number" ? SSF._table[dateNF] : dateNF; | ||||
| 	fmt = fmt.replace(dateNFregex, "(\\d+)"); | ||||
| 	dateNFregex.lastIndex = 0; | ||||
| 	return new RegExp("^" + fmt + "$"); | ||||
| } | ||||
| function dateNF_fix(str/*:string*/, dateNF/*:string*/, match/*:Array<string>*/)/*:string*/ { | ||||
| @ -56,7 +75,6 @@ function dateNF_fix(str/*:string*/, dateNF/*:string*/, match/*:Array<string>*/)/ | ||||
| 			case 'm': if(H >= 0) M = v; else m = v; break; | ||||
| 		} | ||||
| 	}); | ||||
| 	dateNFregex.lastIndex = 0; | ||||
| 	if(S >= 0 && M == -1 && m >= 0) { M = m; m = -1; } | ||||
| 	var datestr = (("" + (Y>=0?Y: new Date().getFullYear())).slice(-4) + "-" + ("00" + (m>=1?m:1)).slice(-2) + "-" + ("00" + (d>=1?d:1)).slice(-2)); | ||||
| 	if(datestr.length == 7) datestr = "0" + datestr; | ||||
| @ -67,12 +85,3 @@ function dateNF_fix(str/*:string*/, dateNF/*:string*/, match/*:Array<string>*/)/ | ||||
| 	return datestr + "T" + timestr; | ||||
| } | ||||
| 
 | ||||
| /* table of bad formats written by third-party tools */ | ||||
| var bad_formats = { | ||||
| 	"d.m": "d\\.m" // Issue #2571 Google Sheets writes invalid format 'd.m', correct format is 'd"."m' or 'd\\.m'
 | ||||
| }; | ||||
| 
 | ||||
| function SSF__load(fmt, idx) { | ||||
| 	return SSF_load(bad_formats[fmt] || fmt, idx); | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										657
									
								
								bits/18_cfb.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										657
									
								
								bits/18_cfb.js
									
									
									
									
									
								
							| @ -1,4 +1,6 @@ | ||||
| var DO_NOT_EXPORT_CFB = true; | ||||
| /*:: | ||||
| declare var Base64:any; | ||||
| declare var ReadShift:any; | ||||
| declare var CheckField:any; | ||||
| declare var prep_blob:any; | ||||
| @ -14,7 +16,6 @@ declare var has_buf:boolean; | ||||
| declare var new_buf:any; | ||||
| declare var new_raw_buf:any; | ||||
| declare var new_unsafe_buf:any; | ||||
| declare var Buffer_from:any; | ||||
| */ | ||||
| /* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /* vim: set ts=2: */ | ||||
| @ -23,6 +24,7 @@ declare var Buffer_from:any; | ||||
| /*global Uint8Array:false, Uint16Array:false */ | ||||
| 
 | ||||
| /*:: | ||||
| declare var DO_NOT_EXPORT_CFB:?boolean; | ||||
| type SectorEntry = { | ||||
| 	name?:string; | ||||
| 	nodes?:Array<number>; | ||||
| @ -39,12 +41,16 @@ type CFBFiles = {[n:string]:CFBEntry}; | ||||
| /* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */ | ||||
| /* vim: set ts=2: */ | ||||
| /*exported CRC32 */ | ||||
| var CRC32 = /*#__PURE__*/(function() { | ||||
| var CRC32 = {}; | ||||
| var CRC32; | ||||
| (function (factory) { | ||||
| 	/*jshint ignore:start */ | ||||
| 	/*eslint-disable */ | ||||
| 	factory(CRC32 = {}); | ||||
| 	/*eslint-enable */ | ||||
| 	/*jshint ignore:end */ | ||||
| }(function(CRC32) { | ||||
| CRC32.version = '1.2.0'; | ||||
| /*:: | ||||
| type CRC32TableType = Array<number> | Int32Array; | ||||
| */ | ||||
| /* see perf/crc32table.js */ | ||||
| /*global Int32Array */ | ||||
| function signed_crc_table()/*:any*/ { | ||||
| 	var c = 0, table/*:Array<number>*/ = new Array(256); | ||||
| @ -65,77 +71,78 @@ function signed_crc_table()/*:any*/ { | ||||
| 	return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table; | ||||
| } | ||||
| 
 | ||||
| var T0 = signed_crc_table(); | ||||
| function slice_by_16_tables(T) { | ||||
| 	var c = 0, v = 0, n = 0, table/*:Array<number>*/ = typeof Int32Array !== 'undefined' ? new Int32Array(4096) : new Array(4096) ; | ||||
| 
 | ||||
| 	for(n = 0; n != 256; ++n) table[n] = T[n]; | ||||
| 	for(n = 0; n != 256; ++n) { | ||||
| 		v = T[n]; | ||||
| 		for(c = 256 + n; c < 4096; c += 256) v = table[c] = (v >>> 8) ^ T[v & 0xFF]; | ||||
| 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]; | ||||
| 	} | ||||
| 	var out = []; | ||||
| 	for(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' && typeof table.subarray == "function" ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256); | ||||
| 	return out; | ||||
| } | ||||
| var TT = slice_by_16_tables(T0); | ||||
| var T1 = TT[0],  T2 = TT[1],  T3 = TT[2],  T4 = TT[3],  T5 = TT[4]; | ||||
| var T6 = TT[5],  T7 = TT[6],  T8 = TT[7],  T9 = TT[8],  Ta = TT[9]; | ||||
| var Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14]; | ||||
| function crc32_bstr(bstr/*:string*/, seed/*:?number*/)/*:number*/ { | ||||
| 	var C = seed/*:: ? 0 : 0 */ ^ -1; | ||||
| 	for(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF]; | ||||
| 	return ~C; | ||||
| 	if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF]; | ||||
| 	return C ^ -1; | ||||
| } | ||||
| 
 | ||||
| function crc32_buf(B/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ { | ||||
| 	var C = seed/*:: ? 0 : 0 */ ^ -1, L = B.length - 15, i = 0; | ||||
| 	for(; i < L;) C = | ||||
| 		Tf[B[i++] ^ (C & 255)] ^ | ||||
| 		Te[B[i++] ^ ((C >> 8) & 255)] ^ | ||||
| 		Td[B[i++] ^ ((C >> 16) & 255)] ^ | ||||
| 		Tc[B[i++] ^ (C >>> 24)] ^ | ||||
| 		Tb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^ | ||||
| 		T7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^ | ||||
| 		T3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]]; | ||||
| 	L += 15; | ||||
| 	while(i < L) C = (C>>>8) ^ T0[(C^B[i++])&0xFF]; | ||||
| 	return ~C; | ||||
| function crc32_buf(buf/*:Uint8Array|Array<number>*/, 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<number>*/, 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 = 0, d = 0; i < L;) { | ||||
| 	for(var i = 0, L=str.length, c, d; i < L;) { | ||||
| 		c = str.charCodeAt(i++); | ||||
| 		if(c < 0x80) { | ||||
| 			C = (C>>>8) ^ T0[(C^c)&0xFF]; | ||||
| 			C = (C>>>8) ^ T[(C ^ c)&0xFF]; | ||||
| 		} else if(c < 0x800) { | ||||
| 			C = (C>>>8) ^ T0[(C ^ (192|((c>>6)&31)))&0xFF]; | ||||
| 			C = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF]; | ||||
| 			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) ^ T0[(C ^ (240|((c>>8)&7)))&0xFF]; | ||||
| 			C = (C>>>8) ^ T0[(C ^ (128|((c>>2)&63)))&0xFF]; | ||||
| 			C = (C>>>8) ^ T0[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF]; | ||||
| 			C = (C>>>8) ^ T0[(C ^ (128|(d&63)))&0xFF]; | ||||
| 			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) ^ T0[(C ^ (224|((c>>12)&15)))&0xFF]; | ||||
| 			C = (C>>>8) ^ T0[(C ^ (128|((c>>6)&63)))&0xFF]; | ||||
| 			C = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF]; | ||||
| 			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; | ||||
| 	return C ^ -1; | ||||
| } | ||||
| CRC32.table = T0; | ||||
| CRC32.table = T; | ||||
| CRC32.bstr = crc32_bstr; | ||||
| CRC32.buf = crc32_buf; | ||||
| CRC32.str = crc32_str; | ||||
| return CRC32; | ||||
| })(); | ||||
| })); | ||||
| /* [MS-CFB] v20171201 */ | ||||
| var CFB = /*#__PURE__*/(function _CFB(){ | ||||
| var CFB = (function _CFB(){ | ||||
| var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/; | ||||
| exports.version = '1.2.2'; | ||||
| exports.version = '1.1.4'; | ||||
| /* [MS-CFB] 2.6.4 */ | ||||
| function namecmp(l/*:string*/, r/*:string*/)/*:number*/ { | ||||
| 	var L = l.split("/"), R = r.split("/"); | ||||
| @ -213,15 +220,8 @@ function parse_extra_field(blob/*:CFBlob*/)/*:any*/ { | ||||
| 					if(flags & 4) p.ctime = blob.read_shift(4); | ||||
| 				} | ||||
| 				if(p.mtime) p.mt = new Date(p.mtime*1000); | ||||
| 			} break; | ||||
| 			/* ZIP64 Extended Information Field */ | ||||
| 			case 0x0001: { | ||||
| 				var sz1 = blob.read_shift(4), sz2 = blob.read_shift(4); | ||||
| 				p.usz = (sz2 * Math.pow(2,32) + sz1); | ||||
| 				sz1 = blob.read_shift(4); sz2 = blob.read_shift(4); | ||||
| 				p.csz = (sz2 * Math.pow(2,32) + sz1); | ||||
| 				// NOTE: volume fields are skipped
 | ||||
| 			} break; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		blob.l = tgt; | ||||
| 		o[type] = p; | ||||
| @ -229,10 +229,9 @@ function parse_extra_field(blob/*:CFBlob*/)/*:any*/ { | ||||
| 	return o; | ||||
| } | ||||
| var fs/*:: = require('fs'); */; | ||||
| function get_fs() { return fs || (fs = _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[0] | 0x20) == 0x6d && (file[1]|0x20) == 0x69) return parse_mad(file, options); | ||||
| if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512"); | ||||
| var mver = 3; | ||||
| var ssz = 512; | ||||
| @ -308,7 +307,7 @@ sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs); | ||||
| /** Chains */ | ||||
| var sector_list/*:SectorList*/ = make_sector_list(sectors, dir_start, fat_addrs, ssz); | ||||
| 
 | ||||
| if(dir_start < sector_list.length) sector_list[dir_start].name = "!Directory"; | ||||
| sector_list[dir_start].name = "!Directory"; | ||||
| if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT"; | ||||
| sector_list[fat_addrs[0]].name = "!FAT"; | ||||
| sector_list.fat_addrs = fat_addrs; | ||||
| @ -442,7 +441,7 @@ function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array<RawBytes>*/, | ||||
| 			if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break; | ||||
| 			fat_addrs.push(q); | ||||
| 		} | ||||
| 		if(cnt >= 1) sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs); | ||||
| 		sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -554,13 +553,9 @@ function read_file(filename/*:string*/, options/*:CFBReadOpts*/) { | ||||
| } | ||||
| 
 | ||||
| function read(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) { | ||||
| 	var type = options && options.type; | ||||
| 	if(!type) { | ||||
| 		if(has_buf && Buffer.isBuffer(blob)) type = "buffer"; | ||||
| 	} | ||||
| 	switch(type || "base64") { | ||||
| 	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 "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); | ||||
| 	} | ||||
| 	return parse(/*::typeof blob == 'string' ? new Buffer(blob, 'utf-8') : */blob, options); | ||||
| @ -607,34 +602,22 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ { | ||||
| 	if(!gc && !f) return; | ||||
| 
 | ||||
| 	var now = new Date(1987, 1, 19), j = 0; | ||||
| 	// Track which names exist
 | ||||
| 	var fullPaths = Object.create ? Object.create(null) : {}; | ||||
| 	var data/*:Array<[string, CFBEntry]>*/ = []; | ||||
| 	for(i = 0; i < cfb.FullPaths.length; ++i) { | ||||
| 		fullPaths[cfb.FullPaths[i]] = true; | ||||
| 		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 = fullPaths[dad]; | ||||
| 		while(!s) { | ||||
| 			while(dirname(dad) && !fullPaths[dirname(dad)]) dad = dirname(dad); | ||||
| 
 | ||||
| 			data.push([dad, ({ | ||||
| 				name: filename(dad).replace("/",""), | ||||
| 				type: 1, | ||||
| 				clsid: HEADER_CLSID, | ||||
| 				ct: now, mt: now, | ||||
| 				content: null | ||||
| 			}/*:any*/)]); | ||||
| 
 | ||||
| 			// Add name to set
 | ||||
| 			fullPaths[dad] = true; | ||||
| 
 | ||||
| 			dad = dirname(data[i][0]); | ||||
| 			s = fullPaths[dad]; | ||||
| 		} | ||||
| 		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]); }); | ||||
| @ -667,20 +650,16 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ { | ||||
| function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ { | ||||
| 	var _opts = options || {}; | ||||
| 	/* MAD is order-sensitive, skip rebuild and sort */ | ||||
| 	if(_opts.fileType == 'mad') return write_mad(cfb, _opts); | ||||
| 	rebuild_cfb(cfb); | ||||
| 	switch(_opts.fileType) { | ||||
| 		case 'zip': return write_zip(cfb, _opts); | ||||
| 		//case 'mad': return write_mad(cfb, _opts);
 | ||||
| 	} | ||||
| 	if(_opts.fileType == 'zip') return write_zip(cfb, _opts); | ||||
| 	var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{ | ||||
| 		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; | ||||
| @ -771,10 +750,6 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|strin | ||||
| 		file = cfb.FileIndex[i]; | ||||
| 		if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN; | ||||
| 		var _nm/*:string*/ = (i === 0 && _opts.root) || file.name; | ||||
| 		if(_nm.length > 31) { | ||||
| 			console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,31)); | ||||
| 			_nm = _nm.slice(0, 31); | ||||
| 		} | ||||
| 		flen = 2*(_nm.length+1); | ||||
| 		o.write_shift(64, _nm, "utf16le"); | ||||
| 		o.write_shift(2, flen); | ||||
| @ -796,36 +771,19 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|strin | ||||
| 		/*:: if(!file.content) throw new Error("unreachable"); */ | ||||
| 		if(file.size >= 0x1000) { | ||||
| 			o.l = (file.start+1) << 9; | ||||
| 			if (has_buf && Buffer.isBuffer(file.content)) { | ||||
| 				file.content.copy(o, o.l, 0, file.size); | ||||
| 				// o is a 0-filled Buffer so just set next offset
 | ||||
| 				o.l += (file.size + 511) & -512; | ||||
| 			} else { | ||||
| 				for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); | ||||
| 				for(; j & 0x1FF; ++j) o.write_shift(1, 0); | ||||
| 			} | ||||
| 			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) { | ||||
| 			if (has_buf && Buffer.isBuffer(file.content)) { | ||||
| 				file.content.copy(o, o.l, 0, file.size); | ||||
| 				// o is a 0-filled Buffer so just set next offset
 | ||||
| 				o.l += (file.size + 63) & -64; | ||||
| 			} else { | ||||
| 				for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); | ||||
| 				for(; j & 0x3F; ++j) o.write_shift(1, 0); | ||||
| 			} | ||||
| 			for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); | ||||
| 			for(; j & 0x3F; ++j) o.write_shift(1, 0); | ||||
| 		} | ||||
| 	} | ||||
| 	if (has_buf) { | ||||
| 		o.l = o.length; | ||||
| 	} else { | ||||
| 		// When using Buffer, already 0-filled
 | ||||
| 		while(o.l < o.length) 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) */ | ||||
| @ -889,13 +847,10 @@ function a2s(o/*:RawBytes*/)/*:string*/ { | ||||
| 
 | ||||
| function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ { | ||||
| 	var o = _write(cfb, options); | ||||
| 	switch(options && options.type || "buffer") { | ||||
| 	switch(options && options.type) { | ||||
| 		case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o; | ||||
| 		case "binary": return typeof o == "string" ? o : a2s(o); | ||||
| 		case "base64": return Base64_encode(typeof o == "string" ? o : a2s(o)); | ||||
| 		case "buffer": if(has_buf) return Buffer.isBuffer(o) ? o : Buffer_from(o); | ||||
| 			/* falls through */ | ||||
| 		case "array": return typeof o == "string" ? s2a(o) : o; | ||||
| 		case "binary": return a2s(o); | ||||
| 		case "base64": return Base64.encode(a2s(o)); | ||||
| 	} | ||||
| 	return o; | ||||
| } | ||||
| @ -965,38 +920,6 @@ function read_bits_n(buf, bl, n) { | ||||
| 	return v & f; | ||||
| } | ||||
| 
 | ||||
| /* helpers for unaligned bit writes */ | ||||
| function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3; | ||||
| 	if(w <= 5) buf[h] |= (v & 7) << w; | ||||
| 	else { | ||||
| 		buf[h] |= (v << w) & 0xFF; | ||||
| 		buf[h+1] = (v&7) >> (8-w); | ||||
| 	} | ||||
| 	return bl + 3; | ||||
| } | ||||
| 
 | ||||
| function write_bits_1(buf, bl, v) { | ||||
| 	var w = bl & 7, h = bl >>> 3; | ||||
| 	v = (v&1) << w; | ||||
| 	buf[h] |= v; | ||||
| 	return bl + 1; | ||||
| } | ||||
| function write_bits_8(buf, bl, v) { | ||||
| 	var w = bl & 7, h = bl >>> 3; | ||||
| 	v <<= w; | ||||
| 	buf[h] |=  v & 0xFF; v >>>= 8; | ||||
| 	buf[h+1] = v; | ||||
| 	return bl + 8; | ||||
| } | ||||
| function write_bits_16(buf, bl, v) { | ||||
| 	var w = bl & 7, h = bl >>> 3; | ||||
| 	v <<= w; | ||||
| 	buf[h] |=  v & 0xFF; v >>>= 8; | ||||
| 	buf[h+1] = v & 0xFF; | ||||
| 	buf[h+2] = v >>> 8; | ||||
| 	return bl + 16; | ||||
| } | ||||
| 
 | ||||
| /* 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; | ||||
| @ -1010,7 +933,7 @@ function realloc(b, sz/*:number*/) { | ||||
| 	} else if(use_typed_arrays) { | ||||
| 		var a = new Uint8Array(M); | ||||
| 		if(a.set) a.set(b); | ||||
| 		else for(; i < L; ++i) a[i] = b[i]; | ||||
| 		else for(; i < b.length; ++i) a[i] = b[i]; | ||||
| 		return a; | ||||
| 	} | ||||
| 	b.length = M; | ||||
| @ -1022,7 +945,30 @@ 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*/ { | ||||
| @ -1062,7 +1008,6 @@ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ { | ||||
| 	return maxlen; | ||||
| } | ||||
| 
 | ||||
| /* Fixed Huffman */ | ||||
| var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512); | ||||
| var fix_dmap = use_typed_arrays ? new Uint16Array(32)  : zero_fill_array(32); | ||||
| if(!use_typed_arrays) { | ||||
| @ -1082,125 +1027,8 @@ if(!use_typed_arrays) { | ||||
| 	for(; i<=279; i++) clens.push(7); | ||||
| 	for(; i<=287; i++) clens.push(8); | ||||
| 	build_tree(clens, fix_lmap, 288); | ||||
| })();var _deflateRaw = /*#__PURE__*/(function _deflateRawIIFE() { | ||||
| 	var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; | ||||
| 	var j = 0, k = 0; | ||||
| 	for(; j < DST_LN.length - 1; ++j) { | ||||
| 		for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; | ||||
| 	} | ||||
| 	for(;k < 32768; ++k) DST_LN_RE[k] = 29; | ||||
| 
 | ||||
| 	var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : []; | ||||
| 	for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) { | ||||
| 		for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; | ||||
| 	} | ||||
| 
 | ||||
| 	function write_stored(data, out) { | ||||
| 		var boff = 0; | ||||
| 		while(boff < data.length) { | ||||
| 			var L = Math.min(0xFFFF, data.length - boff); | ||||
| 			var h = boff + L == data.length; | ||||
| 			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; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Fixed Huffman */ | ||||
| 	function write_huff_fixed(data, out) { | ||||
| 		var bl = 0; | ||||
| 		var boff = 0; | ||||
| 		var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; | ||||
| 		while(boff < data.length) { | ||||
| 			var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); | ||||
| 
 | ||||
| 			/* write a stored block for short data */ | ||||
| 			if(L < 10) { | ||||
| 				bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line
 | ||||
| 				if(bl & 7) bl += 8 - (bl & 7); | ||||
| 				out.l = (bl / 8) | 0; | ||||
| 				out.write_shift(2, L); | ||||
| 				out.write_shift(2, (~L) & 0xFFFF); | ||||
| 				while(L-- > 0) out[out.l++] = data[boff++]; | ||||
| 				bl = out.l * 8; | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line
 | ||||
| 			var hash = 0; | ||||
| 			while(L-- > 0) { | ||||
| 				var d = data[boff]; | ||||
| 				hash = ((hash << 5) ^ d) & 0x7FFF; | ||||
| 
 | ||||
| 				var match = -1, mlen = 0; | ||||
| 
 | ||||
| 				if((match = addrs[hash])) { | ||||
| 					match |= boff & ~0x7FFF; | ||||
| 					if(match > boff) match -= 0x8000; | ||||
| 					if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; | ||||
| 				} | ||||
| 
 | ||||
| 				if(mlen > 2) { | ||||
| 					/* Copy Token  */ | ||||
| 					d = LEN_LN_RE[mlen]; | ||||
| 					if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; | ||||
| 					else { | ||||
| 						write_bits_8(out, bl, 3); | ||||
| 						bl += 5; | ||||
| 						write_bits_8(out, bl, bitswap8[d-23]>>5); | ||||
| 						bl += 3; | ||||
| 					} | ||||
| 					var len_eb = (d < 8) ? 0 : ((d - 4)>>2); | ||||
| 					if(len_eb > 0) { | ||||
| 						write_bits_16(out, bl, mlen - LEN_LN[d]); | ||||
| 						bl += len_eb; | ||||
| 					} | ||||
| 
 | ||||
| 					d = DST_LN_RE[boff - match]; | ||||
| 					bl = write_bits_8(out, bl, bitswap8[d]>>3); | ||||
| 					bl -= 3; | ||||
| 
 | ||||
| 					var dst_eb = d < 4 ? 0 : (d-2)>>1; | ||||
| 					if(dst_eb > 0) { | ||||
| 						write_bits_16(out, bl, boff - match - DST_LN[d]); | ||||
| 						bl += dst_eb; | ||||
| 					} | ||||
| 					for(var q = 0; q < mlen; ++q) { | ||||
| 						addrs[hash] = boff & 0x7FFF; | ||||
| 						hash = ((hash << 5) ^ data[boff]) & 0x7FFF; | ||||
| 						++boff; | ||||
| 					} | ||||
| 					L-= mlen - 1; | ||||
| 				} else { | ||||
| 					/* Literal Token */ | ||||
| 					if(d <= 143) d = d + 48; | ||||
| 					else bl = write_bits_1(out, bl, 1); | ||||
| 					bl = write_bits_8(out, bl, bitswap8[d]); | ||||
| 					addrs[hash] = boff & 0x7FFF; | ||||
| 					++boff; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			bl = write_bits_8(out, bl, 0) - 1; | ||||
| 		} | ||||
| 		out.l = ((bl + 7)/8)|0; | ||||
| 		return out.l; | ||||
| 	} | ||||
| 	return function _deflateRaw(data, out) { | ||||
| 		if(data.length < 8) return write_stored(data, out); | ||||
| 		return write_huff_fixed(data, out); | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| function _deflate(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 */ | ||||
| 
 | ||||
| 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); | ||||
| @ -1304,12 +1132,14 @@ function inflate(data, usz/*:number*/) { | ||||
| 			var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8; | ||||
| 			boff += 32; | ||||
| 			/* push sz bytes */ | ||||
| 			if(sz > 0) { | ||||
| 				if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; } | ||||
| 				while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; } | ||||
| 			} | ||||
| 			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) { | ||||
| 		} else if((header >>> 1) == 1) { | ||||
| 			/* Fixed Huffman */ | ||||
| 			max_len_1 = 9; max_len_2 = 5; | ||||
| 		} else { | ||||
| @ -1317,8 +1147,8 @@ function inflate(data, usz/*:number*/) { | ||||
| 			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
 | ||||
| 			if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } | ||||
| 			/* 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]; | ||||
| @ -1349,13 +1179,12 @@ function inflate(data, usz/*:number*/) { | ||||
| 				} | ||||
| 
 | ||||
| 				/* in the common case, manual byte copy is faster than TA set / Buffer copy */ | ||||
| 				if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } | ||||
| 				if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; } | ||||
| 				while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(usz) return [outbuf, (boff+7)>>>3]; | ||||
| 	return [outbuf.slice(0, woff), (boff+7)>>>3]; | ||||
| 	return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3]; | ||||
| } | ||||
| 
 | ||||
| function _inflate(payload, usz) { | ||||
| @ -1410,11 +1239,6 @@ function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ | ||||
| 
 | ||||
| 		var L = blob.l; | ||||
| 		blob.l = offset + 4; | ||||
| 		/* ZIP64 lengths */ | ||||
| 		if(EF && EF[0x0001]) { | ||||
| 			if((EF[0x0001]||{}).usz) usz = EF[0x0001].usz; | ||||
| 			if((EF[0x0001]||{}).csz) csz = EF[0x0001].csz; | ||||
| 		} | ||||
| 		parse_local_file(blob, csz, usz, o, EF); | ||||
| 		blob.l = L; | ||||
| 	} | ||||
| @ -1444,13 +1268,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C | ||||
| 	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[0x0001]||{}).usz) _usz = ef[0x0001].usz; | ||||
| 		if((ef[0x0001]||{}).csz) _csz = ef[0x0001].csz; | ||||
| 		if(EF) { | ||||
| 			if((EF[0x5455]||{}).mt) date = EF[0x5455].mt; | ||||
| 			if((EF[0x0001]||{}).usz) _usz = EF[0x0001].usz; | ||||
| 			if((EF[0x0001]||{}).csz) _csz = EF[0x0001].csz; | ||||
| 		} | ||||
| 		if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt; | ||||
| 	} | ||||
| 	blob.l += efsz; | ||||
| 
 | ||||
| @ -1460,7 +1278,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C | ||||
| 	var data = blob.slice(blob.l, blob.l + _csz); | ||||
| 	switch(meth) { | ||||
| 		case 8: data = _inflateRawSync(blob, _usz); break; | ||||
| 		case 0: blob.l += _csz; break; // TODO: scan for magic number
 | ||||
| 		case 0: break; | ||||
| 		default: throw new Error("Unsupported ZIP Compression method " + meth); | ||||
| 	} | ||||
| 
 | ||||
| @ -1475,8 +1293,8 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C | ||||
| 
 | ||||
| 	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);
 | ||||
| 	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*/ { | ||||
| @ -1495,17 +1313,16 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ | ||||
| 
 | ||||
| 	for(i = 1; i < cfb.FullPaths.length; ++i) { | ||||
| 		fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i]; | ||||
| 		if(!fi.size || !fi.content || (Array.isArray(fi.content) && fi.content.length == 0) || fp == "\u0001Sh33tJ5") continue; | ||||
| 		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] = typeof fi.content == "string" ? CRC32.bstr(fi.content, 0) : CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0); | ||||
| 		crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0); | ||||
| 
 | ||||
| 		var outbuf = typeof fi.content == "string" ? s2a(fi.content) : fi.content/*::||[]*/; | ||||
| 		var outbuf = fi.content/*::||[]*/; | ||||
| 		if(method == 8) outbuf = _deflateRawSync(outbuf); | ||||
| 
 | ||||
| 		/* local file header */ | ||||
| @ -1528,10 +1345,7 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ | ||||
| 		start_cd += namebuf.length; | ||||
| 		out.push(namebuf); | ||||
| 
 | ||||
| 		/* TODO: extra fields? */ | ||||
| 
 | ||||
| 		/* TODO: encryption header ? */ | ||||
| 
 | ||||
| 		start_cd += outbuf.length; | ||||
| 		out.push(outbuf); | ||||
| 
 | ||||
| @ -1585,212 +1399,6 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ | ||||
| 
 | ||||
| 	return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/)); | ||||
| } | ||||
| var ContentTypeMap = ({ | ||||
| 	"htm": "text/html", | ||||
| 	"xml": "text/xml", | ||||
| 
 | ||||
| 	"gif": "image/gif", | ||||
| 	"jpg": "image/jpeg", | ||||
| 	"png": "image/png", | ||||
| 
 | ||||
| 	"mso": "application/x-mso", | ||||
| 	"thmx": "application/vnd.ms-officetheme", | ||||
| 	"sh33tj5": "application/octet-stream" | ||||
| }/*:any*/); | ||||
| 
 | ||||
| function get_content_type(fi/*:CFBEntry*/, fp/*:string*/)/*:string*/ { | ||||
| 	if(fi.ctype) return fi.ctype; | ||||
| 
 | ||||
| 	var ext = fi.name || "", m = ext.match(/\.([^\.]+)$/); | ||||
| 	if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]]; | ||||
| 
 | ||||
| 	if(fp) { | ||||
| 		m = (ext = fp).match(/[\.\\]([^\.\\])+$/); | ||||
| 		if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]]; | ||||
| 	} | ||||
| 
 | ||||
| 	return "application/octet-stream"; | ||||
| } | ||||
| 
 | ||||
| /* 76 character chunks TODO: intertwine encoding */ | ||||
| function write_base64_76(bstr/*:string*/)/*:string*/ { | ||||
| 	var data = Base64_encode(bstr); | ||||
| 	var o = []; | ||||
| 	for(var i = 0; i < data.length; i+= 76) o.push(data.slice(i, i+76)); | ||||
| 	return o.join("\r\n") + "\r\n"; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| Rules for QP: | ||||
| 	- escape =## applies for all non-display characters and literal "=" | ||||
| 	- space or tab at end of line must be encoded | ||||
| 	- \r\n newlines can be preserved, but bare \r and \n must be escaped | ||||
| 	- lines must not exceed 76 characters, use soft breaks =\r\n | ||||
| 
 | ||||
| TODO: Some files from word appear to write line extensions with bare equals: | ||||
| 
 | ||||
| ``` | ||||
| <table class=3DMsoTableGrid border=3D1 cellspacing=3D0 cellpadding=3D0 width= | ||||
| ="70%" | ||||
| ``` | ||||
| */ | ||||
| function write_quoted_printable(text/*:string*/)/*:string*/ { | ||||
| 	var encoded = text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF=]/g, function(c) { | ||||
| 		var w = c.charCodeAt(0).toString(16).toUpperCase(); | ||||
| 		return "=" + (w.length == 1 ? "0" + w : w); | ||||
| 	}); | ||||
| 
 | ||||
| 	encoded = encoded.replace(/ $/mg, "=20").replace(/\t$/mg, "=09"); | ||||
| 
 | ||||
| 	if(encoded.charAt(0) == "\n") encoded = "=0D" + encoded.slice(1); | ||||
| 	encoded = encoded.replace(/\r(?!\n)/mg, "=0D").replace(/\n\n/mg, "\n=0A").replace(/([^\r\n])\n/mg, "$1=0A"); | ||||
| 
 | ||||
| 	var o/*:Array<string>*/ = [], split = encoded.split("\r\n"); | ||||
| 	for(var si = 0; si < split.length; ++si) { | ||||
| 		var str = split[si]; | ||||
| 		if(str.length == 0) { o.push(""); continue; } | ||||
| 		for(var i = 0; i < str.length;) { | ||||
| 			var end = 76; | ||||
| 			var tmp = str.slice(i, i + end); | ||||
| 			if(tmp.charAt(end - 1) == "=") end --; | ||||
| 			else if(tmp.charAt(end - 2) == "=") end -= 2; | ||||
| 			else if(tmp.charAt(end - 3) == "=") end -= 3; | ||||
| 			tmp = str.slice(i, i + end); | ||||
| 			i += end; | ||||
| 			if(i < str.length) tmp += "="; | ||||
| 			o.push(tmp); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return o.join("\r\n"); | ||||
| } | ||||
| function parse_quoted_printable(data/*:Array<string>*/)/*:RawBytes*/ { | ||||
| 	var o = []; | ||||
| 
 | ||||
| 	/* unify long lines */ | ||||
| 	for(var di = 0; di < data.length; ++di) { | ||||
| 		var line = data[di]; | ||||
| 		while(di <= data.length && line.charAt(line.length - 1) == "=") line = line.slice(0, line.length - 1) + data[++di]; | ||||
| 		o.push(line); | ||||
| 	} | ||||
| 
 | ||||
| 	/* decode */ | ||||
| 	for(var oi = 0; oi < o.length; ++oi) o[oi] = o[oi].replace(/[=][0-9A-Fa-f]{2}/g, function($$) { return String.fromCharCode(parseInt($$.slice(1), 16)); }); | ||||
| 	return s2a(o.join("\r\n")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| function parse_mime(cfb/*:CFBContainer*/, data/*:Array<string>*/, root/*:string*/)/*:void*/ { | ||||
| 	var fname = "", cte = "", ctype = "", fdata; | ||||
| 	var di = 0; | ||||
| 	for(;di < 10; ++di) { | ||||
| 		var line = data[di]; | ||||
| 		if(!line || line.match(/^\s*$/)) break; | ||||
| 		var m = line.match(/^([^:]*?):\s*([^\s].*)$/); | ||||
| 		if(m) switch(m[1].toLowerCase()) { | ||||
| 			case "content-location": fname = m[2].trim(); break; | ||||
| 			case "content-type": ctype = m[2].trim(); break; | ||||
| 			case "content-transfer-encoding": cte = m[2].trim(); break; | ||||
| 		} | ||||
| 	} | ||||
| 	++di; | ||||
| 	switch(cte.toLowerCase()) { | ||||
| 		case 'base64': fdata = s2a(Base64_decode(data.slice(di).join(""))); break; | ||||
| 		case 'quoted-printable': fdata = parse_quoted_printable(data.slice(di)); break; | ||||
| 		default: throw new Error("Unsupported Content-Transfer-Encoding " + cte); | ||||
| 	} | ||||
| 	var file = cfb_add(cfb, fname.slice(root.length), fdata, {unsafe: true}); | ||||
| 	if(ctype) file.ctype = ctype; | ||||
| } | ||||
| 
 | ||||
| function parse_mad(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ { | ||||
| 	if(a2s(file.slice(0,13)).toLowerCase() != "mime-version:") throw new Error("Unsupported MAD header"); | ||||
| 	var root = (options && options.root || ""); | ||||
| 	// $FlowIgnore
 | ||||
| 	var data = (has_buf && Buffer.isBuffer(file) ? file.toString("binary") : a2s(file)).split("\r\n"); | ||||
| 	var di = 0, row = ""; | ||||
| 
 | ||||
| 	/* if root is not specified, scan for the common prefix */ | ||||
| 	for(di = 0; di < data.length; ++di) { | ||||
| 		row = data[di]; | ||||
| 		if(!/^Content-Location:/i.test(row)) continue; | ||||
| 		row = row.slice(row.indexOf("file")); | ||||
| 		if(!root) root = row.slice(0, row.lastIndexOf("/") + 1); | ||||
| 		if(row.slice(0, root.length) == root) continue; | ||||
| 		while(root.length > 0) { | ||||
| 			root = root.slice(0, root.length - 1); | ||||
| 			root = root.slice(0, root.lastIndexOf("/") + 1); | ||||
| 			if(row.slice(0,root.length) == root) break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var mboundary = (data[1] || "").match(/boundary="(.*?)"/); | ||||
| 	if(!mboundary) throw new Error("MAD cannot find boundary"); | ||||
| 	var boundary = "--" + (mboundary[1] || ""); | ||||
| 
 | ||||
| 	var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = []; | ||||
| 	var o = { | ||||
| 		FileIndex: FileIndex, | ||||
| 		FullPaths: FullPaths | ||||
| 	}; | ||||
| 	init_cfb(o); | ||||
| 	var start_di, fcnt = 0; | ||||
| 	for(di = 0; di < data.length; ++di) { | ||||
| 		var line = data[di]; | ||||
| 		if(line !== boundary && line !== boundary + "--") continue; | ||||
| 		if(fcnt++) parse_mime(o, data.slice(start_di, di), root); | ||||
| 		start_di = di; | ||||
| 	} | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ { | ||||
| 	var opts = options || {}; | ||||
| 	var boundary = opts.boundary || "SheetJS"; | ||||
| 	boundary = '------=' + boundary; | ||||
| 
 | ||||
| 	var out = [ | ||||
| 		'MIME-Version: 1.0', | ||||
| 		'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"', | ||||
| 		'', | ||||
| 		'', | ||||
| 		'' | ||||
| 	]; | ||||
| 
 | ||||
| 	var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0]; | ||||
| 	for(var 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; | ||||
| 
 | ||||
| 		/* Normalize filename */ | ||||
| 		fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) { | ||||
| 			return "_x" + c.charCodeAt(0).toString(16) + "_"; | ||||
| 		}).replace(/[\u0080-\uFFFF]/g, function(u) { | ||||
| 			return "_u" + u.charCodeAt(0).toString(16) + "_"; | ||||
| 		}); | ||||
| 
 | ||||
| 		/* Extract content as binary string */ | ||||
| 		var ca = fi.content; | ||||
| 		// $FlowIgnore
 | ||||
| 		var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca); | ||||
| 
 | ||||
| 		/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */ | ||||
| 		var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0; | ||||
| 		for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt; | ||||
| 		var qp = dispcnt >= L * 4 / 5; | ||||
| 
 | ||||
| 		out.push(boundary); | ||||
| 		out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp); | ||||
| 		out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64')); | ||||
| 		out.push('Content-Type: ' + get_content_type(fi, fp)); | ||||
| 		out.push(''); | ||||
| 
 | ||||
| 		out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr)); | ||||
| 	} | ||||
| 	out.push(boundary + '--\r\n'); | ||||
| 	return out.join("\r\n"); | ||||
| } | ||||
| function cfb_new(opts/*:?any*/)/*:CFBContainer*/ { | ||||
| 	var o/*:CFBContainer*/ = ({}/*:any*/); | ||||
| 	init_cfb(o, opts); | ||||
| @ -1872,3 +1480,4 @@ exports.utils = { | ||||
| return exports; | ||||
| })(); | ||||
| 
 | ||||
| if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| var _fs; | ||||
| function set_fs(fs) { _fs = fs; } | ||||
| if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {} | ||||
| 
 | ||||
| /* normalize data for blob ctor */ | ||||
| function blobify(data) { | ||||
| @ -11,16 +11,6 @@ function blobify(data) { | ||||
| 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); | ||||
| 	if(typeof Deno !== 'undefined') { | ||||
| 		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */ | ||||
| 		if(enc && typeof payload == "string") switch(enc) { | ||||
| 			case "utf8": payload = new TextEncoder(enc).encode(payload); break; | ||||
| 			case "binary": payload = s2ab(payload); break; | ||||
| 			/* TODO: binary equivalent */ | ||||
| 			default: throw new Error("Unsupported encoding " + enc); | ||||
| 		} | ||||
| 		return Deno.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); | ||||
| @ -35,7 +25,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) { | ||||
| 			/*:: 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 }); | ||||
| 				return chrome.downloads.download({ url: url, filename: fname, saveAs: true}); | ||||
| 			} | ||||
| 			var a = document.createElement("a"); | ||||
| 			if(a.download != null) { | ||||
| @ -45,10 +35,6 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) { | ||||
| 				if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000); | ||||
| 				return url; | ||||
| 			} | ||||
| 		} else if(typeof URL !== 'undefined' && !URL.createObjectURL && typeof chrome === 'object') { | ||||
| 			/* manifest v3 extensions -- no URL.createObjectURL */ | ||||
| 			var b64 = "data:application/octet-stream;base64," + Base64_encode_arr(new Uint8Array(blobify(data))); | ||||
| 			return chrome.downloads.download({ url: b64, filename: fname, saveAs: true }); | ||||
| 		} | ||||
| 	} | ||||
| 	// $FlowIgnore
 | ||||
| @ -57,20 +43,19 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) { | ||||
| 		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.indexOf("onstruct") == -1) throw e; } | ||||
| 	} 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); | ||||
| 	if(typeof Deno !== 'undefined') return Deno.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.indexOf("onstruct") == -1) throw e; } | ||||
| 	} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; } | ||||
| 	throw new Error("Cannot access file " + path); | ||||
| } | ||||
|  | ||||
| @ -31,19 +31,22 @@ function evert_arr(obj/*:any*/)/*:EvertArrType*/ { | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| var dnthresh  = /*#__PURE__*/Date.UTC(1899, 11, 30, 0, 0, 0); // -2209161600000
 | ||||
| var dnthresh1 = /*#__PURE__*/Date.UTC(1899, 11, 31, 0, 0, 0); // -2209075200000
 | ||||
| var dnthresh2 = /*#__PURE__*/Date.UTC(1904, 0, 1, 0, 0, 0); // -2209075200000
 | ||||
| var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
 | ||||
| function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ { | ||||
| 	var epoch = /*#__PURE__*/v.getTime(); | ||||
| 	var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000); | ||||
| 	if(date1904) { res -= 1462; return res < -1402 ? res - 1 : res; } | ||||
| 	return res < 60 ? res - 1 : res; | ||||
| 	var epoch = v.getTime(); | ||||
| 	if(date1904) epoch -= 1462*24*60*60*1000; | ||||
| 	var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000; | ||||
| 	return (epoch - dnthresh) / (24 * 60 * 60 * 1000); | ||||
| } | ||||
| function numdate(v/*:number*/)/*:Date|number*/ { | ||||
| 	if(v >= 60 && v < 61) return v; | ||||
| 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>60 ? v : (v+1)) * 24 * 60 * 60 * 1000 + dnthresh); | ||||
| 	out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh); | ||||
| 	if (out.getTimezoneOffset() !== refoffset) { | ||||
| 		out.setTime(out.getTime() + (out.getTimezoneOffset() - refoffset) * 60000); | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| @ -74,65 +77,34 @@ function parse_isodur(s) { | ||||
| 	return sec; | ||||
| } | ||||
| 
 | ||||
| /* Blame https://bugs.chromium.org/p/v8/issues/detail?id=7863 for the regexide */ | ||||
| var pdre1 = /^(\d+):(\d+)(:\d+)?(\.\d+)?$/; // HH:MM[:SS[.UUU]]
 | ||||
| var pdre2 = /^(\d+)-(\d+)-(\d+)$/; // YYYY-mm-dd
 | ||||
| var pdre3 = /^(\d+)-(\d+)-(\d+)[T ](\d+):(\d+)(:\d+)?(\.\d+)?$/; // YYYY-mm-dd(T or space)HH:MM[:SS[.UUU]], sans "Z"
 | ||||
| /* parses a date string as a UTC date */ | ||||
| function parseDate(str/*:string*/, date1904/*:boolean*/)/*:Date*/ { | ||||
| 	if(str instanceof Date) return str; | ||||
| 	var m = str.match(pdre1); | ||||
| 	if(m) return new Date((date1904 ? dnthresh2 : dnthresh1) + ((parseInt(m[1], 10)*60 + parseInt(m[2], 10))*60 + (m[3] ? parseInt(m[3].slice(1), 10) : 0))*1000 + (m[4] ? parseInt((m[4]+"000").slice(1,4), 10) : 0)); | ||||
| 	m = str.match(pdre2); | ||||
| 	if(m) return new Date(Date.UTC(+m[1], +m[2]-1, +m[3], 0, 0, 0, 0)); | ||||
| 	/* TODO: 1900-02-29T00:00:00.000 should return a flag to treat as a date code (affects xlml) */ | ||||
| 	m = str.match(pdre3); | ||||
| 	if(m) return new Date(Date.UTC(+m[1], +m[2]-1, +m[3], +m[4], +m[5], ((m[6] && parseInt(m[6].slice(1), 10))|| 0), ((m[7] && parseInt((m[7] + "0000").slice(1,4), 10))||0))); | ||||
| 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 */ | ||||
| function parseDate(str/*:string|Date*/, fixdate/*:?number*/)/*:Date*/ { | ||||
| 	var d = new Date(str); | ||||
| 	return d; | ||||
| 	if(good_pd) { | ||||
| 		/*:: if(fixdate == null) fixdate = 0; */ | ||||
| 		if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000); | ||||
| 		else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000); | ||||
| 		return d; | ||||
| 	} | ||||
| 	if(str instanceof Date) return str; | ||||
| 	if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) { | ||||
| 		var s = d.getFullYear(); | ||||
| 		if(str.indexOf("" + s) > -1) return d; | ||||
| 		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; | ||||
| } | ||||
| 
 | ||||
| function cc2str(arr/*:Array<number>*/, debomit)/*:string*/ { | ||||
| 	if(has_buf && Buffer.isBuffer(arr)) { | ||||
| 		if(debomit && buf_utf16le) { | ||||
| 			// TODO: temporary patch
 | ||||
| 			if(arr[0] == 0xFF && arr[1] == 0xFE) return utf8write(arr.slice(2).toString("utf16le")); | ||||
| 			if(arr[1] == 0xFE && arr[2] == 0xFF) return utf8write(utf16beread(arr.slice(2).toString("binary"))); | ||||
| 		} | ||||
| 		return arr.toString("binary"); | ||||
| 	} | ||||
| 
 | ||||
| 	if(typeof TextDecoder !== "undefined") try { | ||||
| 		if(debomit) { | ||||
| 			if(arr[0] == 0xFF && arr[1] == 0xFE) return utf8write(new TextDecoder("utf-16le").decode(arr.slice(2))); | ||||
| 			if(arr[0] == 0xFE && arr[1] == 0xFF) return utf8write(new TextDecoder("utf-16be").decode(arr.slice(2))); | ||||
| 		} | ||||
| 		var rev = { | ||||
| 			"\u20ac": "\x80", "\u201a": "\x82", "\u0192": "\x83", "\u201e": "\x84", | ||||
| 			"\u2026": "\x85", "\u2020": "\x86", "\u2021": "\x87", "\u02c6": "\x88", | ||||
| 			"\u2030": "\x89", "\u0160": "\x8a", "\u2039": "\x8b", "\u0152": "\x8c", | ||||
| 			"\u017d": "\x8e", "\u2018": "\x91", "\u2019": "\x92", "\u201c": "\x93", | ||||
| 			"\u201d": "\x94", "\u2022": "\x95", "\u2013": "\x96", "\u2014": "\x97", | ||||
| 			"\u02dc": "\x98", "\u2122": "\x99", "\u0161": "\x9a", "\u203a": "\x9b", | ||||
| 			"\u0153": "\x9c", "\u017e": "\x9e", "\u0178": "\x9f" | ||||
| 		}; | ||||
| 		if(Array.isArray(arr)) arr = new Uint8Array(arr); | ||||
| 		return new TextDecoder("latin1").decode(arr).replace(/[€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ]/g, function(c) { return rev[c] || c; }); | ||||
| 	} catch(e) {} | ||||
| 
 | ||||
| 	var o = [], i = 0; | ||||
| 	// this cascade is for the browsers and runtimes of antiquity (and for modern runtimes that lack TextEncoder)
 | ||||
| 	try { | ||||
| 		for(i = 0; i < arr.length - 65536; i+=65536) o.push(String.fromCharCode.apply(0, arr.slice(i, i + 65536))); | ||||
| 		o.push(String.fromCharCode.apply(0, arr.slice(i))); | ||||
| 	} catch(e) { try { | ||||
| 			for(; i < arr.length - 16384; i+=16384) o.push(String.fromCharCode.apply(0, arr.slice(i, i + 16384))); | ||||
| 			o.push(String.fromCharCode.apply(0, arr.slice(i))); | ||||
| 		} catch(e) { | ||||
| 			for(; i != arr.length; ++i) o.push(String.fromCharCode(arr[i])); | ||||
| 		} | ||||
| 	} | ||||
| 	return o.join(""); | ||||
| function cc2str(arr/*:Array<number>*/)/*:string*/ { | ||||
| 	var o = ""; | ||||
| 	for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| function dup(o/*:any*/)/*:any*/ { | ||||
| @ -149,232 +121,75 @@ function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length | ||||
| /* TODO: stress test */ | ||||
| function fuzzynum(s/*:string*/)/*:number*/ { | ||||
| 	var v/*:number*/ = Number(s); | ||||
| 	if(!isNaN(v)) return isFinite(v) ? v : NaN; | ||||
| 	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;}); | ||||
| 	ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;}); | ||||
| 	if(!isNaN(v = Number(ss))) return v / wt; | ||||
| 	return v; | ||||
| } | ||||
| 
 | ||||
| /* NOTE: Chrome rejects bare times like 1:23 PM */ | ||||
| var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))\s+([ap])m?$/; | ||||
| var FDRE2 = /^([01]?\d|2[0-3])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))$/; | ||||
| var FDISO = /^(\d+)-(\d+)-(\d+)[T ](\d+):(\d+)(:\d+)(\.\d+)?[Z]?$/; // YYYY-mm-dd(T or space)HH:MM:SS[.UUU][Z]
 | ||||
| // date regex reference - https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s04.html
 | ||||
| // matches mm/dd/yy, mm/dd/yyyy, dd/mm/yy, dd/mm/yyyy
 | ||||
| var STRICT_DATE_REGEX = [ | ||||
| 	"^(?:(1[0-2]|0[1-9])\\.(3[01]|[12][0-9]|0[1-9])|(3[01]|[12][0-9]|0[1-9])\\.(1[0-2]|0[1-9]))\\.([0-2][0-9]{3}|[0-9]{2})$",  | ||||
| 	"^(?:(1[0-2]|0[1-9])\/(3[01]|[12][0-9]|0[1-9])|(3[01]|[12][0-9]|0[1-9])\/(1[0-2]|0[1-9]))\/([0-2][0-9]{3}|[0-9]{2})$", | ||||
| 	"^(?:(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])|(3[01]|[12][0-9]|0[1-9])-(1[0-2]|0[1-9]))-([0-2][0-9]{3}|[0-9]{2})$", | ||||
| 	"^(?:(1[0-2]|0[1-9])\\.(3[01]|[12][0-9]|0[1-9])|(3[01]|[12][0-9]|0[1-9])\\.(1[0-2]|0[1-9]))\\.([0-2][0-9]{3}|[0-9]{2})$", | ||||
| 	"^(?:(1[0-2]|0[1-9])\/(3[01]|[12][0-9]|0[1-9])|(3[01]|[12][0-9]|0[1-9])\/(1[0-2]|0[1-9]))\/([0-2][0-9]{3}|[0-9]{2})$", | ||||
| 	"^(?:(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])|(3[01]|[12][0-9]|0[1-9])-(1[0-2]|0[1-9]))-([0-2][0-9]{3}|[0-9]{2})$" | ||||
| 	]; | ||||
| 
 | ||||
| /* TODO: 1904 adjustment */ | ||||
| var utc_append_works = new Date("6/9/69 00:00 UTC").valueOf() == -17798400000; | ||||
| function fuzzytime1(M) /*:Date*/ { | ||||
| 	if(!M[2]) return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0)); | ||||
| 	if(M[3]) { | ||||
| 			if(M[4]) return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000)); | ||||
| 			else return new Date(Date.UTC(1899,11,31,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000)); | ||||
| function fuzzydate(s/*:string*/, strictDate/*string*/)/*:Date*/ { | ||||
| 	var o = new Date(s), n = new Date(NaN); | ||||
| 
 | ||||
| 	if(strictDate) { | ||||
| 		var dateFormat = strictDate.toLowerCase().replace(/[.]|[-]/g, '/') | ||||
| 
 | ||||
| 		STRICT_DATE_REGEX | ||||
| 		.map(function (regex) { | ||||
| 			var regexTestString =  | ||||
| 			var matchStr = regexTestString.test(s) | ||||
| 
 | ||||
| 			if(matchStr){ | ||||
| 				s.replace(/[.]|[-]/g, '/') | ||||
| 
 | ||||
| 				if (dateFormat === "dd/mm") { | ||||
| 					var splitDate = s.split('/') | ||||
| 					var newDate = [s[1], s[0], s[2]] | ||||
| 
 | ||||
| 					s = newDate.join('/') | ||||
| 
 | ||||
| 					o = new Date(s) | ||||
| 					return o | ||||
| 				} | ||||
| 				 | ||||
| 				o = new Date(s) | ||||
| 				return o; | ||||
| 			}; | ||||
| 	  	}) | ||||
| 		.filter(function (result) { | ||||
| 			return ((result !== undefined) && (result !== null)) | ||||
| 		}); | ||||
| 
 | ||||
| 		return n; | ||||
| 	} | ||||
| 	else if(M[5]) return new Date(Date.UTC(1899,11,31, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0)); | ||||
| 	else return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0)); | ||||
| } | ||||
| function fuzzytime2(M) /*:Date*/ { | ||||
| 	if(!M[2]) return new Date(Date.UTC(1899,11,31,+M[1], 0, 0, 0)); | ||||
| 	if(M[3]) { | ||||
| 			if(M[4]) return new Date(Date.UTC(1899,11,31,+M[1], +M[2], +M[4], parseFloat(M[3])*1000)); | ||||
| 			else return new Date(Date.UTC(1899,11,31,0, +M[1], +M[2], parseFloat(M[3])*1000)); | ||||
| 	} | ||||
| 	else if(M[5]) return new Date(Date.UTC(1899,11,31, +M[1], +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0)); | ||||
| 	else return new Date(Date.UTC(1899,11,31,+M[1], +M[2], 0, 0)); | ||||
| } | ||||
| var lower_months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december']; | ||||
| function fuzzydate(s/*:string*/)/*:Date*/ { | ||||
| 	// See issue 2863 -- this is technically not supported in Excel but is otherwise useful
 | ||||
| 	if(FDISO.test(s)) return s.indexOf("Z") == -1 ? local_to_utc(new Date(s)) : new Date(s); | ||||
| 	var lower = s.toLowerCase(); | ||||
| 	var lnos = lower.replace(/\s+/g, " ").trim(); | ||||
| 	var M = lnos.match(FDRE1); | ||||
| 	if(M) return fuzzytime1(M); | ||||
| 	M = lnos.match(FDRE2); | ||||
| 	if(M) return fuzzytime2(M); | ||||
| 	M = lnos.match(pdre3); | ||||
| 	if(M) return new Date(Date.UTC(+M[1], +M[2]-1, +M[3], +M[4], +M[5], ((M[6] && parseInt(M[6].slice(1), 10))|| 0), ((M[7] && parseInt((M[7] + "0000").slice(1,4), 10))||0))); | ||||
| 	var o = new Date(utc_append_works && s.indexOf("UTC") == -1 ? s + " UTC": s), n = new Date(NaN); | ||||
| 
 | ||||
| 	var y = o.getYear(), m = o.getMonth(), d = o.getDate(); | ||||
| 	if(isNaN(d)) return n; | ||||
| 	if(lower.match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) { | ||||
| 		lower = lower.replace(/[^a-z]/g,"").replace(/([^a-z]|^)[ap]m?([^a-z]|$)/,""); | ||||
| 		if(lower.length > 3 && lower_months.indexOf(lower) == -1) return n; | ||||
| 	} else if(lower.replace(/[ap]m?/, "").match(/[a-z]/)) return n; | ||||
| 	if(y < 0 || y > 8099 || s.match(/[^-0-9:,\/\\\ ]/)) return n; | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| var split_regex = /*#__PURE__*/(function() { | ||||
| 	var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5; | ||||
| 	return function split_regex(str/*:string*/, re, def/*:string*/)/*:Array<string>*/ { | ||||
| 		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; | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| function utc_to_local(utc) { | ||||
| 	return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate(), utc.getUTCHours(), utc.getUTCMinutes(), utc.getUTCSeconds(), utc.getUTCMilliseconds()); | ||||
| var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5; | ||||
| function split_regex(str/*:string*/, re, def/*:string*/)/*:Array<string>*/ { | ||||
| 	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; | ||||
| } | ||||
| function local_to_utc(local) { | ||||
| 	return new Date(Date.UTC(local.getFullYear(), local.getMonth(), local.getDate(), local.getHours(), local.getMinutes(), local.getSeconds(), local.getMilliseconds())); | ||||
| } | ||||
| 
 | ||||
| function remove_doctype(str) { | ||||
| 	var preamble = str.slice(0, 1024); | ||||
| 	var si = preamble.indexOf("<!DOCTYPE"); | ||||
| 	if(si == -1) return str; | ||||
| 	var m = str.match(/<[\w]/); | ||||
| 	if(!m) return str; | ||||
| 	return str.slice(0, si) + str.slice(m.index); | ||||
| } | ||||
| 
 | ||||
| /* str.match(/<!--[\s\S]*?-->/g) --> str_match_ng(str, "<!--", "-->") */ | ||||
| function str_match_ng(str, s, e) { | ||||
|   var out = []; | ||||
| 
 | ||||
|   var si = str.indexOf(s); | ||||
|   while(si > -1) { | ||||
|     var ei = str.indexOf(e, si + s.length); | ||||
| 		if(ei == -1) break; | ||||
| 
 | ||||
| 		out.push(str.slice(si, ei + e.length)); | ||||
| 		si = str.indexOf(s, ei + e.length); | ||||
| 	} | ||||
| 
 | ||||
|   return out.length > 0 ? out : null; | ||||
| } | ||||
| 
 | ||||
| /* str.replace(/<!--[\s\S]*?-->/g, "") --> str_remove_ng(str, "<!--", "-->") */ | ||||
| function str_remove_ng(str, s, e) { | ||||
|   var out = [], last = 0; | ||||
| 
 | ||||
|   var si = str.indexOf(s); | ||||
| 	if(si == -1) return str; | ||||
|   while(si > -1) { | ||||
| 		out.push(str.slice(last, si)); | ||||
|     var ei = str.indexOf(e, si + s.length); | ||||
| 		if(ei == -1) break; | ||||
| 
 | ||||
| 		if((si = str.indexOf(s, (last = ei + e.length))) == -1) out.push(str.slice(last)); | ||||
| 	} | ||||
| 
 | ||||
|   return out.join(""); | ||||
| } | ||||
| 
 | ||||
| /* str.match(/<tag\b[^>]*?>([\s\S]*?)</tag>/) --> str_match_xml(str, "tag") */ | ||||
| var xml_boundary = { " ": 1, "\t": 1, "\r": 1, "\n": 1, ">": 1 }; | ||||
| function str_match_xml(str, tag) { | ||||
| 	var si = str.indexOf('<' + tag), w = tag.length + 1, L = str.length; | ||||
| 	while(si >= 0 && si <= L - w && !xml_boundary[str.charAt(si + w)]) si = str.indexOf('<' + tag, si+1); | ||||
| 	if(si === -1) return null; | ||||
| 	var sf = str.indexOf(">", si + tag.length); | ||||
| 	if(sf === -1) return null; | ||||
| 	var et = "</" + tag + ">"; | ||||
| 	var ei = str.indexOf(et, sf); | ||||
| 	if(ei == -1) return null; | ||||
| 	return [str.slice(si, ei + et.length), str.slice(sf + 1, ei)]; | ||||
| } | ||||
| 
 | ||||
| /* str.match(/<(?:\w+:)?tag\b[^<>]*?>([\s\S]*?)<\/(?:\w+:)?tag>/) --> str_match_xml(str, "tag") */ | ||||
| var str_match_xml_ns = /*#__PURE__*/(function() { | ||||
| 	var str_match_xml_ns_cache = {}; | ||||
| 	return function str_match_xml_ns(str, tag) { | ||||
| 		var res = str_match_xml_ns_cache[tag]; | ||||
| 		if(!res) str_match_xml_ns_cache[tag] = res = [ | ||||
| 			new RegExp('<(?:\\w+:)?'+tag+'\\b[^<>]*>', "g"), | ||||
| 			new RegExp('</(?:\\w+:)?'+tag+'>', "g") | ||||
| 		]; | ||||
| 		res[0].lastIndex = res[1].lastIndex = 0; | ||||
| 		var m = res[0].exec(str); | ||||
| 		if(!m) return null; | ||||
| 		var si = m.index; | ||||
| 		var sf = res[0].lastIndex; | ||||
| 		res[1].lastIndex = res[0].lastIndex; | ||||
| 		m = res[1].exec(str); | ||||
| 		if(!m) return null; | ||||
| 		var ei = m.index; | ||||
| 		var ef = res[1].lastIndex; | ||||
| 		return [str.slice(si, ef), str.slice(sf, ei)]; | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| /* str.match(/<(?:\w+:)?tag\b[^<>]*?>([\s\S]*?)<\/(?:\w+:)?tag>/g) --> str_match_xml_ns_g(str, "tag") */ | ||||
| var str_match_xml_ns_g = /*#__PURE__*/(function() { | ||||
| 	var str_match_xml_ns_cache = {}; | ||||
| 	return function str_match_xml_ns(str, tag) { | ||||
| 		var out = []; | ||||
| 		var res = str_match_xml_ns_cache[tag]; | ||||
| 		if(!res) str_match_xml_ns_cache[tag] = res = [ | ||||
| 			new RegExp('<(?:\\w+:)?'+tag+'\\b[^<>]*>', "g"), | ||||
| 			new RegExp('</(?:\\w+:)?'+tag+'>', "g") | ||||
| 		]; | ||||
| 		res[0].lastIndex = res[1].lastIndex = 0; | ||||
| 		var m; | ||||
| 		while((m = res[0].exec(str))) { | ||||
| 			var si = m.index; | ||||
| 			res[1].lastIndex = res[0].lastIndex; | ||||
| 			m = res[1].exec(str); | ||||
| 			if(!m) return null; | ||||
| 			var ef = res[1].lastIndex; | ||||
| 			out.push(str.slice(si, ef)); | ||||
| 			res[0].lastIndex = res[1].lastIndex; | ||||
| 		} | ||||
| 		return out.length == 0 ? null : out; | ||||
| 	}; | ||||
| })(); | ||||
| var str_remove_xml_ns_g = /*#__PURE__*/(function() { | ||||
| 	var str_remove_xml_ns_cache = {}; | ||||
| 	return function str_remove_xml_ns_g(str, tag) { | ||||
| 		var out = []; | ||||
| 		var res = str_remove_xml_ns_cache[tag]; | ||||
| 		if(!res) str_remove_xml_ns_cache[tag] = res = [ | ||||
| 			new RegExp('<(?:\\w+:)?'+tag+'\\b[^<>]*>', "g"), | ||||
| 			new RegExp('</(?:\\w+:)?'+tag+'>', "g") | ||||
| 		]; | ||||
| 		res[0].lastIndex = res[1].lastIndex = 0; | ||||
| 		var m; | ||||
| 		var si = 0, ef = 0; | ||||
| 		while((m = res[0].exec(str))) { | ||||
| 			si = m.index; | ||||
| 			out.push(str.slice(ef, si)); | ||||
| 			ef = si; | ||||
| 			res[1].lastIndex = res[0].lastIndex; | ||||
| 			m = res[1].exec(str); | ||||
| 			if(!m) return null; | ||||
| 			ef = res[1].lastIndex; | ||||
| 			res[0].lastIndex = res[1].lastIndex; | ||||
| 		} | ||||
| 		out.push(str.slice(ef)); | ||||
| 		return out.length == 0 ? "" : out.join(""); | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| /* str.match(/<(?:\w+:)?tag\b[^>]*?>([\s\S]*?)<\/(?:\w+:)?tag>/gi) --> str_match_xml_ns_ig(str, "tag") */ | ||||
| var str_match_xml_ig = /*#__PURE__*/(function() { | ||||
| 	var str_match_xml_ns_cache = {}; | ||||
| 	return function str_match_xml_ns(str, tag) { | ||||
| 		var out = []; | ||||
| 		var res = str_match_xml_ns_cache[tag]; | ||||
| 		if(!res) str_match_xml_ns_cache[tag] = res = [ | ||||
| 			new RegExp('<'+tag+'\\b[^<>]*>', "ig"), | ||||
| 			new RegExp('</'+tag+'>', "ig") | ||||
| 		]; | ||||
| 		res[0].lastIndex = res[1].lastIndex = 0; | ||||
| 		var m; | ||||
| 		while((m = res[0].exec(str))) { | ||||
| 			var si = m.index; | ||||
| 			res[1].lastIndex = res[0].lastIndex; | ||||
| 			m = res[1].exec(str); | ||||
| 			if(!m) return null; | ||||
| 			var ef = res[1].lastIndex; | ||||
| 			out.push(str.slice(si, ef)); | ||||
| 			res[0].lastIndex = res[1].lastIndex; | ||||
| 		} | ||||
| 		return out.length == 0 ? null : out; | ||||
| 	}; | ||||
| })(); | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| function getdatastr(data)/*:?string*/ { | ||||
| 	if(!data) return null; | ||||
| 	if(data.content && data.type) return cc2str(data.content, true); | ||||
| 	if(data.data) return debom(data.data); | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| @ -27,10 +27,10 @@ function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getda | ||||
| /* OASIS does not comment on filename case sensitivity */ | ||||
| function safegetzipfile(zip, file/*:string*/) { | ||||
| 	var k = zip.FullPaths || keys(zip.files); | ||||
| 	var f = file.toLowerCase().replace(/[\/]/g, '\\'), g = f.replace(/\\/g,'\/'); | ||||
| 	var f = file.toLowerCase(), g = f.replace(/\//g,'\\'); | ||||
| 	for(var i=0; i<k.length; ++i) { | ||||
| 		var n = k[i].replace(/^Root Entry[\/]/,"").toLowerCase(); | ||||
| 		if(f == n || g == n) return zip.files ? zip.files[k[i]] : zip.FileIndex[i]; | ||||
| 		var n = k[i].toLowerCase(); | ||||
| 		if(f == n || g == n) return zip.files[k[i]]; | ||||
| 	} | ||||
| 	return null; | ||||
| } | ||||
| @ -53,45 +53,47 @@ function getzipstr(zip, file/*:string*/, safe/*:?boolean*/)/*:?string*/ { | ||||
| 	try { return getzipstr(zip, file); } catch(e) { return null; } | ||||
| } | ||||
| 
 | ||||
| function getzipbin(zip, file/*:string*/, safe/*:?boolean*/)/*:any*/ { | ||||
| 	if(!safe) return getdatabin(getzipfile(zip, file)); | ||||
| 	if(!file) return null; | ||||
| 	try { return getzipbin(zip, file); } catch(e) { return null; } | ||||
| } | ||||
| 
 | ||||
| function zipentries(zip) { | ||||
| 	var k = zip.FullPaths || keys(zip.files), o = []; | ||||
| 	for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i].replace(/^Root Entry[\/]/, "")); | ||||
| 	for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i]); | ||||
| 	return o.sort(); | ||||
| } | ||||
| 
 | ||||
| function zip_add_file(zip, path, content) { | ||||
| 	if(zip.FullPaths) { | ||||
| 		if(Array.isArray(content) && typeof content[0] == "string") { | ||||
| 			content = content.join(""); | ||||
| 		} | ||||
| 		if(typeof content == "string") { | ||||
| 			var res; | ||||
| 			if(has_buf) res = Buffer_from(content); | ||||
| 			/* TODO: investigate performance in Edge 13 */ | ||||
| 			//else if(typeof TextEncoder !== "undefined") res = new TextEncoder().encode(content);
 | ||||
| 			else res = utf8decode(content); | ||||
| 			return CFB.utils.cfb_add(zip, path, res); | ||||
| 		} | ||||
| 		CFB.utils.cfb_add(zip, path, content); | ||||
| 	} | ||||
| 	if(zip.FullPaths) CFB.utils.cfb_add(zip, path, content); | ||||
| 	else zip.file(path, content); | ||||
| } | ||||
| 
 | ||||
| function zip_new() { return CFB.utils.cfb_new(); } | ||||
| var jszip; | ||||
| /*:: declare var JSZipSync:any; */ | ||||
| /*global JSZipSync:true */ | ||||
| if(typeof JSZipSync !== 'undefined') jszip = JSZipSync; | ||||
| if(typeof exports !== 'undefined') { | ||||
| 	if(typeof module !== 'undefined' && module.exports) { | ||||
| 		if(typeof jszip === 'undefined') jszip = require('./jszip.js'); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function zip_new() { | ||||
| 	if(!jszip) return CFB.utils.cfb_new(); | ||||
| 	return new jszip(); | ||||
| } | ||||
| 
 | ||||
| function zip_read(d, o) { | ||||
| 	switch(o.type) { | ||||
| 		case "base64": return CFB.read(d, { type: "base64" }); | ||||
| 		case "binary": return CFB.read(d, { type: "binary" }); | ||||
| 		case "buffer": case "array": return CFB.read(d, { type: "buffer" }); | ||||
| 	var zip; | ||||
| 	if(jszip) switch(o.type) { | ||||
| 		case "base64": zip = new jszip(d, { base64:true }); break; | ||||
| 		case "binary": case "array": zip = new jszip(d, { base64:false }); break; | ||||
| 		case "buffer": zip = new jszip(d); break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	throw new Error("Unrecognized type " + o.type); | ||||
| 	else switch(o.type) { | ||||
| 		case "base64": zip = CFB.read(d, { type: "base64" }); break; | ||||
| 		case "binary": zip = CFB.read(d, { type: "binary" }); break; | ||||
| 		case "buffer": case "array": zip = CFB.read(d, { type: "buffer" }); break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	return zip; | ||||
| } | ||||
| 
 | ||||
| function resolve_path(path/*:string*/, base/*:string*/)/*:string*/ { | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n'; | ||||
| var attregexg=/\s([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g; | ||||
| var tagregex1=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?<>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'"<>\s=]+))*\s*[\/\?]?>/mg, tagregex2 = /<[^<>]*>/g; | ||||
| var tagregex = /*#__PURE__*/XML_HEADER.match(tagregex1) ? tagregex1 : tagregex2; | ||||
| var attregexg=/([^"\s?>\/]+)\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 nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/; | ||||
| function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/, skip_LC/*:?boolean*/)/*:any*/ { | ||||
| 	var z = ({}/*:any*/); | ||||
| @ -11,7 +12,7 @@ function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/, skip_LC/*:?boolean* | ||||
| 	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].slice(1); | ||||
| 		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; | ||||
| @ -32,26 +33,6 @@ function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/, skip_LC/*:?boolean* | ||||
| 	} | ||||
| 	return z; | ||||
| } | ||||
| function parsexmltagraw(tag/*:string*/, skip_root/*:?boolean*/, skip_LC/*:?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(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].slice(1); | ||||
| 		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; | ||||
| 		quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0; | ||||
| 		v = cc.slice(c+1+quot, cc.length-quot); | ||||
| 		if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
 | ||||
| 		z[q] = v; | ||||
| 		if(!skip_LC) z[q.toLowerCase()] = v; | ||||
| 	} | ||||
| 	return z; | ||||
| } | ||||
| function strip_ns(x/*:string*/)/*:string*/ { return x.replace(nsregex2, "<$1"); } | ||||
| 
 | ||||
| var encodings = { | ||||
| @ -61,26 +42,22 @@ var encodings = { | ||||
| 	'<': '<', | ||||
| 	'&': '&' | ||||
| }; | ||||
| var rencoding = /*#__PURE__*/evert(encodings); | ||||
| var rencoding = evert(encodings); | ||||
| //var rencstr = "&<>'\"".split("");
 | ||||
| 
 | ||||
| // TODO: CP remap (need to read file version to determine OS)
 | ||||
| var unescapexml/*:StringConv*/ = /*#__PURE__*/(function() { | ||||
| 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})_/g; | ||||
| 	function raw_unescapexml(text/*:string*/)/*:string*/ { | ||||
| 	var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/ig, coderegex = /_x([\da-fA-F]{4})_/ig; | ||||
| 	return function unescapexml(text/*:string*/)/*:string*/ { | ||||
| 		var s = text + '', i = s.indexOf("<![CDATA["); | ||||
| 		if(i == -1) 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 j = s.indexOf("]]>"); | ||||
| 		return raw_unescapexml(s.slice(0, i)) + s.slice(i+9,j) + raw_unescapexml(s.slice(j+3)); | ||||
| 	} | ||||
| 	return function unescapexml(text/*:string*/, xlsx/*:boolean*/) { | ||||
| 		var out = raw_unescapexml(text); | ||||
| 		return xlsx ? out.replace(/\r\n/g, "\n") : out; | ||||
| 		return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3)); | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f\uFFFE-\uFFFF]/g; | ||||
| var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g; | ||||
| function escapexml(text/*:string*/)/*: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) + "_";}); | ||||
| @ -99,24 +76,24 @@ function escapexlml(text/*:string*/)/*:string*/{ | ||||
| } | ||||
| 
 | ||||
| /* TODO: handle codepages */ | ||||
| var xlml_fixstr/*:StringConv*/ = /*#__PURE__*/(function() { | ||||
| var xlml_fixstr/*:StringConv*/ = (function() { | ||||
| 	var entregex = /&#(\d+);/g; | ||||
| 	function entrepl($$/*:string*/,$1/*:string*/)/*:string*/ { return String.fromCharCode(parseInt($1,10)); } | ||||
| 	return function xlml_fixstr(str/*:string*/)/*:string*/ { return str.replace(entregex,entrepl); }; | ||||
| })(); | ||||
| function xlml_unfixstr(str/*:string*/)/*:string*/ { return str.replace(/(\r\n|[\r\n])/g,"\
"); } | ||||
| var xlml_unfixstr/*:StringConv*/ = (function() { | ||||
| 	return function xlml_unfixstr(str/*:string*/)/*:string*/ { return str.replace(/(\r\n|[\r\n])/g,"\
"); }; | ||||
| })(); | ||||
| 
 | ||||
| /* note: xsd:boolean valid values: true / 1 / false / 0 */ | ||||
| function parsexmlbool(value/*:any*/)/*:boolean*/ { | ||||
| 	switch(value) { | ||||
| 		case 1: case true:  case '1': case 'true':  return true; | ||||
| 		case 0: case false: case '0': case 'false': return false; | ||||
| 		//default: throw new Error("Invalid xsd:boolean " + value);
 | ||||
| 		case 1: case true: case '1': case 'true': case 'TRUE': return true; | ||||
| 		/* case '0': case 'false': case 'FALSE':*/ | ||||
| 		default: return false; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| function utf8reada(orig/*:string*/)/*:string*/ { | ||||
| var utf8read/*:StringConv*/ = function utf8reada(orig/*:string*/)/*:string*/ { | ||||
| 	var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0; | ||||
| 	while (i < orig.length) { | ||||
| 		c = orig.charCodeAt(i++); | ||||
| @ -131,31 +108,9 @@ function utf8reada(orig/*:string*/)/*:string*/ { | ||||
| 		out += String.fromCharCode(0xDC00 + (w&1023)); | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| }; | ||||
| 
 | ||||
| function utf8readb(data) { | ||||
| 	var out = new_raw_buf(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; | ||||
| 		else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; } | ||||
| 		else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; } | ||||
| 		else { j = 4; | ||||
| 			w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63); | ||||
| 			w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023); | ||||
| 		} | ||||
| 		if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; } | ||||
| 		out[k++] = w%256; out[k++] = w>>>8; | ||||
| 	} | ||||
| 	return out.slice(0,k).toString('ucs2'); | ||||
| } | ||||
| 
 | ||||
| function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); } | ||||
| 
 | ||||
| var utf8corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3"; | ||||
| var utf8read = has_buf && (/*#__PURE__*/utf8readc(utf8corpus) == /*#__PURE__*/utf8reada(utf8corpus) && utf8readc || /*#__PURE__*/utf8readb(utf8corpus) == /*#__PURE__*/utf8reada(utf8corpus) && utf8readb) || utf8reada; | ||||
| 
 | ||||
| var utf8write/*:StringConv*/ = has_buf ? function(data) { return Buffer_from(data, 'utf8').toString("binary"); } : function(orig/*:string*/)/*:string*/ { | ||||
| var utf8write/*:StringConv*/ = function(orig/*:string*/)/*:string*/ { | ||||
| 	var out/*:Array<string>*/ = [], i = 0, c = 0, d = 0; | ||||
| 	while(i < orig.length) { | ||||
| 		c = orig.charCodeAt(i++); | ||||
| @ -181,7 +136,42 @@ var utf8write/*:StringConv*/ = has_buf ? function(data) { return Buffer_from(dat | ||||
| 	return out.join(""); | ||||
| }; | ||||
| 
 | ||||
| var htmldecode/*:{(s:string):string}*/ = /*#__PURE__*/(function() { | ||||
| if(has_buf) { | ||||
| 	var utf8readb = function utf8readb(data) { | ||||
| 		var out = Buffer.alloc(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; | ||||
| 			else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; } | ||||
| 			else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; } | ||||
| 			else { j = 4; | ||||
| 				w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63); | ||||
| 				w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023); | ||||
| 			} | ||||
| 			if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; } | ||||
| 			out[k++] = w%256; out[k++] = w>>>8; | ||||
| 		} | ||||
| 		return out.slice(0,k).toString('ucs2'); | ||||
| 	}; | ||||
| 	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'); }; | ||||
| 	if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc; | ||||
| 
 | ||||
| 	utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); }; | ||||
| } | ||||
| 
 | ||||
| // matches <foo>...</foo> extracts content
 | ||||
| var matchtag = (function() { | ||||
| 	var mtcache/*:{[k:string]:RegExp}*/ = ({}/*:any*/); | ||||
| 	return function matchtag(f/*:string*/,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',  '&'] | ||||
| @ -191,25 +181,30 @@ var htmldecode/*:{(s:string):string}*/ = /*#__PURE__*/(function() { | ||||
| 				// 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 ])[\t\n\r ]+$/,"$1") | ||||
| 				.replace(/[\t\n\r ]+$/,"") | ||||
| 				// Added line which removes any white space characters after and before html tags
 | ||||
| 				.replace(/>\s+/g,">").replace(/\b\s+</g,"<") | ||||
| 				.replace(/>\s+/g,">").replace(/\s+</g,"<") | ||||
| 				// Replace remaining new lines and spaces with space
 | ||||
| 				.replace(/[\t\n\r ]+/g, " ") | ||||
| 				// Replace <br> tags with new lines
 | ||||
| 				.replace(/<\s*[bB][rR]\s*\/?>/g,"\n") | ||||
| 				// Strip HTML elements
 | ||||
| 				.replace(/<[^<>]*>/g,""); | ||||
| 				.replace(/<[^>]*>/g,""); | ||||
| 		for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]); | ||||
| 		return o; | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^<"'>]*)>([\s\S]*)</; | ||||
| 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') ); | ||||
| };})(); | ||||
| var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</; | ||||
| function parseVector(data/*:string*/, opts)/*:Array<{v:string,t:string}>*/ { | ||||
| 	var h = parsexmltag(data); | ||||
| 
 | ||||
| 	var matches/*:Array<string>*/ = str_match_xml_ns_g(data, h.baseType)||[]; | ||||
| 	var matches/*:Array<string>*/ = data.match(vtregex(h.baseType))||[]; | ||||
| 	var res/*:Array<any>*/ = []; | ||||
| 	if(matches.length != h.size) { | ||||
| 		if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size); | ||||
| @ -243,23 +238,7 @@ function write_vt(s, xlsx/*:?boolean*/)/*:string*/ { | ||||
| 	throw new Error("Unable to serialize " + s); | ||||
| } | ||||
| 
 | ||||
| function xlml_normalize(d)/*:string*/ { | ||||
| 	if(has_buf &&/*::typeof Buffer !== "undefined" && d != null && d instanceof Buffer &&*/ Buffer.isBuffer(d)) return d.toString('utf8'); | ||||
| 	if(typeof d === 'string') return d; | ||||
| 	/* duktape */ | ||||
| 	if(typeof Uint8Array !== 'undefined' && d instanceof Uint8Array) return utf8read(a2s(ab2a(d))); | ||||
| 	throw new Error("Bad input format: expected Buffer or string"); | ||||
| } | ||||
| /* UOS uses CJK in tags, ODS uses invalid XML */ | ||||
| var xlmlregex = /<([\/]?)([^\s?><!\/:"]*:|)([^\s?<>:\/"]+)(?:\s+[^<>=?"'\s]+="[^"]*?")*\s*[\/]?>/mg; | ||||
| 
 | ||||
| var XMLNS = ({ | ||||
| 	CORE_PROPS: 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties', | ||||
| 	CUST_PROPS: "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties", | ||||
| 	EXT_PROPS: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", | ||||
| 	CT: 'http://schemas.openxmlformats.org/package/2006/content-types', | ||||
| 	RELS: 'http://schemas.openxmlformats.org/package/2006/relationships', | ||||
| 	TCMNT: 'http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments', | ||||
| 	'dc': 'http://purl.org/dc/elements/1.1/', | ||||
| 	'dcterms': 'http://purl.org/dc/terms/', | ||||
| 	'dcmitype': 'http://purl.org/dc/dcmitype/', | ||||
| @ -271,7 +250,7 @@ var XMLNS = ({ | ||||
| 	'xsd': 'http://www.w3.org/2001/XMLSchema' | ||||
| }/*:any*/); | ||||
| 
 | ||||
| var XMLNS_main = [ | ||||
| XMLNS.main = [ | ||||
| 	'http://schemas.openxmlformats.org/spreadsheetml/2006/main', | ||||
| 	'http://purl.oclc.org/ooxml/spreadsheetml/main', | ||||
| 	'http://schemas.microsoft.com/office/excel/2006/main', | ||||
|  | ||||
| @ -25,59 +25,53 @@ function write_double_le(b/*:RawBytes|CFBlob*/, v/*:number*/, idx/*:number*/) { | ||||
| 	b[idx + 7] = (e >> 4) | bs; | ||||
| } | ||||
| 
 | ||||
| var ___toBuffer = function(bufs/*:Array<Array<RawBytes> >*/)/*:RawBytes*/ { var x=[],w=10240; for(var i=0;i<bufs[0].length;++i) if(bufs[0][i]) for(var j=0,L=bufs[0][i].length;j<L;j+=w) x.push.apply(x, bufs[0][i].slice(j,j+w)); return x; }; | ||||
| var __toBuffer = has_buf ? function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0].map(function(x) { return Buffer.isBuffer(x) ? x : Buffer_from(x); })) : ___toBuffer(bufs);} : ___toBuffer; | ||||
| 
 | ||||
| var ___utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join("").replace(chr0,''); }; | ||||
| var __utf16le = has_buf ? function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/ || !buf_utf16le) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; } : ___utf16le; | ||||
| 
 | ||||
| var ___hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<s+l; ++i) ss.push(("0" + b[i].toString(16)).slice(-2)); return ss.join(""); }; | ||||
| var __hexlify = has_buf ? 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); } : ___hexlify; | ||||
| 
 | ||||
| var ___utf8 = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); }; | ||||
| var __utf8 = has_buf ? 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); } : ___utf8; | ||||
| 
 | ||||
| var ___lpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 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 ___lpp4 = function lpp4_(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";}; | ||||
| var __lpp4 = ___lpp4; | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| var ___double = function(b/*:RawBytes|CFBlob*/, idx/*:number*/) { return read_double_le(b, idx);}; | ||||
| var __double = ___double; | ||||
| 
 | ||||
| var is_buf = function is_buf_a(a) { return Array.isArray(a) || (typeof Uint8Array !== "undefined" && a instanceof Uint8Array); }; | ||||
| var __toBuffer = function(bufs/*:Array<Array<RawBytes> >*/)/*:RawBytes*/ { var x=[],w=10240; for(var i=0;i<bufs[0].length;++i) if(bufs[0][i]) for(var j=0,L=bufs[0][i].length;j<L;j+=w) x.push.apply(x, bufs[0][i].slice(j,j+w)); return x; }; | ||||
| var ___toBuffer = __toBuffer; | ||||
| var __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join("").replace(chr0,''); }; | ||||
| var ___utf16le = __utf16le; | ||||
| var __hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<s+l; ++i) ss.push(("0" + b[i].toString(16)).slice(-2)); return ss.join(""); }; | ||||
| var ___hexlify = __hexlify; | ||||
| var __utf8 = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); }; | ||||
| var ___utf8 = __utf8; | ||||
| var __lpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 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 __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; | ||||
| 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); }; | ||||
| 
 | ||||
| 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)*/ || !buf_utf16le) 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)*/ || !buf_utf16le) return ___lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len);}; | ||||
| 	__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); }; | ||||
| 	__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); }; | ||||
| 	is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a) || (typeof Uint8Array !== "undefined" && a instanceof Uint8Array); }; | ||||
| 	is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); }; | ||||
| } | ||||
| 
 | ||||
| /* from js-xls */ | ||||
| function cpdoit() { | ||||
| 	__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)) : "";}; | ||||
| 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)) : "";}; | ||||
| } | ||||
| if(typeof $cptable !== 'undefined') cpdoit(); | ||||
| 
 | ||||
| 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]; }; | ||||
| @ -91,7 +85,7 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ { | ||||
| 	switch(t) { | ||||
| 		case 'dbcs': | ||||
| 			loc = this.l; | ||||
| 			if(has_buf && Buffer.isBuffer(this)  && buf_utf16le) o = this.slice(this.l, this.l+2*size).toString("utf16le"); | ||||
| 			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; } | ||||
| 			size *= 2; | ||||
| 			break; | ||||
| @ -100,7 +94,7 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ { | ||||
| 		case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break; | ||||
| 
 | ||||
| 		case 'wstr': | ||||
| 			if(typeof $cptable !== 'undefined') o = $cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size)); | ||||
| 			if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size)); | ||||
| 			else return ReadShift.call(this, size, 'dbcs'); | ||||
| 			size = 2 * size; break; | ||||
| 
 | ||||
| @ -135,8 +129,8 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ { | ||||
| 			} 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)); | ||||
| 			if(typeof cptable !== 'undefined') { | ||||
| 				o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size)); | ||||
| 				break; | ||||
| 			} | ||||
| 		/* falls through */ | ||||
| @ -181,29 +175,21 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/ | ||||
| 		/*:: 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' || f == 'cpstr') { | ||||
| 		if(typeof $cptable !== 'undefined' && current_ansi == 874) { | ||||
| 	} 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 cpp = $cptable.utils.encode(current_ansi, val.charAt(i)); | ||||
| 				this[this.l + i] = cpp[0]; | ||||
| 				var cppayload = cptable.utils.encode(current_ansi, val.charAt(i)); | ||||
| 				this[this.l + i] = cppayload[0]; | ||||
| 			} | ||||
| 			size = val.length; | ||||
| 		} else if(typeof $cptable !== 'undefined' && f == 'cpstr') { | ||||
| 			cpp = $cptable.utils.encode(current_codepage, val); | ||||
| 			/* replace null bytes with _ when relevant */ | ||||
|       if(cpp.length == val.length) for(i = 0; i < val.length; ++i) if(cpp[i] == 0 && val.charCodeAt(i) != 0) cpp[i] = 0x5F; | ||||
|       if(cpp.length == 2 * val.length) for(i = 0; i < val.length; ++i) if(cpp[2*i] == 0 && cpp[2*i+1] == 0 && val.charCodeAt(i) != 0) cpp[2*i] = 0x5F; | ||||
| 			for(i = 0; i < cpp.length; ++i) this[this.l + i] = cpp[i]; | ||||
| 			size = cpp.length; | ||||
| 		} 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); | ||||
| 			size = val.length; | ||||
| 		} | ||||
| 		size = val.length; | ||||
| 	} else if(f === 'hex') { | ||||
| 		for(; i < t; ++i) { | ||||
| 			/*:: if(typeof val !== "string") throw new Error("unreachable"); */ | ||||
|  | ||||
| @ -12,16 +12,15 @@ 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 && R.f(data, length, opts); | ||||
| 		var d = (R.f||parsenoop)(data, length, opts); | ||||
| 		data.l = tgt; | ||||
| 		if(cb(d, R, RT)) return; | ||||
| 		if(cb(d, R.n, RT)) return; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* control buffer usage for fixed-length buffers */ | ||||
| function buf_array()/*:BufArray*/ { | ||||
| 	var bufs/*:Array<Block>*/ = [], blksz = has_buf ? 16384 : 2048; | ||||
| 	var has_buf_copy = has_buf && (typeof new_buf(blksz).copy == "function"); | ||||
| 	var bufs/*:Array<Block>*/ = [], blksz = has_buf ? 256 : 2048; | ||||
| 	var newblk = function ba_newblk(sz/*:number*/)/*:Block*/ { | ||||
| 		var o/*:Block*/ = (new_buf(sz)/*:any*/); | ||||
| 		prep_blob(o, 0); | ||||
| @ -32,11 +31,8 @@ function buf_array()/*:BufArray*/ { | ||||
| 
 | ||||
| 	var endbuf = function ba_endbuf() { | ||||
| 		if(!curbuf) return; | ||||
| 		// workaround for new Buffer(3).slice(0,0) bug in bun 0.1.3
 | ||||
| 		if(curbuf.l) { | ||||
| 			if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; } | ||||
| 			if(curbuf.length > 0) bufs.push(curbuf); | ||||
| 		} | ||||
| 		if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; } | ||||
| 		if(curbuf.length > 0) bufs.push(curbuf); | ||||
| 		curbuf = null; | ||||
| 	}; | ||||
| 
 | ||||
| @ -48,21 +44,16 @@ function buf_array()/*:BufArray*/ { | ||||
| 
 | ||||
| 	var end = function ba_end() { | ||||
| 		endbuf(); | ||||
| 		return bconcat(bufs); | ||||
| 	}; | ||||
| 	var end2 = function() { | ||||
| 		endbuf(); return bufs; | ||||
| 		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; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); }; | ||||
| 
 | ||||
| 	return ({ next:next, push:push, end:end, _bufs:bufs, end2:end2 }/*:any*/); | ||||
| 	return ({ next:next, push:push, end:end, _bufs:bufs }/*:any*/); | ||||
| } | ||||
| 
 | ||||
| function write_record(ba/*:BufArray*/, type/*:number*/, payload, length/*:?number*/) { | ||||
| 	var t/*:number*/ = +type, l; | ||||
| function write_record(ba/*:BufArray*/, type/*:string*/, payload, length/*:?number*/) { | ||||
| 	var t/*:number*/ = +XLSBRE[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*/; | ||||
|  | ||||
| @ -1,4 +0,0 @@ | ||||
| if(typeof cptable !== 'undefined') set_cptable(cptable); | ||||
| else if(typeof module !== "undefined" && typeof require !== 'undefined') { | ||||
| 	set_cptable(require('./dist/cpexcel.js')); | ||||
| } | ||||
							
								
								
									
										38
									
								
								bits/26_crypto.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										38
									
								
								bits/26_crypto.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| var OFFCRYPTO = {}; | ||||
| 
 | ||||
| var make_offcrypto = function(O, _crypto) { | ||||
| 	var crypto; | ||||
| 	if(typeof _crypto !== 'undefined') crypto = _crypto; | ||||
| 	else if(typeof require !== 'undefined') { | ||||
| 		try { crypto = require('crypto'); } | ||||
| 		catch(e) { crypto = null; } | ||||
| 	} | ||||
| 
 | ||||
| 	O.rc4 = function(key, data) { | ||||
| 		var S = new Array(256); | ||||
| 		var c = 0, i = 0, j = 0, t = 0; | ||||
| 		for(i = 0; i != 256; ++i) S[i] = i; | ||||
| 		for(i = 0; i != 256; ++i) { | ||||
| 			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255; | ||||
| 			t = S[i]; S[i] = S[j]; S[j] = t; | ||||
| 		} | ||||
| 		// $FlowIgnore
 | ||||
| 		i = j = 0; var out = new_raw_buf(data.length); | ||||
| 		for(c = 0; c != data.length; ++c) { | ||||
| 			i = (i + 1)&255; | ||||
| 			j = (j + S[i])%256; | ||||
| 			t = S[i]; S[i] = S[j]; S[j] = t; | ||||
| 			out[c] = (data[c] ^ S[(S[i]+S[j])&255]); | ||||
| 		} | ||||
| 		return out; | ||||
| 	}; | ||||
| 
 | ||||
| 	O.md5 = function(hex) { | ||||
| 		if(!crypto) throw new Error("Unsupported crypto"); | ||||
| 		return crypto.createHash('md5').update(hex).digest('hex'); | ||||
| 	}; | ||||
| }; | ||||
| /*:: declare var crypto:any; */ | ||||
| /*global crypto:true */ | ||||
| make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined); | ||||
| 
 | ||||
| @ -9,6 +9,7 @@ function fix_col(cstr/*:string*/)/*:string*/ { return cstr.replace(/^([A-Z])/,"$ | ||||
| function unfix_col(cstr/*:string*/)/*:string*/ { return cstr.replace(/^\$([A-Z])/,"$1"); } | ||||
| 
 | ||||
| function split_cell(cstr/*:string*/)/*:Array<string>*/ { 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) { | ||||
| @ -18,6 +19,7 @@ function decode_cell(cstr/*:string*/)/*:CellAddress*/ { | ||||
| 	} | ||||
| 	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=""; | ||||
| @ -42,17 +44,6 @@ function encode_range(cs/*:CellAddrSpec|Range*/,ce/*:?CellAddrSpec*/)/*:string*/ | ||||
| /*:: if(typeof ce !== 'string') throw "unreachable"; */ | ||||
| 	return cs == ce ? cs : cs + ":" + ce; | ||||
| } | ||||
| function fix_range(a1/*:string*/)/*:string*/ { | ||||
| 	var s = decode_range(a1); | ||||
| 	return "$" + encode_col(s.s.c) + "$" + encode_row(s.s.r) + ":$" + encode_col(s.e.c) + "$" + encode_row(s.e.r); | ||||
| } | ||||
| 
 | ||||
| // List of invalid characters needs to be tested further
 | ||||
| function formula_quote_sheet_name(sname/*:string*/, opts)/*:string*/ { | ||||
| 	if(!sname && !(opts && opts.biff <= 5 && opts.biff >= 2)) throw new Error("empty sheet name"); | ||||
| 	if (/[^\w\u4E00-\u9FFF\u3040-\u30FF]/.test(sname)) return "'" + sname.replace(/'/g, "''") + "'"; | ||||
| 	return sname; | ||||
| } | ||||
| 
 | ||||
| function safe_decode_range(range/*:string*/)/*:Range*/ { | ||||
| 	var o = {s:{c:0,r:0},e:{c:0,r:0}}; | ||||
| @ -70,8 +61,7 @@ function safe_decode_range(range/*:string*/)/*:Range*/ { | ||||
| 	} | ||||
| 	o.s.r = --idx; | ||||
| 
 | ||||
| 	if(i === len || cc != 10) { o.e.c=o.s.c; o.e.r=o.s.r; return o; } | ||||
| 	++i; | ||||
| 	if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; } | ||||
| 
 | ||||
| 	for(idx = 0; i != len; ++i) { | ||||
| 		if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break; | ||||
| @ -89,15 +79,14 @@ 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; } | ||||
| 	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; } | ||||
| } | ||||
| 
 | ||||
| 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(cell.t == "e") return BErr[cell.v] || cell.v; | ||||
| 	if(v == undefined) return safe_format_cell(cell, cell.v); | ||||
| 	return safe_format_cell(cell, v); | ||||
| } | ||||
| @ -108,19 +97,11 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ { | ||||
| 	return { SheetNames: [n], Sheets: sheets }; | ||||
| } | ||||
| 
 | ||||
| function sheet_new(opts) { | ||||
| 	var out = {}; | ||||
| 	var o = opts || {}; | ||||
| 	if(o.dense) out["!data"] = []; | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 	var o = opts || {}; | ||||
| 	var dense = _ws ? (_ws["!data"] != null) : o.dense; | ||||
| 	var dense = _ws ? Array.isArray(_ws) : o.dense; | ||||
| 	if(DENSE != null && dense == null) dense = DENSE; | ||||
| 	var ws/*:Worksheet*/ = _ws || (dense ? ({"!data": []}) : ({}/*:any*/)); | ||||
| 	if(dense && !ws["!data"]) ws["!data"] = []; | ||||
| 	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; | ||||
| @ -128,71 +109,54 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh | ||||
| 			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"; | ||||
| 	} | ||||
| 	var range/*:Range*/ = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}}/*:any*/); | ||||
| 	if(ws["!ref"]){ | ||||
| 	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 = (ws["!ref"] ? _range.e.r + 1 : 0); | ||||
| 	} else { | ||||
| 		range.s.c = range.e.c = range.s.r = range.e.r = 0; | ||||
| 		if(_R == -1) range.e.r = _R = _range.e.r + 1; | ||||
| 	} | ||||
| 	var row = [], seen = false; | ||||
| 	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"); | ||||
| 		var __R = _R + R; | ||||
| 		if(dense) { | ||||
| 			if(!ws["!data"][__R]) ws["!data"][__R] = []; | ||||
| 			row = ws["!data"][__R]; | ||||
| 		} | ||||
| 		var data_R = data[R]; | ||||
| 		for(var C = 0; C != data_R.length; ++C) { | ||||
| 			if(typeof data_R[C] === 'undefined') continue; | ||||
| 			var cell/*:Cell*/ = ({v: data_R[C], t:"" }/*:any*/); | ||||
| 			var __C = _C + C; | ||||
| 		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; | ||||
| 			seen = true; | ||||
| 			if(data_R[C] && typeof data_R[C] === 'object' && !Array.isArray(data_R[C]) && !(data_R[C] instanceof Date)) cell = data_R[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.nullError) { cell.t = 'e'; cell.v = 0; } | ||||
| 					else if(!o.sheetStubs) continue; | ||||
| 					else cell.t = 'z'; | ||||
| 				} | ||||
| 				else if(typeof cell.v === 'number') { | ||||
| 					if(isFinite(cell.v)) cell.t = 'n'; | ||||
| 					else if(isNaN(cell.v)) { cell.t = 'e'; cell.v = 0x0F; /* #VALUE! */ } | ||||
| 					else { cell.t = 'e'; cell.v = 0x07; /*# DIV/0 */ } | ||||
| 				} | ||||
| 				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 || table_fmt[14]; | ||||
| 					if(!o.UTC) cell.v = local_to_utc(cell.v); | ||||
| 					if(o.cellDates) { cell.t = 'd'; cell.w = SSF_format(cell.z, datenum(cell.v, o.date1904)); } | ||||
| 					else { cell.t = 'n'; cell.v = datenum(cell.v, o.date1904); cell.w = SSF_format(cell.z, cell.v); } | ||||
| 					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(dense) { | ||||
| 				if(row[__C] && row[__C].z) cell.z = row[__C].z; | ||||
| 				row[__C] = cell; | ||||
| 				if(!ws[__R]) ws[__R] = []; | ||||
| 				if(ws[__R][__C] && ws[__R][__C].z) cell.z = ws[__R][__C].z; | ||||
| 				ws[__R][__C] = cell; | ||||
| 			} else { | ||||
| 				var cell_ref = encode_col(__C) + (__R + 1)/*:any*/; | ||||
| 				var cell_ref = encode_cell(({c:__C,r:__R}/*:any*/)); | ||||
| 				if(ws[cell_ref] && ws[cell_ref].z) cell.z = ws[cell_ref].z; | ||||
| 				ws[cell_ref] = cell; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(seen && range.s.c < 10400000) ws['!ref'] = encode_range(range); | ||||
| 	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); } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,3 @@ | ||||
| function parse_Int32LE(data) { | ||||
| 	return data.read_shift(4, 'i'); | ||||
| } | ||||
| function write_UInt32LE(x/*:number*/, o) { | ||||
| 	if (!o) o = new_buf(4); | ||||
| 	o.write_shift(4, x); | ||||
| @ -91,19 +88,6 @@ function write_XLSBCell(cell/*:any*/, o/*:?Block*/) { | ||||
| 	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; | ||||
| @ -135,7 +119,8 @@ 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 RK = fInt === 0 ? __double([0, 0, 0, 0, (b[0] & 0xFC), b[1], b[2], b[3]], 0) : __readInt32LE(b, 0) >> 2; | ||||
| 	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; | ||||
| } | ||||
| function write_RkNumber(data/*:number*/, o) { | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| /* [MS-OLEPS] 2.2 PropertyType */ | ||||
| // Note: some tree shakers cannot handle VT_VECTOR | $CONST, hence extra vars
 | ||||
| //var VT_EMPTY    = 0x0000;
 | ||||
| //var VT_NULL     = 0x0001;
 | ||||
| var VT_I2       = 0x0002; | ||||
| @ -21,7 +20,7 @@ var VT_UI4      = 0x0013; | ||||
| //var VT_UI8      = 0x0015;
 | ||||
| //var VT_INT      = 0x0016;
 | ||||
| //var VT_UINT     = 0x0017;
 | ||||
| //var VT_LPSTR    = 0x001E;
 | ||||
| var VT_LPSTR    = 0x001E; | ||||
| //var VT_LPWSTR   = 0x001F;
 | ||||
| var VT_FILETIME = 0x0040; | ||||
| var VT_BLOB     = 0x0041; | ||||
| @ -33,9 +32,7 @@ var VT_BLOB     = 0x0041; | ||||
| var VT_CF       = 0x0047; | ||||
| //var VT_CLSID    = 0x0048;
 | ||||
| //var VT_VERSIONED_STREAM = 0x0049;
 | ||||
| //var VT_VECTOR   = 0x1000;
 | ||||
| var VT_VECTOR_VARIANT = 0x100C; | ||||
| var VT_VECTOR_LPSTR   = 0x101E; | ||||
| var VT_VECTOR   = 0x1000; | ||||
| //var VT_ARRAY    = 0x2000;
 | ||||
| 
 | ||||
| var VT_STRING   = 0x0050; // 2.3.3.1.11 VtString
 | ||||
| @ -44,118 +41,125 @@ var VT_CUSTOM   = [VT_STRING, VT_USTR]; | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */ | ||||
| var DocSummaryPIDDSI = { | ||||
| 	0x01: { n: 'CodePage', t: VT_I2 }, | ||||
| 	0x02: { n: 'Category', t: VT_STRING }, | ||||
| 	0x03: { n: 'PresentationFormat', t: VT_STRING }, | ||||
| 	0x04: { n: 'ByteCount', t: VT_I4 }, | ||||
| 	0x05: { n: 'LineCount', t: VT_I4 }, | ||||
| 	0x06: { n: 'ParagraphCount', t: VT_I4 }, | ||||
| 	0x07: { n: 'SlideCount', t: VT_I4 }, | ||||
| 	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_VARIANT /* VT_VECTOR | VT_VARIANT */ }, | ||||
| 	0x0d: { n: 'TitlesOfParts', t: VT_VECTOR_LPSTR /* VT_VECTOR | VT_LPSTR */ }, | ||||
| 	0x0e: { n: 'Manager', t: VT_STRING }, | ||||
| 	0x0f: { n: 'Company', t: VT_STRING }, | ||||
| 	0x10: { n: 'LinksUpToDate', t: VT_BOOL }, | ||||
| 	0x11: { n: 'CharacterCount', t: VT_I4 }, | ||||
| 	0x13: { n: 'SharedDoc', t: VT_BOOL }, | ||||
| 	0x16: { n: 'HyperlinksChanged', 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 }, | ||||
| 	0x1D: { n: 'Version', t: VT_STRING }, | ||||
| 	0xFF: {}, | ||||
| 	/* [MS-OLEPS] 2.18 */ | ||||
| 	0x80000000: { n: 'Locale', t: VT_UI4 }, | ||||
| 	0x80000003: { n: 'Behavior', t: VT_UI4 }, | ||||
| 	0x72627262: {} | ||||
| 	/*::[*/0x01/*::]*/: { n: 'CodePage', t: VT_I2 }, | ||||
| 	/*::[*/0x02/*::]*/: { n: 'Category', t: VT_STRING }, | ||||
| 	/*::[*/0x03/*::]*/: { n: 'PresentationFormat', t: VT_STRING }, | ||||
| 	/*::[*/0x04/*::]*/: { n: 'ByteCount', t: VT_I4 }, | ||||
| 	/*::[*/0x05/*::]*/: { n: 'LineCount', t: VT_I4 }, | ||||
| 	/*::[*/0x06/*::]*/: { n: 'ParagraphCount', t: VT_I4 }, | ||||
| 	/*::[*/0x07/*::]*/: { n: 'SlideCount', t: VT_I4 }, | ||||
| 	/*::[*/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 }, | ||||
| 	/*::[*/0x0e/*::]*/: { n: 'Manager', t: VT_STRING }, | ||||
| 	/*::[*/0x0f/*::]*/: { n: 'Company', t: VT_STRING }, | ||||
| 	/*::[*/0x10/*::]*/: { n: 'LinksUpToDate', t: VT_BOOL }, | ||||
| 	/*::[*/0x11/*::]*/: { n: 'CharacterCount', t: VT_I4 }, | ||||
| 	/*::[*/0x13/*::]*/: { n: 'SharedDoc', t: VT_BOOL }, | ||||
| 	/*::[*/0x16/*::]*/: { n: 'HyperlinksChanged', 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 }, | ||||
| 	/*::[*/0x1D/*::]*/: { n: 'Version', t: VT_STRING }, | ||||
| 	/*::[*/0xFF/*::]*/: {} | ||||
| }; | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */ | ||||
| var SummaryPIDSI = { | ||||
| 	0x01: { n: 'CodePage', t: VT_I2 }, | ||||
| 	0x02: { n: 'Title', t: VT_STRING }, | ||||
| 	0x03: { n: 'Subject', t: VT_STRING }, | ||||
| 	0x04: { n: 'Author', t: VT_STRING }, | ||||
| 	0x05: { n: 'Keywords', t: VT_STRING }, | ||||
| 	0x06: { n: 'Comments', t: VT_STRING }, | ||||
| 	0x07: { n: 'Template', t: VT_STRING }, | ||||
| 	0x08: { n: 'LastAuthor', t: VT_STRING }, | ||||
| 	0x09: { n: 'RevNumber', t: VT_STRING }, | ||||
| 	0x0A: { n: 'EditTime', t: VT_FILETIME }, | ||||
| 	0x0B: { n: 'LastPrinted', t: VT_FILETIME }, | ||||
| 	0x0C: { n: 'CreatedDate', t: VT_FILETIME }, | ||||
| 	0x0D: { n: 'ModifiedDate', t: VT_FILETIME }, | ||||
| 	0x0E: { n: 'PageCount', t: VT_I4 }, | ||||
| 	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 }, | ||||
| 	0xFF: {}, | ||||
| 	/* [MS-OLEPS] 2.18 */ | ||||
| 	0x80000000: { n: 'Locale', t: VT_UI4 }, | ||||
| 	0x80000003: { n: 'Behavior', t: VT_UI4 }, | ||||
| 	0x72627262: {} | ||||
| 	/*::[*/0x01/*::]*/: { n: 'CodePage', t: VT_I2 }, | ||||
| 	/*::[*/0x02/*::]*/: { n: 'Title', t: VT_STRING }, | ||||
| 	/*::[*/0x03/*::]*/: { n: 'Subject', t: VT_STRING }, | ||||
| 	/*::[*/0x04/*::]*/: { n: 'Author', t: VT_STRING }, | ||||
| 	/*::[*/0x05/*::]*/: { n: 'Keywords', t: VT_STRING }, | ||||
| 	/*::[*/0x06/*::]*/: { n: 'Comments', t: VT_STRING }, | ||||
| 	/*::[*/0x07/*::]*/: { n: 'Template', t: VT_STRING }, | ||||
| 	/*::[*/0x08/*::]*/: { n: 'LastAuthor', t: VT_STRING }, | ||||
| 	/*::[*/0x09/*::]*/: { n: 'RevNumber', t: VT_STRING }, | ||||
| 	/*::[*/0x0A/*::]*/: { n: 'EditTime', t: VT_FILETIME }, | ||||
| 	/*::[*/0x0B/*::]*/: { n: 'LastPrinted', t: VT_FILETIME }, | ||||
| 	/*::[*/0x0C/*::]*/: { n: 'CreatedDate', t: VT_FILETIME }, | ||||
| 	/*::[*/0x0D/*::]*/: { n: 'ModifiedDate', t: VT_FILETIME }, | ||||
| 	/*::[*/0x0E/*::]*/: { n: 'PageCount', t: VT_I4 }, | ||||
| 	/*::[*/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 }, | ||||
| 	/*::[*/0xFF/*::]*/: {} | ||||
| }; | ||||
| 
 | ||||
| /* [MS-OLEPS] 2.18 */ | ||||
| var SpecialProperties = { | ||||
| 	/*::[*/0x80000000/*::]*/: { n: 'Locale', t: VT_UI4 }, | ||||
| 	/*::[*/0x80000003/*::]*/: { n: 'Behavior', t: VT_UI4 }, | ||||
| 	/*::[*/0x72627262/*::]*/: {} | ||||
| }; | ||||
| 
 | ||||
| (function() { | ||||
| 	for(var y in SpecialProperties) if(Object.prototype.hasOwnProperty.call(SpecialProperties, 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
 | ||||
| 	0x0002: "CA", // Canada
 | ||||
| 	0x0003: "", // Latin America (except Brazil)
 | ||||
| 	0x0007: "RU", // Russia
 | ||||
| 	0x0014: "EG", // Egypt
 | ||||
| 	0x001E: "GR", // Greece
 | ||||
| 	0x001F: "NL", // Netherlands
 | ||||
| 	0x0020: "BE", // Belgium
 | ||||
| 	0x0021: "FR", // France
 | ||||
| 	0x0022: "ES", // Spain
 | ||||
| 	0x0024: "HU", // Hungary
 | ||||
| 	0x0027: "IT", // Italy
 | ||||
| 	0x0029: "CH", // Switzerland
 | ||||
| 	0x002B: "AT", // Austria
 | ||||
| 	0x002C: "GB", // United Kingdom
 | ||||
| 	0x002D: "DK", // Denmark
 | ||||
| 	0x002E: "SE", // Sweden
 | ||||
| 	0x002F: "NO", // Norway
 | ||||
| 	0x0030: "PL", // Poland
 | ||||
| 	0x0031: "DE", // Germany
 | ||||
| 	0x0034: "MX", // Mexico
 | ||||
| 	0x0037: "BR", // Brazil
 | ||||
| 	0x003d: "AU", // Australia
 | ||||
| 	0x0040: "NZ", // New Zealand
 | ||||
| 	0x0042: "TH", // Thailand
 | ||||
| 	0x0051: "JP", // Japan
 | ||||
| 	0x0052: "KR", // Korea
 | ||||
| 	0x0054: "VN", // Viet Nam
 | ||||
| 	0x0056: "CN", // China
 | ||||
| 	0x005A: "TR", // Turkey
 | ||||
| 	0x0069: "JS", // Ramastan
 | ||||
| 	0x00D5: "DZ", // Algeria
 | ||||
| 	0x00D8: "MA", // Morocco
 | ||||
| 	0x00DA: "LY", // Libya
 | ||||
| 	0x015F: "PT", // Portugal
 | ||||
| 	0x0162: "IS", // Iceland
 | ||||
| 	0x0166: "FI", // Finland
 | ||||
| 	0x01A4: "CZ", // Czech Republic
 | ||||
| 	0x0376: "TW", // Taiwan
 | ||||
| 	0x03C1: "LB", // Lebanon
 | ||||
| 	0x03C2: "JO", // Jordan
 | ||||
| 	0x03C3: "SY", // Syria
 | ||||
| 	0x03C4: "IQ", // Iraq
 | ||||
| 	0x03C5: "KW", // Kuwait
 | ||||
| 	0x03C6: "SA", // Saudi Arabia
 | ||||
| 	0x03CB: "AE", // United Arab Emirates
 | ||||
| 	0x03CC: "IL", // Israel
 | ||||
| 	0x03CE: "QA", // Qatar
 | ||||
| 	0x03D5: "IR", // Iran
 | ||||
| 	0xFFFF: "US"  // United States
 | ||||
| 	/*::[*/0x0001/*::]*/: "US", // United States
 | ||||
| 	/*::[*/0x0002/*::]*/: "CA", // Canada
 | ||||
| 	/*::[*/0x0003/*::]*/: "", // Latin America (except Brazil)
 | ||||
| 	/*::[*/0x0007/*::]*/: "RU", // Russia
 | ||||
| 	/*::[*/0x0014/*::]*/: "EG", // Egypt
 | ||||
| 	/*::[*/0x001E/*::]*/: "GR", // Greece
 | ||||
| 	/*::[*/0x001F/*::]*/: "NL", // Netherlands
 | ||||
| 	/*::[*/0x0020/*::]*/: "BE", // Belgium
 | ||||
| 	/*::[*/0x0021/*::]*/: "FR", // France
 | ||||
| 	/*::[*/0x0022/*::]*/: "ES", // Spain
 | ||||
| 	/*::[*/0x0024/*::]*/: "HU", // Hungary
 | ||||
| 	/*::[*/0x0027/*::]*/: "IT", // Italy
 | ||||
| 	/*::[*/0x0029/*::]*/: "CH", // Switzerland
 | ||||
| 	/*::[*/0x002B/*::]*/: "AT", // Austria
 | ||||
| 	/*::[*/0x002C/*::]*/: "GB", // United Kingdom
 | ||||
| 	/*::[*/0x002D/*::]*/: "DK", // Denmark
 | ||||
| 	/*::[*/0x002E/*::]*/: "SE", // Sweden
 | ||||
| 	/*::[*/0x002F/*::]*/: "NO", // Norway
 | ||||
| 	/*::[*/0x0030/*::]*/: "PL", // Poland
 | ||||
| 	/*::[*/0x0031/*::]*/: "DE", // Germany
 | ||||
| 	/*::[*/0x0034/*::]*/: "MX", // Mexico
 | ||||
| 	/*::[*/0x0037/*::]*/: "BR", // Brazil
 | ||||
| 	/*::[*/0x003d/*::]*/: "AU", // Australia
 | ||||
| 	/*::[*/0x0040/*::]*/: "NZ", // New Zealand
 | ||||
| 	/*::[*/0x0042/*::]*/: "TH", // Thailand
 | ||||
| 	/*::[*/0x0051/*::]*/: "JP", // Japan
 | ||||
| 	/*::[*/0x0052/*::]*/: "KR", // Korea
 | ||||
| 	/*::[*/0x0054/*::]*/: "VN", // Viet Nam
 | ||||
| 	/*::[*/0x0056/*::]*/: "CN", // China
 | ||||
| 	/*::[*/0x005A/*::]*/: "TR", // Turkey
 | ||||
| 	/*::[*/0x0069/*::]*/: "JS", // Ramastan
 | ||||
| 	/*::[*/0x00D5/*::]*/: "DZ", // Algeria
 | ||||
| 	/*::[*/0x00D8/*::]*/: "MA", // Morocco
 | ||||
| 	/*::[*/0x00DA/*::]*/: "LY", // Libya
 | ||||
| 	/*::[*/0x015F/*::]*/: "PT", // Portugal
 | ||||
| 	/*::[*/0x0162/*::]*/: "IS", // Iceland
 | ||||
| 	/*::[*/0x0166/*::]*/: "FI", // Finland
 | ||||
| 	/*::[*/0x01A4/*::]*/: "CZ", // Czech Republic
 | ||||
| 	/*::[*/0x0376/*::]*/: "TW", // Taiwan
 | ||||
| 	/*::[*/0x03C1/*::]*/: "LB", // Lebanon
 | ||||
| 	/*::[*/0x03C2/*::]*/: "JO", // Jordan
 | ||||
| 	/*::[*/0x03C3/*::]*/: "SY", // Syria
 | ||||
| 	/*::[*/0x03C4/*::]*/: "IQ", // Iraq
 | ||||
| 	/*::[*/0x03C5/*::]*/: "KW", // Kuwait
 | ||||
| 	/*::[*/0x03C6/*::]*/: "SA", // Saudi Arabia
 | ||||
| 	/*::[*/0x03CB/*::]*/: "AE", // United Arab Emirates
 | ||||
| 	/*::[*/0x03CC/*::]*/: "IL", // Israel
 | ||||
| 	/*::[*/0x03CE/*::]*/: "QA", // Qatar
 | ||||
| 	/*::[*/0x03D5/*::]*/: "IR", // Iran
 | ||||
| 	/*::[*/0xFFFF/*::]*/: "US"  // United States
 | ||||
| }; | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.127 */ | ||||
| @ -185,7 +189,7 @@ function rgbify(arr/*:Array<number>*/)/*:Array<[number, number, number]>*/ { ret | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.161 */ | ||||
| /* [MS-XLSB] 2.5.75 Icv */ | ||||
| var _XLSIcv = /*#__PURE__*/ rgbify([ | ||||
| var _XLSIcv = rgbify([ | ||||
| 	/* Color Constants */ | ||||
| 	0x000000, | ||||
| 	0xFFFFFF, | ||||
| @ -258,8 +262,8 @@ var _XLSIcv = /*#__PURE__*/ rgbify([ | ||||
| 	0x333333, | ||||
| 
 | ||||
| 	/* Other entries to appease BIFF8/12 */ | ||||
| 	0x000000, /* 0x40 icvForeground ?? */ | ||||
| 	0xFFFFFF, /* 0x41 icvBackground ?? */ | ||||
| 	0xFFFFFF, /* 0x40 icvForeground ?? */ | ||||
| 	0x000000, /* 0x41 icvBackground ?? */ | ||||
| 	0x000000, /* 0x42 icvFrame ?? */ | ||||
| 	0x000000, /* 0x43 icv3D ?? */ | ||||
| 	0x000000, /* 0x44 icv3DText ?? */ | ||||
| @ -277,47 +281,18 @@ var _XLSIcv = /*#__PURE__*/ rgbify([ | ||||
| 	0x000000, /* 0x50 icvInfoBk ?? */ | ||||
| 	0x000000 /* 0x51 icvInfoText ?? */ | ||||
| ]); | ||||
| var XLSIcv = /*#__PURE__*/dup(_XLSIcv); | ||||
| 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?" | ||||
| 	/*::[*/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);
 | ||||
| var RBErr = { | ||||
| 	"#NULL!":        0x00, | ||||
| 	"#DIV/0!":       0x07, | ||||
| 	"#VALUE!":       0x0F, | ||||
| 	"#REF!":         0x17, | ||||
| 	"#NAME?":        0x1D, | ||||
| 	"#NUM!":         0x24, | ||||
| 	"#N/A":          0x2A, | ||||
| 	"#GETTING_DATA": 0x2B, | ||||
| 	"#WTF?":         0xFF | ||||
| }; | ||||
| 
 | ||||
| var XLSLblBuiltIn = [ | ||||
| 	"_xlnm.Consolidate_Area", | ||||
| 	"_xlnm.Auto_Open", | ||||
| 	"_xlnm.Auto_Close", | ||||
| 	"_xlnm.Extract", | ||||
| 	"_xlnm.Database", | ||||
| 	"_xlnm.Criteria", | ||||
| 	"_xlnm.Print_Area", | ||||
| 	"_xlnm.Print_Titles", | ||||
| 	"_xlnm.Recorder", | ||||
| 	"_xlnm.Data_Form", | ||||
| 	"_xlnm.Auto_Activate", | ||||
| 	"_xlnm.Auto_Deactivate", | ||||
| 	"_xlnm.Sheet_Title", | ||||
| 	"_xlnm._FilterDatabase" | ||||
| ]; | ||||
| 
 | ||||
| var RBErr = evert_num(BErr); | ||||
|  | ||||
							
								
								
									
										199
									
								
								bits/30_ctype.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										199
									
								
								bits/30_ctype.js
									
									
									
									
									
								
							| @ -5,38 +5,14 @@ | ||||
| var ct2type/*{[string]:string}*/ = ({ | ||||
| 	/* Workbook */ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks", | ||||
| 	"application/vnd.ms-excel.sheet.macroEnabled.main+xml": "workbooks", | ||||
| 	"application/vnd.ms-excel.sheet.binary.macroEnabled.main": "workbooks", | ||||
| 	"application/vnd.ms-excel.addin.macroEnabled.main+xml": "workbooks", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml": "workbooks", | ||||
| 
 | ||||
| 	/* Worksheet */ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml": "sheets", | ||||
| 	"application/vnd.ms-excel.worksheet": "sheets", | ||||
| 	"application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */ | ||||
| 
 | ||||
| 	/* Chartsheet */ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml": "charts", | ||||
| 	"application/vnd.ms-excel.chartsheet": "charts", | ||||
| 
 | ||||
| 	/* Macrosheet */ | ||||
| 	"application/vnd.ms-excel.macrosheet+xml": "macros", | ||||
| 	"application/vnd.ms-excel.macrosheet": "macros", | ||||
| 	"application/vnd.ms-excel.intlmacrosheet": "TODO", | ||||
| 	"application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */ | ||||
| 
 | ||||
| 	/* Dialogsheet */ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml": "dialogs", | ||||
| 	"application/vnd.ms-excel.dialogsheet": "dialogs", | ||||
| 
 | ||||
| 	/* Shared Strings */ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml": "strs", | ||||
| 	"application/vnd.ms-excel.sharedStrings": "strs", | ||||
| 
 | ||||
| 	/* Styles */ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml": "styles", | ||||
| 	"application/vnd.ms-excel.styles": "styles", | ||||
| 
 | ||||
| 	/* File Properties */ | ||||
| 	"application/vnd.openxmlformats-package.core-properties+xml": "coreprops", | ||||
| 	"application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops", | ||||
| @ -46,16 +22,6 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO", | ||||
| 
 | ||||
| 	/* Comments */ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml": "comments", | ||||
| 	"application/vnd.ms-excel.comments": "comments", | ||||
| 	"application/vnd.ms-excel.threadedcomments+xml": "threadedcomments", | ||||
| 	"application/vnd.ms-excel.person+xml": "people", | ||||
| 
 | ||||
| 	/* Metadata (Stock/Geography and Dynamic Array) */ | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata", | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "metadata", | ||||
| 
 | ||||
| 	/* PivotTable */ | ||||
| 	"application/vnd.ms-excel.pivotTable": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO", | ||||
| @ -94,6 +60,10 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.ms-excel.externalLink": "links", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links", | ||||
| 
 | ||||
| 	/* Metadata */ | ||||
| 	"application/vnd.ms-excel.sheetMetadata": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO", | ||||
| 
 | ||||
| 	/* PivotCache */ | ||||
| 	"application/vnd.ms-excel.pivotCacheDefinition": "TODO", | ||||
| 	"application/vnd.ms-excel.pivotCacheRecords": "TODO", | ||||
| @ -141,7 +111,7 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 
 | ||||
| 	/* VBA */ | ||||
| 	"application/vnd.ms-office.vbaProject": "vba", | ||||
| 	"application/vnd.ms-office.vbaProjectSignature": "TODO", | ||||
| 	"application/vnd.ms-office.vbaProjectSignature": "vba", | ||||
| 
 | ||||
| 	/* Volatile Dependencies */ | ||||
| 	"application/vnd.ms-office.volatileDependencies": "TODO", | ||||
| @ -176,54 +146,59 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"sheet": "js" | ||||
| }/*:any*/); | ||||
| 
 | ||||
| var CT_LIST = { | ||||
| 	workbooks: { | ||||
| 		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 */ | ||||
| 		xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml", | ||||
| 		xlsb: "application/vnd.ms-excel.sharedStrings" | ||||
| 	}, | ||||
| 	comments: { /* Comments */ | ||||
| 		xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", | ||||
| 		xlsb: "application/vnd.ms-excel.comments" | ||||
| 	}, | ||||
| 	sheets: { /* Worksheet */ | ||||
| 		xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", | ||||
| 		xlsb: "application/vnd.ms-excel.worksheet" | ||||
| 	}, | ||||
| 	charts: { /* Chartsheet */ | ||||
| 		xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml", | ||||
| 		xlsb: "application/vnd.ms-excel.chartsheet" | ||||
| 	}, | ||||
| 	dialogs: { /* Dialogsheet */ | ||||
| 		xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml", | ||||
| 		xlsb: "application/vnd.ms-excel.dialogsheet" | ||||
| 	}, | ||||
| 	macros: { /* Macrosheet (Excel 4.0 Macros) */ | ||||
| 		xlsx: "application/vnd.ms-excel.macrosheet+xml", | ||||
| 		xlsb: "application/vnd.ms-excel.macrosheet" | ||||
| 	}, | ||||
| 	metadata: { /* Metadata (Stock/Geography and Dynamic Array) */ | ||||
| 		xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml", | ||||
| 		xlsb: "application/vnd.ms-excel.sheetMetadata" | ||||
| 	}, | ||||
| 	styles: { /* Styles */ | ||||
| 		xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", | ||||
| 		xlsb: "application/vnd.ms-excel.styles" | ||||
| 	} | ||||
| }; | ||||
| var CT_LIST = (function(){ | ||||
| 	var o = { | ||||
| 		workbooks: { | ||||
| 			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 */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.sharedStrings" | ||||
| 		}, | ||||
| 		comments: { /* Comments */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.comments" | ||||
| 		}, | ||||
| 		sheets: { /* Worksheet */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.worksheet" | ||||
| 		}, | ||||
| 		charts: { /* Chartsheet */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.chartsheet" | ||||
| 		}, | ||||
| 		dialogs: { /* Dialogsheet */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.dialogsheet" | ||||
| 		}, | ||||
| 		macros: { /* Macrosheet (Excel 4.0 Macros) */ | ||||
| 			xlsx: "application/vnd.ms-excel.macrosheet+xml", | ||||
| 			xlsb: "application/vnd.ms-excel.macrosheet" | ||||
| 		}, | ||||
| 		styles: { /* Styles */ | ||||
| 			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", | ||||
| 			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){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); }); | ||||
| 	return o; | ||||
| })(); | ||||
| 
 | ||||
| var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type); | ||||
| 
 | ||||
| XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types'; | ||||
| 
 | ||||
| function new_ct()/*:any*/ { | ||||
| 	return ({ | ||||
| 		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], | ||||
| 		rels:[], strs:[], comments:[], threadedcomments:[], links:[], | ||||
| 		rels:[], strs:[], comments:[], links:[], | ||||
| 		coreprops:[], extprops:[], custprops:[], themes:[], styles:[], | ||||
| 		calcchains:[], vba: [], drawings: [], metadata: [], people:[], | ||||
| 		calcchains:[], vba: [], drawings: [], | ||||
| 		TODO:[], xmlns: "" }/*:any*/); | ||||
| } | ||||
| 
 | ||||
| @ -236,7 +211,7 @@ function parse_ct(data/*:?string*/) { | ||||
| 		switch(y[0].replace(nsregex,"<")) { | ||||
| 			case '<?xml': break; | ||||
| 			case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break; | ||||
| 			case '<Default': ctext[y.Extension.toLowerCase()] = y.ContentType; break; | ||||
| 			case '<Default': ctext[y.Extension] = y.ContentType; break; | ||||
| 			case '<Override': | ||||
| 				if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName); | ||||
| 				break; | ||||
| @ -251,37 +226,36 @@ function parse_ct(data/*:?string*/) { | ||||
| 	return ct; | ||||
| } | ||||
| 
 | ||||
| function write_ct(ct, opts, raw)/*:string*/ { | ||||
| 	var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type); | ||||
| var CTYPE_XML_ROOT = writextag('Types', null, { | ||||
| 	'xmlns': XMLNS.CT, | ||||
| 	'xmlns:xsd': XMLNS.xsd, | ||||
| 	'xmlns:xsi': XMLNS.xsi | ||||
| }); | ||||
| 
 | ||||
| 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'], | ||||
| 	['gif', 'image/gif'], | ||||
| 	['emf', 'image/x-emf'], | ||||
| 	['wmf', 'image/x-wmf'], | ||||
| 	['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'], | ||||
| 	['tif', 'image/tiff'], ['tiff', 'image/tiff'], | ||||
| 	['pdf', 'application/pdf'], | ||||
| 	['rels', type2ct.rels[0]] | ||||
| ].map(function(x) { | ||||
| 	return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]}); | ||||
| }); | ||||
| 
 | ||||
| function write_ct(ct, opts)/*:string*/ { | ||||
| 	var o/*:Array<string>*/ = [], v; | ||||
| 
 | ||||
| 	if(!raw) { | ||||
| 		o[o.length] = (XML_HEADER); | ||||
| 		o[o.length] = writextag('Types', null, { | ||||
| 			'xmlns': XMLNS.CT, | ||||
| 			'xmlns:xsd': XMLNS.xsd, | ||||
| 			'xmlns:xsi': XMLNS.xsi | ||||
| 		}); | ||||
| 		o = o.concat([ | ||||
| 			['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'], | ||||
| 			['gif', 'image/gif'], | ||||
| 			['emf', 'image/x-emf'], | ||||
| 			['wmf', 'image/x-wmf'], | ||||
| 			['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'], | ||||
| 			['tif', 'image/tiff'], ['tiff', 'image/tiff'], | ||||
| 			['pdf', 'application/pdf'], | ||||
| 			['rels', 'application/vnd.openxmlformats-package.relationships+xml'] | ||||
| 		].map(function(x) { | ||||
| 			return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]}); | ||||
| 		})); | ||||
| 	} | ||||
| 	o[o.length] = (XML_HEADER); | ||||
| 	o[o.length] = (CTYPE_XML_ROOT); | ||||
| 	o = o.concat(CTYPE_DEFAULTS); | ||||
| 
 | ||||
| 	/* only write first instance */ | ||||
| 	var f1 = function(w) { | ||||
| @ -289,7 +263,7 @@ function write_ct(ct, opts, raw)/*:string*/ { | ||||
| 			v = ct[w][0]; | ||||
| 			o[o.length] = (writextag('Override', null, { | ||||
| 				'PartName': (v[0] == '/' ? "":"/") + v, | ||||
| 				'ContentType': CT_LIST[w][opts.bookType] || CT_LIST[w]['xlsx'] | ||||
| 				'ContentType': CT_LIST[w][opts.bookType || 'xlsx'] | ||||
| 			})); | ||||
| 		} | ||||
| 	}; | ||||
| @ -299,7 +273,7 @@ function write_ct(ct, opts, raw)/*:string*/ { | ||||
| 		(ct[w]||[]).forEach(function(v) { | ||||
| 			o[o.length] = (writextag('Override', null, { | ||||
| 				'PartName': (v[0] == '/' ? "":"/") + v, | ||||
| 				'ContentType': CT_LIST[w][opts.bookType] || CT_LIST[w]['xlsx'] | ||||
| 				'ContentType': CT_LIST[w][opts.bookType || 'xlsx'] | ||||
| 			})); | ||||
| 		}); | ||||
| 	}; | ||||
| @ -322,10 +296,7 @@ function write_ct(ct, opts, raw)/*:string*/ { | ||||
| 	['coreprops', 'extprops', 'custprops'].forEach(f3); | ||||
| 	f3('vba'); | ||||
| 	f3('comments'); | ||||
| 	f3('threadedcomments'); | ||||
| 	f3('drawings'); | ||||
| 	f2('metadata'); | ||||
| 	f3('people'); | ||||
| 	if(!raw && o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
|  | ||||
| @ -9,28 +9,6 @@ var RELS = ({ | ||||
| 	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", | ||||
| 	CMNT: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", | ||||
| 	CORE_PROPS: "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", | ||||
| 	EXT_PROPS: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', | ||||
| 	CUST_PROPS: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties', | ||||
| 	SST: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings", | ||||
| 	STY: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", | ||||
| 	THEME: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", | ||||
| 	CHART: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", | ||||
| 	CHARTEX: "http://schemas.microsoft.com/office/2014/relationships/chartEx", | ||||
| 	CS: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet", | ||||
| 	WS: [ | ||||
| 		"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", | ||||
| 		"http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet" | ||||
| 	], | ||||
| 	DS: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet", | ||||
| 	MS: "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet", | ||||
| 	IMG: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", | ||||
| 	DRAW: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing", | ||||
| 	XLMETA: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata", | ||||
| 	TCMNT: "http://schemas.microsoft.com/office/2017/10/relationships/threadedComment", | ||||
| 	PEOPLE: "http://schemas.microsoft.com/office/2017/10/relationships/person", | ||||
| 	CONN: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/connections", | ||||
| 	VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject" | ||||
| }/*:any*/); | ||||
| 
 | ||||
| @ -52,7 +30,7 @@ function parse_rels(data/*:?string*/, currentFilePath/*:string*/) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		/* 9.3.2.2 OPC_Relationships */ | ||||
| 		if (y[0] === '<Relationship') { | ||||
| 			var rel = {}; rel.Type = y.Type; rel.Target = unescapexml(y.Target); rel.Id = y.Id; if(y.TargetMode) rel.TargetMode = y.TargetMode; | ||||
| 			var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode; | ||||
| 			var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath); | ||||
| 			rels[canonictarget] = rel; | ||||
| 			hash[y.Id] = rel; | ||||
| @ -62,13 +40,16 @@ function parse_rels(data/*:?string*/, currentFilePath/*:string*/) { | ||||
| 	return rels; | ||||
| } | ||||
| 
 | ||||
| XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships'; | ||||
| 
 | ||||
| var RELS_ROOT = writextag('Relationships', null, { | ||||
| 	//'xmlns:ns0': XMLNS.RELS,
 | ||||
| 	'xmlns': XMLNS.RELS | ||||
| }); | ||||
| 
 | ||||
| /* TODO */ | ||||
| function write_rels(rels)/*:string*/ { | ||||
| 	var o = [XML_HEADER, writextag('Relationships', null, { | ||||
| 		//'xmlns:ns0': XMLNS.RELS,
 | ||||
| 		'xmlns': XMLNS.RELS | ||||
| 	})]; | ||||
| 	var o = [XML_HEADER, RELS_ROOT]; | ||||
| 	keys(rels['!id']).forEach(function(rid) { | ||||
| 		o[o.length] = (writextag('Relationship', null, rels['!id'][rid])); | ||||
| 	}); | ||||
| @ -76,17 +57,16 @@ 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*/ { | ||||
| 	if(!relobj) relobj = {}; | ||||
| 	if(!rels['!id']) rels['!id'] = {}; | ||||
| 	if(!rels['!idx']) rels['!idx'] = 1; | ||||
| 	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */} | ||||
| 	rels['!idx'] = rId + 1; | ||||
| 	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.HLINK, RELS.XPATH, RELS.XMISS].indexOf(relobj.Type) > -1) relobj.TargetMode = "External"; | ||||
| 	else if(RELS_EXTERN.indexOf(relobj.Type) > -1) 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; | ||||
|  | ||||
| @ -1,61 +1,65 @@ | ||||
| /* Open Document Format for Office Applications (OpenDocument) Version 1.2 */ | ||||
| /* Part 3 Section 4 Manifest File */ | ||||
| var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet"; | ||||
| function parse_manifest(d, opts) { | ||||
|   var str = xlml_normalize(d); | ||||
|   var Rn; | ||||
|   var FEtag; | ||||
|   while (Rn = xlmlregex.exec(str)) | ||||
|     switch (Rn[3]) { | ||||
|       case "manifest": | ||||
|         break; | ||||
|       case "file-entry": | ||||
|         FEtag = parsexmltag(Rn[0], false); | ||||
|         if (FEtag.path == "/" && FEtag.type !== CT_ODS) | ||||
|           throw new Error("This OpenDocument is not a spreadsheet"); | ||||
|         break; | ||||
|       case "encryption-data": | ||||
|       case "algorithm": | ||||
|       case "start-key-generation": | ||||
|       case "key-derivation": | ||||
|         throw new Error("Unsupported ODS Encryption"); | ||||
|       default: | ||||
|         if (opts && opts.WTF) | ||||
|           throw Rn; | ||||
|     } | ||||
| 	var str = xlml_normalize(d); | ||||
| 	var Rn; | ||||
| 	var FEtag; | ||||
| 	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| 		case 'manifest': break; // 4.2 <manifest:manifest>
 | ||||
| 		case 'file-entry': // 4.3 <manifest:file-entry>
 | ||||
| 			FEtag = parsexmltag(Rn[0], false); | ||||
| 			if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet"); | ||||
| 			break; | ||||
| 		case 'encryption-data': // 4.4 <manifest:encryption-data>
 | ||||
| 		case 'algorithm': // 4.5 <manifest:algorithm>
 | ||||
| 		case 'start-key-generation': // 4.6 <manifest:start-key-generation>
 | ||||
| 		case 'key-derivation': // 4.7 <manifest:key-derivation>
 | ||||
| 			throw new Error("Unsupported ODS Encryption"); | ||||
| 		default: if(opts && opts.WTF) throw Rn; | ||||
| 	} | ||||
| } | ||||
| function write_manifest(manifest) { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n'); | ||||
|   o.push('  <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n'); | ||||
|   for (var i = 0; i < manifest.length; ++i) | ||||
|     o.push('  <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n'); | ||||
|   o.push("</manifest:manifest>"); | ||||
|   return o.join(""); | ||||
| 
 | ||||
| function write_manifest(manifest/*:Array<Array<string> >*/)/*:string*/ { | ||||
| 	var o = [XML_HEADER]; | ||||
| 	o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n'); | ||||
| 	o.push('  <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n'); | ||||
| 	for(var i = 0; i < manifest.length; ++i) o.push('  <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n'); | ||||
| 	o.push('</manifest:manifest>'); | ||||
| 	return o.join(""); | ||||
| } | ||||
| function write_rdf_type(file, res, tag) { | ||||
|   return [ | ||||
|     '  <rdf:Description rdf:about="' + file + '">\n', | ||||
|     '    <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + "#" + res + '"/>\n', | ||||
|     "  </rdf:Description>\n" | ||||
|   ].join(""); | ||||
| 
 | ||||
| /* Part 3 Section 6 Metadata Manifest File */ | ||||
| function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) { | ||||
| 	return [ | ||||
| 		'  <rdf:Description rdf:about="' + file + '">\n', | ||||
| 		'    <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n', | ||||
| 		'  </rdf:Description>\n' | ||||
| 	].join(""); | ||||
| } | ||||
| function write_rdf_has(base, file) { | ||||
|   return [ | ||||
|     '  <rdf:Description rdf:about="' + base + '">\n', | ||||
|     '    <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n', | ||||
|     "  </rdf:Description>\n" | ||||
|   ].join(""); | ||||
| function write_rdf_has(base/*:string*/, file/*:string*/) { | ||||
| 	return [ | ||||
| 		'  <rdf:Description rdf:about="' + base + '">\n', | ||||
| 		'    <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n', | ||||
| 		'  </rdf:Description>\n' | ||||
| 	].join(""); | ||||
| } | ||||
| function write_rdf(rdf) { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n'); | ||||
|   for (var i = 0; i != rdf.length; ++i) { | ||||
|     o.push(write_rdf_type(rdf[i][0], rdf[i][1])); | ||||
|     o.push(write_rdf_has("", rdf[i][0])); | ||||
|   } | ||||
|   o.push(write_rdf_type("", "Document", "pkg")); | ||||
|   o.push("</rdf:RDF>"); | ||||
|   return o.join(""); | ||||
| } | ||||
| function write_meta_ods(wb, opts) { | ||||
|   return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>SheetJS ' + XLSX.version + "</meta:generator></office:meta></office:document-meta>"; | ||||
| 	var o = [XML_HEADER]; | ||||
| 	o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n'); | ||||
| 	for(var i = 0; i != rdf.length; ++i) { | ||||
| 		o.push(write_rdf_type(rdf[i][0], rdf[i][1])); | ||||
| 		o.push(write_rdf_has("",rdf[i][0])); | ||||
| 	} | ||||
| 	o.push(write_rdf_type("","Document", "pkg")); | ||||
| 	o.push('</rdf:RDF>'); | ||||
| 	return o.join(""); | ||||
| } | ||||
| /* TODO: pull properties */ | ||||
| var write_meta_ods/*:{(wb:Workbook, opts:any):string}*/ = (function() { | ||||
| 	var payload = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>'; | ||||
| 	return function wmo(/*:: wb: Workbook, opts: any*/)/*:string*/ { | ||||
| 		return payload; | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
|  | ||||
| @ -18,12 +18,25 @@ var CORE_PROPS/*:Array<Array<string> >*/ = [ | ||||
| 	["dcterms:modified", "ModifiedDate", 'date'] | ||||
| ]; | ||||
| 
 | ||||
| XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"; | ||||
| RELS.CORE_PROPS  = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties'; | ||||
| 
 | ||||
| var CORE_PROPS_REGEX/*:Array<RegExp>*/ = (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 + ">"); | ||||
| 	} | ||||
| 	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 = str_match_xml(data, f[0]); | ||||
| 		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(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]); | ||||
| 	} | ||||
| @ -31,6 +44,15 @@ function parse_core_props(data) { | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
| var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, { | ||||
| 	//'xmlns': XMLNS.CORE_PROPS,
 | ||||
| 	'xmlns:cp': XMLNS.CORE_PROPS, | ||||
| 	'xmlns:dc': XMLNS.dc, | ||||
| 	'xmlns:dcterms': XMLNS.dcterms, | ||||
| 	'xmlns:dcmitype': XMLNS.dcmitype, | ||||
| 	'xmlns:xsi': XMLNS.xsi | ||||
| }); | ||||
| 
 | ||||
| function cp_doit(f, g, h, o, p) { | ||||
| 	if(p[f] != null || g == null || g === "") return; | ||||
| 	p[f] = g; | ||||
| @ -40,14 +62,7 @@ function cp_doit(f, g, h, o, p) { | ||||
| 
 | ||||
| function write_core_props(cp, _opts) { | ||||
| 	var opts = _opts || {}; | ||||
| 	var o = [XML_HEADER, writextag('cp:coreProperties', null, { | ||||
| 		//'xmlns': XMLNS.CORE_PROPS,
 | ||||
| 		'xmlns:cp': XMLNS.CORE_PROPS, | ||||
| 		'xmlns:dc': XMLNS.dc, | ||||
| 		'xmlns:dcterms': XMLNS.dcterms, | ||||
| 		'xmlns:dcmitype': XMLNS.dcmitype, | ||||
| 		'xmlns:xsi': XMLNS.xsi | ||||
| 	})], p = {}; | ||||
| 	var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {}; | ||||
| 	if(!cp && !opts.Props) return o.join(""); | ||||
| 
 | ||||
| 	if(cp) { | ||||
|  | ||||
| @ -14,6 +14,9 @@ var EXT_PROPS/*:Array<Array<string> >*/ = [ | ||||
| 	["TitlesOfParts", "TitlesOfParts", "raw"] | ||||
| ]; | ||||
| 
 | ||||
| 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", | ||||
| @ -71,12 +74,12 @@ function parse_ext_props(data, p, opts) { | ||||
| 	data = utf8read(data); | ||||
| 
 | ||||
| 	EXT_PROPS.forEach(function(f) { | ||||
| 		var xml = (str_match_xml_ns(data, f[0])||[])[1]; | ||||
| 		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 "raw": | ||||
| 				var cur = str_match_xml(data, f[0]); | ||||
| 				var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">")); | ||||
| 				if(cur && cur.length > 0) q[f[1]] = cur[1]; | ||||
| 				break; | ||||
| 		} | ||||
| @ -87,15 +90,17 @@ function parse_ext_props(data, p, opts) { | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
| var EXT_PROPS_XML_ROOT = writextag('Properties', null, { | ||||
| 	'xmlns': XMLNS.EXT_PROPS, | ||||
| 	'xmlns:vt': XMLNS.vt | ||||
| }); | ||||
| 
 | ||||
| function write_ext_props(cp/*::, opts*/)/*:string*/ { | ||||
| 	var o/*:Array<string>*/ = [], W = writextag; | ||||
| 	if(!cp) cp = {}; | ||||
| 	cp.Application = "SheetJS"; | ||||
| 	o[o.length] = (XML_HEADER); | ||||
| 	o[o.length] = (writextag('Properties', null, { | ||||
| 		'xmlns': XMLNS.EXT_PROPS, | ||||
| 		'xmlns:vt': XMLNS.vt | ||||
| 	})); | ||||
| 	o[o.length] = (EXT_PROPS_XML_ROOT); | ||||
| 
 | ||||
| 	EXT_PROPS.forEach(function(f) { | ||||
| 		if(cp[f[1]] === undefined) return; | ||||
|  | ||||
| @ -1,11 +1,14 @@ | ||||
| /* 15.2.12.2 Custom File Properties Part */ | ||||
| var custregex = /<[^<>]+>[^<]*/g; | ||||
| XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"; | ||||
| RELS.CUST_PROPS  = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties'; | ||||
| 
 | ||||
| var custregex = /<[^>]+>[^<]*/g; | ||||
| function parse_cust_props(data/*:string*/, opts) { | ||||
| 	var p = {}, name = ""; | ||||
| 	var m = data.match(custregex); | ||||
| 	if(m) for(var i = 0; i != m.length; ++i) { | ||||
| 		var x = m[i], y = parsexmltag(x); | ||||
| 		switch(strip_ns(y[0])) { | ||||
| 		switch(y[0]) { | ||||
| 			case '<?xml': break; | ||||
| 			case '<Properties': break; | ||||
| 			case '<property': name = unescapexml(y.name); break; | ||||
| @ -44,11 +47,13 @@ function parse_cust_props(data/*:string*/, opts) { | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
| var CUST_PROPS_XML_ROOT = writextag('Properties', null, { | ||||
| 	'xmlns': XMLNS.CUST_PROPS, | ||||
| 	'xmlns:vt': XMLNS.vt | ||||
| }); | ||||
| 
 | ||||
| function write_cust_props(cp/*::, opts*/)/*:string*/ { | ||||
| 	var o = [XML_HEADER, writextag('Properties', null, { | ||||
| 		'xmlns': XMLNS.CUST_PROPS, | ||||
| 		'xmlns:vt': XMLNS.vt | ||||
| 	})]; | ||||
| 	var o = [XML_HEADER, CUST_PROPS_XML_ROOT]; | ||||
| 	if(!cp) return o.join(""); | ||||
| 	var pid = 1; | ||||
| 	keys(cp).forEach(function custprop(k) { ++pid; | ||||
|  | ||||
| @ -31,10 +31,9 @@ var XLMLDocPropsMap = { | ||||
| 	Identifier: 'Identifier', /* NOTE: missing from schema */ | ||||
| 	Language: 'Language' /* NOTE: missing from schema */ | ||||
| }; | ||||
| var evert_XLMLDPM; | ||||
| var evert_XLMLDPM = evert(XLMLDocPropsMap); | ||||
| 
 | ||||
| function xlml_set_prop(Props, tag/*:string*/, val) { | ||||
| 	if(!evert_XLMLDPM) evert_XLMLDPM = evert(XLMLDocPropsMap); | ||||
| 	tag = evert_XLMLDPM[tag] || tag; | ||||
| 	Props[tag] = val; | ||||
| } | ||||
|  | ||||
| @ -41,18 +41,6 @@ function parse_VtStringBase(blob, stringType, pad) { | ||||
| function parse_VtString(blob, t/*:number*/, pad/*:?boolean*/) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); } | ||||
| function parse_VtUnalignedString(blob, t/*:number*/) { if(!t) throw new Error("VtUnalignedString must have positive length"); return parse_VtStringBase(blob, t, 0); } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.3.1.7 VtVecLpwstrValue */ | ||||
| function parse_VtVecLpwstrValue(blob)/*:Array<string>*/ { | ||||
| 	var length = blob.read_shift(4); | ||||
| 	var ret/*:Array<string>*/ = []; | ||||
| 	for(var i = 0; i != length; ++i) { | ||||
| 		var start = blob.l; | ||||
| 		ret[i] = blob.read_shift(0, 'lpwstr').replace(chr0,''); | ||||
| 		if((blob.l - start) & 0x02) blob.l += 2; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */ | ||||
| function parse_VtVecUnalignedLpstrValue(blob)/*:Array<string>*/ { | ||||
| 	var length = blob.read_shift(4); | ||||
| @ -61,12 +49,14 @@ function parse_VtVecUnalignedLpstrValue(blob)/*:Array<string>*/ { | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */ | ||||
| function parse_VtVecUnalignedLpstr(blob)/*:Array<string>*/ { | ||||
| 	return parse_VtVecUnalignedLpstrValue(blob); | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */ | ||||
| function parse_VtHeadingPair(blob) { | ||||
| 	var start = blob.l; | ||||
| 	var headingString = parse_TypedPropertyValue(blob, VT_USTR); | ||||
| 	if(blob[blob.l] == 0x00 && blob[blob.l+1] == 0x00 && ((blob.l - start) & 0x02)) blob.l += 2; | ||||
| 	var headerParts = parse_TypedPropertyValue(blob, VT_I4); | ||||
| 	return [headingString, headerParts]; | ||||
| } | ||||
| @ -75,10 +65,16 @@ function parse_VtHeadingPair(blob) { | ||||
| function parse_VtVecHeadingPairValue(blob) { | ||||
| 	var cElements = blob.read_shift(4); | ||||
| 	var out = []; | ||||
| 	for(var i = 0; i < cElements / 2; ++i) out.push(parse_VtHeadingPair(blob)); | ||||
| 	for(var i = 0; i != cElements / 2; ++i) out.push(parse_VtHeadingPair(blob)); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */ | ||||
| function parse_VtVecHeadingPair(blob) { | ||||
| 	// NOTE: When invoked, wType & padding were already consumed
 | ||||
| 	return parse_VtVecHeadingPairValue(blob); | ||||
| } | ||||
| 
 | ||||
| /* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */ | ||||
| function parse_dictionary(blob,CodePage) { | ||||
| 	var cnt = blob.read_shift(4); | ||||
| @ -117,23 +113,21 @@ function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ { | ||||
| 	var t = blob.read_shift(2), ret, opts = _opts||{}; | ||||
| 	blob.l += 2; | ||||
| 	if(type !== VT_VARIANT) | ||||
| 	if(t !== type && VT_CUSTOM.indexOf(type)===-1 && !((type & 0xFFFE) == 0x101E && (t & 0xFFFE) == 0x101E)) throw new Error('Expected type ' + type + ' saw ' + t); | ||||
| 	if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t); | ||||
| 	switch(type === VT_VARIANT ? t : type) { | ||||
| 		case 0x02 /*VT_I2*/: ret = blob.read_shift(2, 'i'); if(!opts.raw) blob.l += 2; return ret; | ||||
| 		case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret; | ||||
| 		case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0; | ||||
| 		case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret; | ||||
| 		case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); break; | ||||
| 		case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); break; | ||||
| 		case 0x1E /*VT_LPSTR*/: return parse_lpstr(blob, t, 4).replace(chr0,''); | ||||
| 		case 0x1F /*VT_LPWSTR*/: return parse_lpwstr(blob); | ||||
| 		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 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPairValue(blob); | ||||
| 		case 0x101E /*VT_VECTOR|VT_LPSTR*/: | ||||
| 		case 0x101F /*VT_VECTOR|VT_LPWSTR*/: | ||||
| 			return t == 0x101F ? parse_VtVecLpwstrValue(blob) : parse_VtVecUnalignedLpstrValue(blob); | ||||
| 		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); | ||||
| 	} | ||||
| } | ||||
| @ -185,7 +179,6 @@ function parse_PropertySet(blob, PIDSI) { | ||||
| 			if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i); | ||||
| 		} | ||||
| 		if(PIDSI) { | ||||
| 			if(Props[i][0] == 0 && Props.length > i+1 && Props[i][1] == Props[i+1][1]) continue; // R9
 | ||||
| 			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); | ||||
| @ -233,8 +226,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])\u0000+$/,"$1"); break; | ||||
| 					case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); 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 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; | ||||
| @ -249,7 +242,7 @@ 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" ]; | ||||
| 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; | ||||
| @ -293,7 +286,7 @@ function write_PropertySet(entries, RE, PIDSI) { | ||||
| 
 | ||||
| 	for(i = 0; i < entries.length; ++i) { | ||||
| 		if(RE && !RE[entries[i][0]]) continue; | ||||
| 		if(XLSPSSkip.indexOf(entries[i][0]) > -1 || PseudoPropsPairs.indexOf(entries[i][0]) > -1) continue; | ||||
| 		if(XLSPSSkip.indexOf(entries[i][0]) > -1) continue; | ||||
| 		if(entries[i][1] == null) continue; | ||||
| 
 | ||||
| 		var val = entries[i][1], idx = 0; | ||||
| @ -410,7 +403,7 @@ function parse_Bes(blob/*::, length*/) { | ||||
| } | ||||
| function write_Bes(v, t/*:string*/, o) { | ||||
| 	if(!o) o = new_buf(2); | ||||
| 	o.write_shift(1, ((t == 'e') ? +v : +!!v)); | ||||
| 	o.write_shift(1, +v); | ||||
| 	o.write_shift(1, ((t == 'e') ? 1 : 0)); | ||||
| 	return o; | ||||
| } | ||||
| @ -530,17 +523,16 @@ function parse_URLMoniker(blob/*::, length, opts*/) { | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */ | ||||
| function parse_FileMoniker(blob/*::, length*/) { | ||||
| 	var cAnti = blob.read_shift(2); | ||||
| 	var preamble = ""; while(cAnti-- > 0) preamble += "../"; | ||||
| 	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 preamble + ansiPath.replace(/\\/g,"/"); | ||||
| 	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,""); | ||||
| 	return preamble + unicodePath; | ||||
| 	return unicodePath; | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */ | ||||
| @ -559,13 +551,6 @@ function parse_HyperlinkString(blob/*::, length*/) { | ||||
| 	var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : ""; | ||||
| 	return o; | ||||
| } | ||||
| function write_HyperlinkString(str/*:string*/, o) { | ||||
| 	if(!o) o = new_buf(6 + str.length * 2); | ||||
| 	o.write_shift(4, 1 + str.length); | ||||
| 	for(var i = 0; i < str.length; ++i) o.write_shift(2, str.charCodeAt(i)); | ||||
| 	o.write_shift(2, 0); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.7.1 Hyperlink Object */ | ||||
| function parse_Hyperlink(blob, length)/*:Hyperlink*/ { | ||||
| @ -586,7 +571,6 @@ function parse_Hyperlink(blob, length)/*:Hyperlink*/ { | ||||
| 	var target = targetFrameName||moniker||oleMoniker||""; | ||||
| 	if(target && Loc) target+="#"+Loc; | ||||
| 	if(!target) target = "#" + Loc; | ||||
| 	if((flags & 0x0002) && target.charAt(0) == "/" && target.charAt(1) != "/") target = "file://" + target; | ||||
| 	var out = ({Target:target}/*:any*/); | ||||
| 	if(guid) out.guid = guid; | ||||
| 	if(fileTime) out.time = fileTime; | ||||
| @ -596,31 +580,29 @@ function parse_Hyperlink(blob, length)/*:Hyperlink*/ { | ||||
| function write_Hyperlink(hl) { | ||||
| 	var out = new_buf(512), i = 0; | ||||
| 	var Target = hl.Target; | ||||
| 	if(Target.slice(0,7) == "file://") Target = Target.slice(7); | ||||
| 	var hashidx = Target.indexOf("#"); | ||||
| 	var F = hashidx > -1 ? 0x1f : 0x17; | ||||
| 	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); | ||||
| 		write_HyperlinkString(Target, out); | ||||
| 		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)); | ||||
| 		var Pretarget = hashidx > -1 ? Target.slice(0, hashidx) : Target; | ||||
| 		out.write_shift(4, 2*(Pretarget.length + 1)); | ||||
| 		for(i = 0; i < Pretarget.length; ++i) out.write_shift(2, Pretarget.charCodeAt(i)); | ||||
| 		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); | ||||
| 		if(F & 0x08) write_HyperlinkString(hashidx > -1 ? Target.slice(hashidx+1): "", out); | ||||
| 	} 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 - 3 * P + 1); | ||||
| 		for(i = 0; i < Target.length - 3 * P; ++i) out.write_shift(1, Target.charCodeAt(i + 3 * P) & 0xFF); | ||||
| 		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); | ||||
|  | ||||
| @ -1,20 +1,9 @@ | ||||
| /* [MS-XLS] 2.5.19 */ | ||||
| function parse_XLSCell(blob, length, opts)/*:Cell*/ { | ||||
| function parse_XLSCell(blob/*::, length*/)/*:Cell*/ { | ||||
| 	var rw = blob.read_shift(2); // 0-indexed
 | ||||
| 	var col = blob.read_shift(2); | ||||
| 	var ret = ({r:rw, c:col, ixfe:0}/*:any*/); | ||||
| 	if(opts && opts.biff == 2 || length == 7) { | ||||
| 		/* TODO: pass back flags */ | ||||
| 		var flags = blob.read_shift(1); | ||||
| 		ret.ixfe = flags & 0x3F; | ||||
| 		blob.l += 2; | ||||
| 		/* | ||||
| 		var ifntifmt = blob.read_shift(1); | ||||
| 		var ifmt = ifntifmt & 0x3f, ifnt = ifntifmt >> 6; | ||||
| 		var flags3 = blob.read_shift(1); | ||||
| 		*/ | ||||
| 	} else ret.ixfe = blob.read_shift(2); | ||||
| 	return ret; | ||||
| 	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); | ||||
| @ -122,25 +111,25 @@ function parse_FtCf(blob) { | ||||
| /* [MS-XLS] 2.5.140 - 2.5.154 and friends */ | ||||
| function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); } | ||||
| var FtTab = { | ||||
| 	0x00: parse_FtSkip,      /* FtEnd */ | ||||
| 	0x04: parse_FtSkip,      /* FtMacro */ | ||||
| 	0x05: parse_FtSkip,      /* FtButton */ | ||||
| 	0x06: parse_FtSkip,      /* FtGmo */ | ||||
| 	0x07: parse_FtCf,        /* FtCf */ | ||||
| 	0x08: parse_FtSkip,      /* FtPioGrbit */ | ||||
| 	0x09: parse_FtSkip,      /* FtPictFmla */ | ||||
| 	0x0A: parse_FtSkip,      /* FtCbls */ | ||||
| 	0x0B: parse_FtSkip,      /* FtRbo */ | ||||
| 	0x0C: parse_FtSkip,      /* FtSbs */ | ||||
| 	0x0D: parse_FtNts,       /* FtNts */ | ||||
| 	0x0E: parse_FtSkip,      /* FtSbsFmla */ | ||||
| 	0x0F: parse_FtSkip,      /* FtGboData */ | ||||
| 	0x10: parse_FtSkip,      /* FtEdoData */ | ||||
| 	0x11: parse_FtSkip,      /* FtRboData */ | ||||
| 	0x12: parse_FtSkip,      /* FtCblsData */ | ||||
| 	0x13: parse_FtSkip,      /* FtLbsData */ | ||||
| 	0x14: parse_FtSkip,      /* FtCblsFmla */ | ||||
| 	0x15: parse_FtCmo | ||||
| 	/*::[*/0x00/*::]*/: parse_FtSkip,      /* FtEnd */ | ||||
| 	/*::[*/0x04/*::]*/: parse_FtSkip,      /* FtMacro */ | ||||
| 	/*::[*/0x05/*::]*/: parse_FtSkip,      /* FtButton */ | ||||
| 	/*::[*/0x06/*::]*/: parse_FtSkip,      /* FtGmo */ | ||||
| 	/*::[*/0x07/*::]*/: parse_FtCf,        /* FtCf */ | ||||
| 	/*::[*/0x08/*::]*/: parse_FtSkip,      /* FtPioGrbit */ | ||||
| 	/*::[*/0x09/*::]*/: parse_FtSkip,      /* FtPictFmla */ | ||||
| 	/*::[*/0x0A/*::]*/: parse_FtSkip,      /* FtCbls */ | ||||
| 	/*::[*/0x0B/*::]*/: parse_FtSkip,      /* FtRbo */ | ||||
| 	/*::[*/0x0C/*::]*/: parse_FtSkip,      /* FtSbs */ | ||||
| 	/*::[*/0x0D/*::]*/: parse_FtNts,       /* FtNts */ | ||||
| 	/*::[*/0x0E/*::]*/: parse_FtSkip,      /* FtSbsFmla */ | ||||
| 	/*::[*/0x0F/*::]*/: parse_FtSkip,      /* FtGboData */ | ||||
| 	/*::[*/0x10/*::]*/: parse_FtSkip,      /* FtEdoData */ | ||||
| 	/*::[*/0x11/*::]*/: parse_FtSkip,      /* FtRboData */ | ||||
| 	/*::[*/0x12/*::]*/: parse_FtSkip,      /* FtCblsData */ | ||||
| 	/*::[*/0x13/*::]*/: parse_FtSkip,      /* FtLbsData */ | ||||
| 	/*::[*/0x14/*::]*/: parse_FtSkip,      /* FtCblsFmla */ | ||||
| 	/*::[*/0x15/*::]*/: parse_FtCmo | ||||
| }; | ||||
| function parse_FtArray(blob, length/*::, ot*/) { | ||||
| 	var tgt = blob.l + length; | ||||
| @ -149,7 +138,7 @@ function parse_FtArray(blob, length/*::, ot*/) { | ||||
| 		var ft = blob.read_shift(2); | ||||
| 		blob.l-=2; | ||||
| 		try { | ||||
| 			fts[ft] = FtTab[ft](blob, tgt - blob.l); | ||||
| 			fts.push(FtTab[ft](blob, tgt - blob.l)); | ||||
| 		} catch(e) { blob.l = tgt; return fts; } | ||||
| 	} | ||||
| 	if(blob.l != tgt) blob.l = tgt; //throw new Error("bad Object Ft-sequence");
 | ||||
| @ -234,17 +223,11 @@ function write_WriteAccess(s/*:string*/, opts) { | ||||
| /* [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, fBelow: flags & 0x40, fRight: flags & 0x80 }; | ||||
| 	return { fDialog: flags & 0x10 }; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.28 */ | ||||
| function parse_BoundSheet8(blob, length, opts) { | ||||
| 	var name = ""; | ||||
| 	if(opts.biff == 4) { | ||||
| 		name = parse_ShortXLUnicodeString(blob, 0, opts); | ||||
| 		if(name.length === 0) name = "Sheet1"; | ||||
| 		return { name:name }; | ||||
| 	} | ||||
| 	var pos = blob.read_shift(4); | ||||
| 	var hidden = blob.read_shift(1) & 0x03; | ||||
| 	var dt = blob.read_shift(1); | ||||
| @ -254,7 +237,7 @@ function parse_BoundSheet8(blob, length, opts) { | ||||
| 		case 2: dt = 'Chartsheet'; break; | ||||
| 		case 6: dt = 'VBAModule'; break; | ||||
| 	} | ||||
| 	name = parse_ShortXLUnicodeString(blob, 0, opts); | ||||
| 	var name = parse_ShortXLUnicodeString(blob, 0, opts); | ||||
| 	if(name.length === 0) name = "Sheet1"; | ||||
| 	return { pos:pos, hs:hidden, dt:dt, name:name }; | ||||
| } | ||||
| @ -425,8 +408,8 @@ function write_Font(data, opts) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.149 */ | ||||
| function parse_LabelSst(blob, length, opts) { | ||||
| 	var cell = parse_XLSCell(blob, length, opts); | ||||
| function parse_LabelSst(blob) { | ||||
| 	var cell = parse_XLSCell(blob); | ||||
| 	cell.isst = blob.read_shift(4); | ||||
| 	return cell; | ||||
| } | ||||
| @ -439,9 +422,9 @@ function write_LabelSst(R/*:number*/, C/*:number*/, v/*:number*/, os/*:number*/ | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.148 */ | ||||
| function parse_Label(blob, length, opts) { | ||||
| 	if(opts.biffguess && opts.biff == 2) opts.biff = 5; | ||||
| 	var target = blob.l + length; | ||||
| 	var cell = parse_XLSCell(blob, length, opts); | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	if(opts.biff == 2) blob.l++; | ||||
| 	var str = parse_XLUnicodeString(blob, target - blob.l, opts); | ||||
| 	cell.val = str; | ||||
| 	return cell; | ||||
| @ -475,19 +458,6 @@ function write_Format(i/*:number*/, f/*:string*/, opts, o) { | ||||
| 	return out; | ||||
| } | ||||
| var parse_BIFF2Format = parse_XLUnicodeString2; | ||||
| function write_BIFF2Format(f/*:string*/) { | ||||
| 	var o = new_buf(1 + f.length); | ||||
| 	o.write_shift(1, f.length); | ||||
| 	o.write_shift(f.length, f, "sbcs"); | ||||
| 	return o; | ||||
| } | ||||
| function write_BIFF4Format(f/*:string*/) { | ||||
| 	var o = new_buf(3 + f.length); | ||||
| 	o.l += 2; | ||||
| 	o.write_shift(1, f.length); | ||||
| 	o.write_shift(f.length, f, "sbcs"); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.90 */ | ||||
| function parse_Dimensions(blob, length, opts) { | ||||
| @ -603,52 +573,12 @@ function write_XF(data, ixfeP, opts, o) { | ||||
| 		o.write_shift(2, (data.numFmtId||0)); | ||||
| 		o.write_shift(2, (ixfeP<<4)); | ||||
| 	} | ||||
| 	var f = 0; | ||||
| 	if(data.numFmtId > 0 && b5) f |= 0x0400; | ||||
| 	o.write_shift(4, f); | ||||
| 	o.write_shift(4, 0); | ||||
| 	o.write_shift(4, 0); | ||||
| 	if(!b5) o.write_shift(4, 0); | ||||
| 	o.write_shift(2, 0); | ||||
| 	return o; | ||||
| } | ||||
| function parse_BIFF2XF(blob/*::, length, opts*/) { | ||||
| 	var o = {}; | ||||
| 	o.ifnt = blob.read_shift(1); blob.l++; o.flags = blob.read_shift(1); | ||||
| 	o.numFmtId = o.flags & 0x3F; o.flags>>=6; | ||||
| 	o.fStyle = 0; | ||||
| 	o.data = {}; // TODO
 | ||||
| 	return o; | ||||
| } | ||||
| function write_BIFF2XF(xf) { | ||||
| 	var o = new_buf(4); | ||||
| 	o.l+=2; | ||||
| 	o.write_shift(1, xf.numFmtId); | ||||
| 	o.l++; | ||||
| 	return o; | ||||
| } | ||||
| function write_BIFF3XF(xf) { | ||||
| 	var o = new_buf(12); | ||||
| 	o.l++; | ||||
| 	o.write_shift(1, xf.numFmtId); | ||||
| 	o.l += 10; | ||||
| 	return o; | ||||
| } | ||||
| /* TODO: check other fields */ | ||||
| var write_BIFF4XF = write_BIFF3XF; | ||||
| function parse_BIFF3XF(blob/*::, length, opts*/) { | ||||
| 	var o = {}; | ||||
| 	o.ifnt = blob.read_shift(1); o.numFmtId = blob.read_shift(1); o.flags = blob.read_shift(2); | ||||
| 	o.fStyle = (o.flags >> 2) & 0x01; | ||||
| 	o.data = {}; // TODO
 | ||||
| 	return o; | ||||
| } | ||||
| function parse_BIFF4XF(blob/*::, length, opts*/) { | ||||
| 	var o = {}; | ||||
| 	o.ifnt = blob.read_shift(1); o.numFmtId = blob.read_shift(1); o.flags = blob.read_shift(2); | ||||
| 	o.fStyle = (o.flags >> 2) & 0x01; | ||||
| 	o.data = {}; // TODO
 | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.134 */ | ||||
| function parse_Guts(blob) { | ||||
| @ -669,7 +599,8 @@ function write_Guts(guts/*:Array<number>*/) { | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.24 */ | ||||
| function parse_BoolErr(blob, length, opts) { | ||||
| 	var cell = parse_XLSCell(blob, 6, opts); | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	if(opts.biff == 2) ++blob.l; | ||||
| 	var val = parse_Bes(blob, 2); | ||||
| 	cell.val = val; | ||||
| 	cell.t = (val === true || val === false) ? 'b' : 'e'; | ||||
| @ -683,9 +614,8 @@ function write_BoolErr(R/*:number*/, C/*:number*/, v, os/*:number*/, opts, t/*:s | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.180 Number */ | ||||
| function parse_Number(blob, length, opts) { | ||||
| 	if(opts.biffguess && opts.biff == 2) opts.biff = 5; | ||||
| 	var cell = parse_XLSCell(blob, 6, opts); | ||||
| function parse_Number(blob) { | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	var xnum = parse_Xnum(blob, 8); | ||||
| 	cell.val = xnum; | ||||
| 	return cell; | ||||
| @ -735,6 +665,22 @@ function parse_ExternName(blob, length, opts) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.150 TODO */ | ||||
| var XLSLblBuiltIn = [ | ||||
| 	"_xlnm.Consolidate_Area", | ||||
| 	"_xlnm.Auto_Open", | ||||
| 	"_xlnm.Auto_Close", | ||||
| 	"_xlnm.Extract", | ||||
| 	"_xlnm.Database", | ||||
| 	"_xlnm.Criteria", | ||||
| 	"_xlnm.Print_Area", | ||||
| 	"_xlnm.Print_Titles", | ||||
| 	"_xlnm.Recorder", | ||||
| 	"_xlnm.Data_Form", | ||||
| 	"_xlnm.Auto_Activate", | ||||
| 	"_xlnm.Auto_Deactivate", | ||||
| 	"_xlnm.Sheet_Title", | ||||
| 	"_xlnm._FilterDatabase" | ||||
| ]; | ||||
| function parse_Lbl(blob, length, opts) { | ||||
| 	var target = blob.l + length; | ||||
| 	var flags = blob.read_shift(2); | ||||
| @ -751,9 +697,7 @@ function parse_Lbl(blob, length, opts) { | ||||
| 	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; | ||||
| 	/*jshint -W018 */ | ||||
| 	var rgce = (target == blob.l || cce === 0 || !(npflen > 0)) ? [] : parse_NameParsedFormula(blob, npflen, opts, cce); | ||||
| 	/*jshint +W018 */ | ||||
| 	return { | ||||
| 		chKey: chKey, | ||||
| 		Name: name, | ||||
| @ -762,11 +706,9 @@ function parse_Lbl(blob, length, opts) { | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.106 TODO: legacy record filename encoding */ | ||||
| /* [MS-XLS] 2.4.106 TODO: verify filename encoding */ | ||||
| function parse_ExternSheet(blob, length, opts) { | ||||
| 	if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts); | ||||
| 	/* see issue 2907 */ | ||||
| 	if(!(opts.biff > 8) && (length == blob[blob.l] + (blob[blob.l+1] == 0x03 ? 1 : 0) + 1)) 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)); | ||||
| 		// [iSupBook, itabFirst, itabLast];
 | ||||
| @ -818,34 +760,21 @@ function parse_MTRSettings(blob) { | ||||
| 	return [fMTREnabled, fUserSetThreadCount, cUserThreadCount]; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.186 */ | ||||
| /* [MS-XLS] 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); | ||||
| 	var flags = blob.read_shift(2), idObj = blob.read_shift(2); | ||||
| 	var stAuthor = parse_XLUnicodeString2(blob, 0, opts); | ||||
| 	if(opts.biff < 8) blob.read_shift(1); | ||||
| 	return [{r:row,c:col}, stAuthor, idObj, flags]; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.179 */ | ||||
| function parse_Note(blob, length, opts) { | ||||
| 	if(opts && (opts.biff < 8)) { | ||||
| 		var row = blob.read_shift(2), col = blob.read_shift(2); | ||||
| 		if(row == 0xFFFF || row == -1) return; // TODO: test continuation
 | ||||
| 		var cch = blob.read_shift(2); | ||||
| 		var cmnt = blob.read_shift(Math.min(cch,2048), 'cpstr'); | ||||
| 		return [{r:row, c:col}, cmnt]; | ||||
| 	} | ||||
| 	/* TODO: Support revisions */ | ||||
| 	return parse_NoteSh(blob, length, opts); | ||||
| } | ||||
| function write_NOTE_BIFF2(text/*:string*/, R/*:number*/, C/*:number*/, len/*?:number*/) { | ||||
| 	var o = new_buf(6 + (len || text.length)); | ||||
| 	o.write_shift(2, R); | ||||
| 	o.write_shift(2, C); | ||||
| 	o.write_shift(2, len || text.length); | ||||
| 	o.write_shift(text.length, text, "sbcs"); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.168 */ | ||||
| function parse_MergeCells(blob, length)/*:Array<Range>*/ { | ||||
| @ -869,8 +798,8 @@ function parse_Obj(blob, length, opts) { | ||||
| 	return { cmo: cmo, ft:fts }; | ||||
| } | ||||
| /* from older spec */ | ||||
| var parse_BIFF5OT = { | ||||
| 0x08: function(blob, length) { | ||||
| var parse_BIFF5OT = []; | ||||
| parse_BIFF5OT[0x08] = function(blob, length) { | ||||
| 	var tgt = blob.l + length; | ||||
| 	blob.l += 10; // todo
 | ||||
| 	var cf = blob.read_shift(2); | ||||
| @ -883,7 +812,6 @@ var parse_BIFF5OT = { | ||||
| 	blob.l += cchName; // TODO: stName
 | ||||
| 	blob.l = tgt; // TODO: fmla
 | ||||
| 	return { fmt:cf }; | ||||
| } | ||||
| }; | ||||
| 
 | ||||
| function parse_BIFF5Obj(blob, length, opts) { | ||||
| @ -916,7 +844,7 @@ try { | ||||
| 	var ot = (opts.lastobj||{cmo:[0,0]}).cmo[1]; | ||||
| 	var controlInfo; // eslint-disable-line no-unused-vars
 | ||||
| 	if([0,5,7,11,12,14].indexOf(ot) == -1) blob.l += 6; | ||||
| 	else controlInfo = parse_ControlInfo(blob, 6, opts); // eslint-disable-line no-unused-vars
 | ||||
| 	else controlInfo = parse_ControlInfo(blob, 6, opts); | ||||
| 	var cchText = blob.read_shift(2); | ||||
| 	/*var cbRuns = */blob.read_shift(2); | ||||
| 	/*var ifntEmpty = */parseuint16(blob, 2); | ||||
| @ -1039,20 +967,6 @@ function parse_ColInfo(blob, length, opts) { | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.257 */ | ||||
| function parse_Setup(blob, length) { | ||||
| @ -1095,50 +1009,42 @@ function parse_ImData(blob) { | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| function write_BIFF2Cell(out, r/*:number*/, c/*:number*/, ixfe/*:number*/, ifmt/*:number*/) { | ||||
| 	if(!out) out = new_buf(7); | ||||
| 	out.write_shift(2, r); | ||||
| 	out.write_shift(2, c); | ||||
| 	out.write_shift(1, ixfe||0/* & 0x3F */); | ||||
| 	out.write_shift(1, ifmt||0/* & 0x3F */); | ||||
| 	out.write_shift(1, 0); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* BIFF2_??? where ??? is the name from [XLS] */ | ||||
| function parse_BIFF2STR(blob, length, opts) { | ||||
| 	if(opts.biffguess && opts.biff == 5) opts.biff = 2; | ||||
| 	var cell = parse_XLSCell(blob, 7, opts); | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	++blob.l; | ||||
| 	var str = parse_XLUnicodeString2(blob, length-7, opts); | ||||
| 	cell.t = 'str'; | ||||
| 	cell.val = str; | ||||
| 	return cell; | ||||
| } | ||||
| 
 | ||||
| function parse_BIFF2NUM(blob, length, opts) { | ||||
| 	var cell = parse_XLSCell(blob, 7, opts); | ||||
| function parse_BIFF2NUM(blob/*::, length*/) { | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	++blob.l; | ||||
| 	var num = parse_Xnum(blob, 8); | ||||
| 	cell.t = 'n'; | ||||
| 	cell.val = num; | ||||
| 	return cell; | ||||
| } | ||||
| function write_BIFF2NUM(r/*:number*/, c/*:number*/, val/*:number*/, ixfe, ifmt) { | ||||
| function write_BIFF2NUM(r/*:number*/, c/*:number*/, val/*:number*/) { | ||||
| 	var out = new_buf(15); | ||||
| 	write_BIFF2Cell(out, r, c, ixfe||0, ifmt||0); | ||||
| 	write_BIFF2Cell(out, r, c); | ||||
| 	out.write_shift(8, val, 'f'); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| function parse_BIFF2INT(blob, length, opts) { | ||||
| 	var cell = parse_XLSCell(blob, 7, opts); | ||||
| function parse_BIFF2INT(blob) { | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	++blob.l; | ||||
| 	var num = blob.read_shift(2); | ||||
| 	cell.t = 'n'; | ||||
| 	cell.val = num; | ||||
| 	return cell; | ||||
| } | ||||
| function write_BIFF2INT(r/*:number*/, c/*:number*/, val/*:number*/, ixfe/*:number*/, ifmt/*:number*/) { | ||||
| function write_BIFF2INT(r/*:number*/, c/*:number*/, val/*:number*/) { | ||||
| 	var out = new_buf(9); | ||||
| 	write_BIFF2Cell(out, r, c, ixfe||0, ifmt||0); | ||||
| 	write_BIFF2Cell(out, r, c); | ||||
| 	out.write_shift(2, val); | ||||
| 	return out; | ||||
| } | ||||
| @ -1149,16 +1055,6 @@ function parse_BIFF2STRING(blob) { | ||||
| 	return blob.read_shift(cch, 'sbcs-cont'); | ||||
| } | ||||
| 
 | ||||
| function parse_BIFF2BOOLERR(blob, length, opts) { | ||||
| 	var bestart = blob.l + 7; | ||||
| 	var cell = parse_XLSCell(blob, 6, opts); | ||||
| 	blob.l = bestart; | ||||
| 	var val = parse_Bes(blob, 2); | ||||
| 	cell.val = val; | ||||
| 	cell.t = (val === true || val === false) ? 'b' : 'e'; | ||||
| 	return cell; | ||||
| } | ||||
| 
 | ||||
| /* TODO: convert to BIFF8 font struct */ | ||||
| function parse_BIFF2FONTXTRA(blob, length) { | ||||
| 	blob.l += 6; // unknown
 | ||||
| @ -1172,7 +1068,7 @@ function parse_BIFF2FONTXTRA(blob, length) { | ||||
| /* TODO: parse rich text runs */ | ||||
| function parse_RString(blob, length, opts) { | ||||
| 	var end = blob.l + length; | ||||
| 	var cell = parse_XLSCell(blob, 6, opts); | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	var cch = blob.read_shift(2); | ||||
| 	var str = parse_XLUnicodeStringNoCch(blob, cch, opts); | ||||
| 	blob.l = end; | ||||
| @ -1180,10 +1076,3 @@ function parse_RString(blob, length, opts) { | ||||
| 	cell.val = str; | ||||
| 	return cell; | ||||
| } | ||||
| 
 | ||||
| function parse_BIFF4SheetInfo(blob/*::, length, opts*/) { | ||||
| 	var flags = blob.read_shift(4); | ||||
| 	var cch = blob.read_shift(1), name = blob.read_shift(cch, "sbcs"); | ||||
| 	if(name.length === 0) name = "Sheet1"; | ||||
| 	return { flags: flags, name:name }; | ||||
| } | ||||
							
								
								
									
										661
									
								
								bits/40_harb.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										661
									
								
								bits/40_harb.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1118
									
								
								bits/41_lotus.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1118
									
								
								bits/41_lotus.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -4,7 +4,7 @@ function parse_rpr(rpr) { | ||||
| 	var pass = false; | ||||
| 	if(m) for(;i!=m.length; ++i) { | ||||
| 		var y = parsexmltag(m[i]); | ||||
| 		switch(y[0].replace(/<\w*:/g,"<")) { | ||||
| 		switch(y[0].replace(/\w*:/g,"")) { | ||||
| 			/* 18.8.12 condense CT_BooleanProperty */ | ||||
| 			/* ** not required . */ | ||||
| 			case '<condense': break; | ||||
| @ -81,19 +81,15 @@ function parse_rpr(rpr) { | ||||
| 			case '<color': | ||||
| 				if(y.rgb) font.color = y.rgb.slice(2,8); | ||||
| 				break; | ||||
| 			case '<color>': case '<color/>': case '</color>': break; | ||||
| 
 | ||||
| 			/* 18.8.18 family ST_FontFamily */ | ||||
| 			case '<family': font.family = y.val; break; | ||||
| 			case '<family>': case '<family/>': case '</family>': break; | ||||
| 
 | ||||
| 			/* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */ | ||||
| 			case '<vertAlign': font.valign = y.val; break; | ||||
| 			case '<vertAlign>': case '<vertAlign/>': case '</vertAlign>': break; | ||||
| 
 | ||||
| 			/* 18.8.35 scheme CT_FontScheme TODO */ | ||||
| 			case '<scheme': break; | ||||
| 			case '<scheme>': case '<scheme/>': case '</scheme>': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst': case '<extLst>': case '</extLst>': break; | ||||
| @ -106,15 +102,16 @@ function parse_rpr(rpr) { | ||||
| 	return font; | ||||
| } | ||||
| 
 | ||||
| var parse_rs = /*#__PURE__*/(function() { | ||||
| 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 = str_match_xml_ns(r, "t")/*, cp = 65001*/; | ||||
| 		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 = str_match_xml_ns(r, "rPr"); | ||||
| 		var rpr = r.match(rpregex); | ||||
| 		if(rpr) o.s = parse_rpr(rpr[1]); | ||||
| 		return o; | ||||
| 	} | ||||
| @ -126,7 +123,7 @@ var parse_rs = /*#__PURE__*/(function() { | ||||
| 
 | ||||
| 
 | ||||
| /* Parse a list of <r> tags */ | ||||
| var rs_to_html = /*#__PURE__*/(function parse_rs_factory() { | ||||
| var rs_to_html = (function parse_rs_factory() { | ||||
| 	var nlregex = /(\r\n|\n)/g; | ||||
| 	function parse_rpr2(font, intro, outro) { | ||||
| 		var style/*:Array<string>*/ = []; | ||||
| @ -167,7 +164,8 @@ var rs_to_html = /*#__PURE__*/(function parse_rs_factory() { | ||||
| })(); | ||||
| 
 | ||||
| /* 18.4.8 si CT_Rst */ | ||||
| var sitregex = /<(?:\w+:)?t\b[^<>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r\b[^<>]*>/; | ||||
| var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/; | ||||
| var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g; | ||||
| function parse_si(x, opts) { | ||||
| 	var html = opts ? opts.cellHTML : true; | ||||
| 	var z = {}; | ||||
| @ -176,14 +174,14 @@ function parse_si(x, opts) { | ||||
| 	/* 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]||""), true); | ||||
| 		z.t = unescapexml(utf8read(x.slice(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))) { | ||||
| 		z.r = utf8read(x); | ||||
| 		z.t = unescapexml(utf8read((str_remove_xml_ns_g(x, "rPh").match(sitregex)||[]).join("").replace(tagregex,"")), true); | ||||
| 		z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,""))); | ||||
| 		if(html) z.h = rs_to_html(parse_rs(z.r)); | ||||
| 	} | ||||
| 	/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */ | ||||
| @ -192,30 +190,32 @@ function parse_si(x, opts) { | ||||
| } | ||||
| 
 | ||||
| /* 18.4 Shared String Table */ | ||||
| var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/; | ||||
| var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g; | ||||
| var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/; | ||||
| function parse_sst_xml(data/*:string*/, opts)/*:SST*/ { | ||||
| 	var s/*:SST*/ = ([]/*:any*/), ss = ""; | ||||
| 	if(!data) return s; | ||||
| 	/* 18.4.9 sst CT_Sst */ | ||||
| 	var sst = str_match_xml_ns(data, "sst"); | ||||
| 	var sst = data.match(sstr0); | ||||
| 	if(sst) { | ||||
| 		ss = sst[1].replace(sstr1,"").split(sstr2); | ||||
| 		ss = sst[2].replace(sstr1,"").split(sstr2); | ||||
| 		for(var i = 0; i != ss.length; ++i) { | ||||
| 			var o = parse_si(ss[i].trim(), opts); | ||||
| 			if(o != null) s[s.length] = o; | ||||
| 		} | ||||
| 		sst = parsexmltag(sst[0].slice(0, sst[0].indexOf(">"))); s.Count = sst.count; s.Unique = sst.uniqueCount; | ||||
| 		sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount; | ||||
| 	} | ||||
| 	return s; | ||||
| } | ||||
| 
 | ||||
| RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"; | ||||
| var straywsregex = /^\s|\s$|[\t\n\r]/; | ||||
| function write_sst_xml(sst/*:SST*/, opts)/*:string*/ { | ||||
| 	if(!opts.bookSST) return ""; | ||||
| 	var o = [XML_HEADER]; | ||||
| 	o[o.length] = (writextag('sst', null, { | ||||
| 		xmlns: XMLNS_main[0], | ||||
| 		xmlns: XMLNS.main[0], | ||||
| 		count: sst.Count, | ||||
| 		uniqueCount: sst.Unique | ||||
| 	})); | ||||
| @ -226,7 +226,6 @@ function write_sst_xml(sst/*:SST*/, opts)/*:string*/ { | ||||
| 		else { | ||||
| 			sitag += "<t"; | ||||
| 			if(!s.t) s.t = ""; | ||||
| 			if(typeof s.t !== "string") s.t = String(s.t); | ||||
| 			if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"'; | ||||
| 			sitag += ">" + escapexml(s.t) + "</t>"; | ||||
| 		} | ||||
|  | ||||
| @ -7,23 +7,24 @@ function parse_BrtBeginSst(data) { | ||||
| function parse_sst_bin(data, opts)/*:SST*/ { | ||||
| 	var s/*:SST*/ = ([]/*:any*/); | ||||
| 	var pass = false; | ||||
| 	recordhopper(data, function hopper_sst(val, R, RT) { | ||||
| 	recordhopper(data, function hopper_sst(val, R_n, RT) { | ||||
| 		switch(RT) { | ||||
| 			case 0x009F: /* BrtBeginSst */ | ||||
| 			case 0x009F: /* 'BrtBeginSst' */ | ||||
| 				s.Count = val[0]; s.Unique = val[1]; break; | ||||
| 			case 0x0013: /* BrtSSTItem */ | ||||
| 			case 0x0013: /* 'BrtSSTItem' */ | ||||
| 				s.push(val); break; | ||||
| 			case 0x00A0: /* BrtEndSst */ | ||||
| 			case 0x00A0: /* 'BrtEndSst' */ | ||||
| 				return true; | ||||
| 
 | ||||
| 			case 0x0023: /* BrtFRTBegin */ | ||||
| 			case 0x0023: /* 'BrtFRTBegin' */ | ||||
| 				pass = true; break; | ||||
| 			case 0x0024: /* BrtFRTEnd */ | ||||
| 			case 0x0024: /* 'BrtFRTEnd' */ | ||||
| 				pass = false; break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if(R.T){} | ||||
| 				if(!pass || opts.WTF) throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
| 				if(R_n.indexOf("Begin") > 0){/* empty */} | ||||
| 				else if(R_n.indexOf("End") > 0){/* empty */} | ||||
| 				if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n); | ||||
| 		} | ||||
| 	}); | ||||
| 	return s; | ||||
| @ -40,9 +41,9 @@ var write_BrtSSTItem = write_RichStr; | ||||
| 
 | ||||
| function write_sst_bin(sst/*::, opts*/) { | ||||
| 	var ba = buf_array(); | ||||
| 	write_record(ba, 0x009F /* BrtBeginSst */, write_BrtBeginSst(sst)); | ||||
| 	for(var i = 0; i < sst.length; ++i) write_record(ba, 0x0013 /* BrtSSTItem */, write_BrtSSTItem(sst[i])); | ||||
| 	write_record(ba, "BrtBeginSst", write_BrtBeginSst(sst)); | ||||
| 	for(var i = 0; i < sst.length; ++i) write_record(ba, "BrtSSTItem", write_BrtSSTItem(sst[i])); | ||||
| 	/* FRTSST */ | ||||
| 	write_record(ba, 0x00A0 /* BrtEndSst */); | ||||
| 	write_record(ba, "BrtEndSst"); | ||||
| 	return ba.end(); | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| function _JS2ANSI(str/*:string*/)/*:Array<number>*/ { | ||||
| 	if(typeof $cptable !== 'undefined') return $cptable.utils.encode(current_ansi, str); | ||||
| 	if(typeof cptable !== 'undefined') return cptable.utils.encode(current_ansi, str); | ||||
| 	var o/*:Array<number>*/ = [], oo = str.split(""); | ||||
| 	for(var i = 0; i < oo.length; ++i) o[i] = oo[i].charCodeAt(0); | ||||
| 	return o; | ||||
| @ -208,7 +208,7 @@ function crypto_CreatePasswordVerifier_Method1(Password/*:string*/) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-OFFCRYPTO] 2.3.7.2 Binary Document XOR Array Initialization */ | ||||
| var crypto_CreateXorArray_Method1 = /*#__PURE__*/(function() { | ||||
| var crypto_CreateXorArray_Method1 = (function() { | ||||
| 	var PadArray = [0xBB, 0xFF, 0xFF, 0xBA, 0xFF, 0xFF, 0xB9, 0x80, 0x00, 0xBE, 0x0F, 0x00, 0xBF, 0x0F, 0x00]; | ||||
| 	var InitialCode = [0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3]; | ||||
| 	var XorMatrix = [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09, 0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF, 0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0, 0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40, 0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5, 0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A, 0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9, 0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0, 0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC, 0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10, 0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168, 0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C, 0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD, 0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC, 0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4]; | ||||
|  | ||||
							
								
								
									
										159
									
								
								bits/45_rtf.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										159
									
								
								bits/45_rtf.js
									
									
									
									
									
								
							| @ -1,107 +1,52 @@ | ||||
| function rtf_to_sheet(d, opts) { | ||||
|   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(has_buf && Buffer.isBuffer(d) ? d.toString("binary") : a2s(d), opts); | ||||
|     case "array": | ||||
|       return rtf_to_sheet_str(cc2str(d), opts); | ||||
|   } | ||||
|   throw new Error("Unrecognized type " + opts.type); | ||||
| } | ||||
| function rtf_to_sheet_str(str, opts) { | ||||
|   var o = opts || {}; | ||||
|   var ws = {}; | ||||
|   var dense = o.dense; | ||||
|   if (dense) | ||||
|     ws["!data"] = []; | ||||
|   var rows = str_match_ng(str, "\\trowd", "\\row"); | ||||
|   if (!rows) | ||||
|     throw new Error("RTF missing table"); | ||||
|   var range = { s: { c: 0, r: 0 }, e: { c: 0, r: rows.length - 1 } }; | ||||
|   var row = []; | ||||
|   rows.forEach(function(rowtf, R) { | ||||
|     if (dense) | ||||
|       row = ws["!data"][R] = []; | ||||
|     var rtfre = /\\[\w\-]+\b/g; | ||||
|     var last_index = 0; | ||||
|     var res; | ||||
|     var C = -1; | ||||
|     var payload = []; | ||||
|     while ((res = rtfre.exec(rowtf)) != null) { | ||||
|       var data = rowtf.slice(last_index, rtfre.lastIndex - res[0].length); | ||||
|       if (data.charCodeAt(0) == 32) | ||||
|         data = data.slice(1); | ||||
|       if (data.length) | ||||
|         payload.push(data); | ||||
|       switch (res[0]) { | ||||
|         case "\\cell": | ||||
|           ++C; | ||||
|           if (payload.length) { | ||||
|             var cell = { v: payload.join(""), t: "s" }; | ||||
|             if (cell.v == "TRUE" || cell.v == "FALSE") { | ||||
|               cell.v = cell.v == "TRUE"; | ||||
|               cell.t = "b"; | ||||
|             } else if (!isNaN(fuzzynum(cell.v))) { | ||||
|               cell.t = "n"; | ||||
|               if (o.cellText !== false) | ||||
|                 cell.w = cell.v; | ||||
|               cell.v = fuzzynum(cell.v); | ||||
|             } else if (RBErr[cell.v] != null) { | ||||
|               cell.t = "e"; | ||||
|               cell.w = cell.v; | ||||
|               cell.v = RBErr[cell.v]; | ||||
|             } | ||||
|             if (dense) | ||||
|               row[C] = cell; | ||||
|             else | ||||
|               ws[encode_cell({ r: R, c: C })] = cell; | ||||
|           } | ||||
|           payload = []; | ||||
|           break; | ||||
|         case "\\par": | ||||
|           payload.push("\n"); | ||||
|           break; | ||||
|       } | ||||
|       last_index = rtfre.lastIndex; | ||||
|     } | ||||
|     if (C > range.e.c) | ||||
|       range.e.c = C; | ||||
|   }); | ||||
|   ws["!ref"] = encode_range(range); | ||||
|   return ws; | ||||
| } | ||||
| function rtf_to_workbook(d, opts) { | ||||
|   var wb = sheet_to_workbook(rtf_to_sheet(d, opts), opts); | ||||
|   wb.bookType = "rtf"; | ||||
|   return wb; | ||||
| } | ||||
| function sheet_to_rtf(ws, opts) { | ||||
|   var o = ["{\\rtf1\\ansi"]; | ||||
|   if (!ws["!ref"]) | ||||
|     return o[0] + "}"; | ||||
|   var r = safe_decode_range(ws["!ref"]), cell; | ||||
|   var dense = ws["!data"] != null, row = []; | ||||
|   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"); | ||||
|     if (dense) | ||||
|       row = ws["!data"][R] || []; | ||||
|     for (C = r.s.c; C <= r.e.c; ++C) { | ||||
|       var coord = encode_cell({ r: R, c: C }); | ||||
|       cell = dense ? row[C] : ws[coord]; | ||||
|       if (!cell || cell.v == null && (!cell.f || cell.F)) { | ||||
|         o.push(" \\cell"); | ||||
|         continue; | ||||
|       } | ||||
|       o.push(" " + (cell.w || (format_cell(cell), cell.w) || "").replace(/[\r\n]/g, "\\par ")); | ||||
|       o.push("\\cell"); | ||||
|     } | ||||
|     o.push("\\pard\\intbl\\row"); | ||||
|   } | ||||
|   return o.join("") + "}"; | ||||
| } | ||||
| 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 | ||||
| 	}; | ||||
| })(); | ||||
|  | ||||
| @ -3,7 +3,7 @@ function parse_borders(t, styles, themes, opts) { | ||||
| 	styles.Borders = []; | ||||
| 	var border = {}; | ||||
| 	var pass = false; | ||||
| 	(t.match(tagregex)||[]).forEach(function(x) { | ||||
| 	(t[0].match(tagregex)||[]).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch(strip_ns(y[0])) { | ||||
| 			case '<borders': case '<borders>': case '</borders>': break; | ||||
| @ -78,7 +78,7 @@ function parse_fills(t, styles, themes, opts) { | ||||
| 	styles.Fills = []; | ||||
| 	var fill = {}; | ||||
| 	var pass = false; | ||||
| 	(t.match(tagregex)||[]).forEach(function(x) { | ||||
| 	(t[0].match(tagregex)||[]).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch(strip_ns(y[0])) { | ||||
| 			case '<fills': case '<fills>': case '</fills>': break; | ||||
| @ -144,7 +144,7 @@ function parse_fonts(t, styles, themes, opts) { | ||||
| 	styles.Fonts = []; | ||||
| 	var font = {}; | ||||
| 	var pass = false; | ||||
| 	(t.match(tagregex)||[]).forEach(function(x) { | ||||
| 	(t[0].match(tagregex)||[]).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch(strip_ns(y[0])) { | ||||
| 			case '<fonts': case '<fonts>': case '</fonts>': break; | ||||
| @ -163,12 +163,10 @@ function parse_fonts(t, styles, themes, opts) { | ||||
| 			/* 18.8.2  b CT_BooleanProperty */ | ||||
| 			case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break; | ||||
| 			case '<b/>': font.bold = 1; break; | ||||
| 			case '</b>': case '</b': break; | ||||
| 
 | ||||
| 			/* 18.8.26 i CT_BooleanProperty */ | ||||
| 			case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break; | ||||
| 			case '<i/>': font.italic = 1; break; | ||||
| 			case '</i>': case '</i': break; | ||||
| 
 | ||||
| 			/* 18.4.13 u CT_UnderlineProperty */ | ||||
| 			case '<u': | ||||
| @ -180,55 +178,48 @@ function parse_fonts(t, styles, themes, opts) { | ||||
| 					case "doubleAccounting": font.underline = 0x22; break; | ||||
| 				} break; | ||||
| 			case '<u/>': font.underline = 1; break; | ||||
| 			case '</u>': case '</u': break; | ||||
| 
 | ||||
| 			/* 18.4.10 strike CT_BooleanProperty */ | ||||
| 			case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break; | ||||
| 			case '<strike/>': font.strike = 1; break; | ||||
| 			case '</strike>': case '</strike': break; | ||||
| 
 | ||||
| 			/* 18.4.2  outline CT_BooleanProperty */ | ||||
| 			case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break; | ||||
| 			case '<outline/>': font.outline = 1; break; | ||||
| 			case '</outline>': case '</outline': break; | ||||
| 
 | ||||
| 			/* 18.8.36 shadow CT_BooleanProperty */ | ||||
| 			case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break; | ||||
| 			case '<shadow/>': font.shadow = 1; break; | ||||
| 			case '</shadow>': case '</shadow': break; | ||||
| 
 | ||||
| 			/* 18.8.12 condense CT_BooleanProperty */ | ||||
| 			case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break; | ||||
| 			case '<condense/>': font.condense = 1; break; | ||||
| 			case '</condense>': case '</condense': break; | ||||
| 
 | ||||
| 			/* 18.8.17 extend CT_BooleanProperty */ | ||||
| 			case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break; | ||||
| 			case '<extend/>': font.extend = 1; break; | ||||
| 			case '</extend>': case '</extend': break; | ||||
| 
 | ||||
| 			/* 18.4.11 sz CT_FontSize */ | ||||
| 			case '<sz': if(y.val) font.sz = +y.val; break; | ||||
| 			case '<sz/>': case '</sz>': case '</sz': break; | ||||
| 			case '<sz/>': case '</sz>': break; | ||||
| 
 | ||||
| 			/* 18.4.14 vertAlign CT_VerticalAlignFontProperty */ | ||||
| 			case '<vertAlign': if(y.val) font.vertAlign = y.val; break; | ||||
| 			case '<vertAlign/>': case '</vertAlign>': case '</vertAlign': break; | ||||
| 			case '<vertAlign/>': case '</vertAlign>': break; | ||||
| 
 | ||||
| 			/* 18.8.18 family CT_FontFamily */ | ||||
| 			case '<family': if(y.val) font.family = parseInt(y.val,10); break; | ||||
| 			case '<family/>': case '</family>': case '</family': break; | ||||
| 			case '<family/>': case '</family>': break; | ||||
| 
 | ||||
| 			/* 18.8.35 scheme CT_FontScheme */ | ||||
| 			case '<scheme': if(y.val) font.scheme = y.val; break; | ||||
| 			case '<scheme/>': case '</scheme>': case '</scheme': break; | ||||
| 			case '<scheme/>': case '</scheme>': break; | ||||
| 
 | ||||
| 			/* 18.4.1 charset CT_IntProperty */ | ||||
| 			case '<charset': | ||||
| 				if(y.val == '1') break; | ||||
| 				y.codepage = CS2CP[parseInt(y.val, 10)]; | ||||
| 				break; | ||||
| 			case '<charset/>': case '</charset>': case '</charset': break; | ||||
| 
 | ||||
| 			/* 18.?.? color CT_Color */ | ||||
| 			case '<color': | ||||
| @ -240,7 +231,7 @@ function parse_fonts(t, styles, themes, opts) { | ||||
| 					font.color.index = parseInt(y.indexed, 10); | ||||
| 					var icv = XLSIcv[font.color.index]; | ||||
| 					if(font.color.index == 81) icv = XLSIcv[1]; | ||||
| 					if(!icv) icv = XLSIcv[1]; //throw new Error(x); // note: 206 is valid
 | ||||
| 					if(!icv) throw new Error(x); | ||||
| 					font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16); | ||||
| 				} else if(y.theme) { | ||||
| 					font.color.theme = parseInt(y.theme, 10); | ||||
| @ -251,11 +242,11 @@ function parse_fonts(t, styles, themes, opts) { | ||||
| 				} | ||||
| 
 | ||||
| 				break; | ||||
| 			case '<color/>': case '</color>': case '</color': break; | ||||
| 			case '<color/>': case '</color>': break; | ||||
| 
 | ||||
| 			/* note: sometimes mc:AlternateContent appears bare */ | ||||
| 			case '<AlternateContent': pass = true; break; | ||||
| 			case '</AlternateContent>': case '</AlternateContent': pass = false; break; | ||||
| 			case '</AlternateContent>': pass = false; break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst': case '<extLst>': case '</extLst>': break; | ||||
| @ -271,9 +262,9 @@ function parse_fonts(t, styles, themes, opts) { | ||||
| /* 18.8.31 numFmts CT_NumFmts */ | ||||
| function parse_numFmts(t, styles, opts) { | ||||
| 	styles.NumberFmt = []; | ||||
| 	var k/*Array<number>*/ = (keys(table_fmt)/*:any*/); | ||||
| 	for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = table_fmt[k[i]]; | ||||
| 	var m = t.match(tagregex); | ||||
| 	var k/*Array<number>*/ = (keys(SSF._table)/*:any*/); | ||||
| 	for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]]; | ||||
| 	var m = t[0].match(tagregex); | ||||
| 	if(!m) return; | ||||
| 	for(i=0; i < m.length; ++i) { | ||||
| 		var y = parsexmltag(m[i]); | ||||
| @ -287,7 +278,7 @@ function parse_numFmts(t, styles, opts) { | ||||
| 						for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break; | ||||
| 						styles.NumberFmt[j] = f; | ||||
| 					} | ||||
| 					SSF__load(f,j); | ||||
| 					SSF.load(f,j); | ||||
| 				} | ||||
| 			} break; | ||||
| 			case '</numFmt>': break; | ||||
| @ -314,27 +305,27 @@ function parse_cellXfs(t, styles, opts) { | ||||
| 	styles.CellXf = []; | ||||
| 	var xf; | ||||
| 	var pass = false; | ||||
| 	(t.match(tagregex)||[]).forEach(function(x) { | ||||
| 	(t[0].match(tagregex)||[]).forEach(function(x) { | ||||
| 		var y = parsexmltag(x), i = 0; | ||||
| 		switch(strip_ns(y[0])) { | ||||
| 			case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break; | ||||
| 
 | ||||
| 			/* 18.8.45 xf CT_Xf */ | ||||
| 			case '<xf': case '<xf/>': case '<xf>': | ||||
| 			case '<xf': case '<xf/>': | ||||
| 				xf = y; | ||||
| 				delete xf[0]; | ||||
| 				for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]]) | ||||
| 					xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10); | ||||
| 				for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]]) | ||||
| 					xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]); | ||||
| 				if(styles.NumberFmt && xf.numFmtId > 0x188) { | ||||
| 				if(xf.numFmtId > 0x188) { | ||||
| 					for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; } | ||||
| 				} | ||||
| 				styles.CellXf.push(xf); break; | ||||
| 			case '</xf>': break; | ||||
| 
 | ||||
| 			/* 18.8.1 alignment CT_CellAlignment */ | ||||
| 			case '<alignment': case '<alignment/>': case '<alignment>': | ||||
| 			case '<alignment': case '<alignment/>': | ||||
| 				var alignment = {}; | ||||
| 				if(y.vertical) alignment.vertical = y.vertical; | ||||
| 				if(y.horizontal) alignment.horizontal = y.horizontal; | ||||
| @ -346,12 +337,12 @@ function parse_cellXfs(t, styles, opts) { | ||||
| 			case '</alignment>': break; | ||||
| 
 | ||||
| 			/* 18.8.33 protection CT_CellProtection */ | ||||
| 			case '<protection': case '<protection>': | ||||
| 			case '<protection': | ||||
| 				break; | ||||
| 			case '</protection>': case '<protection/>': break; | ||||
| 
 | ||||
| 			/* note: sometimes mc:AlternateContent appears bare */ | ||||
| 			case '<AlternateContent': case '<AlternateContent>': pass = true; break; | ||||
| 			case '<AlternateContent': pass = true; break; | ||||
| 			case '</AlternateContent>': pass = false; break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| @ -378,32 +369,37 @@ function write_cellXfs(cellXfs)/*:string*/ { | ||||
| } | ||||
| 
 | ||||
| /* 18.8 Styles CT_Stylesheet*/ | ||||
| var parse_sty_xml= /*#__PURE__*/(function make_pstyx() { | ||||
| 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>/; | ||||
| 
 | ||||
| return function parse_sty_xml(data, themes, opts) { | ||||
| 	var styles = {}; | ||||
| 	if(!data) return styles; | ||||
| 	data = remove_doctype(str_remove_ng(data, "<!--", "-->")); | ||||
| 	data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,""); | ||||
| 	/* 18.8.39 styleSheet CT_Stylesheet */ | ||||
| 	var t; | ||||
| 
 | ||||
| 	/* 18.8.31 numFmts CT_NumFmts ? */ | ||||
| 	if((t=str_match_xml_ns(data, "numFmts"))) parse_numFmts(t[0], styles, opts); | ||||
| 	if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts); | ||||
| 
 | ||||
| 	/* 18.8.23 fonts CT_Fonts ? */ | ||||
| 	if((t=str_match_xml_ns(data, "fonts"))) parse_fonts(t[0], styles, themes, opts); | ||||
| 	if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* 18.8.21 fills CT_Fills ? */ | ||||
| 	if((t=str_match_xml_ns(data, "fills"))) parse_fills(t[0], styles, themes, opts); | ||||
| 	if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* 18.8.5  borders CT_Borders ? */ | ||||
| 	if((t=str_match_xml_ns(data, "borders"))) parse_borders(t[0], styles, 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=str_match_xml_ns(data, "cellXfs"))) parse_cellXfs(t[0], styles, opts); | ||||
| 	if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts); | ||||
| 
 | ||||
| 	/* 18.8.15 dxfs CT_Dxfs ? */ | ||||
| 	/* 18.8.42 tableStyles CT_TableStyles ? */ | ||||
| @ -414,11 +410,15 @@ return function parse_sty_xml(data, themes, opts) { | ||||
| }; | ||||
| })(); | ||||
| 
 | ||||
| var STYLES_XML_ROOT = writextag('styleSheet', null, { | ||||
| 	'xmlns': XMLNS.main[0], | ||||
| 	'xmlns:vt': XMLNS.vt | ||||
| }); | ||||
| 
 | ||||
| RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"; | ||||
| 
 | ||||
| function write_sty_xml(wb/*:Workbook*/, opts)/*:string*/ { | ||||
| 	var o = [XML_HEADER, writextag('styleSheet', null, { | ||||
| 		'xmlns': XMLNS_main[0], | ||||
| 		'xmlns:vt': XMLNS.vt | ||||
| 	})], w; | ||||
| 	var o = [XML_HEADER, STYLES_XML_ROOT], w; | ||||
| 	if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w; | ||||
| 	o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>'); | ||||
| 	o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>'); | ||||
|  | ||||
| @ -102,12 +102,11 @@ var XLSBFillPTNames = [ | ||||
| 	"gray125", | ||||
| 	"gray0625" | ||||
| ]; | ||||
| var rev_XLSBFillPTNames/*:EvertNumType*/; | ||||
| 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); | ||||
| 	if(!rev_XLSBFillPTNames) rev_XLSBFillPTNames = (evert(XLSBFillPTNames)/*:any*/); | ||||
| 	var fls/*:number*/ = rev_XLSBFillPTNames[fill.patternType]; | ||||
| 	if(fls == null) fls = 0x28; | ||||
| 	o.write_shift(4, fls); | ||||
| @ -206,60 +205,60 @@ function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) { | ||||
| function parse_sty_bin(data, themes, opts) { | ||||
| 	var styles = {}; | ||||
| 	styles.NumberFmt = ([]/*:any*/); | ||||
| 	for(var y in table_fmt) styles.NumberFmt[y] = table_fmt[y]; | ||||
| 	for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y]; | ||||
| 
 | ||||
| 	styles.CellXf = []; | ||||
| 	styles.Fonts = []; | ||||
| 	var state/*:Array<string>*/ = []; | ||||
| 	var pass = false; | ||||
| 	recordhopper(data, function hopper_sty(val, R, RT) { | ||||
| 	recordhopper(data, function hopper_sty(val, R_n, RT) { | ||||
| 		switch(RT) { | ||||
| 			case 0x002C: /* BrtFmt */ | ||||
| 				styles.NumberFmt[val[0]] = val[1]; SSF__load(val[1], val[0]); | ||||
| 			case 0x002C: /* 'BrtFmt' */ | ||||
| 				styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]); | ||||
| 				break; | ||||
| 			case 0x002B: /* BrtFont */ | ||||
| 			case 0x002B: /* 'BrtFont' */ | ||||
| 				styles.Fonts.push(val); | ||||
| 				if(val.color.theme != null && themes && themes.themeElements && themes.themeElements.clrScheme) { | ||||
| 					val.color.rgb = rgb_tint(themes.themeElements.clrScheme[val.color.theme].rgb, val.color.tint || 0); | ||||
| 				} | ||||
| 				break; | ||||
| 			case 0x0401: /* BrtKnownFonts */ break; | ||||
| 			case 0x002D: /* BrtFill */ | ||||
| 			case 0x0401: /* 'BrtKnownFonts' */ break; | ||||
| 			case 0x002D: /* 'BrtFill' */ | ||||
| 				break; | ||||
| 			case 0x002E: /* BrtBorder */ | ||||
| 			case 0x002E: /* 'BrtBorder' */ | ||||
| 				break; | ||||
| 			case 0x002F: /* BrtXF */ | ||||
| 				if(state[state.length - 1] == 0x0269 /* BrtBeginCellXFs */) { | ||||
| 			case 0x002F: /* 'BrtXF' */ | ||||
| 				if(state[state.length - 1] == "BrtBeginCellXFs") { | ||||
| 					styles.CellXf.push(val); | ||||
| 				} | ||||
| 				break; | ||||
| 			case 0x0030: /* BrtStyle */ | ||||
| 			case 0x01FB: /* BrtDXF */ | ||||
| 			case 0x023C: /* BrtMRUColor */ | ||||
| 			case 0x01DB: /* BrtIndexedColor */ | ||||
| 			case 0x0030: /* 'BrtStyle' */ | ||||
| 			case 0x01FB: /* 'BrtDXF' */ | ||||
| 			case 0x023C: /* 'BrtMRUColor' */ | ||||
| 			case 0x01DB: /* 'BrtIndexedColor': */ | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0493: /* BrtDXF14 */ | ||||
| 			case 0x0836: /* BrtDXF15 */ | ||||
| 			case 0x046A: /* BrtSlicerStyleElement */ | ||||
| 			case 0x0200: /* BrtTableStyleElement */ | ||||
| 			case 0x082F: /* BrtTimelineStyleElement */ | ||||
| 			case 0x0C00: /* BrtUid */ | ||||
| 			case 0x0493: /* 'BrtDXF14' */ | ||||
| 			case 0x0836: /* 'BrtDXF15' */ | ||||
| 			case 0x046A: /* 'BrtSlicerStyleElement' */ | ||||
| 			case 0x0200: /* 'BrtTableStyleElement' */ | ||||
| 			case 0x082F: /* 'BrtTimelineStyleElement' */ | ||||
| 			case 0x0C00: /* 'BrtUid' */ | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0023: /* BrtFRTBegin */ | ||||
| 			case 0x0023: /* 'BrtFRTBegin' */ | ||||
| 				pass = true; break; | ||||
| 			case 0x0024: /* BrtFRTEnd */ | ||||
| 			case 0x0024: /* 'BrtFRTEnd' */ | ||||
| 				pass = false; break; | ||||
| 			case 0x0025: /* BrtACBegin */ | ||||
| 				state.push(RT); pass = true; break; | ||||
| 			case 0x0026: /* BrtACEnd */ | ||||
| 			case 0x0025: /* 'BrtACBegin' */ | ||||
| 				state.push(R_n); pass = true; break; | ||||
| 			case 0x0026: /* 'BrtACEnd' */ | ||||
| 				state.pop(); pass = false; break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if(R.T > 0) state.push(RT); | ||||
| 				else if(R.T < 0) state.pop(); | ||||
| 				else if(!pass || (opts.WTF && state[state.length-1] != 0x0025 /* BrtACBegin */)) throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
| 				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); | ||||
| 		} | ||||
| 	}); | ||||
| 	return styles; | ||||
| @ -274,20 +273,20 @@ function write_FMTS_bin(ba, NF/*:?SSFTable*/) { | ||||
| 	}); | ||||
| 
 | ||||
| 	if(cnt == 0) return; | ||||
| 	write_record(ba, 0x0267 /* BrtBeginFmts */, write_UInt32LE(cnt)); | ||||
| 	write_record(ba, "BrtBeginFmts", write_UInt32LE(cnt)); | ||||
| 	[[5,8],[23,26],[41,44],[/*63*/50,/*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, 0x002C /* BrtFmt */, write_BrtFmt(i, NF[i])); | ||||
| 		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, 0x0268 /* BrtEndFmts */); | ||||
| 	write_record(ba, "BrtEndFmts"); | ||||
| } | ||||
| 
 | ||||
| function write_FONTS_bin(ba/*::, data*/) { | ||||
| 	var cnt = 1; | ||||
| 
 | ||||
| 	if(cnt == 0) return; | ||||
| 	write_record(ba, 0x0263 /* BrtBeginFonts */, write_UInt32LE(cnt)); | ||||
| 	write_record(ba, 0x002B /* BrtFont */, write_BrtFont({ | ||||
| 	write_record(ba, "BrtBeginFonts", write_UInt32LE(cnt)); | ||||
| 	write_record(ba, "BrtFont", write_BrtFont({ | ||||
| 		sz:12, | ||||
| 		color: {theme:1}, | ||||
| 		name: "Calibri", | ||||
| @ -295,77 +294,77 @@ function write_FONTS_bin(ba/*::, data*/) { | ||||
| 		scheme: "minor" | ||||
| 	})); | ||||
| 	/* 1*65491BrtFont [ACFONTS] */ | ||||
| 	write_record(ba, 0x0264 /* BrtEndFonts */); | ||||
| 	write_record(ba, "BrtEndFonts"); | ||||
| } | ||||
| 
 | ||||
| function write_FILLS_bin(ba/*::, data*/) { | ||||
| 	var cnt = 2; | ||||
| 
 | ||||
| 	if(cnt == 0) return; | ||||
| 	write_record(ba, 0x025B /* BrtBeginFills */, write_UInt32LE(cnt)); | ||||
| 	write_record(ba, 0x002D /* BrtFill */, write_BrtFill({patternType:"none"})); | ||||
| 	write_record(ba, 0x002D /* BrtFill */, write_BrtFill({patternType:"gray125"})); | ||||
| 	write_record(ba, "BrtBeginFills", write_UInt32LE(cnt)); | ||||
| 	write_record(ba, "BrtFill", write_BrtFill({patternType:"none"})); | ||||
| 	write_record(ba, "BrtFill", write_BrtFill({patternType:"gray125"})); | ||||
| 	/* 1*65431BrtFill */ | ||||
| 	write_record(ba, 0x025C /* BrtEndFills */); | ||||
| 	write_record(ba, "BrtEndFills"); | ||||
| } | ||||
| 
 | ||||
| function write_BORDERS_bin(ba/*::, data*/) { | ||||
| 	var cnt = 1; | ||||
| 
 | ||||
| 	if(cnt == 0) return; | ||||
| 	write_record(ba, 0x0265 /* BrtBeginBorders */, write_UInt32LE(cnt)); | ||||
| 	write_record(ba, 0x002E /* BrtBorder */, write_BrtBorder({})); | ||||
| 	write_record(ba, "BrtBeginBorders", write_UInt32LE(cnt)); | ||||
| 	write_record(ba, "BrtBorder", write_BrtBorder({})); | ||||
| 	/* 1*65430BrtBorder */ | ||||
| 	write_record(ba, 0x0266 /* BrtEndBorders */); | ||||
| 	write_record(ba, "BrtEndBorders"); | ||||
| } | ||||
| 
 | ||||
| function write_CELLSTYLEXFS_bin(ba/*::, data*/) { | ||||
| 	var cnt = 1; | ||||
| 	write_record(ba, 0x0272 /* BrtBeginCellStyleXFs */, write_UInt32LE(cnt)); | ||||
| 	write_record(ba, 0x002F /* BrtXF */, write_BrtXF({ | ||||
| 	write_record(ba, "BrtBeginCellStyleXFs", write_UInt32LE(cnt)); | ||||
| 	write_record(ba, "BrtXF", write_BrtXF({ | ||||
| 		numFmtId: 0, | ||||
| 		fontId:   0, | ||||
| 		fillId:   0, | ||||
| 		borderId: 0 | ||||
| 	}, 0xFFFF)); | ||||
| 	/* 1*65430(BrtXF *FRT) */ | ||||
| 	write_record(ba, 0x0273 /* BrtEndCellStyleXFs */); | ||||
| 	write_record(ba, "BrtEndCellStyleXFs"); | ||||
| } | ||||
| 
 | ||||
| function write_CELLXFS_bin(ba, data) { | ||||
| 	write_record(ba, 0x0269 /* BrtBeginCellXFs */, write_UInt32LE(data.length)); | ||||
| 	data.forEach(function(c) { write_record(ba, 0x002F /* BrtXF */, write_BrtXF(c,0)); }); | ||||
| 	write_record(ba, "BrtBeginCellXFs", write_UInt32LE(data.length)); | ||||
| 	data.forEach(function(c) { write_record(ba, "BrtXF", write_BrtXF(c,0)); }); | ||||
| 	/* 1*65430(BrtXF *FRT) */ | ||||
| 	write_record(ba, 0x026A /* BrtEndCellXFs */); | ||||
| 	write_record(ba, "BrtEndCellXFs"); | ||||
| } | ||||
| 
 | ||||
| function write_STYLES_bin(ba/*::, data*/) { | ||||
| 	var cnt = 1; | ||||
| 
 | ||||
| 	write_record(ba, 0x026B /* BrtBeginStyles */, write_UInt32LE(cnt)); | ||||
| 	write_record(ba, 0x0030 /* BrtStyle */, write_BrtStyle({ | ||||
| 	write_record(ba, "BrtBeginStyles", write_UInt32LE(cnt)); | ||||
| 	write_record(ba, "BrtStyle", write_BrtStyle({ | ||||
| 		xfId:0, | ||||
| 		builtinId:0, | ||||
| 		name:"Normal" | ||||
| 	})); | ||||
| 	/* 1*65430(BrtStyle *FRT) */ | ||||
| 	write_record(ba, 0x026C /* BrtEndStyles */); | ||||
| 	write_record(ba, "BrtEndStyles"); | ||||
| } | ||||
| 
 | ||||
| function write_DXFS_bin(ba/*::, data*/) { | ||||
| 	var cnt = 0; | ||||
| 
 | ||||
| 	write_record(ba, 0x01F9 /* BrtBeginDXFs */, write_UInt32LE(cnt)); | ||||
| 	write_record(ba, "BrtBeginDXFs", write_UInt32LE(cnt)); | ||||
| 	/* *2147483647(BrtDXF *FRT) */ | ||||
| 	write_record(ba, 0x01FA /* BrtEndDXFs */); | ||||
| 	write_record(ba, "BrtEndDXFs"); | ||||
| } | ||||
| 
 | ||||
| function write_TABLESTYLES_bin(ba/*::, data*/) { | ||||
| 	var cnt = 0; | ||||
| 
 | ||||
| 	write_record(ba, 0x01FC /* BrtBeginTableStyles */, write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4")); | ||||
| 	write_record(ba, "BrtBeginTableStyles", write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4")); | ||||
| 	/* *TABLESTYLE */ | ||||
| 	write_record(ba, 0x01FD /* BrtEndTableStyles */); | ||||
| 	write_record(ba, "BrtEndTableStyles"); | ||||
| } | ||||
| 
 | ||||
| function write_COLORPALETTE_bin(/*::ba, data*/) { | ||||
| @ -376,7 +375,7 @@ function write_COLORPALETTE_bin(/*::ba, data*/) { | ||||
| /* [MS-XLSB] 2.1.7.50 Styles */ | ||||
| function write_sty_bin(wb, opts) { | ||||
| 	var ba = buf_array(); | ||||
| 	write_record(ba, 0x0116 /* BrtBeginStyleSheet */); | ||||
| 	write_record(ba, "BrtBeginStyleSheet"); | ||||
| 	write_FMTS_bin(ba, wb.SSF); | ||||
| 	write_FONTS_bin(ba, wb); | ||||
| 	write_FILLS_bin(ba, wb); | ||||
| @ -388,6 +387,6 @@ function write_sty_bin(wb, opts) { | ||||
| 	write_TABLESTYLES_bin(ba, wb); | ||||
| 	write_COLORPALETTE_bin(ba, wb); | ||||
| 	/* FRTSTYLESHEET*/ | ||||
| 	write_record(ba, 0x0117 /* BrtEndStyleSheet */); | ||||
| 	write_record(ba, "BrtEndStyleSheet"); | ||||
| 	return ba.end(); | ||||
| } | ||||
|  | ||||
| @ -1,3 +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 = [ | ||||
| 	'</a:lt1>', '</a:dk1>', '</a:lt2>', '</a:dk2>', | ||||
| @ -18,12 +20,10 @@ function parse_clrScheme(t, themes, opts) { | ||||
| 			/* 20.1.2.3.32 srgbClr CT_SRgbColor */ | ||||
| 			case '<a:srgbClr': | ||||
| 				color.rgb = y.val; break; | ||||
| 			case '</a:srgbClr>': break; | ||||
| 
 | ||||
| 			/* 20.1.2.3.33 sysClr CT_SystemColor */ | ||||
| 			case '<a:sysClr': | ||||
| 				color.rgb = y.lastClr; break; | ||||
| 			case '</a:sysClr>': break; | ||||
| 
 | ||||
| 			/* 20.1.4.1.1 accent1 (Accent 1) */ | ||||
| 			/* 20.1.4.1.2 accent2 (Accent 2) */ | ||||
| @ -37,10 +37,8 @@ function parse_clrScheme(t, themes, opts) { | ||||
| 			/* 20.1.4.1.19 hlink (Hyperlink) */ | ||||
| 			/* 20.1.4.1.22 lt1 (Light 1) */ | ||||
| 			/* 20.1.4.1.23 lt2 (Light 2) */ | ||||
| 			case '</a:dk1>': | ||||
| 			case '</a:lt1>': | ||||
| 			case '<a:dk1>': | ||||
| 			case '<a:lt1>': | ||||
| 			case '<a:dk1>': case '</a:dk1>': | ||||
| 			case '<a:lt1>': case '</a:lt1>': | ||||
| 			case '<a:dk2>': case '</a:dk2>': | ||||
| 			case '<a:lt2>': case '</a:lt2>': | ||||
| 			case '<a:accent1>': case '</a:accent1>': | ||||
| @ -70,35 +68,41 @@ function parse_fontScheme(/*::t, themes, opts*/) { } | ||||
| /* 20.1.4.1.15 fmtScheme CT_StyleMatrix */ | ||||
| function parse_fmtScheme(/*::t, themes, opts*/) { } | ||||
| 
 | ||||
| var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/; | ||||
| var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/; | ||||
| var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/; | ||||
| 
 | ||||
| /* 20.1.6.10 themeElements CT_BaseStyles */ | ||||
| function parse_themeElements(data, themes, opts) { | ||||
| 	themes.themeElements = {}; | ||||
| 
 | ||||
| 	var t; | ||||
| 
 | ||||
| 	/* clrScheme CT_ColorScheme */ | ||||
| 	if(!(t=str_match_xml(data, "a:clrScheme"))) throw new Error('clrScheme not found in themeElements'); | ||||
| 	parse_clrScheme(t, themes, opts); | ||||
| 
 | ||||
| 	/* fontScheme CT_FontScheme */ | ||||
| 	if(!(t=str_match_xml(data, "a:fontScheme"))) throw new Error('fontScheme not found in themeElements'); | ||||
| 	parse_fontScheme(t, themes, opts); | ||||
| 
 | ||||
| 	/* fmtScheme CT_StyleMatrix */ | ||||
| 	if(!(t=str_match_xml(data, "a:fmtScheme"))) throw new Error('fmtScheme not found in themeElements'); | ||||
| 	parse_fmtScheme(t, themes, opts); | ||||
| 	[ | ||||
| 		/* clrScheme CT_ColorScheme */ | ||||
| 		['clrScheme', clrsregex, parse_clrScheme], | ||||
| 		/* fontScheme CT_FontScheme */ | ||||
| 		['fontScheme', fntsregex, parse_fontScheme], | ||||
| 		/* fmtScheme CT_StyleMatrix */ | ||||
| 		['fmtScheme', fmtsregex, parse_fmtScheme] | ||||
| 	].forEach(function(m) { | ||||
| 		if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements'); | ||||
| 		m[2](t, themes, opts); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/; | ||||
| 
 | ||||
| /* 14.2.7 Theme Part */ | ||||
| function parse_theme_xml(data/*:string*/, opts) { | ||||
| 	/* 20.1.6.9 theme CT_OfficeStyleSheet */ | ||||
| 	if(!data || data.length === 0) data = write_theme(); | ||||
| 	if(!data || data.length === 0) return parse_theme_xml(write_theme()); | ||||
| 
 | ||||
| 	var t; | ||||
| 	var themes = {}; | ||||
| 
 | ||||
| 	/* themeElements CT_BaseStyles */ | ||||
| 	if(!(t=str_match_xml(data, "a:themeElements"))) throw new Error('themeElements not found in theme'); | ||||
| 	if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme'); | ||||
| 	parse_themeElements(t[0], themes, opts); | ||||
| 	themes.raw = data; | ||||
| 	return themes; | ||||
|  | ||||
| @ -3,10 +3,10 @@ function parse_Theme(blob, length, opts) { | ||||
| 	var end = blob.l + length; | ||||
| 	var dwThemeVersion = blob.read_shift(4); | ||||
| 	if(dwThemeVersion === 124226) return; | ||||
| 	if(!opts.cellStyles) { blob.l = end; return; } | ||||
| 	if(!opts.cellStyles || !jszip) { blob.l = end; return; } | ||||
| 	var data = blob.slice(blob.l); | ||||
| 	blob.l = end; | ||||
| 	var zip; try { zip = zip_read(data, {type: "array"}); } catch(e) { return; } | ||||
| 	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); | ||||
|  | ||||
| @ -1,111 +0,0 @@ | ||||
| function parse_BrtMdtinfo(data, length) { | ||||
|   return { | ||||
|     flags: data.read_shift(4), | ||||
|     version: data.read_shift(4), | ||||
|     name: parse_XLWideString(data, length - 8) | ||||
|   }; | ||||
| } | ||||
| function write_BrtMdtinfo(data) { | ||||
|   var o = new_buf(12 + 2 * data.name.length); | ||||
|   o.write_shift(4, data.flags); | ||||
|   o.write_shift(4, data.version); | ||||
|   write_XLWideString(data.name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function parse_BrtMdb(data) { | ||||
|   var out = []; | ||||
|   var cnt = data.read_shift(4); | ||||
|   while (cnt-- > 0) | ||||
|     out.push([data.read_shift(4), data.read_shift(4)]); | ||||
|   return out; | ||||
| } | ||||
| function write_BrtMdb(mdb) { | ||||
|   var o = new_buf(4 + 8 * mdb.length); | ||||
|   o.write_shift(4, mdb.length); | ||||
|   for (var i = 0; i < mdb.length; ++i) { | ||||
|     o.write_shift(4, mdb[i][0]); | ||||
|     o.write_shift(4, mdb[i][1]); | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function write_BrtBeginEsfmd(cnt, name) { | ||||
|   var o = new_buf(8 + 2 * name.length); | ||||
|   o.write_shift(4, cnt); | ||||
|   write_XLWideString(name, o); | ||||
|   return o.slice(0, o.l); | ||||
| } | ||||
| function parse_BrtBeginEsmdb(data) { | ||||
|   data.l += 4; | ||||
|   return data.read_shift(4) != 0; | ||||
| } | ||||
| function write_BrtBeginEsmdb(cnt, cm) { | ||||
|   var o = new_buf(8); | ||||
|   o.write_shift(4, cnt); | ||||
|   o.write_shift(4, cm ? 1 : 0); | ||||
|   return o; | ||||
| } | ||||
| function parse_xlmeta_bin(data, name, _opts) { | ||||
|   var out = { Types: [], Cell: [], Value: [] }; | ||||
|   var opts = _opts || {}; | ||||
|   var state = []; | ||||
|   var pass = false; | ||||
|   var metatype = 2; | ||||
|   recordhopper(data, function(val, R, RT) { | ||||
|     switch (RT) { | ||||
|       case 335: | ||||
|         out.Types.push({ name: val.name }); | ||||
|         break; | ||||
|       case 51: | ||||
|         val.forEach(function(r) { | ||||
|           if (metatype == 1) | ||||
|             out.Cell.push({ type: out.Types[r[0] - 1].name, index: r[1] }); | ||||
|           else if (metatype == 0) | ||||
|             out.Value.push({ type: out.Types[r[0] - 1].name, index: r[1] }); | ||||
|         }); | ||||
|         break; | ||||
|       case 337: | ||||
|         metatype = val ? 1 : 0; | ||||
|         break; | ||||
|       case 338: | ||||
|         metatype = 2; | ||||
|         break; | ||||
|       case 35: | ||||
|         state.push(RT); | ||||
|         pass = true; | ||||
|         break; | ||||
|       case 36: | ||||
|         state.pop(); | ||||
|         pass = false; | ||||
|         break; | ||||
|       default: | ||||
|         if (R.T) { | ||||
|         } else if (!pass || opts.WTF && state[state.length - 1] != 35) | ||||
|           throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
|     } | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_bin() { | ||||
|   var ba = buf_array(); | ||||
|   write_record(ba, 332); | ||||
|   write_record(ba, 334, write_UInt32LE(1)); | ||||
|   write_record(ba, 335, write_BrtMdtinfo({ | ||||
|     name: "XLDAPR", | ||||
|     version: 12e4, | ||||
|     flags: 3496657072 | ||||
|   })); | ||||
|   write_record(ba, 336); | ||||
|   write_record(ba, 339, write_BrtBeginEsfmd(1, "XLDAPR")); | ||||
|   write_record(ba, 52); | ||||
|   write_record(ba, 35, write_UInt32LE(514)); | ||||
|   write_record(ba, 4096, write_UInt32LE(0)); | ||||
|   write_record(ba, 4097, writeuint16(1)); | ||||
|   write_record(ba, 36); | ||||
|   write_record(ba, 53); | ||||
|   write_record(ba, 340); | ||||
|   write_record(ba, 337, write_BrtBeginEsmdb(1, true)); | ||||
|   write_record(ba, 51, write_BrtMdb([[1, 0]])); | ||||
|   write_record(ba, 338); | ||||
|   write_record(ba, 333); | ||||
|   return ba.end(); | ||||
| } | ||||
| @ -1,85 +0,0 @@ | ||||
| function parse_xlmeta_xml(data, name, opts) { | ||||
|   var out = { Types: [], Cell: [], Value: [] }; | ||||
|   if (!data) | ||||
|     return out; | ||||
|   var pass = false; | ||||
|   var metatype = 2; | ||||
|   var lastmeta; | ||||
|   data.replace(tagregex, function(x) { | ||||
|     var y = parsexmltag(x); | ||||
|     switch (strip_ns(y[0])) { | ||||
|       case "<?xml": | ||||
|         break; | ||||
|       case "<metadata": | ||||
|       case "</metadata>": | ||||
|         break; | ||||
|       case "<metadataTypes": | ||||
|       case "</metadataTypes>": | ||||
|         break; | ||||
|       case "<metadataType": | ||||
|         out.Types.push({ name: y.name }); | ||||
|         break; | ||||
|       case "</metadataType>": | ||||
|         break; | ||||
|       case "<futureMetadata": | ||||
|         for (var j = 0; j < out.Types.length; ++j) | ||||
|           if (out.Types[j].name == y.name) | ||||
|             lastmeta = out.Types[j]; | ||||
|         break; | ||||
|       case "</futureMetadata>": | ||||
|         break; | ||||
|       case "<bk>": | ||||
|         break; | ||||
|       case "</bk>": | ||||
|         break; | ||||
|       case "<rc": | ||||
|         if (metatype == 1) | ||||
|           out.Cell.push({ type: out.Types[y.t - 1].name, index: +y.v }); | ||||
|         else if (metatype == 0) | ||||
|           out.Value.push({ type: out.Types[y.t - 1].name, index: +y.v }); | ||||
|         break; | ||||
|       case "</rc>": | ||||
|         break; | ||||
|       case "<cellMetadata": | ||||
|         metatype = 1; | ||||
|         break; | ||||
|       case "</cellMetadata>": | ||||
|         metatype = 2; | ||||
|         break; | ||||
|       case "<valueMetadata": | ||||
|         metatype = 0; | ||||
|         break; | ||||
|       case "</valueMetadata>": | ||||
|         metatype = 2; | ||||
|         break; | ||||
|       case "<extLst": | ||||
|       case "<extLst>": | ||||
|       case "</extLst>": | ||||
|       case "<extLst/>": | ||||
|         break; | ||||
|       case "<ext": | ||||
|         pass = true; | ||||
|         break; | ||||
|       case "</ext>": | ||||
|         pass = false; | ||||
|         break; | ||||
|       case "<rvb": | ||||
|         if (!lastmeta) | ||||
|           break; | ||||
|         if (!lastmeta.offsets) | ||||
|           lastmeta.offsets = []; | ||||
|         lastmeta.offsets.push(+y.i); | ||||
|         break; | ||||
|       default: | ||||
|         if (!pass && (opts == null ? void 0 : opts.WTF)) | ||||
|           throw new Error("unrecognized " + y[0] + " in metadata"); | ||||
|     } | ||||
|     return x; | ||||
|   }); | ||||
|   return out; | ||||
| } | ||||
| function write_xlmeta_xml() { | ||||
|   var o = [XML_HEADER]; | ||||
|   o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>'); | ||||
|   return o.join(""); | ||||
| } | ||||
| @ -36,14 +36,15 @@ function parse_BrtCalcChainItem$(data) { | ||||
| function parse_cc_bin(data, name, opts) { | ||||
| 	var out = []; | ||||
| 	var pass = false; | ||||
| 	recordhopper(data, function hopper_cc(val, R, RT) { | ||||
| 	recordhopper(data, function hopper_cc(val, R_n, RT) { | ||||
| 		switch(RT) { | ||||
| 			case 0x003F: /* 'BrtCalcChainItem$' */ | ||||
| 				out.push(val); break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if(R.T){/* empty */} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
| 				if((R_n||"").indexOf("Begin") > 0){/* empty */} | ||||
| 				else if((R_n||"").indexOf("End") > 0){/* empty */} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n); | ||||
| 		} | ||||
| 	}); | ||||
| 	return out; | ||||
|  | ||||
| @ -11,7 +11,7 @@ function parse_xlink_bin(data, rel, name/*:string*/, _opts) { | ||||
| 
 | ||||
| 	var pass = false, end = false; | ||||
| 
 | ||||
| 	recordhopper(data, function xlink_parse(val, R, RT) { | ||||
| 	recordhopper(data, function xlink_parse(val, R_n, RT) { | ||||
| 		if(end) return; | ||||
| 		switch(RT) { | ||||
| 			case 0x0167: /* 'BrtSupTabs' */ | ||||
| @ -43,8 +43,9 @@ function parse_xlink_bin(data, rel, name/*:string*/, _opts) { | ||||
| 				pass = false; break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if(R.T){/* empty */} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
| 				if((R_n||"").indexOf("Begin") > 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); | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,7 @@ | ||||
| /* 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 */ | ||||
| function parse_drawing(data, rels/*:any*/) { | ||||
| 	if(!data) return "??"; | ||||
| @ -13,7 +16,7 @@ function parse_drawing(data, rels/*:any*/) { | ||||
| 	   the actual type is based on the URI of the graphicData | ||||
| 		TODO: handle embedded charts and other types of graphics | ||||
| 	*/ | ||||
| 	var id = (data.match(/<c:chart [^<>]*r:id="([^<>"]*)"/)||["",""])[1]; | ||||
| 	var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1]; | ||||
| 
 | ||||
| 	return rels['!id'][id].Target; | ||||
| } | ||||
|  | ||||
| @ -1,64 +1,20 @@ | ||||
| /* L.5.5.2 SpreadsheetML Comments + VML Schema */ | ||||
| function parse_vml(data/*:string*/, sheet, comments) { | ||||
| 	var cidx = 0; | ||||
| 	(str_match_xml_ns_g(data, "shape")||[]).forEach(function(m) { | ||||
| 		var type = ""; | ||||
| 		var hidden = true; | ||||
| 		var aidx = -1; | ||||
| 		var R = -1, C = -1; | ||||
| 		m.replace(tagregex, function(x/*:string*/, idx/*:number*/) { | ||||
| 			var y = parsexmltag(x); | ||||
| 			switch(strip_ns(y[0])) { | ||||
| 				case '<ClientData': if(y.ObjectType) type = y.ObjectType; break; | ||||
| 
 | ||||
| 				case '<Visible': case '<Visible/>': hidden = false; break; | ||||
| 
 | ||||
| 				case '<Row': case '<Row>': aidx = idx + x.length; break; | ||||
| 				case '</Row>': R = +m.slice(aidx, idx).trim(); break; | ||||
| 
 | ||||
| 				case '<Column': case '<Column>': aidx = idx + x.length; break; | ||||
| 				case '</Column>': C = +m.slice(aidx, idx).trim(); break; | ||||
| 			} | ||||
| 			return ""; | ||||
| 		}); | ||||
| 		switch(type) { | ||||
| 		case 'Note': | ||||
| 			var cell = ws_get_cell_stub(sheet, ((R>=0 && C>=0) ? encode_cell({r:R,c:C}) : comments[cidx].ref)); | ||||
| 			if(cell.c) { | ||||
| 				cell.c.hidden = hidden; | ||||
| 			} | ||||
| 			++cidx; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* comment boxes */ | ||||
| function write_vml(rId/*:number*/, comments, ws) { | ||||
| var _shapeid = 1024; | ||||
| function write_comments_vml(rId/*:number*/, 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(","); | ||||
| 	var o = [ | ||||
| 		writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"), | ||||
| 		writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}) | ||||
| 		writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}), | ||||
| 		writextag("v:shapetype", [ | ||||
| 			writextag("v:stroke", null, {joinstyle:"miter"}), | ||||
| 			writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"}) | ||||
| 		].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox}) | ||||
| 	]; | ||||
| 	while(_shapeid < rId * 1000) _shapeid += 1000; | ||||
| 
 | ||||
| 	var _shapeid = 65536 * rId; | ||||
| 
 | ||||
| 	var _comments = comments || []; | ||||
| 	if(_comments.length > 0) o.push(writextag("v:shapetype", [ | ||||
| 		writextag("v:stroke", null, {joinstyle:"miter"}), | ||||
| 		writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"}) | ||||
| 	].join(""), {id:"_x0000_t202", coordsize:csize.join(","), 'o:spt':202, path:bbox})); | ||||
| 
 | ||||
| 	_comments.forEach(function(x) { ++_shapeid; o.push(write_vml_comment(x, _shapeid)); }); | ||||
| 	o.push('</xml>'); | ||||
| 	return o.join(""); | ||||
| } | ||||
| 
 | ||||
| function write_vml_comment(x, _shapeid, ws)/*:string*/ { | ||||
| 	comments.forEach(function(x) { | ||||
| 	var c = decode_cell(x[0]); | ||||
| 	var fillopts = /*::(*/{'color2':"#BEFF82", 'type':"gradient"}/*:: :any)*/; | ||||
| 	if(fillopts.type == "gradient") fillopts.angle = "-180"; | ||||
| @ -66,8 +22,9 @@ function write_vml_comment(x, _shapeid, ws)/*:string*/ { | ||||
| 	var fillxml = writextag('v:fill', fillparm, fillopts); | ||||
| 
 | ||||
| 	var shadata = ({on:"t", 'obscured':"t"}/*:any*/); | ||||
| 	++_shapeid; | ||||
| 
 | ||||
| 	return [ | ||||
| 	o = o.concat([ | ||||
| 	'<v:shape' + wxt_helper({ | ||||
| 		id:'_x0000_s' + _shapeid, | ||||
| 		type:"#_x0000_t202", | ||||
| @ -90,5 +47,7 @@ function write_vml_comment(x, _shapeid, ws)/*:string*/ { | ||||
| 			x[1].hidden ? '' : '<x:Visible/>', | ||||
| 		'</x:ClientData>', | ||||
| 	'</v:shape>' | ||||
| 	].join(""); | ||||
| 	]); }); | ||||
| 	o.push('</xml>'); | ||||
| 	return o.join(""); | ||||
| } | ||||
|  | ||||
| @ -1,16 +1,17 @@ | ||||
| function sheet_insert_comments(sheet/*:WorkSheet*/, comments/*:Array<RawComment>*/, threaded/*:boolean*/, people/*:?Array<any>*/) { | ||||
| 	var dense = sheet["!data"] != null; | ||||
| RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"; | ||||
| 
 | ||||
| function sheet_insert_comments(sheet, comments/*:Array<RawComment>*/) { | ||||
| 	var dense = Array.isArray(sheet); | ||||
| 	var cell/*:Cell*/; | ||||
| 	comments.forEach(function(comment) { | ||||
| 		var r = decode_cell(comment.ref); | ||||
| 		if(r.r < 0 || r.c < 0) return; | ||||
| 		if(dense) { | ||||
| 			if(!sheet["!data"][r.r]) sheet["!data"][r.r] = []; | ||||
| 			cell = sheet["!data"][r.r][r.c]; | ||||
| 			if(!sheet[r.r]) sheet[r.r] = []; | ||||
| 			cell = sheet[r.r][r.c]; | ||||
| 		} else cell = sheet[comment.ref]; | ||||
| 		if (!cell) { | ||||
| 			cell = ({t:"z"}/*:any*/); | ||||
| 			if(dense) sheet["!data"][r.r][r.c] = 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; | ||||
| @ -18,21 +19,13 @@ function sheet_insert_comments(sheet/*:WorkSheet*/, comments/*:Array<RawComment> | ||||
| 			if(range.s.c > r.c) range.s.c = r.c; | ||||
| 			if(range.e.c < r.c) range.e.c = r.c; | ||||
| 			var encoded = encode_range(range); | ||||
| 			sheet["!ref"] = encoded; | ||||
| 			if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!cell.c) cell.c = []; | ||||
| 		var o/*:Comment*/ = ({a: comment.author, t: comment.t, r: comment.r, T: threaded}); | ||||
| 		var o/*:Comment*/ = ({a: comment.author, t: comment.t, r: comment.r}); | ||||
| 		if(comment.h) o.h = comment.h; | ||||
| 
 | ||||
| 		/* threaded comments always override */ | ||||
| 		for(var i = cell.c.length - 1; i >= 0; --i) { | ||||
| 			if(!threaded && cell.c[i].T) return; | ||||
| 			if(threaded && !cell.c[i].T) cell.c.splice(i, 1); | ||||
| 		} | ||||
| 		if(threaded && people) for(i = 0; i < people.length; ++i) { | ||||
| 			if(o.a == people[i].id) { o.a = people[i].name || o.a; break; } | ||||
| 		} | ||||
| 		cell.c.push(o); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -4,183 +4,54 @@ function parse_comments_xml(data/*:string*/, opts)/*:Array<RawComment>*/ { | ||||
| 	if(data.match(/<(?:\w+:)?comments *\/>/)) return []; | ||||
| 	var authors/*:Array<string>*/ = []; | ||||
| 	var commentList/*:Array<RawComment>*/ = []; | ||||
| 	var authtag = str_match_xml_ns(data, "authors"); | ||||
| 	var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\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[^<>]*>(.*)/); | ||||
| 		var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/); | ||||
| 		if(a) authors.push(a[1]); | ||||
| 	}); | ||||
| 	var cmnttag = str_match_xml_ns(data, "commentList"); | ||||
| 	var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/); | ||||
| 	if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) { | ||||
| 		if(x === "" || x.trim() === "") return; | ||||
| 		var cm = x.match(/<(?:\w+:)?comment[^<>]*>/); | ||||
| 		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 cell = decode_cell(y.ref); | ||||
| 		if(opts.sheetRows && opts.sheetRows <= cell.r) return; | ||||
| 		var textMatch = str_match_xml_ns(x, "text"); | ||||
| 		var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/); | ||||
| 		var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""}; | ||||
| 		comment.r = rt.r; | ||||
| 		if(rt.r == "<t></t>") 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); | ||||
| 	}); | ||||
| 	return commentList; | ||||
| } | ||||
| 
 | ||||
| var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] }); | ||||
| function write_comments_xml(data/*::, opts*/) { | ||||
| 	var o = [XML_HEADER, writextag('comments', null, { 'xmlns': XMLNS_main[0] })]; | ||||
| 	var o = [XML_HEADER, CMNT_XML_ROOT]; | ||||
| 
 | ||||
| 	var iauthor/*:Array<string>*/ = []; | ||||
| 	o.push("<authors>"); | ||||
| 	data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a); | ||||
| 		if(iauthor.indexOf(a) == -1) { | ||||
| 			iauthor.push(a); | ||||
| 			o.push("<author>" + a + "</author>"); | ||||
| 		} | ||||
| 		if(w.T && w.ID && iauthor.indexOf("tc=" + w.ID) == -1) { | ||||
| 			iauthor.push("tc=" + w.ID); | ||||
| 			o.push("<author>" + "tc=" + w.ID + "</author>"); | ||||
| 		} | ||||
| 		if(iauthor.indexOf(a) > -1) return; | ||||
| 		iauthor.push(a); | ||||
| 		o.push("<author>" + a + "</author>"); | ||||
| 	}); }); | ||||
| 	if(iauthor.length == 0) { iauthor.push("SheetJ5"); o.push("<author>SheetJ5</author>"); } | ||||
| 	o.push("</authors>"); | ||||
| 	o.push("<commentList>"); | ||||
| 	data.forEach(function(d) { | ||||
| 		/* 18.7.3 CT_Comment */ | ||||
| 		var lastauthor = 0, ts = [], tcnt = 0; | ||||
| 		if(d[1][0] && d[1][0].T && d[1][0].ID) lastauthor = iauthor.indexOf("tc=" + d[1][0].ID); | ||||
| 		d[1].forEach(function(c) { | ||||
| 			if(c.a) lastauthor = iauthor.indexOf(escapexml(c.a)); | ||||
| 			if(c.T) ++tcnt; | ||||
| 			ts.push(c.t == null ? "" : escapexml(c.t)); | ||||
| 		}); | ||||
| 		if(tcnt === 0) { | ||||
| 			d[1].forEach(function(c) { | ||||
| 				o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>'); | ||||
| 				o.push(writetag("t", c.t == null ? "" : escapexml(c.t))); | ||||
| 				o.push('</text></comment>'); | ||||
| 			}); | ||||
| 		} else { | ||||
| 			if(d[1][0] && d[1][0].T && d[1][0].ID) lastauthor = iauthor.indexOf("tc=" + d[1][0].ID); | ||||
| 			/* based on Threaded Comments -> Comments projection */ | ||||
| 			o.push('<comment ref="' + d[0] + '" authorId="' + lastauthor + '"><text>'); | ||||
| 			var t = "Comment:\n    " + (ts[0]) + "\n"; | ||||
| 			for(var i = 1; i < ts.length; ++i) t += "Reply:\n    " + ts[i] + "\n"; | ||||
| 			o.push(writetag("t", escapexml(t))); | ||||
| 			/* 18.7.3 CT_Comment */ | ||||
| 			o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>'); | ||||
| 			o.push(writetag("t", c.t == null ? "" : escapexml(c.t))); | ||||
| 			o.push('</text></comment>'); | ||||
| 		} | ||||
| 		}); | ||||
| 	}); | ||||
| 	o.push("</commentList>"); | ||||
| 	if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSX] 2.1.17 */ | ||||
| function parse_tcmnt_xml(data/*:string*/, opts)/*:Array<RawComment>*/ { | ||||
| 	var out = []; | ||||
| 	var pass = false, comment = {}, tidx = 0; | ||||
| 	data.replace(tagregex, function xml_tcmnt(x, idx) { | ||||
| 		var y/*:any*/ = parsexmltag(x); | ||||
| 		switch(strip_ns(y[0])) { | ||||
| 			case '<?xml': break; | ||||
| 
 | ||||
| 			/* 2.6.207 ThreadedComments CT_ThreadedComments */ | ||||
| 			case '<ThreadedComments': break; | ||||
| 			case '</ThreadedComments>': break; | ||||
| 
 | ||||
| 			/* 2.6.205 threadedComment CT_ThreadedComment */ | ||||
| 			case '<threadedComment': comment = {author: y.personId, guid: y.id, ref: y.ref, T: 1}; break; | ||||
| 			case '</threadedComment>': if(comment.t != null) out.push(comment); break; | ||||
| 
 | ||||
| 			case '<text>': case '<text': tidx = idx + x.length; break; | ||||
| 			case '</text>': comment.t = data.slice(tidx, idx).replace(/\r\n/g, "\n").replace(/\r/g, "\n"); break; | ||||
| 
 | ||||
| 			/* 2.6.206 mentions CT_ThreadedCommentMentions TODO */ | ||||
| 			case '<mentions': case '<mentions>': pass = true; break; | ||||
| 			case '</mentions>': pass = false; break; | ||||
| 
 | ||||
| 			/* 2.6.202 mention CT_Mention TODO */ | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 			/* 18.2.7  ext CT_Extension + */ | ||||
| 			case '<ext': pass=true; break; | ||||
| 			case '</ext>': pass=false; break; | ||||
| 
 | ||||
| 			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in threaded comments'); | ||||
| 		} | ||||
| 		return x; | ||||
| 	}); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| function write_tcmnt_xml(comments, people, opts) { | ||||
| 	var o = [XML_HEADER, writextag('ThreadedComments', null, { 'xmlns': XMLNS.TCMNT }).replace(/[\/]>/, ">")]; | ||||
| 	comments.forEach(function(carr) { | ||||
| 		var rootid = ""; | ||||
| 		(carr[1] || []).forEach(function(c, idx) { | ||||
| 			if(!c.T) { delete c.ID; return; } | ||||
| 			if(c.a && people.indexOf(c.a) == -1) people.push(c.a); | ||||
| 			var tcopts = { | ||||
| 				ref: carr[0], | ||||
| 				id: "{54EE7951-7262-4200-6969-" + ("000000000000" + opts.tcid++).slice(-12) + "}" | ||||
| 			}; | ||||
| 			if(idx == 0) rootid = tcopts.id; | ||||
| 			else tcopts.parentId = rootid; | ||||
| 			c.ID = tcopts.id; | ||||
| 			if(c.a) tcopts.personId = "{54EE7950-7262-4200-6969-" + ("000000000000" + people.indexOf(c.a)).slice(-12) + "}"; | ||||
| 			o.push(writextag('threadedComment', writetag('text', c.t||""), tcopts)); | ||||
| 		}); | ||||
| 	}); | ||||
| 	o.push('</ThreadedComments>'); | ||||
| 	return o.join(""); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSX] 2.1.18 */ | ||||
| function parse_people_xml(data/*:string*/, opts) { | ||||
| 	var out = []; | ||||
| 	var pass = false; | ||||
| 	data.replace(tagregex, function xml_tcmnt(x) { | ||||
| 		var y/*:any*/ = parsexmltag(x); | ||||
| 		switch(strip_ns(y[0])) { | ||||
| 			case '<?xml': break; | ||||
| 
 | ||||
| 			/* 2.4.85 personList CT_PersonList */ | ||||
| 			case '<personList': break; | ||||
| 			case '</personList>': break; | ||||
| 
 | ||||
| 			/* 2.6.203 person CT_Person TODO: providers */ | ||||
| 			case '<person': out.push({name: y.displayname, id: y.id }); break; | ||||
| 			case '</person>': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 			/* 18.2.7  ext CT_Extension + */ | ||||
| 			case '<ext': pass=true; break; | ||||
| 			case '</ext>': pass=false; break; | ||||
| 
 | ||||
| 			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in threaded comments'); | ||||
| 		} | ||||
| 		return x; | ||||
| 	}); | ||||
| 	return out; | ||||
| } | ||||
| function write_people_xml(people/*, opts*/) { | ||||
| 	var o = [XML_HEADER, writextag('personList', null, { | ||||
| 		'xmlns': XMLNS.TCMNT, | ||||
| 		'xmlns:x': XMLNS_main[0] | ||||
| 	}).replace(/[\/]>/, ">")]; | ||||
| 	people.forEach(function(person, idx) { | ||||
| 		o.push(writextag('person', null, { | ||||
| 			displayName: person, | ||||
| 			id: "{54EE7950-7262-4200-6969-" + ("000000000000" + idx).slice(-12) + "}", | ||||
| 			userId: person, | ||||
| 			providerId: "None" | ||||
| 		})); | ||||
| 	}); | ||||
| 	o.push("</personList>"); | ||||
| 	return o.join(""); | ||||
| } | ||||
|  | ||||
| @ -29,7 +29,7 @@ function parse_comments_bin(data, opts)/*:Array<RawComment>*/ { | ||||
| 	var authors/*:Array<string>*/ = []; | ||||
| 	var c = {}; | ||||
| 	var pass = false; | ||||
| 	recordhopper(data, function hopper_cmnt(val, R, RT) { | ||||
| 	recordhopper(data, function hopper_cmnt(val, R_n, RT) { | ||||
| 		switch(RT) { | ||||
| 			case 0x0278: /* 'BrtCommentAuthor' */ | ||||
| 				authors.push(val); break; | ||||
| @ -56,8 +56,9 @@ function parse_comments_bin(data, opts)/*:Array<RawComment>*/ { | ||||
| 
 | ||||
| 
 | ||||
| 			default: | ||||
| 				if(R.T){/* empty */} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
| 				if((R_n||"").indexOf("Begin") > 0){/* empty */} | ||||
| 				else if((R_n||"").indexOf("End") > 0){/* empty */} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n); | ||||
| 		} | ||||
| 	}); | ||||
| 	return out; | ||||
| @ -66,39 +67,31 @@ function parse_comments_bin(data, opts)/*:Array<RawComment>*/ { | ||||
| function write_comments_bin(data/*::, opts*/) { | ||||
| 	var ba = buf_array(); | ||||
| 	var iauthor/*:Array<string>*/ = []; | ||||
| 	write_record(ba, 0x0274 /* BrtBeginComments */); | ||||
| 	write_record(ba, "BrtBeginComments"); | ||||
| 
 | ||||
| 	write_record(ba, 0x0276 /* BrtBeginCommentAuthors */); | ||||
| 	write_record(ba, "BrtBeginCommentAuthors"); | ||||
| 	data.forEach(function(comment) { | ||||
| 		comment[1].forEach(function(c) { | ||||
| 			if(iauthor.indexOf(c.a) > -1) return; | ||||
| 			iauthor.push(c.a.slice(0,54)); | ||||
| 			write_record(ba, 0x0278 /* BrtCommentAuthor */, write_BrtCommentAuthor(c.a)); | ||||
| 			if(c.T && c.ID && iauthor.indexOf("tc=" + c.ID) == -1) { | ||||
| 				iauthor.push("tc=" + c.ID); | ||||
| 				write_record(ba, 0x0278 /* BrtCommentAuthor */, write_BrtCommentAuthor("tc=" + c.ID)); | ||||
| 			} | ||||
| 			write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a)); | ||||
| 		}); | ||||
| 	}); | ||||
| 	write_record(ba, 0x0277 /* BrtEndCommentAuthors */); | ||||
| 	write_record(ba, "BrtEndCommentAuthors"); | ||||
| 
 | ||||
| 	write_record(ba, 0x0279 /* BrtBeginCommentList */); | ||||
| 	write_record(ba, "BrtBeginCommentList"); | ||||
| 	data.forEach(function(comment) { | ||||
| 		comment[1].forEach(function(c) { | ||||
| 			var _ia = -1; | ||||
| 			if(c.ID) _ia = iauthor.indexOf("tc=" + c.ID); | ||||
| 			if(_ia == -1 && comment[1][0].T && comment[1][0].ID) _ia = iauthor.indexOf("tc=" + comment[1][0].ID); | ||||
| 			if(_ia == -1) _ia = iauthor.indexOf(c.a); | ||||
| 			c.iauthor = _ia; | ||||
| 			c.iauthor = iauthor.indexOf(c.a); | ||||
| 			var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])}; | ||||
| 			write_record(ba, 0x027B /* BrtBeginComment */, write_BrtBeginComment([range, c])); | ||||
| 			if(c.t && c.t.length > 0) write_record(ba, 0x027D /* BrtCommentText */, write_BrtCommentText(c)); | ||||
| 			write_record(ba, 0x027C /* BrtEndComment */); | ||||
| 			write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c])); | ||||
| 			if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c)); | ||||
| 			write_record(ba, "BrtEndComment"); | ||||
| 			delete c.iauthor; | ||||
| 		}); | ||||
| 	}); | ||||
| 	write_record(ba, 0x027A /* BrtEndCommentList */); | ||||
| 	write_record(ba, "BrtEndCommentList"); | ||||
| 
 | ||||
| 	write_record(ba, 0x0275 /* BrtEndComments */); | ||||
| 	write_record(ba, "BrtEndComments"); | ||||
| 	return ba.end(); | ||||
| } | ||||
|  | ||||
| @ -1,21 +1,21 @@ | ||||
| var CT_VBA = "application/vnd.ms-office.vbaProject"; | ||||
| function make_vba_xls(cfb) { | ||||
|   var newcfb = CFB.utils.cfb_new({ root: "R" }); | ||||
|   cfb.FullPaths.forEach(function(p, i) { | ||||
|     if (p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) | ||||
|       return; | ||||
|     var newpath = p.replace(/^[^\/]*/, "R").replace(/\/_VBA_PROJECT_CUR\u0000*/, ""); | ||||
|     CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content); | ||||
|   }); | ||||
|   return CFB.write(newcfb); | ||||
| function make_vba_xls(cfb/*:CFBContainer*/) { | ||||
| 	var newcfb = CFB.utils.cfb_new({root:"R"}); | ||||
| 	cfb.FullPaths.forEach(function(p, i) { | ||||
| 		if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return; | ||||
| 		var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, ""); | ||||
| 		CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content); | ||||
| 	}); | ||||
| 	return CFB.write(newcfb); | ||||
| } | ||||
| function fill_vba_xls(cfb, vba) { | ||||
|   vba.FullPaths.forEach(function(p, i) { | ||||
|     if (i == 0) | ||||
|       return; | ||||
|     var newpath = p.replace(/^[\/]*[^\/]*[\/]/, "/_VBA_PROJECT_CUR/"); | ||||
|     if (newpath.slice(-1) !== "/") | ||||
|       CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content); | ||||
|   }); | ||||
| 
 | ||||
| function fill_vba_xls(cfb/*:CFBContainer*/, vba/*:CFBContainer*/)/*:void*/ { | ||||
| 	vba.FullPaths.forEach(function(p, i) { | ||||
| 		if(i == 0) return; | ||||
| 		var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/"); | ||||
| 		if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content); | ||||
| 	}); | ||||
| } | ||||
| var VBAFMTS = ["xlsb", "xlsm", "xlam", "biff8", "xla"]; | ||||
| 
 | ||||
| var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ]; | ||||
| 
 | ||||
|  | ||||
| @ -1,3 +1,6 @@ | ||||
| RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"; | ||||
| RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet"; | ||||
| 
 | ||||
| /* macro and dialog sheet stubs */ | ||||
| function parse_ds_bin(/*::data:any, opts, idx:number, rels, wb, themes, styles*/)/*:Worksheet*/ { return {'!type':'dialog'}; } | ||||
| function parse_ds_xml(/*::data:any, opts, idx:number, rels, wb, themes, styles*/)/*:Worksheet*/ { return {'!type':'dialog'}; } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /* TODO: it will be useful to parse the function str */ | ||||
| var rc_to_a1 = /*#__PURE__*/(function(){ | ||||
| var rc_to_a1 = (function(){ | ||||
| 	var rcregex = /(^|[^A-Za-z_])R(\[?-?\d+\]|[1-9]\d*|)C(\[?-?\d+\]|[1-9]\d*|)(?![A-Za-z0-9_])/g; | ||||
| 	var rcbase/*:Cell*/ = ({r:0,c:0}/*:any*/); | ||||
| 	function rcfunc($$,$1,$2,$3) { | ||||
| @ -23,17 +23,14 @@ var rc_to_a1 = /*#__PURE__*/(function(){ | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g; | ||||
| try { | ||||
| 	crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g; | ||||
| }catch(e){} | ||||
| var a1_to_rc = /*#__PURE__*/(function(){ | ||||
| var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g; | ||||
| var a1_to_rc =(function(){ | ||||
| 	return function a1_to_rc(fstr/*:string*/, base/*:CellAddress*/) { | ||||
| 		return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) { | ||||
| 			var c = decode_col($3) - ($2 ? 0 : base.c); | ||||
| 			var r = decode_row($5) - ($4 ? 0 : base.r); | ||||
| 			var R = $4 == "$" ? (r+1) : (r == 0 ? "" : "[" + r + "]"); | ||||
| 			var C = $2 == "$" ? (c+1) : (c == 0 ? "" : "[" + c + "]"); | ||||
| 			var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1)); | ||||
| 			var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1)); | ||||
| 			return $1 + "R" + R + "C" + C; | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
							
								
								
									
										227
									
								
								bits/62_fxls.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										227
									
								
								bits/62_fxls.js
									
									
									
									
									
								
							| @ -495,113 +495,114 @@ function parse_PtgAttrNoop(blob/*::, length, opts*/) { | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.198.25 ; [MS-XLSB] 2.5.97.16 */ | ||||
| var PtgTypes = { | ||||
| 	0x01: { n:'PtgExp', f:parse_PtgExp }, | ||||
| 	0x02: { n:'PtgTbl', f:parse_PtgTbl }, | ||||
| 	0x03: { n:'PtgAdd', f:parseread1 }, | ||||
| 	0x04: { n:'PtgSub', f:parseread1 }, | ||||
| 	0x05: { n:'PtgMul', f:parseread1 }, | ||||
| 	0x06: { n:'PtgDiv', f:parseread1 }, | ||||
| 	0x07: { n:'PtgPower', f:parseread1 }, | ||||
| 	0x08: { n:'PtgConcat', f:parseread1 }, | ||||
| 	0x09: { n:'PtgLt', f:parseread1 }, | ||||
| 	0x0A: { n:'PtgLe', f:parseread1 }, | ||||
| 	0x0B: { n:'PtgEq', f:parseread1 }, | ||||
| 	0x0C: { n:'PtgGe', f:parseread1 }, | ||||
| 	0x0D: { n:'PtgGt', f:parseread1 }, | ||||
| 	0x0E: { n:'PtgNe', f:parseread1 }, | ||||
| 	0x0F: { n:'PtgIsect', f:parseread1 }, | ||||
| 	0x10: { n:'PtgUnion', f:parseread1 }, | ||||
| 	0x11: { n:'PtgRange', f:parseread1 }, | ||||
| 	0x12: { n:'PtgUplus', f:parseread1 }, | ||||
| 	0x13: { n:'PtgUminus', f:parseread1 }, | ||||
| 	0x14: { n:'PtgPercent', f:parseread1 }, | ||||
| 	0x15: { n:'PtgParen', f:parseread1 }, | ||||
| 	0x16: { n:'PtgMissArg', f:parseread1 }, | ||||
| 	0x17: { n:'PtgStr', f:parse_PtgStr }, | ||||
| 	0x1A: { n:'PtgSheet', f:parse_PtgSheet }, | ||||
| 	0x1B: { n:'PtgEndSheet', f:parse_PtgEndSheet }, | ||||
| 	0x1C: { n:'PtgErr', f:parse_PtgErr }, | ||||
| 	0x1D: { n:'PtgBool', f:parse_PtgBool }, | ||||
| 	0x1E: { n:'PtgInt', f:parse_PtgInt }, | ||||
| 	0x1F: { n:'PtgNum', f:parse_PtgNum }, | ||||
| 	0x20: { n:'PtgArray', f:parse_PtgArray }, | ||||
| 	0x21: { n:'PtgFunc', f:parse_PtgFunc }, | ||||
| 	0x22: { n:'PtgFuncVar', f:parse_PtgFuncVar }, | ||||
| 	0x23: { n:'PtgName', f:parse_PtgName }, | ||||
| 	0x24: { n:'PtgRef', f:parse_PtgRef }, | ||||
| 	0x25: { n:'PtgArea', f:parse_PtgArea }, | ||||
| 	0x26: { n:'PtgMemArea', f:parse_PtgMemArea }, | ||||
| 	0x27: { n:'PtgMemErr', f:parse_PtgMemErr }, | ||||
| 	0x28: { n:'PtgMemNoMem', f:parse_PtgMemNoMem }, | ||||
| 	0x29: { n:'PtgMemFunc', f:parse_PtgMemFunc }, | ||||
| 	0x2A: { n:'PtgRefErr', f:parse_PtgRefErr }, | ||||
| 	0x2B: { n:'PtgAreaErr', f:parse_PtgAreaErr }, | ||||
| 	0x2C: { n:'PtgRefN', f:parse_PtgRefN }, | ||||
| 	0x2D: { n:'PtgAreaN', f:parse_PtgAreaN }, | ||||
| 	0x2E: { n:'PtgMemAreaN', f:parse_PtgMemAreaN }, | ||||
| 	0x2F: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN }, | ||||
| 	0x39: { n:'PtgNameX', f:parse_PtgNameX }, | ||||
| 	0x3A: { n:'PtgRef3d', f:parse_PtgRef3d }, | ||||
| 	0x3B: { n:'PtgArea3d', f:parse_PtgArea3d }, | ||||
| 	0x3C: { n:'PtgRefErr3d', f:parse_PtgRefErr3d }, | ||||
| 	0x3D: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d }, | ||||
| 	0xFF: {} | ||||
| 	/*::[*/0x01/*::]*/: { n:'PtgExp', f:parse_PtgExp }, | ||||
| 	/*::[*/0x02/*::]*/: { n:'PtgTbl', f:parse_PtgTbl }, | ||||
| 	/*::[*/0x03/*::]*/: { n:'PtgAdd', f:parseread1 }, | ||||
| 	/*::[*/0x04/*::]*/: { n:'PtgSub', f:parseread1 }, | ||||
| 	/*::[*/0x05/*::]*/: { n:'PtgMul', f:parseread1 }, | ||||
| 	/*::[*/0x06/*::]*/: { n:'PtgDiv', f:parseread1 }, | ||||
| 	/*::[*/0x07/*::]*/: { n:'PtgPower', f:parseread1 }, | ||||
| 	/*::[*/0x08/*::]*/: { n:'PtgConcat', f:parseread1 }, | ||||
| 	/*::[*/0x09/*::]*/: { n:'PtgLt', f:parseread1 }, | ||||
| 	/*::[*/0x0A/*::]*/: { n:'PtgLe', f:parseread1 }, | ||||
| 	/*::[*/0x0B/*::]*/: { n:'PtgEq', f:parseread1 }, | ||||
| 	/*::[*/0x0C/*::]*/: { n:'PtgGe', f:parseread1 }, | ||||
| 	/*::[*/0x0D/*::]*/: { n:'PtgGt', f:parseread1 }, | ||||
| 	/*::[*/0x0E/*::]*/: { n:'PtgNe', f:parseread1 }, | ||||
| 	/*::[*/0x0F/*::]*/: { n:'PtgIsect', f:parseread1 }, | ||||
| 	/*::[*/0x10/*::]*/: { n:'PtgUnion', f:parseread1 }, | ||||
| 	/*::[*/0x11/*::]*/: { n:'PtgRange', f:parseread1 }, | ||||
| 	/*::[*/0x12/*::]*/: { n:'PtgUplus', f:parseread1 }, | ||||
| 	/*::[*/0x13/*::]*/: { n:'PtgUminus', f:parseread1 }, | ||||
| 	/*::[*/0x14/*::]*/: { n:'PtgPercent', f:parseread1 }, | ||||
| 	/*::[*/0x15/*::]*/: { n:'PtgParen', f:parseread1 }, | ||||
| 	/*::[*/0x16/*::]*/: { n:'PtgMissArg', f:parseread1 }, | ||||
| 	/*::[*/0x17/*::]*/: { n:'PtgStr', f:parse_PtgStr }, | ||||
| 	/*::[*/0x1A/*::]*/: { n:'PtgSheet', f:parse_PtgSheet }, | ||||
| 	/*::[*/0x1B/*::]*/: { n:'PtgEndSheet', f:parse_PtgEndSheet }, | ||||
| 	/*::[*/0x1C/*::]*/: { n:'PtgErr', f:parse_PtgErr }, | ||||
| 	/*::[*/0x1D/*::]*/: { n:'PtgBool', f:parse_PtgBool }, | ||||
| 	/*::[*/0x1E/*::]*/: { n:'PtgInt', f:parse_PtgInt }, | ||||
| 	/*::[*/0x1F/*::]*/: { n:'PtgNum', f:parse_PtgNum }, | ||||
| 	/*::[*/0x20/*::]*/: { n:'PtgArray', f:parse_PtgArray }, | ||||
| 	/*::[*/0x21/*::]*/: { n:'PtgFunc', f:parse_PtgFunc }, | ||||
| 	/*::[*/0x22/*::]*/: { n:'PtgFuncVar', f:parse_PtgFuncVar }, | ||||
| 	/*::[*/0x23/*::]*/: { n:'PtgName', f:parse_PtgName }, | ||||
| 	/*::[*/0x24/*::]*/: { n:'PtgRef', f:parse_PtgRef }, | ||||
| 	/*::[*/0x25/*::]*/: { n:'PtgArea', f:parse_PtgArea }, | ||||
| 	/*::[*/0x26/*::]*/: { n:'PtgMemArea', f:parse_PtgMemArea }, | ||||
| 	/*::[*/0x27/*::]*/: { n:'PtgMemErr', f:parse_PtgMemErr }, | ||||
| 	/*::[*/0x28/*::]*/: { n:'PtgMemNoMem', f:parse_PtgMemNoMem }, | ||||
| 	/*::[*/0x29/*::]*/: { n:'PtgMemFunc', f:parse_PtgMemFunc }, | ||||
| 	/*::[*/0x2A/*::]*/: { n:'PtgRefErr', f:parse_PtgRefErr }, | ||||
| 	/*::[*/0x2B/*::]*/: { n:'PtgAreaErr', f:parse_PtgAreaErr }, | ||||
| 	/*::[*/0x2C/*::]*/: { n:'PtgRefN', f:parse_PtgRefN }, | ||||
| 	/*::[*/0x2D/*::]*/: { n:'PtgAreaN', f:parse_PtgAreaN }, | ||||
| 	/*::[*/0x2E/*::]*/: { n:'PtgMemAreaN', f:parse_PtgMemAreaN }, | ||||
| 	/*::[*/0x2F/*::]*/: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN }, | ||||
| 	/*::[*/0x39/*::]*/: { n:'PtgNameX', f:parse_PtgNameX }, | ||||
| 	/*::[*/0x3A/*::]*/: { n:'PtgRef3d', f:parse_PtgRef3d }, | ||||
| 	/*::[*/0x3B/*::]*/: { n:'PtgArea3d', f:parse_PtgArea3d }, | ||||
| 	/*::[*/0x3C/*::]*/: { n:'PtgRefErr3d', f:parse_PtgRefErr3d }, | ||||
| 	/*::[*/0x3D/*::]*/: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d }, | ||||
| 	/*::[*/0xFF/*::]*/: {} | ||||
| }; | ||||
| /* These are duplicated in the PtgTypes table */ | ||||
| var PtgDupes = { | ||||
| 	0x40: 0x20, 0x60: 0x20, | ||||
| 	0x41: 0x21, 0x61: 0x21, | ||||
| 	0x42: 0x22, 0x62: 0x22, | ||||
| 	0x43: 0x23, 0x63: 0x23, | ||||
| 	0x44: 0x24, 0x64: 0x24, | ||||
| 	0x45: 0x25, 0x65: 0x25, | ||||
| 	0x46: 0x26, 0x66: 0x26, | ||||
| 	0x47: 0x27, 0x67: 0x27, | ||||
| 	0x48: 0x28, 0x68: 0x28, | ||||
| 	0x49: 0x29, 0x69: 0x29, | ||||
| 	0x4A: 0x2A, 0x6A: 0x2A, | ||||
| 	0x4B: 0x2B, 0x6B: 0x2B, | ||||
| 	0x4C: 0x2C, 0x6C: 0x2C, | ||||
| 	0x4D: 0x2D, 0x6D: 0x2D, | ||||
| 	0x4E: 0x2E, 0x6E: 0x2E, | ||||
| 	0x4F: 0x2F, 0x6F: 0x2F, | ||||
| 	0x58: 0x22, 0x78: 0x22, | ||||
| 	0x59: 0x39, 0x79: 0x39, | ||||
| 	0x5A: 0x3A, 0x7A: 0x3A, | ||||
| 	0x5B: 0x3B, 0x7B: 0x3B, | ||||
| 	0x5C: 0x3C, 0x7C: 0x3C, | ||||
| 	0x5D: 0x3D, 0x7D: 0x3D | ||||
| 	/*::[*/0x40/*::]*/: 0x20, /*::[*/0x60/*::]*/: 0x20, | ||||
| 	/*::[*/0x41/*::]*/: 0x21, /*::[*/0x61/*::]*/: 0x21, | ||||
| 	/*::[*/0x42/*::]*/: 0x22, /*::[*/0x62/*::]*/: 0x22, | ||||
| 	/*::[*/0x43/*::]*/: 0x23, /*::[*/0x63/*::]*/: 0x23, | ||||
| 	/*::[*/0x44/*::]*/: 0x24, /*::[*/0x64/*::]*/: 0x24, | ||||
| 	/*::[*/0x45/*::]*/: 0x25, /*::[*/0x65/*::]*/: 0x25, | ||||
| 	/*::[*/0x46/*::]*/: 0x26, /*::[*/0x66/*::]*/: 0x26, | ||||
| 	/*::[*/0x47/*::]*/: 0x27, /*::[*/0x67/*::]*/: 0x27, | ||||
| 	/*::[*/0x48/*::]*/: 0x28, /*::[*/0x68/*::]*/: 0x28, | ||||
| 	/*::[*/0x49/*::]*/: 0x29, /*::[*/0x69/*::]*/: 0x29, | ||||
| 	/*::[*/0x4A/*::]*/: 0x2A, /*::[*/0x6A/*::]*/: 0x2A, | ||||
| 	/*::[*/0x4B/*::]*/: 0x2B, /*::[*/0x6B/*::]*/: 0x2B, | ||||
| 	/*::[*/0x4C/*::]*/: 0x2C, /*::[*/0x6C/*::]*/: 0x2C, | ||||
| 	/*::[*/0x4D/*::]*/: 0x2D, /*::[*/0x6D/*::]*/: 0x2D, | ||||
| 	/*::[*/0x4E/*::]*/: 0x2E, /*::[*/0x6E/*::]*/: 0x2E, | ||||
| 	/*::[*/0x4F/*::]*/: 0x2F, /*::[*/0x6F/*::]*/: 0x2F, | ||||
| 	/*::[*/0x58/*::]*/: 0x22, /*::[*/0x78/*::]*/: 0x22, | ||||
| 	/*::[*/0x59/*::]*/: 0x39, /*::[*/0x79/*::]*/: 0x39, | ||||
| 	/*::[*/0x5A/*::]*/: 0x3A, /*::[*/0x7A/*::]*/: 0x3A, | ||||
| 	/*::[*/0x5B/*::]*/: 0x3B, /*::[*/0x7B/*::]*/: 0x3B, | ||||
| 	/*::[*/0x5C/*::]*/: 0x3C, /*::[*/0x7C/*::]*/: 0x3C, | ||||
| 	/*::[*/0x5D/*::]*/: 0x3D, /*::[*/0x7D/*::]*/: 0x3D | ||||
| }; | ||||
| (function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})(); | ||||
| 
 | ||||
| var Ptg18 = { | ||||
| 	0x01: { n:'PtgElfLel', f:parse_PtgElfLel }, | ||||
| 	0x02: { n:'PtgElfRw', f:parse_PtgElfRw }, | ||||
| 	0x03: { n:'PtgElfCol', f:parse_PtgElfCol }, | ||||
| 	0x06: { n:'PtgElfRwV', f:parse_PtgElfRwV }, | ||||
| 	0x07: { n:'PtgElfColV', f:parse_PtgElfColV }, | ||||
| 	0x0A: { n:'PtgElfRadical', f:parse_PtgElfRadical }, | ||||
| 	0x0B: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS }, | ||||
| 	0x0D: { n:'PtgElfColS', f:parse_PtgElfColS }, | ||||
| 	0x0F: { n:'PtgElfColSV', f:parse_PtgElfColSV }, | ||||
| 	0x10: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel }, | ||||
| 	0x19: { n:'PtgList', f:parse_PtgList }, | ||||
| 	0x1D: { n:'PtgSxName', f:parse_PtgSxName }, | ||||
| 	0xFF: {} | ||||
| 	/*::[*/0x01/*::]*/: { n:'PtgElfLel', f:parse_PtgElfLel }, | ||||
| 	/*::[*/0x02/*::]*/: { n:'PtgElfRw', f:parse_PtgElfRw }, | ||||
| 	/*::[*/0x03/*::]*/: { n:'PtgElfCol', f:parse_PtgElfCol }, | ||||
| 	/*::[*/0x06/*::]*/: { n:'PtgElfRwV', f:parse_PtgElfRwV }, | ||||
| 	/*::[*/0x07/*::]*/: { n:'PtgElfColV', f:parse_PtgElfColV }, | ||||
| 	/*::[*/0x0A/*::]*/: { n:'PtgElfRadical', f:parse_PtgElfRadical }, | ||||
| 	/*::[*/0x0B/*::]*/: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS }, | ||||
| 	/*::[*/0x0D/*::]*/: { n:'PtgElfColS', f:parse_PtgElfColS }, | ||||
| 	/*::[*/0x0F/*::]*/: { n:'PtgElfColSV', f:parse_PtgElfColSV }, | ||||
| 	/*::[*/0x10/*::]*/: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel }, | ||||
| 	/*::[*/0x19/*::]*/: { n:'PtgList', f:parse_PtgList }, | ||||
| 	/*::[*/0x1D/*::]*/: { n:'PtgSxName', f:parse_PtgSxName }, | ||||
| 	/*::[*/0xFF/*::]*/: {} | ||||
| }; | ||||
| var Ptg19 = { | ||||
| 	0x00: { n:'PtgAttrNoop', f:parse_PtgAttrNoop }, | ||||
| 	0x01: { n:'PtgAttrSemi', f:parse_PtgAttrSemi }, | ||||
| 	0x02: { n:'PtgAttrIf', f:parse_PtgAttrIf }, | ||||
| 	0x04: { n:'PtgAttrChoose', f:parse_PtgAttrChoose }, | ||||
| 	0x08: { n:'PtgAttrGoto', f:parse_PtgAttrGoto }, | ||||
| 	0x10: { n:'PtgAttrSum', f:parse_PtgAttrSum }, | ||||
| 	0x20: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel }, | ||||
| 	0x21: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel }, | ||||
| 	0x40: { n:'PtgAttrSpace', f:parse_PtgAttrSpace }, | ||||
| 	0x41: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi }, | ||||
| 	0x80: { n:'PtgAttrIfError', f:parse_PtgAttrIfError }, | ||||
| 	0xFF: {} | ||||
| 	/*::[*/0x00/*::]*/: { n:'PtgAttrNoop', f:parse_PtgAttrNoop }, | ||||
| 	/*::[*/0x01/*::]*/: { n:'PtgAttrSemi', f:parse_PtgAttrSemi }, | ||||
| 	/*::[*/0x02/*::]*/: { n:'PtgAttrIf', f:parse_PtgAttrIf }, | ||||
| 	/*::[*/0x04/*::]*/: { n:'PtgAttrChoose', f:parse_PtgAttrChoose }, | ||||
| 	/*::[*/0x08/*::]*/: { n:'PtgAttrGoto', f:parse_PtgAttrGoto }, | ||||
| 	/*::[*/0x10/*::]*/: { n:'PtgAttrSum', f:parse_PtgAttrSum }, | ||||
| 	/*::[*/0x20/*::]*/: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel }, | ||||
| 	/*::[*/0x40/*::]*/: { n:'PtgAttrSpace', f:parse_PtgAttrSpace }, | ||||
| 	/*::[*/0x41/*::]*/: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi }, | ||||
| 	/*::[*/0x80/*::]*/: { n:'PtgAttrIfError', f:parse_PtgAttrIfError }, | ||||
| 	/*::[*/0xFF/*::]*/: {} | ||||
| }; | ||||
| Ptg19[0x21] = Ptg19[0x20]; | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */ | ||||
| function parse_RgbExtra(blob, length, rgce, opts) { | ||||
| @ -645,7 +646,7 @@ function parse_Rgce(blob, length, opts) { | ||||
| 	while(target != blob.l) { | ||||
| 		length = target - blob.l; | ||||
| 		id = blob[blob.l]; | ||||
| 		R = PtgTypes[id] || PtgTypes[PtgDupes[id]]; | ||||
| 		R = PtgTypes[id]; | ||||
| 		if(id === 0x18 || id === 0x19) R = (id === 0x18 ? Ptg18 : Ptg19)[blob[blob.l + 1]]; | ||||
| 		if(!R || !R.f) { /*ptgs.push*/(parsenoop(blob, length)); } | ||||
| 		else { ptgs.push([R.n, R.f(blob, length, opts)]); } | ||||
| @ -688,15 +689,13 @@ var PtgBinOp = { | ||||
| 	PtgSub: "-" | ||||
| }; | ||||
| 
 | ||||
| // TODO: explore space
 | ||||
| function make_3d_range(start, end) { | ||||
| 	var s = start.lastIndexOf("!"), e = end.lastIndexOf("!"); | ||||
| 	if(s == -1 && e == -1) return start + ":" + end; | ||||
| 	if(s > 0 && e > 0 && start.slice(0, s).toLowerCase() == end.slice(0, e).toLowerCase()) return start + ":" + end.slice(e+1); | ||||
| 	console.error("Cannot hydrate range", start, end); | ||||
| 	return start + ":" + end; | ||||
| // List of invalid characters needs to be tested further
 | ||||
| var quoteCharacters /*:RegExp */ = new RegExp(/[^\w\u4E00-\u9FFF\u3040-\u30FF]/); | ||||
| function formula_quote_sheet_name(sname/*:string*/, opts)/*:string*/ { | ||||
| 	if(!sname && !(opts && opts.biff <= 5 && opts.biff >= 2)) throw new Error("empty sheet name"); | ||||
| 	if (quoteCharacters.test(sname)) return "'" + sname + "'"; | ||||
| 	return sname; | ||||
| } | ||||
| 
 | ||||
| function get_ixti_raw(supbooks, ixti/*:number*/, opts)/*:string*/ { | ||||
| 	if(!supbooks) return "SH33TJSERR0"; | ||||
| 	if(opts.biff > 8 && (!supbooks.XTI || !supbooks.XTI[ixti])) return supbooks.SheetNames[ixti]; | ||||
| @ -732,8 +731,7 @@ function get_ixti_raw(supbooks, ixti/*:number*/, opts)/*:string*/ { | ||||
| 	} | ||||
| } | ||||
| function get_ixti(supbooks, ixti/*:number*/, opts)/*:string*/ { | ||||
| 	var ixtiraw = get_ixti_raw(supbooks, ixti, opts); | ||||
| 	return ixtiraw == "#REF" ? ixtiraw : formula_quote_sheet_name(ixtiraw, opts); | ||||
| 	return formula_quote_sheet_name(get_ixti_raw(supbooks, ixti, opts), opts); | ||||
| } | ||||
| function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, opts)/*:string*/ { | ||||
| 	var biff = (opts && opts.biff) || 8; | ||||
| @ -793,7 +791,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, | ||||
| 				break; | ||||
| 			case 'PtgRange': /* [MS-XLS] 2.5.198.83 */ | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(make_3d_range(e2,e1)); | ||||
| 				stack.push(e2+":"+e1); | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'PtgAttrChoose': /* [MS-XLS] 2.5.198.34 */ | ||||
| @ -870,8 +868,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, | ||||
| 				nameidx = (f[1][2]/*:any*/); | ||||
| 				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx]; | ||||
| 				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx); | ||||
| 				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */ | ||||
| 				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6); | ||||
| 				if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name]; | ||||
| 				stack.push(name); | ||||
| 				break; | ||||
| 
 | ||||
| @ -894,7 +891,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, | ||||
| 					if(supbooks[bookidx] && supbooks[bookidx][nameidx]) o += supbooks[bookidx][nameidx].Name; | ||||
| 					else if(supbooks[0] && supbooks[0][nameidx]) o += supbooks[0][nameidx].Name; | ||||
| 					else { | ||||
| 						var ixtidata = (get_ixti_raw(supbooks, bookidx, opts)||"").split(";;"); | ||||
| 						var ixtidata = get_ixti_raw(supbooks, bookidx, opts).split(";;"); | ||||
| 						if(ixtidata[nameidx - 1]) o = ixtidata[nameidx - 1]; // TODO: confirm this is correct
 | ||||
| 						else o += "SH33TJSERRX"; | ||||
| 					} | ||||
| @ -938,7 +935,8 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, | ||||
| 				if(supbooks.sharedf[encode_cell(c)]) { | ||||
| 					var parsedf = (supbooks.sharedf[encode_cell(c)]); | ||||
| 					stack.push(stringify_formula(parsedf, _range, q, supbooks, opts)); | ||||
| 				} else { | ||||
| 				} | ||||
| 				else { | ||||
| 					var fnd = false; | ||||
| 					for(e1=0;e1!=supbooks.arrayf.length; ++e1) { | ||||
| 						/* TODO: should be something like range_has */ | ||||
| @ -1041,7 +1039,6 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, | ||||
| 		} | ||||
| 	} | ||||
| 	if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack"); | ||||
| 	if(stack[0] == "TRUE") return true; if(stack[0] == "FALSE") return false; | ||||
| 	return stack[0]; | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										209
									
								
								bits/63_fbin.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										209
									
								
								bits/63_fbin.js
									
									
									
									
									
								
							| @ -68,7 +68,8 @@ function write_FormulaValue(value) { | ||||
| /* [MS-XLS] 2.4.127 TODO */ | ||||
| function parse_Formula(blob, length, opts) { | ||||
| 	var end = blob.l + length; | ||||
| 	var cell = parse_XLSCell(blob, 6, opts); | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	if(opts.biff == 2) ++blob.l; | ||||
| 	var val = parse_FormulaValue(blob,8); | ||||
| 	var flags = blob.read_shift(1); | ||||
| 	if(opts.biff != 2) { | ||||
| @ -123,209 +124,3 @@ var parse_XLSBCellParsedFormula = parse_XLSBParsedFormula; | ||||
| var parse_XLSBNameParsedFormula = parse_XLSBParsedFormula; | ||||
| /* [MS-XLSB] 2.5.97.98 SharedParsedFormula */ | ||||
| var parse_XLSBSharedParsedFormula = parse_XLSBParsedFormula; | ||||
| 
 | ||||
| /* Writes a PtgNum or PtgInt */ | ||||
| function write_XLSBFormulaNum(val/*:number*/) { | ||||
| 	if((val | 0) == val && val < Math.pow(2,16) && val >= 0) { | ||||
| 		var oint = new_buf(11); | ||||
| 		oint.write_shift(4, 3); | ||||
| 		oint.write_shift(1, 0x1e); | ||||
| 		oint.write_shift(2, val); | ||||
| 		oint.write_shift(4, 0); | ||||
| 		return oint; | ||||
| 	} | ||||
| 
 | ||||
| 	var num = new_buf(17); | ||||
| 	num.write_shift(4, 11); | ||||
| 	num.write_shift(1, 0x1f); | ||||
| 	num.write_shift(8, val); | ||||
| 	num.write_shift(4, 0); | ||||
| 	return num; | ||||
| } | ||||
| /* Writes a PtgErr */ | ||||
| function write_XLSBFormulaErr(val/*:number*/) { | ||||
| 	var oint = new_buf(10); | ||||
| 	oint.write_shift(4, 2); | ||||
| 	oint.write_shift(1, 0x1C); | ||||
| 	oint.write_shift(1, val); | ||||
| 	oint.write_shift(4, 0); | ||||
| 	return oint; | ||||
| } | ||||
| /* Writes a PtgBool */ | ||||
| function write_XLSBFormulaBool(val/*:boolean*/) { | ||||
| 	var oint = new_buf(10); | ||||
| 	oint.write_shift(4, 2); | ||||
| 	oint.write_shift(1, 0x1D); | ||||
| 	oint.write_shift(1, val?1:0); | ||||
| 	oint.write_shift(4, 0); | ||||
| 	return oint; | ||||
| } | ||||
| 
 | ||||
| /* Writes a PtgStr */ | ||||
| function write_XLSBFormulaStr(val/*:string*/) { | ||||
| 	var preamble = new_buf(7); | ||||
| 	preamble.write_shift(4, 3 + 2 * val.length); | ||||
| 	preamble.write_shift(1, 0x17); | ||||
| 	preamble.write_shift(2, val.length); | ||||
| 
 | ||||
| 	var body = new_buf(2 * val.length); | ||||
| 	body.write_shift(2 * val.length, val, "utf16le"); | ||||
| 
 | ||||
| 	var postamble = new_buf(4); | ||||
| 	postamble.write_shift(4, 0); | ||||
| 
 | ||||
| 	return bconcat([preamble, body, postamble]); | ||||
| } | ||||
| 
 | ||||
| /* Writes a PtgRef */ | ||||
| function write_XLSBFormulaRef(str) { | ||||
| 	var cell = decode_cell(str); | ||||
| 	var out = new_buf(15); | ||||
| 	out.write_shift(4, 7); | ||||
| 	out.write_shift(1, 0x04 | ((1)<<5)); | ||||
| 	out.write_shift(4, cell.r); | ||||
| 	out.write_shift(2, cell.c | ((str.charAt(0) == "$" ? 0 : 1)<<14) | ((str.match(/\$\d/) ? 0 : 1)<<15)); // <== ColRelShort
 | ||||
| 	out.write_shift(4, 0); | ||||
| 
 | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Writes a PtgRef3d */ | ||||
| function write_XLSBFormulaRef3D(str, wb) { | ||||
| 	var lastbang = str.lastIndexOf("!"); | ||||
| 	var sname = str.slice(0, lastbang); | ||||
| 	str = str.slice(lastbang+1); | ||||
| 	var cell = decode_cell(str); | ||||
| 	if(sname.charAt(0) == "'") sname = sname.slice(1, -1).replace(/''/g, "'"); | ||||
| 
 | ||||
| 	var out = new_buf(17); | ||||
| 	out.write_shift(4, 9); | ||||
| 	out.write_shift(1, 0x1A | ((1)<<5)); | ||||
| 	out.write_shift(2, 2 + wb.SheetNames.map(function(n) { return n.toLowerCase(); }).indexOf(sname.toLowerCase())); | ||||
| 	out.write_shift(4, cell.r); | ||||
| 	out.write_shift(2, cell.c | ((str.charAt(0) == "$" ? 0 : 1)<<14) | ((str.match(/\$\d/) ? 0 : 1)<<15)); // <== ColRelShort
 | ||||
| 	out.write_shift(4, 0); | ||||
| 
 | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Writes a PtgRefErr3d */ | ||||
| function write_XLSBFormulaRefErr3D(str, wb) { | ||||
| 	var lastbang = str.lastIndexOf("!"); | ||||
| 	var sname = str.slice(0, lastbang); | ||||
| 	str = str.slice(lastbang+1); | ||||
| 	if(sname.charAt(0) == "'") sname = sname.slice(1, -1).replace(/''/g, "'"); | ||||
| 
 | ||||
| 	var out = new_buf(17); | ||||
| 	out.write_shift(4, 9); | ||||
| 	out.write_shift(1, 0x1C | ((1)<<5)); | ||||
| 	out.write_shift(2, 2 + wb.SheetNames.map(function(n) { return n.toLowerCase(); }).indexOf(sname.toLowerCase())); | ||||
| 	out.write_shift(4, 0); | ||||
| 	out.write_shift(2, 0); // <== ColRelShort
 | ||||
| 	out.write_shift(4, 0); | ||||
| 
 | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Writes a single sheet range [PtgRef PtgRef PtgRange] */ | ||||
| function write_XLSBFormulaRange(_str) { | ||||
| 	var parts = _str.split(":"), str = parts[0]; | ||||
| 
 | ||||
| 	var out = new_buf(23); | ||||
| 	out.write_shift(4, 15); | ||||
| 
 | ||||
| 	/* start cell */ | ||||
| 	str = parts[0]; var cell = decode_cell(str); | ||||
| 	out.write_shift(1, 0x04 | ((1)<<5)); | ||||
| 	out.write_shift(4, cell.r); | ||||
| 	out.write_shift(2, cell.c | ((str.charAt(0) == "$" ? 0 : 1)<<14) | ((str.match(/\$\d/) ? 0 : 1)<<15)); // <== ColRelShort
 | ||||
| 	out.write_shift(4, 0); | ||||
| 
 | ||||
| 	/* end cell */ | ||||
| 	str = parts[1]; cell = decode_cell(str); | ||||
| 	out.write_shift(1, 0x04 | ((1)<<5)); | ||||
| 	out.write_shift(4, cell.r); | ||||
| 	out.write_shift(2, cell.c | ((str.charAt(0) == "$" ? 0 : 1)<<14) | ((str.match(/\$\d/) ? 0 : 1)<<15)); // <== ColRelShort
 | ||||
| 	out.write_shift(4, 0); | ||||
| 
 | ||||
| 	/* PtgRange */ | ||||
| 	out.write_shift(1, 0x11); | ||||
| 
 | ||||
| 	out.write_shift(4, 0); | ||||
| 
 | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Writes a range with explicit sheet name [PtgRef3D PtgRef3D PtgRange] */ | ||||
| function write_XLSBFormulaRangeWS(_str, wb) { | ||||
| 	var lastbang = _str.lastIndexOf("!"); | ||||
| 	var sname = _str.slice(0, lastbang); | ||||
| 	_str = _str.slice(lastbang+1); | ||||
| 	if(sname.charAt(0) == "'") sname = sname.slice(1, -1).replace(/''/g, "'"); | ||||
| 	var parts = _str.split(":"); | ||||
| 
 | ||||
| 	var out = new_buf(27); | ||||
| 	out.write_shift(4, 19); | ||||
| 
 | ||||
| 	/* start cell */ | ||||
| 	var str = parts[0], cell = decode_cell(str); | ||||
| 	out.write_shift(1, 0x1A | ((1)<<5)); | ||||
| 	out.write_shift(2, 2 + wb.SheetNames.map(function(n) { return n.toLowerCase(); }).indexOf(sname.toLowerCase())); | ||||
| 	out.write_shift(4, cell.r); | ||||
| 	out.write_shift(2, cell.c | ((str.charAt(0) == "$" ? 0 : 1)<<14) | ((str.match(/\$\d/) ? 0 : 1)<<15)); // <== ColRelShort
 | ||||
| 
 | ||||
| 	/* end cell */ | ||||
| 	str = parts[1]; cell = decode_cell(str); | ||||
| 	out.write_shift(1, 0x1A | ((1)<<5)); | ||||
| 	out.write_shift(2, 2 + wb.SheetNames.map(function(n) { return n.toLowerCase(); }).indexOf(sname.toLowerCase())); | ||||
| 	out.write_shift(4, cell.r); | ||||
| 	out.write_shift(2, cell.c | ((str.charAt(0) == "$" ? 0 : 1)<<14) | ((str.match(/\$\d/) ? 0 : 1)<<15)); // <== ColRelShort
 | ||||
| 
 | ||||
| 	/* PtgRange */ | ||||
| 	out.write_shift(1, 0x11); | ||||
| 
 | ||||
| 	out.write_shift(4, 0); | ||||
| 
 | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Writes a range with explicit sheet name [PtgArea3d] */ | ||||
| function write_XLSBFormulaArea3D(_str, wb) { | ||||
| 	var lastbang = _str.lastIndexOf("!"); | ||||
| 	var sname = _str.slice(0, lastbang); | ||||
| 	_str = _str.slice(lastbang+1); | ||||
| 	if(sname.charAt(0) == "'") sname = sname.slice(1, -1).replace(/''/g, "'"); | ||||
| 	var range = decode_range(_str); | ||||
| 
 | ||||
| 	var out = new_buf(23); | ||||
| 	out.write_shift(4, 15); | ||||
| 
 | ||||
| 	out.write_shift(1, 0x1B | ((1)<<5)); | ||||
| 	out.write_shift(2, 2 + wb.SheetNames.map(function(n) { return n.toLowerCase(); }).indexOf(sname.toLowerCase())); | ||||
| 	out.write_shift(4, range.s.r); | ||||
| 	out.write_shift(4, range.e.r); | ||||
| 	out.write_shift(2, range.s.c); | ||||
| 	out.write_shift(2, range.e.c); | ||||
| 
 | ||||
| 	out.write_shift(4, 0); | ||||
| 
 | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* General Formula */ | ||||
| function write_XLSBFormula(val/*:string|number*/, wb) { | ||||
| 	if(typeof val == "number") return write_XLSBFormulaNum(val); | ||||
| 	if(typeof val == "boolean") return write_XLSBFormulaBool(val); | ||||
| 	if(/^#(DIV\/0!|GETTING_DATA|N\/A|NAME\?|NULL!|NUM!|REF!|VALUE!)$/.test(val)) return write_XLSBFormulaErr(+RBErr[val]); | ||||
| 	if(val.match(/^\$?(?:[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D]|[A-Z]{1,2})\$?(?:10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})$/)) return write_XLSBFormulaRef(val); | ||||
| 	if(val.match(/^\$?(?:[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D]|[A-Z]{1,2})\$?(?:10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5}):\$?(?:[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D]|[A-Z]{1,2})\$?(?:10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})$/)) return write_XLSBFormulaRange(val); | ||||
| 	if(val.match(/^#REF!\$?(?:[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D]|[A-Z]{1,2})\$?(?:10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5}):\$?(?:[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D]|[A-Z]{1,2})\$?(?:10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})$/)) return write_XLSBFormulaArea3D(val, wb); | ||||
| 	if(val.match(/^(?:'[^\\\/?*\[\]:]*'|[^'][^\\\/?*\[\]:'`~!@#$%^()\-=+{}|;,<.>]*)!\$?(?:[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D]|[A-Z]{1,2})\$?(?:10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})$/)) return write_XLSBFormulaRef3D(val, wb); | ||||
| 	if(val.match(/^(?:'[^\\\/?*\[\]:]*'|[^'][^\\\/?*\[\]:'`~!@#$%^()\-=+{}|;,<.>]*)!\$?(?:[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D]|[A-Z]{1,2})\$?(?:10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5}):\$?(?:[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D]|[A-Z]{1,2})\$?(?:10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})$/)) return write_XLSBFormulaRangeWS(val, wb); | ||||
| 	if(/^(?:'[^\\\/?*\[\]:]*'|[^'][^\\\/?*\[\]:'`~!@#$%^()\-=+{}|;,<.>]*)!#REF!$/.test(val)) return write_XLSBFormulaRefErr3D(val, wb); | ||||
| 	if(/^".*"$/.test(val)) return write_XLSBFormulaStr(val); | ||||
| 	if(/^[+-]\d+$/.test(val)) return write_XLSBFormulaNum(parseInt(val, 10)); | ||||
| 	throw "Formula |" + val + "| not supported for XLSB"; | ||||
| } | ||||
| var write_XLSBNameParsedFormula = write_XLSBFormula; | ||||
|  | ||||
							
								
								
									
										2393
									
								
								bits/64_ftab.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2393
									
								
								bits/64_ftab.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -9,8 +9,6 @@ function ods_to_csf_formula(f/*:string*/)/*:string*/ { | ||||
| 	f = f.replace(/COM\.MICROSOFT\./g, ""); | ||||
| 	/* Part 3 Section 5.8 References */ | ||||
| 	f = f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, function($$, $1) { return $1.replace(/\./g,""); }); | ||||
| 	f = f.replace(/\$'([^']|'')+'/g, function($$) { return $$.slice(1); }); | ||||
| 	f = f.replace(/\$([^\]\. #$]+)/g, function($$, $1) { return ($1).match(/^([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])?(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})?$/) ? $$ : $1; }); | ||||
| 	/* TODO: something other than this */ | ||||
| 	f = f.replace(/\[.(#[A-Z]*[?!])\]/g, "$1"); | ||||
| 	return f.replace(/[;~]/g,",").replace(/\|/g,";"); | ||||
| @ -23,14 +21,12 @@ function csf_to_ods_formula(f/*:string*/)/*:string*/ { | ||||
| } | ||||
| 
 | ||||
| function ods_to_csf_3D(r/*:string*/)/*:[string, string]*/ { | ||||
| 	r = r.replace(/\$'([^']|'')+'/g, function($$) { return $$.slice(1); }); | ||||
| 	r = r.replace(/\$([^\]\. #$]+)/g, function($$, $1) { return ($1).match(/^([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])?(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})?$/) ? $$ : $1; }); | ||||
| 	var a = r.split(":"); | ||||
| 	var s = a[0].split(".")[0]; | ||||
| 	return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")]; | ||||
| } | ||||
| 
 | ||||
| function csf_to_ods_3D(r/*:string*/)/*:string*/ { | ||||
| 	return r.replace(/!/,".").replace(/:/, ":."); | ||||
| 	return r.replace(/\./,"!"); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,10 @@ | ||||
| var strs = {}; // shared strings
 | ||||
| var _ssfopts = {}; // spreadsheet formatting options
 | ||||
| 
 | ||||
| RELS.WS = [ | ||||
| 	"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", | ||||
| 	"http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet" | ||||
| ]; | ||||
| 
 | ||||
| /*global Map */ | ||||
| var browser_has_Map = typeof Map !== 'undefined'; | ||||
| @ -41,7 +45,6 @@ function col_obj_w(C/*:number*/, col) { | ||||
| 	if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; } | ||||
| 	else if(col.width != null) p.width = col.width; | ||||
| 	if(col.hidden) p.hidden = true; | ||||
| 	if(col.level != null) { p.outlineLevel = p.level = col.level; } | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
| @ -62,7 +65,7 @@ function get_cell_style(styles/*:Array<any>*/, cell/*:Cell*/, opts) { | ||||
| 	var i = 0x3c, len = styles.length; | ||||
| 	if(z == null && opts.ssf) { | ||||
| 		for(; i < 0x188; ++i) if(opts.ssf[i] == null) { | ||||
| 			SSF__load(cell.z, i); | ||||
| 			SSF.load(cell.z, i); | ||||
| 			// $FlowIgnore
 | ||||
| 			opts.ssf[i] = cell.z; | ||||
| 			opts.revssf[cell.z] = z = i; | ||||
| @ -81,30 +84,30 @@ function get_cell_style(styles/*:Array<any>*/, cell/*:Cell*/, opts) { | ||||
| 	return len; | ||||
| } | ||||
| 
 | ||||
| function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, themes, styles, date1904) { | ||||
| function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, themes, styles) { | ||||
| 	try { | ||||
| 		if(opts.cellNF) p.z = table_fmt[fmtid]; | ||||
| 		if(opts.cellNF) p.z = SSF._table[fmtid]; | ||||
| 	} catch(e) { if(opts.WTF) throw e; } | ||||
| 	if(p.t === 'z' && !opts.cellStyles) return; | ||||
| 	if(p.t === 'z') return; | ||||
| 	if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v); | ||||
| 	if((!opts || opts.cellText !== false) && p.t !== 'z') try { | ||||
| 		if(table_fmt[fmtid] == null) SSF__load(SSFImplicit[fmtid] || "General", fmtid); | ||||
| 	if(!opts || opts.cellText !== false) try { | ||||
| 		if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid); | ||||
| 		if(p.t === 'e') p.w = p.w || BErr[p.v]; | ||||
| 		else if(fmtid === 0) { | ||||
| 			if(p.t === 'n') { | ||||
| 				if((p.v|0) === p.v) p.w = p.v.toString(10); | ||||
| 				else p.w = SSF_general_num(p.v); | ||||
| 				if((p.v|0) === p.v) p.w = SSF._general_int(p.v); | ||||
| 				else p.w = SSF._general_num(p.v); | ||||
| 			} | ||||
| 			else if(p.t === 'd') { | ||||
| 				var dd = datenum(p.v, !!date1904); | ||||
| 				if((dd|0) === dd) p.w = dd.toString(10); | ||||
| 				else p.w = SSF_general_num(dd); | ||||
| 				var dd = datenum(p.v); | ||||
| 				if((dd|0) === dd) p.w = SSF._general_int(dd); | ||||
| 				else p.w = SSF._general_num(dd); | ||||
| 			} | ||||
| 			else if(p.v === undefined) return ""; | ||||
| 			else p.w = SSF_general(p.v,_ssfopts); | ||||
| 			else p.w = SSF._general(p.v,_ssfopts); | ||||
| 		} | ||||
| 		else if(p.t === 'd') p.w = SSF_format(fmtid,datenum(p.v, !!date1904),_ssfopts); | ||||
| 		else p.w = SSF_format(fmtid,p.v,_ssfopts); | ||||
| 		else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts); | ||||
| 		else p.w = SSF.format(fmtid,p.v,_ssfopts); | ||||
| 	} catch(e) { if(opts.WTF) throw e; } | ||||
| 	if(!opts.cellStyles) return; | ||||
| 	if(fillid != null) try { | ||||
|  | ||||
							
								
								
									
										219
									
								
								bits/67_wsxml.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										219
									
								
								bits/67_wsxml.js
									
									
									
									
									
								
							| @ -2,13 +2,15 @@ function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) { | ||||
| 	var d = safe_decode_range(s); | ||||
| 	if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d); | ||||
| } | ||||
| var mergecregex = /<(?:\w+:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g; | ||||
| var hlinkregex = /<(?:\w+:)?hyperlink [^<>]*>/mg; | ||||
| var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g; | ||||
| var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/; | ||||
| var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg; | ||||
| var dimregex = /"(\w*:\w*)"/; | ||||
| var colregex = /<(?:\w+:)?col\b[^<>]*[\/]?>/g; | ||||
| var afregex = /<(?:\w+:)?autoFilter[^>]*/g; | ||||
| var marginregex= /<(?:\w+:)?pageMargins[^<>]*\/>/g; | ||||
| var sheetprregex = /<(?:\w+:)?sheetPr\b[^<>]*?\/>/; | ||||
| var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g; | ||||
| var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g; | ||||
| var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g; | ||||
| var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/; | ||||
| var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/; | ||||
| 
 | ||||
| /* 18.3 Worksheets */ | ||||
| function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBProps*/, themes, styles)/*:Worksheet*/ { | ||||
| @ -17,11 +19,11 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro | ||||
| 	if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| 
 | ||||
| 	/* 18.3.1.99 worksheet CT_Worksheet */ | ||||
| 	var s = ({}/*:any*/); if(opts.dense) s["!data"] = []; | ||||
| 	var s = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 	var refguess/*:Range*/ = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} }/*:any*/); | ||||
| 
 | ||||
| 	var data1 = "", data2 = ""; | ||||
| 	var mtch/*:?any*/ = str_match_xml_ns(data, "sheetData"); | ||||
| 	var mtch/*:?any*/ = data.match(sheetdataregex); | ||||
| 	if(mtch) { | ||||
| 		data1 = data.slice(0, mtch.index); | ||||
| 		data2 = data.slice(mtch.index + mtch[0].length); | ||||
| @ -30,17 +32,16 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro | ||||
| 	/* 18.3.1.82 sheetPr CT_SheetPr */ | ||||
| 	var sheetPr = data1.match(sheetprregex); | ||||
| 	if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx); | ||||
| 	else if((sheetPr = str_match_xml_ns(data1, "sheetPr"))) parse_ws_xml_sheetpr2(sheetPr[0], sheetPr[1]||"", s, wb, idx, styles, themes); | ||||
| 
 | ||||
| 	/* 18.3.1.35 dimension CT_SheetDimension */ | ||||
| 	var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index; | ||||
| 	if(ridx > 0) { | ||||
| 		var ref = data1.slice(ridx,ridx+50).match(dimregex); | ||||
| 		if(ref && !(opts && opts.nodim)) parse_ws_xml_dim(s, ref[1]); | ||||
| 		if(ref) parse_ws_xml_dim(s, ref[1]); | ||||
| 	} | ||||
| 
 | ||||
| 	/* 18.3.1.88 sheetViews CT_SheetViews */ | ||||
| 	var svs = str_match_xml_ns(data1, "sheetViews"); | ||||
| 	var svs = data1.match(svsregex); | ||||
| 	if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb); | ||||
| 
 | ||||
| 	/* 18.3.1.17 cols CT_Cols */ | ||||
| @ -52,7 +53,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro | ||||
| 	} | ||||
| 
 | ||||
| 	/* 18.3.1.80 sheetData CT_SheetData ? */ | ||||
| 	if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles, wb); | ||||
| 	if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles); | ||||
| 
 | ||||
| 	/* 18.3.1.2  autoFilter CT_AutoFilter */ | ||||
| 	var afilter = data2.match(afregex); | ||||
| @ -62,7 +63,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro | ||||
| 	var merges/*:Array<Range>*/ = []; | ||||
| 	var _merge = data2.match(mergecregex); | ||||
| 	if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx) | ||||
| 		merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("=")+2)); | ||||
| 		merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1)); | ||||
| 
 | ||||
| 	/* 18.3.1.48 hyperlinks CT_Hyperlinks */ | ||||
| 	var hlink = data2.match(hlinkregex); | ||||
| @ -72,11 +73,6 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro | ||||
| 	var margins = data2.match(marginregex); | ||||
| 	if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0])); | ||||
| 
 | ||||
| 	/* legacyDrawing */ | ||||
| 	var m; | ||||
| 	if((m = data2.match(/legacyDrawing r:id="(.*?)"/))) s['!legrel'] = m[1]; | ||||
| 
 | ||||
| 	if(opts && opts.nodim) refguess.s.c = refguess.s.r = 0; | ||||
| 	if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess); | ||||
| 	if(opts.sheetRows > 0 && s["!ref"]) { | ||||
| 		var tmpref = safe_decode_range(s["!ref"]); | ||||
| @ -92,7 +88,6 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro | ||||
| 	} | ||||
| 	if(columns.length > 0) s["!cols"] = columns; | ||||
| 	if(merges.length > 0) s["!merges"] = merges; | ||||
| 	if(rels['!id'][s['!legrel']]) s['!legdrawel'] = rels['!id'][s['!legrel']]; | ||||
| 	return s; | ||||
| } | ||||
| 
 | ||||
| @ -109,9 +104,6 @@ function parse_ws_xml_sheetpr(sheetPr/*:string*/, s, wb/*:WBWBProps*/, idx/*:num | ||||
| 	if(!wb.Sheets[idx]) wb.Sheets[idx] = {}; | ||||
| 	if(data.codeName) wb.Sheets[idx].CodeName = unescapexml(utf8read(data.codeName)); | ||||
| } | ||||
| function parse_ws_xml_sheetpr2(sheetPr/*:string*/, body/*:string*/, s, wb/*:WBWBProps*/, idx/*:number*/) { | ||||
| 	parse_ws_xml_sheetpr(sheetPr.slice(0, sheetPr.indexOf(">")), s, wb, idx); | ||||
| } | ||||
| function write_ws_xml_sheetpr(ws, wb, idx, opts, o) { | ||||
| 	var needed = false; | ||||
| 	var props = {}, payload = null; | ||||
| @ -152,27 +144,27 @@ function write_ws_xml_protection(sp)/*:string*/ { | ||||
| } | ||||
| 
 | ||||
| function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) { | ||||
| 	var dense = s["!data"] != null; | ||||
| 	var dense = Array.isArray(s); | ||||
| 	for(var i = 0; i != data.length; ++i) { | ||||
| 		var val = parsexmltag(utf8read(data[i]), true); | ||||
| 		if(!val.ref) return; | ||||
| 		var rel = ((rels || {})['!id']||[])[val.id]; | ||||
| 		if(rel) { | ||||
| 			val.Target = rel.Target; | ||||
| 			if(val.location) val.Target += "#"+unescapexml(val.location); | ||||
| 			if(val.location) val.Target += "#"+val.location; | ||||
| 		} else { | ||||
| 			val.Target = "#" + unescapexml(val.location); | ||||
| 			val.Target = "#" + val.location; | ||||
| 			rel = {Target: val.Target, TargetMode: 'Internal'}; | ||||
| 		} | ||||
| 		val.Rel = rel; | ||||
| 		if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; } | ||||
| 		var rng = safe_decode_range(val.ref); | ||||
| 		for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) { | ||||
| 			var addr = encode_col(C) + encode_row(R); | ||||
| 			var addr = encode_cell({c:C,r:R}); | ||||
| 			if(dense) { | ||||
| 				if(!s["!data"][R]) s["!data"][R] = []; | ||||
| 				if(!s["!data"][R][C]) s["!data"][R][C] = {t:"z",v:undefined}; | ||||
| 				s["!data"][R][C].l = val; | ||||
| 				if(!s[R]) s[R] = []; | ||||
| 				if(!s[R][C]) s[R][C] = {t:"z",v:undefined}; | ||||
| 				s[R][C].l = val; | ||||
| 			} else { | ||||
| 				if(!s[addr]) s[addr] = {t:"z",v:undefined}; | ||||
| 				s[addr].l = val; | ||||
| @ -199,7 +191,6 @@ function parse_ws_xml_cols(columns, cols) { | ||||
| 		var coll = parsexmltag(cols[coli], true); | ||||
| 		if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden); | ||||
| 		var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1; | ||||
| 		if(coll.outlineLevel) coll.level = (+coll.outlineLevel || 0); | ||||
| 		delete coll.min; delete coll.max; coll.width = +coll.width; | ||||
| 		if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); } | ||||
| 		process_col(coll); | ||||
| @ -231,7 +222,7 @@ function write_ws_xml_autofilter(data, ws, wb, idx)/*:string*/ { | ||||
| 		var name = names[i]; | ||||
| 		if(name.Name != '_xlnm._FilterDatabase') continue; | ||||
| 		if(name.Sheet != idx) continue; | ||||
| 		name.Ref = formula_quote_sheet_name(wb.SheetNames[idx]) + "!" + fix_range(ref); break; | ||||
| 		name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break; | ||||
| 	} | ||||
| 	if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref  }); | ||||
| 	return writextag("autoFilter", null, {ref:ref}); | ||||
| @ -239,7 +230,7 @@ function write_ws_xml_autofilter(data, ws, wb, idx)/*:string*/ { | ||||
| 
 | ||||
| /* 18.3.1.88 sheetViews CT_SheetViews */ | ||||
| /* 18.3.1.87 sheetView CT_SheetView */ | ||||
| var sviewregex = /<(?:\w:)?sheetView(?:[^<>a-z][^<>]*)?\/?>/g; | ||||
| var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/?>/; | ||||
| function parse_ws_xml_sheetviews(data, wb/*:WBWBProps*/) { | ||||
| 	if(!wb.Views) wb.Views = [{}]; | ||||
| 	(data.match(sviewregex)||[]).forEach(function(r/*:string*/, i/*:number*/) { | ||||
| @ -249,7 +240,7 @@ function parse_ws_xml_sheetviews(data, wb/*:WBWBProps*/) { | ||||
| 		// $FlowIgnore
 | ||||
| 		if(+tag.zoomScale) wb.Views[i].zoom = +tag.zoomScale; | ||||
| 		// $FlowIgnore
 | ||||
| 		if(tag.rightToLeft && parsexmlbool(tag.rightToLeft)) wb.Views[i].RTL = true; | ||||
| 		if(parsexmlbool(tag.rightToLeft)) wb.Views[i].RTL = true; | ||||
| 	}); | ||||
| } | ||||
| function write_ws_xml_sheetviews(ws, opts, idx, wb)/*:string*/ { | ||||
| @ -259,33 +250,26 @@ function write_ws_xml_sheetviews(ws, opts, idx, wb)/*:string*/ { | ||||
| 	return writextag("sheetViews", writextag("sheetView", null, sview), {}); | ||||
| } | ||||
| 
 | ||||
| function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts, idx, wb, date1904)/*:string*/ { | ||||
| 	if(cell.c) ws['!comments'].push([ref, cell.c]); | ||||
| 	if((cell.v === undefined || cell.t === "z" && !(opts||{}).sheetStubs) && typeof cell.f !== "string" && typeof cell.z == "undefined") return ""; | ||||
| function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string*/ { | ||||
| 	if(cell.v === undefined && typeof cell.f !== "string" || cell.t === 'z') return ""; | ||||
| 	var vv = ""; | ||||
| 	var oldt = cell.t, oldv = cell.v; | ||||
| 	if(cell.t !== "z") switch(cell.t) { | ||||
| 		case 'b': vv = cell.v ? "1" : "0"; break; | ||||
| 		case 'n': | ||||
| 			if(isNaN(cell.v)) { cell.t = "e"; vv = BErr[cell.v = 0x24]; } // #NUM!
 | ||||
| 			else if(!isFinite(cell.v)) { cell.t = "e"; vv = BErr[cell.v = 0x07]; } // #DIV/0!
 | ||||
| 			else vv = ''+cell.v; break; | ||||
| 		case 'n': vv = ''+cell.v; break; | ||||
| 		case 'e': vv = BErr[cell.v]; break; | ||||
| 		case 'd': | ||||
| 			if(opts && opts.cellDates) { | ||||
| 				var _vv = parseDate(cell.v, date1904); | ||||
| 				vv = _vv.toISOString(); | ||||
| 				if(_vv.getUTCFullYear() < 1900) vv = vv.slice(vv.indexOf("T") + 1).replace("Z",""); | ||||
| 			} else { | ||||
| 			if(opts && opts.cellDates) vv = parseDate(cell.v, -1).toISOString(); | ||||
| 			else { | ||||
| 				cell = dup(cell); | ||||
| 				cell.t = 'n'; | ||||
| 				vv = ''+(cell.v = datenum(parseDate(cell.v, date1904), date1904)); | ||||
| 				vv = ''+(cell.v = datenum(parseDate(cell.v))); | ||||
| 			} | ||||
| 			if(typeof cell.z === 'undefined') cell.z = table_fmt[14]; | ||||
| 			if(typeof cell.z === 'undefined') cell.z = SSF._table[14]; | ||||
| 			break; | ||||
| 		default: vv = cell.v; break; | ||||
| 	} | ||||
| 	var v = (cell.t == "z" || cell.v == null)? "" : writetag('v', escapexml(vv)), o = ({r:ref}/*:any*/); | ||||
| 	var v = writetag('v', escapexml(vv)), o = ({r:ref}/*:any*/); | ||||
| 	/* TODO: cell style */ | ||||
| 	var os = get_cell_style(opts.cellXfs, cell, opts); | ||||
| 	if(os !== 0) o.s = os; | ||||
| @ -296,32 +280,29 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts, idx, wb, date1904)/*:st | ||||
| 		case 'e': o.t = "e"; break; | ||||
| 		case 'z': break; | ||||
| 		default: if(cell.v == null) { delete cell.t; break; } | ||||
| 			if(cell.v.length > 32767) throw new Error("Text length must not exceed 32767 characters"); | ||||
| 			if(opts && opts.bookSST) { | ||||
| 				v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings)); | ||||
| 				o.t = "s"; break; | ||||
| 			} | ||||
| 			else o.t = "str"; break; | ||||
| 			o.t = "str"; break; | ||||
| 	} | ||||
| 	if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; } | ||||
| 	if(typeof cell.f == "string" && cell.f) { | ||||
| 		var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null; | ||||
| 		v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : ""); | ||||
| 	} | ||||
| 	if(cell.l) { | ||||
| 		cell.l.display = escapexml(vv); | ||||
| 		ws['!links'].push([ref, cell.l]); | ||||
| 	} | ||||
| 	if(cell.D) o.cm = 1; | ||||
| 	if(cell.l) ws['!links'].push([ref, cell.l]); | ||||
| 	if(cell.c) ws['!comments'].push([ref, cell.c]); | ||||
| 	return writextag('c', v, o); | ||||
| } | ||||
| 
 | ||||
| var parse_ws_xml_data = /*#__PURE__*/(function() { | ||||
| var parse_ws_xml_data = (function() { | ||||
| 	var cellregex = /<(?:\w+:)?c[ \/>]/, rowregex = /<\/(?:\w+:)?row>/; | ||||
| 	var rregex = /r=["']([^"']*)["']/; | ||||
| 	var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/; | ||||
| 	var refregex = /ref=["']([^"']*)["']/; | ||||
| 	var match_v = matchtag("v"), match_f = matchtag("f"); | ||||
| 
 | ||||
| return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, themes, styles, wb) { | ||||
| return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, themes, styles) { | ||||
| 	var ri = 0, x = "", cells/*:Array<string>*/ = [], cref/*:?Array<string>*/ = [], idx=0, i=0, cc=0, d="", p/*:any*/; | ||||
| 	var tag, tagr = 0, tagc = 0; | ||||
| 	var sstr, ftag; | ||||
| @ -329,47 +310,26 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 	var do_format = Array.isArray(styles.CellXf), cf; | ||||
| 	var arrayf/*:Array<[Range, string]>*/ = []; | ||||
| 	var sharedf = []; | ||||
| 	var dense = s["!data"] != null; | ||||
| 	var dense = Array.isArray(s); | ||||
| 	var rows/*:Array<RowInfo>*/ = [], rowobj = {}, rowrite = false; | ||||
| 	var sheetStubs = !!opts.sheetStubs; | ||||
| 	var date1904 = !!((wb||{}).WBProps||{}).date1904; | ||||
| 	for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) { | ||||
| 		x = marr[mt].trim(); | ||||
| 		var xlen = x.length; | ||||
| 		if(xlen === 0) continue; | ||||
| 
 | ||||
| 		/* 18.3.1.73 row CT_Row */ | ||||
| 		var rstarti = 0; | ||||
| 		outa: for(ri = 0; ri < xlen; ++ri) switch(/*x.charCodeAt(ri)*/x[ri]) { | ||||
| 			case ">" /*62*/: | ||||
| 				if(/*x.charCodeAt(ri-1) != 47*/x[ri-1] != "/") { ++ri; break outa; } | ||||
| 				if(opts && opts.cellStyles) { | ||||
| 					// TODO: avoid duplication
 | ||||
| 					tag = parsexmltag(x.slice(rstarti,ri), true); | ||||
| 					tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1; | ||||
| 					if(opts.sheetRows && opts.sheetRows < tagr) continue; | ||||
| 					rowobj = {}; rowrite = false; | ||||
| 					if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); } | ||||
| 					if(tag.hidden && parsexmlbool(tag.hidden)) { rowrite = true; rowobj.hidden = true; } | ||||
| 					if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; } | ||||
| 					if(rowrite) rows[tagr-1] = rowobj; | ||||
| 				} | ||||
| 				break; | ||||
| 			case "<" /*60*/: rstarti = ri; break; | ||||
| 		} | ||||
| 		if(rstarti >= ri) break; | ||||
| 		tag = parsexmltag(x.slice(rstarti,ri), true); | ||||
| 		for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri; | ||||
| 		tag = parsexmltag(x.slice(0,ri), true); | ||||
| 		tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1; | ||||
| 		if(opts.sheetRows && opts.sheetRows < tagr) continue; | ||||
| 		if(!opts.nodim) { | ||||
| 			if(guess.s.r > tagr - 1) guess.s.r = tagr - 1; | ||||
| 			if(guess.e.r < tagr - 1) guess.e.r = tagr - 1; | ||||
| 		} | ||||
| 		if(guess.s.r > tagr - 1) guess.s.r = tagr - 1; | ||||
| 		if(guess.e.r < tagr - 1) guess.e.r = tagr - 1; | ||||
| 
 | ||||
| 		if(opts && opts.cellStyles) { | ||||
| 			rowobj = {}; rowrite = false; | ||||
| 			if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); } | ||||
| 			if(tag.hidden && parsexmlbool(tag.hidden)) { rowrite = true; rowobj.hidden = true; } | ||||
| 			if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; } | ||||
| 			if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; } | ||||
| 			if(rowrite) rows[tagr-1] = rowobj; | ||||
| 		} | ||||
| @ -398,31 +358,23 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 			d = x.slice(i); | ||||
| 			p = ({t:""}/*:any*/); | ||||
| 
 | ||||
| 			if((cref=str_match_xml_ns(d, "v"))!= null && /*::cref != null && */cref[1] !== '') p.v=unescapexml(cref[1]); | ||||
| 			if((cref=d.match(match_v))!= null && /*::cref != null && */cref[1] !== '') p.v=unescapexml(cref[1]); | ||||
| 			if(opts.cellFormula) { | ||||
| 				if((cref=str_match_xml_ns(d, "f"))!= null /*:: && cref != null*/) { | ||||
| 					if(cref[1] == "") { | ||||
| 						if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) { | ||||
| 							// TODO: parse formula
 | ||||
| 							ftag = parsexmltag(cref[0]); | ||||
| 							if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r); | ||||
| 						} | ||||
| 					} else { | ||||
| 						/* TODO: match against XLSXFutureFunctions */ | ||||
| 						p.f=unescapexml(utf8read(cref[1]), true); | ||||
| 						if(!opts.xlfn) p.f = _xlfn(p.f); | ||||
| 						if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) { | ||||
| 							p.F = (d.match(refregex)||[])[1]; | ||||
| 							if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]); | ||||
| 						} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) { | ||||
| 							// TODO: parse formula
 | ||||
| 							ftag = parsexmltag(cref[0]); | ||||
| 							var ___f = unescapexml(utf8read(cref[1])); | ||||
| 							if(!opts.xlfn) ___f = _xlfn(___f); | ||||
| 							sharedf[parseInt(ftag.si, 10)] = [ftag, ___f, tag.r]; | ||||
| 						} | ||||
| 				if((cref=d.match(match_f))!= null && /*::cref != null && */cref[1] !== '') { | ||||
| 					/* TODO: match against XLSXFutureFunctions */ | ||||
| 					p.f=unescapexml(utf8read(cref[1])).replace(/\r\n/g, "\n"); | ||||
| 					if(!opts.xlfn) p.f = _xlfn(p.f); | ||||
| 					if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) { | ||||
| 						p.F = (d.match(refregex)||[])[1]; | ||||
| 						if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]); | ||||
| 					} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) { | ||||
| 						// TODO: parse formula
 | ||||
| 						ftag = parsexmltag(cref[0]); | ||||
| 						var ___f = unescapexml(utf8read(cref[1])); | ||||
| 						if(!opts.xlfn) ___f = _xlfn(___f); | ||||
| 						sharedf[parseInt(ftag.si, 10)] = [ftag, ___f, tag.r]; | ||||
| 					} | ||||
| 				} else if((cref=d.match(/<f[^<>]*\/>/))) { | ||||
| 				} else if((cref=d.match(/<f[^>]*\/>/))) { | ||||
| 					ftag = parsexmltag(cref[0]); | ||||
| 					if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r); | ||||
| 				} | ||||
| @ -464,11 +416,11 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 					break; | ||||
| 				case 'str': | ||||
| 					p.t = "s"; | ||||
| 					p.v = (p.v!=null) ? unescapexml(utf8read(p.v), true) : ''; | ||||
| 					p.v = (p.v!=null) ? utf8read(p.v) : ''; | ||||
| 					if(opts.cellHTML) p.h = escapehtml(p.v); | ||||
| 					break; | ||||
| 				case 'inlineStr': | ||||
| 					cref = str_match_xml_ns(d, "is"); | ||||
| 					cref = d.match(isregex); | ||||
| 					p.t = 's'; | ||||
| 					if(cref != null && (sstr = parse_si(cref[1]))) { | ||||
| 						p.v = sstr.t; | ||||
| @ -477,8 +429,8 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 					break; | ||||
| 				case 'b': p.v = parsexmlbool(p.v); break; | ||||
| 				case 'd': | ||||
| 					if(opts.cellDates) p.v = parseDate(p.v, date1904); | ||||
| 					else { p.v = datenum(parseDate(p.v, date1904), date1904); p.t = 'n'; } | ||||
| 					if(opts.cellDates) p.v = parseDate(p.v, 1); | ||||
| 					else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; } | ||||
| 					break; | ||||
| 				/* error string in .w, number in .v */ | ||||
| 				case 'e': | ||||
| @ -497,22 +449,12 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			safe_format(p, fmtid, fillid, opts, themes, styles, date1904); | ||||
| 			if(opts.cellDates && do_format && p.t == 'n' && fmt_is_date(table_fmt[fmtid])) { p.v = numdate(p.v + (date1904 ? 1462 : 0)); p.t = typeof p.v == "number" ? 'n' : 'd'; } | ||||
| 			if(tag.cm && opts.xlmeta) { | ||||
| 				var cm = (opts.xlmeta.Cell||[])[+tag.cm-1]; | ||||
| 				if(cm && cm.type == 'XLDAPR') p.D = true; | ||||
| 			} | ||||
| 			var _r; | ||||
| 			if(opts.nodim) { | ||||
| 				_r = decode_cell(tag.r); | ||||
| 				if(guess.s.r > _r.r) guess.s.r = _r.r; | ||||
| 				if(guess.e.r < _r.r) guess.e.r = _r.r; | ||||
| 			} | ||||
| 			safe_format(p, fmtid, fillid, opts, themes, styles); | ||||
| 			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); } | ||||
| 			if(dense) { | ||||
| 				_r = decode_cell(tag.r); | ||||
| 				if(!s["!data"][_r.r]) s["!data"][_r.r] = []; | ||||
| 				s["!data"][_r.r][_r.c] = p; | ||||
| 				var _r = decode_cell(tag.r); | ||||
| 				if(!s[_r.r]) s[_r.r] = []; | ||||
| 				s[_r.r][_r.c] = p; | ||||
| 			} else s[tag.r] = p; | ||||
| 		} | ||||
| 	} | ||||
| @ -521,19 +463,17 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th | ||||
| 
 | ||||
| function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*//*::, rels*/)/*:string*/ { | ||||
| 	var o/*:Array<string>*/ = [], r/*:Array<string>*/ = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols/*:Array<string>*/ = [], R=0, C=0, rows = ws['!rows']; | ||||
| 	var dense = ws["!data"] != null, data = dense ? ws["!data"] : []; | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	var params = ({r:rr}/*:any*/), row/*:RowInfo*/, height = -1; | ||||
| 	var date1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904; | ||||
| 	for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C); | ||||
| 	for(R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		r = []; | ||||
| 		rr = encode_row(R); | ||||
| 		var data_R = dense ? data[R] : []; | ||||
| 		for(C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			ref = cols[C] + rr; | ||||
| 			var _cell = dense ? data_R[C] : ws[ref]; | ||||
| 			var _cell = dense ? (ws[R]||[])[C]: ws[ref]; | ||||
| 			if(_cell === undefined) continue; | ||||
| 			if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb, date1904)) != null) r.push(cell); | ||||
| 			if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell); | ||||
| 		} | ||||
| 		if(r.length > 0 || (rows && rows[R])) { | ||||
| 			params = ({r:rr}/*:any*/); | ||||
| @ -565,11 +505,13 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook | ||||
| 	return o.join(""); | ||||
| } | ||||
| 
 | ||||
| var WS_XML_ROOT = writextag('worksheet', null, { | ||||
| 	'xmlns': XMLNS.main[0], | ||||
| 	'xmlns:r': XMLNS.r | ||||
| }); | ||||
| 
 | ||||
| function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ { | ||||
| 	var o = [XML_HEADER, writextag('worksheet', null, { | ||||
| 		'xmlns': XMLNS_main[0], | ||||
| 		'xmlns:r': XMLNS.r | ||||
| 	})]; | ||||
| 	var o = [XML_HEADER, WS_XML_ROOT]; | ||||
| 	var s = wb.SheetNames[idx], sidx = 0, rdata = ""; | ||||
| 	var ws = wb.Sheets[s]; | ||||
| 	if(ws == null) ws = {}; | ||||
| @ -610,7 +552,7 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ { | ||||
| 
 | ||||
| 	/* sheetCalcPr */ | ||||
| 
 | ||||
| 	if(ws['!protect']) o[o.length] = write_ws_xml_protection(ws['!protect']); | ||||
| 	if(ws['!protect'] != null) o[o.length] = write_ws_xml_protection(ws['!protect']); | ||||
| 
 | ||||
| 	/* protectedRanges */ | ||||
| 	/* scenarios */ | ||||
| @ -634,12 +576,11 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ { | ||||
| 			if(!l[1].Target) return; | ||||
| 			rel = ({"ref":l[0]}/*:any*/); | ||||
| 			if(l[1].Target.charAt(0) != "#") { | ||||
| 				rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#[\s\S]*$/, ""), RELS.HLINK); | ||||
| 				rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK); | ||||
| 				rel["r:id"] = "rId"+rId; | ||||
| 			} | ||||
| 			if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1)); | ||||
| 			if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip); | ||||
| 			rel.display = l[1].display; | ||||
| 			o[o.length] = writextag("hyperlink",null,rel); | ||||
| 		}); | ||||
| 		o[o.length] = "</hyperlinks>"; | ||||
|  | ||||
							
								
								
									
										323
									
								
								bits/68_wsbin.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										323
									
								
								bits/68_wsbin.js
									
									
									
									
									
								
							| @ -41,13 +41,12 @@ function write_BrtRowHdr(R/*:number*/, range, ws) { | ||||
| 	o.l += 4; | ||||
| 
 | ||||
| 	var caddr = {r:R, c:0}; | ||||
| 	var dense = ws["!data"] != null; | ||||
| 	for(var i = 0; i < 16; ++i) { | ||||
| 		if((range.s.c > ((i+1) << 10)) || (range.e.c < (i << 10))) continue; | ||||
| 		var first = -1, last = -1; | ||||
| 		for(var j = (i<<10); j < ((i+1)<<10); ++j) { | ||||
| 			caddr.c = j; | ||||
| 			var cell = dense ? (ws["!data"][caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)]; | ||||
| 			var cell = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)]; | ||||
| 			if(cell) { if(first < 0) first = j; last = j; } | ||||
| 		} | ||||
| 		if(first < 0) continue; | ||||
| @ -65,7 +64,7 @@ function write_BrtRowHdr(R/*:number*/, range, ws) { | ||||
| } | ||||
| function write_row_header(ba, ws, range, R) { | ||||
| 	var o = write_BrtRowHdr(R, range, ws); | ||||
| 	if((o.length > 17) || (ws['!rows']||[])[R]) write_record(ba, 0x0000 /* BrtRowHdr */, o); | ||||
| 	if((o.length > 17) || (ws['!rows']||[])[R]) write_record(ba, 'BrtRowHdr', o); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.820 BrtWsDim */ | ||||
| @ -80,23 +79,14 @@ function parse_BrtWsFmtInfo(/*::data, length*/) { | ||||
| /* [MS-XLSB] 2.4.823 BrtWsProp */ | ||||
| function parse_BrtWsProp(data, length) { | ||||
| 	var z = {}; | ||||
| 	var f = data[data.l]; ++data.l; | ||||
| 	z.above = !(f & 0x40); | ||||
| 	z.left  = !(f & 0x80); | ||||
| 	/* TODO: pull flags */ | ||||
| 	data.l += 18; | ||||
| 	data.l += 19; | ||||
| 	z.name = parse_XLSBCodeName(data, length - 19); | ||||
| 	return z; | ||||
| } | ||||
| function write_BrtWsProp(str, outl, o) { | ||||
| function write_BrtWsProp(str, o) { | ||||
| 	if(o == null) o = new_buf(84+4*str.length); | ||||
| 	var f = 0xC0; | ||||
| 	if(outl) { | ||||
| 		if(outl.above) f &= ~0x40; | ||||
| 		if(outl.left)  f &= ~0x80; | ||||
| 	} | ||||
| 	o.write_shift(1, f); | ||||
| 	for(var i = 1; i < 3; ++i) o.write_shift(1,0); | ||||
| 	for(var i = 0; i < 3; ++i) o.write_shift(1,0); | ||||
| 	write_BrtColor({auto:1}, o); | ||||
| 	o.write_shift(-4,-1); | ||||
| 	o.write_shift(-4,-1); | ||||
| @ -113,14 +103,7 @@ function write_BrtCellBlank(cell, ncell, o) { | ||||
| 	if(o == null) o = new_buf(8); | ||||
| 	return write_XLSBCell(ncell, o); | ||||
| } | ||||
| function parse_BrtShortBlank(data) { | ||||
| 	var cell = parse_XLSBShortCell(data); | ||||
| 	return [cell]; | ||||
| } | ||||
| function write_BrtShortBlank(cell, ncell, o) { | ||||
| 	if(o == null) o = new_buf(4); | ||||
| 	return write_XLSBShortCell(ncell, o); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.307 BrtCellBool */ | ||||
| function parse_BrtCellBool(data) { | ||||
| @ -134,17 +117,6 @@ function write_BrtCellBool(cell, ncell, o) { | ||||
| 	o.write_shift(1, cell.v ? 1 : 0); | ||||
| 	return o; | ||||
| } | ||||
| function parse_BrtShortBool(data) { | ||||
| 	var cell = parse_XLSBShortCell(data); | ||||
| 	var fBool = data.read_shift(1); | ||||
| 	return [cell, fBool, 'b']; | ||||
| } | ||||
| function write_BrtShortBool(cell, ncell, o) { | ||||
| 	if(o == null) o = new_buf(5); | ||||
| 	write_XLSBShortCell(ncell, o); | ||||
| 	o.write_shift(1, cell.v ? 1 : 0); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.308 BrtCellError */ | ||||
| function parse_BrtCellError(data) { | ||||
| @ -152,26 +124,6 @@ function parse_BrtCellError(data) { | ||||
| 	var bError = data.read_shift(1); | ||||
| 	return [cell, bError, 'e']; | ||||
| } | ||||
| function write_BrtCellError(cell, ncell, o) { | ||||
| 	if(o == null) o = new_buf(9); | ||||
| 	write_XLSBCell(ncell, o); | ||||
| 	o.write_shift(1, cell.v); | ||||
| 	return o; | ||||
| } | ||||
| function parse_BrtShortError(data) { | ||||
| 	var cell = parse_XLSBShortCell(data); | ||||
| 	var bError = data.read_shift(1); | ||||
| 	return [cell, bError, 'e']; | ||||
| } | ||||
| function write_BrtShortError(cell, ncell, o) { | ||||
| 	if(o == null) o = new_buf(8); | ||||
| 	write_XLSBShortCell(ncell, o); | ||||
| 	o.write_shift(1, cell.v); | ||||
| 	o.write_shift(2, 0); | ||||
| 	o.write_shift(1, 0); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.311 BrtCellIsst */ | ||||
| function parse_BrtCellIsst(data) { | ||||
| @ -185,17 +137,6 @@ function write_BrtCellIsst(cell, ncell, o) { | ||||
| 	o.write_shift(4, ncell.v); | ||||
| 	return o; | ||||
| } | ||||
| function parse_BrtShortIsst(data) { | ||||
| 	var cell = parse_XLSBShortCell(data); | ||||
| 	var isst = data.read_shift(4); | ||||
| 	return [cell, isst, 's']; | ||||
| } | ||||
| function write_BrtShortIsst(cell, ncell, o) { | ||||
| 	if(o == null) o = new_buf(8); | ||||
| 	write_XLSBShortCell(ncell, o); | ||||
| 	o.write_shift(4, ncell.v); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.313 BrtCellReal */ | ||||
| function parse_BrtCellReal(data) { | ||||
| @ -209,17 +150,6 @@ function write_BrtCellReal(cell, ncell, o) { | ||||
| 	write_Xnum(cell.v, o); | ||||
| 	return o; | ||||
| } | ||||
| function parse_BrtShortReal(data) { | ||||
| 	var cell = parse_XLSBShortCell(data); | ||||
| 	var value = parse_Xnum(data); | ||||
| 	return [cell, value, 'n']; | ||||
| } | ||||
| function write_BrtShortReal(cell, ncell, o) { | ||||
| 	if(o == null) o = new_buf(12); | ||||
| 	write_XLSBShortCell(ncell, o); | ||||
| 	write_Xnum(cell.v, o); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.314 BrtCellRk */ | ||||
| function parse_BrtCellRk(data) { | ||||
| @ -233,24 +163,7 @@ function write_BrtCellRk(cell, ncell, o) { | ||||
| 	write_RkNumber(cell.v, o); | ||||
| 	return o; | ||||
| } | ||||
| function parse_BrtShortRk(data) { | ||||
| 	var cell = parse_XLSBShortCell(data); | ||||
| 	var value = parse_RkNumber(data); | ||||
| 	return [cell, value, 'n']; | ||||
| } | ||||
| function write_BrtShortRk(cell, ncell, o) { | ||||
| 	if(o == null) o = new_buf(8); | ||||
| 	write_XLSBShortCell(ncell, o); | ||||
| 	write_RkNumber(cell.v, o); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.323 BrtCellRString */ | ||||
| function parse_BrtCellRString(data) { | ||||
| 	var cell = parse_XLSBCell(data); | ||||
| 	var value = parse_RichStr(data); | ||||
| 	return [cell, value, 'is']; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.317 BrtCellSt */ | ||||
| function parse_BrtCellSt(data) { | ||||
| @ -259,22 +172,9 @@ function parse_BrtCellSt(data) { | ||||
| 	return [cell, value, 'str']; | ||||
| } | ||||
| function write_BrtCellSt(cell, ncell, o) { | ||||
| 	var data = cell.v == null ? "" : String(cell.v); | ||||
| 	if(o == null) o = new_buf(12 + 4 * cell.v.length); | ||||
| 	write_XLSBCell(ncell, o); | ||||
| 	write_XLWideString(data, o); | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| function parse_BrtShortSt(data) { | ||||
| 	var cell = parse_XLSBShortCell(data); | ||||
| 	var value = parse_XLWideString(data); | ||||
| 	return [cell, value, 'str']; | ||||
| } | ||||
| function write_BrtShortSt(cell, ncell, o) { | ||||
| 	var data = cell.v == null ? "" : String(cell.v); | ||||
| 	if(o == null) o = new_buf(8 + 4 * data.length); | ||||
| 	write_XLSBShortCell(ncell, o); | ||||
| 	write_XLWideString(data, o); | ||||
| 	write_XLWideString(cell.v, o); | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| 
 | ||||
| @ -511,7 +411,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 	var opts = _opts || {}; | ||||
| 	if(!rels) rels = {'!id':{}}; | ||||
| 	if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| 	var s/*:Worksheet*/ = ({}); if(opts.dense) s["!data"] = []; | ||||
| 	var s/*:Worksheet*/ = (opts.dense ? [] : {}); | ||||
| 
 | ||||
| 	var ref; | ||||
| 	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} }; | ||||
| @ -539,12 +439,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 	var colinfo/*:Array<ColInfo>*/ = [], rowinfo/*:Array<RowInfo>*/ = []; | ||||
| 	var seencol = false; | ||||
| 
 | ||||
| 	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal }; | ||||
| 
 | ||||
| 	var cm, vm; | ||||
| 	var date1904 = 1462 * +!!((wb||{}).WBProps||{}).date1904; | ||||
| 
 | ||||
| 	recordhopper(data, function ws_parse(val, RR, RT) { | ||||
| 	recordhopper(data, function ws_parse(val, R_n, RT) { | ||||
| 		if(end) return; | ||||
| 		switch(RT) { | ||||
| 			case 0x0094: /* 'BrtWsDim' */ | ||||
| @ -570,13 +465,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x0009: /* 'BrtFmlaNum' */ | ||||
| 			case 0x000A: /* 'BrtFmlaBool' */ | ||||
| 			case 0x000B: /* 'BrtFmlaError' */ | ||||
| 			case 0x000D: /* 'BrtShortRk' */ | ||||
| 			case 0x000E: /* 'BrtShortError' */ | ||||
| 			case 0x000F: /* 'BrtShortBool' */ | ||||
| 			case 0x0010: /* 'BrtShortReal' */ | ||||
| 			case 0x0011: /* 'BrtShortSt' */ | ||||
| 			case 0x0012: /* 'BrtShortIsst' */ | ||||
| 			case 0x003E: /* 'BrtCellRString' */ | ||||
| 				p = ({t:val[2]}/*:any*/); | ||||
| 				switch(val[2]) { | ||||
| 					case 'n': p.v = val[1]; break; | ||||
| @ -584,11 +472,10 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 					case 'b': p.v = val[1] ? true : false; break; | ||||
| 					case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break; | ||||
| 					case 'str': p.t = 's'; p.v = val[1]; break; | ||||
| 					case 'is': p.t = 's'; p.v = val[1].t; break; | ||||
| 				} | ||||
| 				if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles, date1904>0); | ||||
| 				C = val[0].c == -1 ? C + 1 : val[0].c; | ||||
| 				if(opts.dense) { if(!s["!data"][R]) s["!data"][R] = []; s["!data"][R][C] = p; } | ||||
| 				if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles); | ||||
| 				C = val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| 				if(opts.cellFormula) { | ||||
| 					af = false; | ||||
| @ -601,46 +488,30 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 					} | ||||
| 					if(!af && val.length > 3) p.f = val[3]; | ||||
| 				} | ||||
| 
 | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| 				if(refguess.e.c < C) refguess.e.c = C; | ||||
| 				if(opts.cellDates && cf && p.t == 'n' && fmt_is_date(table_fmt[cf.numFmtId])) { | ||||
| 					var _d = SSF_parse_date_code(p.v + date1904); if(_d) { p.t = 'd'; p.v = new Date(Date.UTC(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u)); } | ||||
| 				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) { | ||||
| 					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } | ||||
| 				} | ||||
| 				if(cm) { | ||||
| 					if(cm.type == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0001: /* 'BrtCellBlank' */ | ||||
| 			case 0x000C: /* 'BrtShortBlank' */ | ||||
| 				if(!opts.sheetStubs || pass) break; | ||||
| 				p = ({t:'z',v:void 0}/*:any*/); | ||||
| 				C = val[0].c == -1 ? C + 1 : val[0].c; | ||||
| 				if(opts.dense) { if(!s["!data"][R]) s["!data"][R] = []; s["!data"][R][C] = p; } | ||||
| 				p = ({t:'z',v:undefined}/*:any*/); | ||||
| 				C = val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| 				if(refguess.e.c < C) refguess.e.c = C; | ||||
| 				if(cm) { | ||||
| 					if(cm.type == 'XLDAPR') p.D = true; | ||||
| 					cm = void 0; | ||||
| 				} | ||||
| 				if(vm) vm = void 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x00B0: /* 'BrtMergeCell' */ | ||||
| 				merges.push(val); break; | ||||
| 
 | ||||
| 			case 0x0031: { /* 'BrtCellMeta' */ | ||||
| 				cm = ((opts.xlmeta||{}).Cell||[])[val-1]; | ||||
| 			} break; | ||||
| 
 | ||||
| 			case 0x01EE: /* 'BrtHLink' */ | ||||
| 				var rel = rels['!id'][val.relId]; | ||||
| 				if(rel) { | ||||
| @ -652,11 +523,11 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 				} | ||||
| 				for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) { | ||||
| 					if(opts.dense) { | ||||
| 						if(!s["!data"][R]) s["!data"][R] = []; | ||||
| 						if(!s["!data"][R][C]) s["!data"][R][C] = {t:'z',v:undefined}; | ||||
| 						s["!data"][R][C].l = val; | ||||
| 						if(!s[R]) s[R] = []; | ||||
| 						if(!s[R][C]) s[R][C] = {t:'z',v:undefined}; | ||||
| 						s[R][C].l = val; | ||||
| 					} else { | ||||
| 						addr = encode_col(C) + encode_row(R); | ||||
| 						addr = encode_cell({c:C,r:R}); | ||||
| 						if(!s[addr]) s[addr] = {t:'z',v:undefined}; | ||||
| 						s[addr].l = val; | ||||
| 					} | ||||
| @ -666,14 +537,14 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x01AA: /* 'BrtArrFmla' */ | ||||
| 				if(!opts.cellFormula) break; | ||||
| 				arrayf.push(val); | ||||
| 				cell = ((opts.dense ? s["!data"][R][C] : s[encode_col(C) + rr])/*:any*/); | ||||
| 				cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr])/*:any*/); | ||||
| 				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); | ||||
| 				cell.F = encode_range(val[0]); | ||||
| 				break; | ||||
| 			case 0x01AB: /* 'BrtShrFmla' */ | ||||
| 				if(!opts.cellFormula) break; | ||||
| 				sharedf[encode_cell(val[0].s)] = val[1]; | ||||
| 				cell = (opts.dense ? s["!data"][R][C] : s[encode_col(C) + rr]); | ||||
| 				cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]); | ||||
| 				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); | ||||
| 				break; | ||||
| 
 | ||||
| @ -687,10 +558,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0227: /* 'BrtLegacyDrawing' */ | ||||
| 				if(val) s["!legrel"] = val; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x00A1: /* 'BrtBeginAFilter' */ | ||||
| 				s['!autofilter'] = { ref:encode_range(val) }; | ||||
| 				break; | ||||
| @ -702,7 +569,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x0093: /* 'BrtWsProp' */ | ||||
| 				if(!wb.Sheets[idx]) wb.Sheets[idx] = {}; | ||||
| 				if(val.name) wb.Sheets[idx].CodeName = val.name; | ||||
| 				if(val.above || val.left) s['!outline'] = { above: val.above, left: val.left }; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0089: /* 'BrtBeginWsView' */ | ||||
| @ -720,7 +586,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 
 | ||||
| 			case 0x0097: /* 'BrtPane' */ | ||||
| 				break; | ||||
| 			case 0x0098: /* 'BrtSel' */ | ||||
| 			case 0x00AF: /* 'BrtAFilterDateGroupItem' */ | ||||
| 			case 0x0284: /* 'BrtActiveX' */ | ||||
| 			case 0x0271: /* 'BrtBigName' */ | ||||
| @ -732,6 +597,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x041A: /* 'BrtCFVO14' */ | ||||
| 			case 0x0289: /* 'BrtCellIgnoreEC' */ | ||||
| 			case 0x0451: /* 'BrtCellIgnoreEC14' */ | ||||
| 			case 0x0031: /* 'BrtCellMeta' */ | ||||
| 			case 0x024D: /* 'BrtCellSmartTagProperty' */ | ||||
| 			case 0x025F: /* 'BrtCellWatch' */ | ||||
| 			case 0x0234: /* 'BrtColor' */ | ||||
| @ -747,6 +613,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x0499: /* 'BrtFilter14' */ | ||||
| 			case 0x00A9: /* 'BrtIconFilter' */ | ||||
| 			case 0x049D: /* 'BrtIconFilter14' */ | ||||
| 			case 0x0227: /* 'BrtLegacyDrawing' */ | ||||
| 			case 0x0228: /* 'BrtLegacyDrawingHF' */ | ||||
| 			case 0x0295: /* 'BrtListPart' */ | ||||
| 			case 0x027F: /* 'BrtOleObject' */ | ||||
| @ -758,6 +625,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x02A8: /* 'BrtRangeProtectionIso' */ | ||||
| 			case 0x0450: /* 'BrtRangeProtectionIso14' */ | ||||
| 			case 0x0400: /* 'BrtRwDescent' */ | ||||
| 			case 0x0098: /* 'BrtSel' */ | ||||
| 			case 0x0297: /* 'BrtSheetCalcProp' */ | ||||
| 			case 0x0217: /* 'BrtSheetProtection' */ | ||||
| 			case 0x02A6: /* 'BrtSheetProtectionIso' */ | ||||
| @ -776,13 +644,14 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x0024: /* 'BrtFRTEnd' */ | ||||
| 				pass = false; break; | ||||
| 			case 0x0025: /* 'BrtACBegin' */ | ||||
| 				state.push(RT); pass = true; break; | ||||
| 				state.push(R_n); pass = true; break; | ||||
| 			case 0x0026: /* 'BrtACEnd' */ | ||||
| 				state.pop(); pass = false; break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if(RR.T){/* empty */} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
| 				if((R_n||"").indexOf("Begin") > 0){/* empty */} | ||||
| 				else if((R_n||"").indexOf("End") > 0){/* empty */} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n); | ||||
| 		} | ||||
| 	}, opts); | ||||
| 
 | ||||
| @ -805,131 +674,105 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 	if(merges.length > 0) s["!merges"] = merges; | ||||
| 	if(colinfo.length > 0) s["!cols"] = colinfo; | ||||
| 	if(rowinfo.length > 0) s["!rows"] = rowinfo; | ||||
| 	if(rels['!id'][s['!legrel']]) s['!legdrawel'] = rels['!id'][s['!legrel']]; | ||||
| 	return s; | ||||
| } | ||||
| 
 | ||||
| /* TODO: something useful -- this is a stub */ | ||||
| function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, ws/*:Worksheet*/, last_seen/*:boolean*/, date1904/*:boolean*/)/*:boolean*/ { | ||||
| 	var o/*:any*/ = ({r:R, c:C}/*:any*/); | ||||
| 	if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]); | ||||
| 	if(cell.v === undefined) return false; | ||||
| function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, ws/*:Worksheet*/) { | ||||
| 	if(cell.v === undefined) return; | ||||
| 	var vv = ""; | ||||
| 	switch(cell.t) { | ||||
| 		case 'b': vv = cell.v ? "1" : "0"; break; | ||||
| 		case 'd': // no BrtCellDate :(
 | ||||
| 			cell = dup(cell); | ||||
| 			cell.z = cell.z || table_fmt[14]; | ||||
| 			cell.v = datenum(parseDate(cell.v, date1904), date1904); cell.t = 'n'; | ||||
| 			cell.z = cell.z || SSF._table[14]; | ||||
| 			cell.v = datenum(parseDate(cell.v)); cell.t = 'n'; | ||||
| 			break; | ||||
| 		/* falls through */ | ||||
| 		case 'n': case 'e': vv = ''+cell.v; break; | ||||
| 		default: vv = cell.v; break; | ||||
| 	} | ||||
| 	var o/*:any*/ = ({r:R, c:C}/*:any*/); | ||||
| 	/* TODO: cell style */ | ||||
| 	o.s = get_cell_style(opts.cellXfs, cell, opts); | ||||
| 	if(cell.l) ws['!links'].push([encode_cell(o), cell.l]); | ||||
| 	if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]); | ||||
| 	switch(cell.t) { | ||||
| 		case 's': case 'str': | ||||
| 			if(opts.bookSST) { | ||||
| 				vv = get_sst_id(opts.Strings, (cell.v == null ? "" : String(cell.v)/*:any*/), opts.revStrings); | ||||
| 				vv = get_sst_id(opts.Strings, (cell.v/*:any*/), opts.revStrings); | ||||
| 				o.t = "s"; o.v = vv; | ||||
| 				if(last_seen) write_record(ba, 0x0012 /* BrtShortIsst */, write_BrtShortIsst(cell, o)); | ||||
| 				else write_record(ba, 0x0007 /* BrtCellIsst */, write_BrtCellIsst(cell, o)); | ||||
| 				write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o)); | ||||
| 			} else { | ||||
| 				o.t = "str"; | ||||
| 				if(last_seen) write_record(ba, 0x0011 /* BrtShortSt */, write_BrtShortSt(cell, o)); | ||||
| 				else write_record(ba, 0x0006 /* BrtCellSt */, write_BrtCellSt(cell, o)); | ||||
| 				write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o)); | ||||
| 			} | ||||
| 			return true; | ||||
| 			return; | ||||
| 		case 'n': | ||||
| 			/* TODO: determine threshold for Real vs RK */ | ||||
| 			if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) { | ||||
| 				if(last_seen) write_record(ba, 0x000D /* BrtShortRk */, write_BrtShortRk(cell, o)); | ||||
| 				else write_record(ba, 0x0002 /* BrtCellRk */, write_BrtCellRk(cell, o)); | ||||
| 			} else if(!isFinite(cell.v)) { | ||||
| 				o.t = "e"; | ||||
| 				if(isNaN(cell.v)) { | ||||
| 					if(last_seen) write_record(ba, 0x000E /* BrtShortError */, write_BrtShortError({t:"e", v: 0x24}, o)); // #NUM!
 | ||||
| 					else write_record(ba, 0x0003 /* BrtCellError */, write_BrtCellError({t:"e", v: 0x24}, o)); // #NUM!
 | ||||
| 				} else { | ||||
| 					if(last_seen) write_record(ba, 0x000E /* BrtShortError */, write_BrtShortError({t:"e", v: 0x07}, o)); // #DIV/0!
 | ||||
| 					else write_record(ba, 0x0003 /* BrtCellError */, write_BrtCellError({t:"e", v: 0x07}, o)); // #DIV/0!
 | ||||
| 				} | ||||
| 			} else { | ||||
| 				if(last_seen) write_record(ba, 0x0010 /* BrtShortReal */, write_BrtShortReal(cell, o)); | ||||
| 				else write_record(ba, 0x0005 /* BrtCellReal */, write_BrtCellReal(cell, o)); | ||||
| 			} return true; | ||||
| 			if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o)); | ||||
| 			else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o)); | ||||
| 			return; | ||||
| 		case 'b': | ||||
| 			o.t = "b"; | ||||
| 			if(last_seen) write_record(ba, 0x000F /* BrtShortBool */, write_BrtShortBool(cell, o)); | ||||
| 			else write_record(ba, 0x0004 /* BrtCellBool */, write_BrtCellBool(cell, o)); | ||||
| 			return true; | ||||
| 		case 'e': | ||||
| 			o.t = "e"; | ||||
| 			if(last_seen) write_record(ba, 0x000E /* BrtShortError */, write_BrtShortError(cell, o)); | ||||
| 			else write_record(ba, 0x0003 /* BrtCellError */, write_BrtCellError(cell, o)); | ||||
| 			return true; | ||||
| 			write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o)); | ||||
| 			return; | ||||
| 		case 'e': /* TODO: error */ o.t = "e"; break; | ||||
| 	} | ||||
| 	if(last_seen) write_record(ba, 0x000C /* BrtShortBlank */, write_BrtShortBlank(cell, o)); | ||||
| 	else write_record(ba, 0x0001 /* BrtCellBlank */, write_BrtCellBlank(cell, o)); | ||||
| 	return true; | ||||
| 	write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o)); | ||||
| } | ||||
| 
 | ||||
| function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) { | ||||
| 	var range = safe_decode_range(ws['!ref'] || "A1"), rr = "", cols/*:Array<string>*/ = []; | ||||
| 	var date1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904; | ||||
| 	write_record(ba, 0x0091 /* BrtBeginSheetData */); | ||||
| 	var dense = ws["!data"] != null, row = dense ? ws["!data"][range.s.r] : []; | ||||
| function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) { | ||||
| 	var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols/*:Array<string>*/ = []; | ||||
| 	write_record(ba, 'BrtBeginSheetData'); | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	var cap = range.e.r; | ||||
| 	if(ws['!rows']) cap = Math.max(range.e.r, ws['!rows'].length - 1); | ||||
| 	for(var R = range.s.r; R <= cap; ++R) { | ||||
| 		rr = encode_row(R); | ||||
| 		if(dense) row = ws["!data"][R]; | ||||
| 		/* [ACCELLTABLE] */ | ||||
| 		/* BrtRowHdr */ | ||||
| 		write_row_header(ba, ws, range, R); | ||||
| 		if(dense && !row) continue; | ||||
| 		var last_seen = false; | ||||
| 		if(R <= range.e.r) for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			/* *16384CELL */ | ||||
| 			if(R === range.s.r) cols[C] = encode_col(C); | ||||
| 			var cell = dense ? row[C] : ws[cols[C] + rr]; | ||||
| 			if(!cell) { last_seen = false; continue; } | ||||
| 			ref = cols[C] + rr; | ||||
| 			var cell = dense ? (ws[R]||[])[C] : ws[ref]; | ||||
| 			if(!cell) continue; | ||||
| 			/* write cell */ | ||||
| 			last_seen = write_ws_bin_cell(ba, cell, R, C, opts, ws, last_seen, date1904); | ||||
| 			write_ws_bin_cell(ba, cell, R, C, opts, ws); | ||||
| 		} | ||||
| 	} | ||||
| 	write_record(ba, 0x0092 /* BrtEndSheetData */); | ||||
| 	write_record(ba, 'BrtEndSheetData'); | ||||
| } | ||||
| 
 | ||||
| function write_MERGECELLS(ba, ws/*:Worksheet*/) { | ||||
| 	if(!ws || !ws['!merges']) return; | ||||
| 	write_record(ba, 0x00B1 /* BrtBeginMergeCells */, write_BrtBeginMergeCells(ws['!merges'].length)); | ||||
| 	ws['!merges'].forEach(function(m) { write_record(ba, 0x00B0 /* BrtMergeCell */, write_BrtMergeCell(m)); }); | ||||
| 	write_record(ba, 0x00B2 /* BrtEndMergeCells */); | ||||
| 	write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length)); | ||||
| 	ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); }); | ||||
| 	write_record(ba, 'BrtEndMergeCells'); | ||||
| } | ||||
| 
 | ||||
| function write_COLINFOS(ba, ws/*:Worksheet*//*::, idx:number, opts, wb:Workbook*/) { | ||||
| 	if(!ws || !ws['!cols']) return; | ||||
| 	write_record(ba, 0x0186 /* BrtBeginColInfos */); | ||||
| 	ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 0x003C /* 'BrtColInfo' */, write_BrtColInfo(i, m)); }); | ||||
| 	write_record(ba, 0x0187 /* BrtEndColInfos */); | ||||
| 	write_record(ba, 'BrtBeginColInfos'); | ||||
| 	ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); }); | ||||
| 	write_record(ba, 'BrtEndColInfos'); | ||||
| } | ||||
| 
 | ||||
| function write_IGNOREECS(ba, ws/*:Worksheet*/) { | ||||
| 	if(!ws || !ws['!ref']) return; | ||||
| 	write_record(ba, 0x0288 /* BrtBeginCellIgnoreECs */); | ||||
| 	write_record(ba, 0x0289 /* BrtCellIgnoreEC */, write_BrtCellIgnoreEC(safe_decode_range(ws['!ref']))); | ||||
| 	write_record(ba, 0x028A /* BrtEndCellIgnoreECs */); | ||||
| 	write_record(ba, 'BrtBeginCellIgnoreECs'); | ||||
| 	write_record(ba, 'BrtCellIgnoreEC', write_BrtCellIgnoreEC(safe_decode_range(ws['!ref']))); | ||||
| 	write_record(ba, 'BrtEndCellIgnoreECs'); | ||||
| } | ||||
| 
 | ||||
| function write_HLINKS(ba, ws/*:Worksheet*/, rels) { | ||||
| 	/* *BrtHLink */ | ||||
| 	ws['!links'].forEach(function(l) { | ||||
| 		if(!l[1].Target) return; | ||||
| 		var rId = add_rels(rels, -1, l[1].Target.replace(/#[\s\S]*$/, ""), RELS.HLINK); | ||||
| 		write_record(ba, 0x01EE /* BrtHLink */, write_BrtHLink(l, rId)); | ||||
| 		var rId = add_rels(rels, -1, l[1].Target.replace(/#.*$/, ""), RELS.HLINK); | ||||
| 		write_record(ba, "BrtHLink", write_BrtHLink(l, rId)); | ||||
| 	}); | ||||
| 	delete ws['!links']; | ||||
| } | ||||
| @ -937,7 +780,7 @@ function write_LEGACYDRAWING(ba, ws/*:Worksheet*/, idx/*:number*/, rels) { | ||||
| 	/* [BrtLegacyDrawing] */ | ||||
| 	if(ws['!comments'].length > 0) { | ||||
| 		var rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML); | ||||
| 		write_record(ba, 0x0227 /* BrtLegacyDrawing */, write_RelID("rId" + rId)); | ||||
| 		write_record(ba, "BrtLegacyDrawing", write_RelID("rId" + rId)); | ||||
| 		ws['!legacy'] = rId; | ||||
| 	} | ||||
| } | ||||
| @ -957,41 +800,41 @@ function write_AUTOFILTER(ba, ws, wb, idx) { | ||||
| 		var name = names[i]; | ||||
| 		if(name.Name != '_xlnm._FilterDatabase') continue; | ||||
| 		if(name.Sheet != idx) continue; | ||||
| 		name.Ref = formula_quote_sheet_name(wb.SheetNames[idx]) + "!" + fix_range(ref); break; | ||||
| 		name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break; | ||||
| 	} | ||||
| 	if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: formula_quote_sheet_name(wb.SheetNames[idx]) + "!" + fix_range(ref)  }); | ||||
| 	if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref  }); | ||||
| 
 | ||||
| 	write_record(ba, 0x00A1 /* BrtBeginAFilter */, write_UncheckedRfX(safe_decode_range(ref))); | ||||
| 	write_record(ba, "BrtBeginAFilter", write_UncheckedRfX(safe_decode_range(ref))); | ||||
| 	/* *FILTERCOLUMN */ | ||||
| 	/* [SORTSTATE] */ | ||||
| 	/* BrtEndAFilter */ | ||||
| 	write_record(ba, 0x00A2 /* BrtEndAFilter */); | ||||
| 	write_record(ba, "BrtEndAFilter"); | ||||
| } | ||||
| 
 | ||||
| function write_WSVIEWS2(ba, ws, Workbook) { | ||||
| 	write_record(ba, 0x0085 /* BrtBeginWsViews */); | ||||
| 	write_record(ba, "BrtBeginWsViews"); | ||||
| 	{ /* 1*WSVIEW2 */ | ||||
| 		/* [ACUID] */ | ||||
| 		write_record(ba, 0x0089 /* BrtBeginWsView */, write_BrtBeginWsView(ws, Workbook)); | ||||
| 		write_record(ba, "BrtBeginWsView", write_BrtBeginWsView(ws, Workbook)); | ||||
| 		/* [BrtPane] */ | ||||
| 		/* *4BrtSel */ | ||||
| 		/* *4SXSELECT */ | ||||
| 		/* *FRT */ | ||||
| 		write_record(ba, 0x008A /* BrtEndWsView */); | ||||
| 		write_record(ba, "BrtEndWsView"); | ||||
| 	} | ||||
| 	/* *FRT */ | ||||
| 	write_record(ba, 0x0086 /* BrtEndWsViews */); | ||||
| 	write_record(ba, "BrtEndWsViews"); | ||||
| } | ||||
| 
 | ||||
| function write_WSFMTINFO(/*::ba, ws*/) { | ||||
| 	/* [ACWSFMTINFO] */ | ||||
| 	// write_record(ba, 0x01E5 /* BrtWsFmtInfo */, write_BrtWsFmtInfo(ws));
 | ||||
| 	//write_record(ba, "BrtWsFmtInfo", write_BrtWsFmtInfo(ws));
 | ||||
| } | ||||
| 
 | ||||
| function write_SHEETPROTECT(ba, ws) { | ||||
| 	if(!ws['!protect']) return; | ||||
| 	/* [BrtSheetProtectionIso] */ | ||||
| 	write_record(ba, 0x0217 /* BrtSheetProtection */, write_BrtSheetProtection(ws['!protect'])); | ||||
| 	write_record(ba, "BrtSheetProtection", write_BrtSheetProtection(ws['!protect'])); | ||||
| } | ||||
| 
 | ||||
| function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) { | ||||
| @ -1007,9 +850,9 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	ws['!links'] = []; | ||||
| 	/* passed back to write_zip and removed there */ | ||||
| 	ws['!comments'] = []; | ||||
| 	write_record(ba, 0x0081 /* BrtBeginSheet */); | ||||
| 	if(wb.vbaraw || ws['!outline']) write_record(ba, 0x0093 /* BrtWsProp */, write_BrtWsProp(c, ws['!outline'])); | ||||
| 	write_record(ba, 0x0094 /* BrtWsDim */, write_BrtWsDim(r)); | ||||
| 	write_record(ba, "BrtBeginSheet"); | ||||
| 	if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c)); | ||||
| 	write_record(ba, "BrtWsDim", write_BrtWsDim(r)); | ||||
| 	write_WSVIEWS2(ba, ws, wb.Workbook); | ||||
| 	write_WSFMTINFO(ba, ws); | ||||
| 	write_COLINFOS(ba, ws, idx, opts, wb); | ||||
| @ -1028,7 +871,7 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	/* [DVALS] */ | ||||
| 	write_HLINKS(ba, ws, rels); | ||||
| 	/* [BrtPrintOptions] */ | ||||
| 	if(ws['!margins']) write_record(ba, 0x01DC /* BrtMargins */, write_BrtMargins(ws['!margins'])); | ||||
| 	if(ws['!margins']) write_record(ba, "BrtMargins", write_BrtMargins(ws['!margins'])); | ||||
| 	/* [BrtPageSetup] */ | ||||
| 	/* [HEADERFOOTER] */ | ||||
| 	/* [RWBRK] */ | ||||
| @ -1046,6 +889,6 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	/* [WEBPUBITEMS] */ | ||||
| 	/* [LISTPARTS] */ | ||||
| 	/* FRTWORKSHEET */ | ||||
| 	write_record(ba, 0x0082 /* BrtEndSheet */); | ||||
| 	write_record(ba, "BrtEndSheet"); | ||||
| 	return ba.end(); | ||||
| } | ||||
|  | ||||
| @ -1,19 +1,22 @@ | ||||
| RELS.CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"; | ||||
| RELS.CHARTEX = "http://schemas.microsoft.com/office/2014/relationships/chartEx"; | ||||
| 
 | ||||
| function parse_Cache(data/*:string*/)/*:[Array<number|string>, string, ?string]*/ { | ||||
| 	var col/*:Array<number|string>*/ = []; | ||||
| 	var num = data.match(/^<c:numCache>/); | ||||
| 	var f; | ||||
| 
 | ||||
| 	/* 21.2.2.150 pt CT_NumVal */ | ||||
| 	(data.match(/<c:pt idx="(\d*)"[^<>\/]*><c:v>([^<])<\/c:v><\/c:pt>/mg)||[]).forEach(function(pt) { | ||||
| 		var q = pt.match(/<c:pt idx="(\d*)"[^<>\/]*><c:v>([^<]*)<\/c:v><\/c:pt>/); | ||||
| 	(data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) { | ||||
| 		var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/); | ||||
| 		if(!q) return; | ||||
| 		col[+q[1]] = num ? +q[2] : q[2]; | ||||
| 	}); | ||||
| 
 | ||||
| 	/* 21.2.2.71 formatCode CT_Xstring */ | ||||
| 	var nf = unescapexml((str_match_xml(data, "c:formatCode") || ["","General"])[1]); | ||||
| 	var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]); | ||||
| 
 | ||||
| 	(str_match_ng(data, "<c:f>", "</c:f>")||[]).forEach(function(F) { f = F.replace(/<[^<>]*>/g,""); }); | ||||
| 	(data.match(/<c:f>(.*?)<\/c:f>/mg)||[]).forEach(function(F) { f = F.replace(/<.*?>/g,""); }); | ||||
| 
 | ||||
| 	return [col, nf, f]; | ||||
| } | ||||
| @ -28,16 +31,13 @@ function parse_chart(data/*:?string*/, name/*:string*/, opts, rels, wb, csheet) | ||||
| 	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} }; | ||||
| 
 | ||||
| 	/* 21.2.2.120 numCache CT_NumData */ | ||||
| 	(str_match_ng(data, "<c:numCache>", "</c:numCache>")||[]).forEach(function(nc) { | ||||
| 	(data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) { | ||||
| 		var cache = parse_Cache(nc); | ||||
| 		refguess.s.r = refguess.s.c = 0; | ||||
| 		refguess.e.c = C; | ||||
| 		col = encode_col(C); | ||||
| 		cache[0].forEach(function(n,i) { | ||||
| 			if(cs["!data"]) { | ||||
| 				if(!cs["!data"][i]) cs["!data"][i] = []; | ||||
| 				cs["!data"][i][C] = {t:'n', v:n, z:cache[1] }; | ||||
| 			} else cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] }; | ||||
| 			cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] }; | ||||
| 			R = i; | ||||
| 		}); | ||||
| 		if(refguess.e.r < R) refguess.e.r = R; | ||||
|  | ||||
| @ -1,3 +1,10 @@ | ||||
| RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"; | ||||
| 
 | ||||
| var CS_XML_ROOT = writextag('chartsheet', null, { | ||||
| 	'xmlns': XMLNS.main[0], | ||||
| 	'xmlns:r': XMLNS.r | ||||
| }); | ||||
| 
 | ||||
| /* 18.3 Worksheets also covers Chartsheets */ | ||||
| function parse_cs_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*::, themes, styles*/)/*:Worksheet*/ { | ||||
| 	if(!data) return data; | ||||
| @ -16,16 +23,13 @@ function parse_cs_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*::, them | ||||
| 	if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']]; | ||||
| 	return s; | ||||
| } | ||||
| //function write_cs_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
 | ||||
| //	var o = [XML_HEADER, writextag('chartsheet', null, {
 | ||||
| //		'xmlns': XMLNS_main[0],
 | ||||
| //		'xmlns:r': XMLNS.r
 | ||||
| //	})];
 | ||||
| //	o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
 | ||||
| //	add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
 | ||||
| //	if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
 | ||||
| //	return o.join("");
 | ||||
| //}
 | ||||
| function write_cs_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ { | ||||
| 	var o = [XML_HEADER, CS_XML_ROOT]; | ||||
| 	o[o.length] = writextag("drawing", null, {"r:id": "rId1"}); | ||||
| 	add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW); | ||||
| 	if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.331 BrtCsProp */ | ||||
| function parse_BrtCsProp(data, length/*:number*/) { | ||||
| @ -41,7 +45,7 @@ function parse_cs_bin(data, opts, idx/*:number*/, rels, wb/*::, themes, styles*/ | ||||
| 	var s = {'!type':"chart", '!drawel':null, '!rel':""}; | ||||
| 	var state/*:Array<string>*/ = []; | ||||
| 	var pass = false; | ||||
| 	recordhopper(data, function cs_parse(val, R, RT) { | ||||
| 	recordhopper(data, function cs_parse(val, R_n, RT) { | ||||
| 		switch(RT) { | ||||
| 
 | ||||
| 			case 0x0226: /* 'BrtDrawing' */ | ||||
| @ -67,36 +71,36 @@ function parse_cs_bin(data, opts, idx/*:number*/, rels, wb/*::, themes, styles*/ | ||||
| 			case 0x0024: /* 'BrtFRTEnd' */ | ||||
| 				pass = false; break; | ||||
| 			case 0x0025: /* 'BrtACBegin' */ | ||||
| 				state.push(RT); break; | ||||
| 				state.push(R_n); break; | ||||
| 			case 0x0026: /* 'BrtACEnd' */ | ||||
| 				state.pop(); break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if(R.T > 0) state.push(RT); | ||||
| 				else if(R.T < 0) state.pop(); | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
| 				if((R_n||"").indexOf("Begin") > 0) state.push(R_n); | ||||
| 				else if((R_n||"").indexOf("End") > 0) state.pop(); | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n); | ||||
| 		} | ||||
| 	}, opts); | ||||
| 
 | ||||
| 	if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']]; | ||||
| 	return s; | ||||
| } | ||||
| //function write_cs_bin(/*::idx:number, opts, wb:Workbook, rels*/) {
 | ||||
| //	var ba = buf_array();
 | ||||
| //	write_record(ba, 0x0081 /* BrtBeginSheet */);
 | ||||
| //	/* [BrtCsProp] */
 | ||||
| //	/* CSVIEWS */
 | ||||
| //	/* [[BrtCsProtectionIso] BrtCsProtection] */
 | ||||
| //	/* [USERCSVIEWS] */
 | ||||
| //	/* [BrtMargins] */
 | ||||
| //	/* [BrtCsPageSetup] */
 | ||||
| //	/* [HEADERFOOTER] */
 | ||||
| //	/* BrtDrawing */
 | ||||
| //	/* [BrtLegacyDrawing] */
 | ||||
| //	/* [BrtLegacyDrawingHF] */
 | ||||
| //	/* [BrtBkHim] */
 | ||||
| //	/* [WEBPUBITEMS] */
 | ||||
| //	/* FRTCHARTSHEET */
 | ||||
| //	write_record(ba, 0x0082 /* BrtEndSheet */);
 | ||||
| //	return ba.end();
 | ||||
| //}
 | ||||
| function write_cs_bin(/*::idx:number, opts, wb:Workbook, rels*/) { | ||||
| 	var ba = buf_array(); | ||||
| 	write_record(ba, "BrtBeginSheet"); | ||||
| 	/* [BrtCsProp] */ | ||||
| 	/* CSVIEWS */ | ||||
| 	/* [[BrtCsProtectionIso] BrtCsProtection] */ | ||||
| 	/* [USERCSVIEWS] */ | ||||
| 	/* [BrtMargins] */ | ||||
| 	/* [BrtCsPageSetup] */ | ||||
| 	/* [HEADERFOOTER] */ | ||||
| 	/* BrtDrawing */ | ||||
| 	/* [BrtLegacyDrawing] */ | ||||
| 	/* [BrtLegacyDrawingHF] */ | ||||
| 	/* [BrtBkHim] */ | ||||
| 	/* [WEBPUBITEMS] */ | ||||
| 	/* FRTCHARTSHEET */ | ||||
| 	write_record(ba, "BrtEndSheet"); | ||||
| 	return ba.end(); | ||||
| } | ||||
|  | ||||
| @ -113,19 +113,16 @@ function safe1904(wb/*:Workbook*/)/*:string*/ { | ||||
| 	return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; | ||||
| } | ||||
| 
 | ||||
| var badchars = /*#__PURE__*/":][*?\/\\".split(""); | ||||
| var badchars = "][*?\/\\".split(""); | ||||
| function check_ws_name(n/*:string*/, safe/*:?boolean*/)/*:boolean*/ { | ||||
| 	try { | ||||
| 		if(n == "") throw new Error("Sheet name cannot be blank"); | ||||
| 		if(n.length > 31) throw new Error("Sheet name cannot exceed 31 chars"); | ||||
| 		if(n.charCodeAt(0) == 0x27 || n.charCodeAt(n.length - 1) == 0x27) throw new Error("Sheet name cannot start or end with apostrophe (')"); | ||||
| 		if(n.toLowerCase() == "history") throw new Error("Sheet name cannot be 'History'"); | ||||
| 		badchars.forEach(function(c) { | ||||
| 			if(n.indexOf(c) == -1) return; | ||||
| 			throw new Error("Sheet name cannot contain : \\ / ? * [ ]"); | ||||
| 		}); | ||||
| 	} catch(e) { if(safe) return false; throw e; } | ||||
| 	return true; | ||||
| 	if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); } | ||||
| 	var _good = true; | ||||
| 	badchars.forEach(function(c) { | ||||
| 		if(n.indexOf(c) == -1) return; | ||||
| 		if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]"); | ||||
| 		_good = false; | ||||
| 	}); | ||||
| 	return _good; | ||||
| } | ||||
| function check_wb_names(N, S, codes) { | ||||
| 	N.forEach(function(n,i) { | ||||
| @ -143,16 +140,5 @@ function check_wb(wb) { | ||||
| 	var Sheets = (wb.Workbook && wb.Workbook.Sheets) || []; | ||||
| 	check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw); | ||||
| 	for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i); | ||||
| 	wb.SheetNames.forEach(function(n, i) { | ||||
| 		var ws = wb.Sheets[n]; | ||||
| 		if(!ws || !ws["!autofilter"]) return; | ||||
| 		var DN; | ||||
| 		if(!wb.Workbook) wb.Workbook = {}; | ||||
| 		if(!wb.Workbook.Names) wb.Workbook.Names = []; | ||||
| 		wb.Workbook.Names.forEach(function(dn) { if(dn.Name == "_xlnm._FilterDatabase" && dn.Sheet == i) DN = dn; }); | ||||
| 		var nn = formula_quote_sheet_name(n) + "!" + fix_range(ws["!autofilter"].ref); | ||||
| 		if(DN) DN.Ref = nn; | ||||
| 		else wb.Workbook.Names.push({Name: "_xlnm._FilterDatabase", Sheet: i, Ref: nn}); | ||||
| 	}); | ||||
| 	/* TODO: validate workbook */ | ||||
| } | ||||
|  | ||||
| @ -151,21 +151,23 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ { | ||||
| 		} | ||||
| 		return x; | ||||
| 	}); | ||||
| 	if(XMLNS_main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns); | ||||
| 	if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns); | ||||
| 
 | ||||
| 	parse_wb_defaults(wb); | ||||
| 
 | ||||
| 	return wb; | ||||
| } | ||||
| 
 | ||||
| var WB_XML_ROOT = writextag('workbook', null, { | ||||
| 	'xmlns': XMLNS.main[0], | ||||
| 	//'xmlns:mx': XMLNS.mx,
 | ||||
| 	//'xmlns:s': XMLNS.main[0],
 | ||||
| 	'xmlns:r': XMLNS.r | ||||
| }); | ||||
| 
 | ||||
| function write_wb_xml(wb/*:Workbook*//*::, opts:?WriteOpts*/)/*:string*/ { | ||||
| 	var o = [XML_HEADER]; | ||||
| 	o[o.length] = writextag('workbook', null, { | ||||
| 		'xmlns': XMLNS_main[0], | ||||
| 		//'xmlns:mx': XMLNS.mx,
 | ||||
| 		//'xmlns:s': XMLNS_main[0],
 | ||||
| 		'xmlns:r': XMLNS.r | ||||
| 	}); | ||||
| 	o[o.length] = WB_XML_ROOT; | ||||
| 
 | ||||
| 	var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										126
									
								
								bits/73_wbbin.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										126
									
								
								bits/73_wbbin.js
									
									
									
									
									
								
							| @ -45,7 +45,6 @@ function write_BrtWbProp(data/*:?WBProps*/, o) { | ||||
| 	var flags = 0; | ||||
| 	if(data) { | ||||
| 		/* TODO: mirror parse_BrtWbProp fields */ | ||||
| 		if(data.date1904) flags |= 0x01; | ||||
| 		if(data.filterPrivacy) flags |= 0x08; | ||||
| 	} | ||||
| 	o.write_shift(4, flags); | ||||
| @ -65,19 +64,12 @@ function parse_BrtFRTArchID$(data, length) { | ||||
| /* [MS-XLSB] 2.4.687 BrtName */ | ||||
| function parse_BrtName(data, length, opts) { | ||||
| 	var end = data.l + length; | ||||
| 	var flags = data.read_shift(4); | ||||
| 	data.l += 4; //var flags = data.read_shift(4);
 | ||||
| 	data.l += 1; //var chKey = data.read_shift(1);
 | ||||
| 	var itab = data.read_shift(4); | ||||
| 	var name = parse_XLNameWideString(data); | ||||
| 	var formula; | ||||
| 	var comment = ""; | ||||
| 	try { | ||||
| 		formula = parse_XLSBNameParsedFormula(data, 0, opts); | ||||
| 		try { | ||||
| 			comment = parse_XLNullableWideString(data); | ||||
| 		} catch(e){} | ||||
| 	} catch(e) { console.error("Could not parse defined name " + name); } | ||||
| 	if(flags & 0x20) name = "_xlnm." + name; | ||||
| 	var formula = parse_XLSBNameParsedFormula(data, 0, opts); | ||||
| 	var comment = parse_XLNullableWideString(data); | ||||
| 	//if(0 /* fProc */) {
 | ||||
| 		// unusedstring1: XLNullableWideString
 | ||||
| 		// description: XLNullableWideString
 | ||||
| @ -85,40 +77,11 @@ function parse_BrtName(data, length, opts) { | ||||
| 		// unusedstring2: XLNullableWideString
 | ||||
| 	//}
 | ||||
| 	data.l = end; | ||||
| 	var out = ({Name:name, Ptg:formula, Flags: flags}/*:any*/); | ||||
| 	var out = ({Name:name, Ptg:formula}/*:any*/); | ||||
| 	if(itab < 0xFFFFFFF) out.Sheet = itab; | ||||
| 	if(comment) out.Comment = comment; | ||||
| 	return out; | ||||
| } | ||||
| function write_BrtName(name, wb) { | ||||
| 	var o = new_buf(9); | ||||
| 	var flags = 0; | ||||
| 	var dname = name.Name; | ||||
| 	if(XLSLblBuiltIn.indexOf(dname) > -1) { flags |= 0x20; dname = dname.slice(6); } | ||||
| 	o.write_shift(4, flags); // flags
 | ||||
| 	o.write_shift(1, 0); // chKey
 | ||||
| 	o.write_shift(4, name.Sheet == null ? 0xFFFFFFFF : name.Sheet); | ||||
| 
 | ||||
| 	var arr = [ | ||||
| 		o, | ||||
| 		write_XLWideString(dname), | ||||
| 		write_XLSBNameParsedFormula(name.Ref, wb) | ||||
| 	]; | ||||
| 	if(name.Comment) arr.push(write_XLNullableWideString(name.Comment)); | ||||
| 	else { | ||||
| 		var x = new_buf(4); | ||||
| 		x.write_shift(4, 0xFFFFFFFF); | ||||
| 		arr.push(x); | ||||
| 	} | ||||
| 
 | ||||
| 	// if macro (flags & 0x0F):
 | ||||
| 	// write_shift(4, 0xFFFFFFFF);
 | ||||
| 	// write_XLNullableWideString(description)
 | ||||
| 	// write_XLNullableWideString(helpTopic)
 | ||||
| 	// write_shift(4, 0xFFFFFFFF);
 | ||||
| 
 | ||||
| 	return bconcat(arr); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.61 Workbook */ | ||||
| function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| @ -134,9 +97,7 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| 	supbooks.SheetNames = []; | ||||
| 	supbooks.XTI = []; | ||||
| 
 | ||||
| 	XLSBRecordEnum[0x0010] = { n:"BrtFRTArchID$", f:parse_BrtFRTArchID$ }; | ||||
| 
 | ||||
| 	recordhopper(data, function hopper_wb(val, R, RT) { | ||||
| 	recordhopper(data, function hopper_wb(val, R_n, RT) { | ||||
| 		switch(RT) { | ||||
| 			case 0x009C: /* 'BrtBundleSh' */ | ||||
| 				supbooks.SheetNames.push(val.name); | ||||
| @ -147,7 +108,7 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| 
 | ||||
| 			case 0x0027: /* 'BrtName' */ | ||||
| 				if(val.Sheet != null) opts.SID = val.Sheet; | ||||
| 				val.Ref = val.Ptg ? stringify_formula(val.Ptg, null, null, supbooks, opts) : "#REF!"; | ||||
| 				val.Ref = stringify_formula(val.Ptg, null, null, supbooks, opts); | ||||
| 				delete opts.SID; | ||||
| 				delete val.Ptg; | ||||
| 				Names.push(val); | ||||
| @ -170,18 +131,13 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| 			case 0x0169: /* 'BrtPlaceholderName' */ | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0817: /* 'BrtAbsPath15' */ | ||||
| 			case 0x009E: /* 'BrtBookView' */ | ||||
| 			case 0x008F: /* 'BrtBeginBundleShs' */ | ||||
| 			case 0x0298: /* 'BrtBeginFnGroup' */ | ||||
| 			case 0x0161: /* 'BrtBeginExternals' */ | ||||
| 				break; | ||||
| 
 | ||||
| 			/* case 'BrtModelTimeGroupingCalcCol' */ | ||||
| 			case 0x0C00: /* 'BrtUid' */ | ||||
| 			case 0x0C01: /* 'BrtRevisionPtr' */ | ||||
| 			case 0x0817: /* 'BrtAbsPath15' */ | ||||
| 			case 0x0216: /* 'BrtBookProtection' */ | ||||
| 			case 0x02A5: /* 'BrtBookProtectionIso' */ | ||||
| 			case 0x009E: /* 'BrtBookView' */ | ||||
| 			case 0x009D: /* 'BrtCalcProp' */ | ||||
| 			case 0x0262: /* 'BrtCrashRecErr' */ | ||||
| 			case 0x0802: /* 'BrtDecoupledPivotCacheID' */ | ||||
| @ -206,19 +162,20 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0023: /* 'BrtFRTBegin' */ | ||||
| 				state.push(RT); pass = true; break; | ||||
| 				state.push(R_n); pass = true; break; | ||||
| 			case 0x0024: /* 'BrtFRTEnd' */ | ||||
| 				state.pop(); pass = false; break; | ||||
| 			case 0x0025: /* 'BrtACBegin' */ | ||||
| 				state.push(RT); pass = true; break; | ||||
| 				state.push(R_n); pass = true; break; | ||||
| 			case 0x0026: /* 'BrtACEnd' */ | ||||
| 				state.pop(); pass = false; break; | ||||
| 
 | ||||
| 			case 0x0010: /* 'BrtFRTArchID$' */ break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if(R.T){/* empty */} | ||||
| 				else if(!pass || (opts.WTF && state[state.length-1] != 0x0025 /* BrtACBegin */ && state[state.length-1] != 0x0023 /* BrtFRTBegin */)) throw new Error("Unexpected record 0x" + RT.toString(16)); | ||||
| 				if((R_n||"").indexOf("Begin") > 0){/* empty */} | ||||
| 				else if((R_n||"").indexOf("End") > 0){/* empty */} | ||||
| 				else if(!pass || (opts.WTF && state[state.length-1] != "BrtACBegin" && state[state.length-1] != "BrtFRTBegin")) throw new Error("Unexpected record " + RT + " " + R_n); | ||||
| 		} | ||||
| 	}, opts); | ||||
| 
 | ||||
| @ -232,13 +189,13 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| } | ||||
| 
 | ||||
| function write_BUNDLESHS(ba, wb/*::, opts*/) { | ||||
| 	write_record(ba, 0x008F /* BrtBeginBundleShs */); | ||||
| 	write_record(ba, "BrtBeginBundleShs"); | ||||
| 	for(var idx = 0; idx != wb.SheetNames.length; ++idx) { | ||||
| 		var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0; | ||||
| 		var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] }; | ||||
| 		write_record(ba, 0x009C /* BrtBundleSh */, write_BrtBundleSh(d)); | ||||
| 		write_record(ba, "BrtBundleSh", write_BrtBundleSh(d)); | ||||
| 	} | ||||
| 	write_record(ba, 0x0090 /* BrtEndBundleShs */); | ||||
| 	write_record(ba, "BrtEndBundleShs"); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.649 BrtFileVersion */ | ||||
| @ -249,6 +206,7 @@ function write_BrtFileVersion(data, o) { | ||||
| 	write_XLWideString(XLSX.version, o); | ||||
| 	write_XLWideString(XLSX.version, o); | ||||
| 	write_XLWideString("7262", o); | ||||
| 	o.length = o.l; | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| 
 | ||||
| @ -277,38 +235,10 @@ function write_BOOKVIEWS(ba, wb/*::, opts*/) { | ||||
| 		else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i; | ||||
| 	} | ||||
| 	if(hidden > vistab) return; | ||||
| 	write_record(ba, 0x0087 /* BrtBeginBookViews */); | ||||
| 	write_record(ba, 0x009E /* BrtBookView */, write_BrtBookView(vistab)); | ||||
| 	write_record(ba, "BrtBeginBookViews"); | ||||
| 	write_record(ba, "BrtBookView", write_BrtBookView(vistab)); | ||||
| 	/* 1*(BrtBookView *FRT) */ | ||||
| 	write_record(ba, 0x0088 /* BrtEndBookViews */); | ||||
| } | ||||
| 
 | ||||
| function write_BRTNAMES(ba, wb) { | ||||
| 	if(!wb.Workbook || !wb.Workbook.Names) return; | ||||
| 	wb.Workbook.Names.forEach(function(name) { try { | ||||
| 		if(name.Flags & 0x0e) return; // TODO: macro name write
 | ||||
| 		write_record(ba, 0x0027 /* BrtName */, write_BrtName(name, wb)); | ||||
| 	} catch(e) { | ||||
| 		console.error("Could not serialize defined name " + JSON.stringify(name)); | ||||
| 	} }); | ||||
| } | ||||
| 
 | ||||
| function write_SELF_EXTERNS_xlsb(wb) { | ||||
| 	var L = wb.SheetNames.length; | ||||
| 	var o = new_buf(12 * L + 28); | ||||
| 	o.write_shift(4, L + 2); | ||||
| 	o.write_shift(4, 0); o.write_shift(4, -2); o.write_shift(4, -2); // workbook-level reference
 | ||||
| 	o.write_shift(4, 0); o.write_shift(4, -1); o.write_shift(4, -1); // #REF!...
 | ||||
| 	for(var i = 0; i < L; ++i) { | ||||
| 		o.write_shift(4, 0); o.write_shift(4, i); o.write_shift(4, i); | ||||
| 	} | ||||
| 	return o; | ||||
| } | ||||
| function write_EXTERNALS_xlsb(ba, wb) { | ||||
| 	write_record(ba, 0x0161 /* BrtBeginExternals */); | ||||
| 	write_record(ba, 0x0165 /* BrtSupSelf */); | ||||
| 	write_record(ba, 0x016A /* BrtExternSheet */, write_SELF_EXTERNS_xlsb(wb, 0)); | ||||
| 	write_record(ba, 0x0162 /* BrtEndExternals */); | ||||
| 	write_record(ba, "BrtEndBookViews"); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.305 BrtCalcProp */ | ||||
| @ -334,29 +264,29 @@ function write_EXTERNALS_xlsb(ba, wb) { | ||||
| /* [MS-XLSB] 2.1.7.61 Workbook */ | ||||
| function write_wb_bin(wb, opts) { | ||||
| 	var ba = buf_array(); | ||||
| 	write_record(ba, 0x0083 /* BrtBeginBook */); | ||||
| 	write_record(ba, 0x0080 /* BrtFileVersion */, write_BrtFileVersion()); | ||||
| 	write_record(ba, "BrtBeginBook"); | ||||
| 	write_record(ba, "BrtFileVersion", write_BrtFileVersion()); | ||||
| 	/* [[BrtFileSharingIso] BrtFileSharing] */ | ||||
| 	write_record(ba, 0x0099 /* BrtWbProp */, write_BrtWbProp(wb.Workbook && wb.Workbook.WBProps || null)); | ||||
| 	write_record(ba, "BrtWbProp", write_BrtWbProp(wb.Workbook && wb.Workbook.WBProps || null)); | ||||
| 	/* [ACABSPATH] */ | ||||
| 	/* [[BrtBookProtectionIso] BrtBookProtection] */ | ||||
| 	write_BOOKVIEWS(ba, wb, opts); | ||||
| 	write_BUNDLESHS(ba, wb, opts); | ||||
| 	/* [FNGROUP] */ | ||||
| 	write_EXTERNALS_xlsb(ba, wb); | ||||
| 	if((wb.Workbook||{}).Names) write_BRTNAMES(ba, wb); | ||||
| 	/* write_record(ba, 0x009D BrtCalcProp, write_BrtCalcProp()); */ | ||||
| 	/* [EXTERNALS] */ | ||||
| 	/* *BrtName */ | ||||
| 	/* write_record(ba, "BrtCalcProp", write_BrtCalcProp()); */ | ||||
| 	/* [BrtOleSize] */ | ||||
| 	/* *(BrtUserBookView *FRT) */ | ||||
| 	/* [PIVOTCACHEIDS] */ | ||||
| 	/* [BrtWbFactoid] */ | ||||
| 	/* [SMARTTAGTYPES] */ | ||||
| 	/* [BrtWebOpt] */ | ||||
| 	/* write_record(ba, 0x009B BrtFileRecover, write_BrtFileRecover()); */ | ||||
| 	/* write_record(ba, "BrtFileRecover", write_BrtFileRecover()); */ | ||||
| 	/* [WEBPUBITEMS] */ | ||||
| 	/* [CRERRS] */ | ||||
| 	/* FRTWORKBOOK */ | ||||
| 	write_record(ba, 0x0084 /* BrtEndBook */); | ||||
| 	write_record(ba, "BrtEndBook"); | ||||
| 
 | ||||
| 	return ba.end(); | ||||
| } | ||||
|  | ||||
| @ -28,6 +28,10 @@ function parse_sty(data, name/*:string*/, themes, opts) { | ||||
| 	return parse_sty_xml((data/*:any*/), themes, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_theme(data/*:string*/, name/*:string*/, opts) { | ||||
| 	return parse_theme_xml(data, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_sst(data, name/*:string*/, opts)/*:SST*/ { | ||||
| 	if(name.slice(-4)===".bin") return parse_sst_bin((data/*:any*/), opts); | ||||
| 	return parse_sst_xml((data/*:any*/), opts); | ||||
| @ -48,7 +52,32 @@ function parse_xlink(data, rel, name/*:string*/, opts) { | ||||
| 	return parse_xlink_xml((data/*:any*/), rel, name, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_xlmeta(data, name/*:string*/, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts); | ||||
| 	return parse_xlmeta_xml((data/*:any*/), name, opts); | ||||
| function write_wb(wb, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts); | ||||
| } | ||||
| 
 | ||||
| function write_ws(data/*:number*/, name/*:string*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels); | ||||
| } | ||||
| 
 | ||||
| // eslint-disable-next-line no-unused-vars
 | ||||
| function write_cs(data/*:number*/, name/*:string*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels); | ||||
| } | ||||
| 
 | ||||
| function write_sty(data, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts); | ||||
| } | ||||
| 
 | ||||
| function write_sst(data/*:SST*/, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts); | ||||
| } | ||||
| 
 | ||||
| function write_cmnt(data/*:Array<any>*/, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts); | ||||
| } | ||||
| /* | ||||
| function write_cc(data, name:string, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts); | ||||
| } | ||||
| */ | ||||
|  | ||||
							
								
								
									
										195
									
								
								bits/75_xlml.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										195
									
								
								bits/75_xlml.js
									
									
									
									
									
								
							| @ -1,5 +1,5 @@ | ||||
| var attregexg2=/\b((?:\w+:)?[\w]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g; | ||||
| var attregex2=/\b((?:\w+:)?[\w]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/; | ||||
| var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g; | ||||
| var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/; | ||||
| function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) { | ||||
| 	var words = tag.split(/\s+/); | ||||
| 	var z/*:any*/ = ([]/*:any*/); if(!skip_root) z[0] = words[0]; | ||||
| @ -37,13 +37,10 @@ function xlml_parsexmltagobj(tag/*:string*/) { | ||||
| 
 | ||||
| // ----
 | ||||
| 
 | ||||
| /* map from xlml named formats to SSF TODO: localize */ | ||||
| var XLMLFormatMap/*: {[string]:string}*/; | ||||
| 
 | ||||
| function xlml_format(format, value, date1904)/*:string*/ { | ||||
| function xlml_format(format, value)/*:string*/ { | ||||
| 	var fmt = XLMLFormatMap[format] || unescapexml(format); | ||||
| 	if(fmt === "General") return SSF_general(value); | ||||
| 	return SSF_format(fmt, value, {date1904: !!date1904}); | ||||
| 	if(fmt === "General") return SSF._general(value); | ||||
| 	return SSF.format(fmt, value); | ||||
| } | ||||
| 
 | ||||
| function xlml_set_custprop(Custprops, key, cp, val/*:string*/) { | ||||
| @ -59,24 +56,24 @@ function xlml_set_custprop(Custprops, key, cp, val/*:string*/) { | ||||
| 	Custprops[unescapexml(key)] = oval; | ||||
| } | ||||
| 
 | ||||
| function safe_format_xlml(cell/*:Cell*/, nf, o, date1904) { | ||||
| function safe_format_xlml(cell/*:Cell*/, nf, o) { | ||||
| 	if(cell.t === 'z') return; | ||||
| 	if(!o || o.cellText !== false) try { | ||||
| 		if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; } | ||||
| 		else if(nf === "General") { | ||||
| 			if(cell.t === 'n') { | ||||
| 				if((cell.v|0) === cell.v) cell.w = cell.v.toString(10); | ||||
| 				else cell.w = SSF_general_num(cell.v); | ||||
| 				if((cell.v|0) === cell.v) cell.w = SSF._general_int(cell.v); | ||||
| 				else cell.w = SSF._general_num(cell.v); | ||||
| 			} | ||||
| 			else cell.w = SSF_general(cell.v); | ||||
| 			else cell.w = SSF._general(cell.v); | ||||
| 		} | ||||
| 		else cell.w = xlml_format(nf||"General", cell.v, date1904); | ||||
| 		else cell.w = xlml_format(nf||"General", cell.v); | ||||
| 	} catch(e) { if(o.WTF) throw e; } | ||||
| 	try { | ||||
| 		var z = XLMLFormatMap[nf]||nf||"General"; | ||||
| 		if(o.cellNF) cell.z = z; | ||||
| 		if(o.cellDates && cell.t == 'n' && fmt_is_date(z)) { | ||||
| 			var _d = SSF_parse_date_code(cell.v + (date1904 ? 1462 : 0)); if(_d) { cell.t = 'd'; cell.v = new Date(Date.UTC(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u)); } | ||||
| 		if(o.cellDates && cell.t == 'n' && SSF.is_date(z)) { | ||||
| 			var _d = SSF.parse_date_code(cell.v); if(_d) { cell.t = 'd'; cell.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } | ||||
| 		} | ||||
| 	} catch(e) { if(o.WTF) throw e; } | ||||
| } | ||||
| @ -92,18 +89,17 @@ function process_style_xlml(styles, stag, opts) { | ||||
| } | ||||
| 
 | ||||
| /* TODO: there must exist some form of OSP-blessed spec */ | ||||
| function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o, date1904) { | ||||
| function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o) { | ||||
| 	var nf = "General", sid = cell.StyleID, S = {}; o = o || {}; | ||||
| 	var interiors = []; | ||||
| 	var i = 0; | ||||
| 	if(sid === undefined && row) sid = row.StyleID; | ||||
| 	if(sid === undefined && csty) sid = csty.StyleID; | ||||
| 	while(styles[sid] !== undefined) { | ||||
| 		var ssid = styles[sid]; | ||||
| 		if(ssid.nf) nf = ssid.nf; | ||||
| 		if(ssid.Interior) interiors.push(ssid.Interior); | ||||
| 		if(!ssid.Parent) break; | ||||
| 		sid = ssid.Parent; | ||||
| 		if(styles[sid].nf) nf = styles[sid].nf; | ||||
| 		if(styles[sid].Interior) interiors.push(styles[sid].Interior); | ||||
| 		if(!styles[sid].Parent) break; | ||||
| 		sid = styles[sid].Parent; | ||||
| 	} | ||||
| 	switch(data.Type) { | ||||
| 		case 'Boolean': | ||||
| @ -112,12 +108,13 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a | ||||
| 			break; | ||||
| 		case 'String': | ||||
| 			cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml)); | ||||
| 			cell.v = (xml.indexOf("<") > -1 ? unescapexml(ss||xml).replace(/<[^<>]*>/g, "") : cell.r); // todo: BR etc
 | ||||
| 			cell.v = (xml.indexOf("<") > -1 ? unescapexml(ss||xml).replace(/<.*?>/g, "") : cell.r); // todo: BR etc
 | ||||
| 			break; | ||||
| 		case 'DateTime': | ||||
| 			if(xml.slice(-1) != "Z") xml += "Z"; | ||||
| 			cell.v = datenum(parseDate(xml, date1904), date1904); | ||||
| 			cell.v = (parseDate(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); | ||||
| 			if(cell.v !== cell.v) cell.v = unescapexml(xml); | ||||
| 			else if(cell.v<60) cell.v = cell.v -1; | ||||
| 			if(!nf || nf == "General") nf = "yyyy-mm-dd"; | ||||
| 			/* falls through */ | ||||
| 		case 'Number': | ||||
| @ -130,7 +127,7 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a | ||||
| 			else { cell.t = 's'; cell.v = xlml_fixstr(ss||xml); } | ||||
| 			break; | ||||
| 	} | ||||
| 	safe_format_xlml(cell, nf, o, date1904); | ||||
| 	safe_format_xlml(cell, nf, o); | ||||
| 	if(o.cellFormula !== false) { | ||||
| 		if(cell.Formula) { | ||||
| 			var fstr = unescapexml(cell.Formula); | ||||
| @ -159,56 +156,40 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a | ||||
| 	if(cell.StyleID !== undefined) cell.ixfe = cell.StyleID; | ||||
| } | ||||
| 
 | ||||
| function xlml_prefix_dname(dname) { | ||||
| 	return XLSLblBuiltIn.indexOf("_xlnm." + dname) > -1 ? "_xlnm." + dname : dname; | ||||
| } | ||||
| 
 | ||||
| function xlml_clean_comment(comment/*:any*/) { | ||||
| 	comment.t = comment.v || ""; | ||||
| 	comment.t = comment.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"); | ||||
| 	comment.v = comment.w = comment.ixfe = undefined; | ||||
| } | ||||
| 
 | ||||
| function xlml_normalize(d)/*:string*/ { | ||||
| 	if(has_buf &&/*::typeof Buffer !== "undefined" && d != null && d instanceof Buffer &&*/ Buffer.isBuffer(d)) return d.toString('utf8'); | ||||
| 	if(typeof d === 'string') return d; | ||||
| 	/* duktape */ | ||||
| 	if(typeof Uint8Array !== 'undefined' && d instanceof Uint8Array) return utf8read(a2s(ab2a(d))); | ||||
| 	throw new Error("Bad input format: expected Buffer or string"); | ||||
| } | ||||
| 
 | ||||
| /* TODO: Everything */ | ||||
| /* UOS uses CJK in tags */ | ||||
| var xlmlregex = /<(\/?)([^\s?><!\/:]*:|)([^\s?<>:\/]+)(?:[\s?:\/][^>]*)?>/mg; | ||||
| //var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
 | ||||
| function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 	var opts = _opts || {}; | ||||
| 	make_ssf(); | ||||
| 	make_ssf(SSF); | ||||
| 	var str = debom(xlml_normalize(d)); | ||||
| 	if(opts.type == 'binary' || opts.type == 'array' || opts.type == 'base64') { | ||||
| 		if(typeof $cptable !== 'undefined') str = $cptable.utils.decode(65001, char_codes(str)); | ||||
| 		if(typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str)); | ||||
| 		else str = utf8read(str); | ||||
| 	} | ||||
| 	var opening = str.slice(0, 1024).toLowerCase(), ishtml = false; | ||||
| 	opening = opening.replace(/".*?"/g, ""); | ||||
| 	if((opening.indexOf(">") & 1023) > Math.min((opening.indexOf(",") & 1023), (opening.indexOf(";")&1023))) { var _o = dup(opts); _o.type = "string"; return PRN.to_workbook(str, _o); } | ||||
| 	if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; }); | ||||
| 	if(ishtml) return html_to_workbook(str, opts); | ||||
| 
 | ||||
| 	XLMLFormatMap = ({ | ||||
| 		"General Number": "General", | ||||
| 		"General Date": table_fmt[22], | ||||
| 		"Long Date": "dddd, mmmm dd, yyyy", | ||||
| 		"Medium Date": table_fmt[15], | ||||
| 		"Short Date": table_fmt[14], | ||||
| 		"Long Time": table_fmt[19], | ||||
| 		"Medium Time": table_fmt[18], | ||||
| 		"Short Time": table_fmt[20], | ||||
| 		"Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)', | ||||
| 		"Fixed": table_fmt[2], | ||||
| 		"Standard": table_fmt[4], | ||||
| 		"Percent": table_fmt[10], | ||||
| 		"Scientific": table_fmt[11], | ||||
| 		"Yes/No": '"Yes";"Yes";"No";@', | ||||
| 		"True/False": '"True";"True";"False";@', | ||||
| 		"On/Off": '"Yes";"Yes";"No";@' | ||||
| 	}/*:any*/); | ||||
| 
 | ||||
| 
 | ||||
| 	if(ishtml) return HTML_.to_workbook(str, opts); | ||||
| 	var Rn; | ||||
| 	var state = [], tmp; | ||||
| 	if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| 	var sheets = {}, sheetnames/*:Array<string>*/ = [], cursheet/*:Worksheet*/ = ({}), sheetname = ""; if(opts.dense) cursheet["!data"] = []; | ||||
| 	var cell = ({}/*:any*/), row = {};// eslint-disable-line no-unused-vars
 | ||||
| 	var sheets = {}, sheetnames/*:Array<string>*/ = [], cursheet/*:Worksheet*/ = (opts.dense ? [] : {}), sheetname = ""; | ||||
| 	var table = {}, cell = ({}/*:any*/), row = {};// eslint-disable-line no-unused-vars
 | ||||
| 	var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0; | ||||
| 	var c = 0, r = 0; | ||||
| 	var refguess/*:Range*/ = {s: {r:2000000, c:2000000}, e: {r:0, c:0} }; | ||||
| @ -222,7 +203,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 	var rowinfo/*:Array<RowInfo>*/ = [], rowobj = {}, cc = 0, rr = 0; | ||||
| 	var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false} }/*:any*/), wsprops = {}; | ||||
| 	xlmlregex.lastIndex = 0; | ||||
| 	str = str_remove_ng(str, "<!--", "-->"); | ||||
| 	str = str.replace(/<!--([\s\S]*?)-->/mg,""); | ||||
| 	var raw_Rn3 = ""; | ||||
| 	while((Rn = xlmlregex.exec(str))) switch((Rn[3] = (raw_Rn3 = Rn[3]).toLowerCase())) { | ||||
| 		case 'data' /*case 'Data'*/: | ||||
| @ -232,27 +213,27 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 				break; | ||||
| 			} | ||||
| 			if(state[state.length-1][1]) break; | ||||
| 			if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]==/*"Comment"*/"comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, arrayf, opts, Workbook.WBProps.date1904); | ||||
| 			if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]==/*"Comment"*/"comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, arrayf, opts); | ||||
| 			else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; } | ||||
| 			break; | ||||
| 		case 'cell' /*case 'Cell'*/: | ||||
| 			if(Rn[1]==='/'){ | ||||
| 				if(comments.length > 0) cell.c = comments; | ||||
| 				if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== void 0) { | ||||
| 				if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) { | ||||
| 					if(opts.dense) { | ||||
| 						if(!cursheet["!data"][r]) cursheet["!data"][r] = []; | ||||
| 						cursheet["!data"][r][c] = cell; | ||||
| 						if(!cursheet[r]) cursheet[r] = []; | ||||
| 						cursheet[r][c] = cell; | ||||
| 					} else cursheet[encode_col(c) + encode_row(r)] = cell; | ||||
| 				} | ||||
| 				if(cell.HRef) { | ||||
| 					cell.l = ({Target:unescapexml(cell.HRef)}/*:any*/); | ||||
| 					cell.l = ({Target:cell.HRef}/*:any*/); | ||||
| 					if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip; | ||||
| 					delete cell.HRef; delete cell.HRefScreenTip; | ||||
| 				} | ||||
| 				if(cell.MergeAcross || cell.MergeDown) { | ||||
| 					cc = c + (parseInt(cell.MergeAcross,10)|0); | ||||
| 					rr = r + (parseInt(cell.MergeDown,10)|0); | ||||
| 					if(cc > c || rr > r) merges.push({s:{c:c,r:r},e:{c:cc,r:rr}}); | ||||
| 					merges.push({s:{c:c,r:r},e:{c:cc,r:rr}}); | ||||
| 				} | ||||
| 				if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; } | ||||
| 				else if(cell.MergeAcross || cell.MergeDown) { | ||||
| @ -261,8 +242,8 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 						for(var cmd = r; cmd <= rr; ++cmd) { | ||||
| 							if(cma > c || cmd > r) { | ||||
| 								if(opts.dense) { | ||||
| 									if(!cursheet["!data"][cmd]) cursheet["!data"][cmd] = []; | ||||
| 									cursheet["!data"][cmd][cma] = {t:'z'}; | ||||
| 									if(!cursheet[cmd]) cursheet[cmd] = []; | ||||
| 									cursheet[cmd][cma] = {t:'z'}; | ||||
| 								} else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'}; | ||||
| 							} | ||||
| 						} | ||||
| @ -321,7 +302,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 				state.push([Rn[3], false]); | ||||
| 				tmp = xlml_parsexmltag(Rn[0]); | ||||
| 				sheetname = unescapexml(tmp.Name); | ||||
| 				cursheet = ({}); if(opts.dense) cursheet["!data"] = []; | ||||
| 				cursheet = (opts.dense ? [] : {}); | ||||
| 				merges = []; | ||||
| 				arrayf = []; | ||||
| 				rowinfo = []; | ||||
| @ -333,6 +314,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));} | ||||
| 			else if(Rn[0].slice(-2) == "/>") break; | ||||
| 			else { | ||||
| 				table = xlml_parsexmltag(Rn[0]); | ||||
| 				state.push([Rn[3], false]); | ||||
| 				cstys = []; seencol = false; | ||||
| 			} | ||||
| @ -346,13 +328,12 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 		case 'numberformat' /*case 'NumberFormat'*/: | ||||
| 			stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General"); | ||||
| 			if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf]; | ||||
| 			for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(table_fmt[ssfidx] == stag.nf) break; | ||||
| 			if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(table_fmt[ssfidx] == null) { SSF__load(stag.nf, ssfidx); break; } | ||||
| 			for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break; | ||||
| 			if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; } | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'column' /*case 'Column'*/: | ||||
| 			if(state[state.length-1][0] !== /*'Table'*/'table') break; | ||||
| 			if(Rn[1]==='/') break; | ||||
| 			csty = xlml_parsexmltag(Rn[0]); | ||||
| 			if(csty.Hidden) { csty.hidden = true; delete csty.Hidden; } | ||||
| 			if(csty.Width) csty.wpx = parseInt(csty.Width, 10); | ||||
| @ -370,7 +351,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 			if(!Workbook.Names) Workbook.Names = []; | ||||
| 			var _NamedRange = parsexmltag(Rn[0]); | ||||
| 			var _DefinedName/*:DefinedName*/ = ({ | ||||
| 				Name: xlml_prefix_dname(_NamedRange.Name), | ||||
| 				Name: _NamedRange.Name, | ||||
| 				Ref: rc_to_a1(_NamedRange.RefersTo.slice(1), {r:0, c:0}) | ||||
| 			}/*:any*/); | ||||
| 			if(Workbook.Sheets.length>0) _DefinedName.Sheet=Workbook.Sheets.length-1; | ||||
| @ -443,7 +424,6 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 			} else { | ||||
| 				state.push([Rn[3], false]); | ||||
| 				tmp = xlml_parsexmltag(Rn[0]); | ||||
| 				if(!parsexmlbool(tmp["ShowAlways"]||"0")) comments.hidden = true; | ||||
| 				comment = ({a:tmp.Author}/*:any*/); | ||||
| 			} | ||||
| 			break; | ||||
| @ -491,8 +471,6 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 			else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]); | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'null' /*case 'Null'*/: break; | ||||
| 
 | ||||
| 		default: | ||||
| 			/* FODS file root is <office:document> */ | ||||
| 			if(state.length == 0 && Rn[3] == "document") return parse_fods(str, opts); | ||||
| @ -535,9 +513,6 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 						/*:: if(!Workbook.WBProps) Workbook.WBProps = {}; */ | ||||
| 						Workbook.WBProps.date1904 = true; | ||||
| 						break; | ||||
| 					case 'hidehorizontalscrollbar' /*case 'HideHorizontalScrollBar'*/: break; | ||||
| 					case 'hideverticalscrollbar' /*case 'HideVerticalScrollBar'*/: break; | ||||
| 					case 'hideworkbooktabs' /*case 'HideWorkbookTabs'*/: break; | ||||
| 					case 'windowheight' /*case 'WindowHeight'*/: break; | ||||
| 					case 'windowwidth' /*case 'WindowWidth'*/: break; | ||||
| 					case 'windowtopx' /*case 'WindowTopX'*/: break; | ||||
| @ -606,19 +581,19 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 						break; | ||||
| 					case 'header' /*case 'Header'*/: | ||||
| 						if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml'); | ||||
| 						if(!isNaN(+parsexmltag(Rn[0]).Margin)) cursheet['!margins'].header = +parsexmltag(Rn[0]).Margin; | ||||
| 						cursheet['!margins'].header = parsexmltag(Rn[0]).Margin; | ||||
| 						break; | ||||
| 					case 'footer' /*case 'Footer'*/: | ||||
| 						if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml'); | ||||
| 						if(!isNaN(+parsexmltag(Rn[0]).Margin)) cursheet['!margins'].footer = +parsexmltag(Rn[0]).Margin; | ||||
| 						cursheet['!margins'].footer = parsexmltag(Rn[0]).Margin; | ||||
| 						break; | ||||
| 					case 'pagemargins' /*case 'PageMargins'*/: | ||||
| 						var pagemargins = parsexmltag(Rn[0]); | ||||
| 						if(!cursheet['!margins']) default_margins(cursheet['!margins']={},'xlml'); | ||||
| 						if(!isNaN(+pagemargins.Top)) cursheet['!margins'].top = +pagemargins.Top; | ||||
| 						if(!isNaN(+pagemargins.Left)) cursheet['!margins'].left = +pagemargins.Left; | ||||
| 						if(!isNaN(+pagemargins.Right)) cursheet['!margins'].right = +pagemargins.Right; | ||||
| 						if(!isNaN(+pagemargins.Bottom)) cursheet['!margins'].bottom = +pagemargins.Bottom; | ||||
| 						if(pagemargins.Top) cursheet['!margins'].top = pagemargins.Top; | ||||
| 						if(pagemargins.Left) cursheet['!margins'].left = pagemargins.Left; | ||||
| 						if(pagemargins.Right) cursheet['!margins'].right = pagemargins.Right; | ||||
| 						if(pagemargins.Bottom) cursheet['!margins'].bottom = pagemargins.Bottom; | ||||
| 						break; | ||||
| 					case 'displayrighttoleft' /*case 'DisplayRightToLeft'*/: | ||||
| 						if(!Workbook.Views) Workbook.Views = []; | ||||
| @ -643,7 +618,6 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 
 | ||||
| 					case 'unsynced' /*case 'Unsynced'*/: break; | ||||
| 					case 'print' /*case 'Print'*/: break; | ||||
| 					case 'printerrors' /*case 'PrintErrors'*/: break; | ||||
| 					case 'panes' /*case 'Panes'*/: break; | ||||
| 					case 'scale' /*case 'Scale'*/: break; | ||||
| 					case 'pane' /*case 'Pane'*/: break; | ||||
| @ -683,17 +657,11 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 					case 'allowformatcells' /*case 'AllowFormatCells'*/: break; | ||||
| 					case 'allowsizecols' /*case 'AllowSizeCols'*/: break; | ||||
| 					case 'allowsizerows' /*case 'AllowSizeRows'*/: break; | ||||
| 					case 'nosummaryrowsbelowdetail' /*case 'NoSummaryRowsBelowDetail'*/: | ||||
| 						if(!cursheet["!outline"]) cursheet["!outline"] = {}; | ||||
| 						cursheet["!outline"].above = true; | ||||
| 						break; | ||||
| 					case 'nosummaryrowsbelowdetail' /*case 'NoSummaryRowsBelowDetail'*/: break; | ||||
| 					case 'tabcolorindex' /*case 'TabColorIndex'*/: break; | ||||
| 					case 'donotdisplayheadings' /*case 'DoNotDisplayHeadings'*/: break; | ||||
| 					case 'showpagelayoutzoom' /*case 'ShowPageLayoutZoom'*/: break; | ||||
| 					case 'nosummarycolumnsrightdetail' /*case 'NoSummaryColumnsRightDetail'*/: | ||||
| 						if(!cursheet["!outline"]) cursheet["!outline"] = {}; | ||||
| 						cursheet["!outline"].left = true; | ||||
| 						break; | ||||
| 					case 'nosummarycolumnsrightdetail' /*case 'NoSummaryColumnsRightDetail'*/: break; | ||||
| 					case 'blackandwhite' /*case 'BlackAndWhite'*/: break; | ||||
| 					case 'donotdisplayzeros' /*case 'DoNotDisplayZeros'*/: break; | ||||
| 					case 'displaypagebreak' /*case 'DisplayPageBreak'*/: break; | ||||
| @ -920,17 +888,16 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 	if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets; | ||||
| 	out.SheetNames = sheetnames; | ||||
| 	out.Workbook = Workbook; | ||||
| 	out.SSF = dup(table_fmt); | ||||
| 	out.SSF = SSF.get_table(); | ||||
| 	out.Props = Props; | ||||
| 	out.Custprops = Custprops; | ||||
| 	out.bookType = "xlml"; | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| function parse_xlml(data/*:RawBytes|string*/, opts)/*:Workbook*/ { | ||||
| 	fix_read_opts(opts=opts||{}); | ||||
| 	switch(opts.type||"base64") { | ||||
| 		case "base64": return parse_xlml_xml(Base64_decode(data), opts); | ||||
| 		case "base64": return parse_xlml_xml(Base64.decode(data), opts); | ||||
| 		case "binary": case "buffer": case "file": return parse_xlml_xml(data, opts); | ||||
| 		case "array": return parse_xlml_xml(a2s(data), opts); | ||||
| 	} | ||||
| @ -947,10 +914,9 @@ function write_props_xlml(wb/*:Workbook*/, opts)/*:string*/ { | ||||
| 	return o.join(""); | ||||
| } | ||||
| /* TODO */ | ||||
| function write_wb_xlml(wb/*::, opts*/)/*:string*/ { | ||||
| function write_wb_xlml(/*::wb, opts*/)/*:string*/ { | ||||
| 	/* OfficeDocumentSettings */ | ||||
| 	/* ExcelWorkbook */ | ||||
| 	if((((wb||{}).Workbook||{}).WBProps||{}).date1904) return '<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel"><Date1904/></ExcelWorkbook>'; | ||||
| 	return ""; | ||||
| } | ||||
| /* TODO */ | ||||
| @ -959,14 +925,14 @@ function write_sty_xlml(wb, opts)/*:string*/ { | ||||
| 	var styles/*:Array<string>*/ = ['<Style ss:ID="Default" ss:Name="Normal"><NumberFormat/></Style>']; | ||||
| 	opts.cellXfs.forEach(function(xf, id) { | ||||
| 		var payload/*:Array<string>*/ = []; | ||||
| 		payload.push(writextag('NumberFormat', null, {"ss:Format": escapexml(table_fmt[xf.numFmtId])})); | ||||
| 		payload.push(writextag('NumberFormat', null, {"ss:Format": escapexml(SSF._table[xf.numFmtId])})); | ||||
| 
 | ||||
| 		var o = /*::(*/{"ss:ID": "s" + (21+id)}/*:: :any)*/; | ||||
| 		styles.push(writextag('Style', payload.join(""), o)); | ||||
| 	}); | ||||
| 	return writextag("Styles", styles.join("")); | ||||
| } | ||||
| function write_name_xlml(n) { return writextag("NamedRange", null, {"ss:Name": n.Name.slice(0,6) == "_xlnm." ? n.Name.slice(6) : n.Name, "ss:RefersTo":"=" + a1_to_rc(n.Ref, {r:0,c:0})}); } | ||||
| function write_name_xlml(n) { return writextag("NamedRange", null, {"ss:Name": n.Name, "ss:RefersTo":"=" + a1_to_rc(n.Ref, {r:0,c:0})}); } | ||||
| function write_names_xlml(wb/*::, opts*/)/*:string*/ { | ||||
| 	if(!((wb||{}).Workbook||{}).Names) return ""; | ||||
| 	/*:: if(!wb || !wb.Workbook || !wb.Workbook.Names) throw new Error("unreachable"); */ | ||||
| @ -1106,15 +1072,11 @@ function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workb | ||||
| 	return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x}); | ||||
| } | ||||
| function write_ws_xlml_comment(comments/*:Array<any>*/)/*:string*/ { | ||||
| 	/* TODO: test multiple comments */ | ||||
| 	return comments.map(function(c) { | ||||
| 		// TODO: formatted text
 | ||||
| 		var t = xlml_unfixstr(c.t||""); | ||||
| 		var d =writextag("ss:Data", t, {"xmlns":"http://www.w3.org/TR/REC-html40"}); | ||||
| 		var p = {}; | ||||
| 		if(c.a) p["ss:Author"] = c.a; | ||||
| 		if(!comments.hidden) p["ss:ShowAlways"] = "1"; | ||||
| 		return writextag("Comment", d, p); | ||||
| 		return writextag("Comment", d, {"ss:Author":c.a}); | ||||
| 	}).join(""); | ||||
| } | ||||
| function write_ws_xlml_cell(cell, ref/*:string*/, ws, opts, idx/*:number*/, wb, addr)/*:string*/{ | ||||
| @ -1144,16 +1106,10 @@ function write_ws_xlml_cell(cell, ref/*:string*/, ws, opts, idx/*:number*/, wb, | ||||
| 	var t = "", p = ""; | ||||
| 	switch(cell.t) { | ||||
| 		case 'z': if(!opts.sheetStubs) return ""; break; | ||||
| 		case 'n': { | ||||
| 			if(!isFinite(cell.v)) { | ||||
| 				t = 'Error'; p = BErr[isNaN(cell.v) ? 0x24 : 0x07]; | ||||
| 			} else { | ||||
| 				t = 'Number'; p = String(cell.v); | ||||
| 			} | ||||
| 		} break; | ||||
| 		case 'n': t = 'Number'; p = String(cell.v); break; | ||||
| 		case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break; | ||||
| 		case 'e': t = 'Error'; p = BErr[cell.v]; break; | ||||
| 		case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); if(cell.z == null) cell.z = cell.z || table_fmt[14]; break; | ||||
| 		case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); if(cell.z == null) cell.z = cell.z || SSF._table[14]; break; | ||||
| 		case 's': t = 'String'; p = escapexlml(cell.v||""); break; | ||||
| 	} | ||||
| 	/* TODO: cell style */ | ||||
| @ -1191,13 +1147,10 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo | ||||
| 		if(n.hidden) k['ss:Hidden']="1"; | ||||
| 		o.push(writextag("Column",null,k)); | ||||
| 	}); | ||||
| 	var dense = ws["!data"] != null; | ||||
| 	var addr = {r:0,c:0}; | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])]; | ||||
| 		addr.r = R; | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			addr.c = C; | ||||
| 			var skip = false; | ||||
| 			for(mi = 0; mi != marr.length; ++mi) { | ||||
| 				if(marr[mi].s.c > C) continue; | ||||
| @ -1208,7 +1161,8 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo | ||||
| 				break; | ||||
| 			} | ||||
| 			if(skip) continue; | ||||
| 			var ref = encode_col(C) + encode_row(R), cell = dense ? (ws["!data"][R]||[])[C] : ws[ref]; | ||||
| 			var addr = {r:R,c:C}; | ||||
| 			var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref]; | ||||
| 			row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)); | ||||
| 		} | ||||
| 		row.push("</Row>"); | ||||
| @ -1231,15 +1185,13 @@ function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ { | ||||
| 	/* WorksheetOptions */ | ||||
| 	o.push(write_ws_xlml_wsopts(ws, opts, idx, wb)); | ||||
| 
 | ||||
| 	if(ws && ws["!autofilter"]) o.push('<AutoFilter x:Range="' + a1_to_rc(fix_range(ws["!autofilter"].ref), {r:0,c:0}) + '" xmlns="urn:schemas-microsoft-com:office:excel"></AutoFilter>'); | ||||
| 
 | ||||
| 	return o.join(""); | ||||
| } | ||||
| function write_xlml(wb, opts)/*:string*/ { | ||||
| 	if(!opts) opts = {}; | ||||
| 	if(!wb.SSF) wb.SSF = dup(table_fmt); | ||||
| 	if(!wb.SSF) wb.SSF = SSF.get_table(); | ||||
| 	if(wb.SSF) { | ||||
| 		make_ssf(); SSF_load_table(wb.SSF); | ||||
| 		make_ssf(SSF); SSF.load_table(wb.SSF); | ||||
| 		// $FlowIgnore
 | ||||
| 		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0; | ||||
| 		opts.ssf = wb.SSF; | ||||
| @ -1250,10 +1202,11 @@ function write_xlml(wb, opts)/*:string*/ { | ||||
| 	d.push(write_props_xlml(wb, opts)); | ||||
| 	d.push(write_wb_xlml(wb, opts)); | ||||
| 	d.push(""); | ||||
| 	d.push(write_names_xlml(wb, opts)); | ||||
| 	d.push(""); | ||||
| 	for(var i = 0; i < wb.SheetNames.length; ++i) | ||||
| 		d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])})); | ||||
| 	d[2] = write_sty_xlml(wb, opts); | ||||
| 	d[3] = write_names_xlml(wb, opts); | ||||
| 	return XML_HEADER + writextag("Workbook", d.join(""), { | ||||
| 		'xmlns':      XLMLNS.ss, | ||||
| 		'xmlns:o':    XLMLNS.o, | ||||
|  | ||||
							
								
								
									
										620
									
								
								bits/76_xls.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										620
									
								
								bits/76_xls.js
									
									
									
									
									
								
							| @ -28,46 +28,45 @@ function parse_compobj(obj/*:CFBEntry*/) { | ||||
| 
 | ||||
| /* | ||||
| 	Continue logic for: | ||||
| 	- 2.4.58 Continue          0x003c | ||||
| 	- 2.4.59 ContinueBigName   0x043c | ||||
| 	- 2.4.60 ContinueFrt       0x0812 | ||||
| 	- 2.4.61 ContinueFrt11     0x0875 | ||||
| 	- 2.4.62 ContinueFrt12     0x087f | ||||
| 	- 2.4.58 Continue | ||||
| 	- 2.4.59 ContinueBigName | ||||
| 	- 2.4.60 ContinueFrt | ||||
| 	- 2.4.61 ContinueFrt11 | ||||
| 	- 2.4.62 ContinueFrt12 | ||||
| */ | ||||
| var CONTINUE_RT = [ 0x003c, 0x043c, 0x0812, 0x0875, 0x087f ]; | ||||
| function slurp(RecordType, R, blob, length/*:number*/, opts)/*:any*/ { | ||||
| function slurp(R, blob, length/*:number*/, opts)/*:any*/ { | ||||
| 	var l = length; | ||||
| 	var bufs = []; | ||||
| 	var d = blob.slice(blob.l,blob.l+l); | ||||
| 	if(opts && opts.enc && opts.enc.insitu && d.length > 0) switch(RecordType) { | ||||
| 	case 0x0009: case 0x0209: case 0x0409: case 0x0809/* BOF */: case 0x002F /* FilePass */: case 0x0195 /* FileLock */: case 0x00E1 /* InterfaceHdr */: case 0x0196 /* RRDInfo */: case 0x0138 /* RRDHead */: case 0x0194 /* UsrExcl */: case 0x000a /* EOF */: | ||||
| 	if(opts && opts.enc && opts.enc.insitu && d.length > 0) switch(R.n) { | ||||
| 	case 'BOF': case 'FilePass': case 'FileLock': case 'InterfaceHdr': case 'RRDInfo': case 'RRDHead': case 'UsrExcl': case 'EOF': | ||||
| 		break; | ||||
| 	case 0x0085 /* BoundSheet8 */: | ||||
| 	case 'BoundSheet8': | ||||
| 		break; | ||||
| 	default: | ||||
| 		opts.enc.insitu(d); | ||||
| 	} | ||||
| 	bufs.push(d); | ||||
| 	blob.l += l; | ||||
| 	var nextrt = __readUInt16LE(blob,blob.l), next = XLSRecordEnum[nextrt]; | ||||
| 	var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]); | ||||
| 	var start = 0; | ||||
| 	while(next != null && CONTINUE_RT.indexOf(nextrt) > -1) { | ||||
| 	while(next != null && next.n.slice(0,8) === 'Continue') { | ||||
| 		l = __readUInt16LE(blob,blob.l+2); | ||||
| 		start = blob.l + 4; | ||||
| 		if(nextrt == 0x0812 /* ContinueFrt */) start += 4; | ||||
| 		else if(nextrt == 0x0875 || nextrt == 0x087f) { | ||||
| 		if(next.n == 'ContinueFrt') start += 4; | ||||
| 		else if(next.n.slice(0,11) == 'ContinueFrt') { | ||||
| 			start += 12; | ||||
| 		} | ||||
| 		d = blob.slice(start,blob.l+4+l); | ||||
| 		bufs.push(d); | ||||
| 		blob.l += 4+l; | ||||
| 		next = (XLSRecordEnum[nextrt = __readUInt16LE(blob, blob.l)]); | ||||
| 		next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]); | ||||
| 	} | ||||
| 	var b = (bconcat(bufs)/*:any*/); | ||||
| 	prep_blob(b, 0); | ||||
| 	var ll = 0; b.lens = []; | ||||
| 	for(var j = 0; j < bufs.length; ++j) { b.lens.push(ll); ll += bufs[j].length; } | ||||
| 	if(b.length < length) throw "XLS Record 0x" + RecordType.toString(16) + " Truncated: " + b.length + " < " + length; | ||||
| 	if(b.length < length) throw "XLS Record " + (R && R.n || "??") + " Truncated: " + b.length + " < " + length; | ||||
| 	return R.f(b, b.length, opts); | ||||
| } | ||||
| 
 | ||||
| @ -77,21 +76,21 @@ function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) { | ||||
| 	var fmtid = 0; | ||||
| 	try { | ||||
| 		fmtid = p.z || p.XF.numFmtId || 0; | ||||
| 		if(opts.cellNF && p.z == null) p.z = table_fmt[fmtid]; | ||||
| 		if(opts.cellNF) p.z = SSF._table[fmtid]; | ||||
| 	} catch(e) { if(opts.WTF) throw e; } | ||||
| 	if(!opts || opts.cellText !== false) try { | ||||
| 		if(p.t === 'e') { p.w = p.w || BErr[p.v]; } | ||||
| 		else if(fmtid === 0 || fmtid == "General") { | ||||
| 			if(p.t === 'n') { | ||||
| 				if((p.v|0) === p.v) p.w = p.v.toString(10); | ||||
| 				else p.w = SSF_general_num(p.v); | ||||
| 				if((p.v|0) === p.v) p.w = SSF._general_int(p.v); | ||||
| 				else p.w = SSF._general_num(p.v); | ||||
| 			} | ||||
| 			else p.w = SSF_general(p.v); | ||||
| 			else p.w = SSF._general(p.v); | ||||
| 		} | ||||
| 		else p.w = SSF_format(fmtid,p.v, {date1904:!!date1904, dateNF: opts && opts.dateNF}); | ||||
| 		else p.w = SSF.format(fmtid,p.v, {date1904:!!date1904}); | ||||
| 	} catch(e) { if(opts.WTF) throw e; } | ||||
| 	if(opts.cellDates && fmtid && p.t == 'n' && fmt_is_date(table_fmt[fmtid] || String(fmtid))) { | ||||
| 		var _d = SSF_parse_date_code(p.v + (date1904 ? 1462 : 0)); if(_d) { p.t = 'd'; p.v = new Date(Date.UTC(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u)); } | ||||
| 	if(opts.cellDates && fmtid && p.t == 'n' && SSF.is_date(SSF._table[fmtid] || String(fmtid))) { | ||||
| 		var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -104,7 +103,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var wb = ({opts:{}}/*:any*/); | ||||
| 	var Sheets = {}; | ||||
| 	if(DENSE != null && options.dense == null) options.dense = DENSE; | ||||
| 	var out/*:Worksheet*/ = ({}/*:any*/); if(options.dense) out["!data"] = []; | ||||
| 	var out/*:Worksheet*/ = ((options.dense ? [] : {})/*:any*/); | ||||
| 	var Directory = {}; | ||||
| 	var range/*:Range*/ = ({}/*:any*/); | ||||
| 	var last_formula = null; | ||||
| @ -116,16 +115,16 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var arrayf/*:Array<[Range, string]>*/ = []; | ||||
| 	var temp_val/*:Cell*/; | ||||
| 	var country; | ||||
| 	var cell_valid = true; | ||||
| 	var XFs = []; /* XF records */ | ||||
| 	var palette/*:Array<[number, number, number]>*/ = []; | ||||
| 	var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false}, Views:[{}] }/*:any*/), wsprops = {}; | ||||
| 	var biff4w = false; | ||||
| 	var get_rgb = function getrgb(icv/*:number*/)/*:[number, number, number]*/ { | ||||
| 		if(icv < 8) return XLSIcv[icv]; | ||||
| 		if(icv < 64) return palette[icv-8] || XLSIcv[icv]; | ||||
| 		return XLSIcv[icv]; | ||||
| 	}; | ||||
| 	var process_cell_style = function pcs(line/*:any*/, options) { | ||||
| 	var process_cell_style = function pcs(cell, line/*:any*/, options) { | ||||
| 		var xfd = line.XF.data; | ||||
| 		if(!xfd || !xfd.patternType || !options || !options.cellStyles) return; | ||||
| 		line.s = ({}/*:any*/); | ||||
| @ -135,9 +134,10 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 		if((t = rgb2Hex(get_rgb(xfd.icvBack)))) { line.s.bgColor = {rgb:t}; } | ||||
| 	}; | ||||
| 	var addcell = function addcell(cell/*:any*/, line/*:any*/, options/*:any*/) { | ||||
| 		if(!biff4w && file_depth > 1) return; | ||||
| 		if(options.sheetRows && cell.r >= options.sheetRows) return; | ||||
| 		if(options.cellStyles && line.XF && line.XF.data) process_cell_style(line, options); | ||||
| 		if(file_depth > 1) return; | ||||
| 		if(options.sheetRows && cell.r >= options.sheetRows) cell_valid = false; | ||||
| 		if(!cell_valid) return; | ||||
| 		if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options); | ||||
| 		delete line.ixfe; delete line.XF; | ||||
| 		lastcell = cell; | ||||
| 		last_cell = encode_cell(cell); | ||||
| @ -158,8 +158,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 		} | ||||
| 		{ | ||||
| 			if(options.dense) { | ||||
| 				if(!out["!data"][cell.r]) out["!data"][cell.r] = []; | ||||
| 				out["!data"][cell.r][cell.c] = line; | ||||
| 				if(!out[cell.r]) out[cell.r] = []; | ||||
| 				out[cell.r][cell.c] = line; | ||||
| 			} else out[last_cell] = line; | ||||
| 		} | ||||
| 	}; | ||||
| @ -182,6 +182,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var merges/*:Array<Range>*/ = []; | ||||
| 	var objects = []; | ||||
| 	var colinfo/*:Array<ColInfo>*/ = [], rowinfo/*:Array<RowInfo>*/ = []; | ||||
| 	// eslint-disable-next-line no-unused-vars
 | ||||
| 	var defwidth = 0, defheight = 0; // twips / MDW respectively
 | ||||
| 	var seencol = false; | ||||
| 	var supbooks = ([]/*:any*/); // 1-indexed, will hold extern names
 | ||||
| 	supbooks.SheetNames = opts.snames; | ||||
| @ -189,7 +191,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	supbooks.arrayf = opts.arrayf; | ||||
| 	supbooks.names = []; | ||||
| 	supbooks.XTI = []; | ||||
| 	var last_RT = 0; | ||||
| 	var last_Rn = ''; | ||||
| 	var file_depth = 0; /* TODO: make a real stack */ | ||||
| 	var BIFF2Fmt = 0, BIFF2FmtTable/*:Array<string>*/ = []; | ||||
| 	var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */ | ||||
| @ -202,44 +204,45 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	while(blob.l < blob.length - 1) { | ||||
| 		var s = blob.l; | ||||
| 		var RecordType = blob.read_shift(2); | ||||
| 		if(RecordType === 0 && last_RT === 0x000a /* EOF */) break; | ||||
| 		if(RecordType === 0 && last_Rn === 'EOF') break; | ||||
| 		var length = (blob.l === blob.length ? 0 : blob.read_shift(2)); | ||||
| 		var R = XLSRecordEnum[RecordType]; | ||||
| 		if(file_depth == 0 && [0x0009, 0x0209, 0x0409, 0x0809].indexOf(RecordType) == -1 /* BOF */) break; | ||||
| 		//console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length);
 | ||||
| 		//if(!R) console.log(blob.slice(blob.l, blob.l + length));
 | ||||
| 		if(R && R.f) { | ||||
| 			if(options.bookSheets) { | ||||
| 				if(last_RT === 0x0085 /* BoundSheet8 */ && RecordType !== 0x0085 /* R.n !== 'BoundSheet8' */) break; | ||||
| 				if(last_Rn === 'BoundSheet8' && R.n !== 'BoundSheet8') break; | ||||
| 			} | ||||
| 			last_RT = RecordType; | ||||
| 			last_Rn = R.n; | ||||
| 			if(R.r === 2 || R.r == 12) { | ||||
| 				var rt = blob.read_shift(2); length -= 2; | ||||
| 				if(!opts.enc && rt !== RecordType && (((rt&0xFF)<<8)|(rt>>8)) !== RecordType) throw new Error("rt mismatch: " + rt + "!=" + RecordType); | ||||
| 				if(R.r == 12){ | ||||
| 					blob.l += 10; length -= 10; | ||||
| 				} // skip FRT
 | ||||
| 				if(R.r == 12){ blob.l += 10; length -= 10; } // skip FRT
 | ||||
| 			} | ||||
| 			//console.error(R,blob.l,length,blob.length);
 | ||||
| 			var val/*:any*/ = ({}/*:any*/); | ||||
| 			if(RecordType === 0x000a /* EOF */) val = /*::(*/R.f(blob, length, opts)/*:: :any)*/; | ||||
| 			else val = /*::(*/slurp(RecordType, R, blob, length, opts)/*:: :any)*/; | ||||
| 			if(R.n === 'EOF') val = /*::(*/R.f(blob, length, opts)/*:: :any)*/; | ||||
| 			else val = /*::(*/slurp(R, blob, length, opts)/*:: :any)*/; | ||||
| 			var Rn = R.n; | ||||
| 			/*:: val = (val:any); */ | ||||
| 			if(file_depth == 0 && [0x0009, 0x0209, 0x0409, 0x0809].indexOf(last_RT) === -1 /* BOF */) continue; | ||||
| 			switch(RecordType) { | ||||
| 				case 0x0022 /* Date1904 */: | ||||
| 			if(file_depth == 0 && Rn != 'BOF') continue; | ||||
| 			/* nested switch statements to workaround V8 128 limit */ | ||||
| 			switch(Rn) { | ||||
| 				/* Workbook Options */ | ||||
| 				case 'Date1904': | ||||
| 					/*:: if(!Workbook.WBProps) Workbook.WBProps = {}; */ | ||||
| 					wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break; | ||||
| 				case 0x0086 /* WriteProtect */: wb.opts.WriteProtect = true; break; | ||||
| 				case 0x002f /* FilePass */: | ||||
| 				case 'WriteProtect': wb.opts.WriteProtect = true; break; | ||||
| 				case 'FilePass': | ||||
| 					if(!opts.enc) blob.l = 0; | ||||
| 					opts.enc = val; | ||||
| 					if(!options.password) throw new Error("File is password-protected"); | ||||
| 					if(val.valid == null) throw new Error("Encryption scheme unsupported"); | ||||
| 					if(!val.valid) throw new Error("Password is incorrect"); | ||||
| 					break; | ||||
| 				case 0x005c /* WriteAccess */: opts.lastuser = val; break; | ||||
| 				case 0x0042 /* CodePage */: | ||||
| 				case 'WriteAccess': opts.lastuser = val; break; | ||||
| 				case 'FileSharing': break; //TODO
 | ||||
| 				case 'CodePage': | ||||
| 					var cpval = Number(val); | ||||
| 					/* overrides based on test cases */ | ||||
| 					switch(cpval) { | ||||
| @ -250,33 +253,42 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 					set_cp(opts.codepage = cpval); | ||||
| 					seen_codepage = true; | ||||
| 					break; | ||||
| 				case 0x013d /* RRTabId */: opts.rrtabid = val; break; | ||||
| 				case 0x0019 /* WinProtect */: opts.winlocked = val; break; | ||||
| 				case 0x01b7 /* RefreshAll */: wb.opts["RefreshAll"] = val; break; | ||||
| 				case 0x000c /* CalcCount */: wb.opts["CalcCount"] = val; break; | ||||
| 				case 0x0010 /* CalcDelta */: wb.opts["CalcDelta"] = val; break; | ||||
| 				case 0x0011 /* CalcIter */: wb.opts["CalcIter"] = val; break; | ||||
| 				case 0x000d /* CalcMode */: wb.opts["CalcMode"] = val; break; | ||||
| 				case 0x000e /* CalcPrecision */: wb.opts["CalcPrecision"] = val; break; | ||||
| 				case 0x005f /* CalcSaveRecalc */: wb.opts["CalcSaveRecalc"] = val; break; | ||||
| 				case 0x000f /* CalcRefMode */: opts.CalcRefMode = val; break; // TODO: implement R1C1
 | ||||
| 				case 0x08a3 /* ForceFullCalculation */: wb.opts.FullCalc = val; break; | ||||
| 				case 0x0081 /* WsBool */: | ||||
| 				case 'RRTabId': opts.rrtabid = val; break; | ||||
| 				case 'WinProtect': opts.winlocked = val; break; | ||||
| 				case 'Template': break; // TODO
 | ||||
| 				case 'BookBool': break; // TODO
 | ||||
| 				case 'UsesELFs': break; | ||||
| 				case 'MTRSettings': break; | ||||
| 				case 'RefreshAll': | ||||
| 				case 'CalcCount': | ||||
| 				case 'CalcDelta': | ||||
| 				case 'CalcIter': | ||||
| 				case 'CalcMode': | ||||
| 				case 'CalcPrecision': | ||||
| 				case 'CalcSaveRecalc': | ||||
| 					wb.opts[Rn] = val; break; | ||||
| 				case 'CalcRefMode': opts.CalcRefMode = val; break; // TODO: implement R1C1
 | ||||
| 				case 'Uncalced': break; | ||||
| 				case 'ForceFullCalculation': wb.opts.FullCalc = val; break; | ||||
| 				case 'WsBool': | ||||
| 					if(val.fDialog) out["!type"] = "dialog"; | ||||
| 					if(!val.fBelow) (out["!outline"] || (out["!outline"] = {})).above = true; | ||||
| 					if(!val.fRight) (out["!outline"] || (out["!outline"] = {})).left = true; | ||||
| 					break; // TODO
 | ||||
| 				case 0x0043: /* BIFF2XF */ case 0x0243: /* BIFF3XF */ case 0x0443: /* BIFF4XF */ | ||||
| 				case 0x00e0 /* XF */: | ||||
| 				case 'XF': | ||||
| 					XFs.push(val); break; | ||||
| 				case 0x01ae /* SupBook */: | ||||
| 				case 'ExtSST': break; // TODO
 | ||||
| 				case 'BookExt': break; // TODO
 | ||||
| 				case 'RichTextStream': break; | ||||
| 				case 'BkHim': break; | ||||
| 
 | ||||
| 				case 'SupBook': | ||||
| 					supbooks.push([val]); | ||||
| 					supbooks[supbooks.length-1].XTI = []; | ||||
| 					break; | ||||
| 				case 0x0023: case 0x0223 /* ExternName */: | ||||
| 				case 'ExternName': | ||||
| 					supbooks[supbooks.length-1].push(val); | ||||
| 					break; | ||||
| 				case 0x0018: case 0x0218 /* Lbl */: | ||||
| 				case 'Index': break; // TODO
 | ||||
| 				case 'Lbl': | ||||
| 					last_lbl = ({ | ||||
| 						Name: val.Name, | ||||
| 						Ref: stringify_formula(val.rgce,range,null,supbooks,opts) | ||||
| @ -289,23 +301,26 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d') | ||||
| 							FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) }; | ||||
| 					break; | ||||
| 				case 0x0016 /* ExternCount */: opts.ExternCount = val; break; | ||||
| 				case 0x0017 /* ExternSheet */: | ||||
| 				case 'ExternCount': opts.ExternCount = val; break; | ||||
| 				case 'ExternSheet': | ||||
| 					if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; } | ||||
| 					supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break; | ||||
| 				case 0x0894 /* NameCmt */: | ||||
| 				case 'NameCmt': | ||||
| 					/* TODO: search for correct name */ | ||||
| 					if(opts.biff < 8) break; | ||||
| 					if(last_lbl != null) last_lbl.Comment = val[1]; | ||||
| 					break; | ||||
| 				case 0x0012 /* Protect */: out["!protect"] = val; break; /* for sheet or book */ | ||||
| 				case 0x0013 /* Password */: if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break; | ||||
| 				case 0x0085 /* BoundSheet8 */: { | ||||
| 					Directory[opts.biff == 4 ? opts.snames.length : val.pos] = val; | ||||
| 
 | ||||
| 				case 'Protect': out["!protect"] = val; break; /* for sheet or book */ | ||||
| 				case 'Password': if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break; | ||||
| 				case 'Prot4Rev': case 'Prot4RevPass': break; /*TODO: Revision Control*/ | ||||
| 
 | ||||
| 				case 'BoundSheet8': { | ||||
| 					Directory[val.pos] = val; | ||||
| 					opts.snames.push(val.name); | ||||
| 				} break; | ||||
| 				case 0x000a /* EOF */: { | ||||
| 					if(--file_depth ? !biff4w : biff4w) break; | ||||
| 				case 'EOF': { | ||||
| 					if(--file_depth) break; | ||||
| 					if(range.e) { | ||||
| 						if(range.e.r > 0 && range.e.c > 0) { | ||||
| 							range.e.r--; range.e.c--; | ||||
| @ -326,33 +341,29 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						Workbook.Sheets.push(wsprops); | ||||
| 					} | ||||
| 					if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out; | ||||
| 					out = ({}/*:any*/); if(options.dense) out["!data"] = []; | ||||
| 					out = ((options.dense ? [] : {})/*:any*/); | ||||
| 				} break; | ||||
| 				case 0x0009: case 0x0209: case 0x0409: case 0x0809 /* BOF */: { | ||||
| 				case 'BOF': { | ||||
| 					if(opts.biff === 8) opts.biff = { | ||||
| 						0x0009: 2, | ||||
| 						0x0209: 3, | ||||
| 						0x0409: 4 | ||||
| 						/*::[*/0x0009/*::]*/:2, | ||||
| 						/*::[*/0x0209/*::]*/:3, | ||||
| 						/*::[*/0x0409/*::]*/:4 | ||||
| 					}[RecordType] || { | ||||
| 						0x0200: 2, | ||||
| 						0x0300: 3, | ||||
| 						0x0400: 4, | ||||
| 						0x0500: 5, | ||||
| 						0x0600: 8, | ||||
| 						0x0002: 2, | ||||
| 						0x0007: 2 | ||||
| 						/*::[*/0x0200/*::]*/:2, | ||||
| 						/*::[*/0x0300/*::]*/:3, | ||||
| 						/*::[*/0x0400/*::]*/:4, | ||||
| 						/*::[*/0x0500/*::]*/:5, | ||||
| 						/*::[*/0x0600/*::]*/:8, | ||||
| 						/*::[*/0x0002/*::]*/:2, | ||||
| 						/*::[*/0x0007/*::]*/:2 | ||||
| 					}[val.BIFFVer] || 8; | ||||
| 					opts.biffguess = val.BIFFVer == 0; | ||||
| 					if(val.BIFFVer == 0 && val.dt == 0x1000) { opts.biff = 5; seen_codepage = true; set_cp(opts.codepage = 28591); } | ||||
| 					if(opts.biff == 4 && val.dt & 0x100) biff4w = true; | ||||
| 					if(opts.biff == 8 && val.BIFFVer == 0 && val.dt == 16) opts.biff = 2; | ||||
| 					if(file_depth++ && !biff4w) break; | ||||
| 					out = ({}/*:any*/); if(options.dense) out["!data"] = []; | ||||
| 					if(file_depth++) break; | ||||
| 					cell_valid = true; | ||||
| 					out = ((options.dense ? [] : {})/*:any*/); | ||||
| 
 | ||||
| 					if(opts.biff < 8 && !seen_codepage) { seen_codepage = true; set_cp(opts.codepage = options.codepage || 1252); } | ||||
| 					if(opts.biff == 4 && biff4w) { | ||||
| 						cur_sheet = (Directory[opts.snames.indexOf(cur_sheet)+1] || {name:""}).name; | ||||
| 					} else if(opts.biff < 5 || val.BIFFVer == 0 && val.dt == 0x1000) { | ||||
| 					if(opts.biff < 5) { | ||||
| 						if(cur_sheet === "") cur_sheet = "Sheet1"; | ||||
| 						range = {s:{r:0,c:0},e:{r:0,c:0}}; | ||||
| 						/* fake BoundSheet8 */ | ||||
| @ -367,38 +378,40 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 					objects = []; | ||||
| 					opts.arrayf = arrayf = []; | ||||
| 					colinfo = []; rowinfo = []; | ||||
| 					defwidth = defheight = 0; | ||||
| 					seencol = false; | ||||
| 					wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet }; | ||||
| 				} break; | ||||
| 				case 0x0203 /* Number */: case 0x0003 /* BIFF2NUM */: case 0x0002 /* BIFF2INT */: { | ||||
| 					if(out["!type"] == "chart") if(options.dense ? (out["!data"][val.r]||[])[val.c]: out[encode_col(val.c) + encode_row(val.r)]) ++val.c; | ||||
| 
 | ||||
| 				case 'Number': case 'BIFF2NUM': case 'BIFF2INT': { | ||||
| 					if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c; | ||||
| 					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe]||{}, v:val.val, t:'n'}/*:any*/); | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 				} break; | ||||
| 				case 0x0005: case 0x0205 /* BoolErr */: { | ||||
| 				case 'BoolErr': { | ||||
| 					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t}/*:any*/); | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 				} break; | ||||
| 				case 0x027e /* RK */: { | ||||
| 				case 'RK': { | ||||
| 					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'}/*:any*/); | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 				} break; | ||||
| 				case 0x00bd /* MulRk */: { | ||||
| 				case 'MulRk': { | ||||
| 					for(var j = val.c; j <= val.C; ++j) { | ||||
| 						var ixfe = val.rkrec[j-val.c][0]; | ||||
| 						temp_val= ({ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'}/*:any*/); | ||||
| 						if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 						safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 						addcell({c:j, r:val.r}, temp_val, options); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 0x0006: case 0x0206: case 0x0406 /* Formula */: { | ||||
| 				case 'Formula': { | ||||
| 					if(val.val == 'String') { last_formula = val; break; } | ||||
| 					temp_val = make_cell(val.val, val.cell.ixfe, val.tt); | ||||
| 					temp_val.XF = XFs[temp_val.ixfe]; | ||||
| @ -408,15 +421,15 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 							var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1]; | ||||
| 							var _fe = encode_cell({r:_fr, c:_fc}); | ||||
| 							if(sharedf[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts); | ||||
| 							else temp_val.F = ((options.dense ? (out["!data"][_fr]||[])[_fc]: out[_fe]) || {}).F; | ||||
| 							else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F; | ||||
| 						} else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts); | ||||
| 					} | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell(val.cell, temp_val, options); | ||||
| 					last_formula = val; | ||||
| 				} break; | ||||
| 				case 0x0007: case 0x0207 /* String */: { | ||||
| 				case 'String': { | ||||
| 					if(last_formula) { /* technically always true */ | ||||
| 						last_formula.val = val; | ||||
| 						temp_val = make_cell(val, last_formula.cell.ixfe, 's'); | ||||
| @ -424,16 +437,16 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						if(options.cellFormula) { | ||||
| 							temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts); | ||||
| 						} | ||||
| 						if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 						safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 						addcell(last_formula.cell, temp_val, options); | ||||
| 						last_formula = null; | ||||
| 					} else throw new Error("String record expects Formula"); | ||||
| 				} break; | ||||
| 				case 0x0021: case 0x0221 /* Array */: { | ||||
| 				case 'Array': { | ||||
| 					arrayf.push(val); | ||||
| 					var _arraystart = encode_cell(val[0].s); | ||||
| 					cc = options.dense ? (out["!data"][val[0].s.r]||[])[val[0].s.c] : out[_arraystart]; | ||||
| 					cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart]; | ||||
| 					if(options.cellFormula && cc) { | ||||
| 						if(!last_formula) break; /* technically unreachable */ | ||||
| 						if(!_arraystart || !cc) break; | ||||
| @ -441,95 +454,99 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						cc.F = encode_range(val[0]); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 0x04bc /* ShrFmla */: { | ||||
| 				case 'ShrFmla': { | ||||
| 					if(!cell_valid) break; | ||||
| 					if(!options.cellFormula) break; | ||||
| 					if(last_cell) { | ||||
| 						/* TODO: capture range */ | ||||
| 						if(!last_formula) break; /* technically unreachable */ | ||||
| 						sharedf[encode_cell(last_formula.cell)]= val[0]; | ||||
| 						cc = options.dense ? (out["!data"][last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)]; | ||||
| 						cc = options.dense ? (out[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)]; | ||||
| 						(cc||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 0x00fd /* LabelSst */: | ||||
| 				case 'LabelSst': | ||||
| 					temp_val=make_cell(sst[val.isst].t, val.ixfe, 's'); | ||||
| 					if(sst[val.isst].h) temp_val.h = sst[val.isst].h; | ||||
| 					temp_val.XF = XFs[temp_val.ixfe]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 					break; | ||||
| 				case 0x0201 /* Blank */: if(options.sheetStubs) { | ||||
| 				case 'Blank': if(options.sheetStubs) { | ||||
| 					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'}/*:any*/); | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 				} break; | ||||
| 				case 0x00be /* MulBlank */: if(options.sheetStubs) { | ||||
| 				case 'MulBlank': if(options.sheetStubs) { | ||||
| 					for(var _j = val.c; _j <= val.C; ++_j) { | ||||
| 						var _ixfe = val.ixfe[_j-val.c]; | ||||
| 						temp_val= ({ixfe:_ixfe, XF:XFs[_ixfe], t:'z'}/*:any*/); | ||||
| 						if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 						safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 						addcell({c:_j, r:val.r}, temp_val, options); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 0x00d6 /* RString */: | ||||
| 				case 0x0204 /* Label */: case 0x0004 /* BIFF2STR */: | ||||
| 				case 'RString': | ||||
| 				case 'Label': case 'BIFF2STR': | ||||
| 					temp_val=make_cell(val.val, val.ixfe, 's'); | ||||
| 					temp_val.XF = XFs[temp_val.ixfe]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F]; | ||||
| 					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F]; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 					break; | ||||
| 
 | ||||
| 				case 0x0000: case 0x0200 /* Dimensions */: { | ||||
| 				case 'Dimensions': { | ||||
| 					if(file_depth === 1) range = val; /* TODO: stack */ | ||||
| 				} break; | ||||
| 				case 0x00fc /* SST */: { | ||||
| 				case 'SST': { | ||||
| 					sst = val; | ||||
| 				} break; | ||||
| 				case 0x041e /* Format */: { /* val = [id, fmt] */ | ||||
| 					if(opts.biff >= 3 && opts.biff <= 4) { | ||||
| 				case 'Format': { /* val = [id, fmt] */ | ||||
| 					if(opts.biff == 4) { | ||||
| 						BIFF2FmtTable[BIFF2Fmt++] = val[1]; | ||||
| 						for(var b4idx = 0; b4idx < BIFF2Fmt + 163; ++b4idx) if(table_fmt[b4idx] == val[1]) break; | ||||
| 						if(b4idx >= 163) SSF__load(val[1], BIFF2Fmt + 163); | ||||
| 						for(var b4idx = 0; b4idx < BIFF2Fmt + 163; ++b4idx) if(SSF._table[b4idx] == val[1]) break; | ||||
| 						if(b4idx >= 163) SSF.load(val[1], BIFF2Fmt + 163); | ||||
| 					} | ||||
| 					else SSF__load(val[1], val[0]); | ||||
| 					else SSF.load(val[1], val[0]); | ||||
| 				} break; | ||||
| 				case 0x001e /* BIFF2FORMAT */: { | ||||
| 				case 'BIFF2FORMAT': { | ||||
| 					BIFF2FmtTable[BIFF2Fmt++] = val; | ||||
| 					for(var b2idx = 0; b2idx < BIFF2Fmt + 163; ++b2idx) if(table_fmt[b2idx] == val) break; | ||||
| 					if(b2idx >= 163) SSF__load(val, BIFF2Fmt + 163); | ||||
| 					for(var b2idx = 0; b2idx < BIFF2Fmt + 163; ++b2idx) if(SSF._table[b2idx] == val) break; | ||||
| 					if(b2idx >= 163) SSF.load(val, BIFF2Fmt + 163); | ||||
| 				} break; | ||||
| 
 | ||||
| 				case 0x00e5 /* MergeCells */: merges = merges.concat(val); break; | ||||
| 				case 'MergeCells': merges = merges.concat(val); break; | ||||
| 
 | ||||
| 				case 0x005d /* Obj */: objects[val.cmo[0]] = opts.lastobj = val; break; | ||||
| 				case 0x01b6 /* TxO */: opts.lastobj.TxO = val; break; | ||||
| 				case 0x007f /* ImData */: opts.lastobj.ImData = val; break; | ||||
| 				case 'Obj': objects[val.cmo[0]] = opts.lastobj = val; break; | ||||
| 				case 'TxO': opts.lastobj.TxO = val; break; | ||||
| 				case 'ImData': opts.lastobj.ImData = val; break; | ||||
| 
 | ||||
| 				case 0x01b8 /* HLink */: { | ||||
| 				case 'HLink': { | ||||
| 					for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR) | ||||
| 						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) { | ||||
| 							cc = options.dense ? (out["!data"][rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})]; | ||||
| 							cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})]; | ||||
| 							if(cc) cc.l = val[1]; | ||||
| 						} | ||||
| 				} break; | ||||
| 				case 0x0800 /* HLinkTooltip */: { | ||||
| 				case 'HLinkTooltip': { | ||||
| 					for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR) | ||||
| 						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) { | ||||
| 							cc = options.dense ? (out["!data"][rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})]; | ||||
| 							cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})]; | ||||
| 							if(cc && cc.l) cc.l.Tooltip = val[1]; | ||||
| 							} | ||||
| 				} break; | ||||
| 				case 0x001c /* Note */: { | ||||
| 					/* TODO: comment continuation (row == -1 / 0xFFFF) */ | ||||
| 					cc = options.dense ? (out["!data"][val[0].r]||[])[val[0].c] : out[encode_cell(val[0])]; | ||||
| 
 | ||||
| 				/* Comments */ | ||||
| 				case 'Note': { | ||||
| 					if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */ | ||||
| 					cc = options.dense ? (out[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])]; | ||||
| 					var noteobj = objects[val[2]]; | ||||
| 					if(!cc) { | ||||
| 						if(options.dense) { | ||||
| 							if(!out["!data"][val[0].r]) out["!data"][val[0].r] = []; | ||||
| 							cc = out["!data"][val[0].r][val[0].c] = ({t:"z"}/*:any*/); | ||||
| 							if(!out[val[0].r]) out[val[0].r] = []; | ||||
| 							cc = out[val[0].r][val[0].c] = ({t:"z"}/*:any*/); | ||||
| 						} else { | ||||
| 							cc = out[encode_cell(val[0])] = ({t:"z"}/*:any*/); | ||||
| 						} | ||||
| @ -539,24 +556,26 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						range.s.c = Math.min(range.s.c, val[0].c); | ||||
| 					} | ||||
| 					if(!cc.c) cc.c = []; | ||||
| 					if(opts.biff <= 5 && opts.biff >= 2) cmnt = {a:"SheetJ5", t:val[1]}; | ||||
| 					else { | ||||
| 						var noteobj = objects[val[2]]; | ||||
| 						cmnt = {a:val[1],t:noteobj.TxO.t}; | ||||
| 						if(val[3] != null && !(val[3] & 0x02)) cc.c.hidden = true; | ||||
| 					} | ||||
| 					cmnt = {a:val[1],t:noteobj.TxO.t}; | ||||
| 					cc.c.push(cmnt); | ||||
| 				} break; | ||||
| 				case 0x087d /* XFExt */: update_xfext(XFs[val.ixfe], val.ext); break; | ||||
| 				case 0x007d /* ColInfo */: { | ||||
| 
 | ||||
| 				default: switch(R.n) { /* nested */ | ||||
| 				case 'ClrtClient': break; | ||||
| 				case 'XFExt': update_xfext(XFs[val.ixfe], val.ext); break; | ||||
| 
 | ||||
| 				case 'DefColWidth': defwidth = val; break; | ||||
| 				case 'DefaultRowHeight': defheight = val[1]; break; // TODO: flags
 | ||||
| 
 | ||||
| 				case 'ColInfo': { | ||||
| 					if(!opts.cellStyles) break; | ||||
| 					while(val.e >= val.s) { | ||||
| 						colinfo[val.e--] = { width: val.w/256, level: (val.level || 0), hidden: !!(val.flags & 1) }; | ||||
| 						colinfo[val.e--] = { width: val.w/256 }; | ||||
| 						if(!seencol) { seencol = true; find_mdw_colw(val.w/256); } | ||||
| 						process_col(colinfo[val.e+1]); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 0x0208 /* Row */: { | ||||
| 				case 'Row': { | ||||
| 					var rowobj = {}; | ||||
| 					if(val.level != null) { rowinfo[val.r] = rowobj; rowobj.level = val.level; } | ||||
| 					if(val.hidden) { rowinfo[val.r] = rowobj; rowobj.hidden = true; } | ||||
| @ -565,47 +584,274 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						rowobj.hpt = val.hpt; rowobj.hpx = pt2px(val.hpt); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 0x0026 /* LeftMargin */: | ||||
| 				case 0x0027 /* RightMargin */: | ||||
| 				case 0x0028 /* TopMargin */: | ||||
| 				case 0x0029 /* BottomMargin */: | ||||
| 
 | ||||
| 				case 'LeftMargin': | ||||
| 				case 'RightMargin': | ||||
| 				case 'TopMargin': | ||||
| 				case 'BottomMargin': | ||||
| 					if(!out['!margins']) default_margins(out['!margins'] = {}); | ||||
| 					out['!margins'][({0x26: "left", 0x27:"right", 0x28:"top", 0x29:"bottom"})[RecordType]] = val; | ||||
| 					out['!margins'][Rn.slice(0,-6).toLowerCase()] = val; | ||||
| 					break; | ||||
| 				case 0x00a1 /* Setup */: // TODO
 | ||||
| 
 | ||||
| 				case 'Setup': // TODO
 | ||||
| 					if(!out['!margins']) default_margins(out['!margins'] = {}); | ||||
| 					out['!margins'].header = val.header; | ||||
| 					out['!margins'].footer = val.footer; | ||||
| 					break; | ||||
| 				case 0x023e /* Window2 */: // TODO
 | ||||
| 
 | ||||
| 				case 'Window2': // TODO
 | ||||
| 					// $FlowIgnore
 | ||||
| 					if(val.RTL) Workbook.Views[0].RTL = true; | ||||
| 					break; | ||||
| 				case 0x0092 /* Palette */: palette = val; break; | ||||
| 				case 0x0896 /* Theme */: themes = val; break; | ||||
| 				case 0x008c /* Country */: country = val; break; | ||||
| 				case 0x01ba /* CodeName */: { | ||||
| 
 | ||||
| 				case 'Header': break; // TODO
 | ||||
| 				case 'Footer': break; // TODO
 | ||||
| 				case 'HCenter': break; // TODO
 | ||||
| 				case 'VCenter': break; // TODO
 | ||||
| 				case 'Pls': break; // TODO
 | ||||
| 				case 'GCW': break; | ||||
| 				case 'LHRecord': break; | ||||
| 				case 'DBCell': break; // TODO
 | ||||
| 				case 'EntExU2': break; // TODO
 | ||||
| 				case 'SxView': break; // TODO
 | ||||
| 				case 'Sxvd': break; // TODO
 | ||||
| 				case 'SXVI': break; // TODO
 | ||||
| 				case 'SXVDEx': break; // TODO
 | ||||
| 				case 'SxIvd': break; // TODO
 | ||||
| 				case 'SXString': break; // TODO
 | ||||
| 				case 'Sync': break; | ||||
| 				case 'Addin': break; | ||||
| 				case 'SXDI': break; // TODO
 | ||||
| 				case 'SXLI': break; // TODO
 | ||||
| 				case 'SXEx': break; // TODO
 | ||||
| 				case 'QsiSXTag': break; // TODO
 | ||||
| 				case 'Selection': break; | ||||
| 				case 'Feat': break; | ||||
| 				case 'FeatHdr': case 'FeatHdr11': break; | ||||
| 				case 'Feature11': case 'Feature12': case 'List12': break; | ||||
| 				case 'Country': country = val; break; | ||||
| 				case 'RecalcId': break; | ||||
| 				case 'DxGCol': break; // TODO: htmlify
 | ||||
| 				case 'Fbi': case 'Fbi2': case 'GelFrame': break; | ||||
| 				case 'Font': break; // TODO
 | ||||
| 				case 'XFCRC': break; // TODO
 | ||||
| 				case 'Style': break; // TODO
 | ||||
| 				case 'StyleExt': break; // TODO
 | ||||
| 				case 'Palette': palette = val; break; | ||||
| 				case 'Theme': themes = val; break; | ||||
| 				/* Protection */ | ||||
| 				case 'ScenarioProtect': break; | ||||
| 				case 'ObjProtect': break; | ||||
| 
 | ||||
| 				/* Conditional Formatting */ | ||||
| 				case 'CondFmt12': break; | ||||
| 
 | ||||
| 				/* Table */ | ||||
| 				case 'Table': break; // TODO
 | ||||
| 				case 'TableStyles': break; // TODO
 | ||||
| 				case 'TableStyle': break; // TODO
 | ||||
| 				case 'TableStyleElement': break; // TODO
 | ||||
| 
 | ||||
| 				/* PivotTable */ | ||||
| 				case 'SXStreamID': break; // TODO
 | ||||
| 				case 'SXVS': break; // TODO
 | ||||
| 				case 'DConRef': break; // TODO
 | ||||
| 				case 'SXAddl': break; // TODO
 | ||||
| 				case 'DConBin': break; // TODO
 | ||||
| 				case 'DConName': break; // TODO
 | ||||
| 				case 'SXPI': break; // TODO
 | ||||
| 				case 'SxFormat': break; // TODO
 | ||||
| 				case 'SxSelect': break; // TODO
 | ||||
| 				case 'SxRule': break; // TODO
 | ||||
| 				case 'SxFilt': break; // TODO
 | ||||
| 				case 'SxItm': break; // TODO
 | ||||
| 				case 'SxDXF': break; // TODO
 | ||||
| 
 | ||||
| 				/* Scenario Manager */ | ||||
| 				case 'ScenMan': break; | ||||
| 
 | ||||
| 				/* Data Consolidation */ | ||||
| 				case 'DCon': break; | ||||
| 
 | ||||
| 				/* Watched Cell */ | ||||
| 				case 'CellWatch': break; | ||||
| 
 | ||||
| 				/* Print Settings */ | ||||
| 				case 'PrintRowCol': break; | ||||
| 				case 'PrintGrid': break; | ||||
| 				case 'PrintSize': break; | ||||
| 
 | ||||
| 				case 'XCT': break; | ||||
| 				case 'CRN': break; | ||||
| 
 | ||||
| 				case 'Scl': { | ||||
| 					//console.log("Zoom Level:", val[0]/val[1],val);
 | ||||
| 				} break; | ||||
| 				case 'SheetExt': { | ||||
| 					/* empty */ | ||||
| 				} break; | ||||
| 				case 'SheetExtOptional': { | ||||
| 					/* empty */ | ||||
| 				} break; | ||||
| 
 | ||||
| 				/* VBA */ | ||||
| 				case 'ObNoMacros': { | ||||
| 					/* empty */ | ||||
| 				} break; | ||||
| 				case 'ObProj': { | ||||
| 					/* empty */ | ||||
| 				} break; | ||||
| 				case 'CodeName': { | ||||
| 					/*:: if(!Workbook.WBProps) Workbook.WBProps = {}; */ | ||||
| 					if(!cur_sheet) Workbook.WBProps.CodeName = val || "ThisWorkbook"; | ||||
| 					else wsprops.CodeName = val || wsprops.name; | ||||
| 				} break; | ||||
| 			} | ||||
| 		} else { | ||||
| 			if(!R) console.error("Missing Info for XLS Record 0x" + RecordType.toString(16)); | ||||
| 			blob.l += length; | ||||
| 		} | ||||
| 				case 'GUIDTypeLib': { | ||||
| 					/* empty */ | ||||
| 				} break; | ||||
| 
 | ||||
| 				case 'WOpt': break; // TODO: WTF?
 | ||||
| 				case 'PhoneticInfo': break; | ||||
| 
 | ||||
| 				case 'OleObjectSize': break; | ||||
| 
 | ||||
| 				/* Differential Formatting */ | ||||
| 				case 'DXF': case 'DXFN': case 'DXFN12': case 'DXFN12List': case 'DXFN12NoCB': break; | ||||
| 
 | ||||
| 				/* Data Validation */ | ||||
| 				case 'Dv': case 'DVal': break; | ||||
| 
 | ||||
| 				/* Data Series */ | ||||
| 				case 'BRAI': case 'Series': case 'SeriesText': break; | ||||
| 
 | ||||
| 				/* Data Connection */ | ||||
| 				case 'DConn': break; | ||||
| 				case 'DbOrParamQry': break; | ||||
| 				case 'DBQueryExt': break; | ||||
| 
 | ||||
| 				case 'OleDbConn': break; | ||||
| 				case 'ExtString': break; | ||||
| 
 | ||||
| 				/* Formatting */ | ||||
| 				case 'IFmtRecord': break; | ||||
| 				case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break; | ||||
| 
 | ||||
| 				/* Explicitly Ignored */ | ||||
| 				case 'Excel9File': break; | ||||
| 				case 'Units': break; | ||||
| 				case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': break; | ||||
| 				case 'BuiltInFnGroupCount': /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */ break; | ||||
| 				/* View Stuff */ | ||||
| 				case 'Window1': case 'HideObj': case 'GridSet': case 'Guts': | ||||
| 				case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd': break; | ||||
| 				case 'Pane': break; | ||||
| 				default: switch(R.n) { /* nested */ | ||||
| 				/* Chart */ | ||||
| 				case 'Dat': | ||||
| 				case 'Begin': case 'End': | ||||
| 				case 'StartBlock': case 'EndBlock': | ||||
| 				case 'Frame': case 'Area': | ||||
| 				case 'Axis': case 'AxisLine': case 'Tick': break; | ||||
| 				case 'AxesUsed': | ||||
| 				case 'CrtLayout12': case 'CrtLayout12A': case 'CrtLink': case 'CrtLine': case 'CrtMlFrt': case 'CrtMlFrtContinue': break; | ||||
| 				case 'LineFormat': case 'AreaFormat': | ||||
| 				case 'Chart': case 'Chart3d': case 'Chart3DBarShape': case 'ChartFormat': case 'ChartFrtInfo': break; | ||||
| 				case 'PlotArea': case 'PlotGrowth': break; | ||||
| 				case 'SeriesList': case 'SerParent': case 'SerAuxTrend': break; | ||||
| 				case 'DataFormat': case 'SerToCrt': case 'FontX': break; | ||||
| 				case 'CatSerRange': case 'AxcExt': case 'SerFmt': break; | ||||
| 				case 'ShtProps': break; | ||||
| 				case 'DefaultText': case 'Text': case 'CatLab': break; | ||||
| 				case 'DataLabExtContents': break; | ||||
| 				case 'Legend': case 'LegendException': break; | ||||
| 				case 'Pie': case 'Scatter': break; | ||||
| 				case 'PieFormat': case 'MarkerFormat': break; | ||||
| 				case 'StartObject': case 'EndObject': break; | ||||
| 				case 'AlRuns': case 'ObjectLink': break; | ||||
| 				case 'SIIndex': break; | ||||
| 				case 'AttachedLabel': case 'YMult': break; | ||||
| 
 | ||||
| 				/* Chart Group */ | ||||
| 				case 'Line': case 'Bar': break; | ||||
| 				case 'Surf': break; | ||||
| 
 | ||||
| 				/* Axis Group */ | ||||
| 				case 'AxisParent': break; | ||||
| 				case 'Pos': break; | ||||
| 				case 'ValueRange': break; | ||||
| 
 | ||||
| 				/* Pivot Chart */ | ||||
| 				case 'SXViewEx9': break; // TODO
 | ||||
| 				case 'SXViewLink': break; | ||||
| 				case 'PivotChartBits': break; | ||||
| 				case 'SBaseRef': break; | ||||
| 				case 'TextPropsStream': break; | ||||
| 
 | ||||
| 				/* Chart Misc */ | ||||
| 				case 'LnExt': break; | ||||
| 				case 'MkrExt': break; | ||||
| 				case 'CrtCoopt': break; | ||||
| 
 | ||||
| 				/* Query Table */ | ||||
| 				case 'Qsi': case 'Qsif': case 'Qsir': case 'QsiSXTag': break; | ||||
| 				case 'TxtQry': break; | ||||
| 
 | ||||
| 				/* Filter */ | ||||
| 				case 'FilterMode': break; | ||||
| 				case 'AutoFilter': case 'AutoFilterInfo': break; | ||||
| 				case 'AutoFilter12': break; | ||||
| 				case 'DropDownObjIds': break; | ||||
| 				case 'Sort': break; | ||||
| 				case 'SortData': break; | ||||
| 
 | ||||
| 				/* Drawing */ | ||||
| 				case 'ShapePropsStream': break; | ||||
| 				case 'MsoDrawing': case 'MsoDrawingGroup': case 'MsoDrawingSelection': break; | ||||
| 				/* Pub Stuff */ | ||||
| 				case 'WebPub': case 'AutoWebPub': break; | ||||
| 
 | ||||
| 				/* Print Stuff */ | ||||
| 				case 'HeaderFooter': case 'HFPicture': case 'PLV': | ||||
| 				case 'HorizontalPageBreaks': case 'VerticalPageBreaks': break; | ||||
| 				/* Behavioral */ | ||||
| 				case 'Backup': case 'CompressPictures': case 'Compat12': break; | ||||
| 
 | ||||
| 				/* Should not Happen */ | ||||
| 				case 'Continue': case 'ContinueFrt12': break; | ||||
| 
 | ||||
| 				/* Future Records */ | ||||
| 				case 'FrtFontList': case 'FrtWrapper': break; | ||||
| 
 | ||||
| 				default: switch(R.n) { /* nested */ | ||||
| 				/* BIFF5 records */ | ||||
| 				case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break; | ||||
| 
 | ||||
| 				/* BIFF2-4 records */ | ||||
| 				case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': case 'BIFF2FONTXTRA': break; | ||||
| 				case 'BIFF2XF': case 'BIFF3XF': case 'BIFF4XF': break; | ||||
| 				case 'BIFF4FMTCNT': case 'BIFF2ROW': case 'BIFF2WINDOW2': break; | ||||
| 
 | ||||
| 				/* Miscellaneous */ | ||||
| 				case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt': | ||||
| 				case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData': | ||||
| 				case 'Name': break; | ||||
| 				case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break; | ||||
| 				case 'ListObj': case 'ListField': break; | ||||
| 				case 'RRSort': break; | ||||
| 				case 'BigName': break; | ||||
| 				case 'ToolbarHdr': case 'ToolbarEnd': break; | ||||
| 				case 'DDEObjName': break; | ||||
| 				case 'FRTArchId$': break; | ||||
| 				default: if(options.WTF) throw 'Unrecognized Record ' + R.n; | ||||
| 			}}}} | ||||
| 		} else blob.l += length; | ||||
| 	} | ||||
| 	wb.SheetNames=keys(Directory).sort(function(a,b) { return Number(a) - Number(b); }).map(function(x){return Directory[x].name;}); | ||||
| 	if(!options.bookSheets) wb.Sheets=Sheets; | ||||
| 	if(!wb.SheetNames.length && Preamble["!ref"]) { | ||||
| 		wb.SheetNames.push("Sheet1"); | ||||
| 		/*jshint -W069 */ | ||||
| 		if(wb.Sheets) wb.Sheets["Sheet1"] = Preamble; | ||||
| 		/*jshint +W069 */ | ||||
| 	} else wb.Preamble=Preamble; | ||||
| 	if(wb.Sheets) FilterDatabases.forEach(function(r,i) { wb.Sheets[wb.SheetNames[i]]['!autofilter'] = r; }); | ||||
| 	wb.Preamble=Preamble; | ||||
| 	wb.Strings = sst; | ||||
| 	wb.SSF = dup(table_fmt); | ||||
| 	wb.SSF = SSF.get_table(); | ||||
| 	if(opts.enc) wb.Encryption = opts.enc; | ||||
| 	if(themes) wb.Themes = themes; | ||||
| 	wb.Metadata = {}; | ||||
| @ -623,18 +869,18 @@ var PSCLSID = { | ||||
| }; | ||||
| function parse_xls_props(cfb/*:CFBContainer*/, props, o) { | ||||
| 	/* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */ | ||||
| 	var DSI = CFB.find(cfb, '/!DocumentSummaryInformation'); | ||||
| 	var DSI = CFB.find(cfb, '!DocumentSummaryInformation'); | ||||
| 	if(DSI && DSI.size > 0) try { | ||||
| 		var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI, PSCLSID.DSI); | ||||
| 		for(var d in DocSummary) props[d] = DocSummary[d]; | ||||
| 	} catch(e) {if(o.WTF) console.error(e && e.message || e);} | ||||
| 	} catch(e) {if(o.WTF) throw e;/* empty */} | ||||
| 
 | ||||
| 	/* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/ | ||||
| 	var SI = CFB.find(cfb, '/!SummaryInformation'); | ||||
| 	var SI = CFB.find(cfb, '!SummaryInformation'); | ||||
| 	if(SI && SI.size > 0) try { | ||||
| 		var Summary = parse_PropertySetStream(SI, SummaryPIDSI, PSCLSID.SI); | ||||
| 		for(var s in Summary) if(props[s] == null) props[s] = Summary[s]; | ||||
| 	} catch(e) {if(o.WTF) console.error(e && e.message || e);} | ||||
| 	} catch(e) {if(o.WTF) throw e;/* empty */} | ||||
| 
 | ||||
| 	if(props.HeadingPairs && props.TitlesOfParts) { | ||||
| 		load_props_pairs(props.HeadingPairs, props.TitlesOfParts, props, o); | ||||
| @ -644,8 +890,6 @@ function parse_xls_props(cfb/*:CFBContainer*/, props, o) { | ||||
| function write_xls_props(wb/*:Workbook*/, cfb/*:CFBContainer*/) { | ||||
| 	var DSEntries = [], SEntries = [], CEntries = []; | ||||
| 	var i = 0, Keys; | ||||
| 	var DocSummaryRE/*:{[key:string]:string}*/ = evert_key(DocSummaryPIDDSI, "n"); | ||||
| 	var SummaryRE/*:{[key:string]:string}*/ = evert_key(SummaryPIDSI, "n"); | ||||
| 	if(wb.Props) { | ||||
| 		Keys = keys(wb.Props); | ||||
| 		// $FlowIgnore
 | ||||
| @ -658,7 +902,7 @@ function write_xls_props(wb/*:Workbook*/, cfb/*:CFBContainer*/) { | ||||
| 	} | ||||
| 	var CEntries2 = []; | ||||
| 	for(i = 0; i < CEntries.length; ++i) { | ||||
| 		if(XLSPSSkip.indexOf(CEntries[i][0]) > -1 || PseudoPropsPairs.indexOf(CEntries[i][0]) > -1) continue; | ||||
| 		if(XLSPSSkip.indexOf(CEntries[i][0]) > -1) continue; | ||||
| 		if(CEntries[i][1] == null) continue; | ||||
| 		CEntries2.push(CEntries[i]); | ||||
| 	} | ||||
| @ -678,7 +922,7 @@ if(cfb.FullPaths) { | ||||
| 	WB = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book'); | ||||
| } else { | ||||
| 	switch(options.type) { | ||||
| 		case 'base64': cfb = s2a(Base64_decode(cfb)); break; | ||||
| 		case 'base64': cfb = s2a(Base64.decode(cfb)); break; | ||||
| 		case 'binary': cfb = s2a(cfb); break; | ||||
| 		case 'buffer': break; | ||||
| 		case 'array': if(!Array.isArray(cfb)) cfb = Array.prototype.slice.call(cfb); break; | ||||
| @ -698,8 +942,6 @@ else/*:: if(cfb instanceof CFBContainer) */ { | ||||
| 	else if((_data=CFB.find(cfb, 'PerfectOffice_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options)); | ||||
| 	/* Quattro Pro 9 */ | ||||
| 	else if((_data=CFB.find(cfb, 'NativeContent_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options)); | ||||
| 	/* Works 4 for Mac */ | ||||
| 	else if((_data=CFB.find(cfb, 'MN0')) && _data.content) throw new Error("Unsupported Works 4 for Mac file"); | ||||
| 	else throw new Error("Cannot find Workbook stream"); | ||||
| 	if(options.bookVBA && cfb.FullPaths && CFB.find(cfb, '/_VBA_PROJECT_CUR/VBA/dir')) WorkbookP.vbaraw = make_vba_xls(cfb); | ||||
| } | ||||
|  | ||||
							
								
								
									
										2584
									
								
								bits/77_parsetab.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2584
									
								
								bits/77_parsetab.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,5 +1,5 @@ | ||||
| function write_biff_rec(ba/*:BufArray*/, type/*:number*/, payload, length/*:?number*/)/*:void*/ { | ||||
| 	var t/*:number*/ = type; | ||||
| function write_biff_rec(ba/*:BufArray*/, type/*:number|string*/, payload, length/*:?number*/)/*:void*/ { | ||||
| 	var t/*:number*/ = +type || +XLSRE[/*::String(*/type/*::)*/]; | ||||
| 	if(isNaN(t)) return; | ||||
| 	var len = length || (payload||[]).length || 0; | ||||
| 	var o = ba.next(4); | ||||
| @ -8,10 +8,10 @@ function write_biff_rec(ba/*:BufArray*/, type/*:number*/, payload, length/*:?num | ||||
| 	if(/*:: len != null &&*/len > 0 && is_buf(payload)) ba.push(payload); | ||||
| } | ||||
| 
 | ||||
| function write_biff_continue(ba/*:BufArray*/, type/*:number*/, payload, length/*:?number*/)/*:void*/ { | ||||
| function write_biff_continue(ba/*:BufArray*/, type/*:number|string*/, payload, length/*:?number*/)/*:void*/ { | ||||
| 	var len = length || (payload||[]).length || 0; | ||||
| 	if(len <= 8224) return write_biff_rec(ba, type, payload, len); | ||||
| 	var t = type; | ||||
| 	var t/*:number*/ = +type || +XLSRE[/*::String(*/type/*::)*/]; | ||||
| 	if(isNaN(t)) return; | ||||
| 	var parts = payload.parts || [], sidx = 0; | ||||
| 	var i = 0, w = 0; | ||||
| @ -31,10 +31,20 @@ function write_biff_continue(ba/*:BufArray*/, type/*:number*/, payload, length/* | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function write_BIFF2Cell(out, r/*:number*/, c/*:number*/) { | ||||
| 	if(!out) out = new_buf(7); | ||||
| 	out.write_shift(2, r); | ||||
| 	out.write_shift(2, c); | ||||
| 	out.write_shift(2, 0); | ||||
| 	out.write_shift(1, 0); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| function write_BIFF2BERR(r/*:number*/, c/*:number*/, val, t/*:?string*/) { | ||||
| 	var out = new_buf(9); | ||||
| 	write_BIFF2Cell(out, r, c); | ||||
| 	write_Bes(val, t || 'b', out); | ||||
| 	if(t == 'e') { out.write_shift(1, val); out.write_shift(1, 1); } | ||||
| 	else { out.write_shift(1, val?1:0); out.write_shift(1, 0); } | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| @ -47,373 +57,64 @@ function write_BIFF2LABEL(r/*:number*/, c/*:number*/, val) { | ||||
| 	return out.l < out.length ? out.slice(0, out.l) : out; | ||||
| } | ||||
| 
 | ||||
| function write_comments_biff2(ba/*:BufArray*/, comments/*:Array<[Comment[], number, number]>*/) { | ||||
| 	comments.forEach(function(data) { | ||||
| 		var text = data[0].map(function(cc) { return cc.t; }).join(""); | ||||
| 		// TODO: should '\n' be translated to '\r' to correct for Excel 5.0 bug when exporting to BIFF2/3 ?
 | ||||
| 		if(text.length <= 2048) return write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text, data[1], data[2])); | ||||
| 		write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text.slice(0, 2048), data[1], data[2], text.length)); | ||||
| 		for(var i = 2048; i < text.length; i += 2048) | ||||
| 			write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text.slice(i, Math.min(i+2048, text.length)), -1, -1, Math.min(2048, text.length - i))); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* TODO: BIFF3/4 use different records -- see comments*/ | ||||
| function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, date1904/*:boolean*/) { | ||||
| 	var ifmt = 0; | ||||
| 	if(cell.z != null) { | ||||
| 		ifmt = opts._BIFF2FmtTable.indexOf(cell.z); | ||||
| 		if(ifmt == -1) { opts._BIFF2FmtTable.push(cell.z); ifmt = opts._BIFF2FmtTable.length - 1; } | ||||
| 	} | ||||
| 	var ixfe = 0; | ||||
| 	if(cell.z != null) { | ||||
| 		for(; ixfe < opts.cellXfs.length; ++ixfe) if(opts.cellXfs[ixfe].numFmtId == ifmt) break; | ||||
| 		if(ixfe == opts.cellXfs.length) opts.cellXfs.push({numFmtId: ifmt}); | ||||
| 	} | ||||
| function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*//*::, opts*/) { | ||||
| 	if(cell.v != null) switch(cell.t) { | ||||
| 		case 'd': case 'n': | ||||
| 			var v = cell.t == 'd' ? datenum(parseDate(cell.v, date1904), date1904) : cell.v; | ||||
| 			if(opts.biff == 2 && (v == (v|0)) && (v >= 0) && (v < 65536)) | ||||
| 				// 0x027E (RK) in BIFF3/4
 | ||||
| 				write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v, ixfe, ifmt)); | ||||
| 			else if(isNaN(v)) | ||||
| 				// 0x0205 in BIFF3/4
 | ||||
| 				write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, 0x24, "e")); // #NUM!
 | ||||
| 			else if(!isFinite(v)) | ||||
| 				// 0x0205 in BIFF3/4
 | ||||
| 				write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, 0x07, "e")); // #DIV/0!
 | ||||
| 			var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v; | ||||
| 			if((v == (v|0)) && (v >= 0) && (v < 65536)) | ||||
| 				write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v)); | ||||
| 			else | ||||
| 				// 0x0203 in BIFF3/4
 | ||||
| 				write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v, ixfe, ifmt)); | ||||
| 				write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v)); | ||||
| 			return; | ||||
| 		case 'b': case 'e': | ||||
| 			// 0x0205 in BIFF3/4
 | ||||
| 			write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return; | ||||
| 		case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return; | ||||
| 		/* TODO: codepage, sst */ | ||||
| 		case 's': case 'str': | ||||
| 			// 0x0204 in BIFF3/4
 | ||||
| 			write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v == null ? "" : String(cell.v).slice(0,255))); | ||||
| 			write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v)); | ||||
| 			return; | ||||
| 	} | ||||
| 	// 0x0201 in BIFF3/4
 | ||||
| 	write_biff_rec(ba, 0x0001, write_BIFF2Cell(null, R, C)); | ||||
| } | ||||
| 
 | ||||
| function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) { | ||||
| 	var dense = ws["!data"] != null; | ||||
| 	var range = safe_decode_range(ws['!ref'] || "A1"), rr = "", cols/*:Array<string>*/ = []; | ||||
| function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) { | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	var range = safe_decode_range(ws['!ref'] || "A1"), ref/*:string*/, rr = "", cols/*:Array<string>*/ = []; | ||||
| 	if(range.e.c > 0xFF || range.e.r > 0x3FFF) { | ||||
| 		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384"); | ||||
| 		range.e.c = Math.min(range.e.c, 0xFF); | ||||
| 		range.e.r = Math.min(range.e.r, 0x3FFF); | ||||
| 		range.e.r = Math.min(range.e.c, 0x3FFF); | ||||
| 		ref = encode_range(range); | ||||
| 	} | ||||
| 	var date1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904; | ||||
| 	var row = [], comments = []; | ||||
| 	/* TODO: 0x0000 / 0x0200 dimensions? */ | ||||
| 	for(var C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C); | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		if(dense) row = ws["!data"][R] || []; | ||||
| 		rr = encode_row(R); | ||||
| 		for(C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			var cell = dense ? row[C] : ws[cols[C] + rr]; | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			if(R === range.s.r) cols[C] = encode_col(C); | ||||
| 			ref = cols[C] + rr; | ||||
| 			var cell = dense ? (ws[R]||[])[C] : ws[ref]; | ||||
| 			if(!cell) continue; | ||||
| 			/* write cell */ | ||||
| 			write_ws_biff2_cell(ba, cell, R, C, opts, date1904); | ||||
| 			if(cell.c) comments.push([cell.c, R, C]); | ||||
| 			write_ws_biff2_cell(ba, cell, R, C, opts); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* ... 0x12 0x19 0x13 (Password) */ | ||||
| 	write_comments_biff2(ba, comments); | ||||
| 	/* 0x3d (Window1) ... */ | ||||
| } | ||||
| 
 | ||||
| /* Based on test files */ | ||||
| function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) { | ||||
| 	var o = opts || {}; | ||||
| 
 | ||||
| 	if(DENSE != null && o.dense == null) o.dense = DENSE; | ||||
| 	var ba = buf_array(); | ||||
| 	var idx = 0; | ||||
| 	for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i; | ||||
| 	if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet); | ||||
| 	write_biff_rec(ba, (o.biff == 4 ? 0x0409 : (o.biff == 3 ? 0x0209 : 0x0009)), write_BOF(wb, 0x10, o)); | ||||
| 	if(((wb.Workbook||{}).WBProps||{}).date1904) write_biff_rec(ba, 0x0022, writebool(true)); | ||||
| 	o.cellXfs = [{numFmtId: 0}]; | ||||
| 	o._BIFF2FmtTable/*:Array<string>*/ = ["General"]; o._Fonts = []; | ||||
| 	var body = buf_array(); | ||||
| 	write_ws_biff2(body, wb.Sheets[wb.SheetNames[idx]], idx, o, wb); | ||||
| 
 | ||||
| 	o._BIFF2FmtTable.forEach(function(f) { | ||||
| 		if(o.biff <= 3) write_biff_rec(ba, 0x001E, write_BIFF2Format(f)); | ||||
| 		else write_biff_rec(ba, 0x041E, write_BIFF4Format(f)); | ||||
| 	}); | ||||
| 	o.cellXfs.forEach(function(xf) { | ||||
| 		switch(o.biff) { | ||||
| 			case 2: write_biff_rec(ba, 0x0043, write_BIFF2XF(xf)); break; | ||||
| 			case 3: write_biff_rec(ba, 0x0243, write_BIFF3XF(xf)); break; | ||||
| 			case 4: write_biff_rec(ba, 0x0443, write_BIFF4XF(xf)); break; | ||||
| 		} | ||||
| 	}); | ||||
| 	delete o._BIFF2FmtTable; delete o.cellXfs; delete o._Fonts; | ||||
| 
 | ||||
| 	ba.push(body.end()); | ||||
| 	write_biff_rec(ba, 0x0009, write_BOF(wb, 0x10, o)); | ||||
| 	/* ... */ | ||||
| 	write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb); | ||||
| 	/* ... */ | ||||
| 	write_biff_rec(ba, 0x000A); | ||||
| 	return ba.end(); | ||||
| } | ||||
| 
 | ||||
| var b8oid = 1, b8ocnts/*:Array<[number, number, number]>*/ = []; | ||||
| function write_MsoDrawingGroup() { | ||||
| 	var buf = new_buf(82 + 8 * b8ocnts.length); | ||||
| 	/* [MS-ODRAW] 2.2.12 OfficeArtDggContainer */ | ||||
| 	buf.write_shift(2, 0x0F); | ||||
| 	buf.write_shift(2, 0xF000); | ||||
| 	buf.write_shift(4, 74 + 8 * b8ocnts.length); | ||||
| 	/* 2.2.48 OfficeArtFDGGBlock */ | ||||
| 	{ | ||||
| 		buf.write_shift(2, 0); | ||||
| 		buf.write_shift(2, 0xF006); | ||||
| 		buf.write_shift(4, 16 + 8 * b8ocnts.length); | ||||
| 		/* 2.2.47 OfficeArtFDGG */ | ||||
| 		{ | ||||
| 			buf.write_shift(4, b8oid); | ||||
| 			buf.write_shift(4, b8ocnts.length+1); | ||||
| 			var acc = 0; for(var i = 0; i < b8ocnts.length; ++i) acc += (b8ocnts[i] && b8ocnts[i][1] || 0); buf.write_shift(4, acc); | ||||
| 			buf.write_shift(4, b8ocnts.length); | ||||
| 		} | ||||
| 		/* 2.2.46 OfficeArtIDCL + */ | ||||
| 		b8ocnts.forEach(function(b8) { | ||||
| 			buf.write_shift(4, b8[0]); | ||||
| 			buf.write_shift(4, b8[2]); | ||||
| 		}); | ||||
| 	} | ||||
| 	/* 2.2.9 OfficeArtFOPT */ | ||||
| 	{ | ||||
| 		buf.write_shift(2, 0x33); // 0x03 | (3 << 4)
 | ||||
| 		buf.write_shift(2, 0xF00B); | ||||
| 		buf.write_shift(4, 0x12); // 3 * 6
 | ||||
| 		/* 2.3.21.15 Text Boolean Properties */ | ||||
| 		buf.write_shift(2, 0xBF); buf.write_shift(4, 0x00080008); | ||||
| 		/* 2.3.7.2 fillColor */ | ||||
| 		buf.write_shift(2, 0x0181); buf.write_shift(4, 0x08000041); | ||||
| 		/* 2.3.8.1 lineColor */ | ||||
| 		buf.write_shift(2, 0x01C0); buf.write_shift(4, 0x08000040); | ||||
| 	} | ||||
| 	/* 2.2.45 OfficeArtSplitMenuColorContainer */ | ||||
| 	{ | ||||
| 		buf.write_shift(2, 0x40); | ||||
| 		buf.write_shift(2, 0xF11E); | ||||
| 		buf.write_shift(4, 16); | ||||
| 		buf.write_shift(4, 0x0800000D); | ||||
| 		buf.write_shift(4, 0x0800000C); | ||||
| 		buf.write_shift(4, 0x08000017); | ||||
| 		buf.write_shift(4, 0x100000F7); | ||||
| 	} | ||||
| 	return buf; | ||||
| } | ||||
| function write_comments_biff8(ba/*:BufArray*/, comments/*:Array<[Comment[], number, number]>*/) { | ||||
| 	var notes/*:Array<RawData>*/ = [], sz = 0, pl = buf_array(), baseid = b8oid; | ||||
| 	var _oasc; | ||||
| 	comments.forEach(function(c, ci) { | ||||
| 		var author = ""; | ||||
| 		var text = c[0].map(function(t) { if(t.a && !author) author = t.a; return t.t; }).join(""); | ||||
| 		++b8oid; | ||||
| 
 | ||||
| 		/* 2.2.14 OfficeArtSpContainer */ | ||||
| 		{ | ||||
| 			var oasc = new_buf(0x96); | ||||
| 			oasc.write_shift(2, 0x0F); | ||||
| 			oasc.write_shift(2, 0xF004); | ||||
| 			oasc.write_shift(4, 0x96); | ||||
| 			/* 2.2.40 OfficeArtFSP */ | ||||
| 			{ | ||||
| 				oasc.write_shift(2, 0xca2); // 0x02 | (0xca << 4)
 | ||||
| 				oasc.write_shift(2, 0xF00A); | ||||
| 				oasc.write_shift(4, 8); | ||||
| 				oasc.write_shift(4, b8oid); | ||||
| 				oasc.write_shift(4, 0xA00); | ||||
| 			} | ||||
| 			/* 2.2.9 OfficeArtFOPT */ | ||||
| 			{ | ||||
| 				oasc.write_shift(2, 0xE3); // 0x03 | (14 << 4)
 | ||||
| 				oasc.write_shift(2, 0xF00B); | ||||
| 				oasc.write_shift(4, 0x54); // 14 * 6
 | ||||
| 				/* 2.3.21.1 ITxid */ | ||||
| 				oasc.write_shift(2, 0x80); oasc.write_shift(4, 0); | ||||
| 				/* 2.3.21.12 txdir */ | ||||
| 				oasc.write_shift(2, 0x8B); oasc.write_shift(4, 0x02); | ||||
| 				/* 2.3.21.15 Text Boolean Properties */ | ||||
| 				oasc.write_shift(2, 0xBF); oasc.write_shift(4, 0x00080008); | ||||
| 				/* 2.3.6.30 cxk */ | ||||
| 				oasc.write_shift(2, 0x0158); oasc.l += 4; | ||||
| 				/* 2.3.7.2 fillColor */ | ||||
| 				oasc.write_shift(2, 0x0181); oasc.write_shift(4, 0x08000050); | ||||
| 				/* 2.3.7.4 fillBackColor */ | ||||
| 				oasc.write_shift(2, 0x0183); oasc.write_shift(4, 0x08000050); | ||||
| 				/* 2.3.7.6 fillCrMod */ | ||||
| 				oasc.write_shift(2, 0x0185); oasc.write_shift(4, 0x100000F4); | ||||
| 				/* 2.3.7.43 Fill Style Boolean Properties */ | ||||
| 				oasc.write_shift(2, 0x01BF); oasc.write_shift(4, 0x00100010); | ||||
| 				/* 2.3.8.1 lineColor */ | ||||
| 				oasc.write_shift(2, 0x01C0); oasc.write_shift(4, 0x08000051); | ||||
| 				/* 2.3.8.4 lineCrMod */ | ||||
| 				oasc.write_shift(2, 0x01C3); oasc.write_shift(4, 0x100000F4); | ||||
| 				/* 2.3.13.2 shadowColor */ | ||||
| 				oasc.write_shift(2, 0x0201); oasc.write_shift(4, 0x08000051); | ||||
| 				/* 2.3.13.4 shadowCrMod */ | ||||
| 				oasc.write_shift(2, 0x0203); oasc.write_shift(4, 0x100000F4); | ||||
| 				/* 2.3.13.23 Shadow Style Boolean Properties */ | ||||
| 				oasc.write_shift(2, 0x023F); oasc.write_shift(4, 0x00030001); | ||||
| 				/* 2.3.4.44 Group Shape Boolean Properties */ | ||||
| 				oasc.write_shift(2, 0x03BF); oasc.write_shift(4, 0x00020000 | (c[0].hidden ? 2 : 0)); | ||||
| 			} | ||||
| 			/* [MS-XLS] 2.5.193 OfficeArtClientAnchorSheet */ | ||||
| 			{ | ||||
| 				oasc.l += 2; | ||||
| 				oasc.write_shift(2, 0xF010); | ||||
| 				oasc.write_shift(4, 0x12); | ||||
| 				oasc.write_shift(2, 0x3); // do not move or size with cells
 | ||||
| 				oasc.write_shift(2, c[2] + 2); oasc.l += 2; | ||||
| 				oasc.write_shift(2, c[1] + 1); oasc.l += 2; | ||||
| 				oasc.write_shift(2, c[2] + 4); oasc.l += 2; | ||||
| 				oasc.write_shift(2, c[1] + 5); oasc.l += 2; | ||||
| 			} | ||||
| 			/* [MS-XLS] 2.5.194 OfficeArtClientData */ | ||||
| 			{ | ||||
| 				oasc.l += 2; | ||||
| 				oasc.write_shift(2, 0xF011); | ||||
| 				oasc.l += 4; | ||||
| 			} | ||||
| 			oasc.l = 0x96; | ||||
| 			if(ci == 0) /* write_biff_rec(pl, 0x003C, oasc); */ _oasc = oasc; | ||||
| 			else write_biff_rec(pl, 0x00EC, oasc); | ||||
| 		} | ||||
| 		sz += 0x96; | ||||
| 
 | ||||
| 		/* [MS-XLS] 2.4.181 Obj */ | ||||
| 		{ | ||||
| 			var obj = new_buf(52); // 22 + 26 + 4
 | ||||
| 			/* [MS-XLS] 2.5.143 FtCmo */ | ||||
| 			obj.write_shift(2, 0x15); | ||||
| 			obj.write_shift(2, 0x12); | ||||
| 			obj.write_shift(2, 0x19); | ||||
| 			obj.write_shift(2, b8oid); | ||||
| 			obj.write_shift(2, 0); | ||||
| 			obj.l = 22; | ||||
| 			/* [MS-XLS] 2.5.149 FtNts */ | ||||
| 			obj.write_shift(2, 0x0D); | ||||
| 			obj.write_shift(2, 0x16); | ||||
| 			obj.write_shift(4, 0x62726272); | ||||
| 			obj.write_shift(4, 0x95374305); | ||||
| 			obj.write_shift(4, 0x80301328); | ||||
| 			obj.write_shift(4, 0x69696904 + b8oid*256); | ||||
| 			obj.write_shift(2,0); | ||||
| 			obj.write_shift(4,0); | ||||
| 			// reserved
 | ||||
| 			obj.l += 4; | ||||
| 			write_biff_rec(pl, 0x005D, obj); | ||||
| 		} | ||||
| 
 | ||||
| 		/* [MS-XLS] 2.5.195 OfficeArtClientTextbox */ | ||||
| 		{ | ||||
| 			var oact = new_buf(8); | ||||
| 			oact.l += 2; | ||||
| 			oact.write_shift(2, 0xF00D); | ||||
| 			oact.l += 4; | ||||
| 			write_biff_rec(pl, 0x00EC, oact); | ||||
| 		} | ||||
| 		sz += 8; | ||||
| 
 | ||||
| 		/* [MS-XLS] 2.4.329 TxO */ | ||||
| 		{ | ||||
| 			var txo = new_buf(18); | ||||
| 			txo.write_shift(2, 0x12); | ||||
| 			txo.l += 8; | ||||
| 			txo.write_shift(2, text.length); | ||||
| 			txo.write_shift(2, 0x10); | ||||
| 			txo.l += 4; | ||||
| 			write_biff_rec(pl, 0x01b6, txo); | ||||
| 			/* text continue record TODO: switch to wide strings */ | ||||
| 			{ | ||||
| 				var cont = new_buf(1 + text.length); | ||||
| 				cont.write_shift(1, 0); | ||||
| 				cont.write_shift(text.length, text, "sbcs"); | ||||
| 				write_biff_rec(pl, 0x003C, cont); | ||||
| 			} | ||||
| 			/* formatting continue records */ | ||||
| 			{ | ||||
| 				var conf = new_buf(0x10); | ||||
| 				conf.l += 8; | ||||
| 				conf.write_shift(2, text.length); | ||||
| 				conf.l += 6; | ||||
| 				write_biff_rec(pl, 0x003C, conf); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* 2.4.179 Note */ | ||||
| 		{ | ||||
| 			var notesh = new_buf(12 + author.length); | ||||
| 			notesh.write_shift(2, c[1]); | ||||
| 			notesh.write_shift(2, c[2]); | ||||
| 			notesh.write_shift(2, 0 | (c[0].hidden ? 0 : 2)); | ||||
| 			notesh.write_shift(2, b8oid); | ||||
| 			notesh.write_shift(2, author.length); | ||||
| 			notesh.write_shift(1, 0); | ||||
| 			notesh.write_shift(author.length, author, "sbcs"); | ||||
| 			notesh.l ++; | ||||
| 			notes.push(notesh); | ||||
| 		} | ||||
| 	}); | ||||
| 	/* [MS-ODRAW] 2.2.13 OfficeArtDgContainer */ | ||||
| 	{ | ||||
| 		var hdr = new_buf(80); | ||||
| 		hdr.write_shift(2, 0x0F); | ||||
| 		hdr.write_shift(2, 0xF002); | ||||
| 		hdr.write_shift(4, sz + hdr.length - 8); | ||||
| 		/* [MS-ODRAW] 2.2.49 OfficeArtFDG */ | ||||
| 		{ | ||||
| 			hdr.write_shift(2, 0x10); | ||||
| 			hdr.write_shift(2, 0xF008); | ||||
| 			hdr.write_shift(4, 0x08); | ||||
| 			hdr.write_shift(4, comments.length + 1); | ||||
| 			hdr.write_shift(4, b8oid); | ||||
| 		} | ||||
| 		/* [MS-ODRAW] 2.2.16 OfficeArtSpgrContainer */ | ||||
| 		{ | ||||
| 			hdr.write_shift(2, 0x0f); | ||||
| 			hdr.write_shift(2, 0xF003); | ||||
| 			hdr.write_shift(4, sz + 0x30); | ||||
| 			/* [MS-ODRAW] 2.2.14 OfficeArtSpContainer */ | ||||
| 			{ | ||||
| 				hdr.write_shift(2, 0x0f); | ||||
| 				hdr.write_shift(2, 0xF004); | ||||
| 				hdr.write_shift(4, 0x28); | ||||
| 				/* [MS-ODRAW] 2.2.38 OfficeArtFSPGR */ | ||||
| 				{ | ||||
| 					hdr.write_shift(2, 0x01); | ||||
| 					hdr.write_shift(2, 0xF009); | ||||
| 					hdr.write_shift(4, 0x10); | ||||
| 					hdr.l += 16; | ||||
| 				} | ||||
| 				/* [MS-ODRAW] 2.2.40 OfficeArtFSP */ | ||||
| 				{ | ||||
| 					hdr.write_shift(2, 0x02); | ||||
| 					hdr.write_shift(2, 0xF00A); | ||||
| 					hdr.write_shift(4, 0x08); | ||||
| 					hdr.write_shift(4, baseid); | ||||
| 					hdr.write_shift(4, 0x05); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		write_biff_rec(ba, 0x00EC, /* hdr */ _oasc ? bconcat([hdr, _oasc]) : hdr); | ||||
| 	} | ||||
| 	ba.push(pl.end()); | ||||
| 	notes.forEach(function(n) { write_biff_rec(ba, 0x001C, n); }); | ||||
| 	b8ocnts.push([baseid, comments.length + 1, b8oid]); | ||||
| 	++b8oid; | ||||
| } | ||||
| 
 | ||||
| function write_FONTS_biff8(ba, data, opts) { | ||||
| 	write_biff_rec(ba, 0x0031 /* Font */, write_Font({ | ||||
| 	write_biff_rec(ba, "Font", write_Font({ | ||||
| 		sz:12, | ||||
| 		color: {theme:1}, | ||||
| 		name: "Arial", | ||||
| @ -427,7 +128,7 @@ function write_FMTS_biff8(ba, NF/*:?SSFTable*/, opts) { | ||||
| 	if(!NF) return; | ||||
| 	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) { | ||||
| 		/*:: if(!NF) return; */ | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, 0x041E /* Format */, write_Format(i, NF[i], opts)); | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, "Format", write_Format(i, NF[i], opts)); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| @ -436,7 +137,7 @@ function write_FEAT(ba, ws) { | ||||
| 	var o = new_buf(19); | ||||
| 	o.write_shift(4, 0x867); o.write_shift(4, 0); o.write_shift(4, 0); | ||||
| 	o.write_shift(2, 3); o.write_shift(1, 1); o.write_shift(4, 0); | ||||
| 	write_biff_rec(ba, 0x0867 /* FeatHdr */, o); | ||||
| 	write_biff_rec(ba, "FeatHdr", o); | ||||
| 	/* [MS-XLS] 2.4.111 */ | ||||
| 	o = new_buf(39); | ||||
| 	o.write_shift(4, 0x868); o.write_shift(4, 0); o.write_shift(4, 0); | ||||
| @ -444,62 +145,50 @@ function write_FEAT(ba, ws) { | ||||
| 	o.write_shift(2, 1); o.write_shift(4, 4); o.write_shift(2, 0); | ||||
| 	write_Ref8U(safe_decode_range(ws['!ref']||"A1"), o); | ||||
| 	o.write_shift(4, 4); | ||||
| 	write_biff_rec(ba, 0x0868 /* Feat */, o); | ||||
| 	write_biff_rec(ba, "Feat", o); | ||||
| } | ||||
| 
 | ||||
| function write_CELLXFS_biff8(ba, opts) { | ||||
| 	for(var i = 0; i < 16; ++i) write_biff_rec(ba, 0x00e0 /* XF */, write_XF({numFmtId:0, style:true}, 0, opts)); | ||||
| 	for(var i = 0; i < 16; ++i) write_biff_rec(ba, "XF", write_XF({numFmtId:0, style:true}, 0, opts)); | ||||
| 	opts.cellXfs.forEach(function(c) { | ||||
| 		write_biff_rec(ba, 0x00e0 /* XF */, write_XF(c, 0, opts)); | ||||
| 		write_biff_rec(ba, "XF", write_XF(c, 0, opts)); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function write_ws_biff8_hlinks(ba/*:BufArray*/, ws) { | ||||
| 	for(var R=0; R<ws['!links'].length; ++R) { | ||||
| 		var HL = ws['!links'][R]; | ||||
| 		write_biff_rec(ba, 0x01b8 /* HLink */, write_HLink(HL)); | ||||
| 		if(HL[1].Tooltip) write_biff_rec(ba, 0x0800 /* HLinkTooltip */, write_HLinkTooltip(HL)); | ||||
| 		write_biff_rec(ba, "HLink", write_HLink(HL)); | ||||
| 		if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL)); | ||||
| 	} | ||||
| 	delete ws['!links']; | ||||
| } | ||||
| 
 | ||||
| function write_ws_cols_biff8(ba, cols) { | ||||
| 	if(!cols) return; | ||||
| 	var cnt = 0; | ||||
| 	cols.forEach(function(col, idx) { | ||||
| 		if(++cnt <= 256 && col) { | ||||
| 			write_biff_rec(ba, 0x007d /* ColInfo */, write_ColInfo(col_obj_w(idx, col), idx)); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, date1904/*:boolean*/) { | ||||
| function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) { | ||||
| 	var os = 16 + get_cell_style(opts.cellXfs, cell, opts); | ||||
| 	if(cell.v == null && !cell.bf) { | ||||
| 		write_biff_rec(ba, 0x0201 /* Blank */, write_XLSCell(R, C, os)); | ||||
| 		write_biff_rec(ba, "Blank", write_XLSCell(R, C, os)); | ||||
| 		return; | ||||
| 	} | ||||
| 	if(cell.bf) write_biff_rec(ba, 0x0006 /* Formula */, write_Formula(cell, R, C, opts, os)); | ||||
| 	if(cell.bf) write_biff_rec(ba, "Formula", write_Formula(cell, R, C, opts, os)); | ||||
| 	else switch(cell.t) { | ||||
| 		case 'd': case 'n': | ||||
| 			var v = cell.t == 'd' ? datenum(parseDate(cell.v, date1904), date1904) : cell.v; | ||||
| 			if(isNaN(v)) write_biff_rec(ba, 0x0205 /* BoolErr */, write_BoolErr(R, C, 0x24, os, opts, "e")); // #NUM!
 | ||||
| 			else if(!isFinite(v)) write_biff_rec(ba, 0x0205 /* BoolErr */, write_BoolErr(R, C, 0x07, os, opts, "e")); // #DIV/0!
 | ||||
| 			var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v; | ||||
| 			/* TODO: emit RK as appropriate */ | ||||
| 			else write_biff_rec(ba, 0x0203 /* Number */, write_Number(R, C, v, os, opts)); | ||||
| 			write_biff_rec(ba, "Number", write_Number(R, C, v, os, opts)); | ||||
| 			break; | ||||
| 		case 'b': case 'e': | ||||
| 			write_biff_rec(ba, 0x0205 /* BoolErr */, write_BoolErr(R, C, cell.v, os, opts, cell.t)); | ||||
| 			write_biff_rec(ba, 0x0205, write_BoolErr(R, C, cell.v, os, opts, cell.t)); | ||||
| 			break; | ||||
| 		/* TODO: codepage, sst */ | ||||
| 		case 's': case 'str': | ||||
| 			if(opts.bookSST) { | ||||
| 				var isst = get_sst_id(opts.Strings, cell.v == null ? "" : String(cell.v), opts.revStrings); | ||||
| 				write_biff_rec(ba, 0x00fd /* LabelSst */, write_LabelSst(R, C, isst, os, opts)); | ||||
| 			} else write_biff_rec(ba, 0x0204 /* Label */, write_Label(R, C, (cell.v == null ? "" : String(cell.v)).slice(0,255), os, opts)); | ||||
| 				var isst = get_sst_id(opts.Strings, cell.v, opts.revStrings); | ||||
| 				write_biff_rec(ba, "LabelSst", write_LabelSst(R, C, isst, os, opts)); | ||||
| 			} else write_biff_rec(ba, "Label", write_Label(R, C, cell.v, os, opts)); | ||||
| 			break; | ||||
| 		default: | ||||
| 			write_biff_rec(ba, 0x0201 /* Blank */, write_XLSCell(R, C, os)); | ||||
| 			write_biff_rec(ba, "Blank", write_XLSCell(R, C, os)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -509,72 +198,64 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) { | ||||
| 	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; | ||||
| 	var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/); | ||||
| 	var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/); | ||||
| 	var dense = ws["!data"] != null; | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	var b8 = opts.biff == 8; | ||||
| 	var ref/*:string*/, rr = "", cols/*:Array<string>*/ = []; | ||||
| 	var range = safe_decode_range(ws['!ref'] || "A1"); | ||||
| 	var MAX_ROWS = b8 ? 65536 : 16384; | ||||
| 	if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) { | ||||
| 		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV" + MAX_ROWS); | ||||
| 		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384"); | ||||
| 		range.e.c = Math.min(range.e.c, 0xFF); | ||||
| 		range.e.r = Math.min(range.e.r, MAX_ROWS-1); | ||||
| 		range.e.r = Math.min(range.e.c, MAX_ROWS-1); | ||||
| 	} | ||||
| 
 | ||||
| 	write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts)); | ||||
| 	/* [Uncalced] Index */ | ||||
| 	write_biff_rec(ba, 0x000d /* CalcMode */, writeuint16(1)); | ||||
| 	write_biff_rec(ba, 0x000c /* CalcCount */, writeuint16(100)); | ||||
| 	write_biff_rec(ba, 0x000f /* CalcRefMode */, writebool(true)); | ||||
| 	write_biff_rec(ba, 0x0011 /* CalcIter */, writebool(false)); | ||||
| 	write_biff_rec(ba, 0x0010 /* CalcDelta */, write_Xnum(0.001)); | ||||
| 	write_biff_rec(ba, 0x005f /* CalcSaveRecalc */, writebool(true)); | ||||
| 	write_biff_rec(ba, 0x002a /* PrintRowCol */, writebool(false)); | ||||
| 	write_biff_rec(ba, 0x002b /* PrintGrid */, writebool(false)); | ||||
| 	write_biff_rec(ba, 0x0082 /* GridSet */, writeuint16(1)); | ||||
| 	write_biff_rec(ba, 0x0080 /* Guts */, write_Guts([0,0])); | ||||
| 	write_biff_rec(ba, "CalcMode", writeuint16(1)); | ||||
| 	write_biff_rec(ba, "CalcCount", writeuint16(100)); | ||||
| 	write_biff_rec(ba, "CalcRefMode", writebool(true)); | ||||
| 	write_biff_rec(ba, "CalcIter", writebool(false)); | ||||
| 	write_biff_rec(ba, "CalcDelta", write_Xnum(0.001)); | ||||
| 	write_biff_rec(ba, "CalcSaveRecalc", writebool(true)); | ||||
| 	write_biff_rec(ba, "PrintRowCol", writebool(false)); | ||||
| 	write_biff_rec(ba, "PrintGrid", writebool(false)); | ||||
| 	write_biff_rec(ba, "GridSet", writeuint16(1)); | ||||
| 	write_biff_rec(ba, "Guts", write_Guts([0,0])); | ||||
| 	/* DefaultRowHeight WsBool [Sync] [LPr] [HorizontalPageBreaks] [VerticalPageBreaks] */ | ||||
| 	/* Header (string) */ | ||||
| 	/* Footer (string) */ | ||||
| 	write_biff_rec(ba, 0x0083 /* HCenter */, writebool(false)); | ||||
| 	write_biff_rec(ba, 0x0084 /* VCenter */, writebool(false)); | ||||
| 	write_biff_rec(ba, "HCenter", writebool(false)); | ||||
| 	write_biff_rec(ba, "VCenter", writebool(false)); | ||||
| 	/* ... */ | ||||
| 	if(b8) write_ws_cols_biff8(ba, ws["!cols"]); | ||||
| 	/* ... */ | ||||
| 	write_biff_rec(ba, 0x0200 /* Dimensions */, write_Dimensions(range, opts)); | ||||
| 	write_biff_rec(ba, 0x200, write_Dimensions(range, opts)); | ||||
| 	/* ... */ | ||||
| 
 | ||||
| 	var date1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904; | ||||
| 	if(b8) ws['!links'] = []; | ||||
| 	for(var C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C); | ||||
| 	var comments = []; | ||||
| 	var row = []; | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		if(dense) row = ws["!data"][R] || []; | ||||
| 		rr = encode_row(R); | ||||
| 		for(C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			var cell = dense ? row[C] : ws[cols[C] + rr]; | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			if(R === range.s.r) cols[C] = encode_col(C); | ||||
| 			ref = cols[C] + rr; | ||||
| 			var cell = dense ? (ws[R]||[])[C] : ws[ref]; | ||||
| 			if(!cell) continue; | ||||
| 			/* write cell */ | ||||
| 			write_ws_biff8_cell(ba, cell, R, C, opts, date1904); | ||||
| 			if(b8 && cell.l) ws['!links'].push([cols[C] + rr, cell.l]); | ||||
| 			if(cell.c) comments.push([cell.c, R, C]); | ||||
| 			write_ws_biff8_cell(ba, cell, R, C, opts); | ||||
| 			if(b8 && cell.l) ws['!links'].push([ref, cell.l]); | ||||
| 		} | ||||
| 	} | ||||
| 	var cname/*:string*/ = _sheet.CodeName || _sheet.name || s; | ||||
| 	/* ... */ | ||||
| 	if(b8) write_comments_biff8(ba, comments); else write_comments_biff2(ba, comments); | ||||
| 	if(b8) write_biff_rec(ba, "Window2", write_Window2((_WB.Views||[])[0])); | ||||
| 	/* ... */ | ||||
| 	if(b8) write_biff_rec(ba, 0x023e /* Window2 */, write_Window2((_WB.Views||[])[0])); | ||||
| 	/* ... */ | ||||
| 	if(b8 && (ws['!merges']||[]).length) write_biff_rec(ba, 0x00e5 /* MergeCells */, write_MergeCells(ws['!merges'])); | ||||
| 	if(b8 && (ws['!merges']||[]).length) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges'])); | ||||
| 	/* [LRng] *QUERYTABLE [PHONETICINFO] CONDFMTS */ | ||||
| 	if(b8) write_ws_biff8_hlinks(ba, ws); | ||||
| 	/* [DVAL] */ | ||||
| 	write_biff_rec(ba, 0x01ba /* CodeName */, write_XLUnicodeString(cname, opts)); | ||||
| 	write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts)); | ||||
| 	/* *WebPub *CellWatch [SheetExt] */ | ||||
| 	if(b8) write_FEAT(ba, ws); | ||||
| 	/* *FEAT11 *RECORD12 */ | ||||
| 	write_biff_rec(ba, 0x000a /* EOF */); | ||||
| 	write_biff_rec(ba, "EOF"); | ||||
| 	return ba.end(); | ||||
| } | ||||
| 
 | ||||
| @ -586,61 +267,59 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) { | ||||
| 	var _wb/*:WBProps*/ = /*::((*/_WB.WBProps||{/*::CodeName:"ThisWorkbook"*/}/*:: ):any)*/; | ||||
| 	var b8 = opts.biff == 8, b5 = opts.biff == 5; | ||||
| 	write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts)); | ||||
| 	if(opts.bookType == "xla") write_biff_rec(A, 0x0087 /* Addin */); | ||||
| 	write_biff_rec(A, 0x00e1 /* InterfaceHdr */, b8 ? writeuint16(0x04b0) : null); | ||||
| 	write_biff_rec(A, 0x00c1 /* Mms */, writezeroes(2)); | ||||
| 	if(b5) write_biff_rec(A, 0x00bf /* ToolbarHdr */); | ||||
| 	if(b5) write_biff_rec(A, 0x00c0 /* ToolbarEnd */); | ||||
| 	write_biff_rec(A, 0x00e2 /* InterfaceEnd */); | ||||
| 	write_biff_rec(A, 0x005c /* WriteAccess */, write_WriteAccess("SheetJS", opts)); | ||||
| 	if(opts.bookType == "xla") write_biff_rec(A, "Addin"); | ||||
| 	write_biff_rec(A, "InterfaceHdr", b8 ? writeuint16(0x04b0) : null); | ||||
| 	write_biff_rec(A, "Mms", writezeroes(2)); | ||||
| 	if(b5) write_biff_rec(A, "ToolbarHdr"); | ||||
| 	if(b5) write_biff_rec(A, "ToolbarEnd"); | ||||
| 	write_biff_rec(A, "InterfaceEnd"); | ||||
| 	write_biff_rec(A, "WriteAccess", write_WriteAccess("SheetJS", opts)); | ||||
| 	/* [FileSharing] */ | ||||
| 	write_biff_rec(A, 0x0042 /* CodePage */, writeuint16(b8 ? 0x04b0 : 0x04E4)); | ||||
| 	write_biff_rec(A, "CodePage", writeuint16(b8 ? 0x04b0 : 0x04E4)); | ||||
| 	/* *2047 Lel */ | ||||
| 	if(b8) write_biff_rec(A, 0x0161 /* DSF */, writeuint16(0)); | ||||
| 	if(b8) write_biff_rec(A, 0x01c0 /* Excel9File */); | ||||
| 	write_biff_rec(A, 0x013d /* RRTabId */, write_RRTabId(wb.SheetNames.length)); | ||||
| 	if(b8 && wb.vbaraw) write_biff_rec(A, 0x00d3 /* ObProj */); | ||||
| 	if(b8) write_biff_rec(A, "DSF", writeuint16(0)); | ||||
| 	if(b8) write_biff_rec(A, "Excel9File"); | ||||
| 	write_biff_rec(A, "RRTabId", write_RRTabId(wb.SheetNames.length)); | ||||
| 	if(b8 && wb.vbaraw) write_biff_rec(A, "ObProj"); | ||||
| 	/* [ObNoMacros] */ | ||||
| 	if(b8 && wb.vbaraw) { | ||||
| 		var cname/*:string*/ = _wb.CodeName || "ThisWorkbook"; | ||||
| 		write_biff_rec(A, 0x01ba /* CodeName */, write_XLUnicodeString(cname, opts)); | ||||
| 		write_biff_rec(A, "CodeName", write_XLUnicodeString(cname, opts)); | ||||
| 	} | ||||
| 	write_biff_rec(A, 0x009c /* BuiltInFnGroupCount */, writeuint16(0x11)); | ||||
| 	write_biff_rec(A, "BuiltInFnGroupCount", writeuint16(0x11)); | ||||
| 	/* *FnGroupName *FnGrp12 */ | ||||
| 	/* *Lbl */ | ||||
| 	/* [OleObjectSize] */ | ||||
| 	write_biff_rec(A, 0x0019 /* WinProtect */, writebool(false)); | ||||
| 	write_biff_rec(A, 0x0012 /* Protect */, writebool(false)); | ||||
| 	write_biff_rec(A, 0x0013 /* Password */, writeuint16(0)); | ||||
| 	if(b8) write_biff_rec(A, 0x01af /* Prot4Rev */, writebool(false)); | ||||
| 	if(b8) write_biff_rec(A, 0x01bc /* Prot4RevPass */, writeuint16(0)); | ||||
| 	write_biff_rec(A, 0x003d /* Window1 */, write_Window1(opts)); | ||||
| 	write_biff_rec(A, 0x0040 /* Backup */, writebool(false)); | ||||
| 	write_biff_rec(A, 0x008d /* HideObj */, writeuint16(0)); | ||||
| 	write_biff_rec(A, 0x0022 /* Date1904 */, writebool(safe1904(wb)=="true")); | ||||
| 	write_biff_rec(A, 0x000e /* CalcPrecision */, writebool(true)); | ||||
| 	if(b8) write_biff_rec(A, 0x01b7 /* RefreshAll */, writebool(false)); | ||||
| 	write_biff_rec(A, 0x00DA /* BookBool */, writeuint16(0)); | ||||
| 	write_biff_rec(A, "WinProtect", writebool(false)); | ||||
| 	write_biff_rec(A, "Protect", writebool(false)); | ||||
| 	write_biff_rec(A, "Password", writeuint16(0)); | ||||
| 	if(b8) write_biff_rec(A, "Prot4Rev", writebool(false)); | ||||
| 	if(b8) write_biff_rec(A, "Prot4RevPass", writeuint16(0)); | ||||
| 	write_biff_rec(A, "Window1", write_Window1(opts)); | ||||
| 	write_biff_rec(A, "Backup", writebool(false)); | ||||
| 	write_biff_rec(A, "HideObj", writeuint16(0)); | ||||
| 	write_biff_rec(A, "Date1904", writebool(safe1904(wb)=="true")); | ||||
| 	write_biff_rec(A, "CalcPrecision", writebool(true)); | ||||
| 	if(b8) write_biff_rec(A, "RefreshAll", writebool(false)); | ||||
| 	write_biff_rec(A, "BookBool", writeuint16(0)); | ||||
| 	/* ... */ | ||||
| 	write_FONTS_biff8(A, wb, opts); | ||||
| 	write_FMTS_biff8(A, wb.SSF, opts); | ||||
| 	write_CELLXFS_biff8(A, opts); | ||||
| 	/* ... */ | ||||
| 	if(b8) write_biff_rec(A, 0x0160 /* UsesELFs */, writebool(false)); | ||||
| 	if(b8) write_biff_rec(A, "UsesELFs", writebool(false)); | ||||
| 	var a = A.end(); | ||||
| 
 | ||||
| 	var C = buf_array(); | ||||
| 	/* METADATA [MTRSettings] [ForceFullCalculation] */ | ||||
| 	if(b8) write_biff_rec(C, 0x008C /* Country */, write_Country()); | ||||
| 	/* *SUPBOOK *LBL *RTD [RecalcId] *HFPicture */ | ||||
| 	if(b8) write_biff_rec(C, "Country", write_Country()); | ||||
| 	/* *SUPBOOK *LBL *RTD [RecalcId] *HFPicture *MSODRAWINGGROUP */ | ||||
| 
 | ||||
| 	/* BIFF8: MsoDrawingGroup [*Continue] */ | ||||
| 	if(b8 && b8ocnts.length) write_biff_rec(C, 0x00EB /* MsoDrawingGroup */, write_MsoDrawingGroup()); | ||||
| 	/* BIFF8: [SST *Continue] ExtSST */ | ||||
| 	if(b8 && opts.Strings) write_biff_continue(C, 0x00FC /* SST */, write_SST(opts.Strings, opts)); | ||||
| 	if(b8 && opts.Strings) write_biff_continue(C, "SST", write_SST(opts.Strings, opts)); | ||||
| 
 | ||||
| 	/* *WebPub [WOpt] [CrErr] [BookExt] *FeatHdr *DConn [THEME] [CompressPictures] [Compat12] [GUIDTypeLib] */ | ||||
| 	write_biff_rec(C, 0x000A /* EOF */); | ||||
| 	write_biff_rec(C, "EOF"); | ||||
| 	var c = C.end(); | ||||
| 
 | ||||
| 	var B = buf_array(); | ||||
| @ -649,7 +328,7 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) { | ||||
| 	var start = a.length + blen + c.length; | ||||
| 	for(j = 0; j < wb.SheetNames.length; ++j) { | ||||
| 		var _sheet/*:WBWSProp*/ = _sheets[j] || ({}/*:any*/); | ||||
| 		write_biff_rec(B, 0x0085 /* BoundSheet8 */, write_BoundSheet8({pos:start, hs:_sheet.Hidden||0, dt:0, name:wb.SheetNames[j]}, opts)); | ||||
| 		write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:_sheet.Hidden||0, dt:0, name:wb.SheetNames[j]}, opts)); | ||||
| 		start += bufs[j].length; | ||||
| 	} | ||||
| 	/* 1*BoundSheet8 */ | ||||
| @ -660,7 +339,7 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) { | ||||
| 	if(a.length) out.push(a); | ||||
| 	if(b.length) out.push(b); | ||||
| 	if(c.length) out.push(c); | ||||
| 	return bconcat(out); | ||||
| 	return __toBuffer([out]); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.1.7.20 Workbook Stream */ | ||||
| @ -669,16 +348,15 @@ function write_biff8_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) { | ||||
| 	var bufs = []; | ||||
| 
 | ||||
| 	if(wb && !wb.SSF) { | ||||
| 		wb.SSF = dup(table_fmt); | ||||
| 		wb.SSF = SSF.get_table(); | ||||
| 	} | ||||
| 	if(wb && wb.SSF) { | ||||
| 		make_ssf(); SSF_load_table(wb.SSF); | ||||
| 		make_ssf(SSF); SSF.load_table(wb.SSF); | ||||
| 		// $FlowIgnore
 | ||||
| 		o.revssf = evert_num(wb.SSF); o.revssf[wb.SSF[65535]] = 0; | ||||
| 		o.ssf = wb.SSF; | ||||
| 	} | ||||
| 
 | ||||
| 	b8oid = 1; b8ocnts = []; | ||||
| 	o.Strings = /*::((*/[]/*:: :any):SST)*/; o.Strings.Count = 0; o.Strings.Unique = 0; | ||||
| 	fix_write_opts(o); | ||||
| 
 | ||||
| @ -689,22 +367,10 @@ function write_biff8_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) { | ||||
| 
 | ||||
| 	for(var i = 0; i < wb.SheetNames.length; ++i) bufs[bufs.length] = write_ws_biff8(i, o, wb); | ||||
| 	bufs.unshift(write_biff8_global(wb, bufs, o)); | ||||
| 	return bconcat(bufs); | ||||
| 	return __toBuffer([bufs]); | ||||
| } | ||||
| 
 | ||||
| function write_biff_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) { | ||||
| 	for(var i = 0; i <= wb.SheetNames.length; ++i) { | ||||
| 		var ws = wb.Sheets[wb.SheetNames[i]]; | ||||
| 		if(!ws || !ws["!ref"]) continue; | ||||
| 		var range = decode_range(ws["!ref"]); | ||||
| 		if(range.e.c > 255) { // note: 255 is IV
 | ||||
| 			if(typeof console != "undefined" && console.error) console.error("Worksheet '" + wb.SheetNames[i] + "' extends beyond column IV (255).  Data may be lost."); | ||||
| 		} | ||||
| 		if(range.e.r > 65535) { | ||||
| 			if(typeof console != "undefined" && console.error) console.error("Worksheet '" + wb.SheetNames[i] + "' extends beyond row 65536.  Data may be lost."); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var o = opts || {}; | ||||
| 	switch(o.biff || 2) { | ||||
| 		case 8: case 5: return write_biff8_buf(wb, opts); | ||||
|  | ||||
							
								
								
									
										284
									
								
								bits/79_html.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										284
									
								
								bits/79_html.js
									
									
									
									
									
								
							| @ -1,150 +1,127 @@ | ||||
| /* note: browser DOM element cannot see mso- style attrs, must parse */ | ||||
| function html_to_sheet(str/*:string*/, _opts)/*:Workbook*/ { | ||||
| 	var opts = _opts || {}; | ||||
| 	var dense = (opts.dense != null) ? opts.dense : DENSE; | ||||
| 	var ws/*:Worksheet*/ = ({}/*:any*/); if(dense) ws["!data"] = []; | ||||
| 	str = str_remove_ng(str, "<!--", "-->"); | ||||
| 	var mtch/*:any*/ = str.match(/<table/i); | ||||
| 	if(!mtch) throw new Error("Invalid HTML: could not find <table>"); | ||||
| 	var mtch2/*:any*/ = str.match(/<\/table/i); | ||||
| 	var i/*:number*/ = mtch.index, j/*:number*/ = mtch2 && mtch2.index || str.length; | ||||
| 	var rows = split_regex(str.slice(i, j), /(:?<tr[^<>]*>)/i, "<tr>"); | ||||
| 	var R = -1, C = 0, RS = 0, CS = 0; | ||||
| 	var range/*:Range*/ = {s:{r:10000000, c:10000000},e:{r:0,c:0}}; | ||||
| 	var merges/*:Array<Range>*/ = []; | ||||
| 	for(i = 0; i < rows.length; ++i) { | ||||
| 		var row = rows[i].trim(); | ||||
| 		var hd = row.slice(0,3).toLowerCase(); | ||||
| 		if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; } | ||||
| 		if(hd != "<td" && hd != "<th") continue; | ||||
| 		var cells = row.split(/<\/t[dh]>/i); | ||||
| 		for(j = 0; j < cells.length; ++j) { | ||||
| 			var cell = cells[j].trim(); | ||||
| 			if(!cell.match(/<t[dh]/i)) continue; | ||||
| 			var m = cell, cc = 0; | ||||
| 			/* TODO: parse styles etc */ | ||||
| 			while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1); | ||||
| 			for(var midx = 0; midx < merges.length; ++midx) { | ||||
| 				var _merge/*:Range*/ = merges[midx]; | ||||
| 				if(_merge.s.c == C && _merge.s.r < R && R <= _merge.e.r) { C = _merge.e.c + 1; midx = -1; } | ||||
| var HTML_ = (function() { | ||||
| 	function html_to_sheet(str/*:string*/, _opts)/*:Workbook*/ { | ||||
| 		var opts = _opts || {}; | ||||
| 		if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| 		var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 		str = str.replace(/<!--.*?-->/g, ""); | ||||
| 		var mtch/*:any*/ = str.match(/<table/i); | ||||
| 		if(!mtch) throw new Error("Invalid HTML: could not find <table>"); | ||||
| 		var mtch2/*:any*/ = str.match(/<\/table/i); | ||||
| 		var i/*:number*/ = mtch.index, j/*:number*/ = mtch2 && mtch2.index || str.length; | ||||
| 		var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>"); | ||||
| 		var R = -1, C = 0, RS = 0, CS = 0; | ||||
| 		var range/*:Range*/ = {s:{r:10000000, c:10000000},e:{r:0,c:0}}; | ||||
| 		var merges/*:Array<Range>*/ = []; | ||||
| 		for(i = 0; i < rows.length; ++i) { | ||||
| 			var row = rows[i].trim(); | ||||
| 			var hd = row.slice(0,3).toLowerCase(); | ||||
| 			if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; } | ||||
| 			if(hd != "<td" && hd != "<th") continue; | ||||
| 			var cells = row.split(/<\/t[dh]>/i); | ||||
| 			for(j = 0; j < cells.length; ++j) { | ||||
| 				var cell = cells[j].trim(); | ||||
| 				if(!cell.match(/<t[dh]/i)) continue; | ||||
| 				var m = cell, cc = 0; | ||||
| 				/* TODO: parse styles etc */ | ||||
| 				while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1); | ||||
| 				for(var midx = 0; midx < merges.length; ++midx) { | ||||
| 					var _merge/*:Range*/ = merges[midx]; | ||||
| 					if(_merge.s.c == C && _merge.s.r < R && R <= _merge.e.r) { C = _merge.e.c + 1; midx = -1; } | ||||
| 				} | ||||
| 				var tag = parsexmltag(cell.slice(0, cell.indexOf(">"))); | ||||
| 				CS = tag.colspan ? +tag.colspan : 1; | ||||
| 				if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); | ||||
| 				var _t/*:string*/ = tag.t || ""; | ||||
| 				/* TODO: generate stub cells */ | ||||
| 				if(!m.length) { C += CS; continue; } | ||||
| 				m = htmldecode(m); | ||||
| 				if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R; | ||||
| 				if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C; | ||||
| 				if(!m.length) continue; | ||||
| 				var o/*:Cell*/ = {t:'s', v:m}; | ||||
| 				if(opts.raw || !m.trim().length || _t == 's'){} | ||||
| 				else if(m === 'TRUE') o = {t:'b', v:true}; | ||||
| 				else if(m === 'FALSE') o = {t:'b', v:false}; | ||||
| 				else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)}; | ||||
| 				else if(!isNaN(fuzzydate(m).getDate())) { | ||||
| 					o = ({t:'d', v:parseDate(m)}/*:any*/); | ||||
| 					if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}/*:any*/); | ||||
| 					o.z = opts.dateNF || SSF._table[14]; | ||||
| 				} | ||||
| 				if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; } | ||||
| 				else ws[encode_cell({r:R, c:C})] = o; | ||||
| 				C += CS; | ||||
| 			} | ||||
| 			var tag = parsexmltag(cell.slice(0, cell.indexOf(">"))); | ||||
| 			CS = tag.colspan ? +tag.colspan : 1; | ||||
| 			if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); | ||||
| 			var _t/*:string*/ = tag.t || tag["data-t"] || ""; | ||||
| 			/* TODO: generate stub cells */ | ||||
| 			if(!m.length) { C += CS; continue; } | ||||
| 			m = htmldecode(m); | ||||
| 			if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R; | ||||
| 			if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C; | ||||
| 			if(!m.length) { C += CS; continue; } | ||||
| 			var o/*:Cell*/ = {t:'s', v:m}; | ||||
| 			if(opts.raw || !m.trim().length || _t == 's'){} | ||||
| 			else if(m === 'TRUE') o = {t:'b', v:true}; | ||||
| 			else if(m === 'FALSE') o = {t:'b', v:false}; | ||||
| 			else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)}; | ||||
| 			else if(!isNaN(fuzzydate(m).getDate())) { | ||||
| 				o = ({t:'d', v:parseDate(m)}/*:any*/); | ||||
| 				if(opts.UTC === false) o.v = utc_to_local(o.v); | ||||
| 				if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}/*:any*/); | ||||
| 				o.z = opts.dateNF || table_fmt[14]; | ||||
| 			} else if(m.charCodeAt(0) == 35 /* # */ && RBErr[m] != null) { | ||||
| 				o.t = 'e'; o.w = m; o.v = RBErr[m]; | ||||
| 		} | ||||
| 		ws['!ref'] = encode_range(range); | ||||
| 		if(merges.length) ws["!merges"] = merges; | ||||
| 		return ws; | ||||
| 	} | ||||
| 	function html_to_book(str/*:string*/, opts)/*:Workbook*/ { | ||||
| 		return sheet_to_workbook(html_to_sheet(str, opts), opts); | ||||
| 	} | ||||
| 	function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HTMLOpts*/)/*:string*/ { | ||||
| 		var M/*:Array<Range>*/ = (ws['!merges'] ||[]); | ||||
| 		var oo/*:Array<string>*/ = []; | ||||
| 		for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 			var RS = 0, CS = 0; | ||||
| 			for(var j = 0; j < M.length; ++j) { | ||||
| 				if(M[j].s.r > R || M[j].s.c > C) continue; | ||||
| 				if(M[j].e.r < R || M[j].e.c < C) continue; | ||||
| 				if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; } | ||||
| 				RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break; | ||||
| 			} | ||||
| 			if(o.cellText !== false) o.w = m; | ||||
| 			if(dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = o; } | ||||
| 			else ws[encode_cell({r:R, c:C})] = o; | ||||
| 			C += CS; | ||||
| 			if(RS < 0) continue; | ||||
| 			var coord = encode_cell({r:R,c:C}); | ||||
| 			var cell = o.dense ? (ws[R]||[])[C] : ws[coord]; | ||||
| 			/* TODO: html entities */ | ||||
| 			var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || ""; | ||||
| 			var sp = ({}/*:any*/); | ||||
| 			if(RS > 1) sp.rowspan = RS; | ||||
| 			if(CS > 1) sp.colspan = CS; | ||||
| 			sp.t = cell && cell.t || 'z'; | ||||
| 			if(o.editable) w = '<span contenteditable="true">' + w + '</span>'; | ||||
| 			sp.id = (o.id || "sjs") + "-" + coord; | ||||
| 			if(sp.t != "z") { sp.v = cell.v; if(cell.z != null) sp.z = cell.z; } | ||||
| 			oo.push(writextag('td', w, sp)); | ||||
| 		} | ||||
| 		var preamble = "<tr>"; | ||||
| 		return preamble + oo.join("") + "</tr>"; | ||||
| 	} | ||||
| 	ws['!ref'] = encode_range(range); | ||||
| 	if(merges.length) ws["!merges"] = merges; | ||||
| 	return ws; | ||||
| } | ||||
| function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HTMLOpts*/)/*:string*/ { | ||||
| 	var M/*:Array<Range>*/ = (ws['!merges'] ||[]); | ||||
| 	var oo/*:Array<string>*/ = []; | ||||
| 	var sp = ({}/*:any*/); | ||||
| 	var dense = ws["!data"] != null; | ||||
| 	for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 		var RS = 0, CS = 0; | ||||
| 		for(var j = 0; j < M.length; ++j) { | ||||
| 			if(M[j].s.r > R || M[j].s.c > C) continue; | ||||
| 			if(M[j].e.r < R || M[j].e.c < C) continue; | ||||
| 			if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; } | ||||
| 			RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break; | ||||
| 		} | ||||
| 		if(RS < 0) continue; | ||||
| 		var coord = encode_col(C) + encode_row(R); | ||||
| 		var cell = dense ? (ws["!data"][R]||[])[C] : ws[coord]; | ||||
| 		if(cell && cell.t == 'n' && cell.v != null && !isFinite(cell.v)) { | ||||
| 			if(isNaN(cell.v)) cell = ({t:'e', v:0x24, w:BErr[0x24]}); | ||||
| 			else cell = ({t:'e', v:0x07, w:BErr[0x07]}); | ||||
| 		} | ||||
| 		/* TODO: html entities */ | ||||
| 		var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || ""; | ||||
| 		sp = ({}/*:any*/); | ||||
| 		if(RS > 1) sp.rowspan = RS; | ||||
| 		if(CS > 1) sp.colspan = CS; | ||||
| 		if(o.editable) w = '<span contenteditable="true">' + w + '</span>'; | ||||
| 		else if(cell) { | ||||
| 			sp["data-t"] = cell && cell.t || 'z'; | ||||
| 			// note: data-v is unaffected by the timezone interpretation
 | ||||
| 			if(cell.v != null) sp["data-v"] = escapehtml(cell.v instanceof Date ? cell.v.toISOString() : cell.v); | ||||
| 			if(cell.z != null) sp["data-z"] = cell.z; | ||||
| 			if(cell.f != null) sp["data-f"] = escapehtml(cell.f); | ||||
| 			if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + escapehtml(cell.l.Target) +'">' + w + '</a>'; | ||||
| 		} | ||||
| 		sp.id = (o.id || "sjs") + "-" + coord; | ||||
| 		oo.push(writextag('td', w, sp)); | ||||
| 	function make_html_preamble(ws/*:Worksheet*/, R/*:Range*/, o/*:Sheet2HTMLOpts*/)/*:string*/ { | ||||
| 		var out/*:Array<string>*/ = []; | ||||
| 		return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>'; | ||||
| 	} | ||||
| 	var preamble = "<tr>"; | ||||
| 	return preamble + oo.join("") + "</tr>"; | ||||
| } | ||||
| 	var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>'; | ||||
| 	var _END = '</body></html>'; | ||||
| 	function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workbook*/)/*:string*/ { | ||||
| 		var o = opts || {}; | ||||
| 		var header = o.header != null ? o.header : _BEGIN; | ||||
| 		var footer = o.footer != null ? o.footer : _END; | ||||
| 		var out/*:Array<string>*/ = [header]; | ||||
| 		var r = decode_range(ws['!ref']); | ||||
| 		o.dense = Array.isArray(ws); | ||||
| 		out.push(make_html_preamble(ws, r, o)); | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o)); | ||||
| 		out.push("</table>" + footer); | ||||
| 		return out.join(""); | ||||
| 
 | ||||
| var HTML_BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>'; | ||||
| var HTML_END = '</body></html>'; | ||||
| 
 | ||||
| function html_to_workbook(str/*:string*/, opts)/*:Workbook*/ { | ||||
| 	var mtch = str_match_xml_ig(str, "table"); | ||||
| 	if(!mtch || mtch.length == 0) throw new Error("Invalid HTML: could not find <table>"); | ||||
| 	if(mtch.length == 1) { | ||||
| 		var w = sheet_to_workbook(html_to_sheet(mtch[0], opts), opts); | ||||
| 		w.bookType = "html"; | ||||
| 		return w; | ||||
| 	} | ||||
| 	var wb = book_new(); | ||||
| 	mtch.forEach(function(s, idx) { book_append_sheet(wb, html_to_sheet(s, opts), "Sheet" + (idx+1)); }); | ||||
| 	wb.bookType = "html"; | ||||
| 	return wb; | ||||
| } | ||||
| 
 | ||||
| function make_html_preamble(ws/*:Worksheet*/, R/*:Range*/, o/*:Sheet2HTMLOpts*/)/*:string*/ { | ||||
| 	var out/*:Array<string>*/ = []; | ||||
| 	return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>'; | ||||
| } | ||||
| 
 | ||||
| function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workbook*/)/*:string*/ { | ||||
| 	var o = opts || {}; | ||||
| 	var header = o.header != null ? o.header : HTML_BEGIN; | ||||
| 	var footer = o.footer != null ? o.footer : HTML_END; | ||||
| 	var out/*:Array<string>*/ = [header]; | ||||
| 	var r = decode_range(ws['!ref'] || "A1"); | ||||
| 	out.push(make_html_preamble(ws, r, o)); | ||||
| 	if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o)); | ||||
| 	out.push("</table>" + footer); | ||||
| 	return out.join(""); | ||||
| } | ||||
| 	return { | ||||
| 		to_workbook: html_to_book, | ||||
| 		to_sheet: html_to_sheet, | ||||
| 		_row: make_html_row, | ||||
| 		BEGIN: _BEGIN, | ||||
| 		END: _END, | ||||
| 		_preamble: make_html_preamble, | ||||
| 		from_sheet: sheet_to_html | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ { | ||||
| 	var rows/*:HTMLCollection<HTMLTableRowElement>*/ = table.rows; | ||||
| 	if(!rows) { | ||||
| 		/* not an HTML TABLE */ | ||||
| 		throw "Unsupported origin when " + table.tagName + " is not a TABLE"; | ||||
| 	} | ||||
| 
 | ||||
| 	var opts = _opts || {}; | ||||
| 	var dense = ws["!data"] != null; | ||||
| 	if(DENSE != null) opts.dense = DENSE; | ||||
| 	var or_R = 0, or_C = 0; | ||||
| 	if(opts.origin != null) { | ||||
| 		if(typeof opts.origin == 'number') or_R = opts.origin; | ||||
| @ -153,7 +130,7 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/ | ||||
| 			or_R = _origin.r; or_C = _origin.c; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var rows/*:HTMLCollection<HTMLTableRowElement>*/ = table.getElementsByTagName('tr'); | ||||
| 	var sheetRows = Math.min(opts.sheetRows||10000000, rows.length); | ||||
| 	var range/*:Range*/ = {s:{r:0,c:0},e:{r:or_R,c:or_C}}; | ||||
| 	if(ws["!ref"]) { | ||||
| @ -174,13 +151,12 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/ | ||||
| 			if (opts.display) continue; | ||||
| 			rowinfo[R] = {hidden: true}; | ||||
| 		} | ||||
| 		var elts/*:HTMLCollection<HTMLTableCellElement>*/ = (row.cells); | ||||
| 		var elts/*:HTMLCollection<HTMLTableCellElement>*/ = (row.children/*:any*/); | ||||
| 		for(_C = C = 0; _C < elts.length; ++_C) { | ||||
| 			var elt/*:HTMLTableCellElement*/ = elts[_C]; | ||||
| 			if (opts.display && is_dom_element_hidden(elt)) continue; | ||||
| 			var v/*:?string*/ = elt.hasAttribute('data-v') ? elt.getAttribute('data-v') : elt.hasAttribute('v') ? elt.getAttribute('v') : htmldecode(elt.innerHTML); | ||||
| 			var z/*:?string*/ = elt.getAttribute('data-z') || elt.getAttribute('z'); | ||||
| 			var f/*:?string*/ = elt.hasAttribute('data-f') ? elt.getAttribute('data-f') : elt.hasAttribute('f') ? elt.getAttribute('f') : null; | ||||
| 			var v/*:?string*/ = elt.hasAttribute('v') ? elt.getAttribute('v') : htmldecode(elt.innerHTML); | ||||
| 			var z/*:?string*/ = elt.getAttribute('z'); | ||||
| 			for(midx = 0; midx < merges.length; ++midx) { | ||||
| 				var m/*:Range*/ = merges[midx]; | ||||
| 				if(m.s.c == C + or_C && m.s.r < R + or_R && R + or_R <= m.e.r) { C = m.e.c+1 - or_C; midx = -1; } | ||||
| @ -189,31 +165,21 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/ | ||||
| 			CS = +elt.getAttribute("colspan") || 1; | ||||
| 			if( ((RS = (+elt.getAttribute("rowspan") || 1)))>1 || CS>1) merges.push({s:{r:R + or_R,c:C + or_C},e:{r:R + or_R + (RS||1) - 1, c:C + or_C + (CS||1) - 1}}); | ||||
| 			var o/*:Cell*/ = {t:'s', v:v}; | ||||
| 			var _t/*:string*/ = elt.getAttribute("data-t") || elt.getAttribute("t") || ""; | ||||
| 			var _t/*:string*/ = elt.getAttribute("t") || ""; | ||||
| 			if(v != null) { | ||||
| 				if(v.length == 0) o.t = _t || 'z'; | ||||
| 				else if(opts.raw || v.trim().length == 0 || _t == "s"){} | ||||
| 				else if(_t == "e" && BErr[+v]) o = {t:'e', v:+v, w: BErr[+v]}; | ||||
| 				else if(v === 'TRUE') o = {t:'b', v:true}; | ||||
| 				else if(v === 'FALSE') o = {t:'b', v:false}; | ||||
| 				else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)}; | ||||
| 				else if(!isNaN(fuzzydate(v).getDate())) { | ||||
| 					o = ({t:'d', v:parseDate(v)}/*:any*/); | ||||
| 					if(opts.UTC) o.v = local_to_utc(o.v); | ||||
| 					if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}/*:any*/); | ||||
| 					o.z = opts.dateNF || table_fmt[14]; | ||||
| 				} else if(v.charCodeAt(0) == 35 /* # */ && RBErr[v] != null) o = ({t:'e', v: RBErr[v], w: v}); | ||||
| 					o.z = opts.dateNF || SSF._table[14]; | ||||
| 				} | ||||
| 			} | ||||
| 			if(o.z === undefined && z != null) o.z = z; | ||||
| 			/* The first link is used.  Links are assumed to be fully specified. | ||||
| 			 * TODO: The right way to process relative links is to make a new <a> */ | ||||
| 			var l = "", Aelts = elt.getElementsByTagName("A"); | ||||
| 			if(Aelts && Aelts.length) for(var Aelti = 0; Aelti < Aelts.length; ++Aelti)	if(Aelts[Aelti].hasAttribute("href")) { | ||||
| 				l = Aelts[Aelti].getAttribute("href"); if(l.charAt(0) != "#") break; | ||||
| 			} | ||||
| 			if(l && l.charAt(0) != "#" &&	l.slice(0, 11).toLowerCase() != 'javascript:') o.l = ({ Target: l }); | ||||
| 			if(f != null) o.f = f; | ||||
| 			if(dense) { if(!ws["!data"][R + or_R]) ws["!data"][R + or_R] = []; ws["!data"][R + or_R][C + or_C] = o; } | ||||
| 			if(opts.dense) { if(!ws[R + or_R]) ws[R + or_R] = []; ws[R + or_R][C + or_C] = o; } | ||||
| 			else ws[encode_cell({c:C + or_C, r:R + or_R})] = o; | ||||
| 			if(range.e.c < C + or_C) range.e.c = C + or_C; | ||||
| 			C += CS; | ||||
| @ -229,21 +195,19 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/ | ||||
| 
 | ||||
| function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ { | ||||
| 	var opts = _opts || {}; | ||||
| 	var ws/*:Worksheet*/ = ({}/*:any*/); if(opts.dense) ws["!data"] = []; | ||||
| 	var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 	return sheet_add_dom(ws, table, _opts); | ||||
| } | ||||
| 
 | ||||
| function table_to_book(table/*:HTMLElement*/, opts/*:?any*/)/*:Workbook*/ { | ||||
| 	var o = sheet_to_workbook(parse_dom_table(table, opts), opts); | ||||
| 	//o.bookType = "dom"; // TODO: define a type for this
 | ||||
| 	return o; | ||||
| 	return sheet_to_workbook(parse_dom_table(table, opts), opts); | ||||
| } | ||||
| 
 | ||||
| function is_dom_element_hidden(element/*:HTMLElement*/)/*:boolean*/ { | ||||
| 	var display/*:string*/ = ''; | ||||
| 	var get_computed_style/*:?function*/ = get_get_computed_style_function(element); | ||||
| 	if(get_computed_style) display = get_computed_style(element).getPropertyValue('display'); | ||||
| 	if(!display) display = element.style && element.style.display; | ||||
| 	if(!display) display = element.style.display; // Fallback for cases when getComputedStyle is not available (e.g. an old browser or some Node.js environments) or doesn't work (e.g. if the element is not inserted to a document)
 | ||||
| 	return display === 'none'; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,262 +1,56 @@ | ||||
| /* OpenDocument */ | ||||
| function parse_text_p(text/*:string*//*::, tag*/)/*:Array<any>*/ { | ||||
| 	/* 6.1.2 White Space Characters */ | ||||
| 	var fixed = text | ||||
| 		.replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ") | ||||
| 		.replace(/<text:s\/>/g," ") | ||||
| 		.replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); }) | ||||
| 		.replace(/<text:tab[^<>]*\/>/g,"\t") | ||||
| 		.replace(/<text:line-break\/>/g,"\n"); | ||||
| 	var v = unescapexml(fixed.replace(/<[^<>]*>/g,"")); | ||||
| var parse_content_xml = (function() { | ||||
| 
 | ||||
| 	return [v]; | ||||
| } | ||||
| 	var parse_text_p = function(text/*:string*//*::, tag*/)/*:Array<any>*/ { | ||||
| 		/* 6.1.2 White Space Characters */ | ||||
| 		var fixed = text | ||||
| 			.replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ") | ||||
| 			.replace(/<text:s\/>/g," ") | ||||
| 			.replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); }) | ||||
| 			.replace(/<text:tab[^>]*\/>/g,"\t") | ||||
| 			.replace(/<text:line-break\/>/g,"\n"); | ||||
| 		var v = unescapexml(fixed.replace(/<[^>]*>/g,"")); | ||||
| 
 | ||||
| /* Note: ODS can stick styles in content.xml or styles.xml, FODS blurs lines */ | ||||
| function parse_ods_styles(d/*:string*/, _opts, _nfm) { | ||||
| 	var number_format_map = _nfm || {}; | ||||
| 	var str = xlml_normalize(d); | ||||
| 	xlmlregex.lastIndex = 0; | ||||
| 	str = remove_doctype(str_remove_ng(str, "<!--", "-->")); | ||||
| 	var Rn, NFtag, NF = "", tNF = "", y, etpos = 0, tidx = -1, infmt = false, payload = ""; | ||||
| 	while((Rn = xlmlregex.exec(str))) { | ||||
| 		switch((Rn[3]=Rn[3].replace(/_[\s\S]*$/,""))) { | ||||
| 		/* Number Format Definitions */ | ||||
| 		case 'number-style': // <number:number-style> 16.29.2
 | ||||
| 		case 'currency-style': // <number:currency-style> 16.29.8
 | ||||
| 		case 'percentage-style': // <number:percentage-style> 16.29.10
 | ||||
| 		case 'date-style': // <number:date-style> 16.29.11
 | ||||
| 		case 'time-style': // <number:time-style> 16.29.19
 | ||||
| 		case 'text-style': // <number:text-style> 16.29.26
 | ||||
| 			if(Rn[1]==='/') { | ||||
| 				infmt = false; | ||||
| 				if(NFtag['truncate-on-overflow'] == "false") { | ||||
| 					if(NF.match(/h/)) NF = NF.replace(/h+/, "[$&]"); | ||||
| 					else if(NF.match(/m/)) NF = NF.replace(/m+/, "[$&]"); | ||||
| 					else if(NF.match(/s/)) NF = NF.replace(/s+/, "[$&]"); | ||||
| 				} | ||||
| 				number_format_map[NFtag.name] = NF; | ||||
| 				NF = ""; | ||||
| 			} else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 				infmt = true; | ||||
| 				NF = ""; | ||||
| 				NFtag = parsexmltag(Rn[0], false); | ||||
| 			} break; | ||||
| 		return [v]; | ||||
| 	}; | ||||
| 
 | ||||
| 		// LibreOffice bug https://bugs.documentfoundation.org/show_bug.cgi?id=149484
 | ||||
| 		case 'boolean-style': // <number:boolean-style> 16.29.24
 | ||||
| 			if(Rn[1]==='/') { | ||||
| 				infmt = false; | ||||
| 				number_format_map[NFtag.name] = "General"; | ||||
| 				NF = ""; | ||||
| 			} else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 				infmt = true; | ||||
| 				NF = ""; | ||||
| 				NFtag = parsexmltag(Rn[0], false); | ||||
| 			} break; | ||||
| 	var number_formats = { | ||||
| 		/* ods name: [short ssf fmt, long ssf fmt] */ | ||||
| 		day:           ["d",   "dd"], | ||||
| 		month:         ["m",   "mm"], | ||||
| 		year:          ["y",   "yy"], | ||||
| 		hours:         ["h",   "hh"], | ||||
| 		minutes:       ["m",   "mm"], | ||||
| 		seconds:       ["s",   "ss"], | ||||
| 		"am-pm":       ["A/P", "AM/PM"], | ||||
| 		"day-of-week": ["ddd", "dddd"], | ||||
| 		era:           ["e",   "ee"], | ||||
| 		/* there is no native representation of LO "Q" format */ | ||||
| 		quarter:       ["\\Qm", "m\\\"th quarter\""] | ||||
| 	}; | ||||
| 
 | ||||
| 		/* Number Format Elements */ | ||||
| 		case 'boolean': // <number:boolean> 16.29.25
 | ||||
| 			NF += "General"; // ODF spec is unfortunately underspecified here
 | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'text': // <number:text> 16.29.27
 | ||||
| 			if(Rn[1]==='/') { | ||||
| 				payload = str.slice(tidx, xlmlregex.lastIndex - Rn[0].length); | ||||
| 				// NOTE: Excel has a different interpretation of "%%" and friends
 | ||||
| 				if(payload == "%" && NFtag[0] == '<number:percentage-style') NF += "%"; | ||||
| 				else NF += '"' + payload.replace(/"/g, '""') + '"'; | ||||
| 			} else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 				tidx = xlmlregex.lastIndex; | ||||
| 			} break; | ||||
| 
 | ||||
| 
 | ||||
| 		case 'day': { // <number:day> 16.29.12
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			switch(y["style"]) { | ||||
| 				case "short": NF += "d"; break; | ||||
| 				case "long": NF += "dd"; break; | ||||
| 				default: NF += "dd"; break; // TODO: error condition
 | ||||
| 			} | ||||
| 		} break; | ||||
| 
 | ||||
| 		case 'day-of-week': { // <number:day-of-week> 16.29.16
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			switch(y["style"]) { | ||||
| 				case "short": NF += "ddd"; break; | ||||
| 				case "long": NF += "dddd"; break; | ||||
| 				default: NF += "ddd"; break; | ||||
| 			} | ||||
| 		} break; | ||||
| 
 | ||||
| 		case 'era': { // <number:era> 16.29.15 TODO: proper mapping
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			switch(y["style"]) { | ||||
| 				case "short": NF += "ee"; break; | ||||
| 				case "long": NF += "eeee"; break; | ||||
| 				default: NF += "eeee"; break; // TODO: error condition
 | ||||
| 			} | ||||
| 		} break; | ||||
| 
 | ||||
| 		case 'hours': { // <number:hours> 16.29.20
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			switch(y["style"]) { | ||||
| 				case "short": NF += "h"; break; | ||||
| 				case "long": NF += "hh"; break; | ||||
| 				default: NF += "hh"; break; // TODO: error condition
 | ||||
| 			} | ||||
| 		} break; | ||||
| 
 | ||||
| 		case 'minutes': { // <number:minutes> 16.29.21
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			switch(y["style"]) { | ||||
| 				case "short": NF += "m"; break; | ||||
| 				case "long": NF += "mm"; break; | ||||
| 				default: NF += "mm"; break; // TODO: error condition
 | ||||
| 			} | ||||
| 		} break; | ||||
| 
 | ||||
| 		case 'month': { // <number:month> 16.29.13
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			if(y["textual"]) NF += "mm"; | ||||
| 			switch(y["style"]) { | ||||
| 				case "short": NF += "m"; break; | ||||
| 				case "long": NF += "mm"; break; | ||||
| 				default: NF += "m"; break; | ||||
| 			} | ||||
| 		} break; | ||||
| 
 | ||||
| 		case 'seconds': { // <number:seconds> 16.29.22
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			switch(y["style"]) { | ||||
| 				case "short": NF += "s"; break; | ||||
| 				case "long": NF += "ss"; break; | ||||
| 				default: NF += "ss"; break; // TODO: error condition
 | ||||
| 			} | ||||
| 			if(y["decimal-places"]) NF += "." + fill("0", +y["decimal-places"]); | ||||
| 		} break; | ||||
| 
 | ||||
| 		case 'year': { // <number:year> 16.29.14
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			switch(y["style"]) { | ||||
| 				case "short": NF += "yy"; break; | ||||
| 				case "long": NF += "yyyy"; break; | ||||
| 				default: NF += "yy"; break; // TODO: error condition
 | ||||
| 			} | ||||
| 		} break; | ||||
| 
 | ||||
| 		case 'am-pm': // <number:am-pm> 16.29.23
 | ||||
| 			NF += "AM/PM"; // LO autocorrects A/P -> AM/PM
 | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'week-of-year': // <number:week-of-year> 16.29.17
 | ||||
| 		case 'quarter': // <number:quarter> 16.29.18
 | ||||
| 			console.error("Excel does not support ODS format token " + Rn[3]); | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'fill-character': // <number:fill-character> 16.29.5
 | ||||
| 			if(Rn[1]==='/') { | ||||
| 				payload = str.slice(tidx, xlmlregex.lastIndex - Rn[0].length); | ||||
| 				// NOTE: Excel has a different interpretation of "%%" and friends
 | ||||
| 				NF += '"' + payload.replace(/"/g, '""') + '"*'; | ||||
| 			} else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 				tidx = xlmlregex.lastIndex; | ||||
| 			} break; | ||||
| 
 | ||||
| 		case 'scientific-number': // <number:scientific-number> 16.29.6
 | ||||
| 			// TODO: find a mapping for all parameters
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			NF += "0." + fill("0", +y["min-decimal-places"] || +y["decimal-places"] || 2) + fill("?", +y["decimal-places"] - +y["min-decimal-places"] || 0) + "E" + (parsexmlbool(y["forced-exponent-sign"]) ? "+" : "") + fill("0", +y["min-exponent-digits"] || 2); | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'fraction': // <number:fraction> 16.29.7
 | ||||
| 			// TODO: find a mapping for all parameters
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			if(!+y["min-integer-digits"]) NF += "#"; | ||||
| 			else NF += fill("0", +y["min-integer-digits"]); | ||||
| 			NF += " "; | ||||
| 			NF += fill("?", +y["min-numerator-digits"] || 1); | ||||
| 			NF += "/"; | ||||
| 			if(+y["denominator-value"]) NF += y["denominator-value"]; | ||||
| 			else NF += fill("?", +y["min-denominator-digits"] || 1); | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'currency-symbol': // <number:currency-symbol> 16.29.9
 | ||||
| 			// TODO: localization with [$-...]
 | ||||
| 			if(Rn[1]==='/') { | ||||
| 				NF += '"' + str.slice(tidx, xlmlregex.lastIndex - Rn[0].length).replace(/"/g, '""') + '"'; | ||||
| 			} else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 				tidx = xlmlregex.lastIndex; | ||||
| 			} else NF += "$"; | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'text-properties': // <style:text-properties> 16.29.29
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			switch((y["color"]||"").toLowerCase().replace("#", "")) { | ||||
| 				case "ff0000": case "red": NF = "[Red]" + NF; break; | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'text-content': // <number:text-content> 16.29.28
 | ||||
| 			NF += "@"; | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'map': // <style:map> 16.3
 | ||||
| 			// TODO: handle more complex maps
 | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			if(unescapexml(y["condition"]) == "value()>=0") NF = number_format_map[y["apply-style-name"]] + ";" + NF; | ||||
| 			else console.error("ODS number format may be incorrect: " + y["condition"]); | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'number': // <number:number> 16.29.3
 | ||||
| 			// TODO: handle all the attributes
 | ||||
| 			if(Rn[1]==='/') break; | ||||
| 			y = parsexmltag(Rn[0], false); | ||||
| 			tNF = ""; | ||||
| 			tNF += fill("0", +y["min-integer-digits"] || 1); | ||||
| 			if(parsexmlbool(y["grouping"])) tNF = commaify(fill("#", Math.max(0, 4 - tNF.length)) + tNF); | ||||
| 			if(+y["min-decimal-places"] || +y["decimal-places"]) tNF += "."; | ||||
| 			if(+y["min-decimal-places"]) tNF += fill("0", +y["min-decimal-places"] || 1); | ||||
| 			if(+y["decimal-places"] - (+y["min-decimal-places"]||0)) tNF += fill("0", +y["decimal-places"] - (+y["min-decimal-places"]||0)); // TODO: should this be "#" ?
 | ||||
| 			NF += tNF; | ||||
| 			break; | ||||
| 
 | ||||
| 		case 'embedded-text': // <number:embedded-text> 16.29.4
 | ||||
| 			// TODO: verify interplay with grouping et al
 | ||||
| 			if(Rn[1]==='/') { | ||||
| 				if(etpos == 0) NF += '"' + str.slice(tidx, xlmlregex.lastIndex - Rn[0].length).replace(/"/g, '""') + '"'; | ||||
| 				else NF = NF.slice(0, etpos) + '"' + str.slice(tidx, xlmlregex.lastIndex - Rn[0].length).replace(/"/g, '""') + '"' + NF.slice(etpos); | ||||
| 			} else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 				tidx = xlmlregex.lastIndex; | ||||
| 				etpos = -+parsexmltag(Rn[0], false)["position"] || 0; | ||||
| 			} break; | ||||
| 
 | ||||
| 	}} | ||||
| 	return number_format_map; | ||||
| } | ||||
| 
 | ||||
| function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 	return function pcx(d/*:string*/, _opts)/*:Workbook*/ { | ||||
| 		var opts = _opts || {}; | ||||
| 		if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| 		var str = xlml_normalize(d); | ||||
| 		var state/*:Array<any>*/ = [], tmp; | ||||
| 		var tag/*:: = {}*/; | ||||
| 		var nfidx, NF = "", pidx = 0; | ||||
| 		var NFtag = {name:""}, NF = "", pidx = 0; | ||||
| 		var sheetag/*:: = {name:"", '名称':""}*/; | ||||
| 		var rowtag/*:: = {'行号':""}*/; | ||||
| 		var Sheets = {}, SheetNames/*:Array<string>*/ = []; | ||||
| 		var ws = ({}/*:any*/); if(opts.dense) ws["!data"] = []; | ||||
| 		var ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 		var Rn, q/*:: :any = ({t:"", v:null, z:null, w:"",c:[],}:any)*/; | ||||
| 		var ctag = ({value:""}/*:any*/), ctag2 = ({}/*:any*/); | ||||
| 		var textp = "", textpidx = 0, textptag/*:: = {}*/, oldtextp = "", oldtextpidx = 0; | ||||
| 		var textR = [], oldtextR = []; | ||||
| 		var ctag = ({value:""}/*:any*/); | ||||
| 		var textp = "", textpidx = 0, textptag/*:: = {}*/; | ||||
| 		var textR = []; | ||||
| 		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; | ||||
| 		var row_ol = 0; | ||||
| 		var number_format_map = _nfm || {}, styles = {}, tstyles = {}; | ||||
| 		var number_format_map = {}; | ||||
| 		var merges/*:Array<Range>*/ = [], mrange = {}, mR = 0, mC = 0; | ||||
| 		var rowinfo/*:Array<RowInfo>*/ = [], rowpeat = 1, colpeat = 1; | ||||
| 		var arrayf/*:Array<[Range, string]>*/ = []; | ||||
| 		var WB = {Names:[], WBProps:{}, Sheets:[]}; | ||||
| 		var WB = {Names:[]}; | ||||
| 		var atag = ({}/*:any*/); | ||||
| 		var _Ref/*:[string, string]*/ = ["", ""]; | ||||
| 		var comments/*:Array<Comment>*/ = [], comment/*:Comment*/ = ({}/*:any*/); | ||||
| @ -264,8 +58,8 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 		var isstub = false, intable = false; | ||||
| 		var i = 0; | ||||
| 		xlmlregex.lastIndex = 0; | ||||
| 		str = remove_doctype(str_remove_ng(str, "<!--", "-->")); | ||||
| 		while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_[\s\S]*$/,""))) { | ||||
| 		str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,""); | ||||
| 		while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) { | ||||
| 
 | ||||
| 			case 'table': case '工作表': // 9.1.2 <table:table>
 | ||||
| 				if(Rn[1]==='/') { | ||||
| @ -282,17 +76,13 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 					if(typeof JSON !== 'undefined') JSON.stringify(sheetag); | ||||
| 					SheetNames.push(sheetag.name); | ||||
| 					Sheets[sheetag.name] = ws; | ||||
| 					WB.Sheets.push({ | ||||
| 						/* TODO: CodeName */ | ||||
| 						Hidden: (tstyles[sheetag["style-name"]] && tstyles[sheetag["style-name"]]["display"] ? (parsexmlbool(tstyles[sheetag["style-name"]]["display"]) ? 0 : 1) : 0) | ||||
| 					}); | ||||
| 					intable = false; | ||||
| 				} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 					sheetag = parsexmltag(Rn[0], false); | ||||
| 					R = C = -1; | ||||
| 					range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0; | ||||
| 					ws = ({}/*:any*/); if(opts.dense) ws["!data"] = []; merges = []; | ||||
| 					ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/); merges = []; | ||||
| 					rowinfo = []; | ||||
| 					intable = true; | ||||
| 				} | ||||
| @ -310,18 +100,10 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 				if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol}; | ||||
| 				C = -1; break; | ||||
| 			case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
 | ||||
| 				if(Rn[1] !== '/') { | ||||
| 					++C; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					colpeat = parseInt(ctag['number-columns-repeated']||"1",10) || 1; | ||||
| 					if(opts.sheetStubs) { | ||||
| 						while(colpeat-- > 0) { | ||||
| 							if(opts.dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = {t:'z'}; } | ||||
| 							else ws[encode_cell({r:R,c:C})] = {t:'z'}; | ||||
| 							++C; | ||||
| 						} --C; | ||||
| 					} | ||||
| 					else C += colpeat - 1; | ||||
| 				if(Rn[1] !== '/') ++C; | ||||
| 				if(opts.sheetStubs) { | ||||
| 					if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; } | ||||
| 					else ws[encode_cell({r:R,c:C})] = {t:'z'}; | ||||
| 				} | ||||
| 				textp = ""; textR = []; | ||||
| 				break; /* stub */ | ||||
| @ -329,23 +111,21 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 				if(Rn[0].charAt(Rn[0].length-2) === '/') { | ||||
| 					++C; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					colpeat = parseInt(ctag['number-columns-repeated']||"1", 10)||1; | ||||
| 					colpeat = parseInt(ctag['number-columns-repeated']||"1", 10); | ||||
| 					q = ({t:'z', v:null/*:: , z:null, w:"",c:[]*/}/*:any*/); | ||||
| 					if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula)); | ||||
| 					if(ctag["style-name"] && styles[ctag["style-name"]]) q.z = styles[ctag["style-name"]]; | ||||
| 					if((ctag['数据类型'] || ctag['value-type']) == "string") { | ||||
| 						q.t = "s"; q.v = unescapexml(ctag['string-value'] || ""); | ||||
| 						if(opts.dense) { | ||||
| 							if(!ws["!data"][R]) ws["!data"][R] = []; | ||||
| 							ws["!data"][R][C] = q; | ||||
| 							if(!ws[R]) ws[R] = []; | ||||
| 							ws[R][C] = q; | ||||
| 						} else { | ||||
| 							ws[encode_col(C) + encode_row(R)] = q; | ||||
| 							ws[encode_cell({r:R,c:C})] = q; | ||||
| 						} | ||||
| 					} | ||||
| 					C+= colpeat-1; | ||||
| 				} else if(Rn[1]!=='/') { | ||||
| 					++C; | ||||
| 					textp = oldtextp = ""; textpidx = oldtextpidx = 0; textR = []; oldtextR = []; | ||||
| 					colpeat = 1; | ||||
| 					var rptR = rowpeat ? R + rowpeat - 1 : R; | ||||
| 					if(C > range.e.c) range.e.c = C; | ||||
| @ -353,10 +133,8 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 					if(R < range.s.r) range.s.r = R; | ||||
| 					if(rptR > range.e.r) range.e.r = rptR; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					ctag2 = parsexmltagraw(Rn[0], true); | ||||
| 					comments = []; comment = ({}/*:any*/); | ||||
| 					q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:"",c:[]*/}/*:any*/); | ||||
| 					if(ctag["style-name"] && styles[ctag["style-name"]]) q.z = styles[ctag["style-name"]]; | ||||
| 					if(opts.cellFormula) { | ||||
| 						if(ctag.formula) ctag.formula = unescapexml(ctag.formula); | ||||
| 						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) { | ||||
| @ -373,34 +151,26 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 									q.F = arrayf[i][1]; | ||||
| 					} | ||||
| 					if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) { | ||||
| 						mR = parseInt(ctag['number-rows-spanned']||"1",10) || 1; | ||||
| 						mC = parseInt(ctag['number-columns-spanned']||"1",10) || 1; | ||||
| 						if(mR * mC > 1) { | ||||
| 							mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; | ||||
| 							merges.push(mrange); | ||||
| 						} | ||||
| 						mR = parseInt(ctag['number-rows-spanned'],10) || 0; | ||||
| 						mC = parseInt(ctag['number-columns-spanned'],10) || 0; | ||||
| 						mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; | ||||
| 						merges.push(mrange); | ||||
| 					} | ||||
| 
 | ||||
| 					/* 19.675.2 table:number-columns-repeated */ | ||||
| 					if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10); | ||||
| 
 | ||||
| 					/* 19.385 office:value-type TODO: verify ODS and UOS */ | ||||
| 					/* 19.385 office:value-type */ | ||||
| 					switch(q.t) { | ||||
| 						case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']) || (+ctag['boolean-value'] >= 1); break; | ||||
| 						case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); | ||||
| 							if(opts.cellDates && q.z && fmt_is_date(q.z)) { q.v = numdate(q.v + (WB.WBProps.date1904 ? 1462 : 0)); q.t = typeof q.v == "number" ? 'n' : 'd'; } | ||||
| 							break; | ||||
| 						case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break; | ||||
| 						case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value'], WB.WBProps.date1904); | ||||
| 							if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v, WB.WBProps.date1904); } | ||||
| 							if(!q.z) q.z = 'm/d/yy'; break; | ||||
| 						/* NOTE: for `time`, Excel ODS export incorrectly uses durations relative to 1900 epoch even if 1904 is specified */ | ||||
| 						case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; | ||||
| 							if(opts.cellDates) { q.v = numdate(q.v); q.t = typeof q.v == "number" ? 'n' : 'd'; } | ||||
| 							if(!q.z) q.z = 'HH:MM:SS'; break; | ||||
| 						case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); | ||||
| 							break; | ||||
| 						case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']); | ||||
| 							if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); } | ||||
| 							q.z = 'm/d/yy'; break; | ||||
| 						case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break; | ||||
| 						case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break; | ||||
| 						default: | ||||
| 							if(q.t === 'string' || q.t === 'text' || !q.t) { | ||||
| 								q.t = 's'; | ||||
| @ -409,9 +179,6 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 					} | ||||
| 				} else { | ||||
| 					isstub = false; | ||||
| 					if(ctag2['calcext:value-type'] == "error" && RBErr[textp] != null) { | ||||
| 						q.t = 'e'; q.w = textp; q.v = RBErr[textp]; | ||||
| 					} | ||||
| 					if(q.t === 's') { | ||||
| 						q.v = textp || ''; | ||||
| 						if(textR.length) q.R = textR; | ||||
| @ -426,9 +193,9 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 							for(var rpt = 0; rpt < rowpeat; ++rpt) { | ||||
| 								colpeat = parseInt(ctag['number-columns-repeated']||"1", 10); | ||||
| 								if(opts.dense) { | ||||
| 									if(!ws["!data"][R + rpt]) ws["!data"][R + rpt] = []; | ||||
| 									ws["!data"][R + rpt][C] = rpt == 0 ? q : dup(q); | ||||
| 									while(--colpeat > 0) ws["!data"][R + rpt][C + colpeat] = dup(q); | ||||
| 									if(!ws[R + rpt]) ws[R + rpt] = []; | ||||
| 									ws[R + rpt][C] = rpt == 0 ? q : dup(q); | ||||
| 									while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q); | ||||
| 								} else { | ||||
| 									ws[encode_cell({r:R + rpt,c:C})] = q; | ||||
| 									while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q); | ||||
| @ -452,7 +219,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 			case 'scripts': // 3.12 <office:scripts>
 | ||||
| 			case 'styles': // TODO <office:styles>
 | ||||
| 			case 'font-face-decls': // 3.14 <office:font-face-decls>
 | ||||
| 			case 'master-styles': // 3.15.4 <office:master-styles> -- relevant for FODS
 | ||||
| 			case 'master-styles': //3.15.4 <office:master-styles> -- relevant for FODS
 | ||||
| 				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]); | ||||
| 				break; | ||||
| @ -464,17 +231,10 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 					if(textR.length) /*::(*/comment/*:: :any)*/.R = textR; | ||||
| 					comment.a = creator; | ||||
| 					comments.push(comment); | ||||
| 					textp = oldtextp; textpidx = oldtextpidx; textR = oldtextR; | ||||
| 				} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 					state.push([Rn[3], false]); | ||||
| 					var annotag = parsexmltag(Rn[0], true); | ||||
| 					/* office:display TODO: check if there is a global override */ | ||||
| 					if(!(annotag["display"] && parsexmlbool(annotag["display"]))) comments.hidden = true; | ||||
| 					oldtextp = textp; oldtextpidx = textpidx; oldtextR = textR; | ||||
| 					textp = ""; textpidx = 0; textR = []; | ||||
| 				} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);} | ||||
| 				creator = ""; creatoridx = 0; | ||||
| 				textp = ""; textpidx = 0; textR = []; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'creator': // 4.3.2.7 <dc:creator>
 | ||||
| @ -504,24 +264,23 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 				textp = ""; textpidx = 0; textR = []; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'scientific-number': // <number:scientific-number>
 | ||||
| 			case 'currency-symbol': // <number:currency-symbol>
 | ||||
| 			case 'fill-character': // 16.29.5 <number:fill-character>
 | ||||
| 			case 'scientific-number': // TODO: <number:scientific-number>
 | ||||
| 				break; | ||||
| 			case 'currency-symbol': // TODO: <number:currency-symbol>
 | ||||
| 				break; | ||||
| 			case 'currency-style': // TODO: <number:currency-style>
 | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'text-style': // 16.27.25 <number:text-style>
 | ||||
| 			case 'boolean-style': // 16.27.23 <number:boolean-style>
 | ||||
| 			case 'number-style': // 16.27.2 <number:number-style>
 | ||||
| 			case 'currency-style': // 16.29.8 <number:currency-style>
 | ||||
| 			case 'percentage-style': // 16.27.9 <number:percentage-style>
 | ||||
| 			case 'date-style': // 16.27.10 <number:date-style>
 | ||||
| 			case 'time-style': // 16.27.18 <number:time-style>
 | ||||
| 				if(Rn[1]==='/'){ | ||||
| 					var xlmlidx = xlmlregex.lastIndex; | ||||
| 					parse_ods_styles(str.slice(nfidx, xlmlregex.lastIndex), _opts, number_format_map); | ||||
| 					xlmlregex.lastIndex = xlmlidx; | ||||
| 					number_format_map[NFtag.name] = NF; | ||||
| 					if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp; | ||||
| 				} else if(Rn[0].charAt(Rn[0].length-2) !== '/') { | ||||
| 					nfidx = xlmlregex.lastIndex - Rn[0].length; | ||||
| 					NF = ""; | ||||
| 					NFtag = parsexmltag(Rn[0], false); | ||||
| 					state.push([Rn[3], true]); | ||||
| 				} break; | ||||
| 
 | ||||
| 			case 'script': break; // 3.13 <office:script>
 | ||||
| @ -530,25 +289,24 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 
 | ||||
| 			case 'default-style': // TODO: <style:default-style>
 | ||||
| 			case 'page-layout': break; // TODO: <style:page-layout>
 | ||||
| 			case 'style': { // 16.2 <style:style>
 | ||||
| 				var styletag = parsexmltag(Rn[0], false); | ||||
| 				if(styletag["family"] == "table-cell" && number_format_map[styletag["data-style-name"]]) styles[styletag["name"]] = number_format_map[styletag["data-style-name"]]; | ||||
| 				else if(styletag["family"] == "table") tstyles[styletag["name"]] = styletag; | ||||
| 			} break; | ||||
| 			case 'style': // 16.2 <style:style>
 | ||||
| 				break; | ||||
| 			case 'map': break; // 16.3 <style:map>
 | ||||
| 			case 'font-face': break; // 16.21 <style:font-face>
 | ||||
| 
 | ||||
| 			case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
 | ||||
| 			case 'table-properties': { // 17.15 <style:table-properties>
 | ||||
| 				var proptag = parsexmltag(Rn[0], false); | ||||
| 				if(styletag && styletag.family == "table") styletag.display = proptag.display; | ||||
| 			} break; | ||||
| 			case 'table-properties': break; // 17.15 <style:table-properties>
 | ||||
| 			case 'table-column-properties': break; // 17.16 <style:table-column-properties>
 | ||||
| 			case 'table-row-properties': break; // 17.17 <style:table-row-properties>
 | ||||
| 			case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
 | ||||
| 
 | ||||
| 			case 'number': // 16.27.3 <number:number>
 | ||||
| 				break; | ||||
| 				switch(state[state.length-1][0]) { | ||||
| 					case 'time-style': | ||||
| 					case 'date-style': | ||||
| 						tag = parsexmltag(Rn[0], false); | ||||
| 						NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break; | ||||
| 				} break; | ||||
| 
 | ||||
| 			case 'fraction': break; // TODO 16.27.6 <number:fraction>
 | ||||
| 
 | ||||
| @ -563,9 +321,16 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 			case 'minutes': // 16.27.20 <number:minutes>
 | ||||
| 			case 'seconds': // 16.27.21 <number:seconds>
 | ||||
| 			case 'am-pm': // 16.27.22 <number:am-pm>
 | ||||
| 				break; | ||||
| 				switch(state[state.length-1][0]) { | ||||
| 					case 'time-style': | ||||
| 					case 'date-style': | ||||
| 						tag = parsexmltag(Rn[0], false); | ||||
| 						NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break; | ||||
| 				} break; | ||||
| 
 | ||||
| 			case 'boolean-style': break; // 16.27.23 <number:boolean-style>
 | ||||
| 			case 'boolean': break; // 16.27.24 <number:boolean>
 | ||||
| 			case 'text-style': break; // 16.27.25 <number:text-style>
 | ||||
| 			case 'text': // 16.27.26 <number:text>
 | ||||
| 				if(Rn[0].slice(-2) === "/>") break; | ||||
| 				else if(Rn[1]==="/") switch(state[state.length-1][0]) { | ||||
| @ -601,12 +366,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 			case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
 | ||||
| 			case 'table-columns': break; // 9.1.12 <table:table-columns>
 | ||||
| 
 | ||||
| 			case 'null-date': // 9.4.2 <table:null-date>
 | ||||
| 				tag = parsexmltag(Rn[0], false); | ||||
| 				switch(tag["date-value"]) { | ||||
| 					case "1904-01-01": WB.WBProps.date1904 = true; break; | ||||
| 				} | ||||
| 				break; | ||||
| 			case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
 | ||||
| 
 | ||||
| 			case 'graphic-properties': break; // 17.21 <style:graphic-properties>
 | ||||
| 			case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
 | ||||
| @ -626,9 +386,6 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 				if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) { | ||||
| 					var ptp = parse_text_p(str.slice(textpidx,Rn.index), textptag); | ||||
| 					textp = (textp.length > 0 ? textp + "\n" : "") + ptp[0]; | ||||
| 				} else if(Rn[0].slice(-2) == "/>") { | ||||
| 					/* TODO: is self-closing 文本串 valid? */ | ||||
| 					textp += "\n"; | ||||
| 				} else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; } | ||||
| 				break; // <text:p>
 | ||||
| 			case 's': break; // <text:s>
 | ||||
| @ -658,13 +415,10 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 			case 'help-message': break; // 9.4.6 <table:
 | ||||
| 			case 'error-message': break; // 9.4.7 <table:
 | ||||
| 			case 'database-ranges': break; // 9.4.14 <table:database-ranges>
 | ||||
| 
 | ||||
| 			/* 9.5 Filters */ | ||||
| 			case 'filter': break; // 9.5.2 <table:filter>
 | ||||
| 			case 'filter-and': break; // 9.5.3 <table:filter-and>
 | ||||
| 			case 'filter-or': break; // 9.5.4 <table:filter-or>
 | ||||
| 			case 'filter-condition': break; // 9.5.5 <table:filter-condition>
 | ||||
| 			case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
 | ||||
| 
 | ||||
| 			case 'list-level-style-bullet': break; // 16.31 <text:
 | ||||
| 			case 'list-level-style-number': break; // 16.32 <text:
 | ||||
| @ -759,11 +513,11 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 				if(Rn[1]!== '/') { | ||||
| 					atag = parsexmltag(Rn[0], false); | ||||
| 					if(!atag.href) break; | ||||
| 					atag.Target = unescapexml(atag.href); delete atag.href; | ||||
| 					atag.Target = atag.href; delete atag.href; | ||||
| 					if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) { | ||||
| 						_Ref = ods_to_csf_3D(atag.Target.slice(1)); | ||||
| 						atag.Target = "#" + _Ref[0] + "!" + _Ref[1]; | ||||
| 					} else if(atag.Target.match(/^\.\.[\\\/]/)) atag.Target = atag.Target.slice(3); | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| @ -795,22 +549,20 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ { | ||||
| 		}/*:any*/); | ||||
| 		if(opts.bookSheets) delete /*::(*/out/*:: :any)*/.Sheets; | ||||
| 		return out; | ||||
| } | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	opts = opts || ({}/*:any*/); | ||||
| 	if(safegetzipfile(zip, 'META-INF/manifest.xml')) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts); | ||||
| 	var styles = getzipstr(zip, 'styles.xml'); | ||||
| 	var Styles = styles && parse_ods_styles(utf8read(styles), opts); | ||||
| 	var ods = !!safegetzipfile(zip, 'objectdata'); | ||||
| 	if(ods) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts); | ||||
| 	var content = getzipstr(zip, 'content.xml'); | ||||
| 	if(!content) throw new Error("Missing content.xml in ODS / UOF file"); | ||||
| 	var wb = parse_content_xml(utf8read(content), opts, Styles); | ||||
| 	if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file"); | ||||
| 	var wb = parse_content_xml(ods ? content : utf8read(content), opts); | ||||
| 	if(safegetzipfile(zip, 'meta.xml')) wb.Props = parse_core_props(getzipdata(zip, 'meta.xml')); | ||||
| 	wb.bookType = "ods"; | ||||
| 	return wb; | ||||
| } | ||||
| function parse_fods(data/*:string*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var wb = parse_content_xml(data, opts); | ||||
| 	wb.bookType = "fods"; | ||||
| 	return wb; | ||||
| 	return parse_content_xml(data, opts); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,16 +1,5 @@ | ||||
| /* OpenDocument */ | ||||
| var write_styles_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function() { | ||||
| 	var master_styles = [ | ||||
| 		'<office:master-styles>', | ||||
| 			'<style:master-page style:name="mp1" style:page-layout-name="mp1">', | ||||
| 				'<style:header/>', | ||||
| 				'<style:header-left style:display="false"/>', | ||||
| 				'<style:footer/>', | ||||
| 				'<style:footer-left style:display="false"/>', | ||||
| 			'</style:master-page>', | ||||
| 		'</office:master-styles>' | ||||
| 	].join(""); | ||||
| 
 | ||||
| var write_styles_ods/*:{(wb:any, opts:any):string}*/ = (function() { | ||||
| 	var payload = '<office:document-styles ' + wxt_helper({ | ||||
| 		'xmlns:office':   "urn:oasis:names:tc:opendocument:xmlns:office:1.0", | ||||
| 		'xmlns:table':    "urn:oasis:names:tc:opendocument:xmlns:table:1.0", | ||||
| @ -24,213 +13,33 @@ var write_styles_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function( | ||||
| 		'xmlns:svg':      "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", | ||||
| 		'xmlns:of':       "urn:oasis:names:tc:opendocument:xmlns:of:1.2", | ||||
| 		'office:version': "1.2" | ||||
| 	}) + '>' + master_styles + '</office:document-styles>'; | ||||
| 
 | ||||
| 	}) + '></office:document-styles>'; | ||||
| 	return function wso(/*::wb, opts*/) { | ||||
| 		return XML_HEADER + payload; | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| // TODO: find out if anyone actually read the spec.  LO has some wild errors
 | ||||
| function write_number_format_ods(nf/*:string*/, nfidx/*:string*/)/*:string*/ { | ||||
| 	var type = "number", payload = "", nopts = { "style:name": nfidx }, c = "", i = 0; | ||||
| 	nf = nf.replace(/"[$]"/g, "$"); | ||||
| 	/* TODO: replace with an actual parser based on a real grammar */ | ||||
| 	j: { | ||||
| 		// TODO: support style maps
 | ||||
| 		if(nf.indexOf(";") > -1) { | ||||
| 			console.error("Unsupported ODS Style Map exported.  Using first branch of " + nf); | ||||
| 			nf = nf.slice(0, nf.indexOf(";")); | ||||
| 		} | ||||
| 
 | ||||
| 		if(nf == "@") { type = "text"; payload = "<number:text-content/>"; break j; } | ||||
| 
 | ||||
| 		/* currency flag */ | ||||
| 		if(nf.indexOf(/\$/) > -1) { type = "currency"; } | ||||
| 
 | ||||
| 		/* opening string literal */ | ||||
| 		if(nf[i] == '"') { | ||||
| 			c = ""; | ||||
| 			while(nf[++i] != '"' || nf[++i] == '"') c += nf[i]; --i; | ||||
| 			if(nf[i+1] == "*") { | ||||
| 				i++; | ||||
| 				payload += '<number:fill-character>' + escapexml(c.replace(/""/g, '"')) + '</number:fill-character>'; | ||||
| 			} else { | ||||
| 				payload += '<number:text>' + escapexml(c.replace(/""/g, '"')) + '</number:text>'; | ||||
| 			} | ||||
| 			nf = nf.slice(i+1); i = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		/* fractions */ | ||||
| 		var t = nf.match(/# (\?+)\/(\?+)/); | ||||
| 		if(t) { payload += writextag("number:fraction", null, {"number:min-integer-digits":0, "number:min-numerator-digits": t[1].length, "number:max-denominator-value": Math.max(+(t[1].replace(/./g, "9")), +(t[2].replace(/./g, "9"))) }); break j; } | ||||
| 		if((t=nf.match(/# (\?+)\/(\d+)/))) { payload += writextag("number:fraction", null, {"number:min-integer-digits":0, "number:min-numerator-digits": t[1].length, "number:denominator-value": +t[2]}); break j; } | ||||
| 
 | ||||
| 		/* percentages */ | ||||
| 		if((t=nf.match(/\b(\d+)(|\.\d+)%/))) { type = "percentage"; payload += writextag("number:number", null, {"number:decimal-places": t[2] && t.length - 1 || 0, "number:min-decimal-places": t[2] && t.length - 1 || 0, "number:min-integer-digits": t[1].length }) + "<number:text>%</number:text>"; break j; } | ||||
| 
 | ||||
| 		/* datetime */ | ||||
| 		var has_time = false; | ||||
| 		if(["y","m","d"].indexOf(nf[0]) > -1) { | ||||
| 			type = "date"; | ||||
| 			k: for(; i < nf.length; ++i) switch((c = nf[i].toLowerCase())) { | ||||
| 				case "h": case "s": has_time = true; --i; break k; | ||||
| 				case "m": | ||||
| 					l: for(var h = i+1; h < nf.length; ++h) switch(nf[h]) { | ||||
| 						case "y": case "d": break l; | ||||
| 						case "h": case "s": has_time = true; --i; break k; | ||||
| 					} | ||||
| 					/* falls through */ | ||||
| 				case "y": case "d": | ||||
| 					while((nf[++i]||"").toLowerCase() == c[0]) c += c[0]; --i; | ||||
| 					switch(c) { | ||||
| 						case "y": case "yy": payload += "<number:year/>"; break; | ||||
| 						case "yyy": case "yyyy": payload += '<number:year number:style="long"/>'; break; | ||||
| 						case "mmmmm": console.error("ODS has no equivalent of format |mmmmm|"); | ||||
| 							/* falls through */ | ||||
| 						case "m": case "mm": case "mmm": case "mmmm": | ||||
| 							payload += '<number:month number:style="' + (c.length % 2 ? "short" : "long") + '" number:textual="' + (c.length >= 3 ? "true" : "false") + '"/>'; | ||||
| 							break; | ||||
| 						case "d": case "dd": payload += '<number:day number:style="' + (c.length % 2 ? "short" : "long") + '"/>'; break; | ||||
| 						case "ddd": case "dddd": payload += '<number:day-of-week number:style="' + (c.length % 2 ? "short" : "long") + '"/>'; break; | ||||
| 					} | ||||
| 					break; | ||||
| 				case '"': | ||||
| 					while(nf[++i] != '"' || nf[++i] == '"') c += nf[i]; --i; | ||||
| 					payload += '<number:text>' + escapexml(c.slice(1).replace(/""/g, '"')) + '</number:text>'; | ||||
| 					break; | ||||
| 				case '\\': c = nf[++i]; | ||||
| 					payload += '<number:text>' + escapexml(c) + '</number:text>'; break; | ||||
| 				case '/': case ':': payload += '<number:text>' + escapexml(c) + '</number:text>'; break; | ||||
| 				default: console.error("unrecognized character " + c + " in ODF format " + nf); | ||||
| 			} | ||||
| 			if(!has_time) break j; | ||||
| 			nf = nf.slice(i+1); i = 0; | ||||
| 		} | ||||
| 		if(nf.match(/^\[?[hms]/)) { | ||||
| 			if(type == "number") type = "time"; | ||||
| 			if(nf.match(/\[/)) { | ||||
| 				nf = nf.replace(/[\[\]]/g, ""); | ||||
| 				nopts['number:truncate-on-overflow'] = "false"; | ||||
| 			} | ||||
| 			for(; i < nf.length; ++i) switch((c = nf[i].toLowerCase())) { | ||||
| 				case "h": case "m": case "s": | ||||
| 					while((nf[++i]||"").toLowerCase() == c[0]) c += c[0]; --i; | ||||
| 					switch(c) { | ||||
| 						case "h": case "hh": payload += '<number:hours number:style="' + (c.length % 2 ? "short" : "long") + '"/>'; break; | ||||
| 						case "m": case "mm": payload += '<number:minutes number:style="' + (c.length % 2 ? "short" : "long") + '"/>'; break; | ||||
| 						case "s": case "ss": | ||||
| 							if(nf[i+1] == ".") do { c += nf[i+1]; ++i; } while(nf[i+1] == "0"); | ||||
| 							payload += '<number:seconds number:style="' + (c.match("ss") ? "long" : "short") + '"' + (c.match(/\./) ? ' number:decimal-places="' + (c.match(/0+/)||[""])[0].length + '"' : "")+ '/>'; break; | ||||
| 					} | ||||
| 					break; | ||||
| 				case '"': | ||||
| 					while(nf[++i] != '"' || nf[++i] == '"') c += nf[i]; --i; | ||||
| 					payload += '<number:text>' + escapexml(c.slice(1).replace(/""/g, '"')) + '</number:text>'; | ||||
| 					break; | ||||
| 				case '/': case ':': payload += '<number:text>' + escapexml(c) + '</number:text>'; break; | ||||
| 				case "a": | ||||
| 					if(nf.slice(i, i+3).toLowerCase() == "a/p") { payload += '<number:am-pm/>'; i += 2; break; } // Note: ODF does not support A/P
 | ||||
| 					if(nf.slice(i, i+5).toLowerCase() == "am/pm")  { payload += '<number:am-pm/>'; i += 4; break; } | ||||
| 					/* falls through */ | ||||
| 				default: console.error("unrecognized character " + c + " in ODF format " + nf); | ||||
| 			} | ||||
| 			break j; | ||||
| 		} | ||||
| 
 | ||||
| 		/* currency flag */ | ||||
| 		if(nf.indexOf(/\$/) > -1) { type = "currency"; } | ||||
| 
 | ||||
| 		/* should be in a char loop */ | ||||
| 		if(nf[0] == "$") { payload += '<number:currency-symbol number:language="en" number:country="US">$</number:currency-symbol>'; nf = nf.slice(1); i = 0; } | ||||
| 		i = 0; if(nf[i] == '"') { | ||||
| 			while(nf[++i] != '"' || nf[++i] == '"') c += nf[i]; --i; | ||||
| 			if(nf[i+1] == "*") { | ||||
| 				i++; | ||||
| 				payload += '<number:fill-character>' + escapexml(c.replace(/""/g, '"')) + '</number:fill-character>'; | ||||
| 			} else { | ||||
| 				payload += '<number:text>' + escapexml(c.replace(/""/g, '"')) + '</number:text>'; | ||||
| 			} | ||||
| 			nf = nf.slice(i+1); i = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		/* number TODO: interstitial text e.g. 000)000-0000 */ | ||||
| 		var np = nf.match(/([#0][0#,]*)(\.[0#]*|)(E[+]?0*|)/i); | ||||
| 		if(!np || !np[0]) console.error("Could not find numeric part of " + nf); | ||||
| 		else { | ||||
| 			var base = np[1].replace(/,/g, ""); | ||||
| 			payload += '<number:' + (np[3] ? "scientific-" : "")+ 'number' + | ||||
| 				' number:min-integer-digits="' + (base.indexOf("0") == -1 ? "0" : base.length - base.indexOf("0")) + '"' + | ||||
| 				(np[0].indexOf(",") > -1 ? ' number:grouping="true"' : "") + | ||||
| 				(np[2] && ' number:decimal-places="' + (np[2].length - 1) + '"' || ' number:decimal-places="0"') + | ||||
| 				(np[3] && np[3].indexOf("+") > -1 ? ' number:forced-exponent-sign="true"' : "" ) + | ||||
| 				(np[3] ? ' number:min-exponent-digits="' + np[3].match(/0+/)[0].length + '"' : "" ) + | ||||
| 				'>' + | ||||
| 				/* TODO: interstitial text placeholders */ | ||||
| 				'</number:' + (np[3] ? "scientific-" : "") + 'number>'; | ||||
| 			i = np.index + np[0].length; | ||||
| 		} | ||||
| 
 | ||||
| 		/* residual text */ | ||||
| 		if(nf[i] == '"') { | ||||
| 			c = ""; | ||||
| 			while(nf[++i] != '"' || nf[++i] == '"') c += nf[i]; --i; | ||||
| 			payload += '<number:text>' + escapexml(c.replace(/""/g, '"')) + '</number:text>'; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if(!payload) { console.error("Could not generate ODS number format for |" + nf + "|"); return ""; } | ||||
| 	return writextag("number:" + type + "-style", payload, nopts); | ||||
| } | ||||
| 
 | ||||
| function write_names_ods(Names, SheetNames, idx) { | ||||
| 	//var scoped = Names.filter(function(name) { return name.Sheet == (idx == -1 ? null : idx); });
 | ||||
| 	var scoped = []; for(var namei = 0; namei < Names.length; ++namei) { | ||||
| 		var name = Names[namei]; | ||||
| 		if(!name) continue; | ||||
| 		if(name.Sheet == (idx == -1 ? null : idx)) scoped.push(name); | ||||
| 	} | ||||
| 	if(!scoped.length) return ""; | ||||
| 	return "      <table:named-expressions>\n" + scoped.map(function(name) { | ||||
| 		var odsref =  (idx == -1 ? "$" : "") + csf_to_ods_3D(name.Ref); | ||||
| 		return "        " + writextag("table:named-range", null, { | ||||
| 			"table:name": name.Name, | ||||
| 			"table:cell-range-address": odsref, | ||||
| 			"table:base-cell-address": odsref.replace(/[\.][^\.]*$/, ".$A$1") | ||||
| 		}); | ||||
| 	}).join("\n") + "\n      </table:named-expressions>\n"; | ||||
| } | ||||
| var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function() { | ||||
| var write_content_ods/*:{(wb:any, opts:any):string}*/ = (function() { | ||||
| 	/* 6.1.2 White Space Characters */ | ||||
| 	var write_text_p = function(text/*:string*/, span)/*:string*/ { | ||||
| 	var write_text_p = function(text/*:string*/)/*:string*/ { | ||||
| 		return escapexml(text) | ||||
| 			.replace(/  +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';}) | ||||
| 			.replace(/\t/g, "<text:tab/>") | ||||
| 			.replace(/\n/g, span ? "<text:line-break/>": "</text:p><text:p>") | ||||
| 			.replace(/\n/g, "<text:line-break/>") | ||||
| 			.replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>"); | ||||
| 	}; | ||||
| 
 | ||||
| 	var null_cell_xml = '          <table:table-cell />\n'; | ||||
| 	var write_ws = function(ws, wb/*:Workbook*/, i/*:number*/, opts, nfs, date1904)/*:string*/ { | ||||
| 	var covered_cell_xml = '          <table:covered-table-cell/>\n'; | ||||
| 	var write_ws = function(ws, wb/*:Workbook*/, i/*:number*//*::, opts*/)/*:string*/ { | ||||
| 		/* Section 9 Tables */ | ||||
| 		var o/*:Array<string>*/ = []; | ||||
| 		var tstyle = "ta1"; | ||||
| 		if(((((wb||{}).Workbook||{}).Sheets||[])[i]||{}).Hidden) tstyle = "ta2"; | ||||
| 		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '" table:style-name="' + tstyle + '">\n'); | ||||
| 		var R=0,C=0, range = decode_range(ws['!ref']||"A1"); | ||||
| 		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '" table:style-name="ta1">\n'); | ||||
| 		var R=0,C=0, range = decode_range(ws['!ref']); | ||||
| 		var marr/*:Array<Range>*/ = ws['!merges'] || [], mi = 0; | ||||
| 		var dense = ws["!data"] != null; | ||||
| 		if(ws["!cols"]) { | ||||
| 			for(C = 0; C <= range.e.c; ++C) o.push('        <table:table-column' + (ws["!cols"][C] ? ' table:style-name="co' + ws["!cols"][C].ods + '"' : '') + '></table:table-column>\n'); | ||||
| 		} | ||||
| 		var H = "", ROWS = ws["!rows"]||[]; | ||||
| 		for(R = 0; R < range.s.r; ++R) { | ||||
| 			H = ROWS[R] ? ' table:style-name="ro' + ROWS[R].ods + '"' : ""; | ||||
| 			o.push('        <table:table-row' + H + '></table:table-row>\n'); | ||||
| 		} | ||||
| 		var dense = Array.isArray(ws); | ||||
| 		for(R = 0; R < range.s.r; ++R) o.push('        <table:table-row></table:table-row>\n'); | ||||
| 		for(; R <= range.e.r; ++R) { | ||||
| 			H = ROWS[R] ? ' table:style-name="ro' + ROWS[R].ods + '"' : ""; | ||||
| 			o.push('        <table:table-row' + H + '>\n'); | ||||
| 			o.push('        <table:table-row>\n'); | ||||
| 			for(C=0; C < range.s.c; ++C) o.push(null_cell_xml); | ||||
| 			for(; C <= range.e.c; ++C) { | ||||
| 				var skip = false, ct = {}, textp = ""; | ||||
| @ -244,8 +53,8 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function | ||||
| 					ct['table:number-rows-spanned'] =    (marr[mi].e.r - marr[mi].s.r + 1); | ||||
| 					break; | ||||
| 				} | ||||
| 				if(skip) { o.push('          <table:covered-table-cell/>\n'); continue; } | ||||
| 				var ref = encode_cell({r:R, c:C}), cell = dense ? (ws["!data"][R]||[])[C]: ws[ref]; | ||||
| 				if(skip) { o.push(covered_cell_xml); continue; } | ||||
| 				var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref]; | ||||
| 				if(cell && cell.f) { | ||||
| 					ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f)); | ||||
| 					if(cell.F) { | ||||
| @ -264,110 +73,39 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function | ||||
| 						ct['office:boolean-value'] = (cell.v ? 'true' : 'false'); | ||||
| 						break; | ||||
| 					case 'n': | ||||
| 						if(!isFinite(cell.v)) { | ||||
| 							if(isNaN(cell.v)) { | ||||
| 								textp = "#NUM!"; | ||||
| 								ct['table:formula'] = "of:=#NUM!"; | ||||
| 							} else { | ||||
| 								textp = "#DIV/0!"; | ||||
| 								ct['table:formula'] = "of:=" + (cell.v < 0 ? "-" : "") + "1/0"; | ||||
| 							} | ||||
| 							ct['office:string-value'] = ""; | ||||
| 							ct['office:value-type'] = "string"; | ||||
| 							ct['calcext:value-type'] = "error"; | ||||
| 						} else { | ||||
| 							textp = (cell.w||String(cell.v||0)); | ||||
| 							ct['office:value-type'] = "float"; | ||||
| 							ct['office:value'] = (cell.v||0); | ||||
| 						} | ||||
| 						textp = (cell.w||String(cell.v||0)); | ||||
| 						ct['office:value-type'] = "float"; | ||||
| 						ct['office:value'] = (cell.v||0); | ||||
| 						break; | ||||
| 					case 's': case 'str': | ||||
| 						textp = cell.v == null ? "" : cell.v; | ||||
| 						ct['office:value-type'] = "string"; | ||||
| 						break; | ||||
| 					case 'd': | ||||
| 						textp = (cell.w||(parseDate(cell.v, date1904).toISOString())); | ||||
| 						textp = (cell.w||(parseDate(cell.v).toISOString())); | ||||
| 						ct['office:value-type'] = "date"; | ||||
| 						ct['office:date-value'] = (parseDate(cell.v, date1904).toISOString()); | ||||
| 						ct['office:date-value'] = (parseDate(cell.v).toISOString()); | ||||
| 						ct['table:style-name'] = "ce1"; | ||||
| 						break; | ||||
| 					//case 'e': // TODO: translate to ODS errors
 | ||||
| 					default: o.push(null_cell_xml); continue; // TODO: empty cell with comments
 | ||||
| 					//case 'e':
 | ||||
| 					default: o.push(null_cell_xml); continue; | ||||
| 				} | ||||
| 				var text_p = write_text_p(textp); | ||||
| 				if(cell.l && cell.l.Target) { | ||||
| 					var _tgt = cell.l.Target; | ||||
| 					_tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt; | ||||
| 					// TODO: choose correct parent path format based on link delimiters
 | ||||
| 					if(_tgt.charAt(0) != "#" && !_tgt.match(/^\w+:/)) _tgt = '../' + _tgt; | ||||
| 					text_p = writextag('text:a', text_p, {'xlink:href': _tgt.replace(/&/g, "&")}); | ||||
| 					var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt; | ||||
| 					text_p = writextag('text:a', text_p, {'xlink:href': _tgt}); | ||||
| 				} | ||||
| 				if(nfs[cell.z]) ct["table:style-name"] = "ce" + nfs[cell.z].slice(1); | ||||
| 				var payload = writextag('text:p', text_p, {}); | ||||
| 				if(cell.c) { | ||||
| 					var acreator = "", apayload = "", aprops = {}; | ||||
| 					for(var ci = 0; ci < cell.c.length; ++ci) { | ||||
| 						if(!acreator && cell.c[ci].a) acreator = cell.c[ci].a; | ||||
| 						apayload += "<text:p>" + write_text_p(cell.c[ci].t) + "</text:p>"; | ||||
| 					} | ||||
| 					if(!cell.c.hidden) aprops["office:display"] = true; | ||||
| 					payload = writextag('office:annotation', apayload, aprops) + payload; | ||||
| 				} | ||||
| 				o.push('          ' + writextag('table:table-cell', payload, ct) + '\n'); | ||||
| 				o.push('          ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n'); | ||||
| 			} | ||||
| 			o.push('        </table:table-row>\n'); | ||||
| 		} | ||||
| 		if((wb.Workbook||{}).Names) o.push(write_names_ods(wb.Workbook.Names, wb.SheetNames, i)); | ||||
| 		o.push('      </table:table>\n'); | ||||
| 		return o.join(""); | ||||
| 	}; | ||||
| 
 | ||||
| 	var write_automatic_styles_ods = function(o/*:Array<string>*/, wb) { | ||||
| 	var write_automatic_styles_ods = function(o/*:Array<string>*/) { | ||||
| 		o.push(' <office:automatic-styles>\n'); | ||||
| 
 | ||||
| 		/* column styles */ | ||||
| 		var cidx = 0; | ||||
| 		wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) { | ||||
| 			if(!ws) return; | ||||
| 			if(ws["!cols"]) { | ||||
| 				for(var C = 0; C < ws["!cols"].length; ++C) if(ws["!cols"][C]) { | ||||
| 					var colobj = ws["!cols"][C]; | ||||
| 					if(colobj.width == null && colobj.wpx == null && colobj.wch == null) continue; | ||||
| 					process_col(colobj); | ||||
| 					colobj.ods = cidx; | ||||
| 					var w = ws["!cols"][C].wpx + "px"; | ||||
| 					o.push('  <style:style style:name="co' + cidx + '" style:family="table-column">\n'); | ||||
| 					o.push('   <style:table-column-properties fo:break-before="auto" style:column-width="' + w + '"/>\n'); | ||||
| 					o.push('  </style:style>\n'); | ||||
| 					++cidx; | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 		/* row styles */ | ||||
| 		var ridx = 0; | ||||
| 		wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) { | ||||
| 			if(!ws) return; | ||||
| 			if(ws["!rows"]) { | ||||
| 				for(var R = 0; R < ws["!rows"].length; ++R) if(ws["!rows"][R]) { | ||||
| 					ws["!rows"][R].ods = ridx; | ||||
| 					var h = ws["!rows"][R].hpx + "px"; | ||||
| 					o.push('  <style:style style:name="ro' + ridx + '" style:family="table-row">\n'); | ||||
| 					o.push('   <style:table-row-properties fo:break-before="auto" style:row-height="' + h + '"/>\n'); | ||||
| 					o.push('  </style:style>\n'); | ||||
| 					++ridx; | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 		/* table */ | ||||
| 		o.push('  <style:style style:name="ta1" style:family="table" style:master-page-name="mp1">\n'); | ||||
| 		o.push('   <style:table-properties table:display="true" style:writing-mode="lr-tb"/>\n'); | ||||
| 		o.push('  </style:style>\n'); | ||||
| 		o.push('  <style:style style:name="ta2" style:family="table" style:master-page-name="mp1">\n'); | ||||
| 		o.push('   <style:table-properties table:display="false" style:writing-mode="lr-tb"/>\n'); | ||||
| 		o.push('  </style:style>\n'); | ||||
| 
 | ||||
| 		o.push('  <number:date-style style:name="N37" number:automatic-order="true">\n'); | ||||
| 		o.push('   <number:month number:style="long"/>\n'); | ||||
| 		o.push('   <number:text>/</number:text>\n'); | ||||
| @ -376,32 +114,17 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function | ||||
| 		o.push('   <number:year/>\n'); | ||||
| 		o.push('  </number:date-style>\n'); | ||||
| 
 | ||||
| 		/* number formats, table cells, text */ | ||||
| 		var nfs = {}; | ||||
| 		var nfi = 69; | ||||
| 		wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) { | ||||
| 			if(!ws) return; | ||||
| 			var dense = (ws["!data"] != null); | ||||
| 			if(!ws["!ref"]) return; | ||||
| 			var range = decode_range(ws["!ref"]); | ||||
| 			for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) { | ||||
| 				var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})]; | ||||
| 				if(!c || !c.z || c.z.toLowerCase() == "general") continue; | ||||
| 				if(!nfs[c.z]) { | ||||
| 					var out = write_number_format_ods(c.z, "N" + nfi); | ||||
| 					if(out) { nfs[c.z] = "N" + nfi; ++nfi; o.push(out + "\n"); } | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 		/* table */ | ||||
| 		o.push('  <style:style style:name="ta1" style:family="table">\n'); // style:master-page-name="mp1">\n');
 | ||||
| 		o.push('   <style:table-properties table:display="true" style:writing-mode="lr-tb"/>\n'); | ||||
| 		o.push('  </style:style>\n'); | ||||
| 
 | ||||
| 		/* table cells, text */ | ||||
| 		o.push('  <style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>\n'); | ||||
| 		keys(nfs).forEach(function(nf) { | ||||
| 			o.push('<style:style style:name="ce' + nfs[nf].slice(1) + '" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="' + nfs[nf] + '"/>\n'); | ||||
| 		}); | ||||
| 
 | ||||
| 		/* page-layout */ | ||||
| 
 | ||||
| 		o.push(' </office:automatic-styles>\n'); | ||||
| 		return nfs; | ||||
| 	}; | ||||
| 
 | ||||
| 	return function wcx(wb, opts) { | ||||
| @ -452,18 +175,12 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function | ||||
| 			'office:mimetype': "application/vnd.oasis.opendocument.spreadsheet" | ||||
| 		}); | ||||
| 
 | ||||
| 		if(opts.bookType == "fods") { | ||||
| 			o.push('<office:document' + attr + fods + '>\n'); | ||||
| 			o.push(write_meta_ods().replace(/<office:document-meta[^<>]*?>/, "").replace(/<\/office:document-meta>/, "") + "\n"); | ||||
| 			// TODO: settings (equiv of settings.xml for ODS)
 | ||||
| 		} else o.push('<office:document-content' + attr  + '>\n'); | ||||
| 		// o.push('  <office:scripts/>\n');
 | ||||
| 		var nfs = write_automatic_styles_ods(o, wb); | ||||
| 		if(opts.bookType == "fods") o.push('<office:document' + attr + fods + '>\n'); | ||||
| 		else o.push('<office:document-content' + attr  + '>\n'); | ||||
| 		write_automatic_styles_ods(o); | ||||
| 		o.push('  <office:body>\n'); | ||||
| 		o.push('    <office:spreadsheet>\n'); | ||||
| 		if(((wb.Workbook||{}).WBProps||{}).date1904) o.push('      <table:calculation-settings table:case-sensitive="false" table:search-criteria-must-apply-to-whole-cell="true" table:use-wildcards="true" table:use-regular-expressions="false" table:automatic-find-labels="false">\n        <table:null-date table:date-value="1904-01-01"/>\n      </table:calculation-settings>\n'); | ||||
| 		for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts, nfs, ((wb.Workbook||{}).WBProps||{}).date1904)); | ||||
| 		if((wb.Workbook||{}).Names) o.push(write_names_ods(wb.Workbook.Names, wb.SheetNames, -1)); | ||||
| 		for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts)); | ||||
| 		o.push('    </office:spreadsheet>\n'); | ||||
| 		o.push('  </office:body>\n'); | ||||
| 		if(opts.bookType == "fods") o.push('</office:document>'); | ||||
| @ -475,6 +192,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function | ||||
| function write_ods(wb/*:any*/, opts/*:any*/) { | ||||
| 	if(opts.bookType == "fods") return write_content_ods(wb, opts); | ||||
| 
 | ||||
| 	/*:: if(!jszip) throw new Error("JSZip is not available"); */ | ||||
| 	var zip = zip_new(); | ||||
| 	var f = ""; | ||||
| 
 | ||||
| @ -499,7 +217,7 @@ function write_ods(wb/*:any*/, opts/*:any*/) { | ||||
| 
 | ||||
| 	/* TODO: this is hard-coded to satiate excel */ | ||||
| 	f = "meta.xml"; | ||||
| 	zip_add_file(zip, f, XML_HEADER + write_meta_ods(/*::wb, opts*/)); | ||||
| 	zip_add_file(zip, f, write_meta_ods(/*::wb, opts*/)); | ||||
| 	manifest.push([f, "text/xml"]); | ||||
| 	rdf.push([f, "MetadataFile"]); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										24
									
								
								bits/82_sheeter.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										24
									
								
								bits/82_sheeter.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| function write_sheet_index(wb/*:Workbook*/, sheet/*:?string*/)/*:number*/ { | ||||
| 	if(!sheet) return 0; | ||||
| 	var idx = wb.SheetNames.indexOf(sheet); | ||||
| 	if(idx == -1) throw new Error("Sheet not found: " + sheet); | ||||
| 	return idx; | ||||
| } | ||||
| 
 | ||||
| function write_obj_str(factory/*:WriteObjStrFactory*/) { | ||||
| 	return function write_str(wb/*:Workbook*/, o/*:WriteOpts*/)/*:string*/ { | ||||
| 		var idx = write_sheet_index(wb, o.sheet); | ||||
| 		return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb); | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| var write_htm_str = write_obj_str(HTML_); | ||||
| var write_csv_str = write_obj_str({from_sheet:sheet_to_csv}); | ||||
| var write_slk_str = write_obj_str(typeof SYLK !== "undefined" ? SYLK : {}); | ||||
| var write_dif_str = write_obj_str(typeof DIF !== "undefined" ? DIF : {}); | ||||
| var write_prn_str = write_obj_str(typeof PRN !== "undefined" ? PRN : {}); | ||||
| var write_rtf_str = write_obj_str(typeof RTF !== "undefined" ? RTF : {}); | ||||
| var write_txt_str = write_obj_str({from_sheet:sheet_to_txt}); | ||||
| var write_dbf_buf = write_obj_str(typeof DBF !== "undefined" ? DBF : {}); | ||||
| var write_eth_str = write_obj_str(typeof ETH !== "undefined" ? ETH : {}); | ||||
| 
 | ||||
							
								
								
									
										2296
									
								
								bits/83_numbers.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2296
									
								
								bits/83_numbers.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -8,7 +8,7 @@ function fix_opts_func(defaults/*:Array<Array<any> >*/)/*:{(o:any):void}*/ { | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| function fix_read_opts(opts) { | ||||
| var fix_read_opts = function(opts) { | ||||
| fix_opts_func([ | ||||
| 	['cellNF', false], /* emit cell number format string as .z */ | ||||
| 	['cellHTML', true], /* emit html string as .h */ | ||||
| @ -29,10 +29,9 @@ fix_opts_func([ | ||||
| 	['password',''], /* password */ | ||||
| 	['WTF', false] /* WTF mode (throws errors) */ | ||||
| ])(opts); | ||||
| } | ||||
| }; | ||||
| 
 | ||||
| function fix_write_opts(opts) { | ||||
| fix_opts_func([ | ||||
| var fix_write_opts = fix_opts_func([ | ||||
| 	['cellDates', false], /* write date cells with type `d` */ | ||||
| 
 | ||||
| 	['bookSST', false], /* Generate Shared String Table */ | ||||
| @ -42,5 +41,4 @@ fix_opts_func([ | ||||
| 	['compression', false], /* Use file compression */ | ||||
| 
 | ||||
| 	['WTF', false] /* WTF mode (throws errors) */ | ||||
| ])(opts); | ||||
| } | ||||
| ]); | ||||
|  | ||||
| @ -13,13 +13,6 @@ function safe_parse_wbrels(wbrels, sheets) { | ||||
| 	return !wbrels || wbrels.length === 0 ? null : wbrels; | ||||
| } | ||||
| 
 | ||||
| function parse_sheet_legacy_drawing(sheet, type, zip, path, idx, opts, wb, comments) { | ||||
| 	if(!sheet || !sheet['!legdrawel']) return; | ||||
| 	var dfile = resolve_path(sheet['!legdrawel'].Target, path); | ||||
| 	var draw = getzipstr(zip, dfile, true); | ||||
| 	if(draw) parse_vml(utf8read(draw), sheet, comments||[]); | ||||
| } | ||||
| 
 | ||||
| function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/*:number*/, sheetRels, sheets, stype/*:string*/, opts, wb, themes, styles) { | ||||
| 	try { | ||||
| 		sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path); | ||||
| @ -42,30 +35,23 @@ function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/ | ||||
| 		} | ||||
| 		sheets[sheet] = _ws; | ||||
| 
 | ||||
| 		/* scan rels for comments and threaded comments */ | ||||
| 		var comments = [], tcomments = []; | ||||
| 		/* scan rels for comments */ | ||||
| 		var comments = []; | ||||
| 		if(sheetRels && sheetRels[sheet]) keys(sheetRels[sheet]).forEach(function(n) { | ||||
| 			var dfile = ""; | ||||
| 			if(sheetRels[sheet][n].Type == RELS.CMNT) { | ||||
| 				dfile = resolve_path(sheetRels[sheet][n].Target, path); | ||||
| 				var dfile = resolve_path(sheetRels[sheet][n].Target, path); | ||||
| 				comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts); | ||||
| 				if(!comments || !comments.length) return; | ||||
| 				sheet_insert_comments(_ws, comments, false); | ||||
| 			} | ||||
| 			if(sheetRels[sheet][n].Type == RELS.TCMNT) { | ||||
| 				dfile = resolve_path(sheetRels[sheet][n].Target, path); | ||||
| 				tcomments = tcomments.concat(parse_tcmnt_xml(getzipdata(zip, dfile, true), opts)); | ||||
| 				sheet_insert_comments(_ws, comments); | ||||
| 			} | ||||
| 		}); | ||||
| 		if(tcomments && tcomments.length) sheet_insert_comments(_ws, tcomments, true, opts.people || []); | ||||
| 		parse_sheet_legacy_drawing(_ws, stype, zip, path, idx, opts, wb, comments); | ||||
| 	} catch(e) { if(opts.WTF) throw e; } | ||||
| } | ||||
| 
 | ||||
| function strip_front_slash(x/*:string*/)/*:string*/ { return x.charAt(0) == '/' ? x.slice(1) : x; } | ||||
| 
 | ||||
| function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	make_ssf(); | ||||
| 	make_ssf(SSF); | ||||
| 	opts = opts || {}; | ||||
| 	fix_read_opts(opts); | ||||
| 
 | ||||
| @ -74,30 +60,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	/* UOC */ | ||||
| 	if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts); | ||||
| 	/* Numbers */ | ||||
| 	if(safegetzipfile(zip, 'Index/Document.iwa')) { | ||||
| 		if(typeof Uint8Array == "undefined") throw new Error('NUMBERS file parsing requires Uint8Array support'); | ||||
| 		if(typeof parse_numbers_iwa != "undefined") { | ||||
| 			if(zip.FileIndex) return parse_numbers_iwa(zip, opts); | ||||
| 			var _zip = CFB.utils.cfb_new(); | ||||
| 			zipentries(zip).forEach(function(e) { zip_add_file(_zip, e, getzipbin(zip, e)); }); | ||||
| 			return parse_numbers_iwa(_zip, opts); | ||||
| 		} | ||||
| 		throw new Error('Unsupported NUMBERS file'); | ||||
| 	} | ||||
| 	if(!safegetzipfile(zip, '[Content_Types].xml')) { | ||||
| 		if(safegetzipfile(zip, 'index.xml.gz')) throw new Error('Unsupported NUMBERS 08 file'); | ||||
| 		if(safegetzipfile(zip, 'index.xml')) throw new Error('Unsupported NUMBERS 09 file'); | ||||
| 		var index_zip = CFB.find(zip, 'Index.zip'); | ||||
| 		if(index_zip) { | ||||
| 			opts = dup(opts); | ||||
| 			delete opts.type; | ||||
| 			if(typeof index_zip.content == "string") opts.type = "binary"; | ||||
| 			// TODO: Bun buffer bug
 | ||||
| 			if(typeof Bun !== "undefined" && Buffer.isBuffer(index_zip.content)) return readSync(new Uint8Array(index_zip.content), opts); | ||||
| 			return readSync(index_zip.content, opts); | ||||
| 		} | ||||
| 		throw new Error('Unsupported ZIP file'); | ||||
| 	} | ||||
| 	if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file'); | ||||
| 
 | ||||
| 	var entries = zipentries(zip); | ||||
| 	var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')/*:?any*/)); | ||||
| @ -121,7 +84,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		strs = []; | ||||
| 		if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; } | ||||
| 
 | ||||
| 		if(opts.cellStyles && dir.themes.length) themes = parse_theme_xml(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"", opts); | ||||
| 		if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts); | ||||
| 
 | ||||
| 		if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts); | ||||
| 	} | ||||
| @ -184,17 +147,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var wbrelsi = dir.workbooks[0].lastIndexOf("/"); | ||||
| 	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,""); | ||||
| 	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels'; | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s")); | ||||
| 
 | ||||
| 	if((dir.metadata || []).length >= 1) { | ||||
| 		/* TODO: MDX and other types of metadata */ | ||||
| 		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts); | ||||
| 	} | ||||
| 
 | ||||
| 	if((dir.people || []).length >= 1) { | ||||
| 		opts.people = parse_people_xml(getzipdata(zip, strip_front_slash(dir.people[0])),opts); | ||||
| 	} | ||||
| 
 | ||||
| 	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile); | ||||
| 	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets); | ||||
| 
 | ||||
| 	/* Numbers iOS hack */ | ||||
| @ -204,7 +157,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		if(wbrels && wbrels[i]) { | ||||
| 			path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, ""); | ||||
| 			if(!safegetzipfile(zip, path)) path = wbrels[i][1]; | ||||
| 			if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/[\S\s]*$/,"") + wbrels[i][1]; | ||||
| 			if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1]; | ||||
| 			stype = wbrels[i][2]; | ||||
| 		} else { | ||||
| 			path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext; | ||||
| @ -237,28 +190,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		Strings: strs, | ||||
| 		Styles: styles, | ||||
| 		Themes: themes, | ||||
| 		SSF: dup(table_fmt) | ||||
| 		SSF: SSF.get_table() | ||||
| 	}/*:any*/); | ||||
| 	if(opts && opts.bookFiles) { | ||||
| 		if(zip.files) { | ||||
| 			out.keys = entries; | ||||
| 			out.files = zip.files; | ||||
| 		} else { | ||||
| 			out.keys = []; | ||||
| 			out.files = {}; | ||||
| 			zip.FullPaths.forEach(function(p, idx) { | ||||
| 				p = p.replace(/^Root Entry[\/]/, ""); | ||||
| 				out.keys.push(p); | ||||
| 				out.files[p] = zip.FileIndex[idx]; | ||||
| 			}); | ||||
| 		} | ||||
| 		out.keys = entries; | ||||
| 		out.files = zip.files; | ||||
| 	} | ||||
| 	if(opts && opts.bookVBA) { | ||||
| 		if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true); | ||||
| 		else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true); | ||||
| 	} | ||||
| 	// TODO: pass back content types metadata for xlsm/xlsx resolution
 | ||||
| 	out.bookType = xlsb ? "xlsb" : "xlsx"; | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,9 +1,11 @@ | ||||
| function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	_shapeid = 1024; | ||||
| 	if(opts.bookType == "ods") return write_ods(wb, opts); | ||||
| 	if(wb && !wb.SSF) { | ||||
| 		wb.SSF = dup(table_fmt); | ||||
| 		wb.SSF = SSF.get_table(); | ||||
| 	} | ||||
| 	if(wb && wb.SSF) { | ||||
| 		make_ssf(); SSF_load_table(wb.SSF); | ||||
| 		make_ssf(SSF); SSF.load_table(wb.SSF); | ||||
| 		// $FlowIgnore
 | ||||
| 		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0; | ||||
| 		opts.ssf = wb.SSF; | ||||
| @ -12,166 +14,11 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	opts.Strings = /*::((*/[]/*:: :any):SST)*/; opts.Strings.Count = 0; opts.Strings.Unique = 0; | ||||
| 	if(browser_has_Map) opts.revStrings = new Map(); | ||||
| 	else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; } | ||||
| 	var wbext = "bin"; | ||||
| 	var vbafmt = true; | ||||
| 	var ct = new_ct(); | ||||
| 	fix_write_opts(opts = opts || {}); | ||||
| 	var zip = zip_new(); | ||||
| 	var f = "", rId = 0; | ||||
| 
 | ||||
| 	opts.cellXfs = []; | ||||
| 	get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}}); | ||||
| 
 | ||||
| 	if(!wb.Props) wb.Props = {}; | ||||
| 
 | ||||
| 	f = "docProps/core.xml"; | ||||
| 	zip_add_file(zip, f, write_core_props(wb.Props, opts)); | ||||
| 	ct.coreprops.push(f); | ||||
| 	add_rels(opts.rels, 2, f, RELS.CORE_PROPS); | ||||
| 
 | ||||
| 	/*::if(!wb.Props) throw "unreachable"; */ | ||||
| 	f = "docProps/app.xml"; | ||||
| 	if(wb.Props && wb.Props.SheetNames){/* empty */} | ||||
| 	else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	else { | ||||
| 		var _sn = []; | ||||
| 		for(var _i = 0; _i < wb.SheetNames.length; ++_i) | ||||
| 			if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]); | ||||
| 		wb.Props.SheetNames = _sn; | ||||
| 	} | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip_add_file(zip, f, write_ext_props(wb.Props, opts)); | ||||
| 	ct.extprops.push(f); | ||||
| 	add_rels(opts.rels, 3, f, RELS.EXT_PROPS); | ||||
| 
 | ||||
| 	if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) { | ||||
| 		f = "docProps/custom.xml"; | ||||
| 		zip_add_file(zip, f, write_cust_props(wb.Custprops, opts)); | ||||
| 		ct.custprops.push(f); | ||||
| 		add_rels(opts.rels, 4, f, RELS.CUST_PROPS); | ||||
| 	} | ||||
| 
 | ||||
| 	var people = ["SheetJ5"]; | ||||
| 	opts.tcid = 0; | ||||
| 
 | ||||
| 	for(rId=1;rId <= wb.SheetNames.length; ++rId) { | ||||
| 		var wsrels = {'!id':{}}; | ||||
| 		var ws = wb.Sheets[wb.SheetNames[rId-1]]; | ||||
| 		var _type = (ws || {})["!type"] || "sheet"; | ||||
| 		switch(_type) { | ||||
| 		case "chart": | ||||
| 			/* falls through */ | ||||
| 		default: | ||||
| 			f = "xl/worksheets/sheet" + rId + "." + wbext; | ||||
| 			zip_add_file(zip, f, write_ws_bin(rId-1, opts, wb, wsrels)); | ||||
| 			ct.sheets.push(f); | ||||
| 			add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]); | ||||
| 		} | ||||
| 
 | ||||
| 		if(ws) { | ||||
| 			var comments = ws['!comments']; | ||||
| 			var need_vml = false; | ||||
| 			var cf = ""; | ||||
| 			if(comments && comments.length > 0) { | ||||
| 				var needtc = false; | ||||
| 				comments.forEach(function(carr) { | ||||
| 					carr[1].forEach(function(c) { if(c.T == true) needtc = true; }); | ||||
| 				}); | ||||
| 				if(needtc) { | ||||
| 					cf = "xl/threadedComments/threadedComment" + rId + ".xml"; | ||||
| 					zip_add_file(zip, cf, write_tcmnt_xml(comments, people, opts)); | ||||
| 					ct.threadedcomments.push(cf); | ||||
| 					add_rels(wsrels, -1, "../threadedComments/threadedComment" + rId + ".xml", RELS.TCMNT); | ||||
| 				} | ||||
| 
 | ||||
| 				cf = "xl/comments" + rId + "." + wbext; | ||||
| 				zip_add_file(zip, cf, write_comments_bin(comments, opts)); | ||||
| 				ct.comments.push(cf); | ||||
| 				add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT); | ||||
| 				need_vml = true; | ||||
| 			} | ||||
| 			if(ws['!legacy']) { | ||||
| 				if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_vml(rId, ws['!comments'])); | ||||
| 			} | ||||
| 			delete ws['!comments']; | ||||
| 			delete ws['!legacy']; | ||||
| 		} | ||||
| 
 | ||||
| 		if(wsrels['!id'].rId1) zip_add_file(zip, get_rels_path(f), write_rels(wsrels)); | ||||
| 	} | ||||
| 
 | ||||
| 	if(opts.Strings != null && opts.Strings.length > 0) { | ||||
| 		f = "xl/sharedStrings." + wbext; | ||||
| 		zip_add_file(zip, f, write_sst_bin(opts.Strings, opts)); | ||||
| 		ct.strs.push(f); | ||||
| 		add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/workbook." + wbext; | ||||
| 	zip_add_file(zip, f, write_wb_bin(wb, opts)); | ||||
| 	ct.workbooks.push(f); | ||||
| 	add_rels(opts.rels, 1, f, RELS.WB); | ||||
| 
 | ||||
| 	/* TODO: something more intelligent with themes */ | ||||
| 
 | ||||
| 	f = "xl/theme/theme1.xml"; | ||||
| 	var ww = write_theme(wb.Themes, opts); | ||||
| 	zip_add_file(zip, f, ww); | ||||
| 	ct.themes.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME); | ||||
| 
 | ||||
| 	/* TODO: something more intelligent with styles */ | ||||
| 
 | ||||
| 	f = "xl/styles." + wbext; | ||||
| 	zip_add_file(zip, f, write_sty_bin(wb, opts)); | ||||
| 	ct.styles.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY); | ||||
| 
 | ||||
| 	if(wb.vbaraw && vbafmt) { | ||||
| 		f = "xl/vbaProject.bin"; | ||||
| 		zip_add_file(zip, f, wb.vbaraw); | ||||
| 		ct.vba.push(f); | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta_bin()); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	if(people.length > 1) { | ||||
| 		f = "xl/persons/person.xml"; | ||||
| 		zip_add_file(zip, f, write_people_xml(people, opts)); | ||||
| 		ct.people.push(f); | ||||
| 		add_rels(opts.wbrels, -1, "persons/person.xml", RELS.PEOPLE); | ||||
| 	} | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| 
 | ||||
| 	delete opts.revssf; delete opts.ssf; | ||||
| 	return zip; | ||||
| } | ||||
| 
 | ||||
| function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	if(wb && !wb.SSF) { | ||||
| 		wb.SSF = dup(table_fmt); | ||||
| 	} | ||||
| 	if(wb && wb.SSF) { | ||||
| 		make_ssf(); SSF_load_table(wb.SSF); | ||||
| 		// $FlowIgnore
 | ||||
| 		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0; | ||||
| 		opts.ssf = wb.SSF; | ||||
| 	} | ||||
| 	opts.rels = {}; opts.wbrels = {}; | ||||
| 	opts.Strings = /*::((*/[]/*:: :any):SST)*/; opts.Strings.Count = 0; opts.Strings.Unique = 0; | ||||
| 	if(browser_has_Map) opts.revStrings = new Map(); | ||||
| 	else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; } | ||||
| 	var wbext = "xml"; | ||||
| 	var wbext = opts.bookType == "xlsb" ? "bin" : "xml"; | ||||
| 	var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1; | ||||
| 	var ct = new_ct(); | ||||
| 	fix_write_opts(opts = opts || {}); | ||||
| 	/*:: if(!jszip) throw new Error("JSZip is not available"); */ | ||||
| 	var zip = zip_new(); | ||||
| 	var f = "", rId = 0; | ||||
| 
 | ||||
| @ -207,9 +54,6 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		add_rels(opts.rels, 4, f, RELS.CUST_PROPS); | ||||
| 	} | ||||
| 
 | ||||
| 	var people = ["SheetJ5"]; | ||||
| 	opts.tcid = 0; | ||||
| 
 | ||||
| 	for(rId=1;rId <= wb.SheetNames.length; ++rId) { | ||||
| 		var wsrels = {'!id':{}}; | ||||
| 		var ws = wb.Sheets[wb.SheetNames[rId-1]]; | ||||
| @ -219,7 +63,7 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 			/* falls through */ | ||||
| 		default: | ||||
| 			f = "xl/worksheets/sheet" + rId + "." + wbext; | ||||
| 			zip_add_file(zip, f, write_ws_xml(rId-1, opts, wb, wsrels)); | ||||
| 			zip_add_file(zip, f, write_ws(rId-1, f, opts, wb, wsrels)); | ||||
| 			ct.sheets.push(f); | ||||
| 			add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]); | ||||
| 		} | ||||
| @ -227,27 +71,15 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		if(ws) { | ||||
| 			var comments = ws['!comments']; | ||||
| 			var need_vml = false; | ||||
| 			var cf = ""; | ||||
| 			if(comments && comments.length > 0) { | ||||
| 				var needtc = false; | ||||
| 				comments.forEach(function(carr) { | ||||
| 					carr[1].forEach(function(c) { if(c.T == true) needtc = true; }); | ||||
| 				}); | ||||
| 				if(needtc) { | ||||
| 					cf = "xl/threadedComments/threadedComment" + rId + ".xml"; | ||||
| 					zip_add_file(zip, cf, write_tcmnt_xml(comments, people, opts)); | ||||
| 					ct.threadedcomments.push(cf); | ||||
| 					add_rels(wsrels, -1, "../threadedComments/threadedComment" + rId + ".xml", RELS.TCMNT); | ||||
| 				} | ||||
| 
 | ||||
| 				cf = "xl/comments" + rId + "." + wbext; | ||||
| 				zip_add_file(zip, cf, write_comments_xml(comments, opts)); | ||||
| 				var cf = "xl/comments" + rId + "." + wbext; | ||||
| 				zip_add_file(zip, cf, write_cmnt(comments, cf, opts)); | ||||
| 				ct.comments.push(cf); | ||||
| 				add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT); | ||||
| 				need_vml = true; | ||||
| 			} | ||||
| 			if(ws['!legacy']) { | ||||
| 				if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_vml(rId, ws['!comments'])); | ||||
| 				if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments'])); | ||||
| 			} | ||||
| 			delete ws['!comments']; | ||||
| 			delete ws['!legacy']; | ||||
| @ -258,13 +90,13 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 
 | ||||
| 	if(opts.Strings != null && opts.Strings.length > 0) { | ||||
| 		f = "xl/sharedStrings." + wbext; | ||||
| 		zip_add_file(zip, f, write_sst_xml(opts.Strings, opts)); | ||||
| 		zip_add_file(zip, f, write_sst(opts.Strings, f, opts)); | ||||
| 		ct.strs.push(f); | ||||
| 		add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/workbook." + wbext; | ||||
| 	zip_add_file(zip, f, write_wb_xml(wb, opts)); | ||||
| 	zip_add_file(zip, f, write_wb(wb, f, opts)); | ||||
| 	ct.workbooks.push(f); | ||||
| 	add_rels(opts.rels, 1, f, RELS.WB); | ||||
| 
 | ||||
| @ -278,7 +110,7 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	/* TODO: something more intelligent with styles */ | ||||
| 
 | ||||
| 	f = "xl/styles." + wbext; | ||||
| 	zip_add_file(zip, f, write_sty_xml(wb, opts)); | ||||
| 	zip_add_file(zip, f, write_sty(wb, f, opts)); | ||||
| 	ct.styles.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY); | ||||
| 
 | ||||
| @ -289,18 +121,6 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA); | ||||
| 	} | ||||
| 
 | ||||
| 	f = "xl/metadata." + wbext; | ||||
| 	zip_add_file(zip, f, write_xlmeta_xml()); | ||||
| 	ct.metadata.push(f); | ||||
| 	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); | ||||
| 
 | ||||
| 	if(people.length > 1) { | ||||
| 		f = "xl/persons/person.xml"; | ||||
| 		zip_add_file(zip, f, write_people_xml(people, opts)); | ||||
| 		ct.people.push(f); | ||||
| 		add_rels(opts.wbrels, -1, "persons/person.xml", RELS.PEOPLE); | ||||
| 	} | ||||
| 
 | ||||
| 	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| @ -308,4 +128,3 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	delete opts.revssf; delete opts.ssf; | ||||
| 	return zip; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2,7 +2,7 @@ function firstbyte(f/*:RawData*/,o/*:?TypeOpts*/)/*:Array<number>*/ { | ||||
| 	var x = ""; | ||||
| 	switch((o||{}).type || "base64") { | ||||
| 		case 'buffer': return [f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]]; | ||||
| 		case 'base64': x = Base64_decode(f.slice(0,12)); break; | ||||
| 		case 'base64': x = Base64.decode(f.slice(0,12)); break; | ||||
| 		case 'binary': x = f; break; | ||||
| 		case 'array':  return [f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]]; | ||||
| 		default: throw new Error("Unrecognized type " + (o && o.type || "undefined")); | ||||
| @ -16,6 +16,7 @@ function read_cfb(cfb/*:CFBContainer*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| } | ||||
| 
 | ||||
| function read_zip(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	/*:: if(!jszip) throw new Error("JSZip is not available"); */ | ||||
| 	var zip, d = data; | ||||
| 	var o = opts||{}; | ||||
| 	if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64"; | ||||
| @ -36,27 +37,20 @@ function read_plaintext(data/*:string*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var str = "", bytes = firstbyte(data, o); | ||||
| 	switch(o.type) { | ||||
| 		case 'base64': str = Base64_decode(data); break; | ||||
| 		case 'base64': str = Base64.decode(data); break; | ||||
| 		case 'binary': str = data; break; | ||||
| 		case 'buffer': str = data.toString('binary'); break; | ||||
| 		case 'array': str = cc2str(data); break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 	o.type = "binary"; | ||||
| 	return read_plaintext(str, o); | ||||
| } | ||||
| 
 | ||||
| function read_utf16(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var d = data; | ||||
| 	if(o.type == 'base64') d = Base64_decode(d); | ||||
| 	if(typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) d = new Uint8Array(data); | ||||
| 	d = typeof $cptable !== "undefined" ? $cptable.utils.decode(1200, d.slice(2), 'str') : ( | ||||
| 		(has_buf && Buffer.isBuffer(data)) ? data.slice(2).toString("utf16le") : | ||||
| 		(typeof Uint8Array !== "undefined" && d instanceof Uint8Array) ? ( | ||||
| 			typeof TextDecoder !== "undefined" ? new TextDecoder("utf-16le").decode(d.slice(2)) : utf16lereadu(d.slice(2)) | ||||
| 		) : utf16leread(d.slice(2)) | ||||
| 	); | ||||
| 	if(o.type == 'base64') d = Base64.decode(d); | ||||
| 	d = cptable.utils.decode(1200, d.slice(2), 'str'); | ||||
| 	o.type = "binary"; | ||||
| 	return read_plaintext(d, o); | ||||
| } | ||||
| @ -72,18 +66,14 @@ function read_prn(data, d, o, str) { | ||||
| 
 | ||||
| function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	reset_cp(); | ||||
| 	var o = opts||{}; | ||||
| 	if(o.codepage && typeof $cptable === "undefined") console.error("Codepage tables are not loaded.  Non-ASCII characters may not give expected results"); | ||||
| 	if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), (o = dup(o), o.type = "array", o)); | ||||
| 	/* Javet projects `byte[]` to `Int8Array` */ | ||||
| 	if(typeof Int8Array !== 'undefined' && data instanceof Int8Array) return readSync(new Uint8Array(data.buffer, data.byteOffset, data.length), o); | ||||
| 	if(typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && !o.type) o.type = typeof Deno !== "undefined" ? "buffer" : "array"; | ||||
| 	if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts); | ||||
| 	var d = data, n = [0,0,0,0], str = false; | ||||
| 	var o = opts||{}; | ||||
| 	if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; } | ||||
| 	_ssfopts = {}; | ||||
| 	if(o.dateNF) _ssfopts.dateNF = o.dateNF; | ||||
| 	if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64"; | ||||
| 	if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); if(typeof Uint8Array !== 'undefined' && !has_buf) o.type = "array"; } | ||||
| 	if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); } | ||||
| 	if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); } | ||||
| 	if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') { | ||||
| 		// $FlowIgnore
 | ||||
| @ -93,7 +83,7 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	} | ||||
| 	switch((n = firstbyte(d, o))[0]) { | ||||
| 		case 0xD0: if(n[1] === 0xCF && n[2] === 0x11 && n[3] === 0xE0 && n[4] === 0xA1 && n[5] === 0xB1 && n[6] === 0x1A && n[7] === 0xE1) return read_cfb(CFB.read(d, o), o); break; | ||||
| 		case 0x09: if(n[1] <= 0x08) return parse_xlscfb(d, o); break; | ||||
| 		case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break; | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: | ||||
| 			if(n[1] === 0x49 && n[2] === 0x2a && n[3] === 0x00) throw new Error("TIFF Image File is not a spreadsheet"); | ||||
| @ -102,27 +92,13 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str); | ||||
| 		case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str); | ||||
| 		case 0xFF: | ||||
| 			if(n[1] === 0xFE) { return read_utf16(d, o); } | ||||
| 			else if(n[1] === 0x00 && n[2] === 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); | ||||
| 			break; | ||||
| 		case 0x00: | ||||
| 			if(n[1] === 0x00) { | ||||
| 				if(n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); | ||||
| 				if(n[2] === 0x00 && (n[3] === 0x08 || n[3] === 0x09)) return WK_.to_workbook(d, o); | ||||
| 			} | ||||
| 			break; | ||||
| 		case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break; | ||||
| 		case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break; | ||||
| 		case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o); | ||||
| 		case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return rtf_to_workbook(d, o); break; | ||||
| 		case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break; | ||||
| 		case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o); | ||||
| 		case 0x89: if(n[1] === 0x50 && n[2] === 0x4E && n[3] === 0x47) throw new Error("PNG Image File is not a spreadsheet"); break; | ||||
| 		case 0x08: if(n[1] === 0xE7) throw new Error("Unsupported Multiplan 1.x file!"); break; | ||||
| 		case 0x0C: | ||||
| 			if(n[1] === 0xEC) throw new Error("Unsupported Multiplan 2.x file!"); | ||||
| 			if(n[1] === 0xED) throw new Error("Unsupported Multiplan 3.x file!"); | ||||
| 			break; | ||||
| 	} | ||||
| 	if(DBF_SUPPORTED_VERSIONS.indexOf(n[0]) > -1 && n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o); | ||||
| 	if(DBF.versions.indexOf(n[0]) > -1 && n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o); | ||||
| 	return read_prn(data, d, o, str); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -9,46 +9,22 @@ function write_cfb_ctr(cfb/*:CFBContainer*/, o/*:WriteOpts*/)/*:any*/ { | ||||
| 	return CFB.write(cfb, o); | ||||
| } | ||||
| 
 | ||||
| function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	switch(opts.bookType) { | ||||
| 		case "ods": return write_ods(wb, opts); | ||||
| 		case "numbers": return write_numbers_iwa(wb, opts); | ||||
| 		case "xlsb": return write_zip_xlsb(wb, opts); | ||||
| 		default: return write_zip_xlsx(wb, opts); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*:: declare var encrypt_agile:any; */ | ||||
| function write_zip_type(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ { | ||||
| 	var o = dup(opts||{}); | ||||
| 	var o = opts||{}; | ||||
| 	var z = write_zip(wb, o); | ||||
| 	return write_zip_denouement(z, o); | ||||
| } | ||||
| function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ { | ||||
| 	var o = dup(opts||{}); | ||||
| 	var z = write_zip_xlsx(wb, o); | ||||
| 	return write_zip_denouement(z, o); | ||||
| } | ||||
| function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ { | ||||
| 	var oopts = {}; | ||||
| 	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string"); | ||||
| 	if(o.compression) oopts.compression = 'DEFLATE'; | ||||
| 	if(o.password) oopts.type = ftype; | ||||
| 	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string"; | ||||
| 	else switch(o.type) { | ||||
| 		case "base64": oopts.type = "base64"; break; | ||||
| 		case "binary": oopts.type = "string"; break; | ||||
| 		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files"); | ||||
| 		case "buffer": | ||||
| 		case "file": oopts.type = ftype; break; | ||||
| 		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts); | ||||
| 	if(typeof Deno !== "undefined") { | ||||
| 		if(typeof out == "string") { | ||||
| 			if(o.type == "binary" || o.type == "base64") return out; | ||||
| 			out = new Uint8Array(s2ab(out)); | ||||
| 		} | ||||
| 	} | ||||
| 	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type}) : z.generate(oopts); | ||||
| /*jshint -W083 */ | ||||
| 	if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o); // eslint-disable-line no-undef
 | ||||
| /*jshint +W083 */ | ||||
| @ -66,13 +42,12 @@ function write_string_type(out/*:string*/, opts/*:WriteOpts*/, bom/*:?string*/)/ | ||||
| 	if(!bom) bom = ""; | ||||
| 	var o = bom + out; | ||||
| 	switch(opts.type) { | ||||
| 		case "base64": return Base64_encode(utf8write(o)); | ||||
| 		case "base64": return Base64.encode(utf8write(o)); | ||||
| 		case "binary": return utf8write(o); | ||||
| 		case "string": return out; | ||||
| 		case "file": return write_dl(opts.file, o, 'utf8'); | ||||
| 		case "buffer": { | ||||
| 			if(has_buf) return Buffer_from(o, 'utf8'); | ||||
| 			else if(typeof TextEncoder !== "undefined") return new TextEncoder().encode(o); | ||||
| 			else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); }); | ||||
| 		} | ||||
| 	} | ||||
| @ -81,7 +56,7 @@ function write_string_type(out/*:string*/, opts/*:WriteOpts*/, bom/*:?string*/)/ | ||||
| 
 | ||||
| function write_stxt_type(out/*:string*/, opts/*:WriteOpts*/)/*:any*/ { | ||||
| 	switch(opts.type) { | ||||
| 		case "base64": return Base64_encode_pass(out); | ||||
| 		case "base64": return Base64.encode(out); | ||||
| 		case "binary": return out; | ||||
| 		case "string": return out; /* override in sheet_to_txt */ | ||||
| 		case "file": return write_dl(opts.file, out, 'binary'); | ||||
| @ -102,51 +77,34 @@ function write_binary_type(out, opts/*:WriteOpts*/)/*:any*/ { | ||||
| 			var bstr = ""; | ||||
| 			// $FlowIgnore
 | ||||
| 			for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]); | ||||
| 			return opts.type == 'base64' ? Base64_encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr; | ||||
| 			return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr; | ||||
| 		case "file": return write_dl(opts.file, out); | ||||
| 		case "buffer": return out; | ||||
| 		default: throw new Error("Unrecognized type " + opts.type); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function writeSyncXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 	reset_cp(); | ||||
| 	check_wb(wb); | ||||
| 	var o = dup(opts||{}); | ||||
| 	if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; } | ||||
| 	if(o.type == "array") { o.type = "binary"; var out/*:string*/ = (writeSyncXLSX(wb, o)/*:any*/); o.type = "array"; return s2ab(out); } | ||||
| 	return write_zip_typeXLSX(wb, o); | ||||
| } | ||||
| 
 | ||||
| function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 	reset_cp(); | ||||
| 	check_wb(wb); | ||||
| 	var o = dup(opts||{}); | ||||
| 	var o = opts||{}; | ||||
| 	if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; } | ||||
| 	if(o.type == "array") { o.type = "binary"; var out/*:string*/ = (writeSync(wb, o)/*:any*/); o.type = "array"; return s2ab(out); } | ||||
| 	var idx = 0; | ||||
| 	if(o.sheet) { | ||||
| 		if(typeof o.sheet == "number") idx = o.sheet; | ||||
| 		else idx = wb.SheetNames.indexOf(o.sheet); | ||||
| 		if(!wb.SheetNames[idx]) throw new Error("Sheet not found: " + o.sheet + " : " + (typeof o.sheet)); | ||||
| 	} | ||||
| 	switch(o.bookType || 'xlsb') { | ||||
| 		case 'xml': | ||||
| 		case 'xlml': return write_string_type(write_xlml(wb, o), o); | ||||
| 		case 'slk': | ||||
| 		case 'sylk': return write_string_type(SYLK.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb), o); | ||||
| 		case 'sylk': return write_string_type(write_slk_str(wb, o), o); | ||||
| 		case 'htm': | ||||
| 		case 'html': return write_string_type(sheet_to_html(wb.Sheets[wb.SheetNames[idx]], o), o); | ||||
| 		case 'txt': return write_stxt_type(sheet_to_txt(wb.Sheets[wb.SheetNames[idx]], o), o); | ||||
| 		case 'csv': return write_string_type(sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o), o, "\ufeff"); | ||||
| 		case 'dif': return write_string_type(DIF.from_sheet(wb.Sheets[wb.SheetNames[idx]], o), o); | ||||
| 		case 'dbf': return write_binary_type(DBF.from_sheet(wb.Sheets[wb.SheetNames[idx]], o), o); | ||||
| 		case 'prn': return write_string_type(PRN.from_sheet(wb.Sheets[wb.SheetNames[idx]], o), o); | ||||
| 		case 'rtf': return write_string_type(sheet_to_rtf(wb.Sheets[wb.SheetNames[idx]], o), o); | ||||
| 		case 'eth': return write_string_type(ETH.from_sheet(wb.Sheets[wb.SheetNames[idx]], o), o); | ||||
| 		case 'html': return write_string_type(write_htm_str(wb, o), o); | ||||
| 		case 'txt': return write_stxt_type(write_txt_str(wb, o), o); | ||||
| 		case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff"); | ||||
| 		case 'dif': return write_string_type(write_dif_str(wb, o), o); | ||||
| 		case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o); | ||||
| 		case 'prn': return write_string_type(write_prn_str(wb, o), o); | ||||
| 		case 'rtf': return write_string_type(write_rtf_str(wb, o), o); | ||||
| 		case 'eth': return write_string_type(write_eth_str(wb, o), o); | ||||
| 		case 'fods': return write_string_type(write_ods(wb, o), o); | ||||
| 		case 'wk1': return write_binary_type(WK_.sheet_to_wk1(wb.Sheets[wb.SheetNames[idx]], o), o); | ||||
| 		case 'wk3': return write_binary_type(WK_.book_to_wk3(wb, o), o); | ||||
| 		case 'biff2': if(!o.biff) o.biff = 2; /* falls through */ | ||||
| 		case 'biff3': if(!o.biff) o.biff = 3; /* falls through */ | ||||
| 		case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o); | ||||
| @ -158,7 +116,6 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 		case 'xlsm': | ||||
| 		case 'xlam': | ||||
| 		case 'xlsb': | ||||
| 		case 'numbers': | ||||
| 		case 'ods': return write_zip_type(wb, o); | ||||
| 		default: throw new Error ("Unrecognized bookType |" + o.bookType + "|"); | ||||
| 	} | ||||
| @ -185,14 +142,6 @@ function writeFileSync(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOp | ||||
| 	return writeSync(wb, o); | ||||
| } | ||||
| 
 | ||||
| function writeFileSyncXLSX(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOpts*/) { | ||||
| 	var o = opts||{}; o.type = 'file'; | ||||
| 	o.file = filename; | ||||
| 	resolve_book_type(o); | ||||
| 	return writeSyncXLSX(wb, o); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| function writeFileAsync(filename/*:string*/, wb/*:Workbook*/, opts/*:?WriteFileOpts*/, cb/*:?(e?:ErrnoError)=>void*/) { | ||||
| 	var o = opts||{}; o.type = 'file'; | ||||
| 	o.file = filename; | ||||
|  | ||||
							
								
								
									
										256
									
								
								bits/90_utils.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										256
									
								
								bits/90_utils.js
									
									
									
									
									
								
							| @ -4,18 +4,18 @@ type MJRObject = { | ||||
| 	isempty: boolean; | ||||
| }; | ||||
| */ | ||||
| function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, header/*:number*/, hdr/*:Array<any>*/, o/*:Sheet2JSONOpts*/)/*:MJRObject*/ { | ||||
| function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, header/*:number*/, hdr/*:Array<any>*/, dense/*:boolean*/, o/*:Sheet2JSONOpts*/)/*:MJRObject*/ { | ||||
| 	var rr = encode_row(R); | ||||
| 	var defval = o.defval, raw = o.raw || !Object.prototype.hasOwnProperty.call(o, "raw"); | ||||
| 	var isempty = true, dense = (sheet["!data"] != null); | ||||
| 	var isempty = true; | ||||
| 	var row/*:any*/ = (header === 1) ? [] : {}; | ||||
| 	if(header !== 1) { | ||||
| 		if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; } | ||||
| 		else row.__rowNum__ = R; | ||||
| 	} | ||||
| 	if(!dense || sheet["!data"][R]) for (var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 		var val = dense ? (sheet["!data"][R]||[])[C] : sheet[cols[C] + rr]; | ||||
| 		if(val == null || val.t === undefined) { | ||||
| 	if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 		var val = dense ? sheet[R][C] : sheet[cols[C] + rr]; | ||||
| 		if(val === undefined || val.t === undefined) { | ||||
| 			if(defval === undefined) continue; | ||||
| 			if(hdr[C] != null) { row[hdr[C]] = defval; } | ||||
| 			continue; | ||||
| @ -23,23 +23,17 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar | ||||
| 		var v = val.v; | ||||
| 		switch(val.t){ | ||||
| 			case 'z': if(v == null) break; continue; | ||||
| 			case 'e': v = (v == 0 ? null : void 0); break; | ||||
| 			case 's': case 'b': | ||||
| 			case 'n': if(!val.z || !fmt_is_date(val.z)) break; | ||||
| 			v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
 | ||||
| 			if(typeof v == "number") break; | ||||
| 			/* falls through */ | ||||
| 			case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break; | ||||
| 			case 'e': v = void 0; break; | ||||
| 			case 's': case 'd': case 'b': case 'n': break; | ||||
| 			default: throw new Error('unrecognized type ' + val.t); | ||||
| 		} | ||||
| 		if(hdr[C] != null) { | ||||
| 			if(v == null) { | ||||
| 				if(val.t == "e" && v === null) row[hdr[C]] = null; | ||||
| 				else if(defval !== undefined) row[hdr[C]] = defval; | ||||
| 				if(defval !== undefined) row[hdr[C]] = defval; | ||||
| 				else if(raw && v === null) row[hdr[C]] = null; | ||||
| 				else continue; | ||||
| 			} else { | ||||
| 				row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o); | ||||
| 				row[hdr[C]] = raw || (o.rawNumbers && val.t == "n") ? v : format_cell(val,v,o); | ||||
| 			} | ||||
| 			if(v != null) isempty = false; | ||||
| 		} | ||||
| @ -68,16 +62,12 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) { | ||||
| 	var cols/*:Array<string>*/ = []; | ||||
| 	var out/*:Array<any>*/ = []; | ||||
| 	var outi = 0, counter = 0; | ||||
| 	var dense = sheet["!data"] != null; | ||||
| 	var R = r.s.r, C = 0; | ||||
| 	var header_cnt = {}; | ||||
| 	if(dense && !sheet["!data"][R]) sheet["!data"][R] = []; | ||||
| 	var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || []; | ||||
| 	var rowinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!rows"] || []; | ||||
| 	var dense = Array.isArray(sheet); | ||||
| 	var R = r.s.r, C = 0, CC = 0; | ||||
| 	if(dense && !sheet[R]) sheet[R] = []; | ||||
| 	for(C = r.s.c; C <= r.e.c; ++C) { | ||||
| 		if(((colinfo[C]||{}).hidden)) continue; | ||||
| 		cols[C] = encode_col(C); | ||||
| 		val = dense ? sheet["!data"][R][C] : sheet[cols[C] + rr]; | ||||
| 		val = dense ? sheet[R][C] : sheet[cols[C] + rr]; | ||||
| 		switch(header) { | ||||
| 			case 1: hdr[C] = C - r.s.c; break; | ||||
| 			case 2: hdr[C] = cols[C]; break; | ||||
| @ -85,18 +75,13 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) { | ||||
| 			default: | ||||
| 				if(val == null) val = {w: "__EMPTY", t: "s"}; | ||||
| 				vv = v = format_cell(val, null, o); | ||||
| 				counter = header_cnt[v] || 0; | ||||
| 				if(!counter) header_cnt[v] = 1; | ||||
| 				else { | ||||
| 					do { vv = v + "_" + (counter++); } while(header_cnt[vv]); header_cnt[v] = counter; | ||||
| 					header_cnt[vv] = 1; | ||||
| 				} | ||||
| 				counter = 0; | ||||
| 				for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter); | ||||
| 				hdr[C] = vv; | ||||
| 		} | ||||
| 	} | ||||
| 	for (R = r.s.r + offset; R <= r.e.r; ++R) { | ||||
| 		if ((rowinfo[R]||{}).hidden) continue; | ||||
| 		var row = make_json_row(sheet, r, R, cols, header, hdr, o); | ||||
| 		var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o); | ||||
| 		if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row; | ||||
| 	} | ||||
| 	out.length = outi; | ||||
| @ -104,20 +89,18 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) { | ||||
| } | ||||
| 
 | ||||
| var qreg = /"/g; | ||||
| function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, fs/*:number*/, rs/*:number*/, FS/*:string*/, w/*:number*/, o/*:Sheet2CSVOpts*/)/*:?string*/ { | ||||
| function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, fs/*:number*/, rs/*:number*/, FS/*:string*/, o/*:Sheet2CSVOpts*/)/*:?string*/ { | ||||
| 	var isempty = true; | ||||
| 	var row/*:Array<string>*/ = [], txt = "", rr = encode_row(R); | ||||
| 	var dense = sheet["!data"] != null; | ||||
| 	var datarow = dense && sheet["!data"][R] || []; | ||||
| 	for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 		if (!cols[C]) continue; | ||||
| 		var val = dense ? datarow[C]: sheet[cols[C] + rr]; | ||||
| 		var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr]; | ||||
| 		if(val == null) txt = ""; | ||||
| 		else if(val.v != null) { | ||||
| 			isempty = false; | ||||
| 			txt = ''+(o.rawNumbers && val.t == "n" ? val.v : format_cell(val, null, o)); | ||||
| 			for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34 || o.forceQuotes) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; } | ||||
| 			if(txt == "ID" && w == 0 && row.length == 0) txt = '"ID"'; | ||||
| 			if(txt == "ID") txt = '"ID"'; | ||||
| 		} else if(val.f != null && !val.F) { | ||||
| 			isempty = false; | ||||
| 			txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"'; | ||||
| @ -125,7 +108,6 @@ function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Arr | ||||
| 		/* NOTE: Excel CSV does not support array formulae */ | ||||
| 		row.push(txt); | ||||
| 	} | ||||
| 	if(o.strip) while(row[row.length - 1] === "") --row.length; | ||||
| 	if(o.blankrows === false && isempty) return null; | ||||
| 	return row.join(FS); | ||||
| } | ||||
| @ -137,40 +119,43 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ { | ||||
| 	var r = safe_decode_range(sheet["!ref"]); | ||||
| 	var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0); | ||||
| 	var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0); | ||||
| 	var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$"); | ||||
| 	var row = "", cols/*:Array<string>*/ = []; | ||||
| 	o.dense = Array.isArray(sheet); | ||||
| 	var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || []; | ||||
| 	var rowinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!rows"] || []; | ||||
| 	for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C); | ||||
| 	var w = 0; | ||||
| 	for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 		if ((rowinfo[R]||{}).hidden) continue; | ||||
| 		row = make_csv_row(sheet, r, R, cols, fs, rs, FS, w, o); | ||||
| 		row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o); | ||||
| 		if(row == null) { continue; } | ||||
| 		if(row || (o.blankrows !== false)) out.push((w++ ? RS : "") + row); | ||||
| 		if(o.strip) row = row.replace(endregex,""); | ||||
| 		out.push(row + RS); | ||||
| 	} | ||||
| 	delete o.dense; | ||||
| 	return out.join(""); | ||||
| } | ||||
| 
 | ||||
| function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| 	if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n"; | ||||
| 	var s = sheet_to_csv(sheet, opts); | ||||
| 	if(typeof $cptable == 'undefined' || opts.type == 'string') return s; | ||||
| 	var o = $cptable.utils.encode(1200, s, 'str'); | ||||
| 	if(typeof cptable == 'undefined' || opts.type == 'string') return s; | ||||
| 	var o = cptable.utils.encode(1200, s, 'str'); | ||||
| 	return String.fromCharCode(255) + String.fromCharCode(254) + o; | ||||
| } | ||||
| 
 | ||||
| function sheet_to_formulae(sheet/*:Worksheet*/, opts/*:?Sheet2FormulaOpts*/)/*:Array<string>*/ { | ||||
| function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ { | ||||
| 	var y = "", x, val=""; | ||||
| 	if(sheet == null || sheet["!ref"] == null) return []; | ||||
| 	var r = safe_decode_range(sheet['!ref']), rr = "", cols/*:Array<string>*/ = [], C; | ||||
| 	var cmds/*:Array<string>*/ = []; | ||||
| 	var dense = sheet["!data"] != null; | ||||
| 	var dense = Array.isArray(sheet); | ||||
| 	for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C); | ||||
| 	for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 		rr = encode_row(R); | ||||
| 		for(C = r.s.c; C <= r.e.c; ++C) { | ||||
| 			y = cols[C] + rr; | ||||
| 			x = dense ? (sheet["!data"][R]||[])[C] : sheet[y]; | ||||
| 			x = dense ? (sheet[R]||[])[C] : sheet[y]; | ||||
| 			val = ""; | ||||
| 			if(x === undefined) continue; | ||||
| 			else if(x.F != null) { | ||||
| @ -180,7 +165,6 @@ function sheet_to_formulae(sheet/*:Worksheet*/, opts/*:?Sheet2FormulaOpts*/)/*:A | ||||
| 				if(y.indexOf(":") == -1) y = y + ":" + y; | ||||
| 			} | ||||
| 			if(x.f != null) val = x.f; | ||||
| 			else if(opts && opts.values === false) continue; | ||||
| 			else if(x.t == 'z') continue; | ||||
| 			else if(x.t == 'n' && x.v != null) val = "" + x.v; | ||||
| 			else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE"; | ||||
| @ -196,11 +180,8 @@ function sheet_to_formulae(sheet/*:Worksheet*/, opts/*:?Sheet2FormulaOpts*/)/*:A | ||||
| 
 | ||||
| function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet*/ { | ||||
| 	var o = opts || {}; | ||||
| 	var dense = _ws ? (_ws["!data"] != null) : o.dense; | ||||
| 	if(DENSE != null && dense == null) dense = DENSE; | ||||
| 	var offset = +!o.skipHeader; | ||||
| 	var ws/*:Worksheet*/ = _ws || ({}); | ||||
| 	if(!_ws && dense) ws["!data"] = []; | ||||
| 	var ws/*:Worksheet*/ = _ws || ({}/*:any*/); | ||||
| 	var _R = 0, _C = 0; | ||||
| 	if(ws && o.origin != null) { | ||||
| 		if(typeof o.origin == 'number') _R = o.origin; | ||||
| @ -209,6 +190,7 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet | ||||
| 			_R = _origin.r; _C = _origin.c; | ||||
| 		} | ||||
| 	} | ||||
| 	var cell/*:Cell*/; | ||||
| 	var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}}/*:any*/); | ||||
| 	if(ws['!ref']) { | ||||
| 		var _range = safe_decode_range(ws['!ref']); | ||||
| @ -219,35 +201,28 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet | ||||
| 		if(_R == -1) { _R = 0; range.e.r = js.length - 1 + offset; } | ||||
| 	} | ||||
| 	var hdr/*:Array<string>*/ = o.header || [], C = 0; | ||||
| 	var ROW = []; | ||||
| 
 | ||||
| 	js.forEach(function (JS, R/*:number*/) { | ||||
| 		if(dense && !ws["!data"][_R + R + offset]) ws["!data"][_R + R + offset] = []; | ||||
| 		if(dense) ROW = ws["!data"][_R + R + offset]; | ||||
| 		keys(JS).forEach(function(k) { | ||||
| 			if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k; | ||||
| 			var v = JS[k]; | ||||
| 			var t = 'z'; | ||||
| 			var z = ""; | ||||
| 			var ref = dense ? "" : (encode_col(_C + C) + encode_row(_R + R + offset)); | ||||
| 			var cell/*:Cell*/ = dense ? ROW[_C + C] : ws[ref]; | ||||
| 			var ref = encode_cell({c:_C + C,r:_R + R + offset}); | ||||
| 			cell = utils.sheet_get_cell(ws, ref); | ||||
| 			if(v && typeof v === 'object' && !(v instanceof Date)){ | ||||
| 				if(dense) ROW[_C + C] = v; | ||||
| 				else ws[ref] = v; | ||||
| 				ws[ref] = v; | ||||
| 			} else { | ||||
| 				if(typeof v == 'number') t = 'n'; | ||||
| 				else if(typeof v == 'boolean') t = 'b'; | ||||
| 				else if(typeof v == 'string') t = 's'; | ||||
| 				else if(v instanceof Date) { | ||||
| 					t = 'd'; | ||||
| 					if(!o.UTC) v = local_to_utc(v); | ||||
| 					if(!o.cellDates) { t = 'n'; v = datenum(v); } | ||||
| 					z = (cell != null && cell.z && fmt_is_date(cell.z)) ? cell.z : (o.dateNF || table_fmt[14]); | ||||
| 					z = (o.dateNF || SSF._table[14]); | ||||
| 				} | ||||
| 				else if(v === null && o.nullError) { t = 'e'; v = 0; } | ||||
| 				if(!cell) { | ||||
| 					if(!dense) ws[ref] = cell = ({t:t, v:v}/*:any*/); | ||||
| 					else ROW[_C + C] = cell = ({t:t, v:v}/*:any*/); | ||||
| 				} else { | ||||
| 				if(!cell) ws[ref] = cell = ({t:t, v:v}/*:any*/); | ||||
| 				else { | ||||
| 					cell.t = t; cell.v = v; | ||||
| 					delete cell.w; delete cell.R; | ||||
| 					if(z) cell.z = z; | ||||
| @ -258,132 +233,39 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet | ||||
| 	}); | ||||
| 	range.e.c = Math.max(range.e.c, _C + hdr.length - 1); | ||||
| 	var __R = encode_row(_R); | ||||
| 	if(dense && !ws["!data"][_R]) ws["!data"][_R] = []; | ||||
| 	if(offset) for(C = 0; C < hdr.length; ++C) { | ||||
| 		if(dense) ws["!data"][_R][C + _C] = {t:'s', v:hdr[C]}; | ||||
| 		else ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]}; | ||||
| 	} | ||||
| 	if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]}; | ||||
| 	ws['!ref'] = encode_range(range); | ||||
| 	return ws; | ||||
| } | ||||
| function json_to_sheet(js/*:Array<any>*/, opts)/*:Worksheet*/ { return sheet_add_json(null, js, opts); } | ||||
| 
 | ||||
| /* get cell, creating a stub if necessary */ | ||||
| function ws_get_cell_stub(ws/*:Worksheet*/, R, C/*:?number*/)/*:Cell*/ { | ||||
| 	/* A1 cell address */ | ||||
| 	if(typeof R == "string") { | ||||
| 		if(ws["!data"] != null) { | ||||
| 			var RC = decode_cell(R); | ||||
| 			if(!ws["!data"][RC.r]) ws["!data"][RC.r] = []; | ||||
| 			return ws["!data"][RC.r][RC.c] || (ws["!data"][RC.r][RC.c] = {t:'z'}); | ||||
| 		} | ||||
| 		return ws[R] || (ws[R] = {t:'z'}); | ||||
| 	} | ||||
| 	/* cell address object */ | ||||
| 	if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R)); | ||||
| 	/* R and C are 0-based indices */ | ||||
| 	return ws_get_cell_stub(ws, encode_col(C||0) + encode_row(R)); | ||||
| } | ||||
| 
 | ||||
| /* find sheet index for given name / validate index */ | ||||
| function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) { | ||||
| 	if(typeof sh == "number") { | ||||
| 		if(sh >= 0 && wb.SheetNames.length > sh) return sh; | ||||
| 		throw new Error("Cannot find sheet # " + sh); | ||||
| 	} else if(typeof sh == "string") { | ||||
| 		var idx = wb.SheetNames.indexOf(sh); | ||||
| 		if(idx > -1) return idx; | ||||
| 		throw new Error("Cannot find sheet name |" + sh + "|"); | ||||
| 	} else throw new Error("Cannot find sheet |" + sh + "|"); | ||||
| } | ||||
| 
 | ||||
| /* simple blank or single-sheet workbook object */ | ||||
| function book_new(ws/*:?Worksheet*/, wsname/*:?string*/)/*:Workbook*/ { | ||||
| 	var wb = { SheetNames: [], Sheets: {} }; | ||||
| 	if(ws) book_append_sheet(wb, ws, wsname || "Sheet1"); | ||||
| 	return wb; | ||||
| } | ||||
| 
 | ||||
| /* add a worksheet to the end of a given workbook */ | ||||
| function book_append_sheet(wb/*:Workbook*/, ws/*:Worksheet*/, name/*:?string*/, roll/*:?boolean*/)/*:string*/ { | ||||
| 	var i = 1; | ||||
| 	if(!name) for(; i <= 0xFFFF; ++i, name = undefined) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break; | ||||
| 	if(!name || wb.SheetNames.length >= 0xFFFF) throw new Error("Too many worksheets"); | ||||
| 	if(roll && wb.SheetNames.indexOf(name) >= 0 && name.length < 32) { | ||||
| 		var m = name.match(/\d+$/); // at this point, name length is capped at 32
 | ||||
| 		i = m && +m[0] || 0; | ||||
| 		var root = m && name.slice(0, m.index) || name; | ||||
| 		for(++i; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf(name = root + i) == -1) break; | ||||
| 	} | ||||
| 	check_ws_name(name); | ||||
| 	if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!"); | ||||
| 
 | ||||
| 	wb.SheetNames.push(name); | ||||
| 	wb.Sheets[name] = ws; | ||||
| 	return name; | ||||
| } | ||||
| 
 | ||||
| /* set sheet visibility (visible/hidden/very hidden) */ | ||||
| function book_set_sheet_visibility(wb/*:Workbook*/, sh/*:number|string*/, vis/*:number*/) { | ||||
| 	if(!wb.Workbook) wb.Workbook = {}; | ||||
| 	if(!wb.Workbook.Sheets) wb.Workbook.Sheets = []; | ||||
| 
 | ||||
| 	var idx = wb_sheet_idx(wb, sh); | ||||
| 	// $FlowIgnore
 | ||||
| 	if(!wb.Workbook.Sheets[idx]) wb.Workbook.Sheets[idx] = {}; | ||||
| 
 | ||||
| 	switch(vis) { | ||||
| 		case 0: case 1: case 2: break; | ||||
| 		default: throw new Error("Bad sheet visibility setting " + vis); | ||||
| 	} | ||||
| 	// $FlowIgnore
 | ||||
| 	wb.Workbook.Sheets[idx].Hidden = vis; | ||||
| } | ||||
| 
 | ||||
| /* set number format */ | ||||
| function cell_set_number_format(cell/*:Cell*/, fmt/*:string|number*/) { | ||||
| 	cell.z = fmt; | ||||
| 	return cell; | ||||
| } | ||||
| 
 | ||||
| /* set cell hyperlink */ | ||||
| function cell_set_hyperlink(cell/*:Cell*/, target/*:string*/, tooltip/*:?string*/) { | ||||
| 	if(!target) { | ||||
| 		delete cell.l; | ||||
| 	} else { | ||||
| 		cell.l = ({ Target: target }/*:Hyperlink*/); | ||||
| 		if(tooltip) cell.l.Tooltip = tooltip; | ||||
| 	} | ||||
| 	return cell; | ||||
| } | ||||
| function cell_set_internal_link(cell/*:Cell*/, range/*:string*/, tooltip/*:?string*/) { return cell_set_hyperlink(cell, "#" + range, tooltip); } | ||||
| 
 | ||||
| /* add to cell comments */ | ||||
| function cell_add_comment(cell/*:Cell*/, text/*:string*/, author/*:?string*/) { | ||||
| 	if(!cell.c) cell.c = []; | ||||
| 	cell.c.push({t:text, a:author||"SheetJS"}); | ||||
| } | ||||
| 
 | ||||
| /* set array formula and flush related cells */ | ||||
| function sheet_set_array_formula(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) { | ||||
| 	var rng = typeof range != "string" ? range : safe_decode_range(range); | ||||
| 	var rngstr = typeof range == "string" ? range : encode_range(range); | ||||
| 	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) { | ||||
| 		var cell = ws_get_cell_stub(ws, R, C); | ||||
| 		cell.t = 'n'; | ||||
| 		cell.F = rngstr; | ||||
| 		delete cell.v; | ||||
| 		if(R == rng.s.r && C == rng.s.c) { | ||||
| 			cell.f = formula; | ||||
| 			if(dynamic) cell.D = true; | ||||
| 		} | ||||
| 	} | ||||
| 	var wsr = decode_range(ws["!ref"]); | ||||
| 	if(wsr.s.r > rng.s.r) wsr.s.r = rng.s.r; | ||||
| 	if(wsr.s.c > rng.s.c) wsr.s.c = rng.s.c; | ||||
| 	if(wsr.e.r < rng.e.r) wsr.e.r = rng.e.r; | ||||
| 	if(wsr.e.c < rng.e.c) wsr.e.c = rng.e.c; | ||||
| 	ws["!ref"] = encode_range(wsr); | ||||
| 	return ws; | ||||
| } | ||||
| var utils/*:any*/ = { | ||||
| 	encode_col: encode_col, | ||||
| 	encode_row: encode_row, | ||||
| 	encode_cell: encode_cell, | ||||
| 	encode_range: encode_range, | ||||
| 	decode_col: decode_col, | ||||
| 	decode_row: decode_row, | ||||
| 	split_cell: split_cell, | ||||
| 	decode_cell: decode_cell, | ||||
| 	decode_range: decode_range, | ||||
| 	format_cell: format_cell, | ||||
| 	get_formulae: sheet_to_formulae, | ||||
| 	make_csv: sheet_to_csv, | ||||
| 	make_json: sheet_to_json, | ||||
| 	make_formulae: sheet_to_formulae, | ||||
| 	sheet_add_aoa: sheet_add_aoa, | ||||
| 	sheet_add_json: sheet_add_json, | ||||
| 	sheet_add_dom: sheet_add_dom, | ||||
| 	aoa_to_sheet: aoa_to_sheet, | ||||
| 	json_to_sheet: json_to_sheet, | ||||
| 	table_to_sheet: parse_dom_table, | ||||
| 	table_to_book: table_to_book, | ||||
| 	sheet_to_csv: sheet_to_csv, | ||||
| 	sheet_to_txt: sheet_to_txt, | ||||
| 	sheet_to_json: sheet_to_json, | ||||
| 	sheet_to_html: HTML_.from_sheet, | ||||
| 	sheet_to_formulae: sheet_to_formulae, | ||||
| 	sheet_to_row_object_array: sheet_to_json | ||||
| }; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										151
									
								
								bits/95_api.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										151
									
								
								bits/95_api.js
									
									
									
									
									
								
							| @ -1,41 +1,116 @@ | ||||
| var utils/*:any*/ = { | ||||
| 	encode_col: encode_col, | ||||
| 	encode_row: encode_row, | ||||
| 	encode_cell: encode_cell, | ||||
| 	encode_range: encode_range, | ||||
| 	decode_col: decode_col, | ||||
| 	decode_row: decode_row, | ||||
| 	split_cell: split_cell, | ||||
| 	decode_cell: decode_cell, | ||||
| 	decode_range: decode_range, | ||||
| 	format_cell: format_cell, | ||||
| 	sheet_new: sheet_new, | ||||
| 	sheet_add_aoa: sheet_add_aoa, | ||||
| 	sheet_add_json: sheet_add_json, | ||||
| 	sheet_add_dom: sheet_add_dom, | ||||
| 	aoa_to_sheet: aoa_to_sheet, | ||||
| 	json_to_sheet: json_to_sheet, | ||||
| 	table_to_sheet: parse_dom_table, | ||||
| 	table_to_book: table_to_book, | ||||
| 	sheet_to_csv: sheet_to_csv, | ||||
| 	sheet_to_txt: sheet_to_txt, | ||||
| 	sheet_to_json: sheet_to_json, | ||||
| 	sheet_to_html: sheet_to_html, | ||||
| 	sheet_to_formulae: sheet_to_formulae, | ||||
| 	sheet_to_row_object_array: sheet_to_json, | ||||
| 	sheet_get_cell: ws_get_cell_stub, | ||||
| 	book_new: book_new, | ||||
| 	book_append_sheet: book_append_sheet, | ||||
| 	book_set_sheet_visibility: book_set_sheet_visibility, | ||||
| 	cell_set_number_format: cell_set_number_format, | ||||
| 	cell_set_hyperlink: cell_set_hyperlink, | ||||
| 	cell_set_internal_link: cell_set_internal_link, | ||||
| 	cell_add_comment: cell_add_comment, | ||||
| 	sheet_set_array_formula: sheet_set_array_formula, | ||||
| 	consts: { | ||||
| 		SHEET_VISIBLE: 0, | ||||
| 		SHEET_HIDDEN: 1, | ||||
| 		SHEET_VERY_HIDDEN: 2 | ||||
| (function(utils) { | ||||
| utils.consts = utils.consts || {}; | ||||
| function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); } | ||||
| 
 | ||||
| function get_default(x/*:any*/, y/*:any*/, z/*:any*/)/*:any*/ { return x[y] != null ? x[y] : (x[y] = z); } | ||||
| 
 | ||||
| /* get cell, creating a stub if necessary */ | ||||
| function ws_get_cell_stub(ws/*:Worksheet*/, R, C/*:?number*/)/*:Cell*/ { | ||||
| 	/* A1 cell address */ | ||||
| 	if(typeof R == "string") { | ||||
| 		/* dense */ | ||||
| 		if(Array.isArray(ws)) { | ||||
| 			var RC = decode_cell(R); | ||||
| 			if(!ws[RC.r]) ws[RC.r] = []; | ||||
| 			return ws[RC.r][RC.c] || (ws[RC.r][RC.c] = {t:'z'}); | ||||
| 		} | ||||
| 		return ws[R] || (ws[R] = {t:'z'}); | ||||
| 	} | ||||
| 	/* cell address object */ | ||||
| 	if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R)); | ||||
| 	/* R and C are 0-based indices */ | ||||
| 	return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0})); | ||||
| } | ||||
| utils.sheet_get_cell = ws_get_cell_stub; | ||||
| 
 | ||||
| /* find sheet index for given name / validate index */ | ||||
| function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) { | ||||
| 	if(typeof sh == "number") { | ||||
| 		if(sh >= 0 && wb.SheetNames.length > sh) return sh; | ||||
| 		throw new Error("Cannot find sheet # " + sh); | ||||
| 	} else if(typeof sh == "string") { | ||||
| 		var idx = wb.SheetNames.indexOf(sh); | ||||
| 		if(idx > -1) return idx; | ||||
| 		throw new Error("Cannot find sheet name |" + sh + "|"); | ||||
| 	} else throw new Error("Cannot find sheet |" + sh + "|"); | ||||
| } | ||||
| 
 | ||||
| /* simple blank workbook object */ | ||||
| utils.book_new = function()/*:Workbook*/ { | ||||
| 	return { SheetNames: [], Sheets: {} }; | ||||
| }; | ||||
| 
 | ||||
| /* add a worksheet to the end of a given workbook */ | ||||
| utils.book_append_sheet = function(wb/*:Workbook*/, ws/*:Worksheet*/, name/*:?string*/) { | ||||
| 	if(!name) for(var i = 1; i <= 0xFFFF; ++i, name = undefined) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break; | ||||
| 	if(!name || wb.SheetNames.length >= 0xFFFF) throw new Error("Too many worksheets"); | ||||
| 	check_ws_name(name); | ||||
| 	if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!"); | ||||
| 
 | ||||
| 	wb.SheetNames.push(name); | ||||
| 	wb.Sheets[name] = ws; | ||||
| }; | ||||
| 
 | ||||
| /* set sheet visibility (visible/hidden/very hidden) */ | ||||
| utils.book_set_sheet_visibility = function(wb/*:Workbook*/, sh/*:number|string*/, vis/*:number*/) { | ||||
| 	get_default(wb,"Workbook",{}); | ||||
| 	get_default(wb.Workbook,"Sheets",[]); | ||||
| 
 | ||||
| 	var idx = wb_sheet_idx(wb, sh); | ||||
| 	// $FlowIgnore
 | ||||
| 	get_default(wb.Workbook.Sheets,idx, {}); | ||||
| 
 | ||||
| 	switch(vis) { | ||||
| 		case 0: case 1: case 2: break; | ||||
| 		default: throw new Error("Bad sheet visibility setting " + vis); | ||||
| 	} | ||||
| 	// $FlowIgnore
 | ||||
| 	wb.Workbook.Sheets[idx].Hidden = vis; | ||||
| }; | ||||
| add_consts([ | ||||
| 	["SHEET_VISIBLE", 0], | ||||
| 	["SHEET_HIDDEN", 1], | ||||
| 	["SHEET_VERY_HIDDEN", 2] | ||||
| ]); | ||||
| 
 | ||||
| /* set number format */ | ||||
| utils.cell_set_number_format = function(cell/*:Cell*/, fmt/*:string|number*/) { | ||||
| 	cell.z = fmt; | ||||
| 	return cell; | ||||
| }; | ||||
| 
 | ||||
| /* set cell hyperlink */ | ||||
| utils.cell_set_hyperlink = function(cell/*:Cell*/, target/*:string*/, tooltip/*:?string*/) { | ||||
| 	if(!target) { | ||||
| 		delete cell.l; | ||||
| 	} else { | ||||
| 		cell.l = ({ Target: target }/*:Hyperlink*/); | ||||
| 		if(tooltip) cell.l.Tooltip = tooltip; | ||||
| 	} | ||||
| 	return cell; | ||||
| }; | ||||
| utils.cell_set_internal_link = function(cell/*:Cell*/, range/*:string*/, tooltip/*:?string*/) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); }; | ||||
| 
 | ||||
| /* add to cell comments */ | ||||
| utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?string*/) { | ||||
| 	if(!cell.c) cell.c = []; | ||||
| 	cell.c.push({t:text, a:author||"SheetJS"}); | ||||
| }; | ||||
| 
 | ||||
| /* set array formula and flush related cells */ | ||||
| utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) { | ||||
| 	var rng = typeof range != "string" ? range : safe_decode_range(range); | ||||
| 	var rngstr = typeof range == "string" ? range : encode_range(range); | ||||
| 	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) { | ||||
| 		var cell = ws_get_cell_stub(ws, R, C); | ||||
| 		cell.t = 'n'; | ||||
| 		cell.F = rngstr; | ||||
| 		delete cell.v; | ||||
| 		if(R == rng.s.r && C == rng.s.c) cell.f = formula; | ||||
| 	} | ||||
| 	return ws; | ||||
| }; | ||||
| 
 | ||||
| return utils; | ||||
| })(utils); | ||||
| 
 | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user