Comparing version 0.2.2 to 0.3.0
@@ -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 [![Build Status](https://secure.travis-ci.org/ctalkington/node-archiver.png?branch=master)](http://travis-ci.org/ctalkington/node-archiver) | ||
# Archiver v0.3.0 [![Build Status](https://secure.travis-ci.org/ctalkington/node-archiver.png?branch=master)](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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47163
20
1193
118
5