📄 zipfileindex.java
字号:
return allDirs;
}
catch (IOException e) {
return Collections.EMPTY_SET;
}
finally {
lock.unlock();
}
}
/**
* Tests if a specific path exists in the zip. This method will return true
* for file entries and directories.
*
* @param path A path within the zip.
* @return True if the path is a file or dir, false otherwise.
*/
public boolean contains(String path) {
lock.lock();
try {
checkIndex();
return getZipIndexEntry(path) != null;
}
catch (IOException e) {
return false;
}
finally {
lock.unlock();
}
}
public boolean isDirectory(String path) throws IOException {
lock.lock();
try {
// The top level in a zip file is always a directory.
if (path.length() == 0) {
lastReferenceTimeStamp = System.currentTimeMillis();
return true;
}
if (File.separatorChar != '/')
path = path.replace('/', File.separatorChar);
checkIndex();
return directories.get(path) != null;
}
finally {
lock.unlock();
}
}
public long getLastModified(String path) throws IOException {
lock.lock();
try {
ZipFileIndexEntry entry = getZipIndexEntry(path);
if (entry == null)
throw new FileNotFoundException();
return entry.getLastModified();
}
finally {
lock.unlock();
}
}
public int length(String path) throws IOException {
lock.lock();
try {
ZipFileIndexEntry entry = getZipIndexEntry(path);
if (entry == null)
throw new FileNotFoundException();
if (entry.isDir) {
return 0;
}
byte[] header = getHeader(entry);
// entry is not compressed?
if (get2ByteLittleEndian(header, 8) == 0) {
return entry.compressedSize;
} else {
return entry.size;
}
}
finally {
lock.unlock();
}
}
public byte[] read(String path) throws IOException {
lock.lock();
try {
ZipFileIndexEntry entry = getZipIndexEntry(path);
if (entry == null)
throw new FileNotFoundException(MessageFormat.format("Path not found in ZIP: {0}", path));
return read(entry);
}
finally {
lock.unlock();
}
}
public byte[] read(ZipFileIndexEntry entry) throws IOException {
lock.lock();
try {
openFile();
byte[] result = readBytes(entry);
closeFile();
return result;
}
finally {
lock.unlock();
}
}
public int read(String path, byte[] buffer) throws IOException {
lock.lock();
try {
ZipFileIndexEntry entry = getZipIndexEntry(path);
if (entry == null)
throw new FileNotFoundException();
return read(entry, buffer);
}
finally {
lock.unlock();
}
}
public int read(ZipFileIndexEntry entry, byte[] buffer)
throws IOException {
lock.lock();
try {
int result = readBytes(entry, buffer);
return result;
}
finally {
lock.unlock();
}
}
private byte[] readBytes(ZipFileIndexEntry entry) throws IOException {
byte[] header = getHeader(entry);
int csize = entry.compressedSize;
byte[] cbuf = new byte[csize];
zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
zipRandomFile.readFully(cbuf, 0, csize);
// is this compressed - offset 8 in the ZipEntry header
if (get2ByteLittleEndian(header, 8) == 0)
return cbuf;
int size = entry.size;
byte[] buf = new byte[size];
if (inflate(cbuf, buf) != size)
throw new ZipException("corrupted zip file");
return buf;
}
/**
*
*/
private int readBytes(ZipFileIndexEntry entry, byte[] buffer) throws IOException {
byte[] header = getHeader(entry);
// entry is not compressed?
if (get2ByteLittleEndian(header, 8) == 0) {
zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
int offset = 0;
int size = buffer.length;
while (offset < size) {
int count = zipRandomFile.read(buffer, offset, size - offset);
if (count == -1)
break;
offset += count;
}
return entry.size;
}
int csize = entry.compressedSize;
byte[] cbuf = new byte[csize];
zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28));
zipRandomFile.readFully(cbuf, 0, csize);
int count = inflate(cbuf, buffer);
if (count == -1)
throw new ZipException("corrupted zip file");
return entry.size;
}
//----------------------------------------------------------------------------
// Zip utilities
//----------------------------------------------------------------------------
private byte[] getHeader(ZipFileIndexEntry entry) throws IOException {
zipRandomFile.seek(entry.offset);
byte[] header = new byte[30];
zipRandomFile.readFully(header);
if (get4ByteLittleEndian(header, 0) != 0x04034b50)
throw new ZipException("corrupted zip file");
if ((get2ByteLittleEndian(header, 6) & 1) != 0)
throw new ZipException("encrypted zip file"); // offset 6 in the header of the ZipFileEntry
return header;
}
/*
* Inflate using the java.util.zip.Inflater class
*/
private static Inflater inflater;
private int inflate(byte[] src, byte[] dest) {
// construct the inflater object or reuse an existing one
if (inflater == null)
inflater = new Inflater(true);
synchronized (inflater) {
inflater.reset();
inflater.setInput(src);
try {
return inflater.inflate(dest);
} catch (DataFormatException ex) {
return -1;
}
}
}
/**
* return the two bytes buf[pos], buf[pos+1] as an unsigned integer in little
* endian format.
*/
private static int get2ByteLittleEndian(byte[] buf, int pos) {
return (buf[pos] & 0xFF) + ((buf[pos+1] & 0xFF) << 8);
}
/**
* return the 4 bytes buf[i..i+3] as an integer in little endian format.
*/
private static int get4ByteLittleEndian(byte[] buf, int pos) {
return (buf[pos] & 0xFF) + ((buf[pos + 1] & 0xFF) << 8) +
((buf[pos + 2] & 0xFF) << 16) + ((buf[pos + 3] & 0xFF) << 24);
}
/* ----------------------------------------------------------------------------
* ZipDirectory
* ----------------------------------------------------------------------------*/
private class ZipDirectory {
private String lastDir;
private int lastStart;
private int lastLen;
byte[] zipDir;
RandomAccessFile zipRandomFile = null;
ZipFileIndex zipFileIndex = null;
public ZipDirectory(RandomAccessFile zipRandomFile, long start, long end, ZipFileIndex index) throws IOException {
this.zipRandomFile = zipRandomFile;
this.zipFileIndex = index;
findCENRecord(start, end);
}
/*
* Reads zip file central directory.
* For more details see readCEN in zip_util.c from the JDK sources.
* This is a Java port of that function.
*/
private void findCENRecord(long start, long end) throws IOException {
long totalLength = end - start;
int endbuflen = 1024;
byte[] endbuf = new byte[endbuflen];
long endbufend = end - start;
// There is a variable-length field after the dir offset record. We need to do consequential search.
while (endbufend >= 22) {
if (endbufend < endbuflen)
endbuflen = (int)endbufend;
long endbufpos = endbufend - endbuflen;
zipRandomFile.seek(start + endbufpos);
zipRandomFile.readFully(endbuf, 0, endbuflen);
int i = endbuflen - 22;
while (i >= 0 &&
!(endbuf[i] == 0x50 &&
endbuf[i + 1] == 0x4b &&
endbuf[i + 2] == 0x05 &&
endbuf[i + 3] == 0x06 &&
endbufpos + i + 22 +
get2ByteLittleEndian(endbuf, i + 20) == totalLength)) {
i--;
}
if (i >= 0) {
zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2];
zipDir[0] = endbuf[i + 10];
zipDir[1] = endbuf[i + 11];
zipRandomFile.seek(start + get4ByteLittleEndian(endbuf, i + 16));
zipRandomFile.readFully(zipDir, 2, zipDir.length - 2);
return;
} else {
endbufend = endbufpos + 21;
}
}
throw new ZipException("cannot read zip file");
}
private void buildIndex() throws IOException {
int entryCount = get2ByteLittleEndian(zipDir, 0);
entries = new ZipFileIndexEntry[entryCount];
// Add each of the files
if (entryCount > 0) {
directories = new HashMap();
ArrayList<ZipFileIndexEntry> entryList = new ArrayList<ZipFileIndexEntry>();
int pos = 2;
for (int i = 0; i < entryCount; i++) {
pos = readEntry(pos, entryList, directories);
}
// Add the accumulated dirs into the same list
Iterator i = directories.keySet().iterator();
while (i.hasNext()) {
ZipFileIndexEntry zipFileIndexEntry = new ZipFileIndexEntry( (String) i.next());
zipFileIndexEntry.isDir = true;
entryList.add(zipFileIndexEntry);
}
entries = entryList.toArray(new ZipFileIndexEntry[entryList.size()]);
Arrays.sort(entries);
} else {
cleanupState();
}
}
private int readEntry(int pos, List entryList,
Map 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;
}
// Use the OS's path separator. Keep the position of the last one.
for (int index = fileStart; index < fileEnd; index++) {
byte nextByte = zipDir[index];
if (nextByte == (byte)'\\' || nextByte == (byte)'/') {
zipDir[index] = (byte)File.separatorChar;
fileStart = index + 1;
}
}
String directory = null;
if (fileStart == dirStart)
directory = "";
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 = new String(zipDir, dirStart, lastLen, "UTF-8").intern();
lastDir = directory;
// Enter also all the parent directories
String tempDirectory = directory;
while (directories.get(tempDirectory) == null) {
directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex));
int separator = tempDirectory.lastIndexOf(File.separatorChar);
if (separator == -1)
break;
tempDirectory = tempDirectory.substring(0, separator);
}
}
else {
directory = directory.intern();
if (directories.get(directory) == null) {
directories.put(directory, new DirectoryEntry(directory, zipFileIndex));
}
}
// For each dir create also a file
if (fileStart != fileEnd) {
ZipFileIndexEntry entry = new ZipFileIndexEntry(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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -