| 1 17 package org.apache.bcel.classfile; 18 19 import java.io.ByteArrayInputStream ; 20 import java.io.ByteArrayOutputStream ; 21 import java.io.CharArrayReader ; 22 import java.io.CharArrayWriter ; 23 import java.io.FilterReader ; 24 import java.io.FilterWriter ; 25 import java.io.IOException ; 26 import java.io.PrintStream ; 27 import java.io.PrintWriter ; 28 import java.io.Reader ; 29 import java.io.Writer ; 30 import java.util.ArrayList ; 31 import java.util.List ; 32 import java.util.Locale ; 33 import java.util.zip.GZIPInputStream ; 34 import java.util.zip.GZIPOutputStream ; 35 import org.apache.bcel.Constants; 36 import org.apache.bcel.util.ByteSequence; 37 38 44 public abstract class Utility { 45 46 private static int unwrap( ThreadLocal tl ) { 47 return ((Integer ) tl.get()).intValue(); 48 } 49 50 51 private static void wrap( ThreadLocal tl, int value ) { 52 tl.set(new Integer (value)); 53 } 54 55 private static ThreadLocal consumed_chars = new ThreadLocal () { 56 57 protected Object initialValue() { 58 return new Integer (0); 59 } 60 }; 65 private static boolean wide = false; 74 75 76 82 public static final String accessToString( int access_flags ) { 83 return accessToString(access_flags, false); 84 } 85 86 87 99 public static final String accessToString( int access_flags, boolean for_class ) { 100 StringBuffer buf = new StringBuffer (); 101 int p = 0; 102 for (int i = 0; p < Constants.MAX_ACC_FLAG; i++) { p = pow2(i); 104 if ((access_flags & p) != 0) { 105 110 if (for_class && ((p == Constants.ACC_SUPER) || (p == Constants.ACC_INTERFACE))) { 111 continue; 112 } 113 buf.append(Constants.ACCESS_NAMES[i]).append(" "); 114 } 115 } 116 return buf.toString().trim(); 117 } 118 119 120 123 public static final String classOrInterface( int access_flags ) { 124 return ((access_flags & Constants.ACC_INTERFACE) != 0) ? "interface" : "class"; 125 } 126 127 128 142 public static final String codeToString( byte[] code, ConstantPool constant_pool, int index, 143 int length, boolean verbose ) { 144 StringBuffer buf = new StringBuffer (code.length * 20); ByteSequence stream = new ByteSequence(code); 146 try { 147 for (int i = 0; i < index; i++) { 148 codeToString(stream, constant_pool, verbose); 149 } 150 for (int i = 0; stream.available() > 0; i++) { 151 if ((length < 0) || (i < length)) { 152 String indices = fillup(stream.getIndex() + ":", 6, true, ' '); 153 buf.append(indices).append(codeToString(stream, constant_pool, verbose)) 154 .append('\n'); 155 } 156 } 157 } catch (IOException e) { 158 System.out.println(buf.toString()); 159 e.printStackTrace(); 160 throw new ClassFormatException("Byte code error: " + e); 161 } 162 return buf.toString(); 163 } 164 165 166 public static final String codeToString( byte[] code, ConstantPool constant_pool, int index, 167 int length ) { 168 return codeToString(code, constant_pool, index, length, true); 169 } 170 171 172 181 public static final String codeToString( ByteSequence bytes, ConstantPool constant_pool, 182 boolean verbose ) throws IOException { 183 short opcode = (short) bytes.readUnsignedByte(); 184 int default_offset = 0, low, high, npairs; 185 int index, vindex, constant; 186 int[] match, jump_table; 187 int no_pad_bytes = 0, offset; 188 StringBuffer buf = new StringBuffer (Constants.OPCODE_NAMES[opcode]); 189 192 if ((opcode == Constants.TABLESWITCH) || (opcode == Constants.LOOKUPSWITCH)) { 193 int remainder = bytes.getIndex() % 4; 194 no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder; 195 for (int i = 0; i < no_pad_bytes; i++) { 196 byte b; 197 if ((b = bytes.readByte()) != 0) { 198 System.err.println("Warning: Padding byte != 0 in " 199 + Constants.OPCODE_NAMES[opcode] + ":" + b); 200 } 201 } 202 default_offset = bytes.readInt(); 204 } 205 switch (opcode) { 206 208 case Constants.TABLESWITCH: 209 low = bytes.readInt(); 210 high = bytes.readInt(); 211 offset = bytes.getIndex() - 12 - no_pad_bytes - 1; 212 default_offset += offset; 213 buf.append("\tdefault = ").append(default_offset).append(", low = ").append(low) 214 .append(", high = ").append(high).append("("); 215 jump_table = new int[high - low + 1]; 216 for (int i = 0; i < jump_table.length; i++) { 217 jump_table[i] = offset + bytes.readInt(); 218 buf.append(jump_table[i]); 219 if (i < jump_table.length - 1) { 220 buf.append(", "); 221 } 222 } 223 buf.append(")"); 224 break; 225 227 case Constants.LOOKUPSWITCH: { 228 npairs = bytes.readInt(); 229 offset = bytes.getIndex() - 8 - no_pad_bytes - 1; 230 match = new int[npairs]; 231 jump_table = new int[npairs]; 232 default_offset += offset; 233 buf.append("\tdefault = ").append(default_offset).append(", npairs = ").append( 234 npairs).append(" ("); 235 for (int i = 0; i < npairs; i++) { 236 match[i] = bytes.readInt(); 237 jump_table[i] = offset + bytes.readInt(); 238 buf.append("(").append(match[i]).append(", ").append(jump_table[i]).append(")"); 239 if (i < npairs - 1) { 240 buf.append(", "); 241 } 242 } 243 buf.append(")"); 244 } 245 break; 246 249 case Constants.GOTO: 250 case Constants.IFEQ: 251 case Constants.IFGE: 252 case Constants.IFGT: 253 case Constants.IFLE: 254 case Constants.IFLT: 255 case Constants.JSR: 256 case Constants.IFNE: 257 case Constants.IFNONNULL: 258 case Constants.IFNULL: 259 case Constants.IF_ACMPEQ: 260 case Constants.IF_ACMPNE: 261 case Constants.IF_ICMPEQ: 262 case Constants.IF_ICMPGE: 263 case Constants.IF_ICMPGT: 264 case Constants.IF_ICMPLE: 265 case Constants.IF_ICMPLT: 266 case Constants.IF_ICMPNE: 267 buf.append("\t\t#").append((bytes.getIndex() - 1) + bytes.readShort()); 268 break; 269 271 case Constants.GOTO_W: 272 case Constants.JSR_W: 273 buf.append("\t\t#").append(((bytes.getIndex() - 1) + bytes.readInt())); 274 break; 275 277 case Constants.ALOAD: 278 case Constants.ASTORE: 279 case Constants.DLOAD: 280 case Constants.DSTORE: 281 case Constants.FLOAD: 282 case Constants.FSTORE: 283 case Constants.ILOAD: 284 case Constants.ISTORE: 285 case Constants.LLOAD: 286 case Constants.LSTORE: 287 case Constants.RET: 288 if (wide) { 289 vindex = bytes.readUnsignedShort(); 290 wide = false; } else { 292 vindex = bytes.readUnsignedByte(); 293 } 294 buf.append("\t\t%").append(vindex); 295 break; 296 301 case Constants.WIDE: 302 wide = true; 303 buf.append("\t(wide)"); 304 break; 305 307 case Constants.NEWARRAY: 308 buf.append("\t\t<").append(Constants.TYPE_NAMES[bytes.readByte()]).append(">"); 309 break; 310 312 case Constants.GETFIELD: 313 case Constants.GETSTATIC: 314 case Constants.PUTFIELD: 315 case Constants.PUTSTATIC: 316 index = bytes.readUnsignedShort(); 317 buf.append("\t\t").append( 318 constant_pool.constantToString(index, Constants.CONSTANT_Fieldref)).append( 319 (verbose ? " (" + index + ")" : "")); 320 break; 321 323 case Constants.NEW: 324 case Constants.CHECKCAST: 325 buf.append("\t"); 326 case Constants.INSTANCEOF: 327 index = bytes.readUnsignedShort(); 328 buf.append("\t<").append( 329 constant_pool.constantToString(index, Constants.CONSTANT_Class)) 330 .append(">").append((verbose ? " (" + index + ")" : "")); 331 break; 332 334 case Constants.INVOKESPECIAL: 335 case Constants.INVOKESTATIC: 336 case Constants.INVOKEVIRTUAL: 337 index = bytes.readUnsignedShort(); 338 buf.append("\t").append( 339 constant_pool.constantToString(index, Constants.CONSTANT_Methodref)) 340 .append((verbose ? " (" + index + ")" : "")); 341 break; 342 case Constants.INVOKEINTERFACE: 343 index = bytes.readUnsignedShort(); 344 int nargs = bytes.readUnsignedByte(); buf.append("\t").append( 346 constant_pool 347 .constantToString(index, Constants.CONSTANT_InterfaceMethodref)) 348 .append(verbose ? " (" + index + ")\t" : "").append(nargs).append("\t") 349 .append(bytes.readUnsignedByte()); break; 351 353 case Constants.LDC_W: 354 case Constants.LDC2_W: 355 index = bytes.readUnsignedShort(); 356 buf.append("\t\t").append( 357 constant_pool.constantToString(index, constant_pool.getConstant(index) 358 .getTag())).append((verbose ? " (" + index + ")" : "")); 359 break; 360 case Constants.LDC: 361 index = bytes.readUnsignedByte(); 362 buf.append("\t\t").append( 363 constant_pool.constantToString(index, constant_pool.getConstant(index) 364 .getTag())).append((verbose ? " (" + index + ")" : "")); 365 break; 366 368 case Constants.ANEWARRAY: 369 index = bytes.readUnsignedShort(); 370 buf.append("\t\t<").append( 371 compactClassName(constant_pool.getConstantString(index, 372 Constants.CONSTANT_Class), false)).append(">").append( 373 (verbose ? " (" + index + ")" : "")); 374 break; 375 377 case Constants.MULTIANEWARRAY: { 378 index = bytes.readUnsignedShort(); 379 int dimensions = bytes.readUnsignedByte(); 380 buf.append("\t<").append( 381 compactClassName(constant_pool.getConstantString(index, 382 Constants.CONSTANT_Class), false)).append(">\t").append(dimensions) 383 .append((verbose ? " (" + index + ")" : "")); 384 } 385 break; 386 388 case Constants.IINC: 389 if (wide) { 390 vindex = bytes.readUnsignedShort(); 391 constant = bytes.readShort(); 392 wide = false; 393 } else { 394 vindex = bytes.readUnsignedByte(); 395 constant = bytes.readByte(); 396 } 397 buf.append("\t\t%").append(vindex).append("\t").append(constant); 398 break; 399 default: 400 if (Constants.NO_OF_OPERANDS[opcode] > 0) { 401 for (int i = 0; i < Constants.TYPE_OF_OPERANDS[opcode].length; i++) { 402 buf.append("\t\t"); 403 switch (Constants.TYPE_OF_OPERANDS[opcode][i]) { 404 case Constants.T_BYTE: 405 buf.append(bytes.readByte()); 406 break; 407 case Constants.T_SHORT: 408 buf.append(bytes.readShort()); 409 break; 410 case Constants.T_INT: 411 buf.append(bytes.readInt()); 412 break; 413 default: System.err.println("Unreachable default case reached!"); 415 System.exit(-1); 416 } 417 } 418 } 419 } 420 return buf.toString(); 421 } 422 423 424 public static final String codeToString( ByteSequence bytes, ConstantPool constant_pool ) 425 throws IOException { 426 return codeToString(bytes, constant_pool, true); 427 } 428 429 430 437 public static final String compactClassName( String str ) { 438 return compactClassName(str, true); 439 } 440 441 442 453 public static final String compactClassName( String str, String prefix, boolean chopit ) { 454 int len = prefix.length(); 455 str = str.replace('/', '.'); if (chopit) { 457 if (str.startsWith(prefix) && (str.substring(len).indexOf('.') == -1)) { 459 str = str.substring(len); 460 } 461 } 462 return str; 463 } 464 465 466 476 public static final String compactClassName( String str, boolean chopit ) { 477 return compactClassName(str, "java.lang.", chopit); 478 } 479 480 481 484 public static final int setBit( int flag, int i ) { 485 return flag | pow2(i); 486 } 487 488 489 492 public static final int clearBit( int flag, int i ) { 493 int bit = pow2(i); 494 return (flag & bit) == 0 ? flag : flag ^ bit; 495 } 496 497 498 501 public static final boolean isSet( int flag, int i ) { 502 return (flag & pow2(i)) != 0; 503 } 504 505 506 514 public final static String methodTypeToSignature( String ret, String [] argv ) 515 throws ClassFormatException { 516 StringBuffer buf = new StringBuffer ("("); 517 String str; 518 if (argv != null) { 519 for (int i = 0; i < argv.length; i++) { 520 str = getSignature(argv[i]); 521 if (str.endsWith("V")) { 522 throw new ClassFormatException("Invalid type: " + argv[i]); 523 } 524 buf.append(str); 525 } 526 } 527 str = getSignature(ret); 528 buf.append(")").append(str); 529 return buf.toString(); 530 } 531 532 533 538 public static final String [] methodSignatureArgumentTypes( String signature ) 539 throws ClassFormatException { 540 return methodSignatureArgumentTypes(signature, true); 541 } 542 543 544 550 public static final String [] methodSignatureArgumentTypes( String signature, boolean chopit ) 551 throws ClassFormatException { 552 List vec = new ArrayList (); 553 int index; 554 try { if (signature.charAt(0) != '(') { 556 throw new ClassFormatException("Invalid method signature: " + signature); 557 } 558 index = 1; while (signature.charAt(index) != ')') { 560 vec.add(signatureToString(signature.substring(index), chopit)); 561 index += unwrap(consumed_chars); } 564 } catch (StringIndexOutOfBoundsException e) { throw new ClassFormatException("Invalid method signature: " + signature); 566 } 567 return (String []) vec.toArray(new String [vec.size()]); 568 } 569 570 571 576 public static final String methodSignatureReturnType( String signature ) 577 throws ClassFormatException { 578 return methodSignatureReturnType(signature, true); 579 } 580 581 582 588 public static final String methodSignatureReturnType( String signature, boolean chopit ) 589 throws ClassFormatException { 590 int index; 591 String type; 592 try { 593 index = signature.lastIndexOf(')') + 1; 595 type = signatureToString(signature.substring(index), chopit); 596 } catch (StringIndexOutOfBoundsException e) { throw new ClassFormatException("Invalid method signature: " + signature); 598 } 599 return type; 600 } 601 602 603 611 public static final String methodSignatureToString( String signature, String name, String access ) { 612 return methodSignatureToString(signature, name, access, true); 613 } 614 615 616 public static final String methodSignatureToString( String signature, String name, 617 String access, boolean chopit ) { 618 return methodSignatureToString(signature, name, access, chopit, null); 619 } 620 621 622 649 public static final String methodSignatureToString( String signature, String name, 650 String access, boolean chopit, LocalVariableTable vars ) throws ClassFormatException { 651 StringBuffer buf = new StringBuffer ("("); 652 String type; 653 int index; 654 int var_index = (access.indexOf("static") >= 0) ? 0 : 1; 655 try { if (signature.charAt(0) != '(') { 657 throw new ClassFormatException("Invalid method signature: " + signature); 658 } 659 index = 1; while (signature.charAt(index) != ')') { 661 String param_type = signatureToString(signature.substring(index), chopit); 662 buf.append(param_type); 663 if (vars != null) { 664 LocalVariable l = vars.getLocalVariable(var_index); 665 if (l != null) { 666 buf.append(" ").append(l.getName()); 667 } 668 } else { 669 buf.append(" arg").append(var_index); 670 } 671 if ("double".equals(param_type) || "long".equals(param_type)) { 672 var_index += 2; 673 } else { 674 var_index++; 675 } 676 buf.append(", "); 677 index += unwrap(consumed_chars); } 680 index++; type = signatureToString(signature.substring(index), chopit); 683 } catch (StringIndexOutOfBoundsException e) { throw new ClassFormatException("Invalid method signature: " + signature); 685 } 686 if (buf.length() > 1) { 687 buf.setLength(buf.length() - 2); 688 } 689 buf.append(")"); 690 return access + ((access.length() > 0) ? " " : "") + type + " " + name + buf.toString(); 692 } 693 694 695 private static final int pow2( int n ) { 697 return 1 << n; 698 } 699 700 701 709 public static final String replace( String str, String old, String new_ ) { 710 int index, old_index; 711 StringBuffer buf = new StringBuffer (); 712 try { 713 if ((index = str.indexOf(old)) != -1) { old_index = 0; while ((index = str.indexOf(old, old_index)) != -1) { 717 buf.append(str.substring(old_index, index)); buf.append(new_); old_index = index + old.length(); } 721 buf.append(str.substring(old_index)); str = buf.toString(); 723 } 724 } catch (StringIndexOutOfBoundsException e) { |