throws IOException {
byte buffer[] = new byte[4096];
int len = in.read(buffer);
- while (len > 0) {
+ while (len > -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
buffer2 = Arrays.copyOf(buffer, buffer.length * 2);
pos2 = buffer.length;
- len2 = in.read(buffer2, pos2, buffer.length);
+ len2 = read(in, buffer2, pos2, buffer.length);
if (len2 > 0) {
bytesRead += len2;
}
* process).
*
* @return TRUE if it is
+ *
+ * @throws IOException
+ * in case of I/O error
*/
- public boolean eof() {
- return closed || (stop < 0 && !hasMoreData());
+ public boolean eof() throws IOException {
+ if (closed) {
+ return true;
+ }
+
+ preRead();
+ return !hasMoreData();
}
@Override
*/
protected boolean preRead() throws IOException {
boolean hasRead = false;
- if (!eof && in != null && start >= stop) {
+ if (in != null && !eof && start >= stop) {
start = 0;
if (buffer2 != null) {
buffer = buffer2;
} else {
buffer = originalBuffer;
- stop = read(in, buffer);
+ stop = read(in, buffer, 0, buffer.length);
if (stop > 0) {
bytesRead += stop;
}
* 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) throws IOException {
- return in.read(buffer);
+ 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 fetch more.
+ * We have more data available in the buffer <b>or</b> we can, maybe, fetch
+ * more.
*
* @return TRUE if it is the case, FALSE if not
*/
protected boolean hasMoreData() {
- return !closed && !(eof && start >= stop);
+ if (closed) {
+ return false;
+ }
+
+ return (start < stop) || !eof;
}
/**
* in case of I/O error
*/
protected void flush(boolean includingSubStream) throws IOException {
- out.write(buffer, start, stop - start);
- bytesWritten += (stop - start);
+ if (stop > start) {
+ out.write(buffer, start, stop - start);
+ bytesWritten += (stop - start);
+ }
start = 0;
stop = 0;
* Check if this stream is totally spent (no more data to read or to
* process).
* <p>
- * Note: an empty stream that is still not started will return FALSE, as we
- * don't know yet if it is empty.
+ * Note: when the stream is divided into sub-streams, each sub-stream will
+ * report it is eof when emptied.
*
* @return TRUE if it is
+ *
+ * @throws IOException
+ * in case of I/O error
*/
@Override
- public boolean eof() {
+ public boolean eof() throws IOException {
return super.eof();
}
-
+
/**
* Check if we still have some data in the buffer and, if not, fetch some.
*
protected boolean preRead() throws IOException {
if (!stopped) {
boolean bufferChanged = super.preRead();
- checkBuffer(true);
+ checkBuffer(bufferChanged);
return bufferChanged;
}
* the {@link NextableInputStreamStep}
*/
private void checkBuffer(boolean newBuffer) {
- if (step != null && stop > 0) {
+ if (step != null && stop >= 0) {
if (newBuffer) {
step.clearBuffer();
}
- int stopAt = step.stop(buffer, start, stop);
+ int stopAt = step.stop(buffer, start, stop, eof);
if (stopAt >= 0) {
stop = stopAt;
eof = true;
if (step != null && !hasMoreData() && stopped) {
stop = step.getResumeLen();
start += step.getResumeSkip();
- eof = false;
+ eof = step.getResumeEof();
+ stopped = false;
if (all) {
step = null;
}
- if (!preRead()) {
- checkBuffer(false);
- }
+ checkBuffer(false);
// consider that if EOF, there is no next
return hasMoreData();
*/
public class NextableInputStreamStep {
private int stopAt;
- private int resumeLen;
private int last = -1;
- private int skip;
+ private int resumeLen;
+ private int resumeSkip;
+ private boolean resumeEof;
/**
* Create a new divider that will separate the sub-streams each time it sees
* @param len
* the maximum index to use in the buffer (anything above that is
* not to be used)
+ * @param eof
+ * the current state of the under-laying stream
*
* @return the index at which to stop, or -1
*/
- public int stop(byte[] buffer, int pos, int len) {
+ public int stop(byte[] buffer, int pos, int len, boolean eof) {
for (int i = pos; i < len; i++) {
if (buffer[i] == stopAt) {
if (i > this.last) {
// we skip the sep
- this.skip = 1;
+ this.resumeSkip = 1;
this.resumeLen = len;
+ this.resumeEof = eof;
this.last = i;
return i;
}
/**
* Get the maximum index to use in the buffer used in
- * {@link NextableInputStreamStep#stop(byte[], int, int)} at resume time.
+ * {@link NextableInputStreamStep#stop(byte[], int, int, boolean)} at resume
+ * time.
*
* @return the index
*/
* @return the number of bytes to skip
*/
public int getResumeSkip() {
- return skip;
+ return resumeSkip;
+ }
+
+ /**
+ * Get the under-laying stream state at resume time.
+ *
+ * @return the EOF state
+ */
+ public boolean getResumeEof() {
+ return resumeEof;
}
/**
* Clear the information we may have kept about the current buffer
* <p>
* You should call this method each time you change the content of the
- * buffer used in {@link NextableInputStreamStep#stop(byte[], int, int)}.
+ * buffer used in
+ * {@link NextableInputStreamStep#stop(byte[], int, int, boolean)}.
*/
public void clearBuffer() {
this.last = -1;
- this.skip = 0;
+ this.resumeSkip = 0;
this.resumeLen = 0;
+ this.resumeEof = false;
}
}
}
@Override
- protected int read(InputStream in, byte[] buffer) throws IOException {
- if (buffer.length < maxToSize || source.length < maxToSize * 2) {
+ protected int read(InputStream in, byte[] buffer, int off, int len)
+ throws IOException {
+ if (len < maxToSize || source.length < maxToSize * 2) {
throw new IOException(
"An underlaying buffer is too small for these replace values");
}
// Note: very simple, not efficient implementation, sorry.
int count = 0;
- while (spos < slen && count < buffer.length - maxToSize) {
+ while (spos < slen && count < len - maxToSize) {
boolean replaced = false;
for (int i = 0; i < froms.length; i++) {
if (froms[i] != null && froms[i].length > 0
&& StreamUtils.startsWith(froms[i], source, spos, slen)) {
if (tos[i] != null && tos[i].length > 0) {
- System.arraycopy(tos[i], 0, buffer, spos, tos[i].length);
+ System.arraycopy(tos[i], 0, buffer, off + spos,
+ tos[i].length);
count += tos[i].length;
}
}
if (!replaced) {
- buffer[count++] = source[spos++];
+ buffer[off + count++] = source[spos++];
}
}