private void buildIndex() throws IOException { int entryCount = get2ByteLittleEndian(zipDir, 0); // Add each of the files if (entryCount > 0) { directories = new HashMap<RelativeDirectory, DirectoryEntry>(); ArrayList<Entry> entryList = new ArrayList<Entry>(); int pos = 2; for (int i = 0; i < entryCount; i++) { pos = readEntry(pos, entryList, directories); } // Add the accumulated dirs into the same list for (RelativeDirectory d : directories.keySet()) { // use shared RelativeDirectory objects for parent dirs RelativeDirectory parent = getRelativeDirectory(d.dirname().getPath()); String file = d.basename(); Entry zipFileIndexEntry = new Entry(parent, file); zipFileIndexEntry.isDir = true; entryList.add(zipFileIndexEntry); } entries = entryList.toArray(new Entry[entryList.size()]); Arrays.sort(entries); } else { cleanupState(); } }
public int compareTo(Entry other) { RelativeDirectory otherD = other.dir; if (dir != otherD) { int c = dir.compareTo(otherD); if (c != 0) return c; } return name.compareTo(other.name); }
ZipFileIndex( File zipFile, RelativeDirectory symbolFilePrefix, boolean writeIndex, boolean useCache, String cacheLocation) throws IOException { this.zipFile = zipFile; this.symbolFilePrefix = symbolFilePrefix; this.symbolFilePrefixLength = (symbolFilePrefix == null ? 0 : symbolFilePrefix.getPath().getBytes("UTF-8").length); this.writeIndex = writeIndex; this.usePreindexedCache = useCache; this.preindexedCacheLocation = cacheLocation; if (zipFile != null) { this.zipFileLastModified = zipFile.lastModified(); } // Validate integrity of the zip file checkIndex(); }
private boolean writeIndex() { boolean ret = false; if (readFromIndex || !usePreindexedCache) { return true; } if (!writeIndex) { return true; } File indexFile = getIndexFile(); if (indexFile == null) { return false; } RandomAccessFile raf = null; long writtenSoFar = 0; try { raf = new RandomAccessFile(indexFile, "rw"); raf.writeLong(zipFileLastModified); writtenSoFar += 8; List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>(); Map<RelativeDirectory, Long> offsets = new HashMap<RelativeDirectory, Long>(); raf.writeInt(directories.keySet().size()); writtenSoFar += 4; for (RelativeDirectory dirName : directories.keySet()) { DirectoryEntry dirEntry = directories.get(dirName); directoriesToWrite.add(dirEntry); // Write the dir name bytes byte[] dirNameBytes = dirName.getPath().getBytes("UTF-8"); int dirNameBytesLen = dirNameBytes.length; raf.writeInt(dirNameBytesLen); writtenSoFar += 4; raf.write(dirNameBytes); writtenSoFar += dirNameBytesLen; // Write the number of files in the dir List<Entry> dirEntries = dirEntry.getEntriesAsCollection(); raf.writeInt(dirEntries.size()); writtenSoFar += 4; offsets.put(dirName, new Long(writtenSoFar)); // Write the offset of the file's data in the dir dirEntry.writtenOffsetOffset = 0L; raf.writeLong(0L); writtenSoFar += 8; } for (DirectoryEntry de : directoriesToWrite) { // Fix up the offset in the directory table long currFP = raf.getFilePointer(); long offsetOffset = offsets.get(de.dirName).longValue(); raf.seek(offsetOffset); raf.writeLong(writtenSoFar); raf.seek(currFP); // Now write each of the files in the DirectoryEntry List<Entry> list = de.getEntriesAsCollection(); for (Entry zfie : list) { // Write the name bytes byte[] zfieNameBytes = zfie.name.getBytes("UTF-8"); int zfieNameBytesLen = zfieNameBytes.length; raf.writeInt(zfieNameBytesLen); writtenSoFar += 4; raf.write(zfieNameBytes); writtenSoFar += zfieNameBytesLen; // Write isDir raf.writeByte(zfie.isDir ? (byte) 1 : (byte) 0); writtenSoFar += 1; // Write offset of bytes in the real Jar/Zip file raf.writeInt(zfie.offset); writtenSoFar += 4; // Write size of the file in the real Jar/Zip file raf.writeInt(zfie.size); writtenSoFar += 4; // Write compressed size of the file in the real Jar/Zip file raf.writeInt(zfie.compressedSize); writtenSoFar += 4; // Write java time stamp of the file in the real Jar/Zip file raf.writeLong(zfie.getLastModified()); writtenSoFar += 8; } } } catch (Throwable t) { // Do nothing } finally { try { if (raf != null) { raf.close(); } } catch (IOException ioe) { // Do nothing } } return ret; }
private int readEntry( int pos, List<Entry> entryList, Map<RelativeDirectory, DirectoryEntry> directories) throws IOException { if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) { throw new ZipException("cannot read zip file entry"); } int dirStart = pos + 46; int fileStart = dirStart; int fileEnd = fileStart + get2ByteLittleEndian(zipDir, pos + 28); if (zipFileIndex.symbolFilePrefixLength != 0 && ((fileEnd - fileStart) >= symbolFilePrefixLength)) { dirStart += zipFileIndex.symbolFilePrefixLength; fileStart += zipFileIndex.symbolFilePrefixLength; } // Force any '\' to '/'. Keep the position of the last separator. for (int index = fileStart; index < fileEnd; index++) { byte nextByte = zipDir[index]; if (nextByte == (byte) '\\') { zipDir[index] = (byte) '/'; fileStart = index + 1; } else if (nextByte == (byte) '/') { fileStart = index + 1; } } RelativeDirectory directory = null; if (fileStart == dirStart) directory = getRelativeDirectory(""); else if (lastDir != null && lastLen == fileStart - dirStart - 1) { int index = lastLen - 1; while (zipDir[lastStart + index] == zipDir[dirStart + index]) { if (index == 0) { directory = lastDir; break; } index--; } } // Sub directories if (directory == null) { lastStart = dirStart; lastLen = fileStart - dirStart - 1; directory = getRelativeDirectory(new String(zipDir, dirStart, lastLen, "UTF-8")); lastDir = directory; // Enter also all the parent directories RelativeDirectory tempDirectory = directory; while (directories.get(tempDirectory) == null) { directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex)); if (tempDirectory.path.indexOf("/") == tempDirectory.path.length() - 1) break; else { // use shared RelativeDirectory objects for parent dirs tempDirectory = getRelativeDirectory(tempDirectory.dirname().getPath()); } } } else { if (directories.get(directory) == null) { directories.put(directory, new DirectoryEntry(directory, zipFileIndex)); } } // For each dir create also a file if (fileStart != fileEnd) { Entry entry = new Entry(directory, new String(zipDir, fileStart, fileEnd - fileStart, "UTF-8")); entry.setNativeTime(get4ByteLittleEndian(zipDir, pos + 12)); entry.compressedSize = get4ByteLittleEndian(zipDir, pos + 20); entry.size = get4ByteLittleEndian(zipDir, pos + 24); entry.offset = get4ByteLittleEndian(zipDir, pos + 42); entryList.add(entry); } return pos + 46 + get2ByteLittleEndian(zipDir, pos + 28) + get2ByteLittleEndian(zipDir, pos + 30) + get2ByteLittleEndian(zipDir, pos + 32); }
@Override public boolean equals(Object o) { if (!(o instanceof Entry)) return false; Entry other = (Entry) o; return dir.equals(other.dir) && name.equals(other.name); }