/* * Copyright 1997-2005 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ /* * Native method support for java.util.zip.Deflater */ #include #include #include "jlong.h" #include "jni.h" #include "jni_util.h" #include "zlib.h" #include "java_util_zip_Deflater.h" #define DEF_MEM_LEVEL 8 #define STRIDE_BUF_SIZE 4096 static jfieldID strmID; static jfieldID levelID; static jfieldID strategyID; static jfieldID setParamsID; static jfieldID finishID; static jfieldID finishedID; static jfieldID bufID, offID, lenID; typedef struct { z_stream strm; jbyte in_buf[STRIDE_BUF_SIZE]; jbyte out_buf[STRIDE_BUF_SIZE]; jint stride_read_off; jint stride_read_len; } def_data; JNIEXPORT void JNICALL Java_java_util_zip_Deflater_initIDs(JNIEnv *env, jclass cls) { strmID = (*env)->GetFieldID(env, cls, "strm", "J"); levelID = (*env)->GetFieldID(env, cls, "level", "I"); strategyID = (*env)->GetFieldID(env, cls, "strategy", "I"); setParamsID = (*env)->GetFieldID(env, cls, "setParams", "Z"); finishID = (*env)->GetFieldID(env, cls, "finish", "Z"); finishedID = (*env)->GetFieldID(env, cls, "finished", "Z"); bufID = (*env)->GetFieldID(env, cls, "buf", "[B"); offID = (*env)->GetFieldID(env, cls, "off", "I"); lenID = (*env)->GetFieldID(env, cls, "len", "I"); } JNIEXPORT jlong JNICALL Java_java_util_zip_Deflater_init(JNIEnv *env, jclass cls, jint level, jint strategy, jboolean nowrap) { def_data *defptr = calloc(1, sizeof(def_data)); if (defptr == 0) { JNU_ThrowOutOfMemoryError(env, 0); return jlong_zero; } else { char *msg; switch (deflateInit2(&defptr->strm, level, Z_DEFLATED, nowrap ? -MAX_WBITS : MAX_WBITS, DEF_MEM_LEVEL, strategy)) { case Z_OK: return ptr_to_jlong(defptr); case Z_MEM_ERROR: free(defptr); JNU_ThrowOutOfMemoryError(env, 0); return jlong_zero; case Z_STREAM_ERROR: free(defptr); JNU_ThrowIllegalArgumentException(env, 0); return jlong_zero; default: msg = defptr->strm.msg; free(defptr); JNU_ThrowInternalError(env, msg); return jlong_zero; } } } JNIEXPORT void JNICALL Java_java_util_zip_Deflater_setDictionary(JNIEnv *env, jclass cls, jlong defadr, jarray b, jint off, jint len) { Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0); int res; if (buf == 0) {/* out of memory */ return; } res = deflateSetDictionary(&(((def_data *)jlong_to_ptr(defadr))->strm), buf + off, len); (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0); switch (res) { case Z_OK: break; case Z_STREAM_ERROR: JNU_ThrowIllegalArgumentException(env, 0); break; default: JNU_ThrowInternalError(env, (((def_data *)jlong_to_ptr(defadr))->strm.msg)); break; } } JNIEXPORT jint JNICALL Java_java_util_zip_Deflater_deflateBytes(JNIEnv *env, jobject this, jlong def_adr, jbyteArray writebuf, jint writeoff, jint writelen, jbyteArray readbuf, jint readoff, jint readlen, jboolean setParams, jboolean finish) { def_data *defptr = jlong_to_ptr(def_adr); if(defptr == 0) { JNU_ThrowNullPointerException(env, 0); return 0; } const jint writelen_start = writelen; jboolean finished = JNI_FALSE; z_stream *strm = &defptr->strm; do { /*If read-stride is empty and input-bytes are left, fill it up*/ if (defptr->stride_read_len == 0 && readlen > 0) { defptr->stride_read_len = readlen > STRIDE_BUF_SIZE ? STRIDE_BUF_SIZE : readlen; defptr->stride_read_off = 0; (*env)->GetByteArrayRegion(env, readbuf, readoff, defptr->stride_read_len, &defptr->in_buf); } int availReadBytes = writelen > STRIDE_BUF_SIZE ? STRIDE_BUF_SIZE : writelen; strm->next_in = (Bytef *) (&defptr->in_buf + defptr->stride_read_off); strm->next_out = (Bytef *) &defptr->out_buf; strm->avail_in = defptr->stride_read_len; strm->avail_out = availReadBytes; int zres; if(setParams) { int level = (*env)->GetIntField(env, this, levelID); int strategy = (*env)->GetIntField(env, this, strategyID); /*TODO: What happens if deflateParams was called once, but not all pending output data was written because of the stride limit? Is it o.k. to continue with deflate?*/ zres = deflateParams(strm, level, strategy); }else { /*Only finish if all input data has been beed to zlib, otherwise we finish per stride which lowers compression ratio*/ zres = deflate(strm, (readlen == 0 && finish) ? Z_FINISH : Z_NO_FLUSH); } switch (zres) { case Z_STREAM_END: finished = JNI_TRUE; //fall through case Z_OK: case Z_BUF_ERROR: if(setParams) { (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE); setParams = JNI_FALSE; } int processed_out = availReadBytes - strm->avail_out; int processed_in = defptr->stride_read_len - strm->avail_in; if(processed_out > 0) { (*env)->SetByteArrayRegion(env, writebuf, writeoff, processed_out, &defptr->out_buf); writeoff += processed_out; writelen -= processed_out; } readlen -= processed_in; readoff += processed_in; defptr->stride_read_off += processed_in; defptr->stride_read_len -= processed_in; break; default: JNU_ThrowInternalError(env, strm->msg); } }while(writelen > 0 && readlen > 0 && finished==JNI_FALSE); if(finished) { (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE); } (*env)->SetIntField(env, this, offID, readoff); (*env)->SetIntField(env, this, lenID, readlen); return writelen_start - writelen; } JNIEXPORT jint JNICALL Java_java_util_zip_Deflater_getAdler(JNIEnv *env, jclass cls, jlong defadr) { return ((def_data *)jlong_to_ptr(defadr))->strm.adler; } JNIEXPORT jlong JNICALL Java_java_util_zip_Deflater_getBytesRead(JNIEnv *env, jclass cls, jlong defadr) { return ((def_data *)jlong_to_ptr(defadr))->strm.total_in; } JNIEXPORT jlong JNICALL Java_java_util_zip_Deflater_getBytesWritten(JNIEnv *env, jclass cls, jlong defadr) { return ((def_data *)jlong_to_ptr(defadr))->strm.total_out; } JNIEXPORT void JNICALL Java_java_util_zip_Deflater_reset(JNIEnv *env, jclass cls, jlong defadr) { if (deflateReset(&((def_data *)jlong_to_ptr(defadr))->strm) != Z_OK) { JNU_ThrowInternalError(env, 0); } } JNIEXPORT void JNICALL Java_java_util_zip_Deflater_end(JNIEnv *env, jclass cls, jlong defadr) { def_data *defptr = (def_data *) jlong_to_ptr(defadr); if (deflateEnd(&defptr->strm) == Z_STREAM_ERROR) { JNU_ThrowInternalError(env, 0); } else { free(defptr); } }