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