Initial
This commit is contained in:
288
resources/app/node_modules/unzipper/lib/parse.js
generated
vendored
Normal file
288
resources/app/node_modules/unzipper/lib/parse.js
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
const util = require('util');
|
||||
const zlib = require('zlib');
|
||||
const Stream = require('stream');
|
||||
const PullStream = require('./PullStream');
|
||||
const NoopStream = require('./NoopStream');
|
||||
const BufferStream = require('./BufferStream');
|
||||
const parseExtraField = require('./parseExtraField');
|
||||
const parseDateTime = require('./parseDateTime');
|
||||
const pipeline = Stream.pipeline;
|
||||
const parseBuffer = require('./parseBuffer');
|
||||
|
||||
const endDirectorySignature = Buffer.alloc(4);
|
||||
endDirectorySignature.writeUInt32LE(0x06054b50, 0);
|
||||
|
||||
function Parse(opts) {
|
||||
if (!(this instanceof Parse)) {
|
||||
return new Parse(opts);
|
||||
}
|
||||
const self = this;
|
||||
self._opts = opts || { verbose: false };
|
||||
|
||||
PullStream.call(self, self._opts);
|
||||
self.on('finish', function() {
|
||||
self.emit('end');
|
||||
self.emit('close');
|
||||
});
|
||||
self._readRecord().catch(function(e) {
|
||||
if (!self.__emittedError || self.__emittedError !== e)
|
||||
self.emit('error', e);
|
||||
});
|
||||
}
|
||||
|
||||
util.inherits(Parse, PullStream);
|
||||
|
||||
Parse.prototype._readRecord = function () {
|
||||
const self = this;
|
||||
|
||||
return self.pull(4).then(function(data) {
|
||||
if (data.length === 0)
|
||||
return;
|
||||
|
||||
const signature = data.readUInt32LE(0);
|
||||
|
||||
if (signature === 0x34327243) {
|
||||
return self._readCrxHeader();
|
||||
}
|
||||
if (signature === 0x04034b50) {
|
||||
return self._readFile();
|
||||
}
|
||||
else if (signature === 0x02014b50) {
|
||||
self.reachedCD = true;
|
||||
return self._readCentralDirectoryFileHeader();
|
||||
}
|
||||
else if (signature === 0x06054b50) {
|
||||
return self._readEndOfCentralDirectoryRecord();
|
||||
}
|
||||
else if (self.reachedCD) {
|
||||
// _readEndOfCentralDirectoryRecord expects the EOCD
|
||||
// signature to be consumed so set includeEof=true
|
||||
const includeEof = true;
|
||||
return self.pull(endDirectorySignature, includeEof).then(function() {
|
||||
return self._readEndOfCentralDirectoryRecord();
|
||||
});
|
||||
}
|
||||
else
|
||||
self.emit('error', new Error('invalid signature: 0x' + signature.toString(16)));
|
||||
}).then((function(loop) {
|
||||
if(loop) {
|
||||
return self._readRecord();
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
Parse.prototype._readCrxHeader = function() {
|
||||
const self = this;
|
||||
return self.pull(12).then(function(data) {
|
||||
self.crxHeader = parseBuffer.parse(data, [
|
||||
['version', 4],
|
||||
['pubKeyLength', 4],
|
||||
['signatureLength', 4],
|
||||
]);
|
||||
return self.pull(self.crxHeader.pubKeyLength + self.crxHeader.signatureLength);
|
||||
}).then(function(data) {
|
||||
self.crxHeader.publicKey = data.slice(0, self.crxHeader.pubKeyLength);
|
||||
self.crxHeader.signature = data.slice(self.crxHeader.pubKeyLength);
|
||||
self.emit('crx-header', self.crxHeader);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
Parse.prototype._readFile = function () {
|
||||
const self = this;
|
||||
return self.pull(26).then(function(data) {
|
||||
const vars = parseBuffer.parse(data, [
|
||||
['versionsNeededToExtract', 2],
|
||||
['flags', 2],
|
||||
['compressionMethod', 2],
|
||||
['lastModifiedTime', 2],
|
||||
['lastModifiedDate', 2],
|
||||
['crc32', 4],
|
||||
['compressedSize', 4],
|
||||
['uncompressedSize', 4],
|
||||
['fileNameLength', 2],
|
||||
['extraFieldLength', 2],
|
||||
]);
|
||||
|
||||
vars.lastModifiedDateTime = parseDateTime(vars.lastModifiedDate, vars.lastModifiedTime);
|
||||
|
||||
if (self.crxHeader) vars.crxHeader = self.crxHeader;
|
||||
|
||||
return self.pull(vars.fileNameLength).then(function(fileNameBuffer) {
|
||||
const fileName = fileNameBuffer.toString('utf8');
|
||||
const entry = Stream.PassThrough();
|
||||
let __autodraining = false;
|
||||
|
||||
entry.autodrain = function() {
|
||||
__autodraining = true;
|
||||
const draining = entry.pipe(NoopStream());
|
||||
draining.promise = function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
draining.on('finish', resolve);
|
||||
draining.on('error', reject);
|
||||
});
|
||||
};
|
||||
return draining;
|
||||
};
|
||||
|
||||
entry.buffer = function() {
|
||||
return BufferStream(entry);
|
||||
};
|
||||
|
||||
entry.path = fileName;
|
||||
entry.props = {};
|
||||
entry.props.path = fileName;
|
||||
entry.props.pathBuffer = fileNameBuffer;
|
||||
entry.props.flags = {
|
||||
"isUnicode": (vars.flags & 0x800) != 0
|
||||
};
|
||||
entry.type = (vars.uncompressedSize === 0 && /[/\\]$/.test(fileName)) ? 'Directory' : 'File';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self.pull(vars.extraFieldLength).then(function(extraField) {
|
||||
const extra = parseExtraField(extraField, vars);
|
||||
|
||||
entry.vars = vars;
|
||||
entry.extra = extra;
|
||||
|
||||
if (self._opts.forceStream) {
|
||||
self.push(entry);
|
||||
} else {
|
||||
self.emit('entry', entry);
|
||||
|
||||
if (self._readableState.pipesCount || (self._readableState.pipes && self._readableState.pipes.length))
|
||||
self.push(entry);
|
||||
}
|
||||
|
||||
if (self._opts.verbose)
|
||||
console.log({
|
||||
filename:fileName,
|
||||
vars: vars,
|
||||
extra: extra
|
||||
});
|
||||
|
||||
const fileSizeKnown = !(vars.flags & 0x08) || vars.compressedSize > 0;
|
||||
let eof;
|
||||
|
||||
entry.__autodraining = __autodraining; // expose __autodraining for test purposes
|
||||
const inflater = (vars.compressionMethod && !__autodraining) ? zlib.createInflateRaw() : Stream.PassThrough();
|
||||
|
||||
if (fileSizeKnown) {
|
||||
entry.size = vars.uncompressedSize;
|
||||
eof = vars.compressedSize;
|
||||
} else {
|
||||
eof = Buffer.alloc(4);
|
||||
eof.writeUInt32LE(0x08074b50, 0);
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
pipeline(
|
||||
self.stream(eof),
|
||||
inflater,
|
||||
entry,
|
||||
function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return fileSizeKnown ? resolve(fileSizeKnown) : self._processDataDescriptor(entry).then(resolve).catch(reject);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Parse.prototype._processDataDescriptor = function (entry) {
|
||||
const self = this;
|
||||
return self.pull(16).then(function(data) {
|
||||
const vars = parseBuffer.parse(data, [
|
||||
['dataDescriptorSignature', 4],
|
||||
['crc32', 4],
|
||||
['compressedSize', 4],
|
||||
['uncompressedSize', 4],
|
||||
]);
|
||||
|
||||
entry.size = vars.uncompressedSize;
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
Parse.prototype._readCentralDirectoryFileHeader = function () {
|
||||
const self = this;
|
||||
return self.pull(42).then(function(data) {
|
||||
const vars = parseBuffer.parse(data, [
|
||||
['versionMadeBy', 2],
|
||||
['versionsNeededToExtract', 2],
|
||||
['flags', 2],
|
||||
['compressionMethod', 2],
|
||||
['lastModifiedTime', 2],
|
||||
['lastModifiedDate', 2],
|
||||
['crc32', 4],
|
||||
['compressedSize', 4],
|
||||
['uncompressedSize', 4],
|
||||
['fileNameLength', 2],
|
||||
['extraFieldLength', 2],
|
||||
['fileCommentLength', 2],
|
||||
['diskNumber', 2],
|
||||
['internalFileAttributes', 2],
|
||||
['externalFileAttributes', 4],
|
||||
['offsetToLocalFileHeader', 4],
|
||||
]);
|
||||
|
||||
return self.pull(vars.fileNameLength).then(function(fileName) {
|
||||
vars.fileName = fileName.toString('utf8');
|
||||
return self.pull(vars.extraFieldLength);
|
||||
})
|
||||
.then(function() {
|
||||
return self.pull(vars.fileCommentLength);
|
||||
})
|
||||
.then(function() {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Parse.prototype._readEndOfCentralDirectoryRecord = function() {
|
||||
const self = this;
|
||||
return self.pull(18).then(function(data) {
|
||||
|
||||
const vars = parseBuffer.parse(data, [
|
||||
['diskNumber', 2],
|
||||
['diskStart', 2],
|
||||
['numberOfRecordsOnDisk', 2],
|
||||
['numberOfRecords', 2],
|
||||
['sizeOfCentralDirectory', 4],
|
||||
['offsetToStartOfCentralDirectory', 4],
|
||||
['commentLength', 2],
|
||||
]);
|
||||
|
||||
return self.pull(vars.commentLength).then(function() {
|
||||
self.end();
|
||||
self.push(null);
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
Parse.prototype.promise = function() {
|
||||
const self = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
self.on('finish', resolve);
|
||||
self.on('error', reject);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Parse;
|
||||
Reference in New Issue
Block a user