Comparing version
@@ -12,4 +12,4 @@ ## Contributing | ||
* tests should be added to the nodeunit config in `test/tests.js` | ||
* tests should be added to the nodeunit configs in `tests/` | ||
* tests can be run with `npm test` | ||
* see existing tests for guidance |
var fs = require('fs'); | ||
var archiver = require('archiver'); | ||
var async = require('async'); | ||
@@ -8,10 +9,22 @@ var out = fs.createWriteStream('out.zip'); // or out.tar | ||
archive.on('error', function(err) { | ||
throw err; | ||
}); | ||
archive.pipe(out); | ||
archive.addFile(fs.createReadStream('file1.js'), {name: 'file1.js'}, function() { | ||
archive.addFile(fs.createReadStream('file2.js'), {name: 'file2.js'}, function() { | ||
archive.finalize(function(written) { | ||
console.log(written + ' total bytes written'); | ||
}); | ||
async.forEach(['file1.js', 'file2.js'], function(file, next) { | ||
archive.addFile(fs.createReadStream(file), { name: file }, next); | ||
}, function(err) { | ||
if (err) { | ||
throw err; | ||
} | ||
archive.finalize(function(err, written) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log(written + ' total bytes written'); | ||
}); | ||
}); |
@@ -1,5 +0,5 @@ | ||
/* | ||
/** | ||
* node-archiver | ||
* | ||
* Copyright (c) 2012 Chris Talkington, contributors. | ||
* Copyright (c) 2012-2013 Chris Talkington, contributors. | ||
* Licensed under the MIT license. | ||
@@ -14,8 +14,18 @@ * https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT | ||
archiver.createTar = function(opt) { | ||
return new tarArchiver(opt); | ||
archiver.create = function(type, options) { | ||
if (type === 'zip') { | ||
return new zipArchiver(options); | ||
} else if (type === 'tar') { | ||
return new tarArchiver(options); | ||
} else { | ||
throw new Error('Unknown archive type'); | ||
} | ||
}; | ||
archiver.createZip = function(opt) { | ||
return new zipArchiver(opt); | ||
archiver.createTar = function(options) { | ||
return new tarArchiver(options); | ||
}; | ||
archiver.createZip = function(options) { | ||
return new zipArchiver(options); | ||
}; |
@@ -0,5 +1,13 @@ | ||
/** | ||
* node-archiver | ||
* | ||
* Copyright (c) 2012-2013 Chris Talkington, contributors. | ||
* Licensed under the MIT license. | ||
* https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT | ||
*/ | ||
var stream = require('stream'); | ||
var inherits = require('util').inherits; | ||
var utils = require('../util/utils'); | ||
var util = require('../util'); | ||
@@ -54,4 +62,4 @@ var Archiver = module.exports = function() { | ||
if (utils.lo.isFunction(self.callback)) { | ||
self.callback(self.fileptr); | ||
if (util.lo.isFunction(self.callback)) { | ||
self.callback(null, self.fileptr); | ||
} | ||
@@ -61,3 +69,3 @@ } | ||
//TODO look into possible cpu usage issues | ||
process.nextTick(function() { | ||
util.nextTick(function() { | ||
self._read(); | ||
@@ -73,2 +81,2 @@ }); | ||
// placeholder | ||
}; | ||
}; |
@@ -0,5 +1,14 @@ | ||
/** | ||
* node-archiver | ||
* | ||
* Copyright (c) 2012-2013 Chris Talkington, contributors. | ||
* Licensed under the MIT license. | ||
* https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT | ||
*/ | ||
var inherits = require('util').inherits; | ||
var Archiver = require('./core.js'); | ||
var utils = require('../util/utils'); | ||
var Archiver = require('./core'); | ||
var headers = require('../headers/tar'); | ||
var util = require('../util'); | ||
@@ -13,7 +22,8 @@ var tarArchiver = module.exports = function(options) { | ||
options = self.options = utils.lo.defaults(options, { | ||
options = self.options = util.lo.defaults(options, { | ||
recordSize: 512, | ||
recordsPerBlock: 20 | ||
}); | ||
self.recordSize = 512; | ||
self.recordSize = options.recordSize; | ||
self.blockSize = options.recordsPerBlock * self.recordSize; | ||
@@ -24,76 +34,2 @@ }; | ||
var header = { | ||
format: [ | ||
{'field': 'name', 'length': 100, 'type': 'string'}, | ||
{'field': 'mode', 'length': 8, 'type': 'number'}, | ||
{'field': 'uid', 'length': 8, 'type': 'number'}, | ||
{'field': 'gid', 'length': 8, 'type': 'number'}, | ||
{'field': 'size','length': 12, 'type': 'number'}, | ||
{'field': 'mtime', 'length': 12, 'type': 'number'}, | ||
{'field': 'checksum', 'length': 8, 'type': 'string', 'default': utils.repeat(' ', 8)}, | ||
{'field': 'type', 'length': 1, 'type': 'number'}, | ||
{'field': 'linkName', 'length': 100, 'type': 'string'}, | ||
{'field': 'ustar', 'length': 8, 'type': 'string', 'default': 'ustar '}, | ||
{'field': 'owner', 'length': 32, 'type': 'string'}, | ||
{'field': 'group', 'length': 32, 'type': 'string'}, | ||
{'field': 'majorNumber', 'length': 8, 'type': 'number'}, | ||
{'field': 'minorNumber', 'length': 8, 'type': 'number'}, | ||
{'field': 'filenamePrefix', 'length': 155, 'type': 'string'}, | ||
{'field': 'padding', 'length': 12} | ||
], | ||
create: function(data) { | ||
var buffer = utils.cleanBuffer(512); | ||
var offset = 0; | ||
var val; | ||
this.format.forEach(function(value) { | ||
val = data[value.field] || value.default || ''; | ||
buffer.write(val, offset); | ||
offset += value.length; | ||
}); | ||
var checksum = this.createChecksum(buffer); | ||
for (var i = 0, length = 6; i < length; i += 1) { | ||
buffer[i + 148] = checksum.charCodeAt(i); | ||
} | ||
buffer[154] = 0; | ||
buffer[155] = 0x20; | ||
return buffer; | ||
}, | ||
createChecksum: function(buffer) { | ||
var checksum = 0; | ||
for (var i = 0, length = buffer.length; i < length; i += 1) { | ||
checksum += buffer[i]; | ||
} | ||
checksum = checksum.toString(8); | ||
while (checksum.length < 6) { | ||
checksum = '0' + checksum; | ||
} | ||
return checksum; | ||
}, | ||
read: function(buffer) { | ||
var data = {}; | ||
var offset = 0; | ||
this.format.forEach(function(value) { | ||
data[value.field] = buffer.toString('utf8', offset, offset + (value.length - 1)).replace(/\u0000.*/, ''); | ||
offset += value.length; | ||
}); | ||
delete data.padding; | ||
return data; | ||
} | ||
}; | ||
tarArchiver.prototype._writeData = function(file, sourceBuffer) { | ||
@@ -104,9 +40,9 @@ var self = this; | ||
file.mode = utils.padNumber(file.mode, 7); | ||
file.uid = utils.padNumber(file.uid, 7); | ||
file.gid = utils.padNumber(file.gid, 7); | ||
file.size = utils.padNumber(fileSize, 11); | ||
file.mtime = utils.padNumber(file.mtime, 11); | ||
file.mode = util.padNumber(file.mode, 7); | ||
file.uid = util.padNumber(file.uid, 7); | ||
file.gid = util.padNumber(file.gid, 7); | ||
file.size = util.padNumber(fileSize, 11); | ||
file.mtime = util.padNumber(file.mtime, 11); | ||
var headerBuffer = header.create(file); | ||
var headerBuffer = headers.file.toBuffer(file); | ||
@@ -120,3 +56,3 @@ self.queue.push(headerBuffer); | ||
var extraBytes = self.recordSize - (fileSize % self.recordSize || self.recordSize); | ||
var extraBytesBuffer = utils.cleanBuffer(extraBytes); | ||
var extraBytesBuffer = util.cleanBuffer(extraBytes); | ||
self.queue.push(extraBytesBuffer); | ||
@@ -133,12 +69,16 @@ self.fileptr += extraBytesBuffer.length; | ||
if (util.lo.isFunction(callback) === false) { | ||
callback = util.fallCall; | ||
} | ||
if (self.busy) { | ||
self.emit('error', 'previous file not finished'); | ||
callback(new Error('Previous file not finished')); | ||
return; | ||
} | ||
if (utils.lo.isString(source)) { | ||
if (util.lo.isString(source)) { | ||
source = new Buffer(source, 'utf8'); | ||
} | ||
var file = utils.lo.defaults(data || {}, { | ||
var file = util.lo.defaults(data || {}, { | ||
name: null, | ||
@@ -153,8 +93,8 @@ comment: '', | ||
if (utils.lo.isEmpty(file.name) || utils.lo.isString(file.name) === false) { | ||
self.emit('error', 'name must be a valid string value'); | ||
if (util.lo.isEmpty(file.name) || util.lo.isString(file.name) === false) { | ||
callback(new Error('File name is empty or not a valid string value')); | ||
return; | ||
} | ||
file.name = utils.unixifyPath(file.name); | ||
file.name = util.unixifyPath(file.name); | ||
@@ -168,17 +108,17 @@ if (file.name.substring(0, 1) === '/') { | ||
if (utils.lo.isDate(file.date)) { | ||
if (util.lo.isDate(file.date)) { | ||
file.date = file.date; | ||
} else if (utils.lo.isString(file.date)) { | ||
} else if (util.lo.isString(file.date)) { | ||
file.date = new Date(file.date); | ||
} else if (utils.lo.isNumber(file.mtime) === false) { | ||
} else if (util.lo.isNumber(file.mtime) === false) { | ||
file.date = new Date(); | ||
} | ||
if (utils.lo.isNumber(file.mtime) === false) { | ||
file.mtime = utils.octalDateTime(file.date); | ||
if (util.lo.isNumber(file.mtime) === false) { | ||
file.mtime = util.octalDateTime(file.date); | ||
} | ||
file.gid = utils.lo.isNumber(file.gid) ? file.gid : 0; | ||
file.mode = utils.lo.isNumber(file.mode) ? file.mode : parseInt('777', 8) & 0xfff; | ||
file.uid = utils.lo.isNumber(file.uid) ? file.uid : 0; | ||
file.gid = util.lo.isNumber(file.gid) ? file.gid : 0; | ||
file.mode = util.lo.isNumber(file.mode) ? file.mode : parseInt('777', 8) & 0xfff; | ||
file.uid = util.lo.isNumber(file.uid) ? file.uid : 0; | ||
@@ -201,7 +141,7 @@ self.busy = true; | ||
process.nextTick(onEnd); | ||
} else { | ||
utils.collectStream(source, function(error, buffer) { | ||
if (error) { | ||
self.emit('error', 'stream collection failed'); | ||
util.nextTick(onEnd); | ||
} else if (util.isStream(source)) { | ||
util.collectStream(source, function(err, buffer) { | ||
if (err) { | ||
self.emit('error', new Error('Stream collection failed')); | ||
return; | ||
@@ -213,7 +153,9 @@ } | ||
process.nextTick(onEnd); | ||
util.nextTick(onEnd); | ||
}); | ||
} else { | ||
callback(new Error('A valid Stream or Buffer instance is needed as input source')); | ||
} | ||
process.nextTick(function() { | ||
util.nextTick(function() { | ||
self._read(); | ||
@@ -226,4 +168,8 @@ }); | ||
if (util.lo.isFunction(callback) === false) { | ||
callback = util.fallCall; | ||
} | ||
if (self.files.length === 0) { | ||
self.emit('error', 'no files in tar'); | ||
callback(new Error('No files in archive')); | ||
return; | ||
@@ -233,3 +179,3 @@ } | ||
var endBytes = self.blockSize - (self.fileptr % self.blockSize); | ||
var endBytesBuffer = utils.cleanBuffer(endBytes); | ||
var endBytesBuffer = util.cleanBuffer(endBytes); | ||
@@ -241,2 +187,2 @@ self.queue.push(endBytesBuffer); | ||
self.eof = true; | ||
}; | ||
}; |
@@ -0,6 +1,15 @@ | ||
/** | ||
* node-archiver | ||
* | ||
* Copyright (c) 2012-2013 Chris Talkington, contributors. | ||
* Licensed under the MIT license. | ||
* https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT | ||
*/ | ||
var inherits = require('util').inherits; | ||
var zlib = require('zlib'); | ||
var Archiver = require('./core.js'); | ||
var utils = require('../util/utils'); | ||
var Archiver = require('./core'); | ||
var headers = require('../headers/zip'); | ||
var util = require('../util'); | ||
@@ -12,3 +21,3 @@ var zipArchiver = module.exports = function(options) { | ||
options = self.options = utils.lo.defaults(options || {}, { | ||
options = self.options = util.lo.defaults(options || {}, { | ||
comment: '', | ||
@@ -21,3 +30,3 @@ forceUTC: false, | ||
if (utils.lo.isNumber(options.level)) { | ||
if (util.lo.isNumber(options.level)) { | ||
options.zlib.level = options.level; | ||
@@ -30,184 +39,2 @@ delete options.level; | ||
var fileHeader = { | ||
format: [ | ||
{'field': 'signature', 'length': 4, 'type': 'UInt32LE', 'default': 0x04034b50}, | ||
{'field': 'versionNeededToExtract', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'flags', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'compressionMethod', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'lastModifiedDate', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'crc32', 'length': 4, 'type': 'Int32LE', 'default': 0}, | ||
{'field': 'compressedSize', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'uncompressedSize', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'filenameLength', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'extraFieldLength', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'name', 'length': -1, 'type': 'string'}, | ||
{'field': 'extraField', 'length': -1, 'type': 'string'} | ||
], | ||
create: function(data) { | ||
var buffer = new Buffer(1024); | ||
var offset = 0; | ||
var val; | ||
var fallback; | ||
this.format.forEach(function(value) { | ||
fallback = (value.type === 'string') ? '' : 0; | ||
val = data[value.field] || value.default || fallback; | ||
if (value.field === 'name') { | ||
value.length = buffer.write(val, offset); | ||
buffer.writeUInt16LE(value.length, 26); | ||
} else if (value.field === 'extraField') { | ||
value.length = (val.length > 0) ? buffer.write(val, offset) : 0; | ||
buffer.writeUInt16LE(value.length, 28); | ||
} else if (value.type === 'UInt32LE') { | ||
buffer.writeUInt32LE(val, offset); | ||
} else if (value.type === 'Int32LE') { | ||
buffer.writeInt32LE(val, offset); | ||
} else if (value.type === 'UInt16LE') { | ||
buffer.writeUInt16LE(val, offset); | ||
} else { | ||
buffer.write(val, offset); | ||
} | ||
offset += value.length; | ||
}); | ||
return buffer.slice(0, offset); | ||
} | ||
}; | ||
var dataDescriptorHeader = { | ||
format: [ | ||
{'field': 'signature', 'length': 4, 'type': 'UInt32LE', 'default': 0x08074b50}, | ||
{'field': 'crc32', 'length': 4, 'type': 'Int32LE'}, | ||
{'field': 'compressedSize', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'uncompressedSize', 'length': 4, 'type': 'UInt32LE'} | ||
], | ||
create: function(data) { | ||
var buffer = new Buffer(16); | ||
var offset = 0; | ||
var val; | ||
this.format.forEach(function(value) { | ||
val = data[value.field] || value.default || 0; | ||
if (value.type === 'UInt32LE') { | ||
buffer.writeUInt32LE(val, offset); | ||
} else if (value.type === 'Int32LE') { | ||
buffer.writeInt32LE(val, offset); | ||
} | ||
offset += value.length; | ||
}); | ||
return buffer; | ||
} | ||
}; | ||
var centralDirectoryHeader = { | ||
format: [ | ||
{'field': 'signature', 'length': 4, 'type': 'UInt32LE', 'default': 0x02014b50}, | ||
{'field': 'versionMadeBy', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'versionNeededToExtract', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'flags', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'compressionMethod', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'lastModifiedDate', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'crc32', 'length': 4, 'type': 'Int32LE'}, | ||
{'field': 'compressedSize', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'uncompressedSize', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'filenameLength', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'extraFieldLength', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'commentLength', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'diskNumberStart', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'internalFileAttributes', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'externalFileAttributes', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'offset', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'name', 'length': -1, 'type': 'string'}, | ||
{'field': 'extraField', 'length': -1, 'type': 'string'}, | ||
{'field': 'comment', 'length': -1, 'type': 'string'} | ||
], | ||
create: function(data) { | ||
var buffer = new Buffer(1024); | ||
var offset = 0; | ||
var val; | ||
var fallback; | ||
var nameLength; | ||
this.format.forEach(function(value) { | ||
fallback = (value.type === 'string') ? '' : 0; | ||
val = data[value.field] || value.default || fallback; | ||
if (value.field === 'name') { | ||
value.length = buffer.write(val, offset); | ||
buffer.writeUInt16LE(value.length, 28); | ||
} else if (value.field === 'extraField') { | ||
value.length = (val.length > 0) ? buffer.write(val, offset) : 0; | ||
buffer.writeUInt16LE(value.length, 30); | ||
} else if (value.field === 'comment') { | ||
value.length = (val.length > 0) ? buffer.write(val, offset) : 0; | ||
buffer.writeUInt16LE(value.length, 32); | ||
} else if (value.type === 'UInt32LE') { | ||
buffer.writeUInt32LE(val, offset); | ||
} else if (value.type === 'Int32LE') { | ||
buffer.writeInt32LE(val, offset); | ||
} else if (value.type === 'UInt16LE') { | ||
buffer.writeUInt16LE(val, offset); | ||
} else { | ||
buffer.write(val, offset); | ||
} | ||
offset += value.length; | ||
}); | ||
return buffer.slice(0, offset); | ||
} | ||
}; | ||
var centralDirectoryFooter = { | ||
format: [ | ||
{'field': 'signature', 'length': 4, 'type': 'UInt32LE', 'default': 0x06054b50}, | ||
{'field': 'diskNumber', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'diskNumberStart', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'directoryRecordsDisk', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'directoryRecords', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'directorySize', 'length': 4, 'type': 'UInt32LE'}, | ||
{'field': 'directoryOffset', 'length': 4, 'type': 'UInt32LE'},, | ||
{'field': 'commentLength', 'length': 2, 'type': 'UInt16LE'}, | ||
{'field': 'comment', 'length': -1, 'type': 'string'} | ||
], | ||
create: function(data) { | ||
var buffer = new Buffer(512); | ||
var offset = 0; | ||
var val; | ||
var fallback; | ||
this.format.forEach(function(value) { | ||
fallback = (value.type === 'string') ? '' : 0; | ||
val = data[value.field] || value.default || fallback; | ||
if (value.field === 'comment') { | ||
value.length = (val.length > 0) ? buffer.write(val, offset) : 0; | ||
buffer.writeUInt16LE(value.length, 20); | ||
} else if (value.type === 'UInt32LE') { | ||
buffer.writeUInt32LE(val, offset); | ||
} else if (value.type === 'Int32LE') { | ||
buffer.writeInt32LE(val, offset); | ||
} else if (value.type === 'UInt16LE') { | ||
buffer.writeUInt16LE(val, offset); | ||
} else { | ||
buffer.write(val, offset); | ||
} | ||
offset += value.length; | ||
}); | ||
return buffer.slice(0, offset); | ||
} | ||
}; | ||
// local file header | ||
@@ -219,3 +46,3 @@ zipArchiver.prototype._pushLocalFileHeader = function(file) { | ||
var fileHeaderBuffer = fileHeader.create(file); | ||
var fileHeaderBuffer = headers.file.toBuffer(file); | ||
@@ -229,3 +56,3 @@ self.queue.push(fileHeaderBuffer); | ||
var dataDescriptorBuffer = dataDescriptorHeader.create(file); | ||
var dataDescriptorBuffer = headers.descriptor.toBuffer(file); | ||
@@ -248,3 +75,3 @@ self.queue.push(dataDescriptorBuffer); | ||
centralDirectoryBuffer = centralDirectoryHeader.create(file); | ||
centralDirectoryBuffer = headers.centralHeader.toBuffer(file); | ||
@@ -265,3 +92,3 @@ self.queue.push(centralDirectoryBuffer); | ||
var centralDirectoryFooterBuffer = centralDirectoryFooter.create(centralDirectoryFooterData); | ||
var centralDirectoryFooterBuffer = headers.centralFooter.toBuffer(centralDirectoryFooterData); | ||
@@ -276,12 +103,16 @@ self.queue.push(centralDirectoryFooterBuffer); | ||
if (util.lo.isFunction(callback) === false) { | ||
callback = util.fallCall; | ||
} | ||
if (self.busy) { | ||
self.emit('error', 'previous file not finished'); | ||
callback(new Error('Previous file not finished')); | ||
return; | ||
} | ||
if (utils.lo.isString(source)) { | ||
if (util.lo.isString(source)) { | ||
source = new Buffer(source, 'utf-8'); | ||
} | ||
var file = utils.lo.defaults(data || {}, { | ||
var file = util.lo.defaults(data || {}, { | ||
name: null, | ||
@@ -295,8 +126,8 @@ comment: '', | ||
if (utils.lo.isEmpty(file.name) || utils.lo.isString(file.name) === false) { | ||
self.emit('error', 'name must be a valid string value'); | ||
if (util.lo.isEmpty(file.name) || util.lo.isString(file.name) === false) { | ||
callback(new Error('File name is empty or not a valid string value')); | ||
return; | ||
} | ||
file.name = utils.unixifyPath(file.name); | ||
file.name = util.unixifyPath(file.name); | ||
@@ -307,12 +138,12 @@ if (file.name.substring(0, 1) === '/') { | ||
if (utils.lo.isDate(file.date)) { | ||
if (util.lo.isDate(file.date)) { | ||
file.date = file.date; | ||
} else if (utils.lo.isString(file.date)) { | ||
} else if (util.lo.isString(file.date)) { | ||
file.date = new Date(file.date); | ||
} else if (utils.lo.isNumber(file.lastModifiedDate) === false) { | ||
} else if (util.lo.isNumber(file.lastModifiedDate) === false) { | ||
file.date = new Date(); | ||
} | ||
if (utils.lo.isNumber(file.lastModifiedDate) === false) { | ||
file.lastModifiedDate = utils.dosDateTime(file.date, self.options.forceUTC); | ||
if (util.lo.isNumber(file.lastModifiedDate) === false) { | ||
file.lastModifiedDate = util.dosDateTime(file.date, self.options.forceUTC); | ||
} | ||
@@ -331,3 +162,3 @@ | ||
var checksum = utils.crc32.createCRC32(); | ||
var checksum = util.crc32.createCRC32(); | ||
@@ -358,3 +189,3 @@ function onEnd() { | ||
self.queue.push(source); | ||
process.nextTick(onEnd); | ||
util.nextTick(onEnd); | ||
} else { | ||
@@ -383,4 +214,3 @@ // Assume stream | ||
deflate.end(); | ||
} else { | ||
// Assume stream | ||
} else if (util.isStream(source)) { | ||
source.on('data', function(chunk) { | ||
@@ -390,9 +220,12 @@ update(chunk); | ||
}); | ||
source.on('end', function() { | ||
deflate.end(); | ||
}); | ||
} else { | ||
callback(new Error('A valid Stream or Buffer instance is needed as input source')); | ||
} | ||
} | ||
process.nextTick(function() { | ||
util.nextTick(function() { | ||
self._read(); | ||
@@ -405,4 +238,8 @@ }); | ||
if (util.lo.isFunction(callback) === false) { | ||
callback = util.fallCall; | ||
} | ||
if (self.files.length === 0) { | ||
self.emit('error', 'no files in zip'); | ||
callback(new Error('No files in archive')); | ||
return; | ||
@@ -414,2 +251,2 @@ } | ||
self.eof = true; | ||
}; | ||
}; |
@@ -1,21 +0,9 @@ | ||
// crc32 functionality for zip | ||
/** | ||
* node-archiver | ||
* | ||
* Copyright (c) 2012-2013 Chris Talkington, contributors. | ||
* Licensed under the MIT license. | ||
* https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT | ||
*/ | ||
exports.createCRC32 = function() { | ||
return new CRC32(); | ||
}; | ||
function CRC32() { | ||
this.crc = ~0; | ||
} | ||
CRC32.prototype.update = function(buf) { | ||
for (var i=0; i<buf.length; i++) { | ||
this.crc = (this.crc >>> 8) ^ lookup[(this.crc ^ buf[i]) & 0xff]; | ||
} | ||
}; | ||
CRC32.prototype.digest = function() { | ||
return this.crc ^ -1; | ||
}; | ||
var lookup = [ | ||
@@ -86,2 +74,20 @@ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, | ||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | ||
]; | ||
]; | ||
function CRC32() { | ||
this.crc = ~0; | ||
} | ||
CRC32.prototype.update = function(buffer) { | ||
for (var i = 0; i < buffer.length; i++) { | ||
this.crc = (this.crc >>> 8) ^ lookup[(this.crc ^ buffer[i]) & 0xff]; | ||
} | ||
}; | ||
CRC32.prototype.digest = function() { | ||
return this.crc ^ -1; | ||
}; | ||
exports.createCRC32 = function() { | ||
return new CRC32(); | ||
}; |
{ | ||
"name": "archiver", | ||
"version": "0.2.2", | ||
"version": "0.3.0", | ||
"description": "Creates Archives (ZIP) via Node Streams.", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/ctalkington/node-archiver", |
@@ -1,4 +0,4 @@ | ||
# Archiver [](http://travis-ci.org/ctalkington/node-archiver) | ||
# Archiver v0.3.0 [](http://travis-ci.org/ctalkington/node-archiver) | ||
Creates Archives (ZIP, TAR) via Node Streams. Depends on Node's build-in zlib module for compression available since version 0.6.3. | ||
Creates Archives (Zip, Tar) via Node Streams. Depends on Node's build-in zlib module for compression available since version 0.6.3. | ||
@@ -13,20 +13,30 @@ ## Install | ||
## API | ||
## Core | ||
#### addFile(inputStream, data, callback) | ||
### Methods | ||
Adds a file to the Archiver stream. | ||
#### create(type, options) | ||
#### finalize(callback(written)) | ||
Creates an Archiver instance based on the type (ie zip/tar) passed. | ||
Finalizes the Archiver stream. When everything is done, callback is called with the total number of bytes in the archive. | ||
#### createZip(options) | ||
## Zip | ||
Creates an Archiver Zip instance. | ||
### Methods | ||
#### createTar(options) | ||
#### createZip(options) | ||
Creates an Archiver Tar instance. | ||
Creates an Archiver ZIP object. | ||
### Instance Methods | ||
#### addFile(input, data, callback(err)) | ||
Adds a file to the instance. Input can be in the form of a text string, buffer, or stream. When the instance has received, processed, and emitted the input, the callback is fired. | ||
#### finalize(callback(err, bytesWritten)) | ||
Finalizes the instance. When the instance's stream has finished emitting, the callback is fired. | ||
## Zip | ||
### Options | ||
@@ -36,7 +46,7 @@ | ||
Sets zip comment. | ||
Sets the zip comment. | ||
#### forceUTC `boolean` | ||
If true, forces file date and time to UTC. Helps with testing across timezones. | ||
If true, forces the file date and time to UTC. Helps with testing across timezones. | ||
@@ -51,29 +61,27 @@ #### zlib `object` | ||
Sets file name. | ||
Sets the file name including internal path. | ||
#### date `string` | ||
#### date `string|Date` | ||
Sets file date. | ||
Sets the file date. This can be any valid date string or object. Defaults to current time in locale. | ||
#### store `boolean` | ||
If true, zip contents will be stored without compression. | ||
If true, file contents will be stored without compression. | ||
#### comment `string` | ||
Sets file comment. | ||
Sets the file comment. | ||
## Tar (beta) | ||
### Methods | ||
### Options | ||
#### createTar(options) | ||
#### recordSize `number` | ||
Creates an Archiver Tar object. *in testing* | ||
Sets the size (in bytes) of each record in a block, default is 512 (for advanced users only). | ||
### Options | ||
#### recordsPerBlock `number` | ||
Sets number of records in a block, default is 20 (for advanced users only). | ||
Sets the number of records in a block, default is 20 (for advanced users only). | ||
@@ -84,27 +92,31 @@ ### File Data | ||
Sets file name. | ||
Sets the file name including internal path. | ||
#### date `string` | ||
#### date `string|Date` | ||
Sets file date. | ||
Sets the file date. This can be any valid date string or object. Defaults to current time in locale. | ||
## Examples | ||
Here are a few examples to get you started. | ||
Here are a few examples to get you started. All examples use the [async module](https://github.com/caolan/async) to avoid deep nesting of callbacks. | ||
* [basic packing](https://github.com/ctalkington/node-archiver/blob/master/examples/pack.js) | ||
* [basic packing with async module](https://github.com/ctalkington/node-archiver/blob/master/examples/pack-async.js) | ||
* [tar packing wtih gzip](https://github.com/ctalkington/node-archiver/blob/master/examples/pack-tar-gzip.js) | ||
* [tar packing with gzip](https://github.com/ctalkington/node-archiver/blob/master/examples/pack-tgz.js) | ||
Take a peek at the [examples](https://github.com/ctalkington/node-archiver/blob/master/example) folder for a complete listing. | ||
Take a peek at the [examples](https://github.com/ctalkington/node-archiver/blob/master/examples) folder for a complete listing. | ||
## Contributing | ||
see [CONTRIBUTING](https://github.com/ctalkington/node-archiver/blob/master/CONTRIBUTING.md) | ||
see [CONTRIBUTING](https://github.com/ctalkington/node-archiver/blob/master/CONTRIBUTING.md). | ||
## Changelog | ||
see [CHANGELOG](https://github.com/ctalkington/node-archiver/blob/master/CHANGELOG) | ||
see [CHANGELOG](https://github.com/ctalkington/node-archiver/blob/master/CHANGELOG). | ||
## Credits | ||
Originally inspired by Antoine van Wel's [node-zipstream](https://github.com/wellawaretech/node-zipstream). | ||
Originally inspired by Antoine van Wel's [node-zipstream](https://github.com/wellawaretech/node-zipstream). | ||
## Licensing | ||
This project's code is licensed under the MIT license. see [LICENSE-MIT](https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT). |
@@ -1,2 +0,2 @@ | ||
var utils = require('../lib/util/utils'); | ||
var util = require('../lib/util'); | ||
@@ -27,7 +27,7 @@ var date1 = new Date('Jan 03 2013 14:26:38 GMT'); | ||
var actual = utils.octalDateTime(date1); | ||
var actual = util.octalDateTime(date1); | ||
var expected = octal1; | ||
test.equal(actual, expected); | ||
actual = utils.octalDateTime(date2); | ||
actual = util.octalDateTime(date2); | ||
expected = octal2; | ||
@@ -42,7 +42,7 @@ test.equal(actual, expected); | ||
var actual = utils.convertDateTimeOctal(octal1).toUTCString(); | ||
var actual = util.convertDateTimeOctal(octal1).toUTCString(); | ||
var expected = date1.toUTCString(); | ||
test.equal(actual, expected); | ||
actual = utils.convertDateTimeOctal(octal2).toUTCString(); | ||
actual = util.convertDateTimeOctal(octal2).toUTCString(); | ||
expected = date2.toUTCString(); | ||
@@ -57,7 +57,7 @@ test.equal(actual, expected); | ||
var actual = utils.dosDateTime(date1, true); | ||
var actual = util.dosDateTime(date1, true); | ||
var expected = dos1; | ||
test.equal(actual, expected); | ||
actual = utils.dosDateTime(date2, true); | ||
actual = util.dosDateTime(date2, true); | ||
expected = dos2; | ||
@@ -72,7 +72,7 @@ test.equal(actual, expected); | ||
var actual = adjustByOffset(utils.convertDateTimeDos(dos1)).toUTCString(); | ||
var actual = adjustByOffset(util.convertDateTimeDos(dos1)).toUTCString(); | ||
var expected = date1.toUTCString(); | ||
test.equal(actual, expected); | ||
actual = adjustByOffset(utils.convertDateTimeDos(dos2)).toUTCString(); | ||
actual = adjustByOffset(util.convertDateTimeDos(dos2)).toUTCString(); | ||
expected = date2.toUTCString(); | ||
@@ -79,0 +79,0 @@ test.equal(actual, expected); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
47163
8.25%20
5.26%1193
9.05%118
11.32%5
-16.67%