First working end-to-end unzip test passing
This commit is contained in:
parent
5a13dbfa4d
commit
3411ba2dd3
|
@ -42,16 +42,9 @@ define(function(require) {
|
||||||
|
|
||||||
var Inflater = require("zip.js/inflate");
|
var Inflater = require("zip.js/inflate");
|
||||||
var Deflater = require("zip.js/deflate");
|
var Deflater = require("zip.js/deflate");
|
||||||
|
|
||||||
var TEXT_PLAIN = "text/plain";
|
|
||||||
|
|
||||||
var MESSAGE_EVENT = "message";
|
|
||||||
|
|
||||||
var appendABViewSupported;
|
var TEXT_PLAIN = "text/plain";
|
||||||
try {
|
var MESSAGE_EVENT = "message";
|
||||||
appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
function Crc32() {
|
function Crc32() {
|
||||||
var crc = -1, that = this;
|
var crc = -1, that = this;
|
||||||
|
@ -78,17 +71,6 @@ define(function(require) {
|
||||||
return table;
|
return table;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function blobSlice(blob, index, length) {
|
|
||||||
if (blob.slice)
|
|
||||||
return blob.slice(index, index + length);
|
|
||||||
else if (blob.webkitSlice)
|
|
||||||
return blob.webkitSlice(index, index + length);
|
|
||||||
else if (blob.mozSlice)
|
|
||||||
return blob.mozSlice(index, index + length);
|
|
||||||
else if (blob.msSlice)
|
|
||||||
return blob.msSlice(index, index + length);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDataHelper(byteLength, bytes) {
|
function getDataHelper(byteLength, bytes) {
|
||||||
var dataBuffer, dataArray;
|
var dataBuffer, dataArray;
|
||||||
dataBuffer = new ArrayBuffer(byteLength);
|
dataBuffer = new ArrayBuffer(byteLength);
|
||||||
|
@ -103,171 +85,73 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readers
|
// Readers
|
||||||
function Reader() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function TextReader(text) {
|
// Filer fs-based File Reader, given a path and a fs instance
|
||||||
var that = this, blobReader;
|
function FileReader(path, fs) {
|
||||||
|
|
||||||
function init(callback, onerror) {
|
|
||||||
var blob = new Blob([ text ], {
|
|
||||||
type : TEXT_PLAIN
|
|
||||||
});
|
|
||||||
blobReader = new BlobReader(blob);
|
|
||||||
blobReader.init(function() {
|
|
||||||
that.size = blobReader.size;
|
|
||||||
callback();
|
|
||||||
}, onerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
function readUint8Array(index, length, callback, onerror) {
|
|
||||||
blobReader.readUint8Array(index, length, callback, onerror);
|
|
||||||
}
|
|
||||||
|
|
||||||
that.size = 0;
|
|
||||||
that.init = init;
|
|
||||||
that.readUint8Array = readUint8Array;
|
|
||||||
}
|
|
||||||
TextReader.prototype = new Reader();
|
|
||||||
TextReader.prototype.constructor = TextReader;
|
|
||||||
|
|
||||||
function Uint8Reader(u8) {
|
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
function init(callback, onerror) {
|
function init(callback, onerror) {
|
||||||
that.size = u8.length;
|
fs.stat(path, function(err, stats) {
|
||||||
callback();
|
if(err) return onerror(err);
|
||||||
|
|
||||||
|
that.size = stats.size;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getData(callback, onerror) {
|
||||||
|
if(that.data) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.readFile(path, function(err, data) {
|
||||||
|
if(err) return onerror(err);
|
||||||
|
that.data = data;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function readUint8Array(index, length, callback, onerror) {
|
function readUint8Array(index, length, callback, onerror) {
|
||||||
callback(new Uint8Array(u8.subarray(index, index + length)));
|
getData(function() {
|
||||||
|
callback(that.data.subarray(index, index + length));
|
||||||
|
}, onerror);
|
||||||
}
|
}
|
||||||
|
|
||||||
that.size = 0;
|
that.size = 0;
|
||||||
that.init = init;
|
that.init = init;
|
||||||
that.readUint8Array = readUint8Array;
|
that.readUint8Array = readUint8Array;
|
||||||
}
|
}
|
||||||
Uint8Reader.prototype = new Reader();
|
FileReader.prototype.checkCrc32 = false;
|
||||||
Uint8Reader.prototype.constructor = Uint8Reader;
|
|
||||||
|
|
||||||
function BlobReader(blob) {
|
// Filer fs-based File Writer
|
||||||
var that = this;
|
function FileWriter(path, fs, size) {
|
||||||
|
var that = this;
|
||||||
function init(callback) {
|
|
||||||
this.size = blob.size;
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function readUint8Array(index, length, callback, onerror) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.onload = function(e) {
|
|
||||||
callback(new Uint8Array(e.target.result));
|
|
||||||
};
|
|
||||||
reader.onerror = onerror;
|
|
||||||
reader.readAsArrayBuffer(blobSlice(blob, index, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
that.size = 0;
|
|
||||||
that.init = init;
|
|
||||||
that.readUint8Array = readUint8Array;
|
|
||||||
}
|
|
||||||
BlobReader.prototype = new Reader();
|
|
||||||
BlobReader.prototype.constructor = BlobReader;
|
|
||||||
|
|
||||||
// Writers
|
|
||||||
|
|
||||||
function Writer() {
|
|
||||||
}
|
|
||||||
Writer.prototype.getData = function(callback) {
|
|
||||||
callback(this.data);
|
|
||||||
};
|
|
||||||
|
|
||||||
function TextWriter(encoding) {
|
|
||||||
var that = this, blob;
|
|
||||||
|
|
||||||
function init(callback) {
|
|
||||||
blob = new Blob([], {
|
|
||||||
type : TEXT_PLAIN
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeUint8Array(array, callback) {
|
|
||||||
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
|
|
||||||
type : TEXT_PLAIN
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getData(callback, onerror) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.onload = function(e) {
|
|
||||||
callback(e.target.result);
|
|
||||||
};
|
|
||||||
reader.onerror = onerror;
|
|
||||||
reader.readAsText(blob, encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
that.init = init;
|
|
||||||
that.writeUint8Array = writeUint8Array;
|
|
||||||
that.getData = getData;
|
|
||||||
}
|
|
||||||
TextWriter.prototype = new Writer();
|
|
||||||
TextWriter.prototype.constructor = TextWriter;
|
|
||||||
|
|
||||||
function Uint8Writer() {
|
|
||||||
var that = this, u8;
|
|
||||||
|
|
||||||
function init(callback) {
|
function init(callback) {
|
||||||
u8 = new Uint8Array();
|
// TODO: Overwrite the file. Should we also have a way to fail if exists?
|
||||||
callback();
|
fs.unlink(path, function() {
|
||||||
}
|
callback();
|
||||||
|
});
|
||||||
function writeUint8Array(array, callback) {
|
|
||||||
var both = new Uint8Array(u8.length + array.length);
|
|
||||||
both.set(u8);
|
|
||||||
both.set(array, u8.length);
|
|
||||||
u8 = both;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getData(callback) {
|
function getData(callback) {
|
||||||
callback(u8);
|
callback(that.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
that.init = init;
|
function writeUint8Array(array, callback, onerror) {
|
||||||
|
fs.appendFile(path, array, function(err) {
|
||||||
|
if(err) return onerror(err);
|
||||||
|
that.data = array;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
that.size = size;
|
||||||
|
that.init = init;
|
||||||
that.writeUint8Array = writeUint8Array;
|
that.writeUint8Array = writeUint8Array;
|
||||||
that.getData = getData;
|
that.getData = getData;
|
||||||
}
|
}
|
||||||
Uint8Writer.prototype = new Writer();
|
|
||||||
Uint8Writer.prototype.constructor = Uint8Writer;
|
|
||||||
|
|
||||||
function BlobWriter(contentType) {
|
|
||||||
var blob, that = this;
|
|
||||||
|
|
||||||
function init(callback) {
|
|
||||||
blob = new Blob([], {
|
|
||||||
type : contentType
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeUint8Array(array, callback) {
|
|
||||||
blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
|
|
||||||
type : contentType
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getData(callback) {
|
|
||||||
callback(blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
that.init = init;
|
|
||||||
that.writeUint8Array = writeUint8Array;
|
|
||||||
that.getData = getData;
|
|
||||||
}
|
|
||||||
BlobWriter.prototype = new Writer();
|
|
||||||
BlobWriter.prototype.constructor = BlobWriter;
|
|
||||||
|
|
||||||
// inflate/deflate core functions
|
// inflate/deflate core functions
|
||||||
function launchProcess(process, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
|
function launchProcess(process, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
|
||||||
|
@ -309,7 +193,7 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function inflate(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
|
function inflate(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
|
||||||
var worker, crc32 = new Crc32();
|
var crc32 = new Crc32();
|
||||||
|
|
||||||
function oninflateappend(sending, array) {
|
function oninflateappend(sending, array) {
|
||||||
if (computeCrc32 && !sending)
|
if (computeCrc32 && !sending)
|
||||||
|
@ -321,11 +205,11 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
|
|
||||||
launchProcess(new Inflater(), reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
|
launchProcess(new Inflater(), reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
|
||||||
return worker;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deflate(reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
|
function deflate(reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
|
||||||
var worker, crc32 = new Crc32();
|
var crc32 = new Crc32();
|
||||||
|
|
||||||
function ondeflateappend(sending, array) {
|
function ondeflateappend(sending, array) {
|
||||||
if (sending)
|
if (sending)
|
||||||
|
@ -337,7 +221,7 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
|
|
||||||
launchProcess(new Deflater(), reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
|
launchProcess(new Deflater(), reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
|
||||||
return worker;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function copy(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
|
function copy(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
|
||||||
|
@ -472,7 +356,10 @@ define(function(require) {
|
||||||
readCommonHeader(that, data, 4, false, onerror);
|
readCommonHeader(that, data, 4, false, onerror);
|
||||||
dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
|
dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
|
||||||
writer.init(function() {
|
writer.init(function() {
|
||||||
copy(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
|
if (that.compressionMethod === 0)
|
||||||
|
copy(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
|
||||||
|
else
|
||||||
|
inflate(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
|
||||||
}, onwriteerror);
|
}, onwriteerror);
|
||||||
}, onreaderror);
|
}, onreaderror);
|
||||||
};
|
};
|
||||||
|
@ -676,14 +563,8 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Reader : Reader,
|
FileReader : FileReader,
|
||||||
Writer : Writer,
|
FileWriter : FileWriter,
|
||||||
BlobReader : BlobReader,
|
|
||||||
Uint8Reader : Uint8Reader,
|
|
||||||
TextReader : TextReader,
|
|
||||||
BlobWriter : BlobWriter,
|
|
||||||
Uint8Writer : Uint8Writer,
|
|
||||||
TextWriter : TextWriter,
|
|
||||||
createReader : function(reader, callback, onerror) {
|
createReader : function(reader, callback, onerror) {
|
||||||
reader.init(function() {
|
reader.init(function() {
|
||||||
callback(createZipReader(reader, onerror));
|
callback(createZipReader(reader, onerror));
|
||||||
|
|
|
@ -476,6 +476,44 @@ define(function(require) {
|
||||||
request.send();
|
request.send();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Shell.prototype.unzip = function(path, options, callback) {
|
||||||
|
var fs = this.fs;
|
||||||
|
if(typeof options === 'function') {
|
||||||
|
callback = options;
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
options = options || {};
|
||||||
|
callback = callback || function(){};
|
||||||
|
|
||||||
|
if(!path) {
|
||||||
|
callback(new Errors.EINVAL('missing path argument'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = Path.resolve(this.cwd, path);
|
||||||
|
var destination = Path.resolve(options.destination || this.cwd);
|
||||||
|
|
||||||
|
var Zip = require('zip.js/zip');
|
||||||
|
Zip.createReader(new Zip.FileReader(path, fs), function(reader) {
|
||||||
|
reader.getEntries(function(entries) {
|
||||||
|
|
||||||
|
function inflate(entry, callback) {
|
||||||
|
var path = Path.join(destination, entry.filename);
|
||||||
|
if(entry.directory) {
|
||||||
|
this.mkdirp(path, callback);
|
||||||
|
} else {
|
||||||
|
entry.getData(new Zip.FileWriter(path, fs, entry.uncompressedSize), function() { callback(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async.eachSeries(entries, inflate, function(error) {
|
||||||
|
if(error) return callback(error);
|
||||||
|
reader.close(callback);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, callback);
|
||||||
|
};
|
||||||
|
|
||||||
return Shell;
|
return Shell;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
define(["Filer", "util"], function(Filer, util) {
|
||||||
|
|
||||||
|
describe('FileSystemShell.unzip', function() {
|
||||||
|
beforeEach(util.setup);
|
||||||
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
|
it('should be a function', function() {
|
||||||
|
var shell = util.shell();
|
||||||
|
expect(shell.unzip).to.be.a('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when path argument is absent', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
var shell = fs.Shell();
|
||||||
|
|
||||||
|
shell.unzip(null, function(err) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should download and unzip the contents of a zip file', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
var shell = fs.Shell();
|
||||||
|
var url = "test-file.txt.zip";
|
||||||
|
var contents = "This is a test file used in some of the tests.\n";
|
||||||
|
|
||||||
|
fs.writeFile('/original', contents, function(err) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
shell.wget(url, {filename: url}, function(err, path) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
shell.unzip(path, function(err) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
fs.readFile('/original', function(err, originalData) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
|
||||||
|
fs.readFile('/test-file.txt', function(err, data) {
|
||||||
|
if(err) throw err;
|
||||||
|
expect(util.typedArrayEqual(data, originalData)).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
Binary file not shown.
|
@ -58,6 +58,7 @@ define([
|
||||||
"spec/shell/env.spec",
|
"spec/shell/env.spec",
|
||||||
"spec/shell/mkdirp.spec",
|
"spec/shell/mkdirp.spec",
|
||||||
"spec/shell/wget.spec",
|
"spec/shell/wget.spec",
|
||||||
|
"spec/shell/unzip.spec",
|
||||||
|
|
||||||
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
||||||
"spec/node-js/simple/test-fs-mkdir",
|
"spec/node-js/simple/test-fs-mkdir",
|
||||||
|
|
Loading…
Reference in New Issue