6508981: cleanup file separator handling in JavacFileManager

Reviewed-by: mcimadamore
This commit is contained in:
Jonathan Gibbons 2008-08-26 14:52:59 -07:00
parent b9c79ae213
commit fc7983c405
11 changed files with 675 additions and 299 deletions

View File

@ -65,6 +65,8 @@ import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager; import javax.tools.StandardJavaFileManager;
import com.sun.tools.javac.code.Source; 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.JavacOption;
import com.sun.tools.javac.main.OptionName; import com.sun.tools.javac.main.OptionName;
import com.sun.tools.javac.main.RecognizedOptions; import com.sun.tools.javac.main.RecognizedOptions;
@ -75,8 +77,8 @@ import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Options; import com.sun.tools.javac.util.Options;
import static com.sun.tools.javac.main.OptionName.*;
import static javax.tools.StandardLocation.*; import static javax.tools.StandardLocation.*;
import static com.sun.tools.javac.main.OptionName.*;
/** /**
* This class provides access to the source, class and other files * This class provides access to the source, class and other files
@ -84,9 +86,6 @@ import static javax.tools.StandardLocation.*;
*/ */
public class JavacFileManager implements StandardJavaFileManager { 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; boolean useZipFileIndex;
private static boolean CHECK_ZIP_TIMESTAMP = false; private static boolean CHECK_ZIP_TIMESTAMP = false;
@ -267,6 +266,7 @@ public class JavacFileManager implements StandardJavaFileManager {
printAscii("Invalid class name: \"%s\"", name); printAscii("Invalid class name: \"%s\"", name);
} }
} }
private static void printAscii(String format, Object... args) { private static void printAscii(String format, Object... args) {
String message; String message;
try { try {
@ -278,27 +278,12 @@ public class JavacFileManager implements StandardJavaFileManager {
System.out.println(message); 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 * Insert all files in subdirectory `subdirectory' of `directory' which end
* in one of the extensions in `extensions' into packageSym. * in one of the extensions in `extensions' into packageSym.
*/ */
private void listDirectory(File directory, private void listDirectory(File directory,
String subdirectory, RelativeDirectory subdirectory,
Set<JavaFileObject.Kind> fileKinds, Set<JavaFileObject.Kind> fileKinds,
boolean recurse, boolean recurse,
ListBuffer<JavaFileObject> l) { ListBuffer<JavaFileObject> l) {
@ -329,22 +314,6 @@ public class JavacFileManager implements StandardJavaFileManager {
return; 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); List<String> files = archive.getFiles(subdirectory);
if (files != null) { if (files != null) {
@ -356,8 +325,8 @@ public class JavacFileManager implements StandardJavaFileManager {
} }
} }
if (recurse) { if (recurse) {
for (String s: archive.getSubdirectories()) { for (RelativeDirectory s: archive.getSubdirectories()) {
if (s.startsWith(subdirectory) && !s.equals(subdirectory)) { if (subdirectory.contains(s)) {
// Because the archive map is a flat list of directories, // Because the archive map is a flat list of directories,
// the enclosing loop will pick up all child subdirectories. // the enclosing loop will pick up all child subdirectories.
// Therefore, there is no need to recurse deeper. // Therefore, there is no need to recurse deeper.
@ -366,9 +335,7 @@ public class JavacFileManager implements StandardJavaFileManager {
} }
} }
} else { } else {
File d = subdirectory.length() != 0 File d = subdirectory.getFile(directory);
? new File(directory, subdirectory)
: directory;
if (!caseMapCheck(d, subdirectory)) if (!caseMapCheck(d, subdirectory))
return; return;
@ -381,7 +348,7 @@ public class JavacFileManager implements StandardJavaFileManager {
if (f.isDirectory()) { if (f.isDirectory()) {
if (recurse && SourceVersion.isIdentifier(fname)) { if (recurse && SourceVersion.isIdentifier(fname)) {
listDirectory(directory, listDirectory(directory,
subdirectory + File.separator + fname, new RelativeDirectory(subdirectory, fname),
fileKinds, fileKinds,
recurse, recurse,
l); l);
@ -411,7 +378,7 @@ public class JavacFileManager implements StandardJavaFileManager {
* ends in a string of characters with the same case as given name. * ends in a string of characters with the same case as given name.
* Ignore file separators in both path and 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; if (fileSystemIsCaseSensitive) return true;
// Note that getCanonicalPath() returns the case-sensitive // Note that getCanonicalPath() returns the case-sensitive
// spelled file name. // spelled file name.
@ -422,12 +389,12 @@ public class JavacFileManager implements StandardJavaFileManager {
return false; return false;
} }
char[] pcs = path.toCharArray(); char[] pcs = path.toCharArray();
char[] ncs = name.toCharArray(); char[] ncs = name.path.toCharArray();
int i = pcs.length - 1; int i = pcs.length - 1;
int j = ncs.length - 1; int j = ncs.length - 1;
while (i >= 0 && j >= 0) { while (i >= 0 && j >= 0) {
while (i >= 0 && pcs[i] == File.separatorChar) i--; 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 (i >= 0 && j >= 0) {
if (pcs[i] != ncs[j]) return false; if (pcs[i] != ncs[j]) return false;
i--; i--;
@ -444,13 +411,13 @@ public class JavacFileManager implements StandardJavaFileManager {
public interface Archive { public interface Archive {
void close() throws IOException; 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 { public class MissingArchive implements Archive {
@ -458,30 +425,38 @@ public class JavacFileManager implements StandardJavaFileManager {
public MissingArchive(File name) { public MissingArchive(File name) {
zipFileName = name; zipFileName = name;
} }
public boolean contains(String name) { public boolean contains(RelativePath name) {
return false; return false;
} }
public void close() { public void close() {
} }
public JavaFileObject getFileObject(String subdirectory, String file) { public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
return null; return null;
} }
public List<String> getFiles(String subdirectory) { public List<String> getFiles(RelativeDirectory subdirectory) {
return List.nil(); return List.nil();
} }
public Set<String> getSubdirectories() { public Set<RelativeDirectory> getSubdirectories() {
return Collections.emptySet(); return Collections.emptySet();
} }
public String toString() {
return "MissingArchive[" + zipFileName + "]";
}
} }
/** A directory of zip files already opened. /** A directory of zip files already opened.
*/ */
Map<File, Archive> archives = new HashMap<File,Archive>(); 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. /** Open a new zip file directory.
*/ */
protected Archive openArchive(File zipFileName) throws IOException { protected Archive openArchive(File zipFileName) throws IOException {
@ -540,8 +515,12 @@ public class JavacFileManager implements StandardJavaFileManager {
if (!useZipFileIndex) { if (!useZipFileIndex) {
archive = new ZipArchive(this, zdir); archive = new ZipArchive(this, zdir);
} else { } else {
archive = new ZipFileIndexArchive(this, ZipFileIndex.getZipFileIndex(zipFileName, null, archive = new ZipFileIndexArchive(this,
usePreindexedCache, preindexCacheLocation, options.get("writezipindexfiles") != null)); ZipFileIndex.getZipFileIndex(zipFileName,
null,
usePreindexedCache,
preindexCacheLocation,
options.get("writezipindexfiles") != null));
} }
} }
else { else {
@ -551,10 +530,10 @@ public class JavacFileManager implements StandardJavaFileManager {
else { else {
archive = new ZipFileIndexArchive(this, archive = new ZipFileIndexArchive(this,
ZipFileIndex.getZipFileIndex(zipFileName, ZipFileIndex.getZipFileIndex(zipFileName,
symbolFilePrefix, symbolFilePrefix,
usePreindexedCache, usePreindexedCache,
preindexCacheLocation, preindexCacheLocation,
options.get("writezipindexfiles") != null)); options.get("writezipindexfiles") != null));
} }
} }
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
@ -796,7 +775,7 @@ public class JavacFileManager implements StandardJavaFileManager {
Iterable<? extends File> path = getLocation(location); Iterable<? extends File> path = getLocation(location);
if (path == null) if (path == null)
return List.nil(); return List.nil();
String subdirectory = externalizeFileName(packageName); RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>(); ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
for (File directory : path) for (File directory : path)
@ -877,7 +856,7 @@ public class JavacFileManager implements StandardJavaFileManager {
nullCheck(kind); nullCheck(kind);
if (!sourceOrClass.contains(kind)) if (!sourceOrClass.contains(kind))
throw new IllegalArgumentException("Invalid kind " + 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, public FileObject getFileForInput(Location location,
@ -890,35 +869,32 @@ public class JavacFileManager implements StandardJavaFileManager {
nullCheck(packageName); nullCheck(packageName);
if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701 if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701
throw new IllegalArgumentException("Invalid relative name: " + relativeName); throw new IllegalArgumentException("Invalid relative name: " + relativeName);
String name = packageName.length() == 0 RelativeFile name = packageName.length() == 0
? relativeName ? new RelativeFile(relativeName)
: new File(externalizeFileName(packageName), relativeName).getPath(); : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
return getFileForInput(location, name); 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); Iterable<? extends File> path = getLocation(location);
if (path == null) if (path == null)
return null; return null;
for (File dir: path) { for (File dir: path) {
if (dir.isDirectory()) { if (dir.isDirectory()) {
File f = new File(dir, name.replace('/', File.separatorChar)); File f = name.getFile(dir);
if (f.exists()) if (f.exists())
return new RegularFileObject(this, f); return new RegularFileObject(this, f);
} else { } else {
Archive a = openArchive(dir); Archive a = openArchive(dir);
if (a.contains(name)) { if (a.contains(name)) {
int i = name.lastIndexOf('/'); return a.getFileObject(name.dirname(), name.basename());
String dirname = name.substring(0, i+1);
String basename = name.substring(i+1);
return a.getFileObject(dirname, basename);
} }
} }
} }
return null;
return null;
} }
public JavaFileObject getJavaFileForOutput(Location location, public JavaFileObject getJavaFileForOutput(Location location,
@ -933,7 +909,7 @@ public class JavacFileManager implements StandardJavaFileManager {
nullCheck(kind); nullCheck(kind);
if (!sourceOrClass.contains(kind)) if (!sourceOrClass.contains(kind))
throw new IllegalArgumentException("Invalid kind " + 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, public FileObject getFileForOutput(Location location,
@ -947,14 +923,14 @@ public class JavacFileManager implements StandardJavaFileManager {
nullCheck(packageName); nullCheck(packageName);
if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701 if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701
throw new IllegalArgumentException("relativeName is invalid"); throw new IllegalArgumentException("relativeName is invalid");
String name = packageName.length() == 0 RelativeFile name = packageName.length() == 0
? relativeName ? new RelativeFile(relativeName)
: new File(externalizeFileName(packageName), relativeName).getPath(); : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
return getFileForOutput(location, name, sibling); return getFileForOutput(location, name, sibling);
} }
private JavaFileObject getFileForOutput(Location location, private JavaFileObject getFileForOutput(Location location,
String fileName, RelativeFile fileName,
FileObject sibling) FileObject sibling)
throws IOException throws IOException
{ {
@ -967,7 +943,7 @@ public class JavacFileManager implements StandardJavaFileManager {
if (sibling != null && sibling instanceof RegularFileObject) { if (sibling != null && sibling instanceof RegularFileObject) {
siblingDir = ((RegularFileObject)sibling).f.getParentFile(); 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) { } else if (location == SOURCE_OUTPUT) {
dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir()); dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir());
@ -980,7 +956,7 @@ public class JavacFileManager implements StandardJavaFileManager {
} }
} }
File file = (dir == null ? new File(fileName) : new File(dir, fileName)); File file = fileName.getFile(dir); // null-safe
return new RegularFileObject(this, file); return new RegularFileObject(this, file);
} }

View File

@ -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 + "]";
}
}
}

View File

@ -25,47 +25,75 @@
package com.sun.tools.javac.file; package com.sun.tools.javac.file;
import com.sun.tools.javac.util.List;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import javax.tools.JavaFileObject; 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 { public class SymbolArchive extends ZipArchive {
final File origFile; final File origFile;
final String prefix; final RelativeDirectory prefix;
public SymbolArchive(JavacFileManager fileManager, File orig, ZipFile zdir, String prefix) throws IOException { public SymbolArchive(JavacFileManager fileManager, File orig, ZipFile zdir, RelativeDirectory prefix) throws IOException {
super(fileManager, zdir); super(fileManager, zdir, false);
this.origFile = orig; this.origFile = orig;
this.prefix = prefix; this.prefix = prefix;
initMap();
} }
@Override @Override
void addZipEntry(ZipEntry entry) { void addZipEntry(ZipEntry entry) {
String name = entry.getName(); String name = entry.getName();
if (!name.startsWith(prefix)) { if (!name.startsWith(prefix.path)) {
return; return;
} }
name = name.substring(prefix.length()); name = name.substring(prefix.path.length());
int i = name.lastIndexOf('/'); 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); String basename = name.substring(i + 1);
if (basename.length() == 0) { if (basename.length() == 0) {
return; return;
} }
List<String> list = map.get(dirname); List<String> list = map.get(dirname);
if (list == null) { if (list == null)
list = List.nil(); list = List.nil();
}
list = list.prepend(basename); list = list.prepend(basename);
map.put(dirname, list); map.put(dirname, list);
} }
@Override public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
public JavaFileObject getFileObject(String subdirectory, String file) { RelativeDirectory prefix_subdir = new RelativeDirectory(prefix, subdirectory.path);
return super.getFileObject(prefix + subdirectory, file); 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('/', '.');
}
}
} }

View File

@ -25,18 +25,8 @@
package com.sun.tools.javac.file; package com.sun.tools.javac.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.File;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Writer; import java.io.Writer;
@ -44,13 +34,35 @@ import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder; 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 class ZipArchive implements Archive {
public ZipArchive(JavacFileManager fm, ZipFile zdir) throws IOException { 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.fileManager = fm;
this.zdir = zdir; 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(); ) { for (Enumeration<? extends ZipEntry> e = zdir.entries(); e.hasMoreElements(); ) {
ZipEntry entry; ZipEntry entry;
try { try {
@ -67,7 +79,7 @@ public class ZipArchive implements Archive {
void addZipEntry(ZipEntry entry) { void addZipEntry(ZipEntry entry) {
String name = entry.getName(); String name = entry.getName();
int i = name.lastIndexOf('/'); 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); String basename = name.substring(i+1);
if (basename.length() == 0) if (basename.length() == 0)
return; return;
@ -78,26 +90,25 @@ public class ZipArchive implements Archive {
map.put(dirname, list); map.put(dirname, list);
} }
public boolean contains(String name) { public boolean contains(RelativePath name) {
int i = name.lastIndexOf('/'); RelativeDirectory dirname = name.dirname();
String dirname = name.substring(0, i+1); String basename = name.basename();
String basename = name.substring(i+1);
if (basename.length() == 0) if (basename.length() == 0)
return false; return false;
List<String> list = map.get(dirname); List<String> list = map.get(dirname);
return (list != null && list.contains(basename)); return (list != null && list.contains(basename));
} }
public List<String> getFiles(String subdirectory) { public List<String> getFiles(RelativeDirectory subdirectory) {
return map.get(subdirectory); return map.get(subdirectory);
} }
public JavaFileObject getFileObject(String subdirectory, String file) { public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
ZipEntry ze = zdir.getEntry(subdirectory + file); ZipEntry ze = new RelativeFile(subdirectory, file).getZipEntry(zdir);
return new ZipFileObject(this, file, ze); return new ZipFileObject(this, file, ze);
} }
public Set<String> getSubdirectories() { public Set<RelativeDirectory> getSubdirectories() {
return map.keySet(); return map.keySet();
} }
@ -105,8 +116,12 @@ public class ZipArchive implements Archive {
zdir.close(); zdir.close();
} }
public String toString() {
return "ZipArchive[" + zdir.getName() + "]";
}
protected JavacFileManager fileManager; protected JavacFileManager fileManager;
protected final Map<String,List<String>> map; protected final Map<RelativeDirectory,List<String>> map;
protected final ZipFile zdir; protected final ZipFile zdir;
/** /**
@ -118,7 +133,7 @@ public class ZipArchive implements Archive {
ZipArchive zarch; ZipArchive zarch;
ZipEntry entry; ZipEntry entry;
public ZipFileObject(ZipArchive zarch, String name, ZipEntry entry) { protected ZipFileObject(ZipArchive zarch, String name, ZipEntry entry) {
super(zarch.fileManager); super(zarch.fileManager);
this.zarch = zarch; this.zarch = zarch;
this.name = name; this.name = name;
@ -222,11 +237,6 @@ public class ZipArchive implements Archive {
@Override @Override
protected String inferBinaryName(Iterable<? extends File> path) { protected String inferBinaryName(Iterable<? extends File> path) {
String entryName = getZipEntryName(); 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('/', '.'); return removeExtension(entryName).replace('/', '.');
} }
} }

View File

@ -25,11 +25,12 @@
package com.sun.tools.javac.file; package com.sun.tools.javac.file;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.text.MessageFormat; import java.lang.ref.SoftReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
@ -45,6 +46,9 @@ import java.util.zip.DataFormatException;
import java.util.zip.Inflater; import java.util.zip.Inflater;
import java.util.zip.ZipException; 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. /** 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 * It also uses prebuild index if available. It supports invocations where it will
* serialize an optimized zip index file to disk. * serialize an optimized zip index file to disk.
@ -75,8 +79,8 @@ public class ZipFileIndex {
private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this. 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 Map<RelativeDirectory, DirectoryEntry> directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
private Set<String> allDirs = Collections.<String>emptySet(); private Set<RelativeDirectory> allDirs = Collections.<RelativeDirectory>emptySet();
// ZipFileIndex data entries // ZipFileIndex data entries
private File zipFile; private File zipFile;
@ -87,7 +91,7 @@ public class ZipFileIndex {
private boolean readFromIndex = false; private boolean readFromIndex = false;
private File zipIndexFile = null; private File zipIndexFile = null;
private boolean triedToReadIndex = false; private boolean triedToReadIndex = false;
final String symbolFilePrefix; final RelativeDirectory symbolFilePrefix;
private int symbolFilePrefixLength = 0; private int symbolFilePrefixLength = 0;
private boolean hasPopulatedData = false; private boolean hasPopulatedData = false;
private long lastReferenceTimeStamp = NOT_MODIFIED; private long lastReferenceTimeStamp = NOT_MODIFIED;
@ -97,6 +101,9 @@ public class ZipFileIndex {
private boolean writeIndex = false; private boolean writeIndex = false;
private Map <String, SoftReference<RelativeDirectory>> relativeDirectoryCache =
new HashMap<String, SoftReference<RelativeDirectory>>();
/** /**
* Returns a list of all ZipFileIndex entries * Returns a list of all ZipFileIndex entries
* *
@ -143,7 +150,10 @@ public class ZipFileIndex {
} }
} }
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; ZipFileIndex zi = null;
lock.lock(); lock.lock();
try { try {
@ -231,12 +241,12 @@ public class ZipFileIndex {
} }
} }
private ZipFileIndex(File zipFile, String symbolFilePrefix, boolean writeIndex, private ZipFileIndex(File zipFile, RelativeDirectory symbolFilePrefix, boolean writeIndex,
boolean useCache, String cacheLocation) throws IOException { boolean useCache, String cacheLocation) throws IOException {
this.zipFile = zipFile; this.zipFile = zipFile;
this.symbolFilePrefix = symbolFilePrefix; this.symbolFilePrefix = symbolFilePrefix;
this.symbolFilePrefixLength = (symbolFilePrefix == null ? 0 : this.symbolFilePrefixLength = (symbolFilePrefix == null ? 0 :
symbolFilePrefix.getBytes("UTF-8").length); symbolFilePrefix.getPath().getBytes("UTF-8").length);
this.writeIndex = writeIndex; this.writeIndex = writeIndex;
this.usePreindexedCache = useCache; this.usePreindexedCache = useCache;
this.preindexedCacheLocation = cacheLocation; this.preindexedCacheLocation = cacheLocation;
@ -250,7 +260,7 @@ public class ZipFileIndex {
} }
public String toString() { public String toString() {
return "ZipFileIndex of file:(" + zipFile + ")"; return "ZipFileIndex[" + zipFile + "]";
} }
// Just in case... // Just in case...
@ -291,8 +301,8 @@ public class ZipFileIndex {
return; return;
} }
directories = Collections.<String, DirectoryEntry>emptyMap(); directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
allDirs = Collections.<String>emptySet(); allDirs = Collections.<RelativeDirectory>emptySet();
try { try {
openFile(); openFile();
@ -317,9 +327,9 @@ public class ZipFileIndex {
private void cleanupState() { private void cleanupState() {
// Make sure there is a valid but empty index if the file doesn't exist // Make sure there is a valid but empty index if the file doesn't exist
entries = Entry.EMPTY_ARRAY; entries = Entry.EMPTY_ARRAY;
directories = Collections.<String, DirectoryEntry>emptyMap(); directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
zipFileLastModified = NOT_MODIFIED; zipFileLastModified = NOT_MODIFIED;
allDirs = Collections.<String>emptySet(); allDirs = Collections.<RelativeDirectory>emptySet();
} }
public void close() { public void close() {
@ -346,24 +356,12 @@ public class ZipFileIndex {
/** /**
* Returns the ZipFileIndexEntry for an absolute path, if there is one. * Returns the ZipFileIndexEntry for an absolute path, if there is one.
*/ */
Entry getZipIndexEntry(String path) { Entry getZipIndexEntry(RelativePath path) {
if (File.separatorChar != '/') {
path = path.replace('/', File.separatorChar);
}
lock.lock(); lock.lock();
try { try {
checkIndex(); checkIndex();
String lookFor = ""; DirectoryEntry de = directories.get(path.dirname());
int lastSepIndex = path.lastIndexOf(File.separatorChar); String lookFor = path.basename();
boolean noSeparator = false;
if (lastSepIndex == -1) {
noSeparator = true;
}
DirectoryEntry de = directories.get(noSeparator ? "" : path.substring(0, lastSepIndex));
lookFor = path.substring(noSeparator ? 0 : lastSepIndex + 1);
return de == null ? null : de.getEntry(lookFor); return de == null ? null : de.getEntry(lookFor);
} }
catch (IOException e) { catch (IOException e) {
@ -377,11 +375,7 @@ public class ZipFileIndex {
/** /**
* Returns a javac List of filenames within an absolute path in the ZipFileIndex. * Returns a javac List of filenames within an absolute path in the ZipFileIndex.
*/ */
public com.sun.tools.javac.util.List<String> getFiles(String path) { public com.sun.tools.javac.util.List<String> getFiles(RelativeDirectory path) {
if (File.separatorChar != '/') {
path = path.replace('/', File.separatorChar);
}
lock.lock(); lock.lock();
try { try {
checkIndex(); checkIndex();
@ -402,16 +396,10 @@ public class ZipFileIndex {
} }
} }
public List<String> getAllDirectories(String path) { public List<String> getDirectories(RelativeDirectory path) {
if (File.separatorChar != '/') {
path = path.replace('/', File.separatorChar);
}
lock.lock(); lock.lock();
try { try {
checkIndex(); checkIndex();
path = path.intern();
DirectoryEntry de = directories.get(path); DirectoryEntry de = directories.get(path);
com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories(); com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories();
@ -430,24 +418,18 @@ public class ZipFileIndex {
} }
} }
public Set<String> getAllDirectories() { public Set<RelativeDirectory> getAllDirectories() {
lock.lock(); lock.lock();
try { try {
checkIndex(); checkIndex();
if (allDirs == Collections.EMPTY_SET) { if (allDirs == Collections.EMPTY_SET) {
Set<String> alldirs = new HashSet<String>(); allDirs = new HashSet<RelativeDirectory>(directories.keySet());
Iterator<String> dirsIter = directories.keySet().iterator();
while (dirsIter.hasNext()) {
alldirs.add(new String(dirsIter.next()));
}
allDirs = alldirs;
} }
return allDirs; return allDirs;
} }
catch (IOException e) { catch (IOException e) {
return Collections.<String>emptySet(); return Collections.<RelativeDirectory>emptySet();
} }
finally { finally {
lock.unlock(); lock.unlock();
@ -461,7 +443,7 @@ public class ZipFileIndex {
* @param path A path within the zip. * @param path A path within the zip.
* @return True if the path is a file or dir, false otherwise. * @return True if the path is a file or dir, false otherwise.
*/ */
public boolean contains(String path) { public boolean contains(RelativePath path) {
lock.lock(); lock.lock();
try { try {
checkIndex(); checkIndex();
@ -475,17 +457,15 @@ public class ZipFileIndex {
} }
} }
public boolean isDirectory(String path) throws IOException { public boolean isDirectory(RelativePath path) throws IOException {
lock.lock(); lock.lock();
try { try {
// The top level in a zip file is always a directory. // The top level in a zip file is always a directory.
if (path.length() == 0) { if (path.getPath().length() == 0) {
lastReferenceTimeStamp = System.currentTimeMillis(); lastReferenceTimeStamp = System.currentTimeMillis();
return true; return true;
} }
if (File.separatorChar != '/')
path = path.replace('/', File.separatorChar);
checkIndex(); checkIndex();
return directories.get(path) != null; return directories.get(path) != null;
} }
@ -494,7 +474,7 @@ public class ZipFileIndex {
} }
} }
public long getLastModified(String path) throws IOException { public long getLastModified(RelativeFile path) throws IOException {
lock.lock(); lock.lock();
try { try {
Entry entry = getZipIndexEntry(path); Entry entry = getZipIndexEntry(path);
@ -507,7 +487,7 @@ public class ZipFileIndex {
} }
} }
public int length(String path) throws IOException { public int length(RelativeFile path) throws IOException {
lock.lock(); lock.lock();
try { try {
Entry entry = getZipIndexEntry(path); Entry entry = getZipIndexEntry(path);
@ -531,12 +511,12 @@ public class ZipFileIndex {
} }
} }
public byte[] read(String path) throws IOException { public byte[] read(RelativeFile path) throws IOException {
lock.lock(); lock.lock();
try { try {
Entry entry = getZipIndexEntry(path); Entry entry = getZipIndexEntry(path);
if (entry == null) 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); return read(entry);
} }
finally { finally {
@ -557,7 +537,7 @@ public class ZipFileIndex {
} }
} }
public int read(String path, byte[] buffer) throws IOException { public int read(RelativeFile path, byte[] buffer) throws IOException {
lock.lock(); lock.lock();
try { try {
Entry entry = getZipIndexEntry(path); Entry entry = getZipIndexEntry(path);
@ -690,7 +670,7 @@ public class ZipFileIndex {
* ----------------------------------------------------------------------------*/ * ----------------------------------------------------------------------------*/
private class ZipDirectory { private class ZipDirectory {
private String lastDir; private RelativeDirectory lastDir;
private int lastStart; private int lastStart;
private int lastLen; private int lastLen;
@ -747,13 +727,13 @@ public class ZipFileIndex {
} }
throw new ZipException("cannot read zip file"); throw new ZipException("cannot read zip file");
} }
private void buildIndex() throws IOException { private void buildIndex() throws IOException {
int entryCount = get2ByteLittleEndian(zipDir, 0); int entryCount = get2ByteLittleEndian(zipDir, 0);
entries = new Entry[entryCount];
// Add each of the files // Add each of the files
if (entryCount > 0) { if (entryCount > 0) {
directories = new HashMap<String, DirectoryEntry>(); directories = new HashMap<RelativeDirectory, DirectoryEntry>();
ArrayList<Entry> entryList = new ArrayList<Entry>(); ArrayList<Entry> entryList = new ArrayList<Entry>();
int pos = 2; int pos = 2;
for (int i = 0; i < entryCount; i++) { for (int i = 0; i < entryCount; i++) {
@ -761,9 +741,11 @@ public class ZipFileIndex {
} }
// Add the accumulated dirs into the same list // Add the accumulated dirs into the same list
Iterator i = directories.keySet().iterator(); for (RelativeDirectory d: directories.keySet()) {
while (i.hasNext()) { // use shared RelativeDirectory objects for parent dirs
Entry zipFileIndexEntry = new Entry( (String) i.next()); RelativeDirectory parent = getRelativeDirectory(d.dirname().getPath());
String file = d.basename();
Entry zipFileIndexEntry = new Entry(parent, file);
zipFileIndexEntry.isDir = true; zipFileIndexEntry.isDir = true;
entryList.add(zipFileIndexEntry); entryList.add(zipFileIndexEntry);
} }
@ -776,7 +758,7 @@ public class ZipFileIndex {
} }
private int readEntry(int pos, List<Entry> entryList, 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) { if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) {
throw new ZipException("cannot read zip file entry"); throw new ZipException("cannot read zip file entry");
} }
@ -790,19 +772,20 @@ public class ZipFileIndex {
dirStart += zipFileIndex.symbolFilePrefixLength; dirStart += zipFileIndex.symbolFilePrefixLength;
fileStart += zipFileIndex.symbolFilePrefixLength; fileStart += zipFileIndex.symbolFilePrefixLength;
} }
// Force any '\' to '/'. Keep the position of the last separator.
// Use the OS's path separator. Keep the position of the last one.
for (int index = fileStart; index < fileEnd; index++) { for (int index = fileStart; index < fileEnd; index++) {
byte nextByte = zipDir[index]; byte nextByte = zipDir[index];
if (nextByte == (byte)'\\' || nextByte == (byte)'/') { if (nextByte == (byte)'\\') {
zipDir[index] = (byte)File.separatorChar; zipDir[index] = (byte)'/';
fileStart = index + 1;
} else if (nextByte == (byte)'/') {
fileStart = index + 1; fileStart = index + 1;
} }
} }
String directory = null; RelativeDirectory directory = null;
if (fileStart == dirStart) if (fileStart == dirStart)
directory = ""; directory = getRelativeDirectory("");
else if (lastDir != null && lastLen == fileStart - dirStart - 1) { else if (lastDir != null && lastLen == fileStart - dirStart - 1) {
int index = lastLen - 1; int index = lastLen - 1;
while (zipDir[lastStart + index] == zipDir[dirStart + index]) { while (zipDir[lastStart + index] == zipDir[dirStart + index]) {
@ -819,22 +802,23 @@ public class ZipFileIndex {
lastStart = dirStart; lastStart = dirStart;
lastLen = fileStart - dirStart - 1; lastLen = fileStart - dirStart - 1;
directory = new String(zipDir, dirStart, lastLen, "UTF-8").intern(); directory = getRelativeDirectory(new String(zipDir, dirStart, lastLen, "UTF-8"));
lastDir = directory; lastDir = directory;
// Enter also all the parent directories // Enter also all the parent directories
String tempDirectory = directory; RelativeDirectory tempDirectory = directory;
while (directories.get(tempDirectory) == null) { while (directories.get(tempDirectory) == null) {
directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex)); directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex));
int separator = tempDirectory.lastIndexOf(File.separatorChar); if (tempDirectory.path.indexOf("/") == tempDirectory.path.length() - 1)
if (separator == -1)
break; break;
tempDirectory = tempDirectory.substring(0, separator); else {
// use shared RelativeDirectory objects for parent dirs
tempDirectory = getRelativeDirectory(tempDirectory.dirname().getPath());
}
} }
} }
else { else {
directory = directory.intern();
if (directories.get(directory) == null) { if (directories.get(directory) == null) {
directories.put(directory, new DirectoryEntry(directory, zipFileIndex)); directories.put(directory, new DirectoryEntry(directory, zipFileIndex));
} }
@ -886,7 +870,7 @@ public class ZipFileIndex {
private long writtenOffsetOffset = 0; 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> 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(); private com.sun.tools.javac.util.List<String> zipFileEntriesDirectories = com.sun.tools.javac.util.List.<String>nil();
@ -898,70 +882,50 @@ public class ZipFileIndex {
private int numEntries; private int numEntries;
DirectoryEntry(String dirName, ZipFileIndex index) { DirectoryEntry(RelativeDirectory dirName, ZipFileIndex index) {
filesInited = false; filesInited = false;
directoriesInited = false; directoriesInited = false;
entriesInited = false; entriesInited = false;
if (File.separatorChar == '/') { this.dirName = dirName;
dirName.replace('\\', '/');
}
else {
dirName.replace('/', '\\');
}
this.dirName = dirName.intern();
this.zipFileIndex = index; this.zipFileIndex = index;
} }
private com.sun.tools.javac.util.List<String> getFiles() { private com.sun.tools.javac.util.List<String> getFiles() {
if (filesInited) { if (!filesInited) {
return zipFileEntriesFiles; initEntries();
} for (Entry e : entries) {
if (!e.isDir) {
initEntries(); zipFileEntriesFiles = zipFileEntriesFiles.append(e.name);
}
for (Entry e : entries) {
if (!e.isDir) {
zipFileEntriesFiles = zipFileEntriesFiles.append(e.name);
} }
filesInited = true;
} }
filesInited = true;
return zipFileEntriesFiles; return zipFileEntriesFiles;
} }
private com.sun.tools.javac.util.List<String> getDirectories() { private com.sun.tools.javac.util.List<String> getDirectories() {
if (directoriesInited) { if (!directoriesInited) {
return zipFileEntriesFiles; initEntries();
} for (Entry e : entries) {
if (e.isDir) {
initEntries(); zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name);
}
for (Entry e : entries) {
if (e.isDir) {
zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name);
} }
directoriesInited = true;
} }
directoriesInited = true;
return zipFileEntriesDirectories; return zipFileEntriesDirectories;
} }
private com.sun.tools.javac.util.List<Entry> getEntries() { private com.sun.tools.javac.util.List<Entry> getEntries() {
if (zipFileEntriesInited) { if (!zipFileEntriesInited) {
return zipFileEntries; 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; return zipFileEntries;
} }
@ -986,8 +950,6 @@ public class ZipFileIndex {
int to = -Arrays.binarySearch(zipFileIndex.entries, int to = -Arrays.binarySearch(zipFileIndex.entries,
new Entry(dirName, MAX_CHAR)) - 1; new Entry(dirName, MAX_CHAR)) - 1;
boolean emptyList = false;
for (int i = from; i < to; i++) { for (int i = from; i < to; i++) {
entries.add(zipFileIndex.entries[i]); entries.add(zipFileIndex.entries[i]);
} }
@ -1071,14 +1033,14 @@ public class ZipFileIndex {
if (zipFile.lastModified() != fileStamp) { if (zipFile.lastModified() != fileStamp) {
ret = false; ret = false;
} else { } else {
directories = new HashMap<String, DirectoryEntry>(); directories = new HashMap<RelativeDirectory, DirectoryEntry>();
int numDirs = raf.readInt(); int numDirs = raf.readInt();
for (int nDirs = 0; nDirs < numDirs; nDirs++) { for (int nDirs = 0; nDirs < numDirs; nDirs++) {
int dirNameBytesLen = raf.readInt(); int dirNameBytesLen = raf.readInt();
byte [] dirNameBytes = new byte[dirNameBytesLen]; byte [] dirNameBytes = new byte[dirNameBytesLen];
raf.read(dirNameBytes); raf.read(dirNameBytes);
String dirNameStr = new String(dirNameBytes, "UTF-8"); RelativeDirectory dirNameStr = getRelativeDirectory(new String(dirNameBytes, "UTF-8"));
DirectoryEntry de = new DirectoryEntry(dirNameStr, this); DirectoryEntry de = new DirectoryEntry(dirNameStr, this);
de.numEntries = raf.readInt(); de.numEntries = raf.readInt();
de.writtenOffsetOffset = raf.readLong(); de.writtenOffsetOffset = raf.readLong();
@ -1132,21 +1094,18 @@ public class ZipFileIndex {
raf.writeLong(zipFileLastModified); raf.writeLong(zipFileLastModified);
writtenSoFar += 8; writtenSoFar += 8;
Iterator<String> iterDirName = directories.keySet().iterator();
List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>(); 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()); raf.writeInt(directories.keySet().size());
writtenSoFar += 4; writtenSoFar += 4;
while(iterDirName.hasNext()) { for (RelativeDirectory dirName: directories.keySet()) {
String dirName = iterDirName.next();
DirectoryEntry dirEntry = directories.get(dirName); DirectoryEntry dirEntry = directories.get(dirName);
directoriesToWrite.add(dirEntry); directoriesToWrite.add(dirEntry);
// Write the dir name bytes // Write the dir name bytes
byte [] dirNameBytes = dirName.getBytes("UTF-8"); byte [] dirNameBytes = dirName.getPath().getBytes("UTF-8");
int dirNameBytesLen = dirNameBytes.length; int dirNameBytesLen = dirNameBytes.length;
raf.writeInt(dirNameBytesLen); raf.writeInt(dirNameBytesLen);
writtenSoFar += 4; writtenSoFar += 4;
@ -1251,12 +1210,24 @@ public class ZipFileIndex {
return zipFile; 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> { static class Entry implements Comparable<Entry> {
public static final Entry[] EMPTY_ARRAY = {}; public static final Entry[] EMPTY_ARRAY = {};
// Directory related // Directory related
String dir; RelativeDirectory dir;
boolean isDir; boolean isDir;
// File related // File related
@ -1269,32 +1240,17 @@ public class ZipFileIndex {
private int nativetime; private int nativetime;
public Entry(String path) { public Entry(RelativePath path) {
int separator = path.lastIndexOf(File.separatorChar); this(path.dirname(), path.basename());
if (separator == -1) {
dir = "".intern();
name = path;
} else {
dir = path.substring(0, separator).intern();
name = path.substring(separator + 1);
}
} }
public Entry(String directory, String name) { public Entry(RelativeDirectory directory, String name) {
this.dir = directory.intern(); this.dir = directory;
this.name = name; this.name = name;
} }
public String getName() { public String getName() {
if (dir == null || dir.length() == 0) { return new RelativeFile(dir, name).getPath();
return name;
}
StringBuilder sb = new StringBuilder();
sb.append(dir);
sb.append(File.separatorChar);
sb.append(name);
return sb.toString();
} }
public String getFileName() { public String getFileName() {
@ -1331,7 +1287,7 @@ public class ZipFileIndex {
} }
public int compareTo(Entry other) { public int compareTo(Entry other) {
String otherD = other.dir; RelativeDirectory otherD = other.dir;
if (dir != otherD) { if (dir != otherD) {
int c = dir.compareTo(otherD); int c = dir.compareTo(otherD);
if (c != 0) if (c != 0)
@ -1340,6 +1296,22 @@ public class ZipFileIndex {
return name.compareTo(other.name); 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() { public String toString() {
return isDir ? ("Dir:" + dir + " : " + name) : return isDir ? ("Dir:" + dir + " : " + name) :

View File

@ -29,11 +29,8 @@ import java.io.IOException;
import java.util.Set; import java.util.Set;
import javax.tools.JavaFileObject; 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.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Writer; import java.io.Writer;
@ -42,6 +39,11 @@ import java.nio.ByteBuffer;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder; 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 { public class ZipFileIndexArchive implements Archive {
private final ZipFileIndex zfIndex; private final ZipFileIndex zfIndex;
@ -53,22 +55,22 @@ public class ZipFileIndexArchive implements Archive {
this.zfIndex = zdir; this.zfIndex = zdir;
} }
public boolean contains(String name) { public boolean contains(RelativePath name) {
return zfIndex.contains(name); return zfIndex.contains(name);
} }
public List<String> getFiles(String subdirectory) { public List<String> getFiles(RelativeDirectory subdirectory) {
return zfIndex.getFiles((subdirectory.endsWith("/") || subdirectory.endsWith("\\")) ? subdirectory.substring(0, subdirectory.length() - 1) : subdirectory); return zfIndex.getFiles(subdirectory);
} }
public JavaFileObject getFileObject(String subdirectory, String file) { public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
String fullZipFileName = subdirectory + file; RelativeFile fullZipFileName = new RelativeFile(subdirectory, file);
ZipFileIndex.Entry entry = zfIndex.getZipIndexEntry(fullZipFileName); ZipFileIndex.Entry entry = zfIndex.getZipIndexEntry(fullZipFileName);
JavaFileObject ret = new ZipFileIndexFileObject(fileManager, zfIndex, entry, zfIndex.getZipFile().getPath()); JavaFileObject ret = new ZipFileIndexFileObject(fileManager, zfIndex, entry, zfIndex.getZipFile().getPath());
return ret; return ret;
} }
public Set<String> getSubdirectories() { public Set<RelativeDirectory> getSubdirectories() {
return zfIndex.getAllDirectories(); return zfIndex.getAllDirectories();
} }
@ -76,6 +78,10 @@ public class ZipFileIndexArchive implements Archive {
zfIndex.close(); zfIndex.close();
} }
public String toString() {
return "ZipFileIndexArchive[" + zfIndex + "]";
}
/** /**
* A subclass of JavaFileObject representing zip entries using the com.sun.tools.javac.file.ZipFileIndex implementation. * A subclass of JavaFileObject representing zip entries using the com.sun.tools.javac.file.ZipFileIndex implementation.
*/ */
@ -181,18 +187,11 @@ public class ZipFileIndexArchive implements Archive {
public URI toUri() { public URI toUri() {
String zipName = new File(getZipName()).toURI().normalize().getPath(); String zipName = new File(getZipName()).toURI().normalize().getPath();
String entryName = getZipEntryName(); String entryName = getZipEntryName();
if (File.separatorChar != '/') {
entryName = entryName.replace(File.separatorChar, '/');
}
return URI.create("jar:" + zipName + "!" + entryName); return URI.create("jar:" + zipName + "!" + entryName);
} }
private byte[] read() throws IOException { private byte[] read() throws IOException {
if (entry == null) { assert entry != null; // see constructor
entry = zfIndex.getZipIndexEntry(name);
if (entry == null)
throw new FileNotFoundException();
}
return zfIndex.read(entry); return zfIndex.read(entry);
} }
@ -222,11 +221,11 @@ public class ZipFileIndexArchive implements Archive {
protected String inferBinaryName(Iterable<? extends File> path) { protected String inferBinaryName(Iterable<? extends File> path) {
String entryName = getZipEntryName(); String entryName = getZipEntryName();
if (zfIndex.symbolFilePrefix != null) { if (zfIndex.symbolFilePrefix != null) {
String prefix = zfIndex.symbolFilePrefix; String prefix = zfIndex.symbolFilePrefix.path;
if (entryName.startsWith(prefix)) if (entryName.startsWith(prefix))
entryName = entryName.substring(prefix.length()); entryName = entryName.substring(prefix.length());
} }
return removeExtension(entryName).replace(File.separatorChar, '.'); return removeExtension(entryName).replace('/', '.');
} }
} }

View File

@ -82,6 +82,7 @@ public class DocletInvoker {
cpString = appendPath(System.getProperty("java.class.path"), cpString); cpString = appendPath(System.getProperty("java.class.path"), cpString);
cpString = appendPath(docletPath, cpString); cpString = appendPath(docletPath, cpString);
URL[] urls = pathToURLs(cpString); URL[] urls = pathToURLs(cpString);
System.err.println("DocletInvoker urls=" + urls);
appClassLoader = new URLClassLoader(urls); appClassLoader = new URLClassLoader(urls);
// attempt to find doclet // attempt to find doclet

View File

@ -27,8 +27,6 @@ package javax.tools;
import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileManager.Location;
import java.io.File;
import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**

View File

@ -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 { }

View File

@ -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 { }

View File

@ -35,6 +35,7 @@ import java.util.jar.JarFile;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
import com.sun.tools.javac.file.JavacFileManager; 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.ZipFileIndex;
import com.sun.tools.javac.file.ZipFileIndexArchive; import com.sun.tools.javac.file.ZipFileIndexArchive;
import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context;
@ -45,7 +46,7 @@ public class T6725036 {
} }
void run() throws Exception { 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")); File f = new File(System.getProperty("java.home"));
if (!f.getName().equals("jre")) if (!f.getName().equals("jre"))
@ -53,22 +54,21 @@ public class T6725036 {
File rt_jar = new File(new File(f, "lib"), "rt.jar"); File rt_jar = new File(new File(f, "lib"), "rt.jar");
JarFile j = new JarFile(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(); long jarEntryTime = je.getTime();
ZipFileIndex zfi = ZipFileIndex zfi =
ZipFileIndex.getZipFileIndex(rt_jar, null, false, null, false); ZipFileIndex.getZipFileIndex(rt_jar, null, false, null, false);
long zfiTime = zfi.getLastModified(TEST_ENTRY_NAME); 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(); Context context = new Context();
JavacFileManager fm = new JavacFileManager(context, false, null); JavacFileManager fm = new JavacFileManager(context, false, null);
ZipFileIndexArchive zfia = new ZipFileIndexArchive(fm, zfi); ZipFileIndexArchive zfia = new ZipFileIndexArchive(fm, zfi);
int sep = TEST_ENTRY_NAME.lastIndexOf("/");
JavaFileObject jfo = JavaFileObject jfo =
zfia.getFileObject(TEST_ENTRY_NAME.substring(0, sep + 1), zfia.getFileObject(TEST_ENTRY_NAME.dirname(),
TEST_ENTRY_NAME.substring(sep + 1)); TEST_ENTRY_NAME.basename());
long jfoTime = jfo.getLastModified(); long jfoTime = jfo.getLastModified();
check(je, jarEntryTime, jfo, jfoTime); check(je, jarEntryTime, jfo, jfoTime);