1 16 package org.mortbay.util; 17 18 import java.io.UnsupportedEncodingException ; 19 import java.util.Iterator ; 20 import java.util.Map ; 21 22 import org.apache.commons.logging.Log; 23 import org.mortbay.log.LogFactory; 24 25 26 41 public class UrlEncoded extends MultiMap 42 { 43 private static Log log = LogFactory.getLog(UrlEncoded.class); 44 45 46 public UrlEncoded(UrlEncoded url) 47 { 48 super(url); 49 } 50 51 52 public UrlEncoded() 53 { 54 super(6); 55 } 56 57 58 public UrlEncoded(String s) 59 { 60 super(6); 61 decode(s,StringUtil.__ISO_8859_1); 62 } 63 64 65 public UrlEncoded(String s, String charset) 66 { 67 super(6); 68 decode(s,charset); 69 } 70 71 72 public void decode(String query) 73 { 74 decodeTo(query,this,StringUtil.__ISO_8859_1); 75 } 76 77 78 public void decode(String query,String charset) 79 { 80 decodeTo(query,this,charset); 81 } 82 83 84 86 public String encode() 87 { 88 return encode(StringUtil.__ISO_8859_1,false); 89 } 90 91 92 94 public String encode(String charset) 95 { 96 return encode(charset,false); 97 } 98 99 100 104 public synchronized String encode(String charset, boolean equalsForNullValue) 105 { 106 if (charset==null) 107 charset=StringUtil.__ISO_8859_1; 108 109 StringBuffer result = new StringBuffer (128); 110 synchronized(result) 111 { 112 Iterator iter = entrySet().iterator(); 113 while(iter.hasNext()) 114 { 115 Map.Entry entry = (Map.Entry )iter.next(); 116 117 String key = entry.getKey().toString(); 118 Object list = entry.getValue(); 119 int s=LazyList.size(list); 120 121 if (s==0) 122 { 123 result.append(encodeString(key,charset)); 124 if(equalsForNullValue) 125 result.append('='); 126 } 127 else 128 { 129 for (int i=0;i<s;i++) 130 { 131 if (i>0) 132 result.append('&'); 133 Object val=LazyList.get(list,i); 134 result.append(encodeString(key,charset)); 135 136 if (val!=null) 137 { 138 String str=val.toString(); 139 if (str.length()>0) 140 { 141 result.append('='); 142 result.append(encodeString(str,charset)); 143 } 144 else if (equalsForNullValue) 145 result.append('='); 146 } 147 else if (equalsForNullValue) 148 result.append('='); 149 } 150 } 151 if (iter.hasNext()) 152 result.append('&'); 153 } 154 return result.toString(); 155 } 156 } 157 158 159 163 public static void decodeTo(String content,MultiMap map) 164 { 165 decodeTo(content,map,StringUtil.__ISO_8859_1); 166 } 167 168 169 170 171 174 public static void decodeTo(String content, MultiMap map, String charset) 175 { 176 if (charset==null) 177 charset=StringUtil.__ISO_8859_1; 178 179 synchronized(map) 180 { 181 String key = null; 182 String value = null; 183 int mark=-1; 184 boolean encoded=false; 185 for (int i=0;i<content.length();i++) 186 { 187 char c = content.charAt(i); 188 switch (c) 189 { 190 case '&': 191 value = encoded 192 ?decodeString(content,mark+1,i-mark-1,charset) 193 :content.substring(mark+1,i); 194 195 mark=i; 196 encoded=false; 197 if (key != null) 198 { 199 map.add(key,value); 200 key = null; 201 } 202 break; 203 case '=': 204 if (key!=null) 205 break; 206 key = encoded 207 ?decodeString(content,mark+1,i-mark-1,charset) 208 :content.substring(mark+1,i); 209 mark=i; 210 encoded=false; 211 break; 212 case '+': 213 encoded=true; 214 break; 215 case '%': 216 encoded=true; 217 break; 218 } 219 } 220 221 if (key != null) 222 { 223 value = encoded 224 ?decodeString(content,mark+1,content.length()-mark-1,charset) 225 :content.substring(mark+1); 226 map.add(key,value); 227 } 228 else if (mark<content.length()) 229 { 230 key = encoded 231 ?decodeString(content,mark+1,content.length()-mark-1,charset) 232 :content.substring(mark+1); 233 map.add(key,""); 234 } 235 } 236 } 237 238 239 242 public static void decodeTo(byte[] data, int offset, int length, MultiMap map, String charset) 243 { 244 if (data == null || length == 0) 245 return; 246 247 if (charset==null) 248 charset=StringUtil.__ISO_8859_1; 249 250 synchronized(map) 251 { 252 try 253 { 254 int ix = offset; 255 int end = offset+length; 256 int ox = offset; 257 String key = null; 258 String value = null; 259 while (ix < end) 260 { 261 byte c = data[ix++]; 262 switch ((char) c) 263 { 264 case '&': 265 value = new String (data, offset, ox, charset); 266 if (key != null) 267 { 268 map.add(key,value); 269 key = null; 270 } 271 ox = offset; 272 break; 273 case '=': 274 if (key!=null) 275 break; 276 key = new String (data, offset, ox, charset); 277 ox = offset; 278 break; 279 case '+': 280 data[ox++] = (byte)' '; 281 break; 282 case '%': 283 int i0 = (14<<4)+1; 284 byte b0 = (byte)i0; 285 data[ox++] = (byte) 286 ((TypeUtil.convertHexDigit(data[ix++]) << 4)+ 287 TypeUtil.convertHexDigit(data[ix++])); 288 break; 289 default: 290 data[ox++] = c; 291 } 292 } 293 if (key != null) 294 { 295 value = new String (data, offset, ox, charset); 296 map.add(key,value); 297 } 298 } 299 catch(UnsupportedEncodingException e) 300 { 301 log.warn(LogSupport.EXCEPTION,e); 302 } 303 } 304 } 305 306 307 311 public static String decodeString(String encoded) 312 { 313 return decodeString(encoded,0,encoded.length(),StringUtil.__ISO_8859_1); 314 } 315 316 317 321 public static String decodeString(String encoded,String charset) 322 { 323 return decodeString(encoded,0,encoded.length(),charset); 324 } 325 326 327 328 332 public static String decodeString(String encoded,int offset,int length,String charset) 333 { 334 if (charset==null) 335 charset=StringUtil.__ISO_8859_1; 336 byte[] bytes=null; 337 int n=0; 338 339 for (int i=0;i<length;i++) 340 { 341 char c = encoded.charAt(offset+i); 342 if (c<0||c>0xff) 343 throw new IllegalArgumentException ("Not encoded"); 344 345 if (c=='+') 346 { 347 if (bytes==null) 348 { 349 bytes=new byte[length*2]; 350 encoded.getBytes(offset, offset+i, bytes, 0); 351 n=i; 352 } 353 bytes[n++] = (byte) ' '; 354 } 355 else if (c=='%' && (i+2)<length) 356 { 357 byte b; 358 char cn = encoded.charAt(offset+i+1); 359 if (cn>='a' && cn<='z') 360 b=(byte)(10+cn-'a'); 361 else if (cn>='A' && cn<='Z') 362 b=(byte)(10+cn-'A'); 363 else 364 b=(byte)(cn-'0'); 365 cn = encoded.charAt(offset+i+2); 366 if (cn>='a' && cn<='z') 367 b=(byte)(b*16+10+cn-'a'); 368 else if (cn>='A' && cn<='Z') 369 b=(byte)(b*16+10+cn-'A'); 370 else 371 b=(byte)(b*16+cn-'0'); 372 373 if (bytes==null) 374 { 375 bytes=new byte[length*2]; 376 encoded.getBytes(offset, offset+i, bytes, 0); 377 n=i; 378 } 379 i+=2; 380 bytes[n++]=b; 381 } 382 else if (n>0) 383 bytes[n++] = (byte) c; 384 } 385 386 if (bytes==null) 387 { 388 if (offset==0 && encoded.length()==length) 389 return encoded; 390 return encoded.substring(offset,offset+length); 391 } 392 393 try 394 { 395 return new String (bytes,0,n,charset); 396 } 397 catch (UnsupportedEncodingException e) 398 { 399 return new String (bytes,0,n); 400 } 401 402 } 403 404 405 410 public static String encodeString(String string) 411 { 412 return encodeString(string,StringUtil.__ISO_8859_1); 413 } 414 415 416 420 public static String encodeString(String string,String charset) 421 { 422 if (charset==null) 423 charset=StringUtil.__ISO_8859_1; 424 byte[] bytes=null; 425 try 426 { 427 bytes=string.getBytes(charset); 428 } 429 catch(UnsupportedEncodingException e) 430 { 431 log.warn(LogSupport.EXCEPTION,e); 432 bytes=string.getBytes(); 433 } 434 435 int len=bytes.length; 436 byte[] encoded= new byte[bytes.length*3]; 437 int n=0; 438 boolean noEncode=true; 439 440 for (int i=0;i<len;i++) 441 { 442 byte b = bytes[i]; 443 444 if (b==' ') 445 { 446 noEncode=false; 447 encoded[n++]=(byte)'+'; 448 } 449 else if (b>='a' && b<='z' || 450 b>='A' && b<='Z' || 451 b>='0' && b<='9') 452 { 453 encoded[n++]=b; 454 } 455 else 456 { 457 noEncode=false; 458 encoded[n++]=(byte)'%'; 459 byte nibble= (byte) ((b&0xf0)>>4); 460 if (nibble>=10) 461 encoded[n++]=(byte)('A'+nibble-10); 462 else 463 encoded[n++]=(byte)('0'+nibble); 464 nibble= (byte) (b&0xf); 465 if (nibble>=10) 466 encoded[n++]=(byte)('A'+nibble-10); 467 else 468 encoded[n++]=(byte)('0'+nibble); 469 } 470 } 471 472 if (noEncode) 473 return string; 474 475 try 476 { 477 return new String (encoded,0,n,charset); 478 } 479 catch(UnsupportedEncodingException e) 480 { 481 log.warn(LogSupport.EXCEPTION,e); 482 return new String (encoded,0,n); 483 } 484 } 485 486 487 488 490 public Object clone() 491 { 492 return super.clone(); 493 } 494 } 495 | Popular Tags |