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