langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipArchive.java
changeset 34569 8b372e28f106
parent 34559 9229cc3b3802
parent 34568 afc0330fa0d4
child 34570 8a8f52a733dd
equal deleted inserted replaced
34559:9229cc3b3802 34569:8b372e28f106
     1 /*
       
     2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.javac.file;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.InputStream;
       
    30 import java.io.OutputStream;
       
    31 import java.io.Writer;
       
    32 import java.lang.ref.Reference;
       
    33 import java.lang.ref.SoftReference;
       
    34 import java.net.URI;
       
    35 import java.nio.ByteBuffer;
       
    36 import java.nio.CharBuffer;
       
    37 import java.nio.charset.CharsetDecoder;
       
    38 import java.nio.file.Path;
       
    39 import java.nio.file.Paths;
       
    40 import java.util.Enumeration;
       
    41 import java.util.HashMap;
       
    42 import java.util.Map;
       
    43 import java.util.Objects;
       
    44 import java.util.Set;
       
    45 import java.util.zip.ZipEntry;
       
    46 import java.util.zip.ZipFile;
       
    47 
       
    48 import javax.tools.JavaFileObject;
       
    49 
       
    50 import com.sun.tools.javac.file.JavacFileManager.Archive;
       
    51 import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
       
    52 import com.sun.tools.javac.file.RelativePath.RelativeFile;
       
    53 import com.sun.tools.javac.util.DefinedBy;
       
    54 import com.sun.tools.javac.util.DefinedBy.Api;
       
    55 import com.sun.tools.javac.util.List;
       
    56 
       
    57 /**
       
    58  * <p><b>This is NOT part of any supported API.
       
    59  * If you write code that depends on this, you do so at your own risk.
       
    60  * This code and its internal interfaces are subject to change or
       
    61  * deletion without notice.</b>
       
    62  */
       
    63 public class ZipArchive implements Archive {
       
    64 
       
    65     public ZipArchive(JavacFileManager fm, ZipFile zfile) throws IOException {
       
    66         this(fm, zfile, true);
       
    67     }
       
    68 
       
    69     protected ZipArchive(JavacFileManager fm, ZipFile zfile, boolean initMap) throws IOException {
       
    70         this.fileManager = fm;
       
    71         this.zfile = zfile;
       
    72         this.map = new HashMap<>();
       
    73         if (initMap)
       
    74             initMap();
       
    75     }
       
    76 
       
    77     protected void initMap() throws IOException {
       
    78         for (Enumeration<? extends ZipEntry> e = zfile.entries(); e.hasMoreElements(); ) {
       
    79             ZipEntry entry;
       
    80             try {
       
    81                 entry = e.nextElement();
       
    82             } catch (InternalError ex) {
       
    83                 IOException io = new IOException();
       
    84                 io.initCause(ex); // convenience constructors added in Mustang :-(
       
    85                 throw io;
       
    86             }
       
    87             addZipEntry(entry);
       
    88         }
       
    89     }
       
    90 
       
    91     void addZipEntry(ZipEntry entry) {
       
    92         String name = entry.getName();
       
    93         int i = name.lastIndexOf('/');
       
    94         RelativeDirectory dirname = new RelativeDirectory(name.substring(0, i+1));
       
    95         String basename = name.substring(i+1);
       
    96         if (basename.length() == 0)
       
    97             return;
       
    98         List<String> list = map.get(dirname);
       
    99         if (list == null)
       
   100             list = List.nil();
       
   101         list = list.prepend(basename);
       
   102         map.put(dirname, list);
       
   103     }
       
   104 
       
   105     public boolean contains(RelativePath name) {
       
   106         RelativeDirectory dirname = name.dirname();
       
   107         String basename = name.basename();
       
   108         if (basename.length() == 0)
       
   109             return false;
       
   110         List<String> list = map.get(dirname);
       
   111         return (list != null && list.contains(basename));
       
   112     }
       
   113 
       
   114     public List<String> getFiles(RelativeDirectory subdirectory) {
       
   115         return map.get(subdirectory);
       
   116     }
       
   117 
       
   118     public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
       
   119         ZipEntry ze = new RelativeFile(subdirectory, file).getZipEntry(zfile);
       
   120         return new ZipFileObject(this, file, ze);
       
   121     }
       
   122 
       
   123     public Set<RelativeDirectory> getSubdirectories() {
       
   124         return map.keySet();
       
   125     }
       
   126 
       
   127     public void close() throws IOException {
       
   128         zfile.close();
       
   129     }
       
   130 
       
   131     @Override
       
   132     public String toString() {
       
   133         return "ZipArchive[" + zfile.getName() + "]";
       
   134     }
       
   135 
       
   136     private Path getAbsoluteFile() {
       
   137         Path absFile = (absFileRef == null ? null : absFileRef.get());
       
   138         if (absFile == null) {
       
   139             absFile = Paths.get(zfile.getName()).toAbsolutePath();
       
   140             absFileRef = new SoftReference<>(absFile);
       
   141         }
       
   142         return absFile;
       
   143     }
       
   144 
       
   145     /**
       
   146      * The file manager that created this archive.
       
   147      */
       
   148     protected JavacFileManager fileManager;
       
   149     /**
       
   150      * The index for the contents of this archive.
       
   151      */
       
   152     protected final Map<RelativeDirectory,List<String>> map;
       
   153     /**
       
   154      * The zip file for the archive.
       
   155      */
       
   156     protected final ZipFile zfile;
       
   157     /**
       
   158      * A reference to the absolute filename for the zip file for the archive.
       
   159      */
       
   160     protected Reference<Path> absFileRef;
       
   161 
       
   162     /**
       
   163      * A subclass of JavaFileObject representing zip entries.
       
   164      */
       
   165     public static class ZipFileObject extends BaseFileObject {
       
   166 
       
   167         private String name;
       
   168         ZipArchive zarch;
       
   169         ZipEntry entry;
       
   170 
       
   171         protected ZipFileObject(ZipArchive zarch, String name, ZipEntry entry) {
       
   172             super(zarch.fileManager);
       
   173             this.zarch = zarch;
       
   174             this.name = name;
       
   175             this.entry = entry;
       
   176         }
       
   177 
       
   178         @DefinedBy(Api.COMPILER)
       
   179         public URI toUri() {
       
   180             Path zipFile = Paths.get(zarch.zfile.getName());
       
   181             return createJarUri(zipFile, entry.getName());
       
   182         }
       
   183 
       
   184         @Override @DefinedBy(Api.COMPILER)
       
   185         public String getName() {
       
   186             return zarch.zfile.getName() + "(" + entry.getName() + ")";
       
   187         }
       
   188 
       
   189         @Override
       
   190         public String getShortName() {
       
   191             return Paths.get(zarch.zfile.getName()).getFileName() + "(" + entry + ")";
       
   192         }
       
   193 
       
   194         @Override @DefinedBy(Api.COMPILER)
       
   195         public JavaFileObject.Kind getKind() {
       
   196             return getKind(entry.getName());
       
   197         }
       
   198 
       
   199         @Override @DefinedBy(Api.COMPILER)
       
   200         public InputStream openInputStream() throws IOException {
       
   201             return zarch.zfile.getInputStream(entry);
       
   202         }
       
   203 
       
   204         @Override @DefinedBy(Api.COMPILER)
       
   205         public OutputStream openOutputStream() throws IOException {
       
   206             throw new UnsupportedOperationException();
       
   207         }
       
   208 
       
   209         @Override @DefinedBy(Api.COMPILER)
       
   210         public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
       
   211             CharBuffer cb = fileManager.getCachedContent(this);
       
   212             if (cb == null) {
       
   213                 try (InputStream in = zarch.zfile.getInputStream(entry)) {
       
   214                     ByteBuffer bb = fileManager.makeByteBuffer(in);
       
   215                     JavaFileObject prev = fileManager.log.useSource(this);
       
   216                     try {
       
   217                         cb = fileManager.decode(bb, ignoreEncodingErrors);
       
   218                     } finally {
       
   219                         fileManager.log.useSource(prev);
       
   220                     }
       
   221                     fileManager.recycleByteBuffer(bb);
       
   222                     if (!ignoreEncodingErrors) {
       
   223                         fileManager.cache(this, cb);
       
   224                     }
       
   225                 }
       
   226             }
       
   227             return cb;
       
   228         }
       
   229 
       
   230         @Override @DefinedBy(Api.COMPILER)
       
   231         public Writer openWriter() throws IOException {
       
   232             throw new UnsupportedOperationException();
       
   233         }
       
   234 
       
   235         @Override @DefinedBy(Api.COMPILER)
       
   236         public long getLastModified() {
       
   237             return entry.getTime();
       
   238         }
       
   239 
       
   240         @Override @DefinedBy(Api.COMPILER)
       
   241         public boolean delete() {
       
   242             throw new UnsupportedOperationException();
       
   243         }
       
   244 
       
   245         @Override
       
   246         protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
       
   247             return fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
       
   248         }
       
   249 
       
   250         @Override
       
   251         protected String inferBinaryName(Iterable<? extends Path> path) {
       
   252             String entryName = entry.getName();
       
   253             return removeExtension(entryName).replace('/', '.');
       
   254         }
       
   255 
       
   256         @Override @DefinedBy(Api.COMPILER)
       
   257         public boolean isNameCompatible(String cn, JavaFileObject.Kind k) {
       
   258             Objects.requireNonNull(cn);
       
   259             // null check
       
   260             if (k == Kind.OTHER && getKind() != k) {
       
   261                 return false;
       
   262             }
       
   263             return name.equals(cn + k.extension);
       
   264         }
       
   265 
       
   266         /**
       
   267          * Check if two file objects are equal.
       
   268          * Two ZipFileObjects are equal if the absolute paths of the underlying
       
   269          * zip files are equal and if the paths within those zip files are equal.
       
   270          */
       
   271         @Override
       
   272         public boolean equals(Object other) {
       
   273             if (this == other)
       
   274                 return true;
       
   275 
       
   276             if (!(other instanceof ZipFileObject))
       
   277                 return false;
       
   278 
       
   279             ZipFileObject o = (ZipFileObject) other;
       
   280             return zarch.getAbsoluteFile().equals(o.zarch.getAbsoluteFile())
       
   281                     && entry.getName().equals(o.entry.getName());
       
   282         }
       
   283 
       
   284         @Override
       
   285         public int hashCode() {
       
   286             return zarch.getAbsoluteFile().hashCode() + entry.getName().hashCode();
       
   287         }
       
   288     }
       
   289 
       
   290 }