6508981: cleanup file separator handling in JavacFileManager
authorjjg
Tue, 26 Aug 2008 14:52:59 -0700
changeset 1205 b316e32eb90c
parent 1109 853d8c191eac
child 1206 3a05355982a9
6508981: cleanup file separator handling in JavacFileManager Reviewed-by: mcimadamore
langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java
langtools/src/share/classes/com/sun/tools/javac/file/RelativePath.java
langtools/src/share/classes/com/sun/tools/javac/file/SymbolArchive.java
langtools/src/share/classes/com/sun/tools/javac/file/ZipArchive.java
langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java
langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java
langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java
langtools/src/share/classes/javax/tools/StandardLocation.java
langtools/test/tools/javac/6508981/TestInferBinaryName.java
langtools/test/tools/javac/6508981/p/A.java
langtools/test/tools/javac/T6725036.java
--- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Fri Aug 22 11:46:29 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Tue Aug 26 14:52:59 2008 -0700
@@ -65,6 +65,8 @@
 import javax.tools.StandardJavaFileManager;
 
 import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.file.RelativePath.RelativeFile;
+import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
 import com.sun.tools.javac.main.JavacOption;
 import com.sun.tools.javac.main.OptionName;
 import com.sun.tools.javac.main.RecognizedOptions;
@@ -75,8 +77,8 @@
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Options;
 
+import static javax.tools.StandardLocation.*;
 import static com.sun.tools.javac.main.OptionName.*;
-import static javax.tools.StandardLocation.*;
 
 /**
  * This class provides access to the source, class and other files
@@ -84,9 +86,6 @@
  */
 public class JavacFileManager implements StandardJavaFileManager {
 
-    private static final String[] symbolFileLocation = { "lib", "ct.sym" };
-    private static final String symbolFilePrefix = "META-INF/sym/rt.jar/";
-
     boolean useZipFileIndex;
 
     private static boolean CHECK_ZIP_TIMESTAMP = false;
@@ -267,6 +266,7 @@
             printAscii("Invalid class name: \"%s\"", name);
         }
     }
+
     private static void printAscii(String format, Object... args) {
         String message;
         try {
@@ -278,27 +278,12 @@
         System.out.println(message);
     }
 
-    /** Return external representation of name,
-     *  converting '.' to File.separatorChar.
-     */
-    private static String externalizeFileName(CharSequence name) {
-        return name.toString().replace('.', File.separatorChar);
-    }
-
-    private static String externalizeFileName(CharSequence n, JavaFileObject.Kind kind) {
-        return externalizeFileName(n) + kind.extension;
-    }
-
-    private static String baseName(String fileName) {
-        return fileName.substring(fileName.lastIndexOf(File.separatorChar) + 1);
-    }
-
     /**
      * Insert all files in subdirectory `subdirectory' of `directory' which end
      * in one of the extensions in `extensions' into packageSym.
      */
     private void listDirectory(File directory,
-                               String subdirectory,
+                               RelativeDirectory subdirectory,
                                Set<JavaFileObject.Kind> fileKinds,
                                boolean recurse,
                                ListBuffer<JavaFileObject> l) {
@@ -329,22 +314,6 @@
                     return;
                 }
             }
