alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Utility.java)

This example Java source code file (Utility.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

bytearrayoutputstream, char_map, classformatexception, constantpool, illegally, invalid, ioexception, javareader, javawriter, map_char, runtimeexception, should, string, stringbuffer, util, zip

The Utility.java Java example source code

/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
package com.sun.org.apache.bcel.internal.classfile;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *    "Apache BCEL" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache BCEL", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

import com.sun.org.apache.bcel.internal.Constants;
import com.sun.org.apache.bcel.internal.util.ByteSequence;
import java.io.*;
import java.util.ArrayList;
import java.util.zip.*;

/**
 * Utility functions that do not really belong to any class in particular.
 *
 * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm
 */
public abstract class Utility {
  private static int consumed_chars; /* 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] + " ");
      }
    }

    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!)
   * @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 + 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 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 = " + 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!");
            buf.setLength(0);
          }
        }
      }
    }

    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 becomes
   * <em>String.
   *
   * @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, i.e., chop off the prefix,
   * if the
   * class name starts with this string and the flag <em>chopit is true.
   * Slashes <em>/ 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
   */
  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 becomes
   * <em>java.lang.String,
   * e.g.. If <em>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
   */
  public static final String compactClassName(String str, boolean chopit) {
    return compactClassName(str, "java.lang.", chopit);
  }

  private static final boolean is_digit(char ch) {
    return (ch >= '0') && (ch <= '9');
  }

  private static final boolean is_space(char ch) {
    return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n');
  }

  /**
   * @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(")" + 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
  {
    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;
  }
  /**
   * @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> ::=  | 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> ::= 
   *
   * A method signature represents the arguments that the method expects, and
   * the value that it returns.
   * <method_signature> ::= () 
   * <arguments_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(" " + 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();
  }

  // Guess what this does
  private static final int pow2(int n) {
    return 1 << n;
  }

  /**
   * Replace all occurences of <em>old in str with new.
   *
   * @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>      ::= ||
   * <base_type>       ::= B|C|D|F|I|J|S|Z
   * <object_type>     ::= L;
   * <array_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)
  {
    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);
    }
  }

  /** 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' + type.replace('.', '/') + ';');

    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
   *
   * @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
   *
   * @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();

    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);
    else
      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? "\"" : "") + obj[i].toString() + (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>
  • the ASCII value as a * hexadecimal string, if the value is not in the range * 200..247</li>
  • a Java identifier char not used in a lowercase * hexadecimal string, if the value is in the range * 200..247</li>

      * * <p>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 */ 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 bytes the byte array 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; private static int[] CHAR_MAP = new int[FREE_CHARS]; private static int[] MAP_CHAR = new int[256]; // Reverse map private static final char ESCAPE_CHAR = '$'; static { int j = 0, k = 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() */ 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; } else { 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; } else { // Special escape 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() */ 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; } } return buf.toString(); } }

Other Java examples (source code examples)

Here is a short list of links related to this Java Utility.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.