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 **/
019/**
020 * Implements the CFML Function expandpath
021 */
022package lucee.runtime.functions.system;
023
024import java.io.IOException;
025
026import lucee.commons.io.SystemUtil;
027import lucee.commons.io.res.Resource;
028import lucee.commons.io.res.ResourceProvider;
029import lucee.commons.io.res.util.ResourceUtil;
030import lucee.commons.lang.StringUtil;
031import lucee.runtime.PageContext;
032import lucee.runtime.PageContextImpl;
033import lucee.runtime.PageSource;
034import lucee.runtime.config.ConfigWeb;
035import lucee.runtime.config.ConfigWebImpl;
036import lucee.runtime.config.ConfigWebUtil;
037import lucee.runtime.exp.PageException;
038import lucee.runtime.ext.function.Function;
039import lucee.runtime.type.util.ArrayUtil;
040
041public final class ExpandPath implements Function {
042
043        private static final long serialVersionUID = 6192659914120397912L;
044
045        public static String call(PageContext pc , String relPath) throws PageException {
046                ConfigWeb config=pc.getConfig();
047                relPath=prettifyPath(pc,relPath);
048                
049        String contextPath = pc.getHttpServletRequest().getContextPath();
050        if ( !StringUtil.isEmpty( contextPath ) && relPath.startsWith( contextPath ) ) {
051            boolean sws=StringUtil.startsWith(relPath, '/');
052                relPath = relPath.substring( contextPath.length() );
053            if(sws && !StringUtil.startsWith(relPath, '/'))
054                relPath="/"+relPath;
055        }
056
057        Resource res;
058        
059        if(StringUtil.startsWith(relPath,'/')) {
060                
061                
062                PageContextImpl pci=(PageContextImpl) pc;
063                ConfigWebImpl cwi=(ConfigWebImpl) config;
064                PageSource[] sources = cwi.getPageSources(pci, pc.getApplicationContext().getMappings(), relPath, 
065                                false, pci.useSpecialMappings(), true);
066                
067                if(!ArrayUtil.isEmpty(sources)) {
068                        // first check for existing
069                        for(int i=0;i<sources.length;i++){
070                                if(sources[i].exists()) {
071                                        return toReturnValue(relPath,sources[i].getResource());
072                                }
073                        }
074                        
075                        // no expand needed
076                        if(!SystemUtil.isWindows() && !sources[0].exists()) {
077                                res=pc.getConfig().getResource(relPath);
078                        if(res.exists()) {
079                                return toReturnValue(relPath,res);
080                        }
081                        }
082                        for(int i=0;i<sources.length;i++){
083                                res=sources[i].getResource();
084                                if(res!=null) {
085                                        return toReturnValue(relPath,res);
086                                }
087                        }
088                }
089
090                // no expand needed
091                else if(!SystemUtil.isWindows()) {
092                        res=pc.getConfig().getResource(relPath);
093                if(res.exists()) {
094                        return toReturnValue(relPath,res);
095                }
096                }
097                
098                
099                //Resource[] reses = cwi.getPhysicalResources(pc,pc.getApplicationContext().getMappings(),relPath,false,pci.useSpecialMappings(),true);
100                
101        }
102        relPath=ConfigWebUtil.replacePlaceholder(relPath, config);
103        res=pc.getConfig().getResource(relPath);
104        if(res.isAbsolute()) return toReturnValue(relPath,res);
105        
106        res=ResourceUtil.getResource(pc,pc.getBasePageSource());
107        if(!res.isDirectory())res=res.getParentResource();
108        res = res.getRealResource(relPath);
109        return toReturnValue(relPath,res);
110        
111        }
112
113    private static String toReturnValue(String relPath,Resource res) {
114        String path;
115        char pathChar='/';
116        try {
117            path=res.getCanonicalPath();
118            pathChar=ResourceUtil.FILE_SEPERATOR;
119        } catch (IOException e) {
120            path= res.getAbsolutePath();
121        }
122        boolean pathEndsWithSep=StringUtil.endsWith(path,pathChar);
123        boolean realEndsWithSep=StringUtil.endsWith(relPath,'/');
124        
125        if(realEndsWithSep) {
126            if(!pathEndsWithSep)path=path+pathChar;
127        }
128        else if(pathEndsWithSep) {
129            path=path.substring(0,path.length()-1);
130        }
131        
132        return path;
133    }
134    
135    private static String prettifyPath(PageContext pc, String path) {
136                if(path==null) return null;
137                
138                // UNC Path
139                if(path.startsWith("\\\\") && SystemUtil.isWindows()) {
140                        path=path.substring(2);
141                        path=path.replace('\\','/');
142                        return "//"+StringUtil.replace(path, "//", "/", false);
143                }
144                
145                path=path.replace('\\','/');
146                
147                // virtual file system path
148                int index=path.indexOf("://");
149                if(index!=-1) {
150                        ResourceProvider[] providers = pc.getConfig().getResourceProviders();
151                        String scheme=path.substring(0,index).toLowerCase().trim();
152                        for(int i=0;i<providers.length;i++) {
153                                if(scheme.equalsIgnoreCase(providers[i].getScheme()))
154                                        return scheme+"://"+StringUtil.replace(path.substring(index+3), "//", "/", false);
155                        }
156                }
157
158                return StringUtil.replace(path, "//", "/", false);
159                // TODO /aaa/../bbb/
160        }
161}