SizeLimitInputStream.java

package gov.usgs.earthquake.util;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Stream that only allows a certain number of bytes to be read.
 *
 * Current implementation only tracks read bytes, and ignores any mark or reset
 * calls.
 */
public class SizeLimitInputStream extends FilterInputStream {

	/** Maximum number of bytes to read. */
	private long limit;
	/** Number of bytes already read. */
	private long read = 0L;

	/**
	 * Construct a new SizeLimitInputStream.
	 *
	 * @param in
	 *            stream to limit.
	 * @param limit
	 *            maximum number of bytes allowed to read.
	 */
	public SizeLimitInputStream(InputStream in, final long limit) {
		super(in);
		this.limit = limit;
	}

	/**
	 * Return number of bytes read.
	 * @return bytes read
	 */
	public long getRead() {
		return this.read;
	}

	/**
	 * Read one byte.
	 */
	@Override
	public int read() throws IOException {
		int b = in.read();
		if (b != -1) {
			read++;
			checkLimit();
		}
		return b;
	}

	/**
	 * Read into an array of bytes.
	 */
	@Override
	public int read(byte[] b) throws IOException {
		return read(b, 0, b.length);
	}

	/**
	 * Read into an array of bytes.
	 */
	@Override
	public int read(byte[] b, int off, int len) throws IOException {
		int total = in.read(b, off, len);
		if (total != -1) {
			read += total;
			checkLimit();
		}
		return total;
	}

	/**
	 * Check how many bytes have been read.
	 *
	 * @throws IOException
	 *             if more bytes than the limit allows have been read.
	 */
	protected void checkLimit() throws IOException {
		if (limit > 0 && read > limit) {
			throw new IOException("Read more than size limit (" + limit
					+ ") bytes");
		}
	}

}