scolebourne    2004/11/22 16:04:29

  Modified:    io/src/test/org/apache/commons/io FilenameUtilsTestCase.java
               io/src/java/org/apache/commons/io FilenameUtils.java
  Log:
  Add methods to handle filename prefixes
  
  Revision  Changes    Path
  1.20      +166 -6    
jakarta-commons/io/src/test/org/apache/commons/io/FilenameUtilsTestCase.java
  
  Index: FilenameUtilsTestCase.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/io/src/test/org/apache/commons/io/FilenameUtilsTestCase.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- FilenameUtilsTestCase.java        31 Oct 2004 00:03:03 -0000      1.19
  +++ FilenameUtilsTestCase.java        23 Nov 2004 00:04:29 -0000      1.20
  @@ -113,6 +113,7 @@
       public void testNormalize() throws Exception {
           String[] src =
               {
  +                null,
                   "",
                   "/",
                   "///",
  @@ -129,10 +130,14 @@
                   "/foo/.././bar/",
                   "//foo//./bar",
                   "/../",
  -                "/foo/../../" };
  +                "/foo/../../",
  +                "../foo",
  +                "foo/../../bar",
  +                "foo/../bar" };
   
           String[] dest =
               {
  +                null,
                   "",
                   "/",
                   "/",
  @@ -149,15 +154,19 @@
                   "/bar/",
                   "/foo/bar",
                   null,
  -                null };
  +                null,
  +                null,
  +                null,
  +                "bar" };
   
           assertEquals("Oops, test writer goofed", src.length, dest.length);
   
           for (int i = 0; i < src.length; i++) {
  +            String destStr = FilenameUtils.separatorsToSystem(dest[i]);
  +            String resultStr = FilenameUtils.normalize(src[i]);
               assertEquals(
  -                "Check if '" + src[i] + "' normalized to '" + dest[i] + "'",
  -                dest[i],
  -                FilenameUtils.normalize(src[i]));
  +                "Check if '" + src[i] + "' normalized to '" + destStr + "', 
was '" + resultStr + "'",
  +                destStr, resultStr);
           }
       }
   
  @@ -214,6 +223,46 @@
       }
   
       //-----------------------------------------------------------------------
  +    public void testGetPrefixLength() {
  +        assertEquals(-1, FilenameUtils.getPrefixLength(null));
  +        if (WINDOWS) {
  +            assertEquals(-1, 
FilenameUtils.getPrefixLength("1:\\a\\b\\c.txt"));
  +            assertEquals(-1, FilenameUtils.getPrefixLength("1:"));
  +            assertEquals(-1, FilenameUtils.getPrefixLength("1:a"));
  +            assertEquals(-1, 
FilenameUtils.getPrefixLength("\\\\\\a\\b\\c.txt"));
  +            assertEquals(-1, FilenameUtils.getPrefixLength("\\\\a"));
  +            
  +            assertEquals(0, FilenameUtils.getPrefixLength("a\\b\\c.txt"));
  +            assertEquals(1, FilenameUtils.getPrefixLength("\\a\\b\\c.txt"));
  +            assertEquals(3, 
FilenameUtils.getPrefixLength("C:\\a\\b\\c.txt"));
  +            assertEquals(9, 
FilenameUtils.getPrefixLength("\\\\server\\a\\b\\c.txt"));
  +            
  +            assertEquals(0, FilenameUtils.getPrefixLength("a/b/c.txt"));
  +            assertEquals(1, FilenameUtils.getPrefixLength("/a/b/c.txt"));
  +            assertEquals(3, FilenameUtils.getPrefixLength("C:/a/b/c.txt"));
  +            assertEquals(9, 
FilenameUtils.getPrefixLength("//server/a/b/c.txt"));
  +            
  +            assertEquals(0, FilenameUtils.getPrefixLength("~/a/b/c.txt"));
  +            assertEquals(0, 
FilenameUtils.getPrefixLength("~user/a/b/c.txt"));
  +        } else {
  +            assertEquals(-1, FilenameUtils.getPrefixLength("~"));
  +            assertEquals(-1, FilenameUtils.getPrefixLength("~user"));
  +            
  +            assertEquals(0, FilenameUtils.getPrefixLength("a/b/c.txt"));
  +            assertEquals(1, FilenameUtils.getPrefixLength("/a/b/c.txt"));
  +            assertEquals(2, FilenameUtils.getPrefixLength("~/a/b/c.txt"));
  +            assertEquals(6, 
FilenameUtils.getPrefixLength("~user/a/b/c.txt"));
  +            
  +            assertEquals(0, FilenameUtils.getPrefixLength("a\\b\\c.txt"));
  +            assertEquals(1, FilenameUtils.getPrefixLength("\\a\\b\\c.txt"));
  +            assertEquals(2, FilenameUtils.getPrefixLength("~\\a\\b\\c.txt"));
  +            assertEquals(6, 
FilenameUtils.getPrefixLength("~user\\a\\b\\c.txt"));
  +            
  +            assertEquals(0, 
FilenameUtils.getPrefixLength("C:\\a\\b\\c.txt"));
  +            assertEquals(1, 
FilenameUtils.getPrefixLength("\\\\server\\a\\b\\c.txt"));
  +        }
  +    }
  +    
       public void testIndexOfLastSeparator() {
           assertEquals(-1, FilenameUtils.indexOfLastSeparator(null));
           assertEquals(-1, 
FilenameUtils.indexOfLastSeparator("noseperator.inthispath"));
  @@ -233,6 +282,46 @@
       }
   
       //-----------------------------------------------------------------------
  +    public void testGetPrefix() {
  +        assertEquals(null, FilenameUtils.getPrefix(null));
  +        if (WINDOWS) {
  +            assertEquals(null, FilenameUtils.getPrefix("1:\\a\\b\\c.txt"));
  +            assertEquals(null, FilenameUtils.getPrefix("1:"));
  +            assertEquals(null, FilenameUtils.getPrefix("1:a"));
  +            assertEquals(null, FilenameUtils.getPrefix("\\\\\\a\\b\\c.txt"));
  +            assertEquals(null, FilenameUtils.getPrefix("\\\\a"));
  +            
  +            assertEquals("", FilenameUtils.getPrefix("a\\b\\c.txt"));
  +            assertEquals("\\", FilenameUtils.getPrefix("\\a\\b\\c.txt"));
  +            assertEquals("C:\\", FilenameUtils.getPrefix("C:\\a\\b\\c.txt"));
  +            assertEquals("\\\\server\\", 
FilenameUtils.getPrefix("\\\\server\\a\\b\\c.txt"));
  +            
  +            assertEquals("", FilenameUtils.getPrefix("a/b/c.txt"));
  +            assertEquals("/", FilenameUtils.getPrefix("/a/b/c.txt"));
  +            assertEquals("C:/", FilenameUtils.getPrefix("C:/a/b/c.txt"));
  +            assertEquals("//server/", 
FilenameUtils.getPrefix("//server/a/b/c.txt"));
  +            
  +            assertEquals("", FilenameUtils.getPrefix("~/a/b/c.txt"));
  +            assertEquals("", FilenameUtils.getPrefix("~user/a/b/c.txt"));
  +        } else {
  +            assertEquals(null, FilenameUtils.getPrefix("~"));
  +            assertEquals(null, FilenameUtils.getPrefix("~user"));
  +            
  +            assertEquals("", FilenameUtils.getPrefix("a/b/c.txt"));
  +            assertEquals("/", FilenameUtils.getPrefix("/a/b/c.txt"));
  +            assertEquals("~/", FilenameUtils.getPrefix("~/a/b/c.txt"));
  +            assertEquals("~user/", 
FilenameUtils.getPrefix("~user/a/b/c.txt"));
  +            
  +            assertEquals("", FilenameUtils.getPrefix("a\\b\\c.txt"));
  +            assertEquals("\\", FilenameUtils.getPrefix("\\a\\b\\c.txt"));
  +            assertEquals("~\\", FilenameUtils.getPrefix("~\\a\\b\\c.txt"));
  +            assertEquals("~user\\", 
FilenameUtils.getPrefix("~user\\a\\b\\c.txt"));
  +            
  +            assertEquals("", FilenameUtils.getPrefix("C:\\a\\b\\c.txt"));
  +            assertEquals("\\", 
FilenameUtils.getPrefix("\\\\server\\a\\b\\c.txt"));
  +        }
  +    }
  +
       public void testGetPath() {
           assertEquals(null, FilenameUtils.getPath(null));
           assertEquals("", FilenameUtils.getPath("noseperator.inthispath"));
  @@ -240,6 +329,67 @@
           assertEquals("a/b", FilenameUtils.getPath("a/b/c"));
           assertEquals("a/b/c", FilenameUtils.getPath("a/b/c/"));
           assertEquals("a\\b", FilenameUtils.getPath("a\\b\\c"));
  +        if (WINDOWS) {
  +            assertEquals(null, FilenameUtils.getPath("1:/a/b/c.txt"));
  +            assertEquals(null, FilenameUtils.getPath("1:"));
  +            assertEquals(null, FilenameUtils.getPath("1:a"));
  +            assertEquals(null, FilenameUtils.getPath("///a/b/c.txt"));
  +            assertEquals(null, FilenameUtils.getPath("//a"));
  +            
  +            assertEquals("a/b", FilenameUtils.getPath("a/b/c.txt"));
  +            assertEquals("a/b", FilenameUtils.getPath("/a/b/c.txt"));
  +            assertEquals("a/b", FilenameUtils.getPath("C:/a/b/c.txt"));
  +            assertEquals("a/b", FilenameUtils.getPath("//server/a/b/c.txt"));
  +            
  +            assertEquals("~/a/b", FilenameUtils.getPath("~/a/b/c.txt"));
  +            assertEquals("~user/a/b", 
FilenameUtils.getPath("~user/a/b/c.txt"));
  +        } else {
  +            assertEquals(null, FilenameUtils.getPath("~"));
  +            assertEquals(null, FilenameUtils.getPath("~user"));
  +            
  +            assertEquals("a/b", FilenameUtils.getPath("a/b/c.txt"));
  +            assertEquals("a/b", FilenameUtils.getPath("/a/b/c.txt"));
  +            assertEquals("a/b", FilenameUtils.getPath("~/a/b/c.txt"));
  +            assertEquals("a/b", FilenameUtils.getPath("~user/a/b/c.txt"));
  +            
  +            assertEquals("C:/a/b", FilenameUtils.getPath("C:/a/b/c.txt"));
  +            assertEquals("/server/a/b", 
FilenameUtils.getPath("//server/a/b/c.txt"));
  +        }
  +    }
  +
  +    public void testGetFullPath() {
  +        assertEquals(null, FilenameUtils.getFullPath(null));
  +        assertEquals("", 
FilenameUtils.getFullPath("noseperator.inthispath"));
  +        assertEquals("a/b", FilenameUtils.getFullPath("a/b/c.txt"));
  +        assertEquals("a/b", FilenameUtils.getFullPath("a/b/c"));
  +        assertEquals("a/b/c", FilenameUtils.getFullPath("a/b/c/"));
  +        assertEquals("a\\b", FilenameUtils.getFullPath("a\\b\\c"));
  +        if (WINDOWS) {
  +            assertEquals(null, FilenameUtils.getFullPath("1:/a/b/c.txt"));
  +            assertEquals(null, FilenameUtils.getFullPath("1:"));
  +            assertEquals(null, FilenameUtils.getFullPath("1:a"));
  +            assertEquals(null, FilenameUtils.getFullPath("///a/b/c.txt"));
  +            assertEquals(null, FilenameUtils.getFullPath("//a"));
  +            
  +            assertEquals("a/b", FilenameUtils.getFullPath("a/b/c.txt"));
  +            assertEquals("/a/b", FilenameUtils.getFullPath("/a/b/c.txt"));
  +            assertEquals("C:/a/b", 
FilenameUtils.getFullPath("C:/a/b/c.txt"));
  +            assertEquals("//server/a/b", 
FilenameUtils.getFullPath("//server/a/b/c.txt"));
  +            
  +            assertEquals("~/a/b", FilenameUtils.getFullPath("~/a/b/c.txt"));
  +            assertEquals("~user/a/b", 
FilenameUtils.getFullPath("~user/a/b/c.txt"));
  +        } else {
  +            assertEquals(null, FilenameUtils.getFullPath("~"));
  +            assertEquals(null, FilenameUtils.getFullPath("~user"));
  +            
  +            assertEquals("a/b", FilenameUtils.getFullPath("a/b/c.txt"));
  +            assertEquals("/a/b", FilenameUtils.getFullPath("/a/b/c.txt"));
  +            assertEquals("~/a/b", FilenameUtils.getFullPath("~/a/b/c.txt"));
  +            assertEquals("~user/a/b", 
FilenameUtils.getFullPath("~user/a/b/c.txt"));
  +            
  +            assertEquals("C:/a/b", 
FilenameUtils.getFullPath("C:/a/b/c.txt"));
  +            assertEquals("//server/a/b", 
FilenameUtils.getFullPath("//server/a/b/c.txt"));
  +        }
       }
   
       public void testGetName() {
  @@ -249,6 +399,16 @@
           assertEquals("c", FilenameUtils.getName("a/b/c"));
           assertEquals("", FilenameUtils.getName("a/b/c/"));
           assertEquals("c", FilenameUtils.getName("a\\b\\c"));
  +    }
  +
  +    public void testGetBaseName() {
  +        assertEquals(null, FilenameUtils.getBaseName(null));
  +        assertEquals("noseperator", 
FilenameUtils.getBaseName("noseperator.inthispath"));
  +        assertEquals("c", FilenameUtils.getBaseName("a/b/c.txt"));
  +        assertEquals("c", FilenameUtils.getBaseName("a/b/c"));
  +        assertEquals("", FilenameUtils.getBaseName("a/b/c/"));
  +        assertEquals("c", FilenameUtils.getBaseName("a\\b\\c"));
  +        assertEquals("file.txt", FilenameUtils.getBaseName("file.txt.bak"));
       }
   
       public void testGetExtension() {
  
  
  
  1.27      +270 -270  
jakarta-commons/io/src/java/org/apache/commons/io/FilenameUtils.java
  
  Index: FilenameUtils.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/io/src/java/org/apache/commons/io/FilenameUtils.java,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- FilenameUtils.java        22 Nov 2004 01:11:55 -0000      1.26
  +++ FilenameUtils.java        23 Nov 2004 00:04:29 -0000      1.27
  @@ -23,37 +23,22 @@
   /**
    * Utility class that provides methods to manipulate filenames and filepaths.
    * <p>
  - * This class defines four basic components within a filename (example 
C:\dev\project\file.txt):
  + * This class defines six components within a filename (example 
C:\dev\project\file.txt):
    * <ul>
  - * <li>the prefix - C:\
  - * <li>the path - dev\project
  - * <li>the name - file.txt
  - * <li>the extension - txt
  + * <li>the prefix - C:\</li>
  + * <li>the path - dev\project</li>
  + * <li>the full path - C:\dev\project</li>
  + * <li>the name - file.txt</li>
  + * <li>the base name - file</li>
  + * <li>the extension - txt</li>
    * </ul>
    * The class only supports Unix and Windows style names.
  - * 
  - * <h3>Path-related methods</h3>
  - *
  - * <p>Methods exist to retrieve the components of a typical file path. For
  - * example <code>/www/hosted/mysite/index.html</code>, can be broken into:
  - * <ul>
  - *   <li><code>/www/hosted/mysite/</code> -- retrievable through
  - *       [EMAIL PROTECTED] #getPath}</li>
  - *   <li><code>index.html</code> -- retrievable through [EMAIL PROTECTED] 
#removePath}</li>
  - *   <li><code>/www/hosted/mysite/index</code> -- retrievable through
  - *       [EMAIL PROTECTED] #removeExtension}</li>
  - *   <li><code>html</code> -- retrievable through [EMAIL PROTECTED] 
#getExtension}</li>
  - * </ul>
  - * There are also methods to [EMAIL PROTECTED] #catPath concatenate two 
paths},
  - * [EMAIL PROTECTED] #resolveFile resolve a path relative to a File} and
  - * [EMAIL PROTECTED] #normalize} a path.
    * </p>
  - *
    * <h3>Origin of code</h3>
    * <ul>
  - *   <li>commons-utils repo</li>
  - *   <li>Alexandria's FileUtils.</li>
  - *   <li>Avalon Excalibur's IO.</li>
  + *   <li>Commons Utils</li>
  + *   <li>Alexandria's FileUtils</li>
  + *   <li>Avalon Excalibur's IO</li>
    * </ul>
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Kevin A. Burton</A>
  @@ -91,125 +76,47 @@
        */
       private static final char SYSTEM_SEPARATOR = File.separatorChar;
   
  -//    /**
  -//     * The separator character that is the opposite of the system 
separator.
  -//     */
  -//    private static final char OTHER_SEPARATOR;
  -//    static {
  -//        if (SYSTEM_SEPARATOR == WINDOWS_SEPARATOR) {
  -//            OTHER_SEPARATOR = UNIX_SEPARATOR;
  -//        } else {
  -//            OTHER_SEPARATOR = WINDOWS_SEPARATOR;
  -//        }
  -//    }
  +    /**
  +     * The separator character that is the opposite of the system separator.
  +     */
  +    private static final char OTHER_SEPARATOR;
  +    static {
  +        if (SYSTEM_SEPARATOR == WINDOWS_SEPARATOR) {
  +            OTHER_SEPARATOR = UNIX_SEPARATOR;
  +        } else {
  +            OTHER_SEPARATOR = WINDOWS_SEPARATOR;
  +        }
  +    }
   
       /**
        * Instances should NOT be constructed in standard programming.
        */
       public FilenameUtils() { }
   
  -//    
//-----------------------------------------------------------------------
  -//    /**
  -//     * Checks if the character is a separator.
  -//     * 
  -//     * @param ch  the character to check
  -//     * @return true if it is a separators
  -//     */
  -//    private static boolean isSeparator(char ch) {
  -//        return (ch == UNIX_SEPARATOR) || (ch == WINDOWS_SEPARATOR);
  -//    }
  -//
  -//    
//-----------------------------------------------------------------------
  -//    /**
  -//     * Normalizes a path, removing double and single dot path steps.
  -//     * <p>
  -//     * This method normalizes a path to a standard format.
  -//     * The input may contain separators in either Unix or Windows format.
  -//     * The output will contain separators in the format of the system.
  -//     * <p>
  -//     * A double slash will be merged to a single slash (thus UNC names are 
not handled).
  -//     * A single dot path segment will be removed with no other effect.
  -//     * A double dot will cause that path segment and the one before to be 
removed.
  -//     * If the double dot has no parent path segment to work with, 
<code>null</code>
  -//     * is returned.
  -//     * <pre>
  -//     * /foo//               -->     /foo/
  -//     * /foo/./              -->     /foo/
  -//     * /foo/../bar          -->     /bar
  -//     * /foo/../bar/         -->     /bar/
  -//     * /foo/../bar/../baz   -->     /baz
  -//     * //foo//./bar         -->     /foo/bar
  -//     * /../                 -->     null
  -//     * ../foo               -->     null
  -//     * foo/../../bar        -->     null
  -//     * foo/../bar           -->     bar
  -//     * </pre>
  -//     *
  -//     * @param path  the path to normalize, null returns null
  -//     * @return the normalized String, or null if too many ..'s.
  -//     * @todo prefixes for Windows
  -//     */
  -//    public static String normalize(String path) {
  -//        if (path == null) {
  -//            return null;
  -//        }
  -//        char[] array = path.toCharArray();
  -//        int size = array.length;
  -//        // fix separators
  -//        for (int i = 0; i < array.length; i++) {
  -//            if (array[i] == OTHER_SEPARATOR) {
  -//                array[i] = SYSTEM_SEPARATOR;
  -//            }
  -//        }
  -//        // adjoining slashes
  -//        for (int i = 1; i < size; i++) {
  -//            if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == 
