1/*
2 * Copyright (c) 1997, 2010, 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 "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
44static jfieldID levelID;
45static jfieldID strategyID;
46static jfieldID setParamsID;
47static jfieldID finishID;
48static jfieldID finishedID;
49static jfieldID bufID, offID, lenID;
50
51static void Deflater_initIDs(JNIEnv *env) {
52    jclass cls = (*env)->FindClass(env, "java/util/zip/Deflater");
53    levelID = (*env)->GetFieldID(env, cls, "level", "I");
54    strategyID = (*env)->GetFieldID(env, cls, "strategy", "I");
55    setParamsID = (*env)->GetFieldID(env, cls, "setParams", "Z");
56    finishID = (*env)->GetFieldID(env, cls, "finish", "Z");
57    finishedID = (*env)->GetFieldID(env, cls, "finished", "Z");
58    bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
59    offID = (*env)->GetFieldID(env, cls, "off", "I");
60    lenID = (*env)->GetFieldID(env, cls, "len", "I");
61}
62
63JNIEXPORT jlong JNICALL
64Deflater_init(JNIEnv *env, jclass cls, jint level,
65                                 jint strategy, jboolean nowrap)
66{
67    z_stream *strm = calloc(1, sizeof(z_stream));
68
69    if (strm == 0) {
70        JNU_ThrowOutOfMemoryError(env, 0);
71        return jlong_zero;
72    } else {
73        char *msg;
74        switch (deflateInit2(strm, level, Z_DEFLATED,
75                             nowrap ? -MAX_WBITS : MAX_WBITS,
76                             DEF_MEM_LEVEL, strategy)) {
77          case Z_OK:
78            return ptr_to_jlong(strm);
79          case Z_MEM_ERROR:
80            free(strm);
81            JNU_ThrowOutOfMemoryError(env, 0);
82            return jlong_zero;
83          case Z_STREAM_ERROR:
84            free(strm);
85            JNU_ThrowIllegalArgumentException(env, 0);
86            return jlong_zero;
87          default:
88            msg = strm->msg;
89            free(strm);
90            JNU_ThrowInternalError(env, msg);
91            return jlong_zero;
92        }
93    }
94}
95
96JNIEXPORT void JNICALL
97Deflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
98                                          jarray b, jint off, jint len)
99{
100    Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
101    int res;
102    if (buf == 0) {/* out of memory */
103        return;
104    }
105    res = deflateSetDictionary((z_stream *)jlong_to_ptr(addr), buf + off, len);
106    (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
107    switch (res) {
108    case Z_OK:
109        break;
110    case Z_STREAM_ERROR:
111        JNU_ThrowIllegalArgumentException(env, 0);
112        break;
113    default:
114        JNU_ThrowInternalError(env, ((z_stream *)jlong_to_ptr(addr))->msg);
115        break;
116    }
117}
118
119JNIEXPORT jint JNICALL
120Deflater_deflateBytes(JNIEnv *env, jobject this, jlong addr,
121                                         jarray b, jint off, jint len, jint flush)
122{
123    z_stream *strm = jlong_to_ptr(addr);
124
125    jarray this_buf = (*env)->GetObjectField(env, this, bufID);
126    jint this_off = (*env)->GetIntField(env, this, offID);
127    jint this_len = (*env)->GetIntField(env, this, lenID);
128    jbyte *in_buf;
129    jbyte *out_buf;
130    int res;
131    if ((*env)->GetBooleanField(env, this, setParamsID)) {
132        int level = (*env)->GetIntField(env, this, levelID);
133        int strategy = (*env)->GetIntField(env, this, strategyID);
134        in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
135        if (in_buf == NULL) {
136            // Throw OOME only when length is not zero
137            if (this_len != 0)
138                JNU_ThrowOutOfMemoryError(env, 0);
139            return 0;
140        }
141        out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
142        if (out_buf == NULL) {
143            (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
144            if (len != 0)
145                JNU_ThrowOutOfMemoryError(env, 0);
146            return 0;
147        }
148
149        strm->next_in = (Bytef *) (in_buf + this_off);
150        strm->next_out = (Bytef *) (out_buf + off);
151        strm->avail_in = this_len;
152        strm->avail_out = len;
153        res = deflateParams(strm, level, strategy);
154        (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
155        (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
156
157        switch (res) {
158        case Z_OK:
159            (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
160            this_off += this_len - strm->avail_in;
161            (*env)->SetIntField(env, this, offID, this_off);
162            (*env)->SetIntField(env, this, lenID, strm->avail_in);
163            return len - strm->avail_out;
164        case Z_BUF_ERROR:
165            (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
166            return 0;
167        default:
168            JNU_ThrowInternalError(env, strm->msg);
169            return 0;
170        }
171    } else {
172        jboolean finish = (*env)->GetBooleanField(env, this, finishID);
173        in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
174        if (in_buf == NULL) {
175            if (this_len != 0)
176                JNU_ThrowOutOfMemoryError(env, 0);
177            return 0;
178        }
179        out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
180        if (out_buf == NULL) {
181            (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
182            if (len != 0)
183                JNU_ThrowOutOfMemoryError(env, 0);
184
185            return 0;
186        }
187
188        strm->next_in = (Bytef *) (in_buf + this_off);
189        strm->next_out = (Bytef *) (out_buf + off);
190        strm->avail_in = this_len;
191        strm->avail_out = len;
192        res = deflate(strm, finish ? Z_FINISH : flush);
193        (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
194        (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
195
196        switch (res) {
197        case Z_STREAM_END:
198            (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE);
199            /* fall through */
200        case Z_OK:
201            this_off += this_len - strm->avail_in;
202            (*env)->SetIntField(env, this, offID, this_off);
203            (*env)->SetIntField(env, this, lenID, strm->avail_in);
204            return len - strm->avail_out;
205        case Z_BUF_ERROR:
206            return 0;
207            default:
208            JNU_ThrowInternalError(env, strm->msg);
209            return 0;
210        }
211    }
212}
213
214JNIEXPORT jint JNICALL
215Deflater_getAdler(JNIEnv *env, jclass cls, jlong addr)
216{
217    return ((z_stream *)jlong_to_ptr(addr))->adler;
218}
219
220JNIEXPORT void JNICALL
221Deflater_reset(JNIEnv *env, jclass cls, jlong addr)
222{
223    if (deflateReset((z_stream *)jlong_to_ptr(addr)) != Z_OK) {
224        JNU_ThrowInternalError(env, 0);
225    }
226}
227
228JNIEXPORT void JNICALL
229Deflater_end(JNIEnv *env, jclass cls, jlong addr)
230{
231    if (deflateEnd((z_stream *)jlong_to_ptr(addr)) == Z_STREAM_ERROR) {
232        JNU_ThrowInternalError(env, 0);
233    } else {
234        free((z_stream *)jlong_to_ptr(addr));
235    }
236}
237
238static JNINativeMethod gMethods[] = {
239  NATIVE_METHOD(Deflater, init, "(IIZ)J"),
240  NATIVE_METHOD(Deflater, setDictionary, "(J[BII)V"),
241  NATIVE_METHOD(Deflater, deflateBytes, "(J[BIII)I"),
242  NATIVE_METHOD(Deflater, getAdler, "(J)I"),
243  NATIVE_METHOD(Deflater, reset, "(J)V"),
244  NATIVE_METHOD(Deflater, end, "(J)V"),
245};
246
247void register_java_util_zip_Deflater(JNIEnv* env) {
248    jniRegisterNativeMethods(env, "java/util/zip/Deflater", gMethods, NELEM(gMethods));
249
250    Deflater_initIDs(env);
251}
252