Path: blob/master/src/java.base/share/native/libjava/jni_util.c
41149 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdlib.h>26#include <string.h>2728#include "jvm.h"29#include "jni.h"30#include "jni_util.h"31#include "java_lang_String.h"3233/* Due to a bug in the win32 C runtime library strings34* such as "z:" need to be appended with a "." so we35* must allocate at least 4 bytes to allow room for36* this expansion. See 4235353 for details.37*/38#define MALLOC_MIN4(len) ((char *)malloc((len) + 1 < 4 ? 4 : (len) + 1))3940/**41* Throw a Java exception by name. Similar to SignalError.42*/43JNIEXPORT void JNICALL44JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg)45{46jclass cls = (*env)->FindClass(env, name);4748if (cls != 0) /* Otherwise an exception has already been thrown */49(*env)->ThrowNew(env, cls, msg);50}5152/* JNU_Throw common exceptions */5354JNIEXPORT void JNICALL55JNU_ThrowNullPointerException(JNIEnv *env, const char *msg)56{57JNU_ThrowByName(env, "java/lang/NullPointerException", msg);58}5960JNIEXPORT void JNICALL61JNU_ThrowArrayIndexOutOfBoundsException(JNIEnv *env, const char *msg)62{63JNU_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", msg);64}6566JNIEXPORT void JNICALL67JNU_ThrowOutOfMemoryError(JNIEnv *env, const char *msg)68{69JNU_ThrowByName(env, "java/lang/OutOfMemoryError", msg);70}7172JNIEXPORT void JNICALL73JNU_ThrowIllegalArgumentException(JNIEnv *env, const char *msg)74{75JNU_ThrowByName(env, "java/lang/IllegalArgumentException", msg);76}7778JNIEXPORT void JNICALL79JNU_ThrowInternalError(JNIEnv *env, const char *msg)80{81JNU_ThrowByName(env, "java/lang/InternalError", msg);82}8384JNIEXPORT void JNICALL85JNU_ThrowClassNotFoundException(JNIEnv *env, const char *msg)86{87JNU_ThrowByName(env, "java/lang/ClassNotFoundException", msg);88}8990JNIEXPORT void JNICALL91JNU_ThrowIOException(JNIEnv *env, const char *msg)92{93JNU_ThrowByName(env, "java/io/IOException", msg);94}9596/*97* Throw an exception by name, using the string returned by98* getLastErrorString for the detail string. If the last-error99* string is NULL, use the given default detail string.100*/101JNIEXPORT void JNICALL102JNU_ThrowByNameWithLastError(JNIEnv *env, const char *name,103const char *defaultDetail)104{105char buf[256];106size_t n = getLastErrorString(buf, sizeof(buf));107108if (n > 0) {109jstring s = JNU_NewStringPlatform(env, buf);110if (s != NULL) {111jobject x = JNU_NewObjectByName(env, name,112"(Ljava/lang/String;)V", s);113if (x != NULL) {114(*env)->Throw(env, x);115}116}117}118if (!(*env)->ExceptionOccurred(env)) {119JNU_ThrowByName(env, name, defaultDetail);120}121}122123/*124* Throw an exception by name, using a given message and the string125* returned by getLastErrorString to construct the detail string.126*/127JNIEXPORT void JNICALL128JNU_ThrowByNameWithMessageAndLastError129(JNIEnv *env, const char *name, const char *message)130{131char buf[256];132size_t n = getLastErrorString(buf, sizeof(buf));133size_t messagelen = message == NULL ? 0 : strlen(message);134135if (n > 0) {136jstring s = JNU_NewStringPlatform(env, buf);137if (s != NULL) {138jobject x = NULL;139if (messagelen) {140jstring s2 = NULL;141size_t messageextlen = messagelen + 4;142char *str1 = (char *)malloc((messageextlen) * sizeof(char));143if (str1 == 0) {144JNU_ThrowOutOfMemoryError(env, 0);145return;146}147jio_snprintf(str1, messageextlen, " (%s)", message);148s2 = (*env)->NewStringUTF(env, str1);149free(str1);150JNU_CHECK_EXCEPTION(env);151if (s2 != NULL) {152jstring s3 = JNU_CallMethodByName(153env, NULL, s, "concat",154"(Ljava/lang/String;)Ljava/lang/String;",155s2).l;156(*env)->DeleteLocalRef(env, s2);157JNU_CHECK_EXCEPTION(env);158if (s3 != NULL) {159(*env)->DeleteLocalRef(env, s);160s = s3;161}162}163}164x = JNU_NewObjectByName(env, name, "(Ljava/lang/String;)V", s);165if (x != NULL) {166(*env)->Throw(env, x);167}168}169}170171if (!(*env)->ExceptionOccurred(env)) {172if (messagelen) {173JNU_ThrowByName(env, name, message);174} else {175JNU_ThrowByName(env, name, "no further information");176}177}178}179180/*181* Convenience method.182* Call JNU_ThrowByNameWithLastError for java.io.IOException.183*/184JNIEXPORT void JNICALL185JNU_ThrowIOExceptionWithLastError(JNIEnv *env, const char *defaultDetail)186{187JNU_ThrowByNameWithLastError(env, "java/io/IOException", defaultDetail);188}189190191JNIEXPORT jvalue JNICALL192JNU_CallStaticMethodByName(JNIEnv *env,193jboolean *hasException,194const char *class_name,195const char *name,196const char *signature,197...)198{199jclass clazz;200jmethodID mid;201va_list args;202jvalue result;203const char *p = signature;204205/* find out the return type */206while (*p && *p != ')')207p++;208p++;209210result.i = 0;211212if ((*env)->EnsureLocalCapacity(env, 3) < 0)213goto done2;214215clazz = (*env)->FindClass(env, class_name);216if (clazz == 0)217goto done2;218mid = (*env)->GetStaticMethodID(env, clazz, name, signature);219if (mid == 0)220goto done1;221va_start(args, signature);222switch (*p) {223case 'V':224(*env)->CallStaticVoidMethodV(env, clazz, mid, args);225break;226case '[':227case 'L':228result.l = (*env)->CallStaticObjectMethodV(env, clazz, mid, args);229break;230case 'Z':231result.z = (*env)->CallStaticBooleanMethodV(env, clazz, mid, args);232break;233case 'B':234result.b = (*env)->CallStaticByteMethodV(env, clazz, mid, args);235break;236case 'C':237result.c = (*env)->CallStaticCharMethodV(env, clazz, mid, args);238break;239case 'S':240result.s = (*env)->CallStaticShortMethodV(env, clazz, mid, args);241break;242case 'I':243result.i = (*env)->CallStaticIntMethodV(env, clazz, mid, args);244break;245case 'J':246result.j = (*env)->CallStaticLongMethodV(env, clazz, mid, args);247break;248case 'F':249result.f = (*env)->CallStaticFloatMethodV(env, clazz, mid, args);250break;251case 'D':252result.d = (*env)->CallStaticDoubleMethodV(env, clazz, mid, args);253break;254default:255(*env)->FatalError(env, "JNU_CallStaticMethodByName: illegal signature");256}257va_end(args);258259done1:260(*env)->DeleteLocalRef(env, clazz);261done2:262if (hasException) {263*hasException = (*env)->ExceptionCheck(env);264}265return result;266}267268JNIEXPORT jvalue JNICALL269JNU_CallMethodByName(JNIEnv *env,270jboolean *hasException,271jobject obj,272const char *name,273const char *signature,274...)275{276jvalue result;277va_list args;278279va_start(args, signature);280result = JNU_CallMethodByNameV(env, hasException, obj, name, signature,281args);282va_end(args);283284return result;285}286287288JNIEXPORT jvalue JNICALL289JNU_CallMethodByNameV(JNIEnv *env,290jboolean *hasException,291jobject obj,292const char *name,293const char *signature,294va_list args)295{296jclass clazz;297jmethodID mid;298jvalue result;299const char *p = signature;300301/* find out the return type */302while (*p && *p != ')')303p++;304p++;305306result.i = 0;307308if ((*env)->EnsureLocalCapacity(env, 3) < 0)309goto done2;310311clazz = (*env)->GetObjectClass(env, obj);312mid = (*env)->GetMethodID(env, clazz, name, signature);313if (mid == 0)314goto done1;315316switch (*p) {317case 'V':318(*env)->CallVoidMethodV(env, obj, mid, args);319break;320case '[':321case 'L':322result.l = (*env)->CallObjectMethodV(env, obj, mid, args);323break;324case 'Z':325result.z = (*env)->CallBooleanMethodV(env, obj, mid, args);326break;327case 'B':328result.b = (*env)->CallByteMethodV(env, obj, mid, args);329break;330case 'C':331result.c = (*env)->CallCharMethodV(env, obj, mid, args);332break;333case 'S':334result.s = (*env)->CallShortMethodV(env, obj, mid, args);335break;336case 'I':337result.i = (*env)->CallIntMethodV(env, obj, mid, args);338break;339case 'J':340result.j = (*env)->CallLongMethodV(env, obj, mid, args);341break;342case 'F':343result.f = (*env)->CallFloatMethodV(env, obj, mid, args);344break;345case 'D':346result.d = (*env)->CallDoubleMethodV(env, obj, mid, args);347break;348default:349(*env)->FatalError(env, "JNU_CallMethodByNameV: illegal signature");350}351done1:352(*env)->DeleteLocalRef(env, clazz);353done2:354if (hasException) {355*hasException = (*env)->ExceptionCheck(env);356}357return result;358}359360JNIEXPORT jobject JNICALL361JNU_NewObjectByName(JNIEnv *env, const char *class_name,362const char *constructor_sig, ...)363{364jobject obj = NULL;365366jclass cls = 0;367jmethodID cls_initMID;368va_list args;369370if ((*env)->EnsureLocalCapacity(env, 2) < 0)371goto done;372373cls = (*env)->FindClass(env, class_name);374if (cls == 0) {375goto done;376}377cls_initMID = (*env)->GetMethodID(env, cls,378"<init>", constructor_sig);379if (cls_initMID == NULL) {380goto done;381}382va_start(args, constructor_sig);383obj = (*env)->NewObjectV(env, cls, cls_initMID, args);384va_end(args);385386done:387(*env)->DeleteLocalRef(env, cls);388return obj;389}390391/* Optimized for charset ISO_8559_1 */392static jstring393newSizedString8859_1(JNIEnv *env, const char *str, const int len)394{395jchar buf[512];396jchar *str1;397jstring result;398int i;399400if ((*env)->EnsureLocalCapacity(env, 1) < 0)401return NULL;402403if (len > 512) {404str1 = (jchar *)malloc(len * sizeof(jchar));405if (str1 == 0) {406JNU_ThrowOutOfMemoryError(env, 0);407return 0;408}409} else410str1 = buf;411412for (i=0;i<len;i++)413str1[i] = (unsigned char)str[i];414result = (*env)->NewString(env, str1, len);415if (str1 != buf)416free(str1);417return result;418}419420static jstring421newString8859_1(JNIEnv *env, const char *str)422{423int len = (int)strlen(str);424return newSizedString8859_1(env, str, len);425}426427static const char*428getString8859_1Chars(JNIEnv *env, jstring jstr)429{430int i;431char *result;432jint len = (*env)->GetStringLength(env, jstr);433const jchar *str = (*env)->GetStringCritical(env, jstr, 0);434if (str == 0) {435return 0;436}437438result = MALLOC_MIN4(len);439if (result == 0) {440(*env)->ReleaseStringCritical(env, jstr, str);441JNU_ThrowOutOfMemoryError(env, 0);442return 0;443}444445for (i=0; i<len; i++) {446jchar unicode = str[i];447if (unicode <= 0x00ff)448result[i] = (char)unicode;449else450result[i] = '?';451}452453result[len] = 0;454(*env)->ReleaseStringCritical(env, jstr, str);455return result;456}457458459/* Optimized for charset ISO646-US (us-ascii) */460static jstring461newString646_US(JNIEnv *env, const char *str)462{463int len = (int)strlen(str);464jchar buf[512] = {0};465jchar *str1;466jstring result;467int i;468469if (len > 512) {470str1 = (jchar *)malloc(len * sizeof(jchar));471if (str1 == 0) {472JNU_ThrowOutOfMemoryError(env, 0);473return 0;474}475} else476str1 = buf;477478for (i=0; i<len; i++) {479unsigned char c = (unsigned char)str[i];480if (c <= 0x7f)481str1[i] = c;482else483str1[i] = '?';484}485486result = (*env)->NewString(env, str1, len);487if (str1 != buf)488free(str1);489return result;490}491492static const char*493getString646_USChars(JNIEnv *env, jstring jstr)494{495int i;496char *result;497jint len = (*env)->GetStringLength(env, jstr);498const jchar *str = (*env)->GetStringCritical(env, jstr, 0);499if (str == 0) {500return 0;501}502503result = MALLOC_MIN4(len);504if (result == 0) {505(*env)->ReleaseStringCritical(env, jstr, str);506JNU_ThrowOutOfMemoryError(env, 0);507return 0;508}509510for (i=0; i<len; i++) {511jchar unicode = str[i];512if (unicode <= 0x007f )513result[i] = (char)unicode;514else515result[i] = '?';516}517518result[len] = 0;519(*env)->ReleaseStringCritical(env, jstr, str);520return result;521}522523/* enumeration of c1 row from Cp1252 */524static int cp1252c1chars[32] = {5250x20AC,0xFFFD,0x201A,0x0192,0x201E,0x2026,0x2020,0x2021,5260x02C6,0x2030,0x0160,0x2039,0x0152,0xFFFD,0x017D,0xFFFD,5270xFFFD,0x2018,0x2019,0x201C,0x201D,0x2022,0x2013,0x2014,5280x02Dc,0x2122,0x0161,0x203A,0x0153,0xFFFD,0x017E,0x0178529};530531/* Optimized for charset Cp1252 */532static jstring533newStringCp1252(JNIEnv *env, const char *str)534{535int len = (int) strlen(str);536jchar buf[512];537jchar *str1;538jstring result;539int i;540541if ((*env)->EnsureLocalCapacity(env, 1) < 0)542return NULL;543544if (len > 512) {545str1 = (jchar *)malloc(len * sizeof(jchar));546if (str1 == 0) {547JNU_ThrowOutOfMemoryError(env, 0);548return 0;549}550} else551str1 = buf;552553for (i=0; i<len; i++) {554unsigned char c = (unsigned char)str[i];555if ((c >= 0x80) && (c <= 0x9f))556str1[i] = cp1252c1chars[c-128];557else558str1[i] = c;559}560561result = (*env)->NewString(env, str1, len);562if (str1 != buf)563free(str1);564return result;565}566567static const char*568getStringCp1252Chars(JNIEnv *env, jstring jstr)569{570int i;571char *result;572jint len = (*env)->GetStringLength(env, jstr);573const jchar *str = (*env)->GetStringCritical(env, jstr, 0);574if (str == 0) {575return 0;576}577578result = MALLOC_MIN4(len);579if (result == 0) {580(*env)->ReleaseStringCritical(env, jstr, str);581JNU_ThrowOutOfMemoryError(env, 0);582return 0;583}584585for (i=0; i<len; i++) {586jchar c = str[i];587if (c < 256) {588if ((c >= 0x80) && (c <= 0x9f)) {589result[i] = '?';590} else {591result[i] = (char)c;592}593} else switch(c) {594case 0x20AC: result[i] = (char)0x80; break;595case 0x201A: result[i] = (char)0x82; break;596case 0x0192: result[i] = (char)0x83; break;597case 0x201E: result[i] = (char)0x84; break;598case 0x2026: result[i] = (char)0x85; break;599case 0x2020: result[i] = (char)0x86; break;600case 0x2021: result[i] = (char)0x87; break;601case 0x02C6: result[i] = (char)0x88; break;602case 0x2030: result[i] = (char)0x89; break;603case 0x0160: result[i] = (char)0x8A; break;604case 0x2039: result[i] = (char)0x8B; break;605case 0x0152: result[i] = (char)0x8C; break;606case 0x017D: result[i] = (char)0x8E; break;607case 0x2018: result[i] = (char)0x91; break;608case 0x2019: result[i] = (char)0x92; break;609case 0x201C: result[i] = (char)0x93; break;610case 0x201D: result[i] = (char)0x94; break;611case 0x2022: result[i] = (char)0x95; break;612case 0x2013: result[i] = (char)0x96; break;613case 0x2014: result[i] = (char)0x97; break;614case 0x02DC: result[i] = (char)0x98; break;615case 0x2122: result[i] = (char)0x99; break;616case 0x0161: result[i] = (char)0x9A; break;617case 0x203A: result[i] = (char)0x9B; break;618case 0x0153: result[i] = (char)0x9C; break;619case 0x017E: result[i] = (char)0x9E; break;620case 0x0178: result[i] = (char)0x9F; break;621default: result[i] = '?'; break;622}623}624625result[len] = 0;626(*env)->ReleaseStringCritical(env, jstr, str);627return result;628}629630static int fastEncoding = NO_ENCODING_YET;631static jstring jnuEncoding = NULL;632633/* Cached method IDs */634static jmethodID String_init_ID; /* String(byte[], enc) */635static jmethodID String_getBytes_ID; /* String.getBytes(enc) */636637/* Cached field IDs */638static jfieldID String_coder_ID; /* String.coder */639static jfieldID String_value_ID; /* String.value */640641static jboolean isJNUEncodingSupported = JNI_FALSE;642static jboolean jnuEncodingSupported(JNIEnv *env) {643jboolean exe;644if (isJNUEncodingSupported == JNI_TRUE) {645return JNI_TRUE;646}647isJNUEncodingSupported = (jboolean) JNU_CallStaticMethodByName (648env, &exe,649"java/nio/charset/Charset",650"isSupported",651"(Ljava/lang/String;)Z",652jnuEncoding).z;653return isJNUEncodingSupported;654}655656/* Create a new string by converting str to a heap-allocated byte array and657* calling the appropriate String constructor.658*/659static jstring660newSizedStringJava(JNIEnv *env, const char *str, const int len)661{662jstring result = NULL;663jbyteArray bytes = 0;664665if ((*env)->EnsureLocalCapacity(env, 2) < 0)666return NULL;667668bytes = (*env)->NewByteArray(env, len);669if (bytes != NULL) {670jclass strClazz = JNU_ClassString(env);671CHECK_NULL_RETURN(strClazz, 0);672(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *)str);673if (jnuEncodingSupported(env)) {674result = (*env)->NewObject(env, strClazz,675String_init_ID, bytes, jnuEncoding);676} else {677/*If the encoding specified in sun.jnu.encoding is not endorsed678by "Charset.isSupported" we have to fall back to use String(byte[])679explicitly here without specifying the encoding name, in which the680StringCoding class will pickup the iso-8859-1 as the fallback681converter for us.682*/683jmethodID mid = (*env)->GetMethodID(env, strClazz,684"<init>", "([B)V");685if (mid != NULL) {686result = (*env)->NewObject(env, strClazz, mid, bytes);687}688}689(*env)->DeleteLocalRef(env, bytes);690return result;691}692return NULL;693}694695static jstring696newStringJava(JNIEnv *env, const char *str)697{698int len = (int)strlen(str);699return newSizedStringJava(env, str, len);700}701702/* Optimized for charset UTF-8 */703static jstring704newStringUTF8(JNIEnv *env, const char *str)705{706int len;707const unsigned char *p;708unsigned char asciiCheck;709for (asciiCheck = 0, p = (const unsigned char*)str; *p != '\0'; p++) {710asciiCheck |= *p;711}712len = (int)((const char*)p - str);713714if (asciiCheck < 0x80) {715// ascii fast-path716return newSizedString8859_1(env, str, len);717}718719return newSizedStringJava(env, str, len);720}721722/* Initialize the fast encoding from the encoding name.723* Export InitializeEncoding so that the VM can initialize it if required.724*/725JNIEXPORT void726InitializeEncoding(JNIEnv *env, const char *encname)727{728jclass strClazz = NULL;729730if ((*env)->EnsureLocalCapacity(env, 3) < 0)731return;732733strClazz = JNU_ClassString(env);734CHECK_NULL(strClazz);735736if (encname) {737/*738* On Solaris with nl_langinfo() called in GetJavaProperties():739*740* locale undefined -> NULL -> hardcoded default741* "C" locale -> "" -> hardcoded default (on 2.6)742* "C" locale -> "ISO646-US" (on Sol 7/8)743* "en_US" locale -> "ISO8859-1"744* "en_GB" locale -> "ISO8859-1" (on Sol 7/8)745* "en_UK" locale -> "ISO8859-1" (on 2.6)746*/747if ((strcmp(encname, "8859_1") == 0) ||748(strcmp(encname, "ISO8859-1") == 0) ||749(strcmp(encname, "ISO8859_1") == 0) ||750(strcmp(encname, "ISO-8859-1") == 0)) {751fastEncoding = FAST_8859_1;752} else if (strcmp(encname, "UTF-8") == 0) {753jstring enc = (*env)->NewStringUTF(env, encname);754if (enc == NULL)755return;756fastEncoding = FAST_UTF_8;757jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc);758(*env)->DeleteLocalRef(env, enc);759} else if (strcmp(encname, "ISO646-US") == 0) {760fastEncoding = FAST_646_US;761} else if (strcmp(encname, "Cp1252") == 0 ||762/* This is a temporary fix until we move */763/* to wide character versions of all Windows */764/* calls. */765strcmp(encname, "utf-16le") == 0) {766fastEncoding = FAST_CP1252;767} else {768jstring enc = (*env)->NewStringUTF(env, encname);769if (enc == NULL)770return;771fastEncoding = NO_FAST_ENCODING;772jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc);773(*env)->DeleteLocalRef(env, enc);774}775} else {776JNU_ThrowInternalError(env, "platform encoding undefined");777return;778}779780/* Initialize method-id cache */781String_getBytes_ID = (*env)->GetMethodID(env, strClazz,782"getBytes", "(Ljava/lang/String;)[B");783CHECK_NULL(String_getBytes_ID);784String_init_ID = (*env)->GetMethodID(env, strClazz,785"<init>", "([BLjava/lang/String;)V");786CHECK_NULL(String_init_ID);787String_coder_ID = (*env)->GetFieldID(env, strClazz, "coder", "B");788CHECK_NULL(String_coder_ID);789String_value_ID = (*env)->GetFieldID(env, strClazz, "value", "[B");790CHECK_NULL(String_value_ID);791}792793JNIEXPORT jstring JNICALL794JNU_NewStringPlatform(JNIEnv *env, const char *str)795{796if (fastEncoding == FAST_UTF_8)797return newStringUTF8(env, str);798if (fastEncoding == FAST_8859_1)799return newString8859_1(env, str);800if (fastEncoding == FAST_646_US)801return newString646_US(env, str);802if (fastEncoding == FAST_CP1252)803return newStringCp1252(env, str);804if (fastEncoding == NO_ENCODING_YET) {805JNU_ThrowInternalError(env, "platform encoding not initialized");806return NULL;807}808return newStringJava(env, str);809}810811JNIEXPORT const char *812GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)813{814return JNU_GetStringPlatformChars(env, jstr, isCopy);815}816817static const char* getStringBytes(JNIEnv *env, jstring jstr) {818char *result = NULL;819jbyteArray hab = 0;820821if ((*env)->EnsureLocalCapacity(env, 2) < 0)822return 0;823824if (jnuEncodingSupported(env)) {825hab = (*env)->CallObjectMethod(env, jstr, String_getBytes_ID, jnuEncoding);826} else {827jmethodID mid;828jclass strClazz = JNU_ClassString(env);829CHECK_NULL_RETURN(strClazz, 0);830mid = (*env)->GetMethodID(env, strClazz,831"getBytes", "()[B");832if (mid != NULL) {833hab = (*env)->CallObjectMethod(env, jstr, mid);834}835}836837if (!(*env)->ExceptionCheck(env)) {838jint len = (*env)->GetArrayLength(env, hab);839result = MALLOC_MIN4(len);840if (result == 0) {841JNU_ThrowOutOfMemoryError(env, 0);842(*env)->DeleteLocalRef(env, hab);843return 0;844}845(*env)->GetByteArrayRegion(env, hab, 0, len, (jbyte *)result);846result[len] = 0; /* NULL-terminate */847}848849(*env)->DeleteLocalRef(env, hab);850return result;851}852853static const char*854getStringUTF8(JNIEnv *env, jstring jstr)855{856int i;857char *result;858jbyteArray value;859jint len;860jbyte *str;861jint rlen;862int ri;863jbyte coder = (*env)->GetByteField(env, jstr, String_coder_ID);864if (coder != java_lang_String_LATIN1) {865return getStringBytes(env, jstr);866}867if ((*env)->EnsureLocalCapacity(env, 2) < 0) {868return NULL;869}870value = (*env)->GetObjectField(env, jstr, String_value_ID);871if (value == NULL)872return NULL;873len = (*env)->GetArrayLength(env, value);874str = (*env)->GetPrimitiveArrayCritical(env, value, NULL);875if (str == NULL) {876return NULL;877}878879rlen = len;880// we need two bytes for each latin-1 char above 127 (negative jbytes)881for (i = 0; i < len; i++) {882if (str[i] < 0) {883rlen++;884}885}886887result = MALLOC_MIN4(rlen);888if (result == NULL) {889(*env)->ReleasePrimitiveArrayCritical(env, value, str, 0);890JNU_ThrowOutOfMemoryError(env, 0);891return NULL;892}893894for (ri = 0, i = 0; i < len; i++) {895jbyte c = str[i];896if (c < 0) {897result[ri++] = (char)(0xc0 | ((c & 0xff) >> 6));898result[ri++] = (char)(0x80 | (c & 0x3f));899} else {900result[ri++] = c;901}902}903(*env)->ReleasePrimitiveArrayCritical(env, value, str, 0);904result[rlen] = '\0';905return result;906}907908JNIEXPORT const char * JNICALL909JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)910{911912if (isCopy)913*isCopy = JNI_TRUE;914915if (fastEncoding == FAST_UTF_8)916return getStringUTF8(env, jstr);917if (fastEncoding == FAST_8859_1)918return getString8859_1Chars(env, jstr);919if (fastEncoding == FAST_646_US)920return getString646_USChars(env, jstr);921if (fastEncoding == FAST_CP1252)922return getStringCp1252Chars(env, jstr);923if (fastEncoding == NO_ENCODING_YET) {924JNU_ThrowInternalError(env, "platform encoding not initialized");925return 0;926} else927return getStringBytes(env, jstr);928}929930JNIEXPORT void JNICALL931JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str)932{933free((void *)str);934}935936JNIEXPORT jclass JNICALL937JNU_ClassString(JNIEnv *env)938{939static jclass cls = 0;940if (cls == 0) {941jclass c;942if ((*env)->EnsureLocalCapacity(env, 1) < 0)943return 0;944c = (*env)->FindClass(env, "java/lang/String");945CHECK_NULL_RETURN(c, NULL);946cls = (*env)->NewGlobalRef(env, c);947(*env)->DeleteLocalRef(env, c);948}949return cls;950}951952JNIEXPORT jint JNICALL953JNU_CopyObjectArray(JNIEnv *env, jobjectArray dst, jobjectArray src,954jint count)955{956int i;957if ((*env)->EnsureLocalCapacity(env, 1) < 0)958return -1;959for (i=0; i<count; i++) {960jstring p = (*env)->GetObjectArrayElement(env, src, i);961(*env)->SetObjectArrayElement(env, dst, i, p);962(*env)->DeleteLocalRef(env, p);963}964return 0;965}966967JNIEXPORT void * JNICALL968JNU_GetEnv(JavaVM *vm, jint version)969{970void *env;971(*vm)->GetEnv(vm, &env, version);972return env;973}974975JNIEXPORT jint JNICALL976JNU_IsInstanceOfByName(JNIEnv *env, jobject object, const char* classname)977{978jclass cls;979if ((*env)->EnsureLocalCapacity(env, 1) < 0)980return JNI_ERR;981cls = (*env)->FindClass(env, classname);982if (cls != NULL) {983jint result = (*env)->IsInstanceOf(env, object, cls);984(*env)->DeleteLocalRef(env, cls);985return result;986}987return JNI_ERR;988}989990/************************************************************************991* Debugging utilities992*/993994JNIEXPORT jstring JNICALL995JNU_ToString(JNIEnv *env, jobject object)996{997if (object == NULL) {998return (*env)->NewStringUTF(env, "NULL");999} else {1000return (jstring)JNU_CallMethodByName(env,1001NULL,1002object,1003"toString",1004"()Ljava/lang/String;").l;1005}1006}10071008JNIEXPORT jvalue JNICALL1009JNU_GetFieldByName(JNIEnv *env,1010jboolean *hasException,1011jobject obj,1012const char *name,1013const char *signature)1014{1015jclass cls;1016jfieldID fid;1017jvalue result;10181019result.i = 0;10201021if ((*env)->EnsureLocalCapacity(env, 3) < 0)1022goto done2;10231024cls = (*env)->GetObjectClass(env, obj);1025fid = (*env)->GetFieldID(env, cls, name, signature);1026if (fid == 0)1027goto done1;10281029switch (*signature) {1030case '[':1031case 'L':1032result.l = (*env)->GetObjectField(env, obj, fid);1033break;1034case 'Z':1035result.z = (*env)->GetBooleanField(env, obj, fid);1036break;1037case 'B':1038result.b = (*env)->GetByteField(env, obj, fid);1039break;1040case 'C':1041result.c = (*env)->GetCharField(env, obj, fid);1042break;1043case 'S':1044result.s = (*env)->GetShortField(env, obj, fid);1045break;1046case 'I':1047result.i = (*env)->GetIntField(env, obj, fid);1048break;1049case 'J':1050result.j = (*env)->GetLongField(env, obj, fid);1051break;1052case 'F':1053result.f = (*env)->GetFloatField(env, obj, fid);1054break;1055case 'D':1056result.d = (*env)->GetDoubleField(env, obj, fid);1057break;10581059default:1060(*env)->FatalError(env, "JNU_GetFieldByName: illegal signature");1061}10621063done1:1064(*env)->DeleteLocalRef(env, cls);1065done2:1066if (hasException) {1067*hasException = (*env)->ExceptionCheck(env);1068}1069return result;1070}10711072JNIEXPORT void JNICALL1073JNU_SetFieldByName(JNIEnv *env,1074jboolean *hasException,1075jobject obj,1076const char *name,1077const char *signature,1078...)1079{1080jclass cls;1081jfieldID fid;1082va_list args;10831084if ((*env)->EnsureLocalCapacity(env, 3) < 0)1085goto done2;10861087cls = (*env)->GetObjectClass(env, obj);1088fid = (*env)->GetFieldID(env, cls, name, signature);1089if (fid == 0)1090goto done1;10911092va_start(args, signature);1093switch (*signature) {1094case '[':1095case 'L':1096(*env)->SetObjectField(env, obj, fid, va_arg(args, jobject));1097break;1098case 'Z':1099(*env)->SetBooleanField(env, obj, fid, (jboolean)va_arg(args, int));1100break;1101case 'B':1102(*env)->SetByteField(env, obj, fid, (jbyte)va_arg(args, int));1103break;1104case 'C':1105(*env)->SetCharField(env, obj, fid, (jchar)va_arg(args, int));1106break;1107case 'S':1108(*env)->SetShortField(env, obj, fid, (jshort)va_arg(args, int));1109break;1110case 'I':1111(*env)->SetIntField(env, obj, fid, va_arg(args, jint));1112break;1113case 'J':1114(*env)->SetLongField(env, obj, fid, va_arg(args, jlong));1115break;1116case 'F':1117(*env)->SetFloatField(env, obj, fid, (jfloat)va_arg(args, jdouble));1118break;1119case 'D':1120(*env)->SetDoubleField(env, obj, fid, va_arg(args, jdouble));1121break;11221123default:1124(*env)->FatalError(env, "JNU_SetFieldByName: illegal signature");1125}1126va_end(args);11271128done1:1129(*env)->DeleteLocalRef(env, cls);1130done2:1131if (hasException) {1132*hasException = (*env)->ExceptionCheck(env);1133}1134}11351136JNIEXPORT jvalue JNICALL1137JNU_GetStaticFieldByName(JNIEnv *env,1138jboolean *hasException,1139const char *classname,1140const char *name,1141const char *signature)1142{1143jclass cls;1144jfieldID fid;1145jvalue result;11461147result.i = 0;11481149if ((*env)->EnsureLocalCapacity(env, 3) < 0)1150goto done2;11511152cls = (*env)->FindClass(env, classname);1153if (cls == 0)1154goto done2;11551156fid = (*env)->GetStaticFieldID(env, cls, name, signature);1157if (fid == 0)1158goto done1;11591160switch (*signature) {1161case '[':1162case 'L':1163result.l = (*env)->GetStaticObjectField(env, cls, fid);1164break;1165case 'Z':1166result.z = (*env)->GetStaticBooleanField(env, cls, fid);1167break;1168case 'B':1169result.b = (*env)->GetStaticByteField(env, cls, fid);1170break;1171case 'C':1172result.c = (*env)->GetStaticCharField(env, cls, fid);1173break;1174case 'S':1175result.s = (*env)->GetStaticShortField(env, cls, fid);1176break;1177case 'I':1178result.i = (*env)->GetStaticIntField(env, cls, fid);1179break;1180case 'J':1181result.j = (*env)->GetStaticLongField(env, cls, fid);1182break;1183case 'F':1184result.f = (*env)->GetStaticFloatField(env, cls, fid);1185break;1186case 'D':1187result.d = (*env)->GetStaticDoubleField(env, cls, fid);1188break;11891190default:1191(*env)->FatalError(env, "JNU_GetStaticFieldByName: illegal signature");1192}11931194done1:1195(*env)->DeleteLocalRef(env, cls);1196done2:1197if (hasException) {1198*hasException = (*env)->ExceptionCheck(env);1199}1200return result;1201}120212031204