1 /* 2 * Copyright (c) 1997, 2014, 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 CHECK_NULL(needDictID); 54 finishedID = (*env)->GetFieldID(env, cls, "finished", "Z"); 55 CHECK_NULL(finishedID); 56 bufID = (*env)->GetFieldID(env, cls, "buf", "[B"); 57 CHECK_NULL(bufID); 58 offID = (*env)->GetFieldID(env, cls, "off", "I"); 59 CHECK_NULL(offID); 60 lenID = (*env)->GetFieldID(env, cls, "len", "I"); 61 CHECK_NULL(lenID); 62 } 63 64 JNIEXPORT jlong JNICALL 65 Java_java_util_zip_Inflater_init(JNIEnv *env, jclass cls, jboolean nowrap) 66 { 67 z_stream *strm = calloc(1, sizeof(z_stream)); 68 69 if (strm == NULL) { 70 JNU_ThrowOutOfMemoryError(env, 0); 71 return jlong_zero; 72 } else { 73 const char *msg; 74 int ret = inflateInit2(strm, nowrap ? -MAX_WBITS : MAX_WBITS); 75 switch (ret) { 76 case Z_OK: 77 return ptr_to_jlong(strm); 78 case Z_MEM_ERROR: 79 free(strm); 80 JNU_ThrowOutOfMemoryError(env, 0); 81 return jlong_zero; 82 default: 83 msg = ((strm->msg != NULL) ? strm->msg : 84 (ret == Z_VERSION_ERROR) ? 85 "zlib returned Z_VERSION_ERROR: " 86 "compile time and runtime zlib implementations differ" : 87 (ret == Z_STREAM_ERROR) ? 88 "inflateInit2 returned Z_STREAM_ERROR" : 89 "unknown error initializing zlib library"); 90 free(strm); 91 JNU_ThrowInternalError(env, msg); 92 return jlong_zero; 93 } 94 } 95 } 96 97 JNIEXPORT void JNICALL 98 Java_java_util_zip_Inflater_setDictionary(JNIEnv *env, jclass cls, jlong addr, 99 jarray b, jint off, jint len) 100 { 101 Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0); 102 int res; 103 if (buf == 0) /* out of memory */ 104 return; 105 res = inflateSetDictionary(jlong_to_ptr(addr), 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 case Z_DATA_ERROR: 112 JNU_ThrowIllegalArgumentException(env, ((z_stream *)jlong_to_ptr(addr))->msg); 113 break; 114 default: 115 JNU_ThrowInternalError(env, ((z_stream *)jlong_to_ptr(addr))->msg); 116 break; 117 } 118 } 119 120 JNIEXPORT jint JNICALL 121 Java_java_util_zip_Inflater_inflateBytes(JNIEnv *env, jobject this, jlong addr, 122 jarray b, jint off, jint len) 123 { 124 z_stream *strm = jlong_to_ptr(addr); 125 jarray this_buf = (jarray)(*env)->GetObjectField(env, this, bufID); 126 jint this_off = (*env)->GetIntField(env, this, offID); 127 jint this_len = (*env)->GetIntField(env, this, lenID); 128 129 jbyte *in_buf; 130 jbyte *out_buf; 131 int ret; 132 133 in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0); 134 if (in_buf == NULL) { 135 if (this_len != 0 && (*env)->ExceptionOccurred(env) == NULL) 136 JNU_ThrowOutOfMemoryError(env, 0); 137 return 0; 138 } 139 out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0); 140 if (out_buf == NULL) { 141 (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0); 142 if (len != 0 && (*env)->ExceptionOccurred(env) == NULL) 143 JNU_ThrowOutOfMemoryError(env, 0); 144 return 0; 145 } 146 strm->next_in = (Bytef *) (in_buf + this_off); 147 strm->next_out = (Bytef *) (out_buf + off); 148 strm->avail_in = this_len; 149 strm->avail_out = len; 150 151 /* The flush parameter of inflate() is set to Z_FINISH to skip 152 the allocation of a sliding window until necessary. */ 153 ret = inflate(strm, Z_FINISH); 154 (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0); 155 (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0); 156 157 /* When flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it 158 will return Z_BUF_ERROR if it has not reached the end of the stream. 159 Here we keep the same processing for both these return codes. */ 160 switch (ret) { 161 case Z_STREAM_END: 162 (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE); 163 /* fall through */ 164 case Z_OK: 165 case Z_BUF_ERROR: 166 this_off += this_len - strm->avail_in; 167 (*env)->SetIntField(env, this, offID, this_off); 168 (*env)->SetIntField(env, this, lenID, strm->avail_in); 169 return (jint) (len - strm->avail_out); 170 case Z_NEED_DICT: 171 (*env)->SetBooleanField(env, this, needDictID, JNI_TRUE); 172 /* Might have consumed some input here! */ 173 this_off += this_len - strm->avail_in; 174 (*env)->SetIntField(env, this, offID, this_off); 175 (*env)->SetIntField(env, this, lenID, strm->avail_in); 176 return 0; 177 case Z_DATA_ERROR: 178 ThrowDataFormatException(env, strm->msg); 179 return 0; 180 case Z_MEM_ERROR: 181 JNU_ThrowOutOfMemoryError(env, 0); 182 return 0; 183 default: 184 JNU_ThrowInternalError(env, strm->msg); 185 return 0; 186 } 187 } 188 189 JNIEXPORT jint JNICALL 190 Java_java_util_zip_Inflater_getAdler(JNIEnv *env, jclass cls, jlong addr) 191 { 192 return ((z_stream *)jlong_to_ptr(addr))->adler; 193 } 194 195 JNIEXPORT void JNICALL 196 Java_java_util_zip_Inflater_reset(JNIEnv *env, jclass cls, jlong addr) 197 { 198 if (inflateReset(jlong_to_ptr(addr)) != Z_OK) { 199 JNU_ThrowInternalError(env, 0); 200 } 201 } 202 203 JNIEXPORT void JNICALL 204 Java_java_util_zip_Inflater_end(JNIEnv *env, jclass cls, jlong addr) 205 { 206 if (inflateEnd(jlong_to_ptr(addr)) == Z_STREAM_ERROR) { 207 JNU_ThrowInternalError(env, 0); 208 } else { 209 free(jlong_to_ptr(addr)); 210 } 211 }