8061777: (zipfs) IllegalArgumentException in ZipCoder.toString when using Shitft_JIS
authorsherman
Wed, 01 Jun 2016 09:52:08 -0700
changeset 38769 8046caf79f1c
parent 38768 7d6930523e38
child 38770 e8746fa36f1a
8061777: (zipfs) IllegalArgumentException in ZipCoder.toString when using Shitft_JIS Reviewed-by: psandoz
jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java
jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java
jdk/test/jdk/nio/zipfs/ZFSTests.java
--- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java	Wed Jun 01 14:33:44 2016 +0100
+++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java	Wed Jun 01 09:52:08 2016 -0700
@@ -69,7 +69,7 @@
 
     private final ZipFileSystemProvider provider;
     private final Path zfpath;
-    private final ZipCoder zc;
+    final ZipCoder zc;
     private final boolean noExtt;        // see readExtra()
     private final ZipPath rootdir;
     // configurable by env map
@@ -163,7 +163,7 @@
     @Override
     public ZipPath getPath(String first, String... more) {
         if (more.length == 0) {
-            return new ZipPath(this, getBytes(first));
+            return new ZipPath(this, first);
         }
         StringBuilder sb = new StringBuilder();
         sb.append(first);
@@ -175,7 +175,7 @@
                 sb.append(path);
             }
         }
-        return new ZipPath(this, getBytes(sb.toString()));
+        return new ZipPath(this, sb.toString());
     }
 
     @Override
--- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java	Wed Jun 01 14:33:44 2016 +0100
+++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java	Wed Jun 01 09:52:08 2016 -0700
@@ -52,13 +52,28 @@
         this(zfs, path, false);
     }
 
-    ZipPath(ZipFileSystem zfs, byte[] path, boolean normalized)
-    {
+    ZipPath(ZipFileSystem zfs, byte[] path, boolean normalized) {
         this.zfs = zfs;
-        if (normalized)
+        if (normalized) {
             this.path = path;
-        else
+        } else {
+            if (zfs.zc.isUTF8()) {
+                this.path = normalize(path);
+            } else {
+                // see normalize(String);
+                this.path = normalize(zfs.getString(path));
+            }
+        }
+    }
+
+    ZipPath(ZipFileSystem zfs, String path) {
+        this.zfs = zfs;
+        if (zfs.zc.isUTF8()) {
+            this.path = normalize(zfs.getBytes(path));
+        } else {
+            // see normalize(String);
             this.path = normalize(path);
+        }
     }
 
     @Override
@@ -471,6 +486,50 @@
         return (m == to.length)? to : Arrays.copyOf(to, m);
     }
 
+    // if zfs is NOT in utf8, normalize the path as "String"
+    // to avoid incorrectly normalizing byte '0x5c' (as '\')
+    // to '/'.
+    private byte[] normalize(String path) {
+        int len = path.length();
+        if (len == 0)
+            return new byte[0];
+        char prevC = 0;
+        for (int i = 0; i < len; i++) {
+            char c = path.charAt(i);
+            if (c == '\\' || c == '\u0000')
+                return normalize(path, i, len);
+            if (c == '/' && prevC == '/')
+                return normalize(path, i - 1, len);
+            prevC = c;
+        }
+        if (len > 1 && prevC == '/')
+            path = path.substring(0, len - 1);
+        return zfs.getBytes(path);
+    }
+
+    private byte[] normalize(String path, int off, int len) {
+        StringBuilder to = new StringBuilder(len);
+        to.append(path, 0, off);
+        int m = off;
+        char prevC = 0;
+        while (off < len) {
+            char c = path.charAt(off++);
+            if (c == '\\')
+                c = '/';
+            if (c == '/' && prevC == '/')
+                continue;
+            if (c == '\u0000')
+                throw new InvalidPathException(path,
+                                               "Path: nul character not allowed");
+            to.append(c);
+            prevC = c;
+        }
+        len = to.length();
+        if (len > 1 && prevC == '/')
+            to.delete(len -1, len);
+        return zfs.getBytes(to.toString());
+    }
+
     // Remove DotSlash(./) and resolve DotDot (..) components
     private byte[] getResolved() {
         for (int i = 0; i < path.length; i++) {
--- a/jdk/test/jdk/nio/zipfs/ZFSTests.java	Wed Jun 01 14:33:44 2016 +0100
+++ b/jdk/test/jdk/nio/zipfs/ZFSTests.java	Wed Jun 01 09:52:08 2016 -0700
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 7156873 8040059 8028480 8034773 8153248
+ * @bug 7156873 8040059 8028480 8034773 8153248 8061777
  * @summary ZipFileSystem regression tests
  *
  * @run main ZFSTests
@@ -43,6 +43,7 @@
 
     public static void main(String[] args) throws Throwable {
         test7156873();
+        test8061777();
         tests();
     }
 
@@ -62,6 +63,34 @@
         }
     }
 
+    static void test8061777() throws Throwable {
+        Path path = Paths.get("file.zip");
+        try {
+            URI uri = URI.create("jar:" + path.toUri());
+            Map<String, Object> env = new HashMap<String, Object>();
+            env.put("create", "true");
+            env.put("encoding", "Shift_JIS");
+            try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
+                FileSystemProvider fsp = fs.provider();
+                Path p = fs.getPath("/\u8868\u7533.txt");  // 0x95 0x5c 0x90 0x5c
+                try (OutputStream os = fsp.newOutputStream(p)) {
+                    os.write("Hello!".getBytes("ASCII"));
+                }
+                Path dir = fs.getPath("/");
+                Files.list(dir)
+                     .forEach( child -> {
+                             System.out.println("child:" + child);
+                             if (!child.toString().equals(p.toString()))
+                                 throw new RuntimeException("wrong path name created");
+                          });
+                if (!"Hello!".equals(new String(Files.readAllBytes(p), "ASCII")))
+                    throw new RuntimeException("wrong content in newly created file");
+            }
+        } finally {
+            Files.deleteIfExists(path);
+        }
+    }
+
     static void tests() throws Throwable {
         Path path = Paths.get("file.zip");
         try {