implement Inflater and InflaterInputStream

This commit is contained in:
Joel Dice 2007-09-17 16:15:16 -06:00
parent 8af76b0da6
commit 923c4661e8
4 changed files with 243 additions and 2 deletions

View File

@ -0,0 +1,75 @@
#include "stdlib.h"
#include "string.h"
#include "zlib.h"
#include "jni.h"
#include "jni-util.h"
#undef JNIEXPORT
#define JNIEXPORT __attribute__ ((visibility("default")))
extern "C" JNIEXPORT jlong JNICALL
Java_java_util_zip_Inflater_make
(JNIEnv* e, jclass, jboolean nowrap)
{
z_stream* s = static_cast<z_stream*>(malloc(sizeof(z_stream)));
memset(s, 0, sizeof(z_stream));
int r = inflateInit2(s, (nowrap ? -15 : 15));
if (r != Z_OK) {
free(s);
throwNew(e, "java/lang/RuntimeException", zError(r));
return 0;
}
return reinterpret_cast<jlong>(s);
}
extern "C" JNIEXPORT void JNICALL
Java_java_util_zip_Inflater_dispose(JNIEnv*, jclass, jlong peer)
{
z_stream* s = reinterpret_cast<z_stream*>(peer);
inflateEnd(s);
free(s);
}
extern "C" JNIEXPORT void JNICALL
Java_java_util_zip_Inflater_inflate
(JNIEnv* e, jclass, jlong peer,
jbyteArray input, jint inputOffset, jint inputLength,
jbyteArray output, jint outputOffset, jint outputLength,
jintArray results)
{
z_stream* s = reinterpret_cast<z_stream*>(peer);
jbyte* in = static_cast<jbyte*>(malloc(inputLength));
if (in == 0) {
throwNew(e, "java/lang/OutOfMemoryError", 0);
return;
}
jbyte* out = static_cast<jbyte*>(malloc(outputLength));
if (out == 0) {
free(in);
throwNew(e, "java/lang/OutOfMemoryError", 0);
return;
}
e->GetByteArrayRegion(input, inputOffset, inputLength, in);
s->next_in = reinterpret_cast<Bytef*>(in);
s->avail_in = inputLength;
s->next_out = reinterpret_cast<Bytef*>(out);
s->avail_out = outputLength;
int r = inflate(s, Z_SYNC_FLUSH);
jint resultArray[3]
= { r, inputLength - s->avail_in, outputLength - s->avail_out };
free(in);
e->SetByteArrayRegion(output, outputOffset, resultArray[2], out);
free(out);
e->SetIntArrayRegion(results, 0, 3, resultArray);
}

View File

@ -0,0 +1,11 @@
package java.util.zip;
public class DataFormatException extends Exception {
public DataFormatException(String s) {
super(s);
}
public DataFormatException() {
super();
}
}

View File

@ -0,0 +1,110 @@
package java.util.zip;
public class Inflater {
private static final int Z_OK = 0;
private static final int Z_STREAM_END = 1;
private static final int Z_NEED_DICT = 2;
static {
System.loadLibrary("natives");
}
private long peer;
private byte[] input;
private int offset;
private int length;
private boolean needDictionary;
private boolean finished;
public Inflater(boolean nowrap) {
peer = make(nowrap);
}
public Inflater() {
this(false);
}
private void check() {
if (peer == 0) {
throw new IllegalStateException();
}
}
private static native long make(boolean nowrap);
public boolean finished() {
return finished;
}
public boolean needsDictionary() {
return needDictionary;
}
public boolean needsInput() {
return getRemaining() == 0;
}
public int getRemaining() {
return length;
}
public void setInput(byte[] input, int offset, int length) {
this.input = input;
this.offset = offset;
this.length = length;
}
public int inflate(byte[] output, int offset, int length)
throws DataFormatException
{
final int zlibResult = 0;
final int inputCount = 1;
final int outputCount = 2;
if (peer == 0) {
throw new IllegalStateException();
}
if (input == null || output == null) {
throw new NullPointerException();
}
int[] results = new int[3];
inflate(peer, input, this.offset, this.length,
output, offset, length, results);
if (results[zlibResult] < 0) {
throw new DataFormatException();
}
switch (results[zlibResult]) {
case Z_NEED_DICT:
needDictionary = true;
break;
case Z_STREAM_END:
finished = true;
break;
}
this.offset += results[inputCount];
this.length -= results[inputCount];
return results[outputCount];
}
private static native void inflate
(long peer,
byte[] input, int inputOffset, int inputLength,
byte[] output, int outputOffset, int outputLength,
int[] results);
public void dispose() {
if (peer != 0) {
dispose(peer);
peer = 0;
}
}
private static native void dispose(long peer);
}

View File

@ -2,19 +2,64 @@ package java.util.zip;
import java.io.InputStream;
import java.io.IOException;
import java.io.EOFException;
public class InflaterInputStream extends InputStream {
private final InputStream in;
private final Inflater inflater;
private final byte[] buffer;
public InflaterInputStream(InputStream in, Inflater inflater, int bufferSize)
{
this.in = in;
this.inflater = inflater;
this.buffer = new byte[bufferSize];
}
public InflaterInputStream(InputStream in, Inflater inflater) {
this(in, inflater, 4 * 1024);
}
public InflaterInputStream(InputStream in) {
this.in = in;
this(in, new Inflater());
}
public int read() throws IOException {
throw new IOException("not implemented");
byte[] buffer = new byte[1];
int c = read(buffer);
return (c < 0 ? c : (buffer[0] & 0xFF));
}
public int read(byte[] b, int offset, int length) throws IOException {
if (inflater.finished()) {
return -1;
}
while (true) {
if (inflater.needsInput()) {
int count = in.read(buffer);
if (count > 0) {
inflater.setInput(buffer, 0, count);
} else {
throw new EOFException();
}
}
try {
int count = inflater.inflate(b, offset, length);
if (count > 0) {
return count;
} else if (inflater.needsDictionary()) {
throw new IOException("missing dictionary");
}
} catch (DataFormatException e) {
throw new IOException(e);
}
}
}
public void close() throws IOException {
in.close();
inflater.dispose();
}
}