diff --git a/dec/bit_reader.c b/dec/bit_reader.c index c403b73..4951b2e 100644 --- a/dec/bit_reader.c +++ b/dec/bit_reader.c @@ -29,25 +29,24 @@ void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input) { br->input_ = input; br->val_ = 0; - br->bit_pos_ = 0; + br->bit_pos_ = sizeof(br->val_) << 3; br->avail_in = 0; br->eos_ = 0; br->next_in = br->buf_; } - -void BrotliWarmupBitReader(BrotliBitReader* const br) { - size_t i; - br->val_ = 0; - for (i = 0; i < sizeof(br->val_); ++i) { -#if (BROTLI_64_BITS_LITTLE_ENDIAN) - br->val_ |= ((uint64_t)*br->next_in) << (8 * i); -#else - br->val_ |= ((uint32_t)*br->next_in) << (8 * i); -#endif - ++br->next_in; - --br->avail_in; +int BrotliWarmupBitReader(BrotliBitReader* const br) { + if (br->bit_pos_ == (sizeof(br->val_) << 3)) { + if (!br->avail_in) { + return 0; + } + br->bit_pos_ -= 8; + br->val_ = *br->next_in; + br->val_ <<= br->bit_pos_; + br->next_in++; + br->avail_in--; } + return 1; } #if defined(__cplusplus) || defined(c_plusplus) diff --git a/dec/bit_reader.h b/dec/bit_reader.h index b5639bb..ed6d2c5 100644 --- a/dec/bit_reader.h +++ b/dec/bit_reader.h @@ -27,9 +27,10 @@ extern "C" { #endif -#define BROTLI_MAX_NUM_BIT_READ 25 #define BROTLI_READ_SIZE 1024 -#define BROTLI_IMPLICIT_ZEROES 128 +/* 128 bytes, plus 8 bytes slack for valid 128-byte BrotliCheckInputAmount with + some bytes read in val_ of bit reader. */ +#define BROTLI_IMPLICIT_ZEROES 136 #define BROTLI_IBUF_SIZE (BROTLI_READ_SIZE + BROTLI_IMPLICIT_ZEROES) #define BROTLI_IBUF_MASK (BROTLI_READ_SIZE - 1) @@ -54,13 +55,12 @@ typedef struct { uint8_t buf_[BROTLI_IBUF_SIZE]; } BrotliBitReader; -/* Initializes the bitreader fields. After this, BrotliReadInput then - BrotliWarmupBitReader must be used. */ +/* Initializes the bitreader fields. */ void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input); -/* Initializes bit reading and bit position with the first input data available. - Requires that there is enough input available (BrotliCheckInputAmount). */ -void BrotliWarmupBitReader(BrotliBitReader* const br); +/* Ensures that accumulator is not empty. May consume one byte of input. + Returns 0 if data is required but there is no input available. */ +int BrotliWarmupBitReader(BrotliBitReader* const br); /* Pulls data from the input to the the read buffer. @@ -109,7 +109,14 @@ static BROTLI_INLINE int BrotliReadInput( /* Returns amount of unread bytes the bit reader still has buffered from the BrotliInput, including whole bytes in br->val_. */ static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) { - return br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3); + size_t result = br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3); + if (!br->eos_) { + return result; + } + if (result <= BROTLI_IMPLICIT_ZEROES) { + return 0; + } + return result - BROTLI_IMPLICIT_ZEROES; } /* Checks if there is at least num bytes left in the input ringbuffer (excluding @@ -120,7 +127,8 @@ static BROTLI_INLINE int BrotliCheckInputAmount( return br->avail_in >= num; } -/* Guarantees that there are at least n_bits in the buffer. +/* Guarantees that there are at least n_bits + 1 bits in accumulator. + Precondition: accumulator contains at least 1 bit. n_bits should be in the range [1..24] */ static BROTLI_INLINE void BrotliFillBitWindow( BrotliBitReader* const br, int n_bits) { @@ -188,6 +196,19 @@ static BROTLI_INLINE void BrotliFillBitWindow( #endif } +/* Pulls one byte of input to accumulator. */ +static BROTLI_INLINE void BrotliPullByte(BrotliBitReader* const br) { + br->val_ >>= 8; +#if (BROTLI_64_BITS_LITTLE_ENDIAN) + br->val_ |= ((uint64_t)*br->next_in) << 56; +#else + br->val_ |= ((uint32_t)*br->next_in) << 24; +#endif + br->bit_pos_ -= 8; + --br->avail_in; + ++br->next_in; +} + /* Like BrotliGetBits, but does not mask the result, it is only guaranteed that it has minimum n_bits. */ static BROTLI_INLINE uint32_t BrotliGetBitsUnmasked( @@ -209,28 +230,71 @@ static BROTLI_INLINE void BrotliDropBits( br->bit_pos_ += (uint32_t)n_bits; } -/* Reads the specified number of bits from br and advances the bit pos. */ -static BROTLI_INLINE uint32_t BrotliReadBits( - BrotliBitReader* const br, int n_bits) { - uint32_t val; - BrotliFillBitWindow(br, n_bits); - val = (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits); +/* Reads the specified number of bits from br and advances the bit pos. + Precondition: accumulator MUST contain at least n_bits. */ +static BROTLI_INLINE void BrotliTakeBits( + BrotliBitReader* const br, int n_bits, uint32_t* val) { + *val = (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits); #ifdef BROTLI_DECODE_DEBUG printf("[BrotliReadBits] %d %d %d val: %6x\n", (int)br->avail_in, (int)br->bit_pos_, n_bits, val); #endif br->bit_pos_ += (uint32_t)n_bits; +} + +/* Reads the specified number of bits from br and advances the bit pos. + Assumes that there is enough input to perform BrotliFillBitWindow. */ +static BROTLI_INLINE uint32_t BrotliReadBits( + BrotliBitReader* const br, int n_bits) { + uint32_t val; + BrotliFillBitWindow(br, n_bits); + BrotliTakeBits(br, n_bits, &val); return val; } +/* Tries to read the specified amount of bits. Returns 0, if there is not + enough input. */ +static BROTLI_INLINE int BrotliSafeReadBits( + BrotliBitReader* const br, int n_bits, uint32_t* val) { + while (br->bit_pos_ + (uint32_t)n_bits > (sizeof(br->val_) << 3)) { + if (br->avail_in == 0) { + return 0; + } + BrotliPullByte(br); + } + BrotliTakeBits(br, n_bits, val); + return 1; +} + /* Advances the bit reader position to the next byte boundary and verifies that any skipped bits are set to zero. */ static BROTLI_INLINE int BrotliJumpToByteBoundary(BrotliBitReader* br) { - uint32_t new_bit_pos = (br->bit_pos_ + 7) & (uint32_t)(~7UL); - uint32_t pad_bits = BrotliReadBits(br, (int)(new_bit_pos - br->bit_pos_)); + int pad_bits_count = (64 - (int)br->bit_pos_) & 0x7; + uint32_t pad_bits = 0; + if (pad_bits_count != 0) { + BrotliTakeBits(br, pad_bits_count, &pad_bits); + } return pad_bits == 0; } +/* Peeks a byte at specified offset. + Precondition: bit reader is parked to a byte boundry. + Returns -1 if operation is not feasible. */ +static BROTLI_INLINE int BrotliPeekByte(BrotliBitReader* br, int offset) { + int bytes_left = (int)(sizeof(br->val_) - (br->bit_pos_ >> 3)); + if (br->bit_pos_ & 7) { + return -1; + } + if (offset < bytes_left) { + return (br->val_ >> (br->bit_pos_ + (unsigned)(offset << 3))) & 0xFF; + } + offset -= bytes_left; + if (offset < br->avail_in) { + return br->next_in[offset]; + } + return -1; +} + /* Copies remaining input bytes stored in the bit reader to the output. Value num may not be larger than BrotliGetRemainingBytes. The bit reader must be warmed up again after this. */ @@ -246,9 +310,20 @@ static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest, memcpy(dest, br->next_in, num); br->avail_in -= (uint32_t)num; br->next_in += num; - br->bit_pos_ = 0; } +/* Checks that bit reader hasn't read after the end of input. + Returns 0 if bit reader has used implicit zeroes after the end of input. */ +static BROTLI_INLINE int BrotliIsBitReaderOK(BrotliBitReader* br) { + size_t remaining_bytes = + br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3); + return !br->eos_ || (remaining_bytes >= BROTLI_IMPLICIT_ZEROES); +} + +#undef BROTLI_IMPLICIT_ZEROES +#undef BROTLI_IBUF_SIZE +#undef BROTLI_IBUF_MASK + #if defined(__cplusplus) || defined(c_plusplus) } /* extern "C" */ #endif diff --git a/dec/decode.c b/dec/decode.c index cac091d..c203471 100644 --- a/dec/decode.c +++ b/dec/decode.c @@ -64,17 +64,19 @@ static const uint8_t kCodeLengthCodeOrder[CODE_LENGTH_CODES] = { #define NUM_DISTANCE_SHORT_CODES 16 - +/* Decodes a number in the range [9..24], by reading 1 - 7 bits. + Precondition: bit-reader accumulator has at least 7 bits. */ static uint32_t DecodeWindowBits(BrotliBitReader* br) { uint32_t n; - if (BrotliReadBits(br, 1) == 0) { + BrotliTakeBits(br, 1, &n); + if (n == 0) { return 16; } - n = BrotliReadBits(br, 3); + BrotliTakeBits(br, 3, &n); if (n != 0) { return 17 + n; } - n = BrotliReadBits(br, 3); + BrotliTakeBits(br, 3, &n); if (n != 0) { return 8 + n; } @@ -106,56 +108,125 @@ static BROTLI_INLINE int DecodeVarLenUint8(BrotliBitReader* br) { return 0; } -static BrotliResult DecodeMetaBlockLength(BrotliBitReader* br, - int* meta_block_length, - int* input_end, - int* is_metadata, - int* is_uncompressed) { - int size_nibbles; - int size_bytes; +/* Decodes a metablock length and flags by reading 2 - 31 bits. */ +static BrotliResult BROTLI_NOINLINE DecodeMetaBlockLength(BrotliState* s, + BrotliBitReader* br) { + uint32_t bits; int i; - *input_end = (int)BrotliReadBits(br, 1); - *meta_block_length = 0; - *is_uncompressed = 0; - *is_metadata = 0; - if (*input_end && BrotliReadBits(br, 1)) { - return BROTLI_RESULT_SUCCESS; - } - size_nibbles = (int)BrotliReadBits(br, 2) + 4; - if (size_nibbles == 7) { - *is_metadata = 1; - /* Verify reserved bit. */ - if (BrotliReadBits(br, 1) != 0) { - return BROTLI_FAILURE(); - } - size_bytes = (int)BrotliReadBits(br, 2); - if (size_bytes == 0) { - return BROTLI_RESULT_SUCCESS; - } - for (i = 0; i < size_bytes; ++i) { - int next_byte = (int)BrotliReadBits(br, 8); - if (i + 1 == size_bytes && size_bytes > 1 && next_byte == 0) { + for (;;) { + switch (s->substate_metablock_header) { + case BROTLI_STATE_METABLOCK_HEADER_NONE: + if (!BrotliSafeReadBits(br, 1, &bits)) { + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } + s->is_last_metablock = (uint8_t)bits; + s->meta_block_remaining_len = 0; + s->is_uncompressed = 0; + s->is_metadata = 0; + if (!s->is_last_metablock) { + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NIBBLES; + break; + } + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_EMPTY; + /* No break, transit to the next state. */ + + case BROTLI_STATE_METABLOCK_HEADER_EMPTY: + if (!BrotliSafeReadBits(br, 1, &bits)) { + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } + if (bits) { + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + return BROTLI_RESULT_SUCCESS; + } + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NIBBLES; + /* No break, transit to the next state. */ + + case BROTLI_STATE_METABLOCK_HEADER_NIBBLES: + if (!BrotliSafeReadBits(br, 2, &bits)) { + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } + s->size_nibbles = (uint8_t)(bits + 4); + s->loop_counter = 0; + if (bits == 3) { + s->is_metadata = 1; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_RESERVED; + break; + } + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_SIZE; + /* No break, transit to the next state. */ + + case BROTLI_STATE_METABLOCK_HEADER_SIZE: + i = s->loop_counter; + for (; i < s->size_nibbles; ++i) { + if (!BrotliSafeReadBits(br, 4, &bits)) { + s->loop_counter = i; + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } + if (i + 1 == s->size_nibbles && s->size_nibbles > 4 && bits == 0) { + return BROTLI_FAILURE(); + } + s->meta_block_remaining_len |= (int)(bits << (i * 4)); + } + s->substate_metablock_header = + BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED; + /* No break, transit to the next state. */ + + case BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED: + if (!s->is_last_metablock && !s->is_metadata) { + if (!BrotliSafeReadBits(br, 1, &bits)) { + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } + s->is_uncompressed = (uint8_t)bits; + } + ++s->meta_block_remaining_len; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + return BROTLI_RESULT_SUCCESS; + + case BROTLI_STATE_METABLOCK_HEADER_RESERVED: + if (!BrotliSafeReadBits(br, 1, &bits)) { + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } + if (bits != 0) { + return BROTLI_FAILURE(); + } + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_BYTES; + /* No break, transit to the next state. */ + + case BROTLI_STATE_METABLOCK_HEADER_BYTES: + if (!BrotliSafeReadBits(br, 2, &bits)) { + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } + if (bits == 0) { + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + return BROTLI_RESULT_SUCCESS; + } + s->size_nibbles = (uint8_t)bits; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_METADATA; + /* No break, transit to the next state. */ + + case BROTLI_STATE_METABLOCK_HEADER_METADATA: + i = s->loop_counter; + for (; i < s->size_nibbles; ++i) { + if (!BrotliSafeReadBits(br, 8, &bits)) { + s->loop_counter = i; + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } + if (i + 1 == s->size_nibbles && s->size_nibbles > 1 && bits == 0) { + return BROTLI_FAILURE(); + } + s->meta_block_remaining_len |= (int)(bits << (i * 8)); + } + s->substate_metablock_header = + BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED; + break; + + default: return BROTLI_FAILURE(); - } - *meta_block_length |= next_byte << (i * 8); - } - } else { - for (i = 0; i < size_nibbles; ++i) { - int next_nibble = (int)BrotliReadBits(br, 4); - if (i + 1 == size_nibbles && size_nibbles > 4 && next_nibble == 0) { - return BROTLI_FAILURE(); - } - *meta_block_length |= next_nibble << (i * 4); } } - ++(*meta_block_length); - if (!*input_end && !*is_metadata) { - *is_uncompressed = (int)BrotliReadBits(br, 1); - } - return BROTLI_RESULT_SUCCESS; } -/* Decodes the next Huffman code from bit-stream. */ +/* Decodes the next Huffman code from bit-stream. Reads 0 - 15 bits. */ static BROTLI_INLINE int ReadSymbol(const HuffmanCode* table, BrotliBitReader* br) { /* Read the bits for two reads at once. */ @@ -171,6 +242,7 @@ static BROTLI_INLINE int ReadSymbol(const HuffmanCode* table, return table->value; } +/* Makes a look-up in first level Huffman table. Peeks 8 bits. */ static BROTLI_INLINE void PreloadSymbol(const HuffmanCode* table, BrotliBitReader* br, unsigned* bits, @@ -180,6 +252,8 @@ static BROTLI_INLINE void PreloadSymbol(const HuffmanCode* table, *value = table->value; } +/* Decodes the next Huffman code using data prepared by PreloadSymbol. + Reads 0 - 15 bits. Also peeks 8 following bits. */ static BROTLI_INLINE unsigned ReadPreloadedSymbol(const HuffmanCode* table, BrotliBitReader* br, unsigned* bits, @@ -200,6 +274,18 @@ static BROTLI_INLINE unsigned ReadPreloadedSymbol(const HuffmanCode* table, return result; } +/* Decodes the Huffman tables. + There are 2 scenarios: + A) Huffman code contains only few symbols (0..4). Those symbols are read + directly; their code lengths are defined by the number of symbols. + For this scenario 5 - 35 will be read. + + B) 2-phase decoding: + B.1) Small Huffman table is decoded; it is specified with code lengths + encoded with predefined entropy code. 38 - 74 bits are used. + B.2) Decoded table is used to decode code lengths of symbols in resulting + Huffman table. In worst case 3520 bits are read. +*/ static BrotliResult ReadHuffmanCode(int alphabet_size, HuffmanCode* table, int* opt_table_size, @@ -220,7 +306,7 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, /* Unnecessary masking, but might be good for safety. */ alphabet_size &= 0x3ff; /* State machine */ - if (s->sub1_state == BROTLI_STATE_SUB1_NONE) { + if (s->substate_huffman == BROTLI_STATE_HUFFMAN_NONE) { if (!BrotliCheckInputAmount(br, 32)) { return BROTLI_RESULT_NEEDS_MORE_INPUT; } @@ -238,6 +324,7 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, max_bits_counter >>= 1; ++max_bits; } + /* max_bits == 0..10; symbol == 0..3; 0..30 bits will be read. */ do { int k; uint32_t v = BrotliReadBits(br, max_bits); @@ -260,7 +347,7 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, if (opt_table_size) { *opt_table_size = table_size; } - s->sub1_state = BROTLI_STATE_SUB1_NONE; + s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; return BROTLI_RESULT_SUCCESS; } else { /* Decode Huffman-coded code lengths. */ int i; @@ -312,7 +399,7 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, repeat = 0; repeat_code_len = 0; space = 32768; - s->sub1_state = BROTLI_STATE_SUB1_HUFFMAN_LENGTH_SYMBOLS; + s->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS; } while (symbol < alphabet_size && space > 0) { @@ -334,11 +421,11 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, const HuffmanCode* p = s->table; uint8_t code_len; p += BrotliGetBits(br, BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH); - BrotliDropBits(br, p->bits); - code_len = (uint8_t)p->value; + BrotliDropBits(br, p->bits); /* Use 1..5 bits */ + code_len = (uint8_t)p->value; /* code_len == 0..17 */ if (code_len < kCodeLengthRepeatCode) { repeat = 0; - if (code_len != 0) { + if (code_len != 0) { /* code_len == 1..15 */ symbol_lists[next_symbol[code_len]] = (uint16_t)symbol; next_symbol[code_len] = (int)symbol; prev_code_len = code_len; @@ -346,8 +433,8 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, s->code_length_histo[code_len]++; } symbol++; - } else { - const int extra_bits = code_len - 14; + } else { /* code_len == 16..17 */ + const int extra_bits = code_len - 14; /* extra_bits == 2..3 */ uint32_t old_repeat; uint32_t repeat_delta; uint8_t new_len = 0; @@ -364,7 +451,9 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, repeat <<= extra_bits; } repeat += BrotliReadBits(br, extra_bits) + 3; - repeat_delta = repeat - old_repeat; + repeat_delta = repeat - old_repeat; /* repeat_delta >= 3 */ + /* So, for extra 2..3 bits we produce more than 2 symbols. + Consequently, at most 5 bits per symbol are used. */ if (symbol + repeat_delta > alphabet_size) { return BROTLI_FAILURE(); } @@ -397,16 +486,17 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, *opt_table_size = table_size; } } - s->sub1_state = BROTLI_STATE_SUB1_NONE; + s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; return BROTLI_RESULT_SUCCESS; } +/* Decodes a block length by reading 3..39 bits. */ static BROTLI_INLINE int ReadBlockLength(const HuffmanCode* table, BrotliBitReader* br) { int code; int nbits; code = ReadSymbol(table, br); - nbits = kBlockLengthPrefixCode[code].nbits; + nbits = kBlockLengthPrefixCode[code].nbits; /* nbits == 2..24 */ return kBlockLengthPrefixCode[code].offset + (int)BrotliReadBits(br, nbits); } @@ -467,12 +557,13 @@ void InverseMoveToFrontTransformForTesting(uint8_t* v, int l, BrotliState* s) { } +/* Decodes a series of Huffman table using ReadHuffmanCode function. */ static BrotliResult HuffmanTreeGroupDecode(HuffmanTreeGroup* group, BrotliState* s) { - if (s->sub0_state != BROTLI_STATE_SUB0_TREE_GROUP) { + if (s->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) { s->next = group->codes; s->htree_index = 0; - s->sub0_state = BROTLI_STATE_SUB0_TREE_GROUP; + s->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP; } while (s->htree_index < group->num_htrees) { int table_size; @@ -481,15 +572,21 @@ static BrotliResult HuffmanTreeGroupDecode(HuffmanTreeGroup* group, if (result != BROTLI_RESULT_SUCCESS) return result; group->htrees[s->htree_index] = s->next; s->next += table_size; - if (table_size == 0) { - return BROTLI_FAILURE(); - } ++s->htree_index; } - s->sub0_state = BROTLI_STATE_SUB0_NONE; + s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; return BROTLI_RESULT_SUCCESS; } +/* Decodes a context map. + Decoding is done in 4 phases: + 1) Read auxiliary information (6..16 bits) and allocate memory. + In case of trivial context map, decoding is finished at this phase. + 2) Decode Huffman table using ReadHuffmanCode function. + This table will be used for reading context map items. + 3) Read context map items; "0" values could be run-length encoded. + 4) Optionally, apply InverseMoveToFront transform to the resulting map. + */ static BrotliResult DecodeContextMap(int context_map_size, int* num_htrees, uint8_t** context_map_arg, @@ -498,12 +595,12 @@ static BrotliResult DecodeContextMap(int context_map_size, BrotliResult result = BROTLI_RESULT_SUCCESS; int use_rle_for_zeros; - switch((int)s->sub0_state) { - case BROTLI_STATE_SUB0_NONE: + switch((int)s->substate_context_map) { + case BROTLI_STATE_CONTEXT_MAP_NONE: if (!BrotliCheckInputAmount(br, 32)) { return BROTLI_RESULT_NEEDS_MORE_INPUT; } - *num_htrees = DecodeVarLenUint8(br) + 1; + *num_htrees = DecodeVarLenUint8(br) + 1; /* Reads 1..11 bits. */ s->context_index = 0; BROTLI_LOG_UINT(context_map_size); BROTLI_LOG_UINT(*num_htrees); @@ -521,15 +618,15 @@ static BrotliResult DecodeContextMap(int context_map_size, } else { s->max_run_length_prefix = 0; } - s->sub0_state = BROTLI_STATE_SUB0_CONTEXT_MAP_HUFFMAN; + s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN; /* No break, continue to next state. */ - case BROTLI_STATE_SUB0_CONTEXT_MAP_HUFFMAN: + case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: result = ReadHuffmanCode(*num_htrees + s->max_run_length_prefix, s->context_map_table, NULL, s); if (result != BROTLI_RESULT_SUCCESS) return result; - s->sub0_state = BROTLI_STATE_SUB0_CONTEXT_MAPS; + s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE; /* No break, continue to next state. */ - case BROTLI_STATE_SUB0_CONTEXT_MAPS: { + case BROTLI_STATE_CONTEXT_MAP_DECODE: { int context_index = s->context_index; int max_run_length_prefix = s->max_run_length_prefix; uint8_t* context_map = *context_map_arg; @@ -558,7 +655,7 @@ static BrotliResult DecodeContextMap(int context_map_size, if (BrotliReadBits(br, 1)) { InverseMoveToFrontTransform(context_map, context_map_size, s); } - s->sub0_state = BROTLI_STATE_SUB0_NONE; + s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE; return BROTLI_RESULT_SUCCESS; } } @@ -566,6 +663,8 @@ static BrotliResult DecodeContextMap(int context_map_size, return BROTLI_FAILURE(); } +/* Decodes a command or literal and updates block type ringbuffer. + Reads 0..15 bits. */ static void DecodeBlockType(const int max_block_type, const HuffmanCode* trees, int tree_type, @@ -586,14 +685,15 @@ static void DecodeBlockType(const int max_block_type, ringbuffer[1] = block_type; } -/* Decodes the block type and updates the state for literal context. */ +/* Decodes the block type and updates the state for literal context. + Reads 18..54 bits. */ static void DecodeBlockTypeWithContext(BrotliState* s, BrotliBitReader* br) { uint8_t context_mode; int context_offset; DecodeBlockType(s->num_block_types[0], s->block_type_trees, 0, - s->block_type_rb, br); - s->block_length[0] = ReadBlockLength(s->block_len_trees, br); + s->block_type_rb, br); /* Reads 0..15 bits. */ + s->block_length[0] = ReadBlockLength(s->block_len_trees, br); /* 3..39 bits */ context_offset = s->block_type_rb[1] << kLiteralContextBits; s->context_map_slice = s->context_map + context_offset; s->literal_htree_index = s->context_map_slice[0]; @@ -625,12 +725,12 @@ BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output, int num_read; /* State machine */ for (;;) { - switch ((int)s->sub0_state) { - case BROTLI_STATE_SUB0_NONE: + switch ((int)s->substate_uncompressed) { + case BROTLI_STATE_UNCOMPRESSED_NONE: /* For short lengths copy byte-by-byte */ if (s->meta_block_remaining_len < 8 || s->meta_block_remaining_len < BrotliGetRemainingBytes(&s->br)) { - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_SHORT; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_SHORT; break; } /* Copy remaining bytes from s->br.buf_ to ringbuffer. */ @@ -641,18 +741,21 @@ BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output, if (pos >= s->ringbuffer_size) { s->to_write = s->ringbuffer_size; s->partially_written = 0; - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_1; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE_1; break; } if (pos + s->meta_block_remaining_len >= s->ringbuffer_size) { - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_FILL; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_FILL; } else { - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_COPY; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_COPY; } break; - case BROTLI_STATE_SUB0_UNCOMPRESSED_SHORT: + case BROTLI_STATE_UNCOMPRESSED_SHORT: + if (!BrotliWarmupBitReader(&s->br)) { + return BROTLI_RESULT_NEEDS_MORE_INPUT; + } while (s->meta_block_remaining_len > 0) { - if (!BrotliCheckInputAmount(&s->br, 32)) { + if (!BrotliCheckInputAmount(&s->br, 8)) { return BROTLI_RESULT_NEEDS_MORE_INPUT; } s->ringbuffer[pos++] = (uint8_t)BrotliReadBits(&s->br, 8); @@ -661,26 +764,26 @@ BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output, if (pos >= s->ringbuffer_size) { s->to_write = s->ringbuffer_size; s->partially_written = 0; - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_2; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE_2; } else { - s->sub0_state = BROTLI_STATE_SUB0_NONE; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE; return BROTLI_RESULT_SUCCESS; } /* No break, if state is updated, continue to next state */ - case BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_1: - case BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_2: - case BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_3: + case BROTLI_STATE_UNCOMPRESSED_WRITE_1: + case BROTLI_STATE_UNCOMPRESSED_WRITE_2: + case BROTLI_STATE_UNCOMPRESSED_WRITE_3: result = WriteRingBuffer(output, s); if (result != BROTLI_RESULT_SUCCESS) { return result; } pos &= s->ringbuffer_mask; s->max_distance = s->max_backward_distance; - if (s->sub0_state == BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_2) { - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_SHORT; + if (s->substate_uncompressed == BROTLI_STATE_UNCOMPRESSED_WRITE_2) { + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_SHORT; break; } - if (s->sub0_state == BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_1) { + if (s->substate_uncompressed == BROTLI_STATE_UNCOMPRESSED_WRITE_1) { s->meta_block_remaining_len -= s->ringbuffer_size; /* If we wrote past the logical end of the ringbuffer, copy the tail of the ringbuffer to its beginning and flush the ringbuffer to the @@ -688,13 +791,13 @@ BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output, memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)pos); } if (pos + s->meta_block_remaining_len >= s->ringbuffer_size) { - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_FILL; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_FILL; } else { - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_COPY; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_COPY; break; } /* No break, continue to next state */ - case BROTLI_STATE_SUB0_UNCOMPRESSED_FILL: + case BROTLI_STATE_UNCOMPRESSED_FILL: /* If we have more to copy than the remaining size of the ringbuffer, then we first fill the ringbuffer from the input and then flush the ringbuffer to the output */ @@ -708,10 +811,10 @@ BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output, } s->to_write = s->ringbuffer_size; s->partially_written = 0; - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_3; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE_3; break; /* No break, continue to next state */ - case BROTLI_STATE_SUB0_UNCOMPRESSED_COPY: + case BROTLI_STATE_UNCOMPRESSED_COPY: /* Copy straight from the input onto the ringbuffer. The ringbuffer will be flushed to the output at a later time. */ num_read = BrotliRead(s->br.input_, &s->ringbuffer[pos], @@ -721,14 +824,7 @@ BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output, if (num_read < 0) return BROTLI_FAILURE(); return BROTLI_RESULT_NEEDS_MORE_INPUT; } - s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_WARMUP; - /* No break, continue to next state */ - case BROTLI_STATE_SUB0_UNCOMPRESSED_WARMUP: - if (!BrotliCheckInputAmount(&s->br, 32)) { - return BROTLI_RESULT_NEEDS_MORE_INPUT; - } - BrotliWarmupBitReader(&s->br); - s->sub0_state = BROTLI_STATE_SUB0_NONE; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE; return BROTLI_RESULT_SUCCESS; } } @@ -738,73 +834,92 @@ BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output, int BrotliDecompressedSize(size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size) { - int i; - uint64_t val = 0; - int bit_pos = 0; - int is_last; - int is_uncompressed = 0; - int size_nibbles; - int meta_block_len = 0; - if (encoded_size == 0) { + BrotliMemInput memin; + BrotliInput in = BrotliInitMemInput(encoded_buffer, encoded_size, &memin); + BrotliBitReader br; + BrotliState s; + int next_block_header; + int offset; + BrotliStateInit(&s); + BrotliInitBitReader(&br, in); + if (!BrotliReadInput(&br, 1) || !BrotliWarmupBitReader(&br)) { return 0; } - /* Look at the first 8 bytes, it is enough to decode the length of the first - meta-block. */ - for (i = 0; (size_t)i < encoded_size && i < 8; ++i) { - val |= (uint64_t)encoded_buffer[i] << (8 * i); - } - /* Skip the window bits. */ - ++bit_pos; - if (val & 1) { - bit_pos += 3; - if (((val >> 1) & 7) == 0) { - bit_pos += 3; - } - } - /* Decode the ISLAST bit. */ - is_last = (val >> bit_pos) & 1; - ++bit_pos; - if (is_last) { - /* Decode the ISEMPTY bit, if it is set to 1, we are done. */ - if ((val >> bit_pos) & 1) { - *decoded_size = 0; - return 1; - } - ++bit_pos; - } - /* Decode the length of the first meta-block. */ - size_nibbles = (int)((val >> bit_pos) & 3) + 4; - if (size_nibbles == 7) { - /* First meta-block contains metadata, this case is not supported here. */ + DecodeWindowBits(&br); + if (DecodeMetaBlockLength(&s, &br) != BROTLI_RESULT_SUCCESS) { return 0; } - bit_pos += 2; - for (i = 0; i < size_nibbles; ++i) { - meta_block_len |= (int)((val >> bit_pos) & 0xf) << (4 * i); - bit_pos += 4; - } - ++meta_block_len; - if (is_last) { - /* If this meta-block is the only one, we are done. */ - *decoded_size = (size_t)meta_block_len; + *decoded_size = (size_t)s.meta_block_remaining_len; + if (s.is_last_metablock) { return 1; } - is_uncompressed = (val >> bit_pos) & 1; - ++bit_pos; - if (is_uncompressed) { - /* If the first meta-block is uncompressed, we skip it and look at the - first two bits (ISLAST and ISEMPTY) of the next meta-block, and if - both are set to 1, we have a stream with an uncompressed meta-block - followed by an empty one, so the decompressed size is the size of the - first meta-block. */ - size_t offset = (size_t)((bit_pos + 7) >> 3) + (size_t)meta_block_len; - if (offset < encoded_size && ((encoded_buffer[offset] & 3) == 3)) { - *decoded_size = (size_t)meta_block_len; - return 1; + if (!s.is_uncompressed || !BrotliJumpToByteBoundary(&br)) { + return 0; + } + next_block_header = BrotliPeekByte(&br, s.meta_block_remaining_len); + if (next_block_header != -1) { + return (next_block_header & 3) == 3; + } + /* Currently bit reader can't peek outside of its buffer... */ + offset = BROTLI_READ_SIZE - (int)BrotliGetRemainingBytes(&br); + offset += s.meta_block_remaining_len; + return (offset < encoded_size) && ((encoded_buffer[offset] & 3) == 3); +} + +/* Allocates the smallest feasible ring buffer. + + If we know the data size is small, do not allocate more ringbuffer + size than needed to reduce memory usage. + + This method is called before the first non-empty non-metadata block is + processed. When this method is called, metablock size and flags MUST be + decoded. +*/ +int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s, + BrotliBitReader* br) { + static const int kRingBufferWriteAheadSlack = BROTLI_READ_SIZE; + int is_last = s->is_last_metablock; + s->ringbuffer_size = 1 << s->window_bits; + + if (s->is_uncompressed) { + int next_block_header = BrotliPeekByte(br, s->meta_block_remaining_len); + if (next_block_header != -1) { /* Peek succeeded */ + if ((next_block_header & 3) == 3) { /* ISLAST and ISEMPTY */ + is_last = 1; + } } } - /* Could not get the size because the file has multiple meta-blocks */ - return 0; + + /* We need at least 2 bytes of ring buffer size to get the last two + bytes for context from there */ + if (is_last) { + while (s->ringbuffer_size >= s->meta_block_remaining_len * 2 + && s->ringbuffer_size > 32) { + s->ringbuffer_size >>= 1; + } + } + + /* But make it fit the custom dictionary if there is one. */ + while (s->ringbuffer_size < s->custom_dict_size) { + s->ringbuffer_size <<= 1; + } + + s->ringbuffer_mask = s->ringbuffer_size - 1; + s->ringbuffer = (uint8_t*)malloc((size_t)(s->ringbuffer_size + + kRingBufferWriteAheadSlack + + kMaxDictionaryWordLength)); + if (!s->ringbuffer) { + return 0; + } + s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size; + s->ringbuffer[s->ringbuffer_size - 2] = 0; + s->ringbuffer[s->ringbuffer_size - 1] = 0; + if (s->custom_dict) { + memcpy(&s->ringbuffer[(-s->custom_dict_size) & s->ringbuffer_mask], + s->custom_dict, (size_t)s->custom_dict_size); + } + + return 1; } BrotliResult BrotliDecompressBuffer(size_t encoded_size, @@ -864,16 +979,12 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, BrotliBitReader* br = &s->br; int initial_remaining_len; int bytes_copied; - int is_metadata; - int is_uncompressed; uint8_t *copy_src; uint8_t *copy_dst; /* We need the slack region for the following reasons: - doing up to two 16-byte copies for fast backward copying - transforms - flushing the input s->ringbuffer when decoding uncompressed blocks */ - static const int kRingBufferWriteAheadSlack = - BROTLI_IMPLICIT_ZEROES + BROTLI_READ_SIZE; s->br.input_ = input; /* State machine */ for (;;) { @@ -898,57 +1009,18 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, s->state = BROTLI_STATE_BITREADER_WARMUP; /* No break, continue to next state */ case BROTLI_STATE_BITREADER_WARMUP: - if (!BrotliCheckInputAmount(br, 32)) { + /* Prepare to the first read. */ + if (!BrotliWarmupBitReader(br)) { result = BROTLI_RESULT_NEEDS_MORE_INPUT; break; } - BrotliWarmupBitReader(br); /* Decode window size. */ - s->window_bits = DecodeWindowBits(br); + s->window_bits = DecodeWindowBits(br); /* Reads 1..7 bits. */ if (s->window_bits == 9) { /* Value 9 is reserved for future use. */ result = BROTLI_FAILURE(); break; } - /* Allocate the ringbuffer */ - { - size_t known_size = 0; - s->ringbuffer_size = 1 << s->window_bits; - - /* If we know the data size is small, do not allocate more ringbuffer - size than needed to reduce memory usage. Since this happens after - the first BrotliCheckInputAmount call, we can read the bitreader - buffer at position 0. - We need at least 2 bytes of ring buffer size to get the last two - bytes for context from there */ - if (BrotliDecompressedSize(BROTLI_READ_SIZE, br->buf_, &known_size)) { - while (s->ringbuffer_size >= known_size * 2 - && s->ringbuffer_size > 32) { - s->ringbuffer_size >>= 1; - } - } - - /* But make it fit the custom dictionary if there is one. */ - while (s->ringbuffer_size < s->custom_dict_size) { - s->ringbuffer_size <<= 1; - } - - s->ringbuffer_mask = s->ringbuffer_size - 1; - s->ringbuffer = (uint8_t*)malloc((size_t)(s->ringbuffer_size + - kRingBufferWriteAheadSlack + - kMaxDictionaryWordLength)); - if (!s->ringbuffer) { - result = BROTLI_FAILURE(); - break; - } - s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size; - s->ringbuffer[s->ringbuffer_size - 2] = 0; - s->ringbuffer[s->ringbuffer_size - 1] = 0; - if (s->custom_dict) { - memcpy(&s->ringbuffer[(-s->custom_dict_size) & s->ringbuffer_mask], - s->custom_dict, (size_t)s->custom_dict_size); - } - } s->max_backward_distance = (1 << s->window_bits) - 16; s->max_backward_distance_minus_custom_dict_size = s->max_backward_distance - s->custom_dict_size; @@ -967,35 +1039,24 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, s->state = BROTLI_STATE_METABLOCK_BEGIN; /* No break, continue to next state */ case BROTLI_STATE_METABLOCK_BEGIN: - if (s->input_end) { - s->to_write = pos; - s->partially_written = 0; - s->state = BROTLI_STATE_DONE; - break; - } BrotliStateMetablockBegin(s); - s->state = BROTLI_STATE_METABLOCK_HEADER_1; - /* No break, continue to next state */ - case BROTLI_STATE_METABLOCK_HEADER_1: - if (!BrotliCheckInputAmount(br, 32)) { - result = BROTLI_RESULT_NEEDS_MORE_INPUT; - break; - } BROTLI_LOG_UINT(pos); - if (!DecodeMetaBlockLength(br, - &s->meta_block_remaining_len, - &s->input_end, - &is_metadata, - &is_uncompressed)) { - result = BROTLI_FAILURE(); + s->state = BROTLI_STATE_METABLOCK_HEADER; + /* No break, continue to next state */ + case BROTLI_STATE_METABLOCK_HEADER: + result = DecodeMetaBlockLength(s, br); /* Reads 2 - 31 bits. */ + if (result != BROTLI_RESULT_SUCCESS) { + i = s->loop_counter; /* Has been updated in DecodeMetaBlockLength. */ break; } BROTLI_LOG_UINT(s->meta_block_remaining_len); - if (is_metadata) { + if (s->is_metadata || s->is_uncompressed) { if (!BrotliJumpToByteBoundary(br)) { result = BROTLI_FAILURE(); break; } + } + if (s->is_metadata) { s->state = BROTLI_STATE_METADATA; break; } @@ -1003,11 +1064,13 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, s->state = BROTLI_STATE_METABLOCK_DONE; break; } - if (is_uncompressed) { - if (!BrotliJumpToByteBoundary(br)) { + if (!s->ringbuffer) { + if (!BrotliAllocateRingBuffer(s, br)) { result = BROTLI_FAILURE(); break; } + } + if (s->is_uncompressed) { s->state = BROTLI_STATE_UNCOMPRESSED; break; } @@ -1027,12 +1090,12 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, break; case BROTLI_STATE_METADATA: for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) { - if (!BrotliCheckInputAmount(br, 32)) { + uint32_t bits; + /* Read one byte and ignore it. */ + if (!BrotliSafeReadBits(br, 8, &bits)) { result = BROTLI_RESULT_NEEDS_MORE_INPUT; break; } - /* Read one byte and ignore it. */ - BrotliReadBits(br, 8); } if (result == BROTLI_RESULT_SUCCESS) { s->state = BROTLI_STATE_METABLOCK_DONE; @@ -1040,15 +1103,20 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, break; case BROTLI_STATE_HUFFMAN_CODE_0: if (i >= 3) { - BROTLI_LOG_UINT(s->num_block_type_rb[0]); - BROTLI_LOG_UINT(s->num_block_type_rb[2]); - BROTLI_LOG_UINT(s->num_block_type_rb[4]); + BROTLI_LOG_UINT(s->num_block_types[0]); + BROTLI_LOG_UINT(s->num_block_types[2]); + BROTLI_LOG_UINT(s->num_block_types[4]); BROTLI_LOG_UINT(s->block_length[0]); BROTLI_LOG_UINT(s->block_length[1]); BROTLI_LOG_UINT(s->block_length[2]); - s->state = BROTLI_STATE_METABLOCK_HEADER_2; + s->state = BROTLI_STATE_CONTEXT_MODES; break; } + if (!BrotliWarmupBitReader(br) || !BrotliCheckInputAmount(br, 8)) { + result = BROTLI_RESULT_NEEDS_MORE_INPUT; + break; + } + /* Reads 1..11 bits. */ s->num_block_types[i] = DecodeVarLenUint8(br) + 1; s->state = BROTLI_STATE_HUFFMAN_CODE_1; /* No break, continue to next state */ @@ -1070,12 +1138,19 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, &s->block_len_trees[i * BROTLI_HUFFMAN_MAX_TABLE_SIZE], NULL, s); if (result != BROTLI_RESULT_SUCCESS) break; - s->block_length[i] = ReadBlockLength( + s->state = BROTLI_STATE_HUFFMAN_CODE_3; + /* No break, continue to next state */ + case BROTLI_STATE_HUFFMAN_CODE_3: + if (!BrotliCheckInputAmount(br, 8)) { + result = BROTLI_RESULT_NEEDS_MORE_INPUT; + break; + } + s->block_length[i] = ReadBlockLength( /* Reads 3..39 bits. */ &s->block_len_trees[i * BROTLI_HUFFMAN_MAX_TABLE_SIZE], br); i++; s->state = BROTLI_STATE_HUFFMAN_CODE_0; break; - case BROTLI_STATE_METABLOCK_HEADER_2: + case BROTLI_STATE_CONTEXT_MODES: /* We need up to 256 * 2 + 6 bits, this fits in 128 bytes. */ if (!BrotliCheckInputAmount(br, 128)) { result = BROTLI_RESULT_NEEDS_MORE_INPUT; @@ -1115,12 +1190,11 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, /* No break, continue to next state */ case BROTLI_STATE_CONTEXT_MAP_2: { - int num_dist_htrees; int num_distance_codes = s->num_direct_distance_codes + (48 << s->distance_postfix_bits); result = DecodeContextMap( s->num_block_types[2] << kDistanceContextBits, - &num_dist_htrees, &s->dist_context_map, s); + &s->num_dist_htrees, &s->dist_context_map, s); if (result != BROTLI_RESULT_SUCCESS) { break; } @@ -1130,22 +1204,26 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, &s->insert_copy_hgroup, kNumInsertAndCopyCodes, s->num_block_types[1]); BrotliHuffmanTreeGroupInit( - &s->distance_hgroup, num_distance_codes, num_dist_htrees); + &s->distance_hgroup, num_distance_codes, s->num_dist_htrees); } i = 0; s->state = BROTLI_STATE_TREE_GROUP; /* No break, continue to next state */ case BROTLI_STATE_TREE_GROUP: - switch (i) { - case 0: - result = HuffmanTreeGroupDecode(&s->literal_hgroup, s); - break; - case 1: - result = HuffmanTreeGroupDecode(&s->insert_copy_hgroup, s); - break; - case 2: - result = HuffmanTreeGroupDecode(&s->distance_hgroup, s); - break; + { + HuffmanTreeGroup* hgroup = NULL; + switch (i) { + case 0: + hgroup = &s->literal_hgroup; + break; + case 1: + hgroup = &s->insert_copy_hgroup; + break; + case 2: + hgroup = &s->distance_hgroup; + break; + } + result = HuffmanTreeGroupDecode(hgroup, s); } if (result != BROTLI_RESULT_SUCCESS) break; i++; @@ -1178,12 +1256,12 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, } /* Read the insert/copy length in the command */ if (s->block_length[1] == 0) { - /* Block switch for insert/copy length */ + /* Block switch for insert/copy length. Reads 0..15 bits. */ DecodeBlockType(s->num_block_types[1], s->block_type_trees, 1, s->block_type_rb, br); s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]]; - s->block_length[1] = ReadBlockLength( + s->block_length[1] = ReadBlockLength( /* Reads 3..39 bits. */ &s->block_len_trees[BROTLI_HUFFMAN_MAX_TABLE_SIZE], br); } { @@ -1290,8 +1368,8 @@ postDecodeLiterals: int dist_context_offset; DecodeBlockType(s->num_block_types[2], s->block_type_trees, 2, - s->block_type_rb, br); - s->block_length[2] = ReadBlockLength( + s->block_type_rb, br); /* Reads 0..15 bits. */ + s->block_length[2] = ReadBlockLength( /* Reads 3..39 bits. */ &s->block_len_trees[2 * BROTLI_HUFFMAN_MAX_TABLE_SIZE], br); dist_context_offset = s->block_type_rb[5] << kDistanceContextBits; s->dist_context_map_slice = @@ -1536,8 +1614,14 @@ innerWrite: break; case BROTLI_STATE_METABLOCK_DONE: BrotliStateCleanupAfterMetablock(s); - s->state = BROTLI_STATE_METABLOCK_BEGIN; - break; + if (!s->is_last_metablock) { + s->state = BROTLI_STATE_METABLOCK_BEGIN; + break; + } + s->to_write = pos; + s->partially_written = 0; + s->state = BROTLI_STATE_DONE; + /* No break, continue to next state */ case BROTLI_STATE_DONE: if (s->ringbuffer != 0) { result = WriteRingBuffer(output, s); @@ -1548,10 +1632,9 @@ innerWrite: if (!BrotliJumpToByteBoundary(br)) { result = BROTLI_FAILURE(); } - if (BrotliGetRemainingBytes(br) < BROTLI_IMPLICIT_ZEROES) { - /* The brotli input stream was too small, does not follow the spec. It - might have decompressed fine because of the implicit 128 zeroes added. - NOTE: larger input is allowed, smaller not. */ + if (!BrotliIsBitReaderOK(br)) { + /* The brotli input stream was too small, does not follow the spec. + NOTE: larger input is allowed, smaller not. */ result = BROTLI_FAILURE(); } return result; @@ -1568,6 +1651,7 @@ void BrotliSetCustomDictionary( s->custom_dict_size = (int) size; } + #if defined(__cplusplus) || defined(c_plusplus) } /* extern "C" */ #endif diff --git a/dec/decode.h b/dec/decode.h index 07216d4..8a7919d 100644 --- a/dec/decode.h +++ b/dec/decode.h @@ -150,6 +150,7 @@ BrotliResult BrotliDecompressBufferStreaming(size_t* available_in, void BrotliSetCustomDictionary( size_t size, const uint8_t* dict, BrotliState* s); + /* Escalate internal functions visibility; for testing purposes only. */ void InverseMoveToFrontTransformForTesting(uint8_t* v, int l, BrotliState* s); diff --git a/dec/state.c b/dec/state.c index 9e890e2..b3beeb6 100644 --- a/dec/state.c +++ b/dec/state.c @@ -25,8 +25,11 @@ extern "C" { void BrotliStateInit(BrotliState* s) { s->state = BROTLI_STATE_UNINITED; - s->sub0_state = BROTLI_STATE_SUB0_NONE; - s->sub1_state = BROTLI_STATE_SUB1_NONE; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; + s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE; + s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; s->block_type_trees = NULL; s->block_len_trees = NULL; @@ -45,10 +48,11 @@ void BrotliStateInit(BrotliState* s) { s->distance_hgroup.codes = NULL; s->distance_hgroup.htrees = NULL; + s->custom_dict = NULL; s->custom_dict_size = 0; - s->input_end = 0; + s->is_last_metablock = 0; s->window_bits = 0; s->max_distance = 0; s->dist_rb[0] = 16; diff --git a/dec/state.h b/dec/state.h index d072e00..82ce22b 100644 --- a/dec/state.h +++ b/dec/state.h @@ -32,8 +32,8 @@ typedef enum { BROTLI_STATE_UNINITED, BROTLI_STATE_BITREADER_WARMUP, BROTLI_STATE_METABLOCK_BEGIN, - BROTLI_STATE_METABLOCK_HEADER_1, - BROTLI_STATE_METABLOCK_HEADER_2, + BROTLI_STATE_METABLOCK_HEADER, + BROTLI_STATE_CONTEXT_MODES, BROTLI_STATE_COMMAND_BEGIN, BROTLI_STATE_COMMAND_INNER, BROTLI_STATE_UNCOMPRESSED, @@ -46,6 +46,7 @@ typedef enum { BROTLI_STATE_HUFFMAN_CODE_0, BROTLI_STATE_HUFFMAN_CODE_1, BROTLI_STATE_HUFFMAN_CODE_2, + BROTLI_STATE_HUFFMAN_CODE_3, BROTLI_STATE_CONTEXT_MAP_1, BROTLI_STATE_CONTEXT_MAP_2, BROTLI_STATE_TREE_GROUP, @@ -53,23 +54,41 @@ typedef enum { } BrotliRunningState; typedef enum { - BROTLI_STATE_SUB0_NONE, - BROTLI_STATE_SUB0_UNCOMPRESSED_SHORT, - BROTLI_STATE_SUB0_UNCOMPRESSED_FILL, - BROTLI_STATE_SUB0_UNCOMPRESSED_COPY, - BROTLI_STATE_SUB0_UNCOMPRESSED_WARMUP, - BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_1, - BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_2, - BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_3, - BROTLI_STATE_SUB0_TREE_GROUP, - BROTLI_STATE_SUB0_CONTEXT_MAP_HUFFMAN, - BROTLI_STATE_SUB0_CONTEXT_MAPS -} BrotliRunningSub0State; + BROTLI_STATE_METABLOCK_HEADER_NONE, + BROTLI_STATE_METABLOCK_HEADER_EMPTY, + BROTLI_STATE_METABLOCK_HEADER_NIBBLES, + BROTLI_STATE_METABLOCK_HEADER_SIZE, + BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED, + BROTLI_STATE_METABLOCK_HEADER_RESERVED, + BROTLI_STATE_METABLOCK_HEADER_BYTES, + BROTLI_STATE_METABLOCK_HEADER_METADATA +} BrotliRunningMetablockHeaderState; typedef enum { - BROTLI_STATE_SUB1_NONE, - BROTLI_STATE_SUB1_HUFFMAN_LENGTH_SYMBOLS -} BrotliRunningSub1State; + BROTLI_STATE_UNCOMPRESSED_NONE, + BROTLI_STATE_UNCOMPRESSED_SHORT, + BROTLI_STATE_UNCOMPRESSED_FILL, + BROTLI_STATE_UNCOMPRESSED_COPY, + BROTLI_STATE_UNCOMPRESSED_WRITE_1, + BROTLI_STATE_UNCOMPRESSED_WRITE_2, + BROTLI_STATE_UNCOMPRESSED_WRITE_3 +} BrotliRunningUncompressedState; + +typedef enum { + BROTLI_STATE_TREE_GROUP_NONE, + BROTLI_STATE_TREE_GROUP_LOOP +} BrotliRunningTreeGroupState; + +typedef enum { + BROTLI_STATE_CONTEXT_MAP_NONE, + BROTLI_STATE_CONTEXT_MAP_HUFFMAN, + BROTLI_STATE_CONTEXT_MAP_DECODE +} BrotliRunningContextMapState; + +typedef enum { + BROTLI_STATE_HUFFMAN_NONE, + BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS +} BrotliRunningHuffmanState; typedef struct { BrotliRunningState state; @@ -110,13 +129,15 @@ typedef struct { int distance_postfix_bits; int num_direct_distance_codes; int distance_postfix_mask; + int num_dist_htrees; uint8_t* dist_context_map; - uint8_t literal_htree_index; HuffmanCode *literal_htree; + uint8_t literal_htree_index; uint8_t dist_htree_index; uint8_t repeat_code_len; uint8_t prev_code_len; + int copy_length; int distance_code; @@ -159,10 +180,17 @@ typedef struct { 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 */ + /* States inside function calls */ + BrotliRunningMetablockHeaderState substate_metablock_header; + BrotliRunningTreeGroupState substate_tree_group; + BrotliRunningContextMapState substate_context_map; + BrotliRunningUncompressedState substate_uncompressed; + BrotliRunningHuffmanState substate_huffman; - int input_end; + uint8_t is_last_metablock; + uint8_t is_uncompressed; + uint8_t is_metadata; + uint8_t size_nibbles; uint32_t window_bits; /* For CopyUncompressedBlockToOutput */