mirror of
https://github.com/google/brotli.git
synced 2026-07-09 02:08:06 +00:00
Update API, and more: * remove "custom dictionary" support * c/encoder: fix #580: big-endian build * Java: reduce jar size * Java: speedup decoding * Java: add 32-bit CPU support * Java: make source code JS transpiler-ready
115 lines
3.1 KiB
Java
Executable File
115 lines
3.1 KiB
Java
Executable File
/* 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.
|
|
*/
|
|
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 {
|
|
ERROR,
|
|
DONE,
|
|
NEEDS_MORE_INPUT,
|
|
NEEDS_MORE_OUTPUT,
|
|
OK
|
|
};
|
|
|
|
static class Wrapper {
|
|
private final long[] context = new long[2];
|
|
private final ByteBuffer inputBuffer;
|
|
private Status lastStatus = Status.NEEDS_MORE_INPUT;
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
Status getStatus() {
|
|
return lastStatus;
|
|
}
|
|
|
|
ByteBuffer getInputBuffer() {
|
|
return inputBuffer;
|
|
}
|
|
|
|
ByteBuffer pull() {
|
|
if (context[0] == 0) {
|
|
throw new IllegalStateException("brotli decoder is already destroyed");
|
|
}
|
|
if (lastStatus != Status.NEEDS_MORE_OUTPUT) {
|
|
throw new IllegalStateException("pulling output from decoder in " + lastStatus + " state");
|
|
}
|
|
ByteBuffer result = nativePull(context);
|
|
parseStatus();
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Releases native resources.
|
|
*/
|
|
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();
|
|
}
|
|
}
|
|
}
|