blob: afd40c77e20854e61a175eb3981f93f0fdf7400f [file] [log] [blame]
/*
* SimpleInputStream
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
package org.tukaani.xz;
import java.io.InputStream;
import java.io.IOException;
import org.tukaani.xz.simple.SimpleFilter;
class SimpleInputStream extends InputStream {
private static final int FILTER_BUF_SIZE = 4096;
private InputStream in;
private final SimpleFilter simpleFilter;
private final byte[] filterBuf = new byte[FILTER_BUF_SIZE];
private int pos = 0;
private int filtered = 0;
private int unfiltered = 0;
private boolean endReached = false;
private IOException exception = null;
private final byte[] tempBuf = new byte[1];
static int getMemoryUsage() {
return 1 + FILTER_BUF_SIZE / 1024;
}
SimpleInputStream(InputStream in, SimpleFilter simpleFilter) {
// Check for null because otherwise null isn't detect
// in this constructor.
if (in == null)
throw new NullPointerException();
// The simpleFilter argument comes from this package
// so it is known to be non-null already.
assert simpleFilter != null;
this.in = in;
this.simpleFilter = simpleFilter;
}
public int read() throws IOException {
return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
}
public int read(byte[] buf, int off, int len) throws IOException {
if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
throw new IndexOutOfBoundsException();
if (len == 0)
return 0;
if (in == null)
throw new XZIOException("Stream closed");
if (exception != null)
throw exception;
try {
int size = 0;
while (true) {
// Copy filtered data into the caller-provided buffer.
int copySize = Math.min(filtered, len);
System.arraycopy(filterBuf, pos, buf, off, copySize);
pos += copySize;
filtered -= copySize;
off += copySize;
len -= copySize;
size += copySize;
// If end of filterBuf was reached, move the pending data to
// the beginning of the buffer so that more data can be
// copied into filterBuf on the next loop iteration.
if (pos + filtered + unfiltered == FILTER_BUF_SIZE) {
System.arraycopy(filterBuf, pos, filterBuf, 0,
filtered + unfiltered);
pos = 0;
}
if (len == 0 || endReached)
return size > 0 ? size : -1;
assert filtered == 0;
// Get more data into the temporary buffer.
int inSize = FILTER_BUF_SIZE - (pos + filtered + unfiltered);
inSize = in.read(filterBuf, pos + filtered + unfiltered,
inSize);
if (inSize == -1) {
// Mark the remaining unfiltered bytes to be ready
// to be copied out.
endReached = true;
filtered = unfiltered;
unfiltered = 0;
} else {
// Filter the data in filterBuf.
unfiltered += inSize;
filtered = simpleFilter.code(filterBuf, pos, unfiltered);
assert filtered <= unfiltered;
unfiltered -= filtered;
}
}
} catch (IOException e) {
exception = e;
throw e;
}
}
public int available() throws IOException {
if (in == null)
throw new XZIOException("Stream closed");
if (exception != null)
throw exception;
return filtered;
}
public void close() throws IOException {
if (in != null) {
try {
in.close();
} finally {
in = null;
}
}
}
}