001: package com.quadcap.io;
002:
003: /* Copyright 1997 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.*;
042:
043: import com.quadcap.util.Debug;
044: import com.quadcap.util.Util;
045:
046: /**
047: * A filter input stream that performs dot-unstuffing.
048: *
049: * @author Stan Bailes
050: */
051:
052: public class DotStuffInputStream extends InputStream {
053: InputStream in;
054:
055: static final byte CR = (byte) '\r';
056: static final byte LF = (byte) '\n';
057: static final byte DT = (byte) '.';
058:
059: static final int INIT = 0;
060: static final int END = 1;
061: static final int S1 = 2;
062: static final int S2 = 3;
063: static final int S3 = 4;
064: static final int S4 = 5;
065:
066: int state = INIT;
067: int savec = -1;
068:
069: public DotStuffInputStream(InputStream in) throws IOException {
070: this .in = in;
071: }
072:
073: /**
074: * Reads the next byte of data from this input stream. The value
075: * byte is returned as an <code>int</code> in the range
076: * <code>0</code> to <code>255</code>. If no byte is available
077: * because the end of the stream has been reached, the value
078: * <code>-1</code> is returned. This method blocks until input data
079: * is available, the end of the stream is detected, or an exception
080: * is thrown.
081: * <p>
082: * The <code>read</code> method of <code>DotStuffInputStream</code>
083: * returns -1 when the characteristic 'single dot on a line by itself'
084: * end signature, and removes all leading dots otherwise.
085: *
086: * @return the next byte of data, or <code>-1</code> if the end of the
087: * stream is reached.
088: * @exception IOException if an I/O error occurs.
089: */
090: public int read() throws IOException {
091: int c = savec;
092: if (savec >= 0) {
093: savec = -1;
094: return c;
095: }
096:
097: while (state != END) {
098: c = in.read();
099: switch (state) {
100: case INIT: // at beginning of line
101: switch (c) {
102: case DT:
103: state = S1;
104: break;
105: case CR:
106: state = S3;
107: return CR;
108: case LF:
109: return LF; // state still INIT
110: default:
111: state = S4;
112: return c;
113: }
114: break;
115: case S1: // seen leading DT
116: switch (c) {
117: case LF:
118: state = END;
119: break;
120: case CR:
121: state = S2;
122: break;
123: default:
124: state = S4;
125: return c;
126: }
127: break;
128: case S2: // seen DT, CR. Better have LF next.
129: switch (c) {
130: case LF:
131: state = END;
132: break;
133: case CR:
134: state = S3;
135: return CR;
136: default:
137: state = S4;
138: return c;
139: }
140: break;
141: case S3: // seen CR
142: state = (c == LF) ? INIT : S4;
143: return c;
144: case S4: // just chugging along
145: switch (c) {
146: case CR:
147: state = S3;
148: return CR;
149: case LF:
150: state = INIT;
151: return LF;
152: default:
153: return c;
154: }
155: }
156: }
157: return -1;
158: }
159:
160: /**
161: * Reads up to <code>len</code> bytes of data from this input stream
162: * into an array of bytes. This method blocks until some input is
163: * available.
164: *
165: * @param b the buffer into which the data is read.
166: * @param off the start offset of the data.
167: * @param len the maximum number of bytes read.
168: * @return the total number of bytes read into the buffer, or
169: * <code>-1</code> if there is no more data because the end of
170: * the stream has been reached.
171: * @exception IOException if an I/O error occurs.
172: */
173: public int read(byte b[], int off, int len) throws IOException {
174: int cnt = 0;
175: int c;
176: while (cnt < len && (c = read()) >= 0) {
177: b[off + cnt++] = (byte) c;
178: }
179: return cnt;
180: }
181:
182: /**
183: * Skips over and discards <code>n</code> bytes of data from the
184: * input stream. The <code>skip</code> method may, for a variety of
185: * reasons, end up skipping over some smaller number of bytes,
186: * possibly <code>0</code>. The actual number of bytes skipped is
187: * returned.
188: *
189: * @param n the number of bytes to be skipped.
190: * @return the actual number of bytes skipped.
191: * @exception IOException if an I/O error occurs.
192: */
193: public long skip(long n) throws IOException {
194: int cnt = 0;
195: while (cnt < n && read() >= 0)
196: cnt++;
197: return cnt;
198: }
199:
200: }
|