Compare commits

...

18 Commits

Author SHA1 Message Date
John Shearer b01260294e Truncate stream names to 31 characters
fixes https://github.com/SheetJS/js-cfb/issues/18
2022-11-10 10:35:49 +00:00
SheetJS 5a5870eb1b replace git.io links 2022-04-27 01:46:46 -04:00
SheetJS ad93f76a36 version bump 1.2.2 2022-04-06 02:45:11 -04:00
SheetJS 0e33eb6e13 unify changes with main sheetjs project
- Fixed issue #14 h/t @wisekaa03
- CFB write truncate file names exceeding 32 characters

Co-authored-by: Stanislav Vyaliy <wisekaa03@gmail.com>
2022-03-31 04:57:58 -04:00
SheetJS c5eb7e6278 testing 2022-03-30 13:27:33 -04:00
Christophe Coevoet 99990abf64
Remove unused dependency
The printj package is used only by the cli package.
2022-03-30 09:51:13 +02:00
reviewher 4d8ef18b10
ExtendScript 2021-10-09 17:49:35 -04:00
SheetJS 1e70aae159 version bump 1.2.1: DEFLATE 2021-09-06 15:53:23 -04:00
Ross Johnson efb96a2c2c Use Buffer.copy() if available to write file contents to final CFB Buf 2021-09-05 13:24:57 -04:00
Ross Johnson 4c7b78f9dc Use map when creating CFB storage list (fixes #12) 2021-09-04 19:48:09 -04:00
SheetJS 76e4603fa5 version bump 1.2.0: MAD 2020-07-09 02:20:52 -04:00
Garrett Luu 1a1920c567 CLI refactor 2020-06-25 19:57:40 -07:00
SheetJS 7c1980741a version bump 1.1.4: detect sector cycle (fixes #8) 2020-03-13 01:58:41 -04:00
SheetJS 6367acfd8a Included full license text [ci skip] 2019-10-07 23:13:37 -04:00
SheetJS aff6d67444 version bump 1.1.3: crc32 checksum signed 2019-08-04 15:55:35 -04:00
SheetJS 8756cc9b41 version bump 1.1.2: tree fix h/t @rossj 2019-07-20 18:10:48 -04:00
SheetJS 8d85fb6e74 version bump 1.1.1: skip CLSID chk (h/t @xjnotxj) 2019-06-10 08:44:27 -04:00
Ross Johnson 62bd08588e Fixes #5 2018-12-12 13:50:04 -05:00
59 changed files with 5131 additions and 1462 deletions

91
.github/workflows/node-4+.yml vendored Normal file
View 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
View 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
View 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
View 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'

3
.gitignore vendored
View File

@ -26,7 +26,8 @@ test_files_pres
*.[rR][tT][fF]
*.[eE][tT][hH]
*.[zZ][iI][pP]
*.[mM][sS][iI]
*.[mM][sS][iIgG]
*.[mM][hH][tT]
*.123
*.htm
*.html

View File

@ -1,5 +1,10 @@
language: node_js
dist: xenial
node_js:
- "14"
- "13"
- "12"
- "11"
- "10"
- "9"
- "8"
@ -11,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"

View File

@ -4,6 +4,18 @@ 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

190
LICENSE
View File

@ -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.

View File

@ -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:
@ -46,13 +46,15 @@ init: ## Initial setup for development
.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,23 +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) $(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
dtslint types
./node_modules/.bin/dtslint types
.PHONY: flow
flow: lint ## Run flow checker

View File

@ -22,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
@ -44,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
@ -94,6 +74,7 @@ name, if there are no slashes) and returns an entry object or null if not found.
|------------|:----------------------------------------------------------------|
| `"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]`) |
@ -108,15 +89,17 @@ name, if there are no slashes) and returns an entry object or null if not found.
|------------|:----------------------------------------------------------------|
| `"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 |
| `fileType` | output |
|:-------------------|:------------------------|
| `'cfb'` (default) | CFB container |
| `'zip'` | ZIP file |
| `'mad'` | MIME aggregate document |
`opts.compression` enables DEFLATE compression for ZIP file type.
@ -131,7 +114,7 @@ accept a `name` argument strictly deal with absolute file names:
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.
- `.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`.
@ -157,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) */
}
```
@ -169,7 +153,9 @@ granted by the Apache 2.0 License are reserved by the Original Author.
## References
- [MS-CFB]: Compound File Binary File Format
- ZIP `APPNOTE.TXT`: https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.4.TXT
- `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

View File

@ -1,166 +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('-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]);
}
}

View File

@ -1,44 +1,36 @@
var Base64 = (function make_b64(){
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function(input/*:string*/)/*:string*/ {
var o = "";
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
for(var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
e1 = (c1 >> 2);
c2 = input.charCodeAt(i++);
e2 = ((c1 & 3) << 4) | (c2 >> 4);
c3 = input.charCodeAt(i++);
e3 = ((c2 & 15) << 2) | (c3 >> 6);
e4 = (c3 & 63);
if (isNaN(c2)) { e3 = e4 = 64; }
else if (isNaN(c3)) { e4 = 64; }
o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
}
return o;
},
decode: function b64_decode(input/*:string*/)/*:string*/ {
var o = "";
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
input = input.replace(/[^\w\+\/\=]/g, "");
for(var i = 0; i < input.length;) {
e1 = map.indexOf(input.charAt(i++));
e2 = map.indexOf(input.charAt(i++));
c1 = (e1 << 2) | (e2 >> 4);
o += String.fromCharCode(c1);
e3 = map.indexOf(input.charAt(i++));
c2 = ((e2 & 15) << 4) | (e3 >> 2);
if (e3 !== 64) { o += String.fromCharCode(c2); }
e4 = map.indexOf(input.charAt(i++));
c3 = ((e3 & 3) << 6) | e4;
if (e4 !== 64) { o += String.fromCharCode(c3); }
}
return o;
}
};
})();
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;
}

View File

@ -1,30 +1,33 @@
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 = /*::(*/function(){}/*:: :any)*/;
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() {};
})();
if(typeof Buffer !== 'undefined') {
var nbfs = !Buffer.from;
if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
Buffer_from = /*::((*/nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer)/*::) :any)*/;
// $FlowIgnore
if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
// $FlowIgnore
if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
}
function new_raw_buf(len/*:number*/) {
/* jshint -W056 */
return has_buf ? Buffer.alloc(len) : new 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 */
}
function new_unsafe_buf(len/*:number*/) {
/* jshint -W056 */
return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
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*/)/*:any*/ {
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; });
};

View File

@ -1,18 +1,15 @@
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported CRC32 */
var CRC32;
(function (factory) {
/*jshint ignore:start */
/*eslint-disable */
factory(CRC32 = {});
/*eslint-enable */
/*jshint ignore:end */
}(function(CRC32) {
CRC32.version = '1.2.0';
/* see perf/crc32table.js */
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()/*:any*/ {
function signed_crc_table()/*:CRC32TableType*/ {
var c = 0, table/*:Array<number>*/ = new Array(256);
for(var n =0; n != 256; ++n){
@ -31,71 +28,70 @@ function signed_crc_table()/*:any*/ {
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
}
var T = signed_crc_table();
function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1, L = bstr.length - 1;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
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];
}
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
return C ^ -1;
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(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
if(buf.length > 10000) return crc32_buf_8(buf, seed);
var C = seed ^ -1, L = buf.length - 3;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
function crc32_buf(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_buf_8(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1, L = buf.length - 7;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
}
function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1;
for(var i = 0, L=str.length, c, d; i < L;) {
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) ^ T[(C ^ c)&0xFF];
C = (C>>>8) ^ T0[(C^c)&0xFF];
} else if(c < 0x800) {
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
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) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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 ^ -1;
return ~C;
}
CRC32.table = T;
CRC32.table = T0;
CRC32.bstr = crc32_bstr;
CRC32.buf = crc32_buf;
CRC32.str = crc32_str;
}));
return CRC32;
})();

View File

@ -1,3 +1,3 @@
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var CFB = /*#__PURE__*/(function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;

View File

@ -1 +1 @@
exports.version = '1.1.0';
exports.version = '1.2.2';

View File

@ -1,5 +1,6 @@
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;

View File

@ -5,7 +5,8 @@ function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
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');

View File

@ -13,8 +13,8 @@ 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]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) 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) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -23,13 +23,12 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
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] += "/";

View File

@ -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*/);
}

View File

@ -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);

View File

@ -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];
}
}

View File

@ -1,4 +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);
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
switch(_opts.fileType) {
case 'zip': return write_zip(cfb, _opts);
//case 'mad': return write_mad(cfb, _opts);
}

View File

@ -3,7 +3,6 @@
for(var i = 0; i < cfb.FileIndex.length; ++i) {
var file = cfb.FileIndex[i];
if(!file.content) continue;
/*:: if(file.content == null) throw new Error("unreachable"); */
var flen = file.content.length;
if(flen > 0){
if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;

View File

@ -9,6 +9,10 @@
file = cfb.FileIndex[i];
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
var _nm/*:string*/ = (i === 0 && _opts.root) || file.name;
if(_nm.length > 31) {
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,31));
_nm = _nm.slice(0, 31);
}
flen = 2*(_nm.length+1);
o.write_shift(64, _nm, "utf16le");
o.write_shift(2, flen);

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -42,6 +42,38 @@ function read_bits_n(buf, bl, n) {
return v & f;
}
/* helpers for unaligned bit writes */
function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;
if(w <= 5) buf[h] |= (v & 7) << w;
else {
buf[h] |= (v << w) & 0xFF;
buf[h+1] = (v&7) >> (8-w);
}
return bl + 3;
}
function write_bits_1(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v = (v&1) << w;
buf[h] |= v;
return bl + 1;
}
function write_bits_8(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v;
return bl + 8;
}
function write_bits_16(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v & 0xFF;
buf[h+2] = v >>> 8;
return bl + 16;
}
/* until ArrayBuffer#realloc is a thing, fake a realloc */
function realloc(b, sz/*:number*/) {
var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
@ -55,7 +87,7 @@ function realloc(b, sz/*:number*/) {
} else if(use_typed_arrays) {
var a = new Uint8Array(M);
if(a.set) a.set(b);
else for(; i < b.length; ++i) a[i] = b[i];
else for(; i < L; ++i) a[i] = b[i];
return a;
}
b.length = M;
@ -67,4 +99,64 @@ 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);
})();

View File

@ -1,23 +1,117 @@
var _deflate = (function() {
var _deflateRaw = (function() {
return function deflateRaw(data, out) {
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;
/* TODO: this is only type 0 stored */
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
}
/* 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);
};
})();
return function(data) {
function _deflate(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
};
})();
}

View File

@ -1,64 +1,5 @@
/* modified inflate function also moves original read head */
/* build tree (used for literals and lengths) */
function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
for(i = 0; i < 32; ++i) bl_count[i] = 0;
for(i = L; i < MAX; ++i) clens[i] = 0;
L = clens.length;
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
/* build code tree */
for(i = 0; i < L; ++i) {
bl_count[(w = clens[i])]++;
if(maxlen < w) maxlen = w;
ctree[i] = 0;
}
bl_count[0] = 0;
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
for(i = 0; i < L; ++i) {
ccode = clens[i];
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
}
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
var cleni = 0;
for(i = 0; i < L; ++i) {
cleni = clens[i];
if(cleni != 0) {
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
}
}
return maxlen;
}
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);
})();
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);
@ -162,14 +103,12 @@ function inflate(data, usz/*:number*/) {
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
boff += 32;
/* push sz bytes */
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
if(typeof data.copy === 'function') {
// $FlowIgnore
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
woff += sz; boff += 8*sz;
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
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) {
} else if((header >> 1) == 1) {
/* Fixed Huffman */
max_len_1 = 9; max_len_2 = 5;
} else {
@ -177,8 +116,8 @@ function inflate(data, usz/*:number*/) {
boff = dyn(data, boff);
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
}
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
for(;;) { // while(true) is apparently out of vogue in modern JS circles
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
/* ingest code and move read head */
var bits = read_bits_n(data, boff, max_len_1);
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
@ -209,12 +148,13 @@ function inflate(data, usz/*:number*/) {
}
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
}
}
}
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
if(usz) return [outbuf, (boff+7)>>>3];
return [outbuf.slice(0, woff), (boff+7)>>>3];
}
function _inflate(payload, usz) {

View File

@ -82,7 +82,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
var data = blob.slice(blob.l, blob.l + _csz);
switch(meth) {
case 8: data = _inflateRawSync(blob, _usz); break;
case 0: break;
case 0: break; // TODO: scan for magic number
default: throw new Error("Unsupported ZIP Compression method " + meth);
}
@ -98,6 +98,6 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
var _crc32 = CRC32.buf(data, 0);
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
cfb_add(o, name, data, {unsafe: true, mt: date});
}

View File

@ -46,7 +46,10 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/
start_cd += namebuf.length;
out.push(namebuf);
/* TODO: extra fields? */
/* TODO: encryption header ? */
start_cd += outbuf.length;
out.push(outbuf);

206
bits/84_mht.js Normal file
View 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");
}

View File

@ -4,77 +4,72 @@
/*exported CFB */
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
var Base64 = (function make_b64(){
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function(input/*:string*/)/*:string*/ {
var o = "";
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
for(var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
e1 = (c1 >> 2);
c2 = input.charCodeAt(i++);
e2 = ((c1 & 3) << 4) | (c2 >> 4);
c3 = input.charCodeAt(i++);
e3 = ((c2 & 15) << 2) | (c3 >> 6);
e4 = (c3 & 63);
if (isNaN(c2)) { e3 = e4 = 64; }
else if (isNaN(c3)) { e4 = 64; }
o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
}
return o;
},
decode: function b64_decode(input/*:string*/)/*:string*/ {
var o = "";
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
input = input.replace(/[^\w\+\/\=]/g, "");
for(var i = 0; i < input.length;) {
e1 = map.indexOf(input.charAt(i++));
e2 = map.indexOf(input.charAt(i++));
c1 = (e1 << 2) | (e2 >> 4);
o += String.fromCharCode(c1);
e3 = map.indexOf(input.charAt(i++));
c2 = ((e2 & 15) << 4) | (e3 >> 2);
if (e3 !== 64) { o += String.fromCharCode(c2); }
e4 = map.indexOf(input.charAt(i++));
c3 = ((e3 & 3) << 6) | e4;
if (e4 !== 64) { o += String.fromCharCode(c3); }
}
return o;
}
};
})();
var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && process.versions.node);
var Buffer_from = /*::(*/function(){}/*:: :any)*/;
if(typeof Buffer !== 'undefined') {
var nbfs = !Buffer.from;
if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
Buffer_from = /*::((*/nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer)/*::) :any)*/;
// $FlowIgnore
if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
// $FlowIgnore
if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
var 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;
}
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 */
return has_buf ? Buffer.alloc(len) : new 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 */
}
function new_unsafe_buf(len/*:number*/) {
/* jshint -W056 */
return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
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*/)/*:any*/ {
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; });
};
@ -191,21 +186,18 @@ type SectorList = {
}
type CFBFiles = {[n:string]:CFBEntry};
*/
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported CRC32 */
var CRC32;
(function (factory) {
/*jshint ignore:start */
/*eslint-disable */
factory(CRC32 = {});
/*eslint-enable */
/*jshint ignore:end */
}(function(CRC32) {
CRC32.version = '1.2.0';
/* see perf/crc32table.js */
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()/*:any*/ {
function signed_crc_table()/*:CRC32TableType*/ {
var c = 0, table/*:Array<number>*/ = new Array(256);
for(var n =0; n != 256; ++n){
@ -224,78 +216,77 @@ function signed_crc_table()/*:any*/ {
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
}
var T = signed_crc_table();
function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1, L = bstr.length - 1;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
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];
}
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
return C ^ -1;
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(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
if(buf.length > 10000) return crc32_buf_8(buf, seed);
var C = seed ^ -1, L = buf.length - 3;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
function crc32_buf(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_buf_8(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1, L = buf.length - 7;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
}
function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1;
for(var i = 0, L=str.length, c, d; i < L;) {
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) ^ T[(C ^ c)&0xFF];
C = (C>>>8) ^ T0[(C^c)&0xFF];
} else if(c < 0x800) {
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
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) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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 ^ -1;
return ~C;
}
CRC32.table = T;
CRC32.table = T0;
CRC32.bstr = crc32_bstr;
CRC32.buf = crc32_buf;
CRC32.str = crc32_str;
}));
return CRC32;
})();
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var CFB = /*#__PURE__*/(function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '1.1.0';
exports.version = '1.2.2';
/* [MS-CFB] 2.6.4 */
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
var L = l.split("/"), R = r.split("/");
@ -385,6 +376,7 @@ var fs/*:: = require('fs'); */;
function get_fs() { return fs || (fs = require('fs')); }
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
if((file[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;
@ -490,7 +482,8 @@ function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
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');
@ -542,8 +535,8 @@ 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]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) 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) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -552,13 +545,12 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
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] += "/";
@ -594,7 +586,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);
}
}
@ -626,7 +618,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]);
@ -635,6 +629,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*/);
}
@ -703,9 +698,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);
@ -752,22 +751,34 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
if(!gc && !f) return;
var now = new Date(1987, 1, 19), j = 0;
// Track which names exist
var fullPaths = Object.create ? Object.create(null) : {};
var data/*:Array<[string, CFBEntry]>*/ = [];
for(i = 0; i < cfb.FullPaths.length; ++i) {
fullPaths[cfb.FullPaths[i]] = true;
if(cfb.FileIndex[i].type === 0) continue;
data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
}
for(i = 0; i < data.length; ++i) {
var dad = dirname(data[i][0]);
s = 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];
}
}
data.sort(function(x,y) { return namecmp(x[0], y[0]); });
@ -800,16 +811,20 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
}
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);
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
switch(_opts.fileType) {
case 'zip': return write_zip(cfb, _opts);
//case 'mad': return write_mad(cfb, _opts);
}
var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{
var mini_size = 0, fat_size = 0;
for(var i = 0; i < cfb.FileIndex.length; ++i) {
var file = cfb.FileIndex[i];
if(!file.content) continue;
/*:: if(file.content == null) throw new Error("unreachable"); */
var flen = file.content.length;
if(flen > 0){
if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
@ -900,6 +915,10 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
file = cfb.FileIndex[i];
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
var _nm/*:string*/ = (i === 0 && _opts.root) || file.name;
if(_nm.length > 32) {
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,32));
_nm = _nm.slice(0, 32);
}
flen = 2*(_nm.length+1);
o.write_shift(64, _nm, "utf16le");
o.write_shift(2, flen);
@ -921,19 +940,36 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
/*:: 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);
}
}
}
for(i = 1; i < cfb.FileIndex.length; ++i) {
file = cfb.FileIndex[i];
/*:: if(!file.content) throw new Error("unreachable"); */
if(file.size > 0 && file.size < 0x1000) {
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
for(; j & 0x3F; ++j) o.write_shift(1, 0);
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);
}
return o;
}
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
@ -997,10 +1033,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;
}
@ -1070,6 +1109,38 @@ function read_bits_n(buf, bl, n) {
return v & f;
}
/* helpers for unaligned bit writes */
function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;
if(w <= 5) buf[h] |= (v & 7) << w;
else {
buf[h] |= (v << w) & 0xFF;
buf[h+1] = (v&7) >> (8-w);
}
return bl + 3;
}
function write_bits_1(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v = (v&1) << w;
buf[h] |= v;
return bl + 1;
}
function write_bits_8(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v;
return bl + 8;
}
function write_bits_16(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v & 0xFF;
buf[h+2] = v >>> 8;
return bl + 16;
}
/* until ArrayBuffer#realloc is a thing, fake a realloc */
function realloc(b, sz/*:number*/) {
var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
@ -1083,7 +1154,7 @@ function realloc(b, sz/*:number*/) {
} else if(use_typed_arrays) {
var a = new Uint8Array(M);
if(a.set) a.set(b);
else for(; i < b.length; ++i) a[i] = b[i];
else for(; i < L; ++i) a[i] = b[i];
return a;
}
b.length = M;
@ -1095,30 +1166,7 @@ function zero_fill_array(n) {
var o = new Array(n);
for(var i = 0; i < n; ++i) o[i] = 0;
return o;
}var _deflate = (function() {
var _deflateRaw = (function() {
return function deflateRaw(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
/* TODO: this is only type 0 stored */
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
};
})();
return function(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
};
})();
/* modified inflate function also moves original read head */
}
/* build tree (used for literals and lengths) */
function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
@ -1158,6 +1206,7 @@ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
return maxlen;
}
/* Fixed Huffman */
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
if(!use_typed_arrays) {
@ -1177,8 +1226,125 @@ if(!use_typed_arrays) {
for(; i<=279; i++) clens.push(7);
for(; i<=287; i++) clens.push(8);
build_tree(clens, fix_lmap, 288);
})();var _deflateRaw = /*#__PURE__*/(function _deflateRawIIFE() {
var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];
var j = 0, k = 0;
for(; j < DST_LN.length - 1; ++j) {
for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;
}
for(;k < 32768; ++k) DST_LN_RE[k] = 29;
var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];
for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {
for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;
}
function write_stored(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
}
/* Fixed Huffman */
function write_huff_fixed(data, out) {
var bl = 0;
var boff = 0;
var addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];
while(boff < data.length) {
var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);
/* write a stored block for short data */
if(L < 10) {
bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line
if(bl & 7) bl += 8 - (bl & 7);
out.l = (bl / 8) | 0;
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
bl = out.l * 8;
continue;
}
bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line
var hash = 0;
while(L-- > 0) {
var d = data[boff];
hash = ((hash << 5) ^ d) & 0x7FFF;
var match = -1, mlen = 0;
if((match = addrs[hash])) {
match |= boff & ~0x7FFF;
if(match > boff) match -= 0x8000;
if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;
}
if(mlen > 2) {
/* Copy Token */
d = LEN_LN_RE[mlen];
if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;
else {
write_bits_8(out, bl, 3);
bl += 5;
write_bits_8(out, bl, bitswap8[d-23]>>5);
bl += 3;
}
var len_eb = (d < 8) ? 0 : ((d - 4)>>2);
if(len_eb > 0) {
write_bits_16(out, bl, mlen - LEN_LN[d]);
bl += len_eb;
}
d = DST_LN_RE[boff - match];
bl = write_bits_8(out, bl, bitswap8[d]>>3);
bl -= 3;
var dst_eb = d < 4 ? 0 : (d-2)>>1;
if(dst_eb > 0) {
write_bits_16(out, bl, boff - match - DST_LN[d]);
bl += dst_eb;
}
for(var q = 0; q < mlen; ++q) {
addrs[hash] = boff & 0x7FFF;
hash = ((hash << 5) ^ data[boff]) & 0x7FFF;
++boff;
}
L-= mlen - 1;
} else {
/* Literal Token */
if(d <= 143) d = d + 48;
else bl = write_bits_1(out, bl, 1);
bl = write_bits_8(out, bl, bitswap8[d]);
addrs[hash] = boff & 0x7FFF;
++boff;
}
}
bl = write_bits_8(out, bl, 0) - 1;
}
out.l = ((bl + 7)/8)|0;
return out.l;
}
return function _deflateRaw(data, out) {
if(data.length < 8) return write_stored(data, out);
return write_huff_fixed(data, out);
};
})();
function _deflate(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
}
/* modified inflate function also moves original read head */
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
@ -1282,14 +1448,12 @@ function inflate(data, usz/*:number*/) {
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
boff += 32;
/* push sz bytes */
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
if(typeof data.copy === 'function') {
// $FlowIgnore
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
woff += sz; boff += 8*sz;
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
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) {
} else if((header >> 1) == 1) {
/* Fixed Huffman */
max_len_1 = 9; max_len_2 = 5;
} else {
@ -1297,8 +1461,8 @@ function inflate(data, usz/*:number*/) {
boff = dyn(data, boff);
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
}
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
for(;;) { // while(true) is apparently out of vogue in modern JS circles
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
/* ingest code and move read head */
var bits = read_bits_n(data, boff, max_len_1);
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
@ -1329,12 +1493,13 @@ function inflate(data, usz/*:number*/) {
}
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
}
}
}
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
if(usz) return [outbuf, (boff+7)>>>3];
return [outbuf.slice(0, woff), (boff+7)>>>3];
}
function _inflate(payload, usz) {
@ -1428,7 +1593,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
var data = blob.slice(blob.l, blob.l + _csz);
switch(meth) {
case 8: data = _inflateRawSync(blob, _usz); break;
case 0: break;
case 0: break; // TODO: scan for magic number
default: throw new Error("Unsupported ZIP Compression method " + meth);
}
@ -1444,7 +1609,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
var _crc32 = CRC32.buf(data, 0);
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
cfb_add(o, name, data, {unsafe: true, mt: date});
}
function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
@ -1495,7 +1660,10 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/
start_cd += namebuf.length;
out.push(namebuf);
/* TODO: extra fields? */
/* TODO: encryption header ? */
start_cd += outbuf.length;
out.push(outbuf);
@ -1549,6 +1717,212 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/
return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
}
var ContentTypeMap = ({
"htm": "text/html",
"xml": "text/xml",
"gif": "image/gif",
"jpg": "image/jpeg",
"png": "image/png",
"mso": "application/x-mso",
"thmx": "application/vnd.ms-officetheme",
"sh33tj5": "application/octet-stream"
}/*:any*/);
function get_content_type(fi/*:CFBEntry*/, fp/*:string*/)/*:string*/ {
if(fi.ctype) return fi.ctype;
var ext = fi.name || "", m = ext.match(/\.([^\.]+)$/);
if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];
if(fp) {
m = (ext = fp).match(/[\.\\]([^\.\\])+$/);
if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];
}
return "application/octet-stream";
}
/* 76 character chunks TODO: intertwine encoding */
function write_base64_76(bstr/*:string*/)/*:string*/ {
var data = Base64_encode(bstr);
var o = [];
for(var i = 0; i < data.length; i+= 76) o.push(data.slice(i, i+76));
return o.join("\r\n") + "\r\n";
}
/*
Rules for QP:
- escape =## applies for all non-display characters and literal "="
- space or tab at end of line must be encoded
- \r\n newlines can be preserved, but bare \r and \n must be escaped
- lines must not exceed 76 characters, use soft breaks =\r\n
TODO: Some files from word appear to write line extensions with bare equals:
```
<table class=3DMsoTableGrid border=3D1 cellspacing=3D0 cellpadding=3D0 width=
="70%"
```
*/
function write_quoted_printable(text/*:string*/)/*:string*/ {
var encoded = text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF=]/g, function(c) {
var w = c.charCodeAt(0).toString(16).toUpperCase();
return "=" + (w.length == 1 ? "0" + w : w);
});
encoded = encoded.replace(/ $/mg, "=20").replace(/\t$/mg, "=09");
if(encoded.charAt(0) == "\n") encoded = "=0D" + encoded.slice(1);
encoded = encoded.replace(/\r(?!\n)/mg, "=0D").replace(/\n\n/mg, "\n=0A").replace(/([^\r\n])\n/mg, "$1=0A");
var o/*:Array<string>*/ = [], split = encoded.split("\r\n");
for(var si = 0; si < split.length; ++si) {
var str = split[si];
if(str.length == 0) { o.push(""); continue; }
for(var i = 0; i < str.length;) {
var end = 76;
var tmp = str.slice(i, i + end);
if(tmp.charAt(end - 1) == "=") end --;
else if(tmp.charAt(end - 2) == "=") end -= 2;
else if(tmp.charAt(end - 3) == "=") end -= 3;
tmp = str.slice(i, i + end);
i += end;
if(i < str.length) tmp += "=";
o.push(tmp);
}
}
return o.join("\r\n");
}
function parse_quoted_printable(data/*:Array<string>*/)/*:RawBytes*/ {
var o = [];
/* unify long lines */
for(var di = 0; di < data.length; ++di) {
var line = data[di];
while(di <= data.length && line.charAt(line.length - 1) == "=") line = line.slice(0, line.length - 1) + data[++di];
o.push(line);
}
/* decode */
for(var oi = 0; oi < o.length; ++oi) o[oi] = o[oi].replace(/[=][0-9A-Fa-f]{2}/g, function($$) { return String.fromCharCode(parseInt($$.slice(1), 16)); });
return s2a(o.join("\r\n"));
}
function parse_mime(cfb/*:CFBContainer*/, data/*:Array<string>*/, root/*:string*/)/*:void*/ {
var fname = "", cte = "", ctype = "", fdata;
var di = 0;
for(;di < 10; ++di) {
var line = data[di];
if(!line || line.match(/^\s*$/)) break;
var m = line.match(/^(.*?):\s*([^\s].*)$/);
if(m) switch(m[1].toLowerCase()) {
case "content-location": fname = m[2].trim(); break;
case "content-type": ctype = m[2].trim(); break;
case "content-transfer-encoding": cte = m[2].trim(); break;
}
}
++di;
switch(cte.toLowerCase()) {
case 'base64': fdata = s2a(Base64_decode(data.slice(di).join(""))); break;
case 'quoted-printable': fdata = parse_quoted_printable(data.slice(di)); break;
default: throw new Error("Unsupported Content-Transfer-Encoding " + cte);
}
var file = cfb_add(cfb, fname.slice(root.length), fdata, {unsafe: true});
if(ctype) file.ctype = ctype;
}
function parse_mad(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
if(a2s(file.slice(0,13)).toLowerCase() != "mime-version:") throw new Error("Unsupported MAD header");
var root = (options && options.root || "");
// $FlowIgnore
var data = (has_buf && Buffer.isBuffer(file) ? file.toString("binary") : a2s(file)).split("\r\n");
var di = 0, row = "";
/* if root is not specified, scan for the common prefix */
for(di = 0; di < data.length; ++di) {
row = data[di];
if(!/^Content-Location:/i.test(row)) continue;
row = row.slice(row.indexOf("file"));
if(!root) root = row.slice(0, row.lastIndexOf("/") + 1);
if(row.slice(0, root.length) == root) continue;
while(root.length > 0) {
root = root.slice(0, root.length - 1);
root = root.slice(0, root.lastIndexOf("/") + 1);
if(row.slice(0,root.length) == root) break;
}
}
var mboundary = (data[1] || "").match(/boundary="(.*?)"/);
if(!mboundary) throw new Error("MAD cannot find boundary");
var boundary = "--" + (mboundary[1] || "");
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
var o = {
FileIndex: FileIndex,
FullPaths: FullPaths
};
init_cfb(o);
var start_di, fcnt = 0;
for(di = 0; di < data.length; ++di) {
var line = data[di];
if(line !== boundary && line !== boundary + "--") continue;
if(fcnt++) parse_mime(o, data.slice(start_di, di), root);
start_di = di;
}
return o;
}
function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ {
var opts = options || {};
var boundary = opts.boundary || "SheetJS";
boundary = '------=' + boundary;
var out = [
'MIME-Version: 1.0',
'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"',
'',
'',
''
];
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
for(var i = 1; i < cfb.FullPaths.length; ++i) {
fp = cfb.FullPaths[i].slice(root.length);
fi = cfb.FileIndex[i];
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
/* Normalize filename */
fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) {
return "_x" + c.charCodeAt(0).toString(16) + "_";
}).replace(/[\u0080-\uFFFF]/g, function(u) {
return "_u" + u.charCodeAt(0).toString(16) + "_";
});
/* Extract content as binary string */
var ca = fi.content;
// $FlowIgnore
var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca);
/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */
var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;
for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;
var qp = dispcnt >= L * 4 / 5;
out.push(boundary);
out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);
out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));
out.push('Content-Type: ' + get_content_type(fi, fp));
out.push('');
out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));
}
out.push(boundary + '--\r\n');
return out.join("\r\n");
}
function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
var o/*:CFBContainer*/ = ({}/*:any*/);
init_cfb(o, opts);

745
cfb.js
View File

@ -4,73 +4,68 @@
/*exported CFB */
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
var Base64 = (function make_b64(){
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function(input) {
var o = "";
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
for(var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
e1 = (c1 >> 2);
c2 = input.charCodeAt(i++);
e2 = ((c1 & 3) << 4) | (c2 >> 4);
c3 = input.charCodeAt(i++);
e3 = ((c2 & 15) << 2) | (c3 >> 6);
e4 = (c3 & 63);
if (isNaN(c2)) { e3 = e4 = 64; }
else if (isNaN(c3)) { e4 = 64; }
o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
}
return o;
},
decode: function b64_decode(input) {
var o = "";
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
input = input.replace(/[^\w\+\/\=]/g, "");
for(var i = 0; i < input.length;) {
e1 = map.indexOf(input.charAt(i++));
e2 = map.indexOf(input.charAt(i++));
c1 = (e1 << 2) | (e2 >> 4);
o += String.fromCharCode(c1);
e3 = map.indexOf(input.charAt(i++));
c2 = ((e2 & 15) << 4) | (e3 >> 2);
if (e3 !== 64) { o += String.fromCharCode(c2); }
e4 = map.indexOf(input.charAt(i++));
c3 = ((e3 & 3) << 6) | e4;
if (e4 !== 64) { o += String.fromCharCode(c3); }
}
return o;
}
};
})();
var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && process.versions.node);
var Buffer_from = function(){};
if(typeof Buffer !== 'undefined') {
var nbfs = !Buffer.from;
if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
// $FlowIgnore
if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
// $FlowIgnore
if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
var Base64_map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function Base64_encode(input) {
var o = "";
var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;
for (var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
e1 = (c1 >> 2);
c2 = input.charCodeAt(i++);
e2 = ((c1 & 3) << 4) | (c2 >> 4);
c3 = input.charCodeAt(i++);
e3 = ((c2 & 15) << 2) | (c3 >> 6);
e4 = (c3 & 63);
if (isNaN(c2)) e3 = e4 = 64;
else if (isNaN(c3)) e4 = 64;
o += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4);
}
return o;
}
function Base64_decode(input) {
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;
}
var has_buf = (function() { return typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node; })();
var Buffer_from = (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) {
/* jshint -W056 */
return has_buf ? Buffer.alloc(len) : new 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 */
}
function new_unsafe_buf(len) {
/* jshint -W056 */
return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
if(has_buf) return Buffer.allocUnsafe ? Buffer.allocUnsafe(len) : new Buffer(len);
return typeof Uint8Array != "undefined" ? new Uint8Array(len) : new Array(len);
/* jshint +W056 */
}
@ -173,19 +168,12 @@ function new_buf(sz) {
return o;
}
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported CRC32 */
var CRC32;
(function (factory) {
/*jshint ignore:start */
/*eslint-disable */
factory(CRC32 = {});
/*eslint-enable */
/*jshint ignore:end */
}(function(CRC32) {
CRC32.version = '1.2.0';
/* see perf/crc32table.js */
var CRC32 = (function() {
var CRC32 = {};
CRC32.version = '1.2.1';
/*global Int32Array */
function signed_crc_table() {
var c = 0, table = new Array(256);
@ -206,78 +194,77 @@ function signed_crc_table() {
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
}
var T = signed_crc_table();
var T0 = signed_crc_table();
function slice_by_16_tables(T) {
var c = 0, v = 0, n = 0, table = 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, seed) {
var C = seed ^ -1, L = bstr.length - 1;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
}
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
return C ^ -1;
var C = seed ^ -1;
for(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF];
return ~C;
}
function crc32_buf(buf, seed) {
if(buf.length > 10000) return crc32_buf_8(buf, seed);
var C = seed ^ -1, L = buf.length - 3;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
}
function crc32_buf_8(buf, seed) {
var C = seed ^ -1, L = buf.length - 7;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
function crc32_buf(B, seed) {
var C = seed ^ -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, seed) {
var C = seed ^ -1;
for(var i = 0, L=str.length, c, d; i < L;) {
for(var i = 0, L = str.length, c = 0, d = 0; i < L;) {
c = str.charCodeAt(i++);
if(c < 0x80) {
C = (C>>>8) ^ T[(C ^ c)&0xFF];
C = (C>>>8) ^ T0[(C^c)&0xFF];
} else if(c < 0x800) {
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
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) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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 ^ -1;
return ~C;
}
CRC32.table = T;
CRC32.table = T0;
CRC32.bstr = crc32_bstr;
CRC32.buf = crc32_buf;
CRC32.str = crc32_str;
}));
return CRC32;
})();
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports = {};
exports.version = '1.1.0';
exports.version = '1.2.2';
/* [MS-CFB] 2.6.4 */
function namecmp(l, r) {
var L = l.split("/"), R = r.split("/");
@ -367,6 +354,7 @@ var fs;
function get_fs() { return fs || (fs = require('fs')); }
function parse(file, options) {
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;
@ -472,7 +460,8 @@ function check_get_mver(blob) {
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 = blob.read_shift(2, 'u');
@ -524,8 +513,8 @@ function build_full_paths(FI, FP, Paths) {
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) 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) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -534,13 +523,12 @@ function build_full_paths(FI, FP, Paths) {
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] += "/";
@ -576,7 +564,7 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
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);
}
}
@ -608,7 +596,9 @@ function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
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]);
@ -617,6 +607,7 @@ function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
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])});
}
@ -685,9 +676,13 @@ function read_file(filename, options) {
}
function read(blob, options) {
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": return read_file(blob, options);
case "base64": return parse(s2a(Base64.decode(blob)), options);
case "base64": return parse(s2a(Base64_decode(blob)), options);
case "binary": return parse(s2a(blob), options);
}
return parse(blob, options);
@ -734,22 +729,34 @@ function rebuild_cfb(cfb, f) {
if(!gc && !f) return;
var now = new Date(1987, 1, 19), j = 0;
// Track which names exist
var fullPaths = Object.create ? Object.create(null) : {};
var data = [];
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
})]);
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
})]);
// Add name to set
fullPaths[dad] = true;
dad = dirname(data[i][0]);
s = fullPaths[dad];
}
}
data.sort(function(x,y) { return namecmp(x[0], y[0]); });
@ -784,14 +791,19 @@ function rebuild_cfb(cfb, f) {
function _write(cfb, options) {
var _opts = options || {};
/* MAD is order-sensitive, skip rebuild and sort */
if(_opts.fileType == 'mad') return write_mad(cfb, _opts);
rebuild_cfb(cfb);
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
switch(_opts.fileType) {
case 'zip': return write_zip(cfb, _opts);
//case 'mad': return write_mad(cfb, _opts);
}
var L = (function(cfb){
var mini_size = 0, fat_size = 0;
for(var i = 0; i < cfb.FileIndex.length; ++i) {
var file = cfb.FileIndex[i];
if(!file.content) continue;
var flen = file.content.length;
var flen = file.content.length;
if(flen > 0){
if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
else fat_size += (flen + 0x01FF) >> 9;
@ -879,6 +891,10 @@ flen = file.content.length;
file = cfb.FileIndex[i];
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
var _nm = (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);
@ -899,18 +915,35 @@ flen = file.content.length;
file = cfb.FileIndex[i];
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);
}
}
}
for(i = 1; i < cfb.FileIndex.length; ++i) {
file = cfb.FileIndex[i];
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);
}
return o;
}
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
@ -973,10 +1006,13 @@ function a2s(o) {
function write(cfb, options) {
var o = _write(cfb, options);
switch(options && options.type) {
switch(options && options.type || "buffer") {
case "file": get_fs(); fs.writeFileSync(options.filename, (o)); 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;
}
@ -1046,6 +1082,38 @@ function read_bits_n(buf, bl, n) {
return v & f;
}
/* helpers for unaligned bit writes */
function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;
if(w <= 5) buf[h] |= (v & 7) << w;
else {
buf[h] |= (v << w) & 0xFF;
buf[h+1] = (v&7) >> (8-w);
}
return bl + 3;
}
function write_bits_1(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v = (v&1) << w;
buf[h] |= v;
return bl + 1;
}
function write_bits_8(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v;
return bl + 8;
}
function write_bits_16(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v & 0xFF;
buf[h+2] = v >>> 8;
return bl + 16;
}
/* until ArrayBuffer#realloc is a thing, fake a realloc */
function realloc(b, sz) {
var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
@ -1059,7 +1127,7 @@ function realloc(b, sz) {
} else if(use_typed_arrays) {
var a = new Uint8Array(M);
if(a.set) a.set(b);
else for(; i < b.length; ++i) a[i] = b[i];
else for(; i < L; ++i) a[i] = b[i];
return a;
}
b.length = M;
@ -1071,30 +1139,7 @@ function zero_fill_array(n) {
var o = new Array(n);
for(var i = 0; i < n; ++i) o[i] = 0;
return o;
}var _deflate = (function() {
var _deflateRaw = (function() {
return function deflateRaw(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
/* TODO: this is only type 0 stored */
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
};
})();
return function(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
};
})();
/* modified inflate function also moves original read head */
}
/* build tree (used for literals and lengths) */
function build_tree(clens, cmap, MAX) {
@ -1134,6 +1179,7 @@ function build_tree(clens, cmap, MAX) {
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) {
@ -1153,8 +1199,125 @@ if(!use_typed_arrays) {
for(; i<=279; i++) clens.push(7);
for(; i<=287; i++) clens.push(8);
build_tree(clens, fix_lmap, 288);
})();var _deflateRaw = (function _deflateRawIIFE() {
var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];
var j = 0, k = 0;
for(; j < DST_LN.length - 1; ++j) {
for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;
}
for(;k < 32768; ++k) DST_LN_RE[k] = 29;
var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];
for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {
for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;
}
function write_stored(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
}
/* Fixed Huffman */
function write_huff_fixed(data, out) {
var bl = 0;
var boff = 0;
var addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];
while(boff < data.length) {
var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);
/* write a stored block for short data */
if(L < 10) {
bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line
if(bl & 7) bl += 8 - (bl & 7);
out.l = (bl / 8) | 0;
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
bl = out.l * 8;
continue;
}
bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line
var hash = 0;
while(L-- > 0) {
var d = data[boff];
hash = ((hash << 5) ^ d) & 0x7FFF;
var match = -1, mlen = 0;
if((match = addrs[hash])) {
match |= boff & ~0x7FFF;
if(match > boff) match -= 0x8000;
if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;
}
if(mlen > 2) {
/* Copy Token */
d = LEN_LN_RE[mlen];
if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;
else {
write_bits_8(out, bl, 3);
bl += 5;
write_bits_8(out, bl, bitswap8[d-23]>>5);
bl += 3;
}
var len_eb = (d < 8) ? 0 : ((d - 4)>>2);
if(len_eb > 0) {
write_bits_16(out, bl, mlen - LEN_LN[d]);
bl += len_eb;
}
d = DST_LN_RE[boff - match];
bl = write_bits_8(out, bl, bitswap8[d]>>3);
bl -= 3;
var dst_eb = d < 4 ? 0 : (d-2)>>1;
if(dst_eb > 0) {
write_bits_16(out, bl, boff - match - DST_LN[d]);
bl += dst_eb;
}
for(var q = 0; q < mlen; ++q) {
addrs[hash] = boff & 0x7FFF;
hash = ((hash << 5) ^ data[boff]) & 0x7FFF;
++boff;
}
L-= mlen - 1;
} else {
/* Literal Token */
if(d <= 143) d = d + 48;
else bl = write_bits_1(out, bl, 1);
bl = write_bits_8(out, bl, bitswap8[d]);
addrs[hash] = boff & 0x7FFF;
++boff;
}
}
bl = write_bits_8(out, bl, 0) - 1;
}
out.l = ((bl + 7)/8)|0;
return out.l;
}
return function _deflateRaw(data, out) {
if(data.length < 8) return write_stored(data, out);
return write_huff_fixed(data, out);
};
})();
function _deflate(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
}
/* modified inflate function also moves original read head */
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
@ -1258,14 +1421,12 @@ function inflate(data, usz) {
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
boff += 32;
/* push sz bytes */
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
if(typeof data.copy === 'function') {
// $FlowIgnore
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
woff += sz; boff += 8*sz;
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
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) {
} else if((header >> 1) == 1) {
/* Fixed Huffman */
max_len_1 = 9; max_len_2 = 5;
} else {
@ -1273,8 +1434,8 @@ function inflate(data, usz) {
boff = dyn(data, boff);
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
}
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
for(;;) { // while(true) is apparently out of vogue in modern JS circles
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
/* ingest code and move read head */
var bits = read_bits_n(data, boff, max_len_1);
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
@ -1305,12 +1466,13 @@ function inflate(data, usz) {
}
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
}
}
}
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
if(usz) return [outbuf, (boff+7)>>>3];
return [outbuf.slice(0, woff), (boff+7)>>>3];
}
function _inflate(payload, usz) {
@ -1404,7 +1566,7 @@ function parse_local_file(blob, csz, usz, o, EF) {
var data = blob.slice(blob.l, blob.l + _csz);
switch(meth) {
case 8: data = _inflateRawSync(blob, _usz); break;
case 0: break;
case 0: break; // TODO: scan for magic number
default: throw new Error("Unsupported ZIP Compression method " + meth);
}
@ -1420,7 +1582,7 @@ function parse_local_file(blob, csz, usz, o, EF) {
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 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
cfb_add(o, name, data, {unsafe: true, mt: date});
}
function write_zip(cfb, options) {
@ -1471,7 +1633,10 @@ function write_zip(cfb, options) {
start_cd += namebuf.length;
out.push(namebuf);
/* TODO: extra fields? */
/* TODO: encryption header ? */
start_cd += outbuf.length;
out.push(outbuf);
@ -1525,6 +1690,212 @@ function write_zip(cfb, options) {
return bconcat(([bconcat((out)), bconcat(cdirs), o]));
}
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"
});
function get_content_type(fi, fp) {
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) {
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) {
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 = [], 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) {
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, data, root) {
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, options) {
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 = [], FullPaths = [];
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, options) {
var opts = options || {};
var boundary = opts.boundary || "SheetJS";
boundary = '------=' + boundary;
var out = [
'MIME-Version: 1.0',
'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"',
'',
'',
''
];
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
for(var i = 1; i < cfb.FullPaths.length; ++i) {
fp = cfb.FullPaths[i].slice(root.length);
fi = cfb.FileIndex[i];
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
/* Normalize filename */
fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) {
return "_x" + c.charCodeAt(0).toString(16) + "_";
}).replace(/[\u0080-\uFFFF]/g, function(u) {
return "_u" + u.charCodeAt(0).toString(16) + "_";
});
/* Extract content as binary string */
var ca = fi.content;
// $FlowIgnore
var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca);
/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */
var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;
for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;
var qp = dispcnt >= L * 4 / 5;
out.push(boundary);
out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);
out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));
out.push('Content-Type: ' + get_content_type(fi, fp));
out.push('');
out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));
}
out.push(boundary + '--\r\n');
return out.join("\r\n");
}
function cfb_new(opts) {
var o = ({});
init_cfb(o, opts);

2
dist/.npmignore vendored Normal file
View File

@ -0,0 +1,2 @@
.npmignore
*.sheetjs

190
dist/LICENSE vendored
View File

@ -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.

745
dist/cfb.js vendored
View File

@ -4,73 +4,68 @@
/*exported CFB */
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
var Base64 = (function make_b64(){
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function(input) {
var o = "";
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
for(var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
e1 = (c1 >> 2);
c2 = input.charCodeAt(i++);
e2 = ((c1 & 3) << 4) | (c2 >> 4);
c3 = input.charCodeAt(i++);
e3 = ((c2 & 15) << 2) | (c3 >> 6);
e4 = (c3 & 63);
if (isNaN(c2)) { e3 = e4 = 64; }
else if (isNaN(c3)) { e4 = 64; }
o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
}
return o;
},
decode: function b64_decode(input) {
var o = "";
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
input = input.replace(/[^\w\+\/\=]/g, "");
for(var i = 0; i < input.length;) {
e1 = map.indexOf(input.charAt(i++));
e2 = map.indexOf(input.charAt(i++));
c1 = (e1 << 2) | (e2 >> 4);
o += String.fromCharCode(c1);
e3 = map.indexOf(input.charAt(i++));
c2 = ((e2 & 15) << 4) | (e3 >> 2);
if (e3 !== 64) { o += String.fromCharCode(c2); }
e4 = map.indexOf(input.charAt(i++));
c3 = ((e3 & 3) << 6) | e4;
if (e4 !== 64) { o += String.fromCharCode(c3); }
}
return o;
}
};
})();
var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && process.versions.node);
var Buffer_from = function(){};
if(typeof Buffer !== 'undefined') {
var nbfs = !Buffer.from;
if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
// $FlowIgnore
if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
// $FlowIgnore
if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
var Base64_map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function Base64_encode(input) {
var o = "";
var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;
for (var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
e1 = (c1 >> 2);
c2 = input.charCodeAt(i++);
e2 = ((c1 & 3) << 4) | (c2 >> 4);
c3 = input.charCodeAt(i++);
e3 = ((c2 & 15) << 2) | (c3 >> 6);
e4 = (c3 & 63);
if (isNaN(c2)) e3 = e4 = 64;
else if (isNaN(c3)) e4 = 64;
o += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4);
}
return o;
}
function Base64_decode(input) {
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;
}
var has_buf = (function() { return typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node; })();
var Buffer_from = (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) {
/* jshint -W056 */
return has_buf ? Buffer.alloc(len) : new 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 */
}
function new_unsafe_buf(len) {
/* jshint -W056 */
return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
if(has_buf) return Buffer.allocUnsafe ? Buffer.allocUnsafe(len) : new Buffer(len);
return typeof Uint8Array != "undefined" ? new Uint8Array(len) : new Array(len);
/* jshint +W056 */
}
@ -173,19 +168,12 @@ function new_buf(sz) {
return o;
}
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported CRC32 */
var CRC32;
(function (factory) {
/*jshint ignore:start */
/*eslint-disable */
factory(CRC32 = {});
/*eslint-enable */
/*jshint ignore:end */
}(function(CRC32) {
CRC32.version = '1.2.0';
/* see perf/crc32table.js */
var CRC32 = (function() {
var CRC32 = {};
CRC32.version = '1.2.1';
/*global Int32Array */
function signed_crc_table() {
var c = 0, table = new Array(256);
@ -206,78 +194,77 @@ function signed_crc_table() {
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
}
var T = signed_crc_table();
var T0 = signed_crc_table();
function slice_by_16_tables(T) {
var c = 0, v = 0, n = 0, table = 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, seed) {
var C = seed ^ -1, L = bstr.length - 1;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
}
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
return C ^ -1;
var C = seed ^ -1;
for(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF];
return ~C;
}
function crc32_buf(buf, seed) {
if(buf.length > 10000) return crc32_buf_8(buf, seed);
var C = seed ^ -1, L = buf.length - 3;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
}
function crc32_buf_8(buf, seed) {
var C = seed ^ -1, L = buf.length - 7;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
function crc32_buf(B, seed) {
var C = seed ^ -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, seed) {
var C = seed ^ -1;
for(var i = 0, L=str.length, c, d; i < L;) {
for(var i = 0, L = str.length, c = 0, d = 0; i < L;) {
c = str.charCodeAt(i++);
if(c < 0x80) {
C = (C>>>8) ^ T[(C ^ c)&0xFF];
C = (C>>>8) ^ T0[(C^c)&0xFF];
} else if(c < 0x800) {
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
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) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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 ^ -1;
return ~C;
}
CRC32.table = T;
CRC32.table = T0;
CRC32.bstr = crc32_bstr;
CRC32.buf = crc32_buf;
CRC32.str = crc32_str;
}));
return CRC32;
})();
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports = {};
exports.version = '1.1.0';
exports.version = '1.2.2';
/* [MS-CFB] 2.6.4 */
function namecmp(l, r) {
var L = l.split("/"), R = r.split("/");
@ -367,6 +354,7 @@ var fs;
function get_fs() { return fs || (fs = require('fs')); }
function parse(file, options) {
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;
@ -472,7 +460,8 @@ function check_get_mver(blob) {
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 = blob.read_shift(2, 'u');
@ -524,8 +513,8 @@ function build_full_paths(FI, FP, Paths) {
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) 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) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -534,13 +523,12 @@ function build_full_paths(FI, FP, Paths) {
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] += "/";
@ -576,7 +564,7 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
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);
}
}
@ -608,7 +596,9 @@ function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
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]);
@ -617,6 +607,7 @@ function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
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])});
}
@ -685,9 +676,13 @@ function read_file(filename, options) {
}
function read(blob, options) {
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": return read_file(blob, options);
case "base64": return parse(s2a(Base64.decode(blob)), options);
case "base64": return parse(s2a(Base64_decode(blob)), options);
case "binary": return parse(s2a(blob), options);
}
return parse(blob, options);
@ -734,22 +729,34 @@ function rebuild_cfb(cfb, f) {
if(!gc && !f) return;
var now = new Date(1987, 1, 19), j = 0;
// Track which names exist
var fullPaths = Object.create ? Object.create(null) : {};
var data = [];
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
})]);
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
})]);
// Add name to set
fullPaths[dad] = true;
dad = dirname(data[i][0]);
s = fullPaths[dad];
}
}
data.sort(function(x,y) { return namecmp(x[0], y[0]); });
@ -784,14 +791,19 @@ function rebuild_cfb(cfb, f) {
function _write(cfb, options) {
var _opts = options || {};
/* MAD is order-sensitive, skip rebuild and sort */
if(_opts.fileType == 'mad') return write_mad(cfb, _opts);
rebuild_cfb(cfb);
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
switch(_opts.fileType) {
case 'zip': return write_zip(cfb, _opts);
//case 'mad': return write_mad(cfb, _opts);
}
var L = (function(cfb){
var mini_size = 0, fat_size = 0;
for(var i = 0; i < cfb.FileIndex.length; ++i) {
var file = cfb.FileIndex[i];
if(!file.content) continue;
var flen = file.content.length;
var flen = file.content.length;
if(flen > 0){
if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
else fat_size += (flen + 0x01FF) >> 9;
@ -879,6 +891,10 @@ flen = file.content.length;
file = cfb.FileIndex[i];
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
var _nm = (i === 0 && _opts.root) || file.name;
if(_nm.length > 32) {
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,32));
_nm = _nm.slice(0, 32);
}
flen = 2*(_nm.length+1);
o.write_shift(64, _nm, "utf16le");
o.write_shift(2, flen);
@ -899,18 +915,35 @@ flen = file.content.length;
file = cfb.FileIndex[i];
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);
}
}
}
for(i = 1; i < cfb.FileIndex.length; ++i) {
file = cfb.FileIndex[i];
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);
}
return o;
}
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
@ -973,10 +1006,13 @@ function a2s(o) {
function write(cfb, options) {
var o = _write(cfb, options);
switch(options && options.type) {
switch(options && options.type || "buffer") {
case "file": get_fs(); fs.writeFileSync(options.filename, (o)); 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;
}
@ -1046,6 +1082,38 @@ function read_bits_n(buf, bl, n) {
return v & f;
}
/* helpers for unaligned bit writes */
function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;
if(w <= 5) buf[h] |= (v & 7) << w;
else {
buf[h] |= (v << w) & 0xFF;
buf[h+1] = (v&7) >> (8-w);
}
return bl + 3;
}
function write_bits_1(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v = (v&1) << w;
buf[h] |= v;
return bl + 1;
}
function write_bits_8(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v;
return bl + 8;
}
function write_bits_16(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v & 0xFF;
buf[h+2] = v >>> 8;
return bl + 16;
}
/* until ArrayBuffer#realloc is a thing, fake a realloc */
function realloc(b, sz) {
var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
@ -1059,7 +1127,7 @@ function realloc(b, sz) {
} else if(use_typed_arrays) {
var a = new Uint8Array(M);
if(a.set) a.set(b);
else for(; i < b.length; ++i) a[i] = b[i];
else for(; i < L; ++i) a[i] = b[i];
return a;
}
b.length = M;
@ -1071,30 +1139,7 @@ function zero_fill_array(n) {
var o = new Array(n);
for(var i = 0; i < n; ++i) o[i] = 0;
return o;
}var _deflate = (function() {
var _deflateRaw = (function() {
return function deflateRaw(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
/* TODO: this is only type 0 stored */
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
};
})();
return function(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
};
})();
/* modified inflate function also moves original read head */
}
/* build tree (used for literals and lengths) */
function build_tree(clens, cmap, MAX) {
@ -1134,6 +1179,7 @@ function build_tree(clens, cmap, MAX) {
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) {
@ -1153,8 +1199,125 @@ if(!use_typed_arrays) {
for(; i<=279; i++) clens.push(7);
for(; i<=287; i++) clens.push(8);
build_tree(clens, fix_lmap, 288);
})();var _deflateRaw = (function _deflateRawIIFE() {
var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];
var j = 0, k = 0;
for(; j < DST_LN.length - 1; ++j) {
for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;
}
for(;k < 32768; ++k) DST_LN_RE[k] = 29;
var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];
for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {
for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;
}
function write_stored(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
}
/* Fixed Huffman */
function write_huff_fixed(data, out) {
var bl = 0;
var boff = 0;
var addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];
while(boff < data.length) {
var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);
/* write a stored block for short data */
if(L < 10) {
bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line
if(bl & 7) bl += 8 - (bl & 7);
out.l = (bl / 8) | 0;
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
bl = out.l * 8;
continue;
}
bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line
var hash = 0;
while(L-- > 0) {
var d = data[boff];
hash = ((hash << 5) ^ d) & 0x7FFF;
var match = -1, mlen = 0;
if((match = addrs[hash])) {
match |= boff & ~0x7FFF;
if(match > boff) match -= 0x8000;
if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;
}
if(mlen > 2) {
/* Copy Token */
d = LEN_LN_RE[mlen];
if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;
else {
write_bits_8(out, bl, 3);
bl += 5;
write_bits_8(out, bl, bitswap8[d-23]>>5);
bl += 3;
}
var len_eb = (d < 8) ? 0 : ((d - 4)>>2);
if(len_eb > 0) {
write_bits_16(out, bl, mlen - LEN_LN[d]);
bl += len_eb;
}
d = DST_LN_RE[boff - match];
bl = write_bits_8(out, bl, bitswap8[d]>>3);
bl -= 3;
var dst_eb = d < 4 ? 0 : (d-2)>>1;
if(dst_eb > 0) {
write_bits_16(out, bl, boff - match - DST_LN[d]);
bl += dst_eb;
}
for(var q = 0; q < mlen; ++q) {
addrs[hash] = boff & 0x7FFF;
hash = ((hash << 5) ^ data[boff]) & 0x7FFF;
++boff;
}
L-= mlen - 1;
} else {
/* Literal Token */
if(d <= 143) d = d + 48;
else bl = write_bits_1(out, bl, 1);
bl = write_bits_8(out, bl, bitswap8[d]);
addrs[hash] = boff & 0x7FFF;
++boff;
}
}
bl = write_bits_8(out, bl, 0) - 1;
}
out.l = ((bl + 7)/8)|0;
return out.l;
}
return function _deflateRaw(data, out) {
if(data.length < 8) return write_stored(data, out);
return write_huff_fixed(data, out);
};
})();
function _deflate(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
}
/* modified inflate function also moves original read head */
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
@ -1258,14 +1421,12 @@ function inflate(data, usz) {
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
boff += 32;
/* push sz bytes */
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
if(typeof data.copy === 'function') {
// $FlowIgnore
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
woff += sz; boff += 8*sz;
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
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) {
} else if((header >> 1) == 1) {
/* Fixed Huffman */
max_len_1 = 9; max_len_2 = 5;
} else {
@ -1273,8 +1434,8 @@ function inflate(data, usz) {
boff = dyn(data, boff);
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
}
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
for(;;) { // while(true) is apparently out of vogue in modern JS circles
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
/* ingest code and move read head */
var bits = read_bits_n(data, boff, max_len_1);
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
@ -1305,12 +1466,13 @@ function inflate(data, usz) {
}
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
}
}
}
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
if(usz) return [outbuf, (boff+7)>>>3];
return [outbuf.slice(0, woff), (boff+7)>>>3];
}
function _inflate(payload, usz) {
@ -1404,7 +1566,7 @@ function parse_local_file(blob, csz, usz, o, EF) {
var data = blob.slice(blob.l, blob.l + _csz);
switch(meth) {
case 8: data = _inflateRawSync(blob, _usz); break;
case 0: break;
case 0: break; // TODO: scan for magic number
default: throw new Error("Unsupported ZIP Compression method " + meth);
}
@ -1420,7 +1582,7 @@ function parse_local_file(blob, csz, usz, o, EF) {
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 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
cfb_add(o, name, data, {unsafe: true, mt: date});
}
function write_zip(cfb, options) {
@ -1471,7 +1633,10 @@ function write_zip(cfb, options) {
start_cd += namebuf.length;
out.push(namebuf);
/* TODO: extra fields? */
/* TODO: encryption header ? */
start_cd += outbuf.length;
out.push(outbuf);
@ -1525,6 +1690,212 @@ function write_zip(cfb, options) {
return bconcat(([bconcat((out)), bconcat(cdirs), o]));
}
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"
});
function get_content_type(fi, fp) {
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) {
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) {
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 = [], 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) {
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, data, root) {
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, options) {
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 = [], FullPaths = [];
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, options) {
var opts = options || {};
var boundary = opts.boundary || "SheetJS";
boundary = '------=' + boundary;
var out = [
'MIME-Version: 1.0',
'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"',
'',
'',
''
];
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
for(var i = 1; i < cfb.FullPaths.length; ++i) {
fp = cfb.FullPaths[i].slice(root.length);
fi = cfb.FileIndex[i];
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
/* Normalize filename */
fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) {
return "_x" + c.charCodeAt(0).toString(16) + "_";
}).replace(/[\u0080-\uFFFF]/g, function(u) {
return "_u" + u.charCodeAt(0).toString(16) + "_";
});
/* Extract content as binary string */
var ca = fi.content;
// $FlowIgnore
var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca);
/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */
var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;
for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;
var qp = dispcnt >= L * 4 / 5;
out.push(boundary);
out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);
out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));
out.push('Content-Type: ' + get_content_type(fi, fp));
out.push('');
out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));
}
out.push(boundary + '--\r\n');
return out.join("\r\n");
}
function cfb_new(opts) {
var o = ({});
init_cfb(o, opts);

3
dist/cfb.min.js vendored

File diff suppressed because one or more lines are too long

2
dist/cfb.min.map vendored

File diff suppressed because one or more lines are too long

652
dist/xlscfb.js vendored
View File

@ -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;
@ -16,6 +14,7 @@ declare var has_buf:boolean;
declare var new_buf:any;
declare var new_raw_buf:any;
declare var new_unsafe_buf:any;
declare var Buffer_from:any;
*/
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
@ -24,7 +23,6 @@ declare var new_unsafe_buf:any;
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
/*::
declare var DO_NOT_EXPORT_CFB:?boolean;
type SectorEntry = {
name?:string;
nodes?:Array<number>;
@ -38,21 +36,18 @@ type SectorList = {
}
type CFBFiles = {[n:string]:CFBEntry};
*/
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported CRC32 */
var CRC32;
(function (factory) {
/*jshint ignore:start */
/*eslint-disable */
factory(CRC32 = {});
/*eslint-enable */
/*jshint ignore:end */
}(function(CRC32) {
CRC32.version = '1.2.0';
/* see perf/crc32table.js */
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()/*:any*/ {
function signed_crc_table()/*:CRC32TableType*/ {
var c = 0, table/*:Array<number>*/ = new Array(256);
for(var n =0; n != 256; ++n){
@ -71,78 +66,77 @@ function signed_crc_table()/*:any*/ {
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
}
var T = signed_crc_table();
function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1, L = bstr.length - 1;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
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];
}
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
return C ^ -1;
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(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
if(buf.length > 10000) return crc32_buf_8(buf, seed);
var C = seed ^ -1, L = buf.length - 3;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
function crc32_buf(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_buf_8(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1, L = buf.length - 7;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
}
function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1;
for(var i = 0, L=str.length, c, d; i < L;) {
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) ^ T[(C ^ c)&0xFF];
C = (C>>>8) ^ T0[(C^c)&0xFF];
} else if(c < 0x800) {
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
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) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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 ^ -1;
return ~C;
}
CRC32.table = T;
CRC32.table = T0;
CRC32.bstr = crc32_bstr;
CRC32.buf = crc32_buf;
CRC32.str = crc32_str;
}));
return CRC32;
})();
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var CFB = /*#__PURE__*/(function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '1.1.0';
exports.version = '1.2.2';
/* [MS-CFB] 2.6.4 */
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
var L = l.split("/"), R = r.split("/");
@ -232,6 +226,7 @@ var fs/*:: = require('fs'); */;
function get_fs() { return fs || (fs = require('fs')); }
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
if((file[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;
@ -337,7 +332,8 @@ function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
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');
@ -389,8 +385,8 @@ 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]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) 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) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -399,13 +395,12 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
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] += "/";
@ -441,7 +436,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);
}
}
@ -473,7 +468,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]);
@ -482,6 +479,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*/);
}
@ -550,9 +548,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);
@ -599,22 +601,34 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
if(!gc && !f) return;
var now = new Date(1987, 1, 19), j = 0;
// Track which names exist
var fullPaths = Object.create ? Object.create(null) : {};
var data/*:Array<[string, CFBEntry]>*/ = [];
for(i = 0; i < cfb.FullPaths.length; ++i) {
fullPaths[cfb.FullPaths[i]] = true;
if(cfb.FileIndex[i].type === 0) continue;
data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
}
for(i = 0; i < data.length; ++i) {
var dad = dirname(data[i][0]);
s = 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];
}
}
data.sort(function(x,y) { return namecmp(x[0], y[0]); });
@ -647,16 +661,20 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
}
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);
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
switch(_opts.fileType) {
case 'zip': return write_zip(cfb, _opts);
//case 'mad': return write_mad(cfb, _opts);
}
var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{
var mini_size = 0, fat_size = 0;
for(var i = 0; i < cfb.FileIndex.length; ++i) {
var file = cfb.FileIndex[i];
if(!file.content) continue;
/*:: if(file.content == null) throw new Error("unreachable"); */
var flen = file.content.length;
if(flen > 0){
if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
@ -747,6 +765,10 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
file = cfb.FileIndex[i];
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
var _nm/*:string*/ = (i === 0 && _opts.root) || file.name;
if(_nm.length > 32) {
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,32));
_nm = _nm.slice(0, 32);
}
flen = 2*(_nm.length+1);
o.write_shift(64, _nm, "utf16le");
o.write_shift(2, flen);
@ -768,19 +790,36 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
/*:: 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);
}
}
}
for(i = 1; i < cfb.FileIndex.length; ++i) {
file = cfb.FileIndex[i];
/*:: if(!file.content) throw new Error("unreachable"); */
if(file.size > 0 && file.size < 0x1000) {
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
for(; j & 0x3F; ++j) o.write_shift(1, 0);
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);
}
return o;
}
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
@ -844,10 +883,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;
}
@ -917,6 +959,38 @@ function read_bits_n(buf, bl, n) {
return v & f;
}
/* helpers for unaligned bit writes */
function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;
if(w <= 5) buf[h] |= (v & 7) << w;
else {
buf[h] |= (v << w) & 0xFF;
buf[h+1] = (v&7) >> (8-w);
}
return bl + 3;
}
function write_bits_1(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v = (v&1) << w;
buf[h] |= v;
return bl + 1;
}
function write_bits_8(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v;
return bl + 8;
}
function write_bits_16(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v & 0xFF;
buf[h+2] = v >>> 8;
return bl + 16;
}
/* until ArrayBuffer#realloc is a thing, fake a realloc */
function realloc(b, sz/*:number*/) {
var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
@ -930,7 +1004,7 @@ function realloc(b, sz/*:number*/) {
} else if(use_typed_arrays) {
var a = new Uint8Array(M);
if(a.set) a.set(b);
else for(; i < b.length; ++i) a[i] = b[i];
else for(; i < L; ++i) a[i] = b[i];
return a;
}
b.length = M;
@ -942,30 +1016,7 @@ function zero_fill_array(n) {
var o = new Array(n);
for(var i = 0; i < n; ++i) o[i] = 0;
return o;
}var _deflate = (function() {
var _deflateRaw = (function() {
return function deflateRaw(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
/* TODO: this is only type 0 stored */
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
};
})();
return function(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
};
})();
/* modified inflate function also moves original read head */
}
/* build tree (used for literals and lengths) */
function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
@ -1005,6 +1056,7 @@ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
return maxlen;
}
/* Fixed Huffman */
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
if(!use_typed_arrays) {
@ -1024,8 +1076,125 @@ if(!use_typed_arrays) {
for(; i<=279; i++) clens.push(7);
for(; i<=287; i++) clens.push(8);
build_tree(clens, fix_lmap, 288);
})();var _deflateRaw = /*#__PURE__*/(function _deflateRawIIFE() {
var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];
var j = 0, k = 0;
for(; j < DST_LN.length - 1; ++j) {
for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;
}
for(;k < 32768; ++k) DST_LN_RE[k] = 29;
var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];
for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {
for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;
}
function write_stored(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
}
/* Fixed Huffman */
function write_huff_fixed(data, out) {
var bl = 0;
var boff = 0;
var addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];
while(boff < data.length) {
var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);
/* write a stored block for short data */
if(L < 10) {
bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line
if(bl & 7) bl += 8 - (bl & 7);
out.l = (bl / 8) | 0;
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
bl = out.l * 8;
continue;
}
bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line
var hash = 0;
while(L-- > 0) {
var d = data[boff];
hash = ((hash << 5) ^ d) & 0x7FFF;
var match = -1, mlen = 0;
if((match = addrs[hash])) {
match |= boff & ~0x7FFF;
if(match > boff) match -= 0x8000;
if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;
}
if(mlen > 2) {
/* Copy Token */
d = LEN_LN_RE[mlen];
if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;
else {
write_bits_8(out, bl, 3);
bl += 5;
write_bits_8(out, bl, bitswap8[d-23]>>5);
bl += 3;
}
var len_eb = (d < 8) ? 0 : ((d - 4)>>2);
if(len_eb > 0) {
write_bits_16(out, bl, mlen - LEN_LN[d]);
bl += len_eb;
}
d = DST_LN_RE[boff - match];
bl = write_bits_8(out, bl, bitswap8[d]>>3);
bl -= 3;
var dst_eb = d < 4 ? 0 : (d-2)>>1;
if(dst_eb > 0) {
write_bits_16(out, bl, boff - match - DST_LN[d]);
bl += dst_eb;
}
for(var q = 0; q < mlen; ++q) {
addrs[hash] = boff & 0x7FFF;
hash = ((hash << 5) ^ data[boff]) & 0x7FFF;
++boff;
}
L-= mlen - 1;
} else {
/* Literal Token */
if(d <= 143) d = d + 48;
else bl = write_bits_1(out, bl, 1);
bl = write_bits_8(out, bl, bitswap8[d]);
addrs[hash] = boff & 0x7FFF;
++boff;
}
}
bl = write_bits_8(out, bl, 0) - 1;
}
out.l = ((bl + 7)/8)|0;
return out.l;
}
return function _deflateRaw(data, out) {
if(data.length < 8) return write_stored(data, out);
return write_huff_fixed(data, out);
};
})();
function _deflate(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
}
/* modified inflate function also moves original read head */
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
@ -1129,14 +1298,12 @@ function inflate(data, usz/*:number*/) {
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
boff += 32;
/* push sz bytes */
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
if(typeof data.copy === 'function') {
// $FlowIgnore
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
woff += sz; boff += 8*sz;
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
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) {
} else if((header >> 1) == 1) {
/* Fixed Huffman */
max_len_1 = 9; max_len_2 = 5;
} else {
@ -1144,8 +1311,8 @@ function inflate(data, usz/*:number*/) {
boff = dyn(data, boff);
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
}
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
for(;;) { // while(true) is apparently out of vogue in modern JS circles
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
/* ingest code and move read head */
var bits = read_bits_n(data, boff, max_len_1);
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
@ -1176,12 +1343,13 @@ function inflate(data, usz/*:number*/) {
}
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
}
}
}
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
if(usz) return [outbuf, (boff+7)>>>3];
return [outbuf.slice(0, woff), (boff+7)>>>3];
}
function _inflate(payload, usz) {
@ -1275,7 +1443,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
var data = blob.slice(blob.l, blob.l + _csz);
switch(meth) {
case 8: data = _inflateRawSync(blob, _usz); break;
case 0: break;
case 0: break; // TODO: scan for magic number
default: throw new Error("Unsupported ZIP Compression method " + meth);
}
@ -1291,7 +1459,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
var _crc32 = CRC32.buf(data, 0);
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
cfb_add(o, name, data, {unsafe: true, mt: date});
}
function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
@ -1342,7 +1510,10 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/
start_cd += namebuf.length;
out.push(namebuf);
/* TODO: extra fields? */
/* TODO: encryption header ? */
start_cd += outbuf.length;
out.push(outbuf);
@ -1396,6 +1567,212 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/
return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
}
var ContentTypeMap = ({
"htm": "text/html",
"xml": "text/xml",
"gif": "image/gif",
"jpg": "image/jpeg",
"png": "image/png",
"mso": "application/x-mso",
"thmx": "application/vnd.ms-officetheme",
"sh33tj5": "application/octet-stream"
}/*:any*/);
function get_content_type(fi/*:CFBEntry*/, fp/*:string*/)/*:string*/ {
if(fi.ctype) return fi.ctype;
var ext = fi.name || "", m = ext.match(/\.([^\.]+)$/);
if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];
if(fp) {
m = (ext = fp).match(/[\.\\]([^\.\\])+$/);
if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];
}
return "application/octet-stream";
}
/* 76 character chunks TODO: intertwine encoding */
function write_base64_76(bstr/*:string*/)/*:string*/ {
var data = Base64_encode(bstr);
var o = [];
for(var i = 0; i < data.length; i+= 76) o.push(data.slice(i, i+76));
return o.join("\r\n") + "\r\n";
}
/*
Rules for QP:
- escape =## applies for all non-display characters and literal "="
- space or tab at end of line must be encoded
- \r\n newlines can be preserved, but bare \r and \n must be escaped
- lines must not exceed 76 characters, use soft breaks =\r\n
TODO: Some files from word appear to write line extensions with bare equals:
```
<table class=3DMsoTableGrid border=3D1 cellspacing=3D0 cellpadding=3D0 width=
="70%"
```
*/
function write_quoted_printable(text/*:string*/)/*:string*/ {
var encoded = text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF=]/g, function(c) {
var w = c.charCodeAt(0).toString(16).toUpperCase();
return "=" + (w.length == 1 ? "0" + w : w);
});
encoded = encoded.replace(/ $/mg, "=20").replace(/\t$/mg, "=09");
if(encoded.charAt(0) == "\n") encoded = "=0D" + encoded.slice(1);
encoded = encoded.replace(/\r(?!\n)/mg, "=0D").replace(/\n\n/mg, "\n=0A").replace(/([^\r\n])\n/mg, "$1=0A");
var o/*:Array<string>*/ = [], split = encoded.split("\r\n");
for(var si = 0; si < split.length; ++si) {
var str = split[si];
if(str.length == 0) { o.push(""); continue; }
for(var i = 0; i < str.length;) {
var end = 76;
var tmp = str.slice(i, i + end);
if(tmp.charAt(end - 1) == "=") end --;
else if(tmp.charAt(end - 2) == "=") end -= 2;
else if(tmp.charAt(end - 3) == "=") end -= 3;
tmp = str.slice(i, i + end);
i += end;
if(i < str.length) tmp += "=";
o.push(tmp);
}
}
return o.join("\r\n");
}
function parse_quoted_printable(data/*:Array<string>*/)/*:RawBytes*/ {
var o = [];
/* unify long lines */
for(var di = 0; di < data.length; ++di) {
var line = data[di];
while(di <= data.length && line.charAt(line.length - 1) == "=") line = line.slice(0, line.length - 1) + data[++di];
o.push(line);
}
/* decode */
for(var oi = 0; oi < o.length; ++oi) o[oi] = o[oi].replace(/[=][0-9A-Fa-f]{2}/g, function($$) { return String.fromCharCode(parseInt($$.slice(1), 16)); });
return s2a(o.join("\r\n"));
}
function parse_mime(cfb/*:CFBContainer*/, data/*:Array<string>*/, root/*:string*/)/*:void*/ {
var fname = "", cte = "", ctype = "", fdata;
var di = 0;
for(;di < 10; ++di) {
var line = data[di];
if(!line || line.match(/^\s*$/)) break;
var m = line.match(/^(.*?):\s*([^\s].*)$/);
if(m) switch(m[1].toLowerCase()) {
case "content-location": fname = m[2].trim(); break;
case "content-type": ctype = m[2].trim(); break;
case "content-transfer-encoding": cte = m[2].trim(); break;
}
}
++di;
switch(cte.toLowerCase()) {
case 'base64': fdata = s2a(Base64_decode(data.slice(di).join(""))); break;
case 'quoted-printable': fdata = parse_quoted_printable(data.slice(di)); break;
default: throw new Error("Unsupported Content-Transfer-Encoding " + cte);
}
var file = cfb_add(cfb, fname.slice(root.length), fdata, {unsafe: true});
if(ctype) file.ctype = ctype;
}
function parse_mad(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
if(a2s(file.slice(0,13)).toLowerCase() != "mime-version:") throw new Error("Unsupported MAD header");
var root = (options && options.root || "");
// $FlowIgnore
var data = (has_buf && Buffer.isBuffer(file) ? file.toString("binary") : a2s(file)).split("\r\n");
var di = 0, row = "";
/* if root is not specified, scan for the common prefix */
for(di = 0; di < data.length; ++di) {
row = data[di];
if(!/^Content-Location:/i.test(row)) continue;
row = row.slice(row.indexOf("file"));
if(!root) root = row.slice(0, row.lastIndexOf("/") + 1);
if(row.slice(0, root.length) == root) continue;
while(root.length > 0) {
root = root.slice(0, root.length - 1);
root = root.slice(0, root.lastIndexOf("/") + 1);
if(row.slice(0,root.length) == root) break;
}
}
var mboundary = (data[1] || "").match(/boundary="(.*?)"/);
if(!mboundary) throw new Error("MAD cannot find boundary");
var boundary = "--" + (mboundary[1] || "");
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
var o = {
FileIndex: FileIndex,
FullPaths: FullPaths
};
init_cfb(o);
var start_di, fcnt = 0;
for(di = 0; di < data.length; ++di) {
var line = data[di];
if(line !== boundary && line !== boundary + "--") continue;
if(fcnt++) parse_mime(o, data.slice(start_di, di), root);
start_di = di;
}
return o;
}
function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ {
var opts = options || {};
var boundary = opts.boundary || "SheetJS";
boundary = '------=' + boundary;
var out = [
'MIME-Version: 1.0',
'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"',
'',
'',
''
];
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
for(var i = 1; i < cfb.FullPaths.length; ++i) {
fp = cfb.FullPaths[i].slice(root.length);
fi = cfb.FileIndex[i];
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
/* Normalize filename */
fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) {
return "_x" + c.charCodeAt(0).toString(16) + "_";
}).replace(/[\u0080-\uFFFF]/g, function(u) {
return "_u" + u.charCodeAt(0).toString(16) + "_";
});
/* Extract content as binary string */
var ca = fi.content;
// $FlowIgnore
var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca);
/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */
var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;
for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;
var qp = dispcnt >= L * 4 / 5;
out.push(boundary);
out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);
out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));
out.push('Content-Type: ' + get_content_type(fi, fp));
out.push('');
out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));
}
out.push(boundary + '--\r\n');
return out.join("\r\n");
}
function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
var o/*:CFBContainer*/ = ({}/*:any*/);
init_cfb(o, opts);
@ -1477,4 +1854,3 @@ exports.utils = {
return exports;
})();
if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }

View File

@ -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>
@ -33,25 +34,30 @@ a { text-decoration: none }
Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" checked>
<b>Export Current File</b>
- <a id="savecfb" onclick="savefile('cfb');" href="#">Export data as CFB</a>
- <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="//unpkg.com/filesaver.js/FileSaver.js"></script>
<script src="dist/cfb.min.js"></script>
<script>
/*jshint browser:true */
/* eslint-env browser */
/*global Uint8Array, ArrayBuffer, console, alert */
/*global CFB, out, PRINTJ, saveAs */
/*global Uint8Array, ArrayBuffer */
/*global CFB, out, PRINTJ */
/* exported savefile, download_file */
/* eslint no-use-before-define:0 */
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)); }); }
@ -98,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);
@ -140,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;
@ -160,7 +167,13 @@ var savefile = (function() {
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);
saveAs(new Blob([s2ab(data)],{type:"application/octet-stream"}), "SheetJSCFBDemo." + type);
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);
};
})();
@ -176,7 +189,9 @@ var download_file = (function() {
if(!global_cfb) return alert("Must load a file first!");
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);
};
})();
var _gaq = _gaq || [];

View File

@ -95,5 +95,6 @@ type CFBEntry = {
R: number;
C: number;
content?: CFBlob;
ctype?: string;
}
*/

11
misc/node_version.sh Executable file
View 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

View File

@ -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;
@ -16,4 +14,5 @@ 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;
*/

View File

@ -1,6 +1,6 @@
{
"name": "cfb",
"version": "1.1.0",
"version": "1.2.2",
"author": "sheetjs",
"description": "Compound File Binary File Format extractor",
"keywords": [
@ -8,9 +8,6 @@
"compression",
"office"
],
"bin": {
"cfb": "./bin/cfb.njs"
},
"main": "./cfb",
"types": "types",
"browser": {
@ -19,17 +16,21 @@
"fs": false
},
"dependencies": {
"adler-32": "~1.2.0",
"commander": "^2.16.0",
"crc-32": "~1.2.0",
"printj": "~1.1.2"
"adler-32": "~1.3.0",
"crc-32": "~1.2.0"
},
"devDependencies": {
"@sheetjs/uglify-js": "~2.7.3",
"@types/commander": "^2.9.0",
"@types/node": "^8.10.25",
"acorn": "7.4.1",
"alex": "8.1.1",
"blanket": "~1.2.3",
"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"
},
@ -50,14 +51,13 @@
"files": [
"LICENSE",
"README.md",
"bin/",
"dist/",
"types/index.d.ts",
"types/tsconfig.json",
"cfb.js",
"xlscfb.flow.js"
],
"homepage": "http://sheetjs.com/opensource",
"homepage": "http://sheetjs.com/",
"bugs": {
"url": "https://github.com/SheetJS/js-cfb/issues"
},

View File

@ -0,0 +1 @@
*.tgz

201
packages/cfb-cli/LICENSE Normal file
View 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.

View 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.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-cfb?pixel)](https://github.com/SheetJS/js-cfb)

7
packages/cfb-cli/bin/cfb.njs Executable file
View 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
View 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;

View 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"
}
}

101
shim.js
View File

@ -1,6 +1,41 @@
/* shim.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*! 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;
return function(obj) {
if(typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
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;
};
})();
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);
@ -26,6 +61,23 @@ if(!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(needle)
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';
};
}());
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; }
@ -53,3 +105,50 @@ if(typeof Uint8Array !== 'undefined' && !Uint8Array.prototype.slice) Uint8Array.
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}
}

View File

@ -213,8 +213,8 @@ describe('output formats', function() {
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].charCodeAt(i) == 0x00) good = true;
else if(r[1].charCodeAt(i) > 0xFF) { good = false; break; }
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");
});

7
types/index.d.ts vendored
View File

@ -23,7 +23,7 @@ export function writeFile(cfb: CFB$Container, filename: string, options?: CFB$Wr
export const utils: CFB$Utils;
export interface CFB$CommonOptions {
/** Input data encoding */
/** Data encoding */
type?: 'base64' | 'binary' | 'buffer' | 'file' | 'array';
/** If true, throw errors when features are not understood */
@ -39,7 +39,7 @@ export interface CFB$ParsingOptions extends CFB$CommonOptions {
/** Options for write and writeFile */
export interface CFB$WritingOptions extends CFB$CommonOptions {
/** Output file type */
fileType?: 'cfb' | 'zip';
fileType?: 'cfb' | 'zip' | 'mad';
/** Override default root entry name (CFB only) */
root?: string;
@ -87,6 +87,9 @@ export interface CFB$Entry {
/** Storage location -- see CFB$StorageType */
storage?: string;
/** Content Type (used for MAD) */
ctype?: string;
}
/* File object */

View File

@ -9,6 +9,7 @@
"paths": { "cfb": ["."] },
"types": [],
"noEmit": true,
"strictFunctionTypes": true,
"forceConsistentCasingInFileNames": true
}
}

View File

@ -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;
@ -16,6 +14,7 @@ declare var has_buf:boolean;
declare var new_buf:any;
declare var new_raw_buf:any;
declare var new_unsafe_buf:any;
declare var Buffer_from:any;
*/
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
@ -24,7 +23,6 @@ declare var new_unsafe_buf:any;
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
/*::
declare var DO_NOT_EXPORT_CFB:?boolean;
type SectorEntry = {
name?:string;
nodes?:Array<number>;
@ -38,21 +36,18 @@ type SectorList = {
}
type CFBFiles = {[n:string]:CFBEntry};
*/
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported CRC32 */
var CRC32;
(function (factory) {
/*jshint ignore:start */
/*eslint-disable */
factory(CRC32 = {});
/*eslint-enable */
/*jshint ignore:end */
}(function(CRC32) {
CRC32.version = '1.2.0';
/* see perf/crc32table.js */
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()/*:any*/ {
function signed_crc_table()/*:CRC32TableType*/ {
var c = 0, table/*:Array<number>*/ = new Array(256);
for(var n =0; n != 256; ++n){
@ -71,78 +66,77 @@ function signed_crc_table()/*:any*/ {
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
}
var T = signed_crc_table();
function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1, L = bstr.length - 1;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
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];
}
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
return C ^ -1;
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(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
if(buf.length > 10000) return crc32_buf_8(buf, seed);
var C = seed ^ -1, L = buf.length - 3;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
function crc32_buf(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_buf_8(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1, L = buf.length - 7;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
}
function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
var C = seed ^ -1;
for(var i = 0, L=str.length, c, d; i < L;) {
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) ^ T[(C ^ c)&0xFF];
C = (C>>>8) ^ T0[(C^c)&0xFF];
} else if(c < 0x800) {
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
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) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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 ^ -1;
return ~C;
}
CRC32.table = T;
CRC32.table = T0;
CRC32.bstr = crc32_bstr;
CRC32.buf = crc32_buf;
CRC32.str = crc32_str;
}));
return CRC32;
})();
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var CFB = /*#__PURE__*/(function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '1.1.0';
exports.version = '1.2.2';
/* [MS-CFB] 2.6.4 */
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
var L = l.split("/"), R = r.split("/");
@ -232,6 +226,7 @@ var fs/*:: = require('fs'); */;
function get_fs() { return fs || (fs = require('fs')); }
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
if((file[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;
@ -337,7 +332,8 @@ function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
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');
@ -389,8 +385,8 @@ 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]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) 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) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -399,13 +395,12 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
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] += "/";
@ -441,7 +436,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);
}
}
@ -473,7 +468,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]);
@ -482,6 +479,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*/);
}
@ -550,9 +548,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);
@ -599,22 +601,34 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
if(!gc && !f) return;
var now = new Date(1987, 1, 19), j = 0;
// Track which names exist
var fullPaths = Object.create ? Object.create(null) : {};
var data/*:Array<[string, CFBEntry]>*/ = [];
for(i = 0; i < cfb.FullPaths.length; ++i) {
fullPaths[cfb.FullPaths[i]] = true;
if(cfb.FileIndex[i].type === 0) continue;
data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
}
for(i = 0; i < data.length; ++i) {
var dad = dirname(data[i][0]);
s = 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];
}
}
data.sort(function(x,y) { return namecmp(x[0], y[0]); });
@ -647,16 +661,20 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
}
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);
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
switch(_opts.fileType) {
case 'zip': return write_zip(cfb, _opts);
//case 'mad': return write_mad(cfb, _opts);
}
var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{
var mini_size = 0, fat_size = 0;
for(var i = 0; i < cfb.FileIndex.length; ++i) {
var file = cfb.FileIndex[i];
if(!file.content) continue;
/*:: if(file.content == null) throw new Error("unreachable"); */
var flen = file.content.length;
if(flen > 0){
if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
@ -747,6 +765,10 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
file = cfb.FileIndex[i];
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
var _nm/*:string*/ = (i === 0 && _opts.root) || file.name;
if(_nm.length > 32) {
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,32));
_nm = _nm.slice(0, 32);
}
flen = 2*(_nm.length+1);
o.write_shift(64, _nm, "utf16le");
o.write_shift(2, flen);
@ -768,19 +790,36 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
/*:: 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);
}
}
}
for(i = 1; i < cfb.FileIndex.length; ++i) {
file = cfb.FileIndex[i];
/*:: if(!file.content) throw new Error("unreachable"); */
if(file.size > 0 && file.size < 0x1000) {
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
for(; j & 0x3F; ++j) o.write_shift(1, 0);
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);
}
return o;
}
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
@ -844,10 +883,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;
}
@ -917,6 +959,38 @@ function read_bits_n(buf, bl, n) {
return v & f;
}
/* helpers for unaligned bit writes */
function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;
if(w <= 5) buf[h] |= (v & 7) << w;
else {
buf[h] |= (v << w) & 0xFF;
buf[h+1] = (v&7) >> (8-w);
}
return bl + 3;
}
function write_bits_1(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v = (v&1) << w;
buf[h] |= v;
return bl + 1;
}
function write_bits_8(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v;
return bl + 8;
}
function write_bits_16(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v & 0xFF;
buf[h+2] = v >>> 8;
return bl + 16;
}
/* until ArrayBuffer#realloc is a thing, fake a realloc */
function realloc(b, sz/*:number*/) {
var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
@ -930,7 +1004,7 @@ function realloc(b, sz/*:number*/) {
} else if(use_typed_arrays) {
var a = new Uint8Array(M);
if(a.set) a.set(b);
else for(; i < b.length; ++i) a[i] = b[i];
else for(; i < L; ++i) a[i] = b[i];
return a;
}
b.length = M;
@ -942,30 +1016,7 @@ function zero_fill_array(n) {
var o = new Array(n);
for(var i = 0; i < n; ++i) o[i] = 0;
return o;
}var _deflate = (function() {
var _deflateRaw = (function() {
return function deflateRaw(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
/* TODO: this is only type 0 stored */
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
};
})();
return function(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
};
})();
/* modified inflate function also moves original read head */
}
/* build tree (used for literals and lengths) */
function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
@ -1005,6 +1056,7 @@ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
return maxlen;
}
/* Fixed Huffman */
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
if(!use_typed_arrays) {
@ -1024,8 +1076,125 @@ if(!use_typed_arrays) {
for(; i<=279; i++) clens.push(7);
for(; i<=287; i++) clens.push(8);
build_tree(clens, fix_lmap, 288);
})();var _deflateRaw = /*#__PURE__*/(function _deflateRawIIFE() {
var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];
var j = 0, k = 0;
for(; j < DST_LN.length - 1; ++j) {
for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;
}
for(;k < 32768; ++k) DST_LN_RE[k] = 29;
var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];
for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {
for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;
}
function write_stored(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
}
/* Fixed Huffman */
function write_huff_fixed(data, out) {
var bl = 0;
var boff = 0;
var addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];
while(boff < data.length) {
var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);
/* write a stored block for short data */
if(L < 10) {
bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line
if(bl & 7) bl += 8 - (bl & 7);
out.l = (bl / 8) | 0;
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
bl = out.l * 8;
continue;
}
bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line
var hash = 0;
while(L-- > 0) {
var d = data[boff];
hash = ((hash << 5) ^ d) & 0x7FFF;
var match = -1, mlen = 0;
if((match = addrs[hash])) {
match |= boff & ~0x7FFF;
if(match > boff) match -= 0x8000;
if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;
}
if(mlen > 2) {
/* Copy Token */
d = LEN_LN_RE[mlen];
if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;
else {
write_bits_8(out, bl, 3);
bl += 5;
write_bits_8(out, bl, bitswap8[d-23]>>5);
bl += 3;
}
var len_eb = (d < 8) ? 0 : ((d - 4)>>2);
if(len_eb > 0) {
write_bits_16(out, bl, mlen - LEN_LN[d]);
bl += len_eb;
}
d = DST_LN_RE[boff - match];
bl = write_bits_8(out, bl, bitswap8[d]>>3);
bl -= 3;
var dst_eb = d < 4 ? 0 : (d-2)>>1;
if(dst_eb > 0) {
write_bits_16(out, bl, boff - match - DST_LN[d]);
bl += dst_eb;
}
for(var q = 0; q < mlen; ++q) {
addrs[hash] = boff & 0x7FFF;
hash = ((hash << 5) ^ data[boff]) & 0x7FFF;
++boff;
}
L-= mlen - 1;
} else {
/* Literal Token */
if(d <= 143) d = d + 48;
else bl = write_bits_1(out, bl, 1);
bl = write_bits_8(out, bl, bitswap8[d]);
addrs[hash] = boff & 0x7FFF;
++boff;
}
}
bl = write_bits_8(out, bl, 0) - 1;
}
out.l = ((bl + 7)/8)|0;
return out.l;
}
return function _deflateRaw(data, out) {
if(data.length < 8) return write_stored(data, out);
return write_huff_fixed(data, out);
};
})();
function _deflate(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
}
/* modified inflate function also moves original read head */
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
@ -1129,14 +1298,12 @@ function inflate(data, usz/*:number*/) {
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
boff += 32;
/* push sz bytes */
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
if(typeof data.copy === 'function') {
// $FlowIgnore
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
woff += sz; boff += 8*sz;
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
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) {
} else if((header >> 1) == 1) {
/* Fixed Huffman */
max_len_1 = 9; max_len_2 = 5;
} else {
@ -1144,8 +1311,8 @@ function inflate(data, usz/*:number*/) {
boff = dyn(data, boff);
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
}
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
for(;;) { // while(true) is apparently out of vogue in modern JS circles
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
/* ingest code and move read head */
var bits = read_bits_n(data, boff, max_len_1);
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
@ -1176,12 +1343,13 @@ function inflate(data, usz/*:number*/) {
}
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
}
}
}
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
if(usz) return [outbuf, (boff+7)>>>3];
return [outbuf.slice(0, woff), (boff+7)>>>3];
}
function _inflate(payload, usz) {
@ -1275,7 +1443,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
var data = blob.slice(blob.l, blob.l + _csz);
switch(meth) {
case 8: data = _inflateRawSync(blob, _usz); break;
case 0: break;
case 0: break; // TODO: scan for magic number
default: throw new Error("Unsupported ZIP Compression method " + meth);
}
@ -1291,7 +1459,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
var _crc32 = CRC32.buf(data, 0);
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
cfb_add(o, name, data, {unsafe: true, mt: date});
}
function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
@ -1342,7 +1510,10 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/
start_cd += namebuf.length;
out.push(namebuf);
/* TODO: extra fields? */
/* TODO: encryption header ? */
start_cd += outbuf.length;
out.push(outbuf);
@ -1396,6 +1567,212 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/
return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
}
var ContentTypeMap = ({
"htm": "text/html",
"xml": "text/xml",
"gif": "image/gif",
"jpg": "image/jpeg",
"png": "image/png",
"mso": "application/x-mso",
"thmx": "application/vnd.ms-officetheme",
"sh33tj5": "application/octet-stream"
}/*:any*/);
function get_content_type(fi/*:CFBEntry*/, fp/*:string*/)/*:string*/ {
if(fi.ctype) return fi.ctype;
var ext = fi.name || "", m = ext.match(/\.([^\.]+)$/);
if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];
if(fp) {
m = (ext = fp).match(/[\.\\]([^\.\\])+$/);
if(m && ContentTypeMap[m[1]]) return ContentTypeMap[m[1]];
}
return "application/octet-stream";
}
/* 76 character chunks TODO: intertwine encoding */
function write_base64_76(bstr/*:string*/)/*:string*/ {
var data = Base64_encode(bstr);
var o = [];
for(var i = 0; i < data.length; i+= 76) o.push(data.slice(i, i+76));
return o.join("\r\n") + "\r\n";
}
/*
Rules for QP:
- escape =## applies for all non-display characters and literal "="
- space or tab at end of line must be encoded
- \r\n newlines can be preserved, but bare \r and \n must be escaped
- lines must not exceed 76 characters, use soft breaks =\r\n
TODO: Some files from word appear to write line extensions with bare equals:
```
<table class=3DMsoTableGrid border=3D1 cellspacing=3D0 cellpadding=3D0 width=
="70%"
```
*/
function write_quoted_printable(text/*:string*/)/*:string*/ {
var encoded = text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF=]/g, function(c) {
var w = c.charCodeAt(0).toString(16).toUpperCase();
return "=" + (w.length == 1 ? "0" + w : w);
});
encoded = encoded.replace(/ $/mg, "=20").replace(/\t$/mg, "=09");
if(encoded.charAt(0) == "\n") encoded = "=0D" + encoded.slice(1);
encoded = encoded.replace(/\r(?!\n)/mg, "=0D").replace(/\n\n/mg, "\n=0A").replace(/([^\r\n])\n/mg, "$1=0A");
var o/*:Array<string>*/ = [], split = encoded.split("\r\n");
for(var si = 0; si < split.length; ++si) {
var str = split[si];
if(str.length == 0) { o.push(""); continue; }
for(var i = 0; i < str.length;) {
var end = 76;
var tmp = str.slice(i, i + end);
if(tmp.charAt(end - 1) == "=") end --;
else if(tmp.charAt(end - 2) == "=") end -= 2;
else if(tmp.charAt(end - 3) == "=") end -= 3;
tmp = str.slice(i, i + end);
i += end;
if(i < str.length) tmp += "=";
o.push(tmp);
}
}
return o.join("\r\n");
}
function parse_quoted_printable(data/*:Array<string>*/)/*:RawBytes*/ {
var o = [];
/* unify long lines */
for(var di = 0; di < data.length; ++di) {
var line = data[di];
while(di <= data.length && line.charAt(line.length - 1) == "=") line = line.slice(0, line.length - 1) + data[++di];
o.push(line);
}
/* decode */
for(var oi = 0; oi < o.length; ++oi) o[oi] = o[oi].replace(/[=][0-9A-Fa-f]{2}/g, function($$) { return String.fromCharCode(parseInt($$.slice(1), 16)); });
return s2a(o.join("\r\n"));
}
function parse_mime(cfb/*:CFBContainer*/, data/*:Array<string>*/, root/*:string*/)/*:void*/ {
var fname = "", cte = "", ctype = "", fdata;
var di = 0;
for(;di < 10; ++di) {
var line = data[di];
if(!line || line.match(/^\s*$/)) break;
var m = line.match(/^(.*?):\s*([^\s].*)$/);
if(m) switch(m[1].toLowerCase()) {
case "content-location": fname = m[2].trim(); break;
case "content-type": ctype = m[2].trim(); break;
case "content-transfer-encoding": cte = m[2].trim(); break;
}
}
++di;
switch(cte.toLowerCase()) {
case 'base64': fdata = s2a(Base64_decode(data.slice(di).join(""))); break;
case 'quoted-printable': fdata = parse_quoted_printable(data.slice(di)); break;
default: throw new Error("Unsupported Content-Transfer-Encoding " + cte);
}
var file = cfb_add(cfb, fname.slice(root.length), fdata, {unsafe: true});
if(ctype) file.ctype = ctype;
}
function parse_mad(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
if(a2s(file.slice(0,13)).toLowerCase() != "mime-version:") throw new Error("Unsupported MAD header");
var root = (options && options.root || "");
// $FlowIgnore
var data = (has_buf && Buffer.isBuffer(file) ? file.toString("binary") : a2s(file)).split("\r\n");
var di = 0, row = "";
/* if root is not specified, scan for the common prefix */
for(di = 0; di < data.length; ++di) {
row = data[di];
if(!/^Content-Location:/i.test(row)) continue;
row = row.slice(row.indexOf("file"));
if(!root) root = row.slice(0, row.lastIndexOf("/") + 1);
if(row.slice(0, root.length) == root) continue;
while(root.length > 0) {
root = root.slice(0, root.length - 1);
root = root.slice(0, root.lastIndexOf("/") + 1);
if(row.slice(0,root.length) == root) break;
}
}
var mboundary = (data[1] || "").match(/boundary="(.*?)"/);
if(!mboundary) throw new Error("MAD cannot find boundary");
var boundary = "--" + (mboundary[1] || "");
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
var o = {
FileIndex: FileIndex,
FullPaths: FullPaths
};
init_cfb(o);
var start_di, fcnt = 0;
for(di = 0; di < data.length; ++di) {
var line = data[di];
if(line !== boundary && line !== boundary + "--") continue;
if(fcnt++) parse_mime(o, data.slice(start_di, di), root);
start_di = di;
}
return o;
}
function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ {
var opts = options || {};
var boundary = opts.boundary || "SheetJS";
boundary = '------=' + boundary;
var out = [
'MIME-Version: 1.0',
'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"',
'',
'',
''
];
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
for(var i = 1; i < cfb.FullPaths.length; ++i) {
fp = cfb.FullPaths[i].slice(root.length);
fi = cfb.FileIndex[i];
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
/* Normalize filename */
fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) {
return "_x" + c.charCodeAt(0).toString(16) + "_";
}).replace(/[\u0080-\uFFFF]/g, function(u) {
return "_u" + u.charCodeAt(0).toString(16) + "_";
});
/* Extract content as binary string */
var ca = fi.content;
// $FlowIgnore
var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca);
/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */
var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;
for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;
var qp = dispcnt >= L * 4 / 5;
out.push(boundary);
out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);
out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));
out.push('Content-Type: ' + get_content_type(fi, fp));
out.push('');
out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));
}
out.push(boundary + '--\r\n');
return out.join("\r\n");
}
function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
var o/*:CFBContainer*/ = ({}/*:any*/);
init_cfb(o, opts);
@ -1477,4 +1854,3 @@ exports.utils = {
return exports;
})();
if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }

636
xlscfb.js
View File

@ -1,23 +1,15 @@
var DO_NOT_EXPORT_CFB = true;
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint eqnull:true */
/*exported CFB */
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported CRC32 */
var CRC32;
(function (factory) {
/*jshint ignore:start */
/*eslint-disable */
factory(CRC32 = {});
/*eslint-enable */
/*jshint ignore:end */
}(function(CRC32) {
CRC32.version = '1.2.0';
/* see perf/crc32table.js */
var CRC32 = (function() {
var CRC32 = {};
CRC32.version = '1.2.1';
/*global Int32Array */
function signed_crc_table() {
var c = 0, table = new Array(256);
@ -38,78 +30,77 @@ function signed_crc_table() {
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
}
var T = signed_crc_table();
var T0 = signed_crc_table();
function slice_by_16_tables(T) {
var c = 0, v = 0, n = 0, table = 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, seed) {
var C = seed ^ -1, L = bstr.length - 1;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
}
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
return C ^ -1;
var C = seed ^ -1;
for(var i = 0, L = bstr.length; i < L;) C = (C>>>8) ^ T0[(C^bstr.charCodeAt(i++))&0xFF];
return ~C;
}
function crc32_buf(buf, seed) {
if(buf.length > 10000) return crc32_buf_8(buf, seed);
var C = seed ^ -1, L = buf.length - 3;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
}
function crc32_buf_8(buf, seed) {
var C = seed ^ -1, L = buf.length - 7;
for(var i = 0; i < L;) {
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
}
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
return C ^ -1;
function crc32_buf(B, seed) {
var C = seed ^ -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, seed) {
var C = seed ^ -1;
for(var i = 0, L=str.length, c, d; i < L;) {
for(var i = 0, L = str.length, c = 0, d = 0; i < L;) {
c = str.charCodeAt(i++);
if(c < 0x80) {
C = (C>>>8) ^ T[(C ^ c)&0xFF];
C = (C>>>8) ^ T0[(C^c)&0xFF];
} else if(c < 0x800) {
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
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) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
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 ^ -1;
return ~C;
}
CRC32.table = T;
CRC32.table = T0;
CRC32.bstr = crc32_bstr;
CRC32.buf = crc32_buf;
CRC32.str = crc32_str;
}));
return CRC32;
})();
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports = {};
exports.version = '1.1.0';
exports.version = '1.2.2';
/* [MS-CFB] 2.6.4 */
function namecmp(l, r) {
var L = l.split("/"), R = r.split("/");
@ -199,6 +190,7 @@ var fs;
function get_fs() { return fs || (fs = require('fs')); }
function parse(file, options) {
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;
@ -304,7 +296,8 @@ function check_get_mver(blob) {
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 = blob.read_shift(2, 'u');
@ -356,8 +349,8 @@ function build_full_paths(FI, FP, Paths) {
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) 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) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -366,13 +359,12 @@ function build_full_paths(FI, FP, Paths) {
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] += "/";
@ -408,7 +400,7 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
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);
}
}
@ -440,7 +432,9 @@ function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
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]);
@ -449,6 +443,7 @@ function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
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])});
}
@ -517,9 +512,13 @@ function read_file(filename, options) {
}
function read(blob, options) {
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": return read_file(blob, options);
case "base64": return parse(s2a(Base64.decode(blob)), options);
case "base64": return parse(s2a(Base64_decode(blob)), options);
case "binary": return parse(s2a(blob), options);
}
return parse(blob, options);
@ -566,22 +565,34 @@ function rebuild_cfb(cfb, f) {
if(!gc && !f) return;
var now = new Date(1987, 1, 19), j = 0;
// Track which names exist
var fullPaths = Object.create ? Object.create(null) : {};
var data = [];
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
})]);
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
})]);
// Add name to set
fullPaths[dad] = true;
dad = dirname(data[i][0]);
s = fullPaths[dad];
}
}
data.sort(function(x,y) { return namecmp(x[0], y[0]); });
@ -616,14 +627,19 @@ function rebuild_cfb(cfb, f) {
function _write(cfb, options) {
var _opts = options || {};
/* MAD is order-sensitive, skip rebuild and sort */
if(_opts.fileType == 'mad') return write_mad(cfb, _opts);
rebuild_cfb(cfb);
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
switch(_opts.fileType) {
case 'zip': return write_zip(cfb, _opts);
//case 'mad': return write_mad(cfb, _opts);
}
var L = (function(cfb){
var mini_size = 0, fat_size = 0;
for(var i = 0; i < cfb.FileIndex.length; ++i) {
var file = cfb.FileIndex[i];
if(!file.content) continue;
var flen = file.content.length;
var flen = file.content.length;
if(flen > 0){
if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
else fat_size += (flen + 0x01FF) >> 9;
@ -711,6 +727,10 @@ flen = file.content.length;
file = cfb.FileIndex[i];
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
var _nm = (i === 0 && _opts.root) || file.name;
if(_nm.length > 32) {
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,32));
_nm = _nm.slice(0, 32);
}
flen = 2*(_nm.length+1);
o.write_shift(64, _nm, "utf16le");
o.write_shift(2, flen);
@ -731,18 +751,35 @@ flen = file.content.length;
file = cfb.FileIndex[i];
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);
}
}
}
for(i = 1; i < cfb.FileIndex.length; ++i) {
file = cfb.FileIndex[i];
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);
}
return o;
}
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
@ -805,10 +842,13 @@ function a2s(o) {
function write(cfb, options) {
var o = _write(cfb, options);
switch(options && options.type) {
switch(options && options.type || "buffer") {
case "file": get_fs(); fs.writeFileSync(options.filename, (o)); 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;
}
@ -878,6 +918,38 @@ function read_bits_n(buf, bl, n) {
return v & f;
}
/* helpers for unaligned bit writes */
function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3;
if(w <= 5) buf[h] |= (v & 7) << w;
else {
buf[h] |= (v << w) & 0xFF;
buf[h+1] = (v&7) >> (8-w);
}
return bl + 3;
}
function write_bits_1(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v = (v&1) << w;
buf[h] |= v;
return bl + 1;
}
function write_bits_8(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v;
return bl + 8;
}
function write_bits_16(buf, bl, v) {
var w = bl & 7, h = bl >>> 3;
v <<= w;
buf[h] |= v & 0xFF; v >>>= 8;
buf[h+1] = v & 0xFF;
buf[h+2] = v >>> 8;
return bl + 16;
}
/* until ArrayBuffer#realloc is a thing, fake a realloc */
function realloc(b, sz) {
var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
@ -891,7 +963,7 @@ function realloc(b, sz) {
} else if(use_typed_arrays) {
var a = new Uint8Array(M);
if(a.set) a.set(b);
else for(; i < b.length; ++i) a[i] = b[i];
else for(; i < L; ++i) a[i] = b[i];
return a;
}
b.length = M;
@ -903,30 +975,7 @@ function zero_fill_array(n) {
var o = new Array(n);
for(var i = 0; i < n; ++i) o[i] = 0;
return o;
}var _deflate = (function() {
var _deflateRaw = (function() {
return function deflateRaw(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
/* TODO: this is only type 0 stored */
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
};
})();
return function(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
};
})();
/* modified inflate function also moves original read head */
}
/* build tree (used for literals and lengths) */
function build_tree(clens, cmap, MAX) {
@ -966,6 +1015,7 @@ function build_tree(clens, cmap, MAX) {
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) {
@ -985,8 +1035,125 @@ if(!use_typed_arrays) {
for(; i<=279; i++) clens.push(7);
for(; i<=287; i++) clens.push(8);
build_tree(clens, fix_lmap, 288);
})();var _deflateRaw = (function _deflateRawIIFE() {
var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : [];
var j = 0, k = 0;
for(; j < DST_LN.length - 1; ++j) {
for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j;
}
for(;k < 32768; ++k) DST_LN_RE[k] = 29;
var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x103) : [];
for(j = 0, k = 0; j < LEN_LN.length - 1; ++j) {
for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j;
}
function write_stored(data, out) {
var boff = 0;
while(boff < data.length) {
var L = Math.min(0xFFFF, data.length - boff);
var h = boff + L == data.length;
out.write_shift(1, +h);
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
}
return out.l;
}
/* Fixed Huffman */
function write_huff_fixed(data, out) {
var bl = 0;
var boff = 0;
var addrs = use_typed_arrays ? new Uint16Array(0x8000) : [];
while(boff < data.length) {
var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff);
/* write a stored block for short data */
if(L < 10) {
bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line
if(bl & 7) bl += 8 - (bl & 7);
out.l = (bl / 8) | 0;
out.write_shift(2, L);
out.write_shift(2, (~L) & 0xFFFF);
while(L-- > 0) out[out.l++] = data[boff++];
bl = out.l * 8;
continue;
}
bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line
var hash = 0;
while(L-- > 0) {
var d = data[boff];
hash = ((hash << 5) ^ d) & 0x7FFF;
var match = -1, mlen = 0;
if((match = addrs[hash])) {
match |= boff & ~0x7FFF;
if(match > boff) match -= 0x8000;
if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen;
}
if(mlen > 2) {
/* Copy Token */
d = LEN_LN_RE[mlen];
if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1;
else {
write_bits_8(out, bl, 3);
bl += 5;
write_bits_8(out, bl, bitswap8[d-23]>>5);
bl += 3;
}
var len_eb = (d < 8) ? 0 : ((d - 4)>>2);
if(len_eb > 0) {
write_bits_16(out, bl, mlen - LEN_LN[d]);
bl += len_eb;
}
d = DST_LN_RE[boff - match];
bl = write_bits_8(out, bl, bitswap8[d]>>3);
bl -= 3;
var dst_eb = d < 4 ? 0 : (d-2)>>1;
if(dst_eb > 0) {
write_bits_16(out, bl, boff - match - DST_LN[d]);
bl += dst_eb;
}
for(var q = 0; q < mlen; ++q) {
addrs[hash] = boff & 0x7FFF;
hash = ((hash << 5) ^ data[boff]) & 0x7FFF;
++boff;
}
L-= mlen - 1;
} else {
/* Literal Token */
if(d <= 143) d = d + 48;
else bl = write_bits_1(out, bl, 1);
bl = write_bits_8(out, bl, bitswap8[d]);
addrs[hash] = boff & 0x7FFF;
++boff;
}
}
bl = write_bits_8(out, bl, 0) - 1;
}
out.l = ((bl + 7)/8)|0;
return out.l;
}
return function _deflateRaw(data, out) {
if(data.length < 8) return write_stored(data, out);
return write_huff_fixed(data, out);
};
})();
function _deflate(data) {
var buf = new_buf(50+Math.floor(data.length*1.1));
var off = _deflateRaw(data, buf);
return buf.slice(0, off);
}
/* modified inflate function also moves original read head */
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
@ -1090,14 +1257,12 @@ function inflate(data, usz) {
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
boff += 32;
/* push sz bytes */
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
if(typeof data.copy === 'function') {
// $FlowIgnore
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
woff += sz; boff += 8*sz;
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
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) {
} else if((header >> 1) == 1) {
/* Fixed Huffman */
max_len_1 = 9; max_len_2 = 5;
} else {
@ -1105,8 +1270,8 @@ function inflate(data, usz) {
boff = dyn(data, boff);
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
}
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
for(;;) { // while(true) is apparently out of vogue in modern JS circles
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
/* ingest code and move read head */
var bits = read_bits_n(data, boff, max_len_1);
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
@ -1137,12 +1302,13 @@ function inflate(data, usz) {
}
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; }
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
}
}
}
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
if(usz) return [outbuf, (boff+7)>>>3];
return [outbuf.slice(0, woff), (boff+7)>>>3];
}
function _inflate(payload, usz) {
@ -1236,7 +1402,7 @@ function parse_local_file(blob, csz, usz, o, EF) {
var data = blob.slice(blob.l, blob.l + _csz);
switch(meth) {
case 8: data = _inflateRawSync(blob, _usz); break;
case 0: break;
case 0: break; // TODO: scan for magic number
default: throw new Error("Unsupported ZIP Compression method " + meth);
}
@ -1252,7 +1418,7 @@ function parse_local_file(blob, csz, usz, o, EF) {
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 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
cfb_add(o, name, data, {unsafe: true, mt: date});
}
function write_zip(cfb, options) {
@ -1303,7 +1469,10 @@ function write_zip(cfb, options) {
start_cd += namebuf.length;
out.push(namebuf);
/* TODO: extra fields? */
/* TODO: encryption header ? */
start_cd += outbuf.length;
out.push(outbuf);
@ -1357,6 +1526,212 @@ function write_zip(cfb, options) {
return bconcat(([bconcat((out)), bconcat(cdirs), o]));
}
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"
});
function get_content_type(fi, fp) {
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) {
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) {
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 = [], 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) {
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, data, root) {
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, options) {
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 = [], FullPaths = [];
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, options) {
var opts = options || {};
var boundary = opts.boundary || "SheetJS";
boundary = '------=' + boundary;
var out = [
'MIME-Version: 1.0',
'Content-Type: multipart/related; boundary="' + boundary.slice(2) + '"',
'',
'',
''
];
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
for(var i = 1; i < cfb.FullPaths.length; ++i) {
fp = cfb.FullPaths[i].slice(root.length);
fi = cfb.FileIndex[i];
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
/* Normalize filename */
fp = fp.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7E-\xFF]/g, function(c) {
return "_x" + c.charCodeAt(0).toString(16) + "_";
}).replace(/[\u0080-\uFFFF]/g, function(u) {
return "_u" + u.charCodeAt(0).toString(16) + "_";
});
/* Extract content as binary string */
var ca = fi.content;
// $FlowIgnore
var cstr = has_buf && Buffer.isBuffer(ca) ? ca.toString("binary") : a2s(ca);
/* 4/5 of first 1024 chars ascii -> quoted printable, else base64 */
var dispcnt = 0, L = Math.min(1024, cstr.length), cc = 0;
for(var csl = 0; csl <= L; ++csl) if((cc=cstr.charCodeAt(csl)) >= 0x20 && cc < 0x80) ++dispcnt;
var qp = dispcnt >= L * 4 / 5;
out.push(boundary);
out.push('Content-Location: ' + (opts.root || 'file:///C:/SheetJS/') + fp);
out.push('Content-Transfer-Encoding: ' + (qp ? 'quoted-printable' : 'base64'));
out.push('Content-Type: ' + get_content_type(fi, fp));
out.push('');
out.push(qp ? write_quoted_printable(cstr) : write_base64_76(cstr));
}
out.push(boundary + '--\r\n');
return out.join("\r\n");
}
function cfb_new(opts) {
var o = ({});
init_cfb(o, opts);
@ -1437,4 +1812,3 @@ exports.utils = {
return exports;
})();
if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }