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