comparison src/org/eclipse/jetty/util/UrlEncoded.java @ 1068:9d357b9e4bcb

fix BufferUtil.newBuffer()
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 10 Nov 2016 00:23:05 -0700
parents 8e9db0bbf4f9
children
comparison
equal deleted inserted replaced
1067:56b515be91e1 1068:9d357b9e4bcb
51 * 51 *
52 * @see java.net.URLEncoder 52 * @see java.net.URLEncoder
53 */ 53 */
54 public class UrlEncoded extends MultiMap implements Cloneable 54 public class UrlEncoded extends MultiMap implements Cloneable
55 { 55 {
56 private static final Logger LOG = LoggerFactory.getLogger(UrlEncoded.class); 56 private static final Logger LOG = LoggerFactory.getLogger(UrlEncoded.class);
57 57
58 public static final String ENCODING = System.getProperty("org.eclipse.jetty.util.UrlEncoding.charset",StringUtil.__UTF8); 58 public static final String ENCODING = System.getProperty("org.eclipse.jetty.util.UrlEncoding.charset",StringUtil.__UTF8);
59 59
60 /* ----------------------------------------------------------------- */ 60 /* ----------------------------------------------------------------- */
61 public UrlEncoded(UrlEncoded url) 61 public UrlEncoded(UrlEncoded url)
62 { 62 {
63 super(url); 63 super(url);
64 } 64 }
65 65
66 /* ----------------------------------------------------------------- */ 66 /* ----------------------------------------------------------------- */
67 public UrlEncoded() 67 public UrlEncoded()
68 { 68 {
69 super(6); 69 super(6);
70 } 70 }
71 71
72 /* ----------------------------------------------------------------- */ 72 /* ----------------------------------------------------------------- */
73 public UrlEncoded(String s) 73 public UrlEncoded(String s)
74 { 74 {
75 super(6); 75 super(6);
76 decode(s,ENCODING); 76 decode(s,ENCODING);
77 } 77 }
78 78
79 /* ----------------------------------------------------------------- */ 79 /* ----------------------------------------------------------------- */
80 public UrlEncoded(String s, String charset) 80 public UrlEncoded(String s, String charset)
81 { 81 {
82 super(6); 82 super(6);
83 decode(s,charset); 83 decode(s,charset);
84 } 84 }
85 85
86 /* ----------------------------------------------------------------- */ 86 /* ----------------------------------------------------------------- */
87 public void decode(String query) 87 public void decode(String query)
88 { 88 {
89 decodeTo(query,this,ENCODING,-1); 89 decodeTo(query,this,ENCODING,-1);
90 } 90 }
91 91
92 /* ----------------------------------------------------------------- */ 92 /* ----------------------------------------------------------------- */
93 public void decode(String query,String charset) 93 public void decode(String query,String charset)
94 { 94 {
95 decodeTo(query,this,charset,-1); 95 decodeTo(query,this,charset,-1);
96 } 96 }
97 97
98 /* -------------------------------------------------------------- */ 98 /* -------------------------------------------------------------- */
99 /** Encode Hashtable with % encoding. 99 /** Encode Hashtable with % encoding.
100 */ 100 */
101 public String encode() 101 public String encode()
102 { 102 {
103 return encode(ENCODING,false); 103 return encode(ENCODING,false);
104 } 104 }
105 105
106 /* -------------------------------------------------------------- */ 106 /* -------------------------------------------------------------- */
107 /** Encode Hashtable with % encoding. 107 /** Encode Hashtable with % encoding.
108 */ 108 */
109 public String encode(String charset) 109 public String encode(String charset)
110 { 110 {
111 return encode(charset,false); 111 return encode(charset,false);
112 } 112 }
113 113
114 /* -------------------------------------------------------------- */ 114 /* -------------------------------------------------------------- */
115 /** Encode Hashtable with % encoding. 115 /** Encode Hashtable with % encoding.
116 * @param equalsForNullValue if True, then an '=' is always used, even 116 * @param equalsForNullValue if True, then an '=' is always used, even
117 * for parameters without a value. e.g. "blah?a=&b=&c=". 117 * for parameters without a value. e.g. "blah?a=&b=&c=".
118 */ 118 */
119 public synchronized String encode(String charset, boolean equalsForNullValue) 119 public synchronized String encode(String charset, boolean equalsForNullValue)
120 { 120 {
121 return encode(this,charset,equalsForNullValue); 121 return encode(this,charset,equalsForNullValue);
122 } 122 }
123 123
124 /* -------------------------------------------------------------- */ 124 /* -------------------------------------------------------------- */
125 /** Encode Hashtable with % encoding. 125 /** Encode Hashtable with % encoding.
126 * @param equalsForNullValue if True, then an '=' is always used, even 126 * @param equalsForNullValue if True, then an '=' is always used, even
127 * for parameters without a value. e.g. "blah?a=&b=&c=". 127 * for parameters without a value. e.g. "blah?a=&b=&c=".
128 */ 128 */
129 public static String encode(MultiMap map, String charset, boolean equalsForNullValue) 129 public static String encode(MultiMap map, String charset, boolean equalsForNullValue)
130 { 130 {
131 if (charset==null) 131 if (charset==null)
132 charset=ENCODING; 132 charset=ENCODING;
133 133
134 StringBuilder result = new StringBuilder(128); 134 StringBuilder result = new StringBuilder(128);
135 135
136 Iterator iter = map.entrySet().iterator(); 136 Iterator iter = map.entrySet().iterator();
137 while(iter.hasNext()) 137 while(iter.hasNext())
138 { 138 {
139 Map.Entry entry = (Map.Entry)iter.next(); 139 Map.Entry entry = (Map.Entry)iter.next();
140 140
141 String key = entry.getKey().toString(); 141 String key = entry.getKey().toString();
142 Object list = entry.getValue(); 142 Object list = entry.getValue();
143 int s=LazyList.size(list); 143 int s=LazyList.size(list);
144 144
145 if (s==0) 145 if (s==0)
146 { 146 {
147 result.append(encodeString(key,charset)); 147 result.append(encodeString(key,charset));
148 if(equalsForNullValue) 148 if(equalsForNullValue)
149 result.append('='); 149 result.append('=');
150 } 150 }
151 else 151 else
152 { 152 {
153 for (int i=0;i<s;i++) 153 for (int i=0;i<s;i++)
154 { 154 {
155 if (i>0) 155 if (i>0)
156 result.append('&'); 156 result.append('&');
157 Object val=LazyList.get(list,i); 157 Object val=LazyList.get(list,i);
158 result.append(encodeString(key,charset)); 158 result.append(encodeString(key,charset));
159 159
160 if (val!=null) 160 if (val!=null)
161 { 161 {
162 String str=val.toString(); 162 String str=val.toString();
163 if (str.length()>0) 163 if (str.length()>0)
164 { 164 {
165 result.append('='); 165 result.append('=');
166 result.append(encodeString(str,charset)); 166 result.append(encodeString(str,charset));
167 } 167 }
168 else if (equalsForNullValue) 168 else if (equalsForNullValue)
169 result.append('='); 169 result.append('=');
170 } 170 }
171 else if (equalsForNullValue) 171 else if (equalsForNullValue)
172 result.append('='); 172 result.append('=');
173 } 173 }
174 } 174 }
175 if (iter.hasNext()) 175 if (iter.hasNext())
176 result.append('&'); 176 result.append('&');
177 } 177 }
178 return result.toString(); 178 return result.toString();
179 } 179 }
180 180
181 181
182 182
183 /* -------------------------------------------------------------- */ 183 /* -------------------------------------------------------------- */
184 /** Decoded parameters to Map. 184 /** Decoded parameters to Map.
185 * @param content the string containing the encoded parameters 185 * @param content the string containing the encoded parameters
186 */ 186 */
187 public static void decodeTo(String content, MultiMap map, String charset) 187 public static void decodeTo(String content, MultiMap map, String charset)
188 { 188 {
189 decodeTo(content,map,charset,-1); 189 decodeTo(content,map,charset,-1);
190 } 190 }
191 191
192 /* -------------------------------------------------------------- */ 192 /* -------------------------------------------------------------- */
193 /** Decoded parameters to Map. 193 /** Decoded parameters to Map.
194 * @param content the string containing the encoded parameters 194 * @param content the string containing the encoded parameters
195 */ 195 */
196 public static void decodeTo(String content, MultiMap map, String charset, int maxKeys) 196 public static void decodeTo(String content, MultiMap map, String charset, int maxKeys)
197 { 197 {
198 if (charset==null) 198 if (charset==null)
199 charset=ENCODING; 199 charset=ENCODING;
200 200
201 synchronized(map) 201 synchronized(map)
202 { 202 {
203 String key = null; 203 String key = null;
204 String value = null; 204 String value = null;
205 int mark=-1; 205 int mark=-1;
206 boolean encoded=false; 206 boolean encoded=false;
207 for (int i=0;i<content.length();i++) 207 for (int i=0;i<content.length();i++)
208 { 208 {
209 char c = content.charAt(i); 209 char c = content.charAt(i);
210 switch (c) 210 switch (c)
211 { 211 {
212 case '&': 212 case '&':
213 int l=i-mark-1; 213 int l=i-mark-1;
214 value = l==0?"": 214 value = l==0?"":
215 (encoded?decodeString(content,mark+1,l,charset):content.substring(mark+1,i)); 215 (encoded?decodeString(content,mark+1,l,charset):content.substring(mark+1,i));
216 mark=i; 216 mark=i;
217 encoded=false; 217 encoded=false;
218 if (key != null) 218 if (key != null)
219 { 219 {
220 map.add(key,value); 220 map.add(key,value);
221 } 221 }
222 else if (value!=null&&value.length()>0) 222 else if (value!=null&&value.length()>0)
223 { 223 {
224 map.add(value,""); 224 map.add(value,"");
225 } 225 }
226 key = null; 226 key = null;
227 value=null; 227 value=null;
228 if (maxKeys>0 && map.size()>maxKeys) 228 if (maxKeys>0 && map.size()>maxKeys)
229 throw new IllegalStateException("Form too many keys"); 229 throw new IllegalStateException("Form too many keys");
230 break; 230 break;
231 case '=': 231 case '=':
232 if (key!=null) 232 if (key!=null)
233 break; 233 break;
234 key = encoded?decodeString(content,mark+1,i-mark-1,charset):content.substring(mark+1,i); 234 key = encoded?decodeString(content,mark+1,i-mark-1,charset):content.substring(mark+1,i);
235 mark=i; 235 mark=i;
236 encoded=false; 236 encoded=false;
237 break; 237 break;
238 case '+': 238 case '+':
239 encoded=true; 239 encoded=true;
240 break; 240 break;
241 case '%': 241 case '%':
242 encoded=true; 242 encoded=true;
243 break; 243 break;
244 } 244 }
245 } 245 }
246 246
247 if (key != null) 247 if (key != null)
248 { 248 {
249 int l=content.length()-mark-1; 249 int l=content.length()-mark-1;
250 value = l==0?"":(encoded?decodeString(content,mark+1,l,charset):content.substring(mark+1)); 250 value = l==0?"":(encoded?decodeString(content,mark+1,l,charset):content.substring(mark+1));
251 map.add(key,value); 251 map.add(key,value);
252 } 252 }
253 else if (mark<content.length()) 253 else if (mark<content.length())
254 { 254 {
255 key = encoded 255 key = encoded
256 ?decodeString(content,mark+1,content.length()-mark-1,charset) 256 ?decodeString(content,mark+1,content.length()-mark-1,charset)
257 :content.substring(mark+1); 257 :content.substring(mark+1);
258 if (key != null && key.length() > 0) 258 if (key != null && key.length() > 0)
259 { 259 {
260 map.add(key,""); 260 map.add(key,"");
261 } 261 }
262 } 262 }
263 } 263 }
264 } 264 }
265 265
266 /* -------------------------------------------------------------- */ 266 /* -------------------------------------------------------------- */
267 /** Decoded parameters to Map. 267 /** Decoded parameters to Map.
268 * @param raw the byte[] containing the encoded parameters 268 * @param raw the byte[] containing the encoded parameters
269 * @param offset the offset within raw to decode from 269 * @param offset the offset within raw to decode from
270 * @param length the length of the section to decode 270 * @param length the length of the section to decode
271 * @param map the {@link MultiMap} to populate 271 * @param map the {@link MultiMap} to populate
272 */ 272 */
273 public static void decodeUtf8To(byte[] raw,int offset, int length, MultiMap map) 273 public static void decodeUtf8To(byte[] raw,int offset, int length, MultiMap map)
274 { 274 {
275 decodeUtf8To(raw,offset,length,map,new Utf8StringBuilder()); 275 decodeUtf8To(raw,offset,length,map,new Utf8StringBuilder());
276 } 276 }
277 277
278 /* -------------------------------------------------------------- */ 278 /* -------------------------------------------------------------- */
279 /** Decoded parameters to Map. 279 /** Decoded parameters to Map.
280 * @param raw the byte[] containing the encoded parameters 280 * @param raw the byte[] containing the encoded parameters
281 * @param offset the offset within raw to decode from 281 * @param offset the offset within raw to decode from
282 * @param length the length of the section to decode 282 * @param length the length of the section to decode
283 * @param map the {@link MultiMap} to populate 283 * @param map the {@link MultiMap} to populate
284 * @param buffer the buffer to decode into 284 * @param buffer the buffer to decode into
285 */ 285 */
286 public static void decodeUtf8To(byte[] raw,int offset, int length, MultiMap map,Utf8StringBuilder buffer) 286 public static void decodeUtf8To(byte[] raw,int offset, int length, MultiMap map,Utf8StringBuilder buffer)
287 { 287 {
288 synchronized(map) 288 synchronized(map)
289 { 289 {
290 String key = null; 290 String key = null;
291 String value = null; 291 String value = null;
292 292
293 // TODO cache of parameter names ??? 293 // TODO cache of parameter names ???
294 int end=offset+length; 294 int end=offset+length;
295 for (int i=offset;i<end;i++) 295 for (int i=offset;i<end;i++)
296 { 296 {
297 byte b=raw[i]; 297 byte b=raw[i];
298 try 298 try
299 { 299 {
300 switch ((char)(0xff&b)) 300 switch ((char)(0xff&b))
301 { 301 {
302 case '&': 302 case '&':
303 value = buffer.length()==0?"":buffer.toString(); 303 value = buffer.length()==0?"":buffer.toString();
304 buffer.reset(); 304 buffer.reset();
305 if (key != null) 305 if (key != null)
306 { 306 {
307 map.add(key,value); 307 map.add(key,value);
308 } 308 }
309 else if (value!=null&&value.length()>0) 309 else if (value!=null&&value.length()>0)
310 { 310 {
311 map.add(value,""); 311 map.add(value,"");
312 } 312 }
313 key = null; 313 key = null;
314 value=null; 314 value=null;
315 break; 315 break;
316 316
317 case '=': 317 case '=':
318 if (key!=null) 318 if (key!=null)
319 { 319 {
320 buffer.append(b); 320 buffer.append(b);
321 break; 321 break;
322 } 322 }
323 key = buffer.toString(); 323 key = buffer.toString();
324 buffer.reset(); 324 buffer.reset();
325 break; 325 break;
326 326
327 case '+': 327 case '+':
328 buffer.append((byte)' '); 328 buffer.append((byte)' ');
329 break; 329 break;
330 330
331 case '%': 331 case '%':
332 if (i+2<end) 332 if (i+2<end)
333 { 333 {
334 if ('u'==raw[i+1]) 334 if ('u'==raw[i+1])
335 { 335 {
336 i++; 336 i++;
337 if (i+4<end) 337 if (i+4<end)
338 buffer.getStringBuilder().append(Character.toChars((convertHexDigit(raw[++i])<<12) +(convertHexDigit(raw[++i])<<8) + (convertHexDigit(raw[++i])<<4) +convertHexDigit(raw[++i]))); 338 buffer.getStringBuilder().append(Character.toChars((convertHexDigit(raw[++i])<<12) +(convertHexDigit(raw[++i])<<8) + (convertHexDigit(raw[++i])<<4) +convertHexDigit(raw[++i])));
339 else 339 else
340 { 340 {
341 buffer.getStringBuilder().append(Utf8Appendable.REPLACEMENT); 341 buffer.getStringBuilder().append(Utf8Appendable.REPLACEMENT);
342 i=end; 342 i=end;
343 } 343 }
344 } 344 }
345 else 345 else
346 buffer.append((byte)((convertHexDigit(raw[++i])<<4) + convertHexDigit(raw[++i]))); 346 buffer.append((byte)((convertHexDigit(raw[++i])<<4) + convertHexDigit(raw[++i])));
347 } 347 }
348 else 348 else
349 { 349 {
350 buffer.getStringBuilder().append(Utf8Appendable.REPLACEMENT); 350 buffer.getStringBuilder().append(Utf8Appendable.REPLACEMENT);
351 i=end; 351 i=end;
352 } 352 }
353 break; 353 break;
354 354
355 default: 355 default:
356 buffer.append(b); 356 buffer.append(b);
357 break; 357 break;
358 } 358 }
359 } 359 }
360 catch(NotUtf8Exception e) 360 catch(NotUtf8Exception e)
361 { 361 {
362 LOG.warn(e.toString()); 362 LOG.warn(e.toString());
363 LOG.debug("",e); 363 LOG.debug("",e);
364 } 364 }
365 } 365 }
366 366
367 if (key != null) 367 if (key != null)
368 { 368 {
369 value = buffer.length()==0?"":buffer.toReplacedString(); 369 value = buffer.length()==0?"":buffer.toReplacedString();
370 buffer.reset(); 370 buffer.reset();
371 map.add(key,value); 371 map.add(key,value);
372 } 372 }
373 else if (buffer.length()>0) 373 else if (buffer.length()>0)
374 { 374 {
375 map.add(buffer.toReplacedString(),""); 375 map.add(buffer.toReplacedString(),"");
376 } 376 }
377 } 377 }
378 } 378 }
379 379
380 /* -------------------------------------------------------------- */ 380 /* -------------------------------------------------------------- */
381 /** Decoded parameters to Map. 381 /** Decoded parameters to Map.
382 * @param in InputSteam to read 382 * @param in InputSteam to read
383 * @param map MultiMap to add parameters to 383 * @param map MultiMap to add parameters to
384 * @param maxLength maximum number of keys to read or -1 for no limit 384 * @param maxLength maximum number of keys to read or -1 for no limit
385 */ 385 */
386 public static void decode88591To(InputStream in, MultiMap map, int maxLength, int maxKeys) 386 public static void decode88591To(InputStream in, MultiMap map, int maxLength, int maxKeys)
387 throws IOException 387 throws IOException
388 { 388 {
389 synchronized(map) 389 synchronized(map)
390 { 390 {
391 StringBuffer buffer = new StringBuffer(); 391 StringBuffer buffer = new StringBuffer();
392 String key = null; 392 String key = null;
393 String value = null; 393 String value = null;
394 394
395 int b; 395 int b;
396 396
397 // TODO cache of parameter names ??? 397 // TODO cache of parameter names ???
398 int totalLength=0; 398 int totalLength=0;
399 while ((b=in.read())>=0) 399 while ((b=in.read())>=0)
400 { 400 {
401 switch ((char) b) 401 switch ((char) b)
402 { 402 {
403 case '&': 403 case '&':
404 value = buffer.length()==0?"":buffer.toString(); 404 value = buffer.length()==0?"":buffer.toString();
405 buffer.setLength(0); 405 buffer.setLength(0);
406 if (key != null) 406 if (key != null)
407 { 407 {
408 map.add(key,value); 408 map.add(key,value);
409 } 409 }
410 else if (value!=null&&value.length()>0) 410 else if (value!=null&&value.length()>0)
411 { 411 {
412 map.add(value,""); 412 map.add(value,"");
413 } 413 }
414 key = null; 414 key = null;
415 value=null; 415 value=null;
416 if (maxKeys>0 && map.size()>maxKeys) 416 if (maxKeys>0 && map.size()>maxKeys)
417 throw new IllegalStateException("Form too many keys"); 417 throw new IllegalStateException("Form too many keys");
418 break; 418 break;
419 419
420 case '=': 420 case '=':
421 if (key!=null) 421 if (key!=null)
422 { 422 {
423 buffer.append((char)b); 423 buffer.append((char)b);
424 break; 424 break;
425 } 425 }
426 key = buffer.toString(); 426 key = buffer.toString();
427 buffer.setLength(0); 427 buffer.setLength(0);
428 break; 428 break;
429 429
430 case '+': 430 case '+':
431 buffer.append(' '); 431 buffer.append(' ');
432 break; 432 break;
433 433
434 case '%': 434 case '%':
435 int code0=in.read(); 435 int code0=in.read();
436 if ('u'==code0) 436 if ('u'==code0)
437 { 437 {
438 int code1=in.read(); 438 int code1=in.read();
439 if (code1>=0) 439 if (code1>=0)
440 { 440 {
441 int code2=in.read(); 441 int code2=in.read();
442 if (code2>=0) 442 if (code2>=0)
443 { 443 {
444 int code3=in.read(); 444 int code3=in.read();
445 if (code3>=0) 445 if (code3>=0)
446 buffer.append(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))); 446 buffer.append(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3)));
447 } 447 }
448 } 448 }
449 } 449 }
450 else if (code0>=0) 450 else if (code0>=0)
451 { 451 {
452 int code1=in.read(); 452 int code1=in.read();
453 if (code1>=0) 453 if (code1>=0)
454 buffer.append((char)((convertHexDigit(code0)<<4)+convertHexDigit(code1))); 454 buffer.append((char)((convertHexDigit(code0)<<4)+convertHexDigit(code1)));
455 } 455 }
456 break; 456 break;
457 457
458 default: 458 default:
459 buffer.append((char)b); 459 buffer.append((char)b);
460 break; 460 break;
461 } 461 }
462 if (maxLength>=0 && (++totalLength > maxLength)) 462 if (maxLength>=0 && (++totalLength > maxLength))
463 throw new IllegalStateException("Form too large"); 463 throw new IllegalStateException("Form too large");
464 } 464 }
465 465
466 if (key != null) 466 if (key != null)
467 { 467 {
468 value = buffer.length()==0?"":buffer.toString(); 468 value = buffer.length()==0?"":buffer.toString();
469 buffer.setLength(0); 469 buffer.setLength(0);
470 map.add(key,value); 470 map.add(key,value);
471 } 471 }
472 else if (buffer.length()>0) 472 else if (buffer.length()>0)
473 { 473 {
474 map.add(buffer.toString(), ""); 474 map.add(buffer.toString(), "");
475 } 475 }
476 } 476 }
477 } 477 }
478 478
479 /* -------------------------------------------------------------- */ 479 /* -------------------------------------------------------------- */
480 /** Decoded parameters to Map. 480 /** Decoded parameters to Map.
481 * @param in InputSteam to read 481 * @param in InputSteam to read
482 * @param map MultiMap to add parameters to 482 * @param map MultiMap to add parameters to
483 * @param maxLength maximum number of keys to read or -1 for no limit 483 * @param maxLength maximum number of keys to read or -1 for no limit
484 */ 484 */
485 public static void decodeUtf8To(InputStream in, MultiMap map, int maxLength, int maxKeys) 485 public static void decodeUtf8To(InputStream in, MultiMap map, int maxLength, int maxKeys)
486 throws IOException 486 throws IOException
487 { 487 {
488 synchronized(map) 488 synchronized(map)
489 { 489 {
490 Utf8StringBuilder buffer = new Utf8StringBuilder(); 490 Utf8StringBuilder buffer = new Utf8StringBuilder();
491 String key = null; 491 String key = null;
492 String value = null; 492 String value = null;
493 493
494 int b; 494 int b;
495 495
496 // TODO cache of parameter names ??? 496 // TODO cache of parameter names ???
497 int totalLength=0; 497 int totalLength=0;
498 while ((b=in.read())>=0) 498 while ((b=in.read())>=0)
499 { 499 {
500 try 500 try
501 { 501 {
502 switch ((char) b) 502 switch ((char) b)
503 { 503 {
504 case '&': 504 case '&':
505 value = buffer.length()==0?"":buffer.toString(); 505 value = buffer.length()==0?"":buffer.toString();
506 buffer.reset(); 506 buffer.reset();
507 if (key != null) 507 if (key != null)
508 { 508 {
509 map.add(key,value); 509 map.add(key,value);
510 } 510 }
511 else if (value!=null&&value.length()>0) 511 else if (value!=null&&value.length()>0)
512 { 512 {
513 map.add(value,""); 513 map.add(value,"");
514 } 514 }
515 key = null; 515 key = null;
516 value=null; 516 value=null;
517 if (maxKeys>0 && map.size()>maxKeys) 517 if (maxKeys>0 && map.size()>maxKeys)
518 throw new IllegalStateException("Form too many keys"); 518 throw new IllegalStateException("Form too many keys");
519 break; 519 break;
520 520
521 case '=': 521 case '=':
522 if (key!=null) 522 if (key!=null)
523 { 523 {
524 buffer.append((byte)b); 524 buffer.append((byte)b);
525 break; 525 break;
526 } 526 }
527 key = buffer.toString(); 527 key = buffer.toString();
528 buffer.reset(); 528 buffer.reset();
529 break; 529 break;
530 530
531 case '+': 531 case '+':
532 buffer.append((byte)' '); 532 buffer.append((byte)' ');
533 break; 533 break;
534 534
535 case '%': 535 case '%':
536 int code0=in.read(); 536 int code0=in.read();
537 if ('u'==code0) 537 if ('u'==code0)
538 { 538 {
539 int code1=in.read(); 539 int code1=in.read();
540 if (code1>=0) 540 if (code1>=0)
541 { 541 {
542 int code2=in.read(); 542 int code2=in.read();
543 if (code2>=0) 543 if (code2>=0)
544 { 544 {
545 int code3=in.read(); 545 int code3=in.read();
546 if (code3>=0) 546 if (code3>=0)
547 buffer.getStringBuilder().append(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))); 547 buffer.getStringBuilder().append(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3)));
548 } 548 }
549 } 549 }
550 } 550 }
551 else if (code0>=0) 551 else if (code0>=0)
552 { 552 {
553 int code1=in.read(); 553 int code1=in.read();
554 if (code1>=0) 554 if (code1>=0)
555 buffer.append((byte)((convertHexDigit(code0)<<4)+convertHexDigit(code1))); 555 buffer.append((byte)((convertHexDigit(code0)<<4)+convertHexDigit(code1)));
556 } 556 }
557 break; 557 break;
558 558
559 default: 559 default:
560 buffer.append((byte)b); 560 buffer.append((byte)b);
561 break; 561 break;
562 } 562 }
563 } 563 }
564 catch(NotUtf8Exception e) 564 catch(NotUtf8Exception e)
565 { 565 {
566 LOG.warn(e.toString()); 566 LOG.warn(e.toString());
567 LOG.debug("",e); 567 LOG.debug("",e);
568 } 568 }
569 if (maxLength>=0 && (++totalLength > maxLength)) 569 if (maxLength>=0 && (++totalLength > maxLength))
570 throw new IllegalStateException("Form too large"); 570 throw new IllegalStateException("Form too large");
571 } 571 }
572 572
573 if (key != null) 573 if (key != null)
574 { 574 {
575 value = buffer.length()==0?"":buffer.toString(); 575 value = buffer.length()==0?"":buffer.toString();
576 buffer.reset(); 576 buffer.reset();
577 map.add(key,value); 577 map.add(key,value);
578 } 578 }
579 else if (buffer.length()>0) 579 else if (buffer.length()>0)
580 { 580 {
581 map.add(buffer.toString(), ""); 581 map.add(buffer.toString(), "");
582 } 582 }
583 } 583 }
584 } 584 }
585 585
586 /* -------------------------------------------------------------- */ 586 /* -------------------------------------------------------------- */
587 public static void decodeUtf16To(InputStream in, MultiMap map, int maxLength, int maxKeys) throws IOException 587 public static void decodeUtf16To(InputStream in, MultiMap map, int maxLength, int maxKeys) throws IOException
588 { 588 {
589 InputStreamReader input = new InputStreamReader(in,StringUtil.__UTF16); 589 InputStreamReader input = new InputStreamReader(in,StringUtil.__UTF16);
590 StringWriter buf = new StringWriter(8192); 590 StringWriter buf = new StringWriter(8192);
591 IO.copy(input,buf,maxLength); 591 IO.copy(input,buf,maxLength);
592 592
593 decodeTo(buf.getBuffer().toString(),map,StringUtil.__UTF16,maxKeys); 593 decodeTo(buf.getBuffer().toString(),map,StringUtil.__UTF16,maxKeys);
594 } 594 }
595 595
596 /* -------------------------------------------------------------- */ 596 /* -------------------------------------------------------------- */
597 /** Decoded parameters to Map. 597 /** Decoded parameters to Map.
598 * @param in the stream containing the encoded parameters 598 * @param in the stream containing the encoded parameters
599 */ 599 */
600 public static void decodeTo(InputStream in, MultiMap map, String charset, int maxLength, int maxKeys) 600 public static void decodeTo(InputStream in, MultiMap map, String charset, int maxLength, int maxKeys)
601 throws IOException 601 throws IOException
602 { 602 {
603 //no charset present, use the configured default 603 //no charset present, use the configured default
604 if (charset==null) 604 if (charset==null)
605 { 605 {
606 charset=ENCODING; 606 charset=ENCODING;
607 } 607 }
608 608
609 if (StringUtil.__UTF8.equalsIgnoreCase(charset)) 609 if (StringUtil.__UTF8.equalsIgnoreCase(charset))
610 { 610 {
611 decodeUtf8To(in,map,maxLength,maxKeys); 611 decodeUtf8To(in,map,maxLength,maxKeys);
612 return; 612 return;
613 } 613 }
614 614
615 if (StringUtil.__ISO_8859_1.equals(charset)) 615 if (StringUtil.__ISO_8859_1.equals(charset))
616 { 616 {
617 decode88591To(in,map,maxLength,maxKeys); 617 decode88591To(in,map,maxLength,maxKeys);
618 return; 618 return;
619 } 619 }
620 620
621 if (StringUtil.__UTF16.equalsIgnoreCase(charset)) // Should be all 2 byte encodings 621 if (StringUtil.__UTF16.equalsIgnoreCase(charset)) // Should be all 2 byte encodings
622 { 622 {
623 decodeUtf16To(in,map,maxLength,maxKeys); 623 decodeUtf16To(in,map,maxLength,maxKeys);
624 return; 624 return;
625 } 625 }
626 626
627 627
628 synchronized(map) 628 synchronized(map)
629 { 629 {
630 String key = null; 630 String key = null;
631 String value = null; 631 String value = null;
632 632
633 int c; 633 int c;
634 634
635 int totalLength = 0; 635 int totalLength = 0;
636 ByteArrayOutputStream2 output = new ByteArrayOutputStream2(); 636 ByteArrayOutputStream2 output = new ByteArrayOutputStream2();
637 637
638 int size=0; 638 int size=0;
639 639
640 while ((c=in.read())>0) 640 while ((c=in.read())>0)
641 { 641 {
642 switch ((char) c) 642 switch ((char) c)
643 { 643 {
644 case '&': 644 case '&':
645 size=output.size(); 645 size=output.size();
646 value = size==0?"":output.toString(charset); 646 value = size==0?"":output.toString(charset);
647 output.setCount(0); 647 output.setCount(0);
648 if (key != null) 648 if (key != null)
649 { 649 {
650 map.add(key,value); 650 map.add(key,value);
651 } 651 }
652 else if (value!=null&&value.length()>0) 652 else if (value!=null&&value.length()>0)
653 { 653 {
654 map.add(value,""); 654 map.add(value,"");
655 } 655 }
656 key = null; 656 key = null;
657 value=null; 657 value=null;
658 if (maxKeys>0 && map.size()>maxKeys) 658 if (maxKeys>0 && map.size()>maxKeys)
659 throw new IllegalStateException("Form too many keys"); 659 throw new IllegalStateException("Form too many keys");
660 break; 660 break;
661 case '=': 661 case '=':
662 if (key!=null) 662 if (key!=null)
663 { 663 {
664 output.write(c); 664 output.write(c);
665 break; 665 break;
666 } 666 }
667 size=output.size(); 667 size=output.size();
668 key = size==0?"":output.toString(charset); 668 key = size==0?"":output.toString(charset);
669 output.setCount(0); 669 output.setCount(0);
670 break; 670 break;
671 case '+': 671 case '+':
672 output.write(' '); 672 output.write(' ');
673 break; 673 break;
674 case '%': 674 case '%':
675 int code0=in.read(); 675 int code0=in.read();
676 if ('u'==code0) 676 if ('u'==code0)
677 { 677 {
678 int code1=in.read(); 678 int code1=in.read();
679 if (code1>=0) 679 if (code1>=0)
680 { 680 {
681 int code2=in.read(); 681 int code2=in.read();
682 if (code2>=0) 682 if (code2>=0)
683 { 683 {
684 int code3=in.read(); 684 int code3=in.read();
685 if (code3>=0) 685 if (code3>=0)
686 output.write(new String(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))).getBytes(charset)); 686 output.write(new String(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))).getBytes(charset));
687 } 687 }
688 } 688 }
689 689
690 } 690 }
691 else if (code0>=0) 691 else if (code0>=0)
692 { 692 {
693 int code1=in.read(); 693 int code1=in.read();
694 if (code1>=0) 694 if (code1>=0)
695 output.write((convertHexDigit(code0)<<4)+convertHexDigit(code1)); 695 output.write((convertHexDigit(code0)<<4)+convertHexDigit(code1));
696 } 696 }
697 break; 697 break;
698 default: 698 default:
699 output.write(c); 699 output.write(c);
700 break; 700 break;
701 } 701 }
702 702
703 totalLength++; 703 totalLength++;
704 if (maxLength>=0 && totalLength > maxLength) 704 if (maxLength>=0 && totalLength > maxLength)
705 throw new IllegalStateException("Form too large"); 705 throw new IllegalStateException("Form too large");
706 } 706 }
707 707
708 size=output.size(); 708 size=output.size();
709 if (key != null) 709 if (key != null)
710 { 710 {
711 value = size==0?"":output.toString(charset); 711 value = size==0?"":output.toString(charset);
712 output.setCount(0); 712 output.setCount(0);
713 map.add(key,value); 713 map.add(key,value);
714 } 714 }
715 else if (size>0) 715 else if (size>0)
716 map.add(output.toString(charset),""); 716 map.add(output.toString(charset),"");
717 } 717 }
718 } 718 }
719 719
720 /* -------------------------------------------------------------- */ 720 /* -------------------------------------------------------------- */
721 /** Decode String with % encoding. 721 /** Decode String with % encoding.
722 * This method makes the assumption that the majority of calls 722 * This method makes the assumption that the majority of calls
723 * will need no decoding. 723 * will need no decoding.
724 */ 724 */
725 public static String decodeString(String encoded,int offset,int length,String charset) 725 public static String decodeString(String encoded,int offset,int length,String charset)
726 { 726 {
727 if (charset==null || StringUtil.isUTF8(charset)) 727 if (charset==null || StringUtil.isUTF8(charset))
728 { 728 {
729 Utf8StringBuffer buffer=null; 729 Utf8StringBuffer buffer=null;
730 730
731 for (int i=0;i<length;i++) 731 for (int i=0;i<length;i++)
732 { 732 {
733 char c = encoded.charAt(offset+i); 733 char c = encoded.charAt(offset+i);
734 if (c<0||c>0xff) 734 if (c<0||c>0xff)
735 { 735 {
736 if (buffer==null) 736 if (buffer==null)
737 { 737 {
738 buffer=new Utf8StringBuffer(length); 738 buffer=new Utf8StringBuffer(length);
739 buffer.getStringBuffer().append(encoded,offset,offset+i+1); 739 buffer.getStringBuffer().append(encoded,offset,offset+i+1);
740 } 740 }
741 else 741 else
742 buffer.getStringBuffer().append(c); 742 buffer.getStringBuffer().append(c);
743 } 743 }
744 else if (c=='+') 744 else if (c=='+')
745 { 745 {
746 if (buffer==null) 746 if (buffer==null)
747 { 747 {
748 buffer=new Utf8StringBuffer(length); 748 buffer=new Utf8StringBuffer(length);
749 buffer.getStringBuffer().append(encoded,offset,offset+i); 749 buffer.getStringBuffer().append(encoded,offset,offset+i);
750 } 750 }
751 751
752 buffer.getStringBuffer().append(' '); 752 buffer.getStringBuffer().append(' ');
753 } 753 }
754 else if (c=='%') 754 else if (c=='%')
755 { 755 {
756 if (buffer==null) 756 if (buffer==null)
757 { 757 {
758 buffer=new Utf8StringBuffer(length); 758 buffer=new Utf8StringBuffer(length);
759 buffer.getStringBuffer().append(encoded,offset,offset+i); 759 buffer.getStringBuffer().append(encoded,offset,offset+i);
760 } 760 }
761 761
762 if ((i+2)<length) 762 if ((i+2)<length)
763 { 763 {
764 try 764 try
765 { 765 {
766 if ('u'==encoded.charAt(offset+i+1)) 766 if ('u'==encoded.charAt(offset+i+1))
767 { 767 {
768 if((i+5)<length) 768 if((i+5)<length)
769 { 769 {
770 int o=offset+i+2; 770 int o=offset+i+2;
771 i+=5; 771 i+=5;
772 String unicode = new String(Character.toChars(TypeUtil.parseInt(encoded,o,4,16))); 772 String unicode = new String(Character.toChars(TypeUtil.parseInt(encoded,o,4,16)));
773 buffer.getStringBuffer().append(unicode); 773 buffer.getStringBuffer().append(unicode);
774 } 774 }
775 else 775 else
776 { 776 {
777 i=length; 777 i=length;
778 buffer.getStringBuffer().append(Utf8Appendable.REPLACEMENT); 778 buffer.getStringBuffer().append(Utf8Appendable.REPLACEMENT);
779 } 779 }
780 } 780 }
781 else 781 else
782 { 782 {
783 int o=offset+i+1; 783 int o=offset+i+1;
784 i+=2; 784 i+=2;
785 byte b=(byte)TypeUtil.parseInt(encoded,o,2,16); 785 byte b=(byte)TypeUtil.parseInt(encoded,o,2,16);
786 buffer.append(b); 786 buffer.append(b);
787 } 787 }
788 } 788 }
789 catch(NotUtf8Exception e) 789 catch(NotUtf8Exception e)
790 { 790 {
791 LOG.warn(e.toString()); 791 LOG.warn(e.toString());
792 LOG.debug("",e); 792 LOG.debug("",e);
793 } 793 }
794 catch(NumberFormatException nfe) 794 catch(NumberFormatException nfe)
795 { 795 {
796 LOG.debug("",nfe); 796 LOG.debug("",nfe);
797 buffer.getStringBuffer().append(Utf8Appendable.REPLACEMENT); 797 buffer.getStringBuffer().append(Utf8Appendable.REPLACEMENT);
798 } 798 }
799 } 799 }
800 else 800 else
801 { 801 {
802 buffer.getStringBuffer().append(Utf8Appendable.REPLACEMENT); 802 buffer.getStringBuffer().append(Utf8Appendable.REPLACEMENT);
803 i=length; 803 i=length;
804 } 804 }
805 } 805 }
806 else if (buffer!=null) 806 else if (buffer!=null)
807 buffer.getStringBuffer().append(c); 807 buffer.getStringBuffer().append(c);
808 } 808 }
809 809
810 if (buffer==null) 810 if (buffer==null)
811 { 811 {
812 if (offset==0 && encoded.length()==length) 812 if (offset==0 && encoded.length()==length)
813 return encoded; 813 return encoded;
814 return encoded.substring(offset,offset+length); 814 return encoded.substring(offset,offset+length);
815 } 815 }
816 816
817 return buffer.toReplacedString(); 817 return buffer.toReplacedString();
818 } 818 }
819 else 819 else
820 { 820 {
821 StringBuffer buffer=null; 821 StringBuffer buffer=null;
822 822
823 try 823 try
824 { 824 {
825 for (int i=0;i<length;i++) 825 for (int i=0;i<length;i++)
826 { 826 {
827 char c = encoded.charAt(offset+i); 827 char c = encoded.charAt(offset+i);
828 if (c<0||c>0xff) 828 if (c<0||c>0xff)
829 { 829 {
830 if (buffer==null) 830 if (buffer==null)
831 { 831 {
832 buffer=new StringBuffer(length); 832 buffer=new StringBuffer(length);
833 buffer.append(encoded,offset,offset+i+1); 833 buffer.append(encoded,offset,offset+i+1);
834 } 834 }
835 else 835 else
836 buffer.append(c); 836 buffer.append(c);
837 } 837 }
838 else if (c=='+') 838 else if (c=='+')
839 { 839 {
840 if (buffer==null) 840 if (buffer==null)
841 { 841 {
842 buffer=new StringBuffer(length); 842 buffer=new StringBuffer(length);
843 buffer.append(encoded,offset,offset+i); 843 buffer.append(encoded,offset,offset+i);
844 } 844 }
845 845
846 buffer.append(' '); 846 buffer.append(' ');
847 } 847 }
848 else if (c=='%') 848 else if (c=='%')
849 { 849 {
850 if (buffer==null) 850 if (buffer==null)
851 { 851 {
852 buffer=new StringBuffer(length); 852 buffer=new StringBuffer(length);
853 buffer.append(encoded,offset,offset+i); 853 buffer.append(encoded,offset,offset+i);
854 } 854 }
855 855
856 byte[] ba=new byte[length]; 856 byte[] ba=new byte[length];
857 int n=0; 857 int n=0;
858 while(c>=0 && c<=0xff) 858 while(c>=0 && c<=0xff)
859 { 859 {
860 if (c=='%') 860 if (c=='%')
861 { 861 {
862 if(i+2<length) 862 if(i+2<length)
863 { 863 {
864 try 864 try
865 { 865 {
866 if ('u'==encoded.charAt(offset+i+1)) 866 if ('u'==encoded.charAt(offset+i+1))
867 { 867 {
868 if (i+6<length) 868 if (i+6<length)
869 { 869 {
870 int o=offset+i+2; 870 int o=offset+i+2;
871 i+=6; 871 i+=6;
872 String unicode = new String(Character.toChars(TypeUtil.parseInt(encoded,o,4,16))); 872 String unicode = new String(Character.toChars(TypeUtil.parseInt(encoded,o,4,16)));
873 byte[] reencoded = unicode.getBytes(charset); 873 byte[] reencoded = unicode.getBytes(charset);
874 System.arraycopy(reencoded,0,ba,n,reencoded.length); 874 System.arraycopy(reencoded,0,ba,n,reencoded.length);
875 n+=reencoded.length; 875 n+=reencoded.length;
876 } 876 }
877 else 877 else
878 { 878 {
879 ba[n++] = (byte)'?'; 879 ba[n++] = (byte)'?';
880 i=length; 880 i=length;
881 } 881 }
882 } 882 }
883 else 883 else
884 { 884 {
885 int o=offset+i+1; 885 int o=offset+i+1;
886 i+=3; 886 i+=3;
887 ba[n]=(byte)TypeUtil.parseInt(encoded,o,2,16); 887 ba[n]=(byte)TypeUtil.parseInt(encoded,o,2,16);
888 n++; 888 n++;
889 } 889 }
890 } 890 }
891 catch(NumberFormatException nfe) 891 catch(NumberFormatException nfe)
892 { 892 {
893 LOG.trace("",nfe); 893 LOG.trace("",nfe);
894 ba[n++] = (byte)'?'; 894 ba[n++] = (byte)'?';
895 } 895 }
896 } 896 }
897 else 897 else
898 { 898 {
899 ba[n++] = (byte)'?'; 899 ba[n++] = (byte)'?';
900 i=length; 900 i=length;
901 } 901 }
902 } 902 }
903 else if (c=='+') 903 else if (c=='+')
904 { 904 {
905 ba[n++]=(byte)' '; 905 ba[n++]=(byte)' ';
906 i++; 906 i++;
907 } 907 }
908 else 908 else
909 { 909 {
910 ba[n++]=(byte)c; 910 ba[n++]=(byte)c;
911 i++; 911 i++;
912 } 912 }
913 913
914 if (i>=length) 914 if (i>=length)
915 break; 915 break;
916 c = encoded.charAt(offset+i); 916 c = encoded.charAt(offset+i);
917 } 917 }
918 918
919 i--; 919 i--;
920 buffer.append(new String(ba,0,n,charset)); 920 buffer.append(new String(ba,0,n,charset));
921 921
922 } 922 }
923 else if (buffer!=null) 923 else if (buffer!=null)
924 buffer.append(c); 924 buffer.append(c);
925 } 925 }
926 926
927 if (buffer==null) 927 if (buffer==null)
928 { 928 {
929 if (offset==0 && encoded.length()==length) 929 if (offset==0 && encoded.length()==length)
930 return encoded; 930 return encoded;
931 return encoded.substring(offset,offset+length); 931 return encoded.substring(offset,offset+length);
932 } 932 }
933 933
934 return buffer.toString(); 934 return buffer.toString();
935 } 935 }
936 catch (UnsupportedEncodingException e) 936 catch (UnsupportedEncodingException e)
937 { 937 {
938 throw new RuntimeException(e); 938 throw new RuntimeException(e);
939 } 939 }
940 } 940 }
941 941
942 } 942 }
943 943
944 /* ------------------------------------------------------------ */ 944 /* ------------------------------------------------------------ */
945 /** Perform URL encoding. 945 /** Perform URL encoding.
946 * @param string 946 * @param string
947 * @return encoded string. 947 * @return encoded string.
948 */ 948 */
949 public static String encodeString(String string) 949 public static String encodeString(String string)
950 { 950 {
951 return encodeString(string,ENCODING); 951 return encodeString(string,ENCODING);
952 } 952 }
953 953
954 /* ------------------------------------------------------------ */ 954 /* ------------------------------------------------------------ */
955 /** Perform URL encoding. 955 /** Perform URL encoding.
956 * @param string 956 * @param string
957 * @return encoded string. 957 * @return encoded string.
958 */ 958 */
959 public static String encodeString(String string,String charset) 959 public static String encodeString(String string,String charset)
960 { 960 {
961 if (charset==null) 961 if (charset==null)
962 charset=ENCODING; 962 charset=ENCODING;
963 byte[] bytes=null; 963 byte[] bytes=null;
964 try 964 try
965 { 965 {
966 bytes=string.getBytes(charset); 966 bytes=string.getBytes(charset);
967 } 967 }
968 catch(UnsupportedEncodingException e) 968 catch(UnsupportedEncodingException e)
969 { 969 {
970 // LOG.warn(LogSupport.EXCEPTION,e); 970 // LOG.warn(LogSupport.EXCEPTION,e);
971 bytes=string.getBytes(); 971 bytes=string.getBytes();
972 } 972 }
973 973
974 int len=bytes.length; 974 int len=bytes.length;
975 byte[] encoded= new byte[bytes.length*3]; 975 byte[] encoded= new byte[bytes.length*3];
976 int n=0; 976 int n=0;
977 boolean noEncode=true; 977 boolean noEncode=true;
978 978
979 for (int i=0;i<len;i++) 979 for (int i=0;i<len;i++)
980 { 980 {
981 byte b = bytes[i]; 981 byte b = bytes[i];
982 982
983 if (b==' ') 983 if (b==' ')
984 { 984 {
985 noEncode=false; 985 noEncode=false;
986 encoded[n++]=(byte)'+'; 986 encoded[n++]=(byte)'+';
987 } 987 }
988 else if (b>='a' && b<='z' || 988 else if (b>='a' && b<='z' ||
989 b>='A' && b<='Z' || 989 b>='A' && b<='Z' ||
990 b>='0' && b<='9') 990 b>='0' && b<='9')
991 { 991 {
992 encoded[n++]=b; 992 encoded[n++]=b;
993 } 993 }
994 else 994 else
995 { 995 {
996 noEncode=false; 996 noEncode=false;
997 encoded[n++]=(byte)'%'; 997 encoded[n++]=(byte)'%';
998 byte nibble= (byte) ((b&0xf0)>>4); 998 byte nibble= (byte) ((b&0xf0)>>4);
999 if (nibble>=10) 999 if (nibble>=10)
1000 encoded[n++]=(byte)('A'+nibble-10); 1000 encoded[n++]=(byte)('A'+nibble-10);
1001 else 1001 else
1002 encoded[n++]=(byte)('0'+nibble); 1002 encoded[n++]=(byte)('0'+nibble);
1003 nibble= (byte) (b&0xf); 1003 nibble= (byte) (b&0xf);
1004 if (nibble>=10) 1004 if (nibble>=10)
1005 encoded[n++]=(byte)('A'+nibble-10); 1005 encoded[n++]=(byte)('A'+nibble-10);
1006 else 1006 else
1007 encoded[n++]=(byte)('0'+nibble); 1007 encoded[n++]=(byte)('0'+nibble);
1008 } 1008 }
1009 } 1009 }
1010 1010
1011 if (noEncode) 1011 if (noEncode)
1012 return string; 1012 return string;
1013 1013
1014 try 1014 try
1015 { 1015 {
1016 return new String(encoded,0,n,charset); 1016 return new String(encoded,0,n,charset);
1017 } 1017 }
1018 catch(UnsupportedEncodingException e) 1018 catch(UnsupportedEncodingException e)
1019 { 1019 {
1020 // LOG.warn(LogSupport.EXCEPTION,e); 1020 // LOG.warn(LogSupport.EXCEPTION,e);
1021 return new String(encoded,0,n); 1021 return new String(encoded,0,n);
1022 } 1022 }
1023 } 1023 }
1024 1024
1025 1025
1026 /* ------------------------------------------------------------ */ 1026 /* ------------------------------------------------------------ */
1027 /** 1027 /**
1028 */ 1028 */
1029 @Override 1029 @Override
1030 public Object clone() 1030 public Object clone()
1031 { 1031 {
1032 return new UrlEncoded(this); 1032 return new UrlEncoded(this);
1033 } 1033 }
1034 } 1034 }