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