changeset 2027:a2cbf3efeaa1

More fixes to zip provider * s/pathForprint/pathForPrint/g * Fixed comment typos. * Use String ctor directly, instead of substring(), no need to keep larger array around. * Replaced StringBuffer with StringBuilder. * ZipFilePath.normalize() now works. * ZipPathParser.normalize() now chops trailing slashes. * ZipPathParser.resolve() now handles leading '..' in relative paths properly. * Introduced checkPath() to throw NPE and ProviderMismatchExceptions before using Paths passed as arguments. * Fixed endsWith() to handle absolute other path properly (/foo !endsWith /). * Fixed startsWith(): Absolute paths do not start with relative ones. * Simplified subpath(). (This was overcomplex.) * normalize() now returns null for paths equivalent to "." * Cannot relativize() when exactly one path is absolute. * getParent() returned null instead of "/" for single-element absolute paths ("/foo"). Contributed-by: uckelman@nomic.net
author alanb
date Thu, 03 Dec 2009 19:36:54 +0000
parents ae67e52ef32f
children fa2afb1da3a0
files src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFilePath.java src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipPathParser.java
diffstat 2 files changed, 134 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFilePath.java	Tue Nov 10 11:39:41 2009 +0000
+++ b/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFilePath.java	Thu Dec 03 19:36:54 2009 +0000
@@ -73,13 +73,13 @@
     private final byte[] pathForZip;
     private final ReadLock readLock = new ReentrantReadWriteLock().readLock();
     private ZipFilePath pathToZip;