-            if (subdirectory.length() != 0) {
-                if (!useZipFileIndex) {
-                    subdirectory = subdirectory.replace('\\', '/');
-                    if (!subdirectory.endsWith("/")) subdirectory = subdirectory + "/";
-                }
-                else {
-                    if (File.separatorChar == '/') {
-                        subdirectory = subdirectory.replace('\\', '/');
-                    }
-                    else {
-                        subdirectory = subdirectory.replace('/', '\\');
-                    }
-
-                    if (!subdirectory.endsWith(File.separator)) subdirectory = subdirectory + File.separator;
-                }
-            }
 
             List<String> files = archive.getFiles(subdirectory);
             if (files != null) {
@@ -356,8 +325,8 @@
                 }
             }
             if (recurse) {
-                for (String s: archive.getSubdirectories()) {
-                    if (s.startsWith(subdirectory) && !s.equals(subdirectory)) {
+                for (RelativeDirectory s: archive.getSubdirectories()) {
+                    if (subdirectory.contains(s)) {
                         // Because the archive map is a flat list of directories,
                         // the enclosing loop will pick up all child subdirectories.
                         // Therefore, there is no need to recurse deeper.
@@ -366,9 +335,7 @@
                 }
             }
         } else {
-            File d = subdirectory.length() != 0
-                ? new File(directory, subdirectory)
-                : directory;
+            File d = subdirectory.getFile(directory);
             if (!caseMapCheck(d, subdirectory))
                 return;
 
@@ -381,7 +348,7 @@
                 if (f.isDirectory()) {
                     if (recurse && SourceVersion.isIdentifier(fname)) {
                         listDirectory(directory,
-                                      subdirectory + File.separator + fname,
+                                      new RelativeDirectory(subdirectory, fname),
                                       fileKinds,
                                       recurse,
                                       l);
@@ -411,7 +378,7 @@
      *  ends in a string of characters with the same case as given name.
      *  Ignore file separators in both path and name.
      */
-    private boolean caseMapCheck(File f, String name) {
+    private boolean caseMapCheck(File f, RelativePath name) {
         if (fileSystemIsCaseSensitive) return true;
         // Note that getCanonicalPath() returns the case-sensitive
         // spelled file name.
@@ -422,12 +389,12 @@
             return false;
         }
         char[] pcs = path.toCharArray();
-        char[] ncs = name.toCharArray();
+        char[] ncs = name.path.toCharArray();
         int i = pcs.length - 1;
         int j = ncs.length - 1;
         while (i >= 0 && j >= 0) {
             while (i >= 0 && pcs[i] == File.separatorChar) i--;
-            while (j >= 0 && ncs[j] == File.separatorChar) j--;
+            while (j >= 0 && ncs[j] == '/') j--;
             if (i >= 0 && j >= 0) {
                 if (pcs[i] != ncs[j]) return false;
                 i--;
@@ -444,13 +411,13 @@
     public interface Archive {
         void close() throws IOException;
 
-        boolean contains(String name);
+        boolean contains(RelativePath name);
 
-        JavaFileObject getFileObject(String subdirectory, String file);
+        JavaFileObject getFileObject(RelativeDirectory subdirectory, String file);
 
-        List<String> getFiles(String subdirectory);
+        List<String> getFiles(RelativeDirectory subdirectory);
 
-        Set<String> getSubdirectories();
+        Set<RelativeDirectory> getSubdirectories();
     }
 
     public class MissingArchive implements Archive {
@@ -458,30 +425,38 @@
         public MissingArchive(File name) {
             zipFileName = name;
         }
-        public boolean contains(String name) {
+        public boolean contains(RelativePath name) {
             return false;
         }
 
         public void close() {
         }
 
-        public JavaFileObject getFileObject(String subdirectory, String file) {
+        public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
             return null;
         }
 
-        public List<String> getFiles(String subdirectory) {
+        public List<String> getFiles(RelativeDirectory subdirectory) {
             return List.nil();
         }
 
-        public Set<String> getSubdirectories() {
+        public Set<RelativeDirectory> getSubdirectories() {
             return Collections.emptySet();
         }
+
+        public String toString() {
+            return "MissingArchive[" + zipFileName + "]";
+        }
     }
 
     /** A directory of zip files already opened.
      */
     Map<File, Archive> archives = new HashMap<File,Archive>();
 
+    private static final String[] symbolFileLocation = { "lib", "ct.sym" };
+    private static final RelativeDirectory symbolFilePrefix
+            = new RelativeDirectory("META-INF/sym/rt.jar/");
+
     /** Open a new zip file directory.
      */
     protected Archive openArchive(File zipFileName) throws IOException {
@@ -540,8 +515,12 @@
                     if (!useZipFileIndex) {
                         archive = new ZipArchive(this, zdir);
                     } else {
-                        archive = new ZipFileIndexArchive(this, ZipFileIndex.getZipFileIndex(zipFileName, null,
-                                usePreindexedCache, preindexCacheLocation, options.get("writezipindexfiles") != null));
+                        archive = new ZipFileIndexArchive(this,
+                                ZipFileIndex.getZipFileIndex(zipFileName,
+                                    null,
+                                    usePreindexedCache,
+                                    preindexCacheLocation,
+                                    options.get("writezipindexfiles") != null));
                     }
                 }
                 else {
@@ -551,10 +530,10 @@
                     else {
                         archive = new ZipFileIndexArchive(this,
                                 ZipFileIndex.getZipFileIndex(zipFileName,
-                                symbolFilePrefix,
-                                usePreindexedCache,
-                                preindexCacheLocation,
-                                options.get("writezipindexfiles") != null));
+                                    symbolFilePrefix,
+                                    usePreindexedCache,
+                                    preindexCacheLocation,
+                                    options.get("writezipindexfiles") != null));
                     }
                 }
             } catch (FileNotFoundException ex) {
@@ -796,7 +775,7 @@
         Iterable<? extends File> path = getLocation(location);
         if (path == null)
             return List.nil();
-        String subdirectory = externalizeFileName(packageName);
+        RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
         ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
 
         for (File directory : path)
@@ -877,7 +856,7 @@
         nullCheck(kind);
         if (!sourceOrClass.contains(kind))
             throw new IllegalArgumentException("Invalid kind " + kind);
-        return getFileForInput(location, externalizeFileName(className, kind));
+        return getFileForInput(location, RelativeFile.forClass(className, kind));
     }
 
     public FileObject getFileForInput(Location location,
@@ -890,35 +869,32 @@
         nullCheck(packageName);
         if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701
             throw new IllegalArgumentException("Invalid relative name: " + relativeName);
-        String name = packageName.length() == 0
-            ? relativeName
-            : new File(externalizeFileName(packageName), relativeName).getPath();
+        RelativeFile name = packageName.length() == 0
+            ? new RelativeFile(relativeName)
+            : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
         return getFileForInput(location, name);
     }
 
-    private JavaFileObject getFileForInput(Location location, String name) throws IOException {
+    private JavaFileObject getFileForInput(Location location, RelativeFile name) throws IOException {
         Iterable<? extends File> path = getLocation(location);
         if (path == null)
             return null;
 
         for (File dir: path) {
             if (dir.isDirectory()) {
-                File f = new File(dir, name.replace('/', File.separatorChar));
+                File f = name.getFile(dir);
                 if (f.exists())
                     return new RegularFileObject(this, f);
             } else {
                 Archive a = openArchive(dir);
                 if (a.contains(name)) {
-                    int i = name.lastIndexOf('/');
-                    String dirname = name.substring(0, i+1);
-                    String basename = name.substring(i+1);
-                    return a.getFileObject(dirname, basename);
+                    return a.getFileObject(name.dirname(), name.basename());
                 }
 
             }
         }
+
         return null;
-
     }
 
     public JavaFileObject getJavaFileForOutput(Location location,
@@ -933,7 +909,7 @@
         nullCheck(kind);
         if (!sourceOrClass.contains(kind))
             throw new IllegalArgumentException("Invalid kind " + kind);
-        return getFileForOutput(location, externalizeFileName(className, kind), sibling);
+        return getFileForOutput(location, RelativeFile.forClass(className, kind), sibling);
     }
 
     public FileObject getFileForOutput(Location location,
@@ -947,14 +923,14 @@
         nullCheck(packageName);
         if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701
             throw new IllegalArgumentException("relativeName is invalid");
-        String name = packageName.length() == 0
-            ? relativeName
-            : new File(externalizeFileName(packageName), relativeName).getPath();
+        RelativeFile name = packageName.length() == 0
+            ? new RelativeFile(relativeName)
+            : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
         return getFileForOutput(location, name, sibling);
     }
 
     private JavaFileObject getFileForOutput(Location location,
-                                            String fileName,
+                                            RelativeFile fileName,
                                             FileObject sibling)
         throws IOException
     {
@@ -967,7 +943,7 @@
                 if (sibling != null && sibling instanceof RegularFileObject) {
                     siblingDir = ((RegularFileObject)sibling).f.getParentFile();
                 }
-                return new RegularFileObject(this, new File(siblingDir, baseName(fileName)));
+                return new RegularFileObject(this, new File(siblingDir, fileName.basename()));
             }
         } else if (location == SOURCE_OUTPUT) {
             dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir());
@@ -980,7 +956,7 @@
             }
         }
 
-        File file = (dir == null ? new File(fileName) : new File(dir, fileName));
+        File file = fileName.getFile(dir); // null-safe
         return new RegularFileObject(this, file);
 
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/RelativePath.java	Tue Aug 26 14:52:59 2008 -0700
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.file;
+
+import java.io.File;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import javax.tools.JavaFileObject;
+
+/**
+ * Used to represent a platform-neutral path within a platform-specific
+ * container, such as a directory or zip file.
+ * Internally, the file separator is always '/'.
+ */
+public abstract class RelativePath implements Comparable<RelativePath> {
+    /**
+     * @param p must use '/' as an internal separator
+     */
+    protected RelativePath(String p) {
+        path = p;
+    }
+
+    public abstract RelativeDirectory dirname();
+
+    public abstract String basename();
+
+    public File getFile(File directory) {
+        if (path.length() == 0)
+            return directory;
+        return new File(directory, path.replace('/', File.separatorChar));
+    }
+
+    public int compareTo(RelativePath other) {
+        return path.compareTo(other.path);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof RelativePath))
+            return false;
+         return path.equals(((RelativePath) other).path);
+    }
+
+    @Override
+    public int hashCode() {
+        return path.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "RelPath[" + path + "]";
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    protected final String path;
+
+    /**
+     * Used to represent a platform-neutral subdirectory within a platform-specific
+     * container, such as a directory or zip file.
+     * Internally, the file separator is always '/', and if the path is not empty,
+     * it always ends in a '/' as well.
+     */
+    public static class RelativeDirectory extends RelativePath {
+
+        static RelativeDirectory forPackage(CharSequence packageName) {
+            return new RelativeDirectory(packageName.toString().replace('.', '/'));
+        }
+
+        /**
+         * @param p must use '/' as an internal separator
+         */
+        public RelativeDirectory(String p) {
+            super(p.length() == 0 || p.endsWith("/") ? p : p + "/");
+        }
+
+        /**
+         * @param p must use '/' as an internal separator
+         */
+        public RelativeDirectory(RelativeDirectory d, String p) {
+            this(d.path + p);
+        }
+
+        @Override
+        public RelativeDirectory dirname() {
+            int l = path.length();
+            if (l == 0)
+                return this;
+            int sep = path.lastIndexOf('/', l - 2);
+            return new RelativeDirectory(path.substring(0, sep + 1));
+        }
+
+        @Override
+        public String basename() {
+            int l = path.length();
+            if (l == 0)
+                return path;
+            int sep = path.lastIndexOf('/', l - 2);
+            return path.substring(sep + 1, l - 1);
+        }
+
+        /**
+         * Return true if this subdirectory "contains" the other path.
+         * A subdirectory path does not contain itself.
+         **/
+        boolean contains(RelativePath other) {
+            return other.path.length() > path.length() && other.path.startsWith(path);
+        }
+
+        @Override
+        public String toString() {
+            return "RelativeDirectory[" + path + "]";
+        }
+    }
+
+    /**
+     * Used to represent a platform-neutral file within a platform-specific
+     * container, such as a directory or zip file.
+     * Internally, the file separator is always '/'. It never ends in '/'.
+     */
+    public static class RelativeFile extends RelativePath {
+        static RelativeFile forClass(CharSequence className, JavaFileObject.Kind kind) {
+            return new RelativeFile(className.toString().replace('.', '/') + kind.extension);
+        }
+
+        public RelativeFile(String p) {
+            super(p);
+            if (p.endsWith("/"))
+                throw new IllegalArgumentException(p);
+        }
+
+        /**
+         * @param p must use '/' as an internal separator
+         */
+        public RelativeFile(RelativeDirectory d, String p) {
+            this(d.path + p);
+        }
+
+        RelativeFile(RelativeDirectory d, RelativePath p) {
+            this(d, p.path);
+        }
+
+        @Override
+        public RelativeDirectory dirname() {
+            int sep = path.lastIndexOf('/');
+            return new RelativeDirectory(path.substring(0, sep + 1));
+        }
+
+        @Override
+        public String basename() {
+            int sep = path.lastIndexOf('/');
+            return path.substring(sep + 1);
+        }
+
+        ZipEntry getZipEntry(ZipFile zip) {
+            return zip.getEntry(path);
+        }
+
+        @Override
+        public String toString() {
+            return "RelativeFile[" + path + "]";
+        }
+
+    }
+
+}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/SymbolArchive.java	Fri Aug 22 11:46:29 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/SymbolArchive.java	Tue Aug 26 14:52:59 2008 -0700
@@ -25,47 +25,75 @@
 
 package com.sun.tools.javac.file;
 
-import com.sun.tools.javac.util.List;
 import java.io.File;
 import java.io.IOException;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import javax.tools.JavaFileObject;
 
+import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
+import com.sun.tools.javac.file.RelativePath.RelativeFile;
+import com.sun.tools.javac.util.List;
+
 public class SymbolArchive extends ZipArchive {
 
     final File origFile;
-    final String prefix;
+    final RelativeDirectory prefix;
 
-    public SymbolArchive(JavacFileManager fileManager, File orig, ZipFile zdir, String prefix) throws IOException {
-        super(fileManager, zdir);
+    public SymbolArchive(JavacFileManager fileManager, File orig, ZipFile zdir, RelativeDirectory prefix) throws IOException {
+        super(fileManager, zdir, false);
         this.origFile = orig;
         this.prefix = prefix;
+        initMap();
     }
 
     @Override
     void addZipEntry(ZipEntry entry) {
         String name = entry.getName();
-        if (!name.startsWith(prefix)) {
+        if (!name.startsWith(prefix.path)) {
             return;
         }
-        name = name.substring(prefix.length());
+        name = name.substring(prefix.path.length());
         int i = name.lastIndexOf('/');
-        String dirname = name.substring(0, i + 1);
+        RelativeDirectory dirname = new RelativeDirectory(name.substring(0, i+1));
         String basename = name.substring(i + 1);
         if (basename.length() == 0) {
             return;
         }
         List<String> list = map.get(dirname);
-        if (list == null) {
+        if (list == null)
             list = List.nil();
-        }
         list = list.prepend(basename);
         map.put(dirname, list);
     }
 
-    @Override
-    public JavaFileObject getFileObject(String subdirectory, String file) {
-        return super.getFileObject(prefix + subdirectory, file);
+    public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
+        RelativeDirectory prefix_subdir = new RelativeDirectory(prefix, subdirectory.path);
+        ZipEntry ze = new RelativeFile(prefix_subdir, file).getZipEntry(zdir);
+        return new SymbolFileObject(this, file, ze);
+    }
+
+    public String toString() {
+        return "SymbolArchive[" + zdir.getName() + "]";
     }
+
+    /**
+     * A subclass of JavaFileObject representing zip entries in a symbol file.
+     */
+    public static class SymbolFileObject extends ZipFileObject {
+        protected SymbolFileObject(SymbolArchive zarch, String name, ZipEntry entry) {
+            super(zarch, name, entry);
+        }
+
+        @Override
+        protected String inferBinaryName(Iterable<? extends File> path) {
+            String entryName = getZipEntryName();
+            String prefix = ((SymbolArchive) zarch).prefix.path;
+            if (entryName.startsWith(prefix))
+                entryName = entryName.substring(prefix.length());
+            return removeExtension(entryName).replace('/', '.');
+        }
+    }
+
+
 }
--- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipArchive.java	Fri Aug 22 11:46:29 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipArchive.java	Tue Aug 26 14:52:59 2008 -0700
@@ -25,18 +25,8 @@
 
 package com.sun.tools.javac.file;
 
+import java.io.File;
 import java.io.IOException;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import javax.tools.JavaFileObject;
-
-import com.sun.tools.javac.file.JavacFileManager.Archive;
-import com.sun.tools.javac.util.List;
-import java.io.File;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Writer;
@@ -44,13 +34,35 @@
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.CharsetDecoder;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.file.JavacFileManager.Archive;
+import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
+import com.sun.tools.javac.file.RelativePath.RelativeFile;
+import com.sun.tools.javac.util.List;
 
 public class ZipArchive implements Archive {
 
     public ZipArchive(JavacFileManager fm, ZipFile zdir) throws IOException {
+        this(fm, zdir, true);
+    }
+
+    protected ZipArchive(JavacFileManager fm, ZipFile zdir, boolean initMap) throws IOException {
         this.fileManager = fm;
         this.zdir = zdir;
-        this.map = new HashMap<String,List<String>>();
+        this.map = new HashMap<RelativeDirectory,List<String>>();
+        if (initMap)
+            initMap();
+    }
+
+    protected void initMap() throws IOException {
         for (Enumeration<? extends ZipEntry> e = zdir.entries(); e.hasMoreElements(); ) {
             ZipEntry entry;
             try {
@@ -67,7 +79,7 @@
     void addZipEntry(ZipEntry entry) {
         String name = entry.getName();
         int i = name.lastIndexOf('/');
-        String dirname = name.substring(0, i+1);
+        RelativeDirectory dirname = new RelativeDirectory(name.substring(0, i+1));
         String basename = name.substring(i+1);
         if (basename.length() == 0)
             return;
@@ -78,26 +90,25 @@
         map.put(dirname, list);
     }
 
-    public boolean contains(String name) {
-        int i = name.lastIndexOf('/');
-        String dirname = name.substring(0, i+1);
-        String basename = name.substring(i+1);
+    public boolean contains(RelativePath name) {
+        RelativeDirectory dirname = name.dirname();
+        String basename = name.basename();
         if (basename.length() == 0)
             return false;
         List<String> list = map.get(dirname);
         return (list != null && list.contains(basename));
     }
 
-    public List<String> getFiles(String subdirectory) {
+    public List<String> getFiles(RelativeDirectory subdirectory) {
         return map.get(subdirectory);
     }
 
-    public JavaFileObject getFileObject(String subdirectory, String file) {
-        ZipEntry ze = zdir.getEntry(subdirectory + file);
+    public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
+        ZipEntry ze = new RelativeFile(subdirectory, file).getZipEntry(zdir);
         return new ZipFileObject(this, file, ze);
     }
 
-    public Set<String> getSubdirectories() {
+    public Set<RelativeDirectory> getSubdirectories() {
         return map.keySet();
     }
 
@@ -105,8 +116,12 @@
         zdir.close();
     }
 
+    public String toString() {
+        return "ZipArchive[" + zdir.getName() + "]";
+    }
+
     protected JavacFileManager fileManager;
-    protected final Map<String,List<String>> map;
+    protected final Map<RelativeDirectory,List<String>> map;
     protected final ZipFile zdir;
 
     /**
@@ -118,7 +133,7 @@
         ZipArchive zarch;
         ZipEntry entry;
 
-        public ZipFileObject(ZipArchive zarch, String name, ZipEntry entry) {
+        protected ZipFileObject(ZipArchive zarch, String name, ZipEntry entry) {
             super(zarch.fileManager);
             this.zarch = zarch;
             this.name = name;
@@ -222,11 +237,6 @@
         @Override
         protected String inferBinaryName(Iterable<? extends File> path) {
             String entryName = getZipEntryName();
-            if (zarch instanceof SymbolArchive) {
-                String prefix = ((SymbolArchive) zarch).prefix;
-                if (entryName.startsWith(prefix))
-                    entryName = entryName.substring(prefix.length());
-            }
             return removeExtension(entryName).replace('/', '.');
         }
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java	Fri Aug 22 11:46:29 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java	Tue Aug 26 14:52:59 2008 -0700
@@ -25,11 +25,12 @@
 
 package com.sun.tools.javac.file;
 
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
-import java.text.MessageFormat;
+import java.lang.ref.SoftReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -45,6 +46,9 @@
 import java.util.zip.Inflater;
 import java.util.zip.ZipException;
 
+import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
+import com.sun.tools.javac.file.RelativePath.RelativeFile;
+
 /** This class implements building of index of a zip archive and access to it's context.
  *  It also uses prebuild index if available. It supports invocations where it will
  *  serialize an optimized zip index file to disk.
@@ -75,8 +79,8 @@
 
     private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this.
 
-    private Map<String, DirectoryEntry> directories = Collections.<String, DirectoryEntry>emptyMap();
-    private Set<String> allDirs = Collections.<String>emptySet();
+    private Map<RelativeDirectory, DirectoryEntry> directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
+    private Set<RelativeDirectory> allDirs = Collections.<RelativeDirectory>emptySet();
 
     // ZipFileIndex data entries
     private File zipFile;
@@ -87,7 +91,7 @@
     private boolean readFromIndex = false;
     private File zipIndexFile = null;
     private boolean triedToReadIndex = false;
-    final String symbolFilePrefix;
+    final RelativeDirectory symbolFilePrefix;
     private int symbolFilePrefixLength = 0;
     private boolean hasPopulatedData = false;
     private long lastReferenceTimeStamp = NOT_MODIFIED;
@@ -97,6 +101,9 @@
 
     private boolean writeIndex = false;
 
+    private Map <String, SoftReference<RelativeDirectory>> relativeDirectoryCache =
+            new HashMap<String, SoftReference<RelativeDirectory>>();
+
     /**
      * Returns a list of all ZipFileIndex entries
      *
@@ -143,7 +150,10 @@
         }
     }
 
-    public static ZipFileIndex getZipFileIndex(File zipFile, String symbolFilePrefix, boolean useCache, String cacheLocation, boolean writeIndex) throws IOException {
+    public static ZipFileIndex getZipFileIndex(File zipFile,
+            RelativeDirectory symbolFilePrefix,
+            boolean useCache, String cacheLocation,
+            boolean writeIndex) throws IOException {
         ZipFileIndex zi = null;
         lock.lock();
         try {
@@ -231,12 +241,12 @@
         }
     }
 
-    private ZipFileIndex(File zipFile, String symbolFilePrefix, boolean writeIndex,
+    private ZipFileIndex(File zipFile, RelativeDirectory symbolFilePrefix, boolean writeIndex,
             boolean useCache, String cacheLocation) throws IOException {
         this.zipFile = zipFile;
         this.symbolFilePrefix = symbolFilePrefix;
         this.symbolFilePrefixLength = (symbolFilePrefix == null ? 0 :
-            symbolFilePrefix.getBytes("UTF-8").length);
+            symbolFilePrefix.getPath().getBytes("UTF-8").length);
         this.writeIndex = writeIndex;
         this.usePreindexedCache = useCache;
         this.preindexedCacheLocation = cacheLocation;
@@ -250,7 +260,7 @@
     }
 
     public String toString() {
-        return "ZipFileIndex of file:(" + zipFile + ")";
+        return "ZipFileIndex[" + zipFile + "]";
     }
 
     // Just in case...
@@ -291,8 +301,8 @@
             return;
         }
 
-        directories = Collections.<String, DirectoryEntry>emptyMap();
-        allDirs = Collections.<String>emptySet();
+        directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
+        allDirs = Collections.<RelativeDirectory>emptySet();
 
         try {
             openFile();
@@ -317,9 +327,9 @@
     private void cleanupState() {
         // Make sure there is a valid but empty index if the file doesn't exist
         entries = Entry.EMPTY_ARRAY;
-        directories = Collections.<String, DirectoryEntry>emptyMap();
+        directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
         zipFileLastModified = NOT_MODIFIED;
-        allDirs = Collections.<String>emptySet();
+        allDirs = Collections.<RelativeDirectory>emptySet();
     }
 
     public void close() {
@@ -346,24 +356,12 @@
     /**
      * Returns the ZipFileIndexEntry for an absolute path, if there is one.
      */
-    Entry getZipIndexEntry(String path) {
-        if (File.separatorChar != '/') {
-            path = path.replace('/', File.separatorChar);
-        }
+    Entry getZipIndexEntry(RelativePath path) {
         lock.lock();
         try {
             checkIndex();
-            String lookFor = "";
-            int lastSepIndex = path.lastIndexOf(File.separatorChar);
-            boolean noSeparator = false;
-            if (lastSepIndex == -1) {
-                noSeparator = true;
-            }
-
-            DirectoryEntry de = directories.get(noSeparator ? "" : path.substring(0, lastSepIndex));
-
-            lookFor = path.substring(noSeparator ? 0 : lastSepIndex + 1);
-
+            DirectoryEntry de = directories.get(path.dirname());
+            String lookFor = path.basename();
             return de == null ? null : de.getEntry(lookFor);
         }
         catch (IOException e) {
@@ -377,11 +375,7 @@
     /**
      * Returns a javac List of filenames within an absolute path in the ZipFileIndex.
      */
-    public com.sun.tools.javac.util.List<String> getFiles(String path) {
-        if (File.separatorChar != '/') {
-            path = path.replace('/', File.separatorChar);
-        }
-
+    public com.sun.tools.javac.util.List<String> getFiles(RelativeDirectory path) {
         lock.lock();
         try {
             checkIndex();
@@ -402,16 +396,10 @@
         }
     }
 
-    public List<String> getAllDirectories(String path) {
-
-        if (File.separatorChar != '/') {
-            path = path.replace('/', File.separatorChar);
-        }
-
+    public List<String> getDirectories(RelativeDirectory path) {
         lock.lock();
         try {
             checkIndex();
-            path = path.intern();
 
             DirectoryEntry de = directories.get(path);
             com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories();
@@ -430,24 +418,18 @@
         }
     }
 
-    public Set<String> getAllDirectories() {
+    public Set<RelativeDirectory> getAllDirectories() {
         lock.lock();
         try {
             checkIndex();
             if (allDirs == Collections.EMPTY_SET) {
-                Set<String> alldirs = new HashSet<String>();
-                Iterator<String> dirsIter = directories.keySet().iterator();
-                while (dirsIter.hasNext()) {
-                    alldirs.add(new String(dirsIter.next()));
-                }
-
-                allDirs = alldirs;
+                allDirs = new HashSet<RelativeDirectory>(directories.keySet());
             }
 
             return allDirs;
         }
         catch (IOException e) {
-            return Collections.<String>emptySet();
+            return Collections.<RelativeDirectory>emptySet();
         }
         finally {
             lock.unlock();
@@ -461,7 +443,7 @@
      * @param path A path within the zip.
      * @return True if the path is a file or dir, false otherwise.
      */
-    public boolean contains(String path) {
+    public boolean contains(RelativePath path) {
         lock.lock();
         try {
             checkIndex();
@@ -475,17 +457,15 @@
         }
     }
 
-    public boolean isDirectory(String path) throws IOException {
+    public boolean isDirectory(RelativePath path) throws IOException {
         lock.lock();
         try {
             // The top level in a zip file is always a directory.
-            if (path.length() == 0) {
+            if (path.getPath().length() == 0) {
                 lastReferenceTimeStamp = System.currentTimeMillis();
                 return true;
             }
 
-            if (File.separatorChar != '/')
-                path = path.replace('/', File.separatorChar);
             checkIndex();
             return directories.get(path) != null;
         }
@@ -494,7 +474,7 @@
         }
     }
 
-    public long getLastModified(String path) throws IOException {
+    public long getLastModified(RelativeFile path) throws IOException {
         lock.lock();
         try {
             Entry entry = getZipIndexEntry(path);
@@ -507,7 +487,7 @@
         }
     }
 
-    public int length(String path) throws IOException {
+    public int length(RelativeFile path) throws IOException {
         lock.lock();
         try {
             Entry entry = getZipIndexEntry(path);
@@ -531,12 +511,12 @@
         }
     }
 
-    public byte[] read(String path) throws IOException {
+    public byte[] read(RelativeFile path) throws IOException {
         lock.lock();
         try {
             Entry entry = getZipIndexEntry(path);
             if (entry == null)
-                throw new FileNotFoundException(MessageFormat.format("Path not found in ZIP: {0}", path));
+                throw new FileNotFoundException("Path not found in ZIP: " + path.path);
             return read(entry);
         }
         finally {
@@ -557,7 +537,7 @@
         }
     }
 
-    public int read(String path, byte[] buffer) throws IOException {
+    public int read(RelativeFile path, byte[] buffer) throws IOException {
         lock.lock();
         try {
             Entry entry = getZipIndexEntry(path);
@@ -690,7 +670,7 @@
      * ----------------------------------------------------------------------------*/
 
     private class ZipDirectory {
-        private String lastDir;
+        private RelativeDirectory lastDir;
         private int lastStart;
         private int lastLen;
 
@@ -747,13 +727,13 @@
             }
             throw new ZipException("cannot read zip file");
         }
+
         private void buildIndex() throws IOException {
             int entryCount = get2ByteLittleEndian(zipDir, 0);
 
-            entries = new Entry[entryCount];
             // Add each of the files
             if (entryCount > 0) {
-                directories = new HashMap<String, DirectoryEntry>();
+                directories = new HashMap<RelativeDirectory, DirectoryEntry>();
                 ArrayList<Entry> entryList = new ArrayList<Entry>();
                 int pos = 2;
                 for (int i = 0; i < entryCount; i++) {
@@ -761,9 +741,11 @@
                 }
 
                 // Add the accumulated dirs into the same list
-                Iterator i = directories.keySet().iterator();
-                while (i.hasNext()) {
-                    Entry zipFileIndexEntry = new Entry( (String) i.next());
+                for (RelativeDirectory d: directories.keySet()) {
+                    // use shared RelativeDirectory objects for parent dirs
+                    RelativeDirectory parent = getRelativeDirectory(d.dirname().getPath());
+                    String file = d.basename();
+                    Entry zipFileIndexEntry = new Entry(parent, file);
                     zipFileIndexEntry.isDir = true;
                     entryList.add(zipFileIndexEntry);
                 }
@@ -776,7 +758,7 @@
         }
 
         private int readEntry(int pos, List<Entry> entryList,
-                Map<String, DirectoryEntry> directories) throws IOException {
+                Map<RelativeDirectory, DirectoryEntry> directories) throws IOException {
             if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) {
                 throw new ZipException("cannot read zip file entry");
             }
@@ -790,19 +772,20 @@
                 dirStart += zipFileIndex.symbolFilePrefixLength;
                fileStart += zipFileIndex.symbolFilePrefixLength;
             }
-
-            // Use the OS's path separator. Keep the position of the last one.
+            // Force any '\' to '/'. Keep the position of the last separator.
             for (int index = fileStart; index < fileEnd; index++) {
                 byte nextByte = zipDir[index];
-                if (nextByte == (byte)'\\' || nextByte == (byte)'/') {
-                    zipDir[index] = (byte)File.separatorChar;
+                if (nextByte == (byte)'\\') {
+                    zipDir[index] = (byte)'/';
+                    fileStart = index + 1;
+                } else if (nextByte == (byte)'/') {
                     fileStart = index + 1;
                 }
             }
 
-            String directory = null;
+            RelativeDirectory directory = null;
             if (fileStart == dirStart)
-                directory = "";
+                directory = getRelativeDirectory("");
             else if (lastDir != null && lastLen == fileStart - dirStart - 1) {
                 int index = lastLen - 1;
                 while (zipDir[lastStart + index] == zipDir[dirStart + index]) {
@@ -819,22 +802,23 @@
                 lastStart = dirStart;
                 lastLen = fileStart - dirStart - 1;
 
-                directory = new String(zipDir, dirStart, lastLen, "UTF-8").intern();
+                directory = getRelativeDirectory(new String(zipDir, dirStart, lastLen, "UTF-8"));
                 lastDir = directory;
 
                 // Enter also all the parent directories
-                String tempDirectory = directory;
+                RelativeDirectory tempDirectory = directory;
 
                 while (directories.get(tempDirectory) == null) {
                     directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex));
-                    int separator = tempDirectory.lastIndexOf(File.separatorChar);
-                    if (separator == -1)
+                    if (tempDirectory.path.indexOf("/") == tempDirectory.path.length() - 1)
                         break;
-                    tempDirectory = tempDirectory.substring(0, separator);
+                    else {
+                        // use shared RelativeDirectory objects for parent dirs
+                        tempDirectory = getRelativeDirectory(tempDirectory.dirname().getPath());
+                    }
                 }
             }
             else {
-                directory = directory.intern();
                 if (directories.get(directory) == null) {
                     directories.put(directory, new DirectoryEntry(directory, zipFileIndex));
                 }
@@ -886,7 +870,7 @@
 
         private long writtenOffsetOffset = 0;
 
-        private String dirName;
+        private RelativeDirectory dirName;
 
         private com.sun.tools.javac.util.List<String> zipFileEntriesFiles = com.sun.tools.javac.util.List.<String>nil();
         private com.sun.tools.javac.util.List<String> zipFileEntriesDirectories = com.sun.tools.javac.util.List.<String>nil();
@@ -898,70 +882,50 @@
 
         private int numEntries;
 
-        DirectoryEntry(String dirName, ZipFileIndex index) {
-        filesInited = false;
+        DirectoryEntry(RelativeDirectory dirName, ZipFileIndex index) {
+            filesInited = false;
             directoriesInited = false;
             entriesInited = false;
 
-            if (File.separatorChar == '/') {
-                dirName.replace('\\', '/');
-            }
-            else {
-                dirName.replace('/', '\\');
-            }
-
-            this.dirName = dirName.intern();
+            this.dirName = dirName;
             this.zipFileIndex = index;
         }
 
         private com.sun.tools.javac.util.List<String> getFiles() {
-            if (filesInited) {
-                return zipFileEntriesFiles;
+            if (!filesInited) {
+                initEntries();
+                for (Entry e : entries) {
+                    if (!e.isDir) {
+                        zipFileEntriesFiles = zipFileEntriesFiles.append(e.name);
+                    }
+                }
+                filesInited = true;
             }
-
-            initEntries();
-
-            for (Entry e : entries) {
-                if (!e.isDir) {
-                    zipFileEntriesFiles = zipFileEntriesFiles.append(e.name);
-                }
-            }
-            filesInited = true;
             return zipFileEntriesFiles;
         }
 
         private com.sun.tools.javac.util.List<String> getDirectories() {
-            if (directoriesInited) {
-                return zipFileEntriesFiles;
+            if (!directoriesInited) {
+                initEntries();
+                for (Entry e : entries) {
+                    if (e.isDir) {
+                        zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name);
+                    }
+                }
+                directoriesInited = true;
             }
-
-            initEntries();
-
-            for (Entry e : entries) {
-                if (e.isDir) {
-                    zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name);
-                }
-            }
-
-            directoriesInited = true;
-
             return zipFileEntriesDirectories;
         }
 
         private com.sun.tools.javac.util.List<Entry> getEntries() {
-            if (zipFileEntriesInited) {
-                return zipFileEntries;
+            if (!zipFileEntriesInited) {
+                initEntries();
+                zipFileEntries = com.sun.tools.javac.util.List.nil();
+                for (Entry zfie : entries) {
+                    zipFileEntries = zipFileEntries.append(zfie);
+                }
+                zipFileEntriesInited = true;
             }
-
-            initEntries();
-
-            zipFileEntries = com.sun.tools.javac.util.List.nil();
-            for (Entry zfie : entries) {
-                zipFileEntries = zipFileEntries.append(zfie);
-            }
-
-            zipFileEntriesInited = true;
-
             return zipFileEntries;
         }
 
@@ -986,8 +950,6 @@
                 int to = -Arrays.binarySearch(zipFileIndex.entries,
                         new Entry(dirName, MAX_CHAR)) - 1;
 
-                boolean emptyList = false;
-
                 for (int i = from; i < to; i++) {
                     entries.add(zipFileIndex.entries[i]);
                 }
@@ -1071,14 +1033,14 @@
                 if (zipFile.lastModified() != fileStamp) {
                     ret = false;
                 } else {
-                    directories = new HashMap<String, DirectoryEntry>();
+                    directories = new HashMap<RelativeDirectory, DirectoryEntry>();
                     int numDirs = raf.readInt();
                     for (int nDirs = 0; nDirs < numDirs; nDirs++) {
                         int dirNameBytesLen = raf.readInt();
                         byte [] dirNameBytes = new byte[dirNameBytesLen];
                         raf.read(dirNameBytes);
 
-                        String dirNameStr = new String(dirNameBytes, "UTF-8");
+                        RelativeDirectory dirNameStr = getRelativeDirectory(new String(dirNameBytes, "UTF-8"));
                         DirectoryEntry de = new DirectoryEntry(dirNameStr, this);
                         de.numEntries = raf.readInt();
                         de.writtenOffsetOffset = raf.readLong();
@@ -1132,21 +1094,18 @@
             raf.writeLong(zipFileLastModified);
             writtenSoFar += 8;
 
-
-            Iterator<String> iterDirName = directories.keySet().iterator();
             List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>();
-            Map<String, Long> offsets = new HashMap<String, Long>();
+            Map<RelativeDirectory, Long> offsets = new HashMap<RelativeDirectory, Long>();
             raf.writeInt(directories.keySet().size());
             writtenSoFar += 4;
 
-            while(iterDirName.hasNext()) {
-                String dirName = iterDirName.next();
+            for (RelativeDirectory dirName: directories.keySet()) {
                 DirectoryEntry dirEntry = directories.get(dirName);
 
                 directoriesToWrite.add(dirEntry);
 
                 // Write the dir name bytes
-                byte [] dirNameBytes = dirName.getBytes("UTF-8");
+                byte [] dirNameBytes = dirName.getPath().getBytes("UTF-8");
                 int dirNameBytesLen = dirNameBytes.length;
                 raf.writeInt(dirNameBytesLen);
                 writtenSoFar += 4;
@@ -1251,12 +1210,24 @@
         return zipFile;
     }
 
+    private RelativeDirectory getRelativeDirectory(String path) {
+        RelativeDirectory rd;
+        SoftReference<RelativeDirectory> ref = relativeDirectoryCache.get(path);
+        if (ref != null) {
+            rd = ref.get();
+            if (rd != null)
+                return rd;
+        }
+        rd = new RelativeDirectory(path);
+        relativeDirectoryCache.put(path, new SoftReference<RelativeDirectory>(rd));
+        return rd;
+    }
 
     static class Entry implements Comparable<Entry> {
         public static final Entry[] EMPTY_ARRAY = {};
 
         // Directory related
-        String dir;
+        RelativeDirectory dir;
         boolean isDir;
 
         // File related
@@ -1269,32 +1240,17 @@
 
         private int nativetime;
 
-        public Entry(String path) {
-            int separator = path.lastIndexOf(File.separatorChar);
-            if (separator == -1) {
-                dir = "".intern();
-                name = path;
-            } else {
-                dir = path.substring(0, separator).intern();
-                name = path.substring(separator + 1);
-            }
+        public Entry(RelativePath path) {
+            this(path.dirname(), path.basename());
         }
 
-        public Entry(String directory, String name) {
-            this.dir = directory.intern();
+        public Entry(RelativeDirectory directory, String name) {
+            this.dir = directory;
             this.name = name;
         }
 
         public String getName() {
-            if (dir == null || dir.length() == 0) {
-                return name;
-            }
-
-            StringBuilder sb = new StringBuilder();
-            sb.append(dir);
-            sb.append(File.separatorChar);
-            sb.append(name);
-            return sb.toString();
+            return new RelativeFile(dir, name).getPath();
         }
 
         public String getFileName() {
@@ -1331,7 +1287,7 @@
         }
 
         public int compareTo(Entry other) {
-            String otherD = other.dir;
+            RelativeDirectory otherD = other.dir;
             if (dir != otherD) {
                 int c = dir.compareTo(otherD);
                 if (c != 0)
@@ -1340,6 +1296,22 @@
             return name.compareTo(other.name);
         }
 
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof Entry))
+                return false;
+            Entry other = (Entry) o;
+            return dir.equals(other.dir) && name.equals(other.name);
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 7;
+            hash = 97 * hash + (this.dir != null ? this.dir.hashCode() : 0);
+            hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0);
+            return hash;
+        }
+
 
         public String toString() {
             return isDir ? ("Dir:" + dir + " : " + name) :
--- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java	Fri Aug 22 11:46:29 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java	Tue Aug 26 14:52:59 2008 -0700
@@ -29,11 +29,8 @@
 import java.util.Set;
 import javax.tools.JavaFileObject;
 
-import com.sun.tools.javac.file.JavacFileManager.Archive;
-import com.sun.tools.javac.util.List;
 import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Writer;
@@ -42,6 +39,11 @@
 import java.nio.CharBuffer;
 import java.nio.charset.CharsetDecoder;
 
+import com.sun.tools.javac.file.JavacFileManager.Archive;
+import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
+import com.sun.tools.javac.file.RelativePath.RelativeFile;
+import com.sun.tools.javac.util.List;
+
 public class ZipFileIndexArchive implements Archive {
 
     private final ZipFileIndex zfIndex;
@@ -53,22 +55,22 @@
         this.zfIndex = zdir;
     }
 
-    public boolean contains(String name) {
+    public boolean contains(RelativePath name) {
         return zfIndex.contains(name);
     }
 
-    public List<String> getFiles(String subdirectory) {
-        return zfIndex.getFiles((subdirectory.endsWith("/") || subdirectory.endsWith("\\")) ? subdirectory.substring(0, subdirectory.length() - 1) : subdirectory);
+    public List<String> getFiles(RelativeDirectory subdirectory) {
+        return zfIndex.getFiles(subdirectory);
     }
 
-    public JavaFileObject getFileObject(String subdirectory, String file) {
-        String fullZipFileName = subdirectory + file;
+    public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
+        RelativeFile fullZipFileName = new RelativeFile(subdirectory, file);
         ZipFileIndex.Entry entry = zfIndex.getZipIndexEntry(fullZipFileName);
         JavaFileObject ret = new ZipFileIndexFileObject(fileManager, zfIndex, entry, zfIndex.getZipFile().getPath());
         return ret;
     }
 
-    public Set<String> getSubdirectories() {
+    public Set<RelativeDirectory> getSubdirectories() {
         return zfIndex.getAllDirectories();
     }
 
@@ -76,6 +78,10 @@
         zfIndex.close();
     }
 
+    public String toString() {
+        return "ZipFileIndexArchive[" + zfIndex + "]";
+    }
+
     /**
      * A subclass of JavaFileObject representing zip entries using the com.sun.tools.javac.file.ZipFileIndex implementation.
      */
@@ -181,18 +187,11 @@
         public URI toUri() {
             String zipName = new File(getZipName()).toURI().normalize().getPath();
             String entryName = getZipEntryName();
-            if (File.separatorChar != '/') {
-                entryName = entryName.replace(File.separatorChar, '/');
-            }
             return URI.create("jar:" + zipName + "!" + entryName);
         }
 
         private byte[] read() throws IOException {
-            if (entry == null) {
-                entry = zfIndex.getZipIndexEntry(name);
-                if (entry == null)
-                  throw new FileNotFoundException();
-            }
+            assert entry != null; // see constructor
             return zfIndex.read(entry);
         }
 
@@ -222,11 +221,11 @@
         protected String inferBinaryName(Iterable<? extends File> path) {
             String entryName = getZipEntryName();
             if (zfIndex.symbolFilePrefix != null) {
-                String prefix = zfIndex.symbolFilePrefix;
+                String prefix = zfIndex.symbolFilePrefix.path;
                 if (entryName.startsWith(prefix))
                     entryName = entryName.substring(prefix.length());
             }
-            return removeExtension(entryName).replace(File.separatorChar, '.');
+            return removeExtension(entryName).replace('/', '.');
         }
     }
 
--- a/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java	Fri Aug 22 11:46:29 2008 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java	Tue Aug 26 14:52:59 2008 -0700
@@ -82,6 +82,7 @@
         cpString = appendPath(System.getProperty("java.class.path"), cpString);
         cpString = appendPath(docletPath, cpString);
         URL[] urls = pathToURLs(cpString);
+        System.err.println("DocletInvoker urls=" + urls);
         appClassLoader = new URLClassLoader(urls);
 
         // attempt to find doclet
--- a/langtools/src/share/classes/javax/tools/StandardLocation.java	Fri Aug 22 11:46:29 2008 +0100
+++ b/langtools/src/share/classes/javax/tools/StandardLocation.java	Tue Aug 26 14:52:59 2008 -0700
@@ -27,8 +27,6 @@
 
 import javax.tools.JavaFileManager.Location;
 
-import java.io.File;
-import java.util.*;
 import java.util.concurrent.*;
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6508981/TestInferBinaryName.java	Tue Aug 26 14:52:59 2008 -0700
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6508981
+ * @summary cleanup file separator handling in JavacFileManager
+ * (This test is specifically to test the new impl of inferBinaryName)
+ * @build p.A
+ * @run main TestInferBinaryName
+ */
+
+import java.io.*;
+import java.util.*;
+import javax.tools.*;
+
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Options;
+
+import static javax.tools.JavaFileObject.Kind.*;
+import static javax.tools.StandardLocation.*;
+
+
+/**
+ * Verify the various implementations of inferBinaryName, but configuring
+ * different instances of a file manager, getting a file object, and checking
+ * the impl of inferBinaryName for that file object.
+ */
+public class TestInferBinaryName {
+    static final boolean IGNORE_SYMBOL_FILE = false;
+    static final boolean USE_SYMBOL_FILE = true;
+    static final boolean DONT_USE_ZIP_FILE_INDEX = false;
+    static final boolean USE_ZIP_FILE_INDEX = true;
+
+    public static void main(String... args) throws Exception {
+        new TestInferBinaryName().run();
+    }
+
+    void run() throws Exception {
+        //System.err.println(System.getProperties());
+        testDirectory();
+        testSymbolArchive();
+        testZipArchive();
+        testZipFileIndexArchive();
+        testZipFileIndexArchive2();
+        if (errors > 0)
+            throw new Exception(errors + " error found");
+    }
+
+    void testDirectory() throws IOException {
+        String testClassName = "p.A";
+        JavaFileManager fm =
+            getFileManager("test.classes", USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
+        test("testDirectory",
+             fm, testClassName, "com.sun.tools.javac.file.RegularFileObject");
+    }
+
+    void testSymbolArchive() throws IOException {
+        String testClassName = "java.lang.String";
+        JavaFileManager fm =
+            getFileManager("sun.boot.class.path", USE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX);
+        test("testSymbolArchive",
+             fm, testClassName, "com.sun.tools.javac.file.SymbolArchive$SymbolFileObject");
+    }
+
+    void testZipArchive() throws IOException {
+        String testClassName = "java.lang.String";
+        JavaFileManager fm =
+            getFileManager("sun.boot.class.path", IGNORE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX);
+        test("testZipArchive",
+             fm, testClassName, "com.sun.tools.javac.file.ZipArchive$ZipFileObject");
+    }
+
+    void testZipFileIndexArchive() throws IOException {
+        String testClassName = "java.lang.String";
+        JavaFileManager fm =
+            getFileManager("sun.boot.class.path", USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
+        test("testZipFileIndexArchive",
+             fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
+    }
+
+    void testZipFileIndexArchive2() throws IOException {
+        String testClassName = "java.lang.String";
+        JavaFileManager fm =
+            getFileManager("sun.boot.class.path", IGNORE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
+        test("testZipFileIndexArchive2",
+             fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
+    }
+
+    /**
+     * @param testName for debugging
+     * @param fm suitably configured file manager
+     * @param testClassName the classname to test
+     * @param implClassName the expected classname of the JavaFileObject impl,
+     *     used for checking that we are checking the expected impl of
+     *     inferBinaryName
+     */
+    void test(String testName,
+              JavaFileManager fm, String testClassName, String implClassName) throws IOException {
+        JavaFileObject fo = fm.getJavaFileForInput(CLASS_PATH, testClassName, CLASS);
+        if (fo == null) {
+            System.err.println("Can't find " + testClassName);
+            errors++;
+            return;
+        }
+
+        String cn = fo.getClass().getName();
+        String bn = fm.inferBinaryName(CLASS_PATH, fo);
+        System.err.println(testName + " " + cn + " " + bn);
+        check(cn, implClassName);
+        check(bn, testClassName);
+        System.err.println("OK");
+    }
+
+    JavaFileManager getFileManager(String classpathProperty,
+                                   boolean symFileKind,
+                                   boolean zipFileIndexKind)
+            throws IOException {
+        Context ctx = new Context();
+        // uugh, ugly back door, should be cleaned up, someday
+        if (zipFileIndexKind == USE_ZIP_FILE_INDEX)
+            System.clearProperty("useJavaUtilZip");
+        else
+            System.setProperty("useJavaUtilZip", "true");
+        Options options = Options.instance(ctx);
+        if (symFileKind == IGNORE_SYMBOL_FILE)
+            options.put("ignore.symbol.file", "true");
+        JavacFileManager fm = new JavacFileManager(ctx, false, null);
+        List<File> path = getPath(System.getProperty(classpathProperty));
+        fm.setLocation(CLASS_PATH, path);
+        return fm;
+    }
+
+    List<File> getPath(String s) {
+        List<File> path = new ArrayList<File>();
+        for (String f: s.split(File.pathSeparator)) {
+            if (f.length() > 0)
+                path.add(new File(f));
+        }
+        //System.err.println("path: " + path);
+        return path;
+    }
+
+    void check(String found, String expect) {
+        if (!found.equals(expect)) {
+            System.err.println("Expected: " + expect);
+            System.err.println("   Found: " + found);
+            errors++;
+        }
+    }
+
+    private int errors;
+}
+
+class A { }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6508981/p/A.java	Tue Aug 26 14:52:59 2008 -0700
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package p;
+class A { }
--- a/langtools/test/tools/javac/T6725036.java	Fri Aug 22 11:46:29 2008 +0100
+++ b/langtools/test/tools/javac/T6725036.java	Tue Aug 26 14:52:59 2008 -0700
@@ -35,6 +35,7 @@
 import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.file.RelativePath.RelativeFile;
 import com.sun.tools.javac.file.ZipFileIndex;
 import com.sun.tools.javac.file.ZipFileIndexArchive;
 import com.sun.tools.javac.util.Context;
@@ -45,7 +46,7 @@
     }
 
     void run() throws Exception {
-        String TEST_ENTRY_NAME = "java/lang/String.class";
+        RelativeFile TEST_ENTRY_NAME = new RelativeFile("java/lang/String.class");
 
         File f = new File(System.getProperty("java.home"));
         if (!f.getName().equals("jre"))
@@ -53,22 +54,21 @@
         File rt_jar = new File(new File(f, "lib"), "rt.jar");
 
         JarFile j = new JarFile(rt_jar);
-        JarEntry je = j.getJarEntry(TEST_ENTRY_NAME);
+        JarEntry je = j.getJarEntry(TEST_ENTRY_NAME.getPath());
         long jarEntryTime = je.getTime();
 
         ZipFileIndex zfi =
                 ZipFileIndex.getZipFileIndex(rt_jar, null, false, null, false);
         long zfiTime = zfi.getLastModified(TEST_ENTRY_NAME);
 
-        check(je, jarEntryTime, zfi + ":" + TEST_ENTRY_NAME, zfiTime);
+        check(je, jarEntryTime, zfi + ":" + TEST_ENTRY_NAME.getPath(), zfiTime);
 
         Context context = new Context();
         JavacFileManager fm = new JavacFileManager(context, false, null);
         ZipFileIndexArchive zfia = new ZipFileIndexArchive(fm, zfi);
-        int sep = TEST_ENTRY_NAME.lastIndexOf("/");
         JavaFileObject jfo =
-                zfia.getFileObject(TEST_ENTRY_NAME.substring(0, sep + 1),
-                    TEST_ENTRY_NAME.substring(sep + 1));
+            zfia.getFileObject(TEST_ENTRY_NAME.dirname(),
+                                   TEST_ENTRY_NAME.basename());
         long jfoTime = jfo.getLastModified();
 
         check(je, jarEntryTime, jfo, jfoTime);