Skip to content

Commit

Permalink
version bump 0.13.0: write
Browse files Browse the repository at this point in the history
  • Loading branch information
SheetJSDev committed Sep 14, 2017
1 parent 2d0c71a commit 03044b3
Show file tree
Hide file tree
Showing 57 changed files with 3,279 additions and 497 deletions.
3 changes: 2 additions & 1 deletion .flowconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[ignore]
.*/node_modules/.*
.*/dist/.*
.*/test_files/.*
.*/test_files_pres/.*
.*/test.js

.*/bits/.*
Expand All @@ -11,7 +13,6 @@
.*/demo/browser.js
.*/shim.js

.*/odsbits/.*
.*/xlscfb.js
.*/cfb.js
.*/jszip.js
Expand Down
21 changes: 20 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
node_modules
package-lock.json
*.tgz
misc/coverage.html
prof.js
v8.log
test_files
test_files_pres
*.xls
*.[tT][xX][tT]
*.[cC][sS][vV]
*.[dD][iIbB][fF]
*.[pP][rR][nN]
*.[sS][lL][kK]
*.socialcalc
*.[xX][lL][sSwWcC]
*.[xX][lL][sS][xXmMbB]
*.[oO][dD][sS]
*.[fF][oO][dD][sS]
*.[xX][mM][lL]
*.[uU][oO][sS]
*.[wW][kKqQbB][S1234567890]
*.[qQ][pP][wW]
*.123
*.htm
*.html
*.sheetjs
*.exe
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ before_install:
- "npm install -g npm@4.3.0"
- "npm install -g mocha@2.x voc"
- "npm install blanket"
- "npm install xlsjs"
- "npm install xlsjs crc-32"
- "npm install coveralls mocha-lcov-reporter"
before_script:
- "make init"
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ DEPS=$(sort $(wildcard bits/*.js))
TARGET=$(LIB).js
FLOWTARGET=$(LIB).flow.js
FLOWTGTS=$(TARGET) $(AUXTARGETS)
UGLIFYOPTS=--support-ie8
UGLIFYOPTS=--support-ie8 -m
CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar

## Main Targets
Expand Down Expand Up @@ -48,7 +48,7 @@ init: ## Initial setup for development
dist: dist-deps $(TARGET) ## Prepare JS files for distribution
cp $(TARGET) dist/
cp LICENSE dist/
uglifyjs $(UGLIFYOPTS) $(TARGET) -o dist/$(LIB).min.js --source-map dist/$(LIB).min.map --preamble "$$(head -n 1 bits/00_header.js)"
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
Expand Down Expand Up @@ -102,7 +102,7 @@ tslint: $(TARGET) ## Run typescript checks

.PHONY: flow
flow: lint ## Run flow checker
@flow check --all --show-all-errors
@flow check --all --show-all-errors --include-warnings

.PHONY: cov
cov: misc/coverage.html ## Run coverage test
Expand Down
128 changes: 87 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
# Compound File Binary Format

This is a Pure-JS implementation of MS-CFB: Compound File Binary File Format, a
format used in many Microsoft file types (such as XLS and DOC)
Pure-JS implementation of MS-CFB: Compound File Binary File Format, a container
format used in many Microsoft file types (XLS, DOC, VBA blobs in XLSX and XLSB)

# Utility Installation and Usage
[![Build Status](https://travis-ci.org/SheetJS/js-cfb.svg?branch=master)](https://travis-ci.org/SheetJS/js-cfb)
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-cfb/master.svg)](https://coveralls.io/r/SheetJS/js-cfb?branch=master)
[![Dependencies Status](https://david-dm.org/sheetjs/js-cfb/status.svg)](https://david-dm.org/sheetjs/js-cfb)
[![NPM Downloads](https://img.shields.io/npm/dt/cfb.svg)](https://npmjs.org/package/cfb)
[![ghit.me](https://ghit.me/badge.svg?repo=sheetjs/js-xlsx)](https://ghit.me/repo/sheetjs/js-xlsx)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-cfb?pixel)](https://github.com/SheetJS/js-cfb)

## Installation

In the browser:

```html
<script src="dist/cfb.min.js" type="text/javascript"></script>
```

With [npm](https://www.npmjs.org/package/cfb):

```bash
$ npm install -g cfb
$ cfb path/to/CFB/file
$ npm install cfb
```

The command will extract the storages and streams in the container, generating
files that line up with the tree-based structure of the storage. Metadata such
as the red-black tree are discarded. The `-l` option displays a manifest.

# Library Installation and Usage
The `xlscfb.js` file is designed to be embedded in [js-xlsx](http://git.io/xlsx)

In the browser:

```html
<script src="cfb.js" type="text/javascript"></script>
```
## Library Usage

In node:

Expand All @@ -34,36 +39,72 @@ For example, to get the Workbook content from an XLS file:

```js
var cfb = CFB.read(filename, {type: 'file'});
var workbook = cfb.find('Workbook');
var workbook = CFB.find(cfb, 'Workbook');
var data = workbook.content;
```

The `xlscfb.js` file is designed to be embedded in [js-xlsx](http://git.io/xlsx)

# API
## Command-Line Utility Usage

It is preferable to install the library globally with npm:

Typescript definitions are maintained in `types/index.d.ts`.
```bash
$ npm install -g cfb
```

The global installation adds a command `cfb` which can work with existing files:

- `cfb file` will extract the contents of the file to the current directory.
It will make the corresponding subdirectories.
- `cfb --list-files file` will show a listing of the contained files.
The format follows the `unzip -l` "short format".
- `cfb --repair file` will attempt to repair by reading and re-writing the file.
This fixes some issues with files generated by non-standard tools.


## JS API

TypeScript definitions are maintained in `types/index.d.ts`.

The CFB object exposes the following methods and properties:

`CFB.parse(blob)` takes a nodejs Buffer or an array of bytes and returns an
parsed representation of the data.

`CFB.read(blob, options)` wraps `parse`. `options.type` controls the behavior:
`CFB.read(blob, opts)` wraps `parse`. `opts.type` controls the behavior:

- `file`: `blob` should be a file name
- `base64`: `blob` should be a base64 string
- `binary`: `blob` should be a binary string
- `file`: `blob` is interpreted as a file name that will be read
- `base64`: `blob` is interpreted as base64 string
- `binary`: `blob` is interpreted as binary string
- default: `blob` is interpreted as nodejs buffer or array of bytes

`CFB.find(cfb, path)` performs a case-insensitive match for the path (or file
name, if there are no slashes) and returns an entry object or null if not found.

## Container Object Description
`CFB.write(cfb, opts)` generates a file based on the container. `opts.type`
controls the behavior:

- `base64`: returns a base64 string
- `binary`: returns a binary string
- default: returns a nodejs buffer or array of bytes

`CFB.writeFile(cfb, filename, opts)` creates a file with the specified name.


## Utility Functions

The utility functions are available in the `CFB.utils` object. Functions that
accept a `name` argument strictly deal with absolute file names:

The object returned by `parse` and `read` can be found in the source (`rval`).
It has the following properties and methods:
- `.cfb_new(?opts)` creates a new container object.
- `.cfb_add(cfb, name, ?content, ?opts)` adds a new file to the `cfb`.
- `.cfb_del(cfb, name)` deletes the specified file
- `.cfb_mov(cfb, old_name, new_name)` moves the old file to new path and name

- `.find(path)` is equivalent to `CFB.find(cfb, path)` and should not be used.

## Container Object Description

The objects returned by `parse` and `read` have the following properties:

- `.FullPaths` is an array of the names of all of the streams (files) and
storages (directories) in the container. The paths are properly prefixed from
Expand All @@ -77,32 +118,37 @@ It has the following properties and methods:

- `.raw` contains the raw header and sectors


## Entry Object Description

The entry objects are available from `FullPathDir` and `FileIndex` elements of
the container object.
the container object:

```typescript
interface CFBEntry {
name: string; /** Case-sensitive internal name */
type: number; /** 1 = dir, 2 = file, 5 = root ; see [MS-CFB] 2.6.1 */
content: Buffer | number[] | Uint8Array; /** Raw Content */
ct?: Date; /** Creation Time */
mt?: Date; /** Modification Time */
}
```

- `.name` is the (case sensitive) internal name
- `.type` is the type as defined in "Object Type" in [MS-CFB] 2.6.1:
`2 (stream)` for files, `1 (storage)` for dirs, `5 (root)` for root)
- `.content` is a Buffer/Array with the raw content
- `.ct`/`.mt` are the creation and modification time (if provided in file)

# License
## License

This implementation is covered under Apache 2.0 license. It complies with the
[Open Specifications Promise](http://www.microsoft.com/openspecifications/)
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.

[![Build Status](https://travis-ci.org/SheetJS/js-cfb.svg?branch=master)](https://travis-ci.org/SheetJS/js-cfb)

[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-cfb/master.svg)](https://coveralls.io/r/SheetJS/js-cfb?branch=master)
## References

[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-cfb?pixel)](https://github.com/SheetJS/js-cfb)

[![NPM Downloads](https://img.shields.io/npm/dt/cfb.svg)](https://npmjs.org/package/cfb)
<details>
<summary><b>OSP-covered Specifications</b> (click to show)</summary>

[![Dependencies Status](https://david-dm.org/sheetjs/js-cfb/status.svg)](https://david-dm.org/sheetjs/js-cfb)
- [MS-CFB]: Compound File Binary File Format

[![ghit.me](https://ghit.me/badge.svg?repo=sheetjs/js-cfb)](https://ghit.me/repo/sheetjs/js-cfb)
</details>


25 changes: 16 additions & 9 deletions bin/cfb.njs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
/* eslint-env node */
/* vim: set ts=2 ft=javascript: */
var X = require('../');
var fs = require('fs'), program = require('commander');
var fs = require('fs');
var program = require('commander');
var PRINTJ = require("printj");
program
.version(X.version)
.usage('[options] <file>')
.option('-q, --quiet', 'process but do not report')
.option('-l, --list-files', 'list files')
.option('-d, --dump', 'dump internal representation but do not extract')
.option('-r, --repair', 'attempt to repair and garbage-collect archive')
.option('--dev', 'development mode')
.option('--read', 'read but do not print out contents');

Expand All @@ -33,26 +36,30 @@ if(program.dump) {
console.log(cfb.FullPathDir);
process.exit(0);
}
if(program.listFiles) {
var PRINTJ = require("printj"), sprintf = PRINTJ.sprintf;
if(program.repair) {
X.writeFile(cfb, program.args[0]);
process.exit(0);
}

var sprintf = PRINTJ.sprintf;
function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/, function($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
if(program.listFiles) {
var format_date = function(date/*:Date*/)/*:string*/ {
return sprintf("%02u-%02u-%02u %02u:%02u", date.getUTCMonth()+1, date.getUTCDate(), date.getUTCFullYear()%100, date.getUTCHours(), date.getUTCMinutes());
};

var basetime = new Date(1980,0,1);
var cnt = 0;
var rootsize = 0, filesize = 0;
var cnt = 0, rootsize = 0, filesize = 0;
console.log(" Length Date Time Name");
console.log(" -------- ---- ---- ----");
cfb.FileIndex.forEach(function(file, i) {
cfb.FileIndex.forEach(function(file, i/*:number*/) {
switch(file.type) {
case 5:
basetime = file.ct || file.mt || basetime;
rootsize = file.size;
break;
case 2:
console.log(sprintf("%9lu %s %s", file.size, format_date(basetime), cfb.FullPaths[i]));
console.log(sprintf("%9lu %s %s", file.size, format_date(basetime), fix_string(cfb.FullPaths[i])));
filesize += file.size;
++cnt;
}
Expand All @@ -64,10 +71,10 @@ if(program.listFiles) {
}
for(var i=0; i!==cfb.FullPaths.length; ++i) {
if(cfb.FullPaths[i].slice(-1) === "/") {
console.error("mkdir " + cfb.FullPaths[i]);
console.error("mkdir " + fix_string(cfb.FullPaths[i]));
fs.mkdirSync(cfb.FullPaths[i]);
} else {
console.error("writing " + cfb.FullPaths[i]);
console.error("write " + fix_string(cfb.FullPaths[i]));
fs.writeFileSync(cfb.FullPaths[i], /*::new Buffer((*/cfb.FileIndex[i].content/*:: :any))*/);
}
}
2 changes: 2 additions & 0 deletions bits/00_header.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* 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 */

46 changes: 46 additions & 0 deletions bits/04_base64.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
var Base64 = (function make_b64(){
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function(input/*:string*/)/*:string*/ {
var o = "";
var c1/*:number*/, c2/*:number*/, c3/*:number*/;
var e1/*:number*/, e2/*:number*/, e3/*:number*/, e4/*:number*/;
for(var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
e1 = (c1 >> 2);

c2 = input.charCodeAt(i++);
e2 = ((c1 & 3) << 4) | (c2 >> 4);

c3 = input.charCodeAt(i++);
e3 = ((c2 & 15) << 2) | (c3 >> 6);
e4 = (c3 & 63);
if (isNaN(c2)) { e3 = e4 = 64; }
else if (isNaN(c3)) { e4 = 64; }
o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
}
return o;
},
decode: function b64_decode(input/*:string*/)/*:string*/ {
var o = "";
var c1/*:number*/, c2/*:number*/, c3/*:number*/;
var e1/*:number*/, e2/*:number*/, e3/*:number*/, e4/*:number*/;
input = input.replace(/[^\w\+\/\=]/g, "");
for(var i = 0; i < input.length;) {
e1 = map.indexOf(input.charAt(i++));
e2 = map.indexOf(input.charAt(i++));
c1 = (e1 << 2) | (e2 >> 4);
o += String.fromCharCode(c1);

e3 = map.indexOf(input.charAt(i++));
c2 = ((e2 & 15) << 4) | (e3 >> 2);
if (e3 !== 64) { o += String.fromCharCode(c2); }

e4 = map.indexOf(input.charAt(i++));
c3 = ((e3 & 3) << 6) | e4;
if (e4 !== 64) { o += String.fromCharCode(c3); }
}
return o;
}
};
})();

0 comments on commit 03044b3

Please sign in to comment.