-    private final byte[] pathForprint;
+    private final byte[] pathForPrint;
 
     // package-private
     ZipFilePath(ZipFileSystem fileSystem, byte[] pathInZip) {
         this.fileSystem = fileSystem;
         this.path = pathInZip;
-        this.pathForprint = pathInZip;
+        this.pathForPrint = pathInZip;
         boolean isAbs = (path[0] == '/');
         String toResolve = new String(path);
         if (!isAbs) {
@@ -100,7 +100,19 @@
         this.fileSystem = fileSystem;
         this.path = pathForZip;
         this.pathForZip = pathForZip;
-        this.pathForprint = pathInZip; //given path
+        this.pathForPrint = pathInZip; //given path
+    }
+
+    private ZipFilePath checkPath(Path path) {
+        if (path == null) {
+            throw new NullPointerException();
+        }
+
+        if (!(path instanceof ZipFilePath)) {
+            throw new ProviderMismatchException();
+        }
+
+        return (ZipFilePath) path;
     }
 
     public boolean isNestedZip() {
@@ -257,14 +269,24 @@
 
     @Override
     public ZipFilePath getParent() {
-        int count = getNameCount();
-        if (count == 0 || count == 1) {
+        final int count = getNameCount();
+
+        // a root has no parent
+        if (count == 0) {
             return null;
         }
+
+        // a single-name path
+        if (count == 1) {
+            // has the root as its parent if absolute, and no parent otherwise
+            return isAbsolute() ?
+                new ZipFilePath(this.fileSystem, new byte[]{path[0]}) : null;
+        }
+
+        // all other paths have a parent
         int position = offsets.get(count - 1);
         String parent = subString(0, position - 1);
         return new ZipFilePath(this.fileSystem, parent.getBytes());
-
     }
 
     public ZipFilePath getParentEntry() {
@@ -333,34 +355,33 @@
 
     @Override
     public ZipFilePath subpath(int beginIndex, int endIndex) {
+        initOffsets();
 
-        initOffsets();
         if (beginIndex < 0) {
             throw new IllegalArgumentException();
         }
+
         if (beginIndex >= (1 + offsets.size())) {
             throw new IllegalArgumentException();
         }
+
         if (endIndex > (1 + offsets.size())) {
             throw new IllegalArgumentException();
         }
+
         if (beginIndex >= endIndex) {
             throw new IllegalArgumentException();
         }
 
-        int elements = endIndex - beginIndex;
-        String result = null;
-        StringBuffer result1 = new StringBuffer("");
-        int index = beginIndex;
-        for (; elements-- != 0;) {
-            if (endIndex == offsets.size() && elements == 0) {
-                result1.append(subString(offsets.get(index), path.length));
-                break;
-            }
-            result1.append(subString(offsets.get(index), offsets.get(++index)));
+        String result = subString(
+            offsets.get(beginIndex),
+            endIndex < offsets.size() ? offsets.get(endIndex) : path.length
+        );
+
+        if (result.endsWith("/")) {
+            result = result.substring(0, result.length()-1);
         }
-        result = result1.toString();
-        result = (result.endsWith("/")) ? result.substring(0, result.length() - 1) : result;
+
         return new ZipFilePath(fileSystem, result.getBytes());
     }
 
@@ -382,7 +403,7 @@
 
         int elements = endIndex - beginIndex;
         String result = null;
-        StringBuffer result1 = new StringBuffer("");
+        StringBuilder result1 = new StringBuilder("");
         int index = beginIndex;
 
         for (; elements-- != 0;) {
@@ -498,26 +519,22 @@
 
     @Override
     public Path relativize(Path other) {
-        if (other == null) {
-            throw new NullPointerException();
-        }
-        if (!(other instanceof ZipFilePath)) {
-            throw new ProviderMismatchException();
-        }
-        ZipFilePath other1 = (ZipFilePath) other;
-        if (other1.equals(this)) {
+        final ZipFilePath otherPath = checkPath(other);
+
+        if (otherPath.equals(this)) {
             return null;
         }
-        if (this.isAbsolute() != other1.isAbsolute()) {
-            return other1;
+
+        if (this.isAbsolute() != otherPath.isAbsolute()) {
+            throw new IllegalArgumentException();
         }
 
         int i = 0;
         int ti = this.getNameCount();
-        int oi = other1.getNameCount();
+        int oi = otherPath.getNameCount();
 
         for (; i < ti && i < oi; i++) {
-            if (!this.getName(i).equals(other1.getName(i))) {
+            if (!this.getName(i).equals(otherPath.getName(i))) {
                 break;
             }
         }
@@ -531,7 +548,7 @@
         ZipFilePath subPath = null;
         int subpathlen = 0;
         if (i < oi) {
-            subPath = other1.subpath(i, oi);
+            subPath = otherPath.subpath(i, oi);
             subpathlen = subPath.path.length;
         }
         byte[] result = new byte[arr.length + subpathlen];
@@ -592,56 +609,54 @@
 
     @Override
     public boolean startsWith(Path other) {
+        final ZipFilePath that = checkPath(other);
 
-        ZipFilePath other1 = null;
-        if (other == null) {
-            throw new NullPointerException();
-        }
-        if (other instanceof ZipFilePath) {
-            other1 = (ZipFilePath) other;
-        }
-
-        int otherCount = other1.getNameCount();
-        if (getNameCount() < otherCount) {
+        if (that.isAbsolute() != this.isAbsolute()) {
             return false;
         }
 
-        for (int i = 0; i < otherCount; i++) {
-            if (other1.getName(i).equals(getName(i))) {
+        final int thatCount = that.getNameCount();
+        if (getNameCount() < thatCount) {
+            return false;
+        }
+
+        for (int i = 0; i < thatCount; i++) {
+            if (that.getName(i).equals(getName(i))) {
                 continue;
-            } else {
+            }
+            else {
                 return false;
             }
         }
+
         return true;
-
     }
 
     @Override
     public boolean endsWith(Path other) {
-        ZipFilePath other1 = null;
-        if (other == null) {
-            throw new NullPointerException();
+        final ZipFilePath that = checkPath(other);
+
+        if (that.isAbsolute()) {
+            return this.isAbsolute() ? this.equals(that) : false;
         }
-        if (other instanceof ZipFilePath) {
-            other1 = (ZipFilePath) other;
-        }
-        int i = other1.getNameCount();
-        int j = getNameCount();
+
+        int i = that.getNameCount();
+        int j = this.getNameCount();
 
         if (j < i) {
             return false;
         }
 
         for (--i, --j; i >= 0; i--, j--) {
-            if (other1.getName(i).equals(getName(j))) {
-                continue;
-            } else {
-                return false;
+            if (that.getName(i).equals(this.getName(j))) {
+              continue;
+            }
+            else {
+              return false;
             }
         }
+
         return true;
-
     }
 
     public FileSystemProvider provider() {
@@ -650,7 +665,7 @@
 
     @Override
     public String toString() {
-        return new String(pathForprint);
+        return new String(pathForPrint);
     }
 
     @Override
@@ -677,9 +692,7 @@
 
     @Override
     public int compareTo(Path other) {
-
-        ZipFilePath otherPath = (ZipFilePath) other;
-        //int c = zipPath.compareTo(otherPath.zipPath);
+        final ZipFilePath otherPath = checkPath(other);
 
         int len1 = path.length;
         int len2 = otherPath.path.length;
@@ -1181,21 +1194,23 @@
     }
 
     /*
-     * /foo//                -- >  /foo/
-     * /foo/./               -- > /foo/
+     * /foo//                -- > /foo
+     * /foo/./               -- > /foo
      * /foo/../bar           -- > /bar
      * /foo/../bar/../baz    -- > /baz
      * //foo//./bar          -- > /foo/bar
      * /../                  -- > /
-     * ../foo                -- > foo
+     * ../foo                -- > ../foo
      * foo/bar/..            -- > foo
-     * foo/../../bar         -- > bar
+     * foo/../../bar         -- > ../bar
      * foo/../bar            -- > bar
      **/
     @Override
     public Path normalize() {
-        //pathForZip is normalized path for ZipFileSystem
-        return new ZipFilePath(fileSystem, pathForZip, pathForZip);
+        final String parsed = ZipPathParser.resolve(new String(path));
+
+        return parsed.equals("") ? null :
+            new ZipFilePath(fileSystem, parsed.getBytes(), pathForZip);
     }
 
     @Override
--- a/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipPathParser.java	Tue Nov 10 11:39:41 2009 +0000
+++ b/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipPathParser.java	Thu Dec 03 19:36:54 2009 +0000
@@ -32,8 +32,9 @@
 package com.sun.nio.zipfs;
 
 import java.nio.file.*;
+import java.util.Iterator;
 import java.util.LinkedList;
-import java.util.Stack;
+import java.util.ListIterator;
 import java.util.regex.*;
 
 
@@ -132,7 +133,7 @@
             }
             return 0; // path length >1 and No Prefix
         }
-        return 0; //Path lenght=1 and it does not have any prefix
+        return 0; //Path length=1 and it does not have any prefix
     }
 
     static int nextNonSeparator(String path, int off) {
@@ -178,7 +179,6 @@
             }
         }
         return compList;
-
     }
 
     private static int findZipComponent(int prefixLen, String path) {
@@ -208,14 +208,14 @@
         pathInZip.getChars(0, len, pathArr, 0);
 
         //Repleace all Separators \\ with Zip Separator /
-        //throws InavalidPathException in Windows and Unux if char is not valid
+        //throws InavalidPathException in Windows and Unix if char is not valid
         // in respective file systems.
 
         for (int i = 0; i < len; i++) {
             if (pathArr[i] == '\\') {
                 pathArr[i] = '/';
             }
-            if (fileSepa == '\\') { //If Path is In Windows
+            if (fileSepa == '\\') { //If Path is in Windows
                 if ((pathArr[i] < '\u0020') || (invalidChars.indexOf(pathArr[i]) != -1)) {
                     throw new InvalidPathException(pathInZip, "Invalid char at " + i);
                 }
@@ -223,7 +223,7 @@
                         ((i == len - 1) && pathArr[i] == ' '))) {
                     throw new InvalidPathException(pathInZip, "Trailing space at" + (i - 1));
                 }
-            } else if (fileSepa == '/') { //If path In In Unix
+            } else if (fileSepa == '/') { //If path is in Unix
                 if (pathArr[i] == '\u0000') {
                     throw new InvalidPathException(pathInZip, "Null char at" + i);
                 }
@@ -240,67 +240,63 @@
             }
 
         }
-        return new String(pathArr).substring(0, size);
 
+        // Remove trailing slash unless whole path is '/'
+        if (size > 1 && pathArr[size-1] == '/') size--;
 
+        return new String(pathArr, 0, size);
     }
 
     // Remove DotSlash(./) and resolve DotDot (..) components
     static String resolve(String path) {
+        final boolean prefix = path.startsWith("/");
+        final LinkedList<String> parts = getComponents(path);
 
-        int len = path.length();
-        char pathArr[] = new char[len];
-        path.getChars(0, len, pathArr, 0);
-        //Remove ./ component ,Remove this if not necessary
-        char ch = pathArr[0];
-        int prefixPos = (ch == '/') ? 1 : 0;
-        int size = len;
+        int previousDirsAtBeginning = 0;
 
-        for (int i = prefixPos + 1; i < size; i++) {
-            if ((pathArr[i] == '/' && pathArr[i - 1] == '.') &&
-                    (i == prefixPos + 1 || pathArr[i - 2] == '/')) {
-                System.arraycopy(pathArr, i + 1, pathArr, i - 1, size - (i + 1));
-                size -= 2;
-                i--;
+        // Remove redundant parts.
+        for (ListIterator<String> i = parts.listIterator(); i.hasNext(); ) {
+            final String part = i.next();
+
+            if (part.equals(".")) {
+                // ".": Remove.
+                i.remove();
             }
+            else if (part.equals("..")) {
+                // "..":
+                // Absolute paths: Remove this and the previous name, if any.
+                // Relative paths: Keep if we are part of a leading string of
+                // ".." names; otherwise remove this and the previous name.
+                if (prefix || i.previousIndex() > previousDirsAtBeginning) {
+                    i.remove();
 
-        }
-        //Remove final . if path has one. which is not needed for zip path
-        if ((size >= 2) && pathArr[size - 1] == '.' && pathArr[size - 2] == '/') {
-            System.arraycopy(pathArr, 0, pathArr, 0, size - 1);
-            size -= 1;
+                    // hasPrevious() can be false for the absolute path "/.."
+                    if (i.hasPrevious()) {
+                        i.previous();
+                        i.remove();
+                    }
+                }
+                else {
+                    // We are relative, must keep leading ".."
+                    previousDirsAtBeginning++;
+                }
+            }
+            else {
+                // Otherwise keep this name (for now).
+            }
         }
 
-        //Resolve ../ components
-        String pathStr = new String(pathArr, 0, size);
-        boolean prefix = pathStr.startsWith("/");
-        boolean endsWith = pathStr.endsWith("/");
-        LinkedList<String> compArr = getComponents(pathStr);
-        Stack<String> stack = new Stack<String>();
-        for (int i = 0; i < compArr.size(); i++) {
-            stack.push(compArr.get(i));
-            if (compArr.get(i).equals("..")) {
-                stack.pop();
-                if (i > 0 && stack.size() > 0) {
-                    stack.pop();
-                }
+        // Construct the resulting path string.
+        final StringBuilder res = new StringBuilder(prefix ? "/" : "");
+
+        final Iterator<String> i = parts.iterator();
+        if (i.hasNext()) {
+            res.append(i.next());
+            while (i.hasNext()) {
+                res.append("/").append(i.next());
             }
         }
-        //Construct final path
-        StringBuffer resolved = (prefix) ? new StringBuffer("/") : new StringBuffer("");
-        for (String comp : stack) {
-            resolved.append(comp).append("/");
 
-        }
-
-        String resolvedPath = "";
-        if (!resolved.toString().equals("")) {
-            if (!endsWith && resolved.length() != 1) {
-                resolvedPath = resolved.substring(0, resolved.length() - 1);
-            } else {
-                resolvedPath = resolved.toString();
-            }
-        }
-        return (resolvedPath);
+        return res.toString();
     }
 }