diff --git a/archive.js b/archive.js index 5d6da09..5053e94 100644 --- a/archive.js +++ b/archive.js @@ -65,19 +65,10 @@ bitjs.inherits = function(childCtor, parentCtor) { bitjs.archive.UnarchiveEvent = function(type) { /** * The event type. + * * @type {string} - * @private */ - this.type_ = type; -}; - -/** - * Returns the event type. - * - * @return {string} the event type. - */ -bitjs.archive.UnarchiveEvent.prototype.getType = function() { - return this.type_; + this.type = type; }; /** @@ -88,9 +79,47 @@ bitjs.archive.UnarchiveEvent.Type = { PROGRESS: 'progress', EXTRACT: 'extract', FINISH: 'finish', + INFO: 'info', ERROR: 'error' }; +/** + * Useful for passing info up to the client (for debugging). + * + * @param {string} msg The info message. + */ +bitjs.archive.UnarchiveInfoEvent = function(msg) { + bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.INFO); + + /** + * The information message. + * + * @type {string} + */ + this.msg = msg; +}; +bitjs.inherits(bitjs.archive.UnarchiveInfoEvent, bitjs.archive.UnarchiveEvent); + +/** + * Start event. + * + * @param {string} msg The info message. + */ +bitjs.archive.UnarchiveStartEvent = function() { + bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.START); +}; +bitjs.inherits(bitjs.archive.UnarchiveStartEvent, bitjs.archive.UnarchiveEvent); + +/** + * Finish event. + * + * @param {string} msg The info message. + */ +bitjs.archive.UnarchiveFinishEvent = function() { + bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.FINISH); +}; +bitjs.inherits(bitjs.archive.UnarchiveFinishEvent, bitjs.archive.UnarchiveEvent); + /** * All extracted files returned by an Unarchiver will implement * the following interface: @@ -139,7 +168,7 @@ bitjs.archive.Unarchiver.prototype.worker_ = null; * @protected. */ bitjs.archive.Unarchiver.prototype.getScriptFileName = function() { - throw "Subclasses of AbstractUnarchiver must overload getScriptFileName()"; + throw 'Subclasses of AbstractUnarchiver must overload getScriptFileName()'; }; /** @@ -179,7 +208,7 @@ bitjs.archive.Unarchiver.prototype.removeEventListener = function(type, listener */ bitjs.archive.Unarchiver.prototype.handleWorkerEvent_ = function(e) { if (e instanceof bitjs.archive.UnarchiveEvent) { - var listeners = this.listeners_[e.getType()]; + var listeners = this.listeners_[e.type]; if (listeners instanceof Array) { listeners.forEach(function (listener) { listener(e) }); } @@ -192,17 +221,23 @@ bitjs.archive.Unarchiver.prototype.handleWorkerEvent_ = function(e) { * Starts the unarchive in a separate Web Worker thread and returns immediately. */ bitjs.archive.Unarchiver.prototype.start = function() { + var me = this; var scriptFileName = this.getScriptFileName(); if (scriptFileName) { this.worker_ = new Worker(scriptFileName); this.worker_.onerror = function(e) { - alert("Worker error: " + e.message); + console.log('Worker error: message = ' + e.message); throw e; }; this.worker_.onmessage = function(e) { - alert("Worker onmessage: " + e); + if (e instanceof bitjs.archive.UnarchiveEvent) { + me.handleWorkerEvent_(e.data); + } else if (typeof e.data == 'string') { + // Just log any strings the workers pump our way. + console.log(e.data); + } }; this.worker_.postMessage({file: this.ab}); @@ -218,7 +253,7 @@ bitjs.archive.Unzipper = function(arrayBuffer) { bitjs.base(this, arrayBuffer); }; bitjs.inherits(bitjs.archive.Unzipper, bitjs.archive.Unarchiver); -bitjs.archive.Unzipper.prototype.getScriptFileName = function() { return "unzip.js" }; +bitjs.archive.Unzipper.prototype.getScriptFileName = function() { return 'unzip.js' }; })(); \ No newline at end of file diff --git a/drive.html b/drive.html index a1aefd1..851e783 100644 --- a/drive.html +++ b/drive.html @@ -48,6 +48,7 @@ // unit tests // testAddRemoveEventListeners(); // testAbstractUnarchiveThrows(); +// var uz = new bitjs.archive.Unzipper(null); document.body.querySelector("#filechooser").addEventListener("change", function(evt) { @@ -58,12 +59,14 @@ var fr = new FileReader(); fr.onload = function() { var ua = new bitjs.archive.Unzipper(fr.result); + ua.addEventListener(bitjs.archive.UnarchiveEvent.Type.INFO, function(e) { + console.log("handler: " + e.msg); + }) ua.start(); }; fr.readAsArrayBuffer(blob); } }, false); - var uz = new bitjs.archive.Unzipper(null); \ No newline at end of file diff --git a/unrar.js b/unrar.js index cfd109d..0f82015 100644 --- a/unrar.js +++ b/unrar.js @@ -11,6 +11,12 @@ // This file expects to be invoked as a Worker (see onmessage below). importScripts('binary.js'); +importScripts('archive.js'); + +// Helper function. +var info = function(str) { + postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); +}; // Volume Types var MARK_HEAD = 0x72, @@ -31,17 +37,17 @@ var RarVolumeHeader = function(bstream, bDebug) { var headPos = bstream.bytePtr; // byte 1,2 - postMessage("Rar Volume Header @"+bstream.bytePtr); + info("Rar Volume Header @"+bstream.bytePtr); this.crc = bstream.readBits(16); //console.log(this.crc); if (bDebug) - postMessage(" crc=" + this.crc); + info(" crc=" + this.crc); // byte 3 this.headType = bstream.readBits(8); if (bDebug) - postMessage(" headType=" + this.headType); + info(" headType=" + this.headType); // Get flags // bytes 4,5 @@ -49,7 +55,7 @@ var RarVolumeHeader = function(bstream, bDebug) { this.flags.value = bstream.peekBits(16); if (bDebug) - postMessage(" flags=" + twoByteValueToHexString(this.flags.value)); + info(" flags=" + twoByteValueToHexString(this.flags.value)); switch (this.headType) { case MAIN_HEAD: this.flags.MHD_VOLUME = !!bstream.readBits(1); @@ -80,7 +86,7 @@ var RarVolumeHeader = function(bstream, bDebug) { this.flags.LHD_EXTFLAGS = !!bstream.readBits(1); // 0x2000 bstream.readBits(2); // unused if (bDebug) - postMessage(" LHD_SPLIT_BEFORE = " + this.flags.LHD_SPLIT_BEFORE); + info(" LHD_SPLIT_BEFORE = " + this.flags.LHD_SPLIT_BEFORE); break; default: bstream.readBits(16); @@ -89,7 +95,7 @@ var RarVolumeHeader = function(bstream, bDebug) { // byte 6,7 this.headSize = bstream.readBits(16); if (bDebug) - postMessage(" headSize=" + this.headSize); + info(" headSize=" + this.headSize); switch (this.headType) { case MAIN_HEAD: this.highPosAv = bstream.readBits(16); @@ -97,7 +103,7 @@ var RarVolumeHeader = function(bstream, bDebug) { if (this.flags.MHD_ENCRYPTVER) this.encryptVer = bstream.readBits(8); if (this.debug) - postMessage("Found MAIN_HEAD with highPosAv=" + this.highPosAv + ", posAv=" + this.posAv); + info("Found MAIN_HEAD with highPosAv=" + this.highPosAv + ", posAv=" + this.posAv); break; case FILE_HEAD: this.packSize = bstream.readBits(32); @@ -111,7 +117,7 @@ var RarVolumeHeader = function(bstream, bDebug) { this.fileAttr = bstream.readBits(32); if (this.flags.LHD_LARGE) { - postMessage("Warning: Reading in LHD_LARGE 64-bit size values"); + info("Warning: Reading in LHD_LARGE 64-bit size values"); this.HighPackSize = bstream.readBits(32); this.HighUnpSize = bstream.readBits(32); } else { @@ -138,7 +144,7 @@ var RarVolumeHeader = function(bstream, bDebug) { this.filename = _s; if (this.flags.LHD_SALT) { - postMessage("Warning: Reading in 64-bit salt value"); + info("Warning: Reading in 64-bit salt value"); this.salt = bstream.readBits(64); // 8 bytes } @@ -160,19 +166,19 @@ var RarVolumeHeader = function(bstream, bDebug) { } if (this.flags.LHD_COMMENT) { - postMessage("Found a LHD_COMMENT"); + info("Found a LHD_COMMENT"); } while(headPos + this.headSize > bstream.bytePtr) bstream.readBits(1); if (this.debug) - postMessage("Found FILE_HEAD with packSize=" + this.packSize + ", unpackedSize= " + this.unpackedSize + ", hostOS=" + this.hostOS + ", unpVer=" + this.unpVer + ", method=" + this.method + ", filename=" + this.filename); + info("Found FILE_HEAD with packSize=" + this.packSize + ", unpackedSize= " + this.unpackedSize + ", hostOS=" + this.hostOS + ", unpVer=" + this.unpVer + ", method=" + this.method + ", filename=" + this.filename); break; default: if (this.debug) - postMessage("Found a header of type 0x" + byteValueToHexString(this.headType)); + info("Found a header of type 0x" + byteValueToHexString(this.headType)); // skip the rest of the header bytes (for now) bstream.readBytes( this.headSize - 7 ); break; @@ -247,7 +253,7 @@ function RarReadTables(bstream) { bstream.readBits( (8 - bstream.bitPtr) & 0x7 ); if (bstream.readBits(1)) { - postMessage("Error! PPM not implemented yet"); + info("Error! PPM not implemented yet"); return; } @@ -373,7 +379,7 @@ function RarMakeDecodeTables(BitLength, offset, dec, size) { // TODO: implement function Unpack15(bstream, Solid) { - postMessage("ERROR! RAR 1.5 compression not supported"); + info("ERROR! RAR 1.5 compression not supported"); } function Unpack20(bstream, Solid) { @@ -677,7 +683,7 @@ function RarReadVMCode(bstream) { function RarAddVMCode(firstByte, vmCode, length) { //console.log(vmCode); if (vmCode.length > 0) { - postMessage("Error! RarVM not supported yet!"); + info("Error! RarVM not supported yet!"); } return true; } @@ -723,7 +729,7 @@ function unpack(v) { rBuffer = new bitjs.io.ByteBuffer(v.header.unpackedSize); - postMessage("Unpacking "+v.filename+" RAR v"+Ver); + info("Unpacking "+v.filename+" RAR v"+Ver); switch(Ver) { case 15: // rar 1.5 compression @@ -753,7 +759,7 @@ var RarLocalFile = function(bstream, bDebug) { if (this.header.headType != FILE_HEAD && this.header.headType != ENDARC_HEAD) { this.isValid = false; //progress.isValid = false; - postMessage("Error! RAR Volume did not include a FILE_HEAD header "); + info("Error! RAR Volume did not include a FILE_HEAD header "); } else { // read in the compressed data @@ -770,7 +776,7 @@ RarLocalFile.prototype.unrar = function() { if (!this.header.flags.LHD_SPLIT_BEFORE) { // unstore file if (this.header.method == 0x30) { - postMessage("Unstore "+this.filename); + info("Unstore "+this.filename); this.isValid = true; progress.currentFileBytesUnzipped += this.fileData.length; @@ -787,6 +793,7 @@ RarLocalFile.prototype.unrar = function() { } var unrar = function(arrayBuffer, bDebug) { + postMessage(new bitjs.archive.UnarchiveStartEvent()); var bstream = new bitjs.io.BitStream(arrayBuffer, false /* rtl */); var header = new RarVolumeHeader(bstream, bDebug); @@ -795,12 +802,12 @@ var unrar = function(arrayBuffer, bDebug) { header.flags.value == 0x1A21 && header.headSize == 7) { if (bDebug) - postMessage("Found RAR signature"); + info("Found RAR signature"); var mhead = new RarVolumeHeader(bstream, bDebug); if (mhead.headType != MAIN_HEAD) { progress.isValid = false; - postMessage("Error! RAR did not include a MAIN_HEAD header"); + info("Error! RAR did not include a MAIN_HEAD header"); } else { var localFiles = [], @@ -809,7 +816,7 @@ var unrar = function(arrayBuffer, bDebug) { try { localFile = new RarLocalFile(bstream, bDebug); if (bDebug) - postMessage("RAR localFile isValid=" + localFile.isValid + ", volume packSize=" + localFile.header.packSize); + info("RAR localFile isValid=" + localFile.isValid + ", volume packSize=" + localFile.header.packSize); if (localFile && localFile.isValid && localFile.header.packSize > 0) { progress.totalSizeInBytes += localFile.header.unpackedSize; progress.isValid = true; @@ -821,7 +828,7 @@ var unrar = function(arrayBuffer, bDebug) { } catch(err) { break; } - //postMessage("bstream" + bstream.bytePtr+"/"+bstream.bytes.length); + //info("bstream" + bstream.bytePtr+"/"+bstream.bytes.length); } while( localFile.isValid ); progress.totalNumFilesInZip = localFiles.length; @@ -849,7 +856,7 @@ var unrar = function(arrayBuffer, bDebug) { return bnum - anum;*/ }); - postMessage(localFiles.map(function(a){return a.filename}).join(', ')); + info(localFiles.map(function(a){return a.filename}).join(', ')); for (var i = 0; i < localFiles.length; ++i) { var localfile = localFiles[i]; diff --git a/untar.js b/untar.js index 6c6913f..550a1bd 100644 --- a/untar.js +++ b/untar.js @@ -10,6 +10,12 @@ // This file expects to be invoked as a Worker (see onmessage below). importScripts('binary.js'); +importScripts('archive.js'); + +// Helper function. +var info = function(str) { + postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); +}; // Removes all characters from the first zero-byte in the string onwards. var readCleanString = function(bstr, numBytes) { @@ -56,14 +62,14 @@ var TarLocalFile = function(bstream, bDebug) { this.fileData = null; if (this.debug) { - postMessage("Untarring file '" + this.filename + "'"); - postMessage(" size = " + this.size); - postMessage(" typeflag = " + this.typeflag); + info("Untarring file '" + this.filename + "'"); + info(" size = " + this.size); + info(" typeflag = " + this.typeflag); } // A regular file. if (this.typeflag == 0) { - postMessage(" This is a regular file."); + info(" This is a regular file."); var sizeInBytes = parseInt(this.size); this.fileData = new Uint8Array(bstream.bytes.buffer, bstream.ptr, this.size); if (this.name.length > 0 && this.size > 0 && this.fileData && this.fileData.buffer) { @@ -80,7 +86,7 @@ var TarLocalFile = function(bstream, bDebug) { } } else if (this.typeflag == 5) { if (this.debug) { - postMessage(" This is a directory.") + info(" This is a directory.") } } }; @@ -89,6 +95,7 @@ var TarLocalFile = function(bstream, bDebug) { // returns null on error // returns an array of DecompressedFile objects on success var untar = function(arrayBuffer, bDebug) { + postMessage(new bitjs.archive.UnarchiveStartEvent()); var bstream = new bitjs.io.ByteStream(arrayBuffer); var localFiles = []; @@ -134,7 +141,7 @@ var untar = function(arrayBuffer, bDebug) { // now do the shipping of each file for (var i = 0; i < localFiles.length; ++i) { var localfile = localFiles[i]; - postMessage("Sending file '" + localfile.filename + "' up"); + info("Sending file '" + localfile.filename + "' up"); // update progress progress.currentFilename = localfile.filename; diff --git a/unzip.js b/unzip.js index bb1a97a..8f02ba0 100644 --- a/unzip.js +++ b/unzip.js @@ -12,7 +12,13 @@ // This file expects to be invoked as a Worker (see onmessage below). importScripts('binary.js'); - +importScripts('archive.js'); + +// Helper function. +var info = function(str) { + postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); +}; + var zLocalFileHeaderSignature = 0x04034b50; var zArchiveExtraDataSignature = 0x08064b50; var zCentralFileHeaderSignature = 0x02014b50; @@ -46,25 +52,25 @@ var ZipLocalFile = function(bstream, bDebug) { } if (this.debug) { - postMessage("Zip Local File Header:"); - postMessage(" version=" + this.version); - postMessage(" general purpose=" + this.generalPurpose); - postMessage(" compression method=" + this.compressionMethod); - postMessage(" last mod file time=" + this.lastModFileTime); - postMessage(" last mod file date=" + this.lastModFileDate); - postMessage(" crc32=" + this.crc32); - postMessage(" compressed size=" + this.compressedSize); - postMessage(" uncompressed size=" + this.uncompressedSize); - postMessage(" file name length=" + this.fileNameLength); - postMessage(" extra field length=" + this.extraFieldLength); - postMessage(" filename = '" + this.filename + "'"); + info(new bitjs.archive.UnarchiveInfoEvent("Zip Local File Header:")); + info(" version=" + this.version); + info(" general purpose=" + this.generalPurpose); + info(" compression method=" + this.compressionMethod); + info(" last mod file time=" + this.lastModFileTime); + info(" last mod file date=" + this.lastModFileDate); + info(" crc32=" + this.crc32); + info(" compressed size=" + this.compressedSize); + info(" uncompressed size=" + this.uncompressedSize); + info(" file name length=" + this.fileNameLength); + info(" extra field length=" + this.extraFieldLength); + info(" filename = '" + this.filename + "'"); } this.extraField = null; if (this.extraFieldLength > 0) { this.extraField = bstream.readString(this.extraFieldLength); if (this.debug) { - postMessage(" extra field=" + this.extraField); + info(" extra field=" + this.extraField); } } @@ -93,7 +99,7 @@ ZipLocalFile.prototype.unzip = function() { // Zip Version 1.0, no compression (store only) if (this.compressionMethod == 0 ) { if (this.debug) - postMessage("ZIP v"+this.version+", store only: " + this.filename + " (" + this.compressedSize + " bytes)"); + info("ZIP v"+this.version+", store only: " + this.filename + " (" + this.compressedSize + " bytes)"); progress.currentFileBytesUnzipped = this.compressedSize; progress.totalBytesUnzipped += this.compressedSize; this.isValid = true; @@ -101,12 +107,12 @@ ZipLocalFile.prototype.unzip = function() { // version == 20, compression method == 8 (DEFLATE) else if (this.compressionMethod == 8) { if (this.debug) - postMessage("ZIP v2.0, DEFLATE: " + this.filename + " (" + this.compressedSize + " bytes)"); + info("ZIP v2.0, DEFLATE: " + this.filename + " (" + this.compressedSize + " bytes)"); this.fileData = inflate(this.fileData, this.uncompressedSize); this.isValid = true; } else { - postMessage("UNSUPPORTED VERSION/FORMAT: ZIP v" + this.version + ", compression method=" + this.compressionMethod + ": " + this.filename + " (" + this.compressedSize + " bytes)"); + info("UNSUPPORTED VERSION/FORMAT: ZIP v" + this.version + ", compression method=" + this.compressionMethod + ": " + this.filename + " (" + this.compressedSize + " bytes)"); this.isValid = false; this.fileData = null; } @@ -122,6 +128,8 @@ ZipLocalFile.prototype.unzip = function() { // returns null on error // returns an array of DecompressedFile objects on success var unzip = function(arrayBuffer, bDebug) { + postMessage(new bitjs.archive.UnarchiveStartEvent()); + var bstream = new bitjs.io.ByteStream(arrayBuffer); // detect local file header signature or return null if (bstream.peekNumber(4) == zLocalFileHeaderSignature) { @@ -162,7 +170,7 @@ var unzip = function(arrayBuffer, bDebug) { // archive extra data record if (bstream.peekNumber(4) == zArchiveExtraDataSignature) { if (gDebug) { - postMessage(" Found an Archive Extra Data Signature"); + info(" Found an Archive Extra Data Signature"); } // skipping this record for now bstream.readNumber(4); @@ -174,7 +182,7 @@ var unzip = function(arrayBuffer, bDebug) { // TODO: handle the rest of the structures (Zip64 stuff) if (bstream.peekNumber(4) == zCentralFileHeaderSignature) { if (gDebug) { - postMessage(" Found a Central File Header"); + info(" Found a Central File Header"); } // read all file headers while (bstream.peekNumber(4) == zCentralFileHeaderSignature) { @@ -205,7 +213,7 @@ var unzip = function(arrayBuffer, bDebug) { // digital signature if (bstream.peekNumber(4) == zDigitalSignatureSignature) { if (gDebug) { - postMessage(" Found a Digital Signature"); + info(" Found a Digital Signature"); } bstream.readNumber(4); var sizeOfSignature = bstream.readNumber(2);