001 /*
002 * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package com.sun.tools.javac.file;
027
028 import java.io.File;
029 import java.io.IOException;
030 import java.io.InputStream;
031 import java.io.OutputStream;
032 import java.io.Writer;
033 import java.net.URI;
034 import java.nio.ByteBuffer;
035 import java.nio.CharBuffer;
036 import java.nio.charset.CharsetDecoder;
037 import java.util.Enumeration;
038 import java.util.HashMap;
039 import java.util.Map;
040 import java.util.Set;
041 import java.util.zip.ZipEntry;
042 import java.util.zip.ZipFile;
043
044 import javax.tools.JavaFileObject;
045
046 import com.sun.tools.javac.file.JavacFileManager.Archive;
047 import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
048 import com.sun.tools.javac.file.RelativePath.RelativeFile;
049 import com.sun.tools.javac.util.List;
050
051 public class ZipArchive implements Archive {
052
053 public ZipArchive(JavacFileManager fm, ZipFile zdir) throws IOException {
054 this(fm, zdir, true);
055 }
056
057 protected ZipArchive(JavacFileManager fm, ZipFile zdir, boolean initMap) throws IOException {
058 this.fileManager = fm;
059 this.zdir = zdir;
060 this.map = new HashMap<RelativeDirectory,List<String>>();
061 if (initMap)
062 initMap();
063 }
064
065 protected void initMap() throws IOException {
066 for (Enumeration<? extends ZipEntry> e = zdir.entries(); e.hasMoreElements(); ) {
067 ZipEntry entry;
068 try {
069 entry = e.nextElement();
070 } catch (InternalError ex) {
071 IOException io = new IOException();
072 io.initCause(ex); // convenience constructors added in Mustang :-(
073 throw io;
074 }
075 addZipEntry(entry);
076 }
077 }
078
079 void addZipEntry(ZipEntry entry) {
080 String name = entry.getName();
081 int i = name.lastIndexOf('/');
082 RelativeDirectory dirname = new RelativeDirectory(name.substring(0, i+1));
083 String basename = name.substring(i+1);
084 if (basename.length() == 0)
085 return;
086 List<String> list = map.get(dirname);
087 if (list == null)
088 list = List.nil();
089 list = list.prepend(basename);
090 map.put(dirname, list);
091 }
092
093 public boolean contains(RelativePath name) {
094 RelativeDirectory dirname = name.dirname();
095 String basename = name.basename();
096 if (basename.length() == 0)
097 return false;
098 List<String> list = map.get(dirname);
099 return (list != null && list.contains(basename));
100 }
101
102 public List<String> getFiles(RelativeDirectory subdirectory) {
103 return map.get(subdirectory);
104 }
105
106 public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
107 ZipEntry ze = new RelativeFile(subdirectory, file).getZipEntry(zdir);
108 return new ZipFileObject(this, file, ze);
109 }
110
111 public Set<RelativeDirectory> getSubdirectories() {
112 return map.keySet();
113 }
114
115 public void close() throws IOException {
116 zdir.close();
117 }
118
119 public String toString() {
120 return "ZipArchive[" + zdir.getName() + "]";
121 }
122
123 protected JavacFileManager fileManager;
124 protected final Map<RelativeDirectory,List<String>> map;
125 protected final ZipFile zdir;
126
127 /**
128 * A subclass of JavaFileObject representing zip entries.
129 */
130 public static class ZipFileObject extends BaseFileObject {
131
132 private String name;
133 ZipArchive zarch;
134 ZipEntry entry;
135
136 protected ZipFileObject(ZipArchive zarch, String name, ZipEntry entry) {
137 super(zarch.fileManager);
138 this.zarch = zarch;
139 this.name = name;
140 this.entry = entry;
141 }
142
143 public InputStream openInputStream() throws IOException {
144 return zarch.zdir.getInputStream(entry);
145 }
146
147 public OutputStream openOutputStream() throws IOException {
148 throw new UnsupportedOperationException();
149 }
150
151 protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
152 return fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
153 }
154
155 public Writer openWriter() throws IOException {
156 throw new UnsupportedOperationException();
157 }
158
159 @Deprecated
160 public String getName() {
161 return name;
162 }
163
164 public boolean isNameCompatible(String cn, JavaFileObject.Kind k) {
165 cn.getClass();
166 // null check
167 if (k == Kind.OTHER && getKind() != k) {
168 return false;
169 }
170 return name.equals(cn + k.extension);
171 }
172
173 @Deprecated
174 public String getPath() {
175 return zarch.zdir.getName() + "(" + entry + ")";
176 }
177
178 public long getLastModified() {
179 return entry.getTime();
180 }
181
182 public boolean delete() {
183 throw new UnsupportedOperationException();
184 }
185
186 public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
187 CharBuffer cb = fileManager.getCachedContent(this);
188 if (cb == null) {
189 InputStream in = zarch.zdir.getInputStream(entry);
190 try {
191 ByteBuffer bb = fileManager.makeByteBuffer(in);
192 JavaFileObject prev = fileManager.log.useSource(this);
193 try {
194 cb = fileManager.decode(bb, ignoreEncodingErrors);
195 } finally {
196 fileManager.log.useSource(prev);
197 }
198 fileManager.recycleByteBuffer(bb);
199 if (!ignoreEncodingErrors) {
200 fileManager.cache(this, cb);
201 }
202 } finally {
203 in.close();
204 }
205 }
206 return cb;
207 }
208
209 @Override
210 public boolean equals(Object other) {
211 if (!(other instanceof ZipFileObject)) {
212 return false;
213 }
214 ZipFileObject o = (ZipFileObject) other;
215 return zarch.zdir.equals(o.zarch.zdir) || name.equals(o.name);
216 }
217
218 @Override
219 public int hashCode() {
220 return zarch.zdir.hashCode() + name.hashCode();
221 }
222
223 public String getZipName() {
224 return zarch.zdir.getName();
225 }
226
227 public String getZipEntryName() {
228 return entry.getName();
229 }
230
231 public URI toUri() {
232 String zipName = new File(getZipName()).toURI().normalize().getPath();
233 String entryName = getZipEntryName();
234 return URI.create("jar:" + zipName + "!" + entryName);
235 }
236
237 @Override
238 protected String inferBinaryName(Iterable<? extends File> path) {
239 String entryName = getZipEntryName();
240 return removeExtension(entryName).replace('/', '.');
241 }
242 }
243
244 }