From 35e69fc7cf9421ab04ffc9d52cb36d07fa12984a Mon Sep 17 00:00:00 2001 From: Eugene Kliuchnikov Date: Mon, 26 Feb 2018 09:04:36 -0500 Subject: New feature: "Large Window Brotli" (#640) * New feature: "Large Window Brotli" By setting special encoder/decoder flag it is now possible to extend LZ-window up to 30 bits; though produced stream will not be RFC7932 compliant. Added new dictionary generator - "DSH". It combines speed of "Sieve" and quality of "DM". Plus utilities to prepare train corpora (remove unique strings). Improved compression ratio: now two sub-blocks could be stitched: the last copy command could be extended to span the next sub-block. Fixed compression ineffectiveness caused by floating numbers rounding and wrong cost heuristic. Other C changes: - combined / moved `context.h` to `common` - moved transforms to `common` - unified some aspects of code formatting - added an abstraction for encoder (static) dictionary - moved default allocator/deallocator functions to `common` brotli CLI: - window size is auto-adjusted if not specified explicitly Java: - added "eager" decoding both to JNI wrapper and pure decoder - huge speed-up of `DictionaryData` initialization * Add dictionaryless compressed dictionary * Fix `sources.lst` * Fix `sources.lst` and add a note that `libtool` is also required. * Update setup.py * Fix `EagerStreamTest` * Fix BUILD file * Add missing `libdivsufsort` dependency * Fix "unused parameter" warning. --- java/org/brotli/dec/BUILD | 6 + java/org/brotli/dec/BrotliInputStream.java | 12 +- java/org/brotli/dec/Decode.java | 84 ++--- java/org/brotli/dec/DictionaryData.java | 29 +- java/org/brotli/dec/EagerStreamTest.java | 386 +++++++++++++++++++++ java/org/brotli/dec/State.java | 7 +- java/org/brotli/wrapper/dec/BrotliInputStream.java | 4 + java/org/brotli/wrapper/dec/Decoder.java | 10 + java/org/brotli/wrapper/dec/DecoderJNI.java | 26 +- java/org/brotli/wrapper/dec/EagerStreamTest.java | 75 ++++ java/org/brotli/wrapper/dec/decoder_jni.cc | 31 +- 11 files changed, 588 insertions(+), 82 deletions(-) create mode 100755 java/org/brotli/dec/EagerStreamTest.java create mode 100755 java/org/brotli/wrapper/dec/EagerStreamTest.java (limited to 'java') diff --git a/java/org/brotli/dec/BUILD b/java/org/brotli/dec/BUILD index 8a2558c..e6d3a4d 100644 --- a/java/org/brotli/dec/BUILD +++ b/java/org/brotli/dec/BUILD @@ -43,6 +43,12 @@ java_test( ) 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"], diff --git a/java/org/brotli/dec/BrotliInputStream.java b/java/org/brotli/dec/BrotliInputStream.java index a2bca95..a27e928 100644 --- a/java/org/brotli/dec/BrotliInputStream.java +++ b/java/org/brotli/dec/BrotliInputStream.java @@ -16,7 +16,7 @@ import java.io.InputStream; */ public class BrotliInputStream extends InputStream { - public static final int DEFAULT_INTERNAL_BUFFER_SIZE = 16384; + public static final int DEFAULT_INTERNAL_BUFFER_SIZE = 256; /** * Internal buffer used for efficient byte-by-byte reading. @@ -44,7 +44,8 @@ public class BrotliInputStream extends InputStream { *

For byte-by-byte reading ({@link #read()}) internal buffer with * {@link #DEFAULT_INTERNAL_BUFFER_SIZE} size is allocated and used. * - *

Will block the thread until first kilobyte of data of source is available. + *

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 @@ -59,7 +60,8 @@ public class BrotliInputStream extends InputStream { *

For byte-by-byte reading ({@link #read()}) internal buffer of specified size is * allocated and used. * - *

Will block the thread until first kilobyte of data of source is available. + *

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 @@ -82,6 +84,10 @@ public class BrotliInputStream extends InputStream { } } + public void setEager(boolean eager) { + state.isEager = eager ? 1 : 0; + } + /** * {@inheritDoc} */ diff --git a/java/org/brotli/dec/Decode.java b/java/org/brotli/dec/Decode.java index 4a1ded6..9e3d43b 100644 --- a/java/org/brotli/dec/Decode.java +++ b/java/org/brotli/dec/Decode.java @@ -25,10 +25,10 @@ final class Decode { private static final int COPY_UNCOMPRESSED = 5; private static final int INSERT_LOOP = 6; private static final int COPY_LOOP = 7; - private static final int COPY_WRAP_BUFFER = 8; - private static final int TRANSFORM = 9; - private static final int FINISHED = 10; - private static final int CLOSED = 11; + private static final int TRANSFORM = 8; + private static final int FINISHED = 9; + private static final int CLOSED = 10; + private static final int INIT_WRITE = 11; private static final int WRITE = 12; private static final int DEFAULT_CODE_LENGTH = 8; @@ -550,9 +550,7 @@ final class Decode { private static void readNextMetablockHeader(State s) { if (s.inputEnd != 0) { s.nextRunningState = FINISHED; - s.bytesToWrite = s.pos; - s.bytesWritten = 0; - s.runningState = WRITE; + s.runningState = INIT_WRITE; return; } // TODO: Reset? Do we need this? @@ -674,9 +672,7 @@ final class Decode { s.pos += chunkLength; if (s.pos == s.ringBufferSize) { s.nextRunningState = COPY_UNCOMPRESSED; - s.bytesToWrite = s.ringBufferSize; - s.bytesWritten = 0; - s.runningState = WRITE; + s.runningState = INIT_WRITE; return; } @@ -686,12 +682,12 @@ final class Decode { private static int writeRingBuffer(State s) { int toWrite = Math.min(s.outputLength - s.outputUsed, - s.bytesToWrite - s.bytesWritten); + s.ringBufferBytesReady - s.ringBufferBytesWritten); if (toWrite != 0) { - System.arraycopy(s.ringBuffer, s.bytesWritten, s.output, + System.arraycopy(s.ringBuffer, s.ringBufferBytesWritten, s.output, s.outputOffset + s.outputUsed, toWrite); s.outputUsed += toWrite; - s.bytesWritten += toWrite; + s.ringBufferBytesWritten += toWrite; } if (s.outputUsed < s.outputLength) { @@ -712,6 +708,15 @@ final class Decode { return group; } + // Returns offset in ringBuffer that should trigger WRITE when filled. + private static int calculateFence(State s) { + int result = s.ringBufferSize; + if (s.isEager != 0) { + result = Math.min(result, s.ringBufferBytesWritten + s.outputLength - s.outputUsed); + } + return result; + } + /** * Actual decompress implementation. */ @@ -722,6 +727,7 @@ final class Decode { if (s.runningState == CLOSED) { throw new IllegalStateException("Can't decompress after close"); } + int fence = calculateFence(s); int ringBufferMask = s.ringBufferSize - 1; byte[] ringBuffer = s.ringBuffer; @@ -734,6 +740,7 @@ final class Decode { } readNextMetablockHeader(s); /* Ring-buffer would be reallocated here. */ + fence = calculateFence(s); ringBufferMask = s.ringBufferSize - 1; ringBuffer = s.ringBuffer; continue; @@ -787,12 +794,11 @@ final class Decode { BitReader.fillBitWindow(s); ringBuffer[s.pos] = (byte) readSymbol(s.hGroup0, s.literalTree, s); + s.pos++; s.j++; - if (s.pos++ == ringBufferMask) { + if (s.pos >= fence) { s.nextRunningState = INSERT_LOOP; - s.bytesToWrite = s.ringBufferSize; - s.bytesWritten = 0; - s.runningState = WRITE; + s.runningState = INIT_WRITE; break; } } @@ -813,12 +819,11 @@ final class Decode { prevByte1 = readSymbol( s.hGroup0, s.hGroup0[literalTreeIndex], s); ringBuffer[s.pos] = (byte) prevByte1; + s.pos++; s.j++; - if (s.pos++ == ringBufferMask) { + if (s.pos >= fence) { s.nextRunningState = INSERT_LOOP; - s.bytesToWrite = s.ringBufferSize; - s.bytesWritten = 0; - s.runningState = WRITE; + s.runningState = INIT_WRITE; break; } } @@ -868,7 +873,6 @@ final class Decode { s.maxDistance = s.maxBackwardDistance; } - s.copyDst = s.pos; if (s.distance > s.maxDistance) { s.runningState = TRANSFORM; continue; @@ -907,12 +911,11 @@ final class Decode { ringBuffer[s.pos] = ringBuffer[(s.pos - s.distance) & ringBufferMask]; s.metaBlockLength--; + s.pos++; s.j++; - if (s.pos++ == ringBufferMask) { + if (s.pos >= fence) { s.nextRunningState = COPY_LOOP; - s.bytesToWrite = s.ringBufferSize; - s.bytesWritten = 0; - s.runningState = WRITE; + s.runningState = INIT_WRITE; break; } } @@ -933,16 +936,13 @@ final class Decode { int transformIdx = wordId >>> shift; offset += wordIdx * s.copyLength; if (transformIdx < Transform.NUM_TRANSFORMS) { - int len = Transform.transformDictionaryWord(ringBuffer, s.copyDst, + int len = Transform.transformDictionaryWord(ringBuffer, s.pos, Dictionary.getData(), offset, s.copyLength, transformIdx); - s.copyDst += len; s.pos += len; s.metaBlockLength -= len; - if (s.copyDst >= s.ringBufferSize) { - s.nextRunningState = COPY_WRAP_BUFFER; - s.bytesToWrite = s.ringBufferSize; - s.bytesWritten = 0; - s.runningState = WRITE; + if (s.pos >= fence) { + s.nextRunningState = MAIN_LOOP; + s.runningState = INIT_WRITE; continue; } } else { @@ -954,11 +954,6 @@ final class Decode { s.runningState = MAIN_LOOP; continue; - case COPY_WRAP_BUFFER: - Utils.copyBytesWithin(ringBuffer, 0, s.ringBufferSize, s.copyDst); - s.runningState = MAIN_LOOP; - continue; - case READ_METADATA: while (s.metaBlockLength > 0) { BitReader.readMoreInput(s); @@ -975,6 +970,10 @@ final class Decode { copyUncompressedData(s); continue; + case INIT_WRITE: + s.ringBufferBytesReady = Math.min(s.pos, s.ringBufferSize); + s.runningState = WRITE; + // fall through case WRITE: if (writeRingBuffer(s) == 0) { // Output buffer is full. @@ -983,7 +982,14 @@ final class Decode { if (s.pos >= s.maxBackwardDistance) { s.maxDistance = s.maxBackwardDistance; } - s.pos &= ringBufferMask; + // Wrap the ringBuffer. + if (s.pos >= s.ringBufferSize) { + if (s.pos > s.ringBufferSize) { + Utils.copyBytesWithin(ringBuffer, 0, s.ringBufferSize, s.pos); + } + s.pos &= ringBufferMask; + s.ringBufferBytesWritten = 0; + } s.runningState = s.nextRunningState; continue; diff --git a/java/org/brotli/dec/DictionaryData.java b/java/org/brotli/dec/DictionaryData.java index 9ac6e55..2355b28 100644 --- a/java/org/brotli/dec/DictionaryData.java +++ b/java/org/brotli/dec/DictionaryData.java @@ -6,6 +6,7 @@ package org.brotli.dec; +import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; /** @@ -20,31 +21,33 @@ final class DictionaryData { private static void unpackDictionaryData( ByteBuffer dictionary, String data0, String data1, String skipFlip) { - int n0 = data0.length(); - int n1 = data1.length(); - if (n0 + n1 != dictionary.capacity()) { + // Initialize lower 7 bits of every byte in the dictionary. + byte[] dict; + try { + // NB: String#getBytes(String) is present in JDK 1.1, while other variants require JDK 1.6 and + // above. + dict = (data0 + data1).getBytes("US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // cannot happen + } + if (dict.length != dictionary.capacity()) { throw new RuntimeException("Corrupted brotli dictionary"); } + + // Toggle high bit using run-length delta encoded "skipFlip". int offset = 0; - for (int i = 0; i < n0; ++i) { - dictionary.put(offset, (byte) data0.charAt(i)); - offset++; - } - for (int i = 0; i < n1; ++i) { - dictionary.put(offset, (byte) data1.charAt(i)); - offset++; - } - offset = 0; int n = skipFlip.length(); for (int i = 0; i < n; i += 2) { int skip = skipFlip.charAt(i) - 36; int flip = skipFlip.charAt(i + 1) - 36; offset += skip; for (int j = 0; j < flip; ++j) { - dictionary.put(offset, (byte) (dictionary.get(offset) | 0x80)); + dict[offset] |= 0x80; offset++; } } + + dictionary.put(dict); } static { diff --git a/java/org/brotli/dec/EagerStreamTest.java b/java/org/brotli/dec/EagerStreamTest.java new file mode 100755 index 0000000..069ae34 --- /dev/null +++ b/java/org/brotli/dec/EagerStreamTest.java @@ -0,0 +1,386 @@ +/* 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); + } +} diff --git a/java/org/brotli/dec/State.java b/java/org/brotli/dec/State.java index 183df44..16d1072 100644 --- a/java/org/brotli/dec/State.java +++ b/java/org/brotli/dec/State.java @@ -63,16 +63,17 @@ final class State { int distancePostfixBits; int distance; int copyLength; - int copyDst; int maxBackwardDistance; int maxRingBufferSize; int ringBufferSize; + int ringBufferFence; int expectedTotalSize; int outputOffset; int outputLength; int outputUsed; - int bytesWritten; - int bytesToWrite; + int ringBufferBytesWritten; + int ringBufferBytesReady; + int isEager; InputStream input; // BitReader diff --git a/java/org/brotli/wrapper/dec/BrotliInputStream.java b/java/org/brotli/wrapper/dec/BrotliInputStream.java index d1aa76b..76bcf1d 100644 --- a/java/org/brotli/wrapper/dec/BrotliInputStream.java +++ b/java/org/brotli/wrapper/dec/BrotliInputStream.java @@ -34,6 +34,10 @@ public class BrotliInputStream extends InputStream { this(source, DEFAULT_BUFFER_SIZE); } + public void setEager(boolean eager) { + decoder.setEager(eager); + } + @Override public void close() throws IOException { decoder.close(); diff --git a/java/org/brotli/wrapper/dec/Decoder.java b/java/org/brotli/wrapper/dec/Decoder.java index 95060ae..0326403 100644 --- a/java/org/brotli/wrapper/dec/Decoder.java +++ b/java/org/brotli/wrapper/dec/Decoder.java @@ -19,6 +19,7 @@ public class Decoder { private final DecoderJNI.Wrapper decoder; ByteBuffer buffer; boolean closed; + boolean eager; /** * Creates a Decoder wrapper. @@ -47,6 +48,10 @@ public class Decoder { throw new IOException(message); } + public void setEager(boolean eager) { + this.eager = eager; + } + /** * Continue decoding. * @@ -71,6 +76,11 @@ public class Decoder { 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); diff --git a/java/org/brotli/wrapper/dec/DecoderJNI.java b/java/org/brotli/wrapper/dec/DecoderJNI.java index 3a59053..320705c 100644 --- a/java/org/brotli/wrapper/dec/DecoderJNI.java +++ b/java/org/brotli/wrapper/dec/DecoderJNI.java @@ -12,13 +12,13 @@ import java.nio.ByteBuffer; /** * JNI wrapper for brotli decoder. */ -class DecoderJNI { +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); - enum Status { + public enum Status { ERROR, DONE, NEEDS_MORE_INPUT, @@ -26,12 +26,12 @@ class DecoderJNI { OK }; - static class Wrapper { - private final long[] context = new long[2]; + public static class Wrapper { + private final long[] context = new long[3]; private final ByteBuffer inputBuffer; private Status lastStatus = Status.NEEDS_MORE_INPUT; - Wrapper(int inputBufferSize) throws IOException { + public Wrapper(int inputBufferSize) throws IOException { this.context[1] = inputBufferSize; this.inputBuffer = nativeCreate(this.context); if (this.context[0] == 0) { @@ -39,7 +39,7 @@ class DecoderJNI { } } - void push(int length) { + public void push(int length) { if (length < 0) { throw new IllegalArgumentException("negative block length"); } @@ -71,19 +71,23 @@ class DecoderJNI { } } - Status getStatus() { + public Status getStatus() { return lastStatus; } - ByteBuffer getInputBuffer() { + public ByteBuffer getInputBuffer() { return inputBuffer; } - ByteBuffer pull() { + 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) { + if (lastStatus != Status.NEEDS_MORE_OUTPUT && !hasOutput()) { throw new IllegalStateException("pulling output from decoder in " + lastStatus + " state"); } ByteBuffer result = nativePull(context); @@ -94,7 +98,7 @@ class DecoderJNI { /** * Releases native resources. */ - void destroy() { + public void destroy() { if (context[0] == 0) { throw new IllegalStateException("brotli decoder is already destroyed"); } diff --git a/java/org/brotli/wrapper/dec/EagerStreamTest.java b/java/org/brotli/wrapper/dec/EagerStreamTest.java new file mode 100755 index 0000000..9166092 --- /dev/null +++ b/java/org/brotli/wrapper/dec/EagerStreamTest.java @@ -0,0 +1,75 @@ +/* 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()); + } + +} diff --git a/java/org/brotli/wrapper/dec/decoder_jni.cc b/java/org/brotli/wrapper/dec/decoder_jni.cc index 19c022b..268a10b 100644 --- a/java/org/brotli/wrapper/dec/decoder_jni.cc +++ b/java/org/brotli/wrapper/dec/decoder_jni.cc @@ -45,10 +45,11 @@ Java_org_brotli_wrapper_dec_DecoderJNI_nativeCreate( JNIEnv* env, jobject /*jobj*/, jlongArray ctx) { bool ok = true; DecoderHandle* handle = nullptr; - jlong context[2]; - env->GetLongArrayRegion(ctx, 0, 2, context); + 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; @@ -79,7 +80,7 @@ Java_org_brotli_wrapper_dec_DecoderJNI_nativeCreate( delete handle; } - env->SetLongArrayRegion(ctx, 0, 2, context); + env->SetLongArrayRegion(ctx, 0, 3, context); if (!ok) { return nullptr; @@ -105,11 +106,12 @@ Java_org_brotli_wrapper_dec_DecoderJNI_nativeCreate( JNIEXPORT void JNICALL Java_org_brotli_wrapper_dec_DecoderJNI_nativePush( JNIEnv* env, jobject /*jobj*/, jlongArray ctx, jint input_length) { - jlong context[2]; - env->GetLongArrayRegion(ctx, 0, 2, context); + jlong context[3]; + env->GetLongArrayRegion(ctx, 0, 3, context); DecoderHandle* handle = getHandle(reinterpret_cast(context[0])); context[1] = 0; /* ERROR */ - env->SetLongArrayRegion(ctx, 0, 2, context); + context[2] = 0; + env->SetLongArrayRegion(ctx, 0, 3, context); if (input_length != 0) { /* Still have unconsumed data. Workflow is broken. */ @@ -145,7 +147,8 @@ Java_org_brotli_wrapper_dec_DecoderJNI_nativePush( context[1] = 0; break; } - env->SetLongArrayRegion(ctx, 0, 2, context); + context[2] = BrotliDecoderHasMoreOutput(handle->state) ? 1 : 0; + env->SetLongArrayRegion(ctx, 0, 3, context); } /** @@ -158,12 +161,13 @@ Java_org_brotli_wrapper_dec_DecoderJNI_nativePush( JNIEXPORT jobject JNICALL Java_org_brotli_wrapper_dec_DecoderJNI_nativePull( JNIEnv* env, jobject /*jobj*/, jlongArray ctx) { - jlong context[2]; - env->GetLongArrayRegion(ctx, 0, 2, context); + jlong context[3]; + env->GetLongArrayRegion(ctx, 0, 3, context); DecoderHandle* handle = getHandle(reinterpret_cast(context[0])); size_t data_length = 0; const uint8_t* data = BrotliDecoderTakeOutput(handle->state, &data_length); - if (BrotliDecoderHasMoreOutput(handle->state)) { + bool hasMoreOutput = !!BrotliDecoderHasMoreOutput(handle->state); + if (hasMoreOutput) { context[1] = 3; } else if (BrotliDecoderIsFinished(handle->state)) { /* Bytes after stream end are not allowed. */ @@ -172,7 +176,8 @@ Java_org_brotli_wrapper_dec_DecoderJNI_nativePull( /* Can proceed, or more data is required? */ context[1] = (handle->input_offset == handle->input_length) ? 2 : 4; } - env->SetLongArrayRegion(ctx, 0, 2, context); + context[2] = hasMoreOutput ? 1 : 0; + env->SetLongArrayRegion(ctx, 0, 3, context); return env->NewDirectByteBuffer(const_cast(data), data_length); } @@ -184,8 +189,8 @@ Java_org_brotli_wrapper_dec_DecoderJNI_nativePull( JNIEXPORT void JNICALL Java_org_brotli_wrapper_dec_DecoderJNI_nativeDestroy( JNIEnv* env, jobject /*jobj*/, jlongArray ctx) { - jlong context[2]; - env->GetLongArrayRegion(ctx, 0, 2, context); + jlong context[3]; + env->GetLongArrayRegion(ctx, 0, 3, context); DecoderHandle* handle = getHandle(reinterpret_cast(context[0])); BrotliDecoderDestroyInstance(handle->state); delete[] handle->input_start; -- cgit v1.1