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