diff --git a/dec/decode.c b/dec/decode.c index 8dc55a0..bbdf5f1 100644 --- a/dec/decode.c +++ b/dec/decode.c @@ -86,26 +86,40 @@ static BROTLI_INLINE int DecodeVarLenUint8(BrotliBitReader* br) { return 0; } -static void DecodeMetaBlockLength(BrotliBitReader* br, - int* meta_block_length, - int* input_end, - int* is_uncompressed) { +static int DecodeMetaBlockLength(BrotliBitReader* br, + int* meta_block_length, + int* input_end, + int* is_metadata, + int* is_uncompressed) { int size_nibbles; 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; + return 1; } size_nibbles = (int)BrotliReadBits(br, 2) + 4; + if (size_nibbles == 7) { + *is_metadata = 1; + /* Verify reserved bit. */ + if (BrotliReadBits(br, 1) != 0) { + return 0; + } + size_nibbles = 2 * (int)BrotliReadBits(br, 2); + if (size_nibbles == 0) { + return 1; + } + } for (i = 0; i < size_nibbles; ++i) { *meta_block_length |= (int)BrotliReadBits(br, 4) << (i * 4); } ++(*meta_block_length); - if (!*input_end) { + if (!*input_end && !*is_metadata) { *is_uncompressed = (int)BrotliReadBits(br, 1); } + return 1; } /* Decodes the next Huffman code from bit-stream. */ @@ -375,13 +389,6 @@ static int TranslateShortCodes(int code, int* ringbuffer, int index) { return val; } -static void MoveToFront(uint8_t* v, uint8_t index) { - uint8_t value = v[index]; - uint8_t i = index; - for (; i; --i) v[i] = v[i - 1]; - v[0] = value; -} - static void InverseMoveToFrontTransform(uint8_t* v, int v_len) { uint8_t mtf[256]; int i; @@ -390,8 +397,12 @@ static void InverseMoveToFrontTransform(uint8_t* v, int v_len) { } for (i = 0; i < v_len; ++i) { uint8_t index = v[i]; - v[i] = mtf[index]; - if (index) MoveToFront(mtf, index); + uint8_t value = mtf[index]; + v[i] = value; + for (; index; --index) { + mtf[index] = mtf[index - 1]; + } + mtf[0] = value; } } @@ -971,9 +982,20 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, break; } BROTLI_LOG_UINT(pos); - DecodeMetaBlockLength(br, &s->meta_block_remaining_len, - &s->input_end, &s->is_uncompressed); + if (!DecodeMetaBlockLength(br, + &s->meta_block_remaining_len, + &s->input_end, + &s->is_metadata, + &s->is_uncompressed)) { + result = BROTLI_RESULT_ERROR; + break; + } BROTLI_LOG_UINT(s->meta_block_remaining_len); + if (s->is_metadata) { + BrotliSetBitPos(br, (s->br.bit_pos_ + 7) & (uint32_t)(~7UL)); + s->state = BROTLI_STATE_METADATA; + break; + } if (s->meta_block_remaining_len == 0) { s->state = BROTLI_STATE_METABLOCK_DONE; break; @@ -1000,6 +1022,17 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, if (result != BROTLI_RESULT_SUCCESS) break; s->state = BROTLI_STATE_METABLOCK_DONE; break; + case BROTLI_STATE_METADATA: + for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) { + if (!BrotliReadMoreInput(&s->br)) { + result = BROTLI_RESULT_PARTIAL; + break; + } + /* Read one byte and ignore it. */ + BrotliReadBits(&s->br, 8); + } + s->state = BROTLI_STATE_METABLOCK_DONE; + break; case BROTLI_STATE_HUFFMAN_CODE_0: if (i >= 3) { BROTLI_LOG_UINT(s->num_block_types[0]); diff --git a/dec/state.h b/dec/state.h index 3b985ec..aa5b43a 100644 --- a/dec/state.h +++ b/dec/state.h @@ -39,6 +39,7 @@ typedef enum { BROTLI_STATE_BLOCK_DISTANCE = 15, BROTLI_STATE_BLOCK_POST = 16, BROTLI_STATE_UNCOMPRESSED = 17, + BROTLI_STATE_METADATA = 18, BROTLI_STATE_METABLOCK_DONE = 20, BROTLI_STATE_HUFFMAN_CODE_0 = 30, BROTLI_STATE_HUFFMAN_CODE_1 = 31, @@ -91,6 +92,7 @@ typedef struct { int trivial_literal_context; int meta_block_remaining_len; + int is_metadata; int is_uncompressed; int block_length[3]; int block_type[3];