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