blob: d217341dab617031d4763db4ca6d64952fdf4ddd [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25#include <sys/types.h>
26
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <stdarg.h>
31
32
33#include <limits.h>
34
35#include <com_sun_java_util_jar_pack_NativeUnpack.h>
36
37#include "jni_util.h"
38
39#include "defines.h"
40#include "bytes.h"
41#include "utils.h"
42#include "coding.h"
43#include "bands.h"
44#include "constants.h"
45#include "zip.h"
46#include "unpack.h"
47
48
49static jfieldID unpackerPtrFID;
50static jmethodID currentInstMID;
51static jmethodID readInputMID;
52static jclass NIclazz;
53
54static char* dbg = null;
55
56#define THROW_IOE(x) JNU_ThrowIOException(env,x)
57
58static jlong read_input_via_jni(unpacker* self,
59 void* buf, jlong minlen, jlong maxlen);
60
61static unpacker* get_unpacker(JNIEnv *env, jobject pObj, bool noCreate=false) {
62 unpacker* uPtr = (unpacker*) env->GetLongField(pObj, unpackerPtrFID);
63 //fprintf(stderr, "get_unpacker(%p) uPtr=%p\n", pObj, uPtr);
64 if (uPtr == null) {
65 if (noCreate) return null;
66 uPtr = new unpacker();
67 if (uPtr == null) {
68 THROW_IOE(ERROR_ENOMEM);
69 return null;
70 }
71 //fprintf(stderr, "get_unpacker(%p) uPtr=%p initializing\n", pObj, uPtr);
72 uPtr->init(read_input_via_jni);
73 uPtr->jniobj = (void*) env->NewGlobalRef(pObj);
74 env->SetLongField(pObj, unpackerPtrFID, (jlong)uPtr);
75 }
76 uPtr->jnienv = env; // keep refreshing this in case of MT access
77 return uPtr;
78}
79
80// This is the harder trick: Pull the current state out of mid-air.
81static unpacker* get_unpacker() {
82 //fprintf(stderr, "get_unpacker()\n");
83 JavaVM* vm = null;
84 JNI_GetCreatedJavaVMs(&vm, 1, null);
85 void* envRaw = null;
86 vm->GetEnv(&envRaw, JNI_VERSION_1_1);
87 JNIEnv* env = (JNIEnv*) envRaw;
88 //fprintf(stderr, "get_unpacker() env=%p\n", env);
89 if (env == null)
90 return null;
91 jobject pObj = env->CallStaticObjectMethod(NIclazz, currentInstMID);
92 //fprintf(stderr, "get_unpacker() pObj=%p\n", pObj);
93 if (pObj == null)
94 return null;
95 // Got pObj and env; now do it the easy way.
96 return get_unpacker(env, pObj);
97}
98
99static void free_unpacker(JNIEnv *env, jobject pObj, unpacker* uPtr) {
100 if (uPtr != null) {
101 //fprintf(stderr, "free_unpacker(%p) uPtr=%p\n", pObj, uPtr);
102 env->DeleteGlobalRef((jobject) uPtr->jniobj);
103 uPtr->jniobj = null;
104 uPtr->free();
105 delete uPtr;
106 env->SetLongField(pObj, unpackerPtrFID, (jlong)null);
107 }
108}
109
110unpacker* unpacker::current() {
111 return get_unpacker();
112}
113
114// Callback for fetching data, Java style. Calls NativeUnpack.readInputFn().
115static jlong read_input_via_jni(unpacker* self,
116 void* buf, jlong minlen, jlong maxlen) {
117 JNIEnv* env = (JNIEnv*) self->jnienv;
118 jobject pbuf = env->NewDirectByteBuffer(buf, maxlen);
119 return env->CallLongMethod((jobject) self->jniobj, readInputMID,
120 pbuf, minlen);
121}
122
123JNIEXPORT void JNICALL
124Java_com_sun_java_util_jar_pack_NativeUnpack_initIDs(JNIEnv *env, jclass clazz) {
125 dbg = getenv("DEBUG_ATTACH");
126 while( dbg != null) { sleep(10); }
127 NIclazz = (jclass) env->NewGlobalRef(clazz);
128 unpackerPtrFID = env->GetFieldID(clazz, "unpackerPtr", "J");
129 currentInstMID = env->GetStaticMethodID(clazz, "currentInstance",
130 "()Ljava/lang/Object;");
131 readInputMID = env->GetMethodID(clazz, "readInputFn",
132 "(Ljava/nio/ByteBuffer;J)J");
133 if (unpackerPtrFID == null ||
134 currentInstMID == null ||
135 readInputMID == null ||
136 NIclazz == null) {
137 THROW_IOE("cannot init class members");
138 }
139}
140
141JNIEXPORT jlong JNICALL
142Java_com_sun_java_util_jar_pack_NativeUnpack_start(JNIEnv *env, jobject pObj,
143 jobject pBuf, jlong offset) {
144 unpacker* uPtr = get_unpacker(env, pObj);
145
146 // redirect our io to the default log file or whatever.
147 uPtr->redirect_stdio();
148
149 void* buf = null;
150 size_t buflen = 0;
151 if (pBuf != null) {
152 buf = env->GetDirectBufferAddress(pBuf);
153 buflen = env->GetDirectBufferCapacity(pBuf);
154 if (buflen == 0) buf = null;
155 if (buf == null) { THROW_IOE(ERROR_INTERNAL); return 0; }
156 if ((size_t)offset >= buflen)
157 { buf = null; buflen = 0; }
158 else
159 { buf = (char*)buf + (size_t)offset; buflen -= (size_t)offset; }
160 }
161
162 uPtr->start(buf, buflen);
163 if (uPtr->aborting()) {
164 THROW_IOE(uPtr->get_abort_message());
165 return 0;
166 }
167
168 return ((jlong)
169 uPtr->get_segments_remaining() << 32)
170 + uPtr->get_files_remaining();
171}
172
173JNIEXPORT jboolean JNICALL
174Java_com_sun_java_util_jar_pack_NativeUnpack_getNextFile(JNIEnv *env, jobject pObj,
175 jobjectArray pParts) {
176
177 unpacker* uPtr = get_unpacker(env, pObj);
178 unpacker::file* filep = uPtr->get_next_file();
179
180 if (uPtr->aborting()) {
181 THROW_IOE(uPtr->get_abort_message());
182 return false;
183 }
184
185 if (filep == null) {
186 return false; // end of the sequence
187 }
188 assert(filep == &uPtr->cur_file);
189
190 int pidx = 0, iidx = 0;
191 jintArray pIntParts = (jintArray) env->GetObjectArrayElement(pParts, pidx++);
192 jint* intParts = env->GetIntArrayElements(pIntParts, null);
193 intParts[iidx++] = (jint)( (julong)filep->size >> 32 );
194 intParts[iidx++] = (jint)( (julong)filep->size >> 0 );
195 intParts[iidx++] = filep->modtime;
196 intParts[iidx++] = filep->deflate_hint() ? 1 : 0;
197 env->ReleaseIntArrayElements(pIntParts, intParts, JNI_COMMIT);
198
199 env->SetObjectArrayElement(pParts, pidx++, env->NewStringUTF(filep->name));
200
201 jobject pDataBuf = null;
202 if (filep->data[0].len > 0)
203 pDataBuf = env->NewDirectByteBuffer(filep->data[0].ptr,
204 filep->data[0].len);
205 env->SetObjectArrayElement(pParts, pidx++, pDataBuf);
206 pDataBuf = null;
207 if (filep->data[1].len > 0)
208 pDataBuf = env->NewDirectByteBuffer(filep->data[1].ptr,
209 filep->data[1].len);
210 env->SetObjectArrayElement(pParts, pidx++, pDataBuf);
211
212 return true;
213}
214
215
216JNIEXPORT jobject JNICALL
217Java_com_sun_java_util_jar_pack_NativeUnpack_getUnusedInput(JNIEnv *env, jobject pObj) {
218 unpacker* uPtr = get_unpacker(env, pObj);
219 unpacker::file* filep = &uPtr->cur_file;
220
221 if (uPtr->aborting()) {
222 THROW_IOE(uPtr->get_abort_message());
223 return false;
224 }
225
226 // We have fetched all the files.
227 // Now swallow up any remaining input.
228 if (uPtr->input_remaining() == 0)
229 return null;
230 else
231 return env->NewDirectByteBuffer(uPtr->input_scan(),
232 uPtr->input_remaining());
233}
234
235JNIEXPORT jlong JNICALL
236Java_com_sun_java_util_jar_pack_NativeUnpack_finish(JNIEnv *env, jobject pObj) {
237 unpacker* uPtr = get_unpacker(env, pObj, false);
238 if (uPtr == null) return 0;
239 size_t consumed = uPtr->input_consumed();
240 free_unpacker(env, pObj, uPtr);
241 return consumed;
242}
243
244JNIEXPORT jboolean JNICALL
245Java_com_sun_java_util_jar_pack_NativeUnpack_setOption(JNIEnv *env, jobject pObj,
246 jstring pProp, jstring pValue) {
247 unpacker* uPtr = get_unpacker(env, pObj);
248 const char* prop = env->GetStringUTFChars(pProp, JNI_FALSE);
249 const char* value = env->GetStringUTFChars(pValue, JNI_FALSE);
250 jboolean retval = uPtr->set_option(prop, value);
251 env->ReleaseStringUTFChars(pProp, prop);
252 env->ReleaseStringUTFChars(pValue, value);
253 return retval;
254}
255
256JNIEXPORT jstring JNICALL
257Java_com_sun_java_util_jar_pack_NativeUnpack_getOption(JNIEnv *env, jobject pObj,
258 jstring pProp) {
259
260 unpacker* uPtr = get_unpacker(env, pObj);
261 const char* prop = env->GetStringUTFChars(pProp, JNI_FALSE);
262 const char* value = uPtr->get_option(prop);
263 env->ReleaseStringUTFChars(pProp, prop);
264 if (value == null) return null;
265 return env->NewStringUTF(value);
266}