FileDocCategorySizeDatePackage
Utility.javaAPI DocJava SE 6 API41559Tue Jun 10 00:22:18 BST 2008com.sun.org.apache.bcel.internal.classfile

Utility

public abstract class Utility extends Object
Utility functions that do not really belong to any class in particular.
version
$Id: Utility.java,v 1.1.2.1 2005/07/31 23:46:27 jeffsuttor Exp $
author
M. Dahm

Fields Summary
private static int
consumed_chars
private static boolean
wide
private static final int
FREE_CHARS
private static int[]
CHAR_MAP
private static int[]
MAP_CHAR
private static final char
ESCAPE_CHAR
Constructors Summary
Methods Summary
public static final java.lang.StringaccessToString(int access_flags)
Convert bit field of flags into string such as `static final'.

param
access_flags Access flags
return
String representation of flags

 /* The `WIDE' instruction is used in the
				      * byte code to allow 16-bit wide indices
				      * for local variables. This opcode
				      * precedes an `ILOAD', e.g.. The opcode
				      * immediately following takes an extra
				      * byte which is combined with the
				      * following byte to form a
				      * 16-bit value.
				      */
                          
        
    return accessToString(access_flags, false);
  
public static final java.lang.StringaccessToString(int access_flags, boolean for_class)
Convert bit field of flags into string such as `static final'. Special case: Classes compiled with new compilers and with the `ACC_SUPER' flag would be said to be "synchronized". This is because SUN used the same value for the flags `ACC_SUPER' and `ACC_SYNCHRONIZED'.

param
access_flags Access flags
param
for_class access flags are for class qualifiers ?
return
String representation of flags

    StringBuffer buf = new StringBuffer();

    int p = 0;
    for(int i=0; p < Constants.MAX_ACC_FLAG; i++) { // Loop through known flags
      p = pow2(i);

      if((access_flags & p) != 0) {
	/* Special case: Classes compiled with new compilers and with the
	 * `ACC_SUPER' flag would be said to be "synchronized". This is
	 * because SUN used the same value for the flags `ACC_SUPER' and
	 * `ACC_SYNCHRONIZED'.
	 */
	if(for_class && ((p == Constants.ACC_SUPER) || (p == Constants.ACC_INTERFACE)))
	  continue;	    

	buf.append(Constants.ACCESS_NAMES[i] + " ");
      }
    }

    return buf.toString().trim();
  
private static final shortbyteToShort(byte b)
Convert (signed) byte to (unsigned) short value, i.e., all negative values become positive.

    return (b < 0)? (short)(256 + b) : (short)b;
  
public static final java.lang.StringclassOrInterface(int access_flags)

return
"class" or "interface", depending on the ACC_INTERFACE flag

    return ((access_flags & Constants.ACC_INTERFACE) != 0)? "interface" : "class";
  
public static final intclearBit(int flag, int i)

return
`flag' with bit `i' set to 0

    int bit = pow2(i); 
    return (flag & bit) == 0? flag : flag ^ bit; 
  
public static final java.lang.StringcodeToString(byte[] code, com.sun.org.apache.bcel.internal.classfile.ConstantPool constant_pool, int index, int length, boolean verbose)
Disassemble a byte array of JVM byte codes starting from code line `index' and return the disassembled string representation. Decode only `num' opcodes (including their operands), use -1 if you want to decompile everything.

