1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/util/JavacFileManager.java Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,1715 @@ 1.4 +/* 1.5 + * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Sun designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Sun in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.25 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.26 + * have any questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.javac.util; 1.30 + 1.31 +import com.sun.tools.javac.main.JavacOption; 1.32 +import com.sun.tools.javac.main.OptionName; 1.33 +import com.sun.tools.javac.main.RecognizedOptions; 1.34 +import java.io.ByteArrayOutputStream; 1.35 +import java.io.File; 1.36 +import java.io.FileInputStream; 1.37 +import java.io.FileNotFoundException; 1.38 +import java.io.FileOutputStream; 1.39 +import java.io.IOException; 1.40 +import java.io.InputStream; 1.41 +import java.io.OutputStream; 1.42 +import java.io.OutputStreamWriter; 1.43 +import java.io.Writer; 1.44 +import java.lang.ref.SoftReference; 1.45 +import java.net.MalformedURLException; 1.46 +import java.net.URI; 1.47 +import java.net.URISyntaxException; 1.48 +import java.net.URL; 1.49 +import java.net.URLClassLoader; 1.50 +import java.nio.ByteBuffer; 1.51 +import java.nio.CharBuffer; 1.52 +import java.nio.channels.FileChannel; 1.53 +import java.nio.charset.Charset; 1.54 +import java.nio.charset.CharsetDecoder; 1.55 +import java.nio.charset.CoderResult; 1.56 +import java.nio.charset.CodingErrorAction; 1.57 +import java.nio.charset.IllegalCharsetNameException; 1.58 +import java.nio.charset.UnsupportedCharsetException; 1.59 +import java.util.ArrayList; 1.60 +import java.util.Arrays; 1.61 +import java.util.Collection; 1.62 +import java.util.Collections; 1.63 +import java.util.EnumSet; 1.64 +import java.util.Enumeration; 1.65 +import java.util.HashMap; 1.66 +import java.util.Iterator; 1.67 +import java.util.Map; 1.68 +import java.util.Set; 1.69 +import java.util.zip.ZipEntry; 1.70 +import java.util.zip.ZipFile; 1.71 + 1.72 +import javax.lang.model.SourceVersion; 1.73 +import javax.tools.FileObject; 1.74 +import javax.tools.JavaFileManager; 1.75 +import javax.tools.JavaFileObject; 1.76 + 1.77 +import com.sun.tools.javac.code.Source; 1.78 +import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; 1.79 +import java.util.concurrent.ConcurrentHashMap; 1.80 +import javax.tools.StandardJavaFileManager; 1.81 + 1.82 +import com.sun.tools.javac.zip.*; 1.83 +import java.io.ByteArrayInputStream; 1.84 + 1.85 +import static com.sun.tools.javac.main.OptionName.*; 1.86 +import static javax.tools.StandardLocation.*; 1.87 + 1.88 +/** 1.89 + * This class provides access to the source, class and other files 1.90 + * used by the compiler and related tools. 1.91 + */ 1.92 +public class JavacFileManager implements StandardJavaFileManager { 1.93 + 1.94 + private static final String[] symbolFileLocation = { "lib", "ct.sym" }; 1.95 + private static final String symbolFilePrefix = "META-INF/sym/rt.jar/"; 1.96 + 1.97 + boolean useZipFileIndex; 1.98 + 1.99 + private static int symbolFilePrefixLength = 0; 1.100 + static { 1.101 + try { 1.102 + symbolFilePrefixLength = symbolFilePrefix.getBytes("UTF-8").length; 1.103 + } catch (java.io.UnsupportedEncodingException uee) { 1.104 + // Can't happen...UTF-8 is always supported. 1.105 + } 1.106 + } 1.107 + 1.108 + private static boolean CHECK_ZIP_TIMESTAMP = false; 1.109 + private static Map<File, Boolean> isDirectory = new ConcurrentHashMap<File, Boolean>(); 1.110 + 1.111 + 1.112 + public static char[] toArray(CharBuffer buffer) { 1.113 + if (buffer.hasArray()) 1.114 + return ((CharBuffer)buffer.compact().flip()).array(); 1.115 + else 1.116 + return buffer.toString().toCharArray(); 1.117 + } 1.118 + 1.119 + /** 1.120 + * The log to be used for error reporting. 1.121 + */ 1.122 + protected Log log; 1.123 + 1.124 + /** Encapsulates knowledge of paths 1.125 + */ 1.126 + private Paths paths; 1.127 + 1.128 + private Options options; 1.129 + 1.130 + private final File uninited = new File("U N I N I T E D"); 1.131 + 1.132 + private final Set<JavaFileObject.Kind> sourceOrClass = 1.133 + EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS); 1.134 + 1.135 + /** The standard output directory, primarily used for classes. 1.136 + * Initialized by the "-d" option. 1.137 + * If classOutDir = null, files are written into same directory as the sources 1.138 + * they were generated from. 1.139 + */ 1.140 + private File classOutDir = uninited; 1.141 + 1.142 + /** The output directory, used when generating sources while processing annotations. 1.143 + * Initialized by the "-s" option. 1.144 + */ 1.145 + private File sourceOutDir = uninited; 1.146 + 1.147 + protected boolean mmappedIO; 1.148 + protected boolean ignoreSymbolFile; 1.149 + 1.150 + /** 1.151 + * User provided charset (through javax.tools). 1.152 + */ 1.153 + protected Charset charset; 1.154 + 1.155 + /** 1.156 + * Register a Context.Factory to create a JavacFileManager. 1.157 + */ 1.158 + public static void preRegister(final Context context) { 1.159 + context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() { 1.160 + public JavaFileManager make() { 1.161 + return new JavacFileManager(context, true, null); 1.162 + } 1.163 + }); 1.164 + } 1.165 + 1.166 + /** 1.167 + * Create a JavacFileManager using a given context, optionally registering 1.168 + * it as the JavaFileManager for that context. 1.169 + */ 1.170 + public JavacFileManager(Context context, boolean register, Charset charset) { 1.171 + if (register) 1.172 + context.put(JavaFileManager.class, this); 1.173 + byteBufferCache = new ByteBufferCache(); 1.174 + this.charset = charset; 1.175 + setContext(context); 1.176 + } 1.177 + 1.178 + /** 1.179 + * Set the context for JavacFileManager. 1.180 + */ 1.181 + public void setContext(Context context) { 1.182 + log = Log.instance(context); 1.183 + if (paths == null) { 1.184 + paths = Paths.instance(context); 1.185 + } else { 1.186 + // Reuse the Paths object as it stores the locations that 1.187 + // have been set with setLocation, etc. 1.188 + paths.setContext(context); 1.189 + } 1.190 + 1.191 + options = Options.instance(context); 1.192 + 1.193 + useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null; 1.194 + CHECK_ZIP_TIMESTAMP = System.getProperty("checkZipIndexTimestamp") != null;// TODO: options.get("checkZipIndexTimestamp") != null; 1.195 + 1.196 + mmappedIO = options.get("mmappedIO") != null; 1.197 + ignoreSymbolFile = options.get("ignore.symbol.file") != null; 1.198 + } 1.199 + 1.200 + public JavaFileObject getFileForInput(String name) { 1.201 + return getRegularFile(new File(name)); 1.202 + } 1.203 + 1.204 + public JavaFileObject getRegularFile(File file) { 1.205 + return new RegularFileObject(file); 1.206 + } 1.207 + 1.208 + public JavaFileObject getFileForOutput(String classname, 1.209 + JavaFileObject.Kind kind, 1.210 + JavaFileObject sibling) 1.211 + throws IOException 1.212 + { 1.213 + return getJavaFileForOutput(CLASS_OUTPUT, classname, kind, sibling); 1.214 + } 1.215 + 1.216 + public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) { 1.217 + ListBuffer<File> files = new ListBuffer<File>(); 1.218 + for (String name : names) 1.219 + files.append(new File(nullCheck(name))); 1.220 + return getJavaFileObjectsFromFiles(files.toList()); 1.221 + } 1.222 + 1.223 + public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) { 1.224 + return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names))); 1.225 + } 1.226 + 1.227 + protected JavaFileObject.Kind getKind(String extension) { 1.228 + if (extension.equals(JavaFileObject.Kind.CLASS.extension)) 1.229 + return JavaFileObject.Kind.CLASS; 1.230 + else if (extension.equals(JavaFileObject.Kind.SOURCE.extension)) 1.231 + return JavaFileObject.Kind.SOURCE; 1.232 + else if (extension.equals(JavaFileObject.Kind.HTML.extension)) 1.233 + return JavaFileObject.Kind.HTML; 1.234 + else 1.235 + return JavaFileObject.Kind.OTHER; 1.236 + } 1.237 + 1.238 + private static boolean isValidName(String name) { 1.239 + // Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ), 1.240 + // but the set of keywords depends on the source level, and we don't want 1.241 + // impls of JavaFileManager to have to be dependent on the source level. 1.242 + // Therefore we simply check that the argument is a sequence of identifiers 1.243 + // separated by ".". 1.244 + for (String s : name.split("\\.", -1)) { 1.245 + if (!SourceVersion.isIdentifier(s)) 1.246 + return false; 1.247 + } 1.248 + return true; 1.249 + } 1.250 + 1.251 + private static void validateClassName(String className) { 1.252 + if (!isValidName(className)) 1.253 + throw new IllegalArgumentException("Invalid class name: " + className); 1.254 + } 1.255 + 1.256 + private static void validatePackageName(String packageName) { 1.257 + if (packageName.length() > 0 && !isValidName(packageName)) 1.258 + throw new IllegalArgumentException("Invalid packageName name: " + packageName); 1.259 + } 1.260 + 1.261 + public static void testName(String name, 1.262 + boolean isValidPackageName, 1.263 + boolean isValidClassName) 1.264 + { 1.265 + try { 1.266 + validatePackageName(name); 1.267 + if (!isValidPackageName) 1.268 + throw new AssertionError("Invalid package name accepted: " + name); 1.269 + printAscii("Valid package name: \"%s\"", name); 1.270 + } catch (IllegalArgumentException e) { 1.271 + if (isValidPackageName) 1.272 + throw new AssertionError("Valid package name rejected: " + name); 1.273 + printAscii("Invalid package name: \"%s\"", name); 1.274 + } 1.275 + try { 1.276 + validateClassName(name); 1.277 + if (!isValidClassName) 1.278 + throw new AssertionError("Invalid class name accepted: " + name); 1.279 + printAscii("Valid class name: \"%s\"", name); 1.280 + } catch (IllegalArgumentException e) { 1.281 + if (isValidClassName) 1.282 + throw new AssertionError("Valid class name rejected: " + name); 1.283 + printAscii("Invalid class name: \"%s\"", name); 1.284 + } 1.285 + } 1.286 + private static void printAscii(String format, Object... args) { 1.287 + String message; 1.288 + try { 1.289 + final String ascii = "US-ASCII"; 1.290 + message = new String(String.format(null, format, args).getBytes(ascii), ascii); 1.291 + } catch (java.io.UnsupportedEncodingException ex) { 1.292 + throw new AssertionError(ex); 1.293 + } 1.294 + System.out.println(message); 1.295 + } 1.296 + 1.297 + /** Return external representation of name, 1.298 + * converting '.' to File.separatorChar. 1.299 + */ 1.300 + private static String externalizeFileName(CharSequence name) { 1.301 + return name.toString().replace('.', File.separatorChar); 1.302 + } 1.303 + 1.304 + private static String externalizeFileName(CharSequence n, JavaFileObject.Kind kind) { 1.305 + return externalizeFileName(n) + kind.extension; 1.306 + } 1.307 + 1.308 + private static String baseName(String fileName) { 1.309 + return fileName.substring(fileName.lastIndexOf(File.separatorChar) + 1); 1.310 + } 1.311 + 1.312 + /** 1.313 + * Insert all files in subdirectory `subdirectory' of `directory' which end 1.314 + * in one of the extensions in `extensions' into packageSym. 1.315 + */ 1.316 + private void listDirectory(File directory, 1.317 + String subdirectory, 1.318 + Set<JavaFileObject.Kind> fileKinds, 1.319 + boolean recurse, 1.320 + ListBuffer<JavaFileObject> l) { 1.321 + Archive archive = archives.get(directory); 1.322 + 1.323 + boolean isFile = false; 1.324 + if (CHECK_ZIP_TIMESTAMP) { 1.325 + Boolean isf = isDirectory.get(directory); 1.326 + if (isf == null) { 1.327 + isFile = directory.isFile(); 1.328 + isDirectory.put(directory, isFile); 1.329 + } 1.330 + else { 1.331 + isFile = directory.isFile(); 1.332 + } 1.333 + } 1.334 + else { 1.335 + isFile = directory.isFile(); 1.336 + } 1.337 + 1.338 + if (archive != null || isFile) { 1.339 + if (archive == null) { 1.340 + try { 1.341 + archive = openArchive(directory); 1.342 + } catch (IOException ex) { 1.343 + log.error("error.reading.file", 1.344 + directory, ex.getLocalizedMessage()); 1.345 + return; 1.346 + } 1.347 + } 1.348 + if (subdirectory.length() != 0) { 1.349 + if (!useZipFileIndex) { 1.350 + subdirectory = subdirectory.replace('\\', '/'); 1.351 + if (!subdirectory.endsWith("/")) subdirectory = subdirectory + "/"; 1.352 + } 1.353 + else { 1.354 + if (File.separatorChar == '/') { 1.355 + subdirectory = subdirectory.replace('\\', '/'); 1.356 + } 1.357 + else { 1.358 + subdirectory = subdirectory.replace('/', '\\'); 1.359 + } 1.360 + 1.361 + if (!subdirectory.endsWith(File.separator)) subdirectory = subdirectory + File.separator; 1.362 + } 1.363 + } 1.364 + 1.365 + List<String> files = archive.getFiles(subdirectory); 1.366 + if (files != null) { 1.367 + for (String file; !files.isEmpty(); files = files.tail) { 1.368 + file = files.head; 1.369 + if (isValidFile(file, fileKinds)) { 1.370 + l.append(archive.getFileObject(subdirectory, file)); 1.371 + } 1.372 + } 1.373 + } 1.374 + if (recurse) { 1.375 + for (String s: archive.getSubdirectories()) { 1.376 + if (s.startsWith(subdirectory) && !s.equals(subdirectory)) { 1.377 + // Because the archive map is a flat list of directories, 1.378 + // the enclosing loop will pick up all child subdirectories. 1.379 + // Therefore, there is no need to recurse deeper. 1.380 + listDirectory(directory, s, fileKinds, false, l); 1.381 + } 1.382 + } 1.383 + } 1.384 + } else { 1.385 + File d = subdirectory.length() != 0 1.386 + ? new File(directory, subdirectory) 1.387 + : directory; 1.388 + if (!caseMapCheck(d, subdirectory)) 1.389 + return; 1.390 + 1.391 + File[] files = d.listFiles(); 1.392 + if (files == null) 1.393 + return; 1.394 + 1.395 + for (File f: files) { 1.396 + String fname = f.getName(); 1.397 + if (f.isDirectory()) { 1.398 + if (recurse && SourceVersion.isIdentifier(fname)) { 1.399 + listDirectory(directory, 1.400 + subdirectory + File.separator + fname, 1.401 + fileKinds, 1.402 + recurse, 1.403 + l); 1.404 + } 1.405 + } else { 1.406 + if (isValidFile(fname, fileKinds)) { 1.407 + JavaFileObject fe = 1.408 + new RegularFileObject(fname, new File(d, fname)); 1.409 + l.append(fe); 1.410 + } 1.411 + } 1.412 + } 1.413 + } 1.414 + } 1.415 + 1.416 + private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) { 1.417 + int lastDot = s.lastIndexOf("."); 1.418 + String extn = (lastDot == -1 ? s : s.substring(lastDot)); 1.419 + JavaFileObject.Kind kind = getKind(extn); 1.420 + return fileKinds.contains(kind); 1.421 + } 1.422 + 1.423 + private static final boolean fileSystemIsCaseSensitive = 1.424 + File.separatorChar == '/'; 1.425 + 1.426 + /** Hack to make Windows case sensitive. Test whether given path 1.427 + * ends in a string of characters with the same case as given name. 1.428 + * Ignore file separators in both path and name. 1.429 + */ 1.430 + private boolean caseMapCheck(File f, String name) { 1.431 + if (fileSystemIsCaseSensitive) return true; 1.432 + // Note that getCanonicalPath() returns the case-sensitive 1.433 + // spelled file name. 1.434 + String path; 1.435 + try { 1.436 + path = f.getCanonicalPath(); 1.437 + } catch (IOException ex) { 1.438 + return false; 1.439 + } 1.440 + char[] pcs = path.toCharArray(); 1.441 + char[] ncs = name.toCharArray(); 1.442 + int i = pcs.length - 1; 1.443 + int j = ncs.length - 1; 1.444 + while (i >= 0 && j >= 0) { 1.445 + while (i >= 0 && pcs[i] == File.separatorChar) i--; 1.446 + while (j >= 0 && ncs[j] == File.separatorChar) j--; 1.447 + if (i >= 0 && j >= 0) { 1.448 + if (pcs[i] != ncs[j]) return false; 1.449 + i--; 1.450 + j--; 1.451 + } 1.452 + } 1.453 + return j < 0; 1.454 + } 1.455 + 1.456 + /** 1.457 + * An archive provides a flat directory structure of a ZipFile by 1.458 + * mapping directory names to lists of files (basenames). 1.459 + */ 1.460 + public interface Archive { 1.461 + void close() throws IOException; 1.462 + 1.463 + boolean contains(String name); 1.464 + 1.465 + JavaFileObject getFileObject(String subdirectory, String file); 1.466 + 1.467 + List<String> getFiles(String subdirectory); 1.468 + 1.469 + Set<String> getSubdirectories(); 1.470 + } 1.471 + 1.472 + public class ZipArchive implements Archive { 1.473 + protected final Map<String,List<String>> map; 1.474 + protected final ZipFile zdir; 1.475 + public ZipArchive(ZipFile zdir) throws IOException { 1.476 + this.zdir = zdir; 1.477 + this.map = new HashMap<String,List<String>>(); 1.478 + for (Enumeration<? extends ZipEntry> e = zdir.entries(); e.hasMoreElements(); ) { 1.479 + ZipEntry entry; 1.480 + try { 1.481 + entry = e.nextElement(); 1.482 + } catch (InternalError ex) { 1.483 + IOException io = new IOException(); 1.484 + io.initCause(ex); // convenience constructors added in Mustang :-( 1.485 + throw io; 1.486 + } 1.487 + addZipEntry(entry); 1.488 + } 1.489 + } 1.490 + 1.491 + void addZipEntry(ZipEntry entry) { 1.492 + String name = entry.getName(); 1.493 + int i = name.lastIndexOf('/'); 1.494 + String dirname = name.substring(0, i+1); 1.495 + String basename = name.substring(i+1); 1.496 + if (basename.length() == 0) 1.497 + return; 1.498 + List<String> list = map.get(dirname); 1.499 + if (list == null) 1.500 + list = List.nil(); 1.501 + list = list.prepend(basename); 1.502 + map.put(dirname, list); 1.503 + } 1.504 + 1.505 + public boolean contains(String name) { 1.506 + int i = name.lastIndexOf('/'); 1.507 + String dirname = name.substring(0, i+1); 1.508 + String basename = name.substring(i+1); 1.509 + if (basename.length() == 0) 1.510 + return false; 1.511 + List<String> list = map.get(dirname); 1.512 + return (list != null && list.contains(basename)); 1.513 + } 1.514 + 1.515 + public List<String> getFiles(String subdirectory) { 1.516 + return map.get(subdirectory); 1.517 + } 1.518 + 1.519 + public JavaFileObject getFileObject(String subdirectory, String file) { 1.520 + ZipEntry ze = zdir.getEntry(subdirectory + file); 1.521 + return new ZipFileObject(file, zdir, ze); 1.522 + } 1.523 + 1.524 + public Set<String> getSubdirectories() { 1.525 + return map.keySet(); 1.526 + } 1.527 + 1.528 + public void close() throws IOException { 1.529 + zdir.close(); 1.530 + } 1.531 + } 1.532 + 1.533 + public class SymbolArchive extends ZipArchive { 1.534 + final File origFile; 1.535 + public SymbolArchive(File orig, ZipFile zdir) throws IOException { 1.536 + super(zdir); 1.537 + this.origFile = orig; 1.538 + } 1.539 + 1.540 + @Override 1.541 + void addZipEntry(ZipEntry entry) { 1.542 + // called from super constructor, may not refer to origFile. 1.543 + String name = entry.getName(); 1.544 + if (!name.startsWith(symbolFilePrefix)) 1.545 + return; 1.546 + name = name.substring(symbolFilePrefix.length()); 1.547 + int i = name.lastIndexOf('/'); 1.548 + String dirname = name.substring(0, i+1); 1.549 + String basename = name.substring(i+1); 1.550 + if (basename.length() == 0) 1.551 + return; 1.552 + List<String> list = map.get(dirname); 1.553 + if (list == null) 1.554 + list = List.nil(); 1.555 + list = list.prepend(basename); 1.556 + map.put(dirname, list); 1.557 + } 1.558 + 1.559 + @Override 1.560 + public JavaFileObject getFileObject(String subdirectory, String file) { 1.561 + return super.getFileObject(symbolFilePrefix + subdirectory, file); 1.562 + } 1.563 + } 1.564 + 1.565 + public class MissingArchive implements Archive { 1.566 + final File zipFileName; 1.567 + public MissingArchive(File name) { 1.568 + zipFileName = name; 1.569 + } 1.570 + public boolean contains(String name) { 1.571 + return false; 1.572 + } 1.573 + 1.574 + public void close() { 1.575 + } 1.576 + 1.577 + public JavaFileObject getFileObject(String subdirectory, String file) { 1.578 + return null; 1.579 + } 1.580 + 1.581 + public List<String> getFiles(String subdirectory) { 1.582 + return List.nil(); 1.583 + } 1.584 + 1.585 + public Set<String> getSubdirectories() { 1.586 + return Collections.emptySet(); 1.587 + } 1.588 + } 1.589 + 1.590 + /** A directory of zip files already opened. 1.591 + */ 1.592 + Map<File, Archive> archives = new HashMap<File,Archive>(); 1.593 + 1.594 + /** Open a new zip file directory. 1.595 + */ 1.596 + protected Archive openArchive(File zipFileName) throws IOException { 1.597 + Archive archive = archives.get(zipFileName); 1.598 + if (archive == null) { 1.599 + File origZipFileName = zipFileName; 1.600 + if (!ignoreSymbolFile && paths.isBootClassPathRtJar(zipFileName)) { 1.601 + File file = zipFileName.getParentFile().getParentFile(); // ${java.home} 1.602 + if (new File(file.getName()).equals(new File("jre"))) 1.603 + file = file.getParentFile(); 1.604 + // file == ${jdk.home} 1.605 + for (String name : symbolFileLocation) 1.606 + file = new File(file, name); 1.607 + // file == ${jdk.home}/lib/ct.sym 1.608 + if (file.exists()) 1.609 + zipFileName = file; 1.610 + } 1.611 + 1.612 + try { 1.613 + 1.614 + ZipFile zdir = null; 1.615 + 1.616 + boolean usePreindexedCache = false; 1.617 + String preindexCacheLocation = null; 1.618 + 1.619 + if (!useZipFileIndex) { 1.620 + zdir = new ZipFile(zipFileName); 1.621 + } 1.622 + else { 1.623 + usePreindexedCache = options.get("usezipindex") != null; 1.624 + preindexCacheLocation = options.get("java.io.tmpdir"); 1.625 + String optCacheLoc = options.get("cachezipindexdir"); 1.626 + 1.627 + if (optCacheLoc != null && optCacheLoc.length() != 0) { 1.628 + if (optCacheLoc.startsWith("\"")) { 1.629 + if (optCacheLoc.endsWith("\"")) { 1.630 + optCacheLoc = optCacheLoc.substring(1, optCacheLoc.length() - 1); 1.631 + } 1.632 + else { 1.633 + optCacheLoc = optCacheLoc.substring(1); 1.634 + } 1.635 + } 1.636 + 1.637 + File cacheDir = new File(optCacheLoc); 1.638 + if (cacheDir.exists() && cacheDir.canWrite()) { 1.639 + preindexCacheLocation = optCacheLoc; 1.640 + if (!preindexCacheLocation.endsWith("/") && 1.641 + !preindexCacheLocation.endsWith(File.separator)) { 1.642 + preindexCacheLocation += File.separator; 1.643 + } 1.644 + } 1.645 + } 1.646 + } 1.647 + 1.648 + if (origZipFileName == zipFileName) { 1.649 + if (!useZipFileIndex) { 1.650 + archive = new ZipArchive(zdir); 1.651 + } else { 1.652 + archive = new ZipFileIndexArchive(this, ZipFileIndex.getZipFileIndex(zipFileName, 0, 1.653 + usePreindexedCache, preindexCacheLocation, options.get("writezipindexfiles") != null)); 1.654 + } 1.655 + } 1.656 + else { 1.657 + if (!useZipFileIndex) { 1.658 + archive = new SymbolArchive(origZipFileName, zdir); 1.659 + } 1.660 + else { 1.661 + archive = new ZipFileIndexArchive(this, ZipFileIndex.getZipFileIndex(zipFileName, symbolFilePrefixLength, 1.662 + usePreindexedCache, preindexCacheLocation, options.get("writezipindexfiles") != null)); 1.663 + } 1.664 + } 1.665 + } catch (FileNotFoundException ex) { 1.666 + archive = new MissingArchive(zipFileName); 1.667 + } catch (IOException ex) { 1.668 + log.error("error.reading.file", zipFileName, ex.getLocalizedMessage()); 1.669 + archive = new MissingArchive(zipFileName); 1.670 + } 1.671 + 1.672 + archives.put(origZipFileName, archive); 1.673 + } 1.674 + return archive; 1.675 + } 1.676 + 1.677 + /** Flush any output resources. 1.678 + */ 1.679 + public void flush() { 1.680 + contentCache.clear(); 1.681 + } 1.682 + 1.683 + /** 1.684 + * Close the JavaFileManager, releasing resources. 1.685 + */ 1.686 + public void close() { 1.687 + for (Iterator<Archive> i = archives.values().iterator(); i.hasNext(); ) { 1.688 + Archive a = i.next(); 1.689 + i.remove(); 1.690 + try { 1.691 + a.close(); 1.692 + } catch (IOException e) { 1.693 + } 1.694 + } 1.695 + } 1.696 + 1.697 + private Map<JavaFileObject, SoftReference<CharBuffer>> contentCache = new HashMap<JavaFileObject, SoftReference<CharBuffer>>(); 1.698 + 1.699 + private String defaultEncodingName; 1.700 + private String getDefaultEncodingName() { 1.701 + if (defaultEncodingName == null) { 1.702 + defaultEncodingName = 1.703 + new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding(); 1.704 + } 1.705 + return defaultEncodingName; 1.706 + } 1.707 + 1.708 + protected String getEncodingName() { 1.709 + String encName = options.get(OptionName.ENCODING); 1.710 + if (encName == null) 1.711 + return getDefaultEncodingName(); 1.712 + else 1.713 + return encName; 1.714 + } 1.715 + 1.716 + protected Source getSource() { 1.717 + String sourceName = options.get(OptionName.SOURCE); 1.718 + Source source = null; 1.719 + if (sourceName != null) 1.720 + source = Source.lookup(sourceName); 1.721 + return (source != null ? source : Source.DEFAULT); 1.722 + } 1.723 + 1.724 + /** 1.725 + * Make a byte buffer from an input stream. 1.726 + */ 1.727 + private ByteBuffer makeByteBuffer(InputStream in) 1.728 + throws IOException { 1.729 + int limit = in.available(); 1.730 + if (mmappedIO && in instanceof FileInputStream) { 1.731 + // Experimental memory mapped I/O 1.732 + FileInputStream fin = (FileInputStream)in; 1.733 + return fin.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, limit); 1.734 + } 1.735 + if (limit < 1024) limit = 1024; 1.736 + ByteBuffer result = byteBufferCache.get(limit); 1.737 + int position = 0; 1.738 + while (in.available() != 0) { 1.739 + if (position >= limit) 1.740 + // expand buffer 1.741 + result = ByteBuffer. 1.742 + allocate(limit <<= 1). 1.743 + put((ByteBuffer)result.flip()); 1.744 + int count = in.read(result.array(), 1.745 + position, 1.746 + limit - position); 1.747 + if (count < 0) break; 1.748 + result.position(position += count); 1.749 + } 1.750 + return (ByteBuffer)result.flip(); 1.751 + } 1.752 + 1.753 + /** 1.754 + * A single-element cache of direct byte buffers. 1.755 + */ 1.756 + private static class ByteBufferCache { 1.757 + private ByteBuffer cached; 1.758 + ByteBuffer get(int capacity) { 1.759 + if (capacity < 20480) capacity = 20480; 1.760 + ByteBuffer result = 1.761 + (cached != null && cached.capacity() >= capacity) 1.762 + ? (ByteBuffer)cached.clear() 1.763 + : ByteBuffer.allocate(capacity + capacity>>1); 1.764 + cached = null; 1.765 + return result; 1.766 + } 1.767 + void put(ByteBuffer x) { 1.768 + cached = x; 1.769 + } 1.770 + } 1.771 + private final ByteBufferCache byteBufferCache; 1.772 + 1.773 + private CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) { 1.774 + Charset charset = (this.charset == null) 1.775 + ? Charset.forName(encodingName) 1.776 + : this.charset; 1.777 + CharsetDecoder decoder = charset.newDecoder(); 1.778 + 1.779 + CodingErrorAction action; 1.780 + if (ignoreEncodingErrors) 1.781 + action = CodingErrorAction.REPLACE; 1.782 + else 1.783 + action = CodingErrorAction.REPORT; 1.784 + 1.785 + return decoder 1.786 + .onMalformedInput(action) 1.787 + .onUnmappableCharacter(action); 1.788 + } 1.789 + 1.790 + /** 1.791 + * Decode a ByteBuffer into a CharBuffer. 1.792 + */ 1.793 + private CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) { 1.794 + String encodingName = getEncodingName(); 1.795 + CharsetDecoder decoder; 1.796 + try { 1.797 + decoder = getDecoder(encodingName, ignoreEncodingErrors); 1.798 + } catch (IllegalCharsetNameException e) { 1.799 + log.error("unsupported.encoding", encodingName); 1.800 + return (CharBuffer)CharBuffer.allocate(1).flip(); 1.801 + } catch (UnsupportedCharsetException e) { 1.802 + log.error("unsupported.encoding", encodingName); 1.803 + return (CharBuffer)CharBuffer.allocate(1).flip(); 1.804 + } 1.805 + 1.806 + // slightly overestimate the buffer size to avoid reallocation. 1.807 + float factor = 1.808 + decoder.averageCharsPerByte() * 0.8f + 1.809 + decoder.maxCharsPerByte() * 0.2f; 1.810 + CharBuffer dest = CharBuffer. 1.811 + allocate(10 + (int)(inbuf.remaining()*factor)); 1.812 + 1.813 + while (true) { 1.814 + CoderResult result = decoder.decode(inbuf, dest, true); 1.815 + dest.flip(); 1.816 + 1.817 + if (result.isUnderflow()) { // done reading 1.818 + // make sure there is at least one extra character 1.819 + if (dest.limit() == dest.capacity()) { 1.820 + dest = CharBuffer.allocate(dest.capacity()+1).put(dest); 1.821 + dest.flip(); 1.822 + } 1.823 + return dest; 1.824 + } else if (result.isOverflow()) { // buffer too small; expand 1.825 + int newCapacity = 1.826 + 10 + dest.capacity() + 1.827 + (int)(inbuf.remaining()*decoder.maxCharsPerByte()); 1.828 + dest = CharBuffer.allocate(newCapacity).put(dest); 1.829 + } else if (result.isMalformed() || result.isUnmappable()) { 1.830 + // bad character in input 1.831 + 1.832 + // report coding error (warn only pre 1.5) 1.833 + if (!getSource().allowEncodingErrors()) { 1.834 + log.error(new SimpleDiagnosticPosition(dest.limit()), 1.835 + "illegal.char.for.encoding", 1.836 + charset == null ? encodingName : charset.name()); 1.837 + } else { 1.838 + log.warning(new SimpleDiagnosticPosition(dest.limit()), 1.839 + "illegal.char.for.encoding", 1.840 + charset == null ? encodingName : charset.name()); 1.841 + } 1.842 + 1.843 + // skip past the coding error 1.844 + inbuf.position(inbuf.position() + result.length()); 1.845 + 1.846 + // undo the flip() to prepare the output buffer 1.847 + // for more translation 1.848 + dest.position(dest.limit()); 1.849 + dest.limit(dest.capacity()); 1.850 + dest.put((char)0xfffd); // backward compatible 1.851 + } else { 1.852 + throw new AssertionError(result); 1.853 + } 1.854 + } 1.855 + // unreached 1.856 + } 1.857 + 1.858 + public ClassLoader getClassLoader(Location location) { 1.859 + nullCheck(location); 1.860 + Iterable<? extends File> path = getLocation(location); 1.861 + if (path == null) 1.862 + return null; 1.863 + ListBuffer<URL> lb = new ListBuffer<URL>(); 1.864 + for (File f: path) { 1.865 + try { 1.866 + lb.append(f.toURI().toURL()); 1.867 + } catch (MalformedURLException e) { 1.868 + throw new AssertionError(e); 1.869 + } 1.870 + } 1.871 + return new URLClassLoader(lb.toArray(new URL[lb.size()]), 1.872 + getClass().getClassLoader()); 1.873 + } 1.874 + 1.875 + public Iterable<JavaFileObject> list(Location location, 1.876 + String packageName, 1.877 + Set<JavaFileObject.Kind> kinds, 1.878 + boolean recurse) 1.879 + throws IOException 1.880 + { 1.881 + // validatePackageName(packageName); 1.882 + nullCheck(packageName); 1.883 + nullCheck(kinds); 1.884 + 1.885 + Iterable<? extends File> path = getLocation(location); 1.886 + if (path == null) 1.887 + return List.nil(); 1.888 + String subdirectory = externalizeFileName(packageName); 1.889 + ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>(); 1.890 + 1.891 + for (File directory : path) 1.892 + listDirectory(directory, subdirectory, kinds, recurse, results); 1.893 + 1.894 + return results.toList(); 1.895 + } 1.896 + 1.897 + public String inferBinaryName(Location location, JavaFileObject file) { 1.898 + file.getClass(); // null check 1.899 + location.getClass(); // null check 1.900 + // Need to match the path semantics of list(location, ...) 1.901 + Iterable<? extends File> path = getLocation(location); 1.902 + if (path == null) { 1.903 + //System.err.println("Path for " + location + " is null"); 1.904 + return null; 1.905 + } 1.906 + //System.err.println("Path for " + location + " is " + path); 1.907 + 1.908 + if (file instanceof RegularFileObject) { 1.909 + RegularFileObject r = (RegularFileObject) file; 1.910 + String rPath = r.getPath(); 1.911 + //System.err.println("RegularFileObject " + file + " " +r.getPath()); 1.912 + for (File dir: path) { 1.913 + //System.err.println("dir: " + dir); 1.914 + String dPath = dir.getPath(); 1.915 + if (!dPath.endsWith(File.separator)) 1.916 + dPath += File.separator; 1.917 + if (rPath.regionMatches(true, 0, dPath, 0, dPath.length()) 1.918 + && new File(rPath.substring(0, dPath.length())).equals(new File(dPath))) { 1.919 + String relativeName = rPath.substring(dPath.length()); 1.920 + return removeExtension(relativeName).replace(File.separatorChar, '.'); 1.921 + } 1.922 + } 1.923 + } else if (file instanceof ZipFileObject) { 1.924 + ZipFileObject z = (ZipFileObject) file; 1.925 + String entryName = z.getZipEntryName(); 1.926 + if (entryName.startsWith(symbolFilePrefix)) 1.927 + entryName = entryName.substring(symbolFilePrefix.length()); 1.928 + return removeExtension(entryName).replace('/', '.'); 1.929 + } else if (file instanceof ZipFileIndexFileObject) { 1.930 + ZipFileIndexFileObject z = (ZipFileIndexFileObject) file; 1.931 + String entryName = z.getZipEntryName(); 1.932 + if (entryName.startsWith(symbolFilePrefix)) 1.933 + entryName = entryName.substring(symbolFilePrefix.length()); 1.934 + return removeExtension(entryName).replace(File.separatorChar, '.'); 1.935 + } else 1.936 + throw new IllegalArgumentException(file.getClass().getName()); 1.937 + // System.err.println("inferBinaryName failed for " + file); 1.938 + return null; 1.939 + } 1.940 + // where 1.941 + private static String removeExtension(String fileName) { 1.942 + int lastDot = fileName.lastIndexOf("."); 1.943 + return (lastDot == -1 ? fileName : fileName.substring(0, lastDot)); 1.944 + } 1.945 + 1.946 + public boolean isSameFile(FileObject a, FileObject b) { 1.947 + nullCheck(a); 1.948 + nullCheck(b); 1.949 + if (!(a instanceof BaseFileObject)) 1.950 + throw new IllegalArgumentException("Not supported: " + a); 1.951 + if (!(b instanceof BaseFileObject)) 1.952 + throw new IllegalArgumentException("Not supported: " + b); 1.953 + return a.equals(b); 1.954 + } 1.955 + 1.956 + public boolean handleOption(String current, Iterator<String> remaining) { 1.957 + for (JavacOption o: javacFileManagerOptions) { 1.958 + if (o.matches(current)) { 1.959 + if (o.hasArg()) { 1.960 + if (remaining.hasNext()) { 1.961 + if (!o.process(options, current, remaining.next())) 1.962 + return true; 1.963 + } 1.964 + } else { 1.965 + if (!o.process(options, current)) 1.966 + return true; 1.967 + } 1.968 + // operand missing, or process returned false 1.969 + throw new IllegalArgumentException(current); 1.970 + } 1.971 + } 1.972 + 1.973 + return false; 1.974 + } 1.975 + // where 1.976 + private static JavacOption[] javacFileManagerOptions = 1.977 + RecognizedOptions.getJavacFileManagerOptions( 1.978 + new RecognizedOptions.GrumpyHelper()); 1.979 + 1.980 + public int isSupportedOption(String option) { 1.981 + for (JavacOption o : javacFileManagerOptions) { 1.982 + if (o.matches(option)) 1.983 + return o.hasArg() ? 1 : 0; 1.984 + } 1.985 + return -1; 1.986 + } 1.987 + 1.988 + public boolean hasLocation(Location location) { 1.989 + return getLocation(location) != null; 1.990 + } 1.991 + 1.992 + public JavaFileObject getJavaFileForInput(Location location, 1.993 + String className, 1.994 + JavaFileObject.Kind kind) 1.995 + throws IOException 1.996 + { 1.997 + nullCheck(location); 1.998 + // validateClassName(className); 1.999 + nullCheck(className); 1.1000 + nullCheck(kind); 1.1001 + if (!sourceOrClass.contains(kind)) 1.1002 + throw new IllegalArgumentException("Invalid kind " + kind); 1.1003 + return getFileForInput(location, externalizeFileName(className, kind)); 1.1004 + } 1.1005 + 1.1006 + public FileObject getFileForInput(Location location, 1.1007 + String packageName, 1.1008 + String relativeName) 1.1009 + throws IOException 1.1010 + { 1.1011 + nullCheck(location); 1.1012 + // validatePackageName(packageName); 1.1013 + nullCheck(packageName); 1.1014 + if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701 1.1015 + throw new IllegalArgumentException("Invalid relative name: " + relativeName); 1.1016 + String name = packageName.length() == 0 1.1017 + ? relativeName 1.1018 + : new File(externalizeFileName(packageName), relativeName).getPath(); 1.1019 + return getFileForInput(location, name); 1.1020 + } 1.1021 + 1.1022 + private JavaFileObject getFileForInput(Location location, String name) throws IOException { 1.1023 + Iterable<? extends File> path = getLocation(location); 1.1024 + if (path == null) 1.1025 + return null; 1.1026 + 1.1027 + for (File dir: path) { 1.1028 + if (dir.isDirectory()) { 1.1029 + File f = new File(dir, name.replace('/', File.separatorChar)); 1.1030 + if (f.exists()) 1.1031 + return new RegularFileObject(f); 1.1032 + } else { 1.1033 + Archive a = openArchive(dir); 1.1034 + if (a.contains(name)) { 1.1035 + int i = name.lastIndexOf('/'); 1.1036 + String dirname = name.substring(0, i+1); 1.1037 + String basename = name.substring(i+1); 1.1038 + return a.getFileObject(dirname, basename); 1.1039 + } 1.1040 + 1.1041 + } 1.1042 + } 1.1043 + return null; 1.1044 + 1.1045 + } 1.1046 + 1.1047 + public JavaFileObject getJavaFileForOutput(Location location, 1.1048 + String className, 1.1049 + JavaFileObject.Kind kind, 1.1050 + FileObject sibling) 1.1051 + throws IOException 1.1052 + { 1.1053 + nullCheck(location); 1.1054 + // validateClassName(className); 1.1055 + nullCheck(className); 1.1056 + nullCheck(kind); 1.1057 + if (!sourceOrClass.contains(kind)) 1.1058 + throw new IllegalArgumentException("Invalid kind " + kind); 1.1059 + return getFileForOutput(location, externalizeFileName(className, kind), sibling); 1.1060 + } 1.1061 + 1.1062 + public FileObject getFileForOutput(Location location, 1.1063 + String packageName, 1.1064 + String relativeName, 1.1065 + FileObject sibling) 1.1066 + throws IOException 1.1067 + { 1.1068 + nullCheck(location); 1.1069 + // validatePackageName(packageName); 1.1070 + nullCheck(packageName); 1.1071 + if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701 1.1072 + throw new IllegalArgumentException("relativeName is invalid"); 1.1073 + String name = packageName.length() == 0 1.1074 + ? relativeName 1.1075 + : new File(externalizeFileName(packageName), relativeName).getPath(); 1.1076 + return getFileForOutput(location, name, sibling); 1.1077 + } 1.1078 + 1.1079 + private JavaFileObject getFileForOutput(Location location, 1.1080 + String fileName, 1.1081 + FileObject sibling) 1.1082 + throws IOException 1.1083 + { 1.1084 + File dir; 1.1085 + if (location == CLASS_OUTPUT) { 1.1086 + if (getClassOutDir() != null) { 1.1087 + dir = getClassOutDir(); 1.1088 + } else { 1.1089 + File siblingDir = null; 1.1090 + if (sibling != null && sibling instanceof RegularFileObject) { 1.1091 + siblingDir = ((RegularFileObject)sibling).f.getParentFile(); 1.1092 + } 1.1093 + return new RegularFileObject(new File(siblingDir, baseName(fileName))); 1.1094 + } 1.1095 + } else if (location == SOURCE_OUTPUT) { 1.1096 + dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir()); 1.1097 + } else { 1.1098 + Iterable<? extends File> path = paths.getPathForLocation(location); 1.1099 + dir = null; 1.1100 + for (File f: path) { 1.1101 + dir = f; 1.1102 + break; 1.1103 + } 1.1104 + } 1.1105 + 1.1106 + File file = (dir == null ? new File(fileName) : new File(dir, fileName)); 1.1107 + return new RegularFileObject(file); 1.1108 + 1.1109 + } 1.1110 + 1.1111 + public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles( 1.1112 + Iterable<? extends File> files) 1.1113 + { 1.1114 + ArrayList<RegularFileObject> result; 1.1115 + if (files instanceof Collection) 1.1116 + result = new ArrayList<RegularFileObject>(((Collection)files).size()); 1.1117 + else 1.1118 + result = new ArrayList<RegularFileObject>(); 1.1119 + for (File f: files) 1.1120 + result.add(new RegularFileObject(nullCheck(f))); 1.1121 + return result; 1.1122 + } 1.1123 + 1.1124 + public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) { 1.1125 + return getJavaFileObjectsFromFiles(Arrays.asList(nullCheck(files))); 1.1126 + } 1.1127 + 1.1128 + public void setLocation(Location location, 1.1129 + Iterable<? extends File> path) 1.1130 + throws IOException 1.1131 + { 1.1132 + nullCheck(location); 1.1133 + paths.lazy(); 1.1134 + 1.1135 + final File dir = location.isOutputLocation() ? getOutputDirectory(path) : null; 1.1136 + 1.1137 + if (location == CLASS_OUTPUT) 1.1138 + classOutDir = getOutputLocation(dir, D); 1.1139 + else if (location == SOURCE_OUTPUT) 1.1140 + sourceOutDir = getOutputLocation(dir, S); 1.1141 + else 1.1142 + paths.setPathForLocation(location, path); 1.1143 + } 1.1144 + // where 1.1145 + private File getOutputDirectory(Iterable<? extends File> path) throws IOException { 1.1146 + if (path == null) 1.1147 + return null; 1.1148 + Iterator<? extends File> pathIter = path.iterator(); 1.1149 + if (!pathIter.hasNext()) 1.1150 + throw new IllegalArgumentException("empty path for directory"); 1.1151 + File dir = pathIter.next(); 1.1152 + if (pathIter.hasNext()) 1.1153 + throw new IllegalArgumentException("path too long for directory"); 1.1154 + if (!dir.exists()) 1.1155 + throw new FileNotFoundException(dir + ": does not exist"); 1.1156 + else if (!dir.isDirectory()) 1.1157 + throw new IOException(dir + ": not a directory"); 1.1158 + return dir; 1.1159 + } 1.1160 + 1.1161 + private File getOutputLocation(File dir, OptionName defaultOptionName) { 1.1162 + if (dir != null) 1.1163 + return dir; 1.1164 + String arg = options.get(defaultOptionName); 1.1165 + if (arg == null) 1.1166 + return null; 1.1167 + return new File(arg); 1.1168 + } 1.1169 + 1.1170 + public Iterable<? extends File> getLocation(Location location) { 1.1171 + nullCheck(location); 1.1172 + paths.lazy(); 1.1173 + if (location == CLASS_OUTPUT) { 1.1174 + return (getClassOutDir() == null ? null : List.of(getClassOutDir())); 1.1175 + } else if (location == SOURCE_OUTPUT) { 1.1176 + return (getSourceOutDir() == null ? null : List.of(getSourceOutDir())); 1.1177 + } else 1.1178 + return paths.getPathForLocation(location); 1.1179 + } 1.1180 + 1.1181 + private File getClassOutDir() { 1.1182 + if (classOutDir == uninited) 1.1183 + classOutDir = getOutputLocation(null, D); 1.1184 + return classOutDir; 1.1185 + } 1.1186 + 1.1187 + private File getSourceOutDir() { 1.1188 + if (sourceOutDir == uninited) 1.1189 + sourceOutDir = getOutputLocation(null, S); 1.1190 + return sourceOutDir; 1.1191 + } 1.1192 + 1.1193 + /** 1.1194 + * Enforces the specification of a "relative" URI as used in 1.1195 + * {@linkplain #getFileForInput(Location,String,URI) 1.1196 + * getFileForInput}. This method must follow the rules defined in 1.1197 + * that method, do not make any changes without consulting the 1.1198 + * specification. 1.1199 + */ 1.1200 + protected static boolean isRelativeUri(URI uri) { 1.1201 + if (uri.isAbsolute()) 1.1202 + return false; 1.1203 + String path = uri.normalize().getPath(); 1.1204 + if (path.length() == 0 /* isEmpty() is mustang API */) 1.1205 + return false; 1.1206 + char first = path.charAt(0); 1.1207 + return first != '.' && first != '/'; 1.1208 + } 1.1209 + 1.1210 + /** 1.1211 + * Converts a relative file name to a relative URI. This is 1.1212 + * different from File.toURI as this method does not canonicalize 1.1213 + * the file before creating the URI. Furthermore, no schema is 1.1214 + * used. 1.1215 + * @param file a relative file name 1.1216 + * @return a relative URI 1.1217 + * @throws IllegalArgumentException if the file name is not 1.1218 + * relative according to the definition given in {@link 1.1219 + * javax.tools.JavaFileManager#getFileForInput} 1.1220 + */ 1.1221 + public static String getRelativeName(File file) { 1.1222 + if (!file.isAbsolute()) { 1.1223 + String result = file.getPath().replace(File.separatorChar, '/'); 1.1224 + if (JavacFileManager.isRelativeUri(URI.create(result))) // FIXME 6419701 1.1225 + return result; 1.1226 + } 1.1227 + throw new IllegalArgumentException("Invalid relative path: " + file); 1.1228 + } 1.1229 + 1.1230 + @SuppressWarnings("deprecation") // bug 6410637 1.1231 + protected static String getJavacFileName(FileObject file) { 1.1232 + if (file instanceof BaseFileObject) 1.1233 + return ((BaseFileObject)file).getPath(); 1.1234 + URI uri = file.toUri(); 1.1235 + String scheme = uri.getScheme(); 1.1236 + if (scheme == null || scheme.equals("file") || scheme.equals("jar")) 1.1237 + return uri.getPath(); 1.1238 + else 1.1239 + return uri.toString(); 1.1240 + } 1.1241 + 1.1242 + @SuppressWarnings("deprecation") // bug 6410637 1.1243 + protected static String getJavacBaseFileName(FileObject file) { 1.1244 + if (file instanceof BaseFileObject) 1.1245 + return ((BaseFileObject)file).getName(); 1.1246 + URI uri = file.toUri(); 1.1247 + String scheme = uri.getScheme(); 1.1248 + if (scheme == null || scheme.equals("file") || scheme.equals("jar")) { 1.1249 + String path = uri.getPath(); 1.1250 + if (path == null) 1.1251 + return null; 1.1252 + if (scheme != null && scheme.equals("jar")) 1.1253 + path = path.substring(path.lastIndexOf('!') + 1); 1.1254 + return path.substring(path.lastIndexOf('/') + 1); 1.1255 + } else { 1.1256 + return uri.toString(); 1.1257 + } 1.1258 + } 1.1259 + 1.1260 + private static <T> T nullCheck(T o) { 1.1261 + o.getClass(); // null check 1.1262 + return o; 1.1263 + } 1.1264 + 1.1265 + private static <T> Iterable<T> nullCheck(Iterable<T> it) { 1.1266 + for (T t : it) 1.1267 + t.getClass(); // null check 1.1268 + return it; 1.1269 + } 1.1270 + 1.1271 + /** 1.1272 + * A subclass of JavaFileObject representing regular files. 1.1273 + */ 1.1274 + private class RegularFileObject extends BaseFileObject { 1.1275 + /** Have the parent directories been created? 1.1276 + */ 1.1277 + private boolean hasParents=false; 1.1278 + 1.1279 + /** The file's name. 1.1280 + */ 1.1281 + private String name; 1.1282 + 1.1283 + /** The underlying file. 1.1284 + */ 1.1285 + final File f; 1.1286 + 1.1287 + public RegularFileObject(File f) { 1.1288 + this(f.getName(), f); 1.1289 + } 1.1290 + 1.1291 + public RegularFileObject(String name, File f) { 1.1292 + if (f.isDirectory()) 1.1293 + throw new IllegalArgumentException("directories not supported"); 1.1294 + this.name = name; 1.1295 + this.f = f; 1.1296 + } 1.1297 + 1.1298 + public InputStream openInputStream() throws IOException { 1.1299 + return new FileInputStream(f); 1.1300 + } 1.1301 + 1.1302 + protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) { 1.1303 + return JavacFileManager.this.getDecoder(getEncodingName(), ignoreEncodingErrors); 1.1304 + } 1.1305 + 1.1306 + public OutputStream openOutputStream() throws IOException { 1.1307 + ensureParentDirectoriesExist(); 1.1308 + return new FileOutputStream(f); 1.1309 + } 1.1310 + 1.1311 + public Writer openWriter() throws IOException { 1.1312 + ensureParentDirectoriesExist(); 1.1313 + return new OutputStreamWriter(new FileOutputStream(f), getEncodingName()); 1.1314 + } 1.1315 + 1.1316 + private void ensureParentDirectoriesExist() throws IOException { 1.1317 + if (!hasParents) { 1.1318 + File parent = f.getParentFile(); 1.1319 + if (parent != null && !parent.exists()) { 1.1320 + if (!parent.mkdirs()) { 1.1321 + // if the mkdirs failed, it may be because another process concurrently 1.1322 + // created the directory, so check if the directory got created 1.1323 + // anyway before throwing an exception 1.1324 + if (!parent.exists() || !parent.isDirectory()) 1.1325 + throw new IOException("could not create parent directories"); 1.1326 + } 1.1327 + } 1.1328 + hasParents = true; 1.1329 + } 1.1330 + } 1.1331 + 1.1332 + /** @deprecated see bug 6410637 */ 1.1333 + @Deprecated 1.1334 + public String getName() { 1.1335 + return name; 1.1336 + } 1.1337 + 1.1338 + public boolean isNameCompatible(String cn, JavaFileObject.Kind kind) { 1.1339 + cn.getClass(); // null check 1.1340 + if (kind == Kind.OTHER && getKind() != kind) 1.1341 + return false; 1.1342 + String n = cn + kind.extension; 1.1343 + if (name.equals(n)) 1.1344 + return true; 1.1345 + if (name.equalsIgnoreCase(n)) { 1.1346 + try { 1.1347 + // allow for Windows 1.1348 + return (f.getCanonicalFile().getName().equals(n)); 1.1349 + } catch (IOException e) { 1.1350 + } 1.1351 + } 1.1352 + return false; 1.1353 + } 1.1354 + 1.1355 + /** @deprecated see bug 6410637 */ 1.1356 + @Deprecated 1.1357 + public String getPath() { 1.1358 + return f.getPath(); 1.1359 + } 1.1360 + 1.1361 + public long getLastModified() { 1.1362 + return f.lastModified(); 1.1363 + } 1.1364 + 1.1365 + public boolean delete() { 1.1366 + return f.delete(); 1.1367 + } 1.1368 + 1.1369 + public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException { 1.1370 + SoftReference<CharBuffer> r = contentCache.get(this); 1.1371 + CharBuffer cb = (r == null ? null : r.get()); 1.1372 + if (cb == null) { 1.1373 + InputStream in = new FileInputStream(f); 1.1374 + try { 1.1375 + ByteBuffer bb = makeByteBuffer(in); 1.1376 + JavaFileObject prev = log.useSource(this); 1.1377 + try { 1.1378 + cb = decode(bb, ignoreEncodingErrors); 1.1379 + } finally { 1.1380 + log.useSource(prev); 1.1381 + } 1.1382 + byteBufferCache.put(bb); // save for next time 1.1383 + if (!ignoreEncodingErrors) 1.1384 + contentCache.put(this, new SoftReference<CharBuffer>(cb)); 1.1385 + } finally { 1.1386 + in.close(); 1.1387 + } 1.1388 + } 1.1389 + return cb; 1.1390 + } 1.1391 + 1.1392 + @Override 1.1393 + public boolean equals(Object other) { 1.1394 + if (!(other instanceof RegularFileObject)) 1.1395 + return false; 1.1396 + RegularFileObject o = (RegularFileObject) other; 1.1397 + try { 1.1398 + return f.equals(o.f) 1.1399 + || f.getCanonicalFile().equals(o.f.getCanonicalFile()); 1.1400 + } catch (IOException e) { 1.1401 + return false; 1.1402 + } 1.1403 + } 1.1404 + 1.1405 + @Override 1.1406 + public int hashCode() { 1.1407 + return f.hashCode(); 1.1408 + } 1.1409 + 1.1410 + public URI toUri() { 1.1411 + try { 1.1412 + // Do no use File.toURI to avoid file system access 1.1413 + String path = f.getAbsolutePath().replace(File.separatorChar, '/'); 1.1414 + return new URI("file://" + path).normalize(); 1.1415 + } catch (URISyntaxException ex) { 1.1416 + return f.toURI(); 1.1417 + } 1.1418 + } 1.1419 + 1.1420 + } 1.1421 + 1.1422 + /** 1.1423 + * A subclass of JavaFileObject representing zip entries. 1.1424 + */ 1.1425 + public class ZipFileObject extends BaseFileObject { 1.1426 + 1.1427 + /** The entry's name. 1.1428 + */ 1.1429 + private String name; 1.1430 + 1.1431 + /** The zipfile containing the entry. 1.1432 + */ 1.1433 + ZipFile zdir; 1.1434 + 1.1435 + /** The underlying zip entry object. 1.1436 + */ 1.1437 + ZipEntry entry; 1.1438 + 1.1439 + public ZipFileObject(String name, ZipFile zdir, ZipEntry entry) { 1.1440 + this.name = name; 1.1441 + this.zdir = zdir; 1.1442 + this.entry = entry; 1.1443 + } 1.1444 + 1.1445 + public InputStream openInputStream() throws IOException { 1.1446 + return zdir.getInputStream(entry); 1.1447 + } 1.1448 + 1.1449 + public OutputStream openOutputStream() throws IOException { 1.1450 + throw new UnsupportedOperationException(); 1.1451 + } 1.1452 + 1.1453 + protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) { 1.1454 + return JavacFileManager.this.getDecoder(getEncodingName(), ignoreEncodingErrors); 1.1455 + } 1.1456 + 1.1457 + public Writer openWriter() throws IOException { 1.1458 + throw new UnsupportedOperationException(); 1.1459 + } 1.1460 + 1.1461 + /** @deprecated see bug 6410637 */ 1.1462 + @Deprecated 1.1463 + public String getName() { 1.1464 + return name; 1.1465 + } 1.1466 + 1.1467 + public boolean isNameCompatible(String cn, JavaFileObject.Kind k) { 1.1468 + cn.getClass(); // null check 1.1469 + if (k == Kind.OTHER && getKind() != k) 1.1470 + return false; 1.1471 + return name.equals(cn + k.extension); 1.1472 + } 1.1473 + 1.1474 + /** @deprecated see bug 6410637 */ 1.1475 + @Deprecated 1.1476 + public String getPath() { 1.1477 + return zdir.getName() + "(" + entry + ")"; 1.1478 + } 1.1479 + 1.1480 + public long getLastModified() { 1.1481 + return entry.getTime(); 1.1482 + } 1.1483 + 1.1484 + public boolean delete() { 1.1485 + throw new UnsupportedOperationException(); 1.1486 + } 1.1487 + 1.1488 + public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException { 1.1489 + SoftReference<CharBuffer> r = contentCache.get(this); 1.1490 + CharBuffer cb = (r == null ? null : r.get()); 1.1491 + if (cb == null) { 1.1492 + InputStream in = zdir.getInputStream(entry); 1.1493 + try { 1.1494 + ByteBuffer bb = makeByteBuffer(in); 1.1495 + JavaFileObject prev = log.useSource(this); 1.1496 + try { 1.1497 + cb = decode(bb, ignoreEncodingErrors); 1.1498 + } finally { 1.1499 + log.useSource(prev); 1.1500 + } 1.1501 + byteBufferCache.put(bb); // save for next time 1.1502 + if (!ignoreEncodingErrors) 1.1503 + contentCache.put(this, new SoftReference<CharBuffer>(cb)); 1.1504 + } finally { 1.1505 + in.close(); 1.1506 + } 1.1507 + } 1.1508 + return cb; 1.1509 + } 1.1510 + 1.1511 + @Override 1.1512 + public boolean equals(Object other) { 1.1513 + if (!(other instanceof ZipFileObject)) 1.1514 + return false; 1.1515 + ZipFileObject o = (ZipFileObject) other; 1.1516 + return zdir.equals(o.zdir) || name.equals(o.name); 1.1517 + } 1.1518 + 1.1519 + @Override 1.1520 + public int hashCode() { 1.1521 + return zdir.hashCode() + name.hashCode(); 1.1522 + } 1.1523 + 1.1524 + public String getZipName() { 1.1525 + return zdir.getName(); 1.1526 + } 1.1527 + 1.1528 + public String getZipEntryName() { 1.1529 + return entry.getName(); 1.1530 + } 1.1531 + 1.1532 + public URI toUri() { 1.1533 + String zipName = new File(getZipName()).toURI().normalize().getPath(); 1.1534 + String entryName = getZipEntryName(); 1.1535 + return URI.create("jar:" + zipName + "!" + entryName); 1.1536 + } 1.1537 + 1.1538 + } 1.1539 + 1.1540 + /** 1.1541 + * A subclass of JavaFileObject representing zip entries using the com.sun.tools.javac.zip.ZipFileIndex implementation. 1.1542 + */ 1.1543 + public class ZipFileIndexFileObject extends BaseFileObject { 1.1544 + 1.1545 + /** The entry's name. 1.1546 + */ 1.1547 + private String name; 1.1548 + 1.1549 + /** The zipfile containing the entry. 1.1550 + */ 1.1551 + ZipFileIndex zfIndex; 1.1552 + 1.1553 + /** The underlying zip entry object. 1.1554 + */ 1.1555 + ZipFileIndexEntry entry; 1.1556 + 1.1557 + /** The InputStream for this zip entry (file.) 1.1558 + */ 1.1559 + InputStream inputStream = null; 1.1560 + 1.1561 + /** The name of the zip file where this entry resides. 1.1562 + */ 1.1563 + String zipName; 1.1564 + 1.1565 + JavacFileManager defFileManager = null; 1.1566 + 1.1567 + public ZipFileIndexFileObject(JavacFileManager fileManager, ZipFileIndex zfIndex, ZipFileIndexEntry entry, String zipFileName) { 1.1568 + super(); 1.1569 + this.name = entry.getFileName(); 1.1570 + this.zfIndex = zfIndex; 1.1571 + this.entry = entry; 1.1572 + this.zipName = zipFileName; 1.1573 + defFileManager = fileManager; 1.1574 + } 1.1575 + 1.1576 + public InputStream openInputStream() throws IOException { 1.1577 + 1.1578 + if (inputStream == null) { 1.1579 + inputStream = new ByteArrayInputStream(read()); 1.1580 + } 1.1581 + return inputStream; 1.1582 + } 1.1583 + 1.1584 + protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) { 1.1585 + return JavacFileManager.this.getDecoder(getEncodingName(), ignoreEncodingErrors); 1.1586 + } 1.1587 + 1.1588 + public OutputStream openOutputStream() throws IOException { 1.1589 + throw new UnsupportedOperationException(); 1.1590 + } 1.1591 + 1.1592 + public Writer openWriter() throws IOException { 1.1593 + throw new UnsupportedOperationException(); 1.1594 + } 1.1595 + 1.1596 + /** @deprecated see bug 6410637 */ 1.1597 + @Deprecated 1.1598 + public String getName() { 1.1599 + return name; 1.1600 + } 1.1601 + 1.1602 + public boolean isNameCompatible(String cn, JavaFileObject.Kind k) { 1.1603 + cn.getClass(); // null check 1.1604 + if (k == Kind.OTHER && getKind() != k) 1.1605 + return false; 1.1606 + return name.equals(cn + k.extension); 1.1607 + } 1.1608 + 1.1609 + /** @deprecated see bug 6410637 */ 1.1610 + @Deprecated 1.1611 + public String getPath() { 1.1612 + return entry.getName() + "(" + entry + ")"; 1.1613 + } 1.1614 + 1.1615 + public long getLastModified() { 1.1616 + return entry.getLastModified(); 1.1617 + } 1.1618 + 1.1619 + public boolean delete() { 1.1620 + throw new UnsupportedOperationException(); 1.1621 + } 1.1622 + 1.1623 + @Override 1.1624 + public boolean equals(Object other) { 1.1625 + if (!(other instanceof ZipFileIndexFileObject)) 1.1626 + return false; 1.1627 + ZipFileIndexFileObject o = (ZipFileIndexFileObject) other; 1.1628 + return entry.equals(o.entry); 1.1629 + } 1.1630 + 1.1631 + @Override 1.1632 + public int hashCode() { 1.1633 + return zipName.hashCode() + (name.hashCode() << 10); 1.1634 + } 1.1635 + 1.1636 + public String getZipName() { 1.1637 + return zipName; 1.1638 + } 1.1639 + 1.1640 + public String getZipEntryName() { 1.1641 + return entry.getName(); 1.1642 + } 1.1643 + 1.1644 + public URI toUri() { 1.1645 + String zipName = new File(getZipName()).toURI().normalize().getPath(); 1.1646 + String entryName = getZipEntryName(); 1.1647 + if (File.separatorChar != '/') { 1.1648 + entryName = entryName.replace(File.separatorChar, '/'); 1.1649 + } 1.1650 + return URI.create("jar:" + zipName + "!" + entryName); 1.1651 + } 1.1652 + 1.1653 + private byte[] read() throws IOException { 1.1654 + if (entry == null) { 1.1655 + entry = zfIndex.getZipIndexEntry(name); 1.1656 + if (entry == null) 1.1657 + throw new FileNotFoundException(); 1.1658 + } 1.1659 + return zfIndex.read(entry); 1.1660 + } 1.1661 + 1.1662 + public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException { 1.1663 + SoftReference<CharBuffer> r = defFileManager.contentCache.get(this); 1.1664 + CharBuffer cb = (r == null ? null : r.get()); 1.1665 + if (cb == null) { 1.1666 + InputStream in = new ByteArrayInputStream(zfIndex.read(entry)); 1.1667 + try { 1.1668 + ByteBuffer bb = makeByteBuffer(in); 1.1669 + JavaFileObject prev = log.useSource(this); 1.1670 + try { 1.1671 + cb = decode(bb, ignoreEncodingErrors); 1.1672 + } finally { 1.1673 + log.useSource(prev); 1.1674 + } 1.1675 + byteBufferCache.put(bb); // save for next time 1.1676 + if (!ignoreEncodingErrors) 1.1677 + defFileManager.contentCache.put(this, new SoftReference<CharBuffer>(cb)); 1.1678 + } finally { 1.1679 + in.close(); 1.1680 + } 1.1681 + } 1.1682 + return cb; 1.1683 + } 1.1684 + } 1.1685 + 1.1686 + public class ZipFileIndexArchive implements Archive { 1.1687 + private final ZipFileIndex zfIndex; 1.1688 + private JavacFileManager fileManager; 1.1689 + 1.1690 + public ZipFileIndexArchive(JavacFileManager fileManager, ZipFileIndex zdir) throws IOException { 1.1691 + this.fileManager = fileManager; 1.1692 + this.zfIndex = zdir; 1.1693 + } 1.1694 + 1.1695 + public boolean contains(String name) { 1.1696 + return zfIndex.contains(name); 1.1697 + } 1.1698 + 1.1699 + public com.sun.tools.javac.util.List<String> getFiles(String subdirectory) { 1.1700 + return zfIndex.getFiles(((subdirectory.endsWith("/") || subdirectory.endsWith("\\"))? subdirectory.substring(0, subdirectory.length() - 1) : subdirectory)); 1.1701 + } 1.1702 + 1.1703 + public JavaFileObject getFileObject(String subdirectory, String file) { 1.1704 + String fullZipFileName = subdirectory + file; 1.1705 + ZipFileIndexEntry entry = zfIndex.getZipIndexEntry(fullZipFileName); 1.1706 + JavaFileObject ret = new ZipFileIndexFileObject(fileManager, zfIndex, entry, zfIndex.getZipFile().getPath()); 1.1707 + return ret; 1.1708 + } 1.1709 + 1.1710 + public Set<String> getSubdirectories() { 1.1711 + return zfIndex.getAllDirectories(); 1.1712 + } 1.1713 + 1.1714 + public void close() throws IOException { 1.1715 + zfIndex.close(); 1.1716 + } 1.1717 + } 1.1718 +}