// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
public class StreamReader {
private InputStream input;
private State state;
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
OutputStream output;
private int readGoal;
private int readStatus;
private boolean eof = false;
private byte[] boundary;
private int boundaryLength;
private int matchingBoundaryIndex;
private byte[] matchedBoundaryBytes;
private long bytesConsumed;
public StreamReader(InputStream input) {
this.input = input;
}
public void close() throws IOException {
input.close();
}
public String readLine() throws IOException {
return bytesToString(readLineBytes());
}
public byte[] readLineBytes() throws IOException {
state = READLINE_STATE;
return preformRead();
}
public String read(int count) throws IOException {
return bytesToString(readBytes(count));
}
public byte[] readBytes(int count) throws IOException {
readGoal = count;
readStatus = 0;
state = READCOUNT_STATE;
return preformRead();
}
public void copyBytes(int count, OutputStream output) throws IOException {
readGoal = count;
state = READCOUNT_STATE;
performCopy(output);
}
public String readUpTo(String boundary) throws IOException {
return bytesToString(readBytesUpTo(boundary));
}
public byte[] readBytesUpTo(String boundary) throws IOException {
prepareForReadUpTo(boundary);
return preformRead();
}
private void prepareForReadUpTo(String boundary) {
this.boundary = boundary.getBytes();
boundaryLength = this.boundary.length;
matchedBoundaryBytes = new byte[boundaryLength];
matchingBoundaryIndex = 0;
state = READUPTO_STATE;
}
public void copyBytesUpTo(String boundary, OutputStream outputStream) throws IOException {
prepareForReadUpTo(boundary);
performCopy(outputStream);
}
public int byteCount() {
return byteBuffer.size();
}
public byte[] getBufferedBytes() {
return byteBuffer.toByteArray();
}
private byte[] preformRead() throws IOException {
setReadMode();
clearBuffer();
readUntilFinished();
return getBufferedBytes();
}
private void performCopy(OutputStream output) throws IOException {
setCopyMode(output);
readUntilFinished();
}
private void readUntilFinished() throws IOException {
while (!state.finished())
state.read(input);
}
private void clearBuffer() {
byteBuffer.reset();
}
private void setCopyMode(OutputStream output) {
this.output = output;
}
private void setReadMode() {
output = byteBuffer;
}
private String bytesToString(byte[] bytes) throws UnsupportedEncodingException {
return new String(bytes, "UTF-8");
}
private void changeState(State state) {
this.state = state;
}
public boolean isEof() {
return eof;
}
public long numberOfBytesConsumed() {
return bytesConsumed;
}
public void resetNumberOfBytesConsumed() {
bytesConsumed = 0;
}
private static abstract class State {
public void read(InputStream input) throws IOException {
}
public boolean finished() {
return false;
}
}
private final State READLINE_STATE = new State() {
public void read(InputStream input) throws IOException {
int b = input.read();
if (b == -1) {
changeState(FINAL_STATE);
eof = true;
} else {
bytesConsumed++;
if (b == '\n')
changeState(FINAL_STATE);
else if (b != '\r')
output.write((byte) b);
}
}
};
private final State READCOUNT_STATE = new State() {
public void read(InputStream input) throws IOException {
byte[] bytes = new byte[readGoal - readStatus];
int bytesRead = input.read(bytes);
if (bytesRead < 0) {
changeState(FINAL_STATE);
eof = true;
} else {
bytesConsumed += bytesRead;
readStatus += bytesRead;
output.write(bytes, 0, bytesRead);
}
}
public boolean finished() {
return readStatus >= readGoal;
}
};
private final State READUPTO_STATE = new State() {
public void read(InputStream input) throws IOException {
int b = input.read();
if (b == -1) {
changeState(FINAL_STATE);
eof = true;
} else {
bytesConsumed++;
if (b == boundary[matchingBoundaryIndex]) {
matchedBoundaryBytes[matchingBoundaryIndex++] = (byte) b;
if (matchingBoundaryIndex >= boundaryLength)
changeState(FINAL_STATE);
} else if (matchingBoundaryIndex == 0)
output.write((byte) b);
else {
output.write(matchedBoundaryBytes, 0, matchingBoundaryIndex);
matchingBoundaryIndex = 0;
if (b == boundary[matchingBoundaryIndex])
matchedBoundaryBytes[matchingBoundaryIndex++] = (byte) b;
else
output.write((byte) b);
}
}
}
};
private final State FINAL_STATE = new State() {
public boolean finished() {
return true;
}
};
}