2017-08-28 17:31:29 +08:00
/ * C o p y r i g h t 2 0 1 7 G o o g l e I n c . A l l R i g h t s R e s e r v e d .
Distributed under MIT license .
See file LICENSE for detail or copy at https : //opensource.org/licenses/MIT
* /
2021-06-23 15:40:57 +08:00
/ * *
* @ typedef { Object } Options
* @ property { ? Int8Array } customDictionary
* /
let Options ;
/ * *
* Private scope / static initializer for decoder .
*
2023-04-11 15:17:20 +08:00
* @ return { function ( ! Int8Array , ? Options = ) : ! Int8Array }
2021-06-23 15:40:57 +08:00
* /
let makeBrotliDecode = ( ) => {
2017-08-28 17:31:29 +08:00
/ * *
* @ constructor
* @ param { ! Int8Array } bytes
* @ struct
* /
function InputStream ( bytes ) {
/** @type {!Int8Array} */
this . data = bytes ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . offset = 0 ;
}
2021-01-18 17:56:39 +08:00
/* GENERATED CODE BEGIN */
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
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 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
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 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
let DISTANCE _SHORT _CODE _INDEX _OFFSET = Int32Array . from ( [ 0 , 3 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 3 , 3 , 3 , 3 , 3 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
let DISTANCE _SHORT _CODE _VALUE _OFFSET = Int32Array . from ( [ 0 , 0 , 0 , 0 , - 1 , 1 , - 2 , 2 , - 3 , 3 , - 1 , 1 , - 2 , 2 , - 3 , 3 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
let FIXED _TABLE = Int32Array . from ( [ 0x020000 , 0x020004 , 0x020003 , 0x030002 , 0x020000 , 0x020004 , 0x020003 , 0x040001 , 0x020000 , 0x020004 , 0x020003 , 0x030002 , 0x020000 , 0x020004 , 0x020003 , 0x040005 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
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 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
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 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int16Array} */
2021-06-23 15:40:57 +08:00
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 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int16Array} */
2021-06-23 15:40:57 +08:00
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 ] ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int16Array} */
2021-06-23 15:40:57 +08:00
let CMD _LOOKUP = new Int16Array ( 2816 ) ;
2019-04-12 19:57:42 +08:00
{
unpackCommandLookupTable ( CMD _LOOKUP ) ;
}
/ * *
* @ param { number } i
* @ return { number }
* /
function log2floor ( i ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ result = - 1 ;
let /** @type {number} */ step = 16 ;
2019-04-12 19:57:42 +08:00
while ( step > 0 ) {
2023-04-11 15:17:20 +08:00
if ( ( i >>> step ) !== 0 ) {
2019-04-12 19:57:42 +08:00
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" ;
}
2023-04-11 15:17:20 +08:00
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 ) ;
2019-04-12 19:57:42 +08:00
return ( ( group - 1 ) << npostfix ) + ( 1 << npostfix ) + ndirect + 16 ;
}
/ * *
* @ param { ! Int16Array } cmdLookup
* @ return { void }
* /
function unpackCommandLookupTable ( cmdLookup ) {
2023-04-11 15:17:20 +08:00
let /** @type {!Int16Array} */ insertLengthOffsets = new Int16Array ( 24 ) ;
let /** @type {!Int16Array} */ copyLengthOffsets = new Int16Array ( 24 ) ;
2019-04-12 19:57:42 +08:00
copyLengthOffsets [ 0 ] = 2 ;
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < 23 ; ++ i ) {
2019-04-12 19:57:42 +08:00
insertLengthOffsets [ i + 1 ] = ( insertLengthOffsets [ i ] + ( 1 << INSERT _LENGTH _N _BITS [ i ] ) ) ;
copyLengthOffsets [ i + 1 ] = ( copyLengthOffsets [ i ] + ( 1 << COPY _LENGTH _N _BITS [ i ] ) ) ;
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ cmdCode = 0 ; cmdCode < 704 ; ++ cmdCode ) {
let /** @type {number} */ rangeIdx = cmdCode >>> 6 ;
let /** @type {number} */ distanceContextOffset = - 4 ;
2019-04-12 19:57:42 +08:00
if ( rangeIdx >= 2 ) {
rangeIdx -= 2 ;
distanceContextOffset = 0 ;
}
2023-04-11 15:17:20 +08:00
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 ;
2019-04-12 19:57:42 +08:00
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 ;
}
}
2017-08-28 17:31:29 +08:00
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function decodeWindowBits ( s ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ largeWindowEnabled = s . isLargeWindow ;
2019-04-12 19:57:42 +08:00
s . isLargeWindow = 0 ;
2017-08-28 17:31:29 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
if ( readFewBits ( s , 1 ) === 0 ) {
2017-08-28 17:31:29 +08:00
return 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ n = readFewBits ( s , 3 ) ;
if ( n !== 0 ) {
2017-08-28 17:31:29 +08:00
return 17 + n ;
}
n = readFewBits ( s , 3 ) ;
2023-04-11 15:17:20 +08:00
if ( n !== 0 ) {
if ( n === 1 ) {
if ( largeWindowEnabled === 0 ) {
2019-04-12 19:57:42 +08:00
return - 1 ;
}
s . isLargeWindow = 1 ;
2023-04-11 15:17:20 +08:00
if ( readFewBits ( s , 1 ) === 1 ) {
2019-04-12 19:57:42 +08:00
return - 1 ;
}
n = readFewBits ( s , 6 ) ;
if ( n < 10 || n > 30 ) {
return - 1 ;
}
return n ;
} else {
return 8 + n ;
}
2017-08-28 17:31:29 +08:00
}
return 17 ;
}
2019-04-12 19:57:42 +08:00
/ * *
* @ param { ! State } s
* @ return { void }
* /
function enableEagerOutput ( s ) {
2023-04-11 15:17:20 +08:00
if ( s . runningState !== 1 ) {
2019-04-12 19:57:42 +08:00
throw "State MUST be freshly initialized" ;
}
s . isEager = 1 ;
}
/ * *
* @ param { ! State } s
* @ return { void }
* /
function enableLargeWindow ( s ) {
2023-04-11 15:17:20 +08:00
if ( s . runningState !== 1 ) {
2019-04-12 19:57:42 +08:00
throw "State MUST be freshly initialized" ;
}
s . isLargeWindow = 1 ;
}
2021-01-18 17:56:39 +08:00
/ * *
* @ param { ! State } s
* @ param { ! Int8Array } data
* @ return { void }
* /
function attachDictionaryChunk ( s , data ) {
2023-04-11 15:17:20 +08:00
if ( s . runningState !== 1 ) {
2021-01-18 17:56:39 +08:00
throw "State MUST be freshly initialized" ;
}
2023-04-11 15:17:20 +08:00
if ( s . cdNumChunks === 0 ) {
2021-01-18 17:56:39 +08:00
s . cdChunks = new Array ( 16 ) ;
s . cdChunkOffsets = new Int32Array ( 16 ) ;
s . cdBlockBits = - 1 ;
}
2023-04-11 15:17:20 +08:00
if ( s . cdNumChunks === 15 ) {
2021-01-18 17:56:39 +08:00
throw "Too many dictionary chunks" ;
}
s . cdChunks [ s . cdNumChunks ] = data ;
s . cdNumChunks ++ ;
s . cdTotalSize += data . length ;
s . cdChunkOffsets [ s . cdNumChunks ] = s . cdTotalSize ;
}
2017-08-28 17:31:29 +08:00
/ * *
* @ param { ! State } s
* @ param { ! InputStream } input
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function initState ( s , input ) {
2023-04-11 15:17:20 +08:00
if ( s . runningState !== 0 ) {
2017-08-28 17:31:29 +08:00
throw "State MUST be uninitialized" ;
}
2019-04-12 19:57:42 +08:00
s . blockTrees = new Int32Array ( 3091 ) ;
s . blockTrees [ 0 ] = 7 ;
s . distRbIdx = 3 ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ maxDistanceAlphabetLimit = calculateDistanceAlphabetLimit ( 0x7FFFFFFC , 3 , 15 << 3 ) ;
2019-04-12 19:57:42 +08:00
s . distExtraBits = new Int8Array ( maxDistanceAlphabetLimit ) ;
s . distOffset = new Int32Array ( maxDistanceAlphabetLimit ) ;
2017-08-28 17:31:29 +08:00
s . input = input ;
initBitReader ( s ) ;
s . runningState = 1 ;
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function close ( s ) {
2023-04-11 15:17:20 +08:00
if ( s . runningState === 0 ) {
2017-08-28 17:31:29 +08:00
throw "State MUST be initialized" ;
}
2023-04-11 15:17:20 +08:00
if ( s . runningState === 11 ) {
2017-08-28 17:31:29 +08:00
return ;
}
2019-04-12 19:57:42 +08:00
s . runningState = 11 ;
2023-04-11 15:17:20 +08:00
if ( s . input !== null ) {
2017-08-28 17:31:29 +08:00
closeInput ( s . input ) ;
s . input = null ;
}
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function decodeVarLenUnsignedByte ( s ) {
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
if ( readFewBits ( s , 1 ) !== 0 ) {
let /** @type {number} */ n = readFewBits ( s , 3 ) ;
if ( n === 0 ) {
2017-08-28 17:31:29 +08:00
return 1 ;
} else {
return readFewBits ( s , n ) + ( 1 << n ) ;
}
}
return 0 ;
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
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 ;
2023-04-11 15:17:20 +08:00
if ( ( s . inputEnd !== 0 ) && readFewBits ( s , 1 ) !== 0 ) {
2017-08-28 17:31:29 +08:00
return ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ sizeNibbles = readFewBits ( s , 2 ) + 4 ;
if ( sizeNibbles === 7 ) {
2017-08-28 17:31:29 +08:00
s . isMetadata = 1 ;
2023-04-11 15:17:20 +08:00
if ( readFewBits ( s , 1 ) !== 0 ) {
2017-08-28 17:31:29 +08:00
throw "Corrupted reserved bit" ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ sizeBytes = readFewBits ( s , 2 ) ;
if ( sizeBytes === 0 ) {
2017-08-28 17:31:29 +08:00
return ;
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < sizeBytes ; i ++ ) {
2017-08-28 17:31:29 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ bits = readFewBits ( s , 8 ) ;
if ( bits === 0 && i + 1 === sizeBytes && sizeBytes > 1 ) {
2017-08-28 17:31:29 +08:00
throw "Exuberant nibble" ;
}
s . metaBlockLength |= bits << ( i * 8 ) ;
}
} else {
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < sizeNibbles ; i ++ ) {
2017-08-28 17:31:29 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ bits = readFewBits ( s , 4 ) ;
if ( bits === 0 && i + 1 === sizeNibbles && sizeNibbles > 4 ) {
2017-08-28 17:31:29 +08:00
throw "Exuberant nibble" ;
}
s . metaBlockLength |= bits << ( i * 4 ) ;
}
}
s . metaBlockLength ++ ;
2023-04-11 15:17:20 +08:00
if ( s . inputEnd === 0 ) {
2017-08-28 17:31:29 +08:00
s . isUncompressed = readFewBits ( s , 1 ) ;
}
}
/ * *
2019-04-12 19:57:42 +08:00
* @ param { ! Int32Array } tableGroup
* @ param { number } tableIdx
2017-08-28 17:31:29 +08:00
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
2019-04-12 19:57:42 +08:00
function readSymbol ( tableGroup , tableIdx , s ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ offset = tableGroup [ tableIdx ] ;
let /** @type {number} */ val = ( s . accumulator32 >>> s . bitOffset ) ;
2017-08-28 17:31:29 +08:00
offset += val & 0xFF ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ bits = tableGroup [ offset ] >> 16 ;
let /** @type {number} */ sym = tableGroup [ offset ] & 0xFFFF ;
2017-08-28 17:31:29 +08:00
if ( bits <= 8 ) {
s . bitOffset += bits ;
return sym ;
}
offset += sym ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ mask = ( 1 << bits ) - 1 ;
2017-08-28 17:31:29 +08:00
offset += ( val & mask ) >>> 8 ;
2019-04-12 19:57:42 +08:00
s . bitOffset += ( ( tableGroup [ offset ] >> 16 ) + 8 ) ;
return tableGroup [ offset ] & 0xFFFF ;
2017-08-28 17:31:29 +08:00
}
/ * *
2019-04-12 19:57:42 +08:00
* @ param { ! Int32Array } tableGroup
* @ param { number } tableIdx
2017-08-28 17:31:29 +08:00
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
2019-04-12 19:57:42 +08:00
function readBlockLength ( tableGroup , tableIdx , s ) {
2017-08-28 17:31:29 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ code = readSymbol ( tableGroup , tableIdx , s ) ;
let /** @type {number} */ n = BLOCK _LENGTH _N _BITS [ code ] ;
2017-08-28 17:31:29 +08:00
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
2019-04-12 19:57:42 +08:00
* @ param { number } index
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function moveToFront ( v , index ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ value = v [ index ] ;
2017-08-28 17:31:29 +08:00
for ( ; index > 0 ; index -- ) {
v [ index ] = v [ index - 1 ] ;
}
v [ 0 ] = value ;
}
/ * *
* @ param { ! Int8Array } v
2019-04-12 19:57:42 +08:00
* @ param { number } vLen
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function inverseMoveToFrontTransform ( v , vLen ) {
2023-04-11 15:17:20 +08:00
let /** @type {!Int32Array} */ mtf = new Int32Array ( 256 ) ;
for ( let /** @type {number} */ i = 0 ; i < 256 ; i ++ ) {
2017-08-28 17:31:29 +08:00
mtf [ i ] = i ;
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < vLen ; i ++ ) {
let /** @type {number} */ index = v [ i ] & 0xFF ;
2017-08-28 17:31:29 +08:00
v [ i ] = mtf [ index ] ;
2023-04-11 15:17:20 +08:00
if ( index !== 0 ) {
2017-08-28 17:31:29 +08:00
moveToFront ( mtf , index ) ;
}
}
}
/ * *
* @ param { ! Int32Array } codeLengthCodeLengths
2019-04-12 19:57:42 +08:00
* @ param { number } numSymbols
2017-08-28 17:31:29 +08:00
* @ param { ! Int32Array } codeLengths
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function readHuffmanCodeLengths ( codeLengthCodeLengths , numSymbols , codeLengths , s ) {
2023-04-11 15:17:20 +08:00
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 ;
2019-04-12 19:57:42 +08:00
buildHuffmanTable ( table , tableIdx , 5 , codeLengthCodeLengths , 18 ) ;
2017-08-28 17:31:29 +08:00
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 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ p = ( s . accumulator32 >>> s . bitOffset ) & 31 ;
2017-08-28 17:31:29 +08:00
s . bitOffset += table [ p ] >> 16 ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ codeLen = table [ p ] & 0xFFFF ;
2017-08-28 17:31:29 +08:00
if ( codeLen < 16 ) {
repeat = 0 ;
codeLengths [ symbol ++ ] = codeLen ;
2023-04-11 15:17:20 +08:00
if ( codeLen !== 0 ) {
2017-08-28 17:31:29 +08:00
prevCodeLen = codeLen ;
space -= 32768 >> codeLen ;
}
} else {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ extraBits = codeLen - 14 ;
let /** @type {number} */ newLen = 0 ;
if ( codeLen === 16 ) {
2017-08-28 17:31:29 +08:00
newLen = prevCodeLen ;
}
2023-04-11 15:17:20 +08:00
if ( repeatCodeLen !== newLen ) {
2017-08-28 17:31:29 +08:00
repeat = 0 ;
repeatCodeLen = newLen ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ oldRepeat = repeat ;
2017-08-28 17:31:29 +08:00
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 ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ repeatDelta = repeat - oldRepeat ;
2017-08-28 17:31:29 +08:00
if ( symbol + repeatDelta > numSymbols ) {
throw "symbol + repeatDelta > numSymbols" ;
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < repeatDelta ; i ++ ) {
2017-08-28 17:31:29 +08:00
codeLengths [ symbol ++ ] = repeatCodeLen ;
}
2023-04-11 15:17:20 +08:00
if ( repeatCodeLen !== 0 ) {
2017-08-28 17:31:29 +08:00
space -= repeatDelta << ( 15 - repeatCodeLen ) ;
}
}
}
2023-04-11 15:17:20 +08:00
if ( space !== 0 ) {
2017-08-28 17:31:29 +08:00
throw "Unused space" ;
}
codeLengths . fill ( 0 , symbol , numSymbols ) ;
}
/ * *
* @ param { ! Int32Array } symbols
2019-04-12 19:57:42 +08:00
* @ param { number } length
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function checkDupes ( symbols , length ) {
2023-04-11 15:17:20 +08:00
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 ] ) {
2019-04-12 19:57:42 +08:00
throw "Duplicate simple Huffman code symbol" ;
2017-08-28 17:31:29 +08:00
}
}
}
}
/ * *
2019-04-12 19:57:42 +08:00
* @ param { number } alphabetSizeMax
* @ param { number } alphabetSizeLimit
* @ param { ! Int32Array } tableGroup
* @ param { number } tableIdx
2017-08-28 17:31:29 +08:00
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
* /
function readSimpleHuffmanCode ( alphabetSizeMax , alphabetSizeLimit , tableGroup , tableIdx , s ) {
2023-04-11 15:17:20 +08:00
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 ++ ) {
2019-04-12 19:57:42 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ symbol = readFewBits ( s , maxBits ) ;
2019-04-12 19:57:42 +08:00
if ( symbol >= alphabetSizeLimit ) {
throw "Can't readHuffmanCode" ;
}
symbols [ i ] = symbol ;
}
checkDupes ( symbols , numSymbols ) ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ histogramId = numSymbols ;
if ( numSymbols === 4 ) {
2019-04-12 19:57:42 +08:00
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 ) {
2023-04-11 15:17:20 +08:00
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 ] ;
2019-04-12 19:57:42 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ p = ( s . accumulator32 >>> s . bitOffset ) & 15 ;
2019-04-12 19:57:42 +08:00
s . bitOffset += FIXED _TABLE [ p ] >> 16 ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ v = FIXED _TABLE [ p ] & 0xFFFF ;
2019-04-12 19:57:42 +08:00
codeLengthCodeLengths [ codeLenIdx ] = v ;
2023-04-11 15:17:20 +08:00
if ( v !== 0 ) {
2019-04-12 19:57:42 +08:00
space -= ( 32 >> v ) ;
numCodes ++ ;
}
}
2023-04-11 15:17:20 +08:00
if ( space !== 0 && numCodes !== 1 ) {
2019-04-12 19:57:42 +08:00
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 }
2017-08-28 17:31:29 +08:00
* /
2019-04-12 19:57:42 +08:00
function readHuffmanCode ( alphabetSizeMax , alphabetSizeLimit , tableGroup , tableIdx , s ) {
2017-08-28 17:31:29 +08:00
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ simpleCodeOrSkip = readFewBits ( s , 2 ) ;
if ( simpleCodeOrSkip === 1 ) {
2019-04-12 19:57:42 +08:00
return readSimpleHuffmanCode ( alphabetSizeMax , alphabetSizeLimit , tableGroup , tableIdx , s ) ;
2017-08-28 17:31:29 +08:00
} else {
2019-04-12 19:57:42 +08:00
return readComplexHuffmanCode ( alphabetSizeLimit , simpleCodeOrSkip , tableGroup , tableIdx , s ) ;
2017-08-28 17:31:29 +08:00
}
}
/ * *
2019-04-12 19:57:42 +08:00
* @ param { number } contextMapSize
2017-08-28 17:31:29 +08:00
* @ param { ! Int8Array } contextMap
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function decodeContextMap ( contextMapSize , contextMap , s ) {
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ numTrees = decodeVarLenUnsignedByte ( s ) + 1 ;
if ( numTrees === 1 ) {
2017-08-28 17:31:29 +08:00
contextMap . fill ( 0 , 0 , contextMapSize ) ;
return numTrees ;
}
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ useRleForZeros = readFewBits ( s , 1 ) ;
let /** @type {number} */ maxRunLengthPrefix = 0 ;
if ( useRleForZeros !== 0 ) {
2017-08-28 17:31:29 +08:00
maxRunLengthPrefix = readFewBits ( s , 4 ) + 1 ;
}
2023-04-11 15:17:20 +08:00
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 ;
2019-04-12 19:57:42 +08:00
readHuffmanCode ( alphabetSize , alphabetSize , table , tableIdx , s ) ;
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < contextMapSize ; ) {
2017-08-28 17:31:29 +08:00
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ code = readSymbol ( table , tableIdx , s ) ;
if ( code === 0 ) {
2017-08-28 17:31:29 +08:00
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 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ reps = ( 1 << code ) + readFewBits ( s , code ) ;
while ( reps !== 0 ) {
2017-08-28 17:31:29 +08:00
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 ;
}
2023-04-11 15:17:20 +08:00
if ( readFewBits ( s , 1 ) === 1 ) {
2017-08-28 17:31:29 +08:00
inverseMoveToFrontTransform ( contextMap , contextMapSize ) ;
}
return numTrees ;
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ param { number } treeType
* @ param { number } numBlockTypes
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function decodeBlockTypeAndLength ( s , treeType , numBlockTypes ) {
2023-04-11 15:17:20 +08:00
let /** @type {!Int32Array} */ ringBuffers = s . rings ;
let /** @type {number} */ offset = 4 + treeType * 2 ;
2017-08-28 17:31:29 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ blockType = readSymbol ( s . blockTrees , 2 * treeType , s ) ;
let /** @type {number} */ result = readBlockLength ( s . blockTrees , 2 * treeType + 1 , s ) ;
if ( blockType === 1 ) {
2017-08-28 17:31:29 +08:00
blockType = ringBuffers [ offset + 1 ] + 1 ;
2023-04-11 15:17:20 +08:00
} else if ( blockType === 0 ) {
2017-08-28 17:31:29 +08:00
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
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function decodeLiteralBlockSwitch ( s ) {
s . literalBlockLength = decodeBlockTypeAndLength ( s , 0 , s . numLiteralBlockTypes ) ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ literalBlockType = s . rings [ 5 ] ;
2017-08-28 17:31:29 +08:00
s . contextMapSlice = literalBlockType << 6 ;
2019-04-12 19:57:42 +08:00
s . literalTreeIdx = s . contextMap [ s . contextMapSlice ] & 0xFF ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ contextMode = s . contextModes [ literalBlockType ] ;
2017-08-28 17:31:29 +08:00
s . contextLookupOffset1 = contextMode << 9 ;
s . contextLookupOffset2 = s . contextLookupOffset1 + 256 ;
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function decodeCommandBlockSwitch ( s ) {
s . commandBlockLength = decodeBlockTypeAndLength ( s , 1 , s . numCommandBlockTypes ) ;
2019-04-12 19:57:42 +08:00
s . commandTreeIdx = s . rings [ 7 ] ;
2017-08-28 17:31:29 +08:00
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function decodeDistanceBlockSwitch ( s ) {
s . distanceBlockLength = decodeBlockTypeAndLength ( s , 2 , s . numDistanceBlockTypes ) ;
s . distContextMapSlice = s . rings [ 9 ] << 2 ;
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function maybeReallocateRingBuffer ( s ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ newSize = s . maxRingBufferSize ;
2017-08-28 17:31:29 +08:00
if ( newSize > s . expectedTotalSize ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ minimalNewSize = s . expectedTotalSize ;
2017-08-28 17:31:29 +08:00
while ( ( newSize >> 1 ) > minimalNewSize ) {
newSize >>= 1 ;
}
2023-04-11 15:17:20 +08:00
if ( ( s . inputEnd === 0 ) && newSize < 16384 && s . maxRingBufferSize >= 16384 ) {
2017-08-28 17:31:29 +08:00
newSize = 16384 ;
}
}
if ( newSize <= s . ringBufferSize ) {
return ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ ringBufferSizeWithSlack = newSize + 37 ;
let /** @type {!Int8Array} */ newBuffer = new Int8Array ( ringBufferSizeWithSlack ) ;
if ( s . ringBuffer . length !== 0 ) {
2017-08-28 17:31:29 +08:00
newBuffer . set ( s . ringBuffer . subarray ( 0 , 0 + s . ringBufferSize ) , 0 ) ;
}
s . ringBuffer = newBuffer ;
s . ringBufferSize = newSize ;
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function readNextMetablockHeader ( s ) {
2023-04-11 15:17:20 +08:00
if ( s . inputEnd !== 0 ) {
2019-04-12 19:57:42 +08:00
s . nextRunningState = 10 ;
s . runningState = 12 ;
2017-08-28 17:31:29 +08:00
return ;
}
2019-04-12 19:57:42 +08:00
s . literalTreeGroup = new Int32Array ( 0 ) ;
s . commandTreeGroup = new Int32Array ( 0 ) ;
s . distanceTreeGroup = new Int32Array ( 0 ) ;
2017-08-28 17:31:29 +08:00
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
decodeMetaBlockLength ( s ) ;
2023-04-11 15:17:20 +08:00
if ( ( s . metaBlockLength === 0 ) && ( s . isMetadata === 0 ) ) {
2017-08-28 17:31:29 +08:00
return ;
}
2023-04-11 15:17:20 +08:00
if ( ( s . isUncompressed !== 0 ) || ( s . isMetadata !== 0 ) ) {
2017-08-28 17:31:29 +08:00
jumpToByteBoundary ( s ) ;
2023-04-11 15:17:20 +08:00
s . runningState = ( s . isMetadata !== 0 ) ? 5 : 6 ;
2017-08-28 17:31:29 +08:00
} else {
2019-04-12 19:57:42 +08:00
s . runningState = 3 ;
2017-08-28 17:31:29 +08:00
}
2023-04-11 15:17:20 +08:00
if ( s . isMetadata !== 0 ) {
2017-08-28 17:31:29 +08:00
return ;
}
s . expectedTotalSize += s . metaBlockLength ;
if ( s . expectedTotalSize > 1 << 30 ) {
s . expectedTotalSize = 1 << 30 ;
}
if ( s . ringBufferSize < s . maxRingBufferSize ) {
maybeReallocateRingBuffer ( s ) ;
}
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ param { number } treeType
* @ param { number } numBlockTypes
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function readMetablockPartition ( s , treeType , numBlockTypes ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ offset = s . blockTrees [ 2 * treeType ] ;
2017-08-28 17:31:29 +08:00
if ( numBlockTypes <= 1 ) {
2019-04-12 19:57:42 +08:00
s . blockTrees [ 2 * treeType + 1 ] = offset ;
s . blockTrees [ 2 * treeType + 2 ] = offset ;
2017-08-28 17:31:29 +08:00
return 1 << 28 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ blockTypeAlphabetSize = numBlockTypes + 2 ;
2019-04-12 19:57:42 +08:00
offset += readHuffmanCode ( blockTypeAlphabetSize , blockTypeAlphabetSize , s . blockTrees , 2 * treeType , s ) ;
s . blockTrees [ 2 * treeType + 1 ] = offset ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ blockLengthAlphabetSize = 26 ;
2019-04-12 19:57:42 +08:00
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 ) {
2023-04-11 15:17:20 +08:00
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 ) {
2019-04-12 19:57:42 +08:00
distExtraBits [ i ] = 0 ;
distOffset [ i ] = j + 1 ;
++ i ;
}
while ( i < alphabetSizeLimit ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ base = ndirect + ( ( ( ( 2 + half ) << bits ) - 4 ) << npostfix ) + 1 ;
for ( let /** @type {number} */ j = 0 ; j < postfix ; ++ j ) {
2019-04-12 19:57:42 +08:00
distExtraBits [ i ] = bits ;
distOffset [ i ] = base + j ;
++ i ;
}
bits = bits + half ;
half = half ^ 1 ;
}
2017-08-28 17:31:29 +08:00
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
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 ) ;
2019-04-12 19:57:42 +08:00
s . numDirectDistanceCodes = readFewBits ( s , 4 ) << s . distancePostfixBits ;
2017-08-28 17:31:29 +08:00
s . contextModes = new Int8Array ( s . numLiteralBlockTypes ) ;
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < s . numLiteralBlockTypes ; ) {
let /** @type {number} */ limit = min ( i + 96 , s . numLiteralBlockTypes ) ;
2017-08-28 17:31:29 +08:00
for ( ; i < limit ; ++ i ) {
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2019-04-12 19:57:42 +08:00
s . contextModes [ i ] = readFewBits ( s , 2 ) ;
2017-08-28 17:31:29 +08:00
}
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
}
s . contextMap = new Int8Array ( s . numLiteralBlockTypes << 6 ) ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ numLiteralTrees = decodeContextMap ( s . numLiteralBlockTypes << 6 , s . contextMap , s ) ;
2017-08-28 17:31:29 +08:00
s . trivialLiteralContext = 1 ;
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ j = 0 ; j < s . numLiteralBlockTypes << 6 ; j ++ ) {
if ( s . contextMap [ j ] !== j >> 6 ) {
2017-08-28 17:31:29 +08:00
s . trivialLiteralContext = 0 ;
break ;
}
}
s . distContextMap = new Int8Array ( s . numDistanceBlockTypes << 2 ) ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ numDistTrees = decodeContextMap ( s . numDistanceBlockTypes << 2 , s . distContextMap , s ) ;
2019-04-12 19:57:42 +08:00
s . literalTreeGroup = decodeHuffmanTreeGroup ( 256 , 256 , numLiteralTrees , s ) ;
s . commandTreeGroup = decodeHuffmanTreeGroup ( 704 , 704 , s . numCommandBlockTypes , s ) ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ distanceAlphabetSizeMax = calculateDistanceAlphabetSize ( s . distancePostfixBits , s . numDirectDistanceCodes , 24 ) ;
let /** @type {number} */ distanceAlphabetSizeLimit = distanceAlphabetSizeMax ;
if ( s . isLargeWindow === 1 ) {
2019-04-12 19:57:42 +08:00
distanceAlphabetSizeMax = calculateDistanceAlphabetSize ( s . distancePostfixBits , s . numDirectDistanceCodes , 62 ) ;
distanceAlphabetSizeLimit = calculateDistanceAlphabetLimit ( 0x7FFFFFFC , s . distancePostfixBits , s . numDirectDistanceCodes ) ;
}
s . distanceTreeGroup = decodeHuffmanTreeGroup ( distanceAlphabetSizeMax , distanceAlphabetSizeLimit , numDistTrees , s ) ;
calculateDistanceLut ( s , distanceAlphabetSizeLimit ) ;
2017-08-28 17:31:29 +08:00
s . contextMapSlice = 0 ;
s . distContextMapSlice = 0 ;
2019-04-12 19:57:42 +08:00
s . contextLookupOffset1 = s . contextModes [ 0 ] * 512 ;
2017-08-28 17:31:29 +08:00
s . contextLookupOffset2 = s . contextLookupOffset1 + 256 ;
2019-04-12 19:57:42 +08:00
s . literalTreeIdx = 0 ;
s . commandTreeIdx = 0 ;
2017-08-28 17:31:29 +08:00
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
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function copyUncompressedData ( s ) {
2023-04-11 15:17:20 +08:00
let /** @type {!Int8Array} */ ringBuffer = s . ringBuffer ;
2017-08-28 17:31:29 +08:00
if ( s . metaBlockLength <= 0 ) {
reload ( s ) ;
2019-04-12 19:57:42 +08:00
s . runningState = 2 ;
2017-08-28 17:31:29 +08:00
return ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ chunkLength = min ( s . ringBufferSize - s . pos , s . metaBlockLength ) ;
2021-01-18 17:56:39 +08:00
copyRawBytes ( s , ringBuffer , s . pos , chunkLength ) ;
2017-08-28 17:31:29 +08:00
s . metaBlockLength -= chunkLength ;
s . pos += chunkLength ;
2023-04-11 15:17:20 +08:00
if ( s . pos === s . ringBufferSize ) {
2019-04-12 19:57:42 +08:00
s . nextRunningState = 6 ;
s . runningState = 12 ;
2017-08-28 17:31:29 +08:00
return ;
}
reload ( s ) ;
2019-04-12 19:57:42 +08:00
s . runningState = 2 ;
2017-08-28 17:31:29 +08:00
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function writeRingBuffer ( s ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ toWrite = min ( s . outputLength - s . outputUsed , s . ringBufferBytesReady - s . ringBufferBytesWritten ) ;
if ( toWrite !== 0 ) {
2018-09-13 20:09:32 +08:00
s . output . set ( s . ringBuffer . subarray ( s . ringBufferBytesWritten , s . ringBufferBytesWritten + toWrite ) , s . outputOffset + s . outputUsed ) ;
2017-08-28 17:31:29 +08:00
s . outputUsed += toWrite ;
2018-09-13 20:09:32 +08:00
s . ringBufferBytesWritten += toWrite ;
2017-08-28 17:31:29 +08:00
}
if ( s . outputUsed < s . outputLength ) {
return 1 ;
} else {
return 0 ;
}
}
/ * *
2019-04-12 19:57:42 +08:00
* @ param { number } alphabetSizeMax
* @ param { number } alphabetSizeLimit
* @ param { number } n
2017-08-28 17:31:29 +08:00
* @ param { ! State } s
* @ return { ! Int32Array }
* /
2019-04-12 19:57:42 +08:00
function decodeHuffmanTreeGroup ( alphabetSizeMax , alphabetSizeLimit , n , s ) {
2023-04-11 15:17:20 +08:00
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 ) {
2017-08-28 17:31:29 +08:00
group [ i ] = next ;
2019-04-12 19:57:42 +08:00
next += readHuffmanCode ( alphabetSizeMax , alphabetSizeLimit , group , i , s ) ;
2017-08-28 17:31:29 +08:00
}
return group ;
}
2018-09-13 20:09:32 +08:00
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
2018-09-13 20:09:32 +08:00
* /
function calculateFence ( s ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ result = s . ringBufferSize ;
if ( s . isEager !== 0 ) {
2018-09-13 20:09:32 +08:00
result = min ( result , s . ringBufferBytesWritten + s . outputLength - s . outputUsed ) ;
}
return result ;
}
2021-01-18 17:56:39 +08:00
/ * *
* @ param { ! State } s
* @ param { number } fence
* @ return { void }
* /
function doUseDictionary ( s , fence ) {
if ( s . distance > 0x7FFFFFFC ) {
throw "Invalid backward reference" ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ address = s . distance - s . maxDistance - 1 - s . cdTotalSize ;
2021-01-18 17:56:39 +08:00
if ( address < 0 ) {
initializeCompoundDictionaryCopy ( s , - address - 1 , s . copyLength ) ;
s . runningState = 14 ;
} else {
2023-04-11 15:17:20 +08:00
let /** @type {!Int8Array} */ dictionaryData = /** @type{!Int8Array} */ ( data ) ;
let /** @type {number} */ wordLength = s . copyLength ;
2021-01-18 17:56:39 +08:00
if ( wordLength > 31 ) {
throw "Invalid backward reference" ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ shift = sizeBits [ wordLength ] ;
if ( shift === 0 ) {
2021-01-18 17:56:39 +08:00
throw "Invalid backward reference" ;
}
2023-04-11 15:17:20 +08:00
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 ;
2021-01-18 17:56:39 +08:00
offset += wordIdx * wordLength ;
2023-04-11 15:17:20 +08:00
let /** @type {!Transforms} */ transforms = RFC _TRANSFORMS ;
2021-01-18 17:56:39 +08:00
if ( transformIdx >= transforms . numTransforms ) {
throw "Invalid backward reference" ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ len = transformDictionaryWord ( s . ringBuffer , s . pos , dictionaryData , offset , wordLength , transforms , transformIdx ) ;
2021-01-18 17:56:39 +08:00
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 ) ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ blockBits = 8 ;
while ( ( ( s . cdTotalSize - 1 ) >>> blockBits ) !== 0 ) {
2021-01-18 17:56:39 +08:00
blockBits ++ ;
}
blockBits -= 8 ;
s . cdBlockBits = blockBits ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ cursor = 0 ;
let /** @type {number} */ index = 0 ;
2021-01-18 17:56:39 +08:00
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 ) {
2023-04-11 15:17:20 +08:00
if ( s . cdBlockBits === - 1 ) {
2021-01-18 17:56:39 +08:00
initializeCompoundDictionary ( s ) ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ index = s . cdBlockMap [ address >>> s . cdBlockBits ] ;
2021-01-18 17:56:39 +08:00
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 ) {
2023-04-11 15:17:20 +08:00
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 ;
2021-01-18 17:56:39 +08:00
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 ;
2023-04-11 15:17:20 +08:00
if ( length === remChunkLength ) {
2021-01-18 17:56:39 +08:00
s . cdBrIndex ++ ;
s . cdBrOffset = 0 ;
}
if ( pos >= fence ) {
break ;
}
}
return pos - origPos ;
}
2017-08-28 17:31:29 +08:00
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function decompress ( s ) {
2023-04-11 15:17:20 +08:00
if ( s . runningState === 0 ) {
2017-08-28 17:31:29 +08:00
throw "Can't decompress until initialized" ;
}
2023-04-11 15:17:20 +08:00
if ( s . runningState === 11 ) {
2017-08-28 17:31:29 +08:00
throw "Can't decompress after close" ;
}
2023-04-11 15:17:20 +08:00
if ( s . runningState === 1 ) {
let /** @type {number} */ windowBits = decodeWindowBits ( s ) ;
if ( windowBits === - 1 ) {
2019-04-12 19:57:42 +08:00
throw "Invalid 'windowBits' code" ;
}
s . maxRingBufferSize = 1 << windowBits ;
s . maxBackwardDistance = s . maxRingBufferSize - 16 ;
s . runningState = 2 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ fence = calculateFence ( s ) ;
let /** @type {number} */ ringBufferMask = s . ringBufferSize - 1 ;
let /** @type {!Int8Array} */ ringBuffer = s . ringBuffer ;
while ( s . runningState !== 10 ) {
2017-08-28 17:31:29 +08:00
switch ( s . runningState ) {
2019-04-12 19:57:42 +08:00
case 2 :
2017-08-28 17:31:29 +08:00
if ( s . metaBlockLength < 0 ) {
throw "Invalid metablock length" ;
}
readNextMetablockHeader ( s ) ;
2018-09-13 20:09:32 +08:00
fence = calculateFence ( s ) ;
2017-08-28 17:31:29 +08:00
ringBufferMask = s . ringBufferSize - 1 ;
ringBuffer = s . ringBuffer ;
continue ;
case 3 :
2019-04-12 19:57:42 +08:00
readMetablockHuffmanCodesAndContextMaps ( s ) ;
s . runningState = 4 ;
case 4 :
2017-08-28 17:31:29 +08:00
if ( s . metaBlockLength <= 0 ) {
2019-04-12 19:57:42 +08:00
s . runningState = 2 ;
2017-08-28 17:31:29 +08:00
continue ;
}
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
2023-04-11 15:17:20 +08:00
if ( s . commandBlockLength === 0 ) {
2017-08-28 17:31:29 +08:00
decodeCommandBlockSwitch ( s ) ;
}
s . commandBlockLength -- ;
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
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 ] ;
2019-04-12 19:57:42 +08:00
s . distanceCode = CMD _LOOKUP [ cmdCode + 3 ] ;
2017-08-28 17:31:29 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ insertLengthExtraBits = insertAndCopyExtraBits & 0xFF ;
2021-06-23 15:40:57 +08:00
s . insertLength = insertLengthOffset + ( ( insertLengthExtraBits <= 16 ) ? readFewBits ( s , insertLengthExtraBits ) : readManyBits ( s , insertLengthExtraBits ) ) ;
2017-08-28 17:31:29 +08:00
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ copyLengthExtraBits = insertAndCopyExtraBits >> 8 ;
2021-06-23 15:40:57 +08:00
s . copyLength = copyLengthOffset + ( ( copyLengthExtraBits <= 16 ) ? readFewBits ( s , copyLengthExtraBits ) : readManyBits ( s , copyLengthExtraBits ) ) ;
2017-08-28 17:31:29 +08:00
s . j = 0 ;
2019-04-12 19:57:42 +08:00
s . runningState = 7 ;
case 7 :
2023-04-11 15:17:20 +08:00
if ( s . trivialLiteralContext !== 0 ) {
2017-08-28 17:31:29 +08:00
while ( s . j < s . insertLength ) {
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
2023-04-11 15:17:20 +08:00
if ( s . literalBlockLength === 0 ) {
2017-08-28 17:31:29 +08:00
decodeLiteralBlockSwitch ( s ) ;
}
s . literalBlockLength -- ;
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2019-04-12 19:57:42 +08:00
ringBuffer [ s . pos ] = readSymbol ( s . literalTreeGroup , s . literalTreeIdx , s ) ;
2018-09-13 20:09:32 +08:00
s . pos ++ ;
2017-08-28 17:31:29 +08:00
s . j ++ ;
2018-09-13 20:09:32 +08:00
if ( s . pos >= fence ) {
2019-04-12 19:57:42 +08:00
s . nextRunningState = 7 ;
s . runningState = 12 ;
2017-08-28 17:31:29 +08:00
break ;
}
}
} else {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ prevByte1 = ringBuffer [ ( s . pos - 1 ) & ringBufferMask ] & 0xFF ;
let /** @type {number} */ prevByte2 = ringBuffer [ ( s . pos - 2 ) & ringBufferMask ] & 0xFF ;
2017-08-28 17:31:29 +08:00
while ( s . j < s . insertLength ) {
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
2023-04-11 15:17:20 +08:00
if ( s . literalBlockLength === 0 ) {
2017-08-28 17:31:29 +08:00
decodeLiteralBlockSwitch ( s ) ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ literalContext = LOOKUP [ s . contextLookupOffset1 + prevByte1 ] | LOOKUP [ s . contextLookupOffset2 + prevByte2 ] ;
let /** @type {number} */ literalTreeIdx = s . contextMap [ s . contextMapSlice + literalContext ] & 0xFF ;
2017-08-28 17:31:29 +08:00
s . literalBlockLength -- ;
prevByte2 = prevByte1 ;
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2019-04-12 19:57:42 +08:00
prevByte1 = readSymbol ( s . literalTreeGroup , literalTreeIdx , s ) ;
2017-08-28 17:31:29 +08:00
ringBuffer [ s . pos ] = prevByte1 ;
2018-09-13 20:09:32 +08:00
s . pos ++ ;
2017-08-28 17:31:29 +08:00
s . j ++ ;
2018-09-13 20:09:32 +08:00
if ( s . pos >= fence ) {
2019-04-12 19:57:42 +08:00
s . nextRunningState = 7 ;
s . runningState = 12 ;
2017-08-28 17:31:29 +08:00
break ;
}
}
}
2023-04-11 15:17:20 +08:00
if ( s . runningState !== 7 ) {
2017-08-28 17:31:29 +08:00
continue ;
}
s . metaBlockLength -= s . insertLength ;
if ( s . metaBlockLength <= 0 ) {
2019-04-12 19:57:42 +08:00
s . runningState = 4 ;
2017-08-28 17:31:29 +08:00
continue ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ distanceCode = s . distanceCode ;
2019-04-12 19:57:42 +08:00
if ( distanceCode < 0 ) {
s . distance = s . rings [ s . distRbIdx ] ;
} else {
2017-08-28 17:31:29 +08:00
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
2023-04-11 15:17:20 +08:00
if ( s . distanceBlockLength === 0 ) {
2017-08-28 17:31:29 +08:00
decodeDistanceBlockSwitch ( s ) ;
}
s . distanceBlockLength -- ;
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ distTreeIdx = s . distContextMap [ s . distContextMapSlice + distanceCode ] & 0xFF ;
2019-04-12 19:57:42 +08:00
distanceCode = readSymbol ( s . distanceTreeGroup , distTreeIdx , s ) ;
if ( distanceCode < 16 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ index = ( s . distRbIdx + DISTANCE _SHORT _CODE _INDEX _OFFSET [ distanceCode ] ) & 0x3 ;
2019-04-12 19:57:42 +08:00
s . distance = s . rings [ index ] + DISTANCE _SHORT _CODE _VALUE _OFFSET [ distanceCode ] ;
if ( s . distance < 0 ) {
throw "Negative distance" ;
}
} else {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ extraBits = s . distExtraBits [ distanceCode ] ;
let /** @type {number} */ bits ;
2019-04-12 19:57:42 +08:00
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 ) ) ;
2017-08-28 17:31:29 +08:00
}
2019-04-12 19:57:42 +08:00
s . distance = s . distOffset [ distanceCode ] + ( bits << s . distancePostfixBits ) ;
2017-08-28 17:31:29 +08:00
}
}
2023-04-11 15:17:20 +08:00
if ( s . maxDistance !== s . maxBackwardDistance && s . pos < s . maxBackwardDistance ) {
2017-08-28 17:31:29 +08:00
s . maxDistance = s . pos ;
} else {
s . maxDistance = s . maxBackwardDistance ;
}
if ( s . distance > s . maxDistance ) {
2019-04-12 19:57:42 +08:00
s . runningState = 9 ;
2017-08-28 17:31:29 +08:00
continue ;
}
2019-04-12 19:57:42 +08:00
if ( distanceCode > 0 ) {
s . distRbIdx = ( s . distRbIdx + 1 ) & 0x3 ;
s . rings [ s . distRbIdx ] = s . distance ;
2017-08-28 17:31:29 +08:00
}
if ( s . copyLength > s . metaBlockLength ) {
throw "Invalid backward reference" ;
}
s . j = 0 ;
2019-04-12 19:57:42 +08:00
s . runningState = 8 ;
case 8 :
2023-04-11 15:17:20 +08:00
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 ;
2017-08-28 17:31:29 +08:00
if ( ( srcEnd < ringBufferMask ) && ( dstEnd < ringBufferMask ) ) {
if ( copyLength < 12 || ( srcEnd > dst && dstEnd > src ) ) {
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ k = 0 ; k < copyLength ; k += 4 ) {
2017-08-28 17:31:29 +08:00
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 -- ;
2018-09-13 20:09:32 +08:00
s . pos ++ ;
2017-08-28 17:31:29 +08:00
s . j ++ ;
2018-09-13 20:09:32 +08:00
if ( s . pos >= fence ) {
2019-04-12 19:57:42 +08:00
s . nextRunningState = 8 ;
s . runningState = 12 ;
2017-08-28 17:31:29 +08:00
break ;
}
}
}
2023-04-11 15:17:20 +08:00
if ( s . runningState === 8 ) {
2019-04-12 19:57:42 +08:00
s . runningState = 4 ;
2017-08-28 17:31:29 +08:00
}
continue ;
2019-04-12 19:57:42 +08:00
case 9 :
2021-01-18 17:56:39 +08:00
doUseDictionary ( s , fence ) ;
continue ;
case 14 :
s . pos += copyFromCompoundDictionary ( s , fence ) ;
if ( s . pos >= fence ) {
s . nextRunningState = 14 ;
s . runningState = 12 ;
return ;
2017-08-28 17:31:29 +08:00
}
2019-04-12 19:57:42 +08:00
s . runningState = 4 ;
2017-08-28 17:31:29 +08:00
continue ;
2019-04-12 19:57:42 +08:00
case 5 :
2017-08-28 17:31:29 +08:00
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 -- ;
}
2019-04-12 19:57:42 +08:00
s . runningState = 2 ;
2017-08-28 17:31:29 +08:00
continue ;
2019-04-12 19:57:42 +08:00
case 6 :
2017-08-28 17:31:29 +08:00
copyUncompressedData ( s ) ;
continue ;
case 12 :
2019-04-12 19:57:42 +08:00
s . ringBufferBytesReady = min ( s . pos , s . ringBufferSize ) ;
s . runningState = 13 ;
case 13 :
2023-04-11 15:17:20 +08:00
if ( writeRingBuffer ( s ) === 0 ) {
2017-08-28 17:31:29 +08:00
return ;
}
if ( s . pos >= s . maxBackwardDistance ) {
s . maxDistance = s . maxBackwardDistance ;
}
2018-09-13 20:09:32 +08:00
if ( s . pos >= s . ringBufferSize ) {
if ( s . pos > s . ringBufferSize ) {
ringBuffer . copyWithin ( 0 , s . ringBufferSize , s . pos ) ;
}
s . pos &= ringBufferMask ;
s . ringBufferBytesWritten = 0 ;
}
2017-08-28 17:31:29 +08:00
s . runningState = s . nextRunningState ;
continue ;
default :
throw "Unexpected state " + s . runningState ;
}
}
2023-04-11 15:17:20 +08:00
if ( s . runningState === 10 ) {
2017-08-28 17:31:29 +08:00
if ( s . metaBlockLength < 0 ) {
throw "Invalid metablock length" ;
}
jumpToByteBoundary ( s ) ;
checkHealth ( s , 1 ) ;
}
}
2019-04-12 19:57:42 +08:00
/ * *
* @ constructor
* @ param { number } numTransforms
* @ param { number } prefixSuffixLen
* @ param { number } prefixSuffixCount
* @ struct
* /
function Transforms ( numTransforms , prefixSuffixLen , prefixSuffixCount ) {
2023-04-11 15:17:20 +08:00
/** @type {number} */
2019-04-12 19:57:42 +08:00
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 ) ;
}
2021-06-23 15:40:57 +08:00
/** @type {!Transforms} */
let RFC _TRANSFORMS = new Transforms ( 121 , 167 , 50 ) ;
2017-08-28 17:31:29 +08:00
/ * *
* @ param { ! Int8Array } prefixSuffix
* @ param { ! Int32Array } prefixSuffixHeads
* @ param { ! Int32Array } transforms
* @ param { ! string } prefixSuffixSrc
* @ param { ! string } transformsSrc
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function unpackTransforms ( prefixSuffix , prefixSuffixHeads , transforms , prefixSuffixSrc , transformsSrc ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ n = prefixSuffixSrc . length ;
let /** @type {number} */ index = 1 ;
let /** @type {number} */ j = 0 ;
for ( let /** @type {number} */ i = 0 ; i < n ; ++ i ) {
let /** @type {number} */ c = prefixSuffixSrc . charCodeAt ( i ) ;
if ( c === 35 ) {
2019-04-12 19:57:42 +08:00
prefixSuffixHeads [ index ++ ] = j ;
} else {
prefixSuffix [ j ++ ] = c ;
2017-08-28 17:31:29 +08:00
}
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < 363 ; ++ i ) {
2017-08-28 17:31:29 +08:00
transforms [ i ] = transformsSrc . charCodeAt ( i ) - 32 ;
}
}
{
2021-06-23 15:40:57 +08:00
unpackTransforms ( RFC _TRANSFORMS . prefixSuffixStorage , RFC _TRANSFORMS . prefixSuffixHeads , RFC _TRANSFORMS . triplets , "# #s #, #e #.# the #.com/#\xC2\xA0# 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" ) ;
2017-08-28 17:31:29 +08:00
}
/ * *
* @ param { ! Int8Array } dst
2019-04-12 19:57:42 +08:00
* @ param { number } dstOffset
* @ param { ! Int8Array } src
* @ param { number } srcOffset
* @ param { number } len
* @ param { ! Transforms } transforms
* @ param { number } transformIndex
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
2019-04-12 19:57:42 +08:00
function transformDictionaryWord ( dst , dstOffset , src , srcOffset , len , transforms , transformIndex ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ offset = dstOffset ;
let /** @type {!Int32Array} */ triplets = transforms . triplets ;
let /** @type {!Int8Array} */ prefixSuffixStorage = transforms . prefixSuffixStorage ;
let /** @type {!Int32Array} */ prefixSuffixHeads = transforms . prefixSuffixHeads ;
let /** @type {number} */ transformOffset = 3 * transformIndex ;
let /** @type {number} */ prefixIdx = triplets [ transformOffset ] ;
let /** @type {number} */ transformType = triplets [ transformOffset + 1 ] ;
let /** @type {number} */ suffixIdx = triplets [ transformOffset + 2 ] ;
let /** @type {number} */ prefix = prefixSuffixHeads [ prefixIdx ] ;
let /** @type {number} */ prefixEnd = prefixSuffixHeads [ prefixIdx + 1 ] ;
let /** @type {number} */ suffix = prefixSuffixHeads [ suffixIdx ] ;
let /** @type {number} */ suffixEnd = prefixSuffixHeads [ suffixIdx + 1 ] ;
let /** @type {number} */ omitFirst = transformType - 11 ;
let /** @type {number} */ omitLast = transformType ;
2019-04-12 19:57:42 +08:00
if ( omitFirst < 1 || omitFirst > 9 ) {
omitFirst = 0 ;
}
if ( omitLast < 1 || omitLast > 9 ) {
omitLast = 0 ;
}
2023-04-11 15:17:20 +08:00
while ( prefix !== prefixEnd ) {
2019-04-12 19:57:42 +08:00
dst [ offset ++ ] = prefixSuffixStorage [ prefix ++ ] ;
}
2017-08-28 17:31:29 +08:00
if ( omitFirst > len ) {
omitFirst = len ;
}
2019-04-12 19:57:42 +08:00
srcOffset += omitFirst ;
2017-08-28 17:31:29 +08:00
len -= omitFirst ;
2019-04-12 19:57:42 +08:00
len -= omitLast ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ i = len ;
2017-08-28 17:31:29 +08:00
while ( i > 0 ) {
2019-04-12 19:57:42 +08:00
dst [ offset ++ ] = src [ srcOffset ++ ] ;
2017-08-28 17:31:29 +08:00
i -- ;
}
2023-04-11 15:17:20 +08:00
if ( transformType === 10 || transformType === 11 ) {
let /** @type {number} */ uppercaseOffset = offset - len ;
if ( transformType === 10 ) {
2017-08-28 17:31:29 +08:00
len = 1 ;
}
while ( len > 0 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ c0 = dst [ uppercaseOffset ] & 0xFF ;
2019-04-12 19:57:42 +08:00
if ( c0 < 0xC0 ) {
if ( c0 >= 97 && c0 <= 122 ) {
2017-08-28 17:31:29 +08:00
dst [ uppercaseOffset ] ^= 32 ;
}
uppercaseOffset += 1 ;
len -= 1 ;
2019-04-12 19:57:42 +08:00
} else if ( c0 < 0xE0 ) {
2017-08-28 17:31:29 +08:00
dst [ uppercaseOffset + 1 ] ^= 32 ;
uppercaseOffset += 2 ;
len -= 2 ;
} else {
dst [ uppercaseOffset + 2 ] ^= 5 ;
uppercaseOffset += 3 ;
len -= 3 ;
}
}
2023-04-11 15:17:20 +08:00
} else if ( transformType === 21 || transformType === 22 ) {
let /** @type {number} */ shiftOffset = offset - len ;
let /** @type {number} */ param = transforms . params [ transformIndex ] ;
let /** @type {number} */ scalar = ( param & 0x7FFF ) + ( 0x1000000 - ( param & 0x8000 ) ) ;
2019-04-12 19:57:42 +08:00
while ( len > 0 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ step = 1 ;
let /** @type {number} */ c0 = dst [ shiftOffset ] & 0xFF ;
2019-04-12 19:57:42 +08:00
if ( c0 < 0x80 ) {
scalar += c0 ;
dst [ shiftOffset ] = ( scalar & 0x7F ) ;
} else if ( c0 < 0xC0 ) {
} else if ( c0 < 0xE0 ) {
if ( len >= 2 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ c1 = dst [ shiftOffset + 1 ] ;
2019-04-12 19:57:42 +08:00
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 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ c1 = dst [ shiftOffset + 1 ] ;
let /** @type {number} */ c2 = dst [ shiftOffset + 2 ] ;
2019-04-12 19:57:42 +08:00
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 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ c1 = dst [ shiftOffset + 1 ] ;
let /** @type {number} */ c2 = dst [ shiftOffset + 2 ] ;
let /** @type {number} */ c3 = dst [ shiftOffset + 3 ] ;
2019-04-12 19:57:42 +08:00
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 ;
2023-04-11 15:17:20 +08:00
if ( transformType === 21 ) {
2019-04-12 19:57:42 +08:00
len = 0 ;
}
}
2017-08-28 17:31:29 +08:00
}
2023-04-11 15:17:20 +08:00
while ( suffix !== suffixEnd ) {
2019-04-12 19:57:42 +08:00
dst [ offset ++ ] = prefixSuffixStorage [ suffix ++ ] ;
2017-08-28 17:31:29 +08:00
}
return offset - dstOffset ;
}
/ * *
2019-04-12 19:57:42 +08:00
* @ param { number } key
* @ param { number } len
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function getNextKey ( key , len ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ step = 1 << ( len - 1 ) ;
while ( ( key & step ) !== 0 ) {
2017-08-28 17:31:29 +08:00
step >>= 1 ;
}
return ( key & ( step - 1 ) ) + step ;
}
/ * *
* @ param { ! Int32Array } table
2019-04-12 19:57:42 +08:00
* @ param { number } offset
* @ param { number } step
* @ param { number } end
* @ param { number } item
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function replicateValue ( table , offset , step , end , item ) {
do {
end -= step ;
table [ offset + end ] = item ;
} while ( end > 0 ) ;
}
/ * *
* @ param { ! Int32Array } count
2019-04-12 19:57:42 +08:00
* @ param { number } len
* @ param { number } rootBits
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function nextTableBitSize ( count , len , rootBits ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ left = 1 << ( len - rootBits ) ;
2017-08-28 17:31:29 +08:00
while ( len < 15 ) {
left -= count [ len ] ;
if ( left <= 0 ) {
break ;
}
len ++ ;
left <<= 1 ;
}
return len - rootBits ;
}
/ * *
2019-04-12 19:57:42 +08:00
* @ param { ! Int32Array } tableGroup
* @ param { number } tableIdx
* @ param { number } rootBits
2017-08-28 17:31:29 +08:00
* @ param { ! Int32Array } codeLengths
2019-04-12 19:57:42 +08:00
* @ param { number } codeLengthsSize
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
2019-04-12 19:57:42 +08:00
function buildHuffmanTable ( tableGroup , tableIdx , rootBits , codeLengths , codeLengthsSize ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ tableOffset = tableGroup [ tableIdx ] ;
let /** @type {number} */ key ;
let /** @type {!Int32Array} */ sorted = new Int32Array ( codeLengthsSize ) ;
let /** @type {!Int32Array} */ count = new Int32Array ( 16 ) ;
let /** @type {!Int32Array} */ offset = new Int32Array ( 16 ) ;
let /** @type {number} */ symbol ;
2017-08-28 17:31:29 +08:00
for ( symbol = 0 ; symbol < codeLengthsSize ; symbol ++ ) {
count [ codeLengths [ symbol ] ] ++ ;
}
offset [ 1 ] = 0 ;
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ len = 1 ; len < 15 ; len ++ ) {
2017-08-28 17:31:29 +08:00
offset [ len + 1 ] = offset [ len ] + count [ len ] ;
}
for ( symbol = 0 ; symbol < codeLengthsSize ; symbol ++ ) {
2023-04-11 15:17:20 +08:00
if ( codeLengths [ symbol ] !== 0 ) {
2017-08-28 17:31:29 +08:00
sorted [ offset [ codeLengths [ symbol ] ] ++ ] = symbol ;
}
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ tableBits = rootBits ;
let /** @type {number} */ tableSize = 1 << tableBits ;
let /** @type {number} */ totalSize = tableSize ;
if ( offset [ 15 ] === 1 ) {
2017-08-28 17:31:29 +08:00
for ( key = 0 ; key < totalSize ; key ++ ) {
2019-04-12 19:57:42 +08:00
tableGroup [ tableOffset + key ] = sorted [ 0 ] ;
2017-08-28 17:31:29 +08:00
}
2019-04-12 19:57:42 +08:00
return totalSize ;
2017-08-28 17:31:29 +08:00
}
key = 0 ;
symbol = 0 ;
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ len = 1 , step = 2 ; len <= rootBits ; len ++ , step <<= 1 ) {
2017-08-28 17:31:29 +08:00
for ( ; count [ len ] > 0 ; count [ len ] -- ) {
2019-04-12 19:57:42 +08:00
replicateValue ( tableGroup , tableOffset + key , step , tableSize , len << 16 | sorted [ symbol ++ ] ) ;
2017-08-28 17:31:29 +08:00
key = getNextKey ( key , len ) ;
}
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ mask = totalSize - 1 ;
let /** @type {number} */ low = - 1 ;
let /** @type {number} */ currentOffset = tableOffset ;
for ( let /** @type {number} */ len = rootBits + 1 , step = 2 ; len <= 15 ; len ++ , step <<= 1 ) {
2017-08-28 17:31:29 +08:00
for ( ; count [ len ] > 0 ; count [ len ] -- ) {
2023-04-11 15:17:20 +08:00
if ( ( key & mask ) !== low ) {
2017-08-28 17:31:29 +08:00
currentOffset += tableSize ;
tableBits = nextTableBitSize ( count , len , rootBits ) ;
tableSize = 1 << tableBits ;
totalSize += tableSize ;
low = key & mask ;
2019-04-12 19:57:42 +08:00
tableGroup [ tableOffset + low ] = ( tableBits + rootBits ) << 16 | ( currentOffset - tableOffset - low ) ;
2017-08-28 17:31:29 +08:00
}
2019-04-12 19:57:42 +08:00
replicateValue ( tableGroup , currentOffset + ( key >> rootBits ) , step , tableSize , ( len - rootBits ) << 16 | sorted [ symbol ++ ] ) ;
2017-08-28 17:31:29 +08:00
key = getNextKey ( key , len ) ;
}
}
2019-04-12 19:57:42 +08:00
return totalSize ;
2017-08-28 17:31:29 +08:00
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function doReadMoreInput ( s ) {
2023-04-11 15:17:20 +08:00
if ( s . endOfStreamReached !== 0 ) {
2017-08-28 17:31:29 +08:00
if ( halfAvailable ( s ) >= - 2 ) {
return ;
}
throw "No more input" ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ readOffset = s . halfOffset << 1 ;
let /** @type {number} */ bytesInBuffer = 4096 - readOffset ;
2017-08-28 17:31:29 +08:00
s . byteBuffer . copyWithin ( 0 , readOffset , 4096 ) ;
s . halfOffset = 0 ;
while ( bytesInBuffer < 4096 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ spaceLeft = 4096 - bytesInBuffer ;
let /** @type {number} */ len = readInput ( s . input , s . byteBuffer , bytesInBuffer , spaceLeft ) ;
2017-08-28 17:31:29 +08:00
if ( len <= 0 ) {
s . endOfStreamReached = 1 ;
s . tailBytes = bytesInBuffer ;
bytesInBuffer += 1 ;
break ;
}
bytesInBuffer += len ;
}
bytesToNibbles ( s , bytesInBuffer ) ;
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ param { number } endOfStream
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function checkHealth ( s , endOfStream ) {
2023-04-11 15:17:20 +08:00
if ( s . endOfStreamReached === 0 ) {
2017-08-28 17:31:29 +08:00
return ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ byteOffset = ( s . halfOffset << 1 ) + ( ( s . bitOffset + 7 ) >> 3 ) - 4 ;
2017-08-28 17:31:29 +08:00
if ( byteOffset > s . tailBytes ) {
throw "Read after end" ;
}
2023-04-11 15:17:20 +08:00
if ( ( endOfStream !== 0 ) && ( byteOffset !== s . tailBytes ) ) {
2017-08-28 17:31:29 +08:00
throw "Unused bytes after end" ;
}
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { void }
* /
function assertAccumulatorHealthy ( s ) {
if ( s . bitOffset > 32 ) {
throw "Accumulator underloaded: " + s . bitOffset ;
}
}
/ * *
* @ param { ! State } s
* @ param { number } n
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function readFewBits ( s , n ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ val = ( s . accumulator32 >>> s . bitOffset ) & ( ( 1 << n ) - 1 ) ;
2017-08-28 17:31:29 +08:00
s . bitOffset += n ;
return val ;
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ param { number } n
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function readManyBits ( s , n ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ low = readFewBits ( s , 16 ) ;
2017-08-28 17:31:29 +08:00
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
return low | ( readFewBits ( s , n - 16 ) << 16 ) ;
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function initBitReader ( s ) {
s . byteBuffer = new Int8Array ( 4160 ) ;
s . accumulator32 = 0 ;
s . shortBuffer = new Int16Array ( 2080 ) ;
s . bitOffset = 32 ;
s . halfOffset = 2048 ;
s . endOfStreamReached = 0 ;
prepare ( s ) ;
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function prepare ( s ) {
if ( s . halfOffset > 2030 ) {
doReadMoreInput ( s ) ;
}
checkHealth ( s , 0 ) ;
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function reload ( s ) {
2023-04-11 15:17:20 +08:00
if ( s . bitOffset === 32 ) {
2017-08-28 17:31:29 +08:00
prepare ( s ) ;
}
}
/ * *
* @ param { ! State } s
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function jumpToByteBoundary ( s ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ padding = ( 32 - s . bitOffset ) & 7 ;
if ( padding !== 0 ) {
let /** @type {number} */ paddingBits = readFewBits ( s , padding ) ;
if ( paddingBits !== 0 ) {
2017-08-28 17:31:29 +08:00
throw "Corrupted padding bits" ;
}
}
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function halfAvailable ( s ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ limit = 2048 ;
if ( s . endOfStreamReached !== 0 ) {
2017-08-28 17:31:29 +08:00
limit = ( s . tailBytes + 1 ) >> 1 ;
}
return limit - s . halfOffset ;
}
/ * *
* @ param { ! State } s
* @ param { ! Int8Array } data
2019-04-12 19:57:42 +08:00
* @ param { number } offset
* @ param { number } length
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
2021-01-18 17:56:39 +08:00
function copyRawBytes ( s , data , offset , length ) {
2023-04-11 15:17:20 +08:00
if ( ( s . bitOffset & 7 ) !== 0 ) {
2017-08-28 17:31:29 +08:00
throw "Unaligned copyBytes" ;
}
2023-04-11 15:17:20 +08:00
while ( ( s . bitOffset !== 32 ) && ( length !== 0 ) ) {
2017-08-28 17:31:29 +08:00
data [ offset ++ ] = ( s . accumulator32 >>> s . bitOffset ) ;
s . bitOffset += 8 ;
length -- ;
}
2023-04-11 15:17:20 +08:00
if ( length === 0 ) {
2017-08-28 17:31:29 +08:00
return ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ copyNibbles = min ( halfAvailable ( s ) , length >> 1 ) ;
2017-08-28 17:31:29 +08:00
if ( copyNibbles > 0 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ readOffset = s . halfOffset << 1 ;
let /** @type {number} */ delta = copyNibbles << 1 ;
2017-08-28 17:31:29 +08:00
data . set ( s . byteBuffer . subarray ( readOffset , readOffset + delta ) , offset ) ;
offset += delta ;
length -= delta ;
s . halfOffset += copyNibbles ;
}
2023-04-11 15:17:20 +08:00
if ( length === 0 ) {
2017-08-28 17:31:29 +08:00
return ;
}
if ( halfAvailable ( s ) > 0 ) {
if ( s . bitOffset >= 16 ) {
s . accumulator32 = ( s . shortBuffer [ s . halfOffset ++ ] << 16 ) | ( s . accumulator32 >>> 16 ) ;
s . bitOffset -= 16 ;
}
2023-04-11 15:17:20 +08:00
while ( length !== 0 ) {
2017-08-28 17:31:29 +08:00
data [ offset ++ ] = ( s . accumulator32 >>> s . bitOffset ) ;
s . bitOffset += 8 ;
length -- ;
}
checkHealth ( s , 0 ) ;
return ;
}
while ( length > 0 ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ len = readInput ( s . input , data , offset , length ) ;
if ( len === - 1 ) {
2017-08-28 17:31:29 +08:00
throw "Unexpected end of input" ;
}
offset += len ;
length -= len ;
}
}
/ * *
* @ param { ! State } s
2019-04-12 19:57:42 +08:00
* @ param { number } byteLen
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function bytesToNibbles ( s , byteLen ) {
2023-04-11 15:17:20 +08:00
let /** @type {!Int8Array} */ byteBuffer = s . byteBuffer ;
let /** @type {number} */ halfLen = byteLen >> 1 ;
let /** @type {!Int16Array} */ shortBuffer = s . shortBuffer ;
for ( let /** @type {number} */ i = 0 ; i < halfLen ; ++ i ) {
2017-08-28 17:31:29 +08:00
shortBuffer [ i ] = ( ( byteBuffer [ i * 2 ] & 0xFF ) | ( ( byteBuffer [ ( i * 2 ) + 1 ] & 0xFF ) << 8 ) ) ;
}
}
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
let LOOKUP = new Int32Array ( 2048 ) ;
2017-08-28 17:31:29 +08:00
/ * *
* @ param { ! Int32Array } lookup
* @ param { ! string } map
* @ param { ! string } rle
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
function unpackLookupTable ( lookup , map , rle ) {
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < 256 ; ++ i ) {
2017-08-28 17:31:29 +08:00
lookup [ i ] = i & 0x3F ;
lookup [ 512 + i ] = i >> 2 ;
lookup [ 1792 + i ] = 2 + ( i >> 6 ) ;
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < 128 ; ++ i ) {
2017-08-28 17:31:29 +08:00
lookup [ 1024 + i ] = 4 * ( map . charCodeAt ( i ) - 32 ) ;
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < 64 ; ++ i ) {
2017-08-28 17:31:29 +08:00
lookup [ 1152 + i ] = i & 1 ;
lookup [ 1216 + i ] = 2 + ( i & 1 ) ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ offset = 1280 ;
for ( let /** @type {number} */ k = 0 ; k < 19 ; ++ k ) {
let /** @type {number} */ value = k & 3 ;
let /** @type {number} */ rep = rle . charCodeAt ( k ) - 32 ;
for ( let /** @type {number} */ i = 0 ; i < rep ; ++ i ) {
2017-08-28 17:31:29 +08:00
lookup [ offset ++ ] = value ;
}
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < 16 ; ++ i ) {
2017-08-28 17:31:29 +08:00
lookup [ 1792 + i ] = 1 ;
lookup [ 2032 + i ] = 6 ;
}
lookup [ 1792 ] = 0 ;
lookup [ 2047 ] = 7 ;
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < 256 ; ++ i ) {
2017-08-28 17:31:29 +08:00
lookup [ 1536 + i ] = lookup [ 1792 + i ] << 3 ;
}
}
{
2021-06-23 15:40:57 +08:00
unpackLookupTable ( LOOKUP , " !! ! \"#$##%#$&'##(#)#++++++++++((&*'##,---,---,-----,-----,-----&#'###.///.///./////./////./////&#'# " , "A/* ': & : $ \x81 @" ) ;
2017-08-28 17:31:29 +08:00
}
/ * *
* @ constructor
* @ struct
* /
function State ( ) {
/** @type {!Int8Array} */
this . ringBuffer = new Int8Array ( 0 ) ;
/** @type {!Int8Array} */
this . contextModes = new Int8Array ( 0 ) ;
/** @type {!Int8Array} */
this . contextMap = new Int8Array ( 0 ) ;
/** @type {!Int8Array} */
this . distContextMap = new Int8Array ( 0 ) ;
/** @type {!Int8Array} */
2019-04-12 19:57:42 +08:00
this . distExtraBits = new Int8Array ( 0 ) ;
/** @type {!Int8Array} */
2017-08-28 17:31:29 +08:00
this . output = new Int8Array ( 0 ) ;
/** @type {!Int8Array} */
this . byteBuffer = new Int8Array ( 0 ) ;
/** @type {!Int16Array} */
this . shortBuffer = new Int16Array ( 0 ) ;
/** @type {!Int32Array} */
this . intBuffer = new Int32Array ( 0 ) ;
/** @type {!Int32Array} */
this . rings = new Int32Array ( 0 ) ;
/** @type {!Int32Array} */
this . blockTrees = new Int32Array ( 0 ) ;
/** @type {!Int32Array} */
2019-04-12 19:57:42 +08:00
this . literalTreeGroup = new Int32Array ( 0 ) ;
/** @type {!Int32Array} */
this . commandTreeGroup = new Int32Array ( 0 ) ;
2017-08-28 17:31:29 +08:00
/** @type {!Int32Array} */
2019-04-12 19:57:42 +08:00
this . distanceTreeGroup = new Int32Array ( 0 ) ;
2017-08-28 17:31:29 +08:00
/** @type {!Int32Array} */
2019-04-12 19:57:42 +08:00
this . distOffset = new Int32Array ( 0 ) ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . runningState = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . nextRunningState = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . accumulator32 = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . bitOffset = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . halfOffset = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . tailBytes = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . endOfStreamReached = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . metaBlockLength = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . inputEnd = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . isUncompressed = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . isMetadata = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . literalBlockLength = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . numLiteralBlockTypes = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . commandBlockLength = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . numCommandBlockTypes = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . distanceBlockLength = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . numDistanceBlockTypes = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . pos = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . maxDistance = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . distRbIdx = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . trivialLiteralContext = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2019-04-12 19:57:42 +08:00
this . literalTreeIdx = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2019-04-12 19:57:42 +08:00
this . commandTreeIdx = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . j = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . insertLength = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . contextMapSlice = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . distContextMapSlice = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . contextLookupOffset1 = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . contextLookupOffset2 = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . distanceCode = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . numDirectDistanceCodes = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . distancePostfixBits = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . distance = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . copyLength = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . maxBackwardDistance = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . maxRingBufferSize = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . ringBufferSize = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . expectedTotalSize = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . outputOffset = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . outputLength = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2017-08-28 17:31:29 +08:00
this . outputUsed = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2018-09-13 20:09:32 +08:00
this . ringBufferBytesWritten = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2018-09-13 20:09:32 +08:00
this . ringBufferBytesReady = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2018-09-13 20:09:32 +08:00
this . isEager = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2019-04-12 19:57:42 +08:00
this . isLargeWindow = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2021-01-18 17:56:39 +08:00
this . cdNumChunks = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2021-01-18 17:56:39 +08:00
this . cdTotalSize = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2021-01-18 17:56:39 +08:00
this . cdBrIndex = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2021-01-18 17:56:39 +08:00
this . cdBrOffset = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2021-01-18 17:56:39 +08:00
this . cdBrLength = 0 ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2021-01-18 17:56:39 +08:00
this . cdBrCopied = 0 ;
/** @type {!Array} */
this . cdChunks = new Array ( 0 ) ;
/** @type {!Int32Array} */
this . cdChunkOffsets = new Int32Array ( 0 ) ;
2023-04-11 15:17:20 +08:00
/** @type {number} */
2021-01-18 17:56:39 +08:00
this . cdBlockBits = 0 ;
/** @type {!Int8Array} */
this . cdBlockMap = new Int8Array ( 0 ) ;
2017-08-28 17:31:29 +08:00
/** @type {!InputStream|null} */
this . input = null ;
this . ringBuffer = new Int8Array ( 0 ) ;
this . rings = new Int32Array ( 10 ) ;
this . rings [ 0 ] = 16 ;
this . rings [ 1 ] = 15 ;
this . rings [ 2 ] = 11 ;
this . rings [ 3 ] = 4 ;
}
2021-06-23 15:40:57 +08:00
/** @type {!Int8Array|null} */
let data = null ;
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
let offsets = new Int32Array ( 32 ) ;
2021-01-18 17:56:39 +08:00
/** @type {!Int32Array} */
2021-06-23 15:40:57 +08:00
let sizeBits = new Int32Array ( 32 ) ;
2021-01-18 17:56:39 +08:00
/ * *
* @ param { ! Int8Array } newData
* @ param { ! Int32Array } newSizeBits
* @ return { void }
* /
function setData ( newData , newSizeBits ) {
2023-04-11 15:17:20 +08:00
if ( ( isDirect ( newData ) === 0 ) || ( isReadOnly ( newData ) === 0 ) ) {
2021-01-18 17:56:39 +08:00
throw "newData must be a direct read-only byte buffer" ;
}
if ( newSizeBits . length > 31 ) {
throw "sizeBits length must be at most " + 31 ;
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < 4 ; ++ i ) {
if ( newSizeBits [ i ] !== 0 ) {
2021-01-18 17:56:39 +08:00
throw "first " + 4 + " must be 0" ;
}
}
2023-04-11 15:17:20 +08:00
let /** @type {!Int32Array} */ dictionaryOffsets = offsets ;
let /** @type {!Int32Array} */ dictionarySizeBits = sizeBits ;
2021-01-18 17:56:39 +08:00
dictionarySizeBits . set ( newSizeBits . subarray ( 0 , 0 + newSizeBits . length ) , 0 ) ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ pos = 0 ;
let /** @type {number} */ limit = newData . length ;
for ( let /** @type {number} */ i = 0 ; i < newSizeBits . length ; ++ i ) {
2021-01-18 17:56:39 +08:00
dictionaryOffsets [ i ] = pos ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ bits = dictionarySizeBits [ i ] ;
if ( bits !== 0 ) {
2021-01-18 17:56:39 +08:00
if ( bits >= 31 ) {
throw "newSizeBits values must be less than 31" ;
}
pos += i << bits ;
if ( pos <= 0 || pos > limit ) {
throw "newSizeBits is inconsistent: overflow" ;
}
}
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = newSizeBits . length ; i < 32 ; ++ i ) {
2021-01-18 17:56:39 +08:00
dictionaryOffsets [ i ] = pos ;
}
2023-04-11 15:17:20 +08:00
if ( pos !== limit ) {
2021-01-18 17:56:39 +08:00
throw "newSizeBits is inconsistent: underflow" ;
}
data = newData ;
}
2017-08-28 17:31:29 +08:00
/ * *
* @ param { ! Int8Array } dictionary
* @ param { ! string } data0
* @ param { ! string } data1
* @ param { ! string } skipFlip
2021-01-18 17:56:39 +08:00
* @ param { ! Int32Array } sizeBits
* @ param { ! string } sizeBitsData
2017-10-09 23:07:34 +08:00
* @ return { void }
2017-08-28 17:31:29 +08:00
* /
2021-01-18 17:56:39 +08:00
function unpackDictionaryData ( dictionary , data0 , data1 , skipFlip , sizeBits , sizeBitsData ) {
2023-04-11 15:17:20 +08:00
let /** @type {!Int8Array} */ dict = toUsAsciiBytes ( data0 + data1 ) ;
if ( dict . length !== dictionary . length ) {
2017-08-28 17:31:29 +08:00
throw "Corrupted brotli dictionary" ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ offset = 0 ;
let /** @type {number} */ n = skipFlip . length ;
for ( let /** @type {number} */ i = 0 ; i < n ; i += 2 ) {
let /** @type {number} */ skip = skipFlip . charCodeAt ( i ) - 36 ;
let /** @type {number} */ flip = skipFlip . charCodeAt ( i + 1 ) - 36 ;
for ( let /** @type {number} */ j = 0 ; j < skip ; ++ j ) {
2021-06-23 15:40:57 +08:00
dict [ offset ] ^= 3 ;
offset ++ ;
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ j = 0 ; j < flip ; ++ j ) {
2021-06-23 15:40:57 +08:00
dict [ offset ] ^= 236 ;
2017-08-28 17:31:29 +08:00
offset ++ ;
}
}
2023-04-11 15:17:20 +08:00
for ( let /** @type {number} */ i = 0 ; i < sizeBitsData . length ; ++ i ) {
2021-01-18 17:56:39 +08:00
sizeBits [ i ] = sizeBitsData . charCodeAt ( i ) - 65 ;
}
2018-09-13 20:09:32 +08:00
dictionary . set ( dict ) ;
2017-08-28 17:31:29 +08:00
}
{
2023-04-11 15:17:20 +08:00
let /** @type {!Int8Array} */ dictionaryData = new Int8Array ( 122784 ) ;
let /** @type {!Int32Array} */ dictionarySizeBits = new Int32Array ( 25 ) ;
2021-06-23 15:40:57 +08:00
unpackDictionaryData ( dictionaryData , "wjnfgltmojefofewab`h`lgfgbwbpkltlmozpjwf`jwzlsfmivpwojhfeqfftlqhwf{wzfbqlufqalgzolufelqnallhsobzojufojmfkfosklnfpjgfnlqftlqgolmdwkfnujftejmgsbdfgbzpevookfbgwfqnfb`kbqfbeqlnwqvfnbqhbaofvslmkjdkgbwfobmgmftpfufmmf{w`bpfalwkslpwvpfgnbgfkbmgkfqftkbwmbnfOjmhaoldpjyfabpfkfognbhfnbjmvpfq$*#(klogfmgptjwkMftpqfbgtfqfpjdmwbhfkbufdbnfpffm`boosbwktfoosovpnfmvejonsbqwiljmwkjpojpwdllgmffgtbzptfpwilapnjmgboploldlqj`kvpfpobpwwfbnbqnzellghjmdtjoofbpwtbqgafpwejqfSbdfhmltbtbz-smdnlufwkbmolbgdjufpfoemlwfnv`keffgnbmzql`hj`lmlm`follhkjgfgjfgKlnfqvofklpwbib{jmel`ovaobtpofppkboeplnfpv`kylmf233&lmfp`bqfWjnfqb`faovfelvqtffheb`fklsfdbufkbqgolpwtkfmsbqhhfswsbpppkjsqllnKWNOsobmWzsfglmfpbufhffseobdojmhplogejufwllhqbwfwltmivnswkvpgbqh`bqgejofefbqpwbzhjoowkbweboobvwlfufq-`lnwbohpklsulwfgffsnlgfqfpwwvqmalqmabmgefooqlpfvqo+phjmqlof`lnfb`wpbdfpnffwdlog-isdjwfnubqzefowwkfmpfmggqlsUjft`lsz2-3!?,b=pwlsfopfojfpwlvqsb`h-djesbpw`pp<dqbznfbm%dw8qjgfpklwobwfpbjgqlbgubq#effoilkmqj`hslqwebpw$VB.gfbg?,a=sllqajoowzsfV-P-tllgnvpw1s{8JmelqbmhtjgftbmwtbooofbgX3^8sbvotbufpvqf'+$ tbjwnbppbqnpdlfpdbjmobmdsbjg\"..#ol`hvmjwqllwtbohejqntjef{no!plmdwfpw13s{hjmgqltpwlloelmwnbjopbefpwbqnbsp`lqfqbjmeoltabazpsbmpbzp7s{85s{8bqwpellwqfbotjhjkfbwpwfswqjslqd,obhftfbhwlogElqn`bpwebmpabmhufqzqvmpivozwbph2s{8dlbodqftpoltfgdfjg>!pfwp6s{8-ip<73s{je#+pllmpfbwmlmfwvafyfqlpfmwqffgeb`wjmwldjewkbqn2;s{`bnfkjooalogyllnuljgfbpzqjmdejoosfbhjmjw`lpw0s{8ib`hwbdpajwpqloofgjwhmftmfbq?\"..dqltIPLMgvwzMbnfpbofzlv#olwpsbjmibyy`logfzfpejpkttt-qjphwbapsqfu23s{qjpf16s{Aovfgjmd033/abooelqgfbqmtjogal{-ebjqob`hufqpsbjqivmfwf`kje+\"sj`hfujo'+! tbqnolqgglfpsvoo/333jgfbgqbtkvdfpslwevmgavqmkqfe`foohfzpwj`hklvqolppevfo21s{pvjwgfboQPP!bdfgdqfzDFW!fbpfbjnpdjqobjgp;s{8mbuzdqjgwjsp :::tbqpobgz`bqp*8#~sks<kfoowbootklnyk9\t),\x0E\t#233kboo-\t\tB4s{8svpk`kbw3s{8`qft),?,kbpk46s{eobwqbqf#%%#wfoo`bnslmwlobjgnjppphjswfmwejmfnbofdfwpsolw733/\x0E\t\x0E\t`lloeffw-sks?aq=fqj`nlpwdvjgafoogfp`kbjqnbwkbwln,jnd% ;1ov`h`fmw3338wjmzdlmfkwnopfoogqvdEQFFmlgfmj`h<jg>olpfmvooubpwtjmgQPP#tfbqqfozaffmpbnfgvhfmbpb`bsftjpkdvoeW109kjwppolwdbwfhj`haovqwkfz26s{$$*8*8!=npjftjmpajqgplqwafwbpffhW2;9lqgpwqffnboo53s{ebqn\x0ElupalzpX3^-$*8!SLPWafbqhjgp*8~~nbqzwfmg+VH*rvbgyk9\n.pjy....sqls$*8\x0EojewW2:9uj`fbmgzgfaw=QPPsllomf`haoltW259gllqfuboW249ofwpebjolqbosloomlub`lopdfmf#\x0Elxplewqlnfwjooqlpp?k0=slvqebgfsjmh?wq=njmj*\x7F\"+njmfyk9\x04abqpkfbq33*8njoh#..=jqlmeqfggjphtfmwpljosvwp,ip,klozW119JPAMW139bgbnpffp?k1=iplm$/#$`lmwW129#QPPollsbpjbnllm?,s=plvoOJMFelqw`bqwW279?k2=;3s{\"..?:s{8W379njhf975Ymj`fjm`kZlqhqj`fyk9\b$**8svqfnbdfsbqbwlmfalmg904Y\\le\\$^*8333/yk9\x0Bwbmhzbqgaltoavpk965YIbub03s{\t\x7F~\t&@0&907YifeeF[SJ`bpkujpbdloepmltyk9\x05rvfq-`pppj`hnfbwnjm-ajmggfookjqfsj`pqfmw905YKWWS.132elwltloeFMG#{al{967YALGZgj`h8\t~\tf{jw906Yubqpafbw$~*8gjfw:::8bmmf~~?,Xj^-Obmdhn.^tjqfwlzpbggppfbobof{8\t\n~f`klmjmf-lqd336*wlmziftppbmgofdpqlle333*#133tjmfdfbqgldpallwdbqz`vwpwzofwfnswjlm-{no`l`hdbmd'+$-63s{Sk-Gnjp`bobmolbmgfphnjofqzbmvmj{gjp`*8~\tgvpw`ojs*-\t\t43s{.133GUGp4^=?wbsfgfnlj((*tbdffvqlskjolswpklofEBRpbpjm.15WobapsfwpVQO#avoh`llh8~\x0E\tKFBGX3^*baaqivbm+2:;ofpkwtjm?,j=plmzdvzpev`hsjsf\x7F.\t\" 331 * mgltX2 ^ 8 X ^ 8 \ tOld # pbow \ x0E \ t \ n \ nabmdwqjnabwk * x \ x0E \ t33s { \ t ~ * 8 hl9 \ 0 effpbg = \ x0Ep9 , , # X ^ 8 wloosovd + * x \ tx \ x0E \ t # - ip$133sgvboalbw - ISD * 8 \ t ~ rvlw * 8 \ t \ t$ * 8 \ t \ x0E \ t ~ \ x0E1327132613251324132 ; 132 : 13131312131113101317131613151314131 ; 131 : 130313021301130013071306130513041320132113221323133 : 133 ; 133413351336133713301331133213332 : : : 2 : : ; 2 : : 42 : : 52 : : 62 : : 72 : : 02 : : 12 : : 22 : : 32 : ; : 2 : ; ; 2 : ; 42 : ; 52 : ; 62 : ; 72 : ; 02 : ; 12 : ; 22 : ; 32 : 4 : 2 : 4 ; 2 : 442 : 452 : 462 : 472 : 402 : 412 : 422 : 432 : 5 : 2 : 5 ; 2 : 542 : 552 : 562 : 572 : 502 : 512 : 522 : 532 : 6 : 2 : 6 ; 2 : 642 : 652 : 662 : 672 : 602 : 612 : 622 : 632333231720 : 73333 : : : : ` lnln/Mpfpwffpwbsfqlwlglkb ` f ` bgbb/]lajfmg/Abbp/Aujgb ` bpllwqlelqlplollwqb ` vbogjilpjgldqbmwjslwfnbgfafbodlrv/Efpwlmbgbwqfpsl ` l ` bpbabilwlgbpjmlbdvbsvfpvmlpbmwfgj ` fovjpfoobnbzlylmbbnlqsjpllaqb ` oj ` foolgjlpklqb ` bpj<[< \\ <Q< \\ <R<P=l< \\ =l=o=n< \\ <Q<Y<S<R<R=n<T<[<Q<R<X<R=n<R<Z<Y<R<Q<T=i<q< \\ <Y<Y<]=g<P=g<~=g=m<R<^=g<^<R<q<R<R<]<s<R<W<T<Q<T<L<H<q<Y<p=g=n=g<r<Q<T<P<X< \\ <{< \\ <x< \\ <q=o<r<]=n<Y<t<[<Y<U<Q=o<P<P<N=g=o<Z5m5
2021-01-18 17:56:39 +08:00
flipBuffer ( dictionaryData ) ;
setData ( asReadOnlyBuffer ( dictionaryData ) , dictionarySizeBits ) ;
2017-08-28 17:31:29 +08:00
}
2021-01-18 17:56:39 +08:00
/* GENERATED CODE END */
2017-08-28 17:31:29 +08:00
/ * *
2023-04-11 15:17:20 +08:00
* @ param { number } a
* @ param { number } b
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function min ( a , b ) {
return a <= b ? a : b ;
}
2021-01-18 17:56:39 +08:00
/ * *
* @ param { ! Int8Array } dst
2023-04-11 15:17:20 +08:00
* @ param { number } target
2021-01-18 17:56:39 +08:00
* @ param { ! Int8Array } src
2023-04-11 15:17:20 +08:00
* @ param { number } start
* @ param { number } end
2021-01-18 17:56:39 +08:00
* @ return { void }
* /
function copyBytes ( dst , target , src , start , end ) {
dst . set ( src . slice ( start , end ) , target ) ;
}
2017-08-28 17:31:29 +08:00
/ * *
* @ param { ! InputStream | null } src
* @ param { ! Int8Array } dst
2023-04-11 15:17:20 +08:00
* @ param { number } offset
* @ param { number } length
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function readInput ( src , dst , offset , length ) {
if ( src == null ) return - 1 ;
2023-04-11 15:17:20 +08:00
let /** @type {number} */ end = min ( src . offset + length , src . data . length ) ;
let /** @type {number} */ bytesRead = end - src . offset ;
2017-08-28 17:31:29 +08:00
dst . set ( src . data . subarray ( src . offset , end ) , offset ) ;
src . offset += bytesRead ;
return bytesRead ;
}
/ * *
* @ param { ! InputStream } src
2023-04-11 15:17:20 +08:00
* @ return { number }
2017-08-28 17:31:29 +08:00
* /
function closeInput ( src ) { return 0 ; }
2021-01-18 17:56:39 +08:00
/ * *
* @ param { ! Int8Array } src
* @ return { ! Int8Array }
* /
function asReadOnlyBuffer ( src ) { return src ; }
/ * *
* @ param { ! Int8Array } src
2023-04-11 15:17:20 +08:00
* @ return { number }
2021-01-18 17:56:39 +08:00
* /
function isReadOnly ( src ) { return 1 ; }
/ * *
* @ param { ! Int8Array } src
2023-04-11 15:17:20 +08:00
* @ return { number }
2021-01-18 17:56:39 +08:00
* /
function isDirect ( src ) { return 1 ; }
2018-09-13 20:09:32 +08:00
/ * *
* @ param { ! Int8Array } buffer
* @ return { void }
* /
function flipBuffer ( buffer ) { /* no-op */ }
/ * *
* @ param { ! string } src
* @ return { ! Int8Array }
* /
function toUsAsciiBytes ( src ) {
2023-04-11 15:17:20 +08:00
let /** @type {number} */ n = src . length ;
let /** @type {!Int8Array} */ result = new Int8Array ( n ) ;
for ( let /** @type {number} */ i = 0 ; i < n ; ++ i ) {
2018-09-13 20:09:32 +08:00
result [ i ] = src . charCodeAt ( i ) ;
}
return result ;
}
2017-08-28 17:31:29 +08:00
/ * *
* @ param { ! Int8Array } bytes
2021-01-18 17:56:39 +08:00
* @ param { Options = } options
2017-08-28 17:31:29 +08:00
* @ return { ! Int8Array }
* /
2021-01-18 17:56:39 +08:00
function decode ( bytes , options ) {
2023-04-11 15:17:20 +08:00
let /** @type {!State} */ s = new State ( ) ;
2017-08-28 17:31:29 +08:00
initState ( s , new InputStream ( bytes ) ) ;
2021-01-18 17:56:39 +08:00
if ( options ) {
2021-06-23 15:40:57 +08:00
let customDictionary =
/** @type {?Int8Array} */ ( options [ "customDictionary" ] ) ;
2021-01-18 17:56:39 +08:00
if ( customDictionary ) attachDictionaryChunk ( s , customDictionary ) ;
}
2023-04-11 15:17:20 +08:00
let /** @type {number} */ totalOutput = 0 ;
let /** @type {!Array<!Int8Array>} */ chunks = [ ] ;
2017-08-28 17:31:29 +08:00
while ( true ) {
2023-04-11 15:17:20 +08:00
let /** @type {!Int8Array} */ chunk = new Int8Array ( 16384 ) ;
2017-08-28 17:31:29 +08:00
chunks . push ( chunk ) ;
s . output = chunk ;
s . outputOffset = 0 ;
s . outputLength = 16384 ;
s . outputUsed = 0 ;
decompress ( s ) ;
2018-09-13 20:09:32 +08:00
totalOutput += s . outputUsed ;
2017-08-28 17:31:29 +08:00
if ( s . outputUsed < 16384 ) break ;
}
close ( s ) ;
2023-04-11 15:17:20 +08:00
let /** @type {!Int8Array} */ result = new Int8Array ( totalOutput ) ;
let /** @type {number} */ offset = 0 ;
for ( let /** @type {number} */ i = 0 ; i < chunks . length ; ++ i ) {
let /** @type {!Int8Array} */ chunk = chunks [ i ] ;
let /** @type {number} */ end = min ( totalOutput , offset + 16384 ) ;
let /** @type {number} */ len = end - offset ;
2017-08-28 17:31:29 +08:00
if ( len < 16384 ) {
result . set ( chunk . subarray ( 0 , len ) , offset ) ;
} else {
result . set ( chunk , offset ) ;
}
offset += len ;
}
return result ;
}
2021-06-23 15:40:57 +08:00
return decode ;
} ;
/ * *
2023-04-11 15:17:20 +08:00
* @ type { function ( ! Int8Array , ? Options = ) : ! Int8Array }
2021-06-23 15:40:57 +08:00
* /
export let BrotliDecode = makeBrotliDecode ( ) ;