src/share/classes/com/sun/tools/javac/zip/ZipFileIndex.java

changeset 1
9a66ca7c79fa
child 36
58e352559a41
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/classes/com/sun/tools/javac/zip/ZipFileIndex.java	Sat Dec 01 00:00:00 2007 +0000
     1.3 @@ -0,0 +1,1211 @@
     1.4 +package com.sun.tools.javac.zip;
     1.5 +
     1.6 +import java.io.*;
     1.7 +import java.text.MessageFormat;
     1.8 +import java.util.*;
     1.9 +import java.util.List;
    1.10 +import java.util.concurrent.locks.ReentrantLock;
    1.11 +import java.util.zip.*;
    1.12 +
    1.13 +/** This class implements building of index of a zip archive and access to it's context.
    1.14 + *  It also uses prebuild index if available. It supports invocations where it will
    1.15 + *  serialize an optimized zip index file to disk.
    1.16 + *
    1.17 + *  In oreder to use secondary index file make sure the option "usezipindex" is in the Options object,
    1.18 + *  when JavacFileManager is invoked. (You can pass "-XDusezipindex" on the command line.
    1.19 + *
    1.20 + *  Location where to look for/generate optimized zip index files can be provided using
    1.21 + *  "-XDcachezipindexdir=<directory>". If this flag is not provided, the dfault location is
    1.22 + *  the value of the "java.io.tmpdir" system property.
    1.23 + *
    1.24 + *  If key "-XDwritezipindexfiles" is specified, there will be new optimized index file
    1.25 + *  created for each archive, used by the compiler for compilation, at location,
    1.26 + *  specified by "cachezipindexdir" option.
    1.27 + *
    1.28 + * If nonBatchMode option is specified (-XDnonBatchMode) the compiler will use timestamp
    1.29 + * checking to reindex the zip files if it is needed. In batch mode the timestamps are not checked
    1.30 + * and the compiler uses the cached indexes.
    1.31 + */
    1.32 +public class ZipFileIndex {
    1.33 +    private static final String MIN_CHAR = String.valueOf(Character.MIN_VALUE);
    1.34 +    private static final String MAX_CHAR = String.valueOf(Character.MAX_VALUE);
    1.35 +
    1.36 +    public final static long NOT_MODIFIED = Long.MIN_VALUE;
    1.37 +
    1.38 +    private static Map<File, ZipFileIndex> zipFileIndexCache = new HashMap<File, ZipFileIndex>();
    1.39 +    private static ReentrantLock lock = new ReentrantLock();
    1.40 +
    1.41 +    private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this.
    1.42 +
    1.43 +    private Map<String, DirectoryEntry> directories = Collections.<String, DirectoryEntry>emptyMap();
    1.44 +    private Set<String> allDirs = Collections.<String>emptySet();
    1.45 +
    1.46 +    // ZipFileIndex data entries
    1.47 +    private File zipFile;
    1.48 +    private long zipFileLastModified = NOT_MODIFIED;
    1.49 +    private RandomAccessFile zipRandomFile;
    1.50 +    private ZipFileIndexEntry[] entries;
    1.51 +
    1.52 +    private boolean readFromIndex = false;
    1.53 +    private File zipIndexFile = null;
    1.54 +    private boolean triedToReadIndex = false;
    1.55 +    private int symbolFilePrefixLength = 0;
    1.56 +    private boolean hasPopulatedData = false;
    1.57 +    private long lastReferenceTimeStamp = NOT_MODIFIED;
    1.58 +
    1.59 +    private boolean usePreindexedCache = false;
    1.60 +    private String preindexedCacheLocation = null;
    1.61 +
    1.62 +    private boolean writeIndex = false;
    1.63 +
    1.64 +    /**
    1.65 +     * Returns a list of all ZipFileIndex entries
    1.66 +     *
    1.67 +     * @return A list of ZipFileIndex entries, or an empty list
    1.68 +     */
    1.69 +    public static List<ZipFileIndex> getZipFileIndexes() {
    1.70 +        return getZipFileIndexes(false);
    1.71 +    }
    1.72 +
    1.73 +    /**
    1.74 +     * Returns a list of all ZipFileIndex entries
    1.75 +     *
    1.76 +     * @param openedOnly If true it returns a list of only opened ZipFileIndex entries, otherwise
    1.77 +     *                   all ZipFileEntry(s) are included into the list.
    1.78 +     * @return A list of ZipFileIndex entries, or an empty list
    1.79 +     */
    1.80 +    public static List<ZipFileIndex> getZipFileIndexes(boolean openedOnly) {
    1.81 +        List<ZipFileIndex> zipFileIndexes = new ArrayList<ZipFileIndex>();
    1.82 +        lock.lock();
    1.83 +        try {
    1.84 +            zipFileIndexes.addAll(zipFileIndexCache.values());
    1.85 +
    1.86 +            if (openedOnly) {
    1.87 +                for(ZipFileIndex elem : zipFileIndexes) {
    1.88 +                    if (!elem.isOpen()) {
    1.89 +                        zipFileIndexes.remove(elem);
    1.90 +                    }
    1.91 +                }
    1.92 +            }
    1.93 +        }
    1.94 +        finally {
    1.95 +            lock.unlock();
    1.96 +        }
    1.97 +        return zipFileIndexes;
    1.98 +    }
    1.99 +
   1.100 +    public boolean isOpen() {
   1.101 +        lock.lock();
   1.102 +        try {
   1.103 +            return zipRandomFile != null;
   1.104 +        }
   1.105 +        finally {
   1.106 +            lock.unlock();
   1.107 +        }
   1.108 +    }
   1.109 +
   1.110 +    public static ZipFileIndex getZipFileIndex(File zipFile, int symbolFilePrefixLen, boolean useCache, String cacheLocation, boolean writeIndex) throws IOException {
   1.111 +        ZipFileIndex zi = null;
   1.112 +        lock.lock();
   1.113 +        try {
   1.114 +            zi = getExistingZipIndex(zipFile);
   1.115 +
   1.116 +            if (zi == null || (zi != null && zipFile.lastModified() != zi.zipFileLastModified)) {
   1.117 +                zi = new ZipFileIndex(zipFile, symbolFilePrefixLen, writeIndex,
   1.118 +                        useCache, cacheLocation);
   1.119 +                zipFileIndexCache.put(zipFile, zi);
   1.120 +            }
   1.121 +        }
   1.122 +        finally {
   1.123 +            lock.unlock();
   1.124 +        }
   1.125 +        return zi;
   1.126 +    }
   1.127 +
   1.128 +    public static ZipFileIndex getExistingZipIndex(File zipFile) {
   1.129 +        lock.lock();
   1.130 +        try {
   1.131 +            return zipFileIndexCache.get(zipFile);
   1.132 +        }
   1.133 +        finally {
   1.134 +            lock.unlock();
   1.135 +        }
   1.136 +    }
   1.137 +
   1.138 +    public static void clearCache() {
   1.139 +        lock.lock();
   1.140 +        try {
   1.141 +            zipFileIndexCache.clear();
   1.142 +        }
   1.143 +        finally {
   1.144 +            lock.unlock();
   1.145 +        }
   1.146 +    }
   1.147 +
   1.148 +    public static void clearCache(long timeNotUsed) {
   1.149 +        lock.lock();
   1.150 +        try {
   1.151 +            Iterator<File> cachedFileIterator = zipFileIndexCache.keySet().iterator();
   1.152 +            while (cachedFileIterator.hasNext()) {
   1.153 +                File cachedFile = cachedFileIterator.next();
   1.154 +                ZipFileIndex cachedZipIndex = zipFileIndexCache.get(cachedFile);
   1.155 +                if (cachedZipIndex != null) {
   1.156 +                    long timeToTest = cachedZipIndex.lastReferenceTimeStamp + timeNotUsed;
   1.157 +                    if (timeToTest < cachedZipIndex.lastReferenceTimeStamp || // Overflow...
   1.158 +                            System.currentTimeMillis() > timeToTest) {
   1.159 +                        zipFileIndexCache.remove(cachedFile);
   1.160 +                    }
   1.161 +                }
   1.162 +            }
   1.163 +        }
   1.164 +        finally {
   1.165 +            lock.unlock();
   1.166 +        }
   1.167 +    }
   1.168 +
   1.169 +    public static void removeFromCache(File file) {
   1.170 +        lock.lock();
   1.171 +        try {
   1.172 +            zipFileIndexCache.remove(file);
   1.173 +        }
   1.174 +        finally {
   1.175 +            lock.unlock();
   1.176 +        }
   1.177 +    }
   1.178 +
   1.179 +    /** Sets already opened list of ZipFileIndexes from an outside client
   1.180 +      * of the compiler. This functionality should be used in a non-batch clients of the compiler.
   1.181 +      */
   1.182 +    public static void setOpenedIndexes(List<ZipFileIndex>indexes) throws IllegalStateException {
   1.183 +        lock.lock();
   1.184 +        try {
   1.185 +            if (zipFileIndexCache.isEmpty()) {
   1.186 +                throw new IllegalStateException("Setting opened indexes should be called only when the ZipFileCache is empty. Call JavacFileManager.flush() before calling this method.");
   1.187 +            }
   1.188 +
   1.189 +            for (ZipFileIndex zfi : indexes) {
   1.190 +                zipFileIndexCache.put(zfi.zipFile, zfi);
   1.191 +            }
   1.192 +        }
   1.193 +        finally {
   1.194 +            lock.unlock();
   1.195 +        }
   1.196 +    }
   1.197 +
   1.198 +    private ZipFileIndex(File zipFile, int symbolFilePrefixLen, boolean writeIndex,
   1.199 +            boolean useCache, String cacheLocation) throws IOException {
   1.200 +        this.zipFile = zipFile;
   1.201 +        this.symbolFilePrefixLength = symbolFilePrefixLen;
   1.202 +        this.writeIndex = writeIndex;
   1.203 +        this.usePreindexedCache = useCache;
   1.204 +        this.preindexedCacheLocation = cacheLocation;
   1.205 +
   1.206 +        if (zipFile != null) {
   1.207 +            this.zipFileLastModified = zipFile.lastModified();
   1.208 +        }
   1.209 +
   1.210 +        // Validate integrity of the zip file
   1.211 +        checkIndex();
   1.212 +    }
   1.213 +
   1.214 +    public String toString() {
   1.215 +        return "ZipFileIndex of file:(" + zipFile + ")";
   1.216 +    }
   1.217 +
   1.218 +    // Just in case...
   1.219 +    protected void finalize() {
   1.220 +        closeFile();
   1.221 +    }
   1.222 +
   1.223 +    private boolean isUpToDate() {
   1.224 +        if (zipFile != null &&
   1.225 +                ((!NON_BATCH_MODE) || zipFileLastModified == zipFile.lastModified()) &&
   1.226 +                hasPopulatedData) {
   1.227 +            return true;
   1.228 +        }
   1.229 +
   1.230 +        return false;
   1.231 +    }
   1.232 +
   1.233 +    /**
   1.234 +     * Here we need to make sure that the ZipFileIndex is valid. Check the timestamp of the file and
   1.235 +     * if its the same as the one at the time the index was build we don't need to reopen anything.
   1.236 +     */
   1.237 +    private void checkIndex() throws IOException {
   1.238 +        boolean isUpToDate = true;
   1.239 +        if (!isUpToDate()) {
   1.240 +            closeFile();
   1.241 +            isUpToDate = false;
   1.242 +        }
   1.243 +
   1.244 +        if (zipRandomFile != null || isUpToDate) {
   1.245 +            lastReferenceTimeStamp = System.currentTimeMillis();
   1.246 +            return;
   1.247 +        }
   1.248 +
   1.249 +        hasPopulatedData = true;
   1.250 +
   1.251 +        if (readIndex()) {
   1.252 +            lastReferenceTimeStamp = System.currentTimeMillis();
   1.253 +            return;
   1.254 +        }
   1.255 +
   1.256 +        directories = Collections.<String, DirectoryEntry>emptyMap();
   1.257 +        allDirs = Collections.<String>emptySet();
   1.258 +
   1.259 +        try {
   1.260 +            openFile();
   1.261 +            long totalLength = zipRandomFile.length();
   1.262 +            ZipDirectory directory = new ZipDirectory(zipRandomFile, 0L, totalLength, this);
   1.263 +            directory.buildIndex();
   1.264 +        } finally {
   1.265 +            if (zipRandomFile != null) {
   1.266 +                closeFile();
   1.267 +            }
   1.268 +        }
   1.269 +
   1.270 +        lastReferenceTimeStamp = System.currentTimeMillis();
   1.271 +    }
   1.272 +
   1.273 +    private void openFile() throws FileNotFoundException {
   1.274 +        if (zipRandomFile == null && zipFile != null) {
   1.275 +            zipRandomFile = new RandomAccessFile(zipFile, "r");
   1.276 +        }
   1.277 +    }
   1.278 +
   1.279 +    private void cleanupState() {
   1.280 +        // Make sure there is a valid but empty index if the file doesn't exist
   1.281 +        entries = ZipFileIndexEntry.EMPTY_ARRAY;
   1.282 +        directories = Collections.<String, DirectoryEntry>emptyMap();
   1.283 +        zipFileLastModified = NOT_MODIFIED;
   1.284 +        allDirs = Collections.<String>emptySet();
   1.285 +    }
   1.286 +
   1.287 +    public void close() {
   1.288 +        lock.lock();
   1.289 +        try {
   1.290 +            writeIndex();
   1.291 +            closeFile();
   1.292 +        }
   1.293 +        finally {
   1.294 +            lock.unlock();
   1.295 +        }
   1.296 +    }
   1.297 +
   1.298 +    private void closeFile() {
   1.299 +        if (zipRandomFile != null) {
   1.300 +            try {
   1.301 +                zipRandomFile.close();
   1.302 +            } catch (IOException ex) {
   1.303 +            }
   1.304 +            zipRandomFile = null;
   1.305 +        }
   1.306 +    }
   1.307 +
   1.308 +    /**
   1.309 +     * Returns the ZipFileIndexEntry for an absolute path, if there is one.
   1.310 +     */
   1.311 +    public ZipFileIndexEntry getZipIndexEntry(String path) {
   1.312 +        if (File.separatorChar != '/') {
   1.313 +            path = path.replace('/', File.separatorChar);
   1.314 +        }
   1.315 +        lock.lock();
   1.316 +        try {
   1.317 +            checkIndex();
   1.318 +            String lookFor = "";
   1.319 +            int lastSepIndex = path.lastIndexOf(File.separatorChar);
   1.320 +            boolean noSeparator = false;
   1.321 +            if (lastSepIndex == -1) {
   1.322 +                noSeparator = true;
   1.323 +            }
   1.324 +
   1.325 +            DirectoryEntry de = directories.get(noSeparator ? "" : path.substring(0, lastSepIndex));
   1.326 +
   1.327 +            lookFor = path.substring(noSeparator ? 0 : lastSepIndex + 1);
   1.328 +
   1.329 +            return de == null ? null : de.getEntry(lookFor);
   1.330 +        }
   1.331 +        catch (IOException e) {
   1.332 +            return null;
   1.333 +        }
   1.334 +        finally {
   1.335 +            lock.unlock();
   1.336 +        }
   1.337 +    }
   1.338 +
   1.339 +    /**
   1.340 +     * Returns a javac List of filenames within an absolute path in the ZipFileIndex.
   1.341 +     */
   1.342 +    public com.sun.tools.javac.util.List<String> getFiles(String path) {
   1.343 +        if (File.separatorChar != '/') {
   1.344 +            path = path.replace('/', File.separatorChar);
   1.345 +        }
   1.346 +
   1.347 +        lock.lock();
   1.348 +        try {
   1.349 +            checkIndex();
   1.350 +
   1.351 +            DirectoryEntry de = directories.get(path);
   1.352 +            com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getFiles();
   1.353 +
   1.354 +            if (ret == null) {
   1.355 +                return com.sun.tools.javac.util.List.<String>nil();
   1.356 +            }
   1.357 +            return ret;
   1.358 +        }
   1.359 +        catch (IOException e) {
   1.360 +            return com.sun.tools.javac.util.List.<String>nil();
   1.361 +        }
   1.362 +        finally {
   1.363 +            lock.unlock();
   1.364 +        }
   1.365 +    }
   1.366 +
   1.367 +    public List<String> getAllDirectories(String path) {
   1.368 +
   1.369 +        if (File.separatorChar != '/') {
   1.370 +            path = path.replace('/', File.separatorChar);
   1.371 +        }
   1.372 +
   1.373 +        lock.lock();
   1.374 +        try {
   1.375 +            checkIndex();
   1.376 +            path = path.intern();
   1.377 +
   1.378 +            DirectoryEntry de = directories.get(path);
   1.379 +            com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories();
   1.380 +
   1.381 +            if (ret == null) {
   1.382 +                return com.sun.tools.javac.util.List.<String>nil();
   1.383 +            }
   1.384 +
   1.385 +            return ret;
   1.386 +        }
   1.387 +        catch (IOException e) {
   1.388 +            return com.sun.tools.javac.util.List.<String>nil();
   1.389 +        }
   1.390 +        finally {
   1.391 +            lock.unlock();
   1.392 +        }
   1.393 +    }
   1.394 +
   1.395 +    public Set<String> getAllDirectories() {
   1.396 +        lock.lock();
   1.397 +        try {
   1.398 +            checkIndex();
   1.399 +            if (allDirs == Collections.EMPTY_SET) {
   1.400 +                Set<String> alldirs = new HashSet<String>();
   1.401 +                Iterator<String> dirsIter = directories.keySet().iterator();
   1.402 +                while (dirsIter.hasNext()) {
   1.403 +                    alldirs.add(new String(dirsIter.next()));
   1.404 +                }
   1.405 +
   1.406 +                allDirs = alldirs;
   1.407 +            }
   1.408 +
   1.409 +            return allDirs;
   1.410 +        }
   1.411 +        catch (IOException e) {
   1.412 +            return Collections.<String>emptySet();
   1.413 +        }
   1.414 +        finally {
   1.415 +            lock.unlock();
   1.416 +        }
   1.417 +    }
   1.418 +
   1.419 +    /**
   1.420 +     * Tests if a specific path exists in the zip.  This method will return true
   1.421 +     * for file entries and directories.
   1.422 +     *
   1.423 +     * @param path A path within the zip.
   1.424 +     * @return True if the path is a file or dir, false otherwise.
   1.425 +     */
   1.426 +    public boolean contains(String path) {
   1.427 +        lock.lock();
   1.428 +        try {
   1.429 +            checkIndex();
   1.430 +            return getZipIndexEntry(path) != null;
   1.431 +        }
   1.432 +        catch (IOException e) {
   1.433 +            return false;
   1.434 +        }
   1.435 +        finally {
   1.436 +            lock.unlock();
   1.437 +        }
   1.438 +    }
   1.439 +
   1.440 +    public boolean isDirectory(String path) throws IOException {
   1.441 +        lock.lock();
   1.442 +        try {
   1.443 +            // The top level in a zip file is always a directory.
   1.444 +            if (path.length() == 0) {
   1.445 +                lastReferenceTimeStamp = System.currentTimeMillis();
   1.446 +                return true;
   1.447 +            }
   1.448 +
   1.449 +            if (File.separatorChar != '/')
   1.450 +                path = path.replace('/', File.separatorChar);
   1.451 +            checkIndex();
   1.452 +            return directories.get(path) != null;
   1.453 +        }
   1.454 +        finally {
   1.455 +            lock.unlock();
   1.456 +        }
   1.457 +    }
   1.458 +
   1.459 +    public long getLastModified(String path) throws IOException {
   1.460 +        lock.lock();
   1.461 +        try {
   1.462 +            ZipFileIndexEntry entry = getZipIndexEntry(path);
   1.463 +            if (entry == null)
   1.464 +                throw new FileNotFoundException();
   1.465 +            return entry.getLastModified();
   1.466 +        }
   1.467 +        finally {
   1.468 +            lock.unlock();
   1.469 +        }
   1.470 +    }
   1.471 +
   1.472 +    public int length(String path) throws IOException {
   1.473 +        lock.lock();
   1.474 +        try {
   1.475 +            ZipFileIndexEntry entry = getZipIndexEntry(path);
   1.476 +            if (entry == null)
   1.477 +                throw new FileNotFoundException();
   1.478 +
   1.479 +            if (entry.isDir) {
   1.480 +                return 0;
   1.481 +            }
   1.482 +
   1.483 +            byte[] header = getHeader(entry);
   1.484 +            // entry is not compressed?
   1.485 +            if (get2ByteLittleEndian(header, 8) == 0) {
   1.486 +                return entry.compressedSize;
   1.487 +            } else {
   1.488 +                return entry.size;
   1.489 +            }
   1.490 +        }
   1.491 +        finally {
   1.492 +            lock.unlock();
   1.493 +        }
   1.494 +    }
   1.495 +
   1.496 +    public byte[] read(String path) throws IOException {
   1.497 +        lock.lock();
   1.498 +        try {
   1.499 +            ZipFileIndexEntry entry = getZipIndexEntry(path);
   1.500 +            if (entry == null)
   1.501 +                throw new FileNotFoundException(MessageFormat.format("Path not found in ZIP: {0}", path));
   1.502 +            return read(entry);
   1.503 +        }
   1.504 +        finally {
   1.505 +            lock.unlock();
   1.506 +        }
   1.507 +    }
   1.508 +
   1.509 +    public byte[] read(ZipFileIndexEntry entry) throws IOException {
   1.510 +        lock.lock();
   1.511 +        try {
   1.512 +            openFile();
   1.513 +            byte[] result = readBytes(entry);
   1.514 +            closeFile();
   1.515 +            return result;
   1.516 +        }
   1.517 +        finally {
   1.518 +            lock.unlock();
   1.519 +        }
   1.520 +    }
   1.521 +
   1.522 +    public int read(String path, byte[] buffer) throws IOException {
   1.523 +        lock.lock();
   1.524 +        try {
   1.525 +            ZipFileIndexEntry entry = getZipIndexEntry(path);
   1.526 +            if (entry == null)
   1.527 +                throw new FileNotFoundException();
   1.528 +            return read(entry, buffer);
   1.529 +        }
   1.530 +        finally {
   1.531 +            lock.unlock();
   1.532 +        }
   1.533 +    }
   1.534 +
   1.535 +    public int read(ZipFileIndexEntry entry, byte[] buffer)
   1.536 +            throws IOException {
   1.537 +        lock.lock();
   1.538 +        try {
   1.539 +            int result = readBytes(entry, buffer);
   1.540 +            return result;
   1.541 +        }
   1.542 +        finally {
   1.543 +            lock.unlock();
   1.544 +        }
   1.545 +    }
   1.546 +
   1.547 +    private byte[] readBytes(ZipFileIndexEntry entry) throws IOException {
   1.548 +        byte[] header = getHeader(entry);
   1.549 +        int csize = entry.compressedSize;
   1.550 +        byte[] cbuf = new byte[csize];
   1.551 +        zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
   1.552 +        zipRandomFile.readFully(cbuf, 0, csize);
   1.553 +
   1.554 +        // is this compressed - offset 8 in the ZipEntry header
   1.555 +        if (get2ByteLittleEndian(header, 8) == 0)
   1.556 +            return cbuf;
   1.557 +
   1.558 +        int size = entry.size;
   1.559 +        byte[] buf = new byte[size];
   1.560 +        if (inflate(cbuf, buf) != size)
   1.561 +            throw new ZipException("corrupted zip file");
   1.562 +
   1.563 +        return buf;
   1.564 +    }
   1.565 +
   1.566 +    /**
   1.567 +     *
   1.568 +     */
   1.569 +    private int readBytes(ZipFileIndexEntry entry, byte[] buffer) throws IOException {
   1.570 +        byte[] header = getHeader(entry);
   1.571 +
   1.572 +        // entry is not compressed?
   1.573 +        if (get2ByteLittleEndian(header, 8) == 0) {
   1.574 +            zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
   1.575 +            int offset = 0;
   1.576 +            int size = buffer.length;
   1.577 +            while (offset < size) {
   1.578 +                int count = zipRandomFile.read(buffer, offset, size - offset);
   1.579 +                if (count == -1)
   1.580 +                    break;
   1.581 +                offset += count;
   1.582 +            }
   1.583 +            return entry.size;
   1.584 +        }
   1.585 +
   1.586 +        int csize = entry.compressedSize;
   1.587 +        byte[] cbuf = new byte[csize];
   1.588 +        zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
   1.589 +        zipRandomFile.readFully(cbuf, 0, csize);
   1.590 +
   1.591 +        int count = inflate(cbuf, buffer);
   1.592 +        if (count == -1)
   1.593 +            throw new ZipException("corrupted zip file");
   1.594 +
   1.595 +        return entry.size;
   1.596 +    }
   1.597 +
   1.598 +    //----------------------------------------------------------------------------
   1.599 +    // Zip utilities
   1.600 +    //----------------------------------------------------------------------------
   1.601 +
   1.602 +    private byte[] getHeader(ZipFileIndexEntry entry) throws IOException {
   1.603 +        zipRandomFile.seek(entry.offset);
   1.604 +        byte[] header = new byte[30];
   1.605 +        zipRandomFile.readFully(header);
   1.606 +        if (get4ByteLittleEndian(header, 0) != 0x04034b50)
   1.607 +            throw new ZipException("corrupted zip file");
   1.608 +        if ((get2ByteLittleEndian(header, 6) & 1) != 0)
   1.609 +            throw new ZipException("encrypted zip file"); // offset 6 in the header of the ZipFileEntry
   1.610 +        return header;
   1.611 +    }
   1.612 +
   1.613 +  /*
   1.614 +   * Inflate using the java.util.zip.Inflater class
   1.615 +   */
   1.616 +    private static Inflater inflater;
   1.617 +    private int inflate(byte[] src, byte[] dest) {
   1.618 +
   1.619 +        // construct the inflater object or reuse an existing one
   1.620 +        if (inflater == null)
   1.621 +            inflater = new Inflater(true);
   1.622 +
   1.623 +        synchronized (inflater) {
   1.624 +            inflater.reset();
   1.625 +            inflater.setInput(src);
   1.626 +            try {
   1.627 +                return inflater.inflate(dest);
   1.628 +            } catch (DataFormatException ex) {
   1.629 +                return -1;
   1.630 +            }
   1.631 +        }
   1.632 +    }
   1.633 +
   1.634 +    /**
   1.635 +     * return the two bytes buf[pos], buf[pos+1] as an unsigned integer in little
   1.636 +     * endian format.
   1.637 +     */
   1.638 +    private static int get2ByteLittleEndian(byte[] buf, int pos) {
   1.639 +        return (buf[pos] & 0xFF) + ((buf[pos+1] & 0xFF) << 8);
   1.640 +    }
   1.641 +
   1.642 +    /**
   1.643 +     * return the 4 bytes buf[i..i+3] as an integer in little endian format.
   1.644 +     */
   1.645 +    private static int get4ByteLittleEndian(byte[] buf, int pos) {
   1.646 +        return (buf[pos] & 0xFF) + ((buf[pos + 1] & 0xFF) << 8) +
   1.647 +                ((buf[pos + 2] & 0xFF) << 16) + ((buf[pos + 3] & 0xFF) << 24);
   1.648 +    }
   1.649 +
   1.650 +    /* ----------------------------------------------------------------------------
   1.651 +     * ZipDirectory
   1.652 +     * ----------------------------------------------------------------------------*/
   1.653 +
   1.654 +    private class ZipDirectory {
   1.655 +        private String lastDir;
   1.656 +        private int lastStart;
   1.657 +        private int lastLen;
   1.658 +
   1.659 +        byte[] zipDir;
   1.660 +        RandomAccessFile zipRandomFile = null;
   1.661 +        ZipFileIndex zipFileIndex = null;
   1.662 +
   1.663 +        public ZipDirectory(RandomAccessFile zipRandomFile, long start, long end, ZipFileIndex index) throws IOException {
   1.664 +            this.zipRandomFile = zipRandomFile;
   1.665 +            this.zipFileIndex = index;
   1.666 +
   1.667 +            findCENRecord(start, end);
   1.668 +        }
   1.669 +
   1.670 +        /*
   1.671 +         * Reads zip file central directory.
   1.672 +         * For more details see readCEN in zip_util.c from the JDK sources.
   1.673 +         * This is a Java port of that function.
   1.674 +         */
   1.675 +        private void findCENRecord(long start, long end) throws IOException {
   1.676 +            long totalLength = end - start;
   1.677 +            int endbuflen = 1024;
   1.678 +            byte[] endbuf = new byte[endbuflen];
   1.679 +            long endbufend = end - start;
   1.680 +
   1.681 +            // There is a variable-length field after the dir offset record. We need to do consequential search.
   1.682 +            while (endbufend >= 22) {
   1.683 +                if (endbufend < endbuflen)
   1.684 +                    endbuflen = (int)endbufend;
   1.685 +                long endbufpos = endbufend - endbuflen;
   1.686 +                zipRandomFile.seek(start + endbufpos);
   1.687 +                zipRandomFile.readFully(endbuf, 0, endbuflen);
   1.688 +                int i = endbuflen - 22;
   1.689 +                while (i >= 0 &&
   1.690 +                        !(endbuf[i] == 0x50 &&
   1.691 +                        endbuf[i + 1] == 0x4b &&
   1.692 +                        endbuf[i + 2] == 0x05 &&
   1.693 +                        endbuf[i + 3] == 0x06 &&
   1.694 +                        endbufpos + i + 22 +
   1.695 +                        get2ByteLittleEndian(endbuf, i + 20) == totalLength)) {
   1.696 +                    i--;
   1.697 +                }
   1.698 +
   1.699 +                if (i >= 0) {
   1.700 +                    zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2];
   1.701 +                    zipDir[0] = endbuf[i + 10];
   1.702 +                    zipDir[1] = endbuf[i + 11];
   1.703 +                    zipRandomFile.seek(start + get4ByteLittleEndian(endbuf, i + 16));
   1.704 +                    zipRandomFile.readFully(zipDir, 2, zipDir.length - 2);
   1.705 +                    return;
   1.706 +                } else {
   1.707 +                    endbufend = endbufpos + 21;
   1.708 +                }
   1.709 +            }
   1.710 +            throw new ZipException("cannot read zip file");
   1.711 +        }
   1.712 +        private void buildIndex() throws IOException {
   1.713 +            int entryCount = get2ByteLittleEndian(zipDir, 0);
   1.714 +
   1.715 +            entries = new ZipFileIndexEntry[entryCount];
   1.716 +            // Add each of the files
   1.717 +            if (entryCount > 0) {
   1.718 +                directories = new HashMap<String, DirectoryEntry>();
   1.719 +                ArrayList<ZipFileIndexEntry> entryList = new ArrayList<ZipFileIndexEntry>();
   1.720 +                int pos = 2;
   1.721 +                for (int i = 0; i < entryCount; i++) {
   1.722 +                    pos = readEntry(pos, entryList, directories);
   1.723 +                }
   1.724 +
   1.725 +                // Add the accumulated dirs into the same list
   1.726 +                Iterator i = directories.keySet().iterator();
   1.727 +                while (i.hasNext()) {
   1.728 +                    ZipFileIndexEntry zipFileIndexEntry = new ZipFileIndexEntry( (String) i.next());
   1.729 +                    zipFileIndexEntry.isDir = true;
   1.730 +                    entryList.add(zipFileIndexEntry);
   1.731 +                }
   1.732 +
   1.733 +                entries = entryList.toArray(new ZipFileIndexEntry[entryList.size()]);
   1.734 +                Arrays.sort(entries);
   1.735 +            } else {
   1.736 +                cleanupState();
   1.737 +            }
   1.738 +        }
   1.739 +
   1.740 +        private int readEntry(int pos, List<ZipFileIndexEntry> entryList,
   1.741 +                Map<String, DirectoryEntry> directories) throws IOException {
   1.742 +            if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) {
   1.743 +                throw new ZipException("cannot read zip file entry");
   1.744 +            }
   1.745 +
   1.746 +            int dirStart = pos + 46;
   1.747 +            int fileStart = dirStart;
   1.748 +            int fileEnd = fileStart + get2ByteLittleEndian(zipDir, pos + 28);
   1.749 +
   1.750 +            if (zipFileIndex.symbolFilePrefixLength != 0 &&
   1.751 +                    ((fileEnd - fileStart) >= symbolFilePrefixLength)) {
   1.752 +                dirStart += zipFileIndex.symbolFilePrefixLength;
   1.753 +               fileStart += zipFileIndex.symbolFilePrefixLength;
   1.754 +            }
   1.755 +
   1.756 +            // Use the OS's path separator. Keep the position of the last one.
   1.757 +            for (int index = fileStart; index < fileEnd; index++) {
   1.758 +                byte nextByte = zipDir[index];
   1.759 +                if (nextByte == (byte)'\\' || nextByte == (byte)'/') {
   1.760 +                    zipDir[index] = (byte)File.separatorChar;
   1.761 +                    fileStart = index + 1;
   1.762 +                }
   1.763 +            }
   1.764 +
   1.765 +            String directory = null;
   1.766 +            if (fileStart == dirStart)
   1.767 +                directory = "";
   1.768 +            else if (lastDir != null && lastLen == fileStart - dirStart - 1) {
   1.769 +                int index = lastLen - 1;
   1.770 +                while (zipDir[lastStart + index] == zipDir[dirStart + index]) {
   1.771 +                    if (index == 0) {
   1.772 +                        directory = lastDir;
   1.773 +                        break;
   1.774 +                    }
   1.775 +                    index--;
   1.776 +                }
   1.777 +            }
   1.778 +
   1.779 +            // Sub directories
   1.780 +            if (directory == null) {
   1.781 +                lastStart = dirStart;
   1.782 +                lastLen = fileStart - dirStart - 1;
   1.783 +
   1.784 +                directory = new String(zipDir, dirStart, lastLen, "UTF-8").intern();
   1.785 +                lastDir = directory;
   1.786 +
   1.787 +                // Enter also all the parent directories
   1.788 +                String tempDirectory = directory;
   1.789 +
   1.790 +                while (directories.get(tempDirectory) == null) {
   1.791 +                    directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex));
   1.792 +                    int separator = tempDirectory.lastIndexOf(File.separatorChar);
   1.793 +                    if (separator == -1)
   1.794 +                        break;
   1.795 +                    tempDirectory = tempDirectory.substring(0, separator);
   1.796 +                }
   1.797 +            }
   1.798 +            else {
   1.799 +                directory = directory.intern();
   1.800 +                if (directories.get(directory) == null) {
   1.801 +                    directories.put(directory, new DirectoryEntry(directory, zipFileIndex));
   1.802 +                }
   1.803 +            }
   1.804 +
   1.805 +            // For each dir create also a file
   1.806 +            if (fileStart != fileEnd) {
   1.807 +                ZipFileIndexEntry entry = new ZipFileIndexEntry(directory,
   1.808 +                        new String(zipDir, fileStart, fileEnd - fileStart, "UTF-8"));
   1.809 +
   1.810 +                entry.setNativeTime(get4ByteLittleEndian(zipDir, pos + 12));
   1.811 +                entry.compressedSize = get4ByteLittleEndian(zipDir, pos + 20);
   1.812 +                entry.size = get4ByteLittleEndian(zipDir, pos + 24);
   1.813 +                entry.offset = get4ByteLittleEndian(zipDir, pos + 42);
   1.814 +                entryList.add(entry);
   1.815 +            }
   1.816 +
   1.817 +            return pos + 46 +
   1.818 +                    get2ByteLittleEndian(zipDir, pos + 28) +
   1.819 +                    get2ByteLittleEndian(zipDir, pos + 30) +
   1.820 +                    get2ByteLittleEndian(zipDir, pos + 32);
   1.821 +        }
   1.822 +    }
   1.823 +
   1.824 +    /**
   1.825 +     * Returns the last modified timestamp of a zip file.
   1.826 +     * @return long
   1.827 +     */
   1.828 +    public long getZipFileLastModified() throws IOException {
   1.829 +        lock.lock();
   1.830 +        try {
   1.831 +            checkIndex();
   1.832 +            return zipFileLastModified;
   1.833 +        }
   1.834 +        finally {
   1.835 +            lock.unlock();
   1.836 +        }
   1.837 +    }
   1.838 +
   1.839 +    /** ------------------------------------------------------------------------
   1.840 +     *  DirectoryEntry class
   1.841 +     * -------------------------------------------------------------------------*/
   1.842 +    static class DirectoryEntry {
   1.843 +        private boolean filesInited;
   1.844 +        private boolean directoriesInited;
   1.845 +        private boolean zipFileEntriesInited;
   1.846 +        private boolean entriesInited;
   1.847 +
   1.848 +        private long writtenOffsetOffset = 0;
   1.849 +
   1.850 +        private String dirName;
   1.851 +
   1.852 +        private com.sun.tools.javac.util.List<String> zipFileEntriesFiles = com.sun.tools.javac.util.List.<String>nil();
   1.853 +        private com.sun.tools.javac.util.List<String> zipFileEntriesDirectories = com.sun.tools.javac.util.List.<String>nil();
   1.854 +        private com.sun.tools.javac.util.List<ZipFileIndexEntry>  zipFileEntries = com.sun.tools.javac.util.List.<ZipFileIndexEntry>nil();
   1.855 +
   1.856 +        private List<ZipFileIndexEntry> entries = new ArrayList<ZipFileIndexEntry>();
   1.857 +
   1.858 +        private ZipFileIndex zipFileIndex;
   1.859 +
   1.860 +        private int numEntries;
   1.861 +
   1.862 +        DirectoryEntry(String dirName, ZipFileIndex index) {
   1.863 +        filesInited = false;
   1.864 +            directoriesInited = false;
   1.865 +            entriesInited = false;
   1.866 +
   1.867 +            if (File.separatorChar == '/') {
   1.868 +                dirName.replace('\\', '/');
   1.869 +            }
   1.870 +            else {
   1.871 +                dirName.replace('/', '\\');
   1.872 +            }
   1.873 +
   1.874 +            this.dirName = dirName.intern();
   1.875 +            this.zipFileIndex = index;
   1.876 +        }
   1.877 +
   1.878 +        private com.sun.tools.javac.util.List<String> getFiles() {
   1.879 +            if (filesInited) {
   1.880 +                return zipFileEntriesFiles;
   1.881 +            }
   1.882 +
   1.883 +            initEntries();
   1.884 +
   1.885 +            for (ZipFileIndexEntry e : entries) {
   1.886 +                if (!e.isDir) {
   1.887 +                    zipFileEntriesFiles = zipFileEntriesFiles.append(e.name);
   1.888 +                }
   1.889 +            }
   1.890 +            filesInited = true;
   1.891 +            return zipFileEntriesFiles;
   1.892 +        }
   1.893 +
   1.894 +        private com.sun.tools.javac.util.List<String> getDirectories() {
   1.895 +            if (directoriesInited) {
   1.896 +                return zipFileEntriesFiles;
   1.897 +            }
   1.898 +
   1.899 +            initEntries();
   1.900 +
   1.901 +            for (ZipFileIndexEntry e : entries) {
   1.902 +                if (e.isDir) {
   1.903 +                    zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name);
   1.904 +                }
   1.905 +            }
   1.906 +
   1.907 +            directoriesInited = true;
   1.908 +
   1.909 +            return zipFileEntriesDirectories;
   1.910 +        }
   1.911 +
   1.912 +        private com.sun.tools.javac.util.List<ZipFileIndexEntry> getEntries() {
   1.913 +            if (zipFileEntriesInited) {
   1.914 +                return zipFileEntries;
   1.915 +            }
   1.916 +
   1.917 +            initEntries();
   1.918 +
   1.919 +            zipFileEntries = com.sun.tools.javac.util.List.nil();
   1.920 +            for (ZipFileIndexEntry zfie : entries) {
   1.921 +                zipFileEntries = zipFileEntries.append(zfie);
   1.922 +            }
   1.923 +
   1.924 +            zipFileEntriesInited = true;
   1.925 +
   1.926 +            return zipFileEntries;
   1.927 +        }
   1.928 +
   1.929 +        private ZipFileIndexEntry getEntry(String rootName) {
   1.930 +            initEntries();
   1.931 +            int index = Collections.binarySearch(entries, new ZipFileIndexEntry(dirName, rootName));
   1.932 +            if (index < 0) {
   1.933 +                return null;
   1.934 +            }
   1.935 +
   1.936 +            return entries.get(index);
   1.937 +        }
   1.938 +
   1.939 +        private void initEntries() {
   1.940 +            if (entriesInited) {
   1.941 +                return;
   1.942 +            }
   1.943 +
   1.944 +            if (!zipFileIndex.readFromIndex) {
   1.945 +                int from = -Arrays.binarySearch(zipFileIndex.entries,
   1.946 +                        new ZipFileIndexEntry(dirName, ZipFileIndex.MIN_CHAR)) - 1;
   1.947 +                int to = -Arrays.binarySearch(zipFileIndex.entries,
   1.948 +                        new ZipFileIndexEntry(dirName, MAX_CHAR)) - 1;
   1.949 +
   1.950 +                boolean emptyList = false;
   1.951 +
   1.952 +                for (int i = from; i < to; i++) {
   1.953 +                    entries.add(zipFileIndex.entries[i]);
   1.954 +                }
   1.955 +            } else {
   1.956 +                File indexFile = zipFileIndex.getIndexFile();
   1.957 +                if (indexFile != null) {
   1.958 +                    RandomAccessFile raf = null;
   1.959 +                    try {
   1.960 +                        raf = new RandomAccessFile(indexFile, "r");
   1.961 +                        raf.seek(writtenOffsetOffset);
   1.962 +
   1.963 +                        for (int nFiles = 0; nFiles < numEntries; nFiles++) {
   1.964 +                            // Read the name bytes
   1.965 +                            int zfieNameBytesLen = raf.readInt();
   1.966 +                            byte [] zfieNameBytes = new byte[zfieNameBytesLen];
   1.967 +                            raf.read(zfieNameBytes);
   1.968 +                            String eName = new String(zfieNameBytes, "UTF-8");
   1.969 +
   1.970 +                            // Read isDir
   1.971 +                            boolean eIsDir = raf.readByte() == (byte)0 ? false : true;
   1.972 +
   1.973 +                            // Read offset of bytes in the real Jar/Zip file
   1.974 +                            int eOffset = raf.readInt();
   1.975 +
   1.976 +                            // Read size of the file in the real Jar/Zip file
   1.977 +                            int eSize = raf.readInt();
   1.978 +
   1.979 +                            // Read compressed size of the file in the real Jar/Zip file
   1.980 +                            int eCsize = raf.readInt();
   1.981 +
   1.982 +                            // Read java time stamp of the file in the real Jar/Zip file
   1.983 +                            long eJavaTimestamp = raf.readLong();
   1.984 +
   1.985 +                            ZipFileIndexEntry rfie = new ZipFileIndexEntry(dirName, eName);
   1.986 +                            rfie.isDir = eIsDir;
   1.987 +                            rfie.offset = eOffset;
   1.988 +                            rfie.size = eSize;
   1.989 +                            rfie.compressedSize = eCsize;
   1.990 +                            rfie.javatime = eJavaTimestamp;
   1.991 +                            entries.add(rfie);
   1.992 +                        }
   1.993 +                    } catch (Throwable t) {
   1.994 +                        // Do nothing
   1.995 +                    } finally {
   1.996 +                        try {
   1.997 +                            if (raf == null) {
   1.998 +                                raf.close();
   1.999 +                            }
  1.1000 +                        } catch (Throwable t) {
  1.1001 +                            // Do nothing
  1.1002 +                        }
  1.1003 +                    }
  1.1004 +                }
  1.1005 +            }
  1.1006 +
  1.1007 +            entriesInited = true;
  1.1008 +        }
  1.1009 +
  1.1010 +        List<ZipFileIndexEntry> getEntriesAsCollection() {
  1.1011 +            initEntries();
  1.1012 +
  1.1013 +            return entries;
  1.1014 +        }
  1.1015 +    }
  1.1016 +
  1.1017 +    private boolean readIndex() {
  1.1018 +        if (triedToReadIndex || !usePreindexedCache) {
  1.1019 +            return false;
  1.1020 +        }
  1.1021 +
  1.1022 +        boolean ret = false;
  1.1023 +        lock.lock();
  1.1024 +        try {
  1.1025 +            triedToReadIndex = true;
  1.1026 +            RandomAccessFile raf = null;
  1.1027 +            try {
  1.1028 +                File indexFileName = getIndexFile();
  1.1029 +                raf = new RandomAccessFile(indexFileName, "r");
  1.1030 +
  1.1031 +                long fileStamp = raf.readLong();
  1.1032 +                if (zipFile.lastModified() != fileStamp) {
  1.1033 +                    ret = false;
  1.1034 +                } else {
  1.1035 +                    directories = new HashMap<String, DirectoryEntry>();
  1.1036 +                    int numDirs = raf.readInt();
  1.1037 +                    for (int nDirs = 0; nDirs < numDirs; nDirs++) {
  1.1038 +                        int dirNameBytesLen = raf.readInt();
  1.1039 +                        byte [] dirNameBytes = new byte[dirNameBytesLen];
  1.1040 +                        raf.read(dirNameBytes);
  1.1041 +
  1.1042 +                        String dirNameStr = new String(dirNameBytes, "UTF-8");
  1.1043 +                        DirectoryEntry de = new DirectoryEntry(dirNameStr, this);
  1.1044 +                        de.numEntries = raf.readInt();
  1.1045 +                        de.writtenOffsetOffset = raf.readLong();
  1.1046 +                        directories.put(dirNameStr, de);
  1.1047 +                    }
  1.1048 +                    ret = true;
  1.1049 +                    zipFileLastModified = fileStamp;
  1.1050 +                }
  1.1051 +            } catch (Throwable t) {
  1.1052 +                // Do nothing
  1.1053 +            } finally {
  1.1054 +                if (raf != null) {
  1.1055 +                    try {
  1.1056 +                        raf.close();
  1.1057 +                    } catch (Throwable tt) {
  1.1058 +                        // Do nothing
  1.1059 +                    }
  1.1060 +                }
  1.1061 +            }
  1.1062 +            if (ret == true) {
  1.1063 +                readFromIndex = true;
  1.1064 +            }
  1.1065 +        }
  1.1066 +        finally {
  1.1067 +            lock.unlock();
  1.1068 +        }
  1.1069 +
  1.1070 +        return ret;
  1.1071 +    }
  1.1072 +
  1.1073 +    private boolean writeIndex() {
  1.1074 +        boolean ret = false;
  1.1075 +        if (readFromIndex || !usePreindexedCache) {
  1.1076 +            return true;
  1.1077 +        }
  1.1078 +
  1.1079 +        if (!writeIndex) {
  1.1080 +            return true;
  1.1081 +        }
  1.1082 +
  1.1083 +        File indexFile = getIndexFile();
  1.1084 +        if (indexFile == null) {
  1.1085 +            return false;
  1.1086 +        }
  1.1087 +
  1.1088 +        RandomAccessFile raf = null;
  1.1089 +        long writtenSoFar = 0;
  1.1090 +        try {
  1.1091 +            raf = new RandomAccessFile(indexFile, "rw");
  1.1092 +
  1.1093 +            raf.writeLong(zipFileLastModified);
  1.1094 +            writtenSoFar += 8;
  1.1095 +
  1.1096 +
  1.1097 +            Iterator<String> iterDirName = directories.keySet().iterator();
  1.1098 +            List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>();
  1.1099 +            Map<String, Long> offsets = new HashMap<String, Long>();
  1.1100 +            raf.writeInt(directories.keySet().size());
  1.1101 +            writtenSoFar += 4;
  1.1102 +
  1.1103 +            while(iterDirName.hasNext()) {
  1.1104 +                String dirName = iterDirName.next();
  1.1105 +                DirectoryEntry dirEntry = directories.get(dirName);
  1.1106 +
  1.1107 +                directoriesToWrite.add(dirEntry);
  1.1108 +
  1.1109 +                // Write the dir name bytes
  1.1110 +                byte [] dirNameBytes = dirName.getBytes("UTF-8");
  1.1111 +                int dirNameBytesLen = dirNameBytes.length;
  1.1112 +                raf.writeInt(dirNameBytesLen);
  1.1113 +                writtenSoFar += 4;
  1.1114 +
  1.1115 +                raf.write(dirNameBytes);
  1.1116 +                writtenSoFar += dirNameBytesLen;
  1.1117 +
  1.1118 +                // Write the number of files in the dir
  1.1119 +                List dirEntries = dirEntry.getEntriesAsCollection();
  1.1120 +                raf.writeInt(dirEntries.size());
  1.1121 +                writtenSoFar += 4;
  1.1122 +
  1.1123 +                offsets.put(dirName, new Long(writtenSoFar));
  1.1124 +
  1.1125 +                // Write the offset of the file's data in the dir
  1.1126 +                dirEntry.writtenOffsetOffset = 0L;
  1.1127 +                raf.writeLong(0L);
  1.1128 +                writtenSoFar += 8;
  1.1129 +            }
  1.1130 +
  1.1131 +            for (DirectoryEntry de : directoriesToWrite) {
  1.1132 +                // Fix up the offset in the directory table
  1.1133 +                long currFP = raf.getFilePointer();
  1.1134 +
  1.1135 +                long offsetOffset = offsets.get(de.dirName).longValue();
  1.1136 +                raf.seek(offsetOffset);
  1.1137 +                raf.writeLong(writtenSoFar);
  1.1138 +
  1.1139 +                raf.seek(currFP);
  1.1140 +
  1.1141 +                // Now write each of the files in the DirectoryEntry
  1.1142 +                List<ZipFileIndexEntry> entries = de.getEntriesAsCollection();
  1.1143 +                for (ZipFileIndexEntry zfie : entries) {
  1.1144 +                    // Write the name bytes
  1.1145 +                    byte [] zfieNameBytes = zfie.name.getBytes("UTF-8");
  1.1146 +                    int zfieNameBytesLen = zfieNameBytes.length;
  1.1147 +                    raf.writeInt(zfieNameBytesLen);
  1.1148 +                    writtenSoFar += 4;
  1.1149 +                    raf.write(zfieNameBytes);
  1.1150 +                    writtenSoFar += zfieNameBytesLen;
  1.1151 +
  1.1152 +                    // Write isDir
  1.1153 +                    raf.writeByte(zfie.isDir ? (byte)1 : (byte)0);
  1.1154 +                    writtenSoFar += 1;
  1.1155 +
  1.1156 +                    // Write offset of bytes in the real Jar/Zip file
  1.1157 +                    raf.writeInt(zfie.offset);
  1.1158 +                    writtenSoFar += 4;
  1.1159 +
  1.1160 +                    // Write size of the file in the real Jar/Zip file
  1.1161 +                    raf.writeInt(zfie.size);
  1.1162 +                    writtenSoFar += 4;
  1.1163 +
  1.1164 +                    // Write compressed size of the file in the real Jar/Zip file
  1.1165 +                    raf.writeInt(zfie.compressedSize);
  1.1166 +                    writtenSoFar += 4;
  1.1167 +
  1.1168 +                    // Write java time stamp of the file in the real Jar/Zip file
  1.1169 +                    raf.writeLong(zfie.getLastModified());
  1.1170 +                    writtenSoFar += 8;
  1.1171 +                }
  1.1172 +            }
  1.1173 +        } catch (Throwable t) {
  1.1174 +            // Do nothing
  1.1175 +        } finally {
  1.1176 +            try {
  1.1177 +                if (raf != null) {
  1.1178 +                    raf.close();
  1.1179 +                }
  1.1180 +            } catch(IOException ioe) {
  1.1181 +                // Do nothing
  1.1182 +            }
  1.1183 +        }
  1.1184 +
  1.1185 +        return ret;
  1.1186 +    }
  1.1187 +
  1.1188 +    public boolean writeZipIndex() {
  1.1189 +        lock.lock();
  1.1190 +        try {
  1.1191 +            return writeIndex();
  1.1192 +        }
  1.1193 +        finally {
  1.1194 +            lock.unlock();
  1.1195 +        }
  1.1196 +    }
  1.1197 +
  1.1198 +    private File getIndexFile() {
  1.1199 +        if (zipIndexFile == null) {
  1.1200 +            if (zipFile == null) {
  1.1201 +                return null;
  1.1202 +            }
  1.1203 +
  1.1204 +            zipIndexFile = new File((preindexedCacheLocation == null ? "" : preindexedCacheLocation) +
  1.1205 +                    zipFile.getName() + ".index");
  1.1206 +        }
  1.1207 +
  1.1208 +        return zipIndexFile;
  1.1209 +    }
  1.1210 +
  1.1211 +    public File getZipFile() {
  1.1212 +        return zipFile;
  1.1213 +    }
  1.1214 +}

mercurial