Update decoder:

* use BROTLI_MAX_DISTANCE_BITS instead of magic constant
 * introduce BROTLI_DEPRECATED
 * move BROTLI_RESTRICT to common/port.h
 * promote reg_t to dec/port.h
 * remove deprecated decoder API
 * more optimistic ring-buffer allocation
 * fix MSVC warnings
 * fix (not tested) for ARM 64-bit RBIT
This commit is contained in:
Eugene Kliuchnikov 2016-09-21 15:05:12 +02:00
parent 20e36ef2f7
commit f20b3eeb2f
9 changed files with 157 additions and 226 deletions

View File

@ -32,10 +32,12 @@
#define BROTLI_NUM_DISTANCE_SHORT_CODES 16 #define BROTLI_NUM_DISTANCE_SHORT_CODES 16
#define BROTLI_MAX_NPOSTFIX 3 #define BROTLI_MAX_NPOSTFIX 3
#define BROTLI_MAX_NDIRECT 120 #define BROTLI_MAX_NDIRECT 120
#define BROTLI_MAX_DISTANCE_BITS 24U
/* BROTLI_NUM_DISTANCE_SYMBOLS == 520 */ /* BROTLI_NUM_DISTANCE_SYMBOLS == 520 */
#define BROTLI_NUM_DISTANCE_SYMBOLS (BROTLI_NUM_DISTANCE_SHORT_CODES + \ #define BROTLI_NUM_DISTANCE_SYMBOLS (BROTLI_NUM_DISTANCE_SHORT_CODES + \
BROTLI_MAX_NDIRECT + \ BROTLI_MAX_NDIRECT + \
(24 << (BROTLI_MAX_NPOSTFIX + 1))) (BROTLI_MAX_DISTANCE_BITS << \
(BROTLI_MAX_NPOSTFIX + 1)))
/* 7.1. Context modes and context ID lookup for literals */ /* 7.1. Context modes and context ID lookup for literals */
/* "context IDs for literals are in the range of 0..63" */ /* "context IDs for literals are in the range of 0..63" */

View File

@ -96,12 +96,28 @@ OR:
#define BROTLI_INLINE __forceinline #define BROTLI_INLINE __forceinline
#endif /* _MSC_VER */ #endif /* _MSC_VER */
#if !defined(__cplusplus) && !defined(c_plusplus) && \
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
#define BROTLI_RESTRICT restrict
#elif BROTLI_GCC_VERSION > 295 || defined(__llvm__)
#define BROTLI_RESTRICT __restrict
#else
#define BROTLI_RESTRICT
#endif
#if BROTLI_MODERN_COMPILER || __has_attribute(noinline) #if BROTLI_MODERN_COMPILER || __has_attribute(noinline)
#define BROTLI_NOINLINE __attribute__((noinline)) #define BROTLI_NOINLINE __attribute__((noinline))
#else #else
#define BROTLI_NOINLINE #define BROTLI_NOINLINE
#endif #endif
#if BROTLI_MODERN_COMPILER || __has_attribute(deprecated)
#define BROTLI_DEPRECATED __attribute__((deprecated))
#else
#define BROTLI_DEPRECATED
#endif
#define BROTLI_UNUSED(X) (void)(X) #define BROTLI_UNUSED(X) (void)(X)
#endif /* BROTLI_COMMON_PORT_H_ */ #endif /* BROTLI_COMMON_PORT_H_ */

View File

