|
1 /* |
|
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 |
|
49 static jfieldID unpackerPtrFID; |
|
50 static jmethodID currentInstMID; |
|
51 static jmethodID readInputMID; |
|
52 static jclass NIclazz; |
|
53 |
|
54 static char* dbg = null; |
|
55 |
|
56 #define THROW_IOE(x) JNU_ThrowIOException(env,x) |
|
57 |
|
58 static jlong read_input_via_jni(unpacker* self, |
|
59 void* buf, jlong minlen, jlong maxlen); |
|
60 |
|
61 static 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. |
|
81 static 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 |
|
99 static 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 |
|
110 unpacker* unpacker::current() { |
|
111 return get_unpacker(); |
|
112 } |
|
113 |
|
114 // Callback for fetching data, Java style. Calls NativeUnpack.readInputFn(). |
|
115 static 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 |
|
123 JNIEXPORT void JNICALL |
|
124 Java_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 |
|
141 JNIEXPORT jlong JNICALL |
|
142 Java_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 |
|
173 JNIEXPORT jboolean JNICALL |
|
174 Java_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 |
|
216 JNIEXPORT jobject JNICALL |
|
217 Java_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 |
|
235 JNIEXPORT jlong JNICALL |
|
236 Java_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 |
|
244 JNIEXPORT jboolean JNICALL |
|
245 Java_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 |
|
256 JNIEXPORT jstring JNICALL |
|
257 Java_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 } |