mirror of
https://github.com/google/brotli.git
synced 2025-01-01 04:40:08 +00:00
Add partial output support to the decoder.
This commit is contained in:
parent
5ded136348
commit
64c261113f
240
dec/decode.c
240
dec/decode.c
@ -191,7 +191,7 @@ static BrotliResult ReadHuffmanCodeLengths(
|
||||
const HuffmanCode* p = s->table;
|
||||
uint8_t code_len;
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
return BROTLI_RESULT_PARTIAL;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
BrotliFillBitWindow(br);
|
||||
p += (br->val_ >> br->bit_pos_) & 31;
|
||||
@ -259,7 +259,7 @@ static BrotliResult ReadHuffmanCode(int alphabet_size,
|
||||
switch(s->sub_state[1]) {
|
||||
case BROTLI_STATE_SUB_NONE:
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
return BROTLI_RESULT_PARTIAL;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
s->code_lengths =
|
||||
(uint8_t*)BrotliSafeMalloc((uint64_t)alphabet_size,
|
||||
@ -471,7 +471,7 @@ static BrotliResult DecodeContextMap(int context_map_size,
|
||||
switch(s->sub_state[0]) {
|
||||
case BROTLI_STATE_SUB_NONE:
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
return BROTLI_RESULT_PARTIAL;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
*num_htrees = DecodeVarLenUint8(br) + 1;
|
||||
|
||||
@ -512,7 +512,7 @@ static BrotliResult DecodeContextMap(int context_map_size,
|
||||
while (s->context_index < context_map_size) {
|
||||
int code;
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
return BROTLI_RESULT_PARTIAL;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
code = ReadSymbol(s->context_map_table, br);
|
||||
if (code == 0) {
|
||||
@ -647,6 +647,7 @@ BrotliResult CopyUncompressedBlockToOutput(BrotliOutput output,
|
||||
int br_pos = s->br.pos_ & BROTLI_IBUF_MASK;
|
||||
uint32_t remaining_bits;
|
||||
int num_read;
|
||||
int num_written;
|
||||
|
||||
/* State machine */
|
||||
for (;;) {
|
||||
@ -691,13 +692,24 @@ BrotliResult CopyUncompressedBlockToOutput(BrotliOutput output,
|
||||
rb_pos += s->nbytes;
|
||||
s->meta_block_remaining_len -= s->nbytes;
|
||||
|
||||
s->partially_written = 0;
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_1;
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_1:
|
||||
/* If we wrote past the logical end of the ringbuffer, copy the tail of
|
||||
the ringbuffer to its beginning and flush the ringbuffer to the
|
||||
output. */
|
||||
if (rb_pos >= rb_size) {
|
||||
if (BrotliWrite(output, s->ringbuffer, (size_t)rb_size) < rb_size) {
|
||||
num_written = BrotliWrite(output,
|
||||
s->ringbuffer + s->partially_written,
|
||||
(size_t)(rb_size - s->partially_written));
|
||||
if (num_written < 0) {
|
||||
return BROTLI_RESULT_ERROR;
|
||||
}
|
||||
s->partially_written += num_written;
|
||||
if (s->partially_written < rb_size) {
|
||||
return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
}
|
||||
rb_pos -= rb_size;
|
||||
s->meta_block_remaining_len += rb_size;
|
||||
memcpy(s->ringbuffer, ringbuffer_end, (size_t)rb_pos);
|
||||
@ -707,37 +719,66 @@ BrotliResult CopyUncompressedBlockToOutput(BrotliOutput output,
|
||||
case BROTLI_STATE_SUB_UNCOMPRESSED_SHORT:
|
||||
while (s->meta_block_remaining_len > 0) {
|
||||
if (!BrotliReadMoreInput(&s->br)) {
|
||||
return BROTLI_RESULT_PARTIAL;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
s->ringbuffer[rb_pos++] = (uint8_t)BrotliReadBits(&s->br, 8);
|
||||
if (rb_pos == rb_size) {
|
||||
if (BrotliWrite(output, s->ringbuffer, (size_t)rb_size) < rb_size) {
|
||||
return BROTLI_RESULT_ERROR;
|
||||
}
|
||||
rb_pos = 0;
|
||||
s->partially_written = 0;
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_2;
|
||||
break;
|
||||
}
|
||||
s->meta_block_remaining_len--;
|
||||
}
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_NONE;
|
||||
return BROTLI_RESULT_SUCCESS;
|
||||
if (s->sub_state[0] == BROTLI_STATE_SUB_UNCOMPRESSED_SHORT) {
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_NONE;
|
||||
return BROTLI_RESULT_SUCCESS;
|
||||
}
|
||||
/* No break, if state is updated, continue to next state */
|
||||
case BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_2:
|
||||
num_written = BrotliWrite(output, s->ringbuffer + s->partially_written,
|
||||
(size_t)(rb_size - s->partially_written));
|
||||
if (num_written < 0) {
|
||||
return BROTLI_RESULT_ERROR;
|
||||
}
|
||||
s->partially_written += num_written;
|
||||
if (s->partially_written < rb_size) {
|
||||
return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
}
|
||||
rb_pos = 0;
|
||||
s->meta_block_remaining_len--;
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_UNCOMPRESSED_SHORT;
|
||||
break;
|
||||
case BROTLI_STATE_SUB_UNCOMPRESSED_FILL:
|
||||
/* If we have more to copy than the remaining size of the ringbuffer,
|
||||
then we first fill the ringbuffer from the input and then flush the
|
||||
ringbuffer to the output */
|
||||
while (rb_pos + s->meta_block_remaining_len >= rb_size) {
|
||||
if (rb_pos + s->meta_block_remaining_len >= rb_size) {
|
||||
s->nbytes = rb_size - rb_pos;
|
||||
if (BrotliRead(s->br.input_, &s->ringbuffer[rb_pos],
|
||||
(size_t)s->nbytes) < s->nbytes) {
|
||||
return BROTLI_RESULT_PARTIAL;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (BrotliWrite(output, s->ringbuffer, (size_t)rb_size) < s->nbytes) {
|
||||
return BROTLI_RESULT_ERROR;
|
||||
}
|
||||
s->meta_block_remaining_len -= s->nbytes;
|
||||
rb_pos = 0;
|
||||
s->partially_written = 0;
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_3;
|
||||
} else {
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_UNCOMPRESSED_COPY;
|
||||
break;
|
||||
}
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_UNCOMPRESSED_COPY;
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_3:
|
||||
num_written = BrotliWrite(output, s->ringbuffer + s->partially_written,
|
||||
(size_t)(rb_size - s->partially_written));
|
||||
if (num_written < 0) {
|
||||
return BROTLI_RESULT_ERROR;
|
||||
}
|
||||
s->partially_written += num_written;
|
||||
if (s->partially_written < rb_size) {
|
||||
return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
}
|
||||
s->meta_block_remaining_len -= s->nbytes;
|
||||
rb_pos = 0;
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_UNCOMPRESSED_FILL;
|
||||
break;
|
||||
case BROTLI_STATE_SUB_UNCOMPRESSED_COPY:
|
||||
/* Copy straight from the input onto the ringbuffer. The ringbuffer will
|
||||
be flushed to the output at a later time. */
|
||||
@ -745,7 +786,7 @@ BrotliResult CopyUncompressedBlockToOutput(BrotliOutput output,
|
||||
(size_t)s->meta_block_remaining_len);
|
||||
s->meta_block_remaining_len -= num_read;
|
||||
if (s->meta_block_remaining_len > 0) {
|
||||
return BROTLI_RESULT_PARTIAL;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
|
||||
/* Restore the state of the bit reader. */
|
||||
@ -754,7 +795,7 @@ BrotliResult CopyUncompressedBlockToOutput(BrotliOutput output,
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_SUB_UNCOMPRESSED_WARMUP:
|
||||
if (!BrotliWarmupBitReader(&s->br)) {
|
||||
return BROTLI_RESULT_PARTIAL;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
s->sub_state[0] = BROTLI_STATE_SUB_NONE;
|
||||
return BROTLI_RESULT_SUCCESS;
|
||||
@ -845,7 +886,7 @@ BrotliResult BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
||||
BrotliResult result;
|
||||
BrotliStateInit(&s);
|
||||
result = BrotliDecompressStreaming(input, output, 1, &s);
|
||||
if (result == BROTLI_RESULT_PARTIAL) {
|
||||
if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
|
||||
/* Not ok: it didn't finish even though this is a non-streaming function. */
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
}
|
||||
@ -889,6 +930,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
BrotliBitReader* br = &s->br;
|
||||
int initial_remaining_len;
|
||||
int bytes_copied;
|
||||
int num_written;
|
||||
|
||||
/* We need the slack region for the following reasons:
|
||||
- always doing two 8-byte copies for fast backward copying
|
||||
@ -901,7 +943,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
/* State machine */
|
||||
for (;;) {
|
||||
if (result != BROTLI_RESULT_SUCCESS) {
|
||||
if (result == BROTLI_RESULT_PARTIAL && finish) {
|
||||
if (result == BROTLI_RESULT_NEEDS_MORE_INPUT && finish) {
|
||||
printf("Unexpected end of input. State: %d\n", s->state);
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
}
|
||||
@ -930,7 +972,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_BITREADER_WARMUP:
|
||||
if (!BrotliWarmupBitReader(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
/* Decode window size. */
|
||||
@ -961,10 +1003,11 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_METABLOCK_BEGIN:
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
if (s->input_end) {
|
||||
s->partially_written = 0;
|
||||
s->state = BROTLI_STATE_DONE;
|
||||
break;
|
||||
}
|
||||
@ -1002,7 +1045,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_METABLOCK_HEADER_1:
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
BROTLI_LOG_UINT(pos);
|
||||
@ -1042,6 +1085,9 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
initial_remaining_len = s->meta_block_remaining_len;
|
||||
/* pos is given as argument since s->pos is only updated at the end. */
|
||||
result = CopyUncompressedBlockToOutput(output, pos, s);
|
||||
if (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
|
||||
break;
|
||||
}
|
||||
bytes_copied = initial_remaining_len - s->meta_block_remaining_len;
|
||||
pos += bytes_copied;
|
||||
if (bytes_copied > 0) {
|
||||
@ -1055,7 +1101,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
case BROTLI_STATE_METADATA:
|
||||
for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
|
||||
if (!BrotliReadMoreInput(&s->br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
/* Read one byte and ignore it. */
|
||||
@ -1104,7 +1150,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
break;
|
||||
case BROTLI_STATE_METABLOCK_HEADER_2:
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
s->distance_postfix_bits = (int)BrotliReadBits(br, 2);
|
||||
@ -1178,7 +1224,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
/* Block decoding is the inner loop, jumping with goto makes it 3% faster */
|
||||
BlockBegin:
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
if (s->meta_block_remaining_len <= 0) {
|
||||
@ -1227,7 +1273,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
if (s->trivial_literal_context) {
|
||||
while (i < s->insert_length) {
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
if (s->block_length[0] == 0) {
|
||||
@ -1241,19 +1287,19 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
BROTLI_LOG_UINT(s->literal_htree_index);
|
||||
BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos & s->ringbuffer_mask);
|
||||
if ((pos & s->ringbuffer_mask) == s->ringbuffer_mask) {
|
||||
if (BrotliWrite(output, s->ringbuffer,
|
||||
(size_t)s->ringbuffer_size) < 0) {
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
break;
|
||||
}
|
||||
s->partially_written = 0;
|
||||
s->state = BROTLI_STATE_BLOCK_INNER_WRITE;
|
||||
break;
|
||||
}
|
||||
/* Modifications to this code shold be reflected in
|
||||
BROTLI_STATE_BLOCK_INNER_WRITE case */
|
||||
++pos;
|
||||
++i;
|
||||
}
|
||||
} else {
|
||||
while (i < s->insert_length) {
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
if (s->block_length[0] == 0) {
|
||||
@ -1273,18 +1319,18 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
BROTLI_LOG_UINT(s->literal_htree_index);
|
||||
BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos & s->ringbuffer_mask);
|
||||
if ((pos & s->ringbuffer_mask) == s->ringbuffer_mask) {
|
||||
if (BrotliWrite(output, s->ringbuffer,
|
||||
(size_t)s->ringbuffer_size) < 0) {
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
break;
|
||||
}
|
||||
s->partially_written = 0;
|
||||
s->state = BROTLI_STATE_BLOCK_INNER_WRITE;
|
||||
break;
|
||||
}
|
||||
/* Modifications to this code shold be reflected in
|
||||
BROTLI_STATE_BLOCK_INNER_WRITE case */
|
||||
++pos;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != BROTLI_RESULT_SUCCESS) break;
|
||||
if (result != BROTLI_RESULT_SUCCESS ||
|
||||
s->state == BROTLI_STATE_BLOCK_INNER_WRITE) break;
|
||||
|
||||
s->meta_block_remaining_len -= s->insert_length;
|
||||
if (s->meta_block_remaining_len <= 0) {
|
||||
@ -1299,7 +1345,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
/* No break, go to next state */
|
||||
case BROTLI_STATE_BLOCK_DISTANCE:
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
assert(s->distance_code < 0);
|
||||
@ -1337,7 +1383,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
/* No break, go to next state */
|
||||
case BROTLI_STATE_BLOCK_POST:
|
||||
if (!BrotliReadMoreInput(br)) {
|
||||
result = BROTLI_RESULT_PARTIAL;
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
/* Convert the distance code to the actual distance by possibly */
|
||||
@ -1377,11 +1423,21 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
pos += len;
|
||||
s->meta_block_remaining_len -= len;
|
||||
if (s->copy_dst >= s->ringbuffer_end) {
|
||||
if (BrotliWrite(output, s->ringbuffer,
|
||||
(size_t)s->ringbuffer_size) < 0) {
|
||||
s->partially_written = 0;
|
||||
num_written = BrotliWrite(output, s->ringbuffer,
|
||||
(size_t)s->ringbuffer_size);
|
||||
if (num_written < 0) {
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
break;
|
||||
}
|
||||
s->partially_written += num_written;
|
||||
if (s->partially_written < s->ringbuffer_size) {
|
||||
result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
s->state = BROTLI_STATE_BLOCK_POST_WRITE_1;
|
||||
break;
|
||||
}
|
||||
/* Modifications to this code shold be reflected in
|
||||
BROTLI_STATE_BLOCK_POST_WRITE_1 case */
|
||||
memcpy(s->ringbuffer, s->ringbuffer_end,
|
||||
(size_t)(s->copy_dst - s->ringbuffer_end));
|
||||
}
|
||||
@ -1431,22 +1487,35 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
s->copy_length = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modifications to this loop shold be reflected in
|
||||
BROTLI_STATE_BLOCK_POST_WRITE_2 case */
|
||||
for (i = 0; i < s->copy_length; ++i) {
|
||||
s->ringbuffer[pos & s->ringbuffer_mask] =
|
||||
s->ringbuffer[(pos - s->distance) & s->ringbuffer_mask];
|
||||
if ((pos & s->ringbuffer_mask) == s->ringbuffer_mask) {
|
||||
if (BrotliWrite(output, s->ringbuffer,
|
||||
(size_t)s->ringbuffer_size) < 0) {
|
||||
s->partially_written = 0;
|
||||
num_written = BrotliWrite(output, s->ringbuffer,
|
||||
(size_t)s->ringbuffer_size);
|
||||
if (num_written < 0) {
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
break;
|
||||
}
|
||||
s->partially_written += num_written;
|
||||
if (s->partially_written < s->ringbuffer_size) {
|
||||
result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
s->state = BROTLI_STATE_BLOCK_POST_WRITE_2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++pos;
|
||||
--s->meta_block_remaining_len;
|
||||
}
|
||||
if (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_BLOCK_POST_CONTINUE:
|
||||
/* When we get here, we must have inserted at least one literal and */
|
||||
/* made a copy of at least length two, therefore accessing the last 2 */
|
||||
/* bytes is valid. */
|
||||
@ -1454,6 +1523,62 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
s->prev_byte2 = s->ringbuffer[(pos - 2) & s->ringbuffer_mask];
|
||||
s->state = BROTLI_STATE_BLOCK_BEGIN;
|
||||
goto BlockBegin;
|
||||
case BROTLI_STATE_BLOCK_INNER_WRITE:
|
||||
case BROTLI_STATE_BLOCK_POST_WRITE_1:
|
||||
case BROTLI_STATE_BLOCK_POST_WRITE_2:
|
||||
num_written = BrotliWrite(
|
||||
output, s->ringbuffer + s->partially_written,
|
||||
(size_t)(s->ringbuffer_size - s->partially_written));
|
||||
if (num_written < 0) {
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
break;
|
||||
}
|
||||
s->partially_written += num_written;
|
||||
if (s->partially_written < s->ringbuffer_size) {
|
||||
result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
break;
|
||||
}
|
||||
if (s->state == BROTLI_STATE_BLOCK_POST_WRITE_1) {
|
||||
memcpy(s->ringbuffer, s->ringbuffer_end,
|
||||
(size_t)(s->copy_dst - s->ringbuffer_end));
|
||||
s->state = BROTLI_STATE_BLOCK_POST_CONTINUE;
|
||||
} else if (s->state == BROTLI_STATE_BLOCK_POST_WRITE_2) {
|
||||
/* The tail of "i < s->copy_length" loop. */
|
||||
++pos;
|
||||
--s->meta_block_remaining_len;
|
||||
++i;
|
||||
/* Reenter the loop. */
|
||||
for (; i < s->copy_length; ++i) {
|
||||
s->ringbuffer[pos & s->ringbuffer_mask] =
|
||||
s->ringbuffer[(pos - s->distance) & s->ringbuffer_mask];
|
||||
if ((pos & s->ringbuffer_mask) == s->ringbuffer_mask) {
|
||||
s->partially_written = 0;
|
||||
num_written = BrotliWrite(output, s->ringbuffer,
|
||||
(size_t)s->ringbuffer_size);
|
||||
if (num_written < 0) {
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
break;
|
||||
}
|
||||
s->partially_written += num_written;
|
||||
if (s->partially_written < s->ringbuffer_size) {
|
||||
result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++pos;
|
||||
--s->meta_block_remaining_len;
|
||||
}
|
||||
if (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_BLOCK_POST_CONTINUE;
|
||||
} else { /* BROTLI_STATE_BLOCK_INNER_WRITE */
|
||||
/* The tail of "i < s->insert_length" loop. */
|
||||
++pos;
|
||||
++i;
|
||||
s->state = BROTLI_STATE_BLOCK_INNER;
|
||||
}
|
||||
break;
|
||||
case BROTLI_STATE_METABLOCK_DONE:
|
||||
if (s->context_modes != 0) {
|
||||
free(s->context_modes);
|
||||
@ -1476,10 +1601,17 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
break;
|
||||
case BROTLI_STATE_DONE:
|
||||
if (s->ringbuffer != 0) {
|
||||
if (BrotliWrite(output, s->ringbuffer,
|
||||
(size_t)(pos & s->ringbuffer_mask)) < 0) {
|
||||
num_written = BrotliWrite(
|
||||
output, s->ringbuffer + s->partially_written,
|
||||
(size_t)((pos & s->ringbuffer_mask) - s->partially_written));
|
||||
if (num_written < 0) {
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
}
|
||||
s->partially_written += num_written;
|
||||
if (s->partially_written < (pos & s->ringbuffer_mask)) {
|
||||
result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!JumpToByteBoundary(&s->br)) {
|
||||
result = BROTLI_RESULT_ERROR;
|
||||
|
@ -32,7 +32,9 @@ typedef enum {
|
||||
/* Successfully completely done */
|
||||
BROTLI_RESULT_SUCCESS = 1,
|
||||
/* Partially done, but must be called again with more input */
|
||||
BROTLI_RESULT_PARTIAL = 2
|
||||
BROTLI_RESULT_NEEDS_MORE_INPUT = 2,
|
||||
/* Partially done, but must be called again with more output */
|
||||
BROTLI_RESULT_NEEDS_MORE_OUTPUT = 3
|
||||
} BrotliResult;
|
||||
|
||||
/* Sets *decoded_size to the decompressed size of the given encoded stream. */
|
||||
|
10
dec/state.h
10
dec/state.h
@ -40,7 +40,11 @@ typedef enum {
|
||||
BROTLI_STATE_BLOCK_POST = 16,
|
||||
BROTLI_STATE_UNCOMPRESSED = 17,
|
||||
BROTLI_STATE_METADATA = 18,
|
||||
BROTLI_STATE_BLOCK_INNER_WRITE = 19,
|
||||
BROTLI_STATE_METABLOCK_DONE = 20,
|
||||
BROTLI_STATE_BLOCK_POST_WRITE_1 = 21,
|
||||
BROTLI_STATE_BLOCK_POST_WRITE_2 = 22,
|
||||
BROTLI_STATE_BLOCK_POST_CONTINUE = 23,
|
||||
BROTLI_STATE_HUFFMAN_CODE_0 = 30,
|
||||
BROTLI_STATE_HUFFMAN_CODE_1 = 31,
|
||||
BROTLI_STATE_HUFFMAN_CODE_2 = 32,
|
||||
@ -52,6 +56,9 @@ typedef enum {
|
||||
BROTLI_STATE_SUB_UNCOMPRESSED_FILL = 52,
|
||||
BROTLI_STATE_SUB_UNCOMPRESSED_COPY = 53,
|
||||
BROTLI_STATE_SUB_UNCOMPRESSED_WARMUP = 54,
|
||||
BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_1 = 55,
|
||||
BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_2 = 56,
|
||||
BROTLI_STATE_SUB_UNCOMPRESSED_WRITE_3 = 57,
|
||||
BROTLI_STATE_SUB_HUFFMAN_LENGTH_BEGIN = 60,
|
||||
BROTLI_STATE_SUB_HUFFMAN_LENGTH_SYMBOLS = 61,
|
||||
BROTLI_STATE_SUB_HUFFMAN_DONE = 62,
|
||||
@ -133,6 +140,9 @@ typedef struct {
|
||||
/* For CopyUncompressedBlockToOutput */
|
||||
int nbytes;
|
||||
|
||||
/* For partial write operations */
|
||||
int partially_written;
|
||||
|
||||
/* For HuffmanTreeGroupDecode */
|
||||
int htrees_decoded;
|
||||
|
||||
|
@ -51,8 +51,9 @@ BrotliInput BrotliInitMemInput(const uint8_t* buffer, size_t length,
|
||||
|
||||
int BrotliMemOutputFunction(void* data, const uint8_t* buf, size_t count) {
|
||||
BrotliMemOutput* output = (BrotliMemOutput*)data;
|
||||
if (output->pos + count > output->length) {
|
||||
return -1;
|
||||
size_t limit = output->length - output->pos;
|
||||
if (count > limit) {
|
||||
count = limit;
|
||||
}
|
||||
memcpy(output->buffer + output->pos, buf, count);
|
||||
output->pos += count;
|
||||
|
Loading…
Reference in New Issue
Block a user