Home | History | Annotate | Download | only in xz
      1 /*
      2  * DeltaInputStream
      3  *
      4  * Author: Lasse Collin <lasse.collin (at) tukaani.org>
      5  *
      6  * This file has been put into the public domain.
      7  * You can do whatever you want with this file.
      8  */
      9 
     10 package org.tukaani.xz;
     11 
     12 import java.io.InputStream;
     13 import java.io.IOException;
     14 import org.tukaani.xz.delta.DeltaDecoder;
     15 
     16 /**
     17  * Decodes raw Delta-filtered data (no XZ headers).
     18  * <p>
     19  * The delta filter doesn't change the size of the data and thus it
     20  * cannot have an end-of-payload marker. It will simply decode until
     21  * its input stream indicates end of input.
     22  */
     23 public class DeltaInputStream extends InputStream {
     24     /**
     25      * Smallest supported delta calculation distance.
     26      */
     27     public static final int DISTANCE_MIN = 1;
     28 
     29     /**
     30      * Largest supported delta calculation distance.
     31      */
     32     public static final int DISTANCE_MAX = 256;
     33 
     34     private InputStream in;
     35     private final DeltaDecoder delta;
     36 
     37     private IOException exception = null;
     38 
     39     private final byte[] tempBuf = new byte[1];
     40 
     41     /**
     42      * Creates a new Delta decoder with the given delta calculation distance.
     43      *
     44      * @param       in          input stream from which Delta filtered data
     45      *                          is read
     46      *
     47      * @param       distance    delta calculation distance, must be in the
     48      *                          range [<code>DISTANCE_MIN</code>,
     49      *                          <code>DISTANCE_MAX</code>]
     50      */
     51     public DeltaInputStream(InputStream in, int distance) {
     52         // Check for null because otherwise null isn't detect
     53         // in this constructor.
     54         if (in == null)
     55             throw new NullPointerException();
     56 
     57         this.in = in;
     58         this.delta = new DeltaDecoder(distance);
     59     }
     60 
     61     /**
     62      * Decode the next byte from this input stream.
     63      *
     64      * @return      the next decoded byte, or <code>-1</code> to indicate
     65      *              the end of input on the input stream <code>in</code>
     66      *
     67      * @throws      IOException may be thrown by <code>in</code>
     68      */
     69     public int read() throws IOException {
     70         return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
     71     }
     72 
     73     /**
     74      * Decode into an array of bytes.
     75      * <p>
     76      * This calls <code>in.read(buf, off, len)</code> and defilters the
     77      * returned data.
     78      *
     79      * @param       buf         target buffer for decoded data
     80      * @param       off         start offset in <code>buf</code>
     81      * @param       len         maximum number of bytes to read
     82      *
     83      * @return      number of bytes read, or <code>-1</code> to indicate
     84      *              the end of the input stream <code>in</code>
     85      *
     86      * @throws      XZIOException if the stream has been closed
     87      *
     88      * @throws      IOException may be thrown by underlaying input
     89      *                          stream <code>in</code>
     90      */
     91     public int read(byte[] buf, int off, int len) throws IOException {
     92         if (len == 0)
     93             return 0;
     94 
     95         if (in == null)
     96             throw new XZIOException("Stream closed");
     97 
     98         if (exception != null)
     99             throw exception;
    100 
    101         int size;
    102         try {
    103             size = in.read(buf, off, len);
    104         } catch (IOException e) {
    105             exception = e;
    106             throw e;
    107         }
    108 
    109         if (size == -1)
    110             return -1;
    111 
    112         delta.decode(buf, off, size);
    113         return size;
    114     }
    115 
    116     /**
    117      * Calls <code>in.available()</code>.
    118      *
    119      * @return      the value returned by <code>in.available()</code>
    120      */
    121     public int available() throws IOException {
    122         if (in == null)
    123             throw new XZIOException("Stream closed");
    124 
    125         if (exception != null)
    126             throw exception;
    127 
    128         return in.available();
    129     }
    130 
    131     /**
    132      * Closes the stream and calls <code>in.close()</code>.
    133      * If the stream was already closed, this does nothing.
    134      *
    135      * @throws  IOException if thrown by <code>in.close()</code>
    136      */
    137     public void close() throws IOException {
    138         if (in != null) {
    139             try {
    140                 in.close();
    141             } finally {
    142                 in = null;
    143             }
    144         }
    145     }
    146 }
    147