Comparing version 1.1.1 to 2.0.0
138
index.js
@@ -6,6 +6,8 @@ var fs = require("fs"); | ||
var EventEmitter = require("events").EventEmitter; | ||
var PassThrough = require("stream").PassThrough; | ||
var Iconv = require("iconv").Iconv; | ||
exports.open = open; | ||
exports.fopen = fopen; | ||
exports.fromFd = fromFd; | ||
exports.fromBuffer = fromBuffer; | ||
exports.ZipFile = ZipFile; | ||
@@ -28,3 +30,3 @@ exports.Entry = Entry; | ||
if (err) return callback(err); | ||
fopen(fd, options, function(err, zipfile) { | ||
fromFd(fd, options, function(err, zipfile) { | ||
if (err) fs.close(fd, defaultCallback); | ||
@@ -36,3 +38,3 @@ callback(err, zipfile); | ||
function fopen(fd, options, callback) { | ||
function fromFd(fd, options, callback) { | ||
if (typeof options === "function") { | ||
@@ -46,43 +48,56 @@ callback = options; | ||
if (err) return callback(err); | ||
// search backwards for the eocdr signature. | ||
// the last field of the eocdr is a variable-length comment. | ||
// the comment size is encoded in a 2-byte field in the eocdr, which we can't find without trudging backwards through the comment to find it. | ||
// as a consequence of this design decision, it's possible to have ambiguous zip file metadata if a coherent eocdr was in the comment. | ||
// we search backwards for a eocdr signature, and hope that whoever made the zip file was smart enough to forbid the eocdr signature in the comment. | ||
var eocdrWithoutCommentSize = 22; | ||
var maxCommentSize = 0x10000; // 2-byte size | ||
var bufferSize = Math.min(eocdrWithoutCommentSize + maxCommentSize, stats.size); | ||
var buffer = new Buffer(bufferSize); | ||
var bufferReadStart = stats.size - buffer.length; | ||
readNoEof(fd, buffer, 0, bufferSize, bufferReadStart, function(err) { | ||
if (err) return callback(err); | ||
for (var i = bufferSize - eocdrWithoutCommentSize; i >= 0; i -= 1) { | ||
if (buffer.readUInt32LE(i) !== 0x06054b50) continue; | ||
// found eocdr | ||
var eocdrBuffer = buffer.slice(i); | ||
var fdSlicer = new FdSlicer(fd, {autoClose: true}); | ||
// this ref is unreffed in zipfile.close() | ||
fdSlicer.ref(); | ||
fromFdSlicer(fdSlicer, stats.size, options, callback); | ||
}); | ||
} | ||
// 0 - End of central directory signature = 0x06054b50 | ||
// 4 - Number of this disk | ||
var diskNumber = eocdrBuffer.readUInt16LE(4); | ||
if (diskNumber !== 0) return callback(new Error("multi-disk zip files are not supported: found disk number: " + diskNumber)); | ||
// 6 - Disk where central directory starts | ||
// 8 - Number of central directory records on this disk | ||
// 10 - Total number of central directory records | ||
var entryCount = eocdrBuffer.readUInt16LE(10); | ||
// 12 - Size of central directory (bytes) | ||
// 16 - Offset of start of central directory, relative to start of archive | ||
var cdOffset = eocdrBuffer.readUInt32LE(16); | ||
// 20 - Comment length | ||
var commentLength = eocdrBuffer.readUInt16LE(20); | ||
var expectedCommentLength = eocdrBuffer.length - eocdrWithoutCommentSize; | ||
if (commentLength !== expectedCommentLength) { | ||
return callback(new Error("invalid comment length. expected: " + expectedCommentLength + ". found: " + commentLength)); | ||
} | ||
// 22 - Comment | ||
// the encoding is always cp437. | ||
var comment = bufferToString(eocdrBuffer, 22, eocdrBuffer.length, false); | ||
return callback(null, new ZipFile(fd, cdOffset, stats.size, entryCount, comment, options.autoClose)); | ||
function fromBuffer(buffer, callback) { | ||
if (callback == null) callback = defaultCallback; | ||
// i got your open file right here. | ||
var fdSlicer = new FakeFdSlicer(buffer); | ||
fromFdSlicer(fdSlicer, buffer.length, {}, callback); | ||
} | ||
function fromFdSlicer(fdSlicer, totalSize, options, callback) { | ||
// search backwards for the eocdr signature. | ||
// the last field of the eocdr is a variable-length comment. | ||
// the comment size is encoded in a 2-byte field in the eocdr, which we can't find without trudging backwards through the comment to find it. | ||
// as a consequence of this design decision, it's possible to have ambiguous zip file metadata if a coherent eocdr was in the comment. | ||
// we search backwards for a eocdr signature, and hope that whoever made the zip file was smart enough to forbid the eocdr signature in the comment. | ||
var eocdrWithoutCommentSize = 22; | ||
var maxCommentSize = 0x10000; // 2-byte size | ||
var bufferSize = Math.min(eocdrWithoutCommentSize + maxCommentSize, totalSize); | ||
var buffer = new Buffer(bufferSize); | ||
var bufferReadStart = totalSize - buffer.length; | ||
readFdSlicerNoEof(fdSlicer, buffer, 0, bufferSize, bufferReadStart, function(err) { | ||
if (err) return callback(err); | ||
for (var i = bufferSize - eocdrWithoutCommentSize; i >= 0; i -= 1) { | ||
if (buffer.readUInt32LE(i) !== 0x06054b50) continue; | ||
// found eocdr | ||
var eocdrBuffer = buffer.slice(i); | ||
// 0 - End of central directory signature = 0x06054b50 | ||
// 4 - Number of this disk | ||
var diskNumber = eocdrBuffer.readUInt16LE(4); | ||
if (diskNumber !== 0) return callback(new Error("multi-disk zip files are not supported: found disk number: " + diskNumber)); | ||
// 6 - Disk where central directory starts | ||
// 8 - Number of central directory records on this disk | ||
// 10 - Total number of central directory records | ||
var entryCount = eocdrBuffer.readUInt16LE(10); | ||
// 12 - Size of central directory (bytes) | ||
// 16 - Offset of start of central directory, relative to start of archive | ||
var cdOffset = eocdrBuffer.readUInt32LE(16); | ||
// 20 - Comment length | ||
var commentLength = eocdrBuffer.readUInt16LE(20); | ||
var expectedCommentLength = eocdrBuffer.length - eocdrWithoutCommentSize; | ||
if (commentLength !== expectedCommentLength) { | ||
return callback(new Error("invalid comment length. expected: " + expectedCommentLength + ". found: " + commentLength)); | ||
} | ||
callback(new Error("end of central directory record signature not found")); | ||
}); | ||
// 22 - Comment | ||
// the encoding is always cp437. | ||
var comment = bufferToString(eocdrBuffer, 22, eocdrBuffer.length, false); | ||
return callback(null, new ZipFile(fdSlicer, cdOffset, totalSize, entryCount, comment, options.autoClose)); | ||
} | ||
callback(new Error("end of central directory record signature not found")); | ||
}); | ||
@@ -92,7 +107,6 @@ } | ||
util.inherits(ZipFile, EventEmitter); | ||
function ZipFile(fd, cdOffset, fileSize, entryCount, comment, autoClose) { | ||
function ZipFile(fdSlicer, cdOffset, fileSize, entryCount, comment, autoClose) { | ||
var self = this; | ||
EventEmitter.call(self); | ||
self.fdSlicer = new FdSlicer(fd, {autoClose: true}); | ||
self.fdSlicer.ref(); | ||
self.fdSlicer = fdSlicer; | ||
// forward close events | ||
@@ -302,9 +316,2 @@ self.fdSlicer.on("error", function(err) { | ||
function readNoEof(fd, buffer, offset, length, position, callback) { | ||
fs.read(fd, buffer, offset, length, position, function(err, bytesRead) { | ||
if (err) return callback(err); | ||
if (bytesRead < length) return callback(new Error("unexpected EOF")); | ||
callback(); | ||
}); | ||
} | ||
function readFdSlicerNoEof(fdSlicer, buffer, offset, length, position, callback) { | ||
@@ -325,4 +332,31 @@ fdSlicer.read(buffer, offset, length, position, function(err, bytesRead) { | ||
} | ||
function FakeFdSlicer(buffer) { | ||
// pretend that a buffer is an FdSlicer | ||
this.buffer = buffer; | ||
} | ||
FakeFdSlicer.prototype.read = function(buffer, offset, length, position, callback) { | ||
this.buffer.copy(buffer, offset, position, position + length); | ||
setImmediate(function() { | ||
callback(null, length); | ||
}); | ||
}; | ||
FakeFdSlicer.prototype.createReadStream = function(options) { | ||
var start = options.start; | ||
var end = options.end; | ||
var buffer = new Buffer(end - start); | ||
this.buffer.copy(buffer, 0, start, end); | ||
var stream = new PassThrough(); | ||
stream.write(buffer); | ||
stream.end(); | ||
return stream; | ||
}; | ||
// i promise these functions are working properly :| | ||
FakeFdSlicer.prototype.ref = function() {}; | ||
FakeFdSlicer.prototype.unref = function() {}; | ||
FakeFdSlicer.prototype.on = function() {}; | ||
FakeFdSlicer.prototype.once = function() {}; | ||
function defaultCallback(err) { | ||
if (err) throw err; | ||
} |
{ | ||
"name": "yauzl", | ||
"version": "1.1.1", | ||
"version": "2.0.0", | ||
"description": "yet another unzip library for node", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -54,7 +54,7 @@ # yauzl | ||
Calls `fs.open(path, "r")` and gives the `fd`, `options`, and `callback` to `fopen` below. | ||
Calls `fs.open(path, "r")` and gives the `fd`, `options`, and `callback` to `fromFd` below. | ||
`options` may be omitted or `null` and defaults to `{autoClose: true}`. | ||
### fopen(fd, [options], [callback]) | ||
### fromFd(fd, [options], [callback]) | ||
@@ -79,2 +79,12 @@ Reads from the fd, which is presumed to be an open .zip file. | ||
### fromBuffer(buffer, [callback]) | ||
Like `fromFd`, but reads from a RAM buffer instead of an open file. | ||
`buffer` is a `Buffer`. | ||
`callback` is effectively passed directly to `fromFd`. | ||
If a `ZipFile` is acquired from this method, | ||
it will never emit the `close` event, | ||
and calling `close()` is not necessary. | ||
### dosDateTimeToDate(date, time) | ||
@@ -90,3 +100,3 @@ | ||
The constructor for the class is not part of the public API. | ||
Use `open` or `fopen` instead. | ||
Use `open`, `fromFd`, or `fromBuffer` instead. | ||
@@ -107,2 +117,4 @@ #### Event: "entry" | ||
This event is never emitted if this `ZipFile` was acquired from `fromBuffer()`. | ||
#### openReadStream(entry, [callback]) | ||
@@ -122,3 +134,3 @@ | ||
If `autoClose` is `true` in the original `open` or `fopen` call, | ||
If `autoClose` is `true` in the original `open` or `fromFd` call, | ||
this function will be called automatically effectively in response to this object's `end` event. | ||
@@ -195,3 +207,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` or `fopen`. | ||
* 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 stream you get from `openReadStream`. | ||
@@ -207,3 +219,3 @@ | ||
If the "number of this disk" field in the End of Central Directory Record is not `0`, | ||
the `open` or `fopen` `callback` will receive an `err`. | ||
the `open`, `fromFd`, or `fromBuffer` `callback` will receive an `err`. | ||
By extension the following zip file fields are ignored by this library and not provided to clients: | ||
@@ -210,0 +222,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24368
332
269