X-Git-Url: http://git.nikiroo.be/?p=nikiroo-utils.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fstreams%2FBufferedInputStream.java;fp=src%2Fbe%2Fnikiroo%2Futils%2Fstreams%2FBufferedInputStream.java;h=0000000000000000000000000000000000000000;hp=683fa55865aff5ee4b6d442638721372c99e0e02;hb=ad207feb2815e429ae32484bc6930990099f8ea4;hpb=1b5197ed4ceec2025a9a40c417b37c646b756138 diff --git a/src/be/nikiroo/utils/streams/BufferedInputStream.java b/src/be/nikiroo/utils/streams/BufferedInputStream.java deleted file mode 100644 index 683fa55..0000000 --- a/src/be/nikiroo/utils/streams/BufferedInputStream.java +++ /dev/null @@ -1,522 +0,0 @@ -package be.nikiroo.utils.streams; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -import be.nikiroo.utils.StringUtils; - -/** - * A simple {@link InputStream} that is buffered with a bytes array. - *

- * It is mostly intended to be used as a base class to create new - * {@link InputStream}s with special operation modes, and to give some default - * methods. - * - * @author niki - */ -public class BufferedInputStream extends InputStream { - /** - * The size of the internal buffer (can be different if you pass your own - * buffer, of course). - *

- * A second buffer of twice the size can sometimes be created as needed for - * the {@link BufferedInputStream#startsWith(byte[])} search operation. - */ - static private final int BUFFER_SIZE = 4096; - - /** The current position in the buffer. */ - protected int start; - /** The index of the last usable position of the buffer. */ - protected int stop; - /** The buffer itself. */ - protected byte[] buffer; - /** An End-Of-File (or {@link InputStream}, here) marker. */ - protected boolean eof; - - private boolean closed; - private InputStream in; - private int openCounter; - - // special use, prefetched next buffer - private byte[] buffer2; - private int pos2; - private int len2; - private byte[] originalBuffer; - - private long bytesRead; - - /** - * Create a new {@link BufferedInputStream} that wraps the given - * {@link InputStream}. - * - * @param in - * the {@link InputStream} to wrap - */ - public BufferedInputStream(InputStream in) { - this.in = in; - - this.buffer = new byte[BUFFER_SIZE]; - this.originalBuffer = this.buffer; - this.start = 0; - this.stop = 0; - } - - /** - * Create a new {@link BufferedInputStream} that wraps the given bytes array - * as a data source. - * - * @param in - * the array to wrap, cannot be NULL - */ - public BufferedInputStream(byte[] in) { - this(in, 0, in.length); - } - - /** - * Create a new {@link BufferedInputStream} that wraps the given bytes array - * as a data source. - * - * @param in - * the array to wrap, cannot be NULL - * @param offset - * the offset to start the reading at - * @param length - * the number of bytes to take into account in the array, - * starting from the offset - * - * @throws NullPointerException - * if the array is NULL - * @throws IndexOutOfBoundsException - * if the offset and length do not correspond to the given array - */ - public BufferedInputStream(byte[] in, int offset, int length) { - if (in == null) { - throw new NullPointerException(); - } else if (offset < 0 || length < 0 || length > in.length - offset) { - throw new IndexOutOfBoundsException(); - } - - this.in = null; - - this.buffer = in; - this.originalBuffer = this.buffer; - this.start = offset; - this.stop = length; - } - - /** - * The internal buffer size (can be useful to know for search methods). - * - * @return the size of the internal buffer, in bytes. - */ - public int getInternalBufferSize() { - return originalBuffer.length; - } - - /** - * Return this very same {@link BufferedInputStream}, but keep a counter of - * how many streams were open this way. When calling - * {@link BufferedInputStream#close()}, decrease this counter if it is not - * already zero instead of actually closing the stream. - *

- * You are now responsible for it — you must close it. - *

- * This method allows you to use a wrapping stream around this one and still - * close the wrapping stream. - * - * @return the same stream, but you are now responsible for closing it - * - * @throws IOException - * in case of I/O error or if the stream is closed - */ - public synchronized InputStream open() throws IOException { - checkClose(); - openCounter++; - return this; - } - - /** - * Check if the current content (until eof) is equal to the given search - * term. - *

- * Note: the search term size must be smaller or equal the internal - * buffer size. - * - * @param search - * the term to search for - * - * @return TRUE if the content that will be read starts with it - * - * @throws IOException - * in case of I/O error or if the size of the search term is - * greater than the internal buffer - */ - public boolean is(String search) throws IOException { - return is(StringUtils.getBytes(search)); - } - - /** - * Check if the current content (until eof) is equal to the given search - * term. - *

- * Note: the search term size must be smaller or equal the internal - * buffer size. - * - * @param search - * the term to search for - * - * @return TRUE if the content that will be read starts with it - * - * @throws IOException - * in case of I/O error or if the size of the search term is - * greater than the internal buffer - */ - public boolean is(byte[] search) throws IOException { - if (startsWith(search)) { - return (stop - start) == search.length; - } - - return false; - } - - /** - * Check if the current content (what will be read next) starts with the - * given search term. - *

- * Note: the search term size must be smaller or equal the internal - * buffer size. - * - * @param search - * the term to search for - * - * @return TRUE if the content that will be read starts with it - * - * @throws IOException - * in case of I/O error or if the size of the search term is - * greater than the internal buffer - */ - public boolean startsWith(String search) throws IOException { - return startsWith(StringUtils.getBytes(search)); - } - - /** - * Check if the current content (what will be read next) starts with the - * given search term. - *

- * An empty string will always return true (unless the stream is closed, - * which would throw an {@link IOException}). - *

- * Note: the search term size must be smaller or equal the internal - * buffer size. - * - * @param search - * the term to search for - * - * @return TRUE if the content that will be read starts with it - * - * @throws IOException - * in case of I/O error or if the size of the search term is - * greater than the internal buffer - */ - public boolean startsWith(byte[] search) throws IOException { - if (search.length > originalBuffer.length) { - throw new IOException( - "This stream does not support searching for more than " - + buffer.length + " bytes"); - } - - checkClose(); - - if (available() < search.length) { - preRead(); - } - - if (available() >= search.length) { - // Easy path - return StreamUtils.startsWith(search, buffer, start, stop); - } else if (in != null && !eof) { - // Harder path - if (buffer2 == null && buffer.length == originalBuffer.length) { - buffer2 = Arrays.copyOf(buffer, buffer.length * 2); - - pos2 = buffer.length; - len2 = read(in, buffer2, pos2, buffer.length); - if (len2 > 0) { - bytesRead += len2; - } - - // Note: here, len/len2 = INDEX of last good byte - len2 += pos2; - } - - return StreamUtils.startsWith(search, buffer2, pos2, len2); - } - - return false; - } - - /** - * The number of bytes read from the under-laying {@link InputStream}. - * - * @return the number of bytes - */ - public long getBytesRead() { - return bytesRead; - } - - /** - * Check if this stream is spent (no more data to read or to - * process). - * - * @return TRUE if it is - * - * @throws IOException - * in case of I/O error - */ - public boolean eof() throws IOException { - if (closed) { - return true; - } - - preRead(); - return !hasMoreData(); - } - - /** - * Read the whole {@link InputStream} until the end and return the number of - * bytes read. - * - * @return the number of bytes read - * - * @throws IOException - * in case of I/O error - */ - public long end() throws IOException { - long skipped = 0; - while (hasMoreData()) { - skipped += skip(buffer.length); - } - - return skipped; - } - - @Override - public int read() throws IOException { - checkClose(); - - preRead(); - if (eof) { - return -1; - } - - return buffer[start++]; - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - @Override - public int read(byte[] b, int boff, int blen) throws IOException { - checkClose(); - - if (b == null) { - throw new NullPointerException(); - } else if (boff < 0 || blen < 0 || blen > b.length - boff) { - throw new IndexOutOfBoundsException(); - } else if (blen == 0) { - return 0; - } - - int done = 0; - while (hasMoreData() && done < blen) { - preRead(); - if (hasMoreData()) { - int now = Math.min(blen - done, stop - start); - if (now > 0) { - System.arraycopy(buffer, start, b, boff + done, now); - start += now; - done += now; - } - } - } - - return done > 0 ? done : -1; - } - - @Override - public long skip(long n) throws IOException { - if (n <= 0) { - return 0; - } - - long skipped = 0; - while (hasMoreData() && n > 0) { - preRead(); - - long inBuffer = Math.min(n, available()); - start += inBuffer; - n -= inBuffer; - skipped += inBuffer; - } - - return skipped; - } - - @Override - public int available() { - if (closed) { - return 0; - } - - return Math.max(0, stop - start); - } - - /** - * Closes this stream and releases any system resources associated with the - * stream. - *

- * Including the under-laying {@link InputStream}. - *

- * Note: if you called the {@link BufferedInputStream#open()} method - * prior to this one, it will just decrease the internal count of how many - * open streams it held and do nothing else. The stream will actually be - * closed when you have called {@link BufferedInputStream#close()} once more - * than {@link BufferedInputStream#open()}. - * - * @exception IOException - * in case of I/O error - */ - @Override - public synchronized void close() throws IOException { - close(true); - } - - /** - * Closes this stream and releases any system resources associated with the - * stream. - *

- * Including the under-laying {@link InputStream} if - * incudingSubStream is true. - *

- * You can call this method multiple times, it will not cause an - * {@link IOException} for subsequent calls. - *

- * Note: if you called the {@link BufferedInputStream#open()} method - * prior to this one, it will just decrease the internal count of how many - * open streams it held and do nothing else. The stream will actually be - * closed when you have called {@link BufferedInputStream#close()} once more - * than {@link BufferedInputStream#open()}. - * - * @param includingSubStream - * also close the under-laying stream - * - * @exception IOException - * in case of I/O error - */ - public synchronized void close(boolean includingSubStream) - throws IOException { - if (!closed) { - if (openCounter > 0) { - openCounter--; - } else { - closed = true; - if (includingSubStream && in != null) { - in.close(); - } - } - } - } - - /** - * Check if we still have some data in the buffer and, if not, fetch some. - * - * @return TRUE if we fetched some data, FALSE if there are still some in - * the buffer - * - * @throws IOException - * in case of I/O error - */ - protected boolean preRead() throws IOException { - boolean hasRead = false; - if (in != null && !eof && start >= stop) { - start = 0; - if (buffer2 != null) { - buffer = buffer2; - start = pos2; - stop = len2; - - buffer2 = null; - pos2 = 0; - len2 = 0; - } else { - buffer = originalBuffer; - - stop = read(in, buffer, 0, buffer.length); - if (stop > 0) { - bytesRead += stop; - } - } - - hasRead = true; - } - - if (start >= stop) { - eof = true; - } - - return hasRead; - } - - /** - * Read the under-laying stream into the local buffer. - * - * @param in - * the under-laying {@link InputStream} - * @param buffer - * the buffer we use in this {@link BufferedInputStream} - * @param off - * the offset - * @param len - * the length in bytes - * - * @return the number of bytes read - * - * @throws IOException - * in case of I/O error - */ - protected int read(InputStream in, byte[] buffer, int off, int len) - throws IOException { - return in.read(buffer, off, len); - } - - /** - * We have more data available in the buffer or we can, maybe, fetch - * more. - * - * @return TRUE if it is the case, FALSE if not - */ - protected boolean hasMoreData() { - if (closed) { - return false; - } - - return (start < stop) || !eof; - } - - /** - * Check that the stream was not closed, and throw an {@link IOException} if - * it was. - * - * @throws IOException - * if it was closed - */ - protected void checkClose() throws IOException { - if (closed) { - throw new IOException( - "This BufferedInputStream was closed, you cannot use it anymore."); - } - } -}