Socket
Socket
Sign inDemoInstall

yauzl

Package Overview
Dependencies
Maintainers
2
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

yauzl - npm Package Compare versions

Comparing version 2.3.1 to 2.4.0

338

index.js

@@ -8,2 +8,3 @@ var fs = require("fs");

var PassThrough = require("stream").PassThrough;
var Writable = require("stream").Writable;

@@ -13,10 +14,8 @@ exports.open = open;

exports.fromBuffer = fromBuffer;
exports.fromRandomAccessReader = fromRandomAccessReader;
exports.dosDateTimeToDate = dosDateTimeToDate;
exports.ZipFile = ZipFile;
exports.Entry = Entry;
exports.dosDateTimeToDate = dosDateTimeToDate;
exports.RandomAccessReader = RandomAccessReader;
// cd - Central Directory
// cdr - Central Directory Record
// eocdr - End of Central Directory Record
function open(path, options, callback) {

@@ -27,3 +26,5 @@ if (typeof options === "function") {

}
if (options == null) options = {autoClose: true};
if (options == null) options = {};
if (options.autoClose == null) options.autoClose = true;
if (options.lazyEntries == null) options.lazyEntries = false;
if (callback == null) callback = defaultCallback;

@@ -44,20 +45,44 @@ fs.open(path, "r", function(err, fd) {

}
if (options == null) options = {autoClose: false};
if (options == null) options = {};
if (options.autoClose == null) options.autoClose = false;
if (options.lazyEntries == null) options.lazyEntries = false;
if (callback == null) callback = defaultCallback;
fs.fstat(fd, function(err, stats) {
if (err) return callback(err);
var fdSlicer = fd_slicer.createFromFd(fd, {autoClose: true});
// this ref is unreffed in zipfile.close()
fdSlicer.ref();
fromFdSlicer(fdSlicer, stats.size, options, callback);
var reader = fd_slicer.createFromFd(fd, {autoClose: true});
fromRandomAccessReader(reader, stats.size, options, callback);
});
}
function fromBuffer(buffer, callback) {
if (callback == null) callback = defaultCallback;
function fromBuffer(buffer, options, callback) {
if (typeof options === "function") {
callback = options;
options = null;
}
if (options == null) options = {};
options.autoClose = false;
if (options.lazyEntries == null) options.lazyEntries = false;
// i got your open file right here.
var fdSlicer = fd_slicer.createFromBuffer(buffer);
fromFdSlicer(fdSlicer, buffer.length, {}, callback);
var reader = fd_slicer.createFromBuffer(buffer);
fromRandomAccessReader(reader, buffer.length, options, callback);
}
function fromFdSlicer(fdSlicer, totalSize, options, callback) {
function fromRandomAccessReader(reader, totalSize, options, callback) {
if (typeof options === "function") {
callback = options;
options = null;
}
if (options == null) options = {};
if (options.autoClose == null) options.autoClose = true;
if (options.lazyEntries == null) options.lazyEntries = false;
if (callback == null) callback = defaultCallback;
if (typeof totalSize !== "number") throw new Error("expected totalSize parameter to be a number");
if (totalSize > Number.MAX_SAFE_INTEGER) {
throw new Error("zip file too large. only file sizes up to 2^52 are supported due to JavaScript's Number type being an IEEE 754 double.");
}
// the matching unref() call is in zipfile.close()
reader.ref();
// eocdr means End of Central Directory Record.
// search backwards for the eocdr signature.

@@ -73,3 +98,3 @@ // the last field of the eocdr is a variable-length comment.

var bufferReadStart = totalSize - buffer.length;
readFdSlicerNoEof(fdSlicer, buffer, 0, bufferSize, bufferReadStart, function(err) {
readAndAssertNoEof(reader, buffer, 0, bufferSize, bufferReadStart, function(err) {
if (err) return callback(err);

@@ -91,3 +116,3 @@ for (var i = bufferSize - eocdrWithoutCommentSize; i >= 0; i -= 1) {

// 16 - Offset of start of central directory, relative to start of archive
var cdOffset = eocdrBuffer.readUInt32LE(16);
var centralDirectoryOffset = eocdrBuffer.readUInt32LE(16);
// 20 - Comment length

@@ -102,3 +127,47 @@ var commentLength = eocdrBuffer.readUInt16LE(20);

var comment = bufferToString(eocdrBuffer, 22, eocdrBuffer.length, false);
return callback(null, new ZipFile(fdSlicer, cdOffset, totalSize, entryCount, comment, options.autoClose));
if (!(entryCount === 0xffff || centralDirectoryOffset === 0xffffffff)) {
return callback(null, new ZipFile(reader, centralDirectoryOffset, totalSize, entryCount, comment, options.autoClose, options.lazyEntries));
}
// ZIP64 format
// ZIP64 Zip64 end of central directory locator
var zip64EocdlBuffer = new Buffer(20);
var zip64EocdlOffset = bufferReadStart + i - zip64EocdlBuffer.length;
readAndAssertNoEof(reader, zip64EocdlBuffer, 0, zip64EocdlBuffer.length, zip64EocdlOffset, function(err) {
if (err) return callback(err);
// 0 - zip64 end of central dir locator signature = 0x07064b50
if (zip64EocdlBuffer.readUInt32LE(0) !== 0x07064b50) {
return callback(new Error("invalid ZIP64 End of Central Directory Locator signature"));
}
// 4 - number of the disk with the start of the zip64 end of central directory
// 8 - relative offset of the zip64 end of central directory record
var zip64EocdrOffset = readUInt64LE(zip64EocdlBuffer, 8);
// 16 - total number of disks
// ZIP64 end of central directory record
var zip64EocdrBuffer = new Buffer(56);
readAndAssertNoEof(reader, zip64EocdrBuffer, 0, zip64EocdrBuffer.length, zip64EocdrOffset, function(err) {
if (err) return callback(err);
// 0 - zip64 end of central dir signature 4 bytes (0x06064b50)
if (zip64EocdrBuffer.readUInt32LE(0) !== 0x06064b50) return callback(new Error("invalid ZIP64 end of central directory record signature"));
// 4 - size of zip64 end of central directory record 8 bytes
// 12 - version made by 2 bytes
// 14 - version needed to extract 2 bytes
// 16 - number of this disk 4 bytes
// 20 - number of the disk with the start of the central directory 4 bytes
// 24 - total number of entries in the central directory on this disk 8 bytes
// 32 - total number of entries in the central directory 8 bytes
entryCount = readUInt64LE(zip64EocdrBuffer, 32);
// 40 - size of the central directory 8 bytes
// 48 - offset of start of central directory with respect to the starting disk number 8 bytes
centralDirectoryOffset = readUInt64LE(zip64EocdrBuffer, 48);
// 56 - zip64 extensible data sector (variable size)
return callback(null, new ZipFile(reader, centralDirectoryOffset, totalSize, entryCount, comment, options.autoClose, options.lazyEntries));
});
});
return;
}

@@ -110,15 +179,15 @@ callback(new Error("end of central directory record signature not found"));

util.inherits(ZipFile, EventEmitter);
function ZipFile(fdSlicer, cdOffset, fileSize, entryCount, comment, autoClose) {
function ZipFile(reader, centralDirectoryOffset, fileSize, entryCount, comment, autoClose, lazyEntries) {
var self = this;
EventEmitter.call(self);
self.fdSlicer = fdSlicer;
self.reader = reader;
// forward close events
self.fdSlicer.on("error", function(err) {
self.reader.on("error", function(err) {
// error closing the fd
emitError(self, err);
});
self.fdSlicer.once("close", function() {
self.reader.once("close", function() {
self.emit("close");
});
self.readEntryCursor = cdOffset;
self.readEntryCursor = centralDirectoryOffset;
self.fileSize = fileSize;

@@ -129,6 +198,7 @@ self.entryCount = entryCount;

self.autoClose = !!autoClose;
self.lazyEntries = !!lazyEntries;
self.isOpen = true;
self.emittedError = false;
// make sure events don't fire outta here until the client has a chance to attach listeners
setImmediate(function() { readEntries(self); });
if (!self.lazyEntries) self.readEntry();
}

@@ -138,3 +208,3 @@ ZipFile.prototype.close = function() {

this.isOpen = false;
this.fdSlicer.unref();
this.reader.unref();
};

@@ -152,12 +222,16 @@

function readEntries(self) {
ZipFile.prototype.readEntry = function() {
var self = this;
if (self.entryCount === self.entriesRead) {
// done with metadata
if (self.autoClose) self.close();
if (self.emittedError) return;
return self.emit("end");
setImmediate(function() {
if (self.autoClose) self.close();
if (self.emittedError) return;
self.emit("end");
});
return;
}
if (self.emittedError) return;
var buffer = new Buffer(46);
readFdSlicerNoEof(self.fdSlicer, buffer, 0, buffer.length, self.readEntryCursor, function(err) {
readAndAssertNoEof(self.reader, buffer, 0, buffer.length, self.readEntryCursor, function(err) {
if (err) return emitErrorAndAutoClose(self, err);

@@ -203,10 +277,4 @@ if (self.emittedError) return;

// validate file size
if (entry.compressionMethod === 0) {
var msg = "compressed/uncompressed size mismatch for stored file: " + entry.compressedSize + " != " + entry.uncompressedSize;
if (entry.compressedSize !== entry.uncompressedSize) return emitErrorAndAutoClose(self, new Error(msg));
}
buffer = new Buffer(entry.fileNameLength + entry.extraFieldLength + entry.fileCommentLength);
readFdSlicerNoEof(self.fdSlicer, buffer, 0, buffer.length, self.readEntryCursor, function(err) {
readAndAssertNoEof(self.reader, buffer, 0, buffer.length, self.readEntryCursor, function(err) {
if (err) return emitErrorAndAutoClose(self, err);

@@ -251,2 +319,46 @@ if (self.emittedError) return;

if (entry.uncompressedSize === 0xffffffff ||
entry.compressedSize === 0xffffffff ||
entry.relativeOffsetOfLocalHeader === 0xffffffff) {
// ZIP64 format
// find the Zip64 Extended Information Extra Field
var zip64EiefBuffer = null;
for (var i = 0; i < entry.extraFields.length; i++) {
var extraField = entry.extraFields[i];
if (extraField.id === 0x0001) {
zip64EiefBuffer = extraField.data;
break;
}
}
if (zip64EiefBuffer == null) return emitErrorAndAutoClose(self, new Error("expected Zip64 Extended Information Extra Field"));
var index = 0;
// 0 - Original Size 8 bytes
if (entry.uncompressedSize === 0xffffffff) {
if (index + 8 > zip64EiefBuffer.length) return emitErrorAndAutoClose(self, new Error("Zip64 Extended Information Extra Field does not include Original Size"));
entry.uncompressedSize = readUInt64LE(zip64EiefBuffer, index);
index += 8;
}
// 8 - Compressed Size 8 bytes
if (entry.compressedSize === 0xffffffff) {
if (index + 8 > zip64EiefBuffer.length) return emitErrorAndAutoClose(self, new Error("Zip64 Extended Information Extra Field does not include Compressed Size"));
entry.compressedSize = readUInt64LE(zip64EiefBuffer, index);
index += 8;
}
// 16 - Relative Header Offset 8 bytes
if (entry.relativeOffsetOfLocalHeader === 0xffffffff) {
if (index + 8 > zip64EiefBuffer.length) return emitErrorAndAutoClose(self, new Error("Zip64 Extended Information Extra Field does not include Relative Header Offset"));
entry.relativeOffsetOfLocalHeader = readUInt64LE(zip64EiefBuffer, index);
index += 8;
}
// 24 - Disk Start Number 4 bytes
}
// validate file size
if (entry.compressionMethod === 0) {
if (entry.compressedSize !== entry.uncompressedSize) {
var msg = "compressed/uncompressed size mismatch for stored file: " + entry.compressedSize + " != " + entry.uncompressedSize;
return emitErrorAndAutoClose(self, new Error(msg));
}
}
// validate file name

@@ -257,6 +369,7 @@ if (entry.fileName.indexOf("\\") !== -1) return emitErrorAndAutoClose(self, new Error("invalid characters in fileName: " + entry.fileName));

self.emit("entry", entry);
readEntries(self);
if (!self.lazyEntries) self.readEntry();
});
});
}
};

@@ -267,5 +380,5 @@ ZipFile.prototype.openReadStream = function(entry, callback) {

// make sure we don't lose the fd before we open the actual read stream
self.fdSlicer.ref();
self.reader.ref();
var buffer = new Buffer(30);
readFdSlicerNoEof(self.fdSlicer, buffer, 0, buffer.length, entry.relativeOffsetOfLocalHeader, function(err) {
readAndAssertNoEof(self.reader, buffer, 0, buffer.length, entry.relativeOffsetOfLocalHeader, function(err) {
try {

@@ -313,15 +426,28 @@ if (err) return callback(err);

}
var stream = self.fdSlicer.createReadStream({start: fileDataStart, end: fileDataEnd});
var readStream = self.reader.createReadStream({start: fileDataStart, end: fileDataEnd});
var endpointStream = readStream;
if (compressed) {
var deflateFilter = zlib.createInflateRaw();
var destroyed = false;
var inflateFilter = zlib.createInflateRaw();
readStream.on("error", function(err) {
if (!destroyed) inflateFilter.emit("error", err);
});
var checkerStream = new AssertByteCountStream(entry.uncompressedSize);
deflateFilter.on("error", function(err) {
inflateFilter.on("error", function(err) {
// forward zlib errors to the client-visible stream
checkerStream.emit("error", err);
if (!destroyed) checkerStream.emit("error", err);
});
stream = stream.pipe(deflateFilter).pipe(checkerStream);
checkerStream.destroy = function() {
destroyed = true;
inflateFilter.unpipe(checkerStream);
readStream.unpipe(inflateFilter);
// TODO: the inflateFilter now causes a memory leak. see Issue #27.
readStream.destroy();
};
endpointStream = readStream.pipe(inflateFilter).pipe(checkerStream);
}
callback(null, stream);
callback(null, endpointStream);
} finally {
self.fdSlicer.unref();
self.reader.unref();
}

@@ -350,3 +476,3 @@ });

function readFdSlicerNoEof(fdSlicer, buffer, offset, length, position, callback) {
function readAndAssertNoEof(reader, buffer, offset, length, position, callback) {
if (length === 0) {

@@ -356,3 +482,3 @@ // fs.read will throw an out-of-bounds error if you try to read 0 bytes from a 0 byte file

}
fdSlicer.read(buffer, offset, length, position, function(err, bytesRead) {
reader.read(buffer, offset, length, position, function(err, bytesRead) {
if (err) return callback(err);

@@ -386,2 +512,98 @@ if (bytesRead < length) return callback(new Error("unexpected EOF"));

util.inherits(RandomAccessReader, EventEmitter);
function RandomAccessReader() {
EventEmitter.call(this);
this.refCount = 0;
}
RandomAccessReader.prototype.ref = function() {
this.refCount += 1;
};
RandomAccessReader.prototype.unref = function() {
var self = this;
self.refCount -= 1;
if (self.refCount > 0) return;
if (self.refCount < 0) throw new Error("invalid unref");
self.close(onCloseDone);
function onCloseDone(err) {
if (err) return self.emit('error', err);
self.emit('close');
}
};
RandomAccessReader.prototype.createReadStream = function(options) {
var start = options.start;
var end = options.end;
if (start === end) {
var emptyStream = new PassThrough();
setImmediate(function() {
emptyStream.end();
});
return emptyStream;
}
var stream = this._readStreamForRange(start, end);
var destroyed = false;
var refUnrefFilter = new RefUnrefFilter(this);
stream.on("error", function(err) {
if (!destroyed) refUnrefFilter.emit("error", err);
});
refUnrefFilter.destroy = function() {
stream.unpipe(refUnrefFilter);
refUnrefFilter.unref();
stream.destroy();
};
var byteCounter = new AssertByteCountStream(end - start);
refUnrefFilter.on("error", function(err) {
if (!destroyed) byteCounter.emit("error", err);
});
byteCounter.destroy = function() {
destroyed = true;
refUnrefFilter.unpipe(byteCounter);
refUnrefFilter.destroy();
};
return stream.pipe(refUnrefFilter).pipe(byteCounter);
};
RandomAccessReader.prototype._readStreamForRange = function(start, end) {
throw new Error("not implemented");
};
RandomAccessReader.prototype.read = function(buffer, offset, length, position, callback) {
var readStream = this.createReadStream({start: position, end: position + length});
var writeStream = new Writable();
var written = 0;
writeStream._write = function(chunk, encoding, cb) {
chunk.copy(buffer, offset + written, 0, chunk.length);
written += chunk.length;
cb();
};
writeStream.on("finish", callback);
readStream.on("error", function(error) {
callback(error);
});
readStream.pipe(writeStream);
};
RandomAccessReader.prototype.close = function(callback) {
setImmediate(callback);
};
util.inherits(RefUnrefFilter, PassThrough);
function RefUnrefFilter(context) {
PassThrough.call(this);
this.context = context;
this.context.ref();
this.unreffedYet = false;
}
RefUnrefFilter.prototype._flush = function(cb) {
this.unref();
cb();
};
RefUnrefFilter.prototype.unref = function(cb) {
if (this.unreffedYet) return;
this.unreffedYet = true;
this.context.unref();
};
var cp437 = '\u0000☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ';

@@ -400,4 +622,16 @@ function bufferToString(buffer, start, end, isUtf8) {

function readUInt64LE(buffer, offset) {
// there is no native function for this, because we can't actually store 64-bit integers precisely.
// after 53 bits, JavaScript's Number type (IEEE 754 double) can't store individual integers anymore.
// but since 53 bits is a whole lot more than 32 bits, we do our best anyway.
var lower32 = buffer.readUInt32LE(offset);
var upper32 = buffer.readUInt32LE(offset + 4);
// we can't use bitshifting here, because JavaScript bitshifting only works on 32-bit integers.
return upper32 * 0x100000000 + lower32;
// as long as we're bounds checking the result of this function against the total file size,
// we'll catch any overflow errors, because we already made sure the total file size was within reason.
}
function defaultCallback(err) {
if (err) throw err;
}

9

package.json
{
"name": "yauzl",
"version": "2.3.1",
"version": "2.4.0",
"description": "yet another unzip library for node",

@@ -29,8 +29,9 @@ "main": "index.js",

"dependencies": {
"fd-slicer": "~1.0.1",
"pend": "~1.2.0"
"fd-slicer": "~1.0.1"
},
"devDependencies": {
"istanbul": "~0.3.4"
"bl": "~1.0.0",
"istanbul": "~0.3.4",
"pend": "~1.2.0"
}
}

@@ -30,15 +30,29 @@ # yauzl

var fs = require("fs");
var path = require("path");
var mkdirp = require("mkdirp"); // or similar
yauzl.open("path/to/file.zip", function(err, zipfile) {
yauzl.open("path/to/file.zip", {lazyEntries: true}, function(err, zipfile) {
if (err) throw err;
zipfile.readEntry();
zipfile.on("entry", function(entry) {
if (/\/$/.test(entry.fileName)) {
// directory file names end with '/'
return;
mkdirp(entry.fileName, function(err) {
if (err) throw err;
zipfile.readEntry();
});
} else {
// file entry
zipfile.openReadStream(entry, function(err, readStream) {
if (err) throw err;
// ensure parent directory exists
mkdirp(path.dirname(entry.fileName), function(err) {
if (err) throw err;
readStream.pipe(fs.createWriteStream(entry.fileName));
readStream.on("end", function() {
zipfile.readEntry();
});
});
});
}
zipfile.openReadStream(entry, function(err, readStream) {
if (err) throw err;
// ensure parent directory exists, and then:
readStream.pipe(fs.createWriteStream(entry.fileName));
});
});

@@ -50,3 +64,3 @@ });

The default for every `callback` parameter is:
The default for every optional `callback` parameter is:

@@ -63,4 +77,20 @@ ```js

`options` may be omitted or `null` and defaults to `{autoClose: true}`.
`options` may be omitted or `null`. The defaults are `{autoClose: true, lazyEntries: false}`.
`autoClose` is effectively equivalent to:
```js
zipfile.once("end", function() {
zipfile.close();
});
```
`lazyEntries` indicates that entries should be read only when `readEntry()` is called.
If `lazyEntries` is `false`, `entry` events will be emitted as fast as possible to allow `pipe()`ing
file data from all entries in parallel.
This is not recommended, as it can lead to out of control memory usage for zip files with many entries.
See [issue #22](https://github.com/thejoshwolfe/yauzl/issues/22).
If `lazyEntries` is `true`, an `entry` or `end` event will be emitted in response to each call to `readEntry()`.
This allows processing of one entry at a time, and will keep memory usage under control for zip files with many entries.
### fromFd(fd, [options], [callback])

@@ -77,13 +107,7 @@

`options` may be omitted or `null` and defaults to `{autoClose: false}`.
`autoClose` is effectively equivalent to:
`options` may be omitted or `null`. The defaults are `{autoClose: false, lazyEntries: false}`.
See `open()` for the meaning of the options.
```js
zipfile.once("end", function() {
zipfile.close();
});
```
### fromBuffer(buffer, [options], [callback])
### fromBuffer(buffer, [callback])
Like `fromFd()`, but reads from a RAM buffer instead of an open file.

@@ -97,2 +121,18 @@ `buffer` is a `Buffer`.

`options` may be omitted or `null`. The defaults are `{lazyEntries: false}`.
See `open()` for the meaning of the options.
The `autoClose` option is ignored for this method.
### fromRandomAccessReader(reader, totalSize, [options], [callback])
This method of creating a zip file allows clients to implement their own back-end file system.
For example, a client might translate read calls into network requests.
The `reader` parameter must be of a type that is a subclass of
[RandomAccessReader](#class-randomaccessreader) that implements the required methods.
The `totalSize` is a Number and indicates the total file size of the zip file.
`options` may be omitted or `null`. The defaults are `{autoClose: true, lazyEntries: false}`.
See `open()` for the meaning of the options.
### dosDateTimeToDate(date, time)

@@ -108,3 +148,3 @@

The constructor for the class is not part of the public API.
Use `open()`, `fromFd()`, or `fromBuffer()` instead.
Use `open()`, `fromFd()`, `fromBuffer()`, or `fromRandomAccessReader()` instead.

@@ -114,2 +154,3 @@ #### Event: "entry"

Callback gets `(entry)`, which is an `Entry`.
See `open()` and `readEntry()` for when this event is emitted.

@@ -119,2 +160,3 @@ #### Event: "end"

Emitted after the last `entry` event has been emitted.
See `open()` and `readEntry()` for more info on when this event is emitted.

@@ -125,6 +167,9 @@ #### Event: "close"

This is after calling `close()` (or after the `end` event when `autoClose` is `true`),
and after all streams created from `openReadStream()` have emitted their `end` events.
and after all stream pipelines created from `openReadStream()` have finished reading data from the fd.
This event is never emitted if this `ZipFile` was acquired from `fromBuffer()`.
If this `ZipFile` was acquired from `fromRandomAccessReader()`,
the "fd" in the previous paragraph refers to the `RandomAccessReader` implemented by the client.
If this `ZipFile` was acquired from `fromBuffer()`, this event is never emitted.
#### Event: "error"

@@ -137,4 +182,18 @@

#### openReadStream(entry, [callback])
#### readEntry()
Causes this `ZipFile` to emit an `entry` or `end` event (or an `error` event).
This method must only be called when this `ZipFile` was created with the `lazyEntries` option set to `true` (see `open()`).
When this `ZipFile` was created with the `lazyEntries` option set to `true`,
`entry` and `end` events are only ever emitted in response to this method call.
The event that is emitted in response to this method will not be emitted until after this method has returned,
so it is safe to call this method before attaching event listeners.
After calling this method, calling this method again before the response event has been emitted will cause undefined behavior.
Calling this method after the `end` event has been emitted will cause undefined behavior.
Calling this method after calling `close()` will cause undefined behavior.
#### openReadStream(entry, callback)
`entry` must be an `Entry` object from this `ZipFile`.

@@ -146,3 +205,3 @@ `callback` gets `(err, readStream)`, where `readStream` is a `Readable Stream`.

It's possible for the `readStream` to emit errors for several reasons.
It's possible for the `readStream` it to emit errors for several reasons.
For example, if zlib cannot decompress the data, the zlib error will be emitted from the `readStream`.

@@ -160,2 +219,9 @@ Two more error cases are if the decompressed data has too many or too few actual bytes

It is possible to destroy the `readStream` before it has piped all of its data.
To do this, call `readStream.destroy()`.
You must `unpipe()` the `readStream` from any destination before calling `readStream.destroy()`.
If this zipfile was created using `fromRandomAccessReader()`, the `RandomAccessReader` implementation
must provide readable streams that implement a `.destroy()` method (see `randomAccessReader._readStreamForRange()`)
in order for calls to `readStream.destroy()` to work in this context.
#### close()

@@ -165,7 +231,14 @@

and closes the fd after all streams created by `openReadStream()` have emitted their `end` events.
If this object's `end` event has not been emitted yet, this function causes undefined behavior.
If `autoClose` is `true` in the original `open()` or `fromFd()` call,
If the `autoClose` option is set to `true` (see `open()`),
this function will be called automatically effectively in response to this object's `end` event.
If the `lazyEntries` option is set to `false` (see `open()`) and this object's `end` event has not been emitted yet,
this function causes undefined behavior.
If the `lazyEntries` option is set to `true`,
you can call this function instead of calling `readEntry()` to abort reading the entries of a zipfile.
It is safe to call this function multiple times; after the first call, successive calls have no effect.
This includes situations where the `autoClose` option effectively calls this function for you.
#### isOpen

@@ -219,3 +292,5 @@

where `id` is a `Number` and `data` is a `Buffer`.
None of the extra fields are considered significant by this library.
This library looks for and reads the ZIP64 Extended Information Extra Field (0x0001)
in order to support ZIP64 format zip files.
None of the other fields are considered significant by this library.

@@ -234,2 +309,49 @@ #### comment

### Class: RandomAccessReader
This class is meant to be subclassed by clients and instantiated for the `fromRandomAccessReader()` function.
An example implementation can be found in `test/test.js`.
#### randomAccessReader._readStreamForRange(start, end)
Subclasses *must* implement this method.
`start` and `end` are Numbers and indicate byte offsets from the start of the file.
`end` is exclusive, so `_readStreamForRange(0x1000, 0x2000)` would indicate to read `0x1000` bytes.
`end - start` will always be at least `1`.
This method should return a readable stream which will be `pipe()`ed into another stream.
It is expected that the readable stream will provide data in several chunks if necessary.
If the readable stream provides too many or too few bytes, an error will be emitted.
Any errors emitted on the readable stream will be handled and re-emitted on the client-visible stream
(returned from `zipfile.openReadStream()`) or provided as the `err` argument to the appropriate callback
(for example, for `fromRandomAccessReader()`).
The returned stream *must* implement a method `.destroy()`
if you call `readStream.destroy()` on streams you get from `openReadStream()`.
If you never call `readStream.destroy()`, then streams returned from this method do not need to implement a method `.destroy()`.
`.destroy()` should abort any streaming that is in progress and clean up any associated resources.
`.destroy()` will only be called after the stream has been `unpipe()`d from its destination.
Note that the stream returned from this method might not be the same object that is provided by `openReadStream()`.
The stream returned from this method might be `pipe()`d through one or more filter streams (for example, a zlib inflate stream).
#### randomAccessReader.read(buffer, offset, length, position, callback)
Subclasses may implement this method.
The default implementation uses `createReadStream()` to fill the `buffer`.
This method should behave like `fs.read()`.
#### randomAccessReader.close(callback)
Subclasses may implement this method.
The default implementation is effectively `setImmediate(callback);`.
`callback` takes parameters `(err)`.
This method is called once the all streams returned from `_readStreamForRange()` have ended,
and no more `_readStreamForRange()` or `read()` requests will be issued to this object.
## How to Avoid Crashing

@@ -242,3 +364,3 @@

* Provide `callback` parameters where they are allowed, and check the `err` parameter.
* Attach a listener for the `error` event on any `ZipFile` object you get from `open()`, `fromFd()`, or `fromBuffer()`.
* Attach a listener for the `error` event on any `ZipFile` object you get from `open()`, `fromFd()`, `fromBuffer()`, or `fromRandomAccessReader()`.
* Attach a listener for the `error` event on any stream you get from `openReadStream()`.

@@ -262,2 +384,16 @@

### Limitted ZIP64 Support
For ZIP64, only zip files smaller than `8PiB` are supported,
not the full `16EiB` range that a 64-bit integer should be able to index.
This is due to the JavaScript Number type being an IEEE 754 double precision float.
The Node.js `fs` module probably has this same limitation.
### ZIP64 Extensible Data Sector Is Ignored
The spec does not allow zip file creators to put arbitrary data here,
but rather reserves its use for PKWARE and mentions something about Z390.
This doesn't seem useful to expose in this library, so it is ignored.
### No Multi-Disk Archive Support

@@ -269,3 +405,3 @@

If the "number of this disk" field in the End of Central Directory Record is not `0`,
the `open()`, `fromFd()`, or `fromBuffer()` `callback` will receive an `err`.
the `open()`, `fromFd()`, `fromBuffer()`, or `fromRandomAccessReader()` `callback` will receive an `err`.
By extension the following zip file fields are ignored by this library and not provided to clients:

@@ -306,6 +442,2 @@

### No ZIP64 Support
A ZIP64 file will probably cause undefined behavior.
### Data Descriptors Are Ignored

@@ -326,1 +458,28 @@

This library makes no attempt to interpret the Language Encoding Flag.
## Change History
* 2.4.0
* Add ZIP64 support. [issue #6](https://github.com/thejoshwolfe/yazl/issues/6)
* Add `lazyEntries` option. [issue #22](https://github.com/thejoshwolfe/yazl/issues/22)
* Add `readStream.destroy()` method. [issue #26](https://github.com/thejoshwolfe/yazl/issues/26)
* Add `fromRandomAccessReader()`. [issue #14](https://github.com/thejoshwolfe/yazl/issues/14)
* Add `examples/unzip.js`.
* 2.3.1
* Documentation updates.
* 2.3.0
* Check that `uncompressedSize` is correct, or else emit an error. [issue #13](https://github.com/thejoshwolfe/yazl/issues/13)
* 2.2.1
* Update dependencies.
* 2.2.0
* Update dependencies.
* 2.1.0
* Remove dependency on `iconv`.
* 2.0.3
* Fix crash when trying to read a 0-byte file.
* 2.0.2
* Fix event behavior after errors.
* 2.0.1
* Fix bug with using `iconv`.
* 2.0.0
* Initial release.

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc