1 29 30 package com.caucho.quercus.lib; 31 32 import com.caucho.quercus.Quercus; 33 import com.caucho.quercus.QuercusException; 34 import com.caucho.quercus.QuercusModuleException; 35 import com.caucho.quercus.annotation.Optional; 36 import com.caucho.quercus.annotation.Reference; 37 import com.caucho.quercus.annotation.UsesSymbolTable; 38 import com.caucho.quercus.env.*; 39 import com.caucho.quercus.lib.file.FileModule; 40 import com.caucho.quercus.module.AbstractQuercusModule; 41 import com.caucho.quercus.program.QuercusProgram; 42 import com.caucho.util.L10N; 43 import com.caucho.util.RandomUtil; 44 import com.caucho.vfs.*; 45 46 import java.io.IOException ; 47 import java.io.InputStream ; 48 import java.io.OutputStream ; 49 import java.util.ArrayList ; 50 import java.util.Map ; 51 import java.util.logging.Level ; 52 import java.util.logging.Logger ; 53 import java.util.regex.Matcher ; 54 import java.util.regex.Pattern ; 55 56 59 public class MiscModule extends AbstractQuercusModule { 60 private static final L10N L = new L10N(MiscModule.class); 61 private static final Logger log 62 = Logger.getLogger(MiscModule.class.getName()); 63 64 67 public static String escapeshellcmd(String command) 68 { 69 StringBuilder sb = new StringBuilder (); 70 int len = command.length(); 71 72 boolean hasApos = false; 73 boolean hasQuot = false; 74 75 for (int i = 0; i < len; i++) { 76 char ch = command.charAt(i); 77 78 switch (ch) { 79 case '#': case '&': case ';': case '`': case '|': 80 case '*': case '?': case '~': case '<': case '>': 81 case '^': case '(': case ')': case '[': case ']': 82 case '{': case '}': case '$': case '\\': case ',': 83 case 0x0a: case 0xff: 84 sb.append('\\'); 85 sb.append(ch); 86 break; 87 case '\'': 88 hasApos = ! hasApos; 89 sb.append(ch); 90 break; 91 case '\"': 92 hasQuot = ! hasQuot; 93 sb.append(ch); 94 break; 95 default: 96 sb.append(ch); 97 } 98 } 99 100 String result = sb.toString(); 101 102 if (hasApos) { 103 int p = result.lastIndexOf('\''); 104 result = result.substring(0, p) + "\\" + result.substring(p); 105 } 106 107 if (hasQuot) { 108 int p = result.lastIndexOf('\"'); 109 result = result.substring(0, p) + "\\" + result.substring(p); 110 } 111 112 return result; 113 } 114 115 118 public static String escapeshellarg(String arg) 119 { 120 StringBuilder sb = new StringBuilder (); 121 122 sb.append('\''); 123 124 int len = arg.length(); 125 126 for (int i = 0; i < len; i++) { 127 char ch = arg.charAt(i); 128 129 if (ch == '\'') 130 sb.append("\\\'"); 131 else 132 sb.append(ch); 133 } 134 135 sb.append('\''); 136 137 return sb.toString(); 138 } 139 140 143 @UsesSymbolTable 144 public Value eval(Env env, String code) 145 { 146 try { 147 if (log.isLoggable(Level.FINER)) 148 log.finer(code); 149 150 Quercus quercus = env.getQuercus(); 151 152 QuercusProgram program = quercus.parseCode(code); 153 154 Value value = program.execute(env); 155 156 return value; 157 } catch (IOException e) { 158 throw new QuercusException(e); 159 } 160 } 161 162 165 public Value pack(Env env, String format, Value []args) 166 { 167 try { 168 ArrayList <PackSegment> segments = parsePackFormat(format); 169 170 BinaryBuilderValue bb = new BinaryBuilderValue(); 171 172 int i = 0; 173 for (PackSegment segment : segments) { 174 i = segment.pack(env, bb, i, args); 175 } 176 177 return bb; 178 } catch (IOException e) { 179 throw new QuercusModuleException(e); 180 } 181 } 182 183 186 public Value unpack(Env env, String format, InputStream is) 187 { 188 try { 189 ArrayList <PackSegment> segments = parseUnpackFormat(format); 190 191 ArrayValue array = new ArrayValueImpl(); 192 193 for (PackSegment segment : segments) { 194 segment.unpack(env, array, is); 195 } 196 197 return array; 198 } catch (IOException e) { 199 throw new QuercusModuleException(e); 200 } 201 } 202 203 206 public Value resin_debug(String code) 207 { 208 log.info(code); 209 210 return NullValue.NULL; 211 } 212 213 216 public Value resin_thread_dump() 217 { 218 Thread.dumpStack(); 219 220 return NullValue.NULL; 221 } 222 223 226 public static Value dump_stack(Env env) 227 { 228 try { 229 Exception e = new Exception ("Stack trace"); 230 e.fillInStackTrace(); 231 232 WriteStream out = env.getPwd().lookup("stderr:").openWrite(); 233 try { 234 e.printStackTrace(out.getPrintWriter()); 235 } finally { 237 out.close(); 238 } 239 240 return NullValue.NULL; 241 } catch (IOException e) { 242 throw new QuercusModuleException(e); 243 } 244 } 245 246 249 public static String exec(Env env, String command, 250 @Optional Value output, 251 @Optional @Reference Value result) 252 { 253 String []args = new String [3]; 254 255 try { 256 args[0] = "sh"; 257 args[1] = "-c"; 258 args[2] = command; 259 Process process = Runtime.getRuntime().exec(args); 260 261 InputStream is = process.getInputStream(); 262 OutputStream os = process.getOutputStream(); 263 os.close(); 264 265 StringBuilder sb = new StringBuilder (); 266 String line = ""; 267 268 int ch; 269 boolean hasCr = false; 270 while ((ch = is.read()) >= 0) { 271 if (ch == '\n') { 272 if (! hasCr) { 273 line = sb.toString(); 274 sb.setLength(0); 275 if (output != null) 276 output.put(new StringValueImpl(line)); 277 } 278 hasCr = false; 279 } 280 else if (ch == '\r') { 281 line = sb.toString(); 282 sb.setLength(0); 283 output.put(new StringValueImpl(line)); 284 hasCr = true; 285 } 286 else 287 sb.append((char) ch); 288 } 289 290 if (sb.length() > 0) { 291 line = sb.toString(); 292 sb.setLength(0); 293 output.put(new StringValueImpl(line)); 294 } 295 296 is.close(); 297 298 int status = process.waitFor(); 299 300 result.set(new LongValue(status)); 301 302 return line; 303 } catch (Exception e) { 304 env.warning(e.getMessage(), e); 305 306 return null; 307 } 308 } 309 310 313 public static Value shell_exec(Env env, String command) 314 { 315 String []args = new String [3]; 316 317 try { 318 args[0] = "sh"; 319 args[1] = "-c"; 320 args[2] = command; 321 Process process = Runtime.getRuntime().exec(args); 322 323 InputStream is = process.getInputStream(); 324 OutputStream os = process.getOutputStream(); 325 os.close(); 326 327 StringBuilderValue sb = new StringBuilderValue(); 328 329 int ch; 330 boolean hasCr = false; 331 while ((ch = is.read()) >= 0) { 332 sb.append((char) ch); 333 } 334 335 is.close(); 336 337 int status = process.waitFor(); 338 339 return sb; 340 } catch (Exception e) { 341 env.warning(e.getMessage(), e); 342 343 return NullValue.NULL; 344 } 345 } 346 347 350 public static void passthru(Env env, String command, 351 @Optional @Reference Value result) 352 { 353 354 try { 355 String []args = new String [3]; 356 args[0] = "sh"; 357 args[1] = "-c"; 358 args[2] = command; 359 360 ProcessBuilder processBuilder = new ProcessBuilder (args); 361 processBuilder.redirectErrorStream(true); 362 final Process process = processBuilder.start(); 363 364 try { 365 InputStream is = process.getInputStream(); 366 OutputStream os = process.getOutputStream(); 367 os.close(); 368 369 env.getOut().writeStream(is); 370 is.close(); 371 372 int status = process.waitFor(); 373 } 374 finally { 375 process.destroy(); 376 } 377 } catch (Exception e) { 378 env.warning(e.getMessage(), e); 379 } 380 } 381 382 385 public static int ignore_user_abort(@Optional boolean set) 386 { 387 return 0; 388 } 389 390 393 public String uniqid(@Optional String prefix, @Optional boolean moreEntropy) 394 { 395 StringBuilder sb = new StringBuilder (); 396 397 if (prefix != null) 398 sb.append(prefix); 399 400 addUnique(sb); 401 402 if (moreEntropy) 403 addUnique(sb); 404 405 return sb.toString(); 406 } 407 408 private void addUnique(StringBuilder sb) 409 { 410 long value = RandomUtil.getRandomLong(); 411 412 if (value < 0) 413 value = -value; 414 415 int limit = 13; 416 417 for (; limit > 0; limit--) { 418 long digit = value % 26; 419 value = value / 26; 420 421 sb.append((char) ('a' + digit)); 422 } 423 } 424 425 428 public static Value usleep(long microseconds) 429 { 430 try { 431 Thread.sleep(microseconds / 1000); 432 } catch (Throwable e) { 433 } 434 435 return NullValue.NULL; 436 } 437 438 441 public static long sleep(long seconds) 442 { 443 try { 444 Thread.sleep(seconds * 1000); 445 } catch (Throwable e) { 446 } 447 448 return seconds; 449 } 450 451 459 public static Value get_browser( 460 Env env, 461 @Optional() String user_agent, 462 @Optional() boolean return_array) 463 { 464 if (user_agent == null || 465 user_agent.length() == 0) 466 user_agent = env.getRequest().getHeader("User-Agent"); 467 468 if (user_agent == null) { 469 env.warning(L.l("HTTP_USER_AGENT not set.")); 470 return BooleanValue.FALSE; 471 } 472 473 Value browscap = env.getConfigVar("browscap"); 474 if (browscap == null) { 475 env.warning(L.l("Browscap path not set in PHP.ini.")); 476 return BooleanValue.FALSE; 477 } 478 479 Path path = env.lookup(browscap.toString()); 480 if (path == null) { 481 env.warning(L.l("Browscap file not found.")); 482 return BooleanValue.FALSE; 483 } 484 485 Value ini = FileModule.parse_ini_file(env, path, true); 486 if (ini == BooleanValue.FALSE) 487 return BooleanValue.FALSE; 488 489 return getBrowserReport( 490 env, ini.toArrayValue(env), user_agent, return_array); 491 } 492 493 private static Value getBrowserReport( 494 Env env, 495 ArrayValue browsers, 496 String user_agent, 497 boolean return_array) 498 { 499 StringValue patternMatched = StringValue.EMPTY; 500 String regExpMatched = null; 501 502 for (Map.Entry <Value,Value> entry : browsers.entrySet()) { 503 StringValue pattern = entry.getKey().toStringValue(); 504 505 if (pattern.toString().equals(user_agent)) { 506 patternMatched = pattern; 507 regExpMatched = null; 508 break; 509 } 510 511 String regExp = formatBrowscapRegexp(pattern); 512 Matcher m = Pattern.compile(regExp).matcher(user_agent); 513 514 if (m.matches()) { 516 if (pattern.length() > patternMatched.length()) { 517 patternMatched = pattern; 518 regExpMatched = regExp; 519 } 520 } 521 } 522 523 if (patternMatched.length() == 0) 524 return BooleanValue.FALSE; 525 526 return prepareBrowserReport(env, browsers, patternMatched, regExpMatched, 527 user_agent, return_array); 528 } 529 530 private static Value prepareBrowserReport( 531 Env env, 532 ArrayValue browsers, 533 StringValue patternMatched, 534 String regExpMatched, 535 String user_agent, 536 boolean return_array) 537 { 538 ArrayValue capabilities = browsers.get(patternMatched).toArrayValue(env); 539 540 if (regExpMatched == null) 541 capabilities.put( 542 new StringValueImpl("browser_name_regex"), patternMatched); 543 else 544 capabilities.put("browser_name_regex", regExpMatched); 545 capabilities.put( 546 new StringValueImpl("browser_name_pattern"), patternMatched); 547 548 addBrowserCapabilities(env, browsers, 549 capabilities.get(new StringValueImpl("parent")), capabilities); 550 551 if (return_array) { 552 ArrayValue array = new ArrayValueImpl(); 553 array.put(new StringValueImpl(user_agent), capabilities); 554 return array; 555 } 556 557 ObjectValue object = env.createObject(); 558 for (Map.Entry <Value,Value> entry : capabilities.entrySet()) { 559 object.putFieldInit(env, entry.getKey().toString(), entry.getValue()); 560 } 561 562 return object; 563 } 564 565 private static void addBrowserCapabilities( 566 Env env, 567 ArrayValue browsers, 568 Value browser, 569 ArrayValue cap) 570 { 571 if (browser == UnsetValue.UNSET) 572 return; 573 574 Value field = null; 575 if ((field = browsers.get(browser)) == UnsetValue.UNSET) 576 return; 577 578 ArrayValue browserCapabilities = field.toArrayValue(env); 579 StringValue parentString = new StringValueImpl("parent"); 580 581 for (Map.Entry <Value,Value> entry : browserCapabilities.entrySet()) { 582 Value key = entry.getKey(); 583 584 if (key.equals(parentString)) { 585 addBrowserCapabilities( 586 env, browsers, entry.getValue(), cap); 587 } 588 else if (cap.containsKey(key) == null) 589 cap.put(key, entry.getValue()); 590 } 591 } 592 593 private static String formatBrowscapRegexp(StringValue key) 594 { 595 int length = key.length(); 596 597 StringBuilder sb = new StringBuilder (); 598 for (int i = 0; i < length; i++) { 599 char ch = key.charAt(i); 600 switch (ch) { 601 case '*': 602 sb.append('.'); 603 sb.append('*'); 604 break; 605 case '?': 606 sb.append('.'); 607 break; 608 case '.': 609 sb.append('\\'); 610 sb.append('.'); 611 break; 612 case '+': 613 sb.append('\\'); 614 sb.append('+'); 615 break; 616 case '(': 617 sb.append('\\'); 618 sb.append('('); 619 break; 620 case ')': 621 sb.append('\\'); 622 sb.append(')'); 623 break; 624 case '{': 625 sb.append('\\'); 626 sb.append('{'); 627 break; 628 case '}': 629 sb.append('\\'); 630 sb.append('}'); 631 break; 632 case ']': 633 sb.append('\\'); 634 sb.append(']'); 635 break; 636 case '[': 637 sb.append('\\'); 638 sb.append('['); 639 break; 640 case '\\': 641 sb.append('\\'); 642 sb.append('\\'); 643 break; 644 case '^': 645 sb.append('\\'); 646 sb.append('^'); 647 break; 648 case '$': 649 sb.append('\\'); 650 sb.append('$'); 651 break; 652 case '&': 653 sb.append('\\'); 654 sb.append('&'); 655 break; 656 case '|': 657 sb.append('\\'); 658 sb.append('|'); 659 break; 660 default: 661 sb.append(ch); 662 } 663 } 664 665 return sb.toString(); 666 } 667 668 671 public static String system(Env env, String command, 672 @Optional @Reference Value result) 673 { 674 return exec(env, command, null, result); 675 } 676 677 private static ArrayList <PackSegment> parsePackFormat(String format) 678 { 679 ArrayList <PackSegment> segments = new ArrayList <PackSegment>(); 680 681 int length = format.length(); 682 for (int i = 0; i < length; i++) { 683 char ch = format.charAt(i); 684 685 int count = 0; 686 char ch1 = ' '; 687 for (i++; 688 i < length && '0' <= (ch1 = format.charAt(i)) && ch1 <= '9'; 689 i++) { 690 count = 10 * count + ch1 - '0'; 691 } 692 693 if (ch1 == '*' && count == 0) { 694 i++; 695 count = Integer.MAX_VALUE; 696 } 697 else if (count == 0) 698 count = 1; 699 700 if (i < length) 701 i--; 702 703 switch (ch) { 704 case 'a': 705 segments.add(new SpacePackSegment(count, (byte) 0)); 706 break; 707 case 'A': 708 segments.add(new SpacePackSegment(count, (byte) 0x20)); 709 break; 710 case 'h': 711 segments.add(new RevHexPackSegment(count)); 712 break; 713 case 'H': 714 segments.add(new HexPackSegment(count)); 715 break; 716 case 'c': 717 case 'C': 718 segments.add(new BigEndianPackSegment(count, 1)); 719 break; 720 case 's': 721 case 'n': 722 case 'S': 723 segments.add(new BigEndianPackSegment(count, 2)); 724 break; 725 case 'v': 726 segments.add(new LittleEndianPackSegment(count, 2)); 727 break; 728 case 'l': 729 case 'L': 730 case 'N': 731 segments.add(new BigEndianPackSegment(count, 4)); 732 break; 733 case 'V': 734 segments.add(new LittleEndianPackSegment(count, 4)); 735 break; 736 case 'i': 737 case 'I': 738 segments.add(new BigEndianPackSegment(count, 8)); 739 break; 740 case 'd': 741 segments.add(new DoublePackSegment(count)); 742 break; 743 case 'f': 744 segments.add(new FloatPackSegment(count)); 745 break; 746 case 'x': 747 segments.add(new NullPackSegment(count)); 748 break; 749 case '@': 750 segments.add(new PositionPackSegment(count)); 751 break; 752 } 753 } 754 755 return segments; 756 } 757 758 private static ArrayList <PackSegment> parseUnpackFormat(String format) 759 { 760 ArrayList <PackSegment> segments = new ArrayList <PackSegment>(); 761 762 int length = format.length(); 763 for (int i = 0; i < length; i++) { 764 char ch = format.charAt(i); 765 766 int count = 0; 767 char ch1 = ' '; 768 for (i++; 769 i < length && '0' <= (ch1 = format.charAt(i)) && ch1 <= '9'; 770 i++) { 771 count = 10 * count + ch1 - '0'; 772 } 773 774 if (count == 0) 775 count = 1; 776 777 if (i < length) 778 i--; 779 780 StringBuilder sb = new StringBuilder (); 781 782 for (i++; i < length && (ch1 = format.charAt(i)) != '/'; i++) { 783 sb.append(ch1); 784 } 785 786 String name = sb.toString(); 787 788 switch (ch) { 789 case 'a': 790 segments.add(new SpacePackSegment(name, count, (byte) 0)); 791 break; 792 case 'A': 793 segments.add(new SpacePackSegment(name, count, (byte) 0x20)); 794 break; 795 case 'h': 796 segments.add(new RevHexPackSegment(name, count)); 797 break; 798 case 'H': 799 segments.add(new HexPackSegment(name, count)); 800 break; 801 case 'c': 802 segments.add(new BigEndianPackSegment(name, count, 1, true)); 803 break; 804 case 'C': 805 segments.add(new BigEndianPackSegment(name, count, 1, false)); 806 break; 807 case 's': 808 segments.add(new BigEndianPackSegment(name, count, 2, true)); 809 break; 810 case 'n': 811 case 'S': 812 segments.add(new BigEndianPackSegment(name, count, 2, false)); 813 break; 814 case 'v': 815 segments.add(new LittleEndianPackSegment(name, count, 2)); 816 break; 817 case 'l': 818 segments.add(new BigEndianPackSegment(name, count, 4, true)); 819 break; 820 case 'L': 821 case 'N': 822 segments.add(new BigEndianPackSegment(name, count, 4, false)); 823 break; 824 case 'V': 825 segments.add(new LittleEndianPackSegment(name, count, 4)); 826 break; 827 case 'i': 828 case 'I': 829 segments.add(new BigEndianPackSegment(name, count, 8, false)); 830 break; 831 case 'd': 832 segments.add(new DoublePackSegment(name, count)); 833 break; 834 case 'f': 835 segments.add(new FloatPackSegment(name, count)); 836 break; 837 case 'x': 838 segments.add(new NullPackSegment(name, count)); 839 break; 840 case '@': 841 segments.add(new PositionPackSegment(name, count)); 842 break; 843 } 844 } 845 846 return segments; 847 } 848 849 abstract static class PackSegment { 850 abstract public int pack(Env env, BinaryBuilderValue bb, 851 int i, Value []args) 852 throws IOException ; 853 854 abstract public void unpack(Env env, ArrayValue array, InputStream is) 855 throws IOException ; 856 } 857 858 static class SpacePackSegment extends PackSegment { 859 private final StringValue _name; 860 private final int _length; 861 private final byte _pad; 862 863 SpacePackSegment(int length, byte pad) 864 { 865 this("", length, pad); 866 } 867 868 SpacePackSegment(String name, int length, byte pad) 869 { 870 _name = new StringValueImpl(name); 871 _length = length; 872 _pad = pad; 873 } 874 875 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 876 throws IOException 877 { 878 Value arg; 879 880 if (i < args.length) { 881 arg = args[i]; 882 i++; 883 } 884 else { 885 env.warning("a: not enough arguments"); 886 887 return i; 888 } 889 890 InputStream is = arg.toInputStream(); 891 892 int length = _length; 893 894 for (int j = 0; j < length; j++) { 895 int ch = is.read(); 896 897 if (ch >= 0) 898 bb.appendByte(ch); 899 else if (length == Integer.MAX_VALUE) 900 return i; 901 else 902 bb.appendByte(_pad); 903 } 904 905 return i; 906 } 907 908 public void unpack(Env env, ArrayValue result, InputStream is) 909 throws IOException 910 { 911 BinaryBuilderValue bb = new BinaryBuilderValue(); 912 for (int i = 0; i < _length; i++) { 913 int ch = is.read(); 914 915 if (ch == _pad) { 916 } 917 else if (ch >= 0) 918 bb.appendByte(ch); 919 else 920 break; 921 } 922 923 result.put(_name, bb); 924 } 925 } 926 927 static class HexPackSegment extends PackSegment { 928 private final StringValue _name; 929 private final int _length; 930 931 HexPackSegment(int length) 932 { 933 this("", length); 934 } 935 936 HexPackSegment(String name, int length) 937 { 938 _name = new StringValueImpl(name); 939 _length = length; 940 } 941 942 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 943 throws IOException 944 { 945 Value arg; 946 947 if (i < args.length) { 948 arg = args[i]; 949 i++; 950 } 951 else { 952 env.warning("a: not enough arguments"); 953 954 return i; 955 } 956 957 StringValue s = arg.toStringValue(); 958 959 int strlen = s.length(); 960 961 if (_length == Integer.MAX_VALUE) { 962 } 963 else if (strlen < _length) { 964 env.warning("not enough characters in hex string"); 965 966 return i; 967 } 968 else if (_length < strlen) 969 strlen = _length; 970 971 int tail = strlen / 2; 972 for (int j = 0; j < tail; j++) { 973 int d = 0; 974 975 char ch = s.charAt(2 * j); 976 977 d += 16 * hexToDigit(env, ch); 978 979 ch = s.charAt(2 * j + 1); 980 981 d += hexToDigit(env, ch); 982 983 bb.appendByte(d); 984 } 985 986 if ((strlen & 1) == 1) { 987 int d = 16 * hexToDigit(env, s.charAt(strlen - 1)); 988 989 bb.appendByte(d); 990 } 991 992 return i; 993 } 994 995 public void unpack(Env env, ArrayValue result, InputStream is) 996 throws IOException 997 { 998 StringBuilderValue sb = new StringBuilderValue(); 999 for (int i = _length / 2 - 1; i >= 0; i--) { 1000 int ch = is.read(); 1001 1002 sb.append(digitToHex(ch >> 4)); 1003 sb.append(digitToHex(ch)); 1004 } 1005 1006 result.put(_name, sb); 1007 } 1008 } 1009 1010 static class RevHexPackSegment extends PackSegment { 1011 private final StringValue _name; 1012 private final int _length; 1013 1014 RevHexPackSegment(int length) 1015 { 1016 this("", length); 1017 } 1018 1019 RevHexPackSegment(String name, int length) 1020 { 1021 _name = new StringValueImpl(name); 1022 _length = length; 1023 } 1024 1025 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 1026 throws IOException 1027 { 1028 Value arg; 1029 1030 if (i < args.length) { 1031 arg = args[i]; 1032 i++; 1033 } 1034 else { 1035 env.warning("a: not enough arguments"); 1036 1037 return i; 1038 } 1039 1040 StringValue s = arg.toStringValue(); 1041 1042 int strlen = s.length(); 1043 1044 if (_length == Integer.MAX_VALUE) { 1045 } 1046 else if (strlen < _length) { 1047 env.warning("not enough characters in hex string"); 1048 1049 return i; 1050 } 1051 else if (_length < strlen) 1052 strlen = _length; 1053 1054 int tail = strlen / 2; 1055 for (int j = 0; j < tail; j++) { 1056 int d = 0; 1057 1058 char ch = s.charAt(2 * j); 1059 1060 d += hexToDigit(env, ch); 1061 1062 ch = s.charAt(2 * j + 1); 1063 1064 d += 16 * hexToDigit(env, ch); 1065 1066 bb.appendByte(d); 1067 } 1068 1069 if ((strlen & 1) == 1) { 1070 int d = hexToDigit(env, s.charAt(strlen - 1)); 1071 1072 bb.appendByte(d); 1073 } 1074 1075 return i; 1076 } 1077 1078 public void unpack(Env env, ArrayValue result, InputStream is) 1079 throws IOException 1080 { 1081 StringBuilderValue sb = new StringBuilderValue(); 1082 for (int i = _length / 2 - 1; i >= 0; i--) { 1083 int ch = is.read(); 1084 1085 sb.append(digitToHex(ch)); 1086 sb.append(digitToHex(ch >> 4)); 1087 } 1088 1089 result.put(_name, sb); 1090 } 1091 } 1092 1093 static class BigEndianPackSegment extends PackSegment { 1094 private final String _name; 1095 private final int _length; 1096 private final int _bytes; 1097 private final boolean _isSigned; 1098 1099 BigEndianPackSegment(int length, int bytes) 1100 { 1101 _name = ""; 1102 _length = length; 1103 _bytes = bytes; 1104 _isSigned = false; 1105 } 1106 1107 BigEndianPackSegment(String name, int length, int bytes, boolean isSigned) 1108 { 1109 _name = name; 1110 _length = length; 1111 _bytes = bytes; 1112 _isSigned = isSigned; 1113 } 1114 1115 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 1116 throws IOException 1117 { 1118 for (int j = 0; j < _length; j++) { 1119 Value arg; 1120 1121 if (i < args.length) { 1122 arg = args[i]; 1123 i++; 1124 } 1125 else if (_length == Integer.MAX_VALUE) 1126 return i; 1127 else { 1128 env.warning("a: not enough arguments"); 1129 1130 return i; 1131 } 1132 1133 long v = arg.toLong(); 1134 1135 for (int k = _bytes - 1; k >= 0; k--) { 1136 bb.appendByte((int) (v >> (8 * k))); 1137 } 1138 } 1139 1140 return i; 1141 } 1142 1143 public void unpack(Env env, ArrayValue result, InputStream is) 1144 throws IOException 1145 { 1146 for (int j = 0; j < _length; j++) { 1147 Value key; 1148 1149 if (_name == "") 1150 key = LongValue.create(j); 1151 else if (_length == 1) 1152 key = new StringValueImpl(_name); 1153 else { 1154 StringBuilderValue sb = new StringBuilderValue(); 1155 sb.append(_name); 1156 sb.append(j); 1157 1158 key = sb; 1159 } 1160 1161 long v = 0; 1162 1163 for (int k = 0; k < _bytes; k++) { 1164 long d = is.read() & 0xff; 1165 1166 v = 256 * v + d; 1167 } 1168 1169 if (_isSigned) { 1170 switch (_bytes) { 1171 case 1: 1172 v = (byte) v; 1173 break; 1174 case 2: 1175 v = (short) v; 1176 break; 1177 case 4: 1178 v = (int) v; 1179 break; 1180 } 1181 } 1182 1183 result.put(key, LongValue.create(v)); 1184 } 1185 } 1186 } 1187 1188 static class LittleEndianPackSegment extends PackSegment { 1189 private final String _name; 1190 private final int _length; 1191 private final int _bytes; 1192 1193 LittleEndianPackSegment(int length, int bytes) 1194 { 1195 _name = ""; 1196 _length = length; 1197 _bytes = bytes; 1198 } 1199 1200 LittleEndianPackSegment(String name, int length, int bytes) 1201 { 1202 _name = name; 1203 _length = length; 1204 _bytes = bytes; 1205 } 1206 1207 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 1208 throws IOException 1209 { 1210 for (int j = 0; j < _length; j++) { 1211 Value arg; 1212 1213 if (i < args.length) { 1214 arg = args[i]; 1215 i++; 1216 } 1217 else if (_length == Integer.MAX_VALUE) 1218 return i; 1219 else { 1220 env.warning("a: not enough arguments"); 1221 1222 return i; 1223 } 1224 1225 long v = arg.toLong(); 1226 1227 for (int k = 0; k < _bytes; k++) { 1228 bb.appendByte((int) (v >> (8 * k))); 1229 } 1230 } 1231 1232 return i; 1233 } 1234 1235 public void unpack(Env env, ArrayValue result, InputStream is) 1236 throws IOException 1237 { 1238 for (int j = 0; j < _length; j++) { 1239 Value key; 1240 1241 if (_name == "") 1242 key = LongValue.create(j); 1243 else if (_length == 1) 1244 key = new StringValueImpl(_name); 1245 else { 1246 StringBuilderValue sb = new StringBuilderValue(); 1247 sb.append(_name); 1248 sb.append(j); 1249 1250 key = sb; 1251 } 1252 1253 long v = 0; 1254 1255 for (int k = 0; k < _bytes; k++) { 1256 long d = is.read() & 0xff; 1257 1258 v |= d << 8 * k; 1259 } 1260 1261 result.put(key, LongValue.create(v)); 1262 } 1263 } 1264 } 1265 1266 static class DoublePackSegment extends PackSegment { 1267 private final String _name; 1268 private final int _length; 1269 1270 DoublePackSegment(int length) 1271 { 1272 this("", length); 1273 } 1274 1275 DoublePackSegment(String name, int length) 1276 { 1277 _name = name; 1278 _length = length; 1279 } 1280 1281 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 1282 throws IOException 1283 { 1284 for (int j = 0; j < _length; j++) { 1285 Value arg; 1286 1287 if (i < args.length) { 1288 arg = args[i]; 1289 i++; 1290 } 1291 else if (_length == Integer.MAX_VALUE) 1292 return i; 1293 else { 1294 env.warning("a: not enough arguments"); 1295 1296 return i; 1297 } 1298 1299 double d = arg.toDouble(); 1300 long v = Double.doubleToLongBits(d); 1301 1302 for (int k = 7; k >= 0; k--) { 1303 bb.appendByte((int) (v >> (8 * k))); 1304 } 1305 } 1306 1307 return i; 1308 } 1309 1310 public void unpack(Env env, ArrayValue result, InputStream is) 1311 throws IOException 1312 { 1313 for (int j = 0; j < _length; j++) { 1314 Value key; 1315 1316 if (_name == "") 1317 key = LongValue.create(j); 1318 else if (_length == 1) 1319 key = new StringValueImpl(_name); 1320 else { 1321 StringBuilderValue sb = new StringBuilderValue(); 1322 sb.append(_name); 1323 sb.append(j); 1324 1325 key = sb; 1326 } 1327 1328 long v = 0; 1329 1330 for (int k = 0; k < 8; k++) { 1331 long d = is.read() & 0xff; 1332 1333 v = 256 * v + d; 1334 } 1335 1336 result.put(key, new DoubleValue(Double.longBitsToDouble(v))); 1337 } 1338 } 1339 } 1340 1341 static class FloatPackSegment extends PackSegment { 1342 private final String _name; 1343 private final int _length; 1344 1345 FloatPackSegment(int length) 1346 { 1347 this("", length); 1348 } 1349 1350 FloatPackSegment(String name, int length) 1351 { 1352 _name = name; 1353 _length = length; 1354 } 1355 1356 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 1357 throws IOException 1358 { 1359 for (int j = 0; j < _length; j++) { 1360 Value arg; 1361 1362 if (i < args.length) { 1363 arg = args[i]; 1364 i++; 1365 } 1366 else if (_length == Integer.MAX_VALUE) 1367 return i; 1368 else { 1369 env.warning("a: not enough arguments"); 1370 1371 return i; 1372 } 1373 1374 double d = arg.toDouble(); 1375 int v = Float.floatToIntBits((float) d); 1376 1377 for (int k = 3; k >= 0; k--) { 1378 bb.appendByte((int) (v >> (8 * k))); 1379 } 1380 } 1381 1382 return i; 1383 } 1384 1385 public void unpack(Env env, ArrayValue result, InputStream is) 1386 throws IOException 1387 { 1388 for (int j = 0; j < _length; j++) { 1389 Value key; 1390 1391 if (_name == "") 1392 key = LongValue.create(j); 1393 else if (_length == 1) 1394 key = new StringValueImpl(_name); 1395 else { 1396 StringBuilderValue sb = new StringBuilderValue(); 1397 sb.append(_name); 1398 sb.append(j); 1399 1400 key = sb; 1401 } 1402 1403 int v = 0; 1404 1405 for (int k = 0; k < 4; k++) { 1406 int d = is.read() & 0xff; 1407 1408 v = 256 * v + d; 1409 } 1410 1411 result.put(key, new DoubleValue(Float.intBitsToFloat(v))); 1412 } 1413 } 1414 } 1415 1416 static class NullPackSegment extends PackSegment { 1417 private final String _name; 1418 private final int _length; 1419 1420 NullPackSegment(int length) 1421 { 1422 this("", length); 1423 } 1424 1425 NullPackSegment(String name, int length) 1426 { 1427 _name = name; 1428 1429 if (length == Integer.MAX_VALUE) 1430 length = 0; 1431 1432 _length = length; 1433 } 1434 1435 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 1436 throws IOException 1437 { 1438 for (int j = 0; j < _length; j++) { 1439 bb.appendByte(0); 1440 } 1441 1442 return i; 1443 } 1444 1445 public void unpack(Env env, ArrayValue result, InputStream is) 1446 throws IOException 1447 { 1448 for (int i = 0; i < _length; i++) 1449 is.read(); 1450 } 1451 } 1452 1453 static class PositionPackSegment extends PackSegment { 1454 private final int _length; 1455 1456 PositionPackSegment(int length) 1457 { 1458 this("", length); 1459 } 1460 1461 PositionPackSegment(String name, int length) 1462 { 1463 if (length == Integer.MAX_VALUE) 1464 length = 0; 1465 1466 _length = length; 1467 } 1468 1469 public int pack(Env env, BinaryBuilderValue bb, int i, Value []args) 1470 throws IOException 1471 { 1472 while (bb.length() < _length) { 1473 bb.appendByte(0); 1474 } 1475 1476 return i; 1477 } 1478 1479 public void unpack(Env env, ArrayValue result, InputStream is) 1480 throws IOException 1481 { 1482 throw new UnsupportedOperationException ("'@' skip to position"); 1483 } 1484 } 1485 1486 static int hexToDigit(Env env, char ch) 1487 { 1488 if ('0' <= ch && ch <= '9') 1489 return (ch - '0'); 1490 else if ('a' <= ch && ch <= 'f') 1491 return (ch - 'a' + 10); 1492 else if ('A' <= ch && ch <= 'F') 1493 return (ch - 'A' + 10); 1494 else { 1495 env.warning("pack: non hex digit: " + (char) ch); 1496 1497 return 0; 1498 } 1499 } 1500 1501 static char digitToHex(int d) 1502 { 1503 d &= 0xf; 1504 1505 if (d < 10) 1506 return (char) ('0' + d); 1507 else 1508 return (char) ('a' + d - 10); 1509 } 1510} 1511 | Popular Tags |