001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse.util;
004:
005: import java.io.*;
006:
007: public class StreamReader {
008: private InputStream input;
009:
010: private State state;
011:
012: ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
013:
014: OutputStream output;
015:
016: int readGoal;
017:
018: int readStatus;
019:
020: boolean eof = false;
021:
022: byte[] boundary;
023:
024: int boundaryLength;
025:
026: int matchingBoundaryIndex;
027:
028: byte[] matchedBoundaryBytes;
029:
030: long bytesConsumed;
031:
032: public StreamReader(InputStream input) {
033: this .input = input;
034: }
035:
036: public void close() throws Exception {
037: input.close();
038: }
039:
040: public String readLine() throws Exception {
041: return bytesToString(readLineBytes());
042: }
043:
044: public byte[] readLineBytes() throws Exception {
045: state = READLINE_STATE;
046: return preformRead();
047: }
048:
049: public String read(int count) throws Exception {
050: return bytesToString(readBytes(count));
051: }
052:
053: public byte[] readBytes(int count) throws Exception {
054: readGoal = count;
055: readStatus = 0;
056: state = READCOUNT_STATE;
057: return preformRead();
058: }
059:
060: public void copyBytes(int count, OutputStream output)
061: throws Exception {
062: readGoal = count;
063: state = READCOUNT_STATE;
064: performCopy(output);
065: }
066:
067: public String readUpTo(String boundary) throws Exception {
068: return bytesToString(readBytesUpTo(boundary));
069: }
070:
071: public byte[] readBytesUpTo(String boundary) throws Exception {
072: prepareForReadUpTo(boundary);
073: return preformRead();
074: }
075:
076: private void prepareForReadUpTo(String boundary) {
077: this .boundary = boundary.getBytes();
078: boundaryLength = this .boundary.length;
079: matchedBoundaryBytes = new byte[boundaryLength];
080: matchingBoundaryIndex = 0;
081: state = READUPTO_STATE;
082: }
083:
084: public void copyBytesUpTo(String boundary, OutputStream outputStream)
085: throws Exception {
086: prepareForReadUpTo(boundary);
087: performCopy(outputStream);
088: }
089:
090: public int byteCount() {
091: return byteBuffer.size();
092: }
093:
094: public byte[] getBufferedBytes() {
095: return byteBuffer.toByteArray();
096: }
097:
098: private byte[] preformRead() throws Exception {
099: setReadMode();
100: clearBuffer();
101: readUntilFinished();
102: return getBufferedBytes();
103: }
104:
105: private void performCopy(OutputStream output) throws Exception {
106: setCopyMode(output);
107: readUntilFinished();
108: }
109:
110: private void readUntilFinished() throws Exception {
111: while (!state.finished())
112: state.read(input);
113: }
114:
115: private void clearBuffer() {
116: byteBuffer.reset();
117: }
118:
119: private void setCopyMode(OutputStream output) {
120: this .output = output;
121: }
122:
123: private void setReadMode() {
124: output = byteBuffer;
125: }
126:
127: private String bytesToString(byte[] bytes) throws Exception {
128: return new String(bytes, "UTF-8");
129: }
130:
131: void changeState(State state) {
132: this .state = state;
133: }
134:
135: public boolean isEof() {
136: return eof;
137: }
138:
139: public long numberOfBytesConsumed() {
140: return bytesConsumed;
141: }
142:
143: public void resetNumberOfBytesConsumed() {
144: bytesConsumed = 0;
145: }
146:
147: static abstract class State {
148: public void read(InputStream input) throws Exception {
149: }
150:
151: public boolean finished() {
152: return false;
153: }
154: }
155:
156: private final State READLINE_STATE = new State() {
157: public void read(InputStream input) throws Exception {
158: int b = input.read();
159: if (b == -1) {
160: changeState(FINAL_STATE);
161: eof = true;
162: } else {
163: bytesConsumed++;
164: if (b == '\n')
165: changeState(FINAL_STATE);
166: else if (b != '\r')
167: output.write((byte) b);
168: }
169: }
170: };
171:
172: private final State READCOUNT_STATE = new State() {
173: public void read(InputStream input) throws Exception {
174: byte[] bytes = new byte[readGoal - readStatus];
175: int bytesRead = input.read(bytes);
176:
177: if (bytesRead < 0) {
178: changeState(FINAL_STATE);
179: eof = true;
180: } else {
181: bytesConsumed += bytesRead;
182: readStatus += bytesRead;
183: output.write(bytes, 0, bytesRead);
184: }
185: }
186:
187: public boolean finished() {
188: return readStatus >= readGoal;
189: }
190: };
191:
192: private final State READUPTO_STATE = new State() {
193: public void read(InputStream input) throws Exception {
194: int b = input.read();
195: if (b == -1) {
196: changeState(FINAL_STATE);
197: eof = true;
198: } else {
199: bytesConsumed++;
200: if (b == boundary[matchingBoundaryIndex]) {
201: matchedBoundaryBytes[matchingBoundaryIndex++] = (byte) b;
202: if (matchingBoundaryIndex >= boundaryLength)
203: changeState(FINAL_STATE);
204: } else if (matchingBoundaryIndex == 0)
205: output.write((byte) b);
206: else {
207: output.write(matchedBoundaryBytes, 0,
208: matchingBoundaryIndex);
209: matchingBoundaryIndex = 0;
210: if (b == boundary[matchingBoundaryIndex])
211: matchedBoundaryBytes[matchingBoundaryIndex++] = (byte) b;
212: else
213: output.write((byte) b);
214: }
215: }
216: }
217: };
218:
219: public final State FINAL_STATE = new State() {
220: public boolean finished() {
221: return true;
222: }
223: };
224: }
|