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 if (params[pidx].getName().equalsIgnoreCase("name")) 865 name = params[pidx].getValue(); 866 if (params[pidx].getName().equalsIgnoreCase("filename")) 867 filename = params[pidx].getValue(); 868 } 869 if (name == null) 870 throw new ParseException("'name' parameter not found in header: "+hdr); 871 872 cont_disp = hdr; 873 } 874 875 start += 2; 876 if (start > end) 877 throw new ParseException("End of header not found at offset "+end); 878 879 if (cont_disp == null) 880 throw new ParseException("Missing 'Content-Disposition' header at offset "+start); 881 882 884 if (filename != null) { 886 if (mangler != null) 887 filename = mangler.mangleFilename(filename, name); 888 if (filename != null) 889 { 890 File file = new File (dir, filename); 891 FileOutputStream out = new FileOutputStream (file); 892 893 out.write(data, start, end-start); 894 out.close(); 895 } 896 897 value = filename; 898 } 899 else { 901 value = new String (data, 0, start, end-start); 902 } 903 904 if (idx >= res.length) 905 res = Util.resizeArray(res, idx+10); 906 res[idx] = new NVPair(name, value); 907 908 start = end + boundary.length; 909 } 910 911 return Util.resizeArray(res, idx); 912 } 913 914 915 922 private final static int findEOL(byte[] arr, int off) 923 { 924 while (off < arr.length-1 && 925 !(arr[off++] == '\r' && arr[off] == '\n')); 926 return off-1; 927 } 928 929 957 public final static byte[] mpFormDataEncode(NVPair[] opts, NVPair[] files, 958 NVPair[] cont_type) 959 throws IOException 960 { 961 return mpFormDataEncode(opts, files, cont_type, null); 962 } 963 964 965 private static NVPair[] dummy = new NVPair[0]; 966 967 1022 public final static byte[] mpFormDataEncode(NVPair[] opts, NVPair[] files, 1023 NVPair[] cont_type, 1024 FilenameMangler mangler) 1025 throws IOException 1026 { 1027 int len = 0, 1028 hdr_len = 2 + 2 + 70 + 2 + 39 + 2 + 2; 1029 byte[] boundary = new byte[74], 1031 cont_disp = new byte[40], 1032 filename = new byte[13]; 1033 1034 ContDisp.getBytes(0, ContDisp.length(), cont_disp, 0); 1035 FileName.getBytes(0, FileName.length(), filename, 0); 1036 Boundary.getBytes(0, Boundary.length(), boundary, 0); 1037 1038 if (opts == null) opts = dummy; 1039 if (files == null) files = dummy; 1040 1041 1042 1044 for (int idx=0; idx<opts.length; idx++) 1045 len += hdr_len + opts[idx].getName().length() + 1046 opts[idx].getValue().length(); 1047 1048 for (int idx=0; idx<files.length; idx++) 1049 { 1050 File file = new File (files[idx].getValue()); 1051 String fname = file.getName(); 1052 if (mangler != null) 1053 fname = mangler.mangleFilename(fname, files[idx].getName()); 1054 if (fname != null) 1055 { 1056 len += hdr_len + files[idx].getName().length() + 13; 1057 len += fname.length() + file.length(); 1058 } 1059 } 1060 1061 len -= 2; len += 2 + 2 + 70 + 2 + 2; 1064 1065 1067 byte[] res = new byte[len]; 1068 int pos = 0; 1069 1070 NewBound: for (int new_c=0x30303030; new_c!=0x7A7A7A7A; new_c++) 1071 { 1072 pos = 0; 1073 1074 while (!BoundChar.get(new_c & 0xff)) new_c += 0x00000001; 1076 while (!BoundChar.get(new_c>>8 & 0xff)) new_c += 0x00000100; 1077 while (!BoundChar.get(new_c>>16 & 0xff)) new_c += 0x00010000; 1078 while (!BoundChar.get(new_c>>24 & 0xff)) new_c += 0x01000000; 1079 boundary[40] = (byte) (new_c & 0xff); 1080 boundary[42] = (byte) (new_c>>8 & 0xff); 1081 boundary[44] = (byte) (new_c>>16 & 0xff); 1082 boundary[46] = (byte) (new_c>>24 & 0xff); 1083 1084 int off = 2; 1085 int[] bnd_cmp = Util.compile_search(boundary); 1086 1087 for (int idx=0; idx<opts.length; idx++) 1088 { 1089 System.arraycopy(boundary, off, res, pos, boundary.length-off); 1090 pos += boundary.length - off; 1091 off = 0; 1092 System.arraycopy(cont_disp, 0, res, pos, cont_disp.length); 1093 pos += cont_disp.length; 1094 1095 int nlen = opts[idx].getName().length(); 1096 opts[idx].getName().getBytes(0, nlen, res, pos); 1097 if (nlen >= boundary.length && 1098 Util.findStr(boundary, bnd_cmp, res, pos, pos+nlen) != -1) 1099 continue NewBound; 1100 pos += nlen; 1101 1102 res[pos++] = (byte) '"'; 1103 res[pos++] = (byte) '\r'; 1104 res[pos++] = (byte) '\n'; 1105 res[pos++] = (byte) '\r'; 1106 res[pos++] = (byte) '\n'; 1107 1108 int vlen = opts[idx].getValue().length(); 1109 opts[idx].getValue().getBytes(0, vlen, res, pos); 1110 if (vlen >= boundary.length && 1111 Util.findStr(boundary, bnd_cmp, res, pos, pos+vlen) != -1) 1112 continue NewBound; 1113 pos += vlen; 1114 } 1115 1116 for (int idx=0; idx<files.length; idx++) 1117 { 1118 File file = new File (files[idx].getValue()); 1119 String fname = file.getName(); 1120 if (mangler != null) 1121 fname = mangler.mangleFilename(fname, files[idx].getName()); 1122 if (fname == null) continue; 1123 1124 System.arraycopy(boundary, off, res, pos, boundary.length-off); 1125 pos += boundary.length - off; 1126 off = 0; 1127 System.arraycopy(cont_disp, 0, res, pos, cont_disp.length); 1128 pos += cont_disp.length; 1129 1130 int nlen = files[idx].getName().length(); 1131 files[idx].getName().getBytes(0, nlen, res, pos); 1132 if (nlen >= boundary.length && 1133 Util.findStr(boundary, bnd_cmp, res, pos, pos+nlen) != -1) 1134 continue NewBound; 1135 pos += nlen; 1136 1137 System.arraycopy(filename, 0, res, pos, filename.length); 1138 pos += filename.length; 1139 1140 nlen = fname.length(); 1141 fname.getBytes(0, nlen, res, pos); 1142 if (nlen >= boundary.length && 1143 Util.findStr(boundary, bnd_cmp, res, pos, pos+nlen) != -1) 1144 continue NewBound; 1145 pos += nlen; 1146 1147 res[pos++] = (byte) '"'; 1148 res[pos++] = (byte) '\r'; 1149 res[pos++] = (byte) '\n'; 1150 res[pos++] = (byte) '\r'; 1151 res[pos++] = (byte) '\n'; 1152 1153 nlen = (int) file.length(); 1154 int opos = pos; 1155 FileInputStream fin = new FileInputStream (file); 1156 while (nlen > 0) 1157 { 1158 int got = fin.read(res, pos, nlen); 1159 nlen -= got; 1160 pos += got; 1161 } 1162 if (Util.findStr(boundary, bnd_cmp, res, opos, pos) != -1) 1163 continue NewBound; 1164 } 1165 1166 break NewBound; 1167 } 1168 1169 System.arraycopy(boundary, 0, res, pos, boundary.length); 1170 pos += boundary.length; 1171 res[pos++] = (byte) '-'; 1172 res[pos++] = (byte) '-'; 1173 res[pos++] = (byte) '\r'; 1174 res[pos++] = (byte) '\n'; 1175 1176 if (pos != len) 1177 throw new Error ("Calculated "+len+" bytes but wrote "+pos+" bytes!"); 1178 1179 1183 cont_type[0] = new NVPair("Content-Type", 1184 "multipart/form-data; boundary=" + 1185 new String (boundary, 0, 4, 70)); 1186 1187 return res; 1188 } 1189 1190 1191 1200 public final static String nv2query(NVPair pairs[]) 1201 { 1202 if (pairs == null) 1203 return null; 1204 1205 1206 int idx; 1207 StringBuffer qbuf = new StringBuffer (); 1208 1209 for (idx = 0; idx < pairs.length; idx++) 1210 { 1211 qbuf.append(URLEncode(pairs[idx].getName()) + "=" + 1212 URLEncode(pairs[idx].getValue()) + "&"); 1213 } 1214 1215 if (idx > 0) 1216 qbuf.setLength(qbuf.length()-1); 1218 return qbuf.toString(); 1219 } 1220 1221 1222 1233 public final static NVPair[] query2nv(String query) throws ParseException 1234 { 1235 if (query == null) return null; 1236 1237 int idx = -1, 1238 cnt = 1; 1239 while ((idx = query.indexOf('&', idx+1)) != -1) cnt ++; 1240 NVPair[] pairs = new NVPair[cnt]; 1241 1242 for (idx=0, cnt=0; cnt<pairs.length; cnt++) 1243 { 1244 int eq = query.indexOf('=', idx); 1245 int end = query.indexOf('&', idx); 1246 1247 if (end == -1) end = query.length(); 1248 1249 if (eq == -1 || eq >= end) 1250 throw new ParseException("'=' missing in " + 1251 query.substring(idx, end)); 1252 1253 pairs[cnt] = 1254 new NVPair(URLDecode(query.substring(idx,eq)), 1255 URLDecode(query.substring(eq+1,end))); 1256 1257 idx = end + 1; 1258 } 1259 1260 return pairs; 1261 } 1262 1263 1264 1275 public final static byte[] chunkedEncode(byte[] data, NVPair[] ftrs, 1276 boolean last) 1277 { 1278 return 1279 chunkedEncode(data, 0, data == null ? 0 : data.length, ftrs, last); 1280 } 1281 1282 1283 1296 public final static byte[] chunkedEncode(byte[] data, int off, int len, 1297 NVPair[] ftrs, boolean last) 1298 { 1299 if (data == null) 1300 { 1301 data = new byte[0]; 1302 len = 0; 1303 } 1304 if (last && ftrs == null) ftrs = new NVPair[0]; 1305 1306 String hex_len = Integer.toString(len, 16); 1308 1309 1310 1312 int res_len = 0; 1313 if (len > 0) res_len += hex_len.length() + 2 + len + 2; 1315 1316 if (last) 1317 { 1318 res_len += 1 + 2; for (int idx=0; idx<ftrs.length; idx++) 1320 res_len += ftrs[idx].getName().length() + 2 + ftrs[idx].getValue().length() + 2; res_len += 2; } 1324 1325 1327 byte[] res = new byte[res_len]; 1328 int r_off = 0; 1329 1330 1331 1333 if (len > 0) 1334 { 1335 hex_len.getBytes(0, hex_len.length(), res, r_off); 1336 r_off += hex_len.length(); 1337 res[r_off++] = (byte) '\r'; 1338 res[r_off++] = (byte) '\n'; 1339 1340 System.arraycopy(data, off, res, r_off, len); 1341 r_off += len; 1342 res[r_off++] = (byte) '\r'; 1343 res[r_off++] = (byte) '\n'; 1344 } 1345 1346 if (last) 1347 { 1348 res[r_off++] = (byte) '0'; 1349 res[r_off++] = (byte) '\r'; 1350 res[r_off++] = (byte) '\n'; 1351 1352 for (int idx=0; idx<ftrs.length; idx++) 1353 { 1354 ftrs[idx].getName().getBytes(0, ftrs[idx].getName().length(), 1355 res, r_off); 1356 r_off += ftrs[idx].getName().length(); 1357 1358 res[r_off++] = (byte) ':'; 1359 res[r_off++] = (byte) ' '; 1360 1361 ftrs[idx].getValue().getBytes(0, ftrs[idx].getValue().length(), 1362 res, r_off); 1363 r_off += ftrs[idx].getValue().length(); 1364 1365 res[r_off++] = (byte) '\r'; 1366 res[r_off++] = (byte) '\n'; 1367 } 1368 1369 res[r_off++] = (byte) '\r'; 1370 res[r_off++] = (byte) '\n'; 1371 } 1372 1373 if (r_off != res.length) 1374 throw new Error ("Calculated "+res.length+" bytes but wrote "+r_off+" bytes!"); 1375 1376 return res; 1377 } 1378 1379 1380 1393 public final static Object chunkedDecode(InputStream input) 1394 throws ParseException, IOException 1395 { 1396 int len = getChunkLength(input); 1397 1398 if (len > 0) { 1400 byte[] res = new byte[len]; 1401 1402 int off = 0; 1403 while (len != -1 && off < res.length) 1404 { 1405 len = input.read(res, off, res.length-off); 1406 off += len; 1407 } 1408 1409 if (len == -1) 1410 throw new ParseException("Premature EOF while reading chunk;" + 1411 "Expected: "+res.length+" Bytes, " + 1412 "Received: "+(off+1)+" Bytes"); 1413 1414 input.read(); input.read(); 1417 return res; 1418 } 1419 else { 1421 NVPair[] res = new NVPair[0]; 1422 1423 DataInputStream datain = new DataInputStream (input); 1424 String line; 1425 1426 while ((line = datain.readLine()) != null && line.length() > 0) 1428 { 1429 int colon = line.indexOf(':'); 1430 if (colon == -1) 1431 throw new ParseException("Error in Footer format: no "+ 1432 "':' found in '" + line + "'"); 1433 res = Util.resizeArray(res, res.length+1); 1434 res[res.length-1] = new NVPair(line.substring(0, colon).trim(), 1435 line.substring(colon+1).trim()); 1436 } 1437 1438 return res; 1439 } 1440 1441 } 1442 1443 1444 1452 final static int getChunkLength(InputStream input) 1453 throws ParseException, IOException 1454 { 1455 byte[] hex_len = new byte[8]; int off = 0, 1457 ch; 1458 1459 1460 1462 while ((ch = input.read()) != '\r' && ch != '\n' && 1463 ch != ';' && off < hex_len.length) 1464 hex_len[off++] = (byte) ch; 1465 1466 if (ch == ';') while ((ch = input.read()) != '\r' && ch != '\n') ; 1468 1469 if (ch != '\n' && (ch != '\r' || input.read() != '\n')) 1470 throw new ParseException("Didn't find valid chunk length: " + 1471 new String (hex_len, 0, 0, off)); 1472 1473 1475 int len; 1476 try 1477 { len = Integer.parseInt(new String (hex_len, 0, 0, off).trim(), 1478 16); } 1479 catch (NumberFormatException nfe) 1480 { throw new ParseException("Didn't find valid chunk length: " + 1481 new String (hex_len, 0, 0, off) ); } 1482 1483 return len; 1484 } 1485 1486} 1487 1488 | Popular Tags |