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 "jlong.h" 35 #include "jni.h" 36 #include "jvm.h" 37 #include "jni_util.h" 38 #include "zlib.h" 39 #include "java_util_zip_Inflater.h" 40 41 #define MIN2(x, y) ((x) < (y) ? (x) : (y)) 42 43 #define ThrowDataFormatException(env, msg) \ 44 JNU_ThrowByName(env, "java/util/zip/DataFormatException", msg) 45 46 static jfieldID needDictID; 47 static jfieldID finishedID; 48 static jfieldID bufID, offID, lenID; 49 50 JNIEXPORT void JNICALL 51 Java_java_util_zip_Inflater_initIDs(JNIEnv *env, jclass cls) 52 { 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 Java_java_util_zip_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 Java_java_util_zip_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 Java_java_util_zip_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 115 jarray this_buf = (jarray)(*env)->GetObjectField(env, this, bufID); 116 jint this_off = (*env)->GetIntField(env, this, offID); 117 jint this_len = (*env)->GetIntField(env, this, lenID); 118 jbyte *in_buf; 119 jbyte *out_buf; 120 int ret; 121 /* 122 * Avoid excess copying. 123 * zlib stream usually has a few bytes of overhead for header info 124 * (depends on the underlying data) 125 * 126 * (a) 5 bytes per 16KB 127 * (b) 6 bytes for entire stream 128 * (c) 4 bytes for gzip header 129 * (d) 2 bytes for crc 130 * 131 * Use 20 bytes as the "safe cutoff" number. 132 */ 133 jint in_len = MIN2(this_len, len + 20); 134 jint consumed; 135 136 in_buf = (jbyte *) malloc(in_len); 137 if (in_buf == 0) { 138 if (in_len != 0) 139 JNU_ThrowOutOfMemoryError(env, 0); 140 return 0; 141 } 142 (*env)->GetByteArrayRegion(env, this_buf, this_off, in_len, in_buf); 143 144 out_buf = (jbyte *) malloc(len); 145 if (out_buf == 0) { 146 free(in_buf); 147 if (len != 0) 148 JNU_ThrowOutOfMemoryError(env, 0); 149 return 0; 150 } 151 152 strm->next_in = (Bytef *) in_buf; 153 strm->next_out = (Bytef *) out_buf; 154 strm->avail_in = in_len; 155 strm->avail_out = len; 156 ret = inflate(strm, Z_PARTIAL_FLUSH); 157 158 if (ret == Z_STREAM_END || ret == Z_OK) { 159 (*env)->SetByteArrayRegion(env, b, off, len - strm->avail_out, out_buf); 160 } 161 free(out_buf); 162 free(in_buf); 163 164 switch (ret) { 165 case Z_STREAM_END: 166 (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE); 167 /* fall through */ 168 case Z_OK: 169 consumed = in_len - strm->avail_in; 170 (*env)->SetIntField(env, this, offID, this_off + consumed); 171 (*env)->SetIntField(env, this, lenID, this_len - consumed); 172 return len - strm->avail_out; 173 case Z_NEED_DICT: 174 (*env)->SetBooleanField(env, this, needDictID, JNI_TRUE); 175 /* Might have consumed some input here! */ 176 consumed = in_len - strm->avail_in; 177 (*env)->SetIntField(env, this, offID, this_off + consumed); 178 (*env)->SetIntField(env, this, lenID, this_len - consumed); 179 return 0; 180 case Z_BUF_ERROR: 181 return 0; 182 case Z_DATA_ERROR: 183 ThrowDataFormatException(env, strm->msg); 184 return 0; 185 case Z_MEM_ERROR: 186 JNU_ThrowOutOfMemoryError(env, 0); 187 return 0; 188 default: 189 JNU_ThrowInternalError(env, strm->msg); 190 return 0; 191 } 192 } 193 194 JNIEXPORT jint JNICALL 195 Java_java_util_zip_Inflater_getAdler(JNIEnv *env, jclass cls, jlong addr) 196 { 197 return ((z_stream *)jlong_to_ptr(addr))->adler; 198 } 199 200 JNIEXPORT jlong JNICALL 201 Java_java_util_zip_Inflater_getBytesRead(JNIEnv *env, jclass cls, jlong addr) 202 { 203 return ((z_stream *)jlong_to_ptr(addr))->total_in; 204 } 205 206 JNIEXPORT jlong JNICALL 207 Java_java_util_zip_Inflater_getBytesWritten(JNIEnv *env, jclass cls, jlong addr) 208 { 209 return ((z_stream *)jlong_to_ptr(addr))->total_out; 210 } 211 212 JNIEXPORT void JNICALL 213 Java_java_util_zip_Inflater_reset(JNIEnv *env, jclass cls, jlong addr) 214 { 215 if (inflateReset(jlong_to_ptr(addr)) != Z_OK) { 216 JNU_ThrowInternalError(env, 0); 217 } 218 } 219 220 JNIEXPORT void JNICALL 221 Java_java_util_zip_Inflater_end(JNIEnv *env, jclass cls, jlong addr) 222 { 223 if (inflateEnd(jlong_to_ptr(addr)) == Z_STREAM_ERROR) { 224 JNU_ThrowInternalError(env, 0); 225 } else { 226 free(jlong_to_ptr(addr)); 227 } 228 }