src/share/classes/com/sun/tools/javac/util/JavacFileManager.java

changeset 1
9a66ca7c79fa
child 38
65a447c75d4b
     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 +}

mercurial