/** * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * **/ package lucee.transformer.bytecode.util; import java.io.IOException; import lucee.commons.io.IOUtil; import lucee.commons.io.res.Resource; import lucee.commons.io.res.util.ResourceUtil; import lucee.commons.lang.ClassUtil; import lucee.commons.lang.StringUtil; import lucee.runtime.engine.ThreadLocalPageContext; import lucee.runtime.exp.ExpressionException; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; public class MethodCleaner extends ClassVisitor implements Opcodes { private final String methodName; //private Class[] arguments; private String strArgs; private Class rtn; private String msg; MethodCleaner(ClassVisitor cv, String methodName, Class[] args, Class rtn, String msg) { super(ASM4, cv); this.methodName=methodName; //this.arguments = arguments; StringBuilder sb=new StringBuilder("("); for(int i=0;i<args.length;i++){ sb.append(Type.getDescriptor(args[i])); } sb.append(")"); sb.append(Type.getDescriptor(rtn)); strArgs=sb.toString(); this.rtn=rtn; this.msg=StringUtil.isEmpty(msg)?null:msg; } public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { cv.visit(version, access, name, signature, superName, interfaces); } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if(name.equals(methodName) && desc.equals(strArgs)) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); mv.visitCode(); if(msg==null)empty(mv); else exception(mv); mv.visitEnd(); return mv; } return super.visitMethod(access, name, desc, signature, exceptions); } private void exception(MethodVisitor mv) { mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); mv.visitInsn(DUP); mv.visitLdcInsn(msg); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V"); mv.visitInsn(ATHROW); mv.visitMaxs(3, 1); } private void empty(MethodVisitor mv) { // void if(rtn==void.class) { mv.visitInsn(RETURN); } // int,boolean,short,char,byte else if(rtn==int.class) { mv.visitInsn(ICONST_0); mv.visitInsn(IRETURN); mv.visitMaxs(1, 1); } // double else if(rtn==double.class) { mv.visitInsn(DCONST_0); mv.visitInsn(DRETURN); mv.visitMaxs(2, 1); } // float else if(rtn==float.class) { mv.visitInsn(FCONST_0); mv.visitInsn(FRETURN); mv.visitMaxs(1, 1); } // long else if(rtn==long.class) { mv.visitInsn(LCONST_0); mv.visitInsn(LRETURN); mv.visitMaxs(2, 1); } // Object else { mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); mv.visitMaxs(1, 1); } } public static byte[] modifie(byte[] src, String methodName,Class[] args, Class rtn, String msg){ ClassReader cr = new ClassReader(src); ClassWriter cw = ASMUtil.getClassWriter(); ClassVisitor ca = new MethodCleaner(cw,methodName,args,rtn,msg); cr.accept(ca, 0); return cw.toByteArray(); } public static void modifie(String path, String methodName,String[] argNames, String rtnName, String msg) throws IOException, ExpressionException{ Resource res = ResourceUtil.toResourceExisting(ThreadLocalPageContext.getConfig(), path); Class[] args=new Class[argNames.length]; for(int i=0;i<argNames.length;i++){ args[i]=ClassUtil.loadClass(argNames[i]); } Class rtn=ClassUtil.loadClass(rtnName); byte[] result = modifie(IOUtil.toBytes(res), methodName, args, rtn,msg); IOUtil.write(res, result); } }