Index: third_party/brotli/dec/decode.c |
diff --git a/third_party/brotli/dec/decode.c b/third_party/brotli/dec/decode.c |
index 8dc55a085d3a667a4050d1a1a5f67b33e5af811c..674dbfb5667f1f53e96f86bf007995ebe323966c 100644 |
--- a/third_party/brotli/dec/decode.c |
+++ b/third_party/brotli/dec/decode.c |
@@ -86,26 +86,61 @@ static BROTLI_INLINE int DecodeVarLenUint8(BrotliBitReader* br) { |
return 0; |
} |
-static void DecodeMetaBlockLength(BrotliBitReader* br, |
- int* meta_block_length, |
- int* input_end, |
- int* is_uncompressed) { |
+/* Advances the bit reader position to the next byte boundary and verifies |
+ that any skipped bits are set to zero. */ |
+static BROTLI_INLINE int JumpToByteBoundary(BrotliBitReader* br) { |
+ uint32_t new_bit_pos = (br->bit_pos_ + 7) & (uint32_t)(~7UL); |
+ uint32_t pad_bits = BrotliReadBits(br, (int)(new_bit_pos - br->bit_pos_)); |
+ return pad_bits == 0; |
+} |
+ |
+static int DecodeMetaBlockLength(BrotliBitReader* br, |
+ int* meta_block_length, |
+ int* input_end, |
+ int* is_metadata, |
+ int* is_uncompressed) { |
int size_nibbles; |
+ int size_bytes; |
int i; |
*input_end = (int)BrotliReadBits(br, 1); |
*meta_block_length = 0; |
*is_uncompressed = 0; |
+ *is_metadata = 0; |
if (*input_end && BrotliReadBits(br, 1)) { |
- return; |
+ return 1; |
} |
size_nibbles = (int)BrotliReadBits(br, 2) + 4; |
- for (i = 0; i < size_nibbles; ++i) { |
- *meta_block_length |= (int)BrotliReadBits(br, 4) << (i * 4); |
+ if (size_nibbles == 7) { |
+ *is_metadata = 1; |
+ /* Verify reserved bit. */ |
+ if (BrotliReadBits(br, 1) != 0) { |
+ return 0; |
+ } |
+ size_bytes = (int)BrotliReadBits(br, 2); |
+ if (size_bytes == 0) { |
+ return 1; |
+ } |
+ for (i = 0; i < size_bytes; ++i) { |
+ int next_byte = (int)BrotliReadBits(br, 8); |
+ if (i + 1 == size_bytes && size_bytes > 1 && next_byte == 0) { |
+ return 0; |
+ } |
+ *meta_block_length |= next_byte << (i * 8); |
+ } |
+ } else { |
+ for (i = 0; i < size_nibbles; ++i) { |
+ int next_nibble = (int)BrotliReadBits(br, 4); |
+ if (i + 1 == size_nibbles && size_nibbles > 4 && next_nibble == 0) { |
+ return 0; |
+ } |
+ *meta_block_length |= next_nibble << (i * 4); |
+ } |
} |
++(*meta_block_length); |
- if (!*input_end) { |
+ if (!*input_end && !*is_metadata) { |
*is_uncompressed = (int)BrotliReadBits(br, 1); |
} |
+ return 1; |
} |
/* Decodes the next Huffman code from bit-stream. */ |
@@ -156,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; |
@@ -224,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, |
@@ -250,7 +285,10 @@ static BrotliResult ReadHuffmanCode(int alphabet_size, |
} |
memset(s->code_lengths, 0, (size_t)alphabet_size); |
for (i = 0; i < num_symbols; ++i) { |
- symbols[i] = (int)BrotliReadBits(br, max_bits) % alphabet_size; |
+ symbols[i] = (int)BrotliReadBits(br, max_bits); |
+ if (symbols[i] >= alphabet_size) { |
+ return BROTLI_RESULT_ERROR; |
+ } |
s->code_lengths[symbols[i]] = 2; |
} |
s->code_lengths[symbols[0]] = 1; |
@@ -375,13 +413,6 @@ static int TranslateShortCodes(int code, int* ringbuffer, int index) { |
return val; |
} |
-static void MoveToFront(uint8_t* v, uint8_t index) { |
- uint8_t value = v[index]; |
- uint8_t i = index; |
- for (; i; --i) v[i] = v[i - 1]; |
- v[0] = value; |
-} |
- |
static void InverseMoveToFrontTransform(uint8_t* v, int v_len) { |
uint8_t mtf[256]; |
int i; |
@@ -390,8 +421,12 @@ static void InverseMoveToFrontTransform(uint8_t* v, int v_len) { |
} |
for (i = 0; i < v_len; ++i) { |
uint8_t index = v[i]; |
- v[i] = mtf[index]; |
- if (index) MoveToFront(mtf, index); |
+ uint8_t value = mtf[index]; |
+ v[i] = value; |
+ for (; index; --index) { |
+ mtf[index] = mtf[index - 1]; |
+ } |
+ mtf[0] = value; |
} |
} |
@@ -436,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; |
@@ -477,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) { |
@@ -612,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 (;;) { |
@@ -656,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); |
@@ -672,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; |
- } |
- if (BrotliWrite(output, s->ringbuffer, (size_t)rb_size) < s->nbytes) { |
- return BROTLI_RESULT_ERROR; |
+ return BROTLI_RESULT_NEEDS_MORE_INPUT; |
} |
- 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. */ |
@@ -710,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. */ |
@@ -719,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; |
@@ -810,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; |
} |
@@ -854,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 |
@@ -866,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; |
} |
@@ -895,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. */ |
@@ -926,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; |
} |
@@ -967,19 +1045,36 @@ 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); |
- DecodeMetaBlockLength(br, &s->meta_block_remaining_len, |
- &s->input_end, &s->is_uncompressed); |
+ if (!DecodeMetaBlockLength(br, |
+ &s->meta_block_remaining_len, |
+ &s->input_end, |
+ &s->is_metadata, |
+ &s->is_uncompressed)) { |
+ result = BROTLI_RESULT_ERROR; |
+ break; |
+ } |
BROTLI_LOG_UINT(s->meta_block_remaining_len); |
+ if (s->is_metadata) { |
+ if (!JumpToByteBoundary(&s->br)) { |
+ result = BROTLI_RESULT_ERROR; |
+ break; |
+ } |
+ s->state = BROTLI_STATE_METADATA; |
+ break; |
+ } |
if (s->meta_block_remaining_len == 0) { |
s->state = BROTLI_STATE_METABLOCK_DONE; |
break; |
} |
if (s->is_uncompressed) { |
- BrotliSetBitPos(br, (s->br.bit_pos_ + 7) & (uint32_t)(~7UL)); |
+ if (!JumpToByteBoundary(&s->br)) { |
+ result = BROTLI_RESULT_ERROR; |
+ break; |
+ } |
s->state = BROTLI_STATE_UNCOMPRESSED; |
break; |
} |
@@ -990,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) { |
@@ -1000,6 +1098,17 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output, |
if (result != BROTLI_RESULT_SUCCESS) break; |
s->state = BROTLI_STATE_METABLOCK_DONE; |
break; |
+ case BROTLI_STATE_METADATA: |
+ for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) { |
+ if (!BrotliReadMoreInput(&s->br)) { |
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT; |
+ break; |
+ } |
+ /* Read one byte and ignore it. */ |
+ BrotliReadBits(&s->br, 8); |
+ } |
+ s->state = BROTLI_STATE_METABLOCK_DONE; |
+ break; |
case BROTLI_STATE_HUFFMAN_CODE_0: |
if (i >= 3) { |
BROTLI_LOG_UINT(s->num_block_types[0]); |
@@ -1041,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); |
@@ -1115,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) { |
@@ -1164,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) { |
@@ -1178,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) { |
@@ -1210,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) { |
@@ -1236,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); |
@@ -1274,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 */ |
@@ -1314,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)); |
} |
@@ -1368,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. */ |
@@ -1391,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); |
@@ -1413,10 +1601,20 @@ 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; |
} |
return result; |
default: |