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.
		
		
		
		
		
			
		
			
				
					
					
						
							215 lines
						
					
					
						
							6.7 KiB
						
					
					
				
			
		
		
	
	
							215 lines
						
					
					
						
							6.7 KiB
						
					
					
				"use strict";
 | 
						|
 | 
						|
var utils = require("../utils");
 | 
						|
var ConvertWorker = require("./ConvertWorker");
 | 
						|
var GenericWorker = require("./GenericWorker");
 | 
						|
var base64 = require("../base64");
 | 
						|
var support = require("../support");
 | 
						|
var external = require("../external");
 | 
						|
 | 
						|
var NodejsStreamOutputAdapter = null;
 | 
						|
if (support.nodestream) {
 | 
						|
    try {
 | 
						|
        NodejsStreamOutputAdapter = require("../nodejs/NodejsStreamOutputAdapter");
 | 
						|
    } catch(e) {
 | 
						|
        // ignore
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Apply the final transformation of the data. If the user wants a Blob for
 | 
						|
 * example, it's easier to work with an U8intArray and finally do the
 | 
						|
 * ArrayBuffer/Blob conversion.
 | 
						|
 * @param {String} type the name of the final type
 | 
						|
 * @param {String|Uint8Array|Buffer} content the content to transform
 | 
						|
 * @param {String} mimeType the mime type of the content, if applicable.
 | 
						|
 * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the content in the right format.
 | 
						|
 */
 | 
						|
function transformZipOutput(type, content, mimeType) {
 | 
						|
    switch(type) {
 | 
						|
    case "blob" :
 | 
						|
        return utils.newBlob(utils.transformTo("arraybuffer", content), mimeType);
 | 
						|
    case "base64" :
 | 
						|
        return base64.encode(content);
 | 
						|
    default :
 | 
						|
        return utils.transformTo(type, content);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Concatenate an array of data of the given type.
 | 
						|
 * @param {String} type the type of the data in the given array.
 | 
						|
 * @param {Array} dataArray the array containing the data chunks to concatenate
 | 
						|
 * @return {String|Uint8Array|Buffer} the concatenated data
 | 
						|
 * @throws Error if the asked type is unsupported
 | 
						|
 */
 | 
						|
function concat (type, dataArray) {
 | 
						|
    var i, index = 0, res = null, totalLength = 0;
 | 
						|
    for(i = 0; i < dataArray.length; i++) {
 | 
						|
        totalLength += dataArray[i].length;
 | 
						|
    }
 | 
						|
    switch(type) {
 | 
						|
    case "string":
 | 
						|
        return dataArray.join("");
 | 
						|
    case "array":
 | 
						|
        return Array.prototype.concat.apply([], dataArray);
 | 
						|
    case "uint8array":
 | 
						|
        res = new Uint8Array(totalLength);
 | 
						|
        for(i = 0; i < dataArray.length; i++) {
 | 
						|
            res.set(dataArray[i], index);
 | 
						|
            index += dataArray[i].length;
 | 
						|
        }
 | 
						|
        return res;
 | 
						|
    case "nodebuffer":
 | 
						|
        return Buffer.concat(dataArray);
 | 
						|
    default:
 | 
						|
        throw new Error("concat : unsupported type '"  + type + "'");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Listen a StreamHelper, accumulate its content and concatenate it into a
 | 
						|
 * complete block.
 | 
						|
 * @param {StreamHelper} helper the helper to use.
 | 
						|
 * @param {Function} updateCallback a callback called on each update. Called
 | 
						|
 * with one arg :
 | 
						|
 * - the metadata linked to the update received.
 | 
						|
 * @return Promise the promise for the accumulation.
 | 
						|
 */
 | 
						|
function accumulate(helper, updateCallback) {
 | 
						|
    return new external.Promise(function (resolve, reject){
 | 
						|
        var dataArray = [];
 | 
						|
        var chunkType = helper._internalType,
 | 
						|
            resultType = helper._outputType,
 | 
						|
            mimeType = helper._mimeType;
 | 
						|
        helper
 | 
						|
            .on("data", function (data, meta) {
 | 
						|
                dataArray.push(data);
 | 
						|
                if(updateCallback) {
 | 
						|
                    updateCallback(meta);
 | 
						|
                }
 | 
						|
            })
 | 
						|
            .on("error", function(err) {
 | 
						|
                dataArray = [];
 | 
						|
                reject(err);
 | 
						|
            })
 | 
						|
            .on("end", function (){
 | 
						|
                try {
 | 
						|
                    var result = transformZipOutput(resultType, concat(chunkType, dataArray), mimeType);
 | 
						|
                    resolve(result);
 | 
						|
                } catch (e) {
 | 
						|
                    reject(e);
 | 
						|
                }
 | 
						|
                dataArray = [];
 | 
						|
            })
 | 
						|
            .resume();
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * An helper to easily use workers outside of JSZip.
 | 
						|
 * @constructor
 | 
						|
 * @param {Worker} worker the worker to wrap
 | 
						|
 * @param {String} outputType the type of data expected by the use
 | 
						|
 * @param {String} mimeType the mime type of the content, if applicable.
 | 
						|
 */
 | 
						|
function StreamHelper(worker, outputType, mimeType) {
 | 
						|
    var internalType = outputType;
 | 
						|
    switch(outputType) {
 | 
						|
    case "blob":
 | 
						|
    case "arraybuffer":
 | 
						|
        internalType = "uint8array";
 | 
						|
        break;
 | 
						|
    case "base64":
 | 
						|
        internalType = "string";
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    try {
 | 
						|
        // the type used internally
 | 
						|
        this._internalType = internalType;
 | 
						|
        // the type used to output results
 | 
						|
        this._outputType = outputType;
 | 
						|
        // the mime type
 | 
						|
        this._mimeType = mimeType;
 | 
						|
        utils.checkSupport(internalType);
 | 
						|
        this._worker = worker.pipe(new ConvertWorker(internalType));
 | 
						|
        // the last workers can be rewired without issues but we need to
 | 
						|
        // prevent any updates on previous workers.
 | 
						|
        worker.lock();
 | 
						|
    } catch(e) {
 | 
						|
        this._worker = new GenericWorker("error");
 | 
						|
        this._worker.error(e);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
StreamHelper.prototype = {
 | 
						|
    /**
 | 
						|
     * Listen a StreamHelper, accumulate its content and concatenate it into a
 | 
						|
     * complete block.
 | 
						|
     * @param {Function} updateCb the update callback.
 | 
						|
     * @return Promise the promise for the accumulation.
 | 
						|
     */
 | 
						|
    accumulate : function (updateCb) {
 | 
						|
        return accumulate(this, updateCb);
 | 
						|
    },
 | 
						|
    /**
 | 
						|
     * Add a listener on an event triggered on a stream.
 | 
						|
     * @param {String} evt the name of the event
 | 
						|
     * @param {Function} fn the listener
 | 
						|
     * @return {StreamHelper} the current helper.
 | 
						|
     */
 | 
						|
    on : function (evt, fn) {
 | 
						|
        var self = this;
 | 
						|
 | 
						|
        if(evt === "data") {
 | 
						|
            this._worker.on(evt, function (chunk) {
 | 
						|
                fn.call(self, chunk.data, chunk.meta);
 | 
						|
            });
 | 
						|
        } else {
 | 
						|
            this._worker.on(evt, function () {
 | 
						|
                utils.delay(fn, arguments, self);
 | 
						|
            });
 | 
						|
        }
 | 
						|
        return this;
 | 
						|
    },
 | 
						|
    /**
 | 
						|
     * Resume the flow of chunks.
 | 
						|
     * @return {StreamHelper} the current helper.
 | 
						|
     */
 | 
						|
    resume : function () {
 | 
						|
        utils.delay(this._worker.resume, [], this._worker);
 | 
						|
        return this;
 | 
						|
    },
 | 
						|
    /**
 | 
						|
     * Pause the flow of chunks.
 | 
						|
     * @return {StreamHelper} the current helper.
 | 
						|
     */
 | 
						|
    pause : function () {
 | 
						|
        this._worker.pause();
 | 
						|
        return this;
 | 
						|
    },
 | 
						|
    /**
 | 
						|
     * Return a nodejs stream for this helper.
 | 
						|
     * @param {Function} updateCb the update callback.
 | 
						|
     * @return {NodejsStreamOutputAdapter} the nodejs stream.
 | 
						|
     */
 | 
						|
    toNodejsStream : function (updateCb) {
 | 
						|
        utils.checkSupport("nodestream");
 | 
						|
        if (this._outputType !== "nodebuffer") {
 | 
						|
            // an object stream containing blob/arraybuffer/uint8array/string
 | 
						|
            // is strange and I don't know if it would be useful.
 | 
						|
            // I you find this comment and have a good usecase, please open a
 | 
						|
            // bug report !
 | 
						|
            throw new Error(this._outputType + " is not supported by this method");
 | 
						|
        }
 | 
						|
 | 
						|
        return new NodejsStreamOutputAdapter(this, {
 | 
						|
            objectMode : this._outputType !== "nodebuffer"
 | 
						|
        }, updateCb);
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
module.exports = StreamHelper;
 |