Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. 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.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * 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 <nativehelper/JNIHelp.h>
     33 #include "jlong.h"
     34 #include "jni.h"
     35 #include "jni_util.h"
     36 #include <zlib.h>
     37 
     38 
     39 #define NATIVE_METHOD(className, functionName, signature) \
     40 { #functionName, signature, (void*)(className ## _ ## functionName) }
     41 
     42 #define DEF_MEM_LEVEL 8
     43 
     44 static jfieldID levelID;
     45 static jfieldID strategyID;
     46 static jfieldID setParamsID;
     47 static jfieldID finishID;
     48 static jfieldID finishedID;
     49 static jfieldID bufID, offID, lenID;
     50 
     51 static void Deflater_initIDs(JNIEnv *env) {
     52     jclass cls = (*env)->FindClass(env, "java/util/zip/Deflater");
     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 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         const char *msg;
     74         int ret = deflateInit2(strm, level, Z_DEFLATED,
     75                                nowrap ? -MAX_WBITS : MAX_WBITS,
     76                                DEF_MEM_LEVEL, strategy);
     77         switch (ret) {
     78           case Z_OK:
     79             return ptr_to_jlong(strm);
     80           case Z_MEM_ERROR:
     81             free(strm);
     82             JNU_ThrowOutOfMemoryError(env, 0);
     83             return jlong_zero;
     84           case Z_STREAM_ERROR:
     85             free(strm);
     86             JNU_ThrowIllegalArgumentException(env, 0);
     87             return jlong_zero;
     88           default:
     89             msg = ((strm->msg != NULL) ? strm->msg :
     90                    (ret == Z_VERSION_ERROR) ?
     91                    "zlib returned Z_VERSION_ERROR: "
     92                    "compile time and runtime zlib implementations differ" :
     93                    "unknown error initializing zlib library");
     94             free(strm);
     95             JNU_ThrowInternalError(env, msg);
     96             return jlong_zero;
     97         }
     98     }
     99 }
    100 
    101 JNIEXPORT void JNICALL
    102 Deflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
    103                                           jarray b, jint off, jint len)
    104 {
    105     Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
    106     int res;
    107     if (buf == 0) {/* out of memory */
    108         return;
    109     }
    110     res = deflateSetDictionary((z_stream *)jlong_to_ptr(addr), buf + off, len);
    111     (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
    112     switch (res) {
    113     case Z_OK:
    114         break;
    115     case Z_STREAM_ERROR:
    116         JNU_ThrowIllegalArgumentException(env, 0);
    117         break;
    118     default:
    119         JNU_ThrowInternalError(env, ((z_stream *)jlong_to_ptr(addr))->msg);
    120         break;
    121     }
    122 }
    123 
    124 JNIEXPORT jint JNICALL
    125 Deflater_deflateBytes(JNIEnv *env, jobject this, jlong addr,
    126                                          jarray b, jint off, jint len, jint flush)
    127 {
    128     z_stream *strm = jlong_to_ptr(addr);
    129 
    130     jarray this_buf = (*env)->GetObjectField(env, this, bufID);
    131     jint this_off = (*env)->GetIntField(env, this, offID);
    132     jint this_len = (*env)->GetIntField(env, this, lenID);
    133     jbyte *in_buf;
    134     jbyte *out_buf;
    135     int res;
    136     if ((*env)->GetBooleanField(env, this, setParamsID)) {
    137         int level = (*env)->GetIntField(env, this, levelID);
    138         int strategy = (*env)->GetIntField(env, this, strategyID);
    139         in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
    140         if (in_buf == NULL) {
    141             // Throw OOME only when length is not zero
    142             if (this_len != 0)
    143                 JNU_ThrowOutOfMemoryError(env, 0);
    144             return 0;
    145         }
    146         out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
    147         if (out_buf == NULL) {
    148             (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
    149             if (len != 0)
    150                 JNU_ThrowOutOfMemoryError(env, 0);
    151             return 0;
    152         }
    153 
    154         strm->next_in = (Bytef *) (in_buf + this_off);
    155         strm->next_out = (Bytef *) (out_buf + off);
    156         strm->avail_in = this_len;
    157         strm->avail_out = len;
    158         res = deflateParams(strm, level, strategy);
    159         (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
    160         (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
    161 
    162         switch (res) {
    163         case Z_OK:
    164             (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
    165             this_off += this_len - strm->avail_in;
    166             (*env)->SetIntField(env, this, offID, this_off);
    167             (*env)->SetIntField(env, this, lenID, strm->avail_in);
    168             return len - strm->avail_out;
    169         case Z_BUF_ERROR:
    170             (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
    171             return 0;
    172         default:
    173             JNU_ThrowInternalError(env, strm->msg);
    174             return 0;
    175         }
    176     } else {
    177         jboolean finish = (*env)->GetBooleanField(env, this, finishID);
    178         in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
    179         if (in_buf == NULL) {
    180             if (this_len != 0)
    181                 JNU_ThrowOutOfMemoryError(env, 0);
    182             return 0;
    183         }
    184         out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
    185         if (out_buf == NULL) {
    186             (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
    187             if (len != 0)
    188                 JNU_ThrowOutOfMemoryError(env, 0);
    189 
    190             return 0;
    191         }
    192 
    193         strm->next_in = (Bytef *) (in_buf + this_off);
    194         strm->next_out = (Bytef *) (out_buf + off);
    195         strm->avail_in = this_len;
    196         strm->avail_out = len;
    197         res = deflate(strm, finish ? Z_FINISH : flush);
    198         (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
    199         (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
    200 
    201         switch (res) {
    202         case Z_STREAM_END:
    203             (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE);
    204             /* fall through */
    205         case Z_OK:
    206             this_off += this_len - strm->avail_in;
    207             (*env)->SetIntField(env, this, offID, this_off);
    208             (*env)->SetIntField(env, this, lenID, strm->avail_in);
    209             return len - strm->avail_out;
    210         case Z_BUF_ERROR:
    211             return 0;
    212             default:
    213             JNU_ThrowInternalError(env, strm->msg);
    214             return 0;
    215         }
    216     }
    217 }
    218 
    219 JNIEXPORT jint JNICALL
    220 Deflater_getAdler(JNIEnv *env, jclass cls, jlong addr)
    221 {
    222     return ((z_stream *)jlong_to_ptr(addr))->adler;
    223 }
    224 
    225 JNIEXPORT void JNICALL
    226 Deflater_reset(JNIEnv *env, jclass cls, jlong addr)
    227 {
    228     if (deflateReset((z_stream *)jlong_to_ptr(addr)) != Z_OK) {
    229         JNU_ThrowInternalError(env, 0);
    230     }
    231 }
    232 
    233 JNIEXPORT void JNICALL
    234 Deflater_end(JNIEnv *env, jclass cls, jlong addr)
    235 {
    236     if (deflateEnd((z_stream *)jlong_to_ptr(addr)) == Z_STREAM_ERROR) {
    237         JNU_ThrowInternalError(env, 0);
    238     } else {
    239         free((z_stream *)jlong_to_ptr(addr));
    240     }
    241 }
    242 
    243 static JNINativeMethod gMethods[] = {
    244   NATIVE_METHOD(Deflater, init, "(IIZ)J"),
    245   NATIVE_METHOD(Deflater, setDictionary, "(J[BII)V"),
    246   NATIVE_METHOD(Deflater, deflateBytes, "(J[BIII)I"),
    247   NATIVE_METHOD(Deflater, getAdler, "(J)I"),
    248   NATIVE_METHOD(Deflater, reset, "(J)V"),
    249   NATIVE_METHOD(Deflater, end, "(J)V"),
    250 };
    251 
    252 void register_java_util_zip_Deflater(JNIEnv* env) {
    253     jniRegisterNativeMethods(env, "java/util/zip/Deflater", gMethods, NELEM(gMethods));
    254 
    255     Deflater_initIDs(env);
    256 }
    257