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