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 }