KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > struts > upload > MultipartValueStream


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

18
19 package org.apache.struts.upload;
20
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23
24 import javax.servlet.ServletException JavaDoc;
25
26 /**
27  * This class implements an inputStream that reads another stream until
28  * a multipart boundary is found. The class reports eof when boundary found.
29  * The undelying stream is not closed.
30  *
31  * <p>
32  * See RFC 1867 (http://info.internet.isi.edu:80/in-notes/rfc/files/rfc1867.txt)
33  * for details about the protocol.
34  * <p>
35  *
36  *
37  * @deprecated Use the Commons FileUpload based multipart handler instead. This
38  * class will be removed after Struts 1.2.
39  */

40
41 class MultipartValueStream extends InputStream JavaDoc {
42
43     public static final String JavaDoc HEADER_ENCODING = "iso-8859-1";
44
45     /** the underlying stream */
46     private InputStream JavaDoc in;
47     
48     /** byte buffer with the boundary */
49     private byte boundaryBytes[];
50
51     /** how many curretly matched boundary bytes? */
52     private int matchedBoundaryBytes;
53
54     /** the read ahead buffer (cyclic) */
55     private byte readAheadBytes[];
56
57     /** The start index for the read ahead cyclic buffer (points to the first byte) */
58     private int readAheadBufferStartI;
59
60     /** The end index for the read ahead cyclic buffer (points to the last byte) */
61     private int readAheadBufferEndI;
62
63     /** have we reached the boundary? */
64     private boolean boundaryReached = false;
65
66     /** is the boundary found a final boundary? */
67     private boolean finalBoundaryReached = false;
68
69
70     /**
71      * Create a stream that stops reading at the boundary
72      *
73      * NOTE: the boundary parameter is without the trailing dashes "--".
74      */

75     public MultipartValueStream(InputStream JavaDoc in, String JavaDoc boundary)
76     throws IOException JavaDoc
77     {
78     this.in = in;
79     this.boundaryBytes = ("\r\n" + boundary).getBytes(HEADER_ENCODING);
80     this.matchedBoundaryBytes = 0;
81     this.readAheadBytes = new byte[this.boundaryBytes.length];
82
83     /* Fill read ahead buffer */
84     if (in.read(readAheadBytes, 0, readAheadBytes.length) != readAheadBytes.length) {
85         throw new IOException JavaDoc("end of stream before boundary found!");
86     }
87
88     /* Count the number of matched chars */
89     for (int i = 0; i < readAheadBytes.length; i++) {
90         if (readAheadBytes[i] == boundaryBytes[matchedBoundaryBytes]) {
91         matchedBoundaryBytes++;
92         } else {
93         matchedBoundaryBytes = 0;
94         if (readAheadBytes[i] == boundaryBytes[0]) {
95             matchedBoundaryBytes = 1;
96         }
97         }
98     }
99
100     readAheadBufferStartI = 0;
101     readAheadBufferEndI = readAheadBytes.length - 1;
102     }
103     
104     
105     /**
106      * Read the next byte
107      *
108      * @return -1 on boundary reached
109      * @exception IOException if the ending boundary is never found
110      *
111      */

112
113     public int read() throws IOException JavaDoc {
114     if (boundaryReached) {
115         return -1;
116     }
117     if (matchedBoundaryBytes == boundaryBytes.length) {
118
119         boundaryReached = true;
120
121         /*
122          * Boundary found...
123          *
124          * Read two more bytes:
125          * 1. the bytes are "--": this is the last parameter value (then read "\r\n" too)
126          * 2. the bytes are "\r\n": this is not the last value
127          * 3. the bytes are somthing else: Exception
128          */

129
130         byte buf[] = new byte[2];
131         if (in.read(buf) != 2) {
132         throw new IOException JavaDoc("end of stream before boundary found!");
133         }
134
135         String JavaDoc readStr = new String JavaDoc(buf, HEADER_ENCODING);
136         if (readStr.equals("--")) {
137
138         if (in.read(buf) != 2) {
139             throw new IOException JavaDoc("invalid end of final boundary found!");
140         }
141         readStr = new String JavaDoc(buf, HEADER_ENCODING);
142         if (!readStr.equals("\r\n")) {
143             throw new IOException JavaDoc("invalid end of final boundary found!");
144         }
145         finalBoundaryReached = true;
146
147         } else if (readStr.equals("\r\n")) {
148         finalBoundaryReached = false;
149         } else {
150         throw new IOException JavaDoc("invalid end of boundary found!");
151         }
152
153         return -1;
154     }
155     
156     /*
157      * Might seem odd, but we are supposed to return
158      * a byte as an int in range 0 - 255, and the byte type
159      * is signed (-128 to 127)
160      *
161      */

162     int returnByte = (int)(char) readAheadBytes[readAheadBufferStartI];
163
164     /* Move cyclic-buffers start pointer */
165     readAheadBufferStartI++;
166     if (readAheadBufferStartI == readAheadBytes.length) {
167         readAheadBufferStartI = 0;
168     }
169
170     /* read from the underlying stream */
171     int underlyingRead = in.read();
172     if (underlyingRead == -1) {
173         throw new IOException JavaDoc("end of stream before boundary found!");
174     }
175
176     /* Move cyclic-buffers end pointer */
177     readAheadBufferEndI++;
178     if (readAheadBufferEndI == readAheadBytes.length) {
179         readAheadBufferEndI = 0;
180     }
181     readAheadBytes[readAheadBufferEndI] = (byte) underlyingRead;
182
183     if (readAheadBytes[readAheadBufferEndI] == boundaryBytes[matchedBoundaryBytes]) {
184         matchedBoundaryBytes++;
185     } else {
186         matchedBoundaryBytes = 0;
187             if (readAheadBytes[readAheadBufferEndI] == boundaryBytes[0]) {
188         matchedBoundaryBytes = 1;
189         }
190     }
191     return returnByte;
192     }
193
194     /**
195      * @return true if we are the last stream, ie. we encountered a final boundary
196      * @return false otherwise
197      *
198      * @exception ServletException if the boundary has not yet been reached
199      */

200
201     public boolean encounteredFinalBoundary()
202     throws ServletException JavaDoc
203     {
204     if (!boundaryReached) {
205         throw new ServletException JavaDoc("have not reached boundary yet!");
206     }
207     return finalBoundaryReached;
208     }
209 }
210
Popular Tags