1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-05 02:39:23 +02:00
FBReaderJ/src/org/amse/ys/zip/ZipFile.java
Nikolay Pultsin 9ebd823406 better zip processing
git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@1311 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
2010-04-30 04:26:10 +00:00

142 lines
4.3 KiB
Java

package org.amse.ys.zip;
import java.io.*;
import java.util.*;
public final class ZipFile {
public static interface InputStreamHolder {
InputStream getInputStream() throws IOException;
}
private static final class FileInputStreamHolder implements InputStreamHolder {
private final String myFilePath;
FileInputStreamHolder(String filePath) {
myFilePath = filePath;
}
public InputStream getInputStream() throws IOException {
return new FileInputStream(myFilePath);
}
}
private final InputStreamHolder myStreamHolder;
private final LinkedHashMap<String,LocalFileHeader> myFileHeaders = new LinkedHashMap<String,LocalFileHeader>();
private boolean myAllFilesAreRead;
public ZipFile(String filePath) {
this(new FileInputStreamHolder(filePath));
}
public ZipFile(InputStreamHolder streamHolder) {
myStreamHolder = streamHolder;
}
public Collection<LocalFileHeader> headers() {
try {
readAllHeaders();
} catch (IOException e) {
}
return myFileHeaders.values();
}
private boolean readFileHeader(MyBufferedInputStream baseStream, String fileToFind) throws IOException {
LocalFileHeader header = new LocalFileHeader();
header.readFrom(baseStream);
if (header.FileName != null) {
myFileHeaders.put(header.FileName, header);
}
if ((header.Flags & 0x08) == 0) {
baseStream.skip(header.CompressedSize);
} else {
findAndReadDescriptor(baseStream, header);
}
return header.FileName != null && header.FileName.equals(fileToFind);
}
private void readAllHeaders() throws IOException {
if (myAllFilesAreRead) {
return;
}
myAllFilesAreRead = true;
MyBufferedInputStream baseStream = getBaseStream();
baseStream.setPosition(0);
myFileHeaders.clear();
try {
while (true) {
readFileHeader(baseStream, null);
}
} finally {
storeBaseStream(baseStream);
}
}
/**
* Finds descriptor of the last header and installs sizes of files
*/
private void findAndReadDescriptor(MyBufferedInputStream baseStream, LocalFileHeader header) throws IOException {
Decompressor decompressor = Decompressor.init(baseStream, header);
int uncompressedSize = 0;
while (true) {
int blockSize = decompressor.read(null, 0, 2048);
if (blockSize <= 0) {
break;
}
uncompressedSize += blockSize;
}
header.UncompressedSize = uncompressedSize;
}
private final Queue<MyBufferedInputStream> myStoredStreams = new LinkedList<MyBufferedInputStream>();
synchronized void storeBaseStream(MyBufferedInputStream baseStream) {
myStoredStreams.add(baseStream);
}
synchronized MyBufferedInputStream getBaseStream() throws IOException {
MyBufferedInputStream baseStream = myStoredStreams.poll();
return (baseStream != null) ? baseStream : new MyBufferedInputStream(myStreamHolder);
}
private ZipInputStream createZipInputStream(LocalFileHeader header) throws IOException {
return new ZipInputStream(this, header);
}
public int getEntrySize(String entryName) throws IOException {
return getHeader(entryName).UncompressedSize;
}
public InputStream getInputStream(String entryName) throws IOException {
return createZipInputStream(getHeader(entryName));
}
public LocalFileHeader getHeader(String entryName) throws IOException {
if (!myFileHeaders.isEmpty()) {
LocalFileHeader header = myFileHeaders.get(entryName);
if (header != null) {
return header;
}
if (myAllFilesAreRead) {
throw new ZipException("Entry " + entryName + " is not found");
}
}
// ready to read file header
MyBufferedInputStream baseStream = getBaseStream();
baseStream.setPosition(0);
try {
while (!readFileHeader(baseStream, entryName)) {
}
LocalFileHeader header = myFileHeaders.get(entryName);
if (header != null) {
return header;
}
} finally {
storeBaseStream(baseStream);
}
throw new ZipException("Entry " + entryName + " is not found");
}
}