/* We need the slack region for the following reasons: -doinguptotwo16-bytecopiesforfastbackwardcopying -insertingtransformeddictionaryword:
255 prefix + 32 base + 255 suffix */ staticconst brotli_reg_t kRingBufferWriteAheadSlack = 542;
/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */ static BROTLI_NOINLINE BrotliDecoderErrorCode DecodeVarLenUint8(
BrotliDecoderState* s, BrotliBitReader* br, brotli_reg_t* value) {
brotli_reg_t bits; switch (s->substate_decode_uint8) { case BROTLI_STATE_DECODE_UINT8_NONE: if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, 1, &bits))) { return BROTLI_DECODER_NEEDS_MORE_INPUT;
} if (bits == 0) {
*value = 0; return BROTLI_DECODER_SUCCESS;
} /* Fall through. */
case BROTLI_STATE_DECODE_UINT8_SHORT: if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, 3, &bits))) {
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_SHORT; return BROTLI_DECODER_NEEDS_MORE_INPUT;
} if (bits == 0) {
*value = 1;
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE; return BROTLI_DECODER_SUCCESS;
} /* Use output value as a temporary storage. It MUST be persisted. */
*value = bits; /* Fall through. */
/* Reads and decodes the next Huffman code from bit-stream.
This method peeks 16 bits of input and drops 0 - 15 of them. */ static BROTLI_INLINE brotli_reg_t ReadSymbol(const HuffmanCode* table,
BrotliBitReader* br) { return DecodeSymbol(BrotliGet16BitsUnmasked(br), table, br);
}
/* Same as DecodeSymbol, but it is known that there is less than 15 bits of
input are currently available. */ static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol( const HuffmanCode* table, BrotliBitReader* br, brotli_reg_t* result) {
brotli_reg_t val;
brotli_reg_t available_bits = BrotliGetAvailableBits(br);
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table); if (available_bits == 0) { if (BROTLI_HC_FAST_LOAD_BITS(table) == 0) {
*result = BROTLI_HC_FAST_LOAD_VALUE(table); return BROTLI_TRUE;
} return BROTLI_FALSE; /* No valid bits at all. */
}
val = BrotliGetBitsUnmasked(br);
BROTLI_HC_ADJUST_TABLE_INDEX(table, val & HUFFMAN_TABLE_MASK); if (BROTLI_HC_FAST_LOAD_BITS(table) <= HUFFMAN_TABLE_BITS) { if (BROTLI_HC_FAST_LOAD_BITS(table) <= available_bits) {
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table));
*result = BROTLI_HC_FAST_LOAD_VALUE(table); return BROTLI_TRUE;
} else { return BROTLI_FALSE; /* Not enough bits for the first level. */
}
} if (available_bits <= HUFFMAN_TABLE_BITS) { return BROTLI_FALSE; /* Not enough bits to move to the second level. */
}
/* Speculatively drop HUFFMAN_TABLE_BITS. */
val = (val & BitMask(BROTLI_HC_FAST_LOAD_BITS(table))) >> HUFFMAN_TABLE_BITS;
available_bits -= HUFFMAN_TABLE_BITS;
BROTLI_HC_ADJUST_TABLE_INDEX(table, BROTLI_HC_FAST_LOAD_VALUE(table) + val); if (available_bits < BROTLI_HC_FAST_LOAD_BITS(table)) { return BROTLI_FALSE; /* Not enough bits for the second level. */
}
/* Makes a look-up in first level Huffman table. Peeks 8 bits. */ static BROTLI_INLINE void PreloadSymbol(int safe, const HuffmanCode* table,
BrotliBitReader* br,
brotli_reg_t* bits,
brotli_reg_t* value) { if (safe) { return;
}
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
BROTLI_HC_ADJUST_TABLE_INDEX(table, BrotliGetBits(br, HUFFMAN_TABLE_BITS));
*bits = BROTLI_HC_FAST_LOAD_BITS(table);
*value = BROTLI_HC_FAST_LOAD_VALUE(table);
}
/* Decodes the next Huffman code using data prepared by PreloadSymbol.
Reads 0 - 15 bits. Also peeks 8 following bits. */ static BROTLI_INLINE brotli_reg_t ReadPreloadedSymbol(const HuffmanCode* table,
BrotliBitReader* br,
brotli_reg_t* bits,
brotli_reg_t* value) {
brotli_reg_t result = *value; if (BROTLI_PREDICT_FALSE(*bits > HUFFMAN_TABLE_BITS)) {
brotli_reg_t val = BrotliGet16BitsUnmasked(br); const HuffmanCode* ext = table + (val & HUFFMAN_TABLE_MASK) + *value;
brotli_reg_t mask = BitMask((*bits - HUFFMAN_TABLE_BITS));
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(ext);
BrotliDropBits(br, HUFFMAN_TABLE_BITS);
BROTLI_HC_ADJUST_TABLE_INDEX(ext, (val >> HUFFMAN_TABLE_BITS) & mask);
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(ext));
result = BROTLI_HC_FAST_LOAD_VALUE(ext);
} else {
BrotliDropBits(br, *bits);
}
PreloadSymbol(0, table, br, bits, value); return result;
}
/* Reads up to limit symbols from br and copies them into ringbuffer, startingfrompos.Callermustensurethatthereisenoughspace
for the write. Returns the amount of symbols actually copied. */ static BROTLI_INLINE int BrotliCopyPreloadedSymbolsToU8(const HuffmanCode* table,
BrotliBitReader* br,
brotli_reg_t* bits,
brotli_reg_t* value,
uint8_t* ringbuffer, int pos, constint limit) { /* Calculate range where CheckInputAmount is always true.
Start with the number of bytes we can read. */
int64_t new_lim = br->guard_in - br->next_in; /* Convert to bits, since symbols use variable number of bits. */
new_lim *= 8; /* At most 15 bits per symbol, so this is safe. */
new_lim /= 15; constint kMaximalOverread = 4; int pos_limit = limit; int copies = 0; if ((new_lim - kMaximalOverread) <= limit) { // Safe cast, since new_lim is already < num_steps
pos_limit = (int)(new_lim - kMaximalOverread);
} if (pos_limit < 0) {
pos_limit = 0;
}
copies = pos_limit;
pos_limit += pos; /* Fast path, caller made sure it is safe to write,
we verified that is is safe to read. */ for (; pos < pos_limit; pos++) {
BROTLI_DCHECK(BrotliCheckInputAmount(br));
ringbuffer[pos] = (uint8_t)ReadPreloadedSymbol(table, br, bits, value);
BROTLI_LOG_ARRAY_INDEX(ringbuffer, pos);
} /* Do the remainder, caller made sure it is safe to write,
we need to bverify that it is safe to read. */ while (BrotliCheckInputAmount(br) && copies < limit) {
ringbuffer[pos] = (uint8_t)ReadPreloadedSymbol(table, br, bits, value);
BROTLI_LOG_ARRAY_INDEX(ringbuffer, pos);
pos++;
copies++;
} return copies;
}
static BROTLI_INLINE brotli_reg_t Log2Floor(brotli_reg_t x) {
brotli_reg_t result = 0; while (x) {
x >>= 1;
++result;
} return result;
}
/* Reads (s->symbol + 1) symbols. Totally1..4symbolsareread,1..11bitseach.
The list of symbols MUST NOT contain duplicates. */ static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols(
brotli_reg_t alphabet_size_max, brotli_reg_t alphabet_size_limit,
BrotliDecoderState* s) { /* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */
BrotliBitReader* br = &s->br;
BrotliMetablockHeaderArena* h = &s->arena.header;
brotli_reg_t max_bits = Log2Floor(alphabet_size_max - 1);
brotli_reg_t i = h->sub_loop_counter;
brotli_reg_t num_symbols = h->symbol; while (i <= num_symbols) {
brotli_reg_t v; if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) {
h->sub_loop_counter = i;
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ; return BROTLI_DECODER_NEEDS_MORE_INPUT;
} if (v >= alphabet_size_limit) { return
BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
}
h->symbols_lists_array[i] = (uint16_t)v;
BROTLI_LOG_UINT(h->symbols_lists_array[i]);
++i;
}
for (i = 0; i < num_symbols; ++i) {
brotli_reg_t k = i + 1; for (; k <= num_symbols; ++k) { if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) { return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
}
}
}
Mostofinputvaluesare0and1.Toreducenumberofbranches,wereplace
inner for loop with do-while. */ static BROTLI_NOINLINE void InverseMoveToFrontTransform(
uint8_t* v, brotli_reg_t v_len, BrotliDecoderState* state) { /* Reinitialize elements that could have been changed. */
brotli_reg_t i = 1;
brotli_reg_t upper_bound = state->mtf_upper_bound;
uint32_t* mtf = &state->mtf[1]; /* Make mtf[-1] addressable. */
uint8_t* mtf_u8 = (uint8_t*)mtf; /* Load endian-aware constant. */ const uint8_t b0123[4] = {0, 1, 2, 3};
uint32_t pattern;
memcpy(&pattern, &b0123, 4);
/* Initialize list using 4 consequent values pattern. */
mtf[0] = pattern; do {
pattern += 0x04040404; /* Advance all 4 values by 4. */
mtf[i] = pattern;
i++;
} while (i <= upper_bound);
/* Transform the input. */
upper_bound = 0; for (i = 0; i < v_len; ++i) { int index = v[i];
uint8_t value = mtf_u8[index];
upper_bound |= v[i];
v[i] = value;
mtf_u8[-1] = value; do {
index--;
mtf_u8[index + 1] = mtf_u8[index];
} while (index >= 0);
} /* Remember amount of elements to be reinitialized. */
state->mtf_upper_bound = upper_bound >> 2;
}
/* Decodes a series of Huffman table using ReadHuffmanCode function. */ static BrotliDecoderErrorCode HuffmanTreeGroupDecode(
HuffmanTreeGroup* group, BrotliDecoderState* s) {
BrotliMetablockHeaderArena* h = &s->arena.header; if (h->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
h->next = group->codes;
h->htree_index = 0;
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
} while (h->htree_index < group->num_htrees) {
brotli_reg_t table_size;
BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max,
group->alphabet_size_limit, h->next, &table_size, s); if (result != BROTLI_DECODER_SUCCESS) return result;
group->htrees[h->htree_index] = h->next;
h->next += table_size;
++h->htree_index;
}
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; return BROTLI_DECODER_SUCCESS;
}
/* Decodes a context map. Decodingisdonein4phases: 1)Readauxiliaryinformation(6..16bits)andallocatememory. Incaseoftrivialcontextmap,decodingisfinishedatthisphase. 2)DecodeHuffmantableusingReadHuffmanCodefunction. Thistablewillbeusedforreadingcontextmapitems. 3)Readcontextmapitems;"0"valuescouldberun-lengthencoded.
4) Optionally, apply InverseMoveToFront transform to the resulting map. */ static BrotliDecoderErrorCode DecodeContextMap(brotli_reg_t context_map_size,
brotli_reg_t* num_htrees,
uint8_t** context_map_arg,
BrotliDecoderState* s) {
BrotliBitReader* br = &s->br;
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
BrotliMetablockHeaderArena* h = &s->arena.header;
switch ((int)h->substate_context_map) { case BROTLI_STATE_CONTEXT_MAP_NONE:
result = DecodeVarLenUint8(s, br, num_htrees); if (result != BROTLI_DECODER_SUCCESS) { return result;
}
(*num_htrees)++;
h->context_index = 0;
BROTLI_LOG_UINT(context_map_size);
BROTLI_LOG_UINT(*num_htrees);
*context_map_arg =
(uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)context_map_size); if (*context_map_arg == 0) { return BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP);
} if (*num_htrees <= 1) {
memset(*context_map_arg, 0, (size_t)context_map_size); return BROTLI_DECODER_SUCCESS;
}
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX; /* Fall through. */
case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: {
brotli_reg_t bits; /* In next stage ReadHuffmanCode uses at least 4 bits, so it is safe
to peek 4 bits ahead. */ if (!BrotliSafeGetBits(br, 5, &bits)) { return BROTLI_DECODER_NEEDS_MORE_INPUT;
} if ((bits & 1) != 0) { /* Use RLE for zeros. */
h->max_run_length_prefix = (bits >> 1) + 1;
BrotliDropBits(br, 5);
} else {
h->max_run_length_prefix = 0;
BrotliDropBits(br, 1);
}
BROTLI_LOG_UINT(h->max_run_length_prefix);
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
} /* Fall through. */
case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: {
brotli_reg_t alphabet_size = *num_htrees + h->max_run_length_prefix;
result = ReadHuffmanCode(alphabet_size, alphabet_size,
h->context_map_table, NULL, s); if (result != BROTLI_DECODER_SUCCESS) return result;
h->code = 0xFFFF;
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
} /* Fall through. */
/* Decodes the block type and updates the state for literal context.
Reads 3..54 bits. */ static BROTLI_INLINE BrotliDecoderErrorCode DecodeLiteralBlockSwitchInternal( int safe, BrotliDecoderState* s) {
BrotliDecoderErrorCode result = DecodeBlockTypeAndLength(safe, s, 0); if (result != BROTLI_DECODER_SUCCESS) { return result;
}
PrepareLiteralDecoding(s); return BROTLI_DECODER_SUCCESS;
}
Lasttwobytesofring-bufferareinitializedto0,socontextcalculation
could be done uniformly for the first two and all other positions. */ static BROTLI_BOOL BROTLI_NOINLINE BrotliEnsureRingBuffer(
BrotliDecoderState* s) {
uint8_t* old_ringbuffer = s->ringbuffer; if (s->ringbuffer_size == s->new_ringbuffer_size) { return BROTLI_TRUE;
}
When this method is called, metablock size and flags MUST be decoded. */ staticvoid BROTLI_NOINLINE BrotliCalculateRingBufferSize(
BrotliDecoderState* s) { int window_size = 1 << s->window_bits; int new_ringbuffer_size = window_size; /* We need at least 2 bytes of ring buffer size to get the last two
bytes for context from there */ int min_size = s->ringbuffer_size ? s->ringbuffer_size : 1024; int output_size;
/* If maximum is already reached, no further extension is retired. */ if (s->ringbuffer_size == window_size) { return;
}
/* Metadata blocks does not touch ring buffer. */ if (s->is_metadata) { return;
}
if (!!s->canny_ringbuffer_allocation) { /* Reduce ring buffer size to save memory when server is unscrupulous. Inworstcasememoryusagemightbe1.5xbiggerforashortperiodof
ring buffer reallocation. */ 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. */ static BrotliDecoderErrorCode ReadContextModes(BrotliDecoderState* s) {
BrotliBitReader* br = &s->br; int i = s->loop_counter;
while (i < (int)s->num_block_types[0]) {
brotli_reg_t bits; if (!BrotliSafeReadBits(br, 2, &bits)) {
s->loop_counter = i; return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
s->context_modes[i] = (uint8_t)bits;
BROTLI_LOG_ARRAY_INDEX(s->context_modes, i);
i++;
} return BROTLI_DECODER_SUCCESS;
}
static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) { int offset = s->distance_code - 3; if (s->distance_code <= 3) { /* Compensate double distance-ring-buffer roll for dictionary items. */
s->distance_context = 1 >> s->distance_code;
s->distance_code = s->dist_rb[(s->dist_rb_idx - offset) & 3];
s->dist_rb_idx -= s->distance_context;
} else { int index_delta = 3; int delta; int base = s->distance_code - 10; if (s->distance_code < 10) {
base = s->distance_code - 4;
} else {
index_delta = 2;
} /* Unpack one of six 4-bit values. */
delta = ((0x605142 >> (4 * base)) & 0xF) - 3;
s->distance_code = s->dist_rb[(s->dist_rb_idx + index_delta) & 0x3] + delta; if (s->distance_code <= 0) { /* A huge distance will cause a BROTLI_FAILURE() soon.
This is a little faster than failing here. */
s->distance_code = 0x7FFFFFFF;
}
}
}
static BROTLI_INLINE BROTLI_BOOL CheckInputAmount( int safe, BrotliBitReader* const br) { if (safe) { return BROTLI_TRUE;
} return BrotliCheckInputAmount(br);
}
/* NB: METHOD should return BROTLI_FALSE only in case there is not enough input; incaseof"unsafe"execution,wheninputisguaranteedtobesufficient,
result is ignored. */ #define BROTLI_SAFE(METHOD) \
{ \ if (safe) { \ if (!Safe##METHOD) { \
result = BROTLI_DECODER_NEEDS_MORE_INPUT; \ goto saveStateAndReturn; \
} \
} else { \
METHOD; \
} \
}
/* NB: METHOD should return BROTLI_DECODER_SUCCESS, BROTLI_DECODER_ERROR_*, or
BROTLI_DECODER_NEEDS_MORE_INPUT; the later two break the processing. */ #define BROTLI_SAFE_WITH_STATUS(METHOD) \
{ \
BrotliDecoderErrorCode status; \ if (safe) { \
status = Safe##METHOD; \
} else { \
status = METHOD; \
} \ if (status != BROTLI_DECODER_SUCCESS) { \
result = status; \ goto saveStateAndReturn; \
} \
}
static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( int safe, BrotliDecoderState* s) { int pos = s->pos; int i = s->loop_counter;
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
BrotliBitReader* br = &s->br; int compound_dictionary_size = GetCompoundDictionarySize(s);
if (!CheckInputAmount(safe, br)) {
result = BROTLI_DECODER_NEEDS_MORE_INPUT; goto saveStateAndReturn;
} if (!safe) {
BROTLI_UNUSED(BrotliWarmupBitReader(br));
}
/* Invariant: input stream is never overconsumed: -invalidinputimpliesthatthewholestreamisinvalid->anyamountof inputcouldbereadanddiscarded -whenresultis"needsmoreinput",thenatleastonemorebyteisREQUIRED tocompletedecoding;allinputdataMUSTbeconsumedbydecoder,so clientcouldswaptheinputbuffer -whenresultis"needsmoreoutput"decoderMUSTensurethatitdoesn't holdmorethan7bitsinbitreader;thissavesclientfromswappinginput bufferaheadoftime -whenresultis"success"decoderMUSTreturnallunuseddatabacktoinput
buffer; this is possible because the invariant is held on enter */
BrotliDecoderResult BrotliDecoderDecompressStream(
BrotliDecoderState* s, size_t* available_in, const uint8_t** next_in,
size_t* available_out, uint8_t** next_out, size_t* total_out) {
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
BrotliBitReader* br = &s->br;
size_t input_size = *available_in; #define BROTLI_SAVE_ERROR_CODE(code) \
SaveErrorCode(s, (code), input_size - *available_in) /* Ensure that |total_out| is set, even if no data will ever be pushed out. */ if (total_out) {
*total_out = s->partial_pos_out;
} /* Do not try to process further in a case of unrecoverable error. */ if ((int)s->error_code < 0) { return BROTLI_DECODER_RESULT_ERROR;
} if (*available_out && (!next_out || !*next_out)) { return BROTLI_SAVE_ERROR_CODE(
BROTLI_FAILURE(BROTLI_DECODER_ERROR_INVALID_ARGUMENTS));
} if (!*available_out) next_out = 0; if (s->buffer_length == 0) { /* Just connect bit reader to input stream. */
BrotliBitReaderSetInput(br, *next_in, *available_in);
} else { /* At least one byte of input is required. More than one byte of input may berequiredtocompletethetransaction->readingmoredatamustbe
done in a loop -> do it in a main loop. */
result = BROTLI_DECODER_NEEDS_MORE_INPUT;
BrotliBitReaderSetInput(br, &s->buffer.u8[0], s->buffer_length);
} /* State machine */ for (;;) { if (result != BROTLI_DECODER_SUCCESS) { /* Error, needs more input/output. */ if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) { if (s->ringbuffer != 0) { /* Pro-actively push output. */
BrotliDecoderErrorCode intermediate_result = WriteRingBuffer(s,
available_out, next_out, total_out, BROTLI_TRUE); /* WriteRingBuffer checks s->meta_block_remaining_len validity. */ if ((int)intermediate_result < 0) {
result = intermediate_result; break;
}
} if (s->buffer_length != 0) { /* Used with internal buffer. */ if (br->next_in == br->last_in) { /* Successfully finished read transaction. Accumulatorcontainslessthan8bits,becauseinternalbuffer
is expanded byte-by-byte until it is enough to complete read. */
s->buffer_length = 0; /* Switch to input stream and restart. */
result = BROTLI_DECODER_SUCCESS;
BrotliBitReaderSetInput(br, *next_in, *available_in); continue;
} elseif (*available_in != 0) { /* Not enough data in buffer, but can take one more byte from
input stream. */
result = BROTLI_DECODER_SUCCESS;
BROTLI_DCHECK(s->buffer_length < 8);
s->buffer.u8[s->buffer_length] = **next_in;
s->buffer_length++;
BrotliBitReaderSetInput(br, &s->buffer.u8[0], s->buffer_length);
(*next_in)++;
(*available_in)--; /* Retry with more data in buffer. */ continue;
} /* Can't finish reading and no more input. */ break;
} else { /* Input stream doesn't contain enough input. */ /* Copy tail to internal buffer and return. */
*next_in = br->next_in;
*available_in = BrotliBitReaderGetAvailIn(br); while (*available_in) {
s->buffer.u8[s->buffer_length] = **next_in;
s->buffer_length++;
(*next_in)++;
(*available_in)--;
} break;
} /* Unreachable. */
}
/* Fail or needs more output. */
if (s->buffer_length != 0) { /* Just consumed the buffered input and produced some output. Otherwise
it would result in "needs more input". Reset internal buffer. */
s->buffer_length = 0;
} else { /* Using input stream in last iteration. When decoder switches to input streamithaslessthan8bitsinaccumulator,soitissafeto
return unused accumulator bits there. */
BrotliBitReaderUnload(br);
*available_in = BrotliBitReaderGetAvailIn(br);
*next_in = br->next_in;
} break;
} switch (s->state) { case BROTLI_STATE_UNINITED: /* Prepare to the first read. */ if (!BrotliWarmupBitReader(br)) {
result = BROTLI_DECODER_NEEDS_MORE_INPUT; break;
} /* Decode window size. */
result = DecodeWindowBits(s, br); /* Reads 1..8 bits. */ if (result != BROTLI_DECODER_SUCCESS) { break;
} if (s->large_window) {
s->state = BROTLI_STATE_LARGE_WINDOW_BITS; break;
}
s->state = BROTLI_STATE_INITIALIZE; break;
case BROTLI_STATE_LARGE_WINDOW_BITS: {
brotli_reg_t bits; if (!BrotliSafeReadBits(br, 6, &bits)) {
result = BROTLI_DECODER_NEEDS_MORE_INPUT; break;
}
s->window_bits = bits & 63u; if (s->window_bits < BROTLI_LARGE_MIN_WBITS ||
s->window_bits > BROTLI_LARGE_MAX_WBITS) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); break;
}
s->state = BROTLI_STATE_INITIALIZE;
} /* Fall through. */
case BROTLI_STATE_INITIALIZE:
BROTLI_LOG_UINT(s->window_bits); /* Maximum distance, see section 9.1. of the spec. */
s->max_backward_distance = (1 << s->window_bits) - BROTLI_WINDOW_GAP;
/* Allocate memory for both block_type_trees and block_len_trees. */
s->block_type_trees = (HuffmanCode*)BROTLI_DECODER_ALLOC(s, sizeof(HuffmanCode) * 3 *
(BROTLI_HUFFMAN_MAX_SIZE_258 + BROTLI_HUFFMAN_MAX_SIZE_26)); if (s->block_type_trees == 0) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES); break;
}
s->block_len_trees =
s->block_type_trees + 3 * BROTLI_HUFFMAN_MAX_SIZE_258;
s->state = BROTLI_STATE_METABLOCK_BEGIN; /* Fall through. */
case BROTLI_STATE_METABLOCK_BEGIN:
BrotliDecoderStateMetablockBegin(s);
BROTLI_LOG_UINT(s->pos);
s->state = BROTLI_STATE_METABLOCK_HEADER; /* Fall through. */
case BROTLI_STATE_METABLOCK_HEADER:
result = DecodeMetaBlockLength(s, br); /* Reads 2 - 31 bits. */ if (result != BROTLI_DECODER_SUCCESS) { break;
}
BROTLI_DCHECK(s->meta_block_remaining_len <=
(int)BROTLI_BLOCK_SIZE_CAP);
BROTLI_LOG_UINT(s->is_last_metablock);
BROTLI_LOG_UINT(s->meta_block_remaining_len);
BROTLI_LOG_UINT(s->is_metadata);
BROTLI_LOG_UINT(s->is_uncompressed); if (s->is_metadata || s->is_uncompressed) { if (!BrotliJumpToByteBoundary(br)) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_PADDING_1); break;
}
} if (s->is_metadata) {
s->state = BROTLI_STATE_METADATA; if (s->metadata_start_func) {
s->metadata_start_func(s->metadata_callback_opaque,
(size_t)s->meta_block_remaining_len);
} break;
} if (s->meta_block_remaining_len == 0) {
s->state = BROTLI_STATE_METABLOCK_DONE; break;
}
BrotliCalculateRingBufferSize(s); if (s->is_uncompressed) {
s->state = BROTLI_STATE_UNCOMPRESSED; break;
}
s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER; /* Fall through. */
case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER: {
BrotliMetablockHeaderArena* h = &s->arena.header;
s->loop_counter = 0; /* Initialize compressed metablock header arena. */
h->sub_loop_counter = 0; /* Make small negative indexes addressable. */
h->symbol_lists =
&h->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
s->state = BROTLI_STATE_HUFFMAN_CODE_0;
} /* Fall through. */
case BROTLI_STATE_HUFFMAN_CODE_0: if (s->loop_counter >= 3) {
s->state = BROTLI_STATE_METABLOCK_HEADER_2; break;
} /* Reads 1..11 bits. */
result = DecodeVarLenUint8(s, br, &s->num_block_types[s->loop_counter]); if (result != BROTLI_DECODER_SUCCESS) { break;
}
s->num_block_types[s->loop_counter]++;
BROTLI_LOG_UINT(s->num_block_types[s->loop_counter]); if (s->num_block_types[s->loop_counter] < 2) {
s->loop_counter++; break;
}
s->state = BROTLI_STATE_HUFFMAN_CODE_1; /* Fall through. */
case BROTLI_STATE_HUFFMAN_CODE_1: {
brotli_reg_t alphabet_size = s->num_block_types[s->loop_counter] + 2; int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_258;
result = ReadHuffmanCode(alphabet_size, alphabet_size,
&s->block_type_trees[tree_offset], NULL, s); if (result != BROTLI_DECODER_SUCCESS) break;
s->state = BROTLI_STATE_HUFFMAN_CODE_2;
} /* Fall through. */
case BROTLI_STATE_HUFFMAN_CODE_2: {
brotli_reg_t alphabet_size = BROTLI_NUM_BLOCK_LEN_SYMBOLS; int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26;
result = ReadHuffmanCode(alphabet_size, alphabet_size,
&s->block_len_trees[tree_offset], NULL, s); if (result != BROTLI_DECODER_SUCCESS) break;
s->state = BROTLI_STATE_HUFFMAN_CODE_3;
} /* Fall through. */
case BROTLI_STATE_HUFFMAN_CODE_3: { int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26; if (!SafeReadBlockLength(s, &s->block_length[s->loop_counter],
&s->block_len_trees[tree_offset], br)) {
result = BROTLI_DECODER_NEEDS_MORE_INPUT; break;
}
BROTLI_LOG_UINT(s->block_length[s->loop_counter]);
s->loop_counter++;
s->state = BROTLI_STATE_HUFFMAN_CODE_0; break;
}
case BROTLI_STATE_UNCOMPRESSED: {
result = CopyUncompressedBlockToOutput(
available_out, next_out, total_out, s); if (result != BROTLI_DECODER_SUCCESS) { break;
}
s->state = BROTLI_STATE_METABLOCK_DONE; break;
}
case BROTLI_STATE_METADATA:
result = SkipMetadataBlock(s); if (result != BROTLI_DECODER_SUCCESS) { break;
}
s->state = BROTLI_STATE_METABLOCK_DONE; break;
case BROTLI_STATE_METABLOCK_HEADER_2: {
brotli_reg_t bits; if (!BrotliSafeReadBits(br, 6, &bits)) {
result = BROTLI_DECODER_NEEDS_MORE_INPUT; break;
}
s->distance_postfix_bits = bits & BitMask(2);
bits >>= 2;
s->num_direct_distance_codes = bits << s->distance_postfix_bits;
BROTLI_LOG_UINT(s->num_direct_distance_codes);
BROTLI_LOG_UINT(s->distance_postfix_bits);
s->context_modes =
(uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)s->num_block_types[0]); if (s->context_modes == 0) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES); break;
}
s->loop_counter = 0;
s->state = BROTLI_STATE_CONTEXT_MODES;
} /* Fall through. */
case BROTLI_STATE_CONTEXT_MODES:
result = ReadContextModes(s); if (result != BROTLI_DECODER_SUCCESS) { break;
}
s->state = BROTLI_STATE_CONTEXT_MAP_1; /* Fall through. */
case BROTLI_STATE_CONTEXT_MAP_1:
result = DecodeContextMap(
s->num_block_types[0] << BROTLI_LITERAL_CONTEXT_BITS,
&s->num_literal_htrees, &s->context_map, s); if (result != BROTLI_DECODER_SUCCESS) { break;
}
DetectTrivialLiteralBlockTypes(s);
s->state = BROTLI_STATE_CONTEXT_MAP_2; /* Fall through. */
case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY:
PrepareLiteralDecoding(s);
s->dist_context_map_slice = s->dist_context_map;
s->htree_command = s->insert_copy_hgroup.htrees[0]; if (!BrotliEnsureRingBuffer(s)) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); break;
}
CalculateDistanceLut(s);
s->state = BROTLI_STATE_COMMAND_BEGIN; /* Fall through. */
case BROTLI_STATE_COMMAND_BEGIN: /* Fall through. */ case BROTLI_STATE_COMMAND_INNER: /* Fall through. */ case BROTLI_STATE_COMMAND_POST_DECODE_LITERALS: /* Fall through. */ case BROTLI_STATE_COMMAND_POST_WRAP_COPY:
result = ProcessCommands(s); if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
result = SafeProcessCommands(s);
} break;
case BROTLI_STATE_COMMAND_INNER_WRITE: /* Fall through. */ case BROTLI_STATE_COMMAND_POST_WRITE_1: /* Fall through. */ case BROTLI_STATE_COMMAND_POST_WRITE_2:
result = WriteRingBuffer(
s, available_out, next_out, total_out, BROTLI_FALSE); if (result != BROTLI_DECODER_SUCCESS) { break;
}
WrapRingBuffer(s); if (s->ringbuffer_size == 1 << s->window_bits) {
s->max_distance = s->max_backward_distance;
} if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_1) {
BrotliDecoderCompoundDictionary* addon = s->compound_dictionary; if (addon && (addon->br_length != addon->br_copied)) {
s->pos += CopyFromCompoundDictionary(s, s->pos); if (s->pos >= s->ringbuffer_size) continue;
} if (s->meta_block_remaining_len == 0) { /* Next metablock, if any. */
s->state = BROTLI_STATE_METABLOCK_DONE;
} else {
s->state = BROTLI_STATE_COMMAND_BEGIN;
} break;
} elseif (s->state == BROTLI_STATE_COMMAND_POST_WRITE_2) {
s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY;
} else { /* BROTLI_STATE_COMMAND_INNER_WRITE */ if (s->loop_counter == 0) { if (s->meta_block_remaining_len == 0) {
s->state = BROTLI_STATE_METABLOCK_DONE;
} else {
s->state = BROTLI_STATE_COMMAND_POST_DECODE_LITERALS;
} break;
}
s->state = BROTLI_STATE_COMMAND_INNER;
} break;
case BROTLI_STATE_METABLOCK_DONE: if (s->meta_block_remaining_len < 0) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2); break;
}
BrotliDecoderStateCleanupAfterMetablock(s); if (!s->is_last_metablock) {
s->state = BROTLI_STATE_METABLOCK_BEGIN; break;
} if (!BrotliJumpToByteBoundary(br)) {
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_PADDING_2); break;
} if (s->buffer_length == 0) {
BrotliBitReaderUnload(br);
*available_in = BrotliBitReaderGetAvailIn(br);
*next_in = br->next_in;
}
s->state = BROTLI_STATE_DONE; /* Fall through. */
case BROTLI_STATE_DONE: if (s->ringbuffer != 0) {
result = WriteRingBuffer(
s, available_out, next_out, total_out, BROTLI_TRUE); if (result != BROTLI_DECODER_SUCCESS) { break;
}
} return BROTLI_SAVE_ERROR_CODE(result);
}
} return BROTLI_SAVE_ERROR_CODE(result); #undef BROTLI_SAVE_ERROR_CODE
}
BROTLI_BOOL BrotliDecoderHasMoreOutput(const BrotliDecoderState* s) { /* After unrecoverable error remaining output is considered nonsensical. */ if ((int)s->error_code < 0) { return BROTLI_FALSE;
} return TO_BROTLI_BOOL(
s->ringbuffer != 0 && UnwrittenBytes(s, BROTLI_FALSE) != 0);
}
const uint8_t* BrotliDecoderTakeOutput(BrotliDecoderState* s, size_t* size) {
uint8_t* result = 0;
size_t available_out = *size ? *size : 1u << 24;
size_t requested_out = available_out;
BrotliDecoderErrorCode status; if ((s->ringbuffer == 0) || ((int)s->error_code < 0)) {
*size = 0; return0;
}
WrapRingBuffer(s);
status = WriteRingBuffer(s, &available_out, &result, 0, BROTLI_TRUE); /* Either WriteRingBuffer returns those "success" codes... */ if (status == BROTLI_DECODER_SUCCESS ||
status == BROTLI_DECODER_NEEDS_MORE_OUTPUT) {
*size = requested_out - available_out;
} else { /* ... or stream is broken. Normally this should be caught by
BrotliDecoderDecompressStream, this is just a safeguard. */ if ((int)status < 0) SaveErrorCode(s, status, 0);
*size = 0;
result = 0;
} return result;
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.62Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-24)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.