hic-straw
Version:
Utilities for reading .files (contact matrix files)
1,920 lines (1,686 loc) • 150 kB
JavaScript
// 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