@ -18,13 +18,7 @@
extern "C" { extern "C" {
#endif #endif
#if (BROTLI_64_BITS) #define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(reg_t) >> 1)
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ 4
typedef uint64_t reg_t;
#else
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ 2
typedef uint32_t reg_t;
#endif
static const uint32_t kBitMask[33] = { 0x0000, static const uint32_t kBitMask[33] = { 0x0000,
0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
@ -343,23 +337,6 @@ static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
return TO_BROTLI_BOOL(pad_bits == 0); return TO_BROTLI_BOOL(pad_bits == 0);
} }
/* Peeks a byte at specified offset.
Precondition: bit reader is parked to a byte boundary.
Returns -1 if operation is not feasible. */
static BROTLI_INLINE int BrotliPeekByte(BrotliBitReader* br, size_t offset) {
uint32_t available_bits = BrotliGetAvailableBits(br);
size_t bytes_left = available_bits >> 3;
BROTLI_DCHECK((available_bits & 7) == 0);
if (offset < bytes_left) {
return (BrotliGetBitsUnmasked(br) >> (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 /* 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 num may not be larger than BrotliGetRemainingBytes. The bit reader must be
warmed up again after this. */ warmed up again after this. */

View File

@ -220,7 +220,7 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
case BROTLI_STATE_METABLOCK_HEADER_SIZE: case BROTLI_STATE_METABLOCK_HEADER_SIZE:
i = s->loop_counter; i = s->loop_counter;
for (; i < s->size_nibbles; ++i) { for (; i < (int)s->size_nibbles; ++i) {
if (!BrotliSafeReadBits(br, 4, &bits)) { if (!BrotliSafeReadBits(br, 4, &bits)) {
s->loop_counter = i; s->loop_counter = i;
return BROTLI_DECODER_NEEDS_MORE_INPUT; return BROTLI_DECODER_NEEDS_MORE_INPUT;
@ -269,7 +269,7 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
case BROTLI_STATE_METABLOCK_HEADER_METADATA: case BROTLI_STATE_METABLOCK_HEADER_METADATA:
i = s->loop_counter; i = s->loop_counter;
for (; i < s->size_nibbles; ++i) { for (; i < (int)s->size_nibbles; ++i) {
if (!BrotliSafeReadBits(br, 8, &bits)) { if (!BrotliSafeReadBits(br, 8, &bits)) {
s->loop_counter = i; s->loop_counter = i;
return BROTLI_DECODER_NEEDS_MORE_INPUT; return BROTLI_DECODER_NEEDS_MORE_INPUT;
@ -1173,9 +1173,13 @@ static size_t UnwrittenBytes(const BrotliDecoderState* s, BROTLI_BOOL wrap) {
return partial_pos_rb - s->partial_pos_out; return partial_pos_rb - s->partial_pos_out;
} }
/* Dumps output.
Returns BROTLI_DECODER_NEEDS_MORE_OUTPUT only if there is more output to push
and either ringbuffer is as big as window size, or |force| is true.
*/
static BrotliDecoderErrorCode BROTLI_NOINLINE WriteRingBuffer( static BrotliDecoderErrorCode BROTLI_NOINLINE WriteRingBuffer(
BrotliDecoderState* s, size_t* available_out, uint8_t** next_out, BrotliDecoderState* s, size_t* available_out, uint8_t** next_out,
size_t* total_out) { size_t* total_out, BROTLI_BOOL force) {
uint8_t* start = uint8_t* start =
s->ringbuffer + (s->partial_pos_out & (size_t)s->ringbuffer_mask); s->ringbuffer + (s->partial_pos_out & (size_t)s->ringbuffer_mask);
size_t to_write = UnwrittenBytes(s, BROTLI_TRUE); size_t to_write = UnwrittenBytes(s, BROTLI_TRUE);
@ -1198,11 +1202,17 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE WriteRingBuffer(
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;
if (total_out) *total_out = s->partial_pos_out; if (total_out) *total_out = s->partial_pos_out - (size_t)s->custom_dict_size;
if (num_written < to_write) { if (num_written < to_write) {
if (s->ringbuffer_size == (1 << s->window_bits) || force) {
return BROTLI_DECODER_NEEDS_MORE_OUTPUT; return BROTLI_DECODER_NEEDS_MORE_OUTPUT;
} else {
return BROTLI_DECODER_SUCCESS;
} }
if (s->pos >= s->ringbuffer_size) { }
/* Wrap ring buffer only if it has reached its maximal size. */
if (s->ringbuffer_size == (1 << s->window_bits) &&
s->pos >= s->ringbuffer_size) {
s->pos -= s->ringbuffer_size; s->pos -= s->ringbuffer_size;
s->rb_roundtrips++; s->rb_roundtrips++;
s->should_wrap_ringbuffer = (size_t)s->pos != 0 ? 1 : 0; s->should_wrap_ringbuffer = (size_t)s->pos != 0 ? 1 : 0;
@ -1227,27 +1237,41 @@ static void BROTLI_NOINLINE WrapRingBuffer(BrotliDecoderState* s) {
Custom dictionary, if any, is copied to the end of ringbuffer. Custom dictionary, if any, is copied to the end of ringbuffer.
*/ */
static BROTLI_BOOL BROTLI_NOINLINE BrotliAllocateRingBuffer( static BROTLI_BOOL BROTLI_NOINLINE BrotliEnsureRingBuffer(
BrotliDecoderState* s) { BrotliDecoderState* s) {
/* We need the slack region for the following reasons: /* We need the slack region for the following reasons:
- doing up to two 16-byte copies for fast backward copying - doing up to two 16-byte copies for fast backward copying
- inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */ - inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
static const int kRingBufferWriteAheadSlack = 42; static const int kRingBufferWriteAheadSlack = 42;
s->ringbuffer = (uint8_t*)BROTLI_ALLOC(s, (size_t)(s->ringbuffer_size + uint8_t* old_ringbuffer = s->ringbuffer;
if (s->ringbuffer_size == s->new_ringbuffer_size) {
return BROTLI_TRUE;
}
s->ringbuffer = (uint8_t*)BROTLI_ALLOC(s, (size_t)(s->new_ringbuffer_size +
kRingBufferWriteAheadSlack)); kRingBufferWriteAheadSlack));
if (s->ringbuffer == 0) { if (s->ringbuffer == 0) {
/* Restore previous value. */
s->ringbuffer = old_ringbuffer;
return BROTLI_FALSE; return BROTLI_FALSE;
} }
s->ringbuffer[s->new_ringbuffer_size - 2] = 0;
s->ringbuffer[s->new_ringbuffer_size - 1] = 0;
s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size; if (!old_ringbuffer) {
s->ringbuffer[s->ringbuffer_size - 2] = 0;
s->ringbuffer[s->ringbuffer_size - 1] = 0;
if (s->custom_dict) { if (s->custom_dict) {
memcpy(&s->ringbuffer[(-s->custom_dict_size) & s->ringbuffer_mask], memcpy(s->ringbuffer, s->custom_dict, (size_t)s->custom_dict_size);
s->custom_dict, (size_t)s->custom_dict_size); s->partial_pos_out = (size_t)s->custom_dict_size;
s->pos = s->custom_dict_size;
} }
} else {
memcpy(s->ringbuffer, old_ringbuffer, (size_t)s->pos);
BROTLI_FREE(s, old_ringbuffer);
}
s->ringbuffer_size = s->new_ringbuffer_size;
s->ringbuffer_mask = s->new_ringbuffer_size - 1;
s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size;
return BROTLI_TRUE; return BROTLI_TRUE;
} }
@ -1256,7 +1280,7 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput(
size_t* available_out, uint8_t** next_out, size_t* total_out, size_t* available_out, uint8_t** next_out, size_t* total_out,
BrotliDecoderState* s) { BrotliDecoderState* s) {
/* TODO: avoid allocation for single uncompressed block. */ /* TODO: avoid allocation for single uncompressed block. */
if (!s->ringbuffer && !BrotliAllocateRingBuffer(s)) { if (!BrotliEnsureRingBuffer(s)) {
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1); return BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1);
} }
@ -1275,7 +1299,7 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput(
BrotliCopyBytes(&s->ringbuffer[s->pos], &s->br, (size_t)nbytes); BrotliCopyBytes(&s->ringbuffer[s->pos], &s->br, (size_t)nbytes);
s->pos += nbytes; s->pos += nbytes;
s->meta_block_remaining_len -= nbytes; s->meta_block_remaining_len -= nbytes;
if (s->pos < s->ringbuffer_size) { if (s->pos < 1 << s->window_bits) {
if (s->meta_block_remaining_len == 0) { if (s->meta_block_remaining_len == 0) {
return BROTLI_DECODER_SUCCESS; return BROTLI_DECODER_SUCCESS;
} }
@ -1285,12 +1309,15 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput(
/* No break, continue to next state */ /* No break, continue to next state */
} }
case BROTLI_STATE_UNCOMPRESSED_WRITE: { case BROTLI_STATE_UNCOMPRESSED_WRITE: {
BrotliDecoderErrorCode result = BrotliDecoderErrorCode result;
WriteRingBuffer(s, available_out, next_out, total_out); result = WriteRingBuffer(
s, available_out, next_out, total_out, BROTLI_FALSE);
if (result != BROTLI_DECODER_SUCCESS) { if (result != BROTLI_DECODER_SUCCESS) {
return result; return result;
} }
if (s->ringbuffer_size == 1 << s->window_bits) {
s->max_distance = s->max_backward_distance; s->max_distance = s->max_backward_distance;
}
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE; s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
break; break;
} }
@ -1299,43 +1326,6 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput(
BROTLI_DCHECK(0); /* Unreachable */ BROTLI_DCHECK(0); /* Unreachable */
} }
BROTLI_BOOL BrotliDecompressedSize(size_t encoded_size,
const uint8_t* encoded_buffer,
size_t* decoded_size) {
size_t total_size = 0;
BrotliDecoderState s;
BrotliBitReader* br;
BrotliDecoderStateInit(&s);
br = &s.br;
*decoded_size = 0;
br->next_in = encoded_buffer;
br->avail_in = encoded_size;
if (!BrotliWarmupBitReader(br)) return BROTLI_FALSE;
DecodeWindowBits(br);
while (1) {
size_t block_size;
if (DecodeMetaBlockLength(&s, br) != BROTLI_DECODER_SUCCESS) {
return BROTLI_FALSE;
}
block_size = (size_t)s.meta_block_remaining_len;
if (!s.is_metadata) {
if ((block_size + total_size) < total_size) return BROTLI_FALSE;
total_size += block_size;
}
if (s.is_last_metablock) {
*decoded_size = total_size;
return BROTLI_TRUE;
}
if (!s.is_uncompressed && !s.is_metadata) return BROTLI_FALSE;
if (!BrotliJumpToByteBoundary(br)) return BROTLI_FALSE;
BrotliBitReaderUnload(br);
if (br->avail_in < block_size) return BROTLI_FALSE;
br->avail_in -= block_size;
br->next_in += block_size;
if (!BrotliWarmupBitReader(br)) return BROTLI_FALSE;
}
}
/* Calculates the smallest feasible ring buffer. /* Calculates the smallest feasible ring buffer.
If we know the data size is small, do not allocate more ring buffer If we know the data size is small, do not allocate more ring buffer
@ -1344,31 +1334,38 @@ BROTLI_BOOL BrotliDecompressedSize(size_t encoded_size,
When this method is called, metablock size and flags MUST be decoded. When this method is called, metablock size and flags MUST be decoded.
*/ */
static void BROTLI_NOINLINE BrotliCalculateRingBufferSize( static void BROTLI_NOINLINE BrotliCalculateRingBufferSize(
BrotliDecoderState* s, BrotliBitReader* br) { BrotliDecoderState* s) {
BROTLI_BOOL is_last = TO_BROTLI_BOOL(s->is_last_metablock);
int window_size = 1 << s->window_bits; int window_size = 1 << s->window_bits;
s->ringbuffer_size = window_size; int new_ringbuffer_size = window_size;
if (s->is_uncompressed) {
int next_block_header =
BrotliPeekByte(br, (size_t)s->meta_block_remaining_len);
if (next_block_header != -1) { /* Peek succeeded */
if ((next_block_header & 3) == 3) { /* ISLAST and ISEMPTY */
is_last = BROTLI_TRUE;
}
}
}
/* We need at least 2 bytes of ring buffer size to get the last two /* We need at least 2 bytes of ring buffer size to get the last two
bytes for context from there */ bytes for context from there */
if (is_last) { int min_size = s->ringbuffer_size ? s->ringbuffer_size : 1024;
int min_size_x2 = (s->meta_block_remaining_len + s->custom_dict_size) * 2; int output_size;
while (s->ringbuffer_size >= min_size_x2 && s->ringbuffer_size > 32) {
s->ringbuffer_size >>= 1; /* If maxumum is already reached, no further extention is reuired. */
} if (s->ringbuffer_size == window_size) {
return;
} }
s->ringbuffer_mask = s->ringbuffer_size - 1; /* Metadata blocks does not touch ring buffer. */
if (s->is_metadata) {
return;
}
if (!s->ringbuffer) {
/* Custom dictionanry counts as a "virtual" output. */
output_size = s->custom_dict_size;
} else {
output_size = s->pos;
}
output_size += s->meta_block_remaining_len;
min_size = min_size < output_size ? output_size : min_size;
while ((new_ringbuffer_size >> 1) >= min_size) {
new_ringbuffer_size >>= 1;
}
s->new_ringbuffer_size = new_ringbuffer_size;
} }
/* Reads 1..256 2-bit context modes. */ /* Reads 1..256 2-bit context modes. */
@ -1719,11 +1716,8 @@ postReadDistance:
BROTLI_LOG(("[ProcessCommandsInternal] pos = %d distance = %d\n", BROTLI_LOG(("[ProcessCommandsInternal] pos = %d distance = %d\n",
pos, s->distance_code)); pos, s->distance_code));
if (s->max_distance != s->max_backward_distance) { if (s->max_distance != s->max_backward_distance) {
if (pos < s->max_backward_distance_minus_custom_dict_size) { s->max_distance =
s->max_distance = pos + s->custom_dict_size; (pos < s->max_backward_distance) ? pos : s->max_backward_distance;
} else {
s->max_distance = s->max_backward_distance;
}
} }
i = s->copy_length; i = s->copy_length;
/* Apply copy of LZ77 back-reference, or static dictionary reference if /* Apply copy of LZ77 back-reference, or static dictionary reference if
@ -1905,7 +1899,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
if (result != BROTLI_DECODER_SUCCESS) { /* Error, needs more input/output */ if (result != BROTLI_DECODER_SUCCESS) { /* Error, needs more input/output */
if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) { if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
if (s->ringbuffer != 0) { /* Proactively push output. */ if (s->ringbuffer != 0) { /* Proactively push output. */
WriteRingBuffer(s, available_out, next_out, total_out); WriteRingBuffer(s, available_out, next_out, total_out, BROTLI_TRUE);
} }
if (s->buffer_length != 0) { /* Used with internal buffer. */ if (s->buffer_length != 0) { /* Used with internal buffer. */
if (br->avail_in == 0) { /* Successfully finished read transaction. */ if (br->avail_in == 0) { /* Successfully finished read transaction. */
@ -1984,8 +1978,6 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
s->custom_dict += s->custom_dict_size - s->max_backward_distance; s->custom_dict += s->custom_dict_size - s->max_backward_distance;
s->custom_dict_size = s->max_backward_distance; s->custom_dict_size = s->max_backward_distance;
} }
s->max_backward_distance_minus_custom_dict_size =
s->max_backward_distance - s->custom_dict_size;
/* Allocate memory for both block_type_trees and block_len_trees. */ /* Allocate memory for both block_type_trees and block_len_trees. */
s->block_type_trees = (HuffmanCode*)BROTLI_ALLOC(s, s->block_type_trees = (HuffmanCode*)BROTLI_ALLOC(s,
@ -2028,9 +2020,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
s->state = BROTLI_STATE_METABLOCK_DONE; s->state = BROTLI_STATE_METABLOCK_DONE;
break; break;
} }
if (!s->ringbuffer) { BrotliCalculateRingBufferSize(s);
BrotliCalculateRingBufferSize(s, br);
}
if (s->is_uncompressed) { if (s->is_uncompressed) {
s->state = BROTLI_STATE_UNCOMPRESSED; s->state = BROTLI_STATE_UNCOMPRESSED;
break; break;
@ -2039,8 +2029,10 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
s->state = BROTLI_STATE_HUFFMAN_CODE_0; s->state = BROTLI_STATE_HUFFMAN_CODE_0;
break; break;
case BROTLI_STATE_UNCOMPRESSED: { case BROTLI_STATE_UNCOMPRESSED: {
int bytes_copied = s->meta_block_remaining_len;
result = CopyUncompressedBlockToOutput( result = CopyUncompressedBlockToOutput(
available_out, next_out, total_out, s); available_out, next_out, total_out, s);
bytes_copied -= s->meta_block_remaining_len;
if (result != BROTLI_DECODER_SUCCESS) { if (result != BROTLI_DECODER_SUCCESS) {
break; break;
} }
@ -2148,8 +2140,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
/* 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 = s->num_direct_distance_codes +
s->num_direct_distance_codes + (48U << s->distance_postfix_bits); ((2 * BROTLI_MAX_DISTANCE_BITS) << s->distance_postfix_bits);
result = DecodeContextMap( result = DecodeContextMap(
s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS, s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS,
&s->num_dist_htrees, &s->dist_context_map, s); &s->num_dist_htrees, &s->dist_context_map, s);
@ -2200,7 +2192,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
PrepareLiteralDecoding(s); PrepareLiteralDecoding(s);
s->dist_context_map_slice = s->dist_context_map; s->dist_context_map_slice = s->dist_context_map;
s->htree_command = s->insert_copy_hgroup.htrees[0]; s->htree_command = s->insert_copy_hgroup.htrees[0];
if (!s->ringbuffer && !BrotliAllocateRingBuffer(s)) { if (!BrotliEnsureRingBuffer(s)) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
break; break;
} }
@ -2219,12 +2211,15 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
case BROTLI_STATE_COMMAND_INNER_WRITE: case BROTLI_STATE_COMMAND_INNER_WRITE:
case BROTLI_STATE_COMMAND_POST_WRITE_1: case BROTLI_STATE_COMMAND_POST_WRITE_1:
case BROTLI_STATE_COMMAND_POST_WRITE_2: case BROTLI_STATE_COMMAND_POST_WRITE_2:
result = WriteRingBuffer(s, available_out, next_out, total_out); result = WriteRingBuffer(
s, available_out, next_out, total_out, BROTLI_FALSE);
if (result != BROTLI_DECODER_SUCCESS) { if (result != BROTLI_DECODER_SUCCESS) {
break; break;
} }
WrapRingBuffer(s); WrapRingBuffer(s);
if (s->ringbuffer_size == 1 << s->window_bits) {
s->max_distance = s->max_backward_distance; s->max_distance = s->max_backward_distance;
}
if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_1) { if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_1) {
if (s->meta_block_remaining_len == 0) { if (s->meta_block_remaining_len == 0) {
/* Next metablock, if any */ /* Next metablock, if any */
@ -2270,7 +2265,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
/* No break, continue to next state */ /* No break, continue to next state */
case BROTLI_STATE_DONE: case BROTLI_STATE_DONE:
if (s->ringbuffer != 0) { if (s->ringbuffer != 0) {
result = WriteRingBuffer(s, available_out, next_out, total_out); result = WriteRingBuffer(
s, available_out, next_out, total_out, BROTLI_TRUE);
if (result != BROTLI_DECODER_SUCCESS) { if (result != BROTLI_DECODER_SUCCESS) {
break; break;
} }
@ -2305,7 +2301,7 @@ const uint8_t* BrotliDecoderTakeOutput(BrotliDecoderState* s, size_t* size) {
return 0; return 0;
} }
WrapRingBuffer(s); WrapRingBuffer(s);
status = WriteRingBuffer(s, &available_out, &result, 0); status = WriteRingBuffer(s, &available_out, &result, 0, BROTLI_TRUE);
if (status == BROTLI_DECODER_SUCCESS || if (status == BROTLI_DECODER_SUCCESS ||
status == BROTLI_DECODER_NEEDS_MORE_OUTPUT) { status == BROTLI_DECODER_NEEDS_MORE_OUTPUT) {
*size = requested_out - available_out; *size = requested_out - available_out;
@ -2347,45 +2343,6 @@ uint32_t BrotliDecoderVersion() {
return BROTLI_VERSION; return BROTLI_VERSION;
} }
/* DEPRECATED >>> */
BrotliState* BrotliCreateState(
brotli_alloc_func alloc, brotli_free_func free, void* opaque) {
return (BrotliState*)BrotliDecoderCreateInstance(alloc, free, opaque);
}
void BrotliDestroyState(BrotliState* state) {
BrotliDecoderDestroyInstance((BrotliDecoderState*)state);
}
BrotliResult BrotliDecompressBuffer(
size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size,
uint8_t* decoded_buffer) {
return (BrotliResult)BrotliDecoderDecompress(
encoded_size, encoded_buffer, decoded_size, decoded_buffer);
}
BrotliResult BrotliDecompressStream(
size_t* available_in, const uint8_t** next_in, size_t* available_out,
uint8_t** next_out, size_t* total_out, BrotliState* s) {
return (BrotliResult)BrotliDecoderDecompressStream((BrotliDecoderState*)s,
available_in, next_in, available_out, next_out, total_out);
}
void BrotliSetCustomDictionary(
size_t size, const uint8_t* dict, BrotliState* s) {
BrotliDecoderSetCustomDictionary((BrotliDecoderState*)s, size, dict);
}
BROTLI_BOOL BrotliStateIsStreamStart(const BrotliState* s) {
return !BrotliDecoderIsUsed((const BrotliDecoderState*)s);
}
BROTLI_BOOL BrotliStateIsStreamEnd(const BrotliState* s) {
return BrotliDecoderIsFinished((const BrotliDecoderState*)s);
}
BrotliErrorCode BrotliGetErrorCode(const BrotliState* s) {
return (BrotliErrorCode)BrotliDecoderGetErrorCode(
(const BrotliDecoderState*)s);
}
const char* BrotliErrorString(BrotliErrorCode c) {
return BrotliDecoderErrorString((BrotliDecoderErrorCode)c);
}
/* <<< DEPRECATED */
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */ } /* extern "C" */
#endif #endif

View File

@ -21,7 +21,8 @@ extern "C" {
#define BROTLI_REVERSE_BITS_MAX 8 #define BROTLI_REVERSE_BITS_MAX 8
#ifdef BROTLI_RBIT #ifdef BROTLI_RBIT
#define BROTLI_REVERSE_BITS_BASE (32 - BROTLI_REVERSE_BITS_MAX) #define BROTLI_REVERSE_BITS_BASE \
((sizeof(reg_t) << 3) - BROTLI_REVERSE_BITS_MAX)
#else #else
#define BROTLI_REVERSE_BITS_BASE 0 #define BROTLI_REVERSE_BITS_BASE 0
static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = { static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
@ -61,12 +62,12 @@ static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
#endif /* BROTLI_RBIT */ #endif /* BROTLI_RBIT */
#define BROTLI_REVERSE_BITS_LOWEST \ #define BROTLI_REVERSE_BITS_LOWEST \
(1U << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE)) ((reg_t)1 << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE))
/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX), /* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),
where reverse(value, len) is the bit-wise reversal of the len least where reverse(value, len) is the bit-wise reversal of the len least
significant bits of value. */ significant bits of value. */
static BROTLI_INLINE uint32_t BrotliReverseBits(uint32_t num) { static BROTLI_INLINE reg_t BrotliReverseBits(reg_t num) {
#ifdef BROTLI_RBIT #ifdef BROTLI_RBIT
return BROTLI_RBIT(num); return BROTLI_RBIT(num);
#else #else
@ -105,8 +106,8 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
uint16_t* count) { uint16_t* count) {
HuffmanCode code; /* current table entry */ HuffmanCode code; /* current table entry */
int symbol; /* symbol index in original or sorted table */ int symbol; /* symbol index in original or sorted table */
uint32_t key; /* prefix code */ reg_t key; /* prefix code */
uint32_t key_step; /* prefix code addend */ reg_t key_step; /* prefix code addend */
int step; /* step size to replicate values in current table */ int step; /* step size to replicate values in current table */
int table_size; /* size of current table */ int table_size; /* size of current table */
int sorted[BROTLI_CODE_LENGTH_CODES]; /* symbols sorted by code length */ int sorted[BROTLI_CODE_LENGTH_CODES]; /* symbols sorted by code length */
@ -143,7 +144,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
if (offset[0] == 0) { if (offset[0] == 0) {
code.bits = 0; code.bits = 0;
code.value = (uint16_t)sorted[0]; code.value = (uint16_t)sorted[0];
for (key = 0; key < (uint32_t)table_size; ++key) { for (key = 0; key < (reg_t)table_size; ++key) {
table[key] = code; table[key] = code;
} }
return; return;
@ -175,10 +176,10 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
HuffmanCode* table; /* next available space in table */ HuffmanCode* table; /* next available space in table */
int len; /* current code length */ int len; /* current code length */
int symbol; /* symbol index in original or sorted table */ int symbol; /* symbol index in original or sorted table */
uint32_t key; /* prefix code */ reg_t key; /* prefix code */
uint32_t key_step; /* prefix code addend */ reg_t key_step; /* prefix code addend */
uint32_t sub_key; /* 2nd level table prefix code */ reg_t sub_key; /* 2nd level table prefix code */
uint32_t sub_key_step; /* 2nd level table prefix code addend */ reg_t sub_key_step; /* 2nd level table prefix code addend */
int step; /* step size to replicate values in current table */ int step; /* step size to replicate values in current table */
int table_bits; /* key length of current table */ int table_bits; /* key length of current table */
int table_size; /* size of current table */ int table_size; /* size of current table */

View File

@ -16,6 +16,7 @@
features and attributes features and attributes
* BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned * BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
read and overlapping memcpy; this reduces decompression speed by 5% read and overlapping memcpy; this reduces decompression speed by 5%
* BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs
* BROTLI_DEBUG dumps file name and line number when decoder detects stream * BROTLI_DEBUG dumps file name and line number when decoder detects stream
or memory error or memory error
* BROTLI_ENABLE_LOG enables asserts and dumps various state information * BROTLI_ENABLE_LOG enables asserts and dumps various state information
@ -101,6 +102,12 @@ static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
#define BROTLI_64_BITS 0 #define BROTLI_64_BITS 0
#endif #endif
#if (BROTLI_64_BITS)
#define reg_t uint64_t
#else
#define reg_t uint32_t
#endif
#if defined(BROTLI_BUILD_BIG_ENDIAN) #if defined(BROTLI_BUILD_BIG_ENDIAN)
#define BROTLI_LITTLE_ENDIAN 0 #define BROTLI_LITTLE_ENDIAN 0
#define BROTLI_BIG_ENDIAN 1 #define BROTLI_BIG_ENDIAN 1
@ -132,10 +139,12 @@ static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
if ((N & 4) != 0) {X; X; X; X;} \ if ((N & 4) != 0) {X; X; X; X;} \
} }
#if BROTLI_MODERN_COMPILER || defined(__llvm__) #if (BROTLI_MODERN_COMPILER || defined(__llvm__)) && \
!defined(BROTLI_BUILD_NO_RBIT)
#if defined(BROTLI_TARGET_ARMV7) #if defined(BROTLI_TARGET_ARMV7)
static BROTLI_INLINE unsigned BrotliRBit(unsigned input) { /* TODO: detect ARMv6T2 and enable this code for it. */
unsigned output; static BROTLI_INLINE reg_t BrotliRBit(reg_t input) {
reg_t output;
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input)); __asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
return output; return output;
} }

View File

@ -60,6 +60,9 @@ void BrotliDecoderStateInitWithCustomAllocators(BrotliDecoderState* s,
s->block_type_trees = NULL; s->block_type_trees = NULL;
s->block_len_trees = NULL; s->block_len_trees = NULL;
s->ringbuffer = NULL; s->ringbuffer = NULL;
s->ringbuffer_size = 0;
s->new_ringbuffer_size = 0;
s->ringbuffer_mask = 0;
s->context_map = NULL; s->context_map = NULL;
s->context_modes = NULL; s->context_modes = NULL;

View File

@ -115,7 +115,6 @@ struct BrotliDecoderStateStruct {
int pos; int pos;
int max_backward_distance; int max_backward_distance;
int max_backward_distance_minus_custom_dict_size;
int max_distance; int max_distance;
int ringbuffer_size; int ringbuffer_size;
int ringbuffer_mask; int ringbuffer_mask;
@ -162,7 +161,7 @@ struct BrotliDecoderStateStruct {
/* For partial write operations */ /* For partial write operations */
size_t rb_roundtrips; /* How many times we went around the ringbuffer */ size_t rb_roundtrips; /* How many times we went around the ringbuffer */
size_t partial_pos_out; /* How much output to the user in total (<= rb) */ size_t partial_pos_out; /* How much output to the user in total */
/* For ReadHuffmanCode */ /* For ReadHuffmanCode */
uint32_t symbol; uint32_t symbol;
@ -216,6 +215,8 @@ struct BrotliDecoderStateStruct {
unsigned int size_nibbles : 8; unsigned int size_nibbles : 8;
uint32_t window_bits; uint32_t window_bits;
int new_ringbuffer_size;
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;

View File

@ -126,8 +126,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
be ignored. The dictionary must exist in memory until decoding is done and be ignored. The dictionary must exist in memory until decoding is done and
is owned by the caller. To use: is owned by the caller. To use:
1) Allocate and initialize state with BrotliCreateInstance 1) Allocate and initialize state with BrotliCreateInstance
2) Use BrotliSetCustomDictionary 2) Use BrotliDecoderSetCustomDictionary
3) Use BrotliDecompressStream 3) Use BrotliDecoderDecompressStream
4) Clean up and free state with BrotliDestroyState 4) Clean up and free state with BrotliDestroyState
*/ */
void BrotliDecoderSetCustomDictionary( void BrotliDecoderSetCustomDictionary(
@ -161,7 +161,7 @@ BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* s);
and produced all of the output; returns false otherwise. */ and produced all of the output; returns false otherwise. */
BROTLI_BOOL BrotliDecoderIsFinished(const BrotliDecoderState* s); BROTLI_BOOL BrotliDecoderIsFinished(const BrotliDecoderState* s);
/* Returns detailed error code after BrotliDecompressStream returns /* Returns detailed error code after BrotliDecoderDecompressStream returns
BROTLI_DECODER_RESULT_ERROR. */ BROTLI_DECODER_RESULT_ERROR. */
BrotliDecoderErrorCode BrotliDecoderGetErrorCode(const BrotliDecoderState* s); BrotliDecoderErrorCode BrotliDecoderGetErrorCode(const BrotliDecoderState* s);
@ -170,41 +170,6 @@ const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c);
/* Decoder version. Look at BROTLI_VERSION for more information. */ /* Decoder version. Look at BROTLI_VERSION for more information. */
uint32_t BrotliDecoderVersion(void); uint32_t BrotliDecoderVersion(void);
/* DEPRECATED >>> */
typedef enum {
BROTLI_RESULT_ERROR = 0,
BROTLI_RESULT_SUCCESS = 1,
BROTLI_RESULT_NEEDS_MORE_INPUT = 2,
BROTLI_RESULT_NEEDS_MORE_OUTPUT = 3
} BrotliResult;
typedef enum {
#define BROTLI_COMMA_ ,
#define BROTLI_ERROR_CODE_ENUM_ITEM_(PREFIX, NAME, CODE) \
BROTLI ## PREFIX ## NAME = CODE
BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE_ENUM_ITEM_, BROTLI_COMMA_)
#undef BROTLI_ERROR_CODE_ENUM_ITEM_
#undef BROTLI_COMMA_
} BrotliErrorCode;
typedef struct BrotliStateStruct BrotliState;
BrotliState* BrotliCreateState(
brotli_alloc_func alloc, brotli_free_func free, void* opaque);
void BrotliDestroyState(BrotliState* state);
BROTLI_BOOL BrotliDecompressedSize(
size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size);
BrotliResult BrotliDecompressBuffer(
size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size,
uint8_t* decoded_buffer);
BrotliResult BrotliDecompressStream(
size_t* available_in, const uint8_t** next_in, size_t* available_out,
uint8_t** next_out, size_t* total_out, BrotliState* s);
void BrotliSetCustomDictionary(
size_t size, const uint8_t* dict, BrotliState* s);
BROTLI_BOOL BrotliStateIsStreamStart(const BrotliState* s);
BROTLI_BOOL BrotliStateIsStreamEnd(const BrotliState* s);
BrotliErrorCode BrotliGetErrorCode(const BrotliState* s);
const char* BrotliErrorString(BrotliErrorCode c);
/* <<< DEPRECATED */
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */ } /* extern "C" */
#endif #endif