1/*
2 * Copyright (c) 1997, 2018, 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#include <stdlib.h>
27#include <string.h>
28
29#include "jvm.h"
30#include "jni.h"
31#include "jni_util.h"
32#include "java_lang_String.h"
33
34/* Due to a bug in the win32 C runtime library strings
35 * such as "z:" need to be appended with a "." so we
36 * must allocate at least 4 bytes to allow room for
37 * this expansion. See 4235353 for details.
38 */
39#define MALLOC_MIN4(len) ((char *)malloc((len) + 1 < 4 ? 4 : (len) + 1))
40
41/**
42 * Throw a Java exception by name. Similar to SignalError.
43 */
44JNIEXPORT void JNICALL
45JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg)
46{
47 jclass cls = (*env)->FindClass(env, name);
48
49 if (cls != 0) /* Otherwise an exception has already been thrown */
50 (*env)->ThrowNew(env, cls, msg);
51}
52
53/* JNU_Throw common exceptions */
54
55JNIEXPORT void JNICALL
56JNU_ThrowNullPointerException(JNIEnv *env, const char *msg)
57{
58 JNU_ThrowByName(env, "java/lang/NullPointerException", msg);
59}
60
61JNIEXPORT void JNICALL
62JNU_ThrowArrayIndexOutOfBoundsException(JNIEnv *env, const char *msg)
63{
64 JNU_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", msg);
65}
66
67JNIEXPORT void JNICALL
68JNU_ThrowOutOfMemoryError(JNIEnv *env, const char *msg)
69{
70 JNU_ThrowByName(env, "java/lang/OutOfMemoryError", msg);
71}
72
73JNIEXPORT void JNICALL
74JNU_ThrowIllegalArgumentException(JNIEnv *env, const char *msg)
75{
76 JNU_ThrowByName(env, "java/lang/IllegalArgumentException", msg);
77}
78
79JNIEXPORT void JNICALL
80JNU_ThrowIllegalAccessError(JNIEnv *env, const char *msg)
81{
82 JNU_ThrowByName(env, "java/lang/IllegalAccessError", msg);
83}
84
85JNIEXPORT void JNICALL
86JNU_ThrowIllegalAccessException(JNIEnv *env, const char *msg)
87{
88 JNU_ThrowByName(env, "java/lang/IllegalAccessException", msg);
89}
90
91JNIEXPORT void JNICALL
92JNU_ThrowInternalError(JNIEnv *env, const char *msg)
93{
94 JNU_ThrowByName(env, "java/lang/InternalError", msg);
95}
96
97JNIEXPORT void JNICALL
98JNU_ThrowNoSuchFieldException(JNIEnv *env, const char *msg)
99{
100 JNU_ThrowByName(env, "java/lang/NoSuchFieldException", msg);
101}
102
103JNIEXPORT void JNICALL
104JNU_ThrowNoSuchMethodException(JNIEnv *env, const char *msg)
105{
106 JNU_ThrowByName(env, "java/lang/NoSuchMethodException", msg);
107}
108
109JNIEXPORT void JNICALL
110JNU_ThrowClassNotFoundException(JNIEnv *env, const char *msg)
111{
112 JNU_ThrowByName(env, "java/lang/ClassNotFoundException", msg);
113}
114
115JNIEXPORT void JNICALL
116JNU_ThrowNumberFormatException(JNIEnv *env, const char *msg)
117{
118 JNU_ThrowByName(env, "java/lang/NumberFormatException", msg);
119}
120
121JNIEXPORT void JNICALL
122JNU_ThrowIOException(JNIEnv *env, const char *msg)
123{
124 JNU_ThrowByName(env, "java/io/IOException", msg);
125}
126
127JNIEXPORT void JNICALL
128JNU_ThrowNoSuchFieldError(JNIEnv *env, const char *msg)
129{
130 JNU_ThrowByName(env, "java/lang/NoSuchFieldError", msg);
131}
132
133JNIEXPORT void JNICALL
134JNU_ThrowNoSuchMethodError(JNIEnv *env, const char *msg)
135{
136 JNU_ThrowByName(env, "java/lang/NoSuchMethodError", msg);
137}
138
139JNIEXPORT void JNICALL
140JNU_ThrowStringIndexOutOfBoundsException(JNIEnv *env, const char *msg)
141{
142 JNU_ThrowByName(env, "java/lang/StringIndexOutOfBoundsException", msg);
143}
144
145JNIEXPORT void JNICALL
146JNU_ThrowInstantiationException(JNIEnv *env, const char *msg)
147{
148 JNU_ThrowByName(env, "java/lang/InstantiationException", msg);
149}
150
151/*
152 * Throw an exception by name, using the string returned by
153 * getLastErrorString for the detail string. If the last-error
154 * string is NULL, use the given default detail string.
155 */
156JNIEXPORT void JNICALL
157JNU_ThrowByNameWithLastError(JNIEnv *env, const char *name,
158 const char *defaultDetail)
159{
160 char buf[256];
161 size_t n = getLastErrorString(buf, sizeof(buf));
162
163 if (n > 0) {
164 jstring s = JNU_NewStringPlatform(env, buf);
165 if (s != NULL) {
166 jobject x = JNU_NewObjectByName(env, name,
167 "(Ljava/lang/String;)V", s);
168 if (x != NULL) {
169 (*env)->Throw(env, x);
170 }
171 }
172 }
173 if (!(*env)->ExceptionOccurred(env)) {
174 JNU_ThrowByName(env, name, defaultDetail);
175 }
176}
177
178/*
179 * Throw an exception by name, using a given message and the string
180 * returned by getLastErrorString to construct the detail string.
181 */
182JNIEXPORT void JNICALL
183JNU_ThrowByNameWithMessageAndLastError
184 (JNIEnv *env, const char *name, const char *message)
185{
186 char buf[256];
187 size_t n = getLastErrorString(buf, sizeof(buf));
188 size_t messagelen = message == NULL ? 0 : strlen(message);
189
190 if (n > 0) {
191 jstring s = JNU_NewStringPlatform(env, buf);
192 if (s != NULL) {
193 jobject x = NULL;
194 if (messagelen) {
195 jstring s2 = NULL;
196 size_t messageextlen = messagelen + 4;
197 char *str1 = (char *)malloc((messageextlen) * sizeof(char));
198 if (str1 == 0) {
199 JNU_ThrowOutOfMemoryError(env, 0);
200 return;
201 }
202 jio_snprintf(str1, messageextlen, " (%s)", message);
203 s2 = (*env)->NewStringUTF(env, str1);
204 free(str1);
205 JNU_CHECK_EXCEPTION(env);
206 if (s2 != NULL) {
207 jstring s3 = JNU_CallMethodByName(
208 env, NULL, s, "concat",
209 "(Ljava/lang/String;)Ljava/lang/String;",
210 s2).l;
211 (*env)->DeleteLocalRef(env, s2);
212 JNU_CHECK_EXCEPTION(env);
213 if (s3 != NULL) {
214 (*env)->DeleteLocalRef(env, s);
215 s = s3;
216 }
217 }
218 }
219 x = JNU_NewObjectByName(env, name, "(Ljava/lang/String;)V", s);
220 if (x != NULL) {
221 (*env)->Throw(env, x);
222 }
223 }
224 }
225
226 if (!(*env)->ExceptionOccurred(env)) {
227 if (messagelen) {
228 JNU_ThrowByName(env, name, message);
229 } else {
230 JNU_ThrowByName(env, name, "no further information");
231 }
232 }
233}
234
235/*
236 * Convenience method.
237 * Call JNU_ThrowByNameWithLastError for java.io.IOException.
238 */
239JNIEXPORT void JNICALL
240JNU_ThrowIOExceptionWithLastError(JNIEnv *env, const char *defaultDetail)
241{
242 JNU_ThrowByNameWithLastError(env, "java/io/IOException", defaultDetail);
243}
244
245
246JNIEXPORT jvalue JNICALL
247JNU_CallStaticMethodByName(JNIEnv *env,
248 jboolean *hasException,
249 const char *class_name,
250 const char *name,
251 const char *signature,
252 ...)
253{
254 jclass clazz;
255 jmethodID mid;
256 va_list args;
257 jvalue result;
258 const char *p = signature;
259
260 /* find out the return type */
261 while (*p && *p != ')')
262 p++;
263 p++;
264
265 result.i = 0;
266
267 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
268 goto done2;
269
270 clazz = (*env)->FindClass(env, class_name);
271 if (clazz == 0)
272 goto done2;
273 mid = (*env)->GetStaticMethodID(env, clazz, name, signature);
274 if (mid == 0)
275 goto done1;
276 va_start(args, signature);
277 switch (*p) {
278 case 'V':
279 (*env)->CallStaticVoidMethodV(env, clazz, mid, args);
280 break;
281 case '[':
282 case 'L':
283 result.l = (*env)->CallStaticObjectMethodV(env, clazz, mid, args);
284 break;
285 case 'Z':
286 result.z = (*env)->CallStaticBooleanMethodV(env, clazz, mid, args);
287 break;
288 case 'B':
289 result.b = (*env)->CallStaticByteMethodV(env, clazz, mid, args);
290 break;
291 case 'C':
292 result.c = (*env)->CallStaticCharMethodV(env, clazz, mid, args);
293 break;
294 case 'S':
295 result.s = (*env)->CallStaticShortMethodV(env, clazz, mid, args);
296 break;
297 case 'I':
298 result.i = (*env)->CallStaticIntMethodV(env, clazz, mid, args);
299 break;
300 case 'J':
301 result.j = (*env)->CallStaticLongMethodV(env, clazz, mid, args);
302 break;
303 case 'F':
304 result.f = (*env)->CallStaticFloatMethodV(env, clazz, mid, args);
305 break;
306 case 'D':
307 result.d = (*env)->CallStaticDoubleMethodV(env, clazz, mid, args);
308 break;
309 default:
310 (*env)->FatalError(env, "JNU_CallStaticMethodByName: illegal signature");
311 }
312 va_end(args);
313
314 done1:
315 (*env)->DeleteLocalRef(env, clazz);
316 done2:
317 if (hasException) {
318 *hasException = (*env)->ExceptionCheck(env);
319 }
320 return result;
321}
322
323JNIEXPORT jvalue JNICALL
324JNU_CallMethodByName(JNIEnv *env,
325 jboolean *hasException,
326 jobject obj,
327 const char *name,
328 const char *signature,
329 ...)
330{
331 jvalue result;
332 va_list args;
333
334 va_start(args, signature);
335 result = JNU_CallMethodByNameV(env, hasException, obj, name, signature,
336 args);
337 va_end(args);
338
339 return result;
340}
341
342
343JNIEXPORT jvalue JNICALL
344JNU_CallMethodByNameV(JNIEnv *env,
345 jboolean *hasException,
346 jobject obj,
347 const char *name,
348 const char *signature,
349 va_list args)
350{
351 jclass clazz;
352 jmethodID mid;
353 jvalue result;
354 const char *p = signature;
355
356 /* find out the return type */
357 while (*p && *p != ')')
358 p++;
359 p++;
360
361 result.i = 0;
362
363 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
364 goto done2;
365
366 clazz = (*env)->GetObjectClass(env, obj);
367 mid = (*env)->GetMethodID(env, clazz, name, signature);
368 if (mid == 0)
369 goto done1;
370
371 switch (*p) {
372 case 'V':
373 (*env)->CallVoidMethodV(env, obj, mid, args);
374 break;
375 case '[':
376 case 'L':
377 result.l = (*env)->CallObjectMethodV(env, obj, mid, args);
378 break;
379 case 'Z':
380 result.z = (*env)->CallBooleanMethodV(env, obj, mid, args);
381 break;
382 case 'B':
383 result.b = (*env)->CallByteMethodV(env, obj, mid, args);
384 break;
385 case 'C':
386 result.c = (*env)->CallCharMethodV(env, obj, mid, args);
387 break;
388 case 'S':
389 result.s = (*env)->CallShortMethodV(env, obj, mid, args);
390 break;
391 case 'I':
392 result.i = (*env)->CallIntMethodV(env, obj, mid, args);
393 break;
394 case 'J':
395 result.j = (*env)->CallLongMethodV(env, obj, mid, args);
396 break;
397 case 'F':
398 result.f = (*env)->CallFloatMethodV(env, obj, mid, args);
399 break;
400 case 'D':
401 result.d = (*env)->CallDoubleMethodV(env, obj, mid, args);
402 break;
403 default:
404 (*env)->FatalError(env, "JNU_CallMethodByNameV: illegal signature");
405 }
406 done1:
407 (*env)->DeleteLocalRef(env, clazz);
408 done2:
409 if (hasException) {
410 *hasException = (*env)->ExceptionCheck(env);
411 }
412 return result;
413}
414
415JNIEXPORT jobject JNICALL
416JNU_NewObjectByName(JNIEnv *env, const char *class_name,
417 const char *constructor_sig, ...)
418{
419 jobject obj = NULL;
420
421 jclass cls = 0;
422 jmethodID cls_initMID;
423 va_list args;
424
425 if ((*env)->EnsureLocalCapacity(env, 2) < 0)
426 goto done;
427
428 cls = (*env)->FindClass(env, class_name);
429 if (cls == 0) {
430 goto done;
431 }
432 cls_initMID = (*env)->GetMethodID(env, cls,
433 "<init>", constructor_sig);
434 if (cls_initMID == NULL) {
435 goto done;
436 }
437 va_start(args, constructor_sig);
438 obj = (*env)->NewObjectV(env, cls, cls_initMID, args);
439 va_end(args);
440
441 done:
442 (*env)->DeleteLocalRef(env, cls);
443 return obj;
444}
445
446/* Optimized for charset ISO_8559_1 */
447static jstring
448newSizedString8859_1(JNIEnv *env, const char *str, const int len)
449{
450 jchar buf[512];
451 jchar *str1;
452 jstring result;
453 int i;
454
455 if ((*env)->EnsureLocalCapacity(env, 1) < 0)
456 return NULL;
457
458 if (len > 512) {
459 str1 = (jchar *)malloc(len * sizeof(jchar));
460 if (str1 == 0) {
461 JNU_ThrowOutOfMemoryError(env, 0);
462 return 0;
463 }
464 } else
465 str1 = buf;
466
467 for (i=0;i<len;i++)
468 str1[i] = (unsigned char)str[i];
469 result = (*env)->NewString(env, str1, len);
470 if (str1 != buf)
471 free(str1);
472 return result;
473}
474
475static jstring
476newString8859_1(JNIEnv *env, const char *str)
477{
478 int len = (int)strlen(str);
479 return newSizedString8859_1(env, str, len);
480}
481
482static const char*
483getString8859_1Chars(JNIEnv *env, jstring jstr)
484{
485 int i;
486 char *result;
487 jint len = (*env)->GetStringLength(env, jstr);
488 const jchar *str = (*env)->GetStringCritical(env, jstr, 0);
489 if (str == 0) {
490 return 0;
491 }
492
493 result = MALLOC_MIN4(len);
494 if (result == 0) {
495 (*env)->ReleaseStringCritical(env, jstr, str);
496 JNU_ThrowOutOfMemoryError(env, 0);
497 return 0;
498 }
499
500 for (i=0; i<len; i++) {
501 jchar unicode = str[i];
502 if (unicode <= 0x00ff)
503 result[i] = (char)unicode;
504 else
505 result[i] = '?';
506 }
507
508 result[len] = 0;
509 (*env)->ReleaseStringCritical(env, jstr, str);
510 return result;
511}
512
513
514/* Optimized for charset ISO646-US (us-ascii) */
515static jstring
516newString646_US(JNIEnv *env, const char *str)
517{
518 int len = (int)strlen(str);
519 jchar buf[512];
520 jchar *str1;
521 jstring result;
522 int i;
523
524 if (len > 512) {
525 str1 = (jchar *)malloc(len * sizeof(jchar));
526 if (str1 == 0) {
527 JNU_ThrowOutOfMemoryError(env, 0);
528 return 0;
529 }
530 } else
531 str1 = buf;
532
533 for (i=0; i<len; i++) {
534 unsigned char c = (unsigned char)str[i];
535 if (c <= 0x7f)
536 str1[i] = c;
537 else
538 str1[i] = '?';
539 }
540
541 result = (*env)->NewString(env, str1, len);
542 if (str1 != buf)
543 free(str1);
544 return result;
545}
546
547static const char*
548getString646_USChars(JNIEnv *env, jstring jstr)
549{
550 int i;
551 char *result;
552 jint len = (*env)->GetStringLength(env, jstr);
553 const jchar *str = (*env)->GetStringCritical(env, jstr, 0);
554 if (str == 0) {
555 return 0;
556 }
557
558 result = MALLOC_MIN4(len);
559 if (result == 0) {
560 (*env)->ReleaseStringCritical(env, jstr, str);
561 JNU_ThrowOutOfMemoryError(env, 0);
562 return 0;
563 }
564
565 for (i=0; i<len; i++) {
566 jchar unicode = str[i];
567 if (unicode <= 0x007f )
568 result[i] = (char)unicode;
569 else
570 result[i] = '?';
571 }
572
573 result[len] = 0;
574 (*env)->ReleaseStringCritical(env, jstr, str);
575 return result;
576}
577
578/* enumeration of c1 row from Cp1252 */
579static int cp1252c1chars[32] = {
580 0x20AC,0xFFFD,0x201A,0x0192,0x201E,0x2026,0x2020,0x2021,
581 0x02C6,0x2030,0x0160,0x2039,0x0152,0xFFFD,0x017D,0xFFFD,
582 0xFFFD,0x2018,0x2019,0x201C,0x201D,0x2022,0x2013,0x2014,
583 0x02Dc,0x2122,0x0161,0x203A,0x0153,0xFFFD,0x017E,0x0178
584};
585
586/* Optimized for charset Cp1252 */
587static jstring
588newStringCp1252(JNIEnv *env, const char *str)
589{
590 int len = (int) strlen(str);
591 jchar buf[512];
592 jchar *str1;
593 jstring result;
594 int i;
595
596 if ((*env)->EnsureLocalCapacity(env, 1) < 0)
597 return NULL;
598
599 if (len > 512) {
600 str1 = (jchar *)malloc(len * sizeof(jchar));
601 if (str1 == 0) {
602 JNU_ThrowOutOfMemoryError(env, 0);
603 return 0;
604 }
605 } else
606 str1 = buf;
607
608 for (i=0; i<len; i++) {
609 unsigned char c = (unsigned char)str[i];
610 if ((c >= 0x80) && (c <= 0x9f))
611 str1[i] = cp1252c1chars[c-128];
612 else
613 str1[i] = c;
614 }
615
616 result = (*env)->NewString(env, str1, len);
617 if (str1 != buf)
618 free(str1);
619 return result;
620}
621
622static const char*
623getStringCp1252Chars(JNIEnv *env, jstring jstr)
624{
625 int i;
626 char *result;
627 jint len = (*env)->GetStringLength(env, jstr);
628 const jchar *str = (*env)->GetStringCritical(env, jstr, 0);
629 if (str == 0) {
630 return 0;
631 }
632
633 result = MALLOC_MIN4(len);
634 if (result == 0) {
635 (*env)->ReleaseStringCritical(env, jstr, str);
636 JNU_ThrowOutOfMemoryError(env, 0);
637 return 0;
638 }
639
640 for (i=0; i<len; i++) {
641 jchar c = str[i];
642 if (c < 256) {
643 if ((c >= 0x80) && (c <= 0x9f)) {
644 result[i] = '?';
645 } else {
646 result[i] = (char)c;
647 }
648 } else switch(c) {
649 case 0x20AC: result[i] = (char)0x80; break;
650 case 0x201A: result[i] = (char)0x82; break;
651 case 0x0192: result[i] = (char)0x83; break;
652 case 0x201E: result[i] = (char)0x84; break;
653 case 0x2026: result[i] = (char)0x85; break;
654 case 0x2020: result[i] = (char)0x86; break;
655 case 0x2021: result[i] = (char)0x87; break;
656 case 0x02C6: result[i] = (char)0x88; break;
657 case 0x2030: result[i] = (char)0x89; break;
658 case 0x0160: result[i] = (char)0x8A; break;
659 case 0x2039: result[i] = (char)0x8B; break;
660 case 0x0152: result[i] = (char)0x8C; break;
661 case 0x017D: result[i] = (char)0x8E; break;
662 case 0x2018: result[i] = (char)0x91; break;
663 case 0x2019: result[i] = (char)0x92; break;
664 case 0x201C: result[i] = (char)0x93; break;
665 case 0x201D: result[i] = (char)0x94; break;
666 case 0x2022: result[i] = (char)0x95; break;
667 case 0x2013: result[i] = (char)0x96; break;
668 case 0x2014: result[i] = (char)0x97; break;
669 case 0x02DC: result[i] = (char)0x98; break;
670 case 0x2122: result[i] = (char)0x99; break;
671 case 0x0161: result[i] = (char)0x9A; break;
672 case 0x203A: result[i] = (char)0x9B; break;
673 case 0x0153: result[i] = (char)0x9C; break;
674 case 0x017E: result[i] = (char)0x9E; break;
675 case 0x0178: result[i] = (char)0x9F; break;
676 default: result[i] = '?'; break;
677 }
678 }
679
680 result[len] = 0;
681 (*env)->ReleaseStringCritical(env, jstr, str);
682 return result;
683}
684
685static int fastEncoding = NO_ENCODING_YET;
686static jstring jnuEncoding = NULL;
687
688/* Cached method IDs */
689static jmethodID String_init_ID; /* String(byte[], enc) */
690static jmethodID String_getBytes_ID; /* String.getBytes(enc) */
691
692/* Cached field IDs */
693static jfieldID String_coder_ID; /* String.coder */
694static jfieldID String_value_ID; /* String.value */
695
696static jboolean isJNUEncodingSupported = JNI_FALSE;
697static jboolean jnuEncodingSupported(JNIEnv *env) {
698 jboolean exe;
699 if (isJNUEncodingSupported == JNI_TRUE) {
700 return JNI_TRUE;
701 }
702 isJNUEncodingSupported = (jboolean) JNU_CallStaticMethodByName (
703 env, &exe,
704 "java/nio/charset/Charset",
705 "isSupported",
706 "(Ljava/lang/String;)Z",
707 jnuEncoding).z;
708 return isJNUEncodingSupported;
709}
710
711/* Create a new string by converting str to a heap-allocated byte array and
712 * calling the appropriate String constructor.
713 */
714static jstring
715newSizedStringJava(JNIEnv *env, const char *str, const int len)
716{
717 jstring result = NULL;
718 jbyteArray bytes = 0;
719
720 if ((*env)->EnsureLocalCapacity(env, 2) < 0)
721 return NULL;
722
723 bytes = (*env)->NewByteArray(env, len);
724 if (bytes != NULL) {
725 jclass strClazz = JNU_ClassString(env);
726 CHECK_NULL_RETURN(strClazz, 0);
727 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *)str);
728 if (jnuEncodingSupported(env)) {
729 result = (*env)->NewObject(env, strClazz,
730 String_init_ID, bytes, jnuEncoding);
731 } else {
732 /*If the encoding specified in sun.jnu.encoding is not endorsed
733 by "Charset.isSupported" we have to fall back to use String(byte[])
734 explicitly here without specifying the encoding name, in which the
735 StringCoding class will pickup the iso-8859-1 as the fallback
736 converter for us.
737 */
738 jmethodID mid = (*env)->GetMethodID(env, strClazz,
739 "<init>", "([B)V");
740 if (mid != NULL) {
741 result = (*env)->NewObject(env, strClazz, mid, bytes);
742 }
743 }
744 (*env)->DeleteLocalRef(env, bytes);
745 return result;
746 }
747 return NULL;
748}
749
750static jstring
751newStringJava(JNIEnv *env, const char *str)
752{
753 int len = (int)strlen(str);
754 return newSizedStringJava(env, str, len);
755}
756
757/* Optimized for charset UTF-8 */
758static jstring
759newStringUTF8(JNIEnv *env, const char *str)
760{
761 int len;
762 const unsigned char *p;
763 unsigned char asciiCheck;
764 for (asciiCheck = 0, p = (const unsigned char*)str; *p != '\0'; p++) {
765 asciiCheck |= *p;
766 }
767 len = (int)((const char*)p - str);
768
769 if (asciiCheck < 0x80) {
770 // ascii fast-path
771 return newSizedString8859_1(env, str, len);
772 }
773
774 return newSizedStringJava(env, str, len);
775}
776
777/* Initialize the fast encoding from the encoding name.
778 * Export InitializeEncoding so that the VM can initialize it if required.
779 */
780JNIEXPORT void
781InitializeEncoding(JNIEnv *env, const char *encname)
782{
783 jclass strClazz = NULL;
784
785 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
786 return;
787
788 strClazz = JNU_ClassString(env);
789 CHECK_NULL(strClazz);
790
791 if (encname) {
792 /*
793 * On Solaris with nl_langinfo() called in GetJavaProperties():
794 *
795 * locale undefined -> NULL -> hardcoded default
796 * "C" locale -> "" -> hardcoded default (on 2.6)
797 * "C" locale -> "ISO646-US" (on Sol 7/8)
798 * "en_US" locale -> "ISO8859-1"
799 * "en_GB" locale -> "ISO8859-1" (on Sol 7/8)
800 * "en_UK" locale -> "ISO8859-1" (on 2.6)
801 */
802 if ((strcmp(encname, "8859_1") == 0) ||
803 (strcmp(encname, "ISO8859-1") == 0) ||
804 (strcmp(encname, "ISO8859_1") == 0) ||
805 (strcmp(encname, "ISO-8859-1") == 0)) {
806 fastEncoding = FAST_8859_1;
807 } else if (strcmp(encname, "UTF-8") == 0) {
808 jstring enc = (*env)->NewStringUTF(env, encname);
809 if (enc == NULL)
810 return;
811 fastEncoding = FAST_UTF_8;
812 jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc);
813 (*env)->DeleteLocalRef(env, enc);
814 } else if (strcmp(encname, "ISO646-US") == 0) {
815 fastEncoding = FAST_646_US;
816 } else if (strcmp(encname, "Cp1252") == 0 ||
817 /* This is a temporary fix until we move */
818 /* to wide character versions of all Windows */
819 /* calls. */
820 strcmp(encname, "utf-16le") == 0) {
821 fastEncoding = FAST_CP1252;
822 } else {
823 jstring enc = (*env)->NewStringUTF(env, encname);
824 if (enc == NULL)
825 return;
826 fastEncoding = NO_FAST_ENCODING;
827 jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc);
828 (*env)->DeleteLocalRef(env, enc);
829 }
830 } else {
831 JNU_ThrowInternalError(env, "platform encoding undefined");
832 return;
833 }
834
835 /* Initialize method-id cache */
836 String_getBytes_ID = (*env)->GetMethodID(env, strClazz,
837 "getBytes", "(Ljava/lang/String;)[B");
838 CHECK_NULL(String_getBytes_ID);
839 String_init_ID = (*env)->GetMethodID(env, strClazz,
840 "<init>", "([BLjava/lang/String;)V");
841 CHECK_NULL(String_init_ID);
842 String_coder_ID = (*env)->GetFieldID(env, strClazz, "coder", "B");
843 CHECK_NULL(String_coder_ID);
844 String_value_ID = (*env)->GetFieldID(env, strClazz, "value", "[B");
845 CHECK_NULL(String_value_ID);
846}
847
848JNIEXPORT jstring
849NewStringPlatform(JNIEnv *env, const char *str)
850{
851 return JNU_NewStringPlatform(env, str);
852}
853
854JNIEXPORT jstring JNICALL
855JNU_NewStringPlatform(JNIEnv *env, const char *str)
856{
857 if (fastEncoding == FAST_UTF_8)
858 return newStringUTF8(env, str);
859 if (fastEncoding == FAST_8859_1)
860 return newString8859_1(env, str);
861 if (fastEncoding == FAST_646_US)
862 return newString646_US(env, str);
863 if (fastEncoding == FAST_CP1252)
864 return newStringCp1252(env, str);
865 if (fastEncoding == NO_ENCODING_YET) {
866 JNU_ThrowInternalError(env, "platform encoding not initialized");
867 return NULL;
868 }
869 return newStringJava(env, str);
870}
871
872JNIEXPORT const char *
873GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)
874{
875 return JNU_GetStringPlatformChars(env, jstr, isCopy);
876}
877
878static const char* getStringBytes(JNIEnv *env, jstring jstr) {
879 char *result = NULL;
880 jbyteArray hab = 0;
881
882 if ((*env)->EnsureLocalCapacity(env, 2) < 0)
883 return 0;
884
885 if (jnuEncodingSupported(env)) {
886 hab = (*env)->CallObjectMethod(env, jstr, String_getBytes_ID, jnuEncoding);
887 } else {
888 jmethodID mid;
889 jclass strClazz = JNU_ClassString(env);
890 CHECK_NULL_RETURN(strClazz, 0);
891 mid = (*env)->GetMethodID(env, strClazz,
892 "getBytes", "()[B");
893 if (mid != NULL) {
894 hab = (*env)->CallObjectMethod(env, jstr, mid);
895 }
896 }
897
898 if (!(*env)->ExceptionCheck(env)) {
899 jint len = (*env)->GetArrayLength(env, hab);
900 result = MALLOC_MIN4(len);
901 if (result == 0) {
902 JNU_ThrowOutOfMemoryError(env, 0);
903 (*env)->DeleteLocalRef(env, hab);
904 return 0;
905 }
906 (*env)->GetByteArrayRegion(env, hab, 0, len, (jbyte *)result);
907 result[len] = 0; /* NULL-terminate */
908 }
909
910 (*env)->DeleteLocalRef(env, hab);
911 return result;
912}
913
914static const char*
915getStringUTF8(JNIEnv *env, jstring jstr)
916{
917 int i;
918 char *result;
919 jbyteArray value;
920 jint len;
921 jbyte *str;
922 jint rlen;
923 int ri;
924 jbyte coder = (*env)->GetByteField(env, jstr, String_coder_ID);
925 if (coder != java_lang_String_LATIN1) {
926 return getStringBytes(env, jstr);
927 }
928 if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
929 return NULL;
930 }
931 value = (*env)->GetObjectField(env, jstr, String_value_ID);
932 if (value == NULL)
933 return NULL;
934 len = (*env)->GetArrayLength(env, value);
935 str = (*env)->GetPrimitiveArrayCritical(env, value, NULL);
936 if (str == NULL) {
937 return NULL;
938 }
939
940 rlen = len;
941 // we need two bytes for each latin-1 char above 127 (negative jbytes)
942 for (i = 0; i < len; i++) {
943 if (str[i] < 0) {
944 rlen++;
945 }
946 }
947
948 result = MALLOC_MIN4(rlen);
949 if (result == NULL) {
950 (*env)->ReleasePrimitiveArrayCritical(env, value, str, 0);
951 JNU_ThrowOutOfMemoryError(env, 0);
952 return NULL;
953 }
954
955 for (ri = 0, i = 0; i < len; i++) {
956 jbyte c = str[i];
957 if (c < 0) {
958 result[ri++] = (char)(0xc0 | ((c & 0xff) >> 6));
959 result[ri++] = (char)(0x80 | (c & 0x3f));
960 } else {
961 result[ri++] = c;
962 }
963 }
964 (*env)->ReleasePrimitiveArrayCritical(env, value, str, 0);
965 result[rlen] = '\0';
966 return result;
967}
968
969JNIEXPORT const char * JNICALL
970JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)
971{
972
973 if (isCopy)
974 *isCopy = JNI_TRUE;
975
976 if (fastEncoding == FAST_UTF_8)
977 return getStringUTF8(env, jstr);
978 if (fastEncoding == FAST_8859_1)
979 return getString8859_1Chars(env, jstr);
980 if (fastEncoding == FAST_646_US)
981 return getString646_USChars(env, jstr);
982 if (fastEncoding == FAST_CP1252)
983 return getStringCp1252Chars(env, jstr);
984 if (fastEncoding == NO_ENCODING_YET) {
985 JNU_ThrowInternalError(env, "platform encoding not initialized");
986 return 0;
987 } else
988 return getStringBytes(env, jstr);
989}
990
991JNIEXPORT void JNICALL
992JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str)
993{
994 free((void *)str);
995}
996
997/*
998 * Export the platform dependent path canonicalization so that
999 * VM can find it when loading system classes.
1000 * This function is also used by the instrumentation agent.
1001 */
1002extern int canonicalize(char *path, const char *out, int len);
1003
1004JNIEXPORT int
1005Canonicalize(JNIEnv *unused, char *orig, char *out, int len)
1006{
1007 /* canonicalize an already natived path */
1008 return canonicalize(orig, out, len);
1009}
1010
1011JNIEXPORT jclass JNICALL
1012JNU_ClassString(JNIEnv *env)
1013{
1014 static jclass cls = 0;
1015 if (cls == 0) {
1016 jclass c;
1017 if ((*env)->EnsureLocalCapacity(env, 1) < 0)
1018 return 0;
1019 c = (*env)->FindClass(env, "java/lang/String");
1020 CHECK_NULL_RETURN(c, NULL);
1021 cls = (*env)->NewGlobalRef(env, c);
1022 (*env)->DeleteLocalRef(env, c);
1023 }
1024 return cls;
1025}
1026
1027JNIEXPORT jclass JNICALL
1028JNU_ClassClass(JNIEnv *env)
1029{
1030 static jclass cls = 0;
1031 if (cls == 0) {
1032 jclass c;
1033 if ((*env)->EnsureLocalCapacity(env, 1) < 0)
1034 return 0;
1035 c = (*env)->FindClass(env, "java/lang/Class");
1036 CHECK_NULL_RETURN(c, NULL);
1037 cls = (*env)->NewGlobalRef(env, c);
1038 (*env)->DeleteLocalRef(env, c);
1039 }
1040 return cls;
1041}
1042
1043JNIEXPORT jclass JNICALL
1044JNU_ClassObject(JNIEnv *env)
1045{
1046 static jclass cls = 0;
1047 if (cls == 0) {
1048 jclass c;
1049 if ((*env)->EnsureLocalCapacity(env, 1) < 0)
1050 return 0;
1051 c = (*env)->FindClass(env, "java/lang/Object");
1052 CHECK_NULL_RETURN(c, NULL);
1053 cls = (*env)->NewGlobalRef(env, c);
1054 (*env)->DeleteLocalRef(env, c);
1055 }
1056 return cls;
1057}
1058
1059JNIEXPORT jclass JNICALL
1060JNU_ClassThrowable(JNIEnv *env)
1061{
1062 static jclass cls = 0;
1063 if (cls == 0) {
1064 jclass c;
1065 if ((*env)->EnsureLocalCapacity(env, 1) < 0)
1066 return 0;
1067 c = (*env)->FindClass(env, "java/lang/Throwable");
1068 CHECK_NULL_RETURN(c, NULL);
1069 cls = (*env)->NewGlobalRef(env, c);
1070 (*env)->DeleteLocalRef(env, c);
1071 }
1072 return cls;
1073}
1074
1075JNIEXPORT jint JNICALL
1076JNU_CopyObjectArray(JNIEnv *env, jobjectArray dst, jobjectArray src,
1077 jint count)
1078{
1079 int i;
1080 if ((*env)->EnsureLocalCapacity(env, 1) < 0)
1081 return -1;
1082 for (i=0; i<count; i++) {
1083 jstring p = (*env)->GetObjectArrayElement(env, src, i);
1084 (*env)->SetObjectArrayElement(env, dst, i, p);
1085 (*env)->DeleteLocalRef(env, p);
1086 }
1087 return 0;
1088}
1089
1090JNIEXPORT void * JNICALL
1091JNU_GetEnv(JavaVM *vm, jint version)
1092{
1093 void *env;
1094 (*vm)->GetEnv(vm, &env, version);
1095 return env;
1096}
1097
1098JNIEXPORT jint JNICALL
1099JNU_IsInstanceOfByName(JNIEnv *env, jobject object, char* classname)
1100{
1101 jclass cls;
1102 if ((*env)->EnsureLocalCapacity(env, 1) < 0)
1103 return JNI_ERR;
1104 cls = (*env)->FindClass(env, classname);
1105 if (cls != NULL) {
1106 jint result = (*env)->IsInstanceOf(env, object, cls);
1107 (*env)->DeleteLocalRef(env, cls);
1108 return result;
1109 }
1110 return JNI_ERR;
1111}
1112
1113JNIEXPORT jboolean JNICALL
1114JNU_Equals(JNIEnv *env, jobject object1, jobject object2)
1115{
1116 static jmethodID mid = NULL;
1117 if (mid == NULL) {
1118 jclass objClazz = JNU_ClassObject(env);
1119 CHECK_NULL_RETURN(objClazz, JNI_FALSE);
1120 mid = (*env)->GetMethodID(env, objClazz, "equals",
1121 "(Ljava/lang/Object;)Z");
1122 CHECK_NULL_RETURN(mid, JNI_FALSE);
1123 }
1124 return (*env)->CallBooleanMethod(env, object1, mid, object2);
1125}
1126
1127
1128/************************************************************************
1129 * Thread calls
1130 */
1131
1132static jmethodID Object_waitMID;
1133static jmethodID Object_notifyMID;
1134static jmethodID Object_notifyAllMID;
1135
1136JNIEXPORT void JNICALL
1137JNU_MonitorWait(JNIEnv *env, jobject object, jlong timeout)
1138{
1139 if (object == NULL) {
1140 JNU_ThrowNullPointerException(env, "JNU_MonitorWait argument");
1141 return;
1142 }
1143 if (Object_waitMID == NULL) {
1144 jclass cls = JNU_ClassObject(env);
1145 if (cls == NULL) {
1146 return;
1147 }
1148 Object_waitMID = (*env)->GetMethodID(env, cls, "wait", "(J)V");
1149 if (Object_waitMID == NULL) {
1150 return;
1151 }
1152 }
1153 (*env)->CallVoidMethod(env, object, Object_waitMID, timeout);
1154}
1155
1156JNIEXPORT void JNICALL
1157JNU_Notify(JNIEnv *env, jobject object)
1158{
1159 if (object == NULL) {
1160 JNU_ThrowNullPointerException(env, "JNU_Notify argument");
1161 return;
1162 }
1163 if (Object_notifyMID == NULL) {
1164 jclass cls = JNU_ClassObject(env);
1165 if (cls == NULL) {
1166 return;
1167 }
1168 Object_notifyMID = (*env)->GetMethodID(env, cls, "notify", "()V");
1169 if (Object_notifyMID == NULL) {
1170 return;
1171 }
1172 }
1173 (*env)->CallVoidMethod(env, object, Object_notifyMID);
1174}
1175
1176JNIEXPORT void JNICALL
1177JNU_NotifyAll(JNIEnv *env, jobject object)
1178{
1179 if (object == NULL) {
1180 JNU_ThrowNullPointerException(env, "JNU_NotifyAll argument");
1181 return;
1182 }
1183 if (Object_notifyAllMID == NULL) {
1184 jclass cls = JNU_ClassObject(env);
1185 if (cls == NULL) {
1186 return;
1187 }
1188 Object_notifyAllMID = (*env)->GetMethodID(env, cls,"notifyAll", "()V");
1189 if (Object_notifyAllMID == NULL) {
1190 return;
1191 }
1192 }
1193 (*env)->CallVoidMethod(env, object, Object_notifyAllMID);
1194}
1195
1196
1197/************************************************************************
1198 * Debugging utilities
1199 */
1200
1201JNIEXPORT void JNICALL
1202JNU_PrintString(JNIEnv *env, char *hdr, jstring string)
1203{
1204 if (string == NULL) {
1205 fprintf(stderr, "%s: is NULL\n", hdr);
1206 } else {
1207 const char *stringPtr = JNU_GetStringPlatformChars(env, string, 0);
1208 if (stringPtr == 0)
1209 return;
1210 fprintf(stderr, "%s: %s\n", hdr, stringPtr);
1211 JNU_ReleaseStringPlatformChars(env, string, stringPtr);
1212 }
1213}
1214
1215JNIEXPORT void JNICALL
1216JNU_PrintClass(JNIEnv *env, char* hdr, jobject object)
1217{
1218 if (object == NULL) {
1219 fprintf(stderr, "%s: object is NULL\n", hdr);
1220 return;
1221 } else {
1222 jclass cls = (*env)->GetObjectClass(env, object);
1223 jstring clsName = JNU_ToString(env, cls);
1224 if (clsName == NULL) {
1225 JNU_PrintString(env, hdr, clsName);
1226 }
1227 (*env)->DeleteLocalRef(env, cls);
1228 (*env)->DeleteLocalRef(env, clsName);
1229 }
1230}
1231
1232JNIEXPORT jstring JNICALL
1233JNU_ToString(JNIEnv *env, jobject object)
1234{
1235 if (object == NULL) {
1236 return (*env)->NewStringUTF(env, "NULL");
1237 } else {
1238 return (jstring)JNU_CallMethodByName(env,
1239 NULL,
1240 object,
1241 "toString",
1242 "()Ljava/lang/String;").l;
1243 }
1244}
1245
1246JNIEXPORT jvalue JNICALL
1247JNU_GetFieldByName(JNIEnv *env,
1248 jboolean *hasException,
1249 jobject obj,
1250 const char *name,
1251 const char *signature)
1252{
1253 jclass cls;
1254 jfieldID fid;
1255 jvalue result;
1256
1257 result.i = 0;
1258
1259 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
1260 goto done2;
1261
1262 cls = (*env)->GetObjectClass(env, obj);
1263 fid = (*env)->GetFieldID(env, cls, name, signature);
1264 if (fid == 0)
1265 goto done1;
1266
1267 switch (*signature) {
1268 case '[':
1269 case 'L':
1270 result.l = (*env)->GetObjectField(env, obj, fid);
1271 break;
1272 case 'Z':
1273 result.z = (*env)->GetBooleanField(env, obj, fid);
1274 break;
1275 case 'B':
1276 result.b = (*env)->GetByteField(env, obj, fid);
1277 break;
1278 case 'C':
1279 result.c = (*env)->GetCharField(env, obj, fid);
1280 break;
1281 case 'S':
1282 result.s = (*env)->GetShortField(env, obj, fid);
1283 break;
1284 case 'I':
1285 result.i = (*env)->GetIntField(env, obj, fid);
1286 break;
1287 case 'J':
1288 result.j = (*env)->GetLongField(env, obj, fid);
1289 break;
1290 case 'F':
1291 result.f = (*env)->GetFloatField(env, obj, fid);
1292 break;
1293 case 'D':
1294 result.d = (*env)->GetDoubleField(env, obj, fid);
1295 break;
1296
1297 default:
1298 (*env)->FatalError(env, "JNU_GetFieldByName: illegal signature");
1299 }
1300
1301 done1:
1302 (*env)->DeleteLocalRef(env, cls);
1303 done2:
1304 if (hasException) {
1305 *hasException = (*env)->ExceptionCheck(env);
1306 }
1307 return result;
1308}
1309
1310JNIEXPORT void JNICALL
1311JNU_SetFieldByName(JNIEnv *env,
1312 jboolean *hasException,
1313 jobject obj,
1314 const char *name,
1315 const char *signature,
1316 ...)
1317{
1318 jclass cls;
1319 jfieldID fid;
1320 va_list args;
1321
1322 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
1323 goto done2;
1324
1325 cls = (*env)->GetObjectClass(env, obj);
1326 fid = (*env)->GetFieldID(env, cls, name, signature);
1327 if (fid == 0)
1328 goto done1;
1329
1330 va_start(args, signature);
1331 switch (*signature) {
1332 case '[':
1333 case 'L':
1334 (*env)->SetObjectField(env, obj, fid, va_arg(args, jobject));
1335 break;
1336 case 'Z':
1337 (*env)->SetBooleanField(env, obj, fid, (jboolean)va_arg(args, int));
1338 break;
1339 case 'B':
1340 (*env)->SetByteField(env, obj, fid, (jbyte)va_arg(args, int));
1341 break;
1342 case 'C':
1343 (*env)->SetCharField(env, obj, fid, (jchar)va_arg(args, int));
1344 break;
1345 case 'S':
1346 (*env)->SetShortField(env, obj, fid, (jshort)va_arg(args, int));
1347 break;
1348 case 'I':
1349 (*env)->SetIntField(env, obj, fid, va_arg(args, jint));
1350 break;
1351 case 'J':
1352 (*env)->SetLongField(env, obj, fid, va_arg(args, jlong));
1353 break;
1354 case 'F':
1355 (*env)->SetFloatField(env, obj, fid, (jfloat)va_arg(args, jdouble));
1356 break;
1357 case 'D':
1358 (*env)->SetDoubleField(env, obj, fid, va_arg(args, jdouble));
1359 break;
1360
1361 default:
1362 (*env)->FatalError(env, "JNU_SetFieldByName: illegal signature");
1363 }
1364 va_end(args);
1365
1366 done1:
1367 (*env)->DeleteLocalRef(env, cls);
1368 done2:
1369 if (hasException) {
1370 *hasException = (*env)->ExceptionCheck(env);
1371 }
1372}
1373
1374JNIEXPORT jvalue JNICALL
1375JNU_GetStaticFieldByName(JNIEnv *env,
1376 jboolean *hasException,
1377 const char *classname,
1378 const char *name,
1379 const char *signature)
1380{
1381 jclass cls;
1382 jfieldID fid;
1383 jvalue result;
1384
1385 result.i = 0;
1386
1387 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
1388 goto done2;
1389
1390 cls = (*env)->FindClass(env, classname);
1391 if (cls == 0)
1392 goto done2;
1393
1394 fid = (*env)->GetStaticFieldID(env, cls, name, signature);
1395 if (fid == 0)
1396 goto done1;
1397
1398 switch (*signature) {
1399 case '[':
1400 case 'L':
1401 result.l = (*env)->GetStaticObjectField(env, cls, fid);
1402 break;
1403 case 'Z':
1404 result.z = (*env)->GetStaticBooleanField(env, cls, fid);
1405 break;
1406 case 'B':
1407 result.b = (*env)->GetStaticByteField(env, cls, fid);
1408 break;
1409 case 'C':
1410 result.c = (*env)->GetStaticCharField(env, cls, fid);
1411 break;
1412 case 'S':
1413 result.s = (*env)->GetStaticShortField(env, cls, fid);
1414 break;
1415 case 'I':
1416 result.i = (*env)->GetStaticIntField(env, cls, fid);
1417 break;
1418 case 'J':
1419 result.j = (*env)->GetStaticLongField(env, cls, fid);
1420 break;
1421 case 'F':
1422 result.f = (*env)->GetStaticFloatField(env, cls, fid);
1423 break;
1424 case 'D':
1425 result.d = (*env)->GetStaticDoubleField(env, cls, fid);
1426 break;
1427
1428 default:
1429 (*env)->FatalError(env, "JNU_GetStaticFieldByName: illegal signature");
1430 }
1431
1432 done1:
1433 (*env)->DeleteLocalRef(env, cls);
1434 done2:
1435 if (hasException) {
1436 *hasException = (*env)->ExceptionCheck(env);
1437 }
1438 return result;
1439}
1440
1441JNIEXPORT void JNICALL
1442JNU_SetStaticFieldByName(JNIEnv *env,
1443 jboolean *hasException,
1444 const char *classname,
1445 const char *name,
1446 const char *signature,
1447 ...)
1448{
1449 jclass cls;
1450 jfieldID fid;
1451 va_list args;
1452
1453 if ((*env)->EnsureLocalCapacity(env, 3) < 0)
1454 goto done2;
1455
1456 cls = (*env)->FindClass(env, classname);
1457 if (cls == 0)
1458 goto done2;
1459
1460 fid = (*env)->GetStaticFieldID(env, cls, name, signature);
1461 if (fid == 0)
1462 goto done1;
1463
1464 va_start(args, signature);
1465 switch (*signature) {
1466 case '[':
1467 case 'L':
1468 (*env)->SetStaticObjectField(env, cls, fid, va_arg(args, jobject));
1469 break;
1470 case 'Z':
1471 (*env)->SetStaticBooleanField(env, cls, fid, (jboolean)va_arg(args, int));
1472 break;
1473 case 'B':
1474 (*env)->SetStaticByteField(env, cls, fid, (jbyte)va_arg(args, int));
1475 break;
1476 case 'C':
1477 (*env)->SetStaticCharField(env, cls, fid, (jchar)va_arg(args, int));
1478 break;
1479 case 'S':
1480 (*env)->SetStaticShortField(env, cls, fid, (jshort)va_arg(args, int));
1481 break;
1482 case 'I':
1483 (*env)->SetStaticIntField(env, cls, fid, va_arg(args, jint));
1484 break;
1485 case 'J':
1486 (*env)->SetStaticLongField(env, cls, fid, va_arg(args, jlong));
1487 break;
1488 case 'F':
1489 (*env)->SetStaticFloatField(env, cls, fid, (jfloat)va_arg(args, jdouble));
1490 break;
1491 case 'D':
1492 (*env)->SetStaticDoubleField(env, cls, fid, va_arg(args, jdouble));
1493 break;
1494
1495 default:
1496 (*env)->FatalError(env, "JNU_SetStaticFieldByName: illegal signature");
1497 }
1498 va_end(args);
1499
1500 done1:
1501 (*env)->DeleteLocalRef(env, cls);
1502 done2:
1503 if (hasException) {
1504 *hasException = (*env)->ExceptionCheck(env);
1505 }
1506}
1507