1 /*
2  * Copyright (c) 1997, 2020, 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.Deflater
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <nativehelper/JNIHelp.h>
33 #include "jlong.h"
34 #include "jni.h"
35 #include "jni_util.h"
36 #include <zlib.h>
37 
38 
39 #define NATIVE_METHOD(className, functionName, signature) \
40 { #functionName, signature, (void*)(className ## _ ## functionName) }
41 
42 #define DEF_MEM_LEVEL 8
43 
44 JNIEXPORT jlong JNICALL
Deflater_init(JNIEnv * env,jclass cls,jint level,jint strategy,jboolean nowrap)45 Deflater_init(JNIEnv *env, jclass cls, jint level,
46                                  jint strategy, jboolean nowrap)
47 {
48     z_stream *strm = calloc(1, sizeof(z_stream));
49 
50     if (strm == 0) {
51         JNU_ThrowOutOfMemoryError(env, 0);
52         return jlong_zero;
53     } else {
54         const char *msg;
55         int ret = deflateInit2(strm, level, Z_DEFLATED,
56                                nowrap ? -MAX_WBITS : MAX_WBITS,
57                                DEF_MEM_LEVEL, strategy);
58         switch (ret) {
59           case Z_OK:
60             return ptr_to_jlong(strm);
61           case Z_MEM_ERROR:
62             free(strm);
63             JNU_ThrowOutOfMemoryError(env, 0);
64             return jlong_zero;
65           case Z_STREAM_ERROR:
66             free(strm);
67             JNU_ThrowIllegalArgumentException(env, 0);
68             return jlong_zero;
69           default:
70             msg = ((strm->msg != NULL) ? strm->msg :
71                    (ret == Z_VERSION_ERROR) ?
72                    "zlib returned Z_VERSION_ERROR: "
73                    "compile time and runtime zlib implementations differ" :
74                    "unknown error initializing zlib library");
75             free(strm);
76             JNU_ThrowInternalError(env, msg);
77             return jlong_zero;
78         }
79     }
80 }
81 
throwInternalErrorHelper(JNIEnv * env,z_stream * strm,const char * fixmsg)82 static void throwInternalErrorHelper(JNIEnv *env, z_stream *strm, const char *fixmsg) {
83     const char *msg = NULL;
84     msg = (strm->msg != NULL) ? strm->msg : fixmsg;
85     JNU_ThrowInternalError(env, msg);
86 }
87 
checkSetDictionaryResult(JNIEnv * env,jlong addr,jint res)88 static void checkSetDictionaryResult(JNIEnv *env, jlong addr, jint res)
89 {
90     z_stream *strm = (z_stream *) jlong_to_ptr(addr);
91     switch (res) {
92     case Z_OK:
93         break;
94     case Z_STREAM_ERROR:
95         JNU_ThrowIllegalArgumentException(env, 0);
96         break;
97     default:
98         throwInternalErrorHelper(env, strm, "unknown error in checkSetDictionaryResult");
99         break;
100     }
101 }
102 
103 JNIEXPORT void JNICALL
Deflater_setDictionary(JNIEnv * env,jclass cls,jlong addr,jbyteArray b,jint off,jint len)104 Deflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
105                                           jbyteArray b, jint off, jint len)
106 {
107     int res;
108     Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
109     if (buf == NULL) /* out of memory */
110         return;
111     res = deflateSetDictionary(jlong_to_ptr(addr), buf + off, len);
112     (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
113     checkSetDictionaryResult(env, addr, res);
114 }
115 
116 JNIEXPORT void JNICALL
Deflater_setDictionaryBuffer(JNIEnv * env,jclass cls,jlong addr,jlong bufferAddr,jint len)117 Deflater_setDictionaryBuffer(JNIEnv *env, jclass cls, jlong addr,
118                                           jlong bufferAddr, jint len)
119 {
120     int res;
121     Bytef *buf = jlong_to_ptr(bufferAddr);
122     res = deflateSetDictionary(jlong_to_ptr(addr), buf, len);
123     checkSetDictionaryResult(env, addr, res);
124 }
125 
doDeflate(JNIEnv * env,jlong addr,jbyte * input,jint inputLen,jbyte * output,jint outputLen,jint flush,jint params)126 static jint doDeflate(JNIEnv *env, jlong addr,
127                        jbyte *input, jint inputLen,
128                        jbyte *output, jint outputLen,
129                        jint flush, jint params)
130 {
131     z_stream *strm = jlong_to_ptr(addr);
132     int setParams = params & 1;
133     int res;
134 
135     strm->next_in  = (Bytef *) input;
136     strm->next_out = (Bytef *) output;
137     strm->avail_in  = inputLen;
138     strm->avail_out = outputLen;
139 
140     if (setParams) {
141         int strategy = (params >> 1) & 3;
142         int level = params >> 3;
143         res = deflateParams(strm, level, strategy);
144     } else {
145         res = deflate(strm, flush);
146     }
147     return res;
148 }
149 
checkDeflateStatus(JNIEnv * env,jlong addr,jint inputLen,jint outputLen,jint params,int res)150 static jlong checkDeflateStatus(JNIEnv *env, jlong addr,
151                         jint inputLen,
152                         jint outputLen,
153                         jint params, int res)
154 {
155     z_stream *strm = jlong_to_ptr(addr);
156     jint inputUsed = 0, outputUsed = 0;
157     int finished = 0;
158     int setParams = params & 1;
159 
160     if (setParams) {
161         switch (res) {
162         case Z_OK:
163             setParams = 0;
164             /* fall through */
165         case Z_BUF_ERROR:
166             inputUsed = inputLen - strm->avail_in;
167             outputUsed = outputLen - strm->avail_out;
168             break;
169         default:
170             throwInternalErrorHelper(env, strm, "unknown error in checkDeflateStatus, setParams case");
171             return 0;
172         }
173     } else {
174         switch (res) {
175         case Z_STREAM_END:
176             finished = 1;
177             /* fall through */
178         case Z_OK:
179         case Z_BUF_ERROR:
180             inputUsed = inputLen - strm->avail_in;
181             outputUsed = outputLen - strm->avail_out;
182             break;
183         default:
184             throwInternalErrorHelper(env, strm, "unknown error in checkDeflateStatus");
185             return 0;
186         }
187     }
188     return ((jlong)inputUsed) | (((jlong)outputUsed) << 31) | (((jlong)finished) << 62) | (((jlong)setParams) << 63);
189 }
190 
191 JNIEXPORT jlong JNICALL
Deflater_deflateBytesBytes(JNIEnv * env,jobject this,jlong addr,jbyteArray inputArray,jint inputOff,jint inputLen,jbyteArray outputArray,jint outputOff,jint outputLen,jint flush,jint params)192 Deflater_deflateBytesBytes(JNIEnv *env, jobject this, jlong addr,
193                                          jbyteArray inputArray, jint inputOff, jint inputLen,
194                                          jbyteArray outputArray, jint outputOff, jint outputLen,
195                                          jint flush, jint params)
196 {
197     jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
198     jbyte *output;
199     jlong retVal;
200     jint res;
201 
202     if (input == NULL) {
203         if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
204             JNU_ThrowOutOfMemoryError(env, 0);
205         return 0L;
206     }
207     output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
208     if (output == NULL) {
209         (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
210         if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
211             JNU_ThrowOutOfMemoryError(env, 0);
212         return 0L;
213     }
214 
215      res = doDeflate(env, addr, input + inputOff, inputLen,output + outputOff,
216                      outputLen, flush, params);
217 
218     (*env)->ReleasePrimitiveArrayCritical(env, outputArray, output, 0);
219     (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
220 
221     retVal = checkDeflateStatus(env, addr, inputLen, outputLen, params, res);
222     return retVal;
223 }
224 
225 
226 JNIEXPORT jlong JNICALL
Deflater_deflateBytesBuffer(JNIEnv * env,jobject this,jlong addr,jbyteArray inputArray,jint inputOff,jint inputLen,jlong outputBuffer,jint outputLen,jint flush,jint params)227 Deflater_deflateBytesBuffer(JNIEnv *env, jobject this, jlong addr,
228                                          jbyteArray inputArray, jint inputOff, jint inputLen,
229                                          jlong outputBuffer, jint outputLen,
230                                          jint flush, jint params)
231 {
232     jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
233     jbyte *output;
234     jlong retVal;
235     jint res;
236     if (input == NULL) {
237         if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
238             JNU_ThrowOutOfMemoryError(env, 0);
239         return 0L;
240     }
241     output = jlong_to_ptr(outputBuffer);
242 
243     res = doDeflate(env, addr, input + inputOff, inputLen, output, outputLen,
244                     flush, params);
245 
246     (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
247 
248     retVal = checkDeflateStatus(env, addr, inputLen, outputLen, params, res);
249     return retVal;
250 }
251 
252 JNIEXPORT jlong JNICALL
Deflater_deflateBufferBytes(JNIEnv * env,jobject this,jlong addr,jlong inputBuffer,jint inputLen,jbyteArray outputArray,jint outputOff,jint outputLen,jint flush,jint params)253 Deflater_deflateBufferBytes(JNIEnv *env, jobject this, jlong addr,
254                                          jlong inputBuffer, jint inputLen,
255                                          jbyteArray outputArray, jint outputOff, jint outputLen,
256                                          jint flush, jint params)
257 {
258     jbyte *input = jlong_to_ptr(inputBuffer);
259     jbyte *output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
260     jlong retVal;
261     jint res;
262     if (output == NULL) {
263         if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
264             JNU_ThrowOutOfMemoryError(env, 0);
265         return 0L;
266     }
267 
268     res = doDeflate(env, addr, input, inputLen, output + outputOff, outputLen,
269                     flush, params);
270     (*env)->ReleasePrimitiveArrayCritical(env, outputArray, output, 0);
271 
272     retVal = checkDeflateStatus(env, addr, inputLen, outputLen, params, res);
273     return retVal;
274 }
275 
276 JNIEXPORT jlong JNICALL
Deflater_deflateBufferBuffer(JNIEnv * env,jobject this,jlong addr,jlong inputBuffer,jint inputLen,jlong outputBuffer,jint outputLen,jint flush,jint params)277 Deflater_deflateBufferBuffer(JNIEnv *env, jobject this, jlong addr,
278                                          jlong inputBuffer, jint inputLen,
279                                          jlong outputBuffer, jint outputLen,
280                                          jint flush, jint params)
281 {
282     jbyte *input = jlong_to_ptr(inputBuffer);
283     jbyte *output = jlong_to_ptr(outputBuffer);
284     jlong retVal;
285     jint res;
286 
287     res = doDeflate(env, addr, input, inputLen, output, outputLen, flush, params);
288     retVal = checkDeflateStatus(env, addr, inputLen, outputLen, params, res);
289     return retVal;
290 }
291 
292 JNIEXPORT jint JNICALL
Deflater_getAdler(JNIEnv * env,jclass cls,jlong addr)293 Deflater_getAdler(JNIEnv *env, jclass cls, jlong addr)
294 {
295     return ((z_stream *)jlong_to_ptr(addr))->adler;
296 }
297 
298 JNIEXPORT void JNICALL
Deflater_reset(JNIEnv * env,jclass cls,jlong addr)299 Deflater_reset(JNIEnv *env, jclass cls, jlong addr)
300 {
301     if (deflateReset((z_stream *)jlong_to_ptr(addr)) != Z_OK) {
302         JNU_ThrowInternalError(env, "deflateReset failed");
303     }
304 }
305 
306 JNIEXPORT void JNICALL
Deflater_end(JNIEnv * env,jclass cls,jlong addr)307 Deflater_end(JNIEnv *env, jclass cls, jlong addr)
308 {
309     if (deflateEnd((z_stream *)jlong_to_ptr(addr)) == Z_STREAM_ERROR) {
310         JNU_ThrowInternalError(env, "deflateEnd failed");
311     } else {
312         free((z_stream *)jlong_to_ptr(addr));
313     }
314 }
315 
316 static JNINativeMethod gMethods[] = {
317   NATIVE_METHOD(Deflater, init, "(IIZ)J"),
318   NATIVE_METHOD(Deflater, setDictionary, "(J[BII)V"),
319   NATIVE_METHOD(Deflater, setDictionaryBuffer, "(JJI)V"),
320   NATIVE_METHOD(Deflater, deflateBytesBytes, "(J[BII[BIIII)J"),
321   NATIVE_METHOD(Deflater, deflateBytesBuffer, "(J[BIIJIII)J"),
322   NATIVE_METHOD(Deflater, deflateBufferBytes, "(JJI[BIIII)J"),
323   NATIVE_METHOD(Deflater, deflateBufferBuffer, "(JJIJIII)J"),
324   NATIVE_METHOD(Deflater, getAdler, "(J)I"),
325   NATIVE_METHOD(Deflater, reset, "(J)V"),
326   NATIVE_METHOD(Deflater, end, "(J)V"),
327 };
328 
register_java_util_zip_Deflater(JNIEnv * env)329 void register_java_util_zip_Deflater(JNIEnv* env) {
330     jniRegisterNativeMethods(env, "java/util/zip/Deflater", gMethods, NELEM(gMethods));
331 }
332