From fcc05e3567a233e7d1f3275ae05bab6752ac23ab Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 2 Nov 2014 23:02:42 -0500 Subject: [PATCH] version bump 0.10.2: proper directory/FAT analysis - reprocess directory sector lists if not available - search now strips out OLE metacharacters \0-\5 - strip sourceMappingURL references from minified scripts (h/t @vinin3) - added xlscfb.js for js-xls --- .gitignore | 8 +- Makefile | 50 +++++- README.md | 23 +-- bin/{cfb => cfb.njs} | 14 +- bits/31_version.js | 2 +- bits/40_parse.js | 5 +- bits/41_mver.js | 4 +- bits/44_findpath.js | 6 +- bits/45_readfat.js | 20 +++ bits/46_readdir.js | 2 +- bits/49_readutils.js | 10 +- cfb.js | 49 +++-- dist/cfb.js | 49 +++-- dist/cfb.min.js | 3 +- dist/cfb.min.map | 2 +- dist/xlscfb.js | 383 ++++++++++++++++++++++++++++++++++++++++ misc/strip_sourcemap.sh | 11 ++ misc/suppress_export.js | 1 + package.json | 2 +- test.js | 26 ++- xlscfb.js | 383 ++++++++++++++++++++++++++++++++++++++++ 21 files changed, 984 insertions(+), 69 deletions(-) rename bin/{cfb => cfb.njs} (67%) create mode 100644 dist/xlscfb.js create mode 100755 misc/strip_sourcemap.sh create mode 100644 misc/suppress_export.js create mode 100644 xlscfb.js diff --git a/.gitignore b/.gitignore index 4ddf47a..bfe1a57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ -test_files -node_modules/ -*.xls +node_modules misc/coverage.html prof.js v8.log +test_files +test_files_pres +*.xls +*.sheetjs diff --git a/Makefile b/Makefile index 022b93a..1fa6e4f 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,16 @@ LIB=cfb +FMT=xls doc ppt misc full +REQS= +ADDONS= +AUXTARGETS=xlscfb.js + +ULIB=$(shell echo $(LIB) | tr a-z A-Z) DEPS=$(sort $(wildcard bits/*.js)) TARGET=$(LIB).js +.PHONY: all +all: $(TARGET) $(AUXTARGETS) + $(TARGET): $(DEPS) cat $^ | tr -d '\15\32' > $@ @@ -11,32 +20,48 @@ bits/31_version.js: package.json .PHONY: clean clean: rm -f $(TARGET) - rm -rf ./test_files/ + +.PHONY: clean-data +clean-data: + rm -fr ./test_files/ ./test_files_pres/ .PHONY: init init: if [ ! -e test_files ]; then git clone https://github.com/SheetJS/test_files; fi cd test_files; git pull; make + if [ ! -e test_files_pres ]; then git clone https://github.com/SheetJS/test_files_pres; fi + cd test_files_pres; git pull .PHONY: test mocha test mocha: test.js - mocha -R spec + mocha -R spec -t 20000 .PHONY: prof prof: cat misc/prof.js test.js > prof.js node --prof prof.js +TESTFMT=$(patsubst %,test_%,$(FMT)) +.PHONY: $(TESTFMT) +$(TESTFMT): test_%: + FMTS=$* make test + + .PHONY: lint lint: $(TARGET) - jshint --show-non-errors $(TARGET) - jscs $(TARGET) + jshint --show-non-errors $(TARGET) $(AUXTARGETS) + jscs $(TARGET) $(AUXTARGETS) .PHONY: cov cov-spin cov: misc/coverage.html cov-spin: make cov & bash misc/spin.sh $$! +COVFMT=$(patsubst %,cov_%,$(FMT)) +.PHONY: $(COVFMT) +$(COVFMT): cov_%: + FMTS=$* make cov + misc/coverage.html: $(TARGET) test.js mocha --require blanket -R html-cov > $@ @@ -48,7 +73,22 @@ coveralls-spin: make coveralls & bash misc/spin.sh $$! .PHONY: dist -dist: $(TARGET) +dist: dist-deps $(TARGET) cp $(TARGET) dist/ cp LICENSE dist/ uglifyjs $(TARGET) -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: aux +aux: $(AUXTARGETS) + +.PHONY: xls +xls: xlscfb.js + +XLSDEPS=misc/suppress_export.js $(filter-out bits/08_blob.js,$(DEPS)) +xlscfb.js: $(XLSDEPS) + cat $^ | tr -d '\15\32' > $@ + +.PHONY: dist-deps +dist-deps: xlscfb.js + cp xlscfb.js dist/xlscfb.js diff --git a/README.md b/README.md index f236e27..c2fcb31 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Compound File Binary Format +# 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, DOC, and other Microsoft -Office file types). +Office file types). # Utility Installation and Usage @@ -14,7 +14,7 @@ $ cfb path/to/CFB/file ``` 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 +files that line up with the tree-based structure of the storage. Metadata such as the red-black tree are discarded (and in the future, new CFB containers will exclusively use black nodes) @@ -55,9 +55,9 @@ It has the following properties and methods: - `.find(path)` performs a case-insensitive match for the path (or file name, if there are no slashes) and returns an entry object (described later) or null if - not found + not found -- `.FullPaths` is an array of the names of all of the streams (files) and +- `.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 the root entry (so the entries are unique) @@ -67,24 +67,27 @@ It has the following properties and methods: - `.FileIndex` is an array of the objects from `.FullPathDir`, in the same order as `.FullPaths`. -- `.raw` contains the raw header and sectors +- `.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 entry objects are available from `FullPathDir` and `FileIndex` elements of +the container object. - `.name` is the (case sensitive) internal name -- `.type` is the type (`2 (stream)` for files, `1 (storage)` for dirs, `5 (root)` for root) +- `.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) # Notes -Case comparison has not been verified for non-ASCII character +Case comparison has not been verified for non-ASCII characters Writing is not supported. It is in the works, but it has not yet been released. +The `xlscfb.js` file is designed to be embedded in [js-xls](http://git.io/xls) + # License This implementation is covered under Apache 2.0 license. It complies with the diff --git a/bin/cfb b/bin/cfb.njs similarity index 67% rename from bin/cfb rename to bin/cfb.njs index 3e19d9c..8b18dcd 100755 --- a/bin/cfb +++ b/bin/cfb.njs @@ -5,7 +5,9 @@ var fs = require('fs'), program = require('commander'); program .version(CFB.version) .usage('[options] ') - .option('-q, --quiet', 'print but do not extract') + .option('-q, --quiet', 'process but do not report') + .option('-d, --dump', 'dump internal representation but do not extract') + .option('--dev', 'development mode') .parse(process.argv); if(program.args.length === 0 || !fs.existsSync(program.args[0])) { @@ -13,15 +15,17 @@ if(program.args.length === 0 || !fs.existsSync(program.args[0])) { process.exit(1); } -var cfb = CFB.read(program.args[0], {type:'file'}); -if(program.quiet) { +var opts = {type:'file'}; +if(program.dev) opts.WTF = true; + +var cfb = CFB.read(program.args[0], opts); +if(program.dump) { console.log("Full Paths:") console.log(cfb.FullPaths.map(function(x) { return " " + x; }).join("\n")); console.log("Full Path Directory:") console.log(cfb.FullPathDir); - return; } -for(var i=0; i != cfb.FullPaths.length; ++i) { +if(!program.quiet && !program.dump) for(var i=0; i!=cfb.FullPaths.length; ++i) { if(cfb.FullPaths[i].slice(-1) === "/") { console.error("mkdir " + cfb.FullPaths[i]); fs.mkdirSync(cfb.FullPaths[i]); diff --git a/bits/31_version.js b/bits/31_version.js index bcf5a79..172c898 100644 --- a/bits/31_version.js +++ b/bits/31_version.js @@ -1 +1 @@ -exports.version = '0.10.1'; +exports.version = '0.10.2'; diff --git a/bits/40_parse.js b/bits/40_parse.js index f04b812..a8dad2e 100644 --- a/bits/40_parse.js +++ b/bits/40_parse.js @@ -14,7 +14,8 @@ var blob = file.slice(0,512); prep_blob(blob, 0); /* major version */ -mver = check_get_mver(blob); +var mv = check_get_mver(blob); +mver = mv[0]; switch(mver) { case 3: ssz = 512; break; case 4: ssz = 4096; break; default: throw "Major Version: Expected 3 or 4 saw " + mver; @@ -74,6 +75,8 @@ var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz); sector_list[dir_start].name = "!Directory"; if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT"; sector_list[fat_addrs[0]].name = "!FAT"; +sector_list.fat_addrs = fat_addrs; +sector_list.ssz = ssz; /* [MS-CFB] 2.6.1 Compound File Directory Entry */ var files = {}, Paths = [], FileIndex = [], FullPaths = [], FullPathDir = {}; diff --git a/bits/41_mver.js b/bits/41_mver.js index e67db91..b5db2ea 100644 --- a/bits/41_mver.js +++ b/bits/41_mver.js @@ -7,9 +7,9 @@ function check_get_mver(blob) { blob.chk(HEADER_CLSID, 'CLSID: '); // minor version 2 - blob.l += 2; + var mver = blob.read_shift(2, 'u'); - return blob.read_shift(2,'u'); + return [blob.read_shift(2,'u'), mver]; } function check_shifts(blob, mver) { var shift = 0x09; diff --git a/bits/44_findpath.js b/bits/44_findpath.js index 6575379..596279a 100644 --- a/bits/44_findpath.js +++ b/bits/44_findpath.js @@ -2,13 +2,13 @@ function make_find_path(FullPaths, Paths, FileIndex, files, root_name) { var UCFullPaths = new Array(FullPaths.length); var UCPaths = new Array(Paths.length), i; - for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase(); - for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase(); + for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); + for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); return function find_path(path) { var k; if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; } else k = path.indexOf("/") !== -1; - var UCPath = path.toUpperCase(); + var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!'); var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w === -1) return null; return k === true ? FileIndex[w] : files[Paths[w]]; diff --git a/bits/45_readfat.js b/bits/45_readfat.js index 2c205d6..59bca6d 100644 --- a/bits/45_readfat.js +++ b/bits/45_readfat.js @@ -14,6 +14,26 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) { } } +/** Follow the linked list of sectors for a given starting point */ +function get_sector_list(sectors, start, fat_addrs, ssz, chkd) { + var sl = sectors.length; + var buf, buf_chain; + if(!chkd) chkd = new Array(sl); + var modulus = ssz - 1, j, jj; + buf = []; + buf_chain = []; + for(j=start; j>=0;) { + chkd[j] = true; + buf[buf.length] = j; + buf_chain.push(sectors[j]); + var addr = fat_addrs[Math.floor(j*4/ssz)]; + jj = ((j*4) & modulus); + if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz; + j = __readInt32LE(sectors[addr], jj); + } + return {nodes: buf, data:__toBuffer([buf_chain])}; +} + /** Chase down the sector linked lists */ function make_sector_list(sectors, dir_start, fat_addrs, ssz) { var sl = sectors.length, sector_list = new Array(sl); diff --git a/bits/46_readdir.js b/bits/46_readdir.js index 0551f16..d30a99c 100644 --- a/bits/46_readdir.js +++ b/bits/46_readdir.js @@ -37,7 +37,7 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil /*minifat_size = o.size;*/ } else if(o.size >= 4096 /* MSCSZ */) { o.storage = 'fat'; - if(sector_list[o.start] === undefined) if((o.start+=dir_start)>=sectors.length) o.start-=sectors.length; + if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); sector_list[o.start].name = o.name; o.content = sector_list[o.start].data.slice(0,o.size); prep_blob(o.content, 0); diff --git a/bits/49_readutils.js b/bits/49_readutils.js index 7a85529..771bf59 100644 --- a/bits/49_readutils.js +++ b/bits/49_readutils.js @@ -1,14 +1,14 @@ var fs; -function readFileSync(filename) { +function readFileSync(filename, options) { if(fs === undefined) fs = require('fs'); - return parse(fs.readFileSync(filename)); + return parse(fs.readFileSync(filename), options); } function readSync(blob, options) { switch(options !== undefined && options.type !== undefined ? options.type : "base64") { - case "file": return readFileSync(blob); - case "base64": return parse(s2a(Base64.decode(blob))); - case "binary": return parse(s2a(blob)); + case "file": return readFileSync(blob, options); + case "base64": return parse(s2a(Base64.decode(blob)), options); + case "binary": return parse(s2a(blob), options); } return parse(blob); } diff --git a/cfb.js b/cfb.js index 10f0ad7..4d976a0 100644 --- a/cfb.js +++ b/cfb.js @@ -86,7 +86,7 @@ function prep_blob(blob, pos) { /* [MS-CFB] v20130118 */ var CFB = (function _CFB(){ var exports = {}; -exports.version = '0.10.1'; +exports.version = '0.10.2'; function parse(file) { var mver = 3; // major version var ssz = 512; // sector size @@ -103,7 +103,8 @@ var blob = file.slice(0,512); prep_blob(blob, 0); /* major version */ -mver = check_get_mver(blob); +var mv = check_get_mver(blob); +mver = mv[0]; switch(mver) { case 3: ssz = 512; break; case 4: ssz = 4096; break; default: throw "Major Version: Expected 3 or 4 saw " + mver; @@ -163,6 +164,8 @@ var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz); sector_list[dir_start].name = "!Directory"; if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT"; sector_list[fat_addrs[0]].name = "!FAT"; +sector_list.fat_addrs = fat_addrs; +sector_list.ssz = ssz; /* [MS-CFB] 2.6.1 Compound File Directory Entry */ var files = {}, Paths = [], FileIndex = [], FullPaths = [], FullPathDir = {}; @@ -194,9 +197,9 @@ function check_get_mver(blob) { blob.chk(HEADER_CLSID, 'CLSID: '); // minor version 2 - blob.l += 2; + var mver = blob.read_shift(2, 'u'); - return blob.read_shift(2,'u'); + return [blob.read_shift(2,'u'), mver]; } function check_shifts(blob, mver) { var shift = 0x09; @@ -272,13 +275,13 @@ function build_full_paths(FI, FPD, FP, Paths) { function make_find_path(FullPaths, Paths, FileIndex, files, root_name) { var UCFullPaths = new Array(FullPaths.length); var UCPaths = new Array(Paths.length), i; - for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase(); - for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase(); + for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); + for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); return function find_path(path) { var k; if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; } else k = path.indexOf("/") !== -1; - var UCPath = path.toUpperCase(); + var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!'); var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w === -1) return null; return k === true ? FileIndex[w] : files[Paths[w]]; @@ -301,6 +304,26 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) { } } +/** Follow the linked list of sectors for a given starting point */ +function get_sector_list(sectors, start, fat_addrs, ssz, chkd) { + var sl = sectors.length; + var buf, buf_chain; + if(!chkd) chkd = new Array(sl); + var modulus = ssz - 1, j, jj; + buf = []; + buf_chain = []; + for(j=start; j>=0;) { + chkd[j] = true; + buf[buf.length] = j; + buf_chain.push(sectors[j]); + var addr = fat_addrs[Math.floor(j*4/ssz)]; + jj = ((j*4) & modulus); + if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz; + j = __readInt32LE(sectors[addr], jj); + } + return {nodes: buf, data:__toBuffer([buf_chain])}; +} + /** Chase down the sector linked lists */ function make_sector_list(sectors, dir_start, fat_addrs, ssz) { var sl = sectors.length, sector_list = new Array(sl); @@ -364,7 +387,7 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil /*minifat_size = o.size;*/ } else if(o.size >= 4096 /* MSCSZ */) { o.storage = 'fat'; - if(sector_list[o.start] === undefined) if((o.start+=dir_start)>=sectors.length) o.start-=sectors.length; + if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); sector_list[o.start].name = o.name; o.content = sector_list[o.start].data.slice(0,o.size); prep_blob(o.content, 0); @@ -385,16 +408,16 @@ function read_date(blob, offset) { } var fs; -function readFileSync(filename) { +function readFileSync(filename, options) { if(fs === undefined) fs = require('fs'); - return parse(fs.readFileSync(filename)); + return parse(fs.readFileSync(filename), options); } function readSync(blob, options) { switch(options !== undefined && options.type !== undefined ? options.type : "base64") { - case "file": return readFileSync(blob); - case "base64": return parse(s2a(Base64.decode(blob))); - case "binary": return parse(s2a(blob)); + case "file": return readFileSync(blob, options); + case "base64": return parse(s2a(Base64.decode(blob)), options); + case "binary": return parse(s2a(blob), options); } return parse(blob); } diff --git a/dist/cfb.js b/dist/cfb.js index 10f0ad7..4d976a0 100644 --- a/dist/cfb.js +++ b/dist/cfb.js @@ -86,7 +86,7 @@ function prep_blob(blob, pos) { /* [MS-CFB] v20130118 */ var CFB = (function _CFB(){ var exports = {}; -exports.version = '0.10.1'; +exports.version = '0.10.2'; function parse(file) { var mver = 3; // major version var ssz = 512; // sector size @@ -103,7 +103,8 @@ var blob = file.slice(0,512); prep_blob(blob, 0); /* major version */ -mver = check_get_mver(blob); +var mv = check_get_mver(blob); +mver = mv[0]; switch(mver) { case 3: ssz = 512; break; case 4: ssz = 4096; break; default: throw "Major Version: Expected 3 or 4 saw " + mver; @@ -163,6 +164,8 @@ var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz); sector_list[dir_start].name = "!Directory"; if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT"; sector_list[fat_addrs[0]].name = "!FAT"; +sector_list.fat_addrs = fat_addrs; +sector_list.ssz = ssz; /* [MS-CFB] 2.6.1 Compound File Directory Entry */ var files = {}, Paths = [], FileIndex = [], FullPaths = [], FullPathDir = {}; @@ -194,9 +197,9 @@ function check_get_mver(blob) { blob.chk(HEADER_CLSID, 'CLSID: '); // minor version 2 - blob.l += 2; + var mver = blob.read_shift(2, 'u'); - return blob.read_shift(2,'u'); + return [blob.read_shift(2,'u'), mver]; } function check_shifts(blob, mver) { var shift = 0x09; @@ -272,13 +275,13 @@ function build_full_paths(FI, FPD, FP, Paths) { function make_find_path(FullPaths, Paths, FileIndex, files, root_name) { var UCFullPaths = new Array(FullPaths.length); var UCPaths = new Array(Paths.length), i; - for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase(); - for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase(); + for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); + for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); return function find_path(path) { var k; if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; } else k = path.indexOf("/") !== -1; - var UCPath = path.toUpperCase(); + var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!'); var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w === -1) return null; return k === true ? FileIndex[w] : files[Paths[w]]; @@ -301,6 +304,26 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) { } } +/** Follow the linked list of sectors for a given starting point */ +function get_sector_list(sectors, start, fat_addrs, ssz, chkd) { + var sl = sectors.length; + var buf, buf_chain; + if(!chkd) chkd = new Array(sl); + var modulus = ssz - 1, j, jj; + buf = []; + buf_chain = []; + for(j=start; j>=0;) { + chkd[j] = true; + buf[buf.length] = j; + buf_chain.push(sectors[j]); + var addr = fat_addrs[Math.floor(j*4/ssz)]; + jj = ((j*4) & modulus); + if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz; + j = __readInt32LE(sectors[addr], jj); + } + return {nodes: buf, data:__toBuffer([buf_chain])}; +} + /** Chase down the sector linked lists */ function make_sector_list(sectors, dir_start, fat_addrs, ssz) { var sl = sectors.length, sector_list = new Array(sl); @@ -364,7 +387,7 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil /*minifat_size = o.size;*/ } else if(o.size >= 4096 /* MSCSZ */) { o.storage = 'fat'; - if(sector_list[o.start] === undefined) if((o.start+=dir_start)>=sectors.length) o.start-=sectors.length; + if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); sector_list[o.start].name = o.name; o.content = sector_list[o.start].data.slice(0,o.size); prep_blob(o.content, 0); @@ -385,16 +408,16 @@ function read_date(blob, offset) { } var fs; -function readFileSync(filename) { +function readFileSync(filename, options) { if(fs === undefined) fs = require('fs'); - return parse(fs.readFileSync(filename)); + return parse(fs.readFileSync(filename), options); } function readSync(blob, options) { switch(options !== undefined && options.type !== undefined ? options.type : "base64") { - case "file": return readFileSync(blob); - case "base64": return parse(s2a(Base64.decode(blob))); - case "binary": return parse(s2a(blob)); + case "file": return readFileSync(blob, options); + case "base64": return parse(s2a(Base64.decode(blob)), options); + case "binary": return parse(s2a(blob), options); } return parse(blob); } diff --git a/dist/cfb.min.js b/dist/cfb.min.js index d1cbca1..eb3a884 100644 --- a/dist/cfb.min.js +++ b/dist/cfb.min.js @@ -1,3 +1,2 @@ /* cfb.js (C) 2013-2014 SheetJS -- http://sheetjs.com */ -var Base64=function(){var map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{decode:function(input){var o="";var c1,c2,c3;var e1,e2,e3,e4;input=input.replace(/[^\w\+\/\=]/g,"");for(var i=0;i>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 chr0=/\u0000/g,chr1=/[\u0001-\u0006]/;var s2a,_s2a;s2a=_s2a=function _s2a(s){return s.split("").map(function(x){return x.charCodeAt(0)&255})};var __toBuffer,___toBuffer;__toBuffer=___toBuffer=function(bufs){var x=[];for(var i=0;i0&&Buffer.isBuffer(bufs[0][0])?Buffer.concat(bufs[0]):___toBuffer(bufs)};s2a=function(s){return Buffer(s,"binary")};bconcat=function(bufs){return Buffer.isBuffer(bufs[0])?Buffer.concat(bufs):[].concat.apply([],bufs)}}var __readUInt8=function(b,idx){return b[idx]};var __readUInt16LE=function(b,idx){return b[idx+1]*(1<<8)+b[idx]};var __readInt16LE=function(b,idx){var u=b[idx+1]*(1<<8)+b[idx];return u<32768?u:(65535-u+1)*-1};var __readUInt32LE=function(b,idx){return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]};var __readInt32LE=function(b,idx){return(b[idx+3]<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]};function ReadShift(size,t){var oI,oS,type=0;switch(size){case 1:oI=__readUInt8(this,this.l);break;case 2:oI=(t!=="i"?__readUInt16LE:__readInt16LE)(this,this.l);break;case 4:oI=__readInt32LE(this,this.l);break;case 16:type=2;oS=__hexlify(this,this.l,size)}this.l+=size;if(type===0)return oI;return oS}function CheckField(hexstr,fld){var m=__hexlify(this,this.l,hexstr.length>>1);if(m!==hexstr)throw fld+"Expected "+hexstr+" saw "+m;this.l+=hexstr.length>>1}function prep_blob(blob,pos){blob.l=pos;blob.read_shift=ReadShift;blob.chk=CheckField}var CFB=function _CFB(){var exports={};exports.version="0.10.1";function parse(file){var mver=3;var ssz=512;var nmfs=0;var ndfs=0;var dir_start=0;var minifat_start=0;var difat_start=0;var fat_addrs=[];var blob=file.slice(0,512);prep_blob(blob,0);mver=check_get_mver(blob);switch(mver){case 3:ssz=512;break;case 4:ssz=4096;break;default:throw"Major Version: Expected 3 or 4 saw "+mver}if(ssz!==512){blob=file.slice(0,ssz);prep_blob(blob,28)}var header=file.slice(0,ssz);check_shifts(blob,mver);var nds=blob.read_shift(4,"i");if(mver===3&&nds!==0)throw"# Directory Sectors: Expected 0 saw "+nds;blob.l+=4;dir_start=blob.read_shift(4,"i");blob.l+=4;blob.chk("00100000","Mini Stream Cutoff Size: ");minifat_start=blob.read_shift(4,"i");nmfs=blob.read_shift(4,"i");difat_start=blob.read_shift(4,"i");ndfs=blob.read_shift(4,"i");for(var q,j=0;j<109;++j){q=blob.read_shift(4,"i");if(q<0)break;fat_addrs[j]=q}var sectors=sectorify(file,ssz);sleuth_fat(difat_start,ndfs,sectors,ssz,fat_addrs);var sector_list=make_sector_list(sectors,dir_start,fat_addrs,ssz);sector_list[dir_start].name="!Directory";if(nmfs>0&&minifat_start!==ENDOFCHAIN)sector_list[minifat_start].name="!MiniFAT";sector_list[fat_addrs[0]].name="!FAT";var files={},Paths=[],FileIndex=[],FullPaths=[],FullPathDir={};read_directory(dir_start,sector_list,sectors,Paths,nmfs,files,FileIndex);build_full_paths(FileIndex,FullPathDir,FullPaths,Paths);var root_name=Paths.shift();Paths.root=root_name;var find_path=make_find_path(FullPaths,Paths,FileIndex,files,root_name);return{raw:{header:header,sectors:sectors},FileIndex:FileIndex,FullPaths:FullPaths,FullPathDir:FullPathDir,find:find_path}}function check_get_mver(blob){blob.chk(HEADER_SIGNATURE,"Header Signature: ");blob.chk(HEADER_CLSID,"CLSID: ");blob.l+=2;return blob.read_shift(2,"u")}function check_shifts(blob,mver){var shift=9;blob.chk("feff","Byte Order: ");switch(shift=blob.read_shift(2)){case 9:if(mver!==3)throw"MajorVersion/SectorShift Mismatch";break;case 12:if(mver!==4)throw"MajorVersion/SectorShift Mismatch";break;default:throw"Sector Shift: Expected 9 or 12 saw "+shift}blob.chk("0600","Mini Sector Shift: ");blob.chk("000000000000","Reserved: ")}function sectorify(file,ssz){var nsectors=Math.ceil(file.length/ssz)-1;var sectors=new Array(nsectors);for(var i=1;i>>2)-1;for(var i=0;i=sl)k-=sl;if(chkd[k]===true)continue;buf_chain=[];for(j=k;j>=0;){chkd[j]=true;buf[buf.length]=j;buf_chain.push(sectors[j]);var addr=fat_addrs[Math.floor(j*4/ssz)];jj=j*4&modulus;if(ssz<4+jj)throw"FAT boundary crossed: "+j+" 4 "+ssz;j=__readInt32LE(sectors[addr],jj)}sector_list[k]={nodes:buf,data:__toBuffer([buf_chain])}}return sector_list}function read_directory(dir_start,sector_list,sectors,Paths,nmfs,files,FileIndex){var blob;var minifat_store=0,pl=Paths.length?2:0;var sector=sector_list[dir_start].data;var i=0,namelen=0,name,o,ctime,mtime;for(;i0&&minifat_store!==ENDOFCHAIN)sector_list[minifat_store].name="!StreamData"}else if(o.size>=4096){o.storage="fat";if(sector_list[o.start]===undefined)if((o.start+=dir_start)>=sectors.length)o.start-=sectors.length;sector_list[o.start].name=o.name;o.content=sector_list[o.start].data.slice(0,o.size);prep_blob(o.content,0)}else{o.storage="minifat";if(minifat_store!==ENDOFCHAIN&&o.start!==ENDOFCHAIN){o.content=sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size);prep_blob(o.content,0)}}files[name]=o;FileIndex.push(o)}}function read_date(blob,offset){return new Date((__readUInt32LE(blob,offset+4)/1e7*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7-11644473600)*1e3)}var fs;function readFileSync(filename){if(fs===undefined)fs=require("fs");return parse(fs.readFileSync(filename))}function readSync(blob,options){switch(options!==undefined&&options.type!==undefined?options.type:"base64"){case"file":return readFileSync(blob);case"base64":return parse(s2a(Base64.decode(blob)));case"binary":return parse(s2a(blob))}return parse(blob)}var MSSZ=64;var ENDOFCHAIN=-2;var HEADER_SIGNATURE="d0cf11e0a1b11ae1";var HEADER_CLSID="00000000000000000000000000000000";var consts={MAXREGSECT:-6,DIFSECT:-4,FATSECT:-3,ENDOFCHAIN:ENDOFCHAIN,FREESECT:-1,HEADER_SIGNATURE:HEADER_SIGNATURE,HEADER_MINOR_VERSION:"3e00",MAXREGSID:-6,NOSTREAM:-1,HEADER_CLSID:HEADER_CLSID,EntryTypes:["unknown","storage","stream","lockbytes","property","root"]};exports.read=readSync;exports.parse=parse;exports.utils={ReadShift:ReadShift,CheckField:CheckField,prep_blob:prep_blob,bconcat:bconcat,consts:consts};return exports}();if(typeof require!=="undefined"&&typeof module!=="undefined"&&typeof DO_NOT_EXPORT_CFB==="undefined"){module.exports=CFB} -//# sourceMappingURL=dist/cfb.min.map \ No newline at end of file +var Base64=function(){var map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{decode:function(input){var o="";var c1,c2,c3;var e1,e2,e3,e4;input=input.replace(/[^\w\+\/\=]/g,"");for(var i=0;i>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 chr0=/\u0000/g,chr1=/[\u0001-\u0006]/;var s2a,_s2a;s2a=_s2a=function _s2a(s){return s.split("").map(function(x){return x.charCodeAt(0)&255})};var __toBuffer,___toBuffer;__toBuffer=___toBuffer=function(bufs){var x=[];for(var i=0;i0&&Buffer.isBuffer(bufs[0][0])?Buffer.concat(bufs[0]):___toBuffer(bufs)};s2a=function(s){return Buffer(s,"binary")};bconcat=function(bufs){return Buffer.isBuffer(bufs[0])?Buffer.concat(bufs):[].concat.apply([],bufs)}}var __readUInt8=function(b,idx){return b[idx]};var __readUInt16LE=function(b,idx){return b[idx+1]*(1<<8)+b[idx]};var __readInt16LE=function(b,idx){var u=b[idx+1]*(1<<8)+b[idx];return u<32768?u:(65535-u+1)*-1};var __readUInt32LE=function(b,idx){return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]};var __readInt32LE=function(b,idx){return(b[idx+3]<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]};function ReadShift(size,t){var oI,oS,type=0;switch(size){case 1:oI=__readUInt8(this,this.l);break;case 2:oI=(t!=="i"?__readUInt16LE:__readInt16LE)(this,this.l);break;case 4:oI=__readInt32LE(this,this.l);break;case 16:type=2;oS=__hexlify(this,this.l,size)}this.l+=size;if(type===0)return oI;return oS}function CheckField(hexstr,fld){var m=__hexlify(this,this.l,hexstr.length>>1);if(m!==hexstr)throw fld+"Expected "+hexstr+" saw "+m;this.l+=hexstr.length>>1}function prep_blob(blob,pos){blob.l=pos;blob.read_shift=ReadShift;blob.chk=CheckField}var CFB=function _CFB(){var exports={};exports.version="0.10.2";function parse(file){var mver=3;var ssz=512;var nmfs=0;var ndfs=0;var dir_start=0;var minifat_start=0;var difat_start=0;var fat_addrs=[];var blob=file.slice(0,512);prep_blob(blob,0);var mv=check_get_mver(blob);mver=mv[0];switch(mver){case 3:ssz=512;break;case 4:ssz=4096;break;default:throw"Major Version: Expected 3 or 4 saw "+mver}if(ssz!==512){blob=file.slice(0,ssz);prep_blob(blob,28)}var header=file.slice(0,ssz);check_shifts(blob,mver);var nds=blob.read_shift(4,"i");if(mver===3&&nds!==0)throw"# Directory Sectors: Expected 0 saw "+nds;blob.l+=4;dir_start=blob.read_shift(4,"i");blob.l+=4;blob.chk("00100000","Mini Stream Cutoff Size: ");minifat_start=blob.read_shift(4,"i");nmfs=blob.read_shift(4,"i");difat_start=blob.read_shift(4,"i");ndfs=blob.read_shift(4,"i");for(var q,j=0;j<109;++j){q=blob.read_shift(4,"i");if(q<0)break;fat_addrs[j]=q}var sectors=sectorify(file,ssz);sleuth_fat(difat_start,ndfs,sectors,ssz,fat_addrs);var sector_list=make_sector_list(sectors,dir_start,fat_addrs,ssz);sector_list[dir_start].name="!Directory";if(nmfs>0&&minifat_start!==ENDOFCHAIN)sector_list[minifat_start].name="!MiniFAT";sector_list[fat_addrs[0]].name="!FAT";sector_list.fat_addrs=fat_addrs;sector_list.ssz=ssz;var files={},Paths=[],FileIndex=[],FullPaths=[],FullPathDir={};read_directory(dir_start,sector_list,sectors,Paths,nmfs,files,FileIndex);build_full_paths(FileIndex,FullPathDir,FullPaths,Paths);var root_name=Paths.shift();Paths.root=root_name;var find_path=make_find_path(FullPaths,Paths,FileIndex,files,root_name);return{raw:{header:header,sectors:sectors},FileIndex:FileIndex,FullPaths:FullPaths,FullPathDir:FullPathDir,find:find_path}}function check_get_mver(blob){blob.chk(HEADER_SIGNATURE,"Header Signature: ");blob.chk(HEADER_CLSID,"CLSID: ");var mver=blob.read_shift(2,"u");return[blob.read_shift(2,"u"),mver]}function check_shifts(blob,mver){var shift=9;blob.chk("feff","Byte Order: ");switch(shift=blob.read_shift(2)){case 9:if(mver!==3)throw"MajorVersion/SectorShift Mismatch";break;case 12:if(mver!==4)throw"MajorVersion/SectorShift Mismatch";break;default:throw"Sector Shift: Expected 9 or 12 saw "+shift}blob.chk("0600","Mini Sector Shift: ");blob.chk("000000000000","Reserved: ")}function sectorify(file,ssz){var nsectors=Math.ceil(file.length/ssz)-1;var sectors=new Array(nsectors);for(var i=1;i>>2)-1;for(var i=0;i=0;){chkd[j]=true;buf[buf.length]=j;buf_chain.push(sectors[j]);var addr=fat_addrs[Math.floor(j*4/ssz)];jj=j*4&modulus;if(ssz<4+jj)throw"FAT boundary crossed: "+j+" 4 "+ssz;j=__readInt32LE(sectors[addr],jj)}return{nodes:buf,data:__toBuffer([buf_chain])}}function make_sector_list(sectors,dir_start,fat_addrs,ssz){var sl=sectors.length,sector_list=new Array(sl);var chkd=new Array(sl),buf,buf_chain;var modulus=ssz-1,i,j,k,jj;for(i=0;i=sl)k-=sl;if(chkd[k]===true)continue;buf_chain=[];for(j=k;j>=0;){chkd[j]=true;buf[buf.length]=j;buf_chain.push(sectors[j]);var addr=fat_addrs[Math.floor(j*4/ssz)];jj=j*4&modulus;if(ssz<4+jj)throw"FAT boundary crossed: "+j+" 4 "+ssz;j=__readInt32LE(sectors[addr],jj)}sector_list[k]={nodes:buf,data:__toBuffer([buf_chain])}}return sector_list}function read_directory(dir_start,sector_list,sectors,Paths,nmfs,files,FileIndex){var blob;var minifat_store=0,pl=Paths.length?2:0;var sector=sector_list[dir_start].data;var i=0,namelen=0,name,o,ctime,mtime;for(;i0&&minifat_store!==ENDOFCHAIN)sector_list[minifat_store].name="!StreamData"}else if(o.size>=4096){o.storage="fat";if(sector_list[o.start]===undefined)sector_list[o.start]=get_sector_list(sectors,o.start,sector_list.fat_addrs,sector_list.ssz);sector_list[o.start].name=o.name;o.content=sector_list[o.start].data.slice(0,o.size);prep_blob(o.content,0)}else{o.storage="minifat";if(minifat_store!==ENDOFCHAIN&&o.start!==ENDOFCHAIN){o.content=sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size);prep_blob(o.content,0)}}files[name]=o;FileIndex.push(o)}}function read_date(blob,offset){return new Date((__readUInt32LE(blob,offset+4)/1e7*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7-11644473600)*1e3)}var fs;function readFileSync(filename,options){if(fs===undefined)fs=require("fs");return parse(fs.readFileSync(filename),options)}function readSync(blob,options){switch(options!==undefined&&options.type!==undefined?options.type:"base64"){case"file":return readFileSync(blob,options);case"base64":return parse(s2a(Base64.decode(blob)),options);case"binary":return parse(s2a(blob),options)}return parse(blob)}var MSSZ=64;var ENDOFCHAIN=-2;var HEADER_SIGNATURE="d0cf11e0a1b11ae1";var HEADER_CLSID="00000000000000000000000000000000";var consts={MAXREGSECT:-6,DIFSECT:-4,FATSECT:-3,ENDOFCHAIN:ENDOFCHAIN,FREESECT:-1,HEADER_SIGNATURE:HEADER_SIGNATURE,HEADER_MINOR_VERSION:"3e00",MAXREGSID:-6,NOSTREAM:-1,HEADER_CLSID:HEADER_CLSID,EntryTypes:["unknown","storage","stream","lockbytes","property","root"]};exports.read=readSync;exports.parse=parse;exports.utils={ReadShift:ReadShift,CheckField:CheckField,prep_blob:prep_blob,bconcat:bconcat,consts:consts};return exports}();if(typeof require!=="undefined"&&typeof module!=="undefined"&&typeof DO_NOT_EXPORT_CFB==="undefined"){module.exports=CFB} diff --git a/dist/cfb.min.map b/dist/cfb.min.map index be92749..14c4c49 100644 --- a/dist/cfb.min.map +++ b/dist/cfb.min.map @@ -1 +1 @@ -{"version":3,"file":"dist/cfb.min.js","sources":["cfb.js"],"names":["Base64","map","decode","input","o","c1","c2","c3","e1","e2","e3","e4","replace","i","length","indexOf","charAt","String","fromCharCode","chr0","chr1","s2a","_s2a","s","split","x","charCodeAt","__toBuffer","___toBuffer","bufs","push","apply","__utf16le","___utf16le","b","e","ss","__readUInt16LE","join","__hexlify","___hexlify","l","slice","toString","bconcat","concat","Buffer","isBuffer","__readUInt8","idx","__readInt16LE","u","__readUInt32LE","__readInt32LE","ReadShift","size","t","oI","oS","type","this","CheckField","hexstr","fld","m","prep_blob","blob","pos","read_shift","chk","CFB","_CFB","exports","version","parse","file","mver","ssz","nmfs","ndfs","dir_start","minifat_start","difat_start","fat_addrs","check_get_mver","header","check_shifts","nds","q","j","sectors","sectorify","sleuth_fat","sector_list","make_sector_list","name","ENDOFCHAIN","files","Paths","FileIndex","FullPaths","FullPathDir","read_directory","build_full_paths","root_name","shift","root","find_path","make_find_path","raw","find","HEADER_SIGNATURE","HEADER_CLSID","nsectors","Math","ceil","Array","FI","FPD","FP","L","R","C","pl","dad","UCFullPaths","UCPaths","toUpperCase","path","k","UCPath","w","cnt","sector","sl","chkd","buf","buf_chain","modulus","jj","addr","floor","nodes","data","minifat_store","namelen","ctime","mtime","color","clsid","state","ct","read_date","mt","start","storage","undefined","content","MSSZ","offset","Date","pow","fs","readFileSync","filename","require","readSync","options","consts","MAXREGSECT","DIFSECT","FATSECT","FREESECT","HEADER_MINOR_VERSION","MAXREGSID","NOSTREAM","EntryTypes","read","utils","module","DO_NOT_EXPORT_CFB"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"dist/cfb.min.js","sources":["cfb.js"],"names":["Base64","map","decode","input","o","c1","c2","c3","e1","e2","e3","e4","replace","i","length","indexOf","charAt","String","fromCharCode","chr0","chr1","s2a","_s2a","s","split","x","charCodeAt","__toBuffer","___toBuffer","bufs","push","apply","__utf16le","___utf16le","b","e","ss","__readUInt16LE","join","__hexlify","___hexlify","l","slice","toString","bconcat","concat","Buffer","isBuffer","__readUInt8","idx","__readInt16LE","u","__readUInt32LE","__readInt32LE","ReadShift","size","t","oI","oS","type","this","CheckField","hexstr","fld","m","prep_blob","blob","pos","read_shift","chk","CFB","_CFB","exports","version","parse","file","mver","ssz","nmfs","ndfs","dir_start","minifat_start","difat_start","fat_addrs","mv","check_get_mver","header","check_shifts","nds","q","j","sectors","sectorify","sleuth_fat","sector_list","make_sector_list","name","ENDOFCHAIN","files","Paths","FileIndex","FullPaths","FullPathDir","read_directory","build_full_paths","root_name","shift","root","find_path","make_find_path","raw","find","HEADER_SIGNATURE","HEADER_CLSID","nsectors","Math","ceil","Array","FI","FPD","FP","L","R","C","pl","dad","UCFullPaths","UCPaths","toUpperCase","path","k","UCPath","w","cnt","sector","get_sector_list","start","chkd","sl","buf","buf_chain","modulus","jj","addr","floor","nodes","data","minifat_store","namelen","ctime","mtime","color","clsid","state","ct","read_date","mt","storage","undefined","content","MSSZ","offset","Date","pow","fs","readFileSync","filename","options","require","readSync","consts","MAXREGSECT","DIFSECT","FATSECT","FREESECT","HEADER_MINOR_VERSION","MAXREGSID","NOSTREAM","EntryTypes","read","utils","module","DO_NOT_EXPORT_CFB"],"mappings":";AAIA,GAAIA,QAAS,WACZ,GAAIC,KAAM,mEACV,QACCC,OAAQ,SAASC,OAChB,GAAIC,GAAI,EACR,IAAIC,IAAIC,GAAIC,EACZ,IAAIC,IAAIC,GAAIC,GAAIC,EAChBR,OAAQA,MAAMS,QAAQ,eAAgB,GACtC,KAAI,GAAIC,GAAI,EAAGA,EAAIV,MAAMW,QAAS,CACjCN,GAAKP,IAAIc,QAAQZ,MAAMa,OAAOH,KAC9BJ,IAAKR,IAAIc,QAAQZ,MAAMa,OAAOH,KAC9BR,IAAMG,IAAM,EAAMC,IAAM,CACxBL,IAAKa,OAAOC,aAAab,GAEzBK,IAAKT,IAAIc,QAAQZ,MAAMa,OAAOH,KAC9BP,KAAOG,GAAK,KAAO,EAAMC,IAAM,CAC/B,IAAIA,KAAO,GAAI,CAAEN,GAAKa,OAAOC,aAAaZ,IAE1CK,GAAKV,IAAIc,QAAQZ,MAAMa,OAAOH,KAC9BN,KAAOG,GAAK,IAAM,EAAKC,EACvB,IAAIA,KAAO,GAAI,CAAEP,GAAKa,OAAOC,aAAaX,KAE3C,MAAOH,OAKV,IAAIe,MAAO,UAAWC,KAAO,iBAE7B,IAAIC,KAAKC,IACTD,KAAMC,KAAO,QAASA,MAAKC,GAAK,MAAOA,GAAEC,MAAM,IAAIvB,IAAI,SAASwB,GAAI,MAAOA,GAAEC,WAAW,GAAK,MAC7F,IAAIC,YAAYC,WAChBD,YAAaC,YAAc,SAASC,MAAQ,GAAIJ,KAAQ,KAAI,GAAIZ,GAAI,EAAGA,EAAIgB,KAAK,GAAGf,SAAUD,EAAG,CAAEY,EAAEK,KAAKC,MAAMN,EAAGI,KAAK,GAAGhB,IAAO,MAAOY,GACxI,IAAIO,WAAWC,UACfD,WAAYC,WAAa,SAASC,EAAEX,EAAEY,GAAK,GAAIC,MAAO,KAAI,GAAIvB,GAAEU,EAAGV,EAAEsB,EAAGtB,GAAG,EAAGuB,GAAGN,KAAKb,OAAOC,aAAamB,eAAeH,EAAErB,IAAM,OAAOuB,IAAGE,KAAK,IAAI1B,QAAQO,KAAK,IAAIP,QAAQQ,KAAK,KAClL,IAAImB,WAAWC,UACfD,WAAYC,WAAa,SAASN,EAAEX,EAAEkB,GAAK,MAAOP,GAAEQ,MAAMnB,EAAGA,EAAEkB,GAAIxC,IAAI,SAASwB,GAAG,OAAQA,EAAE,GAAG,IAAI,IAAMA,EAAEkB,SAAS,MAAOL,KAAK,IACjI,IAAIM,SAAU,SAASf,MAAQ,SAAUgB,OAAOd,SAAUF,MAG1D,UAAUiB,UAAW,YAAa,CACjCd,UAAY,SAASE,EAAEX,EAAEY,GACxB,IAAIW,OAAOC,SAASb,GAAI,MAAOD,YAAWC,EAAEX,EAAEY,EAC9C,OAAOD,GAAES,SAAS,UAAUpB,EAAEY,GAAGvB,QAAQO,KAAK,IAAIP,QAAQQ,KAAK,KAEhEmB,WAAY,SAASL,EAAEX,EAAEkB,GAAK,MAAOK,QAAOC,SAASb,GAAKA,EAAES,SAAS,MAAMpB,EAAEA,EAAEkB,GAAKD,WAAWN,EAAEX,EAAEkB,GACnGd,YAAa,SAASE,MAAQ,MAAQA,MAAK,GAAGf,OAAS,GAAKgC,OAAOC,SAASlB,KAAK,GAAG,IAAOiB,OAAOD,OAAOhB,KAAK,IAAMD,YAAYC,MAChIR,KAAM,SAASE,GAAK,MAAOuB,QAAOvB,EAAG,UACrCqB,SAAU,SAASf,MAAQ,MAAOiB,QAAOC,SAASlB,KAAK,IAAMiB,OAAOD,OAAOhB,SAAWgB,OAAOd,SAAUF,OAIxG,GAAImB,aAAc,SAASd,EAAGe,KAAO,MAAOf,GAAEe,KAC9C,IAAIZ,gBAAiB,SAASH,EAAGe,KAAO,MAAOf,GAAEe,IAAI,IAAI,GAAG,GAAGf,EAAEe,KACjE,IAAIC,eAAgB,SAAShB,EAAGe,KAAO,GAAIE,GAAIjB,EAAEe,IAAI,IAAI,GAAG,GAAGf,EAAEe,IAAM,OAAQE,GAAI,MAAUA,GAAK,MAASA,EAAI,IAAM,EACrH,IAAIC,gBAAiB,SAASlB,EAAGe,KAAO,MAAOf,GAAEe,IAAI,IAAI,GAAG,KAAKf,EAAEe,IAAI,IAAI,KAAKf,EAAEe,IAAI,IAAI,GAAGf,EAAEe,KAC/F,IAAII,eAAgB,SAASnB,EAAGe,KAAO,OAAQf,EAAEe,IAAI,IAAI,KAAKf,EAAEe,IAAI,IAAI,KAAKf,EAAEe,IAAI,IAAI,GAAGf,EAAEe,KAE5F,SAASK,WAAUC,KAAMC,GACxB,GAAIC,IAAIC,GAAIC,KAAO,CACnB,QAAOJ,MACN,IAAK,GAAGE,GAAKT,YAAYY,KAAMA,KAAKnB,EAAI,MACxC,KAAK,GAAGgB,IAAMD,IAAM,IAAMnB,eAAiBa,eAAeU,KAAMA,KAAKnB,EAAI,MACzE,KAAK,GAAGgB,GAAKJ,cAAcO,KAAMA,KAAKnB,EAAI,MAC1C,KAAK,IAAIkB,KAAO,CAAGD,IAAKnB,UAAUqB,KAAMA,KAAKnB,EAAGc,MAEjDK,KAAKnB,GAAGc,IAAM,IAAGI,OAAS,EAAG,MAAOF,GAAI,OAAOC,IAGhD,QAASG,YAAWC,OAAQC,KAC3B,GAAIC,GAAIzB,UAAUqB,KAAKA,KAAKnB,EAAEqB,OAAOhD,QAAQ,EAC7C,IAAGkD,IAAMF,OAAQ,KAAMC,KAAM,YAAcD,OAAS,QAAUE,CAC9DJ,MAAKnB,GAAKqB,OAAOhD,QAAQ,EAG1B,QAASmD,WAAUC,KAAMC,KACxBD,KAAKzB,EAAI0B,GACTD,MAAKE,WAAad,SAClBY,MAAKG,IAAMR,WAIZ,GAAIS,KAAM,QAAUC,QACpB,GAAIC,WACJA,SAAQC,QAAU,QAClB,SAASC,OAAMC,MACf,GAAIC,MAAO,CACX,IAAIC,KAAM,GACV,IAAIC,MAAO,CACX,IAAIC,MAAO,CACX,IAAIC,WAAY,CAChB,IAAIC,eAAgB,CACpB,IAAIC,aAAc,CAElB,IAAIC,aAGJ,IAAIjB,MAAOS,KAAKjC,MAAM,EAAE,IACxBuB,WAAUC,KAAM,EAGhB,IAAIkB,IAAKC,eAAenB,KACxBU,MAAOQ,GAAG,EACV,QAAOR,MACN,IAAK,GAAGC,IAAM,GAAK,MAAO,KAAK,GAAGA,IAAM,IAAM,MAC9C,SAAS,KAAM,sCAAwCD,KAIxD,GAAGC,MAAQ,IAAK,CAAEX,KAAOS,KAAKjC,MAAM,EAAEmC,IAAMZ,WAAUC,KAAM,IAE5D,GAAIoB,QAASX,KAAKjC,MAAM,EAAEmC,IAE1BU,cAAarB,KAAMU,KAGnB,IAAIY,KAAMtB,KAAKE,WAAW,EAAG,IAC7B,IAAGQ,OAAS,GAAKY,MAAQ,EAAG,KAAM,uCAAyCA,GAI3EtB,MAAKzB,GAAK,CAGVuC,WAAYd,KAAKE,WAAW,EAAG,IAG/BF,MAAKzB,GAAK,CAGVyB,MAAKG,IAAI,WAAY,4BAGrBY,eAAgBf,KAAKE,WAAW,EAAG,IAGnCU,MAAOZ,KAAKE,WAAW,EAAG,IAG1Bc,aAAchB,KAAKE,WAAW,EAAG,IAGjCW,MAAOb,KAAKE,WAAW,EAAG,IAG1B,KAAI,GAAIqB,GAAGC,EAAI,EAAGA,EAAI,MAAOA,EAAG,CAC/BD,EAAIvB,KAAKE,WAAW,EAAG,IACvB,IAAGqB,EAAE,EAAG,KACRN,WAAUO,GAAKD,EAIhB,GAAIE,SAAUC,UAAUjB,KAAME,IAE9BgB,YAAWX,YAAaH,KAAMY,QAASd,IAAKM,UAG5C,IAAIW,aAAcC,iBAAiBJ,QAASX,UAAWG,UAAWN,IAElEiB,aAAYd,WAAWgB,KAAO,YAC9B,IAAGlB,KAAO,GAAKG,gBAAkBgB,WAAYH,YAAYb,eAAee,KAAO,UAC/EF,aAAYX,UAAU,IAAIa,KAAO,MACjCF,aAAYX,UAAYA,SACxBW,aAAYjB,IAAMA,GAGlB,IAAIqB,UAAYC,SAAYC,aAAgBC,aAAgBC,cAC5DC,gBAAevB,UAAWc,YAAaH,QAASQ,MAAOrB,KAAMoB,MAAOE,UAEpEI,kBAAiBJ,UAAWE,YAAaD,UAAWF,MAEpD,IAAIM,WAAYN,MAAMO,OACtBP,OAAMQ,KAAOF,SAGb,IAAIG,WAAYC,eAAeR,UAAWF,MAAOC,UAAWF,MAAOO,UAEnE,QACCK,KAAMxB,OAAQA,OAAQK,QAASA,SAC/BS,UAAWA,UACXC,UAAWA,UACXC,YAAaA,YACbS,KAAMH,WAKP,QAASvB,gBAAenB,MAEvBA,KAAKG,IAAI2C,iBAAkB,qBAG3B9C,MAAKG,IAAI4C,aAAc,UAGvB,IAAIrC,MAAOV,KAAKE,WAAW,EAAG,IAE9B,QAAQF,KAAKE,WAAW,EAAE,KAAMQ,MAEjC,QAASW,cAAarB,KAAMU,MAC3B,GAAI8B,OAAQ,CAGZxC,MAAKG,IAAI,OAAQ,eAGjB,QAAQqC,MAAQxC,KAAKE,WAAW,IAC/B,IAAK,GAAM,GAAGQ,OAAS,EAAG,KAAM,mCAAqC,MACrE,KAAK,IAAM,GAAGA,OAAS,EAAG,KAAM,mCAAqC,MACrE,SAAS,KAAM,sCAAwC8B,MAIxDxC,KAAKG,IAAI,OAAQ,sBAGjBH,MAAKG,IAAI,eAAgB,cAI1B,QAASuB,WAAUjB,KAAME,KACxB,GAAIqC,UAAWC,KAAKC,KAAKzC,KAAK7D,OAAO+D,KAAK,CAC1C,IAAIc,SAAU,GAAI0B,OAAMH,SACxB,KAAI,GAAIrG,GAAE,EAAGA,EAAIqG,WAAYrG,EAAG8E,QAAQ9E,EAAE,GAAK8D,KAAKjC,MAAM7B,EAAEgE,KAAKhE,EAAE,GAAGgE,IACtEc,SAAQuB,SAAS,GAAKvC,KAAKjC,MAAMwE,SAASrC,IAC1C,OAAOc,SAIR,QAASa,kBAAiBc,GAAIC,IAAKC,GAAIrB,OACtC,GAAItF,GAAI,EAAG4G,EAAI,EAAGC,EAAI,EAAGC,EAAI,EAAGjC,EAAI,EAAGkC,GAAKzB,MAAMrF,MAClD,IAAI+G,KAAM,GAAIR,OAAMO,IAAKnC,EAAI,GAAI4B,OAAMO,GAEvC,MAAM/G,EAAI+G,KAAM/G,EAAG,CAAEgH,IAAIhH,GAAG4E,EAAE5E,GAAGA,CAAG2G,IAAG3G,GAAGsF,MAAMtF,GAEhD,KAAM6E,EAAID,EAAE3E,SAAU4E,EAAG,CACxB7E,EAAI4E,EAAEC,EACN+B,GAAIH,GAAGzG,GAAG4G,CAAGC,GAAIJ,GAAGzG,GAAG6G,CAAGC,GAAIL,GAAGzG,GAAG8G,CACpC,IAAGE,IAAIhH,KAAOA,EAAG,CAChB,GAAG4G,KAAO,GAAkBI,IAAIJ,KAAOA,EAAGI,IAAIhH,GAAKgH,IAAIJ,EACvD,IAAGC,KAAO,GAAKG,IAAIH,KAAOA,EAAGG,IAAIhH,GAAKgH,IAAIH,GAE3C,GAAGC,KAAO,EAAgBE,IAAIF,GAAK9G,CACnC,IAAG4G,KAAO,EAAG,CAAEI,IAAIJ,GAAKI,IAAIhH,EAAI4E,GAAE3D,KAAK2F,GACvC,GAAGC,KAAO,EAAG,CAAEG,IAAIH,GAAKG,IAAIhH,EAAI4E,GAAE3D,KAAK4F,IAExC,IAAI7G,EAAE,EAAGA,IAAM+G,KAAM/G,EAAG,GAAGgH,IAAIhH,KAAOA,EAAG,CACxC,GAAG6G,KAAO,GAAkBG,IAAIH,KAAOA,EAAGG,IAAIhH,GAAKgH,IAAIH,OAClD,IAAGD,KAAO,GAAKI,IAAIJ,KAAOA,EAAGI,IAAIhH,GAAKgH,IAAIJ,GAGhD,IAAI5G,EAAE,EAAGA,EAAI+G,KAAM/G,EAAG,CACrB,GAAGyG,GAAGzG,GAAG8C,OAAS,EAAiB,QACnC+B,GAAImC,IAAIhH,EACR,IAAG6E,IAAM,EAAG8B,GAAG3G,GAAK2G,GAAG,GAAK,IAAMA,GAAG3G,OAChC,OAAM6E,IAAM,EAAG,CACnB8B,GAAG3G,GAAK2G,GAAG9B,GAAK,IAAM8B,GAAG3G,EACzB6E,GAAImC,IAAInC,GAETmC,IAAIhH,GAAK,EAGV2G,GAAG,IAAM,GACT,KAAI3G,EAAE,EAAGA,EAAI+G,KAAM/G,EAAG,CACrB,GAAGyG,GAAGzG,GAAG8C,OAAS,EAAgB6D,GAAG3G,IAAM,GAC3C0G,KAAIC,GAAG3G,IAAMyG,GAAGzG,IAKlB,QAASgG,gBAAeR,UAAWF,MAAOC,UAAWF,MAAOO,WAC3D,GAAIqB,aAAc,GAAIT,OAAMhB,UAAUvF,OACtC,IAAIiH,SAAU,GAAIV,OAAMlB,MAAMrF,QAASD,CACvC,KAAIA,EAAI,EAAGA,EAAIwF,UAAUvF,SAAUD,EAAGiH,YAAYjH,GAAKwF,UAAUxF,GAAGmH,cAAcpH,QAAQO,KAAK,IAAIP,QAAQQ,KAAK,IAChH,KAAIP,EAAI,EAAGA,EAAIsF,MAAMrF,SAAUD,EAAGkH,QAAQlH,GAAKsF,MAAMtF,GAAGmH,cAAcpH,QAAQO,KAAK,IAAIP,QAAQQ,KAAK,IACpG,OAAO,SAASwF,WAAUqB,MACzB,GAAIC,EACJ,IAAGD,KAAKvG,WAAW,KAAO,GAAc,CAAEwG,EAAE,IAAMD,MAAOxB,UAAYwB,SAChEC,GAAID,KAAKlH,QAAQ,QAAU,CAChC,IAAIoH,QAASF,KAAKD,cAAcpH,QAAQO,KAAK,IAAIP,QAAQQ,KAAK,IAC9D,IAAIgH,GAAIF,IAAM,KAAOJ,YAAY/G,QAAQoH,QAAUJ,QAAQhH,QAAQoH,OACnE,IAAGC,KAAO,EAAG,MAAO,KACpB,OAAOF,KAAM,KAAO9B,UAAUgC,GAAKlC,MAAMC,MAAMiC,KAMjD,QAASvC,YAAW5C,IAAKoF,IAAK1C,QAASd,IAAKM,WAC3C,GAAIM,EACJ,IAAGxC,MAAQgD,WAAY,CACtB,GAAGoC,MAAQ,EAAG,KAAM,wCACd,IAAGpF,OAAS,EAAgB,CAClC,GAAIqF,QAAS3C,QAAQ1C,KAAMe,GAAKa,MAAM,GAAG,CACzC,KAAI,GAAIhE,GAAI,EAAGA,EAAImD,IAAKnD,EAAG,CAC1B,IAAI4E,EAAIpC,cAAciF,OAAOzH,EAAE,MAAQoF,WAAY,KACnDd,WAAUrD,KAAK2D,GAEhBI,WAAWxC,cAAciF,OAAOzD,IAAI,GAAGwD,IAAM,EAAG1C,QAASd,IAAKM,YAKhE,QAASoD,iBAAgB5C,QAAS6C,MAAOrD,UAAWN,IAAK4D,MACxD,GAAIC,IAAK/C,QAAQ7E,MACjB,IAAI6H,KAAKC,SACT,KAAIH,KAAMA,KAAO,GAAIpB,OAAMqB,GAC3B,IAAIG,SAAUhE,IAAM,EAAGa,EAAGoD,EAC1BH,OACAC,aACA,KAAIlD,EAAE8C,MAAO9C,GAAG,GAAI,CACnB+C,KAAK/C,GAAK,IACViD,KAAIA,IAAI7H,QAAU4E,CAClBkD,WAAU9G,KAAK6D,QAAQD,GACvB,IAAIqD,MAAO5D,UAAUgC,KAAK6B,MAAMtD,EAAE,EAAEb,KACpCiE,IAAOpD,EAAE,EAAKmD,OACd,IAAGhE,IAAM,EAAIiE,GAAI,KAAM,yBAA2BpD,EAAI,MAAMb,GAC5Da,GAAIrC,cAAcsC,QAAQoD,MAAOD,IAElC,OAAQG,MAAON,IAAKO,KAAKvH,YAAYiH,aAItC,QAAS7C,kBAAiBJ,QAASX,UAAWG,UAAWN,KACxD,GAAI6D,IAAK/C,QAAQ7E,OAAQgF,YAAc,GAAIuB,OAAMqB,GACjD,IAAID,MAAO,GAAIpB,OAAMqB,IAAKC,IAAKC,SAC/B,IAAIC,SAAUhE,IAAM,EAAGhE,EAAG6E,EAAGwC,EAAGY,EAChC,KAAIjI,EAAE,EAAGA,EAAI6H,KAAM7H,EAAG,CACrB8H,MACAT,GAAKrH,EAAImE,SAAY,IAAGkD,GAAKQ,GAAIR,GAAGQ,EACpC,IAAGD,KAAKP,KAAO,KAAM,QACrBU,aACA,KAAIlD,EAAEwC,EAAGxC,GAAG,GAAI,CACf+C,KAAK/C,GAAK,IACViD,KAAIA,IAAI7H,QAAU4E,CAClBkD,WAAU9G,KAAK6D,QAAQD,GACvB,IAAIqD,MAAO5D,UAAUgC,KAAK6B,MAAMtD,EAAE,EAAEb,KACpCiE,IAAOpD,EAAE,EAAKmD,OACd,IAAGhE,IAAM,EAAIiE,GAAI,KAAM,yBAA2BpD,EAAI,MAAMb,GAC5Da,GAAIrC,cAAcsC,QAAQoD,MAAOD,IAElChD,YAAYoC,IAAMe,MAAON,IAAKO,KAAKvH,YAAYiH,aAEhD,MAAO9C,aAIR,QAASS,gBAAevB,UAAWc,YAAaH,QAASQ,MAAOrB,KAAMoB,MAAOE,WAC5E,GAAIlC,KACJ,IAAIiF,eAAgB,EAAGvB,GAAMzB,MAAMrF,OAAO,EAAE,CAC5C,IAAIwH,QAASxC,YAAYd,WAAWkE,IACpC,IAAIrI,GAAI,EAAGuI,QAAU,EAAGpD,KAAM5F,EAAGiJ,MAAOC,KACxC,MAAMzI,EAAIyH,OAAOxH,OAAQD,GAAI,IAAK,CACjCqD,KAAOoE,OAAO5F,MAAM7B,EAAGA,EAAE,IACzBoD,WAAUC,KAAM,GAChBkF,SAAUlF,KAAKE,WAAW,EAC1B,IAAGgF,UAAY,EAAG,QAClBpD,MAAOhE,UAAUkC,KAAK,EAAEkF,QAAQxB,GAChCzB,OAAMrE,KAAKkE,KACX5F,IACC4F,KAAOA,KACPrC,KAAOO,KAAKE,WAAW,GACvBmF,MAAOrF,KAAKE,WAAW,GACvBqD,EAAOvD,KAAKE,WAAW,EAAG,KAC1BsD,EAAOxD,KAAKE,WAAW,EAAG,KAC1BuD,EAAOzD,KAAKE,WAAW,EAAG,KAC1BoF,MAAOtF,KAAKE,WAAW,IACvBqF,MAAOvF,KAAKE,WAAW,EAAG,KAE3BiF,OAAQnF,KAAKE,WAAW,GAAKF,KAAKE,WAAW,GAAKF,KAAKE,WAAW,GAAKF,KAAKE,WAAW,EACvF,IAAGiF,QAAU,EAAG,CACfjJ,EAAEiJ,MAAQA,KAAOjJ,GAAEsJ,GAAKC,UAAUzF,KAAMA,KAAKzB,EAAE,GAEhD6G,MAAQpF,KAAKE,WAAW,GAAKF,KAAKE,WAAW,GAAKF,KAAKE,WAAW,GAAKF,KAAKE,WAAW,EACvF,IAAGkF,QAAU,EAAG,CACflJ,EAAEkJ,MAAQA,KAAOlJ,GAAEwJ,GAAKD,UAAUzF,KAAMA,KAAKzB,EAAE,GAEhDrC,EAAEoI,MAAQtE,KAAKE,WAAW,EAAG,IAC7BhE,GAAEmD,KAAOW,KAAKE,WAAW,EAAG,IAC5B,IAAGhE,EAAEuD,OAAS,EAAG,CAChBwF,cAAgB/I,EAAEoI,KAClB,IAAG1D,KAAO,GAAKqE,gBAAkBlD,WAAYH,YAAYqD,eAAenD,KAAO,kBAEzE,IAAG5F,EAAEmD,MAAQ,KAAkB,CACrCnD,EAAEyJ,QAAU,KACZ,IAAG/D,YAAY1F,EAAEoI,SAAWsB,UAAWhE,YAAY1F,EAAEoI,OAASD,gBAAgB5C,QAASvF,EAAEoI,MAAO1C,YAAYX,UAAWW,YAAYjB,IACnIiB,aAAY1F,EAAEoI,OAAOxC,KAAO5F,EAAE4F,IAC9B5F,GAAE2J,QAAUjE,YAAY1F,EAAEoI,OAAOU,KAAKxG,MAAM,EAAEtC,EAAEmD,KAChDU,WAAU7D,EAAE2J,QAAS,OACf,CACN3J,EAAEyJ,QAAU,SACZ,IAAGV,gBAAkBlD,YAAc7F,EAAEoI,QAAUvC,WAAY,CAC1D7F,EAAE2J,QAAUjE,YAAYqD,eAAeD,KAAKxG,MAAMtC,EAAEoI,MAAMwB,KAAK5J,EAAEoI,MAAMwB,KAAK5J,EAAEmD,KAC9EU,WAAU7D,EAAE2J,QAAS,IAGvB7D,MAAMF,MAAQ5F,CACdgG,WAAUtE,KAAK1B,IAIjB,QAASuJ,WAAUzF,KAAM+F,QACxB,MAAO,IAAIC,OAAU9G,eAAec,KAAK+F,OAAO,GAAG,IAAK9C,KAAKgD,IAAI,EAAE,IAAI/G,eAAec,KAAK+F,QAAQ,IAAQ,aAAa,KAGzH,GAAIG,GACJ,SAASC,cAAaC,SAAUC,SAC/B,GAAGH,KAAON,UAAWM,GAAKI,QAAQ,KAClC,OAAO9F,OAAM0F,GAAGC,aAAaC,UAAWC,SAGzC,QAASE,UAASvG,KAAMqG,SACvB,OAAOA,UAAYT,WAAaS,QAAQ5G,OAASmG,UAAYS,QAAQ5G,KAAO,UAC3E,IAAK,OAAQ,MAAO0G,cAAanG,KAAMqG,QACvC,KAAK,SAAU,MAAO7F,OAAMrD,IAAIrB,OAAOE,OAAOgE,OAAQqG,QACtD,KAAK,SAAU,MAAO7F,OAAMrD,IAAI6C,MAAOqG,SAExC,MAAO7F,OAAMR,MAId,GAAI8F,MAAO,EAGX,IAAI/D,aAAc,CAElB,IAAIe,kBAAmB,kBACvB,IAAIC,cAAe,kCACnB,IAAIyD,SAEHC,YAAa,EACbC,SAAU,EACVC,SAAU,EACV5E,WAAYA,WACZ6E,UAAW,EAEX9D,iBAAkBA,iBAClB+D,qBAAsB,OACtBC,WAAY,EACZC,UAAW,EACXhE,aAAcA,aAEdiE,YAAa,UAAU,UAAU,SAAS,YAAY,WAAW,QAGlE1G,SAAQ2G,KAAOV,QACfjG,SAAQE,MAAQA,KAChBF,SAAQ4G,OACP9H,UAAWA,UACXO,WAAYA,WACZI,UAAWA,UACXrB,QAASA,QACT8H,OAAQA,OAGT,OAAOlG,WAGP,UAAUgG,WAAY,mBAAsBa,UAAW,mBAAsBC,qBAAsB,YAAa,CAAED,OAAO7G,QAAUF"} \ No newline at end of file diff --git a/dist/xlscfb.js b/dist/xlscfb.js new file mode 100644 index 0000000..2bb2335 --- /dev/null +++ b/dist/xlscfb.js @@ -0,0 +1,383 @@ +var DO_NOT_EXPORT_CFB = true; +/* cfb.js (C) 2013-2014 SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +/*jshint eqnull:true */ + +/* [MS-CFB] v20130118 */ +var CFB = (function _CFB(){ +var exports = {}; +exports.version = '0.10.2'; +function parse(file) { +var mver = 3; // major version +var ssz = 512; // sector size +var nmfs = 0; // number of mini FAT sectors +var ndfs = 0; // number of DIFAT sectors +var dir_start = 0; // first directory sector location +var minifat_start = 0; // first mini FAT sector location +var difat_start = 0; // first mini FAT sector location + +var fat_addrs = []; // locations of FAT sectors + +/* [MS-CFB] 2.2 Compound File Header */ +var blob = file.slice(0,512); +prep_blob(blob, 0); + +/* major version */ +var mv = check_get_mver(blob); +mver = mv[0]; +switch(mver) { + case 3: ssz = 512; break; case 4: ssz = 4096; break; + default: throw "Major Version: Expected 3 or 4 saw " + mver; +} + +/* reprocess header */ +if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); } +/* Save header for final object */ +var header = file.slice(0,ssz); + +check_shifts(blob, mver); + +// Number of Directory Sectors +var nds = blob.read_shift(4, 'i'); +if(mver === 3 && nds !== 0) throw '# Directory Sectors: Expected 0 saw ' + nds; + +// Number of FAT Sectors +//var nfs = blob.read_shift(4, 'i'); +blob.l += 4; + +// First Directory Sector Location +dir_start = blob.read_shift(4, 'i'); + +// Transaction Signature +blob.l += 4; + +// Mini Stream Cutoff Size +blob.chk('00100000', 'Mini Stream Cutoff Size: '); + +// First Mini FAT Sector Location +minifat_start = blob.read_shift(4, 'i'); + +// Number of Mini FAT Sectors +nmfs = blob.read_shift(4, 'i'); + +// First DIFAT sector location +difat_start = blob.read_shift(4, 'i'); + +// Number of DIFAT Sectors +ndfs = blob.read_shift(4, 'i'); + +// Grab FAT Sector Locations +for(var q, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */ + q = blob.read_shift(4, 'i'); + if(q<0) break; + fat_addrs[j] = q; +} + +/** Break the file up into sectors */ +var sectors = sectorify(file, ssz); + +sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs); + +/** Chains */ +var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz); + +sector_list[dir_start].name = "!Directory"; +if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT"; +sector_list[fat_addrs[0]].name = "!FAT"; +sector_list.fat_addrs = fat_addrs; +sector_list.ssz = ssz; + +/* [MS-CFB] 2.6.1 Compound File Directory Entry */ +var files = {}, Paths = [], FileIndex = [], FullPaths = [], FullPathDir = {}; +read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex); + +build_full_paths(FileIndex, FullPathDir, FullPaths, Paths); + +var root_name = Paths.shift(); +Paths.root = root_name; + +/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ +var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name); + +return { + raw: {header: header, sectors: sectors}, + FileIndex: FileIndex, + FullPaths: FullPaths, + FullPathDir: FullPathDir, + find: find_path +}; +} // parse + +/* [MS-CFB] 2.2 Compound File Header -- read up to major version */ +function check_get_mver(blob) { + // header signature 8 + blob.chk(HEADER_SIGNATURE, 'Header Signature: '); + + // clsid 16 + blob.chk(HEADER_CLSID, 'CLSID: '); + + // minor version 2 + var mver = blob.read_shift(2, 'u'); + + return [blob.read_shift(2,'u'), mver]; +} +function check_shifts(blob, mver) { + var shift = 0x09; + + // Byte Order + blob.chk('feff', 'Byte Order: '); + + // Sector Shift + switch((shift = blob.read_shift(2))) { + case 0x09: if(mver !== 3) throw 'MajorVersion/SectorShift Mismatch'; break; + case 0x0c: if(mver !== 4) throw 'MajorVersion/SectorShift Mismatch'; break; + default: throw 'Sector Shift: Expected 9 or 12 saw ' + shift; + } + + // Mini Sector Shift + blob.chk('0600', 'Mini Sector Shift: '); + + // Reserved + blob.chk('000000000000', 'Reserved: '); +} + +/** Break the file up into sectors */ +function sectorify(file, ssz) { + var nsectors = Math.ceil(file.length/ssz)-1; + var sectors = new Array(nsectors); + for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz); + sectors[nsectors-1] = file.slice(nsectors*ssz); + return sectors; +} + +/* [MS-CFB] 2.6.4 Red-Black Tree */ +function build_full_paths(FI, FPD, FP, Paths) { + var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length; + var dad = new Array(pl), q = new Array(pl); + + for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; } + + for(; j < q.length; ++j) { + i = q[j]; + L = FI[i].L; R = FI[i].R; C = FI[i].C; + if(dad[i] === i) { + if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L]; + if(R !== -1 && dad[R] !== R) dad[i] = dad[R]; + } + if(C !== -1 /*NOSTREAM*/) dad[C] = i; + if(L !== -1) { dad[L] = dad[i]; q.push(L); } + if(R !== -1) { dad[R] = dad[i]; q.push(R); } + } + for(i=1; i !== pl; ++i) if(dad[i] === i) { + if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; + else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; + } + + for(i=1; i < pl; ++i) { + if(FI[i].type === 0 /* unknown */) continue; + j = dad[i]; + if(j === 0) FP[i] = FP[0] + "/" + FP[i]; + else while(j !== 0) { + FP[i] = FP[j] + "/" + FP[i]; + j = dad[j]; + } + dad[i] = 0; + } + + FP[0] += "/"; + for(i=1; i < pl; ++i) { + if(FI[i].type !== 2 /* stream */) FP[i] += "/"; + FPD[FP[i]] = FI[i]; + } +} + +/* [MS-CFB] 2.6.4 */ +function make_find_path(FullPaths, Paths, FileIndex, files, root_name) { + var UCFullPaths = new Array(FullPaths.length); + var UCPaths = new Array(Paths.length), i; + for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); + for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); + return function find_path(path) { + var k; + if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; } + else k = path.indexOf("/") !== -1; + var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!'); + var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); + if(w === -1) return null; + return k === true ? FileIndex[w] : files[Paths[w]]; + }; +} + +/** Chase down the rest of the DIFAT chain to build a comprehensive list + DIFAT chains by storing the next sector number as the last 32 bytes */ +function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) { + var q; + if(idx === ENDOFCHAIN) { + if(cnt !== 0) throw "DIFAT chain shorter than expected"; + } else if(idx !== -1 /*FREESECT*/) { + var sector = sectors[idx], m = (ssz>>>2)-1; + for(var i = 0; i < m; ++i) { + if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break; + fat_addrs.push(q); + } + sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs); + } +} + +/** Follow the linked list of sectors for a given starting point */ +function get_sector_list(sectors, start, fat_addrs, ssz, chkd) { + var sl = sectors.length; + var buf, buf_chain; + if(!chkd) chkd = new Array(sl); + var modulus = ssz - 1, j, jj; + buf = []; + buf_chain = []; + for(j=start; j>=0;) { + chkd[j] = true; + buf[buf.length] = j; + buf_chain.push(sectors[j]); + var addr = fat_addrs[Math.floor(j*4/ssz)]; + jj = ((j*4) & modulus); + if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz; + j = __readInt32LE(sectors[addr], jj); + } + return {nodes: buf, data:__toBuffer([buf_chain])}; +} + +/** Chase down the sector linked lists */ +function make_sector_list(sectors, dir_start, fat_addrs, ssz) { + var sl = sectors.length, sector_list = new Array(sl); + var chkd = new Array(sl), buf, buf_chain; + var modulus = ssz - 1, i, j, k, jj; + for(i=0; i < sl; ++i) { + buf = []; + k = (i + dir_start); if(k >= sl) k-=sl; + if(chkd[k] === true) continue; + buf_chain = []; + for(j=k; j>=0;) { + chkd[j] = true; + buf[buf.length] = j; + buf_chain.push(sectors[j]); + var addr = fat_addrs[Math.floor(j*4/ssz)]; + jj = ((j*4) & modulus); + if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz; + j = __readInt32LE(sectors[addr], jj); + } + sector_list[k] = {nodes: buf, data:__toBuffer([buf_chain])}; + } + return sector_list; +} + +/* [MS-CFB] 2.6.1 Compound File Directory Entry */ +function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex) { + var blob; + var minifat_store = 0, pl = (Paths.length?2:0); + var sector = sector_list[dir_start].data; + var i = 0, namelen = 0, name, o, ctime, mtime; + for(; i < sector.length; i+= 128) { + blob = sector.slice(i, i+128); + prep_blob(blob, 64); + namelen = blob.read_shift(2); + if(namelen === 0) continue; + name = __utf16le(blob,0,namelen-pl); + Paths.push(name); + o = { + name: name, + type: blob.read_shift(1), + color: blob.read_shift(1), + L: blob.read_shift(4, 'i'), + R: blob.read_shift(4, 'i'), + C: blob.read_shift(4, 'i'), + clsid: blob.read_shift(16), + state: blob.read_shift(4, 'i') + }; + ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); + if(ctime !== 0) { + o.ctime = ctime; o.ct = read_date(blob, blob.l-8); + } + mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); + if(mtime !== 0) { + o.mtime = mtime; o.mt = read_date(blob, blob.l-8); + } + o.start = blob.read_shift(4, 'i'); + o.size = blob.read_shift(4, 'i'); + if(o.type === 5) { /* root */ + minifat_store = o.start; + if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData"; + /*minifat_size = o.size;*/ + } else if(o.size >= 4096 /* MSCSZ */) { + o.storage = 'fat'; + if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); + sector_list[o.start].name = o.name; + o.content = sector_list[o.start].data.slice(0,o.size); + prep_blob(o.content, 0); + } else { + o.storage = 'minifat'; + if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) { + o.content = sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size); + prep_blob(o.content, 0); + } + } + files[name] = o; + FileIndex.push(o); + } +} + +function read_date(blob, offset) { + return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000); +} + +var fs; +function readFileSync(filename, options) { + if(fs === undefined) fs = require('fs'); + return parse(fs.readFileSync(filename), options); +} + +function readSync(blob, options) { + switch(options !== undefined && options.type !== undefined ? options.type : "base64") { + case "file": return readFileSync(blob, options); + case "base64": return parse(s2a(Base64.decode(blob)), options); + case "binary": return parse(s2a(blob), options); + } + return parse(blob); +} + +/** CFB Constants */ +var MSSZ = 64; /* Mini Sector Size = 1<<6 */ +//var MSCSZ = 4096; /* Mini Stream Cutoff Size */ +/* 2.1 Compound File Sector Numbers and Types */ +var ENDOFCHAIN = -2; +/* 2.2 Compound File Header */ +var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1'; +var HEADER_CLSID = '00000000000000000000000000000000'; +var consts = { + /* 2.1 Compund File Sector Numbers and Types */ + MAXREGSECT: -6, + DIFSECT: -4, + FATSECT: -3, + ENDOFCHAIN: ENDOFCHAIN, + FREESECT: -1, + /* 2.2 Compound File Header */ + HEADER_SIGNATURE: HEADER_SIGNATURE, + HEADER_MINOR_VERSION: '3e00', + MAXREGSID: -6, + NOSTREAM: -1, + HEADER_CLSID: HEADER_CLSID, + /* 2.6.1 Compound File Directory Entry */ + EntryTypes: ['unknown','storage','stream','lockbytes','property','root'] +}; + +exports.read = readSync; +exports.parse = parse; +exports.utils = { + ReadShift: ReadShift, + CheckField: CheckField, + prep_blob: prep_blob, + bconcat: bconcat, + consts: consts +}; + +return exports; +})(); + +if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; } diff --git a/misc/strip_sourcemap.sh b/misc/strip_sourcemap.sh new file mode 100755 index 0000000..f6d7ba8 --- /dev/null +++ b/misc/strip_sourcemap.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# strip_sourcemap.sh -- strip sourcemaps from a JS file (missing from uglifyjs) +# Copyright (C) 2014 SheetJS + +if [ $# -gt 0 ]; then + if [ -e "$1" ]; then + sed -i .sheetjs '/sourceMappingURL/d' "$1" + fi +else + cat - | sed '/sourceMappingURL/d' +fi diff --git a/misc/suppress_export.js b/misc/suppress_export.js new file mode 100644 index 0000000..6366ccf --- /dev/null +++ b/misc/suppress_export.js @@ -0,0 +1 @@ +var DO_NOT_EXPORT_CFB = true; diff --git a/package.json b/package.json index a1221c2..dd3717b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cfb", - "version": "0.10.1", + "version": "0.10.2", "author": "sheetjs", "description": "Compound File Binary File Format extractor", "keywords": [ "cfb", "compression", "office" ], diff --git a/test.js b/test.js index ba104f7..aacb80e 100644 --- a/test.js +++ b/test.js @@ -3,21 +3,35 @@ var CFB; var fs = require('fs'); describe('source', function() { it('should load', function() { CFB = require('./'); }); }); -var ffunc = function(x){return x.substr(-4)==".xls" && fails.indexOf(x) === -1;}; +var ex = [".xls",".doc",".ppt"]; +if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;}); +if(process.env.FMTS === "full") process.env.FMTS = ex.join(":"); +if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;}); + +var ffunc = function(x){return (ex.indexOf(x.substr(-4))>=0 || ex.indexOf(x.substr(-3))>=0) && fails.indexOf(x) === -1;}; var fails = fs.existsSync('./fails.lst') ? fs.readFileSync('./fails.lst', 'utf-8').split("\n") : []; var files = fs.readdirSync('test_files').filter(ffunc); var f2011 = fs.readdirSync('test_files/2011').filter(ffunc); var f2013 = fs.readdirSync('test_files/2013').filter(ffunc); +var fpres = fs.readdirSync('test_files_pres').filter(ffunc); var dir = "./test_files/"; function parsetest(x, cfb) { describe(x + ' should have basic parts', function() { it('should find relative path', function() { - if(!cfb.find('Workbook') && !cfb.find('Book')) throw new Error("Cannot find workbook for " + x); + switch(x.substr(-4)) { + case '.xls': if(!cfb.find('Workbook') && !cfb.find('Book')) throw new Error("Cannot find workbook for " + x); break; + case '.ppt': if(!cfb.find('PowerPoint Document')) throw new Error("Cannot find presentation for " + x); break; + case '.doc': if(!cfb.find('WordDocument') && !cfb.find('Word Document')) throw new Error("Cannot find doc for " + x); break; + } }); it('should find absolute path', function() { - if(!cfb.find('/Workbook') && !cfb.find('/Book')) throw new Error("Cannot find workbook for " + x); + switch(x.substr(-4)) { + case '.xls': if(!cfb.find('/Workbook') && !cfb.find('/Book')) throw new Error("Cannot find workbook for " + x); break; + case '.ppt': if(!cfb.find('/PowerPoint Document')) throw new Error("Cannot find presentation for " + x); break; + case '.doc': if(!cfb.find('/WordDocument') && !cfb.find('/Word Document')) throw new Error("Cannot find doc for " + x); break; + } }); }); } @@ -29,6 +43,12 @@ describe('should parse test files', function() { parsetest(x, cfb); }); }); + fpres.forEach(function(x) { + it('should parse ' + x, function() { + var cfb = CFB.read('./test_files_pres/' + x, {type: "file"}); + parsetest(x, cfb); + }); + }); f2011.forEach(function(x) { it('should parse ' + x, function() { var cfb = CFB.read('./test_files/2011/' + x, {type: "file"}); diff --git a/xlscfb.js b/xlscfb.js new file mode 100644 index 0000000..2bb2335 --- /dev/null +++ b/xlscfb.js @@ -0,0 +1,383 @@ +var DO_NOT_EXPORT_CFB = true; +/* cfb.js (C) 2013-2014 SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +/*jshint eqnull:true */ + +/* [MS-CFB] v20130118 */ +var CFB = (function _CFB(){ +var exports = {}; +exports.version = '0.10.2'; +function parse(file) { +var mver = 3; // major version +var ssz = 512; // sector size +var nmfs = 0; // number of mini FAT sectors +var ndfs = 0; // number of DIFAT sectors +var dir_start = 0; // first directory sector location +var minifat_start = 0; // first mini FAT sector location +var difat_start = 0; // first mini FAT sector location + +var fat_addrs = []; // locations of FAT sectors + +/* [MS-CFB] 2.2 Compound File Header */ +var blob = file.slice(0,512); +prep_blob(blob, 0); + +/* major version */ +var mv = check_get_mver(blob); +mver = mv[0]; +switch(mver) { + case 3: ssz = 512; break; case 4: ssz = 4096; break; + default: throw "Major Version: Expected 3 or 4 saw " + mver; +} + +/* reprocess header */ +if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); } +/* Save header for final object */ +var header = file.slice(0,ssz); + +check_shifts(blob, mver); + +// Number of Directory Sectors +var nds = blob.read_shift(4, 'i'); +if(mver === 3 && nds !== 0) throw '# Directory Sectors: Expected 0 saw ' + nds; + +// Number of FAT Sectors +//var nfs = blob.read_shift(4, 'i'); +blob.l += 4; + +// First Directory Sector Location +dir_start = blob.read_shift(4, 'i'); + +// Transaction Signature +blob.l += 4; + +// Mini Stream Cutoff Size +blob.chk('00100000', 'Mini Stream Cutoff Size: '); + +// First Mini FAT Sector Location +minifat_start = blob.read_shift(4, 'i'); + +// Number of Mini FAT Sectors +nmfs = blob.read_shift(4, 'i'); + +// First DIFAT sector location +difat_start = blob.read_shift(4, 'i'); + +// Number of DIFAT Sectors +ndfs = blob.read_shift(4, 'i'); + +// Grab FAT Sector Locations +for(var q, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */ + q = blob.read_shift(4, 'i'); + if(q<0) break; + fat_addrs[j] = q; +} + +/** Break the file up into sectors */ +var sectors = sectorify(file, ssz); + +sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs); + +/** Chains */ +var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz); + +sector_list[dir_start].name = "!Directory"; +if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT"; +sector_list[fat_addrs[0]].name = "!FAT"; +sector_list.fat_addrs = fat_addrs; +sector_list.ssz = ssz; + +/* [MS-CFB] 2.6.1 Compound File Directory Entry */ +var files = {}, Paths = [], FileIndex = [], FullPaths = [], FullPathDir = {}; +read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex); + +build_full_paths(FileIndex, FullPathDir, FullPaths, Paths); + +var root_name = Paths.shift(); +Paths.root = root_name; + +/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ +var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name); + +return { + raw: {header: header, sectors: sectors}, + FileIndex: FileIndex, + FullPaths: FullPaths, + FullPathDir: FullPathDir, + find: find_path +}; +} // parse + +/* [MS-CFB] 2.2 Compound File Header -- read up to major version */ +function check_get_mver(blob) { + // header signature 8 + blob.chk(HEADER_SIGNATURE, 'Header Signature: '); + + // clsid 16 + blob.chk(HEADER_CLSID, 'CLSID: '); + + // minor version 2 + var mver = blob.read_shift(2, 'u'); + + return [blob.read_shift(2,'u'), mver]; +} +function check_shifts(blob, mver) { + var shift = 0x09; + + // Byte Order + blob.chk('feff', 'Byte Order: '); + + // Sector Shift + switch((shift = blob.read_shift(2))) { + case 0x09: if(mver !== 3) throw 'MajorVersion/SectorShift Mismatch'; break; + case 0x0c: if(mver !== 4) throw 'MajorVersion/SectorShift Mismatch'; break; + default: throw 'Sector Shift: Expected 9 or 12 saw ' + shift; + } + + // Mini Sector Shift + blob.chk('0600', 'Mini Sector Shift: '); + + // Reserved + blob.chk('000000000000', 'Reserved: '); +} + +/** Break the file up into sectors */ +function sectorify(file, ssz) { + var nsectors = Math.ceil(file.length/ssz)-1; + var sectors = new Array(nsectors); + for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz); + sectors[nsectors-1] = file.slice(nsectors*ssz); + return sectors; +} + +/* [MS-CFB] 2.6.4 Red-Black Tree */ +function build_full_paths(FI, FPD, FP, Paths) { + var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length; + var dad = new Array(pl), q = new Array(pl); + + for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; } + + for(; j < q.length; ++j) { + i = q[j]; + L = FI[i].L; R = FI[i].R; C = FI[i].C; + if(dad[i] === i) { + if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L]; + if(R !== -1 && dad[R] !== R) dad[i] = dad[R]; + } + if(C !== -1 /*NOSTREAM*/) dad[C] = i; + if(L !== -1) { dad[L] = dad[i]; q.push(L); } + if(R !== -1) { dad[R] = dad[i]; q.push(R); } + } + for(i=1; i !== pl; ++i) if(dad[i] === i) { + if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; + else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; + } + + for(i=1; i < pl; ++i) { + if(FI[i].type === 0 /* unknown */) continue; + j = dad[i]; + if(j === 0) FP[i] = FP[0] + "/" + FP[i]; + else while(j !== 0) { + FP[i] = FP[j] + "/" + FP[i]; + j = dad[j]; + } + dad[i] = 0; + } + + FP[0] += "/"; + for(i=1; i < pl; ++i) { + if(FI[i].type !== 2 /* stream */) FP[i] += "/"; + FPD[FP[i]] = FI[i]; + } +} + +/* [MS-CFB] 2.6.4 */ +function make_find_path(FullPaths, Paths, FileIndex, files, root_name) { + var UCFullPaths = new Array(FullPaths.length); + var UCPaths = new Array(Paths.length), i; + for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); + for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); + return function find_path(path) { + var k; + if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; } + else k = path.indexOf("/") !== -1; + var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!'); + var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); + if(w === -1) return null; + return k === true ? FileIndex[w] : files[Paths[w]]; + }; +} + +/** Chase down the rest of the DIFAT chain to build a comprehensive list + DIFAT chains by storing the next sector number as the last 32 bytes */ +function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) { + var q; + if(idx === ENDOFCHAIN) { + if(cnt !== 0) throw "DIFAT chain shorter than expected"; + } else if(idx !== -1 /*FREESECT*/) { + var sector = sectors[idx], m = (ssz>>>2)-1; + for(var i = 0; i < m; ++i) { + if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break; + fat_addrs.push(q); + } + sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs); + } +} + +/** Follow the linked list of sectors for a given starting point */ +function get_sector_list(sectors, start, fat_addrs, ssz, chkd) { + var sl = sectors.length; + var buf, buf_chain; + if(!chkd) chkd = new Array(sl); + var modulus = ssz - 1, j, jj; + buf = []; + buf_chain = []; + for(j=start; j>=0;) { + chkd[j] = true; + buf[buf.length] = j; + buf_chain.push(sectors[j]); + var addr = fat_addrs[Math.floor(j*4/ssz)]; + jj = ((j*4) & modulus); + if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz; + j = __readInt32LE(sectors[addr], jj); + } + return {nodes: buf, data:__toBuffer([buf_chain])}; +} + +/** Chase down the sector linked lists */ +function make_sector_list(sectors, dir_start, fat_addrs, ssz) { + var sl = sectors.length, sector_list = new Array(sl); + var chkd = new Array(sl), buf, buf_chain; + var modulus = ssz - 1, i, j, k, jj; + for(i=0; i < sl; ++i) { + buf = []; + k = (i + dir_start); if(k >= sl) k-=sl; + if(chkd[k] === true) continue; + buf_chain = []; + for(j=k; j>=0;) { + chkd[j] = true; + buf[buf.length] = j; + buf_chain.push(sectors[j]); + var addr = fat_addrs[Math.floor(j*4/ssz)]; + jj = ((j*4) & modulus); + if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz; + j = __readInt32LE(sectors[addr], jj); + } + sector_list[k] = {nodes: buf, data:__toBuffer([buf_chain])}; + } + return sector_list; +} + +/* [MS-CFB] 2.6.1 Compound File Directory Entry */ +function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex) { + var blob; + var minifat_store = 0, pl = (Paths.length?2:0); + var sector = sector_list[dir_start].data; + var i = 0, namelen = 0, name, o, ctime, mtime; + for(; i < sector.length; i+= 128) { + blob = sector.slice(i, i+128); + prep_blob(blob, 64); + namelen = blob.read_shift(2); + if(namelen === 0) continue; + name = __utf16le(blob,0,namelen-pl); + Paths.push(name); + o = { + name: name, + type: blob.read_shift(1), + color: blob.read_shift(1), + L: blob.read_shift(4, 'i'), + R: blob.read_shift(4, 'i'), + C: blob.read_shift(4, 'i'), + clsid: blob.read_shift(16), + state: blob.read_shift(4, 'i') + }; + ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); + if(ctime !== 0) { + o.ctime = ctime; o.ct = read_date(blob, blob.l-8); + } + mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); + if(mtime !== 0) { + o.mtime = mtime; o.mt = read_date(blob, blob.l-8); + } + o.start = blob.read_shift(4, 'i'); + o.size = blob.read_shift(4, 'i'); + if(o.type === 5) { /* root */ + minifat_store = o.start; + if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData"; + /*minifat_size = o.size;*/ + } else if(o.size >= 4096 /* MSCSZ */) { + o.storage = 'fat'; + if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); + sector_list[o.start].name = o.name; + o.content = sector_list[o.start].data.slice(0,o.size); + prep_blob(o.content, 0); + } else { + o.storage = 'minifat'; + if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) { + o.content = sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size); + prep_blob(o.content, 0); + } + } + files[name] = o; + FileIndex.push(o); + } +} + +function read_date(blob, offset) { + return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000); +} + +var fs; +function readFileSync(filename, options) { + if(fs === undefined) fs = require('fs'); + return parse(fs.readFileSync(filename), options); +} + +function readSync(blob, options) { + switch(options !== undefined && options.type !== undefined ? options.type : "base64") { + case "file": return readFileSync(blob, options); + case "base64": return parse(s2a(Base64.decode(blob)), options); + case "binary": return parse(s2a(blob), options); + } + return parse(blob); +} + +/** CFB Constants */ +var MSSZ = 64; /* Mini Sector Size = 1<<6 */ +//var MSCSZ = 4096; /* Mini Stream Cutoff Size */ +/* 2.1 Compound File Sector Numbers and Types */ +var ENDOFCHAIN = -2; +/* 2.2 Compound File Header */ +var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1'; +var HEADER_CLSID = '00000000000000000000000000000000'; +var consts = { + /* 2.1 Compund File Sector Numbers and Types */ + MAXREGSECT: -6, + DIFSECT: -4, + FATSECT: -3, + ENDOFCHAIN: ENDOFCHAIN, + FREESECT: -1, + /* 2.2 Compound File Header */ + HEADER_SIGNATURE: HEADER_SIGNATURE, + HEADER_MINOR_VERSION: '3e00', + MAXREGSID: -6, + NOSTREAM: -1, + HEADER_CLSID: HEADER_CLSID, + /* 2.6.1 Compound File Directory Entry */ + EntryTypes: ['unknown','storage','stream','lockbytes','property','root'] +}; + +exports.read = readSync; +exports.parse = parse; +exports.utils = { + ReadShift: ReadShift, + CheckField: CheckField, + prep_blob: prep_blob, + bconcat: bconcat, + consts: consts +}; + +return exports; +})(); + +if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }