diff --git a/cps/static/js/archive/archive.js b/cps/static/js/archive/archive.js index b066dc67..84a78734 100644 --- a/cps/static/js/archive/archive.js +++ b/cps/static/js/archive/archive.js @@ -7,369 +7,377 @@ * * Copyright(c) 2011 Google Inc. */ - var bitjs = bitjs || {}; bitjs.archive = bitjs.archive || {}; (function() { -// =========================================================================== -// Stolen from Closure because it's the best way to do Java-like inheritance. -bitjs.base = function(me, opt_methodName, var_args) { - var caller = arguments.callee.caller; - if (caller.superClass_) { - // This is a constructor. Call the superclass constructor. - return caller.superClass_.constructor.apply( - me, Array.prototype.slice.call(arguments, 1)); - } - - var args = Array.prototype.slice.call(arguments, 2); - var foundCaller = false; - for (var ctor = me.constructor; - ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { - if (ctor.prototype[opt_methodName] === caller) { - foundCaller = true; - } else if (foundCaller) { - return ctor.prototype[opt_methodName].apply(me, args); - } - } - - // If we did not find the caller in the prototype chain, - // then one of two things happened: - // 1) The caller is an instance method. - // 2) This method was not called by the right caller. - if (me[opt_methodName] === caller) { - return me.constructor.prototype[opt_methodName].apply(me, args); - } else { - throw Error( - 'goog.base called from a method of one name ' + - 'to a method of a different name'); - } -}; -bitjs.inherits = function(childCtor, parentCtor) { - /** @constructor */ - function tempCtor() {}; - tempCtor.prototype = parentCtor.prototype; - childCtor.superClass_ = parentCtor.prototype; - childCtor.prototype = new tempCtor(); - childCtor.prototype.constructor = childCtor; -}; -// =========================================================================== - -/** - * An unarchive event. - * - * @param {string} type The event type. - * @constructor - */ -bitjs.archive.UnarchiveEvent = function(type) { - /** - * The event type. - * - * @type {string} - */ - this.type = type; -}; - -/** - * The UnarchiveEvent types. - */ -bitjs.archive.UnarchiveEvent.Type = { - START: 'start', - 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); - -/** - * An unrecoverable error has occured. - * - * @param {string} msg The error message. - */ -bitjs.archive.UnarchiveErrorEvent = function(msg) { - bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.ERROR); - - /** - * The information message. - * - * @type {string} - */ - this.msg = msg; -}; -bitjs.inherits(bitjs.archive.UnarchiveErrorEvent, 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); - -/** - * Progress event. - */ -bitjs.archive.UnarchiveProgressEvent = function( - currentFilename, - currentFileNumber, - currentBytesUnarchivedInFile, - currentBytesUnarchived, - totalUncompressedBytesInArchive, - totalFilesInArchive) { - bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.PROGRESS); - - this.currentFilename = currentFilename; - this.currentFileNumber = currentFileNumber; - this.currentBytesUnarchivedInFile = currentBytesUnarchivedInFile; - this.totalFilesInArchive = totalFilesInArchive; - this.currentBytesUnarchived = currentBytesUnarchived; - this.totalUncompressedBytesInArchive = totalUncompressedBytesInArchive; -}; -bitjs.inherits(bitjs.archive.UnarchiveProgressEvent, bitjs.archive.UnarchiveEvent); - -/** - * All extracted files returned by an Unarchiver will implement - * the following interface: - * - * interface UnarchivedFile { - * string filename - * TypedArray fileData - * } - * - */ - -/** - * Extract event. - */ -bitjs.archive.UnarchiveExtractEvent = function(unarchivedFile) { - bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.EXTRACT); - - /** - * @type {UnarchivedFile} - */ - this.unarchivedFile = unarchivedFile; -}; -bitjs.inherits(bitjs.archive.UnarchiveExtractEvent, bitjs.archive.UnarchiveEvent); - - -/** - * Base class for all Unarchivers. - * - * @param {ArrayBuffer} arrayBuffer The Array Buffer. - * @param {string} opt_pathToBitJS Optional string for where the BitJS files are located. - * @constructor - */ -bitjs.archive.Unarchiver = function(arrayBuffer, opt_pathToBitJS) { - /** - * The ArrayBuffer object. - * @type {ArrayBuffer} - * @protected - */ - this.ab = arrayBuffer; - - /** - * The path to the BitJS files. - * @type {string} - * @private - */ - this.pathToBitJS_ = opt_pathToBitJS || '/'; - - /** - * A map from event type to an array of listeners. - * @type {Map.} - */ - this.listeners_ = {}; - for (var type in bitjs.archive.UnarchiveEvent.Type) { - this.listeners_[bitjs.archive.UnarchiveEvent.Type[type]] = []; - } -}; - -/** - * Private web worker initialized during start(). - * @type {Worker} - * @private - */ -bitjs.archive.Unarchiver.prototype.worker_ = null; + // =========================================================================== + // Stolen from Closure because it's the best way to do Java-like inheritance. + bitjs.base = function(me, opt_methodName, var_args) { + var caller = arguments.callee.caller; + if (caller.superClass_) { + // This is a constructor. Call the superclass constructor. + return caller.superClass_.constructor.apply( + me, Array.prototype.slice.call(arguments, 1)); + } + + var args = Array.prototype.slice.call(arguments, 2); + var foundCaller = false; + for (var ctor = me.constructor; ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { + if (ctor.prototype[opt_methodName] === caller) { + foundCaller = true; + } else if (foundCaller) { + return ctor.prototype[opt_methodName].apply(me, args); + } + } + + // If we did not find the caller in the prototype chain, + // then one of two things happened: + // 1) The caller is an instance method. + // 2) This method was not called by the right caller. + if (me[opt_methodName] === caller) { + return me.constructor.prototype[opt_methodName].apply(me, args); + } else { + throw Error( + 'goog.base called from a method of one name ' + + 'to a method of a different name'); + } + }; + bitjs.inherits = function(childCtor, parentCtor) { + /** @constructor */ + function tempCtor() {}; + tempCtor.prototype = parentCtor.prototype; + childCtor.superClass_ = parentCtor.prototype; + childCtor.prototype = new tempCtor(); + childCtor.prototype.constructor = childCtor; + }; + // =========================================================================== + + /** + * An unarchive event. + * + * @param {string} type The event type. + * @constructor + */ + bitjs.archive.UnarchiveEvent = function(type) { + /** + * The event type. + * + * @type {string} + */ + this.type = type; + }; -/** - * This method must be overridden by the subclass to return the script filename. - * @return {string} The script filename. - * @protected. - */ -bitjs.archive.Unarchiver.prototype.getScriptFileName = function() { - throw 'Subclasses of AbstractUnarchiver must overload getScriptFileName()'; -}; + /** + * The UnarchiveEvent types. + */ + bitjs.archive.UnarchiveEvent.Type = { + START: 'start', + PROGRESS: 'progress', + EXTRACT: 'extract', + FINISH: 'finish', + INFO: 'info', + ERROR: 'error' + }; -/** - * Adds an event listener for UnarchiveEvents. - * - * @param {string} Event type. - * @param {function} An event handler function. - */ -bitjs.archive.Unarchiver.prototype.addEventListener = function(type, listener) { - if (type in this.listeners_) { - if (this.listeners_[type].indexOf(listener) == -1) { - this.listeners_[type].push(listener); - } - } -}; + /** + * 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); + + /** + * An unrecoverable error has occured. + * + * @param {string} msg The error message. + */ + bitjs.archive.UnarchiveErrorEvent = function(msg) { + bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.ERROR); + + /** + * The information message. + * + * @type {string} + */ + this.msg = msg; + }; + bitjs.inherits(bitjs.archive.UnarchiveErrorEvent, 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); + + /** + * Progress event. + */ + bitjs.archive.UnarchiveProgressEvent = function( + currentFilename, + currentFileNumber, + currentBytesUnarchivedInFile, + currentBytesUnarchived, + totalUncompressedBytesInArchive, + totalFilesInArchive) { + bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.PROGRESS); + + this.currentFilename = currentFilename; + this.currentFileNumber = currentFileNumber; + this.currentBytesUnarchivedInFile = currentBytesUnarchivedInFile; + this.totalFilesInArchive = totalFilesInArchive; + this.currentBytesUnarchived = currentBytesUnarchived; + this.totalUncompressedBytesInArchive = totalUncompressedBytesInArchive; + }; + bitjs.inherits(bitjs.archive.UnarchiveProgressEvent, bitjs.archive.UnarchiveEvent); + + /** + * All extracted files returned by an Unarchiver will implement + * the following interface: + * + * interface UnarchivedFile { + * string filename + * TypedArray fileData + * } + * + */ + + /** + * Extract event. + */ + bitjs.archive.UnarchiveExtractEvent = function(unarchivedFile) { + bitjs.base(this, bitjs.archive.UnarchiveEvent.Type.EXTRACT); + + /** + * @type {UnarchivedFile} + */ + this.unarchivedFile = unarchivedFile; + }; + bitjs.inherits(bitjs.archive.UnarchiveExtractEvent, bitjs.archive.UnarchiveEvent); + + + /** + * Base class for all Unarchivers. + * + * @param {ArrayBuffer} arrayBuffer The Array Buffer. + * @param {string} opt_pathToBitJS Optional string for where the BitJS files are located. + * @constructor + */ + bitjs.archive.Unarchiver = function(arrayBuffer, opt_pathToBitJS) { + /** + * The ArrayBuffer object. + * @type {ArrayBuffer} + * @protected + */ + this.ab = arrayBuffer; + + /** + * The path to the BitJS files. + * @type {string} + * @private + */ + this.pathToBitJS_ = opt_pathToBitJS || '/'; + + /** + * A map from event type to an array of listeners. + * @type {Map.} + */ + this.listeners_ = {}; + for (var type in bitjs.archive.UnarchiveEvent.Type) { + this.listeners_[bitjs.archive.UnarchiveEvent.Type[type]] = []; + } + }; -/** - * Removes an event listener. - * - * @param {string} Event type. - * @param {EventListener|function} An event listener or handler function. - */ -bitjs.archive.Unarchiver.prototype.removeEventListener = function(type, listener) { - if (type in this.listeners_) { - var index = this.listeners_[type].indexOf(listener); - if (index != -1) { - this.listeners_[type].splice(index, 1); - } - } -}; + /** + * Private web worker initialized during start(). + * @type {Worker} + * @private + */ + bitjs.archive.Unarchiver.prototype.worker_ = null; + + /** + * This method must be overridden by the subclass to return the script filename. + * @return {string} The script filename. + * @protected. + */ + bitjs.archive.Unarchiver.prototype.getScriptFileName = function() { + throw 'Subclasses of AbstractUnarchiver must overload getScriptFileName()'; + }; -/** - * Receive an event and pass it to the listener functions. - * - * @param {bitjs.archive.UnarchiveEvent} e - * @private - */ -bitjs.archive.Unarchiver.prototype.handleWorkerEvent_ = function(e) { - if ((e instanceof bitjs.archive.UnarchiveEvent || e.type) && - this.listeners_[e.type] instanceof Array) { - this.listeners_[e.type].forEach(function (listener) { listener(e) }); - if (e.type == bitjs.archive.UnarchiveEvent.Type.FINISH) { - this.worker_.terminate(); - } - } else { - console.log(e); - } -}; + /** + * Adds an event listener for UnarchiveEvents. + * + * @param {string} Event type. + * @param {function} An event handler function. + */ + bitjs.archive.Unarchiver.prototype.addEventListener = function(type, listener) { + if (type in this.listeners_) { + if (this.listeners_[type].indexOf(listener) == -1) { + this.listeners_[type].push(listener); + } + } + }; -/** - * Starts the unarchive in a separate Web Worker thread and returns immediately. - */ - bitjs.archive.Unarchiver.prototype.start = function() { - var me = this; - var scriptFileName = this.pathToBitJS_ + this.getScriptFileName(); - if (scriptFileName) { - this.worker_ = new Worker(scriptFileName); - - this.worker_.onerror = function(e) { - console.log('Worker error: message = ' + e.message); - throw e; + /** + * Removes an event listener. + * + * @param {string} Event type. + * @param {EventListener|function} An event listener or handler function. + */ + bitjs.archive.Unarchiver.prototype.removeEventListener = function(type, listener) { + if (type in this.listeners_) { + var index = this.listeners_[type].indexOf(listener); + if (index != -1) { + this.listeners_[type].splice(index, 1); + } + } }; - this.worker_.onmessage = function(e) { - if (typeof e.data == 'string') { - // Just log any strings the workers pump our way. - console.log(e.data); - } else { - // Assume that it is an UnarchiveEvent. Some browsers preserve the 'type' - // so that instanceof UnarchiveEvent returns true, but others do not. - me.handleWorkerEvent_(e.data); - } + /** + * Receive an event and pass it to the listener functions. + * + * @param {bitjs.archive.UnarchiveEvent} e + * @private + */ + bitjs.archive.Unarchiver.prototype.handleWorkerEvent_ = function(e) { + if ((e instanceof bitjs.archive.UnarchiveEvent || e.type) && + this.listeners_[e.type] instanceof Array) { + this.listeners_[e.type].forEach(function(listener) { + listener(e) + }); + if (e.type == bitjs.archive.UnarchiveEvent.Type.FINISH) { + this.worker_.terminate(); + } + } else { + console.log(e); + } }; - this.worker_.postMessage({file: this.ab}); - } -}; + /** + * Starts the unarchive in a separate Web Worker thread and returns immediately. + */ + bitjs.archive.Unarchiver.prototype.start = function() { + var me = this; + var scriptFileName = this.pathToBitJS_ + this.getScriptFileName(); + if (scriptFileName) { + this.worker_ = new Worker(scriptFileName); + + this.worker_.onerror = function(e) { + console.log('Worker error: message = ' + e.message); + throw e; + }; + + this.worker_.onmessage = function(e) { + if (typeof e.data == 'string') { + // Just log any strings the workers pump our way. + console.log(e.data); + } else { + // Assume that it is an UnarchiveEvent. Some browsers preserve the 'type' + // so that instanceof UnarchiveEvent returns true, but others do not. + me.handleWorkerEvent_(e.data); + } + }; + + this.worker_.postMessage({ + file: this.ab + }); + } + }; -/** - * Terminates the Web Worker for this Unarchiver and returns immediately. - */ -bitjs.archive.Unarchiver.prototype.stop = function() { - if (this.worker_) { - this.worker_.terminate(); - } -}; + /** + * Terminates the Web Worker for this Unarchiver and returns immediately. + */ + bitjs.archive.Unarchiver.prototype.stop = function() { + if (this.worker_) { + this.worker_.terminate(); + } + }; -/** - * Unzipper - * @extends {bitjs.archive.Unarchiver} - * @constructor - */ -bitjs.archive.Unzipper = function(arrayBuffer, opt_pathToBitJS) { - bitjs.base(this, arrayBuffer, opt_pathToBitJS); -}; -bitjs.inherits(bitjs.archive.Unzipper, bitjs.archive.Unarchiver); -bitjs.archive.Unzipper.prototype.getScriptFileName = function() { return 'unzip.js' }; + /** + * Unzipper + * @extends {bitjs.archive.Unarchiver} + * @constructor + */ + bitjs.archive.Unzipper = function(arrayBuffer, opt_pathToBitJS) { + bitjs.base(this, arrayBuffer, opt_pathToBitJS); + }; + bitjs.inherits(bitjs.archive.Unzipper, bitjs.archive.Unarchiver); + bitjs.archive.Unzipper.prototype.getScriptFileName = function() { + return 'unzip.js' + }; -/** - * Unrarrer - * @extends {bitjs.archive.Unarchiver} - * @constructor - */ -bitjs.archive.Unrarrer = function(arrayBuffer, opt_pathToBitJS) { - bitjs.base(this, arrayBuffer, opt_pathToBitJS); -}; -bitjs.inherits(bitjs.archive.Unrarrer, bitjs.archive.Unarchiver); -bitjs.archive.Unrarrer.prototype.getScriptFileName = function() { return 'unrar.js' }; + /** + * Unrarrer + * @extends {bitjs.archive.Unarchiver} + * @constructor + */ + bitjs.archive.Unrarrer = function(arrayBuffer, opt_pathToBitJS) { + bitjs.base(this, arrayBuffer, opt_pathToBitJS); + }; + bitjs.inherits(bitjs.archive.Unrarrer, bitjs.archive.Unarchiver); + bitjs.archive.Unrarrer.prototype.getScriptFileName = function() { + return 'unrar.js' + }; -/** - * Untarrer - * @extends {bitjs.archive.Unarchiver} - * @constructor - */ -bitjs.archive.Untarrer = function(arrayBuffer, opt_pathToBitJS) { - bitjs.base(this, arrayBuffer, opt_pathToBitJS); -}; -bitjs.inherits(bitjs.archive.Untarrer, bitjs.archive.Unarchiver); -bitjs.archive.Untarrer.prototype.getScriptFileName = function() { return 'untar.js' }; + /** + * Untarrer + * @extends {bitjs.archive.Unarchiver} + * @constructor + */ + bitjs.archive.Untarrer = function(arrayBuffer, opt_pathToBitJS) { + bitjs.base(this, arrayBuffer, opt_pathToBitJS); + }; + bitjs.inherits(bitjs.archive.Untarrer, bitjs.archive.Unarchiver); + bitjs.archive.Untarrer.prototype.getScriptFileName = function() { + return 'untar.js' + }; -/** - * Factory method that creates an unarchiver based on the byte signature found - * in the arrayBuffer. - * @param {ArrayBuffer} ab - * @param {string=} opt_pathToBitJS Path to the unarchiver script files. - * @return {bitjs.archive.Unarchiver} - */ -bitjs.archive.GetUnarchiver = function(ab, opt_pathToBitJS) { - var unarchiver = null; - var pathToBitJS = opt_pathToBitJS || ''; - var h = new Uint8Array(ab, 0, 10); - - if (h[0] == 0x52 && h[1] == 0x61 && h[2] == 0x72 && h[3] == 0x21) { // Rar! - unarchiver = new bitjs.archive.Unrarrer(ab, pathToBitJS); - } else if (h[0] == 80 && h[1] == 75) { // PK (Zip) - unarchiver = new bitjs.archive.Unzipper(ab, pathToBitJS); - } else { // Try with tar - unarchiver = new bitjs.archive.Untarrer(ab, pathToBitJS); - } - return unarchiver; -}; + /** + * Factory method that creates an unarchiver based on the byte signature found + * in the arrayBuffer. + * @param {ArrayBuffer} ab + * @param {string=} opt_pathToBitJS Path to the unarchiver script files. + * @return {bitjs.archive.Unarchiver} + */ + bitjs.archive.GetUnarchiver = function(ab, opt_pathToBitJS) { + var unarchiver = null; + var pathToBitJS = opt_pathToBitJS || ''; + var h = new Uint8Array(ab, 0, 10); + + if (h[0] == 0x52 && h[1] == 0x61 && h[2] == 0x72 && h[3] == 0x21) { // Rar! + unarchiver = new bitjs.archive.Unrarrer(ab, pathToBitJS); + } else if (h[0] == 80 && h[1] == 75) { // PK (Zip) + unarchiver = new bitjs.archive.Unzipper(ab, pathToBitJS); + } else { // Try with tar + unarchiver = new bitjs.archive.Untarrer(ab, pathToBitJS); + } + return unarchiver; + }; })(); \ No newline at end of file diff --git a/cps/static/js/archive/rarvm.js b/cps/static/js/archive/rarvm.js index 0e6870e7..769c25be 100644 --- a/cps/static/js/archive/rarvm.js +++ b/cps/static/js/archive/rarvm.js @@ -12,16 +12,16 @@ var CRCTab = new Array(256).fill(0); function InitCRC() { - for (var i = 0; i < 256; ++i) { - var c = i; - for (var j = 0; j < 8; ++j) { - // Read http://stackoverflow.com/questions/6798111/bitwise-operations-on-32-bit-unsigned-ints - // for the bitwise operator issue (JS interprets operands as 32-bit signed - // integers and we need to deal with unsigned ones here). - c = ((c & 1) ? ((c >>> 1) ^ 0xEDB88320) : (c >>> 1)) >>> 0; + for (var i = 0; i < 256; ++i) { + var c = i; + for (var j = 0; j < 8; ++j) { + // Read http://stackoverflow.com/questions/6798111/bitwise-operations-on-32-bit-unsigned-ints + // for the bitwise operator issue (JS interprets operands as 32-bit signed + // integers and we need to deal with unsigned ones here). + c = ((c & 1) ? ((c >>> 1) ^ 0xEDB88320) : (c >>> 1)) >>> 0; + } + CRCTab[i] = c; } - CRCTab[i] = c; - } } /** @@ -30,42 +30,42 @@ function InitCRC() { * @return {number} */ function CRC(startCRC, arr) { - if (CRCTab[1] == 0) { - InitCRC(); - } - -/* -#if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT) - while (Size>0 && ((long)Data & 7)) - { - StartCRC=CRCTab[(byte)(StartCRC^Data[0])]^(StartCRC>>8); - Size--; - Data++; - } - while (Size>=8) - { - StartCRC^=*(uint32 *)Data; - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC^=*(uint32 *)(Data+4); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - Data+=8; - Size-=8; - } -#endif -*/ - - for (var i = 0; i < arr.length; ++i) { - var byte = ((startCRC ^ arr[i]) >>> 0) & 0xff; - startCRC = (CRCTab[byte] ^ (startCRC >>> 8)) >>> 0; - } - - return startCRC; + if (CRCTab[1] == 0) { + InitCRC(); + } + + /* + #if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT) + while (Size>0 && ((long)Data & 7)) + { + StartCRC=CRCTab[(byte)(StartCRC^Data[0])]^(StartCRC>>8); + Size--; + Data++; + } + while (Size>=8) + { + StartCRC^=*(uint32 *)Data; + StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); + StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); + StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); + StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); + StartCRC^=*(uint32 *)(Data+4); + StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); + StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); + StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); + StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); + Data+=8; + Size-=8; + } + #endif + */ + + for (var i = 0; i < arr.length; ++i) { + var byte = ((startCRC ^ arr[i]) >>> 0) & 0xff; + startCRC = (CRCTab[byte] ^ (startCRC >>> 8)) >>> 0; + } + + return startCRC; } // ============================================================================================== // @@ -85,88 +85,88 @@ var MAXWINMASK = (MAXWINSIZE - 1); /** */ var VM_Commands = { - VM_MOV: 0, - VM_CMP: 1, - VM_ADD: 2, - VM_SUB: 3, - VM_JZ: 4, - VM_JNZ: 5, - VM_INC: 6, - VM_DEC: 7, - VM_JMP: 8, - VM_XOR: 9, - VM_AND: 10, - VM_OR: 11, - VM_TEST: 12, - VM_JS: 13, - VM_JNS: 14, - VM_JB: 15, - VM_JBE: 16, - VM_JA: 17, - VM_JAE: 18, - VM_PUSH: 19, - VM_POP: 20, - VM_CALL: 21, - VM_RET: 22, - VM_NOT: 23, - VM_SHL: 24, - VM_SHR: 25, - VM_SAR: 26, - VM_NEG: 27, - VM_PUSHA: 28, - VM_POPA: 29, - VM_PUSHF: 30, - VM_POPF: 31, - VM_MOVZX: 32, - VM_MOVSX: 33, - VM_XCHG: 34, - VM_MUL: 35, - VM_DIV: 36, - VM_ADC: 37, - VM_SBB: 38, - VM_PRINT: 39, - -/* -#ifdef VM_OPTIMIZE - VM_MOVB, VM_MOVD, VM_CMPB, VM_CMPD, - - VM_ADDB, VM_ADDD, VM_SUBB, VM_SUBD, VM_INCB, VM_INCD, VM_DECB, VM_DECD, - VM_NEGB, VM_NEGD, -#endif -*/ - - // TODO: This enum value would be much larger if VM_OPTIMIZE. - VM_STANDARD: 40, + VM_MOV: 0, + VM_CMP: 1, + VM_ADD: 2, + VM_SUB: 3, + VM_JZ: 4, + VM_JNZ: 5, + VM_INC: 6, + VM_DEC: 7, + VM_JMP: 8, + VM_XOR: 9, + VM_AND: 10, + VM_OR: 11, + VM_TEST: 12, + VM_JS: 13, + VM_JNS: 14, + VM_JB: 15, + VM_JBE: 16, + VM_JA: 17, + VM_JAE: 18, + VM_PUSH: 19, + VM_POP: 20, + VM_CALL: 21, + VM_RET: 22, + VM_NOT: 23, + VM_SHL: 24, + VM_SHR: 25, + VM_SAR: 26, + VM_NEG: 27, + VM_PUSHA: 28, + VM_POPA: 29, + VM_PUSHF: 30, + VM_POPF: 31, + VM_MOVZX: 32, + VM_MOVSX: 33, + VM_XCHG: 34, + VM_MUL: 35, + VM_DIV: 36, + VM_ADC: 37, + VM_SBB: 38, + VM_PRINT: 39, + + /* + #ifdef VM_OPTIMIZE + VM_MOVB, VM_MOVD, VM_CMPB, VM_CMPD, + + VM_ADDB, VM_ADDD, VM_SUBB, VM_SUBD, VM_INCB, VM_INCD, VM_DECB, VM_DECD, + VM_NEGB, VM_NEGD, + #endif + */ + + // TODO: This enum value would be much larger if VM_OPTIMIZE. + VM_STANDARD: 40, }; /** */ var VM_StandardFilters = { - VMSF_NONE: 0, - VMSF_E8: 1, - VMSF_E8E9: 2, - VMSF_ITANIUM: 3, - VMSF_RGB: 4, - VMSF_AUDIO: 5, - VMSF_DELTA: 6, - VMSF_UPCASE: 7, + VMSF_NONE: 0, + VMSF_E8: 1, + VMSF_E8E9: 2, + VMSF_ITANIUM: 3, + VMSF_RGB: 4, + VMSF_AUDIO: 5, + VMSF_DELTA: 6, + VMSF_UPCASE: 7, }; /** */ var VM_Flags = { - VM_FC: 1, - VM_FZ: 2, - VM_FS: 0x80000000, + VM_FC: 1, + VM_FZ: 2, + VM_FS: 0x80000000, }; /** */ var VM_OpType = { - VM_OPREG: 0, - VM_OPINT: 1, - VM_OPREGMEM: 2, - VM_OPNONE: 3, + VM_OPREG: 0, + VM_OPINT: 1, + VM_OPREGMEM: 2, + VM_OPNONE: 3, }; /** @@ -177,27 +177,27 @@ var VM_OpType = { * @return {string} The key/enum value as a string. */ function findKeyForValue(obj, val) { - for (var key in obj) { - if (obj[key] === val) { - return key; + for (var key in obj) { + if (obj[key] === val) { + return key; + } } - } - return null; + return null; } function getDebugString(obj, val) { - var s = 'Unknown.'; - if (obj === VM_Commands) { - s = 'VM_Commands.'; - } else if (obj === VM_StandardFilters) { - s = 'VM_StandardFilters.'; - } else if (obj === VM_Flags) { - s = 'VM_OpType.'; - } else if (obj === VM_OpType) { - s = 'VM_OpType.'; - } - - return s + findKeyForValue(obj, val); + var s = 'Unknown.'; + if (obj === VM_Commands) { + s = 'VM_Commands.'; + } else if (obj === VM_StandardFilters) { + s = 'VM_StandardFilters.'; + } else if (obj === VM_Flags) { + s = 'VM_OpType.'; + } else if (obj === VM_OpType) { + s = 'VM_OpType.'; + } + + return s + findKeyForValue(obj, val); } /** @@ -205,30 +205,30 @@ function getDebugString(obj, val) { * @constructor */ var VM_PreparedOperand = function() { - /** @type {VM_OpType} */ - this.Type; + /** @type {VM_OpType} */ + this.Type; - /** @type {number} */ - this.Data = 0; + /** @type {number} */ + this.Data = 0; - /** @type {number} */ - this.Base = 0; + /** @type {number} */ + this.Base = 0; - // TODO: In C++ this is a uint* - /** @type {Array} */ - this.Addr = null; + // TODO: In C++ this is a uint* + /** @type {Array} */ + this.Addr = null; }; /** @return {string} */ VM_PreparedOperand.prototype.toString = function() { - if (this.Type === null) { - return 'Error: Type was null in VM_PreparedOperand'; - } - return '{ ' - + 'Type: ' + getDebugString(VM_OpType, this.Type) - + ', Data: ' + this.Data - + ', Base: ' + this.Base - + ' }'; + if (this.Type === null) { + return 'Error: Type was null in VM_PreparedOperand'; + } + return '{ ' + + 'Type: ' + getDebugString(VM_OpType, this.Type) + + ', Data: ' + this.Data + + ', Base: ' + this.Base + + ' }'; }; /** @@ -236,31 +236,31 @@ VM_PreparedOperand.prototype.toString = function() { * @constructor */ var VM_PreparedCommand = function() { - /** @type {VM_Commands} */ - this.OpCode; + /** @type {VM_Commands} */ + this.OpCode; - /** @type {boolean} */ - this.ByteMode = false; + /** @type {boolean} */ + this.ByteMode = false; - /** @type {VM_PreparedOperand} */ - this.Op1 = new VM_PreparedOperand(); + /** @type {VM_PreparedOperand} */ + this.Op1 = new VM_PreparedOperand(); - /** @type {VM_PreparedOperand} */ - this.Op2 = new VM_PreparedOperand(); + /** @type {VM_PreparedOperand} */ + this.Op2 = new VM_PreparedOperand(); }; /** @return {string} */ VM_PreparedCommand.prototype.toString = function(indent) { - if (this.OpCode === null) { - return 'Error: OpCode was null in VM_PreparedCommand'; - } - indent = indent || ''; - return indent + '{\n' - + indent + ' OpCode: ' + getDebugString(VM_Commands, this.OpCode) + ',\n' - + indent + ' ByteMode: ' + this.ByteMode + ',\n' - + indent + ' Op1: ' + this.Op1.toString() + ',\n' - + indent + ' Op2: ' + this.Op2.toString() + ',\n' - + indent + '}'; + if (this.OpCode === null) { + return 'Error: OpCode was null in VM_PreparedCommand'; + } + indent = indent || ''; + return indent + '{\n' + + indent + ' OpCode: ' + getDebugString(VM_Commands, this.OpCode) + ',\n' + + indent + ' ByteMode: ' + this.ByteMode + ',\n' + + indent + ' Op1: ' + this.Op1.toString() + ',\n' + + indent + ' Op2: ' + this.Op2.toString() + ',\n' + + indent + '}'; }; /** @@ -268,38 +268,38 @@ VM_PreparedCommand.prototype.toString = function(indent) { * @constructor */ var VM_PreparedProgram = function() { - /** @type {Array} */ - this.Cmd = []; + /** @type {Array} */ + this.Cmd = []; - /** @type {Array} */ - this.AltCmd = null; + /** @type {Array} */ + this.AltCmd = null; - /** @type {Uint8Array} */ - this.GlobalData = new Uint8Array(); + /** @type {Uint8Array} */ + this.GlobalData = new Uint8Array(); - /** @type {Uint8Array} */ - this.StaticData = new Uint8Array(); // static data contained in DB operators + /** @type {Uint8Array} */ + this.StaticData = new Uint8Array(); // static data contained in DB operators - /** @type {Uint32Array} */ - this.InitR = new Uint32Array(7); + /** @type {Uint32Array} */ + this.InitR = new Uint32Array(7); - /** - * A pointer to bytes that have been filtered by a program. - * @type {Uint8Array} - */ - this.FilteredData = null; + /** + * A pointer to bytes that have been filtered by a program. + * @type {Uint8Array} + */ + this.FilteredData = null; }; /** @return {string} */ VM_PreparedProgram.prototype.toString = function() { - var s = '{\n Cmd: [\n'; - for (var i = 0; i < this.Cmd.length; ++i) { - s += this.Cmd[i].toString(' ') + ',\n'; - } - s += '],\n'; - // TODO: Dump GlobalData, StaticData, InitR? - s += ' }\n'; - return s; + var s = '{\n Cmd: [\n'; + for (var i = 0; i < this.Cmd.length; ++i) { + s += this.Cmd[i].toString(' ') + ',\n'; + } + s += '],\n'; + // TODO: Dump GlobalData, StaticData, InitR? + s += ' }\n'; + return s; }; /** @@ -307,78 +307,118 @@ VM_PreparedProgram.prototype.toString = function() { * @constructor */ var UnpackFilter = function() { - /** @type {number} */ - this.BlockStart = 0; + /** @type {number} */ + this.BlockStart = 0; - /** @type {number} */ - this.BlockLength = 0; + /** @type {number} */ + this.BlockLength = 0; - /** @type {number} */ - this.ExecCount = 0; + /** @type {number} */ + this.ExecCount = 0; - /** @type {boolean} */ - this.NextWindow = false; + /** @type {boolean} */ + this.NextWindow = false; - // position of parent filter in Filters array used as prototype for filter - // in PrgStack array. Not defined for filters in Filters array. - /** @type {number} */ - this.ParentFilter = null; + // position of parent filter in Filters array used as prototype for filter + // in PrgStack array. Not defined for filters in Filters array. + /** @type {number} */ + this.ParentFilter = null; - /** @type {VM_PreparedProgram} */ - this.Prg = new VM_PreparedProgram(); + /** @type {VM_PreparedProgram} */ + this.Prg = new VM_PreparedProgram(); }; -var VMCF_OP0 = 0; -var VMCF_OP1 = 1; -var VMCF_OP2 = 2; -var VMCF_OPMASK = 3; -var VMCF_BYTEMODE = 4; -var VMCF_JUMP = 8; -var VMCF_PROC = 16; -var VMCF_USEFLAGS = 32; -var VMCF_CHFLAGS = 64; +var VMCF_OP0 = 0; +var VMCF_OP1 = 1; +var VMCF_OP2 = 2; +var VMCF_OPMASK = 3; +var VMCF_BYTEMODE = 4; +var VMCF_JUMP = 8; +var VMCF_PROC = 16; +var VMCF_USEFLAGS = 32; +var VMCF_CHFLAGS = 64; var VM_CmdFlags = [ - /* VM_MOV */ VMCF_OP2 | VMCF_BYTEMODE , - /* VM_CMP */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_ADD */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_SUB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_JZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , - /* VM_JNZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , - /* VM_INC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_DEC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_JMP */ VMCF_OP1 | VMCF_JUMP , - /* VM_XOR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_AND */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_OR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_TEST */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_JS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , - /* VM_JNS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , - /* VM_JB */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , - /* VM_JBE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , - /* VM_JA */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , - /* VM_JAE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , - /* VM_PUSH */ VMCF_OP1 , - /* VM_POP */ VMCF_OP1 , - /* VM_CALL */ VMCF_OP1 | VMCF_PROC , - /* VM_RET */ VMCF_OP0 | VMCF_PROC , - /* VM_NOT */ VMCF_OP1 | VMCF_BYTEMODE , - /* VM_SHL */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_SHR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_SAR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_NEG */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , - /* VM_PUSHA */ VMCF_OP0 , - /* VM_POPA */ VMCF_OP0 , - /* VM_PUSHF */ VMCF_OP0 | VMCF_USEFLAGS , - /* VM_POPF */ VMCF_OP0 | VMCF_CHFLAGS , - /* VM_MOVZX */ VMCF_OP2 , - /* VM_MOVSX */ VMCF_OP2 , - /* VM_XCHG */ VMCF_OP2 | VMCF_BYTEMODE , - /* VM_MUL */ VMCF_OP2 | VMCF_BYTEMODE , - /* VM_DIV */ VMCF_OP2 | VMCF_BYTEMODE , - /* VM_ADC */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS , - /* VM_SBB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS , - /* VM_PRINT */ VMCF_OP0 , + /* VM_MOV */ + VMCF_OP2 | VMCF_BYTEMODE, + /* VM_CMP */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_ADD */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_SUB */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_JZ */ + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + /* VM_JNZ */ + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + /* VM_INC */ + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_DEC */ + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_JMP */ + VMCF_OP1 | VMCF_JUMP, + /* VM_XOR */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_AND */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_OR */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_TEST */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_JS */ + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + /* VM_JNS */ + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + /* VM_JB */ + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + /* VM_JBE */ + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + /* VM_JA */ + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + /* VM_JAE */ + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + /* VM_PUSH */ + VMCF_OP1, + /* VM_POP */ + VMCF_OP1, + /* VM_CALL */ + VMCF_OP1 | VMCF_PROC, + /* VM_RET */ + VMCF_OP0 | VMCF_PROC, + /* VM_NOT */ + VMCF_OP1 | VMCF_BYTEMODE, + /* VM_SHL */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_SHR */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_SAR */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_NEG */ + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + /* VM_PUSHA */ + VMCF_OP0, + /* VM_POPA */ + VMCF_OP0, + /* VM_PUSHF */ + VMCF_OP0 | VMCF_USEFLAGS, + /* VM_POPF */ + VMCF_OP0 | VMCF_CHFLAGS, + /* VM_MOVZX */ + VMCF_OP2, + /* VM_MOVSX */ + VMCF_OP2, + /* VM_XCHG */ + VMCF_OP2 | VMCF_BYTEMODE, + /* VM_MUL */ + VMCF_OP2 | VMCF_BYTEMODE, + /* VM_DIV */ + VMCF_OP2 | VMCF_BYTEMODE, + /* VM_ADC */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, + /* VM_SBB */ + VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, + /* VM_PRINT */ + VMCF_OP0, ]; @@ -390,50 +430,50 @@ var VM_CmdFlags = [ * @constructor */ var StandardFilterSignature = function(length, crc, type) { - /** @type {number} */ - this.Length = length; + /** @type {number} */ + this.Length = length; - /** @type {number} */ - this.CRC = crc; + /** @type {number} */ + this.CRC = crc; - /** @type {VM_StandardFilters} */ - this.Type = type; + /** @type {VM_StandardFilters} */ + this.Type = type; }; /** * @type {Array} */ var StdList = [ - new StandardFilterSignature(53, 0xad576887, VM_StandardFilters.VMSF_E8), - new StandardFilterSignature(57, 0x3cd7e57e, VM_StandardFilters.VMSF_E8E9), - new StandardFilterSignature(120, 0x3769893f, VM_StandardFilters.VMSF_ITANIUM), - new StandardFilterSignature(29, 0x0e06077d, VM_StandardFilters.VMSF_DELTA), - new StandardFilterSignature(149, 0x1c2c5dc8, VM_StandardFilters.VMSF_RGB), - new StandardFilterSignature(216, 0xbc85e701, VM_StandardFilters.VMSF_AUDIO), - new StandardFilterSignature(40, 0x46b9c560, VM_StandardFilters.VMSF_UPCASE), + new StandardFilterSignature(53, 0xad576887, VM_StandardFilters.VMSF_E8), + new StandardFilterSignature(57, 0x3cd7e57e, VM_StandardFilters.VMSF_E8E9), + new StandardFilterSignature(120, 0x3769893f, VM_StandardFilters.VMSF_ITANIUM), + new StandardFilterSignature(29, 0x0e06077d, VM_StandardFilters.VMSF_DELTA), + new StandardFilterSignature(149, 0x1c2c5dc8, VM_StandardFilters.VMSF_RGB), + new StandardFilterSignature(216, 0xbc85e701, VM_StandardFilters.VMSF_AUDIO), + new StandardFilterSignature(40, 0x46b9c560, VM_StandardFilters.VMSF_UPCASE), ]; /** * @constructor */ var RarVM = function() { - /** @private {Uint8Array} */ - this.mem_ = null; + /** @private {Uint8Array} */ + this.mem_ = null; - /** @private {Uint32Array} */ - this.R_ = new Uint32Array(8); + /** @private {Uint32Array} */ + this.R_ = new Uint32Array(8); - /** @private {number} */ - this.flags_ = 0; + /** @private {number} */ + this.flags_ = 0; }; /** * Initializes the memory of the VM. */ RarVM.prototype.init = function() { - if (!this.mem_) { - this.mem_ = new Uint8Array(VM_MEMSIZE); - } + if (!this.mem_) { + this.mem_ = new Uint8Array(VM_MEMSIZE); + } }; /** @@ -441,13 +481,13 @@ RarVM.prototype.init = function() { * @return {VM_StandardFilters} */ RarVM.prototype.isStandardFilter = function(code) { - var codeCRC = (CRC(0xffffffff, code, code.length) ^ 0xffffffff) >>> 0; - for (var i = 0; i < StdList.length; ++i) { - if (StdList[i].CRC == codeCRC && StdList[i].Length == code.length) - return StdList[i].Type; - } + var codeCRC = (CRC(0xffffffff, code, code.length) ^ 0xffffffff) >>> 0; + for (var i = 0; i < StdList.length; ++i) { + if (StdList[i].CRC == codeCRC && StdList[i].Length == code.length) + return StdList[i].Type; + } - return VM_StandardFilters.VMSF_NONE; + return VM_StandardFilters.VMSF_NONE; }; /** @@ -456,88 +496,88 @@ RarVM.prototype.isStandardFilter = function(code) { * @param {bitjs.io.BitStream} bstream A rtl bit stream. */ RarVM.prototype.decodeArg = function(op, byteMode, bstream) { - var data = bstream.peekBits(16); - if (data & 0x8000) { - op.Type = VM_OpType.VM_OPREG; // Operand is register (R[0]..R[7]) - bstream.readBits(1); // 1 flag bit and... - op.Data = bstream.readBits(3); // ... 3 register number bits - op.Addr = [this.R_[op.Data]] // TODO &R[Op.Data] // Register address - } else { - if ((data & 0xc000) == 0) { - op.Type = VM_OpType.VM_OPINT; // Operand is integer - bstream.readBits(2); // 2 flag bits - if (byteMode) { - op.Data = bstream.readBits(8); // Byte integer. - } else { - op.Data = RarVM.readData(bstream); // 32 bit integer. - } + var data = bstream.peekBits(16); + if (data & 0x8000) { + op.Type = VM_OpType.VM_OPREG; // Operand is register (R[0]..R[7]) + bstream.readBits(1); // 1 flag bit and... + op.Data = bstream.readBits(3); // ... 3 register number bits + op.Addr = [this.R_[op.Data]] // TODO &R[Op.Data] // Register address } else { - // Operand is data addressed by register data, base address or both. - op.Type = VM_OpType.VM_OPREGMEM; - if ((data & 0x2000) == 0) { - bstream.readBits(3); // 3 flag bits - // Base address is zero, just use the address from register. - op.Data = bstream.readBits(3); // (Data>>10)&7 - op.Addr = [this.R_[op.Data]]; // TODO &R[op.Data] - op.Base = 0; - } else { - bstream.readBits(4); // 4 flag bits - if ((data & 0x1000) == 0) { - // Use both register and base address. - op.Data = bstream.readBits(3); - op.Addr = [this.R_[op.Data]]; // TODO &R[op.Data] + if ((data & 0xc000) == 0) { + op.Type = VM_OpType.VM_OPINT; // Operand is integer + bstream.readBits(2); // 2 flag bits + if (byteMode) { + op.Data = bstream.readBits(8); // Byte integer. + } else { + op.Data = RarVM.readData(bstream); // 32 bit integer. + } } else { - // Use base address only. Access memory by fixed address. - op.Data = 0; + // Operand is data addressed by register data, base address or both. + op.Type = VM_OpType.VM_OPREGMEM; + if ((data & 0x2000) == 0) { + bstream.readBits(3); // 3 flag bits + // Base address is zero, just use the address from register. + op.Data = bstream.readBits(3); // (Data>>10)&7 + op.Addr = [this.R_[op.Data]]; // TODO &R[op.Data] + op.Base = 0; + } else { + bstream.readBits(4); // 4 flag bits + if ((data & 0x1000) == 0) { + // Use both register and base address. + op.Data = bstream.readBits(3); + op.Addr = [this.R_[op.Data]]; // TODO &R[op.Data] + } else { + // Use base address only. Access memory by fixed address. + op.Data = 0; + } + op.Base = RarVM.readData(bstream); // Read base address. + } } - op.Base = RarVM.readData(bstream); // Read base address. - } } - } }; /** * @param {VM_PreparedProgram} prg */ RarVM.prototype.execute = function(prg) { - this.R_.set(prg.InitR); - - var globalSize = Math.min(prg.GlobalData.length, VM_GLOBALMEMSIZE); - if (globalSize) { - this.mem_.set(prg.GlobalData.subarray(0, globalSize), VM_GLOBALMEMADDR); - } - - var staticSize = Math.min(prg.StaticData.length, VM_GLOBALMEMSIZE - globalSize); - if (staticSize) { - this.mem_.set(prg.StaticData.subarray(0, staticSize), VM_GLOBALMEMADDR + globalSize); - } - - this.R_[7] = VM_MEMSIZE; - this.flags_ = 0; - - var preparedCodes = prg.AltCmd ? prg.AltCmd : prg.Cmd; - if (prg.Cmd.length > 0 && !this.executeCode(preparedCodes)) { - // Invalid VM program. Let's replace it with 'return' command. - preparedCode.OpCode = VM_Commands.VM_RET; - } - - var dataView = new DataView(this.mem_.buffer, VM_GLOBALMEMADDR); - var newBlockPos = dataView.getUint32(0x20, true /* little endian */) & VM_MEMMASK; - var newBlockSize = dataView.getUint32(0x1c, true /* little endian */) & VM_MEMMASK; - if (newBlockPos + newBlockSize >= VM_MEMSIZE) { - newBlockPos = newBlockSize = 0; - } - prg.FilteredData = this.mem_.subarray(newBlockPos, newBlockPos + newBlockSize); - - prg.GlobalData = new Uint8Array(0); - - var dataSize = Math.min(dataView.getUint32(0x30), - (VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE)); - if (dataSize != 0) { - var len = dataSize + VM_FIXEDGLOBALSIZE; - prg.GlobalData = new Uint8Array(len); - prg.GlobalData.set(mem.subarray(VM_GLOBALMEMADDR, VM_GLOBALMEMADDR + len)); - } + this.R_.set(prg.InitR); + + var globalSize = Math.min(prg.GlobalData.length, VM_GLOBALMEMSIZE); + if (globalSize) { + this.mem_.set(prg.GlobalData.subarray(0, globalSize), VM_GLOBALMEMADDR); + } + + var staticSize = Math.min(prg.StaticData.length, VM_GLOBALMEMSIZE - globalSize); + if (staticSize) { + this.mem_.set(prg.StaticData.subarray(0, staticSize), VM_GLOBALMEMADDR + globalSize); + } + + this.R_[7] = VM_MEMSIZE; + this.flags_ = 0; + + var preparedCodes = prg.AltCmd ? prg.AltCmd : prg.Cmd; + if (prg.Cmd.length > 0 && !this.executeCode(preparedCodes)) { + // Invalid VM program. Let's replace it with 'return' command. + preparedCode.OpCode = VM_Commands.VM_RET; + } + + var dataView = new DataView(this.mem_.buffer, VM_GLOBALMEMADDR); + var newBlockPos = dataView.getUint32(0x20, true /* little endian */ ) & VM_MEMMASK; + var newBlockSize = dataView.getUint32(0x1c, true /* little endian */ ) & VM_MEMMASK; + if (newBlockPos + newBlockSize >= VM_MEMSIZE) { + newBlockPos = newBlockSize = 0; + } + prg.FilteredData = this.mem_.subarray(newBlockPos, newBlockPos + newBlockSize); + + prg.GlobalData = new Uint8Array(0); + + var dataSize = Math.min(dataView.getUint32(0x30), + (VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE)); + if (dataSize != 0) { + var len = dataSize + VM_FIXEDGLOBALSIZE; + prg.GlobalData = new Uint8Array(len); + prg.GlobalData.set(mem.subarray(VM_GLOBALMEMADDR, VM_GLOBALMEMADDR + len)); + } }; /** @@ -545,68 +585,68 @@ RarVM.prototype.execute = function(prg) { * @return {boolean} */ RarVM.prototype.executeCode = function(preparedCodes) { - var codeIndex = 0; - var cmd = preparedCodes[codeIndex]; - // TODO: Why is this an infinite loop instead of just returning - // when a VM_RET is hit? - while (1) { - switch (cmd.OpCode) { - case VM_Commands.VM_RET: - if (this.R_[7] >= VM_MEMSIZE) { - return true; - } - //SET_IP(GET_VALUE(false,(uint *)&Mem[R[7] & VM_MEMMASK])); - this.R_[7] += 4; - continue; - - case VM_Commands.VM_STANDARD: - this.executeStandardFilter(cmd.Op1.Data); - break; - - default: - console.error('RarVM OpCode not supported: ' + getDebugString(VM_Commands, cmd.OpCode)); - break; - } // switch (cmd.OpCode) - codeIndex++; - cmd = preparedCodes[codeIndex]; - } + var codeIndex = 0; + var cmd = preparedCodes[codeIndex]; + // TODO: Why is this an infinite loop instead of just returning + // when a VM_RET is hit? + while (1) { + switch (cmd.OpCode) { + case VM_Commands.VM_RET: + if (this.R_[7] >= VM_MEMSIZE) { + return true; + } + //SET_IP(GET_VALUE(false,(uint *)&Mem[R[7] & VM_MEMMASK])); + this.R_[7] += 4; + continue; + + case VM_Commands.VM_STANDARD: + this.executeStandardFilter(cmd.Op1.Data); + break; + + default: + console.error('RarVM OpCode not supported: ' + getDebugString(VM_Commands, cmd.OpCode)); + break; + } // switch (cmd.OpCode) + codeIndex++; + cmd = preparedCodes[codeIndex]; + } }; /** * @param {number} filterType */ RarVM.prototype.executeStandardFilter = function(filterType) { - switch (filterType) { - case VM_StandardFilters.VMSF_DELTA: - var dataSize = this.R_[4]; - var channels = this.R_[0]; - var srcPos = 0; - var border = dataSize * 2; - - //SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); - var dataView = new DataView(this.mem_.buffer, VM_GLOBALMEMADDR); - dataView.setUint32(0x20, dataSize, true /* little endian */); - - if (dataSize >= VM_GLOBALMEMADDR / 2) { - break; - } + switch (filterType) { + case VM_StandardFilters.VMSF_DELTA: + var dataSize = this.R_[4]; + var channels = this.R_[0]; + var srcPos = 0; + var border = dataSize * 2; + + //SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); + var dataView = new DataView(this.mem_.buffer, VM_GLOBALMEMADDR); + dataView.setUint32(0x20, dataSize, true /* little endian */ ); + + if (dataSize >= VM_GLOBALMEMADDR / 2) { + break; + } - // Bytes from same channels are grouped to continual data blocks, - // so we need to place them back to their interleaving positions. - for (var curChannel = 0; curChannel < channels; ++curChannel) { - var prevByte = 0; - for (var destPos = dataSize + curChannel; destPos < border; destPos += channels) { - prevByte = (prevByte - this.mem_[srcPos++]) & 0xff; - this.mem_[destPos] = prevByte; - } - } + // Bytes from same channels are grouped to continual data blocks, + // so we need to place them back to their interleaving positions. + for (var curChannel = 0; curChannel < channels; ++curChannel) { + var prevByte = 0; + for (var destPos = dataSize + curChannel; destPos < border; destPos += channels) { + prevByte = (prevByte - this.mem_[srcPos++]) & 0xff; + this.mem_[destPos] = prevByte; + } + } - break; + break; - default: - console.error('RarVM Standard Filter not supported: ' + getDebugString(VM_StandardFilters, filterType)); - break; - } + default: + console.error('RarVM Standard Filter not supported: ' + getDebugString(VM_StandardFilters, filterType)); + break; + } }; /** @@ -614,138 +654,138 @@ RarVM.prototype.executeStandardFilter = function(filterType) { * @param {VM_PreparedProgram} prg */ RarVM.prototype.prepare = function(code, prg) { - var codeSize = code.length; - - //InitBitInput(); - //memcpy(InBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); - var bstream = new bitjs.io.BitStream(code.buffer, true /* rtl */); - - // Calculate the single byte XOR checksum to check validity of VM code. - var xorSum=0; - for (var i = 1; i < codeSize; ++i) { - xorSum ^= code[i]; - } - - bstream.readBits(8); - - prg.Cmd = []; // TODO: Is this right? I don't see it being done in rarvm.cpp. - - // VM code is valid if equal. - if (xorSum == code[0]) { - var filterType = this.isStandardFilter(code); - if (filterType != VM_StandardFilters.VMSF_NONE) { - // VM code is found among standard filters. - var curCmd = new VM_PreparedCommand(); - prg.Cmd.push(curCmd); - - curCmd.OpCode = VM_Commands.VM_STANDARD; - curCmd.Op1.Data = filterType; - // TODO: Addr=&CurCmd->Op1.Data - curCmd.Op1.Addr = [curCmd.Op1.Data]; - curCmd.Op2.Addr = [null]; // &CurCmd->Op2.Data; - curCmd.Op1.Type = VM_OpType.VM_OPNONE; - curCmd.Op2.Type = VM_OpType.VM_OPNONE; - codeSize = 0; + var codeSize = code.length; + + //InitBitInput(); + //memcpy(InBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); + var bstream = new bitjs.io.BitStream(code.buffer, true /* rtl */ ); + + // Calculate the single byte XOR checksum to check validity of VM code. + var xorSum = 0; + for (var i = 1; i < codeSize; ++i) { + xorSum ^= code[i]; } - var dataFlag = bstream.readBits(1); + bstream.readBits(8); + + prg.Cmd = []; // TODO: Is this right? I don't see it being done in rarvm.cpp. + + // VM code is valid if equal. + if (xorSum == code[0]) { + var filterType = this.isStandardFilter(code); + if (filterType != VM_StandardFilters.VMSF_NONE) { + // VM code is found among standard filters. + var curCmd = new VM_PreparedCommand(); + prg.Cmd.push(curCmd); + + curCmd.OpCode = VM_Commands.VM_STANDARD; + curCmd.Op1.Data = filterType; + // TODO: Addr=&CurCmd->Op1.Data + curCmd.Op1.Addr = [curCmd.Op1.Data]; + curCmd.Op2.Addr = [null]; // &CurCmd->Op2.Data; + curCmd.Op1.Type = VM_OpType.VM_OPNONE; + curCmd.Op2.Type = VM_OpType.VM_OPNONE; + codeSize = 0; + } - // Read static data contained in DB operators. This data cannot be - // changed, it is a part of VM code, not a filter parameter. + var dataFlag = bstream.readBits(1); - if (dataFlag & 0x8000) { - var dataSize = RarVM.readData(bstream) + 1; - // TODO: This accesses the byte pointer of the bstream directly. Is that ok? - for (var i = 0; i < bstream.bytePtr < codeSize && i < dataSize; ++i) { - // Append a byte to the program's static data. - var newStaticData = new Uint8Array(prg.StaticData.length + 1); - newStaticData.set(prg.StaticData); - newStaticData[newStaticData.length - 1] = bstream.readBits(8); - prg.StaticData = newStaticData; - } - } + // Read static data contained in DB operators. This data cannot be + // changed, it is a part of VM code, not a filter parameter. - while (bstream.bytePtr < codeSize) { - var curCmd = new VM_PreparedCommand(); - prg.Cmd.push(curCmd); // Prg->Cmd.Add(1) - var flag = bstream.peekBits(1); - if (!flag) { // (Data&0x8000)==0 - curCmd.OpCode = bstream.readBits(4); - } else { - curCmd.OpCode = (bstream.readBits(6) - 24); - } + if (dataFlag & 0x8000) { + var dataSize = RarVM.readData(bstream) + 1; + // TODO: This accesses the byte pointer of the bstream directly. Is that ok? + for (var i = 0; i < bstream.bytePtr < codeSize && i < dataSize; ++i) { + // Append a byte to the program's static data. + var newStaticData = new Uint8Array(prg.StaticData.length + 1); + newStaticData.set(prg.StaticData); + newStaticData[newStaticData.length - 1] = bstream.readBits(8); + prg.StaticData = newStaticData; + } + } - if (VM_CmdFlags[curCmd.OpCode] & VMCF_BYTEMODE) { - curCmd.ByteMode = (bstream.readBits(1) != 0); - } else { - curCmd.ByteMode = 0; - } - curCmd.Op1.Type = VM_OpType.VM_OPNONE; - curCmd.Op2.Type = VM_OpType.VM_OPNONE; - var opNum = (VM_CmdFlags[curCmd.OpCode] & VMCF_OPMASK); - curCmd.Op1.Addr = null; - curCmd.Op2.Addr = null; - if (opNum > 0) { - this.decodeArg(curCmd.Op1, curCmd.ByteMode, bstream); // reading the first operand - if (opNum == 2) { - this.decodeArg(curCmd.Op2, curCmd.ByteMode, bstream); // reading the second operand - } else { - if (curCmd.Op1.Type == VM_OpType.VM_OPINT && (VM_CmdFlags[curCmd.OpCode] & (VMCF_JUMP|VMCF_PROC))) { - // Calculating jump distance. - var distance = curCmd.Op1.Data; - if (distance >= 256) { - distance -= 256; + while (bstream.bytePtr < codeSize) { + var curCmd = new VM_PreparedCommand(); + prg.Cmd.push(curCmd); // Prg->Cmd.Add(1) + var flag = bstream.peekBits(1); + if (!flag) { // (Data&0x8000)==0 + curCmd.OpCode = bstream.readBits(4); } else { - if (distance >= 136) { - distance -= 264; - } else { - if (distance >= 16) { - distance -= 8; + curCmd.OpCode = (bstream.readBits(6) - 24); + } + + if (VM_CmdFlags[curCmd.OpCode] & VMCF_BYTEMODE) { + curCmd.ByteMode = (bstream.readBits(1) != 0); + } else { + curCmd.ByteMode = 0; + } + curCmd.Op1.Type = VM_OpType.VM_OPNONE; + curCmd.Op2.Type = VM_OpType.VM_OPNONE; + var opNum = (VM_CmdFlags[curCmd.OpCode] & VMCF_OPMASK); + curCmd.Op1.Addr = null; + curCmd.Op2.Addr = null; + if (opNum > 0) { + this.decodeArg(curCmd.Op1, curCmd.ByteMode, bstream); // reading the first operand + if (opNum == 2) { + this.decodeArg(curCmd.Op2, curCmd.ByteMode, bstream); // reading the second operand } else { - if (distance >= 8) { - distance -= 16; - } + if (curCmd.Op1.Type == VM_OpType.VM_OPINT && (VM_CmdFlags[curCmd.OpCode] & (VMCF_JUMP | VMCF_PROC))) { + // Calculating jump distance. + var distance = curCmd.Op1.Data; + if (distance >= 256) { + distance -= 256; + } else { + if (distance >= 136) { + distance -= 264; + } else { + if (distance >= 16) { + distance -= 8; + } else { + if (distance >= 8) { + distance -= 16; + } + } + } + distance += prg.Cmd.length; + } + curCmd.Op1.Data = distance; + } } - } - distance += prg.Cmd.length; - } - curCmd.Op1.Data = distance; - } + } // if (OpNum>0) + } // while ((uint)InAddrOp1.Data + curCmd.Op1.Addr = [curCmd.Op1.Data]; + curCmd.Op2.Addr = [curCmd.Op2.Data]; + curCmd.Op1.Type = VM_OpType.VM_OPNONE; + curCmd.Op2.Type = VM_OpType.VM_OPNONE; + + // If operand 'Addr' field has not been set by DecodeArg calls above, + // let's set it to point to operand 'Data' field. It is necessary for + // VM_OPINT type operands (usual integers) or maybe if something was + // not set properly for other operands. 'Addr' field is required + // for quicker addressing of operand data. + for (var i = 0; i < prg.Cmd.length; ++i) { + var cmd = prg.Cmd[i]; + if (cmd.Op1.Addr == null) { + cmd.Op1.Addr = [cmd.Op1.Data]; + } + if (cmd.Op2.Addr == null) { + cmd.Op2.Addr = [cmd.Op2.Data]; } - } // if (OpNum>0) - } // while ((uint)InAddrOp1.Data - curCmd.Op1.Addr = [curCmd.Op1.Data]; - curCmd.Op2.Addr = [curCmd.Op2.Data]; - curCmd.Op1.Type = VM_OpType.VM_OPNONE; - curCmd.Op2.Type = VM_OpType.VM_OPNONE; - - // If operand 'Addr' field has not been set by DecodeArg calls above, - // let's set it to point to operand 'Data' field. It is necessary for - // VM_OPINT type operands (usual integers) or maybe if something was - // not set properly for other operands. 'Addr' field is required - // for quicker addressing of operand data. - for (var i = 0; i < prg.Cmd.length; ++i) { - var cmd = prg.Cmd[i]; - if (cmd.Op1.Addr == null) { - cmd.Op1.Addr = [cmd.Op1.Data]; - } - if (cmd.Op2.Addr == null) { - cmd.Op2.Addr = [cmd.Op2.Data]; } - } - -/* -#ifdef VM_OPTIMIZE - if (CodeSize!=0) - Optimize(Prg); -#endif - */ + + /* + #ifdef VM_OPTIMIZE + if (CodeSize!=0) + Optimize(Prg); + #endif + */ }; /** @@ -754,11 +794,11 @@ RarVM.prototype.prepare = function(code, prg) { * @param {number} offset Offset into arr to start setting the value, defaults to 0. */ RarVM.prototype.setLowEndianValue = function(arr, value, offset) { - var i = offset || 0; - arr[i] = value & 0xff; - arr[i + 1] = (value >>> 8) & 0xff; - arr[i + 2] = (value >>> 16) & 0xff; - arr[i + 3] = (value >>> 24) & 0xff; + var i = offset || 0; + arr[i] = value & 0xff; + arr[i + 1] = (value >>> 8) & 0xff; + arr[i + 2] = (value >>> 16) & 0xff; + arr[i + 3] = (value >>> 24) & 0xff; }; /** @@ -769,12 +809,12 @@ RarVM.prototype.setLowEndianValue = function(arr, value, offset) { * @param {number} dataSize The number of bytes to set. */ RarVM.prototype.setMemory = function(pos, buffer, dataSize) { - if (pos < VM_MEMSIZE) { - var numBytes = Math.min(dataSize, VM_MEMSIZE - pos); - for (var i = 0; i < numBytes; ++i) { - this.mem_[pos + i] = buffer[i]; + if (pos < VM_MEMSIZE) { + var numBytes = Math.min(dataSize, VM_MEMSIZE - pos); + for (var i = 0; i < numBytes; ++i) { + this.mem_[pos + i] = buffer[i]; + } } - } }; /** @@ -784,35 +824,35 @@ RarVM.prototype.setMemory = function(pos, buffer, dataSize) { * @return {number} The value of the bits read. */ RarVM.readData = function(bstream) { - // Read in the first 2 bits. - var flags = bstream.readBits(2); - switch (flags) { // Data&0xc000 - // Return the next 4 bits. - case 0: - return bstream.readBits(4); // (Data>>10)&0xf - - case 1: // 0x4000 - // 0x3c00 => 0011 1100 0000 0000 - if (bstream.peekBits(4) == 0) { // (Data&0x3c00)==0 - // Skip the 4 zero bits. - bstream.readBits(4); - // Read in the next 8 and pad with 1s to 32 bits. - return (0xffffff00 | bstream.readBits(8)) >>> 0; // ((Data>>2)&0xff) - } + // Read in the first 2 bits. + var flags = bstream.readBits(2); + switch (flags) { // Data&0xc000 + // Return the next 4 bits. + case 0: + return bstream.readBits(4); // (Data>>10)&0xf + + case 1: // 0x4000 + // 0x3c00 => 0011 1100 0000 0000 + if (bstream.peekBits(4) == 0) { // (Data&0x3c00)==0 + // Skip the 4 zero bits. + bstream.readBits(4); + // Read in the next 8 and pad with 1s to 32 bits. + return (0xffffff00 | bstream.readBits(8)) >>> 0; // ((Data>>2)&0xff) + } - // Else, read in the next 8. - return bstream.readBits(8); + // Else, read in the next 8. + return bstream.readBits(8); - // Read in the next 16. - case 2: // 0x8000 - var val = bstream.getBits(); - bstream.readBits(16); - return val; //bstream.readBits(16); + // Read in the next 16. + case 2: // 0x8000 + var val = bstream.getBits(); + bstream.readBits(16); + return val; //bstream.readBits(16); - // case 3 - default: - return (bstream.readBits(16) << 16) | bstream.readBits(16); - } + // case 3 + default: + return (bstream.readBits(16) << 16) | bstream.readBits(16); + } }; -// ============================================================================================== // +// ============================================================================================== // \ No newline at end of file diff --git a/cps/static/js/archive/unrar.js b/cps/static/js/archive/unrar.js index fe2c74b7..d8a4fda7 100644 --- a/cps/static/js/archive/unrar.js +++ b/cps/static/js/archive/unrar.js @@ -23,42 +23,42 @@ var totalFilesInArchive = 0; // Helper functions. var info = function(str) { - postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); + postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); }; var err = function(str) { - postMessage(new bitjs.archive.UnarchiveErrorEvent(str)); + postMessage(new bitjs.archive.UnarchiveErrorEvent(str)); }; var postProgress = function() { - postMessage(new bitjs.archive.UnarchiveProgressEvent( - currentFilename, - currentFileNumber, - currentBytesUnarchivedInFile, - currentBytesUnarchived, - totalUncompressedBytesInArchive, - totalFilesInArchive)); + postMessage(new bitjs.archive.UnarchiveProgressEvent( + currentFilename, + currentFileNumber, + currentBytesUnarchivedInFile, + currentBytesUnarchived, + totalUncompressedBytesInArchive, + totalFilesInArchive)); }; // shows a byte value as its hex representation var nibble = "0123456789ABCDEF"; var byteValueToHexString = function(num) { - return nibble[num>>4] + nibble[num&0xF]; + return nibble[num >> 4] + nibble[num & 0xF]; }; var twoByteValueToHexString = function(num) { - return nibble[(num>>12)&0xF] + nibble[(num>>8)&0xF] + nibble[(num>>4)&0xF] + nibble[num&0xF]; + return nibble[(num >> 12) & 0xF] + nibble[(num >> 8) & 0xF] + nibble[(num >> 4) & 0xF] + nibble[num & 0xF]; }; // Volume Types -var MARK_HEAD = 0x72, - MAIN_HEAD = 0x73, - FILE_HEAD = 0x74, - COMM_HEAD = 0x75, - AV_HEAD = 0x76, - SUB_HEAD = 0x77, - PROTECT_HEAD = 0x78, - SIGN_HEAD = 0x79, - NEWSUB_HEAD = 0x7a, - ENDARC_HEAD = 0x7b; +var MARK_HEAD = 0x72, + MAIN_HEAD = 0x73, + FILE_HEAD = 0x74, + COMM_HEAD = 0x75, + AV_HEAD = 0x76, + SUB_HEAD = 0x77, + PROTECT_HEAD = 0x78, + SIGN_HEAD = 0x79, + NEWSUB_HEAD = 0x7a, + ENDARC_HEAD = 0x7b; // ============================================================================================== // @@ -67,207 +67,209 @@ var MARK_HEAD = 0x72, * @constructor */ var RarVolumeHeader = function(bstream) { - var headPos = bstream.bytePtr; - // byte 1,2 - info("Rar Volume Header @"+bstream.bytePtr); - - this.crc = bstream.readBits(16); - info(" crc=" + this.crc); - - // byte 3 - this.headType = bstream.readBits(8); - info(" headType=" + this.headType); - - // Get flags - // bytes 4,5 - this.flags = {}; - this.flags.value = bstream.peekBits(16); - - info(" flags=" + twoByteValueToHexString(this.flags.value)); - switch (this.headType) { - case MAIN_HEAD: - this.flags.MHD_VOLUME = !!bstream.readBits(1); - this.flags.MHD_COMMENT = !!bstream.readBits(1); - this.flags.MHD_LOCK = !!bstream.readBits(1); - this.flags.MHD_SOLID = !!bstream.readBits(1); - this.flags.MHD_PACK_COMMENT = !!bstream.readBits(1); - this.flags.MHD_NEWNUMBERING = this.flags.MHD_PACK_COMMENT; - this.flags.MHD_AV = !!bstream.readBits(1); - this.flags.MHD_PROTECT = !!bstream.readBits(1); - this.flags.MHD_PASSWORD = !!bstream.readBits(1); - this.flags.MHD_FIRSTVOLUME = !!bstream.readBits(1); - this.flags.MHD_ENCRYPTVER = !!bstream.readBits(1); - bstream.readBits(6); // unused - break; - case FILE_HEAD: - this.flags.LHD_SPLIT_BEFORE = !!bstream.readBits(1); // 0x0001 - this.flags.LHD_SPLIT_AFTER = !!bstream.readBits(1); // 0x0002 - this.flags.LHD_PASSWORD = !!bstream.readBits(1); // 0x0004 - this.flags.LHD_COMMENT = !!bstream.readBits(1); // 0x0008 - this.flags.LHD_SOLID = !!bstream.readBits(1); // 0x0010 - bstream.readBits(3); // unused - this.flags.LHD_LARGE = !!bstream.readBits(1); // 0x0100 - this.flags.LHD_UNICODE = !!bstream.readBits(1); // 0x0200 - this.flags.LHD_SALT = !!bstream.readBits(1); // 0x0400 - this.flags.LHD_VERSION = !!bstream.readBits(1); // 0x0800 - this.flags.LHD_EXTTIME = !!bstream.readBits(1); // 0x1000 - this.flags.LHD_EXTFLAGS = !!bstream.readBits(1); // 0x2000 - bstream.readBits(2); // unused - info(" LHD_SPLIT_BEFORE = " + this.flags.LHD_SPLIT_BEFORE); - break; - default: - bstream.readBits(16); - } - - // byte 6,7 - this.headSize = bstream.readBits(16); - info(" headSize=" + this.headSize); - switch (this.headType) { - case MAIN_HEAD: - this.highPosAv = bstream.readBits(16); - this.posAv = bstream.readBits(32); - if (this.flags.MHD_ENCRYPTVER) { - this.encryptVer = bstream.readBits(8); - } - info("Found MAIN_HEAD with highPosAv=" + this.highPosAv + ", posAv=" + this.posAv); - break; - case FILE_HEAD: - this.packSize = bstream.readBits(32); - this.unpackedSize = bstream.readBits(32); - this.hostOS = bstream.readBits(8); - this.fileCRC = bstream.readBits(32); - this.fileTime = bstream.readBits(32); - this.unpVer = bstream.readBits(8); - this.method = bstream.readBits(8); - this.nameSize = bstream.readBits(16); - this.fileAttr = bstream.readBits(32); - - if (this.flags.LHD_LARGE) { - info("Warning: Reading in LHD_LARGE 64-bit size values"); - this.HighPackSize = bstream.readBits(32); - this.HighUnpSize = bstream.readBits(32); - } else { - this.HighPackSize = 0; - this.HighUnpSize = 0; - if (this.unpackedSize == 0xffffffff) { - this.HighUnpSize = 0x7fffffff - this.unpackedSize = 0xffffffff; - } - } - this.fullPackSize = 0; - this.fullUnpackSize = 0; - this.fullPackSize |= this.HighPackSize; - this.fullPackSize <<= 32; - this.fullPackSize |= this.packSize; - - // read in filename - - this.filename = bstream.readBytes(this.nameSize); - for (var _i = 0, _s = ''; _i < this.filename.length; _i++) { - _s += String.fromCharCode(this.filename[_i]); - } - - this.filename = _s; - - if (this.flags.LHD_SALT) { - info("Warning: Reading in 64-bit salt value"); - this.salt = bstream.readBits(64); // 8 bytes - } - - if (this.flags.LHD_EXTTIME) { - // 16-bit flags - var extTimeFlags = bstream.readBits(16); - - // this is adapted straight out of arcread.cpp, Archive::ReadHeader() - for (var I = 0; I < 4; ++I) { - var rmode = extTimeFlags >> ((3-I)*4); - if ((rmode & 8)==0) { - continue; - } - if (I!=0) - bstream.readBits(16); - var count = (rmode&3); - for (var J = 0; J < count; ++J) { - bstream.readBits(8); - } - } - } - - if (this.flags.LHD_COMMENT) { - info("Found a LHD_COMMENT"); + var headPos = bstream.bytePtr; + // byte 1,2 + info("Rar Volume Header @" + bstream.bytePtr); + + this.crc = bstream.readBits(16); + info(" crc=" + this.crc); + + // byte 3 + this.headType = bstream.readBits(8); + info(" headType=" + this.headType); + + // Get flags + // bytes 4,5 + this.flags = {}; + this.flags.value = bstream.peekBits(16); + + info(" flags=" + twoByteValueToHexString(this.flags.value)); + switch (this.headType) { + case MAIN_HEAD: + this.flags.MHD_VOLUME = !!bstream.readBits(1); + this.flags.MHD_COMMENT = !!bstream.readBits(1); + this.flags.MHD_LOCK = !!bstream.readBits(1); + this.flags.MHD_SOLID = !!bstream.readBits(1); + this.flags.MHD_PACK_COMMENT = !!bstream.readBits(1); + this.flags.MHD_NEWNUMBERING = this.flags.MHD_PACK_COMMENT; + this.flags.MHD_AV = !!bstream.readBits(1); + this.flags.MHD_PROTECT = !!bstream.readBits(1); + this.flags.MHD_PASSWORD = !!bstream.readBits(1); + this.flags.MHD_FIRSTVOLUME = !!bstream.readBits(1); + this.flags.MHD_ENCRYPTVER = !!bstream.readBits(1); + bstream.readBits(6); // unused + break; + case FILE_HEAD: + this.flags.LHD_SPLIT_BEFORE = !!bstream.readBits(1); // 0x0001 + this.flags.LHD_SPLIT_AFTER = !!bstream.readBits(1); // 0x0002 + this.flags.LHD_PASSWORD = !!bstream.readBits(1); // 0x0004 + this.flags.LHD_COMMENT = !!bstream.readBits(1); // 0x0008 + this.flags.LHD_SOLID = !!bstream.readBits(1); // 0x0010 + bstream.readBits(3); // unused + this.flags.LHD_LARGE = !!bstream.readBits(1); // 0x0100 + this.flags.LHD_UNICODE = !!bstream.readBits(1); // 0x0200 + this.flags.LHD_SALT = !!bstream.readBits(1); // 0x0400 + this.flags.LHD_VERSION = !!bstream.readBits(1); // 0x0800 + this.flags.LHD_EXTTIME = !!bstream.readBits(1); // 0x1000 + this.flags.LHD_EXTFLAGS = !!bstream.readBits(1); // 0x2000 + bstream.readBits(2); // unused + info(" LHD_SPLIT_BEFORE = " + this.flags.LHD_SPLIT_BEFORE); + break; + default: + bstream.readBits(16); } - - - while (headPos + this.headSize > bstream.bytePtr) { - bstream.readBits(1); + + // byte 6,7 + this.headSize = bstream.readBits(16); + info(" headSize=" + this.headSize); + switch (this.headType) { + case MAIN_HEAD: + this.highPosAv = bstream.readBits(16); + this.posAv = bstream.readBits(32); + if (this.flags.MHD_ENCRYPTVER) { + this.encryptVer = bstream.readBits(8); + } + info("Found MAIN_HEAD with highPosAv=" + this.highPosAv + ", posAv=" + this.posAv); + break; + case FILE_HEAD: + this.packSize = bstream.readBits(32); + this.unpackedSize = bstream.readBits(32); + this.hostOS = bstream.readBits(8); + this.fileCRC = bstream.readBits(32); + this.fileTime = bstream.readBits(32); + this.unpVer = bstream.readBits(8); + this.method = bstream.readBits(8); + this.nameSize = bstream.readBits(16); + this.fileAttr = bstream.readBits(32); + + if (this.flags.LHD_LARGE) { + info("Warning: Reading in LHD_LARGE 64-bit size values"); + this.HighPackSize = bstream.readBits(32); + this.HighUnpSize = bstream.readBits(32); + } else { + this.HighPackSize = 0; + this.HighUnpSize = 0; + if (this.unpackedSize == 0xffffffff) { + this.HighUnpSize = 0x7fffffff + this.unpackedSize = 0xffffffff; + } + } + this.fullPackSize = 0; + this.fullUnpackSize = 0; + this.fullPackSize |= this.HighPackSize; + this.fullPackSize <<= 32; + this.fullPackSize |= this.packSize; + + // read in filename + + this.filename = bstream.readBytes(this.nameSize); + for (var _i = 0, _s = ''; _i < this.filename.length; _i++) { + _s += String.fromCharCode(this.filename[_i]); + } + + this.filename = _s; + + if (this.flags.LHD_SALT) { + info("Warning: Reading in 64-bit salt value"); + this.salt = bstream.readBits(64); // 8 bytes + } + + if (this.flags.LHD_EXTTIME) { + // 16-bit flags + var extTimeFlags = bstream.readBits(16); + + // this is adapted straight out of arcread.cpp, Archive::ReadHeader() + for (var I = 0; I < 4; ++I) { + var rmode = extTimeFlags >> ((3 - I) * 4); + if ((rmode & 8) == 0) { + continue; + } + if (I != 0) + bstream.readBits(16); + var count = (rmode & 3); + for (var J = 0; J < count; ++J) { + bstream.readBits(8); + } + } + } + + if (this.flags.LHD_COMMENT) { + info("Found a LHD_COMMENT"); + } + + + while (headPos + this.headSize > bstream.bytePtr) { + bstream.readBits(1); + } + + 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: + 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; } - - 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: - 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; - } }; var BLOCK_LZ = 0, - BLOCK_PPM = 1; - -var rLDecode = [0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224], - rLBits = [0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5], - rDBitLengthCounts = [4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,0,12], - rSDDecode = [0,4,8,16,32,64,128,192], - rSDBits = [2,2,3, 4, 5, 6, 6, 6]; - + BLOCK_PPM = 1; + +var rLDecode = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224], + rLBits = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5], + rDBitLengthCounts = [4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 14, 0, 12], + rSDDecode = [0, 4, 8, 16, 32, 64, 128, 192], + rSDBits = [2, 2, 3, 4, 5, 6, 6, 6]; + var rDDecode = [0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, - 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, - 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304, - 131072, 196608, 262144, 327680, 393216, 458752, 524288, 589824, - 655360, 720896, 786432, 851968, 917504, 983040]; + 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, + 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304, + 131072, 196608, 262144, 327680, 393216, 458752, 524288, 589824, + 655360, 720896, 786432, 851968, 917504, 983040 +]; var rDBits = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, - 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, - 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16]; + 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 +]; var rLOW_DIST_REP_COUNT = 16; var rNC = 299, - rDC = 60, - rLDC = 17, - rRC = 28, - rBC = 20, - rHUFF_TABLE_SIZE = (rNC+rDC+rRC+rLDC); + rDC = 60, + rLDC = 17, + rRC = 28, + rBC = 20, + rHUFF_TABLE_SIZE = (rNC + rDC + rRC + rLDC); var UnpBlockType = BLOCK_LZ; var UnpOldTable = new Array(rHUFF_TABLE_SIZE); var BD = { //bitdecode - DecodeLen: new Array(16), - DecodePos: new Array(16), - DecodeNum: new Array(rBC) + DecodeLen: new Array(16), + DecodePos: new Array(16), + DecodeNum: new Array(rBC) }; var LD = { //litdecode - DecodeLen: new Array(16), - DecodePos: new Array(16), - DecodeNum: new Array(rNC) + DecodeLen: new Array(16), + DecodePos: new Array(16), + DecodeNum: new Array(rNC) }; var DD = { //distdecode - DecodeLen: new Array(16), - DecodePos: new Array(16), - DecodeNum: new Array(rDC) + DecodeLen: new Array(16), + DecodePos: new Array(16), + DecodeNum: new Array(rDC) }; var LDD = { //low dist decode - DecodeLen: new Array(16), - DecodePos: new Array(16), - DecodeNum: new Array(rLDC) + DecodeLen: new Array(16), + DecodePos: new Array(16), + DecodeNum: new Array(rLDC) }; var RD = { //rep decode - DecodeLen: new Array(16), - DecodePos: new Array(16), - DecodeNum: new Array(rRC) + DecodeLen: new Array(16), + DecodePos: new Array(16), + DecodeNum: new Array(rRC) }; /** @@ -304,143 +306,143 @@ var wBuffer; * @param {bitjs.io.BitStream} bstream */ function RarReadTables(bstream) { - var BitLength = new Array(rBC); - var Table = new Array(rHUFF_TABLE_SIZE); - - // before we start anything we need to get byte-aligned - bstream.readBits( (8 - bstream.bitPtr) & 0x7 ); - - if (bstream.readBits(1)) { - info("Error! PPM not implemented yet"); - return; - } - - if (!bstream.readBits(1)) { //discard old table - for (var i = UnpOldTable.length; i--;) { - UnpOldTable[i] = 0; + var BitLength = new Array(rBC); + var Table = new Array(rHUFF_TABLE_SIZE); + + // before we start anything we need to get byte-aligned + bstream.readBits((8 - bstream.bitPtr) & 0x7); + + if (bstream.readBits(1)) { + info("Error! PPM not implemented yet"); + return; } - } - - // read in bit lengths - for (var I = 0; I < rBC; ++I) { - var Length = bstream.readBits(4); - if (Length == 15) { - var ZeroCount = bstream.readBits(4); - if (ZeroCount == 0) { - BitLength[I] = 15; - } - else { - ZeroCount += 2; - while (ZeroCount-- > 0 && I < rBC) - BitLength[I++] = 0; - --I; - } + + if (!bstream.readBits(1)) { //discard old table + for (var i = UnpOldTable.length; i--;) { + UnpOldTable[i] = 0; + } } - else { - BitLength[I] = Length; + + // read in bit lengths + for (var I = 0; I < rBC; ++I) { + var Length = bstream.readBits(4); + if (Length == 15) { + var ZeroCount = bstream.readBits(4); + if (ZeroCount == 0) { + BitLength[I] = 15; + } else { + ZeroCount += 2; + while (ZeroCount-- > 0 && I < rBC) + BitLength[I++] = 0; + --I; + } + } else { + BitLength[I] = Length; + } + } + + // now all 20 bit lengths are obtained, we construct the Huffman Table: + + RarMakeDecodeTables(BitLength, 0, BD, rBC); + + var TableSize = rHUFF_TABLE_SIZE; + //console.log(DecodeLen, DecodePos, DecodeNum); + for (var i = 0; i < TableSize;) { + var num = RarDecodeNumber(bstream, BD); + if (num < 16) { + Table[i] = (num + UnpOldTable[i]) & 0xf; + i++; + } else if (num < 18) { + var N = (num == 16) ? (bstream.readBits(3) + 3) : (bstream.readBits(7) + 11); + + while (N-- > 0 && i < TableSize) { + Table[i] = Table[i - 1]; + i++; + } + } else { + var N = (num == 18) ? (bstream.readBits(3) + 3) : (bstream.readBits(7) + 11); + + while (N-- > 0 && i < TableSize) { + Table[i++] = 0; + } + } } - } - - // now all 20 bit lengths are obtained, we construct the Huffman Table: - - RarMakeDecodeTables(BitLength, 0, BD, rBC); - - var TableSize = rHUFF_TABLE_SIZE; - //console.log(DecodeLen, DecodePos, DecodeNum); - for (var i = 0; i < TableSize;) { - var num = RarDecodeNumber(bstream, BD); - if (num < 16) { - Table[i] = (num + UnpOldTable[i]) & 0xf; - i++; - } else if (num < 18) { - var N = (num == 16) ? (bstream.readBits(3) + 3) : (bstream.readBits(7) + 11); - - while (N-- > 0 && i < TableSize) { - Table[i] = Table[i - 1]; - i++; - } - } else { - var N = (num == 18) ? (bstream.readBits(3) + 3) : (bstream.readBits(7) + 11); - while (N-- > 0 && i < TableSize) { - Table[i++] = 0; - } + RarMakeDecodeTables(Table, 0, LD, rNC); + RarMakeDecodeTables(Table, rNC, DD, rDC); + RarMakeDecodeTables(Table, rNC + rDC, LDD, rLDC); + RarMakeDecodeTables(Table, rNC + rDC + rLDC, RD, rRC); + + for (var i = UnpOldTable.length; i--;) { + UnpOldTable[i] = Table[i]; } - } - - RarMakeDecodeTables(Table, 0, LD, rNC); - RarMakeDecodeTables(Table, rNC, DD, rDC); - RarMakeDecodeTables(Table, rNC + rDC, LDD, rLDC); - RarMakeDecodeTables(Table, rNC + rDC + rLDC, RD, rRC); - - for (var i = UnpOldTable.length; i--;) { - UnpOldTable[i] = Table[i]; - } - return true; + return true; } function RarDecodeNumber(bstream, dec) { - var DecodeLen = dec.DecodeLen, DecodePos = dec.DecodePos, DecodeNum = dec.DecodeNum; - var bitField = bstream.getBits() & 0xfffe; - //some sort of rolled out binary search - var bits = ((bitField < DecodeLen[8])? - ((bitField < DecodeLen[4])? - ((bitField < DecodeLen[2])? - ((bitField < DecodeLen[1])?1:2) - :((bitField < DecodeLen[3])?3:4)) - :(bitField < DecodeLen[6])? - ((bitField < DecodeLen[5])?5:6) - :((bitField < DecodeLen[7])?7:8)) - :((bitField < DecodeLen[12])? - ((bitField < DecodeLen[10])? - ((bitField < DecodeLen[9])?9:10) - :((bitField < DecodeLen[11])?11:12)) - :(bitField < DecodeLen[14])? - ((bitField < DecodeLen[13])?13:14) - :15)); - bstream.readBits(bits); - var N = DecodePos[bits] + ((bitField - DecodeLen[bits -1]) >>> (16 - bits)); - - return DecodeNum[N]; + var DecodeLen = dec.DecodeLen, + DecodePos = dec.DecodePos, + DecodeNum = dec.DecodeNum; + var bitField = bstream.getBits() & 0xfffe; + //some sort of rolled out binary search + var bits = ((bitField < DecodeLen[8]) ? + ((bitField < DecodeLen[4]) ? + ((bitField < DecodeLen[2]) ? + ((bitField < DecodeLen[1]) ? 1 : 2) : + ((bitField < DecodeLen[3]) ? 3 : 4)) : + (bitField < DecodeLen[6]) ? + ((bitField < DecodeLen[5]) ? 5 : 6) : + ((bitField < DecodeLen[7]) ? 7 : 8)) : + ((bitField < DecodeLen[12]) ? + ((bitField < DecodeLen[10]) ? + ((bitField < DecodeLen[9]) ? 9 : 10) : + ((bitField < DecodeLen[11]) ? 11 : 12)) : + (bitField < DecodeLen[14]) ? + ((bitField < DecodeLen[13]) ? 13 : 14) : + 15)); + bstream.readBits(bits); + var N = DecodePos[bits] + ((bitField - DecodeLen[bits - 1]) >>> (16 - bits)); + + return DecodeNum[N]; } function RarMakeDecodeTables(BitLength, offset, dec, size) { - var DecodeLen = dec.DecodeLen; - var DecodePos = dec.DecodePos; - var DecodeNum = dec.DecodeNum; - var LenCount = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; - var TmpPos = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; - var N = 0; - var M = 0; - - for (var i = DecodeNum.length; i--;) { - DecodeNum[i] = 0; - } - for (var i = 0; i < size; i++) { - LenCount[BitLength[i + offset] & 0xF]++; - } - LenCount[0] = 0; - TmpPos[0] = 0; - DecodePos[0] = 0; - DecodeLen[0] = 0; - - for (var I = 1; I < 16; ++I) { - N = 2 * (N+LenCount[I]); - M = (N << (15-I)); - if (M > 0xFFFF) { - M = 0xFFFF; + var DecodeLen = dec.DecodeLen; + var DecodePos = dec.DecodePos; + var DecodeNum = dec.DecodeNum; + var LenCount = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var TmpPos = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var N = 0; + var M = 0; + + for (var i = DecodeNum.length; i--;) { + DecodeNum[i] = 0; } - DecodeLen[I] = M; - DecodePos[I] = DecodePos[I-1] + LenCount[I-1]; - TmpPos[I] = DecodePos[I]; - } - for (I = 0; I < size; ++I) { - if (BitLength[I + offset] != 0) { - DecodeNum[ TmpPos[ BitLength[offset + I] & 0xF ]++] = I; + for (var i = 0; i < size; i++) { + LenCount[BitLength[i + offset] & 0xF]++; + } + LenCount[0] = 0; + TmpPos[0] = 0; + DecodePos[0] = 0; + DecodeLen[0] = 0; + + for (var I = 1; I < 16; ++I) { + N = 2 * (N + LenCount[I]); + M = (N << (15 - I)); + if (M > 0xFFFF) { + M = 0xFFFF; + } + DecodeLen[I] = M; + DecodePos[I] = DecodePos[I - 1] + LenCount[I - 1]; + TmpPos[I] = DecodePos[I]; + } + for (I = 0; I < size; ++I) { + if (BitLength[I + offset] != 0) { + DecodeNum[TmpPos[BitLength[offset + I] & 0xF]++] = I; + } } - } } @@ -450,7 +452,7 @@ function RarMakeDecodeTables(BitLength, offset, dec, size) { * @param {boolean} Solid */ function Unpack15(bstream, Solid) { - info("ERROR! RAR 1.5 compression not supported"); + info("ERROR! RAR 1.5 compression not supported"); } /** @@ -459,88 +461,88 @@ function Unpack15(bstream, Solid) { * @param {boolean} Solid */ function Unpack20(bstream, Solid) { - var destUnpSize = rBuffer.data.length; - var oldDistPtr = 0; - - RarReadTables20(bstream); - while (destUnpSize > rBuffer.ptr) { - var num = RarDecodeNumber(bstream, LD); - if (num < 256) { - rBuffer.insertByte(num); - continue; - } - if (num > 269) { - var Length = rLDecode[num -= 270] + 3; - if ((Bits = rLBits[num]) > 0) { - Length += bstream.readBits(Bits); - } - var DistNumber = RarDecodeNumber(bstream, DD); - var Distance = rDDecode[DistNumber] + 1; - if ((Bits = rDBits[DistNumber]) > 0) { - Distance += bstream.readBits(Bits); - } - if (Distance >= 0x2000) { - Length++; - if (Distance >= 0x40000) { - Length++; + var destUnpSize = rBuffer.data.length; + var oldDistPtr = 0; + + RarReadTables20(bstream); + while (destUnpSize > rBuffer.ptr) { + var num = RarDecodeNumber(bstream, LD); + if (num < 256) { + rBuffer.insertByte(num); + continue; } - } - lastLength = Length; - lastDist = rOldDist[oldDistPtr++ & 3] = Distance; - RarCopyString(Length, Distance); - continue; - } - if (num == 269) { - RarReadTables20(bstream); - RarUpdateProgress(); - continue; - } - if (num == 256) { - lastDist = rOldDist[oldDistPtr++ & 3] = lastDist; - RarCopyString(lastLength, lastDist); - continue; - } - if (num < 261) { - var Distance = rOldDist[(oldDistPtr - (num - 256)) & 3]; - var LengthNumber = RarDecodeNumber(bstream, RD); - var Length = rLDecode[LengthNumber] +2; - if ((Bits = rLBits[LengthNumber]) > 0) { - Length += bstream.readBits(Bits); - } - if (Distance >= 0x101) { - Length++; - if (Distance >= 0x2000) { - Length++ - if (Distance >= 0x40000) { - Length++; - } + if (num > 269) { + var Length = rLDecode[num -= 270] + 3; + if ((Bits = rLBits[num]) > 0) { + Length += bstream.readBits(Bits); + } + var DistNumber = RarDecodeNumber(bstream, DD); + var Distance = rDDecode[DistNumber] + 1; + if ((Bits = rDBits[DistNumber]) > 0) { + Distance += bstream.readBits(Bits); + } + if (Distance >= 0x2000) { + Length++; + if (Distance >= 0x40000) { + Length++; + } + } + lastLength = Length; + lastDist = rOldDist[oldDistPtr++ & 3] = Distance; + RarCopyString(Length, Distance); + continue; } - } - lastLength = Length; - lastDist = rOldDist[oldDistPtr++ & 3] = Distance; - RarCopyString(Length, Distance); - continue; - } - if (num < 270) { - var Distance = rSDDecode[num -= 261] + 1; - if ((Bits = rSDBits[num]) > 0) { - Distance += bstream.readBits(Bits); - } - lastLength = 2; - lastDist = rOldDist[oldDistPtr++ & 3] = Distance; - RarCopyString(2, Distance); - continue; + if (num == 269) { + RarReadTables20(bstream); + RarUpdateProgress(); + continue; + } + if (num == 256) { + lastDist = rOldDist[oldDistPtr++ & 3] = lastDist; + RarCopyString(lastLength, lastDist); + continue; + } + if (num < 261) { + var Distance = rOldDist[(oldDistPtr - (num - 256)) & 3]; + var LengthNumber = RarDecodeNumber(bstream, RD); + var Length = rLDecode[LengthNumber] + 2; + if ((Bits = rLBits[LengthNumber]) > 0) { + Length += bstream.readBits(Bits); + } + if (Distance >= 0x101) { + Length++; + if (Distance >= 0x2000) { + Length++ + if (Distance >= 0x40000) { + Length++; + } + } + } + lastLength = Length; + lastDist = rOldDist[oldDistPtr++ & 3] = Distance; + RarCopyString(Length, Distance); + continue; + } + if (num < 270) { + var Distance = rSDDecode[num -= 261] + 1; + if ((Bits = rSDBits[num]) > 0) { + Distance += bstream.readBits(Bits); + } + lastLength = 2; + lastDist = rOldDist[oldDistPtr++ & 3] = Distance; + RarCopyString(2, Distance); + continue; + } + } - - } - RarUpdateProgress(); + RarUpdateProgress(); } function RarUpdateProgress() { - var change = rBuffer.ptr - currentBytesUnarchivedInFile; - currentBytesUnarchivedInFile = rBuffer.ptr; - currentBytesUnarchived += change; - postProgress(); + var change = rBuffer.ptr - currentBytesUnarchivedInFile; + currentBytesUnarchivedInFile = rBuffer.ptr; + currentBytesUnarchived += change; + postProgress(); } var rNC20 = 298, @@ -552,55 +554,55 @@ var rNC20 = 298, var UnpOldTable20 = new Array(rMC20 * 4); function RarReadTables20(bstream) { - var BitLength = new Array(rBC20); - var Table = new Array(rMC20 * 4); - var TableSize, N, I; - var AudioBlock = bstream.readBits(1); - if (!bstream.readBits(1)) { - for (var i = UnpOldTable20.length; i--;) { - UnpOldTable20[i] = 0; + var BitLength = new Array(rBC20); + var Table = new Array(rMC20 * 4); + var TableSize, N, I; + var AudioBlock = bstream.readBits(1); + if (!bstream.readBits(1)) { + for (var i = UnpOldTable20.length; i--;) { + UnpOldTable20[i] = 0; + } } - } - TableSize = rNC20 + rDC20 + rRC20; - for (var I = 0; I < rBC20; I++) { - BitLength[I] = bstream.readBits(4); - } - RarMakeDecodeTables(BitLength, 0, BD, rBC20); - I = 0; - while (I < TableSize) { - var num = RarDecodeNumber(bstream, BD); - if (num < 16) { - Table[I] = num + UnpOldTable20[I] & 0xf; - I++; - } else if (num == 16) { - N = bstream.readBits(2) + 3; - while (N-- > 0 && I < TableSize) { - Table[I] = Table[I - 1]; - I++; - } - } else { - if (num == 17) { - N = bstream.readBits(3) + 3; - } else { - N = bstream.readBits(7) + 11; - } - while (N-- > 0 && I < TableSize) { - Table[I++] = 0; - } + TableSize = rNC20 + rDC20 + rRC20; + for (var I = 0; I < rBC20; I++) { + BitLength[I] = bstream.readBits(4); + } + RarMakeDecodeTables(BitLength, 0, BD, rBC20); + I = 0; + while (I < TableSize) { + var num = RarDecodeNumber(bstream, BD); + if (num < 16) { + Table[I] = num + UnpOldTable20[I] & 0xf; + I++; + } else if (num == 16) { + N = bstream.readBits(2) + 3; + while (N-- > 0 && I < TableSize) { + Table[I] = Table[I - 1]; + I++; + } + } else { + if (num == 17) { + N = bstream.readBits(3) + 3; + } else { + N = bstream.readBits(7) + 11; + } + while (N-- > 0 && I < TableSize) { + Table[I++] = 0; + } + } + } + RarMakeDecodeTables(Table, 0, LD, rNC20); + RarMakeDecodeTables(Table, rNC20, DD, rDC20); + RarMakeDecodeTables(Table, rNC20 + rDC20, RD, rRC20); + for (var i = UnpOldTable20.length; i--;) { + UnpOldTable20[i] = Table[i]; } - } - RarMakeDecodeTables(Table, 0, LD, rNC20); - RarMakeDecodeTables(Table, rNC20, DD, rDC20); - RarMakeDecodeTables(Table, rNC20 + rDC20, RD, rRC20); - for (var i = UnpOldTable20.length; i--;) { - UnpOldTable20[i] = Table[i]; - } } var lowDistRepCount = 0; var prevLowDist = 0; -var rOldDist = [0,0,0,0]; +var rOldDist = [0, 0, 0, 0]; var lastDist; var lastLength; @@ -631,10 +633,10 @@ var OldFilterLengths = []; var LastFilter = 0; function InitFilters() { - OldFilterLengths = []; - LastFilter = 0; - Filters = []; - PrgStack = []; + OldFilterLengths = []; + LastFilter = 0; + Filters = []; + PrgStack = []; } @@ -643,173 +645,173 @@ function InitFilters() { * @param {Uint8Array} vmCode An array of bytes. */ function RarAddVMCode(firstByte, vmCode) { - VM.init(); - var bstream = new bitjs.io.BitStream(vmCode.buffer, true /* rtl */); - - var filtPos; - if (firstByte & 0x80) { - filtPos = RarVM.readData(bstream); - if (filtPos == 0) { - InitFilters(); + VM.init(); + var bstream = new bitjs.io.BitStream(vmCode.buffer, true /* rtl */ ); + + var filtPos; + if (firstByte & 0x80) { + filtPos = RarVM.readData(bstream); + if (filtPos == 0) { + InitFilters(); + } else { + filtPos--; + } } else { - filtPos--; + filtPos = LastFilter; } - } else { - filtPos = LastFilter; - } - - if (filtPos > Filters.length || filtPos > OldFilterLengths.length) { - return false; - } - - LastFilter = filtPos; - var newFilter = (filtPos == Filters.length); - - // new filter for PrgStack - var stackFilter = new UnpackFilter(); - var filter = null; - // new filter code, never used before since VM reset - if (newFilter) { - // too many different filters, corrupt archive - if (filtPos > 1024) { - return false; + + if (filtPos > Filters.length || filtPos > OldFilterLengths.length) { + return false; } - filter = new UnpackFilter(); - Filters.push(filter); - stackFilter.ParentFilter = (Filters.length - 1); - OldFilterLengths.push(0); // OldFilterLengths.Add(1) - filter.ExecCount = 0; - } else { // filter was used in the past - filter = Filters[filtPos]; - stackFilter.ParentFilter = filtPos; - filter.ExecCount++; - } - - var emptyCount = 0; - for (var i = 0; i < PrgStack.length; ++i) { - PrgStack[i - emptyCount] = PrgStack[i]; - - if (PrgStack[i] == null) { - emptyCount++; + LastFilter = filtPos; + var newFilter = (filtPos == Filters.length); + + // new filter for PrgStack + var stackFilter = new UnpackFilter(); + var filter = null; + // new filter code, never used before since VM reset + if (newFilter) { + // too many different filters, corrupt archive + if (filtPos > 1024) { + return false; + } + + filter = new UnpackFilter(); + Filters.push(filter); + stackFilter.ParentFilter = (Filters.length - 1); + OldFilterLengths.push(0); // OldFilterLengths.Add(1) + filter.ExecCount = 0; + } else { // filter was used in the past + filter = Filters[filtPos]; + stackFilter.ParentFilter = filtPos; + filter.ExecCount++; } - if (emptyCount > 0) { - PrgStack[i] = null; + + var emptyCount = 0; + for (var i = 0; i < PrgStack.length; ++i) { + PrgStack[i - emptyCount] = PrgStack[i]; + + if (PrgStack[i] == null) { + emptyCount++; + } + if (emptyCount > 0) { + PrgStack[i] = null; + } } - } - - if (emptyCount == 0) { - PrgStack.push(null); //PrgStack.Add(1); - emptyCount = 1; - } - - var stackPos = PrgStack.length - emptyCount; - PrgStack[stackPos] = stackFilter; - stackFilter.ExecCount = filter.ExecCount; - - var blockStart = RarVM.readData(bstream); - if (firstByte & 0x40) { - blockStart += 258; - } - stackFilter.BlockStart = (blockStart + rBuffer.ptr) & MAXWINMASK; - - if (firstByte & 0x20) { - stackFilter.BlockLength = RarVM.readData(bstream); - } else { - stackFilter.BlockLength = filtPos < OldFilterLengths.length - ? OldFilterLengths[filtPos] - : 0; - } - stackFilter.NextWindow = (wBuffer.ptr != rBuffer.ptr) && - (((wBuffer.ptr - rBuffer.ptr) & MAXWINMASK) <= blockStart); - - OldFilterLengths[filtPos] = stackFilter.BlockLength; - - for (var i = 0; i < 7; ++i) { - stackFilter.Prg.InitR[i] = 0; - } - stackFilter.Prg.InitR[3] = VM_GLOBALMEMADDR; - stackFilter.Prg.InitR[4] = stackFilter.BlockLength; - stackFilter.Prg.InitR[5] = stackFilter.ExecCount; - - // set registers to optional parameters if any - if (firstByte & 0x10) { - var initMask = bstream.readBits(7); - for (var i = 0; i < 7; ++i) { - if (initMask & (1 << i)) { - stackFilter.Prg.InitR[i] = RarVM.readData(bstream); - } + + if (emptyCount == 0) { + PrgStack.push(null); //PrgStack.Add(1); + emptyCount = 1; } - } - if (newFilter) { - var vmCodeSize = RarVM.readData(bstream); - if (vmCodeSize >= 0x10000 || vmCodeSize == 0) { - return false; + var stackPos = PrgStack.length - emptyCount; + PrgStack[stackPos] = stackFilter; + stackFilter.ExecCount = filter.ExecCount; + + var blockStart = RarVM.readData(bstream); + if (firstByte & 0x40) { + blockStart += 258; } - var vmCode = new Uint8Array(vmCodeSize); - for (var i = 0; i < vmCodeSize; ++i) { - //if (Inp.Overflow(3)) - // return(false); - vmCode[i] = bstream.readBits(8); + stackFilter.BlockStart = (blockStart + rBuffer.ptr) & MAXWINMASK; + + if (firstByte & 0x20) { + stackFilter.BlockLength = RarVM.readData(bstream); + } else { + stackFilter.BlockLength = filtPos < OldFilterLengths.length ? + OldFilterLengths[filtPos] : + 0; } - VM.prepare(vmCode, filter.Prg); - } - stackFilter.Prg.Cmd = filter.Prg.Cmd; - stackFilter.Prg.AltCmd = filter.Prg.Cmd; - - var staticDataSize = filter.Prg.StaticData.length; - if (staticDataSize > 0 && staticDataSize < VM_GLOBALMEMSIZE) { - // read statically defined data contained in DB commands - for (var i = 0; i < staticDataSize; ++i) { - stackFilter.Prg.StaticData[i] = filter.Prg.StaticData[i]; + stackFilter.NextWindow = (wBuffer.ptr != rBuffer.ptr) && + (((wBuffer.ptr - rBuffer.ptr) & MAXWINMASK) <= blockStart); + + OldFilterLengths[filtPos] = stackFilter.BlockLength; + + for (var i = 0; i < 7; ++i) { + stackFilter.Prg.InitR[i] = 0; } - } - - if (stackFilter.Prg.GlobalData.length < VM_FIXEDGLOBALSIZE) { - stackFilter.Prg.GlobalData = new Uint8Array(VM_FIXEDGLOBALSIZE); - } - - var globalData = stackFilter.Prg.GlobalData; - for (var i = 0; i < 7; ++i) { - VM.setLowEndianValue(globalData, stackFilter.Prg.InitR[i], i * 4); - } - - VM.setLowEndianValue(globalData, stackFilter.BlockLength, 0x1c); - VM.setLowEndianValue(globalData, 0, 0x20); - VM.setLowEndianValue(globalData, stackFilter.ExecCount, 0x2c); - for (var i = 0; i < 16; ++i) { - globalData[0x30 + i] = 0; - } - - // put data block passed as parameter if any - if (firstByte & 8) { - //if (Inp.Overflow(3)) - // return(false); - var dataSize = RarVM.readData(bstream); - if (dataSize > (VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE)) { - return(false); + stackFilter.Prg.InitR[3] = VM_GLOBALMEMADDR; + stackFilter.Prg.InitR[4] = stackFilter.BlockLength; + stackFilter.Prg.InitR[5] = stackFilter.ExecCount; + + // set registers to optional parameters if any + if (firstByte & 0x10) { + var initMask = bstream.readBits(7); + for (var i = 0; i < 7; ++i) { + if (initMask & (1 << i)) { + stackFilter.Prg.InitR[i] = RarVM.readData(bstream); + } + } } - var curSize = stackFilter.Prg.GlobalData.length; - if (curSize < dataSize + VM_FIXEDGLOBALSIZE) { - // Resize global data and update the stackFilter and local variable. - var numBytesToAdd = dataSize + VM_FIXEDGLOBALSIZE - curSize; - var newGlobalData = new Uint8Array(globalData.length + numBytesToAdd); - newGlobalData.set(globalData); + if (newFilter) { + var vmCodeSize = RarVM.readData(bstream); + if (vmCodeSize >= 0x10000 || vmCodeSize == 0) { + return false; + } + var vmCode = new Uint8Array(vmCodeSize); + for (var i = 0; i < vmCodeSize; ++i) { + //if (Inp.Overflow(3)) + // return(false); + vmCode[i] = bstream.readBits(8); + } + VM.prepare(vmCode, filter.Prg); + } + stackFilter.Prg.Cmd = filter.Prg.Cmd; + stackFilter.Prg.AltCmd = filter.Prg.Cmd; + + var staticDataSize = filter.Prg.StaticData.length; + if (staticDataSize > 0 && staticDataSize < VM_GLOBALMEMSIZE) { + // read statically defined data contained in DB commands + for (var i = 0; i < staticDataSize; ++i) { + stackFilter.Prg.StaticData[i] = filter.Prg.StaticData[i]; + } + } + + if (stackFilter.Prg.GlobalData.length < VM_FIXEDGLOBALSIZE) { + stackFilter.Prg.GlobalData = new Uint8Array(VM_FIXEDGLOBALSIZE); + } + + var globalData = stackFilter.Prg.GlobalData; + for (var i = 0; i < 7; ++i) { + VM.setLowEndianValue(globalData, stackFilter.Prg.InitR[i], i * 4); + } - stackFilter.Prg.GlobalData = newGlobalData; - globalData = newGlobalData; + VM.setLowEndianValue(globalData, stackFilter.BlockLength, 0x1c); + VM.setLowEndianValue(globalData, 0, 0x20); + VM.setLowEndianValue(globalData, stackFilter.ExecCount, 0x2c); + for (var i = 0; i < 16; ++i) { + globalData[0x30 + i] = 0; } - //byte *GlobalData=&StackFilter->Prg.GlobalData[VM_FIXEDGLOBALSIZE]; - for (var i = 0; i < dataSize; ++i) { - //if (Inp.Overflow(3)) - // return(false); - globalData[VM_FIXEDGLOBALSIZE + i] = bstream.readBits(8); + + // put data block passed as parameter if any + if (firstByte & 8) { + //if (Inp.Overflow(3)) + // return(false); + var dataSize = RarVM.readData(bstream); + if (dataSize > (VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE)) { + return (false); + } + + var curSize = stackFilter.Prg.GlobalData.length; + if (curSize < dataSize + VM_FIXEDGLOBALSIZE) { + // Resize global data and update the stackFilter and local variable. + var numBytesToAdd = dataSize + VM_FIXEDGLOBALSIZE - curSize; + var newGlobalData = new Uint8Array(globalData.length + numBytesToAdd); + newGlobalData.set(globalData); + + stackFilter.Prg.GlobalData = newGlobalData; + globalData = newGlobalData; + } + //byte *GlobalData=&StackFilter->Prg.GlobalData[VM_FIXEDGLOBALSIZE]; + for (var i = 0; i < dataSize; ++i) { + //if (Inp.Overflow(3)) + // return(false); + globalData[VM_FIXEDGLOBALSIZE + i] = bstream.readBits(8); + } } - } - return true; + return true; } @@ -817,21 +819,21 @@ function RarAddVMCode(firstByte, vmCode) { * @param {!bitjs.io.BitStream} bstream */ function RarReadVMCode(bstream) { - var firstByte = bstream.readBits(8); - var length = (firstByte & 7) + 1; - if (length == 7) { - length = bstream.readBits(8) + 7; - } else if (length == 8) { - length = bstream.readBits(16); - } - - // Read all bytes of VM code into an array. - var vmCode = new Uint8Array(length); - for (var i = 0; i < length; i++) { - // Do something here with checking readbuf. - vmCode[i] = bstream.readBits(8); - } - return RarAddVMCode(firstByte, vmCode); + var firstByte = bstream.readBits(8); + var length = (firstByte & 7) + 1; + if (length == 7) { + length = bstream.readBits(8) + 7; + } else if (length == 8) { + length = bstream.readBits(16); + } + + // Read all bytes of VM code into an array. + var vmCode = new Uint8Array(length); + for (var i = 0; i < length; i++) { + // Do something here with checking readbuf. + vmCode[i] = bstream.readBits(8); + } + return RarAddVMCode(firstByte, vmCode); } /** @@ -840,265 +842,265 @@ function RarReadVMCode(bstream) { * @param {boolean} Solid */ function Unpack29(bstream, Solid) { - // lazy initialize rDDecode and rDBits - - var DDecode = new Array(rDC); - var DBits = new Array(rDC); - - var Dist = 0; - var BitLength = 0; - var Slot = 0; - - for (var I = 0; I < rDBitLengthCounts.length; I++,BitLength++) { - for (var J = 0; J < rDBitLengthCounts[I]; J++,Slot++,Dist+=(1<= 271) { - var Length = rLDecode[num -= 271] + 3; - if ((Bits = rLBits[num]) > 0) { - Length += bstream.readBits(Bits); - } - var DistNumber = RarDecodeNumber(bstream, DD); - var Distance = DDecode[DistNumber] + 1; - if ((Bits = DBits[DistNumber]) > 0) { - if (DistNumber > 9) { - if (Bits > 4) { - Distance += ((bstream.getBits() >>> (20 - Bits)) << 4); - bstream.readBits(Bits - 4); - //todo: check this - } - if (lowDistRepCount > 0) { - lowDistRepCount--; - Distance += prevLowDist; - } else { - var LowDist = RarDecodeNumber(bstream, LDD); - if (LowDist == 16) { - lowDistRepCount = rLOW_DIST_REP_COUNT - 1; - Distance += prevLowDist; - } else { - Distance += LowDist; - prevLowDist = LowDist; - } - } - } else { - Distance += bstream.readBits(Bits); - } - } - if (Distance >= 0x2000) { - Length++; - if (Distance >= 0x40000) { - Length++; + // lazy initialize rDDecode and rDBits + + var DDecode = new Array(rDC); + var DBits = new Array(rDC); + + var Dist = 0; + var BitLength = 0; + var Slot = 0; + + for (var I = 0; I < rDBitLengthCounts.length; I++, BitLength++) { + for (var J = 0; J < rDBitLengthCounts[I]; J++, Slot++, Dist += (1 << BitLength)) { + DDecode[Slot] = Dist; + DBits[Slot] = BitLength; } - } - RarInsertOldDist(Distance); - RarInsertLastMatch(Length, Distance); - RarCopyString(Length, Distance); - continue; - } - if (num == 256) { - if (!RarReadEndOfBlock(bstream)) { - break; - } - continue; - } - if (num == 257) { - if (!RarReadVMCode(bstream)) { - break; - } - continue; } - if (num == 258) { - if (lastLength != 0) { - RarCopyString(lastLength, lastDist); - } - continue; - } - if (num < 263) { - var DistNum = num - 259; - var Distance = rOldDist[DistNum]; - - for (var I = DistNum; I > 0; I--) { - rOldDist[I] = rOldDist[I-1]; - } - rOldDist[0] = Distance; - - var LengthNumber = RarDecodeNumber(bstream, RD); - var Length = rLDecode[LengthNumber] + 2; - if ((Bits = rLBits[LengthNumber]) > 0) { - Length += bstream.readBits(Bits); - } - RarInsertLastMatch(Length, Distance); - RarCopyString(Length, Distance); - continue; - } - if (num < 272) { - var Distance = rSDDecode[num -= 263] + 1; - if ((Bits = rSDBits[num]) > 0) { - Distance += bstream.readBits(Bits); - } - RarInsertOldDist(Distance); - RarInsertLastMatch(2, Distance); - RarCopyString(2, Distance); - continue; - } - } // while (true) - RarUpdateProgress(); - RarWriteBuf(); -} -/** - * Does stuff to the current byte buffer (rBuffer) based on - * the filters loaded into the RarVM and writes out to wBuffer. - */ -function RarWriteBuf() { - var writeSize = (rBuffer.ptr & MAXWINMASK); + var Bits; + //tablesRead = false; - for (var i = 0; i < PrgStack.length; ++i) { - var flt = PrgStack[i]; - if (flt == null) { - continue; - } + rOldDist = [0, 0, 0, 0] + + lastDist = 0; + lastLength = 0; - if (flt.NextWindow) { - flt.NextWindow = false; - continue; + for (var i = UnpOldTable.length; i--;) { + UnpOldTable[i] = 0; } - var blockStart = flt.BlockStart; - var blockLength = flt.BlockLength; - - // WrittenBorder = wBuffer.ptr - if (((blockStart - wBuffer.ptr) & MAXWINMASK) < writeSize) { - if (wBuffer.ptr != blockStart) { - // Copy blockStart bytes from rBuffer into wBuffer. - RarWriteArea(wBuffer.ptr, blockStart); - writeSize = (rBuffer.ptr - wBuffer.ptr) & MAXWINMASK; - } - if (blockLength <= writeSize) { - var blockEnd = (blockStart + blockLength) & MAXWINMASK; - if (blockStart < blockEnd || blockEnd == 0) { - VM.setMemory(0, rBuffer.data.subarray(blockStart, blockStart + blockLength), blockLength); - } else { - var firstPartLength = MAXWINSIZE - blockStart; - VM.setMemory(0, rBuffer.data.subarray(blockStart, blockStart + firstPartLength), firstPartLength); - VM.setMemory(firstPartLength, rBuffer.data, blockEnd); - } + // read in Huffman tables + RarReadTables(bstream); - var parentPrg = Filters[flt.ParentFilter].Prg; - var prg = flt.Prg; + while (true) { + var num = RarDecodeNumber(bstream, LD); - if (parentPrg.GlobalData.length > VM_FIXEDGLOBALSIZE) { - // Copy global data from previous script execution if any. - prg.GlobalData = new Uint8Array(parentPrg.GlobalData); + if (num < 256) { + rBuffer.insertByte(num); + continue; } - - RarExecuteCode(prg); - - if (prg.GlobalData.length > VM_FIXEDGLOBALSIZE) { - // Save global data for next script execution. - var globalDataLen = prg.GlobalData.length; - if (parentPrg.GlobalData.length < globalDataLen) { - parentPrg.GlobalData = new Uint8Array(globalDataLen); - } - parentPrg.GlobalData.set( - this.mem_.subarray(VM_FIXEDGLOBALSIZE, VM_FIXEDGLOBALSIZE + globalDataLen), - VM_FIXEDGLOBALSIZE); - } else { - parentPrg.GlobalData = new Uint8Array(0); + if (num >= 271) { + var Length = rLDecode[num -= 271] + 3; + if ((Bits = rLBits[num]) > 0) { + Length += bstream.readBits(Bits); + } + var DistNumber = RarDecodeNumber(bstream, DD); + var Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) { + if (DistNumber > 9) { + if (Bits > 4) { + Distance += ((bstream.getBits() >>> (20 - Bits)) << 4); + bstream.readBits(Bits - 4); + //todo: check this + } + if (lowDistRepCount > 0) { + lowDistRepCount--; + Distance += prevLowDist; + } else { + var LowDist = RarDecodeNumber(bstream, LDD); + if (LowDist == 16) { + lowDistRepCount = rLOW_DIST_REP_COUNT - 1; + Distance += prevLowDist; + } else { + Distance += LowDist; + prevLowDist = LowDist; + } + } + } else { + Distance += bstream.readBits(Bits); + } + } + if (Distance >= 0x2000) { + Length++; + if (Distance >= 0x40000) { + Length++; + } + } + RarInsertOldDist(Distance); + RarInsertLastMatch(Length, Distance); + RarCopyString(Length, Distance); + continue; } + if (num == 256) { + if (!RarReadEndOfBlock(bstream)) { + break; + } + continue; + } + if (num == 257) { + if (!RarReadVMCode(bstream)) { + break; + } + continue; + } + if (num == 258) { + if (lastLength != 0) { + RarCopyString(lastLength, lastDist); + } + continue; + } + if (num < 263) { + var DistNum = num - 259; + var Distance = rOldDist[DistNum]; - var filteredData = prg.FilteredData; - - PrgStack[i] = null; - while (i + 1 < PrgStack.length) { - var nextFilter = PrgStack[i + 1]; - if (nextFilter == null || nextFilter.BlockStart != blockStart || - nextFilter.BlockLength != filteredData.length || nextFilter.NextWindow) { - break; - } + for (var I = DistNum; I > 0; I--) { + rOldDist[I] = rOldDist[I - 1]; + } + rOldDist[0] = Distance; - // Apply several filters to same data block. + var LengthNumber = RarDecodeNumber(bstream, RD); + var Length = rLDecode[LengthNumber] + 2; + if ((Bits = rLBits[LengthNumber]) > 0) { + Length += bstream.readBits(Bits); + } + RarInsertLastMatch(Length, Distance); + RarCopyString(Length, Distance); + continue; + } + if (num < 272) { + var Distance = rSDDecode[num -= 263] + 1; + if ((Bits = rSDBits[num]) > 0) { + Distance += bstream.readBits(Bits); + } + RarInsertOldDist(Distance); + RarInsertLastMatch(2, Distance); + RarCopyString(2, Distance); + continue; + } + } // while (true) + RarUpdateProgress(); + RarWriteBuf(); +} - VM.setMemory(0, filteredData, filteredData.length); +/** + * Does stuff to the current byte buffer (rBuffer) based on + * the filters loaded into the RarVM and writes out to wBuffer. + */ +function RarWriteBuf() { + var writeSize = (rBuffer.ptr & MAXWINMASK); - var parentPrg = Filters[nextFilter.ParentFilter].Prg; - var nextPrg = nextFilter.Prg; + for (var i = 0; i < PrgStack.length; ++i) { + var flt = PrgStack[i]; + if (flt == null) { + continue; + } - var globalDataLen = parentPrg.GlobalData.length; - if (globalDataLen > VM_FIXEDGLOBALSIZE) { - // Copy global data from previous script execution if any. - nextPrg.GlobalData = new Uint8Array(globalDataLen); - nextPrg.GlobalData.set(parentPrg.GlobalData.subarray(VM_FIXEDGLOBALSIZE, VM_FIXEDGLOBALSIZE + globalDataLen), VM_FIXEDGLOBALSIZE); - } + if (flt.NextWindow) { + flt.NextWindow = false; + continue; + } - RarExecuteCode(nextPrg); + var blockStart = flt.BlockStart; + var blockLength = flt.BlockLength; - if (nextPrg.GlobalData.length > VM_GLOBALMEMSIZE) { - // Save global data for next script execution. - var globalDataLen = nextPrg.GlobalData.length; - if (parentPrg.GlobalData.length < globalDataLen) { - parentPrg.GlobalData = new Uint8Array(globalDataLen); + // WrittenBorder = wBuffer.ptr + if (((blockStart - wBuffer.ptr) & MAXWINMASK) < writeSize) { + if (wBuffer.ptr != blockStart) { + // Copy blockStart bytes from rBuffer into wBuffer. + RarWriteArea(wBuffer.ptr, blockStart); + writeSize = (rBuffer.ptr - wBuffer.ptr) & MAXWINMASK; } - parentPrg.GlobalData.set( - this.mem_.subarray(VM_FIXEDGLOBALSIZE, VM_FIXEDGLOBALSIZE + globalDataLen), - VM_FIXEDGLOBALSIZE); - } else { - parentPrg.GlobalData = new Uint8Array(0); - } - - filteredData = nextPrg.FilteredData; - i++; - PrgStack[i] = null; - } // while (i + 1 < PrgStack.length) - - for (var j = 0; j < filteredData.length; ++j) { - wBuffer.insertByte(filteredData[j]); - } - writeSize = (rBuffer.ptr - wBuffer.ptr) & MAXWINMASK; - } // if (blockLength <= writeSize) - else { - for (var j = i; j < PrgStack.length; ++j) { - var flt = PrgStack[j]; - if (flt != null && flt.NextWindow) { - flt.NextWindow = false; - } - } - //WrPtr=WrittenBorder; - return; - } - } // if (((blockStart - wBuffer.ptr) & MAXWINMASK) < writeSize) - } // for (var i = 0; i < PrgStack.length; ++i) + if (blockLength <= writeSize) { + var blockEnd = (blockStart + blockLength) & MAXWINMASK; + if (blockStart < blockEnd || blockEnd == 0) { + VM.setMemory(0, rBuffer.data.subarray(blockStart, blockStart + blockLength), blockLength); + } else { + var firstPartLength = MAXWINSIZE - blockStart; + VM.setMemory(0, rBuffer.data.subarray(blockStart, blockStart + firstPartLength), firstPartLength); + VM.setMemory(firstPartLength, rBuffer.data, blockEnd); + } + + var parentPrg = Filters[flt.ParentFilter].Prg; + var prg = flt.Prg; + + if (parentPrg.GlobalData.length > VM_FIXEDGLOBALSIZE) { + // Copy global data from previous script execution if any. + prg.GlobalData = new Uint8Array(parentPrg.GlobalData); + } + + RarExecuteCode(prg); + + if (prg.GlobalData.length > VM_FIXEDGLOBALSIZE) { + // Save global data for next script execution. + var globalDataLen = prg.GlobalData.length; + if (parentPrg.GlobalData.length < globalDataLen) { + parentPrg.GlobalData = new Uint8Array(globalDataLen); + } + parentPrg.GlobalData.set( + this.mem_.subarray(VM_FIXEDGLOBALSIZE, VM_FIXEDGLOBALSIZE + globalDataLen), + VM_FIXEDGLOBALSIZE); + } else { + parentPrg.GlobalData = new Uint8Array(0); + } + + var filteredData = prg.FilteredData; + + PrgStack[i] = null; + while (i + 1 < PrgStack.length) { + var nextFilter = PrgStack[i + 1]; + if (nextFilter == null || nextFilter.BlockStart != blockStart || + nextFilter.BlockLength != filteredData.length || nextFilter.NextWindow) { + break; + } + + // Apply several filters to same data block. + + VM.setMemory(0, filteredData, filteredData.length); + + var parentPrg = Filters[nextFilter.ParentFilter].Prg; + var nextPrg = nextFilter.Prg; + + var globalDataLen = parentPrg.GlobalData.length; + if (globalDataLen > VM_FIXEDGLOBALSIZE) { + // Copy global data from previous script execution if any. + nextPrg.GlobalData = new Uint8Array(globalDataLen); + nextPrg.GlobalData.set(parentPrg.GlobalData.subarray(VM_FIXEDGLOBALSIZE, VM_FIXEDGLOBALSIZE + globalDataLen), VM_FIXEDGLOBALSIZE); + } + + RarExecuteCode(nextPrg); + + if (nextPrg.GlobalData.length > VM_GLOBALMEMSIZE) { + // Save global data for next script execution. + var globalDataLen = nextPrg.GlobalData.length; + if (parentPrg.GlobalData.length < globalDataLen) { + parentPrg.GlobalData = new Uint8Array(globalDataLen); + } + parentPrg.GlobalData.set( + this.mem_.subarray(VM_FIXEDGLOBALSIZE, VM_FIXEDGLOBALSIZE + globalDataLen), + VM_FIXEDGLOBALSIZE); + } else { + parentPrg.GlobalData = new Uint8Array(0); + } + + filteredData = nextPrg.FilteredData; + i++; + PrgStack[i] = null; + } // while (i + 1 < PrgStack.length) + + for (var j = 0; j < filteredData.length; ++j) { + wBuffer.insertByte(filteredData[j]); + } + writeSize = (rBuffer.ptr - wBuffer.ptr) & MAXWINMASK; + } // if (blockLength <= writeSize) + else { + for (var j = i; j < PrgStack.length; ++j) { + var flt = PrgStack[j]; + if (flt != null && flt.NextWindow) { + flt.NextWindow = false; + } + } + //WrPtr=WrittenBorder; + return; + } + } // if (((blockStart - wBuffer.ptr) & MAXWINMASK) < writeSize) + } // for (var i = 0; i < PrgStack.length; ++i) - // Write any remaining bytes from rBuffer to wBuffer; - RarWriteArea(wBuffer.ptr, rBuffer.ptr); + // Write any remaining bytes from rBuffer to wBuffer; + RarWriteArea(wBuffer.ptr, rBuffer.ptr); - // Now that the filtered buffer has been written, swap it back to rBuffer. - rBuffer = wBuffer; + // Now that the filtered buffer has been written, swap it back to rBuffer. + rBuffer = wBuffer; } /** @@ -1107,14 +1109,14 @@ function RarWriteBuf() { * @param {number} endPtr The ending point to copy from rBuffer. */ function RarWriteArea(startPtr, endPtr) { - if (endPtr < startPtr) { - console.error('endPtr < startPtr, endPtr=' + endPtr + ', startPtr=' + startPtr); -// RarWriteData(startPtr, -(int)StartPtr & MAXWINMASK); -// RarWriteData(0, endPtr); - return; - } else if (startPtr < endPtr) { - RarWriteData(startPtr, endPtr - startPtr); - } + if (endPtr < startPtr) { + console.error('endPtr < startPtr, endPtr=' + endPtr + ', startPtr=' + startPtr); + // RarWriteData(startPtr, -(int)StartPtr & MAXWINMASK); + // RarWriteData(0, endPtr); + return; + } else if (startPtr < endPtr) { + RarWriteData(startPtr, endPtr - startPtr); + } } /** @@ -1123,54 +1125,54 @@ function RarWriteArea(startPtr, endPtr) { * @param {number} numBytes The number of bytes to copy. */ function RarWriteData(offset, numBytes) { - if (wBuffer.ptr >= rBuffer.data.length) { - return; - } - var leftToWrite = rBuffer.data.length - wBuffer.ptr; - if (numBytes > leftToWrite) { - numBytes = leftToWrite; - } - for (var i = 0; i < numBytes; ++i) { - wBuffer.insertByte(rBuffer.data[offset + i]); - } + if (wBuffer.ptr >= rBuffer.data.length) { + return; + } + var leftToWrite = rBuffer.data.length - wBuffer.ptr; + if (numBytes > leftToWrite) { + numBytes = leftToWrite; + } + for (var i = 0; i < numBytes; ++i) { + wBuffer.insertByte(rBuffer.data[offset + i]); + } } /** * @param {VM_PreparedProgram} prg */ -function RarExecuteCode(prg) -{ - if (prg.GlobalData.length > 0) { - var writtenFileSize = wBuffer.ptr; - prg.InitR[6] = writtenFileSize; - VM.setLowEndianValue(prg.GlobalData, writtenFileSize, 0x24); - VM.setLowEndianValue(prg.GlobalData, (writtenFileSize >>> 32) >> 0, 0x28); - VM.execute(prg); - } +function RarExecuteCode(prg) { + if (prg.GlobalData.length > 0) { + var writtenFileSize = wBuffer.ptr; + prg.InitR[6] = writtenFileSize; + VM.setLowEndianValue(prg.GlobalData, writtenFileSize, 0x24); + VM.setLowEndianValue(prg.GlobalData, (writtenFileSize >>> 32) >> 0, 0x28); + VM.execute(prg); + } } function RarReadEndOfBlock(bstream) { - RarUpdateProgress(); - - var NewTable = false, NewFile = false; - if (bstream.readBits(1)) { - NewTable = true; - } else { - NewFile = true; - NewTable = !!bstream.readBits(1); - } - //tablesRead = !NewTable; - return !(NewFile || NewTable && !RarReadTables(bstream)); + RarUpdateProgress(); + + var NewTable = false, + NewFile = false; + if (bstream.readBits(1)) { + NewTable = true; + } else { + NewFile = true; + NewTable = !!bstream.readBits(1); + } + //tablesRead = !NewTable; + return !(NewFile || NewTable && !RarReadTables(bstream)); } function RarInsertLastMatch(length, distance) { - lastDist = distance; - lastLength = length; + lastDist = distance; + lastLength = length; } function RarInsertOldDist(distance) { - rOldDist.splice(3,1); - rOldDist.splice(0,0,distance); + rOldDist.splice(3, 1); + rOldDist.splice(0, 0, distance); } /** @@ -1181,178 +1183,177 @@ function RarInsertOldDist(distance) { * pointer to start copying from. */ function RarCopyString(len, distance) { - var srcPtr = rBuffer.ptr - distance; - if (srcPtr < 0) { - var l = rOldBuffers.length; - while (srcPtr < 0) { - srcPtr = rOldBuffers[--l].data.length + srcPtr; - } - // TODO: lets hope that it never needs to read beyond file boundaries - while (len--) { - rBuffer.insertByte(rOldBuffers[l].data[srcPtr++]); + var srcPtr = rBuffer.ptr - distance; + if (srcPtr < 0) { + var l = rOldBuffers.length; + while (srcPtr < 0) { + srcPtr = rOldBuffers[--l].data.length + srcPtr; + } + // TODO: lets hope that it never needs to read beyond file boundaries + while (len--) { + rBuffer.insertByte(rOldBuffers[l].data[srcPtr++]); + } } - } - if (len > distance) { - while (len--) { - rBuffer.insertByte(rBuffer.data[srcPtr++]); + if (len > distance) { + while (len--) { + rBuffer.insertByte(rBuffer.data[srcPtr++]); + } + } else { + rBuffer.insertBytes(rBuffer.data.subarray(srcPtr, srcPtr + len)); } - } else { - rBuffer.insertBytes(rBuffer.data.subarray(srcPtr, srcPtr + len)); - } } /** * @param {RarLocalFile} v */ function unpack(v) { - // TODO: implement what happens when unpVer is < 15 - var Ver = v.header.unpVer <= 15 ? 15 : v.header.unpVer; - var Solid = v.header.LHD_SOLID; - var bstream = new bitjs.io.BitStream(v.fileData.buffer, true /* rtl */, v.fileData.byteOffset, v.fileData.byteLength ); - - rBuffer = new bitjs.io.ByteBuffer(v.header.unpackedSize); - - info("Unpacking " + v.filename + " RAR v" + Ver); - - switch (Ver) { - case 15: // rar 1.5 compression - Unpack15(bstream, Solid); - break; - case 20: // rar 2.x compression - case 26: // files larger than 2GB - Unpack20(bstream, Solid); - break; - case 29: // rar 3.x compression - case 36: // alternative hash - wBuffer = new bitjs.io.ByteBuffer(rBuffer.data.length); - Unpack29(bstream, Solid); - break; - } // switch(method) - - rOldBuffers.push(rBuffer); - // TODO: clear these old buffers when there's over 4MB of history - return rBuffer.data; + // TODO: implement what happens when unpVer is < 15 + var Ver = v.header.unpVer <= 15 ? 15 : v.header.unpVer; + var Solid = v.header.LHD_SOLID; + var bstream = new bitjs.io.BitStream(v.fileData.buffer, true /* rtl */ , v.fileData.byteOffset, v.fileData.byteLength); + + rBuffer = new bitjs.io.ByteBuffer(v.header.unpackedSize); + + info("Unpacking " + v.filename + " RAR v" + Ver); + + switch (Ver) { + case 15: // rar 1.5 compression + Unpack15(bstream, Solid); + break; + case 20: // rar 2.x compression + case 26: // files larger than 2GB + Unpack20(bstream, Solid); + break; + case 29: // rar 3.x compression + case 36: // alternative hash + wBuffer = new bitjs.io.ByteBuffer(rBuffer.data.length); + Unpack29(bstream, Solid); + break; + } // switch(method) + + rOldBuffers.push(rBuffer); + // TODO: clear these old buffers when there's over 4MB of history + return rBuffer.data; } // bstream is a bit stream var RarLocalFile = function(bstream) { - this.header = new RarVolumeHeader(bstream); - this.filename = this.header.filename; - - if (this.header.headType != FILE_HEAD && this.header.headType != ENDARC_HEAD) { - this.isValid = false; - info("Error! RAR Volume did not include a FILE_HEAD header "); - } - else { - // read in the compressed data - this.fileData = null; - if (this.header.packSize > 0) { - this.fileData = bstream.readBytes(this.header.packSize); - this.isValid = true; + this.header = new RarVolumeHeader(bstream); + this.filename = this.header.filename; + + if (this.header.headType != FILE_HEAD && this.header.headType != ENDARC_HEAD) { + this.isValid = false; + info("Error! RAR Volume did not include a FILE_HEAD header "); + } else { + // read in the compressed data + this.fileData = null; + if (this.header.packSize > 0) { + this.fileData = bstream.readBytes(this.header.packSize); + this.isValid = true; + } } - } }; RarLocalFile.prototype.unrar = function() { - if (!this.header.flags.LHD_SPLIT_BEFORE) { - // unstore file - if (this.header.method == 0x30) { - info("Unstore "+this.filename); - this.isValid = true; - - currentBytesUnarchivedInFile += this.fileData.length; - currentBytesUnarchived += this.fileData.length; - - // Create a new buffer and copy it over. - var len = this.header.packSize; - var newBuffer = new bitjs.io.ByteBuffer(len); - newBuffer.insertBytes(this.fileData); - this.fileData = newBuffer.data; - } else { - this.isValid = true; - this.fileData = unpack(this); + if (!this.header.flags.LHD_SPLIT_BEFORE) { + // unstore file + if (this.header.method == 0x30) { + info("Unstore " + this.filename); + this.isValid = true; + + currentBytesUnarchivedInFile += this.fileData.length; + currentBytesUnarchived += this.fileData.length; + + // Create a new buffer and copy it over. + var len = this.header.packSize; + var newBuffer = new bitjs.io.ByteBuffer(len); + newBuffer.insertBytes(this.fileData); + this.fileData = newBuffer.data; + } else { + this.isValid = true; + this.fileData = unpack(this); + } } - } } var unrar = function(arrayBuffer) { - currentFilename = ""; - currentFileNumber = 0; - currentBytesUnarchivedInFile = 0; - currentBytesUnarchived = 0; - totalUncompressedBytesInArchive = 0; - totalFilesInArchive = 0; - - postMessage(new bitjs.archive.UnarchiveStartEvent()); - var bstream = new bitjs.io.BitStream(arrayBuffer, false /* rtl */); - - var header = new RarVolumeHeader(bstream); - if (header.crc == 0x6152 && - header.headType == 0x72 && - header.flags.value == 0x1A21 && - header.headSize == 7) { - info("Found RAR signature"); - - var mhead = new RarVolumeHeader(bstream); - if (mhead.headType != MAIN_HEAD) { - info("Error! RAR did not include a MAIN_HEAD header"); - } - else { - var localFiles = [], - localFile = null; - do { - try { - localFile = new RarLocalFile(bstream); - info("RAR localFile isValid=" + localFile.isValid + ", volume packSize=" + localFile.header.packSize); - if (localFile && localFile.isValid && localFile.header.packSize > 0) { - totalUncompressedBytesInArchive += localFile.header.unpackedSize; - localFiles.push(localFile); - } else if (localFile.header.packSize == 0 && localFile.header.unpackedSize == 0) { - localFile.isValid = true; - } - } catch(err) { - break; - } - //info("bstream" + bstream.bytePtr+"/"+bstream.bytes.length); - } while (localFile.isValid); - totalFilesInArchive = localFiles.length; - - // now we have all information but things are unpacked - // TODO: unpack - localFiles = localFiles.sort(function(a,b) { - var aname = a.filename.toLowerCase(); - var bname = b.filename.toLowerCase(); - return aname > bname ? 1 : -1; - }); - - info(localFiles.map(function(a){return a.filename}).join(', ')); - for (var i = 0; i < localFiles.length; ++i) { - var localfile = localFiles[i]; - - // update progress - currentFilename = localfile.header.filename; - currentBytesUnarchivedInFile = 0; - - // actually do the unzipping - localfile.unrar(); - - if (localfile.isValid) { - postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile)); - postProgress(); + currentFilename = ""; + currentFileNumber = 0; + currentBytesUnarchivedInFile = 0; + currentBytesUnarchived = 0; + totalUncompressedBytesInArchive = 0; + totalFilesInArchive = 0; + + postMessage(new bitjs.archive.UnarchiveStartEvent()); + var bstream = new bitjs.io.BitStream(arrayBuffer, false /* rtl */ ); + + var header = new RarVolumeHeader(bstream); + if (header.crc == 0x6152 && + header.headType == 0x72 && + header.flags.value == 0x1A21 && + header.headSize == 7) { + info("Found RAR signature"); + + var mhead = new RarVolumeHeader(bstream); + if (mhead.headType != MAIN_HEAD) { + info("Error! RAR did not include a MAIN_HEAD header"); + } else { + var localFiles = [], + localFile = null; + do { + try { + localFile = new RarLocalFile(bstream); + info("RAR localFile isValid=" + localFile.isValid + ", volume packSize=" + localFile.header.packSize); + if (localFile && localFile.isValid && localFile.header.packSize > 0) { + totalUncompressedBytesInArchive += localFile.header.unpackedSize; + localFiles.push(localFile); + } else if (localFile.header.packSize == 0 && localFile.header.unpackedSize == 0) { + localFile.isValid = true; + } + } catch (err) { + break; + } + //info("bstream" + bstream.bytePtr+"/"+bstream.bytes.length); + } while (localFile.isValid); + totalFilesInArchive = localFiles.length; + + // now we have all information but things are unpacked + // TODO: unpack + localFiles = localFiles.sort(function(a, b) { + var aname = a.filename.toLowerCase(); + var bname = b.filename.toLowerCase(); + return aname > bname ? 1 : -1; + }); + + info(localFiles.map(function(a) { + return a.filename + }).join(', ')); + for (var i = 0; i < localFiles.length; ++i) { + var localfile = localFiles[i]; + + // update progress + currentFilename = localfile.header.filename; + currentBytesUnarchivedInFile = 0; + + // actually do the unzipping + localfile.unrar(); + + if (localfile.isValid) { + postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile)); + postProgress(); + } + } + + postProgress(); } - } - - postProgress(); + } else { + err("Invalid RAR file"); } - } - else { - err("Invalid RAR file"); - } - postMessage(new bitjs.archive.UnarchiveFinishEvent()); + postMessage(new bitjs.archive.UnarchiveFinishEvent()); }; // event.data.file has the ArrayBuffer. onmessage = function(event) { - var ab = event.data.file; - unrar(ab, true); -}; + var ab = event.data.file; + unrar(ab, true); +}; \ No newline at end of file diff --git a/cps/static/js/archive/untar.js b/cps/static/js/archive/untar.js index 1116d0b1..e318d117 100644 --- a/cps/static/js/archive/untar.js +++ b/cps/static/js/archive/untar.js @@ -24,167 +24,167 @@ var totalFilesInArchive = 0; // Helper functions. var info = function(str) { - postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); + postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); }; var err = function(str) { - postMessage(new bitjs.archive.UnarchiveErrorEvent(str)); + postMessage(new bitjs.archive.UnarchiveErrorEvent(str)); }; var postProgress = function() { - postMessage(new bitjs.archive.UnarchiveProgressEvent( - currentFilename, - currentFileNumber, - currentBytesUnarchivedInFile, - currentBytesUnarchived, - totalUncompressedBytesInArchive, - totalFilesInArchive)); + postMessage(new bitjs.archive.UnarchiveProgressEvent( + currentFilename, + currentFileNumber, + currentBytesUnarchivedInFile, + currentBytesUnarchived, + totalUncompressedBytesInArchive, + totalFilesInArchive)); }; // Removes all characters from the first zero-byte in the string onwards. var readCleanString = function(bstr, numBytes) { - var str = bstr.readString(numBytes); - var zIndex = str.indexOf(String.fromCharCode(0)); - return zIndex != -1 ? str.substr(0, zIndex) : str; + var str = bstr.readString(numBytes); + var zIndex = str.indexOf(String.fromCharCode(0)); + return zIndex != -1 ? str.substr(0, zIndex) : str; }; // takes a ByteStream and parses out the local file information var TarLocalFile = function(bstream) { - this.isValid = false; - - // Read in the header block - this.name = readCleanString(bstream, 100); - this.mode = readCleanString(bstream, 8); - this.uid = readCleanString(bstream, 8); - this.gid = readCleanString(bstream, 8); - this.size = parseInt(readCleanString(bstream, 12), 8); - this.mtime = readCleanString(bstream, 12); - this.chksum = readCleanString(bstream, 8); - this.typeflag = readCleanString(bstream, 1); - this.linkname = readCleanString(bstream, 100); - this.maybeMagic = readCleanString(bstream, 6); - - if (this.maybeMagic == "ustar") { - this.version = readCleanString(bstream, 2); - this.uname = readCleanString(bstream, 32); - this.gname = readCleanString(bstream, 32); - this.devmajor = readCleanString(bstream, 8); - this.devminor = readCleanString(bstream, 8); - this.prefix = readCleanString(bstream, 155); - - if (this.prefix.length) { - this.name = this.prefix + this.name; + this.isValid = false; + + // Read in the header block + this.name = readCleanString(bstream, 100); + this.mode = readCleanString(bstream, 8); + this.uid = readCleanString(bstream, 8); + this.gid = readCleanString(bstream, 8); + this.size = parseInt(readCleanString(bstream, 12), 8); + this.mtime = readCleanString(bstream, 12); + this.chksum = readCleanString(bstream, 8); + this.typeflag = readCleanString(bstream, 1); + this.linkname = readCleanString(bstream, 100); + this.maybeMagic = readCleanString(bstream, 6); + + if (this.maybeMagic == "ustar") { + this.version = readCleanString(bstream, 2); + this.uname = readCleanString(bstream, 32); + this.gname = readCleanString(bstream, 32); + this.devmajor = readCleanString(bstream, 8); + this.devminor = readCleanString(bstream, 8); + this.prefix = readCleanString(bstream, 155); + + if (this.prefix.length) { + this.name = this.prefix + this.name; + } + bstream.readBytes(12); // 512 - 500 + } else { + bstream.readBytes(255); // 512 - 257 } - bstream.readBytes(12); // 512 - 500 - } else { - bstream.readBytes(255); // 512 - 257 - } - - // Done header, now rest of blocks are the file contents. - this.filename = this.name; - this.fileData = null; - - info("Untarring file '" + this.filename + "'"); - info(" size = " + this.size); - info(" typeflag = " + this.typeflag); - - // A regular file. - if (this.typeflag == 0) { - 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) { - this.isValid = true; - } - - bstream.readBytes(this.size); - // Round up to 512-byte blocks. - var remaining = 512 - bstream.ptr % 512; - if (remaining > 0 && remaining < 512) { - bstream.readBytes(remaining); + // Done header, now rest of blocks are the file contents. + this.filename = this.name; + this.fileData = null; + + info("Untarring file '" + this.filename + "'"); + info(" size = " + this.size); + info(" typeflag = " + this.typeflag); + + // A regular file. + if (this.typeflag == 0) { + 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) { + this.isValid = true; + } + + bstream.readBytes(this.size); + + // Round up to 512-byte blocks. + var remaining = 512 - bstream.ptr % 512; + if (remaining > 0 && remaining < 512) { + bstream.readBytes(remaining); + } + } else if (this.typeflag == 5) { + info(" This is a directory.") } - } else if (this.typeflag == 5) { - info(" This is a directory.") - } }; // Takes an ArrayBuffer of a tar file in // returns null on error // returns an array of DecompressedFile objects on success var untar = function(arrayBuffer) { - currentFilename = ""; - currentFileNumber = 0; - currentBytesUnarchivedInFile = 0; - currentBytesUnarchived = 0; - totalUncompressedBytesInArchive = 0; - totalFilesInArchive = 0; - - postMessage(new bitjs.archive.UnarchiveStartEvent()); - var bstream = new bitjs.io.ByteStream(arrayBuffer); - var localFiles = []; - - // While we don't encounter an empty block, keep making TarLocalFiles. - while (bstream.peekNumber(4) != 0) { - var oneLocalFile = new TarLocalFile(bstream); - if (oneLocalFile && oneLocalFile.isValid) { - localFiles.push(oneLocalFile); - totalUncompressedBytesInArchive += oneLocalFile.size; + currentFilename = ""; + currentFileNumber = 0; + currentBytesUnarchivedInFile = 0; + currentBytesUnarchived = 0; + totalUncompressedBytesInArchive = 0; + totalFilesInArchive = 0; + + postMessage(new bitjs.archive.UnarchiveStartEvent()); + var bstream = new bitjs.io.ByteStream(arrayBuffer); + var localFiles = []; + + // While we don't encounter an empty block, keep making TarLocalFiles. + while (bstream.peekNumber(4) != 0) { + var oneLocalFile = new TarLocalFile(bstream); + if (oneLocalFile && oneLocalFile.isValid) { + localFiles.push(oneLocalFile); + totalUncompressedBytesInArchive += oneLocalFile.size; + } + } + totalFilesInArchive = localFiles.length; + + // got all local files, now sort them + localFiles.sort(function(a, b) { + var aname = a.filename; + var bname = b.filename; + return aname > bname ? 1 : -1; + + // extract the number at the end of both filenames + /* + var aname = a.filename; + var bname = b.filename; + var aindex = aname.length, bindex = bname.length; + + // Find the last number character from the back of the filename. + while (aname[aindex-1] < '0' || aname[aindex-1] > '9') --aindex; + while (bname[bindex-1] < '0' || bname[bindex-1] > '9') --bindex; + + // Find the first number character from the back of the filename + while (aname[aindex-1] >= '0' && aname[aindex-1] <= '9') --aindex; + while (bname[bindex-1] >= '0' && bname[bindex-1] <= '9') --bindex; + + // parse them into numbers and return comparison + var anum = parseInt(aname.substr(aindex), 10), + bnum = parseInt(bname.substr(bindex), 10); + return anum - bnum; + */ + }); + + // report # files and total length + if (localFiles.length > 0) { + postProgress(); } - } - totalFilesInArchive = localFiles.length; - - // got all local files, now sort them - localFiles.sort(function(a,b) { - var aname = a.filename; - var bname = b.filename; - return aname > bname ? 1 : -1; - - // extract the number at the end of both filenames - /* - var aname = a.filename; - var bname = b.filename; - var aindex = aname.length, bindex = bname.length; - - // Find the last number character from the back of the filename. - while (aname[aindex-1] < '0' || aname[aindex-1] > '9') --aindex; - while (bname[bindex-1] < '0' || bname[bindex-1] > '9') --bindex; - - // Find the first number character from the back of the filename - while (aname[aindex-1] >= '0' && aname[aindex-1] <= '9') --aindex; - while (bname[bindex-1] >= '0' && bname[bindex-1] <= '9') --bindex; - - // parse them into numbers and return comparison - var anum = parseInt(aname.substr(aindex), 10), - bnum = parseInt(bname.substr(bindex), 10); - return anum - bnum; - */ - }); - - // report # files and total length - if (localFiles.length > 0) { - postProgress(); - } - - // now do the shipping of each file - for (var i = 0; i < localFiles.length; ++i) { - var localfile = localFiles[i]; - info("Sending file '" + localfile.filename + "' up"); - - // update progress - currentFilename = localfile.filename; - currentFileNumber = i; - currentBytesUnarchivedInFile = localfile.size; - currentBytesUnarchived += localfile.size; - postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile)); - postProgress(); - } - postProgress(); + // now do the shipping of each file + for (var i = 0; i < localFiles.length; ++i) { + var localfile = localFiles[i]; + info("Sending file '" + localfile.filename + "' up"); + + // update progress + currentFilename = localfile.filename; + currentFileNumber = i; + currentBytesUnarchivedInFile = localfile.size; + currentBytesUnarchived += localfile.size; + postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile)); + postProgress(); + } + + postProgress(); - postMessage(new bitjs.archive.UnarchiveFinishEvent()); + postMessage(new bitjs.archive.UnarchiveFinishEvent()); }; // event.data.file has the ArrayBuffer. onmessage = function(event) { - var ab = event.data.file; - untar(ab); -}; + var ab = event.data.file; + untar(ab); +}; \ No newline at end of file diff --git a/cps/static/js/archive/unzip.js b/cps/static/js/archive/unzip.js index 3349faf7..7eedf935 100644 --- a/cps/static/js/archive/unzip.js +++ b/cps/static/js/archive/unzip.js @@ -28,19 +28,19 @@ var totalFilesInArchive = 0; // Helper functions. var info = function(str) { - postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); + postMessage(new bitjs.archive.UnarchiveInfoEvent(str)); }; var err = function(str) { - postMessage(new bitjs.archive.UnarchiveErrorEvent(str)); + postMessage(new bitjs.archive.UnarchiveErrorEvent(str)); }; var postProgress = function() { - postMessage(new bitjs.archive.UnarchiveProgressEvent( - currentFilename, - currentFileNumber, - currentBytesUnarchivedInFile, - currentBytesUnarchived, - totalUncompressedBytesInArchive, - totalFilesInArchive)); + postMessage(new bitjs.archive.UnarchiveProgressEvent( + currentFilename, + currentFileNumber, + currentBytesUnarchivedInFile, + currentBytesUnarchived, + totalUncompressedBytesInArchive, + totalFilesInArchive)); }; var zLocalFileHeaderSignature = 0x04034b50; @@ -52,7 +52,8 @@ var zEndOfCentralDirLocatorSignature = 0x07064b50; // takes a ByteStream and parses out the local file information var ZipLocalFile = function(bstream) { - if (typeof bstream != typeof {} || !bstream.readNumber || typeof bstream.readNumber != typeof function(){}) { + if (typeof bstream != typeof {} || !bstream.readNumber || typeof bstream.readNumber != typeof + function() {}) { return null; } @@ -89,7 +90,7 @@ var ZipLocalFile = function(bstream) { this.extraField = null; if (this.extraFieldLength > 0) { this.extraField = bstream.readString(this.extraFieldLength); - info(" extra field=" + this.extraField); + info(" extra field=" + this.extraField); } // read in the compressed data @@ -113,21 +114,20 @@ var ZipLocalFile = function(bstream) { // determine what kind of compressed data we have and decompress ZipLocalFile.prototype.unzip = function() { - // Zip Version 1.0, no compression (store only) - if (this.compressionMethod == 0 ) { - info("ZIP v"+this.version+", store only: " + this.filename + " (" + this.compressedSize + " bytes)"); - currentBytesUnarchivedInFile = this.compressedSize; - currentBytesUnarchived += this.compressedSize; - } - // version == 20, compression method == 8 (DEFLATE) - else if (this.compressionMethod == 8) { - info("ZIP v2.0, DEFLATE: " + this.filename + " (" + this.compressedSize + " bytes)"); - this.fileData = inflate(this.fileData, this.uncompressedSize); - } - else { - err("UNSUPPORTED VERSION/FORMAT: ZIP v" + this.version + ", compression method=" + this.compressionMethod + ": " + this.filename + " (" + this.compressedSize + " bytes)"); - this.fileData = null; - } + // Zip Version 1.0, no compression (store only) + if (this.compressionMethod == 0) { + info("ZIP v" + this.version + ", store only: " + this.filename + " (" + this.compressedSize + " bytes)"); + currentBytesUnarchivedInFile = this.compressedSize; + currentBytesUnarchived += this.compressedSize; + } + // version == 20, compression method == 8 (DEFLATE) + else if (this.compressionMethod == 8) { + info("ZIP v2.0, DEFLATE: " + this.filename + " (" + this.compressedSize + " bytes)"); + this.fileData = inflate(this.fileData, this.uncompressedSize); + } else { + err("UNSUPPORTED VERSION/FORMAT: ZIP v" + this.version + ", compression method=" + this.compressionMethod + ": " + this.filename + " (" + this.compressedSize + " bytes)"); + this.fileData = null; + } }; @@ -135,19 +135,19 @@ ZipLocalFile.prototype.unzip = function() { // returns null on error // returns an array of DecompressedFile objects on success var unzip = function(arrayBuffer) { - postMessage(new bitjs.archive.UnarchiveStartEvent()); - - currentFilename = ""; - currentFileNumber = 0; - currentBytesUnarchivedInFile = 0; - currentBytesUnarchived = 0; - totalUncompressedBytesInArchive = 0; - totalFilesInArchive = 0; - currentBytesUnarchived = 0; - - var bstream = new bitjs.io.ByteStream(arrayBuffer); - // detect local file header signature or return null - if (bstream.peekNumber(4) == zLocalFileHeaderSignature) { + postMessage(new bitjs.archive.UnarchiveStartEvent()); + + currentFilename = ""; + currentFileNumber = 0; + currentBytesUnarchivedInFile = 0; + currentBytesUnarchived = 0; + totalUncompressedBytesInArchive = 0; + totalFilesInArchive = 0; + currentBytesUnarchived = 0; + + var bstream = new bitjs.io.ByteStream(arrayBuffer); + // detect local file header signature or return null + if (bstream.peekNumber(4) == zLocalFileHeaderSignature) { var localFiles = []; // loop until we don't see any more local files while (bstream.peekNumber(4) == zLocalFileHeaderSignature) { @@ -161,7 +161,7 @@ var unzip = function(arrayBuffer) { totalFilesInArchive = localFiles.length; // got all local files, now sort them - localFiles.sort(function(a,b) { + localFiles.sort(function(a, b) { var aname = a.filename; var bname = b.filename; return aname > bname ? 1 : -1; @@ -261,7 +261,7 @@ var unzip = function(arrayBuffer) { } postProgress(); postMessage(new bitjs.archive.UnarchiveFinishEvent()); - } + } } // returns a table of Huffman codes @@ -299,19 +299,23 @@ function getHuffmanCodes(bitLengths) { var next_code = [], code = 0; for (var bits = 1; bits <= MAX_BITS; ++bits) { - var length = bits-1; + var length = bits - 1; // ensure undefined lengths are zero if (bl_count[length] == undefined) bl_count[length] = 0; - code = (code + bl_count[bits-1]) << 1; + code = (code + bl_count[bits - 1]) << 1; next_code[bits] = code; } // Step 3: Assign numerical values to all codes - var table = {}, tableLength = 0; + var table = {}, + tableLength = 0; for (var n = 0; n < numLengths; ++n) { var len = bitLengths[n]; if (len != 0) { - table[next_code[len]] = { length: len, symbol: n }; //, bitstring: binaryValueToString(next_code[len],len) }; + table[next_code[len]] = { + length: len, + symbol: n + }; //, bitstring: binaryValueToString(next_code[len],len) }; tableLength++; next_code[len]++; } @@ -340,6 +344,7 @@ function getHuffmanCodes(bitLengths) { // fixed Huffman codes go from 7-9 bits, so we need an array whose index can hold up to 9 bits var fixedHCtoLiteral = null; var fixedHCtoDistance = null; + function getFixedLiteralTable() { // create once if (!fixedHCtoLiteral) { @@ -359,7 +364,9 @@ function getFixedDistanceTable() { // create once if (!fixedHCtoDistance) { var bitlengths = new Array(32); - for (var i = 0; i < 32; ++i) { bitlengths[i] = 5; } + for (var i = 0; i < 32; ++i) { + bitlengths[i] = 5; + } // get huffman code table fixedHCtoDistance = getHuffmanCodes(bitlengths); @@ -370,14 +377,15 @@ function getFixedDistanceTable() { // extract one bit at a time until we find a matching Huffman Code // then return that symbol function decodeSymbol(bstream, hcTable) { - var code = 0, len = 0; + var code = 0, + len = 0; var match = false; // loop until we match for (;;) { // read in next bit var bit = bstream.readBits(1); - code = (code<<1) | bit; + code = (code << 1) | bit; ++len; // check against Huffman Code table and break if found @@ -395,61 +403,98 @@ function decodeSymbol(bstream, hcTable) { var CodeLengthCodeOrder = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; - /* - Extra Extra Extra - Code Bits Length(s) Code Bits Lengths Code Bits Length(s) - ---- ---- ------ ---- ---- ------- ---- ---- ------- - 257 0 3 267 1 15,16 277 4 67-82 - 258 0 4 268 1 17,18 278 4 83-98 - 259 0 5 269 2 19-22 279 4 99-114 - 260 0 6 270 2 23-26 280 4 115-130 - 261 0 7 271 2 27-30 281 5 131-162 - 262 0 8 272 2 31-34 282 5 163-194 - 263 0 9 273 3 35-42 283 5 195-226 - 264 0 10 274 3 43-50 284 5 227-257 - 265 1 11,12 275 3 51-58 285 0 258 - 266 1 13,14 276 3 59-66 - */ +/* + Extra Extra Extra +Code Bits Length(s) Code Bits Lengths Code Bits Length(s) +---- ---- ------ ---- ---- ------- ---- ---- ------- + 257 0 3 267 1 15,16 277 4 67-82 + 258 0 4 268 1 17,18 278 4 83-98 + 259 0 5 269 2 19-22 279 4 99-114 + 260 0 6 270 2 23-26 280 4 115-130 + 261 0 7 271 2 27-30 281 5 131-162 + 262 0 8 272 2 31-34 282 5 163-194 + 263 0 9 273 3 35-42 283 5 195-226 + 264 0 10 274 3 43-50 284 5 227-257 + 265 1 11,12 275 3 51-58 285 0 258 + 266 1 13,14 276 3 59-66 +*/ var LengthLookupTable = [ - [0,3], [0,4], [0,5], [0,6], - [0,7], [0,8], [0,9], [0,10], - [1,11], [1,13], [1,15], [1,17], - [2,19], [2,23], [2,27], [2,31], - [3,35], [3,43], [3,51], [3,59], - [4,67], [4,83], [4,99], [4,115], - [5,131], [5,163], [5,195], [5,227], - [0,258] + [0, 3], + [0, 4], + [0, 5], + [0, 6], + [0, 7], + [0, 8], + [0, 9], + [0, 10], + [1, 11], + [1, 13], + [1, 15], + [1, 17], + [2, 19], + [2, 23], + [2, 27], + [2, 31], + [3, 35], + [3, 43], + [3, 51], + [3, 59], + [4, 67], + [4, 83], + [4, 99], + [4, 115], + [5, 131], + [5, 163], + [5, 195], + [5, 227], + [0, 258] ]; - /* - Extra Extra Extra - Code Bits Dist Code Bits Dist Code Bits Distance - ---- ---- ---- ---- ---- ------ ---- ---- -------- - 0 0 1 10 4 33-48 20 9 1025-1536 - 1 0 2 11 4 49-64 21 9 1537-2048 - 2 0 3 12 5 65-96 22 10 2049-3072 - 3 0 4 13 5 97-128 23 10 3073-4096 - 4 1 5,6 14 6 129-192 24 11 4097-6144 - 5 1 7,8 15 6 193-256 25 11 6145-8192 - 6 2 9-12 16 7 257-384 26 12 8193-12288 - 7 2 13-16 17 7 385-512 27 12 12289-16384 - 8 3 17-24 18 8 513-768 28 13 16385-24576 - 9 3 25-32 19 8 769-1024 29 13 24577-32768 - */ +/* + Extra Extra Extra + Code Bits Dist Code Bits Dist Code Bits Distance + ---- ---- ---- ---- ---- ------ ---- ---- -------- + 0 0 1 10 4 33-48 20 9 1025-1536 + 1 0 2 11 4 49-64 21 9 1537-2048 + 2 0 3 12 5 65-96 22 10 2049-3072 + 3 0 4 13 5 97-128 23 10 3073-4096 + 4 1 5,6 14 6 129-192 24 11 4097-6144 + 5 1 7,8 15 6 193-256 25 11 6145-8192 + 6 2 9-12 16 7 257-384 26 12 8193-12288 + 7 2 13-16 17 7 385-512 27 12 12289-16384 + 8 3 17-24 18 8 513-768 28 13 16385-24576 + 9 3 25-32 19 8 769-1024 29 13 24577-32768 +*/ var DistLookupTable = [ - [0,1], [0,2], [0,3], [0,4], - [1,5], [1,7], - [2,9], [2,13], - [3,17], [3,25], - [4,33], [4,49], - [5,65], [5,97], - [6,129], [6,193], - [7,257], [7,385], - [8,513], [8,769], - [9,1025], [9,1537], - [10,2049], [10,3073], - [11,4097], [11,6145], - [12,8193], [12,12289], - [13,16385], [13,24577] + [0, 1], + [0, 2], + [0, 3], + [0, 4], + [1, 5], + [1, 7], + [2, 9], + [2, 13], + [3, 17], + [3, 25], + [4, 33], + [4, 49], + [5, 65], + [5, 97], + [6, 129], + [6, 193], + [7, 257], + [7, 385], + [8, 513], + [8, 769], + [9, 1025], + [9, 1537], + [10, 2049], + [10, 3073], + [11, 4097], + [11, 6145], + [12, 8193], + [12, 12289], + [13, 16385], + [13, 24577] ]; function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) { @@ -468,7 +513,8 @@ function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) { stream, and copy length bytes from this position to the output stream. */ - var numSymbols = 0, blockSize = 0; + var numSymbols = 0, + blockSize = 0; for (;;) { var symbol = decodeSymbol(bstream, hcLiteralTable); ++numSymbols; @@ -476,14 +522,12 @@ function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) { // copy literal byte to output buffer.insertByte(symbol); blockSize++; - } - else { + } else { // end of block reached if (symbol == 256) { break; - } - else { - var lengthLookup = LengthLookupTable[symbol-257], + } else { + var lengthLookup = LengthLookupTable[symbol - 257], length = lengthLookup[1] + bstream.readBits(lengthLookup[0]), distLookup = DistLookupTable[decodeSymbol(bstream, hcDistanceTable)], distance = distLookup[1] + bstream.readBits(distLookup[0]); @@ -501,13 +545,13 @@ function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) { // loop for each character var ch = buffer.ptr - distance; blockSize += length; - if(length > distance) { - var data = buffer.data; - while (length--) { - buffer.insertByte(data[ch++]); - } + if (length > distance) { + var data = buffer.data; + while (length--) { + buffer.insertByte(data[ch++]); + } } else { - buffer.insertBytes(buffer.data.subarray(ch, ch + length)) + buffer.insertBytes(buffer.data.subarray(ch, ch + length)) } } // length-distance pair } // length-distance pair or end-of-block @@ -519,16 +563,17 @@ function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) { // compression method 8 // deflate: http://tools.ietf.org/html/rfc1951 function inflate(compressedData, numDecompressedBytes) { - // Bit stream representing the compressed data. - var bstream = new bitjs.io.BitStream(compressedData.buffer, - false /* rtl */, - compressedData.byteOffset, - compressedData.byteLength); - var buffer = new bitjs.io.ByteBuffer(numDecompressedBytes); - var numBlocks = 0, blockSize = 0; - - // block format: http://tools.ietf.org/html/rfc1951#page-9 - do { + // Bit stream representing the compressed data. + var bstream = new bitjs.io.BitStream(compressedData.buffer, + false /* rtl */ , + compressedData.byteOffset, + compressedData.byteLength); + var buffer = new bitjs.io.ByteBuffer(numDecompressedBytes); + var numBlocks = 0, + blockSize = 0; + + // block format: http://tools.ietf.org/html/rfc1951#page-9 + do { var bFinal = bstream.readBits(1), bType = bstream.readBits(2); blockSize = 0; @@ -540,23 +585,23 @@ function inflate(compressedData, numDecompressedBytes) { var len = bstream.readBits(16), nlen = bstream.readBits(16); // TODO: check if nlen is the ones-complement of len? - if(len > 0) buffer.insertBytes(bstream.readBytes(len)); + if (len > 0) buffer.insertBytes(bstream.readBytes(len)); blockSize = len; } // fixed Huffman codes - else if(bType == 1) { + else if (bType == 1) { blockSize = inflateBlockData(bstream, getFixedLiteralTable(), getFixedDistanceTable(), buffer); } // dynamic Huffman codes - else if(bType == 2) { + else if (bType == 2) { var numLiteralLengthCodes = bstream.readBits(5) + 257; var numDistanceCodes = bstream.readBits(5) + 1, numCodeLengthCodes = bstream.readBits(4) + 4; // populate the array of code length codes (first de-compaction) - var codeLengthsCodeLengths = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + var codeLengthsCodeLengths = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for (var i = 0; i < numCodeLengthCodes; ++i) { - codeLengthsCodeLengths[ CodeLengthCodeOrder[i] ] = bstream.readBits(3); + codeLengthsCodeLengths[CodeLengthCodeOrder[i]] = bstream.readBits(3); } // get the Huffman Codes for the code lengths @@ -585,20 +630,17 @@ function inflate(compressedData, numDecompressedBytes) { if (symbol <= 15) { literalCodeLengths.push(symbol); prevCodeLength = symbol; - } - else if (symbol == 16) { + } else if (symbol == 16) { var repeat = bstream.readBits(2) + 3; while (repeat--) { literalCodeLengths.push(prevCodeLength); } - } - else if (symbol == 17) { + } else if (symbol == 17) { var repeat = bstream.readBits(3) + 3; while (repeat--) { literalCodeLengths.push(0); } - } - else if (symbol == 18) { + } else if (symbol == 18) { var repeat = bstream.readBits(7) + 11; while (repeat--) { literalCodeLengths.push(0); @@ -624,14 +666,14 @@ function inflate(compressedData, numDecompressedBytes) { currentBytesUnarchivedInFile += blockSize; currentBytesUnarchived += blockSize; postProgress(); - } while (bFinal != 1); - // we are done reading blocks if the bFinal bit was set for this block + } while (bFinal != 1); + // we are done reading blocks if the bFinal bit was set for this block - // return the buffer data bytes - return buffer.data; + // return the buffer data bytes + return buffer.data; } // event.data.file has the ArrayBuffer. onmessage = function(event) { - unzip(event.data.file, true); -}; + unzip(event.data.file, true); +}; \ No newline at end of file diff --git a/cps/static/js/io/bitstream.js b/cps/static/js/io/bitstream.js index 47e7c9cd..77ba260f 100644 --- a/cps/static/js/io/bitstream.js +++ b/cps/static/js/io/bitstream.js @@ -8,228 +8,226 @@ * Copyright(c) 2011 Google Inc. * Copyright(c) 2011 antimatter15 */ - var bitjs = bitjs || {}; bitjs.io = bitjs.io || {}; (function() { -// mask for getting the Nth bit (zero-based) -bitjs.BIT = [ 0x01, 0x02, 0x04, 0x08, - 0x10, 0x20, 0x40, 0x80, - 0x100, 0x200, 0x400, 0x800, - 0x1000, 0x2000, 0x4000, 0x8000]; - -// mask for getting N number of bits (0-8) -var BITMASK = [0, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF ]; - - -/** - * This bit stream peeks and consumes bits out of a binary stream. - * - * @param {ArrayBuffer} ab An ArrayBuffer object or a Uint8Array. - * @param {boolean} rtl Whether the stream reads bits from the byte starting - * from bit 7 to 0 (true) or bit 0 to 7 (false). - * @param {Number} opt_offset The offset into the ArrayBuffer - * @param {Number} opt_length The length of this BitStream - */ -bitjs.io.BitStream = function(ab, rtl, opt_offset, opt_length) { - if (!ab || !ab.toString || ab.toString() !== "[object ArrayBuffer]") { - throw "Error! BitArray constructed with an invalid ArrayBuffer object"; - } - - var offset = opt_offset || 0; - var length = opt_length || ab.byteLength; - this.bytes = new Uint8Array(ab, offset, length); - this.bytePtr = 0; // tracks which byte we are on - this.bitPtr = 0; // tracks which bit we are on (can have values 0 through 7) - this.peekBits = rtl ? this.peekBits_rtl : this.peekBits_ltr; -}; - - -/** - * byte0 byte1 byte2 byte3 - * 7......0 | 7......0 | 7......0 | 7......0 - * - * The bit pointer starts at bit0 of byte0 and moves left until it reaches - * bit7 of byte0, then jumps to bit0 of byte1, etc. - * @param {number} n The number of bits to peek. - * @param {boolean=} movePointers Whether to move the pointer, defaults false. - * @return {number} The peeked bits, as an unsigned number. - */ -bitjs.io.BitStream.prototype.peekBits_ltr = function(n, movePointers) { - if (n <= 0 || typeof n != typeof 1) { - return 0; - } - - var movePointers = movePointers || false, - bytePtr = this.bytePtr, - bitPtr = this.bitPtr, - result = 0, - bitsIn = 0, - bytes = this.bytes; - - // keep going until we have no more bits left to peek at - // TODO: Consider putting all bits from bytes we will need into a variable and then - // shifting/masking it to just extract the bits we want. - // This could be considerably faster when reading more than 3 or 4 bits at a time. - while (n > 0) { - if (bytePtr >= bytes.length) { - throw "Error! Overflowed the bit stream! n=" + n + ", bytePtr=" + bytePtr + ", bytes.length=" + - bytes.length + ", bitPtr=" + bitPtr; - return -1; - } - - var numBitsLeftInThisByte = (8 - bitPtr); - if (n >= numBitsLeftInThisByte) { - var mask = (BITMASK[numBitsLeftInThisByte] << bitPtr); - result |= (((bytes[bytePtr] & mask) >> bitPtr) << bitsIn); - - bytePtr++; - bitPtr = 0; - bitsIn += numBitsLeftInThisByte; - n -= numBitsLeftInThisByte; - } - else { - var mask = (BITMASK[n] << bitPtr); - result |= (((bytes[bytePtr] & mask) >> bitPtr) << bitsIn); - - bitPtr += n; - bitsIn += n; - n = 0; - } - } - - if (movePointers) { - this.bitPtr = bitPtr; - this.bytePtr = bytePtr; - } - - return result; -}; - - -/** - * byte0 byte1 byte2 byte3 - * 7......0 | 7......0 | 7......0 | 7......0 - * - * The bit pointer starts at bit7 of byte0 and moves right until it reaches - * bit0 of byte0, then goes to bit7 of byte1, etc. - * @param {number} n The number of bits to peek. - * @param {boolean=} movePointers Whether to move the pointer, defaults false. - * @return {number} The peeked bits, as an unsigned number. - */ -bitjs.io.BitStream.prototype.peekBits_rtl = function(n, movePointers) { - if (n <= 0 || typeof n != typeof 1) { - return 0; - } - - var movePointers = movePointers || false, - bytePtr = this.bytePtr, - bitPtr = this.bitPtr, - result = 0, - bytes = this.bytes; - - // keep going until we have no more bits left to peek at - // TODO: Consider putting all bits from bytes we will need into a variable and then - // shifting/masking it to just extract the bits we want. - // This could be considerably faster when reading more than 3 or 4 bits at a time. - while (n > 0) { - - if (bytePtr >= bytes.length) { - throw "Error! Overflowed the bit stream! n=" + n + ", bytePtr=" + bytePtr + ", bytes.length=" + - bytes.length + ", bitPtr=" + bitPtr; - return -1; - } - - var numBitsLeftInThisByte = (8 - bitPtr); - if (n >= numBitsLeftInThisByte) { - result <<= numBitsLeftInThisByte; - result |= (BITMASK[numBitsLeftInThisByte] & bytes[bytePtr]); - bytePtr++; - bitPtr = 0; - n -= numBitsLeftInThisByte; - } - else { - result <<= n; - result |= ((bytes[bytePtr] & (BITMASK[n] << (8 - n - bitPtr))) >> (8 - n - bitPtr)); - - bitPtr += n; - n = 0; - } - } - - if (movePointers) { - this.bitPtr = bitPtr; - this.bytePtr = bytePtr; - } - - return result; -}; - - -/** - * Peek at 16 bits from current position in the buffer. - * Bit at (bytePtr,bitPtr) has the highest position in returning data. - * Taken from getbits.hpp in unrar. - * TODO: Move this out of BitStream and into unrar. - */ -bitjs.io.BitStream.prototype.getBits = function() { - return (((((this.bytes[this.bytePtr] & 0xff) << 16) + - ((this.bytes[this.bytePtr+1] & 0xff) << 8) + - ((this.bytes[this.bytePtr+2] & 0xff))) >>> (8-this.bitPtr)) & 0xffff); -}; - - -/** - * Reads n bits out of the stream, consuming them (moving the bit pointer). - * @param {number} n The number of bits to read. - * @return {number} The read bits, as an unsigned number. - */ -bitjs.io.BitStream.prototype.readBits = function(n) { - return this.peekBits(n, true); -}; - - -/** - * This returns n bytes as a sub-array, advancing the pointer if movePointers - * is true. Only use this for uncompressed blocks as this throws away remaining - * bits in the current byte. - * @param {number} n The number of bytes to peek. - * @param {boolean=} movePointers Whether to move the pointer, defaults false. - * @return {Uint8Array} The subarray. - */ -bitjs.io.BitStream.prototype.peekBytes = function(n, movePointers) { - if (n <= 0 || typeof n != typeof 1) { - return 0; - } - - // from http://tools.ietf.org/html/rfc1951#page-11 - // "Any bits of input up to the next byte boundary are ignored." - while (this.bitPtr != 0) { - this.readBits(1); - } - - var movePointers = movePointers || false; - var bytePtr = this.bytePtr, - bitPtr = this.bitPtr; - - var result = this.bytes.subarray(bytePtr, bytePtr + n); - - if (movePointers) { - this.bytePtr += n; - } - - return result; -}; - - -/** - * @param {number} n The number of bytes to read. - * @return {Uint8Array} The subarray. - */ -bitjs.io.BitStream.prototype.readBytes = function(n) { - return this.peekBytes(n, true); -}; - -})(); + // mask for getting the Nth bit (zero-based) + bitjs.BIT = [0x01, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80, + 0x100, 0x200, 0x400, 0x800, + 0x1000, 0x2000, 0x4000, 0x8000 + ]; + + // mask for getting N number of bits (0-8) + var BITMASK = [0, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF]; + + + /** + * This bit stream peeks and consumes bits out of a binary stream. + * + * @param {ArrayBuffer} ab An ArrayBuffer object or a Uint8Array. + * @param {boolean} rtl Whether the stream reads bits from the byte starting + * from bit 7 to 0 (true) or bit 0 to 7 (false). + * @param {Number} opt_offset The offset into the ArrayBuffer + * @param {Number} opt_length The length of this BitStream + */ + bitjs.io.BitStream = function(ab, rtl, opt_offset, opt_length) { + if (!ab || !ab.toString || ab.toString() !== "[object ArrayBuffer]") { + throw "Error! BitArray constructed with an invalid ArrayBuffer object"; + } + + var offset = opt_offset || 0; + var length = opt_length || ab.byteLength; + this.bytes = new Uint8Array(ab, offset, length); + this.bytePtr = 0; // tracks which byte we are on + this.bitPtr = 0; // tracks which bit we are on (can have values 0 through 7) + this.peekBits = rtl ? this.peekBits_rtl : this.peekBits_ltr; + }; + + + /** + * byte0 byte1 byte2 byte3 + * 7......0 | 7......0 | 7......0 | 7......0 + * + * The bit pointer starts at bit0 of byte0 and moves left until it reaches + * bit7 of byte0, then jumps to bit0 of byte1, etc. + * @param {number} n The number of bits to peek. + * @param {boolean=} movePointers Whether to move the pointer, defaults false. + * @return {number} The peeked bits, as an unsigned number. + */ + bitjs.io.BitStream.prototype.peekBits_ltr = function(n, movePointers) { + if (n <= 0 || typeof n != typeof 1) { + return 0; + } + + var movePointers = movePointers || false, + bytePtr = this.bytePtr, + bitPtr = this.bitPtr, + result = 0, + bitsIn = 0, + bytes = this.bytes; + + // keep going until we have no more bits left to peek at + // TODO: Consider putting all bits from bytes we will need into a variable and then + // shifting/masking it to just extract the bits we want. + // This could be considerably faster when reading more than 3 or 4 bits at a time. + while (n > 0) { + if (bytePtr >= bytes.length) { + throw "Error! Overflowed the bit stream! n=" + n + ", bytePtr=" + bytePtr + ", bytes.length=" + + bytes.length + ", bitPtr=" + bitPtr; + return -1; + } + + var numBitsLeftInThisByte = (8 - bitPtr); + if (n >= numBitsLeftInThisByte) { + var mask = (BITMASK[numBitsLeftInThisByte] << bitPtr); + result |= (((bytes[bytePtr] & mask) >> bitPtr) << bitsIn); + + bytePtr++; + bitPtr = 0; + bitsIn += numBitsLeftInThisByte; + n -= numBitsLeftInThisByte; + } else { + var mask = (BITMASK[n] << bitPtr); + result |= (((bytes[bytePtr] & mask) >> bitPtr) << bitsIn); + + bitPtr += n; + bitsIn += n; + n = 0; + } + } + + if (movePointers) { + this.bitPtr = bitPtr; + this.bytePtr = bytePtr; + } + + return result; + }; + + + /** + * byte0 byte1 byte2 byte3 + * 7......0 | 7......0 | 7......0 | 7......0 + * + * The bit pointer starts at bit7 of byte0 and moves right until it reaches + * bit0 of byte0, then goes to bit7 of byte1, etc. + * @param {number} n The number of bits to peek. + * @param {boolean=} movePointers Whether to move the pointer, defaults false. + * @return {number} The peeked bits, as an unsigned number. + */ + bitjs.io.BitStream.prototype.peekBits_rtl = function(n, movePointers) { + if (n <= 0 || typeof n != typeof 1) { + return 0; + } + + var movePointers = movePointers || false, + bytePtr = this.bytePtr, + bitPtr = this.bitPtr, + result = 0, + bytes = this.bytes; + + // keep going until we have no more bits left to peek at + // TODO: Consider putting all bits from bytes we will need into a variable and then + // shifting/masking it to just extract the bits we want. + // This could be considerably faster when reading more than 3 or 4 bits at a time. + while (n > 0) { + + if (bytePtr >= bytes.length) { + throw "Error! Overflowed the bit stream! n=" + n + ", bytePtr=" + bytePtr + ", bytes.length=" + + bytes.length + ", bitPtr=" + bitPtr; + return -1; + } + + var numBitsLeftInThisByte = (8 - bitPtr); + if (n >= numBitsLeftInThisByte) { + result <<= numBitsLeftInThisByte; + result |= (BITMASK[numBitsLeftInThisByte] & bytes[bytePtr]); + bytePtr++; + bitPtr = 0; + n -= numBitsLeftInThisByte; + } else { + result <<= n; + result |= ((bytes[bytePtr] & (BITMASK[n] << (8 - n - bitPtr))) >> (8 - n - bitPtr)); + + bitPtr += n; + n = 0; + } + } + + if (movePointers) { + this.bitPtr = bitPtr; + this.bytePtr = bytePtr; + } + + return result; + }; + + + /** + * Peek at 16 bits from current position in the buffer. + * Bit at (bytePtr,bitPtr) has the highest position in returning data. + * Taken from getbits.hpp in unrar. + * TODO: Move this out of BitStream and into unrar. + */ + bitjs.io.BitStream.prototype.getBits = function() { + return (((((this.bytes[this.bytePtr] & 0xff) << 16) + + ((this.bytes[this.bytePtr + 1] & 0xff) << 8) + + ((this.bytes[this.bytePtr + 2] & 0xff))) >>> (8 - this.bitPtr)) & 0xffff); + }; + + + /** + * Reads n bits out of the stream, consuming them (moving the bit pointer). + * @param {number} n The number of bits to read. + * @return {number} The read bits, as an unsigned number. + */ + bitjs.io.BitStream.prototype.readBits = function(n) { + return this.peekBits(n, true); + }; + + + /** + * This returns n bytes as a sub-array, advancing the pointer if movePointers + * is true. Only use this for uncompressed blocks as this throws away remaining + * bits in the current byte. + * @param {number} n The number of bytes to peek. + * @param {boolean=} movePointers Whether to move the pointer, defaults false. + * @return {Uint8Array} The subarray. + */ + bitjs.io.BitStream.prototype.peekBytes = function(n, movePointers) { + if (n <= 0 || typeof n != typeof 1) { + return 0; + } + + // from http://tools.ietf.org/html/rfc1951#page-11 + // "Any bits of input up to the next byte boundary are ignored." + while (this.bitPtr != 0) { + this.readBits(1); + } + + var movePointers = movePointers || false; + var bytePtr = this.bytePtr, + bitPtr = this.bitPtr; + + var result = this.bytes.subarray(bytePtr, bytePtr + n); + + if (movePointers) { + this.bytePtr += n; + } + + return result; + }; + + + /** + * @param {number} n The number of bytes to read. + * @return {Uint8Array} The subarray. + */ + bitjs.io.BitStream.prototype.readBytes = function(n) { + return this.peekBytes(n, true); + }; + +})(); \ No newline at end of file diff --git a/cps/static/js/io/bytebuffer.js b/cps/static/js/io/bytebuffer.js index 811d0ab6..cb9f955e 100644 --- a/cps/static/js/io/bytebuffer.js +++ b/cps/static/js/io/bytebuffer.js @@ -8,115 +8,114 @@ * Copyright(c) 2011 Google Inc. * Copyright(c) 2011 antimatter15 */ - var bitjs = bitjs || {}; bitjs.io = bitjs.io || {}; (function() { -/** - * A write-only Byte buffer which uses a Uint8 Typed Array as a backing store. - * @param {number} numBytes The number of bytes to allocate. - * @constructor - */ -bitjs.io.ByteBuffer = function(numBytes) { - if (typeof numBytes != typeof 1 || numBytes <= 0) { - throw "Error! ByteBuffer initialized with '" + numBytes + "'"; - } - this.data = new Uint8Array(numBytes); - this.ptr = 0; -}; - - -/** - * @param {number} b The byte to insert. - */ -bitjs.io.ByteBuffer.prototype.insertByte = function(b) { - // TODO: throw if byte is invalid? - this.data[this.ptr++] = b; -}; - - -/** - * @param {Array.|Uint8Array|Int8Array} bytes The bytes to insert. - */ -bitjs.io.ByteBuffer.prototype.insertBytes = function(bytes) { - // TODO: throw if bytes is invalid? - this.data.set(bytes, this.ptr); - this.ptr += bytes.length; -}; - - -/** - * Writes an unsigned number into the next n bytes. If the number is too large - * to fit into n bytes or is negative, an error is thrown. - * @param {number} num The unsigned number to write. - * @param {number} numBytes The number of bytes to write the number into. - */ -bitjs.io.ByteBuffer.prototype.writeNumber = function(num, numBytes) { - if (numBytes < 1) { - throw 'Trying to write into too few bytes: ' + numBytes; - } - if (num < 0) { - throw 'Trying to write a negative number (' + num + - ') as an unsigned number to an ArrayBuffer'; - } - if (num > (Math.pow(2, numBytes * 8) - 1)) { - throw 'Trying to write ' + num + ' into only ' + numBytes + ' bytes'; - } - - // Roll 8-bits at a time into an array of bytes. - var bytes = []; - while (numBytes-- > 0) { - var eightBits = num & 255; - bytes.push(eightBits); - num >>= 8; - } - - this.insertBytes(bytes); -}; - - -/** - * Writes a signed number into the next n bytes. If the number is too large - * to fit into n bytes, an error is thrown. - * @param {number} num The signed number to write. - * @param {number} numBytes The number of bytes to write the number into. - */ -bitjs.io.ByteBuffer.prototype.writeSignedNumber = function(num, numBytes) { - if (numBytes < 1) { - throw 'Trying to write into too few bytes: ' + numBytes; - } - - var HALF = Math.pow(2, (numBytes * 8) - 1); - if (num >= HALF || num < -HALF) { - throw 'Trying to write ' + num + ' into only ' + numBytes + ' bytes'; - } - - // Roll 8-bits at a time into an array of bytes. - var bytes = []; - while (numBytes-- > 0) { - var eightBits = num & 255; - bytes.push(eightBits); - num >>= 8; - } - - this.insertBytes(bytes); -}; - - -/** - * @param {string} str The ASCII string to write. - */ -bitjs.io.ByteBuffer.prototype.writeASCIIString = function(str) { - for (var i = 0; i < str.length; ++i) { - var curByte = str.charCodeAt(i); - if (curByte < 0 || curByte > 255) { - throw 'Trying to write a non-ASCII string!'; - } - this.insertByte(curByte); - } -}; - -})(); + /** + * A write-only Byte buffer which uses a Uint8 Typed Array as a backing store. + * @param {number} numBytes The number of bytes to allocate. + * @constructor + */ + bitjs.io.ByteBuffer = function(numBytes) { + if (typeof numBytes != typeof 1 || numBytes <= 0) { + throw "Error! ByteBuffer initialized with '" + numBytes + "'"; + } + this.data = new Uint8Array(numBytes); + this.ptr = 0; + }; + + + /** + * @param {number} b The byte to insert. + */ + bitjs.io.ByteBuffer.prototype.insertByte = function(b) { + // TODO: throw if byte is invalid? + this.data[this.ptr++] = b; + }; + + + /** + * @param {Array.|Uint8Array|Int8Array} bytes The bytes to insert. + */ + bitjs.io.ByteBuffer.prototype.insertBytes = function(bytes) { + // TODO: throw if bytes is invalid? + this.data.set(bytes, this.ptr); + this.ptr += bytes.length; + }; + + + /** + * Writes an unsigned number into the next n bytes. If the number is too large + * to fit into n bytes or is negative, an error is thrown. + * @param {number} num The unsigned number to write. + * @param {number} numBytes The number of bytes to write the number into. + */ + bitjs.io.ByteBuffer.prototype.writeNumber = function(num, numBytes) { + if (numBytes < 1) { + throw 'Trying to write into too few bytes: ' + numBytes; + } + if (num < 0) { + throw 'Trying to write a negative number (' + num + + ') as an unsigned number to an ArrayBuffer'; + } + if (num > (Math.pow(2, numBytes * 8) - 1)) { + throw 'Trying to write ' + num + ' into only ' + numBytes + ' bytes'; + } + + // Roll 8-bits at a time into an array of bytes. + var bytes = []; + while (numBytes-- > 0) { + var eightBits = num & 255; + bytes.push(eightBits); + num >>= 8; + } + + this.insertBytes(bytes); + }; + + + /** + * Writes a signed number into the next n bytes. If the number is too large + * to fit into n bytes, an error is thrown. + * @param {number} num The signed number to write. + * @param {number} numBytes The number of bytes to write the number into. + */ + bitjs.io.ByteBuffer.prototype.writeSignedNumber = function(num, numBytes) { + if (numBytes < 1) { + throw 'Trying to write into too few bytes: ' + numBytes; + } + + var HALF = Math.pow(2, (numBytes * 8) - 1); + if (num >= HALF || num < -HALF) { + throw 'Trying to write ' + num + ' into only ' + numBytes + ' bytes'; + } + + // Roll 8-bits at a time into an array of bytes. + var bytes = []; + while (numBytes-- > 0) { + var eightBits = num & 255; + bytes.push(eightBits); + num >>= 8; + } + + this.insertBytes(bytes); + }; + + + /** + * @param {string} str The ASCII string to write. + */ + bitjs.io.ByteBuffer.prototype.writeASCIIString = function(str) { + for (var i = 0; i < str.length; ++i) { + var curByte = str.charCodeAt(i); + if (curByte < 0 || curByte > 255) { + throw 'Trying to write a non-ASCII string!'; + } + this.insertByte(curByte); + } + }; + +})(); \ No newline at end of file diff --git a/cps/static/js/io/bytestream.js b/cps/static/js/io/bytestream.js index a67a7122..b434b8e7 100644 --- a/cps/static/js/io/bytestream.js +++ b/cps/static/js/io/bytestream.js @@ -8,157 +8,156 @@ * Copyright(c) 2011 Google Inc. * Copyright(c) 2011 antimatter15 */ - var bitjs = bitjs || {}; bitjs.io = bitjs.io || {}; (function() { -/** - * This object allows you to peek and consume bytes as numbers and strings - * out of an ArrayBuffer. In this buffer, everything must be byte-aligned. - * - * @param {ArrayBuffer} ab The ArrayBuffer object. - * @param {number=} opt_offset The offset into the ArrayBuffer - * @param {number=} opt_length The length of this BitStream - * @constructor - */ -bitjs.io.ByteStream = function(ab, opt_offset, opt_length) { - var offset = opt_offset || 0; - var length = opt_length || ab.byteLength; - this.bytes = new Uint8Array(ab, offset, length); - this.ptr = 0; -}; - - -/** - * Peeks at the next n bytes as an unsigned number but does not advance the - * pointer - * TODO: This apparently cannot read more than 4 bytes as a number? - * @param {number} n The number of bytes to peek at. - * @return {number} The n bytes interpreted as an unsigned number. - */ -bitjs.io.ByteStream.prototype.peekNumber = function(n) { - // TODO: return error if n would go past the end of the stream? - if (n <= 0 || typeof n != typeof 1) - return -1; - - var result = 0; - // read from last byte to first byte and roll them in - var curByte = this.ptr + n - 1; - while (curByte >= this.ptr) { - result <<= 8; - result |= this.bytes[curByte]; - --curByte; - } - return result; -}; - - -/** - * Returns the next n bytes as an unsigned number (or -1 on error) - * and advances the stream pointer n bytes. - * @param {number} n The number of bytes to read. - * @return {number} The n bytes interpreted as an unsigned number. - */ -bitjs.io.ByteStream.prototype.readNumber = function(n) { - var num = this.peekNumber( n ); - this.ptr += n; - return num; -}; - - -/** - * Returns the next n bytes as a signed number but does not advance the - * pointer. - * @param {number} n The number of bytes to read. - * @return {number} The bytes interpreted as a signed number. - */ -bitjs.io.ByteStream.prototype.peekSignedNumber = function(n) { - var num = this.peekNumber(n); - var HALF = Math.pow(2, (n * 8) - 1); - var FULL = HALF * 2; - - if (num >= HALF) num -= FULL; - - return num; -}; - - -/** - * Returns the next n bytes as a signed number and advances the stream pointer. - * @param {number} n The number of bytes to read. - * @return {number} The bytes interpreted as a signed number. - */ -bitjs.io.ByteStream.prototype.readSignedNumber = function(n) { - var num = this.peekSignedNumber(n); - this.ptr += n; - return num; -}; - - -/** - * This returns n bytes as a sub-array, advancing the pointer if movePointers - * is true. - * @param {number} n The number of bytes to read. - * @param {boolean} movePointers Whether to move the pointers. - * @return {Uint8Array} The subarray. - */ -bitjs.io.ByteStream.prototype.peekBytes = function(n, movePointers) { - if (n <= 0 || typeof n != typeof 1) { - return null; - } - - var result = this.bytes.subarray(this.ptr, this.ptr + n); - - if (movePointers) { - this.ptr += n; - } - - return result; -}; - - -/** - * Reads the next n bytes as a sub-array. - * @param {number} n The number of bytes to read. - * @return {Uint8Array} The subarray. - */ -bitjs.io.ByteStream.prototype.readBytes = function(n) { - return this.peekBytes(n, true); -}; - - -/** - * Peeks at the next n bytes as a string but does not advance the pointer. - * @param {number} n The number of bytes to peek at. - * @return {string} The next n bytes as a string. - */ -bitjs.io.ByteStream.prototype.peekString = function(n) { - if (n <= 0 || typeof n != typeof 1) { - return ""; - } - - var result = ""; - for (var p = this.ptr, end = this.ptr + n; p < end; ++p) { - result += String.fromCharCode(this.bytes[p]); - } - return result; -}; - - -/** - * Returns the next n bytes as an ASCII string and advances the stream pointer - * n bytes. - * @param {number} n The number of bytes to read. - * @return {string} The next n bytes as a string. - */ -bitjs.io.ByteStream.prototype.readString = function(n) { - var strToReturn = this.peekString(n); - this.ptr += n; - return strToReturn; -}; - - -})(); + /** + * This object allows you to peek and consume bytes as numbers and strings + * out of an ArrayBuffer. In this buffer, everything must be byte-aligned. + * + * @param {ArrayBuffer} ab The ArrayBuffer object. + * @param {number=} opt_offset The offset into the ArrayBuffer + * @param {number=} opt_length The length of this BitStream + * @constructor + */ + bitjs.io.ByteStream = function(ab, opt_offset, opt_length) { + var offset = opt_offset || 0; + var length = opt_length || ab.byteLength; + this.bytes = new Uint8Array(ab, offset, length); + this.ptr = 0; + }; + + + /** + * Peeks at the next n bytes as an unsigned number but does not advance the + * pointer + * TODO: This apparently cannot read more than 4 bytes as a number? + * @param {number} n The number of bytes to peek at. + * @return {number} The n bytes interpreted as an unsigned number. + */ + bitjs.io.ByteStream.prototype.peekNumber = function(n) { + // TODO: return error if n would go past the end of the stream? + if (n <= 0 || typeof n != typeof 1) + return -1; + + var result = 0; + // read from last byte to first byte and roll them in + var curByte = this.ptr + n - 1; + while (curByte >= this.ptr) { + result <<= 8; + result |= this.bytes[curByte]; + --curByte; + } + return result; + }; + + + /** + * Returns the next n bytes as an unsigned number (or -1 on error) + * and advances the stream pointer n bytes. + * @param {number} n The number of bytes to read. + * @return {number} The n bytes interpreted as an unsigned number. + */ + bitjs.io.ByteStream.prototype.readNumber = function(n) { + var num = this.peekNumber(n); + this.ptr += n; + return num; + }; + + + /** + * Returns the next n bytes as a signed number but does not advance the + * pointer. + * @param {number} n The number of bytes to read. + * @return {number} The bytes interpreted as a signed number. + */ + bitjs.io.ByteStream.prototype.peekSignedNumber = function(n) { + var num = this.peekNumber(n); + var HALF = Math.pow(2, (n * 8) - 1); + var FULL = HALF * 2; + + if (num >= HALF) num -= FULL; + + return num; + }; + + + /** + * Returns the next n bytes as a signed number and advances the stream pointer. + * @param {number} n The number of bytes to read. + * @return {number} The bytes interpreted as a signed number. + */ + bitjs.io.ByteStream.prototype.readSignedNumber = function(n) { + var num = this.peekSignedNumber(n); + this.ptr += n; + return num; + }; + + + /** + * This returns n bytes as a sub-array, advancing the pointer if movePointers + * is true. + * @param {number} n The number of bytes to read. + * @param {boolean} movePointers Whether to move the pointers. + * @return {Uint8Array} The subarray. + */ + bitjs.io.ByteStream.prototype.peekBytes = function(n, movePointers) { + if (n <= 0 || typeof n != typeof 1) { + return null; + } + + var result = this.bytes.subarray(this.ptr, this.ptr + n); + + if (movePointers) { + this.ptr += n; + } + + return result; + }; + + + /** + * Reads the next n bytes as a sub-array. + * @param {number} n The number of bytes to read. + * @return {Uint8Array} The subarray. + */ + bitjs.io.ByteStream.prototype.readBytes = function(n) { + return this.peekBytes(n, true); + }; + + + /** + * Peeks at the next n bytes as a string but does not advance the pointer. + * @param {number} n The number of bytes to peek at. + * @return {string} The next n bytes as a string. + */ + bitjs.io.ByteStream.prototype.peekString = function(n) { + if (n <= 0 || typeof n != typeof 1) { + return ""; + } + + var result = ""; + for (var p = this.ptr, end = this.ptr + n; p < end; ++p) { + result += String.fromCharCode(this.bytes[p]); + } + return result; + }; + + + /** + * Returns the next n bytes as an ASCII string and advances the stream pointer + * n bytes. + * @param {number} n The number of bytes to read. + * @return {string} The next n bytes as a string. + */ + bitjs.io.ByteStream.prototype.readString = function(n) { + var strToReturn = this.peekString(n); + this.ptr += n; + return strToReturn; + }; + + +})(); \ No newline at end of file