Mega Code Archive

 
Categories / Java / File Input Output
 

Convert a path to a cananonical form

//  // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at  // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //  /**  * URI Holder. This class assists with the decoding and encoding or HTTP URI's.  * It differs from the java.net.URL class as it does not provide communications  * ability, but it does assist with query string formatting.  * <P>  * UTF-8 encoding is used by default for % encoded characters. This may be  * overridden with the org.mortbay.util.URI.charset system property.  *   * @see UrlEncoded  * @author Greg Wilkins (gregw)  */ public class Utils {   /**    * Convert a path to a cananonical form. All instances of "." and ".." are    * factored out. Null is returned if the path tries to .. above its root.    *     * @param path    * @return path or null.    */   public static String canonicalPath(String path) {     if (path == null || path.length() == 0)       return path;     int end = path.length();     int queryIdx = path.indexOf('?');     int start = path.lastIndexOf('/', (queryIdx > 0 ? queryIdx : end));     search: while (end > 0) {       switch (end - start) {       case 2: // possible single dot         if (path.charAt(start + 1) != '.')           break;         break search;       case 3: // possible double dot         if (path.charAt(start + 1) != '.' || path.charAt(start + 2) != '.')           break;         break search;       }       end = start;       start = path.lastIndexOf('/', end - 1);     }     // If we have checked the entire string     if (start >= end)       return path;     StringBuffer buf = new StringBuffer(path);     int delStart = -1;     int delEnd = -1;     int skip = 0;     while (end > 0) {       switch (end - start) {       case 2: // possible single dot         if (buf.charAt(start + 1) != '.') {           if (skip > 0 && --skip == 0) {             delStart = start >= 0 ? start : 0;             if (delStart > 0 && delEnd == buf.length() && buf.charAt(delEnd - 1) == '.')               delStart++;           }           break;         }         if (start < 0 && buf.length() > 2 && buf.charAt(1) == '/' && buf.charAt(2) == '/')           break;         if (delEnd < 0)           delEnd = end;         delStart = start;         if (delStart < 0 || delStart == 0 && buf.charAt(delStart) == '/') {           delStart++;           if (delEnd < buf.length() && buf.charAt(delEnd) == '/')             delEnd++;           break;         }         if (end == buf.length())           delStart++;         end = start--;         while (start >= 0 && buf.charAt(start) != '/')           start--;         continue;       case 3: // possible double dot         if (buf.charAt(start + 1) != '.' || buf.charAt(start + 2) != '.') {           if (skip > 0 && --skip == 0) {             delStart = start >= 0 ? start : 0;             if (delStart > 0 && delEnd == buf.length() && buf.charAt(delEnd - 1) == '.')               delStart++;           }           break;         }         delStart = start;         if (delEnd < 0)           delEnd = end;         skip++;         end = start--;         while (start >= 0 && buf.charAt(start) != '/')           start--;         continue;       default:         if (skip > 0 && --skip == 0) {           delStart = start >= 0 ? start : 0;           if (delEnd == buf.length() && buf.charAt(delEnd - 1) == '.')             delStart++;         }       }       // Do the delete       if (skip <= 0 && delStart >= 0 && delStart >= 0) {         buf.delete(delStart, delEnd);         delStart = delEnd = -1;         if (skip > 0)           delEnd = end;       }       end = start--;       while (start >= 0 && buf.charAt(start) != '/')         start--;     }     // Too many ..     if (skip > 0)       return null;     // Do the delete     if (delEnd >= 0)       buf.delete(delStart, delEnd);     return buf.toString();   } }