package com.onionnetworks.io; import java.io.*; import java.net.*; /** * * This class provides a FilterInputStream that only allows a finite number * of bytes to be read, even if the actual InputStream is much longer. This * is useful for demultiplexing operations where there may be a number of * sub-InputStreams available in a parent InputStream. * * Once the specified number of bytes have been read, a -1 will be returned. * If the underlying inputstream returns a -1 before the specified number * of bytes have been read, an EOFException will be thrown. If one does * NOT close() the FiniteInputStream, the parent InputStream can still be * used to read additional data. Calling close() on the FiniteInputStream * will close the parent InputStream. * */ public class FiniteInputStream extends FilterInputStream { protected long left; /** * @param is The parent InputStream to read from. * @param count the total number of bytes to allow to be read from * the parent. */ public FiniteInputStream(InputStream is, long count) { super(is); if (is == null) { throw new NullPointerException(); } if (count < 0) { throw new IllegalArgumentException("count must be > 0"); } left = count; } /** * wraps read(byte[],int,int) to read a single byte. */ public int read() throws IOException { byte[] b = new byte[1]; if (read(b,0,1) == -1) { return -1; } return b[0] & 0xFF; } /** * Read some bytes. This will read no more total bytes from the parent * than the count specified in the constructor. * * @return The number of bytes read, or -1 if the specified number * of bytes for the FiniteInputStream have been read. * @throws EOFException If the parent stream unexpectantly ends before the * <code>count</code> bytes have been read. */ public int read(byte[] b, int off, int len) throws IOException { // check the len so that a 0 len returns a 0 result if (left == 0 && len > 0) { return -1; } // trunc the read if they want more than is left. //FIX unit test the LONG // The (int) cast is safe because len is an int and thus left will not // return if it would overflow an int. int c = in.read(b,off,(int) Math.min(len,left)); if (c < 0) { throw new EOFException(); } left -= c; return c; } public long skip(long n) throws IOException { long result = in.skip(Math.min(n,left)); left -= result; return result; } public int available() throws IOException { // (int) cast is safe because in.available must be an int and thus // smaller than overflow. return (int) Math.min(in.available(),left); } }