⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 utility.java

📁 Java Bytecode Editor 是一个 JAVA 的字节码反汇编和修改器。它可以很方便的修改已经编译成 Class 文件的 JAVA 文件。
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
package org.apache.bcel.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 org.apache.bcel.Constants;
import org.apache.bcel.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.
 *
 * @version $Id: Utility.java,v 1.2 2006/08/22 15:33:21 andos Exp $
 * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
 */
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!)</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 + 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!");
	    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>.
   *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -