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

Sat, 01 Dec 2007 00:00:00 +0000

author
duke
date
Sat, 01 Dec 2007 00:00:00 +0000
changeset 1
9a66ca7c79fa
child 36
58e352559a41
permissions
-rw-r--r--

Initial load

duke@1 1 package com.sun.tools.javac.zip;
duke@1 2
duke@1 3 import java.io.*;
duke@1 4 import java.text.MessageFormat;
duke@1 5 import java.util.*;
duke@1 6 import java.util.List;
duke@1 7 import java.util.concurrent.locks.ReentrantLock;
duke@1 8 import java.util.zip.*;
duke@1 9
duke@1 10 /** This class implements building of index of a zip archive and access to it's context.
duke@1 11 * It also uses prebuild index if available. It supports invocations where it will
duke@1 12 * serialize an optimized zip index file to disk.
duke@1 13 *
duke@1 14 * In oreder to use secondary index file make sure the option "usezipindex" is in the Options object,
duke@1 15 * when JavacFileManager is invoked. (You can pass "-XDusezipindex" on the command line.
duke@1 16 *
duke@1 17 * Location where to look for/generate optimized zip index files can be provided using
duke@1 18 * "-XDcachezipindexdir=<directory>". If this flag is not provided, the dfault location is
duke@1 19 * the value of the "java.io.tmpdir" system property.
duke@1 20 *
duke@1 21 * If key "-XDwritezipindexfiles" is specified, there will be new optimized index file
duke@1 22 * created for each archive, used by the compiler for compilation, at location,
duke@1 23 * specified by "cachezipindexdir" option.
duke@1 24 *
duke@1 25 * If nonBatchMode option is specified (-XDnonBatchMode) the compiler will use timestamp
duke@1 26 * checking to reindex the zip files if it is needed. In batch mode the timestamps are not checked
duke@1 27 * and the compiler uses the cached indexes.
duke@1 28 */
duke@1 29 public class ZipFileIndex {
duke@1 30 private static final String MIN_CHAR = String.valueOf(Character.MIN_VALUE);
duke@1 31 private static final String MAX_CHAR = String.valueOf(Character.MAX_VALUE);
duke@1 32
duke@1 33 public final static long NOT_MODIFIED = Long.MIN_VALUE;
duke@1 34
duke@1 35 private static Map<File, ZipFileIndex> zipFileIndexCache = new HashMap<File, ZipFileIndex>();
duke@1 36 private static ReentrantLock lock = new ReentrantLock();
duke@1 37
duke@1 38 private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this.
duke@1 39
duke@1 40 private Map<String, DirectoryEntry> directories = Collections.<String, DirectoryEntry>emptyMap();
duke@1 41 private Set<String> allDirs = Collections.<String>emptySet();
duke@1 42
duke@1 43 // ZipFileIndex data entries
duke@1 44 private File zipFile;
duke@1 45 private long zipFileLastModified = NOT_MODIFIED;
duke@1 46 private RandomAccessFile zipRandomFile;
duke@1 47 private ZipFileIndexEntry[] entries;
duke@1 48
duke@1 49 private boolean readFromIndex = false;
duke@1 50 private File zipIndexFile = null;
duke@1 51 private boolean triedToReadIndex = false;
duke@1 52 private int symbolFilePrefixLength = 0;
duke@1 53 private boolean hasPopulatedData = false;
duke@1 54 private long lastReferenceTimeStamp = NOT_MODIFIED;
duke@1 55
duke@1 56 private boolean usePreindexedCache = false;
duke@1 57 private String preindexedCacheLocation = null;
duke@1 58
duke@1 59 private boolean writeIndex = false;
duke@1 60
duke@1 61 /**
duke@1 62 * Returns a list of all ZipFileIndex entries
duke@1 63 *
duke@1 64 * @return A list of ZipFileIndex entries, or an empty list
duke@1 65 */
duke@1 66 public static List<ZipFileIndex> getZipFileIndexes() {
duke@1 67 return getZipFileIndexes(false);
duke@1 68 }
duke@1 69
duke@1 70 /**
duke@1 71 * Returns a list of all ZipFileIndex entries
duke@1 72 *
duke@1 73 * @param openedOnly If true it returns a list of only opened ZipFileIndex entries, otherwise
duke@1 74 * all ZipFileEntry(s) are included into the list.
duke@1 75 * @return A list of ZipFileIndex entries, or an empty list
duke@1 76 */
duke@1 77 public static List<ZipFileIndex> getZipFileIndexes(boolean openedOnly) {
duke@1 78 List<ZipFileIndex> zipFileIndexes = new ArrayList<ZipFileIndex>();
duke@1 79 lock.lock();
duke@1 80 try {
duke@1 81 zipFileIndexes.addAll(zipFileIndexCache.values());
duke@1 82
duke@1 83 if (openedOnly) {
duke@1 84 for(ZipFileIndex elem : zipFileIndexes) {
duke@1 85 if (!elem.isOpen()) {
duke@1 86 zipFileIndexes.remove(elem);
duke@1 87 }
duke@1 88 }
duke@1 89 }
duke@1 90 }
duke@1 91 finally {
duke@1 92 lock.unlock();
duke@1 93 }
duke@1 94 return zipFileIndexes;
duke@1 95 }
duke@1 96
duke@1 97 public boolean isOpen() {
duke@1 98 lock.lock();
duke@1 99 try {
duke@1 100 return zipRandomFile != null;
duke@1 101 }
duke@1 102 finally {
duke@1 103 lock.unlock();
duke@1 104 }
duke@1 105 }
duke@1 106
duke@1 107 public static ZipFileIndex getZipFileIndex(File zipFile, int symbolFilePrefixLen, boolean useCache, String cacheLocation, boolean writeIndex) throws IOException {
duke@1 108 ZipFileIndex zi = null;
duke@1 109 lock.lock();
duke@1 110 try {
duke@1 111 zi = getExistingZipIndex(zipFile);
duke@1 112
duke@1 113 if (zi == null || (zi != null && zipFile.lastModified() != zi.zipFileLastModified)) {
duke@1 114 zi = new ZipFileIndex(zipFile, symbolFilePrefixLen, writeIndex,
duke@1 115 useCache, cacheLocation);
duke@1 116 zipFileIndexCache.put(zipFile, zi);
duke@1 117 }
duke@1 118 }
duke@1 119 finally {
duke@1 120 lock.unlock();
duke@1 121 }
duke@1 122 return zi;
duke@1 123 }
duke@1 124
duke@1 125 public static ZipFileIndex getExistingZipIndex(File zipFile) {
duke@1 126 lock.lock();
duke@1 127 try {
duke@1 128 return zipFileIndexCache.get(zipFile);
duke@1 129 }
duke@1 130 finally {
duke@1 131 lock.unlock();
duke@1 132 }
duke@1 133 }
duke@1 134
duke@1 135 public static void clearCache() {
duke@1 136 lock.lock();
duke@1 137 try {
duke@1 138 zipFileIndexCache.clear();
duke@1 139 }
duke@1 140 finally {
duke@1 141 lock.unlock();
duke@1 142 }
duke@1 143 }
duke@1 144
duke@1 145 public static void clearCache(long timeNotUsed) {
duke@1 146 lock.lock();
duke@1 147 try {
duke@1 148 Iterator<File> cachedFileIterator = zipFileIndexCache.keySet().iterator();
duke@1 149 while (cachedFileIterator.hasNext()) {
duke@1 150 File cachedFile = cachedFileIterator.next();
duke@1 151 ZipFileIndex cachedZipIndex = zipFileIndexCache.get(cachedFile);
duke@1 152 if (cachedZipIndex != null) {
duke@1 153 long timeToTest = cachedZipIndex.lastReferenceTimeStamp + timeNotUsed;
duke@1 154 if (timeToTest < cachedZipIndex.lastReferenceTimeStamp || // Overflow...
duke@1 155 System.currentTimeMillis() > timeToTest) {
duke@1 156 zipFileIndexCache.remove(cachedFile);
duke@1 157 }
duke@1 158 }
duke@1 159 }
duke@1 160 }
duke@1 161 finally {
duke@1 162 lock.unlock();
duke@1 163 }
duke@1 164 }
duke@1 165
duke@1 166 public static void removeFromCache(File file) {
duke@1 167 lock.lock();
duke@1 168 try {
duke@1 169 zipFileIndexCache.remove(file);
duke@1 170 }
duke@1 171 finally {
duke@1 172 lock.unlock();
duke@1 173 }
duke@1 174 }
duke@1 175
duke@1 176 /** Sets already opened list of ZipFileIndexes from an outside client
duke@1 177 * of the compiler. This functionality should be used in a non-batch clients of the compiler.
duke@1 178 */
duke@1 179 public static void setOpenedIndexes(List<ZipFileIndex>indexes) throws IllegalStateException {
duke@1 180 lock.lock();
duke@1 181 try {
duke@1 182 if (zipFileIndexCache.isEmpty()) {
duke@1 183 throw new IllegalStateException("Setting opened indexes should be called only when the ZipFileCache is empty. Call JavacFileManager.flush() before calling this method.");
duke@1 184 }
duke@1 185
duke@1 186 for (ZipFileIndex zfi : indexes) {
duke@1 187 zipFileIndexCache.put(zfi.zipFile, zfi);
duke@1 188 }
duke@1 189 }
duke@1 190 finally {
duke@1 191 lock.unlock();
duke@1 192 }
duke@1 193 }
duke@1 194
duke@1 195 private ZipFileIndex(File zipFile, int symbolFilePrefixLen, boolean writeIndex,
duke@1 196 boolean useCache, String cacheLocation) throws IOException {
duke@1 197 this.zipFile = zipFile;
duke@1 198 this.symbolFilePrefixLength = symbolFilePrefixLen;
duke@1 199 this.writeIndex = writeIndex;
duke@1 200 this.usePreindexedCache = useCache;
duke@1 201 this.preindexedCacheLocation = cacheLocation;
duke@1 202
duke@1 203 if (zipFile != null) {
duke@1 204 this.zipFileLastModified = zipFile.lastModified();
duke@1 205 }
duke@1 206
duke@1 207 // Validate integrity of the zip file
duke@1 208 checkIndex();
duke@1 209 }
duke@1 210
duke@1 211 public String toString() {
duke@1 212 return "ZipFileIndex of file:(" + zipFile + ")";
duke@1 213 }
duke@1 214
duke@1 215 // Just in case...
duke@1 216 protected void finalize() {
duke@1 217 closeFile();
duke@1 218 }
duke@1 219
duke@1 220 private boolean isUpToDate() {
duke@1 221 if (zipFile != null &&
duke@1 222 ((!NON_BATCH_MODE) || zipFileLastModified == zipFile.lastModified()) &&
duke@1 223 hasPopulatedData) {
duke@1 224 return true;
duke@1 225 }
duke@1 226
duke@1 227 return false;
duke@1 228 }
duke@1 229
duke@1 230 /**
duke@1 231 * Here we need to make sure that the ZipFileIndex is valid. Check the timestamp of the file and
duke@1 232 * if its the same as the one at the time the index was build we don't need to reopen anything.
duke@1 233 */
duke@1 234 private void checkIndex() throws IOException {
duke@1 235 boolean isUpToDate = true;
duke@1 236 if (!isUpToDate()) {
duke@1 237 closeFile();
duke@1 238 isUpToDate = false;
duke@1 239 }
duke@1 240
duke@1 241 if (zipRandomFile != null || isUpToDate) {
duke@1 242 lastReferenceTimeStamp = System.currentTimeMillis();
duke@1 243 return;
duke@1 244 }
duke@1 245
duke@1 246 hasPopulatedData = true;
duke@1 247
duke@1 248 if (readIndex()) {
duke@1 249 lastReferenceTimeStamp = System.currentTimeMillis();
duke@1 250 return;
duke@1 251 }
duke@1 252
duke@1 253 directories = Collections.<String, DirectoryEntry>emptyMap();
duke@1 254 allDirs = Collections.<String>emptySet();
duke@1 255
duke@1 256 try {
duke@1 257 openFile();
duke@1 258 long totalLength = zipRandomFile.length();
duke@1 259 ZipDirectory directory = new ZipDirectory(zipRandomFile, 0L, totalLength, this);
duke@1 260 directory.buildIndex();
duke@1 261 } finally {
duke@1 262 if (zipRandomFile != null) {
duke@1 263 closeFile();
duke@1 264 }
duke@1 265 }
duke@1 266
duke@1 267 lastReferenceTimeStamp = System.currentTimeMillis();
duke@1 268 }
duke@1 269
duke@1 270 private void openFile() throws FileNotFoundException {
duke@1 271 if (zipRandomFile == null && zipFile != null) {
duke@1 272 zipRandomFile = new RandomAccessFile(zipFile, "r");
duke@1 273 }
duke@1 274 }
duke@1 275
duke@1 276 private void cleanupState() {
duke@1 277 // Make sure there is a valid but empty index if the file doesn't exist
duke@1 278 entries = ZipFileIndexEntry.EMPTY_ARRAY;
duke@1 279 directories = Collections.<String, DirectoryEntry>emptyMap();
duke@1 280 zipFileLastModified = NOT_MODIFIED;
duke@1 281 allDirs = Collections.<String>emptySet();
duke@1 282 }
duke@1 283
duke@1 284 public void close() {
duke@1 285 lock.lock();
duke@1 286 try {
duke@1 287 writeIndex();
duke@1 288 closeFile();
duke@1 289 }
duke@1 290 finally {
duke@1 291 lock.unlock();
duke@1 292 }
duke@1 293 }
duke@1 294
duke@1 295 private void closeFile() {
duke@1 296 if (zipRandomFile != null) {
duke@1 297 try {
duke@1 298 zipRandomFile.close();
duke@1 299 } catch (IOException ex) {
duke@1 300 }
duke@1 301 zipRandomFile = null;
duke@1 302 }
duke@1 303 }
duke@1 304
duke@1 305 /**
duke@1 306 * Returns the ZipFileIndexEntry for an absolute path, if there is one.
duke@1 307 */
duke@1 308 public ZipFileIndexEntry getZipIndexEntry(String path) {
duke@1 309 if (File.separatorChar != '/') {
duke@1 310 path = path.replace('/', File.separatorChar);
duke@1 311 }
duke@1 312 lock.lock();
duke@1 313 try {
duke@1 314 checkIndex();
duke@1 315 String lookFor = "";
duke@1 316 int lastSepIndex = path.lastIndexOf(File.separatorChar);
duke@1 317 boolean noSeparator = false;
duke@1 318 if (lastSepIndex == -1) {
duke@1 319 noSeparator = true;
duke@1 320 }
duke@1 321
duke@1 322 DirectoryEntry de = directories.get(noSeparator ? "" : path.substring(0, lastSepIndex));
duke@1 323
duke@1 324 lookFor = path.substring(noSeparator ? 0 : lastSepIndex + 1);
duke@1 325
duke@1 326 return de == null ? null : de.getEntry(lookFor);
duke@1 327 }
duke@1 328 catch (IOException e) {
duke@1 329 return null;
duke@1 330 }
duke@1 331 finally {
duke@1 332 lock.unlock();
duke@1 333 }
duke@1 334 }
duke@1 335
duke@1 336 /**
duke@1 337 * Returns a javac List of filenames within an absolute path in the ZipFileIndex.
duke@1 338 */
duke@1 339 public com.sun.tools.javac.util.List<String> getFiles(String path) {
duke@1 340 if (File.separatorChar != '/') {
duke@1 341 path = path.replace('/', File.separatorChar);
duke@1 342 }
duke@1 343
duke@1 344 lock.lock();
duke@1 345 try {
duke@1 346 checkIndex();
duke@1 347
duke@1 348 DirectoryEntry de = directories.get(path);
duke@1 349 com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getFiles();
duke@1 350
duke@1 351 if (ret == null) {
duke@1 352 return com.sun.tools.javac.util.List.<String>nil();
duke@1 353 }
duke@1 354 return ret;
duke@1 355 }
duke@1 356 catch (IOException e) {
duke@1 357 return com.sun.tools.javac.util.List.<String>nil();
duke@1 358 }
duke@1 359 finally {
duke@1 360 lock.unlock();
duke@1 361 }
duke@1 362 }
duke@1 363
duke@1 364 public List<String> getAllDirectories(String path) {
duke@1 365
duke@1 366 if (File.separatorChar != '/') {
duke@1 367 path = path.replace('/', File.separatorChar);
duke@1 368 }
duke@1 369
duke@1 370 lock.lock();
duke@1 371 try {
duke@1 372 checkIndex();
duke@1 373 path = path.intern();
duke@1 374
duke@1 375 DirectoryEntry de = directories.get(path);
duke@1 376 com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories();
duke@1 377
duke@1 378 if (ret == null) {
duke@1 379 return com.sun.tools.javac.util.List.<String>nil();
duke@1 380 }
duke@1 381
duke@1 382 return ret;
duke@1 383 }
duke@1 384 catch (IOException e) {
duke@1 385 return com.sun.tools.javac.util.List.<String>nil();
duke@1 386 }
duke@1 387 finally {
duke@1 388 lock.unlock();
duke@1 389 }
duke@1 390 }
duke@1 391
duke@1 392 public Set<String> getAllDirectories() {
duke@1 393 lock.lock();
duke@1 394 try {
duke@1 395 checkIndex();
duke@1 396 if (allDirs == Collections.EMPTY_SET) {
duke@1 397 Set<String> alldirs = new HashSet<String>();
duke@1 398 Iterator<String> dirsIter = directories.keySet().iterator();
duke@1 399 while (dirsIter.hasNext()) {
duke@1 400 alldirs.add(new String(dirsIter.next()));
duke@1 401 }
duke@1 402
duke@1 403 allDirs = alldirs;
duke@1 404 }
duke@1 405
duke@1 406 return allDirs;
duke@1 407 }
duke@1 408 catch (IOException e) {
duke@1 409 return Collections.<String>emptySet();
duke@1 410 }
duke@1 411 finally {
duke@1 412 lock.unlock();
duke@1 413 }
duke@1 414 }
duke@1 415
duke@1 416 /**
duke@1 417 * Tests if a specific path exists in the zip. This method will return true
duke@1 418 * for file entries and directories.
duke@1 419 *
duke@1 420 * @param path A path within the zip.
duke@1 421 * @return True if the path is a file or dir, false otherwise.
duke@1 422 */
duke@1 423 public boolean contains(String path) {
duke@1 424 lock.lock();
duke@1 425 try {
duke@1 426 checkIndex();
duke@1 427 return getZipIndexEntry(path) != null;
duke@1 428 }
duke@1 429 catch (IOException e) {
duke@1 430 return false;
duke@1 431 }
duke@1 432 finally {
duke@1 433 lock.unlock();
duke@1 434 }
duke@1 435 }
duke@1 436
duke@1 437 public boolean isDirectory(String path) throws IOException {
duke@1 438 lock.lock();
duke@1 439 try {
duke@1 440 // The top level in a zip file is always a directory.
duke@1 441 if (path.length() == 0) {
duke@1 442 lastReferenceTimeStamp = System.currentTimeMillis();
duke@1 443 return true;
duke@1 444 }
duke@1 445
duke@1 446 if (File.separatorChar != '/')
duke@1 447 path = path.replace('/', File.separatorChar);
duke@1 448 checkIndex();
duke@1 449 return directories.get(path) != null;
duke@1 450 }
duke@1 451 finally {
duke@1 452 lock.unlock();
duke@1 453 }
duke@1 454 }
duke@1 455
duke@1 456 public long getLastModified(String path) throws IOException {
duke@1 457 lock.lock();
duke@1 458 try {
duke@1 459 ZipFileIndexEntry entry = getZipIndexEntry(path);
duke@1 460 if (entry == null)
duke@1 461 throw new FileNotFoundException();
duke@1 462 return entry.getLastModified();
duke@1 463 }
duke@1 464 finally {
duke@1 465 lock.unlock();
duke@1 466 }
duke@1 467 }
duke@1 468
duke@1 469 public int length(String path) throws IOException {
duke@1 470 lock.lock();
duke@1 471 try {
duke@1 472 ZipFileIndexEntry entry = getZipIndexEntry(path);
duke@1 473 if (entry == null)
duke@1 474 throw new FileNotFoundException();
duke@1 475
duke@1 476 if (entry.isDir) {
duke@1 477 return 0;
duke@1 478 }
duke@1 479
duke@1 480 byte[] header = getHeader(entry);
duke@1 481 // entry is not compressed?
duke@1 482 if (get2ByteLittleEndian(header, 8) == 0) {
duke@1 483 return entry.compressedSize;
duke@1 484 } else {
duke@1 485 return entry.size;
duke@1 486 }
duke@1 487 }
duke@1 488 finally {
duke@1 489 lock.unlock();
duke@1 490 }
duke@1 491 }
duke@1 492
duke@1 493 public byte[] read(String path) throws IOException {
duke@1 494 lock.lock();
duke@1 495 try {
duke@1 496 ZipFileIndexEntry entry = getZipIndexEntry(path);
duke@1 497 if (entry == null)
duke@1 498 throw new FileNotFoundException(MessageFormat.format("Path not found in ZIP: {0}", path));
duke@1 499 return read(entry);
duke@1 500 }
duke@1 501 finally {
duke@1 502 lock.unlock();
duke@1 503 }
duke@1 504 }
duke@1 505
duke@1 506 public byte[] read(ZipFileIndexEntry entry) throws IOException {
duke@1 507 lock.lock();
duke@1 508 try {
duke@1 509 openFile();
duke@1 510 byte[] result = readBytes(entry);
duke@1 511 closeFile();
duke@1 512 return result;
duke@1 513 }
duke@1 514 finally {
duke@1 515 lock.unlock();
duke@1 516 }
duke@1 517 }
duke@1 518
duke@1 519 public int read(String path, byte[] buffer) throws IOException {
duke@1 520 lock.lock();
duke@1 521 try {
duke@1 522 ZipFileIndexEntry entry = getZipIndexEntry(path);
duke@1 523 if (entry == null)
duke@1 524 throw new FileNotFoundException();
duke@1 525 return read(entry, buffer);
duke@1 526 }
duke@1 527 finally {
duke@1 528 lock.unlock();
duke@1 529 }
duke@1 530 }
duke@1 531
duke@1 532 public int read(ZipFileIndexEntry entry, byte[] buffer)
duke@1 533 throws IOException {
duke@1 534 lock.lock();
duke@1 535 try {
duke@1 536 int result = readBytes(entry, buffer);
duke@1 537 return result;
duke@1 538 }
duke@1 539 finally {
duke@1 540 lock.unlock();
duke@1 541 }
duke@1 542 }
duke@1 543
duke@1 544 private byte[] readBytes(ZipFileIndexEntry entry) throws IOException {
duke@1 545 byte[] header = getHeader(entry);
duke@1 546 int csize = entry.compressedSize;
duke@1 547 byte[] cbuf = new byte[csize];
duke@1 548 zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
duke@1 549 zipRandomFile.readFully(cbuf, 0, csize);
duke@1 550
duke@1 551 // is this compressed - offset 8 in the ZipEntry header
duke@1 552 if (get2ByteLittleEndian(header, 8) == 0)
duke@1 553 return cbuf;
duke@1 554
duke@1 555 int size = entry.size;
duke@1 556 byte[] buf = new byte[size];
duke@1 557 if (inflate(cbuf, buf) != size)
duke@1 558 throw new ZipException("corrupted zip file");
duke@1 559
duke@1 560 return buf;
duke@1 561 }
duke@1 562
duke@1 563 /**
duke@1 564 *
duke@1 565 */
duke@1 566 private int readBytes(ZipFileIndexEntry entry, byte[] buffer) throws IOException {
duke@1 567 byte[] header = getHeader(entry);
duke@1 568
duke@1 569 // entry is not compressed?
duke@1 570 if (get2ByteLittleEndian(header, 8) == 0) {
duke@1 571 zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
duke@1 572 int offset = 0;
duke@1 573 int size = buffer.length;
duke@1 574 while (offset < size) {
duke@1 575 int count = zipRandomFile.read(buffer, offset, size - offset);
duke@1 576 if (count == -1)
duke@1 577 break;
duke@1 578 offset += count;
duke@1 579 }
duke@1 580 return entry.size;
duke@1 581 }
duke@1 582
duke@1 583 int csize = entry.compressedSize;
duke@1 584 byte[] cbuf = new byte[csize];
duke@1 585 zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
duke@1 586 zipRandomFile.readFully(cbuf, 0, csize);
duke@1 587
duke@1 588 int count = inflate(cbuf, buffer);
duke@1 589 if (count == -1)
duke@1 590 throw new ZipException("corrupted zip file");
duke@1 591
duke@1 592 return entry.size;
duke@1 593 }
duke@1 594
duke@1 595 //----------------------------------------------------------------------------
duke@1 596 // Zip utilities
duke@1 597 //----------------------------------------------------------------------------
duke@1 598
duke@1 599 private byte[] getHeader(ZipFileIndexEntry entry) throws IOException {
duke@1 600 zipRandomFile.seek(entry.offset);
duke@1 601 byte[] header = new byte[30];
duke@1 602 zipRandomFile.readFully(header);
duke@1 603 if (get4ByteLittleEndian(header, 0) != 0x04034b50)
duke@1 604 throw new ZipException("corrupted zip file");
duke@1 605 if ((get2ByteLittleEndian(header, 6) & 1) != 0)
duke@1 606 throw new ZipException("encrypted zip file"); // offset 6 in the header of the ZipFileEntry
duke@1 607 return header;
duke@1 608 }
duke@1 609
duke@1 610 /*
duke@1 611 * Inflate using the java.util.zip.Inflater class
duke@1 612 */
duke@1 613 private static Inflater inflater;
duke@1 614 private int inflate(byte[] src, byte[] dest) {
duke@1 615
duke@1 616 // construct the inflater object or reuse an existing one
duke@1 617 if (inflater == null)
duke@1 618 inflater = new Inflater(true);
duke@1 619
duke@1 620 synchronized (inflater) {
duke@1 621 inflater.reset();
duke@1 622 inflater.setInput(src);
duke@1 623 try {
duke@1 624 return inflater.inflate(dest);
duke@1 625 } catch (DataFormatException ex) {
duke@1 626 return -1;
duke@1 627 }
duke@1 628 }
duke@1 629 }
duke@1 630
duke@1 631 /**
duke@1 632 * return the two bytes buf[pos], buf[pos+1] as an unsigned integer in little
duke@1 633 * endian format.
duke@1 634 */
duke@1 635 private static int get2ByteLittleEndian(byte[] buf, int pos) {
duke@1 636 return (buf[pos] & 0xFF) + ((buf[pos+1] & 0xFF) << 8);
duke@1 637 }
duke@1 638
duke@1 639 /**
duke@1 640 * return the 4 bytes buf[i..i+3] as an integer in little endian format.
duke@1 641 */
duke@1 642 private static int get4ByteLittleEndian(byte[] buf, int pos) {
duke@1 643 return (buf[pos] & 0xFF) + ((buf[pos + 1] & 0xFF) << 8) +
duke@1 644 ((buf[pos + 2] & 0xFF) << 16) + ((buf[pos + 3] & 0xFF) << 24);
duke@1 645 }
duke@1 646
duke@1 647 /* ----------------------------------------------------------------------------
duke@1 648 * ZipDirectory
duke@1 649 * ----------------------------------------------------------------------------*/
duke@1 650
duke@1 651 private class ZipDirectory {
duke@1 652 private String lastDir;
duke@1 653 private int lastStart;
duke@1 654 private int lastLen;
duke@1 655
duke@1 656 byte[] zipDir;
duke@1 657 RandomAccessFile zipRandomFile = null;
duke@1 658 ZipFileIndex zipFileIndex = null;
duke@1 659
duke@1 660 public ZipDirectory(RandomAccessFile zipRandomFile, long start, long end, ZipFileIndex index) throws IOException {
duke@1 661 this.zipRandomFile = zipRandomFile;
duke@1 662 this.zipFileIndex = index;
duke@1 663
duke@1 664 findCENRecord(start, end);
duke@1 665 }
duke@1 666
duke@1 667 /*
duke@1 668 * Reads zip file central directory.
duke@1 669 * For more details see readCEN in zip_util.c from the JDK sources.
duke@1 670 * This is a Java port of that function.
duke@1 671 */
duke@1 672 private void findCENRecord(long start, long end) throws IOException {
duke@1 673 long totalLength = end - start;
duke@1 674 int endbuflen = 1024;
duke@1 675 byte[] endbuf = new byte[endbuflen];
duke@1 676 long endbufend = end - start;
duke@1 677
duke@1 678 // There is a variable-length field after the dir offset record. We need to do consequential search.
duke@1 679 while (endbufend >= 22) {
duke@1 680 if (endbufend < endbuflen)
duke@1 681 endbuflen = (int)endbufend;
duke@1 682 long endbufpos = endbufend - endbuflen;
duke@1 683 zipRandomFile.seek(start + endbufpos);
duke@1 684 zipRandomFile.readFully(endbuf, 0, endbuflen);
duke@1 685 int i = endbuflen - 22;
duke@1 686 while (i >= 0 &&
duke@1 687 !(endbuf[i] == 0x50 &&
duke@1 688 endbuf[i + 1] == 0x4b &&
duke@1 689 endbuf[i + 2] == 0x05 &&
duke@1 690 endbuf[i + 3] == 0x06 &&
duke@1 691 endbufpos + i + 22 +
duke@1 692 get2ByteLittleEndian(endbuf, i + 20) == totalLength)) {
duke@1 693 i--;
duke@1 694 }
duke@1 695
duke@1 696 if (i >= 0) {
duke@1 697 zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2];
duke@1 698 zipDir[0] = endbuf[i + 10];
duke@1 699 zipDir[1] = endbuf[i + 11];
duke@1 700 zipRandomFile.seek(start + get4ByteLittleEndian(endbuf, i + 16));
duke@1 701 zipRandomFile.readFully(zipDir, 2, zipDir.length - 2);
duke@1 702 return;
duke@1 703 } else {
duke@1 704 endbufend = endbufpos + 21;
duke@1 705 }
duke@1 706 }
duke@1 707 throw new ZipException("cannot read zip file");
duke@1 708 }
duke@1 709 private void buildIndex() throws IOException {
duke@1 710 int entryCount = get2ByteLittleEndian(zipDir, 0);
duke@1 711
duke@1 712 entries = new ZipFileIndexEntry[entryCount];
duke@1 713 // Add each of the files
duke@1 714 if (entryCount > 0) {
duke@1 715 directories = new HashMap<String, DirectoryEntry>();
duke@1 716 ArrayList<ZipFileIndexEntry> entryList = new ArrayList<ZipFileIndexEntry>();
duke@1 717 int pos = 2;
duke@1 718 for (int i = 0; i < entryCount; i++) {
duke@1 719 pos = readEntry(pos, entryList, directories);
duke@1 720 }
duke@1 721
duke@1 722 // Add the accumulated dirs into the same list
duke@1 723 Iterator i = directories.keySet().iterator();
duke@1 724 while (i.hasNext()) {
duke@1 725 ZipFileIndexEntry zipFileIndexEntry = new ZipFileIndexEntry( (String) i.next());
duke@1 726 zipFileIndexEntry.isDir = true;
duke@1 727 entryList.add(zipFileIndexEntry);
duke@1 728 }
duke@1 729
duke@1 730 entries = entryList.toArray(new ZipFileIndexEntry[entryList.size()]);
duke@1 731 Arrays.sort(entries);
duke@1 732 } else {
duke@1 733 cleanupState();
duke@1 734 }
duke@1 735 }
duke@1 736
duke@1 737 private int readEntry(int pos, List<ZipFileIndexEntry> entryList,
duke@1 738 Map<String, DirectoryEntry> directories) throws IOException {
duke@1 739 if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) {
duke@1 740 throw new ZipException("cannot read zip file entry");
duke@1 741 }
duke@1 742
duke@1 743 int dirStart = pos + 46;
duke@1 744 int fileStart = dirStart;
duke@1 745 int fileEnd = fileStart + get2ByteLittleEndian(zipDir, pos + 28);
duke@1 746
duke@1 747 if (zipFileIndex.symbolFilePrefixLength != 0 &&
duke@1 748 ((fileEnd - fileStart) >= symbolFilePrefixLength)) {
duke@1 749 dirStart += zipFileIndex.symbolFilePrefixLength;
duke@1 750 fileStart += zipFileIndex.symbolFilePrefixLength;
duke@1 751 }
duke@1 752
duke@1 753 // Use the OS's path separator. Keep the position of the last one.
duke@1 754 for (int index = fileStart; index < fileEnd; index++) {
duke@1 755 byte nextByte = zipDir[index];
duke@1 756 if (nextByte == (byte)'\\' || nextByte == (byte)'/') {
duke@1 757 zipDir[index] = (byte)File.separatorChar;
duke@1 758 fileStart = index + 1;
duke@1 759 }
duke@1 760 }
duke@1 761
duke@1 762 String directory = null;
duke@1 763 if (fileStart == dirStart)
duke@1 764 directory = "";
duke@1 765 else if (lastDir != null && lastLen == fileStart - dirStart - 1) {
duke@1 766 int index = lastLen - 1;
duke@1 767 while (zipDir[lastStart + index] == zipDir[dirStart + index]) {
duke@1 768 if (index == 0) {
duke@1 769 directory = lastDir;
duke@1 770 break;
duke@1 771 }
duke@1 772 index--;
duke@1 773 }
duke@1 774 }
duke@1 775
duke@1 776 // Sub directories
duke@1 777 if (directory == null) {
duke@1 778 lastStart = dirStart;
duke@1 779 lastLen = fileStart - dirStart - 1;
duke@1 780
duke@1 781 directory = new String(zipDir, dirStart, lastLen, "UTF-8").intern();
duke@1 782 lastDir = directory;
duke@1 783
duke@1 784 // Enter also all the parent directories
duke@1 785 String tempDirectory = directory;
duke@1 786
duke@1 787 while (directories.get(tempDirectory) == null) {
duke@1 788 directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex));
duke@1 789 int separator = tempDirectory.lastIndexOf(File.separatorChar);
duke@1 790 if (separator == -1)
duke@1 791 break;
duke@1 792 tempDirectory = tempDirectory.substring(0, separator);
duke@1 793 }
duke@1 794 }
duke@1 795 else {
duke@1 796 directory = directory.intern();
duke@1 797 if (directories.get(directory) == null) {
duke@1 798 directories.put(directory, new DirectoryEntry(directory, zipFileIndex));
duke@1 799 }
duke@1 800 }
duke@1 801
duke@1 802 // For each dir create also a file
duke@1 803 if (fileStart != fileEnd) {
duke@1 804 ZipFileIndexEntry entry = new ZipFileIndexEntry(directory,
duke@1 805 new String(zipDir, fileStart, fileEnd - fileStart, "UTF-8"));
duke@1 806
duke@1 807 entry.setNativeTime(get4ByteLittleEndian(zipDir, pos + 12));
duke@1 808 entry.compressedSize = get4ByteLittleEndian(zipDir, pos + 20);
duke@1 809 entry.size = get4ByteLittleEndian(zipDir, pos + 24);
duke@1 810 entry.offset = get4ByteLittleEndian(zipDir, pos + 42);
duke@1 811 entryList.add(entry);
duke@1 812 }
duke@1 813
duke@1 814 return pos + 46 +
duke@1 815 get2ByteLittleEndian(zipDir, pos + 28) +
duke@1 816 get2ByteLittleEndian(zipDir, pos + 30) +
duke@1 817 get2ByteLittleEndian(zipDir, pos + 32);
duke@1 818 }
duke@1 819 }
duke@1 820
duke@1 821 /**
duke@1 822 * Returns the last modified timestamp of a zip file.
duke@1 823 * @return long
duke@1 824 */
duke@1 825 public long getZipFileLastModified() throws IOException {
duke@1 826 lock.lock();
duke@1 827 try {
duke@1 828 checkIndex();
duke@1 829 return zipFileLastModified;
duke@1 830 }
duke@1 831 finally {
duke@1 832 lock.unlock();
duke@1 833 }
duke@1 834 }
duke@1 835
duke@1 836 /** ------------------------------------------------------------------------
duke@1 837 * DirectoryEntry class
duke@1 838 * -------------------------------------------------------------------------*/
duke@1 839 static class DirectoryEntry {
duke@1 840 private boolean filesInited;
duke@1 841 private boolean directoriesInited;
duke@1 842 private boolean zipFileEntriesInited;
duke@1 843 private boolean entriesInited;
duke@1 844
duke@1 845 private long writtenOffsetOffset = 0;
duke@1 846
duke@1 847 private String dirName;
duke@1 848
duke@1 849 private com.sun.tools.javac.util.List<String> zipFileEntriesFiles = com.sun.tools.javac.util.List.<String>nil();
duke@1 850 private com.sun.tools.javac.util.List<String> zipFileEntriesDirectories = com.sun.tools.javac.util.List.<String>nil();
duke@1 851 private com.sun.tools.javac.util.List<ZipFileIndexEntry> zipFileEntries = com.sun.tools.javac.util.List.<ZipFileIndexEntry>nil();
duke@1 852
duke@1 853 private List<ZipFileIndexEntry> entries = new ArrayList<ZipFileIndexEntry>();
duke@1 854
duke@1 855 private ZipFileIndex zipFileIndex;
duke@1 856
duke@1 857 private int numEntries;
duke@1 858
duke@1 859 DirectoryEntry(String dirName, ZipFileIndex index) {
duke@1 860 filesInited = false;
duke@1 861 directoriesInited = false;
duke@1 862 entriesInited = false;
duke@1 863
duke@1 864 if (File.separatorChar == '/') {
duke@1 865 dirName.replace('\\', '/');
duke@1 866 }
duke@1 867 else {
duke@1 868 dirName.replace('/', '\\');
duke@1 869 }
duke@1 870
duke@1 871 this.dirName = dirName.intern();
duke@1 872 this.zipFileIndex = index;
duke@1 873 }
duke@1 874
duke@1 875 private com.sun.tools.javac.util.List<String> getFiles() {
duke@1 876 if (filesInited) {
duke@1 877 return zipFileEntriesFiles;
duke@1 878 }
duke@1 879
duke@1 880 initEntries();
duke@1 881
duke@1 882 for (ZipFileIndexEntry e : entries) {
duke@1 883 if (!e.isDir) {
duke@1 884 zipFileEntriesFiles = zipFileEntriesFiles.append(e.name);
duke@1 885 }
duke@1 886 }
duke@1 887 filesInited = true;
duke@1 888 return zipFileEntriesFiles;
duke@1 889 }
duke@1 890
duke@1 891 private com.sun.tools.javac.util.List<String> getDirectories() {
duke@1 892 if (directoriesInited) {
duke@1 893 return zipFileEntriesFiles;
duke@1 894 }
duke@1 895
duke@1 896 initEntries();
duke@1 897
duke@1 898 for (ZipFileIndexEntry e : entries) {
duke@1 899 if (e.isDir) {
duke@1 900 zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name);
duke@1 901 }
duke@1 902 }
duke@1 903
duke@1 904 directoriesInited = true;
duke@1 905
duke@1 906 return zipFileEntriesDirectories;
duke@1 907 }
duke@1 908
duke@1 909 private com.sun.tools.javac.util.List<ZipFileIndexEntry> getEntries() {
duke@1 910 if (zipFileEntriesInited) {
duke@1 911 return zipFileEntries;
duke@1 912 }
duke@1 913
duke@1 914 initEntries();
duke@1 915
duke@1 916 zipFileEntries = com.sun.tools.javac.util.List.nil();
duke@1 917 for (ZipFileIndexEntry zfie : entries) {
duke@1 918 zipFileEntries = zipFileEntries.append(zfie);
duke@1 919 }
duke@1 920
duke@1 921 zipFileEntriesInited = true;
duke@1 922
duke@1 923 return zipFileEntries;
duke@1 924 }
duke@1 925
duke@1 926 private ZipFileIndexEntry getEntry(String rootName) {
duke@1 927 initEntries();
duke@1 928 int index = Collections.binarySearch(entries, new ZipFileIndexEntry(dirName, rootName));
duke@1 929 if (index < 0) {
duke@1 930 return null;
duke@1 931 }
duke@1 932
duke@1 933 return entries.get(index);
duke@1 934 }
duke@1 935
duke@1 936 private void initEntries() {
duke@1 937 if (entriesInited) {
duke@1 938 return;
duke@1 939 }
duke@1 940
duke@1 941 if (!zipFileIndex.readFromIndex) {
duke@1 942 int from = -Arrays.binarySearch(zipFileIndex.entries,
duke@1 943 new ZipFileIndexEntry(dirName, ZipFileIndex.MIN_CHAR)) - 1;
duke@1 944 int to = -Arrays.binarySearch(zipFileIndex.entries,
duke@1 945 new ZipFileIndexEntry(dirName, MAX_CHAR)) - 1;
duke@1 946
duke@1 947 boolean emptyList = false;
duke@1 948
duke@1 949 for (int i = from; i < to; i++) {
duke@1 950 entries.add(zipFileIndex.entries[i]);
duke@1 951 }
duke@1 952 } else {
duke@1 953 File indexFile = zipFileIndex.getIndexFile();
duke@1 954 if (indexFile != null) {
duke@1 955 RandomAccessFile raf = null;
duke@1 956 try {
duke@1 957 raf = new RandomAccessFile(indexFile, "r");
duke@1 958 raf.seek(writtenOffsetOffset);
duke@1 959
duke@1 960 for (int nFiles = 0; nFiles < numEntries; nFiles++) {
duke@1 961 // Read the name bytes
duke@1 962 int zfieNameBytesLen = raf.readInt();
duke@1 963 byte [] zfieNameBytes = new byte[zfieNameBytesLen];
duke@1 964 raf.read(zfieNameBytes);
duke@1 965 String eName = new String(zfieNameBytes, "UTF-8");
duke@1 966
duke@1 967 // Read isDir
duke@1 968 boolean eIsDir = raf.readByte() == (byte)0 ? false : true;
duke@1 969
duke@1 970 // Read offset of bytes in the real Jar/Zip file
duke@1 971 int eOffset = raf.readInt();
duke@1 972
duke@1 973 // Read size of the file in the real Jar/Zip file
duke@1 974 int eSize = raf.readInt();
duke@1 975
duke@1 976 // Read compressed size of the file in the real Jar/Zip file
duke@1 977 int eCsize = raf.readInt();
duke@1 978
duke@1 979 // Read java time stamp of the file in the real Jar/Zip file
duke@1 980 long eJavaTimestamp = raf.readLong();
duke@1 981
duke@1 982 ZipFileIndexEntry rfie = new ZipFileIndexEntry(dirName, eName);
duke@1 983 rfie.isDir = eIsDir;
duke@1 984 rfie.offset = eOffset;
duke@1 985 rfie.size = eSize;
duke@1 986 rfie.compressedSize = eCsize;
duke@1 987 rfie.javatime = eJavaTimestamp;
duke@1 988 entries.add(rfie);
duke@1 989 }
duke@1 990 } catch (Throwable t) {
duke@1 991 // Do nothing
duke@1 992 } finally {
duke@1 993 try {
duke@1 994 if (raf == null) {
duke@1 995 raf.close();
duke@1 996 }
duke@1 997 } catch (Throwable t) {
duke@1 998 // Do nothing
duke@1 999 }
duke@1 1000 }
duke@1 1001 }
duke@1 1002 }
duke@1 1003
duke@1 1004 entriesInited = true;
duke@1 1005 }
duke@1 1006
duke@1 1007 List<ZipFileIndexEntry> getEntriesAsCollection() {
duke@1 1008 initEntries();
duke@1 1009
duke@1 1010 return entries;
duke@1 1011 }
duke@1 1012 }
duke@1 1013
duke@1 1014 private boolean readIndex() {
duke@1 1015 if (triedToReadIndex || !usePreindexedCache) {
duke@1 1016 return false;
duke@1 1017 }
duke@1 1018
duke@1 1019 boolean ret = false;
duke@1 1020 lock.lock();
duke@1 1021 try {
duke@1 1022 triedToReadIndex = true;
duke@1 1023 RandomAccessFile raf = null;
duke@1 1024 try {
duke@1 1025 File indexFileName = getIndexFile();
duke@1 1026 raf = new RandomAccessFile(indexFileName, "r");
duke@1 1027
duke@1 1028 long fileStamp = raf.readLong();
duke@1 1029 if (zipFile.lastModified() != fileStamp) {
duke@1 1030 ret = false;
duke@1 1031 } else {
duke@1 1032 directories = new HashMap<String, DirectoryEntry>();
duke@1 1033 int numDirs = raf.readInt();
duke@1 1034 for (int nDirs = 0; nDirs < numDirs; nDirs++) {
duke@1 1035 int dirNameBytesLen = raf.readInt();
duke@1 1036 byte [] dirNameBytes = new byte[dirNameBytesLen];
duke@1 1037 raf.read(dirNameBytes);
duke@1 1038
duke@1 1039 String dirNameStr = new String(dirNameBytes, "UTF-8");
duke@1 1040 DirectoryEntry de = new DirectoryEntry(dirNameStr, this);
duke@1 1041 de.numEntries = raf.readInt();
duke@1 1042 de.writtenOffsetOffset = raf.readLong();
duke@1 1043 directories.put(dirNameStr, de);
duke@1 1044 }
duke@1 1045 ret = true;
duke@1 1046 zipFileLastModified = fileStamp;
duke@1 1047 }
duke@1 1048 } catch (Throwable t) {
duke@1 1049 // Do nothing
duke@1 1050 } finally {
duke@1 1051 if (raf != null) {
duke@1 1052 try {
duke@1 1053 raf.close();
duke@1 1054 } catch (Throwable tt) {
duke@1 1055 // Do nothing
duke@1 1056 }
duke@1 1057 }
duke@1 1058 }
duke@1 1059 if (ret == true) {
duke@1 1060 readFromIndex = true;
duke@1 1061 }
duke@1 1062 }
duke@1 1063 finally {
duke@1 1064 lock.unlock();
duke@1 1065 }
duke@1 1066
duke@1 1067 return ret;
duke@1 1068 }
duke@1 1069
duke@1 1070 private boolean writeIndex() {
duke@1 1071 boolean ret = false;
duke@1 1072 if (readFromIndex || !usePreindexedCache) {
duke@1 1073 return true;
duke@1 1074 }
duke@1 1075
duke@1 1076 if (!writeIndex) {
duke@1 1077 return true;
duke@1 1078 }
duke@1 1079
duke@1 1080 File indexFile = getIndexFile();
duke@1 1081 if (indexFile == null) {
duke@1 1082 return false;
duke@1 1083 }
duke@1 1084
duke@1 1085 RandomAccessFile raf = null;
duke@1 1086 long writtenSoFar = 0;
duke@1 1087 try {
duke@1 1088 raf = new RandomAccessFile(indexFile, "rw");
duke@1 1089
duke@1 1090 raf.writeLong(zipFileLastModified);
duke@1 1091 writtenSoFar += 8;
duke@1 1092
duke@1 1093
duke@1 1094 Iterator<String> iterDirName = directories.keySet().iterator();
duke@1 1095 List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>();
duke@1 1096 Map<String, Long> offsets = new HashMap<String, Long>();
duke@1 1097 raf.writeInt(directories.keySet().size());
duke@1 1098 writtenSoFar += 4;
duke@1 1099
duke@1 1100 while(iterDirName.hasNext()) {
duke@1 1101 String dirName = iterDirName.next();
duke@1 1102 DirectoryEntry dirEntry = directories.get(dirName);
duke@1 1103
duke@1 1104 directoriesToWrite.add(dirEntry);
duke@1 1105
duke@1 1106 // Write the dir name bytes
duke@1 1107 byte [] dirNameBytes = dirName.getBytes("UTF-8");
duke@1 1108 int dirNameBytesLen = dirNameBytes.length;
duke@1 1109 raf.writeInt(dirNameBytesLen);
duke@1 1110 writtenSoFar += 4;
duke@1 1111
duke@1 1112 raf.write(dirNameBytes);
duke@1 1113 writtenSoFar += dirNameBytesLen;
duke@1 1114
duke@1 1115 // Write the number of files in the dir
duke@1 1116 List dirEntries = dirEntry.getEntriesAsCollection();
duke@1 1117 raf.writeInt(dirEntries.size());
duke@1 1118 writtenSoFar += 4;
duke@1 1119
duke@1 1120 offsets.put(dirName, new Long(writtenSoFar));
duke@1 1121
duke@1 1122 // Write the offset of the file's data in the dir
duke@1 1123 dirEntry.writtenOffsetOffset = 0L;
duke@1 1124 raf.writeLong(0L);
duke@1 1125 writtenSoFar += 8;
duke@1 1126 }
duke@1 1127
duke@1 1128 for (DirectoryEntry de : directoriesToWrite) {
duke@1 1129 // Fix up the offset in the directory table
duke@1 1130 long currFP = raf.getFilePointer();
duke@1 1131
duke@1 1132 long offsetOffset = offsets.get(de.dirName).longValue();
duke@1 1133 raf.seek(offsetOffset);
duke@1 1134 raf.writeLong(writtenSoFar);
duke@1 1135
duke@1 1136 raf.seek(currFP);
duke@1 1137
duke@1 1138 // Now write each of the files in the DirectoryEntry
duke@1 1139 List<ZipFileIndexEntry> entries = de.getEntriesAsCollection();
duke@1 1140 for (ZipFileIndexEntry zfie : entries) {
duke@1 1141 // Write the name bytes
duke@1 1142 byte [] zfieNameBytes = zfie.name.getBytes("UTF-8");
duke@1 1143 int zfieNameBytesLen = zfieNameBytes.length;
duke@1 1144 raf.writeInt(zfieNameBytesLen);
duke@1 1145 writtenSoFar += 4;
duke@1 1146 raf.write(zfieNameBytes);
duke@1 1147 writtenSoFar += zfieNameBytesLen;
duke@1 1148
duke@1 1149 // Write isDir
duke@1 1150 raf.writeByte(zfie.isDir ? (byte)1 : (byte)0);
duke@1 1151 writtenSoFar += 1;
duke@1 1152
duke@1 1153 // Write offset of bytes in the real Jar/Zip file
duke@1 1154 raf.writeInt(zfie.offset);
duke@1 1155 writtenSoFar += 4;
duke@1 1156
duke@1 1157 // Write size of the file in the real Jar/Zip file
duke@1 1158 raf.writeInt(zfie.size);
duke@1 1159 writtenSoFar += 4;
duke@1 1160
duke@1 1161 // Write compressed size of the file in the real Jar/Zip file
duke@1 1162 raf.writeInt(zfie.compressedSize);
duke@1 1163 writtenSoFar += 4;
duke@1 1164
duke@1 1165 // Write java time stamp of the file in the real Jar/Zip file
duke@1 1166 raf.writeLong(zfie.getLastModified());
duke@1 1167 writtenSoFar += 8;
duke@1 1168 }
duke@1 1169 }
duke@1 1170 } catch (Throwable t) {
duke@1 1171 // Do nothing
duke@1 1172 } finally {
duke@1 1173 try {
duke@1 1174 if (raf != null) {
duke@1 1175 raf.close();
duke@1 1176 }
duke@1 1177 } catch(IOException ioe) {
duke@1 1178 // Do nothing
duke@1 1179 }
duke@1 1180 }
duke@1 1181
duke@1 1182 return ret;
duke@1 1183 }
duke@1 1184
duke@1 1185 public boolean writeZipIndex() {
duke@1 1186 lock.lock();
duke@1 1187 try {
duke@1 1188 return writeIndex();
duke@1 1189 }
duke@1 1190 finally {
duke@1 1191 lock.unlock();
duke@1 1192 }
duke@1 1193 }
duke@1 1194
duke@1 1195 private File getIndexFile() {
duke@1 1196 if (zipIndexFile == null) {
duke@1 1197 if (zipFile == null) {
duke@1 1198 return null;
duke@1 1199 }
duke@1 1200
duke@1 1201 zipIndexFile = new File((preindexedCacheLocation == null ? "" : preindexedCacheLocation) +
duke@1 1202 zipFile.getName() + ".index");
duke@1 1203 }
duke@1 1204
duke@1 1205 return zipIndexFile;
duke@1 1206 }
duke@1 1207
duke@1 1208 public File getZipFile() {
duke@1 1209 return zipFile;
duke@1 1210 }
duke@1 1211 }

mercurial