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.Inflater 28 */ 29 30 #include <stddef.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <errno.h> 34 #include <string.h> 35 #include "jlong.h" 36 #include "jni.h" 37 #include "jvm.h" 38 #include "jni_util.h" 39 #include <zlib.h> 40 #include "java_util_zip_Inflater.h" 41 42 #define ThrowDataFormatException(env, msg) \ 43 JNU_ThrowByName(env, "java/util/zip/DataFormatException", msg) 44 45 static jfieldID needDictID; 46 static jfieldID finishedID; 47 static jfieldID bufID, offID, lenID; 48 49 JNIEXPORT void JNICALL 50 Java_java_util_zip_Inflater_initIDs(JNIEnv *env, jclass cls) 51 { 52 needDictID = (*env)->GetFieldID(env, cls, "needDict", "Z"); 53 finishedID = (*env)->GetFieldID(env, cls, "finished", "Z"); 54 bufID = (*env)->GetFieldID(env, cls, "buf", "[B"); 55 offID = (*env)->GetFieldID(env, cls, "off", "I"); 56 lenID = (*env)->GetFieldID(env, cls, "len", "I"); 57 } 58 59 JNIEXPORT jlong JNICALL 60 Java_java_util_zip_Inflater_init(JNIEnv *env, jclass cls, jboolean nowrap) 61 { 62 z_stream *strm = calloc(1, sizeof(z_stream)); 63 64 if (strm == NULL) { 65 JNU_ThrowOutOfMemoryError(env, 0); 66 return jlong_zero; 67 } else { 68 const char *msg; 69 int ret = inflateInit2(strm, nowrap ? -MAX_WBITS : MAX_WBITS); 70 switch (ret) { 71 case Z_OK: 72 return ptr_to_jlong(strm); 73 case Z_MEM_ERROR: 74 free(strm); 75 JNU_ThrowOutOfMemoryError(env, 0); 76 return jlong_zero; 77 default: 78 msg = ((strm->msg != NULL) ? strm->msg : 79 (ret == Z_VERSION_ERROR) ? 80 "zlib returned Z_VERSION_ERROR: " 81 "compile time and runtime zlib implementations differ" : 82 (ret == Z_STREAM_ERROR) ? 83 "inflateInit2 returned Z_STREAM_ERROR" : 84 "unknown error initializing zlib library"); 85 free(strm); 86 JNU_ThrowInternalError(env, msg); 87 return jlong_zero; 88 } 89 } 90 } 91 92 JNIEXPORT void JNICALL 93 Java_java_util_zip_Inflater_setDictionary(JNIEnv *env, jclass cls, jlong addr, 94 jarray b, jint off, jint len) 95 { 96 Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0); 97 int res; 98 if (buf == 0) /* out of memory */ 99 return; 100 res = inflateSetDictionary(jlong_to_ptr(addr), buf + off, len); 101 (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0); 102 switch (res) { 103 case Z_OK: 104 break; 105 case Z_STREAM_ERROR: 106 case Z_DATA_ERROR: 107 JNU_ThrowIllegalArgumentException(env, ((z_stream *)jlong_to_ptr(addr))->msg); 108 break; 109 default: 110 JNU_ThrowInternalError(env, ((z_stream *)jlong_to_ptr(addr))->msg); 111 break; 112 } 113 } 114 115 JNIEXPORT jint JNICALL 116 Java_java_util_zip_Inflater_inflateBytes(JNIEnv *env, jobject this, jlong addr, 117 jarray b, jint off, jint len) 118 { 119 z_stream *strm = jlong_to_ptr(addr); 120 jarray this_buf = (jarray)(*env)->GetObjectField(env, this, bufID); 121 jint this_off = (*env)->GetIntField(env, this, offID); 122 jint this_len = (*env)->GetIntField(env, this, lenID); 123 124 jbyte *in_buf; 125 jbyte *out_buf; 126 int ret; 127 128 in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0); 129 if (in_buf == NULL) { 130 if (this_len != 0) 131 JNU_ThrowOutOfMemoryError(env, 0); 132 return 0; 133 } 134 out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0); 135 if (out_buf == NULL) { 136 (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0); 137 if (len != 0) 138 JNU_ThrowOutOfMemoryError(env, 0); 139 return 0; 140 } 141 strm->next_in = (Bytef *) (in_buf + this_off); 142 strm->next_out = (Bytef *) (out_buf + off); 143 strm->avail_in = this_len; 144 strm->avail_out = len; 145 ret = inflate(strm, Z_PARTIAL_FLUSH); 146 (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0); 147 (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0); 148 149 switch (ret) { 150 case Z_STREAM_END: 151 (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE); 152 /* fall through */ 153 case Z_OK: 154 this_off += this_len - strm->avail_in; 155 (*env)->SetIntField(env, this, offID, this_off); 156 (*env)->SetIntField(env, this, lenID, strm->avail_in); 157 return len - strm->avail_out; 158 case Z_NEED_DICT: 159 (*env)->SetBooleanField(env, this, needDictID, JNI_TRUE); 160 /* Might have consumed some input here! */ 161 this_off += this_len - strm->avail_in; 162 (*env)->SetIntField(env, this, offID, this_off); 163 (*env)->SetIntField(env, this, lenID, strm->avail_in); 164 return 0; 165 case Z_BUF_ERROR: 166 return 0; 167 case Z_DATA_ERROR: 168 ThrowDataFormatException(env, strm->msg); 169 return 0; 170 case Z_MEM_ERROR: 171 JNU_ThrowOutOfMemoryError(env, 0); 172 return 0; 173 default: 174 JNU_ThrowInternalError(env, strm->msg); 175 return 0; 176 } 177 } 178 179 JNIEXPORT jint JNICALL 180 Java_java_util_zip_Inflater_getAdler(JNIEnv *env, jclass cls, jlong addr) 181 { 182 return ((z_stream *)jlong_to_ptr(addr))->adler; 183 } 184 185 JNIEXPORT void JNICALL 186 Java_java_util_zip_Inflater_reset(JNIEnv *env, jclass cls, jlong addr) 187 { 188 if (inflateReset(jlong_to_ptr(addr)) != Z_OK) { 189 JNU_ThrowInternalError(env, 0); 190 } 191 } 192 193 JNIEXPORT void JNICALL 194 Java_java_util_zip_Inflater_end(JNIEnv *env, jclass cls, jlong addr) 195 { 196 if (inflateEnd(jlong_to_ptr(addr)) == Z_STREAM_ERROR) { 197 JNU_ThrowInternalError(env, 0); 198 } else { 199 free(jlong_to_ptr(addr)); 200 } 201 }