KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tomcat > util > buf > UDecoder


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You 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 implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.tomcat.util.buf;
19
20 import java.io.CharConversionException JavaDoc;
21 import java.io.IOException JavaDoc;
22
23 /**
24  * All URL decoding happens here. This way we can reuse, review, optimize
25  * without adding complexity to the buffers.
26  *
27  * The conversion will modify the original buffer.
28  *
29  * @author Costin Manolache
30  */

31 public final class UDecoder {
32     
33     private static org.apache.commons.logging.Log log=
34         org.apache.commons.logging.LogFactory.getLog(UDecoder.class );
35     
36     public UDecoder()
37     {
38     }
39
40     /** URLDecode, will modify the source. Includes converting
41      * '+' to ' '.
42      */

43     public void convert( ByteChunk mb )
44         throws IOException JavaDoc
45     {
46         convert(mb, true);
47     }
48
49     /** URLDecode, will modify the source.
50      */

51     public void convert( ByteChunk mb, boolean query )
52     throws IOException JavaDoc
53     {
54     int start=mb.getOffset();
55     byte buff[]=mb.getBytes();
56     int end=mb.getEnd();
57
58     int idx= ByteChunk.indexOf( buff, start, end, '%' );
59         int idx2=-1;
60         if( query )
61             idx2= ByteChunk.indexOf( buff, start, end, '+' );
62     if( idx<0 && idx2<0 ) {
63         return;
64     }
65
66     // idx will be the smallest positive inxes ( first % or + )
67
if( idx2 >= 0 && idx2 < idx ) idx=idx2;
68     if( idx < 0 ) idx=idx2;
69
70     for( int j=idx; j<end; j++, idx++ ) {
71         if( buff[ j ] == '+' && query) {
72         buff[idx]= (byte)' ' ;
73         } else if( buff[ j ] != '%' ) {
74         buff[idx]= buff[j];
75         } else {
76         // read next 2 digits
77
if( j+2 >= end ) {
78             throw new CharConversionException JavaDoc("EOF");
79         }
80         byte b1= buff[j+1];
81         byte b2=buff[j+2];
82         if( !isHexDigit( b1 ) || ! isHexDigit(b2 ))
83             throw new CharConversionException JavaDoc( "isHexDigit");
84         
85         j+=2;
86         int res=x2c( b1, b2 );
87         buff[idx]=(byte)res;
88         }
89     }
90
91     mb.setEnd( idx );
92     
93     return;
94     }
95
96     // -------------------- Additional methods --------------------
97
// XXX What do we do about charset ????
98

99     /** In-buffer processing - the buffer will be modified
100      * Includes converting '+' to ' '.
101      */

102     public void convert( CharChunk mb )
103     throws IOException JavaDoc
104     {
105         convert(mb, true);
106     }
107
108     /** In-buffer processing - the buffer will be modified
109      */

110     public void convert( CharChunk mb, boolean query )
111     throws IOException JavaDoc
112     {
113     // log( "Converting a char chunk ");
114
int start=mb.getOffset();
115     char buff[]=mb.getBuffer();
116     int cend=mb.getEnd();
117
118     int idx= CharChunk.indexOf( buff, start, cend, '%' );
119         int idx2=-1;
120         if( query )
121             idx2= CharChunk.indexOf( buff, start, cend, '+' );
122     if( idx<0 && idx2<0 ) {
123         return;
124     }
125     
126     if( idx2 >= 0 && idx2 < idx ) idx=idx2;
127     if( idx < 0 ) idx=idx2;
128
129     for( int j=idx; j<cend; j++, idx++ ) {
130         if( buff[ j ] == '+' && query ) {
131         buff[idx]=( ' ' );
132         } else if( buff[ j ] != '%' ) {
133         buff[idx]=buff[j];
134         } else {
135         // read next 2 digits
136
if( j+2 >= cend ) {
137             // invalid
138
throw new CharConversionException JavaDoc("EOF");
139         }
140         char b1= buff[j+1];
141         char b2=buff[j+2];
142         if( !isHexDigit( b1 ) || ! isHexDigit(b2 ))
143             throw new CharConversionException JavaDoc("isHexDigit");
144         
145         j+=2;
146         int res=x2c( b1, b2 );
147         buff[idx]=(char)res;
148         }
149     }
150     mb.setEnd( idx );
151     }
152
153     /** URLDecode, will modify the source
154      * Includes converting '+' to ' '.
155      */

156     public void convert(MessageBytes mb)
157     throws IOException JavaDoc
158     {
159         convert(mb, true);
160     }
161
162     /** URLDecode, will modify the source
163      */

164     public void convert(MessageBytes mb, boolean query)
165     throws IOException JavaDoc
166     {
167     
168     switch (mb.getType()) {
169     case MessageBytes.T_STR:
170         String JavaDoc strValue=mb.toString();
171         if( strValue==null ) return;
172         mb.setString( convert( strValue, query ));
173         break;
174     case MessageBytes.T_CHARS:
175         CharChunk charC=mb.getCharChunk();
176         convert( charC, query );
177         break;
178     case MessageBytes.T_BYTES:
179         ByteChunk bytesC=mb.getByteChunk();
180         convert( bytesC, query );
181         break;
182     }
183     }
184
185     // XXX Old code, needs to be replaced !!!!
186
//
187
public final String JavaDoc convert(String JavaDoc str)
188     {
189         return convert(str, true);
190     }
191
192     public final String JavaDoc convert(String JavaDoc str, boolean query)
193     {
194         if (str == null) return null;
195     
196     if( (!query || str.indexOf( '+' ) < 0) && str.indexOf( '%' ) < 0 )
197         return str;
198     
199         StringBuffer JavaDoc dec = new StringBuffer JavaDoc(); // decoded string output
200
int strPos = 0;
201         int strLen = str.length();
202
203         dec.ensureCapacity(str.length());
204         while (strPos < strLen) {
205             int laPos; // lookahead position
206

207             // look ahead to next URLencoded metacharacter, if any
208
for (laPos = strPos; laPos < strLen; laPos++) {
209                 char laChar = str.charAt(laPos);
210                 if ((laChar == '+' && query) || (laChar == '%')) {
211                     break;
212                 }
213             }
214
215             // if there were non-metacharacters, copy them all as a block
216
if (laPos > strPos) {
217                 dec.append(str.substring(strPos,laPos));
218                 strPos = laPos;
219             }
220
221             // shortcut out of here if we're at the end of the string
222
if (strPos >= strLen) {
223                 break;
224             }
225
226             // process next metacharacter
227
char metaChar = str.charAt(strPos);
228             if (metaChar == '+') {
229                 dec.append(' ');
230                 strPos++;
231                 continue;
232             } else if (metaChar == '%') {
233         // We throw the original exception - the super will deal with
234
// it
235
// try {
236
dec.append((char)Integer.
237                parseInt(str.substring(strPos + 1, strPos + 3),16));
238                 strPos += 3;
239             }
240         }
241
242         return dec.toString();
243     }
244
245
246
247     private static boolean isHexDigit( int c ) {
248     return ( ( c>='0' && c<='9' ) ||
249          ( c>='a' && c<='f' ) ||
250          ( c>='A' && c<='F' ));
251     }
252     
253     private static int x2c( byte b1, byte b2 ) {
254     int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 :
255         (b1 -'0');
256     digit*=16;
257     digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 :
258         (b2 -'0');
259     return digit;
260     }
261
262     private static int x2c( char b1, char b2 ) {
263     int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 :
264         (b1 -'0');
265     digit*=16;
266     digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 :
267         (b2 -'0');
268     return digit;
269     }
270
271     private final static int debug=0;
272     private static void log( String JavaDoc s ) {
273         if (log.isDebugEnabled())
274             log.debug("URLDecoder: " + s );
275     }
276
277 }
278
Popular Tags