KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > servlet > multipart > TokenStream


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.servlet.multipart;
17
18 import java.io.IOException JavaDoc;
19 import java.io.PushbackInputStream JavaDoc;
20
21 /**
22  * Utility class for MultipartParser. Divides the inputstream into parts
23  * separated by a given boundary.
24  *
25  * A newline is espected after each boundary and is parsed away.
26  * @author <a HREF="mailto:j.tervoorde@home.nl">Jeroen ter Voorde</a>
27  * @version CVS $Id: TokenStream.java 30932 2004-07-29 17:35:38Z vgritsenko $
28  */

29 class TokenStream extends PushbackInputStream JavaDoc {
30
31     /**
32      * Initial state, no boundary has been set.
33      */

34     public static final int STATE_NOBOUNDARY = -1;
35
36     /**
37      * Fully read a part, now at the beginning of a new part
38      */

39     public static final int STATE_NEXTPART = -2;
40
41     /**
42      * Read last boundary, end of multipart block
43      */

44     public static final int STATE_ENDMULTIPART = -3;
45
46     /**
47      * End of stream, this should not happen
48      */

49     public static final int STATE_ENDOFSTREAM = -4;
50
51     /**
52      * Currently reading a part
53      */

54     public static final int STATE_READING = -5;
55
56     /** Field in */
57     private PushbackInputStream JavaDoc in = null;
58
59     /** Field boundary */
60     private byte[] boundary = null;
61
62     /** Field state */
63     private int state = STATE_NOBOUNDARY;
64
65     /**
66      * Creates a new pushback token stream from in.
67      *
68      * @param in The input stream
69      */

70     public TokenStream(PushbackInputStream JavaDoc in) {
71         this(in,1);
72     }
73     
74     /**
75      * Creates a new pushback token stream from in.
76      *
77      * @param in The input stream
78      * @param size Size (in bytes) of the pushback buffer
79      */

80     public TokenStream(PushbackInputStream JavaDoc in, int size) {
81         super(in,size);
82         this.in = in;
83     }
84
85     /**
86      * Sets the boundary to scan for
87      *
88      * @param boundary A byte array containg the boundary
89      *
90      * @throws MultipartException
91      */

92     public void setBoundary(byte[] boundary) throws MultipartException {
93         this.boundary = boundary;
94         if (state == STATE_NOBOUNDARY) {
95             state = STATE_READING;
96         }
97     }
98
99     /**
100      * Start reading the next part in the stream. This method may only be called
101      * if state is STATE_NEXTPART. It will throw a MultipartException if not.
102      *
103      * @throws MultipartException
104      */

105     public void nextPart() throws MultipartException {
106         if (state != STATE_NEXTPART) {
107             throw new MultipartException("Illegal state");
108         }
109         state = STATE_READING;
110     }
111
112     /**
113      * Return the stream state
114      *
115      * @return
116      */

117     public int getState() {
118         return state;
119     }
120
121     /**
122      * Fill the ouput buffer until either it's full, the boundary has been reached or
123      * the end of the inputstream has been reached.
124      * When a boundary is reached it is entirely read away including trailing \r's and \n's.
125      * It will not be written to the output buffer.
126      * The stream state is updated after each call.
127      *
128      * @param out The output buffer
129      *
130      * @return
131      *
132      * @throws IOException
133      */

134     private int readToBoundary(byte[] out) throws IOException JavaDoc {
135         if (state != STATE_READING) {
136             return 0;
137         }
138         int boundaryIndex = 0;
139         int written = 0;
140         int b = in.read();
141
142         while (true) {
143             while ((byte) b != boundary[0]) {
144                 if (b == -1) {
145                     state = STATE_ENDOFSTREAM;
146                     return written;
147                 }
148                 out[written++] = (byte) b;
149
150                 if (written == out.length) {
151                     return written;
152                 }
153                 b = in.read();
154             }
155             boundaryIndex = 0; // we know the first byte matched
156
// check for boundary
157
while ((boundaryIndex < boundary.length)
158                     && ((byte) b == boundary[boundaryIndex])) {
159                 b = in.read();
160                 boundaryIndex++;
161             }
162
163             if (boundaryIndex == boundary.length) { // matched boundary
164
if (b != -1) {
165                     if (b == '\r') { // newline, another part follows
166
state = STATE_NEXTPART;
167                         in.read();
168                     } else if (b == '-') { // hyphen, end of multipart
169
state = STATE_ENDMULTIPART;
170                         in.read(); // read next hyphen
171
in.read(); // read \r
172
in.read(); // read \n
173
} else { // something else, error
174
throw new IOException JavaDoc(
175                                 "Unexpected character after boundary");
176                     }
177                 } else { // nothing after boundary, this shouldn't happen either
178
state = STATE_ENDOFSTREAM;
179                 }
180                 return written;
181             } else { // did not match boundary
182
// bytes skipped, write first skipped byte, push back the rest
183
if (b != -1) { // b may be -1
184
in.unread(b); // the non-matching byte
185
}
186                 in.unread(boundary, 1,
187                         boundaryIndex - 1); // unread skipped boundary data
188
out[written++] = boundary[0];
189                 if (written == out.length) {
190                     return written;
191                 }
192             }
193             b = in.read();
194         }
195     }
196
197     /**
198      * @see java.io.InputStream#read(byte[])
199      *
200      * @param out
201      *
202      * @return
203      *
204      * @throws IOException
205      */

206     public int read(byte[] out) throws IOException JavaDoc {
207         if (state != STATE_READING) {
208             return 0;
209         }
210         return readToBoundary(out);
211     }
212
213     /**
214      * @see java.io.InputStream#read(byte[],int,int)
215      *
216      * @param out
217      * @param off
218      * @param len
219      *
220      * @return
221      *
222      * @throws IOException
223      */

224     public int read(byte[] out, int off, int len) throws IOException JavaDoc {
225         if ((off < 0) || (off >= out.length)) {
226             throw new IOException JavaDoc("Buffer offset outside buffer");
227         }
228         if (off + len >= out.length) {
229             throw new IOException JavaDoc("Buffer end outside buffer");
230         }
231         if (len < 0) {
232             throw new IOException JavaDoc("Length must be a positive integer");
233         }
234         byte[] buf = new byte[len];
235         int read = read(buf);
236         if (read > 0) {
237             System.arraycopy(buf, 0, out, off, read);
238         }
239         return read;
240     }
241
242     /**
243      * @see java.io.InputStream#read()
244      *
245      * @return
246      *
247      * @throws IOException
248      */

249     public int read() throws IOException JavaDoc {
250         byte[] buf = new byte[1];
251         int read = read(buf);
252
253         if (read == 0) {
254             return -1;
255         } else {
256             return buf[0];
257         }
258     }
259 }
260
Popular Tags