TrinetraLabs/Placebo_AI
0
1"use strict";2var utf8 = require("./utf8");3var utils = require("./utils");4var GenericWorker = require("./stream/GenericWorker");5var StreamHelper = require("./stream/StreamHelper");6var defaults = require("./defaults");7var CompressedObject = require("./compressedObject");8var ZipObject = require("./zipObject");9var generate = require("./generate");10var nodejsUtils = require("./nodejsUtils");11var NodejsStreamInputAdapter = require("./nodejs/NodejsStreamInputAdapter");12 13 14/**15 * Add a file in the current folder.16 * @private17 * @param {string} name the name of the file18 * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file19 * @param {Object} originalOptions the options of the file20 * @return {Object} the new file.21 */22var fileAdd = function(name, data, originalOptions) {23 // be sure sub folders exist24 var dataType = utils.getTypeOf(data),25 parent;26 27 28 /*29 * Correct options.30 */31 32 var o = utils.extend(originalOptions || {}, defaults);33 o.date = o.date || new Date();34 if (o.compression !== null) {35 o.compression = o.compression.toUpperCase();36 }37 38 if (typeof o.unixPermissions === "string") {39 o.unixPermissions = parseInt(o.unixPermissions, 8);40 }41 42 // UNX_IFDIR 0040000 see zipinfo.c43 if (o.unixPermissions && (o.unixPermissions & 0x4000)) {44 o.dir = true;45 }46 // Bit 4 Directory47 if (o.dosPermissions && (o.dosPermissions & 0x0010)) {48 o.dir = true;49 }50 51 if (o.dir) {52 name = forceTrailingSlash(name);53 }54 if (o.createFolders && (parent = parentFolder(name))) {55 folderAdd.call(this, parent, true);56 }57 58 var isUnicodeString = dataType === "string" && o.binary === false && o.base64 === false;59 if (!originalOptions || typeof originalOptions.binary === "undefined") {60 o.binary = !isUnicodeString;61 }62 63 64 var isCompressedEmpty = (data instanceof CompressedObject) && data.uncompressedSize === 0;65 66 if (isCompressedEmpty || o.dir || !data || data.length === 0) {67 o.base64 = false;68 o.binary = true;69 data = "";70 o.compression = "STORE";71 dataType = "string";72 }73 74 /*75 * Convert content to fit.76 */77 78 var zipObjectContent = null;79 if (data instanceof CompressedObject || data instanceof GenericWorker) {80 zipObjectContent = data;81 } else if (nodejsUtils.isNode && nodejsUtils.isStream(data)) {82 zipObjectContent = new NodejsStreamInputAdapter(name, data);83 } else {84 zipObjectContent = utils.prepareContent(name, data, o.binary, o.optimizedBinaryString, o.base64);85 }86 87 var object = new ZipObject(name, zipObjectContent, o);88 this.files[name] = object;89 /*90 TODO: we can't throw an exception because we have async promises91 (we can have a promise of a Date() for example) but returning a92 promise is useless because file(name, data) returns the JSZip93 object for chaining. Should we break that to allow the user94 to catch the error ?95 96 return external.Promise.resolve(zipObjectContent)97 .then(function () {98 return object;99 });100 */101};102 103/**104 * Find the parent folder of the path.105 * @private106 * @param {string} path the path to use107 * @return {string} the parent folder, or ""108 */109var parentFolder = function (path) {110 if (path.slice(-1) === "/") {111 path = path.substring(0, path.length - 1);112 }113 var lastSlash = path.lastIndexOf("/");114 return (lastSlash > 0) ? path.substring(0, lastSlash) : "";115};116 117/**118 * Returns the path with a slash at the end.119 * @private120 * @param {String} path the path to check.121 * @return {String} the path with a trailing slash.122 */123var forceTrailingSlash = function(path) {124 // Check the name ends with a /125 if (path.slice(-1) !== "/") {126 path += "/"; // IE doesn't like substr(-1)127 }128 return path;129};130 131/**132 * Add a (sub) folder in the current folder.133 * @private134 * @param {string} name the folder's name135 * @param {boolean=} [createFolders] If true, automatically create sub136 * folders. Defaults to false.137 * @return {Object} the new folder.138 */139var folderAdd = function(name, createFolders) {140 createFolders = (typeof createFolders !== "undefined") ? createFolders : defaults.createFolders;141 142 name = forceTrailingSlash(name);143 144 // Does this folder already exist?145 if (!this.files[name]) {146 fileAdd.call(this, name, null, {147 dir: true,148 createFolders: createFolders149 });150 }151 return this.files[name];152};153 154/**155* Cross-window, cross-Node-context regular expression detection156* @param {Object} object Anything157* @return {Boolean} true if the object is a regular expression,158* false otherwise159*/160function isRegExp(object) {161 return Object.prototype.toString.call(object) === "[object RegExp]";162}163 164// return the actual prototype of JSZip165var out = {166 /**167 * @see loadAsync168 */169 load: function() {170 throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");171 },172 173 174 /**175 * Call a callback function for each entry at this folder level.176 * @param {Function} cb the callback function:177 * function (relativePath, file) {...}178 * It takes 2 arguments : the relative path and the file.179 */180 forEach: function(cb) {181 var filename, relativePath, file;182 // ignore warning about unwanted properties because this.files is a null prototype object183 /* eslint-disable-next-line guard-for-in */184 for (filename in this.files) {185 file = this.files[filename];186 relativePath = filename.slice(this.root.length, filename.length);187 if (relativePath && filename.slice(0, this.root.length) === this.root) { // the file is in the current root188 cb(relativePath, file); // TODO reverse the parameters ? need to be clean AND consistent with the filter search fn...189 }190 }191 },192 193 /**194 * Filter nested files/folders with the specified function.195 * @param {Function} search the predicate to use :196 * function (relativePath, file) {...}197 * It takes 2 arguments : the relative path and the file.198 * @return {Array} An array of matching elements.199 */200 filter: function(search) {201 var result = [];202 this.forEach(function (relativePath, entry) {203 if (search(relativePath, entry)) { // the file matches the function204 result.push(entry);205 }206 207 });208 return result;209 },210 211 /**212 * Add a file to the zip file, or search a file.213 * @param {string|RegExp} name The name of the file to add (if data is defined),214 * the name of the file to find (if no data) or a regex to match files.215 * @param {String|ArrayBuffer|Uint8Array|Buffer} data The file data, either raw or base64 encoded216 * @param {Object} o File options217 * @return {JSZip|Object|Array} this JSZip object (when adding a file),218 * a file (when searching by string) or an array of files (when searching by regex).219 */220 file: function(name, data, o) {221 if (arguments.length === 1) {222 if (isRegExp(name)) {223 var regexp = name;224 return this.filter(function(relativePath, file) {225 return !file.dir && regexp.test(relativePath);226 });227 }228 else { // text229 var obj = this.files[this.root + name];230 if (obj && !obj.dir) {231 return obj;232 } else {233 return null;234 }235 }236 }237 else { // more than one argument : we have data !238 name = this.root + name;239 fileAdd.call(this, name, data, o);240 }241 return this;242 },243 244 /**245 * Add a directory to the zip file, or search.246 * @param {String|RegExp} arg The name of the directory to add, or a regex to search folders.247 * @return {JSZip} an object with the new directory as the root, or an array containing matching folders.248 */249 folder: function(arg) {250 if (!arg) {251 return this;252 }253 254 if (isRegExp(arg)) {255 return this.filter(function(relativePath, file) {256 return file.dir && arg.test(relativePath);257 });258 }259 260 // else, name is a new folder261 var name = this.root + arg;262 var newFolder = folderAdd.call(this, name);263 264 // Allow chaining by returning a new object with this folder as the root265 var ret = this.clone();266 ret.root = newFolder.name;267 return ret;268 },269 270 /**271 * Delete a file, or a directory and all sub-files, from the zip272 * @param {string} name the name of the file to delete273 * @return {JSZip} this JSZip object274 */275 remove: function(name) {276 name = this.root + name;277 var file = this.files[name];278 if (!file) {279 // Look for any folders280 if (name.slice(-1) !== "/") {281 name += "/";282 }283 file = this.files[name];284 }285 286 if (file && !file.dir) {287 // file288 delete this.files[name];289 } else {290 // maybe a folder, delete recursively291 var kids = this.filter(function(relativePath, file) {292 return file.name.slice(0, name.length) === name;293 });294 for (var i = 0; i < kids.length; i++) {295 delete this.files[kids[i].name];296 }297 }298 299 return this;300 },301 302 /**303 * @deprecated This method has been removed in JSZip 3.0, please check the upgrade guide.304 */305 generate: function() {306 throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");307 },308 309 /**310 * Generate the complete zip file as an internal stream.311 * @param {Object} options the options to generate the zip file :312 * - compression, "STORE" by default.313 * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob.314 * @return {StreamHelper} the streamed zip file.315 */316 generateInternalStream: function(options) {317 var worker, opts = {};318 try {319 opts = utils.extend(options || {}, {320 streamFiles: false,321 compression: "STORE",322 compressionOptions : null,323 type: "",324 platform: "DOS",325 comment: null,326 mimeType: "application/zip",327 encodeFileName: utf8.utf8encode328 });329 330 opts.type = opts.type.toLowerCase();331 opts.compression = opts.compression.toUpperCase();332 333 // "binarystring" is preferred but the internals use "string".334 if(opts.type === "binarystring") {335 opts.type = "string";336 }337 338 if (!opts.type) {339 throw new Error("No output type specified.");340 }341 342 utils.checkSupport(opts.type);343 344 // accept nodejs `process.platform`345 if(346 opts.platform === "darwin" ||347 opts.platform === "freebsd" ||348 opts.platform === "linux" ||349 opts.platform === "sunos"350 ) {351 opts.platform = "UNIX";352 }353 if (opts.platform === "win32") {354 opts.platform = "DOS";355 }356 357 var comment = opts.comment || this.comment || "";358 worker = generate.generateWorker(this, opts, comment);359 } catch (e) {360 worker = new GenericWorker("error");361 worker.error(e);362 }363 return new StreamHelper(worker, opts.type || "string", opts.mimeType);364 },365 /**366 * Generate the complete zip file asynchronously.367 * @see generateInternalStream368 */369 generateAsync: function(options, onUpdate) {370 return this.generateInternalStream(options).accumulate(onUpdate);371 },372 /**373 * Generate the complete zip file asynchronously.374 * @see generateInternalStream375 */376 generateNodeStream: function(options, onUpdate) {377 options = options || {};378 if (!options.type) {379 options.type = "nodebuffer";380 }381 return this.generateInternalStream(options).toNodejsStream(onUpdate);382 }383};384module.exports = out;385 