| 1 28 29 package HTTPClient; 30 31 32 import java.util.BitSet ; 33 import java.util.Vector ; 34 import java.util.StringTokenizer ; 35 import java.io.IOException ; 36 import java.io.InputStream ; 37 import java.io.DataInputStream ; 38 import java.io.File ; 39 import java.io.FileInputStream ; 40 import java.io.FileOutputStream ; 41 import java.io.BufferedReader ; 42 43 44 50 51 public class Codecs 52 { 53 private static BitSet BoundChar; 54 private static BitSet EBCDICUnsafeChar; 55 private static byte[] Base64EncMap, Base64DecMap; 56 private static char[] UUEncMap; 57 private static byte[] UUDecMap; 58 59 60 private final static String ContDisp = "\r\nContent-Disposition: form-data; name=\""; 61 private final static String FileName = "\"; filename=\""; 62 private final static String Boundary = "\r\n-----ieoau._._+2_8_GoodLuck8.3-dskdfJwSJKlrWLr0234324jfLdsjfdAuaoei-----"; 63 64 65 67 static 68 { 69 BoundChar = new BitSet (256); 72 for (int ch='0'; ch <= '9'; ch++) BoundChar.set(ch); 73 for (int ch='A'; ch <= 'Z'; ch++) BoundChar.set(ch); 74 for (int ch='a'; ch <= 'z'; ch++) BoundChar.set(ch); 75 BoundChar.set('+'); 76 BoundChar.set('_'); 77 BoundChar.set('-'); 78 BoundChar.set('.'); 79 80 EBCDICUnsafeChar = new BitSet (256); 83 EBCDICUnsafeChar.set('!'); 84 EBCDICUnsafeChar.set('"'); 85 EBCDICUnsafeChar.set('#'); 86 EBCDICUnsafeChar.set('$'); 87 EBCDICUnsafeChar.set('@'); 88 EBCDICUnsafeChar.set('['); 89 EBCDICUnsafeChar.set('\\'); 90 EBCDICUnsafeChar.set(']'); 91 EBCDICUnsafeChar.set('^'); 92 EBCDICUnsafeChar.set('`'); 93 EBCDICUnsafeChar.set('{'); 94 EBCDICUnsafeChar.set('|'); 95 EBCDICUnsafeChar.set('}'); 96 EBCDICUnsafeChar.set('~'); 97 98 byte[] map = { 100 (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', 101 (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', 102 (byte)'M', (byte)'N', (byte)'O', (byte)'P', (byte)'Q', (byte)'R', 103 (byte)'S', (byte)'T', (byte)'U', (byte)'V', (byte)'W', (byte)'X', 104 (byte)'Y', (byte)'Z', 105 (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', 106 (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', 107 (byte)'m', (byte)'n', (byte)'o', (byte)'p', (byte)'q', (byte)'r', 108 (byte)'s', (byte)'t', (byte)'u', (byte)'v', (byte)'w', (byte)'x', 109 (byte)'y', (byte)'z', 110 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', 111 (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' }; 112 Base64EncMap = map; 113 Base64DecMap = new byte[128]; 114 for (int idx=0; idx<Base64EncMap.length; idx++) 115 Base64DecMap[Base64EncMap[idx]] = (byte) idx; 116 117 UUEncMap = new char[64]; 119 for (int idx=0; idx<UUEncMap.length; idx++) 120 UUEncMap[idx] = (char) (idx + 0x20); 121 UUDecMap = new byte[128]; 122 for (int idx=0; idx<UUEncMap.length; idx++) 123 UUDecMap[UUEncMap[idx]] = (byte) idx; 124 } 125 126 127 129 132 private Codecs() {} 133 134 135 137 145 public final static String base64Encode(String str) 146 { 147 if (str == null) return null; 148 149 byte data[] = new byte[str.length()]; 150 str.getBytes(0, str.length(), data, 0); 151 152 return new String (base64Encode(data), 0); 153 } 154 155 156 163 public final static byte[] base64Encode(byte[] data) 164 { 165 if (data == null) return null; 166 167 int sidx, didx; 168 byte dest[] = new byte[((data.length+2)/3)*4]; 169 170 171 for (sidx=0, didx=0; sidx < data.length-2; sidx += 3) 173 { 174 dest[didx++] = Base64EncMap[(data[sidx] >>> 2) & 077]; 175 dest[didx++] = Base64EncMap[(data[sidx+1] >>> 4) & 017 | 176 (data[sidx] << 4) & 077]; 177 dest[didx++] = Base64EncMap[(data[sidx+2] >>> 6) & 003 | 178 (data[sidx+1] << 2) & 077]; 179 dest[didx++] = Base64EncMap[data[sidx+2] & 077]; 180 } 181 if (sidx < data.length) 182 { 183 dest[didx++] = Base64EncMap[(data[sidx] >>> 2) & 077]; 184 if (sidx < data.length-1) 185 { 186 dest[didx++] = Base64EncMap[(data[sidx+1] >>> 4) & 017 | 187 (data[sidx] << 4) & 077]; 188 dest[didx++] = Base64EncMap[(data[sidx+1] << 2) & 077]; 189 } 190 else 191 dest[didx++] = Base64EncMap[(data[sidx] << 4) & 077]; 192 } 193 194 for ( ; didx < dest.length; didx++) 196 dest[didx] = (byte) '='; 197 198 return dest; 199 } 200 201 202 209 public final static String base64Decode(String str) 210 { 211 if (str == null) return null; 212 213 byte data[] = new byte[str.length()]; 214 str.getBytes(0, str.length(), data, 0); 215 216 return new String (base64Decode(data), 0); 217 } 218 219 220 227 public final static byte[] base64Decode(byte[] data) 228 { 229 if (data == null) return null; 230 231 int tail = data.length; 232 while (data[tail-1] == '=') tail--; 233 234 byte dest[] = new byte[tail - data.length/4]; 235 236 237 for (int idx = 0; idx <data.length; idx++) 239 data[idx] = Base64DecMap[data[idx]]; 240 241 int sidx, didx; 243 for (sidx = 0, didx=0; didx < dest.length-2; sidx += 4, didx += 3) 244 { 245 dest[didx] = (byte) ( ((data[sidx] << 2) & 255) | 246 ((data[sidx+1] >>> 4) & 003) ); 247 dest[didx+1] = (byte) ( ((data[sidx+1] << 4) & 255) | 248 ((data[sidx+2] >>> 2) & 017) ); 249 dest[didx+2] = (byte) ( ((data[sidx+2] << 6) & 255) | 250 (data[sidx+3] & 077) ); 251 } 252 if (didx < dest.length) 253 dest[didx] = (byte) ( ((data[sidx] << 2) & 255) | 254 ((data[sidx+1] >>> 4) & 003) ); 255 if (++didx < dest.length) 256 dest[didx] = (byte) ( ((data[sidx+1] << 4) & 255) | 257 ((data[sidx+2] >>> 2) & 017) ); 258 259 return dest; 260 } 261 262 263 276 public final static char[] uuencode(byte[] data) 277 { 278 if (data == null) return null; 279 if (data.length == 0) return new char[0]; 280 281 int line_len = 45; 283 int sidx, didx; 284 char nl[] = System.getProperty("line.separator", "\n").toCharArray(), 285 dest[] = new char[(data.length+2)/3*4 + 286 ((data.length+line_len-1)/line_len)*(nl.length+1)]; 287 288 for (sidx=0, didx=0; sidx+line_len < data.length; ) 290 { 291 dest[didx++] = UUEncMap[line_len]; 293 294 for (int end = sidx+line_len; sidx < end; sidx += 3) 296 { 297 dest[didx++] = UUEncMap[(data[sidx] >>> 2) & 077]; 298 dest[didx++] = UUEncMap[(data[sidx+1] >>> 4) & 017 | 299 (data[sidx] << 4) & 077]; 300 dest[didx++] = UUEncMap[(data[sidx+2] >>> 6) & 003 | 301 (data[sidx+1] << 2) & 077]; 302 dest[didx++] = UUEncMap[data[sidx+2] & 077]; 303 } 304 305 for (int idx=0; idx<nl.length; idx++) dest[didx++] = nl[idx]; 307 } 308 309 311 dest[didx++] = UUEncMap[data.length-sidx]; 313 314 for (; sidx+2 < data.length; sidx += 3) 316 { 317 dest[didx++] = UUEncMap[(data[sidx] >>> 2) & 077]; 318 dest[didx++] = UUEncMap[(data[sidx+1] >>> 4) & 017 | 319 (data[sidx] << 4) & 077]; 320 dest[didx++] = UUEncMap[(data[sidx+2] >>> 6) & 003 | 321 (data[sidx+1] << 2) & 077]; 322 dest[didx++] = UUEncMap[data[sidx+2] & 077]; 323 } 324 325 if (sidx < data.length-1) 326 { 327 dest[didx++] = UUEncMap[(data[sidx] >>> 2) & 077]; 328 dest[didx++] = UUEncMap[(data[sidx+1] >>> 4) & 017 | 329 (data[sidx] << 4) & 077]; 330 dest[didx++] = UUEncMap[(data[sidx+1] << 2) & 077]; 331 dest[didx++] = UUEncMap[0]; 332 } 333 else if (sidx < data.length) 334 { 335 dest[didx++] = UUEncMap[(data[sidx] >>> 2) & 077]; 336 dest[didx++] = UUEncMap[(data[sidx] << 4) & 077]; 337 dest[didx++] = UUEncMap[0]; 338 dest[didx++] = UUEncMap[0]; 339 } 340 341 for (int idx=0; idx<nl.length; idx++) dest[didx++] = nl[idx]; 343 344 if (didx != dest.length) 346 throw new Error ("Calculated "+dest.length+" chars but wrote "+didx+" chars!"); 347 348 return dest; 349 } 350 351 352 360 private final static byte[] uudecode(BufferedReader rdr) 361 throws ParseException, IOException  362 { 363 String line, file_name; 364 int file_mode; 365 366 367 369 while ((line = rdr.readLine()) != null && !line.startsWith("begin ")) 370 ; 371 if (line == null) 372 throw new ParseException("'begin' line not found"); 373 374 375 377 StringTokenizer tok = new StringTokenizer (line); 378 tok.nextToken(); try { file_mode = Integer.parseInt(tok.nextToken(), 8); } 381 catch (Exception e) 382 { throw new ParseException("Invalid mode on line: " + line); } 383 try { file_name = tok.nextToken(); } 385 catch (java.util.NoSuchElementException e) 386 { throw new ParseException("No file name found on line: " + line); } 387 388 389 391 byte[] body = new byte[1000]; 392 int off = 0; 393 394 while ((line = rdr.readLine()) != null && !line.equals("end")) 395 { 396 byte[] tmp = uudecode(line.toCharArray()); 397 if (off + tmp.length > body.length) 398 body = Util.resizeArray(body, off+1000); 399 System.arraycopy(tmp, 0, body, off, tmp.length); 400 off += tmp.length; 401 } 402 403 if (line == null) 404 throw new ParseException("'end' line not found"); 405 406 407 return Util.resizeArray(body, off); 408 } 409 410 411 421 public final static byte[] uudecode(char[] data) 422 { 423 if (data == null) return null; 424 425 int sidx, didx; 426 byte dest[] = new byte[data.length/4*3]; 427 428 429 for (sidx=0, didx=0; sidx < data.length; ) 430 { 431 int len = UUDecMap[data[sidx++]]; 433 434 int end = didx+len; 436 for (; didx < end-2; sidx += 4) 437 { 438 byte A = UUDecMap[data[sidx]], 439 B = UUDecMap[data[sidx+1]], 440 C = UUDecMap[data[sidx+2]], 441 D = UUDecMap[data[sidx+3]]; 442 dest[didx++] = (byte) ( ((A << 2) & 255) | ((B >>> 4) & 003) ); 443 dest[didx++] = (byte) ( ((B << 4) & 255) | ((C >>> 2) & 017) ); 444 dest[didx++] = (byte) ( ((C << 6) & 255) | (D & 077) ); 445 } 446 447 if (didx < end) 448 { 449 byte A = UUDecMap[data[sidx]], 450 B = UUDecMap[data[sidx+1]]; 451 dest[didx++] = (byte) ( ((A << 2) & 255) | ((B >>> 4) & 003) ); 452 } 453 if (didx < end) 454 { 455 byte B = UUDecMap[data[sidx+1]], 456 C = UUDecMap[data[sidx+2]]; 457 dest[didx++] = (byte) ( ((B << 4) & 255) | ((C >>> 2) & 017) ); 458 } 459 460 while (sidx < data.length && 462 data[sidx] != '\n' && data[sidx] != '\r') 463 sidx++; 464 465 while (sidx < data.length && 467 (data[sidx] == '\n' || data[sidx] == '\r')) 468 sidx++; 469 } 470 471 return Util.resizeArray(dest, didx); 472 } 473 474 475 483 public final static String quotedPrintableEncode(String str) 484 { 485 if (str == null) return null; 486 487 char map[] = 488 {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}, 489 nl[] = System.getProperty("line.separator", "\n").toCharArray(), 490 res[] = new char[(int) (str.length()*1.5)], 491 src[] = str.toCharArray(); 492 char ch; 493 int cnt = 0, 494 didx = 1, 495 last = 0, 496 slen = str.length(); 497 498 499 for (int sidx=0; sidx < slen; sidx++) 500 { 501 ch = src[sidx]; 502 503 if (ch == nl[0] && match(src, sidx, nl)) { 505 if (res[didx-1] == ' ') { 507 res[didx-1] = '='; 508 res[didx++] = '2'; 509 res[didx++] = '0'; 510 } 511 else if (res[didx-1] == '\t') { 513 res[didx-1] = '='; 514 res[didx++] = '0'; 515 res[didx++] = '9'; 516 } 517 518 res[didx++] = '\r'; 519 res[didx++] = '\n'; 520 sidx += nl.length - 1; 521 cnt = didx; 522 } 523 else if (ch > 126 || (ch < 32 && ch != '\t') || ch == '=' || 524 EBCDICUnsafeChar.get((int) ch)) 525 { res[didx++] = '='; 527 res[didx++] = map[(ch & 0xf0) >>> 4]; 528 res[didx++] = map[ch & 0x0f]; 529 } 530 else { 532 res[didx++] = ch; 533 } 534 535 if (didx > cnt+70) { 537 res[didx++] = '='; 538 res[didx++] = '\r'; 539 res[didx++] = '\n'; 540 cnt = didx; 541 } 542 543 if (didx > res.length-5) 544 res = Util.resizeArray(res, res.length+500); 545 } 546 547 return String.valueOf(res, 1, didx-1); 548 } 549 550 private final static boolean match(char[] str, int start, char[] arr) 551 { 552 if (str.length < start + arr.length) return false; 553 554 for (int idx=1; idx < arr.length; idx++) 555 if (str[start+idx] != arr[idx]) return false; 556 return true; 557 } 558 559 560 570 public final static String quotedPrintableDecode(String str) 571 throws ParseException 572 { 573 if (str == null) return null; 574 575 char res[] = new char[(int) (str.length()*1.1)], 576 src[] = str.toCharArray(), 577 nl[] = System.getProperty("line.separator", "\n").toCharArray(); 578 int last = 0, 579 didx = 0, 580 slen = str.length(); 581 582 583 for (int sidx=0; sidx<slen; ) 584 { 585 char ch = src[sidx++]; 586 587 if (ch == '=') 588 { 589 if (sidx >= slen-1) 590 throw new ParseException("Premature end of input detected"); 591 592 if (src[sidx] == '\n' || src[sidx] == '\r') 593 { sidx++; 595 596 if (src[sidx-1] == '\r' && 597 src[sidx] == '\n') 598 sidx++; 599 } 600 else { 602 char repl; 603 int hi = Character.digit(src[sidx], 16), 604 lo = Character.digit(src[sidx+1], 16); 605 606 if ((hi | lo) < 0) 607 throw new ParseException(new String (src, sidx-1, 3) + 608 " is an invalid code"); 609 else 610 { 611 repl = (char) (hi << 4 | lo); 612 sidx += 2; 613 } 614 615 res[didx++] = repl; 616 } 617 last = didx; 618 } 619 else if (ch == '\n' || ch == '\r') { 621 if (ch == '\r' && sidx < slen && src[sidx] == '\n') 622 sidx++; 623 for (int idx=0; idx<nl.length; idx++) 624 res[last++] = nl[idx]; 625 didx = last; 626 } 627 else { 629 res[didx++] = ch; 630 if (ch != ' ' && ch != '\t') last = didx; 632 } 633 634 if (didx > res.length-nl.length-2) 635 res = Util.resizeArray(res, res.length+500); 636 } 637 638 return new String (res, 0, didx); 639 } 640 641 642 649 public final static String URLEncode(String str) 650 { 651 if (str == null) return null; 652 653 return java.net.URLEncoder.encode(str); 654 } 655 656 657 665 public final static String URLDecode(String str) throws ParseException 666 { 667 if (str == null) return null; 668 669 char[] res = new char[str.length()]; 670 int didx = 0; 671 672 for (int sidx=0; sidx<str.length(); sidx++) 673 { 674 char ch = str.charAt(sidx); 675 if (ch == '+') 676 res[didx++] = ' '; 677 else if (ch == '%') 678 { 679 try 680 { 681 res[didx++] = (char) 682 Integer.parseInt(str.substring(sidx+1,sidx+3), 16); 683 sidx += 2; 684 } 685 catch (NumberFormatException e) 686 { 687 throw new ParseException(str.substring(sidx,sidx+3) + 688 " is an invalid code"); 689 } 690 } 691 else 692 res[didx++] = ch; 693 } 694 695 return String.valueOf(res, 0, didx); 696 } 697 698 699 715 public final static NVPair[] mpFormDataDecode(byte[] data, String cont_type, 716 String dir) 717 throws IOException , ParseException 718 { 719 return mpFormDataDecode(data, cont_type, dir, null); 720 } 721 722 723 777 public final static NVPair[] mpFormDataDecode(byte[] data, String cont_type, 778 String dir, 779 FilenameMangler mangler) 780 throws IOException , ParseException 781 { 782 784 String bndstr = Util.getParameter("boundary", cont_type); 785 if (bndstr == null) 786 throw new ParseException("'boundary' parameter not found in Content-type: " + cont_type); 787 788 byte[] srtbndry = new byte[bndstr.length()+4], 789 boundary = new byte[bndstr.length()+6], 790 endbndry = new byte[bndstr.length()+6]; 791 792 ( "--" + bndstr + "\r\n").getBytes(0, srtbndry.length, srtbndry, 0); 793 ("\r\n--" + bndstr + "\r\n").getBytes(0, boundary.length, boundary, 0); 794 ("\r\n--" + bndstr + "--" ).getBytes(0, endbndry.length, endbndry, 0); 795 796 797 799 int[] bs = Util.compile_search(srtbndry), 800 bc = Util.compile_search(boundary), 801 be = Util.compile_search(endbndry); 802 803 804 806 int start = Util.findStr(srtbndry, bs, data, 0, data.length); 807 if (start == -1) throw new ParseException("Starting boundary not found: " + 809 new String (srtbndry,0)); 810 start += srtbndry.length; 811 812 NVPair[] res = new NVPair[10]; 813 boolean done = false; 814 int idx; 815 816 for (idx=0; !done; idx++) 817 { 818 820 int end = Util.findStr(boundary, bc, data, start, data.length); 821 if (end == -1) { 823 end = Util.findStr(endbndry, be, data, start, data.length); 824 if (end == -1) 825 throw new ParseException("Ending boundary not found: " + 826 new String (endbndry,0)); 827 done = true; 828 } 829 830 832 String hdr, name=null, value, filename=null, cont_disp = null; 833 834 while (true) 835 { 836 int next = findEOL(data, start) + 2; 837 if (next-2 <= start) break; hdr = new String (data, 0, start, next-2-start); 839 start = next; 840 841 byte ch; 843 while (next < data.length-1 && 844 ((ch = data[next]) == ' ' || ch == '\t')) 845 { 846 next = findEOL(data, start) + 2; 847 hdr += new String (data, 0, start, next-2-start); 848 start = next; 849 } 850 851 if (!hdr.regionMatches(true, 0, "Content-Disposition", 0, 19)) 852 continue; 853 Vector pcd = 854 Util.parseHeader(hdr.substring(hdr.indexOf(':')+1)); 855 HttpHeaderElement elem = Util.getElement(pcd, "form-data"); 856 857 if (elem == null) 858 throw new ParseException("Expected 'Content-Disposition: form-data' in line: "+hdr); 859 860 NVPair[] params = elem.getParams(); 861 name = filename = null; 862 for (int pidx=0; pidx<params.length; pidx++) 863 { 864 |