mirror of
https://github.com/google/brotli.git
synced 2024-11-24 20:40:13 +00:00
Update (#589)
* cleanup * fix `unbrotli` CLI * Java retouch for faster JS decoder
This commit is contained in:
parent
4f455cac32
commit
6535435413
@ -1260,8 +1260,6 @@ static void BROTLI_NOINLINE WrapRingBuffer(BrotliDecoderState* s) {
|
||||
|
||||
Last two bytes of ring-buffer are initialized to 0, so context calculation
|
||||
could be done uniformly for the first two and all other positions.
|
||||
|
||||
Custom dictionary, if any, is copied to the end of ring-buffer.
|
||||
*/
|
||||
static BROTLI_BOOL BROTLI_NOINLINE BrotliEnsureRingBuffer(
|
||||
BrotliDecoderState* s) {
|
||||
|
@ -20,7 +20,9 @@
|
||||
#define BUCKET_SIZE (1 << BUCKET_BITS)
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return MAX_TREE_COMP_LENGTH; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
|
||||
return MAX_TREE_COMP_LENGTH;
|
||||
}
|
||||
|
||||
static uint32_t FN(HashBytes)(const uint8_t *data) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;
|
||||
|
@ -146,7 +146,7 @@ static Command ParseAlias(const char* name) {
|
||||
size_t unbrotli_len = strlen(unbrotli);
|
||||
name = FileName(name);
|
||||
/* Partial comparison. On Windows there could be ".exe" suffix. */
|
||||
if (strncmp(name, unbrotli, unbrotli_len)) {
|
||||
if (strncmp(name, unbrotli, unbrotli_len) == 0) {
|
||||
char terminator = name[unbrotli_len];
|
||||
if (terminator == 0 || terminator == '.') return COMMAND_DECOMPRESS;
|
||||
}
|
||||
|
@ -43,11 +43,13 @@ final class BitReader {
|
||||
* <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
|
||||
* buffer.
|
||||
*/
|
||||
// TODO: Split to check and read; move read outside of decoding loop.
|
||||
static void readMoreInput(State s) {
|
||||
if (s.halfOffset <= HALF_WATERLINE) {
|
||||
return;
|
||||
if (s.halfOffset > HALF_WATERLINE) {
|
||||
doReadMoreInput(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void doReadMoreInput(State s) {
|
||||
if (s.endOfStreamReached != 0) {
|
||||
if (halfAvailable(s) >= -2) {
|
||||
return;
|
||||
@ -89,6 +91,7 @@ final class BitReader {
|
||||
|
||||
static void fillBitWindow(State s) {
|
||||
if (s.bitOffset >= HALF_BITNESS) {
|
||||
// Same as doFillBitWindow. JVM fails to inline it.
|
||||
if (BITNESS == 64) {
|
||||
s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS)
|
||||
| (s.accumulator64 >>> HALF_BITNESS);
|
||||
@ -100,6 +103,17 @@ final class BitReader {
|
||||
}
|
||||
}
|
||||
|
||||
private static void doFillBitWindow(State s) {
|
||||
if (BITNESS == 64) {
|
||||
s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS)
|
||||
| (s.accumulator64 >>> HALF_BITNESS);
|
||||
} else {
|
||||
s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS)
|
||||
| (s.accumulator32 >>> HALF_BITNESS);
|
||||
}
|
||||
s.bitOffset -= HALF_BITNESS;
|
||||
}
|
||||
|
||||
static int peekBits(State s) {
|
||||
if (BITNESS == 64) {
|
||||
return (int) (s.accumulator64 >>> s.bitOffset);
|
||||
@ -109,7 +123,6 @@ final class BitReader {
|
||||
}
|
||||
|
||||
static int readFewBits(State s, int n) {
|
||||
fillBitWindow(s);
|
||||
int val = peekBits(s) & ((1 << n) - 1);
|
||||
s.bitOffset += n;
|
||||
return val;
|
||||
@ -119,18 +132,16 @@ final class BitReader {
|
||||
if (HALF_BITNESS >= 24) {
|
||||
return readFewBits(s, n);
|
||||
} else {
|
||||
if (n <= 16) {
|
||||
return readFewBits(s, n);
|
||||
} else if (s.bitOffset + n <= BITNESS) {
|
||||
return readFewBits(s, n);
|
||||
} else {
|
||||
int lo = readFewBits(s, 16);
|
||||
int hi = readFewBits(s, n - 16);
|
||||
return lo | (hi << 16);
|
||||
}
|
||||
return (n <= 16) ? readFewBits(s, n) : readManyBits(s, n);
|
||||
}
|
||||
}
|
||||
|
||||
private static int readManyBits(State s, int n) {
|
||||
int low = readFewBits(s, 16);
|
||||
doFillBitWindow(s);
|
||||
return low | (readFewBits(s, n - 16) << 16);
|
||||
}
|
||||
|
||||
static void initBitReader(State s) {
|
||||
s.byteBuffer = new byte[BUFFER_SIZE];
|
||||
if (BITNESS == 64) {
|
||||
@ -146,11 +157,11 @@ final class BitReader {
|
||||
prepare(s);
|
||||
}
|
||||
|
||||
static void prepare(State s) {
|
||||
private static void prepare(State s) {
|
||||
readMoreInput(s);
|
||||
checkHealth(s, 0);
|
||||
fillBitWindow(s);
|
||||
fillBitWindow(s);
|
||||
doFillBitWindow(s);
|
||||
doFillBitWindow(s);
|
||||
}
|
||||
|
||||
static void reload(State s) {
|
||||
@ -162,7 +173,7 @@ final class BitReader {
|
||||
static void jumpToByteBoundary(State s) {
|
||||
int padding = (BITNESS - s.bitOffset) & 7;
|
||||
if (padding != 0) {
|
||||
int paddingBits = readBits(s, padding);
|
||||
int paddingBits = readFewBits(s, padding);
|
||||
if (paddingBits != 0) {
|
||||
throw new BrotliRuntimeException("Corrupted padding bits");
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ final class Decode {
|
||||
};
|
||||
|
||||
private static int decodeWindowBits(State s) {
|
||||
BitReader.fillBitWindow(s);
|
||||
if (BitReader.readFewBits(s, 1) == 0) {
|
||||
return 16;
|
||||
}
|
||||
@ -178,6 +179,7 @@ final class Decode {
|
||||
* Decodes a number in the range [0..255], by reading 1 - 11 bits.
|
||||
*/
|
||||
private static int decodeVarLenUnsignedByte(State s) {
|
||||
BitReader.fillBitWindow(s);
|
||||
if (BitReader.readFewBits(s, 1) != 0) {
|
||||
int n = BitReader.readFewBits(s, 3);
|
||||
if (n == 0) {
|
||||
@ -190,6 +192,7 @@ final class Decode {
|
||||
}
|
||||
|
||||
private static void decodeMetaBlockLength(State s) {
|
||||
BitReader.fillBitWindow(s);
|
||||
s.inputEnd = BitReader.readFewBits(s, 1);
|
||||
s.metaBlockLength = 0;
|
||||
s.isUncompressed = 0;
|
||||
@ -208,6 +211,7 @@ final class Decode {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < sizeBytes; i++) {
|
||||
BitReader.fillBitWindow(s);
|
||||
int bits = BitReader.readFewBits(s, 8);
|
||||
if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {
|
||||
throw new BrotliRuntimeException("Exuberant nibble");
|
||||
@ -216,6 +220,7 @@ final class Decode {
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < sizeNibbles; i++) {
|
||||
BitReader.fillBitWindow(s);
|
||||
int bits = BitReader.readFewBits(s, 4);
|
||||
if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {
|
||||
throw new BrotliRuntimeException("Exuberant nibble");
|
||||
@ -252,6 +257,7 @@ final class Decode {
|
||||
BitReader.fillBitWindow(s);
|
||||
int code = readSymbol(table, offset, s);
|
||||
int n = BLOCK_LENGTH_N_BITS[code];
|
||||
BitReader.fillBitWindow(s);
|
||||
return BLOCK_LENGTH_OFFSET[code] + BitReader.readBits(s, n);
|
||||
}
|
||||
|
||||
@ -325,6 +331,7 @@ final class Decode {
|
||||
repeat -= 2;
|
||||
repeat <<= extraBits;
|
||||
}
|
||||
BitReader.fillBitWindow(s);
|
||||
repeat += BitReader.readFewBits(s, extraBits) + 3;
|
||||
int repeatDelta = repeat - oldRepeat;
|
||||
if (symbol + repeatDelta > numSymbols) {
|
||||
@ -363,6 +370,7 @@ final class Decode {
|
||||
BitReader.readMoreInput(s);
|
||||
// TODO: Avoid allocation.
|
||||
int[] codeLengths = new int[alphabetSize];
|
||||
BitReader.fillBitWindow(s);
|
||||
simpleCodeOrSkip = BitReader.readFewBits(s, 2);
|
||||
if (simpleCodeOrSkip == 1) { // Read symbols, codes & code lengths directly.
|
||||
int maxBitsCounter = alphabetSize - 1;
|
||||
@ -376,6 +384,7 @@ final class Decode {
|
||||
// TODO: uncomment when codeLengths is reused.
|
||||
// Utils.fillWithZeroes(codeLengths, 0, alphabetSize);
|
||||
for (int i = 0; i < numSymbols; i++) {
|
||||
BitReader.fillBitWindow(s);
|
||||
symbols[i] = BitReader.readFewBits(s, maxBits) % alphabetSize;
|
||||
codeLengths[symbols[i]] = 2;
|
||||
}
|
||||
@ -433,6 +442,7 @@ final class Decode {
|
||||
return numTrees;
|
||||
}
|
||||
|
||||
BitReader.fillBitWindow(s);
|
||||
int useRleForZeros = BitReader.readFewBits(s, 1);
|
||||
int maxRunLengthPrefix = 0;
|
||||
if (useRleForZeros != 0) {
|
||||
@ -448,6 +458,7 @@ final class Decode {
|
||||
contextMap[i] = 0;
|
||||
i++;
|
||||
} else if (code <= maxRunLengthPrefix) {
|
||||
BitReader.fillBitWindow(s);
|
||||
int reps = (1 << code) + BitReader.readFewBits(s, code);
|
||||
while (reps != 0) {
|
||||
if (i >= contextMapSize) {
|
||||
@ -462,6 +473,7 @@ final class Decode {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
BitReader.fillBitWindow(s);
|
||||
if (BitReader.readFewBits(s, 1) == 1) {
|
||||
inverseMoveToFrontTransform(contextMap, contextMapSize);
|
||||
}
|
||||
@ -590,6 +602,7 @@ final class Decode {
|
||||
s.distanceBlockLength = readMetablockPartition(s, 2, s.numDistanceBlockTypes);
|
||||
|
||||
BitReader.readMoreInput(s);
|
||||
BitReader.fillBitWindow(s);
|
||||
s.distancePostfixBits = BitReader.readFewBits(s, 2);
|
||||
s.numDirectDistanceCodes =
|
||||
NUM_DISTANCE_SHORT_CODES + (BitReader.readFewBits(s, 4) << s.distancePostfixBits);
|
||||
@ -601,6 +614,7 @@ final class Decode {
|
||||
/* Ensure that less than 256 bits read between readMoreInput. */
|
||||
int limit = Math.min(i + 96, s.numLiteralBlockTypes);
|
||||
for (; i < limit; ++i) {
|
||||
BitReader.fillBitWindow(s);
|
||||
s.contextModes[i] = (byte) (BitReader.readFewBits(s, 2));
|
||||
}
|
||||
BitReader.readMoreInput(s);
|
||||
@ -671,10 +685,6 @@ final class Decode {
|
||||
}
|
||||
|
||||
private static int writeRingBuffer(State s) {
|
||||
if (s.bytesToIgnore != 0) {
|
||||
s.bytesWritten += s.bytesToIgnore;
|
||||
s.bytesToIgnore = 0;
|
||||
}
|
||||
int toWrite = Math.min(s.outputLength - s.outputUsed,
|
||||
s.bytesToWrite - s.bytesWritten);
|
||||
if (toWrite != 0) {
|
||||
@ -752,11 +762,15 @@ final class Decode {
|
||||
s.distanceCode = -1;
|
||||
}
|
||||
int insertCode = INSERT_RANGE_LUT[rangeIdx] + ((cmdCode >>> 3) & 7);
|
||||
BitReader.fillBitWindow(s);
|
||||
int insertBits = INSERT_LENGTH_N_BITS[insertCode];
|
||||
int insertExtra = BitReader.readBits(s, insertBits);
|
||||
s.insertLength = INSERT_LENGTH_OFFSET[insertCode] + insertExtra;
|
||||
int copyCode = COPY_RANGE_LUT[rangeIdx] + (cmdCode & 7);
|
||||
s.insertLength = INSERT_LENGTH_OFFSET[insertCode] + BitReader
|
||||
.readBits(s, INSERT_LENGTH_N_BITS[insertCode]);
|
||||
s.copyLength = COPY_LENGTH_OFFSET[copyCode] + BitReader
|
||||
.readBits(s, COPY_LENGTH_N_BITS[copyCode]);
|
||||
BitReader.fillBitWindow(s);
|
||||
int copyBits = COPY_LENGTH_N_BITS[copyCode];
|
||||
int copyExtra = BitReader.readBits(s, copyBits);
|
||||
s.copyLength = COPY_LENGTH_OFFSET[copyCode] + copyExtra;
|
||||
|
||||
s.j = 0;
|
||||
s.runningState = INSERT_LOOP;
|
||||
@ -833,8 +847,10 @@ final class Decode {
|
||||
s.distanceCode >>>= s.distancePostfixBits;
|
||||
int n = (s.distanceCode >>> 1) + 1;
|
||||
int offset = ((2 + (s.distanceCode & 1)) << n) - 4;
|
||||
BitReader.fillBitWindow(s);
|
||||
int distanceExtra = BitReader.readBits(s, n);
|
||||
s.distanceCode = s.numDirectDistanceCodes + postfix
|
||||
+ ((offset + BitReader.readBits(s, n)) << s.distancePostfixBits);
|
||||
+ ((offset + distanceExtra) << s.distancePostfixBits);
|
||||
}
|
||||
}
|
||||
|
||||
@ -873,9 +889,15 @@ final class Decode {
|
||||
int src = (s.pos - s.distance) & ringBufferMask;
|
||||
int dst = s.pos;
|
||||
int copyLength = s.copyLength - s.j;
|
||||
if ((src + copyLength < ringBufferMask) && (dst + copyLength < ringBufferMask)) {
|
||||
for (int k = 0; k < copyLength; ++k) {
|
||||
ringBuffer[dst++] = ringBuffer[src++];
|
||||
int srcEnd = src + copyLength;
|
||||
int dstEnd = dst + copyLength;
|
||||
if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) {
|
||||
if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) {
|
||||
for (int k = 0; k < copyLength; ++k) {
|
||||
ringBuffer[dst++] = ringBuffer[src++];
|
||||
}
|
||||
} else {
|
||||
Utils.copyBytesWithin(ringBuffer, dst, src, srcEnd);
|
||||
}
|
||||
s.j += copyLength;
|
||||
s.metaBlockLength -= copyLength;
|
||||
@ -941,6 +963,7 @@ final class Decode {
|
||||
while (s.metaBlockLength > 0) {
|
||||
BitReader.readMoreInput(s);
|
||||
// Optimize
|
||||
BitReader.fillBitWindow(s);
|
||||
BitReader.readFewBits(s, 8);
|
||||
s.metaBlockLength--;
|
||||
}
|
||||
|
@ -35,6 +35,9 @@ public final class Dictionary {
|
||||
}
|
||||
|
||||
public static void setData(ByteBuffer data) {
|
||||
if (!data.isDirect() || !data.isReadOnly()) {
|
||||
throw new BrotliRuntimeException("data must be a direct read-only byte buffer");
|
||||
}
|
||||
Dictionary.data = data;
|
||||
}
|
||||
|
||||
|
@ -19,18 +19,20 @@ final class DictionaryData {
|
||||
private static final String SKIP_FLIP = "\u06F7%\u018C'T%\u0085'W%\u00D7%O%g%\u00A6&\u0193%\u01E5&>&*&'&^&\u0088\u0178\u0C3E&\u01AD&\u0192&)&^&%&'&\u0082&P&1&\u00B1&3&]&m&u&E&t&C&\u00CF&V&V&/&>&6&\u0F76\u177Co&p&@&E&M&P&x&@&F&e&\u00CC&7&:&(&D&0&C&)&.&F&-&1&(&L&F&1\u025E*\u03EA\u21F3&\u1372&K&;&)&E&H&P&0&?&9&V&\u0081&-&v&a&,&E&)&?&=&'&'&B&\u0D2E&\u0503&\u0316*&*8&%&%&&&%,)&\u009A&>&\u0086&7&]&F&2&>&J&6&n&2&%&?&\u008E&2&6&J&g&-&0&,&*&J&*&O&)&6&(&<&B&N&.&P&@&2&.&W&M&%\u053C\u0084(,(<&,&\u03DA&\u18C7&-&,(%&(&%&(\u013B0&X&D&\u0081&j&'&J&(&.&B&3&Z&R&h&3&E&E&<\u00C6-\u0360\u1EF3&%8?&@&,&Z&@&0&J&,&^&x&_&6&C&6&C\u072C\u2A25&f&-&-&-&-&,&J&2&8&z&8&C&Y&8&-&d&\u1E78\u00CC-&7&1&F&7&t&W&7&I&.&.&^&=\u0F9C\u19D3&8(>&/&/&\u077B')'\u1065')'%@/&0&%\u043E\u09C0*&*@&C\u053D\u05D4\u0274\u05EB4\u0DD7\u071A\u04D16\u0D84&/\u0178\u0303Z&*%\u0246\u03FF&\u0134&1\u00A8\u04B4\u0174";
|
||||
|
||||
private static void unpackDictionaryData(
|
||||
byte[] dictionary, String data0, String data1, String skipFlip) {
|
||||
ByteBuffer dictionary, String data0, String data1, String skipFlip) {
|
||||
int n0 = data0.length();
|
||||
int n1 = data1.length();
|
||||
if (n0 + n1 != dictionary.length) {
|
||||
if (n0 + n1 != dictionary.capacity()) {
|
||||
throw new RuntimeException("Corrupted brotli dictionary");
|
||||
}
|
||||
int offset = 0;
|
||||
for (int i = 0; i < n0; ++i) {
|
||||
dictionary[offset++] = (byte) data0.charAt(i);
|
||||
dictionary.put(offset, (byte) data0.charAt(i));
|
||||
offset++;
|
||||
}
|
||||
for (int i = 0; i < n1; ++i) {
|
||||
dictionary[offset++] = (byte) data1.charAt(i);
|
||||
dictionary.put(offset, (byte) data1.charAt(i));
|
||||
offset++;
|
||||
}
|
||||
offset = 0;
|
||||
int n = skipFlip.length();
|
||||
@ -39,15 +41,15 @@ final class DictionaryData {
|
||||
int flip = skipFlip.charAt(i + 1) - 36;
|
||||
offset += skip;
|
||||
for (int j = 0; j < flip; ++j) {
|
||||
dictionary[offset] = (byte) (dictionary[offset] | 0x80);
|
||||
dictionary.put(offset, (byte) (dictionary.get(offset) | 0x80));
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
byte[] dictionary = new byte[122784];
|
||||
ByteBuffer dictionary = ByteBuffer.allocateDirect(122784);
|
||||
unpackDictionaryData(dictionary, DATA0, DATA1, SKIP_FLIP);
|
||||
Dictionary.setData(ByteBuffer.wrap(dictionary).asReadOnlyBuffer());
|
||||
Dictionary.setData(dictionary.asReadOnlyBuffer());
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ final class State {
|
||||
int maxRingBufferSize;
|
||||
int ringBufferSize;
|
||||
int expectedTotalSize;
|
||||
int bytesToIgnore;
|
||||
int outputOffset;
|
||||
int outputLength;
|
||||
int outputUsed;
|
||||
|
Loading…
Reference in New Issue
Block a user