Remove brotli test binaries for F-Droid compliance (#11)
This commit is contained in:
parent
5483b18549
commit
eda8397043
123 changed files with 0 additions and 34418 deletions
|
|
@ -1,61 +0,0 @@
|
|||
# Description:
|
||||
# Java port of Brotli decoder.
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # MIT
|
||||
|
||||
java_library(
|
||||
name = "dec",
|
||||
srcs = glob(
|
||||
["*.java"],
|
||||
exclude = ["*Test*.java"],
|
||||
),
|
||||
proguard_specs = ["proguard.cfg"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "test_lib",
|
||||
testonly = 1,
|
||||
srcs = glob(["*Test*.java"]),
|
||||
deps = [
|
||||
":dec",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "BitReaderTest",
|
||||
test_class = "org.brotli.dec.BitReaderTest",
|
||||
runtime_deps = [":test_lib"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "DecodeTest",
|
||||
test_class = "org.brotli.dec.DecodeTest",
|
||||
runtime_deps = [":test_lib"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "DictionaryTest",
|
||||
test_class = "org.brotli.dec.DictionaryTest",
|
||||
runtime_deps = [":test_lib"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "EagerStreamTest",
|
||||
test_class = "org.brotli.dec.EagerStreamTest",
|
||||
runtime_deps = [":test_lib"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "SynthTest",
|
||||
test_class = "org.brotli.dec.SynthTest",
|
||||
runtime_deps = [":test_lib"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "TransformTest",
|
||||
test_class = "org.brotli.dec.TransformTest",
|
||||
runtime_deps = [":test_lib"],
|
||||
)
|
||||
|
|
@ -1,266 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
/**
|
||||
* Bit reading helpers.
|
||||
*/
|
||||
final class BitReader {
|
||||
|
||||
// Possible values: {5, 6}. 5 corresponds to 32-bit build, 6 to 64-bit. This value is used for
|
||||
// conditional compilation -> produced artifacts might be binary INCOMPATIBLE (JLS 13.2).
|
||||
private static final int LOG_BITNESS = 6;
|
||||
private static final int BITNESS = 1 << LOG_BITNESS;
|
||||
|
||||
private static final int BYTENESS = BITNESS / 8;
|
||||
private static final int CAPACITY = 4096;
|
||||
// After encountering the end of the input stream, this amount of zero bytes will be appended.
|
||||
private static final int SLACK = 64;
|
||||
private static final int BUFFER_SIZE = CAPACITY + SLACK;
|
||||
// Don't bother to replenish the buffer while this number of bytes is available.
|
||||
private static final int SAFEGUARD = 36;
|
||||
private static final int WATERLINE = CAPACITY - SAFEGUARD;
|
||||
|
||||
// "Half" refers to "half of native integer type", i.e. on 64-bit machines it is 32-bit type,
|
||||
// on 32-bit machines it is 16-bit.
|
||||
private static final int HALF_BITNESS = BITNESS / 2;
|
||||
private static final int HALF_SIZE = BYTENESS / 2;
|
||||
private static final int HALVES_CAPACITY = CAPACITY / HALF_SIZE;
|
||||
private static final int HALF_BUFFER_SIZE = BUFFER_SIZE / HALF_SIZE;
|
||||
private static final int HALF_WATERLINE = WATERLINE / HALF_SIZE;
|
||||
|
||||
private static final int LOG_HALF_SIZE = LOG_BITNESS - 4;
|
||||
|
||||
/**
|
||||
* Fills up the input buffer.
|
||||
*
|
||||
* <p> No-op if there are at least 36 bytes present after current position.
|
||||
*
|
||||
* <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
|
||||
* buffer.
|
||||
*/
|
||||
static void readMoreInput(State s) {
|
||||
if (s.halfOffset > HALF_WATERLINE) {
|
||||
doReadMoreInput(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void doReadMoreInput(State s) {
|
||||
if (s.endOfStreamReached != 0) {
|
||||
if (halfAvailable(s) >= -2) {
|
||||
return;
|
||||
}
|
||||
throw new BrotliRuntimeException("No more input");
|
||||
}
|
||||
int readOffset = s.halfOffset << LOG_HALF_SIZE;
|
||||
int bytesInBuffer = CAPACITY - readOffset;
|
||||
// Move unused bytes to the head of the buffer.
|
||||
Utils.copyBytesWithin(s.byteBuffer, 0, readOffset, CAPACITY);
|
||||
s.halfOffset = 0;
|
||||
while (bytesInBuffer < CAPACITY) {
|
||||
int spaceLeft = CAPACITY - bytesInBuffer;
|
||||
int len = Utils.readInput(s.input, s.byteBuffer, bytesInBuffer, spaceLeft);
|
||||
// EOF is -1 in Java, but 0 in C#.
|
||||
if (len <= 0) {
|
||||
s.endOfStreamReached = 1;
|
||||
s.tailBytes = bytesInBuffer;
|
||||
bytesInBuffer += HALF_SIZE - 1;
|
||||
break;
|
||||
}
|
||||
bytesInBuffer += len;
|
||||
}
|
||||
bytesToNibbles(s, bytesInBuffer);
|
||||
}
|
||||
|
||||
static void checkHealth(State s, int endOfStream) {
|
||||
if (s.endOfStreamReached == 0) {
|
||||
return;
|
||||
}
|
||||
int byteOffset = (s.halfOffset << LOG_HALF_SIZE) + ((s.bitOffset + 7) >> 3) - BYTENESS;
|
||||
if (byteOffset > s.tailBytes) {
|
||||
throw new BrotliRuntimeException("Read after end");
|
||||
}
|
||||
if ((endOfStream != 0) && (byteOffset != s.tailBytes)) {
|
||||
throw new BrotliRuntimeException("Unused bytes after end");
|
||||
}
|
||||
}
|
||||
|
||||
static void fillBitWindow(State s) {
|
||||
if (s.bitOffset >= HALF_BITNESS) {
|
||||
// Same as doFillBitWindow. JVM fails to inline it.
|
||||
if (BITNESS == 64) {
|
||||
s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS)
|
||||
| (s.accumulator64 >>> HALF_BITNESS);
|
||||
} else {
|
||||
s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS)
|
||||
| (s.accumulator32 >>> HALF_BITNESS);
|
||||
}
|
||||
s.bitOffset -= HALF_BITNESS;
|
||||
}
|
||||
}
|
||||
|
||||
private static void doFillBitWindow(State s) {
|
||||
if (BITNESS == 64) {
|
||||
s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS)
|
||||
| (s.accumulator64 >>> HALF_BITNESS);
|
||||
} else {
|
||||
s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS)
|
||||
| (s.accumulator32 >>> HALF_BITNESS);
|
||||
}
|
||||
s.bitOffset -= HALF_BITNESS;
|
||||
}
|
||||
|
||||
static int peekBits(State s) {
|
||||
if (BITNESS == 64) {
|
||||
return (int) (s.accumulator64 >>> s.bitOffset);
|
||||
} else {
|
||||
return s.accumulator32 >>> s.bitOffset;
|
||||
}
|
||||
}
|
||||
|
||||
static int readFewBits(State s, int n) {
|
||||
int val = peekBits(s) & ((1 << n) - 1);
|
||||
s.bitOffset += n;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int readBits(State s, int n) {
|
||||
if (HALF_BITNESS >= 24) {
|
||||
return readFewBits(s, n);
|
||||
} else {
|
||||
return (n <= 16) ? readFewBits(s, n) : readManyBits(s, n);
|
||||
}
|
||||
}
|
||||
|
||||
private static int readManyBits(State s, int n) {
|
||||
int low = readFewBits(s, 16);
|
||||
doFillBitWindow(s);
|
||||
return low | (readFewBits(s, n - 16) << 16);
|
||||
}
|
||||
|
||||
static void initBitReader(State s) {
|
||||
s.byteBuffer = new byte[BUFFER_SIZE];
|
||||
if (BITNESS == 64) {
|
||||
s.accumulator64 = 0;
|
||||
s.intBuffer = new int[HALF_BUFFER_SIZE];
|
||||
} else {
|
||||
s.accumulator32 = 0;
|
||||
s.shortBuffer = new short[HALF_BUFFER_SIZE];
|
||||
}
|
||||
s.bitOffset = BITNESS;
|
||||
s.halfOffset = HALVES_CAPACITY;
|
||||
s.endOfStreamReached = 0;
|
||||
prepare(s);
|
||||
}
|
||||
|
||||
private static void prepare(State s) {
|
||||
readMoreInput(s);
|
||||
checkHealth(s, 0);
|
||||
doFillBitWindow(s);
|
||||
doFillBitWindow(s);
|
||||
}
|
||||
|
||||
static void reload(State s) {
|
||||
if (s.bitOffset == BITNESS) {
|
||||
prepare(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void jumpToByteBoundary(State s) {
|
||||
int padding = (BITNESS - s.bitOffset) & 7;
|
||||
if (padding != 0) {
|
||||
int paddingBits = readFewBits(s, padding);
|
||||
if (paddingBits != 0) {
|
||||
throw new BrotliRuntimeException("Corrupted padding bits");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int halfAvailable(State s) {
|
||||
int limit = HALVES_CAPACITY;
|
||||
if (s.endOfStreamReached != 0) {
|
||||
limit = (s.tailBytes + (HALF_SIZE - 1)) >> LOG_HALF_SIZE;
|
||||
}
|
||||
return limit - s.halfOffset;
|
||||
}
|
||||
|
||||
static void copyBytes(State s, byte[] data, int offset, int length) {
|
||||
if ((s.bitOffset & 7) != 0) {
|
||||
throw new BrotliRuntimeException("Unaligned copyBytes");
|
||||
}
|
||||
|
||||
// Drain accumulator.
|
||||
while ((s.bitOffset != BITNESS) && (length != 0)) {
|
||||
data[offset++] = (byte) peekBits(s);
|
||||
s.bitOffset += 8;
|
||||
length--;
|
||||
}
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get data from shadow buffer with "sizeof(int)" granularity.
|
||||
int copyNibbles = Math.min(halfAvailable(s), length >> LOG_HALF_SIZE);
|
||||
if (copyNibbles > 0) {
|
||||
int readOffset = s.halfOffset << LOG_HALF_SIZE;
|
||||
int delta = copyNibbles << LOG_HALF_SIZE;
|
||||
System.arraycopy(s.byteBuffer, readOffset, data, offset, delta);
|
||||
offset += delta;
|
||||
length -= delta;
|
||||
s.halfOffset += copyNibbles;
|
||||
}
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read tail bytes.
|
||||
if (halfAvailable(s) > 0) {
|
||||
// length = 1..3
|
||||
fillBitWindow(s);
|
||||
while (length != 0) {
|
||||
data[offset++] = (byte) peekBits(s);
|
||||
s.bitOffset += 8;
|
||||
length--;
|
||||
}
|
||||
checkHealth(s, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now it is possible to copy bytes directly.
|
||||
while (length > 0) {
|
||||
int len = Utils.readInput(s.input, data, offset, length);
|
||||
if (len == -1) {
|
||||
throw new BrotliRuntimeException("Unexpected end of input");
|
||||
}
|
||||
offset += len;
|
||||
length -= len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates bytes to halves (int/short).
|
||||
*/
|
||||
static void bytesToNibbles(State s, int byteLen) {
|
||||
byte[] byteBuffer = s.byteBuffer;
|
||||
int halfLen = byteLen >> LOG_HALF_SIZE;
|
||||
if (BITNESS == 64) {
|
||||
int[] intBuffer = s.intBuffer;
|
||||
for (int i = 0; i < halfLen; ++i) {
|
||||
intBuffer[i] = ((byteBuffer[i * 4] & 0xFF))
|
||||
| ((byteBuffer[(i * 4) + 1] & 0xFF) << 8)
|
||||
| ((byteBuffer[(i * 4) + 2] & 0xFF) << 16)
|
||||
| ((byteBuffer[(i * 4) + 3] & 0xFF) << 24);
|
||||
}
|
||||
} else {
|
||||
short[] shortBuffer = s.shortBuffer;
|
||||
for (int i = 0; i < halfLen; ++i) {
|
||||
shortBuffer[i] = (short) ((byteBuffer[i * 2] & 0xFF)
|
||||
| ((byteBuffer[(i * 2) + 1] & 0xFF) << 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Tests for {@link BitReader}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class BitReaderTest {
|
||||
|
||||
@Test
|
||||
public void testReadAfterEos() {
|
||||
State reader = new State();
|
||||
Decode.initState(reader, new ByteArrayInputStream(new byte[1]));
|
||||
BitReader.readBits(reader, 9);
|
||||
try {
|
||||
BitReader.checkHealth(reader, 0);
|
||||
} catch (BrotliRuntimeException ex) {
|
||||
// This exception is expected.
|
||||
return;
|
||||
}
|
||||
fail("BrotliRuntimeException should have been thrown by BitReader.checkHealth");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* {@link InputStream} decorator that decompresses brotli data.
|
||||
*
|
||||
* <p> Not thread-safe.
|
||||
*/
|
||||
public class BrotliInputStream extends InputStream {
|
||||
|
||||
public static final int DEFAULT_INTERNAL_BUFFER_SIZE = 256;
|
||||
|
||||
/**
|
||||
* Internal buffer used for efficient byte-by-byte reading.
|
||||
*/
|
||||
private byte[] buffer;
|
||||
|
||||
/**
|
||||
* Number of decoded but still unused bytes in internal buffer.
|
||||
*/
|
||||
private int remainingBufferBytes;
|
||||
|
||||
/**
|
||||
* Next unused byte offset.
|
||||
*/
|
||||
private int bufferOffset;
|
||||
|
||||
/**
|
||||
* Decoder state.
|
||||
*/
|
||||
private final State state = new State();
|
||||
|
||||
/**
|
||||
* Creates a {@link InputStream} wrapper that decompresses brotli data.
|
||||
*
|
||||
* <p> For byte-by-byte reading ({@link #read()}) internal buffer with
|
||||
* {@link #DEFAULT_INTERNAL_BUFFER_SIZE} size is allocated and used.
|
||||
*
|
||||
* <p> Will block the thread until first {@link BitReader#CAPACITY} bytes of data of source
|
||||
* are available.
|
||||
*
|
||||
* @param source underlying data source
|
||||
* @throws IOException in case of corrupted data or source stream problems
|
||||
*/
|
||||
public BrotliInputStream(InputStream source) throws IOException {
|
||||
this(source, DEFAULT_INTERNAL_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link InputStream} wrapper that decompresses brotli data.
|
||||
*
|
||||
* <p> For byte-by-byte reading ({@link #read()}) internal buffer of specified size is
|
||||
* allocated and used.
|
||||
*
|
||||
* <p> Will block the thread until first {@link BitReader#CAPACITY} bytes of data of source
|
||||
* are available.
|
||||
*
|
||||
* @param source compressed data source
|
||||
* @param byteReadBufferSize size of internal buffer used in case of
|
||||
* byte-by-byte reading
|
||||
* @throws IOException in case of corrupted data or source stream problems
|
||||
*/
|
||||
public BrotliInputStream(InputStream source, int byteReadBufferSize) throws IOException {
|
||||
if (byteReadBufferSize <= 0) {
|
||||
throw new IllegalArgumentException("Bad buffer size:" + byteReadBufferSize);
|
||||
} else if (source == null) {
|
||||
throw new IllegalArgumentException("source is null");
|
||||
}
|
||||
this.buffer = new byte[byteReadBufferSize];
|
||||
this.remainingBufferBytes = 0;
|
||||
this.bufferOffset = 0;
|
||||
try {
|
||||
Decode.initState(state, source);
|
||||
} catch (BrotliRuntimeException ex) {
|
||||
throw new IOException("Brotli decoder initialization failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void setEager(boolean eager) {
|
||||
state.isEager = eager ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Decode.close(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (bufferOffset >= remainingBufferBytes) {
|
||||
remainingBufferBytes = read(buffer, 0, buffer.length);
|
||||
bufferOffset = 0;
|
||||
if (remainingBufferBytes == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return buffer[bufferOffset++] & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int read(byte[] destBuffer, int destOffset, int destLen) throws IOException {
|
||||
if (destOffset < 0) {
|
||||
throw new IllegalArgumentException("Bad offset: " + destOffset);
|
||||
} else if (destLen < 0) {
|
||||
throw new IllegalArgumentException("Bad length: " + destLen);
|
||||
} else if (destOffset + destLen > destBuffer.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.length);
|
||||
} else if (destLen == 0) {
|
||||
return 0;
|
||||
}
|
||||
int copyLen = Math.max(remainingBufferBytes - bufferOffset, 0);
|
||||
if (copyLen != 0) {
|
||||
copyLen = Math.min(copyLen, destLen);
|
||||
System.arraycopy(buffer, bufferOffset, destBuffer, destOffset, copyLen);
|
||||
bufferOffset += copyLen;
|
||||
destOffset += copyLen;
|
||||
destLen -= copyLen;
|
||||
if (destLen == 0) {
|
||||
return copyLen;
|
||||
}
|
||||
}
|
||||
try {
|
||||
state.output = destBuffer;
|
||||
state.outputOffset = destOffset;
|
||||
state.outputLength = destLen;
|
||||
state.outputUsed = 0;
|
||||
Decode.decompress(state);
|
||||
if (state.outputUsed == 0) {
|
||||
return -1;
|
||||
}
|
||||
return state.outputUsed + copyLen;
|
||||
} catch (BrotliRuntimeException ex) {
|
||||
throw new IOException("Brotli stream decoding failed", ex);
|
||||
}
|
||||
|
||||
// <{[INJECTED CODE]}>
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
/**
|
||||
* Unchecked exception used internally.
|
||||
*/
|
||||
class BrotliRuntimeException extends RuntimeException {
|
||||
|
||||
BrotliRuntimeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
BrotliRuntimeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
/**
|
||||
* Common context lookup table for all context modes.
|
||||
*/
|
||||
final class Context {
|
||||
|
||||
static final int[] LOOKUP = new int[2048];
|
||||
|
||||
private static final String UTF_MAP = " !! ! \"#$##%#$&'##(#)#+++++++++"
|
||||
+ "+((&*'##,---,---,-----,-----,-----&#'###.///.///./////./////./////&#'# ";
|
||||
private static final String UTF_RLE = "A/* ': & : $ \u0081 @";
|
||||
|
||||
private static void unpackLookupTable(int[] lookup, String map, String rle) {
|
||||
// LSB6, MSB6, SIGNED
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
lookup[i] = i & 0x3F;
|
||||
lookup[512 + i] = i >> 2;
|
||||
lookup[1792 + i] = 2 + (i >> 6);
|
||||
}
|
||||
// UTF8
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
lookup[1024 + i] = 4 * (map.charAt(i) - 32);
|
||||
}
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
lookup[1152 + i] = i & 1;
|
||||
lookup[1216 + i] = 2 + (i & 1);
|
||||
}
|
||||
int offset = 1280;
|
||||
for (int k = 0; k < 19; ++k) {
|
||||
int value = k & 3;
|
||||
int rep = rle.charAt(k) - 32;
|
||||
for (int i = 0; i < rep; ++i) {
|
||||
lookup[offset++] = value;
|
||||
}
|
||||
}
|
||||
// SIGNED
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
lookup[1792 + i] = 1;
|
||||
lookup[2032 + i] = 6;
|
||||
}
|
||||
lookup[1792] = 0;
|
||||
lookup[2047] = 7;
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
lookup[1536 + i] = lookup[1792 + i] << 3;
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
unpackLookupTable(LOOKUP, UTF_MAP, UTF_RLE);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,160 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Tests for {@link Decode}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class DecodeTest {
|
||||
|
||||
static byte[] readUniBytes(String uniBytes) {
|
||||
byte[] result = new byte[uniBytes.length()];
|
||||
for (int i = 0; i < result.length; ++i) {
|
||||
result[i] = (byte) uniBytes.charAt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] decompress(byte[] data, boolean byByte) throws IOException {
|
||||
byte[] buffer = new byte[65536];
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(data);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
BrotliInputStream brotliInput = new BrotliInputStream(input);
|
||||
if (byByte) {
|
||||
byte[] oneByte = new byte[1];
|
||||
while (true) {
|
||||
int next = brotliInput.read();
|
||||
if (next == -1) {
|
||||
break;
|
||||
}
|
||||
oneByte[0] = (byte) next;
|
||||
output.write(oneByte, 0, 1);
|
||||
}
|
||||
} else {
|
||||
while (true) {
|
||||
int len = brotliInput.read(buffer, 0, buffer.length);
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
output.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
brotliInput.close();
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
private void checkDecodeResource(String expected, String compressed) throws IOException {
|
||||
byte[] expectedBytes = readUniBytes(expected);
|
||||
byte[] compressedBytes = readUniBytes(compressed);
|
||||
byte[] actual = decompress(compressedBytes, false);
|
||||
assertArrayEquals(expectedBytes, actual);
|
||||
byte[] actualByByte = decompress(compressedBytes, true);
|
||||
assertArrayEquals(expectedBytes, actualByByte);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() throws IOException {
|
||||
checkDecodeResource(
|
||||
"",
|
||||
"\u0006");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testX() throws IOException {
|
||||
checkDecodeResource(
|
||||
"X",
|
||||
"\u000B\u0000\u0080X\u0003");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testX10Y10() throws IOException {
|
||||
checkDecodeResource(
|
||||
"XXXXXXXXXXYYYYYYYYYY",
|
||||
"\u001B\u0013\u0000\u0000\u00A4\u00B0\u00B2\u00EA\u0081G\u0002\u008A");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testX64() throws IOException {
|
||||
checkDecodeResource(
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"\u001B\u003F\u0000\u0000$\u00B0\u00E2\u0099\u0080\u0012");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUkkonooa() throws IOException {
|
||||
checkDecodeResource(
|
||||
"ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, "
|
||||
+ "pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies.",
|
||||
"\u001Bv\u0000\u0000\u0014J\u00AC\u009Bz\u00BD\u00E1\u0097\u009D\u007F\u008E\u00C2\u0082"
|
||||
+ "6\u000E\u009C\u00E0\u0090\u0003\u00F7\u008B\u009E8\u00E6\u00B6\u0000\u00AB\u00C3\u00CA"
|
||||
+ "\u00A0\u00C2\u00DAf6\u00DC\u00CD\u0080\u008D.!\u00D7n\u00E3\u00EAL\u00B8\u00F0\u00D2"
|
||||
+ "\u00B8\u00C7\u00C2pM:\u00F0i~\u00A1\u00B8Es\u00AB\u00C4W\u001E");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMonkey() throws IOException {
|
||||
checkDecodeResource(
|
||||
"znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmz"
|
||||
+ "xc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxc"
|
||||
+ "nzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqeriou"
|
||||
+ "pqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyio"
|
||||
+ "wtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuri"
|
||||
+ "ouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwot"
|
||||
+ "ueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfh"
|
||||
+ "klasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfa"
|
||||
+ "sdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjka"
|
||||
+ "ghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj",
|
||||
"\u001BJ\u0003\u0000\u008C\u0094n\u00DE\u00B4\u00D7\u0096\u00B1x\u0086\u00F2-\u00E1\u001A"
|
||||
+ "\u00BC\u000B\u001C\u00BA\u00A9\u00C7\u00F7\u00CCn\u00B2B4QD\u008BN\u0013\b\u00A0\u00CDn"
|
||||
+ "\u00E8,\u00A5S\u00A1\u009C],\u001D#\u001A\u00D2V\u00BE\u00DB\u00EB&\u00BA\u0003e|\u0096j"
|
||||
+ "\u00A2v\u00EC\u00EF\u0087G3\u00D6\'\u000Ec\u0095\u00E2\u001D\u008D,\u00C5\u00D1(\u009F`"
|
||||
+ "\u0094o\u0002\u008B\u00DD\u00AAd\u0094,\u001E;e|\u0007EZ\u00B2\u00E2\u00FCI\u0081,\u009F"
|
||||
+ "@\u00AE\u00EFh\u0081\u00AC\u0016z\u000F\u00F5;m\u001C\u00B9\u001E-_\u00D5\u00C8\u00AF^"
|
||||
+ "\u0085\u00AA\u0005\u00BESu\u00C2\u00B0\"\u008A\u0015\u00C6\u00A3\u00B1\u00E6B\u0014"
|
||||
+ "\u00F4\u0084TS\u0019_\u00BE\u00C3\u00F2\u001D\u00D1\u00B7\u00E5\u00DD\u00B6\u00D9#\u00C6"
|
||||
+ "\u00F6\u009F\u009E\u00F6Me0\u00FB\u00C0qE\u0004\u00AD\u0003\u00B5\u00BE\u00C9\u00CB"
|
||||
+ "\u00FD\u00E2PZFt\u0004\r\u00FF \u0004w\u00B2m\'\u00BFG\u00A9\u009D\u001B\u0096,b\u0090#"
|
||||
+ "\u008B\u00E0\u00F8\u001D\u00CF\u00AF\u001D=\u00EE\u008A\u00C8u#f\u00DD\u00DE\u00D6m"
|
||||
+ "\u00E3*\u0082\u008Ax\u008A\u00DB\u00E6 L\u00B7\\c\u00BA0\u00E3?\u00B6\u00EE\u008C\""
|
||||
+ "\u00A2*\u00B0\"\n\u0099\u00FF=bQ\u00EE\b\u00F6=J\u00E4\u00CC\u00EF\"\u0087\u0011\u00E2"
|
||||
+ "\u0083(\u00E4\u00F5\u008F5\u0019c[\u00E1Z\u0092s\u00DD\u00A1P\u009D8\\\u00EB\u00B5\u0003"
|
||||
+ "jd\u0090\u0094\u00C8\u008D\u00FB/\u008A\u0086\"\u00CC\u001D\u0087\u00E0H\n\u0096w\u00909"
|
||||
+ "\u00C6##H\u00FB\u0011GV\u00CA \u00E3B\u0081\u00F7w2\u00C1\u00A5\\@!e\u0017@)\u0017\u0017"
|
||||
+ "lV2\u00988\u0006\u00DC\u0099M3)\u00BB\u0002\u00DFL&\u0093l\u0017\u0082\u0086 \u00D7"
|
||||
+ "\u0003y}\u009A\u0000\u00D7\u0087\u0000\u00E7\u000Bf\u00E3Lfqg\b2\u00F9\b>\u00813\u00CD"
|
||||
+ "\u0017r1\u00F0\u00B8\u0094RK\u00901\u008Eh\u00C1\u00EF\u0090\u00C9\u00E5\u00F2a\tr%"
|
||||
+ "\u00AD\u00EC\u00C5b\u00C0\u000B\u0012\u0005\u00F7\u0091u\r\u00EEa..\u0019\t\u00C2\u0003"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFox() throws IOException {
|
||||
checkDecodeResource(
|
||||
"The quick brown fox jumps over the lazy dog",
|
||||
"\u001B*\u0000\u0000\u0004\u0004\u00BAF:\u0085\u0003\u00E9\u00FA\f\u0091\u0002H\u0011,"
|
||||
+ "\u00F3\u008A:\u00A3V\u007F\u001A\u00AE\u00BF\u00A4\u00AB\u008EM\u00BF\u00ED\u00E2\u0004K"
|
||||
+ "\u0091\u00FF\u0087\u00E9\u001E");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUtils() {
|
||||
new Context();
|
||||
new Decode();
|
||||
new Dictionary();
|
||||
new Huffman();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Collection of static dictionary words.
|
||||
*
|
||||
* <p>Dictionary content is loaded from binary resource when {@link #getData()} is executed for the
|
||||
* first time. Consequently, it saves memory and CPU in case dictionary is not required.
|
||||
*
|
||||
* <p>One possible drawback is that multiple threads that need dictionary data may be blocked (only
|
||||
* once in each classworld). To avoid this, it is enough to call {@link #getData()} proactively.
|
||||
*/
|
||||
public final class Dictionary {
|
||||
private static volatile ByteBuffer data;
|
||||
|
||||
private static class DataLoader {
|
||||
static final boolean OK;
|
||||
|
||||
static {
|
||||
boolean ok = true;
|
||||
try {
|
||||
Class.forName(Dictionary.class.getPackage().getName() + ".DictionaryData");
|
||||
} catch (Throwable ex) {
|
||||
ok = false;
|
||||
}
|
||||
OK = ok;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setData(ByteBuffer data) {
|
||||
if (!data.isDirect() || !data.isReadOnly()) {
|
||||
throw new BrotliRuntimeException("data must be a direct read-only byte buffer");
|
||||
}
|
||||
Dictionary.data = data;
|
||||
}
|
||||
|
||||
public static ByteBuffer getData() {
|
||||
if (data != null) {
|
||||
return data;
|
||||
}
|
||||
if (!DataLoader.OK) {
|
||||
throw new BrotliRuntimeException("brotli dictionary is not set");
|
||||
}
|
||||
/* Might have been set when {@link DictionaryData} was loaded.*/
|
||||
return data;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,38 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Tests for {@link Dictionary}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class DictionaryTest {
|
||||
|
||||
private static long crc64(ByteBuffer data) {
|
||||
long crc = -1;
|
||||
for (int i = 0; i < data.capacity(); ++i) {
|
||||
long c = (crc ^ (long) (data.get(i) & 0xFF)) & 0xFF;
|
||||
for (int k = 0; k < 8; k++) {
|
||||
c = (c >>> 1) ^ (-(c & 1L) & -3932672073523589310L);
|
||||
}
|
||||
crc = c ^ (crc >>> 8);
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetData() {
|
||||
assertEquals(37084801881332636L, crc64(Dictionary.getData()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,386 +0,0 @@
|
|||
/* Copyright 2018 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Tests for {@link Decode}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class EagerStreamTest {
|
||||
|
||||
private static final byte[] DATA = {
|
||||
31, 118, -122, 17, -43, -92, 84, 0, -76, 42, -80, -101, 95, -74, -104, -120, -89, -127, 30, 58,
|
||||
-4, 11, 91, -104, -99, -81, 44, 86, 61, 108, -74, -97, 68, 32, -120, -78, 97, -107, 88, -52,
|
||||
-22, -55, -8, -56, -106, -117, 49, 113, -106, -82, -43, -12, -11, -91, -66, 55, 68, 118, -127,
|
||||
-77, -104, -12, 103, -14, -94, -30, -112, 100, 79, -72, -42, 121, 62, -99, 76, -39, -89, 42, 58,
|
||||
-110, 91, 65, 32, -102, -113, 49, 4, 73, 60, 122, -106, 107, 16, -123, 30, -97, 90, -102, -83,
|
||||
-65, -90, 34, 26, -26, 52, 75, -118, 43, -47, -47, 52, 84, -10, -121, -68, -2, 20, 80, 101, 53,
|
||||
101, -119, -17, -111, -75, -21, -66, -96, -80, -114, 4, -65, 124, -89, -3, -25, -25, -21, -35,
|
||||
-15, -114, 55, 14, -76, -68, 71, 9, 123, 46, 78, 67, -18, -127, 70, -93, -128, -44, -87, 3, 36,
|
||||
-107, -3, 62, 83, 75, -123, -125, -11, 50, 46, -68, 80, 54, 9, -116, -29, 82, -14, -87, -94, 92,
|
||||
-88, -86, -18, -1, 22, 3, 46, -98, -128, -27, 121, -56, 88, -37, 85, -43, 61, -60, 12, -122,
|
||||
107, -64, -27, -45, -110, 123, 60, 99, 108, 46, -29, -77, 76, 65, 100, 92, -104, 40, 63, 19, 36,
|
||||
-89, 80, -39, 37, -95, -74, 97, 90, -109, 54, 105, -10, -38, 100, 95, 27, 36, 33, -60, 39, 100,
|
||||
32, -18, 93, -46, -99, 103, 127, -91, -62, 82, 76, 56, -66, -110, -16, 83, -116, -76, -9, -47,
|
||||
-5, -32, -65, 111, 0, 55, 47, -60, -95, -56, -100, 65, 125, 38, 77, 38, -32, -62, 55, 119, 10,
|
||||
120, -69, 33, -111, -62, -87, 17, 102, -95, -106, 26, -50, -16, -109, 94, 83, -79, 90, 2, 42,
|
||||
-47, 37, -124, 114, -68, 6, 104, -65, 38, -108, -114, -110, 73, -95, -83, -90, -86, -36, -48,
|
||||
-63, -97, -120, -25, -53, 93, -77, -50, 59, -74, -9, 36, 85, 11, 76, 95, 74, -61, -9, 116, -14,
|
||||
-38, 73, 78, 44, -92, 58, -27, -54, 38, 81, 50, -36, -46, -117, 126, 89, 53, -37, -58, -12, 61,
|
||||
77, -56, -85, -21, -128, 43, -111, 14, 54, 57, 116, 52, -85, 70, 88, -72, -26, 54, 109, -70,
|
||||
-84, -13, -1, -54, 91, 81, 101, -65, 49, -48, -16, 26, -115, -39, 100, -21, 105, -121, 38, 72,
|
||||
-115, 104, -100, 36, 120, 15, -109, 115, 64, 118, -68, -14, -26, -57, -71, 9, -118, -113, 15,
|
||||
94, 108, 114, 109, -14, -80, -31, -57, -6, 57, 111, -36, -92, -25, -23, -71, -61, 120, 93, -65,
|
||||
104, -123, -53, 35, -77, -8, -23, -31, 99, -3, 73, 75, 98, -2, -94, 73, 91, -109, -38, -78,
|
||||
-106, -121, -17, -21, 55, 45, -26, -7, -93, 38, 59, -90, -116, 3, -68, -2, -110, 19, -96, 28,
|
||||
-23, -39, 102, 99, 8, -82, -41, 63, 88, -70, 115, -123, -11, 111, 92, 47, -12, -16, -70, -2,
|
||||
-29, 101, 61, -45, -57, 54, 24, -125, 20, -37, -75, 89, -56, 52, 125, 22, -68, -63, 105, -91,
|
||||
-20, 91, 56, -99, -56, 35, -77, -78, -24, -79, 57, 5, -55, 101, -127, 75, -35, -113, -51, -103,
|
||||
79, 102, 16, -124, -79, -128, -45, -65, -84, -97, -91, -90, -105, 76, 90, -93, 90, -49, -41,
|
||||
104, 44, 81, -37, -84, 103, -120, -51, 79, -43, -114, -101, 38, -78, -94, -1, 15, 109, -62, 34,
|
||||
-65, -127, 98, 32, 46, -72, 70, 58, -61, -55, 90, 30, -103, 5, 109, -105, -119, 81, 92, -40,
|
||||
-75, -23, -77, 36, 18, 62, -33, -51, -38, -19, -12, 89, -101, 117, 94, 71, 127, -43, 54, 115,
|
||||
-67, 34, -83, -115, 127, 127, 42, 126, -121, -121, -40, 56, -113, 60, -27, 30, 44, -21, 98,
|
||||
-123, -14, 91, -69, 15, -81, 119, -101, 25, -73, 40, 105, 26, -86, -31, 86, -75, 74, 94, -74,
|
||||
19, -4, -20, 69, 24, 43, -5, -91, 6, -89, 52, 77, -65, -71, 82, -81, -52, 22, -61, -15, 51, 22,
|
||||
1, 70, -43, -3, -39, -27, 123, -13, -127, -86, 65, 51, 45, 127, -101, -27, -3, -44, -34, 75, 69,
|
||||
77, 71, -34, 7, -51, 93, -83, -84, -57, -38, -100, 59, -105, -1, 44, -47, 63, 96, -127, 32, -63,
|
||||
16, 80, -64, -127, 6, 54, 12, 44, 28, 48, -128, 4, 10, -104, 64, 3, 11, -47, 59, -79, -125, 52,
|
||||
-16, -78, -66, 19, -6, -33, -107, -10, -4, -42, 102, -31, -32, 99, 115, -22, -96, -45, -112, 28,
|
||||
126, -44, -4, -47, -99, 127, -84, 37, -112, -34, 36, 1, -68, -14, -16, 55, 83, -99, 120, -69,
|
||||
-30, 89, 48, 126, -80, -43, 15, 13, -18, 14, -4, -126, -120, -118, -11, 100, 16, 76, 17, 54,
|
||||
-75, 114, 101, 37, 121, -23, -65, 39, 94, -48, -78, 67, -61, 75, 48, 23, -127, 83, -124, 95, -5,
|
||||
67, 13, 87, 18, -2, 117, -36, -121, 115, -112, -107, -54, -36, 14, -4, -68, 35, 32, 79, -118,
|
||||
81, 94, -56, -110, 37, -84, -121, 72, -7, -52, -40, -44, -1, 73, 123, 12, 42, -67, -87, 63, -2,
|
||||
-100, 29, -41, 112, 98, -125, 88, 97, -56, 90, 7, -40, -111, -126, 74, 121, -95, -45, -69, 48,
|
||||
-98, 18, -20, -124, 3, 46, -5, 26, 24, -79, 109, 4, 43, 60, 97, 96, -76, -21, 95, -52, -40, -45,
|
||||
2, -103, -107, -9, 79, -79, -82, -73, -51, -74, -10, 81, -77, 111, -96, -41, -120, -38, 24, -87,
|
||||
93, -41, 64, 72, 57, -81, -32, 60, -79, 36, -84, -89, -7, -25, 81, -98, 36, -22, -69, 86, 123,
|
||||
120, -16, -113, -70, 47, -125, 2, 97, 78, -91, 102, 120, -91, 5, -71, 39, 116, -12, -79, -29,
|
||||
-9, 87, -5, -37, 87, -73, 116, -15, -10, -106, -49, -3, -21, 5, 120, 47, 72, -40, 79, -3, 85,
|
||||
-84, -87, 57, -83, -67, -64, 122, -39, 36, 70, -27, 71, -73, 42, -100, -99, 124, -90, 90, -29,
|
||||
-54, -115, 7, 89, -51, 9, -43, 32, 79, -104, 127, -38, 7, 93, -80, -124, 27, 96, 54, -51, -7,
|
||||
57, 57, 63, 21, 110, 70, 122, 76, 51, 124, 78, -5, 126, -100, -98, 116, 59, 125, -106, -113,
|
||||
-111, -128, 92, 43, -19, -2, 105, -90, 96, -116, -116, -30, 115, -20, -106, 64, -108, -111, 94,
|
||||
-9, -123, 52, -71, -88, -84, 87, -25, -54, -117, -2, -29, 29, -85, -22, -20, -94, -25, 98, 101,
|
||||
114, 80, -55, -51, 97, 99, 117, -86, 2, 79, 48, 110, 44, -94, -127, -85, 61, -95, 30, -91, -125,
|
||||
83, 113, -93, -4, -126, -98, -93, -68, -99, -70, -37, -73, -90, 4, 53, -2, 78, -35, 101, 42, -6,
|
||||
-3, 106, -117, -127, 48, 31, 88, 117, 116, 106, -98, -23, -117, -7, -57, -128, -118, -117, -118,
|
||||
115, 30, -61, 6, -38, -114, -103, 37, 53, -4, -100, -121, 98, -110, -113, 2, -20, 26, -88, -118,
|
||||
19, -71, 39, -54, -11, -28, 47, 28, 89, 35, -13, -20, -48, 14, -6, -91, -85, -119, -7, 116, 112,
|
||||
114, 41, 44, -1, -39, 60, -85, -54, 101, -119, 95, -77, -64, -121, 47, 75, -78, -30, -66, -38,
|
||||
-15, 98, 14, 82, -60, 85, -90, -78, 112, -7, 64, 5, 28, 64, 41, -64, 57, 85, 21, 122, -52, 90,
|
||||
70, -73, 17, 47, -125, 40, -45, -7, -91, 100, -21, -120, -51, 21, 65, 31, 110, -105, -79, -80,
|
||||
105, -43, 73, -61, 45, -30, -4, 83, 95, 3, 109, 55, -92, 120, 74, -36, -111, 54, -26, 76, -69,
|
||||
7, -20, 55, 4, 70, -124, -31, -32, 127, -63, -58, 73, 106, 109, -41, -45, 96, 30, 63, 14, 8, 16,
|
||||
-88, 69, -115, -17, -14, -116, 115, -88, 119, -65, 16, -64, -112, -73, -10, -46, -7, 113, 5, 54,
|
||||
-38, -47, -18, 106, 23, 12, -117, 120, -107, 121, -62, -35, -6, -56, 112, 81, 3, 5, 31, -11,
|
||||
-92, -85, -29, 102, 43, 108, 88, -69, 55, -74, 110, 97, -128, 29, -63, -114, -19, 77, 123, 23,
|
||||
76, 81, 57, 51, 117, -74, -1, 74, 84, 70, 86, -109, -127, 122, 10, 9, 23, 71, 110, -116, -30,
|
||||
-85, -104, 2, 40, -62, 20, 46, 8, 95, 46, 13, 113, -83, 124, 33, 38, 105, -99, 72, -62, -80,
|
||||
-16, -118, 92, -66, -14, -124, 112, 79, 103, 53, -127, 61, -31, -92, 92, -42, -37, -37, -24,
|
||||
-116, 2, -81, 40, 46, -44, 23, -68, -113, 88, 92, 95, 11, 118, 98, 19, -80, -102, 96, 73, -20,
|
||||
47, -105, -120, -74, -83, -77, -87, -59, -97, 112, 99, -52, 80, 116, -119, -44, 18, 62, 108, 73,
|
||||
-34, 70, 28, 73, 81, -26, 87, -125, -55, 64, -53, -73, 114, -3, -45, -109, 19, -2, 68, 119, 14,
|
||||
26, 72, 19, 13, -121, -98, 26, -52, 85, 34, 17, -95, -7, 20, -12, 106, -11, 104, 20, -106, -42,
|
||||
-26, 107, -106, 112, 103, -53, -62, 13, -58, -23, 23, 65, -104, -55, -90, 107, 55, -77, -25,
|
||||
-125, 63, -61, -21, 117, -102, -70, -93, -67, -45, -61, 18, -63, 7, -127, 90, 16, -25, 116, 80,
|
||||
35, 105, 80, -93, 105, -44, 114, -126, -103, 88, -102, -76, -94, -66, 69, -35, 22, 36, 95, -55,
|
||||
22, 43, 78, -111, 109, 72, 104, -49, -9, -48, 59, 102, -54, -43, -128, 111, 127, -9, 35, 23,
|
||||
-79, 40, -122, -52, 36, -81, -4, -102, -2, -62, 53, -111, -117, 40, 122, -95, 55, 32, -127, -9,
|
||||
-91, 79, -109, -81, -3, 98, -78, 56, -119, 69, -41, 76, -102, 18, 90, -15, 12, -60, 86, -106,
|
||||
34, -118, -43, -13, 61, -106, -56, 48, 27, -15, -70, -41, 127, 61, -2, -80, -13, 86, 28, 91,
|
||||
-10, -8, 98, -20, 54, 122, -116, -55, -70, -94, 54, -64, 71, 102, -106, -1, 99, -73, -71, -18,
|
||||
-11, 56, 11, -27, -5, 11, -86, 126, 8, 46, -21, 63, -66, -43, 88, 46, -113, -5, 113, 26, -9,
|
||||
-32, 18, -3, -6, -38, 81, 38, -110, 111, 97, 34, 65, 114, -71, -118, 9, -110, -109, -61, -113,
|
||||
31, -82, -102, -127, 16, -7, -16, -11, -87, -76, -41, -52, 58, -116, 100, 102, -127, 6, 127, 64,
|
||||
14, 110, 112, 43, 44, 87, 42, -118, -119, -39, 64, -7, 57, 16, 2, -69, -12, -54, -94, 36, -48,
|
||||
123, -119, 82, 46, 26, -62, 30, 97, -17, 34, 80, 32, -15, 116, -96, -3, 33, 34, 51, 59, -63,
|
||||
-100, -7, -79, -126, -21, -15, -18, -113, 30, -25, 107, -25, -125, 53, 82, -15, -80, 96, -24,
|
||||
-47, 94, -25, -109, -94, 114, -62, 112, -104, 26, -107, -68, -14, -36, -9, -89, 27, -75, 62, 62,
|
||||
-20, -125, -77, -57, -127, 80, 58, -118, 63, -27, -82, -126, 74, -23, -91, -28, -95, 8, -122,
|
||||
-73, 28, -87, -74, 80, -15, -119, 14, 32, 124, 73, 15, 61, -32, -68, 81, 56, -119, 66, 105, 3,
|
||||
-15, 20, -86, 124, -70, -113, 100, -72, -117, -97, 127, 103, 16, 105, 8, 39, -128, -64, -47, 66,
|
||||
123, -110, 13, 123, -124, -24, 42, 102, -4, 47, 107, 125, 63, -52, -35, 113, -74, 13, 8, 17, 16,
|
||||
-106, -21, -69, 47, -3, 103, -2, 19, -100, 111, -11, 1, 112, 90, -38, -31, -45, -55, 25, 92,
|
||||
-122, 66, -18, -98, -82, -49, 119, -35, -128, 26, 60, -79, -23, 127, 82, -52, 115, 77, -109,
|
||||
-111, 17, -99, 31, 33, 41, 35, 87, -47, -126, -18, -25, 81, -71, 9, -72, -92, 64, -92, 23, 116,
|
||||
96, 40, 55, -87, 119, -105, 66, 49, 46, -10, 26, -25, -105, 127, -124, 86, -2, 39, 116, -108, 6,
|
||||
21, 15, 1, 75, -5, 101, 13, 57, 70, 126, -50, -97, 123, -73, -77, 53, -11, -73, 44, -99, 91, 85,
|
||||
21, -59, -1, 117, 64, -100, 47, 75, 93, 9, -4, 83, -55, 15, 99, 31, 43, -49, 15, -89, -115,
|
||||
-114, -50, -35, -19, -65, 122, -39, 92, -21, -3, -66, 8, -70, 107, -55, -86, -36, -23, -21, 80,
|
||||
-79, 48, 116, 57, -71, 33, -111, -68, -75, 37, 55, 39, 124, 96, -66, 10, 14, 118, 50, 85, -33,
|
||||
54, -101, -7, 21, 88, -122, 50, -92, 123, 37, 109, -60, -127, 26, 110, -20, -31, -66, -56, -24,
|
||||
47, -14, -60, -101, 69, -38, 78, 0, 44, -71, 108, 4, 25, -68, -106, 20, -40, -103, 108, -70,
|
||||
-56, 78, 12, 82, 81, 46, -105, -123, -46, -20, -127, -67, -77, 76, -74, 40, 105, 2, 27, 112,
|
||||
-107, -121, -53, 6, -88, -11, 26, 41, 64, -69, -44, 27, 47, 24, -31, -86, -4, 4, -46, 42, 50,
|
||||
-55, 37, -11, -95, 108, 54, 37, 67, 37, -14, -40, 41, 124, 22, 108, 99, 16, 55, 88, 19, 49, -87,
|
||||
27, 17, -68, -107, 15, -62, 84, 109, 72, -26, 71, 63, -17, -72, -63, -101, -8, 62, 24, -112,
|
||||
126, -102, -64, 29, -19, -75, 74, 29, 90, -90, 83, -22, 106, -27, -114, 56, -111, -33, 11, 3,
|
||||
-16, 94, 115, -97, 67, -78, 62, -93, -36, 60, -65, -54, 72, 70, 44, -77, 73, 29, -106, 38, 72,
|
||||
-37, -110, 79, -98, -15, -58, 96, -85, -68, -15, 73, 57, -127, 14, -123, -40, 70, 63, -64, 115,
|
||||
-63, 127, 94, 85, 52, 30, -62, 83, -30, -97, 82, 39, 2, 36, -50, 106, 116, 66, 104, -14, 73, 14,
|
||||
-106, -127, 11, 41, -27, 56, -99, -74, 55, 123, 124, 9, 46, 12, -97, -37, -10, 122, 124, -27,
|
||||
-64, 93, -70, 9, 119, 13, -9, -71, -118, 19, 50, -36, 114, 120, -24, -62, 40, 127, 9, -62, 84,
|
||||
57, 66, 91, -114, 120, -49, 63, 99, -73, -66, -64, 84, -31, 67, -52, 12, 38, -62, 37, -122, -50,
|
||||
-95, 24, 19, 54, -80, 57, -118, -84, 124, 90, 53, 72, 29, -123, 67, -65, 99, -58, -28, 20, -110,
|
||||
-103, 92, -91, -108, 23, -118, 44, 74, 76, -29, 94, -121, -37, -32, 107, -62, -67, -55, -45,
|
||||
-50, -44, 25, -77, -102, 90, -128, -31, -5, -64, 110, 122, 88, -18, -53, -85, 122, -11, 100,
|
||||
-106, 97, 59, -103, -110, 5, -16, 59, -126, -74, 9, -119, 115, 49, -73, -42, 32, 100, 59, -98,
|
||||
106, 55, -101, 87, 126, 59, -23, 106, -102, 100, -69, -46, 76, 53, -107, -119, -113, 104, 117,
|
||||
-27, 75, -32, 8, -81, -10, 50, 108, -32, 51, -79, -53, -2, 66, -9, 113, 14, 99, -100, -34, -21,
|
||||
13, 2, 45, -33, 0, -16, -64, -126, 69, -25, -34, 28, 105, -48, -38, 82, 12, 27, -71, 35, 13, 11,
|
||||
21, 26, -19, -4, 44, -52, -126, -63, -32, -84, -22, -63, -29, 96, -97, -82, -12, -53, 98, 41,
|
||||
-69, -38, 101, -31, 47, -9, 16, -10, 9, -36, -103, -91, -65, -36, -93, -45, 94, 110, 54, -94,
|
||||
68, -39, -116, -40, 61, -112, -91, -79, 98, -36, 87, 35, 88, -61, 125, 112, -84, 48, -38, 105,
|
||||
-92, 69, -68, 92, 0, 27, -72, -65, 97, 98, 66, 97, -74, 29, 46, -21, 102, 61, 120, -62, 38,
|
||||
-125, -60, -43, 4, 5, -27, 113, -43, 105, -22, -110, 68, 13, -14, -23, 18, 95, -79, -108, 87,
|
||||
19, -80, 16, 54, -121, 88, -64, -113, 73, 3, -20, 17, 0, 26, -88, -49, -2, 21, 120, -105, -85,
|
||||
-113, 76, 106, 37, -13, -75, 29, -127, 10, -17, -53, -124, 24, 37, -31, 26, -1, 109, 88, -88,
|
||||
-37, -51, -32, -125, 48, -40, 123, -108, 55, -120, -62, -91, 47, 62, -127, -25, 99, 68, 22, -40,
|
||||
58, 119, -31, -93, -122, 39, -92, 25, -127, -42, 97, 69, -6, 110, -61, -21, -94, 82, 123, -93,
|
||||
-51, -90, 50, -96, 127, -32, 125, -76, 117, 75, -52, 79, 110, -51, -15, -81, 49, 62, 118, 120,
|
||||
-27, 22, 84, -22, 77, -105, 87, -7, -23, 47, -8, 108, 82, -12, 84, -52, -85, 68, -89, -24, -32,
|
||||
6, -34, -83, 80, 44, 12, -51, 50, 74, -121, -106, 6, 85, 32, 42, 76, -59, -52, -99, 102, 108,
|
||||
-127, -49, 0, 60, 62, 2, 13, -19, -92, -41, -69, 55, -70, 94, 23, 36, 89, 70, -115, -51, 26,
|
||||
-95, 13, -69, 42, 62, 59, -24, -63, -50, -6, -86, -97, -115, -58, -107, 69, -12, -109, 73, 4,
|
||||
63, 12, 32, 13, -123, -72, -41, -7, -81, 37, -91, -128, 109, -79, -80, 88, -22, 108, 126, 103,
|
||||
27, -29, -81, 52, 55, -91, -13, -43, -75, -59, 80, -6, 6, 83, -103, -64, 8, 63, -34, -59, 21,
|
||||
55, -115, 62, 77, 30, -50, -71, -66, 87, 99, -47, 0, 124, 76, 120, 79, -12, 54, -16, -98, -72,
|
||||
-41, -66, -14, 114, -27, 108, 57, -49, 107, -73, 90, 107, -103, 25, -107, 112, -119, -54, 106,
|
||||
-54, -8, -13, -81, -62, 92, -84, 113, 77, 74, -63, 104, 92, -94, -128, -43, -54, -71, 117, 27,
|
||||
14, 98, 52, 119, -93, -77, -80, -46, 88, 35, 123, 86, 87, 122, 62, 108, 19, 27, 111, 2, 62, -67,
|
||||
89, 14, -82, 41, 123, -117, 74, 109, -124, -115, 15, 123, -65, 42, -81, -105, 19, -30, 86, -72,
|
||||
84, 63, -109, 34, -65, -127, 6, -104, 77, 103, -111, 90, 16, 31, -74, -33, 122, 58, 52, 10, 2,
|
||||
65, 72, 68, 79, 52, 31, -19, 100, -86, 21, -49, 116, 101, 82, 111, -96, -76, 67, -40, -62, -15,
|
||||
-79, 109, -58, 6, 11, -91, -29, 65, 21, 75, 74, -28, 21, 103, 46, 48, -42, 51, -110, 80, -95,
|
||||
-102, -9, 8, -95, 102, 102, 16, 105, 103, 92, -106, -109, 77, 93, 32, -12, -25, 5, 17, -86, -34,
|
||||
58, -50, 55, 63, -8, -72, 3, 26, 91, 72, 71, -77, 94, 91, 39, 45, 7, 0, 30, -45, -100, 35, 43,
|
||||
-41, -72, 16, -103, -115, -4, 51, 39, -23, -89, -84, 105, 94, -91, -88, 82, 123, -26, 51, -16,
|
||||
97, 47, -39, 35, 46, -89, 74, 7, -80, 116, -21, 82, -84, -13, -99, 31, -58, -93, 36, 99, 36, 44,
|
||||
-65, 45, 94, -91, -41, 115, -10, 116, -67, 45, 19, -20, 113, -62, 111, 124, 108, 71, -121, -64,
|
||||
122, -121, -105, 114, 115, -126, -93, -108, -113, -1, -80, -86, 116, -111, -29, 53, -76, 87, 19,
|
||||
45, -30, 91, 91, -7, -49, 12, 112, -8, -26, 82, 58, -82, -76, 119, -50, 14, 85, 113, 20, 48,
|
||||
-102, 37, 24, -120, -107, -52, 67, -44, -92, -79, -40, 28, 21, 55, 116, 88, 19, -49, -78, 86,
|
||||
-89, 74, -4, 118, 75, 11, -103, -127, -47, -16, -77, -78, 8, 2, -88, 50, 23, -99, 102, -100,
|
||||
-116, -99, -109, -112, -115, 78, 55, -39, -84, 100, -91, -101, 73, -9, 39, -23, 62, -125, -106,
|
||||
-55, 119, -118, 114, -33, -99, 20, -53, 91, 115, 47, -93, 51, -99, -9, 92, -71, 120, 57, -44,
|
||||
-87, -11, 108, 30, 43, -4, 118, 90, 126, -54, -99, -47, -2, -61, -3, -62, 45, 92, -70, -105, 30,
|
||||
98, 112, -94, 56, 35, -22, 32, -93, -6, -36, -5, -77, -78, 120, 45, 104, 69, -49, -30, 39, 75,
|
||||
38, -94, -12, 34, 34, -44, 48, -100, 74, 34, 69, 94, -12, 73, 27, -111, 90, 33, -38, 93, 40,
|
||||
-16, 89, 26, -110, -116, -10, -65, 85, -57, 48, -86, 121, 118, -41, 63, 33, 109, -78, -26, 122,
|
||||
111, -115, -52, 95, 26, -70, -14, -86, -80, -27, -6, 12, -44, 123, 28, 93, -74, 14, -124, 87,
|
||||
-28, -12, 111, -117, -83, 48, -41, -3, 60, -51, -91, 118, 54, 110, 18, -2, -120, -66, 46, -35,
|
||||
-91, 106, 94, -91, -11, 41, -92, -22, 96, -113, -109, 105, 56, -80, 17, -118, 124, -16, 30, 30,
|
||||
117, 126, -99, -106, -69, -28, 85, 85, -41, 21, -95, -85, -112, -125, -45, 69, 10, -34, -120,
|
||||
33, -58, 120, 51, -22, -7, 31, -34, 4, 55, -102, -70, 118, -83, 49, 111, -45, -9, 69, -95, -66,
|
||||
116, -3, 104, -61, 17, 21, -20, 121, 117, 127, -70, 5, 89, -89, 51, 15, 64, 126, -73, 97, 90,
|
||||
119, -22, -37, -54, 52, -33, 26, -54, 75, 79, 73, 100, 44, 3, 53, -25, 49, -123, -101, -80, -54,
|
||||
-81, -32, 88, 49, -14, -4, 18, 42, 52, -65, -33, 68, 83, -89, -11, 57, 102, 71, 122, 74, -92,
|
||||
-44, -94, -108, 14, 104, -107, -124, -63, 8, 32, 85, -18, -16, -91, -63, -38, 27, -108, 24, 19,
|
||||
-33, 53, 70, -32, 41, 38, -77, -30, 89, 28, -15, -89, -86, 32, 51, 28, 67, 124, -96, -103, -34,
|
||||
-113, 22, 15, -8, 104, -38, -56, 65, -96, -111, 104, -9, -38, 107, 55, 112, 47, 99, 50, -18, 90,
|
||||
-69, 116, 80, 95, 52, -27, -98, 6, 12, -11, 124, -120, -96, -91, 118, -51, -120, 90, -92, -104,
|
||||
-83, -73, 84, 61, 78, -39, -99, 33, 58, -45, -14, 127, -20, -44, 125, 21, -26, -21, -36, 51, 73,
|
||||
71, 73, -17, 83, 11, 107, 91, 36, -65, -24, 56, 117, 114, -126, -34, 1, 120, 66, -50, 14, 91,
|
||||
97, -35, 75, 87, 123, -53, 63, -38, -74, -62, -117, -45, -40, 125, -5, 53, 50, 0, -110, 7, 7,
|
||||
45, 37, -71, -21, 70, -95, -60, 74, -55, -54, -96, 115, -62, -32, -3, -121, -18, 27, -107, 49,
|
||||
-39, 58, -39, 91, 107, 65, -99, -64, -19, -10, -126, 38, -40, -112, 0, 16, 107, -59, 119, -70,
|
||||
79, 49, -18, -76, -22, -38, -98, 35, -99, 61, 67, -100, 29, -104, -17, 22, 108, 105, 88, -114,
|
||||
-65, 84, 99, -69, -84, -87, -81, -28, 68, -66, 3, 69, -69, 83, 16, 61, -102, 50, 67, 46, -98,
|
||||
-77, -40, -78, 48, 68, -85, 123, -92, 37, 14, 75, 13, -23, -110, 23, 26, 90, -81, -1, -109, 85,
|
||||
121, -68, -55, -7, 21, -81, -35, 41, 3, -72, -52, 36, 35, -83, -9, -81, -124, -104, 31, 54, 8,
|
||||
-32, 80, 73, 89, -41, 116, 127, -110, 68, -82, 82, -79, 105, 113, -110, -70, 121, -24, -54, 37,
|
||||
-12, -70, -77, 15, 14, 105, -19, 16, -6, 73, 102, 121, -116, -62, 54, 65, 119, 43, 60, -79, -66,
|
||||
-17, 1, 97, -1, -11, -5, 104, 10, 59, -108, 21, -8, 64, -71, -86, 14, -98, -87, -49, 30, -45,
|
||||
109, 43, -67, 10, -122, 25, 98, -102, 127, -27, -52, -61, -66, -47, 114, -94, -126, 4, 0, -65,
|
||||
-11, -51, -67, 84, -43, 44, 88, 53, -6, 124, 11, -123, 34, 12, 102, -13, -106, 47, 62, -71, 43,
|
||||
-65, 28, 37, 32, 80, 23, 6, 75, -103, 73, 112, 33, 84, -89, 12, -81, 42, 65, 58, 14, -102, 90,
|
||||
29, -116, 104, 107, -99, -1, -43, 122, 118, 88, -2, 117, 84, 1, -123, -2, 2, -32, -18, -122,
|
||||
-36, -58, 16, 76, 115, 27, -121, -2, -79, -44, -39, 33, -29, 33, -34, 55, 71, 61, 117, -22,
|
||||
-126, 51, 29, 55, -34, -48, 17, -57, 74, 71, -33, -50, 60, 41, -119, -93, -45, -127, -30, 104,
|
||||
35, 60, -117, -113, 81, -59, -39, -84, -39, -46, -106, 57, 77, 62, -11, -44, -87, 71, 35, -117,
|
||||
-87, -77, -98, 68, -29, -121, -16, -16, 39, 48, -74, 23, 82, -62, 32, 62, 27, 125, 84, 39, -91,
|
||||
-91, -93, 76, -24, 98, 123, -58, -114, 17, 28, 93, -17, 74, 92, -17, 9, -86, -116, -72, 54, -74,
|
||||
71, 9, -97, -33, -20, -126, -50, 117, 102, 54, 123, 124, -70, 30, -102, 27, 23, 105, -40, -35,
|
||||
-89, -33, 89, 3, 44, 18, -15, 10, 116, -111, 1, -81, -31, -125, -102, 103, -93, -15, 72, 84, 19,
|
||||
-30, -17, -115, 99, 43, 5, -92, 52, 59, -55, -105, -128, 19, 8, -78, 43, 7, -55, -126, -106, 11,
|
||||
69, 118, 24, -128, -54, -86, 22, -121, -43, 69, -15, 96, 52, 52, 90, -118, -10, -58, 121, 63,
|
||||
-48, -13, 22, -101, 17, 42, -28, -54, -63, 121, -96, 111, 113, 103, 126, 37, -52, -40, -106,
|
||||
-104, 123, -48, -92, 83, 100, -70, -52, -59, -93, -116, -90, -93, 82, -117, 103, 52, -71, -42,
|
||||
57, 25, 57, -74, 71, 7, 32, 96, -60, 11, 121, 58, 71, 40, -92, 35, 88, -12, -109, -56, -122,
|
||||
-30, -118, 103, 65, -5, -90, -97, 103, -117, 66, -20, -42, -46, 67, -29, -23, 72, -97, 26, -54,
|
||||
-103, -76, -47, -71, 23, -83, -20, 95, 111, 101, -83, 106, -71, -70, -63, 55, -85, -41, 117, -9,
|
||||
37, 96, -71, -118, -44, -43, 2, 107, 113, -39, -107, 41, -13, 0, -87, 77, 83, 99, 68, -84, -6,
|
||||
-1, 67, 124, -57, 115, 29, 24, 26, -42, 104, 58, -87, -38, 12, -98, 11, 109, 62, 59, -66, -48,
|
||||
-20, 70, -111, 11, 120, 21, -58, -29, -76, 44, -7, 26, -119, -59, -87, 44, 122, 8, 114, -58,
|
||||
-109, -119, -63, -58, -51, 33, 35, -109, 81, 110, -90, 121, -21, 64, -60, 68, 18, 75, -82, -81,
|
||||
-103, -76, -116, 23, 53, 58, -41, -23, 49, -102, 81, 101, 39, -59, -91, -98, 111, 2, 65, 110,
|
||||
121, 5, 13, 97, -119, 109, 40, 82, 47, -51, 47, -57, 35, -109, 53, -42, 10, 3, -15, 122, -25,
|
||||
-67, -62, -121, -120, -31, 18, -20, 87, -88, 75, 95, -121, -93, 33, 61, -88, -96, 88, -69, -54,
|
||||
-121, -99, 49, 122, -53, -49, -125, 53, -79, -46, -128, 109, 125, -93, -83, 44, -101, 69, 68,
|
||||
-91, -17, 55, -13, -75, -80, 21, 32, -13, 40, 86, -65, 85, 80, -82, -38, -52, 110, -119, 100, 8,
|
||||
77, -23, 67, -41, 73, 27, 38, 9, -11, -32, -30, 75, -15, 67, -41, 46, 27, -89, 9, 117, -38, -14,
|
||||
-81, -4, 71, 113, -79, 81, -36, 63, 15, -70, 104, 34, -56, -39, 93, -34, -127, 90, -36, 73, 47,
|
||||
-76, 113, 55, 123, -92, 48, 116, 108, -123, 31, -67, -39, 3, -9, 6, 13, -17, -50, -125, 1, 105,
|
||||
121, 100, 79, 82, -85, 123, -33, -73, 54, -61, -113, 121, -110, 69, 119, 94, -112, -120, -34,
|
||||
-35, -104, -116, 44, 85, 109, -104, 127, 120, 87, 75, -48, -115, 74, 85, -47, -53, 16, -5, 92,
|
||||
67, -32, 12, 79, 109, 105, 5, -92, 51, 46, 96, -96, 63, 106, 82, -54, -95, 20, -60, -23, 48, -5,
|
||||
-128, 22, 23, -93, 93, -64, 35, 21, -121, -79, 59, -1, -50, 55, -7, -10, -85, 3, -7, 121, 98, 5,
|
||||
-19, 76, -78, -128, -47, -42, 61, -59, -46, -24, -16, -51, -48, 122, -26, 74, -91, 54, 53, 46,
|
||||
74, 25, -30, -74, 52, -22, 118, -103, -53, -113, 44, -19, 70, -86, 106, 72, -68, -86, 110, 34,
|
||||
-35, 57, -43, 32, -4, 14, 102, 25, -76, -84, -86, -83, -2, -107, -4, 49, -97, -83, -95, 6, 100,
|
||||
-73, 6, 34, 49, 59, 50, 30, -8, 6, -55, 24, -6, 67, -121, 115, 40, -50, -75, -46, -26, 111, -20,
|
||||
-75, -83, -16, -48, 65, -64, 119, 62, -59, 3, -12, 109, 0, -118, -94, 17, -51, 124, 63, 42, -3,
|
||||
44, 53, -81, -35, -33, -83, 115, -114, -4, -104, 44, 7, -81, -97, -102, 104, 29, -97, 70, 91, 3,
|
||||
88, 67, -127, 78, -92, -16, -34, -18, -81, -125, -38, 117, -78, -36, 9, 76, -85, 121, 2, 10,
|
||||
114, 65, -5, -29, -34, 101, 20, -108, 46, -90, -98, 85, -62, -51, 108, -72, -51, 44, 22, 112,
|
||||
121, 58, -58, 109, -96, 58, 103, 27, -88, -81, 99, -7, -33, -113, 64, -122, 115, 19, -93, 37,
|
||||
-19, 93, -98, 78, 115, 91, -88, -82, -36, 61, 90, 77, 27, 26, -116, 80, 90, 85, 6, -87, 59, 110,
|
||||
63, 20, -81, -127, -53, 18, -73, 39, 75, 79, -106, 29, -50, -13, 43, -99, -92, 109, 80, -83, 69,
|
||||
-102, 38, 90, -41, 48, -47, -93, 18, 116, 32, 90, -73, -96, 90, 49, 19, 73, -35, 60, 53, -72,
|
||||
-52, 84, 52, 27, -67, -114, 82, 79, -89, -80, -111, 124, -51, 80, 110, -76, 125, 18, -73, 44,
|
||||
-100, 118, -16, -64, -35, 22, -86, -116, -19, -101, -35, 42, 85, -83, 69, -65, 37, -104, -88,
|
||||
-108, -25, -9, 15, 91, -100, -86, 8, -75, -37, 103, 3, -69, -9, 114, -25, 25, -87, 118, -75,
|
||||
-115, -8, 74, 53, 73, 46, -22, -108, 30, 71, -96, 40, -76, 121, 71, -63, 95, 96, 113, -54, 87,
|
||||
1, -79, 2, -40, 11, 22, -118, -117, 94, -44, -112, -27, -86, 96, -4, -58, 121, -71, 54, -58,
|
||||
-71, -125, -65, 126, -116, -107, 125, -28, -74, 97, 15, -76, 59, -26, 58, -38, -39, 122, 55, 85,
|
||||
-109, -114, 75, 25, -74, 57, -78, -10, -76, -115, -12, 29, 84, 86, 97, 5, 116, -114, 62, -98,
|
||||
-36, 105, -119, -19, 12, 11, 49, 76, 21, 56, 1, 115, 115, 42, -67, 60, -40, 19, 38, 50, 33, 112,
|
||||
98, 123, -76, -74, 50, 66, 18, -61, -114, 36, -95, 92, 124, 20, -56, 29, -41, 28, -4, -106, 115,
|
||||
-83, 98, -47, 96, 87, -72, 96, -83, -93, 1, 112, -43, 59, -80, -24, 46, -45, 87, 92, -108, -78,
|
||||
101, -112, 111, -119, -67, 26, 97, 1, 36, -128, 120, 8, -20, 84, 107, -9, -104, 25, 0, -36, 58,
|
||||
111, 81, -83, 65, 42, 51, 61, -71, 118, 111, 29, -93, 39, -56, -72, -18, -53, 0, 34, -77, -59,
|
||||
112, -79, 51, 86, 82, -24, 64, -120, -1, -102, -3, 42, -93, 16, 38, 100, 39, -124, 92, -89, 31,
|
||||
94, -32, 40, 19, -8, 48, -83, -66, -68, 110, -72, 36, -38, -91, -63, 33, 35, -96, -121, -119,
|
||||
-59, 56, 89, -117, -123, -79, -68, 42, -4, -116, -108, -104, -84, -111, -26, 94, -38, 61, 94,
|
||||
-72, -85, -18, -30, 118, -14, -94, -74, -24, -21, -90, -83, -116, -38, -8, 9, -17, 72, -62, -78,
|
||||
-75, 47, -117, 109, 127, -87, -36, 53, 90, 16, -72, -50, 40, 87, 97, -51, -96, -55, -120, -32,
|
||||
-58, -21, 102, 117, -121, -98, 74, -67, 104, -122, 108, -3, -96, 64, -114, -3, 30, 48, -14, 44,
|
||||
-41, 91, 54, 58, 80, -13, -88, 121, 32, 122, 25, 24, 9, 72, 17, -1, -93, -66, 96, -84, 4, 37,
|
||||
69, 91, 64, 32, 46, 89, 7, -32, -120, 10, -38, -3, -59, -75, 14, 116, 115, 121, 99, 122, -95,
|
||||
107, 1, 65, 70, -45, 35, -52, -87, -56, 43, 121, 12, -93, -8, 83, -118, 15, -33, -67, 45, 74,
|
||||
-66, -31, -28, 5, 104, -13, 113, 19, -89, 105, 66, -82, 74, 54, -104, 69, 103, 86, 118, -44,
|
||||
-75, -47, 81, -75, 8, -32, -95, 121, 48, -121, -106, -88, -15, -52, -99, -78, 58, 113, 16, 71,
|
||||
-48, 76, 80, 81, 59, 43, -106, 27, -49, 2, -11, -71, -30, -80, -44, 62, -113, -20, 12, -60, -87,
|
||||
22, -30, 64, -120, 127, 121, 47, 127, 58, -98, -4, 79, -72, -117, 115, 52, 95, 40, -59, -125,
|
||||
-33, 125, -96, -93, -92, 17, -99, -85, 10, -119, 91, -115, -63, -32, -11, -102, -105, -93, 90,
|
||||
37, 94, -104, -47, -63, -94, 15, -34, 20, 73, -59, 85, -31, 6, 106, -67, 14, -125, 28, -63, 40,
|
||||
86, -68, 104, -22, 124, -27, -84, -13, 43, -45, -30, -95, 95, 16, 79, 23, -66, -78, -74, 43, 86,
|
||||
70, -95, 90, -65, -1, -58, 54, 12, 47, -47, 28, 91, -54, -19, -75, -43, 12, -108, 12, 71, 38,
|
||||
118, -8, 1, 42, -113, -6, 1, -93, 118, 67, -79, 25, -80, 118, 34, -29, 0, -23, 86, 53, -118, 89,
|
||||
112, 0, -61, -88, 76, -24, 59, -75, 23, -1, 64, -80, -52, -40, 34, -50, -19, -127, 57, 79, 43,
|
||||
92, -113, -96, 73, 0, 33, 122, 42, 104, -62, -66, -108, -104, 45, -120, 69, -3, -20, -113, -40,
|
||||
-70, -96, 72, -21, -95, 1, -16, -124, -87, 125, 56, -108, 7, -112, -104, 105, 80, -34, -93, 24,
|
||||
-6, 35, -38, 42, -4, 23, -112, 40, 45, 106, -72, 29, 44, -36, -61, -8, -93, -34, 3, -41, -26,
|
||||
121, 6, 100, -14, -112, -117, -15, -120, -92, 44, -43, 94, -13, 121, -59, -82, -68, 7, -19,
|
||||
-110, -121, -58, -118, -121, 92, -8, 33, -120, -28, -95, -31, -120, -62, 49, 51, 3, 68, 4, -56,
|
||||
51, -13, -90, 47, -16, -24, 63, 125, -11, -94, 99, 69, -84, -54, 127, 81, -120, 42, -47, -128,
|
||||
-13, 38, 115, 59, -112, -30, -9, -116, 121, 63, 111, 32, -116, -2, 0, -33, 79, -67, 90, -65,
|
||||
-108, -107, -5, -107, 11, -102, 91, 106, -42, 74, 45, -80, -65, 54, 36, 121, -125, -118, -34,
|
||||
-51, 36, -85, -78, 86, 121, -103, -39, 35, -76, 17, 59, 68, -40, -43, -27, 63, -76, 126, -94,
|
||||
18, 87, 20, 92, 38, -6, -54, 9, 45, 93, -57, 53, -11, -44, -38, -24, -126, -40, -24, -35, -121,
|
||||
-55, -87, -63, 70, -88, 13, -78, -89, 2, 50, 59, 4, -14, 81, 25, 34, -20, 87, 116, -76, -31,
|
||||
-93, 15, 112, 61, -43, -11, -86, -25, 10, 41, 1, 60, 105, -42, -90, -44, 38, 98, 126, -128, 28,
|
||||
99, 20, -97, 105, -101, 27, -106, 13, -108, -18, 23, -79, 121, 57, 93, -16, -37, -82, -1, -128,
|
||||
-67, 99, 117, 79, 85, 83, 12, 53, -101, -52, -75, 72, -128, -62, 45, -54, 11, 0, -58, -88, 11,
|
||||
121, 33, 86, -87, 31, -54, 109, -37, 10, 119, -9, 55, -7, 77, -52, 93, 64, -62, 115, -88, -4,
|
||||
67, -1, -37, 31, 107, 90, -109, -121, 71, 105, -123, 61, 75, 89, 108, -91, -6, 115, 45, 109, 10,
|
||||
-35, -84, 41, 127, 104, -84, -70, -6, -118, 6, 110, 99, -7, -112, 15, -79, -20, 51, -41, 78, 25,
|
||||
-97, -2, -121, -117, 7, -87, -76, 60, -7, -7, 0, 51, 91, 34, 85, 21, -1, 108, 41, 8, 126, -25,
|
||||
-30, 68, 109, -52, -51, 1, -111, 11, -22, -70, -33, 95, 40, 6, 63, 52, -66, -20, -6, -104, 81,
|
||||
57, 22, 82, 119, 126, 76, -10, -108, -63, -123, 19, 23, -106, -1, 117, 26, 112, -85, -78, 81,
|
||||
-116, 53, 86, -126, -80, 122, 36, 67, 18, 19, -114, 73, 125, -3, -69, 99, 10, -30, 19, 112,
|
||||
-103, 0, -61, 47, -106, -45, -105, -107, -56, 23, 14, 51, -70, 30, -32, 30, 7, 22, -31, -41, 19,
|
||||
-47, -64, -52, 119, -66, 54, -109, -87, 3, 95, -124, 94, -48, 36, -40, 13, 19, 91, -14, -115,
|
||||
103, 66, 20, 44, 47, 8, -40, 4, -114, -110, -47, -28, -108, 89, 0, -7, -71, -91, -43, 98, 8,
|
||||
-85, -98, -113, 103, -71, 69, 14, -95, -36, 92, -17, -66, -95, 123, -15, 52, 88, -60, -23, 123,
|
||||
-61, -4, -33, -45, 77, 57, -121, 119, 116, -40, -31, -15, 96, 54, -49, -44, 36, -37, 111, -45,
|
||||
-17, 12, 14, 21, 105, 48, 51, 42, -89, 55, 61, -5, -2, -36, -88, 36, -35, -29, -7, -68, -28,
|
||||
-76, 5, -38, -66, -72, 24, -120, 8, -86, -28, 0, 71, -89, 20, -40, -100, 61, -57, 52, 23, 66,
|
||||
-2, -24, -7, 86, -100, 111, -114, -47, -25, -40, -61, -67, -104, 33, 49, 16, -115, 9, -64, 27,
|
||||
122, 34, -33, -89, -113, -50, 42, 111, -14, 110, 43, 32, -112, 101, -59, 28, 76, -2, -117, 47,
|
||||
5, -73, -75, 21, -91, 99, 81, 93, -17, -119, 68, -21, -84, -51, -64, -98, 58, -33, 77, 4, 18,
|
||||
116, 62, 111, -105, -13, 91, -92, 81, -34, 40, 17, -128, 85, -19, 20, 8, 92, 83, 10, 3, 40, 89,
|
||||
60, 109, -23, 59, -66, -22, 43, 124, 25, -105, 77, 14, 75, -111, 13, 45, -90, -108, -79, 78,
|
||||
-45, -55, -44, -86, -20, -41, -11, 65, 76, -79, 91, -23, 77, -84, 114, -109, 2, -71, 68, 8, -31,
|
||||
99, 97, -104, -94, 69, 64, -16, -48, -78, 99, -58, -17, 95, 96, -64, 47, 96, -69, 60, 28, 114,
|
||||
64, -128, -128, 114, 28, -124, 72, -41, -48, 82, -6, 63, -27, -126, -86, -121, 0, 4, 4, 35,
|
||||
-111, 66, 64, -61, 117, -92, 48, 88, -128, 116, 7, -24, -111, -55, 96, -59, -96, 49, -70, -41,
|
||||
-47, 85, 86, -37, -32, 53, -49, 62, 68, 80, -37, 95, 29, -114, 11, -65, 90, -99, -97, 101, 96,
|
||||
-88, 5, 34, 3, 23, -22, 42, 4, -4, 17, -121, 106, -60, 33, -38, -32, -8, 41, -87, -4, -35, -102,
|
||||
7, 18, 35, -7, 85, -18, 60, 15, 34, 82, 46, 68, 63, 80, -38, 4, 51, -74, -34, 83, -33, -8, 44,
|
||||
87, -18, -8, 46, -53, -109, -121, -114, 10, 63, -36, -1, -123, 69, 107, -58, 33, -11, 63, -117,
|
||||
60, 22, 73, -36, 22, -76, -92, -74, -37, -35, 87, 40, -97, -6, 95, -25, -2, -99, -101, 102, -48,
|
||||
45, -55, 85, 94, -48, 57, -100, 34, 16, -63, -16, 106, -75, -7, -109, 71, -74, 20, -16, 37, 90,
|
||||
-61, 69, 19, -111, 95, -104, 116, 75, -68, 85, -80, 66, 127, 127, 67, -98, 121, 53, 23, -3, 56,
|
||||
-89, 99, 57, 9, 122, 76, 119, 1, -117, 47, -105, -42, -7, 51, -8, -81, 48, -60, -69, -29, 24,
|
||||
19, -81, 43, 31, -36, 62, 96, 20, -58, 39, -122, -115, 7, -114, 118, 27, 27, 78, -101, 75, -93,
|
||||
-104, -8, 119, 121, -97, -84, 58, 33, 18, -35, -29, 20, 20, 7, 112, 60, 31, -12, 7, -128, -55,
|
||||
-68, -7, -12, -115, 97, 115, 44, -46, -68, 108, 36, 121, -1, 84, -4, -26, -126, 85, -32, 36, 26,
|
||||
-19, 71, -121, -92, -51, -116, 81, -71, -83, -50, 21, -119, -60, -78, -84, 102, 19, -26, 118,
|
||||
-53, -13, 16, 36, -64, -83, -66, 32, -99, 54, 83, 104, 61, -19, 107, 95, -66, -42, -6, 25, 86,
|
||||
-13, -53, -49, -9, 74, -13, 58, 125, -96, -32, -22, -21, -12, -38, -114, -88, -100, 35, -87,
|
||||
-108, -2, -103, 87, -119, -109, 50, -28, -101, -4, -43, 105, 119, -118, 103, -104, 41, 47, 71,
|
||||
53, 11, -53, 59, -13, -11, 83, -33, 28, 11, 78, -59, 73, -33, -60, 119, -73, -127, 98, 39, 77,
|
||||
21, -8, -103, 103, 44, -87, -52, -74, 56, -63, -70, -121, 40, 103, 7, -100, 113, 53, -46, 44,
|
||||
16, 31, 102, -31, 104, -38, -120, 118, -122, -55, 25, 1, 92, 22, -14, 24, 108, 92, -90, -93,
|
||||
-16, -99, -13, -127, 75, 101, -42, -86, -29, -51, -49, -105, -118, 91, -56, -51, -73, 117, 53,
|
||||
-39, -73, 121, 83, -49, -10, -86, 11, -97, 40, -33, 6, -40, -9, -32, 92, -101, -83, 116, -5,
|
||||
-57, -93, -121, 2, 38, -65, -6, 45, 100, 92, 92, 74, 115, 45, -33, 92, -11, 70, 33, 76, 85, 94,
|
||||
1, -111, -103, 6, -4, -31, 44, -53, -77, -45, 100, -83, 92, -11, 10, -7, 126, 23, 36, 61, -18,
|
||||
-28, 67, 126, 53, -45, -77, 95, 43, -73, 30, -37, 122, -53, -79, -77, -42, 71, -124, 43, -89,
|
||||
60, -80, -89, -68, 96, 29, 103, -50, -93, 105, 7
|
||||
};
|
||||
|
||||
static class ProxyStream extends FilterInputStream {
|
||||
int readBytes;
|
||||
|
||||
ProxyStream(InputStream is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int result = super.read(b, off, len);
|
||||
if (result > 0) {
|
||||
readBytes += result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEagerStream() throws IOException {
|
||||
ProxyStream ps = new ProxyStream(new ByteArrayInputStream(DATA));
|
||||
BrotliInputStream reader = new BrotliInputStream(ps, 1);
|
||||
byte[] buffer = new byte[1];
|
||||
reader.read(buffer);
|
||||
reader.close();
|
||||
int normalReadBytes = ps.readBytes;
|
||||
|
||||
ps = new ProxyStream(new ByteArrayInputStream(DATA));
|
||||
reader = new BrotliInputStream(ps, 1);
|
||||
reader.setEager(true);
|
||||
reader.read(buffer);
|
||||
reader.close();
|
||||
int eagerReadBytes = ps.readBytes;
|
||||
|
||||
// Did not continue decoding - suspended as soon as enough data was decoded.
|
||||
assertTrue(eagerReadBytes < normalReadBytes);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
/**
|
||||
* Utilities for building Huffman decoding tables.
|
||||
*/
|
||||
final class Huffman {
|
||||
|
||||
private static final int MAX_LENGTH = 15;
|
||||
|
||||
/**
|
||||
* Returns reverse(reverse(key, len) + 1, len).
|
||||
*
|
||||
* <p> reverse(key, len) is the bit-wise reversal of the len least significant bits of key.
|
||||
*/
|
||||
private static int getNextKey(int key, int len) {
|
||||
int step = 1 << (len - 1);
|
||||
while ((key & step) != 0) {
|
||||
step >>= 1;
|
||||
}
|
||||
return (key & (step - 1)) + step;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores {@code item} in {@code table[0], table[step], table[2 * step] .., table[end]}.
|
||||
*
|
||||
* <p> Assumes that end is an integer multiple of step.
|
||||
*/
|
||||
private static void replicateValue(int[] table, int offset, int step, int end, int item) {
|
||||
do {
|
||||
end -= step;
|
||||
table[offset + end] = item;
|
||||
} while (end > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param count histogram of bit lengths for the remaining symbols,
|
||||
* @param len code length of the next processed symbol.
|
||||
* @return table width of the next 2nd level table.
|
||||
*/
|
||||
private static int nextTableBitSize(int[] count, int len, int rootBits) {
|
||||
int left = 1 << (len - rootBits);
|
||||
while (len < MAX_LENGTH) {
|
||||
left -= count[len];
|
||||
if (left <= 0) {
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
left <<= 1;
|
||||
}
|
||||
return len - rootBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds Huffman lookup table assuming code lengths are in symbol order.
|
||||
*/
|
||||
static void buildHuffmanTable(int[] rootTable, int tableOffset, int rootBits, int[] codeLengths,
|
||||
int codeLengthsSize) {
|
||||
int key; // Reversed prefix code.
|
||||
int[] sorted = new int[codeLengthsSize]; // Symbols sorted by code length.
|
||||
// TODO: fill with zeroes?
|
||||
int[] count = new int[MAX_LENGTH + 1]; // Number of codes of each length.
|
||||
int[] offset = new int[MAX_LENGTH + 1]; // Offsets in sorted table for each length.
|
||||
int symbol;
|
||||
|
||||
// Build histogram of code lengths.
|
||||
for (symbol = 0; symbol < codeLengthsSize; symbol++) {
|
||||
count[codeLengths[symbol]]++;
|
||||
}
|
||||
|
||||
// Generate offsets into sorted symbol table by code length.
|
||||
offset[1] = 0;
|
||||
for (int len = 1; len < MAX_LENGTH; len++) {
|
||||
offset[len + 1] = offset[len] + count[len];
|
||||
}
|
||||
|
||||
// Sort symbols by length, by symbol order within each length.
|
||||
for (symbol = 0; symbol < codeLengthsSize; symbol++) {
|
||||
if (codeLengths[symbol] != 0) {
|
||||
sorted[offset[codeLengths[symbol]]++] = symbol;
|
||||
}
|
||||
}
|
||||
|
||||
int tableBits = rootBits;
|
||||
int tableSize = 1 << tableBits;
|
||||
int totalSize = tableSize;
|
||||
|
||||
// Special case code with only one value.
|
||||
if (offset[MAX_LENGTH] == 1) {
|
||||
for (key = 0; key < totalSize; key++) {
|
||||
rootTable[tableOffset + key] = sorted[0];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill in root table.
|
||||
key = 0;
|
||||
symbol = 0;
|
||||
for (int len = 1, step = 2; len <= rootBits; len++, step <<= 1) {
|
||||
for (; count[len] > 0; count[len]--) {
|
||||
replicateValue(rootTable, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
|
||||
key = getNextKey(key, len);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in 2nd level tables and add pointers to root table.
|
||||
int mask = totalSize - 1;
|
||||
int low = -1;
|
||||
int currentOffset = tableOffset;
|
||||
for (int len = rootBits + 1, step = 2; len <= MAX_LENGTH; len++, step <<= 1) {
|
||||
for (; count[len] > 0; count[len]--) {
|
||||
if ((key & mask) != low) {
|
||||
currentOffset += tableSize;
|
||||
tableBits = nextTableBitSize(count, len, rootBits);
|
||||
tableSize = 1 << tableBits;
|
||||
totalSize += tableSize;
|
||||
low = key & mask;
|
||||
rootTable[tableOffset + low] =
|
||||
(tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
|
||||
}
|
||||
replicateValue(rootTable, currentOffset + (key >> rootBits), step, tableSize,
|
||||
(len - rootBits) << 16 | sorted[symbol++]);
|
||||
key = getNextKey(key, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/* Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Tests for {@link Dictionary}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class SetDictionaryTest {
|
||||
|
||||
/** See {@link SynthTest} */
|
||||
private static final byte[] BASE_DICT_WORD = {
|
||||
(byte) 0x1b, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
|
||||
(byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
|
||||
(byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
|
||||
(byte) 0x1b, (byte) 0x41, (byte) 0x02
|
||||
};
|
||||
|
||||
/** See {@link SynthTest} */
|
||||
private static final byte[] ONE_COMMAND = {
|
||||
(byte) 0x1b, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
|
||||
(byte) 0xe3, (byte) 0xb4, (byte) 0x0d, (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x5b,
|
||||
(byte) 0x26, (byte) 0x31, (byte) 0x40, (byte) 0x02, (byte) 0x00, (byte) 0xe0, (byte) 0x4e,
|
||||
(byte) 0x1b, (byte) 0x11, (byte) 0x86, (byte) 0x02
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testSetDictionary() throws IOException {
|
||||
byte[] buffer = new byte[16];
|
||||
BrotliInputStream decoder;
|
||||
|
||||
// No dictionary set; still decoding should succeed, if no dictionary entries are used.
|
||||
decoder = new BrotliInputStream(new ByteArrayInputStream(ONE_COMMAND));
|
||||
assertEquals(3, decoder.read(buffer, 0, buffer.length));
|
||||
assertEquals("aaa", new String(buffer, 0, 3, "US-ASCII"));
|
||||
decoder.close();
|
||||
|
||||
// Decoding of dictionary item must fail.
|
||||
decoder = new BrotliInputStream(new ByteArrayInputStream(BASE_DICT_WORD));
|
||||
boolean decodingFailed = false;
|
||||
try {
|
||||
decoder.read(buffer, 0, buffer.length);
|
||||
} catch (IOException ex) {
|
||||
decodingFailed = true;
|
||||
}
|
||||
assertEquals(true, decodingFailed);
|
||||
decoder.close();
|
||||
|
||||
// Load dictionary data.
|
||||
FileChannel dictionaryChannel =
|
||||
new FileInputStream(System.getProperty("RFC_DICTIONARY")).getChannel();
|
||||
ByteBuffer dictionary = dictionaryChannel.map(FileChannel.MapMode.READ_ONLY, 0, 122784).load();
|
||||
Dictionary.setData(dictionary);
|
||||
|
||||
// Retry decoding of dictionary item.
|
||||
decoder = new BrotliInputStream(new ByteArrayInputStream(BASE_DICT_WORD));
|
||||
assertEquals(4, decoder.read(buffer, 0, buffer.length));
|
||||
assertEquals("time", new String(buffer, 0, 4, "US-ASCII"));
|
||||
decoder.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
final class State {
|
||||
byte[] ringBuffer;
|
||||
byte[] contextModes;
|
||||
byte[] contextMap;
|
||||
byte[] distContextMap;
|
||||
byte[] output;
|
||||
byte[] byteBuffer; // BitReader
|
||||
|
||||
short[] shortBuffer; // BitReader
|
||||
|
||||
int[] intBuffer; // BitReader
|
||||
int[] rings;
|
||||
int[] blockTrees;
|
||||
int[] hGroup0;
|
||||
int[] hGroup1;
|
||||
int[] hGroup2;
|
||||
|
||||
long accumulator64; // BitReader: pre-fetched bits.
|
||||
|
||||
int runningState; // Default value is 0 == Decode.UNINITIALIZED
|
||||
int nextRunningState;
|
||||
int accumulator32; // BitReader: pre-fetched bits.
|
||||
int bitOffset; // BitReader: bit-reading position in accumulator.
|
||||
int halfOffset; // BitReader: offset of next item in intBuffer/shortBuffer.
|
||||
int tailBytes; // BitReader: number of bytes in unfinished half.
|
||||
int endOfStreamReached; // BitReader: input stream is finished.
|
||||
int metaBlockLength;
|
||||
int inputEnd;
|
||||
int isUncompressed;
|
||||
int isMetadata;
|
||||
int literalBlockLength;
|
||||
int numLiteralBlockTypes;
|
||||
int commandBlockLength;
|
||||
int numCommandBlockTypes;
|
||||
int distanceBlockLength;
|
||||
int numDistanceBlockTypes;
|
||||
int pos;
|
||||
int maxDistance;
|
||||
int distRbIdx;
|
||||
int trivialLiteralContext;
|
||||
int literalTreeIndex;
|
||||
int literalTree;
|
||||
int j;
|
||||
int insertLength;
|
||||
int contextMapSlice;
|
||||
int distContextMapSlice;
|
||||
int contextLookupOffset1;
|
||||
int contextLookupOffset2;
|
||||
int treeCommandOffset;
|
||||
int distanceCode;
|
||||
int numDirectDistanceCodes;
|
||||
int distancePostfixMask;
|
||||
int distancePostfixBits;
|
||||
int distance;
|
||||
int copyLength;
|
||||
int maxBackwardDistance;
|
||||
int maxRingBufferSize;
|
||||
int ringBufferSize;
|
||||
int ringBufferFence;
|
||||
int expectedTotalSize;
|
||||
int outputOffset;
|
||||
int outputLength;
|
||||
int outputUsed;
|
||||
int ringBufferBytesWritten;
|
||||
int ringBufferBytesReady;
|
||||
int isEager;
|
||||
|
||||
InputStream input; // BitReader
|
||||
|
||||
State() {
|
||||
this.ringBuffer = new byte[0];
|
||||
this.rings = new int[10];
|
||||
this.rings[0] = 16;
|
||||
this.rings[1] = 15;
|
||||
this.rings[2] = 11;
|
||||
this.rings[3] = 4;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,115 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Transformations on dictionary words.
|
||||
*/
|
||||
final class Transform {
|
||||
|
||||
static final int NUM_TRANSFORMS = 121;
|
||||
private static final int[] TRANSFORMS = new int[NUM_TRANSFORMS * 3];
|
||||
private static final byte[] PREFIX_SUFFIX = new byte[217];
|
||||
private static final int[] PREFIX_SUFFIX_HEADS = new int[51];
|
||||
|
||||
// Bundle of 0-terminated strings.
|
||||
private static final String PREFIX_SUFFIX_SRC = "# #s #, #e #.# the #.com/#\u00C2\u00A0# 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 #";
|
||||
private static final String TRANSFORMS_SRC = " !! ! , *! &! \" ! ) * * - ! # ! #!*! "
|
||||
+ "+ ,$ ! - % . / # 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";
|
||||
|
||||
private static void unpackTransforms(byte[] prefixSuffix, int[] prefixSuffixHeads,
|
||||
int[] transforms, String prefixSuffixSrc, String transformsSrc) {
|
||||
int n = prefixSuffixSrc.length();
|
||||
int index = 1;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
char c = prefixSuffixSrc.charAt(i);
|
||||
prefixSuffix[i] = (byte) c;
|
||||
if (c == 35) { // == #
|
||||
prefixSuffixHeads[index++] = i + 1;
|
||||
prefixSuffix[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_TRANSFORMS * 3; ++i) {
|
||||
transforms[i] = transformsSrc.charAt(i) - 32;
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
unpackTransforms(PREFIX_SUFFIX, PREFIX_SUFFIX_HEADS, TRANSFORMS, PREFIX_SUFFIX_SRC,
|
||||
TRANSFORMS_SRC);
|
||||
}
|
||||
|
||||
static int transformDictionaryWord(byte[] dst, int dstOffset, ByteBuffer data, int wordOffset,
|
||||
int len, int transformIndex) {
|
||||
int offset = dstOffset;
|
||||
int transformOffset = 3 * transformIndex;
|
||||
int transformPrefix = PREFIX_SUFFIX_HEADS[TRANSFORMS[transformOffset]];
|
||||
int transformType = TRANSFORMS[transformOffset + 1];
|
||||
int transformSuffix = PREFIX_SUFFIX_HEADS[TRANSFORMS[transformOffset + 2]];
|
||||
|
||||
// Copy prefix.
|
||||
while (PREFIX_SUFFIX[transformPrefix] != 0) {
|
||||
dst[offset++] = PREFIX_SUFFIX[transformPrefix++];
|
||||
}
|
||||
|
||||
// Copy trimmed word.
|
||||
int omitFirst = transformType >= 12 ? (transformType - 11) : 0;
|
||||
if (omitFirst > len) {
|
||||
omitFirst = len;
|
||||
}
|
||||
wordOffset += omitFirst;
|
||||
len -= omitFirst;
|
||||
len -= transformType <= 9 ? transformType : 0; // Omit last.
|
||||
int i = len;
|
||||
while (i > 0) {
|
||||
dst[offset++] = data.get(wordOffset++);
|
||||
i--;
|
||||
}
|
||||
|
||||
// Ferment.
|
||||
if (transformType == 11 || transformType == 10) {
|
||||
int uppercaseOffset = offset - len;
|
||||
if (transformType == 10) {
|
||||
len = 1;
|
||||
}
|
||||
while (len > 0) {
|
||||
int tmp = dst[uppercaseOffset] & 0xFF;
|
||||
if (tmp < 0xc0) {
|
||||
if (tmp >= 97 && tmp <= 122) { // in [a..z] range
|
||||
dst[uppercaseOffset] ^= (byte) 32;
|
||||
}
|
||||
uppercaseOffset += 1;
|
||||
len -= 1;
|
||||
} else if (tmp < 0xe0) {
|
||||
dst[uppercaseOffset + 1] ^= (byte) 32;
|
||||
uppercaseOffset += 2;
|
||||
len -= 2;
|
||||
} else {
|
||||
dst[uppercaseOffset + 2] ^= (byte) 5;
|
||||
uppercaseOffset += 3;
|
||||
len -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy suffix.
|
||||
while (PREFIX_SUFFIX[transformSuffix] != 0) {
|
||||
dst[offset++] = PREFIX_SUFFIX[transformSuffix++];
|
||||
}
|
||||
|
||||
return offset - dstOffset;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Tests for {@link Transform}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class TransformTest {
|
||||
|
||||
private static long crc64(byte[] data) {
|
||||
long crc = -1;
|
||||
for (int i = 0; i < data.length; ++i) {
|
||||
long c = (crc ^ (long) (data[i] & 0xFF)) & 0xFF;
|
||||
for (int k = 0; k < 8; k++) {
|
||||
c = (c >>> 1) ^ (-(c & 1L) & -3932672073523589310L);
|
||||
}
|
||||
crc = c ^ (crc >>> 8);
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrimAll() {
|
||||
byte[] output = new byte[0];
|
||||
byte[] input = {119, 111, 114, 100}; // "word"
|
||||
Transform.transformDictionaryWord(
|
||||
output, 0, ByteBuffer.wrap(input), 0, input.length, 39);
|
||||
byte[] expectedOutput = new byte[0];
|
||||
assertArrayEquals(expectedOutput, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCapitalize() {
|
||||
byte[] output = new byte[6];
|
||||
byte[] input = {113, -61, -90, -32, -92, -86}; // "qæप"
|
||||
Transform.transformDictionaryWord(
|
||||
output, 0, ByteBuffer.wrap(input), 0, input.length, 44);
|
||||
byte[] expectedOutput = {81, -61, -122, -32, -92, -81}; // "QÆय"
|
||||
assertArrayEquals(expectedOutput, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllTransforms() {
|
||||
/* This string allows to apply all transforms: head and tail cutting, capitalization and
|
||||
turning to upper case; all results will be mutually different. */
|
||||
// "o123456789abcdef"
|
||||
byte[] testWord = {111, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102};
|
||||
byte[] output = new byte[2259];
|
||||
int offset = 0;
|
||||
for (int i = 0; i < Transform.NUM_TRANSFORMS; ++i) {
|
||||
offset += Transform.transformDictionaryWord(
|
||||
output, offset, ByteBuffer.wrap(testWord), 0, testWord.length, i);
|
||||
output[offset++] = -1;
|
||||
}
|
||||
assertEquals(output.length, offset);
|
||||
assertEquals(8929191060211225186L, crc64(output));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.dec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A set of utility methods.
|
||||
*/
|
||||
final class Utils {
|
||||
|
||||
private static final byte[] BYTE_ZEROES = new byte[1024];
|
||||
|
||||
private static final int[] INT_ZEROES = new int[1024];
|
||||
|
||||
/**
|
||||
* Fills byte array with zeroes.
|
||||
*
|
||||
* <p> Current implementation uses {@link System#arraycopy}, so it should be used for length not
|
||||
* less than 16.
|
||||
*
|
||||
* @param dest array to fill with zeroes
|
||||
* @param offset the first byte to fill
|
||||
* @param length number of bytes to change
|
||||
*/
|
||||
static void fillBytesWithZeroes(byte[] dest, int start, int end) {
|
||||
int cursor = start;
|
||||
while (cursor < end) {
|
||||
int step = Math.min(cursor + 1024, end) - cursor;
|
||||
System.arraycopy(BYTE_ZEROES, 0, dest, cursor, step);
|
||||
cursor += step;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills int array with zeroes.
|
||||
*
|
||||
* <p> Current implementation uses {@link System#arraycopy}, so it should be used for length not
|
||||
* less than 16.
|
||||
*
|
||||
* @param dest array to fill with zeroes
|
||||
* @param offset the first item to fill
|
||||
* @param length number of item to change
|
||||
*/
|
||||
static void fillIntsWithZeroes(int[] dest, int start, int end) {
|
||||
int cursor = start;
|
||||
while (cursor < end) {
|
||||
int step = Math.min(cursor + 1024, end) - cursor;
|
||||
System.arraycopy(INT_ZEROES, 0, dest, cursor, step);
|
||||
cursor += step;
|
||||
}
|
||||
}
|
||||
|
||||
static void copyBytesWithin(byte[] bytes, int target, int start, int end) {
|
||||
System.arraycopy(bytes, start, bytes, target, end - start);
|
||||
}
|
||||
|
||||
static int readInput(InputStream src, byte[] dst, int offset, int length) {
|
||||
try {
|
||||
return src.read(dst, offset, length);
|
||||
} catch (IOException e) {
|
||||
throw new BrotliRuntimeException("Failed to read input", e);
|
||||
}
|
||||
}
|
||||
|
||||
static void closeInput(InputStream src) throws IOException {
|
||||
src.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.brotli</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>dec</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.groupId}:${project.artifactId}</name>
|
||||
|
||||
<properties>
|
||||
<manifestdir>${project.build.directory}/osgi</manifestdir>
|
||||
<manifestfile>${manifestdir}/MANIFEST.MF</manifestfile>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>../../..</sourceDirectory>
|
||||
<testSourceDirectory>../../..</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>org/brotli/dec/*.java</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/*Test*.java</exclude>
|
||||
</excludes>
|
||||
<testIncludes>
|
||||
<include>org/brotli/dec/*Test*.java</include>
|
||||
</testIncludes>
|
||||
<testExcludes>
|
||||
<exclude>org/brotli/dec/SetDictionaryTest.java</exclude>
|
||||
</testExcludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>org/brotli/dec/*.java</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/*Test*.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.10.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sourcepath>.</sourcepath>
|
||||
<sourceFileExcludes>
|
||||
<exclude>**/*Test*.java</exclude>
|
||||
</sourceFileExcludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<forced>true</forced>
|
||||
</archive>
|
||||
<excludeDependencies>true</excludeDependencies>
|
||||
<manifestLocation>${manifestdir}</manifestLocation>
|
||||
<instructions>
|
||||
<_nouses>true</_nouses>
|
||||
<Bundle-SymbolicName>org.brotli.${project.artifactId}</Bundle-SymbolicName>
|
||||
<Bundle-Description>${project.description}</Bundle-Description>
|
||||
<Export-Package>org.brotli.dec;version=${project.version};-noimport:=true</Export-Package>
|
||||
<Private-Package></Private-Package>
|
||||
<Import-Package>*</Import-Package>
|
||||
<DynamicImport-Package></DynamicImport-Package>
|
||||
<Bundle-DocURL>${project.url}</Bundle-DocURL>
|
||||
</instructions>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bundle-manifest</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${manifestfile}</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
# DictionaryData is an optionally / dynamically loaded built-in dictionary.
|
||||
-keep class org.brotli.dec.DictionaryData
|
||||
|
||||
# We get the fully-qualified name of DictionaryData from Dictionary, so avoid
|
||||
# renaming it.
|
||||
-keepnames class org.brotli.dec.Dictionary
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
# Description:
|
||||
# Integration test runner + corpus for Java port of Brotli decoder.
|
||||
|
||||
java_library(
|
||||
name = "brotli_jni_test_base",
|
||||
srcs = ["BrotliJniTestBase.java"],
|
||||
visibility = [
|
||||
"//java/org/brotli/wrapper/common:__pkg__",
|
||||
"//java/org/brotli/wrapper/dec:__pkg__",
|
||||
"//java/org/brotli/wrapper/enc:__pkg__",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "bundle_helper",
|
||||
srcs = ["BundleHelper.java"],
|
||||
visibility = [
|
||||
"//java/org/brotli/wrapper/dec:__pkg__",
|
||||
"//java/org/brotli/wrapper/enc:__pkg__",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "bundle_checker",
|
||||
srcs = ["BundleChecker.java"],
|
||||
deps = [
|
||||
":bundle_helper",
|
||||
"//java/org/brotli/dec",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "bundle_checker_bin",
|
||||
main_class = "org.brotli.integration.BundleChecker",
|
||||
runtime_deps = [":bundle_checker"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "bundle_checker_data_test",
|
||||
args = ["java/org/brotli/integration/test_data.zip"],
|
||||
data = ["test_data.zip"],
|
||||
main_class = "org.brotli.integration.BundleChecker",
|
||||
use_testrunner = 0,
|
||||
runtime_deps = [":bundle_checker"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "bundle_checker_fuzz_test",
|
||||
args = [
|
||||
"-s",
|
||||
"java/org/brotli/integration/fuzz_data.zip",
|
||||
],
|
||||
data = ["fuzz_data.zip"],
|
||||
main_class = "org.brotli.integration.BundleChecker",
|
||||
use_testrunner = 0,
|
||||
runtime_deps = [":bundle_checker"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_data",
|
||||
srcs = ["test_data.zip"],
|
||||
visibility = [
|
||||
"//java/org/brotli/wrapper/dec:__pkg__",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_corpus",
|
||||
srcs = ["test_corpus.zip"],
|
||||
visibility = [
|
||||
"//java/org/brotli/wrapper/enc:__pkg__",
|
||||
],
|
||||
)
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package org.brotli.integration;
|
||||
|
||||
/**
|
||||
* Optionally loads brotli JNI wrapper native library.
|
||||
*/
|
||||
public class BrotliJniTestBase {
|
||||
static {
|
||||
String jniLibrary = System.getProperty("BROTLI_JNI_LIBRARY");
|
||||
if (jniLibrary != null) {
|
||||
System.load(new java.io.File(jniLibrary).getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/* Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.integration;
|
||||
|
||||
import org.brotli.dec.BrotliInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* Decompress files and (optionally) checks their checksums.
|
||||
*
|
||||
* <p> File are read from ZIP archive passed as an array of bytes. Multiple checkers negotiate about
|
||||
* task distribution via shared AtomicInteger counter.
|
||||
* <p> All entries are expected to be valid brotli compressed streams and output CRC64 checksum
|
||||
* is expected to match the checksum hex-encoded in the first part of entry name.
|
||||
*/
|
||||
public class BundleChecker implements Runnable {
|
||||
private final AtomicInteger nextJob;
|
||||
private final InputStream input;
|
||||
private final boolean sanityCheck;
|
||||
|
||||
/**
|
||||
* @param sanityCheck do not calculate checksum and ignore {@link IOException}.
|
||||
*/
|
||||
public BundleChecker(InputStream input, AtomicInteger nextJob, boolean sanityCheck) {
|
||||
this.input = input;
|
||||
this.nextJob = nextJob;
|
||||
this.sanityCheck = sanityCheck;
|
||||
}
|
||||
|
||||
private long decompressAndCalculateCrc(ZipInputStream input) throws IOException {
|
||||
/* Do not allow entry readers to close the whole ZipInputStream. */
|
||||
FilterInputStream entryStream = new FilterInputStream(input) {
|
||||
@Override
|
||||
public void close() {}
|
||||
};
|
||||
|
||||
BrotliInputStream decompressedStream = new BrotliInputStream(entryStream);
|
||||
long crc;
|
||||
try {
|
||||
crc = BundleHelper.fingerprintStream(decompressedStream);
|
||||
} finally {
|
||||
decompressedStream.close();
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String entryName = "";
|
||||
ZipInputStream zis = new ZipInputStream(input);
|
||||
try {
|
||||
int entryIndex = 0;
|
||||
ZipEntry entry;
|
||||
int jobIndex = nextJob.getAndIncrement();
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
if (entryIndex++ != jobIndex) {
|
||||
zis.closeEntry();
|
||||
continue;
|
||||
}
|
||||
entryName = entry.getName();
|
||||
long entryCrc = BundleHelper.getExpectedFingerprint(entryName);
|
||||
try {
|
||||
if (entryCrc != decompressAndCalculateCrc(zis) && !sanityCheck) {
|
||||
throw new RuntimeException("CRC mismatch");
|
||||
}
|
||||
} catch (IOException iox) {
|
||||
if (!sanityCheck) {
|
||||
throw new RuntimeException("Decompression failed", iox);
|
||||
}
|
||||
}
|
||||
zis.closeEntry();
|
||||
entryName = "";
|
||||
jobIndex = nextJob.getAndIncrement();
|
||||
}
|
||||
zis.close();
|
||||
input.close();
|
||||
} catch (Throwable ex) {
|
||||
throw new RuntimeException(entryName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException {
|
||||
int argsOffset = 0;
|
||||
boolean sanityCheck = false;
|
||||
if (args.length != 0) {
|
||||
if (args[0].equals("-s")) {
|
||||
sanityCheck = true;
|
||||
argsOffset = 1;
|
||||
}
|
||||
}
|
||||
if (args.length == argsOffset) {
|
||||
throw new RuntimeException("Usage: BundleChecker [-s] <fileX.zip> ...");
|
||||
}
|
||||
for (int i = argsOffset; i < args.length; ++i) {
|
||||
new BundleChecker(new FileInputStream(args[i]), new AtomicInteger(0), sanityCheck).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
/* Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.integration;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* Utilities to work test files bundles in zip archive.
|
||||
*/
|
||||
public class BundleHelper {
|
||||
private BundleHelper() { }
|
||||
|
||||
public static List<String> listEntries(InputStream input) throws IOException {
|
||||
List<String> result = new ArrayList<String>();
|
||||
ZipInputStream zis = new ZipInputStream(input);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (!entry.isDirectory()) {
|
||||
result.add(entry.getName());
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] readStream(InputStream input) throws IOException {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[65536];
|
||||
int bytesRead;
|
||||
while ((bytesRead = input.read(buffer)) != -1) {
|
||||
result.write(buffer, 0, bytesRead);
|
||||
}
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] readEntry(InputStream input, String entryName) throws IOException {
|
||||
ZipInputStream zis = new ZipInputStream(input);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.getName().equals(entryName)) {
|
||||
byte[] result = readStream(zis);
|
||||
zis.closeEntry();
|
||||
return result;
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
/* entry not found */
|
||||
return null;
|
||||
}
|
||||
|
||||
/** ECMA CRC64 polynomial. */
|
||||
private static final long CRC_64_POLY =
|
||||
new BigInteger("C96C5795D7870F42", 16).longValue();
|
||||
|
||||
/**
|
||||
* Rolls CRC64 calculation.
|
||||
*
|
||||
* <p> {@code CRC64(data) = -1 ^ updateCrc64((... updateCrc64(-1, firstBlock), ...), lastBlock);}
|
||||
* <p> This simple and reliable checksum is chosen to make is easy to calculate the same value
|
||||
* across the variety of languages (C++, Java, Go, ...).
|
||||
*/
|
||||
public static long updateCrc64(long crc, byte[] data, int offset, int length) {
|
||||
for (int i = offset; i < offset + length; ++i) {
|
||||
long c = (crc ^ (long) (data[i] & 0xFF)) & 0xFF;
|
||||
for (int k = 0; k < 8; k++) {
|
||||
c = ((c & 1) == 1) ? CRC_64_POLY ^ (c >>> 1) : c >>> 1;
|
||||
}
|
||||
crc = c ^ (crc >>> 8);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates CRC64 of stream contents.
|
||||
*/
|
||||
public static long fingerprintStream(InputStream input) throws IOException {
|
||||
byte[] buffer = new byte[65536];
|
||||
long crc = -1;
|
||||
while (true) {
|
||||
int len = input.read(buffer);
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
crc = updateCrc64(crc, buffer, 0, len);
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
public static long getExpectedFingerprint(String entryName) {
|
||||
int dotIndex = entryName.indexOf('.');
|
||||
String entryCrcString = (dotIndex == -1) ? entryName : entryName.substring(0, dotIndex);
|
||||
return new BigInteger(entryCrcString, 16).longValue();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,65 +0,0 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.brotli</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>integration</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.groupId}:${project.artifactId}</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.brotli</groupId>
|
||||
<artifactId>dec</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>.</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>data</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<mainClass>org.brotli.integration.BundleChecker</mainClass>
|
||||
<arguments>
|
||||
<argument>test_data.zip</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>fuzz</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<mainClass>org.brotli.integration.BundleChecker</mainClass>
|
||||
<arguments>
|
||||
<argument>-s</argument>
|
||||
<argument>fuzz_data.zip</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,101 +0,0 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.brotli</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>${project.groupId}:${project.artifactId}</name>
|
||||
<description>Brotli is a generic-purpose lossless compression algorithm.</description>
|
||||
<url>http://brotli.org</url>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>http://www.opensource.org/licenses/mit-license.php</url>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<organization>Google</organization>
|
||||
<organizationUrl>https://github.com/google</organizationUrl>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/google/brotli.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/google/brotli.git</developerConnection>
|
||||
<url>https://github.com/google/brotli</url>
|
||||
</scm>
|
||||
|
||||
<modules>
|
||||
<module>dec</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release-sign-artifacts</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>performRelease</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.7</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<serverId>ossrh</serverId>
|
||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
||||
<autoReleaseAfterClose>false</autoReleaseAfterClose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # MIT
|
||||
|
||||
filegroup(
|
||||
name = "jni_src",
|
||||
srcs = ["common_jni.cc"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "brotli_jni_no_dictionary_data",
|
||||
srcs = ["//:brotli_jni_no_dictionary_data.dll"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "common",
|
||||
srcs = glob(
|
||||
["*.java"],
|
||||
exclude = ["*Test*.java"],
|
||||
),
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "SetZeroDictionaryTest",
|
||||
size = "small",
|
||||
srcs = ["SetZeroDictionaryTest.java"],
|
||||
data = [
|
||||
":brotli_jni_no_dictionary_data", # Bazel JNI workaround
|
||||
],
|
||||
jvm_flags = [
|
||||
"-DBROTLI_JNI_LIBRARY=$(location :brotli_jni_no_dictionary_data)",
|
||||
],
|
||||
deps = [
|
||||
":common",
|
||||
"//java/org/brotli/integration:brotli_jni_test_base",
|
||||
"//java/org/brotli/wrapper/dec",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "rfc_dictionary",
|
||||
srcs = ["//:dictionary"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "SetRfcDictionaryTest",
|
||||
size = "small",
|
||||
srcs = ["SetRfcDictionaryTest.java"],
|
||||
data = [
|
||||
":rfc_dictionary",
|
||||
":brotli_jni_no_dictionary_data", # Bazel JNI workaround
|
||||
],
|
||||
jvm_flags = [
|
||||
"-DRFC_DICTIONARY=$(location :rfc_dictionary)",
|
||||
"-DBROTLI_JNI_LIBRARY=$(location :brotli_jni_no_dictionary_data)",
|
||||
],
|
||||
deps = [
|
||||
":common",
|
||||
"//java/org/brotli/integration:brotli_jni_test_base",
|
||||
"//java/org/brotli/wrapper/dec",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.common;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* JNI wrapper for brotli common.
|
||||
*/
|
||||
public class BrotliCommon {
|
||||
public static final int RFC_DICTIONARY_SIZE = 122784;
|
||||
|
||||
/* 96cecd2ee7a666d5aa3627d74735b32a */
|
||||
private static final byte[] RFC_DICTIONARY_MD5 = {
|
||||
-106, -50, -51, 46, -25, -90, 102, -43, -86, 54, 39, -41, 71, 53, -77, 42
|
||||
};
|
||||
|
||||
/* 72b41051cb61a9281ba3c4414c289da50d9a7640 */
|
||||
private static final byte[] RFC_DICTIONARY_SHA_1 = {
|
||||
114, -76, 16, 81, -53, 97, -87, 40, 27, -93, -60, 65, 76, 40, -99, -91, 13, -102, 118, 64
|
||||
};
|
||||
|
||||
/* 20e42eb1b511c21806d4d227d07e5dd06877d8ce7b3a817f378f313653f35c70 */
|
||||
private static final byte[] RFC_DICTIONARY_SHA_256 = {
|
||||
32, -28, 46, -79, -75, 17, -62, 24, 6, -44, -46, 39, -48, 126, 93, -48,
|
||||
104, 119, -40, -50, 123, 58, -127, 127, 55, -113, 49, 54, 83, -13, 92, 112
|
||||
};
|
||||
|
||||
private static boolean isDictionaryDataSet;
|
||||
private static final Object mutex = new Object();
|
||||
|
||||
/**
|
||||
* Checks if the given checksum matches MD5 checksum of the RFC dictionary.
|
||||
*/
|
||||
public static boolean checkDictionaryDataMd5(byte[] digest) {
|
||||
return Arrays.equals(RFC_DICTIONARY_MD5, digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given checksum matches SHA-1 checksum of the RFC dictionary.
|
||||
*/
|
||||
public static boolean checkDictionaryDataSha1(byte[] digest) {
|
||||
return Arrays.equals(RFC_DICTIONARY_SHA_1, digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given checksum matches SHA-256 checksum of the RFC dictionary.
|
||||
*/
|
||||
public static boolean checkDictionaryDataSha256(byte[] digest) {
|
||||
return Arrays.equals(RFC_DICTIONARY_SHA_256, digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes to a new direct ByteBuffer.
|
||||
*
|
||||
* Direct byte buffers are used to supply native code with large data chunks.
|
||||
*/
|
||||
public static ByteBuffer makeNative(byte[] data) {
|
||||
ByteBuffer result = ByteBuffer.allocateDirect(data.length);
|
||||
result.put(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies data and sets it to be brotli dictionary.
|
||||
*/
|
||||
public static void setDictionaryData(byte[] data) {
|
||||
if (data.length != RFC_DICTIONARY_SIZE) {
|
||||
throw new IllegalArgumentException("invalid dictionary size");
|
||||
}
|
||||
synchronized (mutex) {
|
||||
if (isDictionaryDataSet) {
|
||||
return;
|
||||
}
|
||||
setDictionaryData(makeNative(data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data and sets it to be brotli dictionary.
|
||||
*/
|
||||
public static void setDictionaryData(InputStream src) throws IOException {
|
||||
synchronized (mutex) {
|
||||
if (isDictionaryDataSet) {
|
||||
return;
|
||||
}
|
||||
ByteBuffer copy = ByteBuffer.allocateDirect(RFC_DICTIONARY_SIZE);
|
||||
byte[] buffer = new byte[4096];
|
||||
int readBytes;
|
||||
while ((readBytes = src.read(buffer)) != -1) {
|
||||
if (copy.remaining() < readBytes) {
|
||||
throw new IllegalArgumentException("invalid dictionary size");
|
||||
}
|
||||
copy.put(buffer, 0, readBytes);
|
||||
}
|
||||
if (copy.remaining() != 0) {
|
||||
throw new IllegalArgumentException("invalid dictionary size " + copy.remaining());
|
||||
}
|
||||
setDictionaryData(copy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data to be brotli dictionary.
|
||||
*/
|
||||
public static void setDictionaryData(ByteBuffer data) {
|
||||
if (!data.isDirect()) {
|
||||
throw new IllegalArgumentException("direct byte buffer is expected");
|
||||
}
|
||||
if (data.capacity() != RFC_DICTIONARY_SIZE) {
|
||||
throw new IllegalArgumentException("invalid dictionary size");
|
||||
}
|
||||
synchronized (mutex) {
|
||||
if (isDictionaryDataSet) {
|
||||
return;
|
||||
}
|
||||
if (!CommonJNI.nativeSetDictionaryData(data)) {
|
||||
throw new RuntimeException("setting dictionary failed");
|
||||
}
|
||||
isDictionaryDataSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.common;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* JNI wrapper for brotli common.
|
||||
*/
|
||||
class CommonJNI {
|
||||
static native boolean nativeSetDictionaryData(ByteBuffer data);
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.common;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import org.brotli.wrapper.dec.BrotliInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Tests for {@link BrotliCommon}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class SetRfcDictionaryTest extends BrotliJniTestBase {
|
||||
|
||||
@Test
|
||||
public void testRfcDictionaryChecksums() throws IOException, NoSuchAlgorithmException {
|
||||
FileInputStream dictionary = new FileInputStream(System.getProperty("RFC_DICTIONARY"));
|
||||
byte[] data = new byte[BrotliCommon.RFC_DICTIONARY_SIZE + 1];
|
||||
int offset = 0;
|
||||
try {
|
||||
int readBytes;
|
||||
while ((readBytes = dictionary.read(data, offset, data.length - offset)) != -1) {
|
||||
offset += readBytes;
|
||||
if (offset > BrotliCommon.RFC_DICTIONARY_SIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
dictionary.close();
|
||||
}
|
||||
if (offset != BrotliCommon.RFC_DICTIONARY_SIZE) {
|
||||
fail("dictionary size mismatch");
|
||||
}
|
||||
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.update(data, 0, offset);
|
||||
assertTrue(BrotliCommon.checkDictionaryDataMd5(md5.digest()));
|
||||
|
||||
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
|
||||
sha1.update(data, 0, offset);
|
||||
assertTrue(BrotliCommon.checkDictionaryDataSha1(sha1.digest()));
|
||||
|
||||
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
|
||||
sha256.update(data, 0, offset);
|
||||
assertTrue(BrotliCommon.checkDictionaryDataSha256(sha256.digest()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRfcDictionary() throws IOException {
|
||||
/* "leftdatadataleft" encoded with dictionary words. */
|
||||
byte[] data = {27, 15, 0, 0, 0, 0, -128, -29, -76, 13, 0, 0, 7, 91, 38, 49, 64, 2, 0, -32, 78,
|
||||
27, 65, -128, 32, 80, 16, 36, 8, 6};
|
||||
FileInputStream dictionary = new FileInputStream(System.getProperty("RFC_DICTIONARY"));
|
||||
try {
|
||||
BrotliCommon.setDictionaryData(dictionary);
|
||||
} finally {
|
||||
dictionary.close();
|
||||
}
|
||||
|
||||
BrotliInputStream decoder = new BrotliInputStream(new ByteArrayInputStream(data));
|
||||
byte[] output = new byte[17];
|
||||
int offset = 0;
|
||||
try {
|
||||
int bytesRead;
|
||||
while ((bytesRead = decoder.read(output, offset, 17 - offset)) != -1) {
|
||||
offset += bytesRead;
|
||||
}
|
||||
} finally {
|
||||
decoder.close();
|
||||
}
|
||||
assertEquals(16, offset);
|
||||
byte[] expected = {
|
||||
'l', 'e', 'f', 't',
|
||||
'd', 'a', 't', 'a',
|
||||
'd', 'a', 't', 'a',
|
||||
'l', 'e', 'f', 't',
|
||||
0
|
||||
};
|
||||
assertArrayEquals(expected, output);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.common;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import org.brotli.wrapper.dec.BrotliInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Tests for {@link BrotliCommon}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class SetZeroDictionaryTest extends BrotliJniTestBase {
|
||||
|
||||
@Test
|
||||
public void testZeroDictionary() throws IOException {
|
||||
/* "leftdatadataleft" encoded with dictionary words. */
|
||||
byte[] data = {27, 15, 0, 0, 0, 0, -128, -29, -76, 13, 0, 0, 7, 91, 38, 49, 64, 2, 0, -32, 78,
|
||||
27, 65, -128, 32, 80, 16, 36, 8, 6};
|
||||
byte[] dictionary = new byte[BrotliCommon.RFC_DICTIONARY_SIZE];
|
||||
BrotliCommon.setDictionaryData(dictionary);
|
||||
|
||||
BrotliInputStream decoder = new BrotliInputStream(new ByteArrayInputStream(data));
|
||||
byte[] output = new byte[17];
|
||||
int offset = 0;
|
||||
try {
|
||||
int bytesRead;
|
||||
while ((bytesRead = decoder.read(output, offset, 17 - offset)) != -1) {
|
||||
offset += bytesRead;
|
||||
}
|
||||
} finally {
|
||||
decoder.close();
|
||||
}
|
||||
assertEquals(16, offset);
|
||||
assertArrayEquals(new byte[17], output);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "../common/dictionary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set data to be brotli dictionary data.
|
||||
*
|
||||
* @param buffer direct ByteBuffer
|
||||
* @returns false if dictionary data was already set; otherwise true
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_brotli_wrapper_common_CommonJNI_nativeSetDictionaryData(
|
||||
JNIEnv* env, jobject /*jobj*/, jobject buffer) {
|
||||
jobject buffer_ref = env->NewGlobalRef(buffer);
|
||||
if (!buffer_ref) {
|
||||
return false;
|
||||
}
|
||||
uint8_t* data = static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
|
||||
if (!data) {
|
||||
env->DeleteGlobalRef(buffer_ref);
|
||||
return false;
|
||||
}
|
||||
|
||||
BrotliSetDictionaryData(data);
|
||||
|
||||
const BrotliDictionary* dictionary = BrotliGetDictionary();
|
||||
if (dictionary->data != data) {
|
||||
env->DeleteGlobalRef(buffer_ref);
|
||||
} else {
|
||||
/* Don't release reference; it is an intended memory leak. */
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # MIT
|
||||
|
||||
filegroup(
|
||||
name = "jni_src",
|
||||
srcs = ["decoder_jni.cc"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "dec",
|
||||
srcs = glob(
|
||||
["*.java"],
|
||||
exclude = ["*Test*.java"],
|
||||
),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "brotli_jni",
|
||||
srcs = ["//:brotli_jni.dll"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_bundle",
|
||||
srcs = ["//java/org/brotli/integration:test_data"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "BrotliDecoderChannelTest",
|
||||
size = "large",
|
||||
srcs = ["BrotliDecoderChannelTest.java"],
|
||||
data = [
|
||||
":brotli_jni", # Bazel JNI workaround
|
||||
":test_bundle",
|
||||
],
|
||||
jvm_flags = [
|
||||
"-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
|
||||
"-DTEST_BUNDLE=$(location :test_bundle)",
|
||||
],
|
||||
deps = [
|
||||
":dec",
|
||||
"//java/org/brotli/integration:brotli_jni_test_base",
|
||||
"//java/org/brotli/integration:bundle_helper",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "BrotliInputStreamTest",
|
||||
size = "large",
|
||||
srcs = ["BrotliInputStreamTest.java"],
|
||||
data = [
|
||||
":brotli_jni", # Bazel JNI workaround
|
||||
":test_bundle",
|
||||
],
|
||||
jvm_flags = [
|
||||
"-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
|
||||
"-DTEST_BUNDLE=$(location :test_bundle)",
|
||||
],
|
||||
deps = [
|
||||
":dec",
|
||||
"//java/org/brotli/integration:brotli_jni_test_base",
|
||||
"//java/org/brotli/integration:bundle_helper",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "DecoderTest",
|
||||
size = "large",
|
||||
srcs = ["DecoderTest.java"],
|
||||
data = [
|
||||
":brotli_jni", # Bazel JNI workaround
|
||||
":test_bundle",
|
||||
],
|
||||
jvm_flags = [
|
||||
"-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
|
||||
"-DTEST_BUNDLE=$(location :test_bundle)",
|
||||
],
|
||||
deps = [
|
||||
":dec",
|
||||
"//java/org/brotli/integration:brotli_jni_test_base",
|
||||
"//java/org/brotli/integration:bundle_helper",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.dec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
|
||||
/**
|
||||
* ReadableByteChannel that wraps native brotli decoder.
|
||||
*/
|
||||
public class BrotliDecoderChannel extends Decoder implements ReadableByteChannel {
|
||||
/** The default internal buffer size used by the decoder. */
|
||||
private static final int DEFAULT_BUFFER_SIZE = 16384;
|
||||
|
||||
private final Object mutex = new Object();
|
||||
|
||||
/**
|
||||
* Creates a BrotliDecoderChannel.
|
||||
*
|
||||
* @param source underlying source
|
||||
* @param bufferSize intermediate buffer size
|
||||
* @param customDictionary initial LZ77 dictionary
|
||||
*/
|
||||
public BrotliDecoderChannel(ReadableByteChannel source, int bufferSize) throws IOException {
|
||||
super(source, bufferSize);
|
||||
}
|
||||
|
||||
public BrotliDecoderChannel(ReadableByteChannel source) throws IOException {
|
||||
this(source, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
synchronized (mutex) {
|
||||
return !closed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
synchronized (mutex) {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
synchronized (mutex) {
|
||||
if (closed) {
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
int result = 0;
|
||||
while (dst.hasRemaining()) {
|
||||
int outputSize = decode();
|
||||
if (outputSize <= 0) {
|
||||
return result == 0 ? outputSize : result;
|
||||
}
|
||||
result += consume(dst);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.dec;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import org.brotli.integration.BundleHelper;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.List;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.AllTests;
|
||||
|
||||
/** Tests for {@link org.brotli.wrapper.dec.BrotliDecoderChannel}. */
|
||||
@RunWith(AllTests.class)
|
||||
public class BrotliDecoderChannelTest extends BrotliJniTestBase {
|
||||
|
||||
static InputStream getBundle() throws IOException {
|
||||
return new FileInputStream(System.getProperty("TEST_BUNDLE"));
|
||||
}
|
||||
|
||||
/** Creates a test suite. */
|
||||
public static TestSuite suite() throws IOException {
|
||||
TestSuite suite = new TestSuite();
|
||||
InputStream bundle = getBundle();
|
||||
try {
|
||||
List<String> entries = BundleHelper.listEntries(bundle);
|
||||
for (String entry : entries) {
|
||||
suite.addTest(new ChannelTestCase(entry));
|
||||
}
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
/** Test case with a unique name. */
|
||||
static class ChannelTestCase extends TestCase {
|
||||
final String entryName;
|
||||
ChannelTestCase(String entryName) {
|
||||
super("BrotliDecoderChannelTest." + entryName);
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
BrotliDecoderChannelTest.run(entryName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void run(String entryName) throws Throwable {
|
||||
InputStream bundle = getBundle();
|
||||
byte[] compressed;
|
||||
try {
|
||||
compressed = BundleHelper.readEntry(bundle, entryName);
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
if (compressed == null) {
|
||||
throw new RuntimeException("Can't read bundle entry: " + entryName);
|
||||
}
|
||||
|
||||
ReadableByteChannel src = Channels.newChannel(new ByteArrayInputStream(compressed));
|
||||
ReadableByteChannel decoder = new BrotliDecoderChannel(src);
|
||||
long crc;
|
||||
try {
|
||||
crc = BundleHelper.fingerprintStream(Channels.newInputStream(decoder));
|
||||
} finally {
|
||||
decoder.close();
|
||||
}
|
||||
assertEquals(BundleHelper.getExpectedFingerprint(entryName), crc);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.dec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.Channels;
|
||||
|
||||
/**
|
||||
* InputStream that wraps native brotli decoder.
|
||||
*/
|
||||
public class BrotliInputStream extends InputStream {
|
||||
/** The default internal buffer size used by the decoder. */
|
||||
private static final int DEFAULT_BUFFER_SIZE = 16384;
|
||||
|
||||
private final Decoder decoder;
|
||||
|
||||
/**
|
||||
* Creates a BrotliInputStream.
|
||||
*
|
||||
* @param source underlying source
|
||||
* @param bufferSize intermediate buffer size
|
||||
*/
|
||||
public BrotliInputStream(InputStream source, int bufferSize)
|
||||
throws IOException {
|
||||
this.decoder = new Decoder(Channels.newChannel(source), bufferSize);
|
||||
}
|
||||
|
||||
public BrotliInputStream(InputStream source) throws IOException {
|
||||
this(source, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
public void setEager(boolean eager) {
|
||||
decoder.setEager(eager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
decoder.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return (decoder.buffer != null) ? decoder.buffer.remaining() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (decoder.closed) {
|
||||
throw new IOException("read after close");
|
||||
}
|
||||
if (decoder.decode() == -1) {
|
||||
return -1;
|
||||
}
|
||||
return decoder.buffer.get() & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (decoder.closed) {
|
||||
throw new IOException("read after close");
|
||||
}
|
||||
if (decoder.decode() == -1) {
|
||||
return -1;
|
||||
}
|
||||
int result = 0;
|
||||
while (len > 0) {
|
||||
int limit = Math.min(len, decoder.buffer.remaining());
|
||||
decoder.buffer.get(b, off, limit);
|
||||
off += limit;
|
||||
len -= limit;
|
||||
result += limit;
|
||||
if (decoder.decode() == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
if (decoder.closed) {
|
||||
throw new IOException("read after close");
|
||||
}
|
||||
long result = 0;
|
||||
while (n > 0) {
|
||||
if (decoder.decode() == -1) {
|
||||
break;
|
||||
}
|
||||
int limit = (int) Math.min(n, (long) decoder.buffer.remaining());
|
||||
decoder.discard(limit);
|
||||
result += limit;
|
||||
n -= limit;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.dec;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import org.brotli.integration.BundleHelper;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.AllTests;
|
||||
|
||||
/** Tests for {@link org.brotli.wrapper.dec.BrotliInputStream}. */
|
||||
@RunWith(AllTests.class)
|
||||
public class BrotliInputStreamTest extends BrotliJniTestBase {
|
||||
|
||||
static InputStream getBundle() throws IOException {
|
||||
return new FileInputStream(System.getProperty("TEST_BUNDLE"));
|
||||
}
|
||||
|
||||
/** Creates a test suite. */
|
||||
public static TestSuite suite() throws IOException {
|
||||
TestSuite suite = new TestSuite();
|
||||
InputStream bundle = getBundle();
|
||||
try {
|
||||
List<String> entries = BundleHelper.listEntries(bundle);
|
||||
for (String entry : entries) {
|
||||
suite.addTest(new StreamTestCase(entry));
|
||||
}
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
/** Test case with a unique name. */
|
||||
static class StreamTestCase extends TestCase {
|
||||
final String entryName;
|
||||
StreamTestCase(String entryName) {
|
||||
super("BrotliInputStreamTest." + entryName);
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
BrotliInputStreamTest.run(entryName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void run(String entryName) throws Throwable {
|
||||
InputStream bundle = getBundle();
|
||||
byte[] compressed;
|
||||
try {
|
||||
compressed = BundleHelper.readEntry(bundle, entryName);
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
if (compressed == null) {
|
||||
throw new RuntimeException("Can't read bundle entry: " + entryName);
|
||||
}
|
||||
|
||||
InputStream src = new ByteArrayInputStream(compressed);
|
||||
InputStream decoder = new BrotliInputStream(src);
|
||||
long crc;
|
||||
try {
|
||||
crc = BundleHelper.fingerprintStream(decoder);
|
||||
} finally {
|
||||
decoder.close();
|
||||
}
|
||||
assertEquals(BundleHelper.getExpectedFingerprint(entryName), crc);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.dec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Base class for InputStream / Channel implementations.
|
||||
*/
|
||||
public class Decoder {
|
||||
private final ReadableByteChannel source;
|
||||
private final DecoderJNI.Wrapper decoder;
|
||||
ByteBuffer buffer;
|
||||
boolean closed;
|
||||
boolean eager;
|
||||
|
||||
/**
|
||||
* Creates a Decoder wrapper.
|
||||
*
|
||||
* @param source underlying source
|
||||
* @param inputBufferSize read buffer size
|
||||
*/
|
||||
public Decoder(ReadableByteChannel source, int inputBufferSize)
|
||||
throws IOException {
|
||||
if (inputBufferSize <= 0) {
|
||||
throw new IllegalArgumentException("buffer size must be positive");
|
||||
}
|
||||
if (source == null) {
|
||||
throw new NullPointerException("source can not be null");
|
||||
}
|
||||
this.source = source;
|
||||
this.decoder = new DecoderJNI.Wrapper(inputBufferSize);
|
||||
}
|
||||
|
||||
private void fail(String message) throws IOException {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ex) {
|
||||
/* Ignore */
|
||||
}
|
||||
throw new IOException(message);
|
||||
}
|
||||
|
||||
public void setEager(boolean eager) {
|
||||
this.eager = eager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue decoding.
|
||||
*
|
||||
* @return -1 if stream is finished, or number of bytes available in read buffer (> 0)
|
||||
*/
|
||||
int decode() throws IOException {
|
||||
while (true) {
|
||||
if (buffer != null) {
|
||||
if (!buffer.hasRemaining()) {
|
||||
buffer = null;
|
||||
} else {
|
||||
return buffer.remaining();
|
||||
}
|
||||
}
|
||||
|
||||
switch (decoder.getStatus()) {
|
||||
case DONE:
|
||||
return -1;
|
||||
|
||||
case OK:
|
||||
decoder.push(0);
|
||||
break;
|
||||
|
||||
case NEEDS_MORE_INPUT:
|
||||
// In "eager" more pulling preempts pushing.
|
||||
if (eager && decoder.hasOutput()) {
|
||||
buffer = decoder.pull();
|
||||
break;
|
||||
}
|
||||
ByteBuffer inputBuffer = decoder.getInputBuffer();
|
||||
inputBuffer.clear();
|
||||
int bytesRead = source.read(inputBuffer);
|
||||
if (bytesRead == -1) {
|
||||
fail("unexpected end of input");
|
||||
}
|
||||
decoder.push(bytesRead);
|
||||
break;
|
||||
|
||||
case NEEDS_MORE_OUTPUT:
|
||||
buffer = decoder.pull();
|
||||
break;
|
||||
|
||||
default:
|
||||
fail("corrupted input");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void discard(int length) {
|
||||
buffer.position(buffer.position() + length);
|
||||
if (!buffer.hasRemaining()) {
|
||||
buffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
int consume(ByteBuffer dst) {
|
||||
ByteBuffer slice = buffer.slice();
|
||||
int limit = Math.min(slice.remaining(), dst.remaining());
|
||||
slice.limit(limit);
|
||||
dst.put(slice);
|
||||
discard(limit);
|
||||
return limit;
|
||||
}
|
||||
|
||||
void close() throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
decoder.destroy();
|
||||
source.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the given data buffer.
|
||||
*/
|
||||
public static byte[] decompress(byte[] data) throws IOException {
|
||||
DecoderJNI.Wrapper decoder = new DecoderJNI.Wrapper(data.length);
|
||||
ArrayList<byte[]> output = new ArrayList<byte[]>();
|
||||
int totalOutputSize = 0;
|
||||
try {
|
||||
decoder.getInputBuffer().put(data);
|
||||
decoder.push(data.length);
|
||||
while (decoder.getStatus() != DecoderJNI.Status.DONE) {
|
||||
switch (decoder.getStatus()) {
|
||||
case OK:
|
||||
decoder.push(0);
|
||||
break;
|
||||
|
||||
case NEEDS_MORE_OUTPUT:
|
||||
ByteBuffer buffer = decoder.pull();
|
||||
byte[] chunk = new byte[buffer.remaining()];
|
||||
buffer.get(chunk);
|
||||
output.add(chunk);
|
||||
totalOutputSize += chunk.length;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IOException("corrupted input");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
decoder.destroy();
|
||||
}
|
||||
if (output.size() == 1) {
|
||||
return output.get(0);
|
||||
}
|
||||
byte[] result = new byte[totalOutputSize];
|
||||
int offset = 0;
|
||||
for (byte[] chunk : output) {
|
||||
System.arraycopy(chunk, 0, result, offset, chunk.length);
|
||||
offset += chunk.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.dec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* JNI wrapper for brotli decoder.
|
||||
*/
|
||||
public class DecoderJNI {
|
||||
private static native ByteBuffer nativeCreate(long[] context);
|
||||
private static native void nativePush(long[] context, int length);
|
||||
private static native ByteBuffer nativePull(long[] context);
|
||||
private static native void nativeDestroy(long[] context);
|
||||
|
||||
public enum Status {
|
||||
ERROR,
|
||||
DONE,
|
||||
NEEDS_MORE_INPUT,
|
||||
NEEDS_MORE_OUTPUT,
|
||||
OK
|
||||
};
|
||||
|
||||
public static class Wrapper {
|
||||
private final long[] context = new long[3];
|
||||
private final ByteBuffer inputBuffer;
|
||||
private Status lastStatus = Status.NEEDS_MORE_INPUT;
|
||||
|
||||
public Wrapper(int inputBufferSize) throws IOException {
|
||||
this.context[1] = inputBufferSize;
|
||||
this.inputBuffer = nativeCreate(this.context);
|
||||
if (this.context[0] == 0) {
|
||||
throw new IOException("failed to initialize native brotli decoder");
|
||||
}
|
||||
}
|
||||
|
||||
public void push(int length) {
|
||||
if (length < 0) {
|
||||
throw new IllegalArgumentException("negative block length");
|
||||
}
|
||||
if (context[0] == 0) {
|
||||
throw new IllegalStateException("brotli decoder is already destroyed");
|
||||
}
|
||||
if (lastStatus != Status.NEEDS_MORE_INPUT && lastStatus != Status.OK) {
|
||||
throw new IllegalStateException("pushing input to decoder in " + lastStatus + " state");
|
||||
}
|
||||
if (lastStatus == Status.OK && length != 0) {
|
||||
throw new IllegalStateException("pushing input to decoder in OK state");
|
||||
}
|
||||
nativePush(context, length);
|
||||
parseStatus();
|
||||
}
|
||||
|
||||
private void parseStatus() {
|
||||
long status = context[1];
|
||||
if (status == 1) {
|
||||
lastStatus = Status.DONE;
|
||||
} else if (status == 2) {
|
||||
lastStatus = Status.NEEDS_MORE_INPUT;
|
||||
} else if (status == 3) {
|
||||
lastStatus = Status.NEEDS_MORE_OUTPUT;
|
||||
} else if (status == 4) {
|
||||
lastStatus = Status.OK;
|
||||
} else {
|
||||
lastStatus = Status.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return lastStatus;
|
||||
}
|
||||
|
||||
public ByteBuffer getInputBuffer() {
|
||||
return inputBuffer;
|
||||
}
|
||||
|
||||
public boolean hasOutput() {
|
||||
return context[2] != 0;
|
||||
}
|
||||
|
||||
public ByteBuffer pull() {
|
||||
if (context[0] == 0) {
|
||||
throw new IllegalStateException("brotli decoder is already destroyed");
|
||||
}
|
||||
if (lastStatus != Status.NEEDS_MORE_OUTPUT && !hasOutput()) {
|
||||
throw new IllegalStateException("pulling output from decoder in " + lastStatus + " state");
|
||||
}
|
||||
ByteBuffer result = nativePull(context);
|
||||
parseStatus();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases native resources.
|
||||
*/
|
||||
public void destroy() {
|
||||
if (context[0] == 0) {
|
||||
throw new IllegalStateException("brotli decoder is already destroyed");
|
||||
}
|
||||
nativeDestroy(context);
|
||||
context[0] = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
if (context[0] != 0) {
|
||||
/* TODO: log resource leak? */
|
||||
destroy();
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.dec;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import org.brotli.integration.BundleHelper;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.AllTests;
|
||||
|
||||
/** Tests for {@link org.brotli.wrapper.dec.Decoder}. */
|
||||
@RunWith(AllTests.class)
|
||||
public class DecoderTest extends BrotliJniTestBase {
|
||||
|
||||
static InputStream getBundle() throws IOException {
|
||||
return new FileInputStream(System.getProperty("TEST_BUNDLE"));
|
||||
}
|
||||
|
||||
/** Creates a test suite. */
|
||||
public static TestSuite suite() throws IOException {
|
||||
TestSuite suite = new TestSuite();
|
||||
InputStream bundle = getBundle();
|
||||
try {
|
||||
List<String> entries = BundleHelper.listEntries(bundle);
|
||||
for (String entry : entries) {
|
||||
suite.addTest(new DecoderTestCase(entry));
|
||||
}
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
/** Test case with a unique name. */
|
||||
static class DecoderTestCase extends TestCase {
|
||||
final String entryName;
|
||||
DecoderTestCase(String entryName) {
|
||||
super("DecoderTest." + entryName);
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
DecoderTest.run(entryName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void run(String entryName) throws Throwable {
|
||||
InputStream bundle = getBundle();
|
||||
byte[] compressed;
|
||||
try {
|
||||
compressed = BundleHelper.readEntry(bundle, entryName);
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
if (compressed == null) {
|
||||
throw new RuntimeException("Can't read bundle entry: " + entryName);
|
||||
}
|
||||
|
||||
byte[] decompressed = Decoder.decompress(compressed);
|
||||
|
||||
long crc = BundleHelper.fingerprintStream(new ByteArrayInputStream(decompressed));
|
||||
assertEquals(BundleHelper.getExpectedFingerprint(entryName), crc);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.dec;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Tests for {@link org.brotli.wrapper.dec.BrotliInputStream}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class EagerStreamTest extends BrotliJniTestBase {
|
||||
|
||||
@Test
|
||||
public void testEagerReading() throws IOException {
|
||||
final StringBuilder log = new StringBuilder();
|
||||
final byte[] data = {0, 0, 16, 42, 3};
|
||||
InputStream source = new InputStream() {
|
||||
int index;
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
if (index < data.length) {
|
||||
log.append("<").append(index);
|
||||
return data[index++];
|
||||
} else {
|
||||
log.append("<#");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (len < 1) {
|
||||
return 0;
|
||||
}
|
||||
int d = read();
|
||||
if (d == -1) {
|
||||
return 0;
|
||||
}
|
||||
b[off] = (byte) d;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
BrotliInputStream reader = new BrotliInputStream(source);
|
||||
reader.setEager(true);
|
||||
int count = 0;
|
||||
while (true) {
|
||||
log.append("^").append(count);
|
||||
int b = reader.read();
|
||||
if (b == -1) {
|
||||
log.append(">#");
|
||||
break;
|
||||
} else {
|
||||
log.append(">").append(count++);
|
||||
}
|
||||
}
|
||||
// Lazy log: ^0<0<1<2<3<4>0^1>#
|
||||
assertEquals("^0<0<1<2<3>0^1<4>#", log.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <brotli/decode.h>
|
||||
|
||||
namespace {
|
||||
/* A structure used to persist the decoder's state in between calls. */
|
||||
typedef struct DecoderHandle {
|
||||
BrotliDecoderState* state;
|
||||
|
||||
uint8_t* input_start;
|
||||
size_t input_offset;
|
||||
size_t input_length;
|
||||
} DecoderHandle;
|
||||
|
||||
/* Obtain handle from opaque pointer. */
|
||||
DecoderHandle* getHandle(void* opaque) {
|
||||
return static_cast<DecoderHandle*>(opaque);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a new Decoder.
|
||||
*
|
||||
* Cookie to address created decoder is stored in out_cookie. In case of failure
|
||||
* cookie is 0.
|
||||
*
|
||||
* @param ctx {out_cookie, in_directBufferSize} tuple
|
||||
* @returns direct ByteBuffer if directBufferSize is not 0; otherwise null
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_brotli_wrapper_dec_DecoderJNI_nativeCreate(
|
||||
JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
|
||||
bool ok = true;
|
||||
DecoderHandle* handle = nullptr;
|
||||
jlong context[3];
|
||||
env->GetLongArrayRegion(ctx, 0, 3, context);
|
||||
size_t input_size = context[1];
|
||||
context[0] = 0;
|
||||
context[2] = 0;
|
||||
handle = new (std::nothrow) DecoderHandle();
|
||||
ok = !!handle;
|
||||
|
||||
if (ok) {
|
||||
handle->input_offset = 0;
|
||||
handle->input_length = 0;
|
||||
handle->input_start = nullptr;
|
||||
|
||||
if (input_size == 0) {
|
||||
ok = false;
|
||||
} else {
|
||||
handle->input_start = new (std::nothrow) uint8_t[input_size];
|
||||
ok = !!handle->input_start;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
handle->state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
|
||||
ok = !!handle->state;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* TODO: future versions (e.g. when 128-bit architecture comes)
|
||||
might require thread-safe cookie<->handle mapping. */
|
||||
context[0] = reinterpret_cast<jlong>(handle);
|
||||
} else if (!!handle) {
|
||||
if (!!handle->input_start) delete[] handle->input_start;
|
||||
delete handle;
|
||||
}
|
||||
|
||||
env->SetLongArrayRegion(ctx, 0, 3, context);
|
||||
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return env->NewDirectByteBuffer(handle->input_start, input_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push data to decoder.
|
||||
*
|
||||
* status codes:
|
||||
* - 0 error happened
|
||||
* - 1 stream is finished, no more input / output expected
|
||||
* - 2 needs more input to process further
|
||||
* - 3 needs more output to process further
|
||||
* - 4 ok, can proceed further without additional input
|
||||
*
|
||||
* @param ctx {in_cookie, out_status} tuple
|
||||
* @param input_length number of bytes provided in input or direct input;
|
||||
* 0 to process further previous input
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_brotli_wrapper_dec_DecoderJNI_nativePush(
|
||||
JNIEnv* env, jobject /*jobj*/, jlongArray ctx, jint input_length) {
|
||||
jlong context[3];
|
||||
env->GetLongArrayRegion(ctx, 0, 3, context);
|
||||
DecoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
|
||||
context[1] = 0; /* ERROR */
|
||||
context[2] = 0;
|
||||
env->SetLongArrayRegion(ctx, 0, 3, context);
|
||||
|
||||
if (input_length != 0) {
|
||||
/* Still have unconsumed data. Workflow is broken. */
|
||||
if (handle->input_offset < handle->input_length) {
|
||||
return;
|
||||
}
|
||||
handle->input_offset = 0;
|
||||
handle->input_length = input_length;
|
||||
}
|
||||
|
||||
/* Actual decompression. */
|
||||
const uint8_t* in = handle->input_start + handle->input_offset;
|
||||
size_t in_size = handle->input_length - handle->input_offset;
|
||||
size_t out_size = 0;
|
||||
BrotliDecoderResult status = BrotliDecoderDecompressStream(
|
||||
handle->state, &in_size, &in, &out_size, nullptr, nullptr);
|
||||
handle->input_offset = handle->input_length - in_size;
|
||||
switch (status) {
|
||||
case BROTLI_DECODER_RESULT_SUCCESS:
|
||||
/* Bytes after stream end are not allowed. */
|
||||
context[1] = (handle->input_offset == handle->input_length) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
|
||||
context[1] = 2;
|
||||
break;
|
||||
|
||||
case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
|
||||
context[1] = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
context[1] = 0;
|
||||
break;
|
||||
}
|
||||
context[2] = BrotliDecoderHasMoreOutput(handle->state) ? 1 : 0;
|
||||
env->SetLongArrayRegion(ctx, 0, 3, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull decompressed data from decoder.
|
||||
*
|
||||
* @param ctx {in_cookie, out_status} tuple
|
||||
* @returns direct ByteBuffer; all the produced data MUST be consumed before
|
||||
* any further invocation; null in case of error
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_brotli_wrapper_dec_DecoderJNI_nativePull(
|
||||
JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
|
||||
jlong context[3];
|
||||
env->GetLongArrayRegion(ctx, 0, 3, context);
|
||||
DecoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
|
||||
size_t data_length = 0;
|
||||
const uint8_t* data = BrotliDecoderTakeOutput(handle->state, &data_length);
|
||||
bool hasMoreOutput = !!BrotliDecoderHasMoreOutput(handle->state);
|
||||
if (hasMoreOutput) {
|
||||
context[1] = 3;
|
||||
} else if (BrotliDecoderIsFinished(handle->state)) {
|
||||
/* Bytes after stream end are not allowed. */
|
||||
context[1] = (handle->input_offset == handle->input_length) ? 1 : 0;
|
||||
} else {
|
||||
/* Can proceed, or more data is required? */
|
||||
context[1] = (handle->input_offset == handle->input_length) ? 2 : 4;
|
||||
}
|
||||
context[2] = hasMoreOutput ? 1 : 0;
|
||||
env->SetLongArrayRegion(ctx, 0, 3, context);
|
||||
return env->NewDirectByteBuffer(const_cast<uint8_t*>(data), data_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all used resources.
|
||||
*
|
||||
* @param ctx {in_cookie} tuple
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_brotli_wrapper_dec_DecoderJNI_nativeDestroy(
|
||||
JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
|
||||
jlong context[3];
|
||||
env->GetLongArrayRegion(ctx, 0, 3, context);
|
||||
DecoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
|
||||
BrotliDecoderDestroyInstance(handle->state);
|
||||
delete[] handle->input_start;
|
||||
delete handle;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # MIT
|
||||
|
||||
filegroup(
|
||||
name = "jni_src",
|
||||
srcs = ["encoder_jni.cc"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "brotli_jni",
|
||||
srcs = ["//:brotli_jni.dll"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "enc",
|
||||
srcs = glob(
|
||||
["*.java"],
|
||||
exclude = ["*Test*.java"],
|
||||
),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_bundle",
|
||||
srcs = ["//java/org/brotli/integration:test_corpus"],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "BrotliEncoderChannelTest",
|
||||
size = "large",
|
||||
srcs = ["BrotliEncoderChannelTest.java"],
|
||||
data = [
|
||||
":brotli_jni", # Bazel JNI workaround
|
||||
":test_bundle",
|
||||
],
|
||||
jvm_flags = [
|
||||
"-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
|
||||
"-DTEST_BUNDLE=$(location :test_bundle)",
|
||||
],
|
||||
shard_count = 15,
|
||||
deps = [
|
||||
":enc",
|
||||
"//java/org/brotli/integration:brotli_jni_test_base",
|
||||
"//java/org/brotli/integration:bundle_helper",
|
||||
"//java/org/brotli/wrapper/dec",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "BrotliOutputStreamTest",
|
||||
size = "large",
|
||||
srcs = ["BrotliOutputStreamTest.java"],
|
||||
data = [
|
||||
":brotli_jni", # Bazel JNI workaround
|
||||
":test_bundle",
|
||||
],
|
||||
jvm_flags = [
|
||||
"-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
|
||||
"-DTEST_BUNDLE=$(location :test_bundle)",
|
||||
],
|
||||
shard_count = 15,
|
||||
deps = [
|
||||
":enc",
|
||||
"//java/org/brotli/integration:brotli_jni_test_base",
|
||||
"//java/org/brotli/integration:bundle_helper",
|
||||
"//java/org/brotli/wrapper/dec",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
||||
java_test(
|
||||
name = "EncoderTest",
|
||||
size = "large",
|
||||
srcs = ["EncoderTest.java"],
|
||||
data = [
|
||||
":brotli_jni", # Bazel JNI workaround
|
||||
":test_bundle",
|
||||
],
|
||||
jvm_flags = [
|
||||
"-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
|
||||
"-DTEST_BUNDLE=$(location :test_bundle)",
|
||||
],
|
||||
shard_count = 15,
|
||||
deps = [
|
||||
":enc",
|
||||
"//java/org/brotli/integration:brotli_jni_test_base",
|
||||
"//java/org/brotli/integration:bundle_helper",
|
||||
"//java/org/brotli/wrapper/dec",
|
||||
"@junit_junit//jar",
|
||||
],
|
||||
)
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.enc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
/**
|
||||
* WritableByteChannel that wraps native brotli encoder.
|
||||
*/
|
||||
public class BrotliEncoderChannel extends Encoder implements WritableByteChannel {
|
||||
/** The default internal buffer size used by the decoder. */
|
||||
private static final int DEFAULT_BUFFER_SIZE = 16384;
|
||||
|
||||
private final Object mutex = new Object();
|
||||
|
||||
/**
|
||||
* Creates a BrotliEncoderChannel.
|
||||
*
|
||||
* @param destination underlying destination
|
||||
* @param params encoding settings
|
||||
* @param bufferSize intermediate buffer size
|
||||
*/
|
||||
public BrotliEncoderChannel(WritableByteChannel destination, Encoder.Parameters params,
|
||||
int bufferSize) throws IOException {
|
||||
super(destination, params, bufferSize);
|
||||
}
|
||||
|
||||
public BrotliEncoderChannel(WritableByteChannel destination, Encoder.Parameters params)
|
||||
throws IOException {
|
||||
this(destination, params, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
public BrotliEncoderChannel(WritableByteChannel destination) throws IOException {
|
||||
this(destination, new Encoder.Parameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
synchronized (mutex) {
|
||||
return !closed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
synchronized (mutex) {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
synchronized (mutex) {
|
||||
if (closed) {
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
int result = 0;
|
||||
while (src.hasRemaining() && encode(EncoderJNI.Operation.PROCESS)) {
|
||||
int limit = Math.min(src.remaining(), inputBuffer.remaining());
|
||||
ByteBuffer slice = src.slice();
|
||||
slice.limit(limit);
|
||||
inputBuffer.put(slice);
|
||||
result += limit;
|
||||
src.position(src.position() + limit);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
package org.brotli.wrapper.enc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import org.brotli.integration.BundleHelper;
|
||||
import org.brotli.wrapper.dec.BrotliInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.List;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.AllTests;
|
||||
|
||||
/** Tests for {@link org.brotli.wrapper.enc.BrotliEncoderChannel}. */
|
||||
@RunWith(AllTests.class)
|
||||
public class BrotliEncoderChannelTest extends BrotliJniTestBase {
|
||||
|
||||
private enum TestMode {
|
||||
WRITE_ALL,
|
||||
WRITE_CHUNKS
|
||||
}
|
||||
|
||||
private static final int CHUNK_SIZE = 256;
|
||||
|
||||
static InputStream getBundle() throws IOException {
|
||||
return new FileInputStream(System.getProperty("TEST_BUNDLE"));
|
||||
}
|
||||
|
||||
/** Creates a test suite. */
|
||||
public static TestSuite suite() throws IOException {
|
||||
TestSuite suite = new TestSuite();
|
||||
InputStream bundle = getBundle();
|
||||
try {
|
||||
List<String> entries = BundleHelper.listEntries(bundle);
|
||||
for (String entry : entries) {
|
||||
suite.addTest(new ChannleTestCase(entry, TestMode.WRITE_ALL));
|
||||
suite.addTest(new ChannleTestCase(entry, TestMode.WRITE_CHUNKS));
|
||||
}
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
/** Test case with a unique name. */
|
||||
static class ChannleTestCase extends TestCase {
|
||||
final String entryName;
|
||||
final TestMode mode;
|
||||
ChannleTestCase(String entryName, TestMode mode) {
|
||||
super("BrotliEncoderChannelTest." + entryName + "." + mode.name());
|
||||
this.entryName = entryName;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
BrotliEncoderChannelTest.run(entryName, mode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void run(String entryName, TestMode mode) throws Throwable {
|
||||
InputStream bundle = getBundle();
|
||||
byte[] original;
|
||||
try {
|
||||
original = BundleHelper.readEntry(bundle, entryName);
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
if (original == null) {
|
||||
throw new RuntimeException("Can't read bundle entry: " + entryName);
|
||||
}
|
||||
|
||||
if ((mode == TestMode.WRITE_CHUNKS) && (original.length <= CHUNK_SIZE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream dst = new ByteArrayOutputStream();
|
||||
WritableByteChannel encoder = new BrotliEncoderChannel(Channels.newChannel(dst));
|
||||
ByteBuffer src = ByteBuffer.wrap(original);
|
||||
try {
|
||||
switch (mode) {
|
||||
case WRITE_ALL:
|
||||
encoder.write(src);
|
||||
break;
|
||||
|
||||
case WRITE_CHUNKS:
|
||||
while (src.hasRemaining()) {
|
||||
int limit = Math.min(CHUNK_SIZE, src.remaining());
|
||||
ByteBuffer slice = src.slice();
|
||||
slice.limit(limit);
|
||||
src.position(src.position() + limit);
|
||||
encoder.write(slice);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
encoder.close();
|
||||
}
|
||||
|
||||
InputStream decoder = new BrotliInputStream(new ByteArrayInputStream(dst.toByteArray()));
|
||||
try {
|
||||
long originalCrc = BundleHelper.fingerprintStream(new ByteArrayInputStream(original));
|
||||
long crc = BundleHelper.fingerprintStream(decoder);
|
||||
assertEquals(originalCrc, crc);
|
||||
} finally {
|
||||
decoder.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.enc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.Channels;
|
||||
|
||||
/**
|
||||
* Output stream that wraps native brotli encoder.
|
||||
*/
|
||||
public class BrotliOutputStream extends OutputStream {
|
||||
/** The default internal buffer size used by the encoder. */
|
||||
private static final int DEFAULT_BUFFER_SIZE = 16384;
|
||||
|
||||
private final Encoder encoder;
|
||||
|
||||
/**
|
||||
* Creates a BrotliOutputStream.
|
||||
*
|
||||
* @param destination underlying destination
|
||||
* @param params encoding settings
|
||||
* @param bufferSize intermediate buffer size
|
||||
*/
|
||||
public BrotliOutputStream(OutputStream destination, Encoder.Parameters params, int bufferSize)
|
||||
throws IOException {
|
||||
this.encoder = new Encoder(Channels.newChannel(destination), params, bufferSize);
|
||||
}
|
||||
|
||||
public BrotliOutputStream(OutputStream destination, Encoder.Parameters params)
|
||||
throws IOException {
|
||||
this(destination, params, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
public BrotliOutputStream(OutputStream destination) throws IOException {
|
||||
this(destination, new Encoder.Parameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
encoder.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
if (encoder.closed) {
|
||||
throw new IOException("write after close");
|
||||
}
|
||||
encoder.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (encoder.closed) {
|
||||
throw new IOException("write after close");
|
||||
}
|
||||
while (!encoder.encode(EncoderJNI.Operation.PROCESS)) {
|
||||
// Busy-wait loop.
|
||||
}
|
||||
encoder.inputBuffer.put((byte) b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
this.write(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
if (encoder.closed) {
|
||||
throw new IOException("write after close");
|
||||
}
|
||||
while (len > 0) {
|
||||
if (!encoder.encode(EncoderJNI.Operation.PROCESS)) {
|
||||
continue;
|
||||
}
|
||||
int limit = Math.min(len, encoder.inputBuffer.remaining());
|
||||
encoder.inputBuffer.put(b, off, limit);
|
||||
off += limit;
|
||||
len -= limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
package org.brotli.wrapper.enc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import org.brotli.integration.BundleHelper;
|
||||
import org.brotli.wrapper.dec.BrotliInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.AllTests;
|
||||
|
||||
/** Tests for {@link org.brotli.wrapper.enc.BrotliOutputStream}. */
|
||||
@RunWith(AllTests.class)
|
||||
public class BrotliOutputStreamTest extends BrotliJniTestBase {
|
||||
|
||||
private enum TestMode {
|
||||
WRITE_ALL,
|
||||
WRITE_CHUNKS,
|
||||
WRITE_BYTE
|
||||
}
|
||||
|
||||
private static final int CHUNK_SIZE = 256;
|
||||
|
||||
static InputStream getBundle() throws IOException {
|
||||
return new FileInputStream(System.getProperty("TEST_BUNDLE"));
|
||||
}
|
||||
|
||||
/** Creates a test suite. */
|
||||
public static TestSuite suite() throws IOException {
|
||||
TestSuite suite = new TestSuite();
|
||||
InputStream bundle = getBundle();
|
||||
try {
|
||||
List<String> entries = BundleHelper.listEntries(bundle);
|
||||
for (String entry : entries) {
|
||||
suite.addTest(new StreamTestCase(entry, TestMode.WRITE_ALL));
|
||||
suite.addTest(new StreamTestCase(entry, TestMode.WRITE_CHUNKS));
|
||||
suite.addTest(new StreamTestCase(entry, TestMode.WRITE_BYTE));
|
||||
}
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
/** Test case with a unique name. */
|
||||
static class StreamTestCase extends TestCase {
|
||||
final String entryName;
|
||||
final TestMode mode;
|
||||
StreamTestCase(String entryName, TestMode mode) {
|
||||
super("BrotliOutputStreamTest." + entryName + "." + mode.name());
|
||||
this.entryName = entryName;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
BrotliOutputStreamTest.run(entryName, mode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void run(String entryName, TestMode mode) throws Throwable {
|
||||
InputStream bundle = getBundle();
|
||||
byte[] original;
|
||||
try {
|
||||
original = BundleHelper.readEntry(bundle, entryName);
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
if (original == null) {
|
||||
throw new RuntimeException("Can't read bundle entry: " + entryName);
|
||||
}
|
||||
|
||||
if ((mode == TestMode.WRITE_CHUNKS) && (original.length <= CHUNK_SIZE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream dst = new ByteArrayOutputStream();
|
||||
OutputStream encoder = new BrotliOutputStream(dst);
|
||||
try {
|
||||
switch (mode) {
|
||||
case WRITE_ALL:
|
||||
encoder.write(original);
|
||||
break;
|
||||
|
||||
case WRITE_CHUNKS:
|
||||
for (int offset = 0; offset < original.length; offset += CHUNK_SIZE) {
|
||||
encoder.write(original, offset, Math.min(CHUNK_SIZE, original.length - offset));
|
||||
}
|
||||
break;
|
||||
|
||||
case WRITE_BYTE:
|
||||
for (byte singleByte : original) {
|
||||
encoder.write(singleByte);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
encoder.close();
|
||||
}
|
||||
|
||||
InputStream decoder = new BrotliInputStream(new ByteArrayInputStream(dst.toByteArray()));
|
||||
try {
|
||||
long originalCrc = BundleHelper.fingerprintStream(new ByteArrayInputStream(original));
|
||||
long crc = BundleHelper.fingerprintStream(decoder);
|
||||
assertEquals(originalCrc, crc);
|
||||
} finally {
|
||||
decoder.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.enc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Base class for OutputStream / Channel implementations.
|
||||
*/
|
||||
public class Encoder {
|
||||
private final WritableByteChannel destination;
|
||||
private final EncoderJNI.Wrapper encoder;
|
||||
final ByteBuffer inputBuffer;
|
||||
ByteBuffer buffer;
|
||||
boolean closed;
|
||||
|
||||
/**
|
||||
* Brotli encoder settings.
|
||||
*/
|
||||
public static final class Parameters {
|
||||
private int quality = -1;
|
||||
private int lgwin = -1;
|
||||
|
||||
public Parameters() { }
|
||||
|
||||
private Parameters(Parameters other) {
|
||||
this.quality = other.quality;
|
||||
this.lgwin = other.lgwin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param quality compression quality, or -1 for default
|
||||
*/
|
||||
public Parameters setQuality(int quality) {
|
||||
if (quality < -1 || quality > 11) {
|
||||
throw new IllegalArgumentException("quality should be in range [0, 11], or -1");
|
||||
}
|
||||
this.quality = quality;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lgwin log2(LZ window size), or -1 for default
|
||||
*/
|
||||
public Parameters setWindow(int lgwin) {
|
||||
if ((lgwin != -1) && ((lgwin < 10) || (lgwin > 24))) {
|
||||
throw new IllegalArgumentException("lgwin should be in range [10, 24], or -1");
|
||||
}
|
||||
this.lgwin = lgwin;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Encoder wrapper.
|
||||
*
|
||||
* @param destination underlying destination
|
||||
* @param params encoding parameters
|
||||
* @param inputBufferSize read buffer size
|
||||
*/
|
||||
Encoder(WritableByteChannel destination, Parameters params, int inputBufferSize)
|
||||
throws IOException {
|
||||
if (inputBufferSize <= 0) {
|
||||
throw new IllegalArgumentException("buffer size must be positive");
|
||||
}
|
||||
if (destination == null) {
|
||||
throw new NullPointerException("destination can not be null");
|
||||
}
|
||||
this.destination = destination;
|
||||
this.encoder = new EncoderJNI.Wrapper(inputBufferSize, params.quality, params.lgwin);
|
||||
this.inputBuffer = this.encoder.getInputBuffer();
|
||||
}
|
||||
|
||||
private void fail(String message) throws IOException {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ex) {
|
||||
/* Ignore */
|
||||
}
|
||||
throw new IOException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param force repeat pushing until all output is consumed
|
||||
* @return true if all encoder output is consumed
|
||||
*/
|
||||
boolean pushOutput(boolean force) throws IOException {
|
||||
while (buffer != null) {
|
||||
if (buffer.hasRemaining()) {
|
||||
destination.write(buffer);
|
||||
}
|
||||
if (!buffer.hasRemaining()) {
|
||||
buffer = null;
|
||||
} else if (!force) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there is space in inputBuffer.
|
||||
*/
|
||||
boolean encode(EncoderJNI.Operation op) throws IOException {
|
||||
boolean force = (op != EncoderJNI.Operation.PROCESS);
|
||||
if (force) {
|
||||
inputBuffer.limit(inputBuffer.position());
|
||||
} else if (inputBuffer.hasRemaining()) {
|
||||
return true;
|
||||
}
|
||||
boolean hasInput = true;
|
||||
while (true) {
|
||||
if (!encoder.isSuccess()) {
|
||||
fail("encoding failed");
|
||||
} else if (!pushOutput(force)) {
|
||||
return false;
|
||||
} else if (encoder.hasMoreOutput()) {
|
||||
buffer = encoder.pull();
|
||||
} else if (encoder.hasRemainingInput()) {
|
||||
encoder.push(op, 0);
|
||||
} else if (hasInput) {
|
||||
encoder.push(op, inputBuffer.limit());
|
||||
hasInput = false;
|
||||
} else {
|
||||
inputBuffer.clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flush() throws IOException {
|
||||
encode(EncoderJNI.Operation.FLUSH);
|
||||
}
|
||||
|
||||
void close() throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
try {
|
||||
encode(EncoderJNI.Operation.FINISH);
|
||||
} finally {
|
||||
encoder.destroy();
|
||||
destination.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given data buffer.
|
||||
*/
|
||||
public static byte[] compress(byte[] data, Parameters params) throws IOException {
|
||||
EncoderJNI.Wrapper encoder = new EncoderJNI.Wrapper(data.length, params.quality, params.lgwin);
|
||||
ArrayList<byte[]> output = new ArrayList<byte[]>();
|
||||
int totalOutputSize = 0;
|
||||
try {
|
||||
encoder.getInputBuffer().put(data);
|
||||
encoder.push(EncoderJNI.Operation.FINISH, data.length);
|
||||
while (true) {
|
||||
if (!encoder.isSuccess()) {
|
||||
throw new IOException("encoding failed");
|
||||
} else if (encoder.hasMoreOutput()) {
|
||||
ByteBuffer buffer = encoder.pull();
|
||||
byte[] chunk = new byte[buffer.remaining()];
|
||||
buffer.get(chunk);
|
||||
output.add(chunk);
|
||||
totalOutputSize += chunk.length;
|
||||
} else if (!encoder.isFinished()) {
|
||||
encoder.push(EncoderJNI.Operation.FINISH, 0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
encoder.destroy();
|
||||
}
|
||||
if (output.size() == 1) {
|
||||
return output.get(0);
|
||||
}
|
||||
byte[] result = new byte[totalOutputSize];
|
||||
int offset = 0;
|
||||
for (byte[] chunk : output) {
|
||||
System.arraycopy(chunk, 0, result, offset, chunk.length);
|
||||
offset += chunk.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] compress(byte[] data) throws IOException {
|
||||
return compress(data, new Parameters());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
package org.brotli.wrapper.enc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* JNI wrapper for brotli encoder.
|
||||
*/
|
||||
class EncoderJNI {
|
||||
private static native ByteBuffer nativeCreate(long[] context);
|
||||
private static native void nativePush(long[] context, int length);
|
||||
private static native ByteBuffer nativePull(long[] context);
|
||||
private static native void nativeDestroy(long[] context);
|
||||
|
||||
enum Operation {
|
||||
PROCESS,
|
||||
FLUSH,
|
||||
FINISH
|
||||
}
|
||||
|
||||
static class Wrapper {
|
||||
protected final long[] context = new long[5];
|
||||
private final ByteBuffer inputBuffer;
|
||||
|
||||
Wrapper(int inputBufferSize, int quality, int lgwin)
|
||||
throws IOException {
|
||||
this.context[1] = inputBufferSize;
|
||||
this.context[2] = quality;
|
||||
this.context[3] = lgwin;
|
||||
this.inputBuffer = nativeCreate(this.context);
|
||||
if (this.context[0] == 0) {
|
||||
throw new IOException("failed to initialize native brotli encoder");
|
||||
}
|
||||
this.context[1] = 1;
|
||||
this.context[2] = 0;
|
||||
this.context[3] = 0;
|
||||
}
|
||||
|
||||
void push(Operation op, int length) {
|
||||
if (length < 0) {
|
||||
throw new IllegalArgumentException("negative block length");
|
||||
}
|
||||
if (context[0] == 0) {
|
||||
throw new IllegalStateException("brotli encoder is already destroyed");
|
||||
}
|
||||
if (!isSuccess() || hasMoreOutput()) {
|
||||
throw new IllegalStateException("pushing input to encoder in unexpected state");
|
||||
}
|
||||
if (hasRemainingInput() && length != 0) {
|
||||
throw new IllegalStateException("pushing input to encoder over previous input");
|
||||
}
|
||||
context[1] = op.ordinal();
|
||||
nativePush(context, length);
|
||||
}
|
||||
|
||||
boolean isSuccess() {
|
||||
return context[1] != 0;
|
||||
}
|
||||
|
||||
boolean hasMoreOutput() {
|
||||
return context[2] != 0;
|
||||
}
|
||||
|
||||
boolean hasRemainingInput() {
|
||||
return context[3] != 0;
|
||||
}
|
||||
|
||||
boolean isFinished() {
|
||||
return context[4] != 0;
|
||||
}
|
||||
|
||||
ByteBuffer getInputBuffer() {
|
||||
return inputBuffer;
|
||||
}
|
||||
|
||||
ByteBuffer pull() {
|
||||
if (context[0] == 0) {
|
||||
throw new IllegalStateException("brotli encoder is already destroyed");
|
||||
}
|
||||
if (!isSuccess() || !hasMoreOutput()) {
|
||||
throw new IllegalStateException("pulling while data is not ready");
|
||||
}
|
||||
return nativePull(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases native resources.
|
||||
*/
|
||||
void destroy() {
|
||||
if (context[0] == 0) {
|
||||
throw new IllegalStateException("brotli encoder is already destroyed");
|
||||
}
|
||||
nativeDestroy(context);
|
||||
context[0] = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
if (context[0] != 0) {
|
||||
/* TODO: log resource leak? */
|
||||
destroy();
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
package org.brotli.wrapper.enc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.brotli.integration.BrotliJniTestBase;
|
||||
import org.brotli.integration.BundleHelper;
|
||||
import org.brotli.wrapper.dec.BrotliInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.AllTests;
|
||||
|
||||
/** Tests for {@link org.brotli.wrapper.enc.Encoder}. */
|
||||
@RunWith(AllTests.class)
|
||||
public class EncoderTest extends BrotliJniTestBase {
|
||||
static InputStream getBundle() throws IOException {
|
||||
return new FileInputStream(System.getProperty("TEST_BUNDLE"));
|
||||
}
|
||||
|
||||
/** Creates a test suite. */
|
||||
public static TestSuite suite() throws IOException {
|
||||
TestSuite suite = new TestSuite();
|
||||
InputStream bundle = getBundle();
|
||||
try {
|
||||
List<String> entries = BundleHelper.listEntries(bundle);
|
||||
for (String entry : entries) {
|
||||
suite.addTest(new EncoderTestCase(entry));
|
||||
}
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
/** Test case with a unique name. */
|
||||
static class EncoderTestCase extends TestCase {
|
||||
final String entryName;
|
||||
EncoderTestCase(String entryName) {
|
||||
super("EncoderTest." + entryName);
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
EncoderTest.run(entryName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void run(String entryName) throws Throwable {
|
||||
InputStream bundle = getBundle();
|
||||
byte[] original;
|
||||
try {
|
||||
original = BundleHelper.readEntry(bundle, entryName);
|
||||
} finally {
|
||||
bundle.close();
|
||||
}
|
||||
if (original == null) {
|
||||
throw new RuntimeException("Can't read bundle entry: " + entryName);
|
||||
}
|
||||
|
||||
for (int window = 10; window <= 22; window++) {
|
||||
byte[] compressed =
|
||||
Encoder.compress(original, new Encoder.Parameters().setQuality(6).setWindow(window));
|
||||
|
||||
InputStream decoder = new BrotliInputStream(new ByteArrayInputStream(compressed));
|
||||
try {
|
||||
long originalCrc = BundleHelper.fingerprintStream(new ByteArrayInputStream(original));
|
||||
long crc = BundleHelper.fingerprintStream(decoder);
|
||||
assertEquals(originalCrc, crc);
|
||||
} finally {
|
||||
decoder.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <brotli/encode.h>
|
||||
|
||||
namespace {
|
||||
/* A structure used to persist the encoder's state in between calls. */
|
||||
typedef struct EncoderHandle {
|
||||
BrotliEncoderState* state;
|
||||
|
||||
uint8_t* input_start;
|
||||
size_t input_offset;
|
||||
size_t input_last;
|
||||
} EncoderHandle;
|
||||
|
||||
/* Obtain handle from opaque pointer. */
|
||||
EncoderHandle* getHandle(void* opaque) {
|
||||
return static_cast<EncoderHandle*>(opaque);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a new Encoder.
|
||||
*
|
||||
* Cookie to address created encoder is stored in out_cookie. In case of failure
|
||||
* cookie is 0.
|
||||
*
|
||||
* @param ctx {out_cookie, in_directBufferSize, in_quality, in_lgwin} tuple
|
||||
* @returns direct ByteBuffer if directBufferSize is not 0; otherwise null
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_brotli_wrapper_enc_EncoderJNI_nativeCreate(
|
||||
JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
|
||||
bool ok = true;
|
||||
EncoderHandle* handle = nullptr;
|
||||
jlong context[5];
|
||||
env->GetLongArrayRegion(ctx, 0, 5, context);
|
||||
size_t input_size = context[1];
|
||||
context[0] = 0;
|
||||
handle = new (std::nothrow) EncoderHandle();
|
||||
ok = !!handle;
|
||||
|
||||
if (ok) {
|
||||
handle->input_offset = 0;
|
||||
handle->input_last = 0;
|
||||
handle->input_start = nullptr;
|
||||
|
||||
if (input_size == 0) {
|
||||
ok = false;
|
||||
} else {
|
||||
handle->input_start = new (std::nothrow) uint8_t[input_size];
|
||||
ok = !!handle->input_start;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
handle->state = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
|
||||
ok = !!handle->state;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
int quality = context[2];
|
||||
if (quality >= 0) {
|
||||
BrotliEncoderSetParameter(handle->state, BROTLI_PARAM_QUALITY, quality);
|
||||
}
|
||||
int lgwin = context[3];
|
||||
if (lgwin >= 0) {
|
||||
BrotliEncoderSetParameter(handle->state, BROTLI_PARAM_LGWIN, lgwin);
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* TODO: future versions (e.g. when 128-bit architecture comes)
|
||||
might require thread-safe cookie<->handle mapping. */
|
||||
context[0] = reinterpret_cast<jlong>(handle);
|
||||
} else if (!!handle) {
|
||||
if (!!handle->input_start) delete[] handle->input_start;
|
||||
delete handle;
|
||||
}
|
||||
|
||||
env->SetLongArrayRegion(ctx, 0, 1, context);
|
||||
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return env->NewDirectByteBuffer(handle->input_start, input_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push data to encoder.
|
||||
*
|
||||
* @param ctx {in_cookie, in_operation_out_success, out_has_more_output,
|
||||
* out_has_remaining_input} tuple
|
||||
* @param input_length number of bytes provided in input or direct input;
|
||||
* 0 to process further previous input
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_brotli_wrapper_enc_EncoderJNI_nativePush(
|
||||
JNIEnv* env, jobject /*jobj*/, jlongArray ctx, jint input_length) {
|
||||
jlong context[5];
|
||||
env->GetLongArrayRegion(ctx, 0, 5, context);
|
||||
EncoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
|
||||
int operation = context[1];
|
||||
context[1] = 0; /* ERROR */
|
||||
env->SetLongArrayRegion(ctx, 0, 5, context);
|
||||
|
||||
BrotliEncoderOperation op;
|
||||
switch (operation) {
|
||||
case 0: op = BROTLI_OPERATION_PROCESS; break;
|
||||
case 1: op = BROTLI_OPERATION_FLUSH; break;
|
||||
case 2: op = BROTLI_OPERATION_FINISH; break;
|
||||
default: return; /* ERROR */
|
||||
}
|
||||
|
||||
if (input_length != 0) {
|
||||
/* Still have unconsumed data. Workflow is broken. */
|
||||
if (handle->input_offset < handle->input_last) {
|
||||
return;
|
||||
}
|
||||
handle->input_offset = 0;
|
||||
handle->input_last = input_length;
|
||||
}
|
||||
|
||||
/* Actual compression. */
|
||||
const uint8_t* in = handle->input_start + handle->input_offset;
|
||||
size_t in_size = handle->input_last - handle->input_offset;
|
||||
size_t out_size = 0;
|
||||
BROTLI_BOOL status = BrotliEncoderCompressStream(
|
||||
handle->state, op, &in_size, &in, &out_size, nullptr, nullptr);
|
||||
handle->input_offset = handle->input_last - in_size;
|
||||
if (!!status) {
|
||||
context[1] = 1;
|
||||
context[2] = BrotliEncoderHasMoreOutput(handle->state) ? 1 : 0;
|
||||
context[3] = (handle->input_offset != handle->input_last) ? 1 : 0;
|
||||
context[4] = BrotliEncoderIsFinished(handle->state) ? 1 : 0;
|
||||
}
|
||||
env->SetLongArrayRegion(ctx, 0, 5, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull decompressed data from encoder.
|
||||
*
|
||||
* @param ctx {in_cookie, out_success, out_has_more_output,
|
||||
* out_has_remaining_input} tuple
|
||||
* @returns direct ByteBuffer; all the produced data MUST be consumed before
|
||||
* any further invocation; null in case of error
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_brotli_wrapper_enc_EncoderJNI_nativePull(
|
||||
JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
|
||||
jlong context[5];
|
||||
env->GetLongArrayRegion(ctx, 0, 5, context);
|
||||
EncoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
|
||||
size_t data_length = 0;
|
||||
const uint8_t* data = BrotliEncoderTakeOutput(handle->state, &data_length);
|
||||
context[1] = 1;
|
||||
context[2] = BrotliEncoderHasMoreOutput(handle->state) ? 1 : 0;
|
||||
context[3] = (handle->input_offset != handle->input_last) ? 1 : 0;
|
||||
context[4] = BrotliEncoderIsFinished(handle->state) ? 1 : 0;
|
||||
env->SetLongArrayRegion(ctx, 0, 5, context);
|
||||
return env->NewDirectByteBuffer(const_cast<uint8_t*>(data), data_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all used resources.
|
||||
*
|
||||
* @param ctx {in_cookie} tuple
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_brotli_wrapper_enc_EncoderJNI_nativeDestroy(
|
||||
JNIEnv* env, jobject /*jobj*/, jlongArray ctx) {
|
||||
jlong context[2];
|
||||
env->GetLongArrayRegion(ctx, 0, 2, context);
|
||||
EncoderHandle* handle = getHandle(reinterpret_cast<void*>(context[0]));
|
||||
BrotliEncoderDestroyInstance(handle->state);
|
||||
delete[] handle->input_start;
|
||||
delete handle;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
17
app/src/main/cpp/woff2/brotli/tests/Makefile
vendored
17
app/src/main/cpp/woff2/brotli/tests/Makefile
vendored
|
|
@ -1,17 +0,0 @@
|
|||
#brotli/tests
|
||||
|
||||
BROTLI = ..
|
||||
|
||||
all: test
|
||||
|
||||
test: deps
|
||||
./compatibility_test.sh
|
||||
./roundtrip_test.sh
|
||||
|
||||
deps :
|
||||
$(MAKE) -C $(BROTLI) brotli
|
||||
|
||||
clean :
|
||||
rm -f testdata/*.{br,unbr,uncompressed}
|
||||
rm -f $(BROTLI)/{enc,dec,tools}/*.{un,}br
|
||||
$(MAKE) -C $(BROTLI)/tools clean
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test that the brotli command-line tool can decompress old brotli-compressed
|
||||
# files.
|
||||
|
||||
set -o errexit
|
||||
|
||||
BROTLI=bin/brotli
|
||||
TMP_DIR=bin/tmp
|
||||
|
||||
for file in tests/testdata/*.compressed*; do
|
||||
echo "Testing decompression of file $file"
|
||||
expected=${file%.compressed*}
|
||||
uncompressed=${TMP_DIR}/${expected##*/}.uncompressed
|
||||
echo $uncompressed
|
||||
$BROTLI $file -fdo $uncompressed
|
||||
diff -q $uncompressed $expected
|
||||
# Test the streaming version
|
||||
cat $file | $BROTLI -dc > $uncompressed
|
||||
diff -q $uncompressed $expected
|
||||
rm -f $uncompressed
|
||||
done
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Roundtrip test for the brotli command-line tool.
|
||||
|
||||
set -o errexit
|
||||
|
||||
BROTLI=bin/brotli
|
||||
TMP_DIR=bin/tmp
|
||||
INPUTS="""
|
||||
tests/testdata/alice29.txt
|
||||
tests/testdata/asyoulik.txt
|
||||
tests/testdata/lcet10.txt
|
||||
tests/testdata/plrabn12.txt
|
||||
c/enc/encode.c
|
||||
c/common/dictionary.h
|
||||
c/dec/decode.c
|
||||
"""
|
||||
|
||||
for file in $INPUTS; do
|
||||
for quality in 1 6 9 11; do
|
||||
echo "Roundtrip testing $file at quality $quality"
|
||||
compressed=${TMP_DIR}/${file##*/}.br
|
||||
uncompressed=${TMP_DIR}/${file##*/}.unbr
|
||||
$BROTLI -fq $quality $file -o $compressed
|
||||
$BROTLI $compressed -fdo $uncompressed
|
||||
diff -q $file $uncompressed
|
||||
# Test the streaming version
|
||||
cat $file | $BROTLI -cq $quality | $BROTLI -cd >$uncompressed
|
||||
diff -q $file $uncompressed
|
||||
done
|
||||
done
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
string(REGEX REPLACE "([a-zA-Z0-9\\.]+)\\.compressed(\\.[0-9]+)?$" "\\1" REFERENCE_DATA "${INPUT}")
|
||||
string(REGEX REPLACE "\\.compressed" "" OUTPUT_FILE "${INPUT}")
|
||||
get_filename_component(OUTPUT_NAME "${OUTPUT_FILE}" NAME)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMAND ${BROTLI_WRAPPER} ${BROTLI_CLI} --force --decompress ${INPUT} --output=${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}.unbr
|
||||
RESULT_VARIABLE result)
|
||||
if(result)
|
||||
message(FATAL_ERROR "Decompression failed")
|
||||
endif()
|
||||
|
||||
function(test_file_equality f1 f2)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 2.8.7)
|
||||
file(SHA512 "${f1}" f1_cs)
|
||||
file(SHA512 "${f2}" f2_cs)
|
||||
if(NOT "${f1_cs}" STREQUAL "${f2_cs}")
|
||||
message(FATAL_ERROR "Files do not match")
|
||||
endif()
|
||||
else()
|
||||
file(READ "${f1}" f1_contents)
|
||||
file(READ "${f2}" f2_contents)
|
||||
if(NOT "${f1_contents}" STREQUAL "${f2_contents}")
|
||||
message(FATAL_ERROR "Files do not match")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
test_file_equality("${REFERENCE_DATA}" "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}.unbr")
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
execute_process(
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMAND ${BROTLI_WRAPPER} ${BROTLI_CLI} --force --quality=${QUALITY} ${INPUT} --output=${OUTPUT}.br
|
||||
RESULT_VARIABLE result
|
||||
ERROR_VARIABLE result_stderr)
|
||||
if(result)
|
||||
message(FATAL_ERROR "Compression failed: ${result_stderr}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMAND ${BROTLI_WRAPPER} ${BROTLI_CLI} --force --decompress ${OUTPUT}.br --output=${OUTPUT}.unbr
|
||||
RESULT_VARIABLE result)
|
||||
if(result)
|
||||
message(FATAL_ERROR "Decompression failed")
|
||||
endif()
|
||||
|
||||
function(test_file_equality f1 f2)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 2.8.7)
|
||||
file(SHA512 "${f1}" f1_cs)
|
||||
file(SHA512 "${f2}" f2_cs)
|
||||
if(NOT "${f1_cs}" STREQUAL "${f2_cs}")
|
||||
message(FATAL_ERROR "Files do not match")
|
||||
endif()
|
||||
else()
|
||||
file(READ "${f1}" f1_contents)
|
||||
file(READ "${f2}" f2_contents)
|
||||
if(NOT "${f1_contents}" STREQUAL "${f2_contents}")
|
||||
message(FATAL_ERROR "Files do not match")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
test_file_equality("${INPUT}" "${OUTPUT}.unbr")
|
||||
|
|
@ -1 +0,0 @@
|
|||
XXXXXXXXXXYYYYYYYYYY
|
||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
Binary file not shown.
3609
app/src/main/cpp/woff2/brotli/tests/testdata/alice29.txt
vendored
3609
app/src/main/cpp/woff2/brotli/tests/testdata/alice29.txt
vendored
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
3
|
||||
|
|
@ -1 +0,0 @@
|
|||
5
|
||||
|
|
@ -1 +0,0 @@
|
|||
7
|
||||
|
|
@ -1 +0,0 @@
|
|||
9
|
||||
|
|
@ -1 +0,0 @@
|
|||
;
|
||||
|
|
@ -1 +0,0 @@
|
|||
=
|
||||
|
|
@ -1 +0,0 @@
|
|||
?
|
||||
|
|
@ -1 +0,0 @@
|
|||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
7519
app/src/main/cpp/woff2/brotli/tests/testdata/lcet10.txt
vendored
7519
app/src/main/cpp/woff2/brotli/tests/testdata/lcet10.txt
vendored
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue