// public method for encoding
exports.encode = function(input) { var output = []; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0, len = input.length, remainingBytes = len;
var isArray = utils.getTypeOf(input) !== "string"; while (i < input.length) {
remainingBytes = len - i;
if (!isArray) {
chr1 = input.charCodeAt(i++);
chr2 = i < len ? input.charCodeAt(i++) : 0;
chr3 = i < len ? input.charCodeAt(i++) : 0;
} else {
chr1 = input[i++];
chr2 = i < len ? input[i++] : 0;
chr3 = i < len ? input[i++] : 0;
}
// public method for decoding
exports.decode = function(input) { var chr1, chr2, chr3; var enc1, enc2, enc3, enc4; var i = 0, resultIndex = 0;
var dataUrlPrefix = "data:";
if (input.substr(0, dataUrlPrefix.length) === dataUrlPrefix) { // This is a common error: people give a data url // (data:image/png;base64,iVBOR...) with a {base64: true} and // wonders why things don't work. // We can detect that the string input looks like a data url but we // *can't* be sure it is one: removing everything up to the comma would // be too dangerous. thrownew Error("Invalid base64 input, it looks like a data url.");
}
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
var totalLength = input.length * 3 / 4; if(input.charAt(input.length - 1) === _keyStr.charAt(64)) {
totalLength--;
} if(input.charAt(input.length - 2) === _keyStr.charAt(64)) {
totalLength--;
} if (totalLength % 1 !== 0) { // totalLength is not an integer, the length does not match a valid // base64 content. That can happen if: // - the input is not a base64 content // - the input is *almost* a base64 content, with a extra chars at the // beginning or at the end // - the input uses a base64 variant (base64url for example) thrownew Error("Invalid base64 input, bad content length.");
} var output; if (support.uint8array) {
output = new Uint8Array(totalLength|0);
} else {
output = new Array(totalLength|0);
}
var external = require("./external"); var DataWorker = require('./stream/DataWorker'); var DataLengthProbe = require('./stream/DataLengthProbe'); var Crc32Probe = require('./stream/Crc32Probe'); var DataLengthProbe = require('./stream/DataLengthProbe');
/** * Represent a compressed object, with everything needed to decompress it. * @constructor * @param {number} compressedSize the size of the data compressed. * @param {number} uncompressedSize the size of the data after decompression. * @param {number} crc32 the crc32 of the decompressed file. * @param {object} compression the type of compression, see lib/compressions.js. * @param {String|ArrayBuffer|Uint8Array|Buffer} data the compressed data.
*/ function CompressedObject(compressedSize, uncompressedSize, crc32, compression, data) { this.compressedSize = compressedSize; this.uncompressedSize = uncompressedSize; this.crc32 = crc32; this.compression = compression; this.compressedContent = data;
}
CompressedObject.prototype = { /** * Create a worker to get the uncompressed content. * @return {GenericWorker} the worker.
*/
getContentWorker : function () { var worker = new DataWorker(external.Promise.resolve(this.compressedContent))
.pipe(this.compression.uncompressWorker())
.pipe(new DataLengthProbe("data_length"));
var that = this;
worker.on("end", function () { if(this.streamInfo['data_length'] !== that.uncompressedSize) { thrownew Error("Bug : uncompressed data size mismatch");
}
}); return worker;
}, /** * Create a worker to get the compressed content. * @return {GenericWorker} the worker.
*/
getCompressedWorker : function () { returnnew DataWorker(external.Promise.resolve(this.compressedContent))
.withStreamInfo("compressedSize", this.compressedSize)
.withStreamInfo("uncompressedSize", this.uncompressedSize)
.withStreamInfo("crc32", this.crc32)
.withStreamInfo("compression", this.compression)
;
}
};
/** * Chain the given worker with other workers to compress the content with the * given compresion. * @param {GenericWorker} uncompressedWorker the worker to pipe. * @param {Object} compression the compression object. * @param {Object} compressionOptions the options to use when compressing. * @return {GenericWorker} the new worker compressing the content.
*/
CompressedObject.createWorkerFrom = function (uncompressedWorker, compression, compressionOptions) { return uncompressedWorker
.pipe(new Crc32Probe())
.pipe(new DataLengthProbe("uncompressedSize"))
.pipe(compression.compressWorker(compressionOptions))
.pipe(new DataLengthProbe("compressedSize"))
.withStreamInfo("compression", compression);
};
/** * The following functions come from pako, from pako/lib/zlib/crc32.js * released under the MIT license, see pako https://github.com/nodeca/pako/
*/
// Use ordinary array, since untyped makes no boost here function makeTable() { var c, table = [];
for(var n =0; n < 256; n++){
c = n; for(var k =0; k < 8; k++){
c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
table[n] = c;
}
return table;
}
// Create table on load. Just 255 signed longs. Not a problem. var crcTable = makeTable();
function crc32(crc, buf, len, pos) { var t = crcTable, end = pos + len;
crc = crc ^ (-1);
for (var i = pos; i < end; i++ ) {
crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
}
return (crc ^ (-1)); // >>> 0;
}
// That's all for the pako functions.
/** * Compute the crc32 of a string. * This is almost the same as the function crc32, but for strings. Using the * same function for the two use cases leads to horrible performances. * @param {Number} crc the starting value of the crc. * @param {String} str the string to use. * @param {Number} len the length of the string. * @param {Number} pos the starting position for the crc32 computation. * @return {Number} the computed crc32.
*/ function crc32str(crc, str, len, pos) { var t = crcTable, end = pos + len;
crc = crc ^ (-1);
for (var i = pos; i < end; i++ ) {
crc = (crc >>> 8) ^ t[(crc ^ str.charCodeAt(i)) & 0xFF];
}
return (crc ^ (-1)); // >>> 0;
}
module.exports = function crc32wrapper(input, crc) { if (typeof input === "undefined" || !input.length) { return 0;
}
var isArray = utils.getTypeOf(input) !== "string";
},{}],6:[function(require,module,exports){ /* global Promise */ 'use strict';
// load the global object first: // - it should be better integrated in the system (unhandledRejection in node) // - the environment may have a custom Promise implementation (see zone.js) var ES6Promise = null; if (typeof Promise !== "undefined") {
ES6Promise = Promise;
} else {
ES6Promise = require("lie");
}
/** * Let the user use/change some implementations.
*/
module.exports = {
Promise: ES6Promise
};
var pako = require("pako"); var utils = require("./utils"); var GenericWorker = require("./stream/GenericWorker");
var ARRAY_TYPE = USE_TYPEDARRAY ? "uint8array" : "array";
exports.magic = "\x08\x00";
/** * Create a worker that uses pako to inflate/deflate. * @constructor * @param {String} action the name of the pako function to call : either "Deflate" or "Inflate". * @param {Object} options the options to use when (de)compressing.
*/ function FlateWorker(action, options) {
GenericWorker.call(this, "FlateWorker/" + action);
this._pako = null; this._pakoAction = action; this._pakoOptions = options; // the `meta` object from the last chunk received // this allow this worker to pass around metadata this.meta = {};
}
/** * Create the _pako object. * TODO: lazy-loading this object isn't the best solution but it's the * quickest. The best solution is to lazy-load the worker list. See also the * issue #446.
*/
FlateWorker.prototype._createPako = function () { this._pako = new pako[this._pakoAction]({
raw: true,
level: this._pakoOptions.level || -1 // default compression
}); var self = this; this._pako.onData = function(data) {
self.push({
data : data,
meta : self.meta
});
};
};
exports.compressWorker = function (compressionOptions) { returnnew FlateWorker("Deflate", compressionOptions);
};
exports.uncompressWorker = function () { returnnew FlateWorker("Inflate", {});
};
var utils = require('../utils'); var GenericWorker = require('../stream/GenericWorker'); var utf8 = require('../utf8'); var crc32 = require('../crc32'); var signature = require('../signature');
/** * Transform an integer into a string in hexadecimal. * @private * @param {number} dec the number to convert. * @param {number} bytes the number of bytes to generate. * @returns {string} the result.
*/ var decToHex = function(dec, bytes) { var hex = "", i; for (i = 0; i < bytes; i++) {
hex += String.fromCharCode(dec & 0xff);
dec = dec >>> 8;
} return hex;
};
/** * Generate the UNIX part of the external file attributes. * @param {Object} unixPermissions the unix permissions or null. * @param {Boolean} isDir true if the entry is a directory, false otherwise. * @return {Number} a 32 bit integer. * * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute : * * TTTTsstrwxrwxrwx0000000000ADVSHR * ^^^^____________________________ file type, see zipinfo.c (UNX_*) * ^^^_________________________ setuid, setgid, sticky * ^^^^^^^^^________________ permissions * ^^^^^^^^^^______ not used ? * ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only
*/ var generateUnixExternalFileAttr = function (unixPermissions, isDir) {
var result = unixPermissions; if (!unixPermissions) { // I can't use octal values in strict mode, hence the hexa. // 040775 => 0x41fd // 0100664 => 0x81b4
result = isDir ? 0x41fd : 0x81b4;
} return (result & 0xFFFF) << 16;
};
/** * Generate the DOS part of the external file attributes. * @param {Object} dosPermissions the dos permissions or null. * @param {Boolean} isDir true if the entry is a directory, false otherwise. * @return {Number} a 32 bit integer. * * Bit 0 Read-Only * Bit 1 Hidden * Bit 2 System * Bit 3 Volume Label * Bit 4 Directory * Bit 5 Archive
*/ var generateDosExternalFileAttr = function (dosPermissions, isDir) {
// the dir flag is already set for compatibility return (dosPermissions || 0) & 0x3F;
};
/** * Generate the various parts used in the construction of the final zip file. * @param {Object} streamInfo the hash with informations about the compressed file. * @param {Boolean} streamedContent is the content streamed ? * @param {Boolean} streamingEnded is the stream finished ? * @param {number} offset the current offset from the start of the zip file. * @param {String} platform let's pretend we are this platform (change platform dependents fields) * @param {Function} encodeFileName the function to encode the file name / comment. * @return {Object} the zip parts.
*/ var generateZipParts = function(streamInfo, streamedContent, streamingEnded, offset, platform, encodeFileName) { var file = streamInfo['file'],
compression = streamInfo['compression'],
useCustomEncoding = encodeFileName !== utf8.utf8encode,
encodedFileName = utils.transformTo("string", encodeFileName(file.name)),
utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)),
comment = file.comment,
encodedComment = utils.transformTo("string", encodeFileName(comment)),
utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)),
useUTF8ForFileName = utfEncodedFileName.length !== file.name.length,
useUTF8ForComment = utfEncodedComment.length !== comment.length,
dosTime,
dosDate,
extraFields = "",
unicodePathExtraField = "",
unicodeCommentExtraField = "",
dir = file.dir,
date = file.date;
// if the content is streamed, the sizes/crc32 are only available AFTER // the end of the stream. if (!streamedContent || streamingEnded) {
dataInfo.crc32 = streamInfo['crc32'];
dataInfo.compressedSize = streamInfo['compressedSize'];
dataInfo.uncompressedSize = streamInfo['uncompressedSize'];
}
var bitflag = 0; if (streamedContent) { // Bit 3: the sizes/crc32 are set to zero in the local header. // The correct values are put in the data descriptor immediately // following the compressed data.
bitflag |= 0x0008;
} if (!useCustomEncoding && (useUTF8ForFileName || useUTF8ForComment)) { // Bit 11: Language encoding flag (EFS).
bitflag |= 0x0800;
}
var extFileAttr = 0; var versionMadeBy = 0; if (dir) { // dos or unix, we set the dos dir flag
extFileAttr |= 0x00010;
} if(platform === "UNIX") {
versionMadeBy = 0x031E; // UNIX, version 3.0
extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir);
} else { // DOS or other, fallback to DOS
versionMadeBy = 0x0014; // DOS, version 2.0
extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir);
}
if (useUTF8ForFileName) { // set the unicode path extra field. unzip needs at least one extra // field to correctly handle unicode path, so using the path is as good // as any other information. This could improve the situation with // other archive managers too. // This field is usually used without the utf8 flag, with a non // unicode path in the header (winrar, winzip). This helps (a bit) // with the messy Windows' default compressed folders feature but // breaks on p7zip which doesn't seek the unicode path extra field. // So for now, UTF-8 everywhere !
unicodePathExtraField = // Version
decToHex(1, 1) + // NameCRC32
decToHex(crc32(encodedFileName), 4) + // UnicodeName
utfEncodedFileName;
extraFields += // Info-ZIP Unicode Path Extra Field "\x75\x70" + // size
decToHex(unicodePathExtraField.length, 2) + // content
unicodePathExtraField;
}
extraFields += // Info-ZIP Unicode Path Extra Field "\x75\x63" + // size
decToHex(unicodeCommentExtraField.length, 2) + // content
unicodeCommentExtraField;
}
var header = "";
// version needed to extract
header += "\x0A\x00"; // general purpose bit flag
header += decToHex(bitflag, 2); // compression method
header += compression.magic; // last mod file time
header += decToHex(dosTime, 2); // last mod file date
header += decToHex(dosDate, 2); // crc-32
header += decToHex(dataInfo.crc32, 4); // compressed size
header += decToHex(dataInfo.compressedSize, 4); // uncompressed size
header += decToHex(dataInfo.uncompressedSize, 4); // file name length
header += decToHex(encodedFileName.length, 2); // extra field length
header += decToHex(extraFields.length, 2);
var fileRecord = signature.LOCAL_FILE_HEADER + header + encodedFileName + extraFields;
var dirRecord = signature.CENTRAL_FILE_HEADER + // version made by (00: DOS)
decToHex(versionMadeBy, 2) + // file header (common to file and central directory)
header + // file comment length
decToHex(encodedComment.length, 2) + // disk number start "\x00\x00" + // internal file attributes TODO "\x00\x00" + // external file attributes
decToHex(extFileAttr, 4) + // relative offset of local header
decToHex(offset, 4) + // file name
encodedFileName + // extra field
extraFields + // file comment
encodedComment;
/** * Generate the EOCD record. * @param {Number} entriesCount the number of entries in the zip file. * @param {Number} centralDirLength the length (in bytes) of the central dir. * @param {Number} localDirLength the length (in bytes) of the local dir. * @param {String} comment the zip file comment as a binary string. * @param {Function} encodeFileName the function to encode the comment. * @return {String} the EOCD record.
*/ var generateCentralDirectoryEnd = function (entriesCount, centralDirLength, localDirLength, comment, encodeFileName) { var dirEnd = ""; var encodedComment = utils.transformTo("string", encodeFileName(comment));
// end of central dir signature
dirEnd = signature.CENTRAL_DIRECTORY_END + // number of this disk "\x00\x00" + // number of the disk with the start of the central directory "\x00\x00" + // total number of entries in the central directory on this disk
decToHex(entriesCount, 2) + // total number of entries in the central directory
decToHex(entriesCount, 2) + // size of the central directory 4 bytes
decToHex(centralDirLength, 4) + // offset of start of central directory with respect to the starting disk number
decToHex(localDirLength, 4) + // .ZIP file comment length
decToHex(encodedComment.length, 2) + // .ZIP file comment
encodedComment;
return dirEnd;
};
/** * Generate data descriptors for a file entry. * @param {Object} streamInfo the hash generated by a worker, containing informations * on the file entry. * @return {String} the data descriptors.
*/ var generateDataDescriptors = function (streamInfo) { var descriptor = "";
descriptor = signature.DATA_DESCRIPTOR + // crc-32 4 bytes
decToHex(streamInfo['crc32'], 4) + // compressed size 4 bytes
decToHex(streamInfo['compressedSize'], 4) + // uncompressed size 4 bytes
decToHex(streamInfo['uncompressedSize'], 4);
return descriptor;
};
/** * A worker to concatenate other workers to create a zip file. * @param {Boolean} streamFiles `true` to stream the content of the files, * `false` to accumulate it. * @param {String} comment the comment to use. * @param {String} platform the platform to use, "UNIX" or "DOS". * @param {Function} encodeFileName the function to encode file names and comments.
*/ function ZipFileWorker(streamFiles, comment, platform, encodeFileName) {
GenericWorker.call(this, "ZipFileWorker"); // The number of bytes written so far. This doesn't count accumulated chunks. this.bytesWritten = 0; // The comment of the zip file this.zipComment = comment; // The platform "generating" the zip file. this.zipPlatform = platform; // the function to encode file names and comments. this.encodeFileName = encodeFileName; // Should we stream the content of the files ? this.streamFiles = streamFiles; // If `streamFiles` is false, we will need to accumulate the content of the // files to calculate sizes / crc32 (and write them *before* the content). // This boolean indicates if we are accumulating chunks (it will change a lot // during the lifetime of this worker). this.accumulate = false; // The buffer receiving chunks when accumulating content. this.contentBuffer = []; // The list of generated directory records. this.dirRecords = []; // The offset (in bytes) from the beginning of the zip file for the current source. this.currentSourceOffset = 0; // The total number of entries in this zip file. this.entriesCount = 0; // the name of the file currently being added, null when handling the end of the zip file. // Used for the emited metadata. this.currentFile = null;
/** * The worker started a new source (an other worker). * @param {Object} streamInfo the streamInfo object from the new source.
*/
ZipFileWorker.prototype.openedSource = function (streamInfo) { this.currentSourceOffset = this.bytesWritten; this.currentFile = streamInfo['file'].name;
var streamedContent = this.streamFiles && !streamInfo['file'].dir;
// don't stream folders (because they don't have any content) if(streamedContent) { var record = generateZipParts(streamInfo, streamedContent, false, this.currentSourceOffset, this.zipPlatform, this.encodeFileName); this.push({
data : record.fileRecord,
meta : {percent:0}
});
} else { // we need to wait for the whole file before pushing anything this.accumulate = true;
}
};
/** * The worker finished a source (an other worker). * @param {Object} streamInfo the streamInfo object from the finished source.
*/
ZipFileWorker.prototype.closedSource = function (streamInfo) { this.accumulate = false; var streamedContent = this.streamFiles && !streamInfo['file'].dir; var record = generateZipParts(streamInfo, streamedContent, true, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
this.dirRecords.push(record.dirRecord); if(streamedContent) { // after the streamed file, we put data descriptors this.push({
data : generateDataDescriptors(streamInfo),
meta : {percent:100}
});
} else { // the content wasn't streamed, we need to push everything now // first the file record, then the content this.push({
data : record.fileRecord,
meta : {percent:0}
}); while(this.contentBuffer.length) { this.push(this.contentBuffer.shift());
}
} this.currentFile = null;
};
/** * @see GenericWorker.flush
*/
ZipFileWorker.prototype.flush = function () {
var localDirLength = this.bytesWritten; for(var i = 0; i < this.dirRecords.length; i++) { this.push({
data : this.dirRecords[i],
meta : {percent:100}
});
} var centralDirLength = this.bytesWritten - localDirLength;
var dirEnd = generateCentralDirectoryEnd(this.dirRecords.length, centralDirLength, localDirLength, this.zipComment, this.encodeFileName);
this.push({
data : dirEnd,
meta : {percent:100}
});
};
/** * Prepare the next source to be read.
*/
ZipFileWorker.prototype.prepareNextSource = function () { this.previous = this._sources.shift(); this.openedSource(this.previous.streamInfo); if (this.isPaused) { this.previous.pause();
} else { this.previous.resume();
}
};
/** * @see GenericWorker.registerPrevious
*/
ZipFileWorker.prototype.registerPrevious = function (previous) { this._sources.push(previous); var self = this;
previous.on('data', function (chunk) {
self.processChunk(chunk);
});
previous.on('end', function () {
self.closedSource(self.previous.streamInfo); if(self._sources.length) {
self.prepareNextSource();
} else {
self.end();
}
});
previous.on('error', function (e) {
self.error(e);
}); returnthis;
};
var compressions = require('../compressions'); var ZipFileWorker = require('./ZipFileWorker');
/** * Find the compression to use. * @param {String} fileCompression the compression defined at the file level, if any. * @param {String} zipCompression the compression defined at the load() level. * @return {Object} the compression object to use.
*/ var getCompression = function (fileCompression, zipCompression) {
var compressionName = fileCompression || zipCompression; var compression = compressions[compressionName]; if (!compression) { thrownew Error(compressionName + " is not a valid compression method !");
} return compression;
};
/** * Create a worker to generate a zip file. * @param {JSZip} zip the JSZip instance at the right root level. * @param {Object} options to generate the zip file. * @param {String} comment the comment to use.
*/
exports.generateWorker = function (zip, options, comment) {
var zipFileWorker = new ZipFileWorker(options.streamFiles, comment, options.platform, options.encodeFileName); var entriesCount = 0; try {
zip.forEach(function (relativePath, file) {
entriesCount++; var compression = getCompression(file.options.compression, options.compression); var compressionOptions = file.options.compressionOptions || options.compressionOptions || {}; var dir = file.dir, date = file.date;
/** * Representation a of zip file in js * @constructor
*/ function JSZip() { // if this constructor is used without `new`, it adds `new` before itself: if(!(thisinstanceof JSZip)) { returnnew JSZip();
}
if(arguments.length) { thrownew Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
}
// Where we are in the hierarchy this.root = ""; this.clone = function() { var newObj = new JSZip(); for (var i in this) { if (typeofthis[i] !== "function") {
newObj[i] = this[i];
}
} return newObj;
};
}
JSZip.prototype = require('./object');
JSZip.prototype.loadAsync = require('./load');
JSZip.support = require('./support');
JSZip.defaults = require('./defaults');
// TODO find a better way to handle this version, // a require('package.json').version doesn't work with webpack, see #327
JSZip.version = "3.2.0";
JSZip.loadAsync = function (content, options) { returnnew JSZip().loadAsync(content, options);
};
},{"./defaults":5,"./external":6,"./load":11,"./object":15,"./support":30}],11:[function(require,module,exports){ 'use strict'; var utils = require('./utils'); var external = require("./external"); var utf8 = require('./utf8'); var utils = require('./utils'); var ZipEntries = require('./zipEntries'); var Crc32Probe = require('./stream/Crc32Probe'); var nodejsUtils = require("./nodejsUtils");
/** * Check the CRC32 of an entry. * @param {ZipEntry} zipEntry the zip entry to check. * @return {Promise} the result.
*/ function checkEntryCRC32(zipEntry) { returnnew external.Promise(function (resolve, reject) { var worker = zipEntry.decompressed.getContentWorker().pipe(new Crc32Probe());
worker.on("error", function (e) {
reject(e);
})
.on("end", function () { if (worker.streamInfo.crc32 !== zipEntry.decompressed.crc32) {
reject(new Error("Corrupted zip : CRC32 mismatch"));
} else {
resolve();
}
})
.resume();
});
}
if (nodejsUtils.isNode && nodejsUtils.isStream(data)) { return external.Promise.reject(new Error("JSZip can't accept a stream when loading a zip file."));
}
return utils.prepareContent("the loaded zip file", data, true, options.optimizedBinaryString, options.base64)
.then(function(data) { var zipEntries = new ZipEntries(options);
zipEntries.load(data); return zipEntries;
}).then(function checkCRC32(zipEntries) { var promises = [external.Promise.resolve(zipEntries)]; var files = zipEntries.files; if (options.checkCRC32) { for (var i = 0; i < files.length; i++) {
promises.push(checkEntryCRC32(files[i]));
}
} return external.Promise.all(promises);
}).then(function addFiles(results) { var zipEntries = results.shift(); var files = zipEntries.files; for (var i = 0; i < files.length; i++) { var input = files[i];
zip.file(input.fileNameStr, input.decompressed, {
binary: true,
optimizedBinaryString: true,
date: input.date,
dir: input.dir,
comment : input.fileCommentStr.length ? input.fileCommentStr : null,
unixPermissions : input.unixPermissions,
dosPermissions : input.dosPermissions,
createFolders: options.createFolders
});
} if (zipEntries.zipComment.length) {
zip.comment = zipEntries.zipComment;
}
var utils = require('../utils'); var GenericWorker = require('../stream/GenericWorker');
/** * A worker that use a nodejs stream as source. * @constructor * @param {String} filename the name of the file entry for this stream. * @param {Readable} stream the nodejs stream.
*/ function NodejsStreamInputAdapter(filename, stream) {
GenericWorker.call(this, "Nodejs stream input adapter for " + filename); this._upstreamEnded = false; this._bindStream(stream);
}
var Readable = require('readable-stream').Readable;
var utils = require('../utils');
utils.inherits(NodejsStreamOutputAdapter, Readable);
/** * A nodejs stream using a worker as source. * @see the SourceWrapper in http://nodejs.org/api/stream.html * @constructor * @param {StreamHelper} helper the helper wrapping the worker * @param {Object} options the nodejs stream options * @param {Function} updateCb the update callback.
*/ function NodejsStreamOutputAdapter(helper, options, updateCb) {
Readable.call(this, options); this._helper = helper;
var self = this;
helper.on("data", function (data, meta) { if (!self.push(data)) {
self._helper.pause();
} if(updateCb) {
updateCb(meta);
}
})
.on("error", function(e) {
self.emit('error', e);
})
.on("end", function () {
self.push(null);
});
}
module.exports = { /** * True if this is running in Nodejs, will be undefined in a browser. * In a browser, browserify won't include this file and the whole module * will be resolved an empty object.
*/
isNode : typeof Buffer !== "undefined", /** * Create a new nodejs Buffer from an existing content. * @param {Object} data the data to pass to the constructor. * @param {String} encoding the encoding to use. * @return {Buffer} a new Buffer.
*/
newBufferFrom: function(data, encoding) { if (Buffer.from && Buffer.from !== Uint8Array.from) { return Buffer.from(data, encoding);
} else { if (typeof data === "number") { // Safeguard for old Node.js versions. On newer versions, // Buffer.from(number) / Buffer(number, encoding) already throw. thrownew Error("The \"data\" argument must not be a number");
} returnnew Buffer(data, encoding);
}
}, /** * Create a new nodejs Buffer with the specified size. * @param {Integer} size the size of the buffer. * @return {Buffer} a new Buffer.
*/
allocBuffer: function (size) { if (Buffer.alloc) { return Buffer.alloc(size);
} else { var buf = new Buffer(size);
buf.fill(0); return buf;
}
}, /** * Find out if an object is a Buffer. * @param {Object} b the object to test. * @return {Boolean} true if the object is a Buffer, false otherwise.
*/
isBuffer : function(b){ return Buffer.isBuffer(b);
},
},{}],15:[function(require,module,exports){ '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();
}
var zipObjectContent = null; if (data instanceof CompressedObject || data instanceof GenericWorker) {
zipObjectContent = data;
} elseif (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 ?
/** * 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; for (filename in this.files) { if (!this.files.hasOwnProperty(filename)) { continue; } 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; }
// 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; },
/** * Generate the complete zip file * @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 {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file */ generate: function(options) { 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 });
},{"./compressedObject":2,"./defaults":5,"./generate":9,"./nodejs/NodejsStreamInputAdapter":12,"./nodejsUtils":14,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31,"./utils":32,"./zipObject":35}],16:[function(require,module,exports){ /* * This file is used by module bundlers (browserify/webpack/etc) when * including a stream implementation. We use "readable-stream" to get a * consistent behavior between nodejs versions but bundlers often have a shim * for "stream". Using this shim greatly improve the compatibility and greatly * reduce the final size of the bundle (only one stream implementation, not * two). */ module.exports = require("stream");
},{"stream":undefined}],17:[function(require,module,exports){ 'use strict'; var DataReader = require('./DataReader'); var utils = require('../utils');
},{"../utils":32,"./DataReader":18}],18:[function(require,module,exports){ 'use strict'; var utils = require('../utils');
function DataReader(data) { this.data = data; // type : see implementation this.length = data.length; this.index = 0; this.zero = 0; } DataReader.prototype = { /** * Check that the offset will not go too far. * @param {string} offset the additional offset to check. * @throws {Error} an Error if the offset is out of bounds. */ checkOffset: function(offset) { this.checkIndex(this.index + offset); }, /** * Check that the specified index will not be too far. * @param {string} newIndex the index to check. * @throws {Error} an Error if the index is out of bounds. */ checkIndex: function(newIndex) { if (this.length < this.zero + newIndex || newIndex < 0) { throw new Error("End of data reached (data length = " + this.length + ", asked index = " + (newIndex) + "). Corrupted zip ?"); } }, /** * Change the index. * @param {number} newIndex The new index. * @throws {Error} if the new index is out of the data. */ setIndex: function(newIndex) { this.checkIndex(newIndex); this.index = newIndex; }, /** * Skip the next n bytes. * @param {number} n the number of bytes to skip. * @throws {Error} if the new index is out of the data. */ skip: function(n) { this.setIndex(this.index + n); }, /** * Get the byte at the specified index. * @param {number} i the index to use. * @return {number} a byte. */ byteAt: function(i) { // see implementations }, /** * Get the next number with a given byte size. * @param {number} size the number of bytes to read. * @return {number} the corresponding number. */ readInt: function(size) { var result = 0, i; this.checkOffset(size); for (i = this.index + size - 1; i >= this.index; i--) { result = (result << 8) + this.byteAt(i); } this.index += size; return result; }, /** * Get the next string with a given byte size. * @param {number} size the number of bytes to read. * @return {string} the corresponding string. */ readString: function(size) { return utils.transformTo("string", this.readData(size)); }, /** * Get raw data without conversion, <size> bytes. * @param {number} size the number of bytes to read. * @return {Object} the raw data, implementation specific. */ readData: function(size) { // see implementations }, /** * Find the last occurence of a zip signature (4 bytes). * @param {string} sig the signature to find. * @return {number} the index of the last occurence, -1 if not found. */ lastIndexOfSignature: function(sig) { // see implementations }, /** * Read the signature (4 bytes) at the current position and compare it with sig. * @param {string} sig the expected signature * @return {boolean} true if the signature matches, false otherwise. */ readAndCheckSignature: function(sig) { // see implementations }, /** * Get the next date. * @return {Date} the date. */ readDate: function() { var dostime = this.readInt(4); return new Date(Date.UTC( ((dostime >> 25) & 0x7f) + 1980, // year ((dostime >> 21) & 0x0f) - 1, // month (dostime >> 16) & 0x1f, // day (dostime >> 11) & 0x1f, // hour (dostime >> 5) & 0x3f, // minute (dostime & 0x1f) << 1)); // second } }; module.exports = DataReader;
},{"../utils":32}],19:[function(require,module,exports){ 'use strict'; var Uint8ArrayReader = require('./Uint8ArrayReader'); var utils = require('../utils');
function NodeBufferReader(data) { Uint8ArrayReader.call(this, data); } utils.inherits(NodeBufferReader, Uint8ArrayReader);
var utils = require('../utils'); var support = require('../support'); var ArrayReader = require('./ArrayReader'); var StringReader = require('./StringReader'); var NodeBufferReader = require('./NodeBufferReader'); var Uint8ArrayReader = require('./Uint8ArrayReader');
/** * Create a reader adapted to the data. * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data to read. * @return {DataReader} the data reader. */ module.exports = function (data) { var type = utils.getTypeOf(data); utils.checkSupport(type); if (type === "string" && !support.uint8array) { return new StringReader(data); } if (type === "nodebuffer") { return new NodeBufferReader(data); } if (support.uint8array) { return new Uint8ArrayReader(utils.transformTo("uint8array", data)); } return new ArrayReader(utils.transformTo("array", data)); };
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.