@loaders.gl/compression
Version:
Decompression and compression plugins for loaders.gl
1,506 lines (1,500 loc) • 209 kB
text/typescript
// @ts-nocheck
/* eslint-disable */
// Forked from https://raw.githubusercontent.com/google/brotli/master/js/decode.js
// A pure javascript decoder is provided
/* Copyright 2017 Google Inc. All Rights Reserved.
* Distributed under MIT license.
* See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/**
* @typedef {Object} Options
* @property {?Int8Array} customDictionary
*/
let Options;
/**
* Private scope / static initializer for decoder.
*
* @return {function(!Int8Array, Options=):!Int8Array}
*/
let makeBrotliDecode = () => {
/**
* @constructor
* @param {!Int8Array} bytes
* @struct
*/
function InputStream(bytes) {
/** @type {!Int8Array} */
this.data = bytes;
/** @type {!number} */
this.offset = 0;
}
/* GENERATED CODE BEGIN */
/** @type {!Int32Array} */
let 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
]);
/** @type {!Int32Array} */
let CODE_LENGTH_CODE_ORDER = Int32Array.from([
1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15
]);
/** @type {!Int32Array} */
let DISTANCE_SHORT_CODE_INDEX_OFFSET = Int32Array.from([
0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3
]);
/** @type {!Int32Array} */
let DISTANCE_SHORT_CODE_VALUE_OFFSET = Int32Array.from([
0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
]);
/** @type {!Int32Array} */
let FIXED_TABLE = Int32Array.from([
0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040001, 0x020000,
0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040005
]);
/** @type {!Int32Array} */
let 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
]);
/** @type {!Int32Array} */
let 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
]);
/** @type {!Int16Array} */
let 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
]);
/** @type {!Int16Array} */
let 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
]);
/** @type {!Int16Array} */
let CMD_LOOKUP = new Int16Array(2816);
{
unpackCommandLookupTable(CMD_LOOKUP);
}
/**
* @param {number} i
* @return {number}
*/
function log2floor(i) {
let /** @type{number} */ result = -1;
let /** @type{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';
}
let /** @type{number} */ offset = ((maxDistance - ndirect) >> npostfix) + 4;
let /** @type{number} */ ndistbits = log2floor(offset) - 1;
let /** @type{number} */ group = ((ndistbits - 1) << 1) | ((offset >> ndistbits) & 1);
return ((group - 1) << npostfix) + (1 << npostfix) + ndirect + 16;
}
/**
* @param {!Int16Array} cmdLookup
* @return {void}
*/
function unpackCommandLookupTable(cmdLookup) {
let /** @type{!Int16Array} */ insertLengthOffsets = new Int16Array(24);
let /** @type{!Int16Array} */ copyLengthOffsets = new Int16Array(24);
copyLengthOffsets[0] = 2;
for (let /** @type{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 (let /** @type{number} */ cmdCode = 0; cmdCode < 704; ++cmdCode) {
let /** @type{number} */ rangeIdx = cmdCode >>> 6;
let /** @type{number} */ distanceContextOffset = -4;
if (rangeIdx >= 2) {
rangeIdx -= 2;
distanceContextOffset = 0;
}
let /** @type{number} */ insertCode =
(((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7);
let /** @type{number} */ copyCode =
(((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7);
let /** @type{number} */ copyLengthOffset = copyLengthOffsets[copyCode];
let /** @type{number} */ distanceContext =
distanceContextOffset + (copyLengthOffset > 4 ? 3 : copyLengthOffset - 2);
let /** @type{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}
*/
function decodeWindowBits(s) {
let /** @type{number} */ largeWindowEnabled = s.isLargeWindow;
s.isLargeWindow = 0;
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
if (readFewBits(s, 1) == 0) {
return 16;
}
let /** @type{number} */ n = readFewBits(s, 3);
if (n != 0) {
return 17 + n;
}
n = readFewBits(s, 3);
if (n != 0) {
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 {!Int8Array} data
* @return {void}
*/
function attachDictionaryChunk(s, data) {
if (s.runningState != 1) {
throw 'State MUST be freshly initialized';
}
if (s.cdNumChunks == 0) {
s.cdChunks = new Array(16);
s.cdChunkOffsets = new Int32Array(16);
s.cdBlockBits = -1;
}
if (s.cdNumChunks == 15) {
throw 'Too many dictionary chunks';
}
s.cdChunks[s.cdNumChunks] = data;
s.cdNumChunks++;
s.cdTotalSize += data.length;
s.cdChunkOffsets[s.cdNumChunks] = s.cdTotalSize;
}
/**
* @param {!State} s
* @param {!InputStream} input
* @return {void}
*/
function initState(s, input) {
if (s.runningState != 0) {
throw 'State MUST be uninitialized';
}
s.blockTrees = new Int32Array(3091);
s.blockTrees[0] = 7;
s.distRbIdx = 3;
let /** @type{number} */ maxDistanceAlphabetLimit = calculateDistanceAlphabetLimit(
0x7ffffffc,
3,
15 << 3
);
s.distExtraBits = new Int8Array(maxDistanceAlphabetLimit);
s.distOffset = new Int32Array(maxDistanceAlphabetLimit);
s.input = input;
initBitReader(s);
s.runningState = 1;
}
/**
* @param {!State} s
* @return {void}
*/
function close(s) {
if (s.runningState == 0) {
throw 'State MUST be initialized';
}
if (s.runningState == 11) {
return;
}
s.runningState = 11;
if (s.input != null) {
closeInput(s.input);
s.input = null;
}
}
/**
* @param {!State} s
* @return {number}
*/
function decodeVarLenUnsignedByte(s) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
if (readFewBits(s, 1) != 0) {
let /** @type{number} */ n = readFewBits(s, 3);
if (n == 0) {
return 1;
} else {
return readFewBits(s, n) + (1 << n);
}
}
return 0;
}
/**
* @param {!State} s
* @return {void}
*/
function decodeMetaBlockLength(s) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
s.inputEnd = readFewBits(s, 1);
s.metaBlockLength = 0;
s.isUncompressed = 0;
s.isMetadata = 0;
if (s.inputEnd != 0 && readFewBits(s, 1) != 0) {
return;
}
let /** @type{number} */ sizeNibbles = readFewBits(s, 2) + 4;
if (sizeNibbles == 7) {
s.isMetadata = 1;
if (readFewBits(s, 1) != 0) {
throw 'Corrupted reserved bit';
}
let /** @type{number} */ sizeBytes = readFewBits(s, 2);
if (sizeBytes == 0) {
return;
}
for (let /** @type{number} */ i = 0; i < sizeBytes; i++) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ bits = readFewBits(s, 8);
if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {
throw 'Exuberant nibble';
}
s.metaBlockLength |= bits << (i * 8);
}
} else {
for (let /** @type{number} */ i = 0; i < sizeNibbles; i++) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ bits = readFewBits(s, 4);
if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {
throw 'Exuberant nibble';
}
s.metaBlockLength |= bits << (i * 4);
}
}
s.metaBlockLength++;
if (s.inputEnd == 0) {
s.isUncompressed = readFewBits(s, 1);
}
}
/**
* @param {!Int32Array} tableGroup
* @param {number} tableIdx
* @param {!State} s
* @return {number}
*/
function readSymbol(tableGroup, tableIdx, s) {
let /** @type{number} */ offset = tableGroup[tableIdx];
let /** @type{number} */ val = s.accumulator32 >>> s.bitOffset;
offset += val & 0xff;
let /** @type{number} */ bits = tableGroup[offset] >> 16;
let /** @type{number} */ sym = tableGroup[offset] & 0xffff;
if (bits <= 8) {
s.bitOffset += bits;
return sym;
}
offset += sym;
let /** @type{number} */ mask = (1 << bits) - 1;
offset += (val & mask) >>> 8;
s.bitOffset += (tableGroup[offset] >> 16) + 8;
return tableGroup[offset] & 0xffff;
}
/**
* @param {!Int32Array} tableGroup
* @param {number} tableIdx
* @param {!State} s
* @return {number}
*/
function readBlockLength(tableGroup, tableIdx, s) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ code = readSymbol(tableGroup, tableIdx, s);
let /** @type{number} */ n = BLOCK_LENGTH_N_BITS[code];
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
return BLOCK_LENGTH_OFFSET[code] + (n <= 16 ? readFewBits(s, n) : readManyBits(s, n));
}
/**
* @param {!Int32Array} v
* @param {number} index
* @return {void}
*/
function moveToFront(v, index) {
let /** @type{number} */ value = v[index];
for (; index > 0; index--) {
v[index] = v[index - 1];
}
v[0] = value;
}
/**
* @param {!Int8Array} v
* @param {number} vLen
* @return {void}
*/
function inverseMoveToFrontTransform(v, vLen) {
let /** @type{!Int32Array} */ mtf = new Int32Array(256);
for (let /** @type{number} */ i = 0; i < 256; i++) {
mtf[i] = i;
}
for (let /** @type{number} */ i = 0; i < vLen; i++) {
let /** @type{number} */ index = v[i] & 0xff;
v[i] = mtf[index];
if (index != 0) {
moveToFront(mtf, index);
}
}
}
/**
* @param {!Int32Array} codeLengthCodeLengths
* @param {number} numSymbols
* @param {!Int32Array} codeLengths
* @param {!State} s
* @return {void}
*/
function readHuffmanCodeLengths(codeLengthCodeLengths, numSymbols, codeLengths, s) {
let /** @type{number} */ symbol = 0;
let /** @type{number} */ prevCodeLen = 8;
let /** @type{number} */ repeat = 0;
let /** @type{number} */ repeatCodeLen = 0;
let /** @type{number} */ space = 32768;
let /** @type{!Int32Array} */ table = new Int32Array(32 + 1);
let /** @type{number} */ tableIdx = table.length - 1;
buildHuffmanTable(table, tableIdx, 5, codeLengthCodeLengths, 18);
while (symbol < numSymbols && space > 0) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ p = (s.accumulator32 >>> s.bitOffset) & 31;
s.bitOffset += table[p] >> 16;
let /** @type{number} */ codeLen = table[p] & 0xffff;
if (codeLen < 16) {
repeat = 0;
codeLengths[symbol++] = codeLen;
if (codeLen != 0) {
prevCodeLen = codeLen;
space -= 32768 >> codeLen;
}
} else {
let /** @type{number} */ extraBits = codeLen - 14;
let /** @type{number} */ newLen = 0;
if (codeLen == 16) {
newLen = prevCodeLen;
}
if (repeatCodeLen != newLen) {
repeat = 0;
repeatCodeLen = newLen;
}
let /** @type{number} */ oldRepeat = repeat;
if (repeat > 0) {
repeat -= 2;
repeat <<= extraBits;
}
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
repeat += readFewBits(s, extraBits) + 3;
let /** @type{number} */ repeatDelta = repeat - oldRepeat;
if (symbol + repeatDelta > numSymbols) {
throw 'symbol + repeatDelta > numSymbols';
}
for (let /** @type{number} */ i = 0; i < repeatDelta; i++) {
codeLengths[symbol++] = repeatCodeLen;
}
if (repeatCodeLen != 0) {
space -= repeatDelta << (15 - repeatCodeLen);
}
}
}
if (space != 0) {
throw 'Unused space';
}
codeLengths.fill(0, symbol, numSymbols);
}
/**
* @param {!Int32Array} symbols
* @param {number} length
* @return {void}
*/
function checkDupes(symbols, length) {
for (let /** @type{number} */ i = 0; i < length - 1; ++i) {
for (let /** @type{number} */ j = i + 1; j < length; ++j) {
if (symbols[i] == symbols[j]) {
throw 'Duplicate simple Huffman code symbol';
}
}
}
}
/**
* @param {number} alphabetSizeMax
* @param {number} alphabetSizeLimit
* @param {!Int32Array} tableGroup
* @param {number} tableIdx
* @param {!State} s
* @return {number}
*/
function readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s) {
let /** @type{!Int32Array} */ codeLengths = new Int32Array(alphabetSizeLimit);
let /** @type{!Int32Array} */ symbols = new Int32Array(4);
let /** @type{number} */ maxBits = 1 + log2floor(alphabetSizeMax - 1);
let /** @type{number} */ numSymbols = readFewBits(s, 2) + 1;
for (let /** @type{number} */ i = 0; i < numSymbols; i++) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ symbol = readFewBits(s, maxBits);
if (symbol >= alphabetSizeLimit) {
throw "Can't readHuffmanCode";
}
symbols[i] = symbol;
}
checkDupes(symbols, numSymbols);
let /** @type{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 readComplexHuffmanCode(alphabetSizeLimit, skip, tableGroup, tableIdx, s) {
let /** @type{!Int32Array} */ codeLengths = new Int32Array(alphabetSizeLimit);
let /** @type{!Int32Array} */ codeLengthCodeLengths = new Int32Array(18);
let /** @type{number} */ space = 32;
let /** @type{number} */ numCodes = 0;
for (let /** @type{number} */ i = skip; i < 18 && space > 0; i++) {
let /** @type{number} */ codeLenIdx = CODE_LENGTH_CODE_ORDER[i];
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ p = (s.accumulator32 >>> s.bitOffset) & 15;
s.bitOffset += FIXED_TABLE[p] >> 16;
let /** @type{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);
}
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ simpleCodeOrSkip = readFewBits(s, 2);
if (simpleCodeOrSkip == 1) {
return readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s);
} else {
return readComplexHuffmanCode(alphabetSizeLimit, simpleCodeOrSkip, tableGroup, tableIdx, s);
}
}
/**
* @param {number} contextMapSize
* @param {!Int8Array} contextMap
* @param {!State} s
* @return {number}
*/
function decodeContextMap(contextMapSize, contextMap, s) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
let /** @type{number} */ numTrees = decodeVarLenUnsignedByte(s) + 1;
if (numTrees == 1) {
contextMap.fill(0, 0, contextMapSize);
return numTrees;
}
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ useRleForZeros = readFewBits(s, 1);
let /** @type{number} */ maxRunLengthPrefix = 0;
if (useRleForZeros != 0) {
maxRunLengthPrefix = readFewBits(s, 4) + 1;
}
let /** @type{number} */ alphabetSize = numTrees + maxRunLengthPrefix;
let /** @type{number} */ tableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSize + 31) >> 5];
let /** @type{!Int32Array} */ table = new Int32Array(tableSize + 1);
let /** @type{number} */ tableIdx = table.length - 1;
readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s);
for (let /** @type{number} */ i = 0; i < contextMapSize; ) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ code = readSymbol(table, tableIdx, s);
if (code == 0) {
contextMap[i] = 0;
i++;
} else if (code <= maxRunLengthPrefix) {
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ reps = (1 << code) + readFewBits(s, code);
while (reps != 0) {
if (i >= contextMapSize) {
throw 'Corrupted context map';
}
contextMap[i] = 0;
i++;
reps--;
}
} else {
contextMap[i] = code - maxRunLengthPrefix;
i++;
}
}
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
if (readFewBits(s, 1) == 1) {
inverseMoveToFrontTransform(contextMap, contextMapSize);
}
return numTrees;
}
/**
* @param {!State} s
* @param {number} treeType
* @param {number} numBlockTypes
* @return {number}
*/
function decodeBlockTypeAndLength(s, treeType, numBlockTypes) {
let /** @type{!Int32Array} */ ringBuffers = s.rings;
let /** @type{number} */ offset = 4 + treeType * 2;
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ blockType = readSymbol(s.blockTrees, 2 * treeType, s);
let /** @type{number} */ result = readBlockLength(s.blockTrees, 2 * treeType + 1, s);
if (blockType == 1) {
blockType = ringBuffers[offset + 1] + 1;
} else if (blockType == 0) {
blockType = ringBuffers[offset];
} else {
blockType -= 2;
}
if (blockType >= numBlockTypes) {
blockType -= numBlockTypes;
}
ringBuffers[offset] = ringBuffers[offset + 1];
ringBuffers[offset + 1] = blockType;
return result;
}
/**
* @param {!State} s
* @return {void}
*/
function decodeLiteralBlockSwitch(s) {
s.literalBlockLength = decodeBlockTypeAndLength(s, 0, s.numLiteralBlockTypes);
let /** @type{number} */ literalBlockType = s.rings[5];
s.contextMapSlice = literalBlockType << 6;
s.literalTreeIdx = s.contextMap[s.contextMapSlice] & 0xff;
let /** @type{number} */ contextMode = s.contextModes[literalBlockType];
s.contextLookupOffset1 = contextMode << 9;
s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
}
/**
* @param {!State} s
* @return {void}
*/
function decodeCommandBlockSwitch(s) {
s.commandBlockLength = decodeBlockTypeAndLength(s, 1, s.numCommandBlockTypes);
s.commandTreeIdx = s.rings[7];
}
/**
* @param {!State} s
* @return {void}
*/
function decodeDistanceBlockSwitch(s) {
s.distanceBlockLength = decodeBlockTypeAndLength(s, 2, s.numDistanceBlockTypes);
s.distContextMapSlice = s.rings[9] << 2;
}
/**
* @param {!State} s
* @return {void}
*/
function maybeReallocateRingBuffer(s) {
let /** @type{number} */ newSize = s.maxRingBufferSize;
if (newSize > s.expectedTotalSize) {
let /** @type{number} */ minimalNewSize = s.expectedTotalSize;
while (newSize >> 1 > minimalNewSize) {
newSize >>= 1;
}
if (s.inputEnd == 0 && newSize < 16384 && s.maxRingBufferSize >= 16384) {
newSize = 16384;
}
}
if (newSize <= s.ringBufferSize) {
return;
}
let /** @type{number} */ ringBufferSizeWithSlack = newSize + 37;
let /** @type{!Int8Array} */ newBuffer = new Int8Array(ringBufferSizeWithSlack);
if (s.ringBuffer.length != 0) {
newBuffer.set(s.ringBuffer.subarray(0, 0 + s.ringBufferSize), 0);
}
s.ringBuffer = newBuffer;
s.ringBufferSize = newSize;
}
/**
* @param {!State} s
* @return {void}
*/
function readNextMetablockHeader(s) {
if (s.inputEnd != 0) {
s.nextRunningState = 10;
s.runningState = 12;
return;
}
s.literalTreeGroup = new Int32Array(0);
s.commandTreeGroup = new Int32Array(0);
s.distanceTreeGroup = new Int32Array(0);
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
decodeMetaBlockLength(s);
if (s.metaBlockLength == 0 && s.isMetadata == 0) {
return;
}
if (s.isUncompressed != 0 || s.isMetadata != 0) {
jumpToByteBoundary(s);
s.runningState = s.isMetadata != 0 ? 5 : 6;
} else {
s.runningState = 3;
}
if (s.isMetadata != 0) {
return;
}
s.expectedTotalSize += s.metaBlockLength;
if (s.expectedTotalSize > 1 << 30) {
s.expectedTotalSize = 1 << 30;
}
if (s.ringBufferSize < s.maxRingBufferSize) {
maybeReallocateRingBuffer(s);
}
}
/**
* @param {!State} s
* @param {number} treeType
* @param {number} numBlockTypes
* @return {number}
*/
function readMetablockPartition(s, treeType, numBlockTypes) {
let /** @type{number} */ offset = s.blockTrees[2 * treeType];
if (numBlockTypes <= 1) {
s.blockTrees[2 * treeType + 1] = offset;
s.blockTrees[2 * treeType + 2] = offset;
return 1 << 28;
}
let /** @type{number} */ blockTypeAlphabetSize = numBlockTypes + 2;
offset += readHuffmanCode(
blockTypeAlphabetSize,
blockTypeAlphabetSize,
s.blockTrees,
2 * treeType,
s
);
s.blockTrees[2 * treeType + 1] = offset;
let /** @type{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) {
let /** @type{!Int8Array} */ distExtraBits = s.distExtraBits;
let /** @type{!Int32Array} */ distOffset = s.distOffset;
let /** @type{number} */ npostfix = s.distancePostfixBits;
let /** @type{number} */ ndirect = s.numDirectDistanceCodes;
let /** @type{number} */ postfix = 1 << npostfix;
let /** @type{number} */ bits = 1;
let /** @type{number} */ half = 0;
let /** @type{number} */ i = 16;
for (let /** @type{number} */ j = 0; j < ndirect; ++j) {
distExtraBits[i] = 0;
distOffset[i] = j + 1;
++i;
}
while (i < alphabetSizeLimit) {
let /** @type{number} */ base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
for (let /** @type{number} */ j = 0; j < postfix; ++j) {
distExtraBits[i] = bits;
distOffset[i] = base + j;
++i;
}
bits = bits + half;
half = half ^ 1;
}
}
/**
* @param {!State} s
* @return {void}
*/
function readMetablockHuffmanCodesAndContextMaps(s) {
s.numLiteralBlockTypes = decodeVarLenUnsignedByte(s) + 1;
s.literalBlockLength = readMetablockPartition(s, 0, s.numLiteralBlockTypes);
s.numCommandBlockTypes = decodeVarLenUnsignedByte(s) + 1;
s.commandBlockLength = readMetablockPartition(s, 1, s.numCommandBlockTypes);
s.numDistanceBlockTypes = decodeVarLenUnsignedByte(s) + 1;
s.distanceBlockLength = readMetablockPartition(s, 2, s.numDistanceBlockTypes);
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
s.distancePostfixBits = readFewBits(s, 2);
s.numDirectDistanceCodes = readFewBits(s, 4) << s.distancePostfixBits;
s.contextModes = new Int8Array(s.numLiteralBlockTypes);
for (let /** @type{number} */ i = 0; i < s.numLiteralBlockTypes; ) {
let /** @type{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);
}
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
}
s.contextMap = new Int8Array(s.numLiteralBlockTypes << 6);
let /** @type{number} */ numLiteralTrees = decodeContextMap(
s.numLiteralBlockTypes << 6,
s.contextMap,
s
);
s.trivialLiteralContext = 1;
for (let /** @type{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);
let /** @type{number} */ numDistTrees = decodeContextMap(
s.numDistanceBlockTypes << 2,
s.distContextMap,
s
);
s.literalTreeGroup = decodeHuffmanTreeGroup(256, 256, numLiteralTrees, s);
s.commandTreeGroup = decodeHuffmanTreeGroup(704, 704, s.numCommandBlockTypes, s);
let /** @type{number} */ distanceAlphabetSizeMax = calculateDistanceAlphabetSize(
s.distancePostfixBits,
s.numDirectDistanceCodes,
24
);
let /** @type{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] * 512;
s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
s.literalTreeIdx = 0;
s.commandTreeIdx = 0;
s.rings[4] = 1;
s.rings[5] = 0;
s.rings[6] = 1;
s.rings[7] = 0;
s.rings[8] = 1;
s.rings[9] = 0;
}
/**
* @param {!State} s
* @return {void}
*/
function copyUncompressedData(s) {
let /** @type{!Int8Array} */ ringBuffer = s.ringBuffer;
if (s.metaBlockLength <= 0) {
reload(s);
s.runningState = 2;
return;
}
let /** @type{number} */ chunkLength = min(s.ringBufferSize - s.pos, s.metaBlockLength);
copyRawBytes(s, ringBuffer, s.pos, chunkLength);
s.metaBlockLength -= chunkLength;
s.pos += chunkLength;
if (s.pos == s.ringBufferSize) {
s.nextRunningState = 6;
s.runningState = 12;
return;
}
reload(s);
s.runningState = 2;
}
/**
* @param {!State} s
* @return {number}
*/
function writeRingBuffer(s) {
let /** @type{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;
s.ringBufferBytesWritten += toWrite;
}
if (s.outputUsed < s.outputLength) {
return 1;
} else {
return 0;
}
}
/**
* @param {number} alphabetSizeMax
* @param {number} alphabetSizeLimit
* @param {number} n
* @param {!State} s
* @return {!Int32Array}
*/
function decodeHuffmanTreeGroup(alphabetSizeMax, alphabetSizeLimit, n, s) {
let /** @type{number} */ maxTableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSizeLimit + 31) >> 5];
let /** @type{!Int32Array} */ group = new Int32Array(n + n * maxTableSize);
let /** @type{number} */ next = n;
for (let /** @type{number} */ i = 0; i < n; ++i) {
group[i] = next;
next += readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, group, i, s);
}
return group;
}
/**
* @param {!State} s
* @return {number}
*/
function calculateFence(s) {
let /** @type{number} */ result = s.ringBufferSize;
if (s.isEager != 0) {
result = min(result, s.ringBufferBytesWritten + s.outputLength - s.outputUsed);
}
return result;
}
/**
* @param {!State} s
* @param {number} fence
* @return {void}
*/
function doUseDictionary(s, fence) {
if (s.distance > 0x7ffffffc) {
throw 'Invalid backward reference';
}
let /** @type{number} */ address = s.distance - s.maxDistance - 1 - s.cdTotalSize;
if (address < 0) {
initializeCompoundDictionaryCopy(s, -address - 1, s.copyLength);
s.runningState = 14;
} else {
let /** @type{!Int8Array} */ dictionaryData = /** @type{!Int8Array} */ data;
let /** @type{number} */ wordLength = s.copyLength;
if (wordLength > 31) {
throw 'Invalid backward reference';
}
let /** @type{number} */ shift = sizeBits[wordLength];
if (shift == 0) {
throw 'Invalid backward reference';
}
let /** @type{number} */ offset = offsets[wordLength];
let /** @type{number} */ mask = (1 << shift) - 1;
let /** @type{number} */ wordIdx = address & mask;
let /** @type{number} */ transformIdx = address >>> shift;
offset += wordIdx * wordLength;
let /** @type{!Transforms} */ transforms = RFC_TRANSFORMS;
if (transformIdx >= transforms.numTransforms) {
throw 'Invalid backward reference';
}
let /** @type{number} */ len = transformDictionaryWord(
s.ringBuffer,
s.pos,
dictionaryData,
offset,
wordLength,
transforms,
transformIdx
);
s.pos += len;
s.metaBlockLength -= len;
if (s.pos >= fence) {
s.nextRunningState = 4;
s.runningState = 12;
return;
}
s.runningState = 4;
}
}
/**
* @param {!State} s
* @return {void}
*/
function initializeCompoundDictionary(s) {
s.cdBlockMap = new Int8Array(256);
let /** @type{number} */ blockBits = 8;
while ((s.cdTotalSize - 1) >>> blockBits != 0) {
blockBits++;
}
blockBits -= 8;
s.cdBlockBits = blockBits;
let /** @type{number} */ cursor = 0;
let /** @type{number} */ index = 0;
while (cursor < s.cdTotalSize) {
while (s.cdChunkOffsets[index + 1] < cursor) {
index++;
}
s.cdBlockMap[cursor >>> blockBits] = index;
cursor += 1 << blockBits;
}
}
/**
* @param {!State} s
* @param {number} address
* @param {number} length
* @return {void}
*/
function initializeCompoundDictionaryCopy(s, address, length) {
if (s.cdBlockBits == -1) {
initializeCompoundDictionary(s);
}
let /** @type{number} */ index = s.cdBlockMap[address >>> s.cdBlockBits];
while (address >= s.cdChunkOffsets[index + 1]) {
index++;
}
if (s.cdTotalSize > address + length) {
throw 'Invalid backward reference';
}
s.distRbIdx = (s.distRbIdx + 1) & 0x3;
s.rings[s.distRbIdx] = s.distance;
s.metaBlockLength -= length;
s.cdBrIndex = index;
s.cdBrOffset = address - s.cdChunkOffsets[index];
s.cdBrLength = length;
s.cdBrCopied = 0;
}
/**
* @param {!State} s
* @param {number} fence
* @return {number}
*/
function copyFromCompoundDictionary(s, fence) {
let /** @type{number} */ pos = s.pos;
let /** @type{number} */ origPos = pos;
while (s.cdBrLength != s.cdBrCopied) {
let /** @type{number} */ space = fence - pos;
let /** @type{number} */ chunkLength =
s.cdChunkOffsets[s.cdBrIndex + 1] - s.cdChunkOffsets[s.cdBrIndex];
let /** @type{number} */ remChunkLength = chunkLength - s.cdBrOffset;
let /** @type{number} */ length = s.cdBrLength - s.cdBrCopied;
if (length > remChunkLength) {
length = remChunkLength;
}
if (length > space) {
length = space;
}
copyBytes(s.ringBuffer, pos, s.cdChunks[s.cdBrIndex], s.cdBrOffset, s.cdBrOffset + length);
pos += length;
s.cdBrOffset += length;
s.cdBrCopied += length;
if (length == remChunkLength) {
s.cdBrIndex++;
s.cdBrOffset = 0;
}
if (pos >= fence) {
break;
}
}
return pos - origPos;
}
/**
* @param {!State} s
* @return {void}
*/
function decompress(s) {
if (s.runningState == 0) {
throw "Can't decompress until initialized";
}
if (s.runningState == 11) {
throw "Can't decompress after close";
}
if (s.runningState == 1) {
let /** @type{number} */ windowBits = decodeWindowBits(s);
if (windowBits == -1) {
throw "Invalid 'windowBits' code";
}
s.maxRingBufferSize = 1 << windowBits;
s.maxBackwardDistance = s.maxRingBufferSize - 16;
s.runningState = 2;
}
let /** @type{number} */ fence = calculateFence(s);
let /** @type{number} */ ringBufferMask = s.ringBufferSize - 1;
let /** @type{!Int8Array} */ ringBuffer = s.ringBuffer;
while (s.runningState != 10) {
switch (s.runningState) {
case 2:
if (s.metaBlockLength < 0) {
throw 'Invalid metablock length';
}
readNextMetablockHeader(s);
fence = calculateFence(s);
ringBufferMask = s.ringBufferSize - 1;
ringBuffer = s.ringBuffer;
continue;
case 3:
readMetablockHuffmanCodesAndContextMaps(s);
s.runningState = 4;
case 4:
if (s.metaBlockLength <= 0) {
s.runningState = 2;
continue;
}
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
if (s.commandBlockLength == 0) {
decodeCommandBlockSwitch(s);
}
s.commandBlockLength--;
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ cmdCode =
readSymbol(s.commandTreeGroup, s.commandTreeIdx, s) << 2;
let /** @type{number} */ insertAndCopyExtraBits = CMD_LOOKUP[cmdCode];
let /** @type{number} */ insertLengthOffset = CMD_LOOKUP[cmdCode + 1];
let /** @type{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;
}
let /** @type{number} */ insertLengthExtraBits = insertAndCopyExtraBits & 0xff;
s.insertLength =
insertLengthOffset +
(insertLengthExtraBits <= 16
? readFewBits(s, insertLengthExtraBits)
: readManyBits(s, insertLengthExtraBits));
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ copyLengthExtraBits = insertAndCopyExtraBits >> 8;
s.copyLength =
copyLengthOffset +
(copyLengthExtraBits <= 16
? readFewBits(s, copyLengthExtraBits)
: readManyBits(s, copyLengthExtraBits));
s.j = 0;
s.runningState = 7;
case 7:
if (s.trivialLiteralContext != 0) {
while (s.j < s.insertLength) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
if (s.literalBlockLength == 0) {
decodeLiteralBlockSwitch(s);
}
s.literalBlockLength--;
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
ringBuffer[s.pos] = readSymbol(s.literalTreeGroup, s.literalTreeIdx, s);
s.pos++;
s.j++;
if (s.pos >= fence) {
s.nextRunningState = 7;
s.runningState = 12;
break;
}
}
} else {
let /** @type{number} */ prevByte1 = ringBuffer[(s.pos - 1) & ringBufferMask] & 0xff;
let /** @type{number} */ prevByte2 = ringBuffer[(s.pos - 2) & ringBufferMask] & 0xff;
while (s.j < s.insertLength) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
if (s.literalBlockLength == 0) {
decodeLiteralBlockSwitch(s);
}
let /** @type{number} */ literalContext =
LOOKUP[s.contextLookupOffset1 + prevByte1] |
LOOKUP[s.contextLookupOffset2 + prevByte2];
let /** @type{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.literalTreeGroup, literalTreeIdx, s);
ringBuffer[s.pos] = prevByte1;
s.pos++;
s.j++;
if (s.pos >= fence) {
s.nextRunningState = 7;
s.runningState = 12;
break;
}
}
}
if (s.runningState != 7) {
continue;
}
s.metaBlockLength -= s.insertLength;
if (s.metaBlockLength <= 0) {
s.runningState = 4;
continue;
}
let /** @type{number} */ distanceCode = s.distanceCode;
if (distanceCode < 0) {
s.distance = s.rings[s.distRbIdx];
} else {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
if (s.distanceBlockLength == 0) {
decodeDistanceBlockSwitch(s);
}
s.distanceBlockLength--;
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
let /** @type{number} */ distTreeIdx =
s.distContextMap[s.distContextMapSlice + distanceCode] & 0xff;
distanceCode = readSymbol(s.distanceTreeGroup, distTreeIdx, s);
if (distanceCode < 16) {
let /** @type{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';
}
} else {
let /** @type{number} */ extraBits = s.distExtraBits[distanceCode];
let /** @type{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);
}
}
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 = 9;
continue;
}
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 = 8;
case 8:
let /** @type{number} */ src = (s.pos - s.distance) & ringBufferMask;
let /** @type{number} */ dst = s.pos;
let /** @type{number} */ copyLength = s.copyLength - s.j;
let /** @type{number} */ srcEnd = src + copyLength;
let /** @type{number} */ dstEnd = dst + copyLength;
if (srcEnd < ringBufferMask && dstEnd < ringBufferMask) {
if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) {
for (let /** @type{number} */ k = 0; k < copyLength; k += 4) {
ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++];
}
} else {
ringBuffer.copyWithin(dst, src, srcEnd);
}
s.j += copyLength;
s.metaBlockLength -= copyLength;
s.pos += copyLength;
} else {
for (; s.j < s.copyLength; ) {
ringBuffer[s.pos] = ringBuffer[(s.pos - s.distance) & ringBufferMask];
s.metaBlockLength--;
s.pos++;
s.j++;
if (s.pos >= fence) {
s.nextRunningState = 8;
s.runningState = 12;
break;
}
}
}
if (s.runningState == 8) {
s.runningState = 4;
}
continue;
case 9:
doUseDictionary(s, fence);
continue;
case 14:
s.pos += copyFromCompoundDictionary(s, fence);
if (s.pos >= fence) {
s.nextRunningState = 14;
s.runningState = 12;
return;
}
s.runningState = 4;
continue;
case 5:
while (s.metaBlockLength > 0) {
if (s.halfOffset > 2030) {
doReadMoreInput(s);
}
if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16;
}
readFewBits(s, 8);
s.metaBlockLength--;
}
s.runningState = 2;
continue;
case 6:
copyUncompressedData(s);
continue;
case 12:
s.ringBufferBytesReady = min(s.pos, s.ringBufferSize);
s.runningState = 13;
case 13:
if (writeRingBuffer(s) == 0) {
return;
}
if (s.pos >= s.maxBackwardDistance) {
s.maxDistance = s.maxBackwardDistance;
}
if (s.pos >= s.ringBufferSize) {
if (s.pos > s.ringBufferSize) {
ringBuffer.copyWithin(0, s.ringBufferSize, s.pos);
}
s.pos &= ringBufferMask;
s.ringBufferBytesWritten = 0;
}
s.runningState = s.nextRunningState;
continue;
default:
throw 'Unexpected state ' + s.runningState;
}
}
if (s.runningState == 10) {
if (s.metaBlockLength < 0) {
throw 'Invalid metablock length';
}
jumpToByteBoundary(s);
checkHealth(s, 1);
}
}
/**
* @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);
}
/** @type {!Transforms} */
let RFC_TRANSFORMS = new Transforms(121, 167, 50);
/**
* @param {!Int8Array} prefixSuffix
* @param {!Int32Array} prefixSuffixHeads
* @param {!Int32Array} transforms
*