1 /************************************************************************
2 * Copyright (c) 1999-2006 The Apache Software Foundation. *
3 * All rights reserved. *
4 * ------------------------------------------------------------------- *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you *
6 * may not use this file except in compliance with the License. You *
7 * may obtain a copy of the License at: *
8 * *
9 * http://www.apache.org/licenses/LICENSE-2.0 *
10 * *
11 * Unless required by applicable law or agreed to in writing, software *
12 * distributed under the License is distributed on an "AS IS" BASIS, *
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
14 * implied. See the License for the specific language governing *
15 * permissions and limitations under the License. *
16 ***********************************************************************/
17
18 package org.apache.james.util;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22
23 /***
24 * An InputStream class that terminates the stream when it encounters a
25 * particular byte sequence.
26 *
27 * @version 1.0.0, 24/04/1999
28 */
29 public class CharTerminatedInputStream
30 extends InputStream {
31
32 /***
33 * The wrapped input stream
34 */
35 private InputStream in;
36
37 /***
38 * The terminating character array
39 */
40 private int match[];
41
42 /***
43 * An array containing the last N characters read from the stream, where
44 * N is the length of the terminating character array
45 */
46 private int buffer[];
47
48 /***
49 * The number of bytes that have been read that have not been placed
50 * in the internal buffer.
51 */
52 private int pos = 0;
53
54 /***
55 * Whether the terminating sequence has been read from the stream
56 */
57 private boolean endFound = false;
58
59 /***
60 * A constructor for this object that takes a stream to be wrapped
61 * and a terminating character sequence.
62 *
63 * @param in the <code>InputStream</code> to be wrapped
64 * @param terminator the array of characters that will terminate the stream.
65 *
66 * @throws IllegalArgumentException if the terminator array is null or empty
67 */
68 public CharTerminatedInputStream(InputStream in, char[] terminator) {
69 if (terminator == null) {
70 throw new IllegalArgumentException("The terminating character array cannot be null.");
71 }
72 if (terminator.length == 0) {
73 throw new IllegalArgumentException("The terminating character array cannot be of zero length.");
74 }
75 match = new int[terminator.length];
76 buffer = new int[terminator.length];
77 for (int i = 0; i < terminator.length; i++) {
78 match[i] = (int)terminator[i];
79 buffer[i] = (int)terminator[i];
80 }
81 this.in = in;
82 }
83
84 /***
85 * Read a byte off this stream.
86 *
87 * @return the byte read off the stream
88 * @throws IOException if an IOException is encountered while reading off the stream
89 * @throws ProtocolException if the underlying stream returns -1 before the terminator is seen.
90 */
91 public int read() throws IOException {
92 if (endFound) {
93
94 return -1;
95 }
96 if (pos == 0) {
97
98 int b = in.read();
99 if (b == -1) {
100
101 throw new java.net.ProtocolException("pre-mature end of data");
102 }
103 if (b != match[0]) {
104
105 return b;
106 }
107
108
109 buffer[0] = b;
110 pos++;
111 } else {
112 if (buffer[0] != match[0]) {
113
114
115
116 return topChar();
117 }
118
119 }
120
121
122
123
124 for (int i = 0; i < match.length; i++) {
125 if (i >= pos) {
126 int b = in.read();
127 if (b == -1) {
128
129
130
131 return topChar();
132 }
133
134 buffer[pos] = b;
135 pos++;
136 }
137 if (buffer[i] != match[i]) {
138
139 return topChar();
140 }
141 }
142
143 endFound = true;
144 return -1;
145 }
146
147 /***
148 * Private helper method to update the internal buffer of last read characters
149 *
150 * @return the byte that was previously at the front of the internal buffer
151 */
152 private int topChar() {
153 int b = buffer[0];
154 if (pos > 1) {
155
156 System.arraycopy(buffer, 1, buffer, 0, pos - 1);
157 }
158 pos--;
159 return b;
160 }
161 }
162