mirror of
https://github.com/google/brotli.git
synced 2024-11-22 19:50:06 +00:00
Update decoder
* More discreet trivial literal context detection * Make total_out parameter nullable * More strict stream validity check * Added BrotliErrorString
This commit is contained in:
parent
3e528595e0
commit
755b909424
83
dec/decode.c
83
dec/decode.c
@ -1066,22 +1066,45 @@ static BROTLI_INLINE int DecodeBlockTypeAndLength(int safe,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void DetectTrivialLiteralBlockTypes(BrotliState* s) {
|
||||
size_t i;
|
||||
for (i = 0; i < 8; ++i) s->trivial_literal_contexts[i] = 0;
|
||||
for (i = 0; i < s->num_block_types[0]; i++) {
|
||||
size_t offset = i << kLiteralContextBits;
|
||||
size_t error = 0;
|
||||
size_t sample = s->context_map[offset];
|
||||
size_t j;
|
||||
for (j = 0; j < (1u << kLiteralContextBits);) {
|
||||
BROTLI_REPEAT(4, error |= s->context_map[offset + j++] ^ sample;)
|
||||
}
|
||||
if (error == 0) {
|
||||
s->trivial_literal_contexts[i >> 5] |= 1u << (i & 31);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void PrepareLiteralDecoding(BrotliState* s) {
|
||||
uint8_t context_mode;
|
||||
size_t trivial;
|
||||
uint32_t block_type = s->block_type_rb[1];
|
||||
uint32_t context_offset = block_type << kLiteralContextBits;
|
||||
s->context_map_slice = s->context_map + context_offset;
|
||||
trivial = s->trivial_literal_contexts[block_type >> 5];
|
||||
s->trivial_literal_context = (trivial >> (block_type & 31)) & 1;
|
||||
s->literal_htree = s->literal_hgroup.htrees[s->context_map_slice[0]];
|
||||
context_mode = s->context_modes[block_type];
|
||||
s->context_lookup1 = &kContextLookup[kContextLookupOffsets[context_mode]];
|
||||
s->context_lookup2 = &kContextLookup[kContextLookupOffsets[context_mode + 1]];
|
||||
}
|
||||
|
||||
/* Decodes the block type and updates the state for literal context.
|
||||
Reads 3..54 bits. */
|
||||
static BROTLI_INLINE int DecodeLiteralBlockSwitchInternal(int safe,
|
||||
BrotliState* s) {
|
||||
uint8_t context_mode;
|
||||
uint32_t context_offset;
|
||||
if (!DecodeBlockTypeAndLength(safe, s, 0)) {
|
||||
return 0;
|
||||
}
|
||||
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];
|
||||
s->literal_htree = s->literal_hgroup.htrees[s->literal_htree_index];
|
||||
context_mode = s->context_modes[s->block_type_rb[1]];
|
||||
s->context_lookup1 = &kContextLookup[kContextLookupOffsets[context_mode]];
|
||||
s->context_lookup2 = &kContextLookup[kContextLookupOffsets[context_mode + 1]];
|
||||
PrepareLiteralDecoding(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1153,7 +1176,7 @@ static BrotliErrorCode BROTLI_NOINLINE WriteRingBuffer(size_t* available_out,
|
||||
BROTLI_LOG_UINT(to_write);
|
||||
BROTLI_LOG_UINT(num_written);
|
||||
s->partial_pos_out += num_written;
|
||||
*total_out = s->partial_pos_out;
|
||||
if (total_out) *total_out = s->partial_pos_out;
|
||||
if (num_written < to_write) {
|
||||
return BROTLI_NEEDS_MORE_OUTPUT;
|
||||
}
|
||||
@ -1566,6 +1589,7 @@ CommandInner:
|
||||
if (PREDICT_FALSE(s->block_length[0] == 0)) {
|
||||
BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
|
||||
PreloadSymbol(safe, s->literal_htree, br, &bits, &value);
|
||||
if (!s->trivial_literal_context) goto CommandInner;
|
||||
}
|
||||
if (!safe) {
|
||||
s->ringbuffer[pos] =
|
||||
@ -1579,7 +1603,6 @@ CommandInner:
|
||||
s->ringbuffer[pos] = (uint8_t)literal;
|
||||
}
|
||||
--s->block_length[0];
|
||||
BROTLI_LOG_UINT(s->literal_htree_index);
|
||||
BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos);
|
||||
++pos;
|
||||
if (PREDICT_FALSE(pos == s->ringbuffer_size)) {
|
||||
@ -1601,6 +1624,7 @@ CommandInner:
|
||||
}
|
||||
if (PREDICT_FALSE(s->block_length[0] == 0)) {
|
||||
BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
|
||||
if (s->trivial_literal_context) goto CommandInner;
|
||||
}
|
||||
context = s->context_lookup1[p1] | s->context_lookup2[p2];
|
||||
BROTLI_LOG_UINT(context);
|
||||
@ -1629,7 +1653,7 @@ CommandInner:
|
||||
} while (--i != 0);
|
||||
}
|
||||
BROTLI_LOG_UINT(s->meta_block_remaining_len);
|
||||
if (s->meta_block_remaining_len <= 0) {
|
||||
if (PREDICT_FALSE(s->meta_block_remaining_len <= 0)) {
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
goto saveStateAndReturn;
|
||||
}
|
||||
@ -1709,12 +1733,6 @@ postReadDistance:
|
||||
s->dist_rb[s->dist_rb_idx & 3] = s->distance_code;
|
||||
++s->dist_rb_idx;
|
||||
s->meta_block_remaining_len -= i;
|
||||
if (PREDICT_FALSE(s->meta_block_remaining_len < 0)) {
|
||||
BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
|
||||
"len: %d bytes left: %d\n",
|
||||
pos, s->distance_code, i, s->meta_block_remaining_len));
|
||||
return BROTLI_FAILURE(BROTLI_ERROR_FORMAT_BLOCK_LENGTH_2);
|
||||
}
|
||||
/* There are 32+ bytes of slack in the ringbuffer allocation.
|
||||
Also, we have 16 short codes, that make these 16 bytes irrelevant
|
||||
in the ringbuffer. Let's copy over them as a first guess.
|
||||
@ -2071,23 +2089,16 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
}
|
||||
s->state = BROTLI_STATE_CONTEXT_MAP_1;
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_CONTEXT_MAP_1: {
|
||||
uint32_t j;
|
||||
result = DecodeContextMap(s->num_block_types[0] << kLiteralContextBits,
|
||||
&s->num_literal_htrees, &s->context_map, s);
|
||||
case BROTLI_STATE_CONTEXT_MAP_1:
|
||||
result = DecodeContextMap(
|
||||
s->num_block_types[0] << kLiteralContextBits,
|
||||
&s->num_literal_htrees, &s->context_map, s);
|
||||
if (result != BROTLI_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
s->trivial_literal_context = 1;
|
||||
for (j = 0; j < s->num_block_types[0] << kLiteralContextBits; j++) {
|
||||
if (s->context_map[j] != j >> kLiteralContextBits) {
|
||||
s->trivial_literal_context = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DetectTrivialLiteralBlockTypes(s);
|
||||
s->state = BROTLI_STATE_CONTEXT_MAP_2;
|
||||
/* No break, continue to next state */
|
||||
}
|
||||
case BROTLI_STATE_CONTEXT_MAP_2:
|
||||
{
|
||||
uint32_t num_distance_codes =
|
||||
@ -2137,15 +2148,9 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
if (result != BROTLI_SUCCESS) break;
|
||||
s->loop_counter++;
|
||||
if (s->loop_counter >= 3) {
|
||||
uint8_t context_mode = s->context_modes[s->block_type_rb[1]];
|
||||
s->context_map_slice = s->context_map;
|
||||
PrepareLiteralDecoding(s);
|
||||
s->dist_context_map_slice = s->dist_context_map;
|
||||
s->context_lookup1 =
|
||||
&kContextLookup[kContextLookupOffsets[context_mode]];
|
||||
s->context_lookup2 =
|
||||
&kContextLookup[kContextLookupOffsets[context_mode + 1]];
|
||||
s->htree_command = s->insert_copy_hgroup.htrees[0];
|
||||
s->literal_htree = s->literal_hgroup.htrees[s->literal_htree_index];
|
||||
if (!s->ringbuffer && !BrotliAllocateRingBuffer(s)) {
|
||||
result = BROTLI_FAILURE(BROTLI_ERROR_ALLOC_RING_BUFFER_2);
|
||||
break;
|
||||
@ -2194,6 +2199,10 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
}
|
||||
break;
|
||||
case BROTLI_STATE_METABLOCK_DONE:
|
||||
if (s->meta_block_remaining_len < 0) {
|
||||
result = BROTLI_FAILURE(BROTLI_ERROR_FORMAT_BLOCK_LENGTH_2);
|
||||
break;
|
||||
}
|
||||
BrotliStateCleanupAfterMetablock(s);
|
||||
if (!s->is_last_metablock) {
|
||||
s->state = BROTLI_STATE_METABLOCK_BEGIN;
|
||||
|
107
dec/decode.h
107
dec/decode.h
@ -28,49 +28,57 @@ typedef enum {
|
||||
BROTLI_RESULT_NEEDS_MORE_OUTPUT = 3
|
||||
} BrotliResult;
|
||||
|
||||
#define BROTLI_ERROR_CODES_LIST(BROTLI_ERROR_CODE, SEPARATOR) \
|
||||
BROTLI_ERROR_CODE(BROTLI_NO_ERROR, 0) SEPARATOR \
|
||||
/* Same as BrotliResult values */ \
|
||||
BROTLI_ERROR_CODE(BROTLI_SUCCESS, 1) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_NEEDS_MORE_INPUT, 2) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_NEEDS_MORE_OUTPUT, 3) SEPARATOR \
|
||||
\
|
||||
/* Errors caused by invalid input */ \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_EXUBERANT_NIBBLE, -1) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_RESERVED, -2) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_EXUBERANT_META_NIBBLE, -3) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET, -4) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME, -5) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_CL_SPACE, -6) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_HUFFMAN_SPACE, -7) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_CONTEXT_MAP_REPEAT, -8) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_BLOCK_LENGTH_1, -9) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_BLOCK_LENGTH_2, -10) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_TRANSFORM, -11) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_DICTIONARY, -12) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_WINDOW_BITS, -13) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_PADDING_1, -14) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_FORMAT_PADDING_2, -15) SEPARATOR \
|
||||
\
|
||||
/* -16..-20 codes are reserved */ \
|
||||
\
|
||||
/* Memory allocation problems */ \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_ALLOC_CONTEXT_MODES, -21) SEPARATOR \
|
||||
/* Literal, insert and distance trees together */ \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_ALLOC_TREE_GROUPS, -22) SEPARATOR \
|
||||
/* -23..-24 codes are reserved for distinct tree groups */ \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_ALLOC_CONTEXT_MAP, -25) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_ALLOC_RING_BUFFER_1, -26) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_ALLOC_RING_BUFFER_2, -27) SEPARATOR \
|
||||
/* -28..-29 codes are reserved for dynamic ringbuffer allocation */ \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_ALLOC_BLOCK_TYPE_TREES, -30) SEPARATOR \
|
||||
\
|
||||
/* "Impossible" states */ \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_UNREACHABLE_1, -31) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_UNREACHABLE_2, -32) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_UNREACHABLE_3, -33) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_UNREACHABLE_4, -34) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_UNREACHABLE_5, -35) SEPARATOR \
|
||||
BROTLI_ERROR_CODE(BROTLI_ERROR_UNREACHABLE_6, -36)
|
||||
|
||||
typedef enum {
|
||||
BROTLI_NO_ERROR = 0,
|
||||
/* Same as BrotliResult values */
|
||||
BROTLI_SUCCESS = 1,
|
||||
BROTLI_NEEDS_MORE_INPUT = 2,
|
||||
BROTLI_NEEDS_MORE_OUTPUT = 3,
|
||||
|
||||
/* Errors caused by invalid input */
|
||||
BROTLI_ERROR_FORMAT_EXUBERANT_NIBBLE = -1,
|
||||
BROTLI_ERROR_FORMAT_RESERVED = -2,
|
||||
BROTLI_ERROR_FORMAT_EXUBERANT_META_NIBBLE = -3,
|
||||
BROTLI_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET = -4,
|
||||
BROTLI_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME = -5,
|
||||
BROTLI_ERROR_FORMAT_CL_SPACE = -6,
|
||||
BROTLI_ERROR_FORMAT_HUFFMAN_SPACE = -7,
|
||||
BROTLI_ERROR_FORMAT_CONTEXT_MAP_REPEAT = -8,
|
||||
BROTLI_ERROR_FORMAT_BLOCK_LENGTH_1 = -9,
|
||||
BROTLI_ERROR_FORMAT_BLOCK_LENGTH_2 = -10,
|
||||
BROTLI_ERROR_FORMAT_TRANSFORM = -11,
|
||||
BROTLI_ERROR_FORMAT_DICTIONARY = -12,
|
||||
BROTLI_ERROR_FORMAT_WINDOW_BITS = -13,
|
||||
BROTLI_ERROR_FORMAT_PADDING_1 = -14,
|
||||
BROTLI_ERROR_FORMAT_PADDING_2 = -15,
|
||||
|
||||
/* -16..-20 codes are reserved */
|
||||
|
||||
/* Memory allocation problems */
|
||||
BROTLI_ERROR_ALLOC_CONTEXT_MODES = -21,
|
||||
BROTLI_ERROR_ALLOC_TREE_GROUPS = -22, /* Literal, insert, distance */
|
||||
/* -23..-24 codes are reserved for distinct tree groups */
|
||||
BROTLI_ERROR_ALLOC_CONTEXT_MAP = -25,
|
||||
BROTLI_ERROR_ALLOC_RING_BUFFER_1 = -26,
|
||||
BROTLI_ERROR_ALLOC_RING_BUFFER_2 = -27,
|
||||
/* -28..-29 codes are reserved for dynamic ringbuffer allocation */
|
||||
BROTLI_ERROR_ALLOC_BLOCK_TYPE_TREES = -30,
|
||||
|
||||
/* "Impossible" states */
|
||||
BROTLI_ERROR_UNREACHABLE_1 = -31,
|
||||
BROTLI_ERROR_UNREACHABLE_2 = -32,
|
||||
BROTLI_ERROR_UNREACHABLE_3 = -33,
|
||||
BROTLI_ERROR_UNREACHABLE_4 = -34,
|
||||
BROTLI_ERROR_UNREACHABLE_5 = -35,
|
||||
BROTLI_ERROR_UNREACHABLE_6 = -36
|
||||
#define _BROTLI_COMMA /**/,
|
||||
#define _BROTLI_ERROR_CODE_ENUM_ITEM(NAME, CODE) NAME = CODE
|
||||
BROTLI_ERROR_CODES_LIST(_BROTLI_ERROR_CODE_ENUM_ITEM, _BROTLI_COMMA)
|
||||
#undef _BROTLI_ERROR_CODE_ENUM_ITEM
|
||||
#undef _BROTLI_COMMA
|
||||
} BrotliErrorCode;
|
||||
|
||||
#define BROTLI_LAST_ERROR_CODE BROTLI_ERROR_UNREACHABLE_6
|
||||
@ -111,8 +119,8 @@ BrotliResult BrotliDecompressBuffer(size_t encoded_size,
|
||||
bytes consumed, and the |*next_in| pointer will be incremented by that
|
||||
amount. Similarly, |*available_out| will be decremented by the amount of
|
||||
output bytes written, and the |*next_out| pointer will be incremented by that
|
||||
amount. |total_out| will be set to the number of bytes decompressed since
|
||||
last state initialization.
|
||||
amount. |total_out|, if it is not a null-pointer, will be set to the number
|
||||
of bytes decompressed since the last state initialization.
|
||||
|
||||
Input is never overconsumed, so |next_in| and |available_in| could be passed
|
||||
to the next consumer after decoding is complete. */
|
||||
@ -149,6 +157,17 @@ int BrotliStateIsStreamEnd(const BrotliState* s);
|
||||
BROTLI_RESULT_ERROR. */
|
||||
BrotliErrorCode BrotliGetErrorCode(const BrotliState* s);
|
||||
|
||||
static inline const char* BrotliErrorString(BrotliErrorCode c) {
|
||||
switch (c) {
|
||||
#define _BROTLI_ERROR_CODE_CASE(NAME, CODE) case NAME: return #NAME;
|
||||
#define _BROTLI_NOTHING
|
||||
BROTLI_ERROR_CODES_LIST(_BROTLI_ERROR_CODE_CASE, _BROTLI_NOTHING)
|
||||
#undef _BROTLI_ERROR_CODE_CASE
|
||||
#undef _BROTLI_NOTHING
|
||||
default: return "INVALID BrotliErrorCode";
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
@ -118,7 +118,6 @@ void BrotliStateMetablockBegin(BrotliState* s) {
|
||||
s->context_modes = NULL;
|
||||
s->dist_context_map = NULL;
|
||||
s->context_map_slice = NULL;
|
||||
s->literal_htree_index = 0;
|
||||
s->literal_htree = NULL;
|
||||
s->dist_context_map_slice = NULL;
|
||||
s->dist_htree_index = 0;
|
||||
|
@ -152,7 +152,6 @@ struct BrotliStateStruct {
|
||||
uint32_t num_dist_htrees;
|
||||
uint8_t* dist_context_map;
|
||||
HuffmanCode* literal_htree;
|
||||
uint8_t literal_htree_index;
|
||||
uint8_t dist_htree_index;
|
||||
uint32_t repeat_code_len;
|
||||
uint32_t prev_code_len;
|
||||
@ -218,6 +217,8 @@ struct BrotliStateStruct {
|
||||
uint32_t num_literal_htrees;
|
||||
uint8_t* context_map;
|
||||
uint8_t* context_modes;
|
||||
|
||||
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
||||
};
|
||||
|
||||
typedef struct BrotliStateStruct BrotliStateInternal;
|
||||
|
Loading…
Reference in New Issue
Block a user