You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					385 lines
				
				12 KiB
			
		
		
			
		
	
	
					385 lines
				
				12 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								var utf8 = require("./utf8");
							 | 
						||
| 
								 | 
							
								var utils = require("./utils");
							 | 
						||
| 
								 | 
							
								var GenericWorker = require("./stream/GenericWorker");
							 | 
						||
| 
								 | 
							
								var StreamHelper = require("./stream/StreamHelper");
							 | 
						||
| 
								 | 
							
								var defaults = require("./defaults");
							 | 
						||
| 
								 | 
							
								var CompressedObject = require("./compressedObject");
							 | 
						||
| 
								 | 
							
								var ZipObject = require("./zipObject");
							 | 
						||
| 
								 | 
							
								var generate = require("./generate");
							 | 
						||
| 
								 | 
							
								var nodejsUtils = require("./nodejsUtils");
							 | 
						||
| 
								 | 
							
								var NodejsStreamInputAdapter = require("./nodejs/NodejsStreamInputAdapter");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Add a file in the current folder.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 * @param {string} name the name of the file
							 | 
						||
| 
								 | 
							
								 * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file
							 | 
						||
| 
								 | 
							
								 * @param {Object} originalOptions the options of the file
							 | 
						||
| 
								 | 
							
								 * @return {Object} the new file.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var fileAdd = function(name, data, originalOptions) {
							 | 
						||
| 
								 | 
							
								    // be sure sub folders exist
							 | 
						||
| 
								 | 
							
								    var dataType = utils.getTypeOf(data),
							 | 
						||
| 
								 | 
							
								        parent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*
							 | 
						||
| 
								 | 
							
								     * Correct options.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var o = utils.extend(originalOptions || {}, defaults);
							 | 
						||
| 
								 | 
							
								    o.date = o.date || new Date();
							 | 
						||
| 
								 | 
							
								    if (o.compression !== null) {
							 | 
						||
| 
								 | 
							
								        o.compression = o.compression.toUpperCase();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (typeof o.unixPermissions === "string") {
							 | 
						||
| 
								 | 
							
								        o.unixPermissions = parseInt(o.unixPermissions, 8);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // UNX_IFDIR  0040000 see zipinfo.c
							 | 
						||
| 
								 | 
							
								    if (o.unixPermissions && (o.unixPermissions & 0x4000)) {
							 | 
						||
| 
								 | 
							
								        o.dir = true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Bit 4    Directory
							 | 
						||
| 
								 | 
							
								    if (o.dosPermissions && (o.dosPermissions & 0x0010)) {
							 | 
						||
| 
								 | 
							
								        o.dir = true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (o.dir) {
							 | 
						||
| 
								 | 
							
								        name = forceTrailingSlash(name);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (o.createFolders && (parent = parentFolder(name))) {
							 | 
						||
| 
								 | 
							
								        folderAdd.call(this, parent, true);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var isUnicodeString = dataType === "string" && o.binary === false && o.base64 === false;
							 | 
						||
| 
								 | 
							
								    if (!originalOptions || typeof originalOptions.binary === "undefined") {
							 | 
						||
| 
								 | 
							
								        o.binary = !isUnicodeString;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var isCompressedEmpty = (data instanceof CompressedObject) && data.uncompressedSize === 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (isCompressedEmpty || o.dir || !data || data.length === 0) {
							 | 
						||
| 
								 | 
							
								        o.base64 = false;
							 | 
						||
| 
								 | 
							
								        o.binary = true;
							 | 
						||
| 
								 | 
							
								        data = "";
							 | 
						||
| 
								 | 
							
								        o.compression = "STORE";
							 | 
						||
| 
								 | 
							
								        dataType = "string";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*
							 | 
						||
| 
								 | 
							
								     * Convert content to fit.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var zipObjectContent = null;
							 | 
						||
| 
								 | 
							
								    if (data instanceof CompressedObject || data instanceof GenericWorker) {
							 | 
						||
| 
								 | 
							
								        zipObjectContent = data;
							 | 
						||
| 
								 | 
							
								    } else if (nodejsUtils.isNode && nodejsUtils.isStream(data)) {
							 | 
						||
| 
								 | 
							
								        zipObjectContent = new NodejsStreamInputAdapter(name, data);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        zipObjectContent = utils.prepareContent(name, data, o.binary, o.optimizedBinaryString, o.base64);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var object = new ZipObject(name, zipObjectContent, o);
							 | 
						||
| 
								 | 
							
								    this.files[name] = object;
							 | 
						||
| 
								 | 
							
								    /*
							 | 
						||
| 
								 | 
							
								    TODO: we can't throw an exception because we have async promises
							 | 
						||
| 
								 | 
							
								    (we can have a promise of a Date() for example) but returning a
							 | 
						||
| 
								 | 
							
								    promise is useless because file(name, data) returns the JSZip
							 | 
						||
| 
								 | 
							
								    object for chaining. Should we break that to allow the user
							 | 
						||
| 
								 | 
							
								    to catch the error ?
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return external.Promise.resolve(zipObjectContent)
							 | 
						||
| 
								 | 
							
								    .then(function () {
							 | 
						||
| 
								 | 
							
								        return object;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Find the parent folder of the path.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 * @param {string} path the path to use
							 | 
						||
| 
								 | 
							
								 * @return {string} the parent folder, or ""
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var parentFolder = function (path) {
							 | 
						||
| 
								 | 
							
								    if (path.slice(-1) === "/") {
							 | 
						||
| 
								 | 
							
								        path = path.substring(0, path.length - 1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    var lastSlash = path.lastIndexOf("/");
							 | 
						||
| 
								 | 
							
								    return (lastSlash > 0) ? path.substring(0, lastSlash) : "";
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Returns the path with a slash at the end.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 * @param {String} path the path to check.
							 | 
						||
| 
								 | 
							
								 * @return {String} the path with a trailing slash.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var forceTrailingSlash = function(path) {
							 | 
						||
| 
								 | 
							
								    // Check the name ends with a /
							 | 
						||
| 
								 | 
							
								    if (path.slice(-1) !== "/") {
							 | 
						||
| 
								 | 
							
								        path += "/"; // IE doesn't like substr(-1)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return path;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Add a (sub) folder in the current folder.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 * @param {string} name the folder's name
							 | 
						||
| 
								 | 
							
								 * @param {boolean=} [createFolders] If true, automatically create sub
							 | 
						||
| 
								 | 
							
								 *  folders. Defaults to false.
							 | 
						||
| 
								 | 
							
								 * @return {Object} the new folder.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var folderAdd = function(name, createFolders) {
							 | 
						||
| 
								 | 
							
								    createFolders = (typeof createFolders !== "undefined") ? createFolders : defaults.createFolders;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    name = forceTrailingSlash(name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Does this folder already exist?
							 | 
						||
| 
								 | 
							
								    if (!this.files[name]) {
							 | 
						||
| 
								 | 
							
								        fileAdd.call(this, name, null, {
							 | 
						||
| 
								 | 
							
								            dir: true,
							 | 
						||
| 
								 | 
							
								            createFolders: createFolders
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return this.files[name];
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* Cross-window, cross-Node-context regular expression detection
							 | 
						||
| 
								 | 
							
								* @param  {Object}  object Anything
							 | 
						||
| 
								 | 
							
								* @return {Boolean}        true if the object is a regular expression,
							 | 
						||
| 
								 | 
							
								* false otherwise
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								function isRegExp(object) {
							 | 
						||
| 
								 | 
							
								    return Object.prototype.toString.call(object) === "[object RegExp]";
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// return the actual prototype of JSZip
							 | 
						||
| 
								 | 
							
								var out = {
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @see loadAsync
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    load: function() {
							 | 
						||
| 
								 | 
							
								        throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Call a callback function for each entry at this folder level.
							 | 
						||
| 
								 | 
							
								     * @param {Function} cb the callback function:
							 | 
						||
| 
								 | 
							
								     * function (relativePath, file) {...}
							 | 
						||
| 
								 | 
							
								     * It takes 2 arguments : the relative path and the file.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    forEach: function(cb) {
							 | 
						||
| 
								 | 
							
								        var filename, relativePath, file;
							 | 
						||
| 
								 | 
							
								        // ignore warning about unwanted properties because this.files is a null prototype object
							 | 
						||
| 
								 | 
							
								        /* eslint-disable-next-line guard-for-in */
							 | 
						||
| 
								 | 
							
								        for (filename in this.files) {
							 | 
						||
| 
								 | 
							
								            file = this.files[filename];
							 | 
						||
| 
								 | 
							
								            relativePath = filename.slice(this.root.length, filename.length);
							 | 
						||
| 
								 | 
							
								            if (relativePath && filename.slice(0, this.root.length) === this.root) { // the file is in the current root
							 | 
						||
| 
								 | 
							
								                cb(relativePath, file); // TODO reverse the parameters ? need to be clean AND consistent with the filter search fn...
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Filter nested files/folders with the specified function.
							 | 
						||
| 
								 | 
							
								     * @param {Function} search the predicate to use :
							 | 
						||
| 
								 | 
							
								     * function (relativePath, file) {...}
							 | 
						||
| 
								 | 
							
								     * It takes 2 arguments : the relative path and the file.
							 | 
						||
| 
								 | 
							
								     * @return {Array} An array of matching elements.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    filter: function(search) {
							 | 
						||
| 
								 | 
							
								        var result = [];
							 | 
						||
| 
								 | 
							
								        this.forEach(function (relativePath, entry) {
							 | 
						||
| 
								 | 
							
								            if (search(relativePath, entry)) { // the file matches the function
							 | 
						||
| 
								 | 
							
								                result.push(entry);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								        return result;
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Add a file to the zip file, or search a file.
							 | 
						||
| 
								 | 
							
								     * @param   {string|RegExp} name The name of the file to add (if data is defined),
							 | 
						||
| 
								 | 
							
								     * the name of the file to find (if no data) or a regex to match files.
							 | 
						||
| 
								 | 
							
								     * @param   {String|ArrayBuffer|Uint8Array|Buffer} data  The file data, either raw or base64 encoded
							 | 
						||
| 
								 | 
							
								     * @param   {Object} o     File options
							 | 
						||
| 
								 | 
							
								     * @return  {JSZip|Object|Array} this JSZip object (when adding a file),
							 | 
						||
| 
								 | 
							
								     * a file (when searching by string) or an array of files (when searching by regex).
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    file: function(name, data, o) {
							 | 
						||
| 
								 | 
							
								        if (arguments.length === 1) {
							 | 
						||
| 
								 | 
							
								            if (isRegExp(name)) {
							 | 
						||
| 
								 | 
							
								                var regexp = name;
							 | 
						||
| 
								 | 
							
								                return this.filter(function(relativePath, file) {
							 | 
						||
| 
								 | 
							
								                    return !file.dir && regexp.test(relativePath);
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else { // text
							 | 
						||
| 
								 | 
							
								                var obj = this.files[this.root + name];
							 | 
						||
| 
								 | 
							
								                if (obj && !obj.dir) {
							 | 
						||
| 
								 | 
							
								                    return obj;
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    return null;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else { // more than one argument : we have data !
							 | 
						||
| 
								 | 
							
								            name = this.root + name;
							 | 
						||
| 
								 | 
							
								            fileAdd.call(this, name, data, o);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return this;
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Add a directory to the zip file, or search.
							 | 
						||
| 
								 | 
							
								     * @param   {String|RegExp} arg The name of the directory to add, or a regex to search folders.
							 | 
						||
| 
								 | 
							
								     * @return  {JSZip} an object with the new directory as the root, or an array containing matching folders.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    folder: function(arg) {
							 | 
						||
| 
								 | 
							
								        if (!arg) {
							 | 
						||
| 
								 | 
							
								            return this;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (isRegExp(arg)) {
							 | 
						||
| 
								 | 
							
								            return this.filter(function(relativePath, file) {
							 | 
						||
| 
								 | 
							
								                return file.dir && arg.test(relativePath);
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // else, name is a new folder
							 | 
						||
| 
								 | 
							
								        var name = this.root + arg;
							 | 
						||
| 
								 | 
							
								        var newFolder = folderAdd.call(this, name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Allow chaining by returning a new object with this folder as the root
							 | 
						||
| 
								 | 
							
								        var ret = this.clone();
							 | 
						||
| 
								 | 
							
								        ret.root = newFolder.name;
							 | 
						||
| 
								 | 
							
								        return ret;
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Delete a file, or a directory and all sub-files, from the zip
							 | 
						||
| 
								 | 
							
								     * @param {string} name the name of the file to delete
							 | 
						||
| 
								 | 
							
								     * @return {JSZip} this JSZip object
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    remove: function(name) {
							 | 
						||
| 
								 | 
							
								        name = this.root + name;
							 | 
						||
| 
								 | 
							
								        var file = this.files[name];
							 | 
						||
| 
								 | 
							
								        if (!file) {
							 | 
						||
| 
								 | 
							
								            // Look for any folders
							 | 
						||
| 
								 | 
							
								            if (name.slice(-1) !== "/") {
							 | 
						||
| 
								 | 
							
								                name += "/";
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            file = this.files[name];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (file && !file.dir) {
							 | 
						||
| 
								 | 
							
								            // file
							 | 
						||
| 
								 | 
							
								            delete this.files[name];
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            // maybe a folder, delete recursively
							 | 
						||
| 
								 | 
							
								            var kids = this.filter(function(relativePath, file) {
							 | 
						||
| 
								 | 
							
								                return file.name.slice(0, name.length) === name;
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								            for (var i = 0; i < kids.length; i++) {
							 | 
						||
| 
								 | 
							
								                delete this.files[kids[i].name];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return this;
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @deprecated This method has been removed in JSZip 3.0, please check the upgrade guide.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    generate: function() {
							 | 
						||
| 
								 | 
							
								        throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Generate the complete zip file as an internal stream.
							 | 
						||
| 
								 | 
							
								     * @param {Object} options the options to generate the zip file :
							 | 
						||
| 
								 | 
							
								     * - compression, "STORE" by default.
							 | 
						||
| 
								 | 
							
								     * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob.
							 | 
						||
| 
								 | 
							
								     * @return {StreamHelper} the streamed zip file.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    generateInternalStream: function(options) {
							 | 
						||
| 
								 | 
							
								        var worker, opts = {};
							 | 
						||
| 
								 | 
							
								        try {
							 | 
						||
| 
								 | 
							
								            opts = utils.extend(options || {}, {
							 | 
						||
| 
								 | 
							
								                streamFiles: false,
							 | 
						||
| 
								 | 
							
								                compression: "STORE",
							 | 
						||
| 
								 | 
							
								                compressionOptions : null,
							 | 
						||
| 
								 | 
							
								                type: "",
							 | 
						||
| 
								 | 
							
								                platform: "DOS",
							 | 
						||
| 
								 | 
							
								                comment: null,
							 | 
						||
| 
								 | 
							
								                mimeType: "application/zip",
							 | 
						||
| 
								 | 
							
								                encodeFileName: utf8.utf8encode
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            opts.type = opts.type.toLowerCase();
							 | 
						||
| 
								 | 
							
								            opts.compression = opts.compression.toUpperCase();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // "binarystring" is preferred but the internals use "string".
							 | 
						||
| 
								 | 
							
								            if(opts.type === "binarystring") {
							 | 
						||
| 
								 | 
							
								                opts.type = "string";
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (!opts.type) {
							 | 
						||
| 
								 | 
							
								                throw new Error("No output type specified.");
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            utils.checkSupport(opts.type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // accept nodejs `process.platform`
							 | 
						||
| 
								 | 
							
								            if(
							 | 
						||
| 
								 | 
							
								                opts.platform === "darwin" ||
							 | 
						||
| 
								 | 
							
								                opts.platform === "freebsd" ||
							 | 
						||
| 
								 | 
							
								                opts.platform === "linux" ||
							 | 
						||
| 
								 | 
							
								                opts.platform === "sunos"
							 | 
						||
| 
								 | 
							
								            ) {
							 | 
						||
| 
								 | 
							
								                opts.platform = "UNIX";
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (opts.platform === "win32") {
							 | 
						||
| 
								 | 
							
								                opts.platform = "DOS";
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var comment = opts.comment || this.comment || "";
							 | 
						||
| 
								 | 
							
								            worker = generate.generateWorker(this, opts, comment);
							 | 
						||
| 
								 | 
							
								        } catch (e) {
							 | 
						||
| 
								 | 
							
								            worker = new GenericWorker("error");
							 | 
						||
| 
								 | 
							
								            worker.error(e);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return new StreamHelper(worker, opts.type || "string", opts.mimeType);
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Generate the complete zip file asynchronously.
							 | 
						||
| 
								 | 
							
								     * @see generateInternalStream
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    generateAsync: function(options, onUpdate) {
							 | 
						||
| 
								 | 
							
								        return this.generateInternalStream(options).accumulate(onUpdate);
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Generate the complete zip file asynchronously.
							 | 
						||
| 
								 | 
							
								     * @see generateInternalStream
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    generateNodeStream: function(options, onUpdate) {
							 | 
						||
| 
								 | 
							
								        options = options || {};
							 | 
						||
| 
								 | 
							
								        if (!options.type) {
							 | 
						||
| 
								 | 
							
								            options.type = "nodebuffer";
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return this.generateInternalStream(options).toNodejsStream(onUpdate);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								module.exports = out;
							 |