summaryrefslogtreecommitdiffstats
path: root/third_party/brotli
diff options
context:
space:
mode:
authoreustas <eustas@chromium.org>2015-04-24 02:09:54 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-24 09:10:54 +0000
commitb908807119a855e63c92f33db3c0657a83b3d85e (patch)
treec0fc1ebf5fbc9877563acdec12f28418e2677c7d /third_party/brotli
parent40d81fd5fea87aa63e82f1875e5874315ab215cf (diff)
downloadchromium_src-b908807119a855e63c92f33db3c0657a83b3d85e.zip
chromium_src-b908807119a855e63c92f33db3c0657a83b3d85e.tar.gz
chromium_src-b908807119a855e63c92f33db3c0657a83b3d85e.tar.bz2
Update Brotli to revision ec03509
This brings in the output streaming decode support. BUG=472009 Review URL: https://codereview.chromium.org/1061993007 Cr-Commit-Position: refs/heads/master@{#326762}
Diffstat (limited to 'third_party/brotli')
-rw-r--r--third_party/brotli/README.chromium2
-rw-r--r--third_party/brotli/dec/Makefile2
-rw-r--r--third_party/brotli/dec/decode.c346
-rw-r--r--third_party/brotli/dec/decode.h4
-rw-r--r--third_party/brotli/dec/state.h12
-rw-r--r--third_party/brotli/dec/streams.c5
6 files changed, 292 insertions, 79 deletions
diff --git a/third_party/brotli/README.chromium b/third_party/brotli/README.chromium
index 73a720e..2a2fe66 100644
--- a/third_party/brotli/README.chromium
+++ b/third_party/brotli/README.chromium
@@ -1,6 +1,6 @@
Name: Brotli
URL: https://github.com/google/brotli
-Version: 9e53d522a34bb8eabfda4a50f7e9da1d1e57a98f
+Version: ec03509d6d5d18a57afe1254e713b6787ef1c516
License: Apache 2.0
License File: LICENSE
Security Critical: yes
diff --git a/third_party/brotli/dec/Makefile b/third_party/brotli/dec/Makefile
index b033c5f..5a1fcd0 100644
--- a/third_party/brotli/dec/Makefile
+++ b/third_party/brotli/dec/Makefile
@@ -2,7 +2,7 @@
include ../shared.mk
-CPPFLAGS += -Wall
+CFLAGS += -Wall
OBJS = bit_reader.o decode.o huffman.o safe_malloc.o state.o streams.o
diff --git a/third_party/brotli/dec/decode.c b/third_party/brotli/dec/decode.c
index 8dc55a0..674dbfb 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:
diff --git a/third_party/brotli/dec/decode.h b/third_party/brotli/dec/decode.h
index 9efd34a..834a7b5 100644
--- a/third_party/brotli/dec/decode.h
+++ b/third_party/brotli/dec/decode.h
@@ -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. */
diff --git a/third_party/brotli/dec/state.h b/third_party/brotli/dec/state.h
index 3b985ec..e5d6b5a 100644
--- a/third_party/brotli/dec/state.h
+++ b/third_party/brotli/dec/state.h
@@ -39,7 +39,12 @@ typedef enum {
BROTLI_STATE_BLOCK_DISTANCE = 15,
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,
@@ -51,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,
@@ -91,6 +99,7 @@ typedef struct {
int trivial_literal_context;
int meta_block_remaining_len;
+ int is_metadata;
int is_uncompressed;
int block_length[3];
int block_type[3];
@@ -131,6 +140,9 @@ typedef struct {
/* For CopyUncompressedBlockToOutput */
int nbytes;
+ /* For partial write operations */
+ int partially_written;
+
/* For HuffmanTreeGroupDecode */
int htrees_decoded;
diff --git a/third_party/brotli/dec/streams.c b/third_party/brotli/dec/streams.c
index 623d417..b33f7a4 100644
--- a/third_party/brotli/dec/streams.c
+++ b/third_party/brotli/dec/streams.c
@@ -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;