├── .eslintrc ├── .flowconfig ├── .github └── workflows │ ├── node-4+.yml │ ├── node-iojs.yml │ ├── node-pretest.yml │ └── node-zero.yml ├── .gitignore ├── .jscs.json ├── .jshintrc ├── .spelling ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── bits ├── 00_header.js ├── 04_base64.js ├── 05_buf.js ├── 08_blob.js ├── 10_types.js ├── 21_crc32.js ├── 30_cfbheader.js ├── 31_version.js ├── 33_sort.js ├── 35_path.js ├── 37_dosdates.js ├── 38_extrafield.js ├── 39_fs.js ├── 40_parse.js ├── 41_mver.js ├── 42_sectorify.js ├── 43_rbtree.js ├── 44_readmfat.js ├── 45_readfat.js ├── 46_readdir.js ├── 49_readutils.js ├── 50_init.js ├── 51_seed.js ├── 54_rebuild.js ├── 55_check.js ├── 56_dirtree.js ├── 57_resort.js ├── 58_btree.js ├── 59_rebuild.js ├── 60_writehead.js ├── 61_layout.js ├── 62_alloc.js ├── 63_header.js ├── 64_difat.js ├── 65_fat.js ├── 66_dir.js ├── 67_stream.js ├── 68_mini.js ├── 69_writefoot.js ├── 70_find.js ├── 75_consts.js ├── 77_writeutils.js ├── 78_zlib.js ├── 79_flate.js ├── 80_deflate.js ├── 81_inflate.js ├── 82_zparse.js ├── 83_zwrite.js ├── 84_mht.js ├── 85_api.js ├── 88_cfbexports.js ├── 89_cfbfooter.js ├── 98_exports.js └── 99_footer.js ├── cfb.flow.js ├── cfb.js ├── dist ├── .npmignore ├── LICENSE ├── cfb.js ├── cfb.min.js ├── cfb.min.map └── xlscfb.js ├── fails.lst ├── index.html ├── misc ├── flow.js ├── flowdeps.js ├── help.sh ├── node_version.sh ├── spin.sh ├── strip_sourcemap.sh └── xlscfb.js ├── package.json ├── packages └── cfb-cli │ ├── .npmignore │ ├── LICENSE │ ├── README.md │ ├── bin │ └── cfb.njs │ ├── index.js │ └── package.json ├── shim.js ├── test.js ├── types ├── bin_cfb.ts ├── index.d.ts ├── roundtrip.ts ├── tsconfig.json └── tslint.json ├── xlscfb.flow.js └── xlscfb.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { "shared-node-browser":true }, 3 | "globals": {}, 4 | "parserOptions": { 5 | "ecmaVersion": 3 6 | }, 7 | "plugins": [ "html", "json" ], 8 | "extends": "eslint:recommended", 9 | "rules": { 10 | "comma-style": [ 2, "last" ], 11 | "comma-dangle": [ 2, "never" ], 12 | "curly": 0, 13 | "no-bitwise": 0, 14 | "no-console": 0, 15 | "no-control-regex": 0, 16 | "no-empty": 0, 17 | "no-trailing-spaces": 2, 18 | "no-use-before-define": [ 1, { 19 | "functions":false, "classes":true, "variables":false 20 | }], 21 | "no-useless-escape": 0, 22 | "semi": [ 2, "always" ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/.* 3 | .*/dist/.* 4 | .*/test_files/.* 5 | .*/test_files_pres/.* 6 | 7 | .*/bits/.* 8 | .*/ctest/.* 9 | .*/misc/.* 10 | .*/perf/.* 11 | 12 | .*/demo/browser.js 13 | .*/shim.js 14 | 15 | .*/xlscfb.js 16 | .*/cfb.js 17 | .*/jszip.js 18 | .*/tests/.* 19 | .*/demos/.* 20 | 21 | [include] 22 | cfb.flow.js 23 | xlscfb.flow.js 24 | .*/bin/.*.njs 25 | test.js 26 | 27 | [libs] 28 | bits/10_types.js 29 | misc/flow.js 30 | misc/flowdeps.js 31 | 32 | [options] 33 | module.file_ext=.js 34 | module.file_ext=.njs 35 | module.ignore_non_literal_requires=true 36 | suppress_comment= \\(.\\|\n\\)*\\$FlowIgnore 37 | 38 | -------------------------------------------------------------------------------- /.github/workflows/node-4+.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | matrix: 7 | runs-on: ubuntu-latest 8 | outputs: 9 | latest: ${{ steps.set-matrix.outputs.requireds }} 10 | steps: 11 | - uses: ljharb/actions/node/matrix@main 12 | id: set-matrix 13 | with: 14 | versionsAsRoot: true 15 | type: 'majors' 16 | preset: '>=4' 17 | 18 | latest: 19 | needs: [matrix] 20 | name: 'latest majors' 21 | runs-on: ubuntu-latest 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | node-version: ${{ fromJson(needs.matrix.outputs.latest) }} 27 | include: 28 | - node-version: '14.' 29 | env: 30 | TZ: America/New_York 31 | - node-version: '13.' 32 | env: 33 | TZ: Europe/London 34 | - node-version: '12.' 35 | env: 36 | TZ: Asia/Seoul 37 | - node-version: '11.' 38 | env: 39 | TZ: America/Los_Angeles 40 | FMTS: misc 41 | - node-version: '10.' 42 | env: 43 | TZ: Europe/Berlin 44 | FMTS: misc 45 | - node-version: '9.' 46 | env: 47 | TZ: Asia/Kolkata 48 | FMTS: misc 49 | - node-version: '8.' 50 | env: 51 | TZ: Asia/Shanghai 52 | FMTS: misc 53 | - node-version: '7.' 54 | env: 55 | TZ: America/Cancun 56 | FMTS: misc 57 | - node-version: '6.' 58 | env: 59 | TZ: Asia/Seoul 60 | FMTS: misc 61 | - node-version: '5.' 62 | env: 63 | TZ: America/Anchorage 64 | FMTS: misc 65 | - node-version: '4.' 66 | env: 67 | TZ: America/Barbados 68 | FMTS: misc 69 | - node-version: '4.4.7' # see GH issue #1150 70 | env: 71 | TZ: Asia/Tokyo 72 | FMTS: misc 73 | 74 | steps: 75 | - uses: actions/checkout@v2 76 | - uses: ljharb/actions/node/install@main 77 | name: 'nvm install ${{ matrix.node-version }} && npm install' 78 | with: 79 | node-version: ${{ matrix.node-version }} 80 | - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 81 | - run: sudo chmod a+x /usr/bin/rooster 82 | - run: make init 83 | - run: 'cd test_files; make all; cd -' 84 | - run: npm run test 85 | 86 | node: 87 | name: 'node 4+' 88 | needs: [latest] 89 | runs-on: ubuntu-latest 90 | steps: 91 | - run: 'echo tests completed' 92 | -------------------------------------------------------------------------------- /.github/workflows/node-iojs.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js (io.js)' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | matrix: 7 | runs-on: ubuntu-latest 8 | outputs: 9 | latest: ${{ steps.set-matrix.outputs.requireds }} 10 | steps: 11 | - uses: ljharb/actions/node/matrix@main 12 | id: set-matrix 13 | with: 14 | type: 'majors' 15 | preset: 'iojs' 16 | 17 | latest: 18 | needs: [matrix] 19 | name: 'latest majors' 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: ${{ fromJson(needs.matrix.outputs.latest) }} 25 | 26 | steps: 27 | - uses: actions/checkout@v2 28 | - uses: ljharb/actions/node/install@main 29 | name: 'nvm install ${{ matrix.node-version }} && npm install' 30 | with: 31 | node-version: ${{ matrix.node-version }} 32 | skip-ls-check: true 33 | - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 34 | - run: sudo chmod a+x /usr/bin/rooster 35 | - run: make init 36 | - run: 'cd test_files; make all; cd -' 37 | - run: npm run test 38 | #- run: 'cd packages/ssf; npm run tests-only; cd -' 39 | 40 | node: 41 | name: 'io.js' 42 | needs: [latest] 43 | runs-on: ubuntu-latest 44 | steps: 45 | - run: 'echo tests completed' 46 | -------------------------------------------------------------------------------- /.github/workflows/node-pretest.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: pretest/posttest' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | pretest: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: ljharb/actions/node/install@main 12 | name: 'nvm install lts/* && npm install' 13 | with: 14 | node-version: 'lts/*' 15 | - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 16 | - run: sudo chmod a+x /usr/bin/rooster 17 | - run: make init 18 | - run: 'cd test_files; make all; cd -' 19 | #- run: npm run pretest 20 | 21 | # posttest: 22 | # runs-on: ubuntu-latest 23 | 24 | # steps: 25 | # - uses: actions/checkout@v2 26 | # - uses: ljharb/actions/node/install@main 27 | # name: 'nvm install lts/* && npm install' 28 | # with: 29 | # node-version: 'lts/*' 30 | # - run: make init 31 | # - run: 'cd test_files; make all; cd -' 32 | # - run: npm run posttest 33 | -------------------------------------------------------------------------------- /.github/workflows/node-zero.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js (0.x)' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | matrix: 7 | runs-on: ubuntu-latest 8 | outputs: 9 | stable: ${{ steps.set-matrix.outputs.requireds }} 10 | # unstable: ${{ steps.set-matrix.outputs.optionals }} 11 | steps: 12 | - uses: ljharb/actions/node/matrix@main 13 | id: set-matrix 14 | with: 15 | versionsAsRoot: true 16 | preset: '0.x' 17 | 18 | stable: 19 | needs: [matrix] 20 | name: 'stable minors' 21 | runs-on: ubuntu-latest 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | node-version: ${{ fromJson(needs.matrix.outputs.stable) }} 27 | include: 28 | - node-version: '0.12.' 29 | env: 30 | TZ: America/Cayman 31 | FMTS: misc 32 | - node-version: '0.10.' 33 | env: 34 | TZ: Pacific/Honolulu 35 | FMTS: misc 36 | - node-version: '0.8.' 37 | env: 38 | TZ: America/Mexico_City 39 | FMTS: misc 40 | 41 | steps: 42 | - uses: actions/checkout@v2 43 | - uses: ljharb/actions/node/install@main 44 | name: 'nvm install ${{ matrix.node-version }} && npm install' 45 | with: 46 | node-version: ${{ matrix.node-version }} 47 | cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }} 48 | skip-ls-check: true 49 | - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 50 | - run: sudo chmod a+x /usr/bin/rooster 51 | - run: make init 52 | - run: 'cd test_files; make all; cd -' 53 | - run: npm run test 54 | #- run: 'cd packages/ssf; npm run tests-only; cd -' 55 | 56 | # unstable: 57 | # needs: [matrix, stable] 58 | # name: 'unstable minors' 59 | # continue-on-error: true 60 | # if: ${{ !github.head_ref || !startsWith(github.head_ref, 'renovate') }} 61 | # runs-on: ubuntu-latest 62 | 63 | # strategy: 64 | # fail-fast: false 65 | # matrix: 66 | # node-version: ${{ fromJson(needs.matrix.outputs.unstable) }} 67 | # 68 | # steps: 69 | # - uses: actions/checkout@v2 70 | # - uses: ljharb/actions/node/install@main 71 | # name: 'nvm install ${{ matrix.node-version }} && npm install' 72 | # with: 73 | # node-version: ${{ matrix.node-version }} 74 | # cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }} 75 | # skip-ls-check: true 76 | # - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64 77 | # - run: sudo chmod a+x /usr/bin/rooster 78 | # - run: make init 79 | # - run: 'cd test_files; make all; cd -' 80 | # - run: npm run tests-only 81 | 82 | node: 83 | name: 'node 0.x' 84 | # needs: [stable, unstable] 85 | needs: [stable] 86 | runs-on: ubuntu-latest 87 | steps: 88 | - run: 'echo tests completed' 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | *.tgz 4 | misc/coverage.html 5 | prof.js 6 | v8.log 7 | test_files 8 | test_files_pres 9 | *.[tT][xX][tT] 10 | *.[cC][sS][vV] 11 | *.[dD][iIbB][fF] 12 | *.[pP][rR][nN] 13 | *.[pP][mM][dD]* 14 | *.[pP][dD][fF] 15 | *.[sS][lL][kK] 16 | *.socialcalc 17 | *.[xX][lL][sSwWcCaAtTmM] 18 | *.[xX][lL][sSaAtT][xXmMbB] 19 | *.[oO][dD][sS] 20 | *.[fF][oO][dD][sS] 21 | *.[xX][mM][lL] 22 | *.[uU][oO][sS] 23 | *.[wW][kKqQbB][S1234567890] 24 | *.[qQ][pP][wW] 25 | *.[bB][iI][fF][fF][23458] 26 | *.[rR][tT][fF] 27 | *.[eE][tT][hH] 28 | *.[zZ][iI][pP] 29 | *.[mM][sS][iIgG] 30 | *.[mM][hH][tT] 31 | *.123 32 | *.htm 33 | *.html 34 | *.sheetjs 35 | *.exe 36 | *.img 37 | -------------------------------------------------------------------------------- /.jscs.json: -------------------------------------------------------------------------------- 1 | { 2 | "requireCommaBeforeLineBreak": true, 3 | "disallowTrailingWhitespace": true, 4 | "disallowTrailingComma": true 5 | } 6 | 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": false, 3 | "curly": false 4 | } 5 | -------------------------------------------------------------------------------- /.spelling: -------------------------------------------------------------------------------- 1 | # cfb.js (C) 2013-present SheetJS -- http://sheetjs.com 2 | SheetJS 3 | js-xlsx 4 | 5 | # CFB-related terms 6 | CFB 7 | storages 8 | 9 | # Third-party 10 | NPM 11 | nodejs 12 | npm 13 | 14 | # Other terms 15 | Base64 16 | metadata 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: xenial 3 | node_js: 4 | - "14" 5 | - "13" 6 | - "12" 7 | - "11" 8 | - "10" 9 | - "9" 10 | - "8" 11 | - "7" 12 | - "6" 13 | - "5" 14 | - "4" 15 | - "0.12" 16 | - "0.10" 17 | - "0.8" 18 | before_install: 19 | - "npm config set strict-ssl false" 20 | - "./misc/node_version.sh" 21 | - "npm install -g mocha@2.x voc" 22 | - "npm install blanket" 23 | - "npm install word crc-32" 24 | - "npm install coveralls mocha-lcov-reporter" 25 | before_script: 26 | - "make init" 27 | install: 28 | - npm install 29 | after_success: 30 | - "make coveralls-spin" 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | This log is intended to keep track of backwards-incompatible changes, including 4 | but not limited to API changes and file location changes. Minor behavioral 5 | changes may not be included if they are not expected to break existing code. 6 | 7 | ## 1.2.1 (2021-09-06) 8 | 9 | * CFB write optimizations (h/t @rossj Ross Johnson) 10 | * `read` in NodeJS will treat `Buffer` input as type `"buffer"` by default 11 | * `deflate` / ZIP support fixed Huffman compression 12 | * `inflate` more aggressive reallocs 13 | 14 | ## 1.2.0 (2020-07-09) 15 | 16 | * Support for MAD file format (MIME aggregate document) 17 | * Spun off the CLI tool to the `cfb-cli` module 18 | 19 | ## 1.1.0 (2018-09-04) 20 | 21 | * Support for ZIP file format 22 | 23 | ## 1.0.6 (2018-04-09) 24 | 25 | * `lastIndexOf` in FAT builder enables larger file parsing at minor cost 26 | 27 | ## 1.0.0 (2017-11-05) 28 | 29 | * Actually walk mini-fat 30 | 31 | ## 0.14.0 (2017-11-04) 32 | 33 | * Completely removed `FullPathDir` 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (C) 2013-present SheetJS LLC 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/bin/bash 2 | LIB=cfb 3 | FMT=xls doc ppt misc full 4 | REQS= 5 | ADDONS= 6 | AUXTARGETS=xlscfb.js 7 | CMDS=packages/cfb-cli/bin/cfb.njs 8 | HTMLLINT=index.html 9 | 10 | ULIB=$(shell echo $(LIB) | tr a-z A-Z) 11 | DEPS=$(sort $(wildcard bits/*.js)) 12 | TARGET=$(LIB).js 13 | FLOWTARGET=$(LIB).flow.js 14 | FLOWTGTS=$(TARGET) $(AUXTARGETS) 15 | UGLIFYOPTS=--support-ie8 -m 16 | CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar 17 | 18 | ## Main Targets 19 | 20 | .PHONY: all 21 | all: $(TARGET) $(AUXTARGETS) ## Build library and auxiliary scripts 22 | 23 | $(FLOWTGTS): %.js : %.flow.js 24 | node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@ 25 | 26 | $(FLOWTARGET): $(DEPS) 27 | cat $^ | tr -d '\15\32' > $@ 28 | 29 | bits/31_version.js: package.json 30 | echo "exports.version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@ 31 | 32 | .PHONY: clean 33 | clean: ## Remove targets and build artifacts 34 | rm -f $(TARGET) $(FLOWTARGET) xlscfb.js xlscfb.flow.js 35 | 36 | .PHONY: clean-data 37 | clean-data: 38 | rm -fr ./test_files/ ./test_files_pres/ 39 | 40 | .PHONY: init 41 | init: ## Initial setup for development 42 | if [ ! -e test_files ]; then git clone --depth=1 https://github.com/SheetJS/test_files; fi 43 | cd test_files; git pull; make 44 | if [ ! -e test_files_pres ]; then git clone --depth=1 https://github.com/SheetJS/test_files_pres; fi 45 | cd test_files_pres; git pull 46 | 47 | .PHONY: dist 48 | dist: dist-deps $(TARGET) ## Prepare JS files for distribution 49 | mkdir -p dist 50 | cp LICENSE dist/ 51 | cp $(TARGET) dist/ 52 | uglifyjs $(TARGET) $(UGLIFYOPTS) -o dist/$(LIB).min.js --source-map dist/$(LIB).min.map --preamble "$$(head -n 1 bits/00_header.js)" 53 | misc/strip_sourcemap.sh dist/$(LIB).min.js 54 | 55 | .PHONY: dist-deps 56 | dist-deps: xlscfb.js ## Copy dependencies for distribution 57 | mkdir -p dist 58 | cp xlscfb.flow.js dist/xlscfb.js 59 | 60 | .PHONY: aux 61 | aux: $(AUXTARGETS) 62 | 63 | .PHONY: xls 64 | xls: xlscfb.js 65 | 66 | XLSSKIP=bits/08_blob.js bits/04_base64.js bits/05_buf.js bits/98_exports.js 67 | XLSDEPS=misc/xlscfb.js $(filter-out $(XLSSKIP),$(DEPS)) 68 | xlscfb.flow.js: $(XLSDEPS) ## Build support library 69 | cat $^ | tr -d '\15\32' | grep -v DO_NOT_EXPORT_CFB > $@ 70 | 71 | BYTEFILE=dist/cfb.min.js dist/xlscfb.js 72 | .PHONY: bytes 73 | bytes: ## Display minified and gzipped file sizes 74 | for i in $(BYTEFILE); do npx printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done 75 | 76 | 77 | ## Testing 78 | 79 | .PHONY: test mocha 80 | test mocha: test.js $(TARGET) ## Run test suite 81 | mocha -R spec -t 20000 82 | 83 | #* To run tests for one format, make test_ 84 | #* To run the core test suite, make test_misc 85 | TESTFMT=$(patsubst %,test_%,$(FMT)) 86 | .PHONY: $(TESTFMT) 87 | $(TESTFMT): test_%: 88 | FMTS=$* make test 89 | 90 | 91 | ## Code Checking 92 | 93 | .PHONY: fullint 94 | fullint: lint old-lint tslint flow mdlint ## Run all checks 95 | 96 | .PHONY: lint 97 | lint: $(TARGET) $(AUXTARGETS) ## Run eslint checks 98 | @./node_modules/.bin/eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(CMDS) $(HTMLLINT) package.json 99 | @if [ -x "$(CLOSURE)" ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi 100 | 101 | .PHONY: old-lint 102 | old-lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks 103 | @./node_modules/.bin/jscs $(TARGET) $(AUXTARGETS) test.js 104 | @./node_modules/.bin/jshint --show-non-errors $(TARGET) $(AUXTARGETS) 105 | @./node_modules/.bin/jshint --show-non-errors $(CMDS) 106 | @./node_modules/.bin/jshint --show-non-errors package.json test.js 107 | @./node_modules/.bin/jshint --show-non-errors --extract=always $(HTMLLINT) 108 | @if [ -x "$(CLOSURE)" ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi 109 | 110 | .PHONY: tslint 111 | tslint: $(TARGET) ## Run typescript checks 112 | #@npm install dtslint typescript 113 | #@npm run-script dtslint 114 | ./node_modules/.bin/dtslint types 115 | 116 | .PHONY: flow 117 | flow: lint ## Run flow checker 118 | @flow check --all --show-all-errors --include-warnings 119 | 120 | .PHONY: cov 121 | cov: misc/coverage.html ## Run coverage test 122 | 123 | misc/coverage.html: $(TARGET) test.js 124 | mocha --require blanket -R html-cov -t 20000 > $@ 125 | 126 | .PHONY: coveralls 127 | coveralls: ## Coverage Test + Send to coveralls.io 128 | mocha --require blanket --reporter mocha-lcov-reporter -t 20000 | node ./node_modules/coveralls/bin/coveralls.js 129 | 130 | MDLINT=README.md 131 | .PHONY: mdlint 132 | mdlint: $(MDLINT) ## Check markdown documents 133 | alex $^ 134 | mdspell -a -n -x -r --en-us $^ 135 | 136 | .PHONY: help 137 | help: 138 | @grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) | bash misc/help.sh 139 | 140 | #* To show a spinner, append "-spin" to any target e.g. cov-spin 141 | %-spin: 142 | @make $* & bash misc/spin.sh $$! 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Container File Blobs 2 | 3 | Pure JS implementation of various container file formats, including ZIP and CFB. 4 | 5 | [![Build Status](https://travis-ci.org/SheetJS/js-cfb.svg?branch=master)](https://travis-ci.org/SheetJS/js-cfb) 6 | [![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-cfb/master.svg)](https://coveralls.io/r/SheetJS/js-cfb?branch=master) 7 | [![Dependencies Status](https://david-dm.org/sheetjs/js-cfb/status.svg)](https://david-dm.org/sheetjs/js-cfb) 8 | [![NPM Downloads](https://img.shields.io/npm/dt/cfb.svg)](https://npmjs.org/package/cfb) 9 | [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-cfb?pixel)](https://github.com/SheetJS/js-cfb) 10 | 11 | ## Installation 12 | 13 | In the browser: 14 | 15 | ```html 16 | 17 | ``` 18 | 19 | With [npm](https://www.npmjs.org/package/cfb): 20 | 21 | ```bash 22 | $ npm install cfb 23 | ``` 24 | 25 | The `xlscfb.js` file is designed to be embedded in [js-xlsx](https://github.com/SheetJS/sheetjs) 26 | 27 | 28 | ## Library Usage 29 | 30 | In node: 31 | 32 | ```js 33 | var CFB = require('cfb'); 34 | ``` 35 | 36 | For example, to get the Workbook content from an Excel 2003 XLS file: 37 | 38 | ```js 39 | var cfb = CFB.read(filename, {type: 'file'}); 40 | var workbook = CFB.find(cfb, 'Workbook'); 41 | var data = workbook.content; 42 | ``` 43 | 44 | 45 | ## Command-Line Utility Usage 46 | 47 | The [`cfb-cli`](https://www.npmjs.com/package/cfb-cli) module ships with a CLI 48 | tool for manipulating and inspecting supported files. 49 | 50 | 51 | ## JS API 52 | 53 | TypeScript definitions are maintained in `types/index.d.ts`. 54 | 55 | The CFB object exposes the following methods and properties: 56 | 57 | `CFB.parse(blob)` takes a nodejs Buffer or an array of bytes and returns an 58 | parsed representation of the data. 59 | 60 | `CFB.read(blob, opts)` wraps `parse`. 61 | 62 | `CFB.find(cfb, path)` performs a case-insensitive match for the path (or file 63 | name, if there are no slashes) and returns an entry object or null if not found. 64 | 65 | `CFB.write(cfb, opts)` generates a file based on the container. 66 | 67 | `CFB.writeFile(cfb, filename, opts)` creates a file with the specified name. 68 | 69 | ### Parse Options 70 | 71 | `CFB.read` takes an options argument. `opts.type` controls the behavior: 72 | 73 | | `type` | expected input | 74 | |------------|:----------------------------------------------------------------| 75 | | `"base64"` | string: Base64 encoding of the file | 76 | | `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) | 77 | | `"buffer"` | nodejs Buffer | 78 | | `"file"` | string: path of file that will be read (nodejs only) | 79 | | (default) | buffer or array of 8-bit unsigned int (byte `n` is `data[n]`) | 80 | 81 | 82 | ### Write Options 83 | 84 | `CFB.write` and `CFB.writeFile` take options argument. 85 | 86 | `opts.type` controls the behavior: 87 | 88 | | `type` | output | 89 | |------------|:----------------------------------------------------------------| 90 | | `"base64"` | string: Base64 encoding of the file | 91 | | `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) | 92 | | `"buffer"` | nodejs Buffer | 93 | | `"file"` | string: path of file that will be created (nodejs only) | 94 | | (default) | buffer if available, array of 8-bit unsigned int otherwise | 95 | 96 | `opts.fileType` controls the output file type: 97 | 98 | | `fileType` | output | 99 | |:-------------------|:------------------------| 100 | | `'cfb'` (default) | CFB container | 101 | | `'zip'` | ZIP file | 102 | | `'mad'` | MIME aggregate document | 103 | 104 | `opts.compression` enables DEFLATE compression for ZIP file type. 105 | 106 | 107 | ## Utility Functions 108 | 109 | The utility functions are available in the `CFB.utils` object. Functions that 110 | accept a `name` argument strictly deal with absolute file names: 111 | 112 | - `.cfb_new(?opts)` creates a new container object. 113 | - `.cfb_add(cfb, name, ?content, ?opts)` adds a new file to the `cfb`. 114 | Set the option `{unsafe:true}` to skip existence checks (for bulk additions) 115 | - `.cfb_del(cfb, name)` deletes the specified file 116 | - `.cfb_mov(cfb, old_name, new_name)` moves the old file to new path and name 117 | - `.use_zlib(require("zlib"))` loads a nodejs `zlib` instance. 118 | 119 | By default, the library uses a pure JS inflate/deflate implementation. NodeJS 120 | `zlib.InflateRaw` exposes the number of bytes read in versions after `8.11.0`. 121 | If a supplied `zlib` does not support the required features, a warning will be 122 | displayed in the console and the pure JS fallback will be used. 123 | 124 | 125 | ## Container Object Description 126 | 127 | The objects returned by `parse` and `read` have the following properties: 128 | 129 | - `.FullPaths` is an array of the names of all of the streams (files) and 130 | storages (directories) in the container. The paths are properly prefixed from 131 | the root entry (so the entries are unique) 132 | 133 | - `.FileIndex` is an array, in the same order as `.FullPaths`, whose values are 134 | objects following the schema: 135 | 136 | ```typescript 137 | interface CFBEntry { 138 | name: string; /** Case-sensitive internal name */ 139 | type: number; /** 1 = dir, 2 = file, 5 = root ; see [MS-CFB] 2.6.1 */ 140 | content: Buffer | number[] | Uint8Array; /** Raw Content */ 141 | ct?: Date; /** Creation Time */ 142 | mt?: Date; /** Modification Time */ 143 | ctype?: String; /** Content-Type (for MAD) */ 144 | } 145 | ``` 146 | 147 | 148 | ## License 149 | 150 | Please consult the attached LICENSE file for details. All rights not explicitly 151 | granted by the Apache 2.0 License are reserved by the Original Author. 152 | 153 | 154 | ## References 155 | 156 | - `MS-CFB`: Compound File Binary File Format 157 | - ZIP `APPNOTE.TXT`: .ZIP File Format Specification 158 | - RFC1951: https://www.ietf.org/rfc/rfc1951.txt 159 | - RFC2045: https://www.ietf.org/rfc/rfc2045.txt 160 | - RFC2557: https://www.ietf.org/rfc/rfc2557.txt 161 | 162 | -------------------------------------------------------------------------------- /bits/00_header.js: -------------------------------------------------------------------------------- 1 | /* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */ 2 | /* vim: set ts=2: */ 3 | /*jshint eqnull:true */ 4 | /*exported CFB */ 5 | /*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */ 6 | 7 | -------------------------------------------------------------------------------- /bits/04_base64.js: -------------------------------------------------------------------------------- 1 | var Base64_map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 2 | function Base64_encode(input/*:string*/)/*:string*/ { 3 | var o = ""; 4 | var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; 5 | for (var i = 0; i < input.length; ) { 6 | c1 = input.charCodeAt(i++); 7 | e1 = (c1 >> 2); 8 | c2 = input.charCodeAt(i++); 9 | e2 = ((c1 & 3) << 4) | (c2 >> 4); 10 | c3 = input.charCodeAt(i++); 11 | e3 = ((c2 & 15) << 2) | (c3 >> 6); 12 | e4 = (c3 & 63); 13 | if (isNaN(c2)) e3 = e4 = 64; 14 | else if (isNaN(c3)) e4 = 64; 15 | o += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4); 16 | } 17 | return o; 18 | } 19 | function Base64_decode(input/*:string*/)/*:string*/ { 20 | var o = ""; 21 | var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0; 22 | input = input.replace(/[^\w\+\/\=]/g, ""); 23 | for (var i = 0; i < input.length;) { 24 | e1 = Base64_map.indexOf(input.charAt(i++)); 25 | e2 = Base64_map.indexOf(input.charAt(i++)); 26 | c1 = (e1 << 2) | (e2 >> 4); 27 | o += String.fromCharCode(c1); 28 | e3 = Base64_map.indexOf(input.charAt(i++)); 29 | c2 = ((e2 & 15) << 4) | (e3 >> 2); 30 | if (e3 !== 64) o += String.fromCharCode(c2); 31 | e4 = Base64_map.indexOf(input.charAt(i++)); 32 | c3 = ((e3 & 3) << 6) | e4; 33 | if (e4 !== 64) o += String.fromCharCode(c3); 34 | } 35 | return o; 36 | } 37 | -------------------------------------------------------------------------------- /bits/05_buf.js: -------------------------------------------------------------------------------- 1 | var has_buf = /*#__PURE__*/(function() { return typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node; })(); 2 | 3 | var Buffer_from = /*#__PURE__*/(function() { 4 | if(typeof Buffer !== 'undefined') { 5 | var nbfs = !Buffer.from; 6 | if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; } 7 | return nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer); 8 | } 9 | return function() {}; 10 | })(); 11 | 12 | 13 | function new_raw_buf(len/*:number*/) { 14 | /* jshint -W056 */ 15 | if(has_buf) { 16 | if(Buffer.alloc) return Buffer.alloc(len); 17 | var b = new Buffer(len); b.fill(0); return b; 18 | } 19 | return typeof Uint8Array != "undefined" ? new Uint8Array(len) : new Array(len); 20 | /* jshint +W056 */ 21 | } 22 | 23 | function new_unsafe_buf(len/*:number*/) { 24 | /* jshint -W056 */ 25 | if(has_buf) return Buffer.allocUnsafe ? Buffer.allocUnsafe(len) : new Buffer(len); 26 | return typeof Uint8Array != "undefined" ? new Uint8Array(len) : new Array(len); 27 | /* jshint +W056 */ 28 | } 29 | 30 | var s2a = function s2a(s/*:string*/)/*:RawBytes*/ { 31 | if(has_buf) return Buffer_from(s, "binary"); 32 | return s.split("").map(function(x/*:string*/)/*:number*/{ return x.charCodeAt(0) & 0xff; }); 33 | }; 34 | 35 | var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g; 36 | -------------------------------------------------------------------------------- /bits/08_blob.js: -------------------------------------------------------------------------------- 1 | var __toBuffer = function(bufs/*:Array >*/)/*:RawBytes*/ { var x = []; for(var i = 0; i < bufs[0].length; ++i) { x.push.apply(x, bufs[0][i]); } return x; }; 2 | var ___toBuffer = __toBuffer; 3 | var __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { var ss/*:Array*/=[]; for(var i=s; i*/=[]; for(var i=s; i*/)/*:RawBytes*/ { 8 | if(Array.isArray(bufs[0])/*:: && bufs[0] instanceof Array*/) return /*::(*/[].concat.apply([], bufs)/*:: :any)*/; 9 | var maxlen = 0, i = 0; 10 | for(i = 0; i < bufs.length; ++i) maxlen += bufs[i].length; 11 | var o = new Uint8Array(maxlen); 12 | for(i = 0, maxlen = 0; i < bufs.length; maxlen += bufs[i].length, ++i) o.set(bufs[i], maxlen); 13 | return o; 14 | }; 15 | var bconcat = __bconcat; 16 | 17 | 18 | if(has_buf/*:: && typeof Buffer !== 'undefined'*/) { 19 | __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { 20 | if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___utf16le(b,s,e); 21 | return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; 22 | }; 23 | __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); }; 24 | __toBuffer = function(bufs/*:Array>*/)/*:RawBytes*/ { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat((bufs[0]/*:any*/)) : ___toBuffer(bufs);}; 25 | s2a = function(s/*:string*/)/*:RawBytes*/ { return Buffer_from(s, "binary"); }; 26 | bconcat = function(bufs/*:Array*/)/*:RawBytes*/ { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(/*::(*/bufs/*:: :any)*/) : __bconcat(bufs); }; 27 | } 28 | 29 | 30 | var __readUInt8 = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx]; }; 31 | var __readUInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx+1]*(1<<8)+b[idx]; }; 32 | var __readInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { var u = b[idx+1]*(1<<8)+b[idx]; return (u < 0x8000) ? u : (0xffff - u + 1) * -1; }; 33 | var __readUInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; }; 34 | var __readInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx+3]<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; }; 35 | 36 | function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ { 37 | var oI/*:: :number = 0*/, oS/*:: :string = ""*/, type = 0; 38 | switch(size) { 39 | case 1: oI = __readUInt8(this, this.l); break; 40 | case 2: oI = (t !== 'i' ? __readUInt16LE : __readInt16LE)(this, this.l); break; 41 | case 4: oI = __readInt32LE(this, this.l); break; 42 | case 16: type = 2; oS = __hexlify(this, this.l, size); 43 | } 44 | this.l += size; if(type === 0) return oI; return oS; 45 | } 46 | 47 | var __writeUInt32LE = function(b/*:RawBytes|CFBlob*/, val/*:number*/, idx/*:number*/)/*:void*/ { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); b[idx+2] = ((val >>> 16) & 0xFF); b[idx+3] = ((val >>> 24) & 0xFF); }; 48 | var __writeInt32LE = function(b/*:RawBytes|CFBlob*/, val/*:number*/, idx/*:number*/)/*:void*/ { b[idx] = (val & 0xFF); b[idx+1] = ((val >> 8) & 0xFF); b[idx+2] = ((val >> 16) & 0xFF); b[idx+3] = ((val >> 24) & 0xFF); }; 49 | 50 | function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/ { 51 | var size = 0, i = 0; 52 | switch(f) { 53 | case "hex": for(; i < t; ++i) { 54 | /*:: if(typeof val !== "string") throw new Error("unreachable"); */ 55 | this[this.l++] = parseInt(val.slice(2*i, 2*i+2), 16)||0; 56 | } return this; 57 | case "utf16le": 58 | /*:: if(typeof val !== "string") throw new Error("unreachable"); */ 59 | var end/*:number*/ = this.l + t; 60 | for(i = 0; i < Math.min(val.length, t); ++i) { 61 | var cc = val.charCodeAt(i); 62 | this[this.l++] = cc & 0xff; 63 | this[this.l++] = cc >> 8; 64 | } 65 | while(this.l < end) this[this.l++] = 0; 66 | return this; 67 | } 68 | /*:: if(typeof val !== "number") throw new Error("unreachable"); */ 69 | switch(t) { 70 | case 1: size = 1; this[this.l] = val&0xFF; break; 71 | case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break; 72 | case 4: size = 4; __writeUInt32LE(this, val, this.l); break; 73 | case -4: size = 4; __writeInt32LE(this, val, this.l); break; 74 | } 75 | this.l += size; return this; 76 | } 77 | 78 | function CheckField(hexstr/*:string*/, fld/*:string*/)/*:void*/ { 79 | var m = __hexlify(this,this.l,hexstr.length>>1); 80 | if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m); 81 | this.l += hexstr.length>>1; 82 | } 83 | 84 | function prep_blob(blob/*:CFBlob*/, pos/*:number*/)/*:void*/ { 85 | blob.l = pos; 86 | blob.read_shift = /*::(*/ReadShift/*:: :any)*/; 87 | blob.chk = CheckField; 88 | blob.write_shift = WriteShift; 89 | } 90 | 91 | function new_buf(sz/*:number*/)/*:any*/ { 92 | var o/*:CFBlob*/ = (new_raw_buf(sz)/*:any*/); 93 | prep_blob(o, 0); 94 | return o; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /bits/10_types.js: -------------------------------------------------------------------------------- 1 | /*:: 2 | declare var DO_NOT_EXPORT_CFB:?boolean; 3 | type SectorEntry = { 4 | name?:string; 5 | nodes?:Array; 6 | data:RawBytes; 7 | }; 8 | type SectorList = { 9 | [k:string|number]:SectorEntry; 10 | name:?string; 11 | fat_addrs:Array; 12 | ssz:number; 13 | } 14 | type CFBFiles = {[n:string]:CFBEntry}; 15 | */ 16 | -------------------------------------------------------------------------------- /bits/21_crc32.js: -------------------------------------------------------------------------------- 1 | /*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */ 2 | /* vim: set ts=2: */ 3 | /*exported CRC32 */ 4 | var CRC32 = /*#__PURE__*/(function() { 5 | var CRC32 = {}; 6 | CRC32.version = '1.2.1'; 7 | /*:: 8 | type ABuf = Array | Buffer | Uint8Array; 9 | type CRC32TableType = Array | Int32Array; 10 | */ 11 | /*global Int32Array */ 12 | function signed_crc_table()/*:CRC32TableType*/ { 13 | var c = 0, table/*:Array*/ = new Array(256); 14 | 15 | for(var n =0; n != 256; ++n){ 16 | c = n; 17 | c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 18 | c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 19 | c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 20 | c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 21 | c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 22 | c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 23 | c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 24 | c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 25 | table[n] = c; 26 | } 27 | 28 | return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table; 29 | } 30 | 31 | var T0 = signed_crc_table(); 32 | function slice_by_16_tables(T) { 33 | var c = 0, v = 0, n = 0, table/*:Array*/ = typeof Int32Array !== 'undefined' ? new Int32Array(4096) : new Array(4096) ; 34 | 35 | for(n = 0; n != 256; ++n) table[n] = T[n]; 36 | for(n = 0; n != 256; ++n) { 37 | v = T[n]; 38 | for(c = 256 + n; c < 4096; c += 256) v = table[c] = (v >>> 8) ^ T[v & 0xFF]; 39 | } 40 | var out = []; 41 | for(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256); 42 | return out; 43 | } 44 | var TT = slice_by_16_tables(T0); 45 | var T1 = TT[0], T2 = TT[1], T3 = TT[2], T4 = TT[3], T5 = TT[4]; 46 | var T6 = TT[5], T7 = TT[6], T8 = TT[7], T9 = TT[8], Ta = TT[9]; 47 | var Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14]; 48 | function crc32_bstr(bstr/*:string*/, seed/*:?number*/)/*:number*/ { 49 | var C = seed/*:: ? 0 : 0 */ ^ -1; 50 | for(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF]; 51 | return ~C; 52 | } 53 | 54 | function crc32_buf(B/*:ABuf*/, seed/*:?number*/)/*:number*/ { 55 | var C = seed/*:: ? 0 : 0 */ ^ -1, L = B.length - 15, i = 0; 56 | for(; i < L;) C = 57 | Tf[B[i++] ^ (C & 255)] ^ 58 | Te[B[i++] ^ ((C >> 8) & 255)] ^ 59 | Td[B[i++] ^ ((C >> 16) & 255)] ^ 60 | Tc[B[i++] ^ (C >>> 24)] ^ 61 | Tb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^ 62 | T7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^ 63 | T3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]]; 64 | L += 15; 65 | while(i < L) C = (C>>>8) ^ T0[(C^B[i++])&0xFF]; 66 | return ~C; 67 | } 68 | 69 | function crc32_str(str/*:string*/, seed/*:?number*/)/*:number*/ { 70 | var C = seed/*:: ? 0 : 0 */ ^ -1; 71 | for(var i = 0, L = str.length, c = 0, d = 0; i < L;) { 72 | c = str.charCodeAt(i++); 73 | if(c < 0x80) { 74 | C = (C>>>8) ^ T0[(C^c)&0xFF]; 75 | } else if(c < 0x800) { 76 | C = (C>>>8) ^ T0[(C ^ (192|((c>>6)&31)))&0xFF]; 77 | C = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF]; 78 | } else if(c >= 0xD800 && c < 0xE000) { 79 | c = (c&1023)+64; d = str.charCodeAt(i++)&1023; 80 | C = (C>>>8) ^ T0[(C ^ (240|((c>>8)&7)))&0xFF]; 81 | C = (C>>>8) ^ T0[(C ^ (128|((c>>2)&63)))&0xFF]; 82 | C = (C>>>8) ^ T0[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF]; 83 | C = (C>>>8) ^ T0[(C ^ (128|(d&63)))&0xFF]; 84 | } else { 85 | C = (C>>>8) ^ T0[(C ^ (224|((c>>12)&15)))&0xFF]; 86 | C = (C>>>8) ^ T0[(C ^ (128|((c>>6)&63)))&0xFF]; 87 | C = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF]; 88 | } 89 | } 90 | return ~C; 91 | } 92 | CRC32.table = T0; 93 | CRC32.bstr = crc32_bstr; 94 | CRC32.buf = crc32_buf; 95 | CRC32.str = crc32_str; 96 | return CRC32; 97 | })(); 98 | -------------------------------------------------------------------------------- /bits/30_cfbheader.js: -------------------------------------------------------------------------------- 1 | /* [MS-CFB] v20171201 */ 2 | var CFB = /*#__PURE__*/(function _CFB(){ 3 | var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/; 4 | -------------------------------------------------------------------------------- /bits/31_version.js: -------------------------------------------------------------------------------- 1 | exports.version = '1.2.2'; 2 | -------------------------------------------------------------------------------- /bits/33_sort.js: -------------------------------------------------------------------------------- 1 | /* [MS-CFB] 2.6.4 */ 2 | function namecmp(l/*:string*/, r/*:string*/)/*:number*/ { 3 | var L = l.split("/"), R = r.split("/"); 4 | for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) { 5 | if((c = L[i].length - R[i].length)) return c; 6 | if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1; 7 | } 8 | return L.length - R.length; 9 | } 10 | -------------------------------------------------------------------------------- /bits/35_path.js: -------------------------------------------------------------------------------- 1 | function dirname(p/*:string*/)/*:string*/ { 2 | if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1)); 3 | var c = p.lastIndexOf("/"); 4 | return (c === -1) ? p : p.slice(0, c+1); 5 | } 6 | 7 | function filename(p/*:string*/)/*:string*/ { 8 | if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1)); 9 | var c = p.lastIndexOf("/"); 10 | return (c === -1) ? p : p.slice(c+1); 11 | } 12 | -------------------------------------------------------------------------------- /bits/37_dosdates.js: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------- */ 2 | /* DOS Date format: 3 | high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low 4 | add 1980 to stored year 5 | stored second should be doubled 6 | */ 7 | 8 | /* write JS date to buf as a DOS date */ 9 | function write_dos_date(buf/*:CFBlob*/, date/*:Date|string*/) { 10 | if(typeof date === "string") date = new Date(date); 11 | var hms/*:number*/ = date.getHours(); 12 | hms = hms << 6 | date.getMinutes(); 13 | hms = hms << 5 | (date.getSeconds()>>>1); 14 | buf.write_shift(2, hms); 15 | var ymd/*:number*/ = (date.getFullYear() - 1980); 16 | ymd = ymd << 4 | (date.getMonth()+1); 17 | ymd = ymd << 5 | date.getDate(); 18 | buf.write_shift(2, ymd); 19 | } 20 | 21 | /* read four bytes from buf and interpret as a DOS date */ 22 | function parse_dos_date(buf/*:CFBlob*/)/*:Date*/ { 23 | var hms = buf.read_shift(2) & 0xFFFF; 24 | var ymd = buf.read_shift(2) & 0xFFFF; 25 | var val = new Date(); 26 | var d = ymd & 0x1F; ymd >>>= 5; 27 | var m = ymd & 0x0F; ymd >>>= 4; 28 | val.setMilliseconds(0); 29 | val.setFullYear(ymd + 1980); 30 | val.setMonth(m-1); 31 | val.setDate(d); 32 | var S = hms & 0x1F; hms >>>= 5; 33 | var M = hms & 0x3F; hms >>>= 6; 34 | val.setHours(hms); 35 | val.setMinutes(M); 36 | val.setSeconds(S<<1); 37 | return val; 38 | } 39 | -------------------------------------------------------------------------------- /bits/38_extrafield.js: -------------------------------------------------------------------------------- 1 | function parse_extra_field(blob/*:CFBlob*/)/*:any*/ { 2 | prep_blob(blob, 0); 3 | var o = /*::(*/{}/*:: :any)*/; 4 | var flags = 0; 5 | while(blob.l <= blob.length - 4) { 6 | var type = blob.read_shift(2); 7 | var sz = blob.read_shift(2), tgt = blob.l + sz; 8 | var p = {}; 9 | switch(type) { 10 | /* UNIX-style Timestamps */ 11 | case 0x5455: { 12 | flags = blob.read_shift(1); 13 | if(flags & 1) p.mtime = blob.read_shift(4); 14 | /* for some reason, CD flag corresponds to LFH */ 15 | if(sz > 5) { 16 | if(flags & 2) p.atime = blob.read_shift(4); 17 | if(flags & 4) p.ctime = blob.read_shift(4); 18 | } 19 | if(p.mtime) p.mt = new Date(p.mtime*1000); 20 | } 21 | break; 22 | } 23 | blob.l = tgt; 24 | o[type] = p; 25 | } 26 | return o; 27 | } 28 | -------------------------------------------------------------------------------- /bits/39_fs.js: -------------------------------------------------------------------------------- 1 | var fs/*:: = require('fs'); */; 2 | function get_fs() { return fs || (fs = require('fs')); } 3 | -------------------------------------------------------------------------------- /bits/40_parse.js: -------------------------------------------------------------------------------- 1 | function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ { 2 | if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options); 3 | if((file[0] | 0x20) == 0x6d && (file[1]|0x20) == 0x69) return parse_mad(file, options); 4 | if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512"); 5 | var mver = 3; 6 | var ssz = 512; 7 | var nmfs = 0; // number of mini FAT sectors 8 | var difat_sec_cnt = 0; 9 | var dir_start = 0; 10 | var minifat_start = 0; 11 | var difat_start = 0; 12 | 13 | var fat_addrs/*:Array*/ = []; // locations of FAT sectors 14 | 15 | /* [MS-CFB] 2.2 Compound File Header */ 16 | var blob/*:CFBlob*/ = /*::(*/file.slice(0,512)/*:: :any)*/; 17 | prep_blob(blob, 0); 18 | 19 | /* major version */ 20 | var mv = check_get_mver(blob); 21 | mver = mv[0]; 22 | switch(mver) { 23 | case 3: ssz = 512; break; case 4: ssz = 4096; break; 24 | case 0: if(mv[1] == 0) return parse_zip(file, options); 25 | /* falls through */ 26 | default: throw new Error("Major Version: Expected 3 or 4 saw " + mver); 27 | } 28 | 29 | /* reprocess header */ 30 | if(ssz !== 512) { blob = /*::(*/file.slice(0,ssz)/*:: :any)*/; prep_blob(blob, 28 /* blob.l */); } 31 | /* Save header for final object */ 32 | var header/*:RawBytes*/ = file.slice(0,ssz); 33 | 34 | check_shifts(blob, mver); 35 | 36 | // Number of Directory Sectors 37 | var dir_cnt/*:number*/ = blob.read_shift(4, 'i'); 38 | if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt); 39 | 40 | // Number of FAT Sectors 41 | blob.l += 4; 42 | 43 | // First Directory Sector Location 44 | dir_start = blob.read_shift(4, 'i'); 45 | 46 | // Transaction Signature 47 | blob.l += 4; 48 | 49 | // Mini Stream Cutoff Size 50 | blob.chk('00100000', 'Mini Stream Cutoff Size: '); 51 | 52 | // First Mini FAT Sector Location 53 | minifat_start = blob.read_shift(4, 'i'); 54 | 55 | // Number of Mini FAT Sectors 56 | nmfs = blob.read_shift(4, 'i'); 57 | 58 | // First DIFAT sector location 59 | difat_start = blob.read_shift(4, 'i'); 60 | 61 | // Number of DIFAT Sectors 62 | difat_sec_cnt = blob.read_shift(4, 'i'); 63 | 64 | // Grab FAT Sector Locations 65 | for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */ 66 | q = blob.read_shift(4, 'i'); 67 | if(q<0) break; 68 | fat_addrs[j] = q; 69 | } 70 | 71 | /** Break the file up into sectors */ 72 | var sectors/*:Array*/ = sectorify(file, ssz); 73 | 74 | sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs); 75 | 76 | /** Chains */ 77 | var sector_list/*:SectorList*/ = make_sector_list(sectors, dir_start, fat_addrs, ssz); 78 | 79 | sector_list[dir_start].name = "!Directory"; 80 | if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT"; 81 | sector_list[fat_addrs[0]].name = "!FAT"; 82 | sector_list.fat_addrs = fat_addrs; 83 | sector_list.ssz = ssz; 84 | 85 | /* [MS-CFB] 2.6.1 Compound File Directory Entry */ 86 | var files/*:CFBFiles*/ = {}, Paths/*:Array*/ = [], FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array*/ = []; 87 | read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start); 88 | 89 | build_full_paths(FileIndex, FullPaths, Paths); 90 | Paths.shift(); 91 | 92 | var o = { 93 | FileIndex: FileIndex, 94 | FullPaths: FullPaths 95 | }; 96 | 97 | // $FlowIgnore 98 | if(options && options.raw) o.raw = {header: header, sectors: sectors}; 99 | return o; 100 | } // parse 101 | 102 | -------------------------------------------------------------------------------- /bits/41_mver.js: -------------------------------------------------------------------------------- 1 | /* [MS-CFB] 2.2 Compound File Header -- read up to major version */ 2 | function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ { 3 | if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0]; 4 | // header signature 8 5 | blob.chk(HEADER_SIGNATURE, 'Header Signature: '); 6 | 7 | // clsid 16 8 | //blob.chk(HEADER_CLSID, 'CLSID: '); 9 | blob.l += 16; 10 | 11 | // minor version 2 12 | var mver/*:number*/ = blob.read_shift(2, 'u'); 13 | 14 | return [blob.read_shift(2,'u'), mver]; 15 | } 16 | function check_shifts(blob/*:CFBlob*/, mver/*:number*/)/*:void*/ { 17 | var shift = 0x09; 18 | 19 | // Byte Order 20 | //blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff 21 | blob.l += 2; 22 | 23 | // Sector Shift 24 | switch((shift = blob.read_shift(2))) { 25 | case 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break; 26 | case 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break; 27 | default: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift); 28 | } 29 | 30 | // Mini Sector Shift 31 | blob.chk('0600', 'Mini Sector Shift: '); 32 | 33 | // Reserved 34 | blob.chk('000000000000', 'Reserved: '); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /bits/42_sectorify.js: -------------------------------------------------------------------------------- 1 | /** Break the file up into sectors */ 2 | function sectorify(file/*:RawBytes*/, ssz/*:number*/)/*:Array*/ { 3 | var nsectors = Math.ceil(file.length/ssz)-1; 4 | var sectors/*:Array*/ = []; 5 | for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz); 6 | sectors[nsectors-1] = file.slice(nsectors*ssz); 7 | return sectors; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /bits/43_rbtree.js: -------------------------------------------------------------------------------- 1 | /* [MS-CFB] 2.6.4 Red-Black Tree */ 2 | function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array*/, Paths/*:Array*/)/*:void*/ { 3 | var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length; 4 | var dad/*:Array*/ = [], q/*:Array*/ = []; 5 | 6 | for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; } 7 | 8 | for(; j < q.length; ++j) { 9 | i = q[j]; 10 | L = FI[i].L; R = FI[i].R; C = FI[i].C; 11 | if(dad[i] === i) { 12 | if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L]; 13 | if(R !== -1 && dad[R] !== R) dad[i] = dad[R]; 14 | } 15 | if(C !== -1 /*NOSTREAM*/) dad[C] = i; 16 | if(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); } 17 | if(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); } 18 | } 19 | for(i=1; i < pl; ++i) if(dad[i] === i) { 20 | if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; 21 | else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; 22 | } 23 | 24 | for(i=1; i < pl; ++i) { 25 | if(FI[i].type === 0 /* unknown */) continue; 26 | j = i; 27 | if(j != dad[j]) do { 28 | j = dad[j]; 29 | FP[i] = FP[j] + "/" + FP[i]; 30 | } while (j !== 0 && -1 !== dad[j] && j != dad[j]); 31 | dad[i] = -1; 32 | } 33 | 34 | FP[0] += "/"; 35 | for(i=1; i < pl; ++i) { 36 | if(FI[i].type !== 2 /* stream */) FP[i] += "/"; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /bits/44_readmfat.js: -------------------------------------------------------------------------------- 1 | function get_mfat_entry(entry/*:CFBEntry*/, payload/*:RawBytes*/, mini/*:?RawBytes*/)/*:CFBlob*/ { 2 | var start = entry.start, size = entry.size; 3 | //return (payload.slice(start*MSSZ, start*MSSZ + size)/*:any*/); 4 | var o = []; 5 | var idx = start; 6 | while(mini && size > 0 && idx >= 0) { 7 | o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ)); 8 | size -= MSSZ; 9 | idx = __readInt32LE(mini, idx * 4); 10 | } 11 | if(o.length === 0) return (new_buf(0)/*:any*/); 12 | return (bconcat(o).slice(0, entry.size)/*:any*/); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /bits/45_readfat.js: -------------------------------------------------------------------------------- 1 | /** Chase down the rest of the DIFAT chain to build a comprehensive list 2 | DIFAT chains by storing the next sector number as the last 32 bits */ 3 | function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array*/, ssz/*:number*/, fat_addrs)/*:void*/ { 4 | var q/*:number*/ = ENDOFCHAIN; 5 | if(idx === ENDOFCHAIN) { 6 | if(cnt !== 0) throw new Error("DIFAT chain shorter than expected"); 7 | } else if(idx !== -1 /*FREESECT*/) { 8 | var sector = sectors[idx], m = (ssz>>>2)-1; 9 | if(!sector) return; 10 | for(var i = 0; i < m; ++i) { 11 | if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break; 12 | fat_addrs.push(q); 13 | } 14 | if(cnt >= 1) sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs); 15 | } 16 | } 17 | 18 | /** Follow the linked list of sectors for a given starting point */ 19 | function get_sector_list(sectors/*:Array*/, start/*:number*/, fat_addrs/*:Array*/, ssz/*:number*/, chkd/*:?Array*/)/*:SectorEntry*/ { 20 | var buf/*:Array*/ = [], buf_chain/*:Array*/ = []; 21 | if(!chkd) chkd = []; 22 | var modulus = ssz - 1, j = 0, jj = 0; 23 | for(j=start; j>=0;) { 24 | chkd[j] = true; 25 | buf[buf.length] = j; 26 | buf_chain.push(sectors[j]); 27 | var addr = fat_addrs[Math.floor(j*4/ssz)]; 28 | jj = ((j*4) & modulus); 29 | if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz); 30 | if(!sectors[addr]) break; 31 | j = __readInt32LE(sectors[addr], jj); 32 | } 33 | return {nodes: buf, data:__toBuffer([buf_chain])}; 34 | } 35 | 36 | /** Chase down the sector linked lists */ 37 | function make_sector_list(sectors/*:Array*/, dir_start/*:number*/, fat_addrs/*:Array*/, ssz/*:number*/)/*:SectorList*/ { 38 | var sl = sectors.length, sector_list/*:SectorList*/ = ([]/*:any*/); 39 | var chkd/*:Array*/ = [], buf/*:Array*/ = [], buf_chain/*:Array*/ = []; 40 | var modulus = ssz - 1, i=0, j=0, k=0, jj=0; 41 | for(i=0; i < sl; ++i) { 42 | buf = ([]/*:Array*/); 43 | k = (i + dir_start); if(k >= sl) k-=sl; 44 | if(chkd[k]) continue; 45 | buf_chain = []; 46 | var seen = []; 47 | for(j=k; j>=0;) { 48 | seen[j] = true; 49 | chkd[j] = true; 50 | buf[buf.length] = j; 51 | buf_chain.push(sectors[j]); 52 | var addr/*:number*/ = fat_addrs[Math.floor(j*4/ssz)]; 53 | jj = ((j*4) & modulus); 54 | if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz); 55 | if(!sectors[addr]) break; 56 | j = __readInt32LE(sectors[addr], jj); 57 | if(seen[j]) break; 58 | } 59 | sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])}/*:SectorEntry*/); 60 | } 61 | return sector_list; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /bits/46_readdir.js: -------------------------------------------------------------------------------- 1 | /* [MS-CFB] 2.6.1 Compound File Directory Entry */ 2 | function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sectors/*:Array*/, Paths/*:Array*/, nmfs, files, FileIndex, mini) { 3 | var minifat_store = 0, pl = (Paths.length?2:0); 4 | var sector = sector_list[dir_start].data; 5 | var i = 0, namelen = 0, name; 6 | for(; i < sector.length; i+= 128) { 7 | var blob/*:CFBlob*/ = /*::(*/sector.slice(i, i+128)/*:: :any)*/; 8 | prep_blob(blob, 64); 9 | namelen = blob.read_shift(2); 10 | name = __utf16le(blob,0,namelen-pl); 11 | Paths.push(name); 12 | var o/*:CFBEntry*/ = ({ 13 | name: name, 14 | type: blob.read_shift(1), 15 | color: blob.read_shift(1), 16 | L: blob.read_shift(4, 'i'), 17 | R: blob.read_shift(4, 'i'), 18 | C: blob.read_shift(4, 'i'), 19 | clsid: blob.read_shift(16), 20 | state: blob.read_shift(4, 'i'), 21 | start: 0, 22 | size: 0 23 | }); 24 | var ctime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); 25 | if(ctime !== 0) o.ct = read_date(blob, blob.l-8); 26 | var mtime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); 27 | if(mtime !== 0) o.mt = read_date(blob, blob.l-8); 28 | o.start = blob.read_shift(4, 'i'); 29 | o.size = blob.read_shift(4, 'i'); 30 | if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; } 31 | if(o.type === 5) { /* root */ 32 | minifat_store = o.start; 33 | if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData"; 34 | /*minifat_size = o.size;*/ 35 | } else if(o.size >= 4096 /* MSCSZ */) { 36 | o.storage = 'fat'; 37 | if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); 38 | sector_list[o.start].name = o.name; 39 | o.content = (sector_list[o.start].data.slice(0,o.size)/*:any*/); 40 | } else { 41 | o.storage = 'minifat'; 42 | if(o.size < 0) o.size = 0; 43 | else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) { 44 | o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data); 45 | } 46 | } 47 | if(o.content) prep_blob(o.content, 0); 48 | files[name] = o; 49 | FileIndex.push(o); 50 | } 51 | } 52 | 53 | function read_date(blob/*:RawBytes|CFBlob*/, offset/*:number*/)/*:Date*/ { 54 | return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /bits/49_readutils.js: -------------------------------------------------------------------------------- 1 | function read_file(filename/*:string*/, options/*:CFBReadOpts*/) { 2 | get_fs(); 3 | return parse(fs.readFileSync(filename), options); 4 | } 5 | 6 | function read(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) { 7 | var type = options && options.type; 8 | if(!type) { 9 | if(has_buf && Buffer.isBuffer(blob)) type = "buffer"; 10 | } 11 | switch(type || "base64") { 12 | case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return read_file(blob, options); 13 | case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64_decode(blob)), options); 14 | case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options); 15 | } 16 | return parse(/*::typeof blob == 'string' ? new Buffer(blob, 'utf-8') : */blob, options); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /bits/50_init.js: -------------------------------------------------------------------------------- 1 | function init_cfb(cfb/*:CFBContainer*/, opts/*:?any*/)/*:void*/ { 2 | var o = opts || {}, root = o.root || "Root Entry"; 3 | if(!cfb.FullPaths) cfb.FullPaths = []; 4 | if(!cfb.FileIndex) cfb.FileIndex = []; 5 | if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure"); 6 | if(cfb.FullPaths.length === 0) { 7 | cfb.FullPaths[0] = root + "/"; 8 | cfb.FileIndex[0] = ({ name: root, type: 5 }/*:any*/); 9 | } 10 | if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID; 11 | seed_cfb(cfb); 12 | } 13 | -------------------------------------------------------------------------------- /bits/51_seed.js: -------------------------------------------------------------------------------- 1 | function seed_cfb(cfb/*:CFBContainer*/)/*:void*/ { 2 | var nm = "\u0001Sh33tJ5"; 3 | if(CFB.find(cfb, "/" + nm)) return; 4 | var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54; 5 | cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }/*:any*/)); 6 | cfb.FullPaths.push(cfb.FullPaths[0] + nm); 7 | rebuild_cfb(cfb); 8 | } 9 | -------------------------------------------------------------------------------- /bits/54_rebuild.js: -------------------------------------------------------------------------------- 1 | function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ { 2 | init_cfb(cfb); 3 | -------------------------------------------------------------------------------- /bits/55_check.js: -------------------------------------------------------------------------------- 1 | var gc = false, s = false; 2 | for(var i = cfb.FullPaths.length - 1; i >= 0; --i) { 3 | var _file = cfb.FileIndex[i]; 4 | switch(_file.type) { 5 | case 0: 6 | if(s) gc = true; 7 | else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); } 8 | break; 9 | case 1: case 2: case 5: 10 | s = true; 11 | if(isNaN(_file.R * _file.L * _file.C)) gc = true; 12 | if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true; 13 | break; 14 | default: gc = true; break; 15 | } 16 | } 17 | if(!gc && !f) return; 18 | 19 | -------------------------------------------------------------------------------- /bits/56_dirtree.js: -------------------------------------------------------------------------------- 1 | var now = new Date(1987, 1, 19), j = 0; 2 | // Track which names exist 3 | var fullPaths = Object.create ? Object.create(null) : {}; 4 | var data/*:Array<[string, CFBEntry]>*/ = []; 5 | for(i = 0; i < cfb.FullPaths.length; ++i) { 6 | fullPaths[cfb.FullPaths[i]] = true; 7 | if(cfb.FileIndex[i].type === 0) continue; 8 | data.push([cfb.FullPaths[i], cfb.FileIndex[i]]); 9 | } 10 | for(i = 0; i < data.length; ++i) { 11 | var dad = dirname(data[i][0]); 12 | s = fullPaths[dad]; 13 | while(!s) { 14 | while(dirname(dad) && !fullPaths[dirname(dad)]) dad = dirname(dad); 15 | 16 | data.push([dad, ({ 17 | name: filename(dad).replace("/",""), 18 | type: 1, 19 | clsid: HEADER_CLSID, 20 | ct: now, mt: now, 21 | content: null 22 | }/*:any*/)]); 23 | 24 | // Add name to set 25 | fullPaths[dad] = true; 26 | 27 | dad = dirname(data[i][0]); 28 | s = fullPaths[dad]; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /bits/57_resort.js: -------------------------------------------------------------------------------- 1 | data.sort(function(x,y) { return namecmp(x[0], y[0]); }); 2 | cfb.FullPaths = []; cfb.FileIndex = []; 3 | for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; } 4 | -------------------------------------------------------------------------------- /bits/58_btree.js: -------------------------------------------------------------------------------- 1 | for(i = 0; i < data.length; ++i) { 2 | var elt = cfb.FileIndex[i]; 3 | var nm = cfb.FullPaths[i]; 4 | 5 | elt.name = filename(nm).replace("/",""); 6 | elt.L = elt.R = elt.C = -(elt.color = 1); 7 | elt.size = elt.content ? elt.content.length : 0; 8 | elt.start = 0; 9 | elt.clsid = (elt.clsid || HEADER_CLSID); 10 | if(i === 0) { 11 | elt.C = data.length > 1 ? 1 : -1; 12 | elt.size = 0; 13 | elt.type = 5; 14 | } else if(nm.slice(-1) == "/") { 15 | for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break; 16 | elt.C = j >= data.length ? -1 : j; 17 | for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break; 18 | elt.R = j >= data.length ? -1 : j; 19 | elt.type = 1; 20 | } else { 21 | if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1; 22 | elt.type = 2; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /bits/59_rebuild.js: -------------------------------------------------------------------------------- 1 | } 2 | 3 | -------------------------------------------------------------------------------- /bits/60_writehead.js: -------------------------------------------------------------------------------- 1 | function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ { 2 | var _opts = options || {}; 3 | /* MAD is order-sensitive, skip rebuild and sort */ 4 | if(_opts.fileType == 'mad') return write_mad(cfb, _opts); 5 | rebuild_cfb(cfb); 6 | switch(_opts.fileType) { 7 | case 'zip': return write_zip(cfb, _opts); 8 | //case 'mad': return write_mad(cfb, _opts); 9 | } 10 | -------------------------------------------------------------------------------- /bits/61_layout.js: -------------------------------------------------------------------------------- 1 | var L = (function(cfb/*:CFBContainer*/)/*:Array*/{ 2 | var mini_size = 0, fat_size = 0; 3 | for(var i = 0; i < cfb.FileIndex.length; ++i) { 4 | var file = cfb.FileIndex[i]; 5 | if(!file.content) continue; 6 | var flen = file.content.length; 7 | if(flen > 0){ 8 | if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6; 9 | else fat_size += (flen + 0x01FF) >> 9; 10 | } 11 | } 12 | var dir_cnt = (cfb.FullPaths.length +3) >> 2; 13 | var mini_cnt = (mini_size + 7) >> 3; 14 | var mfat_cnt = (mini_size + 0x7F) >> 7; 15 | var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt; 16 | var fat_cnt = (fat_base + 0x7F) >> 7; 17 | var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F); 18 | while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F); 19 | var L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0]; 20 | cfb.FileIndex[0].size = mini_size << 6; 21 | L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3); 22 | return L; 23 | })(cfb); 24 | -------------------------------------------------------------------------------- /bits/62_alloc.js: -------------------------------------------------------------------------------- 1 | var o = new_buf(L[7] << 9); 2 | var i = 0, T = 0; 3 | -------------------------------------------------------------------------------- /bits/63_header.js: -------------------------------------------------------------------------------- 1 | { 2 | for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]); 3 | for(i = 0; i < 8; ++i) o.write_shift(2, 0); 4 | o.write_shift(2, 0x003E); 5 | o.write_shift(2, 0x0003); 6 | o.write_shift(2, 0xFFFE); 7 | o.write_shift(2, 0x0009); 8 | o.write_shift(2, 0x0006); 9 | for(i = 0; i < 3; ++i) o.write_shift(2, 0); 10 | o.write_shift(4, 0); 11 | o.write_shift(4, L[2]); 12 | o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1); 13 | o.write_shift(4, 0); 14 | o.write_shift(4, 1<<12); 15 | o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN); 16 | o.write_shift(4, L[3]); 17 | o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN); 18 | o.write_shift(4, L[1]); 19 | for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1); 20 | } 21 | -------------------------------------------------------------------------------- /bits/64_difat.js: -------------------------------------------------------------------------------- 1 | if(L[1]) { 2 | for(T = 0; T < L[1]; ++T) { 3 | for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1); 4 | o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /bits/65_fat.js: -------------------------------------------------------------------------------- 1 | var chainit = function(w/*:number*/)/*:void*/ { 2 | for(T += w; i> 9); 20 | } 21 | chainit((L[6] + 7) >> 3); 22 | while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN); 23 | T = i = 0; 24 | for(j = 0; j < cfb.FileIndex.length; ++j) { 25 | file = cfb.FileIndex[j]; 26 | if(!file.content) continue; 27 | /*:: if(file.content == null) throw new Error("unreachable"); */ 28 | flen = file.content.length; 29 | if(!flen || flen >= 0x1000) continue; 30 | file.start = T; 31 | chainit((flen + 0x3F) >> 6); 32 | } 33 | while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN); 34 | -------------------------------------------------------------------------------- /bits/66_dir.js: -------------------------------------------------------------------------------- 1 | for(i = 0; i < L[4]<<2; ++i) { 2 | var nm = cfb.FullPaths[i]; 3 | if(!nm || nm.length === 0) { 4 | for(j = 0; j < 17; ++j) o.write_shift(4, 0); 5 | for(j = 0; j < 3; ++j) o.write_shift(4, -1); 6 | for(j = 0; j < 12; ++j) o.write_shift(4, 0); 7 | continue; 8 | } 9 | file = cfb.FileIndex[i]; 10 | if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN; 11 | var _nm/*:string*/ = (i === 0 && _opts.root) || file.name; 12 | if(_nm.length > 31) { 13 | console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,31)); 14 | _nm = _nm.slice(0, 31); 15 | } 16 | flen = 2*(_nm.length+1); 17 | o.write_shift(64, _nm, "utf16le"); 18 | o.write_shift(2, flen); 19 | o.write_shift(1, file.type); 20 | o.write_shift(1, file.color); 21 | o.write_shift(-4, file.L); 22 | o.write_shift(-4, file.R); 23 | o.write_shift(-4, file.C); 24 | if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0); 25 | else o.write_shift(16, file.clsid, "hex"); 26 | o.write_shift(4, file.state || 0); 27 | o.write_shift(4, 0); o.write_shift(4, 0); 28 | o.write_shift(4, 0); o.write_shift(4, 0); 29 | o.write_shift(4, file.start); 30 | o.write_shift(4, file.size); o.write_shift(4, 0); 31 | } 32 | -------------------------------------------------------------------------------- /bits/67_stream.js: -------------------------------------------------------------------------------- 1 | for(i = 1; i < cfb.FileIndex.length; ++i) { 2 | file = cfb.FileIndex[i]; 3 | /*:: if(!file.content) throw new Error("unreachable"); */ 4 | if(file.size >= 0x1000) { 5 | o.l = (file.start+1) << 9; 6 | if (has_buf && Buffer.isBuffer(file.content)) { 7 | file.content.copy(o, o.l, 0, file.size); 8 | // o is a 0-filled Buffer so just set next offset 9 | o.l += (file.size + 511) & -512; 10 | } else { 11 | for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); 12 | for(; j & 0x1FF; ++j) o.write_shift(1, 0); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bits/68_mini.js: -------------------------------------------------------------------------------- 1 | for(i = 1; i < cfb.FileIndex.length; ++i) { 2 | file = cfb.FileIndex[i]; 3 | /*:: if(!file.content) throw new Error("unreachable"); */ 4 | if(file.size > 0 && file.size < 0x1000) { 5 | if (has_buf && Buffer.isBuffer(file.content)) { 6 | file.content.copy(o, o.l, 0, file.size); 7 | // o is a 0-filled Buffer so just set next offset 8 | o.l += (file.size + 63) & -64; 9 | } else { 10 | for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); 11 | for(; j & 0x3F; ++j) o.write_shift(1, 0); 12 | } 13 | } 14 | } 15 | if (has_buf) { 16 | o.l = o.length; 17 | } else { 18 | // When using Buffer, already 0-filled 19 | while(o.l < o.length) o.write_shift(1, 0); 20 | } 21 | -------------------------------------------------------------------------------- /bits/69_writefoot.js: -------------------------------------------------------------------------------- 1 | return o; 2 | } 3 | -------------------------------------------------------------------------------- /bits/70_find.js: -------------------------------------------------------------------------------- 1 | /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ 2 | function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { 3 | var UCFullPaths/*:Array*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); }); 4 | var UCPaths/*:Array*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; }); 5 | var k/*:boolean*/ = false; 6 | if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; } 7 | else k = path.indexOf("/") !== -1; 8 | var UCPath/*:string*/ = path.toUpperCase(); 9 | var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); 10 | if(w !== -1) return cfb.FileIndex[w]; 11 | 12 | var m = !UCPath.match(chr1); 13 | UCPath = UCPath.replace(chr0,''); 14 | if(m) UCPath = UCPath.replace(chr1,'!'); 15 | for(w = 0; w < UCFullPaths.length; ++w) { 16 | if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; 17 | if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; 18 | } 19 | return null; 20 | } 21 | -------------------------------------------------------------------------------- /bits/75_consts.js: -------------------------------------------------------------------------------- 1 | /** CFB Constants */ 2 | var MSSZ = 64; /* Mini Sector Size = 1<<6 */ 3 | //var MSCSZ = 4096; /* Mini Stream Cutoff Size */ 4 | /* 2.1 Compound File Sector Numbers and Types */ 5 | var ENDOFCHAIN = -2; 6 | /* 2.2 Compound File Header */ 7 | var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1'; 8 | var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1]; 9 | var HEADER_CLSID = '00000000000000000000000000000000'; 10 | var consts = { 11 | /* 2.1 Compund File Sector Numbers and Types */ 12 | MAXREGSECT: -6, 13 | DIFSECT: -4, 14 | FATSECT: -3, 15 | ENDOFCHAIN: ENDOFCHAIN, 16 | FREESECT: -1, 17 | /* 2.2 Compound File Header */ 18 | HEADER_SIGNATURE: HEADER_SIGNATURE, 19 | HEADER_MINOR_VERSION: '3e00', 20 | MAXREGSID: -6, 21 | NOSTREAM: -1, 22 | HEADER_CLSID: HEADER_CLSID, 23 | /* 2.6.1 Compound File Directory Entry */ 24 | EntryTypes: ['unknown','storage','stream','lockbytes','property','root'] 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /bits/77_writeutils.js: -------------------------------------------------------------------------------- 1 | function write_file(cfb/*:CFBContainer*/, filename/*:string*/, options/*:CFBWriteOpts*/)/*:void*/ { 2 | get_fs(); 3 | var o = _write(cfb, options); 4 | /*:: if(typeof Buffer == 'undefined' || !Buffer.isBuffer(o) || !(o instanceof Buffer)) throw new Error("unreachable"); */ 5 | fs.writeFileSync(filename, o); 6 | } 7 | 8 | function a2s(o/*:RawBytes*/)/*:string*/ { 9 | var out = new Array(o.length); 10 | for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]); 11 | return out.join(""); 12 | } 13 | 14 | function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ { 15 | var o = _write(cfb, options); 16 | switch(options && options.type || "buffer") { 17 | case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o; 18 | case "binary": return typeof o == "string" ? o : a2s(o); 19 | case "base64": return Base64_encode(typeof o == "string" ? o : a2s(o)); 20 | case "buffer": if(has_buf) return Buffer.isBuffer(o) ? o : Buffer_from(o); 21 | /* falls through */ 22 | case "array": return typeof o == "string" ? s2a(o) : o; 23 | } 24 | return o; 25 | } 26 | -------------------------------------------------------------------------------- /bits/78_zlib.js: -------------------------------------------------------------------------------- 1 | /* node < 8.1 zlib does not expose bytesRead, so default to pure JS */ 2 | var _zlib; 3 | function use_zlib(zlib) { try { 4 | var InflateRaw = zlib.InflateRaw; 5 | var InflRaw = new InflateRaw(); 6 | InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag); 7 | if(InflRaw.bytesRead) _zlib = zlib; 8 | else throw new Error("zlib does not expose bytesRead"); 9 | } catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } } 10 | 11 | function _inflateRawSync(payload, usz) { 12 | if(!_zlib) return _inflate(payload, usz); 13 | var InflateRaw = _zlib.InflateRaw; 14 | var InflRaw = new InflateRaw(); 15 | var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag); 16 | payload.l += InflRaw.bytesRead; 17 | return out; 18 | } 19 | 20 | function _deflateRawSync(payload) { 21 | return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload); 22 | } 23 | -------------------------------------------------------------------------------- /bits/79_flate.js: -------------------------------------------------------------------------------- 1 | var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]; 2 | 3 | /* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */ 4 | var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ]; 5 | 6 | /* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */ 7 | var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ]; 8 | 9 | function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; } 10 | 11 | var use_typed_arrays = typeof Uint8Array !== 'undefined'; 12 | 13 | var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : []; 14 | for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q); 15 | 16 | function bit_swap_n(n, b) { 17 | var rev = bitswap8[n & 0xFF]; 18 | if(b <= 8) return rev >>> (8-b); 19 | rev = (rev << 8) | bitswap8[(n>>8)&0xFF]; 20 | if(b <= 16) return rev >>> (16-b); 21 | rev = (rev << 8) | bitswap8[(n>>16)&0xFF]; 22 | return rev >>> (24-b); 23 | } 24 | 25 | /* helpers for unaligned bit reads */ 26 | function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; } 27 | function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; } 28 | function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; } 29 | function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; } 30 | function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; } 31 | 32 | /* works up to n = 3 * 8 + 1 = 25 */ 33 | function read_bits_n(buf, bl, n) { 34 | var w = (bl&7), h = (bl>>>3), f = ((1<>> w; 36 | if(n < 8 - w) return v & f; 37 | v |= buf[h+1]<<(8-w); 38 | if(n < 16 - w) return v & f; 39 | v |= buf[h+2]<<(16-w); 40 | if(n < 24 - w) return v & f; 41 | v |= buf[h+3]<<(24-w); 42 | return v & f; 43 | } 44 | 45 | /* helpers for unaligned bit writes */ 46 | function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3; 47 | if(w <= 5) buf[h] |= (v & 7) << w; 48 | else { 49 | buf[h] |= (v << w) & 0xFF; 50 | buf[h+1] = (v&7) >> (8-w); 51 | } 52 | return bl + 3; 53 | } 54 | 55 | function write_bits_1(buf, bl, v) { 56 | var w = bl & 7, h = bl >>> 3; 57 | v = (v&1) << w; 58 | buf[h] |= v; 59 | return bl + 1; 60 | } 61 | function write_bits_8(buf, bl, v) { 62 | var w = bl & 7, h = bl >>> 3; 63 | v <<= w; 64 | buf[h] |= v & 0xFF; v >>>= 8; 65 | buf[h+1] = v; 66 | return bl + 8; 67 | } 68 | function write_bits_16(buf, bl, v) { 69 | var w = bl & 7, h = bl >>> 3; 70 | v <<= w; 71 | buf[h] |= v & 0xFF; v >>>= 8; 72 | buf[h+1] = v & 0xFF; 73 | buf[h+2] = v >>> 8; 74 | return bl + 16; 75 | } 76 | 77 | /* until ArrayBuffer#realloc is a thing, fake a realloc */ 78 | function realloc(b, sz/*:number*/) { 79 | var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0; 80 | if(L >= sz) return b; 81 | if(has_buf) { 82 | var o = new_unsafe_buf(M); 83 | // $FlowIgnore 84 | if(b.copy) b.copy(o); 85 | else for(; i < b.length; ++i) o[i] = b[i]; 86 | return o; 87 | } else if(use_typed_arrays) { 88 | var a = new Uint8Array(M); 89 | if(a.set) a.set(b); 90 | else for(; i < L; ++i) a[i] = b[i]; 91 | return a; 92 | } 93 | b.length = M; 94 | return b; 95 | } 96 | 97 | /* zero-filled arrays for older browsers */ 98 | function zero_fill_array(n) { 99 | var o = new Array(n); 100 | for(var i = 0; i < n; ++i) o[i] = 0; 101 | return o; 102 | } 103 | 104 | /* build tree (used for literals and lengths) */ 105 | function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ { 106 | var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length; 107 | 108 | var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32); 109 | for(i = 0; i < 32; ++i) bl_count[i] = 0; 110 | 111 | for(i = L; i < MAX; ++i) clens[i] = 0; 112 | L = clens.length; 113 | 114 | var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // [] 115 | 116 | /* build code tree */ 117 | for(i = 0; i < L; ++i) { 118 | bl_count[(w = clens[i])]++; 119 | if(maxlen < w) maxlen = w; 120 | ctree[i] = 0; 121 | } 122 | bl_count[0] = 0; 123 | for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1); 124 | for(i = 0; i < L; ++i) { 125 | ccode = clens[i]; 126 | if(ccode != 0) ctree[i] = bl_count[ccode+16]++; 127 | } 128 | 129 | /* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */ 130 | var cleni = 0; 131 | for(i = 0; i < L; ++i) { 132 | cleni = clens[i]; 133 | if(cleni != 0) { 134 | ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni); 135 | for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j) 136 | cmap[ccode|(j<*/ = []; 151 | var i = 0; 152 | for(;i<32; i++) dlens.push(5); 153 | build_tree(dlens, fix_dmap, 32); 154 | 155 | var clens/*:Array*/ = []; 156 | i = 0; 157 | for(; i<=143; i++) clens.push(8); 158 | for(; i<=255; i++) clens.push(9); 159 | for(; i<=279; i++) clens.push(7); 160 | for(; i<=287; i++) clens.push(8); 161 | build_tree(clens, fix_lmap, 288); 162 | })(); -------------------------------------------------------------------------------- /bits/80_deflate.js: -------------------------------------------------------------------------------- 1 | var _deflateRaw = /*#__PURE__*/(function _deflateRawIIFE() { 2 | var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; 3 | var j = 0, k = 0; 4 | for(; j < DST_LN.length - 1; ++j) { 5 | for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; 6 | } 7 | for(;k < 32768; ++k) DST_LN_RE[k] = 29; 8 | 9 | var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : []; 10 | for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) { 11 | for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; 12 | } 13 | 14 | function write_stored(data, out) { 15 | var boff = 0; 16 | while(boff < data.length) { 17 | var L = Math.min(0xFFFF, data.length - boff); 18 | var h = boff + L == data.length; 19 | out.write_shift(1, +h); 20 | out.write_shift(2, L); 21 | out.write_shift(2, (~L) & 0xFFFF); 22 | while(L-- > 0) out[out.l++] = data[boff++]; 23 | } 24 | return out.l; 25 | } 26 | 27 | /* Fixed Huffman */ 28 | function write_huff_fixed(data, out) { 29 | var bl = 0; 30 | var boff = 0; 31 | var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; 32 | while(boff < data.length) { 33 | var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); 34 | 35 | /* write a stored block for short data */ 36 | if(L < 10) { 37 | bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line 38 | if(bl & 7) bl += 8 - (bl & 7); 39 | out.l = (bl / 8) | 0; 40 | out.write_shift(2, L); 41 | out.write_shift(2, (~L) & 0xFFFF); 42 | while(L-- > 0) out[out.l++] = data[boff++]; 43 | bl = out.l * 8; 44 | continue; 45 | } 46 | 47 | bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line 48 | var hash = 0; 49 | while(L-- > 0) { 50 | var d = data[boff]; 51 | hash = ((hash << 5) ^ d) & 0x7FFF; 52 | 53 | var match = -1, mlen = 0; 54 | 55 | if((match = addrs[hash])) { 56 | match |= boff & ~0x7FFF; 57 | if(match > boff) match -= 0x8000; 58 | if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; 59 | } 60 | 61 | if(mlen > 2) { 62 | /* Copy Token */ 63 | d = LEN_LN_RE[mlen]; 64 | if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; 65 | else { 66 | write_bits_8(out, bl, 3); 67 | bl += 5; 68 | write_bits_8(out, bl, bitswap8[d-23]>>5); 69 | bl += 3; 70 | } 71 | var len_eb = (d < 8) ? 0 : ((d - 4)>>2); 72 | if(len_eb > 0) { 73 | write_bits_16(out, bl, mlen - LEN_LN[d]); 74 | bl += len_eb; 75 | } 76 | 77 | d = DST_LN_RE[boff - match]; 78 | bl = write_bits_8(out, bl, bitswap8[d]>>3); 79 | bl -= 3; 80 | 81 | var dst_eb = d < 4 ? 0 : (d-2)>>1; 82 | if(dst_eb > 0) { 83 | write_bits_16(out, bl, boff - match - DST_LN[d]); 84 | bl += dst_eb; 85 | } 86 | for(var q = 0; q < mlen; ++q) { 87 | addrs[hash] = boff & 0x7FFF; 88 | hash = ((hash << 5) ^ data[boff]) & 0x7FFF; 89 | ++boff; 90 | } 91 | L-= mlen - 1; 92 | } else { 93 | /* Literal Token */ 94 | if(d <= 143) d = d + 48; 95 | else bl = write_bits_1(out, bl, 1); 96 | bl = write_bits_8(out, bl, bitswap8[d]); 97 | addrs[hash] = boff & 0x7FFF; 98 | ++boff; 99 | } 100 | } 101 | 102 | bl = write_bits_8(out, bl, 0) - 1; 103 | } 104 | out.l = ((bl + 7)/8)|0; 105 | return out.l; 106 | } 107 | return function _deflateRaw(data, out) { 108 | if(data.length < 8) return write_stored(data, out); 109 | return write_huff_fixed(data, out); 110 | }; 111 | })(); 112 | 113 | function _deflate(data) { 114 | var buf = new_buf(50+Math.floor(data.length*1.1)); 115 | var off = _deflateRaw(data, buf); 116 | return buf.slice(0, off); 117 | } 118 | -------------------------------------------------------------------------------- /bits/81_inflate.js: -------------------------------------------------------------------------------- 1 | /* modified inflate function also moves original read head */ 2 | 3 | var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768); 4 | var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768); 5 | var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128); 6 | var dyn_len_1 = 1, dyn_len_2 = 1; 7 | 8 | /* 5.5.3 Expanding Huffman Codes */ 9 | function dyn(data, boff/*:number*/) { 10 | /* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */ 11 | var _HLIT = read_bits_5(data, boff) + 257; boff += 5; 12 | var _HDIST = read_bits_5(data, boff) + 1; boff += 5; 13 | var _HCLEN = read_bits_4(data, boff) + 4; boff += 4; 14 | var w = 0; 15 | 16 | /* grab and store code lengths */ 17 | var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19); 18 | var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; 19 | var maxlen = 1; 20 | var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8); 21 | var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8); 22 | var L = clens.length; /* 19 */ 23 | for(var i = 0; i < _HCLEN; ++i) { 24 | clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff); 25 | if(maxlen < w) maxlen = w; 26 | bl_count[w]++; 27 | boff += 3; 28 | } 29 | 30 | /* build code tree */ 31 | var ccode = 0; 32 | bl_count[0] = 0; 33 | for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1; 34 | for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++; 35 | /* cmap[7 bits from stream] = (off&7) + (lit<<3) */ 36 | var cleni = 0; 37 | for(i = 0; i < L; ++i) { 38 | cleni = clens[i]; 39 | if(cleni != 0) { 40 | ccode = bitswap8[ctree[i]]>>(8-cleni); 41 | for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<*/ = []; 47 | maxlen = 1; 48 | for(; hcodes.length < _HLIT + _HDIST;) { 49 | ccode = dyn_cmap[read_bits_7(data, boff)]; 50 | boff += ccode & 7; 51 | switch((ccode >>>= 3)) { 52 | case 16: 53 | w = 3 + read_bits_2(data, boff); boff += 2; 54 | ccode = hcodes[hcodes.length - 1]; 55 | while(w-- > 0) hcodes.push(ccode); 56 | break; 57 | case 17: 58 | w = 3 + read_bits_3(data, boff); boff += 3; 59 | while(w-- > 0) hcodes.push(0); 60 | break; 61 | case 18: 62 | w = 11 + read_bits_7(data, boff); boff += 7; 63 | while(w -- > 0) hcodes.push(0); 64 | break; 65 | default: 66 | hcodes.push(ccode); 67 | if(maxlen < ccode) maxlen = ccode; 68 | break; 69 | } 70 | } 71 | 72 | /* build literal / length trees */ 73 | var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT); 74 | for(i = _HLIT; i < 286; ++i) h1[i] = 0; 75 | for(i = _HDIST; i < 30; ++i) h2[i] = 0; 76 | dyn_len_1 = build_tree(h1, dyn_lmap, 286); 77 | dyn_len_2 = build_tree(h2, dyn_dmap, 30); 78 | return boff; 79 | } 80 | 81 | /* return [ data, bytesRead ] */ 82 | function inflate(data, usz/*:number*/) { 83 | /* shortcircuit for empty buffer [0x03, 0x00] */ 84 | if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; } 85 | 86 | /* bit offset */ 87 | var boff = 0; 88 | 89 | /* header includes final bit and type bits */ 90 | var header = 0; 91 | 92 | var outbuf = new_unsafe_buf(usz ? usz : (1<<18)); 93 | var woff = 0; 94 | var OL = outbuf.length>>>0; 95 | var max_len_1 = 0, max_len_2 = 0; 96 | 97 | while((header&1) == 0) { 98 | header = read_bits_3(data, boff); boff += 3; 99 | if((header >>> 1) == 0) { 100 | /* Stored block */ 101 | if(boff & 7) boff += 8 - (boff&7); 102 | /* 2 bytes sz, 2 bytes bit inverse */ 103 | var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8; 104 | boff += 32; 105 | /* push sz bytes */ 106 | if(sz > 0) { 107 | if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; } 108 | while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; } 109 | } 110 | continue; 111 | } else if((header >> 1) == 1) { 112 | /* Fixed Huffman */ 113 | max_len_1 = 9; max_len_2 = 5; 114 | } else { 115 | /* Dynamic Huffman */ 116 | boff = dyn(data, boff); 117 | max_len_1 = dyn_len_1; max_len_2 = dyn_len_2; 118 | } 119 | for(;;) { // while(true) is apparently out of vogue in modern JS circles 120 | if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } 121 | /* ingest code and move read head */ 122 | var bits = read_bits_n(data, boff, max_len_1); 123 | var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits]; 124 | boff += code & 15; code >>>= 4; 125 | /* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */ 126 | if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code; 127 | else if(code == 256) break; 128 | else { 129 | code -= 257; 130 | var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0; 131 | var tgt = woff + LEN_LN[code]; 132 | /* length extra bits */ 133 | if(len_eb > 0) { 134 | tgt += read_bits_n(data, boff, len_eb); 135 | boff += len_eb; 136 | } 137 | 138 | /* dist code */ 139 | bits = read_bits_n(data, boff, max_len_2); 140 | code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits]; 141 | boff += code & 15; code >>>= 4; 142 | var dst_eb = (code < 4 ? 0 : (code-2)>>1); 143 | var dst = DST_LN[code]; 144 | /* dist extra bits */ 145 | if(dst_eb > 0) { 146 | dst += read_bits_n(data, boff, dst_eb); 147 | boff += dst_eb; 148 | } 149 | 150 | /* in the common case, manual byte copy is faster than TA set / Buffer copy */ 151 | if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } 152 | while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } 153 | } 154 | } 155 | } 156 | if(usz) return [outbuf, (boff+7)>>>3]; 157 | return [outbuf.slice(0, woff), (boff+7)>>>3]; 158 | } 159 | 160 | function _inflate(payload, usz) { 161 | var data = payload.slice(payload.l||0); 162 | var out = inflate(data, usz); 163 | payload.l += out[1]; 164 | return out[0]; 165 | } 166 | 167 | -------------------------------------------------------------------------------- /bits/82_zparse.js: -------------------------------------------------------------------------------- 1 | function warn_or_throw(wrn, msg) { 2 | if(wrn) { if(typeof console !== 'undefined') console.error(msg); } 3 | else throw new Error(msg); 4 | } 5 | 6 | function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ { 7 | var blob/*:CFBlob*/ = /*::(*/file/*:: :any)*/; 8 | prep_blob(blob, 0); 9 | 10 | var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array*/ = []; 11 | var o = { 12 | FileIndex: FileIndex, 13 | FullPaths: FullPaths 14 | }; 15 | init_cfb(o, { root: options.root }); 16 | 17 | /* find end of central directory, start just after signature */ 18 | var i = blob.length - 4; 19 | while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i; 20 | blob.l = i + 4; 21 | 22 | /* parse end of central directory */ 23 | blob.l += 4; 24 | var fcnt = blob.read_shift(2); 25 | blob.l += 6; 26 | var start_cd = blob.read_shift(4); 27 | 28 | /* parse central directory */ 29 | blob.l = start_cd; 30 | 31 | for(i = 0; i < fcnt; ++i) { 32 | /* trust local file header instead of CD entry */ 33 | blob.l += 20; 34 | var csz = blob.read_shift(4); 35 | var usz = blob.read_shift(4); 36 | var namelen = blob.read_shift(2); 37 | var efsz = blob.read_shift(2); 38 | var fcsz = blob.read_shift(2); 39 | blob.l += 8; 40 | var offset = blob.read_shift(4); 41 | var EF = parse_extra_field(/*::(*/blob.slice(blob.l+namelen, blob.l+namelen+efsz)/*:: :any)*/); 42 | blob.l += namelen + efsz + fcsz; 43 | 44 | var L = blob.l; 45 | blob.l = offset + 4; 46 | parse_local_file(blob, csz, usz, o, EF); 47 | blob.l = L; 48 | } 49 | 50 | return o; 51 | } 52 | 53 | 54 | /* head starts just after local file header signature */ 55 | function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:CFBContainer*/, EF) { 56 | /* [local file header] */ 57 | blob.l += 2; 58 | var flags = blob.read_shift(2); 59 | var meth = blob.read_shift(2); 60 | var date = parse_dos_date(blob); 61 | 62 | if(flags & 0x2041) throw new Error("Unsupported ZIP encryption"); 63 | var crc32 = blob.read_shift(4); 64 | var _csz = blob.read_shift(4); 65 | var _usz = blob.read_shift(4); 66 | 67 | var namelen = blob.read_shift(2); 68 | var efsz = blob.read_shift(2); 69 | 70 | // TODO: flags & (1<<11) // UTF8 71 | var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]); 72 | if(efsz) { 73 | var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/); 74 | if((ef[0x5455]||{}).mt) date = ef[0x5455].mt; 75 | if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt; 76 | } 77 | blob.l += efsz; 78 | 79 | /* [encryption header] */ 80 | 81 | /* [file data] */ 82 | var data = blob.slice(blob.l, blob.l + _csz); 83 | switch(meth) { 84 | case 8: data = _inflateRawSync(blob, _usz); break; 85 | case 0: break; // TODO: scan for magic number 86 | default: throw new Error("Unsupported ZIP Compression method " + meth); 87 | } 88 | 89 | /* [data descriptor] */ 90 | var wrn = false; 91 | if(flags & 8) { 92 | crc32 = blob.read_shift(4); 93 | if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; } 94 | _csz = blob.read_shift(4); 95 | _usz = blob.read_shift(4); 96 | } 97 | 98 | if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz); 99 | if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz); 100 | var _crc32 = CRC32.buf(data, 0); 101 | if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32); 102 | cfb_add(o, name, data, {unsafe: true, mt: date}); 103 | } 104 | -------------------------------------------------------------------------------- /bits/83_zwrite.js: -------------------------------------------------------------------------------- 1 | function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ { 2 | var _opts = options || {}; 3 | var out = [], cdirs = []; 4 | var o/*:CFBlob*/ = new_buf(1); 5 | var method = (_opts.compression ? 8 : 0), flags = 0; 6 | var desc = false; 7 | if(desc) flags |= 8; 8 | var i = 0, j = 0; 9 | 10 | var start_cd = 0, fcnt = 0; 11 | var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0]; 12 | var crcs = []; 13 | var sz_cd = 0; 14 | 15 | for(i = 1; i < cfb.FullPaths.length; ++i) { 16 | fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i]; 17 | if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue; 18 | var start = start_cd; 19 | 20 | /* TODO: CP437 filename */ 21 | var namebuf = new_buf(fp.length); 22 | for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F); 23 | namebuf = namebuf.slice(0, namebuf.l); 24 | crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0); 25 | 26 | var outbuf = fi.content/*::||[]*/; 27 | if(method == 8) outbuf = _deflateRawSync(outbuf); 28 | 29 | /* local file header */ 30 | o = new_buf(30); 31 | o.write_shift(4, 0x04034b50); 32 | o.write_shift(2, 20); 33 | o.write_shift(2, flags); 34 | o.write_shift(2, method); 35 | /* TODO: last mod file time/date */ 36 | if(fi.mt) write_dos_date(o, fi.mt); 37 | else o.write_shift(4, 0); 38 | o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]); 39 | o.write_shift(4, (flags & 8) ? 0 : outbuf.length); 40 | o.write_shift(4, (flags & 8) ? 0 : /*::(*/fi.content/*::||[])*/.length); 41 | o.write_shift(2, namebuf.length); 42 | o.write_shift(2, 0); 43 | 44 | start_cd += o.length; 45 | out.push(o); 46 | start_cd += namebuf.length; 47 | out.push(namebuf); 48 | 49 | /* TODO: extra fields? */ 50 | 51 | /* TODO: encryption header ? */ 52 | 53 | start_cd += outbuf.length; 54 | out.push(outbuf); 55 | 56 | /* data descriptor */ 57 | if(flags & 8) { 58 | o = new_buf(12); 59 | o.write_shift(-4, crcs[fcnt]); 60 | o.write_shift(4, outbuf.length); 61 | o.write_shift(4, /*::(*/fi.content/*::||[])*/.length); 62 | start_cd += o.l; 63 | out.push(o); 64 | } 65 | 66 | /* central directory */ 67 | o = new_buf(46); 68 | o.write_shift(4, 0x02014b50); 69 | o.write_shift(2, 0); 70 | o.write_shift(2, 20); 71 | o.write_shift(2, flags); 72 | o.write_shift(2, method); 73 | o.write_shift(4, 0); /* TODO: last mod file time/date */ 74 | o.write_shift(-4, crcs[fcnt]); 75 | 76 | o.write_shift(4, outbuf.length); 77 | o.write_shift(4, /*::(*/fi.content/*::||[])*/.length); 78 | o.write_shift(2, namebuf.length); 79 | o.write_shift(2, 0); 80 | o.write_shift(2, 0); 81 | o.write_shift(2, 0); 82 | o.write_shift(2, 0); 83 | o.write_shift(4, 0); 84 | o.write_shift(4, start); 85 | 86 | sz_cd += o.l; 87 | cdirs.push(o); 88 | sz_cd += namebuf.length; 89 | cdirs.push(namebuf); 90 | ++fcnt; 91 | } 92 | 93 | /* end of central directory */ 94 | o = new_buf(22); 95 | o.write_shift(4, 0x06054b50); 96 | o.write_shift(2, 0); 97 | o.write_shift(2, 0); 98 | o.write_shift(2, fcnt); 99 | o.write_shift(2, fcnt); 100 | o.write_shift(4, sz_cd); 101 | o.write_shift(4, start_cd); 102 | o.write_shift(2, 0); 103 | 104 | return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/)); 105 | } 106 | -------------------------------------------------------------------------------- /bits/84_mht.js: -------------------------------------------------------------------------------- 1 | var ContentTypeMap = ({ 2 | "htm": "text/html", 3 | "xml": "text/xml", 4 | 5 | "gif": "image/gif", 6 | "jpg": "image/jpeg", 7 | "png": "image/png", 8 | 9 | "mso": "application/x-mso", 10 | "thmx": "application/vnd.ms-officetheme", 11 | "sh33tj5": "application/octet-stream" 12 | }/*:any*/); 13 | 14 | function get_content_type(fi/*:CFBEntry*/, fp/*:string*/)/*:string*/ { 15 | if(fi.ctype) return fi.ctype; 16 | 17 | var ext = fi.name || "", m = ext.match(/\.([^\.]+)$/); 18 | if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]]; 19 | 20 | if(fp) { 21 | m = (ext = fp).match(/[\.\\]([^\.\\])+$/); 22 | if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]]; 23 | } 24 | 25 | return "application/octet-stream"; 26 | } 27 | 28 | /* 76 character chunks TODO: intertwine encoding */ 29 | function write_base64_76(bstr/*:string*/)/*:string*/ { 30 | var data = Base64_encode(bstr); 31 | var o = []; 32 | for(var i = 0; i < data.length; i+= 76) o.push(data.slice(i, i+76)); 33 | return o.join("\r\n") + "\r\n"; 34 | } 35 | 36 | /* 37 | Rules for QP: 38 | - escape =## applies for all non-display characters and literal "=" 39 | - space or tab at end of line must be encoded 40 | - \r\n newlines can be preserved, but bare \r and \n must be escaped 41 | - lines must not exceed 76 characters, use soft breaks =\r\n 42 | 43 | TODO: Some files from word appear to write line extensions with bare equals: 44 | 45 | ``` 46 | */ = [], split = encoded.split("\r\n"); 62 | for(var si = 0; si < split.length; ++si) { 63 | var str = split[si]; 64 | if(str.length == 0) { o.push(""); continue; } 65 | for(var i = 0; i < str.length;) { 66 | var end = 76; 67 | var tmp = str.slice(i, i + end); 68 | if(tmp.charAt(end - 1) == "=") end --; 69 | else if(tmp.charAt(end - 2) == "=") end -= 2; 70 | else if(tmp.charAt(end - 3) == "=") end -= 3; 71 | tmp = str.slice(i, i + end); 72 | i += end; 73 | if(i < str.length) tmp += "="; 74 | o.push(tmp); 75 | } 76 | } 77 | 78 | return o.join("\r\n"); 79 | } 80 | function parse_quoted_printable(data/*:Array*/)/*:RawBytes*/ { 81 | var o = []; 82 | 83 | /* unify long lines */ 84 | for(var di = 0; di < data.length; ++di) { 85 | var line = data[di]; 86 | while(di <= data.length && line.charAt(line.length - 1) == "=") line = line.slice(0, line.length - 1) + data[++di]; 87 | o.push(line); 88 | } 89 | 90 | /* decode */ 91 | 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)); }); 92 | return s2a(o.join("\r\n")); 93 | } 94 | 95 | 96 | function parse_mime(cfb/*:CFBContainer*/, data/*:Array*/, root/*:string*/)/*:void*/ { 97 | var fname = "", cte = "", ctype = "", fdata; 98 | var di = 0; 99 | for(;di < 10; ++di) { 100 | var line = data[di]; 101 | if(!line || line.match(/^\s*$/)) break; 102 | var m = line.match(/^(.*?):\s*([^\s].*)$/); 103 | if(m) switch(m[1].toLowerCase()) { 104 | case "content-location": fname = m[2].trim(); break; 105 | case "content-type": ctype = m[2].trim(); break; 106 | case "content-transfer-encoding": cte = m[2].trim(); break; 107 | } 108 | } 109 | ++di; 110 | switch(cte.toLowerCase()) { 111 | case 'base64': fdata = s2a(Base64_decode(data.slice(di).join(""))); break; 112 | case 'quoted-printable': fdata = parse_quoted_printable(data.slice(di)); break; 113 | default: throw new Error("Unsupported Content-Transfer-Encoding " + cte); 114 | } 115 | var file = cfb_add(cfb, fname.slice(root.length), fdata, {unsafe: true}); 116 | if(ctype) file.ctype = ctype; 117 | } 118 | 119 | function parse_mad(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ { 120 | if(a2s(file.slice(0,13)).toLowerCase() != "mime-version:") throw new Error("Unsupported MAD header"); 121 | var root = (options && options.root || ""); 122 | // $FlowIgnore 123 | var data = (has_buf && Buffer.isBuffer(file) ? file.toString("binary") : a2s(file)).split("\r\n"); 124 | var di = 0, row = ""; 125 | 126 | /* if root is not specified, scan for the common prefix */ 127 | for(di = 0; di < data.length; ++di) { 128 | row = data[di]; 129 | if(!/^Content-Location:/i.test(row)) continue; 130 | row = row.slice(row.indexOf("file")); 131 | if(!root) root = row.slice(0, row.lastIndexOf("/") + 1); 132 | if(row.slice(0, root.length) == root) continue; 133 | while(root.length > 0) { 134 | root = root.slice(0, root.length - 1); 135 | root = root.slice(0, root.lastIndexOf("/") + 1); 136 | if(row.slice(0,root.length) == root) break; 137 | } 138 | } 139 | 140 | var mboundary = (data[1] || "").match(/boundary="(.*?)"/); 141 | if(!mboundary) throw new Error("MAD cannot find boundary"); 142 | var boundary = "--" + (mboundary[1] || ""); 143 | 144 | var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array*/ = []; 145 | var o = { 146 | FileIndex: FileIndex, 147 | FullPaths: FullPaths 148 | }; 149 | init_cfb(o); 150 | var start_di, fcnt = 0; 151 | for(di = 0; di < data.length; ++di) { 152 | var line = data[di]; 153 | if(line !== boundary && line !== boundary + "--") continue; 154 | if(fcnt++) parse_mime(o, data.slice(start_di, di), root); 155 | start_di = di; 156 | } 157 | return o; 158 | } 159 | 160 | function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ { 161 | var opts = options || {}; 162 | var boundary = opts.boundary || "SheetJS"; 163 | boundary = '------=' + boundary; 164 | 165 | var out = [ 166 | 'MIME-Version: 1.0', 167 | 'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"', 168 | '', 169 | '', 170 | '' 171 | ]; 172 | 173 | var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0]; 174 | for(var i = 1; i < cfb.FullPaths.length; ++i) { 175 | fp = cfb.FullPaths[i].slice(root.length); 176 | fi = cfb.FileIndex[i]; 177 | if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue; 178 | 179 | /* Normalize filename */ 180 | fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) { 181 | return "_x" + c.charCodeAt(0).toString(16) + "_"; 182 | }).replace(/[\u0080-\uFFFF]/g, function(u) { 183 | return "_u" + u.charCodeAt(0).toString(16) + "_"; 184 | }); 185 | 186 | /* Extract content as binary string */ 187 | var ca = fi.content; 188 | // $FlowIgnore 189 | var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca); 190 | 191 | /* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */ 192 | var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0; 193 | for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt; 194 | var qp = dispcnt >= L * 4 / 5; 195 | 196 | out.push(boundary); 197 | out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp); 198 | out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64')); 199 | out.push('Content-Type: ' + get_content_type(fi, fp)); 200 | out.push(''); 201 | 202 | out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr)); 203 | } 204 | out.push(boundary + '--\r\n'); 205 | return out.join("\r\n"); 206 | } 207 | -------------------------------------------------------------------------------- /bits/85_api.js: -------------------------------------------------------------------------------- 1 | function cfb_new(opts/*:?any*/)/*:CFBContainer*/ { 2 | var o/*:CFBContainer*/ = ({}/*:any*/); 3 | init_cfb(o, opts); 4 | return o; 5 | } 6 | 7 | function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ { 8 | var unsafe = opts && opts.unsafe; 9 | if(!unsafe) init_cfb(cfb); 10 | var file = !unsafe && CFB.find(cfb, name); 11 | if(!file) { 12 | var fpath/*:string*/ = cfb.FullPaths[0]; 13 | if(name.slice(0, fpath.length) == fpath) fpath = name; 14 | else { 15 | if(fpath.slice(-1) != "/") fpath += "/"; 16 | fpath = (fpath + name).replace("//","/"); 17 | } 18 | file = ({name: filename(name), type: 2}/*:any*/); 19 | cfb.FileIndex.push(file); 20 | cfb.FullPaths.push(fpath); 21 | if(!unsafe) CFB.utils.cfb_gc(cfb); 22 | } 23 | /*:: if(!file) throw new Error("unreachable"); */ 24 | file.content = (content/*:any*/); 25 | file.size = content ? content.length : 0; 26 | if(opts) { 27 | if(opts.CLSID) file.clsid = opts.CLSID; 28 | if(opts.mt) file.mt = opts.mt; 29 | if(opts.ct) file.ct = opts.ct; 30 | } 31 | return file; 32 | } 33 | 34 | function cfb_del(cfb/*:CFBContainer*/, name/*:string*/)/*:boolean*/ { 35 | init_cfb(cfb); 36 | var file = CFB.find(cfb, name); 37 | if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) { 38 | cfb.FileIndex.splice(j, 1); 39 | cfb.FullPaths.splice(j, 1); 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | function cfb_mov(cfb/*:CFBContainer*/, old_name/*:string*/, new_name/*:string*/)/*:boolean*/ { 46 | init_cfb(cfb); 47 | var file = CFB.find(cfb, old_name); 48 | if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) { 49 | cfb.FileIndex[j].name = filename(new_name); 50 | cfb.FullPaths[j] = new_name; 51 | return true; 52 | } 53 | return false; 54 | } 55 | 56 | function cfb_gc(cfb/*:CFBContainer*/)/*:void*/ { rebuild_cfb(cfb, true); } 57 | 58 | -------------------------------------------------------------------------------- /bits/88_cfbexports.js: -------------------------------------------------------------------------------- 1 | exports.find = find; 2 | exports.read = read; 3 | exports.parse = parse; 4 | exports.write = write; 5 | exports.writeFile = write_file; 6 | exports.utils = { 7 | cfb_new: cfb_new, 8 | cfb_add: cfb_add, 9 | cfb_del: cfb_del, 10 | cfb_mov: cfb_mov, 11 | cfb_gc: cfb_gc, 12 | ReadShift: ReadShift, 13 | CheckField: CheckField, 14 | prep_blob: prep_blob, 15 | bconcat: bconcat, 16 | use_zlib: use_zlib, 17 | _deflateRaw: _deflate, 18 | _inflateRaw: _inflate, 19 | consts: consts 20 | }; 21 | 22 | return exports; 23 | -------------------------------------------------------------------------------- /bits/89_cfbfooter.js: -------------------------------------------------------------------------------- 1 | })(); 2 | 3 | -------------------------------------------------------------------------------- /bits/98_exports.js: -------------------------------------------------------------------------------- 1 | if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; } 2 | -------------------------------------------------------------------------------- /bits/99_footer.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SheetJS/js-cfb/b01260294e204f7c128ba6ae81ec4f4d3d61a298/bits/99_footer.js -------------------------------------------------------------------------------- /dist/.npmignore: -------------------------------------------------------------------------------- 1 | .npmignore 2 | *.sheetjs 3 | -------------------------------------------------------------------------------- /dist/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (C) 2013-present SheetJS LLC 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /fails.lst: -------------------------------------------------------------------------------- 1 | # not CFB or ZIP 2 | apachepoi_testEXCEL_3.xls 3 | apachepoi_testEXCEL_4.xls 4 | xlrd_biff4_no_format_no_window2.xls 5 | libreoffice_calc_csv-import_malformed-quotes.xls 6 | # file exceeding 31 chars 7 | apachepoi_59746_NoRowNums.xlsx 8 | apachepoi_WithEmbeded.xlsx 9 | apachepoi_picture.xlsx 10 | roo_name_with_leading_slash.xlsx 11 | spout-xlsx_sheet_with_prefixed_xml_files.xlsx 12 | # not a valid file 13 | openpyxl_r_null_archive.xlsx 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | JS-CFB Live Demo 9 | 24 | 25 | 26 |
 27 | SheetJS CFB Preview Live Demo
 28 | 
 29 | Source Code Repo
 30 | Issues?  Something look weird?  Click here and report an issue
 31 | 
Drop an XLS file here to see the CFB structure.
32 | 33 | Advanced Demo Options: 34 | Use readAsBinaryString: (when available) 35 | 36 | Export Current File 37 | - Export data as CFB (Container File Binary Format) 38 | - Export data as ZIP 39 | - Export data as MAD (MIME aggregate document) 40 |
41 |

 42 | 
43 | 44 | 45 | 46 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /misc/flow.js: -------------------------------------------------------------------------------- 1 | /*:: 2 | 3 | type CFBModule = { 4 | version:string; 5 | find:(cfb:CFBContainer, path:string)=>?CFBEntry; 6 | read:(blob:RawBytes|string, opts:CFBReadOpts)=>CFBContainer; 7 | write:(cfb:CFBContainer, opts:CFBWriteOpts)=>RawBytes|string; 8 | writeFile:(cfb:CFBContainer, filename:string, opts:CFBWriteOpts)=>void; 9 | parse:(file:RawBytes, opts:CFBReadOpts)=>CFBContainer; 10 | utils:CFBUtils; 11 | }; 12 | 13 | type CFBUtils = any; 14 | 15 | type ReadShiftFunc = { 16 | //(size:number, t:?string):number|string; 17 | (size:16):string; 18 | (size:1|2|4, t:?string):number; 19 | }; 20 | type CheckFieldFunc = {(hexstr:string, fld:string):void;}; 21 | 22 | type WriteShiftFunc = { 23 | //(size:number, val:string|number, f:?string):any; 24 | (size:1|2|4|-4, val:number):any; 25 | (size:number, val:string, f:"hex"|"utf16le"):any; 26 | } 27 | 28 | type RawBytes = Array | Buffer | Uint8Array; 29 | 30 | class CFBlobArray extends Array { 31 | l:number; 32 | write_shift:WriteShiftFunc; 33 | read_shift:ReadShiftFunc; 34 | chk:CheckFieldFunc; 35 | }; 36 | interface CFBlobBuffer extends Buffer { 37 | l:number; 38 | slice:(start?:number, end:?number)=>Buffer; 39 | write_shift:WriteShiftFunc; 40 | read_shift:ReadShiftFunc; 41 | chk:CheckFieldFunc; 42 | }; 43 | interface CFBlobUint8 extends Uint8Array { 44 | l:number; 45 | slice:(start?:number, end:?number)=>Uint8Array; 46 | write_shift:WriteShiftFunc; 47 | read_shift:ReadShiftFunc; 48 | chk:CheckFieldFunc; 49 | }; 50 | 51 | interface CFBlobber { 52 | [n:number]:number; 53 | l:number; 54 | length:number; 55 | slice:(start:?number, end:?number)=>RawBytes; 56 | write_shift:WriteShiftFunc; 57 | read_shift:ReadShiftFunc; 58 | chk:CheckFieldFunc; 59 | }; 60 | 61 | type CFBlob = CFBlobArray | CFBlobBuffer | CFBlobUint8; 62 | 63 | type CFBWriteOpts = any; 64 | 65 | interface CFBReadOpts { 66 | type?:string; 67 | root?:string; 68 | }; 69 | 70 | type CFBFileIndex = Array; 71 | 72 | type CFBFindPath = (n:string)=>?CFBEntry; 73 | 74 | type CFBContainer = { 75 | raw?:{ 76 | header:any; 77 | sectors:Array; 78 | }; 79 | FileIndex:CFBFileIndex; 80 | FullPaths:Array; 81 | } 82 | 83 | type CFBEntry = { 84 | name: string; 85 | type: number; 86 | ct?: Date; 87 | mt?: Date; 88 | color: number; 89 | clsid: string; 90 | state: number; 91 | start: number; 92 | size: number; 93 | storage?: "fat" | "minifat"; 94 | L: number; 95 | R: number; 96 | C: number; 97 | content?: CFBlob; 98 | ctype?: string; 99 | } 100 | */ 101 | -------------------------------------------------------------------------------- /misc/flowdeps.js: -------------------------------------------------------------------------------- 1 | /*:: 2 | 3 | declare module 'cfb' { declare module.exports:CFBModule; }; 4 | declare module '../' { declare module.exports:CFBModule; }; 5 | declare module './' { declare module.exports:CFBModule; }; 6 | 7 | declare module 'commander' { declare module.exports:any; }; 8 | declare module 'printj' { 9 | declare var sprintf:(fmt:string, ...args:any)=>string; 10 | }; 11 | declare module 'crc-32' { declare module.exports: any; }; 12 | */ 13 | -------------------------------------------------------------------------------- /misc/help.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # make_help.sh -- process listing of targets and special items in Makefile 3 | # Copyright (C) 2016-present SheetJS 4 | # 5 | # usage in makefile: pipe the output of the following command: 6 | # @grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) 7 | # 8 | # lines starting with "## " are treated as subtitles 9 | # lines starting with "#* " are treated as plaintext comments 10 | # multiple targets with "## " after the ":" are rendered as separate targets 11 | # if the presumed default target is labeled, it will be assigned a unique color 12 | 13 | awk ' 14 | BEGIN{recipes=0;} 15 | !/#[#*] .*$/ {next;} 16 | {multi=0; isrecipe=0;} 17 | /^[^#]*:/ {isrecipe=1; ++recipes;} 18 | /^[^ :]* .*:/ {multi=1} 19 | multi==0 && isrecipe>0 { if(recipes > 1) print; else print $0, "[default]"; next} 20 | isrecipe == 0 {print; next} 21 | multi>0 { 22 | k=split($0, msg, "##"); m=split($0, a, ":"); n=split(a[1], b, " "); 23 | for(i=1; i<=n; ++i) print b[i] ":", "##" msg[2], (recipes==1 && i==1 ? "[default]" : "") 24 | } 25 | END {} 26 | ' | if [[ -t 1 ]]; then 27 | awk ' 28 | BEGIN {FS = ":.*?## "} 29 | {color=36} 30 | /\[default\]/ {color=35} 31 | NF==1 && /^##/ {color=34} 32 | NF==1 && /^#\*/ {color=20; $1 = substr($1, 4)} 33 | {printf "\033[" color "m%-20s\033[0m %s\n", $1, $2;} 34 | END{}' - 35 | else 36 | awk ' 37 | BEGIN {FS = ":.*?## "} 38 | /^#\* / {$1 = substr($1, 4)} 39 | {printf "%-20s %s\n", $1, $2;} 40 | END{}' - 41 | fi 42 | 43 | -------------------------------------------------------------------------------- /misc/node_version.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # This script will check the current version of node and install another version 4 | # of npm if node is version 0.8 5 | 6 | version=$(node --version) 7 | 8 | if [[ $version =~ v0\.8\. ]] 9 | then 10 | npm install -g npm@4.3.0 11 | fi -------------------------------------------------------------------------------- /misc/spin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # spin.sh -- show a spinner (for coverage test) 3 | # Copyright (C) 2014-present SheetJS 4 | 5 | wpid=$1 6 | delay=1 7 | str="|/-\\" 8 | while [ $(ps -a|awk '$1=='$wpid' {print $1}') ]; do 9 | t=${str#?} 10 | printf " [%c]" "$str" 11 | str=$t${str%"$t"} 12 | sleep $delay 13 | printf "\b\b\b\b" 14 | done 15 | -------------------------------------------------------------------------------- /misc/strip_sourcemap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # strip_sourcemap.sh -- strip sourcemaps from a JS file (missing from uglifyjs) 3 | # Copyright (C) 2014 SheetJS 4 | 5 | if [ $# -gt 0 ]; then 6 | if [ -e "$1" ]; then 7 | sed -i .sheetjs '/sourceMappingURL/d' "$1" 8 | fi 9 | else 10 | cat - | sed '/sourceMappingURL/d' 11 | fi 12 | -------------------------------------------------------------------------------- /misc/xlscfb.js: -------------------------------------------------------------------------------- 1 | /*:: 2 | declare var ReadShift:any; 3 | declare var CheckField:any; 4 | declare var prep_blob:any; 5 | declare var __readUInt32LE:any; 6 | declare var __readInt32LE:any; 7 | declare var __toBuffer:any; 8 | declare var __utf16le:any; 9 | declare var bconcat:any; 10 | declare var s2a:any; 11 | declare var chr0:any; 12 | declare var chr1:any; 13 | declare var has_buf:boolean; 14 | declare var new_buf:any; 15 | declare var new_raw_buf:any; 16 | declare var new_unsafe_buf:any; 17 | declare var Buffer_from:any; 18 | */ 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cfb", 3 | "version": "1.2.2", 4 | "author": "sheetjs", 5 | "description": "Compound File Binary File Format extractor", 6 | "keywords": [ 7 | "cfb", 8 | "compression", 9 | "office" 10 | ], 11 | "main": "./cfb", 12 | "types": "types", 13 | "browser": { 14 | "node": false, 15 | "process": false, 16 | "fs": false 17 | }, 18 | "dependencies": { 19 | "adler-32": "~1.3.0", 20 | "crc-32": "~1.2.0" 21 | }, 22 | "devDependencies": { 23 | "@sheetjs/uglify-js": "~2.7.3", 24 | "@types/node": "^8.10.25", 25 | "acorn": "7.4.1", 26 | "alex": "8.1.1", 27 | "blanket": "~1.2.3", 28 | "dtslint": "~0.1.2", 29 | "eslint": "7.23.0", 30 | "eslint-plugin-html": "^6.1.2", 31 | "eslint-plugin-json": "^2.1.2", 32 | "jscs": "3.0.7", 33 | "jshint": "2.13.4", 34 | "mocha": "~2.5.3", 35 | "typescript": "2.2.0" 36 | }, 37 | "repository": { 38 | "type": "git", 39 | "url": "git://github.com/SheetJS/js-cfb.git" 40 | }, 41 | "scripts": { 42 | "pretest": "make init", 43 | "test": "make test", 44 | "dtslint": "dtslint types" 45 | }, 46 | "config": { 47 | "blanket": { 48 | "pattern": "cfb.js" 49 | } 50 | }, 51 | "files": [ 52 | "LICENSE", 53 | "README.md", 54 | "dist/", 55 | "types/index.d.ts", 56 | "types/tsconfig.json", 57 | "cfb.js", 58 | "xlscfb.flow.js" 59 | ], 60 | "homepage": "http://sheetjs.com/", 61 | "bugs": { 62 | "url": "https://github.com/SheetJS/js-cfb/issues" 63 | }, 64 | "license": "Apache-2.0", 65 | "engines": { 66 | "node": ">=0.8" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/cfb-cli/.npmignore: -------------------------------------------------------------------------------- 1 | *.tgz 2 | -------------------------------------------------------------------------------- /packages/cfb-cli/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (C) 2013-present SheetJS LLC 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /packages/cfb-cli/README.md: -------------------------------------------------------------------------------- 1 | # Container File Blobs 2 | 3 | This CLI tool inspects and can manipulate supported files, leveraging the base 4 | [`cfb` library](https://www.npmjs.com/package/cfb). 5 | 6 | 7 | ## Installation 8 | 9 | It is preferable to install the library globally with npm: 10 | 11 | ```bash 12 | $ npm install -g cfb-cli 13 | ``` 14 | 15 | The global installation adds a command `cfb-cli` which can work with files. 16 | 17 | 18 | ## Usage 19 | 20 | - `cfb file [names...]` extracts the contents of the file. If additional names 21 | are supplied, only the listed files will be extracted. 22 | 23 | - `cfb -l file` lists the contained files (following `unzip -l` "short format") 24 | 25 | - `cfb -r file` attempts to repair by reading and re-writing the file. 26 | This fixes some issues with files generated by non-standard tools. 27 | 28 | - `cfb -c file [files...]` creates a new file containing the listed files. 29 | The default root entry name is `Root Entry`. 30 | 31 | - `cfb -a file [files...]` adds the listed files to the original file. 32 | 33 | - `cfb -d file [files...]` deletes the listed files from the original file. 34 | 35 | 36 | ## License 37 | 38 | Please consult the attached LICENSE file for details. All rights not explicitly 39 | granted by the Apache 2.0 license are reserved by the Original Author. 40 | 41 | 42 | ## Credits 43 | 44 | Special thanks to [Garrett Luu](https://garrettluu.com/) for spinning off the 45 | command from the CFB module. 46 | 47 | 48 | [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-cfb?pixel)](https://github.com/SheetJS/js-cfb) 49 | -------------------------------------------------------------------------------- /packages/cfb-cli/bin/cfb.njs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */ 3 | /* eslint-env node */ 4 | /* vim: set ts=2 ft=javascript: */ 5 | var cli = require('../'); 6 | 7 | cli(); 8 | -------------------------------------------------------------------------------- /packages/cfb-cli/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* index.js (C) 2020-present SheetJS -- http://sheetjs.com */ 3 | /* eslint-env node */ 4 | /* vim: set ts=2 ft=javascript: */ 5 | 6 | var n = "cfb-cli"; 7 | var X = require('cfb'); 8 | var fs = require('fs'); 9 | var program = require('commander'); 10 | var PRINTJ = require("printj"); 11 | function run() { 12 | var sprintf = PRINTJ.sprintf; 13 | program 14 | .version(X.version) 15 | .usage('[options] [subfiles...]') 16 | .option('-l, --list-files', 'list files') 17 | .option('-r, --repair', 'attempt to repair and garbage-collect archive') 18 | .option('-c, --create', 'create file') 19 | .option('-a, --append', 'add files to CFB (overwrite existing data)') 20 | .option('-d, --delete', 'delete files from CFB') 21 | .option('-O, --to-stdout', 'extract raw contents to stdout') 22 | .option('-z, --dump', 'dump internal representation but do not extract') 23 | .option('-q, --quiet', 'process but do not report') 24 | .option('--here', 'skip the CFB root name when extracting') 25 | .option('--osx', 'use OSX-style unzip listing') 26 | .option('--zlib', 'use native zlib') 27 | .option('--local', 'print times in local timezone') 28 | .option('--dev', 'development mode') 29 | .option('--read', 'read but do not print out contents'); 30 | program.parse(process.argv); 31 | 32 | if (program.zlib) X.utils.use_zlib(require('zlib')); 33 | 34 | var exit = process.exit; 35 | var die = function (errno/*:number*/, msg/*:string*/) { console.error(n + ": " + msg); exit(errno); }; 36 | var logit = function (cmd/*:string*/, f/*:string*/) { console.error(sprintf("%-6s %s", cmd, f)); }; 37 | 38 | if (program.args.length === 0) die(1, "must specify a filename"); 39 | 40 | if (program.create) { 41 | logit("create", program.args[0]); 42 | var newcfb = X.utils.cfb_new(); 43 | X.writeFile(newcfb, program.args[0]); 44 | } 45 | 46 | if (!fs.existsSync(program.args[0])) die(1, "must specify a filename"); 47 | 48 | var opts = ({ type: 'file' }/*:any*/); 49 | if (program.dev) opts.WTF = true; 50 | 51 | var cfb = X.read(program.args[0], opts); 52 | if (program.quiet) exit(0); 53 | 54 | if (program.dump) { 55 | console.log("Full Paths:"); 56 | console.log(cfb.FullPaths.map(function (x/*:string*/) { return " " + x; }).join("\n")); 57 | console.log("File Index:"); 58 | console.log(cfb.FileIndex); 59 | exit(0); 60 | } 61 | if (program.repair) { X.writeFile(cfb, program.args[0]); exit(0); } 62 | 63 | var rlen = cfb.FullPaths[0].length; 64 | 65 | function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/g, function ($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); } 66 | var format_date = function (date/*:Date*/, osx/*:?any*/)/*:string*/ { 67 | var datefmt = osx ? "%02u-%02u-%04u %02u:%02u" : "%02u-%02u-%02u %02u:%02u"; 68 | var MM = program.local ? date.getMonth() + 1 : date.getUTCMonth() + 1; 69 | var DD = program.local ? date.getDate() : date.getUTCDate(); 70 | var YY = (program.local ? date.getFullYear() : date.getUTCFullYear()) % (osx ? 10000 : 100); 71 | var hh = program.local ? date.getHours() : date.getUTCHours(); 72 | var mm = program.local ? date.getMinutes() : date.getUTCMinutes(); 73 | return sprintf(datefmt, MM, DD, YY, hh, mm); 74 | }; 75 | 76 | if (program.listFiles) { 77 | var basetime = new Date(Date.UTC(1980, 0, 1)); 78 | var cnt = 0, rootsize = 0, filesize = 0; 79 | var fmtstr = "%9lu %s %s"; 80 | if (program.osx) { 81 | console.log("Archive: " + program.args[0]); 82 | console.log(" Length Date Time Name"); 83 | console.log("--------- ---------- ----- ----"); 84 | fmtstr = "%9lu %s %s"; 85 | } else { 86 | console.log(" Length Date Time Name"); 87 | console.log(" -------- ---- ---- ----"); 88 | } 89 | cfb.FileIndex.forEach(function (file/*:CFBEntry*/, i/*:number*/) { 90 | switch (file.type) { 91 | case 5: 92 | basetime = file.ct || file.mt || basetime; 93 | rootsize = file.size; 94 | break; 95 | case 2: 96 | var fixname = fix_string(cfb.FullPaths[i]); 97 | if (program.osx && fixname.match(/\\u0001Sh33tJ5/)) return; 98 | if (program.here) fixname = fixname.slice(rlen); 99 | console.log(sprintf(fmtstr, file.size, format_date(file.mt || basetime, program.osx), fixname)); 100 | filesize += file.size; 101 | ++cnt; 102 | } 103 | }); 104 | var outfmt = "%9lu %lu file%s"; 105 | if (program.osx) { 106 | console.log("--------- -------"); 107 | outfmt = "%9lu %lu file%s"; 108 | } else { 109 | console.log(" -------- -------"); 110 | } 111 | console.log(sprintf(outfmt, rootsize || filesize, cnt, (cnt !== 1 ? "s" : ""))); 112 | 113 | exit(0); 114 | } 115 | 116 | function mkdirp(path/*:string*/) { 117 | path.split("/").reduce(function (acc/*:string*/, p/*:string*/) { 118 | acc += p + "/"; 119 | if (!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); } 120 | return acc; 121 | }, ""); 122 | } 123 | 124 | function write(path/*:string*/, data/*:CFBEntry*/) { 125 | logit("write", fix_string(path)); 126 | fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/ || new Buffer(0)); 127 | } 128 | 129 | if (program.create || program.append) { 130 | program.args.slice(1).forEach(function (x/*:string*/) { 131 | logit("append", x); 132 | X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x)); 133 | }); 134 | X.writeFile(cfb, program.args[0]); 135 | exit(0); 136 | } 137 | 138 | if (program.delete) { 139 | program.args.slice(1).forEach(function (x/*:string*/) { 140 | logit("delete", x); 141 | X.utils.cfb_del(cfb, "/" + x); 142 | }); 143 | X.writeFile(cfb, program.args[0]); 144 | exit(0); 145 | } 146 | 147 | if (program.args.length > 1) { 148 | program.args.slice(1).forEach(function (x/*:string*/) { 149 | var data/*:?CFBEntry*/ = X.find(cfb, x.replace(/\\u000\d/g, "!")); 150 | if (!data) { console.error(x + ": file not found"); return; } 151 | if (data.type !== 2) { console.error(x + ": not a file"); return; } 152 | var idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx]; 153 | if (program.toStdout) return process.stdout.write(/*::new Buffer((*/data.content/*:: :any))*/); 154 | mkdirp(path.slice(0, path.lastIndexOf("/"))); 155 | write(path, data); 156 | }); 157 | exit(0); 158 | } 159 | 160 | if (program.toStdout) exit(0); 161 | for (var i = program.here ? 1 : 0; i !== cfb.FullPaths.length; ++i) { 162 | if (!cfb.FileIndex[i].name) continue; 163 | var fp = cfb.FullPaths[i]; 164 | if (program.here) fp = fp.slice(rlen); 165 | if (fp.slice(-1) === "/") mkdirp(fp); 166 | else { 167 | if (fp.indexOf("/") > -1) mkdirp(fp.slice(0, fp.lastIndexOf("/"))); 168 | write(fp, cfb.FileIndex[i]); 169 | } 170 | } 171 | } 172 | 173 | module.exports = run; -------------------------------------------------------------------------------- /packages/cfb-cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cfb-cli", 3 | "version": "1.0.1", 4 | "description": "Command-line interface for cfb", 5 | "bin": { 6 | "cfb-cli": "./bin/cfb.njs" 7 | }, 8 | "main": "index.js", 9 | "author": "Garrett Luu", 10 | "license": "Apache-2.0", 11 | "dependencies": { 12 | "cfb": "^1.1.4", 13 | "commander": "^5.1.0", 14 | "printj": "^1.2.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /shim.js: -------------------------------------------------------------------------------- 1 | /*! shim.js (C) 2013-present SheetJS -- http://sheetjs.com */ 2 | /* ES3/5 Compatibility shims and other utilities for older browsers. */ 3 | 4 | // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys 5 | if(!Object.keys) Object.keys = (function() { 6 | var hasOwnProperty = Object.prototype.hasOwnProperty, 7 | hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), 8 | dontEnums = [ 9 | 'toString', 10 | 'toLocaleString', 11 | 'valueOf', 12 | 'hasOwnProperty', 13 | 'isPrototypeOf', 14 | 'propertyIsEnumerable', 15 | 'constructor' 16 | ], 17 | dontEnumsLength = dontEnums.length; 18 | 19 | return function(obj) { 20 | if(typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object'); 21 | 22 | var result = []; 23 | 24 | for(var prop in obj) if(hasOwnProperty.call(obj, prop)) result.push(prop); 25 | 26 | if(hasDontEnumBug) 27 | for(var i=0; i < dontEnumsLength; ++i) 28 | if(hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); 29 | return result; 30 | }; 31 | })(); 32 | 33 | if(!String.prototype.trim) String.prototype.trim = function() { 34 | var s = this.replace(/^\s+/, ''); 35 | for(var i = s.length - 1; i >=0 ; --i) if(!s.charAt(i).match(/^\s/)) return s.slice(0,i+1); 36 | return ""; 37 | }; 38 | 39 | if(!Array.prototype.forEach) Array.prototype.forEach = function(cb) { 40 | var len = (this.length>>>0), self = (arguments[1]||void 0); 41 | for(var i=0; i>>0), self = (arguments[1]||void 0), A = new Array(len); 46 | for(var i=0; i>>0), i = ((arguments[1]|0)||0); 52 | for(i<0 && (i+=len)<0 && (i=0); i>>0), i = len - 1; 58 | for(; i>=0; --i) if(this[i] === needle) return i; 59 | return -1; 60 | }; 61 | 62 | if(!Array.isArray) Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]"; }; 63 | 64 | if(!Date.prototype.toISOString) Date.prototype.toISOString = (function() { 65 | function p(n,i) { return ('0000000' + n).slice(-(i||2)); } 66 | 67 | return function _toISOString() { 68 | var y = this.getUTCFullYear(), yr = ""; 69 | if(y>9999) yr = '+' + p( y, 6); 70 | else if(y<0) yr = '-' + p(-y, 6); 71 | else yr = p( y, 4); 72 | 73 | return [ 74 | yr, p(this.getUTCMonth()+1), p(this.getUTCDate()) 75 | ].join('-') + 'T' + [ 76 | p(this.getUTCHours()), p(this.getUTCMinutes()), p(this.getUTCSeconds()) 77 | ].join(':') + '.' + p(this.getUTCMilliseconds(),3) + 'Z'; 78 | }; 79 | }()); 80 | 81 | if(typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) ArrayBuffer.prototype.slice = function(start, end) { 82 | if(start == null) start = 0; 83 | if(start < 0) { start += this.byteLength; if(start < 0) start = 0; } 84 | if(start >= this.byteLength) return new Uint8Array(0); 85 | if(end == null) end = this.byteLength; 86 | if(end < 0) { end += this.byteLength; if(end < 0) end = 0; } 87 | if(end > this.byteLength) end = this.byteLength; 88 | if(start > end) return new Uint8Array(0); 89 | var out = new ArrayBuffer(end - start); 90 | var view = new Uint8Array(out); 91 | var data = new Uint8Array(this, start, end - start) 92 | /* IE10 should have Uint8Array#set */ 93 | if(view.set) view.set(data); else while(start <= --end) view[end - start] = data[end]; 94 | return out; 95 | }; 96 | if(typeof Uint8Array !== 'undefined' && !Uint8Array.prototype.slice) Uint8Array.prototype.slice = function(start, end) { 97 | if(start == null) start = 0; 98 | if(start < 0) { start += this.length; if(start < 0) start = 0; } 99 | if(start >= this.length) return new Uint8Array(0); 100 | if(end == null) end = this.length; 101 | if(end < 0) { end += this.length; if(end < 0) end = 0; } 102 | if(end > this.length) end = this.length; 103 | if(start > end) return new Uint8Array(0); 104 | var out = new Uint8Array(end - start); 105 | while(start <= --end) out[end - start] = this[end]; 106 | return out; 107 | }; 108 | 109 | // VBScript + ActiveX fallback for IE5+ 110 | var IE_SaveFile = (function() { try { 111 | if(typeof IE_SaveFile_Impl == "undefined") document.write([ 112 | '