Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b01260294e | ||
5a5870eb1b | |||
ad93f76a36 | |||
0e33eb6e13 | |||
c5eb7e6278 | |||
99990abf64 | |||
|
4d8ef18b10 | ||
1e70aae159 | |||
|
efb96a2c2c | ||
|
4c7b78f9dc | ||
76e4603fa5 | |||
|
1a1920c567 | ||
7c1980741a | |||
6367acfd8a | |||
aff6d67444 | |||
8756cc9b41 | |||
8d85fb6e74 | |||
|
62bd08588e | ||
d9b99d68a7 | |||
8ee792f343 | |||
c88a98104d | |||
8bb0c56acd | |||
35d59c57bf | |||
17b1a8de5a | |||
98e9d2e641 | |||
25688e28fe | |||
b0e076f003 | |||
8cd01668f0 | |||
46719dfe3c |
20
.eslintrc
20
.eslintrc
@ -2,17 +2,23 @@
|
||||
"env": { "shared-node-browser":true },
|
||||
"globals": {},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 3,
|
||||
"ecmaVersion": 3
|
||||
},
|
||||
"plugins": [ "html", "json" ],
|
||||
"!extends": "eslint:recommended",
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
"no-console": 0,
|
||||
"no-bitwise": 0,
|
||||
"curly": 0,
|
||||
"comma-style": [ 2, "last" ],
|
||||
"comma-dangle": [ 2, "never" ],
|
||||
"curly": 0,
|
||||
"no-bitwise": 0,
|
||||
"no-console": 0,
|
||||
"no-control-regex": 0,
|
||||
"no-empty": 0,
|
||||
"no-trailing-spaces": 2,
|
||||
"semi": [ 2, "always" ],
|
||||
"comma-dangle": [ 2, "never" ]
|
||||
"no-use-before-define": [ 1, {
|
||||
"functions":false, "classes":true, "variables":false
|
||||
}],
|
||||
"no-useless-escape": 0,
|
||||
"semi": [ 2, "always" ]
|
||||
}
|
||||
}
|
||||
|
@ -34,3 +34,4 @@ module.file_ext=.js
|
||||
module.file_ext=.njs
|
||||
module.ignore_non_literal_requires=true
|
||||
suppress_comment= \\(.\\|\n\\)*\\$FlowIgnore
|
||||
|
||||
|
91
.github/workflows/node-4+.yml
vendored
Normal file
91
.github/workflows/node-4+.yml
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
name: 'Tests: node.js'
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
latest: ${{ steps.set-matrix.outputs.requireds }}
|
||||
steps:
|
||||
- uses: ljharb/actions/node/matrix@main
|
||||
id: set-matrix
|
||||
with:
|
||||
versionsAsRoot: true
|
||||
type: 'majors'
|
||||
preset: '>=4'
|
||||
|
||||
latest:
|
||||
needs: [matrix]
|
||||
name: 'latest majors'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: ${{ fromJson(needs.matrix.outputs.latest) }}
|
||||
include:
|
||||
- node-version: '14.'
|
||||
env:
|
||||
TZ: America/New_York
|
||||
- node-version: '13.'
|
||||
env:
|
||||
TZ: Europe/London
|
||||
- node-version: '12.'
|
||||
env:
|
||||
TZ: Asia/Seoul
|
||||
- node-version: '11.'
|
||||
env:
|
||||
TZ: America/Los_Angeles
|
||||
FMTS: misc
|
||||
- node-version: '10.'
|
||||
env:
|
||||
TZ: Europe/Berlin
|
||||
FMTS: misc
|
||||
- node-version: '9.'
|
||||
env:
|
||||
TZ: Asia/Kolkata
|
||||
FMTS: misc
|
||||
- node-version: '8.'
|
||||
env:
|
||||
TZ: Asia/Shanghai
|
||||
FMTS: misc
|
||||
- node-version: '7.'
|
||||
env:
|
||||
TZ: America/Cancun
|
||||
FMTS: misc
|
||||
- node-version: '6.'
|
||||
env:
|
||||
TZ: Asia/Seoul
|
||||
FMTS: misc
|
||||
- node-version: '5.'
|
||||
env:
|
||||
TZ: America/Anchorage
|
||||
FMTS: misc
|
||||
- node-version: '4.'
|
||||
env:
|
||||
TZ: America/Barbados
|
||||
FMTS: misc
|
||||
- node-version: '4.4.7' # see GH issue #1150
|
||||
env:
|
||||
TZ: Asia/Tokyo
|
||||
FMTS: misc
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ljharb/actions/node/install@main
|
||||
name: 'nvm install ${{ matrix.node-version }} && npm install'
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64
|
||||
- run: sudo chmod a+x /usr/bin/rooster
|
||||
- run: make init
|
||||
- run: 'cd test_files; make all; cd -'
|
||||
- run: npm run test
|
||||
|
||||
node:
|
||||
name: 'node 4+'
|
||||
needs: [latest]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: 'echo tests completed'
|
45
.github/workflows/node-iojs.yml
vendored
Normal file
45
.github/workflows/node-iojs.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
name: 'Tests: node.js (io.js)'
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
latest: ${{ steps.set-matrix.outputs.requireds }}
|
||||
steps:
|
||||
- uses: ljharb/actions/node/matrix@main
|
||||
id: set-matrix
|
||||
with:
|
||||
type: 'majors'
|
||||
preset: 'iojs'
|
||||
|
||||
latest:
|
||||
needs: [matrix]
|
||||
name: 'latest majors'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.matrix.outputs.latest) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ljharb/actions/node/install@main
|
||||
name: 'nvm install ${{ matrix.node-version }} && npm install'
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
skip-ls-check: true
|
||||
- run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64
|
||||
- run: sudo chmod a+x /usr/bin/rooster
|
||||
- run: make init
|
||||
- run: 'cd test_files; make all; cd -'
|
||||
- run: npm run test
|
||||
#- run: 'cd packages/ssf; npm run tests-only; cd -'
|
||||
|
||||
node:
|
||||
name: 'io.js'
|
||||
needs: [latest]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: 'echo tests completed'
|
32
.github/workflows/node-pretest.yml
vendored
Normal file
32
.github/workflows/node-pretest.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: 'Tests: pretest/posttest'
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
pretest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ljharb/actions/node/install@main
|
||||
name: 'nvm install lts/* && npm install'
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64
|
||||
- run: sudo chmod a+x /usr/bin/rooster
|
||||
- run: make init
|
||||
- run: 'cd test_files; make all; cd -'
|
||||
#- run: npm run pretest
|
||||
|
||||
# posttest:
|
||||
# runs-on: ubuntu-latest
|
||||
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - uses: ljharb/actions/node/install@main
|
||||
# name: 'nvm install lts/* && npm install'
|
||||
# with:
|
||||
# node-version: 'lts/*'
|
||||
# - run: make init
|
||||
# - run: 'cd test_files; make all; cd -'
|
||||
# - run: npm run posttest
|
88
.github/workflows/node-zero.yml
vendored
Normal file
88
.github/workflows/node-zero.yml
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
name: 'Tests: node.js (0.x)'
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
stable: ${{ steps.set-matrix.outputs.requireds }}
|
||||
# unstable: ${{ steps.set-matrix.outputs.optionals }}
|
||||
steps:
|
||||
- uses: ljharb/actions/node/matrix@main
|
||||
id: set-matrix
|
||||
with:
|
||||
versionsAsRoot: true
|
||||
preset: '0.x'
|
||||
|
||||
stable:
|
||||
needs: [matrix]
|
||||
name: 'stable minors'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: ${{ fromJson(needs.matrix.outputs.stable) }}
|
||||
include:
|
||||
- node-version: '0.12.'
|
||||
env:
|
||||
TZ: America/Cayman
|
||||
FMTS: misc
|
||||
- node-version: '0.10.'
|
||||
env:
|
||||
TZ: Pacific/Honolulu
|
||||
FMTS: misc
|
||||
- node-version: '0.8.'
|
||||
env:
|
||||
TZ: America/Mexico_City
|
||||
FMTS: misc
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ljharb/actions/node/install@main
|
||||
name: 'nvm install ${{ matrix.node-version }} && npm install'
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }}
|
||||
skip-ls-check: true
|
||||
- run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64
|
||||
- run: sudo chmod a+x /usr/bin/rooster
|
||||
- run: make init
|
||||
- run: 'cd test_files; make all; cd -'
|
||||
- run: npm run test
|
||||
#- run: 'cd packages/ssf; npm run tests-only; cd -'
|
||||
|
||||
# unstable:
|
||||
# needs: [matrix, stable]
|
||||
# name: 'unstable minors'
|
||||
# continue-on-error: true
|
||||
# if: ${{ !github.head_ref || !startsWith(github.head_ref, 'renovate') }}
|
||||
# runs-on: ubuntu-latest
|
||||
|
||||
# strategy:
|
||||
# fail-fast: false
|
||||
# matrix:
|
||||
# node-version: ${{ fromJson(needs.matrix.outputs.unstable) }}
|
||||
#
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - uses: ljharb/actions/node/install@main
|
||||
# name: 'nvm install ${{ matrix.node-version }} && npm install'
|
||||
# with:
|
||||
# node-version: ${{ matrix.node-version }}
|
||||
# cache-node-modules-key: node_modules-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }}
|
||||
# skip-ls-check: true
|
||||
# - run: sudo curl -Lo /usr/bin/rooster https://github.com/SheetJS/rooster/releases/download/v0.2.0/rooster-v0.2.0-linux-amd64
|
||||
# - run: sudo chmod a+x /usr/bin/rooster
|
||||
# - run: make init
|
||||
# - run: 'cd test_files; make all; cd -'
|
||||
# - run: npm run tests-only
|
||||
|
||||
node:
|
||||
name: 'node 0.x'
|
||||
# needs: [stable, unstable]
|
||||
needs: [stable]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: 'echo tests completed'
|
13
.gitignore
vendored
13
.gitignore
vendored
@ -10,18 +10,27 @@ test_files_pres
|
||||
*.[cC][sS][vV]
|
||||
*.[dD][iIbB][fF]
|
||||
*.[pP][rR][nN]
|
||||
*.[pP][mM][dD]*
|
||||
*.[pP][dD][fF]
|
||||
*.[sS][lL][kK]
|
||||
*.socialcalc
|
||||
*.[xX][lL][sSwWcC]
|
||||
*.[xX][lL][sS][xXmMbB]
|
||||
*.[xX][lL][sSwWcCaAtTmM]
|
||||
*.[xX][lL][sSaAtT][xXmMbB]
|
||||
*.[oO][dD][sS]
|
||||
*.[fF][oO][dD][sS]
|
||||
*.[xX][mM][lL]
|
||||
*.[uU][oO][sS]
|
||||
*.[wW][kKqQbB][S1234567890]
|
||||
*.[qQ][pP][wW]
|
||||
*.[bB][iI][fF][fF][23458]
|
||||
*.[rR][tT][fF]
|
||||
*.[eE][tT][hH]
|
||||
*.[zZ][iI][pP]
|
||||
*.[mM][sS][iIgG]
|
||||
*.[mM][hH][tT]
|
||||
*.123
|
||||
*.htm
|
||||
*.html
|
||||
*.sheetjs
|
||||
*.exe
|
||||
*.img
|
||||
|
13
.travis.yml
13
.travis.yml
@ -1,5 +1,11 @@
|
||||
language: node_js
|
||||
dist: xenial
|
||||
node_js:
|
||||
- "14"
|
||||
- "13"
|
||||
- "12"
|
||||
- "11"
|
||||
- "10"
|
||||
- "9"
|
||||
- "8"
|
||||
- "7"
|
||||
@ -10,12 +16,15 @@ node_js:
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
before_install:
|
||||
- "npm install -g npm@4.3.0"
|
||||
- "npm config set strict-ssl false"
|
||||
- "./misc/node_version.sh"
|
||||
- "npm install -g mocha@2.x voc"
|
||||
- "npm install blanket"
|
||||
- "npm install xlsjs crc-32"
|
||||
- "npm install word crc-32"
|
||||
- "npm install coveralls mocha-lcov-reporter"
|
||||
before_script:
|
||||
- "make init"
|
||||
install:
|
||||
- npm install
|
||||
after_success:
|
||||
- "make coveralls-spin"
|
||||
|
24
CHANGELOG.md
24
CHANGELOG.md
@ -4,6 +4,30 @@ This log is intended to keep track of backwards-incompatible changes, including
|
||||
but not limited to API changes and file location changes. Minor behavioral
|
||||
changes may not be included if they are not expected to break existing code.
|
||||
|
||||
## 1.2.1 (2021-09-06)
|
||||
|
||||
* CFB write optimizations (h/t @rossj Ross Johnson)
|
||||
* `read` in NodeJS will treat `Buffer` input as type `"buffer"` by default
|
||||
* `deflate` / ZIP support fixed Huffman compression
|
||||
* `inflate` more aggressive reallocs
|
||||
|
||||
## 1.2.0 (2020-07-09)
|
||||
|
||||
* Support for MAD file format (MIME aggregate document)
|
||||
* Spun off the CLI tool to the `cfb-cli` module
|
||||
|
||||
## 1.1.0 (2018-09-04)
|
||||
|
||||
* Support for ZIP file format
|
||||
|
||||
## 1.0.6 (2018-04-09)
|
||||
|
||||
* `lastIndexOf` in FAT builder enables larger file parsing at minor cost
|
||||
|
||||
## 1.0.0 (2017-11-05)
|
||||
|
||||
* Actually walk mini-fat
|
||||
|
||||
## 0.14.0 (2017-11-04)
|
||||
|
||||
* Completely removed `FullPathDir`
|
||||
|
190
LICENSE
190
LICENSE
@ -1,4 +1,192 @@
|
||||
Copyright (C) 2013-present SheetJS
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2013-present SheetJS LLC
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
39
Makefile
39
Makefile
@ -4,7 +4,7 @@ FMT=xls doc ppt misc full
|
||||
REQS=
|
||||
ADDONS=
|
||||
AUXTARGETS=xlscfb.js
|
||||
CMDS=bin/cfb.njs
|
||||
CMDS=packages/cfb-cli/bin/cfb.njs
|
||||
HTMLLINT=index.html
|
||||
|
||||
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
|
||||
@ -31,7 +31,7 @@ bits/31_version.js: package.json
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Remove targets and build artifacts
|
||||
rm -f $(TARGET) $(FLOWTARGET)
|
||||
rm -f $(TARGET) $(FLOWTARGET) xlscfb.js xlscfb.flow.js
|
||||
|
||||
.PHONY: clean-data
|
||||
clean-data:
|
||||
@ -39,20 +39,22 @@ clean-data:
|
||||
|
||||
.PHONY: init
|
||||
init: ## Initial setup for development
|
||||
if [ ! -e test_files ]; then git clone https://github.com/SheetJS/test_files; fi
|
||||
if [ ! -e test_files ]; then git clone --depth=1 https://github.com/SheetJS/test_files; fi
|
||||
cd test_files; git pull; make
|
||||
if [ ! -e test_files_pres ]; then git clone https://github.com/SheetJS/test_files_pres; fi
|
||||
if [ ! -e test_files_pres ]; then git clone --depth=1 https://github.com/SheetJS/test_files_pres; fi
|
||||
cd test_files_pres; git pull
|
||||
|
||||
.PHONY: dist
|
||||
dist: dist-deps $(TARGET) ## Prepare JS files for distribution
|
||||
cp $(TARGET) dist/
|
||||
mkdir -p dist
|
||||
cp LICENSE dist/
|
||||
cp $(TARGET) dist/
|
||||
uglifyjs $(TARGET) $(UGLIFYOPTS) -o dist/$(LIB).min.js --source-map dist/$(LIB).min.map --preamble "$$(head -n 1 bits/00_header.js)"
|
||||
misc/strip_sourcemap.sh dist/$(LIB).min.js
|
||||
|
||||
.PHONY: dist-deps
|
||||
dist-deps: xlscfb.js ## Copy dependencies for distribution
|
||||
mkdir -p dist
|
||||
cp xlscfb.flow.js dist/xlscfb.js
|
||||
|
||||
.PHONY: aux
|
||||
@ -61,15 +63,15 @@ aux: $(AUXTARGETS)
|
||||
.PHONY: xls
|
||||
xls: xlscfb.js
|
||||
|
||||
XLSSKIP=bits/08_blob.js bits/04_base64.js bits/05_buf.js
|
||||
XLSDEPS=misc/suppress_export.js $(filter-out $(XLSSKIP),$(DEPS))
|
||||
XLSSKIP=bits/08_blob.js bits/04_base64.js bits/05_buf.js bits/98_exports.js
|
||||
XLSDEPS=misc/xlscfb.js $(filter-out $(XLSSKIP),$(DEPS))
|
||||
xlscfb.flow.js: $(XLSDEPS) ## Build support library
|
||||
cat $^ | tr -d '\15\32' > $@
|
||||
cat $^ | tr -d '\15\32' | grep -v DO_NOT_EXPORT_CFB > $@
|
||||
|
||||
BYTEFILE=dist/cfb.min.js dist/xlscfb.js
|
||||
.PHONY: bytes
|
||||
bytes: ## Display minified and gzipped file sizes
|
||||
for i in $(BYTEFILE); do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
|
||||
for i in $(BYTEFILE); do npx printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
|
||||
|
||||
|
||||
## Testing
|
||||
@ -93,22 +95,23 @@ fullint: lint old-lint tslint flow mdlint ## Run all checks
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(TARGET) $(AUXTARGETS) ## Run eslint checks
|
||||
@eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(AUXTARGETS) $(CMDS) $(HTMLLINT) package.json
|
||||
if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
|
||||
@./node_modules/.bin/eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(CMDS) $(HTMLLINT) package.json
|
||||
@if [ -x "$(CLOSURE)" ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
|
||||
|
||||
.PHONY: old-lint
|
||||
old-lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
|
||||
@jshint --show-non-errors $(TARGET) $(AUXTARGETS)
|
||||
@jshint --show-non-errors $(CMDS)
|
||||
@jshint --show-non-errors package.json test.js
|
||||
@jshint --show-non-errors --extract=always $(HTMLLINT)
|
||||
@jscs $(TARGET) $(AUXTARGETS) test.js
|
||||
if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
|
||||
@./node_modules/.bin/jscs $(TARGET) $(AUXTARGETS) test.js
|
||||
@./node_modules/.bin/jshint --show-non-errors $(TARGET) $(AUXTARGETS)
|
||||
@./node_modules/.bin/jshint --show-non-errors $(CMDS)
|
||||
@./node_modules/.bin/jshint --show-non-errors package.json test.js
|
||||
@./node_modules/.bin/jshint --show-non-errors --extract=always $(HTMLLINT)
|
||||
@if [ -x "$(CLOSURE)" ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
|
||||
|
||||
.PHONY: tslint
|
||||
tslint: $(TARGET) ## Run typescript checks
|
||||
#@npm install dtslint typescript
|
||||
@npm run-script dtslint
|
||||
#@npm run-script dtslint
|
||||
./node_modules/.bin/dtslint types
|
||||
|
||||
.PHONY: flow
|
||||
flow: lint ## Run flow checker
|
||||
|
107
README.md
107
README.md
@ -1,13 +1,11 @@
|
||||
# Compound File Binary Format
|
||||
# Container File Blobs
|
||||
|
||||
Pure JS implementation of MS-CFB: Compound File Binary File Format, a container
|
||||
format used in many Microsoft file types (XLS, DOC, VBA blobs in XLSX and XLSB)
|
||||
Pure JS implementation of various container file formats, including ZIP and CFB.
|
||||
|
||||
[](https://travis-ci.org/SheetJS/js-cfb)
|
||||
[](https://coveralls.io/r/SheetJS/js-cfb?branch=master)
|
||||
[](https://david-dm.org/sheetjs/js-cfb)
|
||||
[](https://npmjs.org/package/cfb)
|
||||
[](https://ghit.me/repo/sheetjs/js-xlsx)
|
||||
[](https://github.com/SheetJS/js-cfb)
|
||||
|
||||
## Installation
|
||||
@ -24,7 +22,7 @@ With [npm](https://www.npmjs.org/package/cfb):
|
||||
$ npm install cfb
|
||||
```
|
||||
|
||||
The `xlscfb.js` file is designed to be embedded in [js-xlsx](http://git.io/xlsx)
|
||||
The `xlscfb.js` file is designed to be embedded in [js-xlsx](https://github.com/SheetJS/sheetjs)
|
||||
|
||||
|
||||
## Library Usage
|
||||
@ -46,28 +44,8 @@ var data = workbook.content;
|
||||
|
||||
## Command-Line Utility Usage
|
||||
|
||||
It is preferable to install the library globally with npm:
|
||||
|
||||
```bash
|
||||
$ npm install -g cfb
|
||||
```
|
||||
|
||||
The global installation adds a command `cfb` which can work with files:
|
||||
|
||||
- `cfb file [names...]` extracts the contents of the file. If additional names
|
||||
are supplied, only the listed files will be extracted.
|
||||
|
||||
- `cfb -l file` lists the contained files (following `unzip -l` "short format")
|
||||
|
||||
- `cfb -r file` attempts to repair by reading and re-writing the file.
|
||||
This fixes some issues with files generated by non-standard tools.
|
||||
|
||||
- `cfb -c file [files...]` creates a new file containing the listed files.
|
||||
The default root entry name is `Root Entry`.
|
||||
|
||||
- `cfb -a file [files...]` adds the listed files to the original file.
|
||||
|
||||
- `cfb -d file [files...]` deletes the listed files from the original file.
|
||||
The [`cfb-cli`](https://www.npmjs.com/package/cfb-cli) module ships with a CLI
|
||||
tool for manipulating and inspecting supported files.
|
||||
|
||||
|
||||
## JS API
|
||||
@ -79,29 +57,52 @@ The CFB object exposes the following methods and properties:
|
||||
`CFB.parse(blob)` takes a nodejs Buffer or an array of bytes and returns an
|
||||
parsed representation of the data.
|
||||
|
||||
`CFB.read(blob, opts)` wraps `parse`. `opts.type` controls the behavior:
|
||||
|
||||
| `type` | expected input |
|
||||
|------------|-----------------------------------------------------------------|
|
||||
| `"base64"` | string: Base64 encoding of the file |
|
||||
| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
|
||||
| `"file"` | string: path of file that will be read (nodejs only) |
|
||||
| (default) | buffer or array of 8-bit unsigned int (byte `n` is `data[n]`) |
|
||||
`CFB.read(blob, opts)` wraps `parse`.
|
||||
|
||||
`CFB.find(cfb, path)` performs a case-insensitive match for the path (or file
|
||||
name, if there are no slashes) and returns an entry object or null if not found.
|
||||
|
||||
`CFB.write(cfb, opts)` generates a file based on the container. `opts.type`
|
||||
controls the behavior:
|
||||
|
||||
| `type` | output |
|
||||
|------------|-----------------------------------------------------------------|
|
||||
| `"base64"` | string: Base64 encoding of the file |
|
||||
| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
|
||||
| (default) | buffer if available, array of 8-bit unsigned int otherwise |
|
||||
`CFB.write(cfb, opts)` generates a file based on the container.
|
||||
|
||||
`CFB.writeFile(cfb, filename, opts)` creates a file with the specified name.
|
||||
|
||||
### Parse Options
|
||||
|
||||
`CFB.read` takes an options argument. `opts.type` controls the behavior:
|
||||
|
||||
| `type` | expected input |
|
||||
|------------|:----------------------------------------------------------------|
|
||||
| `"base64"` | string: Base64 encoding of the file |
|
||||
| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
|
||||
| `"buffer"` | nodejs Buffer |
|
||||
| `"file"` | string: path of file that will be read (nodejs only) |
|
||||
| (default) | buffer or array of 8-bit unsigned int (byte `n` is `data[n]`) |
|
||||
|
||||
|
||||
### Write Options
|
||||
|
||||
`CFB.write` and `CFB.writeFile` take options argument.
|
||||
|
||||
`opts.type` controls the behavior:
|
||||
|
||||
| `type` | output |
|
||||
|------------|:----------------------------------------------------------------|
|
||||
| `"base64"` | string: Base64 encoding of the file |
|
||||
| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
|
||||
| `"buffer"` | nodejs Buffer |
|
||||
| `"file"` | string: path of file that will be created (nodejs only) |
|
||||
| (default) | buffer if available, array of 8-bit unsigned int otherwise |
|
||||
|
||||
`opts.fileType` controls the output file type:
|
||||
|
||||
| `fileType` | output |
|
||||
|:-------------------|:------------------------|
|
||||
| `'cfb'` (default) | CFB container |
|
||||
| `'zip'` | ZIP file |
|
||||
| `'mad'` | MIME aggregate document |
|
||||
|
||||
`opts.compression` enables DEFLATE compression for ZIP file type.
|
||||
|
||||
|
||||
## Utility Functions
|
||||
|
||||
@ -110,8 +111,15 @@ accept a `name` argument strictly deal with absolute file names:
|
||||
|
||||
- `.cfb_new(?opts)` creates a new container object.
|
||||
- `.cfb_add(cfb, name, ?content, ?opts)` adds a new file to the `cfb`.
|
||||
Set the option `{unsafe:true}` to skip existence checks (for bulk additions)
|
||||
- `.cfb_del(cfb, name)` deletes the specified file
|
||||
- `.cfb_mov(cfb, old_name, new_name)` moves the old file to new path and name
|
||||
- `.use_zlib(require("zlib"))` loads a nodejs `zlib` instance.
|
||||
|
||||
By default, the library uses a pure JS inflate/deflate implementation. NodeJS
|
||||
`zlib.InflateRaw` exposes the number of bytes read in versions after `8.11.0`.
|
||||
If a supplied `zlib` does not support the required features, a warning will be
|
||||
displayed in the console and the pure JS fallback will be used.
|
||||
|
||||
|
||||
## Container Object Description
|
||||
@ -132,6 +140,7 @@ interface CFBEntry {
|
||||
content: Buffer | number[] | Uint8Array; /** Raw Content */
|
||||
ct?: Date; /** Creation Time */
|
||||
mt?: Date; /** Modification Time */
|
||||
ctype?: String; /** Content-Type (for MAD) */
|
||||
}
|
||||
```
|
||||
|
||||
@ -144,11 +153,9 @@ granted by the Apache 2.0 License are reserved by the Original Author.
|
||||
|
||||
## References
|
||||
|
||||
|
||||
<details>
|
||||
<summary><b>OSP-covered Specifications</b> (click to show)</summary>
|
||||
|
||||
- [MS-CFB]: Compound File Binary File Format
|
||||
|
||||
</details>
|
||||
- `MS-CFB`: Compound File Binary File Format
|
||||
- ZIP `APPNOTE.TXT`: .ZIP File Format Specification
|
||||
- RFC1951: https://www.ietf.org/rfc/rfc1951.txt
|
||||
- RFC2045: https://www.ietf.org/rfc/rfc2045.txt
|
||||
- RFC2557: https://www.ietf.org/rfc/rfc2557.txt
|
||||
|
||||
|
128
bin/cfb.njs
128
bin/cfb.njs
@ -1,128 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* vim: set ts=2 ft=javascript: */
|
||||
var n = "cfb";
|
||||
var X = require('../');
|
||||
var fs = require('fs');
|
||||
var program = require('commander');
|
||||
var PRINTJ = require("printj");
|
||||
var sprintf = PRINTJ.sprintf;
|
||||
program
|
||||
.version(X.version)
|
||||
.usage('[options] <file> [subfiles...]')
|
||||
.option('-l, --list-files', 'list files')
|
||||
.option('-r, --repair', 'attempt to repair and garbage-collect archive')
|
||||
.option('-c, --create', 'create file')
|
||||
.option('-a, --append', 'add files to CFB (overwrite existing data)')
|
||||
.option('-d, --delete', 'delete files from CFB')
|
||||
.option('-z, --dump', 'dump internal representation but do not extract')
|
||||
.option('-q, --quiet', 'process but do not report')
|
||||
.option('--dev', 'development mode')
|
||||
.option('--read', 'read but do not print out contents');
|
||||
|
||||
program.parse(process.argv);
|
||||
|
||||
var exit = process.exit;
|
||||
var die = function(errno/*:number*/, msg/*:string*/) { console.error(n + ": " + msg); exit(errno); };
|
||||
var logit = function(cmd/*:string*/, f/*:string*/) { console.error(sprintf("%-6s %s", cmd, f)); };
|
||||
|
||||
if(program.args.length === 0) die(1, "must specify a filename");
|
||||
|
||||
if(program.create) {
|
||||
logit("create", program.args[0]);
|
||||
var newcfb = X.utils.cfb_new();
|
||||
X.writeFile(newcfb, program.args[0]);
|
||||
}
|
||||
|
||||
if(!fs.existsSync(program.args[0])) die(1, "must specify a filename");
|
||||
|
||||
var opts = ({type:'file'}/*:any*/);
|
||||
if(program.dev) opts.WTF = true;
|
||||
|
||||
var cfb = X.read(program.args[0], opts);
|
||||
if(program.quiet) exit(0);
|
||||
|
||||
if(program.dump) {
|
||||
console.log("Full Paths:");
|
||||
console.log(cfb.FullPaths.map(function(x/*:string*/) { return " " + x; }).join("\n"));
|
||||
console.log("File Index:");
|
||||
console.log(cfb.FileIndex);
|
||||
exit(0);
|
||||
}
|
||||
if(program.repair) { X.writeFile(cfb, program.args[0]); exit(0); }
|
||||
|
||||
function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/, function($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
|
||||
var format_date = function(date/*:Date*/)/*:string*/ {
|
||||
return sprintf("%02u-%02u-%02u %02u:%02u", date.getUTCMonth()+1, date.getUTCDate(), date.getUTCFullYear()%100, date.getUTCHours(), date.getUTCMinutes());
|
||||
};
|
||||
|
||||
if(program.listFiles) {
|
||||
var basetime = new Date(1980,0,1);
|
||||
var cnt = 0, rootsize = 0, filesize = 0;
|
||||
console.log(" Length Date Time Name");
|
||||
console.log(" -------- ---- ---- ----");
|
||||
cfb.FileIndex.forEach(function(file/*:CFBEntry*/, i/*:number*/) {
|
||||
switch(file.type) {
|
||||
case 5:
|
||||
basetime = file.ct || file.mt || basetime;
|
||||
rootsize = file.size;
|
||||
break;
|
||||
case 2:
|
||||
console.log(sprintf("%9lu %s %s", file.size, format_date(basetime), fix_string(cfb.FullPaths[i])));
|
||||
filesize += file.size;
|
||||
++cnt;
|
||||
}
|
||||
});
|
||||
console.log(" -------- -------");
|
||||
console.log(sprintf("%9lu %lu file%s", rootsize || filesize, cnt, (cnt !== 1 ? "s" : "")));
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
function mkdirp(path/*:string*/) { path.split("/").reduce(function(acc/*:string*/, p/*:string*/) {
|
||||
acc += p + "/";
|
||||
if(!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); }
|
||||
return acc;
|
||||
}, ""); }
|
||||
|
||||
function write(path/*:string*/, data/*:CFBEntry*/) {
|
||||
logit("write", fix_string(path));
|
||||
fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/ || new Buffer(0));
|
||||
}
|
||||
|
||||
if(program.create || program.append) {
|
||||
program.args.slice(1).forEach(function(x/*:string*/) {
|
||||
logit("append", x);
|
||||
X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x));
|
||||
});
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(program.delete) {
|
||||
program.args.slice(1).forEach(function(x/*:string*/) {
|
||||
logit("delete", x);
|
||||
X.utils.cfb_del(cfb, "/" + x);
|
||||
});
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(program.args.length > 1) {
|
||||
program.args.slice(1).forEach(function(x/*:string*/) {
|
||||
var data/*:?CFBEntry*/ = X.find(cfb, x);
|
||||
if(!data) { console.error(x + ": file not found"); return; }
|
||||
if(data.type !== 2) { console.error(x + ": not a file"); return; }
|
||||
var idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx];
|
||||
mkdirp(path.slice(0, path.lastIndexOf("/")));
|
||||
write(path, data);
|
||||
});
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(var i=0; i!==cfb.FullPaths.length; ++i) {
|
||||
if(!cfb.FileIndex[i].name) continue;
|
||||
if(cfb.FullPaths[i].slice(-1) === "/") mkdirp(cfb.FullPaths[i]);
|
||||
else write(cfb.FullPaths[i], cfb.FileIndex[i]);
|
||||
}
|
@ -2,5 +2,5 @@
|
||||
/* vim: set ts=2: */
|
||||
/*jshint eqnull:true */
|
||||
/*exported CFB */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
|
||||
|
||||
|
@ -1,46 +1,36 @@
|
||||
var Base64 = (function make_b64(){
|
||||
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
return {
|
||||
encode: function(input/*:string*/)/*:string*/ {
|
||||
var o = "";
|
||||
var c1/*:number*/, c2/*:number*/, c3/*:number*/;
|
||||
var e1/*:number*/, e2/*:number*/, e3/*:number*/, e4/*:number*/;
|
||||
for(var i = 0; i < input.length; ) {
|
||||
c1 = input.charCodeAt(i++);
|
||||
e1 = (c1 >> 2);
|
||||
|
||||
c2 = input.charCodeAt(i++);
|
||||
e2 = ((c1 & 3) << 4) | (c2 >> 4);
|
||||
|
||||
c3 = input.charCodeAt(i++);
|
||||
e3 = ((c2 & 15) << 2) | (c3 >> 6);
|
||||
e4 = (c3 & 63);
|
||||
if (isNaN(c2)) { e3 = e4 = 64; }
|
||||
else if (isNaN(c3)) { e4 = 64; }
|
||||
o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
|
||||
}
|
||||
return o;
|
||||
},
|
||||
decode: function b64_decode(input/*:string*/)/*:string*/ {
|
||||
var o = "";
|
||||
var c1/*:number*/, c2/*:number*/, c3/*:number*/;
|
||||
var e1/*:number*/, e2/*:number*/, e3/*:number*/, e4/*:number*/;
|
||||
input = input.replace(/[^\w\+\/\=]/g, "");
|
||||
for(var i = 0; i < input.length;) {
|
||||
e1 = map.indexOf(input.charAt(i++));
|
||||
e2 = map.indexOf(input.charAt(i++));
|
||||
c1 = (e1 << 2) | (e2 >> 4);
|
||||
o += String.fromCharCode(c1);
|
||||
|
||||
e3 = map.indexOf(input.charAt(i++));
|
||||
c2 = ((e2 & 15) << 4) | (e3 >> 2);
|
||||
if (e3 !== 64) { o += String.fromCharCode(c2); }
|
||||
|
||||
e4 = map.indexOf(input.charAt(i++));
|
||||
c3 = ((e3 & 3) << 6) | e4;
|
||||
if (e4 !== 64) { o += String.fromCharCode(c3); }
|
||||
}
|
||||
return o;
|
||||
}
|
||||
};
|
||||
})();
|
||||
var Base64_map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
function Base64_encode(input/*:string*/)/*:string*/ {
|
||||
var o = "";
|
||||
var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;
|
||||
for (var i = 0; i < input.length; ) {
|
||||
c1 = input.charCodeAt(i++);
|
||||
e1 = (c1 >> 2);
|
||||
c2 = input.charCodeAt(i++);
|
||||
e2 = ((c1 & 3) << 4) | (c2 >> 4);
|
||||
c3 = input.charCodeAt(i++);
|
||||
e3 = ((c2 & 15) << 2) | (c3 >> 6);
|
||||
e4 = (c3 & 63);
|
||||
if (isNaN(c2)) e3 = e4 = 64;
|
||||
else if (isNaN(c3)) e4 = 64;
|
||||
o += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function Base64_decode(input/*:string*/)/*:string*/ {
|
||||
var o = "";
|
||||
var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;
|
||||
input = input.replace(/[^\w\+\/\=]/g, "");
|
||||
for (var i = 0; i < input.length;) {
|
||||
e1 = Base64_map.indexOf(input.charAt(i++));
|
||||
e2 = Base64_map.indexOf(input.charAt(i++));
|
||||
c1 = (e1 << 2) | (e2 >> 4);
|
||||
o += String.fromCharCode(c1);
|
||||
e3 = Base64_map.indexOf(input.charAt(i++));
|
||||
c2 = ((e2 & 15) << 4) | (e3 >> 2);
|
||||
if (e3 !== 64) o += String.fromCharCode(c2);
|
||||
e4 = Base64_map.indexOf(input.charAt(i++));
|
||||
c3 = ((e3 & 3) << 6) | e4;
|
||||
if (e4 !== 64) o += String.fromCharCode(c3);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
@ -1,15 +1,35 @@
|
||||
var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && process.versions.node);
|
||||
var has_buf = /*#__PURE__*/(function() { return typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node; })();
|
||||
|
||||
var Buffer_from = /*#__PURE__*/(function() {
|
||||
if(typeof Buffer !== 'undefined') {
|
||||
var nbfs = !Buffer.from;
|
||||
if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
|
||||
return nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
|
||||
}
|
||||
return function() {};
|
||||
})();
|
||||
|
||||
|
||||
function new_raw_buf(len/*:number*/) {
|
||||
/* jshint -W056 */
|
||||
// $FlowIgnore
|
||||
return new (has_buf ? Buffer : Array)(len);
|
||||
if(has_buf) {
|
||||
if(Buffer.alloc) return Buffer.alloc(len);
|
||||
var b = new Buffer(len); b.fill(0); return b;
|
||||
}
|
||||
return typeof Uint8Array != "undefined" ? new Uint8Array(len) : new Array(len);
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
var s2a = function s2a(s/*:string*/) {
|
||||
if(has_buf) return new Buffer(s, "binary");
|
||||
return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
|
||||
function new_unsafe_buf(len/*:number*/) {
|
||||
/* jshint -W056 */
|
||||
if(has_buf) return Buffer.allocUnsafe ? Buffer.allocUnsafe(len) : new Buffer(len);
|
||||
return typeof Uint8Array != "undefined" ? new Uint8Array(len) : new Array(len);
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
var s2a = function s2a(s/*:string*/)/*:RawBytes*/ {
|
||||
if(has_buf) return Buffer_from(s, "binary");
|
||||
return s.split("").map(function(x/*:string*/)/*:number*/{ return x.charCodeAt(0) & 0xff; });
|
||||
};
|
||||
|
||||
var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/;
|
||||
var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g;
|
||||
|
@ -22,7 +22,7 @@ if(has_buf/*:: && typeof Buffer !== 'undefined'*/) {
|
||||
};
|
||||
__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); };
|
||||
__toBuffer = function(bufs/*:Array<Array<RawBytes>>*/)/*:RawBytes*/ { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat((bufs[0]/*:any*/)) : ___toBuffer(bufs);};
|
||||
s2a = function(s/*:string*/)/*:RawBytes*/ { return new Buffer(s, "binary"); };
|
||||
s2a = function(s/*:string*/)/*:RawBytes*/ { return Buffer_from(s, "binary"); };
|
||||
bconcat = function(bufs/*:Array<RawBytes>*/)/*:RawBytes*/ { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(/*::(*/bufs/*:: :any)*/) : __bconcat(bufs); };
|
||||
}
|
||||
|
||||
|
97
bits/21_crc32.js
Normal file
97
bits/21_crc32.js
Normal file
@ -0,0 +1,97 @@
|
||||
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
var CRC32 = /*#__PURE__*/(function() {
|
||||
var CRC32 = {};
|
||||
CRC32.version = '1.2.1';
|
||||
/*::
|
||||
type ABuf = Array<number> | Buffer | Uint8Array;
|
||||
type CRC32TableType = Array<number> | Int32Array;
|
||||
*/
|
||||
/*global Int32Array */
|
||||
function signed_crc_table()/*:CRC32TableType*/ {
|
||||
var c = 0, table/*:Array<number>*/ = new Array(256);
|
||||
|
||||
for(var n =0; n != 256; ++n){
|
||||
c = n;
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
|
||||
}
|
||||
|
||||
var T0 = signed_crc_table();
|
||||
function slice_by_16_tables(T) {
|
||||
var c = 0, v = 0, n = 0, table/*:Array<number>*/ = typeof Int32Array !== 'undefined' ? new Int32Array(4096) : new Array(4096) ;
|
||||
|
||||
for(n = 0; n != 256; ++n) table[n] = T[n];
|
||||
for(n = 0; n != 256; ++n) {
|
||||
v = T[n];
|
||||
for(c = 256 + n; c < 4096; c += 256) v = table[c] = (v >>> 8) ^ T[v & 0xFF];
|
||||
}
|
||||
var out = [];
|
||||
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);
|
||||
return out;
|
||||
}
|
||||
var TT = slice_by_16_tables(T0);
|
||||
var T1 = TT[0], T2 = TT[1], T3 = TT[2], T4 = TT[3], T5 = TT[4];
|
||||
var T6 = TT[5], T7 = TT[6], T8 = TT[7], T9 = TT[8], Ta = TT[9];
|
||||
var Tb = TT[10], Tc = TT[11], Td = TT[12], Te = TT[13], Tf = TT[14];
|
||||
function crc32_bstr(bstr/*:string*/, seed/*:?number*/)/*:number*/ {
|
||||
var C = seed/*:: ? 0 : 0 */ ^ -1;
|
||||
for(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
return ~C;
|
||||
}
|
||||
|
||||
function crc32_buf(B/*:ABuf*/, seed/*:?number*/)/*:number*/ {
|
||||
var C = seed/*:: ? 0 : 0 */ ^ -1, L = B.length - 15, i = 0;
|
||||
for(; i < L;) C =
|
||||
Tf[B[i++] ^ (C & 255)] ^
|
||||
Te[B[i++] ^ ((C >> 8) & 255)] ^
|
||||
Td[B[i++] ^ ((C >> 16) & 255)] ^
|
||||
Tc[B[i++] ^ (C >>> 24)] ^
|
||||
Tb[B[i++]] ^ Ta[B[i++]] ^ T9[B[i++]] ^ T8[B[i++]] ^
|
||||
T7[B[i++]] ^ T6[B[i++]] ^ T5[B[i++]] ^ T4[B[i++]] ^
|
||||
T3[B[i++]] ^ T2[B[i++]] ^ T1[B[i++]] ^ T0[B[i++]];
|
||||
L += 15;
|
||||
while(i < L) C = (C>>>8) ^ T0[(C^B[i++])&0xFF];
|
||||
return ~C;
|
||||
}
|
||||
|
||||
function crc32_str(str/*:string*/, seed/*:?number*/)/*:number*/ {
|
||||
var C = seed/*:: ? 0 : 0 */ ^ -1;
|
||||
for(var i = 0, L = str.length, c = 0, d = 0; i < L;) {
|
||||
c = str.charCodeAt(i++);
|
||||
if(c < 0x80) {
|
||||
C = (C>>>8) ^ T0[(C^c)&0xFF];
|
||||
} else if(c < 0x800) {
|
||||
C = (C>>>8) ^ T0[(C ^ (192|((c>>6)&31)))&0xFF];
|
||||
C = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF];
|
||||
} else if(c >= 0xD800 && c < 0xE000) {
|
||||
c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
|
||||
C = (C>>>8) ^ T0[(C ^ (240|((c>>8)&7)))&0xFF];
|
||||
C = (C>>>8) ^ T0[(C ^ (128|((c>>2)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T0[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
|
||||
C = (C>>>8) ^ T0[(C ^ (128|(d&63)))&0xFF];
|
||||
} else {
|
||||
C = (C>>>8) ^ T0[(C ^ (224|((c>>12)&15)))&0xFF];
|
||||
C = (C>>>8) ^ T0[(C ^ (128|((c>>6)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T0[(C ^ (128|(c&63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return ~C;
|
||||
}
|
||||
CRC32.table = T0;
|
||||
CRC32.bstr = crc32_bstr;
|
||||
CRC32.buf = crc32_buf;
|
||||
CRC32.str = crc32_str;
|
||||
return CRC32;
|
||||
})();
|
@ -1,3 +1,3 @@
|
||||
/* [MS-CFB] v20130118 */
|
||||
var CFB = (function _CFB(){
|
||||
/* [MS-CFB] v20171201 */
|
||||
var CFB = /*#__PURE__*/(function _CFB(){
|
||||
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
|
||||
|
@ -1 +1 @@
|
||||
exports.version = '0.14.0';
|
||||
exports.version = '1.2.2';
|
||||
|
38
bits/37_dosdates.js
Normal file
38
bits/37_dosdates.js
Normal file
@ -0,0 +1,38 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* DOS Date format:
|
||||
high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
|
||||
add 1980 to stored year
|
||||
stored second should be doubled
|
||||
*/
|
||||
|
||||
/* write JS date to buf as a DOS date */
|
||||
function write_dos_date(buf/*:CFBlob*/, date/*:Date|string*/) {
|
||||
if(typeof date === "string") date = new Date(date);
|
||||
var hms/*:number*/ = date.getHours();
|
||||
hms = hms << 6 | date.getMinutes();
|
||||
hms = hms << 5 | (date.getSeconds()>>>1);
|
||||
buf.write_shift(2, hms);
|
||||
var ymd/*:number*/ = (date.getFullYear() - 1980);
|
||||
ymd = ymd << 4 | (date.getMonth()+1);
|
||||
ymd = ymd << 5 | date.getDate();
|
||||
buf.write_shift(2, ymd);
|
||||
}
|
||||
|
||||
/* read four bytes from buf and interpret as a DOS date */
|
||||
function parse_dos_date(buf/*:CFBlob*/)/*:Date*/ {
|
||||
var hms = buf.read_shift(2) & 0xFFFF;
|
||||
var ymd = buf.read_shift(2) & 0xFFFF;
|
||||
var val = new Date();
|
||||
var d = ymd & 0x1F; ymd >>>= 5;
|
||||
var m = ymd & 0x0F; ymd >>>= 4;
|
||||
val.setMilliseconds(0);
|
||||
val.setFullYear(ymd + 1980);
|
||||
val.setMonth(m-1);
|
||||
val.setDate(d);
|
||||
var S = hms & 0x1F; hms >>>= 5;
|
||||
var M = hms & 0x3F; hms >>>= 6;
|
||||
val.setHours(hms);
|
||||
val.setMinutes(M);
|
||||
val.setSeconds(S<<1);
|
||||
return val;
|
||||
}
|
27
bits/38_extrafield.js
Normal file
27
bits/38_extrafield.js
Normal file
@ -0,0 +1,27 @@
|
||||
function parse_extra_field(blob/*:CFBlob*/)/*:any*/ {
|
||||
prep_blob(blob, 0);
|
||||
var o = /*::(*/{}/*:: :any)*/;
|
||||
var flags = 0;
|
||||
while(blob.l <= blob.length - 4) {
|
||||
var type = blob.read_shift(2);
|
||||
var sz = blob.read_shift(2), tgt = blob.l + sz;
|
||||
var p = {};
|
||||
switch(type) {
|
||||
/* UNIX-style Timestamps */
|
||||
case 0x5455: {
|
||||
flags = blob.read_shift(1);
|
||||
if(flags & 1) p.mtime = blob.read_shift(4);
|
||||
/* for some reason, CD flag corresponds to LFH */
|
||||
if(sz > 5) {
|
||||
if(flags & 2) p.atime = blob.read_shift(4);
|
||||
if(flags & 4) p.ctime = blob.read_shift(4);
|
||||
}
|
||||
if(p.mtime) p.mt = new Date(p.mtime*1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
blob.l = tgt;
|
||||
o[type] = p;
|
||||
}
|
||||
return o;
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if((file[0] | 0x20) == 0x6d && (file[1]|0x20) == 0x69) return parse_mad(file, options);
|
||||
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
var nmfs = 0; // number of mini FAT sectors
|
||||
@ -18,6 +21,8 @@ var mv = check_get_mver(blob);
|
||||
mver = mv[0];
|
||||
switch(mver) {
|
||||
case 3: ssz = 512; break; case 4: ssz = 4096; break;
|
||||
case 0: if(mv[1] == 0) return parse_zip(file, options);
|
||||
/* falls through */
|
||||
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
|
||||
}
|
||||
|
||||
@ -79,7 +84,7 @@ sector_list.ssz = ssz;
|
||||
|
||||
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
|
||||
var files/*:CFBFiles*/ = {}, Paths/*:Array<string>*/ = [], FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
|
||||
read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex);
|
||||
read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);
|
||||
|
||||
build_full_paths(FileIndex, FullPaths, Paths);
|
||||
Paths.shift();
|
||||
|
@ -1,10 +1,12 @@
|
||||
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
|
||||
function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
|
||||
if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
|
||||
// header signature 8
|
||||
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
|
||||
|
||||
// clsid 16
|
||||
blob.chk(HEADER_CLSID, 'CLSID: ');
|
||||
//blob.chk(HEADER_CLSID, 'CLSID: ');
|
||||
blob.l += 16;
|
||||
|
||||
// minor version 2
|
||||
var mver/*:number*/ = blob.read_shift(2, 'u');
|
||||
|
@ -13,23 +13,22 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
|
||||
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
|
||||
}
|
||||
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
|
||||
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
|
||||
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
|
||||
if(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
|
||||
if(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
|
||||
}
|
||||
for(i=1; i !== pl; ++i) if(dad[i] === i) {
|
||||
for(i=1; i < pl; ++i) if(dad[i] === i) {
|
||||
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
|
||||
else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
|
||||
}
|
||||
|
||||
for(i=1; i < pl; ++i) {
|
||||
if(FI[i].type === 0 /* unknown */) continue;
|
||||
j = dad[i];
|
||||
if(j === 0) FP[i] = FP[0] + "/" + FP[i];
|
||||
else while(j !== 0 && j !== dad[j]) {
|
||||
FP[i] = FP[j] + "/" + FP[i];
|
||||
j = i;
|
||||
if(j != dad[j]) do {
|
||||
j = dad[j];
|
||||
}
|
||||
dad[i] = 0;
|
||||
FP[i] = FP[j] + "/" + FP[i];
|
||||
} while (j !== 0 && -1 !== dad[j] && j != dad[j]);
|
||||
dad[i] = -1;
|
||||
}
|
||||
|
||||
FP[0] += "/";
|
||||
|
14
bits/44_readmfat.js
Normal file
14
bits/44_readmfat.js
Normal file
@ -0,0 +1,14 @@
|
||||
function get_mfat_entry(entry/*:CFBEntry*/, payload/*:RawBytes*/, mini/*:?RawBytes*/)/*:CFBlob*/ {
|
||||
var start = entry.start, size = entry.size;
|
||||
//return (payload.slice(start*MSSZ, start*MSSZ + size)/*:any*/);
|
||||
var o = [];
|
||||
var idx = start;
|
||||
while(mini && size > 0 && idx >= 0) {
|
||||
o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));
|
||||
size -= MSSZ;
|
||||
idx = __readInt32LE(mini, idx * 4);
|
||||
}
|
||||
if(o.length === 0) return (new_buf(0)/*:any*/);
|
||||
return (bconcat(o).slice(0, entry.size)/*:any*/);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array<RawBytes>*/,
|
||||
if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;
|
||||
fat_addrs.push(q);
|
||||
}
|
||||
sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
|
||||
if(cnt >= 1) sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,9 @@ function make_sector_list(sectors/*:Array<RawBytes>*/, dir_start/*:number*/, fat
|
||||
k = (i + dir_start); if(k >= sl) k-=sl;
|
||||
if(chkd[k]) continue;
|
||||
buf_chain = [];
|
||||
var seen = [];
|
||||
for(j=k; j>=0;) {
|
||||
seen[j] = true;
|
||||
chkd[j] = true;
|
||||
buf[buf.length] = j;
|
||||
buf_chain.push(sectors[j]);
|
||||
@ -52,6 +54,7 @@ function make_sector_list(sectors/*:Array<RawBytes>*/, dir_start/*:number*/, fat
|
||||
if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
|
||||
if(!sectors[addr]) break;
|
||||
j = __readInt32LE(sectors[addr], jj);
|
||||
if(seen[j]) break;
|
||||
}
|
||||
sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])}/*:SectorEntry*/);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
|
||||
function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sectors/*:Array<RawBytes>*/, Paths/*:Array<string>*/, nmfs, files, FileIndex) {
|
||||
function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sectors/*:Array<RawBytes>*/, Paths/*:Array<string>*/, nmfs, files, FileIndex, mini) {
|
||||
var minifat_store = 0, pl = (Paths.length?2:0);
|
||||
var sector = sector_list[dir_start].data;
|
||||
var i = 0, namelen = 0, name;
|
||||
@ -37,14 +37,14 @@ function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sector
|
||||
if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
|
||||
sector_list[o.start].name = o.name;
|
||||
o.content = (sector_list[o.start].data.slice(0,o.size)/*:any*/);
|
||||
prep_blob(o.content, 0);
|
||||
} else {
|
||||
o.storage = 'minifat';
|
||||
if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
|
||||
o.content = (sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size)/*:any*/);
|
||||
prep_blob(o.content, 0);
|
||||
if(o.size < 0) o.size = 0;
|
||||
else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
|
||||
o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
|
||||
}
|
||||
}
|
||||
if(o.content) prep_blob(o.content, 0);
|
||||
files[name] = o;
|
||||
FileIndex.push(o);
|
||||
}
|
||||
|
@ -4,9 +4,13 @@ function read_file(filename/*:string*/, options/*:CFBReadOpts*/) {
|
||||
}
|
||||
|
||||
function read(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) {
|
||||
switch(options && options.type || "base64") {
|
||||
var type = options && options.type;
|
||||
if(!type) {
|
||||
if(has_buf && Buffer.isBuffer(blob)) type = "buffer";
|
||||
}
|
||||
switch(type || "base64") {
|
||||
case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return read_file(blob, options);
|
||||
case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64.decode(blob)), options);
|
||||
case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64_decode(blob)), options);
|
||||
case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options);
|
||||
}
|
||||
return parse(/*::typeof blob == 'string' ? new Buffer(blob, 'utf-8') : */blob, options);
|
||||
|
@ -1,19 +1,31 @@
|
||||
var now = new Date(1987, 1, 19), j = 0;
|
||||
// Track which names exist
|
||||
var fullPaths = Object.create ? Object.create(null) : {};
|
||||
var data/*:Array<[string, CFBEntry]>*/ = [];
|
||||
for(i = 0; i < cfb.FullPaths.length; ++i) {
|
||||
fullPaths[cfb.FullPaths[i]] = true;
|
||||
if(cfb.FileIndex[i].type === 0) continue;
|
||||
data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
|
||||
}
|
||||
for(i = 0; i < data.length; ++i) {
|
||||
var dad = dirname(data[i][0]);
|
||||
s = false;
|
||||
for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
|
||||
if(!s) data.push([dad, ({
|
||||
name: filename(dad).replace("/",""),
|
||||
type: 1,
|
||||
clsid: HEADER_CLSID,
|
||||
ct: now, mt: now,
|
||||
content: null
|
||||
}/*:any*/)]);
|
||||
s = fullPaths[dad];
|
||||
while(!s) {
|
||||
while(dirname(dad) && !fullPaths[dirname(dad)]) dad = dirname(dad);
|
||||
|
||||
data.push([dad, ({
|
||||
name: filename(dad).replace("/",""),
|
||||
type: 1,
|
||||
clsid: HEADER_CLSID,
|
||||
ct: now, mt: now,
|
||||
content: null
|
||||
}/*:any*/)]);
|
||||
|
||||
// Add name to set
|
||||
fullPaths[dad] = true;
|
||||
|
||||
dad = dirname(data[i][0]);
|
||||
s = fullPaths[dad];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,9 @@
|
||||
function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
|
||||
var _opts = options || {};
|
||||
/* MAD is order-sensitive, skip rebuild and sort */
|
||||
if(_opts.fileType == 'mad') return write_mad(cfb, _opts);
|
||||
rebuild_cfb(cfb);
|
||||
switch(_opts.fileType) {
|
||||
case 'zip': return write_zip(cfb, _opts);
|
||||
//case 'mad': return write_mad(cfb, _opts);
|
||||
}
|
||||
|
@ -3,11 +3,11 @@
|
||||
for(var i = 0; i < cfb.FileIndex.length; ++i) {
|
||||
var file = cfb.FileIndex[i];
|
||||
if(!file.content) continue;
|
||||
/*:: if(file.content == null) throw new Error("unreachable"); */
|
||||
var flen = file.content.length;
|
||||
if(flen === 0){}
|
||||
else if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
|
||||
else fat_size += (flen + 0x01FF) >> 9;
|
||||
if(flen > 0){
|
||||
if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
|
||||
else fat_size += (flen + 0x01FF) >> 9;
|
||||
}
|
||||
}
|
||||
var dir_cnt = (cfb.FullPaths.length +3) >> 2;
|
||||
var mini_cnt = (mini_size + 7) >> 3;
|
||||
|
@ -8,8 +8,13 @@
|
||||
}
|
||||
file = cfb.FileIndex[i];
|
||||
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
|
||||
flen = 2*(file.name.length+1);
|
||||
o.write_shift(64, file.name, "utf16le");
|
||||
var _nm/*:string*/ = (i === 0 && _opts.root) || file.name;
|
||||
if(_nm.length > 31) {
|
||||
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,31));
|
||||
_nm = _nm.slice(0, 31);
|
||||
}
|
||||
flen = 2*(_nm.length+1);
|
||||
o.write_shift(64, _nm, "utf16le");
|
||||
o.write_shift(2, flen);
|
||||
o.write_shift(1, file.type);
|
||||
o.write_shift(1, file.color);
|
||||
|
@ -3,7 +3,13 @@
|
||||
/*:: if(!file.content) throw new Error("unreachable"); */
|
||||
if(file.size >= 0x1000) {
|
||||
o.l = (file.start+1) << 9;
|
||||
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
|
||||
for(; j & 0x1FF; ++j) o.write_shift(1, 0);
|
||||
if (has_buf && Buffer.isBuffer(file.content)) {
|
||||
file.content.copy(o, o.l, 0, file.size);
|
||||
// o is a 0-filled Buffer so just set next offset
|
||||
o.l += (file.size + 511) & -512;
|
||||
} else {
|
||||
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
|
||||
for(; j & 0x1FF; ++j) o.write_shift(1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,19 @@
|
||||
file = cfb.FileIndex[i];
|
||||
/*:: if(!file.content) throw new Error("unreachable"); */
|
||||
if(file.size > 0 && file.size < 0x1000) {
|
||||
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
|
||||
for(; j & 0x3F; ++j) o.write_shift(1, 0);
|
||||
if (has_buf && Buffer.isBuffer(file.content)) {
|
||||
file.content.copy(o, o.l, 0, file.size);
|
||||
// o is a 0-filled Buffer so just set next offset
|
||||
o.l += (file.size + 63) & -64;
|
||||
} else {
|
||||
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
|
||||
for(; j & 0x3F; ++j) o.write_shift(1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
while(o.l < o.length) o.write_shift(1, 0);
|
||||
if (has_buf) {
|
||||
o.l = o.length;
|
||||
} else {
|
||||
// When using Buffer, already 0-filled
|
||||
while(o.l < o.length) o.write_shift(1, 0);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
|
||||
function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ {
|
||||
//return cfb.find(path);
|
||||
var UCFullPaths/*:Array<string>*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
|
||||
var UCPaths/*:Array<string>*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
|
||||
var k/*:boolean*/ = false;
|
||||
@ -10,10 +9,12 @@ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ {
|
||||
var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
|
||||
if(w !== -1) return cfb.FileIndex[w];
|
||||
|
||||
UCPath = UCPath.replace(chr0,'').replace(chr1,'!');
|
||||
var m = !UCPath.match(chr1);
|
||||
UCPath = UCPath.replace(chr0,'');
|
||||
if(m) UCPath = UCPath.replace(chr1,'!');
|
||||
for(w = 0; w < UCFullPaths.length; ++w) {
|
||||
if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w];
|
||||
if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w];
|
||||
if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
|
||||
if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -13,10 +13,13 @@ function a2s(o/*:RawBytes*/)/*:string*/ {
|
||||
|
||||
function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
|
||||
var o = _write(cfb, options);
|
||||
switch(options && options.type) {
|
||||
switch(options && options.type || "buffer") {
|
||||
case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "binary": return a2s(o);
|
||||
case "base64": return Base64.encode(a2s(o));
|
||||
case "binary": return typeof o == "string" ? o : a2s(o);
|
||||
case "base64": return Base64_encode(typeof o == "string" ? o : a2s(o));
|
||||
case "buffer": if(has_buf) return Buffer.isBuffer(o) ? o : Buffer_from(o);
|
||||
/* falls through */
|
||||
case "array": return typeof o == "string" ? s2a(o) : o;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
22
bits/78_zlib.js
Normal file
22
bits/78_zlib.js
Normal file
@ -0,0 +1,22 @@
|
||||
/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
|
||||
var _zlib;
|
||||
function use_zlib(zlib) { try {
|
||||
var InflateRaw = zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
|
||||
if(InflRaw.bytesRead) _zlib = zlib;
|
||||
else throw new Error("zlib does not expose bytesRead");
|
||||
} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
|
||||
|
||||
function _inflateRawSync(payload, usz) {
|
||||
if(!_zlib) return _inflate(payload, usz);
|
||||
var InflateRaw = _zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
|
||||
payload.l += InflRaw.bytesRead;
|
||||
return out;
|
||||
}
|
||||
|
||||
function _deflateRawSync(payload) {
|
||||
return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
|
||||
}
|
162
bits/79_flate.js
Normal file
162
bits/79_flate.js
Normal file
@ -0,0 +1,162 @@
|
||||
var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
||||
|
||||
/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
|
||||
var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
|
||||
|
||||
/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
|
||||
var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
|
||||
|
||||
function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
|
||||
|
||||
var use_typed_arrays = typeof Uint8Array !== 'undefined';
|
||||
|
||||
var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
|
||||
for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
|
||||
|
||||
function bit_swap_n(n, b) {
|
||||
var rev = bitswap8[n & 0xFF];
|
||||
if(b <= 8) return rev >>> (8-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
|
||||
if(b <= 16) return rev >>> (16-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
|
||||
return rev >>> (24-b);
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit reads */
|
||||
function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
|
||||
function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
|
||||
function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
|
||||
function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
|
||||
function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
|
||||
|
||||
/* works up to n = 3 * 8 + 1 = 25 */
|
||||
function read_bits_n(buf, bl, n) {
|
||||
var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
|
||||
var v = buf[h] >>> w;
|
||||
if(n < 8 - w) return v & f;
|
||||
v |= buf[h+1]<<(8-w);
|
||||
if(n < 16 - w) return v & f;
|
||||
v |= buf[h+2]<<(16-w);
|
||||
if(n < 24 - w) return v & f;
|
||||
v |= buf[h+3]<<(24-w);
|
||||
return v & f;
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit writes */
|
||||
function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;
|
||||
if(w <= 5) buf[h] |= (v & 7) << w;
|
||||
else {
|
||||
buf[h] |= (v << w) & 0xFF;
|
||||
buf[h+1] = (v&7) >> (8-w);
|
||||
}
|
||||
return bl + 3;
|
||||
}
|
||||
|
||||
function write_bits_1(buf, bl, v) {
|
||||
var w = bl & 7, h = bl >>> 3;
|
||||
v = (v&1) << w;
|
||||
buf[h] |= v;
|
||||
return bl + 1;
|
||||
}
|
||||
function write_bits_8(buf, bl, v) {
|
||||
var w = bl & 7, h = bl >>> 3;
|
||||
v <<= w;
|
||||
buf[h] |= v & 0xFF; v >>>= 8;
|
||||
buf[h+1] = v;
|
||||
return bl + 8;
|
||||
}
|
||||
function write_bits_16(buf, bl, v) {
|
||||
var w = bl & 7, h = bl >>> 3;
|
||||
v <<= w;
|
||||
buf[h] |= v & 0xFF; v >>>= 8;
|
||||
buf[h+1] = v & 0xFF;
|
||||
buf[h+2] = v >>> 8;
|
||||
return bl + 16;
|
||||
}
|
||||
|
||||
/* until ArrayBuffer#realloc is a thing, fake a realloc */
|
||||
function realloc(b, sz/*:number*/) {
|
||||
var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
|
||||
if(L >= sz) return b;
|
||||
if(has_buf) {
|
||||
var o = new_unsafe_buf(M);
|
||||
// $FlowIgnore
|
||||
if(b.copy) b.copy(o);
|
||||
else for(; i < b.length; ++i) o[i] = b[i];
|
||||
return o;
|
||||
} else if(use_typed_arrays) {
|
||||
var a = new Uint8Array(M);
|
||||
if(a.set) a.set(b);
|
||||
else for(; i < L; ++i) a[i] = b[i];
|
||||
return a;
|
||||
}
|
||||
b.length = M;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* zero-filled arrays for older browsers */
|
||||
function zero_fill_array(n) {
|
||||
var o = new Array(n);
|
||||
for(var i = 0; i < n; ++i) o[i] = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
/* build tree (used for literals and lengths) */
|
||||
function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
|
||||
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
||||
|
||||
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
||||
|
||||
for(i = L; i < MAX; ++i) clens[i] = 0;
|
||||
L = clens.length;
|
||||
|
||||
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
||||
|
||||
/* build code tree */
|
||||
for(i = 0; i < L; ++i) {
|
||||
bl_count[(w = clens[i])]++;
|
||||
if(maxlen < w) maxlen = w;
|
||||
ctree[i] = 0;
|
||||
}
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
||||
for(i = 0; i < L; ++i) {
|
||||
ccode = clens[i];
|
||||
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
||||
}
|
||||
|
||||
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
||||
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
||||
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
/* Fixed Huffman */
|
||||
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
||||
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
if(!use_typed_arrays) {
|
||||
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
||||
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
||||
}
|
||||
(function() {
|
||||
var dlens/*:Array<number>*/ = [];
|
||||
var i = 0;
|
||||
for(;i<32; i++) dlens.push(5);
|
||||
build_tree(dlens, fix_dmap, 32);
|
||||
|
||||
var clens/*:Array<number>*/ = [];
|
||||
i = 0;
|
||||
for(; i<=143; i++) clens.push(8);
|
||||
for(; i<=255; i++) clens.push(9);
|
||||
for(; i<=279; i++) clens.push(7);
|
||||
for(; i<=287; i++) clens.push(8);
|
||||
build_tree(clens, fix_lmap, 288);
|
||||
})();
|
117
bits/80_deflate.js
Normal file
117
bits/80_deflate.js
Normal file
@ -0,0 +1,117 @@
|
||||
var _deflateRaw = /*#__PURE__*/(function _deflateRawIIFE() {
|
||||
var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];
|
||||
var j = 0, k = 0;
|
||||
for(; j < DST_LN.length - 1; ++j) {
|
||||
for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;
|
||||
}
|
||||
for(;k < 32768; ++k) DST_LN_RE[k] = 29;
|
||||
|
||||
var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];
|
||||
for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {
|
||||
for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;
|
||||
}
|
||||
|
||||
function write_stored(data, out) {
|
||||
var boff = 0;
|
||||
while(boff < data.length) {
|
||||
var L = Math.min(0xFFFF, data.length - boff);
|
||||
var h = boff + L == data.length;
|
||||
out.write_shift(1, +h);
|
||||
out.write_shift(2, L);
|
||||
out.write_shift(2, (~L) & 0xFFFF);
|
||||
while(L-- > 0) out[out.l++] = data[boff++];
|
||||
}
|
||||
return out.l;
|
||||
}
|
||||
|
||||
/* Fixed Huffman */
|
||||
function write_huff_fixed(data, out) {
|
||||
var bl = 0;
|
||||
var boff = 0;
|
||||
var addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];
|
||||
while(boff < data.length) {
|
||||
var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);
|
||||
|
||||
/* write a stored block for short data */
|
||||
if(L < 10) {
|
||||
bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line
|
||||
if(bl & 7) bl += 8 - (bl & 7);
|
||||
out.l = (bl / 8) | 0;
|
||||
out.write_shift(2, L);
|
||||
out.write_shift(2, (~L) & 0xFFFF);
|
||||
while(L-- > 0) out[out.l++] = data[boff++];
|
||||
bl = out.l * 8;
|
||||
continue;
|
||||
}
|
||||
|
||||
bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line
|
||||
var hash = 0;
|
||||
while(L-- > 0) {
|
||||
var d = data[boff];
|
||||
hash = ((hash << 5) ^ d) & 0x7FFF;
|
||||
|
||||
var match = -1, mlen = 0;
|
||||
|
||||
if((match = addrs[hash])) {
|
||||
match |= boff & ~0x7FFF;
|
||||
if(match > boff) match -= 0x8000;
|
||||
if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;
|
||||
}
|
||||
|
||||
if(mlen > 2) {
|
||||
/* Copy Token */
|
||||
d = LEN_LN_RE[mlen];
|
||||
if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;
|
||||
else {
|
||||
write_bits_8(out, bl, 3);
|
||||
bl += 5;
|
||||
write_bits_8(out, bl, bitswap8[d-23]>>5);
|
||||
bl += 3;
|
||||
}
|
||||
var len_eb = (d < 8) ? 0 : ((d - 4)>>2);
|
||||
if(len_eb > 0) {
|
||||
write_bits_16(out, bl, mlen - LEN_LN[d]);
|
||||
bl += len_eb;
|
||||
}
|
||||
|
||||
d = DST_LN_RE[boff - match];
|
||||
bl = write_bits_8(out, bl, bitswap8[d]>>3);
|
||||
bl -= 3;
|
||||
|
||||
var dst_eb = d < 4 ? 0 : (d-2)>>1;
|
||||
if(dst_eb > 0) {
|
||||
write_bits_16(out, bl, boff - match - DST_LN[d]);
|
||||
bl += dst_eb;
|
||||
}
|
||||
for(var q = 0; q < mlen; ++q) {
|
||||
addrs[hash] = boff & 0x7FFF;
|
||||
hash = ((hash << 5) ^ data[boff]) & 0x7FFF;
|
||||
++boff;
|
||||
}
|
||||
L-= mlen - 1;
|
||||
} else {
|
||||
/* Literal Token */
|
||||
if(d <= 143) d = d + 48;
|
||||
else bl = write_bits_1(out, bl, 1);
|
||||
bl = write_bits_8(out, bl, bitswap8[d]);
|
||||
addrs[hash] = boff & 0x7FFF;
|
||||
++boff;
|
||||
}
|
||||
}
|
||||
|
||||
bl = write_bits_8(out, bl, 0) - 1;
|
||||
}
|
||||
out.l = ((bl + 7)/8)|0;
|
||||
return out.l;
|
||||
}
|
||||
return function _deflateRaw(data, out) {
|
||||
if(data.length < 8) return write_stored(data, out);
|
||||
return write_huff_fixed(data, out);
|
||||
};
|
||||
})();
|
||||
|
||||
function _deflate(data) {
|
||||
var buf = new_buf(50+Math.floor(data.length*1.1));
|
||||
var off = _deflateRaw(data, buf);
|
||||
return buf.slice(0, off);
|
||||
}
|
166
bits/81_inflate.js
Normal file
166
bits/81_inflate.js
Normal file
@ -0,0 +1,166 @@
|
||||
/* modified inflate function also moves original read head */
|
||||
|
||||
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
||||
var dyn_len_1 = 1, dyn_len_2 = 1;
|
||||
|
||||
/* 5.5.3 Expanding Huffman Codes */
|
||||
function dyn(data, boff/*:number*/) {
|
||||
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
||||
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
||||
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
||||
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
||||
var w = 0;
|
||||
|
||||
/* grab and store code lengths */
|
||||
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
||||
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var maxlen = 1;
|
||||
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var L = clens.length; /* 19 */
|
||||
for(var i = 0; i < _HCLEN; ++i) {
|
||||
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
||||
if(maxlen < w) maxlen = w;
|
||||
bl_count[w]++;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* build code tree */
|
||||
var ccode = 0;
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
||||
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
||||
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
||||
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
||||
}
|
||||
}
|
||||
|
||||
/* read literal and dist codes at once */
|
||||
var hcodes/*:Array<number>*/ = [];
|
||||
maxlen = 1;
|
||||
for(; hcodes.length < _HLIT + _HDIST;) {
|
||||
ccode = dyn_cmap[read_bits_7(data, boff)];
|
||||
boff += ccode & 7;
|
||||
switch((ccode >>>= 3)) {
|
||||
case 16:
|
||||
w = 3 + read_bits_2(data, boff); boff += 2;
|
||||
ccode = hcodes[hcodes.length - 1];
|
||||
while(w-- > 0) hcodes.push(ccode);
|
||||
break;
|
||||
case 17:
|
||||
w = 3 + read_bits_3(data, boff); boff += 3;
|
||||
while(w-- > 0) hcodes.push(0);
|
||||
break;
|
||||
case 18:
|
||||
w = 11 + read_bits_7(data, boff); boff += 7;
|
||||
while(w -- > 0) hcodes.push(0);
|
||||
break;
|
||||
default:
|
||||
hcodes.push(ccode);
|
||||
if(maxlen < ccode) maxlen = ccode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build literal / length trees */
|
||||
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
||||
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
||||
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
||||
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
||||
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
||||
return boff;
|
||||
}
|
||||
|
||||
/* return [ data, bytesRead ] */
|
||||
function inflate(data, usz/*:number*/) {
|
||||
/* shortcircuit for empty buffer [0x03, 0x00] */
|
||||
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
||||
|
||||
/* bit offset */
|
||||
var boff = 0;
|
||||
|
||||
/* header includes final bit and type bits */
|
||||
var header = 0;
|
||||
|
||||
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
||||
var woff = 0;
|
||||
var OL = outbuf.length>>>0;
|
||||
var max_len_1 = 0, max_len_2 = 0;
|
||||
|
||||
while((header&1) == 0) {
|
||||
header = read_bits_3(data, boff); boff += 3;
|
||||
if((header >>> 1) == 0) {
|
||||
/* Stored block */
|
||||
if(boff & 7) boff += 8 - (boff&7);
|
||||
/* 2 bytes sz, 2 bytes bit inverse */
|
||||
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
||||
boff += 32;
|
||||
/* push sz bytes */
|
||||
if(sz > 0) {
|
||||
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
||||
while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
||||
}
|
||||
continue;
|
||||
} else if((header >> 1) == 1) {
|
||||
/* Fixed Huffman */
|
||||
max_len_1 = 9; max_len_2 = 5;
|
||||
} else {
|
||||
/* Dynamic Huffman */
|
||||
boff = dyn(data, boff);
|
||||
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
||||
}
|
||||
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
||||
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
||||
/* ingest code and move read head */
|
||||
var bits = read_bits_n(data, boff, max_len_1);
|
||||
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
||||
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
||||
else if(code == 256) break;
|
||||
else {
|
||||
code -= 257;
|
||||
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
||||
var tgt = woff + LEN_LN[code];
|
||||
/* length extra bits */
|
||||
if(len_eb > 0) {
|
||||
tgt += read_bits_n(data, boff, len_eb);
|
||||
boff += len_eb;
|
||||
}
|
||||
|
||||
/* dist code */
|
||||
bits = read_bits_n(data, boff, max_len_2);
|
||||
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
||||
var dst = DST_LN[code];
|
||||
/* dist extra bits */
|
||||
if(dst_eb > 0) {
|
||||
dst += read_bits_n(data, boff, dst_eb);
|
||||
boff += dst_eb;
|
||||
}
|
||||
|
||||
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
||||
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }
|
||||
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
||||
}
|
||||
}
|
||||
}
|
||||
if(usz) return [outbuf, (boff+7)>>>3];
|
||||
return [outbuf.slice(0, woff), (boff+7)>>>3];
|
||||
}
|
||||
|
||||
function _inflate(payload, usz) {
|
||||
var data = payload.slice(payload.l||0);
|
||||
var out = inflate(data, usz);
|
||||
payload.l += out[1];
|
||||
return out[0];
|
||||
}
|
||||
|
103
bits/82_zparse.js
Normal file
103
bits/82_zparse.js
Normal file
@ -0,0 +1,103 @@
|
||||
function warn_or_throw(wrn, msg) {
|
||||
if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
|
||||
else throw new Error(msg);
|
||||
}
|
||||
|
||||
function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
var blob/*:CFBlob*/ = /*::(*/file/*:: :any)*/;
|
||||
prep_blob(blob, 0);
|
||||
|
||||
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o, { root: options.root });
|
||||
|
||||
/* find end of central directory, start just after signature */
|
||||
var i = blob.length - 4;
|
||||
while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
|
||||
blob.l = i + 4;
|
||||
|
||||
/* parse end of central directory */
|
||||
blob.l += 4;
|
||||
var fcnt = blob.read_shift(2);
|
||||
blob.l += 6;
|
||||
var start_cd = blob.read_shift(4);
|
||||
|
||||
/* parse central directory */
|
||||
blob.l = start_cd;
|
||||
|
||||
for(i = 0; i < fcnt; ++i) {
|
||||
/* trust local file header instead of CD entry */
|
||||
blob.l += 20;
|
||||
var csz = blob.read_shift(4);
|
||||
var usz = blob.read_shift(4);
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
var fcsz = blob.read_shift(2);
|
||||
blob.l += 8;
|
||||
var offset = blob.read_shift(4);
|
||||
var EF = parse_extra_field(/*::(*/blob.slice(blob.l+namelen, blob.l+namelen+efsz)/*:: :any)*/);
|
||||
blob.l += namelen + efsz + fcsz;
|
||||
|
||||
var L = blob.l;
|
||||
blob.l = offset + 4;
|
||||
parse_local_file(blob, csz, usz, o, EF);
|
||||
blob.l = L;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* head starts just after local file header signature */
|
||||
function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:CFBContainer*/, EF) {
|
||||
/* [local file header] */
|
||||
blob.l += 2;
|
||||
var flags = blob.read_shift(2);
|
||||
var meth = blob.read_shift(2);
|
||||
var date = parse_dos_date(blob);
|
||||
|
||||
if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
|
||||
var crc32 = blob.read_shift(4);
|
||||
var _csz = blob.read_shift(4);
|
||||
var _usz = blob.read_shift(4);
|
||||
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
|
||||
// TODO: flags & (1<<11) // UTF8
|
||||
var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
|
||||
if(efsz) {
|
||||
var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/);
|
||||
if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
|
||||
if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
|
||||
}
|
||||
blob.l += efsz;
|
||||
|
||||
/* [encryption header] */
|
||||
|
||||
/* [file data] */
|
||||
var data = blob.slice(blob.l, blob.l + _csz);
|
||||
switch(meth) {
|
||||
case 8: data = _inflateRawSync(blob, _usz); break;
|
||||
case 0: break; // TODO: scan for magic number
|
||||
default: throw new Error("Unsupported ZIP Compression method " + meth);
|
||||
}
|
||||
|
||||
/* [data descriptor] */
|
||||
var wrn = false;
|
||||
if(flags & 8) {
|
||||
crc32 = blob.read_shift(4);
|
||||
if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
|
||||
_csz = blob.read_shift(4);
|
||||
_usz = blob.read_shift(4);
|
||||
}
|
||||
|
||||
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
|
||||
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
|
||||
var _crc32 = CRC32.buf(data, 0);
|
||||
if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
|
||||
cfb_add(o, name, data, {unsafe: true, mt: date});
|
||||
}
|
105
bits/83_zwrite.js
Normal file
105
bits/83_zwrite.js
Normal file
@ -0,0 +1,105 @@
|
||||
function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
var out = [], cdirs = [];
|
||||
var o/*:CFBlob*/ = new_buf(1);
|
||||
var method = (_opts.compression ? 8 : 0), flags = 0;
|
||||
var desc = false;
|
||||
if(desc) flags |= 8;
|
||||
var i = 0, j = 0;
|
||||
|
||||
var start_cd = 0, fcnt = 0;
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
var crcs = [];
|
||||
var sz_cd = 0;
|
||||
|
||||
for(i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
var start = start_cd;
|
||||
|
||||
/* TODO: CP437 filename */
|
||||
var namebuf = new_buf(fp.length);
|
||||
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
|
||||
namebuf = namebuf.slice(0, namebuf.l);
|
||||
crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
|
||||
|
||||
var outbuf = fi.content/*::||[]*/;
|
||||
if(method == 8) outbuf = _deflateRawSync(outbuf);
|
||||
|
||||
/* local file header */
|
||||
o = new_buf(30);
|
||||
o.write_shift(4, 0x04034b50);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
/* TODO: last mod file time/date */
|
||||
if(fi.mt) write_dos_date(o, fi.mt);
|
||||
else o.write_shift(4, 0);
|
||||
o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
|
||||
o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
|
||||
o.write_shift(4, (flags & 8) ? 0 : /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
start_cd += o.length;
|
||||
out.push(o);
|
||||
start_cd += namebuf.length;
|
||||
out.push(namebuf);
|
||||
|
||||
/* TODO: extra fields? */
|
||||
|
||||
/* TODO: encryption header ? */
|
||||
|
||||
start_cd += outbuf.length;
|
||||
out.push(outbuf);
|
||||
|
||||
/* data descriptor */
|
||||
if(flags & 8) {
|
||||
o = new_buf(12);
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
start_cd += o.l;
|
||||
out.push(o);
|
||||
}
|
||||
|
||||
/* central directory */
|
||||
o = new_buf(46);
|
||||
o.write_shift(4, 0x02014b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
o.write_shift(4, 0); /* TODO: last mod file time/date */
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, start);
|
||||
|
||||
sz_cd += o.l;
|
||||
cdirs.push(o);
|
||||
sz_cd += namebuf.length;
|
||||
cdirs.push(namebuf);
|
||||
++fcnt;
|
||||
}
|
||||
|
||||
/* end of central directory */
|
||||
o = new_buf(22);
|
||||
o.write_shift(4, 0x06054b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(4, sz_cd);
|
||||
o.write_shift(4, start_cd);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
|
||||
}
|
206
bits/84_mht.js
Normal file
206
bits/84_mht.js
Normal file
@ -0,0 +1,206 @@
|
||||
var ContentTypeMap = ({
|
||||
"htm": "text/html",
|
||||
"xml": "text/xml",
|
||||
|
||||
"gif": "image/gif",
|
||||
"jpg": "image/jpeg",
|
||||
"png": "image/png",
|
||||
|
||||
"mso": "application/x-mso",
|
||||
"thmx": "application/vnd.ms-officetheme",
|
||||
"sh33tj5": "application/octet-stream"
|
||||
}/*:any*/);
|
||||
|
||||
function get_content_type(fi/*:CFBEntry*/, fp/*:string*/)/*:string*/ {
|
||||
if(fi.ctype) return fi.ctype;
|
||||
|
||||
var ext = fi.name || "", m = ext.match(/\.([^\.]+)$/);
|
||||
if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];
|
||||
|
||||
if(fp) {
|
||||
m = (ext = fp).match(/[\.\\]([^\.\\])+$/);
|
||||
if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];
|
||||
}
|
||||
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
/* 76 character chunks TODO: intertwine encoding */
|
||||
function write_base64_76(bstr/*:string*/)/*:string*/ {
|
||||
var data = Base64_encode(bstr);
|
||||
var o = [];
|
||||
for(var i = 0; i < data.length; i+= 76) o.push(data.slice(i, i+76));
|
||||
return o.join("\r\n") + "\r\n";
|
||||
}
|
||||
|
||||
/*
|
||||
Rules for QP:
|
||||
- escape =## applies for all non-display characters and literal "="
|
||||
- space or tab at end of line must be encoded
|
||||
- \r\n newlines can be preserved, but bare \r and \n must be escaped
|
||||
- lines must not exceed 76 characters, use soft breaks =\r\n
|
||||
|
||||
TODO: Some files from word appear to write line extensions with bare equals:
|
||||
|
||||
```
|
||||
<table class=3DMsoTableGrid border=3D1 cellspacing=3D0 cellpadding=3D0 width=
|
||||
="70%"
|
||||
```
|
||||
*/
|
||||
function write_quoted_printable(text/*:string*/)/*:string*/ {
|
||||
var encoded = text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF=]/g, function(c) {
|
||||
var w = c.charCodeAt(0).toString(16).toUpperCase();
|
||||
return "=" + (w.length == 1 ? "0" + w : w);
|
||||
});
|
||||
|
||||
encoded = encoded.replace(/ $/mg, "=20").replace(/\t$/mg, "=09");
|
||||
|
||||
if(encoded.charAt(0) == "\n") encoded = "=0D" + encoded.slice(1);
|
||||
encoded = encoded.replace(/\r(?!\n)/mg, "=0D").replace(/\n\n/mg, "\n=0A").replace(/([^\r\n])\n/mg, "$1=0A");
|
||||
|
||||
var o/*:Array<string>*/ = [], split = encoded.split("\r\n");
|
||||
for(var si = 0; si < split.length; ++si) {
|
||||
var str = split[si];
|
||||
if(str.length == 0) { o.push(""); continue; }
|
||||
for(var i = 0; i < str.length;) {
|
||||
var end = 76;
|
||||
var tmp = str.slice(i, i + end);
|
||||
if(tmp.charAt(end - 1) == "=") end --;
|
||||
else if(tmp.charAt(end - 2) == "=") end -= 2;
|
||||
else if(tmp.charAt(end - 3) == "=") end -= 3;
|
||||
tmp = str.slice(i, i + end);
|
||||
i += end;
|
||||
if(i < str.length) tmp += "=";
|
||||
o.push(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return o.join("\r\n");
|
||||
}
|
||||
function parse_quoted_printable(data/*:Array<string>*/)/*:RawBytes*/ {
|
||||
var o = [];
|
||||
|
||||
/* unify long lines */
|
||||
for(var di = 0; di < data.length; ++di) {
|
||||
var line = data[di];
|
||||
while(di <= data.length && line.charAt(line.length - 1) == "=") line = line.slice(0, line.length - 1) + data[++di];
|
||||
o.push(line);
|
||||
}
|
||||
|
||||
/* decode */
|
||||
for(var oi = 0; oi < o.length; ++oi) o[oi] = o[oi].replace(/[=][0-9A-Fa-f]{2}/g, function($$) { return String.fromCharCode(parseInt($$.slice(1), 16)); });
|
||||
return s2a(o.join("\r\n"));
|
||||
}
|
||||
|
||||
|
||||
function parse_mime(cfb/*:CFBContainer*/, data/*:Array<string>*/, root/*:string*/)/*:void*/ {
|
||||
var fname = "", cte = "", ctype = "", fdata;
|
||||
var di = 0;
|
||||
for(;di < 10; ++di) {
|
||||
var line = data[di];
|
||||
if(!line || line.match(/^\s*$/)) break;
|
||||
var m = line.match(/^(.*?):\s*([^\s].*)$/);
|
||||
if(m) switch(m[1].toLowerCase()) {
|
||||
case "content-location": fname = m[2].trim(); break;
|
||||
case "content-type": ctype = m[2].trim(); break;
|
||||
case "content-transfer-encoding": cte = m[2].trim(); break;
|
||||
}
|
||||
}
|
||||
++di;
|
||||
switch(cte.toLowerCase()) {
|
||||
case 'base64': fdata = s2a(Base64_decode(data.slice(di).join(""))); break;
|
||||
case 'quoted-printable': fdata = parse_quoted_printable(data.slice(di)); break;
|
||||
default: throw new Error("Unsupported Content-Transfer-Encoding " + cte);
|
||||
}
|
||||
var file = cfb_add(cfb, fname.slice(root.length), fdata, {unsafe: true});
|
||||
if(ctype) file.ctype = ctype;
|
||||
}
|
||||
|
||||
function parse_mad(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
if(a2s(file.slice(0,13)).toLowerCase() != "mime-version:") throw new Error("Unsupported MAD header");
|
||||
var root = (options && options.root || "");
|
||||
// $FlowIgnore
|
||||
var data = (has_buf && Buffer.isBuffer(file) ? file.toString("binary") : a2s(file)).split("\r\n");
|
||||
var di = 0, row = "";
|
||||
|
||||
/* if root is not specified, scan for the common prefix */
|
||||
for(di = 0; di < data.length; ++di) {
|
||||
row = data[di];
|
||||
if(!/^Content-Location:/i.test(row)) continue;
|
||||
row = row.slice(row.indexOf("file"));
|
||||
if(!root) root = row.slice(0, row.lastIndexOf("/") + 1);
|
||||
if(row.slice(0, root.length) == root) continue;
|
||||
while(root.length > 0) {
|
||||
root = root.slice(0, root.length - 1);
|
||||
root = root.slice(0, root.lastIndexOf("/") + 1);
|
||||
if(row.slice(0,root.length) == root) break;
|
||||
}
|
||||
}
|
||||
|
||||
var mboundary = (data[1] || "").match(/boundary="(.*?)"/);
|
||||
if(!mboundary) throw new Error("MAD cannot find boundary");
|
||||
var boundary = "--" + (mboundary[1] || "");
|
||||
|
||||
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o);
|
||||
var start_di, fcnt = 0;
|
||||
for(di = 0; di < data.length; ++di) {
|
||||
var line = data[di];
|
||||
if(line !== boundary && line !== boundary + "--") continue;
|
||||
if(fcnt++) parse_mime(o, data.slice(start_di, di), root);
|
||||
start_di = di;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ {
|
||||
var opts = options || {};
|
||||
var boundary = opts.boundary || "SheetJS";
|
||||
boundary = '------=' + boundary;
|
||||
|
||||
var out = [
|
||||
'MIME-Version: 1.0',
|
||||
'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"',
|
||||
'',
|
||||
'',
|
||||
''
|
||||
];
|
||||
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
for(var i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length);
|
||||
fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
|
||||
/* Normalize filename */
|
||||
fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) {
|
||||
return "_x" + c.charCodeAt(0).toString(16) + "_";
|
||||
}).replace(/[\u0080-\uFFFF]/g, function(u) {
|
||||
return "_u" + u.charCodeAt(0).toString(16) + "_";
|
||||
});
|
||||
|
||||
/* Extract content as binary string */
|
||||
var ca = fi.content;
|
||||
// $FlowIgnore
|
||||
var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca);
|
||||
|
||||
/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */
|
||||
var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;
|
||||
for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;
|
||||
var qp = dispcnt >= L * 4 / 5;
|
||||
|
||||
out.push(boundary);
|
||||
out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);
|
||||
out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));
|
||||
out.push('Content-Type: ' + get_content_type(fi, fp));
|
||||
out.push('');
|
||||
|
||||
out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));
|
||||
}
|
||||
out.push(boundary + '--\r\n');
|
||||
return out.join("\r\n");
|
||||
}
|
@ -5,8 +5,9 @@ function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
|
||||
}
|
||||
|
||||
function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ {
|
||||
init_cfb(cfb);
|
||||
var file = CFB.find(cfb, name);
|
||||
var unsafe = opts && opts.unsafe;
|
||||
if(!unsafe) init_cfb(cfb);
|
||||
var file = !unsafe && CFB.find(cfb, name);
|
||||
if(!file) {
|
||||
var fpath/*:string*/ = cfb.FullPaths[0];
|
||||
if(name.slice(0, fpath.length) == fpath) fpath = name;
|
||||
@ -17,13 +18,15 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
file = ({name: filename(name), type: 2}/*:any*/);
|
||||
cfb.FileIndex.push(file);
|
||||
cfb.FullPaths.push(fpath);
|
||||
CFB.utils.cfb_gc(cfb);
|
||||
if(!unsafe) CFB.utils.cfb_gc(cfb);
|
||||
}
|
||||
/*:: if(!file) throw new Error("unreachable"); */
|
||||
file.content = (content/*:any*/);
|
||||
file.size = content ? content.length : 0;
|
||||
if(opts) {
|
||||
if(opts.CLSID) file.clsid = opts.CLSID;
|
||||
if(opts.mt) file.mt = opts.mt;
|
||||
if(opts.ct) file.ct = opts.ct;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ exports.utils = {
|
||||
CheckField: CheckField,
|
||||
prep_blob: prep_blob,
|
||||
bconcat: bconcat,
|
||||
use_zlib: use_zlib,
|
||||
_deflateRaw: _deflate,
|
||||
_inflateRaw: _inflate,
|
||||
consts: consts
|
||||
};
|
||||
|
||||
|
1342
cfb.flow.js
1342
cfb.flow.js
File diff suppressed because it is too large
Load Diff
2
dist/.npmignore
vendored
Normal file
2
dist/.npmignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.npmignore
|
||||
*.sheetjs
|
190
dist/LICENSE
vendored
190
dist/LICENSE
vendored
@ -1,4 +1,192 @@
|
||||
Copyright (C) 2013-present SheetJS
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2013-present SheetJS LLC
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
1331
dist/cfb.js
vendored
1331
dist/cfb.js
vendored
File diff suppressed because it is too large
Load Diff
3
dist/cfb.min.js
vendored
3
dist/cfb.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/cfb.min.map
vendored
2
dist/cfb.min.map
vendored
File diff suppressed because one or more lines are too long
1236
dist/xlscfb.js
vendored
1236
dist/xlscfb.js
vendored
File diff suppressed because it is too large
Load Diff
12
fails.lst
12
fails.lst
@ -1,7 +1,13 @@
|
||||
apachepoi_61300.xls
|
||||
# not CFB or ZIP
|
||||
apachepoi_testEXCEL_3.xls
|
||||
apachepoi_testEXCEL_4.xls
|
||||
xlrd_biff4_no_format_no_window2.xls
|
||||
roo_type_excelx.xls
|
||||
roo_type_openoffice.xls
|
||||
libreoffice_calc_csv-import_malformed-quotes.xls
|
||||
# file exceeding 31 chars
|
||||
apachepoi_59746_NoRowNums.xlsx
|
||||
apachepoi_WithEmbeded.xlsx
|
||||
apachepoi_picture.xlsx
|
||||
roo_name_with_leading_slash.xlsx
|
||||
spout-xlsx_sheet_with_prefixed_xml_files.xlsx
|
||||
# not a valid file
|
||||
openpyxl_r_null_archive.xlsx
|
||||
|
68
index.html
68
index.html
@ -3,6 +3,7 @@
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>JS-CFB Live Demo</title>
|
||||
<style>
|
||||
@ -32,22 +33,31 @@ a { text-decoration: none }
|
||||
<b>Advanced Demo Options:</b>
|
||||
Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" checked>
|
||||
|
||||
<a id="saveit" onclick="savefile();" href="#">Export data</a>
|
||||
<b>Export Current File</b>
|
||||
- <a id="savecfb" onclick="savefile('cfb');" href="#">Export data as CFB</a> (Container File Binary Format)
|
||||
- <a id="savezip" onclick="savefile('zip');" href="#">Export data as ZIP</a>
|
||||
- <a id="savemad" onclick="savefile('mad');" href="#">Export data as MAD</a> (MIME aggregate document)
|
||||
</pre>
|
||||
<pre id="out"></pre>
|
||||
<br />
|
||||
<script src="shim.js"></script>
|
||||
<script src="https://unpkg.com/printj/dist/printj.min.js"></script>
|
||||
<script src="cfb.js"></script>
|
||||
<script src="//rawgit.com/eligrey/Blob.js/master/Blob.js"></script>
|
||||
<script src="//rawgit.com/eligrey/FileSaver.js/master/FileSaver.js"></script>
|
||||
<script src="dist/cfb.min.js"></script>
|
||||
<script>
|
||||
/*jshint browser:true */
|
||||
/* eslint-env browser */
|
||||
/*global Uint8Array, ArrayBuffer */
|
||||
/*global CFB, out, PRINTJ */
|
||||
/* exported savefile, download_file */
|
||||
/* eslint no-use-before-define:0 */
|
||||
/*global CFB, out */
|
||||
var global_cfb;
|
||||
|
||||
if(!String.prototype.repeat) String.prototype.repeat = function(count) {
|
||||
var o = "";
|
||||
for(var i = 0; i < count; ++i) o += this;
|
||||
return o;
|
||||
};
|
||||
|
||||
var get_manifest = (function() {
|
||||
var sprintf = PRINTJ.sprintf;
|
||||
function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/, function($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
|
||||
@ -56,6 +66,7 @@ var get_manifest = (function() {
|
||||
};
|
||||
return function get_manifest(cfb) {
|
||||
var out = [];
|
||||
var rlen = cfb.FullPaths[0].length;
|
||||
|
||||
var basetime = new Date(1980,0,1);
|
||||
var cnt = 0, rootsize = 0, filesize = 0;
|
||||
@ -68,7 +79,10 @@ var get_manifest = (function() {
|
||||
rootsize = file.size;
|
||||
break;
|
||||
case 2:
|
||||
out.push(sprintf("%9lu %s <a href=\"#\" onclick=\"download_file(%d);\">%s</a>", file.size, format_date(basetime), i, fix_string(cfb.FullPaths[i])));
|
||||
var fixname = fix_string(cfb.FullPaths[i]);
|
||||
if(fixname.match(/\\u0001Sh33tJ5/)) return;
|
||||
fixname = fixname.slice(rlen);
|
||||
out.push(sprintf("%9lu %s <a href=\"#\" onclick=\"download_file(%d);\">%s</a>", file.size, format_date(basetime), i, fixname));
|
||||
filesize += file.size;
|
||||
++cnt;
|
||||
}
|
||||
@ -90,20 +104,13 @@ var do_file = (function() {
|
||||
var domrabs = document.getElementsByName("userabs")[0];
|
||||
if(!rABS) domrabs.disabled = !(domrabs.checked = false);
|
||||
|
||||
function fixdata(data) {
|
||||
var o = "", l = 0, w = 10240;
|
||||
for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,new Uint8Array(data.slice(l*w,l*w+w)));
|
||||
o+=String.fromCharCode.apply(null, new Uint8Array(data.slice(l*w)));
|
||||
return o;
|
||||
}
|
||||
|
||||
return function do_file(files) {
|
||||
rABS = domrabs.checked;
|
||||
var f = files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
var data = e.target.result;
|
||||
var cfb = CFB.read(rABS ? data : btoa(fixdata(data)), {type: rABS ? 'binary' : 'base64'});
|
||||
var cfb = CFB.read(rABS ? data : new Uint8Array(data), {type: rABS ? 'binary' : 'buffer'});
|
||||
process_data(cfb);
|
||||
};
|
||||
if(rABS) reader.readAsBinaryString(f);
|
||||
@ -132,6 +139,14 @@ var do_file = (function() {
|
||||
drop.addEventListener('drop', handleDrop, false);
|
||||
})();
|
||||
|
||||
function saveAs(blob, fname) {
|
||||
var url = URL.createObjectURL(blob);
|
||||
var a = document.createElement("a");
|
||||
a.download = fname; a.href = url; document.body.appendChild(a); a.click();
|
||||
/*:: if(document.body == null) throw new Error("unreachable"); */ document.body.removeChild(a);
|
||||
if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
|
||||
}
|
||||
|
||||
var savefile = (function() {
|
||||
var s2ab = function s2ab(s) {
|
||||
var buf, i=0;
|
||||
@ -147,12 +162,18 @@ var savefile = (function() {
|
||||
}
|
||||
};
|
||||
|
||||
return function savefile() {
|
||||
return function savefile(type) {
|
||||
if(!global_cfb) return alert("Must load a file first!");
|
||||
console.log(global_cfb);
|
||||
var data = CFB.write(global_cfb, {type:'binary'});
|
||||
console.log(data);
|
||||
saveAs(new Blob([s2ab(data)],{type:"application/octet-stream"}), "sheetjs.xls");
|
||||
if(typeof console !== 'undefined') console.log(global_cfb);
|
||||
var data = CFB.write(global_cfb, {type:'binary', fileType: type});
|
||||
if(typeof console !== 'undefined') console.log(data);
|
||||
var newcfb = CFB.read(data, {type:'binary'});
|
||||
console.log(newcfb);
|
||||
|
||||
var fname = "SheetJSCFBDemo." + type;
|
||||
var blob = new Blob([s2ab(data)],{type:"application/octet-stream"});
|
||||
if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
|
||||
saveAs(blob, fname);
|
||||
};
|
||||
})();
|
||||
|
||||
@ -166,14 +187,13 @@ var download_file = (function() {
|
||||
|
||||
return function download_file(i) {
|
||||
if(!global_cfb) return alert("Must load a file first!");
|
||||
console.log(global_cfb);
|
||||
if(typeof console !== 'undefined') console.log(global_cfb);
|
||||
var file = global_cfb.FileIndex[i], data = file.content;
|
||||
saveAs(new Blob([a2ab(data)],{type:"application/octet-stream"}), file.name);
|
||||
var blob = new Blob([a2ab(data)],{type:"application/octet-stream"});
|
||||
if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, file.name);
|
||||
saveAs(blob, file.name);
|
||||
};
|
||||
})();
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
/* eslint no-use-before-define:0 */
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
@ -64,6 +64,7 @@ type CFBWriteOpts = any;
|
||||
|
||||
interface CFBReadOpts {
|
||||
type?:string;
|
||||
root?:string;
|
||||
};
|
||||
|
||||
type CFBFileIndex = Array<CFBEntry>;
|
||||
@ -94,5 +95,6 @@ type CFBEntry = {
|
||||
R: number;
|
||||
C: number;
|
||||
content?: CFBlob;
|
||||
ctype?: string;
|
||||
}
|
||||
*/
|
||||
|
@ -1,10 +1,12 @@
|
||||
/*::
|
||||
|
||||
declare module 'cfb' { declare var exports:CFBModule; };
|
||||
declare module '../' { declare var exports:CFBModule; };
|
||||
declare module './' { declare var exports:CFBModule; };
|
||||
declare module 'cfb' { declare module.exports:CFBModule; };
|
||||
declare module '../' { declare module.exports:CFBModule; };
|
||||
declare module './' { declare module.exports:CFBModule; };
|
||||
|
||||
declare module 'commander' { declare var exports:any; };
|
||||
declare module 'printj' { declare var exports:any; };
|
||||
declare module 'crc-32' { declare var exports: any; };
|
||||
declare module 'commander' { declare module.exports:any; };
|
||||
declare module 'printj' {
|
||||
declare var sprintf:(fmt:string, ...args:any)=>string;
|
||||
};
|
||||
declare module 'crc-32' { declare module.exports: any; };
|
||||
*/
|
||||
|
11
misc/node_version.sh
Executable file
11
misc/node_version.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
# This script will check the current version of node and install another version
|
||||
# of npm if node is version 0.8
|
||||
|
||||
version=$(node --version)
|
||||
|
||||
if [[ $version =~ v0\.8\. ]]
|
||||
then
|
||||
npm install -g npm@4.3.0
|
||||
fi
|
@ -1,6 +1,4 @@
|
||||
var DO_NOT_EXPORT_CFB = true;
|
||||
/*::
|
||||
declare var Base64:any;
|
||||
declare var ReadShift:any;
|
||||
declare var CheckField:any;
|
||||
declare var prep_blob:any;
|
||||
@ -12,5 +10,9 @@ declare var bconcat:any;
|
||||
declare var s2a:any;
|
||||
declare var chr0:any;
|
||||
declare var chr1:any;
|
||||
declare var has_buf:boolean;
|
||||
declare var new_buf:any;
|
||||
declare var new_raw_buf:any;
|
||||
declare var new_unsafe_buf:any;
|
||||
declare var Buffer_from:any;
|
||||
*/
|
57
package.json
57
package.json
@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "cfb",
|
||||
"version": "0.14.0",
|
||||
"version": "1.2.2",
|
||||
"author": "sheetjs",
|
||||
"description": "Compound File Binary File Format extractor",
|
||||
"keywords": [ "cfb", "compression", "office" ],
|
||||
"bin": {
|
||||
"cfb": "./bin/cfb.njs"
|
||||
},
|
||||
"keywords": [
|
||||
"cfb",
|
||||
"compression",
|
||||
"office"
|
||||
],
|
||||
"main": "./cfb",
|
||||
"types": "types",
|
||||
"browser": {
|
||||
@ -15,20 +16,28 @@
|
||||
"fs": false
|
||||
},
|
||||
"dependencies": {
|
||||
"printj":"~1.1.0",
|
||||
"commander":"~2.11.0"
|
||||
"adler-32": "~1.3.0",
|
||||
"crc-32": "~1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"crc-32":"~1.1.1",
|
||||
"mocha":"~2.5.3",
|
||||
"@sheetjs/uglify-js": "~2.7.3",
|
||||
"@types/node": "^8.10.25",
|
||||
"acorn": "7.4.1",
|
||||
"alex": "8.1.1",
|
||||
"blanket": "~1.2.3",
|
||||
"@sheetjs/uglify-js":"~2.7.3",
|
||||
"@types/node":"^8.0.7",
|
||||
"@types/commander":"^2.9.0",
|
||||
"dtslint": "^0.1.2",
|
||||
"dtslint": "~0.1.2",
|
||||
"eslint": "7.23.0",
|
||||
"eslint-plugin-html": "^6.1.2",
|
||||
"eslint-plugin-json": "^2.1.2",
|
||||
"jscs": "3.0.7",
|
||||
"jshint": "2.13.4",
|
||||
"mocha": "~2.5.3",
|
||||
"typescript": "2.2.0"
|
||||
},
|
||||
"repository": { "type":"git", "url":"git://github.com/SheetJS/js-cfb.git" },
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/SheetJS/js-cfb.git"
|
||||
},
|
||||
"scripts": {
|
||||
"pretest": "make init",
|
||||
"test": "make test",
|
||||
@ -39,9 +48,21 @@
|
||||
"pattern": "cfb.js"
|
||||
}
|
||||
},
|
||||
"files": [ "LICENSE", "README.md", "bin/", "dist/", "types/index.d.ts", "types/tsconfig.json", "cfb.js", "xlscfb.flow.js" ],
|
||||
"homepage": "http://sheetjs.com/opensource",
|
||||
"bugs": { "url": "https://github.com/SheetJS/js-cfb/issues" },
|
||||
"files": [
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"dist/",
|
||||
"types/index.d.ts",
|
||||
"types/tsconfig.json",
|
||||
"cfb.js",
|
||||
"xlscfb.flow.js"
|
||||
],
|
||||
"homepage": "http://sheetjs.com/",
|
||||
"bugs": {
|
||||
"url": "https://github.com/SheetJS/js-cfb/issues"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"engines": { "node": ">=0.8" }
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
}
|
||||
|
1
packages/cfb-cli/.npmignore
Normal file
1
packages/cfb-cli/.npmignore
Normal file
@ -0,0 +1 @@
|
||||
*.tgz
|
201
packages/cfb-cli/LICENSE
Normal file
201
packages/cfb-cli/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2013-present SheetJS LLC
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
48
packages/cfb-cli/README.md
Normal file
48
packages/cfb-cli/README.md
Normal file
@ -0,0 +1,48 @@
|
||||
# Container File Blobs
|
||||
|
||||
This CLI tool inspects and can manipulate supported files, leveraging the base
|
||||
[`cfb` library](https://www.npmjs.com/package/cfb).
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
It is preferable to install the library globally with npm:
|
||||
|
||||
```bash
|
||||
$ npm install -g cfb-cli
|
||||
```
|
||||
|
||||
The global installation adds a command `cfb-cli` which can work with files.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
- `cfb file [names...]` extracts the contents of the file. If additional names
|
||||
are supplied, only the listed files will be extracted.
|
||||
|
||||
- `cfb -l file` lists the contained files (following `unzip -l` "short format")
|
||||
|
||||
- `cfb -r file` attempts to repair by reading and re-writing the file.
|
||||
This fixes some issues with files generated by non-standard tools.
|
||||
|
||||
- `cfb -c file [files...]` creates a new file containing the listed files.
|
||||
The default root entry name is `Root Entry`.
|
||||
|
||||
- `cfb -a file [files...]` adds the listed files to the original file.
|
||||
|
||||
- `cfb -d file [files...]` deletes the listed files from the original file.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Please consult the attached LICENSE file for details. All rights not explicitly
|
||||
granted by the Apache 2.0 license are reserved by the Original Author.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
Special thanks to [Garrett Luu](https://garrettluu.com/) for spinning off the
|
||||
command from the CFB module.
|
||||
|
||||
|
||||
[](https://github.com/SheetJS/js-cfb)
|
7
packages/cfb-cli/bin/cfb.njs
Executable file
7
packages/cfb-cli/bin/cfb.njs
Executable file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* vim: set ts=2 ft=javascript: */
|
||||
var cli = require('../');
|
||||
|
||||
cli();
|
173
packages/cfb-cli/index.js
Normal file
173
packages/cfb-cli/index.js
Normal file
@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env node
|
||||
/* index.js (C) 2020-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* vim: set ts=2 ft=javascript: */
|
||||
|
||||
var n = "cfb-cli";
|
||||
var X = require('cfb');
|
||||
var fs = require('fs');
|
||||
var program = require('commander');
|
||||
var PRINTJ = require("printj");
|
||||
function run() {
|
||||
var sprintf = PRINTJ.sprintf;
|
||||
program
|
||||
.version(X.version)
|
||||
.usage('[options] <file> [subfiles...]')
|
||||
.option('-l, --list-files', 'list files')
|
||||
.option('-r, --repair', 'attempt to repair and garbage-collect archive')
|
||||
.option('-c, --create', 'create file')
|
||||
.option('-a, --append', 'add files to CFB (overwrite existing data)')
|
||||
.option('-d, --delete', 'delete files from CFB')
|
||||
.option('-O, --to-stdout', 'extract raw contents to stdout')
|
||||
.option('-z, --dump', 'dump internal representation but do not extract')
|
||||
.option('-q, --quiet', 'process but do not report')
|
||||
.option('--here', 'skip the CFB root name when extracting')
|
||||
.option('--osx', 'use OSX-style unzip listing')
|
||||
.option('--zlib', 'use native zlib')
|
||||
.option('--local', 'print times in local timezone')
|
||||
.option('--dev', 'development mode')
|
||||
.option('--read', 'read but do not print out contents');
|
||||
program.parse(process.argv);
|
||||
|
||||
if (program.zlib) X.utils.use_zlib(require('zlib'));
|
||||
|
||||
var exit = process.exit;
|
||||
var die = function (errno/*:number*/, msg/*:string*/) { console.error(n + ": " + msg); exit(errno); };
|
||||
var logit = function (cmd/*:string*/, f/*:string*/) { console.error(sprintf("%-6s %s", cmd, f)); };
|
||||
|
||||
if (program.args.length === 0) die(1, "must specify a filename");
|
||||
|
||||
if (program.create) {
|
||||
logit("create", program.args[0]);
|
||||
var newcfb = X.utils.cfb_new();
|
||||
X.writeFile(newcfb, program.args[0]);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(program.args[0])) die(1, "must specify a filename");
|
||||
|
||||
var opts = ({ type: 'file' }/*:any*/);
|
||||
if (program.dev) opts.WTF = true;
|
||||
|
||||
var cfb = X.read(program.args[0], opts);
|
||||
if (program.quiet) exit(0);
|
||||
|
||||
if (program.dump) {
|
||||
console.log("Full Paths:");
|
||||
console.log(cfb.FullPaths.map(function (x/*:string*/) { return " " + x; }).join("\n"));
|
||||
console.log("File Index:");
|
||||
console.log(cfb.FileIndex);
|
||||
exit(0);
|
||||
}
|
||||
if (program.repair) { X.writeFile(cfb, program.args[0]); exit(0); }
|
||||
|
||||
var rlen = cfb.FullPaths[0].length;
|
||||
|
||||
function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/g, function ($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
|
||||
var format_date = function (date/*:Date*/, osx/*:?any*/)/*:string*/ {
|
||||
var datefmt = osx ? "%02u-%02u-%04u %02u:%02u" : "%02u-%02u-%02u %02u:%02u";
|
||||
var MM = program.local ? date.getMonth() + 1 : date.getUTCMonth() + 1;
|
||||
var DD = program.local ? date.getDate() : date.getUTCDate();
|
||||
var YY = (program.local ? date.getFullYear() : date.getUTCFullYear()) % (osx ? 10000 : 100);
|
||||
var hh = program.local ? date.getHours() : date.getUTCHours();
|
||||
var mm = program.local ? date.getMinutes() : date.getUTCMinutes();
|
||||
return sprintf(datefmt, MM, DD, YY, hh, mm);
|
||||
};
|
||||
|
||||
if (program.listFiles) {
|
||||
var basetime = new Date(Date.UTC(1980, 0, 1));
|
||||
var cnt = 0, rootsize = 0, filesize = 0;
|
||||
var fmtstr = "%9lu %s %s";
|
||||
if (program.osx) {
|
||||
console.log("Archive: " + program.args[0]);
|
||||
console.log(" Length Date Time Name");
|
||||
console.log("--------- ---------- ----- ----");
|
||||
fmtstr = "%9lu %s %s";
|
||||
} else {
|
||||
console.log(" Length Date Time Name");
|
||||
console.log(" -------- ---- ---- ----");
|
||||
}
|
||||
cfb.FileIndex.forEach(function (file/*:CFBEntry*/, i/*:number*/) {
|
||||
switch (file.type) {
|
||||
case 5:
|
||||
basetime = file.ct || file.mt || basetime;
|
||||
rootsize = file.size;
|
||||
break;
|
||||
case 2:
|
||||
var fixname = fix_string(cfb.FullPaths[i]);
|
||||
if (program.osx && fixname.match(/\\u0001Sh33tJ5/)) return;
|
||||
if (program.here) fixname = fixname.slice(rlen);
|
||||
console.log(sprintf(fmtstr, file.size, format_date(file.mt || basetime, program.osx), fixname));
|
||||
filesize += file.size;
|
||||
++cnt;
|
||||
}
|
||||
});
|
||||
var outfmt = "%9lu %lu file%s";
|
||||
if (program.osx) {
|
||||
console.log("--------- -------");
|
||||
outfmt = "%9lu %lu file%s";
|
||||
} else {
|
||||
console.log(" -------- -------");
|
||||
}
|
||||
console.log(sprintf(outfmt, rootsize || filesize, cnt, (cnt !== 1 ? "s" : "")));
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
function mkdirp(path/*:string*/) {
|
||||
path.split("/").reduce(function (acc/*:string*/, p/*:string*/) {
|
||||
acc += p + "/";
|
||||
if (!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); }
|
||||
return acc;
|
||||
}, "");
|
||||
}
|
||||
|
||||
function write(path/*:string*/, data/*:CFBEntry*/) {
|
||||
logit("write", fix_string(path));
|
||||
fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/ || new Buffer(0));
|
||||
}
|
||||
|
||||
if (program.create || program.append) {
|
||||
program.args.slice(1).forEach(function (x/*:string*/) {
|
||||
logit("append", x);
|
||||
X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x));
|
||||
});
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (program.delete) {
|
||||
program.args.slice(1).forEach(function (x/*:string*/) {
|
||||
logit("delete", x);
|
||||
X.utils.cfb_del(cfb, "/" + x);
|
||||
});
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (program.args.length > 1) {
|
||||
program.args.slice(1).forEach(function (x/*:string*/) {
|
||||
var data/*:?CFBEntry*/ = X.find(cfb, x.replace(/\\u000\d/g, "!"));
|
||||
if (!data) { console.error(x + ": file not found"); return; }
|
||||
if (data.type !== 2) { console.error(x + ": not a file"); return; }
|
||||
var idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx];
|
||||
if (program.toStdout) return process.stdout.write(/*::new Buffer((*/data.content/*:: :any))*/);
|
||||
mkdirp(path.slice(0, path.lastIndexOf("/")));
|
||||
write(path, data);
|
||||
});
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (program.toStdout) exit(0);
|
||||
for (var i = program.here ? 1 : 0; i !== cfb.FullPaths.length; ++i) {
|
||||
if (!cfb.FileIndex[i].name) continue;
|
||||
var fp = cfb.FullPaths[i];
|
||||
if (program.here) fp = fp.slice(rlen);
|
||||
if (fp.slice(-1) === "/") mkdirp(fp);
|
||||
else {
|
||||
if (fp.indexOf("/") > -1) mkdirp(fp.slice(0, fp.lastIndexOf("/")));
|
||||
write(fp, cfb.FileIndex[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = run;
|
16
packages/cfb-cli/package.json
Normal file
16
packages/cfb-cli/package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "cfb-cli",
|
||||
"version": "1.0.1",
|
||||
"description": "Command-line interface for cfb",
|
||||
"bin": {
|
||||
"cfb-cli": "./bin/cfb.njs"
|
||||
},
|
||||
"main": "index.js",
|
||||
"author": "Garrett Luu",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"cfb": "^1.1.4",
|
||||
"commander": "^5.1.0",
|
||||
"printj": "^1.2.2"
|
||||
}
|
||||
}
|
475
shim.js
475
shim.js
@ -1,343 +1,154 @@
|
||||
/*! shim.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* ES3/5 Compatibility shims and other utilities for older browsers. */
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
|
||||
if (!Object.keys) {
|
||||
Object.keys = (function () {
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty,
|
||||
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
|
||||
dontEnums = [
|
||||
'toString',
|
||||
'toLocaleString',
|
||||
'valueOf',
|
||||
'hasOwnProperty',
|
||||
'isPrototypeOf',
|
||||
'propertyIsEnumerable',
|
||||
'constructor'
|
||||
],
|
||||
dontEnumsLength = dontEnums.length;
|
||||
if(!Object.keys) Object.keys = (function() {
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty,
|
||||
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
|
||||
dontEnums = [
|
||||
'toString',
|
||||
'toLocaleString',
|
||||
'valueOf',
|
||||
'hasOwnProperty',
|
||||
'isPrototypeOf',
|
||||
'propertyIsEnumerable',
|
||||
'constructor'
|
||||
],
|
||||
dontEnumsLength = dontEnums.length;
|
||||
|
||||
return function (obj) {
|
||||
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
|
||||
return function(obj) {
|
||||
if(typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
|
||||
|
||||
var result = [];
|
||||
var result = [];
|
||||
|
||||
for (var prop in obj) {
|
||||
if (hasOwnProperty.call(obj, prop)) result.push(prop);
|
||||
}
|
||||
for(var prop in obj) if(hasOwnProperty.call(obj, prop)) result.push(prop);
|
||||
|
||||
if (hasDontEnumBug) {
|
||||
for (var i=0; i < dontEnumsLength; i++) {
|
||||
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
}
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
|
||||
if (!Array.prototype.filter)
|
||||
{
|
||||
Array.prototype.filter = function(fun /*, thisp */)
|
||||
{
|
||||
"use strict";
|
||||
|
||||
if (this == null)
|
||||
throw new TypeError();
|
||||
|
||||
var t = Object(this);
|
||||
var len = t.length >>> 0;
|
||||
if (typeof fun != "function")
|
||||
throw new TypeError();
|
||||
|
||||
var res = [];
|
||||
var thisp = arguments[1];
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
if (i in t)
|
||||
{
|
||||
var val = t[i]; // in case fun mutates this
|
||||
if (fun.call(thisp, val, i, t))
|
||||
res.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
if(hasDontEnumBug)
|
||||
for(var i=0; i < dontEnumsLength; ++i)
|
||||
if(hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
|
||||
if (!String.prototype.trim) {
|
||||
String.prototype.trim = function () {
|
||||
return this.replace(/^\s+|\s+$/g, '');
|
||||
if(!String.prototype.trim) String.prototype.trim = function() {
|
||||
var s = this.replace(/^\s+/, '');
|
||||
for(var i = s.length - 1; i >=0 ; --i) if(!s.charAt(i).match(/^\s/)) return s.slice(0,i+1);
|
||||
return "";
|
||||
};
|
||||
|
||||
if(!Array.prototype.forEach) Array.prototype.forEach = function(cb) {
|
||||
var len = (this.length>>>0), self = (arguments[1]||void 0);
|
||||
for(var i=0; i<len; ++i) if(i in this) self ? cb.call(self, this[i], i, this) : cb(this[i], i, this);
|
||||
};
|
||||
|
||||
if(!Array.prototype.map) Array.prototype.map = function(cb) {
|
||||
var len = (this.length>>>0), self = (arguments[1]||void 0), A = new Array(len);
|
||||
for(var i=0; i<len; ++i) if(i in this) A[i] = self ? cb.call(self, this[i], i, this) : cb(this[i], i, this);
|
||||
return A;
|
||||
};
|
||||
|
||||
if(!Array.prototype.indexOf) Array.prototype.indexOf = function(needle) {
|
||||
var len = (this.length>>>0), i = ((arguments[1]|0)||0);
|
||||
for(i<0 && (i+=len)<0 && (i=0); i<len; ++i) if(this[i] === needle) return i;
|
||||
return -1;
|
||||
};
|
||||
|
||||
if(!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(needle) {
|
||||
var len = (this.length>>>0), i = len - 1;
|
||||
for(; i>=0; --i) if(this[i] === needle) return i;
|
||||
return -1;
|
||||
};
|
||||
|
||||
if(!Array.isArray) Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]"; };
|
||||
|
||||
if(!Date.prototype.toISOString) Date.prototype.toISOString = (function() {
|
||||
function p(n,i) { return ('0000000' + n).slice(-(i||2)); }
|
||||
|
||||
return function _toISOString() {
|
||||
var y = this.getUTCFullYear(), yr = "";
|
||||
if(y>9999) yr = '+' + p( y, 6);
|
||||
else if(y<0) yr = '-' + p(-y, 6);
|
||||
else yr = p( y, 4);
|
||||
|
||||
return [
|
||||
yr, p(this.getUTCMonth()+1), p(this.getUTCDate())
|
||||
].join('-') + 'T' + [
|
||||
p(this.getUTCHours()), p(this.getUTCMinutes()), p(this.getUTCSeconds())
|
||||
].join(':') + '.' + p(this.getUTCMilliseconds(),3) + 'Z';
|
||||
};
|
||||
}
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
|
||||
if (!Array.prototype.forEach)
|
||||
{
|
||||
Array.prototype.forEach = function(fun /*, thisArg */)
|
||||
{
|
||||
"use strict";
|
||||
|
||||
if (this === void 0 || this === null)
|
||||
throw new TypeError();
|
||||
|
||||
var t = Object(this);
|
||||
var len = t.length >>> 0;
|
||||
if (typeof fun !== "function")
|
||||
throw new TypeError();
|
||||
|
||||
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
if (i in t)
|
||||
fun.call(thisArg, t[i], i, t);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Production steps of ECMA-262, Edition 5, 15.4.4.19
|
||||
// Reference: http://es5.github.com/#x15.4.4.19
|
||||
if (!Array.prototype.map) {
|
||||
Array.prototype.map = function(callback, thisArg) {
|
||||
|
||||
var T, A, k;
|
||||
|
||||
if (this == null) {
|
||||
throw new TypeError(" this is null or not defined");
|
||||
}
|
||||
|
||||
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
|
||||
var O = Object(this);
|
||||
|
||||
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
|
||||
// 3. Let len be ToUint32(lenValue).
|
||||
var len = O.length >>> 0;
|
||||
|
||||
// 4. If IsCallable(callback) is false, throw a TypeError exception.
|
||||
// See: http://es5.github.com/#x9.11
|
||||
if (typeof callback !== "function") {
|
||||
throw new TypeError(callback + " is not a function");
|
||||
}
|
||||
|
||||
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
if (thisArg) {
|
||||
T = thisArg;
|
||||
}
|
||||
|
||||
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
|
||||
// the standard built-in constructor with that name and len is the value of len.
|
||||
A = new Array(len);
|
||||
|
||||
// 7. Let k be 0
|
||||
k = 0;
|
||||
|
||||
// 8. Repeat, while k < len
|
||||
while(k < len) {
|
||||
|
||||
var kValue, mappedValue;
|
||||
|
||||
// a. Let Pk be ToString(k).
|
||||
// This is implicit for LHS operands of the in operator
|
||||
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
|
||||
// This step can be combined with c
|
||||
// c. If kPresent is true, then
|
||||
if (k in O) {
|
||||
|
||||
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
|
||||
kValue = O[ k ];
|
||||
|
||||
// ii. Let mappedValue be the result of calling the Call internal method of callback
|
||||
// with T as the this value and argument list containing kValue, k, and O.
|
||||
mappedValue = callback.call(T, kValue, k, O);
|
||||
|
||||
// iii. Call the DefineOwnProperty internal method of A with arguments
|
||||
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
|
||||
// and false.
|
||||
|
||||
// In browsers that support Object.defineProperty, use the following:
|
||||
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
|
||||
|
||||
// For best browser support, use the following:
|
||||
A[ k ] = mappedValue;
|
||||
}
|
||||
// d. Increase k by 1.
|
||||
k++;
|
||||
}
|
||||
|
||||
// 9. return A
|
||||
return A;
|
||||
};
|
||||
}
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
|
||||
if (!Array.prototype.indexOf) {
|
||||
Array.prototype.indexOf = function (searchElement, fromIndex) {
|
||||
if ( this === undefined || this === null ) {
|
||||
throw new TypeError( '"this" is null or not defined' );
|
||||
}
|
||||
|
||||
var length = this.length >>> 0; // Hack to convert object.length to a UInt32
|
||||
|
||||
fromIndex = +fromIndex || 0;
|
||||
|
||||
if (Math.abs(fromIndex) === Infinity) {
|
||||
fromIndex = 0;
|
||||
}
|
||||
|
||||
if (fromIndex < 0) {
|
||||
fromIndex += length;
|
||||
if (fromIndex < 0) {
|
||||
fromIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (;fromIndex < length; fromIndex++) {
|
||||
if (this[fromIndex] === searchElement) {
|
||||
return fromIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
|
||||
|
||||
if (! Array.isArray) {
|
||||
Array.isArray = function(obj) {
|
||||
return Object.prototype.toString.call(obj) === "[object Array]";
|
||||
};
|
||||
}
|
||||
|
||||
// https://github.com/ttaubert/node-arraybuffer-slice
|
||||
// (c) 2013 Tim Taubert <tim@timtaubert.de>
|
||||
// arraybuffer-slice may be freely distributed under the MIT license.
|
||||
|
||||
"use strict";
|
||||
|
||||
if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
|
||||
ArrayBuffer.prototype.slice = function (begin, end) {
|
||||
begin = (begin|0) || 0;
|
||||
var num = this.byteLength;
|
||||
end = end === (void 0) ? num : (end|0);
|
||||
|
||||
// Handle negative values.
|
||||
if (begin < 0) begin += num;
|
||||
if (end < 0) end += num;
|
||||
|
||||
if (num === 0 || begin >= num || begin >= end) {
|
||||
return new ArrayBuffer(0);
|
||||
}
|
||||
|
||||
var length = Math.min(num - begin, end - begin);
|
||||
var target = new ArrayBuffer(length);
|
||||
var targetArray = new Uint8Array(target);
|
||||
targetArray.set(new Uint8Array(this, begin, length));
|
||||
return target;
|
||||
};
|
||||
}
|
||||
|
||||
// https://github.com/davidchambers/Base64.js
|
||||
// (C) 2015 David Chambers
|
||||
// Base64.js may be freely distributed under the Apache 2.0 License.
|
||||
;(function () {
|
||||
|
||||
var object =
|
||||
typeof exports != 'undefined' ? exports :
|
||||
typeof self != 'undefined' ? self : // #8: web workers
|
||||
$.global; // #31: ExtendScript
|
||||
|
||||
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||
|
||||
function InvalidCharacterError(message) {
|
||||
this.message = message;
|
||||
}
|
||||
InvalidCharacterError.prototype = new Error;
|
||||
InvalidCharacterError.prototype.name = 'InvalidCharacterError';
|
||||
|
||||
// encoder
|
||||
// [https://gist.github.com/999166] by [https://github.com/nignag]
|
||||
object.btoa || (
|
||||
object.btoa = function (input) {
|
||||
var str = String(input);
|
||||
for (
|
||||
// initialize result and counter
|
||||
var block, charCode, idx = 0, map = chars, output = '';
|
||||
// if the next str index does not exist:
|
||||
// change the mapping table to "="
|
||||
// check if d has no fractional digits
|
||||
str.charAt(idx | 0) || (map = '=', idx % 1);
|
||||
// "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
|
||||
output += map.charAt(63 & block >> 8 - idx % 1 * 8)
|
||||
) {
|
||||
charCode = str.charCodeAt(idx += 3/4);
|
||||
if (charCode > 0xFF) {
|
||||
throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
|
||||
}
|
||||
block = block << 8 | charCode;
|
||||
}
|
||||
return output;
|
||||
});
|
||||
|
||||
// decoder
|
||||
// [https://gist.github.com/1020396] by [https://github.com/atk]
|
||||
object.atob || (
|
||||
object.atob = function (input) {
|
||||
var str = String(input).replace(/[=]+$/, ''); // #31: ExtendScript bad parse of /=
|
||||
if (str.length % 4 == 1) {
|
||||
throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
|
||||
}
|
||||
for (
|
||||
// initialize result and counters
|
||||
var bc = 0, bs, buffer, idx = 0, output = '';
|
||||
// get next character
|
||||
buffer = str.charAt(idx++);
|
||||
// character found in table? initialize bit storage and add its ascii value;
|
||||
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
|
||||
// and if not first of each 4 characters,
|
||||
// convert the first 8 bits to one ascii character
|
||||
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
|
||||
) {
|
||||
// try to find character in table (0-63, not found => -1)
|
||||
buffer = chars.indexOf(buffer);
|
||||
}
|
||||
return output;
|
||||
});
|
||||
}());
|
||||
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
|
||||
if (!Date.prototype.toISOString) {
|
||||
(function() {
|
||||
|
||||
function pad(number) {
|
||||
if (number < 10) {
|
||||
return '0' + number;
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
Date.prototype.toISOString = function() {
|
||||
return this.getUTCFullYear() +
|
||||
'-' + pad(this.getUTCMonth() + 1) +
|
||||
'-' + pad(this.getUTCDate()) +
|
||||
'T' + pad(this.getUTCHours()) +
|
||||
':' + pad(this.getUTCMinutes()) +
|
||||
':' + pad(this.getUTCSeconds()) +
|
||||
'.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) +
|
||||
'Z';
|
||||
};
|
||||
|
||||
}());
|
||||
}
|
||||
|
||||
// note: MDN shim will not work in IE
|
||||
if(typeof Uint8Array !== 'undefined' && !Uint8Array.prototype.slice) Uint8Array.prototype.slice = function(start, end) {
|
||||
if(start < 0) { start += this.length; if(start < 0) start = 0; }
|
||||
if(start >= this.length) return new Uint8Array(0);
|
||||
if(end == null) end = this.length;
|
||||
if(end < 0) { end += this.length; if(end < 0) end = 0; }
|
||||
if(end > this.length) end = this.length;
|
||||
var out = new Uint8Array(end - start);
|
||||
while(start <= --end) out[end - start] = this[end];
|
||||
return out;
|
||||
if(typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) ArrayBuffer.prototype.slice = function(start, end) {
|
||||
if(start == null) start = 0;
|
||||
if(start < 0) { start += this.byteLength; if(start < 0) start = 0; }
|
||||
if(start >= this.byteLength) return new Uint8Array(0);
|
||||
if(end == null) end = this.byteLength;
|
||||
if(end < 0) { end += this.byteLength; if(end < 0) end = 0; }
|
||||
if(end > this.byteLength) end = this.byteLength;
|
||||
if(start > end) return new Uint8Array(0);
|
||||
var out = new ArrayBuffer(end - start);
|
||||
var view = new Uint8Array(out);
|
||||
var data = new Uint8Array(this, start, end - start)
|
||||
/* IE10 should have Uint8Array#set */
|
||||
if(view.set) view.set(data); else while(start <= --end) view[end - start] = data[end];
|
||||
return out;
|
||||
};
|
||||
if(typeof Uint8Array !== 'undefined' && !Uint8Array.prototype.slice) Uint8Array.prototype.slice = function(start, end) {
|
||||
if(start == null) start = 0;
|
||||
if(start < 0) { start += this.length; if(start < 0) start = 0; }
|
||||
if(start >= this.length) return new Uint8Array(0);
|
||||
if(end == null) end = this.length;
|
||||
if(end < 0) { end += this.length; if(end < 0) end = 0; }
|
||||
if(end > this.length) end = this.length;
|
||||
if(start > end) return new Uint8Array(0);
|
||||
var out = new Uint8Array(end - start);
|
||||
while(start <= --end) out[end - start] = this[end];
|
||||
return out;
|
||||
};
|
||||
|
||||
// VBScript + ActiveX fallback for IE5+
|
||||
var IE_SaveFile = (function() { try {
|
||||
if(typeof IE_SaveFile_Impl == "undefined") document.write([
|
||||
'<script type="text/vbscript" language="vbscript">',
|
||||
'IE_GetProfileAndPath_Key = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\"',
|
||||
'Function IE_GetProfileAndPath(key): Set wshell = CreateObject("WScript.Shell"): IE_GetProfileAndPath = wshell.RegRead(IE_GetProfileAndPath_Key & key): IE_GetProfileAndPath = wshell.ExpandEnvironmentStrings("%USERPROFILE%") & "!" & IE_GetProfileAndPath: End Function',
|
||||
'Function IE_SaveFile_Impl(FileName, payload): Dim data, plen, i, bit: data = CStr(payload): plen = Len(data): Set fso = CreateObject("Scripting.FileSystemObject"): fso.CreateTextFile FileName, True: Set f = fso.GetFile(FileName): Set stream = f.OpenAsTextStream(2, 0): For i = 1 To plen Step 3: bit = Mid(data, i, 2): stream.write Chr(CLng("&h" & bit)): Next: stream.Close: IE_SaveFile_Impl = True: End Function',
|
||||
'|/script>'.replace("|","<")
|
||||
].join("\r\n"));
|
||||
if(typeof IE_SaveFile_Impl == "undefined") return void 0;
|
||||
var IE_GetPath = (function() {
|
||||
var DDP1 = "";
|
||||
try { DDP1 = IE_GetProfileAndPath("{374DE290-123F-4565-9164-39C4925E467B}"); } catch(e) { try { DDP1 = IE_GetProfileAndPath("Personal"); } catch(e) { try { DDP1 = IE_GetProfileAndPath("Desktop"); } catch(e) { throw e; }}}
|
||||
var o = DDP1.split("!");
|
||||
DDP = o[1].replace("%USERPROFILE%", o[0]);
|
||||
return function(path) { return DDP + "\\" + path; };
|
||||
})();
|
||||
function fix_data(data) {
|
||||
var out = [];
|
||||
var T = typeof data == "string";
|
||||
for(var i = 0; i < data.length; ++i) out.push(("00"+(T ? data.charCodeAt(i) : data[i]).toString(16)).slice(-2));
|
||||
var o = out.join("|");
|
||||
return o;
|
||||
}
|
||||
return function(data, filename) { return IE_SaveFile_Impl(IE_GetPath(filename), fix_data(data)); };
|
||||
} catch(e) { return void 0; }})();
|
||||
var IE_LoadFile = (function() { try {
|
||||
if(typeof IE_LoadFile_Impl == "undefined") document.write([
|
||||
'<script type="text/vbscript" language="vbscript">',
|
||||
'Function IE_LoadFile_Impl(FileName): Dim out(), plen, i, cc: Set fso = CreateObject("Scripting.FileSystemObject"): Set f = fso.GetFile(FileName): Set stream = f.OpenAsTextStream(1, 0): plen = f.Size: ReDim out(plen): For i = 1 To plen Step 1: cc = Hex(Asc(stream.read(1))): If Len(cc) < 2 Then: cc = "0" & cc: End If: out(i) = cc: Next: IE_LoadFile_Impl = Join(out,""): End Function',
|
||||
'|/script>'.replace("|","<")
|
||||
].join("\r\n"));
|
||||
if(typeof IE_LoadFile_Impl == "undefined") return void 0;
|
||||
function fix_data(data) {
|
||||
var out = [];
|
||||
for(var i = 0; i < data.length; i+=2) out.push(String.fromCharCode(parseInt(data.slice(i, i+2), 16)));
|
||||
var o = out.join("");
|
||||
return o;
|
||||
}
|
||||
return function(filename) { return fix_data(IE_LoadFile_Impl(filename)); };
|
||||
} catch(e) { return void 0; }})();
|
||||
|
||||
// getComputedStyle polyfill from https://gist.github.com/8HNHoFtE/5891086
|
||||
if(typeof window !== 'undefined' && typeof window.getComputedStyle !== 'function') {
|
||||
window.getComputedStyle = function(e,t){return this.el=e,this.getPropertyValue=function(t){var n=/(\-([a-z]){1})/g;return t=="float"&&(t="styleFloat"),n.test(t)&&(t=t.replace(n,function(){return arguments[2].toUpperCase()})),e.currentStyle[t]?e.currentStyle[t]:null},this}
|
||||
}
|
||||
|
224
test.js
224
test.js
@ -1,6 +1,7 @@
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint mocha:true */
|
||||
/* eslint-env mocha */
|
||||
/*global process, require */
|
||||
/*::
|
||||
declare type EmptyFunc = (() => void) | null;
|
||||
@ -11,9 +12,11 @@ declare var before:(test:EmptyFunc)=>void;
|
||||
*/
|
||||
var CFB;
|
||||
var fs = require('fs');
|
||||
describe('source', function() { it('should load', function() { CFB = require('./'); }); });
|
||||
describe('source', function() { it('should load', function() { CFB = require('./'); if(zlibify) CFB.utils.use_zlib(require("zlib")); }); });
|
||||
var CRC32 = require('crc-32');
|
||||
|
||||
var WTF = !!process.env.WTF;
|
||||
var zlibify = !!process.env.ZLIB;
|
||||
var ex = [".xls",".doc",".ppt"];
|
||||
if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;});
|
||||
if(process.env.FMTS === "full") process.env.FMTS = ex.join(":");
|
||||
@ -25,68 +28,113 @@ var files = fs.readdirSync('test_files').filter(ffunc);
|
||||
var f2011 = fs.readdirSync('test_files/2011').filter(ffunc);
|
||||
var f2013 = fs.readdirSync('test_files/2013').filter(ffunc);
|
||||
var fpres = fs.readdirSync('test_files_pres').filter(ffunc);
|
||||
var fxlsx = fs.readdirSync('test_files').filter(function(x) { return x.slice(-5) == ".xlsx" && fails.indexOf(x) === -1; });
|
||||
|
||||
var dir = "./test_files/";
|
||||
var TYPE = "buffer";
|
||||
|
||||
var names = [
|
||||
var names/*:Array<Array<string>>*/ = [
|
||||
["!DocumentSummaryInformation", "\u0005"],
|
||||
["!SummaryInformation", "\u0005"],
|
||||
["!CompObj", "\u0001"],
|
||||
["!DataSpaces", "\u0006"],
|
||||
["/!DataSpaces/Version", "\u0006"],
|
||||
["!DRMContent", "\u0009"],
|
||||
["!DRMViewerContent", "\u0009"],
|
||||
["!Ole", "\u0001"]
|
||||
].map(function(x) { return [x[0], x[0].replace("!", x[1])]; });
|
||||
|
||||
/* [ rel, abs ] */
|
||||
var ENTRIES/*:Array<Array<string>>*/ = [
|
||||
/* DOC */
|
||||
["WordDocument", "/WordDocument"],
|
||||
/* PPT */
|
||||
["PowerPoint Document", "/PowerPoint Document"],
|
||||
/* XLS */
|
||||
["Workbook", "/Workbook"],
|
||||
["Book", "/Book"],
|
||||
/* OPC */
|
||||
["[Content_Types].xml", "/[Content_Types].xml"],
|
||||
/* ODF */
|
||||
["content.xml", "/content.xml"],
|
||||
/* XLSX */
|
||||
["workbook.xml", "/xl/workbook.xml"],
|
||||
/* Encrypted */
|
||||
["EncryptedPackage", "/EncryptedPackage"],
|
||||
["EncryptionInfo", "/EncryptionInfo"]
|
||||
];
|
||||
|
||||
var REL_FILES = ENTRIES.map(function(e) { return e[0]; });
|
||||
var ABS_FILES = ENTRIES.map(function(e) { return e[1]; });
|
||||
|
||||
function has_file(cfb, files/*:Array<string>*/)/*:string*/ {
|
||||
for(var i = 0; i < files.length; ++i) if(CFB.find(cfb, files[i])) return files[i];
|
||||
return "";
|
||||
}
|
||||
|
||||
function zero_dates(cfb) {
|
||||
cfb.FileIndex.forEach(function(f) { delete f.mt; delete f.ct; });
|
||||
}
|
||||
|
||||
function parsetest(x, cfb) {
|
||||
describe(x + ' should have basic parts', function() {
|
||||
it('should find relative path', function() {
|
||||
switch(x.substr(-4)) {
|
||||
case '.xls': if(!CFB.find(cfb, 'Workbook') && !CFB.find(cfb, 'Book')) throw new Error("Cannot find workbook for " + x); break;
|
||||
case '.ppt': if(!CFB.find(cfb, 'PowerPoint Document')) throw new Error("Cannot find presentation for " + x); break;
|
||||
case '.doc': if(!CFB.find(cfb, 'WordDocument') && !CFB.find(cfb, 'Word Document')) throw new Error("Cannot find doc for " + x); break;
|
||||
}
|
||||
if(!has_file(cfb, REL_FILES)) throw new Error("Cannot find content for " + x);
|
||||
});
|
||||
it('should find absolute path', function() {
|
||||
switch(x.substr(-4)) {
|
||||
case '.xls': if(!CFB.find(cfb, '/Workbook') && !CFB.find(cfb, '/Book')) throw new Error("Cannot find workbook for " + x); break;
|
||||
case '.ppt': if(!CFB.find(cfb, '/PowerPoint Document')) throw new Error("Cannot find presentation for " + x); break;
|
||||
case '.doc': if(!CFB.find(cfb, '/WordDocument') && !CFB.find(cfb, '/Word Document')) throw new Error("Cannot find doc for " + x); break;
|
||||
}
|
||||
if(!has_file(cfb, ABS_FILES)) throw new Error("Cannot find content for " + x);
|
||||
});
|
||||
it('should handle "!" aliases', function() {
|
||||
names.forEach(function(n) { if(CFB.find(cfb,n[0]) != CFB.find(cfb,n[1])) throw new Error("Bad name: " + n.join(" != ")); });
|
||||
});
|
||||
it('should handle size < 0', function() {
|
||||
cfb.FileIndex.forEach(function(p, i) { if(p.size < 0) throw new Error(cfb.FullPaths[i] + " size=" + p.size); });
|
||||
});
|
||||
});
|
||||
describe(x + ' should roundtrip', function() {
|
||||
var data, newcfb;
|
||||
it('should roundtrip safely', function() {
|
||||
data = CFB.write(cfb, {type:TYPE});
|
||||
newcfb = CFB.read(data, {type:TYPE});
|
||||
var datacfb, newcfb;
|
||||
var datazip, newzip;
|
||||
var datacmp, newcmp;
|
||||
before(function() {
|
||||
/* cfb */
|
||||
zero_dates(cfb);
|
||||
datacfb = CFB.write(cfb, {type:TYPE});
|
||||
newcfb = CFB.read(datacfb, {type:TYPE});
|
||||
zero_dates(newcfb);
|
||||
|
||||
/* zip */
|
||||
zero_dates(cfb);
|
||||
datazip = CFB.write(cfb, {type:TYPE, fileType:"zip"});
|
||||
newzip = CFB.read(datazip, {type:TYPE});
|
||||
zero_dates(newzip);
|
||||
|
||||
/* zip with compression */
|
||||
zero_dates(cfb);
|
||||
datacmp = CFB.write(cfb, {type:TYPE, fileType:"zip", compression:1});
|
||||
newcmp = CFB.read(datacmp, {type:TYPE});
|
||||
zero_dates(newcmp);
|
||||
});
|
||||
it('should preserve content', function() {
|
||||
var _old, _new;
|
||||
switch(x.substr(-4)) {
|
||||
case '.xls':
|
||||
_old = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book');
|
||||
_new = CFB.find(newcfb, '/Workbook') || CFB.find(newcfb, '/Book');
|
||||
break;
|
||||
case '.ppt':
|
||||
_old = CFB.find(cfb, '/PowerPoint Document');
|
||||
_new = CFB.find(newcfb, '/PowerPoint Document');
|
||||
break;
|
||||
case '.doc':
|
||||
_old = CFB.find(cfb, '/WordDocument') || CFB.find(cfb, '/Word Document');
|
||||
_new = CFB.find(newcfb, '/WordDocument') || CFB.find(newcfb, '/Word Document');
|
||||
break;
|
||||
}
|
||||
/*:: if(!_old || !_new) throw "unreachable"; */
|
||||
if(CRC32.buf(_old.content) != CRC32.buf(_new.content)) throw new Error(x + " failed roundtrip test");
|
||||
var path = has_file(cfb, REL_FILES);
|
||||
var _old = CFB.find(cfb, path);
|
||||
var _cfb = CFB.find(newcfb, path);
|
||||
var _zip = CFB.find(newzip, path);
|
||||
var _cmp = CFB.find(newcmp, path);
|
||||
/*:: if(!_old || !_cfb || !_zip || !_cmp) throw "unreachable"; */
|
||||
var c1 = CRC32.buf(_old.content);
|
||||
var c2 = CRC32.buf(_cfb.content);
|
||||
var c3 = CRC32.buf(_zip.content);
|
||||
var c4 = CRC32.buf(_cmp.content);
|
||||
if(c1 != c2) throw new Error(x + " failed CFB roundtrip test");
|
||||
if(c1 != c3) throw new Error(x + " failed ZIP roundtrip test");
|
||||
if(c1 != c4) throw new Error(x + " failed ZIP compression roundtrip test");
|
||||
});
|
||||
it('should be idempotent', function() {
|
||||
var dat2 = CFB.write(newcfb, {type:TYPE});
|
||||
if(CRC32.buf(data) != CRC32.buf(dat2)) throw new Error(x + " failed idempotent test");
|
||||
if(CRC32.buf(datacfb) != CRC32.buf(dat2)) throw new Error(x + " failed CFB idempotent test");
|
||||
var dat2zip = CFB.write(newzip, {type:TYPE, fileType:"zip"});
|
||||
if(CRC32.buf(datazip) != CRC32.buf(dat2zip)) throw new Error(x + " failed ZIP idempotent test");
|
||||
var dat2cmp = CFB.write(newcmp, {type:TYPE, fileType:"zip", compression:1});
|
||||
if(CRC32.buf(datacmp) != CRC32.buf(dat2cmp)) throw new Error(x + " failed ZIP idempotent test");
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -94,40 +142,136 @@ function parsetest(x, cfb) {
|
||||
describe('should parse test files', function() {
|
||||
files.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
var cfb = CFB.read('./test_files/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
});
|
||||
});
|
||||
fpres.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
var cfb = CFB.read('./test_files_pres/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files_pres/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
});
|
||||
});
|
||||
f2011.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
var cfb = CFB.read('./test_files/2011/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files/2011/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
});
|
||||
});
|
||||
f2013.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
var cfb = CFB.read('./test_files/2013/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files/2013/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
});
|
||||
});
|
||||
fxlsx.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
try {
|
||||
var cfb = CFB.read('./test_files/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
} catch(e) {
|
||||
if(e.message.match(/CFB file size /)) return;
|
||||
if(!e.message.match(/Header Signature: Expected d0cf11e0a1b11ae1 saw /)) throw e;
|
||||
}
|
||||
});
|
||||
});
|
||||
it('should recognize correct magic number', function() {
|
||||
var cfb = CFB.read('./test_files/AutoFilter.xls', {type: "file"});
|
||||
if(!CFB.find(cfb, '!CompObj')) throw new Error("Could not find !CompObj");
|
||||
if(!CFB.find(cfb, '\u0001CompObj')) throw new Error("Could not find 1CompObj");
|
||||
if(CFB.find(cfb, '\u0005CompObj')) throw new Error("Found 5CompObj");
|
||||
|
||||
if(!CFB.find(cfb, '!DocumentSummaryInformation')) throw new Error("Could not find !DSI");
|
||||
if(!CFB.find(cfb, '\u0005DocumentSummaryInformation')) throw new Error("Could not find 5DSI");
|
||||
if(CFB.find(cfb, '\u0001DocumentSummaryInformation')) throw new Error("Found 1DSI");
|
||||
});
|
||||
});
|
||||
|
||||
var cp = 'custom_properties.xls';
|
||||
|
||||
var xl = 'custom_properties.xlsx';
|
||||
describe('input formats', function() {
|
||||
it('should read binary strings', function() {
|
||||
CFB.read(fs.readFileSync(dir + '/' + cp, 'binary'), {type: 'binary'});
|
||||
CFB.read(fs.readFileSync(dir + '/' + xl, 'binary'), {type: 'binary'});
|
||||
});
|
||||
it('should read base64 strings', function() {
|
||||
CFB.read(fs.readFileSync(dir + '/' + cp, 'base64'), {type: 'base64'});
|
||||
CFB.read(fs.readFileSync(dir + '/' + xl, 'base64'), {type: 'base64'});
|
||||
});
|
||||
it('should read buffers', function() {
|
||||
CFB.read(fs.readFileSync(dir + '/' + cp), {type: 'buffer'});
|
||||
CFB.read(fs.readFileSync(dir + '/' + xl), {type: 'buffer'});
|
||||
});
|
||||
});
|
||||
describe('output formats', function() {
|
||||
it('should write binary strings', function() {
|
||||
var t = [
|
||||
[ "CFB", CFB.write(CFB.read(fs.readFileSync(dir + '/' + cp, 'binary'), {type: 'binary'}), {type: 'binary'})],
|
||||
[ "ZIP", CFB.write(CFB.read(fs.readFileSync(dir + '/' + xl, 'binary'), {type: 'binary'}), {type: 'binary', fileType: 'zip'})]
|
||||
];
|
||||
t.forEach(function(r) {
|
||||
if(typeof r[1] != "string") throw new Error(r[0] + " binary write failed");
|
||||
var good = false;
|
||||
for(var i = 0; i < r[1].length; ++i) {
|
||||
if(/*::((*/r[1]/*:: :any):string)*/.charCodeAt(i) == 0x00) good = true;
|
||||
else if(/*::((*/r[1]/*:: :any):string)*/.charCodeAt(i) > 0xFF) { good = false; break; }
|
||||
}
|
||||
if(!good) throw new Error(r[0] + " binary write failed");
|
||||
});
|
||||
});
|
||||
it('should write base64 strings', function() {
|
||||
var t = [
|
||||
[ "CFB", CFB.write(CFB.read(fs.readFileSync(dir + '/' + cp, 'base64'), {type: 'base64'}), {type: 'base64'})],
|
||||
[ "ZIP", CFB.write(CFB.read(fs.readFileSync(dir + '/' + xl, 'base64'), {type: 'base64'}), {type: 'base64', fileType: 'zip'})]
|
||||
];
|
||||
t.forEach(function(r) {
|
||||
if(typeof r[1] != "string") throw new Error(r[0] + " base64 write failed");
|
||||
var good = false;
|
||||
if(r[1].match(/[^a-zA-Z0-9+\/\+\.=]/)) throw new Error(r[0] + " base64 write failed");
|
||||
});
|
||||
});
|
||||
it('should write buffers', function() {
|
||||
var t1 = CFB.write(CFB.read(fs.readFileSync(dir + '/' + cp), {type: 'buffer'}), {type: 'buffer'});
|
||||
var t2 = CFB.write(CFB.read(fs.readFileSync(dir + '/' + xl), {type: 'buffer'}), {type: 'buffer'});
|
||||
if(!Buffer.isBuffer(t1)) throw new Error("CFB buffer write failed");
|
||||
if(!Buffer.isBuffer(t2)) throw new Error("ZIP buffer write failed");
|
||||
});
|
||||
});
|
||||
|
||||
describe('api', function() {
|
||||
it('should generate a file with custom root', function() {
|
||||
var cfb = CFB.utils.cfb_new({root:'SheetJS'});
|
||||
if(cfb.FileIndex[0].name != 'SheetJS') throw new Error("Bad root name");
|
||||
var newcfb = CFB.read(CFB.write(cfb, {type:'base64'}), {type:'base64'});
|
||||
if(newcfb.FileIndex[0].name != 'SheetJS') throw new Error("Bad root name");
|
||||
});
|
||||
it('should be able to delete a file', function() {
|
||||
var cfb = CFB.read(fs.readFileSync(dir + '/' + cp, 'binary'), {type: 'binary'});
|
||||
if(!CFB.find(cfb, '/Workbook')) throw new Error("Cannot find /Workbook");
|
||||
CFB.utils.cfb_del(cfb, '/Workbook');
|
||||
if(CFB.utils.cfb_del(cfb, '/Workbook')) throw new Error("Found /Workbook");
|
||||
if(CFB.find(cfb, '/Workbook')) throw new Error("Failed deleting /Workbook");
|
||||
var newcfb = CFB.read(CFB.write(cfb, {type:'binary'}), {type:'binary'});
|
||||
if(CFB.find(newcfb, '/Workbook')) throw new Error("Found /Workbook");
|
||||
});
|
||||
it('should be able to move a file', function() {
|
||||
var cfb = CFB.read(fs.readFileSync(dir + '/' + cp, 'binary'), {type: 'binary'});
|
||||
if(!CFB.find(cfb, '/Workbook')) throw new Error("Cannot find /Workbook");
|
||||
CFB.utils.cfb_mov(cfb, '/Workbook', '/Book');
|
||||
if(CFB.utils.cfb_mov(cfb, '/Workbook', '/Work')) throw new Error("Found /Workbook");
|
||||
if(CFB.find(cfb, '/Workbook')) throw new Error("Failed deleting /Workbook");
|
||||
var newcfb = CFB.read(CFB.write(cfb, {type:'binary'}), {type:'binary'});
|
||||
if(CFB.find(newcfb, '/Workbook')) throw new Error("Found /Workbook");
|
||||
});
|
||||
it('should be able to add a file', function() {
|
||||
var cfb = CFB.read(fs.readFileSync(dir + '/' + cp, 'binary'), {type: 'binary'});
|
||||
CFB.utils.cfb_add(cfb, '/dafuq', [1,2,3]);
|
||||
var newcfb = CFB.read(CFB.write(cfb, {type:'binary'}), {type:'binary'});
|
||||
var file = CFB.find(cfb, '/dafuq');
|
||||
if(!file || !file.content) throw new Error("Cannot find /dafuq");
|
||||
if(file.content.length != 3) throw new Error("Bad content length " + file.content.length);
|
||||
file = CFB.find(newcfb, '/dafuq');
|
||||
if(!file || !file.content) throw new Error("Cannot find /dafuq");
|
||||
if(file.content.length != 3) throw new Error("Bad content length " + file.content.length);
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* vim: set ts=2 ft=javascript: */
|
||||
/// <reference types="../node_modules/@types/node" />
|
||||
const n = "cfb";
|
||||
import * as X from 'cfb';
|
||||
import fs = require('fs');
|
||||
@ -10,13 +11,14 @@ const sprintf = PRINTJ.sprintf;
|
||||
program
|
||||
.version(X.version)
|
||||
.usage('[options] <file> [subfiles...]')
|
||||
.option('-q, --quiet', 'process but do not report')
|
||||
.option('-l, --list-files', 'list files')
|
||||
.option('-z, --dump', 'dump internal representation but do not extract')
|
||||
.option('-r, --repair', 'attempt to repair and garbage-collect archive')
|
||||
.option('-c, --create', 'create file')
|
||||
.option('-a, --append', 'add files to CFB (overwrite existing data)')
|
||||
.option('-d, --delete', 'delete files from CFB')
|
||||
.option('-O, --to-stdout', 'extract raw contents to stdout')
|
||||
.option('-z, --dump', 'dump internal representation but do not extract')
|
||||
.option('-q, --quiet', 'process but do not report')
|
||||
.option('--dev', 'development mode')
|
||||
.option('--read', 'read but do not print out contents');
|
||||
|
||||
@ -36,10 +38,10 @@ if(program.create) {
|
||||
|
||||
if(!fs.existsSync(program.args[0])) die(1, "must specify a filename");
|
||||
|
||||
const opts: X.CFBParsingOptions = {type:'file'};
|
||||
const opts: X.CFB$ParsingOptions = {type:'file'};
|
||||
if(program.dev) opts.WTF = true;
|
||||
|
||||
const cfb: X.CFBContainer = X.read(program.args[0], opts);
|
||||
const cfb: X.CFB$Container = X.read(program.args[0], opts);
|
||||
if(program.quiet) exit(0);
|
||||
|
||||
if(program.dump) {
|
||||
@ -61,7 +63,7 @@ if(program.listFiles) {
|
||||
let cnt = 0, rootsize = 0, filesize = 0;
|
||||
console.log(" Length Date Time Name");
|
||||
console.log(" -------- ---- ---- ----");
|
||||
cfb.FileIndex.forEach((file: X.CFBEntry, i: number) => {
|
||||
cfb.FileIndex.forEach((file: X.CFB$Entry, i: number) => {
|
||||
switch(file.type) {
|
||||
case 5:
|
||||
basetime = file.ct || file.mt || basetime;
|
||||
@ -85,7 +87,7 @@ const mkdirp = (path: string) => { path.split("/").reduce((acc: string, p: strin
|
||||
return acc;
|
||||
}, ""); };
|
||||
|
||||
const write = (path: string, data: X.CFBEntry) => {
|
||||
const write = (path: string, data: X.CFB$Entry) => {
|
||||
logit("write", fix_string(path));
|
||||
fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/);
|
||||
};
|
||||
@ -110,16 +112,18 @@ if(program.delete) {
|
||||
|
||||
if(program.args.length > 1) {
|
||||
program.args.slice(1).forEach((x: string) => {
|
||||
const data/*:?CFBEntry*/ = X.find(cfb, x);
|
||||
const data: X.CFB$Entry = X.find(cfb, x.replace(/\\u000\d/g,"!"));
|
||||
if(!data) { console.error(x + ": file not found"); return; }
|
||||
if(data.type !== 2) { console.error(x + ": not a file"); return; }
|
||||
const idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx];
|
||||
if(program.toStdout) return process.stdout.write(new Buffer(<any>data.content));
|
||||
mkdirp(path.slice(0, path.lastIndexOf("/")));
|
||||
write(path, data);
|
||||
});
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(program.toStdout) exit(0);
|
||||
for(let i=0; i!==cfb.FullPaths.length; ++i) {
|
||||
if(!cfb.FileIndex[i].name) continue;
|
||||
if(cfb.FullPaths[i].slice(-1) === "/") mkdirp(cfb.FullPaths[i]);
|
||||
|
142
types/index.d.ts
vendored
142
types/index.d.ts
vendored
@ -5,100 +5,124 @@
|
||||
export const version: string;
|
||||
|
||||
/** Parse a buffer or array */
|
||||
export function parse(f: CFB$Blob, options?: CFBParsingOptions): CFBContainer;
|
||||
export function parse(f: CFB$Blob, options?: CFB$ParsingOptions): CFB$Container;
|
||||
|
||||
/** Read a blob or file or binary string */
|
||||
export function read(f: CFB$Blob | string, options?: CFBParsingOptions): CFBContainer;
|
||||
export function read(f: CFB$Blob | string, options?: CFB$ParsingOptions): CFB$Container;
|
||||
|
||||
/** Find a file entry given a path or file name */
|
||||
export function find(cfb: CFBContainer, path: string): CFBEntry | null;
|
||||
export function find(cfb: CFB$Container, path: string): CFB$Entry | null;
|
||||
|
||||
/** Generate a container file */
|
||||
export function write(cfb: CFBContainer, options?: any): any;
|
||||
export function write(cfb: CFB$Container, options?: CFB$WritingOptions): any;
|
||||
|
||||
/** Write a container file to the filesystem */
|
||||
export function writeFile(cfb: CFBContainer, filename: string, options?: any): any;
|
||||
export function writeFile(cfb: CFB$Container, filename: string, options?: CFB$WritingOptions): any;
|
||||
|
||||
/** Utility functions */
|
||||
export const utils: CFB$Utils;
|
||||
|
||||
export interface CFB$CommonOptions {
|
||||
/** Data encoding */
|
||||
type?: 'base64' | 'binary' | 'buffer' | 'file' | 'array';
|
||||
|
||||
/** Options for read and readFile */
|
||||
export interface CFBParsingOptions {
|
||||
/** Input data encoding */
|
||||
type?: 'base64' | 'binary' | 'buffer' | 'file' | 'array';
|
||||
/** If true, throw errors when features are not understood */
|
||||
WTF?: boolean;
|
||||
/** If true, include raw data in output */
|
||||
raw?: boolean;
|
||||
/** If true, throw errors when features are not understood */
|
||||
WTF?: boolean;
|
||||
}
|
||||
|
||||
export type CFB$Blob = Buffer | number[] | Uint8Array;
|
||||
/** Options for read and readFile */
|
||||
export interface CFB$ParsingOptions extends CFB$CommonOptions {
|
||||
/** If true, include raw data in output */
|
||||
raw?: boolean;
|
||||
}
|
||||
|
||||
export enum CFBEntryType { unknown, storage, stream, lockbytes, property, root }
|
||||
export enum CFBStorageType { fat, minifat }
|
||||
/** Options for write and writeFile */
|
||||
export interface CFB$WritingOptions extends CFB$CommonOptions {
|
||||
/** Output file type */
|
||||
fileType?: 'cfb' | 'zip' | 'mad';
|
||||
|
||||
/** Override default root entry name (CFB only) */
|
||||
root?: string;
|
||||
|
||||
/** Enable compression (ZIP only) */
|
||||
compression?: boolean;
|
||||
}
|
||||
|
||||
export type CFB$Blob = number[] | Uint8Array;
|
||||
|
||||
export enum CFB$EntryType { unknown, storage, stream, lockbytes, property, root }
|
||||
export enum CFB$StorageType { fat, minifat }
|
||||
|
||||
/** CFB File Entry Object */
|
||||
export interface CFBEntry {
|
||||
/** Case-sensitive internal name */
|
||||
name: string;
|
||||
export interface CFB$Entry {
|
||||
/** Case-sensitive internal name */
|
||||
name: string;
|
||||
|
||||
/** CFB type (salient types: stream, storage) -- see CFBEntryType */
|
||||
type: number;
|
||||
/** CFB type (salient types: stream, storage) -- see CFB$EntryType */
|
||||
type: number;
|
||||
|
||||
/** Raw Content (Buffer when available, Array of bytes otherwise) */
|
||||
content: CFB$Blob;
|
||||
/** Raw Content (Buffer when available, Array of bytes otherwise) */
|
||||
content: CFB$Blob;
|
||||
|
||||
/** Creation Time */
|
||||
ct?: Date;
|
||||
/** Creation Time */
|
||||
ct?: Date;
|
||||
|
||||
/** Modification Time */
|
||||
mt?: Date;
|
||||
/** Modification Time */
|
||||
mt?: Date;
|
||||
|
||||
/** Red/Black Tree color: 0 = red, 1 = black */
|
||||
color: number;
|
||||
/** Red/Black Tree color: 0 = red, 1 = black */
|
||||
color: number;
|
||||
|
||||
/** Class ID represented as hex string */
|
||||
clsid: string;
|
||||
/** Class ID represented as hex string */
|
||||
clsid: string;
|
||||
|
||||
/** User-Defined State Bits */
|
||||
state: number;
|
||||
/** User-Defined State Bits */
|
||||
state: number;
|
||||
|
||||
/** Starting Sector */
|
||||
start: number;
|
||||
/** Starting Sector */
|
||||
start: number;
|
||||
|
||||
/** Data Size */
|
||||
size: number;
|
||||
/** Data Size */
|
||||
size: number;
|
||||
|
||||
/** Storage location -- see CFBStorageType */
|
||||
storage?: string;
|
||||
/** Storage location -- see CFB$StorageType */
|
||||
storage?: string;
|
||||
|
||||
/** Content Type (used for MAD) */
|
||||
ctype?: string;
|
||||
}
|
||||
|
||||
/* File object */
|
||||
export interface CFBContainer {
|
||||
/* list of streams and storages */
|
||||
FullPaths: string[];
|
||||
export interface CFB$Container {
|
||||
/* List of streams and storages */
|
||||
FullPaths: string[];
|
||||
|
||||
/* Array of entries in the same order as FullPaths */
|
||||
FileIndex: CFBEntry[];
|
||||
/* Array of entries in the same order as FullPaths */
|
||||
FileIndex: CFB$Entry[];
|
||||
|
||||
/* Raw Content, in chunks (Buffer when available, Array of bytes otherwise) */
|
||||
raw?: {
|
||||
header: CFB$Blob,
|
||||
sectors: CFB$Blob[];
|
||||
};
|
||||
/* Raw Content, in chunks (Buffer when available, Array of bytes otherwise) */
|
||||
raw?: {
|
||||
header: CFB$Blob,
|
||||
sectors: CFB$Blob[];
|
||||
};
|
||||
}
|
||||
|
||||
/** cfb_add options */
|
||||
export interface CFB$AddOpts {
|
||||
/** Skip existence and safety checks (best for bulk write operations) */
|
||||
unsafe?: boolean;
|
||||
}
|
||||
|
||||
/** General utilities */
|
||||
export interface CFB$Utils {
|
||||
cfb_new(opts?: any): CFBContainer;
|
||||
cfb_add(cfb: CFBContainer, name: string, content: any, opts?: any): CFBEntry;
|
||||
cfb_del(cfb: CFBContainer, name: string): boolean;
|
||||
cfb_mov(cfb: CFBContainer, old_name: string, new_name: string): boolean;
|
||||
cfb_gc(cfb: CFBContainer): void;
|
||||
ReadShift(size: number, t?: string): number|string;
|
||||
WarnField(hexstr: string, fld?: string): void;
|
||||
CheckField(hexstr: string, fld?: string): void;
|
||||
prep_blob(blob: any, pos?: number): CFB$Blob;
|
||||
bconcat(bufs: any[]): any;
|
||||
cfb_new(opts?: any): CFB$Container;
|
||||
cfb_add(cfb: CFB$Container, name: string, content: any, opts?: CFB$AddOpts): CFB$Entry;
|
||||
cfb_del(cfb: CFB$Container, name: string): boolean;
|
||||
cfb_mov(cfb: CFB$Container, old_name: string, new_name: string): boolean;
|
||||
cfb_gc(cfb: CFB$Container): void;
|
||||
ReadShift(size: number, t?: string): number|string;
|
||||
WarnField(hexstr: string, fld?: string): void;
|
||||
CheckField(hexstr: string, fld?: string): void;
|
||||
prep_blob(blob: any, pos?: number): CFB$Blob;
|
||||
bconcat(bufs: any[]): any;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ const old_cfb = CFB.read("t2.xls", {type:"file"});
|
||||
const new_cfb = CFB.utils.cfb_new({root:"R", clsid: old_cfb.FileIndex[0].clsid });
|
||||
old_cfb.FullPaths.forEach((p, i) => {
|
||||
if(p.slice(-1) === "/") return;
|
||||
CFB.utils.cfb_add(new_cfb, p.replace(/^[^/]*/,"R"), old_cfb.FileIndex[i].content);
|
||||
CFB.utils.cfb_add(new_cfb, p.replace(/^[^/]*/,"R"), old_cfb.FileIndex[i].content, {unsafe: true});
|
||||
});
|
||||
dumpit(new_cfb);
|
||||
CFB.writeFile(new_cfb, "t3.xls");
|
||||
|
@ -9,6 +9,7 @@
|
||||
"paths": { "cfb": ["."] },
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"strictFunctionTypes": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
"only-arrow-functions": false,
|
||||
"no-consecutive-blank-lines": false,
|
||||
"prefer-conditional-expression": false,
|
||||
"one-variable-per-declaration": false
|
||||
"one-variable-per-declaration": false,
|
||||
"no-implicit-dependencies": false,
|
||||
"prefer-template": false
|
||||
}
|
||||
}
|
||||
|
1236
xlscfb.flow.js
1236
xlscfb.flow.js
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user