[Proxool-cvs] proxool/src/java/org/logicalcobwebs/asm/util CheckClassAdapter.java,NONE,1.1 CheckCode
UNMAINTAINED!
Brought to you by:
billhorsman
From: <bil...@us...> - 2003-12-12 19:16:12
|
Update of /cvsroot/proxool/proxool/src/java/org/logicalcobwebs/asm/util In directory sc8-pr-cvs1:/tmp/cvs-serv22981/src/java/org/logicalcobwebs/asm/util Added Files: CheckClassAdapter.java CheckCodeAdapter.java DumpClassVisitor.java DumpCodeVisitor.java PrintClassVisitor.java PrintCodeVisitor.java TraceClassVisitor.java TraceCodeVisitor.java package.html Log Message: Repackaged ASM project --- NEW FILE: CheckClassAdapter.java --- /*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000,2002,2003 INRIA, France Telecom * 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. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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. * * Contact: Eri...@rd... * * Author: Eric Bruneton */ package org.logicalcobwebs.asm.util; import org.logicalcobwebs.asm.ClassAdapter; import org.logicalcobwebs.asm.ClassVisitor; import org.logicalcobwebs.asm.CodeVisitor; import org.logicalcobwebs.asm.Constants; import org.logicalcobwebs.asm.Attribute; /** * A {@link ClassAdapter ClssAdapter} that checks that its methods are properly * used. More precisely this class adapter checks each method call individually, * based <i>only</i> on its arguments, but does <i>not</i> check the * <i>sequence</i> of method calls. For example, the invalid sequence * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC, * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter. */ public class CheckClassAdapter extends ClassAdapter { /** * <tt>true</tt> if the visit method has been called. */ private boolean start; /** * <tt>true</tt> if the visitEnd method has been called. */ private boolean end; /** * Constructs a new {@link CheckClassAdapter CheckClassAdapter} object. * * @param cv the class visitor to which this adapter must delegate calls. */ public CheckClassAdapter (final ClassVisitor cv) { super(cv); } public void visit ( final int access, final String name, final String superName, final String[] interfaces, final String sourceFile) { if (start) { throw new IllegalStateException("visit must be called only once"); } else { start = true; } checkState(); checkAccess(access, 1 + 2 + 4 + 16 + 512 + 1024 + 32 + 65536 + 131072); CheckCodeAdapter.checkInternalName(name, "class name"); if (name.equals("java/lang/Object")) { if (superName != null) { throw new IllegalArgumentException( "The super class name of the Object class must be 'null'"); } } else { CheckCodeAdapter.checkInternalName(superName, "super class name"); } if ((access & Constants.ACC_INTERFACE) != 0) { if (!superName.equals("java/lang/Object")) { throw new IllegalArgumentException( "The super class name of interfaces must be 'java/lang/Object'"); } } if (interfaces != null) { for (int i = 0; i < interfaces.length; ++i) { CheckCodeAdapter.checkInternalName( interfaces[i], "interface name at index " + i); } } cv.visit(access, name, superName, interfaces, sourceFile); } public void visitInnerClass ( final String name, final String outerName, final String innerName, final int access) { checkState(); CheckCodeAdapter.checkInternalName(name, "class name"); if (outerName != null) { CheckCodeAdapter.checkInternalName(outerName, "outer class name"); } if (innerName != null) { CheckCodeAdapter.checkIdentifier(innerName, "inner class name"); } checkAccess(access, 1 + 2 + 4 + 8 + 16 + 512 + 1024 + 32); cv.visitInnerClass(name, outerName, innerName, access); } public void visitField ( final int access, final String name, final String desc, final Object value, final Attribute attrs) { checkState(); checkAccess(access, 1 + 2 + 4 + 8 + 16 + 64 + 128 + 65536 + 131072); CheckCodeAdapter.checkIdentifier(name, "field name"); CheckCodeAdapter.checkDesc(desc, false); if (value != null) { CheckCodeAdapter.checkConstant(value); } cv.visitField(access, name, desc, value, attrs); } public CodeVisitor visitMethod ( final int access, final String name, final String desc, final String[] exceptions, final Attribute attrs) { checkState(); checkAccess( access, 1 + 2 + 4 + 8 + 16 + 32 + 256 + 1024 + 2048 + 65536 + 131072); CheckCodeAdapter.checkMethodIdentifier(name, "method name"); CheckCodeAdapter.checkMethodDesc(desc); if (exceptions != null) { for (int i = 0; i < exceptions.length; ++i) { CheckCodeAdapter.checkInternalName( exceptions[i], "exception name at index " + i); } } return new CheckCodeAdapter( cv.visitMethod(access, name, desc, exceptions, attrs)); } public void visitAttribute (final Attribute attr) { checkState(); if (attr == null) { throw new IllegalArgumentException( "Invalid attribute (must not be null)"); } } public void visitEnd () { checkState(); end = true; cv.visitEnd(); } // --------------------------------------------------------------------------- /** * Checks that the visit method has been called and that visitEnd has not been * called. */ private void checkState () { if (!start) { throw new IllegalStateException( "Cannot visit member before visit has been called."); } if (end) { throw new IllegalStateException( "Cannot visit member after visitEnd has been called."); } } /** * Checks that the given access flags do not contain invalid flags. This * method also checks that mutually incompatible flags are not set * simultaneously. * * @param access the access flags to be checked * @param possibleAccess the valid access flags. */ static void checkAccess (final int access, final int possibleAccess) { if ((access & ~possibleAccess) != 0) { throw new IllegalArgumentException("Invalid access flags: " + access); } int pub = ((access & Constants.ACC_PUBLIC) != 0 ? 1 : 0); int pri = ((access & Constants.ACC_PRIVATE) != 0 ? 1 : 0); int pro = ((access & Constants.ACC_PROTECTED) != 0 ? 1 : 0); if (pub + pri + pro > 1) { throw new IllegalArgumentException( "public private and protected are mutually exclusive: " + access); } int fin = ((access & Constants.ACC_FINAL) != 0 ? 1 : 0); int abs = ((access & Constants.ACC_ABSTRACT) != 0 ? 1 : 0); if (fin + abs > 1) { throw new IllegalArgumentException( "final and abstract are mutually exclusive: " + access); } } } --- NEW FILE: CheckCodeAdapter.java --- /*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000,2002,2003 INRIA, France Telecom * 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. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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. * * Contact: Eri...@rd... * * Author: Eric Bruneton */ package org.logicalcobwebs.asm.util; import org.logicalcobwebs.asm.Label; import org.logicalcobwebs.asm.CodeAdapter; import org.logicalcobwebs.asm.CodeVisitor; import org.logicalcobwebs.asm.Constants; import org.logicalcobwebs.asm.Attribute; import java.util.HashMap; /** * A {@link CodeAdapter CodeAdapter} that checks that its methods are properly * used. More precisely this code adapter checks each instruction individually * (i.e., each visit method checks some preconditions based <i>only</i> on its * arguments - such as the fact that the given opcode is correct for a given * visit method), but does <i>not</i> check the <i>sequence</i> of instructions. * For example, in a method whose signature is <tt>void m ()</tt>, the invalid * instruction IRETURN, or the invalid sequence IADD L2I will <i>not</i> be * detected by this code adapter. */ public class CheckCodeAdapter extends CodeAdapter { /** * <tt>true</tt> if the visitMaxs method has been called. */ private boolean end; /** * The already visited labels. This map associate Integer values to Label * keys. */ private HashMap labels; /** * Code of the visit method to be used for each opcode. */ private final static int[] TYPE = new int[] { 0, //NOP 0, //ACONST_NULL 0, //ICONST_M1 0, //ICONST_0 0, //ICONST_1 0, //ICONST_2 0, //ICONST_3 0, //ICONST_4 0, //ICONST_5 0, //LCONST_0 0, //LCONST_1 0, //FCONST_0 0, //FCONST_1 0, //FCONST_2 0, //DCONST_0 0, //DCONST_1 1, //BIPUSH 1, //SIPUSH 7, //LDC -1, //LDC_W -1, //LDC2_W 2, //ILOAD 2, //LLOAD 2, //FLOAD 2, //DLOAD 2, //ALOAD -1, //ILOAD_0 -1, //ILOAD_1 -1, //ILOAD_2 -1, //ILOAD_3 -1, //LLOAD_0 -1, //LLOAD_1 -1, //LLOAD_2 -1, //LLOAD_3 -1, //FLOAD_0 -1, //FLOAD_1 -1, //FLOAD_2 -1, //FLOAD_3 -1, //DLOAD_0 -1, //DLOAD_1 -1, //DLOAD_2 -1, //DLOAD_3 -1, //ALOAD_0 -1, //ALOAD_1 -1, //ALOAD_2 -1, //ALOAD_3 0, //IALOAD 0, //LALOAD 0, //FALOAD 0, //DALOAD 0, //AALOAD 0, //BALOAD 0, //CALOAD 0, //SALOAD 2, //ISTORE 2, //LSTORE 2, //FSTORE 2, //DSTORE 2, //ASTORE -1, //ISTORE_0 -1, //ISTORE_1 -1, //ISTORE_2 -1, //ISTORE_3 -1, //LSTORE_0 -1, //LSTORE_1 -1, //LSTORE_2 -1, //LSTORE_3 -1, //FSTORE_0 -1, //FSTORE_1 -1, //FSTORE_2 -1, //FSTORE_3 -1, //DSTORE_0 -1, //DSTORE_1 -1, //DSTORE_2 -1, //DSTORE_3 -1, //ASTORE_0 -1, //ASTORE_1 -1, //ASTORE_2 -1, //ASTORE_3 0, //IASTORE 0, //LASTORE 0, //FASTORE 0, //DASTORE 0, //AASTORE 0, //BASTORE 0, //CASTORE 0, //SASTORE 0, //POP 0, //POP2 0, //DUP 0, //DUP_X1 0, //DUP_X2 0, //DUP2 0, //DUP2_X1 0, //DUP2_X2 0, //SWAP 0, //IADD 0, //LADD 0, //FADD 0, //DADD 0, //ISUB 0, //LSUB 0, //FSUB 0, //DSUB 0, //IMUL 0, //LMUL 0, //FMUL 0, //DMUL 0, //IDIV 0, //LDIV 0, //FDIV 0, //DDIV 0, //IREM 0, //LREM 0, //FREM 0, //DREM 0, //INEG 0, //LNEG 0, //FNEG 0, //DNEG 0, //ISHL 0, //LSHL 0, //ISHR 0, //LSHR 0, //IUSHR 0, //LUSHR 0, //IAND 0, //LAND 0, //IOR 0, //LOR 0, //IXOR 0, //LXOR 8, //IINC 0, //I2L 0, //I2F 0, //I2D 0, //L2I 0, //L2F 0, //L2D 0, //F2I 0, //F2L 0, //F2D 0, //D2I 0, //D2L 0, //D2F 0, //I2B 0, //I2C 0, //I2S 0, //LCMP 0, //FCMPL 0, //FCMPG 0, //DCMPL 0, //DCMPG 6, //IFEQ 6, //IFNE 6, //IFLT 6, //IFGE 6, //IFGT 6, //IFLE 6, //IF_ICMPEQ 6, //IF_ICMPNE 6, //IF_ICMPLT 6, //IF_ICMPGE 6, //IF_ICMPGT 6, //IF_ICMPLE 6, //IF_ACMPEQ 6, //IF_ACMPNE 6, //GOTO 6, //JSR 2, //RET 9, //TABLESWITCH 10, //LOOKUPSWITCH 0, //IRETURN 0, //LRETURN 0, //FRETURN 0, //DRETURN 0, //ARETURN 0, //RETURN 4, //GETSTATIC 4, //PUTSTATIC 4, //GETFIELD 4, //PUTFIELD 5, //INVOKEVIRTUAL 5, //INVOKESPECIAL 5, //INVOKESTATIC 5, //INVOKEINTERFACE -1, //UNUSED 3, //NEW 1, //NEWARRAY 3, //ANEWARRAY 0, //ARRAYLENGTH 0, //ATHROW 3, //CHECKCAST 3, //INSTANCEOF 0, //MONITORENTER 0, //MONITOREXIT -1, //WIDE 11, //MULTIANEWARRAY 6, //IFNULL 6, //IFNONNULL -1, //GOTO_W -1 //JSR_W }; /** * Constructs a new {@link CheckCodeAdapter CheckCodeAdapter} object. * * @param cv the code visitor to which this adapter must delegate calls. */ public CheckCodeAdapter (final CodeVisitor cv) { super(cv); this.labels = new HashMap(); } public void visitInsn (final int opcode) { checkEnd(); checkOpcode(opcode, 0); cv.visitInsn(opcode); } public void visitIntInsn (final int opcode, final int operand) { checkEnd(); checkOpcode(opcode, 1); switch (opcode) { case Constants.BIPUSH: checkSignedByte(operand, "Invalid operand"); break; case Constants.SIPUSH: checkSignedShort(operand, "Invalid operand"); break; //case Constants.NEWARRAY: default: if (operand < Constants.T_BOOLEAN || operand > Constants.T_LONG) { throw new IllegalArgumentException( "Invalid operand (must be an array type code T_...): " + operand); } } cv.visitIntInsn(opcode, operand); } public void visitVarInsn (final int opcode, final int var) { checkEnd(); checkOpcode(opcode, 2); checkUnsignedShort(var, "Invalid variable index"); cv.visitVarInsn(opcode, var); } public void visitTypeInsn (final int opcode, final String desc) { checkEnd(); checkOpcode(opcode, 3); if (desc != null && desc.length() > 0 && desc.charAt(0) == '[') { checkDesc(desc, false); } else { checkInternalName(desc, "type"); } if (opcode == Constants.NEW && desc.charAt(0) == '[') { throw new IllegalArgumentException( "NEW cannot be used to create arrays: " + desc); } cv.visitTypeInsn(opcode, desc); } public void visitFieldInsn ( final int opcode, final String owner, final String name, final String desc) { checkEnd(); checkOpcode(opcode, 4); checkInternalName(owner, "owner"); checkIdentifier(name, "name"); checkDesc(desc, false); cv.visitFieldInsn(opcode, owner, name, desc); } public void visitMethodInsn ( final int opcode, final String owner, final String name, final String desc) { checkEnd(); checkOpcode(opcode, 5); checkInternalName(owner, "owner"); checkMethodIdentifier(name, "name"); checkMethodDesc(desc); cv.visitMethodInsn(opcode, owner, name, desc); } public void visitJumpInsn (final int opcode, final Label label) { checkEnd(); checkOpcode(opcode, 6); checkLabel(label, false, "label"); cv.visitJumpInsn(opcode, label); } public void visitLabel (final Label label) { checkEnd(); checkLabel(label, false, "label"); if (labels.get(label) != null) { throw new IllegalArgumentException("Already visited label"); } else { labels.put(label, new Integer(labels.size())); } cv.visitLabel(label); } public void visitLdcInsn (final Object cst) { checkEnd(); checkConstant(cst); cv.visitLdcInsn(cst); } public void visitIincInsn (final int var, final int increment) { checkEnd(); checkUnsignedShort(var, "Invalid variable index"); checkSignedShort(increment, "Invalid increment"); cv.visitIincInsn(var, increment); } public void visitTableSwitchInsn ( final int min, final int max, final Label dflt, final Label labels[]) { checkEnd(); if (max < min) { throw new IllegalArgumentException( "Max = " + max + " must be greater than or equal to min = " + min); } checkLabel(dflt, false, "default label"); if (labels == null || labels.length != max - min + 1) { throw new IllegalArgumentException( "There must be max - min + 1 labels"); } for (int i = 0; i < labels.length; ++i) { checkLabel(labels[i], false, "label at index " + i); } cv.visitTableSwitchInsn(min, max, dflt, labels); } public void visitLookupSwitchInsn ( final Label dflt, final int keys[], final Label labels[]) { checkEnd(); checkLabel(dflt, false, "default label"); if (keys == null || labels == null || keys.length != labels.length) { throw new IllegalArgumentException( "There must be the same number of keys and labels"); } for (int i = 0; i < labels.length; ++i) { checkLabel(labels[i], false, "label at index " + i); } cv.visitLookupSwitchInsn(dflt, keys, labels); } public void visitMultiANewArrayInsn (final String desc, final int dims) { checkEnd(); checkDesc(desc, false); if (desc.charAt(0) != '[') { throw new IllegalArgumentException( "Invalid descriptor (must be an array type descriptor): " + desc); } if (dims < 1) { throw new IllegalArgumentException( "Invalid dimensions (must be greater than 0): " + dims); } if (dims > desc.lastIndexOf('[') + 1) { throw new IllegalArgumentException( "Invalid dimensions (must not be greater than dims(desc)): " + dims); } cv.visitMultiANewArrayInsn(desc, dims); } public void visitTryCatchBlock ( final Label start, final Label end, final Label handler, final String type) { checkLabel(start, true, "start label"); checkLabel(end, true, "end label"); checkLabel(handler, true, "handler label"); if (type != null) { checkInternalName(type, "type"); } int s = ((Integer)labels.get(start)).intValue(); int e = ((Integer)labels.get(end)).intValue(); if (e <= s) { throw new IllegalArgumentException( "Invalid start and end labels (end must be greater than start)"); } cv.visitTryCatchBlock(start, end, handler, type); } public void visitMaxs (final int maxStack, final int maxLocals) { checkEnd(); end = true; checkUnsignedShort(maxStack, "Invalid max stack"); checkUnsignedShort(maxLocals, "Invalid max locals"); cv.visitMaxs(maxStack, maxLocals); } public void visitLocalVariable ( final String name, final String desc, final Label start, final Label end, final int index) { checkIdentifier(name, "name"); checkDesc(desc, false); checkLabel(start, true, "start label"); checkLabel(end, true, "end label"); checkUnsignedShort(index, "Invalid variable index"); int s = ((Integer)labels.get(start)).intValue(); int e = ((Integer)labels.get(end)).intValue(); if (e <= s) { throw new IllegalArgumentException( "Invalid start and end labels (end must be greater than start)"); } cv.visitLocalVariable(name, desc, start, end, index); } public void visitLineNumber (final int line, final Label start) { checkUnsignedShort(line, "Invalid line number"); checkLabel(start, true, "start label"); cv.visitLineNumber(line, start); } public void visitAttribute (Attribute attr) { if (attr == null) { throw new IllegalArgumentException( "Invalid attribute (must not be null)"); } } // --------------------------------------------------------------------------- /** * Checks that the visitMaxs method has not been called. */ void checkEnd () { if (end) { throw new IllegalStateException( "Cannot visit instructions after visitMaxs has been called."); } } /** * Checks that the type of the given opcode is equal to the given type. * * @param opcode the opcode to be checked. * @param type the expected opcode type. */ static void checkOpcode (final int opcode, final int type) { if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) { throw new IllegalArgumentException("Invalid opcode: " + opcode); } } /** * Checks that the given value is a signed byte. * * @param value the value to be checked. * @param msg an message to be used in case of error. */ static void checkSignedByte (final int value, final String msg) { if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { throw new IllegalArgumentException( msg + " (must be a signed byte): " + value); } } /** * Checks that the given value is a signed short. * * @param value the value to be checked. * @param msg an message to be used in case of error. */ static void checkSignedShort (final int value, final String msg) { if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { throw new IllegalArgumentException( msg + " (must be a signed short): " + value); } } /** * Checks that the given value is an unsigned short. * * @param value the value to be checked. * @param msg an message to be used in case of error. */ static void checkUnsignedShort (final int value, final String msg) { if (value < 0 || value > 65535) { throw new IllegalArgumentException( msg + " (must be an unsigned short): " + value); } } /** * Checks that the given value is an {@link java.lang.Integer Integer}, a * {@link java.lang.Float Float}, a {@link java.lang.Long Long}, a {@link * java.lang.Double Double} or a {@link String String}. * * @param cst the value to be checked. */ static void checkConstant (final Object cst) { if (!(cst instanceof Integer) && !(cst instanceof Float) && !(cst instanceof Long) && !(cst instanceof Double) && !(cst instanceof String)) { throw new IllegalArgumentException("Invalid constant: " + cst); } } /** * Checks that the given string is a valid Java identifier. * * @param name the string to be checked. * @param msg a message to be used in case of error. */ static void checkIdentifier (final String name, final String msg) { checkIdentifier(name, 0, -1, msg); } /** * Checks that the given substring is a valid Java identifier. * * @param name the string to be checked. * @param start index of the first character of the identifier (inclusive). * @param end index of the last character of the identifier (exclusive). -1 is * equivalent to <tt>name.length()</tt> if name is not <tt>null</tt>. * @param msg a message to be used in case of error. */ static void checkIdentifier ( final String name, final int start, final int end, final String msg) { if (name == null || (end == -1 ? name.length() <= start : end <= start)) { throw new IllegalArgumentException( "Invalid " + msg + " (must not be null or empty)"); } if (!Character.isJavaIdentifierStart(name.charAt(start))) { throw new IllegalArgumentException( "Invalid " + msg + " (must be a valid Java identifier): " + name); } int max = (end == -1 ? name.length() : end); for (int i = start + 1; i < max; ++i) { if (!Character.isJavaIdentifierPart(name.charAt(i))) { throw new IllegalArgumentException( "Invalid " + msg + " (must be a valid Java identifier): " + name); } } } /** * Checks that the given string is a valid Java identifier or is equal to * '<init>' or '<clinit>'. * * @param name the string to be checked. * @param msg a message to be used in case of error. */ static void checkMethodIdentifier (final String name, final String msg) { if (name == null || name.length() == 0) { throw new IllegalArgumentException( "Invalid " + msg + " (must not be null or empty)"); } if (name.equals("<init>") || name.equals("<clinit>")) { return; } if (!Character.isJavaIdentifierStart(name.charAt(0))) { throw new IllegalArgumentException( "Invalid " + msg + " (must be a '<init>', '<clinit>' or a valid Java identifier): " + name); } for (int i = 1; i < name.length(); ++i) { if (!Character.isJavaIdentifierPart(name.charAt(i))) { throw new IllegalArgumentException( "Invalid " + msg + " (must be '<init>' or '<clinit>' or a valid Java identifier): " + name); } } } /** * Checks that the given string is a valid internal class name. * * @param name the string to be checked. * @param msg a message to be used in case of error. */ static void checkInternalName (final String name, final String msg) { checkInternalName(name, 0, -1, msg); } /** * Checks that the given substring is a valid internal class name. * * @param name the string to be checked. * @param start index of the first character of the identifier (inclusive). * @param end index of the last character of the identifier (exclusive). -1 is * equivalent to <tt>name.length()</tt> if name is not <tt>null</tt>. * @param msg a message to be used in case of error. */ static void checkInternalName ( final String name, final int start, final int end, final String msg) { if (name == null || name.length() == 0) { throw new IllegalArgumentException( "Invalid " + msg + " (must not be null or empty)"); } int max = (end == -1 ? name.length() : end); try { int begin = start; int slash; do { slash = name.indexOf('/', begin + 1); if (slash == -1 || slash > max) { slash = max; } checkIdentifier(name, begin, slash, null); begin = slash + 1; } while (slash != max); } catch (IllegalArgumentException _) { throw new IllegalArgumentException( "Invalid " + msg + " (must be a fully qualified class name in internal form): " + name); } } /** * Checks that the given string is a valid type descriptor. * * @param desc the string to be checked. * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid. */ static void checkDesc (final String desc, final boolean canBeVoid) { int end = checkDesc(desc, 0, canBeVoid); if (end != desc.length()) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } } /** * Checks that a the given substring is a valid type descriptor. * * @param desc the string to be checked. * @param start index of the first character of the identifier (inclusive). * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid. * @return the index of the last character of the type decriptor, plus one. */ static int checkDesc ( final String desc, final int start, final boolean canBeVoid) { if (desc == null || start >= desc.length()) { throw new IllegalArgumentException( "Invalid type descriptor (must not be null or empty)"); } int index; switch (desc.charAt(start)) { case 'V': if (canBeVoid) { return start + 1; } else { throw new IllegalArgumentException("Invalid descriptor: " + desc); } case 'Z': case 'C': case 'B': case 'S': case 'I': case 'F': case 'J': case 'D': return start + 1; case '[': index = start + 1; while (index < desc.length() && desc.charAt(index) == '[') { ++index; } if (index < desc.length()) { return checkDesc(desc, index, false); } else { throw new IllegalArgumentException("Invalid descriptor: " + desc); } case 'L': index = desc.indexOf(';', start); if (index == -1 || index - start < 2) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } try { checkInternalName(desc, start + 1, index, null); } catch (IllegalArgumentException _) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } return index + 1; default: throw new IllegalArgumentException("Invalid descriptor: " + desc); } } /** * Checks that the given string is a valid method descriptor. * * @param desc the string to be checked. */ static void checkMethodDesc (final String desc) { if (desc == null || desc.length() == 0) { throw new IllegalArgumentException( "Invalid method descriptor (must not be null or empty)"); } if (desc.charAt(0) != '(' || desc.length() < 3) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } int start = 1; if (desc.charAt(start) != ')') { do { if (desc.charAt(start) == 'V') { throw new IllegalArgumentException("Invalid descriptor: " + desc); } start = checkDesc(desc, start, false); } while (start < desc.length() && desc.charAt(start) != ')'); } start = checkDesc(desc, start + 1, true); if (start != desc.length()) { throw new IllegalArgumentException("Invalid descriptor: " + desc); } } /** * Checks that the given label is not null. This method can also check that * the label has been visited. * * @param label the label to be checked. * @param checkVisited <tt>true</tt> to check that the label has been visited. * @param msg a message to be used in case of error. */ void checkLabel ( final Label label, final boolean checkVisited, final String msg) { if (label == null) { throw new IllegalArgumentException( "Invalid " + msg + " (must not be null)"); } if (checkVisited && labels.get(label) == null) { throw new IllegalArgumentException( "Invalid " + msg + " (must be visited first)"); } } } --- NEW FILE: DumpClassVisitor.java --- /*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000,2002,2003 INRIA, France Telecom * 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. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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. * * Contact: Eri...@rd... * * Author: Eric Bruneton */ package org.logicalcobwebs.asm.util; import org.logicalcobwebs.asm.Constants; import org.logicalcobwebs.asm.ClassReader; import org.logicalcobwebs.asm.CodeVisitor; import org.logicalcobwebs.asm.Attribute; import java.io.PrintWriter; /** * A {@link PrintClassVisitor PrintClassVisitor} that prints the ASM code that * generates the classes it visits. This class visitor can be used to quickly * write ASM code to generate some given bytecode: * <ul> * <li>write the Java source code equivalent to the bytecode you want to * generate;</li> * <li>compile it with <tt>javac</tt>;</li> * <li>make a {@link DumpClassVisitor DumpClassVisitor} visit this compiled * class (see the {@link #main main} method);</li> * <li>edit the generated source code, if necessary.</li> * </ul> * The source code printed when visiting the <tt>Hello</tt> class is the * following: * <p> * <blockquote> * <pre> * import org.logicalcobwebs.asm.*; * import java.io.FileOutputStream; * * public class Dump implements Constants { * * public static void main (String[] args) throws Exception { * * ClassWriter cw = new ClassWriter(false); * CodeVisitor cv; * * cw.visit(ACC_PUBLIC + ACC_SUPER, "Hello", "java/lang/Object", null, "Hello.java"); * * { * cv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null); * cv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); * cv.visitLdcInsn("hello"); * cv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); * cv.visitInsn(RETURN); * cv.visitMaxs(2, 1); * } * { * cv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null); * cv.visitVarInsn(ALOAD, 0); * cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); * cv.visitInsn(RETURN); * cv.visitMaxs(1, 1); * } * cw.visitEnd(); * * FileOutputStream os = new FileOutputStream("Dumped.class"); * os.write(cw.toByteArray()); * os.close(); * } * } * </pre> * </blockquote> * where <tt>Hello</tt> is defined by: * <p> * <blockquote> * <pre> * public class Hello { * * public static void main (String[] args) { * System.out.println("hello"); * } * } * </pre> * </blockquote> */ public class DumpClassVisitor extends PrintClassVisitor { /** * Prints the ASM source code to generate the given class to the standard * output. * <p> * Usage: DumpClassVisitor <fully qualified class name> * * @param args the command line arguments. * * @throws Exception if the class cannot be found, or if an IO exception * occurs. */ public static void main (final String[] args) throws Exception { if (args.length == 0) { System.err.println("Prints the ASM code to generate the given class."); System.err.println("Usage: DumpClassVisitor <fully qualified class name>"); System.exit(-1); } ClassReader cr = new ClassReader(args[0]); cr.accept(new DumpClassVisitor(new PrintWriter(System.out)), true); } /** * Constructs a new {@link DumpClassVisitor DumpClassVisitor} object. * * @param pw the print writer to be used to print the class. */ public DumpClassVisitor (final PrintWriter pw) { super(pw); } public void visit ( final int access, final String name, final String superName, final String[] interfaces, final String sourceFile) { text.add("import org.logicalcobwebs.asm.*;\n"); text.add("import java.io.FileOutputStream;\n\n"); text.add("public class Dump implements Constants {\n\n"); text.add("public static void main (String[] args) throws Exception {\n\n"); text.add("ClassWriter cw = new ClassWriter(false);\n"); text.add("CodeVisitor cv;\n\n"); buf.setLength(0); buf.append("cw.visit("); appendAccess(access | 262144); buf.append(", "); appendConstant(buf, name); buf.append(", "); appendConstant(buf, superName); buf.append(", "); if (interfaces != null && interfaces.length > 0) { buf.append("new String[] {"); for (int i = 0; i < interfaces.length; ++i) { buf.append(i == 0 ? " " : ", "); appendConstant(buf, interfaces[i]); } buf.append(" }"); } else { buf.append("null"); } buf.append(", "); appendConstant(buf, sourceFile); buf.append(");\n\n"); text.add(buf.toString()); } public void visitInnerClass ( final String name, final String outerName, final String innerName, final int access) { buf.setLength(0); buf.append("cw.visitInnerClass("); appendConstant(buf, name); buf.append(", "); appendConstant(buf, outerName); buf.append(", "); appendConstant(buf, innerName); buf.append(", "); appendAccess(access); buf.append(");\n\n"); text.add(buf.toString()); } public void visitField ( final int access, final String name, final String desc, final Object value, final Attribute attrs) { buf.setLength(0); buf.append("cw.visitField("); appendAccess(access); buf.append(", "); appendConstant(buf, name); buf.append(", "); appendConstant(buf, desc); buf.append(", "); appendConstant(buf, value); buf.append(", null);\n\n"); if (attrs != null) { buf.append("// WARNING! skipped some non standard field attributes\n"); } text.add(buf.toString()); } public CodeVisitor visitMethod ( final int access, final String name, final String desc, final String[] exceptions, final Attribute attrs) { buf.setLength(0); buf.append("{\n").append("cv = cw.visitMethod("); appendAccess(access); buf.append(", "); appendConstant(buf, name); buf.append(", "); appendConstant(buf, desc); buf.append(", "); if (exceptions != null && exceptions.length > 0) { buf.append("new String[] {"); for (int i = 0; i < exceptions.length; ++i) { buf.append(i == 0 ? " " : ", "); appendConstant(buf, exceptions[i]); } buf.append(" }"); } else { buf.append("null"); } buf.append(", null);\n"); if (attrs != null) { buf.append("// WARNING! skipped some non standard method attributes\n"); } text.add(buf.toString()); PrintCodeVisitor pcv = new DumpCodeVisitor(); text.add(pcv.getText()); text.add("}\n"); return pcv; } public void visitAttribute (final Attribute attr) { buf.setLength(0); buf.append("// WARNING! skipped a non standard class attribute of type \""); buf.append(attr.type); buf.append("\"\n"); text.add(buf.toString()); } public void visitEnd () { text.add("cw.visitEnd();\n\n"); text.add("FileOutputStream os = new FileOutputStream(\"Dumped.class\");\n"); text.add("os.write(cw.toByteArray());\n"); text.add("os.close();\n"); text.add("}\n"); text.add("}\n"); super.visitEnd(); } /** * Appends a string representation of the given access modifiers to {@link * #buf buf}. * * @param access some access modifiers. */ void appendAccess (final int access) { boolean first = true; if ((access & Constants.ACC_PUBLIC) != 0) { buf.append("ACC_PUBLIC"); first = false; } if ((access & Constants.ACC_PRIVATE) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_PRIVATE"); first = false; } if ((access & Constants.ACC_PROTECTED) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_PROTECTED"); first = false; } if ((access & Constants.ACC_FINAL) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_FINAL"); first = false; } if ((access & Constants.ACC_STATIC) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_STATIC"); first = false; } if ((access & Constants.ACC_SYNCHRONIZED) != 0) { if (!first) { buf.append(" + "); } if ((access & 262144) != 0) { buf.append("ACC_SUPER"); } else { buf.append("ACC_SYNCHRONIZED"); } first = false; } if ((access & Constants.ACC_VOLATILE) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_VOLATILE"); first = false; } if ((access & Constants.ACC_TRANSIENT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_TRANSIENT"); first = false; } if ((access & Constants.ACC_NATIVE) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_NATIVE"); first = false; } if ((access & Constants.ACC_ABSTRACT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_ABSTRACT"); first = false; } if ((access & Constants.ACC_INTERFACE) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_INTERFACE"); first = false; } if ((access & Constants.ACC_STRICT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_STRICT"); first = false; } if ((access & Constants.ACC_SYNTHETIC) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_SYNTHETIC"); first = false; } if ((access & Constants.ACC_DEPRECATED) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_DEPRECATED"); first = false; } if (first) { buf.append("0"); } } /** * Appends a string representation of the given constant to the given buffer. * * @param buf a string buffer. * @param cst an {@link java.lang.Integer Integer}, {@link java.lang.Float * Float}, {@link java.lang.Long Long}, {@link java.lang.Double Double} * or {@link String String} object. May be <tt>null</tt>. */ static void appendConstant (final StringBuffer buf, final Object cst) { if (cst == null) { buf.append("null"); } else if (cst instanceof String) { String s = (String)cst; buf.append("\""); for (int i = 0; i < s.length(); ++i) { char c = s.charAt(i); if (c == '\n') { buf.append("\\n"); } else if (c == '\\') { buf.append("\\\\"); } else if (c == '"') { buf.append("\\\""); } else { buf.append(c); } } buf.append("\""); } else if (cst instanceof Integer) { buf.append("new Integer(") .append(cst) .append(")"); } else if (cst instanceof Float) { buf.append("new Float(") .append(cst) .append("F)"); } else if (cst instanceof Long) { buf.append("new Long(") .append(cst) .append("L)"); } else if (cst instanceof Double) { buf.append("new Double(") .append(cst) .append(")"); } } } --- NEW FILE: DumpCodeVisitor.java --- /*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000,2002,2003 INRIA, France Telecom * 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. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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. * * Contact: Eri...@rd... * * Author: Eric Bruneton */ package org.logicalcobwebs.asm.util; import org.logicalcobwebs.asm.Label; import org.logicalcobwebs.asm.Attribute; import java.util.HashMap; /** * A {@link PrintCodeVisitor PrintCodeVisitor} that prints the ASM code that * generates the code it visits. */ public class DumpCodeVisitor extends PrintCodeVisitor { /** * The label names. This map associate String values to Label keys. */ private final HashMap labelNames; /** * Constructs a new {@link DumpCodeVisitor DumpCodeVisitor} object. */ public DumpCodeVisitor () { this.labelNames = new HashMap(); } public void printInsn (final int opcode) { buf.append("cv.visitInsn("). append(OPCODES[opcode]). append(");\n"); } public void printIntInsn (final int opcode, final int operand) { buf.append("cv.visitIntInsn("). append(OPCODES[opcode]). append(", "). append(operand). append(");\n"); } public void printVarInsn (final int opcode, final int var) { buf.append("cv.visitVarInsn("). append(OPCODES[opcode]). append(", "). append(var). append(");\n"); } public void printTypeInsn (final int opcode, final String desc) { buf.append("cv.visitTypeInsn("). append(OPCODES[opcode]). append(", "); DumpClassVisitor.appendConstant(buf, desc); buf.append(");\n"); } public void printFieldInsn ( final int opcode, final String owner, final String name, final String desc) { buf.append("cv.visitFieldInsn(") .append(OPCODES[opcode]) .append(", "); DumpClassVisitor.appendConstant(buf, owner); buf.append(", "); DumpClassVisitor.appendConstant(buf, name); buf.append(", "); DumpClassVisitor.appendConstant(buf, desc); buf.append(");\n"); } public void printMethodInsn ( final int opcode, final String owner, final String name, final String desc) { buf.append("cv.visitMethodInsn(") .append(OPCODES[opcode]) .append(", "); DumpClassVisitor.appendConstant(buf, owner); buf.append(", "); DumpClassVisitor.appendConstant(buf, name); buf.append(", "); DumpClassVisitor.appendConstant(buf, desc); buf.append(");\n"); } public void printJumpInsn (final int opcode, final Label label) { declareLabel(label); buf.append("cv.visitJumpInsn(") .append(OPCODES[opcode]) .append(", "); appendLabel(label); buf.append(");\n"); } public void printLabel (final Label label) { declareLabel(label); buf.append("cv.visitLabel("); appendLabel(label); buf.append(");\n"); } public void printLdcInsn (final Object cst) { buf.append("cv.visitLdcInsn("); DumpClassVisitor.appendConstant(buf, cst); buf.append(");\n"); } public void printIincInsn (final int var, final int increment) { buf.append("cv.visitIincInsn(") .append(var) .append(", ") .append(increment) .append(");\n"); } public void printTableSwitchInsn ( final int min, final int max, final Label dflt, final Label labels[]) { for (int i = 0; i < labels.length; ++i) { declareLabel(labels[i]); } declareLabel(dflt); buf.append("cv.visitTableSwitchInsn(") .append(min) .append(", ") .append(max) .append(", "); appendLabel(dflt); buf.append(", new Label[] {"); for (int i = 0; i < labels.length; ++i) { buf.append(i == 0 ? " " : ", "); appendLabel(labels[i]); } buf.append(" });\n"); } public void printLookupSwitchInsn ( final Label dflt, final int keys[], final Label labels[]) { for (int i = 0; i < labels.length; ++i) { declareLabel(labels[i]); } declareLabel(dflt); buf.append("cv.visitLookupSwitchInsn("); appendLabel(dflt); buf.append(", new int[] {"); for (int i = 0; i < keys.length; ++i) { buf.append(i == 0 ? " " : ", ").append(keys[i]); } buf.append(" }, new Label[] {"); for (int i = 0; i < labels.length; ++i) { buf.append(i == 0 ? " " : ", "); appendLabel(labels[i]); } buf.append(" });\n"); } public void printMultiANewArrayInsn (final String desc, final int dims) { buf.append("cv.visitMultiANewArrayInsn("); DumpClassVisitor.appendConstant(buf, desc); buf.append(", ") .append(dims) .append(");\n"); } public void printTryCatchBlock ( final Label start, final Label end, final Label handler, final String type) { buf.append("cv.visitTryCatchBlock("); appendLabel(start); buf.append(", "); appendLabel(end); buf.append(", "); appendLabel(handler); buf.append(", "); DumpClassVisitor.appendConstant(buf, type); buf.append(");\n"); } public void printMaxs (final int maxStack, final int maxLocals) { buf.append("cv.visitMaxs(") .append(maxStack) .append(", ") .append(maxLocals) .append(");\n"); } public void printLocalVariable ( final String name, final String desc, final Label start, final Label end, final int index) { buf.append("cv.visitLocalVariable("); DumpClassVisitor.appendConstant(buf, name); buf.append(", "); DumpClassVisitor.appendConstant(buf, desc); buf.append(", "); appendLabel(start); buf.append(", "); appendLabel(end); buf.append(", ").append(index).append(");\n"); } public void printLineNumber (final int line, final Label start) { buf.append("cv.visitLineNumber(") .append(line) .append(", "); appendLabel(start); buf.append(");\n"); } public void printAttribute (final Attribute attr) { buf.append("// WARNING! skipped a non standard code attribute of type \""); buf.append(attr.type); buf.append("\"\n"); } /** * Appends a declaration of the given label to {@link #buf buf}. This * declaration is of the form "Label lXXX = new Label();". Does nothing * if the given label has already been declared. * * @param l a label. */ private void declareLabel (final Label l) { String name = (String)labelNames.get(l); if (name == null) { name = "l" + labelNames.size(); labelNames.put(l, name); buf.append("Label ") .append(name) .append(" = new Label();\n"); } } /** * Appends the name of the given label to {@link #buf buf}. The given label * <i>must</i> already have a name. One way to ensure this is to always call * {@link #declareLabel declared} before calling this method. * * @param l a label. */ private void appendLabel (final Label l) { buf.append((String)labelNames.get(l)); } } --- NEW FILE: PrintClassVisitor.java --- /*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000,2002,2003 INRIA, France Telecom * 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. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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. * * Contact: Eri...@rd... * * Author: Eric Bruneton */ package org.logicalcobwebs.asm.util; import org.logicalcobwebs.asm.ClassVisitor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; /** * An abstract class visitor that prints the classes it visits. */ public abstract class PrintClassVisitor implements ClassVisitor { /** * The text to be printed. Since the code of methods is not necessarily * visited in sequential order, one method after the other, but can be * interlaced (some instructions from method one, then some instructions from * method two, then some instructions from method one again...), it is not * possible to print the visited instructions directly to a sequential * stream. A class is therefore printed in a two steps process: a string tree * is constructed during the visit, and printed to a sequential stream at the * end of the visit. This string tree is stored in this field, as a string * list that can contain other string lists, which can themselves contain * other string lists, and so on. */ protected final List text; /** * A buffer that can be used to create strings. */ protected final StringBuffer buf; /** * The print writer to be used to print the class. */ protected final PrintWriter pw; /** * Constructs a new {@link PrintClassVisitor PrintClassVisitor} object. * * @param pw the print writer to be used to print the class. */ public PrintClassVisitor (final PrintWriter pw) { this.text = new ArrayList(); this.buf = new StringBuffer(); this.pw = pw; } public void visitEnd () { printList(text); pw.flush(); } /** * Prints the given string tree to {@link pw pw}. * * @param l a string tree, i.e., a string list that can contain other string * lists, and so on recursively. */ private void printList (final List l) { for (int i = 0; i < l.size(); ++i) { Object o = l.get(i); if (o instanceof List) { printList((List)o); } else { pw.print(o.toString()); } } } } --- NEW FILE: PrintCodeVisitor.java --- /*** * ASM: a very small and fast Java bytecode manipulation framework * Copyright (c) 2000,2002,2003 INRIA, France Telecom * 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. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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. * * Contact: Eri...@rd... * * Author: Eric Bruneton */ package org.logicalcobwebs.asm.util; import org.logicalcobwebs.asm.CodeVisitor; import org.logicalcobwebs.asm.Label; import org.logicalcobwebs.asm.Attribute; import java.util.ArrayList; import java.util.List; /** * An abstract code visitor that prints the code it visits. Each * <tt>visit</tt><i>XXX</i> method clears the {@link #buf buf} buffer, calls the * corresponding <tt>print</tt><i>XXX</i> method, and then adds the buffer's * content to the {@link #text text} list. In order to provide a concrete * print code visitor, one must implement the <tt>print</tt><i>XXX</i> methods * in a sub class of this class. Each method should print the instructions it * visits in {@link #buf buf}. */ public abstract class PrintCodeVisitor implements CodeVisitor { /** * The text to be printed. See {@link PrintClassVisitor#text text}. */ protected final List text; /** * A buffer used to convert instructions to strings. */ protected final StringBuffer buf; /** * The names of the Java Virtual Machine opcodes. */ public final static String[] OPCODES = { "NOP", "ACONST_NULL", "ICONST_M1", "ICONST_0", "ICONST_1", "ICONST_2", "ICONST_3", "ICONST_4", "ICONST_5", "LCONST_0", "LCONST_1", "FCONST_0", "FCONST_1", "FCONST_2", "DCONST_0", "DCONST_1", "BIPUSH", "SIPUSH", "LDC", null, null, "ILOAD", "LLOAD", "FLOAD", "DLOAD", "ALOAD", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... [truncated message content] |