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.
		
		
		
		
		
			
		
			
				
					127 lines
				
				3.8 KiB
			
		
		
			
		
	
	
					127 lines
				
				3.8 KiB
			| 
											2 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.destroy) | ||
|  |             req.destroy() | ||
|  |           else 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; | ||
|  | }; |