| // Copyright 2008 Google Inc. All Rights Reserved. |
| |
| package com.google.common.io.protocol; |
| |
| import java.io.*; |
| |
| /** |
| * An input stream backed by another input stream, where reading from the |
| * underlying input stream is limited to a fixed number of bytes. Also does |
| * some buffering. |
| * |
| */ |
| public class BoundInputStream extends InputStream { |
| |
| /** Buffer size */ |
| static final int BUF_SIZE = 4096; |
| |
| /** Number of bytes that may still be read from the underlying stream */ |
| private int remaining; |
| |
| /** Small buffer to avoid making OS calls for each byte read. */ |
| private byte[] buf; |
| |
| /** Current position in the buffer */ |
| private int bufPos; |
| |
| /** Filled size of the buffer */ |
| private int bufSize; |
| |
| /** Underlying stream to read from */ |
| private InputStream base; |
| |
| public BoundInputStream(InputStream base, int len) { |
| this.base = base; |
| this.remaining = len; |
| |
| buf = new byte[Math.min(len, BUF_SIZE)]; |
| } |
| |
| /** |
| * Make sure there is at least one byte in the buffer. If not possible, |
| * return false. |
| */ |
| private boolean checkBuf() throws IOException { |
| if (remaining <= 0) { |
| return false; |
| } |
| |
| if (bufPos >= bufSize) { |
| bufSize = base.read(buf, 0, Math.min(remaining, buf.length)); |
| if (bufSize <= 0) { |
| remaining = 0; |
| return false; |
| } |
| bufPos = 0; |
| } |
| return true; |
| } |
| |
| public int available() { |
| return bufSize - bufPos; |
| } |
| |
| public int read() throws IOException { |
| if (!checkBuf()) { |
| return -1; |
| } |
| remaining--; |
| return buf[bufPos++] & 255; |
| } |
| |
| public int read(byte[] data, int start, int count) throws IOException { |
| if (!checkBuf()) { |
| return -1; |
| } |
| count = Math.min(count, bufSize - bufPos); |
| System.arraycopy(buf, bufPos, data, start, count); |
| bufPos += count; |
| remaining -= count; |
| return count; |
| } |
| |
| /** |
| * How many bytes are remaining, based on the length provided to the |
| * constructor. The underlying stream may terminate earlier. Provided mainly |
| * for testing purposes. |
| */ |
| public int getRemaining() { |
| return remaining; |
| } |
| } |