All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mediautil.gen.directio.SplitInputStream Maven / Gradle / Ivy

Go to download

SDK for dev_appserver (local development) with some of the dependencies shaded (repackaged)

There is a newer version: 2.0.31
Show newest version
/* MediaUtil LLJTran - $RCSfile: SplitInputStream.java,v $
 * Copyright (C) 1999-2005 Dmitriy Rogatkin, Suresh Mahalingam.  All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  $Id: SplitInputStream.java,v 1.4 2005/08/18 04:35:34 drogatkin Exp $
 *
 */
package mediautil.gen.directio;

import java.io.*;

import mediautil.gen.BasicIo;

/**
 * This class enables the Sharing of an InputStream (Say from a file) by One or
 * more IterativeReaders with a main reader. The main reader is any reader like
 * say an ImageReader for reading images.

* * This is accomplished by using a common buffer. The read/skip calls on this * class by the main reader calls nextRead() on the SubStreams to consume the * buffered data before the buffer is filled again. * @see IterativeReader * * @author Suresh Mahalingam ([email protected]) */ public class SplitInputStream extends FilterInputStream { private byte q[]; private final static int DEF_BUF_SIZE = 5120; private final static int DEF_INC_SIZE = 1024; private byte oneByteArr[] = new byte[1]; private int bufSize, incSize, qEnd, q2nd; private boolean eofFlag; private int qPtrs[]; private int subReaderIds[]; private IterativeReader codes[]; private SubStream subStreams[]; private byte requestBuf[]; private int requestPos, requestRemain; private int curReaderId; private int maxReaderId; private int maxBufSize, maxBufUsage; private class SubStream extends InputStream implements ByteCounter { public SplitInputStream parentThis; private byte oneByteArr[] = new byte[1]; private int readerNo, readerId; public int minReadSize, readCushion; public boolean closedFlag; private int counterArr[]; private boolean upMode; private long totalBytes; public SubStream(SplitInputStream parentThis, int minReadSize, int readCushion) { this.parentThis = parentThis; this.readCushion = readCushion; this.minReadSize = minReadSize; closedFlag = false; readerNo = -1; readerId = 0; totalBytes = 0; counterArr = null; } public SubStream(SplitInputStream parentThis) { this(parentThis, 750, 750); } public void setCounter(int counterArr[], boolean upMode) { int i = counterArr[0]; // Good if an exception is detected this.counterArr = counterArr; this.upMode = upMode; } public long getTotalBytes() { return totalBytes; } private String validate() { String retVal = null; if(!closedFlag) { if(readerNo < 0) retVal = "Attempt to read from an invalid or unattached substream"; else if(readerId != curReaderId) retVal = "Substream Context Error: Iterative code attached as id " + curReaderId + " attempting to read from substream with id " + readerId; } return retVal; } public int read(byte b[], int off, int len) throws IOException { // String ioError = validate(); Inlining validate for performance String ioError = null; if(!closedFlag) { if(readerNo < 0) ioError = "Attempt to read from an invalid or unattached substream"; else if(readerId != curReaderId) ioError = "Substream Context Error: Iterative code attached as id " + curReaderId + " attempting to read from substream with id " + readerId; if(ioError != null) throw new IOException(ioError); } if(len < 0) throw new IndexOutOfBoundsException("Negative Length Read attempted, len = " + len); byte b1 = b[off], b2 = b[off + len -1]; if(len == 0) return 0; if(closedFlag) return -1; if(q == null) q = new byte[bufSize]; // Begin q.dequeue(in, readerNo, b, off, len) int remain = len; int qReadSize = qEnd - qPtrs[readerNo]; if(qReadSize > len) qReadSize = len; if(qReadSize > 0) { System.arraycopy(q, qPtrs[readerNo], b, off, qReadSize); qPtrs[readerNo] += qReadSize; off += qReadSize; remain -= qReadSize; } int retVal = len; if(remain > 0) { if(!eofFlag) remain -= fillAndDequeue(readerNo, b, off, remain); retVal -= remain; if(retVal <= 0) { retVal = -1; detachSubReaderNo(readerNo-1); } } // End q.dequeue(in, readerNo, b, off, len) if(retVal > 0) { totalBytes += retVal; if(counterArr != null) { if(upMode) counterArr[0] += retVal; else counterArr[0] -= retVal; } } return retVal; } public int read() throws IOException { int retVal = -1; if(read(oneByteArr, 0, 1) == 1) retVal = oneByteArr[0] & 255; return retVal; } /** * Does not strictly conform to InputStream spec since it always returns * n unless it is eof. **/ public long skip(long n) throws IOException { String ioError = validate(); if(ioError != null) throw new IOException(ioError); int retVal = (int)n; if(closedFlag || retVal < 0) retVal = 0; qPtrs[readerNo] += retVal; totalBytes += retVal; if(counterArr != null) { if(upMode) counterArr[0] += retVal; else counterArr[0] -= retVal; } return retVal; } /** * Does not strictly conform to InputStream spec since it always returns * atleast 1 unless the end of file is reached. **/ public int available() throws IOException { String ioError = validate(); if(ioError != null) throw new IOException(ioError); int retVal = 0; if(!closedFlag) { retVal = qEnd - qPtrs[readerNo]; if(retVal <= 0) retVal = eofFlag?0:1; } return retVal; } public void close() throws IOException { String ioError = validate(); if(ioError != null) throw new IOException(ioError); if(readerNo > 0) detachSubReaderNo(readerNo-1); } } // This is inlined in read calls to improve performance. Is it going to? private int dequeue(int readerNo, byte b[], int off, int n) { int qReadSize = qEnd - qPtrs[readerNo]; if(qReadSize > n) qReadSize = n; if(qReadSize > 0) { if(b != null) System.arraycopy(q, qPtrs[readerNo], b, off, qReadSize); qPtrs[readerNo] += qReadSize; } else qReadSize = 0; return qReadSize; } private void reallocBuf(int newLen) { int offset = findQBegin(null); byte newQ[] = new byte[newLen]; int copyLen = qEnd - offset; if(copyLen > 0) System.arraycopy(q, offset, newQ, 0, copyLen); else offset = qEnd; q = newQ; int i; for(i = 0; i < qPtrs.length; ++i) qPtrs[i] -= offset; qEnd -= offset; q2nd -= offset; if(newLen > maxBufSize) maxBufSize = newLen; } private int fillAndDequeue(int readerNo, byte b[], int off, int len) throws IOException { // Caller would have done basic dequeue, but still to be sure. int qReadSize = dequeue(readerNo, b, off, len); int remain = len - qReadSize; off += qReadSize; int qPtr = qPtrs[readerNo]; int i; // Real Tough fillAndDequeue if(remain > 0 && !eofFlag) { // Since dequeue done skipLen >= 0 int skipLen = qPtr - qEnd; int fillSize = remain + skipLen; int reqSize = fillSize + (qEnd - q2nd); int readLen, actualRead; if(q2nd < qPtr) skipLen = q2nd - qEnd; if(q2nd > qEnd && fillSize > bufSize && (reqSize <= bufSize || (reqSize - bufSize -1)/incSize < (fillSize - bufSize -1)/incSize)) { int newQStart = qPtr + remain; if(newQStart > q2nd) newQStart = q2nd; int dFillLen = newQStart - qEnd; int dRemain = dFillLen; readLen = 0; if(requestBuf != null) { readLen = requestRemain; if(readLen > dRemain) readLen = dRemain; } if(readLen > 0) { actualRead = BasicIo.read(in, requestBuf, requestPos, readLen, readLen); if(actualRead < readLen) eofFlag = true; int xferLen = actualRead - skipLen; if(xferLen > 0) { if(b != null) System.arraycopy(requestBuf, requestPos + skipLen, b, off, xferLen); skipLen = 0; off += xferLen; remain -= xferLen; } else skipLen = -xferLen; dRemain -= actualRead; } if(skipLen > 0 && !eofFlag) { actualRead = (int) BasicIo.skip(in, skipLen); if(actualRead < skipLen) eofFlag = true; skipLen -= actualRead; dRemain -= actualRead; } if(dRemain > 0 && !eofFlag) { if(b!= null) actualRead = BasicIo.read(in, b, off, dRemain, dRemain); else actualRead = (int) BasicIo.skip(in, dRemain); if(actualRead < dRemain) eofFlag = true; off += actualRead; remain -= actualRead; dRemain -= actualRead; } readLen = dFillLen - dRemain; qEnd += readLen; if(readLen > requestRemain) readLen = requestRemain; requestPos += readLen; requestRemain -= readLen; qPtr += len - qReadSize - remain; } if(requestBuf == null && skipLen > 0 && !eofFlag) { actualRead = (int) BasicIo.skip(in, skipLen); if(actualRead < skipLen) eofFlag = true; readLen = requestRemain; if(readLen > actualRead) readLen = actualRead; requestPos += readLen; requestRemain -= readLen; qEnd += actualRead; } qPtrs[readerNo] = qPtr; if(remain > 0 && !eofFlag) { int newQBegin = q2nd; if(qEnd < q2nd) newQBegin = qEnd; fillSize = remain + (qPtr - qEnd); reqSize = fillSize + (qEnd - newQBegin); if(reqSize > maxBufUsage) maxBufUsage = reqSize; if(reqSize > q.length) reallocBuf(reqSize + incSize - 1 - (reqSize - 1 - bufSize)%incSize); else { if(qEnd > newQBegin && newQBegin > 0) System.arraycopy(q, newQBegin, q, 0, qEnd - newQBegin); i = 0; do { qPtrs[i] -= newQBegin; ++i; } while(i < qPtrs.length); qEnd -= newQBegin; q2nd -= newQBegin; } int maxFillSize = bufSize - qEnd; if(maxFillSize < fillSize) maxFillSize = fillSize; actualRead = BasicIo.read(in, q, qEnd, fillSize, maxFillSize); if(actualRead < fillSize) eofFlag = true; readLen = requestRemain; if(readLen > actualRead) readLen = actualRead; if(readLen > 0) { if(requestBuf != null) System.arraycopy(q, qEnd, requestBuf, requestPos, readLen); requestPos += readLen; requestRemain -= readLen; } qEnd += actualRead; // Finally Dequeue bytes read remain -= dequeue(readerNo, b, off, remain); } } return len - remain; } private int findQBegin(int qBeginIndex[]) { int i, qBegin, index = -1; if(qPtrs.length == 0) qBegin = 0; else { qBegin = 0x7FFFFFFF; i = 0; do if(qPtrs[i] < qBegin) { qBegin = qPtrs[i]; index = i; } while(++i < qPtrs.length); } if(qBeginIndex != null) qBeginIndex[0] = index; return qBegin; } private void init(InputStream mainStream, int bufSize, int incSize) { if(bufSize < 2048) bufSize = 2048; if(incSize < 512) incSize = 512; this.bufSize = bufSize; maxBufSize = bufSize; this.incSize = incSize; qPtrs = new int[1]; qPtrs[0] = 0; qEnd = 0; q = null; eofFlag = false; subReaderIds = new int[0]; subStreams = new SubStream[0]; codes = new IterativeReader[0]; curReaderId = -1; maxReaderId = 0; } /** * Creates a new SplitInputStream Object. This can be used as an Input * Stream. * @param mainStream The main input Stream, say a FileInputStream. Note that * this need not be buffered since SplitInputStream itself does buffering. * The Main Object (Say ImageReader) will read from the newly constructed * SplitInputStream object after attaching zero or more IterativeReaders. * The SplitInputStream and Sub Streams see the same data as in mainStream. * @param bufSize The Initial BufferSize. This will be increased if one of * the Sub Readers read way beyond the requested Size * @param incSize The buffer Size is always increase/decreased in multiples * of incSize */ public SplitInputStream(InputStream mainStream, int bufSize, int incSize) { super(mainStream); init(mainStream, bufSize, incSize); } /** * Creates a new SplitInputStream Object with default parameters. The * bufSize used is 5120 bytes, incSize used is 1024. * @param mainStream The main input Stream, say a FileInputStream. Note that * this need not be buffered since SplitInputStream itself does buffering. * The Main Object (Say ImageReader) will read from the newly constructed * SplitInputStream object after attaching zero or more IterativeReaders. * The SplitInputStream and Sub Streams see the same data as in mainStream. */ public SplitInputStream(InputStream mainStream) { this(mainStream, DEF_BUF_SIZE, DEF_INC_SIZE); } /** * Creates a Sub Stream for use by an instance of IterativeReader. The * SubStream sees the same data as in the mainStream. The Buffer Size of the * SplitInputStream if less than (minReadSize+readCushion+512) is resized to * that value. * @param minReadSize The minimum Number of Bytes that should be passed to * the nextRead method of the IterativeReader. This value is limited to * atleast 512. * @param readCushion The maximum number of bytes by which a nextRead() call * to the subReader may overshoot the requested number of bytes. If a * nextRead() call exceeds the limit beyond readCushion a buffer expansion * may result which affects performance. This value is limited to atleast * 512. * @return An InputStream which also implements ByteCounter which can be * used by the IterativeReader to keep track of the bytes read/skipped. This * Input Stream must be used directly (without creating a * BufferedInputStream) by an Object implementing IterativeReader. The * attachSubReader() method must be called with the IterativeReader Object * and this return value after this call.

* * Please note that the returned Input Stream does not strictly confirm to * jdk's InputStream spec in the following: *

    *
  • The Skip call always skips the required number of bytes unless the * end of file has already been detected. This is because for skip just * the internal q pointers are incremented without actually checking for * the end of file. This is to avoid possible unnecessary buffering of * data. *
  • available always returns atleast 1 unless the end of file has been * detected *
* @see IterativeReader * @see #attachSubReader(IterativeReader, InputStream) * @see ByteCounter */ public InputStream createSubStream(int minReadSize, int readCushion) { if(minReadSize < 512) minReadSize = 512; if(readCushion < 512) readCushion = 512; return new SubStream(this, minReadSize, readCushion); } /** * Creates a Sub Stream for use by an instance of IterativeReader. A minimum * read Size of 750 and a read Cushion of 750 is used. * @return An InputStream which also implements ByteCounter which can be * used by the IterativeReader to keep track of the bytes read/skipped. This * Input Stream must be used directly (without creating a * BufferedInputStream) by an Object implementing IterativeReader. The * attachSubReader() method must be called with the IterativeReader Object * and this return value after this call.

* * Please note that the returned Input Stream does not strictly confirm to * jdk's InputStream spec in the following: *

    *
  • The Skip call always skips the required number of bytes unless the * end of file has already been detected. This is because for skip just * the internal q pointers are incremented without actually checking for * the end of file. This is to avoid possible unnecessary buffering of * data. *
  • available always returns atleast 1 unless the end of file has been * detected *
* @see IterativeReader * @see #attachSubReader(IterativeReader,InputStream) * @see ByteCounter */ public InputStream createSubStream() { return new SubStream(this); } /** * This call must follow a createSubStream() call to attach an * IterativeReader to read from the subStream created. This subReader is * detached by a detachSubReader(..) call or when the nextRead() method * returns IterativeReader.STOP or when the subStream is closed. * @param code The IterativeReader to share the main Input. The nextRead() * method is called on code by the read/skip calls on SplitInputStream as * and when required. * @param subStream The SubStream which was created using createSubStream() * call and not yet attached. The nextRead() calls to the IterativeReader * specified by the parameter code must read from this subStream. * @return An integer representing a SubReader Id. This id should be passed * if a stream is required to be detached. * @see IterativeReader#nextRead(int) * @see #createSubStream(int,int) * @see #detachSubReader(int) */ public int attachSubReader(IterativeReader code, InputStream subStream) { String err = null; SubStream sub = null; if(code == null) throw new NullPointerException("code is NULL"); if(!(subStream instanceof SubStream)) err = "subStream passed was not created using createSubStream call"; else { sub = (SubStream) subStream; if(sub.parentThis != this) err = "subStream was created from another SplitInputStream instance"; else if(sub.readerNo > 0 || sub.readerId > 0) err = "subStream already in use"; } if(err != null) throw new RuntimeException(err); int minBufSize = sub.minReadSize + sub.readCushion + 512; if(minBufSize > bufSize) { if(q != null) reallocBuf(minBufSize); bufSize = minBufSize; } int newSubReaderIds[] = new int[subReaderIds.length+1]; IterativeReader newCodes[] = new IterativeReader[codes.length+1]; SubStream newSubStreams[] = new SubStream[subStreams.length+1]; System.arraycopy(subReaderIds, 0, newSubReaderIds, 0, subReaderIds.length); System.arraycopy(codes, 0, newCodes, 0, codes.length); System.arraycopy(subStreams, 0, newSubStreams, 0, subStreams.length); newCodes[codes.length] = code; newSubStreams[subStreams.length] = sub; maxReaderId++; int retVal = maxReaderId; newSubReaderIds[subReaderIds.length] = retVal; sub.readerNo = newSubStreams.length; sub.readerId = retVal; int newQPtrs[] = new int[qPtrs.length + 1]; System.arraycopy(qPtrs, 0, newQPtrs, 0, qPtrs.length); int i; newQPtrs[qPtrs.length] = findQBegin(null); qPtrs = newQPtrs; subReaderIds = newSubReaderIds; codes = newCodes; subStreams = newSubStreams; return retVal; } /** * Detaches a Sub Reader and its Stream. Note that it is not necessary to * call this method explicitly as the Sub Reader is automatically detached * when the nextRead() returns IterativeReader.STOP or when the subStream is * closed. * @param subReaderId Id to detach * @see #attachSubReader(IterativeReader,InputStream) */ public void detachSubReader(int subReaderId) { int i; for(i=0; i < subReaderIds.length; i++) if(subReaderIds[i] == subReaderId) break; if(i >= subReaderIds.length) throw new RuntimeException("SubReaderId " + subReaderId + " Not found for detaching from SplitInputStream"); detachSubReaderNo(i); } private void detachSubReaderNo(int subReaderNo) { int i, j, readerNo = subReaderNo+1; codes[subReaderNo] = null; SubStream detachedStream = subStreams[subReaderNo]; detachedStream.readerNo = -1; detachedStream.readerId = 0; detachedStream.closedFlag = true; subStreams[subReaderNo] = null; int newSubReaderIds[] = new int[subReaderIds.length-1]; IterativeReader newCodes[] = new IterativeReader[codes.length-1]; SubStream newSubStreams[] = new SubStream[subStreams.length-1]; System.arraycopy(subReaderIds, 0, newSubReaderIds, 0, subReaderNo); System.arraycopy(codes, 0, newCodes, 0, subReaderNo); System.arraycopy(subStreams, 0, newSubStreams, 0, subReaderNo); System.arraycopy(subReaderIds, subReaderNo+1, newSubReaderIds, subReaderNo, newSubReaderIds.length-subReaderNo); System.arraycopy(codes, subReaderNo+1, newCodes, subReaderNo, newCodes.length-subReaderNo); System.arraycopy(subStreams, subReaderNo+1, newSubStreams, subReaderNo, newSubStreams.length-subReaderNo); // q.detach(in, subReaderNo+1); int newQPtrs[] = new int[qPtrs.length - 1]; for(i = 0, j = 0; i < qPtrs.length; ++i) if(i != readerNo) { newQPtrs[j] = qPtrs[i]; ++j; } codes = newCodes; subStreams = newSubStreams; qPtrs = newQPtrs; subReaderIds = newSubReaderIds; for(i = 0; i < subStreams.length; i++) if(subStreams[i].readerNo > readerNo) subStreams[i].readerNo--; } private boolean isSkipCall = false; /** * Read method of the SplitInputStream. * See the documentation of InputStream.read(..) for more information. This * reads from the underlying InputStream and buffers the data for use by the * subReaders. * @exception IOException If the underlying stream throws an IOException or * if the nextRead() call of a subReader throws an IOException */ public int read(byte b[], int off, int len) throws IOException { boolean isSkip = isSkipCall; isSkipCall = false; byte b1, b2; if(!isSkip) { if(len < 0) throw new IndexOutOfBoundsException("Negative Length Read attempted, len = " + len); b1 = b[off]; b2 = b[off + len -1]; } if(len <= 0) return 0; if(q == null) q = new byte[bufSize]; int remain = len; // Begin q.dequeue(in, 0, b, off, remain) int qReadSize = qEnd - qPtrs[0]; if(qReadSize > remain) qReadSize = remain; if(qReadSize > 0) { if(b != null) System.arraycopy(q, qPtrs[0], b, off, qReadSize); remain -= qReadSize; off += qReadSize; } // End q.dequeue(in, 0, b, off, remain) qPtrs[0] += len; requestBuf = b; requestPos = off; requestRemain = remain; int i, testPtr, indexArr[] = null; maxBufUsage = 0; while(requestRemain > 0 && (qPtrs.length > 1 || !eofFlag)) { if(indexArr == null) indexArr = new int[1]; int newQBegin = findQBegin(indexArr); int newQ2nd = 0x7FFFFFFF; int newQBeginIndex = indexArr[0], newQ2ndIndex = 0; if(qPtrs.length > 1) { i = 0; do { if(i != newQBeginIndex && (testPtr = qPtrs[i]) <= newQ2nd) { newQ2nd = testPtr; newQ2ndIndex = i; } ++i; } while(i < qPtrs.length); } if(newQBegin >= qEnd) { i = 0; if(eofFlag) // Wrapup do { IterativeReader reader = codes[0]; SubStream stream = subStreams[0]; curReaderId = subReaderIds[0]; reader.nextRead(stream.minReadSize); curReaderId = -1; if(!stream.closedFlag) detachSubReaderNo(0); } while(codes.length > 0); else { remain = requestRemain; requestRemain = 0; // Should be = qEnd. qPtrs[0] -= remain; qReadSize = bufSize; if(qReadSize > remain) qReadSize = remain; q2nd = newQBegin; qReadSize = fillAndDequeue(0, b, requestPos, qReadSize); requestPos += qReadSize; requestRemain = remain - qReadSize; if(!eofFlag) qPtrs[0] += requestRemain; } } else { q2nd = newQ2nd; int headStreamNo = newQBeginIndex - 1; IterativeReader headReader = codes[headStreamNo]; SubStream headStream = subStreams[headStreamNo]; int numBytes = qEnd - newQBegin - headStream.readCushion; SubStream nextStream = null; if(newQ2ndIndex > 0) nextStream = subStreams[newQ2ndIndex-1]; if(numBytes < headStream.minReadSize || newQ2ndIndex == 0 || (qEnd - newQ2nd - nextStream.readCushion) < nextStream.minReadSize) numBytes += bufSize - (qEnd - newQ2nd); curReaderId = subReaderIds[headStreamNo]; int readerStatus = headReader.nextRead(numBytes); curReaderId = -1; if(!headStream.closedFlag && (readerStatus != IterativeReader.CONTINUE)) detachSubReaderNo(headStreamNo); } } if(q.length > bufSize && maxBufUsage > 0 && q.length - maxBufUsage >= incSize) { int resizeLen = bufSize; if(maxBufUsage > bufSize) resizeLen = maxBufUsage + (incSize - 1 - (maxBufUsage - 1 - bufSize)%incSize); reallocBuf(resizeLen); } int retVal = len - requestRemain; requestBuf = null; requestRemain = 0; if(retVal == 0) retVal = -1; return retVal; } /** * Read method of the SplitInputStream. * See the documentation of InputStream.read(..) for more information. This * reads from the underlying InputStream and buffers the data for use by the * subReaders. * @exception IOException If the underlying stream throws an IOException or * if the nextRead() call of a subReader throws an IOException */ public int read() throws IOException { int retVal = -1; if(read(oneByteArr, 0, 1) == 1) retVal = oneByteArr[0] & 255; return retVal; } /** * Skip method of the SplitInputStream. * See the documentation of InputStream.skip(..) for more information. This * skips from the underlying InputStream and buffers the data for use by the * subReaders. * @exception IOException If the underlying stream throws an IOException or * if the nextRead() call of a subReader throws an IOException */ public long skip(long n) throws IOException { long retVal = n; if(retVal < 0) retVal = 0; if(retVal > 0) { isSkipCall = true; retVal = read(null, 0, (int)retVal); if(retVal < 0) retVal = 0; } return retVal; } /** * Available method of the SplitInputStream. * See the documentation of InputStream.available(..) for more information. * This method does not strictly conform to InputStream spec since it always * returns atleast 1 unless the end of file is reached. */ public int available() { int retVal = qEnd - qPtrs[0]; if(retVal <= 0) retVal = eofFlag?0:1; return retVal; } /** * Returns the max bufSize. For debugging and informational purposes. * @return Max Buf Size */ public int getMaxBufSize() { return maxBufSize; } /** * This should be called when the Main Object (Say ImageReader) has finished * reading. This is to ensure that all the SubReaders finish reading any * data left in the buffer/mainStream and detach. */ public void wrapup() throws IOException { int readerNo; while(codes.length > 0) skip(100000); q = null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy