package railo.commons.io;
import java.io.IOException;
import railo.commons.io.res.Resource;
import railo.commons.lang.StringUtil;
import railo.runtime.SourceFile;
import railo.runtime.type.Array;
import railo.runtime.type.util.ListUtil;
/**
* represent a cfml file on the runtime system
*/
public final class SourceFileImpl implements SourceFile {
private final Resource root;
private Resource file;
private String realpath;
private boolean isOutSide=false;
private String name;
private String className;
private String packageName;
private String javaName;
private boolean trusted;
private boolean hasArchive;
/**
* constructor of the class
* @param root rott directory of the file
* @param realPath relative path to root directory
*/
public SourceFileImpl(Resource root, String realPath) {
this.root=root;
this.realpath=realPath.replace('\\','/');
if(realPath.indexOf('/')==0) {
}
else if(realPath.startsWith("../")) {
isOutSide=true;
}
else if(realPath.startsWith("./")) {
this.realpath=this.realpath.substring(1);
}
else {
this.realpath="/"+this.realpath;
}
}
/**
* constructor of the class
* @param parent parent sourceFile
* @param realPath relapath to parent sourc file (not root)
*/
public SourceFileImpl(SourceFileImpl parent, String realPath) {
realpath=realPath.replace('\\','/');
if(realPath.equals(".") || realPath.equals(".."))realPath+="/";
this.root=parent.root;
name=parent.name;
trusted=parent.trusted;
hasArchive=parent.hasArchive;
isOutSide=parent.isOutSide;
if(realPath.indexOf('/')==0) {
isOutSide=false;
this.realpath=realPath;
}
else if(realPath.indexOf("./")==0) {
this.realpath=mergeRealPathes(parent.getRealpath(), realPath.substring(2));
}
else {
this.realpath=mergeRealPathes(parent.getRealpath(), realPath);
}
}
/**
* merge to realpath to one
* @param parentRealPath
* @param newRealPath
* @return merged realpath
*/
private String mergeRealPathes(String parentRealPath, String newRealPath) {
// remove file from parent
parentRealPath=pathRemoveLast(parentRealPath);
while(newRealPath.startsWith("../")) {
parentRealPath=pathRemoveLast(parentRealPath);
newRealPath=newRealPath.substring(3);
}
// check if come back
String path=parentRealPath+"/"+newRealPath;
if(path.startsWith("../")) {
int count=0;
while(path.startsWith("../")) {
count++;
path=path.substring(3);
}
String strRoot=root.getAbsolutePath().replace('\\','/');
if(strRoot.lastIndexOf('/')!=strRoot.length()-1) {
strRoot+='/';
}
int rootLen=strRoot.length();
String[] arr=path.split("/");
for(int i=count;i>0;i--) {
if(arr.length>i) {
String tmp="/"+list(arr,0,i);
if(strRoot.lastIndexOf(tmp)==rootLen-tmp.length()) {
StringBuilder rtn=new StringBuilder();
while(i<count-i) {
count--;
rtn.append("../");
}
isOutSide=rtn.length()!=0;
return rtn.toString()+(rtn.length()==0?"/":"")+list(arr,i,arr.length);
}
}
}
//System.out.println(strRoot+" - "+path);
}
return parentRealPath+"/"+newRealPath;
}
/**
* convert a String array to a string list, but only part of it
* @param arr String Array
* @param from start from here
* @param len how many element
* @return String list
*/
private String list(String[] arr,int from, int len) {
StringBuilder sb=new StringBuilder();
for(int i=from;i<len;i++) {
sb.append(arr[i]);
if(i+1!=arr.length)sb.append('/');
}
return sb.toString();
}
/**
* remove the last elemtn of a path
* @param path path to remove last element from it
* @return path with removed element
*/
private String pathRemoveLast(String path) {
if(path.length()==0) {
isOutSide=true;
return "..";
}
else if(path.lastIndexOf("..")==path.length()-2){
isOutSide=true;
return path+"/..";
}
return path.substring(0,path.lastIndexOf('/'));
}
public Resource getFile() {
return getResource();
}
@Override
public Resource getResource() {
if(file==null) {
if(isOutSide) {
try {
file=root.getRealResource(realpath).getCanonicalResource();
} catch (IOException e) {
}
}
file=root.getRealResource(realpath);
}
return file;
}
/**
* @return Returns the realpath.
*/
public String getRealpath() {
return realpath;
}
/**
* @return Returns the root.
*/
public Resource getRoot() {
return root;
}
/**
* @return returns a variable string based on realpath and return it
*/
public String getRealPathAsVariableString() {
return StringUtil.toIdentityVariableName(getRealpath());
//return StringUtil.toClassName(getRealpath());
}
/**
* @return returns the a classname matching to filename
*/
public String getClassName() {
if(className==null) createClassAndPackage();
return className;
}
/**
* @return returns the java name
*/
public String getJavaName() {
if(javaName==null) createClassAndPackage();
return javaName;
}
/**
* @return returns the a package matching to file
*/
public String getPackageName() {
if(packageName==null) createClassAndPackage();
return packageName;
}
private void createClassAndPackage() {
String str=realpath;
StringBuilder packageName=new StringBuilder();
StringBuilder javaName=new StringBuilder();
while(str.indexOf('/')==0)str=str.substring(1);
while(str.lastIndexOf('/')==str.length()-1)str=str.substring(0,str.length()-1);
//String[] arr=str.split("/");
Array arr = ListUtil.listToArray(str, '/');
int len=arr.size();
String value;
for(int i=1;i<=len;i++) {
value=(String) arr.get(i,"");
String varName=StringUtil.toVariableName(value);
javaName.append("/"+varName);
if(i==len) {
className=varName.toLowerCase();
}
else {
if(i!=0) packageName.append('.');
packageName.append(varName);
}
}
this.packageName=packageName.toString().toLowerCase();
this.javaName=javaName.toString().toLowerCase();
}
/**
* @return returns a variable string based on root and return it
*/
public String getRootPathAsVariableString() {
return StringUtil.toIdentityVariableName(root.getAbsolutePath());
}
/**
* @return has context a archive or not
*/
public boolean hasArchive() {
return hasArchive;
}
/**
* @return returns if is trusted or not
*/
public boolean isTrusted() {
return trusted;
}
@Override
public Resource getPhyscalFile() {
return getFile();
}
@Override
public String getDisplayPath() {
return getFile().getAbsolutePath();
}
@Override
public String getFullClassName() {
String p=getPackageName();
if(p.length()==0) return getClassName();
return p.concat(".").concat(getClassName());
}
}