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) { |
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 } |
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 } |
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(); |
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 } |