1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include "hy2sie.h" 19 #include "zip.h" 20 21 #include "zlib.h" 22 #include <memory.h> 23 #define jclmem_allocate_memory(env, byteCount) sieb_malloc(env, byteCount) 24 #define jclmem_free_memory(env, pointer) sieb_free(env, pointer) 25 26 #include <fcntl.h> 27 28 void throwNewDataFormatException (JNIEnv * env, const char *message); 29 30 void zfree PROTOTYPE ((void *opaque, void *address)); 31 void *zalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size)); 32 33 34 static struct { 35 jfieldID inRead; 36 jfieldID finished; 37 jfieldID needsDictionary; 38 } gCachedFields; 39 40 41 42 /* Create a new stream . This stream cannot be used until it has been properly initialized. */ 43 JNIEXPORT jlong JNICALL 44 Java_java_util_zip_Inflater_createStream (JNIEnv * env, jobject recv, 45 jboolean noHeader) 46 { 47 PORT_ACCESS_FROM_ENV (env); 48 49 JCLZipStream *jstream; 50 z_stream *stream; 51 int err = 0; 52 int wbits = 15; /*Use MAX for fastest */ 53 #ifdef HY_ZIP_API 54 VMI_ACCESS_FROM_ENV (env); 55 VMIZipFunctionTable *zipFuncs; 56 zipFuncs = (*VMI)->GetZipFunctions(VMI); 57 #endif 58 59 /*Allocate mem for wrapped struct */ 60 jstream = jclmem_allocate_memory (env, sizeof (JCLZipStream)); 61 if (jstream == NULL) 62 { 63 throwNewOutOfMemoryError (env, ""); 64 return -1; 65 } 66 67 /*Allocate the z_stream */ 68 stream = jclmem_allocate_memory (env, sizeof (z_stream)); 69 if (stream == NULL) 70 { 71 jclmem_free_memory (env, jstream); 72 throwNewOutOfMemoryError (env, ""); 73 return -1; 74 } 75 stream->opaque = (void *) privatePortLibrary; 76 stream->zalloc = zalloc; 77 stream->zfree = zfree; 78 stream->adler = 1; 79 jstream->stream = stream; 80 jstream->dict = NULL; 81 jstream->inaddr = NULL; 82 jstream->inCap = 0; 83 84 /* 85 * In the range 8..15 for checked, or -8..-15 for unchecked inflate. Unchecked 86 * is appropriate for formats like zip that do their own validity checking. 87 */ 88 if (noHeader) 89 wbits = wbits / -1; 90 err = inflateInit2 (stream, wbits); /*Window bits to use. 15 is fastest but consumes the most memory */ 91 92 if (err != Z_OK) 93 { 94 jclmem_free_memory (env, stream); 95 jclmem_free_memory (env, jstream); 96 THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException); 97 return -1; 98 } 99 100 return (jlong) ((IDATA) jstream); 101 } 102 103 JNIEXPORT void JNICALL 104 Java_java_util_zip_Inflater_setInputImpl (JNIEnv * env, jobject recv, 105 jbyteArray buf, jint off, jint len, 106 jlong handle) 107 { 108 PORT_ACCESS_FROM_ENV (env); 109 110 JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle); 111 if (stream->inaddr != NULL) { 112 /* Input has already been provided, free the old buffer. */ 113 jclmem_free_memory (env, stream->inaddr); 114 } 115 U_8* baseAddr = jclmem_allocate_memory (env, len); 116 if (baseAddr == NULL) { 117 throwNewOutOfMemoryError (env, ""); 118 return; 119 } 120 stream->inaddr = baseAddr; 121 stream->stream->next_in = (Bytef *) baseAddr; 122 stream->stream->avail_in = len; 123 (*env)->GetByteArrayRegion(env, buf, off, len, (jbyte*) baseAddr); 124 } 125 126 JNIEXPORT jint JNICALL 127 Java_java_util_zip_Inflater_setFileInputImpl (JNIEnv * env, jobject recv, 128 jobject javaFileDescriptor, jlong off, jint len, jlong handle) 129 { 130 PORT_ACCESS_FROM_ENV (env); 131 132 U_8 * baseAddr; 133 JCLZipStream * stream = (JCLZipStream *) ((IDATA) handle); 134 135 if (stream->inCap < len) { 136 // No input buffer as yet (or one that is too small). 137 jclmem_free_memory(env, stream->inaddr); 138 baseAddr = jclmem_allocate_memory(env, len); 139 if (baseAddr == NULL) 140 { 141 throwNewOutOfMemoryError(env, ""); 142 return -1; 143 } 144 stream->inaddr = baseAddr; 145 } 146 stream->stream->next_in = (Bytef *) stream->inaddr; 147 stream->stream->avail_in = len; 148 149 int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor); 150 lseek(fd, off, SEEK_SET); 151 int cnt = read(fd, stream->inaddr, len); 152 153 return cnt; 154 } 155 156 JNIEXPORT jint JNICALL 157 Java_java_util_zip_Inflater_inflateImpl (JNIEnv * env, jobject recv, 158 jbyteArray buf, int off, int len, 159 jlong handle) 160 { 161 jbyte *out; 162 JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle); 163 jint err = 0; 164 jfieldID fid = 0, fid2 = 0; 165 jint sin, sout, inBytes = 0; 166 167 /* We need to get the number of bytes already read */ 168 fid = gCachedFields.inRead; 169 inBytes = ((*env)->GetIntField (env, recv, fid)); 170 171 stream->stream->avail_out = len; 172 sin = stream->stream->total_in; 173 sout = stream->stream->total_out; 174 out = ((*env)->GetPrimitiveArrayCritical (env, buf, 0)); 175 if (out == NULL) { 176 throwNewOutOfMemoryError(env, ""); 177 return -1; 178 } 179 stream->stream->next_out = (Bytef *) out + off; 180 err = inflate (stream->stream, Z_SYNC_FLUSH); 181 ((*env)->ReleasePrimitiveArrayCritical (env, buf, out, 0)); 182 183 if (err != Z_OK) 184 { 185 if(err == Z_STREAM_ERROR) { 186 return 0; 187 } 188 if (err == Z_STREAM_END || err == Z_NEED_DICT) 189 { 190 ((*env)->SetIntField (env, recv, fid, (jint) stream->stream->total_in - sin + inBytes)); /* Update inRead */ 191 if (err == Z_STREAM_END) 192 fid2 = gCachedFields.finished; 193 else 194 fid2 = gCachedFields.needsDictionary; 195 196 ((*env)->SetBooleanField (env, recv, fid2, JNI_TRUE)); 197 return stream->stream->total_out - sout; 198 } 199 else 200 { 201 THROW_ZIP_EXCEPTION(env, err, DataFormatException); 202 return -1; 203 } 204 } 205 206 /* Need to update the number of input bytes read. Is there a better way 207 * (Maybe global the fid then delete when end is called)? 208 */ 209 ((*env)-> 210 SetIntField (env, recv, fid, 211 (jint) stream->stream->total_in - sin + inBytes)); 212 213 return stream->stream->total_out - sout; 214 } 215 216 JNIEXPORT jint JNICALL 217 Java_java_util_zip_Inflater_getAdlerImpl (JNIEnv * env, jobject recv, 218 jlong handle) 219 { 220 JCLZipStream *stream; 221 222 stream = (JCLZipStream *) ((IDATA) handle); 223 224 return stream->stream->adler; 225 } 226 227 JNIEXPORT void JNICALL 228 Java_java_util_zip_Inflater_endImpl (JNIEnv * env, jobject recv, jlong handle) 229 { 230 PORT_ACCESS_FROM_ENV (env); 231 JCLZipStream *stream; 232 233 stream = (JCLZipStream *) ((IDATA) handle); 234 inflateEnd (stream->stream); 235 if (stream->inaddr != NULL) /*Input has been provided, free the buffer */ 236 jclmem_free_memory (env, stream->inaddr); 237 if (stream->dict != NULL) 238 jclmem_free_memory (env, stream->dict); 239 jclmem_free_memory (env, stream->stream); 240 jclmem_free_memory (env, stream); 241 } 242 243 JNIEXPORT void JNICALL 244 Java_java_util_zip_Inflater_setDictionaryImpl (JNIEnv * env, jobject recv, 245 jbyteArray dict, int off, 246 int len, jlong handle) 247 { 248 PORT_ACCESS_FROM_ENV (env); 249 int err = 0; 250 U_8 *dBytes; 251 JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle); 252 253 dBytes = jclmem_allocate_memory (env, len); 254 if (dBytes == NULL) 255 { 256 throwNewOutOfMemoryError (env, ""); 257 return; 258 } 259 (*env)->GetByteArrayRegion (env, dict, off, len, (mcSignednessBull)dBytes); 260 err = inflateSetDictionary (stream->stream, (Bytef *) dBytes, len); 261 if (err != Z_OK) 262 { 263 jclmem_free_memory (env, dBytes); 264 THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException); 265 return; 266 } 267 stream->dict = dBytes; 268 } 269 270 JNIEXPORT void JNICALL 271 Java_java_util_zip_Inflater_resetImpl (JNIEnv * env, jobject recv, 272 jlong handle) 273 { 274 JCLZipStream *stream; 275 int err = 0; 276 stream = (JCLZipStream *) ((IDATA) handle); 277 278 err = inflateReset (stream->stream); 279 if (err != Z_OK) 280 { 281 THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException); 282 return; 283 } 284 } 285 286 /** 287 * Throw java.util.zip.DataFormatException 288 */ 289 void 290 throwNewDataFormatException (JNIEnv * env, const char *message) 291 { 292 jniThrowException(env, "java/util/zip/DataFormatException", message); 293 } 294 295 JNIEXPORT jlong JNICALL 296 Java_java_util_zip_Inflater_getTotalOutImpl (JNIEnv * env, jobject recv, 297 jlong handle) 298 { 299 JCLZipStream *stream; 300 301 stream = (JCLZipStream *) ((IDATA) handle); 302 return stream->stream->total_out; 303 304 } 305 306 JNIEXPORT jlong JNICALL 307 Java_java_util_zip_Inflater_getTotalInImpl (JNIEnv * env, jobject recv, 308 jlong handle) 309 { 310 JCLZipStream *stream; 311 312 stream = (JCLZipStream *) ((IDATA) handle); 313 return stream->stream->total_in; 314 } 315 316 JNIEXPORT void JNICALL 317 Java_java_util_zip_Inflater_oneTimeInitialization (JNIEnv * env, jclass clazz) 318 { 319 memset(&gCachedFields, 0, sizeof(gCachedFields)); 320 gCachedFields.inRead = (*env)->GetFieldID (env, clazz, "inRead", "I"); 321 gCachedFields.finished = (*env)->GetFieldID (env, clazz, "finished", "Z"); 322 gCachedFields.needsDictionary = (*env)->GetFieldID (env, clazz, "needsDictionary", "Z"); 323 } 324 325 /* 326 * JNI registration 327 */ 328 static JNINativeMethod gMethods[] = { 329 /* name, signature, funcPtr */ 330 { "createStream", "(Z)J", Java_java_util_zip_Inflater_createStream }, 331 { "setInputImpl", "([BIIJ)V", Java_java_util_zip_Inflater_setInputImpl }, 332 { "setFileInputImpl", "(Ljava/io/FileDescriptor;JIJ)I", Java_java_util_zip_Inflater_setFileInputImpl }, 333 { "inflateImpl", "([BIIJ)I", Java_java_util_zip_Inflater_inflateImpl }, 334 { "getAdlerImpl", "(J)I", Java_java_util_zip_Inflater_getAdlerImpl }, 335 { "endImpl", "(J)V", Java_java_util_zip_Inflater_endImpl }, 336 { "setDictionaryImpl", "([BIIJ)V", Java_java_util_zip_Inflater_setDictionaryImpl }, 337 { "resetImpl", "(J)V", Java_java_util_zip_Inflater_resetImpl }, 338 { "getTotalOutImpl", "(J)J", Java_java_util_zip_Inflater_getTotalOutImpl }, 339 { "getTotalInImpl", "(J)J", Java_java_util_zip_Inflater_getTotalInImpl }, 340 { "oneTimeInitialization", "()V", Java_java_util_zip_Inflater_oneTimeInitialization }, 341 }; 342 int register_java_util_zip_Inflater(JNIEnv* env) 343 { 344 return jniRegisterNativeMethods(env, "java/util/zip/Inflater", 345 gMethods, NELEM(gMethods)); 346 } 347