mirror of https://github.com/google/brotli
Decoder: implement custom allocator feature
Drive-by: conform stricter compilation flags; cleanup shared.mk
This commit is contained in:
parent
befc549b47
commit
b693812271
75
dec/decode.c
75
dec/decode.c
|
@ -73,6 +73,34 @@ static const uint8_t kCodeLengthPrefixValue[16] = {
|
|||
|
||||
#define NUM_DISTANCE_SHORT_CODES 16
|
||||
|
||||
BrotliState* BrotliCreateState(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
BrotliState* state = 0;
|
||||
if (!alloc_func && !free_func) {
|
||||
state = (BrotliState*)malloc(sizeof(BrotliState));
|
||||
} else if (alloc_func && free_func) {
|
||||
state = (BrotliState*)alloc_func(opaque, sizeof(BrotliState));
|
||||
}
|
||||
if (state == 0) {
|
||||
(void)BROTLI_FAILURE();
|
||||
return 0;
|
||||
}
|
||||
BrotliStateInitWithCustomAllocators(state, alloc_func, free_func, opaque);
|
||||
return state;
|
||||
}
|
||||
|
||||
/* Deinitializes and frees BrotliState instance. */
|
||||
void BrotliDestroyState(BrotliState* state) {
|
||||
if (!state) {
|
||||
return;
|
||||
} else {
|
||||
brotli_free_func free_func = state->free_func;
|
||||
void* opaque = state->memory_manager_opaque;
|
||||
BrotliStateCleanup(state);
|
||||
free_func(opaque, state);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
|
@ -907,7 +935,7 @@ static BrotliResult DecodeContextMap(uint32_t context_map_size,
|
|||
s->context_index = 0;
|
||||
BROTLI_LOG_UINT(context_map_size);
|
||||
BROTLI_LOG_UINT(*num_htrees);
|
||||
*context_map_arg = (uint8_t*)malloc((size_t)context_map_size);
|
||||
*context_map_arg = (uint8_t*)BROTLI_ALLOC(s, (size_t)context_map_size);
|
||||
if (*context_map_arg == 0) {
|
||||
return BROTLI_FAILURE();
|
||||
}
|
||||
|
@ -1006,7 +1034,7 @@ rleCode:
|
|||
|
||||
/* Decodes a command or literal and updates block type ringbuffer.
|
||||
Reads 3..54 bits. */
|
||||
static int BROTLI_INLINE DecodeBlockTypeAndLength(int safe,
|
||||
static BROTLI_INLINE int DecodeBlockTypeAndLength(int safe,
|
||||
BrotliState* s, int tree_type) {
|
||||
uint32_t max_block_type = s->num_block_types[tree_type];
|
||||
int tree_offset = tree_type * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
|
||||
|
@ -1048,7 +1076,7 @@ static int BROTLI_INLINE DecodeBlockTypeAndLength(int safe,
|
|||
|
||||
/* Decodes the block type and updates the state for literal context.
|
||||
Reads 3..54 bits. */
|
||||
static int BROTLI_INLINE DecodeLiteralBlockSwitchInternal(int safe,
|
||||
static BROTLI_INLINE int DecodeLiteralBlockSwitchInternal(int safe,
|
||||
BrotliState* s) {
|
||||
uint8_t context_mode;
|
||||
uint32_t context_offset;
|
||||
|
@ -1075,7 +1103,7 @@ static int BROTLI_NOINLINE SafeDecodeLiteralBlockSwitch(BrotliState* s) {
|
|||
|
||||
/* Block switch for insert/copy length.
|
||||
Reads 3..54 bits. */
|
||||
static int BROTLI_INLINE DecodeCommandBlockSwitchInternal(int safe,
|
||||
static BROTLI_INLINE int DecodeCommandBlockSwitchInternal(int safe,
|
||||
BrotliState* s) {
|
||||
if (!DecodeBlockTypeAndLength(safe, s, 1)) {
|
||||
return 0;
|
||||
|
@ -1093,7 +1121,7 @@ static int BROTLI_NOINLINE SafeDecodeCommandBlockSwitch(BrotliState* s) {
|
|||
|
||||
/* Block switch for distance codes.
|
||||
Reads 3..54 bits. */
|
||||
static int BROTLI_INLINE DecodeDistanceBlockSwitchInternal(int safe,
|
||||
static BROTLI_INLINE int DecodeDistanceBlockSwitchInternal(int safe,
|
||||
BrotliState* s) {
|
||||
if (!DecodeBlockTypeAndLength(safe, s, 2)) {
|
||||
return 0;
|
||||
|
@ -1255,7 +1283,7 @@ static int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s,
|
|||
}
|
||||
|
||||
s->ringbuffer_mask = s->ringbuffer_size - 1;
|
||||
s->ringbuffer = (uint8_t*)malloc((size_t)(s->ringbuffer_size +
|
||||
s->ringbuffer = (uint8_t*)BROTLI_ALLOC(s, (size_t)(s->ringbuffer_size +
|
||||
kRingBufferWriteAheadSlack + kBrotliMaxDictionaryWordLength));
|
||||
if (s->ringbuffer == 0) {
|
||||
return 0;
|
||||
|
@ -1289,7 +1317,7 @@ static BrotliResult ReadContextModes(BrotliState* s) {
|
|||
return BROTLI_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static void BROTLI_INLINE TakeDistanceFromRingBuffer(BrotliState* s) {
|
||||
static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliState* s) {
|
||||
if (s->distance_code == 0) {
|
||||
--s->dist_rb_idx;
|
||||
s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
|
||||
|
@ -1329,7 +1357,7 @@ static BROTLI_INLINE int SafeReadBits(
|
|||
}
|
||||
|
||||
/* Precondition: s->distance_code < 0 */
|
||||
static int BROTLI_INLINE ReadDistanceInternal(int safe,
|
||||
static BROTLI_INLINE int ReadDistanceInternal(int safe,
|
||||
BrotliState* s, BrotliBitReader* br) {
|
||||
int distval;
|
||||
BrotliBitReaderState memento;
|
||||
|
@ -1386,15 +1414,15 @@ static int BROTLI_INLINE ReadDistanceInternal(int safe,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void BROTLI_INLINE ReadDistance(BrotliState* s, BrotliBitReader* br) {
|
||||
static BROTLI_INLINE void ReadDistance(BrotliState* s, BrotliBitReader* br) {
|
||||
ReadDistanceInternal(0, s, br);
|
||||
}
|
||||
|
||||
static int BROTLI_INLINE SafeReadDistance(BrotliState* s, BrotliBitReader* br) {
|
||||
static BROTLI_INLINE int SafeReadDistance(BrotliState* s, BrotliBitReader* br) {
|
||||
return ReadDistanceInternal(1, s, br);
|
||||
}
|
||||
|
||||
static int BROTLI_INLINE ReadCommandInternal(int safe,
|
||||
static BROTLI_INLINE int ReadCommandInternal(int safe,
|
||||
BrotliState* s, BrotliBitReader* br, int* insert_length) {
|
||||
uint32_t cmd_code;
|
||||
uint32_t insert_len_extra = 0;
|
||||
|
@ -1432,12 +1460,12 @@ static int BROTLI_INLINE ReadCommandInternal(int safe,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void BROTLI_INLINE ReadCommand(BrotliState* s, BrotliBitReader* br,
|
||||
static BROTLI_INLINE void ReadCommand(BrotliState* s, BrotliBitReader* br,
|
||||
int* insert_length) {
|
||||
ReadCommandInternal(0, s, br, insert_length);
|
||||
}
|
||||
|
||||
static int BROTLI_INLINE SafeReadCommand(BrotliState* s, BrotliBitReader* br,
|
||||
static BROTLI_INLINE int SafeReadCommand(BrotliState* s, BrotliBitReader* br,
|
||||
int* insert_length) {
|
||||
return ReadCommandInternal(1, s, br, insert_length);
|
||||
}
|
||||
|
@ -1833,10 +1861,10 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
|||
size_t total_out;
|
||||
|
||||
if (s->legacy_input_buffer == 0) {
|
||||
s->legacy_input_buffer = (uint8_t*)malloc(kBufferSize);
|
||||
s->legacy_input_buffer = (uint8_t*)BROTLI_ALLOC(s, kBufferSize);
|
||||
}
|
||||
if (s->legacy_output_buffer == 0) {
|
||||
s->legacy_output_buffer = (uint8_t*)malloc(kBufferSize);
|
||||
s->legacy_output_buffer = (uint8_t*)BROTLI_ALLOC(s, kBufferSize);
|
||||
}
|
||||
if (s->legacy_input_buffer == 0 || s->legacy_output_buffer == 0) {
|
||||
return BROTLI_FAILURE();
|
||||
|
@ -2010,7 +2038,7 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
|||
s->max_backward_distance - s->custom_dict_size;
|
||||
|
||||
/* Allocate memory for both block_type_trees and block_len_trees. */
|
||||
s->block_type_trees = (HuffmanCode*)malloc(
|
||||
s->block_type_trees = (HuffmanCode*)BROTLI_ALLOC(s,
|
||||
6 * BROTLI_HUFFMAN_MAX_TABLE_SIZE * sizeof(HuffmanCode));
|
||||
if (s->block_type_trees == 0) {
|
||||
result = BROTLI_FAILURE();
|
||||
|
@ -2145,7 +2173,8 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
|||
BROTLI_LOG_UINT(s->num_direct_distance_codes);
|
||||
BROTLI_LOG_UINT(s->distance_postfix_bits);
|
||||
s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits);
|
||||
s->context_modes = (uint8_t*)malloc((size_t)s->num_block_types[0]);
|
||||
s->context_modes =
|
||||
(uint8_t*)BROTLI_ALLOC(s, (size_t)s->num_block_types[0]);
|
||||
if (s->context_modes == 0) {
|
||||
result = BROTLI_FAILURE();
|
||||
break;
|
||||
|
@ -2188,13 +2217,13 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
|||
if (result != BROTLI_RESULT_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
BrotliHuffmanTreeGroupInit(
|
||||
&s->literal_hgroup, kNumLiteralCodes, s->num_literal_htrees);
|
||||
BrotliHuffmanTreeGroupInit(
|
||||
&s->insert_copy_hgroup, kNumInsertAndCopyCodes,
|
||||
BrotliHuffmanTreeGroupInit(s, &s->literal_hgroup, kNumLiteralCodes,
|
||||
s->num_literal_htrees);
|
||||
BrotliHuffmanTreeGroupInit(s, &s->insert_copy_hgroup,
|
||||
kNumInsertAndCopyCodes,
|
||||
s->num_block_types[1]);
|
||||
BrotliHuffmanTreeGroupInit(
|
||||
&s->distance_hgroup, num_distance_codes, s->num_dist_htrees);
|
||||
BrotliHuffmanTreeGroupInit(s, &s->distance_hgroup, num_distance_codes,
|
||||
s->num_dist_htrees);
|
||||
if (s->literal_hgroup.codes == 0 ||
|
||||
s->insert_copy_hgroup.codes == 0 ||
|
||||
s->distance_hgroup.codes == 0) {
|
||||
|
|
10
dec/decode.h
10
dec/decode.h
|
@ -51,6 +51,16 @@ static inline BrotliResult BrotliFailure(const char *f, int l, const char *fn) {
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Creates the instance of BrotliState and initializes it. alloc_func and
|
||||
free_func MUST be both zero or both non-zero. In the case they are both zero,
|
||||
default memory allocators are used. opaque parameter is passed to alloc_func
|
||||
and free_func when they are called. */
|
||||
BrotliState* BrotliCreateState(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||
|
||||
/* Deinitializes and frees BrotliState instance. */
|
||||
void BrotliDestroyState(BrotliState* state);
|
||||
|
||||
/* Sets *decoded_size to the decompressed size of the given encoded stream. */
|
||||
/* This function only works if the encoded buffer has a single meta block, */
|
||||
/* or if it has two meta-blocks, where the first is uncompressed and the */
|
||||
|
|
|
@ -362,24 +362,6 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
|||
return goal_size;
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeGroupInit(HuffmanTreeGroup* group, uint32_t alphabet_size,
|
||||
uint32_t ntrees) {
|
||||
/* Pack two mallocs into one */
|
||||
const size_t code_size =
|
||||
sizeof(HuffmanCode) * (size_t)(ntrees * BROTLI_HUFFMAN_MAX_TABLE_SIZE);
|
||||
const size_t htree_size = sizeof(HuffmanCode*) * (size_t)ntrees;
|
||||
char *p = (char*)malloc(code_size + htree_size);
|
||||
group->alphabet_size = (uint16_t)alphabet_size;
|
||||
group->num_htrees = (uint16_t)ntrees;
|
||||
group->codes = (HuffmanCode*)p;
|
||||
group->htrees = (HuffmanCode**)(p + code_size);
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
|
||||
BROTLI_FREE(group->codes);
|
||||
group->htrees = NULL;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
@ -70,10 +70,6 @@ typedef struct {
|
|||
uint16_t num_htrees;
|
||||
} HuffmanTreeGroup;
|
||||
|
||||
void BrotliHuffmanTreeGroupInit(HuffmanTreeGroup* group,
|
||||
uint32_t alphabet_size, uint32_t ntrees);
|
||||
void BrotliHuffmanTreeGroupRelease(HuffmanTreeGroup* group);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
@ -237,8 +237,10 @@ static BROTLI_INLINE unsigned BrotliRBit(unsigned input) {
|
|||
#define BROTLI_HAS_UBFX 0
|
||||
#endif
|
||||
|
||||
#define BROTLI_FREE(X) { \
|
||||
free(X); \
|
||||
#define BROTLI_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
||||
|
||||
#define BROTLI_FREE(S, X) { \
|
||||
S->free_func(S->memory_manager_opaque, X); \
|
||||
X = NULL; \
|
||||
}
|
||||
|
||||
|
|
62
dec/state.c
62
dec/state.c
|
@ -23,7 +23,32 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
static void* DefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void DefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
}
|
||||
|
||||
void BrotliStateInit(BrotliState* s) {
|
||||
BrotliStateInitWithCustomAllocators(s, 0, 0, 0);
|
||||
}
|
||||
|
||||
void BrotliStateInitWithCustomAllocators(BrotliState* s,
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
if (!alloc_func) {
|
||||
s->alloc_func = DefaultAllocFunc;
|
||||
s->free_func = DefaultFreeFunc;
|
||||
s->memory_manager_opaque = 0;
|
||||
} else {
|
||||
s->alloc_func = alloc_func;
|
||||
s->free_func = free_func;
|
||||
s->memory_manager_opaque = opaque;
|
||||
}
|
||||
|
||||
BrotliInitBitReader(&s->br);
|
||||
s->state = BROTLI_STATE_UNINITED;
|
||||
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
|
||||
|
@ -120,22 +145,22 @@ void BrotliStateMetablockBegin(BrotliState* s) {
|
|||
}
|
||||
|
||||
void BrotliStateCleanupAfterMetablock(BrotliState* s) {
|
||||
BROTLI_FREE(s->context_modes);
|
||||
BROTLI_FREE(s->context_map);
|
||||
BROTLI_FREE(s->dist_context_map);
|
||||
BROTLI_FREE(s, s->context_modes);
|
||||
BROTLI_FREE(s, s->context_map);
|
||||
BROTLI_FREE(s, s->dist_context_map);
|
||||
|
||||
BrotliHuffmanTreeGroupRelease(&s->literal_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(&s->insert_copy_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(&s->distance_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(s, &s->literal_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(s, &s->insert_copy_hgroup);
|
||||
BrotliHuffmanTreeGroupRelease(s, &s->distance_hgroup);
|
||||
}
|
||||
|
||||
void BrotliStateCleanup(BrotliState* s) {
|
||||
BrotliStateCleanupAfterMetablock(s);
|
||||
|
||||
BROTLI_FREE(s->ringbuffer);
|
||||
BROTLI_FREE(s->block_type_trees);
|
||||
BROTLI_FREE(s->legacy_input_buffer);
|
||||
BROTLI_FREE(s->legacy_output_buffer);
|
||||
BROTLI_FREE(s, s->ringbuffer);
|
||||
BROTLI_FREE(s, s->block_type_trees);
|
||||
BROTLI_FREE(s, s->legacy_input_buffer);
|
||||
BROTLI_FREE(s, s->legacy_output_buffer);
|
||||
}
|
||||
|
||||
int BrotliStateIsStreamStart(const BrotliState* s) {
|
||||
|
@ -147,6 +172,23 @@ int BrotliStateIsStreamEnd(const BrotliState* s) {
|
|||
return s->state == BROTLI_STATE_DONE;
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeGroupInit(BrotliState* s, HuffmanTreeGroup* group,
|
||||
uint32_t alphabet_size, uint32_t ntrees) {
|
||||
/* Pack two allocations into one */
|
||||
const size_t code_size =
|
||||
sizeof(HuffmanCode) * (size_t)(ntrees * BROTLI_HUFFMAN_MAX_TABLE_SIZE);
|
||||
const size_t htree_size = sizeof(HuffmanCode*) * (size_t)ntrees;
|
||||
char *p = (char*)BROTLI_ALLOC(s, code_size + htree_size);
|
||||
group->alphabet_size = (uint16_t)alphabet_size;
|
||||
group->num_htrees = (uint16_t)ntrees;
|
||||
group->codes = (HuffmanCode*)p;
|
||||
group->htrees = (HuffmanCode**)(p + code_size);
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeGroupRelease(BrotliState* s, HuffmanTreeGroup* group) {
|
||||
BROTLI_FREE(s, group->codes);
|
||||
group->htrees = NULL;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
|
12
dec/state.h
12
dec/state.h
|
@ -106,6 +106,10 @@ struct BrotliStateStruct {
|
|||
BrotliRunningState state;
|
||||
BrotliBitReader br;
|
||||
|
||||
brotli_alloc_func alloc_func;
|
||||
brotli_free_func free_func;
|
||||
void* memory_manager_opaque;
|
||||
|
||||
/* Temporary storage for remaining input. */
|
||||
union {
|
||||
uint64_t u64;
|
||||
|
@ -234,10 +238,16 @@ struct BrotliStateStruct {
|
|||
typedef struct BrotliStateStruct BrotliState;
|
||||
|
||||
void BrotliStateInit(BrotliState* s);
|
||||
void BrotliStateInitWithCustomAllocators(BrotliState* s,
|
||||
brotli_alloc_func alloc_func,
|
||||
brotli_free_func free_func,
|
||||
void* opaque);
|
||||
void BrotliStateCleanup(BrotliState* s);
|
||||
void BrotliStateMetablockBegin(BrotliState* s);
|
||||
void BrotliStateCleanupAfterMetablock(BrotliState* s);
|
||||
|
||||
void BrotliHuffmanTreeGroupInit(BrotliState* s, HuffmanTreeGroup* group,
|
||||
uint32_t alphabet_size, uint32_t ntrees);
|
||||
void BrotliHuffmanTreeGroupRelease(BrotliState* s, HuffmanTreeGroup* group);
|
||||
|
||||
/* Returns 1, if s is in a state where we have not read any input bytes yet,
|
||||
and 0 otherwise */
|
||||
|
|
11
dec/types.h
11
dec/types.h
|
@ -33,4 +33,15 @@ typedef __int64 int64_t;
|
|||
#include <stdint.h>
|
||||
#endif /* defined(_MSC_VER) && (_MSC_VER < 1600) */
|
||||
|
||||
/* Allocating function pointer. Function MUST return 0 in the case of failure.
|
||||
Otherwise it MUST return a valid pointer to a memory region of at least
|
||||
size length. Neither items nor size are allowed to be 0.
|
||||
opaque argument is a pointer provided by client and could be used to bind
|
||||
function to specific object (memory pool). */
|
||||
typedef void* (*brotli_alloc_func) (void* opaque, size_t size);
|
||||
|
||||
/* Deallocating function pointer. Function SHOULD be no-op in the case the
|
||||
address is 0. */
|
||||
typedef void (*brotli_free_func) (void* opaque, void* address);
|
||||
|
||||
#endif /* BROTLI_DEC_TYPES_H_ */
|
||||
|
|
Loading…
Reference in New Issue