import DecodeStream from 'src/core/streams/DecodeStream' ; import { StreamType } from 'src/core/streams/Stream' ; class LZWStream extends DecodeStream { private stream : StreamType ; private cachedData : number ; private bitsCached : number ; private lzwState : { earlyChange : 0 | 1 ; codeLength : number ; nextCode : number ; dictionaryValues : Uint8Array ; dictionaryLengths : Uint16Array ; dictionaryPrevCodes : Uint16Array ; currentSequence : Uint8Array ; currentSequenceLength : number ; prevCode ? : number | null ; } ; constructor ( stream , maybeLength , earlyChange ) { super ( maybeLength ) ; this . stream = stream ; this . cachedData = 0 ; this . bitsCached = 0 ; const maxLzwDictionarySize = 4096 ; const lzwState = { earlyChange , codeLength : 9 , nextCode : 258 , dictionaryValues : new Uint8Array ( maxLzwDictionarySize ) , dictionaryLengths : new Uint16Array ( maxLzwDictionarySize ) , dictionaryPrevCodes : new Uint16Array ( maxLzwDictionarySize ) , currentSequence : new Uint8Array ( maxLzwDictionarySize ) , currentSequenceLength : 0 , } ; for ( let i = 0 ; i < 256 ; ++ i ) { lzwState . dictionaryValues [ i ] = i ; lzwState . dictionaryLengths [ i ] = 1 ; } this . lzwState = lzwState ; } protected readBlock ( ) { const blockSize = 512 ; let estimatedDecodedSize = blockSize * 2 ; const decodedSizeDelta = blockSize ; let i ; let j ; let q ; const lzwState = this . lzwState ; if ( ! lzwState ) { return ; } const earlyChange = lzwState . earlyChange ; let nextCode = lzwState . nextCode ; const dictionaryValues = lzwState . dictionaryValues ; const dictionaryLengths = lzwState . dictionaryLengths ; const dictionaryPrevCodes = lzwState . dictionaryPrevCodes ; let codeLength = lzwState . codeLength ; let prevCode = lzwState . prevCode ; const currentSequence = lzwState . currentSequence ; let currentSequenceLength = lzwState . currentSequenceLength ; let decodedLength = 0 ; let currentBufferLength = this . bufferLength ; let buffer = this . ensureBuffer ( this . bufferLength + estimatedDecodedSize ) ; for ( i = 0 ; i < blockSize ; i ++ ) { const code = this . readBits ( codeLength ) ; const hasPrev = currentSequenceLength > 0 ; if ( ! code || code < 256 ) { currentSequence [ 0 ] = code as number ; currentSequenceLength = 1 ; } else if ( code >= 258 ) { if ( code < nextCode ) { currentSequenceLength = dictionaryLengths [ code ] ; for ( j = currentSequenceLength - 1 , q = code ; j >= 0 ; j -- ) { currentSequence [ j ] = dictionaryValues [ q ] ; q = dictionaryPrevCodes [ q ] ; } } else { currentSequence [ currentSequenceLength ++ ] = currentSequence [ 0 ] ; } } else if ( code === 256 ) { codeLength = 9 ; nextCode = 258 ; currentSequenceLength = 0 ; continue ; } else { this . eof = true ; delete this . lzwState ; break ; } if ( hasPrev ) { dictionaryPrevCodes [ nextCode ] = prevCode as number ; dictionaryLengths [ nextCode ] = dictionaryLengths [ prevCode as number ] + 1 ; dictionaryValues [ nextCode ] = currentSequence [ 0 ] ; nextCode ++ ; codeLength = ( nextCode + earlyChange ) & ( nextCode + earlyChange - 1 ) ? codeLength : Math . min ( Math . log ( nextCode + earlyChange ) / 0.6931471805599453 + 1 , 12 ) | 0 ; } prevCode = code ; decodedLength += currentSequenceLength ; if ( estimatedDecodedSize < decodedLength ) { do { estimatedDecodedSize += decodedSizeDelta ; } while ( estimatedDecodedSize < decodedLength ) ; buffer = this . ensureBuffer ( this . bufferLength + estimatedDecodedSize ) ; } for ( j = 0 ; j < currentSequenceLength ; j ++ ) { buffer [ currentBufferLength ++ ] = currentSequence [ j ] ; } } lzwState . nextCode = nextCode ; lzwState . codeLength = codeLength ; lzwState . prevCode = prevCode ; lzwState . currentSequenceLength = currentSequenceLength ; this . bufferLength = currentBufferLength ; } private readBits ( n ) { let bitsCached = this . bitsCached ; let cachedData = this . cachedData ; while ( bitsCached < n ) { const c = this . stream . getByte ( ) ; if ( c === - 1 ) { this . eof = true ; return null ; } cachedData = ( cachedData << 8 ) | c ; bitsCached += 8 ; } this . bitsCached = bitsCached -= n ; this . cachedData = cachedData ; return ( cachedData >>> bitsCached ) & ( ( 1 << n ) - 1 ) ; } } export default LZWStream ;