| 1 package com.sun.org.apache.bcel.internal.classfile; 2 3 56 57 import com.sun.org.apache.bcel.internal.Constants; 58 import com.sun.org.apache.bcel.internal.util.ByteSequence; 59 import java.io.*; 60 import java.util.ArrayList ; 61 import java.util.zip.*; 62 63 69 public abstract class Utility { 70 private static int consumed_chars; 75 private static boolean wide=false; 84 90 public static final String accessToString(int access_flags) { 91 return accessToString(access_flags, false); 92 } 93 94 106 public static final String accessToString(int access_flags, 107 boolean for_class) 108 { 109 StringBuffer buf = new StringBuffer (); 110 111 int p = 0; 112 for(int i=0; p < Constants.MAX_ACC_FLAG; i++) { p = pow2(i); 114 115 if((access_flags & p) != 0) { 116 121 if(for_class && ((p == Constants.ACC_SUPER) || (p == Constants.ACC_INTERFACE))) 122 continue; 123 124 buf.append(Constants.ACCESS_NAMES[i] + " "); 125 } 126 } 127 128 return buf.toString().trim(); 129 } 130 131 134 public static final String classOrInterface(int access_flags) { 135 return ((access_flags & Constants.ACC_INTERFACE) != 0)? "interface" : "class"; 136 } 137 138 152 public static final String codeToString(byte[] code, 153 ConstantPool constant_pool, 154 int index, int length, boolean verbose) 155 { 156 StringBuffer buf = new StringBuffer (code.length * 20); ByteSequence stream = new ByteSequence(code); 158 159 try { 160 for(int i=0; i < index; i++) codeToString(stream, constant_pool, verbose); 162 163 for(int i=0; stream.available() > 0; i++) { 164 if((length < 0) || (i < length)) { 165 String indices = fillup(stream.getIndex() + ":", 6, true, ' '); 166 buf.append(indices + codeToString(stream, constant_pool, verbose) + '\n'); 167 } 168 } 169 } catch(IOException e) { 170 System.out.println(buf.toString()); 171 e.printStackTrace(); 172 throw new ClassFormatError ("Byte code error: " + e); 173 } 174 175 return buf.toString(); 176 } 177 178 public static final String codeToString(byte[] code, 179 ConstantPool constant_pool, 180 int index, int length) { 181 return codeToString(code, constant_pool, index, length, true); 182 } 183 184 193 public static final String codeToString(ByteSequence bytes, 194 ConstantPool constant_pool, boolean verbose) 195 throws IOException 196 { 197 short opcode = (short)bytes.readUnsignedByte(); 198 int default_offset=0, low, high, npairs; 199 int index, vindex, constant; 200 int[] match, jump_table; 201 int no_pad_bytes=0, offset; 202 StringBuffer buf = new StringBuffer (Constants.OPCODE_NAMES[opcode]); 203 204 207 if((opcode == Constants.TABLESWITCH) || (opcode == Constants.LOOKUPSWITCH)) { 208 int remainder = bytes.getIndex() % 4; 209 no_pad_bytes = (remainder == 0)? 0 : 4 - remainder; 210 211 for(int i=0; i < no_pad_bytes; i++) { 212 byte b; 213 214 if((b=bytes.readByte()) != 0) 215 System.err.println("Warning: Padding byte != 0 in " + 216 Constants.OPCODE_NAMES[opcode] + ":" + b); 217 } 218 219 default_offset = bytes.readInt(); 221 } 222 223 switch(opcode) { 224 226 case Constants.TABLESWITCH: 227 low = bytes.readInt(); 228 high = bytes.readInt(); 229 230 offset = bytes.getIndex() - 12 - no_pad_bytes - 1; 231 default_offset += offset; 232 233 buf.append("\tdefault = " + default_offset + ", low = " + low + 234 ", high = " + high + "("); 235 236 jump_table = new int[high - low + 1]; 237 for(int i=0; i < jump_table.length; i++) { 238 jump_table[i] = offset + bytes.readInt(); 239 buf.append(jump_table[i]); 240 241 if(i < jump_table.length - 1) 242 buf.append(", "); 243 } 244 buf.append(")"); 245 246 break; 247 248 250 case Constants.LOOKUPSWITCH: { 251 252 npairs = bytes.readInt(); 253 offset = bytes.getIndex() - 8 - no_pad_bytes - 1; 254 255 match = new int[npairs]; 256 jump_table = new int[npairs]; 257 default_offset += offset; 258 259 buf.append("\tdefault = " + default_offset + ", npairs = " + npairs + 260 " ("); 261 262 for(int i=0; i < npairs; i++) { 263 match[i] = bytes.readInt(); 264 265 jump_table[i] = offset + bytes.readInt(); 266 267 buf.append("(" + match[i] + ", " + jump_table[i] + ")"); 268 269 if(i < npairs - 1) 270 buf.append(", "); 271 } 272 buf.append(")"); 273 } 274 break; 275 276 279 case Constants.GOTO: case Constants.IFEQ: case Constants.IFGE: case Constants.IFGT: 280 case Constants.IFLE: case Constants.IFLT: case Constants.JSR: case Constants.IFNE: 281 case Constants.IFNONNULL: case Constants.IFNULL: case Constants.IF_ACMPEQ: 282 case Constants.IF_ACMPNE: case Constants.IF_ICMPEQ: case Constants.IF_ICMPGE: case Constants.IF_ICMPGT: 283 case Constants.IF_ICMPLE: case Constants.IF_ICMPLT: case Constants.IF_ICMPNE: 284 buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readShort())); 285 break; 286 287 289 case Constants.GOTO_W: case Constants.JSR_W: 290 buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readInt())); 291 break; 292 293 295 case Constants.ALOAD: case Constants.ASTORE: case Constants.DLOAD: case Constants.DSTORE: case Constants.FLOAD: 296 case Constants.FSTORE: case Constants.ILOAD: case Constants.ISTORE: case Constants.LLOAD: case Constants.LSTORE: 297 case Constants.RET: 298 if(wide) { 299 vindex = bytes.readUnsignedShort(); 300 wide=false; } 302 else 303 vindex = bytes.readUnsignedByte(); 304 305 buf.append("\t\t%" + vindex); 306 break; 307 308 313 case Constants.WIDE: 314 wide = true; 315 buf.append("\t(wide)"); 316 break; 317 318 320 case Constants.NEWARRAY: 321 buf.append("\t\t<" + Constants.TYPE_NAMES[bytes.readByte()] + ">"); 322 break; 323 324 326 case Constants.GETFIELD: case Constants.GETSTATIC: case Constants.PUTFIELD: case Constants.PUTSTATIC: 327 index = bytes.readUnsignedShort(); 328 buf.append("\t\t" + 329 constant_pool.constantToString(index, Constants.CONSTANT_Fieldref) + 330 (verbose? " (" + index + ")" : "")); 331 break; 332 333 335 case Constants.NEW: 336 case Constants.CHECKCAST: 337 buf.append("\t"); 338 case Constants.INSTANCEOF: 339 index = bytes.readUnsignedShort(); 340 buf.append("\t<" + constant_pool.constantToString(index, 341 Constants.CONSTANT_Class) + 342 ">" + (verbose? " (" + index + ")" : "")); 343 break; 344 345 347 case Constants.INVOKESPECIAL: case Constants.INVOKESTATIC: case Constants.INVOKEVIRTUAL: 348 index = bytes.readUnsignedShort(); 349 buf.append("\t" + constant_pool.constantToString(index, 350 Constants.CONSTANT_Methodref) + 351 (verbose? " (" + index + ")" : "")); 352 break; 353 354 case Constants.INVOKEINTERFACE: 355 index = bytes.readUnsignedShort(); 356 int nargs = bytes.readUnsignedByte(); buf.append("\t" + 358 constant_pool.constantToString(index, 359 Constants.CONSTANT_InterfaceMethodref) + 360 (verbose? " (" + index + ")\t" : "") + nargs + "\t" + 361 bytes.readUnsignedByte()); break; 363 364 366 case Constants.LDC_W: case Constants.LDC2_W: 367 index = bytes.readUnsignedShort(); 368 369 buf.append("\t\t" + constant_pool.constantToString 370 (index, constant_pool.getConstant(index).getTag()) + 371 (verbose? " (" + index + ")" : "")); 372 break; 373 374 case Constants.LDC: 375 index = bytes.readUnsignedByte(); 376 377 buf.append("\t\t" + 378 constant_pool.constantToString 379 (index, constant_pool.getConstant(index).getTag()) + 380 (verbose? " (" + index + ")" : "")); 381 break; 382 383 385 case Constants.ANEWARRAY: 386 index = bytes.readUnsignedShort(); 387 388 buf.append("\t\t<" + compactClassName(constant_pool.getConstantString 389 (index, Constants.CONSTANT_Class), false) + 390 ">" + (verbose? " (" + index + ")": "")); 391 break; 392 393 395 case Constants.MULTIANEWARRAY: { 396 index = bytes.readUnsignedShort(); 397 int dimensions = bytes.readUnsignedByte(); 398 399 buf.append("\t<" + compactClassName(constant_pool.getConstantString 400 (index, Constants.CONSTANT_Class), false) + 401 ">\t" + dimensions + (verbose? " (" + index + ")" : "")); 402 } 403 break; 404 405 407 case Constants.IINC: 408 if(wide) { 409 vindex = bytes.readUnsignedShort(); 410 constant = bytes.readShort(); 411 wide = false; 412 } 413 else { 414 vindex = bytes.readUnsignedByte(); 415 constant = bytes.readByte(); 416 } 417 buf.append("\t\t%" + vindex + "\t" + constant); 418 break; 419 420 default: 421 if(Constants.NO_OF_OPERANDS[opcode] > 0) { 422 for(int i=0; i < Constants.TYPE_OF_OPERANDS[opcode].length; i++) { 423 buf.append("\t\t"); 424 switch(Constants.TYPE_OF_OPERANDS[opcode][i]) { 425 case Constants.T_BYTE: buf.append(bytes.readByte()); break; 426 case Constants.T_SHORT: buf.append(bytes.readShort()); break; 427 case Constants.T_INT: buf.append(bytes.readInt()); break; 428 429 default: System.err.println("Unreachable default case reached!"); 431 System.exit(-1); 432 } 433 } 434 } 435 } 436 437 return buf.toString(); 438 } 439 440 public static final String codeToString(ByteSequence bytes, ConstantPool constant_pool) 441 throws IOException 442 { 443 return codeToString(bytes, constant_pool, true); 444 } 445 446 453 public static final String compactClassName(String str) { 454 return compactClassName(str, true); 455 } 456 457 468 public static final String compactClassName(String str, 469 String prefix, 470 boolean chopit) 471 { 472 int len = prefix.length(); 473 474 str = str.replace('/', '.'); 476 if(chopit) { 477 if(str.startsWith(prefix) && 479 (str.substring(len).indexOf('.') == -1)) 480 str = str.substring(len); 481 } 482 483 return str; 484 } 485 486 496 public static final String compactClassName(String str, boolean chopit) { 497 return compactClassName(str, "java.lang.", chopit); 498 } 499 500 private static final boolean is_digit(char ch) { 501 return (ch >= '0') && (ch <= '9'); 502 } 503 504 private static final boolean is_space(char ch) { 505 return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n'); 506 } 507 508 511 public static final int setBit(int flag, int i) { 512 return flag | pow2(i); 513 } 514 515 518 public static final int clearBit(int flag, int i) { 519 int bit = pow2(i); 520 return (flag & bit) == 0? flag : flag ^ bit; 521 } 522 523 526 public static final boolean isSet(int flag, int i) { 527 return (flag & pow2(i)) != 0; 528 } 529 530 538 public final static String methodTypeToSignature(String ret, String [] argv) 539 throws ClassFormatError  540 { 541 StringBuffer buf = new StringBuffer ("("); 542 String str; 543 544 if(argv != null) 545 for(int i=0; i < argv.length; i++) { 546 str = getSignature(argv[i]); 547 548 if(str.endsWith("V")) throw new ClassFormatError ("Invalid type: " + argv[i]); 550 551 buf.append(str); 552 } 553 554 str = getSignature(ret); 555 556 buf.append(")" + str); 557 558 return buf.toString(); 559 } 560 561 566 public static final String [] methodSignatureArgumentTypes(String signature) 567 throws ClassFormatError 568 { 569 return methodSignatureArgumentTypes(signature, true); 570 } 571 572 578 public static final String [] methodSignatureArgumentTypes(String signature, 579 boolean chopit) 580 throws ClassFormatError  581 { 582 ArrayList vec = new ArrayList (); 583 int index; 584 String [] types; 585 586 try { if(signature.charAt(0) != '(') 588 throw new ClassFormatError ("Invalid method signature: " + signature); 589 590 index = 1; 592 while(signature.charAt(index) != ')') { 593 vec.add(signatureToString(signature.substring(index), chopit)); 594 index += consumed_chars; } 596 } catch(StringIndexOutOfBoundsException e) { throw new ClassFormatError ("Invalid method signature: " + signature); 598 } 599 600 types = new String [vec.size()]; 601 vec.toArray(types); 602 return types; 603 } 604 609 public static final String methodSignatureReturnType(String signature) 610 throws ClassFormatError 611 { 612 return methodSignatureReturnType(signature, true); 613 } 614 620 public static final String methodSignatureReturnType(String signature, 621 boolean chopit) 622 throws ClassFormatError  623 { 624 int index; 625 String type; 626 627 try { 628 index = signature.lastIndexOf(')') + 1; 630 type = signatureToString(signature.substring(index), chopit); 631 } catch(StringIndexOutOfBoundsException e) { throw new ClassFormatError ("Invalid method signature: " + signature); 633 } 634 635 return type; 636 } 637 638 646 public static final String methodSignatureToString(String signature, 647 String name, 648 String access) { 649 return methodSignatureToString(signature, name, access, true); 650 } 651 652 public static final String methodSignatureToString(String signature, 653 String name, 654 String access, 655 boolean chopit) { 656 return methodSignatureToString(signature, name, access, chopit, null); 657 } 658 659 686 public static final String methodSignatureToString(String signature, 687 String name, 688 String access, 689 boolean chopit, 690 LocalVariableTable vars) 691 throws ClassFormatError  692 { 693 StringBuffer buf = new StringBuffer ("("); 694 String type; 695 int index; 696 int var_index = (access.indexOf("static") >= 0)? 0 : 1; 697 698 try { if(signature.charAt(0) != '(') 700 throw new ClassFormatError ("Invalid method signature: " + signature); 701 702 index = 1; 704 while(signature.charAt(index) != ')') { 705 buf.append(signatureToString(signature.substring(index), chopit)); 706 707 if(vars != null) { 708 LocalVariable l = vars.getLocalVariable(var_index); 709 710 if(l != null) 711 buf.append(" " + l.getName()); 712 } else 713 buf.append(" arg" + var_index); 714 715 var_index++; 716 buf.append(", "); 717 index += consumed_chars; } 719 720 index++; 722 type = signatureToString(signature.substring(index), chopit); 724 725 } catch(StringIndexOutOfBoundsException e) { throw new ClassFormatError ("Invalid method signature: " + signature); 727 } 728 729 if(buf.length() > 1) buf.setLength(buf.length() - 2); 731 732 buf.append(")"); 733 734 return access + ((access.length() > 0)? " " : "") + type + " " + name + buf.toString(); 736 } 737 738 private static final int pow2(int n) { 740 return 1 << n; 741 } 742 743 751 public static final String replace(String str, String old, String new_) { 752 int index, old_index; 753 StringBuffer buf = new StringBuffer (); 754 755 try { 756 if((index = str.indexOf(old)) != -1) { old_index = 0; 759 while((index = str.indexOf(old, old_index)) != -1) { 761 buf.append(str.substring(old_index, index)); buf.append(new_); 764 old_index = index + old.length(); } 766 767 buf.append(str.substring(old_index)); str = buf.toString(); 769 } 770 } catch(StringIndexOutOfBoundsException e) { System.err.println(e); 772 } 773 774 return str; 775 } 776 777 783 public static final String signatureToString(String signature) { 784 return signatureToString(signature, true); 785 } 786 787 821 public static final String signatureToString(String signature, 822 boolean chopit) 823 { 824 consumed_chars = 1; 826 try { 827 switch(signature.charAt(0)) { 828 case 'B' : return "byte"; 829 case 'C' : return "char"; 830 case 'D' : return "double"; 831 case 'F' : return "float"; 832 case 'I' : return "int"; 833 case 'J' : return "long"; 834 835 case 'L' : { int index = signature.indexOf(';'); 838 if(index < 0) 839 throw new ClassFormatError ("Invalid signature: " + signature); 840 841 consumed_chars = index + 1; 843 return compactClassName(signature.substring(1, index), chopit); 844 } 845 846 case 'S' : return "short"; 847 case 'Z' : return "boolean"; 848 849 case '[' : { int n; 851 StringBuffer buf, brackets; 852 String type; 853 char ch; 854 int consumed_chars; 856 brackets = new StringBuffer (); 858 for(n=0; signature.charAt(n) == '['; n++) 860 brackets.append("[]"); 861 862 consumed_chars = n; 864 type = signatureToString(signature.substring(n), chopit); 866 867 Utility.consumed_chars += consumed_chars; 868 return type + brackets.toString(); 869 } 870 871 case 'V' : return "void"; 872 873 default : throw new ClassFormatError ("Invalid signature: `" + 874 signature + "'"); 875 } 876 } catch(StringIndexOutOfBoundsException e) { throw new ClassFormatError ("Invalid signature: " + e + ":" + signature); 878 } 879 } 880 881 887 public static String getSignature(String type) { 888 StringBuffer buf = new StringBuffer (); 889 char[] chars = type.toCharArray(); 890 boolean char_found = false, delim = false; 891 int index = -1; 892 893 loop: 894 for(int i=0; i < chars.length; i++) { 895 switch(chars[i]) { 896 case ' ': case '\t' |