aboutsummaryrefslogtreecommitdiff
path: root/js/decode.js
diff options
context:
space:
mode:
authorEugene Kliuchnikov <eustas@google.com>2019-04-12 13:57:42 +0200
committerGitHub <noreply@github.com>2019-04-12 13:57:42 +0200
commit4b2b2d4f83ffeaac7708e44409fe34896a01a278 (patch)
tree04dff6010a8fad91ba93eff45a8730ed5fc40f14 /js/decode.js
parent9cd01c0437e8b6010434d3491a348a5645de624b (diff)
downloadbrotli-4b2b2d4f83ffeaac7708e44409fe34896a01a278.zip
brotli-4b2b2d4f83ffeaac7708e44409fe34896a01a278.tar.gz
brotli-4b2b2d4f83ffeaac7708e44409fe34896a01a278.tar.bz2
Update (#749)
Update: * Bazel: fix MSVC configuration * C: common: extended documentation and helpers around distance codes * C: common: enable BROTLI_DCHECK in "debug" builds * C: common: fix implicit trailing zero in `kPrefixSuffix` * C: dec: fix possible bit reader discharge for "large-window" mode * C: dec: simplify distance decoding via lookup table * C: dec: reuse decoder state members memory via union with lookup table * C: dec: add decoder state diagram * C: enc: clarify access to static dictionary * C: enc: improve static dictionary hash * C: enc: add "stream offset" parameter for parallel encoding * C: enc: reorganize hasher; now Q2-Q3 require exactly 256KiB to avoid global TCMalloc lock * C: enc: fix rare access to uninitialized data in ring-buffer * C: enc: reorganize logging / checks in `write_bits.h` * Java: dec: add "large-window" support * Java: dec: improve speed * Java: dec: debug and 32-bit mode are now activated via system properties * Java: dec: demystify some state variables (use better names) * Dictionary generator: add single input mode * Java: dec: modernize tests * Bazel: js: pick working commit for closure rules
Diffstat (limited to 'js/decode.js')
-rwxr-xr-x[-rw-r--r--]js/decode.js1155
1 files changed, 725 insertions, 430 deletions
diff --git a/js/decode.js b/js/decode.js
index 40a4df7..7896a50 100644..100755
--- a/js/decode.js
+++ b/js/decode.js
@@ -22,25 +22,98 @@ function BrotliDecodeClosure() {
/** @type {!number} */
this.offset = 0;
}
+ var MAX_HUFFMAN_TABLE_SIZE = Int32Array.from([256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822, 854, 886, 920, 952, 984, 1016, 1048, 1080]);
var CODE_LENGTH_CODE_ORDER = Int32Array.from([1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
- var DISTANCE_SHORT_CODE_INDEX_OFFSET = Int32Array.from([3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2]);
+ var DISTANCE_SHORT_CODE_INDEX_OFFSET = Int32Array.from([0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3]);
var DISTANCE_SHORT_CODE_VALUE_OFFSET = Int32Array.from([0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3]);
var FIXED_TABLE = Int32Array.from([0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040001, 0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040005]);
var DICTIONARY_OFFSETS_BY_LENGTH = Int32Array.from([0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032, 53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536, 115968, 118528, 119872, 121280, 122016]);
var DICTIONARY_SIZE_BITS_BY_LENGTH = Int32Array.from([0, 0, 0, 0, 10, 10, 11, 11, 10, 10, 10, 10, 10, 9, 9, 8, 7, 7, 8, 7, 7, 6, 6, 5, 5]);
var BLOCK_LENGTH_OFFSET = Int32Array.from([1, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 145, 177, 209, 241, 305, 369, 497, 753, 1265, 2289, 4337, 8433, 16625]);
var BLOCK_LENGTH_N_BITS = Int32Array.from([2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 24]);
- var INSERT_LENGTH_OFFSET = Int32Array.from([0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594]);
- var INSERT_LENGTH_N_BITS = Int32Array.from([0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24]);
- var COPY_LENGTH_OFFSET = Int32Array.from([2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118]);
- var COPY_LENGTH_N_BITS = Int32Array.from([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24]);
- var INSERT_RANGE_LUT = Int32Array.from([0, 0, 8, 8, 0, 16, 8, 16, 16]);
- var COPY_RANGE_LUT = Int32Array.from([0, 8, 0, 8, 16, 0, 16, 8, 16]);
+ var INSERT_LENGTH_N_BITS = Int16Array.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0E, 0x18]);
+ var COPY_LENGTH_N_BITS = Int16Array.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x18]);
+ var CMD_LOOKUP = new Int16Array(2816);
+ {
+ unpackCommandLookupTable(CMD_LOOKUP);
+ }
+ /**
+ * @param {number} i
+ * @return {number}
+ */
+ function log2floor(i) {
+ var /** number */ result = -1;
+ var /** number */ step = 16;
+ while (step > 0) {
+ if ((i >>> step) != 0) {
+ result += step;
+ i = i >>> step;
+ }
+ step = step >> 1;
+ }
+ return result + i;
+ }
+ /**
+ * @param {number} npostfix
+ * @param {number} ndirect
+ * @param {number} maxndistbits
+ * @return {number}
+ */
+ function calculateDistanceAlphabetSize(npostfix, ndirect, maxndistbits) {
+ return 16 + ndirect + 2 * (maxndistbits << npostfix);
+ }
+ /**
+ * @param {number} maxDistance
+ * @param {number} npostfix
+ * @param {number} ndirect
+ * @return {number}
+ */
+ function calculateDistanceAlphabetLimit(maxDistance, npostfix, ndirect) {
+ if (maxDistance < ndirect + (2 << npostfix)) {
+ throw "maxDistance is too small";
+ }
+ var /** number */ offset = ((maxDistance - ndirect) >> npostfix) + 4;
+ var /** number */ ndistbits = log2floor(offset) - 1;
+ var /** number */ group = ((ndistbits - 1) << 1) | ((offset >> ndistbits) & 1);
+ return ((group - 1) << npostfix) + (1 << npostfix) + ndirect + 16;
+ }
+ /**
+ * @param {!Int16Array} cmdLookup
+ * @return {void}
+ */
+ function unpackCommandLookupTable(cmdLookup) {
+ var /** !Int16Array */ insertLengthOffsets = new Int16Array(24);
+ var /** !Int16Array */ copyLengthOffsets = new Int16Array(24);
+ copyLengthOffsets[0] = 2;
+ for (var /** number */ i = 0; i < 23; ++i) {
+ insertLengthOffsets[i + 1] = (insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i]));
+ copyLengthOffsets[i + 1] = (copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i]));
+ }
+ for (var /** number */ cmdCode = 0; cmdCode < 704; ++cmdCode) {
+ var /** number */ rangeIdx = cmdCode >>> 6;
+ var /** number */ distanceContextOffset = -4;
+ if (rangeIdx >= 2) {
+ rangeIdx -= 2;
+ distanceContextOffset = 0;
+ }
+ var /** number */ insertCode = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7);
+ var /** number */ copyCode = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7);
+ var /** number */ copyLengthOffset = copyLengthOffsets[copyCode];
+ var /** number */ distanceContext = distanceContextOffset + (copyLengthOffset > 4 ? 3 : copyLengthOffset - 2);
+ var /** number */ index = cmdCode * 4;
+ cmdLookup[index + 0] = (INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8));
+ cmdLookup[index + 1] = insertLengthOffsets[insertCode];
+ cmdLookup[index + 2] = copyLengthOffsets[copyCode];
+ cmdLookup[index + 3] = distanceContext;
+ }
+ }
/**
* @param {!State} s
- * @return {!number}
+ * @return {number}
*/
function decodeWindowBits(s) {
+ var /** number */ largeWindowEnabled = s.isLargeWindow;
+ s.isLargeWindow = 0;
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
@@ -48,18 +121,53 @@ function BrotliDecodeClosure() {
if (readFewBits(s, 1) == 0) {
return 16;
}
- var /** !number */ n = readFewBits(s, 3);
+ var /** number */ n = readFewBits(s, 3);
if (n != 0) {
return 17 + n;
}
n = readFewBits(s, 3);
if (n != 0) {
- return 8 + n;
+ if (n == 1) {
+ if (largeWindowEnabled == 0) {
+ return -1;
+ }
+ s.isLargeWindow = 1;
+ if (readFewBits(s, 1) == 1) {
+ return -1;
+ }
+ n = readFewBits(s, 6);
+ if (n < 10 || n > 30) {
+ return -1;
+ }
+ return n;
+ } else {
+ return 8 + n;
+ }
}
return 17;
}
/**
* @param {!State} s
+ * @return {void}
+ */
+ function enableEagerOutput(s) {
+ if (s.runningState != 1) {
+ throw "State MUST be freshly initialized";
+ }
+ s.isEager = 1;
+ }
+ /**
+ * @param {!State} s
+ * @return {void}
+ */
+ function enableLargeWindow(s) {
+ if (s.runningState != 1) {
+ throw "State MUST be freshly initialized";
+ }
+ s.isLargeWindow = 1;
+ }
+ /**
+ * @param {!State} s
* @param {!InputStream} input
* @return {void}
*/
@@ -67,15 +175,14 @@ function BrotliDecodeClosure() {
if (s.runningState != 0) {
throw "State MUST be uninitialized";
}
- s.blockTrees = new Int32Array(6480);
+ s.blockTrees = new Int32Array(3091);
+ s.blockTrees[0] = 7;
+ s.distRbIdx = 3;
+ var /** number */ maxDistanceAlphabetLimit = calculateDistanceAlphabetLimit(0x7FFFFFFC, 3, 15 << 3);
+ s.distExtraBits = new Int8Array(maxDistanceAlphabetLimit);
+ s.distOffset = new Int32Array(maxDistanceAlphabetLimit);
s.input = input;
initBitReader(s);
- var /** !number */ windowBits = decodeWindowBits(s);
- if (windowBits == 9) {
- throw "Invalid 'windowBits' code";
- }
- s.maxRingBufferSize = 1 << windowBits;
- s.maxBackwardDistance = s.maxRingBufferSize - 16;
s.runningState = 1;
}
/**
@@ -86,10 +193,10 @@ function BrotliDecodeClosure() {
if (s.runningState == 0) {
throw "State MUST be initialized";
}
- if (s.runningState == 10) {
+ if (s.runningState == 11) {
return;
}
- s.runningState = 10;
+ s.runningState = 11;
if (s.input != null) {
closeInput(s.input);
s.input = null;
@@ -97,7 +204,7 @@ function BrotliDecodeClosure() {
}
/**
* @param {!State} s
- * @return {!number}
+ * @return {number}
*/
function decodeVarLenUnsignedByte(s) {
if (s.bitOffset >= 16) {
@@ -105,7 +212,7 @@ function BrotliDecodeClosure() {
s.bitOffset -= 16;
}
if (readFewBits(s, 1) != 0) {
- var /** !number */ n = readFewBits(s, 3);
+ var /** number */ n = readFewBits(s, 3);
if (n == 0) {
return 1;
} else {
@@ -130,34 +237,34 @@ function BrotliDecodeClosure() {
if ((s.inputEnd != 0) && readFewBits(s, 1) != 0) {
return;
}
- var /** !number */ sizeNibbles = readFewBits(s, 2) + 4;
+ var /** number */ sizeNibbles = readFewBits(s, 2) + 4;
if (sizeNibbles == 7) {
s.isMetadata = 1;
if (readFewBits(s, 1) != 0) {
throw "Corrupted reserved bit";
}
- var /** !number */ sizeBytes = readFewBits(s, 2);
+ var /** number */ sizeBytes = readFewBits(s, 2);
if (sizeBytes == 0) {
return;
}
- for (var /** !number */ i = 0; i < sizeBytes; i++) {
+ for (var /** number */ i = 0; i < sizeBytes; i++) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ bits = readFewBits(s, 8);
+ var /** number */ bits = readFewBits(s, 8);
if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {
throw "Exuberant nibble";
}
s.metaBlockLength |= bits << (i * 8);
}
} else {
- for (var /** !number */ i = 0; i < sizeNibbles; i++) {
+ for (var /** number */ i = 0; i < sizeNibbles; i++) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ bits = readFewBits(s, 4);
+ var /** number */ bits = readFewBits(s, 4);
if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {
throw "Exuberant nibble";
}
@@ -170,39 +277,40 @@ function BrotliDecodeClosure() {
}
}
/**
- * @param {!Int32Array} table
- * @param {!number} offset
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
* @param {!State} s
- * @return {!number}
+ * @return {number}
*/
- function readSymbol(table, offset, s) {
- var /** !number */ val = (s.accumulator32 >>> s.bitOffset);
+ function readSymbol(tableGroup, tableIdx, s) {
+ var /** number */ offset = tableGroup[tableIdx];
+ var /** number */ val = (s.accumulator32 >>> s.bitOffset);
offset += val & 0xFF;
- var /** !number */ bits = table[offset] >> 16;
- var /** !number */ sym = table[offset] & 0xFFFF;
+ var /** number */ bits = tableGroup[offset] >> 16;
+ var /** number */ sym = tableGroup[offset] & 0xFFFF;
if (bits <= 8) {
s.bitOffset += bits;
return sym;
}
offset += sym;
- var /** !number */ mask = (1 << bits) - 1;
+ var /** number */ mask = (1 << bits) - 1;
offset += (val & mask) >>> 8;
- s.bitOffset += ((table[offset] >> 16) + 8);
- return table[offset] & 0xFFFF;
+ s.bitOffset += ((tableGroup[offset] >> 16) + 8);
+ return tableGroup[offset] & 0xFFFF;
}
/**
- * @param {!Int32Array} table
- * @param {!number} offset
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
* @param {!State} s
- * @return {!number}
+ * @return {number}
*/
- function readBlockLength(table, offset, s) {
+ function readBlockLength(tableGroup, tableIdx, s) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ code = readSymbol(table, offset, s);
- var /** !number */ n = BLOCK_LENGTH_N_BITS[code];
+ var /** number */ code = readSymbol(tableGroup, tableIdx, s);
+ var /** number */ n = BLOCK_LENGTH_N_BITS[code];
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
@@ -210,26 +318,12 @@ function BrotliDecodeClosure() {
return BLOCK_LENGTH_OFFSET[code] + ((n <= 16) ? readFewBits(s, n) : readManyBits(s, n));
}
/**
- * @param {!number} code
- * @param {!Int32Array} ringBuffer
- * @param {!number} index
- * @return {!number}
- */
- function translateShortCodes(code, ringBuffer, index) {
- if (code < 16) {
- index += DISTANCE_SHORT_CODE_INDEX_OFFSET[code];
- index &= 3;
- return ringBuffer[index] + DISTANCE_SHORT_CODE_VALUE_OFFSET[code];
- }
- return code - 16 + 1;
- }
- /**
* @param {!Int32Array} v
- * @param {!number} index
+ * @param {number} index
* @return {void}
*/
function moveToFront(v, index) {
- var /** !number */ value = v[index];
+ var /** number */ value = v[index];
for (; index > 0; index--) {
v[index] = v[index - 1];
}
@@ -237,16 +331,16 @@ function BrotliDecodeClosure() {
}
/**
* @param {!Int8Array} v
- * @param {!number} vLen
+ * @param {number} vLen
* @return {void}
*/
function inverseMoveToFrontTransform(v, vLen) {
var /** !Int32Array */ mtf = new Int32Array(256);
- for (var /** !number */ i = 0; i < 256; i++) {
+ for (var /** number */ i = 0; i < 256; i++) {
mtf[i] = i;
}
- for (var /** !number */ i = 0; i < vLen; i++) {
- var /** !number */ index = v[i] & 0xFF;
+ for (var /** number */ i = 0; i < vLen; i++) {
+ var /** number */ index = v[i] & 0xFF;
v[i] = mtf[index];
if (index != 0) {
moveToFront(mtf, index);
@@ -255,19 +349,20 @@ function BrotliDecodeClosure() {
}
/**
* @param {!Int32Array} codeLengthCodeLengths
- * @param {!number} numSymbols
+ * @param {number} numSymbols
* @param {!Int32Array} codeLengths
* @param {!State} s
* @return {void}
*/
function readHuffmanCodeLengths(codeLengthCodeLengths, numSymbols, codeLengths, s) {
- var /** !number */ symbol = 0;
- var /** !number */ prevCodeLen = 8;
- var /** !number */ repeat = 0;
- var /** !number */ repeatCodeLen = 0;
- var /** !number */ space = 32768;
- var /** !Int32Array */ table = new Int32Array(32);
- buildHuffmanTable(table, 0, 5, codeLengthCodeLengths, 18);
+ var /** number */ symbol = 0;
+ var /** number */ prevCodeLen = 8;
+ var /** number */ repeat = 0;
+ var /** number */ repeatCodeLen = 0;
+ var /** number */ space = 32768;
+ var /** !Int32Array */ table = new Int32Array(32 + 1);
+ var /** number */ tableIdx = table.length - 1;
+ buildHuffmanTable(table, tableIdx, 5, codeLengthCodeLengths, 18);
while (symbol < numSymbols && space > 0) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
@@ -276,9 +371,9 @@ function BrotliDecodeClosure() {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ p = (s.accumulator32 >>> s.bitOffset) & 31;
+ var /** number */ p = (s.accumulator32 >>> s.bitOffset) & 31;
s.bitOffset += table[p] >> 16;
- var /** !number */ codeLen = table[p] & 0xFFFF;
+ var /** number */ codeLen = table[p] & 0xFFFF;
if (codeLen < 16) {
repeat = 0;
codeLengths[symbol++] = codeLen;
@@ -287,8 +382,8 @@ function BrotliDecodeClosure() {
space -= 32768 >> codeLen;
}
} else {
- var /** !number */ extraBits = codeLen - 14;
- var /** !number */ newLen = 0;
+ var /** number */ extraBits = codeLen - 14;
+ var /** number */ newLen = 0;
if (codeLen == 16) {
newLen = prevCodeLen;
}
@@ -296,7 +391,7 @@ function BrotliDecodeClosure() {
repeat = 0;
repeatCodeLen = newLen;
}
- var /** !number */ oldRepeat = repeat;
+ var /** number */ oldRepeat = repeat;
if (repeat > 0) {
repeat -= 2;
repeat <<= extraBits;
@@ -306,11 +401,11 @@ function BrotliDecodeClosure() {
s.bitOffset -= 16;
}
repeat += readFewBits(s, extraBits) + 3;
- var /** !number */ repeatDelta = repeat - oldRepeat;
+ var /** number */ repeatDelta = repeat - oldRepeat;
if (symbol + repeatDelta > numSymbols) {
throw "symbol + repeatDelta > numSymbols";
}
- for (var /** !number */ i = 0; i < repeatDelta; i++) {
+ for (var /** number */ i = 0; i < repeatDelta; i++) {
codeLengths[symbol++] = repeatCodeLen;
}
if (repeatCodeLen != 0) {
@@ -325,112 +420,145 @@ function BrotliDecodeClosure() {
}
/**
* @param {!Int32Array} symbols
- * @param {!number} length
- * @return {!number}
+ * @param {number} length
+ * @return {void}
*/
function checkDupes(symbols, length) {
- for (var /** !number */ i = 0; i < length - 1; ++i) {
- for (var /** !number */ j = i + 1; j < length; ++j) {
+ for (var /** number */ i = 0; i < length - 1; ++i) {
+ for (var /** number */ j = i + 1; j < length; ++j) {
if (symbols[i] == symbols[j]) {
- return 0;
+ throw "Duplicate simple Huffman code symbol";
}
}
}
- return 1;
}
/**
- * @param {!number} alphabetSize
- * @param {!Int32Array} table
- * @param {!number} offset
+ * @param {number} alphabetSizeMax
+ * @param {number} alphabetSizeLimit
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
* @param {!State} s
- * @return {void}
+ * @return {number}
+ */
+ function readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s) {
+ var /** !Int32Array */ codeLengths = new Int32Array(alphabetSizeLimit);
+ var /** !Int32Array */ symbols = new Int32Array(4);
+ var /** number */ maxBits = 1 + log2floor(alphabetSizeMax - 1);
+ var /** number */ numSymbols = readFewBits(s, 2) + 1;
+ for (var /** number */ i = 0; i < numSymbols; i++) {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ symbol = readFewBits(s, maxBits);
+ if (symbol >= alphabetSizeLimit) {
+ throw "Can't readHuffmanCode";
+ }
+ symbols[i] = symbol;
+ }
+ checkDupes(symbols, numSymbols);
+ var /** number */ histogramId = numSymbols;
+ if (numSymbols == 4) {
+ histogramId += readFewBits(s, 1);
+ }
+ switch(histogramId) {
+ case 1:
+ codeLengths[symbols[0]] = 1;
+ break;
+ case 2:
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 1;
+ break;
+ case 3:
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 2;
+ break;
+ case 4:
+ codeLengths[symbols[0]] = 2;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 2;
+ codeLengths[symbols[3]] = 2;
+ break;
+ case 5:
+ codeLengths[symbols[0]] = 1;
+ codeLengths[symbols[1]] = 2;
+ codeLengths[symbols[2]] = 3;
+ codeLengths[symbols[3]] = 3;
+ break;
+ default:
+ break;
+ }
+ return buildHuffmanTable(tableGroup, tableIdx, 8, codeLengths, alphabetSizeLimit);
+ }
+ /**
+ * @param {number} alphabetSizeLimit
+ * @param {number} skip
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {!State} s
+ * @return {number}
*/
- function readHuffmanCode(alphabetSize, table, offset, s) {
- var /** !number */ ok = 1;
- var /** !number */ simpleCodeOrSkip;
+ function readComplexHuffmanCode(alphabetSizeLimit, skip, tableGroup, tableIdx, s) {
+ var /** !Int32Array */ codeLengths = new Int32Array(alphabetSizeLimit);
+ var /** !Int32Array */ codeLengthCodeLengths = new Int32Array(18);
+ var /** number */ space = 32;
+ var /** number */ numCodes = 0;
+ for (var /** number */ i = skip; i < 18 && space > 0; i++) {
+ var /** number */ codeLenIdx = CODE_LENGTH_CODE_ORDER[i];
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ var /** number */ p = (s.accumulator32 >>> s.bitOffset) & 15;
+ s.bitOffset += FIXED_TABLE[p] >> 16;
+ var /** number */ v = FIXED_TABLE[p] & 0xFFFF;
+ codeLengthCodeLengths[codeLenIdx] = v;
+ if (v != 0) {
+ space -= (32 >> v);
+ numCodes++;
+ }
+ }
+ if (space != 0 && numCodes != 1) {
+ throw "Corrupted Huffman code histogram";
+ }
+ readHuffmanCodeLengths(codeLengthCodeLengths, alphabetSizeLimit, codeLengths, s);
+ return buildHuffmanTable(tableGroup, tableIdx, 8, codeLengths, alphabetSizeLimit);
+ }
+ /**
+ * @param {number} alphabetSizeMax
+ * @param {number} alphabetSizeLimit
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {!State} s
+ * @return {number}
+ */
+ function readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
- var /** !Int32Array */ codeLengths = new Int32Array(alphabetSize);
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- simpleCodeOrSkip = readFewBits(s, 2);
+ var /** number */ simpleCodeOrSkip = readFewBits(s, 2);
if (simpleCodeOrSkip == 1) {
- var /** !number */ maxBitsCounter = alphabetSize - 1;
- var /** !number */ maxBits = 0;
- var /** !Int32Array */ symbols = new Int32Array(4);
- var /** !number */ numSymbols = readFewBits(s, 2) + 1;
- while (maxBitsCounter != 0) {
- maxBitsCounter >>= 1;
- maxBits++;
- }
- for (var /** !number */ i = 0; i < numSymbols; i++) {
- if (s.bitOffset >= 16) {
- s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
- s.bitOffset -= 16;
- }
- symbols[i] = readFewBits(s, maxBits) % alphabetSize;
- codeLengths[symbols[i]] = 2;
- }
- codeLengths[symbols[0]] = 1;
- switch(numSymbols) {
- case 2:
- codeLengths[symbols[1]] = 1;
- break;
- case 4:
- if (readFewBits(s, 1) == 1) {
- codeLengths[symbols[2]] = 3;
- codeLengths[symbols[3]] = 3;
- } else {
- codeLengths[symbols[0]] = 2;
- }
- break;
- default:
- break;
- }
- ok = checkDupes(symbols, numSymbols);
+ return readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s);
} else {
- var /** !Int32Array */ codeLengthCodeLengths = new Int32Array(18);
- var /** !number */ space = 32;
- var /** !number */ numCodes = 0;
- for (var /** !number */ i = simpleCodeOrSkip; i < 18 && space > 0; i++) {
- var /** !number */ codeLenIdx = CODE_LENGTH_CODE_ORDER[i];
- if (s.bitOffset >= 16) {
- s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
- s.bitOffset -= 16;
- }
- var /** !number */ p = (s.accumulator32 >>> s.bitOffset) & 15;
- s.bitOffset += FIXED_TABLE[p] >> 16;
- var /** !number */ v = FIXED_TABLE[p] & 0xFFFF;
- codeLengthCodeLengths[codeLenIdx] = v;
- if (v != 0) {
- space -= (32 >> v);
- numCodes++;
- }
- }
- if (space != 0 && numCodes != 1) {
- ok = 0;
- }
- readHuffmanCodeLengths(codeLengthCodeLengths, alphabetSize, codeLengths, s);
- }
- if (ok == 0) {
- throw "Can't readHuffmanCode";
+ return readComplexHuffmanCode(alphabetSizeLimit, simpleCodeOrSkip, tableGroup, tableIdx, s);
}
- buildHuffmanTable(table, offset, 8, codeLengths, alphabetSize);
}
/**
- * @param {!number} contextMapSize
+ * @param {number} contextMapSize
* @param {!Int8Array} contextMap
* @param {!State} s
- * @return {!number}
+ * @return {number}
*/
function decodeContextMap(contextMapSize, contextMap, s) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
- var /** !number */ numTrees = decodeVarLenUnsignedByte(s) + 1;
+ var /** number */ numTrees = decodeVarLenUnsignedByte(s) + 1;
if (numTrees == 1) {
contextMap.fill(0, 0, contextMapSize);
return numTrees;
@@ -439,14 +567,17 @@ function BrotliDecodeClosure() {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ useRleForZeros = readFewBits(s, 1);
- var /** !number */ maxRunLengthPrefix = 0;
+ var /** number */ useRleForZeros = readFewBits(s, 1);
+ var /** number */ maxRunLengthPrefix = 0;
if (useRleForZeros != 0) {
maxRunLengthPrefix = readFewBits(s, 4) + 1;
}
- var /** !Int32Array */ table = new Int32Array(1080);
- readHuffmanCode(numTrees + maxRunLengthPrefix, table, 0, s);
- for (var /** !number */ i = 0; i < contextMapSize; ) {
+ var /** number */ alphabetSize = numTrees + maxRunLengthPrefix;
+ var /** number */ tableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSize + 31) >> 5];
+ var /** !Int32Array */ table = new Int32Array(tableSize + 1);
+ var /** number */ tableIdx = table.length - 1;
+ readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s);
+ for (var /** number */ i = 0; i < contextMapSize; ) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
@@ -454,7 +585,7 @@ function BrotliDecodeClosure() {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ code = readSymbol(table, 0, s);
+ var /** number */ code = readSymbol(table, tableIdx, s);
if (code == 0) {
contextMap[i] = 0;
i++;
@@ -463,7 +594,7 @@ function BrotliDecodeClosure() {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ reps = (1 << code) + readFewBits(s, code);
+ var /** number */ reps = (1 << code) + readFewBits(s, code);
while (reps != 0) {
if (i >= contextMapSize) {
throw "Corrupted context map";
@@ -488,19 +619,19 @@ function BrotliDecodeClosure() {
}
/**
* @param {!State} s
- * @param {!number} treeType
- * @param {!number} numBlockTypes
- * @return {!number}
+ * @param {number} treeType
+ * @param {number} numBlockTypes
+ * @return {number}
*/
function decodeBlockTypeAndLength(s, treeType, numBlockTypes) {
var /** !Int32Array */ ringBuffers = s.rings;
- var /** !number */ offset = 4 + treeType * 2;
+ var /** number */ offset = 4 + treeType * 2;
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ blockType = readSymbol(s.blockTrees, treeType * 1080, s);
- var /** !number */ result = readBlockLength(s.blockTrees, (treeType + 3) * 1080, s);
+ var /** number */ blockType = readSymbol(s.blockTrees, 2 * treeType, s);
+ var /** number */ result = readBlockLength(s.blockTrees, 2 * treeType + 1, s);
if (blockType == 1) {
blockType = ringBuffers[offset + 1] + 1;
} else if (blockType == 0) {
@@ -521,11 +652,10 @@ function BrotliDecodeClosure() {
*/
function decodeLiteralBlockSwitch(s) {
s.literalBlockLength = decodeBlockTypeAndLength(s, 0, s.numLiteralBlockTypes);
- var /** !number */ literalBlockType = s.rings[5];
+ var /** number */ literalBlockType = s.rings[5];
s.contextMapSlice = literalBlockType << 6;
- s.literalTreeIndex = s.contextMap[s.contextMapSlice] & 0xFF;
- s.literalTree = s.hGroup0[s.literalTreeIndex];
- var /** !number */ contextMode = s.contextModes[literalBlockType];
+ s.literalTreeIdx = s.contextMap[s.contextMapSlice] & 0xFF;
+ var /** number */ contextMode = s.contextModes[literalBlockType];
s.contextLookupOffset1 = contextMode << 9;
s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
}
@@ -535,7 +665,7 @@ function BrotliDecodeClosure() {
*/
function decodeCommandBlockSwitch(s) {
s.commandBlockLength = decodeBlockTypeAndLength(s, 1, s.numCommandBlockTypes);
- s.treeCommandOffset = s.hGroup1[s.rings[7]];
+ s.commandTreeIdx = s.rings[7];
}
/**
* @param {!State} s
@@ -550,9 +680,9 @@ function BrotliDecodeClosure() {
* @return {void}
*/
function maybeReallocateRingBuffer(s) {
- var /** !number */ newSize = s.maxRingBufferSize;
+ var /** number */ newSize = s.maxRingBufferSize;
if (newSize > s.expectedTotalSize) {
- var /** !number */ minimalNewSize = s.expectedTotalSize;
+ var /** number */ minimalNewSize = s.expectedTotalSize;
while ((newSize >> 1) > minimalNewSize) {
newSize >>= 1;
}
@@ -563,7 +693,7 @@ function BrotliDecodeClosure() {
if (newSize <= s.ringBufferSize) {
return;
}
- var /** !number */ ringBufferSizeWithSlack = newSize + 37;
+ var /** number */ ringBufferSizeWithSlack = newSize + 37;
var /** !Int8Array */ newBuffer = new Int8Array(ringBufferSizeWithSlack);
if (s.ringBuffer.length != 0) {
newBuffer.set(s.ringBuffer.subarray(0, 0 + s.ringBufferSize), 0);
@@ -577,13 +707,13 @@ function BrotliDecodeClosure() {
*/
function readNextMetablockHeader(s) {
if (s.inputEnd != 0) {
- s.nextRunningState = 9;
- s.runningState = 11;
+ s.nextRunningState = 10;
+ s.runningState = 12;
return;
}
- s.hGroup0 = new Int32Array(0);
- s.hGroup1 = new Int32Array(0);
- s.hGroup2 = new Int32Array(0);
+ s.literalTreeGroup = new Int32Array(0);
+ s.commandTreeGroup = new Int32Array(0);
+ s.distanceTreeGroup = new Int32Array(0);
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
@@ -593,9 +723,9 @@ function BrotliDecodeClosure() {
}
if ((s.isUncompressed != 0) || (s.isMetadata != 0)) {
jumpToByteBoundary(s);
- s.runningState = (s.isMetadata != 0) ? 4 : 5;
+ s.runningState = (s.isMetadata != 0) ? 5 : 6;
} else {
- s.runningState = 2;
+ s.runningState = 3;
}
if (s.isMetadata != 0) {
return;
@@ -610,17 +740,54 @@ function BrotliDecodeClosure() {
}
/**
* @param {!State} s
- * @param {!number} treeType
- * @param {!number} numBlockTypes
- * @return {!number}
+ * @param {number} treeType
+ * @param {number} numBlockTypes
+ * @return {number}
*/
function readMetablockPartition(s, treeType, numBlockTypes) {
+ var /** number */ offset = s.blockTrees[2 * treeType];
if (numBlockTypes <= 1) {
+ s.blockTrees[2 * treeType + 1] = offset;
+ s.blockTrees[2 * treeType + 2] = offset;
return 1 << 28;
}
- readHuffmanCode(numBlockTypes + 2, s.blockTrees, treeType * 1080, s);
- readHuffmanCode(26, s.blockTrees, (treeType + 3) * 1080, s);
- return readBlockLength(s.blockTrees, (treeType + 3) * 1080, s);
+ var /** number */ blockTypeAlphabetSize = numBlockTypes + 2;
+ offset += readHuffmanCode(blockTypeAlphabetSize, blockTypeAlphabetSize, s.blockTrees, 2 * treeType, s);
+ s.blockTrees[2 * treeType + 1] = offset;
+ var /** number */ blockLengthAlphabetSize = 26;
+ offset += readHuffmanCode(blockLengthAlphabetSize, blockLengthAlphabetSize, s.blockTrees, 2 * treeType + 1, s);
+ s.blockTrees[2 * treeType + 2] = offset;
+ return readBlockLength(s.blockTrees, 2 * treeType + 1, s);
+ }
+ /**
+ * @param {!State} s
+ * @param {number} alphabetSizeLimit
+ * @return {void}
+ */
+ function calculateDistanceLut(s, alphabetSizeLimit) {
+ var /** !Int8Array */ distExtraBits = s.distExtraBits;
+ var /** !Int32Array */ distOffset = s.distOffset;
+ var /** number */ npostfix = s.distancePostfixBits;
+ var /** number */ ndirect = s.numDirectDistanceCodes;
+ var /** number */ postfix = 1 << npostfix;
+ var /** number */ bits = 1;
+ var /** number */ half = 0;
+ var /** number */ i = 16;
+ for (var /** number */ j = 0; j < ndirect; ++j) {
+ distExtraBits[i] = 0;
+ distOffset[i] = j + 1;
+ ++i;
+ }
+ while (i < alphabetSizeLimit) {
+ var /** number */ base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
+ for (var /** number */ j = 0; j < postfix; ++j) {
+ distExtraBits[i] = bits;
+ distOffset[i] = base + j;
+ ++i;
+ }
+ bits = bits + half;
+ half = half ^ 1;
+ }
}
/**
* @param {!State} s
@@ -641,44 +808,49 @@ function BrotliDecodeClosure() {
s.bitOffset -= 16;
}
s.distancePostfixBits = readFewBits(s, 2);
- s.numDirectDistanceCodes = 16 + (readFewBits(s, 4) << s.distancePostfixBits);
+ s.numDirectDistanceCodes = readFewBits(s, 4) << s.distancePostfixBits;
s.distancePostfixMask = (1 << s.distancePostfixBits) - 1;
- var /** !number */ numDistanceCodes = s.numDirectDistanceCodes + (48 << s.distancePostfixBits);
s.contextModes = new Int8Array(s.numLiteralBlockTypes);
- for (var /** !number */ i = 0; i < s.numLiteralBlockTypes; ) {
- var /** !number */ limit = min(i + 96, s.numLiteralBlockTypes);
+ for (var /** number */ i = 0; i < s.numLiteralBlockTypes; ) {
+ var /** number */ limit = min(i + 96, s.numLiteralBlockTypes);
for (; i < limit; ++i) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- s.contextModes[i] = (readFewBits(s, 2));
+ s.contextModes[i] = readFewBits(s, 2);
}
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
}
s.contextMap = new Int8Array(s.numLiteralBlockTypes << 6);
- var /** !number */ numLiteralTrees = decodeContextMap(s.numLiteralBlockTypes << 6, s.contextMap, s);
+ var /** number */ numLiteralTrees = decodeContextMap(s.numLiteralBlockTypes << 6, s.contextMap, s);
s.trivialLiteralContext = 1;
- for (var /** !number */ j = 0; j < s.numLiteralBlockTypes << 6; j++) {
+ for (var /** number */ j = 0; j < s.numLiteralBlockTypes << 6; j++) {
if (s.contextMap[j] != j >> 6) {
s.trivialLiteralContext = 0;
break;
}
}
s.distContextMap = new Int8Array(s.numDistanceBlockTypes << 2);
- var /** !number */ numDistTrees = decodeContextMap(s.numDistanceBlockTypes << 2, s.distContextMap, s);
- s.hGroup0 = decodeHuffmanTreeGroup(256, numLiteralTrees, s);
- s.hGroup1 = decodeHuffmanTreeGroup(704, s.numCommandBlockTypes, s);
- s.hGroup2 = decodeHuffmanTreeGroup(numDistanceCodes, numDistTrees, s);
+ var /** number */ numDistTrees = decodeContextMap(s.numDistanceBlockTypes << 2, s.distContextMap, s);
+ s.literalTreeGroup = decodeHuffmanTreeGroup(256, 256, numLiteralTrees, s);
+ s.commandTreeGroup = decodeHuffmanTreeGroup(704, 704, s.numCommandBlockTypes, s);
+ var /** number */ distanceAlphabetSizeMax = calculateDistanceAlphabetSize(s.distancePostfixBits, s.numDirectDistanceCodes, 24);
+ var /** number */ distanceAlphabetSizeLimit = distanceAlphabetSizeMax;
+ if (s.isLargeWindow == 1) {
+ distanceAlphabetSizeMax = calculateDistanceAlphabetSize(s.distancePostfixBits, s.numDirectDistanceCodes, 62);
+ distanceAlphabetSizeLimit = calculateDistanceAlphabetLimit(0x7FFFFFFC, s.distancePostfixBits, s.numDirectDistanceCodes);
+ }
+ s.distanceTreeGroup = decodeHuffmanTreeGroup(distanceAlphabetSizeMax, distanceAlphabetSizeLimit, numDistTrees, s);
+ calculateDistanceLut(s, distanceAlphabetSizeLimit);
s.contextMapSlice = 0;
s.distContextMapSlice = 0;
- s.contextLookupOffset1 = (s.contextModes[0]) << 9;
+ s.contextLookupOffset1 = s.contextModes[0] * 512;
s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
- s.literalTreeIndex = 0;
- s.literalTree = s.hGroup0[0];
- s.treeCommandOffset = s.hGroup1[0];
+ s.literalTreeIdx = 0;
+ s.commandTreeIdx = 0;
s.rings[4] = 1;
s.rings[5] = 0;
s.rings[6] = 1;
@@ -694,27 +866,27 @@ function BrotliDecodeClosure() {
var /** !Int8Array */ ringBuffer = s.ringBuffer;
if (s.metaBlockLength <= 0) {
reload(s);
- s.runningState = 1;
+ s.runningState = 2;
return;
}
- var /** !number */ chunkLength = min(s.ringBufferSize - s.pos, s.metaBlockLength);
+ var /** number */ chunkLength = min(s.ringBufferSize - s.pos, s.metaBlockLength);
copyBytes(s, ringBuffer, s.pos, chunkLength);
s.metaBlockLength -= chunkLength;
s.pos += chunkLength;
if (s.pos == s.ringBufferSize) {
- s.nextRunningState = 5;
- s.runningState = 11;
+ s.nextRunningState = 6;
+ s.runningState = 12;
return;
}
reload(s);
- s.runningState = 1;
+ s.runningState = 2;
}
/**
* @param {!State} s
- * @return {!number}
+ * @return {number}
*/
function writeRingBuffer(s) {
- var /** !number */ toWrite = min(s.outputLength - s.outputUsed, s.ringBufferBytesReady - s.ringBufferBytesWritten);
+ var /** number */ toWrite = min(s.outputLength - s.outputUsed, s.ringBufferBytesReady - s.ringBufferBytesWritten);
if (toWrite != 0) {
s.output.set(s.ringBuffer.subarray(s.ringBufferBytesWritten, s.ringBufferBytesWritten + toWrite), s.outputOffset + s.outputUsed);
s.outputUsed += toWrite;
@@ -727,27 +899,28 @@ function BrotliDecodeClosure() {
}
}
/**
- * @param {!number} alphabetSize
- * @param {!number} n
+ * @param {number} alphabetSizeMax
+ * @param {number} alphabetSizeLimit
+ * @param {number} n
* @param {!State} s
* @return {!Int32Array}
*/
- function decodeHuffmanTreeGroup(alphabetSize, n, s) {
- var /** !Int32Array */ group = new Int32Array(n + (n * 1080));
- var /** !number */ next = n;
- for (var /** !number */ i = 0; i < n; i++) {
+ function decodeHuffmanTreeGroup(alphabetSizeMax, alphabetSizeLimit, n, s) {
+ var /** number */ maxTableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSizeLimit + 31) >> 5];
+ var /** !Int32Array */ group = new Int32Array(n + n * maxTableSize);
+ var /** number */ next = n;
+ for (var /** number */ i = 0; i < n; ++i) {
group[i] = next;
- readHuffmanCode(alphabetSize, group, next, s);
- next += 1080;
+ next += readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, group, i, s);
}
return group;
}
/**
* @param {!State} s
- * @return {!number}
+ * @return {number}
*/
function calculateFence(s) {
- var /** !number */ result = s.ringBufferSize;
+ var /** number */ result = s.ringBufferSize;
if (s.isEager != 0) {
result = min(result, s.ringBufferBytesWritten + s.outputLength - s.outputUsed);
}
@@ -761,15 +934,24 @@ function BrotliDecodeClosure() {
if (s.runningState == 0) {
throw "Can't decompress until initialized";
}
- if (s.runningState == 10) {
+ if (s.runningState == 11) {
throw "Can't decompress after close";
}
- var /** !number */ fence = calculateFence(s);
- var /** !number */ ringBufferMask = s.ringBufferSize - 1;
+ if (s.runningState == 1) {
+ var /** number */ windowBits = decodeWindowBits(s);
+ if (windowBits == -1) {
+ throw "Invalid 'windowBits' code";
+ }
+ s.maxRingBufferSize = 1 << windowBits;
+ s.maxBackwardDistance = s.maxRingBufferSize - 16;
+ s.runningState = 2;
+ }
+ var /** number */ fence = calculateFence(s);
+ var /** number */ ringBufferMask = s.ringBufferSize - 1;
var /** !Int8Array */ ringBuffer = s.ringBuffer;
- while (s.runningState != 9) {
+ while (s.runningState != 10) {
switch(s.runningState) {
- case 1:
+ case 2:
if (s.metaBlockLength < 0) {
throw "Invalid metablock length";
}
@@ -778,12 +960,12 @@ function BrotliDecodeClosure() {
ringBufferMask = s.ringBufferSize - 1;
ringBuffer = s.ringBuffer;
continue;
- case 2:
- readMetablockHuffmanCodesAndContextMaps(s);
- s.runningState = 3;
case 3:
+ readMetablockHuffmanCodesAndContextMaps(s);
+ s.runningState = 4;
+ case 4:
if (s.metaBlockLength <= 0) {
- s.runningState = 1;
+ s.runningState = 2;
continue;
}
if (s.halfOffset > 2030) {
@@ -797,32 +979,26 @@ function BrotliDecodeClosure() {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ cmdCode = readSymbol(s.hGroup1, s.treeCommandOffset, s);
- var /** !number */ rangeIdx = cmdCode >>> 6;
- s.distanceCode = 0;
- if (rangeIdx >= 2) {
- rangeIdx -= 2;
- s.distanceCode = -1;
- }
- var /** !number */ insertCode = INSERT_RANGE_LUT[rangeIdx] + ((cmdCode >>> 3) & 7);
+ var /** number */ cmdCode = readSymbol(s.commandTreeGroup, s.commandTreeIdx, s) << 2;
+ var /** number */ insertAndCopyExtraBits = CMD_LOOKUP[cmdCode];
+ var /** number */ insertLengthOffset = CMD_LOOKUP[cmdCode + 1];
+ var /** number */ copyLengthOffset = CMD_LOOKUP[cmdCode + 2];
+ s.distanceCode = CMD_LOOKUP[cmdCode + 3];
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ insertBits = INSERT_LENGTH_N_BITS[insertCode];
- var /** !number */ insertExtra = ((insertBits <= 16) ? readFewBits(s, insertBits) : readManyBits(s, insertBits));
- s.insertLength = INSERT_LENGTH_OFFSET[insertCode] + insertExtra;
- var /** !number */ copyCode = COPY_RANGE_LUT[rangeIdx] + (cmdCode & 7);
+ var /** number */ extraBits = insertAndCopyExtraBits & 0xFF;
+ s.insertLength = insertLengthOffset + ((extraBits <= 16) ? readFewBits(s, extraBits) : readManyBits(s, extraBits));
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- var /** !number */ copyBits = COPY_LENGTH_N_BITS[copyCode];
- var /** !number */ copyExtra = ((copyBits <= 16) ? readFewBits(s, copyBits) : readManyBits(s, copyBits));
- s.copyLength = COPY_LENGTH_OFFSET[copyCode] + copyExtra;
+ var /** number */ extraBits = insertAndCopyExtraBits >> 8;
+ s.copyLength = copyLengthOffset + ((extraBits <= 16) ? readFewBits(s, extraBits) : readManyBits(s, extraBits));
s.j = 0;
- s.runningState = 6;
- case 6:
+ s.runningState = 7;
+ case 7:
if (s.trivialLiteralContext != 0) {
while (s.j < s.insertLength) {
if (s.halfOffset > 2030) {
@@ -836,18 +1012,18 @@ function BrotliDecodeClosure() {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- ringBuffer[s.pos] = readSymbol(s.hGroup0, s.literalTree, s);
+ ringBuffer[s.pos] = readSymbol(s.literalTreeGroup, s.literalTreeIdx, s);
s.pos++;
s.j++;
if (s.pos >= fence) {
- s.nextRunningState = 6;
- s.runningState = 11;
+ s.nextRunningState = 7;
+ s.runningState = 12;
break;
}
}
} else {
- var /** !number */ prevByte1 = ringBuffer[(s.pos - 1) & ringBufferMask] & 0xFF;
- var /** !number */ prevByte2 = ringBuffer[(s.pos - 2) & ringBufferMask] & 0xFF;
+ var /** number */ prevByte1 = ringBuffer[(s.pos - 1) & ringBufferMask] & 0xFF;
+ var /** number */ prevByte2 = ringBuffer[(s.pos - 2) & ringBufferMask] & 0xFF;
while (s.j < s.insertLength) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
@@ -855,33 +1031,37 @@ function BrotliDecodeClosure() {
if (s.literalBlockLength == 0) {
decodeLiteralBlockSwitch(s);
}
- var /** !number */ literalTreeIndex = s.contextMap[s.contextMapSlice + (LOOKUP[s.contextLookupOffset1 + prevByte1] | LOOKUP[s.contextLookupOffset2 + prevByte2])] & 0xFF;
+ var /** number */ literalContext = LOOKUP[s.contextLookupOffset1 + prevByte1] | LOOKUP[s.contextLookupOffset2 + prevByte2];
+ var /** number */ literalTreeIdx = s.contextMap[s.contextMapSlice + literalContext] & 0xFF;
s.literalBlockLength--;
prevByte2 = prevByte1;
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- prevByte1 = readSymbol(s.hGroup0, s.hGroup0[literalTreeIndex], s);
+ prevByte1 = readSymbol(s.literalTreeGroup, literalTreeIdx, s);
ringBuffer[s.pos] = prevByte1;
s.pos++;
s.j++;
if (s.pos >= fence) {
- s.nextRunningState = 6;
- s.runningState = 11;
+ s.nextRunningState = 7;
+ s.runningState = 12;
break;
}
}
}
- if (s.runningState != 6) {
+ if (s.runningState != 7) {
continue;
}
s.metaBlockLength -= s.insertLength;
if (s.metaBlockLength <= 0) {
- s.runningState = 3;
+ s.runningState = 4;
continue;
}
- if (s.distanceCode < 0) {
+ var /** number */ distanceCode = s.distanceCode;
+ if (distanceCode < 0) {
+ s.distance = s.rings[s.distRbIdx];
+ } else {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
@@ -893,52 +1073,56 @@ function BrotliDecodeClosure() {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
- s.distanceCode = readSymbol(s.hGroup2, s.hGroup2[s.distContextMap[s.distContextMapSlice + (s.copyLength > 4 ? 3 : s.copyLength - 2)] & 0xFF], s);
- if (s.distanceCode >= s.numDirectDistanceCodes) {
- s.distanceCode -= s.numDirectDistanceCodes;
- var /** !number */ postfix = s.distanceCode & s.distancePostfixMask;
- s.distanceCode >>>= s.distancePostfixBits;
- var /** !number */ n = (s.distanceCode >>> 1) + 1;
- var /** !number */ offset = ((2 + (s.distanceCode & 1)) << n) - 4;
- if (s.bitOffset >= 16) {
- s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
- s.bitOffset -= 16;
+ var /** number */ distTreeIdx = s.distContextMap[s.distContextMapSlice + distanceCode] & 0xFF;
+ distanceCode = readSymbol(s.distanceTreeGroup, distTreeIdx, s);
+ if (distanceCode < 16) {
+ var /** number */ index = (s.distRbIdx + DISTANCE_SHORT_CODE_INDEX_OFFSET[distanceCode]) & 0x3;
+ s.distance = s.rings[index] + DISTANCE_SHORT_CODE_VALUE_OFFSET[distanceCode];
+ if (s.distance < 0) {
+ throw "Negative distance";
}
- var /** !number */ distanceExtra = ((n <= 16) ? readFewBits(s, n) : readManyBits(s, n));
- s.distanceCode = s.numDirectDistanceCodes + postfix + ((offset + distanceExtra) << s.distancePostfixBits);
+ } else {
+ var /** number */ extraBits = s.distExtraBits[distanceCode];
+ var /** number */ bits;
+ if (s.bitOffset + extraBits <= 32) {
+ bits = readFewBits(s, extraBits);
+ } else {
+ if (s.bitOffset >= 16) {
+ s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
+ s.bitOffset -= 16;
+ }
+ bits = ((extraBits <= 16) ? readFewBits(s, extraBits) : readManyBits(s, extraBits));
+ }
+ s.distance = s.distOffset[distanceCode] + (bits << s.distancePostfixBits);
}
}
- s.distance = translateShortCodes(s.distanceCode, s.rings, s.distRbIdx);
- if (s.distance < 0) {
- throw "Negative distance";
- }
if (s.maxDistance != s.maxBackwardDistance && s.pos < s.maxBackwardDistance) {
s.maxDistance = s.pos;
} else {
s.maxDistance = s.maxBackwardDistance;
}
if (s.distance > s.maxDistance) {
- s.runningState = 8;
+ s.runningState = 9;
continue;
}
- if (s.distanceCode > 0) {
- s.rings[s.distRbIdx & 3] = s.distance;
- s.distRbIdx++;
+ if (distanceCode > 0) {
+ s.distRbIdx = (s.distRbIdx + 1) & 0x3;
+ s.rings[s.distRbIdx] = s.distance;
}
if (s.copyLength > s.metaBlockLength) {
throw "Invalid backward reference";
}
s.j = 0;
- s.runningState = 7;
- case 7:
- var /** !number */ src = (s.pos - s.distance) & ringBufferMask;
- var /** !number */ dst = s.pos;
- var /** !number */ copyLength = s.copyLength - s.j;
- var /** !number */ srcEnd = src + copyLength;
- var /** !number */ dstEnd = dst + copyLength;
+ s.runningState = 8;
+ case 8:
+ var /** number */ src = (s.pos - s.distance) & ringBufferMask;
+ var /** number */ dst = s.pos;
+ var /** number */ copyLength = s.copyLength - s.j;
+ var /** number */ srcEnd = src + copyLength;
+ var /** number */ dstEnd = dst + copyLength;
if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) {
if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) {
- for (var /** !number */ k = 0; k < copyLength; k += 4) {
+ for (var /** number */ k = 0; k < copyLength; k += 4) {
ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++];
@@ -957,32 +1141,35 @@ function BrotliDecodeClosure() {
s.pos++;
s.j++;
if (s.pos >= fence) {
- s.nextRunningState = 7;
- s.runningState = 11;
+ s.nextRunningState = 8;
+ s.runningState = 12;
break;
}
}
}
- if (s.runningState == 7) {
- s.runningState = 3;
+ if (s.runningState == 8) {
+ s.runningState = 4;
}
continue;
- case 8:
+ case 9:
+ if (s.distance > 0x7FFFFFFC) {
+ throw "Invalid backward reference";
+ }
if (s.copyLength >= 4 && s.copyLength <= 24) {
- var /** !number */ offset = DICTIONARY_OFFSETS_BY_LENGTH[s.copyLength];
- var /** !number */ wordId = s.distance - s.maxDistance - 1;
- var /** !number */ shift = DICTIONARY_SIZE_BITS_BY_LENGTH[s.copyLength];
- var /** !number */ mask = (1 << shift) - 1;
- var /** !number */ wordIdx = wordId & mask;
- var /** !number */ transformIdx = wordId >>> shift;
+ var /** number */ offset = DICTIONARY_OFFSETS_BY_LENGTH[s.copyLength];
+ var /** number */ wordId = s.distance - s.maxDistance - 1;
+ var /** number */ shift = DICTIONARY_SIZE_BITS_BY_LENGTH[s.copyLength];
+ var /** number */ mask = (1 << shift) - 1;
+ var /** number */ wordIdx = wordId & mask;
+ var /** number */ transformIdx = wordId >>> shift;
offset += wordIdx * s.copyLength;
if (transformIdx < 121) {
- var /** !number */ len = transformDictionaryWord(ringBuffer, s.pos, DICTIONARY_DATA, offset, s.copyLength, transformIdx);
+ var /** number */ len = transformDictionaryWord(ringBuffer, s.pos, DICTIONARY_DATA, offset, s.copyLength, RFC_TRANSFORMS, transformIdx);
s.pos += len;
s.metaBlockLength -= len;
if (s.pos >= fence) {
- s.nextRunningState = 3;
- s.runningState = 11;
+ s.nextRunningState = 4;
+ s.runningState = 12;
continue;
}
} else {
@@ -991,9 +1178,9 @@ function BrotliDecodeClosure() {
} else {
throw "Invalid backward reference";
}
- s.runningState = 3;
+ s.runningState = 4;
continue;
- case 4:
+ case 5:
while (s.metaBlockLength > 0) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
@@ -1005,15 +1192,15 @@ function BrotliDecodeClosure() {
readFewBits(s, 8);
s.metaBlockLength--;
}
- s.runningState = 1;
+ s.runningState = 2;
continue;
- case 5:
+ case 6:
copyUncompressedData(s);
continue;
- case 11:
- s.ringBufferBytesReady = min(s.pos, s.ringBufferSize);
- s.runningState = 12;
case 12:
+ s.ringBufferBytesReady = min(s.pos, s.ringBufferSize);
+ s.runningState = 13;
+ case 13:
if (writeRingBuffer(s) == 0) {
return;
}
@@ -1033,7 +1220,7 @@ function BrotliDecodeClosure() {
throw "Unexpected state " + s.runningState;
}
}
- if (s.runningState == 9) {
+ if (s.runningState == 10) {
if (s.metaBlockLength < 0) {
throw "Invalid metablock length";
}
@@ -1042,9 +1229,32 @@ function BrotliDecodeClosure() {
}
}
- var TRANSFORMS = new Int32Array(363);
- var PREFIX_SUFFIX = new Int8Array(217);
- var PREFIX_SUFFIX_HEADS = new Int32Array(51);
+ /**
+ * @constructor
+ * @param {number} numTransforms
+ * @param {number} prefixSuffixLen
+ * @param {number} prefixSuffixCount
+ * @struct
+ */
+ function Transforms(numTransforms, prefixSuffixLen, prefixSuffixCount) {
+ /** @type {!number} */
+ this.numTransforms = 0;
+ /** @type {!Int32Array} */
+ this.triplets = new Int32Array(0);
+ /** @type {!Int8Array} */
+ this.prefixSuffixStorage = new Int8Array(0);
+ /** @type {!Int32Array} */
+ this.prefixSuffixHeads = new Int32Array(0);
+ /** @type {!Int16Array} */
+ this.params = new Int16Array(0);
+ this.numTransforms = numTransforms;
+ this.triplets = new Int32Array(numTransforms * 3);
+ this.params = new Int16Array(numTransforms);
+ this.prefixSuffixStorage = new Int8Array(prefixSuffixLen);
+ this.prefixSuffixHeads = new Int32Array(prefixSuffixCount + 1);
+ }
+
+ var RFC_TRANSFORMS = new Transforms(121, 167, 50);
/**
* @param {!Int8Array} prefixSuffix
* @param {!Int32Array} prefixSuffixHeads
@@ -1054,67 +1264,83 @@ function BrotliDecodeClosure() {
* @return {void}
*/
function unpackTransforms(prefixSuffix, prefixSuffixHeads, transforms, prefixSuffixSrc, transformsSrc) {
- var /** !number */ n = prefixSuffixSrc.length;
- var /** !number */ index = 1;
- for (var /** !number */ i = 0; i < n; ++i) {
- var /** !number */ c = prefixSuffixSrc.charCodeAt(i);
- prefixSuffix[i] = c;
+ var /** number */ n = prefixSuffixSrc.length;
+ var /** number */ index = 1;
+ var /** number */ j = 0;
+ for (var /** number */ i = 0; i < n; ++i) {
+ var /** number */ c = prefixSuffixSrc.charCodeAt(i);
if (c == 35) {
- prefixSuffixHeads[index++] = i + 1;
- prefixSuffix[i] = 0;
+ prefixSuffixHeads[index++] = j;
+ } else {
+ prefixSuffix[j++] = c;
}
}
- for (var /** !number */ i = 0; i < 363; ++i) {
+ for (var /** number */ i = 0; i < 363; ++i) {
transforms[i] = transformsSrc.charCodeAt(i) - 32;
}
}
{
- unpackTransforms(PREFIX_SUFFIX, PREFIX_SUFFIX_HEADS, TRANSFORMS, "# #s #, #e #.# the #.com/#\u00C2\u00A0# of # and # in # to #\"#\">#\n#]# for # a # that #. # with #'# from # by #. The # on # as # is #ing #\n\t#:#ed #(# at #ly #=\"# of the #. This #,# not #er #al #='#ful #ive #less #est #ize #ous #", " !! ! , *! &! \" ! ) * * - ! # ! #!*! + ,$ ! - % . / # 0 1 . \" 2 3!* 4% ! # / 5 6 7 8 0 1 & $ 9 + : ; < ' != > ?! 4 @ 4 2 & A *# ( B C& ) % ) !*# *-% A +! *. D! %' & E *6 F G% ! *A *% H! D I!+! J!+ K +- *4! A L!*4 M N +6 O!*% +.! K *G P +%( ! G *D +D Q +# *K!*G!+D!+# +G +A +4!+% +K!+4!*D!+K!*K");
+ unpackTransforms(RFC_TRANSFORMS.prefixSuffixStorage, RFC_TRANSFORMS.prefixSuffixHeads, RFC_TRANSFORMS.triplets, "# #s #, #e #.# the #.com/#\u00C2\u00A0# of # and # in # to #\"#\">#\n#]# for # a # that #. # with #'# from # by #. The # on # as # is #ing #\n\t#:#ed #(# at #ly #=\"# of the #. This #,# not #er #al #='#ful #ive #less #est #ize #ous #", " !! ! , *! &! \" ! ) * * - ! # ! #!*! + ,$ ! - % . / # 0 1 . \" 2 3!* 4% ! # / 5 6 7 8 0 1 & $ 9 + : ; < ' != > ?! 4 @ 4 2 & A *# ( B C& ) % ) !*# *-% A +! *. D! %' & E *6 F G% ! *A *% H! D I!+! J!+ K +- *4! A L!*4 M N +6 O!*% +.! K *G P +%( ! G *D +D Q +# *K!*G!+D!+# +G +A +4!+% +K!+4!*D!+K!*K");
}
/**
* @param {!Int8Array} dst
- * @param {!number} dstOffset
- * @param {!Int8Array} data
- * @param {!number} wordOffset
- * @param {!number} len
- * @param {!number} transformIndex
- * @return {!number}
+ * @param {number} dstOffset
+ * @param {!Int8Array} src
+ * @param {number} srcOffset
+ * @param {number} len
+ * @param {!Transforms} transforms
+ * @param {number} transformIndex
+ * @return {number}
*/
- function transformDictionaryWord(dst, dstOffset, data, wordOffset, len, transformIndex) {
- var /** !number */ offset = dstOffset;
- var /** !number */ transformOffset = 3 * transformIndex;
- var /** !number */ transformPrefix = PREFIX_SUFFIX_HEADS[TRANSFORMS[transformOffset]];
- var /** !number */ transformType = TRANSFORMS[transformOffset + 1];
- var /** !number */ transformSuffix = PREFIX_SUFFIX_HEADS[TRANSFORMS[transformOffset + 2]];
- while (PREFIX_SUFFIX[transformPrefix] != 0) {
- dst[offset++] = PREFIX_SUFFIX[transformPrefix++];
+ function transformDictionaryWord(dst, dstOffset, src, srcOffset, len, transforms, transformIndex) {
+ var /** number */ offset = dstOffset;
+ var /** !Int32Array */ triplets = transforms.triplets;
+ var /** !Int8Array */ prefixSuffixStorage = transforms.prefixSuffixStorage;
+ var /** !Int32Array */ prefixSuffixHeads = transforms.prefixSuffixHeads;
+ var /** number */ transformOffset = 3 * transformIndex;
+ var /** number */ prefixIdx = triplets[transformOffset];
+ var /** number */ transformType = triplets[transformOffset + 1];
+ var /** number */ suffixIdx = triplets[transformOffset + 2];
+ var /** number */ prefix = prefixSuffixHeads[prefixIdx];
+ var /** number */ prefixEnd = prefixSuffixHeads[prefixIdx + 1];
+ var /** number */ suffix = prefixSuffixHeads[suffixIdx];
+ var /** number */ suffixEnd = prefixSuffixHeads[suffixIdx + 1];
+ var /** number */ omitFirst = transformType - 11;
+ var /** number */ omitLast = transformType - 0;
+ if (omitFirst < 1 || omitFirst > 9) {
+ omitFirst = 0;
+ }
+ if (omitLast < 1 || omitLast > 9) {
+ omitLast = 0;
+ }
+ while (prefix != prefixEnd) {
+ dst[offset++] = prefixSuffixStorage[prefix++];
}
- var /** !number */ omitFirst = transformType >= 12 ? (transformType - 11) : 0;
if (omitFirst > len) {
omitFirst = len;
}
- wordOffset += omitFirst;
+ srcOffset += omitFirst;
len -= omitFirst;
- len -= transformType <= 9 ? transformType : 0;
- var /** !number */ i = len;
+ len -= omitLast;
+ var /** number */ i = len;
while (i > 0) {
- dst[offset++] = data[wordOffset++];
+ dst[offset++] = src[srcOffset++];
i--;
}
- if (transformType == 11 || transformType == 10) {
- var /** !number */ uppercaseOffset = offset - len;
+ if (transformType == 10 || transformType == 11) {
+ var /** number */ uppercaseOffset = offset - len;
if (transformType == 10) {
len = 1;
}
while (len > 0) {
- var /** !number */ tmp = dst[uppercaseOffset] & 0xFF;
- if (tmp < 0xc0) {
- if (tmp >= 97 && tmp <= 122) {
+ var /** number */ c0 = dst[uppercaseOffset] & 0xFF;
+ if (c0 < 0xC0) {
+ if (c0 >= 97 && c0 <= 122) {
dst[uppercaseOffset] ^= 32;
}
uppercaseOffset += 1;
len -= 1;
- } else if (tmp < 0xe0) {
+ } else if (c0 < 0xE0) {
dst[uppercaseOffset + 1] ^= 32;
uppercaseOffset += 2;
len -= 2;
@@ -1124,20 +1350,74 @@ function BrotliDecodeClosure() {
len -= 3;
}
}
+ } else if (transformType == 21 || transformType == 22) {
+ var /** number */ shiftOffset = offset - len;
+ var /** number */ param = transforms.params[transformIndex];
+ var /** number */ scalar = (param & 0x7FFF) + (0x1000000 - (param & 0x8000));
+ while (len > 0) {
+ var /** number */ step = 1;
+ var /** number */ c0 = dst[shiftOffset] & 0xFF;
+ if (c0 < 0x80) {
+ scalar += c0;
+ dst[shiftOffset] = (scalar & 0x7F);
+ } else if (c0 < 0xC0) {
+ } else if (c0 < 0xE0) {
+ if (len >= 2) {
+ var /** number */ c1 = dst[shiftOffset + 1];
+ scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6);
+ dst[shiftOffset] = (0xC0 | ((scalar >> 6) & 0x1F));
+ dst[shiftOffset + 1] = ((c1 & 0xC0) | (scalar & 0x3F));
+ step = 2;
+ } else {
+ step = len;
+ }
+ } else if (c0 < 0xF0) {
+ if (len >= 3) {
+ var /** number */ c1 = dst[shiftOffset + 1];
+ var /** number */ c2 = dst[shiftOffset + 2];
+ scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12);
+ dst[shiftOffset] = (0xE0 | ((scalar >> 12) & 0x0F));
+ dst[shiftOffset + 1] = ((c1 & 0xC0) | ((scalar >> 6) & 0x3F));
+ dst[shiftOffset + 2] = ((c2 & 0xC0) | (scalar & 0x3F));
+ step = 3;
+ } else {
+ step = len;
+ }
+ } else if (c0 < 0xF8) {
+ if (len >= 4) {
+ var /** number */ c1 = dst[shiftOffset + 1];
+ var /** number */ c2 = dst[shiftOffset + 2];
+ var /** number */ c3 = dst[shiftOffset + 3];
+ scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18);
+ dst[shiftOffset] = (0xF0 | ((scalar >> 18) & 0x07));
+ dst[shiftOffset + 1] = ((c1 & 0xC0) | ((scalar >> 12) & 0x3F));
+ dst[shiftOffset + 2] = ((c2 & 0xC0) | ((scalar >> 6) & 0x3F));
+ dst[shiftOffset + 3] = ((c3 & 0xC0) | (scalar & 0x3F));
+ step = 4;
+ } else {
+ step = len;
+ }
+ }
+ shiftOffset += step;
+ len -= step;
+ if (transformType == 21) {
+ len = 0;
+ }
+ }
}
- while (PREFIX_SUFFIX[transformSuffix] != 0) {
- dst[offset++] = PREFIX_SUFFIX[transformSuffix++];
+ while (suffix != suffixEnd) {
+ dst[offset++] = prefixSuffixStorage[suffix++];
}
return offset - dstOffset;
}
/**
- * @param {!number} key
- * @param {!number} len
- * @return {!number}
+ * @param {number} key
+ * @param {number} len
+ * @return {number}
*/
function getNextKey(key, len) {
- var /** !number */ step = 1 << (len - 1);
+ var /** number */ step = 1 << (len - 1);
while ((key & step) != 0) {
step >>= 1;
}
@@ -1145,10 +1425,10 @@ function BrotliDecodeClosure() {
}
/**
* @param {!Int32Array} table
- * @param {!number} offset
- * @param {!number} step
- * @param {!number} end
- * @param {!number} item
+ * @param {number} offset
+ * @param {number} step
+ * @param {number} end
+ * @param {number} item
* @return {void}
*/
function replicateValue(table, offset, step, end, item) {
@@ -1159,12 +1439,12 @@ function BrotliDecodeClosure() {
}
/**
* @param {!Int32Array} count
- * @param {!number} len
- * @param {!number} rootBits
- * @return {!number}
+ * @param {number} len
+ * @param {number} rootBits
+ * @return {number}
*/
function nextTableBitSize(count, len, rootBits) {
- var /** !number */ left = 1 << (len - rootBits);
+ var /** number */ left = 1 << (len - rootBits);
while (len < 15) {
left -= count[len];
if (left <= 0) {
@@ -1176,24 +1456,25 @@ function BrotliDecodeClosure() {
return len - rootBits;
}
/**
- * @param {!Int32Array} rootTable
- * @param {!number} tableOffset
- * @param {!number} rootBits
+ * @param {!Int32Array} tableGroup
+ * @param {number} tableIdx
+ * @param {number} rootBits
* @param {!Int32Array} codeLengths
- * @param {!number} codeLengthsSize
- * @return {void}
+ * @param {number} codeLengthsSize
+ * @return {number}
*/
- function buildHuffmanTable(rootTable, tableOffset, rootBits, codeLengths, codeLengthsSize) {
- var /** !number */ key;
+ function buildHuffmanTable(tableGroup, tableIdx, rootBits, codeLengths, codeLengthsSize) {
+ var /** number */ tableOffset = tableGroup[tableIdx];
+ var /** number */ key;
var /** !Int32Array */ sorted = new Int32Array(codeLengthsSize);
var /** !Int32Array */ count = new Int32Array(16);
var /** !Int32Array */ offset = new Int32Array(16);
- var /** !number */ symbol;
+ var /** number */ symbol;
for (symbol = 0; symbol < codeLengthsSize; symbol++) {
count[codeLengths[symbol]]++;
}
offset[1] = 0;
- for (var /** !number */ len = 1; len < 15; len++) {
+ for (var /** number */ len = 1; len < 15; len++) {
offset[len + 1] = offset[len] + count[len];
}
for (symbol = 0; symbol < codeLengthsSize; symbol++) {
@@ -1201,27 +1482,27 @@ function BrotliDecodeClosure() {
sorted[offset[codeLengths[symbol]]++] = symbol;
}
}
- var /** !number */ tableBits = rootBits;
- var /** !number */ tableSize = 1 << tableBits;
- var /** !number */ totalSize = tableSize;
+ var /** number */ tableBits = rootBits;
+ var /** number */ tableSize = 1 << tableBits;
+ var /** number */ totalSize = tableSize;
if (offset[15] == 1) {
for (key = 0; key < totalSize; key++) {
- rootTable[tableOffset + key] = sorted[0];
+ tableGroup[tableOffset + key] = sorted[0];
}
- return;
+ return totalSize;
}
key = 0;
symbol = 0;
- for (var /** !number */ len = 1, step = 2; len <= rootBits; len++, step <<= 1) {
+ for (var /** number */ len = 1, step = 2; len <= rootBits; len++, step <<= 1) {
for (; count[len] > 0; count[len]--) {
- replicateValue(rootTable, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
+ replicateValue(tableGroup, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
key = getNextKey(key, len);
}
}
- var /** !number */ mask = totalSize - 1;
- var /** !number */ low = -1;
- var /** !number */ currentOffset = tableOffset;
- for (var /** !number */ len = rootBits + 1, step = 2; len <= 15; len++, step <<= 1) {
+ var /** number */ mask = totalSize - 1;
+ var /** number */ low = -1;
+ var /** number */ currentOffset = tableOffset;
+ for (var /** number */ len = rootBits + 1, step = 2; len <= 15; len++, step <<= 1) {
for (; count[len] > 0; count[len]--) {
if ((key & mask) != low) {
currentOffset += tableSize;
@@ -1229,12 +1510,13 @@ function BrotliDecodeClosure() {
tableSize = 1 << tableBits;
totalSize += tableSize;
low = key & mask;
- rootTable[tableOffset + low] = (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
+ tableGroup[tableOffset + low] = (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
}
- replicateValue(rootTable, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
+ replicateValue(tableGroup, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
key = getNextKey(key, len);
}
}
+ return totalSize;
}
/**
@@ -1248,13 +1530,13 @@ function BrotliDecodeClosure() {
}
throw "No more input";
}
- var /** !number */ readOffset = s.halfOffset << 1;
- var /** !number */ bytesInBuffer = 4096 - readOffset;
+ var /** number */ readOffset = s.halfOffset << 1;
+ var /** number */ bytesInBuffer = 4096 - readOffset;
s.byteBuffer.copyWithin(0, readOffset, 4096);
s.halfOffset = 0;
while (bytesInBuffer < 4096) {
- var /** !number */ spaceLeft = 4096 - bytesInBuffer;
- var /** !number */ len = readInput(s.input, s.byteBuffer, bytesInBuffer, spaceLeft);
+ var /** number */ spaceLeft = 4096 - bytesInBuffer;
+ var /** number */ len = readInput(s.input, s.byteBuffer, bytesInBuffer, spaceLeft);
if (len <= 0) {
s.endOfStreamReached = 1;
s.tailBytes = bytesInBuffer;
@@ -1267,14 +1549,14 @@ function BrotliDecodeClosure() {
}
/**
* @param {!State} s
- * @param {!number} endOfStream
+ * @param {number} endOfStream
* @return {void}
*/
function checkHealth(s, endOfStream) {
if (s.endOfStreamReached == 0) {
return;
}
- var /** !number */ byteOffset = (s.halfOffset << 1) + ((s.bitOffset + 7) >> 3) - 4;
+ var /** number */ byteOffset = (s.halfOffset << 1) + ((s.bitOffset + 7) >> 3) - 4;
if (byteOffset > s.tailBytes) {
throw "Read after end";
}
@@ -1284,21 +1566,30 @@ function BrotliDecodeClosure() {
}
/**
* @param {!State} s
- * @param {!number} n
- * @return {!number}
+ * @return {void}
+ */
+ function assertAccumulatorHealthy(s) {
+ if (s.bitOffset > 32) {
+ throw "Accumulator underloaded: " + s.bitOffset;
+ }
+ }
+ /**
+ * @param {!State} s
+ * @param {number} n
+ * @return {number}
*/
function readFewBits(s, n) {
- var /** !number */ val = (s.accumulator32 >>> s.bitOffset) & ((1 << n) - 1);
+ var /** number */ val = (s.accumulator32 >>> s.bitOffset) & ((1 << n) - 1);
s.bitOffset += n;
return val;
}
/**
* @param {!State} s
- * @param {!number} n
- * @return {!number}
+ * @param {number} n
+ * @return {number}
*/
function readManyBits(s, n) {
- var /** !number */ low = readFewBits(s, 16);
+ var /** number */ low = readFewBits(s, 16);
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
return low | (readFewBits(s, n - 16) << 16);
@@ -1344,9 +1635,9 @@ function BrotliDecodeClosure() {
* @return {void}
*/
function jumpToByteBoundary(s) {
- var /** !number */ padding = (32 - s.bitOffset) & 7;
+ var /** number */ padding = (32 - s.bitOffset) & 7;
if (padding != 0) {
- var /** !number */ paddingBits = readFewBits(s, padding);
+ var /** number */ paddingBits = readFewBits(s, padding);
if (paddingBits != 0) {
throw "Corrupted padding bits";
}
@@ -1354,10 +1645,10 @@ function BrotliDecodeClosure() {
}
/**
* @param {!State} s
- * @return {!number}
+ * @return {number}
*/
function halfAvailable(s) {
- var /** !number */ limit = 2048;
+ var /** number */ limit = 2048;
if (s.endOfStreamReached != 0) {
limit = (s.tailBytes + 1) >> 1;
}
@@ -1366,8 +1657,8 @@ function BrotliDecodeClosure() {
/**
* @param {!State} s
* @param {!Int8Array} data
- * @param {!number} offset
- * @param {!number} length
+ * @param {number} offset
+ * @param {number} length
* @return {void}
*/
function copyBytes(s, data, offset, length) {
@@ -1382,10 +1673,10 @@ function BrotliDecodeClosure() {
if (length == 0) {
return;
}
- var /** !number */ copyNibbles = min(halfAvailable(s), length >> 1);
+ var /** number */ copyNibbles = min(halfAvailable(s), length >> 1);
if (copyNibbles > 0) {
- var /** !number */ readOffset = s.halfOffset << 1;
- var /** !number */ delta = copyNibbles << 1;
+ var /** number */ readOffset = s.halfOffset << 1;
+ var /** number */ delta = copyNibbles << 1;
data.set(s.byteBuffer.subarray(readOffset, readOffset + delta), offset);
offset += delta;
length -= delta;
@@ -1408,7 +1699,7 @@ function BrotliDecodeClosure() {
return;
}
while (length > 0) {
- var /** !number */ len = readInput(s.input, data, offset, length);
+ var /** number */ len = readInput(s.input, data, offset, length);
if (len == -1) {
throw "Unexpected end of input";
}
@@ -1418,14 +1709,14 @@ function BrotliDecodeClosure() {
}
/**
* @param {!State} s
- * @param {!number} byteLen
+ * @param {number} byteLen
* @return {void}
*/
function bytesToNibbles(s, byteLen) {
var /** !Int8Array */ byteBuffer = s.byteBuffer;
- var /** !number */ halfLen = byteLen >> 1;
+ var /** number */ halfLen = byteLen >> 1;
var /** !Int16Array */ shortBuffer = s.shortBuffer;
- for (var /** !number */ i = 0; i < halfLen; ++i) {
+ for (var /** number */ i = 0; i < halfLen; ++i) {
shortBuffer[i] = ((byteBuffer[i * 2] & 0xFF) | ((byteBuffer[(i * 2) + 1] & 0xFF) << 8));
}
}
@@ -1438,33 +1729,33 @@ function BrotliDecodeClosure() {
* @return {void}
*/
function unpackLookupTable(lookup, map, rle) {
- for (var /** !number */ i = 0; i < 256; ++i) {
+ for (var /** number */ i = 0; i < 256; ++i) {
lookup[i] = i & 0x3F;
lookup[512 + i] = i >> 2;
lookup[1792 + i] = 2 + (i >> 6);
}
- for (var /** !number */ i = 0; i < 128; ++i) {
+ for (var /** number */ i = 0; i < 128; ++i) {
lookup[1024 + i] = 4 * (map.charCodeAt(i) - 32);
}
- for (var /** !number */ i = 0; i < 64; ++i) {
+ for (var /** number */ i = 0; i < 64; ++i) {
lookup[1152 + i] = i & 1;
lookup[1216 + i] = 2 + (i & 1);
}
- var /** !number */ offset = 1280;
- for (var /** !number */ k = 0; k < 19; ++k) {
- var /** !number */ value = k & 3;
- var /** !number */ rep = rle.charCodeAt(k) - 32;
- for (var /** !number */ i = 0; i < rep; ++i) {
+ var /** number */ offset = 1280;
+ for (var /** number */ k = 0; k < 19; ++k) {
+ var /** number */ value = k & 3;
+ var /** number */ rep = rle.charCodeAt(k) - 32;
+ for (var /** number */ i = 0; i < rep; ++i) {
lookup[offset++] = value;
}
}
- for (var /** !number */ i = 0; i < 16; ++i) {
+ for (var /** number */ i = 0; i < 16; ++i) {
lookup[1792 + i] = 1;
lookup[2032 + i] = 6;
}
lookup[1792] = 0;
lookup[2047] = 7;
- for (var /** !number */ i = 0; i < 256; ++i) {
+ for (var /** number */ i = 0; i < 256; ++i) {
lookup[1536 + i] = lookup[1792 + i] << 3;
}
}
@@ -1486,6 +1777,8 @@ function BrotliDecodeClosure() {
/** @type {!Int8Array} */
this.distContextMap = new Int8Array(0);
/** @type {!Int8Array} */
+ this.distExtraBits = new Int8Array(0);
+ /** @type {!Int8Array} */
this.output = new Int8Array(0);
/** @type {!Int8Array} */
this.byteBuffer = new Int8Array(0);
@@ -1498,11 +1791,13 @@ function BrotliDecodeClosure() {
/** @type {!Int32Array} */
this.blockTrees = new Int32Array(0);
/** @type {!Int32Array} */
- this.hGroup0 = new Int32Array(0);
+ this.literalTreeGroup = new Int32Array(0);
+ /** @type {!Int32Array} */
+ this.commandTreeGroup = new Int32Array(0);
/** @type {!Int32Array} */
- this.hGroup1 = new Int32Array(0);
+ this.distanceTreeGroup = new Int32Array(0);
/** @type {!Int32Array} */
- this.hGroup2 = new Int32Array(0);
+ this.distOffset = new Int32Array(0);
/** @type {!number} */
this.runningState = 0;
/** @type {!number} */
@@ -1546,9 +1841,9 @@ function BrotliDecodeClosure() {
/** @type {!number} */
this.trivialLiteralContext = 0;
/** @type {!number} */
- this.literalTreeIndex = 0;
+ this.literalTreeIdx = 0;
/** @type {!number} */
- this.literalTree = 0;
+ this.commandTreeIdx = 0;
/** @type {!number} */
this.j = 0;
/** @type {!number} */
@@ -1562,8 +1857,6 @@ function BrotliDecodeClosure() {
/** @type {!number} */
this.contextLookupOffset2 = 0;
/** @type {!number} */
- this.treeCommandOffset = 0;
- /** @type {!number} */
this.distanceCode = 0;
/** @type {!number} */
this.numDirectDistanceCodes = 0;
@@ -1595,6 +1888,8 @@ function BrotliDecodeClosure() {
this.ringBufferBytesReady = 0;
/** @type {!number} */
this.isEager = 0;
+ /** @type {!number} */
+ this.isLargeWindow = 0;
/** @type {!InputStream|null} */
this.input = null;
this.ringBuffer = new Int8Array(0);
@@ -1617,13 +1912,13 @@ function BrotliDecodeClosure() {
if (dict.length != dictionary.length) {
throw "Corrupted brotli dictionary";
}
- var /** !number */ offset = 0;
- var /** !number */ n = skipFlip.length;
- for (var /** !number */ i = 0; i < n; i += 2) {
- var /** !number */ skip = skipFlip.charCodeAt(i) - 36;
- var /** !number */ flip = skipFlip.charCodeAt(i + 1) - 36;
+ var /** number */ offset = 0;
+ var /** number */ n = skipFlip.length;
+ for (var /** number */ i = 0; i < n; i += 2) {
+ var /** number */ skip = skipFlip.charCodeAt(i) - 36;
+ var /** number */ flip = skipFlip.charCodeAt(i + 1) - 36;
offset += skip;
- for (var /** !number */ j = 0; j < flip; ++j) {
+ for (var /** number */ j = 0; j < flip; ++j) {
dict[offset] |= 0x80;
offset++;
}