You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
3.7 KiB
125 lines
3.7 KiB
4 years ago
|
var Promise = require('bluebird');
|
||
|
var Decrypt = require('../Decrypt');
|
||
|
var PullStream = require('../PullStream');
|
||
|
var Stream = require('stream');
|
||
|
var binary = require('binary');
|
||
|
var zlib = require('zlib');
|
||
|
var parseExtraField = require('../parseExtraField');
|
||
|
var Buffer = require('../Buffer');
|
||
|
var parseDateTime = require('../parseDateTime');
|
||
|
|
||
|
// Backwards compatibility for node versions < 8
|
||
|
if (!Stream.Writable || !Stream.Writable.prototype.destroy)
|
||
|
Stream = require('readable-stream');
|
||
|
|
||
|
module.exports = function unzip(source,offset,_password, directoryVars) {
|
||
|
var file = PullStream(),
|
||
|
entry = Stream.PassThrough();
|
||
|
|
||
|
var req = source.stream(offset);
|
||
|
req.pipe(file).on('error', function(e) {
|
||
|
entry.emit('error', e);
|
||
|
});
|
||
|
|
||
|
entry.vars = file.pull(30)
|
||
|
.then(function(data) {
|
||
|
var vars = binary.parse(data)
|
||
|
.word32lu('signature')
|
||
|
.word16lu('versionsNeededToExtract')
|
||
|
.word16lu('flags')
|
||
|
.word16lu('compressionMethod')
|
||
|
.word16lu('lastModifiedTime')
|
||
|
.word16lu('lastModifiedDate')
|
||
|
.word32lu('crc32')
|
||
|
.word32lu('compressedSize')
|
||
|
.word32lu('uncompressedSize')
|
||
|
.word16lu('fileNameLength')
|
||
|
.word16lu('extraFieldLength')
|
||
|
.vars;
|
||
|
|
||
|
vars.lastModifiedDateTime = parseDateTime(vars.lastModifiedDate, vars.lastModifiedTime);
|
||
|
|
||
|
return file.pull(vars.fileNameLength)
|
||
|
.then(function(fileName) {
|
||
|
vars.fileName = fileName.toString('utf8');
|
||
|
return file.pull(vars.extraFieldLength);
|
||
|
})
|
||
|
.then(function(extraField) {
|
||
|
var checkEncryption;
|
||
|
vars.extra = parseExtraField(extraField, vars);
|
||
|
// Ignore logal file header vars if the directory vars are available
|
||
|
if (directoryVars && directoryVars.compressedSize) vars = directoryVars;
|
||
|
|
||
|
if (vars.flags & 0x01) checkEncryption = file.pull(12)
|
||
|
.then(function(header) {
|
||
|
if (!_password)
|
||
|
throw new Error('MISSING_PASSWORD');
|
||
|
|
||
|
var decrypt = Decrypt();
|
||
|
|
||
|
String(_password).split('').forEach(function(d) {
|
||
|
decrypt.update(d);
|
||
|
});
|
||
|
|
||
|
for (var i=0; i < header.length; i++)
|
||
|
header[i] = decrypt.decryptByte(header[i]);
|
||
|
|
||
|
vars.decrypt = decrypt;
|
||
|
vars.compressedSize -= 12;
|
||
|
|
||
|
var check = (vars.flags & 0x8) ? (vars.lastModifiedTime >> 8) & 0xff : (vars.crc32 >> 24) & 0xff;
|
||
|
if (header[11] !== check)
|
||
|
throw new Error('BAD_PASSWORD');
|
||
|
|
||
|
return vars;
|
||
|
});
|
||
|
|
||
|
return Promise.resolve(checkEncryption)
|
||
|
.then(function() {
|
||
|
entry.emit('vars',vars);
|
||
|
return vars;
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
entry.vars.then(function(vars) {
|
||
|
var fileSizeKnown = !(vars.flags & 0x08) || vars.compressedSize > 0,
|
||
|
eof;
|
||
|
|
||
|
var inflater = vars.compressionMethod ? zlib.createInflateRaw() : Stream.PassThrough();
|
||
|
|
||
|
if (fileSizeKnown) {
|
||
|
entry.size = vars.uncompressedSize;
|
||
|
eof = vars.compressedSize;
|
||
|
} else {
|
||
|
eof = Buffer.alloc(4);
|
||
|
eof.writeUInt32LE(0x08074b50, 0);
|
||
|
}
|
||
|
|
||
|
var stream = file.stream(eof);
|
||
|
|
||
|
if (vars.decrypt)
|
||
|
stream = stream.pipe(vars.decrypt.stream());
|
||
|
|
||
|
stream
|
||
|
.pipe(inflater)
|
||
|
.on('error',function(err) { entry.emit('error',err);})
|
||
|
.pipe(entry)
|
||
|
.on('finish', function() {
|
||
|
if (req.abort)
|
||
|
req.abort();
|
||
|
else if (req.close)
|
||
|
req.close();
|
||
|
else if (req.push)
|
||
|
req.push();
|
||
|
else
|
||
|
console.log('warning - unable to close stream');
|
||
|
});
|
||
|
})
|
||
|
.catch(function(e) {
|
||
|
entry.emit('error',e);
|
||
|
});
|
||
|
|
||
|
return entry;
|
||
|
};
|