mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-04 10:19:33 +02:00
better zip processing
git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@1311 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
parent
dabac4421a
commit
9ebd823406
13 changed files with 688 additions and 711 deletions
Binary file not shown.
|
@ -4,7 +4,7 @@ include $(CLEAR_VARS)
|
|||
|
||||
LOCAL_MODULE := DeflatingDecompressor
|
||||
LOCAL_SRC_FILES := DeflatingDecompressor.cpp
|
||||
#LOCAL_LDLIBS := -lz
|
||||
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
|
||||
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -lz
|
||||
LOCAL_ALLOW_UNDEFINED_SYMBOLS := false
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
|
|
@ -39,9 +39,9 @@ void Java_org_amse_ys_zip_NativeDeflatingDecompressor_endInflating(JNIEnv *env,
|
|||
}
|
||||
}
|
||||
|
||||
// returns ((used inLength) << 16) + utLength
|
||||
// returns (endFlag << 32) + ((used inLength) << 16) + outLength
|
||||
extern "C"
|
||||
jint Java_org_amse_ys_zip_NativeDeflatingDecompressor_inflate(JNIEnv *env, jobject thiz, jbyteArray in, jint inOffset, jint inLength, jbyteArray out) {
|
||||
jlong Java_org_amse_ys_zip_NativeDeflatingDecompressor_inflate(JNIEnv *env, jobject thiz, jbyteArray in, jint inOffset, jint inLength, jbyteArray out) {
|
||||
int i;
|
||||
z_stream *stream = 0;
|
||||
for (i = 0; i < SIZE; ++i) {
|
||||
|
@ -64,8 +64,12 @@ jint Java_org_amse_ys_zip_NativeDeflatingDecompressor_inflate(JNIEnv *env, jobje
|
|||
const int code = inflate(stream, Z_SYNC_FLUSH);
|
||||
env->ReleaseByteArrayElements(in, inStart, 0);
|
||||
env->ReleaseByteArrayElements(out, outStart, 0);
|
||||
if ((code == Z_OK) || (code == Z_STREAM_END)) {
|
||||
return ((inLength - stream->avail_in) << 16) + outLength - stream->avail_out;
|
||||
if (code == Z_OK || code == Z_STREAM_END) {
|
||||
jlong result = ((inLength - stream->avail_in) << 16) + outLength - stream->avail_out;
|
||||
if (code == Z_STREAM_END) {
|
||||
result |= ((jlong)1) << 32;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,11 +25,15 @@ final class CircularBuffer {
|
|||
if (from + length > DICTIONARY_LENGTH) {
|
||||
final int firstPart = DICTIONARY_LENGTH - from;
|
||||
final int secondPart = length - firstPart;
|
||||
System.arraycopy(myBuffer, from, buffer, offset, firstPart);
|
||||
System.arraycopy(myBuffer, 0, buffer, offset + firstPart, secondPart);
|
||||
if (buffer != null) {
|
||||
System.arraycopy(myBuffer, from, buffer, offset, firstPart);
|
||||
System.arraycopy(myBuffer, 0, buffer, offset + firstPart, secondPart);
|
||||
}
|
||||
myCurrentPosition = secondPart;
|
||||
} else {
|
||||
System.arraycopy(myBuffer, from, buffer, offset, length);
|
||||
if (buffer != null) {
|
||||
System.arraycopy(myBuffer, from, buffer, offset, length);
|
||||
}
|
||||
myCurrentPosition = from + length;
|
||||
}
|
||||
myBytesReady -= length;
|
||||
|
|
|
@ -7,6 +7,9 @@ public abstract class Decompressor {
|
|||
public Decompressor(MyBufferedInputStream is, LocalFileHeader header) {
|
||||
}
|
||||
|
||||
/**
|
||||
* byte b[] -- target buffer for bytes; might be null
|
||||
*/
|
||||
public abstract int read(byte b[], int off, int len) throws IOException;
|
||||
public abstract int read() throws IOException;
|
||||
|
||||
|
@ -35,10 +38,7 @@ public abstract class Decompressor {
|
|||
return decompressor;
|
||||
}
|
||||
}
|
||||
return
|
||||
NativeDeflatingDecompressor.INITIALIZED
|
||||
? new NativeDeflatingDecompressor(is, header)
|
||||
: new DeflatingDecompressor(is, header);
|
||||
return new NativeDeflatingDecompressor(is, header);
|
||||
default:
|
||||
throw new ZipException("Unsupported method of compression");
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public class DeflatingDecompressor extends AbstractDeflatingDecompressor {
|
|||
void reset(MyBufferedInputStream inputStream, LocalFileHeader header) throws IOException {
|
||||
myStream = inputStream;
|
||||
myHeader = header;
|
||||
myTotalLength = header.getCompressedSize();
|
||||
myTotalLength = header.CompressedSize;
|
||||
myBytesRead = 0;
|
||||
myCurrentPosition = 0;
|
||||
myTheBlockIsFinal = false;
|
||||
|
@ -56,7 +56,7 @@ public class DeflatingDecompressor extends AbstractDeflatingDecompressor {
|
|||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return myHeader.getUncompressedSize() - myCurrentPosition;
|
||||
return myHeader.UncompressedSize - myCurrentPosition;
|
||||
}
|
||||
|
||||
private void ensure16BitsInBuffer() throws IOException {
|
||||
|
|
|
@ -8,62 +8,57 @@ package org.amse.ys.zip;
|
|||
import java.io.IOException;
|
||||
|
||||
public class LocalFileHeader {
|
||||
/**
|
||||
* Initilization of constants. Implements: versions, ...
|
||||
*/
|
||||
static final int FILE_HEADER_SIGNATURE = 0x04034b50;
|
||||
static final int FOLDER_HEADER_SIGNATURE = 0x02014b50;
|
||||
static final int DATA_DESCRIPTOR_SIGNATURE = 0x07084b50;
|
||||
|
||||
final int VersionNeededToExtract;
|
||||
final int GeneralPurposeFlag;
|
||||
final int CompressionMethod;
|
||||
private int myCompressedSize; // not final!
|
||||
private int myUncompressedSize; // not final!
|
||||
final int OffsetOfLocalData;
|
||||
public final String FileName;
|
||||
private boolean mySizeIsKnown;
|
||||
int Signature;
|
||||
|
||||
LocalFileHeader(int versionNeededToExtract, int generalPurposeFlag,
|
||||
int compressionMethod, int compressedSize, int uncompressedSize,
|
||||
int offsetOfLocalData, String fileName) {
|
||||
VersionNeededToExtract = versionNeededToExtract;
|
||||
GeneralPurposeFlag = generalPurposeFlag;
|
||||
CompressionMethod = compressionMethod;
|
||||
myCompressedSize = compressedSize;
|
||||
myUncompressedSize = uncompressedSize;
|
||||
OffsetOfLocalData = offsetOfLocalData;
|
||||
FileName = fileName;
|
||||
mySizeIsKnown = ((GeneralPurposeFlag & 8) == 0);
|
||||
int Version;
|
||||
int Flags;
|
||||
int CompressionMethod;
|
||||
int ModificationTime;
|
||||
int ModificationDate;
|
||||
int CRC32;
|
||||
int CompressedSize;
|
||||
int UncompressedSize;
|
||||
int NameLength;
|
||||
int ExtraLength;
|
||||
|
||||
public String FileName;
|
||||
int DataOffset;
|
||||
|
||||
LocalFileHeader() {
|
||||
}
|
||||
|
||||
boolean sizeIsKnown() {
|
||||
return mySizeIsKnown;
|
||||
}
|
||||
|
||||
int getCompressedSize() throws IOException {
|
||||
if (mySizeIsKnown) {
|
||||
return myCompressedSize;
|
||||
} else {
|
||||
throw new ZipException(
|
||||
"Error in getCompressedSize: file size is not known yet");
|
||||
}
|
||||
}
|
||||
|
||||
int getUncompressedSize() throws IOException {
|
||||
if (mySizeIsKnown) {
|
||||
return myUncompressedSize;
|
||||
} else {
|
||||
throw new ZipException(
|
||||
"Error in getUncompressedSize: file size is not known yet");
|
||||
}
|
||||
}
|
||||
|
||||
void setSizes(int compressedSize, int uncompressedSize) {
|
||||
if (!mySizeIsKnown) {
|
||||
myCompressedSize = compressedSize;
|
||||
myUncompressedSize = uncompressedSize;
|
||||
mySizeIsKnown = true;
|
||||
}
|
||||
void readFrom(MyBufferedInputStream stream) throws IOException {
|
||||
Signature = stream.read4Bytes();
|
||||
switch (Signature) {
|
||||
default:
|
||||
break;
|
||||
case FILE_HEADER_SIGNATURE:
|
||||
Version = stream.read2Bytes();
|
||||
Flags = stream.read2Bytes();
|
||||
CompressionMethod = stream.read2Bytes();
|
||||
ModificationTime = stream.read2Bytes();
|
||||
ModificationDate = stream.read2Bytes();
|
||||
CRC32 = stream.read4Bytes();
|
||||
CompressedSize = stream.read4Bytes();
|
||||
UncompressedSize = stream.read4Bytes();
|
||||
if (CompressionMethod == 0 && CompressedSize != UncompressedSize) {
|
||||
CompressedSize = UncompressedSize;
|
||||
}
|
||||
NameLength = stream.read2Bytes();
|
||||
ExtraLength = stream.read2Bytes();
|
||||
FileName = stream.readString(NameLength);
|
||||
stream.skip(ExtraLength);
|
||||
break;
|
||||
case DATA_DESCRIPTOR_SIGNATURE:
|
||||
CRC32 = stream.read4Bytes();
|
||||
CompressedSize = stream.read4Bytes();
|
||||
UncompressedSize = stream.read4Bytes();
|
||||
break;
|
||||
}
|
||||
DataOffset = stream.offset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,9 +114,32 @@ final class MyBufferedInputStream extends InputStream {
|
|||
}
|
||||
|
||||
public void backSkip(int n) throws IOException {
|
||||
throw new IOException("Back skip is not implemented");
|
||||
if (n > 0) {
|
||||
if (myPositionInBuffer >= n) {
|
||||
myPositionInBuffer -= n;
|
||||
myBytesReady += n;
|
||||
myCurrentPosition -= n;
|
||||
} else {
|
||||
myFileInputStream.close();
|
||||
myFileInputStream = myStreamHolder.getInputStream();
|
||||
myBytesReady = 0;
|
||||
myPositionInBuffer = 0;
|
||||
int position = myCurrentPosition - n;
|
||||
myCurrentPosition = 0;
|
||||
skip(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setPosition(int position) throws IOException {
|
||||
if (myCurrentPosition < position) {
|
||||
skip(position - myCurrentPosition);
|
||||
} else {
|
||||
backSkip(myCurrentPosition - position);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public void setPosition(int position) throws IOException {
|
||||
if (myCurrentPosition < position) {
|
||||
skip(position - myCurrentPosition);
|
||||
|
@ -125,9 +148,10 @@ final class MyBufferedInputStream extends InputStream {
|
|||
myFileInputStream = myStreamHolder.getInputStream();
|
||||
myBytesReady = 0;
|
||||
skip(position);
|
||||
myCurrentPosition = position;
|
||||
}
|
||||
myCurrentPosition = position;
|
||||
}
|
||||
*/
|
||||
|
||||
public void close() throws IOException {
|
||||
myFileInputStream.close();
|
||||
|
|
|
@ -3,16 +3,8 @@ package org.amse.ys.zip;
|
|||
import java.io.*;
|
||||
|
||||
public class NativeDeflatingDecompressor extends AbstractDeflatingDecompressor {
|
||||
public static final boolean INITIALIZED;
|
||||
static {
|
||||
boolean ini;
|
||||
try {
|
||||
System.loadLibrary("DeflatingDecompressor");
|
||||
ini = true;
|
||||
} catch (Throwable t) {
|
||||
ini = false;
|
||||
}
|
||||
INITIALIZED = ini;
|
||||
System.loadLibrary("DeflatingDecompressor");
|
||||
}
|
||||
|
||||
// common variables
|
||||
|
@ -39,8 +31,8 @@ public class NativeDeflatingDecompressor extends AbstractDeflatingDecompressor {
|
|||
endInflating();
|
||||
|
||||
myStream = inputStream;
|
||||
myCompressedAvailable = header.getCompressedSize();
|
||||
myAvailable = header.getUncompressedSize();
|
||||
myCompressedAvailable = header.CompressedSize;
|
||||
myAvailable = header.UncompressedSize;
|
||||
|
||||
myInBufferOffset = IN_BUFFER_SIZE;
|
||||
myInBufferLength = 0;
|
||||
|
@ -71,7 +63,9 @@ public class NativeDeflatingDecompressor extends AbstractDeflatingDecompressor {
|
|||
throw new IOException("cannot read from zip");
|
||||
}
|
||||
final int ready = (toFill < myOutBufferLength) ? toFill : myOutBufferLength;
|
||||
System.arraycopy(myOutBuffer, myOutBufferOffset, b, off, ready);
|
||||
if (b != null) {
|
||||
System.arraycopy(myOutBuffer, myOutBufferOffset, b, off, ready);
|
||||
}
|
||||
off += ready;
|
||||
myOutBufferOffset += ready;
|
||||
toFill -= ready;
|
||||
|
@ -108,18 +102,25 @@ public class NativeDeflatingDecompressor extends AbstractDeflatingDecompressor {
|
|||
myInBufferLength = toRead;
|
||||
myCompressedAvailable -= toRead;
|
||||
}
|
||||
final int code = inflate(myInBuffer, myInBufferOffset, myInBufferLength, myOutBuffer);
|
||||
if (code == 0) {
|
||||
final long result = inflate(myInBuffer, myInBufferOffset, myInBufferLength, myOutBuffer);
|
||||
if (result == 0) {
|
||||
throw new IOException("cannot read from base stream");
|
||||
}
|
||||
myInBufferOffset += code >> 16;
|
||||
myInBufferLength -= code >> 16;
|
||||
final int in = (int)(result >> 16) & 0xFFFF;
|
||||
final int out = (int)result & 0xFFFF;
|
||||
myInBufferOffset += in;
|
||||
myInBufferLength -= in;
|
||||
myOutBufferOffset = 0;
|
||||
myOutBufferLength = code & 0x0FFFF;
|
||||
myOutBufferLength = out;
|
||||
if ((result & (1L << 32)) != 0) {
|
||||
endInflating();
|
||||
myStream.backSkip(myInBufferLength - myInBufferOffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private native boolean startInflating();
|
||||
private native void endInflating();
|
||||
private native int inflate(byte[] in, int inOffset, int inLength, byte[] out);
|
||||
private native long inflate(byte[] in, int inOffset, int inLength, byte[] out);
|
||||
}
|
||||
|
|
|
@ -20,13 +20,15 @@ public class NoCompressionDecompressor extends Decompressor {
|
|||
if (value == -1) {
|
||||
break;
|
||||
}
|
||||
b[off + i] = (byte)value;
|
||||
if (b != null) {
|
||||
b[off + i] = (byte)value;
|
||||
}
|
||||
}
|
||||
return (i > 0) ? i : -1;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if (myCurrentPosition < myHeader.getCompressedSize()) {
|
||||
if (myCurrentPosition < myHeader.CompressedSize) {
|
||||
myCurrentPosition++;
|
||||
return myStream.read();
|
||||
} else {
|
||||
|
@ -35,6 +37,6 @@ public class NoCompressionDecompressor extends Decompressor {
|
|||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return (myHeader.getUncompressedSize() - myCurrentPosition);
|
||||
return (myHeader.UncompressedSize - myCurrentPosition);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,28 +42,18 @@ public final class ZipFile {
|
|||
}
|
||||
|
||||
private boolean readFileHeader(MyBufferedInputStream baseStream, String fileToFind) throws IOException {
|
||||
int version2extract = baseStream.read2Bytes();
|
||||
int generalFlag = baseStream.read2Bytes();
|
||||
int compressionMethod = baseStream.read2Bytes();
|
||||
baseStream.skip(8);
|
||||
LocalFileHeader header = new LocalFileHeader();
|
||||
header.readFrom(baseStream);
|
||||
|
||||
int compressedSize = baseStream.read4Bytes();
|
||||
int uncompressedSize = baseStream.read4Bytes();
|
||||
int fileNameSize = baseStream.read2Bytes();
|
||||
int extraField = baseStream.read2Bytes();
|
||||
|
||||
final String fileName = baseStream.readString(fileNameSize);
|
||||
baseStream.skip(extraField);
|
||||
LocalFileHeader header = new LocalFileHeader(version2extract, generalFlag,
|
||||
compressionMethod, compressedSize, uncompressedSize,
|
||||
baseStream.offset(), fileName);
|
||||
myFileHeaders.put(fileName, header);
|
||||
if (header.sizeIsKnown()) {
|
||||
baseStream.skip(compressedSize);
|
||||
if (header.FileName != null) {
|
||||
myFileHeaders.put(header.FileName, header);
|
||||
}
|
||||
if ((header.Flags & 0x08) == 0) {
|
||||
baseStream.skip(header.CompressedSize);
|
||||
} else {
|
||||
findAndReadDescriptor(baseStream, header);
|
||||
}
|
||||
return fileName.equals(fileToFind);
|
||||
return header.FileName != null && header.FileName.equals(fileToFind);
|
||||
}
|
||||
|
||||
private void readAllHeaders() throws IOException {
|
||||
|
@ -78,16 +68,6 @@ public final class ZipFile {
|
|||
|
||||
try {
|
||||
while (true) {
|
||||
int header = baseStream.read4Bytes();
|
||||
if (header != LocalFileHeader.FILE_HEADER_SIGNATURE) {
|
||||
if (header == LocalFileHeader.FOLDER_HEADER_SIGNATURE) {
|
||||
break; // central directory, no more files
|
||||
} else {
|
||||
throw new ZipException(
|
||||
"readHeaders. Wrong signature found = " + header
|
||||
+ " at position " + baseStream.offset());
|
||||
}
|
||||
}
|
||||
readFileHeader(baseStream, null);
|
||||
}
|
||||
} finally {
|
||||
|
@ -99,39 +79,16 @@ public final class ZipFile {
|
|||
* Finds descriptor of the last header and installs sizes of files
|
||||
*/
|
||||
private void findAndReadDescriptor(MyBufferedInputStream baseStream, LocalFileHeader header) throws IOException {
|
||||
loop:
|
||||
while (true) {
|
||||
int signature = 0;
|
||||
do {
|
||||
int nextByte = baseStream.read();
|
||||
if (nextByte < 0) {
|
||||
throw new ZipException(
|
||||
"readFileHeaders. Unexpected end of file when looking for DataDescriptor");
|
||||
}
|
||||
signature = ((signature >> 8) & 0x0FFFFFF) | (nextByte << 24);
|
||||
} while (
|
||||
signature != LocalFileHeader.FILE_HEADER_SIGNATURE &&
|
||||
signature != LocalFileHeader.FOLDER_HEADER_SIGNATURE &&
|
||||
signature != LocalFileHeader.DATA_DESCRIPTOR_SIGNATURE
|
||||
);
|
||||
switch (signature) {
|
||||
case LocalFileHeader.FILE_HEADER_SIGNATURE:
|
||||
break loop;
|
||||
case LocalFileHeader.FOLDER_HEADER_SIGNATURE:
|
||||
break loop;
|
||||
case LocalFileHeader.DATA_DESCRIPTOR_SIGNATURE:
|
||||
baseStream.skip(4);
|
||||
int compressedSize = baseStream.read4Bytes();
|
||||
int uncompressedSize = baseStream.read4Bytes();
|
||||
if ((baseStream.offset() - header.OffsetOfLocalData - 16) == compressedSize) {
|
||||
header.setSizes(compressedSize, uncompressedSize);
|
||||
break loop;
|
||||
} else {
|
||||
baseStream.backSkip(12);
|
||||
continue loop;
|
||||
}
|
||||
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>();
|
||||
|
@ -150,7 +107,7 @@ loop:
|
|||
}
|
||||
|
||||
public int getEntrySize(String entryName) throws IOException {
|
||||
return getHeader(entryName).getUncompressedSize();
|
||||
return getHeader(entryName).UncompressedSize;
|
||||
}
|
||||
|
||||
public InputStream getInputStream(String entryName) throws IOException {
|
||||
|
@ -171,18 +128,8 @@ loop:
|
|||
MyBufferedInputStream baseStream = getBaseStream();
|
||||
baseStream.setPosition(0);
|
||||
try {
|
||||
do {
|
||||
int signature = baseStream.read4Bytes();
|
||||
if (signature != LocalFileHeader.FILE_HEADER_SIGNATURE) {
|
||||
if (signature == LocalFileHeader.FOLDER_HEADER_SIGNATURE) {
|
||||
break; // central directory, no more files
|
||||
} else {
|
||||
throw new ZipException(
|
||||
"Wrong signature " + signature
|
||||
+ " found at position " + baseStream.offset());
|
||||
}
|
||||
}
|
||||
} while (!readFileHeader(baseStream, entryName));
|
||||
while (!readFileHeader(baseStream, entryName)) {
|
||||
}
|
||||
LocalFileHeader header = myFileHeaders.get(entryName);
|
||||
if (header != null) {
|
||||
return header;
|
||||
|
|
|
@ -14,7 +14,7 @@ class ZipInputStream extends InputStream {
|
|||
public ZipInputStream(ZipFile parent, LocalFileHeader header) throws IOException {
|
||||
myParent = parent;
|
||||
myBaseStream = parent.getBaseStream();
|
||||
myBaseStream.setPosition(header.OffsetOfLocalData);
|
||||
myBaseStream.setPosition(header.DataOffset);
|
||||
myDecompressor = Decompressor.init(myBaseStream, header);
|
||||
}
|
||||
|
||||
|
|
|
@ -832,7 +832,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
|||
}
|
||||
|
||||
public final synchronized void gotoPosition(int paragraphIndex, int wordIndex, int charIndex) {
|
||||
if (myModel != null) {
|
||||
if (myModel != null && myModel.getParagraphsNumber() > 0) {
|
||||
myCurrentPage.moveStartCursor(paragraphIndex, wordIndex, charIndex);
|
||||
myPreviousPage.reset();
|
||||
myNextPage.reset();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue