Home | History | Annotate | Download | only in xz
      1 /*
      2  * SimpleInputStream
      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.simple.SimpleFilter;
     15 
     16 class SimpleInputStream extends InputStream {
     17     private static final int FILTER_BUF_SIZE = 4096;
     18 
     19     private InputStream in;
     20     private final SimpleFilter simpleFilter;
     21 
     22     private final byte[] filterBuf = new byte[FILTER_BUF_SIZE];
     23     private int pos = 0;
     24     private int filtered = 0;
     25     private int unfiltered = 0;
     26 
     27     private boolean endReached = false;
     28     private IOException exception = null;
     29 
     30     private final byte[] tempBuf = new byte[1];
     31 
     32     static int getMemoryUsage() {
     33         return 1 + FILTER_BUF_SIZE / 1024;
     34     }
     35 
     36     SimpleInputStream(InputStream in, SimpleFilter simpleFilter) {
     37         // Check for null because otherwise null isn't detect
     38         // in this constructor.
     39         if (in == null)
     40             throw new NullPointerException();
     41 
     42         // The simpleFilter argument comes from this package
     43         // so it is known to be non-null already.
     44         assert simpleFilter != null;
     45 
     46         this.in = in;
     47         this.simpleFilter = simpleFilter;
     48     }
     49 
     50     public int read() throws IOException {
     51         return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
     52     }
     53 
     54     public int read(byte[] buf, int off, int len) throws IOException {
     55         if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
     56             throw new IndexOutOfBoundsException();
     57 
     58         if (len == 0)
     59             return 0;
     60 
     61         if (in == null)
     62             throw new XZIOException("Stream closed");
     63 
     64         if (exception != null)
     65             throw exception;
     66 
     67         try {
     68             int size = 0;
     69 
     70             while (true) {
     71                 // Copy filtered data into the caller-provided buffer.
     72                 int copySize = Math.min(filtered, len);
     73                 System.arraycopy(filterBuf, pos, buf, off, copySize);
     74                 pos += copySize;
     75                 filtered -= copySize;
     76                 off += copySize;
     77                 len -= copySize;
     78                 size += copySize;
     79 
     80                 // If end of filterBuf was reached, move the pending data to
     81                 // the beginning of the buffer so that more data can be
     82                 // copied into filterBuf on the next loop iteration.
     83                 if (pos + filtered + unfiltered == FILTER_BUF_SIZE) {
     84                     System.arraycopy(filterBuf, pos, filterBuf, 0,
     85                                      filtered + unfiltered);
     86                     pos = 0;
     87                 }
     88 
     89                 if (len == 0 || endReached)
     90                     return size > 0 ? size : -1;
     91 
     92                 assert filtered == 0;
     93 
     94                 // Get more data into the temporary buffer.
     95                 int inSize = FILTER_BUF_SIZE - (pos + filtered + unfiltered);
     96                 inSize = in.read(filterBuf, pos + filtered + unfiltered,
     97                                  inSize);
     98 
     99                 if (inSize == -1) {
    100                     // Mark the remaining unfiltered bytes to be ready
    101                     // to be copied out.
    102                     endReached = true;
    103                     filtered = unfiltered;
    104                     unfiltered = 0;
    105                 } else {
    106                     // Filter the data in filterBuf.
    107                     unfiltered += inSize;
    108                     filtered = simpleFilter.code(filterBuf, pos, unfiltered);
    109                     assert filtered <= unfiltered;
    110                     unfiltered -= filtered;
    111                 }
    112             }
    113         } catch (IOException e) {
    114             exception = e;
    115             throw e;
    116         }
    117     }
    118 
    119     public int available() throws IOException {
    120         if (in == null)
    121             throw new XZIOException("Stream closed");
    122 
    123         if (exception != null)
    124             throw exception;
    125 
    126         return filtered;
    127     }
    128 
    129     public void close() throws IOException {
    130         if (in != null) {
    131             try {
    132                 in.close();
    133             } finally {
    134                 in = null;
    135             }
    136         }
    137     }
    138 }
    139