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

changeset 103
e571266ae14f
parent 71
41fb91c70d47
child 184
905e151a185a
equal deleted inserted replaced
100:37551dc0f591 103:e571266ae14f
23 * have any questions. 23 * have any questions.
24 */ 24 */
25 25
26 package com.sun.tools.javac.file; 26 package com.sun.tools.javac.file;
27 27
28
28 import java.io.File; 29 import java.io.File;
29 import java.io.FileNotFoundException; 30 import java.io.FileNotFoundException;
30 import java.io.IOException; 31 import java.io.IOException;
31 import java.io.RandomAccessFile; 32 import java.io.RandomAccessFile;
32 import java.text.MessageFormat; 33 import java.lang.ref.SoftReference;
33 import java.util.ArrayList; 34 import java.util.ArrayList;
34 import java.util.Arrays; 35 import java.util.Arrays;
35 import java.util.Calendar; 36 import java.util.Calendar;
36 import java.util.Collections; 37 import java.util.Collections;
37 import java.util.HashMap; 38 import java.util.HashMap;
42 import java.util.Set; 43 import java.util.Set;
43 import java.util.concurrent.locks.ReentrantLock; 44 import java.util.concurrent.locks.ReentrantLock;
44 import java.util.zip.DataFormatException; 45 import java.util.zip.DataFormatException;
45 import java.util.zip.Inflater; 46 import java.util.zip.Inflater;
46 import java.util.zip.ZipException; 47 import java.util.zip.ZipException;
48
49 import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
50 import com.sun.tools.javac.file.RelativePath.RelativeFile;
47 51
48 /** This class implements building of index of a zip archive and access to it's context. 52 /** This class implements building of index of a zip archive and access to it's context.
49 * It also uses prebuild index if available. It supports invocations where it will 53 * It also uses prebuild index if available. It supports invocations where it will
50 * serialize an optimized zip index file to disk. 54 * serialize an optimized zip index file to disk.
51 * 55 *
73 private static Map<File, ZipFileIndex> zipFileIndexCache = new HashMap<File, ZipFileIndex>(); 77 private static Map<File, ZipFileIndex> zipFileIndexCache = new HashMap<File, ZipFileIndex>();
74 private static ReentrantLock lock = new ReentrantLock(); 78 private static ReentrantLock lock = new ReentrantLock();
75 79
76 private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this. 80 private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this.
77 81
78 private Map<String, DirectoryEntry> directories = Collections.<String, DirectoryEntry>emptyMap(); 82 private Map<RelativeDirectory, DirectoryEntry> directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
79 private Set<String> allDirs = Collections.<String>emptySet(); 83 private Set<RelativeDirectory> allDirs = Collections.<RelativeDirectory>emptySet();
80 84
81 // ZipFileIndex data entries 85 // ZipFileIndex data entries
82 private File zipFile; 86 private File zipFile;
83 private long zipFileLastModified = NOT_MODIFIED; 87 private long zipFileLastModified = NOT_MODIFIED;
84 private RandomAccessFile zipRandomFile; 88 private RandomAccessFile zipRandomFile;
85 private Entry[] entries; 89 private Entry[] entries;
86 90
87 private boolean readFromIndex = false; 91 private boolean readFromIndex = false;
88 private File zipIndexFile = null; 92 private File zipIndexFile = null;
89 private boolean triedToReadIndex = false; 93 private boolean triedToReadIndex = false;
90 final String symbolFilePrefix; 94 final RelativeDirectory symbolFilePrefix;
91 private int symbolFilePrefixLength = 0; 95 private int symbolFilePrefixLength = 0;
92 private boolean hasPopulatedData = false; 96 private boolean hasPopulatedData = false;
93 private long lastReferenceTimeStamp = NOT_MODIFIED; 97 private long lastReferenceTimeStamp = NOT_MODIFIED;
94 98
95 private boolean usePreindexedCache = false; 99 private boolean usePreindexedCache = false;
96 private String preindexedCacheLocation = null; 100 private String preindexedCacheLocation = null;
97 101
98 private boolean writeIndex = false; 102 private boolean writeIndex = false;
103
104 private Map <String, SoftReference<RelativeDirectory>> relativeDirectoryCache =
105 new HashMap<String, SoftReference<RelativeDirectory>>();
99 106
100 /** 107 /**
101 * Returns a list of all ZipFileIndex entries 108 * Returns a list of all ZipFileIndex entries
102 * 109 *
103 * @return A list of ZipFileIndex entries, or an empty list 110 * @return A list of ZipFileIndex entries, or an empty list
141 finally { 148 finally {
142 lock.unlock(); 149 lock.unlock();
143 } 150 }
144 } 151 }
145 152
146 public static ZipFileIndex getZipFileIndex(File zipFile, String symbolFilePrefix, boolean useCache, String cacheLocation, boolean writeIndex) throws IOException { 153 public static ZipFileIndex getZipFileIndex(File zipFile,
154 RelativeDirectory symbolFilePrefix,
155 boolean useCache, String cacheLocation,
156 boolean writeIndex) throws IOException {
147 ZipFileIndex zi = null; 157 ZipFileIndex zi = null;
148 lock.lock(); 158 lock.lock();
149 try { 159 try {
150 zi = getExistingZipIndex(zipFile); 160 zi = getExistingZipIndex(zipFile);
151 161
229 finally { 239 finally {
230 lock.unlock(); 240 lock.unlock();
231 } 241 }
232 } 242 }
233 243
234 private ZipFileIndex(File zipFile, String symbolFilePrefix, boolean writeIndex, 244 private ZipFileIndex(File zipFile, RelativeDirectory symbolFilePrefix, boolean writeIndex,
235 boolean useCache, String cacheLocation) throws IOException { 245 boolean useCache, String cacheLocation) throws IOException {
236 this.zipFile = zipFile; 246 this.zipFile = zipFile;
237 this.symbolFilePrefix = symbolFilePrefix; 247 this.symbolFilePrefix = symbolFilePrefix;
238 this.symbolFilePrefixLength = (symbolFilePrefix == null ? 0 : 248 this.symbolFilePrefixLength = (symbolFilePrefix == null ? 0 :
239 symbolFilePrefix.getBytes("UTF-8").length); 249 symbolFilePrefix.getPath().getBytes("UTF-8").length);
240 this.writeIndex = writeIndex; 250 this.writeIndex = writeIndex;
241 this.usePreindexedCache = useCache; 251 this.usePreindexedCache = useCache;
242 this.preindexedCacheLocation = cacheLocation; 252 this.preindexedCacheLocation = cacheLocation;
243 253
244 if (zipFile != null) { 254 if (zipFile != null) {
248 // Validate integrity of the zip file 258 // Validate integrity of the zip file
249 checkIndex(); 259 checkIndex();
250 } 260 }
251 261
252 public String toString() { 262 public String toString() {
253 return "ZipFileIndex of file:(" + zipFile + ")"; 263 return "ZipFileIndex[" + zipFile + "]";
254 } 264 }
255 265
256 // Just in case... 266 // Just in case...
257 protected void finalize() { 267 protected void finalize() {
258 closeFile(); 268 closeFile();
289 if (readIndex()) { 299 if (readIndex()) {
290 lastReferenceTimeStamp = System.currentTimeMillis(); 300 lastReferenceTimeStamp = System.currentTimeMillis();
291 return; 301 return;
292 } 302 }
293 303
294 directories = Collections.<String, DirectoryEntry>emptyMap(); 304 directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
295 allDirs = Collections.<String>emptySet(); 305 allDirs = Collections.<RelativeDirectory>emptySet();
296 306
297 try { 307 try {
298 openFile(); 308 openFile();
299 long totalLength = zipRandomFile.length(); 309 long totalLength = zipRandomFile.length();
300 ZipDirectory directory = new ZipDirectory(zipRandomFile, 0L, totalLength, this); 310 ZipDirectory directory = new ZipDirectory(zipRandomFile, 0L, totalLength, this);
315 } 325 }
316 326
317 private void cleanupState() { 327 private void cleanupState() {
318 // Make sure there is a valid but empty index if the file doesn't exist 328 // Make sure there is a valid but empty index if the file doesn't exist
319 entries = Entry.EMPTY_ARRAY; 329 entries = Entry.EMPTY_ARRAY;
320 directories = Collections.<String, DirectoryEntry>emptyMap(); 330 directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap();
321 zipFileLastModified = NOT_MODIFIED; 331 zipFileLastModified = NOT_MODIFIED;
322 allDirs = Collections.<String>emptySet(); 332 allDirs = Collections.<RelativeDirectory>emptySet();
323 } 333 }
324 334
325 public void close() { 335 public void close() {
326 lock.lock(); 336 lock.lock();
327 try { 337 try {
344 } 354 }
345 355
346 /** 356 /**
347 * Returns the ZipFileIndexEntry for an absolute path, if there is one. 357 * Returns the ZipFileIndexEntry for an absolute path, if there is one.
348 */ 358 */
349 Entry getZipIndexEntry(String path) { 359 Entry getZipIndexEntry(RelativePath path) {
350 if (File.separatorChar != '/') {
351 path = path.replace('/', File.separatorChar);
352 }
353 lock.lock(); 360 lock.lock();
354 try { 361 try {
355 checkIndex(); 362 checkIndex();
356 String lookFor = ""; 363 DirectoryEntry de = directories.get(path.dirname());
357 int lastSepIndex = path.lastIndexOf(File.separatorChar); 364 String lookFor = path.basename();
358 boolean noSeparator = false;
359 if (lastSepIndex == -1) {
360 noSeparator = true;
361 }
362
363 DirectoryEntry de = directories.get(noSeparator ? "" : path.substring(0, lastSepIndex));
364
365 lookFor = path.substring(noSeparator ? 0 : lastSepIndex + 1);
366
367 return de == null ? null : de.getEntry(lookFor); 365 return de == null ? null : de.getEntry(lookFor);
368 } 366 }
369 catch (IOException e) { 367 catch (IOException e) {
370 return null; 368 return null;
371 } 369 }
375 } 373 }
376 374
377 /** 375 /**
378 * Returns a javac List of filenames within an absolute path in the ZipFileIndex. 376 * Returns a javac List of filenames within an absolute path in the ZipFileIndex.
379 */ 377 */
380 public com.sun.tools.javac.util.List<String> getFiles(String path) { 378 public com.sun.tools.javac.util.List<String> getFiles(RelativeDirectory path) {
381 if (File.separatorChar != '/') {
382 path = path.replace('/', File.separatorChar);
383 }
384
385 lock.lock(); 379 lock.lock();
386 try { 380 try {
387 checkIndex(); 381 checkIndex();
388 382
389 DirectoryEntry de = directories.get(path); 383 DirectoryEntry de = directories.get(path);
400 finally { 394 finally {
401 lock.unlock(); 395 lock.unlock();
402 } 396 }
403 } 397 }
404 398
405 public List<String> getAllDirectories(String path) { 399 public List<String> getDirectories(RelativeDirectory path) {
406
407 if (File.separatorChar != '/') {
408 path = path.replace('/', File.separatorChar);
409 }
410
411 lock.lock(); 400 lock.lock();
412 try { 401 try {
413 checkIndex(); 402 checkIndex();
414 path = path.intern();
415 403
416 DirectoryEntry de = directories.get(path); 404 DirectoryEntry de = directories.get(path);
417 com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories(); 405 com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories();
418 406
419 if (ret == null) { 407 if (ret == null) {
428 finally { 416 finally {
429 lock.unlock(); 417 lock.unlock();
430 } 418 }
431 } 419 }
432 420
433 public Set<String> getAllDirectories() { 421 public Set<RelativeDirectory> getAllDirectories() {
434 lock.lock(); 422 lock.lock();
435 try { 423 try {
436 checkIndex(); 424 checkIndex();
437 if (allDirs == Collections.EMPTY_SET) { 425 if (allDirs == Collections.EMPTY_SET) {
438 Set<String> alldirs = new HashSet<String>(); 426 allDirs = new HashSet<RelativeDirectory>(directories.keySet());
439 Iterator<String> dirsIter = directories.keySet().iterator();
440 while (dirsIter.hasNext()) {
441 alldirs.add(new String(dirsIter.next()));
442 }
443
444 allDirs = alldirs;
445 } 427 }
446 428
447 return allDirs; 429 return allDirs;
448 } 430 }
449 catch (IOException e) { 431 catch (IOException e) {
450 return Collections.<String>emptySet(); 432 return Collections.<RelativeDirectory>emptySet();
451 } 433 }
452 finally { 434 finally {
453 lock.unlock(); 435 lock.unlock();
454 } 436 }
455 } 437 }
459 * for file entries and directories. 441 * for file entries and directories.
460 * 442 *
461 * @param path A path within the zip. 443 * @param path A path within the zip.
462 * @return True if the path is a file or dir, false otherwise. 444 * @return True if the path is a file or dir, false otherwise.
463 */ 445 */
464 public boolean contains(String path) { 446 public boolean contains(RelativePath path) {
465 lock.lock(); 447 lock.lock();
466 try { 448 try {
467 checkIndex(); 449 checkIndex();
468 return getZipIndexEntry(path) != null; 450 return getZipIndexEntry(path) != null;
469 } 451 }
473 finally { 455 finally {
474 lock.unlock(); 456 lock.unlock();
475 } 457 }
476 } 458 }
477 459
478 public boolean isDirectory(String path) throws IOException { 460 public boolean isDirectory(RelativePath path) throws IOException {
479 lock.lock(); 461 lock.lock();
480 try { 462 try {
481 // The top level in a zip file is always a directory. 463 // The top level in a zip file is always a directory.
482 if (path.length() == 0) { 464 if (path.getPath().length() == 0) {
483 lastReferenceTimeStamp = System.currentTimeMillis(); 465 lastReferenceTimeStamp = System.currentTimeMillis();
484 return true; 466 return true;
485 } 467 }
486 468
487 if (File.separatorChar != '/')
488 path = path.replace('/', File.separatorChar);
489 checkIndex(); 469 checkIndex();
490 return directories.get(path) != null; 470 return directories.get(path) != null;
491 } 471 }
492 finally { 472 finally {
493 lock.unlock(); 473 lock.unlock();
494 } 474 }
495 } 475 }
496 476
497 public long getLastModified(String path) throws IOException { 477 public long getLastModified(RelativeFile path) throws IOException {
498 lock.lock(); 478 lock.lock();
499 try { 479 try {
500 Entry entry = getZipIndexEntry(path); 480 Entry entry = getZipIndexEntry(path);
501 if (entry == null) 481 if (entry == null)
502 throw new FileNotFoundException(); 482 throw new FileNotFoundException();
505 finally { 485 finally {
506 lock.unlock(); 486 lock.unlock();
507 } 487 }
508 } 488 }
509 489
510 public int length(String path) throws IOException { 490 public int length(RelativeFile path) throws IOException {
511 lock.lock(); 491 lock.lock();
512 try { 492 try {
513 Entry entry = getZipIndexEntry(path); 493 Entry entry = getZipIndexEntry(path);
514 if (entry == null) 494 if (entry == null)
515 throw new FileNotFoundException(); 495 throw new FileNotFoundException();
529 finally { 509 finally {
530 lock.unlock(); 510 lock.unlock();
531 } 511 }
532 } 512 }
533 513
534 public byte[] read(String path) throws IOException { 514 public byte[] read(RelativeFile path) throws IOException {
535 lock.lock(); 515 lock.lock();
536 try { 516 try {
537 Entry entry = getZipIndexEntry(path); 517 Entry entry = getZipIndexEntry(path);
538 if (entry == null) 518 if (entry == null)
539 throw new FileNotFoundException(MessageFormat.format("Path not found in ZIP: {0}", path)); 519 throw new FileNotFoundException("Path not found in ZIP: " + path.path);
540 return read(entry); 520 return read(entry);
541 } 521 }
542 finally { 522 finally {
543 lock.unlock(); 523 lock.unlock();
544 } 524 }
555 finally { 535 finally {
556 lock.unlock(); 536 lock.unlock();
557 } 537 }
558 } 538 }
559 539
560 public int read(String path, byte[] buffer) throws IOException { 540 public int read(RelativeFile path, byte[] buffer) throws IOException {
561 lock.lock(); 541 lock.lock();
562 try { 542 try {
563 Entry entry = getZipIndexEntry(path); 543 Entry entry = getZipIndexEntry(path);
564 if (entry == null) 544 if (entry == null)
565 throw new FileNotFoundException(); 545 throw new FileNotFoundException();
688 /* ---------------------------------------------------------------------------- 668 /* ----------------------------------------------------------------------------
689 * ZipDirectory 669 * ZipDirectory
690 * ----------------------------------------------------------------------------*/ 670 * ----------------------------------------------------------------------------*/
691 671
692 private class ZipDirectory { 672 private class ZipDirectory {
693 private String lastDir; 673 private RelativeDirectory lastDir;
694 private int lastStart; 674 private int lastStart;
695 private int lastLen; 675 private int lastLen;
696 676
697 byte[] zipDir; 677 byte[] zipDir;
698 RandomAccessFile zipRandomFile = null; 678 RandomAccessFile zipRandomFile = null;
745 endbufend = endbufpos + 21; 725 endbufend = endbufpos + 21;
746 } 726 }
747 } 727 }
748 throw new ZipException("cannot read zip file"); 728 throw new ZipException("cannot read zip file");
749 } 729 }
730
750 private void buildIndex() throws IOException { 731 private void buildIndex() throws IOException {
751 int entryCount = get2ByteLittleEndian(zipDir, 0); 732 int entryCount = get2ByteLittleEndian(zipDir, 0);
752 733
753 entries = new Entry[entryCount];
754 // Add each of the files 734 // Add each of the files
755 if (entryCount > 0) { 735 if (entryCount > 0) {
756 directories = new HashMap<String, DirectoryEntry>(); 736 directories = new HashMap<RelativeDirectory, DirectoryEntry>();
757 ArrayList<Entry> entryList = new ArrayList<Entry>(); 737 ArrayList<Entry> entryList = new ArrayList<Entry>();
758 int pos = 2; 738 int pos = 2;
759 for (int i = 0; i < entryCount; i++) { 739 for (int i = 0; i < entryCount; i++) {
760 pos = readEntry(pos, entryList, directories); 740 pos = readEntry(pos, entryList, directories);
761 } 741 }
762 742
763 // Add the accumulated dirs into the same list 743 // Add the accumulated dirs into the same list
764 Iterator i = directories.keySet().iterator(); 744 for (RelativeDirectory d: directories.keySet()) {
765 while (i.hasNext()) { 745 // use shared RelativeDirectory objects for parent dirs
766 Entry zipFileIndexEntry = new Entry( (String) i.next()); 746 RelativeDirectory parent = getRelativeDirectory(d.dirname().getPath());
747 String file = d.basename();
748 Entry zipFileIndexEntry = new Entry(parent, file);
767 zipFileIndexEntry.isDir = true; 749 zipFileIndexEntry.isDir = true;
768 entryList.add(zipFileIndexEntry); 750 entryList.add(zipFileIndexEntry);
769 } 751 }
770 752
771 entries = entryList.toArray(new Entry[entryList.size()]); 753 entries = entryList.toArray(new Entry[entryList.size()]);
774 cleanupState(); 756 cleanupState();
775 } 757 }
776 } 758 }
777 759
778 private int readEntry(int pos, List<Entry> entryList, 760 private int readEntry(int pos, List<Entry> entryList,
779 Map<String, DirectoryEntry> directories) throws IOException { 761 Map<RelativeDirectory, DirectoryEntry> directories) throws IOException {
780 if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) { 762 if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) {
781 throw new ZipException("cannot read zip file entry"); 763 throw new ZipException("cannot read zip file entry");
782 } 764 }
783 765
784 int dirStart = pos + 46; 766 int dirStart = pos + 46;
788 if (zipFileIndex.symbolFilePrefixLength != 0 && 770 if (zipFileIndex.symbolFilePrefixLength != 0 &&
789 ((fileEnd - fileStart) >= symbolFilePrefixLength)) { 771 ((fileEnd - fileStart) >= symbolFilePrefixLength)) {
790 dirStart += zipFileIndex.symbolFilePrefixLength; 772 dirStart += zipFileIndex.symbolFilePrefixLength;
791 fileStart += zipFileIndex.symbolFilePrefixLength; 773 fileStart += zipFileIndex.symbolFilePrefixLength;
792 } 774 }
793 775 // Force any '\' to '/'. Keep the position of the last separator.
794 // Use the OS's path separator. Keep the position of the last one.
795 for (int index = fileStart; index < fileEnd; index++) { 776 for (int index = fileStart; index < fileEnd; index++) {
796 byte nextByte = zipDir[index]; 777 byte nextByte = zipDir[index];
797 if (nextByte == (byte)'\\' || nextByte == (byte)'/') { 778 if (nextByte == (byte)'\\') {
798 zipDir[index] = (byte)File.separatorChar; 779 zipDir[index] = (byte)'/';
799 fileStart = index + 1; 780 fileStart = index + 1;
800 } 781 } else if (nextByte == (byte)'/') {
801 } 782 fileStart = index + 1;
802 783 }
803 String directory = null; 784 }
785
786 RelativeDirectory directory = null;
804 if (fileStart == dirStart) 787 if (fileStart == dirStart)
805 directory = ""; 788 directory = getRelativeDirectory("");
806 else if (lastDir != null && lastLen == fileStart - dirStart - 1) { 789 else if (lastDir != null && lastLen == fileStart - dirStart - 1) {
807 int index = lastLen - 1; 790 int index = lastLen - 1;
808 while (zipDir[lastStart + index] == zipDir[dirStart + index]) { 791 while (zipDir[lastStart + index] == zipDir[dirStart + index]) {
809 if (index == 0) { 792 if (index == 0) {
810 directory = lastDir; 793 directory = lastDir;
817 // Sub directories 800 // Sub directories
818 if (directory == null) { 801 if (directory == null) {
819 lastStart = dirStart; 802 lastStart = dirStart;
820 lastLen = fileStart - dirStart - 1; 803 lastLen = fileStart - dirStart - 1;
821 804
822 directory = new String(zipDir, dirStart, lastLen, "UTF-8").intern(); 805 directory = getRelativeDirectory(new String(zipDir, dirStart, lastLen, "UTF-8"));
823 lastDir = directory; 806 lastDir = directory;
824 807
825 // Enter also all the parent directories 808 // Enter also all the parent directories
826 String tempDirectory = directory; 809 RelativeDirectory tempDirectory = directory;
827 810
828 while (directories.get(tempDirectory) == null) { 811 while (directories.get(tempDirectory) == null) {
829 directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex)); 812 directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex));
830 int separator = tempDirectory.lastIndexOf(File.separatorChar); 813 if (tempDirectory.path.indexOf("/") == tempDirectory.path.length() - 1)
831 if (separator == -1)
832 break; 814 break;
833 tempDirectory = tempDirectory.substring(0, separator); 815 else {
816 // use shared RelativeDirectory objects for parent dirs
817 tempDirectory = getRelativeDirectory(tempDirectory.dirname().getPath());
818 }
834 } 819 }
835 } 820 }
836 else { 821 else {
837 directory = directory.intern();
838 if (directories.get(directory) == null) { 822 if (directories.get(directory) == null) {
839 directories.put(directory, new DirectoryEntry(directory, zipFileIndex)); 823 directories.put(directory, new DirectoryEntry(directory, zipFileIndex));
840 } 824 }
841 } 825 }
842 826
884 private boolean zipFileEntriesInited; 868 private boolean zipFileEntriesInited;
885 private boolean entriesInited; 869 private boolean entriesInited;
886 870
887 private long writtenOffsetOffset = 0; 871 private long writtenOffsetOffset = 0;
888 872
889 private String dirName; 873 private RelativeDirectory dirName;
890 874
891 private com.sun.tools.javac.util.List<String> zipFileEntriesFiles = com.sun.tools.javac.util.List.<String>nil(); 875 private com.sun.tools.javac.util.List<String> zipFileEntriesFiles = com.sun.tools.javac.util.List.<String>nil();
892 private com.sun.tools.javac.util.List<String> zipFileEntriesDirectories = com.sun.tools.javac.util.List.<String>nil(); 876 private com.sun.tools.javac.util.List<String> zipFileEntriesDirectories = com.sun.tools.javac.util.List.<String>nil();
893 private com.sun.tools.javac.util.List<Entry> zipFileEntries = com.sun.tools.javac.util.List.<Entry>nil(); 877 private com.sun.tools.javac.util.List<Entry> zipFileEntries = com.sun.tools.javac.util.List.<Entry>nil();
894 878
896 880
897 private ZipFileIndex zipFileIndex; 881 private ZipFileIndex zipFileIndex;
898 882
899 private int numEntries; 883 private int numEntries;
900 884
901 DirectoryEntry(String dirName, ZipFileIndex index) { 885 DirectoryEntry(RelativeDirectory dirName, ZipFileIndex index) {
902 filesInited = false; 886 filesInited = false;
903 directoriesInited = false; 887 directoriesInited = false;
904 entriesInited = false; 888 entriesInited = false;
905 889
906 if (File.separatorChar == '/') { 890 this.dirName = dirName;
907 dirName.replace('\\', '/');
908 }
909 else {
910 dirName.replace('/', '\\');
911 }
912
913 this.dirName = dirName.intern();
914 this.zipFileIndex = index; 891 this.zipFileIndex = index;
915 } 892 }
916 893
917 private com.sun.tools.javac.util.List<String> getFiles() { 894 private com.sun.tools.javac.util.List<String> getFiles() {
918 if (filesInited) { 895 if (!filesInited) {
919 return zipFileEntriesFiles; 896 initEntries();
920 } 897 for (Entry e : entries) {
921 898 if (!e.isDir) {
922 initEntries(); 899 zipFileEntriesFiles = zipFileEntriesFiles.append(e.name);
923 900 }
924 for (Entry e : entries) { 901 }
925 if (!e.isDir) { 902 filesInited = true;
926 zipFileEntriesFiles = zipFileEntriesFiles.append(e.name); 903 }
927 }
928 }
929 filesInited = true;
930 return zipFileEntriesFiles; 904 return zipFileEntriesFiles;
931 } 905 }
932 906
933 private com.sun.tools.javac.util.List<String> getDirectories() { 907 private com.sun.tools.javac.util.List<String> getDirectories() {
934 if (directoriesInited) { 908 if (!directoriesInited) {
935 return zipFileEntriesFiles; 909 initEntries();
936 } 910 for (Entry e : entries) {
937 911 if (e.isDir) {
938 initEntries(); 912 zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name);
939 913 }
940 for (Entry e : entries) { 914 }
941 if (e.isDir) { 915 directoriesInited = true;
942 zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name); 916 }
943 }
944 }
945
946 directoriesInited = true;
947
948 return zipFileEntriesDirectories; 917 return zipFileEntriesDirectories;
949 } 918 }
950 919
951 private com.sun.tools.javac.util.List<Entry> getEntries() { 920 private com.sun.tools.javac.util.List<Entry> getEntries() {
952 if (zipFileEntriesInited) { 921 if (!zipFileEntriesInited) {
953 return zipFileEntries; 922 initEntries();
954 } 923 zipFileEntries = com.sun.tools.javac.util.List.nil();
955 924 for (Entry zfie : entries) {
956 initEntries(); 925 zipFileEntries = zipFileEntries.append(zfie);
957 926 }
958 zipFileEntries = com.sun.tools.javac.util.List.nil(); 927 zipFileEntriesInited = true;
959 for (Entry zfie : entries) { 928 }
960 zipFileEntries = zipFileEntries.append(zfie);
961 }
962
963 zipFileEntriesInited = true;
964
965 return zipFileEntries; 929 return zipFileEntries;
966 } 930 }
967 931
968 private Entry getEntry(String rootName) { 932 private Entry getEntry(String rootName) {
969 initEntries(); 933 initEntries();
983 if (!zipFileIndex.readFromIndex) { 947 if (!zipFileIndex.readFromIndex) {
984 int from = -Arrays.binarySearch(zipFileIndex.entries, 948 int from = -Arrays.binarySearch(zipFileIndex.entries,
985 new Entry(dirName, ZipFileIndex.MIN_CHAR)) - 1; 949 new Entry(dirName, ZipFileIndex.MIN_CHAR)) - 1;
986 int to = -Arrays.binarySearch(zipFileIndex.entries, 950 int to = -Arrays.binarySearch(zipFileIndex.entries,
987 new Entry(dirName, MAX_CHAR)) - 1; 951 new Entry(dirName, MAX_CHAR)) - 1;
988
989 boolean emptyList = false;
990 952
991 for (int i = from; i < to; i++) { 953 for (int i = from; i < to; i++) {
992 entries.add(zipFileIndex.entries[i]); 954 entries.add(zipFileIndex.entries[i]);
993 } 955 }
994 } else { 956 } else {
1069 1031
1070 long fileStamp = raf.readLong(); 1032 long fileStamp = raf.readLong();
1071 if (zipFile.lastModified() != fileStamp) { 1033 if (zipFile.lastModified() != fileStamp) {
1072 ret = false; 1034 ret = false;
1073 } else { 1035 } else {
1074 directories = new HashMap<String, DirectoryEntry>(); 1036 directories = new HashMap<RelativeDirectory, DirectoryEntry>();
1075 int numDirs = raf.readInt(); 1037 int numDirs = raf.readInt();
1076 for (int nDirs = 0; nDirs < numDirs; nDirs++) { 1038 for (int nDirs = 0; nDirs < numDirs; nDirs++) {
1077 int dirNameBytesLen = raf.readInt(); 1039 int dirNameBytesLen = raf.readInt();
1078 byte [] dirNameBytes = new byte[dirNameBytesLen]; 1040 byte [] dirNameBytes = new byte[dirNameBytesLen];
1079 raf.read(dirNameBytes); 1041 raf.read(dirNameBytes);
1080 1042
1081 String dirNameStr = new String(dirNameBytes, "UTF-8"); 1043 RelativeDirectory dirNameStr = getRelativeDirectory(new String(dirNameBytes, "UTF-8"));
1082 DirectoryEntry de = new DirectoryEntry(dirNameStr, this); 1044 DirectoryEntry de = new DirectoryEntry(dirNameStr, this);
1083 de.numEntries = raf.readInt(); 1045 de.numEntries = raf.readInt();
1084 de.writtenOffsetOffset = raf.readLong(); 1046 de.writtenOffsetOffset = raf.readLong();
1085 directories.put(dirNameStr, de); 1047 directories.put(dirNameStr, de);
1086 } 1048 }
1130 raf = new RandomAccessFile(indexFile, "rw"); 1092 raf = new RandomAccessFile(indexFile, "rw");
1131 1093
1132 raf.writeLong(zipFileLastModified); 1094 raf.writeLong(zipFileLastModified);
1133 writtenSoFar += 8; 1095 writtenSoFar += 8;
1134 1096
1135
1136 Iterator<String> iterDirName = directories.keySet().iterator();
1137 List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>(); 1097 List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>();
1138 Map<String, Long> offsets = new HashMap<String, Long>(); 1098 Map<RelativeDirectory, Long> offsets = new HashMap<RelativeDirectory, Long>();
1139 raf.writeInt(directories.keySet().size()); 1099 raf.writeInt(directories.keySet().size());
1140 writtenSoFar += 4; 1100 writtenSoFar += 4;
1141 1101
1142 while(iterDirName.hasNext()) { 1102 for (RelativeDirectory dirName: directories.keySet()) {
1143 String dirName = iterDirName.next();
1144 DirectoryEntry dirEntry = directories.get(dirName); 1103 DirectoryEntry dirEntry = directories.get(dirName);
1145 1104
1146 directoriesToWrite.add(dirEntry); 1105 directoriesToWrite.add(dirEntry);
1147 1106
1148 // Write the dir name bytes 1107 // Write the dir name bytes
1149 byte [] dirNameBytes = dirName.getBytes("UTF-8"); 1108 byte [] dirNameBytes = dirName.getPath().getBytes("UTF-8");
1150 int dirNameBytesLen = dirNameBytes.length; 1109 int dirNameBytesLen = dirNameBytes.length;
1151 raf.writeInt(dirNameBytesLen); 1110 raf.writeInt(dirNameBytesLen);
1152 writtenSoFar += 4; 1111 writtenSoFar += 4;
1153 1112
1154 raf.write(dirNameBytes); 1113 raf.write(dirNameBytes);
1249 1208
1250 public File getZipFile() { 1209 public File getZipFile() {
1251 return zipFile; 1210 return zipFile;
1252 } 1211 }
1253 1212
1213 private RelativeDirectory getRelativeDirectory(String path) {
1214 RelativeDirectory rd;
1215 SoftReference<RelativeDirectory> ref = relativeDirectoryCache.get(path);
1216 if (ref != null) {
1217 rd = ref.get();
1218 if (rd != null)
1219 return rd;
1220 }
1221 rd = new RelativeDirectory(path);
1222 relativeDirectoryCache.put(path, new SoftReference<RelativeDirectory>(rd));
1223 return rd;
1224 }
1254 1225
1255 static class Entry implements Comparable<Entry> { 1226 static class Entry implements Comparable<Entry> {
1256 public static final Entry[] EMPTY_ARRAY = {}; 1227 public static final Entry[] EMPTY_ARRAY = {};
1257 1228
1258 // Directory related 1229 // Directory related
1259 String dir; 1230 RelativeDirectory dir;
1260 boolean isDir; 1231 boolean isDir;
1261 1232
1262 // File related 1233 // File related
1263 String name; 1234 String name;
1264 1235
1267 int compressedSize; 1238 int compressedSize;
1268 long javatime; 1239 long javatime;
1269 1240
1270 private int nativetime; 1241 private int nativetime;
1271 1242
1272 public Entry(String path) { 1243 public Entry(RelativePath path) {
1273 int separator = path.lastIndexOf(File.separatorChar); 1244 this(path.dirname(), path.basename());
1274 if (separator == -1) { 1245 }
1275 dir = "".intern(); 1246
1276 name = path; 1247 public Entry(RelativeDirectory directory, String name) {
1277 } else { 1248 this.dir = directory;
1278 dir = path.substring(0, separator).intern();
1279 name = path.substring(separator + 1);
1280 }
1281 }
1282
1283 public Entry(String directory, String name) {
1284 this.dir = directory.intern();
1285 this.name = name; 1249 this.name = name;
1286 } 1250 }
1287 1251
1288 public String getName() { 1252 public String getName() {
1289 if (dir == null || dir.length() == 0) { 1253 return new RelativeFile(dir, name).getPath();
1290 return name;
1291 }
1292
1293 StringBuilder sb = new StringBuilder();
1294 sb.append(dir);
1295 sb.append(File.separatorChar);
1296 sb.append(name);
1297 return sb.toString();
1298 } 1254 }
1299 1255
1300 public String getFileName() { 1256 public String getFileName() {
1301 return name; 1257 return name;
1302 } 1258 }
1329 public boolean isDirectory() { 1285 public boolean isDirectory() {
1330 return isDir; 1286 return isDir;
1331 } 1287 }
1332 1288
1333 public int compareTo(Entry other) { 1289 public int compareTo(Entry other) {
1334 String otherD = other.dir; 1290 RelativeDirectory otherD = other.dir;
1335 if (dir != otherD) { 1291 if (dir != otherD) {
1336 int c = dir.compareTo(otherD); 1292 int c = dir.compareTo(otherD);
1337 if (c != 0) 1293 if (c != 0)
1338 return c; 1294 return c;
1339 } 1295 }
1340 return name.compareTo(other.name); 1296 return name.compareTo(other.name);
1341 } 1297 }
1342 1298
1299 @Override
1300 public boolean equals(Object o) {
1301 if (!(o instanceof Entry))
1302 return false;
1303 Entry other = (Entry) o;
1304 return dir.equals(other.dir) && name.equals(other.name);
1305 }
1306
1307 @Override
1308 public int hashCode() {
1309 int hash = 7;
1310 hash = 97 * hash + (this.dir != null ? this.dir.hashCode() : 0);
1311 hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0);
1312 return hash;
1313 }
1314
1343 1315
1344 public String toString() { 1316 public String toString() {
1345 return isDir ? ("Dir:" + dir + " : " + name) : 1317 return isDir ? ("Dir:" + dir + " : " + name) :
1346 (dir + ":" + name); 1318 (dir + ":" + name);
1347 } 1319 }

mercurial