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 java.io.IOException; 022import java.io.InputStream; 023import java.util.HashMap; 024import java.util.Map; 025 026import lucee.commons.io.res.filter.ExtensionResourceFilter; 027import lucee.commons.lang.StringUtil; 028import lucee.runtime.PageContext; 029import lucee.runtime.config.Config; 030import lucee.runtime.functions.system.ExpandPath; 031import lucee.runtime.type.util.ListUtil; 032 033import org.objectweb.asm.ClassReader; 034import org.objectweb.asm.ClassVisitor; 035 036public class SourceNameClassVisitor extends ClassVisitor { 037 038 039 040 //private String sourceName; 041 //private String sourcePath; 042 private ExtensionResourceFilter filter; 043 private SourceInfo source; 044 045 public SourceNameClassVisitor(Config config, int arg0, boolean onlyCFC) { 046 super(arg0); 047 if(onlyCFC) { 048 filter = new ExtensionResourceFilter(new String[]{config.getCFCExtension()},true,true); 049 } 050 else { 051 filter = new ExtensionResourceFilter(config.getCFMLExtensions(),true,true); 052 filter.addExtension(config.getCFCExtension()); 053 } 054 055 } 056 057 @Override 058 public void visitSource(String source, String debug) { 059 super.visitSource(source, debug); 060 if(!StringUtil.isEmpty(source)){ 061 062 String name=ListUtil.last(source, "/\\"); 063 064 if(filter.accept(name)) { 065 // older than 4.2.1.008 066 if(StringUtil.isEmpty(debug)) { 067 this.source=new SourceInfo(name,source); // source is a relative path 068 } 069 else { 070 //in that case source holds the absolute path 071 String[] arr=ListUtil.listToStringArray(debug, ';'); 072 String str; int index; 073 Map<String,String> map=new HashMap<String, String>(); 074 for(int i=0;i<arr.length;i++){ 075 str=arr[i].trim(); 076 index=str.indexOf(':'); 077 if(index==-1) map.put(str.toLowerCase(),""); 078 else map.put(str.substring(0,index).toLowerCase(),str.substring(index+1)); 079 080 } 081 String rel = map.get("rel"); 082 String abs = map.get("abs"); 083 if(StringUtil.isEmpty(abs)) abs=source; 084 085 this.source=new SourceInfo(name,rel,abs); 086 } 087 } 088 } 089 } 090 091 092 public static SourceInfo getSourceInfo(Config config,Class clazz, boolean onlyCFC) throws IOException { 093 String name = "/"+clazz.getName().replace('.', '/')+".class"; 094 InputStream in=clazz.getResourceAsStream(name); 095 ClassReader classReader=new ClassReader(in); 096 SourceNameClassVisitor visitor = new SourceNameClassVisitor(config,4,onlyCFC); 097 classReader.accept(visitor, 0); 098 if(visitor.source==null || visitor.source.name==null) return null; 099 return visitor.source; 100 101 } 102 103 public static class SourceInfo { 104 105 public final String name; 106 public final String relativePath; 107 private String _absolutePath; 108 109 public SourceInfo(String name,String relativePath) { 110 this(name,relativePath,null); 111 } 112 113 public SourceInfo(String name,String relativePath,String absolutePath) { 114 this.name=name; 115 this.relativePath=relativePath; 116 this._absolutePath=absolutePath; 117 } 118 119 public String toString(){ 120 return new StringBuilder("absolute-path:"+_absolutePath+";relative-path:"+relativePath+";name:"+name).toString(); 121 } 122 123 public String absolutePath(PageContext pc) { 124 if(!StringUtil.isEmpty(_absolutePath)) return _absolutePath; 125 try{ 126 _absolutePath=ExpandPath.call(pc, relativePath); 127 }catch(Exception e) {} 128 return _absolutePath; 129 } 130 } 131}