org.h2.compress.LZFInputStream Maven / Gradle / Ivy
/*
* Copyright 2004-2022 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (https://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.compress;
import java.io.IOException;
import java.io.InputStream;
import org.h2.mvstore.DataUtils;
import org.h2.util.Utils;
/**
* An input stream to read from an LZF stream.
* The data is automatically expanded.
*/
public class LZFInputStream extends InputStream {
private final InputStream in;
private CompressLZF decompress = new CompressLZF();
private int pos;
private int bufferLength;
private byte[] inBuffer;
private byte[] buffer;
public LZFInputStream(InputStream in) throws IOException {
this.in = in;
if (readInt() != LZFOutputStream.MAGIC) {
throw new IOException("Not an LZFInputStream");
}
}
private static byte[] ensureSize(byte[] buff, int len) {
return buff == null || buff.length < len ? Utils.newBytes(len) : buff;
}
private void fillBuffer() throws IOException {
if (buffer != null && pos < bufferLength) {
return;
}
int len = readInt();
if (decompress == null) {
// EOF
this.bufferLength = 0;
} else if (len < 0) {
len = -len;
buffer = ensureSize(buffer, len);
readFully(buffer, len);
this.bufferLength = len;
} else {
inBuffer = ensureSize(inBuffer, len);
int size = readInt();
readFully(inBuffer, len);
buffer = ensureSize(buffer, size);
try {
decompress.expand(inBuffer, 0, len, buffer, 0, size);
} catch (ArrayIndexOutOfBoundsException e) {
throw DataUtils.convertToIOException(e);
}
this.bufferLength = size;
}
pos = 0;
}
private void readFully(byte[] buff, int len) throws IOException {
int off = 0;
while (len > 0) {
int l = in.read(buff, off, len);
len -= l;
off += l;
}
}
private int readInt() throws IOException {
int x = in.read();
if (x < 0) {
decompress = null;
return 0;
}
x = (x << 24) + (in.read() << 16) + (in.read() << 8) + in.read();
return x;
}
@Override
public int read() throws IOException {
fillBuffer();
if (pos >= bufferLength) {
return -1;
}
return buffer[pos++] & 255;
}
@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 == 0) {
return 0;
}
int read = 0;
while (len > 0) {
int r = readBlock(b, off, len);
if (r < 0) {
break;
}
read += r;
off += r;
len -= r;
}
return read == 0 ? -1 : read;
}
private int readBlock(byte[] b, int off, int len) throws IOException {
fillBuffer();
if (pos >= bufferLength) {
return -1;
}
int max = Math.min(len, bufferLength - pos);
max = Math.min(max, b.length - off);
System.arraycopy(buffer, pos, b, off, max);
pos += max;
return max;
}
@Override
public void close() throws IOException {
in.close();
}
}