You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by do...@apache.org on 2002/08/31 05:54:10 UTC

cvs commit: jakarta-avalon-excalibur/io/src/java/org/apache/avalon/excalibur/io FileUtil.java

donaldp     2002/08/30 20:54:10

  Modified:    io/src/java/org/apache/avalon/excalibur/io FileUtil.java
  Log:
  Fixed up the normalize method so that it actually works in more circumstances.
  
  Submitted By: "Nicolas Leclerc" <nl...@novadeck.com>
  
  Revision  Changes    Path
  1.31      +122 -38   jakarta-avalon-excalibur/io/src/java/org/apache/avalon/excalibur/io/FileUtil.java
  
  Index: FileUtil.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/io/src/java/org/apache/avalon/excalibur/io/FileUtil.java,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- FileUtil.java	7 Aug 2002 05:44:02 -0000	1.30
  +++ FileUtil.java	31 Aug 2002 03:54:10 -0000	1.31
  @@ -433,10 +433,21 @@
       }
   
       /**
  -     * Normalize a path.
  -     * Eliminates "/../" and "/./" in a string. Returns <code>null</code> if the ..'s went past the
  -     * root.
  -     * Eg:
  +     * Normalize a path. That means:
  +     * <ul>
  +     *   <li>changes to unix style if under windows</li>
  +     *   <li>eliminates "/../" and "/./"</li>
  +     *   <li>if path is absolute (starts with '/') and there are
  +     *   too many occurences of "../" (would then have some kind
  +     *   of 'negative' path) returns null.</li>
  +     *   <li>If path is relative, the exceeding ../ are kept at
  +     *   the begining of the path.</li>
  +     * </ul>
  +     * <br><br>
  +     *
  +     * <b>Note:</b> note that this method has been tested with unix and windows only.
  +     *
  +     * <p>Eg:</p>
        * <pre>
        * /foo//               -->     /foo/
        * /foo/./              -->     /foo/
  @@ -447,47 +458,122 @@
        * /../                 -->     null
        * </pre>
        *
  -     * @param path the path to normalize
  -     * @return the normalized String, or <code>null</code> if too many ..'s.
  +     * @param path the path to be normalized.
  +     * @return the normalized path or null.
  +     * @throws NullPointerException if path is null.
        */
  -    public static String normalize( final String path )
  +    public static final String normalize( String path )
       {
  -        String normalized = path;
  -        // Resolve occurrences of "//" in the normalized path
  -        while( true )
  +        if( path.length() < 2 )
  +            return path;
  +
  +        StringBuffer buff = new StringBuffer( path );
  +
  +        int length = path.length();
  +
  +        // this whole prefix thing is for windows compatibility only.
  +        String prefix = null;
  +
  +        if( length > 2 && buff.charAt( 1 ) == ':' )
           {
  -            int index = normalized.indexOf( "//" );
  -            if( index < 0 )
  -                break;
  -            normalized = normalized.substring( 0, index ) +
  -                normalized.substring( index + 1 );
  +            prefix = path.substring( 0, 2 );
  +            buff.delete( 0, 2 );
  +            path = path.substring( 2 );
  +            length -= 2;
           }
   
  -        // Resolve occurrences of "/./" in the normalized path
  -        while( true )
  +        boolean startsWithSlash = length > 0 && (buff.charAt( 0 ) == '/' || buff.charAt( 0 ) == '\\');
  +
  +        boolean expStart = true;
  +        int ptCount = 0;
  +        int lastSlash = length + 1;
  +        int upLevel = 0;
  +
  +        for( int i = length - 1; i >= 0; i-- )
  +            switch( path.charAt( i ) )
  +            {
  +                case '\\':
  +                    buff.setCharAt( i, '/' );
  +                case '/':
  +                    if( lastSlash == i + 1 )
  +                        buff.deleteCharAt( i );
  +
  +                    switch( ptCount )
  +                    {
  +                        case 1:
  +                            buff.delete( i, lastSlash );
  +                            break;
  +
  +                        case 2:
  +                            upLevel++;
  +                            break;
  +
  +                        default:
  +                            if( upLevel > 0 && lastSlash != i + 1 )
  +                            {
  +                                buff.delete( i, lastSlash + 3 );
  +                                upLevel--;
  +                            }
  +                            break;
  +                    }
  +
  +                    ptCount = 0;
  +                    expStart = true;
  +                    lastSlash = i;
  +                    break;
  +
  +                case '.':
  +                    if( expStart )
  +                    {
  +                        ptCount++;
  +                    }
  +                    break;
  +
  +                default:
  +                    ptCount = 0;
  +                    expStart = false;
  +                    break;
  +            }
  +
  +        switch( ptCount )
           {
  -            int index = normalized.indexOf( "/./" );
  -            if( index < 0 )
  +            case 1:
  +                buff.delete( 0, lastSlash );
                   break;
  -            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 )
  +            case 2:
  +                break;
  +
  +            default:
  +                if( upLevel > 0 )
  +                {
  +                    if( startsWithSlash )
  +                        return null;
  +                    else
  +                        upLevel = 1;
  +                }
  +
  +                while( upLevel > 0 )
  +                {
  +                    buff.delete( 0, lastSlash + 3 );
  +                    upLevel--;
  +                }
                   break;
  -            if( index == 0 )
  -                return null;  // Trying to go outside our context
  -            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;
  +        length = buff.length();
  +        boolean isLengthNull = length == 0;
  +        char firstChar = isLengthNull?(char)0:buff.charAt( 0 );
  +
  +        if( !startsWithSlash && !isLengthNull && firstChar == '/' )
  +            buff.deleteCharAt( 0 );
  +        else if( startsWithSlash && (isLengthNull || (!isLengthNull && firstChar != '/')) )
  +            buff.insert( 0, '/' );
  +
  +        if( prefix != null )
  +            buff.insert( 0, prefix );
  +
  +        return buff.toString();
       }
   
       /**
  @@ -597,7 +683,7 @@
           filenm = sb.toString();
   
           //must be relative
  -        File file = ( new File( baseFile, filenm ) ).getAbsoluteFile();
  +        File file = (new File( baseFile, filenm )).getAbsoluteFile();
   
           try
           {
  @@ -712,7 +798,6 @@
           }
       }
   
  -
       /**
        * Make a directory. If there already exists a file with specified name or
        * the directory is unable to be created then an exception is thrown.
  @@ -865,5 +950,4 @@
   
           return size;
       }
  -
   }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>