View Javadoc
1   /*
2    * Copyright (c) 2005, 2011, 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.util.Set;
30  import javax.tools.JavaFileObject;
31  
32  import java.io.ByteArrayInputStream;
33  import java.io.File;
34  import java.io.InputStream;
35  import java.io.OutputStream;
36  import java.io.Writer;
37  import java.net.URI;
38  import java.nio.ByteBuffer;
39  import java.nio.CharBuffer;
40  import java.nio.charset.CharsetDecoder;
41  
42  import com.sun.tools.javac.file.JavacFileManager.Archive;
43  import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
44  import com.sun.tools.javac.file.RelativePath.RelativeFile;
45  import com.sun.tools.javac.util.Assert;
46  import com.sun.tools.javac.util.List;
47  
48  /**
49   * <p><b>This is NOT part of any supported API.
50   * If you write code that depends on this, you do so at your own risk.
51   * This code and its internal interfaces are subject to change or
52   * deletion without notice.</b>
53   */
54  public class ZipFileIndexArchive implements Archive {
55  
56      private final ZipFileIndex zfIndex;
57      private JavacFileManager fileManager;
58  
59      public ZipFileIndexArchive(JavacFileManager fileManager, ZipFileIndex zdir) throws IOException {
60          super();
61          this.fileManager = fileManager;
62          this.zfIndex = zdir;
63      }
64  
65      public boolean contains(RelativePath name) {
66          return zfIndex.contains(name);
67      }
68  
69      public List<String> getFiles(RelativeDirectory subdirectory) {
70          return zfIndex.getFiles(subdirectory);
71      }
72  
73      public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
74          RelativeFile fullZipFileName = new RelativeFile(subdirectory, file);
75          ZipFileIndex.Entry entry = zfIndex.getZipIndexEntry(fullZipFileName);
76          JavaFileObject ret = new ZipFileIndexFileObject(fileManager, zfIndex, entry, zfIndex.getZipFile());
77          return ret;
78      }
79  
80      public Set<RelativeDirectory> getSubdirectories() {
81          return zfIndex.getAllDirectories();
82      }
83  
84      public void close() throws IOException {
85          zfIndex.close();
86      }
87  
88      @Override
89      public String toString() {
90          return "ZipFileIndexArchive[" + zfIndex + "]";
91      }
92  
93      /**
94       * A subclass of JavaFileObject representing zip entries using the com.sun.tools.javac.file.ZipFileIndex implementation.
95       */
96      public static class ZipFileIndexFileObject extends BaseFileObject {
97  
98          /** The entry's name.
99           */
100         private String name;
101 
102         /** The zipfile containing the entry.
103          */
104         ZipFileIndex zfIndex;
105 
106         /** The underlying zip entry object.
107          */
108         ZipFileIndex.Entry entry;
109 
110         /** The InputStream for this zip entry (file.)
111          */
112         InputStream inputStream = null;
113 
114         /** The name of the zip file where this entry resides.
115          */
116         File zipName;
117 
118 
119         ZipFileIndexFileObject(JavacFileManager fileManager, ZipFileIndex zfIndex, ZipFileIndex.Entry entry, File zipFileName) {
120             super(fileManager);
121             this.name = entry.getFileName();
122             this.zfIndex = zfIndex;
123             this.entry = entry;
124             this.zipName = zipFileName;
125         }
126 
127         @Override
128         public URI toUri() {
129             return createJarUri(zipName, getPrefixedEntryName());
130         }
131 
132         @Override
133         public String getName() {
134             return zipName + "(" + getPrefixedEntryName() + ")";
135         }
136 
137         @Override
138         public String getShortName() {
139             return zipName.getName() + "(" + entry.getName() + ")";
140         }
141 
142         @Override
143         public JavaFileObject.Kind getKind() {
144             return getKind(entry.getName());
145         }
146 
147         @Override
148         public InputStream openInputStream() throws IOException {
149             if (inputStream == null) {
150                 Assert.checkNonNull(entry); // see constructor
151                 inputStream = new ByteArrayInputStream(zfIndex.read(entry));
152             }
153             return inputStream;
154         }
155 
156         @Override
157         public OutputStream openOutputStream() throws IOException {
158             throw new UnsupportedOperationException();
159         }
160 
161         @Override
162         public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
163             CharBuffer cb = fileManager.getCachedContent(this);
164             if (cb == null) {
165                 InputStream in = new ByteArrayInputStream(zfIndex.read(entry));
166                 try {
167                     ByteBuffer bb = fileManager.makeByteBuffer(in);
168                     JavaFileObject prev = fileManager.log.useSource(this);
169                     try {
170                         cb = fileManager.decode(bb, ignoreEncodingErrors);
171                     } finally {
172                         fileManager.log.useSource(prev);
173                     }
174                     fileManager.recycleByteBuffer(bb); // save for next time
175                     if (!ignoreEncodingErrors)
176                         fileManager.cache(this, cb);
177                 } finally {
178                     in.close();
179                 }
180             }
181             return cb;
182         }
183 
184         @Override
185         public Writer openWriter() throws IOException {
186             throw new UnsupportedOperationException();
187         }
188 
189         @Override
190         public long getLastModified() {
191             return entry.getLastModified();
192         }
193 
194         @Override
195         public boolean delete() {
196             throw new UnsupportedOperationException();
197         }
198 
199         @Override
200         protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
201             return fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
202         }
203 
204         @Override
205         protected String inferBinaryName(Iterable<? extends File> path) {
206             String entryName = entry.getName();
207             if (zfIndex.symbolFilePrefix != null) {
208                 String prefix = zfIndex.symbolFilePrefix.path;
209                 if (entryName.startsWith(prefix))
210                     entryName = entryName.substring(prefix.length());
211             }
212             return removeExtension(entryName).replace('/', '.');
213         }
214 
215         @Override
216         public boolean isNameCompatible(String cn, JavaFileObject.Kind k) {
217             cn.getClass(); // null check
218             if (k == Kind.OTHER && getKind() != k)
219                 return false;
220             return name.equals(cn + k.extension);
221         }
222 
223         /**
224          * Check if two file objects are equal.
225          * Two ZipFileIndexFileObjects are equal if the absolute paths of the underlying
226          * zip files are equal and if the paths within those zip files are equal.
227          */
228         @Override
229         public boolean equals(Object other) {
230             if (this == other)
231                 return true;
232 
233             if (!(other instanceof ZipFileIndexFileObject))
234                 return false;
235 
236             ZipFileIndexFileObject o = (ZipFileIndexFileObject) other;
237             return zfIndex.getAbsoluteFile().equals(o.zfIndex.getAbsoluteFile())
238                     && name.equals(o.name);
239         }
240 
241         @Override
242         public int hashCode() {
243             return zfIndex.getAbsoluteFile().hashCode() + name.hashCode();
244         }
245 
246         private String getPrefixedEntryName() {
247             if (zfIndex.symbolFilePrefix != null)
248                 return zfIndex.symbolFilePrefix.path + entry.getName();
249             else
250                 return entry.getName();
251         }
252     }
253 
254 }