Comparing version 0.9.0-rc9 to 0.9.0
@@ -5,4 +5,4 @@ var Promise = require('bluebird'); | ||
// Backwards compatibility for node 0.8 | ||
if (!Stream.Writable) | ||
// Backwards compatibility for node versions < 8 | ||
if (!Stream.Writable || !Stream.Writable.prototype.destroy) | ||
Stream = require('readable-stream'); | ||
@@ -9,0 +9,0 @@ |
var bigInt = require('big-integer'); | ||
var Stream = require('stream'); | ||
// Backwards compatibility for node 0.8 | ||
if (!Stream.Writable) | ||
// Backwards compatibility for node versions < 8 | ||
if (!Stream.Writable || !Stream.Writable.prototype.destroy) | ||
Stream = require('readable-stream'); | ||
@@ -7,0 +7,0 @@ |
@@ -15,3 +15,18 @@ module.exports = Extract; | ||
var self = this; | ||
var finishCb; | ||
var pending = 0; | ||
var _final = typeof this._final === 'function' ? this._final : undefined; | ||
function checkFinished() { | ||
if (pending === 0 && finishCb) { | ||
_final ? _final(finishCb) : finishCb(); | ||
} | ||
} | ||
this._final = function(cb) { | ||
finishCb = cb; | ||
checkFinished(); | ||
}; | ||
Parse.call(self,opts); | ||
@@ -21,9 +36,25 @@ | ||
if (entry.type == 'Directory') return; | ||
entry.pipe(Writer({ | ||
path: path.join(opts.path,entry.path) | ||
})) | ||
// to avoid zip slip (writing outside of the destination), we resolve | ||
// the target path, and make sure it's nested in the intended | ||
// destination, or not extract it otherwise. | ||
var extractPath = path.join(opts.path, entry.path); | ||
if (extractPath.indexOf(opts.path) != 0) { | ||
return; | ||
} | ||
const writer = opts.getWriter ? opts.getWriter({path: extractPath}) : Writer({ path: extractPath }); | ||
pending += 1; | ||
entry.pipe(writer) | ||
.on('error',function(e) { | ||
self.emit('error',e); | ||
pending -= 1; | ||
checkFinished(); | ||
}) | ||
.on('close', function() { | ||
pending -= 1; | ||
checkFinished(); | ||
}); | ||
}); | ||
} |
var Stream = require('stream'); | ||
var util = require('util'); | ||
// Backwards compatibility for node 0.8 | ||
if (!Stream.Writable) | ||
// Backwards compatibility for node versions < 8 | ||
if (!Stream.Writable || !Stream.Writable.prototype.destroy) | ||
Stream = require('readable-stream'); | ||
@@ -7,0 +7,0 @@ |
@@ -0,5 +1,6 @@ | ||
var binary = require('binary'); | ||
var PullStream = require('../PullStream'); | ||
var unzip = require('./unzip'); | ||
var Promise = require('bluebird'); | ||
var BufferStream = require('../BufferStream'); | ||
var read = require('../read'); | ||
@@ -11,3 +12,5 @@ var signature = Buffer(4); | ||
var endDir = PullStream(), | ||
records = PullStream(); | ||
records = PullStream(), | ||
self = this, | ||
vars; | ||
@@ -20,33 +23,62 @@ return source.size() | ||
.then(function() { | ||
return read.endOfDirectory(endDir); | ||
return endDir.pull(22); | ||
}) | ||
.then(function(vars) { | ||
Object.defineProperty(vars,'source',{value: source}); | ||
.then(function(data) { | ||
vars = binary.parse(data) | ||
.word32lu('signature') | ||
.word16lu('diskNumber') | ||
.word16lu('diskStart') | ||
.word16lu('numberOfRecordsOnDisk') | ||
.word16lu('numberOfRecords') | ||
.word32lu('sizeOfCentralDirectory') | ||
.word32lu('offsetToStartOfCentralDirectory') | ||
.word16lu('commentLength') | ||
.vars; | ||
source.stream(vars.offsetToStartOfCentralDirectory).pipe(records); | ||
vars.files = Promise.mapSeries(Array(vars.numberOfRecords),function() { | ||
return read.directoryFileHeader(records) | ||
.then(function(file) { | ||
file.stream = function(_password, _raw) { | ||
var input = source.stream(file.offsetToLocalFileHeader); | ||
var output = read.fileStream(input.pipe(PullStream()),{password:_password, raw: _raw}); | ||
return records.pull(46).then(function(data) { | ||
var vars = binary.parse(data) | ||
.word32lu('signature') | ||
.word16lu('versionMadeBy') | ||
.word16lu('versionsNeededToExtract') | ||
.word16lu('flags') | ||
.word16lu('compressionMethod') | ||
.word16lu('lastModifiedTime') | ||
.word16lu('lastModifiedDate') | ||
.word32lu('crc32') | ||
.word32lu('compressedSize') | ||
.word32lu('uncompressedSize') | ||
.word16lu('fileNameLength') | ||
.word16lu('extraFieldLength') | ||
.word16lu('fileCommentLength') | ||
.word16lu('diskNumber') | ||
.word16lu('internalFileAttributes') | ||
.word32lu('externalFileAttributes') | ||
.word32lu('offsetToLocalFileHeader') | ||
.vars; | ||
input.on('error',function(err) { | ||
output.emit('error',err); | ||
}); | ||
return output; | ||
}; | ||
file.buffer = function(_password) { | ||
return BufferStream(file.stream(_password)); | ||
}; | ||
return file; | ||
}); | ||
return records.pull(vars.fileNameLength).then(function(fileName) { | ||
vars.path = fileName.toString('utf8'); | ||
return records.pull(vars.extraFieldLength); | ||
}) | ||
.then(function(extraField) { | ||
return records.pull(vars.fileCommentLength); | ||
}) | ||
.then(function(comment) { | ||
vars.comment = comment; | ||
vars.stream = function(_password) { | ||
return unzip(source, vars.offsetToLocalFileHeader,_password); | ||
}; | ||
vars.buffer = function(_password) { | ||
return BufferStream(vars.stream(_password)); | ||
}; | ||
return vars; | ||
}); | ||
}); | ||
return Promise.props(vars); | ||
}); | ||
return Promise.props(vars); | ||
}); | ||
}; |
221
lib/parse.js
var util = require('util'); | ||
var zlib = require('zlib'); | ||
var Stream = require('stream'); | ||
var binary = require('binary'); | ||
var Promise = require('bluebird'); | ||
var PullStream = require('./PullStream'); | ||
var read = require('./read'); | ||
var NoopStream = require('./NoopStream'); | ||
var BufferStream = require('./BufferStream'); | ||
// Backwards compatibility for node 0.8 | ||
if (!Stream.Writable) | ||
// Backwards compatibility for node versions < 8 | ||
if (!Stream.Writable || !Stream.Writable.prototype.destroy) | ||
Stream = require('readable-stream'); | ||
@@ -36,26 +39,21 @@ | ||
// Read signature and put back on buffer | ||
var signature = data.readUInt32LE(0); | ||
self.buffer = Buffer.concat([data,self.buffer]); | ||
if (signature === 0x04034b50) | ||
if (signature === 0x04034b50) { | ||
return self._readFile(); | ||
} | ||
else if (signature === 0x02014b50) { | ||
self.__ended = true; | ||
return read.directoryFileHeader(self) | ||
.then(function(vars) { | ||
return self._readRecord(); | ||
}); | ||
return self._readCentralDirectoryFileHeader(); | ||
} | ||
else if (signature === 0x06054b50 || self.__ended) { | ||
else if (signature === 0x06054b50) { | ||
return self._readEndOfCentralDirectoryRecord(); | ||
} | ||
else if (self.__ended) { | ||
return self.pull(endDirectorySignature).then(function() { | ||
return read.endOfDirectory(self); | ||
}) | ||
.then(function() { | ||
self.end(); | ||
self.push(null); | ||
return self._readEndOfCentralDirectoryRecord(); | ||
}); | ||
} | ||
else | ||
self.emit('error', Error('invalid signature: 0x' + signature.toString(16))); | ||
self.emit('error', new Error('invalid signature: 0x' + signature.toString(16))); | ||
}); | ||
@@ -66,38 +64,179 @@ }; | ||
var self = this; | ||
var entry = read.fileStream(self,self._opts); | ||
self.pull(26).then(function(data) { | ||
var vars = binary.parse(data) | ||
.word16lu('versionsNeededToExtract') | ||
.word16lu('flags') | ||
.word16lu('compressionMethod') | ||
.word16lu('lastModifiedTime') | ||
.word16lu('lastModifiedDate') | ||
.word32lu('crc32') | ||
.word32lu('compressedSize') | ||
.word32lu('uncompressedSize') | ||
.word16lu('fileNameLength') | ||
.word16lu('extraFieldLength') | ||
.vars; | ||
entry.header.then(function(vars) { | ||
var fileSizeKnown = !(vars.flags & 0x08); | ||
entry.path = vars.path; | ||
entry.props = {}; | ||
entry.props.path = vars.fileName; | ||
entry.type = (vars.compressedSize === 0 && /[\/\\]$/.test(vars.path)) ? 'Directory' : 'File'; | ||
return self.pull(vars.fileNameLength).then(function(fileName) { | ||
fileName = fileName.toString('utf8'); | ||
var entry = Stream.PassThrough(); | ||
entry.autodrain = function() { | ||
return new Promise(function(resolve,reject) { | ||
entry.pipe(NoopStream()); | ||
entry.on('finish',resolve); | ||
entry.on('error',reject); | ||
}); | ||
}; | ||
entry.autodrain = function() { | ||
entry.autodraining = true; | ||
return new Promise(function(resolve,reject) { | ||
entry.on('finish',resolve); | ||
entry.on('error',reject); | ||
}); | ||
}; | ||
entry.buffer = function() { | ||
return BufferStream(entry); | ||
}; | ||
self.emit('entry',entry); | ||
entry.path = fileName; | ||
entry.props = {}; | ||
entry.props.path = fileName; | ||
entry.type = (vars.uncompressedSize === 0 && /[\/\\]$/.test(fileName)) ? 'Directory' : 'File'; | ||
if (self._readableState.pipesCount) | ||
self.push(entry); | ||
if (self._opts.verbose) { | ||
if (entry.type === 'Directory') { | ||
console.log(' creating:', fileName); | ||
} else if (entry.type === 'File') { | ||
if (vars.compressionMethod === 0) { | ||
console.log(' extracting:', fileName); | ||
} else { | ||
console.log(' inflating:', fileName); | ||
} | ||
} | ||
} | ||
self.pull(vars.extraFieldLength).then(function(extraField) { | ||
var extra = binary.parse(extraField) | ||
.word16lu('signature') | ||
.word16lu('partsize') | ||
.word64lu('uncompressedSize') | ||
.word64lu('compressedSize') | ||
.word64lu('offset') | ||
.word64lu('disknum') | ||
.vars; | ||
if (vars.compressedSize === 0xffffffff) | ||
vars.compressedSize = extra.compressedSize; | ||
if (vars.uncompressedSize === 0xffffffff) | ||
vars.uncompressedSize= extra.uncompressedSize; | ||
entry | ||
.on('finish', function() { | ||
Promise.resolve(!fileSizeKnown && read.dataDescriptor(self)) | ||
.then(function() { | ||
return self._readRecord(); | ||
}); | ||
entry.vars = vars; | ||
entry.extra = extra; | ||
self.emit('entry', entry); | ||
if (self._readableState.pipesCount) | ||
self.push(entry); | ||
if (self._opts.verbose) | ||
console.log({ | ||
filename:fileName, | ||
vars: vars, | ||
extra: extra | ||
}); | ||
var fileSizeKnown = !(vars.flags & 0x08), | ||
eof; | ||
var inflater = vars.compressionMethod ? zlib.createInflateRaw() : Stream.PassThrough(); | ||
if (fileSizeKnown) { | ||
entry.size = vars.uncompressedSize; | ||
eof = vars.compressedSize; | ||
} else { | ||
eof = new Buffer(4); | ||
eof.writeUInt32LE(0x08074b50, 0); | ||
} | ||
self.stream(eof) | ||
.pipe(inflater) | ||
.on('error',function(err) { self.emit('error',err);}) | ||
.pipe(entry) | ||
.on('finish', function() { | ||
return fileSizeKnown ? self._readRecord() : self._processDataDescriptor(entry); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}; | ||
Parse.prototype._processDataDescriptor = function (entry) { | ||
var self = this; | ||
self.pull(16).then(function(data) { | ||
var vars = binary.parse(data) | ||
.word32lu('dataDescriptorSignature') | ||
.word32lu('crc32') | ||
.word32lu('compressedSize') | ||
.word32lu('uncompressedSize') | ||
.vars; | ||
entry.size = vars.uncompressedSize; | ||
self._readRecord(); | ||
}); | ||
}; | ||
Parse.prototype._readCentralDirectoryFileHeader = function () { | ||
var self = this; | ||
self.pull(42).then(function(data) { | ||
var vars = binary.parse(data) | ||
.word16lu('versionMadeBy') | ||
.word16lu('versionsNeededToExtract') | ||
.word16lu('flags') | ||
.word16lu('compressionMethod') | ||
.word16lu('lastModifiedTime') | ||
.word16lu('lastModifiedDate') | ||
.word32lu('crc32') | ||
.word32lu('compressedSize') | ||
.word32lu('uncompressedSize') | ||
.word16lu('fileNameLength') | ||
.word16lu('extraFieldLength') | ||
.word16lu('fileCommentLength') | ||
.word16lu('diskNumber') | ||
.word16lu('internalFileAttributes') | ||
.word32lu('externalFileAttributes') | ||
.word32lu('offsetToLocalFileHeader') | ||
.vars; | ||
return self.pull(vars.fileNameLength).then(function(fileName) { | ||
vars.fileName = fileName.toString('utf8'); | ||
return self.pull(vars.extraFieldLength); | ||
}) | ||
.then(function(extraField) { | ||
return self.pull(vars.fileCommentLength); | ||
}) | ||
.then(function(fileComment) { | ||
return self._readRecord(); | ||
}); | ||
}); | ||
}; | ||
Parse.prototype._readEndOfCentralDirectoryRecord = function() { | ||
var self = this; | ||
self.pull(18).then(function(data) { | ||
var vars = binary.parse(data) | ||
.word16lu('diskNumber') | ||
.word16lu('diskStart') | ||
.word16lu('numberOfRecordsOnDisk') | ||
.word16lu('numberOfRecords') | ||
.word32lu('sizeOfCentralDirectory') | ||
.word32lu('offsetToStartOfCentralDirectory') | ||
.word16lu('commentLength') | ||
.vars; | ||
self.pull(vars.commentLength).then(function(comment) { | ||
comment = comment.toString('utf8'); | ||
self.end(); | ||
self.push(null); | ||
}); | ||
}); | ||
}; | ||
Parse.prototype.promise = function() { | ||
@@ -104,0 +243,0 @@ var self = this; |
@@ -6,16 +6,14 @@ var Stream = require('stream'); | ||
// Backwards compatibility for node 0.8 | ||
if (!Stream.Writable) | ||
// Backwards compatibility for node versions < 8 | ||
if (!Stream.Writable || !Stream.Writable.prototype.destroy) | ||
Stream = require('readable-stream'); | ||
function parseOne(match,opts) { | ||
opts = opts || {}; | ||
var inStream = Stream.PassThrough({objectMode:true}); | ||
var outStream = Stream.PassThrough(); | ||
var transform = Stream.Transform({objectMode:true}); | ||
var re = match && new RegExp(match); | ||
var re = match instanceof RegExp ? match : (match && new RegExp(match)); | ||
var found; | ||
transform._transform = function(entry,e,cb) { | ||
entry.password = opts.password; | ||
if (found || (re && !re.exec(entry.path))) { | ||
@@ -61,3 +59,2 @@ entry.autodrain(); | ||
module.exports = parseOne; | ||
module.exports = parseOne; |
@@ -6,4 +6,4 @@ var Stream = require('stream'); | ||
// Backwards compatibility for node 0.8 | ||
if (!Stream.Writable) | ||
// Backwards compatibility for node versions < 8 | ||
if (!Stream.Writable || !Stream.Writable.prototype.destroy) | ||
Stream = require('readable-stream'); | ||
@@ -37,3 +37,3 @@ | ||
var p = Stream.PassThrough(); | ||
var done,packet,self= this; | ||
var count = 0,done,packet,self= this; | ||
@@ -66,8 +66,9 @@ function pull() { | ||
if (!done) { | ||
if (self.finished && !self.__ended) { | ||
if (self.finished && !this.__ended) { | ||
self.removeListener('chunk',pull); | ||
self.emit('error',new Error('FILE_ENDED')); | ||
self.emit('error', new Error('FILE_ENDED')); | ||
this.__ended = true; | ||
return; | ||
} | ||
} else { | ||
@@ -74,0 +75,0 @@ self.removeListener('chunk',pull); |
{ | ||
"name": "unzipper", | ||
"version": "0.9.0-rc9", | ||
"version": "0.9.0", | ||
"description": "Unzip cross-platform streaming API ", | ||
@@ -33,3 +33,3 @@ "author": "Evan Oxfeld <eoxfeld@gmail.com>", | ||
"listenercount": "~1.0.1", | ||
"readable-stream": "~2.1.5", | ||
"readable-stream": "~2.3.6", | ||
"setimmediate": "~1.0.4" | ||
@@ -39,4 +39,4 @@ }, | ||
"aws-sdk": "^2.77.0", | ||
"request": "^2.79.0", | ||
"tap": "^10.3.2", | ||
"request": "2.79.0", | ||
"tap": ">= 0.3.0 < 1", | ||
"temp": ">= 0.4.0 < 1", | ||
@@ -43,0 +43,0 @@ "dirdiff": ">= 0.0.1 < 1", |
# unzipper [![Build Status](https://api.travis-ci.org/ZJONSSON/node-unzipper.png)](https://api.travis-ci.org/ZJONSSON/node-unzipper) | ||
This is a fork of [node-unzip](https://github.com/EvanOxfeld/node-pullstream) which has not been maintained in a while. This fork addresses the following issues: | ||
This is a fork of [node-unzip](https://github.com/EvanOxfeld/node-unzip) which has not been maintained in a while. This fork addresses the following issues: | ||
* finish/close events are not always triggered, particular when the input stream is slower than the receivers | ||
@@ -157,3 +157,3 @@ * Any files are buffered into memory before passing on to entry | ||
.pipe(fs.createWriteStream('firstFile')) | ||
.on('error',reject); | ||
.on('error',reject) | ||
.on('finish',resolve) | ||
@@ -164,4 +164,4 @@ }); | ||
### Open.url([requestLibrary], [url]) | ||
This function will return a Promise to the central directory information from a URL point to a zipfile. Range-headers are used to avoid reading the whole file. Unzipper does not ship with a request library so you will have to provide it as the first option. The url parameter can either be a string or an object that will be passed to each request (containing the url, but also any optional properties such as cookies, proxy etc) | ||
### Open.url([requestLibrary], [url | options]) | ||
This function will return a Promise to the central directory information from a URL point to a zipfile. Range-headers are used to avoid reading the whole file. Unzipper does not ship with a request library so you will have to provide it as the first option. | ||
@@ -186,2 +186,24 @@ Live Example: (extracts a tiny xml file from the middle of a 500MB zipfile) | ||
This function takes a second parameter which can either be a string containing the `url` to request, or an `options` object to invoke the supplied `request` library with. This can be used when other request options are required, such as custom heders or authentication to a third party service. | ||
```js | ||
const request = require('google-oauth-jwt').requestWithJWT(); | ||
const googleStorageOptions = { | ||
url: `https://www.googleapis.com/storage/v1/b/m-bucket-name/o/my-object-name`, | ||
qs: { alt: 'media' }, | ||
jwt: { | ||
email: google.storage.credentials.client_email, | ||
key: google.storage.credentials.private_key, | ||
scopes: ['https://www.googleapis.com/auth/devstorage.read_only'] | ||
} | ||
}); | ||
return unzipper.Open.url(request, googleStorageOptions).then((zip) => { | ||
const file = zip.files.find((file) => file.path === 'my-filename'); | ||
return file.stream().pipe(res); | ||
}); | ||
``` | ||
### Open.s3([aws-sdk], [params]) | ||
@@ -203,3 +225,3 @@ This function will return a Promise to the central directory information from a zipfile on S3. Range-headers are used to avoid reading the whole file. Unzipper does not ship with with the aws-sdk so you have to provide an instanciated client as first arguments. The params object requires `Bucket` and `Key` to fetch the correct file. | ||
.pipe(fs.createWriteStream('firstFile')) | ||
.on('error',reject); | ||
.on('error',reject) | ||
.on('finish',resolve) | ||
@@ -206,0 +228,0 @@ }); |
Sorry, the diff of this file is not supported yet
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
36264
753
231
15
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedstring_decoder@1.1.1(transitive)
- Removedbuffer-shims@1.0.0(transitive)
- Removedprocess-nextick-args@1.0.7(transitive)
- Removedreadable-stream@2.1.5(transitive)
- Removedstring_decoder@0.10.31(transitive)
Updatedreadable-stream@~2.3.6