UNPKG

hic-straw

Version:

Utilities for reading .files (contact matrix files)

1,920 lines (1,686 loc) 150 kB
// from https://github.com/imaya/zlib.js /** * @fileoverview Zlib namespace. Zlib の仕様に準拠した圧縮は Zlib.Deflate で実装 * されている. これは Inflate との共存を考慮している為. */ var USE_TYPEDARRAY = true; var Zlib = { Huffman: {}, Util: {}, CRC32: {} }; /** * Compression Method * @enum {number} */ Zlib.CompressionMethod = { DEFLATE: 8, RESERVED: 15 }; /** * @param {Object=} opt_params options. * @constructor */ Zlib.Zip = function(opt_params) { opt_params = opt_params || {}; /** @type {Array.<{ * buffer: !(Array.<number>|Uint8Array), * option: Object, * compressed: boolean, * encrypted: boolean, * size: number, * crc32: number * }>} */ this.files = []; /** @type {(Array.<number>|Uint8Array)} */ this.comment = opt_params['comment']; /** @type {(Array.<number>|Uint8Array)} */ this.password; }; /** * @enum {number} */ Zlib.Zip.CompressionMethod = { STORE: 0, DEFLATE: 8 }; /** * @enum {number} */ Zlib.Zip.OperatingSystem = { MSDOS: 0, UNIX: 3, MACINTOSH: 7 }; /** * @enum {number} */ Zlib.Zip.Flags = { ENCRYPT: 0x0001, DESCRIPTOR: 0x0008, UTF8: 0x0800 }; /** * @type {Array.<number>} * @const */ Zlib.Zip.FileHeaderSignature = [0x50, 0x4b, 0x01, 0x02]; /** * @type {Array.<number>} * @const */ Zlib.Zip.LocalFileHeaderSignature = [0x50, 0x4b, 0x03, 0x04]; /** * @type {Array.<number>} * @const */ Zlib.Zip.CentralDirectorySignature = [0x50, 0x4b, 0x05, 0x06]; /** * @param {Array.<number>|Uint8Array} input * @param {Object=} opt_params options. */ Zlib.Zip.prototype.addFile = function(input, opt_params) { opt_params = opt_params || {}; /** @type {string} */ var filename = '' || opt_params['filename']; /** @type {boolean} */ var compressed; /** @type {number} */ var size = input.length; /** @type {number} */ var crc32 = 0; if (USE_TYPEDARRAY && input instanceof Array) { input = new Uint8Array(input); } // default if (typeof opt_params['compressionMethod'] !== 'number') { opt_params['compressionMethod'] = Zlib.Zip.CompressionMethod.DEFLATE; } // その場で圧縮する場合 if (opt_params['compress']) { switch (opt_params['compressionMethod']) { case Zlib.Zip.CompressionMethod.STORE: break; case Zlib.Zip.CompressionMethod.DEFLATE: crc32 = Zlib.CRC32.calc(input); input = this.deflateWithOption(input, opt_params); compressed = true; break; default: throw new Error('unknown compression method:' + opt_params['compressionMethod']); } } this.files.push({ buffer: input, option: opt_params, compressed: compressed, encrypted: false, size: size, crc32: crc32 }); }; /** * @param {(Array.<number>|Uint8Array)} password */ Zlib.Zip.prototype.setPassword = function(password) { this.password = password; }; Zlib.Zip.prototype.compress = function() { /** @type {Array.<{ * buffer: !(Array.<number>|Uint8Array), * option: Object, * compressed: boolean, * encrypted: boolean, * size: number, * crc32: number * }>} */ var files = this.files; /** @type {{ * buffer: !(Array.<number>|Uint8Array), * option: Object, * compressed: boolean, * encrypted: boolean, * size: number, * crc32: number * }} */ var file; /** @type {!(Array.<number>|Uint8Array)} */ var output; /** @type {number} */ var op1; /** @type {number} */ var op2; /** @type {number} */ var op3; /** @type {number} */ var localFileSize = 0; /** @type {number} */ var centralDirectorySize = 0; /** @type {number} */ var endOfCentralDirectorySize; /** @type {number} */ var offset; /** @type {number} */ var needVersion; /** @type {number} */ var flags; /** @type {Zlib.Zip.CompressionMethod} */ var compressionMethod; /** @type {Date} */ var date; /** @type {number} */ var crc32; /** @type {number} */ var size; /** @type {number} */ var plainSize; /** @type {number} */ var filenameLength; /** @type {number} */ var extraFieldLength; /** @type {number} */ var commentLength; /** @type {(Array.<number>|Uint8Array)} */ var filename; /** @type {(Array.<number>|Uint8Array)} */ var extraField; /** @type {(Array.<number>|Uint8Array)} */ var comment; /** @type {(Array.<number>|Uint8Array)} */ var buffer; /** @type {*} */ var tmp; /** @type {Array.<number>|Uint32Array|Object} */ var key; /** @type {number} */ var i; /** @type {number} */ var il; /** @type {number} */ var j; /** @type {number} */ var jl; // ファイルの圧縮 for (i = 0, il = files.length; i < il; ++i) { file = files[i]; filenameLength = (file.option['filename']) ? file.option['filename'].length : 0; extraFieldLength = (file.option['extraField']) ? file.option['extraField'].length : 0; commentLength = (file.option['comment']) ? file.option['comment'].length : 0; // 圧縮されていなかったら圧縮 if (!file.compressed) { // 圧縮前に CRC32 の計算をしておく file.crc32 = Zlib.CRC32.calc(file.buffer); switch (file.option['compressionMethod']) { case Zlib.Zip.CompressionMethod.STORE: break; case Zlib.Zip.CompressionMethod.DEFLATE: file.buffer = this.deflateWithOption(file.buffer, file.option); file.compressed = true; break; default: throw new Error('unknown compression method:' + file.option['compressionMethod']); } } // encryption if (file.option['password'] !== void 0|| this.password !== void 0) { // init encryption key = this.createEncryptionKey(file.option['password'] || this.password); // add header buffer = file.buffer; if (USE_TYPEDARRAY) { tmp = new Uint8Array(buffer.length + 12); tmp.set(buffer, 12); buffer = tmp; } else { buffer.unshift(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } for (j = 0; j < 12; ++j) { buffer[j] = this.encode( key, i === 11 ? (file.crc32 & 0xff) : (Math.random() * 256 | 0) ); } // data encryption for (jl = buffer.length; j < jl; ++j) { buffer[j] = this.encode(key, buffer[j]); } file.buffer = buffer; } // 必要バッファサイズの計算 localFileSize += // local file header 30 + filenameLength + // file data file.buffer.length; centralDirectorySize += // file header 46 + filenameLength + commentLength; } // end of central directory endOfCentralDirectorySize = 22 + (this.comment ? this.comment.length : 0); output = new (USE_TYPEDARRAY ? Uint8Array : Array)( localFileSize + centralDirectorySize + endOfCentralDirectorySize ); op1 = 0; op2 = localFileSize; op3 = op2 + centralDirectorySize; // ファイルの圧縮 for (i = 0, il = files.length; i < il; ++i) { file = files[i]; filenameLength = file.option['filename'] ? file.option['filename'].length : 0; extraFieldLength = 0; // TODO commentLength = file.option['comment'] ? file.option['comment'].length : 0; //------------------------------------------------------------------------- // local file header & file header //------------------------------------------------------------------------- offset = op1; // signature // local file header output[op1++] = Zlib.Zip.LocalFileHeaderSignature[0]; output[op1++] = Zlib.Zip.LocalFileHeaderSignature[1]; output[op1++] = Zlib.Zip.LocalFileHeaderSignature[2]; output[op1++] = Zlib.Zip.LocalFileHeaderSignature[3]; // file header output[op2++] = Zlib.Zip.FileHeaderSignature[0]; output[op2++] = Zlib.Zip.FileHeaderSignature[1]; output[op2++] = Zlib.Zip.FileHeaderSignature[2]; output[op2++] = Zlib.Zip.FileHeaderSignature[3]; // compressor info needVersion = 20; output[op2++] = needVersion & 0xff; output[op2++] = /** @type {Zlib.Zip.OperatingSystem} */ (file.option['os']) || Zlib.Zip.OperatingSystem.MSDOS; // need version output[op1++] = output[op2++] = needVersion & 0xff; output[op1++] = output[op2++] = (needVersion >> 8) & 0xff; // general purpose bit flag flags = 0; if (file.option['password'] || this.password) { flags |= Zlib.Zip.Flags.ENCRYPT; } output[op1++] = output[op2++] = flags & 0xff; output[op1++] = output[op2++] = (flags >> 8) & 0xff; // compression method compressionMethod = /** @type {Zlib.Zip.CompressionMethod} */ (file.option['compressionMethod']); output[op1++] = output[op2++] = compressionMethod & 0xff; output[op1++] = output[op2++] = (compressionMethod >> 8) & 0xff; // date date = /** @type {(Date|undefined)} */(file.option['date']) || new Date(); output[op1++] = output[op2++] = ((date.getMinutes() & 0x7) << 5) | (date.getSeconds() / 2 | 0); output[op1++] = output[op2++] = (date.getHours() << 3) | (date.getMinutes() >> 3); // output[op1++] = output[op2++] = ((date.getMonth() + 1 & 0x7) << 5) | (date.getDate()); output[op1++] = output[op2++] = ((date.getFullYear() - 1980 & 0x7f) << 1) | (date.getMonth() + 1 >> 3); // CRC-32 crc32 = file.crc32; output[op1++] = output[op2++] = crc32 & 0xff; output[op1++] = output[op2++] = (crc32 >> 8) & 0xff; output[op1++] = output[op2++] = (crc32 >> 16) & 0xff; output[op1++] = output[op2++] = (crc32 >> 24) & 0xff; // compressed size size = file.buffer.length; output[op1++] = output[op2++] = size & 0xff; output[op1++] = output[op2++] = (size >> 8) & 0xff; output[op1++] = output[op2++] = (size >> 16) & 0xff; output[op1++] = output[op2++] = (size >> 24) & 0xff; // uncompressed size plainSize = file.size; output[op1++] = output[op2++] = plainSize & 0xff; output[op1++] = output[op2++] = (plainSize >> 8) & 0xff; output[op1++] = output[op2++] = (plainSize >> 16) & 0xff; output[op1++] = output[op2++] = (plainSize >> 24) & 0xff; // filename length output[op1++] = output[op2++] = filenameLength & 0xff; output[op1++] = output[op2++] = (filenameLength >> 8) & 0xff; // extra field length output[op1++] = output[op2++] = extraFieldLength & 0xff; output[op1++] = output[op2++] = (extraFieldLength >> 8) & 0xff; // file comment length output[op2++] = commentLength & 0xff; output[op2++] = (commentLength >> 8) & 0xff; // disk number start output[op2++] = 0; output[op2++] = 0; // internal file attributes output[op2++] = 0; output[op2++] = 0; // external file attributes output[op2++] = 0; output[op2++] = 0; output[op2++] = 0; output[op2++] = 0; // relative offset of local header output[op2++] = offset & 0xff; output[op2++] = (offset >> 8) & 0xff; output[op2++] = (offset >> 16) & 0xff; output[op2++] = (offset >> 24) & 0xff; // filename filename = file.option['filename']; if (filename) { if (USE_TYPEDARRAY) { output.set(filename, op1); output.set(filename, op2); op1 += filenameLength; op2 += filenameLength; } else { for (j = 0; j < filenameLength; ++j) { output[op1++] = output[op2++] = filename[j]; } } } // extra field extraField = file.option['extraField']; if (extraField) { if (USE_TYPEDARRAY) { output.set(extraField, op1); output.set(extraField, op2); op1 += extraFieldLength; op2 += extraFieldLength; } else { for (j = 0; j < commentLength; ++j) { output[op1++] = output[op2++] = extraField[j]; } } } // comment comment = file.option['comment']; if (comment) { if (USE_TYPEDARRAY) { output.set(comment, op2); op2 += commentLength; } else { for (j = 0; j < commentLength; ++j) { output[op2++] = comment[j]; } } } //------------------------------------------------------------------------- // file data //------------------------------------------------------------------------- if (USE_TYPEDARRAY) { output.set(file.buffer, op1); op1 += file.buffer.length; } else { for (j = 0, jl = file.buffer.length; j < jl; ++j) { output[op1++] = file.buffer[j]; } } } //------------------------------------------------------------------------- // end of central directory //------------------------------------------------------------------------- // signature output[op3++] = Zlib.Zip.CentralDirectorySignature[0]; output[op3++] = Zlib.Zip.CentralDirectorySignature[1]; output[op3++] = Zlib.Zip.CentralDirectorySignature[2]; output[op3++] = Zlib.Zip.CentralDirectorySignature[3]; // number of this disk output[op3++] = 0; output[op3++] = 0; // number of the disk with the start of the central directory output[op3++] = 0; output[op3++] = 0; // total number of entries in the central directory on this disk output[op3++] = il & 0xff; output[op3++] = (il >> 8) & 0xff; // total number of entries in the central directory output[op3++] = il & 0xff; output[op3++] = (il >> 8) & 0xff; // size of the central directory output[op3++] = centralDirectorySize & 0xff; output[op3++] = (centralDirectorySize >> 8) & 0xff; output[op3++] = (centralDirectorySize >> 16) & 0xff; output[op3++] = (centralDirectorySize >> 24) & 0xff; // offset of start of central directory with respect to the starting disk number output[op3++] = localFileSize & 0xff; output[op3++] = (localFileSize >> 8) & 0xff; output[op3++] = (localFileSize >> 16) & 0xff; output[op3++] = (localFileSize >> 24) & 0xff; // .ZIP file comment length commentLength = this.comment ? this.comment.length : 0; output[op3++] = commentLength & 0xff; output[op3++] = (commentLength >> 8) & 0xff; // .ZIP file comment if (this.comment) { if (USE_TYPEDARRAY) { output.set(this.comment, op3); op3 += commentLength; } else { for (j = 0, jl = commentLength; j < jl; ++j) { output[op3++] = this.comment[j]; } } } return output; }; /** * @param {!(Array.<number>|Uint8Array)} input * @param {Object=} opt_params options. * @return {!(Array.<number>|Uint8Array)} */ Zlib.Zip.prototype.deflateWithOption = function(input, opt_params) { /** @type {Zlib.RawDeflate} */ var deflator = new Zlib.RawDeflate(input, opt_params['deflateOption']); return deflator.compress(); }; /** * @param {(Array.<number>|Uint32Array)} key * @return {number} */ Zlib.Zip.prototype.getByte = function(key) { /** @type {number} */ var tmp = ((key[2] & 0xffff) | 2); return ((tmp * (tmp ^ 1)) >> 8) & 0xff; }; /** * @param {(Array.<number>|Uint32Array|Object)} key * @param {number} n * @return {number} */ Zlib.Zip.prototype.encode = function(key, n) { /** @type {number} */ var tmp = this.getByte(/** @type {(Array.<number>|Uint32Array)} */(key)); this.updateKeys(/** @type {(Array.<number>|Uint32Array)} */(key), n); return tmp ^ n; }; /** * @param {(Array.<number>|Uint32Array)} key * @param {number} n */ Zlib.Zip.prototype.updateKeys = function(key, n) { key[0] = Zlib.CRC32.single(key[0], n); key[1] = (((((key[1] + (key[0] & 0xff)) * 20173 >>> 0) * 6681) >>> 0) + 1) >>> 0; key[2] = Zlib.CRC32.single(key[2], key[1] >>> 24); }; /** * @param {(Array.<number>|Uint8Array)} password * @return {!(Array.<number>|Uint32Array|Object)} */ Zlib.Zip.prototype.createEncryptionKey = function(password) { /** @type {!(Array.<number>|Uint32Array)} */ var key = [305419896, 591751049, 878082192]; /** @type {number} */ var i; /** @type {number} */ var il; if (USE_TYPEDARRAY) { key = new Uint32Array(key); } for (i = 0, il = password.length; i < il; ++i) { this.updateKeys(key, password[i] & 0xff); } return key; }; /** * build huffman table from length list. * @param {!(Array.<number>|Uint8Array)} lengths length list. * @return {!Array} huffman table. */ Zlib.Huffman.buildHuffmanTable = function(lengths) { /** @type {number} length list size. */ var listSize = lengths.length; /** @type {number} max code length for table size. */ var maxCodeLength = 0; /** @type {number} min code length for table size. */ var minCodeLength = Number.POSITIVE_INFINITY; /** @type {number} table size. */ var size; /** @type {!(Array|Uint8Array)} huffman code table. */ var table; /** @type {number} bit length. */ var bitLength; /** @type {number} huffman code. */ var code; /** * サイズが 2^maxlength 個のテーブルを埋めるためのスキップ長. * @type {number} skip length for table filling. */ var skip; /** @type {number} reversed code. */ var reversed; /** @type {number} reverse temp. */ var rtemp; /** @type {number} loop counter. */ var i; /** @type {number} loop limit. */ var il; /** @type {number} loop counter. */ var j; /** @type {number} table value. */ var value; // Math.max は遅いので最長の値は for-loop で取得する for (i = 0, il = listSize; i < il; ++i) { if (lengths[i] > maxCodeLength) { maxCodeLength = lengths[i]; } if (lengths[i] < minCodeLength) { minCodeLength = lengths[i]; } } size = 1 << maxCodeLength; table = new (USE_TYPEDARRAY ? Uint32Array : Array)(size); // ビット長の短い順からハフマン符号を割り当てる for (bitLength = 1, code = 0, skip = 2; bitLength <= maxCodeLength;) { for (i = 0; i < listSize; ++i) { if (lengths[i] === bitLength) { // ビットオーダーが逆になるためビット長分並びを反転する for (reversed = 0, rtemp = code, j = 0; j < bitLength; ++j) { reversed = (reversed << 1) | (rtemp & 1); rtemp >>= 1; } // 最大ビット長をもとにテーブルを作るため、 // 最大ビット長以外では 0 / 1 どちらでも良い箇所ができる // そのどちらでも良い場所は同じ値で埋めることで // 本来のビット長以上のビット数取得しても問題が起こらないようにする value = (bitLength << 16) | i; for (j = reversed; j < size; j += skip) { table[j] = value; } ++code; } } // 次のビット長へ ++bitLength; code <<= 1; skip <<= 1; } return [table, maxCodeLength, minCodeLength]; }; //----------------------------------------------------------------------------- /** @define {number} buffer block size. */ var ZLIB_RAW_INFLATE_BUFFER_SIZE = 0x8000; // [ 0x8000 >= ZLIB_BUFFER_BLOCK_SIZE ] //----------------------------------------------------------------------------- var buildHuffmanTable = Zlib.Huffman.buildHuffmanTable; /** * @constructor * @param {!(Uint8Array|Array.<number>)} input input buffer. * @param {Object} opt_params option parameter. * * opt_params は以下のプロパティを指定する事ができます。 * - index: input buffer の deflate コンテナの開始位置. * - blockSize: バッファのブロックサイズ. * - bufferType: Zlib.RawInflate.BufferType の値によってバッファの管理方法を指定する. * - resize: 確保したバッファが実際の大きさより大きかった場合に切り詰める. */ Zlib.RawInflate = function(input, opt_params) { /** @type {!(Array.<number>|Uint8Array)} inflated buffer */ this.buffer; /** @type {!Array.<(Array.<number>|Uint8Array)>} */ this.blocks = []; /** @type {number} block size. */ this.bufferSize = ZLIB_RAW_INFLATE_BUFFER_SIZE; /** @type {!number} total output buffer pointer. */ this.totalpos = 0; /** @type {!number} input buffer pointer. */ this.ip = 0; /** @type {!number} bit stream reader buffer. */ this.bitsbuf = 0; /** @type {!number} bit stream reader buffer size. */ this.bitsbuflen = 0; /** @type {!(Array.<number>|Uint8Array)} input buffer. */ this.input = USE_TYPEDARRAY ? new Uint8Array(input) : input; /** @type {!(Uint8Array|Array.<number>)} output buffer. */ this.output; /** @type {!number} output buffer pointer. */ this.op; /** @type {boolean} is final block flag. */ this.bfinal = false; /** @type {Zlib.RawInflate.BufferType} buffer management. */ this.bufferType = Zlib.RawInflate.BufferType.ADAPTIVE; /** @type {boolean} resize flag for memory size optimization. */ this.resize = false; // option parameters if (opt_params || !(opt_params = {})) { if (opt_params['index']) { this.ip = opt_params['index']; } if (opt_params['bufferSize']) { this.bufferSize = opt_params['bufferSize']; } if (opt_params['bufferType']) { this.bufferType = opt_params['bufferType']; } if (opt_params['resize']) { this.resize = opt_params['resize']; } } // initialize switch (this.bufferType) { case Zlib.RawInflate.BufferType.BLOCK: this.op = Zlib.RawInflate.MaxBackwardLength; this.output = new (USE_TYPEDARRAY ? Uint8Array : Array)( Zlib.RawInflate.MaxBackwardLength + this.bufferSize + Zlib.RawInflate.MaxCopyLength ); break; case Zlib.RawInflate.BufferType.ADAPTIVE: this.op = 0; this.output = new (USE_TYPEDARRAY ? Uint8Array : Array)(this.bufferSize); break; default: throw new Error('invalid inflate mode'); } }; /** * @enum {number} */ Zlib.RawInflate.BufferType = { BLOCK: 0, ADAPTIVE: 1 }; /** * decompress. * @return {!(Uint8Array|Array.<number>)} inflated buffer. */ Zlib.RawInflate.prototype.decompress = function() { while (!this.bfinal) { this.parseBlock(); } switch (this.bufferType) { case Zlib.RawInflate.BufferType.BLOCK: return this.concatBufferBlock(); case Zlib.RawInflate.BufferType.ADAPTIVE: return this.concatBufferDynamic(); default: throw new Error('invalid inflate mode'); } }; /** * @const * @type {number} max backward length for LZ77. */ Zlib.RawInflate.MaxBackwardLength = 32768; /** * @const * @type {number} max copy length for LZ77. */ Zlib.RawInflate.MaxCopyLength = 258; /** * huffman order * @const * @type {!(Array.<number>|Uint8Array)} */ Zlib.RawInflate.Order = (function(table) { return USE_TYPEDARRAY ? new Uint16Array(table) : table; })([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); /** * huffman length code table. * @const * @type {!(Array.<number>|Uint16Array)} */ Zlib.RawInflate.LengthCodeTable = (function(table) { return USE_TYPEDARRAY ? new Uint16Array(table) : table; })([ 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000d, 0x000f, 0x0011, 0x0013, 0x0017, 0x001b, 0x001f, 0x0023, 0x002b, 0x0033, 0x003b, 0x0043, 0x0053, 0x0063, 0x0073, 0x0083, 0x00a3, 0x00c3, 0x00e3, 0x0102, 0x0102, 0x0102 ]); /** * huffman length extra-bits table. * @const * @type {!(Array.<number>|Uint8Array)} */ Zlib.RawInflate.LengthExtraTable = (function(table) { return USE_TYPEDARRAY ? new Uint8Array(table) : table; })([ 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, 0, 0 ]); /** * huffman dist code table. * @const * @type {!(Array.<number>|Uint16Array)} */ Zlib.RawInflate.DistCodeTable = (function(table) { return USE_TYPEDARRAY ? new Uint16Array(table) : table; })([ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d, 0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1, 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01, 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001 ]); /** * huffman dist extra-bits table. * @const * @type {!(Array.<number>|Uint8Array)} */ Zlib.RawInflate.DistExtraTable = (function(table) { return USE_TYPEDARRAY ? new Uint8Array(table) : table; })([ 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 ]); /** * fixed huffman length code table * @const * @type {!Array} */ Zlib.RawInflate.FixedLiteralLengthTable = (function(table) { return table; })((function() { var lengths = new (USE_TYPEDARRAY ? Uint8Array : Array)(288); var i, il; for (i = 0, il = lengths.length; i < il; ++i) { lengths[i] = (i <= 143) ? 8 : (i <= 255) ? 9 : (i <= 279) ? 7 : 8; } return buildHuffmanTable(lengths); })()); /** * fixed huffman distance code table * @const * @type {!Array} */ Zlib.RawInflate.FixedDistanceTable = (function(table) { return table; })((function() { var lengths = new (USE_TYPEDARRAY ? Uint8Array : Array)(30); var i, il; for (i = 0, il = lengths.length; i < il; ++i) { lengths[i] = 5; } return buildHuffmanTable(lengths); })()); /** * parse deflated block. */ Zlib.RawInflate.prototype.parseBlock = function() { /** @type {number} header */ var hdr = this.readBits(3); // BFINAL if (hdr & 0x1) { this.bfinal = true; } // BTYPE hdr >>>= 1; switch (hdr) { // uncompressed case 0: this.parseUncompressedBlock(); break; // fixed huffman case 1: this.parseFixedHuffmanBlock(); break; // dynamic huffman case 2: this.parseDynamicHuffmanBlock(); break; // reserved or other default: throw new Error('unknown BTYPE: ' + hdr); } }; /** * read inflate bits * @param {number} length bits length. * @return {number} read bits. */ Zlib.RawInflate.prototype.readBits = function(length) { var bitsbuf = this.bitsbuf; var bitsbuflen = this.bitsbuflen; var input = this.input; var ip = this.ip; /** @type {number} */ var inputLength = input.length; /** @type {number} input and output byte. */ var octet; // input byte if (ip + ((length - bitsbuflen + 7) >> 3) >= inputLength) { throw new Error('input buffer is broken'); } // not enough buffer while (bitsbuflen < length) { bitsbuf |= input[ip++] << bitsbuflen; bitsbuflen += 8; } // output byte octet = bitsbuf & /* MASK */ ((1 << length) - 1); bitsbuf >>>= length; bitsbuflen -= length; this.bitsbuf = bitsbuf; this.bitsbuflen = bitsbuflen; this.ip = ip; return octet; }; /** * read huffman code using table * @param {!(Array.<number>|Uint8Array|Uint16Array)} table huffman code table. * @return {number} huffman code. */ Zlib.RawInflate.prototype.readCodeByTable = function(table) { var bitsbuf = this.bitsbuf; var bitsbuflen = this.bitsbuflen; var input = this.input; var ip = this.ip; /** @type {number} */ var inputLength = input.length; /** @type {!(Array.<number>|Uint8Array)} huffman code table */ var codeTable = table[0]; /** @type {number} */ var maxCodeLength = table[1]; /** @type {number} code length & code (16bit, 16bit) */ var codeWithLength; /** @type {number} code bits length */ var codeLength; // not enough buffer while (bitsbuflen < maxCodeLength) { if (ip >= inputLength) { break; } bitsbuf |= input[ip++] << bitsbuflen; bitsbuflen += 8; } // read max length codeWithLength = codeTable[bitsbuf & ((1 << maxCodeLength) - 1)]; codeLength = codeWithLength >>> 16; if (codeLength > bitsbuflen) { throw new Error('invalid code length: ' + codeLength); } this.bitsbuf = bitsbuf >> codeLength; this.bitsbuflen = bitsbuflen - codeLength; this.ip = ip; return codeWithLength & 0xffff; }; /** * parse uncompressed block. */ Zlib.RawInflate.prototype.parseUncompressedBlock = function() { var input = this.input; var ip = this.ip; var output = this.output; var op = this.op; /** @type {number} */ var inputLength = input.length; /** @type {number} block length */ var len; /** @type {number} number for check block length */ var nlen; /** @type {number} output buffer length */ var olength = output.length; /** @type {number} copy counter */ var preCopy; // skip buffered header bits this.bitsbuf = 0; this.bitsbuflen = 0; // len if (ip + 1 >= inputLength) { throw new Error('invalid uncompressed block header: LEN'); } len = input[ip++] | (input[ip++] << 8); // nlen if (ip + 1 >= inputLength) { throw new Error('invalid uncompressed block header: NLEN'); } nlen = input[ip++] | (input[ip++] << 8); // check len & nlen if (len === ~nlen) { throw new Error('invalid uncompressed block header: length verify'); } // check size if (ip + len > input.length) { throw new Error('input buffer is broken'); } // expand buffer switch (this.bufferType) { case Zlib.RawInflate.BufferType.BLOCK: // pre copy while (op + len > output.length) { preCopy = olength - op; len -= preCopy; if (USE_TYPEDARRAY) { output.set(input.subarray(ip, ip + preCopy), op); op += preCopy; ip += preCopy; } else { while (preCopy--) { output[op++] = input[ip++]; } } this.op = op; output = this.expandBufferBlock(); op = this.op; } break; case Zlib.RawInflate.BufferType.ADAPTIVE: while (op + len > output.length) { output = this.expandBufferAdaptive({fixRatio: 2}); } break; default: throw new Error('invalid inflate mode'); } // copy if (USE_TYPEDARRAY) { output.set(input.subarray(ip, ip + len), op); op += len; ip += len; } else { while (len--) { output[op++] = input[ip++]; } } this.ip = ip; this.op = op; this.output = output; }; /** * parse fixed huffman block. */ Zlib.RawInflate.prototype.parseFixedHuffmanBlock = function() { switch (this.bufferType) { case Zlib.RawInflate.BufferType.ADAPTIVE: this.decodeHuffmanAdaptive( Zlib.RawInflate.FixedLiteralLengthTable, Zlib.RawInflate.FixedDistanceTable ); break; case Zlib.RawInflate.BufferType.BLOCK: this.decodeHuffmanBlock( Zlib.RawInflate.FixedLiteralLengthTable, Zlib.RawInflate.FixedDistanceTable ); break; default: throw new Error('invalid inflate mode'); } }; /** * parse dynamic huffman block. */ Zlib.RawInflate.prototype.parseDynamicHuffmanBlock = function() { /** @type {number} number of literal and length codes. */ var hlit = this.readBits(5) + 257; /** @type {number} number of distance codes. */ var hdist = this.readBits(5) + 1; /** @type {number} number of code lengths. */ var hclen = this.readBits(4) + 4; /** @type {!(Uint8Array|Array.<number>)} code lengths. */ var codeLengths = new (USE_TYPEDARRAY ? Uint8Array : Array)(Zlib.RawInflate.Order.length); /** @type {!Array} code lengths table. */ var codeLengthsTable; /** @type {!(Uint8Array|Array.<number>)} literal and length code table. */ var litlenTable; /** @type {!(Uint8Array|Array.<number>)} distance code table. */ var distTable; /** @type {!(Uint8Array|Array.<number>)} code length table. */ var lengthTable; /** @type {number} */ var code; /** @type {number} */ var prev; /** @type {number} */ var repeat; /** @type {number} loop counter. */ var i; /** @type {number} loop limit. */ var il; // decode code lengths for (i = 0; i < hclen; ++i) { codeLengths[Zlib.RawInflate.Order[i]] = this.readBits(3); } if (!USE_TYPEDARRAY) { for (i = hclen, hclen = codeLengths.length; i < hclen; ++i) { codeLengths[Zlib.RawInflate.Order[i]] = 0; } } // decode length table codeLengthsTable = buildHuffmanTable(codeLengths); lengthTable = new (USE_TYPEDARRAY ? Uint8Array : Array)(hlit + hdist); for (i = 0, il = hlit + hdist; i < il;) { code = this.readCodeByTable(codeLengthsTable); switch (code) { case 16: repeat = 3 + this.readBits(2); while (repeat--) { lengthTable[i++] = prev; } break; case 17: repeat = 3 + this.readBits(3); while (repeat--) { lengthTable[i++] = 0; } prev = 0; break; case 18: repeat = 11 + this.readBits(7); while (repeat--) { lengthTable[i++] = 0; } prev = 0; break; default: lengthTable[i++] = code; prev = code; break; } } litlenTable = USE_TYPEDARRAY ? buildHuffmanTable(lengthTable.subarray(0, hlit)) : buildHuffmanTable(lengthTable.slice(0, hlit)); distTable = USE_TYPEDARRAY ? buildHuffmanTable(lengthTable.subarray(hlit)) : buildHuffmanTable(lengthTable.slice(hlit)); switch (this.bufferType) { case Zlib.RawInflate.BufferType.ADAPTIVE: this.decodeHuffmanAdaptive(litlenTable, distTable); break; case Zlib.RawInflate.BufferType.BLOCK: this.decodeHuffmanBlock(litlenTable, distTable); break; default: throw new Error('invalid inflate mode'); } }; /** * decode huffman code * @param {!(Array.<number>|Uint16Array)} litlen literal and length code table. * @param {!(Array.<number>|Uint8Array)} dist distination code table. */ Zlib.RawInflate.prototype.decodeHuffmanBlock = function(litlen, dist) { var output = this.output; var op = this.op; this.currentLitlenTable = litlen; /** @type {number} output position limit. */ var olength = output.length - Zlib.RawInflate.MaxCopyLength; /** @type {number} huffman code. */ var code; /** @type {number} table index. */ var ti; /** @type {number} huffman code distination. */ var codeDist; /** @type {number} huffman code length. */ var codeLength; var lengthCodeTable = Zlib.RawInflate.LengthCodeTable; var lengthExtraTable = Zlib.RawInflate.LengthExtraTable; var distCodeTable = Zlib.RawInflate.DistCodeTable; var distExtraTable = Zlib.RawInflate.DistExtraTable; while ((code = this.readCodeByTable(litlen)) !== 256) { // literal if (code < 256) { if (op >= olength) { this.op = op; output = this.expandBufferBlock(); op = this.op; } output[op++] = code; continue; } // length code ti = code - 257; codeLength = lengthCodeTable[ti]; if (lengthExtraTable[ti] > 0) { codeLength += this.readBits(lengthExtraTable[ti]); } // dist code code = this.readCodeByTable(dist); codeDist = distCodeTable[code]; if (distExtraTable[code] > 0) { codeDist += this.readBits(distExtraTable[code]); } // lz77 decode if (op >= olength) { this.op = op; output = this.expandBufferBlock(); op = this.op; } while (codeLength--) { output[op] = output[(op++) - codeDist]; } } while (this.bitsbuflen >= 8) { this.bitsbuflen -= 8; this.ip--; } this.op = op; }; /** * decode huffman code (adaptive) * @param {!(Array.<number>|Uint16Array)} litlen literal and length code table. * @param {!(Array.<number>|Uint8Array)} dist distination code table. */ Zlib.RawInflate.prototype.decodeHuffmanAdaptive = function(litlen, dist) { var output = this.output; var op = this.op; this.currentLitlenTable = litlen; /** @type {number} output position limit. */ var olength = output.length; /** @type {number} huffman code. */ var code; /** @type {number} table index. */ var ti; /** @type {number} huffman code distination. */ var codeDist; /** @type {number} huffman code length. */ var codeLength; var lengthCodeTable = Zlib.RawInflate.LengthCodeTable; var lengthExtraTable = Zlib.RawInflate.LengthExtraTable; var distCodeTable = Zlib.RawInflate.DistCodeTable; var distExtraTable = Zlib.RawInflate.DistExtraTable; while ((code = this.readCodeByTable(litlen)) !== 256) { // literal if (code < 256) { if (op >= olength) { output = this.expandBufferAdaptive(); olength = output.length; } output[op++] = code; continue; } // length code ti = code - 257; codeLength = lengthCodeTable[ti]; if (lengthExtraTable[ti] > 0) { codeLength += this.readBits(lengthExtraTable[ti]); } // dist code code = this.readCodeByTable(dist); codeDist = distCodeTable[code]; if (distExtraTable[code] > 0) { codeDist += this.readBits(distExtraTable[code]); } // lz77 decode if (op + codeLength > olength) { output = this.expandBufferAdaptive(); olength = output.length; } while (codeLength--) { output[op] = output[(op++) - codeDist]; } } while (this.bitsbuflen >= 8) { this.bitsbuflen -= 8; this.ip--; } this.op = op; }; /** * expand output buffer. * @param {Object=} opt_param option parameters. * @return {!(Array.<number>|Uint8Array)} output buffer. */ Zlib.RawInflate.prototype.expandBufferBlock = function(opt_param) { /** @type {!(Array.<number>|Uint8Array)} store buffer. */ var buffer = new (USE_TYPEDARRAY ? Uint8Array : Array)( this.op - Zlib.RawInflate.MaxBackwardLength ); /** @type {number} backward base point */ var backward = this.op - Zlib.RawInflate.MaxBackwardLength; /** @type {number} copy index. */ var i; /** @type {number} copy limit */ var il; var output = this.output; // copy to output buffer if (USE_TYPEDARRAY) { buffer.set(output.subarray(Zlib.RawInflate.MaxBackwardLength, buffer.length)); } else { for (i = 0, il = buffer.length; i < il; ++i) { buffer[i] = output[i + Zlib.RawInflate.MaxBackwardLength]; } } this.blocks.push(buffer); this.totalpos += buffer.length; // copy to backward buffer if (USE_TYPEDARRAY) { output.set( output.subarray(backward, backward + Zlib.RawInflate.MaxBackwardLength) ); } else { for (i = 0; i < Zlib.RawInflate.MaxBackwardLength; ++i) { output[i] = output[backward + i]; } } this.op = Zlib.RawInflate.MaxBackwardLength; return output; }; /** * expand output buffer. (adaptive) * @param {Object=} opt_param option parameters. * @return {!(Array.<number>|Uint8Array)} output buffer pointer. */ Zlib.RawInflate.prototype.expandBufferAdaptive = function(opt_param) { /** @type {!(Array.<number>|Uint8Array)} store buffer. */ var buffer; /** @type {number} expantion ratio. */ var ratio = (this.input.length / this.ip + 1) | 0; /** @type {number} maximum number of huffman code. */ var maxHuffCode; /** @type {number} new output buffer size. */ var newSize; /** @type {number} max inflate size. */ var maxInflateSize; var input = this.input; var output = this.output; if (opt_param) { if (typeof opt_param.fixRatio === 'number') { ratio = opt_param.fixRatio; } if (typeof opt_param.addRatio === 'number') { ratio += opt_param.addRatio; } } // calculate new buffer size if (ratio < 2) { maxHuffCode = (input.length - this.ip) / this.currentLitlenTable[2]; maxInflateSize = (maxHuffCode / 2 * 258) | 0; newSize = maxInflateSize < output.length ? output.length + maxInflateSize : output.length << 1; } else { newSize = output.length * ratio; } // buffer expantion if (USE_TYPEDARRAY) { buffer = new Uint8Array(newSize); buffer.set(output); } else { buffer = output; } this.output = buffer; return this.output; }; /** * concat output buffer. * @return {!(Array.<number>|Uint8Array)} output buffer. */ Zlib.RawInflate.prototype.concatBufferBlock = function() { /** @type {number} buffer pointer. */ var pos = 0; /** @type {number} buffer pointer. */ var limit = this.totalpos + (this.op - Zlib.RawInflate.MaxBackwardLength); /** @type {!(Array.<number>|Uint8Array)} output block array. */ var output = this.output; /** @type {!Array} blocks array. */ var blocks = this.blocks; /** @type {!(Array.<number>|Uint8Array)} output block array. */ var block; /** @type {!(Array.<number>|Uint8Array)} output buffer. */ var buffer = new (USE_TYPEDARRAY ? Uint8Array : Array)(limit); /** @type {number} loop counter. */ var i; /** @type {number} loop limiter. */ var il; /** @type {number} loop counter. */ var j; /** @type {number} loop limiter. */ var jl; // single buffer if (blocks.length === 0) { return USE_TYPEDARRAY ? this.output.subarray(Zlib.RawInflate.MaxBackwardLength, this.op) : this.output.slice(Zlib.RawInflate.MaxBackwardLength, this.op); } // copy to buffer for (i = 0, il = blocks.length; i < il; ++i) { block = blocks[i]; for (j = 0, jl = block.length; j < jl; ++j) { buffer[pos++] = block[j]; } } // current buffer for (i = Zlib.RawInflate.MaxBackwardLength, il = this.op; i < il; ++i) { buffer[pos++] = output[i]; } this.blocks = []; this.buffer = buffer; return this.buffer; }; /** * concat output buffer. (dynamic) * @return {!(Array.<number>|Uint8Array)} output buffer. */ Zlib.RawInflate.prototype.concatBufferDynamic = function() { /** @type {Array.<number>|Uint8Array} output buffer. */ var buffer; var op = this.op; if (USE_TYPEDARRAY) { if (this.resize) { buffer = new Uint8Array(op); buffer.set(this.output.subarray(0, op)); } else { buffer = this.output.subarray(0, op); } } else { if (this.output.length > op) { this.output.length = op; } buffer = this.output; } this.buffer = buffer; return this.buffer; }; var buildHuffmanTable = Zlib.Huffman.buildHuffmanTable; /** * @param {!(Uint8Array|Array.<number>)} input input buffer. * @param {number} ip input buffer pointer. * @param {number=} opt_buffersize buffer block size. * @constructor */ Zlib.RawInflateStream = function(input, ip, opt_buffersize) { /** @type {!Array.<(Array|Uint8Array)>} */ this.blocks = []; /** @type {number} block size. */ this.bufferSize = opt_buffersize ? opt_buffersize : ZLIB_STREAM_RAW_INFLATE_BUFFER_SIZE; /** @type {!number} total output buffer pointer. */ this.totalpos = 0; /** @type {!number} input buffer pointer. */ this.ip = ip === void 0 ? 0 : ip; /** @type {!number} bit stream reader buffer. */ this.bitsbuf = 0; /** @type {!number} bit stream reader buffer size. */ this.bitsbuflen = 0; /** @type {!(Array|Uint8Array)} input buffer. */ this.input = USE_TYPEDARRAY ? new Uint8Array(input) : input; /** @type {!(Uint8Array|Array)} output buffer. */ this.output = new (USE_TYPEDARRAY ? Uint8Array : Array)(this.bufferSize); /** @type {!number} output buffer pointer. */ this.op = 0; /** @type {boolean} is final block flag. */ this.bfinal = false; /** @type {number} uncompressed block length. */ this.blockLength; /** @type {boolean} resize flag for memory size optimization. */ this.resize = false; /** @type {Array} */ this.litlenTable; /** @type {Array} */ this.distTable; /** @type {number} */ this.sp = 0; // stream pointer /** @type {Zlib.RawInflateStream.Status} */ this.status = Zlib.RawInflateStream.Status.INITIALIZED; // // backup // /** @type {!number} */ this.ip_; /** @type {!number} */ this.bitsbuflen_; /** @type {!number} */ this.bitsbuf_; }; /** * @enum {number} */ Zlib.RawInflateStream.BlockType = { UNCOMPRESSED: 0, FIXED: 1, DYNAMIC: 2 }; /** * @enum {number} */ Zlib.RawInflateStream.Status = { INITIALIZED: 0, BLOCK_HEADER_START: 1, BLOCK_HEADER_END: 2, BLOCK_BODY_START: 3, BLOCK_BODY_END: 4, DECODE_BLOCK_START: 5, DECODE_BLOCK_END: 6 }; /** * decompress. * @return {!(Uint8Array|Array)} inflated buffer. */ Zlib.RawInflateStream.prototype.decompress = function(newInput, ip) { /** @type {boolean} */ var stop = false; if (newInput !== void 0) { this.input = newInput; } if (ip !== void 0) { this.ip = ip; } // decompress while (!stop) { switch (this.status) { // block header case Zlib.RawInflateStream.Status.INITIALIZED: case Zlib.RawInflateStream.Status.BLOCK_HEADER_START: if (this.readBlockHeader() < 0) { stop = true; } break; // block body case Zlib.RawInflateStream.Status.BLOCK_HEADER_END: /* FALLTHROUGH */ case Zlib.RawInflateStream.Status.BLOCK_BODY_START: switch(this.currentBlockType) { case Zlib.RawInflateStream.BlockType.UNCOMPRESSED: if (this.readUncompressedBlockHeader() < 0) { stop = true; } break; case Zlib.RawInflateStream.BlockType.FIXED: if (this.parseFixedHuffmanBlock() < 0) { stop = true; } break; case Zlib.RawInflateStream.BlockType.DYNAMIC: if (this.parseDynamicHuffmanBlock() < 0) { stop = true; } break; } break; // decode data case Zlib.RawInflateStream.Status.BLOCK_BODY_END: case Zlib.RawInflateStream.Status.DECODE_BLOCK_START: switch(this.currentBlockType) { case Zlib.RawInflateStream.BlockType.UNCOMPRESSED: if (this.parseUncompressedBlock() < 0) { stop = true; } break; case Zlib.RawInflateStream.BlockType.FIXED: /* FALLTHROUGH */ case Zlib.RawInflateStream.BlockType.DYNAMIC: if (this.decodeHuffman() < 0) { stop = true; } break; } break; case Zlib.RawInflateStream.Status.DECODE_BLOCK_END: if (this.bfinal) { stop = true; } else { this.status = Zlib.RawInflateStream.Status.INITIALIZED; } break; } } return this.concatBuffer(); }; /** * @const * @type {number} max backward length for LZ77. */ Zlib.RawInflateStream.MaxBackwardLength = 32768; /** * @const * @type {number} max copy length for LZ77. */ Zlib.RawInflateStream.MaxCopyLength = 258; /** * huffman order * @const * @type {!(Array.<number>|Uint8Array)} */ Zlib.RawInflateStream.Order = (function(table) { return USE_TYPEDARRAY ? new Uint16Array(table) : table; })([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); /** * huffman length code table. * @const * @type {!(Array.<number>|Uint16Array)} */ Zlib.RawInflateStream.LengthCodeTable = (function(table) { return USE_TYPEDARRAY ? new Uint16Array(table) : table; })([ 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000d, 0x000f, 0x0011, 0x0013, 0x0017, 0x001b, 0x001f, 0x0023, 0x002b, 0x0033, 0x003b, 0x0043, 0x0053, 0x0063, 0x0073, 0x0083, 0x00a3, 0x00c3, 0x00e3, 0x0102, 0x0102, 0x0102 ]); /** * huffman length extra-bits table. * @const * @type {!(Array.<number>|Uint8Array)} */ Zlib.RawInflateStream.LengthExtraTable = (function(table) { return USE_TYPEDARRAY ? new Uint8Array(table) : table; })([ 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, 0, 0 ]); /** * huffman dist code table. * @const * @type {!(Array.<number>|Uint16Array)} */ Zlib.RawInflateStream.DistCodeTable = (function(table) { return USE_TYPEDARRAY ? new Uint16Array(table) : table; })([ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d, 0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1, 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01, 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001 ]); /** * huffman dist extra-bits table. * @const * @type {!(Array.<number>|Uint8Array)} */ Zlib.RawInflateStream.DistExtraTable = (function(table) { return USE_TYPEDARRAY ? new Uint8Array(table) : table; })([ 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 ]); /** * fixed huffman length code table * @const * @type {!Array} */ Zlib.RawInflateStream.FixedLiteralLengthTable = (function(table) { return table; })((function() { var lengths = new (USE_TYPEDARRAY ? Uint8Array : Array)(288); var i, il; for (i = 0, il = lengths.length; i < il; ++i) { lengths[i] = (i <= 143) ? 8 : (i <= 255) ? 9 : (i <= 279) ? 7 : 8; } return buildHuffmanTable(lengths); })()); /** * fixed huffman distance code table * @const * @type {!Array} */ Zlib.RawInflateStream.FixedDistanceTable = (function(table) { return table; })((function() { var lengths = new (USE_TYPEDARRAY ? Uint8Array : Array)(30); var i, il; for (i = 0, il = lengths.length; i < il; ++i) { lengths[i] = 5; } return buildHuffmanTable(lengths); })()); /** * parse deflated block. */ Zlib.RawInflateStream.prototype.readBlockHeader = function() { /** @type {number} header */ var hdr; this.status = Zlib.RawInflateStream.Status.BLOCK_HEADER_START; this.save_(); if ((hdr = this.readBits(3)) < 0) { this.restore_(); return -1; } // BFINAL if (hdr & 0x1) { this.bfinal = true; } // BTYPE hdr >>>= 1; switch (hdr) { case 0: // uncompressed this.currentBlockType = Zlib.RawInflateStream.BlockType.UNCOMPRESSED; break; case 1: // fixed huffman this.currentBlockType = Zlib.RawInflateStream.BlockType.FIXED; break; case 2: // dynamic huffman this.currentBlockType = Zlib.RawInflateStream.BlockType.DYNAMIC; break; default: // reserved or other throw new Error('unknown BTYPE: ' + hdr); } this.status = Zlib.RawInflateStream.Status.BLOCK_HEADER_END; }; /** * read inflate bits * @param {number} length bits length. * @return {number} read bits. */ Zlib.RawInflateStream.prototype.readBits = function(length) { var bitsbuf = this.bitsbuf; var bitsbuflen = this.bitsbuflen; var input = this.input; var ip = this.ip; /** @type {number} input and output byte. */ var octet; // not enough buffer while (bitsbuflen < length) { // input byte if (input.length <= ip) { return -1; } octet = input[ip++]; // concat octet bitsbuf |= octet << bitsbuflen; bitsbuflen += 8; } // output byte octet = bitsbuf & /* MASK */ ((1 << length) - 1); bitsbuf >>>= length; bitsbuflen -= length; this.bitsbuf = bitsbuf; this.bitsbuflen = bitsbuflen; this.ip = ip; return octet; }; /** * read huffman code using table * @param {Array} table huffman code table. * @return {number} huffman code. */ Z