mirror of https://github.com/google/brotli
Merge pull request #164 from szabadka/master
Update brotli decoder with latest improvements.
This commit is contained in:
commit
b3905e8075
|
@ -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)
|
||||
|
|
111
dec/bit_reader.h
111
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
|
||||
|
|
612
dec/decode.c
612
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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
10
dec/state.c
10
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;
|
||||
|
|
70
dec/state.h
70
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 */
|
||||
|
|
Loading…
Reference in New Issue