diff --git a/jni/DeflatingDecompressor/DeflatingDecompressor.cpp b/jni/DeflatingDecompressor/DeflatingDecompressor.cpp index f84bf6cad..a31a7fb9b 100644 --- a/jni/DeflatingDecompressor/DeflatingDecompressor.cpp +++ b/jni/DeflatingDecompressor/DeflatingDecompressor.cpp @@ -7,52 +7,41 @@ #define SIZE 10 -static jobject keys[SIZE] = { 0 }; -static z_stream* values[SIZE] = { 0 }; +static z_stream* ourStreams[SIZE] = { 0 }; extern "C" -jboolean Java_org_amse_ys_zip_DeflatingDecompressor_startInflating(JNIEnv *env, jobject thiz) { +jint Java_org_amse_ys_zip_DeflatingDecompressor_startInflating(JNIEnv *env, jobject thiz) { int i; for (i = 0; i < SIZE; ++i) { - if (keys[i] == 0) { - keys[i] = thiz; - values[i] = new z_stream; - memset(values[i], 0, sizeof(z_stream)); - inflateInit2(values[i], -MAX_WBITS); - return 1; + if (ourStreams[i] == 0) { + ourStreams[i] = new z_stream; + memset(ourStreams[i], 0, sizeof(z_stream)); + inflateInit2(ourStreams[i], -MAX_WBITS); + return i; } } - return 0; + return -1; } extern "C" -void Java_org_amse_ys_zip_DeflatingDecompressor_endInflating(JNIEnv *env, jobject thiz) { - int i; - for (i = 0; i < SIZE; ++i) { - if (keys[i] == thiz) { - keys[i] = 0; - inflateEnd(values[i]); - delete values[i]; - values[i] = 0; - break; - } +void Java_org_amse_ys_zip_DeflatingDecompressor_endInflating(JNIEnv *env, jobject thiz, jint inflatorId) { + if (inflatorId >= 0 && inflatorId < SIZE) { + inflateEnd(ourStreams[inflatorId]); + delete ourStreams[inflatorId]; + ourStreams[inflatorId] = 0; } } // returns (endFlag << 32) + ((used inLength) << 16) + outLength extern "C" -jlong Java_org_amse_ys_zip_DeflatingDecompressor_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) { - if (keys[i] == thiz) { - stream = values[i]; - break; - } - } - if (stream == 0) { +jlong Java_org_amse_ys_zip_DeflatingDecompressor_inflate(JNIEnv *env, jobject thiz, jint inflatorId, jbyteArray in, jint inOffset, jint inLength, jbyteArray out) { + if (inflatorId < 0 || inflatorId >= SIZE) { return -1; } + z_stream *stream = ourStreams[inflatorId]; + if (stream == 0) { + return -2; + } jbyte* inStart = env->GetByteArrayElements(in, 0); jbyte* outStart = env->GetByteArrayElements(out, 0); @@ -71,5 +60,5 @@ jlong Java_org_amse_ys_zip_DeflatingDecompressor_inflate(JNIEnv *env, jobject th } return result; } - return -2; + return -3; } diff --git a/src/org/amse/ys/zip/Decompressor.java b/src/org/amse/ys/zip/Decompressor.java index d5c52d64a..4a84e7809 100644 --- a/src/org/amse/ys/zip/Decompressor.java +++ b/src/org/amse/ys/zip/Decompressor.java @@ -26,7 +26,7 @@ public abstract class Decompressor { } } - public static Decompressor init(MyBufferedInputStream is, LocalFileHeader header) throws IOException { + static Decompressor init(MyBufferedInputStream is, LocalFileHeader header) throws IOException { switch (header.CompressionMethod) { case 0: return new NoCompressionDecompressor(is, header); diff --git a/src/org/amse/ys/zip/DeflatingDecompressor.java b/src/org/amse/ys/zip/DeflatingDecompressor.java index 8c6736922..c2b632183 100644 --- a/src/org/amse/ys/zip/DeflatingDecompressor.java +++ b/src/org/amse/ys/zip/DeflatingDecompressor.java @@ -7,10 +7,10 @@ class DeflatingDecompressor extends Decompressor { System.loadLibrary("DeflatingDecompressor"); } - // common variables - private MyBufferedInputStream myStream; - private int myCompressedAvailable; - private int myAvailable; + // common variables + private MyBufferedInputStream myStream; + private int myCompressedAvailable; + private int myAvailable; private static final int IN_BUFFER_SIZE = 2048; private static final int OUT_BUFFER_SIZE = 32768; @@ -22,21 +22,21 @@ class DeflatingDecompressor extends Decompressor { private int myOutBufferOffset; private int myOutBufferLength; - private boolean myInflatingInProgress; + private volatile int myInflatorId = -1; - public DeflatingDecompressor(MyBufferedInputStream inputStream, LocalFileHeader header) throws IOException { - super(); - reset(inputStream, header); - } + public DeflatingDecompressor(MyBufferedInputStream inputStream, LocalFileHeader header) throws IOException { + super(); + reset(inputStream, header); + } - void reset(MyBufferedInputStream inputStream, LocalFileHeader header) throws IOException { - if (myInflatingInProgress) { - endInflating(); - myInflatingInProgress = false; + void reset(MyBufferedInputStream inputStream, LocalFileHeader header) throws IOException { + if (myInflatorId != -1) { + endInflating(myInflatorId); + myInflatorId = -1; } - myStream = inputStream; - myCompressedAvailable = header.CompressedSize; + myStream = inputStream; + myCompressedAvailable = header.CompressedSize; if (myCompressedAvailable <= 0) { myCompressedAvailable = Integer.MAX_VALUE; } @@ -50,17 +50,19 @@ class DeflatingDecompressor extends Decompressor { myOutBufferOffset = OUT_BUFFER_SIZE; myOutBufferLength = 0; - startInflating(); - myInflatingInProgress = true; - } + myInflatorId = startInflating(); + if (myInflatorId == -1) { + throw new IOException("cannot start inflating"); + } + } @Override - public int available() { - return myAvailable; - } + public int available() { + return myAvailable; + } @Override - public int read(byte[] b, int off, int len) throws IOException { + public int read(byte[] b, int off, int len) throws IOException { if (myAvailable <= 0) { return -1; } @@ -72,7 +74,7 @@ class DeflatingDecompressor extends Decompressor { fillOutBuffer(); } if (myOutBufferLength == 0) { - if (myInflatingInProgress) { + if (myInflatorId != -1) { throw new IOException("cannot read from zip"); } else { len -= toFill; @@ -94,10 +96,10 @@ class DeflatingDecompressor extends Decompressor { myAvailable = 0; } return len; - } + } @Override - public int read() throws IOException { + public int read() throws IOException { if (myAvailable <= 0) { return -1; } @@ -105,7 +107,7 @@ class DeflatingDecompressor extends Decompressor { fillOutBuffer(); } if (myOutBufferLength == 0) { - if (myInflatingInProgress) { + if (myInflatorId != -1) { throw new IOException("cannot read from zip"); } else { myAvailable = 0; @@ -115,10 +117,10 @@ class DeflatingDecompressor extends Decompressor { --myAvailable; --myOutBufferLength; return myOutBuffer[myOutBufferOffset++]; - } + } private void fillOutBuffer() throws IOException { - if (!myInflatingInProgress) { + if (myInflatorId == -1) { return; } @@ -136,7 +138,7 @@ class DeflatingDecompressor extends Decompressor { if (myInBufferLength == 0) { break; } - final long result = inflate(myInBuffer, myInBufferOffset, myInBufferLength, myOutBuffer); + final long result = inflate(myInflatorId, myInBuffer, myInBufferOffset, myInBufferLength, myOutBuffer); if (result <= 0) { throw new IOException("Cannot inflate zip-compressed block, code = " + result); } @@ -147,15 +149,15 @@ class DeflatingDecompressor extends Decompressor { myOutBufferOffset = 0; myOutBufferLength = out; if ((result & (1L << 32)) != 0) { - endInflating(); - myInflatingInProgress = false; + endInflating(myInflatorId); + myInflatorId = -1; myStream.backSkip(myInBufferLength); break; } } } - private native boolean startInflating(); - private native void endInflating(); - private native long inflate(byte[] in, int inOffset, int inLength, byte[] out); + private native int startInflating(); + private native void endInflating(int inflatorId); + private native long inflate(int inflatorId, byte[] in, int inOffset, int inLength, byte[] out); } diff --git a/src/org/amse/ys/zip/ZipFile.java b/src/org/amse/ys/zip/ZipFile.java index 9283037b6..167befb52 100644 --- a/src/org/amse/ys/zip/ZipFile.java +++ b/src/org/amse/ys/zip/ZipFile.java @@ -1,160 +1,161 @@ -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 myFileHeaders = new LinkedHashMap() { - private static final long serialVersionUID = -4412796553514902113L; - - @Override - public LocalFileHeader get(Object key) { - return super.get(((String)key).toLowerCase()); - } - - @Override - public LocalFileHeader put(String key, LocalFileHeader value) { - return super.put(key.toLowerCase(), value); - } - }; - - private boolean myAllFilesAreRead; - - public ZipFile(String filePath) { - this(new FileInputStreamHolder(filePath)); - } - - public ZipFile(InputStreamHolder streamHolder) { - myStreamHolder = streamHolder; - } - - public Collection 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.Signature != LocalFileHeader.FILE_HEADER_SIGNATURE) { - return false; - } - if (header.FileName != null) { - myFileHeaders.put(header.FileName, header); - if (header.FileName.equalsIgnoreCase(fileToFind)) { - return true; - } - } - if ((header.Flags & 0x08) == 0) { - baseStream.skip(header.CompressedSize); - } else { - findAndReadDescriptor(baseStream, header); - } - return false; - } - - 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 myStoredStreams = new LinkedList(); - - 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"); - } -} +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 myFileHeaders = new LinkedHashMap() { + private static final long serialVersionUID = -4412796553514902113L; + + @Override + public LocalFileHeader get(Object key) { + return super.get(((String)key).toLowerCase()); + } + + @Override + public LocalFileHeader put(String key, LocalFileHeader value) { + return super.put(key.toLowerCase(), value); + } + }; + + private boolean myAllFilesAreRead; + + public ZipFile(String filePath) { + this(new FileInputStreamHolder(filePath)); + } + + public ZipFile(InputStreamHolder streamHolder) { + myStreamHolder = streamHolder; + } + + public Collection 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.Signature != LocalFileHeader.FILE_HEADER_SIGNATURE) { + return false; + } + if (header.FileName != null) { + myFileHeaders.put(header.FileName, header); + if (header.FileName.equalsIgnoreCase(fileToFind)) { + return true; + } + } + if ((header.Flags & 0x08) == 0) { + baseStream.skip(header.CompressedSize); + } else { + findAndReadDescriptor(baseStream, header); + } + return false; + } + + 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; + Decompressor.storeDecompressor(decompressor); + } + + private final Queue myStoredStreams = new LinkedList(); + + 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"); + } +}