js-cfb/bin/cfb.njs

167 lines
5.7 KiB
Plaintext
Raw Normal View History

2013-09-05 18:55:36 +00:00
#!/usr/bin/env node
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* eslint-env node */
/* vim: set ts=2 ft=javascript: */
var n = "cfb";
var X = require('../');
2017-09-14 21:14:22 +00:00
var fs = require('fs');
var program = require('commander');
var PRINTJ = require("printj");
var sprintf = PRINTJ.sprintf;
program
.version(X.version)
.usage('[options] <file> [subfiles...]')
.option('-l, --list-files', 'list files')
2017-09-14 21:14:22 +00:00
.option('-r, --repair', 'attempt to repair and garbage-collect archive')
.option('-c, --create', 'create file')
.option('-a, --append', 'add files to CFB (overwrite existing data)')
.option('-d, --delete', 'delete files from CFB')
.option('-O, --to-stdout', 'extract raw contents to stdout')
.option('-z, --dump', 'dump internal representation but do not extract')
.option('-q, --quiet', 'process but do not report')
2018-09-04 07:14:20 +00:00
.option('--here', 'skip the CFB root name when extracting')
.option('--osx', 'use OSX-style unzip listing')
.option('--zlib', 'use native zlib')
.option('--local', 'print times in local timezone')
.option('--dev', 'development mode')
.option('--read', 'read but do not print out contents');
program.parse(process.argv);
2013-09-05 18:55:36 +00:00
2018-09-04 07:14:20 +00:00
if(program.zlib) X.utils.use_zlib(require('zlib'));
var exit = process.exit;
var die = function(errno/*:number*/, msg/*:string*/) { console.error(n + ": " + msg); exit(errno); };
var logit = function(cmd/*:string*/, f/*:string*/) { console.error(sprintf("%-6s %s", cmd, f)); };
if(program.args.length === 0) die(1, "must specify a filename");
if(program.create) {
logit("create", program.args[0]);
var newcfb = X.utils.cfb_new();
X.writeFile(newcfb, program.args[0]);
2013-09-05 18:55:36 +00:00
}
if(!fs.existsSync(program.args[0])) die(1, "must specify a filename");
var opts = ({type:'file'}/*:any*/);
if(program.dev) opts.WTF = true;
var cfb = X.read(program.args[0], opts);
if(program.quiet) exit(0);
if(program.dump) {
console.log("Full Paths:");
console.log(cfb.FullPaths.map(function(x/*:string*/) { return " " + x; }).join("\n"));
console.log("File Index:");
console.log(cfb.FileIndex);
exit(0);
2017-09-14 21:14:22 +00:00
}
if(program.repair) { X.writeFile(cfb, program.args[0]); exit(0); }
2018-09-04 07:14:20 +00:00
var rlen = cfb.FullPaths[0].length;
function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/g, function($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
2018-09-04 07:14:20 +00:00
var format_date = function(date/*:Date*/, osx/*:?any*/)/*:string*/ {
var datefmt = osx ? "%02u-%02u-%04u %02u:%02u": "%02u-%02u-%02u %02u:%02u";
var MM = program.local ? date.getMonth() + 1 : date.getUTCMonth() + 1;
var DD = program.local ? date.getDate() : date.getUTCDate();
var YY = (program.local ? date.getFullYear() : date.getUTCFullYear())%(osx ? 10000 : 100);
var hh = program.local ? date.getHours() : date.getUTCHours();
var mm = program.local ? date.getMinutes() : date.getUTCMinutes();
return sprintf(datefmt, MM, DD, YY, hh, mm);
};
if(program.listFiles) {
2018-09-04 07:14:20 +00:00
var basetime = new Date(Date.UTC(1980,0,1));
2017-09-14 21:14:22 +00:00
var cnt = 0, rootsize = 0, filesize = 0;
2018-09-04 07:14:20 +00:00
var fmtstr = "%9lu %s %s";
if(program.osx) {
console.log("Archive: " + program.args[0]);
console.log(" Length Date Time Name");
console.log("--------- ---------- ----- ----");
fmtstr = "%9lu %s %s";
} else {
console.log(" Length Date Time Name");
console.log(" -------- ---- ---- ----");
}
cfb.FileIndex.forEach(function(file/*:CFBEntry*/, i/*:number*/) {
switch(file.type) {
case 5:
basetime = file.ct || file.mt || basetime;
rootsize = file.size;
break;
case 2:
2018-09-04 07:14:20 +00:00
var fixname = fix_string(cfb.FullPaths[i]);
if(program.osx && fixname.match(/\\u0001Sh33tJ5/)) return;
if(program.here) fixname = fixname.slice(rlen);
console.log(sprintf(fmtstr, file.size, format_date(file.mt || basetime, program.osx), fixname));
filesize += file.size;
++cnt;
}
});
2018-09-04 07:14:20 +00:00
var outfmt = "%9lu %lu file%s";
if(program.osx) {
console.log("--------- -------");
outfmt = "%9lu %lu file%s";
} else {
console.log(" -------- -------");
}
console.log(sprintf(outfmt, rootsize || filesize, cnt, (cnt !== 1 ? "s" : "")));
exit(0);
}
function mkdirp(path/*:string*/) { path.split("/").reduce(function(acc/*:string*/, p/*:string*/) {
acc += p + "/";
if(!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); }
return acc;
}, ""); }
function write(path/*:string*/, data/*:CFBEntry*/) {
logit("write", fix_string(path));
fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/ || new Buffer(0));
2013-09-05 18:55:36 +00:00
}
if(program.create || program.append) {
program.args.slice(1).forEach(function(x/*:string*/) {
logit("append", x);
X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x));
});
X.writeFile(cfb, program.args[0]);
exit(0);
}
if(program.delete) {
program.args.slice(1).forEach(function(x/*:string*/) {
logit("delete", x);
X.utils.cfb_del(cfb, "/" + x);
});
X.writeFile(cfb, program.args[0]);
exit(0);
}
if(program.args.length > 1) {
program.args.slice(1).forEach(function(x/*:string*/) {
var data/*:?CFBEntry*/ = X.find(cfb, x.replace(/\\u000\d/g,"!"));
if(!data) { console.error(x + ": file not found"); return; }
if(data.type !== 2) { console.error(x + ": not a file"); return; }
var idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx];
if(program.toStdout) return process.stdout.write(/*::new Buffer((*/data.content/*:: :any))*/);
mkdirp(path.slice(0, path.lastIndexOf("/")));
write(path, data);
});
exit(0);
}
if(program.toStdout) exit(0);
2018-09-04 07:14:20 +00:00
for(var i=program.here ? 1 : 0; i!==cfb.FullPaths.length; ++i) {
if(!cfb.FileIndex[i].name) continue;
2018-09-04 07:14:20 +00:00
var fp = cfb.FullPaths[i];
if(program.here) fp = fp.slice(rlen);
if(fp.slice(-1) === "/") mkdirp(fp);
else {
if(fp.indexOf("/") > -1) mkdirp(fp.slice(0, fp.lastIndexOf("/")));
write(fp, cfb.FileIndex[i]);
}
2013-09-05 18:55:36 +00:00
}