update brotli decoder with latest improvements

This commit is contained in:
Lode Vandevenne 2015-08-28 15:20:24 +02:00
parent 5da4f65c43
commit db71549ac5
9 changed files with 1484 additions and 1432 deletions

View File

@ -32,8 +32,7 @@ void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input) {
br->bit_pos_ = 0;
br->avail_in = 0;
br->eos_ = 0;
br->tmp_bytes_read_ = 0;
br->next_in = NULL;
br->next_in = br->buf_;
}

View File

@ -29,7 +29,8 @@ extern "C" {
#define BROTLI_MAX_NUM_BIT_READ 25
#define BROTLI_READ_SIZE 1024
#define BROTLI_IBUF_SIZE (BROTLI_READ_SIZE + 128)
#define BROTLI_IMPLICIT_ZEROES 128
#define BROTLI_IBUF_SIZE (BROTLI_READ_SIZE + BROTLI_IMPLICIT_ZEROES)
#define BROTLI_IBUF_MASK (BROTLI_READ_SIZE - 1)
/* Masking with this expression turns to a single "Unsigned Bit Field Extract"
@ -48,9 +49,6 @@ typedef struct {
int eos_; /* input stream is finished */
BrotliInput input_; /* input callback */
/* indicates how much bytes already read when reading partial data */
int tmp_bytes_read_;
/* Input byte buffer, consist of a ringbuffer and a "slack" region where */
/* bytes from the start of the ringbuffer are copied. */
uint8_t buf_[BROTLI_IBUF_SIZE];
@ -73,8 +71,8 @@ void BrotliWarmupBitReader(BrotliBitReader* const br);
when more data is available makes it continue including the partially read
data
If finish is true and the end of the stream is reached, 128 additional zero
bytes are copied to the ringbuffer.
If finish is true and the end of the stream is reached,
BROTLI_IMPLICIT_ZEROES additional zero bytes are copied to the ringbuffer.
*/
static BROTLI_INLINE int BrotliReadInput(
BrotliBitReader* const br, int finish) {
@ -83,35 +81,27 @@ static BROTLI_INLINE int BrotliReadInput(
} else {
size_t i;
int bytes_read;
uint8_t* dst = br->buf_;
if (br->next_in != br->buf_) {
int num = (int)(br->avail_in);
for (i = 0; i < num; i++) {
for (i = 0; i < br->avail_in; i++) {
br->buf_[i] = br->next_in[i];
}
br->next_in = br->buf_;
br->tmp_bytes_read_ = num;
}
bytes_read = BrotliRead(br->input_, dst + br->tmp_bytes_read_,
(size_t) (BROTLI_READ_SIZE - br->tmp_bytes_read_));
bytes_read = BrotliRead(br->input_, br->next_in + br->avail_in,
(size_t)(BROTLI_READ_SIZE - br->avail_in));
if (bytes_read < 0) {
return 0;
}
bytes_read += br->tmp_bytes_read_;
br->tmp_bytes_read_ = 0;
if (bytes_read < BROTLI_READ_SIZE) {
br->avail_in += (uint32_t)bytes_read;
if (br->avail_in < BROTLI_READ_SIZE) {
if (!finish) {
br->tmp_bytes_read_ = bytes_read;
return 0;
}
br->eos_ = 1;
/* Store 128 bytes of zero after the stream end. */
memset(dst + bytes_read, 0, 128);
bytes_read += 128;
/* Store BROTLI_IMPLICIT_ZEROES bytes of zero after the stream end. */
memset(br->next_in + br->avail_in, 0, BROTLI_IMPLICIT_ZEROES);
br->avail_in += BROTLI_IMPLICIT_ZEROES;
}
br->avail_in = (uint32_t)bytes_read;
br->next_in = br->buf_;
return 1;
}
}
@ -123,7 +113,8 @@ static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
}
/* Checks if there is at least num bytes left in the input ringbuffer (excluding
the bits remaining in br->val_). The maximum value for num is 128 bytes. */
the bits remaining in br->val_). The maximum value for num is
BROTLI_IMPLICIT_ZEROES bytes. */
static BROTLI_INLINE int BrotliCheckInputAmount(
BrotliBitReader* const br, size_t num) {
return br->avail_in >= num;
@ -134,28 +125,56 @@ static BROTLI_INLINE int BrotliCheckInputAmount(
static BROTLI_INLINE void BrotliFillBitWindow(
BrotliBitReader* const br, int n_bits) {
#if (BROTLI_64_BITS_LITTLE_ENDIAN)
if (br->bit_pos_ >= 32) {
br->val_ >>= 32;
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
br->val_ |= ((uint64_t)(*(const uint32_t*)(br->next_in))) << 32;
br->avail_in -= 4;
br->next_in += 4;
if (IS_CONSTANT(n_bits) && n_bits <= 8) {
if (br->bit_pos_ >= 56) {
br->val_ >>= 56;
br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
br->val_ |= (*(const uint64_t*)(br->next_in)) << 8;
br->avail_in -= 7;
br->next_in += 7;
}
} else if (IS_CONSTANT(n_bits) && n_bits <= 16) {
if (br->bit_pos_ >= 48) {
br->val_ >>= 48;
br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
br->val_ |= (*(const uint64_t*)(br->next_in)) << 16;
br->avail_in -= 6;
br->next_in += 6;
}
} else {
if (br->bit_pos_ >= 32) {
br->val_ >>= 32;
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
br->val_ |= ((uint64_t)(*(const uint32_t*)(br->next_in))) << 32;
br->avail_in -= 4;
br->next_in += 4;
}
}
#elif (BROTLI_LITTLE_ENDIAN)
if (br->bit_pos_ >= 16) {
br->val_ >>= 16;
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
br->val_ |= ((uint32_t)(*(const uint16_t*)(br->next_in))) << 16;
br->avail_in -= 2;
br->next_in += 2;
}
if (!IS_CONSTANT(n_bits) || (n_bits > 16)) {
if (br->bit_pos_ >= 8) {
br->val_ >>= 8;
br->bit_pos_ ^= 8; /* here same as -= 8 because of the if condition */
br->val_ |= ((uint32_t)*br->next_in) << 24;
--br->avail_in;
++br->next_in;
if (IS_CONSTANT(n_bits) && n_bits <= 8) {
if (br->bit_pos_ >= 24) {
br->val_ >>= 24;
br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
br->val_ |= (*(const uint32_t*)(br->next_in)) << 8;
br->avail_in -= 3;
br->next_in += 3;
}
} else {
if (br->bit_pos_ >= 16) {
br->val_ >>= 16;
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
br->val_ |= ((uint32_t)(*(const uint16_t*)(br->next_in))) << 16;
br->avail_in -= 2;
br->next_in += 2;
}
if (!IS_CONSTANT(n_bits) || (n_bits > 16)) {
if (br->bit_pos_ >= 8) {
br->val_ >>= 8;
br->bit_pos_ ^= 8; /* here same as -= 8 because of the if condition */
br->val_ |= ((uint32_t)*br->next_in) << 24;
--br->avail_in;
++br->next_in;
}
}
}
#else

File diff suppressed because it is too large Load Diff

View File

@ -25,19 +25,18 @@
extern "C" {
#endif
#define MAX_LENGTH 15
/* For current format this constant equals to kNumInsertAndCopyCodes */
#define MAX_CODE_LENGTHS_SIZE 704
/* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the
bit-wise reversal of the len least significant bits of key. */
static BROTLI_INLINE int GetNextKey(int key, int len) {
int step = 1 << (len - 1);
static BROTLI_INLINE uint32_t GetNextKey(uint32_t key, int len) {
#ifdef BROTLI_RBIT
return BROTLI_RBIT(BROTLI_RBIT(key) + (1 << (8 * sizeof(unsigned) - len)));
#else
unsigned step = (unsigned)(1 << (len - 1));
while (key & step) {
step >>= 1;
}
return (key & (step - 1)) + step;
#endif
}
/* Stores code in table[0], table[step], table[2*step], ..., table[end] */
@ -57,7 +56,7 @@ static BROTLI_INLINE void ReplicateValue(HuffmanCode* table,
static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
int len, int root_bits) {
int left = 1 << (len - root_bits);
while (len < MAX_LENGTH) {
while (len < BROTLI_HUFFMAN_MAX_CODE_LENGTH) {
left -= count[len];
if (left <= 0) break;
++len;
@ -66,66 +65,95 @@ static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
return len - root_bits;
}
void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
const uint8_t* const code_lengths,
uint16_t *count) {
HuffmanCode code; /* current table entry */
int symbol; /* symbol index in original or sorted table */
unsigned key; /* reversed prefix code */
int step; /* step size to replicate values in current table */
int table_size; /* size of current table */
int sorted[18]; /* symbols sorted by code length */
/* offsets in sorted table for each length */
int offset[BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1];
int bits;
int bits_count;
/* generate offsets into sorted symbol table by code length */
symbol = -1;
bits = 1;
BROTLI_REPEAT(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH, {
symbol += count[bits];
offset[bits] = symbol;
bits++;
});
offset[0] = 17;
/* sort symbols by length, by symbol order within each length */
symbol = 18;
do {
BROTLI_REPEAT(6, {
symbol--;
sorted[offset[code_lengths[symbol]]--] = symbol;
});
} while (symbol != 0);
table_size = 1 << BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH;
/* special case code with only one value */
if (offset[BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH] == 0) {
code.bits = 0;
code.value = (uint16_t)sorted[0];
for (key = 0; key < table_size; ++key) {
table[key] = code;
}
return;
}
/* fill in table */
key = 0;
symbol = 0;
bits = 1;
step = 2;
do {
code.bits = (uint8_t)bits;
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
code.value = (uint16_t)sorted[symbol++];
ReplicateValue(&table[key], step, table_size, code);
key = GetNextKey(key, bits);
}
step <<= 1;
} while (++bits <= BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
}
int BrotliBuildHuffmanTable(HuffmanCode* root_table,
int root_bits,
const uint8_t* const code_lengths,
int code_lengths_size,
const uint16_t* const symbol_lists,
uint16_t *count) {
HuffmanCode code; /* current table entry */
HuffmanCode* table; /* next available space in table */
int len; /* current code length */
int symbol; /* symbol index in original or sorted table */
int key; /* reversed prefix code */
int symbol; /* symbol index in original or sorted table */
unsigned key; /* reversed prefix code */
int step; /* step size to replicate values in current table */
int low; /* low bits for current root entry */
int mask; /* mask for low bits */
unsigned low; /* low bits for current root entry */
unsigned mask; /* mask for low bits */
int table_bits; /* key length of current table */
int table_size; /* size of current table */
int total_size; /* sum of root table size and 2nd level table sizes */
/* symbols sorted by code length */
uint16_t sorted[MAX_CODE_LENGTHS_SIZE];
/* offsets in sorted table for each length */
uint16_t offset[MAX_LENGTH + 1];
int max_length = 1;
int max_length = -1;
int bits;
int bits_count;
if (PREDICT_FALSE(code_lengths_size > MAX_CODE_LENGTHS_SIZE)) {
return 0;
}
/* generate offsets into sorted symbol table by code length */
{
uint16_t sum = 0;
for (len = 1; len <= MAX_LENGTH; len++) {
offset[len] = sum;
if (count[len]) {
sum = (uint16_t)(sum + count[len]);
max_length = len;
}
}
}
/* sort symbols by length, by symbol order within each length */
for (symbol = 0; symbol < code_lengths_size; symbol++) {
if (code_lengths[symbol] != 0) {
sorted[offset[code_lengths[symbol]]++] = (uint16_t)symbol;
}
}
while (symbol_lists[max_length] == 0xFFFF) max_length--;
max_length += BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1;
table = root_table;
table_bits = root_bits;
table_size = 1 << table_bits;
total_size = table_size;
/* special case code with only one value */
if (offset[MAX_LENGTH] == 1) {
code.bits = 0;
code.value = (uint16_t)sorted[0];
for (key = 0; key < total_size; ++key) {
table[key] = code;
}
return total_size;
}
/* fill in root table */
/* let's reduce the table size to a smaller size if possible, and */
/* create the repetitions by memcpy if possible in the coming loop */
@ -134,17 +162,19 @@ int BrotliBuildHuffmanTable(HuffmanCode* root_table,
table_size = 1 << table_bits;
}
key = 0;
symbol = 0;
code.bits = 1;
bits = 1;
step = 2;
do {
for (; count[code.bits] != 0; --count[code.bits]) {
code.value = (uint16_t)sorted[symbol++];
code.bits = (uint8_t)bits;
symbol = bits - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
symbol = symbol_lists[symbol];
code.value = (uint16_t)symbol;
ReplicateValue(&table[key], step, table_size, code);
key = GetNextKey(key, code.bits);
key = GetNextKey(key, bits);
}
step <<= 1;
} while (++code.bits <= table_bits);
} while (++bits <= table_bits);
/* if root_bits != table_bits we only created one fraction of the */
/* table, and we need to replicate it now. */
@ -155,9 +185,10 @@ int BrotliBuildHuffmanTable(HuffmanCode* root_table,
}
/* fill in 2nd level tables and add pointers to root table */
mask = total_size - 1;
low = -1;
mask = (unsigned)(total_size - 1);
low = (unsigned)-1;
for (len = root_bits + 1, step = 2; len <= max_length; ++len, step <<= 1) {
symbol = len - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
for (; count[len] != 0; --count[len]) {
if ((key & mask) != low) {
table += table_size;
@ -169,12 +200,12 @@ int BrotliBuildHuffmanTable(HuffmanCode* root_table,
root_table[low].value = (uint16_t)((table - root_table) - low);
}
code.bits = (uint8_t)(len - root_bits);
code.value = (uint16_t)sorted[symbol++];
symbol = symbol_lists[symbol];
code.value = (uint16_t)symbol;
ReplicateValue(&table[key >> root_bits], step, table_size, code);
key = GetNextKey(key, len);
}
}
return total_size;
}

View File

@ -24,21 +24,33 @@
extern "C" {
#endif
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
/* For current format this constant equals to kNumInsertAndCopyCodes */
#define BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE 704
/* Maximum possible Huffman table size for an alphabet size of 704, max code
* length 15 and root table bits 8. */
#define BROTLI_HUFFMAN_MAX_TABLE_SIZE 1080
#define BROTLI_HUFFMAN_MAX_TABLE_SIZE 1080
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
typedef struct {
uint8_t bits; /* number of bits used for this symbol */
uint16_t value; /* symbol value or table offset */
} HuffmanCode;
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
/* Returns false in case of error (invalid tree or memory error). */
void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
const uint8_t* const code_lengths,
uint16_t *count);
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
/* Returns size of resulting table. */
int BrotliBuildHuffmanTable(HuffmanCode* root_table,
int root_bits,
const uint8_t* const code_lengths,
int code_lengths_size,
const uint16_t* const symbol_lists,
uint16_t *count_arg);
int BrotliBuildSimpleHuffmanTable(HuffmanCode* table,

View File

@ -130,4 +130,21 @@ OR:
#define BROTLI_NO_ASAN
#endif
#define BROTLI_REPEAT(N, X) { \
if ((N & 1) != 0) {X;} \
if ((N & 2) != 0) {X; X;} \
if ((N & 4) != 0) {X; X; X; X;} \
}
#if (__GNUC__ > 2) || defined(__llvm__)
#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7))
static BROTLI_INLINE unsigned BrotliRBit(unsigned input) {
unsigned output;
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
return output;
}
#define BROTLI_RBIT(x) BrotliRBit(x)
#endif /* armv7 */
#endif /* gcc || clang */
#endif /* BROTLI_DEC_PORT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -45,9 +45,6 @@ void BrotliStateInit(BrotliState* s) {
s->distance_hgroup.codes = NULL;
s->distance_hgroup.htrees = NULL;
s->code_lengths = NULL;
s->context_map_table = NULL;
s->custom_dict = NULL;
s->custom_dict_size = 0;
@ -62,6 +59,9 @@ void BrotliStateInit(BrotliState* s) {
s->block_type_trees = NULL;
s->block_len_trees = NULL;
/* Make small negative indexes addressable. */
s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
s->mtf_upper_bound = 255;
}
@ -84,6 +84,7 @@ void BrotliStateMetablockBegin(BrotliState* s) {
s->dist_context_map = NULL;
s->context_map_slice = NULL;
s->literal_htree_index = 0;
s->literal_htree = NULL;
s->dist_context_map_slice = NULL;
s->dist_htree_index = 0;
s->context_lookup1 = NULL;
@ -122,13 +123,6 @@ void BrotliStateCleanupAfterMetablock(BrotliState* s) {
}
void BrotliStateCleanup(BrotliState* s) {
if (s->context_map_table != 0) {
free(s->context_map_table);
}
if (s->code_lengths != 0) {
free(s->code_lengths);
}
if (s->context_modes != 0) {
free(s->context_modes);
}

View File

@ -34,17 +34,15 @@ typedef enum {
BROTLI_STATE_METABLOCK_BEGIN,
BROTLI_STATE_METABLOCK_HEADER_1,
BROTLI_STATE_METABLOCK_HEADER_2,
BROTLI_STATE_BLOCK_BEGIN,
BROTLI_STATE_BLOCK_INNER,
BROTLI_STATE_BLOCK_DISTANCE,
BROTLI_STATE_BLOCK_POST,
BROTLI_STATE_COMMAND_BEGIN,
BROTLI_STATE_COMMAND_INNER,
BROTLI_STATE_UNCOMPRESSED,
BROTLI_STATE_METADATA,
BROTLI_STATE_BLOCK_INNER_WRITE,
BROTLI_STATE_COMMAND_INNER_WRITE,
BROTLI_STATE_METABLOCK_DONE,
BROTLI_STATE_BLOCK_POST_WRITE_1,
BROTLI_STATE_BLOCK_POST_WRITE_2,
BROTLI_STATE_BLOCK_POST_WRAP_COPY,
BROTLI_STATE_COMMAND_POST_WRITE_1,
BROTLI_STATE_COMMAND_POST_WRITE_2,
BROTLI_STATE_COMMAND_POST_WRAP_COPY,
BROTLI_STATE_HUFFMAN_CODE_0,
BROTLI_STATE_HUFFMAN_CODE_1,
BROTLI_STATE_HUFFMAN_CODE_2,
@ -70,92 +68,76 @@ typedef enum {
typedef enum {
BROTLI_STATE_SUB1_NONE,
BROTLI_STATE_SUB1_HUFFMAN_LENGTH_BEGIN,
BROTLI_STATE_SUB1_HUFFMAN_LENGTH_SYMBOLS,
BROTLI_STATE_SUB1_HUFFMAN_DONE
BROTLI_STATE_SUB1_HUFFMAN_LENGTH_SYMBOLS
} BrotliRunningSub1State;
typedef struct {
BrotliRunningState state;
BrotliRunningSub0State sub0_state; /* State inside function call */
BrotliRunningSub1State sub1_state; /* State inside function call */
/* This counter is reused for several disjoint loops. */
BrotliBitReader br;
int loop_counter;
int pos;
int input_end;
uint32_t window_bits;
int max_backward_distance;
int max_backward_distance_minus_custom_dict_size;
int max_distance;
int ringbuffer_size;
int ringbuffer_mask;
int dist_rb_idx;
int dist_rb[4];
uint8_t* ringbuffer;
uint8_t* ringbuffer_end;
HuffmanCode* htree_command;
const uint8_t* context_lookup1;
const uint8_t* context_lookup2;
uint8_t* context_map_slice;
uint8_t* dist_context_map_slice;
/* This ring buffer holds a few past copy distances that will be used by */
/* some special distance codes. */
int dist_rb[4];
int dist_rb_idx;
HuffmanTreeGroup literal_hgroup;
HuffmanTreeGroup insert_copy_hgroup;
HuffmanTreeGroup distance_hgroup;
HuffmanCode* block_type_trees;
HuffmanCode* block_len_trees;
BrotliBitReader br;
/* This counter is reused for several disjoint loops. */
int loop_counter;
/* This is true if the literal context map histogram type always matches the
block type. It is then not needed to keep the context (faster decoding). */
int trivial_literal_context;
int distance_context;
int meta_block_remaining_len;
int is_metadata;
int is_uncompressed;
int block_length[3];
int num_block_types[3];
int block_type_rb[6];
int distance_postfix_bits;
int num_direct_distance_codes;
int distance_postfix_mask;
uint8_t* context_map;
uint8_t* context_modes;
int num_literal_htrees;
uint8_t* dist_context_map;
int num_dist_htrees;
uint8_t* context_map_slice;
uint8_t* dist_context_map_slice;
uint8_t literal_htree_index;
HuffmanCode *literal_htree;
uint8_t dist_htree_index;
uint8_t prev_code_len;
uint8_t repeat_code_len;
const uint8_t* context_lookup1;
const uint8_t* context_lookup2;
HuffmanCode* htree_command;
uint8_t prev_code_len;
int copy_length;
int distance_code;
int distance;
/* For CopyUncompressedBlockToOutput */
int nbytes;
/* For partial write operations */
int to_write;
int partially_written;
/* For HuffmanTreeGroupDecode */
int htrees_decoded;
/* For ReadHuffmanCodeLengths */
int symbol;
int repeat;
int space;
HuffmanCode table[32];
uint8_t code_length_code_lengths[18];
/* For ReadHuffmanCode */
uint8_t* code_lengths;
/* The maximum non-zero code length index in code lengths */
uint32_t huffman_max_nonzero;
uint32_t symbol;
uint32_t repeat;
uint32_t space;
HuffmanCode table[32];
/* List of of symbol chains. */
uint16_t* symbol_lists;
/* Storage from symbol_lists. */
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE];
/* Tails of symbol chains. */
int next_symbol[32];
uint8_t code_length_code_lengths[18];
/* Population counts for the code lengths */
uint16_t code_length_histo[16];
@ -166,7 +148,7 @@ typedef struct {
/* For DecodeContextMap */
int context_index;
int max_run_length_prefix;
HuffmanCode* context_map_table;
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_TABLE_SIZE];
/* For InverseMoveToFrontTransform */
int mtf_upper_bound;
@ -175,6 +157,20 @@ typedef struct {
/* For custom dictionaries */
const uint8_t* custom_dict;
int custom_dict_size;
/* less used attributes are in the end of this struct */
BrotliRunningSub0State sub0_state; /* State inside function call */
BrotliRunningSub1State sub1_state; /* State inside function call */
int input_end;
uint32_t window_bits;
/* For CopyUncompressedBlockToOutput */
int nbytes;
int num_literal_htrees;
uint8_t* context_map;
uint8_t* context_modes;
} BrotliState;
void BrotliStateInit(BrotliState* s);