const fsystem = require("./fileSystem").require(); const pth = require("path"); const Constants = require("./constants"); const Errors = require("./errors"); const isWin = typeof process === "object" && "win32" === process.platform; const is_Obj = (obj) => obj && typeof obj === "object"; // generate CRC32 lookup table const crcTable = new Uint32Array(256).map((t, c) => { for (let k = 0; k < 8; k++) { if ((c & 1) !== 0) { c = 0xedb88320 ^ (c >>> 1); } else { c >>>= 1; } } return c >>> 0; }); // UTILS functions function Utils(opts) { this.sep = pth.sep; this.fs = fsystem; if (is_Obj(opts)) { // custom filesystem if (is_Obj(opts.fs) && typeof opts.fs.statSync === "function") { this.fs = opts.fs; } } } module.exports = Utils; // INSTANCED functions Utils.prototype.makeDir = function (/*String*/ folder) { const self = this; // Sync - make directories tree function mkdirSync(/*String*/ fpath) { let resolvedPath = fpath.split(self.sep)[0]; fpath.split(self.sep).forEach(function (name) { if (!name || name.substr(-1, 1) === ":") return; resolvedPath += self.sep + name; var stat; try { stat = self.fs.statSync(resolvedPath); } catch (e) { self.fs.mkdirSync(resolvedPath); } if (stat && stat.isFile()) throw Errors.FILE_IN_THE_WAY.replace("%s", resolvedPath); }); } mkdirSync(folder); }; Utils.prototype.writeFileTo = function (/*String*/ path, /*Buffer*/ content, /*Boolean*/ overwrite, /*Number*/ attr) { const self = this; if (self.fs.existsSync(path)) { if (!overwrite) return false; // cannot overwrite var stat = self.fs.statSync(path); if (stat.isDirectory()) { return false; } } var folder = pth.dirname(path); if (!self.fs.existsSync(folder)) { self.makeDir(folder); } var fd; try { fd = self.fs.openSync(path, "w", 438); // 0666 } catch (e) { self.fs.chmodSync(path, 438); fd = self.fs.openSync(path, "w", 438); } if (fd) { try { self.fs.writeSync(fd, content, 0, content.length, 0); } finally { self.fs.closeSync(fd); } } self.fs.chmodSync(path, attr || 438); return true; }; Utils.prototype.writeFileToAsync = function (/*String*/ path, /*Buffer*/ content, /*Boolean*/ overwrite, /*Number*/ attr, /*Function*/ callback) { if (typeof attr === "function") { callback = attr; attr = undefined; } const self = this; self.fs.exists(path, function (exist) { if (exist && !overwrite) return callback(false); self.fs.stat(path, function (err, stat) { if (exist && stat.isDirectory()) { return callback(false); } var folder = pth.dirname(path); self.fs.exists(folder, function (exists) { if (!exists) self.makeDir(folder); self.fs.open(path, "w", 438, function (err, fd) { if (err) { self.fs.chmod(path, 438, function () { self.fs.open(path, "w", 438, function (err, fd) { self.fs.write(fd, content, 0, content.length, 0, function () { self.fs.close(fd, function () { self.fs.chmod(path, attr || 438, function () { callback(true); }); }); }); }); }); } else if (fd) { self.fs.write(fd, content, 0, content.length, 0, function () { self.fs.close(fd, function () { self.fs.chmod(path, attr || 438, function () { callback(true); }); }); }); } else { self.fs.chmod(path, attr || 438, function () { callback(true); }); } }); }); }); }); }; Utils.prototype.findFiles = function (/*String*/ path) { const self = this; function findSync(/*String*/ dir, /*RegExp*/ pattern, /*Boolean*/ recursive) { if (typeof pattern === "boolean") { recursive = pattern; pattern = undefined; } let files = []; self.fs.readdirSync(dir).forEach(function (file) { var path = pth.join(dir, file); if (self.fs.statSync(path).isDirectory() && recursive) files = files.concat(findSync(path, pattern, recursive)); if (!pattern || pattern.test(path)) { files.push(pth.normalize(path) + (self.fs.statSync(path).isDirectory() ? self.sep : "")); } }); return files; } return findSync(path, undefined, true); }; Utils.prototype.getAttributes = function () {}; Utils.prototype.setAttributes = function () {}; // STATIC functions // crc32 single update (it is part of crc32) Utils.crc32update = function (crc, byte) { return crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8); }; Utils.crc32 = function (buf) { if (typeof buf === "string") { buf = Buffer.from(buf, "utf8"); } // Generate crcTable if (!crcTable.length) genCRCTable(); let len = buf.length; let crc = ~0; for (let off = 0; off < len; ) crc = Utils.crc32update(crc, buf[off++]); // xor and cast as uint32 number return ~crc >>> 0; }; Utils.methodToString = function (/*Number*/ method) { switch (method) { case Constants.STORED: return "STORED (" + method + ")"; case Constants.DEFLATED: return "DEFLATED (" + method + ")"; default: return "UNSUPPORTED (" + method + ")"; } }; // removes ".." style path elements Utils.canonical = function (/*string*/ path) { if (!path) return ""; // trick normalize think path is absolute var safeSuffix = pth.posix.normalize("/" + path.split("\\").join("/")); return pth.join(".", safeSuffix); }; // make abolute paths taking prefix as root folder Utils.sanitize = function (/*string*/ prefix, /*string*/ name) { prefix = pth.resolve(pth.normalize(prefix)); var parts = name.split("/"); for (var i = 0, l = parts.length; i < l; i++) { var path = pth.normalize(pth.join(prefix, parts.slice(i, l).join(pth.sep))); if (path.indexOf(prefix) === 0) { return path; } } return pth.normalize(pth.join(prefix, pth.basename(name))); }; // converts buffer, Uint8Array, string types to buffer Utils.toBuffer = function toBuffer(/*buffer, Uint8Array, string*/ input) { if (Buffer.isBuffer(input)) { return input; } else if (input instanceof Uint8Array) { return Buffer.from(input); } else { // expect string all other values are invalid and return empty buffer return typeof input === "string" ? Buffer.from(input, "utf8") : Buffer.alloc(0); } }; Utils.readBigUInt64LE = function (/*Buffer*/ buffer, /*int*/ index) { var slice = Buffer.from(buffer.slice(index, index + 8)); slice.swap64(); return parseInt(`0x${slice.toString("hex")}`); }; Utils.isWin = isWin; // Do we have windows system Utils.crcTable = crcTable;