/* 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 enableEagerOutput() {
|
decoder.enableEagerOutput();
|
}
|
|
@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");
|
}
|
int decoded;
|
// Iterate until at leat one byte is decoded, or EOF reached.
|
while (true) {
|
decoded = decoder.decode();
|
if (decoded != 0) {
|
break;
|
}
|
}
|
|
if (decoded == -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;
|
}
|
}
|