You are viewing a plain text version of this content. The canonical link for it is here.
Posted to bcel-dev@jakarta.apache.org by tc...@apache.org on 2006/03/15 12:33:43 UTC

svn commit: r386056 [9/28] - in /jakarta/bcel/trunk: examples/ examples/Mini/ src/java/org/apache/bcel/ src/java/org/apache/bcel/classfile/ src/java/org/apache/bcel/generic/ src/java/org/apache/bcel/util/ src/java/org/apache/bcel/verifier/ src/java/org...

Modified: jakarta/bcel/trunk/src/java/org/apache/bcel/classfile/Utility.java
URL: http://svn.apache.org/viewcvs/jakarta/bcel/trunk/src/java/org/apache/bcel/classfile/Utility.java?rev=386056&r1=386055&r2=386056&view=diff
==============================================================================
--- jakarta/bcel/trunk/src/java/org/apache/bcel/classfile/Utility.java (original)
+++ jakarta/bcel/trunk/src/java/org/apache/bcel/classfile/Utility.java Wed Mar 15 03:31:56 2006
@@ -13,10 +13,9 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License. 
  *
- */ 
+ */
 package org.apache.bcel.classfile;
 
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.CharArrayReader;
@@ -44,1331 +43,1300 @@
  */
 public abstract class Utility {
 
-    private static int unwrap(ThreadLocal tl) {
-        return ((Integer)tl.get()).intValue();
+    private static int unwrap( ThreadLocal tl ) {
+        return ((Integer) tl.get()).intValue();
     }
 
-    private static void wrap(ThreadLocal tl, int value) {
+
+    private static void wrap( ThreadLocal tl, int value ) {
         tl.set(new Integer(value));
     }
 
-  private static ThreadLocal consumed_chars = new ThreadLocal() {
-      protected Object initialValue() {
-          return new Integer(0);
-      }
-  };/* How many chars have been consumed
-				      * during parsing in signatureToString().
-				      * Read by methodSignatureToString().
-				      * Set by side effect,but only internally.
-				      */
-
-  private static boolean wide=false; /* 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.
-				      */
-  /**
-   * Convert bit field of flags into string such as `static final'.
-   *
-   * @param  access_flags Access flags
-   * @return String representation of flags
-   */
-  public static final String accessToString(int access_flags) {
-    return accessToString(access_flags, false);
-  }
-
-  /**
-   * 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
-   */
-  public static final String accessToString(int access_flags, 
-					    boolean for_class)
-  {
-    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]).append(" ");
-      }
-    }
-
-    return buf.toString().trim();
-  }
-
-  /**
-   * @return "class" or "interface", depending on the ACC_INTERFACE flag
-   */
-  public static final String classOrInterface(int access_flags) {
-    return ((access_flags & Constants.ACC_INTERFACE) != 0)? "interface" : "class";
-  }
-
-  /**
-   * 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
-   * <EM>(number of opcodes, not bytes!)</EM>
-   * @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
-   */
-  public static final String codeToString(byte[] code, 
-					  ConstantPool constant_pool, 
-					  int index, int length, boolean verbose)
-  {
-    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).append(codeToString(stream, constant_pool, verbose)).append('\n');
-	}
-      }
-    } catch(IOException e) {
-      System.out.println(buf.toString());
-      e.printStackTrace();
-      throw new ClassFormatException("Byte code error: " + e);
-    }
-
-    return buf.toString();
-  }
-
-  public static final String codeToString(byte[] code, 
-					  ConstantPool constant_pool, 
-					  int index, int length) {
-    return codeToString(code, constant_pool, index, length, true);
-  }
-
-  /**
-   * 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
-   */
-  public static final String codeToString(ByteSequence bytes,
-					  ConstantPool constant_pool, boolean verbose)
-       throws IOException
-  {
-    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 = ").append(default_offset).append(", low = ").append(low)
-		 .append(", high = ").append(high).append("(");
-
-      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 = ").append(default_offset).append(", npairs = ").append(npairs)
-		 .append(" (");
-
-      for(int i=0; i < npairs; i++) {
-	match[i]      = bytes.readInt();
-
-	jump_table[i] = offset + bytes.readInt();
-
-	buf.append("(").append(match[i]).append(", ").append(jump_table[i]).append(")");
-
-	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#").append((bytes.getIndex() - 1) + bytes.readShort());
-      break;
-	  
-      /* 32-bit wide jumps
-       */
-    case Constants.GOTO_W: case Constants.JSR_W:
-      buf.append("\t\t#").append(((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%").append(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<").append(Constants.TYPE_NAMES[bytes.readByte()]).append(">");
-      break;
-
-      /* Access object/class fields.
-       */
-    case Constants.GETFIELD: case Constants.GETSTATIC: case Constants.PUTFIELD: case Constants.PUTSTATIC:
-      index = bytes.readUnsignedShort();
-      buf.append("\t\t")
-		 .append(constant_pool.constantToString(index, Constants.CONSTANT_Fieldref))
-		 .append((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<").append(constant_pool.constantToString(index, Constants.CONSTANT_Class))
-			.append(">").append((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").append(constant_pool.constantToString(index,
-						       Constants.CONSTANT_Methodref))
-		 .append((verbose? " (" + index + ")" : ""));
-      break;
-
-    case Constants.INVOKEINTERFACE:
-      index = bytes.readUnsignedShort();
-      int nargs = bytes.readUnsignedByte(); // historical, redundant
-      buf.append("\t").append(constant_pool.constantToString(index,
-						Constants.CONSTANT_InterfaceMethodref))
-			.append(verbose? " (" + index + ")\t" : "").append(nargs).append("\t") 
-		 .append(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").append(constant_pool.constantToString
-		 (index, constant_pool.getConstant(index).getTag()))
-		 .append((verbose? " (" + index + ")" : ""));
-      break;
-
-    case Constants.LDC:
-      index = bytes.readUnsignedByte();
-
-      buf.append("\t\t").append(
-    		  constant_pool.constantToString(index, constant_pool.getConstant(index).getTag()))
-    		  .append((verbose? " (" + index + ")" : ""));
-      break;
-	
-      /* Array of references.
-       */
-    case Constants.ANEWARRAY:
-      index = bytes.readUnsignedShort();
-	  
-      buf.append("\t\t<").append(compactClassName(constant_pool.getConstantString
-					  (index, Constants.CONSTANT_Class), false))
-		 .append(">").append((verbose? " (" + index + ")": ""));
-      break;
-	
-      /* Multidimensional array of references.
-       */
-    case Constants.MULTIANEWARRAY: {
-      index          = bytes.readUnsignedShort();
-      int dimensions = bytes.readUnsignedByte();
-
-      buf.append("\t<").append(compactClassName(constant_pool.getConstantString
-					  (index, Constants.CONSTANT_Class), false))
-		 .append(">\t").append(dimensions).append((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%").append(vindex).append("\t").append(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 String codeToString(ByteSequence bytes, ConstantPool constant_pool)
-    throws IOException
-  {
-    return codeToString(bytes, constant_pool, true);
-  }
-
-  /**
-   * Shorten long class names, <em>java/lang/String</em> becomes 
-   * <em>String</em>.
-   *
-   * @param str The long class name
-   * @return Compacted class name
-   */
-  public static final String compactClassName(String str) {
-    return compactClassName(str, true);
-  }
- 
-  /**
-   * Shorten long class name <em>str</em>, i.e., chop off the <em>prefix</em>,
-   * if the
-   * class name starts with this string and the flag <em>chopit</em> is true.
-   * Slashes <em>/</em> are converted to dots <em>.</em>.
-   *
-   * @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
-   */
-  public static final String compactClassName(String str, 
-					      String prefix,
-					      boolean chopit)
-  {
-    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;
-  }
-
-  /**
-   * Shorten long class names, <em>java/lang/String</em> becomes 
-   * <em>java.lang.String</em>,
-   * e.g.. If <em>chopit</em> is <em>true</em> the prefix <em>java.lang</em>
-   * is also removed.
-   *
-   * @param str The long class name
-   * @param chopit Flag that determines whether chopping is executed or not
-   * @return Compacted class name
-   */
-  public static final String compactClassName(String str, boolean chopit) {
-    return compactClassName(str, "java.lang.", chopit);
-  }    
-
-  /**
-   * @return `flag' with bit `i' set to 1
-   */
-  public static final int setBit(int flag, int i) {
-    return flag | pow2(i); 
-  }
-
-  /**
-   * @return `flag' with bit `i' set to 0
-   */
-  public static final int clearBit(int flag, int i) {
-    int bit = pow2(i); 
-    return (flag & bit) == 0? flag : flag ^ bit; 
-  }
-   
-  /**
-   * @return true, if bit `i' in `flag' is set
-   */
-  public static final boolean isSet(int flag, int i) {
-    return (flag & pow2(i)) != 0;
-  }
-
-  /**
-   * 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
-   */
-  public final static String methodTypeToSignature(String ret, String[] argv)
-    throws ClassFormatException
-  {
-    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(")").append(str);
-
-    return buf.toString();
-  }
-
-  /**
-   * @param  signature    Method signature
-   * @return Array of argument types
-   * @throws  ClassFormatException  
-   */
-  public static final String[] methodSignatureArgumentTypes(String signature)
-    throws ClassFormatException 
-  {
-    return methodSignatureArgumentTypes(signature, true);
-  }    
-
-  /**
-   * @param  signature    Method signature
-   * @param chopit Shorten class names ?
-   * @return Array of argument types
-   * @throws  ClassFormatException  
-   */
-  public static final String[] methodSignatureArgumentTypes(String signature,
-							    boolean chopit)
-    throws ClassFormatException
-  {
-    List vec = new ArrayList();
-    int       index;
-
-    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));
-    //corrected concurrent private static field acess
-	index += unwrap(consumed_chars); // update position
-      }
-    } catch(StringIndexOutOfBoundsException e) { // Should never occur
-      throw new ClassFormatException("Invalid method signature: " + signature);
-    }
-	
-    return (String[])vec.toArray(new String[vec.size()]);
-  }      
-  /**
-   * @param  signature    Method signature
-   * @return return type of method
-   * @throws  ClassFormatException  
-   */
-  public static final String methodSignatureReturnType(String signature)
-       throws ClassFormatException 
-  {
-    return methodSignatureReturnType(signature, true);
-  }    
-  /**
-   * @param  signature    Method signature
-   * @param chopit Shorten class names ?
-   * @return return type of method
-   * @throws  ClassFormatException  
-   */
-  public static final String methodSignatureReturnType(String signature,
-						       boolean chopit)
-       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;
-  }
-
-  /**
-   * 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
-   */
-  public static final String methodSignatureToString(String signature,
-						     String name,
-						     String access) {
-    return methodSignatureToString(signature, name, access, true);
-  }
-
-  public static final String methodSignatureToString(String signature,
-						     String name,
-						     String access,
-						     boolean chopit) {
-    return methodSignatureToString(signature, name, access, chopit, null);
-  }
-
-  /**
-   * A return­type signature represents the return value from a method.
-   * It is a series of bytes in the following grammar:
-   *
-   * <return_signature> ::= <field_type> | 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:
-   *
-   * <argument_signature> ::= <field_type>
-   *
-   * A method signature represents the arguments that the method expects, and
-   * the value that it returns.
-   * <method_signature> ::= (<arguments_signature>) <return_signature>
-   * <arguments_signature>::= <argument_signature>*
-   *
-   * 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  
-   */
-  public static final String methodSignatureToString(String signature,
-						     String name,
-						     String access,
-						     boolean chopit,
-						     LocalVariableTable vars)
-    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(" ").append(l.getName());
-	} else
-	  buf.append(" arg").append(var_index);
-
-	if("double".equals(param_type) || "long".equals(param_type))
-	  var_index += 2;
-	else
-	  var_index++;
-
-	buf.append(", ");
-    //corrected concurrent private static field acess
-	index += unwrap(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();
-  }
-
-  // Guess what this does
-  private static final int pow2(int n) {
-    return 1 << n;
-  }
-    
-  /**
-   * Replace all occurences of <em>old</em> in <em>str</em> with <em>new</em>.
-   *
-   * @param str String to permute
-   * @param old String to be replaced
-   * @param new_ Replacement string
-   * @return new String object
-   */
-  public static final String replace(String str, String old, String new_) {
-    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;
-  }
-
-  /**
-   * Converts signature to string with all class names compacted.
-   *
-   * @param signature to convert
-   * @return Human readable signature
-   */
-  public static final String signatureToString(String signature) {
-    return signatureToString(signature, true);
-  }    
-
-  /**
-   * 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:
-   *
-   * <PRE>
-   * <field_signature> ::= <field_type>
-   * <field_type>      ::= <base_type>|<object_type>|<array_type>
-   * <base_type>       ::= B|C|D|F|I|J|S|Z
-   * <object_type>     ::= L<fullclassname>;
-   * <array_type>      ::= [<field_type>
-   *
-   * 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<fullclassname>; ... an object of the given class
-   * S short signed short
-   * Z boolean true or false
-   * [<field sig> ... array
-   * </PRE>
-   *
-   * 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
-   */
-  public static final String signatureToString(String signature,
-					       boolean chopit)
-  {
-    //corrected concurrent private static field acess
-    wrap(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);
-
-    //corrected concurrent private static field acess
-	wrap(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 brackets;
-	String       type;
-	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);
-
-    //corrected concurrent private static field acess
-	//Utility.consumed_chars += consumed_chars; is replaced by:
-    int _temp = unwrap(Utility.consumed_chars)+consumed_chars;
-    wrap(Utility.consumed_chars, _temp);
-
-	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);
-    }
-  }
-
-  /** 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
-   */
-  public static String getSignature(String type) {
-    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').append(type.replace('.', '/')).append(';');
-
-    return buf.toString();
-  }
-
-  private static int countBrackets(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;
-  }
-
-  /**
-   * Return type of method signature as a byte value as defined in <em>Constants</em>
-   *
-   * @param  signature in format described above
-   * @return type of method signature
-   * @see    Constants
-   */
-  public static final byte typeOfMethodSignature(String signature)
-    throws ClassFormatException
-  {
-    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);
-    }
-  }
-
-  /**
-   * Return type of signature as a byte value as defined in <em>Constants</em>
-   *
-   * @param  signature in format described above
-   * @return type of signature
-   * @see    Constants
-   */
-  public static final byte typeOfSignature(String signature)
-    throws ClassFormatException
-  {
-    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);
-    }
-  }
-
-  /** Map opcode names to opcode numbers. E.g., return Constants.ALOAD for "aload"
-   */
-  public static short searchOpcode(String name) {
-    name = name.toLowerCase(Locale.ENGLISH);
-
-    for(short i=0; i < Constants.OPCODE_NAMES.length; i++)
-      if(Constants.OPCODE_NAMES[i].equals(name))
-	return i;
-    
-    return -1;
-  }
-
-  /**
-   * Convert (signed) byte to (unsigned) short value, i.e., all negative
-   * values become positive.
-   */
-  private static final short byteToShort(byte b) {
-    return (b < 0)? (short)(256 + b) : (short)b;
-  }
-
-  /** Convert bytes into hexidecimal string
-   *
-   * @return bytes as hexidecimal string, e.g. 00 FA 12 ...
-   */
-  public static final String toHexString(byte[] bytes) {
-    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();
-  }
-
-  /**
-   * 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
-   */
-  public static final String format(int i, int length, boolean left_justify, char fill) {
-    return fillup(Integer.toString(i), length, left_justify, 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
-   */
-  public static final String fillup(String str, int length, boolean left_justify, char fill) {
-    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);    
-
-    return new String(buf) + str;
-  }
-
-  static final boolean equals(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 void printArray(PrintStream out, Object[] obj) {
-    out.println(printArray(obj, true));
-  }
-
-  public static final void printArray(PrintWriter out, Object[] obj) {
-    out.println(printArray(obj, true));
-  }
-
-  public static final String printArray(Object[] obj) {
-    return printArray(obj, true);
-  }
-
-  public static final String printArray(Object[] obj, boolean braces) {
-    return printArray(obj, braces, false);
-  }
-
-  public static final String printArray(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? "\"" : "")).append(obj[i].toString()).append((quote? "\"" : ""));
-      } else {
-	    buf.append("null");
-      }
-
-      if(i < obj.length - 1) {
-	    buf.append(", ");
-      }
-    }
-
-    if(braces)
-      buf.append('}');
-
-    return buf.toString();
-  }
-
-  /** @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)
-   */
-  public static boolean isJavaIdentifierPart(char ch) {
-    return ((ch >= 'a') && (ch <= 'z')) ||
-      ((ch >= 'A') && (ch <= 'Z')) ||
-      ((ch >= '0') && (ch <= '9')) ||
-      (ch == '_');
-  }
-
-  /** 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 <p><ul><li> the ASCII value as a
-   * hexadecimal string, if the value is not in the range
-   * 200..247</li> <li>a Java identifier char not used in a lowercase
-   * hexadecimal string, if the value is in the range
-   * 200..247</li><ul></p>
-   *
-   * <p>This operation inflates the original byte array by roughly 40-50%</p>
-   *
-   * @param bytes the byte array to convert
-   * @param compress use gzip to minimize string
-   */
-  public static String encode(byte[] bytes, boolean compress) throws IOException {
-    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();
-  }
-
-  /** Decode a string back to a byte array.
-   *
-   * @param s the string to convert
-   * @param uncompress use gzip to uncompress the stream of bytes
-   */
-  public static byte[] decode(String s, boolean uncompress) throws IOException {
-    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;
-  }
-
-  // A-Z, g-z, _, $
-  private static final int   FREE_CHARS  = 48;
-          static       int[] CHAR_MAP    = new int[FREE_CHARS];
-          static       int[] MAP_CHAR    = new int[256]; // Reverse map
-  private static final char  ESCAPE_CHAR = '$';
-
-  static {
-    int j = 0;
-    for(int i='A'; i <= 'Z'; i++) {
-      CHAR_MAP[j] = i;
-      MAP_CHAR[i] = j;
-      j++;
-    }
-
-    for(int i='g'; i <= 'z'; i++) {
-      CHAR_MAP[j] = i;
-      MAP_CHAR[i] = j;
-      j++;
-    }
-
-    CHAR_MAP[j]   = '$';
-    MAP_CHAR['$'] = j;
-    j++;
-
-    CHAR_MAP[j]   = '_';
-    MAP_CHAR['_'] = j;
-  }
-
-  /** Decode characters into bytes.
-   * Used by <a href="Utility.html#decode(java.lang.String, boolean)">decode()</a>
-   */
-  private static class JavaReader extends FilterReader {
-    public JavaReader(Reader in) {
-      super(in);
-    }
-
-    public int read() throws IOException {
-      int b = in.read();
-
-      if(b != ESCAPE_CHAR)
-    	  return b;
-      
-      int i = in.read();
-	  if(i < 0)
-	    return -1;
-
-	  if(((i >= '0') && (i <= '9')) || ((i >= 'a') && (i <= 'f'))) { // Normal escape
-	    int j = in.read();
-
-	    if(j < 0)
-	      return -1;
-
-	    char[] tmp = { (char)i, (char)j };
-	    int s   = Integer.parseInt(new String(tmp), 16);
-
-	    return s;
-	  }
-	  return MAP_CHAR[i];
-    }
-
-    public int read(char[] cbuf, int off, int len) throws IOException {
-      for(int i=0; i < len; i++)
-	cbuf[off + i] = (char)read();
-
-      return len;
-    }
-  }
-
-  /** Encode bytes into valid java identifier characters.
-   * Used by <a href="Utility.html#encode(byte[], boolean)">encode()</a>
-   */
-  private static class JavaWriter extends FilterWriter {
-    public JavaWriter(Writer out) {
-      super(out);
-    }
-
-    public void write(int b) throws IOException {
-      if(isJavaIdentifierPart((char)b) && (b != ESCAPE_CHAR)) {
-	out.write(b);
-      } else {
-	out.write(ESCAPE_CHAR); // Escape character
-
-	// Special escape
-	if(b >= 0 && b < FREE_CHARS) {
-	  out.write(CHAR_MAP[b]);
-	} else { // Normal escape
-	  char[] tmp = Integer.toHexString(b).toCharArray();
-
-	  if(tmp.length == 1) {
-	    out.write('0');
-	    out.write(tmp[0]);
-	  } else {
-	    out.write(tmp[0]);
-	    out.write(tmp[1]);
-	  }
-	}
-      }
-    }
-
-    public void write(char[] cbuf, int off, int len) throws IOException {
-      for(int i=0; i < len; i++)
-	write(cbuf[off + i]);
-    }
-
-    public void write(String str, int off, int len) throws IOException {
-      write(str.toCharArray(), off, len);
-    }
-  }
-
-  /**
-   * Escape all occurences of newline chars '\n', quotes \", etc.
-   */
-  public static final String convertString(String label) {
-    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;
-      }
+    private static ThreadLocal consumed_chars = new ThreadLocal() {
+
+        protected Object initialValue() {
+            return new Integer(0);
+        }
+    };/* How many chars have been consumed
+     * during parsing in signatureToString().
+     * Read by methodSignatureToString().
+     * Set by side effect,but only internally.
+     */
+    private static boolean wide = false; /* 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.
+     */
+
+
+    /**
+     * Convert bit field of flags into string such as `static final'.
+     *
+     * @param  access_flags Access flags
+     * @return String representation of flags
+     */
+    public static final String accessToString( int access_flags ) {
+        return accessToString(access_flags, false);
+    }
+
+
+    /**
+     * 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
+     */
+    public static final String accessToString( int access_flags, boolean for_class ) {
+        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]).append(" ");
+            }
+        }
+        return buf.toString().trim();
+    }
+
+
+    /**
+     * @return "class" or "interface", depending on the ACC_INTERFACE flag
+     */
+    public static final String classOrInterface( int access_flags ) {
+        return ((access_flags & Constants.ACC_INTERFACE) != 0) ? "interface" : "class";
+    }
+
+
+    /**
+     * 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
+     * <EM>(number of opcodes, not bytes!)</EM>
+     * @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
+     */
+    public static final String codeToString( byte[] code, ConstantPool constant_pool, int index,
+            int length, boolean verbose ) {
+        StringBuffer buf = new StringBuffer(code.length * 20); // Should be sufficient
+        ByteSequence stream = new ByteSequence(code);
+        try {
+            for (int i = 0; i < index; i++) {
+                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).append(codeToString(stream, constant_pool, verbose))
+                            .append('\n');
+                }
+            }
+        } catch (IOException e) {
+            System.out.println(buf.toString());
+            e.printStackTrace();
+            throw new ClassFormatException("Byte code error: " + e);
+        }
+        return buf.toString();
+    }
+
+
+    public static final String codeToString( byte[] code, ConstantPool constant_pool, int index,
+            int length ) {
+        return codeToString(code, constant_pool, index, length, true);
+    }
+
+
+    /**
+     * 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
+     */
+    public static final String codeToString( ByteSequence bytes, ConstantPool constant_pool,
+            boolean verbose ) throws IOException {
+        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 = ").append(default_offset).append(", low = ").append(low)
+                        .append(", high = ").append(high).append("(");
+                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 = ").append(default_offset).append(", npairs = ").append(
+                        npairs).append(" (");
+                for (int i = 0; i < npairs; i++) {
+                    match[i] = bytes.readInt();
+                    jump_table[i] = offset + bytes.readInt();
+                    buf.append("(").append(match[i]).append(", ").append(jump_table[i]).append(")");
+                    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#").append((bytes.getIndex() - 1) + bytes.readShort());
+                break;
+            /* 32-bit wide jumps
+             */
+            case Constants.GOTO_W:
+            case Constants.JSR_W:
+                buf.append("\t\t#").append(((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%").append(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<").append(Constants.TYPE_NAMES[bytes.readByte()]).append(">");
+                break;
+            /* Access object/class fields.
+             */
+            case Constants.GETFIELD:
+            case Constants.GETSTATIC:
+            case Constants.PUTFIELD:
+            case Constants.PUTSTATIC:
+                index = bytes.readUnsignedShort();
+                buf.append("\t\t").append(
+                        constant_pool.constantToString(index, Constants.CONSTANT_Fieldref)).append(
+                        (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<").append(
+                        constant_pool.constantToString(index, Constants.CONSTANT_Class))
+                        .append(">").append((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").append(
+                        constant_pool.constantToString(index, Constants.CONSTANT_Methodref))
+                        .append((verbose ? " (" + index + ")" : ""));
+                break;
+            case Constants.INVOKEINTERFACE:
+                index = bytes.readUnsignedShort();
+                int nargs = bytes.readUnsignedByte(); // historical, redundant
+                buf.append("\t").append(
+                        constant_pool
+                                .constantToString(index, Constants.CONSTANT_InterfaceMethodref))
+                        .append(verbose ? " (" + index + ")\t" : "").append(nargs).append("\t")
+                        .append(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").append(
+                        constant_pool.constantToString(index, constant_pool.getConstant(index)
+                                .getTag())).append((verbose ? " (" + index + ")" : ""));
+                break;
+            case Constants.LDC:
+                index = bytes.readUnsignedByte();
+                buf.append("\t\t").append(
+                        constant_pool.constantToString(index, constant_pool.getConstant(index)
+                                .getTag())).append((verbose ? " (" + index + ")" : ""));
+                break;
+            /* Array of references.
+             */
+            case Constants.ANEWARRAY:
+                index = bytes.readUnsignedShort();
+                buf.append("\t\t<").append(
+                        compactClassName(constant_pool.getConstantString(index,
+                                Constants.CONSTANT_Class), false)).append(">").append(
+                        (verbose ? " (" + index + ")" : ""));
+                break;
+            /* Multidimensional array of references.
+             */
+            case Constants.MULTIANEWARRAY: {
+                index = bytes.readUnsignedShort();
+                int dimensions = bytes.readUnsignedByte();
+                buf.append("\t<").append(
+                        compactClassName(constant_pool.getConstantString(index,
+                                Constants.CONSTANT_Class), false)).append(">\t").append(dimensions)
+                        .append((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%").append(vindex).append("\t").append(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 String codeToString( ByteSequence bytes, ConstantPool constant_pool )
+            throws IOException {
+        return codeToString(bytes, constant_pool, true);
+    }
+
+
+    /**
+     * Shorten long class names, <em>java/lang/String</em> becomes 
+     * <em>String</em>.
+     *
+     * @param str The long class name
+     * @return Compacted class name
+     */
+    public static final String compactClassName( String str ) {
+        return compactClassName(str, true);
+    }
+
+
+    /**
+     * Shorten long class name <em>str</em>, i.e., chop off the <em>prefix</em>,
+     * if the
+     * class name starts with this string and the flag <em>chopit</em> is true.
+     * Slashes <em>/</em> are converted to dots <em>.</em>.
+     *
+     * @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
+     */
+    public static final String compactClassName( String str, String prefix, boolean chopit ) {
+        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;
+    }
+
+
+    /**
+     * Shorten long class names, <em>java/lang/String</em> becomes 
+     * <em>java.lang.String</em>,
+     * e.g.. If <em>chopit</em> is <em>true</em> the prefix <em>java.lang</em>
+     * is also removed.
+     *
+     * @param str The long class name
+     * @param chopit Flag that determines whether chopping is executed or not
+     * @return Compacted class name
+     */
+    public static final String compactClassName( String str, boolean chopit ) {
+        return compactClassName(str, "java.lang.", chopit);
+    }
+
+
+    /**
+     * @return `flag' with bit `i' set to 1
+     */
+    public static final int setBit( int flag, int i ) {
+        return flag | pow2(i);
+    }
+
+
+    /**
+     * @return `flag' with bit `i' set to 0
+     */
+    public static final int clearBit( int flag, int i ) {
+        int bit = pow2(i);
+        return (flag & bit) == 0 ? flag : flag ^ bit;
+    }
+
+
+    /**
+     * @return true, if bit `i' in `flag' is set
+     */
+    public static final boolean isSet( int flag, int i ) {
+        return (flag & pow2(i)) != 0;
+    }
+
+
+    /**
+     * 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
+     */
+    public final static String methodTypeToSignature( String ret, String[] argv )
+            throws ClassFormatException {
+        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")) {
+                    throw new ClassFormatException("Invalid type: " + argv[i]);
+                }
+                buf.append(str);
+            }
+        }
+        str = getSignature(ret);
+        buf.append(")").append(str);
+        return buf.toString();
+    }
+
+
+    /**
+     * @param  signature    Method signature
+     * @return Array of argument types
+     * @throws  ClassFormatException  
+     */
+    public static final String[] methodSignatureArgumentTypes( String signature )
+            throws ClassFormatException {
+        return methodSignatureArgumentTypes(signature, true);
+    }
+
+
+    /**
+     * @param  signature    Method signature
+     * @param chopit Shorten class names ?
+     * @return Array of argument types
+     * @throws  ClassFormatException  
+     */
+    public static final String[] methodSignatureArgumentTypes( String signature, boolean chopit )
+            throws ClassFormatException {
+        List vec = new ArrayList();
+        int index;
+        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));
+                //corrected concurrent private static field acess
+                index += unwrap(consumed_chars); // update position
+            }
+        } catch (StringIndexOutOfBoundsException e) { // Should never occur
+            throw new ClassFormatException("Invalid method signature: " + signature);
+        }
+        return (String[]) vec.toArray(new String[vec.size()]);
+    }
+
+
+    /**
+     * @param  signature    Method signature
+     * @return return type of method
+     * @throws  ClassFormatException  
+     */
+    public static final String methodSignatureReturnType( String signature )
+            throws ClassFormatException {
+        return methodSignatureReturnType(signature, true);
+    }
+
+
+    /**
+     * @param  signature    Method signature
+     * @param chopit Shorten class names ?
+     * @return return type of method
+     * @throws  ClassFormatException  
+     */
+    public static final String methodSignatureReturnType( String signature, boolean chopit )
+            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;
+    }
+
+
+    /**
+     * 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
+     */
+    public static final String methodSignatureToString( String signature, String name, String access ) {
+        return methodSignatureToString(signature, name, access, true);
+    }
+
+
+    public static final String methodSignatureToString( String signature, String name,
+            String access, boolean chopit ) {
+        return methodSignatureToString(signature, name, access, chopit, null);
+    }
+
+
+    /**
+     * A return­type signature represents the return value from a method.
+     * It is a series of bytes in the following grammar:
+     *
+     * <return_signature> ::= <field_type> | 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:
+     *
+     * <argument_signature> ::= <field_type>
+     *
+     * A method signature represents the arguments that the method expects, and
+     * the value that it returns.
+     * <method_signature> ::= (<arguments_signature>) <return_signature>
+     * <arguments_signature>::= <argument_signature>*
+     *
+     * 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  
+     */
+    public static final String methodSignatureToString( String signature, String name,
+            String access, boolean chopit, LocalVariableTable vars ) 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(" ").append(l.getName());
+                    }
+                } else {
+                    buf.append(" arg").append(var_index);
+                }
+                if ("double".equals(param_type) || "long".equals(param_type)) {
+                    var_index += 2;
+                } else {
+                    var_index++;
+                }
+                buf.append(", ");
+                //corrected concurrent private static field acess
+                index += unwrap(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) {
+            buf.setLength(buf.length() - 2);
+        }
+        buf.append(")");
+        return access + ((access.length() > 0) ? " " : "") + // May be an empty string
+                type + " " + name + buf.toString();
+    }
+
+
+    // Guess what this does
+    private static final int pow2( int n ) {
+        return 1 << n;
+    }
+
+
+    /**
+     * Replace all occurences of <em>old</em> in <em>str</em> with <em>new</em>.
+     *
+     * @param str String to permute
+     * @param old String to be replaced
+     * @param new_ Replacement string
+     * @return new String object
+     */
+    public static final String replace( String str, String old, String new_ ) {
+        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;
     }
 
-    return buf.toString();
-  }
+
+    /**
+     * Converts signature to string with all class names compacted.
+     *
+     * @param signature to convert
+     * @return Human readable signature
+     */
+    public static final String signatureToString( String signature ) {
+        return signatureToString(signature, true);
+    }
+
+
+    /**
+     * 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:
+     *
+     * <PRE>
+     * <field_signature> ::= <field_type>
+     * <field_type>      ::= <base_type>|<object_type>|<array_type>
+     * <base_type>       ::= B|C|D|F|I|J|S|Z
+     * <object_type>     ::= L<fullclassname>;
+     * <array_type>      ::= [<field_type>
+     *
+     * 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<fullclassname>; ... an object of the given class
+     * S short signed short
+     * Z boolean true or false
+     * [<field sig> ... array
+     * </PRE>
+     *
+     * 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
+     */
+    public static final String signatureToString( String signature, boolean chopit ) {
+        //corrected concurrent private static field acess
+        wrap(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);
+                    }
+                    //corrected concurrent private static field acess
+                    wrap(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 brackets;
+                    String type;
+                    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);
+                    //corrected concurrent private static field acess
+                    //Utility.consumed_chars += consumed_chars; is replaced by:
+                    int _temp = unwrap(Utility.consumed_chars) + consumed_chars;
+                    wrap(Utility.consumed_chars, _temp);
+                    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);
+        }
+    }
+
+
+    /** 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
+     */
+    public static String getSignature( String type ) {
+        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) {
+            buf.append('L').append(type.replace('.', '/')).append(';');
+        }
+        return buf.toString();
+    }
+
+
+    private static int countBrackets( 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;
+    }
+
+
+    /**
+     * Return type of method signature as a byte value as defined in <em>Constants</em>
+     *
+     * @param  signature in format described above
+     * @return type of method signature
+     * @see    Constants
+     */
+    public static final byte typeOfMethodSignature( String signature ) throws ClassFormatException {
+        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);
+        }
+    }
+
+
+    /**
+     * Return type of signature as a byte value as defined in <em>Constants</em>
+     *
+     * @param  signature in format described above
+     * @return type of signature
+     * @see    Constants
+     */
+    public static final byte typeOfSignature( String signature ) throws ClassFormatException {
+        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);
+        }
+    }
+
+
+    /** Map opcode names to opcode numbers. E.g., return Constants.ALOAD for "aload"
+     */
+    public static short searchOpcode( String name ) {
+        name = name.toLowerCase(Locale.ENGLISH);
+        for (short i = 0; i < Constants.OPCODE_NAMES.length; i++) {
+            if (Constants.OPCODE_NAMES[i].equals(name)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+
+    /**
+     * Convert (signed) byte to (unsigned) short value, i.e., all negative
+     * values become positive.
+     */
+    private static final short byteToShort( byte b ) {
+        return (b < 0) ? (short) (256 + b) : (short) b;
+    }
+
+
+    /** Convert bytes into hexidecimal string
+     *
+     * @return bytes as hexidecimal string, e.g. 00 FA 12 ...
+     */
+    public static final String toHexString( byte[] bytes ) {
+        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) {
+                buf.append('0');
+            }
+            buf.append(hex);
+            if (i < bytes.length - 1) {
+                buf.append(' ');
+            }
+        }
+        return buf.toString();
+    }
+
+
+    /**
+     * 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
+     */
+    public static final String format( int i, int length, boolean left_justify, char fill ) {
+        return fillup(Integer.toString(i), length, left_justify, 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
+     */
+    public static final String fillup( String str, int length, boolean left_justify, char fill ) {
+        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);
+        }
+        return new String(buf) + str;
+    }
+
+
+    static final boolean equals( 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 void printArray( PrintStream out, Object[] obj ) {
+        out.println(printArray(obj, true));
+    }
+
+
+    public static final void printArray( PrintWriter out, Object[] obj ) {
+        out.println(printArray(obj, true));
+    }
+
+
+    public static final String printArray( Object[] obj ) {
+        return printArray(obj, true);
+    }
+
+
+    public static final String printArray( Object[] obj, boolean braces ) {
+        return printArray(obj, braces, false);
+    }
+
+
+    public static final String printArray( 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 ? "\"" : "")).append(obj[i].toString()).append(
+                        (quote ? "\"" : ""));
+            } else {
+                buf.append("null");
+            }
+            if (i < obj.length - 1) {
+                buf.append(", ");
+            }
+        }
+        if (braces) {
+            buf.append('}');
+        }
+        return buf.toString();
+    }
+
+
+    /** @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)
+     */
+    public static boolean isJavaIdentifierPart( char ch ) {
+        return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))
+                || ((ch >= '0') && (ch <= '9')) || (ch == '_');
+    }
+
+
+    /** 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 <p><ul><li> the ASCII value as a
+     * hexadecimal string, if the value is not in the range
+     * 200..247</li> <li>a Java identifier char not used in a lowercase
+     * hexadecimal string, if the value is in the range
+     * 200..247</li><ul></p>
+     *
+     * <p>This operation inflates the original byte array by roughly 40-50%</p>
+     *
+     * @param bytes the byte array to convert
+     * @param compress use gzip to minimize string
+     */
+    public static String encode( byte[] bytes, boolean compress ) throws IOException {
+        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();
+    }
+
+
+    /** Decode a string back to a byte array.
+     *
+     * @param s the string to convert
+     * @param uncompress use gzip to uncompress the stream of bytes
+     */
+    public static byte[] decode( String s, boolean uncompress ) throws IOException {
+        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;
+    }
+
+    // A-Z, g-z, _, $
+    private static final int FREE_CHARS = 48;
+    static int[] CHAR_MAP = new int[FREE_CHARS];
+    static int[] MAP_CHAR = new int[256]; // Reverse map
+    private static final char ESCAPE_CHAR = '$';
+    static {
+        int j = 0;
+        for (int i = 'A'; i <= 'Z'; i++) {
+            CHAR_MAP[j] = i;
+            MAP_CHAR[i] = j;
+            j++;
+        }
+        for (int i = 'g'; i <= 'z'; i++) {
+            CHAR_MAP[j] = i;
+            MAP_CHAR[i] = j;
+            j++;
+        }
+        CHAR_MAP[j] = '$';
+        MAP_CHAR['$'] = j;
+        j++;
+        CHAR_MAP[j] = '_';
+        MAP_CHAR['_'] = j;
+    }
+
+    /** Decode characters into bytes.
+     * Used by <a href="Utility.html#decode(java.lang.String, boolean)">decode()</a>
+     */
+    private static class JavaReader extends FilterReader {
+
+        public JavaReader(Reader in) {
+            super(in);
+        }
+
+
+        public int read() throws IOException {
+            int b = in.read();
+            if (b != ESCAPE_CHAR) {
+                return b;
+            }
+            int i = in.read();
+            if (i < 0) {
+                return -1;
+            }
+            if (((i >= '0') && (i <= '9')) || ((i >= 'a') && (i <= 'f'))) { // Normal escape
+                int j = in.read();
+                if (j < 0) {
+                    return -1;
+                }
+                char[] tmp = {
+                        (char) i, (char) j
+                };
+                int s = Integer.parseInt(new String(tmp), 16);
+                return s;
+            }
+            return MAP_CHAR[i];
+        }
+
+
+        public int read( char[] cbuf, int off, int len ) throws IOException {
+            for (int i = 0; i < len; i++) {
+                cbuf[off + i] = (char) read();
+            }
+            return len;
+        }
+    }
+
+    /** Encode bytes into valid java identifier characters.
+     * Used by <a href="Utility.html#encode(byte[], boolean)">encode()</a>
+     */
+    private static class JavaWriter extends FilterWriter {
+
+        public JavaWriter(Writer out) {
+            super(out);
+        }
+
+
+        public void write( int b ) throws IOException {
+            if (isJavaIdentifierPart((char) b) && (b != ESCAPE_CHAR)) {
+                out.write(b);
+            } else {
+                out.write(ESCAPE_CHAR); // Escape character
+                // Special escape
+                if (b >= 0 && b < FREE_CHARS) {
+                    out.write(CHAR_MAP[b]);
+                } else { // Normal escape
+                    char[] tmp = Integer.toHexString(b).toCharArray();
+                    if (tmp.length == 1) {
+                        out.write('0');
+                        out.write(tmp[0]);
+                    } else {
+                        out.write(tmp[0]);
+                        out.write(tmp[1]);
+                    }
+                }
+            }
+        }
+
+
+        public void write( char[] cbuf, int off, int len ) throws IOException {
+            for (int i = 0; i < len; i++) {
+                write(cbuf[off + i]);
+            }
+        }
+
+
+        public void write( String str, int off, int len ) throws IOException {
+            write(str.toCharArray(), off, len);
+        }
+    }
+
+
+    /**
+     * Escape all occurences of newline chars '\n', quotes \", etc.
+     */
+    public static final String convertString( String label ) {
+        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;
+            }

[... 5 lines stripped ...]


---------------------------------------------------------------------
To unsubscribe, e-mail: bcel-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: bcel-dev-help@jakarta.apache.org