SYSTEM_SEPARATOR) {
  -//                System.arraycopy(array, i, array, i - 1, size - i);
  -//                size--;
  -//                i--;
  -//            }
  -//        }
  -//        // dot slash
  -//        for (int i = 2; i < size; i++) {
  -//            if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == '.' &&
  -//                    array[i - 2] == SYSTEM_SEPARATOR) {
  -//                System.arraycopy(array, i, array, i - 2, size - i);
  -//                size -=2;
  -//                i--;
  -//            }
  -//        }
  -//        // double dot slash
  -//        outer:
  -//        for (int i = 2; i < size; i++) {
  -//            if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == '.' &&
  -//                    array[i - 2] == '.' && (i == 2 || array[i - 3] == 
SYSTEM_SEPARATOR)) {
  -//                if (i == 2) {
  -//                    return null;
  -//                }
  -//                int j;
  -//                for (j = i - 4 ; j >= 0; j--) {
  -//                    if (array[j] == SYSTEM_SEPARATOR) {
  -//                        System.arraycopy(array, i, array, j, size - i);
  -//                        size -= (i - j);
  -//                        i = j + 1;
  -//                        continue outer;
  -//                    }
  -//                }
  -//                System.arraycopy(array, i + 1, array, 0, size - i - 1);
  -//                size -= (i + 1);
  -//                i = 1;
  -//            }
  -//        }
  -//        
  -//        return new String(array, 0, size);
  -//    }
  +    //-----------------------------------------------------------------------
  +    /**
  +     * Checks if the character is a separator.
  +     * 
  +     * @param ch  the character to check
  +     * @return true if it is a separators
  +     */
  +    private static boolean isSeparator(char ch) {
  +        return (ch == UNIX_SEPARATOR) || (ch == WINDOWS_SEPARATOR);
  +    }
   
       //-----------------------------------------------------------------------
       /**
  -     * Normalize a path.
  -     * Eliminates "/../" and "/./" in a string. Returns <code>null</code> if
  -     * the ..'s went past the root.
  -     * Eg:
  +     * Normalizes a path, removing double and single dot path steps.
  +     * <p>
  +     * This method normalizes a path to a standard format.
  +     * The input may contain separators in either Unix or Windows format.
  +     * The output will contain separators in the format of the system.
  +     * <p>
  +     * A double slash will be merged to a single slash (thus UNC names are 
not handled).
  +     * A single dot path segment will be removed with no other effect.
  +     * A double dot will cause that path segment and the one before to be 
removed.
  +     * If the double dot has no parent path segment to work with, 
<code>null</code>
  +     * is returned.
        * <pre>
        * /foo//               -->     /foo/
        * /foo/./              -->     /foo/
  @@ -218,53 +125,74 @@
        * /foo/../bar/../baz   -->     /baz
        * //foo//./bar         -->     /foo/bar
        * /../                 -->     null
  +     * ../foo               -->     null
  +     * foo/../../bar        -->     null
  +     * foo/../bar           -->     bar
        * </pre>
        *
  -     * @param path the path to normalize
  -     * @return the normalized String, or <code>null</code> if too many ..'s.
  -     * @todo Make this non-unix specific
  -     */
  -    public static String normalize(String path) {
  -        String normalized = path;
  -        // Resolve occurrences of "//" in the normalized path
  -        while (true) {
  -            int index = normalized.indexOf("//");
  -            if (index < 0) {
  -                break;
  +     * @param filename  the filename to normalize, null returns null
  +     * @return the normalized String, or null if too many ..'s.
  +     */
  +    public static String normalize(String filename) {
  +        if (filename == null) {
  +            return null;
  +        }
  +        char[] array = filename.toCharArray();
  +        int prefix = getPrefixLength(filename);
  +        if (prefix < 0) {
  +            return null;
  +        }
  +        
  +        // TODO: Use prefix
  +        
  +        int size = array.length;
  +        // fix separators
  +        for (int i = 0; i < array.length; i++) {
  +            if (array[i] == OTHER_SEPARATOR) {
  +                array[i] = SYSTEM_SEPARATOR;
               }
  -            normalized =
  -                normalized.substring(0, index)
  -                    + normalized.substring(index + 1);
           }
  -
  -        // Resolve occurrences of "/./" in the normalized path
  -        while (true) {
  -            int index = normalized.indexOf("/./");
  -            if (index < 0) {
  -                break;
  +        // adjoining slashes
  +        for (int i = 1; i < size; i++) {
  +            if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == 
SYSTEM_SEPARATOR) {
  +                System.arraycopy(array, i, array, i - 1, size - i);
  +                size--;
  +                i--;
               }
  -            normalized =
  -                normalized.substring(0, index)
  -                    + normalized.substring(index + 2);
           }
  -
  -        // Resolve occurrences of "/../" in the normalized path
  -        while (true) {
  -            int index = normalized.indexOf("/../");
  -            if (index < 0) {
  -                break;
  +        // dot slash
  +        for (int i = 2; i < size; i++) {
  +            if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == '.' &&
  +                    array[i - 2] == SYSTEM_SEPARATOR) {
  +                System.arraycopy(array, i, array, i - 2, size - i);
  +                size -=2;
  +                i--;
               }
  -            if (index == 0) {
  -                return null; // Trying to go outside our context
  +        }
  +        // double dot slash
  +        outer:
  +        for (int i = 2; i < size; i++) {
  +            if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == '.' &&
  +                    array[i - 2] == '.' && (i == 2 || array[i - 3] == 
SYSTEM_SEPARATOR)) {
  +                if (i == 2) {
  +                    return null;
  +                }
  +                int j;
  +                for (j = i - 4 ; j >= 0; j--) {
  +                    if (array[j] == SYSTEM_SEPARATOR) {
  +                        System.arraycopy(array, i, array, j, size - i);
  +                        size -= (i - j);
  +                        i = j + 1;
  +                        continue outer;
  +                    }
  +                }
  +                System.arraycopy(array, i + 1, array, 0, size - i - 1);
  +                size -= (i + 1);
  +                i = 1;
               }
  -            int index2 = normalized.lastIndexOf('/', index - 1);
  -            normalized =
  -                normalized.substring(0, index2)
  -                    + normalized.substring(index + 3);
           }
  -
  -        // Return the normalized path that we have completed
  -        return normalized;
  +        
  +        return new String(array, 0, size);
       }
   
       /**
  @@ -431,61 +359,81 @@
       }
   
       //-----------------------------------------------------------------------
  -//    /**
  -//     * Returns the length of the filename prefix, such as <code>C:/</code> 
or <code>~/</code>.
  -//     * <p>
  -//     * This method will handle a file in either Unix or Windows format.
  -//     * The prefix includes the first slash in the full filename.
  -//     * <pre>
  -//     * Windows:
  -//     * a\b\c.txt           --> ""          --> relative
  -//     * \a\b\c.txt          --> "\"         --> drive relative
  -//     * C:\a\b\c.txt        --> "C:\"       --> absolute
  -//     * \\server\a\b\c.txt  --> "\\server\" --> UNC
  -//     * 
  -//     * Unix:
  -//     * a/b/c.txt           --> ""          --> relative
  -//     * /a/b/c.txt          --> "/"         --> absolute
  -//     * ~/a/b/c.txt         --> "~/"        --> current user relative
  -//     * ~user/a/b/c.txt     --> "~user/"    --> named user relative
  -//     * </pre>
  -//     * 
  -//     * @param filename  the filename to find the prefix in, null returns -1
  -//     * @return the length of the prefix, -1 if invalid or null
  -//     */
  -//    public static int getPrefixLength(String filename) {
  -//        if (filename == null) {
  -//            return -1;
  -//        }
  -//        int len = filename.length();
  -//        if (len == 0) {
  -//            return 0;
  -//        }
  -//        if (SYSTEM_SEPARATOR == WINDOWS_SEPARATOR) {
  -//            char ch0 = filename.charAt(0);
  -//            if (len == 1) {
  -//                return (isSeparator(ch0) ? 1 : 0);
  -//            } else {
  -//                char ch1 = filename.charAt(1);
  -//                if (ch1 == ':') {
  -//                    ch0 = Character.toUpperCase(ch0);
  -//                    if (ch0 < 'A' || ch0 > 'Z' || len == 2 || 
isSeparator(filename.charAt(2)) == false) {
  -//                        return -1;
  -//                    }
  -//                    return 3;
  -//                } else if (isSeparator(ch0) && isSeparator(ch1)) {
  -//                    int pos = Math.min(
  -//                        filename.indexOf(UNIX_SEPARATOR, 2),
  -//                        filename.indexOf(WINDOWS_SEPARATOR, 2));
  -//                    return (pos == -1 || pos == 2 ? -1 : pos + 1);
  -//                } else {
  -//                    return (isSeparator(ch0) ? 1 : 0);
  -//                }
  -//            }
  -//        } else {
  -//        }
  -//        return 0;
  -//    }
  +    /**
  +     * Returns the length of the filename prefix, such as <code>C:/</code> 
or <code>~/</code>.
  +     * <p>
  +     * This method will handle a file in either Unix or Windows format.
  +     * The prefix includes the first slash in the full filename.
  +     * <pre>
  +     * Windows:
  +     * a\b\c.txt           --> ""          --> relative
  +     * \a\b\c.txt          --> "\"         --> drive relative
  +     * C:\a\b\c.txt        --> "C:\"       --> absolute
  +     * \\server\a\b\c.txt  --> "\\server\" --> UNC
  +     * 
  +     * Unix:
  +     * a/b/c.txt           --> ""          --> relative
  +     * /a/b/c.txt          --> "/"         --> absolute
  +     * ~/a/b/c.txt         --> "~/"        --> current user relative
  +     * ~user/a/b/c.txt     --> "~user/"    --> named user relative
  +     * </pre>
  +     * 
  +     * @param filename  the filename to find the prefix in, null returns -1
  +     * @return the length of the prefix, -1 if invalid or null
  +     */
  +    public static int getPrefixLength(String filename) {
  +        if (filename == null) {
  +            return -1;
  +        }
  +        int len = filename.length();
  +        if (len == 0) {
  +            return 0;
  +        }
  +        if (SYSTEM_SEPARATOR == WINDOWS_SEPARATOR) {
  +            char ch0 = filename.charAt(0);
  +            if (len == 1) {
  +                return (isSeparator(ch0) ? 1 : 0);
  +            } else {
  +                char ch1 = filename.charAt(1);
  +                if (ch1 == ':') {
  +                    ch0 = Character.toUpperCase(ch0);
  +                    if (ch0 < 'A' || ch0 > 'Z' || len == 2 || 
isSeparator(filename.charAt(2)) == false) {
  +                        return -1;
  +                    }
  +                    return 3;
  +                } else if (isSeparator(ch0) && isSeparator(ch1)) {
  +                    int posUnix = filename.indexOf(UNIX_SEPARATOR, 2);
  +                    int posWin = filename.indexOf(WINDOWS_SEPARATOR, 2);
  +                    if ((posUnix == -1 && posWin == -1) || posUnix == 2 || 
posWin == 2) {
  +                        return -1;
  +                    }
  +                    posUnix = (posUnix == -1 ? posWin : posUnix);
  +                    posWin = (posWin == -1 ? posUnix : posWin);
  +                    return Math.min(posUnix, posWin) + 1;
  +                } else {
  +                    return (isSeparator(ch0) ? 1 : 0);
  +                }
  +            }
  +        } else {
  +            char ch0 = filename.charAt(0);
  +            char ch1 = filename.charAt(1);
  +            if (ch0 == '~') {
  +                if (len == 1) {
  +                    return -1;
  +                }
  +                int posUnix = filename.indexOf(UNIX_SEPARATOR, 1);
  +                int posWin = filename.indexOf(WINDOWS_SEPARATOR, 1);
  +                if (posUnix == -1 && posWin == -1) {
  +                    return -1;
  +                }
  +                posUnix = (posUnix == -1 ? posWin : posUnix);
  +                posWin = (posWin == -1 ? posUnix : posWin);
  +                return Math.min(posUnix, posWin) + 1;
  +            } else {
  +                return (isSeparator(ch0) ? 1 : 0);
  +            }
  +        }
  +    }
   
       /**
        * Returns the index of the last directory separator character.
  @@ -527,61 +475,95 @@
       }
   
       //-----------------------------------------------------------------------
  -//    /**
  -//     * Gets the prefix from a full filename, such as <code>C:/</code> or 
<code>~/</code>.
  -//     * <p>
  -//     * This method will handle a file in either Unix or Windows format.
  -//     * The prefix includes the first slash in the full filename.
  -//     * <pre>
  -//     * Windows:
  -//     * a\b\c.txt           --> ""          --> relative
  -//     * \a\b\c.txt          --> "\"         --> drive relative
  -//     * C:\a\b\c.txt        --> "C:\"       --> absolute
  -//     * \\server\a\b\c.txt  --> "\\server\" --> UNC
  -//     * 
  -//     * Unix:
  -//     * a/b/c.txt           --> ""          --> relative
  -//     * /a/b/c.txt          --> "/"         --> absolute
  -//     * ~/a/b/c.txt         --> "~/"        --> current user relative
  -//     * ~user/a/b/c.txt     --> "~user/"    --> named user relative
  -//     * </pre>
  -//     *
  -//     * @param filename  the filename to query, null returns null
  -//     * @return the prefix of the file, null if invalid
  -//     */
  -//    public static String getPrefix(String filename) {
  -//        if (filename == null) {
  -//            return null;
  -//        }
  -//        int len = getPrefixLength(filename);
  -//        if (len < 0) {
  -//            return null;
  -//        }
  -//        return filename.substring(0, len);
  -//    }
  +    /**
  +     * Gets the prefix from a full filename, such as <code>C:/</code> or 
<code>~/</code>.
  +     * <p>
  +     * This method will handle a file in either Unix or Windows format.
  +     * The prefix includes the first slash in the full filename.
  +     * <pre>
  +     * Windows:
  +     * a\b\c.txt           --> ""          --> relative
  +     * \a\b\c.txt          --> "\"         --> drive relative
  +     * C:\a\b\c.txt        --> "C:\"       --> absolute
  +     * \\server\a\b\c.txt  --> "\\server\" --> UNC
  +     * 
  +     * Unix:
  +     * a/b/c.txt           --> ""          --> relative
  +     * /a/b/c.txt          --> "/"         --> absolute
  +     * ~/a/b/c.txt         --> "~/"        --> current user relative
  +     * ~user/a/b/c.txt     --> "~user/"    --> named user relative
  +     * </pre>
  +     *
  +     * @param filename  the filename to query, null returns null
  +     * @return the prefix of the file, null if invalid
  +     */
  +    public static String getPrefix(String filename) {
  +        if (filename == null) {
  +            return null;
  +        }
  +        int len = getPrefixLength(filename);
  +        if (len < 0) {
  +            return null;
  +        }
  +        return filename.substring(0, len);
  +    }
   
       /**
  -     * Gets the path from a full filename.
  +     * Gets the path from a full filename, which excludes the prefix.
        * <p>
        * This method will handle a file in either Unix or Windows format.
        * The text before the last forward or backslash is returned.
  -     * This method is roughly equivalent to the unix command 
<code>dirname</code>.
        * <pre>
  -     * a/b/c.txt --> a/b
  -     * a.txt     --> ""
  -     * a/b/c     --> a/b
  -     * a/b/c/    --> a/b/c
  +     * ~/a/b/c.txt --> a/b
  +     * a.txt       --> ""
  +     * a/b/c       --> a/b
  +     * a/b/c/      --> a/b/c
        * </pre>
        *
        * @param filename  the filename to query, null returns null
  -     * @return the path of the file, or an empty string if none exists
  +     * @return the path of the file, an empty string if none exists, null if 
invalid
        */
       public static String getPath(String filename) {
           if (filename == null) {
               return null;
           }
  +        int prefix = getPrefixLength(filename);
  +        if (prefix < 0) {
  +            return null;
  +        }
  +        int index = indexOfLastSeparator(filename);
  +        if (index < 0) {
  +            return "";
  +        } else {
  +            return filename.substring(prefix, index);
  +        }
  +    }
  +
  +    /**
  +     * Gets the full path from a full filename, which is the prefix + path.
  +     * <p>
  +     * This method will handle a file in either Unix or Windows format.
  +     * The text before the last forward or backslash is returned.
  +     * <pre>
  +     * ~/a/b/c.txt --> ~/a/b
  +     * a.txt       --> ""
  +     * a/b/c       --> a/b
  +     * a/b/c/      --> a/b/c
  +     * </pre>
  +     *
  +     * @param filename  the filename to query, null returns null
  +     * @return the path of the file, an empty string if none exists, null if 
invalid
  +     */
  +    public static String getFullPath(String filename) {
  +        if (filename == null) {
  +            return null;
  +        }
  +        int prefix = getPrefixLength(filename); // validate the prefix
  +        if (prefix < 0) {
  +            return null;
  +        }
           int index = indexOfLastSeparator(filename);
  -        if (index == -1) {
  +        if (index < 0) {
               return "";
           } else {
               return filename.substring(0, index);
  @@ -593,7 +575,6 @@
        * <p>
        * This method will handle a file in either Unix or Windows format.
        * The text after the last forward or backslash is returned.
  -     * This method is roughly equivalent to the unix command 
<code>basename</code>.
        * <pre>
        * a/b/c.txt --> c.txt
        * a.txt     --> a.txt
  @@ -610,6 +591,25 @@
           }
           int index = indexOfLastSeparator(filename);
           return filename.substring(index + 1);
  +    }
  +
  +    /**
  +     * Gets the base name, minus the full path and extension, from a full 
filename.
  +     * <p>
  +     * This method will handle a file in either Unix or Windows format.
  +     * The text after the last forward or backslash and before the last dot 
is returned.
  +     * <pre>
  +     * a/b/c.txt --> c
  +     * a.txt     --> a
  +     * a/b/c     --> c
  +     * a/b/c/    --> ""
  +     * </pre>
  +     *
  +     * @param filename  the filename to query, null returns null
  +     * @return the name of the file without the path, or an empty string if 
none exists
  +     */
  +    public static String getBaseName(String filename) {
  +        return removeExtension(getName(filename));
       }
   
       /**
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to