param
code byte code array
param
constant_pool Array of constants
param
index offset in `code' array (number of opcodes, not bytes!)
param
length number of opcodes to decompile, -1 for all
param
verbose be verbose, e.g. print constant pool index
return
String representation of byte codes

    StringBuffer buf    = new StringBuffer(code.length * 20); // Should be sufficient
    ByteSequence stream = new ByteSequence(code);

    try {
      for(int i=0; i < index; i++) // Skip `index' lines of code
	codeToString(stream, constant_pool, verbose);

      for(int i=0; stream.available() > 0; i++) {
	if((length < 0) || (i < length)) {
	  String indices = fillup(stream.getIndex() + ":", 6, true, ' ");
	  buf.append(indices + codeToString(stream, constant_pool, verbose) + '\n");
	}
      }
    } catch(IOException e) {
      System.out.println(buf.toString());
      e.printStackTrace();
      throw new ClassFormatException("Byte code error: " + e);
    }

    return buf.toString();
  
public static final java.lang.StringcodeToString(byte[] code, com.sun.org.apache.bcel.internal.classfile.ConstantPool constant_pool, int index, int length)

    return codeToString(code, constant_pool, index, length, true);
  
public static final java.lang.StringcodeToString(com.sun.org.apache.bcel.internal.util.ByteSequence bytes, com.sun.org.apache.bcel.internal.classfile.ConstantPool constant_pool, boolean verbose)
Disassemble a stream of byte codes and return the string representation.

param
bytes stream of bytes
param
constant_pool Array of constants
param
verbose be verbose, e.g. print constant pool index
return
String representation of byte code

    short        opcode = (short)bytes.readUnsignedByte();
    int          default_offset=0, low, high, npairs;
    int          index, vindex, constant;
    int[]        match, jump_table;
    int          no_pad_bytes=0, offset;
    StringBuffer buf = new StringBuffer(Constants.OPCODE_NAMES[opcode]);

    /* Special case: Skip (0-3) padding bytes, i.e., the
     * following bytes are 4-byte-aligned
     */
    if((opcode == Constants.TABLESWITCH) || (opcode == Constants.LOOKUPSWITCH)) {
      int remainder = bytes.getIndex() % 4;
      no_pad_bytes  = (remainder == 0)? 0 : 4 - remainder;

      for(int i=0; i < no_pad_bytes; i++) {
	byte b;

	if((b=bytes.readByte()) != 0)
	  System.err.println("Warning: Padding byte != 0 in " +
			     Constants.OPCODE_NAMES[opcode] + ":" + b);
      }

      // Both cases have a field default_offset in common
      default_offset = bytes.readInt();
    }

    switch(opcode) {
      /* Table switch has variable length arguments.
       */
    case Constants.TABLESWITCH:
      low  = bytes.readInt();
      high = bytes.readInt();

      offset = bytes.getIndex() - 12 - no_pad_bytes - 1;
      default_offset += offset;

      buf.append("\tdefault = " + default_offset + ", low = " + low + 
		 ", high = " + high + "(");

      jump_table = new int[high - low + 1];
      for(int i=0; i < jump_table.length; i++) {
	jump_table[i] = offset + bytes.readInt();
	buf.append(jump_table[i]);

	if(i < jump_table.length - 1)
	  buf.append(", ");
      }
      buf.append(")");

      break;

      /* Lookup switch has variable length arguments.
       */
    case Constants.LOOKUPSWITCH: {

      npairs = bytes.readInt();
      offset = bytes.getIndex() - 8 - no_pad_bytes - 1;
	  
      match      = new int[npairs];
      jump_table = new int[npairs];
      default_offset += offset;

      buf.append("\tdefault = " + default_offset + ", npairs = " + npairs +
		 " (");

      for(int i=0; i < npairs; i++) {
	match[i]      = bytes.readInt();

	jump_table[i] = offset + bytes.readInt();

	buf.append("(" + match[i] + ", " + jump_table[i] + ")");

	if(i < npairs - 1)
	  buf.append(", ");
      }
      buf.append(")");
    }
    break;

    /* Two address bytes + offset from start of byte stream form the
     * jump target
     */
    case Constants.GOTO:      case Constants.IFEQ:      case Constants.IFGE:      case Constants.IFGT:
    case Constants.IFLE:      case Constants.IFLT:      case Constants.JSR: case Constants.IFNE:
    case Constants.IFNONNULL: case Constants.IFNULL:    case Constants.IF_ACMPEQ:
    case Constants.IF_ACMPNE: case Constants.IF_ICMPEQ: case Constants.IF_ICMPGE: case Constants.IF_ICMPGT:
    case Constants.IF_ICMPLE: case Constants.IF_ICMPLT: case Constants.IF_ICMPNE:
      buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readShort()));
      break;
	  
      /* 32-bit wide jumps
       */
    case Constants.GOTO_W: case Constants.JSR_W:
      buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readInt()));
      break;

      /* Index byte references local variable (register)
       */
    case Constants.ALOAD:  case Constants.ASTORE: case Constants.DLOAD:  case Constants.DSTORE: case Constants.FLOAD:
    case Constants.FSTORE: case Constants.ILOAD:  case Constants.ISTORE: case Constants.LLOAD:  case Constants.LSTORE:
    case Constants.RET: 
      if(wide) {
	vindex = bytes.readUnsignedShort();
	wide=false; // Clear flag
      }
      else
	vindex = bytes.readUnsignedByte();

      buf.append("\t\t%" + vindex);
      break;

      /*
       * Remember wide byte which is used to form a 16-bit address in the
       * following instruction. Relies on that the method is called again with
       * the following opcode.
       */
    case Constants.WIDE:
      wide      = true;
      buf.append("\t(wide)");
      break;

      /* Array of basic type.
       */
    case Constants.NEWARRAY:
      buf.append("\t\t<" + Constants.TYPE_NAMES[bytes.readByte()] + ">");
      break;

      /* Access object/class fields.
       */
    case Constants.GETFIELD: case Constants.GETSTATIC: case Constants.PUTFIELD: case Constants.PUTSTATIC:
      index = bytes.readUnsignedShort();
      buf.append("\t\t" +
		 constant_pool.constantToString(index, Constants.CONSTANT_Fieldref) +
		 (verbose? " (" + index + ")" : ""));
      break;
	  
      /* Operands are references to classes in constant pool
       */
    case Constants.NEW:
    case Constants.CHECKCAST:
      buf.append("\t");
    case Constants.INSTANCEOF:
      index = bytes.readUnsignedShort();
      buf.append("\t<" + constant_pool.constantToString(index,
							Constants.CONSTANT_Class) +
		 ">" + (verbose? " (" + index + ")" : ""));
      break;

      /* Operands are references to methods in constant pool
       */
    case Constants.INVOKESPECIAL: case Constants.INVOKESTATIC: case Constants.INVOKEVIRTUAL:
      index = bytes.readUnsignedShort();
      buf.append("\t" + constant_pool.constantToString(index,
						       Constants.CONSTANT_Methodref) +
		 (verbose? " (" + index + ")" : ""));
      break;

    case Constants.INVOKEINTERFACE:
      index = bytes.readUnsignedShort();
      int nargs = bytes.readUnsignedByte(); // historical, redundant
      buf.append("\t" + 
		 constant_pool.constantToString(index,
						Constants.CONSTANT_InterfaceMethodref) +
		 (verbose? " (" + index + ")\t" : "") + nargs + "\t" + 
		 bytes.readUnsignedByte()); // Last byte is a reserved space
      break;
	
      /* Operands are references to items in constant pool
       */
    case Constants.LDC_W: case Constants.LDC2_W:
      index = bytes.readUnsignedShort();

      buf.append("\t\t" + constant_pool.constantToString
		 (index, constant_pool.getConstant(index).getTag()) +
		 (verbose? " (" + index + ")" : ""));
      break;

    case Constants.LDC:
      index = bytes.readUnsignedByte();

      buf.append("\t\t" + 
		 constant_pool.constantToString
		 (index, constant_pool.getConstant(index).getTag()) +
		 (verbose? " (" + index + ")" : ""));
      break;
	
      /* Array of references.
       */
    case Constants.ANEWARRAY:
      index = bytes.readUnsignedShort();
	  
      buf.append("\t\t<" + compactClassName(constant_pool.getConstantString
					  (index, Constants.CONSTANT_Class), false) +
		 ">" + (verbose? " (" + index + ")": ""));
      break;
	
      /* Multidimensional array of references.
       */
    case Constants.MULTIANEWARRAY: {
      index          = bytes.readUnsignedShort();
      int dimensions = bytes.readUnsignedByte();

      buf.append("\t<" + compactClassName(constant_pool.getConstantString
					  (index, Constants.CONSTANT_Class), false) +
		 ">\t" + dimensions + (verbose? " (" + index + ")" : ""));
    }
    break;

    /* Increment local variable.
     */
    case Constants.IINC:
      if(wide) {
	vindex   = bytes.readUnsignedShort();
	constant = bytes.readShort();
	wide     = false;
      }
      else {
	vindex   = bytes.readUnsignedByte();
	constant = bytes.readByte();
      }
      buf.append("\t\t%" + vindex + "\t" + constant);
      break;

    default:
      if(Constants.NO_OF_OPERANDS[opcode] > 0) {
	for(int i=0; i < Constants.TYPE_OF_OPERANDS[opcode].length; i++) {
	  buf.append("\t\t");
	  switch(Constants.TYPE_OF_OPERANDS[opcode][i]) {
	  case Constants.T_BYTE:  buf.append(bytes.readByte()); break;
	  case Constants.T_SHORT: buf.append(bytes.readShort());       break;
	  case Constants.T_INT:   buf.append(bytes.readInt());         break;
					      
	  default: // Never reached
	    System.err.println("Unreachable default case reached!");
	    System.exit(-1);
	  }
	}
      }
    }

    return buf.toString();
  
