diff options
author | Yaco <franco@reevo.org> | 2021-10-19 20:24:11 -0300 |
---|---|---|
committer | Yaco <franco@reevo.org> | 2021-10-19 20:24:11 -0300 |
commit | e3880a1c86acaa3bbd05786ad2f5c586e6511a58 (patch) | |
tree | ec77bfc5b69f259a159c95188797bd0dade92357 /www/wiki/extensions/Maps/resources/GoogleMaps/geoxml3/ZipFile.complete.js | |
parent | 20ca0685509f8010580d3b45036a64ab48616af1 (diff) |
updates Maps to 7.13.0
Diffstat (limited to 'www/wiki/extensions/Maps/resources/GoogleMaps/geoxml3/ZipFile.complete.js')
-rw-r--r-- | www/wiki/extensions/Maps/resources/GoogleMaps/geoxml3/ZipFile.complete.js | 3939 |
1 files changed, 2008 insertions, 1931 deletions
diff --git a/www/wiki/extensions/Maps/resources/GoogleMaps/geoxml3/ZipFile.complete.js b/www/wiki/extensions/Maps/resources/GoogleMaps/geoxml3/ZipFile.complete.js index d49bb056..f2f374cf 100644 --- a/www/wiki/extensions/Maps/resources/GoogleMaps/geoxml3/ZipFile.complete.js +++ b/www/wiki/extensions/Maps/resources/GoogleMaps/geoxml3/ZipFile.complete.js @@ -19,143 +19,143 @@ (function(){ - if (typeof JSIO == "object"){ - var e1 = new Error("JSIO is already defined"); - e1.source = "JSIO.core.js"; - throw e1; - } - - JSIO = {}; - - JSIO.version = "2.0 2012Feb"; - - JSIO.throwError = function(msg, source, sub) { - var error = new Error("Error: " + msg); - error.source = (source || this._typename || 'JSIO') + (sub ? '.'+sub : ''); - throw error; - } - - // Format a number as hex. Quantities over 7ffffff will be displayed properly. - JSIO.decimalToHexString = function(number, digits) { - if (number < 0) { - number = 0xFFFFFFFF + number + 1; - } - var r1 = number.toString(16).toUpperCase(); - if (digits) { - r1 = "00000000" + r1; - r1 = r1.substring(r1.length - digits); - } - return r1; - }; - - JSIO.FileType = { - Text : 0, - Binary : 1, - XML : 2, - Unknown : 3 - }; - - - JSIO.guessFileType = function(name) { - if (name == "makefile") { return JSIO.FileType.Text; } - - var lastDot = name.lastIndexOf("."); - if (lastDot <= 0) { return JSIO.FileType.Unknown; } - - var ext= name.substring(lastDot); - if (ext == ".zip") { return JSIO.FileType.Binary; } - if (ext == ".xlsx") { return JSIO.FileType.Binary; } - if (ext == ".docx") { return JSIO.FileType.Binary; } - if (ext == ".dll") { return JSIO.FileType.Binary; } - if (ext == ".obj") { return JSIO.FileType.Binary; } - if (ext == ".pdb") { return JSIO.FileType.Binary; } - if (ext == ".exe") { return JSIO.FileType.Binary; } - if (ext == ".kmz") { return JSIO.FileType.Binary; } - - if (ext == ".xml") { return JSIO.FileType.XML; } - if (ext == ".xsl") { return JSIO.FileType.XML; } - if (ext == ".kml") { return JSIO.FileType.XML; } - if (ext == ".csproj") { return JSIO.FileType.XML; } - if (ext == ".vbproj") { return JSIO.FileType.XML; } - if (ext == ".shfbproj") { return JSIO.FileType.XML; } - if (ext == ".resx") { return JSIO.FileType.XML; } - if (ext == ".xslt") { return JSIO.FileType.XML; } - - if (ext == ".sln") { return JSIO.FileType.Text; } - if (ext == ".htm") { return JSIO.FileType.Text; } - if (ext == ".html") { return JSIO.FileType.Text; } - if (ext == ".js") { return JSIO.FileType.Text; } - if (ext == ".vb") { return JSIO.FileType.Text; } - if (ext == ".txt") { return JSIO.FileType.Text; } - if (ext == ".rels") { return JSIO.FileType.Text; } - if (ext == ".css") { return JSIO.FileType.Text; } - if (ext == ".cs") { return JSIO.FileType.Text; } - if (ext == ".asp") { return JSIO.FileType.Text; } - - return JSIO.FileType.Unknown; - }; - - JSIO.stringOfLength = function (charCode, length) { - var s3 = ""; - for (var i = 0; i < length; i++) { - s3 += String.fromCharCode(charCode); - } - return s3; - }; - - JSIO.formatByteArray = function(b) { - var s1 = "0000 "; - var s2 = ""; - for (var i = 0; i < b.length; i++) { - if (i !== 0 && i % 16 === 0) { - s1 += " " + s2 +"\n" + JSIO.decimalToHexString(i, 4) + " "; - s2 = ""; - } - s1 += JSIO.decimalToHexString(b[i], 2) + " "; - if (b[i] >=32 && b[i] <= 126) { - s2 += String.fromCharCode(b[i]); - } else { - s2 += "."; - } - } - if (s2.length > 0) { - s1 += JSIO.stringOfLength(32, ((i%16>0)? ((16 - i%16) * 3) : 0) + 4) + s2; - } - return s1; - }; - - JSIO.htmlEscape = function(str) { - return str - .replace(new RegExp( "&", "g" ), "&") - .replace(new RegExp( "<", "g" ), "<") - .replace(new RegExp( ">", "g" ), ">") - .replace(new RegExp( "\x13", "g" ), "<br/>") - .replace(new RegExp( "\x10", "g" ), "<br/>"); - }; - - JSIO.massApply = function(func, funcThis, arr, needReturn) { - var arrayLimit = 99999; // Chrome has an apply/array limit of 99999; Firefox = 491519 - if (arr.length < arrayLimit) return func.apply(funcThis, arr); - else { - var newThis = funcThis; - var offset = 0; - var end = 99999; - - while (offset < arr.length) { - var arrSlice; - if (arr.subarray) arrSlice = arr.subarray(offset, end); - else if (arr.slice) arrSlice = arr.slice(offset, end); - - if (needReturn) newThis += func.apply(newThis, arrSlice); - else func.apply(funcThis, arrSlice); - - offset += arrayLimit; - end += arrayLimit; - end = Math.min(arr.length, end); - } - return newThis; - } - } + if (typeof JSIO == "object"){ + var e1 = new Error("JSIO is already defined"); + e1.source = "JSIO.core.js"; + throw e1; + } + + JSIO = {}; + + JSIO.version = "2.0 2012Feb"; + + JSIO.throwError = function(msg, source, sub) { + var error = new Error("Error: " + msg); + error.source = (source || this._typename || 'JSIO') + (sub ? '.'+sub : ''); + throw error; + } + + // Format a number as hex. Quantities over 7ffffff will be displayed properly. + JSIO.decimalToHexString = function(number, digits) { + if (number < 0) { + number = 0xFFFFFFFF + number + 1; + } + var r1 = number.toString(16).toUpperCase(); + if (digits) { + r1 = "00000000" + r1; + r1 = r1.substring(r1.length - digits); + } + return r1; + }; + + JSIO.FileType = { + Text : 0, + Binary : 1, + XML : 2, + Unknown : 3 + }; + + + JSIO.guessFileType = function(name) { + if (name == "makefile") { return JSIO.FileType.Text; } + + var lastDot = name.lastIndexOf("."); + if (lastDot <= 0) { return JSIO.FileType.Unknown; } + + var ext= name.substring(lastDot); + if (ext == ".zip") { return JSIO.FileType.Binary; } + if (ext == ".xlsx") { return JSIO.FileType.Binary; } + if (ext == ".docx") { return JSIO.FileType.Binary; } + if (ext == ".dll") { return JSIO.FileType.Binary; } + if (ext == ".obj") { return JSIO.FileType.Binary; } + if (ext == ".pdb") { return JSIO.FileType.Binary; } + if (ext == ".exe") { return JSIO.FileType.Binary; } + if (ext == ".kmz") { return JSIO.FileType.Binary; } + + if (ext == ".xml") { return JSIO.FileType.XML; } + if (ext == ".xsl") { return JSIO.FileType.XML; } + if (ext == ".kml") { return JSIO.FileType.XML; } + if (ext == ".csproj") { return JSIO.FileType.XML; } + if (ext == ".vbproj") { return JSIO.FileType.XML; } + if (ext == ".shfbproj") { return JSIO.FileType.XML; } + if (ext == ".resx") { return JSIO.FileType.XML; } + if (ext == ".xslt") { return JSIO.FileType.XML; } + + if (ext == ".sln") { return JSIO.FileType.Text; } + if (ext == ".htm") { return JSIO.FileType.Text; } + if (ext == ".html") { return JSIO.FileType.Text; } + if (ext == ".js") { return JSIO.FileType.Text; } + if (ext == ".vb") { return JSIO.FileType.Text; } + if (ext == ".txt") { return JSIO.FileType.Text; } + if (ext == ".rels") { return JSIO.FileType.Text; } + if (ext == ".css") { return JSIO.FileType.Text; } + if (ext == ".cs") { return JSIO.FileType.Text; } + if (ext == ".asp") { return JSIO.FileType.Text; } + + return JSIO.FileType.Unknown; + }; + + JSIO.stringOfLength = function (charCode, length) { + var s3 = ""; + for (var i = 0; i < length; i++) { + s3 += String.fromCharCode(charCode); + } + return s3; + }; + + JSIO.formatByteArray = function(b) { + var s1 = "0000 "; + var s2 = ""; + for (var i = 0; i < b.length; i++) { + if (i !== 0 && i % 16 === 0) { + s1 += " " + s2 +"\n" + JSIO.decimalToHexString(i, 4) + " "; + s2 = ""; + } + s1 += JSIO.decimalToHexString(b[i], 2) + " "; + if (b[i] >=32 && b[i] <= 126) { + s2 += String.fromCharCode(b[i]); + } else { + s2 += "."; + } + } + if (s2.length > 0) { + s1 += JSIO.stringOfLength(32, ((i%16>0)? ((16 - i%16) * 3) : 0) + 4) + s2; + } + return s1; + }; + + JSIO.htmlEscape = function(str) { + return str + .replace(new RegExp( "&", "g" ), "&") + .replace(new RegExp( "<", "g" ), "<") + .replace(new RegExp( ">", "g" ), ">") + .replace(new RegExp( "\x13", "g" ), "<br/>") + .replace(new RegExp( "\x10", "g" ), "<br/>"); + }; + + JSIO.massApply = function(func, funcThis, arr, needReturn) { + var arrayLimit = 65536; // Chrome has an apply/array limit of 99999; Firefox = 491519, Safari = 65536 + if (arr.length < arrayLimit) return func.apply(funcThis, arr); + else { + var newThis = funcThis; + var offset = 0; + var end = 65536; + + while (offset < arr.length) { + var arrSlice; + if (arr.subarray) arrSlice = arr.subarray(offset, end); + else if (arr.slice) arrSlice = arr.slice(offset, end); + + if (needReturn) newThis += func.apply(newThis, arrSlice); + else func.apply(funcThis, arrSlice); + + offset += arrayLimit; + end += arrayLimit; + end = Math.min(arr.length, end); + } + return newThis; + } + } })(); @@ -197,364 +197,364 @@ (function(){ - var version = "2.0 2012Feb"; - - if (typeof JSIO !== "object") { JSIO = {}; } - if ((typeof JSIO.version !== "string")) { - JSIO.version = version; - } - else if ((JSIO.version.length < 3) || - (JSIO.version.substring(0,3) !== "2.0")) { - JSIO.version += " " + version; - } - - // ======================================================= - // the base object, used as the prototype of all ByteReader objects. - var _byteReaderBase = function () { - this.position = 0; - // position must be incremented in .readByte() for all derived classes - }; - - _byteReaderBase.prototype._throwError = JSIO.throwError; - - _byteReaderBase.prototype._limitCheck = function(len, startPos) { - var LOE = { - len: len, - pos: startPos, - end: startPos+len - }; - - if (len === 0) return {len:0, pos:0, end:0}; - if (len < 0) this._throwError("Invalid read length"); - if (!this.length) return {len:len, pos:this.position, end:len+this.position}; - if (!startPos >= 0) LOE.pos = this.position; - if (this.length <= LOE.pos) this._throwError("EOF reached"); - - LOE.end = LOE.pos+len; - if (this.length < LOE.end) LOE.end = LOE.pos+(LOE.len = this.length-this.position); - return LOE; - } - - JSIO.SeekOrigin = { - Begin : 0, - Current : 1, - End : 2, - SEEK_SET : 0, - SEEK_CUR : 1, - SEEK_END : 2 - }; - - _byteReaderBase.prototype.seek = function(offset, origin) { - switch (origin) { - case JSIO.SeekOrigin.Begin: - if (offset == this.position) return this.position; - if (!this.length) { - if (offset < this.position) this._throwError('Uni-directional stream cannot seek backwards', null, 'seek'); - else if (offset > this.position) return this.read(offset - this.position); // read will limit check - } - else { - if (this.length < offset) this._throwError('Cannot seek past reader length', null, 'seek'); - this.position = offset; - } - break; - case JSIO.SeekOrigin.Current: - return this.seek(this.position + offset, JSIO.SeekOrigin.Begin); - break; - case JSIO.SeekOrigin.End: - if (!this.length) this._throwError('Uni-directional stream has no known end length for seek', null, 'seek'); - return this.seek(this.length - 1 + offset, JSIO.SeekOrigin.Begin); - break; - default: - this._throwError('Invalid seek method', null, 'seek'); - break; - } - - return this.position; - }; - - _byteReaderBase.prototype.read = function(len, startPos) { - var LOE = this._limitCheck(len, startPos); - if (LOE.len === 0) return []; - if (LOE.pos != this.position) this.seek(LOE.pos, JSIO.SeekOrigin.Begin); - - var bytesRead = []; - - // Faster methods with an array or stream - if (this.array && this.array.subarray) bytesRead = this.array.subarray(LOE.pos, LOE.end); - else if (this.array && this.array.slice) bytesRead = this.array.slice(LOE.pos, LOE.end); - else if (this.stream) bytesRead = this.stream.read(LOE.len, LOE.pos); - else if (this.length) { // Random-access stream - for(var i=LOE.pos; i<LOE.end; i++) { bytesRead.push(this.readByteAt(i)); } - } - else { // Uni-directional stream - for(var i=LOE.pos; i<LOE.end; i++) { - var b = this.readByte(); - if (b === null || b === undefined) break; - bytesRead.push(b); - } - } - this.position = LOE.end; - return bytesRead; - }; - - _byteReaderBase.prototype.beginRead = function(len, startPos, callback) { - var LOE = this._limitCheck(len, startPos); - if (LOE.len === 0) return setTimeout(function() { callback([]); }, 1); - if (LOE.pos != this.position) this.seek(LOE.pos, JSIO.SeekOrigin.Begin); - - var bytesRead = []; - var thisReader = this; - var leftToRead = LOE.len; - - var readBatchAsync = function() { - var c = 0; - var pos = thisReader.position; - - // read a 32k batch - var l = (leftToRead >= 32768) ? 32768 : leftToRead; - var newBytes = thisReader.read(l); - JSIO.massApply(bytesRead.push, bytesRead, newBytes); - c += l; - leftToRead -= l; - if (newBytes.length < l) leftToRead = 0; - - if (leftToRead>0) setTimeout(readBatchAsync, 1); - else callback(bytesRead); - }; - - // kickoff - setTimeout(readBatchAsync, 1); // always async, in ALL situations - return null; - }; - - _byteReaderBase.prototype.readToEnd = function() { - if (this.array && this.array.subarray) return this.array.subarray(this.position); - else if (this.array && this.array.slice) return this.array.slice(this.position); - else if (this.length) return this.read(this.length - this.position); - else return this.read(9000 * 9000); // over 9000 - }; - - _byteReaderBase.prototype.beginReadToEnd = function(callback) { - if (this.array && this.array.subarray) setTimeout(function() { callback( this.array.subarray(this.position) ); }, 1); - else if (this.array && this.array.slice) setTimeout(function() { callback( this.array.slice(this.position) ); }, 1); - else if (this.length) return this.beginRead(this.length - this.position, this.position, callback); - else return this.beginRead(9000 * 9000, this.position, callback); - }; - - // Generic routines; one of these two MUST be overloaded (preferrably both) - _byteReaderBase.prototype.readByte = function(){ - if (this.length && this.position >= this.length) return null; // EOF - - var byte; - if (this.array) byte = this.array[this.position++]; - else if (this.length) byte = this.readByteAt(this.position++); - else if (this.stream) byte = this.stream.read(1)[0]; - else byte = this.read(1)[0]; - return (byte === null || byte === undefined) ? null : byte; - }; - _byteReaderBase.prototype.readByteAt = function(i) { - var pos = this.position; // no position changes on this one - if (i === null || i === undefined) i = this.position; - - var byte; - if (this.array) byte = this.array[i]; - else if (i === pos) byte = this.readByte(); - else if (this.stream) byte = this.stream.read(1, i)[0]; - else byte = this.read(1, i)[0]; - - this.position = pos; - return (byte === null || byte === undefined) ? null : byte; - } - - _byteReaderBase.prototype.readBytes = _byteReaderBase.prototype.read; - _byteReaderBase.prototype.beginReadBytes = function(len, callback) { return this.beginRead(len, this.position, callback); }; - - _byteReaderBase.prototype.readNumber = function(len, startPos){ - var LOE = this._limitCheck(len, startPos); - if (LOE.len === 0) LOE.len = 1; - if (LOE.pos != this.position) this.seek(LOE.pos, JSIO.SeekOrigin.Begin); - - var result = 0; - var bytes = this.read(LOE.len, LOE.pos); - for (var i=bytes.length-1; i>=0; i--) { - // IE only supports 32-bit integer shifting - //result = result << 8 | bytes[i]; - result = result*256 + bytes[i]; - } - return result; - }; - - _byteReaderBase.prototype.readString = function(len, startPos){ - var LOE = this._limitCheck(len, startPos); - if (LOE.len === 0) return ''; - if (LOE.pos != this.position) this.seek(LOE.pos, JSIO.SeekOrigin.Begin); - - var result = ''; - var bytes = this.read(LOE.len, LOE.pos); - for(var i=0; i<bytes.length; i++){ - result += String.fromCharCode(bytes[i]); - } - return result; - }; - - _byteReaderBase.prototype.readNullTerminatedString = function(startPos){ - var pos = startPos || this.position; - if (this.length && this.length < pos) this._throwError('EOF reached', null, 'readNullTerminatedString'); - if (pos != this.position) this.seek(pos, JSIO.SeekOrigin.Begin); - - var slarge = ""; - var s = ""; - var c = 0; - - // Faster method with an array - if (this.array && this.array.indexOf) { - var len = pos - this.array.indexOf(0, pos); - if (len > 0) return this.readString(len, pos); - } - - var ch; - while(1) { - ch = String.fromCharCode(this.readByteAt(pos+c)); - if (ch === null) break; - - s += ch; - c++; - if(c >= 32768) { - slarge += s; - s = ""; - pos += c; - this.position += c; - c = 0; - } - }; - this.position = pos + c; - return slarge + s; - }; - - _byteReaderBase.prototype.beginReadNullTerminatedString = function(callback, startPos){ - var pos = startPos || this.position; - if (this.length && this.length < pos) this._throwError('EOF reached', null, 'beginReadNullTerminatedString'); - - var slarge = ""; - var s = ""; - var thisBinStream = this; - - var readBatchAsync = function() { - var c = 0; - - var ch; - while(1) { - ch = String.fromCharCode(this.readByteAt(pos+c)); - if (ch === null) break; - - s += ch; - c++; - if(c >= 32768) { - slarge += s; - s = ""; - pos += c; - this.position += c; - c = 0; - } - }; - - thisBinStream.position = pos + c; - if (ch!==null) setTimeout(readBatchAsync, 1); - else callback(slarge+s); - }; - - // Faster method with an array - if (this.array && this.array.indexOf) { - var len = pos - this.array.indexOf(0, pos); - if (len > 0) readBatchASync = function() { callback(thisBinStream.readString(len, pos)); }; - } - - // kickoff - setTimeout(readBatchAsync, 1); // always async, in ALL situations - return null; - }; - - - - JSIO._ByteReaderBase = _byteReaderBase; - // ======================================================= - - - - - // ======================================================= - // reads from an array of bytes. - // This basically wraps a readByte() fn onto array access. - var _arrayReader = function(array) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.ArrayReader', 'ctor'); - this.position = 0; - this.array = array; - this.length = array.length; - this._typename = "JSIO.ArrayReader"; - this._version = version; - return this; - }; - - _arrayReader.prototype = new JSIO._ByteReaderBase(); - - _arrayReader.prototype.readByte = function() { - if (this.position >= this.array.length) return null; // EOF - return this.array[this.position++]; - }; - _arrayReader.prototype.readByteAt = function(i) { - return this.array[i]; - }; - - // ======================================================= - - - // ======================================================= - // reads bytes at a time from a defined segment of a stream. - var _streamSegmentReader = function(stream, offset, len) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.StreamSegmentReader', 'ctor'); - if (!stream) this._throwError('You must pass a non-null stream', 'JSIO.StreamSegmentReader', 'ctor'); - - if (!(offset >= 1)) offset = 0; - if (!(len >= 1)) len = 0; - - this.stream = stream; - this.array = null; - if (stream.array) { - var end = len ? offset + len : null; - if (stream.array.subarray) this.array = stream.array.subarray(offset, end); - else if (stream.array.slice) this.array = stream.array.slice(offset, end); - } - this.length = this.array ? this.array.length : (stream.length ? stream.length - offset : null); - this.offset = offset; - this.limit = len; - this.position = 0; - this._typeName = 'JSIO.StreamSegmentReader'; - this._version = version; - - if (this.array) { - this.readByte = _arrayReader.prototype.readByte; - this.readByteAt = _arrayReader.prototype.readByteAt; - } - return this; - }; - - _streamSegmentReader.prototype = new JSIO._ByteReaderBase(); - - _streamSegmentReader.prototype.readByte = function() { - if (this.limit && this.position >= this.limit) return null; // EOF - this.position++; - return this.stream.readByteAt(this.offset + this.position - 1); - }; - _streamSegmentReader.prototype.readByteAt = function(i) { - if (this.limit && i >= this.limit) return null; // EOF - return this.stream.readByteAt(this.offset + i); - }; - - // ======================================================= - - JSIO.ArrayReader = _arrayReader; - JSIO.StreamReader = _streamSegmentReader; - JSIO.StreamSegmentReader = _streamSegmentReader; + var version = "2.0 2012Feb"; + + if (typeof JSIO !== "object") { JSIO = {}; } + if ((typeof JSIO.version !== "string")) { + JSIO.version = version; + } + else if ((JSIO.version.length < 3) || + (JSIO.version.substring(0,3) !== "2.0")) { + JSIO.version += " " + version; + } + + // ======================================================= + // the base object, used as the prototype of all ByteReader objects. + var _byteReaderBase = function () { + this.position = 0; + // position must be incremented in .readByte() for all derived classes + }; + + _byteReaderBase.prototype._throwError = JSIO.throwError; + + _byteReaderBase.prototype._limitCheck = function(len, startPos) { + var LOE = { + len: len, + pos: startPos, + end: startPos+len + }; + + if (len === 0) return {len:0, pos:0, end:0}; + if (len < 0) this._throwError("Invalid read length"); + if (!this.length) return {len:len, pos:this.position, end:len+this.position}; + if (!startPos >= 0) LOE.pos = this.position; + if (this.length <= LOE.pos) this._throwError("EOF reached"); + + LOE.end = LOE.pos+len; + if (this.length < LOE.end) LOE.end = LOE.pos+(LOE.len = this.length-this.position); + return LOE; + } + + JSIO.SeekOrigin = { + Begin : 0, + Current : 1, + End : 2, + SEEK_SET : 0, + SEEK_CUR : 1, + SEEK_END : 2 + }; + + _byteReaderBase.prototype.seek = function(offset, origin) { + switch (origin) { + case JSIO.SeekOrigin.Begin: + if (offset == this.position) return this.position; + if (!this.length) { + if (offset < this.position) this._throwError('Uni-directional stream cannot seek backwards', null, 'seek'); + else if (offset > this.position) return this.read(offset - this.position); // read will limit check + } + else { + if (this.length < offset) this._throwError('Cannot seek past reader length', null, 'seek'); + this.position = offset; + } + break; + case JSIO.SeekOrigin.Current: + return this.seek(this.position + offset, JSIO.SeekOrigin.Begin); + break; + case JSIO.SeekOrigin.End: + if (!this.length) this._throwError('Uni-directional stream has no known end length for seek', null, 'seek'); + return this.seek(this.length - 1 + offset, JSIO.SeekOrigin.Begin); + break; + default: + this._throwError('Invalid seek method', null, 'seek'); + break; + } + + return this.position; + }; + + _byteReaderBase.prototype.read = function(len, startPos) { + var LOE = this._limitCheck(len, startPos); + if (LOE.len === 0) return []; + if (LOE.pos != this.position) this.seek(LOE.pos, JSIO.SeekOrigin.Begin); + + var bytesRead = []; + + // Faster methods with an array or stream + if (this.array && this.array.subarray) bytesRead = this.array.subarray(LOE.pos, LOE.end); + else if (this.array && this.array.slice) bytesRead = this.array.slice(LOE.pos, LOE.end); + else if (this.stream) bytesRead = this.stream.read(LOE.len, LOE.pos); + else if (this.length) { // Random-access stream + for(var i=LOE.pos; i<LOE.end; i++) { bytesRead.push(this.readByteAt(i)); } + } + else { // Uni-directional stream + for(var i=LOE.pos; i<LOE.end; i++) { + var b = this.readByte(); + if (b === null || b === undefined) break; + bytesRead.push(b); + } + } + this.position = LOE.end; + return bytesRead; + }; + + _byteReaderBase.prototype.beginRead = function(len, startPos, callback) { + var LOE = this._limitCheck(len, startPos); + if (LOE.len === 0) return setTimeout(function() { callback([]); }, 1); + if (LOE.pos != this.position) this.seek(LOE.pos, JSIO.SeekOrigin.Begin); + + var bytesRead = []; + var thisReader = this; + var leftToRead = LOE.len; + + var readBatchAsync = function() { + var c = 0; + var pos = thisReader.position; + + // read a 32k batch + var l = (leftToRead >= 32768) ? 32768 : leftToRead; + var newBytes = thisReader.read(l); + JSIO.massApply(bytesRead.push, bytesRead, newBytes); + c += l; + leftToRead -= l; + if (newBytes.length < l) leftToRead = 0; + + if (leftToRead>0) setTimeout(readBatchAsync, 1); + else callback(bytesRead); + }; + + // kickoff + setTimeout(readBatchAsync, 1); // always async, in ALL situations + return null; + }; + + _byteReaderBase.prototype.readToEnd = function() { + if (this.array && this.array.subarray) return this.array.subarray(this.position); + else if (this.array && this.array.slice) return this.array.slice(this.position); + else if (this.length) return this.read(this.length - this.position); + else return this.read(9000 * 9000); // over 9000 + }; + + _byteReaderBase.prototype.beginReadToEnd = function(callback) { + if (this.array && this.array.subarray) setTimeout(function() { callback( this.array.subarray(this.position) ); }, 1); + else if (this.array && this.array.slice) setTimeout(function() { callback( this.array.slice(this.position) ); }, 1); + else if (this.length) return this.beginRead(this.length - this.position, this.position, callback); + else return this.beginRead(9000 * 9000, this.position, callback); + }; + + // Generic routines; one of these two MUST be overloaded (preferrably both) + _byteReaderBase.prototype.readByte = function(){ + if (this.length && this.position >= this.length) return null; // EOF + + var oneByte; + if (this.array) oneByte = this.array[this.position++]; + else if (this.length) oneByte = this.readByteAt(this.position++); + else if (this.stream) oneByte = this.stream.read(1)[0]; + else oneByte = this.read(1)[0]; + return (oneByte === null || oneByte === undefined) ? null : oneByte; + }; + _byteReaderBase.prototype.readByteAt = function(i) { + var pos = this.position; // no position changes on this one + if (i === null || i === undefined) i = this.position; + + var oneByte; + if (this.array) oneByte = this.array[i]; + else if (i === pos) oneByte = this.readByte(); + else if (this.stream) oneByte = this.stream.read(1, i)[0]; + else oneByte = this.read(1, i)[0]; + + this.position = pos; + return (oneByte === null || oneByte === undefined) ? null : oneByte; + } + + _byteReaderBase.prototype.readBytes = _byteReaderBase.prototype.read; + _byteReaderBase.prototype.beginReadBytes = function(len, callback) { return this.beginRead(len, this.position, callback); }; + + _byteReaderBase.prototype.readNumber = function(len, startPos){ + var LOE = this._limitCheck(len, startPos); + if (LOE.len === 0) LOE.len = 1; + if (LOE.pos != this.position) this.seek(LOE.pos, JSIO.SeekOrigin.Begin); + + var result = 0; + var bytes = this.read(LOE.len, LOE.pos); + for (var i=bytes.length-1; i>=0; i--) { + // IE only supports 32-bit integer shifting + //result = result << 8 | bytes[i]; + result = result*256 + bytes[i]; + } + return result; + }; + + _byteReaderBase.prototype.readString = function(len, startPos){ + var LOE = this._limitCheck(len, startPos); + if (LOE.len === 0) return ''; + if (LOE.pos != this.position) this.seek(LOE.pos, JSIO.SeekOrigin.Begin); + + var result = ''; + var bytes = this.read(LOE.len, LOE.pos); + for(var i=0; i<bytes.length; i++){ + result += String.fromCharCode(bytes[i]); + } + return result; + }; + + _byteReaderBase.prototype.readNullTerminatedString = function(startPos){ + var pos = startPos || this.position; + if (this.length && this.length < pos) this._throwError('EOF reached', null, 'readNullTerminatedString'); + if (pos != this.position) this.seek(pos, JSIO.SeekOrigin.Begin); + + var slarge = ""; + var s = ""; + var c = 0; + + // Faster method with an array + if (this.array && this.array.indexOf) { + var len = pos - this.array.indexOf(0, pos); + if (len > 0) return this.readString(len, pos); + } + + var ch; + while(1) { + ch = String.fromCharCode(this.readByteAt(pos+c)); + if (ch === null) break; + + s += ch; + c++; + if(c >= 32768) { + slarge += s; + s = ""; + pos += c; + this.position += c; + c = 0; + } + }; + this.position = pos + c; + return slarge + s; + }; + + _byteReaderBase.prototype.beginReadNullTerminatedString = function(callback, startPos){ + var pos = startPos || this.position; + if (this.length && this.length < pos) this._throwError('EOF reached', null, 'beginReadNullTerminatedString'); + + var slarge = ""; + var s = ""; + var thisBinStream = this; + + var readBatchAsync = function() { + var c = 0; + + var ch; + while(1) { + ch = String.fromCharCode(this.readByteAt(pos+c)); + if (ch === null) break; + + s += ch; + c++; + if(c >= 32768) { + slarge += s; + s = ""; + pos += c; + this.position += c; + c = 0; + } + }; + + thisBinStream.position = pos + c; + if (ch!==null) setTimeout(readBatchAsync, 1); + else callback(slarge+s); + }; + + // Faster method with an array + if (this.array && this.array.indexOf) { + var len = pos - this.array.indexOf(0, pos); + if (len > 0) readBatchASync = function() { callback(thisBinStream.readString(len, pos)); }; + } + + // kickoff + setTimeout(readBatchAsync, 1); // always async, in ALL situations + return null; + }; + + + + JSIO._ByteReaderBase = _byteReaderBase; + // ======================================================= + + + + + // ======================================================= + // reads from an array of bytes. + // This basically wraps a readByte() fn onto array access. + var _arrayReader = function(array) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.ArrayReader', 'ctor'); + this.position = 0; + this.array = array; + this.length = array.length; + this._typename = "JSIO.ArrayReader"; + this._version = version; + return this; + }; + + _arrayReader.prototype = new JSIO._ByteReaderBase(); + + _arrayReader.prototype.readByte = function() { + if (this.position >= this.array.length) return null; // EOF + return this.array[this.position++]; + }; + _arrayReader.prototype.readByteAt = function(i) { + return this.array[i]; + }; + + // ======================================================= + + + // ======================================================= + // reads bytes at a time from a defined segment of a stream. + var _streamSegmentReader = function(stream, offset, len) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.StreamSegmentReader', 'ctor'); + if (!stream) this._throwError('You must pass a non-null stream', 'JSIO.StreamSegmentReader', 'ctor'); + + if (!(offset >= 1)) offset = 0; + if (!(len >= 1)) len = 0; + + this.stream = stream; + this.array = null; + if (stream.array) { + var end = len ? offset + len : null; + if (stream.array.subarray) this.array = stream.array.subarray(offset, end); + else if (stream.array.slice) this.array = stream.array.slice(offset, end); + } + this.length = this.array ? this.array.length : (stream.length ? stream.length - offset : null); + this.offset = offset; + this.limit = len; + this.position = 0; + this._typeName = 'JSIO.StreamSegmentReader'; + this._version = version; + + if (this.array) { + this.readByte = _arrayReader.prototype.readByte; + this.readByteAt = _arrayReader.prototype.readByteAt; + } + return this; + }; + + _streamSegmentReader.prototype = new JSIO._ByteReaderBase(); + + _streamSegmentReader.prototype.readByte = function() { + if (this.limit && this.position >= this.limit) return null; // EOF + this.position++; + return this.stream.readByteAt(this.offset + this.position - 1); + }; + _streamSegmentReader.prototype.readByteAt = function(i) { + if (this.limit && i >= this.limit) return null; // EOF + return this.stream.readByteAt(this.offset + i); + }; + + // ======================================================= + + JSIO.ArrayReader = _arrayReader; + JSIO.StreamReader = _streamSegmentReader; + JSIO.StreamSegmentReader = _streamSegmentReader; })(); @@ -574,195 +574,195 @@ // This work is licensed under the GPLv3. (function(){ - var version = "2.0 2012Feb"; - var typename = "JSIO.BinaryUrlStream"; - - if ((typeof JSIO !== "object") || - (typeof JSIO.version !== "string") || - (JSIO.version.length < 3) || - (JSIO.version.substring(0,3) !== "2.0")) - JSIO.throwError('This extension requires JSIO.core.js v2.0', typename); - - if (typeof JSIO._ByteReaderBase !== "function") - JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); - - if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { - var IEBinaryToArray_ByteStr_Script = - "<!-- IEBinaryToArray_ByteStr -->\r\n"+ - "<script type='text/vbscript'>\r\n"+ - "Function IEBinaryToArray_ByteStr(Binary)\r\n"+ - " IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+ - "End Function\r\n"+ - "Function IEBinaryToArray_ByteAsc_Last(Binary)\r\n"+ - " Dim lastIndex\r\n"+ - " lastIndex = LenB(Binary)\r\n"+ - " if lastIndex mod 2 Then\r\n"+ - " IEBinaryToArray_ByteAsc_Last = AscB( MidB( Binary, lastIndex, 1 ) )\r\n"+ - " Else\r\n"+ - " IEBinaryToArray_ByteAsc_Last = -1\r\n"+ - " End If\r\n"+ - "End Function\r\n"+ - "</script>\r\n"; - - // inject VBScript - document.write(IEBinaryToArray_ByteStr_Script); - } - - JSIO.IEByteMapping = null; - - var bus = function(url, callback) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.BinaryUrlStream', 'ctor'); - - this.callback = callback; - this.position = 0; - this.length = null; - this.readByte = JSIO.ArrayReader.prototype.readByte; - this.readByteAt = JSIO.ArrayReader.prototype.readByteAt; - this.req = null; - this._typename = typename; - this._version = version; - this.status = "-none-"; - - var _IeGetBinResource = function(fileURL){ - var binStream = this; - // http://stackoverflow.com/questions/1919972/how-do-i-access-xhr-responsebody-for-binary-data-from-javascript-in-ie - - // my helper to convert from responseBody to a byte array - var convertResponseBodyToArray = function (binary) { - var byteArray = new Array; - - try { - // very fast; very little work involved - byteArray = new VBArray(binary).toArray(); - } - catch(err) { - // use the BinaryToArray VBScript - if (!JSIO.IEByteMapping) { - JSIO.IEByteMapping = {}; - for ( var i = 0; i < 256; i++ ) { - for ( var j = 0; j < 256; j++ ) { - JSIO.IEByteMapping[ String.fromCharCode( i + j * 256 ) ] = [ i, j ]; - } - } - } - var rawBytes = IEBinaryToArray_ByteStr(binary); - var lastAsc = IEBinaryToArray_ByteAsc_Last(binary); - - for ( var i = 0; i < rawBytes.length; i++ ) { - byteArray.push.apply(byteArray, JSIO.IEByteMapping[ rawBytes.substr(i,1) ]); - } - if (lastAsc >= 0) byteArray.push(lastAsc); - } - - return byteArray; - }; - - this.req = (function() { - if (window.XMLHttpRequest) return new window.XMLHttpRequest(); - else if (window.ActiveXObject) { - // the many versions of IE's XML fetchers - var AXOs = [ - 'MSXML2.XMLHTTP.6.0', - 'MSXML2.XMLHTTP.5.0', - 'MSXML2.XMLHTTP.4.0', - 'MSXML2.XMLHTTP.3.0', - 'MSXML2.XMLHTTP', - 'Microsoft.XMLHTTP', - 'MSXML.XMLHTTP' - ]; - for (var i = 0; i < AXOs.length; i++) { - try { return new ActiveXObject(AXOs[i]); } - catch(e) { continue; } - } - } - return null; - })(); - this.req.open("GET", fileURL, true); - this.req.setRequestHeader("Accept-Charset", "x-user-defined"); - this.req.onreadystatechange = function(event){ - if (binStream.req.readyState == 4) { - binStream.status = "Status: " + binStream.req.status + ' ' + binStream.req.statusText; - if (binStream.req.status == 200) { - binStream.array = convertResponseBodyToArray(binStream.req.responseBody); - binStream.length = binStream.array.length; - if (binStream.length < 0) this._throwError('Failed to load "'+ fileURL + '" after converting'); - - if (typeof binStream.callback == "function") binStream.callback(binStream); - } - else { - binStream._throwError('Failed to load "'+ fileURL + '": HTTP ' + binStream.status); - } - } - }; - this.req.send(); - }; - - var _NormalGetBinResource = function(fileURL){ - var binStream= this; - this.req = new XMLHttpRequest(); - this.req.open('GET', fileURL, true); - this.req.onreadystatechange = function(aEvt) { - if (binStream.req.readyState == 4) { - binStream.status = "Status: " + binStream.req.status + ' ' + binStream.req.statusText; - if(binStream.req.status == 200){ - var fileContents = binStream.req.responseText; - binStream.length = fileContents.byteLength; - binStream.array = fileContents.split(''); - for ( var i = 0; i < binStream.array.length; i++ ) { - binStream.array[i] = binStream.array[i].charCodeAt(0) & 0xff; - } - - if (typeof binStream.callback == "function") binStream.callback(binStream); - } - else { - binStream._throwError('Failed to load "'+ fileURL + '": HTTP ' + binStream.status); - } - } - }; - //XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com] - this.req.overrideMimeType('text/plain; charset=x-user-defined'); - this.req.send(null); - }; - - // http://stackoverflow.com/questions/327685/is-there-a-way-to-read-binary-data-into-javascript - var _ArrayBufferGetBinResource = function(fileURL){ - var binStream= this; - this.req = new XMLHttpRequest(); - this.req.open('GET', fileURL, true); - this.req.onreadystatechange = function(aEvt) { - if (binStream.req.readyState == 4) { - binStream.status = "Status: " + binStream.req.status + ' ' + binStream.req.statusText; - if(binStream.req.status == 200){ - var fileContents = binStream.req.response; - binStream.length = fileContents.byteLength; - binStream.array = new Uint8Array(fileContents); - - if (typeof binStream.callback == "function") binStream.callback(binStream); - } - else { - binStream._throwError('Failed to load "'+ fileURL + '": HTTP ' + binStream.status); - } - } - }; - this.req.responseType = 'arraybuffer'; - this.req.overrideMimeType('text/plain; charset=x-user-defined'); - this.req.send(null); - }; - - - if (typeof ArrayBuffer !== 'undefined') _ArrayBufferGetBinResource.apply(this, [url]); - else if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) _IeGetBinResource.apply(this, [url]); - else _NormalGetBinResource.apply(this, [url]); - }; - - bus.prototype = new JSIO._ByteReaderBase(); - - bus.prototype.readByte = function(){ - var byte = this.readByteAt(this.position++); - return (byte === null || byte === undefined) ? null : byte; - }; - - JSIO.BinaryUrlStream = bus; + var version = "2.0 2012Feb"; + var typename = "JSIO.BinaryUrlStream"; + + if ((typeof JSIO !== "object") || + (typeof JSIO.version !== "string") || + (JSIO.version.length < 3) || + (JSIO.version.substring(0,3) !== "2.0")) + JSIO.throwError('This extension requires JSIO.core.js v2.0', typename); + + if (typeof JSIO._ByteReaderBase !== "function") + JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); + + if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { + var IEBinaryToArray_ByteStr_Script = + "<!-- IEBinaryToArray_ByteStr -->\r\n"+ + "<script type='text/vbscript'>\r\n"+ + "Function IEBinaryToArray_ByteStr(Binary)\r\n"+ + " IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+ + "End Function\r\n"+ + "Function IEBinaryToArray_ByteAsc_Last(Binary)\r\n"+ + " Dim lastIndex\r\n"+ + " lastIndex = LenB(Binary)\r\n"+ + " if lastIndex mod 2 Then\r\n"+ + " IEBinaryToArray_ByteAsc_Last = AscB( MidB( Binary, lastIndex, 1 ) )\r\n"+ + " Else\r\n"+ + " IEBinaryToArray_ByteAsc_Last = -1\r\n"+ + " End If\r\n"+ + "End Function\r\n"+ + "</script>\r\n"; + + // inject VBScript + document.write(IEBinaryToArray_ByteStr_Script); + } + + JSIO.IEByteMapping = null; + + var bus = function(url, callback) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.BinaryUrlStream', 'ctor'); + + this.callback = callback; + this.position = 0; + this.length = null; + this.readByte = JSIO.ArrayReader.prototype.readByte; + this.readByteAt = JSIO.ArrayReader.prototype.readByteAt; + this.req = null; + this._typename = typename; + this._version = version; + this.status = "-none-"; + + var _IeGetBinResource = function(fileURL){ + var binStream = this; + // http://stackoverflow.com/questions/1919972/how-do-i-access-xhr-responsebody-for-binary-data-from-javascript-in-ie + + // my helper to convert from responseBody to a byte array + var convertResponseBodyToArray = function (binary) { + var byteArray = new Array; + + try { + // very fast; very little work involved + byteArray = new VBArray(binary).toArray(); + } + catch(err) { + // use the BinaryToArray VBScript + if (!JSIO.IEByteMapping) { + JSIO.IEByteMapping = {}; + for ( var i = 0; i < 256; i++ ) { + for ( var j = 0; j < 256; j++ ) { + JSIO.IEByteMapping[ String.fromCharCode( i + j * 256 ) ] = [ i, j ]; + } + } + } + var rawBytes = IEBinaryToArray_ByteStr(binary); + var lastAsc = IEBinaryToArray_ByteAsc_Last(binary); + + for ( var i = 0; i < rawBytes.length; i++ ) { + byteArray.push.apply(byteArray, JSIO.IEByteMapping[ rawBytes.substr(i,1) ]); + } + if (lastAsc >= 0) byteArray.push(lastAsc); + } + + return byteArray; + }; + + this.req = (function() { + if (window.XMLHttpRequest) return new window.XMLHttpRequest(); + else if (window.ActiveXObject) { + // the many versions of IE's XML fetchers + var AXOs = [ + 'MSXML2.XMLHTTP.6.0', + 'MSXML2.XMLHTTP.5.0', + 'MSXML2.XMLHTTP.4.0', + 'MSXML2.XMLHTTP.3.0', + 'MSXML2.XMLHTTP', + 'Microsoft.XMLHTTP', + 'MSXML.XMLHTTP' + ]; + for (var i = 0; i < AXOs.length; i++) { + try { return new ActiveXObject(AXOs[i]); } + catch(e) { continue; } + } + } + return null; + })(); + this.req.open("GET", fileURL, true); + this.req.setRequestHeader("Accept-Charset", "x-user-defined"); + this.req.onreadystatechange = function(event){ + if (binStream.req.readyState == 4) { + binStream.status = "Status: " + binStream.req.status + ' ' + binStream.req.statusText; + if (binStream.req.status == 200) { + binStream.array = convertResponseBodyToArray(binStream.req.responseBody); + binStream.length = binStream.array.length; + if (binStream.length < 0) this._throwError('Failed to load "'+ fileURL + '" after converting'); + + if (typeof binStream.callback == "function") binStream.callback(binStream); + } + else { + binStream._throwError('Failed to load "'+ fileURL + '": HTTP ' + binStream.status); + } + } + }; + this.req.send(); + }; + + var _NormalGetBinResource = function(fileURL){ + var binStream= this; + this.req = new XMLHttpRequest(); + this.req.open('GET', fileURL, true); + this.req.onreadystatechange = function(aEvt) { + if (binStream.req.readyState == 4) { + binStream.status = "Status: " + binStream.req.status + ' ' + binStream.req.statusText; + if(binStream.req.status == 200){ + var fileContents = binStream.req.responseText; + binStream.length = fileContents.byteLength; + binStream.array = fileContents.split(''); + for ( var i = 0; i < binStream.array.length; i++ ) { + binStream.array[i] = binStream.array[i].charCodeAt(0) & 0xff; + } + + if (typeof binStream.callback == "function") binStream.callback(binStream); + } + else { + binStream._throwError('Failed to load "'+ fileURL + '": HTTP ' + binStream.status); + } + } + }; + //XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com] + if (!!this.req.overrideMimeType) this.req.overrideMimeType('text/plain; charset=x-user-defined'); + this.req.send(null); + }; + + // http://stackoverflow.com/questions/327685/is-there-a-way-to-read-binary-data-into-javascript + var _ArrayBufferGetBinResource = function(fileURL){ + var binStream= this; + this.req = new XMLHttpRequest(); + this.req.open('GET', fileURL, true); + this.req.onreadystatechange = function(aEvt) { + if (binStream.req.readyState == 4) { + binStream.status = "Status: " + binStream.req.status + ' ' + binStream.req.statusText; + if(binStream.req.status == 200){ + var fileContents = binStream.req.response; + binStream.length = fileContents.byteLength; + binStream.array = new Uint8Array(fileContents); + if (typeof binStream.callback == "function") binStream.callback(binStream); + } + else { + binStream._throwError('Failed to load "'+ fileURL + '": HTTP ' + binStream.status); + } + } + }; + this.req.responseType = 'arraybuffer'; + // http://stackoverflow.com/questions/11284728/how-do-i-access-8-bit-binary-data-from-javascript-in-opera + if (!!this.req.overrideMimeType) this.req.overrideMimeType('application/octet-stream; charset=x-user-defined'); + this.req.send(null); + }; + + + if (typeof ArrayBuffer !== 'undefined') _ArrayBufferGetBinResource.apply(this, [url]); + else if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) _IeGetBinResource.apply(this, [url]); + else _NormalGetBinResource.apply(this, [url]); + }; + + bus.prototype = new JSIO._ByteReaderBase(); + + bus.prototype.readByte = function(){ + var oneByte = this.readByteAt(this.position++); + return (oneByte === null || oneByte === undefined) ? null : oneByte; + }; + + JSIO.BinaryUrlStream = bus; })(); @@ -786,147 +786,147 @@ // This work is licensed under the GPLv3. (function(){ - var version = "2.0 2012Feb"; - var typename = "JSIO.TextDecoder"; - - if ((typeof JSIO !== "object") || - (typeof JSIO.version !== "string") || - (JSIO.version.length < 3) || - (JSIO.version.substring(0,3) !== "2.0")) - JSIO.throwError('This extension requires JSIO.core.js v2.0', typename); - - if (typeof JSIO._ByteReaderBase !== "function") - JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); - - var _ansi = function(reader) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.TextDecoder.ANSI', 'ctor'); - this.byteReader = reader; - this.charWidth = 1; - this._version = version; - this._typename = typename + ".ANSI"; - return this; - }; - - _ansi.prototype.readChar = function() { - var code = this.byteReader.readByte(); - return (code < 0) ? null : String.fromCharCode(code); - }; - - _ansi.prototype.parseChar = function(code) { - return (code < 0) ? null : String.fromCharCode(code); - }; - - var _utf16 = function(reader) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.TextDecoder.UTF16', 'ctor'); - this.byteReader = reader; - this.charWidth = 2; - this.bomState = 0; - this._version = version; - this._typename = typename + ".UTF16"; - return this; - }; - - _utf16.prototype.readChar = function() { - var b1 = this.byteReader.readByte(); - if (b1 < 0) return null; - var b2 = this.byteReader.readByte(); - if (b2 < 0) this._throwError('Incomplete UTF16 character', null, 'readChar'); - - if ((this.bomState === 0) && ((b1 + b2) == 509)) { - this.bomState = (b2 == 254) ? 1 : 2; - - b1 = this.byteReader.readByte(); - if (b1 < 0) return null; - b2 = this.byteReader.readByte(); - if (b2 < 0) this._throwError('Incomplete UTF16 character', null, 'readChar'); - } - else { - this.bomState = 1; - } - return this.parseChar(b1, b2); - }; - - _utf16.prototype.parseChar = function(b1, b2) { - return String.fromCharCode( this.bomState == 1 ? (b2 << 8 | b1) : (b1 << 8 | b2) ); - } - - /* RFC 3629 */ - var _utf8 = function(reader) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.TextDecoder.UTF8', 'ctor'); - this.byteReader = reader; - this.charWidth = null; - this.waitBom = true; - this.strict = false; - this.pendingChar = null; - this._version = version; - this._typename = typename + ".UTF8"; - return this; - }; - - _utf8.prototype.readChar = function() { - var ch = null; - do { - if (this.pendingChar !== null) { - ch = this.pendingChar; - this.pendingChar = null; - } - else { - var b1 = this.byteReader.readByte(); - if (b1 === null) return null; - - if ((b1 & 0x80) === 0) ch = String.fromCharCode(b1); - else { - var currentPrefix = 0xC0; - var ttlBytes = 0; - do { - var mask = currentPrefix >> 1 | 0x80; - if((b1 & mask) == currentPrefix) break; - currentPrefix = currentPrefix >> 1 | 0x80; - } while(++ttlBytes < 5); - - if (ttlBytes > 0) { - var code; - if (ttlBytes === 1) code = (b1 & 0x1F) << 6 | (this.byteReader.readByte() & 0x3F); - else { - code = code << 6*ttlBytes - var bytes = this.byteReader.read(ttlBytes); - for (var i = 0; i > ttlBytes; i++) { - var bi = bytes[i]; - if ((bi & 0xC0) != 0x80) this._throwError('Invalid sequence character', null, 'readChar'); - code = (code << 6) | (bi & 0x3F); - } - } - - if (code <= 0xFFFF) { - ch = (code == 0xFEFF && this.waitBom) ? null : String.fromCharCode(code); - } - else { - var v = code - 0x10000; - var w1 = 0xD800 | ((v >> 10) & 0x3FF); - var w2 = 0xDC00 | (v & 0x3FF); - this.pendingChar = String.fromCharCode(w2); - ch = String.fromCharCode(w1); - } - } - else { - // a byte higher than 0x80. - if (this.strict) this._throwError('Invalid character', null, 'readChar'); - // fall back to "super ascii" (eg IBM-437) - else ch = String.fromCharCode(b1); - } - } - } - this.waitBom = false; - } while(ch === null); - return ch; - }; - - JSIO.TextDecoder = { - Default : _ansi, - ANSI : _ansi, - UTF16 : _utf16, - UTF8 : _utf8 - }; + var version = "2.0 2012Feb"; + var typename = "JSIO.TextDecoder"; + + if ((typeof JSIO !== "object") || + (typeof JSIO.version !== "string") || + (JSIO.version.length < 3) || + (JSIO.version.substring(0,3) !== "2.0")) + JSIO.throwError('This extension requires JSIO.core.js v2.0', typename); + + if (typeof JSIO._ByteReaderBase !== "function") + JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); + + var _ansi = function(reader) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.TextDecoder.ANSI', 'ctor'); + this.byteReader = reader; + this.charWidth = 1; + this._version = version; + this._typename = typename + ".ANSI"; + return this; + }; + + _ansi.prototype.readChar = function() { + var code = this.byteReader.readByte(); + return (code < 0) ? null : String.fromCharCode(code); + }; + + _ansi.prototype.parseChar = function(code) { + return (code < 0) ? null : String.fromCharCode(code); + }; + + var _utf16 = function(reader) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.TextDecoder.UTF16', 'ctor'); + this.byteReader = reader; + this.charWidth = 2; + this.bomState = 0; + this._version = version; + this._typename = typename + ".UTF16"; + return this; + }; + + _utf16.prototype.readChar = function() { + var b1 = this.byteReader.readByte(); + if (b1 < 0) return null; + var b2 = this.byteReader.readByte(); + if (b2 < 0) this._throwError('Incomplete UTF16 character', null, 'readChar'); + + if ((this.bomState === 0) && ((b1 + b2) == 509)) { + this.bomState = (b2 == 254) ? 1 : 2; + + b1 = this.byteReader.readByte(); + if (b1 < 0) return null; + b2 = this.byteReader.readByte(); + if (b2 < 0) this._throwError('Incomplete UTF16 character', null, 'readChar'); + } + else { + this.bomState = 1; + } + return this.parseChar(b1, b2); + }; + + _utf16.prototype.parseChar = function(b1, b2) { + return String.fromCharCode( this.bomState == 1 ? (b2 << 8 | b1) : (b1 << 8 | b2) ); + } + + /* RFC 3629 */ + var _utf8 = function(reader) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.TextDecoder.UTF8', 'ctor'); + this.byteReader = reader; + this.charWidth = null; + this.waitBom = true; + this.strict = false; + this.pendingChar = null; + this._version = version; + this._typename = typename + ".UTF8"; + return this; + }; + + _utf8.prototype.readChar = function() { + var ch = null; + do { + if (this.pendingChar !== null) { + ch = this.pendingChar; + this.pendingChar = null; + } + else { + var b1 = this.byteReader.readByte(); + if (b1 === null) return null; + + if ((b1 & 0x80) === 0) ch = String.fromCharCode(b1); + else { + var currentPrefix = 0xC0; + var ttlBytes = 0; + do { + var mask = currentPrefix >> 1 | 0x80; + if((b1 & mask) == currentPrefix) break; + currentPrefix = currentPrefix >> 1 | 0x80; + } while(++ttlBytes < 5); + + if (ttlBytes > 0) { + var code; + if (ttlBytes === 1) code = (b1 & 0x1F) << 6 | (this.byteReader.readByte() & 0x3F); + else { + code = code << 6*ttlBytes + var bytes = this.byteReader.read(ttlBytes); + for (var i = 0; i > ttlBytes; i++) { + var bi = bytes[i]; + if ((bi & 0xC0) != 0x80) this._throwError('Invalid sequence character', null, 'readChar'); + code = (code << 6) | (bi & 0x3F); + } + } + + if (code <= 0xFFFF) { + ch = (code == 0xFEFF && this.waitBom) ? null : String.fromCharCode(code); + } + else { + var v = code - 0x10000; + var w1 = 0xD800 | ((v >> 10) & 0x3FF); + var w2 = 0xDC00 | (v & 0x3FF); + this.pendingChar = String.fromCharCode(w2); + ch = String.fromCharCode(w1); + } + } + else { + // a byte higher than 0x80. + if (this.strict) this._throwError('Invalid character', null, 'readChar'); + // fall back to "super ascii" (eg IBM-437) + else ch = String.fromCharCode(b1); + } + } + } + this.waitBom = false; + } while(ch === null); + return ch; + }; + + JSIO.TextDecoder = { + Default : _ansi, + ANSI : _ansi, + UTF16 : _utf16, + UTF8 : _utf8 + }; })(); @@ -962,122 +962,122 @@ (function(){ - var version = "2.0 2012Feb"; - var typename = "JSIO.TextReader"; - - if (typeof JSIO._ByteReaderBase !== "function") - JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); - - var tr = function(textDecoder) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', typename, 'ctor'); - this.decoder = textDecoder; - this._version = version; - this._typename = typename; - this.unreads = []; - }; - - // read one char - tr.prototype.readChar = function() { - return (this.unreads.length > 0) ? this.unreads.pop() : this.decoder.readChar(); - }; - - // read a length of data - tr.prototype.read = function(n) { - // ANSI makes this easy - if (this.decoder.charWidth === 1) return JSIO.massApply(String.fromCharCode, new String, this.decoder.byteReader.read(n), true); - - var s = ""; - for (vari=0; i<n; i++) { - var ch = this.readChar(); - if (ch !== null) s+= ch; - else break; - } - return s; - }; - - tr.prototype.unreadChar = function(ch) { - this.unreads.push(ch); - }; - - tr.prototype.readToEnd = function() { - // ANSI makes this easy - if (this.decoder.charWidth === 1) return JSIO.massApply(String.fromCharCode, new String, this.decoder.byteReader.readToEnd(n), true); - - var slarge = ""; - var s = ""; - var c = 0; - var ch = this.readChar(); - while(ch !== null) { - s += ch; - c++; - if(c >= 32768) { - slarge += s; - s = ""; - c = 0; - } - ch = this.readChar(); - } - return slarge + s; - }; - - tr.prototype.beginReadToEnd = function(callback) { - // ANSI makes this easy - if (this.decoder.charWidth === 1) { - this.decoder.byteReader.beginReadToEnd(function (bytes) { - callback( JSIO.massApply(String.fromCharCode, new String, bytes, true) ); - }); - return null; - } - - var slarge = ""; - var s = ""; - var txtrdr = this; - - var readBatchAsync = function() { - var c = 0; - var ch = txtrdr.readChar(); - while(ch !== null) { - s += ch;c++; - if(c >= 32768) { - slarge += s; - s = ""; - break; - } - ch = txtrdr.readChar(); - } - if (ch!==null){ - setTimeout(readBatchAsync, 1); - } - else { - callback(slarge+s); - } - }; - - // kickoff - setTimeout(readBatchAsync, 1); // always async, in ALL situations - return null; - }; - - tr.prototype.readLine = function() { - var s = ""; - var ch = this.readChar(); - if (ch === null) return null; - - while(ch != "\r" && ch != "\n") { - s += ch; - ch = this.readChar(); - if (ch === null) return s; - } - if(ch == "\r") { - ch = this.readChar(); - if(ch !== null && ch != "\n"){ - this.unreadChar(ch); - } - } - return s; - }; - - JSIO.TextReader = tr; + var version = "2.0 2012Feb"; + var typename = "JSIO.TextReader"; + + if (typeof JSIO._ByteReaderBase !== "function") + JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); + + var tr = function(textDecoder) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', typename, 'ctor'); + this.decoder = textDecoder; + this._version = version; + this._typename = typename; + this.unreads = []; + }; + + // read one char + tr.prototype.readChar = function() { + return (this.unreads.length > 0) ? this.unreads.pop() : this.decoder.readChar(); + }; + + // read a length of data + tr.prototype.read = function(n) { + // ANSI makes this easy + if (this.decoder.charWidth === 1) return JSIO.massApply(String.fromCharCode, new String, this.decoder.byteReader.read(n), true); + + var s = ""; + for (vari=0; i<n; i++) { + var ch = this.readChar(); + if (ch !== null) s+= ch; + else break; + } + return s; + }; + + tr.prototype.unreadChar = function(ch) { + this.unreads.push(ch); + }; + + tr.prototype.readToEnd = function() { + // ANSI makes this easy + if (this.decoder.charWidth === 1) return JSIO.massApply(String.fromCharCode, new String, this.decoder.byteReader.readToEnd(n), true); + + var slarge = ""; + var s = ""; + var c = 0; + var ch = this.readChar(); + while(ch !== null) { + s += ch; + c++; + if(c >= 32768) { + slarge += s; + s = ""; + c = 0; + } + ch = this.readChar(); + } + return slarge + s; + }; + + tr.prototype.beginReadToEnd = function(callback) { + // ANSI makes this easy + if (this.decoder.charWidth === 1) { + this.decoder.byteReader.beginReadToEnd(function (bytes) { + callback( JSIO.massApply(String.fromCharCode, new String, bytes, true) ); + }); + return null; + } + + var slarge = ""; + var s = ""; + var txtrdr = this; + + var readBatchAsync = function() { + var c = 0; + var ch = txtrdr.readChar(); + while(ch !== null) { + s += ch;c++; + if(c >= 32768) { + slarge += s; + s = ""; + break; + } + ch = txtrdr.readChar(); + } + if (ch!==null){ + setTimeout(readBatchAsync, 1); + } + else { + callback(slarge+s); + } + }; + + // kickoff + setTimeout(readBatchAsync, 1); // always async, in ALL situations + return null; + }; + + tr.prototype.readLine = function() { + var s = ""; + var ch = this.readChar(); + if (ch === null) return null; + + while(ch != "\r" && ch != "\n") { + s += ch; + ch = this.readChar(); + if (ch === null) return s; + } + if(ch == "\r") { + ch = this.readChar(); + if(ch !== null && ch != "\n"){ + this.unreadChar(ch); + } + } + return s; + }; + + JSIO.TextReader = tr; })(); @@ -1116,111 +1116,111 @@ // This work is licensed under the GPLv3. (function(){ - var version = "2.0 2012Feb"; - var typename = "JSIO.Crc32"; - - if (typeof JSIO._ByteReaderBase !== "function") - JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); - - JSIO.crc32Table = null; - JSIO.crc32Polynomial = 0xEDB88320; - - var crc32TableCalc = function () { - // do this once only, for all instances - if (JSIO.crc32Table) return; - JSIO.crc32Table = new Array(256); - for (var i = 0; i < 256; i++) { - var c=i; - for (var k = 0; k < 8; k++) { - if ((c & 1) == 1) c = JSIO.crc32Polynomial ^ (c>>>1); - else c >>>= 1; - } - JSIO.crc32Table[i] = c; - } - }; - - JSIO.computeCrc32 = function(str) { - crc32TableCalc(); // once - var c = 0xFFFFFFFF; - var sL = str.length; - if (typeof str == "object") { - for (var n1=0; n1<sL; n1++) { - c = JSIO.crc32Table[(c&0xff) ^ str[n1]] ^ (c>>>8); - } - } else { - for (var n2=0; n2<sL; n2++) { - c = JSIO.crc32Table[(c&0xff) ^ str.charCodeAt(n2)] ^ (c>>>8); - } - } - c ^= 0xFFFFFFFF; - if (c < 0) c += 0xFFFFFFFF+1; - return c; - }; - - // ======================================================= - var _crc32 = function() { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', typename, 'ctor'); - crc32TableCalc(); // once - this._typename = typename; - this._version = version; - this._runningCrc32 = 0xFFFFFFFF; - }; - - _crc32.prototype.slurpByte = function(b) { - var r = this._runningCrc32; - this._runningCrc32 = r>>>8 ^ JSIO.crc32Table[b ^ (r & 0x000000FF)]; - }; - - _crc32.prototype.result = function() { - var c = this._runningCrc32 ^ 0xFFFFFFFF; - if (c < 0) c += 0xFFFFFFFF+1; - return c; - }; - // ======================================================= - - - - var _crc32CalculatingReader = function(reader) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.Crc32Reader', 'ctor'); - this._byteReader = reader; - this._typename = "JSIO.Crc32Reader"; - this._version = version; - this._crc32 = new JSIO.Crc32(); - }; - - _crc32CalculatingReader.prototype = new JSIO._ByteReaderBase(); - - _crc32CalculatingReader.prototype.readByte = function() { - var b = this._byteReader.readByte(); - if (b !== null) this._crc32.slurpByte(b); - this.position++; - return b; - }; - - _crc32CalculatingReader.prototype.read = function(len) { - if (len === 0) return []; - var bytes = this._byteReader.read(len); - len = bytes.length; - - var tbl = JSIO.crc32Table; - var r = this._crc32._runningCrc32; - var t; - for (var i = 0; i < len; i++) { - t = tbl[ bytes[i] ^ (r & 0x000000FF) ]; - r = (r >>> 8) ^ t; - } - this._crc32._runningCrc32 = r; - - this.position += len; - return bytes; - } - - _crc32CalculatingReader.prototype.crc32 = function() { - return this._crc32.result(); - }; - - JSIO.Crc32 = _crc32; - JSIO.Crc32Reader = _crc32CalculatingReader; + var version = "2.0 2012Feb"; + var typename = "JSIO.Crc32"; + + if (typeof JSIO._ByteReaderBase !== "function") + JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); + + JSIO.crc32Table = null; + JSIO.crc32Polynomial = 0xEDB88320; + + var crc32TableCalc = function () { + // do this once only, for all instances + if (JSIO.crc32Table) return; + JSIO.crc32Table = new Array(256); + for (var i = 0; i < 256; i++) { + var c=i; + for (var k = 0; k < 8; k++) { + if ((c & 1) == 1) c = JSIO.crc32Polynomial ^ (c>>>1); + else c >>>= 1; + } + JSIO.crc32Table[i] = c; + } + }; + + JSIO.computeCrc32 = function(str) { + crc32TableCalc(); // once + var c = 0xFFFFFFFF; + var sL = str.length; + if (typeof str == "object") { + for (var n1=0; n1<sL; n1++) { + c = JSIO.crc32Table[(c&0xff) ^ str[n1]] ^ (c>>>8); + } + } else { + for (var n2=0; n2<sL; n2++) { + c = JSIO.crc32Table[(c&0xff) ^ str.charCodeAt(n2)] ^ (c>>>8); + } + } + c ^= 0xFFFFFFFF; + if (c < 0) c += 0xFFFFFFFF+1; + return c; + }; + + // ======================================================= + var _crc32 = function() { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', typename, 'ctor'); + crc32TableCalc(); // once + this._typename = typename; + this._version = version; + this._runningCrc32 = 0xFFFFFFFF; + }; + + _crc32.prototype.slurpByte = function(b) { + var r = this._runningCrc32; + this._runningCrc32 = r>>>8 ^ JSIO.crc32Table[b ^ (r & 0x000000FF)]; + }; + + _crc32.prototype.result = function() { + var c = this._runningCrc32 ^ 0xFFFFFFFF; + if (c < 0) c += 0xFFFFFFFF+1; + return c; + }; + // ======================================================= + + + + var _crc32CalculatingReader = function(reader) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', 'JSIO.Crc32Reader', 'ctor'); + this._byteReader = reader; + this._typename = "JSIO.Crc32Reader"; + this._version = version; + this._crc32 = new JSIO.Crc32(); + }; + + _crc32CalculatingReader.prototype = new JSIO._ByteReaderBase(); + + _crc32CalculatingReader.prototype.readByte = function() { + var b = this._byteReader.readByte(); + if (b !== null) this._crc32.slurpByte(b); + this.position++; + return b; + }; + + _crc32CalculatingReader.prototype.read = function(len) { + if (len === 0) return []; + var bytes = this._byteReader.read(len); + len = bytes.length; + + var tbl = JSIO.crc32Table; + var r = this._crc32._runningCrc32; + var t; + for (var i = 0; i < len; i++) { + t = tbl[ bytes[i] ^ (r & 0x000000FF) ]; + r = (r >>> 8) ^ t; + } + this._crc32._runningCrc32 = r; + + this.position += len; + return bytes; + } + + _crc32CalculatingReader.prototype.crc32 = function() { + return this._crc32.result(); + }; + + JSIO.Crc32 = _crc32; + JSIO.Crc32Reader = _crc32CalculatingReader; })(); @@ -1263,436 +1263,436 @@ (function(){ - var version = "2.0 2012Feb"; - var typename = "JSIO.InflatingReader"; - - if (typeof JSIO._ByteReaderBase !== "function") - JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); - - // ======================================================= - // _InternalBitReader is used internally in the InflatingReader class. - // - - JSIO.bitShiftTable = null; - - var bitShiftTableCalc = function () { - // do this once only, for all instances - if (JSIO.bitShiftTable) return; - - var bits = 8; - JSIO.bitShiftTable = { - LSB: new Array(bits), - MSB: new Array(bits) - } - for (var bp = 0; bp < bits; bp++) { - var lim = bits - bp; - JSIO.bitShiftTable.LSB[bp] = new Array(lim); - JSIO.bitShiftTable.MSB[bp] = new Array(lim); - - var maskLSB = 1 << bp; - var maskMSB = 1 << lim-1; - for (var len = 1; len <= lim; len++) { - JSIO.bitShiftTable.LSB[bp][len-1] = maskLSB; - JSIO.bitShiftTable.MSB[bp][len-1] = maskMSB; - maskLSB |= 1 << bp+len; - maskMSB |= 1 << lim-len-1; - } - } - }; - - var _InternalBitReader = function(reader) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', typename + '._InternalBitReader.ctor'); - this.bitsLength = 0; - this.bits = 0; - this.byteReader = reader; - this._typeName = typename + "._InternalBitReader"; - this._version = version; - bitShiftTableCalc(); - }; - - _InternalBitReader.prototype._throwError = JSIO.throwError; - - _InternalBitReader.prototype.readBit = function() { - if (this.bitsLength === 0) { - var nextByte = this.byteReader.readByte(); - if (nextByte === null) this._throwError('Unexpected end of stream', null, 'readBit'); - this.bits = nextByte; - this.bitsLength = 8; - } - - var bit = (this.bits & 1 << 8-this.bitsLength) !== 0; - this.bitsLength--; - return bit; - }; - - _InternalBitReader.prototype.align = function() { this.bitsLength = 0; }; - - _InternalBitReader.prototype.readBits = function(len, type) { - var data = 0; - type = type || 'LSB'; - var tbl = JSIO.bitShiftTable[type]; - var dl = 0; - while (len > 0) { - if (this.bitsLength === 0) { - var nextByte = this.byteReader.readByte(); - if (nextByte === null) this._throwError('Unexpected end of stream', null, 'read'+type); - this.bits = nextByte; - this.bitsLength = 8; - } - - var maskLen = (this.bitsLength >= len) ? len : this.bitsLength; - var bitsPos = 8-this.bitsLength; - data |= (this.bits & tbl[bitsPos][maskLen-1]) >>> bitsPos << dl; - - dl += maskLen; - len -= maskLen; - this.bitsLength -= maskLen; - }; - return data; - }; - - _InternalBitReader.prototype.readLSB = function(len) { return this.readBits(len, 'LSB'); } - _InternalBitReader.prototype.readMSB = function(len) { return this.readBits(len, 'MSB'); } - - // - // ======================================================= - - - /* inflating ByteReader - RFC 1951 */ - var _inflatingReader = function(reader) { - if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', typename, 'ctor'); - this._byteReader = reader; - this._bitReader = new _InternalBitReader(reader); - this._buffer = []; - this._bufferPosition = 0; - this._state = 0; - this._blockFinal = false; - this._typeName = typename; - this._version = version; - return this; - }; - - - // shared fns and variables - - var staticCodes = null; - var staticDistances = null; - - var clenMap = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; - - var buildCodes = function(lengths){ - var i=0; - var codes = new Array(lengths.length); - var maxBits = lengths[0]; - for (i=1; i<lengths.length; i++) { - if (maxBits < lengths[i]) maxBits = lengths[i]; - } - - var bitLengthsCount = new Array(maxBits + 1); - for (i=0; i<=maxBits; i++) bitLengthsCount[i]=0; - - for (i=0; i<lengths.length; i++) { - ++bitLengthsCount[lengths[i]]; - } - - var nextCode = new Array(maxBits + 1); - var code = 0; - bitLengthsCount[0] = 0; - for (var bits=1; bits<=maxBits; bits++) { - code = (code + bitLengthsCount[bits - 1]) << 1; - nextCode[bits] = code; - } - - for (i=0; i<codes.length; i++) { - var len = lengths[i]; - if (len !== 0) { - codes[i] = nextCode[len]; - nextCode[len]++; - } - } - return codes; - }; - - var buildTree = function(codes, lengths){ - var nonEmptyCodes = []; - for(var i=0; i<codes.length; ++i) { - if(lengths[i] > 0) { - var code = {}; - code.bits = codes[i]; - code.length = lengths[i]; - code.index = i; - nonEmptyCodes.push(code); - } - } - return buildTreeBranch(nonEmptyCodes, 0, 0); - }; - - - var buildTreeBranch = function(codes, prefix, prefixLength){ - if (codes.length === 0) return null; - - var zeros = []; - var ones = []; - var branch = {}; - branch.isLeaf = false; - for(var i=0; i<codes.length; ++i) { - if (codes[i].length == prefixLength && codes[i].bits == prefix) { - branch.isLeaf = true; - branch.index = codes[i].index; - break; - } - else { - var nextBit = ((codes[i].bits >> (codes[i].length - prefixLength - 1)) & 1) > 0; - if (nextBit) ones.push(codes[i]); - else zeros.push(codes[i]); - } - } - if(!branch.isLeaf) { - branch.zero = buildTreeBranch(zeros, (prefix << 1), prefixLength + 1); - branch.one = buildTreeBranch(ones, (prefix << 1) | 1, prefixLength + 1); - } - return branch; - }; - - - var encodedLengthStart = [3,4,5,6,7,8,9,10, - 11,13,15,17,19,23,27,31,35,43,51,59,67,83,99, - 115,131,163,195,227,258]; - - var encodedLengthAdditionalBits = [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,0]; - - var encodedDistanceStart = [1,2,3,4, 5,7,9, 13,17,25, 33,49,65, - 97,129,193,257,385,513,769,1025,1537,2049, - 3073,4097,6145,8193,12289,16385,24577]; - - var encodedDistanceAdditionalBits = [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]; - - - var readDynamicTrees = function(bitReader){ - var hlit = bitReader.readLSB(5) + 257; - var hdist = bitReader.readLSB(5) + 1; - var hclen = bitReader.readLSB(4) + 4; - var clen = new Array(19); - var i; - for (i=0; i<clen.length; i++) { clen[i] = 0; } - for (i=0; i<hclen; i++) { clen[clenMap[i]] = bitReader.readLSB(3); } - - var clenCodes = buildCodes(clen); - var clenTree = buildTree(clenCodes, clen); - - var lengthsSequence = []; - while(lengthsSequence.length < hlit + hdist) { - var p = clenTree; - while(!p.isLeaf) { p = bitReader.readBit() ? p.one : p.zero; } - - var code = p.index; - if (code <= 15) lengthsSequence.push(code); - else if (code == 16) { - // TODO: replace with faster repeat algorythm - var repeat = bitReader.readLSB(2) + 3; - for(var q=0; q<repeat; ++q){ - lengthsSequence.push(lengthsSequence[lengthsSequence.length - 1]); - } - } - else if (code == 17) { - var repeat1 = bitReader.readLSB(3) + 3; - for(var q1=0; q1<repeat1; ++q1) { - lengthsSequence.push(0); - } - } - else if (code == 18) { - var repeat2 = bitReader.readLSB(7) + 11; - for(var q2=0; q2<repeat2; ++q2){ - lengthsSequence.push(0); - } - } - } - - var codesLengths = lengthsSequence.slice(0, hlit); - var codes = buildCodes(codesLengths); - var distancesLengths = lengthsSequence.slice(hlit, hlit + hdist); - var distances = buildCodes(distancesLengths); - - return { - codesTree : buildTree(codes, codesLengths), - distancesTree : buildTree(distances, distancesLengths) - }; - }; - - - _inflatingReader.prototype = new JSIO._ByteReaderBase(); - - - // internal instance fns - _inflatingReader.prototype._decodeItem = function() { - if (this._state == 2) return null; // end-of-blocks - - var item; - if(this._state === 0) { - this._blockFinal = this._bitReader.readBit(); - var blockType = this._bitReader.readLSB(2); - switch(blockType) { - case 0: - this._bitReader.align(); - var len = this._bitReader.readLSB(16); // low-byte first, as opposed to readNumber's HBF - var nlen = this._bitReader.readLSB(16); - if ((len & ~nlen) != len) this._throwError('Invalid block type 0 length', null, '_decodeItem'); - - item = {}; - item.itemType = 0; - item.array = this._bitReader.byteReader.read(len); - if (item.array.length < len) this._throwError('Incomplete block', null, '_decodeItem'); - if (this._blockFinal) this._state = 2; - return item; - case 1: - this._codesTree = staticCodes; - this._distancesTree = staticDistances; - this._state = 1; - break; - case 2: - var dTrees = readDynamicTrees(this._bitReader); - this._codesTree = dTrees.codesTree; - this._distancesTree = dTrees.distancesTree; - this._state = 1; - break; - default: - this._throwError('Invalid block type ('+ blockType +')', null, '_decodeItem'); - } - } - - item = {}; - - var p = this._codesTree; - while (!p.isLeaf) { p = this._bitReader.readBit() ? p.one : p.zero; } - if(p.index < 256) { - item.itemType = 2; - item.symbol = p.index; - } else if(p.index > 256) { - var lengthCode = p.index; - if(lengthCode > 285) this._throwError('Invalid length code', null, '_decodeItem'); - - var length = encodedLengthStart[lengthCode - 257]; - if(encodedLengthAdditionalBits[lengthCode - 257] > 0) { - length += this._bitReader.readLSB(encodedLengthAdditionalBits[lengthCode - 257]); - } - - p = this._distancesTree; - while (!p.isLeaf) { p = this._bitReader.readBit() ? p.one : p.zero; } - - var distanceCode = p.index; - var distance = encodedDistanceStart[distanceCode]; - if (encodedDistanceAdditionalBits[distanceCode] > 0) - distance += this._bitReader.readLSB(encodedDistanceAdditionalBits[distanceCode]); - - item.itemType = 3; - item.distance = distance; - item.length = length; - } else { - item.itemType = 1; - this._state = this._blockFinal ? 2 : 0; // EOB - } - return item; - }; - - - - // public instance functions - - _inflatingReader.prototype.readByte = function() { - var byte = this.read(1)[0]; - return (byte === null || byte === undefined) ? null : byte; - }; - - _inflatingReader.prototype.read = function(len) { - var b = this._buffer; // (since we use this so much...) - - // Keep reading until we get to the right length - while (this._bufferPosition+len > b.length) { - var item = this._decodeItem(); - if (item === null) { // EOF - len = b.length - this._bufferPosition; - break; - } - switch(item.itemType) { - case 0: - JSIO.massApply(b.push, b, item.array); - break; - case 2: - b.push(item.symbol); - break; - case 3: - var j = b.length - item.distance; - if (item.distance >= item.length) - JSIO.massApply(b.push, b, b.slice(j, j+item.length)); - // sometimes DEFLATE tries some trickery with "look-ahead" compression - else { - // this is basically just a repetition of the same string, plus some possible cutoff - var count = parseInt(item.length / item.distance); - var repArr = b.slice(j); - // http://stackoverflow.com/questions/202605/repeat-string-javascript/5450113#5450113 - while (count > 0) { - if (count & 1) JSIO.massApply( b.push, b, repArr); - if (count >>= 1) JSIO.massApply(repArr.push, repArr, repArr); - } - // add any remaining cutoff - var r; - if (r = item.length % item.distance) - JSIO.massApply(b.push, b, b.slice(j, j+r)); - } - break; - } - } - var bytes = b.slice(this._bufferPosition, this._bufferPosition+len); - this._bufferPosition += len; - this.position += len; - - if (this._bufferPosition > 0xC000) { - var shift = b.length - 0x8000; - if (shift > this._bufferPosition) shift = this._bufferPosition; - b.splice(0, shift); - this._bufferPosition -= shift; - } - - return bytes; - }; - - // initialization routine - once per type - (function(){ - - var codes = new Array(288); - var codesLengths = new Array(288); - var i=0; - for ( i = 0; i <= 143; i++) { - codes[i] = 0x0030 + i; - codesLengths[i] = 8; - } - for ( i = 144; i <= 255; i++) { - codes[i] = 0x0190 + i - 144; - codesLengths[i] = 9; - } - for ( i = 256; i <= 279; i++) { - codes[i] = 0x0000 + i - 256; - codesLengths[i] = 7; - } - for ( i = 280; i <= 287; i++) { - codes[i] = 0x00C0 + i - 280; - codesLengths[i] = 8; - } - staticCodes = buildTree(codes, codesLengths); - - var distances = new Array(32); - var distancesLengths = new Array(32); - for ( i = 0; i <= 31; i++) { - distances[i] = i; - distancesLengths[i] = 5; - } - staticDistances = buildTree(distances, distancesLengths); - })(); - - - JSIO.InflatingReader = _inflatingReader; + var version = "2.0 2012Feb"; + var typename = "JSIO.InflatingReader"; + + if (typeof JSIO._ByteReaderBase !== "function") + JSIO.throwError('This extension requires JSIO.BasicByteReaders.js', typename); + + // ======================================================= + // _InternalBitReader is used internally in the InflatingReader class. + // + + JSIO.bitShiftTable = null; + + var bitShiftTableCalc = function () { + // do this once only, for all instances + if (JSIO.bitShiftTable) return; + + var bits = 8; + JSIO.bitShiftTable = { + LSB: new Array(bits), + MSB: new Array(bits) + } + for (var bp = 0; bp < bits; bp++) { + var lim = bits - bp; + JSIO.bitShiftTable.LSB[bp] = new Array(lim); + JSIO.bitShiftTable.MSB[bp] = new Array(lim); + + var maskLSB = 1 << bp; + var maskMSB = 1 << lim-1; + for (var len = 1; len <= lim; len++) { + JSIO.bitShiftTable.LSB[bp][len-1] = maskLSB; + JSIO.bitShiftTable.MSB[bp][len-1] = maskMSB; + maskLSB |= 1 << bp+len; + maskMSB |= 1 << lim-len-1; + } + } + }; + + var _InternalBitReader = function(reader) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', typename + '._InternalBitReader.ctor'); + this.bitsLength = 0; + this.bits = 0; + this.byteReader = reader; + this._typeName = typename + "._InternalBitReader"; + this._version = version; + bitShiftTableCalc(); + }; + + _InternalBitReader.prototype._throwError = JSIO.throwError; + + _InternalBitReader.prototype.readBit = function() { + if (this.bitsLength === 0) { + var nextByte = this.byteReader.readByte(); + if (nextByte === null) this._throwError('Unexpected end of stream', null, 'readBit'); + this.bits = nextByte; + this.bitsLength = 8; + } + + var bit = (this.bits & 1 << 8-this.bitsLength) !== 0; + this.bitsLength--; + return bit; + }; + + _InternalBitReader.prototype.align = function() { this.bitsLength = 0; }; + + _InternalBitReader.prototype.readBits = function(len, type) { + var data = 0; + type = type || 'LSB'; + var tbl = JSIO.bitShiftTable[type]; + var dl = 0; + while (len > 0) { + if (this.bitsLength === 0) { + var nextByte = this.byteReader.readByte(); + if (nextByte === null) this._throwError('Unexpected end of stream', null, 'read'+type); + this.bits = nextByte; + this.bitsLength = 8; + } + + var maskLen = (this.bitsLength >= len) ? len : this.bitsLength; + var bitsPos = 8-this.bitsLength; + data |= (this.bits & tbl[bitsPos][maskLen-1]) >>> bitsPos << dl; + + dl += maskLen; + len -= maskLen; + this.bitsLength -= maskLen; + }; + return data; + }; + + _InternalBitReader.prototype.readLSB = function(len) { return this.readBits(len, 'LSB'); } + _InternalBitReader.prototype.readMSB = function(len) { return this.readBits(len, 'MSB'); } + + // + // ======================================================= + + + /* inflating ByteReader - RFC 1951 */ + var _inflatingReader = function(reader) { + if (! (this instanceof arguments.callee) ) this._throwError('You must use new to instantiate this class', typename, 'ctor'); + this._byteReader = reader; + this._bitReader = new _InternalBitReader(reader); + this._buffer = []; + this._bufferPosition = 0; + this._state = 0; + this._blockFinal = false; + this._typeName = typename; + this._version = version; + return this; + }; + + + // shared fns and variables + + var staticCodes = null; + var staticDistances = null; + + var clenMap = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; + + var buildCodes = function(lengths){ + var i=0; + var codes = new Array(lengths.length); + var maxBits = lengths[0]; + for (i=1; i<lengths.length; i++) { + if (maxBits < lengths[i]) maxBits = lengths[i]; + } + + var bitLengthsCount = new Array(maxBits + 1); + for (i=0; i<=maxBits; i++) bitLengthsCount[i]=0; + + for (i=0; i<lengths.length; i++) { + ++bitLengthsCount[lengths[i]]; + } + + var nextCode = new Array(maxBits + 1); + var code = 0; + bitLengthsCount[0] = 0; + for (var bits=1; bits<=maxBits; bits++) { + code = (code + bitLengthsCount[bits - 1]) << 1; + nextCode[bits] = code; + } + + for (i=0; i<codes.length; i++) { + var len = lengths[i]; + if (len !== 0) { + codes[i] = nextCode[len]; + nextCode[len]++; + } + } + return codes; + }; + + var buildTree = function(codes, lengths){ + var nonEmptyCodes = []; + for(var i=0; i<codes.length; ++i) { + if(lengths[i] > 0) { + var code = {}; + code.bits = codes[i]; + code.length = lengths[i]; + code.index = i; + nonEmptyCodes.push(code); + } + } + return buildTreeBranch(nonEmptyCodes, 0, 0); + }; + + + var buildTreeBranch = function(codes, prefix, prefixLength){ + if (codes.length === 0) return null; + + var zeros = []; + var ones = []; + var branch = {}; + branch.isLeaf = false; + for(var i=0; i<codes.length; ++i) { + if (codes[i].length == prefixLength && codes[i].bits == prefix) { + branch.isLeaf = true; + branch.index = codes[i].index; + break; + } + else { + var nextBit = ((codes[i].bits >> (codes[i].length - prefixLength - 1)) & 1) > 0; + if (nextBit) ones.push(codes[i]); + else zeros.push(codes[i]); + } + } + if(!branch.isLeaf) { + branch.zero = buildTreeBranch(zeros, (prefix << 1), prefixLength + 1); + branch.one = buildTreeBranch(ones, (prefix << 1) | 1, prefixLength + 1); + } + return branch; + }; + + + var encodedLengthStart = [3,4,5,6,7,8,9,10, + 11,13,15,17,19,23,27,31,35,43,51,59,67,83,99, + 115,131,163,195,227,258]; + + var encodedLengthAdditionalBits = [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,0]; + + var encodedDistanceStart = [1,2,3,4, 5,7,9, 13,17,25, 33,49,65, + 97,129,193,257,385,513,769,1025,1537,2049, + 3073,4097,6145,8193,12289,16385,24577]; + + var encodedDistanceAdditionalBits = [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]; + + + var readDynamicTrees = function(bitReader){ + var hlit = bitReader.readLSB(5) + 257; + var hdist = bitReader.readLSB(5) + 1; + var hclen = bitReader.readLSB(4) + 4; + var clen = new Array(19); + var i; + for (i=0; i<clen.length; i++) { clen[i] = 0; } + for (i=0; i<hclen; i++) { clen[clenMap[i]] = bitReader.readLSB(3); } + + var clenCodes = buildCodes(clen); + var clenTree = buildTree(clenCodes, clen); + + var lengthsSequence = []; + while(lengthsSequence.length < hlit + hdist) { + var p = clenTree; + while(!p.isLeaf) { p = bitReader.readBit() ? p.one : p.zero; } + + var code = p.index; + if (code <= 15) lengthsSequence.push(code); + else if (code == 16) { + // TODO: replace with faster repeat algorythm + var repeat = bitReader.readLSB(2) + 3; + for(var q=0; q<repeat; ++q){ + lengthsSequence.push(lengthsSequence[lengthsSequence.length - 1]); + } + } + else if (code == 17) { + var repeat1 = bitReader.readLSB(3) + 3; + for(var q1=0; q1<repeat1; ++q1) { + lengthsSequence.push(0); + } + } + else if (code == 18) { + var repeat2 = bitReader.readLSB(7) + 11; + for(var q2=0; q2<repeat2; ++q2){ + lengthsSequence.push(0); + } + } + } + + var codesLengths = lengthsSequence.slice(0, hlit); + var codes = buildCodes(codesLengths); + var distancesLengths = lengthsSequence.slice(hlit, hlit + hdist); + var distances = buildCodes(distancesLengths); + + return { + codesTree : buildTree(codes, codesLengths), + distancesTree : buildTree(distances, distancesLengths) + }; + }; + + + _inflatingReader.prototype = new JSIO._ByteReaderBase(); + + + // internal instance fns + _inflatingReader.prototype._decodeItem = function() { + if (this._state == 2) return null; // end-of-blocks + + var item; + if(this._state === 0) { + this._blockFinal = this._bitReader.readBit(); + var blockType = this._bitReader.readLSB(2); + switch(blockType) { + case 0: + this._bitReader.align(); + var len = this._bitReader.readLSB(16); // low-byte first, as opposed to readNumber's HBF + var nlen = this._bitReader.readLSB(16); + if ((len & ~nlen) != len) this._throwError('Invalid block type 0 length', null, '_decodeItem'); + + item = {}; + item.itemType = 0; + item.array = this._bitReader.byteReader.read(len); + if (item.array.length < len) this._throwError('Incomplete block', null, '_decodeItem'); + if (this._blockFinal) this._state = 2; + return item; + case 1: + this._codesTree = staticCodes; + this._distancesTree = staticDistances; + this._state = 1; + break; + case 2: + var dTrees = readDynamicTrees(this._bitReader); + this._codesTree = dTrees.codesTree; + this._distancesTree = dTrees.distancesTree; + this._state = 1; + break; + default: + this._throwError('Invalid block type ('+ blockType +')', null, '_decodeItem'); + } + } + + item = {}; + + var p = this._codesTree; + while (!p.isLeaf) { p = this._bitReader.readBit() ? p.one : p.zero; } + if(p.index < 256) { + item.itemType = 2; + item.symbol = p.index; + } else if(p.index > 256) { + var lengthCode = p.index; + if(lengthCode > 285) this._throwError('Invalid length code', null, '_decodeItem'); + + var length = encodedLengthStart[lengthCode - 257]; + if(encodedLengthAdditionalBits[lengthCode - 257] > 0) { + length += this._bitReader.readLSB(encodedLengthAdditionalBits[lengthCode - 257]); + } + + p = this._distancesTree; + while (!p.isLeaf) { p = this._bitReader.readBit() ? p.one : p.zero; } + + var distanceCode = p.index; + var distance = encodedDistanceStart[distanceCode]; + if (encodedDistanceAdditionalBits[distanceCode] > 0) + distance += this._bitReader.readLSB(encodedDistanceAdditionalBits[distanceCode]); + + item.itemType = 3; + item.distance = distance; + item.length = length; + } else { + item.itemType = 1; + this._state = this._blockFinal ? 2 : 0; // EOB + } + return item; + }; + + + + // public instance functions + + _inflatingReader.prototype.readByte = function() { + var oneByte = this.read(1)[0]; + return (oneByte === null || oneByte === undefined) ? null : oneByte; + }; + + _inflatingReader.prototype.read = function(len) { + var b = this._buffer; // (since we use this so much...) + + // Keep reading until we get to the right length + while (this._bufferPosition+len > b.length) { + var item = this._decodeItem(); + if (item === null) { // EOF + len = b.length - this._bufferPosition; + break; + } + switch(item.itemType) { + case 0: + JSIO.massApply(b.push, b, item.array); + break; + case 2: + b.push(item.symbol); + break; + case 3: + var j = b.length - item.distance; + if (item.distance >= item.length) + JSIO.massApply(b.push, b, b.slice(j, j+item.length)); + // sometimes DEFLATE tries some trickery with "look-ahead" compression + else { + // this is basically just a repetition of the same string, plus some possible cutoff + var count = parseInt(item.length / item.distance); + var repArr = b.slice(j); + // http://stackoverflow.com/questions/202605/repeat-string-javascript/5450113#5450113 + while (count > 0) { + if (count & 1) JSIO.massApply( b.push, b, repArr); + if (count >>= 1) JSIO.massApply(repArr.push, repArr, repArr); + } + // add any remaining cutoff + var r; + if (r = item.length % item.distance) + JSIO.massApply(b.push, b, b.slice(j, j+r)); + } + break; + } + } + var bytes = b.slice(this._bufferPosition, this._bufferPosition+len); + this._bufferPosition += len; + this.position += len; + + if (this._bufferPosition > 0xC000) { + var shift = b.length - 0x8000; + if (shift > this._bufferPosition) shift = this._bufferPosition; + b.splice(0, shift); + this._bufferPosition -= shift; + } + + return bytes; + }; + + // initialization routine - once per type + (function(){ + + var codes = new Array(288); + var codesLengths = new Array(288); + var i=0; + for ( i = 0; i <= 143; i++) { + codes[i] = 0x0030 + i; + codesLengths[i] = 8; + } + for ( i = 144; i <= 255; i++) { + codes[i] = 0x0190 + i - 144; + codesLengths[i] = 9; + } + for ( i = 256; i <= 279; i++) { + codes[i] = 0x0000 + i - 256; + codesLengths[i] = 7; + } + for ( i = 280; i <= 287; i++) { + codes[i] = 0x00C0 + i - 280; + codesLengths[i] = 8; + } + staticCodes = buildTree(codes, codesLengths); + + var distances = new Array(32); + var distancesLengths = new Array(32); + for ( i = 0; i <= 31; i++) { + distances[i] = i; + distancesLengths[i] = 5; + } + staticDistances = buildTree(distances, distancesLengths); + })(); + + + JSIO.InflatingReader = _inflatingReader; })(); @@ -1713,460 +1713,537 @@ // This work is licensed under the GPLv3. (function(){ - var version = "2.0 2012Feb"; - var typename = "Zipfile"; - - if (typeof JSIO.BinaryUrlStream !== "function") JSIO.throwError('This extension requires JSIO.BinaryUrlStream.js v2.0', typename); - if (typeof JSIO.TextDecoder !== "object") JSIO.throwError('This extension requires JSIO.TextDecoder.js v2.0', typename); - if (typeof JSIO.TextReader !== "function") JSIO.throwError('This extension requires JSIO.TextReader.js v2.0', typename); - if (typeof JSIO.Crc32 !== "function") JSIO.throwError('This extension requires JSIO.Crc32.js v2.0', typename); - if (typeof JSIO.InflatingReader !== "function") JSIO.throwError('This extension requires JSIO.InflatingReader.js v2.0', typename); - - // ======================================================= - function ZipEntry(zip) { - this.zipfile = zip; - this._typename = "ZipEntry"; - this._version = version; - this._crcCalculator = null; - } - - ZipEntry.prototype._throwError = JSIO.throwError; - - // return byte array or string - ZipEntry.prototype.extract = function(callback, asString) { - this.contentType = JSIO.guessFileType(this.name); - asString = asString || ( this.contentType == JSIO.FileType.Text || - this.contentType == JSIO.FileType.XML); - var thisEntry = this; - - if (this.compressionMethod !== 0 && this.compressionMethod != 8) - this._throwError('Unsupported compression method: ' + this.compressionMethod, null, 'extract'); - - var reader = (asString) ? this.openTextReader(thisEntry.utf8 ? JSIO.TextDecoder.UTF8 : JSIO.TextDecoder.ANSI) : this.openBinaryReader(); - - // diagnostic purpose only; tag the reader with the entry name - reader.zipEntryName = thisEntry.name; - - if (typeof callback != "function") { - // synchronous - var result = reader.readToEnd(); - this.verifyCrc32(); - return result; - } - - // asynchronous - reader.beginReadToEnd(function(result){ - try { - thisEntry.verifyCrc32(); - callback(thisEntry, result); - } - catch (exc1) { - callback(thisEntry, exc1); - } - }); - return null; - }; - - - // open a ByteReader on the entry, which will read binary - // content from the compressed stream. - ZipEntry.prototype.openBinaryReader = function() { - var reader = - new JSIO.StreamSegmentReader(this.zipfile.binaryStream, - this.offset + this.lengthOfHeader, - this.compressedSize); - if (this.compressionMethod === 0) { - this._crcCalculator = new JSIO.Crc32Reader(reader); - } - else { - var inflator = new JSIO.InflatingReader(reader); - this._crcCalculator = new JSIO.Crc32Reader(inflator); - } - // Whether compressed or not, the source ByteReader in each case - // is wrapped in a second ByteReader object that calculates CRC - // as it reads. That way, after all reading is complete, the - // caller can check the calcuated CRC against the expected CRC. - return this._crcCalculator; - }; - - // open a TextReader on the entry, to read text from the - // compressed stream. - ZipEntry.prototype.openTextReader = function(decoderKind) { - var reader = this.openBinaryReader(); - decoderKind = decoderKind || JSIO.TextDecoder.UTF8; - var d = new decoderKind(reader); - var textReader = new JSIO.TextReader(d); - d._parent = textReader; // store a reference, for diagnostic purposes only - return textReader; - }; - - // verify the CRC on the entry. - // call this after all bytes have been read. - ZipEntry.prototype.verifyCrc32 = function() { - var computedCrc = this._crcCalculator.crc32(); - var rc = false; // CRC FAIL - if (this.crc32 != computedCrc) { - var msg = "WARNING: CRC check failed: " + - "entry(" + this.name + ") " + - "computed(" + JSIO.decimalToHexString(computedCrc,8) + ") " + - "expected(" + JSIO.decimalToHexString(this.crc32,8) + ") "; - this.zipfile.status.push(msg); - } else { - rc = true; // OK - if (this.zipfile.verbose>2) { - this.zipfile.status.push("INFO: CRC check ok: 0x" + - JSIO.decimalToHexString(this.crc32,8)); - } - } - return rc; - }; - - - // ctor - ZipFile = function(fileUrl, callback, verbosity) { - if (! (this instanceof arguments.callee) ) JSIO.throwError('You must use new to instantiate this class', typename, 'ctor'); - - this.verbose = verbosity || 0; - this.entries = []; - this.entryNames = []; - this.status = []; - this._version = version; - this._typename = "ZipFile"; - this._throwError = JSIO.throwError; - - var thisZipFile = this; - - // Could use a back-tracking reader for the central directory, but - // there's no point, since all the zip data is held in memory anyway. - - /* function ReadCentralDirectory(){ - var posn = thisZipFile.binaryStream.length - 64; - var maxSeekback = Math.Max(s.Length - 0x4000, 10); - var success = false; - var nTries = 0; - do - { - thisZipFile.binaryStream.Seek(posn, SeekOrigin.Begin); - var bytesRead = thisZipFile.binaryStream.findSignature(thisZipFile.Signatures.EndOfCentralDirectory); - if (bytesRead != -1) - success = true; - else - { - nTries++; - // increasingly larger - posn -= (32 * (nTries + 1) * nTries); - if (posn < 0) posn = 0; // BOF - } - } - while (!success && posn > maxSeekback); - if (!success) { - thisZipFile.status.push("cannot find End of Central Directory"); - return; - } - } */ - - - function DateFromPackedFormat(packed) { - if (packed == 0xFFFF || packed === 0) return new Date(1995, 0, 1, 0,0,0,0); - - var packedTime = packed & 0x0000ffff; - var packedDate = ((packed & 0xffff0000) >> 16); - - var year = 1980 + ((packedDate & 0xFE00) >> 9); - var month = ((packedDate & 0x01E0) >> 5) -1; - var day = packedDate & 0x001F; - - var hour = (packedTime & 0xF800) >> 11; - var minute = (packedTime & 0x07E0) >> 5; - var second = (packedTime & 0x001F) * 2; - - // Validation and error checking. - // This is not foolproof but will catch most errors. - - // I can't believe how many different ways applications - // can mess up a simple date format. - - if (second >= 60) { minute++; second = 0; } - if (minute >= 60) { hour++; minute = 0; } - if (hour >= 24) { day++; hour = 0; } - var success = false; - var d; - try { - d = new Date(year, month, day, hour, minute, second, 0); - success= true; - } - catch (exc1) { - if (year == 1980 && (month === 0 || day === 0)) { - try { - d = new Date(1980, 0, 1, hour, minute, second, 0); - success= true; - } - catch (exc2) { - try { - d = new Date(1980, 0, 1, 0, 0, 0, 0); - success= true; - } - catch (exc3) { } // how could this fail?? - } - } - else { - try { - if (year < 1980) year = 1980; - if (year > 2030) year = 2030; - if (month < 1) month = 1; - if (month > 12) month = 12; - if (day < 1) day = 1; - if (day > 31) day = 31; - if (minute < 0) minute = 0; - if (minute > 59) minute = 59; - if (second < 0) second = 0; - if (second > 59) second = 59; - d = new Date(year, month-1, day, hour, minute, second, 0); - success= true; - } - catch (exc4){} - } - } - if (!success) this._throwError('Bad date/time value in this ZIP file', null, 'DateFromPackedFormat'); - return d; - } - - - function ReadZipEntries () { - // read only once - if (thisZipFile.entryNames.length === 0){ - var e; - while ((e = ReadZipEntry()) !== null) { - thisZipFile.entries.push(e); - thisZipFile.entryNames.push(e.name); - } - } - } - - - function ReadZipEntry () { - var offset = thisZipFile.binaryStream.position; - var sig = thisZipFile.binaryStream.readNumber(4); - if (sig == ZipFile.Signatures.DirEntry) { - // after all entries, comes the central directory - if (thisZipFile.verbose > 0) { - thisZipFile.status.push("INFO: at offset 0x" + - JSIO.decimalToHexString(offset) + - ", found start of Zip Directory."); - } - // all done reading - return null; - } - if (sig != ZipFile.Signatures.Entry) { - thisZipFile.status.push("WARNING: at offset 0x" + - JSIO.decimalToHexString(offset) + - ", found unexpected signature: 0x" + - JSIO.decimalToHexString(sig)); - return null; - } - - var entry = new ZipEntry(thisZipFile); - entry.offset = offset; - entry.versionNeeded = thisZipFile.binaryStream.readNumber(2); - entry.bitField = thisZipFile.binaryStream.readNumber(2); - entry.compressionMethod = thisZipFile.binaryStream.readNumber(2); - var timeBlob = thisZipFile.binaryStream.readNumber(4); - entry.lastModified = DateFromPackedFormat(timeBlob); - entry.crc32 = thisZipFile.binaryStream.readNumber(4); - entry.compressedSize = thisZipFile.binaryStream.readNumber(4); - entry.uncompressedSize = thisZipFile.binaryStream.readNumber(4); - - if ((entry.bitField & 0x01) == 0x01){ - thisZipFile.status.push("This zipfile uses Encryption, which is not supported by ZipFile.js."); - return null; - } - - entry.utf8 = ((entry.bitField & 0x0800) == 0x0800); - - if ((entry.bitField & 0x0008) == 0x0008){ - thisZipFile.status.push("This zipfile uses a bit 3 trailing data descriptor, which is not supported by ZipFile.js."); - return null; - } - - if (entry.compressedSize == 0xFFFFFFFF || - entry.uncompressedSize == 0xFFFFFFFF) { - thisZipFile.status.push("This zipfile uses ZIP64, which is not supported by ZipFile.js"); - return null; - } - - var filenameLength = thisZipFile.binaryStream.readNumber(2); - var extraFieldLength = thisZipFile.binaryStream.readNumber(2); - - thisZipFile.status.push("INFO: filename length= " + filenameLength); - - // we've read 30 bytes of metadata so far - var bytesRead = 30 + filenameLength + extraFieldLength; - - if (entry.utf8) { - thisZipFile.status.push("INFO: before filename, position= 0x" + - JSIO.decimalToHexString( thisZipFile.binaryStream.position )); - var binReader = - new JSIO.StreamSegmentReader(thisZipFile.binaryStream, - thisZipFile.binaryStream.position, - filenameLength); - var utf8Decoder = new JSIO.TextDecoder.UTF8(binReader); - var textReader = new JSIO.TextReader(utf8Decoder); - entry.name = textReader.readToEnd(); - - // advance the filepointer: - thisZipFile.binaryStream.seek(filenameLength, - JSIO.SeekOrigin.Current, - thisZipFile); - - thisZipFile.status.push("INFO: after filename, position= 0x" + - JSIO.decimalToHexString( thisZipFile.binaryStream.position )); - } - else { - entry.name = thisZipFile.binaryStream.readString(filenameLength); - } - - // There are a bunch of things in the "extra" header, thisZipFile we - // could parse, like timestamps and other things. This class - // only identifies and separates them. - - // More info here: http://www.pkware.com/documents/casestudies/APPNOTE.TXT - - var extraPos = 0; - entry.extra = []; - while (extraPos < extraFieldLength) { - var extraBlock = { - type: thisZipFile.binaryStream.readNumber(2), - size: thisZipFile.binaryStream.readNumber(2) - }; - extraBlock.typeDescription = ZipFile.ExtraFieldTypes[extraBlock.type]; - extraBlock.data = thisZipFile.binaryStream.read(extraBlock.size); - entry.extra.push(extraBlock); - extraPos += 4 + extraBlock.size; - } - - if (thisZipFile.verbose > 1) { - thisZipFile.status.push("INFO: at offset 0x" + - JSIO.decimalToHexString(entry.offset) + - ", found entry '" + entry.name + "' fnl(" + - filenameLength + ") efl(" + - extraFieldLength +")"); - } - - if (extraFieldLength > 0) { - if (thisZipFile.verbose > 0) { - thisZipFile.status.push("INFO: entry " + entry.name + " has " + - extraFieldLength + " bytes of " + - "extra metadata (ID'd but ignored)"); - } - } - - entry.lengthOfHeader = bytesRead; - entry.totalEntrySize = entry.lengthOfHeader + entry.compressedSize; - - // seek past the data without reading it. We will read on Extract() - if (thisZipFile.verbose > 1) { - thisZipFile.status.push("INFO: seek 0x" + - JSIO.decimalToHexString(entry.compressedSize) + - " (" + entry.compressedSize + ") bytes"); - } - - thisZipFile.binaryStream.seek(entry.compressedSize, - JSIO.SeekOrigin.Current, - thisZipFile); - - return entry; - } - - - var parseZipFile = function(bfr){ - try { - if (bfr.req.status == 200) { - var sig = thisZipFile.binaryStream.readNumber(4); - if (sig != ZipFile.Signatures.Entry){ - thisZipFile.status.push("WARNING: this file does not appear to be a zip file"); - } else { - thisZipFile.binaryStream.seek(0, JSIO.SeekOrigin.Begin); - ReadZipEntries(); - if (thisZipFile.verbose > 0) { - thisZipFile.status.push("INFO: read " + thisZipFile.entries.length + " entries"); - } - } - } - else { - thisZipFile.status.push("ERROR: the URL could not be read (" + - bfr.req.status + " " + bfr.req.statusText + ")"); - } - callback(thisZipFile); - } - catch (exc1) - { - thisZipFile.status.push("Exception: " + exc1.message); - callback(thisZipFile); - } - }; - - this.binaryStream = new JSIO.BinaryUrlStream(fileUrl, parseZipFile); - - return this; - }; - - - ZipFile.Signatures = { - Entry : 0x04034b50, - EndOfCentralDirectory : 0x06054b50, - DirEntry : 0x02014b50 - }; - - ZipFile.Version = version; - - ZipFile.EncryptionAlgorithm = { - None : 0, - PkzipWeak : 1, - WinZipAes : 2 - }; - - ZipFile.ExtraFieldTypes = {}; - ZipFile.ExtraFieldTypes[0x0001] = 'Zip64 Extended Info'; - ZipFile.ExtraFieldTypes[0x0007] = 'AV Info'; - ZipFile.ExtraFieldTypes[0x0008] = 'Extended Language Encoding Data (PFS)'; - ZipFile.ExtraFieldTypes[0x0009] = 'OS/2'; - ZipFile.ExtraFieldTypes[0x000a] = 'NTFS '; - ZipFile.ExtraFieldTypes[0x000c] = 'OpenVMS'; - ZipFile.ExtraFieldTypes[0x000d] = 'UNIX'; - ZipFile.ExtraFieldTypes[0x000e] = 'File Stream and Fork Descriptors'; - ZipFile.ExtraFieldTypes[0x000f] = 'Patch Descriptor'; - ZipFile.ExtraFieldTypes[0x0014] = 'PKCS#7 Store for X.509 Certificates'; - ZipFile.ExtraFieldTypes[0x0015] = 'X.509 Certificate ID and Signature (Individual File)'; - ZipFile.ExtraFieldTypes[0x0016] = 'X.509 Certificate ID (Central Directory)'; - ZipFile.ExtraFieldTypes[0x0017] = 'Strong Encryption Header'; - ZipFile.ExtraFieldTypes[0x0018] = 'Record Management Controls'; - ZipFile.ExtraFieldTypes[0x0019] = 'PKCS#7 Encryption Recipient Certificate List'; - ZipFile.ExtraFieldTypes[0x0065] = 'IBM S/390 (Z390), AS/400 (I400) attributes (uncompressed)'; - ZipFile.ExtraFieldTypes[0x0066] = 'IBM S/390 (Z390), AS/400 (I400) attributes (compressed)'; - ZipFile.ExtraFieldTypes[0x4690] = 'POSZIP 4690 (reserved) '; - ZipFile.ExtraFieldTypes[0x07c8] = 'Macintosh'; - ZipFile.ExtraFieldTypes[0x2605] = 'ZipIt Macintosh'; - ZipFile.ExtraFieldTypes[0x2705] = 'ZipIt Macintosh 1.3.5+'; - ZipFile.ExtraFieldTypes[0x2805] = 'ZipIt Macintosh 1.3.5+'; - ZipFile.ExtraFieldTypes[0x334d] = 'Info-ZIP Macintosh'; - ZipFile.ExtraFieldTypes[0x4341] = 'Acorn/SparkFS '; - ZipFile.ExtraFieldTypes[0x4453] = 'Windows NT security descriptor (binary ACL)'; - ZipFile.ExtraFieldTypes[0x4704] = 'VM/CMS'; - ZipFile.ExtraFieldTypes[0x470f] = 'MVS'; - ZipFile.ExtraFieldTypes[0x4b46] = 'FWKCS MD5'; - ZipFile.ExtraFieldTypes[0x4c41] = 'OS/2 access control list (text ACL)'; - ZipFile.ExtraFieldTypes[0x4d49] = 'Info-ZIP OpenVMS'; - ZipFile.ExtraFieldTypes[0x4f4c] = 'Xceed original location extra field'; - ZipFile.ExtraFieldTypes[0x5356] = 'AOS/VS (ACL)'; - ZipFile.ExtraFieldTypes[0x5455] = 'extended timestamp'; - ZipFile.ExtraFieldTypes[0x554e] = 'Xceed unicode extra field'; - ZipFile.ExtraFieldTypes[0x5855] = 'Info-ZIP UNIX (original, also OS/2, NT, etc)'; - ZipFile.ExtraFieldTypes[0x6375] = 'Info-ZIP Unicode Comment Extra Field'; - ZipFile.ExtraFieldTypes[0x6542] = 'BeOS/BeBox'; - ZipFile.ExtraFieldTypes[0x7075] = 'Info-ZIP Unicode Path Extra Field'; - ZipFile.ExtraFieldTypes[0x756e] = 'ASi UNIX'; - ZipFile.ExtraFieldTypes[0x7855] = 'Info-ZIP UNIX (new)'; - ZipFile.ExtraFieldTypes[0xa220] = 'Microsoft Open Packaging Growth Hint'; - ZipFile.ExtraFieldTypes[0xfd4a] = 'SMS/QDOS'; + var version = "2.0 2012Feb"; + var typename = "Zipfile"; + + if (typeof JSIO.BinaryUrlStream !== "function") JSIO.throwError('This extension requires JSIO.BinaryUrlStream.js v2.0', typename); + if (typeof JSIO.TextDecoder !== "object") JSIO.throwError('This extension requires JSIO.TextDecoder.js v2.0', typename); + if (typeof JSIO.TextReader !== "function") JSIO.throwError('This extension requires JSIO.TextReader.js v2.0', typename); + if (typeof JSIO.Crc32 !== "function") JSIO.throwError('This extension requires JSIO.Crc32.js v2.0', typename); + if (typeof JSIO.InflatingReader !== "function") JSIO.throwError('This extension requires JSIO.InflatingReader.js v2.0', typename); + + // ======================================================= + function ZipEntry(zip) { + this.zipfile = zip; + this._typename = "ZipEntry"; + this._version = version; + this._crcCalculator = null; + } + + ZipEntry.prototype._throwError = JSIO.throwError; + + // return byte array or string + ZipEntry.prototype.extract = function(callback, asString) { + this.contentType = JSIO.guessFileType(this.name); + asString = asString || ( this.contentType == JSIO.FileType.Text || + this.contentType == JSIO.FileType.XML); + var thisEntry = this; + + if (this.compressionMethod !== 0 && this.compressionMethod != 8) + this._throwError('Unsupported compression method: ' + this.compressionMethod, null, 'extract'); + + var reader = (asString) ? this.openTextReader(thisEntry.utf8 ? JSIO.TextDecoder.UTF8 : JSIO.TextDecoder.ANSI) : this.openBinaryReader(); + + // diagnostic purpose only; tag the reader with the entry name + reader.zipEntryName = thisEntry.name; + + if (typeof callback != "function") { + // synchronous + var result = reader.readToEnd(); + this.verifyCrc32(); + return result; + } + + // asynchronous + reader.beginReadToEnd(function(result){ + try { + thisEntry.verifyCrc32(); + callback(thisEntry, result); + } + catch (exc1) { + this.zipfile.status.push("EXCEPTION: " + exc1.message); + callback(thisEntry, exc1); + } + }); + return null; + }; + + + // open a ByteReader on the entry, which will read binary + // content from the compressed stream. + ZipEntry.prototype.openBinaryReader = function() { + var reader = + new JSIO.StreamSegmentReader(this.zipfile.binaryStream, + this.offset + this.lengthOfHeader, + this.compressedSize); + if (this.compressionMethod === 0) { + this._crcCalculator = new JSIO.Crc32Reader(reader); + } + else { + var inflator = new JSIO.InflatingReader(reader); + this._crcCalculator = new JSIO.Crc32Reader(inflator); + } + // Whether compressed or not, the source ByteReader in each case + // is wrapped in a second ByteReader object that calculates CRC + // as it reads. That way, after all reading is complete, the + // caller can check the calcuated CRC against the expected CRC. + return this._crcCalculator; + }; + + // open a TextReader on the entry, to read text from the + // compressed stream. + ZipEntry.prototype.openTextReader = function(decoderKind) { + var reader = this.openBinaryReader(); + decoderKind = decoderKind || JSIO.TextDecoder.UTF8; + var d = new decoderKind(reader); + var textReader = new JSIO.TextReader(d); + d._parent = textReader; // store a reference, for diagnostic purposes only + return textReader; + }; + + // verify the CRC on the entry. + // call this after all bytes have been read. + ZipEntry.prototype.verifyCrc32 = function() { + var computedCrc = this._crcCalculator.crc32(); + var rc = false; // CRC FAIL + if (this.crc32 != computedCrc) { + var msg = "WARNING: CRC check failed: " + + "entry(" + this.name + ") " + + "computed(" + JSIO.decimalToHexString(computedCrc,8) + ") " + + "expected(" + JSIO.decimalToHexString(this.crc32,8) + ") "; + this.zipfile.status.push(msg); + } else { + rc = true; // OK + if (this.zipfile.verbose>2) { + this.zipfile.status.push("INFO: CRC check ok: 0x" + + JSIO.decimalToHexString(this.crc32,8)); + } + } + return rc; + }; + + + // ctor + ZipFile = function(fileUrl, callback, verbosity) { + if (! (this instanceof arguments.callee) ) JSIO.throwError('You must use new to instantiate this class', typename, 'ctor'); + + this.verbose = verbosity || 0; + this.entries = []; + this.entryNames = []; + this.status = []; + this._version = version; + this._typename = "ZipFile"; + this._throwError = JSIO.throwError; + + var thisZipFile = this; + + // Could use a back-tracking reader for the central directory, but + // there's no point, since all the zip data is held in memory anyway. + + /* function ReadCentralDirectory(){ + var posn = thisZipFile.binaryStream.length - 64; + var maxSeekback = Math.Max(s.Length - 0x4000, 10); + var success = false; + var nTries = 0; + do + { + thisZipFile.binaryStream.Seek(posn, SeekOrigin.Begin); + var bytesRead = thisZipFile.binaryStream.findSignature(thisZipFile.Signatures.EndOfCentralDirectory); + if (bytesRead != -1) + success = true; + else + { + nTries++; + // increasingly larger + posn -= (32 * (nTries + 1) * nTries); + if (posn < 0) posn = 0; // BOF + } + } + while (!success && posn > maxSeekback); + if (!success) { + thisZipFile.status.push("cannot find End of Central Directory"); + return; + } + } */ + + + function DateFromPackedFormat(packed) { + if (packed == 0xFFFF || packed === 0) return new Date(1995, 0, 1, 0,0,0,0); + + var packedTime = packed & 0x0000ffff; + var packedDate = ((packed & 0xffff0000) >> 16); + + var year = 1980 + ((packedDate & 0xFE00) >> 9); + var month = ((packedDate & 0x01E0) >> 5) -1; + var day = packedDate & 0x001F; + + var hour = (packedTime & 0xF800) >> 11; + var minute = (packedTime & 0x07E0) >> 5; + var second = (packedTime & 0x001F) * 2; + + // Validation and error checking. + // This is not foolproof but will catch most errors. + + // I can't believe how many different ways applications + // can mess up a simple date format. + + if (second >= 60) { minute++; second = 0; } + if (minute >= 60) { hour++; minute = 0; } + if (hour >= 24) { day++; hour = 0; } + var success = false; + var d; + try { + d = new Date(year, month, day, hour, minute, second, 0); + success= true; + } + catch (exc1) { + if (year == 1980 && (month === 0 || day === 0)) { + try { + d = new Date(1980, 0, 1, hour, minute, second, 0); + success= true; + } + catch (exc2) { + try { + d = new Date(1980, 0, 1, 0, 0, 0, 0); + success= true; + } + catch (exc3) { } // how could this fail?? + } + } + else { + try { + if (year < 1980) year = 1980; + if (year > 2030) year = 2030; + if (month < 1) month = 1; + if (month > 12) month = 12; + if (day < 1) day = 1; + if (day > 31) day = 31; + if (minute < 0) minute = 0; + if (minute > 59) minute = 59; + if (second < 0) second = 0; + if (second > 59) second = 59; + d = new Date(year, month-1, day, hour, minute, second, 0); + success= true; + } + catch (exc4){} + } + } + if (!success) this._throwError('Bad date/time value in this ZIP file', null, 'DateFromPackedFormat'); + return d; + } + + + function ReadZipEntries () { + // read only once + if (thisZipFile.entryNames.length === 0){ + var e; + while ((e = ReadZipEntry()) !== null) { + thisZipFile.entries.push(e); + thisZipFile.entryNames.push(e.name); + } + } + } + + + function ReadZipEntry () { + var offset = thisZipFile.binaryStream.position; + var sig = thisZipFile.binaryStream.readNumber(4); + if (sig == ZipFile.Signatures.DirEntry) { + // after all entries, comes the central directory + if (thisZipFile.verbose > 2) { + thisZipFile.status.push("INFO: at offset 0x" + + JSIO.decimalToHexString(offset) + + ", found start of Zip Directory."); + } + // all done reading + return null; + } + if (sig != ZipFile.Signatures.Entry) { + thisZipFile.status.push("WARNING: at offset 0x" + + JSIO.decimalToHexString(offset) + + ", found unexpected signature: 0x" + + JSIO.decimalToHexString(sig)); + return null; + } + + var entry = new ZipEntry(thisZipFile); + entry.offset = offset; + entry.versionNeeded = thisZipFile.binaryStream.readNumber(2); + entry.bitField = thisZipFile.binaryStream.readNumber(2); + entry.compressionMethod = thisZipFile.binaryStream.readNumber(2); + var timeBlob = thisZipFile.binaryStream.readNumber(4); + entry.lastModified = DateFromPackedFormat(timeBlob); + entry.crc32 = thisZipFile.binaryStream.readNumber(4); + entry.compressedSize = thisZipFile.binaryStream.readNumber(4); + entry.uncompressedSize = thisZipFile.binaryStream.readNumber(4); + + if (thisZipFile.verbose>2) { + thisZipFile.status.push("INFO: crc32 0x" + + JSIO.decimalToHexString(entry.crc32) + + " (" + entry.crc32 + ")"); + thisZipFile.status.push("INFO: compressedSize 0x" + + JSIO.decimalToHexString(entry.compressedSize) + + " (" + entry.compressedSize + ") bytes"); + thisZipFile.status.push("INFO: uncompressedSize 0x" + + JSIO.decimalToHexString(entry.uncompressedSize) + + " (" + entry.uncompressedSize + ") bytes"); + } + if ((entry.bitField & 0x01) == 0x01){ + thisZipFile.status.push("This zipfile uses Encryption, which is not supported by ZipFile.js."); + return null; + } + + entry.utf8 = ((entry.bitField & 0x0800) == 0x0800); + + if (entry.compressedSize == 0xFFFFFFFF || + entry.uncompressedSize == 0xFFFFFFFF) { + thisZipFile.status.push("This zipfile uses ZIP64, which is not supported by ZipFile.js"); + return null; + } + + var filenameLength = thisZipFile.binaryStream.readNumber(2); + var extraFieldLength = thisZipFile.binaryStream.readNumber(2); + + if (thisZipFile.verbose>2) { + thisZipFile.status.push("INFO: filename length= " + filenameLength); + } + + // we've read 30 bytes of metadata so far + var bytesRead = 30 + filenameLength + extraFieldLength; + + if (entry.utf8) { + thisZipFile.status.push("INFO: before filename, position= 0x" + + JSIO.decimalToHexString( thisZipFile.binaryStream.position )); + var binReader = + new JSIO.StreamSegmentReader(thisZipFile.binaryStream, + thisZipFile.binaryStream.position, + filenameLength); + var utf8Decoder = new JSIO.TextDecoder.UTF8(binReader); + var textReader = new JSIO.TextReader(utf8Decoder); + entry.name = textReader.readToEnd(); + + // advance the filepointer: + thisZipFile.binaryStream.seek(filenameLength, + JSIO.SeekOrigin.Current, + thisZipFile); + + thisZipFile.status.push("INFO: after filename, position= 0x" + + JSIO.decimalToHexString( thisZipFile.binaryStream.position )); + } + else { + entry.name = thisZipFile.binaryStream.readString(filenameLength); + } + + // There are a bunch of things in the "extra" header, thisZipFile we + // could parse, like timestamps and other things. This class + // only identifies and separates them. + + // More info here: http://www.pkware.com/documents/casestudies/APPNOTE.TXT + + var extraPos = 0; + entry.extra = []; + while (extraPos < extraFieldLength) { + var extraBlock = { + type: thisZipFile.binaryStream.readNumber(2), + size: thisZipFile.binaryStream.readNumber(2) + }; + extraBlock.typeDescription = ZipFile.ExtraFieldTypes[extraBlock.type]; + extraBlock.data = thisZipFile.binaryStream.read(extraBlock.size); + entry.extra.push(extraBlock); + extraPos += 4 + extraBlock.size; + } + + if (thisZipFile.verbose > 1) { + thisZipFile.status.push("INFO: at offset 0x" + + JSIO.decimalToHexString(entry.offset) + + ", found entry '" + entry.name + "' fnl(" + + filenameLength + ") efl(" + + extraFieldLength +")"); + } + + if (extraFieldLength > 0) { + if (thisZipFile.verbose > 0) { + thisZipFile.status.push("INFO: entry " + entry.name + " has " + + extraFieldLength + " bytes of " + + "extra metadata (ID'd but ignored)"); + } + } + + entry.lengthOfHeader = bytesRead; + if (thisZipFile.verbose>2) { + thisZipFile.status.push("INFO: lengthOfHeader 0x" + + JSIO.decimalToHexString(entry.lengthOfHeader) + + " (" + entry.lengthOfHeader + ")"); + } + + /* + Data descriptor Offset Bytes Description[25] + 0 0/4 Optional data descriptor signature = 0x08074b50 + 0/4 4 CRC-32 + 4/8 4 Compressed size + 8/12 4 Uncompressed size + */ + + if ((entry.bitField & 0x0008) == 0x0008){ + thisZipFile.status.push("INFO: This zipfile uses a bit 3 trailing data descriptor"); + // return null; + var currentPosition = thisZipFile.binaryStream.position; + var dataDescLength = 0; + if (thisZipFile.verbose>2) { + thisZipFile.status.push("INFO: currentPosition 0x" + + JSIO.decimalToHexString(thisZipFile.binaryStream.position) + + " (" + thisZipFile.binaryStream.position + ")"); + thisZipFile.status.push("INFO: length 0x" + + JSIO.decimalToHexString(thisZipFile.binaryStream.length) + + " (" + thisZipFile.binaryStream.length + ")"); + } + + for (var i=0; i<128; i++) { // maximum search backwards from end for signature is 128 bytes + thisZipFile.binaryStream.seek(thisZipFile.binaryStream.length-i-4,JSIO.SeekOrigin.Begin); + var num = thisZipFile.binaryStream.readNumber(4) + if (thisZipFile.verbose>2) { + thisZipFile.status.push("INFO: ["+i+"] 0x" + + JSIO.decimalToHexString(num) + + " (" + num + ")"); + } + if (num == ZipFile.Signatures.DataDescriptor) { + sig = num; + entry.crc32 = thisZipFile.binaryStream.readNumber(4); + entry.compressedSize = thisZipFile.binaryStream.readNumber(4); + entry.uncompressedSize = thisZipFile.binaryStream.readNumber(4); + dataDescLength = 16; + break; + } + } + + if (thisZipFile.verbose>2) { + thisZipFile.status.push("INFO: sig 0x" + + JSIO.decimalToHexString(sig) + + " (" + sig + ")"); + thisZipFile.status.push("INFO: crc32 0x" + + JSIO.decimalToHexString(entry.crc32) + + " (" + entry.crc32 + ")"); + thisZipFile.status.push("INFO: compressedSize 0x" + + JSIO.decimalToHexString(entry.compressedSize) + + " (" + entry.compressedSize + ") bytes"); + thisZipFile.status.push("INFO: uncompressedSize 0x" + + JSIO.decimalToHexString(entry.uncompressedSize) + + " (" + entry.uncompressedSize + ") bytes"); + thisZipFile.status.push("INFO: lengthOfHeader 0x" + + JSIO.decimalToHexString(entry.lengthOfHeader) + + " (" + entry.lengthOfHeader + ")"); + } + + thisZipFile.binaryStream.position = currentPosition+dataDescLength; + } + + entry.totalEntrySize = entry.lengthOfHeader + entry.compressedSize; + + // seek past the data without reading it. We will read on Extract() + if (thisZipFile.verbose > 1) { + thisZipFile.status.push("INFO: seek 0x" + + JSIO.decimalToHexString(entry.compressedSize) + + " (" + entry.compressedSize + ") bytes"); + } + + thisZipFile.binaryStream.seek(entry.compressedSize, + JSIO.SeekOrigin.Current, + thisZipFile); + + return entry; + } + + + var parseZipFile = function(bfr){ + try { + if (bfr.req.status == 200) { + var sig = thisZipFile.binaryStream.readNumber(4); + if (sig != ZipFile.Signatures.Entry){ + thisZipFile.status.push("WARNING: this file does not appear to be a zip file"); + } else { + thisZipFile.binaryStream.seek(0, JSIO.SeekOrigin.Begin); + ReadZipEntries(); + if (thisZipFile.verbose > 0) { + thisZipFile.status.push("INFO: read " + thisZipFile.entries.length + " entries"); + } + } + } + else { + thisZipFile.status.push("ERROR: the URL could not be read (" + + bfr.req.status + " " + bfr.req.statusText + ")"); + } + callback(thisZipFile); + } + catch (exc1) + { + thisZipFile.status.push("EXCEPTION: " + exc1.message); + callback(thisZipFile); + } + }; + + this.binaryStream = new JSIO.BinaryUrlStream(fileUrl, parseZipFile); + + return this; + }; + + + ZipFile.Signatures = { + Entry : 0x04034b50, + EndOfCentralDirectory : 0x06054b50, + DirEntry : 0x02014b50, + DataDescriptor : 0x08074b50 + }; + + ZipFile.Version = version; + + ZipFile.EncryptionAlgorithm = { + None : 0, + PkzipWeak : 1, + WinZipAes : 2 + }; + + ZipFile.ExtraFieldTypes = {}; + ZipFile.ExtraFieldTypes[0x0001] = 'Zip64 Extended Info'; + ZipFile.ExtraFieldTypes[0x0007] = 'AV Info'; + ZipFile.ExtraFieldTypes[0x0008] = 'Extended Language Encoding Data (PFS)'; + ZipFile.ExtraFieldTypes[0x0009] = 'OS/2'; + ZipFile.ExtraFieldTypes[0x000a] = 'NTFS '; + ZipFile.ExtraFieldTypes[0x000c] = 'OpenVMS'; + ZipFile.ExtraFieldTypes[0x000d] = 'UNIX'; + ZipFile.ExtraFieldTypes[0x000e] = 'File Stream and Fork Descriptors'; + ZipFile.ExtraFieldTypes[0x000f] = 'Patch Descriptor'; + ZipFile.ExtraFieldTypes[0x0014] = 'PKCS#7 Store for X.509 Certificates'; + ZipFile.ExtraFieldTypes[0x0015] = 'X.509 Certificate ID and Signature (Individual File)'; + ZipFile.ExtraFieldTypes[0x0016] = 'X.509 Certificate ID (Central Directory)'; + ZipFile.ExtraFieldTypes[0x0017] = 'Strong Encryption Header'; + ZipFile.ExtraFieldTypes[0x0018] = 'Record Management Controls'; + ZipFile.ExtraFieldTypes[0x0019] = 'PKCS#7 Encryption Recipient Certificate List'; + ZipFile.ExtraFieldTypes[0x0065] = 'IBM S/390 (Z390), AS/400 (I400) attributes (uncompressed)'; + ZipFile.ExtraFieldTypes[0x0066] = 'IBM S/390 (Z390), AS/400 (I400) attributes (compressed)'; + ZipFile.ExtraFieldTypes[0x4690] = 'POSZIP 4690 (reserved) '; + ZipFile.ExtraFieldTypes[0x07c8] = 'Macintosh'; + ZipFile.ExtraFieldTypes[0x2605] = 'ZipIt Macintosh'; + ZipFile.ExtraFieldTypes[0x2705] = 'ZipIt Macintosh 1.3.5+'; + ZipFile.ExtraFieldTypes[0x2805] = 'ZipIt Macintosh 1.3.5+'; + ZipFile.ExtraFieldTypes[0x334d] = 'Info-ZIP Macintosh'; + ZipFile.ExtraFieldTypes[0x4341] = 'Acorn/SparkFS '; + ZipFile.ExtraFieldTypes[0x4453] = 'Windows NT security descriptor (binary ACL)'; + ZipFile.ExtraFieldTypes[0x4704] = 'VM/CMS'; + ZipFile.ExtraFieldTypes[0x470f] = 'MVS'; + ZipFile.ExtraFieldTypes[0x4b46] = 'FWKCS MD5'; + ZipFile.ExtraFieldTypes[0x4c41] = 'OS/2 access control list (text ACL)'; + ZipFile.ExtraFieldTypes[0x4d49] = 'Info-ZIP OpenVMS'; + ZipFile.ExtraFieldTypes[0x4f4c] = 'Xceed original location extra field'; + ZipFile.ExtraFieldTypes[0x5356] = 'AOS/VS (ACL)'; + ZipFile.ExtraFieldTypes[0x5455] = 'extended timestamp'; + ZipFile.ExtraFieldTypes[0x554e] = 'Xceed unicode extra field'; + ZipFile.ExtraFieldTypes[0x5855] = 'Info-ZIP UNIX (original, also OS/2, NT, etc)'; + ZipFile.ExtraFieldTypes[0x6375] = 'Info-ZIP Unicode Comment Extra Field'; + ZipFile.ExtraFieldTypes[0x6542] = 'BeOS/BeBox'; + ZipFile.ExtraFieldTypes[0x7075] = 'Info-ZIP Unicode Path Extra Field'; + ZipFile.ExtraFieldTypes[0x756e] = 'ASi UNIX'; + ZipFile.ExtraFieldTypes[0x7855] = 'Info-ZIP UNIX (new)'; + ZipFile.ExtraFieldTypes[0xa220] = 'Microsoft Open Packaging Growth Hint'; + ZipFile.ExtraFieldTypes[0xfd4a] = 'SMS/QDOS'; })(); |