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