SizeLimitInputStream.java Source code

Java tutorial

Introduction

Here is the source code for SizeLimitInputStream.java

Source

/*
 * Input stream wrapper with a byte limit.
 * Copyright (C) 2004 Stephen Ostermiller
 * http://ostermiller.org/contact.pl?regarding=Java+Utilities
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * See COPYING.TXT for details.
 */

import java.io.*;

/**
 * An input stream wrapper that will read only a set number of bytes from the
 * underlying stream.
 *
 * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
 * @since ostermillerutils 1.04.00
 */
public class SizeLimitInputStream extends InputStream {

    /**
     * The input stream that is being protected.
     * All methods should be forwarded to it,
     * after checking the size that has been read.
     *
     * @since ostermillerutils 1.04.00
     */
    protected InputStream in;

    /**
     * The number of bytes to read at most from this
     * Stream.  Read methods should
     * check to ensure that bytesRead never
     * exceeds maxBytesToRead.
     *
     * @since ostermillerutils 1.04.00
     */
    protected long maxBytesToRead = 0;

    /**
     * The number of bytes that have been read
     * from this stream.  Read methods should
     * check to ensure that bytesRead never
     * exceeds maxBytesToRead.
     *
     * @since ostermillerutils 1.04.00
     */
    protected long bytesRead = 0;

    /**
     * The number of bytes that have been read
     * from this stream since mark() was called.
     *
     * @since ostermillerutils 1.04.00
     */
    protected long bytesReadSinceMark = 0;

    /**
     * The number of bytes the user has request
     * to have been marked for reset.
     *
     * @since ostermillerutils 1.04.00
     */
    protected long markReadLimitBytes = -1;

    /**
     * Get the number of bytes actually read
     * from this stream.
     *
     * @return number of bytes that have already been taken from this stream.
     *
     * @since ostermillerutils 1.04.00
     */
    public long getBytesRead() {
        return bytesRead;
    }

    /**
     * Get the maximum number of bytes left to read
     * before the limit (set in the constructor) is reached.
     *
     * @return The number of bytes that (at a maximum) are left to be taken from this stream.
     *
     * @since ostermillerutils 1.04.00
     */
    public long getBytesLeft() {
        return maxBytesToRead - bytesRead;
    }

    /**
     * Tell whether the number of bytes specified
     * in the constructor have been read yet.
     *
     * @return true iff the specified number of bytes have all been read.
     *
     * @since ostermillerutils 1.04.00
     */
    public boolean allBytesRead() {
        return getBytesLeft() == 0;
    }

    /**
     * Get the number of total bytes (including bytes already read)
     * that can be read from this stream (as set in the constructor).
     * @return Maximum bytes that can be read until the size limit runs out
     *
     * @since ostermillerutils 1.04.00
     */
    public long getMaxBytesToRead() {
        return maxBytesToRead;
    }

    /**
     * Create a new size limit input stream from
     * another stream given a size limit.
     *
     * @param in The input stream.
     * @param maxBytesToRead the max number of bytes to allow to be read from the underlying stream.
     *
     * @since ostermillerutils 1.04.00
     */
    public SizeLimitInputStream(InputStream in, long maxBytesToRead) {
        this.in = in;
        this.maxBytesToRead = maxBytesToRead;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int read() throws IOException {
        if (bytesRead >= maxBytesToRead) {
            return -1;
        }
        int b = in.read();
        if (b != -1) {
            bytesRead++;
            bytesReadSinceMark++;
        }
        return b;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int read(byte[] b) throws IOException {
        return this.read(b, 0, b.length);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        if (bytesRead >= maxBytesToRead) {
            return -1;
        }
        long bytesLeft = getBytesLeft();
        if (len > bytesLeft) {
            len = (int) bytesLeft;
        }
        int bytesJustRead = in.read(b, off, len);
        bytesRead += bytesJustRead;
        bytesReadSinceMark += bytesJustRead;
        return bytesJustRead;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public long skip(long n) throws IOException {
        if (bytesRead >= maxBytesToRead) {
            return -1;
        }
        long bytesLeft = getBytesLeft();
        if (n > bytesLeft) {
            n = bytesLeft;
        }
        return in.skip(n);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int available() throws IOException {
        int available = in.available();
        long bytesLeft = getBytesLeft();
        if (available > bytesLeft) {
            available = (int) bytesLeft;
        }
        return available;
    }

    /**
     * Close this stream and underlying streams.
     * Calling this method may make data on the
     * underlying stream unavailable.
     * <p>
     * Consider wrapping this stream in a NoCloseStream
     * so that clients can
     * call close() with no effect.
     *
     * @since ostermillerutils 1.04.00
     */
    @Override
    public void close() throws IOException {
        in.close();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void mark(int readlimit) {
        if (in.markSupported()) {
            markReadLimitBytes = readlimit;
            bytesReadSinceMark = 0;
            in.mark(readlimit);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void reset() throws IOException {
        if (in.markSupported() && bytesReadSinceMark <= markReadLimitBytes) {
            bytesRead -= bytesReadSinceMark;
            in.reset();
            bytesReadSinceMark = 0;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean markSupported() {
        return in.markSupported();
    }
}