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;
63 uPtr = (unpacker*)jlong2ptr(env->GetLongField(pObj, unpackerPtrFID));
64 //fprintf(stderr, "get_unpacker(%p) uPtr=%p\n", pObj, uPtr);
65 if (uPtr == null) {
66 if (noCreate) return null;
67 uPtr = new unpacker();
68 if (uPtr == null) {
69 THROW_IOE(ERROR_ENOMEM);
70 return null;
71 }
72 //fprintf(stderr, "get_unpacker(%p) uPtr=%p initializing\n", pObj, uPtr);
73 uPtr->init(read_input_via_jni);
74 uPtr->jniobj = (void*) env->NewGlobalRef(pObj);
75 env->SetLongField(pObj, unpackerPtrFID, ptr2jlong(uPtr));
76 }
77 uPtr->jnienv = env; // keep refreshing this in case of MT access
78 return uPtr;
79 }
80
81 // This is the harder trick: Pull the current state out of mid-air.
82 static unpacker* get_unpacker() {
83 //fprintf(stderr, "get_unpacker()\n");
84 JavaVM* vm = null;
85 jsize nVM = 0;
86 jint retval = JNI_GetCreatedJavaVMs(&vm, 1, &nVM);
87 // other VM implements may differ, thus for correctness, we need these checks
88 if (retval != JNI_OK || nVM != 1)
89 return null;
90 void* envRaw = null;
91 vm->GetEnv(&envRaw, JNI_VERSION_1_1);
92 JNIEnv* env = (JNIEnv*) envRaw;
93 //fprintf(stderr, "get_unpacker() env=%p\n", env);
94 if (env == null)
95 return null;
96 jobject pObj = env->CallStaticObjectMethod(NIclazz, currentInstMID);
97 //fprintf(stderr, "get_unpacker() pObj=%p\n", pObj);
98 if (pObj == null)
99 return null;
100 // Got pObj and env; now do it the easy way.
101 return get_unpacker(env, pObj);
102 }
103
104 static void free_unpacker(JNIEnv *env, jobject pObj, unpacker* uPtr) {
105 if (uPtr != null) {
106 //fprintf(stderr, "free_unpacker(%p) uPtr=%p\n", pObj, uPtr);
107 env->DeleteGlobalRef((jobject) uPtr->jniobj);
108 uPtr->jniobj = null;
109 uPtr->free();
110 delete uPtr;
111 env->SetLongField(pObj, unpackerPtrFID, (jlong)null);
112 }
113 }
114
115 unpacker* unpacker::current() {
116 return get_unpacker();
117 }
118
119 // Callback for fetching data, Java style. Calls NativeUnpack.readInputFn().
120 static jlong read_input_via_jni(unpacker* self,
121 void* buf, jlong minlen, jlong maxlen) {
122 JNIEnv* env = (JNIEnv*) self->jnienv;
123 jobject pbuf = env->NewDirectByteBuffer(buf, maxlen);
124 return env->CallLongMethod((jobject) self->jniobj, readInputMID,
125 pbuf, minlen);
126 }
127
128 JNIEXPORT void JNICALL
129 Java_com_sun_java_util_jar_pack_NativeUnpack_initIDs(JNIEnv *env, jclass clazz) {
130 dbg = getenv("DEBUG_ATTACH");
131 while( dbg != null) { sleep(10); }
132 NIclazz = (jclass) env->NewGlobalRef(clazz);
133 unpackerPtrFID = env->GetFieldID(clazz, "unpackerPtr", "J");
134 currentInstMID = env->GetStaticMethodID(clazz, "currentInstance",
135 "()Ljava/lang/Object;");
136 readInputMID = env->GetMethodID(clazz, "readInputFn",
137 "(Ljava/nio/ByteBuffer;J)J");
138 if (unpackerPtrFID == null ||
139 currentInstMID == null ||
140 readInputMID == null ||
141 NIclazz == null) {
142 THROW_IOE("cannot init class members");
143 }
144 }
145
146 JNIEXPORT jlong JNICALL
147 Java_com_sun_java_util_jar_pack_NativeUnpack_start(JNIEnv *env, jobject pObj,
148 jobject pBuf, jlong offset) {
149 unpacker* uPtr = get_unpacker(env, pObj);
150
151 // redirect our io to the default log file or whatever.
152 uPtr->redirect_stdio();
153
154 void* buf = null;
155 size_t buflen = 0;
156 if (pBuf != null) {
157 buf = env->GetDirectBufferAddress(pBuf);
158 buflen = (size_t)env->GetDirectBufferCapacity(pBuf);
159 if (buflen == 0) buf = null;
160 if (buf == null) { THROW_IOE(ERROR_INTERNAL); return 0; }
161 if ((size_t)offset >= buflen)
162 { buf = null; buflen = 0; }
163 else
164 { buf = (char*)buf + (size_t)offset; buflen -= (size_t)offset; }
165 }
166
167 uPtr->start(buf, buflen);
168 if (uPtr->aborting()) {
169 THROW_IOE(uPtr->get_abort_message());
170 return 0;
171 }
172
173 return ((jlong)
174 uPtr->get_segments_remaining() << 32)
175 + uPtr->get_files_remaining();
176 }
177
178 JNIEXPORT jboolean JNICALL
179 Java_com_sun_java_util_jar_pack_NativeUnpack_getNextFile(JNIEnv *env, jobject pObj,
180 jobjectArray pParts) {
181
182 unpacker* uPtr = get_unpacker(env, pObj);
183 unpacker::file* filep = uPtr->get_next_file();
184
185 if (uPtr->aborting()) {
186 THROW_IOE(uPtr->get_abort_message());
213 pDataBuf = env->NewDirectByteBuffer(filep->data[1].ptr,
214 filep->data[1].len);
215 env->SetObjectArrayElement(pParts, pidx++, pDataBuf);
216
217 return true;
218 }
219
220
221 JNIEXPORT jobject JNICALL
222 Java_com_sun_java_util_jar_pack_NativeUnpack_getUnusedInput(JNIEnv *env, jobject pObj) {
223 unpacker* uPtr = get_unpacker(env, pObj);
224 unpacker::file* filep = &uPtr->cur_file;
225
226 if (uPtr->aborting()) {
227 THROW_IOE(uPtr->get_abort_message());
228 return false;
229 }
230
231 // We have fetched all the files.
232 // Now swallow up any remaining input.
233 if (uPtr->input_remaining() == 0)
234 return null;
235 else
236 return env->NewDirectByteBuffer(uPtr->input_scan(),
237 uPtr->input_remaining());
238 }
239
240 JNIEXPORT jlong JNICALL
241 Java_com_sun_java_util_jar_pack_NativeUnpack_finish(JNIEnv *env, jobject pObj) {
242 unpacker* uPtr = get_unpacker(env, pObj, false);
243 if (uPtr == null) return 0;
244 size_t consumed = uPtr->input_consumed();
245 free_unpacker(env, pObj, uPtr);
246 return consumed;
247 }
248
249 JNIEXPORT jboolean JNICALL
250 Java_com_sun_java_util_jar_pack_NativeUnpack_setOption(JNIEnv *env, jobject pObj,
251 jstring pProp, jstring pValue) {
252 unpacker* uPtr = get_unpacker(env, pObj);
253 const char* prop = env->GetStringUTFChars(pProp, JNI_FALSE);
254 const char* value = env->GetStringUTFChars(pValue, JNI_FALSE);
255 jboolean retval = uPtr->set_option(prop, value);
256 env->ReleaseStringUTFChars(pProp, prop);
257 env->ReleaseStringUTFChars(pValue, value);
|
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 static jmethodID getUnpackerPtrMID;
54
55 static char* dbg = null;
56
57 #define THROW_IOE(x) JNU_ThrowIOException(env,x)
58
59 static jlong read_input_via_jni(unpacker* self,
60 void* buf, jlong minlen, jlong maxlen);
61
62 static unpacker* get_unpacker(JNIEnv *env, jobject pObj, bool noCreate=false) {
63 unpacker* uPtr;
64 jlong p = env->CallLongMethod(pObj, getUnpackerPtrMID);
65 uPtr = (unpacker*)jlong2ptr(p);
66 if (uPtr == null) {
67 if (noCreate) return null;
68 uPtr = new unpacker();
69 if (uPtr == null) {
70 THROW_IOE(ERROR_ENOMEM);
71 return null;
72 }
73 //fprintf(stderr, "get_unpacker(%p) uPtr=%p initializing\n", pObj, uPtr);
74 uPtr->init(read_input_via_jni);
75 uPtr->jniobj = (void*) env->NewGlobalRef(pObj);
76 env->SetLongField(pObj, unpackerPtrFID, ptr2jlong(uPtr));
77 }
78 uPtr->jnienv = env; // keep refreshing this in case of MT access
79 return uPtr;
80 }
81
82 // This is the harder trick: Pull the current state out of mid-air.
83 static unpacker* get_unpacker() {
84 //fprintf(stderr, "get_unpacker()\n");
85 JavaVM* vm = null;
86 jsize nVM = 0;
87 jint retval = JNI_GetCreatedJavaVMs(&vm, 1, &nVM);
88 // other VM implements may differ, thus for correctness, we need these checks
89 if (retval != JNI_OK || nVM != 1)
90 return null;
91 void* envRaw = null;
92 vm->GetEnv(&envRaw, JNI_VERSION_1_1);
93 JNIEnv* env = (JNIEnv*) envRaw;
94 //fprintf(stderr, "get_unpacker() env=%p\n", env);
95 if (env == null)
96 return null;
97 jobject pObj = env->CallStaticObjectMethod(NIclazz, currentInstMID);
98 //fprintf(stderr, "get_unpacker0() pObj=%p\n", pObj);
99 if (pObj != null) {
100 // Got pObj and env; now do it the easy way.
101 return get_unpacker(env, pObj);
102 }
103 // this should really not happen, if it does something is seriously
104 // wrong throw an exception
105 THROW_IOE(ERROR_INTERNAL);
106 return null;
107 }
108
109 static void free_unpacker(JNIEnv *env, jobject pObj, unpacker* uPtr) {
110 if (uPtr != null) {
111 //fprintf(stderr, "free_unpacker(%p) uPtr=%p\n", pObj, uPtr);
112 env->DeleteGlobalRef((jobject) uPtr->jniobj);
113 uPtr->jniobj = null;
114 uPtr->free();
115 delete uPtr;
116 env->SetLongField(pObj, unpackerPtrFID, (jlong)null);
117 }
118 }
119
120 unpacker* unpacker::current() {
121 return get_unpacker();
122 }
123
124 // Callback for fetching data, Java style. Calls NativeUnpack.readInputFn().
125 static jlong read_input_via_jni(unpacker* self,
126 void* buf, jlong minlen, jlong maxlen) {
127 JNIEnv* env = (JNIEnv*) self->jnienv;
128 jobject pbuf = env->NewDirectByteBuffer(buf, maxlen);
129 return env->CallLongMethod((jobject) self->jniobj, readInputMID,
130 pbuf, minlen);
131 }
132
133 JNIEXPORT void JNICALL
134 Java_com_sun_java_util_jar_pack_NativeUnpack_initIDs(JNIEnv *env, jclass clazz) {
135 #ifndef PRODUCT
136 dbg = getenv("DEBUG_ATTACH");
137 while( dbg != null) { sleep(10); }
138 #endif
139 NIclazz = (jclass) env->NewGlobalRef(clazz);
140 unpackerPtrFID = env->GetFieldID(clazz, "unpackerPtr", "J");
141 currentInstMID = env->GetStaticMethodID(clazz, "currentInstance",
142 "()Ljava/lang/Object;");
143 readInputMID = env->GetMethodID(clazz, "readInputFn",
144 "(Ljava/nio/ByteBuffer;J)J");
145 getUnpackerPtrMID = env->GetMethodID(clazz, "getUnpackerPtr", "()J");
146
147 if (unpackerPtrFID == null ||
148 currentInstMID == null ||
149 readInputMID == null ||
150 NIclazz == null ||
151 getUnpackerPtrMID == null) {
152 THROW_IOE("cannot init class members");
153 }
154 }
155
156 JNIEXPORT jlong JNICALL
157 Java_com_sun_java_util_jar_pack_NativeUnpack_start(JNIEnv *env, jobject pObj,
158 jobject pBuf, jlong offset) {
159 // try to get the unpacker pointer the hard way first, we do this to ensure
160 // valid object pointers and env is intact, if not now is good time to bail.
161 unpacker* uPtr = get_unpacker();
162 //fprintf(stderr, "start(%p) uPtr=%p initializing\n", pObj, uPtr);
163 if (uPtr == null) {
164 return -1;
165 }
166 // redirect our io to the default log file or whatever.
167 uPtr->redirect_stdio();
168
169 void* buf = null;
170 size_t buflen = 0;
171 if (pBuf != null) {
172 buf = env->GetDirectBufferAddress(pBuf);
173 buflen = (size_t)env->GetDirectBufferCapacity(pBuf);
174 if (buflen == 0) buf = null;
175 if (buf == null) { THROW_IOE(ERROR_INTERNAL); return 0; }
176 if ((size_t)offset >= buflen)
177 { buf = null; buflen = 0; }
178 else
179 { buf = (char*)buf + (size_t)offset; buflen -= (size_t)offset; }
180 }
181 // before we start off we make sure there is no other error by the time we
182 // get here
183 if (uPtr->aborting()) {
184 THROW_IOE(uPtr->get_abort_message());
185 return 0;
186 }
187 uPtr->start(buf, buflen);
188 if (uPtr->aborting()) {
189 THROW_IOE(uPtr->get_abort_message());
190 return 0;
191 }
192
193 return ((jlong)
194 uPtr->get_segments_remaining() << 32)
195 + uPtr->get_files_remaining();
196 }
197
198 JNIEXPORT jboolean JNICALL
199 Java_com_sun_java_util_jar_pack_NativeUnpack_getNextFile(JNIEnv *env, jobject pObj,
200 jobjectArray pParts) {
201
202 unpacker* uPtr = get_unpacker(env, pObj);
203 unpacker::file* filep = uPtr->get_next_file();
204
205 if (uPtr->aborting()) {
206 THROW_IOE(uPtr->get_abort_message());
233 pDataBuf = env->NewDirectByteBuffer(filep->data[1].ptr,
234 filep->data[1].len);
235 env->SetObjectArrayElement(pParts, pidx++, pDataBuf);
236
237 return true;
238 }
239
240
241 JNIEXPORT jobject JNICALL
242 Java_com_sun_java_util_jar_pack_NativeUnpack_getUnusedInput(JNIEnv *env, jobject pObj) {
243 unpacker* uPtr = get_unpacker(env, pObj);
244 unpacker::file* filep = &uPtr->cur_file;
245
246 if (uPtr->aborting()) {
247 THROW_IOE(uPtr->get_abort_message());
248 return false;
249 }
250
251 // We have fetched all the files.
252 // Now swallow up any remaining input.
253 if (uPtr->input_remaining() == 0) {
254 return null;
255 } else {
256 bytes remaining_bytes;
257 remaining_bytes.malloc(uPtr->input_remaining());
258 remaining_bytes.copyFrom(uPtr->input_scan(), uPtr->input_remaining());
259 return env->NewDirectByteBuffer(remaining_bytes.ptr, remaining_bytes.len);
260 }
261 }
262
263 JNIEXPORT jlong JNICALL
264 Java_com_sun_java_util_jar_pack_NativeUnpack_finish(JNIEnv *env, jobject pObj) {
265 unpacker* uPtr = get_unpacker(env, pObj, false);
266 if (uPtr == null) return 0;
267 size_t consumed = uPtr->input_consumed();
268 free_unpacker(env, pObj, uPtr);
269 return consumed;
270 }
271
272 JNIEXPORT jboolean JNICALL
273 Java_com_sun_java_util_jar_pack_NativeUnpack_setOption(JNIEnv *env, jobject pObj,
274 jstring pProp, jstring pValue) {
275 unpacker* uPtr = get_unpacker(env, pObj);
276 const char* prop = env->GetStringUTFChars(pProp, JNI_FALSE);
277 const char* value = env->GetStringUTFChars(pValue, JNI_FALSE);
278 jboolean retval = uPtr->set_option(prop, value);
279 env->ReleaseStringUTFChars(pProp, prop);
280 env->ReleaseStringUTFChars(pValue, value);
|