1 /* 2 * Copyright (c) 1997, 2010, 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 <stdio.h> 31 #include <stdlib.h> 32 #include <errno.h> 33 #include <string.h> 34 #include "JNIHelp.h" 35 #include "jlong.h" 36 #include "jni.h" 37 #include "jvm.h" 38 #include "jni_util.h" 39 #include <zlib.h> 40 41 #define NATIVE_METHOD(className, functionName, signature) \ 42 { #functionName, signature, (void*)(className ## _ ## functionName) } 43 44 #define ThrowDataFormatException(env, msg) \ 45 JNU_ThrowByName(env, "java/util/zip/DataFormatException", msg) 46 47 static jfieldID needDictID; 48 static jfieldID finishedID; 49 static jfieldID bufID, offID, lenID; 50 51 static void Inflater_initIDs(JNIEnv *env) { 52 jclass cls = (*env)->FindClass(env, "java/util/zip/Inflater"); 53 needDictID = (*env)->GetFieldID(env, cls, "needDict", "Z"); 54 finishedID = (*env)->GetFieldID(env, cls, "finished", "Z"); 55 bufID = (*env)->GetFieldID(env, cls, "buf", "[B"); 56 offID = (*env)->GetFieldID(env, cls, "off", "I"); 57 lenID = (*env)->GetFieldID(env, cls, "len", "I"); 58 } 59 60 JNIEXPORT jlong JNICALL 61 Inflater_init(JNIEnv *env, jclass cls, jboolean nowrap) 62 { 63 z_stream *strm = calloc(1, sizeof(z_stream)); 64 65 if (strm == 0) { 66 JNU_ThrowOutOfMemoryError(env, 0); 67 return jlong_zero; 68 } else { 69 char *msg; 70 switch (inflateInit2(strm, nowrap ? -MAX_WBITS : MAX_WBITS)) { 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; 79 free(strm); 80 JNU_ThrowInternalError(env, msg); 81 return jlong_zero; 82 } 83 } 84 } 85 86 JNIEXPORT void JNICALL 87 Inflater_setDictionary(JNIEnv *env, jclass cls, jlong addr, 88 jarray b, jint off, jint len) 89 { 90 Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0); 91 int res; 92 if (buf == 0) /* out of memory */ 93 return; 94 res = inflateSetDictionary(jlong_to_ptr(addr), buf + off, len); 95 (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0); 96 switch (res) { 97 case Z_OK: 98 break; 99 case Z_STREAM_ERROR: 100 case Z_DATA_ERROR: 101 JNU_ThrowIllegalArgumentException(env, ((z_stream *)jlong_to_ptr(addr))->msg); 102 break; 103 default: 104 JNU_ThrowInternalError(env, ((z_stream *)jlong_to_ptr(addr))->msg); 105 break; 106 } 107 } 108 109 JNIEXPORT jint JNICALL 110 Inflater_inflateBytes(JNIEnv *env, jobject this, jlong addr, 111 jarray b, jint off, jint len) 112 { 113 z_stream *strm = jlong_to_ptr(addr); 114 jarray this_buf = (jarray)(*env)->GetObjectField(env, this, bufID); 115 jint this_off = (*env)->GetIntField(env, this, offID); 116 jint this_len = (*env)->GetIntField(env, this, lenID); 117 118 jbyte *in_buf; 119 jbyte *out_buf; 120 int ret; 121 122 in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0); 123 if (in_buf == NULL) { 124 if (this_len != 0) 125 JNU_ThrowOutOfMemoryError(env, 0); 126 return 0; 127 } 128 out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0); 129 if (out_buf == NULL) { 130 (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0); 131 if (len != 0) 132 JNU_ThrowOutOfMemoryError(env, 0); 133 return 0; 134 } 135 strm->next_in = (Bytef *) (in_buf + this_off); 136 strm->next_out = (Bytef *) (out_buf + off); 137 strm->avail_in = this_len; 138 strm->avail_out = len; 139 ret = inflate(strm, Z_PARTIAL_FLUSH); 140 (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0); 141 (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0); 142 143 switch (ret) { 144 case Z_STREAM_END: 145 (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE); 146 /* fall through */ 147 case Z_OK: 148 this_off += this_len - strm->avail_in; 149 (*env)->SetIntField(env, this, offID, this_off); 150 (*env)->SetIntField(env, this, lenID, strm->avail_in); 151 return len - strm->avail_out; 152 case Z_NEED_DICT: 153 (*env)->SetBooleanField(env, this, needDictID, JNI_TRUE); 154 /* Might have consumed some input here! */ 155 this_off += this_len - strm->avail_in; 156 (*env)->SetIntField(env, this, offID, this_off); 157 (*env)->SetIntField(env, this, lenID, strm->avail_in); 158 return 0; 159 case Z_BUF_ERROR: 160 return 0; 161 case Z_DATA_ERROR: 162 ThrowDataFormatException(env, strm->msg); 163 return 0; 164 case Z_MEM_ERROR: 165 JNU_ThrowOutOfMemoryError(env, 0); 166 return 0; 167 default: 168 JNU_ThrowInternalError(env, strm->msg); 169 return 0; 170 } 171 } 172 173 JNIEXPORT jint JNICALL 174 Inflater_getAdler(JNIEnv *env, jclass cls, jlong addr) 175 { 176 return ((z_stream *)jlong_to_ptr(addr))->adler; 177 } 178 179 JNIEXPORT void JNICALL 180 Inflater_reset(JNIEnv *env, jclass cls, jlong addr) 181 { 182 if (inflateReset(jlong_to_ptr(addr)) != Z_OK) { 183 JNU_ThrowInternalError(env, 0); 184 } 185 } 186 187 JNIEXPORT void JNICALL 188 Inflater_end(JNIEnv *env, jclass cls, jlong addr) 189 { 190 if (inflateEnd(jlong_to_ptr(addr)) == Z_STREAM_ERROR) { 191 JNU_ThrowInternalError(env, 0); 192 } else { 193 free(jlong_to_ptr(addr)); 194 } 195 } 196 197 static JNINativeMethod gMethods[] = { 198 NATIVE_METHOD(Inflater, init, "(Z)J"), 199 NATIVE_METHOD(Inflater, setDictionary, "(J[BII)V"), 200 NATIVE_METHOD(Inflater, inflateBytes, "(J[BII)I"), 201 NATIVE_METHOD(Inflater, getAdler, "(J)I"), 202 NATIVE_METHOD(Inflater, reset, "(J)V"), 203 NATIVE_METHOD(Inflater, end, "(J)V"), 204 }; 205 206 void register_java_util_zip_Inflater(JNIEnv* env) { 207 jniRegisterNativeMethods(env, "java/util/zip/Inflater", gMethods, NELEM(gMethods)); 208 209 Inflater_initIDs(env); 210 } 211