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
			| 
								 
											3 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;
							 | 
						||
| 
								 | 
							
								};
							 |