further preparations for Kotlin transpilation

PiperOrigin-RevId: 603638823
This commit is contained in:
Evgenii Kliuchnikov 2024-02-02 03:26:05 -08:00 committed by Copybara-Service
parent 200f37984a
commit c1362a7903
11 changed files with 391 additions and 335 deletions

View File

@ -146,9 +146,9 @@ final class BitReader {
* otherwise BitReader will become broken. * otherwise BitReader will become broken.
*/ */
static int readFewBits(State s, int n) { static int readFewBits(State s, int n) {
final int val = peekBits(s) & ((1 << n) - 1); final int v = peekBits(s) & ((1 << n) - 1);
s.bitOffset += n; s.bitOffset += n;
return val; return v;
} }
static int readBits(State s, int n) { static int readBits(State s, int n) {
@ -212,31 +212,33 @@ final class BitReader {
} }
static void copyRawBytes(State s, byte[] data, int offset, int length) { static void copyRawBytes(State s, byte[] data, int offset, int length) {
int pos = offset;
int len = length;
if ((s.bitOffset & 7) != 0) { if ((s.bitOffset & 7) != 0) {
throw new BrotliRuntimeException("Unaligned copyBytes"); throw new BrotliRuntimeException("Unaligned copyBytes");
} }
// Drain accumulator. // Drain accumulator.
while ((s.bitOffset != BITNESS) && (length != 0)) { while ((s.bitOffset != BITNESS) && (len != 0)) {
data[offset++] = (byte) peekBits(s); data[pos++] = (byte) peekBits(s);
s.bitOffset += 8; s.bitOffset += 8;
length--; len--;
} }
if (length == 0) { if (len == 0) {
return; return;
} }
// Get data from shadow buffer with "sizeof(int)" granularity. // Get data from shadow buffer with "sizeof(int)" granularity.
final int copyNibbles = Math.min(halfAvailable(s), length >> LOG_HALF_SIZE); final int copyNibbles = Math.min(halfAvailable(s), len >> LOG_HALF_SIZE);
if (copyNibbles > 0) { if (copyNibbles > 0) {
final int readOffset = s.halfOffset << LOG_HALF_SIZE; final int readOffset = s.halfOffset << LOG_HALF_SIZE;
final int delta = copyNibbles << LOG_HALF_SIZE; final int delta = copyNibbles << LOG_HALF_SIZE;
System.arraycopy(s.byteBuffer, readOffset, data, offset, delta); System.arraycopy(s.byteBuffer, readOffset, data, pos, delta);
offset += delta; pos += delta;
length -= delta; len -= delta;
s.halfOffset += copyNibbles; s.halfOffset += copyNibbles;
} }
if (length == 0) { if (len == 0) {
return; return;
} }
@ -244,23 +246,23 @@ final class BitReader {
if (halfAvailable(s) > 0) { if (halfAvailable(s) > 0) {
// length = 1..3 // length = 1..3
fillBitWindow(s); fillBitWindow(s);
while (length != 0) { while (len != 0) {
data[offset++] = (byte) peekBits(s); data[pos++] = (byte) peekBits(s);
s.bitOffset += 8; s.bitOffset += 8;
length--; len--;
} }
checkHealth(s, 0); checkHealth(s, 0);
return; return;
} }
// Now it is possible to copy bytes directly. // Now it is possible to copy bytes directly.
while (length > 0) { while (len > 0) {
final int len = Utils.readInput(s, data, offset, length); final int chunkLen = Utils.readInput(s, data, pos, len);
if (len == -1) { if (chunkLen == -1) {
throw new BrotliRuntimeException("Unexpected end of input"); throw new BrotliRuntimeException("Unexpected end of input");
} }
offset += len; pos += chunkLen;
length -= len; len -= chunkLen;
} }
} }
@ -273,16 +275,16 @@ final class BitReader {
if (BITNESS == 64) { if (BITNESS == 64) {
final int[] intBuffer = s.intBuffer; final int[] intBuffer = s.intBuffer;
for (int i = 0; i < halfLen; ++i) { for (int i = 0; i < halfLen; ++i) {
intBuffer[i] = ((byteBuffer[i * 4] & 0xFF)) intBuffer[i] = ((int) byteBuffer[i * 4] & 0xFF)
| ((byteBuffer[(i * 4) + 1] & 0xFF) << 8) | (((int) byteBuffer[(i * 4) + 1] & 0xFF) << 8)
| ((byteBuffer[(i * 4) + 2] & 0xFF) << 16) | (((int) byteBuffer[(i * 4) + 2] & 0xFF) << 16)
| ((byteBuffer[(i * 4) + 3] & 0xFF) << 24); | (((int) byteBuffer[(i * 4) + 3] & 0xFF) << 24);
} }
} else { } else {
final short[] shortBuffer = s.shortBuffer; final short[] shortBuffer = s.shortBuffer;
for (int i = 0; i < halfLen; ++i) { for (int i = 0; i < halfLen; ++i) {
shortBuffer[i] = (short) ((byteBuffer[i * 2] & 0xFF) shortBuffer[i] = (short) (((int) byteBuffer[i * 2] & 0xFF)
| ((byteBuffer[(i * 2) + 1] & 0xFF) << 8)); | (((int) byteBuffer[(i * 2) + 1] & 0xFF) << 8));
} }
} }
} }

View File

@ -26,7 +26,7 @@ final class Context {
} }
// UTF8 // UTF8
for (int i = 0; i < 128; ++i) { for (int i = 0; i < 128; ++i) {
lookup[1024 + i] = 4 * (map.charAt(i) - 32); lookup[1024 + i] = 4 * ((int) map.charAt(i) - 32);
} }
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
lookup[1152 + i] = i & 1; lookup[1152 + i] = i & 1;
@ -35,7 +35,7 @@ final class Context {
int offset = 1280; int offset = 1280;
for (int k = 0; k < 19; ++k) { for (int k = 0; k < 19; ++k) {
final int value = k & 3; final int value = k & 3;
final int rep = rle.charAt(k) - 32; final int rep = (int) rle.charAt(k) - 32;
for (int i = 0; i < rep; ++i) { for (int i = 0; i < rep; ++i) {
lookup[offset++] = value; lookup[offset++] = value;
} }

View File

@ -137,14 +137,16 @@ final class Decode {
private static int log2floor(int i) { private static int log2floor(int i) {
int result = -1; int result = -1;
int step = 16; int step = 16;
int v = i;
while (step > 0) { while (step > 0) {
if ((i >>> step) != 0) { int next = v >>> step;
if (next != 0) {
result += step; result += step;
i = i >>> step; v = next;
} }
step = step >> 1; step = step >> 1;
} }
return result + i; return result + v;
} }
private static int calculateDistanceAlphabetSize(int npostfix, int ndirect, int maxndistbits) { private static int calculateDistanceAlphabetSize(int npostfix, int ndirect, int maxndistbits) {
@ -164,14 +166,12 @@ final class Decode {
} }
private static void unpackCommandLookupTable(short[] cmdLookup) { private static void unpackCommandLookupTable(short[] cmdLookup) {
final short[] insertLengthOffsets = new short[24]; final int[] insertLengthOffsets = new int[24];
final short[] copyLengthOffsets = new short[24]; final int[] copyLengthOffsets = new int[24];
copyLengthOffsets[0] = 2; copyLengthOffsets[0] = 2;
for (int i = 0; i < 23; ++i) { for (int i = 0; i < 23; ++i) {
insertLengthOffsets[i + 1] = insertLengthOffsets[i + 1] = insertLengthOffsets[i] + (1 << (int) INSERT_LENGTH_N_BITS[i]);
(short) (insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i])); copyLengthOffsets[i + 1] = copyLengthOffsets[i] + (1 << (int) COPY_LENGTH_N_BITS[i]);
copyLengthOffsets[i + 1] =
(short) (copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i]));
} }
for (int cmdCode = 0; cmdCode < NUM_COMMAND_CODES; ++cmdCode) { for (int cmdCode = 0; cmdCode < NUM_COMMAND_CODES; ++cmdCode) {
@ -184,14 +184,15 @@ final class Decode {
} }
final int insertCode = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7); final int insertCode = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7);
final int copyCode = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7); final int copyCode = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7);
final short copyLengthOffset = copyLengthOffsets[copyCode]; final int copyLengthOffset = copyLengthOffsets[copyCode];
final int distanceContext = final int distanceContext =
distanceContextOffset + (copyLengthOffset > 4 ? 3 : copyLengthOffset - 2); distanceContextOffset + (copyLengthOffset > 4 ? 3 : (copyLengthOffset - 2));
final int index = cmdCode * 4; final int index = cmdCode * 4;
cmdLookup[index + 0] = cmdLookup[index + 0] =
(short) (INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8)); (short)
cmdLookup[index + 1] = insertLengthOffsets[insertCode]; ((int) INSERT_LENGTH_N_BITS[insertCode] | ((int) COPY_LENGTH_N_BITS[copyCode] << 8));
cmdLookup[index + 2] = copyLengthOffsets[copyCode]; cmdLookup[index + 1] = (short) insertLengthOffsets[insertCode];
cmdLookup[index + 2] = (short) copyLengthOffsets[copyCode];
cmdLookup[index + 3] = (short) distanceContext; cmdLookup[index + 3] = (short) distanceContext;
} }
} }
@ -357,7 +358,7 @@ final class Decode {
if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) { if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {
throw new BrotliRuntimeException("Exuberant nibble"); throw new BrotliRuntimeException("Exuberant nibble");
} }
s.metaBlockLength |= bits << (i * 8); s.metaBlockLength += bits << (i * 8);
} }
} else { } else {
for (int i = 0; i < sizeNibbles; ++i) { for (int i = 0; i < sizeNibbles; ++i) {
@ -366,7 +367,7 @@ final class Decode {
if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) { if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {
throw new BrotliRuntimeException("Exuberant nibble"); throw new BrotliRuntimeException("Exuberant nibble");
} }
s.metaBlockLength |= bits << (i * 4); s.metaBlockLength += bits << (i * 4);
} }
} }
s.metaBlockLength++; s.metaBlockLength++;
@ -380,8 +381,8 @@ final class Decode {
*/ */
private static int readSymbol(int[] tableGroup, int tableIdx, State s) { private static int readSymbol(int[] tableGroup, int tableIdx, State s) {
int offset = tableGroup[tableIdx]; int offset = tableGroup[tableIdx];
final int val = BitReader.peekBits(s); final int v = BitReader.peekBits(s);
offset += val & HUFFMAN_TABLE_MASK; offset += v & HUFFMAN_TABLE_MASK;
final int bits = tableGroup[offset] >> 16; final int bits = tableGroup[offset] >> 16;
final int sym = tableGroup[offset] & 0xFFFF; final int sym = tableGroup[offset] & 0xFFFF;
if (bits <= HUFFMAN_TABLE_BITS) { if (bits <= HUFFMAN_TABLE_BITS) {
@ -390,7 +391,7 @@ final class Decode {
} }
offset += sym; offset += sym;
final int mask = (1 << bits) - 1; final int mask = (1 << bits) - 1;
offset += (val & mask) >>> HUFFMAN_TABLE_BITS; offset += (v & mask) >>> HUFFMAN_TABLE_BITS;
s.bitOffset += ((tableGroup[offset] >> 16) + HUFFMAN_TABLE_BITS); s.bitOffset += ((tableGroup[offset] >> 16) + HUFFMAN_TABLE_BITS);
return tableGroup[offset] & 0xFFFF; return tableGroup[offset] & 0xFFFF;
} }
@ -404,10 +405,11 @@ final class Decode {
} }
private static void moveToFront(int[] v, int index) { private static void moveToFront(int[] v, int index) {
final int value = v[index]; int i = index;
while (index > 0) { final int value = v[i];
v[index] = v[index - 1]; while (i > 0) {
index--; v[i] = v[i - 1];
i--;
} }
v[0] = value; v[0] = value;
} }
@ -418,7 +420,7 @@ final class Decode {
mtf[i] = i; mtf[i] = i;
} }
for (int i = 0; i < vLen; ++i) { for (int i = 0; i < vLen; ++i) {
final int index = v[i] & 0xFF; final int index = (int) v[i] & 0xFF;
v[i] = (byte) mtf[index]; v[i] = (byte) mtf[index];
if (index != 0) { if (index != 0) {
moveToFront(mtf, index); moveToFront(mtf, index);
@ -463,7 +465,7 @@ final class Decode {
final int oldRepeat = repeat; final int oldRepeat = repeat;
if (repeat > 0) { if (repeat > 0) {
repeat -= 2; repeat -= 2;
repeat <<= extraBits; repeat = repeat << extraBits;
} }
BitReader.fillBitWindow(s); BitReader.fillBitWindow(s);
repeat += BitReader.readFewBits(s, extraBits) + 3; repeat += BitReader.readFewBits(s, extraBits) + 3;
@ -689,8 +691,8 @@ final class Decode {
s.literalBlockLength = decodeBlockTypeAndLength(s, 0, s.numLiteralBlockTypes); s.literalBlockLength = decodeBlockTypeAndLength(s, 0, s.numLiteralBlockTypes);
final int literalBlockType = s.rings[5]; final int literalBlockType = s.rings[5];
s.contextMapSlice = literalBlockType << LITERAL_CONTEXT_BITS; s.contextMapSlice = literalBlockType << LITERAL_CONTEXT_BITS;
s.literalTreeIdx = s.contextMap[s.contextMapSlice] & 0xFF; s.literalTreeIdx = (int) s.contextMap[s.contextMapSlice] & 0xFF;
final int contextMode = s.contextModes[literalBlockType]; final int contextMode = (int) s.contextModes[literalBlockType];
s.contextLookupOffset1 = contextMode << 9; s.contextLookupOffset1 = contextMode << 9;
s.contextLookupOffset2 = s.contextLookupOffset1 + 256; s.contextLookupOffset2 = s.contextLookupOffset1 + 256;
} }
@ -711,7 +713,7 @@ final class Decode {
/* TODO(eustas): Handle 2GB+ cases more gracefully. */ /* TODO(eustas): Handle 2GB+ cases more gracefully. */
final int minimalNewSize = s.expectedTotalSize; final int minimalNewSize = s.expectedTotalSize;
while ((newSize >> 1) > minimalNewSize) { while ((newSize >> 1) > minimalNewSize) {
newSize >>= 1; newSize = newSize >> 1;
} }
if ((s.inputEnd == 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) { if ((s.inputEnd == 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) {
newSize = 16384; newSize = 16384;
@ -722,8 +724,9 @@ final class Decode {
} }
final int ringBufferSizeWithSlack = newSize + MAX_TRANSFORMED_WORD_LENGTH; final int ringBufferSizeWithSlack = newSize + MAX_TRANSFORMED_WORD_LENGTH;
final byte[] newBuffer = new byte[ringBufferSizeWithSlack]; final byte[] newBuffer = new byte[ringBufferSizeWithSlack];
if (s.ringBuffer.length != 0) { final byte[] oldBuffer = s.ringBuffer;
System.arraycopy(s.ringBuffer, 0, newBuffer, 0, s.ringBufferSize); if (oldBuffer.length != 0) {
System.arraycopy(oldBuffer, 0, newBuffer, 0, s.ringBufferSize);
} }
s.ringBuffer = newBuffer; s.ringBuffer = newBuffer;
s.ringBufferSize = newSize; s.ringBufferSize = newSize;
@ -850,7 +853,7 @@ final class Decode {
final int numLiteralTrees = decodeContextMap(contextMapLength, s.contextMap, s); final int numLiteralTrees = decodeContextMap(contextMapLength, s.contextMap, s);
s.trivialLiteralContext = 1; s.trivialLiteralContext = 1;
for (int j = 0; j < contextMapLength; ++j) { for (int j = 0; j < contextMapLength; ++j) {
if (s.contextMap[j] != j >> LITERAL_CONTEXT_BITS) { if ((int) s.contextMap[j] != j >> LITERAL_CONTEXT_BITS) {
s.trivialLiteralContext = 0; s.trivialLiteralContext = 0;
break; break;
} }
@ -1021,7 +1024,7 @@ final class Decode {
if (s.cdBlockBits == -1) { if (s.cdBlockBits == -1) {
initializeCompoundDictionary(s); initializeCompoundDictionary(s);
} }
int index = s.cdBlockMap[address >>> s.cdBlockBits]; int index = (int) s.cdBlockMap[address >>> s.cdBlockBits];
while (address >= s.cdChunkOffsets[index + 1]) { while (address >= s.cdChunkOffsets[index + 1]) {
index++; index++;
} }
@ -1123,10 +1126,10 @@ final class Decode {
s.commandBlockLength--; s.commandBlockLength--;
BitReader.fillBitWindow(s); BitReader.fillBitWindow(s);
final int cmdCode = readSymbol(s.commandTreeGroup, s.commandTreeIdx, s) << 2; final int cmdCode = readSymbol(s.commandTreeGroup, s.commandTreeIdx, s) << 2;
final short insertAndCopyExtraBits = CMD_LOOKUP[cmdCode]; final int insertAndCopyExtraBits = (int) CMD_LOOKUP[cmdCode];
final int insertLengthOffset = CMD_LOOKUP[cmdCode + 1]; final int insertLengthOffset = (int) CMD_LOOKUP[cmdCode + 1];
final int copyLengthOffset = CMD_LOOKUP[cmdCode + 2]; final int copyLengthOffset = (int) CMD_LOOKUP[cmdCode + 2];
s.distanceCode = CMD_LOOKUP[cmdCode + 3]; s.distanceCode = (int) CMD_LOOKUP[cmdCode + 3];
BitReader.fillBitWindow(s); BitReader.fillBitWindow(s);
{ {
final int insertLengthExtraBits = insertAndCopyExtraBits & 0xFF; final int insertLengthExtraBits = insertAndCopyExtraBits & 0xFF;
@ -1161,8 +1164,8 @@ final class Decode {
} }
} }
} else { } else {
int prevByte1 = ringBuffer[(s.pos - 1) & ringBufferMask] & 0xFF; int prevByte1 = (int) ringBuffer[(s.pos - 1) & ringBufferMask] & 0xFF;
int prevByte2 = ringBuffer[(s.pos - 2) & ringBufferMask] & 0xFF; int prevByte2 = (int) ringBuffer[(s.pos - 2) & ringBufferMask] & 0xFF;
while (s.j < s.insertLength) { while (s.j < s.insertLength) {
BitReader.readMoreInput(s); BitReader.readMoreInput(s);
if (s.literalBlockLength == 0) { if (s.literalBlockLength == 0) {
@ -1170,7 +1173,8 @@ final class Decode {
} }
final int literalContext = Context.LOOKUP[s.contextLookupOffset1 + prevByte1] final int literalContext = Context.LOOKUP[s.contextLookupOffset1 + prevByte1]
| Context.LOOKUP[s.contextLookupOffset2 + prevByte2]; | Context.LOOKUP[s.contextLookupOffset2 + prevByte2];
final int literalTreeIdx = s.contextMap[s.contextMapSlice + literalContext] & 0xFF; final int literalTreeIdx =
(int) s.contextMap[s.contextMapSlice + literalContext] & 0xFF;
s.literalBlockLength--; s.literalBlockLength--;
prevByte2 = prevByte1; prevByte2 = prevByte1;
BitReader.fillBitWindow(s); BitReader.fillBitWindow(s);
@ -1204,7 +1208,8 @@ final class Decode {
} }
s.distanceBlockLength--; s.distanceBlockLength--;
BitReader.fillBitWindow(s); BitReader.fillBitWindow(s);
final int distTreeIdx = s.distContextMap[s.distContextMapSlice + distanceCode] & 0xFF; final int distTreeIdx =
(int) s.distContextMap[s.distContextMapSlice + distanceCode] & 0xFF;
distanceCode = readSymbol(s.distanceTreeGroup, distTreeIdx, s); distanceCode = readSymbol(s.distanceTreeGroup, distTreeIdx, s);
if (distanceCode < NUM_DISTANCE_SHORT_CODES) { if (distanceCode < NUM_DISTANCE_SHORT_CODES) {
final int index = final int index =
@ -1214,7 +1219,7 @@ final class Decode {
throw new BrotliRuntimeException("Negative distance"); // COV_NF_LINE throw new BrotliRuntimeException("Negative distance"); // COV_NF_LINE
} }
} else { } else {
final int extraBits = s.distExtraBits[distanceCode]; final int extraBits = (int) s.distExtraBits[distanceCode];
int bits; int bits;
if (s.bitOffset + extraBits <= BitReader.BITNESS) { if (s.bitOffset + extraBits <= BitReader.BITNESS) {
bits = BitReader.readFewBits(s, extraBits); bits = BitReader.readFewBits(s, extraBits);
@ -1337,7 +1342,7 @@ final class Decode {
if (s.pos > s.ringBufferSize) { if (s.pos > s.ringBufferSize) {
Utils.copyBytesWithin(ringBuffer, 0, s.ringBufferSize, s.pos); Utils.copyBytesWithin(ringBuffer, 0, s.ringBufferSize, s.pos);
} }
s.pos &= ringBufferMask; s.pos = s.pos & ringBufferMask;
s.ringBufferBytesWritten = 0; s.ringBufferBytesWritten = 0;
} }
s.runningState = s.nextRunningState; s.runningState = s.nextRunningState;

View File

@ -45,20 +45,20 @@ final class DictionaryData {
int offset = 0; int offset = 0;
final int n = skipFlip.length() >> 1; final int n = skipFlip.length() >> 1;
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
final int skip = skipFlip.charAt(2 * i) - 36; final int skip = (int) skipFlip.charAt(2 * i) - 36;
final int flip = skipFlip.charAt(2 * i + 1) - 36; final int flip = (int) skipFlip.charAt(2 * i + 1) - 36;
for (int j = 0; j < skip; ++j) { for (int j = 0; j < skip; ++j) {
dict[offset] ^= 3; dict[offset] = (byte) ((int) dict[offset] ^ 3);
offset++; offset++;
} }
for (int j = 0; j < flip; ++j) { for (int j = 0; j < flip; ++j) {
dict[offset] ^= 236; dict[offset] = (byte) ((int) dict[offset] ^ 236);
offset++; offset++;
} }
} }
for (int i = 0; i < sizeBitsData.length(); ++i) { for (int i = 0; i < sizeBitsData.length(); ++i) {
sizeBits[i] = sizeBitsData.charAt(i) - 65; sizeBits[i] = (int) sizeBitsData.charAt(i) - 65;
} }
dictionary.put(dict); dictionary.put(dict);

View File

@ -21,7 +21,7 @@ final class Huffman {
private static int getNextKey(int key, int len) { private static int getNextKey(int key, int len) {
int step = 1 << (len - 1); int step = 1 << (len - 1);
while ((key & step) != 0) { while ((key & step) != 0) {
step >>= 1; step = step >> 1;
} }
return (key & (step - 1)) + step; return (key & (step - 1)) + step;
} }
@ -32,10 +32,11 @@ final class Huffman {
* <p> Assumes that end is an integer multiple of step. * <p> Assumes that end is an integer multiple of step.
*/ */
private static void replicateValue(int[] table, int offset, int step, int end, int item) { private static void replicateValue(int[] table, int offset, int step, int end, int item) {
int pos = end;
do { do {
end -= step; pos -= step;
table[offset + end] = item; table[offset + pos] = item;
} while (end > 0); } while (pos > 0);
} }
/** /**
@ -44,16 +45,17 @@ final class Huffman {
* @return table width of the next 2nd level table. * @return table width of the next 2nd level table.
*/ */
private static int nextTableBitSize(int[] count, int len, int rootBits) { private static int nextTableBitSize(int[] count, int len, int rootBits) {
int left = 1 << (len - rootBits); int bits = len;
while (len < MAX_LENGTH) { int left = 1 << (bits - rootBits);
left -= count[len]; while (bits < MAX_LENGTH) {
left -= count[bits];
if (left <= 0) { if (left <= 0) {
break; break;
} }
len++; bits++;
left <<= 1; left = left << 1;
} }
return len - rootBits; return bits - rootBits;
} }
/** /**
@ -104,7 +106,7 @@ final class Huffman {
int symbol = 0; int symbol = 0;
int step = 1; int step = 1;
for (int len = 1; len <= rootBits; ++len) { for (int len = 1; len <= rootBits; ++len) {
step <<= 1; step = step << 1;
while (count[len] > 0) { while (count[len] > 0) {
replicateValue(tableGroup, tableOffset + key, step, tableSize, replicateValue(tableGroup, tableOffset + key, step, tableSize,
len << 16 | sorted[symbol++]); len << 16 | sorted[symbol++]);
@ -119,7 +121,7 @@ final class Huffman {
int currentOffset = tableOffset; int currentOffset = tableOffset;
step = 1; step = 1;
for (int len = rootBits + 1; len <= MAX_LENGTH; ++len) { for (int len = rootBits + 1; len <= MAX_LENGTH; ++len) {
step <<= 1; step = step << 1;
while (count[len] > 0) { while (count[len] > 0) {
if ((key & mask) != low) { if ((key & mask) != low) {
currentOffset += tableSize; currentOffset += tableSize;

View File

@ -87,7 +87,7 @@ final class State {
int cdBlockBits; int cdBlockBits;
byte[] cdBlockMap; byte[] cdBlockMap;
InputStream /* @Nullable */ input; // BitReader InputStream input = Utils.makeEmptyInput(); // BitReader
State() { State() {
this.ringBuffer = new byte[0]; this.ringBuffer = new byte[0];

View File

@ -80,7 +80,7 @@ final class Transform {
int index = 1; int index = 1;
int j = 0; int j = 0;
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
final char c = prefixSuffixSrc.charAt(i); final int c = (int) prefixSuffixSrc.charAt(i);
if (c == 35) { // == # if (c == 35) { // == #
prefixSuffixHeads[index++] = j; prefixSuffixHeads[index++] = j;
} else { } else {
@ -89,7 +89,7 @@ final class Transform {
} }
for (int i = 0; i < NUM_RFC_TRANSFORMS * 3; ++i) { for (int i = 0; i < NUM_RFC_TRANSFORMS * 3; ++i) {
transforms[i] = transformsSrc.charAt(i) - 32; transforms[i] = (int) transformsSrc.charAt(i) - 32;
} }
} }
@ -99,7 +99,7 @@ final class Transform {
} }
static int transformDictionaryWord(byte[] dst, int dstOffset, ByteBuffer src, int srcOffset, static int transformDictionaryWord(byte[] dst, int dstOffset, ByteBuffer src, int srcOffset,
int len, Transforms transforms, int transformIndex) { int wordLen, Transforms transforms, int transformIndex) {
int offset = dstOffset; int offset = dstOffset;
final int[] triplets = transforms.triplets; final int[] triplets = transforms.triplets;
final byte[] prefixSuffixStorage = transforms.prefixSuffixStorage; final byte[] prefixSuffixStorage = transforms.prefixSuffixStorage;
@ -127,16 +127,17 @@ final class Transform {
dst[offset++] = prefixSuffixStorage[prefix++]; dst[offset++] = prefixSuffixStorage[prefix++];
} }
int len = wordLen;
// Copy trimmed word. // Copy trimmed word.
if (omitFirst > len) { if (omitFirst > len) {
omitFirst = len; omitFirst = len;
} }
srcOffset += omitFirst; int dictOffset = srcOffset + omitFirst;
len -= omitFirst; len -= omitFirst;
len -= omitLast; len -= omitLast;
int i = len; int i = len;
while (i > 0) { while (i > 0) {
dst[offset++] = src.get(srcOffset++); dst[offset++] = src.get(dictOffset++);
i--; i--;
} }
@ -147,31 +148,31 @@ final class Transform {
len = 1; len = 1;
} }
while (len > 0) { while (len > 0) {
final int c0 = dst[uppercaseOffset] & 0xFF; final int c0 = (int) dst[uppercaseOffset] & 0xFF;
if (c0 < 0xC0) { if (c0 < 0xC0) {
if (c0 >= 97 && c0 <= 122) { // in [a..z] range if (c0 >= 97 && c0 <= 122) { // in [a..z] range
dst[uppercaseOffset] ^= (byte) 32; dst[uppercaseOffset] = (byte) ((int) dst[uppercaseOffset] ^ 32);
} }
uppercaseOffset += 1; uppercaseOffset += 1;
len -= 1; len -= 1;
} else if (c0 < 0xE0) { } else if (c0 < 0xE0) {
dst[uppercaseOffset + 1] ^= (byte) 32; dst[uppercaseOffset + 1] = (byte) ((int) dst[uppercaseOffset + 1] ^ 32);
uppercaseOffset += 2; uppercaseOffset += 2;
len -= 2; len -= 2;
} else { } else {
dst[uppercaseOffset + 2] ^= (byte) 5; dst[uppercaseOffset + 2] = (byte) ((int) dst[uppercaseOffset + 2] ^ 5);
uppercaseOffset += 3; uppercaseOffset += 3;
len -= 3; len -= 3;
} }
} }
} else if (transformType == SHIFT_FIRST || transformType == SHIFT_ALL) { } else if (transformType == SHIFT_FIRST || transformType == SHIFT_ALL) {
int shiftOffset = offset - len; int shiftOffset = offset - len;
final short param = transforms.params[transformIndex]; final int param = (int) transforms.params[transformIndex];
/* Limited sign extension: scalar < (1 << 24). */ /* Limited sign extension: scalar < (1 << 24). */
int scalar = (param & 0x7FFF) + (0x1000000 - (param & 0x8000)); int scalar = (param & 0x7FFF) + (0x1000000 - (param & 0x8000));
while (len > 0) { while (len > 0) {
int step = 1; int step = 1;
final int c0 = dst[shiftOffset] & 0xFF; final int c0 = (int) dst[shiftOffset] & 0xFF;
if (c0 < 0x80) { if (c0 < 0x80) {
/* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */ /* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
scalar += c0; scalar += c0;
@ -181,7 +182,7 @@ final class Transform {
} else if (c0 < 0xE0) { } else if (c0 < 0xE0) {
/* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */ /* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
if (len >= 2) { if (len >= 2) {
final byte c1 = dst[shiftOffset + 1]; final int c1 = (int) dst[shiftOffset + 1];
scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6); scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6);
dst[shiftOffset] = (byte) (0xC0 | ((scalar >> 6) & 0x1F)); dst[shiftOffset] = (byte) (0xC0 | ((scalar >> 6) & 0x1F));
dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | (scalar & 0x3F)); dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | (scalar & 0x3F));
@ -192,8 +193,8 @@ final class Transform {
} else if (c0 < 0xF0) { } else if (c0 < 0xF0) {
/* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */ /* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
if (len >= 3) { if (len >= 3) {
final byte c1 = dst[shiftOffset + 1]; final int c1 = (int) dst[shiftOffset + 1];
final byte c2 = dst[shiftOffset + 2]; final int c2 = (int) dst[shiftOffset + 2];
scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12); scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12);
dst[shiftOffset] = (byte) (0xE0 | ((scalar >> 12) & 0x0F)); dst[shiftOffset] = (byte) (0xE0 | ((scalar >> 12) & 0x0F));
dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | ((scalar >> 6) & 0x3F)); dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | ((scalar >> 6) & 0x3F));
@ -205,9 +206,9 @@ final class Transform {
} else if (c0 < 0xF8) { } else if (c0 < 0xF8) {
/* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */ /* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
if (len >= 4) { if (len >= 4) {
final byte c1 = dst[shiftOffset + 1]; final int c1 = (int) dst[shiftOffset + 1];
final byte c2 = dst[shiftOffset + 2]; final int c2 = (int) dst[shiftOffset + 2];
final byte c3 = dst[shiftOffset + 3]; final int c3 = (int) dst[shiftOffset + 3];
scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18); scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18);
dst[shiftOffset] = (byte) (0xF0 | ((scalar >> 18) & 0x07)); dst[shiftOffset] = (byte) (0xF0 | ((scalar >> 18) & 0x07));
dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | ((scalar >> 12) & 0x3F)); dst[shiftOffset + 1] = (byte) ((c1 & 0xC0) | ((scalar >> 12) & 0x3F));

View File

@ -6,7 +6,9 @@
package org.brotli.dec; package org.brotli.dec;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.Buffer; import java.nio.Buffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -74,11 +76,13 @@ final class Utils {
} }
} }
static InputStream makeEmptyInput() {
return new ByteArrayInputStream(new byte[0]);
}
static void closeInput(State s) throws IOException { static void closeInput(State s) throws IOException {
if (s.input != null) { s.input.close();
s.input.close(); s.input = makeEmptyInput();
s.input = null;
}
} }
static byte[] toUsAsciiBytes(String src) { static byte[] toUsAsciiBytes(String src) {

View File

@ -47,14 +47,16 @@ let makeBrotliDecode = () => {
function log2floor(i) { function log2floor(i) {
let /** @type {number} */ result = -1; let /** @type {number} */ result = -1;
let /** @type {number} */ step = 16; let /** @type {number} */ step = 16;
let /** @type {number} */ v = i;
while (step > 0) { while (step > 0) {
if ((i >>> step) !== 0) { let /** @type {number} */ next = v >>> step;
if (next !== 0) {
result += step; result += step;
i = i >>> step; v = next;
} }
step = step >> 1; step = step >> 1;
} }
return result + i; return result + v;
} }
/** /**
* @param {number} npostfix * @param {number} npostfix
@ -85,12 +87,12 @@ let makeBrotliDecode = () => {
* @return {void} * @return {void}
*/ */
function unpackCommandLookupTable(cmdLookup) { function unpackCommandLookupTable(cmdLookup) {
const /** @type {!Int16Array} */ insertLengthOffsets = new Int16Array(24); const /** @type {!Int32Array} */ insertLengthOffsets = new Int32Array(24);
const /** @type {!Int16Array} */ copyLengthOffsets = new Int16Array(24); const /** @type {!Int32Array} */ copyLengthOffsets = new Int32Array(24);
copyLengthOffsets[0] = 2; copyLengthOffsets[0] = 2;
for (let /** @type {number} */ i = 0; i < 23; ++i) { for (let /** @type {number} */ i = 0; i < 23; ++i) {
insertLengthOffsets[i + 1] = (insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i])); insertLengthOffsets[i + 1] = insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i]);
copyLengthOffsets[i + 1] = (copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i])); copyLengthOffsets[i + 1] = copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i]);
} }
for (let /** @type {number} */ cmdCode = 0; cmdCode < 704; ++cmdCode) { for (let /** @type {number} */ cmdCode = 0; cmdCode < 704; ++cmdCode) {
let /** @type {number} */ rangeIdx = cmdCode >>> 6; let /** @type {number} */ rangeIdx = cmdCode >>> 6;
@ -102,9 +104,9 @@ let makeBrotliDecode = () => {
const /** @type {number} */ insertCode = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7); const /** @type {number} */ insertCode = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7);
const /** @type {number} */ copyCode = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7); const /** @type {number} */ copyCode = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7);
const /** @type {number} */ copyLengthOffset = copyLengthOffsets[copyCode]; const /** @type {number} */ copyLengthOffset = copyLengthOffsets[copyCode];
const /** @type {number} */ distanceContext = distanceContextOffset + (copyLengthOffset > 4 ? 3 : copyLengthOffset - 2); const /** @type {number} */ distanceContext = distanceContextOffset + (copyLengthOffset > 4 ? 3 : (copyLengthOffset - 2));
const /** @type {number} */ index = cmdCode * 4; const /** @type {number} */ index = cmdCode * 4;
cmdLookup[index] = (INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8)); cmdLookup[index] = INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8);
cmdLookup[index + 1] = insertLengthOffsets[insertCode]; cmdLookup[index + 1] = insertLengthOffsets[insertCode];
cmdLookup[index + 2] = copyLengthOffsets[copyCode]; cmdLookup[index + 2] = copyLengthOffsets[copyCode];
cmdLookup[index + 3] = distanceContext; cmdLookup[index + 3] = distanceContext;
@ -220,7 +222,7 @@ let makeBrotliDecode = () => {
return; return;
} }
s.runningState = 11; s.runningState = 11;
s.input = null; s.input = new InputStream(new Int8Array(0));
} }
/** /**
* @param {!State} s * @param {!State} s
@ -267,7 +269,7 @@ let makeBrotliDecode = () => {
if (sizeBytes === 0) { if (sizeBytes === 0) {
return; return;
} }
for (let /** @type {number} */ i = 0; i < sizeBytes; i++) { for (let /** @type {number} */ i = 0; i < sizeBytes; ++i) {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
@ -276,10 +278,10 @@ let makeBrotliDecode = () => {
if (bits === 0 && i + 1 === sizeBytes && sizeBytes > 1) { if (bits === 0 && i + 1 === sizeBytes && sizeBytes > 1) {
throw new Error("Exuberant nibble"); throw new Error("Exuberant nibble");
} }
s.metaBlockLength |= bits << (i * 8); s.metaBlockLength += bits << (i * 8);
} }
} else { } else {
for (let /** @type {number} */ i = 0; i < sizeNibbles; i++) { for (let /** @type {number} */ i = 0; i < sizeNibbles; ++i) {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
@ -288,7 +290,7 @@ let makeBrotliDecode = () => {
if (bits === 0 && i + 1 === sizeNibbles && sizeNibbles > 4) { if (bits === 0 && i + 1 === sizeNibbles && sizeNibbles > 4) {
throw new Error("Exuberant nibble"); throw new Error("Exuberant nibble");
} }
s.metaBlockLength |= bits << (i * 4); s.metaBlockLength += bits << (i * 4);
} }
} }
s.metaBlockLength++; s.metaBlockLength++;
@ -304,8 +306,8 @@ let makeBrotliDecode = () => {
*/ */
function readSymbol(tableGroup, tableIdx, s) { function readSymbol(tableGroup, tableIdx, s) {
let /** @type {number} */ offset = tableGroup[tableIdx]; let /** @type {number} */ offset = tableGroup[tableIdx];
const /** @type {number} */ val = (s.accumulator32 >>> s.bitOffset); const /** @type {number} */ v = s.accumulator32 >>> s.bitOffset;
offset += val & 0xFF; offset += v & 0xFF;
const /** @type {number} */ bits = tableGroup[offset] >> 16; const /** @type {number} */ bits = tableGroup[offset] >> 16;
const /** @type {number} */ sym = tableGroup[offset] & 0xFFFF; const /** @type {number} */ sym = tableGroup[offset] & 0xFFFF;
if (bits <= 8) { if (bits <= 8) {
@ -314,8 +316,8 @@ let makeBrotliDecode = () => {
} }
offset += sym; offset += sym;
const /** @type {number} */ mask = (1 << bits) - 1; const /** @type {number} */ mask = (1 << bits) - 1;
offset += (val & mask) >>> 8; offset += (v & mask) >>> 8;
s.bitOffset += ((tableGroup[offset] >> 16) + 8); s.bitOffset += (tableGroup[offset] >> 16) + 8;
return tableGroup[offset] & 0xFFFF; return tableGroup[offset] & 0xFFFF;
} }
/** /**
@ -343,9 +345,11 @@ let makeBrotliDecode = () => {
* @return {void} * @return {void}
*/ */
function moveToFront(v, index) { function moveToFront(v, index) {
const /** @type {number} */ value = v[index]; let /** @type {number} */ i = index;
for (; index > 0; index--) { const /** @type {number} */ value = v[i];
v[index] = v[index - 1]; while (i > 0) {
v[i] = v[i - 1];
i--;
} }
v[0] = value; v[0] = value;
} }
@ -356,10 +360,10 @@ let makeBrotliDecode = () => {
*/ */
function inverseMoveToFrontTransform(v, vLen) { function inverseMoveToFrontTransform(v, vLen) {
const /** @type {!Int32Array} */ mtf = new Int32Array(256); const /** @type {!Int32Array} */ mtf = new Int32Array(256);
for (let /** @type {number} */ i = 0; i < 256; i++) { for (let /** @type {number} */ i = 0; i < 256; ++i) {
mtf[i] = i; mtf[i] = i;
} }
for (let /** @type {number} */ i = 0; i < vLen; i++) { for (let /** @type {number} */ i = 0; i < vLen; ++i) {
const /** @type {number} */ index = v[i] & 0xFF; const /** @type {number} */ index = v[i] & 0xFF;
v[i] = mtf[index]; v[i] = mtf[index];
if (index !== 0) { if (index !== 0) {
@ -414,7 +418,7 @@ let makeBrotliDecode = () => {
const /** @type {number} */ oldRepeat = repeat; const /** @type {number} */ oldRepeat = repeat;
if (repeat > 0) { if (repeat > 0) {
repeat -= 2; repeat -= 2;
repeat <<= extraBits; repeat = repeat << extraBits;
} }
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
@ -425,7 +429,7 @@ let makeBrotliDecode = () => {
if (symbol + repeatDelta > numSymbols) { if (symbol + repeatDelta > numSymbols) {
throw new Error("symbol + repeatDelta > numSymbols"); throw new Error("symbol + repeatDelta > numSymbols");
} }
for (let /** @type {number} */ i = 0; i < repeatDelta; i++) { for (let /** @type {number} */ i = 0; i < repeatDelta; ++i) {
codeLengths[symbol++] = repeatCodeLen; codeLengths[symbol++] = repeatCodeLen;
} }
if (repeatCodeLen !== 0) { if (repeatCodeLen !== 0) {
@ -465,7 +469,7 @@ let makeBrotliDecode = () => {
const /** @type {!Int32Array} */ symbols = new Int32Array(4); const /** @type {!Int32Array} */ symbols = new Int32Array(4);
const /** @type {number} */ maxBits = 1 + log2floor(alphabetSizeMax - 1); const /** @type {number} */ maxBits = 1 + log2floor(alphabetSizeMax - 1);
const /** @type {number} */ numSymbols = readFewBits(s, 2) + 1; const /** @type {number} */ numSymbols = readFewBits(s, 2) + 1;
for (let /** @type {number} */ i = 0; i < numSymbols; i++) { for (let /** @type {number} */ i = 0; i < numSymbols; ++i) {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
@ -524,7 +528,7 @@ let makeBrotliDecode = () => {
const /** @type {!Int32Array} */ codeLengthCodeLengths = new Int32Array(18); const /** @type {!Int32Array} */ codeLengthCodeLengths = new Int32Array(18);
let /** @type {number} */ space = 32; let /** @type {number} */ space = 32;
let /** @type {number} */ numCodes = 0; let /** @type {number} */ numCodes = 0;
for (let /** @type {number} */ i = skip; i < 18 && space > 0; i++) { for (let /** @type {number} */ i = skip; i < 18; ++i) {
const /** @type {number} */ codeLenIdx = CODE_LENGTH_CODE_ORDER[i]; const /** @type {number} */ codeLenIdx = CODE_LENGTH_CODE_ORDER[i];
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
@ -535,8 +539,10 @@ let makeBrotliDecode = () => {
const /** @type {number} */ v = FIXED_TABLE[p] & 0xFFFF; const /** @type {number} */ v = FIXED_TABLE[p] & 0xFFFF;
codeLengthCodeLengths[codeLenIdx] = v; codeLengthCodeLengths[codeLenIdx] = v;
if (v !== 0) { if (v !== 0) {
space -= (32 >> v); space -= 32 >> v;
numCodes++; numCodes++;
if (space <= 0)
break;
} }
} }
if (space !== 0 && numCodes !== 1) { if (space !== 0 && numCodes !== 1) {
@ -597,7 +603,8 @@ let makeBrotliDecode = () => {
const /** @type {!Int32Array} */ table = new Int32Array(tableSize + 1); const /** @type {!Int32Array} */ table = new Int32Array(tableSize + 1);
const /** @type {number} */ tableIdx = table.length - 1; const /** @type {number} */ tableIdx = table.length - 1;
readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s); readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s);
for (let /** @type {number} */ i = 0; i < contextMapSize; ) { let /** @type {number} */ i = 0;
while (i < contextMapSize) {
if (s.halfOffset > 2030) { if (s.halfOffset > 2030) {
doReadMoreInput(s); doReadMoreInput(s);
} }
@ -624,7 +631,7 @@ let makeBrotliDecode = () => {
reps--; reps--;
} }
} else { } else {
contextMap[i] = (code - maxRunLengthPrefix); contextMap[i] = code - maxRunLengthPrefix;
i++; i++;
} }
} }
@ -704,7 +711,7 @@ let makeBrotliDecode = () => {
if (newSize > s.expectedTotalSize) { if (newSize > s.expectedTotalSize) {
const /** @type {number} */ minimalNewSize = s.expectedTotalSize; const /** @type {number} */ minimalNewSize = s.expectedTotalSize;
while ((newSize >> 1) > minimalNewSize) { while ((newSize >> 1) > minimalNewSize) {
newSize >>= 1; newSize = newSize >> 1;
} }
if ((s.inputEnd === 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) { if ((s.inputEnd === 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) {
newSize = 16384; newSize = 16384;
@ -715,8 +722,9 @@ let makeBrotliDecode = () => {
} }
const /** @type {number} */ ringBufferSizeWithSlack = newSize + 37; const /** @type {number} */ ringBufferSizeWithSlack = newSize + 37;
const /** @type {!Int8Array} */ newBuffer = new Int8Array(ringBufferSizeWithSlack); const /** @type {!Int8Array} */ newBuffer = new Int8Array(ringBufferSizeWithSlack);
if (s.ringBuffer.length !== 0) { const /** @type {!Int8Array} */ oldBuffer = s.ringBuffer;
newBuffer.set(s.ringBuffer.subarray(0, s.ringBufferSize), 0); if (oldBuffer.length !== 0) {
newBuffer.set(oldBuffer.subarray(0, s.ringBufferSize), 0);
} }
s.ringBuffer = newBuffer; s.ringBuffer = newBuffer;
s.ringBufferSize = newSize; s.ringBufferSize = newSize;
@ -830,23 +838,26 @@ let makeBrotliDecode = () => {
s.distancePostfixBits = readFewBits(s, 2); s.distancePostfixBits = readFewBits(s, 2);
s.numDirectDistanceCodes = readFewBits(s, 4) << s.distancePostfixBits; s.numDirectDistanceCodes = readFewBits(s, 4) << s.distancePostfixBits;
s.contextModes = new Int8Array(s.numLiteralBlockTypes); s.contextModes = new Int8Array(s.numLiteralBlockTypes);
for (let /** @type {number} */ i = 0; i < s.numLiteralBlockTypes; ) { let /** @type {number} */ i = 0;
while (i < s.numLiteralBlockTypes) {
const /** @type {number} */ limit = Math.min(i + 96, s.numLiteralBlockTypes); const /** @type {number} */ limit = Math.min(i + 96, s.numLiteralBlockTypes);
for (; i < limit; ++i) { while (i < limit) {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
} }
s.contextModes[i] = readFewBits(s, 2); s.contextModes[i] = readFewBits(s, 2);
i++;
} }
if (s.halfOffset > 2030) { if (s.halfOffset > 2030) {
doReadMoreInput(s); doReadMoreInput(s);
} }
} }
s.contextMap = new Int8Array(s.numLiteralBlockTypes << 6); const /** @type {number} */ contextMapLength = s.numLiteralBlockTypes << 6;
const /** @type {number} */ numLiteralTrees = decodeContextMap(s.numLiteralBlockTypes << 6, s.contextMap, s); s.contextMap = new Int8Array(contextMapLength);
const /** @type {number} */ numLiteralTrees = decodeContextMap(contextMapLength, s.contextMap, s);
s.trivialLiteralContext = 1; s.trivialLiteralContext = 1;
for (let /** @type {number} */ j = 0; j < s.numLiteralBlockTypes << 6; j++) { for (let /** @type {number} */ j = 0; j < contextMapLength; ++j) {
if (s.contextMap[j] !== j >> 6) { if (s.contextMap[j] !== j >> 6) {
s.trivialLiteralContext = 0; s.trivialLiteralContext = 0;
break; break;
@ -1264,7 +1275,8 @@ let makeBrotliDecode = () => {
const /** @type {number} */ dstEnd = dst + copyLength; const /** @type {number} */ dstEnd = dst + copyLength;
if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) { if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) {
if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) { if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) {
for (let /** @type {number} */ k = 0; k < copyLength; k += 4) { const /** @type {number} */ numQuads = (copyLength + 3) >> 2;
for (let /** @type {number} */ k = 0; k < numQuads; ++k) {
ringBuffer[dst++] = ringBuffer[src++]; ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++]; ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++]; ringBuffer[dst++] = ringBuffer[src++];
@ -1277,7 +1289,7 @@ let makeBrotliDecode = () => {
s.metaBlockLength -= copyLength; s.metaBlockLength -= copyLength;
s.pos += copyLength; s.pos += copyLength;
} else { } else {
for (; s.j < s.copyLength; ) { while (s.j < s.copyLength) {
ringBuffer[s.pos] = ringBuffer[(s.pos - s.distance) & ringBufferMask]; ringBuffer[s.pos] = ringBuffer[(s.pos - s.distance) & ringBufferMask];
s.metaBlockLength--; s.metaBlockLength--;
s.pos++; s.pos++;
@ -1336,7 +1348,7 @@ let makeBrotliDecode = () => {
if (s.pos > s.ringBufferSize) { if (s.pos > s.ringBufferSize) {
ringBuffer.copyWithin(0, s.ringBufferSize, s.pos); ringBuffer.copyWithin(0, s.ringBufferSize, s.pos);
} }
s.pos &= ringBufferMask; s.pos = s.pos & ringBufferMask;
s.ringBufferBytesWritten = 0; s.ringBufferBytesWritten = 0;
} }
s.runningState = s.nextRunningState; s.runningState = s.nextRunningState;
@ -1413,12 +1425,12 @@ let makeBrotliDecode = () => {
* @param {number} dstOffset * @param {number} dstOffset
* @param {!Int8Array} src * @param {!Int8Array} src
* @param {number} srcOffset * @param {number} srcOffset
* @param {number} len * @param {number} wordLen
* @param {!Transforms} transforms * @param {!Transforms} transforms
* @param {number} transformIndex * @param {number} transformIndex
* @return {number} * @return {number}
*/ */
function transformDictionaryWord(dst, dstOffset, src, srcOffset, len, transforms, transformIndex) { function transformDictionaryWord(dst, dstOffset, src, srcOffset, wordLen, transforms, transformIndex) {
let /** @type {number} */ offset = dstOffset; let /** @type {number} */ offset = dstOffset;
const /** @type {!Int32Array} */ triplets = transforms.triplets; const /** @type {!Int32Array} */ triplets = transforms.triplets;
const /** @type {!Int8Array} */ prefixSuffixStorage = transforms.prefixSuffixStorage; const /** @type {!Int8Array} */ prefixSuffixStorage = transforms.prefixSuffixStorage;
@ -1442,15 +1454,16 @@ let makeBrotliDecode = () => {
while (prefix !== prefixEnd) { while (prefix !== prefixEnd) {
dst[offset++] = prefixSuffixStorage[prefix++]; dst[offset++] = prefixSuffixStorage[prefix++];
} }
let /** @type {number} */ len = wordLen;
if (omitFirst > len) { if (omitFirst > len) {
omitFirst = len; omitFirst = len;
} }
srcOffset += omitFirst; let /** @type {number} */ dictOffset = srcOffset + omitFirst;
len -= omitFirst; len -= omitFirst;
len -= omitLast; len -= omitLast;
let /** @type {number} */ i = len; let /** @type {number} */ i = len;
while (i > 0) { while (i > 0) {
dst[offset++] = src[srcOffset++]; dst[offset++] = src[dictOffset++];
i--; i--;
} }
if (transformType === 10 || transformType === 11) { if (transformType === 10 || transformType === 11) {
@ -1462,16 +1475,16 @@ let makeBrotliDecode = () => {
const /** @type {number} */ c0 = dst[uppercaseOffset] & 0xFF; const /** @type {number} */ c0 = dst[uppercaseOffset] & 0xFF;
if (c0 < 0xC0) { if (c0 < 0xC0) {
if (c0 >= 97 && c0 <= 122) { if (c0 >= 97 && c0 <= 122) {
dst[uppercaseOffset] ^= 32; dst[uppercaseOffset] = dst[uppercaseOffset] ^ 32;
} }
uppercaseOffset += 1; uppercaseOffset += 1;
len -= 1; len -= 1;
} else if (c0 < 0xE0) { } else if (c0 < 0xE0) {
dst[uppercaseOffset + 1] ^= 32; dst[uppercaseOffset + 1] = dst[uppercaseOffset + 1] ^ 32;
uppercaseOffset += 2; uppercaseOffset += 2;
len -= 2; len -= 2;
} else { } else {
dst[uppercaseOffset + 2] ^= 5; dst[uppercaseOffset + 2] = dst[uppercaseOffset + 2] ^ 5;
uppercaseOffset += 3; uppercaseOffset += 3;
len -= 3; len -= 3;
} }
@ -1485,14 +1498,14 @@ let makeBrotliDecode = () => {
const /** @type {number} */ c0 = dst[shiftOffset] & 0xFF; const /** @type {number} */ c0 = dst[shiftOffset] & 0xFF;
if (c0 < 0x80) { if (c0 < 0x80) {
scalar += c0; scalar += c0;
dst[shiftOffset] = (scalar & 0x7F); dst[shiftOffset] = scalar & 0x7F;
} else if (c0 < 0xC0) { } else if (c0 < 0xC0) {
} else if (c0 < 0xE0) { } else if (c0 < 0xE0) {
if (len >= 2) { if (len >= 2) {
const /** @type {number} */ c1 = dst[shiftOffset + 1]; const /** @type {number} */ c1 = dst[shiftOffset + 1];
scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6); scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6);
dst[shiftOffset] = (0xC0 | ((scalar >> 6) & 0x1F)); dst[shiftOffset] = 0xC0 | ((scalar >> 6) & 0x1F);
dst[shiftOffset + 1] = ((c1 & 0xC0) | (scalar & 0x3F)); dst[shiftOffset + 1] = (c1 & 0xC0) | (scalar & 0x3F);
step = 2; step = 2;
} else { } else {
step = len; step = len;
@ -1502,9 +1515,9 @@ let makeBrotliDecode = () => {
const /** @type {number} */ c1 = dst[shiftOffset + 1]; const /** @type {number} */ c1 = dst[shiftOffset + 1];
const /** @type {number} */ c2 = dst[shiftOffset + 2]; const /** @type {number} */ c2 = dst[shiftOffset + 2];
scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12); scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12);
dst[shiftOffset] = (0xE0 | ((scalar >> 12) & 0x0F)); dst[shiftOffset] = 0xE0 | ((scalar >> 12) & 0x0F);
dst[shiftOffset + 1] = ((c1 & 0xC0) | ((scalar >> 6) & 0x3F)); dst[shiftOffset + 1] = (c1 & 0xC0) | ((scalar >> 6) & 0x3F);
dst[shiftOffset + 2] = ((c2 & 0xC0) | (scalar & 0x3F)); dst[shiftOffset + 2] = (c2 & 0xC0) | (scalar & 0x3F);
step = 3; step = 3;
} else { } else {
step = len; step = len;
@ -1515,10 +1528,10 @@ let makeBrotliDecode = () => {
const /** @type {number} */ c2 = dst[shiftOffset + 2]; const /** @type {number} */ c2 = dst[shiftOffset + 2];
const /** @type {number} */ c3 = dst[shiftOffset + 3]; const /** @type {number} */ c3 = dst[shiftOffset + 3];
scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18); scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18);
dst[shiftOffset] = (0xF0 | ((scalar >> 18) & 0x07)); dst[shiftOffset] = 0xF0 | ((scalar >> 18) & 0x07);
dst[shiftOffset + 1] = ((c1 & 0xC0) | ((scalar >> 12) & 0x3F)); dst[shiftOffset + 1] = (c1 & 0xC0) | ((scalar >> 12) & 0x3F);
dst[shiftOffset + 2] = ((c2 & 0xC0) | ((scalar >> 6) & 0x3F)); dst[shiftOffset + 2] = (c2 & 0xC0) | ((scalar >> 6) & 0x3F);
dst[shiftOffset + 3] = ((c3 & 0xC0) | (scalar & 0x3F)); dst[shiftOffset + 3] = (c3 & 0xC0) | (scalar & 0x3F);
step = 4; step = 4;
} else { } else {
step = len; step = len;
@ -1545,7 +1558,7 @@ let makeBrotliDecode = () => {
function getNextKey(key, len) { function getNextKey(key, len) {
let /** @type {number} */ step = 1 << (len - 1); let /** @type {number} */ step = 1 << (len - 1);
while ((key & step) !== 0) { while ((key & step) !== 0) {
step >>= 1; step = step >> 1;
} }
return (key & (step - 1)) + step; return (key & (step - 1)) + step;
} }
@ -1558,10 +1571,11 @@ let makeBrotliDecode = () => {
* @return {void} * @return {void}
*/ */
function replicateValue(table, offset, step, end, item) { function replicateValue(table, offset, step, end, item) {
let /** @type {number} */ pos = end;
do { do {
end -= step; pos -= step;
table[offset + end] = item; table[offset + pos] = item;
} while (end > 0); } while (pos > 0);
} }
/** /**
* @param {!Int32Array} count * @param {!Int32Array} count
@ -1570,16 +1584,17 @@ let makeBrotliDecode = () => {
* @return {number} * @return {number}
*/ */
function nextTableBitSize(count, len, rootBits) { function nextTableBitSize(count, len, rootBits) {
let /** @type {number} */ left = 1 << (len - rootBits); let /** @type {number} */ bits = len;
while (len < 15) { let /** @type {number} */ left = 1 << (bits - rootBits);
left -= count[len]; while (bits < 15) {
left -= count[bits];
if (left <= 0) { if (left <= 0) {
break; break;
} }
len++; bits++;
left <<= 1; left = left << 1;
} }
return len - rootBits; return bits - rootBits;
} }
/** /**
* @param {!Int32Array} tableGroup * @param {!Int32Array} tableGroup
@ -1591,45 +1606,48 @@ let makeBrotliDecode = () => {
*/ */
function buildHuffmanTable(tableGroup, tableIdx, rootBits, codeLengths, codeLengthsSize) { function buildHuffmanTable(tableGroup, tableIdx, rootBits, codeLengths, codeLengthsSize) {
const /** @type {number} */ tableOffset = tableGroup[tableIdx]; const /** @type {number} */ tableOffset = tableGroup[tableIdx];
let /** @type {number} */ key;
const /** @type {!Int32Array} */ sorted = new Int32Array(codeLengthsSize); const /** @type {!Int32Array} */ sorted = new Int32Array(codeLengthsSize);
const /** @type {!Int32Array} */ count = new Int32Array(16); const /** @type {!Int32Array} */ count = new Int32Array(16);
const /** @type {!Int32Array} */ offset = new Int32Array(16); const /** @type {!Int32Array} */ offset = new Int32Array(16);
let /** @type {number} */ symbol; for (let /** @type {number} */ sym = 0; sym < codeLengthsSize; ++sym) {
for (symbol = 0; symbol < codeLengthsSize; symbol++) { count[codeLengths[sym]]++;
count[codeLengths[symbol]]++;
} }
offset[1] = 0; offset[1] = 0;
for (let /** @type {number} */ len = 1; len < 15; len++) { for (let /** @type {number} */ len = 1; len < 15; ++len) {
offset[len + 1] = offset[len] + count[len]; offset[len + 1] = offset[len] + count[len];
} }
for (symbol = 0; symbol < codeLengthsSize; symbol++) { for (let /** @type {number} */ sym = 0; sym < codeLengthsSize; ++sym) {
if (codeLengths[symbol] !== 0) { if (codeLengths[sym] !== 0) {
sorted[offset[codeLengths[symbol]]++] = symbol; sorted[offset[codeLengths[sym]]++] = sym;
} }
} }
let /** @type {number} */ tableBits = rootBits; let /** @type {number} */ tableBits = rootBits;
let /** @type {number} */ tableSize = 1 << tableBits; let /** @type {number} */ tableSize = 1 << tableBits;
let /** @type {number} */ totalSize = tableSize; let /** @type {number} */ totalSize = tableSize;
if (offset[15] === 1) { if (offset[15] === 1) {
for (key = 0; key < totalSize; key++) { for (let /** @type {number} */ k = 0; k < totalSize; ++k) {
tableGroup[tableOffset + key] = sorted[0]; tableGroup[tableOffset + k] = sorted[0];
} }
return totalSize; return totalSize;
} }
key = 0; let /** @type {number} */ key = 0;
symbol = 0; let /** @type {number} */ symbol = 0;
for (let /** @type {number} */ len = 1, /** @type {number} */ step = 2; len <= rootBits; len++, step <<= 1) { let /** @type {number} */ step = 1;
for (; count[len] > 0; count[len]--) { for (let /** @type {number} */ len = 1; len <= rootBits; ++len) {
step = step << 1;
while (count[len] > 0) {
replicateValue(tableGroup, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]); replicateValue(tableGroup, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
key = getNextKey(key, len); key = getNextKey(key, len);
count[len]--;
} }
} }
const /** @type {number} */ mask = totalSize - 1; const /** @type {number} */ mask = totalSize - 1;
let /** @type {number} */ low = -1; let /** @type {number} */ low = -1;
let /** @type {number} */ currentOffset = tableOffset; let /** @type {number} */ currentOffset = tableOffset;
for (let /** @type {number} */ len = rootBits + 1, /** @type {number} */ step = 2; len <= 15; len++, step <<= 1) { step = 1;
for (; count[len] > 0; count[len]--) { for (let /** @type {number} */ len = rootBits + 1; len <= 15; ++len) {
step = step << 1;
while (count[len] > 0) {
if ((key & mask) !== low) { if ((key & mask) !== low) {
currentOffset += tableSize; currentOffset += tableSize;
tableBits = nextTableBitSize(count, len, rootBits); tableBits = nextTableBitSize(count, len, rootBits);
@ -1640,6 +1658,7 @@ let makeBrotliDecode = () => {
} }
replicateValue(tableGroup, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]); replicateValue(tableGroup, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
key = getNextKey(key, len); key = getNextKey(key, len);
count[len]--;
} }
} }
return totalSize; return totalSize;
@ -1696,9 +1715,9 @@ let makeBrotliDecode = () => {
* @return {number} * @return {number}
*/ */
function readFewBits(s, n) { function readFewBits(s, n) {
const /** @type {number} */ val = (s.accumulator32 >>> s.bitOffset) & ((1 << n) - 1); const /** @type {number} */ v = (s.accumulator32 >>> s.bitOffset) & ((1 << n) - 1);
s.bitOffset += n; s.bitOffset += n;
return val; return v;
} }
/** /**
* @param {!State} s * @param {!State} s
@ -1779,27 +1798,29 @@ let makeBrotliDecode = () => {
* @return {void} * @return {void}
*/ */
function copyRawBytes(s, data, offset, length) { function copyRawBytes(s, data, offset, length) {
let /** @type {number} */ pos = offset;
let /** @type {number} */ len = length;
if ((s.bitOffset & 7) !== 0) { if ((s.bitOffset & 7) !== 0) {
throw new Error("Unaligned copyBytes"); throw new Error("Unaligned copyBytes");
} }
while ((s.bitOffset !== 32) && (length !== 0)) { while ((s.bitOffset !== 32) && (len !== 0)) {
data[offset++] = (s.accumulator32 >>> s.bitOffset); data[pos++] = s.accumulator32 >>> s.bitOffset;
s.bitOffset += 8; s.bitOffset += 8;
length--; len--;
} }
if (length === 0) { if (len === 0) {
return; return;
} }
const /** @type {number} */ copyNibbles = Math.min(halfAvailable(s), length >> 1); const /** @type {number} */ copyNibbles = Math.min(halfAvailable(s), len >> 1);
if (copyNibbles > 0) { if (copyNibbles > 0) {
const /** @type {number} */ readOffset = s.halfOffset << 1; const /** @type {number} */ readOffset = s.halfOffset << 1;
const /** @type {number} */ delta = copyNibbles << 1; const /** @type {number} */ delta = copyNibbles << 1;
data.set(s.byteBuffer.subarray(readOffset, readOffset + delta), offset); data.set(s.byteBuffer.subarray(readOffset, readOffset + delta), pos);
offset += delta; pos += delta;
length -= delta; len -= delta;
s.halfOffset += copyNibbles; s.halfOffset += copyNibbles;
} }
if (length === 0) { if (len === 0) {
return; return;
} }
if (halfAvailable(s) > 0) { if (halfAvailable(s) > 0) {
@ -1807,21 +1828,21 @@ let makeBrotliDecode = () => {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
} }
while (length !== 0) { while (len !== 0) {
data[offset++] = (s.accumulator32 >>> s.bitOffset); data[pos++] = s.accumulator32 >>> s.bitOffset;
s.bitOffset += 8; s.bitOffset += 8;
length--; len--;
} }
checkHealth(s, 0); checkHealth(s, 0);
return; return;
} }
while (length > 0) { while (len > 0) {
const /** @type {number} */ len = readInput(s, data, offset, length); const /** @type {number} */ chunkLen = readInput(s, data, pos, len);
if (len === -1) { if (chunkLen === -1) {
throw new Error("Unexpected end of input"); throw new Error("Unexpected end of input");
} }
offset += len; pos += chunkLen;
length -= len; len -= chunkLen;
} }
} }
/** /**
@ -1834,7 +1855,7 @@ let makeBrotliDecode = () => {
const /** @type {number} */ halfLen = byteLen >> 1; const /** @type {number} */ halfLen = byteLen >> 1;
const /** @type {!Int16Array} */ shortBuffer = s.shortBuffer; const /** @type {!Int16Array} */ shortBuffer = s.shortBuffer;
for (let /** @type {number} */ i = 0; i < halfLen; ++i) { for (let /** @type {number} */ i = 0; i < halfLen; ++i) {
shortBuffer[i] = ((byteBuffer[i * 2] & 0xFF) | ((byteBuffer[(i * 2) + 1] & 0xFF) << 8)); shortBuffer[i] = (byteBuffer[i * 2] & 0xFF) | ((byteBuffer[(i * 2) + 1] & 0xFF) << 8);
} }
} }
@ -2028,8 +2049,8 @@ let makeBrotliDecode = () => {
this.cdBlockBits = 0; this.cdBlockBits = 0;
/** @type {!Int8Array} */ /** @type {!Int8Array} */
this.cdBlockMap = new Int8Array(0); this.cdBlockMap = new Int8Array(0);
/** @type {!InputStream|null} */ /** @type {!InputStream} */
this.input = null; this.input = new InputStream(new Int8Array(0));
this.ringBuffer = new Int8Array(0); this.ringBuffer = new Int8Array(0);
this.rings = new Int32Array(10); this.rings = new Int32Array(10);
this.rings[0] = 16; this.rings[0] = 16;
@ -2100,16 +2121,16 @@ let makeBrotliDecode = () => {
throw new Error("Corrupted brotli dictionary"); throw new Error("Corrupted brotli dictionary");
} }
let /** @type {number} */ offset = 0; let /** @type {number} */ offset = 0;
const /** @type {number} */ n = skipFlip.length; const /** @type {number} */ n = skipFlip.length >> 1;
for (let /** @type {number} */ i = 0; i < n; i += 2) { for (let /** @type {number} */ i = 0; i < n; ++i) {
const /** @type {number} */ skip = skipFlip.charCodeAt(i) - 36; const /** @type {number} */ skip = skipFlip.charCodeAt(2 * i) - 36;
const /** @type {number} */ flip = skipFlip.charCodeAt(i + 1) - 36; const /** @type {number} */ flip = skipFlip.charCodeAt(2 * i + 1) - 36;
for (let /** @type {number} */ j = 0; j < skip; ++j) { for (let /** @type {number} */ j = 0; j < skip; ++j) {
dict[offset] ^= 3; dict[offset] = dict[offset] ^ 3;
offset++; offset++;
} }
for (let /** @type {number} */ j = 0; j < flip; ++j) { for (let /** @type {number} */ j = 0; j < flip; ++j) {
dict[offset] ^= 236; dict[offset] = dict[offset] ^ 236;
offset++; offset++;
} }
} }
@ -2158,8 +2179,8 @@ let makeBrotliDecode = () => {
return -1; return -1;
} }
const /** @type {!InputStream} */ src = s.input; const /** @type {!InputStream} */ src = s.input;
let /** @type {number} */ end = Math.min(src.offset + length, src.data.length); const /** @type {number} */ end = Math.min(src.offset + length, src.data.length);
let /** @type {number} */ bytesRead = end - src.offset; const /** @type {number} */ bytesRead = end - src.offset;
dst.set(src.data.subarray(src.offset, end), offset); dst.set(src.data.subarray(src.offset, end), offset);
src.offset += bytesRead; src.offset += bytesRead;
return bytesRead; return bytesRead;
@ -2169,8 +2190,8 @@ let makeBrotliDecode = () => {
* @return {!Int8Array} * @return {!Int8Array}
*/ */
function toUsAsciiBytes(src) { function toUsAsciiBytes(src) {
let /** @type {number} */ n = src.length; const /** @type {number} */ n = src.length;
let /** @type {!Int8Array} */ result = new Int8Array(n); const /** @type {!Int8Array} */ result = new Int8Array(n);
for (let /** @type {number} */ i = 0; i < n; ++i) { for (let /** @type {number} */ i = 0; i < n; ++i) {
result[i] = src.charCodeAt(i); result[i] = src.charCodeAt(i);
} }

2
js/decode.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -25,14 +25,16 @@ const CMD_LOOKUP = new Int16Array(2816);
function log2floor(i: number): number { function log2floor(i: number): number {
let result: number = -1; let result: number = -1;
let step = 16; let step = 16;
let v: number = i;
while (step > 0) { while (step > 0) {
if ((i >>> step) !== 0) { let next: number = v >>> step;
if (next !== 0) {
result += step; result += step;
i = i >>> step; v = next;
} }
step = step >> 1; step = step >> 1;
} }
return result + i; return result + v;
} }
function calculateDistanceAlphabetSize(npostfix: number, ndirect: number, maxndistbits: number): number { function calculateDistanceAlphabetSize(npostfix: number, ndirect: number, maxndistbits: number): number {
return 16 + ndirect + 2 * (maxndistbits << npostfix); return 16 + ndirect + 2 * (maxndistbits << npostfix);
@ -47,12 +49,12 @@ function calculateDistanceAlphabetLimit(maxDistance: number, npostfix: number, n
return ((group - 1) << npostfix) + (1 << npostfix) + ndirect + 16; return ((group - 1) << npostfix) + (1 << npostfix) + ndirect + 16;
} }
function unpackCommandLookupTable(cmdLookup: Int16Array): void { function unpackCommandLookupTable(cmdLookup: Int16Array): void {
const insertLengthOffsets = new Int16Array(24); const insertLengthOffsets = new Int32Array(24);
const copyLengthOffsets = new Int16Array(24); const copyLengthOffsets = new Int32Array(24);
copyLengthOffsets[0] = 2; copyLengthOffsets[0] = 2;
for (let i = 0; i < 23; ++i) { for (let i = 0; i < 23; ++i) {
insertLengthOffsets[i + 1] = (insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i])); insertLengthOffsets[i + 1] = insertLengthOffsets[i] + (1 << INSERT_LENGTH_N_BITS[i]);
copyLengthOffsets[i + 1] = (copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i])); copyLengthOffsets[i + 1] = copyLengthOffsets[i] + (1 << COPY_LENGTH_N_BITS[i]);
} }
for (let cmdCode = 0; cmdCode < 704; ++cmdCode) { for (let cmdCode = 0; cmdCode < 704; ++cmdCode) {
let rangeIdx: number = cmdCode >>> 6; let rangeIdx: number = cmdCode >>> 6;
@ -64,9 +66,9 @@ function unpackCommandLookupTable(cmdLookup: Int16Array): void {
const insertCode: number = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7); const insertCode: number = (((0x29850 >>> (rangeIdx * 2)) & 0x3) << 3) | ((cmdCode >>> 3) & 7);
const copyCode: number = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7); const copyCode: number = (((0x26244 >>> (rangeIdx * 2)) & 0x3) << 3) | (cmdCode & 7);
const copyLengthOffset: number = copyLengthOffsets[copyCode]; const copyLengthOffset: number = copyLengthOffsets[copyCode];
const distanceContext: number = distanceContextOffset + (copyLengthOffset > 4 ? 3 : copyLengthOffset - 2); const distanceContext: number = distanceContextOffset + (copyLengthOffset > 4 ? 3 : (copyLengthOffset - 2));
const index: number = cmdCode * 4; const index: number = cmdCode * 4;
cmdLookup[index] = (INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8)); cmdLookup[index] = INSERT_LENGTH_N_BITS[insertCode] | (COPY_LENGTH_N_BITS[copyCode] << 8);
cmdLookup[index + 1] = insertLengthOffsets[insertCode]; cmdLookup[index + 1] = insertLengthOffsets[insertCode];
cmdLookup[index + 2] = copyLengthOffsets[copyCode]; cmdLookup[index + 2] = copyLengthOffsets[copyCode];
cmdLookup[index + 3] = distanceContext; cmdLookup[index + 3] = distanceContext;
@ -157,7 +159,7 @@ function close(s: State): void {
return; return;
} }
s.runningState = 11; s.runningState = 11;
s.input = null; s.input = new InputStream(new Int8Array(0));
} }
function decodeVarLenUnsignedByte(s: State): number { function decodeVarLenUnsignedByte(s: State): number {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
@ -196,7 +198,7 @@ function decodeMetaBlockLength(s: State): void {
if (sizeBytes === 0) { if (sizeBytes === 0) {
return; return;
} }
for (let i = 0; i < sizeBytes; i++) { for (let i = 0; i < sizeBytes; ++i) {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
@ -205,10 +207,10 @@ function decodeMetaBlockLength(s: State): void {
if (bits === 0 && i + 1 === sizeBytes && sizeBytes > 1) { if (bits === 0 && i + 1 === sizeBytes && sizeBytes > 1) {
throw new Error("Exuberant nibble"); throw new Error("Exuberant nibble");
} }
s.metaBlockLength |= bits << (i * 8); s.metaBlockLength += bits << (i * 8);
} }
} else { } else {
for (let i = 0; i < sizeNibbles; i++) { for (let i = 0; i < sizeNibbles; ++i) {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
@ -217,7 +219,7 @@ function decodeMetaBlockLength(s: State): void {
if (bits === 0 && i + 1 === sizeNibbles && sizeNibbles > 4) { if (bits === 0 && i + 1 === sizeNibbles && sizeNibbles > 4) {
throw new Error("Exuberant nibble"); throw new Error("Exuberant nibble");
} }
s.metaBlockLength |= bits << (i * 4); s.metaBlockLength += bits << (i * 4);
} }
} }
s.metaBlockLength++; s.metaBlockLength++;
@ -227,8 +229,8 @@ function decodeMetaBlockLength(s: State): void {
} }
function readSymbol(tableGroup: Int32Array, tableIdx: number, s: State): number { function readSymbol(tableGroup: Int32Array, tableIdx: number, s: State): number {
let offset: number = tableGroup[tableIdx]; let offset: number = tableGroup[tableIdx];
const val: number = (s.accumulator32 >>> s.bitOffset); const v: number = s.accumulator32 >>> s.bitOffset;
offset += val & 0xFF; offset += v & 0xFF;
const bits: number = tableGroup[offset] >> 16; const bits: number = tableGroup[offset] >> 16;
const sym: number = tableGroup[offset] & 0xFFFF; const sym: number = tableGroup[offset] & 0xFFFF;
if (bits <= 8) { if (bits <= 8) {
@ -237,8 +239,8 @@ function readSymbol(tableGroup: Int32Array, tableIdx: number, s: State): number
} }
offset += sym; offset += sym;
const mask: number = (1 << bits) - 1; const mask: number = (1 << bits) - 1;
offset += (val & mask) >>> 8; offset += (v & mask) >>> 8;
s.bitOffset += ((tableGroup[offset] >> 16) + 8); s.bitOffset += (tableGroup[offset] >> 16) + 8;
return tableGroup[offset] & 0xFFFF; return tableGroup[offset] & 0xFFFF;
} }
function readBlockLength(tableGroup: Int32Array, tableIdx: number, s: State): number { function readBlockLength(tableGroup: Int32Array, tableIdx: number, s: State): number {
@ -255,18 +257,20 @@ function readBlockLength(tableGroup: Int32Array, tableIdx: number, s: State): nu
return BLOCK_LENGTH_OFFSET[code] + ((n <= 16) ? readFewBits(s, n) : readManyBits(s, n)); return BLOCK_LENGTH_OFFSET[code] + ((n <= 16) ? readFewBits(s, n) : readManyBits(s, n));
} }
function moveToFront(v: Int32Array, index: number): void { function moveToFront(v: Int32Array, index: number): void {
const value: number = v[index]; let i: number = index;
for (; index > 0; index--) { const value: number = v[i];
v[index] = v[index - 1]; while (i > 0) {
v[i] = v[i - 1];
i--;
} }
v[0] = value; v[0] = value;
} }
function inverseMoveToFrontTransform(v: Int8Array, vLen: number): void { function inverseMoveToFrontTransform(v: Int8Array, vLen: number): void {
const mtf = new Int32Array(256); const mtf = new Int32Array(256);
for (let i = 0; i < 256; i++) { for (let i = 0; i < 256; ++i) {
mtf[i] = i; mtf[i] = i;
} }
for (let i = 0; i < vLen; i++) { for (let i = 0; i < vLen; ++i) {
const index: number = v[i] & 0xFF; const index: number = v[i] & 0xFF;
v[i] = mtf[index]; v[i] = mtf[index];
if (index !== 0) { if (index !== 0) {
@ -314,7 +318,7 @@ function readHuffmanCodeLengths(codeLengthCodeLengths: Int32Array, numSymbols: n
const oldRepeat: number = repeat; const oldRepeat: number = repeat;
if (repeat > 0) { if (repeat > 0) {
repeat -= 2; repeat -= 2;
repeat <<= extraBits; repeat = repeat << extraBits;
} }
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
@ -325,7 +329,7 @@ function readHuffmanCodeLengths(codeLengthCodeLengths: Int32Array, numSymbols: n
if (symbol + repeatDelta > numSymbols) { if (symbol + repeatDelta > numSymbols) {
throw new Error("symbol + repeatDelta > numSymbols"); throw new Error("symbol + repeatDelta > numSymbols");
} }
for (let i = 0; i < repeatDelta; i++) { for (let i = 0; i < repeatDelta; ++i) {
codeLengths[symbol++] = repeatCodeLen; codeLengths[symbol++] = repeatCodeLen;
} }
if (repeatCodeLen !== 0) { if (repeatCodeLen !== 0) {
@ -352,7 +356,7 @@ function readSimpleHuffmanCode(alphabetSizeMax: number, alphabetSizeLimit: numbe
const symbols = new Int32Array(4); const symbols = new Int32Array(4);
const maxBits: number = 1 + log2floor(alphabetSizeMax - 1); const maxBits: number = 1 + log2floor(alphabetSizeMax - 1);
const numSymbols: number = readFewBits(s, 2) + 1; const numSymbols: number = readFewBits(s, 2) + 1;
for (let i = 0; i < numSymbols; i++) { for (let i = 0; i < numSymbols; ++i) {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
@ -403,7 +407,7 @@ function readComplexHuffmanCode(alphabetSizeLimit: number, skip: number, tableGr
const codeLengthCodeLengths = new Int32Array(18); const codeLengthCodeLengths = new Int32Array(18);
let space = 32; let space = 32;
let numCodes = 0; let numCodes = 0;
for (let i: number = skip; i < 18 && space > 0; i++) { for (let i: number = skip; i < 18; ++i) {
const codeLenIdx: number = CODE_LENGTH_CODE_ORDER[i]; const codeLenIdx: number = CODE_LENGTH_CODE_ORDER[i];
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
@ -414,8 +418,10 @@ function readComplexHuffmanCode(alphabetSizeLimit: number, skip: number, tableGr
const v: number = FIXED_TABLE[p] & 0xFFFF; const v: number = FIXED_TABLE[p] & 0xFFFF;
codeLengthCodeLengths[codeLenIdx] = v; codeLengthCodeLengths[codeLenIdx] = v;
if (v !== 0) { if (v !== 0) {
space -= (32 >> v); space -= 32 >> v;
numCodes++; numCodes++;
if (space <= 0)
break;
} }
} }
if (space !== 0 && numCodes !== 1) { if (space !== 0 && numCodes !== 1) {
@ -462,7 +468,8 @@ function decodeContextMap(contextMapSize: number, contextMap: Int8Array, s: Stat
const table = new Int32Array(tableSize + 1); const table = new Int32Array(tableSize + 1);
const tableIdx: number = table.length - 1; const tableIdx: number = table.length - 1;
readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s); readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s);
for (let i = 0; i < contextMapSize; ) { let i = 0;
while (i < contextMapSize) {
if (s.halfOffset > 2030) { if (s.halfOffset > 2030) {
doReadMoreInput(s); doReadMoreInput(s);
} }
@ -489,7 +496,7 @@ function decodeContextMap(contextMapSize: number, contextMap: Int8Array, s: Stat
reps--; reps--;
} }
} else { } else {
contextMap[i] = (code - maxRunLengthPrefix); contextMap[i] = code - maxRunLengthPrefix;
i++; i++;
} }
} }
@ -547,7 +554,7 @@ function maybeReallocateRingBuffer(s: State): void {
if (newSize > s.expectedTotalSize) { if (newSize > s.expectedTotalSize) {
const minimalNewSize: number = s.expectedTotalSize; const minimalNewSize: number = s.expectedTotalSize;
while ((newSize >> 1) > minimalNewSize) { while ((newSize >> 1) > minimalNewSize) {
newSize >>= 1; newSize = newSize >> 1;
} }
if ((s.inputEnd === 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) { if ((s.inputEnd === 0) && newSize < 16384 && s.maxRingBufferSize >= 16384) {
newSize = 16384; newSize = 16384;
@ -558,8 +565,9 @@ function maybeReallocateRingBuffer(s: State): void {
} }
const ringBufferSizeWithSlack: number = newSize + 37; const ringBufferSizeWithSlack: number = newSize + 37;
const newBuffer = new Int8Array(ringBufferSizeWithSlack); const newBuffer = new Int8Array(ringBufferSizeWithSlack);
if (s.ringBuffer.length !== 0) { const oldBuffer: Int8Array = s.ringBuffer;
newBuffer.set(s.ringBuffer.subarray(0, s.ringBufferSize), 0); if (oldBuffer.length !== 0) {
newBuffer.set(oldBuffer.subarray(0, s.ringBufferSize), 0);
} }
s.ringBuffer = newBuffer; s.ringBuffer = newBuffer;
s.ringBufferSize = newSize; s.ringBufferSize = newSize;
@ -654,23 +662,26 @@ function readMetablockHuffmanCodesAndContextMaps(s: State): void {
s.distancePostfixBits = readFewBits(s, 2); s.distancePostfixBits = readFewBits(s, 2);
s.numDirectDistanceCodes = readFewBits(s, 4) << s.distancePostfixBits; s.numDirectDistanceCodes = readFewBits(s, 4) << s.distancePostfixBits;
s.contextModes = new Int8Array(s.numLiteralBlockTypes); s.contextModes = new Int8Array(s.numLiteralBlockTypes);
for (let i = 0; i < s.numLiteralBlockTypes; ) { let i = 0;
while (i < s.numLiteralBlockTypes) {
const limit: number = Math.min(i + 96, s.numLiteralBlockTypes); const limit: number = Math.min(i + 96, s.numLiteralBlockTypes);
for (; i < limit; ++i) { while (i < limit) {
if (s.bitOffset >= 16) { if (s.bitOffset >= 16) {
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
} }
s.contextModes[i] = readFewBits(s, 2); s.contextModes[i] = readFewBits(s, 2);
i++;
} }
if (s.halfOffset > 2030) { if (s.halfOffset > 2030) {
doReadMoreInput(s); doReadMoreInput(s);
} }
} }
s.contextMap = new Int8Array(s.numLiteralBlockTypes << 6); const contextMapLength: number = s.numLiteralBlockTypes << 6;
const numLiteralTrees: number = decodeContextMap(s.numLiteralBlockTypes << 6, s.contextMap, s); s.contextMap = new Int8Array(contextMapLength);
const numLiteralTrees: number = decodeContextMap(contextMapLength, s.contextMap, s);
s.trivialLiteralContext = 1; s.trivialLiteralContext = 1;
for (let j = 0; j < s.numLiteralBlockTypes << 6; j++) { for (let j = 0; j < contextMapLength; ++j) {
if (s.contextMap[j] !== j >> 6) { if (s.contextMap[j] !== j >> 6) {
s.trivialLiteralContext = 0; s.trivialLiteralContext = 0;
break; break;
@ -1054,7 +1065,8 @@ function decompress(s: State): void {
const dstEnd: number = dst + copyLength; const dstEnd: number = dst + copyLength;
if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) { if ((srcEnd < ringBufferMask) && (dstEnd < ringBufferMask)) {
if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) { if (copyLength < 12 || (srcEnd > dst && dstEnd > src)) {
for (let k = 0; k < copyLength; k += 4) { const numQuads: number = (copyLength + 3) >> 2;
for (let k = 0; k < numQuads; ++k) {
ringBuffer[dst++] = ringBuffer[src++]; ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++]; ringBuffer[dst++] = ringBuffer[src++];
ringBuffer[dst++] = ringBuffer[src++]; ringBuffer[dst++] = ringBuffer[src++];
@ -1067,7 +1079,7 @@ function decompress(s: State): void {
s.metaBlockLength -= copyLength; s.metaBlockLength -= copyLength;
s.pos += copyLength; s.pos += copyLength;
} else { } else {
for (; s.j < s.copyLength; ) { while (s.j < s.copyLength) {
ringBuffer[s.pos] = ringBuffer[(s.pos - s.distance) & ringBufferMask]; ringBuffer[s.pos] = ringBuffer[(s.pos - s.distance) & ringBufferMask];
s.metaBlockLength--; s.metaBlockLength--;
s.pos++; s.pos++;
@ -1129,7 +1141,7 @@ function decompress(s: State): void {
if (s.pos > s.ringBufferSize) { if (s.pos > s.ringBufferSize) {
ringBuffer.copyWithin(0, s.ringBufferSize, s.pos); ringBuffer.copyWithin(0, s.ringBufferSize, s.pos);
} }
s.pos &= ringBufferMask; s.pos = s.pos & ringBufferMask;
s.ringBufferBytesWritten = 0; s.ringBufferBytesWritten = 0;
} }
s.runningState = s.nextRunningState; s.runningState = s.nextRunningState;
@ -1182,7 +1194,7 @@ function unpackTransforms(prefixSuffix: Int8Array, prefixSuffixHeads: Int32Array
{ {
unpackTransforms(RFC_TRANSFORMS.prefixSuffixStorage, RFC_TRANSFORMS.prefixSuffixHeads, RFC_TRANSFORMS.triplets, "# #s #, #e #.# the #.com/#\xC2\xA0# of # and # in # to #\"#\">#\n#]# for # a # that #. # with #'# from # by #. The # on # as # is #ing #\n\t#:#ed #(# at #ly #=\"# of the #. This #,# not #er #al #='#ful #ive #less #est #ize #ous #", " !! ! , *! &! \" ! ) * * - ! # ! #!*! + ,$ ! - % . / # 0 1 . \" 2 3!* 4% ! # / 5 6 7 8 0 1 & $ 9 + : ; < ' != > ?! 4 @ 4 2 & A *# ( B C& ) % ) !*# *-% A +! *. D! %' & E *6 F G% ! *A *% H! D I!+! J!+ K +- *4! A L!*4 M N +6 O!*% +.! K *G P +%( ! G *D +D Q +# *K!*G!+D!+# +G +A +4!+% +K!+4!*D!+K!*K"); unpackTransforms(RFC_TRANSFORMS.prefixSuffixStorage, RFC_TRANSFORMS.prefixSuffixHeads, RFC_TRANSFORMS.triplets, "# #s #, #e #.# the #.com/#\xC2\xA0# of # and # in # to #\"#\">#\n#]# for # a # that #. # with #'# from # by #. The # on # as # is #ing #\n\t#:#ed #(# at #ly #=\"# of the #. This #,# not #er #al #='#ful #ive #less #est #ize #ous #", " !! ! , *! &! \" ! ) * * - ! # ! #!*! + ,$ ! - % . / # 0 1 . \" 2 3!* 4% ! # / 5 6 7 8 0 1 & $ 9 + : ; < ' != > ?! 4 @ 4 2 & A *# ( B C& ) % ) !*# *-% A +! *. D! %' & E *6 F G% ! *A *% H! D I!+! J!+ K +- *4! A L!*4 M N +6 O!*% +.! K *G P +%( ! G *D +D Q +# *K!*G!+D!+# +G +A +4!+% +K!+4!*D!+K!*K");
} }
function transformDictionaryWord(dst: Int8Array, dstOffset: number, src: ByteBuffer, srcOffset: number, len: number, transforms: Transforms, transformIndex: number): number { function transformDictionaryWord(dst: Int8Array, dstOffset: number, src: ByteBuffer, srcOffset: number, wordLen: number, transforms: Transforms, transformIndex: number): number {
let offset: number = dstOffset; let offset: number = dstOffset;
const triplets: Int32Array = transforms.triplets; const triplets: Int32Array = transforms.triplets;
const prefixSuffixStorage: Int8Array = transforms.prefixSuffixStorage; const prefixSuffixStorage: Int8Array = transforms.prefixSuffixStorage;
@ -1206,15 +1218,16 @@ function transformDictionaryWord(dst: Int8Array, dstOffset: number, src: ByteBuf
while (prefix !== prefixEnd) { while (prefix !== prefixEnd) {
dst[offset++] = prefixSuffixStorage[prefix++]; dst[offset++] = prefixSuffixStorage[prefix++];
} }
let len: number = wordLen;
if (omitFirst > len) { if (omitFirst > len) {
omitFirst = len; omitFirst = len;
} }
srcOffset += omitFirst; let dictOffset: number = srcOffset + omitFirst;
len -= omitFirst; len -= omitFirst;
len -= omitLast; len -= omitLast;
let i: number = len; let i: number = len;
while (i > 0) { while (i > 0) {
dst[offset++] = src[srcOffset++]; dst[offset++] = src[dictOffset++];
i--; i--;
} }
if (transformType === 10 || transformType === 11) { if (transformType === 10 || transformType === 11) {
@ -1226,16 +1239,16 @@ function transformDictionaryWord(dst: Int8Array, dstOffset: number, src: ByteBuf
const c0: number = dst[uppercaseOffset] & 0xFF; const c0: number = dst[uppercaseOffset] & 0xFF;
if (c0 < 0xC0) { if (c0 < 0xC0) {
if (c0 >= 97 && c0 <= 122) { if (c0 >= 97 && c0 <= 122) {
dst[uppercaseOffset] ^= 32; dst[uppercaseOffset] = dst[uppercaseOffset] ^ 32;
} }
uppercaseOffset += 1; uppercaseOffset += 1;
len -= 1; len -= 1;
} else if (c0 < 0xE0) { } else if (c0 < 0xE0) {
dst[uppercaseOffset + 1] ^= 32; dst[uppercaseOffset + 1] = dst[uppercaseOffset + 1] ^ 32;
uppercaseOffset += 2; uppercaseOffset += 2;
len -= 2; len -= 2;
} else { } else {
dst[uppercaseOffset + 2] ^= 5; dst[uppercaseOffset + 2] = dst[uppercaseOffset + 2] ^ 5;
uppercaseOffset += 3; uppercaseOffset += 3;
len -= 3; len -= 3;
} }
@ -1249,14 +1262,14 @@ function transformDictionaryWord(dst: Int8Array, dstOffset: number, src: ByteBuf
const c0: number = dst[shiftOffset] & 0xFF; const c0: number = dst[shiftOffset] & 0xFF;
if (c0 < 0x80) { if (c0 < 0x80) {
scalar += c0; scalar += c0;
dst[shiftOffset] = (scalar & 0x7F); dst[shiftOffset] = scalar & 0x7F;
} else if (c0 < 0xC0) { } else if (c0 < 0xC0) {
} else if (c0 < 0xE0) { } else if (c0 < 0xE0) {
if (len >= 2) { if (len >= 2) {
const c1: number = dst[shiftOffset + 1]; const c1: number = dst[shiftOffset + 1];
scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6); scalar += (c1 & 0x3F) | ((c0 & 0x1F) << 6);
dst[shiftOffset] = (0xC0 | ((scalar >> 6) & 0x1F)); dst[shiftOffset] = 0xC0 | ((scalar >> 6) & 0x1F);
dst[shiftOffset + 1] = ((c1 & 0xC0) | (scalar & 0x3F)); dst[shiftOffset + 1] = (c1 & 0xC0) | (scalar & 0x3F);
step = 2; step = 2;
} else { } else {
step = len; step = len;
@ -1266,9 +1279,9 @@ function transformDictionaryWord(dst: Int8Array, dstOffset: number, src: ByteBuf
const c1: number = dst[shiftOffset + 1]; const c1: number = dst[shiftOffset + 1];
const c2: number = dst[shiftOffset + 2]; const c2: number = dst[shiftOffset + 2];
scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12); scalar += (c2 & 0x3F) | ((c1 & 0x3F) << 6) | ((c0 & 0x0F) << 12);
dst[shiftOffset] = (0xE0 | ((scalar >> 12) & 0x0F)); dst[shiftOffset] = 0xE0 | ((scalar >> 12) & 0x0F);
dst[shiftOffset + 1] = ((c1 & 0xC0) | ((scalar >> 6) & 0x3F)); dst[shiftOffset + 1] = (c1 & 0xC0) | ((scalar >> 6) & 0x3F);
dst[shiftOffset + 2] = ((c2 & 0xC0) | (scalar & 0x3F)); dst[shiftOffset + 2] = (c2 & 0xC0) | (scalar & 0x3F);
step = 3; step = 3;
} else { } else {
step = len; step = len;
@ -1279,10 +1292,10 @@ function transformDictionaryWord(dst: Int8Array, dstOffset: number, src: ByteBuf
const c2: number = dst[shiftOffset + 2]; const c2: number = dst[shiftOffset + 2];
const c3: number = dst[shiftOffset + 3]; const c3: number = dst[shiftOffset + 3];
scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18); scalar += (c3 & 0x3F) | ((c2 & 0x3F) << 6) | ((c1 & 0x3F) << 12) | ((c0 & 0x07) << 18);
dst[shiftOffset] = (0xF0 | ((scalar >> 18) & 0x07)); dst[shiftOffset] = 0xF0 | ((scalar >> 18) & 0x07);
dst[shiftOffset + 1] = ((c1 & 0xC0) | ((scalar >> 12) & 0x3F)); dst[shiftOffset + 1] = (c1 & 0xC0) | ((scalar >> 12) & 0x3F);
dst[shiftOffset + 2] = ((c2 & 0xC0) | ((scalar >> 6) & 0x3F)); dst[shiftOffset + 2] = (c2 & 0xC0) | ((scalar >> 6) & 0x3F);
dst[shiftOffset + 3] = ((c3 & 0xC0) | (scalar & 0x3F)); dst[shiftOffset + 3] = (c3 & 0xC0) | (scalar & 0x3F);
step = 4; step = 4;
} else { } else {
step = len; step = len;
@ -1304,69 +1317,74 @@ function transformDictionaryWord(dst: Int8Array, dstOffset: number, src: ByteBuf
function getNextKey(key: number, len: number): number { function getNextKey(key: number, len: number): number {
let step: number = 1 << (len - 1); let step: number = 1 << (len - 1);
while ((key & step) !== 0) { while ((key & step) !== 0) {
step >>= 1; step = step >> 1;
} }
return (key & (step - 1)) + step; return (key & (step - 1)) + step;
} }
function replicateValue(table: Int32Array, offset: number, step: number, end: number, item: number): void { function replicateValue(table: Int32Array, offset: number, step: number, end: number, item: number): void {
let pos: number = end;
do { do {
end -= step; pos -= step;
table[offset + end] = item; table[offset + pos] = item;
} while (end > 0); } while (pos > 0);
} }
function nextTableBitSize(count: Int32Array, len: number, rootBits: number): number { function nextTableBitSize(count: Int32Array, len: number, rootBits: number): number {
let left: number = 1 << (len - rootBits); let bits: number = len;
while (len < 15) { let left: number = 1 << (bits - rootBits);
left -= count[len]; while (bits < 15) {
left -= count[bits];
if (left <= 0) { if (left <= 0) {
break; break;
} }
len++; bits++;
left <<= 1; left = left << 1;
} }
return len - rootBits; return bits - rootBits;
} }
function buildHuffmanTable(tableGroup: Int32Array, tableIdx: number, rootBits: number, codeLengths: Int32Array, codeLengthsSize: number): number { function buildHuffmanTable(tableGroup: Int32Array, tableIdx: number, rootBits: number, codeLengths: Int32Array, codeLengthsSize: number): number {
const tableOffset: number = tableGroup[tableIdx]; const tableOffset: number = tableGroup[tableIdx];
let key: number;
const sorted = new Int32Array(codeLengthsSize); const sorted = new Int32Array(codeLengthsSize);
const count = new Int32Array(16); const count = new Int32Array(16);
const offset = new Int32Array(16); const offset = new Int32Array(16);
let symbol: number; for (let sym = 0; sym < codeLengthsSize; ++sym) {
for (symbol = 0; symbol < codeLengthsSize; symbol++) { count[codeLengths[sym]]++;
count[codeLengths[symbol]]++;
} }
offset[1] = 0; offset[1] = 0;
for (let len = 1; len < 15; len++) { for (let len = 1; len < 15; ++len) {
offset[len + 1] = offset[len] + count[len]; offset[len + 1] = offset[len] + count[len];
} }
for (symbol = 0; symbol < codeLengthsSize; symbol++) { for (let sym = 0; sym < codeLengthsSize; ++sym) {
if (codeLengths[symbol] !== 0) { if (codeLengths[sym] !== 0) {
sorted[offset[codeLengths[symbol]]++] = symbol; sorted[offset[codeLengths[sym]]++] = sym;
} }
} }
let tableBits: number = rootBits; let tableBits: number = rootBits;
let tableSize: number = 1 << tableBits; let tableSize: number = 1 << tableBits;
let totalSize: number = tableSize; let totalSize: number = tableSize;
if (offset[15] === 1) { if (offset[15] === 1) {
for (key = 0; key < totalSize; key++) { for (let k = 0; k < totalSize; ++k) {
tableGroup[tableOffset + key] = sorted[0]; tableGroup[tableOffset + k] = sorted[0];
} }
return totalSize; return totalSize;
} }
key = 0; let key = 0;
symbol = 0; let symbol = 0;
for (let len = 1, step = 2; len <= rootBits; len++, step <<= 1) { let step = 1;
for (; count[len] > 0; count[len]--) { for (let len = 1; len <= rootBits; ++len) {
step = step << 1;
while (count[len] > 0) {
replicateValue(tableGroup, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]); replicateValue(tableGroup, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
key = getNextKey(key, len); key = getNextKey(key, len);
count[len]--;
} }
} }
const mask: number = totalSize - 1; const mask: number = totalSize - 1;
let low: number = -1; let low: number = -1;
let currentOffset: number = tableOffset; let currentOffset: number = tableOffset;
for (let len: number = rootBits + 1, step = 2; len <= 15; len++, step <<= 1) { step = 1;
for (; count[len] > 0; count[len]--) { for (let len: number = rootBits + 1; len <= 15; ++len) {
step = step << 1;
while (count[len] > 0) {
if ((key & mask) !== low) { if ((key & mask) !== low) {
currentOffset += tableSize; currentOffset += tableSize;
tableBits = nextTableBitSize(count, len, rootBits); tableBits = nextTableBitSize(count, len, rootBits);
@ -1377,6 +1395,7 @@ function buildHuffmanTable(tableGroup: Int32Array, tableIdx: number, rootBits: n
} }
replicateValue(tableGroup, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]); replicateValue(tableGroup, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
key = getNextKey(key, len); key = getNextKey(key, len);
count[len]--;
} }
} }
return totalSize; return totalSize;
@ -1419,9 +1438,9 @@ function checkHealth(s: State, endOfStream: number): void {
} }
} }
function readFewBits(s: State, n: number): number { function readFewBits(s: State, n: number): number {
const val: number = (s.accumulator32 >>> s.bitOffset) & ((1 << n) - 1); const v: number = (s.accumulator32 >>> s.bitOffset) & ((1 << n) - 1);
s.bitOffset += n; s.bitOffset += n;
return val; return v;
} }
function readManyBits(s: State, n: number): number { function readManyBits(s: State, n: number): number {
const low: number = readFewBits(s, 16); const low: number = readFewBits(s, 16);
@ -1470,27 +1489,29 @@ function halfAvailable(s: State): number {
return limit - s.halfOffset; return limit - s.halfOffset;
} }
function copyRawBytes(s: State, data: Int8Array, offset: number, length: number): void { function copyRawBytes(s: State, data: Int8Array, offset: number, length: number): void {
let pos: number = offset;
let len: number = length;
if ((s.bitOffset & 7) !== 0) { if ((s.bitOffset & 7) !== 0) {
throw new Error("Unaligned copyBytes"); throw new Error("Unaligned copyBytes");
} }
while ((s.bitOffset !== 32) && (length !== 0)) { while ((s.bitOffset !== 32) && (len !== 0)) {
data[offset++] = (s.accumulator32 >>> s.bitOffset); data[pos++] = s.accumulator32 >>> s.bitOffset;
s.bitOffset += 8; s.bitOffset += 8;
length--; len--;
} }
if (length === 0) { if (len === 0) {
return; return;
} }
const copyNibbles: number = Math.min(halfAvailable(s), length >> 1); const copyNibbles: number = Math.min(halfAvailable(s), len >> 1);
if (copyNibbles > 0) { if (copyNibbles > 0) {
const readOffset: number = s.halfOffset << 1; const readOffset: number = s.halfOffset << 1;
const delta: number = copyNibbles << 1; const delta: number = copyNibbles << 1;
data.set(s.byteBuffer.subarray(readOffset, readOffset + delta), offset); data.set(s.byteBuffer.subarray(readOffset, readOffset + delta), pos);
offset += delta; pos += delta;
length -= delta; len -= delta;
s.halfOffset += copyNibbles; s.halfOffset += copyNibbles;
} }
if (length === 0) { if (len === 0) {
return; return;
} }
if (halfAvailable(s) > 0) { if (halfAvailable(s) > 0) {
@ -1498,21 +1519,21 @@ function copyRawBytes(s: State, data: Int8Array, offset: number, length: number)
s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16); s.accumulator32 = (s.shortBuffer[s.halfOffset++] << 16) | (s.accumulator32 >>> 16);
s.bitOffset -= 16; s.bitOffset -= 16;
} }
while (length !== 0) { while (len !== 0) {
data[offset++] = (s.accumulator32 >>> s.bitOffset); data[pos++] = s.accumulator32 >>> s.bitOffset;
s.bitOffset += 8; s.bitOffset += 8;
length--; len--;
} }
checkHealth(s, 0); checkHealth(s, 0);
return; return;
} }
while (length > 0) { while (len > 0) {
const len: number = readInput(s, data, offset, length); const chunkLen: number = readInput(s, data, pos, len);
if (len === -1) { if (chunkLen === -1) {
throw new Error("Unexpected end of input"); throw new Error("Unexpected end of input");
} }
offset += len; pos += chunkLen;
length -= len; len -= chunkLen;
} }
} }
function bytesToNibbles(s: State, byteLen: number): void { function bytesToNibbles(s: State, byteLen: number): void {
@ -1520,7 +1541,7 @@ function bytesToNibbles(s: State, byteLen: number): void {
const halfLen: number = byteLen >> 1; const halfLen: number = byteLen >> 1;
const shortBuffer: Int16Array = s.shortBuffer; const shortBuffer: Int16Array = s.shortBuffer;
for (let i = 0; i < halfLen; ++i) { for (let i = 0; i < halfLen; ++i) {
shortBuffer[i] = ((byteBuffer[i * 2] & 0xFF) | ((byteBuffer[(i * 2) + 1] & 0xFF) << 8)); shortBuffer[i] = (byteBuffer[i * 2] & 0xFF) | ((byteBuffer[(i * 2) + 1] & 0xFF) << 8);
} }
} }
@ -1632,7 +1653,7 @@ class State {
cdChunkOffsets = new Int32Array(0); cdChunkOffsets = new Int32Array(0);
cdBlockBits = 0; cdBlockBits = 0;
cdBlockMap = new Int8Array(0); cdBlockMap = new Int8Array(0);
input: InputStream|null = null; input = new InputStream(new Int8Array(0));
constructor () { constructor () {
this.ringBuffer = new Int8Array(0); this.ringBuffer = new Int8Array(0);
this.rings = new Int32Array(10); this.rings = new Int32Array(10);
@ -1688,16 +1709,16 @@ function unpackDictionaryData(dictionary: ByteBuffer, data0: string, data1: stri
throw new Error("Corrupted brotli dictionary"); throw new Error("Corrupted brotli dictionary");
} }
let offset = 0; let offset = 0;
const n: number = skipFlip.length; const n: number = skipFlip.length >> 1;
for (let i = 0; i < n; i += 2) { for (let i = 0; i < n; ++i) {
const skip: number = skipFlip.charCodeAt(i) - 36; const skip: number = skipFlip.charCodeAt(2 * i) - 36;
const flip: number = skipFlip.charCodeAt(i + 1) - 36; const flip: number = skipFlip.charCodeAt(2 * i + 1) - 36;
for (let j = 0; j < skip; ++j) { for (let j = 0; j < skip; ++j) {
dict[offset] ^= 3; dict[offset] = dict[offset] ^ 3;
offset++; offset++;
} }
for (let j = 0; j < flip; ++j) { for (let j = 0; j < flip; ++j) {
dict[offset] ^= 236; dict[offset] = dict[offset] ^ 236;
offset++; offset++;
} }
} }