Home | History | Annotate | Download | only in native
      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