/* * DeltaInputStream * * 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.delta.DeltaDecoder; /** * Decodes raw Delta-filtered data (no XZ headers). *

* 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 [DISTANCE_MIN, * DISTANCE_MAX] */ 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 -1 to indicate * the end of input on the input stream in * * @throws IOException may be thrown by in */ public int read() throws IOException { return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF); } /** * Decode into an array of bytes. *

* This calls in.read(buf, off, len) and defilters the * returned data. * * @param buf target buffer for decoded data * @param off start offset in buf * @param len maximum number of bytes to read * * @return number of bytes read, or -1 to indicate * the end of the input stream in * * @throws XZIOException if the stream has been closed * * @throws IOException may be thrown by underlaying input * stream in */ 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 in.available(). * * @return the value returned by in.available() */ 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 in.close(). * If the stream was already closed, this does nothing. * * @throws IOException if thrown by in.close() */ public void close() throws IOException { if (in != null) { try { in.close(); } finally { in = null; } } } }