summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreustas <eustas@chromium.org>2015-11-07 15:43:06 -0800
committerCommit bot <commit-bot@chromium.org>2015-11-07 23:43:58 +0000
commitf9a29fdb5041606057668f7a900f6c08ae6d51cb (patch)
treee0464c5cbde49bbf29451ac1c9e8371c69603250
parent67b3cb5374eb47fd6c20924b37141bf9ea5e79d2 (diff)
downloadchromium_src-f9a29fdb5041606057668f7a900f6c08ae6d51cb.zip
chromium_src-f9a29fdb5041606057668f7a900f6c08ae6d51cb.tar.gz
chromium_src-f9a29fdb5041606057668f7a900f6c08ae6d51cb.tar.bz2
Update brotli from 8e90bf4c5f6479353beb83af4118782621947765 (Oct 5 2015) to c90ec29f54e9165df815b0f1311cfddb1be4afad (Nov 7 2015)
BUG=472009 Review URL: https://codereview.chromium.org/1411573011 Cr-Commit-Position: refs/heads/master@{#358538}
-rw-r--r--third_party/brotli/README.chromium2
-rw-r--r--third_party/brotli/dec/bit_reader.c21
-rw-r--r--third_party/brotli/dec/bit_reader.h236
-rw-r--r--third_party/brotli/dec/decode.c2130
-rw-r--r--third_party/brotli/dec/decode.h17
-rw-r--r--third_party/brotli/dec/huffman.c1
-rw-r--r--third_party/brotli/dec/port.h83
-rw-r--r--third_party/brotli/dec/prefix.h2
-rw-r--r--third_party/brotli/dec/state.c46
-rw-r--r--third_party/brotli/dec/state.h68
-rw-r--r--third_party/brotli/dec/streams.c2
-rw-r--r--third_party/brotli/dec/streams.h2
-rw-r--r--third_party/brotli/dec/types.h16
13 files changed, 1676 insertions, 950 deletions
diff --git a/third_party/brotli/README.chromium b/third_party/brotli/README.chromium
index c57d2f2..972cdb3 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: 8e90bf4c5f6479353beb83af4118782621947765
+Version: c90ec29f54e9165df815b0f1311cfddb1be4afad
License: Apache 2.0
License File: LICENSE
Security Critical: yes
diff --git a/third_party/brotli/dec/bit_reader.c b/third_party/brotli/dec/bit_reader.c
index 351cbc2..ddd014e 100644
--- a/third_party/brotli/dec/bit_reader.c
+++ b/third_party/brotli/dec/bit_reader.c
@@ -24,15 +24,9 @@
extern "C" {
#endif
-void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input) {
- BROTLI_DCHECK(br != NULL);
-
- br->input_ = input;
+void BrotliInitBitReader(BrotliBitReader* const br) {
br->val_ = 0;
br->bit_pos_ = sizeof(br->val_) << 3;
- br->avail_in = 0;
- br->eos_ = 0;
- br->next_in = br->buf_;
}
int BrotliWarmupBitReader(BrotliBitReader* const br) {
@@ -43,12 +37,17 @@ int BrotliWarmupBitReader(BrotliBitReader* const br) {
if (!BROTLI_ALIGNED_READ) {
aligned_read_mask = 0;
}
- while (br->bit_pos_ == (sizeof(br->val_) << 3) ||
- (((size_t)br->next_in) & aligned_read_mask) != 0) {
- if (!br->avail_in) {
+ if (BrotliGetAvailableBits(br) == 0) {
+ if (!BrotliPullByte(br)) {
return 0;
}
- BrotliPullByte(br);
+ }
+
+ while ((((size_t)br->next_in) & aligned_read_mask) != 0) {
+ if (!BrotliPullByte(br)) {
+ /* If we consumed all the input, we don't care about the alignment. */
+ return 1;
+ }
}
return 1;
}
diff --git a/third_party/brotli/dec/bit_reader.h b/third_party/brotli/dec/bit_reader.h
index f25fd4a..f390348 100644
--- a/third_party/brotli/dec/bit_reader.h
+++ b/third_party/brotli/dec/bit_reader.h
@@ -20,45 +20,57 @@
#include <string.h>
#include "./port.h"
-#include "./streams.h"
#include "./types.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
-#define BROTLI_READ_SIZE 1024
-/* 128 bytes, plus 8 bytes slack for valid 128-byte BrotliCheckInputAmount with
- some bytes read in val_ of bit reader. */
-#define BROTLI_IMPLICIT_ZEROES 136
-#define BROTLI_IBUF_SIZE (BROTLI_READ_SIZE + BROTLI_IMPLICIT_ZEROES)
-#define BROTLI_IBUF_MASK (BROTLI_READ_SIZE - 1)
+#if (BROTLI_64_BITS)
+#define BROTLI_SHORT_FILL_BIT_WINDOW_READ 4
+typedef uint64_t reg_t;
+#else
+#define BROTLI_SHORT_FILL_BIT_WINDOW_READ 2
+typedef uint32_t reg_t;
+#endif
+
+static const uint32_t kBitMask[33] = { 0x0000,
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+ 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+ 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+ 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+ 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
+ 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
+ 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
+ 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+};
-/* Masking with this expression turns to a single "Unsigned Bit Field Extract"
- UBFX instruction on ARM. */
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
+ if (IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
+ /* Masking with this expression turns to a single
+ "Unsigned Bit Field Extract" UBFX instruction on ARM. */
return ~((0xffffffffU) << n);
+ } else {
+ return kBitMask[n];
+ }
}
typedef struct {
-#if (BROTLI_64_BITS)
- uint64_t val_; /* pre-fetched bits */
-#else
- uint32_t val_; /* pre-fetched bits */
-#endif
+ reg_t val_; /* pre-fetched bits */
uint32_t bit_pos_; /* current bit-reading position in val_ */
- uint8_t* next_in; /* the byte we're reading from */
- uint32_t avail_in;
- int eos_; /* input stream is finished */
- BrotliInput input_; /* input callback */
-
- /* Input byte buffer, consist of a ringbuffer and a "slack" region where */
- /* bytes from the start of the ringbuffer are copied. */
- uint8_t buf_[BROTLI_IBUF_SIZE];
+ const uint8_t* next_in; /* the byte we're reading from */
+ size_t avail_in;
} BrotliBitReader;
+typedef struct {
+ reg_t val_;
+ uint32_t bit_pos_;
+ const uint8_t* next_in;
+ size_t avail_in;
+} BrotliBitReaderState;
+
/* Initializes the bitreader fields. */
-void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input);
+void BrotliInitBitReader(BrotliBitReader* const br);
/* Ensures that accumulator is not empty. May consume one byte of input.
Returns 0 if data is required but there is no input available.
@@ -66,66 +78,35 @@ void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input);
reading. */
int BrotliWarmupBitReader(BrotliBitReader* const br);
-/* Pulls data from the input to the the read buffer.
+static BROTLI_INLINE void BrotliBitReaderSaveState(
+ BrotliBitReader* const from, BrotliBitReaderState* to) {
+ to->val_ = from->val_;
+ to->bit_pos_ = from->bit_pos_;
+ to->next_in = from->next_in;
+ to->avail_in = from->avail_in;
+}
- Returns 0 if one of:
- - the input callback returned an error, or
- - there is no more input and the position is past the end of the stream.
- - finish is false and less than BROTLI_READ_SIZE are available - a next call
- when more data is available makes it continue including the partially read
- data
+static BROTLI_INLINE void BrotliBitReaderRestoreState(
+ BrotliBitReader* const to, BrotliBitReaderState* from) {
+ to->val_ = from->val_;
+ to->bit_pos_ = from->bit_pos_;
+ to->next_in = from->next_in;
+ to->avail_in = from->avail_in;
+}
- If finish is true and the end of the stream is reached,
- BROTLI_IMPLICIT_ZEROES additional zero bytes are copied to the ringbuffer.
-*/
-static BROTLI_INLINE int BrotliReadInput(
- BrotliBitReader* const br, int finish) {
- if (PREDICT_FALSE(br->eos_)) {
- return 0;
- } else {
- size_t i;
- int bytes_read;
- if (br->next_in != br->buf_) {
- for (i = 0; i < br->avail_in; i++) {
- br->buf_[i] = br->next_in[i];
- }
- br->next_in = br->buf_;
- }
- bytes_read = BrotliRead(br->input_, br->next_in + br->avail_in,
- (size_t)(BROTLI_READ_SIZE - br->avail_in));
- if (bytes_read < 0) {
- return 0;
- }
- br->avail_in += (uint32_t)bytes_read;
- if (br->avail_in < BROTLI_READ_SIZE) {
- if (!finish) {
- return 0;
- }
- br->eos_ = 1;
- /* Store BROTLI_IMPLICIT_ZEROES bytes of zero after the stream end. */
- memset(br->next_in + br->avail_in, 0, BROTLI_IMPLICIT_ZEROES);
- br->avail_in += BROTLI_IMPLICIT_ZEROES;
- }
- return 1;
- }
+static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
+ const BrotliBitReader* br) {
+ return (BROTLI_64_BITS ? 64 : 32) - br->bit_pos_;
}
/* Returns amount of unread bytes the bit reader still has buffered from the
BrotliInput, including whole bytes in br->val_. */
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
- size_t result = br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3);
- if (!br->eos_) {
- return result;
- }
- if (result <= BROTLI_IMPLICIT_ZEROES) {
- return 0;
- }
- return result - BROTLI_IMPLICIT_ZEROES;
+ return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
}
/* Checks if there is at least num bytes left in the input ringbuffer (excluding
- the bits remaining in br->val_). The maximum value for num is
- BROTLI_IMPLICIT_ZEROES bytes. */
+ the bits remaining in br->val_). */
static BROTLI_INLINE int BrotliCheckInputAmount(
BrotliBitReader* const br, size_t num) {
return br->avail_in >= num;
@@ -160,6 +141,7 @@ static BROTLI_INLINE uint32_t BrotliLoad32LE(const uint8_t* in) {
}
}
+#if (BROTLI_64_BITS)
static BROTLI_INLINE uint64_t BrotliLoad64LE(const uint8_t* in) {
if (BROTLI_LITTLE_ENDIAN) {
return *((const uint64_t*)in);
@@ -186,6 +168,7 @@ static BROTLI_INLINE uint64_t BrotliLoad64LE(const uint8_t* in) {
return value;
}
}
+#endif
/* Guarantees that there are at least n_bits + 1 bits in accumulator.
Precondition: accumulator contains at least 1 bit.
@@ -215,8 +198,8 @@ static BROTLI_INLINE void BrotliFillBitWindow(
br->val_ >>= 32;
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
br->val_ |= ((uint64_t)BrotliLoad32LE(br->next_in)) << 32;
- br->avail_in -= 4;
- br->next_in += 4;
+ br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
+ br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
}
}
#else
@@ -233,15 +216,24 @@ static BROTLI_INLINE void BrotliFillBitWindow(
br->val_ >>= 16;
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
br->val_ |= ((uint32_t)BrotliLoad16LE(br->next_in)) << 16;
- br->avail_in -= 2;
- br->next_in += 2;
+ br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
+ br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
}
}
#endif
}
+/* Mosltly like BrotliFillBitWindow, but guarantees only 16 bits and reads no
+ more than BROTLI_SHORT_FILL_BIT_WINDOW_READ bytes of input. */
+static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) {
+ BrotliFillBitWindow(br, 17);
+}
+
/* Pulls one byte of input to accumulator. */
-static BROTLI_INLINE void BrotliPullByte(BrotliBitReader* const br) {
+static BROTLI_INLINE int BrotliPullByte(BrotliBitReader* const br) {
+ if (br->avail_in == 0) {
+ return 0;
+ }
br->val_ >>= 8;
#if (BROTLI_64_BITS)
br->val_ |= ((uint64_t)*br->next_in) << 56;
@@ -251,39 +243,68 @@ static BROTLI_INLINE void BrotliPullByte(BrotliBitReader* const br) {
br->bit_pos_ -= 8;
--br->avail_in;
++br->next_in;
+ return 1;
}
-/* Like BrotliGetBits, but does not mask the result, it is only guaranteed
-that it has minimum n_bits. */
-static BROTLI_INLINE uint32_t BrotliGetBitsUnmasked(
- BrotliBitReader* const br, uint32_t n_bits) {
- BrotliFillBitWindow(br, n_bits);
- return (uint32_t)(br->val_ >> br->bit_pos_);
+/* Returns currently available bits.
+ The number of valid bits could be calclulated by BrotliGetAvailableBits. */
+static BROTLI_INLINE reg_t BrotliGetBitsUnmasked(BrotliBitReader* const br) {
+ return br->val_ >> br->bit_pos_;
+}
+
+/* Like BrotliGetBits, but does not mask the result.
+ The result contains at least 16 valid bits. */
+static BROTLI_INLINE uint32_t BrotliGet16BitsUnmasked(
+ BrotliBitReader* const br) {
+ BrotliFillBitWindow(br, 16);
+ return (uint32_t)BrotliGetBitsUnmasked(br);
}
/* Returns the specified number of bits from br without advancing bit pos. */
static BROTLI_INLINE uint32_t BrotliGetBits(
BrotliBitReader* const br, uint32_t n_bits) {
BrotliFillBitWindow(br, n_bits);
- return (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits);
+ return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
+}
+
+/* Tries to peek the specified amount of bits. Returns 0, if there is not
+ enough input. */
+static BROTLI_INLINE int BrotliSafeGetBits(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+ while (BrotliGetAvailableBits(br) < n_bits) {
+ if (!BrotliPullByte(br)) {
+ return 0;
+ }
+ }
+ *val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
+ return 1;
}
/* Advances the bit pos by n_bits. */
static BROTLI_INLINE void BrotliDropBits(
- BrotliBitReader* const br, int n_bits) {
- br->bit_pos_ += (uint32_t)n_bits;
+ BrotliBitReader* const br, uint32_t n_bits) {
+ br->bit_pos_ += n_bits;
+}
+
+static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
+ uint32_t unused_bytes = BrotliGetAvailableBits(br) >> 3;
+ uint32_t unused_bits = unused_bytes << 3;
+ br->avail_in += unused_bytes;
+ br->next_in -= unused_bytes;
+ br->val_ <<= unused_bits;
+ br->bit_pos_ += unused_bits;
}
/* Reads the specified number of bits from br and advances the bit pos.
Precondition: accumulator MUST contain at least n_bits. */
static BROTLI_INLINE void BrotliTakeBits(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
- *val = (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits);
+ *val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
#ifdef BROTLI_DECODE_DEBUG
printf("[BrotliReadBits] %d %d %d val: %6x\n",
(int)br->avail_in, (int)br->bit_pos_, n_bits, (int)*val);
#endif
- br->bit_pos_ += n_bits;
+ BrotliDropBits(br, n_bits);
}
/* Reads the specified number of bits from br and advances the bit pos.
@@ -307,14 +328,13 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
}
/* Tries to read the specified amount of bits. Returns 0, if there is not
- enough input. */
+ enough input. n_bits MUST be positive. */
static BROTLI_INLINE int BrotliSafeReadBits(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
- while (br->bit_pos_ + (uint32_t)n_bits > (sizeof(br->val_) << 3)) {
- if (br->avail_in == 0) {
+ while (BrotliGetAvailableBits(br) < n_bits) {
+ if (!BrotliPullByte(br)) {
return 0;
}
- BrotliPullByte(br);
}
BrotliTakeBits(br, n_bits, val);
return 1;
@@ -323,7 +343,7 @@ static BROTLI_INLINE int BrotliSafeReadBits(
/* Advances the bit reader position to the next byte boundary and verifies
that any skipped bits are set to zero. */
static BROTLI_INLINE int BrotliJumpToByteBoundary(BrotliBitReader* br) {
- uint32_t pad_bits_count = (64 - (int)br->bit_pos_) & 0x7;
+ uint32_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7;
uint32_t pad_bits = 0;
if (pad_bits_count != 0) {
BrotliTakeBits(br, pad_bits_count, &pad_bits);
@@ -335,12 +355,13 @@ static BROTLI_INLINE int BrotliJumpToByteBoundary(BrotliBitReader* br) {
Precondition: bit reader is parked to a byte boundary.
Returns -1 if operation is not feasible. */
static BROTLI_INLINE int BrotliPeekByte(BrotliBitReader* br, size_t offset) {
- size_t bytes_left = sizeof(br->val_) - (br->bit_pos_ >> 3);
- if (br->bit_pos_ & 7) {
+ uint32_t available_bits = BrotliGetAvailableBits(br);
+ size_t bytes_left = available_bits >> 3;
+ if (available_bits & 7) {
return -1;
}
if (offset < bytes_left) {
- return (br->val_ >> (br->bit_pos_ + (unsigned)(offset << 3))) & 0xFF;
+ return (BrotliGetBitsUnmasked(br) >> (unsigned)(offset << 3)) & 0xFF;
}
offset -= bytes_left;
if (offset < br->avail_in) {
@@ -354,30 +375,17 @@ static BROTLI_INLINE int BrotliPeekByte(BrotliBitReader* br, size_t offset) {
warmed up again after this. */
static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
BrotliBitReader* br, size_t num) {
- while (br->bit_pos_ + 8 <= (BROTLI_64_BITS ? 64 : 32)
- && num > 0) {
- *dest = (uint8_t)(br->val_ >> br->bit_pos_);
- br->bit_pos_ += 8;
+ while (BrotliGetAvailableBits(br) >= 8 && num > 0) {
+ *dest = (uint8_t)BrotliGetBitsUnmasked(br);
+ BrotliDropBits(br, 8);
++dest;
--num;
}
memcpy(dest, br->next_in, num);
- br->avail_in -= (uint32_t)num;
+ br->avail_in -= num;
br->next_in += num;
}
-/* Checks that bit reader hasn't read after the end of input.
- Returns 0 if bit reader has used implicit zeroes after the end of input. */
-static BROTLI_INLINE int BrotliIsBitReaderOK(BrotliBitReader* br) {
- size_t remaining_bytes =
- br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3);
- return !br->eos_ || (remaining_bytes >= BROTLI_IMPLICIT_ZEROES);
-}
-
-#undef BROTLI_IMPLICIT_ZEROES
-#undef BROTLI_IBUF_SIZE
-#undef BROTLI_IBUF_MASK
-
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
diff --git a/third_party/brotli/dec/decode.c b/third_party/brotli/dec/decode.c
index eb91ce3..bd0d213 100644
--- a/third_party/brotli/dec/decode.c
+++ b/third_party/brotli/dec/decode.c
@@ -46,8 +46,8 @@ extern "C" {
#define BROTLI_LOG(x)
#endif
-static const uint8_t kDefaultCodeLength = 8;
-static const uint8_t kCodeLengthRepeatCode = 16;
+static const uint32_t kDefaultCodeLength = 8;
+static const uint32_t kCodeLengthRepeatCode = 16;
static const uint32_t kNumLiteralCodes = 256;
static const uint32_t kNumInsertAndCopyCodes = 704;
static const uint32_t kNumBlockLengthCodes = 26;
@@ -274,27 +274,94 @@ static BrotliResult BROTLI_NOINLINE DecodeMetaBlockLength(BrotliState* s,
}
}
-/* Decodes the next Huffman code from bit-stream. Reads 0 - 15 bits. */
-static BROTLI_INLINE uint32_t ReadSymbol(const HuffmanCode* table,
- BrotliBitReader* br) {
- /* Read the bits for two reads at once. */
- uint32_t val = BrotliGetBitsUnmasked(br, 15);
- table += val & HUFFMAN_TABLE_MASK;
+/* Decodes the Huffman code.
+ This method doesn't read data from the bit reader, BUT drops the amount of
+ bits that correspond to the decoded symbol.
+ bits MUST contain at least 15 (BROTLI_HUFFMAN_MAX_CODE_LENGTH) valid bits. */
+static BROTLI_INLINE uint32_t DecodeSymbol(uint32_t bits,
+ const HuffmanCode* table,
+ BrotliBitReader* br) {
+ table += bits & HUFFMAN_TABLE_MASK;
if (table->bits > HUFFMAN_TABLE_BITS) {
uint32_t nbits = table->bits - HUFFMAN_TABLE_BITS;
BrotliDropBits(br, HUFFMAN_TABLE_BITS);
table += table->value;
- table += (val >> HUFFMAN_TABLE_BITS) & BitMask(nbits);
+ table += (bits >> HUFFMAN_TABLE_BITS) & BitMask(nbits);
}
BrotliDropBits(br, table->bits);
return table->value;
}
+/* 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 uint32_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 int SafeDecodeSymbol(const HuffmanCode* table,
+ BrotliBitReader* br,
+ uint32_t* result) {
+ uint32_t val;
+ uint32_t available_bits = BrotliGetAvailableBits(br);
+ if (available_bits == 0) {
+ if (table->bits == 0) {
+ *result = table->value;
+ return 1;
+ }
+ return 0; /* No valid bits at all. */
+ }
+ val = (uint32_t)BrotliGetBitsUnmasked(br);
+ table += val & HUFFMAN_TABLE_MASK;
+ if (table->bits <= HUFFMAN_TABLE_BITS) {
+ if (table->bits <= available_bits) {
+ BrotliDropBits(br, table->bits);
+ *result = table->value;
+ return 1;
+ } else {
+ return 0; /* Not enough bits for the first level. */
+ }
+ }
+ if (available_bits <= HUFFMAN_TABLE_BITS) {
+ return 0; /* Not enough bits to move to the second level. */
+ }
+
+ /* Speculatively drop HUFFMAN_TABLE_BITS. */
+ val = (val & BitMask(table->bits)) >> HUFFMAN_TABLE_BITS;
+ available_bits -= HUFFMAN_TABLE_BITS;
+ table += table->value + val;
+ if (available_bits < table->bits) {
+ return 0; /* Not enough bits for the second level. */
+ }
+
+ BrotliDropBits(br, HUFFMAN_TABLE_BITS + table->bits);
+ *result = table->value;
+ return 1;
+}
+
+static BROTLI_INLINE int SafeReadSymbol(const HuffmanCode* table,
+ BrotliBitReader* br,
+ uint32_t* result) {
+ uint32_t val;
+ if (PREDICT_TRUE(BrotliSafeGetBits(br, 15, &val))) {
+ *result = DecodeSymbol(val, table, br);
+ return 1;
+ }
+ return SafeDecodeSymbol(table, br, result);
+}
+
+
/* Makes a look-up in first level Huffman table. Peeks 8 bits. */
-static BROTLI_INLINE void PreloadSymbol(const HuffmanCode* table,
+static BROTLI_INLINE void PreloadSymbol(int safe,
+ const HuffmanCode* table,
BrotliBitReader* br,
uint32_t* bits,
uint32_t* value) {
+ if (safe) {
+ return;
+ }
table += BrotliGetBits(br, HUFFMAN_TABLE_BITS);
*bits = table->bits;
*value = table->value;
@@ -308,7 +375,7 @@ static BROTLI_INLINE uint32_t ReadPreloadedSymbol(const HuffmanCode* table,
uint32_t* value) {
uint32_t result = *value;
if (PREDICT_FALSE(*bits > HUFFMAN_TABLE_BITS)) {
- uint32_t val = BrotliGetBitsUnmasked(br, 15);
+ uint32_t val = BrotliGet16BitsUnmasked(br);
const HuffmanCode* ext = table + (val & HUFFMAN_TABLE_MASK) + *value;
uint32_t mask = BitMask((*bits - HUFFMAN_TABLE_BITS));
BrotliDropBits(br, HUFFMAN_TABLE_BITS);
@@ -316,9 +383,9 @@ static BROTLI_INLINE uint32_t ReadPreloadedSymbol(const HuffmanCode* table,
BrotliDropBits(br, ext->bits);
result = ext->value;
} else {
- BrotliDropBits(br, (int)*bits);
+ BrotliDropBits(br, *bits);
}
- PreloadSymbol(table, br, bits, value);
+ PreloadSymbol(0, table, br, bits, value);
return result;
}
@@ -331,6 +398,250 @@ static BROTLI_INLINE uint32_t Log2Floor(uint32_t x) {
return result;
}
+/* Reads (s->symbol + 1) symbols.
+ Totally 1..4 symbols are read, 1..10 bits each.
+ The list of symbols MUST NOT contain duplicates.
+ */
+static BrotliResult ReadSimpleHuffmanSymbols(uint32_t alphabet_size,
+ BrotliState* s) {
+ /* max_bits == 1..10; symbol == 0..3; 1..40 bits will be read. */
+ BrotliBitReader* br = &s->br;
+ uint32_t max_bits = Log2Floor(alphabet_size - 1);
+ uint32_t i = s->sub_loop_counter;
+ uint32_t num_symbols = s->symbol;
+ while (i <= num_symbols) {
+ uint32_t v;
+ if (PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) {
+ s->sub_loop_counter = i;
+ s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ if (v >= alphabet_size) {
+ return BROTLI_FAILURE();
+ }
+ s->symbols_lists_array[i] = (uint16_t)v;
+ BROTLI_LOG_UINT(s->symbols_lists_array[i]);
+ ++i;
+ }
+
+ for (i = 0; i < num_symbols; ++i) {
+ uint32_t k = i + 1;
+ for (; k <= num_symbols; ++k) {
+ if (s->symbols_lists_array[i] == s->symbols_lists_array[k]) {
+ return BROTLI_FAILURE();
+ }
+ }
+ }
+
+ return BROTLI_RESULT_SUCCESS;
+}
+
+/* Process single decoded symbol code length:
+ A) reset the repeat variable
+ B) remember code length (if it is not 0)
+ C) extend corredponding index-chain
+ D) reduce the huffman space
+ E) update the histogram
+ */
+static BROTLI_INLINE void ProcessSingleCodeLength(uint32_t code_len,
+ uint32_t* symbol, uint32_t* repeat, uint32_t* space,
+ uint32_t* prev_code_len, uint16_t* symbol_lists,
+ uint16_t* code_length_histo, int* next_symbol) {
+ *repeat = 0;
+ if (code_len != 0) { /* code_len == 1..15 */
+ symbol_lists[next_symbol[code_len]] = (uint16_t)(*symbol);
+ next_symbol[code_len] = (int)(*symbol);
+ *prev_code_len = code_len;
+ *space -= 32768U >> code_len;
+ code_length_histo[code_len]++;
+ }
+ (*symbol)++;
+}
+
+/* Process repeated symbol code length.
+ A) Check if it is the extension of previous repeat sequence; if the decoded
+ value is not kCodeLengthRepeatCode, then it is a new symbol-skip
+ B) Update repeat variable
+ C) Check if operation is feasible (fits alphapet)
+ D) For each symbol do the same operations as in ProcessSingleCodeLength
+
+ PRECONDITION: code_len == kCodeLengthRepeatCode or kCodeLengthRepeatCode + 1
+ */
+static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len,
+ uint32_t repeat_delta, uint32_t alphabet_size, uint32_t* symbol,
+ uint32_t* repeat, uint32_t* space, uint32_t* prev_code_len,
+ uint32_t* repeat_code_len, uint16_t* symbol_lists,
+ uint16_t* code_length_histo, int* next_symbol) {
+ uint32_t old_repeat;
+ uint32_t new_len = 0;
+ if (code_len == kCodeLengthRepeatCode) {
+ new_len = *prev_code_len;
+ }
+ if (*repeat_code_len != new_len) {
+ *repeat = 0;
+ *repeat_code_len = new_len;
+ }
+ old_repeat = *repeat;
+ if (*repeat > 0) {
+ *repeat -= 2;
+ *repeat <<= code_len - 14U;
+ }
+ *repeat += repeat_delta + 3U;
+ repeat_delta = *repeat - old_repeat;
+ if (*symbol + repeat_delta > alphabet_size) {
+ (void)BROTLI_FAILURE();
+ *symbol = alphabet_size;
+ *space = 0xFFFFF;
+ return;
+ }
+ if (*repeat_code_len != 0) {
+ unsigned last = *symbol + repeat_delta;
+ int next = next_symbol[*repeat_code_len];
+ do {
+ symbol_lists[next] = (uint16_t)*symbol;
+ next = (int)*symbol;
+ } while (++(*symbol) != last);
+ next_symbol[*repeat_code_len] = next;
+ *space -= repeat_delta << (15 - *repeat_code_len);
+ code_length_histo[*repeat_code_len] = (uint16_t)
+ (code_length_histo[*repeat_code_len] + repeat_delta);
+ } else {
+ *symbol += repeat_delta;
+ }
+}
+
+/* Reads and decodes symbol codelengths. */
+static BrotliResult ReadSymbolCodeLengths(
+ uint32_t alphabet_size, BrotliState* s) {
+ BrotliBitReader* br = &s->br;
+ uint32_t symbol = s->symbol;
+ uint32_t repeat = s->repeat;
+ uint32_t space = s->space;
+ uint32_t prev_code_len = s->prev_code_len;
+ uint32_t repeat_code_len = s->repeat_code_len;
+ uint16_t* symbol_lists = s->symbol_lists;
+ uint16_t* code_length_histo = s->code_length_histo;
+ int* next_symbol = s->next_symbol;
+ if (!BrotliWarmupBitReader(br)) {
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ while (symbol < alphabet_size && space > 0) {
+ const HuffmanCode* p = s->table;
+ uint32_t code_len;
+ if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) {
+ s->symbol = symbol;
+ s->repeat = repeat;
+ s->prev_code_len = prev_code_len;
+ s->repeat_code_len = repeat_code_len;
+ s->space = space;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ BrotliFillBitWindow16(br);
+ p += BrotliGetBitsUnmasked(br) &
+ BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
+ BrotliDropBits(br, p->bits); /* Use 1..5 bits */
+ code_len = p->value; /* code_len == 0..17 */
+ if (code_len < kCodeLengthRepeatCode) {
+ ProcessSingleCodeLength(code_len, &symbol, &repeat, &space,
+ &prev_code_len, symbol_lists, code_length_histo, next_symbol);
+ } else { /* code_len == 16..17, extra_bits == 2..3 */
+ uint32_t repeat_delta =
+ (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(code_len - 14U);
+ BrotliDropBits(br, code_len - 14U);
+ ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
+ &symbol, &repeat, &space, &prev_code_len, &repeat_code_len,
+ symbol_lists, code_length_histo, next_symbol);
+ }
+ }
+ s->space = space;
+ return BROTLI_RESULT_SUCCESS;
+}
+
+static BrotliResult SafeReadSymbolCodeLengths(
+ uint32_t alphabet_size, BrotliState* s) {
+ BrotliBitReader* br = &s->br;
+ while (s->symbol < alphabet_size && s->space > 0) {
+ const HuffmanCode* p = s->table;
+ uint32_t code_len;
+ uint32_t bits = 0;
+ uint32_t available_bits = BrotliGetAvailableBits(br);
+ if (available_bits != 0) {
+ bits = (uint32_t)BrotliGetBitsUnmasked(br);
+ }
+ p += bits & BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
+ if (p->bits > available_bits) goto pullMoreInput;
+ code_len = p->value; /* code_len == 0..17 */
+ if (code_len < kCodeLengthRepeatCode) {
+ BrotliDropBits(br, p->bits);
+ ProcessSingleCodeLength(code_len, &s->symbol, &s->repeat, &s->space,
+ &s->prev_code_len, s->symbol_lists, s->code_length_histo,
+ s->next_symbol);
+ } else { /* code_len == 16..17, extra_bits == 2..3 */
+ uint32_t extra_bits = code_len - 14U;
+ uint32_t repeat_delta = (bits >> p->bits) & BitMask(extra_bits);
+ if (available_bits < p->bits + extra_bits) goto pullMoreInput;
+ BrotliDropBits(br, p->bits + extra_bits);
+ ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
+ &s->symbol, &s->repeat, &s->space, &s->prev_code_len,
+ &s->repeat_code_len, s->symbol_lists, s->code_length_histo,
+ s->next_symbol);
+ }
+ continue;
+
+pullMoreInput:
+ if (!BrotliPullByte(br)) {
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ }
+ return BROTLI_RESULT_SUCCESS;
+}
+
+/* Reads and decodes 15..18 codes using static prefix code.
+ Each code is 2..4 bits long. In total 30..72 bits are used. */
+static BrotliResult ReadCodeLengthCodeLengths(BrotliState* s) {
+ BrotliBitReader* br = &s->br;
+ uint32_t num_codes = s->repeat;
+ unsigned space = s->space;
+ uint32_t i = s->sub_loop_counter;
+ for (; i < CODE_LENGTH_CODES; ++i) {
+ const uint8_t code_len_idx = kCodeLengthCodeOrder[i];
+ uint32_t ix;
+ uint32_t v;
+ if (PREDICT_FALSE(!BrotliSafeGetBits(br, 4, &ix))) {
+ uint32_t available_bits = BrotliGetAvailableBits(br);
+ if (available_bits != 0) {
+ ix = BrotliGetBitsUnmasked(br) & 0xF;
+ } else {
+ ix = 0;
+ }
+ if (kCodeLengthPrefixLength[ix] > available_bits) {
+ s->sub_loop_counter = i;
+ s->repeat = num_codes;
+ s->space = space;
+ s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ }
+ v = kCodeLengthPrefixValue[ix];
+ BrotliDropBits(br, kCodeLengthPrefixLength[ix]);
+ s->code_length_code_lengths[code_len_idx] = (uint8_t)v;
+ BROTLI_LOG_ARRAY_INDEX(s->code_length_code_lengths, code_len_idx);
+ if (v != 0) {
+ space = space - (32U >> v);
+ ++num_codes;
+ ++s->code_length_histo[v];
+ if (space - 1U >= 32U) {
+ /* space is 0 or wrapped around */
+ break;
+ }
+ }
+ }
+ if (!(num_codes == 1 || space == 0)) {
+ return BROTLI_FAILURE();
+ }
+ return BROTLI_RESULT_SUCCESS;
+}
+
/* Decodes the Huffman tables.
There are 2 scenarios:
A) Huffman code contains only few symbols (1..4). Those symbols are read
@@ -348,84 +659,71 @@ static BrotliResult ReadHuffmanCode(uint32_t alphabet_size,
uint32_t* opt_table_size,
BrotliState* s) {
BrotliBitReader* br = &s->br;
- uint32_t i;
/* Unnecessary masking, but might be good for safety. */
alphabet_size &= 0x3ff;
/* State machine */
switch (s->substate_huffman) {
case BROTLI_STATE_HUFFMAN_NONE:
- if (!BrotliCheckInputAmount(br, 32)) {
+ if (!BrotliSafeReadBits(br, 2, &s->sub_loop_counter)) {
return BROTLI_RESULT_NEEDS_MORE_INPUT;
}
- i = BrotliReadBits(br, 2);
+ BROTLI_LOG_UINT(s->sub_loop_counter);
/* The value is used as follows:
1 for simple code;
0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
- BROTLI_LOG_UINT(i);
- if (i == 1) {
- /* Read symbols, codes & code lengths directly. */
- uint32_t max_bits = Log2Floor(alphabet_size - 1);
- uint32_t num_symbols = BrotliReadBits(br, 2);
- for (i = 0; i < 4; ++i) {
- s->symbols_lists_array[i] = 0;
- }
- i = 0;
- /* max_bits == 0..10; symbol == 0..3; 0..40 bits will be read. */
- do {
- uint32_t v = BrotliReadBits(br, max_bits);
- if (v >= alphabet_size) {
- return BROTLI_FAILURE();
- }
- s->symbols_lists_array[i] = (uint16_t)v;
- BROTLI_LOG_UINT(s->symbols_lists_array[i]);
- } while (++i <= num_symbols);
- for (i = 0; i < num_symbols; ++i) {
- uint32_t k = i + 1;
- for (; k <= num_symbols; ++k) {
- if (s->symbols_lists_array[i] == s->symbols_lists_array[k]) {
- return BROTLI_FAILURE();
- }
- }
- }
- if (num_symbols == 3) {
- num_symbols += BrotliReadBits(br, 1);
- }
- BROTLI_LOG_UINT(num_symbols);
- i = BrotliBuildSimpleHuffmanTable(
- table, HUFFMAN_TABLE_BITS, s->symbols_lists_array, num_symbols);
- if (opt_table_size) {
- *opt_table_size = i;
- }
- s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
- return BROTLI_RESULT_SUCCESS;
- } else { /* Decode Huffman-coded code lengths. */
- int8_t num_codes = 0;
- unsigned space = 32;
+ if (s->sub_loop_counter != 1) {
+ s->space = 32;
+ s->repeat = 0; /* num_codes */
memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo[0]) *
(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1));
memset(&s->code_length_code_lengths[0], 0,
- sizeof(s->code_length_code_lengths));
- /* 15..18 codes will be read, 2..4 bits each; 30..72 bits totally. */
- for (; i < CODE_LENGTH_CODES; ++i) {
- const uint8_t code_len_idx = kCodeLengthCodeOrder[i];
- uint8_t ix = (uint8_t)BrotliGetBits(br, 4);
- uint8_t v = kCodeLengthPrefixValue[ix];
- BrotliDropBits(br, kCodeLengthPrefixLength[ix]);
- s->code_length_code_lengths[code_len_idx] = v;
- BROTLI_LOG_ARRAY_INDEX(s->code_length_code_lengths, code_len_idx);
- if (v != 0) {
- space = space - (32U >> v);
- ++num_codes;
- ++s->code_length_histo[v];
- if (space - 1U >= 32U) {
- /* space is 0 or wrapped around */
- break;
- }
- }
- }
- if (!(num_codes == 1 || space == 0)) {
- return BROTLI_FAILURE();
+ sizeof(s->code_length_code_lengths));
+ s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
+ goto Complex;
+ }
+ /* No break, transit to the next state. */
+
+ case BROTLI_STATE_HUFFMAN_SIMPLE_SIZE:
+ /* Read symbols, codes & code lengths directly. */
+ if (!BrotliSafeReadBits(br, 2, &s->symbol)) { /* num_symbols */
+ s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ s->sub_loop_counter = 0;
+ /* No break, transit to the next state. */
+ case BROTLI_STATE_HUFFMAN_SIMPLE_READ: {
+ BrotliResult result = ReadSimpleHuffmanSymbols(alphabet_size, s);
+ if (result != BROTLI_RESULT_SUCCESS) {
+ return result;
+ }
+ /* No break, transit to the next state. */
+ }
+ case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: {
+ uint32_t table_size;
+ if (s->symbol == 3) {
+ uint32_t bits;
+ if (!BrotliSafeReadBits(br, 1, &bits)) {
+ s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
}
+ s->symbol += bits;
+ }
+ BROTLI_LOG_UINT(s->symbol);
+ table_size = BrotliBuildSimpleHuffmanTable(
+ table, HUFFMAN_TABLE_BITS, s->symbols_lists_array, s->symbol);
+ if (opt_table_size) {
+ *opt_table_size = table_size;
+ }
+ s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
+ return BROTLI_RESULT_SUCCESS;
+ }
+
+Complex: /* Decode Huffman-coded code lengths. */
+ case BROTLI_STATE_HUFFMAN_COMPLEX: {
+ uint32_t i;
+ BrotliResult result = ReadCodeLengthCodeLengths(s);
+ if (result != BROTLI_RESULT_SUCCESS) {
+ return result;
}
BrotliBuildCodeLengthsHuffmanTable(s->table,
s->code_length_code_lengths,
@@ -443,89 +741,25 @@ static BrotliResult ReadHuffmanCode(uint32_t alphabet_size,
s->space = 32768;
s->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
/* No break, transit to the next state. */
+ }
case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: {
- uint32_t symbol = s->symbol;
- uint32_t repeat = s->repeat;
- uint32_t space = s->space;
- uint8_t prev_code_len = s->prev_code_len;
- uint8_t repeat_code_len = s->repeat_code_len;
- uint16_t* symbol_lists = s->symbol_lists;
- uint16_t* code_length_histo = s->code_length_histo;
- int* next_symbol = s->next_symbol;
- while (symbol < alphabet_size && space > 0) {
- const HuffmanCode* p = s->table;
- uint8_t code_len;
- if (!BrotliCheckInputAmount(br, 8)) {
- s->symbol = symbol;
- s->repeat = repeat;
- s->prev_code_len = prev_code_len;
- s->repeat_code_len = repeat_code_len;
- s->space = space;
- return BROTLI_RESULT_NEEDS_MORE_INPUT;
- }
- p += BrotliGetBits(br, BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
- BrotliDropBits(br, p->bits); /* Use 1..5 bits */
- code_len = (uint8_t)p->value; /* code_len == 0..17 */
- if (code_len < kCodeLengthRepeatCode) {
- repeat = 0;
- if (code_len != 0) { /* code_len == 1..15 */
- symbol_lists[next_symbol[code_len]] = (uint16_t)symbol;
- next_symbol[code_len] = (int)symbol;
- prev_code_len = code_len;
- space -= 32768U >> code_len;
- code_length_histo[code_len]++;
- }
- symbol++;
- } else { /* code_len == 16..17, extra_bits == 2..3 */
- uint32_t repeat_delta = BrotliReadBits(br, code_len - 14U);
- uint32_t old_repeat;
- uint8_t new_len = 0;
- if (code_len == kCodeLengthRepeatCode) {
- new_len = prev_code_len;
- }
- if (repeat_code_len != new_len) {
- repeat = 0;
- repeat_code_len = new_len;
- }
- old_repeat = repeat;
- if (repeat > 0) {
- repeat -= 2;
- repeat <<= code_len - 14;
- }
- repeat += repeat_delta + 3;
- repeat_delta = repeat - old_repeat; /* repeat_delta >= 3 */
- /* So, for extra 2..3 bits we produce more than 2 symbols.
- Consequently, at most 5 bits per symbol are used. */
- if (symbol + repeat_delta > alphabet_size) {
- return BROTLI_FAILURE();
- }
- if (repeat_code_len != 0) {
- unsigned last = symbol + repeat_delta;
- int next = next_symbol[repeat_code_len];
- do {
- symbol_lists[next] = (uint16_t)symbol;
- next = (int)symbol;
- } while (++symbol != last);
- next_symbol[repeat_code_len] = next;
- space -= repeat_delta << (15 - repeat_code_len);
- code_length_histo[repeat_code_len] = (uint16_t)
- (code_length_histo[repeat_code_len] + repeat_delta);
- } else {
- symbol += repeat_delta;
- }
- }
+ uint32_t table_size;
+ BrotliResult result = ReadSymbolCodeLengths(alphabet_size, s);
+ if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+ result = SafeReadSymbolCodeLengths(alphabet_size, s);
}
- if (space != 0) {
- BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", space));
+ if (result != BROTLI_RESULT_SUCCESS) {
+ return result;
+ }
+
+ if (s->space != 0) {
+ BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", s->space));
return BROTLI_FAILURE();
}
- {
- uint32_t table_size = BrotliBuildHuffmanTable(
- table, HUFFMAN_TABLE_BITS, symbol_lists,
- s->code_length_histo);
- if (opt_table_size) {
- *opt_table_size = table_size;
- }
+ table_size = BrotliBuildHuffmanTable(table, HUFFMAN_TABLE_BITS,
+ s->symbol_lists, s->code_length_histo);
+ if (opt_table_size) {
+ *opt_table_size = table_size;
}
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
return BROTLI_RESULT_SUCCESS;
@@ -537,13 +771,41 @@ static BrotliResult ReadHuffmanCode(uint32_t alphabet_size,
}
/* Decodes a block length by reading 3..39 bits. */
-static BROTLI_INLINE int ReadBlockLength(const HuffmanCode* table,
- BrotliBitReader* br) {
+static BROTLI_INLINE uint32_t ReadBlockLength(const HuffmanCode* table,
+ BrotliBitReader* br) {
uint32_t code;
uint32_t nbits;
code = ReadSymbol(table, br);
nbits = kBlockLengthPrefixCode[code].nbits; /* nbits == 2..24 */
- return kBlockLengthPrefixCode[code].offset + (int)BrotliReadBits(br, nbits);
+ return kBlockLengthPrefixCode[code].offset + BrotliReadBits(br, nbits);
+}
+
+/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then
+ reading can't be continued with ReadBlockLength. */
+static BROTLI_INLINE int SafeReadBlockLength(BrotliState* s,
+ uint32_t* result,
+ const HuffmanCode* table,
+ BrotliBitReader* br) {
+ uint32_t index;
+ if (s->substate_read_block_length == BROTLI_STATE_READ_BLOCK_LENGTH_NONE) {
+ if (!SafeReadSymbol(table, br, &index)) {
+ return 0;
+ }
+ } else {
+ index = s->block_length_index;
+ }
+ {
+ uint32_t bits;
+ uint32_t nbits = kBlockLengthPrefixCode[index].nbits; /* nbits == 2..24 */
+ if (!BrotliSafeReadBits(br, nbits, &bits)) {
+ s->block_length_index = index;
+ s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX;
+ return 0;
+ }
+ *result = kBlockLengthPrefixCode[index].offset + bits;
+ s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
+ return 1;
+ }
}
/* Transform:
@@ -597,12 +859,6 @@ static BROTLI_NOINLINE void InverseMoveToFrontTransform(uint8_t* v,
state->mtf_upper_bound = upper_bound;
}
-/* Expose function for testing. Will be removed by linker as unused. */
-void InverseMoveToFrontTransformForTesting(
- uint8_t* v, uint32_t l, BrotliState* s) {
- InverseMoveToFrontTransform(v, l, s);
-}
-
/* Decodes a series of Huffman table using ReadHuffmanCode function. */
static BrotliResult HuffmanTreeGroupDecode(HuffmanTreeGroup* group,
@@ -640,7 +896,6 @@ static BrotliResult DecodeContextMap(uint32_t context_map_size,
BrotliState* s) {
BrotliBitReader* br = &s->br;
BrotliResult result = BROTLI_RESULT_SUCCESS;
- int use_rle_for_zeros;
switch((int)s->substate_context_map) {
case BROTLI_STATE_CONTEXT_MAP_NONE:
@@ -662,41 +917,65 @@ static BrotliResult DecodeContextMap(uint32_t context_map_size,
}
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
/* No break, continue to next state. */
- case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX:
- if (!BrotliWarmupBitReader(br) || !BrotliCheckInputAmount(br, 8)) {
+ case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: {
+ uint32_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_RESULT_NEEDS_MORE_INPUT;
}
- use_rle_for_zeros = (int)BrotliReadBits(br, 1);
- if (use_rle_for_zeros) {
- s->max_run_length_prefix = BrotliReadBits(br, 4) + 1;
+ if ((bits & 1) != 0) { /* Use RLE for zeroes. */
+ s->max_run_length_prefix = (bits >> 1) + 1;
+ BrotliDropBits(br, 5);
} else {
s->max_run_length_prefix = 0;
+ BrotliDropBits(br, 1);
}
BROTLI_LOG_UINT(s->max_run_length_prefix);
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
/* No break, continue to next state. */
+ }
case BROTLI_STATE_CONTEXT_MAP_HUFFMAN:
result = ReadHuffmanCode(*num_htrees + s->max_run_length_prefix,
s->context_map_table, NULL, s);
if (result != BROTLI_RESULT_SUCCESS) return result;
+ s->code = 0xFFFF;
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
/* No break, continue to next state. */
case BROTLI_STATE_CONTEXT_MAP_DECODE: {
uint32_t context_index = s->context_index;
uint32_t max_run_length_prefix = s->max_run_length_prefix;
uint8_t* context_map = *context_map_arg;
- uint32_t code;
+ uint32_t code = s->code;
+ if (code != 0xFFFF) {
+ goto rleCode;
+ }
while (context_index < context_map_size) {
- if (!BrotliCheckInputAmount(br, 32)) {
+ if (!SafeReadSymbol(s->context_map_table, br, &code)) {
+ s->code = 0xFFFF;
s->context_index = context_index;
return BROTLI_RESULT_NEEDS_MORE_INPUT;
}
- code = ReadSymbol(s->context_map_table, br);
BROTLI_LOG_UINT(code);
+
if (code == 0) {
context_map[context_index++] = 0;
- } else if (code <= max_run_length_prefix) {
- uint32_t reps = (1U << code) + BrotliReadBits(br, code);
+ continue;
+ }
+ if (code > max_run_length_prefix) {
+ context_map[context_index++] =
+ (uint8_t)(code - max_run_length_prefix);
+ continue;
+ }
+rleCode:
+ {
+ uint32_t reps;
+ if (!BrotliSafeReadBits(br, code, &reps)) {
+ s->code = code;
+ s->context_index = context_index;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ reps += 1U << code;
BROTLI_LOG_UINT(reps);
if (context_index + reps > context_map_size) {
return BROTLI_FAILURE();
@@ -704,13 +983,18 @@ static BrotliResult DecodeContextMap(uint32_t context_map_size,
do {
context_map[context_index++] = 0;
} while (--reps);
- } else {
- context_map[context_index++] =
- (uint8_t)(code - max_run_length_prefix);
}
}
- if (BrotliReadBits(br, 1)) {
- InverseMoveToFrontTransform(context_map, context_map_size, s);
+ /* No break, continue to next state. */
+ }
+ case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: {
+ uint32_t bits;
+ if (!BrotliSafeReadBits(br, 1, &bits)) {
+ s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ if (bits != 0) {
+ InverseMoveToFrontTransform(*context_map_arg, context_map_size, s);
}
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
return BROTLI_RESULT_SUCCESS;
@@ -721,15 +1005,32 @@ static BrotliResult DecodeContextMap(uint32_t context_map_size,
}
/* Decodes a command or literal and updates block type ringbuffer.
- Reads 0..15 bits. */
-static void DecodeBlockType(const uint32_t max_block_type,
- const HuffmanCode* trees,
- int tree_type,
- uint32_t* ringbuffers,
- BrotliBitReader* br) {
- uint32_t* ringbuffer = ringbuffers + tree_type * 2;
- uint32_t block_type = ReadSymbol(
- &trees[tree_type * BROTLI_HUFFMAN_MAX_TABLE_SIZE], br);
+ Reads 3..54 bits. */
+static int BROTLI_INLINE DecodeBlockTypeAndLength(int safe,
+ BrotliState* s, int tree_type) {
+ uint32_t max_block_type = s->num_block_types[tree_type];
+ int tree_offset = tree_type * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
+ const HuffmanCode* type_tree = &s->block_type_trees[tree_offset];
+ const HuffmanCode* len_tree = &s->block_len_trees[tree_offset];
+ BrotliBitReader* br = &s->br;
+ uint32_t* ringbuffer = &s->block_type_rb[tree_type * 2];
+ uint32_t block_type;
+
+ /* Read 0..15 + 3..39 bits */
+ if (!safe) {
+ block_type = ReadSymbol(type_tree, br);
+ s->block_length[tree_type] = ReadBlockLength(len_tree, br);
+ } else {
+ BrotliBitReaderState memento;
+ BrotliBitReaderSaveState(br, &memento);
+ if (!SafeReadSymbol(type_tree, br, &block_type)) return 0;
+ if (!SafeReadBlockLength(s, &s->block_length[tree_type], len_tree, br)) {
+ s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
+ BrotliBitReaderRestoreState(br, &memento);
+ return 0;
+ }
+ }
+
if (block_type == 1) {
block_type = ringbuffer[1] + 1;
} else if (block_type == 0) {
@@ -742,17 +1043,18 @@ static void DecodeBlockType(const uint32_t max_block_type,
}
ringbuffer[0] = ringbuffer[1];
ringbuffer[1] = block_type;
+ return 1;
}
/* Decodes the block type and updates the state for literal context.
- Reads 18..54 bits. */
-static void DecodeBlockTypeWithContext(BrotliState* s,
- BrotliBitReader* br) {
+ Reads 3..54 bits. */
+static int BROTLI_INLINE DecodeLiteralBlockSwitchInternal(int safe,
+ BrotliState* s) {
uint8_t context_mode;
uint32_t context_offset;
- DecodeBlockType(s->num_block_types[0], s->block_type_trees, 0,
- s->block_type_rb, br); /* Reads 0..15 bits. */
- s->block_length[0] = ReadBlockLength(s->block_len_trees, br); /* 3..39 bits */
+ if (!DecodeBlockTypeAndLength(safe, s, 0)) {
+ return 0;
+ }
context_offset = s->block_type_rb[1] << kLiteralContextBits;
s->context_map_slice = s->context_map + context_offset;
s->literal_htree_index = s->context_map_slice[0];
@@ -760,115 +1062,125 @@ static void DecodeBlockTypeWithContext(BrotliState* s,
context_mode = s->context_modes[s->block_type_rb[1]];
s->context_lookup1 = &kContextLookup[kContextLookupOffsets[context_mode]];
s->context_lookup2 = &kContextLookup[kContextLookupOffsets[context_mode + 1]];
+ return 1;
+}
+
+static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliState* s) {
+ DecodeLiteralBlockSwitchInternal(0, s);
+}
+
+static int BROTLI_NOINLINE SafeDecodeLiteralBlockSwitch(BrotliState* s) {
+ return DecodeLiteralBlockSwitchInternal(1, s);
+}
+
+/* Block switch for insert/copy length.
+ Reads 3..54 bits. */
+static int BROTLI_INLINE DecodeCommandBlockSwitchInternal(int safe,
+ BrotliState* s) {
+ if (!DecodeBlockTypeAndLength(safe, s, 1)) {
+ return 0;
+ }
+ s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]];
+ return 1;
+}
+
+static void BROTLI_NOINLINE DecodeCommandBlockSwitch(BrotliState* s) {
+ DecodeCommandBlockSwitchInternal(0, s);
+}
+static int BROTLI_NOINLINE SafeDecodeCommandBlockSwitch(BrotliState* s) {
+ return DecodeCommandBlockSwitchInternal(1, s);
+}
+
+/* Block switch for distance codes.
+ Reads 3..54 bits. */
+static int BROTLI_INLINE DecodeDistanceBlockSwitchInternal(int safe,
+ BrotliState* s) {
+ if (!DecodeBlockTypeAndLength(safe, s, 2)) {
+ return 0;
+ }
+ s->dist_context_map_slice =
+ s->dist_context_map + (s->block_type_rb[5] << kDistanceContextBits);
+ s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
+ return 1;
}
-BrotliResult WriteRingBuffer(BrotliOutput output,
- BrotliState* s) {
- int num_written;
+static void BROTLI_NOINLINE DecodeDistanceBlockSwitch(BrotliState* s) {
+ DecodeDistanceBlockSwitchInternal(0, s);
+}
+
+static int BROTLI_NOINLINE SafeDecodeDistanceBlockSwitch(BrotliState* s) {
+ return DecodeDistanceBlockSwitchInternal(1, s);
+}
+
+static BrotliResult WriteRingBuffer(size_t* available_out, uint8_t** next_out,
+ size_t* total_out, BrotliState* s) {
+ size_t pos = (s->pos > s->ringbuffer_size) ?
+ (size_t)s->ringbuffer_size : (size_t)(s->pos);
+ uint8_t* start = s->ringbuffer
+ + (s->partial_pos_out & (size_t)s->ringbuffer_mask);
+ size_t partial_pos_rb =
+ (s->rb_roundtrips * (size_t)s->ringbuffer_size) + pos;
+ size_t to_write = (partial_pos_rb - s->partial_pos_out);
+ size_t num_written = *available_out;
+ if (num_written > to_write) {
+ num_written = to_write;
+ }
if (s->meta_block_remaining_len < 0) {
return BROTLI_FAILURE();
}
- num_written = BrotliWrite(
- output, s->ringbuffer + s->partially_written,
- (size_t)(s->to_write - s->partially_written));
- BROTLI_LOG_UINT(s->partially_written);
- BROTLI_LOG_UINT(s->to_write);
+ memcpy(*next_out, start, num_written);
+ *next_out += num_written;
+ *available_out -= num_written;
+ BROTLI_LOG_UINT(to_write);
BROTLI_LOG_UINT(num_written);
- if (num_written < 0) {
- return BROTLI_FAILURE();
- }
- s->partially_written += num_written;
- if (s->partially_written < s->to_write) {
+ s->partial_pos_out += (size_t)num_written;
+ *total_out = s->partial_pos_out;
+ if (num_written < to_write) {
return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
}
return BROTLI_RESULT_SUCCESS;
}
-BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output,
- int pos,
- BrotliState* s) {
- BrotliResult result;
- int num_read;
- int nbytes;
+static BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(
+ size_t* available_out, uint8_t** next_out, size_t* total_out,
+ BrotliState* s) {
/* State machine */
for (;;) {
- switch ((int)s->substate_uncompressed) {
- case BROTLI_STATE_UNCOMPRESSED_NONE:
- nbytes = (int)BrotliGetRemainingBytes(&s->br);
- /* For short lengths copy byte-by-byte */
- if (s->meta_block_remaining_len < 8 ||
- s->meta_block_remaining_len < nbytes) {
- s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_SHORT;
- break;
+ switch (s->substate_uncompressed) {
+ case BROTLI_STATE_UNCOMPRESSED_NONE: {
+ int nbytes = (int)BrotliGetRemainingBytes(&s->br);
+ if (nbytes > s->meta_block_remaining_len) {
+ nbytes = s->meta_block_remaining_len;
+ }
+ if (s->pos + nbytes > s->ringbuffer_size) {
+ nbytes = s->ringbuffer_size - s->pos;
}
/* Copy remaining bytes from s->br.buf_ to ringbuffer. */
- BrotliCopyBytes(&s->ringbuffer[pos], &s->br, (size_t)nbytes);
- pos += nbytes;
+ BrotliCopyBytes(&s->ringbuffer[s->pos], &s->br, (size_t)nbytes);
+ s->pos += nbytes;
s->meta_block_remaining_len -= nbytes;
- if (pos >= s->ringbuffer_size) {
- s->to_write = s->ringbuffer_size;
- s->partially_written = 0;
- s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE;
- break;
- }
- s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_COPY;
- break;
- case BROTLI_STATE_UNCOMPRESSED_SHORT:
- if (!BrotliWarmupBitReader(&s->br)) {
- return BROTLI_RESULT_NEEDS_MORE_INPUT;
- }
- while (s->meta_block_remaining_len > 0) {
- if (!BrotliCheckInputAmount(&s->br, 8)) {
- return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ if (s->pos < s->ringbuffer_size) {
+ if (s->meta_block_remaining_len == 0) {
+ return BROTLI_RESULT_SUCCESS;
}
- s->ringbuffer[pos++] = (uint8_t)BrotliReadBits(&s->br, 8);
- s->meta_block_remaining_len--;
- }
- if (pos >= s->ringbuffer_size) {
- s->to_write = s->ringbuffer_size;
- s->partially_written = 0;
- s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE;
- } else {
- s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
- return BROTLI_RESULT_SUCCESS;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
}
- /* No break, if state is updated, continue to next state */
- case BROTLI_STATE_UNCOMPRESSED_WRITE:
- result = WriteRingBuffer(output, s);
+ s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE;
+ /*s->partial_pos_rb += (size_t)s->ringbuffer_size;*/
+ /* No break, continue to next state */
+ }
+ case BROTLI_STATE_UNCOMPRESSED_WRITE: {
+ BrotliResult result = WriteRingBuffer(
+ available_out, next_out, total_out, s);
if (result != BROTLI_RESULT_SUCCESS) {
return result;
}
- pos &= s->ringbuffer_mask;
+ s->pos = 0;
+ s->rb_roundtrips++;
s->max_distance = s->max_backward_distance;
- /* 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. */
- memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)pos);
- s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_COPY;
- /* No break, continue to next state */
- case BROTLI_STATE_UNCOMPRESSED_COPY:
- /* Copy straight from the input onto the ringbuffer. The ringbuffer will
- be flushed to the output at a later time. */
- nbytes = s->meta_block_remaining_len;
- if (pos + nbytes > s->ringbuffer_size) {
- nbytes = s->ringbuffer_size - pos;
- }
- num_read = BrotliRead(s->br.input_, &s->ringbuffer[pos],
- (size_t)nbytes);
- pos += num_read;
- s->meta_block_remaining_len -= num_read;
- if (num_read < nbytes) {
- if (num_read < 0) return BROTLI_FAILURE();
- return BROTLI_RESULT_NEEDS_MORE_INPUT;
- }
- if (pos == s->ringbuffer_size) {
- s->to_write = s->ringbuffer_size;
- s->partially_written = 0;
- s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE;
- break;
- }
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
- return BROTLI_RESULT_SUCCESS;
+ break;
+ }
}
}
return BROTLI_FAILURE();
@@ -877,36 +1189,27 @@ BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output,
int BrotliDecompressedSize(size_t encoded_size,
const uint8_t* encoded_buffer,
size_t* decoded_size) {
- BrotliMemInput memin;
- BrotliInput in = BrotliInitMemInput(encoded_buffer, encoded_size, &memin);
- BrotliBitReader br;
BrotliState s;
int next_block_header;
- size_t offset;
BrotliStateInit(&s);
- BrotliInitBitReader(&br, in);
- if (!BrotliReadInput(&br, 1) || !BrotliWarmupBitReader(&br)) {
+ s.br.next_in = encoded_buffer;
+ s.br.avail_in = encoded_size;
+ if (!BrotliWarmupBitReader(&s.br)) {
return 0;
}
- DecodeWindowBits(&br);
- if (DecodeMetaBlockLength(&s, &br) != BROTLI_RESULT_SUCCESS) {
+ DecodeWindowBits(&s.br);
+ if (DecodeMetaBlockLength(&s, &s.br) != BROTLI_RESULT_SUCCESS) {
return 0;
}
*decoded_size = (size_t)s.meta_block_remaining_len;
if (s.is_last_metablock) {
return 1;
}
- if (!s.is_uncompressed || !BrotliJumpToByteBoundary(&br)) {
+ if (!s.is_uncompressed || !BrotliJumpToByteBoundary(&s.br)) {
return 0;
}
- next_block_header = BrotliPeekByte(&br, (size_t)s.meta_block_remaining_len);
- if (next_block_header != -1) {
- return (next_block_header & 3) == 3;
- }
- /* Currently bit reader can't peek outside of its buffer... */
- offset = BROTLI_READ_SIZE - BrotliGetRemainingBytes(&br);
- offset += (size_t)s.meta_block_remaining_len;
- return (offset < encoded_size) && ((encoded_buffer[offset] & 3) == 3);
+ next_block_header = BrotliPeekByte(&s.br, (size_t)s.meta_block_remaining_len);
+ return (next_block_header != -1) && ((next_block_header & 3) == 3);
}
/* Allocates the smallest feasible ring buffer.
@@ -918,9 +1221,12 @@ int BrotliDecompressedSize(size_t encoded_size,
processed. When this method is called, metablock size and flags MUST be
decoded.
*/
-int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s,
+static int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s,
BrotliBitReader* br) {
- static const int kRingBufferWriteAheadSlack = BROTLI_READ_SIZE;
+ /* We need the slack region for the following reasons:
+ - doing up to two 16-byte copies for fast backward copying
+ - inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
+ static const int kRingBufferWriteAheadSlack = 42;
int is_last = s->is_last_metablock;
s->ringbuffer_size = 1 << s->window_bits;
@@ -950,8 +1256,7 @@ int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s,
s->ringbuffer_mask = s->ringbuffer_size - 1;
s->ringbuffer = (uint8_t*)malloc((size_t)(s->ringbuffer_size +
- kRingBufferWriteAheadSlack +
- kBrotliMaxDictionaryWordLength));
+ kRingBufferWriteAheadSlack + kBrotliMaxDictionaryWordLength));
if (s->ringbuffer == 0) {
return 0;
}
@@ -966,17 +1271,527 @@ int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s,
return 1;
}
+/* Reads 1..256 2-bit context modes. */
+static BrotliResult ReadContextModes(BrotliState* s) {
+ BrotliBitReader* br = &s->br;
+ int i = s->loop_counter;
+
+ while (i < (int)s->num_block_types[0]) {
+ uint32_t bits;
+ if (!BrotliSafeReadBits(br, 2, &bits)) {
+ s->loop_counter = i;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ s->context_modes[i] = (uint8_t)(bits << 1);
+ BROTLI_LOG_ARRAY_INDEX(s->context_modes, i);
+ i++;
+ }
+ return BROTLI_RESULT_SUCCESS;
+}
+
+static void BROTLI_INLINE TakeDistanceFromRingBuffer(BrotliState* s) {
+ if (s->distance_code == 0) {
+ --s->dist_rb_idx;
+ s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
+ } else {
+ int distance_code = s->distance_code << 1;
+ /* kDistanceShortCodeIndexOffset has 2-bit values from LSB: */
+ /* 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
+ const uint32_t kDistanceShortCodeIndexOffset = 0xaaafff1b;
+ /* kDistanceShortCodeValueOffset has 2-bit values from LSB: */
+ /*-0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */
+ const uint32_t kDistanceShortCodeValueOffset = 0xfa5fa500;
+ int v = (s->dist_rb_idx +
+ (int)(kDistanceShortCodeIndexOffset >> distance_code)) & 0x3;
+ s->distance_code = s->dist_rb[v];
+ v = (int)(kDistanceShortCodeValueOffset >> distance_code) & 0x3;
+ if ((distance_code & 0x3) != 0) {
+ s->distance_code += v;
+ } else {
+ s->distance_code -= v;
+ 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 = 0x0fffffff;
+ }
+ }
+ }
+}
+
+static BROTLI_INLINE int SafeReadBits(
+ BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+ if (n_bits != 0) {
+ return BrotliSafeReadBits(br, n_bits, val);
+ } else {
+ *val = 0;
+ return 1;
+ }
+}
+
+/* Precondition: s->distance_code < 0 */
+static int BROTLI_INLINE ReadDistanceInternal(int safe,
+ BrotliState* s, BrotliBitReader* br) {
+ int distval;
+ BrotliBitReaderState memento;
+ HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index];
+ if (!safe) {
+ s->distance_code = (int)ReadSymbol(distance_tree, br);
+ } else {
+ uint32_t code;
+ BrotliBitReaderSaveState(br, &memento);
+ if (!SafeReadSymbol(distance_tree, br, &code)) {
+ return 0;
+ }
+ s->distance_code = (int)code;
+ }
+ /* Convert the distance code to the actual distance by possibly */
+ /* looking up past distances from the s->ringbuffer. */
+ if ((s->distance_code & ~0xf) == 0) {
+ TakeDistanceFromRingBuffer(s);
+ --s->block_length[2];
+ return 1;
+ }
+ distval = s->distance_code - (int)s->num_direct_distance_codes;
+ if (distval >= 0) {
+ uint32_t nbits;
+ int postfix;
+ int offset;
+ if (!safe && (s->distance_postfix_bits == 0)) {
+ nbits = ((uint32_t)distval >> 1) + 1;
+ offset = ((2 + (distval & 1)) << nbits) - 4;
+ s->distance_code = (int)s->num_direct_distance_codes +
+ offset + (int)BrotliReadBits(br, nbits);
+ } else {
+ /* This branch also works well when s->distance_postfix_bits == 0 */
+ uint32_t bits;
+ postfix = distval & s->distance_postfix_mask;
+ distval >>= s->distance_postfix_bits;
+ nbits = ((uint32_t)distval >> 1) + 1;
+ if (safe) {
+ if (!SafeReadBits(br, nbits, &bits)) {
+ s->distance_code = -1; /* Restore precondition. */
+ BrotliBitReaderRestoreState(br, &memento);
+ return 0;
+ }
+ } else {
+ bits = BrotliReadBits(br, nbits);
+ }
+ offset = ((2 + (distval & 1)) << nbits) - 4;
+ s->distance_code = (int)s->num_direct_distance_codes +
+ ((offset + (int)bits) << s->distance_postfix_bits) + postfix;
+ }
+ }
+ s->distance_code = s->distance_code - NUM_DISTANCE_SHORT_CODES + 1;
+ --s->block_length[2];
+ return 1;
+}
+
+static void BROTLI_INLINE ReadDistance(BrotliState* s, BrotliBitReader* br) {
+ ReadDistanceInternal(0, s, br);
+}
+
+static int BROTLI_INLINE SafeReadDistance(BrotliState* s, BrotliBitReader* br) {
+ return ReadDistanceInternal(1, s, br);
+}
+
+static int BROTLI_INLINE ReadCommandInternal(int safe,
+ BrotliState* s, BrotliBitReader* br, int* insert_length) {
+ uint32_t cmd_code;
+ uint32_t insert_len_extra = 0;
+ uint32_t copy_length;
+ CmdLutElement v;
+ BrotliBitReaderState memento;
+ if (!safe) {
+ cmd_code = ReadSymbol(s->htree_command, br);
+ } else {
+ BrotliBitReaderSaveState(br, &memento);
+ if (!SafeReadSymbol(s->htree_command, br, &cmd_code)) {
+ return 0;
+ }
+ }
+ v = kCmdLut[cmd_code];
+ s->distance_code = v.distance_code;
+ s->distance_context = v.context;
+ s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
+ *insert_length = v.insert_len_offset;
+ if (!safe) {
+ if (PREDICT_FALSE(v.insert_len_extra_bits != 0)) {
+ insert_len_extra = BrotliReadBits(br, v.insert_len_extra_bits);
+ }
+ copy_length = BrotliReadBits(br, v.copy_len_extra_bits);
+ } else {
+ if (!SafeReadBits(br, v.insert_len_extra_bits, &insert_len_extra) ||
+ !SafeReadBits(br, v.copy_len_extra_bits, &copy_length)) {
+ BrotliBitReaderRestoreState(br, &memento);
+ return 0;
+ }
+ }
+ s->copy_length = (int)copy_length + v.copy_len_offset;
+ --s->block_length[1];
+ *insert_length += (int)insert_len_extra;
+ return 1;
+}
+
+static void BROTLI_INLINE ReadCommand(BrotliState* s, BrotliBitReader* br,
+ int* insert_length) {
+ ReadCommandInternal(0, s, br, insert_length);
+}
+
+static int BROTLI_INLINE SafeReadCommand(BrotliState* s, BrotliBitReader* br,
+ int* insert_length) {
+ return ReadCommandInternal(1, s, br, insert_length);
+}
+
+static BROTLI_INLINE int WarmupBitReader(int safe, BrotliBitReader* const br) {
+ if (safe) {
+ return 1;
+ }
+ return BrotliWarmupBitReader(br);
+}
+
+static BROTLI_INLINE int CheckInputAmount(int safe,
+ BrotliBitReader* const br, size_t num) {
+ if (safe) {
+ return 1;
+ }
+ return BrotliCheckInputAmount(br, num);
+}
+
+#define BROTLI_SAFE(METHOD) { \
+ if (safe) { \
+ if (! Safe ## METHOD ) { \
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT; \
+ goto saveStateAndReturn; \
+ } \
+ } else { \
+ METHOD ; \
+ } \
+}
+
+static BROTLI_INLINE BrotliResult ProcessCommandsInternal(int safe,
+ BrotliState* s) {
+ int pos = s->pos;
+ int i = s->loop_counter;
+ BrotliResult result = BROTLI_RESULT_SUCCESS;
+ BrotliBitReader* br = &s->br;
+
+ if (!CheckInputAmount(safe, br, 28) || !WarmupBitReader(safe, br)) {
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+
+ /* Jump into state machine. */
+ if (s->state == BROTLI_STATE_COMMAND_BEGIN) {
+ goto CommandBegin;
+ } else if (s->state == BROTLI_STATE_COMMAND_INNER) {
+ goto CommandInner;
+ } else if (s->state == BROTLI_STATE_COMMAND_POST_DECODE_LITERALS) {
+ goto CommandPostDecodeLiterals;
+ } else if (s->state == BROTLI_STATE_COMMAND_POST_WRAP_COPY) {
+ goto CommandPostWrapCopy;
+ } else {
+ return BROTLI_FAILURE();
+ }
+
+CommandBegin:
+ if (safe) {
+ s->state = BROTLI_STATE_COMMAND_BEGIN;
+ }
+ if (!CheckInputAmount(safe, br, 28)) { /* 156 bits + 7 bytes */
+ s->state = BROTLI_STATE_COMMAND_BEGIN;
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ if (PREDICT_FALSE(s->block_length[1] == 0)) {
+ BROTLI_SAFE(DecodeCommandBlockSwitch(s));
+ goto CommandBegin;
+ }
+ /* Read the insert/copy length in the command */
+ BROTLI_SAFE(ReadCommand(s, br, &i));
+ BROTLI_LOG_UINT(i);
+ BROTLI_LOG_UINT(s->copy_length);
+ BROTLI_LOG_UINT(s->distance_code);
+ if (i == 0) {
+ goto CommandPostDecodeLiterals;
+ }
+ s->meta_block_remaining_len -= i;
+
+CommandInner:
+ if (safe) {
+ s->state = BROTLI_STATE_COMMAND_INNER;
+ }
+ /* Read the literals in the command */
+ if (s->trivial_literal_context) {
+ uint32_t bits;
+ uint32_t value;
+ PreloadSymbol(safe, s->literal_htree, br, &bits, &value);
+ do {
+ if (!CheckInputAmount(safe, br, 28)) { /* 162 bits + 7 bytes */
+ s->state = BROTLI_STATE_COMMAND_INNER;
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ if (PREDICT_FALSE(s->block_length[0] == 0)) {
+ BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
+ PreloadSymbol(safe, s->literal_htree, br, &bits, &value);
+ }
+ if (!safe) {
+ s->ringbuffer[pos] = (uint8_t)ReadPreloadedSymbol(
+ s->literal_htree, br, &bits, &value);
+ } else {
+ uint32_t literal;
+ if (!SafeReadSymbol(s->literal_htree, br, &literal)) {
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ s->ringbuffer[pos] = (uint8_t)literal;
+ }
+ --s->block_length[0];
+ BROTLI_LOG_UINT(s->literal_htree_index);
+ BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos);
+ ++pos;
+ if (PREDICT_FALSE(pos == s->ringbuffer_size)) {
+ s->state = BROTLI_STATE_COMMAND_INNER_WRITE;
+ --i;
+ goto saveStateAndReturn;
+ }
+ } while (--i != 0);
+ } else {
+ uint8_t p1 = s->ringbuffer[(pos - 1) & s->ringbuffer_mask];
+ uint8_t p2 = s->ringbuffer[(pos - 2) & s->ringbuffer_mask];
+ do {
+ const HuffmanCode* hc;
+ uint8_t context;
+ if (!CheckInputAmount(safe, br, 28)) { /* 162 bits + 7 bytes */
+ s->state = BROTLI_STATE_COMMAND_INNER;
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ if (PREDICT_FALSE(s->block_length[0] == 0)) {
+ BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
+ }
+ context = s->context_lookup1[p1] | s->context_lookup2[p2];
+ BROTLI_LOG_UINT(context);
+ hc = s->literal_hgroup.htrees[s->context_map_slice[context]];
+ p2 = p1;
+ if (!safe) {
+ p1 = (uint8_t)ReadSymbol(hc, br);
+ } else {
+ uint32_t literal;
+ if (!SafeReadSymbol(hc, br, &literal)) {
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+ goto saveStateAndReturn;
+ }
+ p1 = (uint8_t)literal;
+ }
+ s->ringbuffer[pos] = p1;
+ --s->block_length[0];
+ BROTLI_LOG_UINT(s->context_map_slice[context]);
+ BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos & s->ringbuffer_mask);
+ ++pos;
+ if (PREDICT_FALSE(pos == s->ringbuffer_size)) {
+ s->state = BROTLI_STATE_COMMAND_INNER_WRITE;
+ --i;
+ goto saveStateAndReturn;
+ }
+ } while (--i != 0);
+ }
+ if (s->meta_block_remaining_len <= 0) {
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ goto saveStateAndReturn;
+ }
+
+CommandPostDecodeLiterals:
+ if (safe) {
+ s->state = BROTLI_STATE_COMMAND_POST_DECODE_LITERALS;
+ }
+ if (s->distance_code >= 0) {
+ --s->dist_rb_idx;
+ s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
+ goto postReadDistance; /* We already have the implicit distance */
+ }
+ /* Read distance code in the command, unless it was implicitly zero. */
+ if (PREDICT_FALSE(s->block_length[2] == 0)) {
+ BROTLI_SAFE(DecodeDistanceBlockSwitch(s));
+ }
+ BROTLI_SAFE(ReadDistance(s, br));
+postReadDistance:
+ BROTLI_LOG_UINT(s->distance_code);
+ if (s->max_distance != s->max_backward_distance) {
+ if (pos < s->max_backward_distance_minus_custom_dict_size) {
+ s->max_distance = pos + s->custom_dict_size;
+ } else {
+ s->max_distance = s->max_backward_distance;
+ }
+ }
+ i = s->copy_length;
+ /* Apply copy of LZ77 back-reference, or static dictionary reference if
+ the distance is larger than the max LZ77 distance */
+ if (s->distance_code > s->max_distance) {
+ if (i >= kBrotliMinDictionaryWordLength &&
+ i <= kBrotliMaxDictionaryWordLength) {
+ int offset = kBrotliDictionaryOffsetsByLength[i];
+ int word_id = s->distance_code - s->max_distance - 1;
+ uint32_t shift = kBrotliDictionarySizeBitsByLength[i];
+ int mask = (int)BitMask(shift);
+ int word_idx = word_id & mask;
+ int transform_idx = word_id >> shift;
+ offset += word_idx * i;
+ if (transform_idx < kNumTransforms) {
+ const uint8_t* word = &kBrotliDictionary[offset];
+ int len = i;
+ if (transform_idx == 0) {
+ memcpy(&s->ringbuffer[pos], word, (size_t)len);
+ } else {
+ len = TransformDictionaryWord(
+ &s->ringbuffer[pos], word, len, transform_idx);
+ }
+ pos += len;
+ s->meta_block_remaining_len -= len;
+ if (pos >= s->ringbuffer_size) {
+ /*s->partial_pos_rb += (size_t)s->ringbuffer_size;*/
+ s->state = BROTLI_STATE_COMMAND_POST_WRITE_1;
+ goto saveStateAndReturn;
+ }
+ } else {
+ BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+ "len: %d bytes left: %d\n",
+ pos, s->distance_code, i,
+ s->meta_block_remaining_len));
+ return BROTLI_FAILURE();
+ }
+ } else {
+ BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+ "len: %d bytes left: %d\n", pos, s->distance_code, i,
+ s->meta_block_remaining_len));
+ return BROTLI_FAILURE();
+ }
+ } else {
+ const uint8_t *ringbuffer_end_minus_copy_length =
+ s->ringbuffer_end - i;
+ uint8_t* copy_src = &s->ringbuffer[
+ (pos - s->distance_code) & s->ringbuffer_mask];
+ uint8_t* copy_dst = &s->ringbuffer[pos];
+ /* update the recent distances cache */
+ s->dist_rb[s->dist_rb_idx & 3] = s->distance_code;
+ ++s->dist_rb_idx;
+ s->meta_block_remaining_len -= i;
+ if (PREDICT_FALSE(s->meta_block_remaining_len < 0)) {
+ BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+ "len: %d bytes left: %d\n", pos, s->distance_code, i,
+ s->meta_block_remaining_len));
+ return BROTLI_FAILURE();
+ }
+ /* There is 128+ bytes of slack in the ringbuffer allocation.
+ Also, we have 16 short codes, that make these 16 bytes irrelevant
+ in the ringbuffer. Let's copy over them as a first guess.
+ */
+ memmove16(copy_dst, copy_src);
+ /* Now check if the copy extends over the ringbuffer end,
+ or if the copy overlaps with itself, if yes, do wrap-copy. */
+ if (copy_src < copy_dst) {
+ if (copy_dst >= ringbuffer_end_minus_copy_length) {
+ goto CommandPostWrapCopy;
+ }
+ if (copy_src + i > copy_dst) {
+ goto postSelfintersecting;
+ }
+ } else {
+ if (copy_src >= ringbuffer_end_minus_copy_length) {
+ goto CommandPostWrapCopy;
+ }
+ if (copy_dst + i > copy_src) {
+ goto postSelfintersecting;
+ }
+ }
+ pos += i;
+ if (i > 16) {
+ if (i > 32) {
+ memcpy(copy_dst + 16, copy_src + 16, (size_t)(i - 16));
+ } else {
+ /* This branch covers about 45% cases.
+ Fixed size short copy allows more compiler optimizations. */
+ memmove16(copy_dst + 16, copy_src + 16);
+ }
+ }
+ }
+ if (s->meta_block_remaining_len <= 0) {
+ /* Next metablock, if any */
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ goto saveStateAndReturn;
+ } else {
+ goto CommandBegin;
+ }
+postSelfintersecting:
+ while (--i >= 0) {
+ s->ringbuffer[pos] =
+ s->ringbuffer[(pos - s->distance_code) & s->ringbuffer_mask];
+ ++pos;
+ }
+ if (s->meta_block_remaining_len <= 0) {
+ /* Next metablock, if any */
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ goto saveStateAndReturn;
+ } else {
+ goto CommandBegin;
+ }
+
+CommandPostWrapCopy:
+ s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY;
+ while (--i >= 0) {
+ s->ringbuffer[pos] =
+ s->ringbuffer[(pos - s->distance_code) & s->ringbuffer_mask];
+ ++pos;
+ if (pos == s->ringbuffer_size) {
+ /*s->partial_pos_rb += (size_t)s->ringbuffer_size;*/
+ s->state = BROTLI_STATE_COMMAND_POST_WRITE_2;
+ goto saveStateAndReturn;
+ }
+ }
+ if (s->meta_block_remaining_len <= 0) {
+ /* Next metablock, if any */
+ s->state = BROTLI_STATE_METABLOCK_DONE;
+ goto saveStateAndReturn;
+ } else {
+ goto CommandBegin;
+ }
+
+saveStateAndReturn:
+ s->pos = pos;
+ s->loop_counter = i;
+ return result;
+}
+
+#undef BROTLI_SAFE
+
+static BROTLI_NOINLINE BrotliResult ProcessCommands(BrotliState* s) {
+ return ProcessCommandsInternal(0, s);
+}
+
+static BROTLI_NOINLINE BrotliResult SafeProcessCommands(BrotliState* s) {
+ return ProcessCommandsInternal(1, s);
+}
+
BrotliResult BrotliDecompressBuffer(size_t encoded_size,
const uint8_t* encoded_buffer,
size_t* decoded_size,
uint8_t* decoded_buffer) {
- BrotliMemInput memin;
- BrotliInput in = BrotliInitMemInput(encoded_buffer, encoded_size, &memin);
- BrotliMemOutput mout;
- BrotliOutput out = BrotliInitMemOutput(decoded_buffer, *decoded_size, &mout);
- BrotliResult success = BrotliDecompress(in, out);
- *decoded_size = mout.pos;
- return success;
+ BrotliState s;
+ BrotliResult result;
+ size_t total_out = 0;
+ size_t available_in = encoded_size;
+ const uint8_t* next_in = encoded_buffer;
+ size_t available_out = *decoded_size;
+ uint8_t* next_out = decoded_buffer;
+ BrotliStateInit(&s);
+ result = BrotliDecompressStream(&available_in, &next_in, &available_out,
+ &next_out, &total_out, &s);
+ *decoded_size = total_out;
+ BrotliStateCleanup(&s);
+ if (result != BROTLI_RESULT_SUCCESS) {
+ result = BROTLI_RESULT_ERROR;
+ }
+ return result;
}
BrotliResult BrotliDecompress(BrotliInput input, BrotliOutput output) {
@@ -999,61 +1814,184 @@ BrotliResult BrotliDecompressBufferStreaming(size_t* available_in,
uint8_t** next_out,
size_t* total_out,
BrotliState* s) {
- BrotliMemInput memin;
- BrotliInput in = BrotliInitMemInput(*next_in, *available_in, &memin);
- BrotliMemOutput memout;
- BrotliOutput out = BrotliInitMemOutput(*next_out, *available_out, &memout);
- BrotliResult result = BrotliDecompressStreaming(in, out, finish, s);
- /* The current implementation reads everything, so 0 bytes are available. */
- *next_in += memin.pos;
- *available_in -= memin.pos;
- /* Update the output position to where we write next. */
- *next_out += memout.pos;
- *available_out -= memout.pos;
- *total_out += memout.pos;
+ BrotliResult result = BrotliDecompressStream(available_in, next_in,
+ available_out, next_out, total_out, s);
+ if (finish && result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+ result = BROTLI_FAILURE();
+ }
return result;
}
BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
int finish, BrotliState* s) {
- uint8_t context;
- int pos = s->pos;
- int i = s->loop_counter;
- uint32_t j;
+ const size_t kBufferSize = 65536;
+ BrotliResult result;
+ uint8_t* input_buffer;
+ uint8_t* output_buffer;
+ size_t avail_in;
+ const uint8_t* next_in;
+ size_t total_out;
+
+ if (s->legacy_input_buffer == 0) {
+ s->legacy_input_buffer = (uint8_t*)malloc(kBufferSize);
+ }
+ if (s->legacy_output_buffer == 0) {
+ s->legacy_output_buffer = (uint8_t*)malloc(kBufferSize);
+ }
+ if (s->legacy_input_buffer == 0 || s->legacy_output_buffer == 0) {
+ return BROTLI_FAILURE();
+ }
+ input_buffer = s->legacy_input_buffer;
+ output_buffer = s->legacy_output_buffer;
+
+ /* Push remaining output. */
+ if (s->legacy_output_len > s->legacy_output_pos) {
+ size_t to_write = s->legacy_output_len - s->legacy_output_pos;
+ int num_written = BrotliWrite(
+ output, output_buffer + s->legacy_output_pos, to_write);
+ if (num_written < 0) {
+ return BROTLI_FAILURE();
+ }
+ s->legacy_output_pos += (size_t)num_written;
+ if ((size_t)num_written < to_write) {
+ return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
+ }
+ }
+ s->legacy_output_pos = 0;
+
+ avail_in = s->legacy_input_len - s->legacy_input_pos;
+ next_in = input_buffer + s->legacy_input_pos;
+
+ while (1) {
+ size_t to_write;
+ int num_written;
+ size_t avail_out = kBufferSize;
+ uint8_t* next_out = output_buffer;
+ result = BrotliDecompressStream(&avail_in, &next_in,
+ &avail_out, &next_out, &total_out, s);
+ s->legacy_input_pos = (size_t)(next_out - input_buffer);
+ to_write = (size_t)(next_out - output_buffer);
+ num_written = BrotliWrite(output, output_buffer, to_write);
+ if (num_written < 0) {
+ return BROTLI_FAILURE();
+ }
+ if ((size_t)num_written < to_write) {
+ s->legacy_output_len = to_write;
+ s->legacy_output_pos = (size_t)num_written;
+ return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
+ }
+ if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+ int num_read = BrotliRead(input, input_buffer, kBufferSize);
+ if (num_read < 0 || (num_read == 0 && finish)) {
+ return BROTLI_FAILURE();
+ }
+ if (num_read == 0) {
+ s->legacy_input_len = 0;
+ s->legacy_input_pos = 0;
+ return BROTLI_RESULT_NEEDS_MORE_INPUT;
+ }
+ avail_in = (size_t)num_read;
+ next_in = input_buffer;
+ s->legacy_input_len = avail_in;
+ s->legacy_input_pos = 0;
+ } else if (result != BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
+ /* Success or failure. */
+ return result;
+ }
+ }
+}
+
+/* Invariant: input stream is never overconsumed:
+ * invalid input implies that the whole stream is invalid -> any amount of
+ input could be read and discarded
+ * when result is "needs more input", then at leat one more byte is REQUIRED
+ to complete decoding; all input data MUST be consumed by decoder, so
+ client could swap the input buffer
+ * when result is "needs more output" decoder MUST ensure that it doesn't
+ hold more than 7 bits in bit reader; this saves client from swapping input
+ buffer ahead of time
+ * when result is "success" decoder MUST return all unused data back to input
+ buffer; this is possible because the invariant is hold on enter
+*/
+BrotliResult BrotliDecompressStream(size_t* available_in,
+ const uint8_t** next_in, size_t* available_out, uint8_t** next_out,
+ size_t* total_out, BrotliState* s) {
BrotliResult result = BROTLI_RESULT_SUCCESS;
BrotliBitReader* br = &s->br;
- int initial_remaining_len;
- int bytes_copied;
- uint8_t *copy_src;
- uint8_t *copy_dst;
- /* We need the slack region for the following reasons:
- - doing up to two 16-byte copies for fast backward copying
- - transforms
- - flushing the input s->ringbuffer when decoding uncompressed blocks */
- s->br.input_ = input;
+ if (s->buffer_length == 0) { /* Just connect bit reader to input stream. */
+ br->avail_in = *available_in;
+ br->next_in = *next_in;
+ } else {
+ /* At least one byte of input is required. More than one byte of input may
+ be required to complete the transaction -> reading more data must be
+ done in a loop -> do it in a main loop. */
+ result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+ br->next_in = &s->buffer.u8[0];
+ }
/* State machine */
for (;;) {
- if (result != BROTLI_RESULT_SUCCESS) {
+ if (result != BROTLI_RESULT_SUCCESS) { /* Error | needs more input/output */
if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
- if (BrotliReadInput(br, finish)) {
- result = BROTLI_RESULT_SUCCESS;
- continue;
- }
- if (finish) {
- BROTLI_LOG(("Unexpected end of input. State: %d\n", s->state));
- result = BROTLI_FAILURE();
+ if (s->ringbuffer != 0) { /* Proactively push output. */
+ WriteRingBuffer(available_out, next_out, total_out, s);
+ }
+ if (s->buffer_length != 0) { /* Used with internal buffer. */
+ if (br->avail_in == 0) { /* Successfully finished read transaction. */
+ /* Accamulator contains less than 8 bits, because internal buffer
+ is expanded byte-by-byte until it is enough to complete read. */
+ s->buffer_length = 0;
+ /* Switch to input stream and restart. */
+ result = BROTLI_RESULT_SUCCESS;
+ br->avail_in = *available_in;
+ br->next_in = *next_in;
+ continue;
+ } else if (*available_in != 0) {
+ /* Not enough data in buffer, but can take one more byte from
+ input stream. */
+ result = BROTLI_RESULT_SUCCESS;
+ s->buffer.u8[s->buffer_length] = **next_in;
+ s->buffer_length++;
+ br->avail_in = 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 = br->avail_in;
+ 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
+ stream it has less than 8 bits in accamulator, so it is safe to
+ return unused accamulator bits there. */
+ BrotliBitReaderUnload(br);
+ *available_in = br->avail_in;
+ *next_in = br->next_in;
}
- break; /* Fail, or partial data. */
+ break;
}
switch (s->state) {
case BROTLI_STATE_UNINITED:
- pos = 0;
- BrotliInitBitReader(br, input);
-
- s->state = BROTLI_STATE_BITREADER_WARMUP;
- /* No break, continue to next state */
- case BROTLI_STATE_BITREADER_WARMUP:
/* Prepare to the first read. */
if (!BrotliWarmupBitReader(br)) {
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
@@ -1085,13 +2023,12 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
/* No break, continue to next state */
case BROTLI_STATE_METABLOCK_BEGIN:
BrotliStateMetablockBegin(s);
- BROTLI_LOG_UINT(pos);
+ BROTLI_LOG_UINT(s->pos);
s->state = BROTLI_STATE_METABLOCK_HEADER;
/* No break, continue to next state */
case BROTLI_STATE_METABLOCK_HEADER:
result = DecodeMetaBlockLength(s, br); /* Reads 2 - 31 bits. */
if (result != BROTLI_RESULT_SUCCESS) {
- i = s->loop_counter; /* Has been updated in DecodeMetaBlockLength. */
break;
}
BROTLI_LOG_UINT(s->is_last_metablock);
@@ -1122,20 +2059,20 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
s->state = BROTLI_STATE_UNCOMPRESSED;
break;
}
- i = 0;
+ s->loop_counter = 0;
s->state = BROTLI_STATE_HUFFMAN_CODE_0;
break;
- case BROTLI_STATE_UNCOMPRESSED:
- 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);
- bytes_copied = initial_remaining_len - s->meta_block_remaining_len;
- pos = (pos + bytes_copied) & s->ringbuffer_mask;
+ case BROTLI_STATE_UNCOMPRESSED: {
+ int bytes_copied = s->meta_block_remaining_len;
+ result = CopyUncompressedBlockToOutput(
+ available_out, next_out, total_out, s);
+ bytes_copied -= s->meta_block_remaining_len;
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) {
uint32_t bits;
@@ -1150,63 +2087,61 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
}
break;
case BROTLI_STATE_HUFFMAN_CODE_0:
- if (i >= 3) {
- s->state = BROTLI_STATE_CONTEXT_MODES;
+ 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[i]);
+ result = DecodeVarLenUint8(s, br, &s->num_block_types[s->loop_counter]);
if (result != BROTLI_RESULT_SUCCESS) {
break;
}
- s->num_block_types[i]++;
- BROTLI_LOG_UINT(s->num_block_types[i]);
- s->state = BROTLI_STATE_HUFFMAN_CODE_1;
- /* No break, continue to next state */
- case BROTLI_STATE_HUFFMAN_CODE_1:
- if (!BrotliWarmupBitReader(br)) {
- result = BROTLI_RESULT_NEEDS_MORE_INPUT;
- break;
- }
- if (s->num_block_types[i] >= 2) {
- result = ReadHuffmanCode(s->num_block_types[i] + 2,
- &s->block_type_trees[i * BROTLI_HUFFMAN_MAX_TABLE_SIZE],
- NULL, s);
- if (result != BROTLI_RESULT_SUCCESS) break;
- s->state = BROTLI_STATE_HUFFMAN_CODE_2;
- } else {
- i++;
- s->state = BROTLI_STATE_HUFFMAN_CODE_0;
+ 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;
+ /* No break, continue to next state */
+ case BROTLI_STATE_HUFFMAN_CODE_1: {
+ int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
+ result = ReadHuffmanCode(s->num_block_types[s->loop_counter] + 2,
+ &s->block_type_trees[tree_offset], NULL, s);
+ if (result != BROTLI_RESULT_SUCCESS) break;
+ s->state = BROTLI_STATE_HUFFMAN_CODE_2;
/* No break, continue to next state */
- case BROTLI_STATE_HUFFMAN_CODE_2:
+ }
+ case BROTLI_STATE_HUFFMAN_CODE_2: {
+ int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
result = ReadHuffmanCode(kNumBlockLengthCodes,
- &s->block_len_trees[i * BROTLI_HUFFMAN_MAX_TABLE_SIZE],
- NULL, s);
+ &s->block_len_trees[tree_offset], NULL, s);
if (result != BROTLI_RESULT_SUCCESS) break;
s->state = BROTLI_STATE_HUFFMAN_CODE_3;
/* No break, continue to next state */
- case BROTLI_STATE_HUFFMAN_CODE_3:
- if (!BrotliCheckInputAmount(br, 8)) {
+ }
+ case BROTLI_STATE_HUFFMAN_CODE_3: {
+ int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
+ if (!SafeReadBlockLength(s, &s->block_length[s->loop_counter],
+ &s->block_len_trees[tree_offset], br)) {
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
break;
}
- s->block_length[i] = ReadBlockLength( /* Reads 3..39 bits. */
- &s->block_len_trees[i * BROTLI_HUFFMAN_MAX_TABLE_SIZE], br);
- BROTLI_LOG_UINT(s->block_length[i]);
- i++;
+ BROTLI_LOG_UINT(s->block_length[s->loop_counter]);
+ s->loop_counter++;
s->state = BROTLI_STATE_HUFFMAN_CODE_0;
break;
- case BROTLI_STATE_CONTEXT_MODES:
- /* We need up to 256 * 2 + 6 bits, this fits in 128 bytes. */
- if (!BrotliCheckInputAmount(br, 128)) {
+ }
+ case BROTLI_STATE_METABLOCK_HEADER_2: {
+ uint32_t bits;
+ if (!BrotliSafeReadBits(br, 6, &bits)) {
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
break;
}
- s->distance_postfix_bits = BrotliReadBits(br, 2);
+ s->distance_postfix_bits = bits & BitMask(2);
+ bits >>= 2;
s->num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES +
- (BrotliReadBits(br, 4) << s->distance_postfix_bits);
+ (bits << s->distance_postfix_bits);
BROTLI_LOG_UINT(s->num_direct_distance_codes);
BROTLI_LOG_UINT(s->distance_postfix_bits);
s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits);
@@ -1215,13 +2150,19 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
result = BROTLI_FAILURE();
break;
}
- for (j = 0; j < s->num_block_types[0]; ++j) {
- s->context_modes[j] = (uint8_t)(BrotliReadBits(br, 2) << 1);
- BROTLI_LOG_ARRAY_INDEX(s->context_modes, j);
+ s->loop_counter = 0;
+ s->state = BROTLI_STATE_CONTEXT_MODES;
+ /* No break, continue to next state */
+ }
+ case BROTLI_STATE_CONTEXT_MODES:
+ result = ReadContextModes(s);
+ if (result != BROTLI_RESULT_SUCCESS) {
+ break;
}
s->state = BROTLI_STATE_CONTEXT_MAP_1;
/* No break, continue to next state */
- case BROTLI_STATE_CONTEXT_MAP_1:
+ case BROTLI_STATE_CONTEXT_MAP_1: {
+ uint32_t j;
result = DecodeContextMap(s->num_block_types[0] << kLiteralContextBits,
&s->num_literal_htrees, &s->context_map, s);
if (result != BROTLI_RESULT_SUCCESS) {
@@ -1236,6 +2177,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
}
s->state = BROTLI_STATE_CONTEXT_MAP_2;
/* No break, continue to next state */
+ }
case BROTLI_STATE_CONTEXT_MAP_2:
{
uint32_t num_distance_codes =
@@ -1259,13 +2201,13 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
return BROTLI_FAILURE();
}
}
- i = 0;
+ s->loop_counter = 0;
s->state = BROTLI_STATE_TREE_GROUP;
/* No break, continue to next state */
case BROTLI_STATE_TREE_GROUP:
{
HuffmanTreeGroup* hgroup = NULL;
- switch (i) {
+ switch (s->loop_counter) {
case 0:
hgroup = &s->literal_hgroup;
break;
@@ -1279,8 +2221,8 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
result = HuffmanTreeGroupDecode(hgroup, s);
}
if (result != BROTLI_RESULT_SUCCESS) break;
- i++;
- if (i >= 3) {
+ s->loop_counter++;
+ if (s->loop_counter >= 3) {
uint8_t context_mode = s->context_modes[s->block_type_rb[1]];
s->context_map_slice = s->context_map;
s->dist_context_map_slice = s->dist_context_map;
@@ -1294,377 +2236,43 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
}
break;
case BROTLI_STATE_COMMAND_BEGIN:
- if (s->meta_block_remaining_len <= 0) {
- /* Next metablock, if any */
- s->state = BROTLI_STATE_METABLOCK_DONE;
- break;
- }
- /* Decoding of Brotli commands is the inner loop, jumping with goto makes it
- 3% faster */
- CommandBegin:
- if (!BrotliCheckInputAmount(br, 32)) {
- s->state = BROTLI_STATE_COMMAND_BEGIN;
- result = BROTLI_RESULT_NEEDS_MORE_INPUT;
- break;
- }
- /* Read the insert/copy length in the command */
- if (s->block_length[1] == 0) {
- /* Block switch for insert/copy length. Reads 0..15 bits. */
- DecodeBlockType(s->num_block_types[1],
- s->block_type_trees, 1,
- s->block_type_rb, br);
- s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]];
- s->block_length[1] = ReadBlockLength( /* Reads 3..39 bits. */
- &s->block_len_trees[BROTLI_HUFFMAN_MAX_TABLE_SIZE], br);
- }
- {
- uint32_t cmd_code = ReadSymbol(s->htree_command, br);
- int insert_len_extra = 0;
- CmdLutElement v;
- --s->block_length[1];
- v = kCmdLut[cmd_code];
- s->distance_code = v.distance_code;
- s->distance_context = v.context;
- s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
- i = v.insert_len_offset;
- if (PREDICT_FALSE(v.insert_len_extra_bits != 0)) {
- insert_len_extra = (int)BrotliReadBits(br, v.insert_len_extra_bits);
- }
- s->copy_length = (int)BrotliReadBits(br, v.copy_len_extra_bits) +
- v.copy_len_offset;
- i += insert_len_extra;
- }
- BROTLI_LOG_UINT(i);
- BROTLI_LOG_UINT(s->copy_length);
- BROTLI_LOG_UINT(s->distance_code);
- if (i == 0) {
- goto postDecodeLiterals;
- }
- s->meta_block_remaining_len -= i;
- /* No break, go to next state */
case BROTLI_STATE_COMMAND_INNER:
- /* Read the literals in the command */
- if (s->trivial_literal_context) {
- uint32_t bits;
- uint32_t value;
- PreloadSymbol(s->literal_htree, br, &bits, &value);
- do {
- if (!BrotliCheckInputAmount(br, 64)) {
- s->state = BROTLI_STATE_COMMAND_INNER;
- result = BROTLI_RESULT_NEEDS_MORE_INPUT;
- break;
- }
- if (PREDICT_FALSE(s->block_length[0] == 0)) {
- /* Block switch for literals */
- DecodeBlockTypeWithContext(s, br);
- PreloadSymbol(s->literal_htree, br, &bits, &value);
- }
- s->ringbuffer[pos] =
- (uint8_t)ReadPreloadedSymbol(s->literal_htree,
- br, &bits, &value);
- --s->block_length[0];
- BROTLI_LOG_UINT(s->literal_htree_index);
- BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos);
- ++pos;
- if (PREDICT_FALSE(pos == s->ringbuffer_size)) {
- s->to_write = s->ringbuffer_size;
- s->partially_written = 0;
- s->state = BROTLI_STATE_COMMAND_INNER_WRITE;
- --i;
- goto innerWrite;
- }
- } while (--i != 0);
- } else {
- uint8_t p1 = s->ringbuffer[(pos - 1) & s->ringbuffer_mask];
- uint8_t p2 = s->ringbuffer[(pos - 2) & s->ringbuffer_mask];
- do {
- const HuffmanCode* hc;
- if (!BrotliCheckInputAmount(br, 64)) {
- s->state = BROTLI_STATE_COMMAND_INNER;
- result = BROTLI_RESULT_NEEDS_MORE_INPUT;
- break;
- }
- if (PREDICT_FALSE(s->block_length[0] == 0)) {
- /* Block switch for literals */
- DecodeBlockTypeWithContext(s, br);
- }
- context = s->context_lookup1[p1] | s->context_lookup2[p2];
- BROTLI_LOG_UINT(context);
- hc = s->literal_hgroup.htrees[s->context_map_slice[context]];
- --s->block_length[0];
- p2 = p1;
- p1 = (uint8_t)ReadSymbol(hc, br);
- s->ringbuffer[pos] = p1;
- BROTLI_LOG_UINT(s->context_map_slice[context]);
- BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos & s->ringbuffer_mask);
- ++pos;
- if (PREDICT_FALSE(pos == s->ringbuffer_size)) {
- s->to_write = s->ringbuffer_size;
- s->partially_written = 0;
- s->state = BROTLI_STATE_COMMAND_INNER_WRITE;
- --i;
- goto innerWrite;
- }
- } while (--i != 0);
- }
- if (result != BROTLI_RESULT_SUCCESS) break;
- if (s->meta_block_remaining_len <= 0) {
- s->state = BROTLI_STATE_METABLOCK_DONE;
- break;
- }
-postDecodeLiterals:
- if (s->distance_code >= 0) {
- --s->dist_rb_idx;
- s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
- goto postReadDistance; /* We already have the implicit distance */
- }
- /* Read distance code in the command, unless it was implicitly zero. */
- BROTLI_DCHECK(s->distance_code < 0);
- if (s->block_length[2] == 0) {
- /* Block switch for distance codes */
- uint32_t dist_context_offset;
- DecodeBlockType(s->num_block_types[2],
- s->block_type_trees, 2,
- s->block_type_rb, br); /* Reads 0..15 bits. */
- s->block_length[2] = ReadBlockLength( /* Reads 3..39 bits. */
- &s->block_len_trees[2 * BROTLI_HUFFMAN_MAX_TABLE_SIZE], br);
- dist_context_offset = s->block_type_rb[5] << kDistanceContextBits;
- s->dist_context_map_slice =
- s->dist_context_map + dist_context_offset;
- s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
- }
- --s->block_length[2];
- s->distance_code = (int)ReadSymbol(
- s->distance_hgroup.htrees[s->dist_htree_index], br);
- /* Convert the distance code to the actual distance by possibly */
- /* looking up past distances from the s->ringbuffer. */
- if ((s->distance_code & ~0xf) == 0) {
- if (s->distance_code == 0) {
- --s->dist_rb_idx;
- s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
- } else {
- int distance_code = s->distance_code << 1;
- /* kDistanceShortCodeIndexOffset has 2-bit values from LSB: */
- /* 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
- const uint32_t kDistanceShortCodeIndexOffset = 0xaaafff1b;
- /* kDistanceShortCodeValueOffset has 2-bit values from LSB: */
- /* 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 1, 1, 2, 2, 3, 3 */
- const uint32_t kDistanceShortCodeValueOffset = 0xfa5fa500;
- int v = (s->dist_rb_idx +
- (int)(kDistanceShortCodeIndexOffset >> distance_code)) & 0x3;
- s->distance_code = s->dist_rb[v];
- v = (int)(kDistanceShortCodeValueOffset >> distance_code) & 0x3;
- if ((distance_code & 0x3) != 0) {
- s->distance_code += v;
- } else {
- s->distance_code -= v;
- 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 = 0x0fffffff;
- }
- }
- }
- } else {
- int distval = s->distance_code - (int)s->num_direct_distance_codes;
- if (distval >= 0) {
- uint32_t nbits;
- int postfix;
- int offset;
- if (s->distance_postfix_bits == 0) {
- nbits = ((uint32_t)distval >> 1) + 1;
- offset = ((2 + (distval & 1)) << nbits) - 4;
- s->distance_code = (int)s->num_direct_distance_codes +
- offset + (int)BrotliReadBits(br, nbits);
- } else {
- postfix = distval & s->distance_postfix_mask;
- distval >>= s->distance_postfix_bits;
- nbits = ((uint32_t)distval >> 1) + 1;
- offset = ((2 + (distval & 1)) << nbits) - 4;
- s->distance_code = (int)s->num_direct_distance_codes +
- ((offset + (int)BrotliReadBits(br, nbits)) <<
- s->distance_postfix_bits) + postfix;
- }
- }
- s->distance_code = s->distance_code - NUM_DISTANCE_SHORT_CODES + 1;
- }
-postReadDistance:
- BROTLI_LOG_UINT(s->distance_code);
- if (s->max_distance != s->max_backward_distance) {
- if (pos < s->max_backward_distance_minus_custom_dict_size) {
- s->max_distance = pos + s->custom_dict_size;
- } else {
- s->max_distance = s->max_backward_distance;
- }
- }
- i = s->copy_length;
- /* Apply copy of LZ77 back-reference, or static dictionary reference if
- the distance is larger than the max LZ77 distance */
- if (s->distance_code > s->max_distance) {
- if (i >= kBrotliMinDictionaryWordLength &&
- i <= kBrotliMaxDictionaryWordLength) {
- int offset = kBrotliDictionaryOffsetsByLength[i];
- int word_id = s->distance_code - s->max_distance - 1;
- uint32_t shift = kBrotliDictionarySizeBitsByLength[i];
- int mask = (int)BitMask(shift);
- int word_idx = word_id & mask;
- int transform_idx = word_id >> shift;
- offset += word_idx * i;
- if (transform_idx < kNumTransforms) {
- const uint8_t* word = &kBrotliDictionary[offset];
- int len = i;
- if (transform_idx == 0) {
- memcpy(&s->ringbuffer[pos], word, (size_t)len);
- } else {
- len = TransformDictionaryWord(
- &s->ringbuffer[pos], word, len, transform_idx);
- }
- pos += len;
- s->meta_block_remaining_len -= len;
- if (pos >= s->ringbuffer_size) {
- s->to_write = s->ringbuffer_size;
- s->partially_written = 0;
- s->state = BROTLI_STATE_COMMAND_POST_WRITE_1;
- break;
- }
- } else {
- BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
- "len: %d bytes left: %d\n",
- pos, s->distance_code, i,
- s->meta_block_remaining_len));
- result = BROTLI_FAILURE();
- break;
- }
- } else {
- BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
- "len: %d bytes left: %d\n", pos, s->distance_code, i,
- s->meta_block_remaining_len));
- result = BROTLI_FAILURE();
- break;
- }
- } else {
- const uint8_t *ringbuffer_end_minus_copy_length =
- s->ringbuffer_end - i;
- copy_src = &s->ringbuffer[(pos - s->distance_code) &
- s->ringbuffer_mask];
- copy_dst = &s->ringbuffer[pos];
- /* update the recent distances cache */
- s->dist_rb[s->dist_rb_idx & 3] = s->distance_code;
- ++s->dist_rb_idx;
- s->meta_block_remaining_len -= i;
- if (PREDICT_FALSE(s->meta_block_remaining_len < 0)) {
- BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
- "len: %d bytes left: %d\n", pos, s->distance_code, i,
- s->meta_block_remaining_len));
- result = BROTLI_FAILURE();
- break;
- }
- /* There is 128+ bytes of slack in the ringbuffer allocation.
- Also, we have 16 short codes, that make these 16 bytes irrelevant
- in the ringbuffer. Let's copy over them as a first guess.
- */
- memmove16(copy_dst, copy_src);
- /* Now check if the copy extends over the ringbuffer end,
- or if the copy overlaps with itself, if yes, do wrap-copy. */
- if (copy_src < copy_dst) {
- if (copy_dst >= ringbuffer_end_minus_copy_length) {
- goto postWrapCopy;
- }
- if (copy_src + i > copy_dst) {
- goto postSelfintersecting;
- }
- } else {
- if (copy_src >= ringbuffer_end_minus_copy_length) {
- goto postWrapCopy;
- }
- if (copy_dst + i > copy_src) {
- goto postSelfintersecting;
- }
- }
- pos += i;
- if (i > 16) {
- if (i > 32) {
- memcpy(copy_dst + 16, copy_src + 16, (size_t)(i - 16));
- } else {
- /* This branch covers about 45% cases.
- Fixed size short copy allows more compiler optimizations. */
- memmove16(copy_dst + 16, copy_src + 16);
- }
- }
- }
- if (s->meta_block_remaining_len <= 0) {
- /* Next metablock, if any */
- s->state = BROTLI_STATE_METABLOCK_DONE;
- break;
- } else {
- goto CommandBegin;
- }
- postSelfintersecting:
- while (--i >= 0) {
- s->ringbuffer[pos] =
- s->ringbuffer[(pos - s->distance_code) & s->ringbuffer_mask];
- ++pos;
- }
- if (s->meta_block_remaining_len <= 0) {
- /* Next metablock, if any */
- s->state = BROTLI_STATE_METABLOCK_DONE;
- break;
- } else {
- goto CommandBegin;
- }
- postWrapCopy:
- s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY;
- /* No break, go to next state */
+ case BROTLI_STATE_COMMAND_POST_DECODE_LITERALS:
case BROTLI_STATE_COMMAND_POST_WRAP_COPY:
- while (--i >= 0) {
- s->ringbuffer[pos] =
- s->ringbuffer[(pos - s->distance_code) & s->ringbuffer_mask];
- ++pos;
- if (pos == s->ringbuffer_size) {
- s->to_write = s->ringbuffer_size;
- s->partially_written = 0;
- s->state = BROTLI_STATE_COMMAND_POST_WRITE_2;
- break;
- }
- }
- if (s->state == BROTLI_STATE_COMMAND_POST_WRAP_COPY) {
- if (s->meta_block_remaining_len <= 0) {
- /* Next metablock, if any */
- s->state = BROTLI_STATE_METABLOCK_DONE;
- break;
- } else {
- goto CommandBegin;
- }
+ result = ProcessCommands(s);
+ if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+ result = SafeProcessCommands(s);
}
break;
case BROTLI_STATE_COMMAND_INNER_WRITE:
case BROTLI_STATE_COMMAND_POST_WRITE_1:
case BROTLI_STATE_COMMAND_POST_WRITE_2:
-innerWrite:
- result = WriteRingBuffer(output, s);
+ result = WriteRingBuffer(available_out, next_out, total_out, s);
if (result != BROTLI_RESULT_SUCCESS) {
break;
}
- pos -= s->ringbuffer_size;
+ s->pos -= s->ringbuffer_size;
+ s->rb_roundtrips++;
s->max_distance = s->max_backward_distance;
if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_1) {
- memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)pos);
+ memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)s->pos);
if (s->meta_block_remaining_len <= 0) {
/* Next metablock, if any */
s->state = BROTLI_STATE_METABLOCK_DONE;
- break;
} else {
- goto CommandBegin;
+ s->state = BROTLI_STATE_COMMAND_BEGIN;
}
+ break;
} else if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_2) {
s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY;
} else { /* BROTLI_STATE_COMMAND_INNER_WRITE */
- if (i == 0) {
+ if (s->loop_counter == 0) {
if (s->meta_block_remaining_len <= 0) {
s->state = BROTLI_STATE_METABLOCK_DONE;
- break;
+ } else {
+ s->state = BROTLI_STATE_COMMAND_POST_DECODE_LITERALS;
}
- goto postDecodeLiterals;
+ break;
}
s->state = BROTLI_STATE_COMMAND_INNER;
}
@@ -1675,30 +2283,26 @@ innerWrite:
s->state = BROTLI_STATE_METABLOCK_BEGIN;
break;
}
- s->to_write = pos;
- s->partially_written = 0;
+ if (!BrotliJumpToByteBoundary(br)) {
+ result = BROTLI_FAILURE();
+ }
+ if (s->buffer_length == 0) {
+ BrotliBitReaderUnload(br);
+ *available_in = br->avail_in;
+ *next_in = br->next_in;
+ }
s->state = BROTLI_STATE_DONE;
/* No break, continue to next state */
case BROTLI_STATE_DONE:
if (s->ringbuffer != 0) {
- result = WriteRingBuffer(output, s);
+ result = WriteRingBuffer(available_out, next_out, total_out, s);
if (result != BROTLI_RESULT_SUCCESS) {
break;
}
}
- if (!BrotliJumpToByteBoundary(br)) {
- result = BROTLI_FAILURE();
- }
- if (!BrotliIsBitReaderOK(br)) {
- /* The brotli input stream was too small, does not follow the spec.
- NOTE: larger input is allowed, smaller not. */
- result = BROTLI_FAILURE();
- }
return result;
}
}
- s->pos = pos;
- s->loop_counter = i;
return result;
}
diff --git a/third_party/brotli/dec/decode.h b/third_party/brotli/dec/decode.h
index cd3d124..78a156e 100644
--- a/third_party/brotli/dec/decode.h
+++ b/third_party/brotli/dec/decode.h
@@ -62,9 +62,6 @@ int BrotliDecompressedSize(size_t encoded_size,
/* Decompresses the data in encoded_buffer into decoded_buffer, and sets */
/* *decoded_size to the decompressed length. */
-/* Returns 0 if there was either a bit stream error or memory allocation */
-/* error, and 1 otherwise. */
-/* If decoded size is zero, returns 1 and keeps decoded_buffer unchanged. */
BrotliResult BrotliDecompressBuffer(size_t encoded_size,
const uint8_t* encoded_buffer,
size_t* decoded_size,
@@ -72,6 +69,7 @@ BrotliResult BrotliDecompressBuffer(size_t encoded_size,
/* Same as above, but uses the specified input and output callbacks instead */
/* of reading from and writing to pre-allocated memory buffers. */
+/* DEPRECATED */
BrotliResult BrotliDecompress(BrotliInput input, BrotliOutput output);
/* Same as above, but supports the caller to call the decoder repeatedly with
@@ -99,6 +97,7 @@ BrotliResult BrotliDecompress(BrotliInput input, BrotliOutput output);
it returning a smaller value than the amount of bytes to write always results
in an error.
*/
+/* DEPRECATED */
BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
int finish, BrotliState* s);
@@ -129,6 +128,7 @@ BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
*available_out yourself before a next call, e.g. to point to a new larger
buffer.
*/
+/* DEPRECATED */
BrotliResult BrotliDecompressBufferStreaming(size_t* available_in,
const uint8_t** next_in,
int finish,
@@ -137,6 +137,13 @@ BrotliResult BrotliDecompressBufferStreaming(size_t* available_in,
size_t* total_out,
BrotliState* s);
+BrotliResult BrotliDecompressStream(size_t* available_in,
+ const uint8_t** next_in,
+ size_t* available_out,
+ uint8_t** next_out,
+ size_t* total_out,
+ BrotliState* s);
+
/* Fills the new state with a dictionary for LZ77, warming up the ringbuffer,
e.g. for custom static dictionaries for data formats.
Not to be confused with the built-in transformable dictionary of Brotli.
@@ -151,10 +158,6 @@ void BrotliSetCustomDictionary(
size_t size, const uint8_t* dict, BrotliState* s);
-/* Escalate internal functions visibility; for testing purposes only. */
-void InverseMoveToFrontTransformForTesting(
- uint8_t* v, uint32_t l, BrotliState* s);
-
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
diff --git a/third_party/brotli/dec/huffman.c b/third_party/brotli/dec/huffman.c
index d4ccbd9..0628c36 100644
--- a/third_party/brotli/dec/huffman.c
+++ b/third_party/brotli/dec/huffman.c
@@ -377,6 +377,7 @@ void BrotliHuffmanTreeGroupInit(HuffmanTreeGroup* group, uint32_t alphabet_size,
void BrotliHuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
BROTLI_FREE(group->codes);
+ group->htrees = NULL;
}
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/third_party/brotli/dec/port.h b/third_party/brotli/dec/port.h
index bf33242..f8fc4a8 100644
--- a/third_party/brotli/dec/port.h
+++ b/third_party/brotli/dec/port.h
@@ -19,8 +19,10 @@
* BROTLI_BUILD_32_BIT disables 64-bit optimizations
* BROTLI_BUILD_64_BIT forces to use 64-bit optimizations
* BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations
- * BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
* BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations
+ * BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
+ * BROTLI_BUILD_MODERN_COMPILER forces to use modern compilers built-ins,
+ features and attributes
* BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
read and overlapping memcpy; this reduces decompression speed by 5%
* BROTLI_DEBUG dumps file name and line number when decoder detects stream
@@ -46,6 +48,59 @@
#define __has_feature(x) 0
#endif
+#if defined(__sparc)
+#define BROTLI_TARGET_SPARC
+#endif
+
+#if defined(__arm__) || defined(__thumb__) || \
+ defined(_M_ARM) || defined(_M_ARMT)
+#define BROTLI_TARGET_ARM
+#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) || \
+ (defined(M_ARM) && (M_ARM >= 7))
+#define BROTLI_TARGET_ARMV7
+#endif /* ARMv7 */
+#if defined(__aarch64__)
+#define BROTLI_TARGET_ARMV8
+#endif /* ARMv8 */
+#endif /* ARM */
+
+#if defined(__x86_64__) || defined(_M_X64)
+#define BROTLI_TARGET_X64
+#endif
+
+#if defined(__PPC64__)
+#define BROTLI_TARGET_POWERPC64
+#endif
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define BROTLI_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+#else
+#define BROTLI_GCC_VERSION 0
+#endif
+
+#if defined(__ICC)
+#define BROTLI_ICC_VERSION __ICC
+#else
+#define BROTLI_ICC_VERSION 0
+#endif
+
+#if defined(BROTLI_BUILD_MODERN_COMPILER)
+#define BROTLI_MODERN_COMPILER 1
+#elif (BROTLI_GCC_VERSION > 300) || (BROTLI_ICC_VERSION >= 1600)
+#define BROTLI_MODERN_COMPILER 1
+#else
+#define BROTLI_MODERN_COMPILER 0
+#endif
+
+/* SPARC and ARMv6 don't support unaligned read.
+ Choose portable build for them. */
+#if !defined(BROTLI_BUILD_PORTABLE)
+#if defined(BROTLI_TARGET_SPARC) || \
+ (defined(BROTLI_TARGET_ARM) && !defined(BROTLI_TARGET_ARMV7))
+#define BROTLI_BUILD_PORTABLE
+#endif /* SPARK or ARMv6 */
+#endif /* portable build */
+
#ifdef BROTLI_BUILD_PORTABLE
#define BROTLI_ALIGNED_READ 1
#define BROTLI_SAFE_MEMMOVE 1
@@ -73,8 +128,7 @@ OR:
}
*/
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || \
- (defined(__llvm__) && __has_builtin(__builtin_expect))
+#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_expect)
#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
#else
@@ -83,15 +137,13 @@ OR:
#endif
/* IS_CONSTANT macros returns true for compile-time constant expressions. */
-#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) || \
- (defined(__llvm__) && __has_builtin(__builtin_constant_p))
+#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_constant_p)
#define IS_CONSTANT(x) __builtin_constant_p(x)
#else
#define IS_CONSTANT(x) 0
#endif
-#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) || \
- (defined(__llvm__) && __has_attribute(always_inline))
+#if BROTLI_MODERN_COMPILER || __has_attribute(always_inline)
#define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
#else
#define ATTRIBUTE_ALWAYS_INLINE
@@ -118,8 +170,8 @@ OR:
#define BROTLI_64_BITS 1
#elif defined(BROTLI_BUILD_32_BIT)
#define BROTLI_64_BITS 0
-#elif defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || \
- defined(__PPC64__)
+#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8) || \
+ defined(BROTLI_TARGET_POWERPC64)
#define BROTLI_64_BITS 1
#else
#define BROTLI_64_BITS 0
@@ -150,8 +202,7 @@ OR:
#define BROTLI_LITTLE_ENDIAN 0
#endif
-#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || \
- (defined(__llvm__) && __has_attribute(noinline))
+#if BROTLI_MODERN_COMPILER || __has_attribute(noinline)
#define BROTLI_NOINLINE __attribute__ ((noinline))
#else
#define BROTLI_NOINLINE
@@ -169,8 +220,8 @@ OR:
if ((N & 4) != 0) {X; X; X; X;} \
}
-#if (__GNUC__ > 2) || defined(__llvm__)
-#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7))
+#if BROTLI_MODERN_COMPILER || defined(__llvm__)
+#if defined(BROTLI_TARGET_ARMV7)
static BROTLI_INLINE unsigned BrotliRBit(unsigned input) {
unsigned output;
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
@@ -180,6 +231,12 @@ static BROTLI_INLINE unsigned BrotliRBit(unsigned input) {
#endif /* armv7 */
#endif /* gcc || clang */
+#if defined(BROTLI_TARGET_ARM)
+#define BROTLI_HAS_UBFX 1
+#else
+#define BROTLI_HAS_UBFX 0
+#endif
+
#define BROTLI_FREE(X) { \
free(X); \
X = NULL; \
diff --git a/third_party/brotli/dec/prefix.h b/third_party/brotli/dec/prefix.h
index 0d77f6e..91e43e92 100644
--- a/third_party/brotli/dec/prefix.h
+++ b/third_party/brotli/dec/prefix.h
@@ -23,7 +23,7 @@
/* Represents the range of values belonging to a prefix code: */
/* [offset, offset + 2^nbits) */
struct PrefixCodeRange {
- int16_t offset;
+ uint16_t offset;
uint8_t nbits;
};
diff --git a/third_party/brotli/dec/state.c b/third_party/brotli/dec/state.c
index d32dfd3..f4f239a 100644
--- a/third_party/brotli/dec/state.c
+++ b/third_party/brotli/dec/state.c
@@ -24,6 +24,7 @@ extern "C" {
#endif
void BrotliStateInit(BrotliState* s) {
+ BrotliInitBitReader(&s->br);
s->state = BROTLI_STATE_UNINITED;
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
@@ -31,9 +32,13 @@ void BrotliStateInit(BrotliState* s) {
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
+ s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
+ s->buffer_length = 0;
s->loop_counter = 0;
s->pos = 0;
+ s->rb_roundtrips = 0;
+ s->partial_pos_out = 0;
s->block_type_trees = NULL;
s->block_len_trees = NULL;
@@ -45,6 +50,8 @@ void BrotliStateInit(BrotliState* s) {
s->context_map_slice = NULL;
s->dist_context_map_slice = NULL;
+ s->sub_loop_counter = 0;
+
s->literal_hgroup.codes = NULL;
s->literal_hgroup.htrees = NULL;
s->insert_copy_hgroup.codes = NULL;
@@ -71,13 +78,20 @@ void BrotliStateInit(BrotliState* s) {
s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
s->mtf_upper_bound = 255;
+
+ s->legacy_input_buffer = 0;
+ s->legacy_output_buffer = 0;
+ s->legacy_input_len = 0;
+ s->legacy_output_len = 0;
+ s->legacy_input_pos = 0;
+ s->legacy_output_pos = 0;
}
void BrotliStateMetablockBegin(BrotliState* s) {
s->meta_block_remaining_len = 0;
- s->block_length[0] = 1 << 28;
- s->block_length[1] = 1 << 28;
- s->block_length[2] = 1 << 28;
+ s->block_length[0] = 1U << 28;
+ s->block_length[1] = 1U << 28;
+ s->block_length[2] = 1U << 28;
s->num_block_types[0] = 1;
s->num_block_types[1] = 1;
s->num_block_types[2] = 1;
@@ -113,27 +127,27 @@ void BrotliStateCleanupAfterMetablock(BrotliState* s) {
BrotliHuffmanTreeGroupRelease(&s->literal_hgroup);
BrotliHuffmanTreeGroupRelease(&s->insert_copy_hgroup);
BrotliHuffmanTreeGroupRelease(&s->distance_hgroup);
- s->literal_hgroup.codes = NULL;
- s->literal_hgroup.htrees = NULL;
- s->insert_copy_hgroup.codes = NULL;
- s->insert_copy_hgroup.htrees = NULL;
- s->distance_hgroup.codes = NULL;
- s->distance_hgroup.htrees = NULL;
}
void BrotliStateCleanup(BrotliState* s) {
- BROTLI_FREE(s->context_modes);
- BROTLI_FREE(s->context_map);
- BROTLI_FREE(s->dist_context_map);
-
- BrotliHuffmanTreeGroupRelease(&s->literal_hgroup);
- BrotliHuffmanTreeGroupRelease(&s->insert_copy_hgroup);
- BrotliHuffmanTreeGroupRelease(&s->distance_hgroup);
+ BrotliStateCleanupAfterMetablock(s);
BROTLI_FREE(s->ringbuffer);
BROTLI_FREE(s->block_type_trees);
+ BROTLI_FREE(s->legacy_input_buffer);
+ BROTLI_FREE(s->legacy_output_buffer);
}
+int BrotliStateIsStreamStart(const BrotliState* s) {
+ return (s->state == BROTLI_STATE_UNINITED &&
+ BrotliGetAvailableBits(&s->br) == 0);
+}
+
+int BrotliStateIsStreamEnd(const BrotliState* s) {
+ return s->state == BROTLI_STATE_DONE;
+}
+
+
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
diff --git a/third_party/brotli/dec/state.h b/third_party/brotli/dec/state.h
index 241ee6c..0d9329b 100644
--- a/third_party/brotli/dec/state.h
+++ b/third_party/brotli/dec/state.h
@@ -21,7 +21,6 @@
#include <stdio.h>
#include "./bit_reader.h"
#include "./huffman.h"
-#include "./streams.h"
#include "./types.h"
#if defined(__cplusplus) || defined(c_plusplus)
@@ -30,19 +29,20 @@ extern "C" {
typedef enum {
BROTLI_STATE_UNINITED,
- BROTLI_STATE_BITREADER_WARMUP,
BROTLI_STATE_METABLOCK_BEGIN,
BROTLI_STATE_METABLOCK_HEADER,
+ BROTLI_STATE_METABLOCK_HEADER_2,
BROTLI_STATE_CONTEXT_MODES,
BROTLI_STATE_COMMAND_BEGIN,
BROTLI_STATE_COMMAND_INNER,
+ BROTLI_STATE_COMMAND_POST_DECODE_LITERALS,
+ BROTLI_STATE_COMMAND_POST_WRAP_COPY,
BROTLI_STATE_UNCOMPRESSED,
BROTLI_STATE_METADATA,
BROTLI_STATE_COMMAND_INNER_WRITE,
BROTLI_STATE_METABLOCK_DONE,
BROTLI_STATE_COMMAND_POST_WRITE_1,
BROTLI_STATE_COMMAND_POST_WRITE_2,
- BROTLI_STATE_COMMAND_POST_WRAP_COPY,
BROTLI_STATE_HUFFMAN_CODE_0,
BROTLI_STATE_HUFFMAN_CODE_1,
BROTLI_STATE_HUFFMAN_CODE_2,
@@ -66,8 +66,6 @@ typedef enum {
typedef enum {
BROTLI_STATE_UNCOMPRESSED_NONE,
- BROTLI_STATE_UNCOMPRESSED_SHORT,
- BROTLI_STATE_UNCOMPRESSED_COPY,
BROTLI_STATE_UNCOMPRESSED_WRITE
} BrotliRunningUncompressedState;
@@ -80,11 +78,16 @@ typedef enum {
BROTLI_STATE_CONTEXT_MAP_NONE,
BROTLI_STATE_CONTEXT_MAP_READ_PREFIX,
BROTLI_STATE_CONTEXT_MAP_HUFFMAN,
- BROTLI_STATE_CONTEXT_MAP_DECODE
+ BROTLI_STATE_CONTEXT_MAP_DECODE,
+ BROTLI_STATE_CONTEXT_MAP_TRANSFORM
} BrotliRunningContextMapState;
typedef enum {
BROTLI_STATE_HUFFMAN_NONE,
+ BROTLI_STATE_HUFFMAN_SIMPLE_SIZE,
+ BROTLI_STATE_HUFFMAN_SIMPLE_READ,
+ BROTLI_STATE_HUFFMAN_SIMPLE_BUILD,
+ BROTLI_STATE_HUFFMAN_COMPLEX,
BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS
} BrotliRunningHuffmanState;
@@ -94,10 +97,23 @@ typedef enum {
BROTLI_STATE_DECODE_UINT8_LONG
} BrotliRunningDecodeUint8State;
-typedef struct {
+typedef enum {
+ BROTLI_STATE_READ_BLOCK_LENGTH_NONE,
+ BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
+} BrotliRunningReadBlockLengthState;
+
+struct BrotliStateStruct {
BrotliRunningState state;
- /* This counter is reused for several disjoint loops. */
BrotliBitReader br;
+
+ /* Temporary storage for remaining input. */
+ union {
+ uint64_t u64;
+ uint8_t u8[8];
+ } buffer;
+ uint32_t buffer_length;
+
+ /* This counter is reused for several disjoint loops. */
int loop_counter;
int pos;
int max_backward_distance;
@@ -115,6 +131,8 @@ typedef struct {
uint8_t* context_map_slice;
uint8_t* dist_context_map_slice;
+ uint32_t sub_loop_counter;
+
/* This ring buffer holds a few past copy distances that will be used by */
/* some special distance codes. */
HuffmanTreeGroup literal_hgroup;
@@ -127,7 +145,8 @@ typedef struct {
int trivial_literal_context;
int distance_context;
int meta_block_remaining_len;
- int block_length[3];
+ uint32_t block_length_index;
+ uint32_t block_length[3];
uint32_t num_block_types[3];
uint32_t block_type_rb[6];
uint32_t distance_postfix_bits;
@@ -138,16 +157,16 @@ typedef struct {
HuffmanCode *literal_htree;
uint8_t literal_htree_index;
uint8_t dist_htree_index;
- uint8_t repeat_code_len;
- uint8_t prev_code_len;
+ uint32_t repeat_code_len;
+ uint32_t prev_code_len;
int copy_length;
int distance_code;
/* For partial write operations */
- int to_write;
- int partially_written;
+ size_t rb_roundtrips; /* How many times we went around the ringbuffer */
+ size_t partial_pos_out; /* How much output to the user in total (<= rb) */
/* For ReadHuffmanCode */
uint32_t symbol;
@@ -173,6 +192,7 @@ typedef struct {
/* For DecodeContextMap */
uint32_t context_index;
uint32_t max_run_length_prefix;
+ uint32_t code;
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_TABLE_SIZE];
/* For InverseMoveToFrontTransform */
@@ -191,6 +211,7 @@ typedef struct {
BrotliRunningUncompressedState substate_uncompressed;
BrotliRunningHuffmanState substate_huffman;
BrotliRunningDecodeUint8State substate_decode_uint8;
+ BrotliRunningReadBlockLengthState substate_read_block_length;
uint8_t is_last_metablock;
uint8_t is_uncompressed;
@@ -201,13 +222,32 @@ typedef struct {
uint32_t num_literal_htrees;
uint8_t* context_map;
uint8_t* context_modes;
-} BrotliState;
+
+ uint8_t* legacy_input_buffer;
+ uint8_t* legacy_output_buffer;
+ size_t legacy_input_len;
+ size_t legacy_output_len;
+ size_t legacy_input_pos;
+ size_t legacy_output_pos;
+};
+
+typedef struct BrotliStateStruct BrotliState;
void BrotliStateInit(BrotliState* s);
void BrotliStateCleanup(BrotliState* s);
void BrotliStateMetablockBegin(BrotliState* s);
void BrotliStateCleanupAfterMetablock(BrotliState* s);
+
+/* Returns 1, if s is in a state where we have not read any input bytes yet,
+ and 0 otherwise */
+int BrotliStateIsStreamStart(const BrotliState* s);
+
+/* Returns 1, if s is in a state where we reached the end of the input and
+ produced all of the output, and 0 otherwise. */
+int BrotliStateIsStreamEnd(const BrotliState* s);
+
+
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
diff --git a/third_party/brotli/dec/streams.c b/third_party/brotli/dec/streams.c
index f7060a9..007c513 100644
--- a/third_party/brotli/dec/streams.c
+++ b/third_party/brotli/dec/streams.c
@@ -99,7 +99,7 @@ int BrotliNullOutputFunction(void* data , const uint8_t* buf, size_t count) {
return (int)count;
}
-BrotliOutput BrotliNullOutput() {
+BrotliOutput BrotliNullOutput(void) {
BrotliOutput out;
out.cb_ = BrotliNullOutputFunction;
out.data_ = NULL;
diff --git a/third_party/brotli/dec/streams.h b/third_party/brotli/dec/streams.h
index decfa7e..99eb125 100644
--- a/third_party/brotli/dec/streams.h
+++ b/third_party/brotli/dec/streams.h
@@ -95,7 +95,7 @@ BrotliOutput BrotliFileOutput(FILE* f);
/* Output callback that does nothing, always consumes the whole input. */
int BrotliNullOutputFunction(void* data, const uint8_t* buf, size_t count);
-BrotliOutput BrotliNullOutput();
+BrotliOutput BrotliNullOutput(void);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
diff --git a/third_party/brotli/dec/types.h b/third_party/brotli/dec/types.h
index e7e5ab1..8a9cc4a 100644
--- a/third_party/brotli/dec/types.h
+++ b/third_party/brotli/dec/types.h
@@ -21,14 +21,14 @@
#include <stddef.h> /* for size_t */
#if defined(_MSC_VER) && (_MSC_VER < 1600)
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long int uint64_t;
-typedef long long int int64_t;
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
#else
#include <stdint.h>
#endif /* defined(_MSC_VER) && (_MSC_VER < 1600) */