/* * DeltaInputStream * * 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.delta.DeltaDecoder; /** * Decodes raw Delta-filtered data (no XZ headers). * <p> * The delta filter doesn't change the size of the data and thus it * cannot have an end-of-payload marker. It will simply decode until * its input stream indicates end of input. */ public class DeltaInputStream extends InputStream { /** * Smallest supported delta calculation distance. */ public static final int DISTANCE_MIN = 1; /** * Largest supported delta calculation distance. */ public static final int DISTANCE_MAX = 256; private InputStream in; private final DeltaDecoder delta; private IOException exception = null; private final byte[] tempBuf = new byte[1]; /** * Creates a new Delta decoder with the given delta calculation distance. * * @param in input stream from which Delta filtered data * is read * * @param distance delta calculation distance, must be in the * range [<code>DISTANCE_MIN</code>, * <code>DISTANCE_MAX</code>] */ public DeltaInputStream(InputStream in, int distance) { // Check for null because otherwise null isn't detect // in this constructor. if (in == null) throw new NullPointerException(); this.in = in; this.delta = new DeltaDecoder(distance); } /** * Decode the next byte from this input stream. * * @return the next decoded byte, or <code>-1</code> to indicate * the end of input on the input stream <code>in</code> * * @throws IOException may be thrown by <code>in</code> */ public int read() throws IOException { return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF); } /** * Decode into an array of bytes. * <p> * This calls <code>in.read(buf, off, len)</code> and defilters the * returned data. * * @param buf target buffer for decoded data * @param off start offset in <code>buf</code> * @param len maximum number of bytes to read * * @return number of bytes read, or <code>-1</code> to indicate * the end of the input stream <code>in</code> * * @throws XZIOException if the stream has been closed * * @throws IOException may be thrown by underlaying input * stream <code>in</code> */ public int read(byte[] buf, int off, int len) throws IOException { if (len == 0) return 0; if (in == null) throw new XZIOException("Stream closed"); if (exception != null) throw exception; int size; try { size = in.read(buf, off, len); } catch (IOException e) { exception = e; throw e; } if (size == -1) return -1; delta.decode(buf, off, size); return size; } /** * Calls <code>in.available()</code>. * * @return the value returned by <code>in.available()</code> */ public int available() throws IOException { if (in == null) throw new XZIOException("Stream closed"); if (exception != null) throw exception; return in.available(); } /** * Closes the stream and calls <code>in.close()</code>. * If the stream was already closed, this does nothing. * * @throws IOException if thrown by <code>in.close()</code> */ public void close() throws IOException { if (in != null) { try { in.close(); } finally { in = null; } } } }