001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.transformer.bytecode.util;
020
021import lucee.commons.lang.StringUtil;
022import lucee.runtime.type.util.ListUtil;
023
024import org.objectweb.asm.ClassReader;
025import org.objectweb.asm.ClassVisitor;
026import org.objectweb.asm.ClassWriter;
027import org.objectweb.asm.MethodVisitor;
028import org.objectweb.asm.Opcodes;
029
030public class ClassRenamer extends ClassVisitor implements Opcodes {
031
032        private final String newName;
033        private String oldName;
034        private boolean doNothing;
035
036        ClassRenamer(ClassVisitor cv, String newName) {
037                super(ASM4, cv);
038                newName=ListUtil.trim(newName, "\\/");
039                this.newName = newName;
040        }
041
042        public void visit(int version, int access, String name, String signature,String superName, String[] interfaces) {
043                oldName=name;
044                doNothing=oldName.equals(newName);
045                
046                cv.visit(version, ACC_PUBLIC, newName, signature, superName, interfaces);
047        }
048
049        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
050                MethodVisitor mv = cv.visitMethod(access, name, fixDesc(desc),fixSignature(signature), exceptions);
051                if (mv != null && (access & ACC_ABSTRACT) == 0) {
052                        mv = new MethodRenamer(mv);
053                }
054                return mv;
055        }
056
057        class MethodRenamer extends MethodVisitor {
058
059                public MethodRenamer(final MethodVisitor mv) {
060                        super(ASM4, mv);
061                }
062
063                public void visitTypeInsn(int i, String s) {
064                        if (!doNothing && oldName.equals(s)) {
065                                s = newName;
066                        }
067                        mv.visitTypeInsn(i, s);
068                }
069
070                public void visitFieldInsn(int opcode, String owner, String name,
071                                String desc) {
072                        if (!doNothing && oldName.equals(owner)) {
073                                mv.visitFieldInsn(opcode, newName, name, fixDesc(desc));
074                        } else {
075                                mv.visitFieldInsn(opcode, owner, name, fixDesc(desc));
076                        }
077                }
078
079                public void visitMethodInsn(int opcode, String owner, String name,
080                                String desc) {
081                        if (!doNothing && oldName.equals(owner)) {
082                                mv.visitMethodInsn(opcode, newName, name, fixDesc(desc));
083                        } else {
084                                mv.visitMethodInsn(opcode, owner, name, fixDesc(desc));
085                        }
086                }
087        }
088
089        private String fixDesc(String desc) {
090                //print.e("fixDesc:"+desc);
091                return _fix(desc);
092        }
093
094        private String fixSignature(String signature) {
095                //print.e("fixSignature:"+signature);
096                return _fix(signature);
097        }
098
099        private String _fix(String str) {
100                if (!doNothing && !StringUtil.isEmpty(str)) {
101                        if (str.indexOf(oldName) != -1) {
102                                str = StringUtil.replace(str, oldName, newName,false);
103                        }
104                }
105                return str;
106        }
107        
108        public static byte[] rename(byte[] src, String newName){
109                ClassReader cr = new ClassReader(src);
110                ClassWriter cw = ASMUtil.getClassWriter();
111                ClassVisitor ca = new ClassRenamer(cw,newName);
112                cr.accept(ca, 0);
113                return cw.toByteArray();
114        }
115
116        /*public static void main(String[] args) throws Throwable {
117                String path = "/Users/mic/Projects/Lucee/webroot/WEB-INF/lucee/cfclasses/CF_Users_mic_Projects_Lucee_webroot_jm4653/jira/test/test_cfm$cf.class";
118                ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
119                Resource res = frp.getResource(path);
120                print.e(getClassName(res));
121        }*/
122}