1 /*
   2  * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 /*
  27  * Native method support for java.util.zip.Deflater
  28  */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include "jlong.h"
  33 #include "jni.h"
  34 #include "jni_util.h"
  35 #include "zlib.h"
  36 
  37 #include "java_util_zip_Deflater.h"
  38 
  39 #define DEF_MEM_LEVEL 8
  40 
  41 static jfieldID strmID;
  42 static jfieldID levelID;
  43 static jfieldID strategyID;
  44 static jfieldID setParamsID;
  45 static jfieldID finishID;
  46 static jfieldID finishedID;
  47 static jfieldID bufID, offID, lenID;
  48 
  49 JNIEXPORT void JNICALL
  50 Java_java_util_zip_Deflater_initIDs(JNIEnv *env, jclass cls)
  51 {
  52     strmID = (*env)->GetFieldID(env, cls, "strm", "J");
  53     levelID = (*env)->GetFieldID(env, cls, "level", "I");
  54     strategyID = (*env)->GetFieldID(env, cls, "strategy", "I");
  55     setParamsID = (*env)->GetFieldID(env, cls, "setParams", "Z");
  56     finishID = (*env)->GetFieldID(env, cls, "finish", "Z");
  57     finishedID = (*env)->GetFieldID(env, cls, "finished", "Z");
  58     bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
  59     offID = (*env)->GetFieldID(env, cls, "off", "I");
  60     lenID = (*env)->GetFieldID(env, cls, "len", "I");
  61 }
  62 
  63 JNIEXPORT jlong JNICALL
  64 Java_java_util_zip_Deflater_init(JNIEnv *env, jclass cls, jint level,
  65                                  jint strategy, jboolean nowrap)
  66 {
  67     z_stream *strm = calloc(1, sizeof(z_stream));
  68 
  69     if (strm == 0) {
  70         JNU_ThrowOutOfMemoryError(env, 0);
  71         return jlong_zero;
  72     } else {
  73         char *msg;
  74         switch (deflateInit2(strm, level, Z_DEFLATED,
  75                              nowrap ? -MAX_WBITS : MAX_WBITS,
  76                              DEF_MEM_LEVEL, strategy)) {
  77           case Z_OK:
  78             return ptr_to_jlong(strm);
  79           case Z_MEM_ERROR:
  80             free(strm);
  81             JNU_ThrowOutOfMemoryError(env, 0);
  82             return jlong_zero;
  83           case Z_STREAM_ERROR:
  84             free(strm);
  85             JNU_ThrowIllegalArgumentException(env, 0);
  86             return jlong_zero;
  87           default:
  88             msg = strm->msg;
  89             free(strm);
  90             JNU_ThrowInternalError(env, msg);
  91             return jlong_zero;
  92         }
  93     }
  94 }
  95 
  96 JNIEXPORT void JNICALL
  97 Java_java_util_zip_Deflater_setDictionary(JNIEnv *env, jclass cls, jlong strm,
  98                                           jarray b, jint off, jint len)
  99 {
 100     Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
 101     int res;
 102     if (buf == 0) {/* out of memory */
 103         return;
 104     }
 105     res = deflateSetDictionary((z_stream *)jlong_to_ptr(strm), buf + off, len);
 106     (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
 107     switch (res) {
 108     case Z_OK:
 109         break;
 110     case Z_STREAM_ERROR:
 111         JNU_ThrowIllegalArgumentException(env, 0);
 112         break;
 113     default:
 114         JNU_ThrowInternalError(env, ((z_stream *)jlong_to_ptr(strm))->msg);
 115         break;
 116     }
 117 }
 118 
 119 JNIEXPORT jint JNICALL
 120 Java_java_util_zip_Deflater_deflateBytes(JNIEnv *env, jobject this,
 121                                          jarray b, jint off, jint len)
 122 {
 123     z_stream *strm = jlong_to_ptr((*env)->GetLongField(env, this, strmID));
 124 
 125     if (strm == 0) {
 126         JNU_ThrowNullPointerException(env, 0);
 127         return 0;
 128     } else {
 129         jarray this_buf = (*env)->GetObjectField(env, this, bufID);
 130         jint this_off = (*env)->GetIntField(env, this, offID);
 131         jint this_len = (*env)->GetIntField(env, this, lenID);
 132         jbyte *in_buf;
 133         jbyte *out_buf;
 134         int res;
 135         if ((*env)->GetBooleanField(env, this, setParamsID)) {
 136             int level = (*env)->GetIntField(env, this, levelID);
 137             int strategy = (*env)->GetIntField(env, this, strategyID);
 138 
 139             in_buf = (jbyte *) malloc(this_len);
 140             if (in_buf == 0) {
 141                 JNU_ThrowOutOfMemoryError(env, 0);
 142                 return 0;
 143             }
 144             (*env)->GetByteArrayRegion(env, this_buf, this_off, this_len, in_buf);
 145 
 146             out_buf = (jbyte *) malloc(len);
 147             if (out_buf == 0) {
 148                 free(in_buf);
 149                 JNU_ThrowOutOfMemoryError(env, 0);
 150                 return 0;
 151             }
 152 
 153             strm->next_in = (Bytef *) in_buf;
 154             strm->next_out = (Bytef *) out_buf;
 155             strm->avail_in = this_len;
 156             strm->avail_out = len;
 157             res = deflateParams(strm, level, strategy);
 158 
 159             if (res == Z_OK) {
 160                 (*env)->SetByteArrayRegion(env, b, off, len - strm->avail_out, out_buf);
 161             }
 162             free(out_buf);
 163             free(in_buf);
 164 
 165             switch (res) {
 166             case Z_OK:
 167                 (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
 168                 this_off += this_len - strm->avail_in;
 169                 (*env)->SetIntField(env, this, offID, this_off);
 170                 (*env)->SetIntField(env, this, lenID, strm->avail_in);
 171                 return len - strm->avail_out;
 172             case Z_BUF_ERROR:
 173                 (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
 174                 return 0;
 175             default:
 176                 JNU_ThrowInternalError(env, strm->msg);
 177                 return 0;
 178             }
 179         } else {
 180             jboolean finish = (*env)->GetBooleanField(env, this, finishID);
 181 
 182             in_buf = (jbyte *) malloc(this_len);
 183             if (in_buf == 0) {
 184                 JNU_ThrowOutOfMemoryError(env, 0);
 185                 return 0;
 186             }
 187             (*env)->GetByteArrayRegion(env, this_buf, this_off, this_len, in_buf);
 188 
 189             out_buf = (jbyte *) malloc(len);
 190             if (out_buf == 0) {
 191                 free(in_buf);
 192                 JNU_ThrowOutOfMemoryError(env, 0);
 193                 return 0;
 194             }
 195 
 196             strm->next_in = (Bytef *) in_buf;
 197             strm->next_out = (Bytef *) out_buf;
 198             strm->avail_in = this_len;
 199             strm->avail_out = len;
 200             res = deflate(strm, finish ? Z_FINISH : Z_NO_FLUSH);
 201 
 202             if (res == Z_STREAM_END || res == Z_OK) {
 203                 (*env)->SetByteArrayRegion(env, b, off, len - strm->avail_out, out_buf);
 204             }
 205             free(out_buf);
 206             free(in_buf);
 207 
 208             switch (res) {
 209             case Z_STREAM_END:
 210                 (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE);
 211                 /* fall through */
 212             case Z_OK:
 213                 this_off += this_len - strm->avail_in;
 214                 (*env)->SetIntField(env, this, offID, this_off);
 215                 (*env)->SetIntField(env, this, lenID, strm->avail_in);
 216                 return len - strm->avail_out;
 217             case Z_BUF_ERROR:
 218                 return 0;
 219             default:
 220                 JNU_ThrowInternalError(env, strm->msg);
 221                 return 0;
 222             }
 223         }
 224     }
 225 }
 226 
 227 JNIEXPORT jint JNICALL
 228 Java_java_util_zip_Deflater_getAdler(JNIEnv *env, jclass cls, jlong strm)
 229 {
 230     return ((z_stream *)jlong_to_ptr(strm))->adler;
 231 }
 232 
 233 JNIEXPORT jlong JNICALL
 234 Java_java_util_zip_Deflater_getBytesRead(JNIEnv *env, jclass cls, jlong strm)
 235 {
 236     return ((z_stream *)jlong_to_ptr(strm))->total_in;
 237 }
 238 
 239 JNIEXPORT jlong JNICALL
 240 Java_java_util_zip_Deflater_getBytesWritten(JNIEnv *env, jclass cls, jlong strm)
 241 {
 242     return ((z_stream *)jlong_to_ptr(strm))->total_out;
 243 }
 244 
 245 JNIEXPORT void JNICALL
 246 Java_java_util_zip_Deflater_reset(JNIEnv *env, jclass cls, jlong strm)
 247 {
 248     if (deflateReset((z_stream *)jlong_to_ptr(strm)) != Z_OK) {
 249         JNU_ThrowInternalError(env, 0);
 250     }
 251 }
 252 
 253 JNIEXPORT void JNICALL
 254 Java_java_util_zip_Deflater_end(JNIEnv *env, jclass cls, jlong strm)
 255 {
 256     if (deflateEnd((z_stream *)jlong_to_ptr(strm)) == Z_STREAM_ERROR) {
 257         JNU_ThrowInternalError(env, 0);
 258     } else {
 259         free((z_stream *)jlong_to_ptr(strm));
 260     }
 261 }