UNPKG

@loaders.gl/compression

Version:

Decompression and compression plugins for loaders.gl

4 lines 292 kB
{ "version": 3, "sources": ["../src/index.ts", "../src/lib/compression.ts", "../src/lib/no-compression.ts", "../src/lib/deflate-compression.ts", "../src/lib/gzip-compression.ts", "../src/lib/brotli-compression.ts", "../src/brotli/decode.ts", "../src/lib/snappy-compression.ts", "../src/lib/lz4-compression.ts", "../src/lib/zstd-compression.ts", "../src/compress-on-worker.ts"], "sourcesContent": ["// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nexport type {CompressionOptions} from './lib/compression';\n\nexport {Compression} from './lib/compression';\n\nexport {NoCompression} from './lib/no-compression';\nexport {DeflateCompression} from './lib/deflate-compression';\nexport {GZipCompression} from './lib/gzip-compression';\nexport {BrotliCompression} from './lib/brotli-compression';\nexport {SnappyCompression} from './lib/snappy-compression';\nexport {LZ4Compression} from './lib/lz4-compression';\nexport {ZstdCompression} from './lib/zstd-compression';\n\nexport type {CompressionWorkerOptions} from './compress-on-worker';\nexport {CompressionWorker, compressOnWorker} from './compress-on-worker';\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// Compression interface\nimport {concatenateArrayBuffersAsync, registerJSModules} from '@loaders.gl/loader-utils';\n\n/** Compression options */\nexport type CompressionOptions = {\n // operation: 'compress' | 'decompress';\n modules?: {[moduleName: string]: any};\n};\n\n/** Compression */\nexport abstract class Compression {\n abstract readonly name: string;\n abstract readonly extensions: string[];\n abstract readonly contentEncodings: string[];\n abstract readonly isSupported: boolean;\n\n constructor(options?: CompressionOptions) {\n this.compressBatches = this.compressBatches.bind(this);\n this.decompressBatches = this.decompressBatches.bind(this);\n }\n\n /** Preloads any dynamic libraries. May enable sync functions */\n async preload(modules: Record<string, any> = {}): Promise<void> {\n registerJSModules(modules);\n return;\n }\n\n /** Asynchronously compress data */\n async compress(input: ArrayBuffer): Promise<ArrayBuffer> {\n await this.preload();\n return this.compressSync(input);\n }\n\n /** Asynchronously decompress data */\n async decompress(input: ArrayBuffer, size?: number): Promise<ArrayBuffer> {\n await this.preload();\n return this.decompressSync(input, size);\n }\n\n /** Synchronously compress data */\n compressSync(input: ArrayBuffer): ArrayBuffer {\n throw new Error(`${this.name}: sync compression not supported`);\n }\n\n /** Synchronously compress data */\n decompressSync(input: ArrayBuffer, size?: number): ArrayBuffer {\n throw new Error(`${this.name}: sync decompression not supported`);\n }\n\n /** Compress batches */\n async *compressBatches(\n asyncIterator: AsyncIterable<ArrayBuffer> | Iterable<ArrayBuffer>\n ): AsyncIterable<ArrayBuffer> {\n // TODO - implement incremental compression\n const input = await this.concatenate(asyncIterator);\n yield this.compress(input);\n }\n\n /** Decompress batches */\n async *decompressBatches(\n asyncIterator: AsyncIterable<ArrayBuffer> | Iterable<ArrayBuffer>\n ): AsyncIterable<ArrayBuffer> {\n // TODO - implement incremental compression\n const input = await this.concatenate(asyncIterator);\n yield this.decompress(input);\n }\n\n // HELPERS\n\n protected concatenate(asyncIterator): Promise<ArrayBuffer> {\n return concatenateArrayBuffersAsync(asyncIterator);\n }\n\n protected improveError(error) {\n if (!error.message.includes(this.name)) {\n error.message = `${this.name} ${error.message}`;\n }\n return error;\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// NO COMPRESSION\nimport type {CompressionOptions} from './compression';\nimport {Compression} from './compression';\n\n/**\n * Applies no compression.\n */\nexport class NoCompression extends Compression {\n readonly name: string = 'uncompressed';\n readonly extensions: string[] = [];\n readonly contentEncodings: string[] = [];\n readonly isSupported = true;\n\n readonly options: CompressionOptions;\n\n constructor(options?: CompressionOptions) {\n super(options);\n this.options = options || {};\n }\n\n compressSync(input: ArrayBuffer): ArrayBuffer {\n return input;\n }\n\n decompressSync(input: ArrayBuffer): ArrayBuffer {\n return input;\n }\n\n async *compressBatches(\n asyncIterator: AsyncIterable<ArrayBuffer> | Iterable<ArrayBuffer>\n ): AsyncIterable<ArrayBuffer> {\n return yield* asyncIterator;\n }\n\n async *decompressBatches(\n asyncIterator: AsyncIterable<ArrayBuffer> | Iterable<ArrayBuffer>\n ): AsyncIterable<ArrayBuffer> {\n return yield* asyncIterator;\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// DEFLATE\nimport type {CompressionOptions} from './compression';\nimport {Compression} from './compression';\nimport {isBrowser, toArrayBuffer, promisify1} from '@loaders.gl/loader-utils';\nimport pako from 'pako'; // https://bundlephobia.com/package/pako\nimport zlib from 'zlib';\n\nexport type DeflateCompressionOptions = CompressionOptions & {\n deflate?: pako.InflateOptions & pako.DeflateOptions & {useZlib?: boolean};\n /** creates raw data, without wrapper (header and adler32 crc). */\n raw?: boolean;\n};\n\n/**\n * DEFLATE compression / decompression\n */\nexport class DeflateCompression extends Compression {\n readonly name: string = 'deflate';\n readonly extensions: string[] = [];\n readonly contentEncodings = ['deflate'];\n readonly isSupported = true;\n\n readonly options: DeflateCompressionOptions;\n\n private _chunks: ArrayBuffer[] = [];\n\n constructor(options: DeflateCompressionOptions = {}) {\n super(options);\n this.options = options;\n }\n\n async compress(input: ArrayBuffer): Promise<ArrayBuffer> {\n // On Node.js we can use built-in zlib\n if (!isBrowser && this.options.deflate?.useZlib) {\n const buffer = this.options.deflate?.gzip\n ? await promisify1(zlib.gzip)(input)\n : await promisify1(zlib.deflate)(input);\n return toArrayBuffer(buffer as Buffer);\n }\n return this.compressSync(input);\n }\n\n async decompress(input: ArrayBuffer): Promise<ArrayBuffer> {\n // On Node.js we can use built-in zlib\n if (!isBrowser && this.options.deflate?.useZlib) {\n const buffer = this.options.deflate?.gzip\n ? await promisify1(zlib.gunzip)(input)\n : await promisify1(zlib.inflate)(input);\n return toArrayBuffer(buffer as Buffer);\n }\n return this.decompressSync(input);\n }\n\n compressSync(input: ArrayBuffer): ArrayBuffer {\n // On Node.js we can use built-in zlib\n if (!isBrowser && this.options.deflate?.useZlib) {\n const buffer = this.options.deflate?.gzip ? zlib.gzipSync(input) : zlib.deflateSync(input);\n return toArrayBuffer(buffer);\n }\n const pakoOptions: pako.DeflateOptions = this.options?.deflate || {};\n const inputArray = new Uint8Array(input);\n const deflate = this.options?.raw ? pako.deflateRaw : pako.deflate;\n return toArrayBuffer(deflate(inputArray, pakoOptions).buffer);\n }\n\n decompressSync(input: ArrayBuffer): ArrayBuffer {\n // On Node.js we can use built-in zlib\n if (!isBrowser && this.options.deflate?.useZlib) {\n const buffer = this.options.deflate?.gzip ? zlib.gunzipSync(input) : zlib.inflateSync(input);\n return toArrayBuffer(buffer);\n }\n const pakoOptions: pako.InflateOptions = this.options?.deflate || {};\n const inputArray = new Uint8Array(input);\n const inflate = this.options?.raw ? pako.inflateRaw : pako.inflate;\n return toArrayBuffer(inflate(inputArray, pakoOptions).buffer);\n }\n\n async *compressBatches(\n asyncIterator: AsyncIterable<ArrayBuffer> | Iterable<ArrayBuffer>\n ): AsyncIterable<ArrayBuffer> {\n const pakoOptions: pako.DeflateOptions = this.options?.deflate || {};\n const pakoProcessor = new pako.Deflate(pakoOptions);\n yield* this.transformBatches(pakoProcessor, asyncIterator);\n }\n\n async *decompressBatches(\n asyncIterator: AsyncIterable<ArrayBuffer> | Iterable<ArrayBuffer>\n ): AsyncIterable<ArrayBuffer> {\n const pakoOptions: pako.InflateOptions = this.options?.deflate || {};\n const pakoProcessor = new pako.Inflate(pakoOptions);\n yield* this.transformBatches(pakoProcessor, asyncIterator);\n }\n\n async *transformBatches(\n pakoProcessor: pako.Inflate | pako.Deflate,\n asyncIterator: AsyncIterable<ArrayBuffer> | Iterable<ArrayBuffer>\n ): AsyncIterable<ArrayBuffer> {\n pakoProcessor.onData = this._onData.bind(this);\n pakoProcessor.onEnd = this._onEnd.bind(this);\n for await (const chunk of asyncIterator) {\n const uint8Array = new Uint8Array(chunk);\n const ok = pakoProcessor.push(uint8Array, false); // false -> not last chunk\n if (!ok) {\n throw new Error(`${this._getError()}write`);\n }\n const chunks = this._getChunks();\n yield* chunks;\n }\n\n // End\n const emptyChunk = new Uint8Array(0);\n const ok = pakoProcessor.push(emptyChunk, true); // true -> last chunk\n if (!ok) {\n // For some reason we get error but it still works???\n // throw new Error(this._getError() + 'end');\n }\n const chunks = this._getChunks();\n yield* chunks;\n }\n\n _onData(chunk) {\n this._chunks.push(chunk);\n }\n\n _onEnd(status) {\n if (status !== 0) {\n throw new Error(this._getError(status) + this._chunks.length);\n }\n }\n\n _getChunks(): ArrayBuffer[] {\n const chunks = this._chunks;\n this._chunks = [];\n return chunks;\n }\n\n // TODO - For some reason we don't get the error message from pako in _onEnd?\n _getError(code: number = 0): string {\n const MESSAGES = {\n /* Z_NEED_DICT 2 */\n 2: 'need dictionary',\n /* Z_STREAM_END 1 */\n 1: 'stream end',\n /* Z_OK 0 */\n 0: '',\n /* Z_ERRNO (-1) */\n '-1': 'file error',\n /* Z_STREAM_ERROR (-2) */\n '-2': 'stream error',\n /* Z_DATA_ERROR (-3) */\n '-3': 'data error',\n /* Z_MEM_ERROR (-4) */\n '-4': 'insufficient memory',\n /* Z_BUF_ERROR (-5) */\n '-5': 'buffer error',\n /* Z_VERSION_ERROR (-6) */\n '-6': 'incompatible version'\n };\n return `${this.name}: ${MESSAGES[code]}`;\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// GZIP\n// import {isBrowser} from '@loaders.gl/loader-utils';\nimport type {CompressionOptions} from './compression';\nimport {DeflateCompression} from './deflate-compression';\nimport pako from 'pako'; // https://bundlephobia.com/package/pako\n\nexport type GZipCompressionOptions = CompressionOptions & {\n gzip?: pako.InflateOptions & pako.DeflateOptions;\n};\n\n/**\n * GZIP compression / decompression\n */\nexport class GZipCompression extends DeflateCompression {\n readonly name: string = 'gzip';\n readonly extensions = ['gz', 'gzip'];\n readonly contentEncodings = ['gzip', 'x-gzip'];\n readonly isSupported = true;\n\n constructor(options?: GZipCompressionOptions) {\n super({...options, deflate: {...options?.gzip, gzip: true}});\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// BROTLI\nimport type {CompressionOptions} from './compression';\nimport {Compression} from './compression';\nimport {\n isBrowser,\n toArrayBuffer,\n registerJSModules,\n getJSModule,\n getJSModuleOrNull,\n promisify1\n} from '@loaders.gl/loader-utils';\n\nimport type brotliNamespace from 'brotli';\n// import brotli from 'brotli'; // https://bundlephobia.com/package/brotli\nimport {BrotliDecode} from '../brotli/decode';\nimport zlib from 'zlib';\n\nexport type BrotliCompressionOptions = CompressionOptions & {\n brotli?: {\n mode?: number;\n quality?: number;\n lgwin?: number;\n useZlib?: boolean;\n };\n};\n\nconst DEFAULT_BROTLI_OPTIONS = {\n brotli: {\n mode: 0,\n quality: 8,\n lgwin: 22\n }\n};\n\ntype Brotli = typeof brotliNamespace;\n\n/**\n * brotli compression / decompression\n */\nexport class BrotliCompression extends Compression {\n readonly name: string = 'brotli';\n readonly extensions = ['br'];\n readonly contentEncodings = ['br'];\n readonly isSupported = true;\n readonly options: BrotliCompressionOptions;\n\n constructor(options: BrotliCompressionOptions) {\n super(options);\n this.options = options;\n registerJSModules(options?.modules);\n }\n\n /**\n * brotli is an injectable dependency due to big size\n * @param options\n */\n async preload(modules: Record<string, any> = {}): Promise<void> {\n registerJSModules(modules);\n }\n\n async compress(input: ArrayBuffer): Promise<ArrayBuffer> {\n // On Node.js we can use built-in zlib\n if (!isBrowser && this.options.brotli?.useZlib) {\n const buffer = await promisify1(zlib.brotliCompress)(input);\n return toArrayBuffer(buffer);\n }\n return this.compressSync(input);\n }\n\n compressSync(input: ArrayBuffer): ArrayBuffer {\n // On Node.js we can use built-in zlib\n if (!isBrowser && this.options.brotli?.useZlib) {\n const buffer = zlib.brotliCompressSync(input);\n return toArrayBuffer(buffer);\n }\n const brotliOptions = {...DEFAULT_BROTLI_OPTIONS.brotli, ...this.options?.brotli};\n const inputArray = new Uint8Array(input);\n\n const brotli = getJSModule<Brotli>('brotli', this.name);\n // @ts-ignore brotli types state that only Buffers are accepted...\n const outputArray = brotli.compress(inputArray, brotliOptions);\n return toArrayBuffer(outputArray.buffer);\n }\n\n async decompress(input: ArrayBuffer): Promise<ArrayBuffer> {\n // On Node.js we can use built-in zlib\n if (!isBrowser && this.options.brotli?.useZlib) {\n const buffer = await promisify1(zlib.brotliDecompress)(input);\n return toArrayBuffer(buffer);\n }\n return this.decompressSync(input);\n }\n\n decompressSync(input: ArrayBuffer): ArrayBuffer {\n // On Node.js we can use built-in zlib\n if (!isBrowser && this.options.brotli?.useZlib) {\n const buffer = zlib.brotliDecompressSync(input);\n return toArrayBuffer(buffer);\n }\n\n const brotliOptions = {...DEFAULT_BROTLI_OPTIONS.brotli, ...this.options?.brotli};\n const inputArray = new Uint8Array(input);\n\n const brotli = getJSModuleOrNull<Brotli>('brotli');\n if (brotli) {\n // @ts-ignore brotli types state that only Buffers are accepted...\n const outputArray = brotli.decompress(inputArray, brotliOptions);\n return toArrayBuffer(outputArray.buffer);\n }\n const outputArray = BrotliDecode(inputArray, undefined);\n return outputArray.buffer;\n }\n}\n", "// @ts-nocheck\n/* eslint-disable */\n\n// Forked from https://raw.githubusercontent.com/google/brotli/master/js/decode.js\n// A pure javascript decoder is provided\n/* Copyright 2017 Google Inc. All Rights Reserved.\n * Distributed under MIT license.\n * See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n */\n\n/**\n * @typedef {Object} Options\n * @property {?Int8Array} customDictionary\n */\nlet Options;\n\n/**\n * Private scope / static initializer for decoder.\n *\n * @return {function(!Int8Array, Options=):!Int8Array}\n */\nlet makeBrotliDecode = () => {\n /**\n * @constructor\n * @param {!Int8Array} bytes\n * @struct\n */\n function InputStream(bytes) {\n /** @type {!Int8Array} */\n this.data = bytes;\n /** @type {!number} */\n this.offset = 0;\n }\n\n /* GENERATED CODE BEGIN */\n /** @type {!Int32Array} */\n let MAX_HUFFMAN_TABLE_SIZE = Int32Array.from([\n 256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822, 854, 886, 920, 952,\n 984, 1016, 1048, 1080\n ]);\n /** @type {!Int32Array} */\n let CODE_LENGTH_CODE_ORDER = Int32Array.from([\n 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15\n ]);\n /** @type {!Int32Array} */\n let DISTANCE_SHORT_CODE_INDEX_OFFSET = Int32Array.from([\n 0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3\n ]);\n /** @type {!Int32Array} */\n let DISTANCE_SHORT_CODE_VALUE_OFFSET = Int32Array.from([\n 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3\n ]);\n /** @type {!Int32Array} */\n let FIXED_TABLE = Int32Array.from([\n 0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040001, 0x020000,\n 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040005\n ]);\n /** @type {!Int32Array} */\n let BLOCK_LENGTH_OFFSET = Int32Array.from([\n 1, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 145, 177, 209, 241, 305, 369, 497, 753, 1265,\n 2289, 4337, 8433, 16625\n ]);\n /** @type {!Int32Array} */\n let BLOCK_LENGTH_N_BITS = Int32Array.from([\n 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\n ]);\n /** @type {!Int16Array} */\n let INSERT_LENGTH_N_BITS = Int16Array.from([\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05,\n 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0c, 0x0e, 0x18\n ]);\n /** @type {!Int16Array} */\n let COPY_LENGTH_N_BITS = Int16Array.from([\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04,\n 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x18\n ]);\n /** @type {!Int16Array} */\n let CMD_LOOKUP = new Int16Array(2816);\n {\n unpackCommandLookupTable(CMD_LOOKUP);\n }\n /**\n * @param {number} i\n * @return {number}\n */\n function log2floor(i) {\n let /** @type{number} */ result = -1;\n let /** @type{number} */ step = 16;\n while (step > 0) {\n if (i >>> step != 0) {\n result += step;\n i = i >>> step;\n }\n step = step >> 1;\n }\n return result + i;\n }\n /**\n * @param {number} npostfix\n * @param {number} ndirect\n * @param {number} maxndistbits\n * @return {number}\n */\n function calculateDistanceAlphabetSize(npostfix, ndirect, maxndistbits) {\n return 16 + ndirect + 2 * (maxndistbits << npostfix);\n }\n /**\n * @param {number} maxDistance\n * @param {number} npostfix\n * @param {number} ndirect\n * @return {number}\n */\n function calculateDistanceAlphabetLimit(maxDistance, npostfix, ndirect) {\n if (maxDistance < ndirect + (2 << npostfix)) {\n throw 'maxDistance is too small';\n }\n let /** @type{number} */ offset = ((maxDistance - ndirect) >> npostfix) + 4;\n let /** @type{number} */ ndistbits = log2floor(offset) - 1;\n let /** @type{number} */ group = ((ndistbits - 1) << 1) | ((offset >> ndistbits) & 1);\n return ((group - 1) << npostfix) + (1 << npostfix) + ndirect + 16;\n }\n /**\n * @param {!Int16Array} cmdLookup\n * @return {void}\n */\n function unpackCommandLookupTable(cmdLookup) {\n let /** @type{!Int16Array} */ insertLengthOffsets = new Int16Array(24);\n let /** @type{!Int16Array} */ copyLengthOffsets = new Int16Array(24);\n copyLengthOffsets[0] = 2;\n for (let /** @type{number} */ i = 0; i < 23; ++i) {\n insertLengthOffsets[i + 1] = insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i]);\n copyLengthOffsets[i + 1] = copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i]);\n }\n for (let /** @type{number} */ cmdCode = 0; cmdCode < 704; ++cmdCode) {\n let /** @type{number} */ rangeIdx = cmdCode >>> 6;\n let /** @type{number} */ distanceContextOffset = -4;\n if (rangeIdx >= 2) {\n rangeIdx -= 2;\n distanceContextOffset = 0;\n }\n let /** @type{number} */ insertCode =\n (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7);\n let /** @type{number} */ copyCode =\n (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7);\n let /** @type{number} */ copyLengthOffset = copyLengthOffsets[copyCode];\n let /** @type{number} */ distanceContext =\n distanceContextOffset + (copyLengthOffset > 4 ? 3 : copyLengthOffset - 2);\n let /** @type{number} */ index = cmdCode * 4;\n cmdLookup[index + 0] = INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8);\n cmdLookup[index + 1] = insertLengthOffsets[insertCode];\n cmdLookup[index + 2] = copyLengthOffsets[copyCode];\n cmdLookup[index + 3] = distanceContext;\n }\n }\n /**\n * @param {!State} s\n * @return {number}\n */\n function decodeWindowBits(s) {\n let /** @type{number} */ largeWindowEnabled = s.isLargeWindow;\n s.isLargeWindow = 0;\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n if (readFewBits(s, 1) == 0) {\n return 16;\n }\n let /** @type{number} */ n = readFewBits(s, 3);\n if (n != 0) {\n return 17 + n;\n }\n n = readFewBits(s, 3);\n if (n != 0) {\n if (n == 1) {\n if (largeWindowEnabled == 0) {\n return -1;\n }\n s.isLargeWindow = 1;\n if (readFewBits(s, 1) == 1) {\n return -1;\n }\n n = readFewBits(s, 6);\n if (n < 10 || n > 30) {\n return -1;\n }\n return n;\n } else {\n return 8 + n;\n }\n }\n return 17;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function enableEagerOutput(s) {\n if (s.runningState != 1) {\n throw 'State MUST be freshly initialized';\n }\n s.isEager = 1;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function enableLargeWindow(s) {\n if (s.runningState != 1) {\n throw 'State MUST be freshly initialized';\n }\n s.isLargeWindow = 1;\n }\n /**\n * @param {!State} s\n * @param {!Int8Array} data\n * @return {void}\n */\n function attachDictionaryChunk(s, data) {\n if (s.runningState != 1) {\n throw 'State MUST be freshly initialized';\n }\n if (s.cdNumChunks == 0) {\n s.cdChunks = new Array(16);\n s.cdChunkOffsets = new Int32Array(16);\n s.cdBlockBits = -1;\n }\n if (s.cdNumChunks == 15) {\n throw 'Too many dictionary chunks';\n }\n s.cdChunks[s.cdNumChunks] = data;\n s.cdNumChunks++;\n s.cdTotalSize += data.length;\n s.cdChunkOffsets[s.cdNumChunks] = s.cdTotalSize;\n }\n /**\n * @param {!State} s\n * @param {!InputStream} input\n * @return {void}\n */\n function initState(s, input) {\n if (s.runningState != 0) {\n throw 'State MUST be uninitialized';\n }\n s.blockTrees = new Int32Array(3091);\n s.blockTrees[0] = 7;\n s.distRbIdx = 3;\n let /** @type{number} */ maxDistanceAlphabetLimit = calculateDistanceAlphabetLimit(\n 0x7ffffffc,\n 3,\n 15 << 3\n );\n s.distExtraBits = new Int8Array(maxDistanceAlphabetLimit);\n s.distOffset = new Int32Array(maxDistanceAlphabetLimit);\n s.input = input;\n initBitReader(s);\n s.runningState = 1;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function close(s) {\n if (s.runningState == 0) {\n throw 'State MUST be initialized';\n }\n if (s.runningState == 11) {\n return;\n }\n s.runningState = 11;\n if (s.input != null) {\n closeInput(s.input);\n s.input = null;\n }\n }\n /**\n * @param {!State} s\n * @return {number}\n */\n function decodeVarLenUnsignedByte(s) {\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n if (readFewBits(s, 1) != 0) {\n let /** @type{number} */ n = readFewBits(s, 3);\n if (n == 0) {\n return 1;\n } else {\n return readFewBits(s, n) + (1 << n);\n }\n }\n return 0;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function decodeMetaBlockLength(s) {\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n s.inputEnd = readFewBits(s, 1);\n s.metaBlockLength = 0;\n s.isUncompressed = 0;\n s.isMetadata = 0;\n if (s.inputEnd != 0 && readFewBits(s, 1) != 0) {\n return;\n }\n let /** @type{number} */ sizeNibbles = readFewBits(s, 2) + 4;\n if (sizeNibbles == 7) {\n s.isMetadata = 1;\n if (readFewBits(s, 1) != 0) {\n throw 'Corrupted reserved bit';\n }\n let /** @type{number} */ sizeBytes = readFewBits(s, 2);\n if (sizeBytes == 0) {\n return;\n }\n for (let /** @type{number} */ i = 0; i < sizeBytes; i++) {\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ bits = readFewBits(s, 8);\n if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {\n throw 'Exuberant nibble';\n }\n s.metaBlockLength |= bits << (i * 8);\n }\n } else {\n for (let /** @type{number} */ i = 0; i < sizeNibbles; i++) {\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ bits = readFewBits(s, 4);\n if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {\n throw 'Exuberant nibble';\n }\n s.metaBlockLength |= bits << (i * 4);\n }\n }\n s.metaBlockLength++;\n if (s.inputEnd == 0) {\n s.isUncompressed = readFewBits(s, 1);\n }\n }\n /**\n * @param {!Int32Array} tableGroup\n * @param {number} tableIdx\n * @param {!State} s\n * @return {number}\n */\n function readSymbol(tableGroup, tableIdx, s) {\n let /** @type{number} */ offset = tableGroup[tableIdx];\n let /** @type{number} */ val = s.accumulator32 >>> s.bitOffset;\n offset += val & 0xff;\n let /** @type{number} */ bits = tableGroup[offset] >> 16;\n let /** @type{number} */ sym = tableGroup[offset] & 0xffff;\n if (bits <= 8) {\n s.bitOffset += bits;\n return sym;\n }\n offset += sym;\n let /** @type{number} */ mask = (1 << bits) - 1;\n offset += (val & mask) >>> 8;\n s.bitOffset += (tableGroup[offset] >> 16) + 8;\n return tableGroup[offset] & 0xffff;\n }\n /**\n * @param {!Int32Array} tableGroup\n * @param {number} tableIdx\n * @param {!State} s\n * @return {number}\n */\n function readBlockLength(tableGroup, tableIdx, s) {\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ code = readSymbol(tableGroup, tableIdx, s);\n let /** @type{number} */ n = BLOCK_LENGTH_N_BITS[code];\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n return BLOCK_LENGTH_OFFSET[code] + (n <= 16 ? readFewBits(s, n) : readManyBits(s, n));\n }\n /**\n * @param {!Int32Array} v\n * @param {number} index\n * @return {void}\n */\n function moveToFront(v, index) {\n let /** @type{number} */ value = v[index];\n for (; index > 0; index--) {\n v[index] = v[index - 1];\n }\n v[0] = value;\n }\n /**\n * @param {!Int8Array} v\n * @param {number} vLen\n * @return {void}\n */\n function inverseMoveToFrontTransform(v, vLen) {\n let /** @type{!Int32Array} */ mtf = new Int32Array(256);\n for (let /** @type{number} */ i = 0; i < 256; i++) {\n mtf[i] = i;\n }\n for (let /** @type{number} */ i = 0; i < vLen; i++) {\n let /** @type{number} */ index = v[i] & 0xff;\n v[i] = mtf[index];\n if (index != 0) {\n moveToFront(mtf, index);\n }\n }\n }\n /**\n * @param {!Int32Array} codeLengthCodeLengths\n * @param {number} numSymbols\n * @param {!Int32Array} codeLengths\n * @param {!State} s\n * @return {void}\n */\n function readHuffmanCodeLengths(codeLengthCodeLengths, numSymbols, codeLengths, s) {\n let /** @type{number} */ symbol = 0;\n let /** @type{number} */ prevCodeLen = 8;\n let /** @type{number} */ repeat = 0;\n let /** @type{number} */ repeatCodeLen = 0;\n let /** @type{number} */ space = 32768;\n let /** @type{!Int32Array} */ table = new Int32Array(32 + 1);\n let /** @type{number} */ tableIdx = table.length - 1;\n buildHuffmanTable(table, tableIdx, 5, codeLengthCodeLengths, 18);\n while (symbol < numSymbols && space > 0) {\n if (s.halfOffset > 2030) {\n doReadMoreInput(s);\n }\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ p = (s.accumulator32 >>> s.bitOffset) & 31;\n s.bitOffset += table[p] >> 16;\n let /** @type{number} */ codeLen = table[p] & 0xffff;\n if (codeLen < 16) {\n repeat = 0;\n codeLengths[symbol++] = codeLen;\n if (codeLen != 0) {\n prevCodeLen = codeLen;\n space -= 32768 >> codeLen;\n }\n } else {\n let /** @type{number} */ extraBits = codeLen - 14;\n let /** @type{number} */ newLen = 0;\n if (codeLen == 16) {\n newLen = prevCodeLen;\n }\n if (repeatCodeLen != newLen) {\n repeat = 0;\n repeatCodeLen = newLen;\n }\n let /** @type{number} */ oldRepeat = repeat;\n if (repeat > 0) {\n repeat -= 2;\n repeat <<= extraBits;\n }\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n repeat += readFewBits(s, extraBits) + 3;\n let /** @type{number} */ repeatDelta = repeat - oldRepeat;\n if (symbol + repeatDelta > numSymbols) {\n throw 'symbol + repeatDelta > numSymbols';\n }\n for (let /** @type{number} */ i = 0; i < repeatDelta; i++) {\n codeLengths[symbol++] = repeatCodeLen;\n }\n if (repeatCodeLen != 0) {\n space -= repeatDelta << (15 - repeatCodeLen);\n }\n }\n }\n if (space != 0) {\n throw 'Unused space';\n }\n codeLengths.fill(0, symbol, numSymbols);\n }\n /**\n * @param {!Int32Array} symbols\n * @param {number} length\n * @return {void}\n */\n function checkDupes(symbols, length) {\n for (let /** @type{number} */ i = 0; i < length - 1; ++i) {\n for (let /** @type{number} */ j = i + 1; j < length; ++j) {\n if (symbols[i] == symbols[j]) {\n throw 'Duplicate simple Huffman code symbol';\n }\n }\n }\n }\n /**\n * @param {number} alphabetSizeMax\n * @param {number} alphabetSizeLimit\n * @param {!Int32Array} tableGroup\n * @param {number} tableIdx\n * @param {!State} s\n * @return {number}\n */\n function readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s) {\n let /** @type{!Int32Array} */ codeLengths = new Int32Array(alphabetSizeLimit);\n let /** @type{!Int32Array} */ symbols = new Int32Array(4);\n let /** @type{number} */ maxBits = 1 + log2floor(alphabetSizeMax - 1);\n let /** @type{number} */ numSymbols = readFewBits(s, 2) + 1;\n for (let /** @type{number} */ i = 0; i < numSymbols; i++) {\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ symbol = readFewBits(s, maxBits);\n if (symbol >= alphabetSizeLimit) {\n throw \"Can't readHuffmanCode\";\n }\n symbols[i] = symbol;\n }\n checkDupes(symbols, numSymbols);\n let /** @type{number} */ histogramId = numSymbols;\n if (numSymbols == 4) {\n histogramId += readFewBits(s, 1);\n }\n switch (histogramId) {\n case 1:\n codeLengths[symbols[0]] = 1;\n break;\n case 2:\n codeLengths[symbols[0]] = 1;\n codeLengths[symbols[1]] = 1;\n break;\n case 3:\n codeLengths[symbols[0]] = 1;\n codeLengths[symbols[1]] = 2;\n codeLengths[symbols[2]] = 2;\n break;\n case 4:\n codeLengths[symbols[0]] = 2;\n codeLengths[symbols[1]] = 2;\n codeLengths[symbols[2]] = 2;\n codeLengths[symbols[3]] = 2;\n break;\n case 5:\n codeLengths[symbols[0]] = 1;\n codeLengths[symbols[1]] = 2;\n codeLengths[symbols[2]] = 3;\n codeLengths[symbols[3]] = 3;\n break;\n default:\n break;\n }\n return buildHuffmanTable(tableGroup, tableIdx, 8, codeLengths, alphabetSizeLimit);\n }\n /**\n * @param {number} alphabetSizeLimit\n * @param {number} skip\n * @param {!Int32Array} tableGroup\n * @param {number} tableIdx\n * @param {!State} s\n * @return {number}\n */\n function readComplexHuffmanCode(alphabetSizeLimit, skip, tableGroup, tableIdx, s) {\n let /** @type{!Int32Array} */ codeLengths = new Int32Array(alphabetSizeLimit);\n let /** @type{!Int32Array} */ codeLengthCodeLengths = new Int32Array(18);\n let /** @type{number} */ space = 32;\n let /** @type{number} */ numCodes = 0;\n for (let /** @type{number} */ i = skip; i < 18 && space > 0; i++) {\n let /** @type{number} */ codeLenIdx = CODE_LENGTH_CODE_ORDER[i];\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ p = (s.accumulator32 >>> s.bitOffset) & 15;\n s.bitOffset += FIXED_TABLE[p] >> 16;\n let /** @type{number} */ v = FIXED_TABLE[p] & 0xffff;\n codeLengthCodeLengths[codeLenIdx] = v;\n if (v != 0) {\n space -= 32 >> v;\n numCodes++;\n }\n }\n if (space != 0 && numCodes != 1) {\n throw 'Corrupted Huffman code histogram';\n }\n readHuffmanCodeLengths(codeLengthCodeLengths, alphabetSizeLimit, codeLengths, s);\n return buildHuffmanTable(tableGroup, tableIdx, 8, codeLengths, alphabetSizeLimit);\n }\n /**\n * @param {number} alphabetSizeMax\n * @param {number} alphabetSizeLimit\n * @param {!Int32Array} tableGroup\n * @param {number} tableIdx\n * @param {!State} s\n * @return {number}\n */\n function readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s) {\n if (s.halfOffset > 2030) {\n doReadMoreInput(s);\n }\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ simpleCodeOrSkip = readFewBits(s, 2);\n if (simpleCodeOrSkip == 1) {\n return readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s);\n } else {\n return readComplexHuffmanCode(alphabetSizeLimit, simpleCodeOrSkip, tableGroup, tableIdx, s);\n }\n }\n /**\n * @param {number} contextMapSize\n * @param {!Int8Array} contextMap\n * @param {!State} s\n * @return {number}\n */\n function decodeContextMap(contextMapSize, contextMap, s) {\n if (s.halfOffset > 2030) {\n doReadMoreInput(s);\n }\n let /** @type{number} */ numTrees = decodeVarLenUnsignedByte(s) + 1;\n if (numTrees == 1) {\n contextMap.fill(0, 0, contextMapSize);\n return numTrees;\n }\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ useRleForZeros = readFewBits(s, 1);\n let /** @type{number} */ maxRunLengthPrefix = 0;\n if (useRleForZeros != 0) {\n maxRunLengthPrefix = readFewBits(s, 4) + 1;\n }\n let /** @type{number} */ alphabetSize = numTrees + maxRunLengthPrefix;\n let /** @type{number} */ tableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSize + 31) >> 5];\n let /** @type{!Int32Array} */ table = new Int32Array(tableSize + 1);\n let /** @type{number} */ tableIdx = table.length - 1;\n readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s);\n for (let /** @type{number} */ i = 0; i < contextMapSize; ) {\n if (s.halfOffset > 2030) {\n doReadMoreInput(s);\n }\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ code = readSymbol(table, tableIdx, s);\n if (code == 0) {\n contextMap[i] = 0;\n i++;\n } else if (code <= maxRunLengthPrefix) {\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ reps = (1 << code) + readFewBits(s, code);\n while (reps != 0) {\n if (i >= contextMapSize) {\n throw 'Corrupted context map';\n }\n contextMap[i] = 0;\n i++;\n reps--;\n }\n } else {\n contextMap[i] = code - maxRunLengthPrefix;\n i++;\n }\n }\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n if (readFewBits(s, 1) == 1) {\n inverseMoveToFrontTransform(contextMap, contextMapSize);\n }\n return numTrees;\n }\n /**\n * @param {!State} s\n * @param {number} treeType\n * @param {number} numBlockTypes\n * @return {number}\n */\n function decodeBlockTypeAndLength(s, treeType, numBlockTypes) {\n let /** @type{!Int32Array} */ ringBuffers = s.rings;\n let /** @type{number} */ offset = 4 + treeType * 2;\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n let /** @type{number} */ blockType = readSymbol(s.blockTrees, 2 * treeType, s);\n let /** @type{number} */ result = readBlockLength(s.blockTrees, 2 * treeType + 1, s);\n if (blockType == 1) {\n blockType = ringBuffers[offset + 1] + 1;\n } else if (blockType == 0) {\n blockType = ringBuffers[offset];\n } else {\n blockType -= 2;\n }\n if (blockType >= numBlockTypes) {\n blockType -= numBlockTypes;\n }\n ringBuffers[offset] = ringBuffers[offset + 1];\n ringBuffers[offset + 1] = blockType;\n return result;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function decodeLiteralBlockSwitch(s) {\n s.literalBlockLength = decodeBlockTypeAndLength(s, 0, s.numLiteralBlockTypes);\n let /** @type{number} */ literalBlockType = s.rings[5];\n s.contextMapSlice = literalBlockType << 6;\n s.literalTreeIdx = s.contextMap[s.contextMapSlice] & 0xff;\n let /** @type{number} */ contextMode = s.contextModes[literalBlockType];\n s.contextLookupOffset1 = contextMode << 9;\n s.contextLookupOffset2 = s.contextLookupOffset1 + 256;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function decodeCommandBlockSwitch(s) {\n s.commandBlockLength = decodeBlockTypeAndLength(s, 1, s.numCommandBlockTypes);\n s.commandTreeIdx = s.rings[7];\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function decodeDistanceBlockSwitch(s) {\n s.distanceBlockLength = decodeBlockTypeAndLength(s, 2, s.numDistanceBlockTypes);\n s.distContextMapSlice = s.rings[9] << 2;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function maybeReallocateRingBuffer(s) {\n let /** @type{number} */ newSize = s.maxRingBufferSize;\n if (newSize > s.expectedTotalSize) {\n let /** @type{number} */ minimalNewSize = s.expectedTotalSize;\n while (newSize >> 1 > minimalNewSize) {\n newSize >>= 1;\n }\n if (s.inputEnd == 0 && newSize < 16384 && s.maxRingBufferSize >= 16384) {\n newSize = 16384;\n }\n }\n if (newSize <= s.ringBufferSize) {\n return;\n }\n let /** @type{number} */ ringBufferSizeWithSlack = newSize + 37;\n let /** @type{!Int8Array} */ newBuffer = new Int8Array(ringBufferSizeWithSlack);\n if (s.ringBuffer.length != 0) {\n newBuffer.set(s.ringBuffer.subarray(0, 0 + s.ringBufferSize), 0);\n }\n s.ringBuffer = newBuffer;\n s.ringBufferSize = newSize;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function readNextMetablockHeader(s) {\n if (s.inputEnd != 0) {\n s.nextRunningState = 10;\n s.runningState = 12;\n return;\n }\n s.literalTreeGroup = new Int32Array(0);\n s.commandTreeGroup = new Int32Array(0);\n s.distanceTreeGroup = new Int32Array(0);\n if (s.halfOffset > 2030) {\n doReadMoreInput(s);\n }\n decodeMetaBlockLength(s);\n if (s.metaBlockLength == 0 && s.isMetadata == 0) {\n return;\n }\n if (s.isUncompressed != 0 || s.isMetadata != 0) {\n jumpToByteBoundary(s);\n s.runningState = s.isMetadata != 0 ? 5 : 6;\n } else {\n s.runningState = 3;\n }\n if (s.isMetadata != 0) {\n return;\n }\n s.expectedTotalSize += s.metaBlockLength;\n if (s.expectedTotalSize > 1 << 30) {\n s.expectedTotalSize = 1 << 30;\n }\n if (s.ringBufferSize < s.maxRingBufferSize) {\n maybeReallocateRingBuffer(s);\n }\n }\n /**\n * @param {!State} s\n * @param {number} treeType\n * @param {number} numBlockTypes\n * @return {number}\n */\n function readMetablockPartition(s, treeType, numBlockTypes) {\n let /** @type{number} */ offset = s.blockTrees[2 * treeType];\n if (numBlockTypes <= 1) {\n s.blockTrees[2 * treeType + 1] = offset;\n s.blockTrees[2 * treeType + 2] = offset;\n return 1 << 28;\n }\n let /** @type{number} */ blockTypeAlphabetSize = numBlockTypes + 2;\n offset += readHuffmanCode(\n blockTypeAlphabetSize,\n blockTypeAlphabetSize,\n s.blockTrees,\n 2 * treeType,\n s\n );\n s.blockTrees[2 * treeType + 1] = offset;\n let /** @type{number} */ blockLengthAlphabetSize = 26;\n offset += readHuffmanCode(\n blockLengthAlphabetSize,\n blockLengthAlphabetSize,\n s.blockTrees,\n 2 * treeType + 1,\n s\n );\n s.blockTrees[2 * treeType + 2] = offset;\n return readBlockLength(s.blockTrees, 2 * treeType + 1, s);\n }\n /**\n * @param {!State} s\n * @param {number} alphabetSizeLimit\n * @return {void}\n */\n function calculateDistanceLut(s, alphabetSizeLimit) {\n let /** @type{!Int8Array} */ distExtraBits = s.distExtraBits;\n let /** @type{!Int32Array} */ distOffset = s.distOffset;\n let /** @type{number} */ npostfix = s.distancePostfixBits;\n let /** @type{number} */ ndirect = s.numDirectDistanceCodes;\n let /** @type{number} */ postfix = 1 << npostfix;\n let /** @type{number} */ bits = 1;\n let /** @type{number} */ half = 0;\n let /** @type{number} */ i = 16;\n for (let /** @type{number} */ j = 0; j < ndirect; ++j) {\n distExtraBits[i] = 0;\n distOffset[i] = j + 1;\n ++i;\n }\n while (i < alphabetSizeLimit) {\n let /** @type{number} */ base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;\n for (let /** @type{number} */ j = 0; j < postfix; ++j) {\n distExtraBits[i] = bits;\n distOffset[i] = base + j;\n ++i;\n }\n bits = bits + half;\n half = half ^ 1;\n }\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function readMetablockHuffmanCodesAndContextMaps(s) {\n s.numLiteralBlockTypes = decodeVarLenUnsignedByte(s) + 1;\n s.literalBlockLength = readMetablockPartition(s, 0, s.numLiteralBlockTypes);\n s.numCommandBlockTypes = decodeVarLenUnsignedByte(s) + 1;\n s.commandBlockLength = readMetablockPartition(s, 1, s.numCommandBlockTypes);\n s.numDistanceBlockTypes = decodeVarLenUnsignedByte(s) + 1;\n s.distanceBlockLength = readMetablockPartition(s, 2, s.numDistanceBlockTypes);\n if (s.halfOffset > 2030) {\n doReadMoreInput(s);\n }\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n s.distancePostfixBits = readFewBits(s, 2);\n s.numDirectDistanceCodes = readFewBits(s, 4) << s.distancePostfixBits;\n s.contextModes = new Int8Array(s.numLiteralBlockTypes);\n for (let /** @type{number} */ i = 0; i < s.numLiteralBlockTypes; ) {\n let /** @type{number} */ limit = min(i + 96, s.numLiteralBlockTypes);\n for (; i < limit; ++i) {\n if (s.bitOffset >= 16) {\n s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);\n s.bitOffset -= 16;\n }\n s.contextModes[i] = readFewBits(s, 2);\n }\n if (s.halfOffset > 2030) {\n doReadMoreInput(s);\n }\n }\n s.contextMap = new Int8Array(s.numLiteralBlockTypes << 6);\n let /** @type{number} */ numLiteralTrees = decodeContextMap(\n s.numLiteralBlockTypes << 6,\n s.contextMap,\n s\n );\n s.trivialLiteralContext = 1;\n for (let /** @type{number} */ j = 0; j < s.numLiteralBlockTypes << 6; j++) {\n if (s.contextMap[j] != j >> 6) {\n s.trivialLiteralContext = 0;\n break;\n }\n }\n s.distContextMap = new Int8Array(s.numDistanceBlockTypes << 2);\n let /** @type{number} */ numDistTrees = decodeContextMap(\n s.numDistanceBlockTypes << 2,\n s.distContextMap,\n s\n );\n s.literalTreeGroup = decodeHuffmanTreeGroup(256, 256, numLiteralTrees, s);\n s.commandTreeGroup = decodeHuffmanTreeGroup(704, 704, s.numCommandBlockTypes, s);\n let /** @type{number} */ distanceAlphabetSizeMax = calculateDistanceAlphabetSize(\n s.distancePostfixBits,\n s.numDirectDistanceCodes,\n 24\n );\n let /** @type{number} */ distanceAlphabetSizeLimit = distanceAlphabetSizeMax;\n if (s.isLargeWindow == 1) {\n distanceAlphabetSizeMax = calculateDistanceAlphabetSize(\n s.distancePostfixBits,\n s.numDirectDistanceCodes,\n 62\n );\n distanceAlphabetSizeLimit = calculateDistanceAlphabetLimit(\n 0x7ffffffc,\n s.distancePostfixBits,\n s.numDirectDistanceCodes\n );\n }\n s.distanceTreeGroup = decodeHuffmanTreeGroup(\n distanceAlphabetSizeMax,\n distanceAlphabetSizeLimit,\n numDistTrees,\n s\n );\n calculateDistanceLut(s, distanceAlphabetSizeLimit);\n s.contextMapSlice = 0;\n s.distContextMapSlice = 0;\n s.contextLookupOffset1 = s.contextModes[0] * 512;\n s.contextLookupOffset2 = s.contextLookupOffset1 + 256;\n s.literalTreeIdx = 0;\n s.commandTreeIdx = 0;\n s.rings[4] = 1;\n s.rings[5] = 0;\n s.rings[6] = 1;\n s.rings[7] = 0;\n s.rings[8] = 1;\n s.rings[9] = 0;\n }\n /**\n * @param {!State} s\n * @return {void}\n */\n function copyUncompressedData(s) {\n let /** @type{!Int8Array} */ ringBuffer = s.ringBuffer;\n if (s.metaBlockLength <= 0) {\n reload(s);\n s.runningState = 2;\n return;\n }\n let /** @type{number} */ chunkLength = min(s.ringBufferSize - s.pos, s.metaBlockLength);\n copyRawBytes(s, ringBuffer, s.pos, chunkLength);\n s.metaBlockLength -= chunkLength;\n s.pos += chunkLength;\n if (s.pos == s.ringBufferSize) {\n s.nextRunningState = 6;\n s.runningState = 12;\n return;\n }\n reload(s);\n s.runningState = 2;\n }\n /**\n * @param {!State} s\n * @return {number}\n */\n function writeRingBuffer(s) {\n let /** @type{number} */ toWrite = min(\n s.outputLength - s.outputUsed,\n s.ringBufferBytesReady - s.ringBufferBytesWritten\n );\n if (toWrite != 0) {\n s.output.set(\n s.ringBuffer.subarray(s.ringBufferBytesWritten, s.ringBufferBytesWritten + toWrite),\n s.outputOffset + s.outputUsed\n );\n s.outputUsed += toWrite;\n s.ringBufferBytesWritten += toWrite;\n }\n if (s.outputUsed < s.outputLength) {\n return 1;\n } else {\n return 0;\n }\n }\n /**\n * @param {number} alphabetSizeMax\n * @param {number} alphabetSizeLimit\n * @param {number} n\n * @param {!State} s\n * @return {!Int32Array}\n */\n function decodeHuffmanTreeGroup(alphabetSizeMax, alphabetSizeLimit, n, s) {\n let /** @type{number} */ maxTableSize = MAX_HUFFMAN_TABLE_SIZE[(alphabetSizeLimit + 31) >> 5];\n let /** @type{!Int32Array} */ group = new Int32Array(n + n * maxTableSize);\n let /** @type{number} */ next = n;\n for (let /** @type{number} */ i = 0; i < n; ++i) {\n group[i] = next;\n next += readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, group, i, s);\n }\n return group;\n }\n /**\n * @param {!State} s\n * @return {number}\n */\n function calculateFence(s) {\n let /** @type{number} */ result = s.ringBufferSize;\n if (s.isEager != 0) {\n result = min(result, s.ringBufferBytesWritten + s.outputLength - s.outputUsed);\n }\n return result;\n }\n /**\n * @param {!State} s\n * @param {number} fence\n * @return {void}\n */\n function doUseDictionary(s, fence) {\n if (s.distance > 0x7ffffffc) {\n throw 'Invalid backward reference';\n }\n let /** @type{number} */ address = s.distance - s.maxDistance - 1 - s.cdTotalSize;\n if