From f1e35a9d3aa12d7b964fc138141f3298aa22ade7 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 26 Aug 2024 16:24:44 +0200 Subject: [PATCH] Java bindings: make sure a valid UTF-8 string is passed to NewStringUTF() --- swig/include/java/typemaps_java.i | 91 ++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/swig/include/java/typemaps_java.i b/swig/include/java/typemaps_java.i index 4f41baf5631f..682995cd12fd 100644 --- a/swig/include/java/typemaps_java.i +++ b/swig/include/java/typemaps_java.i @@ -19,6 +19,45 @@ %include "arrays_java.i"; %include "typemaps.i" + +%fragment("SafeNewStringUTF8","header") +%{ +static jstring +SafeNewStringUTF8(JNIEnv *jenv, const char* pszInput) +{ + jstring ret = 0; + if (pszInput) + { + if( !CPLIsUTF8(pszInput, -1) ) + { + CPLError(CE_Warning, CPLE_AppDefined, + "A non-UTF8 string has been detected. Forcing it to ASCII"); + char* pszTmp = CPLUTF8ForceToASCII(pszInput, '_'); +#ifdef __cplusplus + ret = jenv->NewStringUTF(pszTmp); +#else + ret = (*jenv)->NewStringUTF(jenv, pszTmp); +#endif + CPLFree(pszTmp); + } + else + { +#ifdef __cplusplus + ret = jenv->NewStringUTF(pszInput); +#else + ret = (*jenv)->NewStringUTF(jenv, pszInput); +#endif + } + } + return ret; +} +%} + +// Overrides typemap defined in /usr/share/swig4.0/java.swg +%typemap(out, fragment="SafeNewStringUTF8", noblock=1) char * { + $result = SafeNewStringUTF8(jenv, (const char *)$1); +} + %apply (int) {VSI_RETVAL}; %typemap(javabody) SWIGTYPE %{ @@ -250,7 +289,7 @@ $2 = &pGCPs; } -%typemap(argout) (int *nGCPs, GDAL_GCP const **pGCPs ) +%typemap(argout, fragment="SafeNewStringUTF8") (int *nGCPs, GDAL_GCP const **pGCPs ) { /* %typemap(argout) (int *nGCPs, GDAL_GCP const **pGCPs ) */ const jclass GCPClass = jenv->FindClass("org/gdal/gdal/GCP"); @@ -261,8 +300,8 @@ int i; for (i=0; i<*$1; i++ ) { - jstring stringInfo = jenv->NewStringUTF((*$2)[i].pszInfo); - jstring stringId = jenv->NewStringUTF((*$2)[i].pszId); + jstring stringInfo = SafeNewStringUTF8(jenv, (*$2)[i].pszInfo); + jstring stringId = SafeNewStringUTF8(jenv, (*$2)[i].pszId); jobject GCPobj = jenv->NewObject(GCPClass, GCPcon, (*$2)[i].dfGCPX, (*$2)[i].dfGCPY, @@ -441,12 +480,12 @@ * Typemaps for (retStringAndCPLFree*) ***************************************************/ -%typemap(out) (retStringAndCPLFree*) +%typemap(out, fragment="SafeNewStringUTF8") (retStringAndCPLFree*) { /* %typemap(out) (retStringAndCPLFree*) */ if(result) { - $result = jenv->NewStringUTF((const char *)result); + $result = SafeNewStringUTF8(jenv, (const char *)result); CPLFree(result); } } @@ -1035,7 +1074,7 @@ } } -%fragment("GetCSLStringAsHashTable","header") +%fragment("GetCSLStringAsHashTable","header", fragment="SafeNewStringUTF8") %{ /* Convert a char array to a Hashtable */ static jobject @@ -1054,8 +1093,8 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { keyptr = CPLStrdup(*stringarray); keyptr[pszSep - *stringarray] = '\0'; valptr = pszSep + 1; - jstring name = jenv->NewStringUTF(keyptr); - jstring value = jenv->NewStringUTF(valptr); + jstring name = SafeNewStringUTF8(jenv, keyptr); + jstring value = SafeNewStringUTF8(jenv, valptr); jenv->CallObjectMethod(jHashtable, put, name, value); jenv->DeleteLocalRef(name); jenv->DeleteLocalRef(value); @@ -1151,7 +1190,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { CSLDestroy( $1 ); } -%typemap(out) char **options +%typemap(out, fragment="SafeNewStringUTF8") char **options { /* %typemap(out) char **options */ char **stringarray = $1; @@ -1162,8 +1201,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { $result = jenv->NewObject(vector, constructor); if ( stringarray != NULL ) { while(*stringarray != NULL) { - /*printf("working on string %s\n", *stringarray);*/ - jstring value = (jstring)jenv->NewStringUTF(*stringarray); + jstring value = SafeNewStringUTF8(jenv, *stringarray); jenv->CallBooleanMethod($result, add, value); jenv->DeleteLocalRef(value); stringarray++; @@ -1183,7 +1221,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { * Typemaps for retAsStringArrayNoFree ***************************************************/ -%typemap(out) char **retAsStringArrayNoFree +%typemap(out,fragment="SafeNewStringUTF8") char **retAsStringArrayNoFree { /* %typemap(out) char **retAsStringArrayNoFree */ char **stringarray = result; @@ -1196,7 +1234,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { /* exception checking omitted */ for (i=0; iNewStringUTF(*stringarray++); + temp_string = SafeNewStringUTF8(jenv, *stringarray++); jenv->SetObjectArrayElement(jresult, i, temp_string); jenv->DeleteLocalRef(temp_string); } @@ -1214,7 +1252,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { * Typemaps for retAsStringArrayNoFree ***************************************************/ -%typemap(out) char **retAsStringArrayAndFree +%typemap(out, fragment="SafeNewStringUTF8") char **retAsStringArrayAndFree { /* %typemap(out) char **retAsStringArrayAndFree */ char **stringarray = result; @@ -1227,7 +1265,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { /* exception checking omitted */ for (i=0; iNewStringUTF(*stringarray++); + temp_string = SafeNewStringUTF8(jenv, *stringarray++); jenv->SetObjectArrayElement(jresult, i, temp_string); jenv->DeleteLocalRef(temp_string); } @@ -1261,10 +1299,10 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { $1 = &ret; } -%typemap(argout) char **OUTPUT +%typemap(argout, fragment="SafeNewStringUTF8") char **OUTPUT { /* %typemap(argout) char **OUTPUT */ - jstring temp_string = jenv->NewStringUTF(ret$argnum); + jstring temp_string = SafeNewStringUTF8(jenv, ret$argnum); jenv->SetObjectArrayElement($input, 0, temp_string); jenv->DeleteLocalRef(temp_string); } @@ -1285,7 +1323,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { /* Almost same as %typemap(out) char **options */ /* but we CSLDestroy the char** pointer at the end */ -%typemap(out) char **CSL +%typemap(out, fragment="SafeNewStringUTF8") char **CSL { /* %typemap(out) char **CSL */ char **stringarray = $1; @@ -1296,8 +1334,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { $result = jenv->NewObject(vector, constructor); if ( stringarray != NULL ) { while(*stringarray != NULL) { - /*printf("working on string %s\n", *stringarray);*/ - jstring value = (jstring)jenv->NewStringUTF(*stringarray); + jstring value = SafeNewStringUTF8(jenv, *stringarray); jenv->CallBooleanMethod($result, add, value); jenv->DeleteLocalRef(value); stringarray++; @@ -1324,13 +1361,13 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { $1 = &argout; } -%typemap(argout) (char **argout) +%typemap(argout, fragment="SafeNewStringUTF8") (char **argout) { /* %typemap(argout) (char **argout) */ jstring temp_string; if($input != NULL && (int)jenv->GetArrayLength($input) >= 1) { - temp_string = jenv->NewStringUTF(argout$argnum); + temp_string = SafeNewStringUTF8(jenv, argout$argnum); jenv->SetObjectArrayElement($input, 0, temp_string); jenv->DeleteLocalRef(temp_string); } @@ -1497,7 +1534,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { /* This allows a C function to return a char ** as a Java String array */ -%typemap(out) char ** { +%typemap(out, fragment="SafeNewStringUTF8") char ** { /* %typemap(out) char ** */ int i; int len=0; @@ -1509,7 +1546,7 @@ GetCSLStringAsHashTable(JNIEnv *jenv, char **stringarray, bool bFreeCSL ) { /* exception checking omitted */ for (i=0; iNewStringUTF(*result++); + temp_string = SafeNewStringUTF8(jenv, *result++); jenv->SetObjectArrayElement(jresult, i, temp_string); jenv->DeleteLocalRef(temp_string); } @@ -2509,7 +2546,7 @@ DEFINE_BOOLEAN_FUNC_ARRAY_IN(double, jdouble, GetDoubleArrayElements, ReleaseDou CPLFree( $1 ); } -%typemap(out) OGRCodedValue* +%typemap(out, fragment="SafeNewStringUTF8") OGRCodedValue* { /* %typemap(out) OGRCodedValue* */ /* Convert a OGRCodedValue* to a HashMap */ @@ -2525,10 +2562,10 @@ DEFINE_BOOLEAN_FUNC_ARRAY_IN(double, jdouble, GetDoubleArrayElements, ReleaseDou $result = jenv->NewObject(hashMapClass, constructor); for( int i = 0; ($1)[i].pszCode != NULL; i++ ) { - jstring name = jenv->NewStringUTF(($1)[i].pszCode); + jstring name = SafeNewStringUTF8(jenv, ($1)[i].pszCode); if( ($1)[i].pszValue ) { - jstring value = jenv->NewStringUTF(($1)[i].pszValue); + jstring value = SafeNewStringUTF8(jenv, ($1)[i].pszValue); jenv->CallObjectMethod($result, put, name, value); jenv->DeleteLocalRef(value); }