/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
*/
package brotli4cj
import std.io.*
import std.ast.*
import std.math.*
class Decode {
static let MIN_LARGE_WINDOW_BITS: Int32 = 10
static let MAX_LARGE_WINDOW_BITS: Int32 = 30
private static let UNINITIALIZED: Int32 = 0
private static let INITIALIZED: Int32 = 1
private static let BLOCK_START: Int32 = 2
private static let COMPRESSED_BLOCK_START: Int32 = 3
private static let MAIN_LOOP: Int32 = 4
private static let READ_METADATA: Int32 = 5
private static let COPY_UNCOMPRESSED: Int32 = 6
private static let INSERT_LOOP: Int32 = 7
private static let COPY_LOOP: Int32 = 8
private static let USE_DICTIONARY: Int32 = 9
private static let FINISHED: Int32 = 10
private static let CLOSED: Int32 = 11
private static let INIT_WRITE: Int32 = 12
private static let WRITE: Int32 = 13
private static let COPY_FROM_COMPOUND_DICTIONARY: Int32 = 14
private static let DEFAULT_CODE_LENGTH: Int32 = 8
private static let CODE_LENGTH_REPEAT_CODE: Int32 = 16
private static let NUM_LITERAL_CODES: Int32 = 256
private static let NUM_COMMAND_CODES: Int32 = 704
private static let NUM_BLOCK_LENGTH_CODES: Int32 = 26
private static let LITERAL_CONTEXT_BITS: Int32 = 6
private static let DISTANCE_CONTEXT_BITS: Int32 = 2
private static let CD_BLOCK_MAP_BITS: Int32 = 8
private static let HUFFMAN_TABLE_BITS: Int32 = 8
private static let HUFFMAN_TABLE_MASK: Int32 = 255
static let MAX_HUFFMAN_TABLE_SIZE: Array<Int32> = [256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822, 854, 886, 920, 952, 984, 1016, 1048, 1080]
private static let HUFFMAN_TABLE_SIZE_26: Int32 = 396
private static let HUFFMAN_TABLE_SIZE_258: Int32 = 632
private static let CODE_LENGTH_CODES: Int32 = 18
private static let CODE_LENGTH_CODE_ORDER: Array<Int32> = [1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15]
private static let NUM_DISTANCE_SHORT_CODES: Int32 = 16
private static let DISTANCE_SHORT_CODE_INDEX_OFFSET: Array<Int32> = [0, 3, 2, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3]
private static let DISTANCE_SHORT_CODE_VALUE_OFFSET: Array<Int32> = [0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3]
static let FIXED_TABLE: Array<Int32> = [0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040001,
0x020000, 0x020004, 0x020003, 0x030002, 0x020000, 0x020004, 0x020003, 0x040005]
static let MAX_TRANSFORMED_WORD_LENGTH: Int32 = 5 + 24 + 8
static let MAX_DISTANCE_BITS: Int32 = 24
static let MAX_LARGE_WINDOW_DISTANCE_BITS: Int32 = 62
static let MAX_ALLOWED_DISTANCE: Int32 = 0x7FFFFFFC
static let BLOCK_LENGTH_OFFSET: Array<Int32> = [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]
static let BLOCK_LENGTH_N_BITS: Array<Int32> = [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]
static let INSERT_LENGTH_N_BITS: Array<Int16> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03,
0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0E, 0x18]
static let COPY_LENGTH_N_BITS: Array<Int16> = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02,
0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x18]
static let CMD_LOOKUP = Array<Int16>(Int64(NUM_COMMAND_CODES * 4)) { _ => 0 }
static init() {
unpackCommandLookupTable(CMD_LOOKUP);
}
static func log2floor(i: Int32): Int32 {
var tempv: Int32 = i
var result: Int32 = -1
var step: Int32 = 16
while (step > 0) {
let next = Utils.rightShift(tempv, step)
if (next != 0) {
result += step
tempv = next
}
step = step >> 1
}
return result + tempv
}
private static func calculateDistanceAlphabetSize(npostfix: Int32, ndirect: Int32, maxndistbits: Int32): Int32 {
return NUM_DISTANCE_SHORT_CODES + ndirect + 2 * (maxndistbits << npostfix)
}
private static func calculateDistanceAlphabetLimit(maxDistance: Int32, npostfix: Int32, ndirect: Int32): Int32 {
if (maxDistance < ndirect + (2 << npostfix)) {
throw IllegalArgumentException("maxDistance is too small")
}
let offset = ((maxDistance - ndirect) >> npostfix) + 4
let ndistbits = log2floor(offset) - 1
let group = ((ndistbits - 1) << 1) | ((offset >> ndistbits) & 1)
return ((group - 1) << npostfix) + (1 << npostfix) + ndirect + NUM_DISTANCE_SHORT_CODES
}
private static func unpackCommandLookupTable(cmdLookup: Array<Int16>): Unit {
let insertLengthOffsets = Array<Int32>(24) { _ => 0 }
let copyLengthOffsets = Array<Int32>(24) { _ => 0 }
copyLengthOffsets[0] = 2
for (i in 0..23) {
insertLengthOffsets[i + 1] = insertLengthOffsets[i] + (1 << Int32(INSERT_LENGTH_N_BITS[i]))
copyLengthOffsets[i + 1] = copyLengthOffsets[i] + (1 << Int32(COPY_LENGTH_N_BITS[i]))
}
for (cmdCode in 0..NUM_COMMAND_CODES) {
var rangeIdx: Int32 = Utils.rightShift(cmdCode, 6)
var distanceContextOffset: Int32 = -4
if (rangeIdx >= 2) {
rangeIdx -= 2
distanceContextOffset = 0
}
let insertCode: Int32 = (((Utils.rightShift(0x29850, (rangeIdx * 2))) & 3) << 3) | (Utils.rightShift(cmdCode, 3)) & 7
let copyCode: Int32 = (((Utils.rightShift(0x26244, (rangeIdx * 2))) & 3) << 3) | (cmdCode & 7)
let copyLengthOffset: Int32 = copyLengthOffsets[Int64(copyCode)]
let distanceContext: Int32 = distanceContextOffset + (if (copyLengthOffset > 4) { 3 } else { (copyLengthOffset - 2) })
let index: Int32 = cmdCode * 4
cmdLookup[Int64(index + 0)] = Int16(Int32(INSERT_LENGTH_N_BITS[Int64(insertCode)]) | (Int32(COPY_LENGTH_N_BITS[Int64(copyCode)]) << 8))
cmdLookup[Int64(index + 1)] = Int16(insertLengthOffsets[Int64(insertCode)])
cmdLookup[Int64(index + 2)] = Int16(copyLengthOffsets[Int64(copyCode)])
cmdLookup[Int64(index + 3)] = Int16(distanceContext)
}
}
/**
* Reads brotli stream header and parses "window bits".
*
* @param s initialized state, before any read is performed.
* @return -1 if header is invalid
*/
private static func decodeWindowBits(s: State): Int32 {
let largeWindowEnabled = s.isLargeWindow
s.isLargeWindow = 0
BitReader.fillBitWindow(s)
if (BitReader.readFewBits(s, 1) == 0) {
return 16
}
var n: Int32 = BitReader.readFewBits(s, 3)
if (n != 0) {
return 17 + n
}
n = BitReader.readFewBits(s, 3)
if (n != 0) {
if (n == 1) {
if (largeWindowEnabled == 0) {
return -1
}
s.isLargeWindow = 1
if (BitReader.readFewBits(s, 1) == 1) {
return -1
}
n = BitReader.readFewBits(s, 6)
if (n < MIN_LARGE_WINDOW_BITS || n > MAX_LARGE_WINDOW_BITS) {
return -1
}
return n
} else {
return 8 + n
}
}
return 17
}
static func enableEagerOutput(s: State): Unit {
if (s.runningState != INITIALIZED) {
throw Exception("State MUST be freshly initialized")
}
s.isEager = 1
}
static func enableLargeWindow(s: State): Unit {
if (s.runningState != INITIALIZED) {
throw Exception("State MUST be freshly initialized")
}
s.isLargeWindow = 1
}
static func attachDictionaryChunk(s: State, data: Array<UInt8>): Unit {
if (s.runningState != INITIALIZED) {
throw Exception("State MUST be freshly initialized")
}
if (s.cdNumChunks == 0) {
s.cdChunks = Array<Array<UInt8>>(16) { _ => Array<UInt8>(0) { _ => 0 } }
s.cdChunkOffsets = Array<Int32>(16) { _ => 0 }
s.cdBlockBits = -1
}
if (s.cdNumChunks == 15) {
throw Exception("Too many dictionary chunks")
}
s.cdChunks[Int64(s.cdNumChunks)] = data
s.cdNumChunks++
s.cdTotalSize += Int32(data.size)
s.cdChunkOffsets[Int64(s.cdNumChunks)] = s.cdTotalSize
}
static func initState(s: State): Unit {
if (s.runningState != UNINITIALIZED) {
throw Exception("State MUST be uninitialized")
}
s.blockTrees = Array<Int32>(Int64(7 + (HUFFMAN_TABLE_SIZE_258 + HUFFMAN_TABLE_SIZE_26) * 3)) { _ => 0 }
s.blockTrees[0] = 7
s.distRbIdx = 3
let maxDistanceAlphabetLimit = calculateDistanceAlphabetLimit(MAX_ALLOWED_DISTANCE, 3, 15 << 3)
s.distExtraBits = Array<UInt8>(Int64(maxDistanceAlphabetLimit)) { _ => 0 }
s.distOffset = Array<Int32>(Int64(maxDistanceAlphabetLimit)) { _ => 0 }
BitReader.initBitReader(s)
s.runningState = INITIALIZED
}
static func close(s: State): Unit {
if (s.runningState == UNINITIALIZED) {
throw Exception("State MUST be initialized")
}
if (s.runningState == CLOSED) {
return
}
s.runningState = CLOSED
Utils.closeInput(s)
}
/**
* Decodes a number in the range [0..255], by reading 1 - 11 bits.
*/
private static func decodeVarLenUnsignedByte(s: State): Int32 {
BitReader.fillBitWindow(s)
if (BitReader.readFewBits(s, 1) != 0) {
let n = BitReader.readFewBits(s, 3)
if (n == 0) {
return 1
} else {
return BitReader.readFewBits(s, n) + (1 << n)
}
}
return 0
}
private static func decodeMetaBlockLength(s: State): Unit {
BitReader.fillBitWindow(s)
s.inputEnd = BitReader.readFewBits(s, 1)
s.metaBlockLength = 0
s.isUncompressed = 0
s.isMetadata = 0
if ((s.inputEnd != 0) && BitReader.readFewBits(s, 1) != 0) {
return
}
let sizeNibbles = BitReader.readFewBits(s, 2) + 4
if (sizeNibbles == 7) {
s.isMetadata = 1
if (BitReader.readFewBits(s, 1) != 0) {
throw BrotliRuntimeException("Corrupted reserved bit")
}
let sizeBytes = BitReader.readFewBits(s, 2)
if (sizeBytes == 0) {
return
}
for (i in 0..sizeBytes) {
BitReader.fillBitWindow(s)
let bits = BitReader.readFewBits(s, 8)
if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {
throw BrotliRuntimeException("Exuberant nibble")
}
s.metaBlockLength += bits << (i * 8)
}
} else {
for (i in 0..sizeNibbles) {
BitReader.fillBitWindow(s)
let bits = BitReader.readFewBits(s, 4)
if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {
throw BrotliRuntimeException("Exuberant nibble")
}
s.metaBlockLength += bits << (i * 4)
}
}
s.metaBlockLength++
if (s.inputEnd == 0) {
s.isUncompressed = BitReader.readFewBits(s, 1)
}
}
static var asddd: Bool = true
/**
* Decodes the next Huffman code from bit-stream.
*/
private static func readSymbol(tableGroup: Array<Int32>, tableIdx: Int32, s: State): Int32 {
var offset = tableGroup[Int64(tableIdx)]
if (Int64(offset) >= tableGroup.size) {
return -1
}
let v: Int32 = Int32(BitReader.peekBits(s))
offset += Int32(v) & HUFFMAN_TABLE_MASK
let bits = tableGroup[Int64(offset)] >> 16
let sym = tableGroup[Int64(offset)] & 0xFFFF
if (bits <= HUFFMAN_TABLE_BITS) {
s.bitOffset += bits
return sym
}
offset += sym
let mask: Int32 = (1 << bits) - 1
offset += Utils.rightShift((Int32(v) & mask), HUFFMAN_TABLE_BITS)
s.bitOffset += ((tableGroup[Int64(offset)] >> 16) + HUFFMAN_TABLE_BITS)
return tableGroup[Int64(offset)] & 0xFFFF
}
private static func readBlockLength(tableGroup: Array<Int32>, tableIdx: Int32, s: State): Int32 {
BitReader.fillBitWindow(s)
let code = readSymbol(tableGroup, tableIdx, s)
let n = BLOCK_LENGTH_N_BITS[Int64(code)]
BitReader.fillBitWindow(s)
return BLOCK_LENGTH_OFFSET[Int64(code)] + BitReader.readBits(s, n)
}
private static func moveToFront(v: Array<Int32>, index: Int32): Unit {
var i = index
let value = v[Int64(i)]
while (i > 0) {
v[Int64(i)] = v[Int64(i - 1)]
i--
}
v[0] = value
}
private static func inverseMoveToFrontTransform(v: Array<UInt8>, vLen: Int32): Unit {
let mtf = Array<Int32>(Int64(256)) { _ => 0 }
for (i in 0..256) {
mtf[Int64(i)] = Int32(i)
}
for (i in 0..vLen) {
let index = Int32(v[Int64(i)]) & 0xFF
v[Int64(i)] = UInt8(mtf[Int64(index)])
if (index != 0) {
moveToFront(mtf, index)
}
}
}
private static func readHuffmanCodeLengths(codeLengthCodeLengths: Array<Int32>, numSymbols: Int32, codeLengths: Array<Int32>, s: State): Unit {
var symbol: Int32 = 0
var prevCodeLen = DEFAULT_CODE_LENGTH
var repeat: Int32 = 0
var repeatCodeLen: Int32 = 0
var space: Int32 = 32768
let table = Array<Int32>(Int64(32 + 1)) { _ => 0 }
let tableIdx = Int32(table.size) - 1
Huffman.buildHuffmanTable(table, tableIdx, 5, codeLengthCodeLengths, CODE_LENGTH_CODES)
while (symbol < numSymbols && space > 0) {
BitReader.readMoreInput(s)
BitReader.fillBitWindow(s)
let p = BitReader.peekBits(s) & 31
s.bitOffset += table[Int64(p)] >> 16
let codeLen = table[Int64(p)] & 0xFFFF
if (codeLen < CODE_LENGTH_REPEAT_CODE) {
repeat = 0
codeLengths[Int64(match (0) { case _ => symbol++; symbol - 1 })] = codeLen
if (codeLen != 0) {
prevCodeLen = codeLen
space -= 32768 >> codeLen
}
} else {
let extraBits = codeLen - 14
var newLen: Int32 = 0
if (codeLen == CODE_LENGTH_REPEAT_CODE) {
newLen = prevCodeLen
}
if (repeatCodeLen != newLen) {
repeat = 0
repeatCodeLen = newLen
}
let oldRepeat = repeat
if (repeat > 0) {
repeat -= 2
repeat = repeat << extraBits
}
BitReader.fillBitWindow(s)
repeat += BitReader.readFewBits(s, extraBits) + 3
let repeatDelta = repeat - oldRepeat
if (symbol + repeatDelta > numSymbols) {
throw BrotliRuntimeException("symbol + repeatDelta > numSymbols")
}
var i: Int32 = 0
while (i < repeatDelta) {
codeLengths[Int64(match (0) { case _ => symbol++; symbol - 1 })] = repeatCodeLen
i++
}
if (repeatCodeLen != 0) {
space -= repeatDelta << (15 - repeatCodeLen)
}
}
}
if (space != 0) {
throw BrotliRuntimeException("Unused space")
}
Utils.fillIntsWithZeroes(codeLengths, symbol, numSymbols)
}
private static func checkDupes(symbols: Array<Int32>, length: Int32): Unit {
for (i in 0..length - 1) {
for (j in i + 1..length) {
if (symbols[Int64(i)] == symbols[Int64(j)]) {
throw BrotliRuntimeException("Duplicate simple Huffman code symbol")
}
}
}
}
/**
* Reads up to 4 symbols directly and applies predefined histograms.
*/
private static func readSimpleHuffmanCode(alphabetSizeMax: Int32, alphabetSizeLimit: Int32, tableGroup: Array<Int32>, tableIdx: Int32, s: State): Int32 {
let codeLengths = Array<Int32>(Int64(alphabetSizeLimit)) { _ => 0 }
let symbols = Array<Int32>(4) { _ => 0 }
let maxBits = 1 + log2floor(alphabetSizeMax - 1)
let numSymbols = BitReader.readFewBits(s, 2) + 1
for (i in 0..numSymbols) {
BitReader.fillBitWindow(s)
let symbol = BitReader.readFewBits(s, maxBits)
if (symbol >= alphabetSizeLimit) {
throw BrotliRuntimeException("Can\'t readHuffmanCode")
}
symbols[Int64(i)] = symbol
}
checkDupes(symbols, numSymbols)
var histogramId = numSymbols
if (numSymbols == 4) {
histogramId += BitReader.readFewBits(s, 1)
}
match (histogramId) {
case 1 => codeLengths[Int64(symbols[0])] = 1
case 2 => codeLengths[Int64(symbols[0])] = 1
codeLengths[Int64(symbols[1])] = 1
case 3 => codeLengths[Int64(symbols[0])] = 1
codeLengths[Int64(symbols[1])] = 2
codeLengths[Int64(symbols[2])] = 2
case 4 =>
codeLengths[Int64(symbols[0])] = 2
codeLengths[Int64(symbols[1])] = 2
codeLengths[Int64(symbols[2])] = 2
codeLengths[Int64(symbols[3])] = 2
case 5 =>
codeLengths[Int64(symbols[0])] = 1
codeLengths[Int64(symbols[1])] = 2
codeLengths[Int64(symbols[2])] = 3
codeLengths[Int64(symbols[3])] = 3
case _ => ()
}
return Huffman.buildHuffmanTable(tableGroup, tableIdx, HUFFMAN_TABLE_BITS, codeLengths, alphabetSizeLimit)
}
/**
* Decode Huffman-coded code lengths.
*
* @return number of slots used by resulting Huffman table
*/
private static func readComplexHuffmanCode(alphabetSizeLimit: Int32, skip: Int32, tableGroup: Array<Int32>, tableIdx: Int32, s: State): Int32 {
let codeLengths = Array<Int32>(Int64(alphabetSizeLimit)) { _ => 0 }
let codeLengthCodeLengths = Array<Int32>(Int64(CODE_LENGTH_CODES)) { _ => 0 }
var space = 32
var numCodes = 0
var i = skip
while (i < CODE_LENGTH_CODES) {
let codeLenIdx = CODE_LENGTH_CODE_ORDER[Int64(i)]
BitReader.fillBitWindow(s)
let p = BitReader.peekBits(s) & 15
s.bitOffset += FIXED_TABLE[Int64(p)] >> 16
let v = FIXED_TABLE[Int64(p)] & 0xFFFF
codeLengthCodeLengths[Int64(codeLenIdx)] = v
if (v != 0) {
space -= (32 >> v)
numCodes++
if (space <= 0) {
break
}
}
i++
}
if (space != 0 && numCodes != 1) {
throw BrotliRuntimeException("Corrupted Huffman code histogram")
}
readHuffmanCodeLengths(codeLengthCodeLengths, alphabetSizeLimit, codeLengths, s)
return Huffman.buildHuffmanTable(tableGroup, tableIdx, HUFFMAN_TABLE_BITS, codeLengths, alphabetSizeLimit)
}
private static func readHuffmanCode(alphabetSizeMax: Int32, alphabetSizeLimit: Int32, tableGroup: Array<Int32>, tableIdx: Int32, s: State): Int32 {
BitReader.readMoreInput(s)
BitReader.fillBitWindow(s)
let simpleCodeOrSkip = BitReader.readFewBits(s, 2)
if (simpleCodeOrSkip == 1) {
return readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s)
} else {
return readComplexHuffmanCode(alphabetSizeLimit, simpleCodeOrSkip, tableGroup, tableIdx, s)
}
}
private static func decodeContextMap(contextMapSize: Int32, contextMap: Array<UInt8>, s: State): Int32 {
BitReader.readMoreInput(s)
let numTrees = decodeVarLenUnsignedByte(s) + 1
if (numTrees == 1) {
Utils.fillBytesWithZeroes(contextMap, 0, contextMapSize)
return numTrees
}
BitReader.fillBitWindow(s)
let useRleForZeros = BitReader.readFewBits(s, 1)
var maxRunLengthPrefix: Int32 = 0
if (useRleForZeros != 0) {
maxRunLengthPrefix = BitReader.readFewBits(s, 4) + 1
}
let alphabetSize = numTrees + maxRunLengthPrefix
let tableSize = MAX_HUFFMAN_TABLE_SIZE[Int64((alphabetSize + 31) >> 5)]
let table = Array<Int32>(Int64(tableSize + 1)) { _ => 0 }
let tableIdx: Int32 = Int32(table.size) - 1
readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s)
var i: Int32 = 0
while (i < contextMapSize) {
BitReader.readMoreInput(s)
BitReader.fillBitWindow(s)
let code = readSymbol(table, tableIdx, s)
if (code == 0) {
contextMap[Int64(i)] = 0
i++
} else {
if (code <= maxRunLengthPrefix) {
BitReader.fillBitWindow(s)
var reps = (1 << code) + BitReader.readFewBits(s, code)
while (reps != 0) {
if (i >= contextMapSize) {
throw BrotliRuntimeException("Corrupted context map")
}
contextMap[Int64(i)] = 0
i++
reps--
}
} else {
contextMap[Int64(i)] = UInt8(code - maxRunLengthPrefix)
i++
}
}
}
BitReader.fillBitWindow(s)
if (BitReader.readFewBits(s, 1) == 1) {
inverseMoveToFrontTransform(contextMap, contextMapSize)
}
return numTrees
}
private static func decodeBlockTypeAndLength(s: State, treeType: Int32, numBlockTypes: Int32): Int32 {
let ringBuffers: Array<Int32> = s.rings
let offset = 4 + treeType * 2
BitReader.fillBitWindow(s)
var blockType = BitReader.readFewBits(s, 2)
let result = readBlockLength(s.blockTrees, 2 * treeType + 1, s)
if (blockType == 1) {
blockType = ringBuffers[Int64(offset + 1)] + 1
} else {
if (blockType == 0) {
blockType = ringBuffers[Int64(offset)]
} else {
blockType -= 2
}
}
if (blockType >= numBlockTypes) {
blockType -= numBlockTypes
}
ringBuffers[Int64(offset)] = ringBuffers[Int64(offset + 1)]
ringBuffers[Int64(offset + 1)] = blockType
return result
}
private static func decodeLiteralBlockSwitch(s: State): Unit {
s.literalBlockLength = decodeBlockTypeAndLength(s, 0, s.numLiteralBlockTypes)
let literalBlockType = s.rings[5]
s.contextMapSlice = literalBlockType << LITERAL_CONTEXT_BITS
s.literalTreeIdx = Int32(s.contextMap[Int64(s.contextMapSlice)]) & 0xFF
let contextMode = Int32(s.contextModes[Int64(literalBlockType)])
s.contextLookupOffset1 = contextMode << 9
s.contextLookupOffset2 = s.contextLookupOffset1 + 256
}
private static func decodeCommandBlockSwitch(s: State): Unit {
s.commandBlockLength = decodeBlockTypeAndLength(s, 1, s.numCommandBlockTypes)
s.commandTreeIdx = s.rings[Int64(7)]
}
private static func decodeDistanceBlockSwitch(s: State): Unit {
s.distanceBlockLength = decodeBlockTypeAndLength(s, 2, s.numDistanceBlockTypes)
s.distContextMapSlice = s.rings[Int64(9)] << DISTANCE_CONTEXT_BITS
}
private static func maybeReallocateRingBuffer(s: State): Unit {
var newSize = s.maxRingBufferSize
if (newSize > s.expectedTotalSize) {
let minimalNewSize = s.expectedTotalSize
while ((newSize >> 1) > minimalNewSize) {
newSize = newSize >> 1
}
if ((s.inputEnd == 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) {
newSize = 16384
}
}
if (newSize <= s.ringBufferSize) {
return
}
let ringBufferSizeWithSlack = newSize + MAX_TRANSFORMED_WORD_LENGTH
let newBuffer = Array<UInt8>(Int64(ringBufferSizeWithSlack)) { _ => 0 }
let oldBuffer = s.ringBuffer
if (Int64(oldBuffer.size) != 0) {
oldBuffer.copyTo(newBuffer, 0, 0, Int64(s.ringBufferSize))
}
s.ringBuffer = newBuffer
s.ringBufferSize = newSize
}
private static func readNextMetablockHeader(s: State): Unit {
if (s.inputEnd != 0) {
s.nextRunningState = FINISHED
s.runningState = INIT_WRITE
return
}
s.literalTreeGroup = Array<Int32>(0) { _ => 0 }
s.commandTreeGroup = Array<Int32>(0) { _ => 0 }
s.distanceTreeGroup = Array<Int32>(0) { _ => 0 }
BitReader.readMoreInput(s)
decodeMetaBlockLength(s)
if ((s.metaBlockLength == 0) && (s.isMetadata == 0)) {
return
}
if ((s.isUncompressed != 0) || (s.isMetadata != 0)) {
BitReader.jumpToByteBoundary(s)
s.runningState = if (s.isMetadata != 0) { READ_METADATA } else { COPY_UNCOMPRESSED }
} else {
s.runningState = COMPRESSED_BLOCK_START
}
if (s.isMetadata != 0) {
return
}
s.expectedTotalSize += s.metaBlockLength
if (s.expectedTotalSize > 1 << 30) {
s.expectedTotalSize = 1 << 30
}
if (s.ringBufferSize < s.maxRingBufferSize) {
maybeReallocateRingBuffer(s)
}
}
private static func readMetablockPartition(s: State, treeType: Int32, numBlockTypes: Int32): Int32 {
var offset = s.blockTrees[Int64(2 * treeType)]
if (numBlockTypes <= 1) {
s.blockTrees[Int64(2 * treeType + 1)] = offset
s.blockTrees[Int64(2 * treeType + 2)] = offset
return 1 << 28
}
let blockTypeAlphabetSize = numBlockTypes + 2
offset += readHuffmanCode(blockTypeAlphabetSize, blockTypeAlphabetSize, s.blockTrees, 2 * treeType, s)
s.blockTrees[Int64(2 * treeType + 1)] = offset
let blockLengthAlphabetSize = NUM_BLOCK_LENGTH_CODES
offset += readHuffmanCode(blockLengthAlphabetSize, blockLengthAlphabetSize, s.blockTrees, 2 * treeType + 1, s)
s.blockTrees[Int64(2 * treeType + 2)] = offset
return readBlockLength(s.blockTrees, 2 * treeType + 1, s)
}
private static func calculateDistanceLut(s: State, alphabetSizeLimit: Int32): Unit {
let distExtraBits = s.distExtraBits
let distOffset = s.distOffset
let npostfix = s.distancePostfixBits
let ndirect = s.numDirectDistanceCodes
let postfix: Int32 = 1 << npostfix
var bits: Int32 = 1
var half: Int32 = 0
var i = NUM_DISTANCE_SHORT_CODES
for (j in 0..ndirect) {
distExtraBits[Int64(i)] = 0
distOffset[Int64(i)] = j + 1
i++
}
while (i < alphabetSizeLimit) {
let base: Int32 = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1
for (j in 0..postfix) {
distExtraBits[Int64(i)] = UInt8(bits)
distOffset[Int64(i)] = base + j
i++
}
bits = bits + half
half = half ^ 1
}
}
static func readMetablockHuffmanCodesAndContextMaps(s: State): Unit {
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)
BitReader.readMoreInput(s)
BitReader.fillBitWindow(s)
s.distancePostfixBits = BitReader.readFewBits(s, 2)
s.numDirectDistanceCodes = BitReader.readFewBits(s, 4) << s.distancePostfixBits
s.contextModes = Array<UInt8>(Int64(s.numLiteralBlockTypes)) { _ => 0 }
var i: Int32 = 0
while (i < s.numLiteralBlockTypes) {
let limit = min(i + 96, s.numLiteralBlockTypes)
while (i < limit) {
BitReader.fillBitWindow(s)
s.contextModes[Int64(i)] = UInt8(BitReader.readFewBits(s, 2))
i++
}
BitReader.readMoreInput(s)
}
let contextMapLength: Int32 = s.numLiteralBlockTypes << LITERAL_CONTEXT_BITS
s.contextMap = Array<UInt8>(Int64(contextMapLength)) { _ => 0 }
let numLiteralTrees: Int32 = decodeContextMap(contextMapLength, s.contextMap, s)
s.trivialLiteralContext = 1
for (j in 0..contextMapLength) {
if (Int32(s.contextMap[Int64(j)]) != j >> LITERAL_CONTEXT_BITS) {
s.trivialLiteralContext = 0
break
}
}
var num: Int32 = s.numDistanceBlockTypes << DISTANCE_CONTEXT_BITS
s.distContextMap = Array<UInt8>(Int64(num)) { _ => 0 }
let numDistTrees: Int32 = decodeContextMap(num, s.distContextMap, s)
s.literalTreeGroup = decodeHuffmanTreeGroup(NUM_LITERAL_CODES, NUM_LITERAL_CODES, numLiteralTrees, s)
s.commandTreeGroup = decodeHuffmanTreeGroup(NUM_COMMAND_CODES, NUM_COMMAND_CODES, s.numCommandBlockTypes, s)
sdadas++
var distanceAlphabetSizeMax: Int32 = calculateDistanceAlphabetSize(s.distancePostfixBits, s.numDirectDistanceCodes, MAX_DISTANCE_BITS)
var distanceAlphabetSizeLimit: Int32 = distanceAlphabetSizeMax
if (s.isLargeWindow == 1) {
distanceAlphabetSizeMax = calculateDistanceAlphabetSize(s.distancePostfixBits, s.numDirectDistanceCodes, MAX_LARGE_WINDOW_DISTANCE_BITS)
distanceAlphabetSizeLimit = calculateDistanceAlphabetLimit(MAX_ALLOWED_DISTANCE, s.distancePostfixBits, s.numDirectDistanceCodes)
}
s.distanceTreeGroup = decodeHuffmanTreeGroup(distanceAlphabetSizeMax, distanceAlphabetSizeLimit, numDistTrees, s)
calculateDistanceLut(s, distanceAlphabetSizeLimit)
s.contextMapSlice = 0
s.distContextMapSlice = 0
s.contextLookupOffset1 = Int32(s.contextModes[0]) * 512
s.contextLookupOffset2 = s.contextLookupOffset1 + 256
s.literalTreeIdx = 0
s.commandTreeIdx = 0
s.rings[4] = 1
s.rings[5] = 0
s.rings[6] = 1
s.rings[7] = 0
s.rings[8] = 1
s.rings[9] = 0
}
private static func copyUncompressedData(s: State): Unit {
let ringBuffer = s.ringBuffer
if (s.metaBlockLength <= 0) {
BitReader.reload(s)
s.runningState = BLOCK_START
return
}
let chunkLength = min(s.ringBufferSize - s.pos, s.metaBlockLength)
BitReader.copyRawBytes(s, ringBuffer, s.pos, chunkLength)
s.metaBlockLength -= chunkLength
s.pos += chunkLength
if (s.pos == s.ringBufferSize) {
s.nextRunningState = COPY_UNCOMPRESSED
s.runningState = INIT_WRITE
return
}
BitReader.reload(s)
s.runningState = BLOCK_START
}
private static func writeRingBuffer(s: State): Int32 {
let toWrite = min(s.outputLength - s.outputUsed, s.ringBufferBytesReady - s.ringBufferBytesWritten)
if (toWrite != 0) {
s.ringBuffer.copyTo( s.output, Int64(s.ringBufferBytesWritten), Int64(s.outputOffset + s.outputUsed), Int64(toWrite))
s.outputUsed += toWrite
s.ringBufferBytesWritten += toWrite
}
if (s.outputUsed < s.outputLength) {
return 1
} else {
return 0
}
}
private static func decodeHuffmanTreeGroup(alphabetSizeMax: Int32, alphabetSizeLimit: Int32, n: Int32, s: State): Array<Int32> {
let maxTableSize = MAX_HUFFMAN_TABLE_SIZE[Int64((alphabetSizeLimit + 31) >> 5)]
let group = Array<Int32>(Int64(n + n * maxTableSize)) { _ => 0 }
var next: Int32 = n
for (i in 0..n) {
group[Int64(i)] = next
next += readHuffmanCode(alphabetSizeMax, alphabetSizeLimit, group, i, s)
}
return group
}
private static func calculateFence(s: State): Int32 {
var result = s.ringBufferSize
if (s.isEager != 0) {
result = min(result, s.ringBufferBytesWritten + s.outputLength - s.outputUsed)
}
return result
}
private static func doUseDictionary(s: State, fence: Int32): Unit {
if (s.distance > MAX_ALLOWED_DISTANCE) {
throw BrotliRuntimeException("Invalid backward reference")
}
let address: Int32 = s.distance - s.maxDistance - 1 - s.cdTotalSize
if (address < 0) {
initializeCompoundDictionaryCopy(s, -address - 1, s.copyLength)
s.runningState = COPY_FROM_COMPOUND_DICTIONARY
} else {
let dictionaryData = Dictionary.getData()
let wordLength: Int32 = s.copyLength
if (wordLength > Dictionary.MAX_DICTIONARY_WORD_LENGTH) {
throw BrotliRuntimeException("Invalid backward reference")
}
let shift: Int32 = Dictionary.sizeBits[Int64(wordLength)]
if (shift == 0) {
throw BrotliRuntimeException("Invalid backward reference")
}
var offset: Int32 = Dictionary.offsets[Int64(wordLength)]
let mask: Int32 = (1 << shift) - 1
let wordIdx: Int32 = address & mask
let transformIdx: Int32 = Utils.rightShift(address, shift)
offset += wordIdx * wordLength
let transforms = Transform.RFC_TRANSFORMS
if (transformIdx >= transforms.numTransforms) {
throw BrotliRuntimeException("Invalid backward reference")
}
let len = Transform.transformDictionaryWord(s.ringBuffer, s.pos, dictionaryData, offset, wordLength, transforms, transformIdx)
s.pos += len
s.metaBlockLength -= len
if (s.pos >= fence) {
s.nextRunningState = MAIN_LOOP
s.runningState = INIT_WRITE
return
}
s.runningState = MAIN_LOOP
}
}
private static func initializeCompoundDictionary(s: State): Unit {
s.cdBlockMap = Array<UInt8>(Int64(1 << CD_BLOCK_MAP_BITS)) { _ => 0 }
var blockBits = CD_BLOCK_MAP_BITS
while (Utils.rightShift((s.cdTotalSize - 1), blockBits) != 0) {
blockBits++
}
blockBits -= CD_BLOCK_MAP_BITS
s.cdBlockBits = blockBits
var cursor: Int32 = 0
var index: Int32 = 0
while (cursor < s.cdTotalSize) {
while (s.cdChunkOffsets[Int64(index + 1)] < cursor) {
index++
}
s.cdBlockMap[Int64(Utils.rightShift(cursor, blockBits))] = UInt8(index)
cursor += 1 << blockBits
}
}
private static func initializeCompoundDictionaryCopy(s: State, address: Int32, length: Int32): Unit {
if (s.cdBlockBits == -1) {
initializeCompoundDictionary(s)
}
var index = Int32(s.cdBlockMap[Int64(Utils.rightShift(address, s.cdBlockBits))])
while (address >= s.cdChunkOffsets[Int64(index + 1)]) {
index++
}
if (s.cdTotalSize > address + length) {
throw BrotliRuntimeException("Invalid backward reference")
}
s.distRbIdx = (s.distRbIdx + 1) & 0x3
s.rings[Int64(s.distRbIdx)] = s.distance
s.metaBlockLength -= length
s.cdBrIndex = index
s.cdBrOffset = address - s.cdChunkOffsets[Int64(index)]
s.cdBrLength = length
s.cdBrCopied = 0
}
private static func copyFromCompoundDictionary(s: State, fence: Int32): Int32 {
var pos = s.pos
let origPos = pos
while (s.cdBrLength != s.cdBrCopied) {
let space = fence - pos
let chunkLength = s.cdChunkOffsets[Int64(s.cdBrIndex + 1)] - s.cdChunkOffsets[Int64(s.cdBrIndex)]
let remChunkLength = chunkLength - s.cdBrOffset
var length = s.cdBrLength - s.cdBrCopied
if (length > remChunkLength) {
length = remChunkLength
}
if (length > space) {
length = space
}
Utils.copyBytes(s.ringBuffer, pos, s.cdChunks[Int64(s.cdBrIndex)], s.cdBrOffset, s.cdBrOffset + length)
pos += length
s.cdBrOffset += length
s.cdBrCopied += length
if (length == remChunkLength) {
s.cdBrIndex++
s.cdBrOffset = 0
}
if (pos >= fence) {
break
}
}
return pos - origPos
}
static var sda: Bool = true
static var sdadas: Int64 = 0
static var sdaddd: Bool = true
static var sdaddsd: Bool = true
static func decompress(s: State): Unit {
if (s.runningState == UNINITIALIZED) {
throw Exception("Can\'t decompress until initialized")
}
if (s.runningState == CLOSED) {
throw Exception("Can\'t decompress after close")
}
if (s.runningState == INITIALIZED) {
let windowBits = decodeWindowBits(s)
if (windowBits == -1) {
throw BrotliRuntimeException("Invalid \'windowBits\' code")
}
s.maxRingBufferSize = 1 << windowBits
s.maxBackwardDistance = s.maxRingBufferSize - 16
s.runningState = BLOCK_START
}
var fence = calculateFence(s)
var ringBufferMask = s.ringBufferSize - 1
var ringBuffer = s.ringBuffer
while (s.runningState != FINISHED) {
match (s.runningState) {
case 2 =>
if (s.metaBlockLength < 0) {
throw BrotliRuntimeException("Invalid metablock length")
}
readNextMetablockHeader(s)
fence = calculateFence(s)
ringBufferMask = s.ringBufferSize - 1
ringBuffer = s.ringBuffer
continue
case 3 =>
readMetablockHuffmanCodesAndContextMaps(s)
s.runningState = MAIN_LOOP
case 4 =>
if (s.metaBlockLength <= 0) {
s.runningState = BLOCK_START
continue
}
BitReader.readMoreInput(s)
if (s.commandBlockLength == 0) {
decodeCommandBlockSwitch(s)
}
s.commandBlockLength--
BitReader.fillBitWindow(s)
let cmdCode = readSymbol(s.commandTreeGroup, s.commandTreeIdx, s) << 2
let insertAndCopyExtraBits = Int32(CMD_LOOKUP[Int64(cmdCode)])
let insertLengthOffset = Int32(CMD_LOOKUP[Int64(cmdCode + 1)])
let copyLengthOffset = Int32(CMD_LOOKUP[Int64(cmdCode + 2)])
s.distanceCode = Int32(CMD_LOOKUP[Int64(cmdCode + 3)])
BitReader.fillBitWindow(s)
let insertLengthExtraBits = insertAndCopyExtraBits & 0xFF
s.insertLength = insertLengthOffset + Int32(BitReader.readBits(s, insertLengthExtraBits))
BitReader.fillBitWindow(s)
do {
let copyLengthExtraBits = insertAndCopyExtraBits >> 8
s.copyLength = copyLengthOffset + Int32(BitReader.readBits(s, copyLengthExtraBits))
} while (false)
s.j = 0
s.runningState = INSERT_LOOP
case 7 =>
if (s.trivialLiteralContext != 0) {
while (s.j < s.insertLength) {
BitReader.readMoreInput(s)
if (s.literalBlockLength == 0) {
decodeLiteralBlockSwitch(s)
}
s.literalBlockLength--
BitReader.fillBitWindow(s)
ringBuffer[Int64(s.pos)] = UInt8(readSymbol(s.literalTreeGroup, s.literalTreeIdx, s))
s.pos++
s.j++
if (s.pos >= fence) {
s.nextRunningState = INSERT_LOOP
s.runningState = INIT_WRITE
break
}
}
} else {
var prevByte1 = Int32(ringBuffer[Int64((s.pos - 1) & ringBufferMask)] & 0xFF)
var prevByte2 = Int32(ringBuffer[Int64((s.pos - 2) & ringBufferMask)] & 0xFF)
while (s.j < s.insertLength) {
BitReader.readMoreInput(s)
if (s.literalBlockLength == 0) {
decodeLiteralBlockSwitch(s)
}
let literalContext: Int32 = Context.LOOKUP[Int64(s.contextLookupOffset1 + prevByte1)] | Context.LOOKUP[Int64(s.contextLookupOffset2 + prevByte2)]
let literalTreeIdx: Int32 = Int32(s.contextMap[Int64(s.contextMapSlice + literalContext)]) & 0xFF
s.literalBlockLength--
prevByte2 = prevByte1
BitReader.fillBitWindow(s)
prevByte1 = Int32(readSymbol(s.literalTreeGroup, literalTreeIdx, s))
ringBuffer[Int64(s.pos)] = UInt8(prevByte1)
s.pos++
s.j++
if (s.pos >= fence) {
s.nextRunningState = INSERT_LOOP
s.runningState = INIT_WRITE
break
}
}
}
if (s.runningState != INSERT_LOOP) {
continue
}
s.metaBlockLength -= s.insertLength
if (s.metaBlockLength <= 0) {
s.runningState = MAIN_LOOP
continue
}
var distanceCode = s.distanceCode
if (distanceCode < 0) {
s.distance = Int32(s.rings[Int64(s.distRbIdx)])
} else {
BitReader.readMoreInput(s)
if (s.distanceBlockLength == 0) {
decodeDistanceBlockSwitch(s)
}
s.distanceBlockLength--
BitReader.fillBitWindow(s)
let distTreeIdx = Int32(s.distContextMap[Int64(s.distContextMapSlice + distanceCode)]) & 0xFF
distanceCode = Int32(readSymbol(s.distanceTreeGroup, distTreeIdx, s))
if (distanceCode < NUM_DISTANCE_SHORT_CODES) {
let index = (s.distRbIdx + Int32(DISTANCE_SHORT_CODE_INDEX_OFFSET[Int64(distanceCode)])) & 0x3
s.distance = s.rings[Int64(index)] + Int32(DISTANCE_SHORT_CODE_VALUE_OFFSET[Int64(distanceCode)])
if (s.distance < 0) {
throw BrotliRuntimeException("Negative distance")
}
} else {
let extraBits = Int32(s.distExtraBits[Int64(distanceCode)])
var bits: Int32 = 0
if (s.bitOffset + extraBits <= BitReader.BITNESS) {
bits = BitReader.readFewBits(s, extraBits)
} else {
BitReader.fillBitWindow(s)
bits = BitReader.readBits(s, extraBits)
}
s.distance = s.distOffset[Int64(distanceCode)] + (bits << s.distancePostfixBits)
}
}
if (s.maxDistance != s.maxBackwardDistance && s.pos < s.maxBackwardDistance) {
s.maxDistance = s.pos
} else {
s.maxDistance = s.maxBackwardDistance
}
if (s.distance > s.maxDistance) {
s.runningState = USE_DICTIONARY
continue
}
if (distanceCode > 0) {
s.distRbIdx = (s.distRbIdx + 1) & 0x3
s.rings[Int64(s.distRbIdx)] = s.distance
}
if (s.copyLength > s.metaBlockLength) {
throw BrotliRuntimeException("Invalid backward reference")
}
s.j = 0
s.runningState = COPY_LOOP
case 8 =>
var src = (s.pos - s.distance) & ringBufferMask
var dst = s.pos
let copyLength = s.copyLength - s.j
let srcEnd = src + copyLength
let dstEnd = dst + copyLength
if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) {
if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) {
let numQuads = (copyLength + 3) >> 2
for (k in 0..numQuads) {
ringBuffer[Int64(match (0) { case _ => dst++; dst - 1 })] = ringBuffer[Int64(match (0) { case _ => src++; src - 1 })]
ringBuffer[Int64(match (0) { case _ => dst++; dst - 1 })] = ringBuffer[Int64(match (0) { case _ => src++; src - 1 })]
ringBuffer[Int64(match (0) { case _ => dst++; dst - 1 })] = ringBuffer[Int64(match (0) { case _ => src++; src - 1 })]
ringBuffer[Int64(match (0) { case _ => dst++; dst - 1 })] = ringBuffer[Int64(match (0) { case _ => src++; src - 1 })]
}
} else {
Utils.copyBytesWithin(ringBuffer, dst, src, srcEnd)
}
s.j += copyLength
s.metaBlockLength -= copyLength
s.pos += copyLength
} else {
while (s.j < s.copyLength) {
ringBuffer[Int64(s.pos)] = ringBuffer[Int64((s.pos - s.distance) & ringBufferMask)]
s.metaBlockLength--
s.pos++
s.j++
if (s.pos >= fence) {
s.nextRunningState = COPY_LOOP
s.runningState = INIT_WRITE
return
}
}
}
if (s.runningState == COPY_LOOP) {
s.runningState = MAIN_LOOP
}
continue
case 9 =>
doUseDictionary(s, fence)
continue
case 14 =>
s.pos += copyFromCompoundDictionary(s, fence)
if (s.pos >= fence) {
s.nextRunningState = COPY_FROM_COMPOUND_DICTIONARY
s.runningState = INIT_WRITE
return
}
s.runningState = MAIN_LOOP
continue
case 5 =>
while (s.metaBlockLength > 0) {
BitReader.readMoreInput(s)
BitReader.fillBitWindow(s)
BitReader.readFewBits(s, 8)
s.metaBlockLength--
}
s.runningState = BLOCK_START
continue
case 6 =>
copyUncompressedData(s)
continue
case 12 =>
s.ringBufferBytesReady = min(s.pos, s.ringBufferSize)
s.runningState = 13
case 13 =>
if (writeRingBuffer(s) == 0) {
// Output buffer is full.
return
}
if (s.pos >= s.maxBackwardDistance) {
s.maxDistance = s.maxBackwardDistance;
}
// Wrap the ringBuffer.
if (s.pos >= s.ringBufferSize) {
if (s.pos > s.ringBufferSize) {
Utils.copyBytesWithin(ringBuffer, 0, s.ringBufferSize, s.pos);
}
s.pos = s.pos & ringBufferMask;
s.ringBufferBytesWritten = 0;
}
s.runningState = s.nextRunningState;
continue
case _ =>
throw BrotliRuntimeException("Unexpected state " + s.runningState.toString())
}
}
if (s.runningState == FINISHED) {
if (s.metaBlockLength < 0) {
throw BrotliRuntimeException("Invalid metablock length")
}
BitReader.jumpToByteBoundary(s)
BitReader.checkHealth(s, 1)
}
}
}