Merge pull request #358 from eustas/master

Update decoder
This commit is contained in:
eustas 2016-06-02 11:36:28 +02:00
commit 37984adb6a
4 changed files with 111 additions and 83 deletions

View File

@ -1066,22 +1066,45 @@ static BROTLI_INLINE int DecodeBlockTypeAndLength(int safe,
return 1; 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. /* Decodes the block type and updates the state for literal context.
Reads 3..54 bits. */ Reads 3..54 bits. */
static BROTLI_INLINE int DecodeLiteralBlockSwitchInternal(int safe, static BROTLI_INLINE int DecodeLiteralBlockSwitchInternal(int safe,
BrotliState* s) { BrotliState* s) {
uint8_t context_mode;
uint32_t context_offset;
if (!DecodeBlockTypeAndLength(safe, s, 0)) { if (!DecodeBlockTypeAndLength(safe, s, 0)) {
return 0; return 0;
} }
context_offset = s->block_type_rb[1] << kLiteralContextBits; PrepareLiteralDecoding(s);
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]];
return 1; return 1;
} }
@ -1153,7 +1176,7 @@ static BrotliErrorCode BROTLI_NOINLINE WriteRingBuffer(size_t* available_out,
BROTLI_LOG_UINT(to_write); BROTLI_LOG_UINT(to_write);
BROTLI_LOG_UINT(num_written); BROTLI_LOG_UINT(num_written);
s->partial_pos_out += 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) { if (num_written < to_write) {
return BROTLI_NEEDS_MORE_OUTPUT; return BROTLI_NEEDS_MORE_OUTPUT;
} }
@ -1566,6 +1589,7 @@ CommandInner:
if (PREDICT_FALSE(s->block_length[0] == 0)) { if (PREDICT_FALSE(s->block_length[0] == 0)) {
BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
PreloadSymbol(safe, s->literal_htree, br, &bits, &value); PreloadSymbol(safe, s->literal_htree, br, &bits, &value);
if (!s->trivial_literal_context) goto CommandInner;
} }
if (!safe) { if (!safe) {
s->ringbuffer[pos] = s->ringbuffer[pos] =
@ -1579,7 +1603,6 @@ CommandInner:
s->ringbuffer[pos] = (uint8_t)literal; s->ringbuffer[pos] = (uint8_t)literal;
} }
--s->block_length[0]; --s->block_length[0];
BROTLI_LOG_UINT(s->literal_htree_index);
BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos); BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos);
++pos; ++pos;
if (PREDICT_FALSE(pos == s->ringbuffer_size)) { if (PREDICT_FALSE(pos == s->ringbuffer_size)) {
@ -1601,6 +1624,7 @@ CommandInner:
} }
if (PREDICT_FALSE(s->block_length[0] == 0)) { if (PREDICT_FALSE(s->block_length[0] == 0)) {
BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
if (s->trivial_literal_context) goto CommandInner;
} }
context = s->context_lookup1[p1] | s->context_lookup2[p2]; context = s->context_lookup1[p1] | s->context_lookup2[p2];
BROTLI_LOG_UINT(context); BROTLI_LOG_UINT(context);
@ -1629,7 +1653,7 @@ CommandInner:
} while (--i != 0); } while (--i != 0);
} }
BROTLI_LOG_UINT(s->meta_block_remaining_len); 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; s->state = BROTLI_STATE_METABLOCK_DONE;
goto saveStateAndReturn; goto saveStateAndReturn;
} }
@ -1709,12 +1733,6 @@ postReadDistance:
s->dist_rb[s->dist_rb_idx & 3] = s->distance_code; s->dist_rb[s->dist_rb_idx & 3] = s->distance_code;
++s->dist_rb_idx; ++s->dist_rb_idx;
s->meta_block_remaining_len -= i; 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. /* There are 32+ bytes of slack in the ringbuffer allocation.
Also, we have 16 short codes, that make these 16 bytes irrelevant Also, we have 16 short codes, that make these 16 bytes irrelevant
in the ringbuffer. Let's copy over them as a first guess. 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; s->state = BROTLI_STATE_CONTEXT_MAP_1;
/* No break, continue to next state */ /* No break, continue to next state */
case BROTLI_STATE_CONTEXT_MAP_1: { case BROTLI_STATE_CONTEXT_MAP_1:
uint32_t j; result = DecodeContextMap(
result = DecodeContextMap(s->num_block_types[0] << kLiteralContextBits, s->num_block_types[0] << kLiteralContextBits,
&s->num_literal_htrees, &s->context_map, s); &s->num_literal_htrees, &s->context_map, s);
if (result != BROTLI_SUCCESS) { if (result != BROTLI_SUCCESS) {
break; break;
} }
s->trivial_literal_context = 1; DetectTrivialLiteralBlockTypes(s);
for (j = 0; j < s->num_block_types[0] << kLiteralContextBits; j++) {
if (s->context_map[j] != j >> kLiteralContextBits) {
s->trivial_literal_context = 0;
break;
}
}
s->state = BROTLI_STATE_CONTEXT_MAP_2; s->state = BROTLI_STATE_CONTEXT_MAP_2;
/* No break, continue to next state */ /* No break, continue to next state */
}
case BROTLI_STATE_CONTEXT_MAP_2: case BROTLI_STATE_CONTEXT_MAP_2:
{ {
uint32_t num_distance_codes = uint32_t num_distance_codes =
@ -2137,15 +2148,9 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
if (result != BROTLI_SUCCESS) break; if (result != BROTLI_SUCCESS) break;
s->loop_counter++; s->loop_counter++;
if (s->loop_counter >= 3) { if (s->loop_counter >= 3) {
uint8_t context_mode = s->context_modes[s->block_type_rb[1]]; PrepareLiteralDecoding(s);
s->context_map_slice = s->context_map;
s->dist_context_map_slice = s->dist_context_map; 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->htree_command = s->insert_copy_hgroup.htrees[0];
s->literal_htree = s->literal_hgroup.htrees[s->literal_htree_index];
if (!s->ringbuffer && !BrotliAllocateRingBuffer(s)) { if (!s->ringbuffer && !BrotliAllocateRingBuffer(s)) {
result = BROTLI_FAILURE(BROTLI_ERROR_ALLOC_RING_BUFFER_2); result = BROTLI_FAILURE(BROTLI_ERROR_ALLOC_RING_BUFFER_2);
break; break;
@ -2194,6 +2199,10 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
} }
break; break;
case BROTLI_STATE_METABLOCK_DONE: case BROTLI_STATE_METABLOCK_DONE:
if (s->meta_block_remaining_len < 0) {
result = BROTLI_FAILURE(BROTLI_ERROR_FORMAT_BLOCK_LENGTH_2);
break;
}
BrotliStateCleanupAfterMetablock(s); BrotliStateCleanupAfterMetablock(s);
if (!s->is_last_metablock) { if (!s->is_last_metablock) {
s->state = BROTLI_STATE_METABLOCK_BEGIN; s->state = BROTLI_STATE_METABLOCK_BEGIN;

View File

@ -28,49 +28,57 @@ typedef enum {
BROTLI_RESULT_NEEDS_MORE_OUTPUT = 3 BROTLI_RESULT_NEEDS_MORE_OUTPUT = 3
} BrotliResult; } 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 { typedef enum {
BROTLI_NO_ERROR = 0, #define _BROTLI_COMMA /**/,
/* Same as BrotliResult values */ #define _BROTLI_ERROR_CODE_ENUM_ITEM(NAME, CODE) NAME = CODE
BROTLI_SUCCESS = 1, BROTLI_ERROR_CODES_LIST(_BROTLI_ERROR_CODE_ENUM_ITEM, _BROTLI_COMMA)
BROTLI_NEEDS_MORE_INPUT = 2, #undef _BROTLI_ERROR_CODE_ENUM_ITEM
BROTLI_NEEDS_MORE_OUTPUT = 3, #undef _BROTLI_COMMA
/* 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
} BrotliErrorCode; } BrotliErrorCode;
#define BROTLI_LAST_ERROR_CODE BROTLI_ERROR_UNREACHABLE_6 #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 bytes consumed, and the |*next_in| pointer will be incremented by that
amount. Similarly, |*available_out| will be decremented by the amount of amount. Similarly, |*available_out| will be decremented by the amount of
output bytes written, and the |*next_out| pointer will be incremented by that 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 amount. |total_out|, if it is not a null-pointer, will be set to the number
last state initialization. of bytes decompressed since the last state initialization.
Input is never overconsumed, so |next_in| and |available_in| could be passed Input is never overconsumed, so |next_in| and |available_in| could be passed
to the next consumer after decoding is complete. */ to the next consumer after decoding is complete. */
@ -149,6 +157,17 @@ int BrotliStateIsStreamEnd(const BrotliState* s);
BROTLI_RESULT_ERROR. */ BROTLI_RESULT_ERROR. */
BrotliErrorCode BrotliGetErrorCode(const BrotliState* s); BrotliErrorCode BrotliGetErrorCode(const BrotliState* s);
static 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) #if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */ } /* extern "C" */
#endif #endif

View File

@ -118,7 +118,6 @@ void BrotliStateMetablockBegin(BrotliState* s) {
s->context_modes = NULL; s->context_modes = NULL;
s->dist_context_map = NULL; s->dist_context_map = NULL;
s->context_map_slice = NULL; s->context_map_slice = NULL;
s->literal_htree_index = 0;
s->literal_htree = NULL; s->literal_htree = NULL;
s->dist_context_map_slice = NULL; s->dist_context_map_slice = NULL;
s->dist_htree_index = 0; s->dist_htree_index = 0;

View File

@ -152,7 +152,6 @@ struct BrotliStateStruct {
uint32_t num_dist_htrees; uint32_t num_dist_htrees;
uint8_t* dist_context_map; uint8_t* dist_context_map;
HuffmanCode* literal_htree; HuffmanCode* literal_htree;
uint8_t literal_htree_index;
uint8_t dist_htree_index; uint8_t dist_htree_index;
uint32_t repeat_code_len; uint32_t repeat_code_len;
uint32_t prev_code_len; uint32_t prev_code_len;
@ -218,6 +217,8 @@ struct BrotliStateStruct {
uint32_t num_literal_htrees; uint32_t num_literal_htrees;
uint8_t* context_map; uint8_t* context_map;
uint8_t* context_modes; uint8_t* context_modes;
uint32_t trivial_literal_contexts[8]; /* 256 bits */
}; };
typedef struct BrotliStateStruct BrotliStateInternal; typedef struct BrotliStateStruct BrotliStateInternal;