public static final java.lang.StringcodeToString(com.sun.org.apache.bcel.internal.util.ByteSequence bytes, com.sun.org.apache.bcel.internal.classfile.ConstantPool constant_pool)

    return codeToString(bytes, constant_pool, true);
  
public static final java.lang.StringcompactClassName(java.lang.String str, boolean chopit)
Shorten long class names, java/lang/String becomes java.lang.String, e.g.. If chopit is true the prefix java.lang is also removed.

param
str The long class name
param
chopit Flag that determines whether chopping is executed or not
return
Compacted class name

    return compactClassName(str, "java.lang.", chopit);
  
public static final java.lang.StringcompactClassName(java.lang.String str)
Shorten long class names, java/lang/String becomes String.

param
str The long class name
return
Compacted class name

    return compactClassName(str, true);
  
public static final java.lang.StringcompactClassName(java.lang.String str, java.lang.String prefix, boolean chopit)
Shorten long class name str, i.e., chop off the prefix, if the class name starts with this string and the flag chopit is true. Slashes / are converted to dots ..

param
str The long class name
param
prefix The prefix the get rid off
param
chopit Flag that determines whether chopping is executed or not
return
Compacted class name

    int len = prefix.length();

    str = str.replace('/", '."); // Is `/' on all systems, even DOS

    if(chopit) {
      // If string starts with `prefix' and contains no further dots
      if(str.startsWith(prefix) &&
	 (str.substring(len).indexOf('.") == -1))
	str = str.substring(len);
    }
	
    return str;
  
public static final java.lang.StringconvertString(java.lang.String label)
Escape all occurences of newline chars '\n', quotes \", etc.

    char[]       ch  = label.toCharArray();
    StringBuffer buf = new StringBuffer();

    for(int i=0; i < ch.length; i++) {
      switch(ch[i]) {
      case '\n":
	buf.append("\\n"); break;
      case '\r":
	buf.append("\\r"); break;
      case '\"":
	buf.append("\\\""); break;
      case '\'":
	buf.append("\\'"); break;
      case '\\":
	buf.append("\\\\"); break;
      default:
	buf.append(ch[i]); break;
      }
    }

    return buf.toString();
  
private static intcountBrackets(java.lang.String brackets)

    char[]  chars = brackets.toCharArray();
    int     count = 0;
    boolean open  = false;

    for(int i=0; i<chars.length; i++) {
      switch(chars[i]) {
      case '[":
	if(open)
	  throw new RuntimeException("Illegally nested brackets:" + brackets);
	open = true;
	break;

      case ']":
	if(!open)
	  throw new RuntimeException("Illegally nested brackets:" + brackets);
	open = false;
	count++;
	break;

      default:
	// Don't care
      }
    }

    if(open)
      throw new RuntimeException("Illegally nested brackets:" + brackets);

    return count;
  
public static byte[]decode(java.lang.String s, boolean uncompress)
Decode a string back to a byte array.

param
bytes the byte array to convert
param
uncompress use gzip to uncompress the stream of bytes

    char[] chars = s.toCharArray();

    CharArrayReader car = new CharArrayReader(chars);
    JavaReader      jr  = new JavaReader(car);

    ByteArrayOutputStream bos = new ByteArrayOutputStream();

    int ch;

    while((ch = jr.read()) >= 0) {
      bos.write(ch);
    }

    bos.close();
    car.close();
    jr.close();

    byte[] bytes = bos.toByteArray();

    if(uncompress) {
      GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes));

      byte[] tmp   = new byte[bytes.length * 3]; // Rough estimate
      int    count = 0;
      int    b;

      while((b = gis.read()) >= 0)
	tmp[count++] = (byte)b;

      bytes = new byte[count];
      System.arraycopy(tmp, 0, bytes, 0, count);
    }

    return bytes;
  
public static java.lang.Stringencode(byte[] bytes, boolean compress)
Encode byte array it into Java identifier string, i.e., a string that only contains the following characters: (a, ... z, A, ... Z, 0, ... 9, _, $). The encoding algorithm itself is not too clever: if the current byte's ASCII value already is a valid Java identifier part, leave it as it is. Otherwise it writes the escape character($) followed by

  • the ASCII value as a hexadecimal string, if the value is not in the range 200..247
  • a Java identifier char not used in a lowercase hexadecimal string, if the value is in the range 200..247
    • This operation inflates the original byte array by roughly 40-50%

      param
      bytes the byte array to convert
      param
      compress use gzip to minimize string

          if(compress) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            GZIPOutputStream      gos  = new GZIPOutputStream(baos);
      
            gos.write(bytes, 0, bytes.length);
            gos.close();
            baos.close();
      
            bytes = baos.toByteArray();
          }
      
          CharArrayWriter caw = new CharArrayWriter();
          JavaWriter      jw  = new JavaWriter(caw);
      
          for(int i=0; i < bytes.length; i++) {
            int in = bytes[i] & 0x000000ff; // Normalize to unsigned
            jw.write(in);
          }
      
          return caw.toString();
        
static final booleanequals(byte[] a, byte[] b)

    int size;

    if((size=a.length) != b.length)
      return false;

    for(int i=0; i < size; i++)
      if(a[i] != b[i])
	return false;

    return true;
  
public static final java.lang.Stringfillup(java.lang.String str, int length, boolean left_justify, char fill)
Fillup char with up to length characters with char `fill' and justify it left or right.

param
str string to format
param
length length of desired string
param
left_justify format left or right
param
fill fill character
return
formatted string

    int    len = length - str.length();
    char[] buf = new char[(len < 0)? 0 : len];

    for(int j=0; j < buf.length; j++)
      buf[j] = fill;

    if(left_justify)
      return str + new String(buf);    
    else
      return new String(buf) + str;
  
public static final java.lang.Stringformat(int i, int length, boolean left_justify, char fill)
Return a string for an integer justified left or right and filled up with `fill' characters if necessary.

param
i integer to format
param
length length of desired string
param
left_justify format left or right
param
fill fill character
return
formatted int

    return fillup(Integer.toString(i), length, left_justify, fill);
  
public static java.lang.StringgetSignature(java.lang.String type)
Parse Java type such as "char", or "java.lang.String[]" and return the signature in byte code format, e.g. "C" or "[Ljava/lang/String;" respectively.

param
type Java type
return
byte code signature

    StringBuffer buf        = new StringBuffer();
    char[]       chars      = type.toCharArray();
    boolean      char_found = false, delim = false;
    int          index      = -1;

  loop:
    for(int i=0; i < chars.length; i++) {
      switch(chars[i]) {
      case ' ": case '\t": case '\n": case '\r": case '\f":
	if(char_found)
	  delim = true;
	break;

      case '[":
	if(!char_found)
	  throw new RuntimeException("Illegal type: " + type);

	index = i;
	break loop;

      default:
	char_found = true;
	if(!delim)
	  buf.append(chars[i]);
      }
    }

    int brackets = 0;

    if(index > 0)
      brackets = countBrackets(type.substring(index));

    type = buf.toString();
    buf.setLength(0);

    for(int i=0; i < brackets; i++)
      buf.append('[");

    boolean found = false;

    for(int i=Constants.T_BOOLEAN; (i <= Constants.T_VOID) && !found; i++) {
      if(Constants.TYPE_NAMES[i].equals(type)) {
	found = true;
	buf.append(Constants.SHORT_TYPE_NAMES[i]);
      }
    }
    
    if(!found) // Class name
      buf.append('L" + type.replace('.", '/") + ';");

    return buf.toString();
  
public static booleanisJavaIdentifierPart(char ch)

return
true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)

    return ((ch >= 'a") && (ch <= 'z")) ||
      ((ch >= 'A") && (ch <= 'Z")) ||
      ((ch >= '0") && (ch <= '9")) ||
      (ch == '_");
  
public static final booleanisSet(int flag, int i)

return
true, if bit `i' in `flag' is set

    return (flag & pow2(i)) != 0;
  
private static final booleanis_digit(char ch)

    return (ch >= '0") && (ch <= '9");
  
private static final booleanis_space(char ch)

    return (ch == ' ") || (ch == '\t") || (ch == '\r") || (ch == '\n");
  
public static final java.lang.String[]methodSignatureArgumentTypes(java.lang.String signature)

param
signature Method signature
return
Array of argument types
throws
ClassFormatException

    return methodSignatureArgumentTypes(signature, true);
  
public static final java.lang.String[]methodSignatureArgumentTypes(java.lang.String signature, boolean chopit)

param
signature Method signature
param
chopit Shorten class names ?
return
Array of argument types
throws
ClassFormatException

    ArrayList vec = new ArrayList();
    int       index;
    String[]  types;

    try { // Read all declarations between for `(' and `)'
      if(signature.charAt(0) != '(")
	throw new ClassFormatException("Invalid method signature: " + signature);

      index = 1; // current string position

      while(signature.charAt(index) != ')") {
	vec.add(signatureToString(signature.substring(index), chopit));
	index += consumed_chars; // update position
      }
    } catch(StringIndexOutOfBoundsException e) { // Should never occur
      throw new ClassFormatException("Invalid method signature: " + signature);
    }
	
    types = new String[vec.size()];
    vec.toArray(types);
    return types;
  
public static final java.lang.StringmethodSignatureReturnType(java.lang.String signature)

param
signature Method signature
return
return type of method
throws
ClassFormatException

    return methodSignatureReturnType(signature, true);
  
public static final java.lang.StringmethodSignatureReturnType(java.lang.String signature, boolean chopit)

param
signature Method signature
param
chopit Shorten class names ?
return
return type of method
throws
ClassFormatException

    int    index;
    String type;

    try {
      // Read return type after `)'
      index = signature.lastIndexOf(')") + 1; 
      type = signatureToString(signature.substring(index), chopit);
    } catch(StringIndexOutOfBoundsException e) { // Should never occur
      throw new ClassFormatException("Invalid method signature: " + signature);
    }

    return type;
  
public static final java.lang.StringmethodSignatureToString(java.lang.String signature, java.lang.String name, java.lang.String access)
Converts method signature to string with all class names compacted.

param
signature to convert
param
name of method
param
access flags of method
return
Human readable signature

    return methodSignatureToString(signature, name, access, true);
  
public static final java.lang.StringmethodSignatureToString(java.lang.String signature, java.lang.String name, java.lang.String access, boolean chopit)

    return methodSignatureToString(signature, name, access, chopit, null);
  
public static final java.lang.StringmethodSignatureToString(java.lang.String signature, java.lang.String name, java.lang.String access, boolean chopit, com.sun.org.apache.bcel.internal.classfile.LocalVariableTable vars)
A return type signature represents the return value from a method. It is a series of bytes in the following grammar: ::= | V The character V indicates that the method returns no value. Otherwise, the signature indicates the type of the return value. An argument signature represents an argument passed to a method: ::= A method signature represents the arguments that the method expects, and the value that it returns. ::= () ::= * This method converts such a string into a Java type declaration like `void _main(String[])' and throws a `ClassFormatException' when the parsed type is invalid.

param
signature Method signature
param
name Method name
param
access Method access rights
return
Java type declaration
throws
ClassFormatException

    StringBuffer buf = new StringBuffer("(");
    String       type;
    int          index;
    int          var_index = (access.indexOf("static") >= 0)? 0 : 1;

    try { // Read all declarations between for `(' and `)'
      if(signature.charAt(0) != '(")
	throw new ClassFormatException("Invalid method signature: " + signature);

      index = 1; // current string position

      while(signature.charAt(index) != ')") {
	String param_type = signatureToString(signature.substring(index), chopit);
	buf.append(param_type);

	if(vars != null) {
	  LocalVariable l = vars.getLocalVariable(var_index);

	  if(l != null)
	    buf.append(" " + l.getName());
	} else
	  buf.append(" arg" + var_index);

	if("double".equals(param_type) || "long".equals(param_type))
	  var_index += 2;
	else
	  var_index++;

	buf.append(", ");
	index += consumed_chars; // update position
      }

      index++; // update position

      // Read return type after `)'
      type = signatureToString(signature.substring(index), chopit);

    } catch(StringIndexOutOfBoundsException e) { // Should never occur
      throw new ClassFormatException("Invalid method signature: " + signature);
    }

    if(buf.length() > 1) // Tack off the extra ", "
      buf.setLength(buf.length() - 2);

    buf.append(")");

    return access + ((access.length() > 0)? " " : "") + // May be an empty string
      type + " " + name + buf.toString();
  
public static final java.lang.StringmethodTypeToSignature(java.lang.String ret, java.lang.String[] argv)
Converts string containing the method return and argument types to a byte code method signature.

param
ret Return type of method
param
argv Types of method arguments
return
Byte code representation of method signature

    StringBuffer buf = new StringBuffer("(");
    String       str;

    if(argv != null)
      for(int i=0; i < argv.length; i++) {
	str = getSignature(argv[i]);

	if(str.endsWith("V")) // void can't be a method argument
	  throw new ClassFormatException("Invalid type: " + argv[i]);

	buf.append(str);
      }

    str = getSignature(ret);

    buf.append(")" + str);

    return buf.toString();
  
private static final intpow2(int n)

    return 1 << n;
  
public static final voidprintArray(java.io.PrintStream out, java.lang.Object[] obj)

    out.println(printArray(obj, true));
  
public static final voidprintArray(java.io.PrintWriter out, java.lang.Object[] obj)

    out.println(printArray(obj, true));
  
public static final java.lang.StringprintArray(java.lang.Object[] obj)

    return printArray(obj, true);
  
public static final java.lang.StringprintArray(java.lang.Object[] obj, boolean braces)

    return printArray(obj, braces, false);
  
public static final java.lang.StringprintArray(java.lang.Object[] obj, boolean braces, boolean quote)

    if(obj == null)
      return null;

    StringBuffer buf = new StringBuffer();
    if(braces)
      buf.append('{");

    for(int i=0; i < obj.length; i++) {
      if(obj[i] != null) {
	buf.append((quote? "\"" : "") + obj[i].toString() + (quote? "\"" : ""));
      } else {
	buf.append("null");
      }

      if(i < obj.length - 1) {
	buf.append(", ");
      }
    }

    if(braces)
      buf.append('}");

    return buf.toString();
  
public static final java.lang.Stringreplace(java.lang.String str, java.lang.String old, java.lang.String new_)
Replace all occurences of old in str with new.

param
str String to permute
param
old String to be replaced
param
new Replacement string
return
new String object

    int          index, old_index;
    StringBuffer buf = new StringBuffer();

    try {
      if((index = str.indexOf(old)) != -1) { // `old' found in str
	old_index = 0;                       // String start offset
	  
	// While we have something to replace
	while((index = str.indexOf(old, old_index)) != -1) {
	  buf.append(str.substring(old_index, index)); // append prefix
	  buf.append(new_);                            // append replacement
	      
	  old_index = index + old.length(); // Skip `old'.length chars
	}

	buf.append(str.substring(old_index)); // append rest of string
	str = buf.toString();	
      }
    } catch(StringIndexOutOfBoundsException e) { // Should not occur
      System.err.println(e);
    }

    return str;
  
public static shortsearchOpcode(java.lang.String name)
Map opcode names to opcode numbers. E.g., return Constants.ALOAD for "aload"

    name = name.toLowerCase();

    for(short i=0; i < Constants.OPCODE_NAMES.length; i++)
      if(Constants.OPCODE_NAMES[i].equals(name))
	return i;
    
    return -1;
  
public static final intsetBit(int flag, int i)

return
`flag' with bit `i' set to 1

    return flag | pow2(i); 
  
public static final java.lang.StringsignatureToString(java.lang.String signature)
Converts signature to string with all class names compacted.

param
signature to convert
return
Human readable signature

    return signatureToString(signature, true);
  
public static final java.lang.StringsignatureToString(java.lang.String signature, boolean chopit)
The field signature represents the value of an argument to a function or the value of a variable. It is a series of bytes generated by the following grammar:
 ::= 
 ::= ||
 ::= B|C|D|F|I|J|S|Z
 ::= L;
 ::= [

The meaning of the base types is as follows:
B byte signed byte
C char character
D double double precision IEEE float
F float single precision IEEE float
I int integer
J long long integer
L; ... an object of the given class
S short signed short
Z boolean true or false
[ ... array
This method converts this string into a Java type declaration such as `String[]' and throws a `ClassFormatException' when the parsed type is invalid.

param
signature Class signature
param
chopit Flag that determines whether chopping is executed or not
return
Java type declaration
throws
ClassFormatException

    consumed_chars = 1; // This is the default, read just one char like `B'

    try {
      switch(signature.charAt(0)) {
      case 'B" : return "byte";
      case 'C" : return "char";
      case 'D" : return "double";
      case 'F" : return "float";
      case 'I" : return "int";
      case 'J" : return "long";

      case 'L" : { // Full class name
	int    index = signature.indexOf(';"); // Look for closing `;'

	if(index < 0)
	  throw new ClassFormatException("Invalid signature: " + signature);
	
	consumed_chars = index + 1; // "Lblabla;" `L' and `;' are removed

	return compactClassName(signature.substring(1, index), chopit);
      }

      case 'S" : return "short";
      case 'Z" : return "boolean";

      case '[" : { // Array declaration
	int          n;
	StringBuffer buf, brackets;
	String       type;
	char         ch;
	int          consumed_chars; // Shadows global var

	brackets = new StringBuffer(); // Accumulate []'s

	// Count opening brackets and look for optional size argument
	for(n=0; signature.charAt(n) == '["; n++)
	  brackets.append("[]");

	consumed_chars = n; // Remember value

	// The rest of the string denotes a `<field_type>'
	type = signatureToString(signature.substring(n), chopit);
	
	Utility.consumed_chars += consumed_chars;
	return type + brackets.toString();
      }

      case 'V" : return "void";

      default  : throw new ClassFormatException("Invalid signature: `" +
					    signature + "'");
      }
    } catch(StringIndexOutOfBoundsException e) { // Should never occur
      throw new ClassFormatException("Invalid signature: " + e + ":" + signature);
    }
  
public static final java.lang.StringtoHexString(byte[] bytes)
Convert bytes into hexidecimal string

return
bytes as hexidecimal string, e.g. 00 FA 12 ...

    StringBuffer buf = new StringBuffer();

    for(int i=0; i < bytes.length; i++) {
      short  b   = byteToShort(bytes[i]);
      String hex = Integer.toString(b, 0x10);

      if(b < 0x10) // just one digit, prepend '0'
	buf.append('0");

      buf.append(hex);

      if(i < bytes.length - 1)
	buf.append(' ");
    }

    return buf.toString();
  
public static final bytetypeOfMethodSignature(java.lang.String signature)
Return type of method signature as a byte value as defined in Constants

param
signature in format described above
return
type of method signature
see
Constants

    int index;

    try {
      if(signature.charAt(0) != '(")
	throw new ClassFormatException("Invalid method signature: " + signature);

      index = signature.lastIndexOf(')") + 1;
      return typeOfSignature(signature.substring(index));
    } catch(StringIndexOutOfBoundsException e) {
      throw new ClassFormatException("Invalid method signature: " + signature);
    }
  
public static final bytetypeOfSignature(java.lang.String signature)
Return type of signature as a byte value as defined in Constants

param
signature in format described above
return
type of signature
see
Constants

    try {
      switch(signature.charAt(0)) {
      case 'B" : return Constants.T_BYTE;
      case 'C" : return Constants.T_CHAR;
      case 'D" : return Constants.T_DOUBLE;
      case 'F" : return Constants.T_FLOAT;
      case 'I" : return Constants.T_INT;
      case 'J" : return Constants.T_LONG;
      case 'L" : return Constants.T_REFERENCE;
      case '[" : return Constants.T_ARRAY;
      case 'V" : return Constants.T_VOID;
      case 'Z" : return Constants.T_BOOLEAN;
      case 'S" : return Constants.T_SHORT;
      default:  
	throw new ClassFormatException("Invalid method signature: " + signature);
      }
    } catch(StringIndexOutOfBoundsException e) {
      throw new ClassFormatException("Invalid method signature: " + signature);
    }