/* * SimpleInputStream * * Author: Lasse Collin * * 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; } } } }