diff --git a/bin/cfb.njs b/bin/cfb.njs deleted file mode 100755 index 862c818..0000000 --- a/bin/cfb.njs +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env node -/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */ -/* eslint-env node */ -/* vim: set ts=2 ft=javascript: */ -var n = "cfb"; -var X = require('../'); -var fs = require('fs'); -var program = require('commander'); -var PRINTJ = require("printj"); -var sprintf = PRINTJ.sprintf; -program - .version(X.version) - .usage('[options] [subfiles...]') - .option('-l, --list-files', 'list files') - .option('-r, --repair', 'attempt to repair and garbage-collect archive') - .option('-c, --create', 'create file') - .option('-a, --append', 'add files to CFB (overwrite existing data)') - .option('-d, --delete', 'delete files from CFB') - .option('-O, --to-stdout', 'extract raw contents to stdout') - .option('-z, --dump', 'dump internal representation but do not extract') - .option('-q, --quiet', 'process but do not report') - .option('--here', 'skip the CFB root name when extracting') - .option('--osx', 'use OSX-style unzip listing') - .option('--zlib', 'use native zlib') - .option('--local', 'print times in local timezone') - .option('--dev', 'development mode') - .option('--read', 'read but do not print out contents'); -program.parse(process.argv); - -if(program.zlib) X.utils.use_zlib(require('zlib')); - -var exit = process.exit; -var die = function(errno/*:number*/, msg/*:string*/) { console.error(n + ": " + msg); exit(errno); }; -var logit = function(cmd/*:string*/, f/*:string*/) { console.error(sprintf("%-6s %s", cmd, f)); }; - -if(program.args.length === 0) die(1, "must specify a filename"); - -if(program.create) { - logit("create", program.args[0]); - var newcfb = X.utils.cfb_new(); - X.writeFile(newcfb, program.args[0]); -} - -if(!fs.existsSync(program.args[0])) die(1, "must specify a filename"); - -var opts = ({type:'file'}/*:any*/); -if(program.dev) opts.WTF = true; - -var cfb = X.read(program.args[0], opts); -if(program.quiet) exit(0); - -if(program.dump) { - console.log("Full Paths:"); - console.log(cfb.FullPaths.map(function(x/*:string*/) { return " " + x; }).join("\n")); - console.log("File Index:"); - console.log(cfb.FileIndex); - exit(0); -} -if(program.repair) { X.writeFile(cfb, program.args[0]); exit(0); } - -var rlen = cfb.FullPaths[0].length; - -function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/g, function($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); } -var format_date = function(date/*:Date*/, osx/*:?any*/)/*:string*/ { - var datefmt = osx ? "%02u-%02u-%04u %02u:%02u": "%02u-%02u-%02u %02u:%02u"; - var MM = program.local ? date.getMonth() + 1 : date.getUTCMonth() + 1; - var DD = program.local ? date.getDate() : date.getUTCDate(); - var YY = (program.local ? date.getFullYear() : date.getUTCFullYear())%(osx ? 10000 : 100); - var hh = program.local ? date.getHours() : date.getUTCHours(); - var mm = program.local ? date.getMinutes() : date.getUTCMinutes(); - return sprintf(datefmt, MM, DD, YY, hh, mm); -}; - -if(program.listFiles) { - var basetime = new Date(Date.UTC(1980,0,1)); - var cnt = 0, rootsize = 0, filesize = 0; - var fmtstr = "%9lu %s %s"; - if(program.osx) { - console.log("Archive: " + program.args[0]); - console.log(" Length Date Time Name"); - console.log("--------- ---------- ----- ----"); - fmtstr = "%9lu %s %s"; - } else { - console.log(" Length Date Time Name"); - console.log(" -------- ---- ---- ----"); - } - cfb.FileIndex.forEach(function(file/*:CFBEntry*/, i/*:number*/) { - switch(file.type) { - case 5: - basetime = file.ct || file.mt || basetime; - rootsize = file.size; - break; - case 2: - var fixname = fix_string(cfb.FullPaths[i]); - if(program.osx && fixname.match(/\\u0001Sh33tJ5/)) return; - if(program.here) fixname = fixname.slice(rlen); - console.log(sprintf(fmtstr, file.size, format_date(file.mt || basetime, program.osx), fixname)); - filesize += file.size; - ++cnt; - } - }); - var outfmt = "%9lu %lu file%s"; - if(program.osx) { - console.log("--------- -------"); - outfmt = "%9lu %lu file%s"; - } else { - console.log(" -------- -------"); - } - console.log(sprintf(outfmt, rootsize || filesize, cnt, (cnt !== 1 ? "s" : ""))); - - exit(0); -} - -function mkdirp(path/*:string*/) { path.split("/").reduce(function(acc/*:string*/, p/*:string*/) { - acc += p + "/"; - if(!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); } - return acc; -}, ""); } - -function write(path/*:string*/, data/*:CFBEntry*/) { - logit("write", fix_string(path)); - fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/ || new Buffer(0)); -} - -if(program.create || program.append) { - program.args.slice(1).forEach(function(x/*:string*/) { - logit("append", x); - X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x)); - }); - X.writeFile(cfb, program.args[0]); - exit(0); -} - -if(program.delete) { - program.args.slice(1).forEach(function(x/*:string*/) { - logit("delete", x); - X.utils.cfb_del(cfb, "/" + x); - }); - X.writeFile(cfb, program.args[0]); - exit(0); -} - -if(program.args.length > 1) { - program.args.slice(1).forEach(function(x/*:string*/) { - var data/*:?CFBEntry*/ = X.find(cfb, x.replace(/\\u000\d/g,"!")); - if(!data) { console.error(x + ": file not found"); return; } - if(data.type !== 2) { console.error(x + ": not a file"); return; } - var idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx]; - if(program.toStdout) return process.stdout.write(/*::new Buffer((*/data.content/*:: :any))*/); - mkdirp(path.slice(0, path.lastIndexOf("/"))); - write(path, data); - }); - exit(0); -} - -if(program.toStdout) exit(0); -for(var i=program.here ? 1 : 0; i!==cfb.FullPaths.length; ++i) { - if(!cfb.FileIndex[i].name) continue; - var fp = cfb.FullPaths[i]; - if(program.here) fp = fp.slice(rlen); - if(fp.slice(-1) === "/") mkdirp(fp); - else { - if(fp.indexOf("/") > -1) mkdirp(fp.slice(0, fp.lastIndexOf("/"))); - write(fp, cfb.FileIndex[i]); - } -} diff --git a/packages/cfb-cli/bin/cfb.njs b/packages/cfb-cli/bin/cfb.njs new file mode 100755 index 0000000..7a99151 --- /dev/null +++ b/packages/cfb-cli/bin/cfb.njs @@ -0,0 +1,7 @@ +#!/usr/bin/env node +/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* eslint-env node */ +/* vim: set ts=2 ft=javascript: */ +var cli = require('../'); + +cli(); diff --git a/packages/cfb-cli/index.js b/packages/cfb-cli/index.js new file mode 100644 index 0000000..a6398dd --- /dev/null +++ b/packages/cfb-cli/index.js @@ -0,0 +1,173 @@ +#!/usr/bin/env node +/* index.js (C) 2020-present SheetJS -- http://sheetjs.com */ +/* eslint-env node */ +/* vim: set ts=2 ft=javascript: */ + +var n = "cfb-cli"; +var X = require('cfb'); +var fs = require('fs'); +var program = require('commander'); +var PRINTJ = require("printj"); +function run() { + var sprintf = PRINTJ.sprintf; + program + .version(X.version) + .usage('[options] [subfiles...]') + .option('-l, --list-files', 'list files') + .option('-r, --repair', 'attempt to repair and garbage-collect archive') + .option('-c, --create', 'create file') + .option('-a, --append', 'add files to CFB (overwrite existing data)') + .option('-d, --delete', 'delete files from CFB') + .option('-O, --to-stdout', 'extract raw contents to stdout') + .option('-z, --dump', 'dump internal representation but do not extract') + .option('-q, --quiet', 'process but do not report') + .option('--here', 'skip the CFB root name when extracting') + .option('--osx', 'use OSX-style unzip listing') + .option('--zlib', 'use native zlib') + .option('--local', 'print times in local timezone') + .option('--dev', 'development mode') + .option('--read', 'read but do not print out contents'); + program.parse(process.argv); + + if (program.zlib) X.utils.use_zlib(require('zlib')); + + var exit = process.exit; + var die = function (errno/*:number*/, msg/*:string*/) { console.error(n + ": " + msg); exit(errno); }; + var logit = function (cmd/*:string*/, f/*:string*/) { console.error(sprintf("%-6s %s", cmd, f)); }; + + if (program.args.length === 0) die(1, "must specify a filename"); + + if (program.create) { + logit("create", program.args[0]); + var newcfb = X.utils.cfb_new(); + X.writeFile(newcfb, program.args[0]); + } + + if (!fs.existsSync(program.args[0])) die(1, "must specify a filename"); + + var opts = ({ type: 'file' }/*:any*/); + if (program.dev) opts.WTF = true; + + var cfb = X.read(program.args[0], opts); + if (program.quiet) exit(0); + + if (program.dump) { + console.log("Full Paths:"); + console.log(cfb.FullPaths.map(function (x/*:string*/) { return " " + x; }).join("\n")); + console.log("File Index:"); + console.log(cfb.FileIndex); + exit(0); + } + if (program.repair) { X.writeFile(cfb, program.args[0]); exit(0); } + + var rlen = cfb.FullPaths[0].length; + + function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/g, function ($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); } + var format_date = function (date/*:Date*/, osx/*:?any*/)/*:string*/ { + var datefmt = osx ? "%02u-%02u-%04u %02u:%02u" : "%02u-%02u-%02u %02u:%02u"; + var MM = program.local ? date.getMonth() + 1 : date.getUTCMonth() + 1; + var DD = program.local ? date.getDate() : date.getUTCDate(); + var YY = (program.local ? date.getFullYear() : date.getUTCFullYear()) % (osx ? 10000 : 100); + var hh = program.local ? date.getHours() : date.getUTCHours(); + var mm = program.local ? date.getMinutes() : date.getUTCMinutes(); + return sprintf(datefmt, MM, DD, YY, hh, mm); + }; + + if (program.listFiles) { + var basetime = new Date(Date.UTC(1980, 0, 1)); + var cnt = 0, rootsize = 0, filesize = 0; + var fmtstr = "%9lu %s %s"; + if (program.osx) { + console.log("Archive: " + program.args[0]); + console.log(" Length Date Time Name"); + console.log("--------- ---------- ----- ----"); + fmtstr = "%9lu %s %s"; + } else { + console.log(" Length Date Time Name"); + console.log(" -------- ---- ---- ----"); + } + cfb.FileIndex.forEach(function (file/*:CFBEntry*/, i/*:number*/) { + switch (file.type) { + case 5: + basetime = file.ct || file.mt || basetime; + rootsize = file.size; + break; + case 2: + var fixname = fix_string(cfb.FullPaths[i]); + if (program.osx && fixname.match(/\\u0001Sh33tJ5/)) return; + if (program.here) fixname = fixname.slice(rlen); + console.log(sprintf(fmtstr, file.size, format_date(file.mt || basetime, program.osx), fixname)); + filesize += file.size; + ++cnt; + } + }); + var outfmt = "%9lu %lu file%s"; + if (program.osx) { + console.log("--------- -------"); + outfmt = "%9lu %lu file%s"; + } else { + console.log(" -------- -------"); + } + console.log(sprintf(outfmt, rootsize || filesize, cnt, (cnt !== 1 ? "s" : ""))); + + exit(0); + } + + function mkdirp(path/*:string*/) { + path.split("/").reduce(function (acc/*:string*/, p/*:string*/) { + acc += p + "/"; + if (!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); } + return acc; + }, ""); + } + + function write(path/*:string*/, data/*:CFBEntry*/) { + logit("write", fix_string(path)); + fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/ || new Buffer(0)); + } + + if (program.create || program.append) { + program.args.slice(1).forEach(function (x/*:string*/) { + logit("append", x); + X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x)); + }); + X.writeFile(cfb, program.args[0]); + exit(0); + } + + if (program.delete) { + program.args.slice(1).forEach(function (x/*:string*/) { + logit("delete", x); + X.utils.cfb_del(cfb, "/" + x); + }); + X.writeFile(cfb, program.args[0]); + exit(0); + } + + if (program.args.length > 1) { + program.args.slice(1).forEach(function (x/*:string*/) { + var data/*:?CFBEntry*/ = X.find(cfb, x.replace(/\\u000\d/g, "!")); + if (!data) { console.error(x + ": file not found"); return; } + if (data.type !== 2) { console.error(x + ": not a file"); return; } + var idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx]; + if (program.toStdout) return process.stdout.write(/*::new Buffer((*/data.content/*:: :any))*/); + mkdirp(path.slice(0, path.lastIndexOf("/"))); + write(path, data); + }); + exit(0); + } + + if (program.toStdout) exit(0); + for (var i = program.here ? 1 : 0; i !== cfb.FullPaths.length; ++i) { + if (!cfb.FileIndex[i].name) continue; + var fp = cfb.FullPaths[i]; + if (program.here) fp = fp.slice(rlen); + if (fp.slice(-1) === "/") mkdirp(fp); + else { + if (fp.indexOf("/") > -1) mkdirp(fp.slice(0, fp.lastIndexOf("/"))); + write(fp, cfb.FileIndex[i]); + } + } +} + +module.exports = run; \ No newline at end of file diff --git a/packages/cfb-cli/package.json b/packages/cfb-cli/package.json new file mode 100644 index 0000000..a5773ad --- /dev/null +++ b/packages/cfb-cli/package.json @@ -0,0 +1,17 @@ +{ + "name": "cfb-cli", + "version": "1.0.0", + "description": "Command-line interface for cfb", + "bin": { + "cfb-cli": "./bin/cfb.njs" + }, + "main": "index.js", + "author": "Garrett Luu", + "license": "Apache-2.0", + "dependencies": { + "cfb": "^1.1.4", + "commander": "^5.1.0", + "fs": "0.0.1-security", + "printj": "^1.2.2" + } +}