From f1e35a9d3aa12d7b964fc138141f3298aa22ade7 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 26 Aug 2024 16:24:44 +0200 Subject: [PATCH 1/2] 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); } From 17b70813c7119eb865abfbaa12b6fd505ac2cbf6 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 26 Aug 2024 17:24:16 +0200 Subject: [PATCH 2/2] Java bindings: OGR module: add various xxxxAsByteArray() method that return a byte[] when content is not UTF-8 Fixes #10521 Fixes #10630 --- swig/include/java/typemaps_java.i | 23 +++++ swig/include/ogr.i | 141 +++++++++++++++++++++++++++-- swig/java/CMakeLists.txt | 15 ++- swig/java/apps/OGRTest.java | 47 ++++++++++ swig/java/javadoc.java | 76 +++++++++++++++- swig/java/test_data/iso_8859_1.csv | 2 + 6 files changed, 291 insertions(+), 13 deletions(-) create mode 100644 swig/java/apps/OGRTest.java create mode 100644 swig/java/test_data/iso_8859_1.csv diff --git a/swig/include/java/typemaps_java.i b/swig/include/java/typemaps_java.i index 682995cd12fd..551cc42b1f4e 100644 --- a/swig/include/java/typemaps_java.i +++ b/swig/include/java/typemaps_java.i @@ -498,6 +498,29 @@ SafeNewStringUTF8(JNIEnv *jenv, const char* pszInput) return $jnicall; } +/*************************************************** + * Typemaps for (StringAsByteArray*) + ***************************************************/ + +%typemap(out) (StringAsByteArray*) +{ + /* %typemap(out) (StringAsByteArray*) */ + if(result) + { + const size_t nLen = strlen((const char*)result); + jbyteArray byteArray = jenv->NewByteArray(nLen); + jenv->SetByteArrayRegion(byteArray, (jsize)0, (jsize)nLen, (jbyte*)result); + $result = byteArray; + } +} + +%typemap(jni) (StringAsByteArray*) "jbyteArray" +%typemap(jtype) (StringAsByteArray*) "byte[]" +%typemap(jstype) (StringAsByteArray*) "byte[]" +%typemap(javain) (StringAsByteArray*) "$javainput" +%typemap(javaout) (StringAsByteArray*) { + return $jnicall; + } /*************************************************** * Typemaps for (char **ignorechange) diff --git a/swig/include/ogr.i b/swig/include/ogr.i index a176f12feed7..10c2b9d256df 100644 --- a/swig/include/ogr.i +++ b/swig/include/ogr.i @@ -52,6 +52,12 @@ typedef char retStringAndCPLFree; %} #endif +#ifdef SWIGJAVA +%inline %{ +typedef const char StringAsByteArray; +%} +#endif + #ifdef SWIGCSHARP %include swig_csharp_extensions.i #endif @@ -930,6 +936,12 @@ public: return OGR_DS_GetName(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetNameAsByteArray() { + return OGR_DS_GetName(self); + } +#endif + OGRErr DeleteLayer(int index){ return OGR_DS_DeleteLayer(self, index); } @@ -1324,6 +1336,12 @@ public: return OGR_L_GetName(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetNameAsByteArray() { + return OGR_L_GetName(self); + } +#endif + /* Added in OGR 1.8.0 */ OGRwkbGeometryType GetGeomType() { return (OGRwkbGeometryType) OGR_L_GetGeomType(self); @@ -1333,10 +1351,22 @@ public: return OGR_L_GetGeometryColumn(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetGeometryColumnAsByteArray() { + return OGR_L_GetGeometryColumn(self); + } +#endif + const char * GetFIDColumn() { return OGR_L_GetFIDColumn(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetFIDColumnAsByteArray() { + return OGR_L_GetFIDColumn(self); + } +#endif + %newobject GetFeature; OGRFeatureShadow *GetFeature(GIntBig fid) { return (OGRFeatureShadow*) OGR_L_GetFeature(self, fid); @@ -1985,17 +2015,40 @@ public: /* ---- GetFieldAsString --------------------- */ const char* GetFieldAsString(int id) { - return (const char *) OGR_F_GetFieldAsString(self, id); + return OGR_F_GetFieldAsString(self, id); } const char* GetFieldAsString(const char* field_name) { int i = OGR_F_GetFieldIndex(self, field_name); if (i == -1) - CPLError(CE_Failure, 1, FIELD_NAME_ERROR_TMPL, field_name); + { + CPLError(CE_Failure, 1, FIELD_NAME_ERROR_TMPL, field_name); + return NULL; + } else - return (const char *) OGR_F_GetFieldAsString(self, i); - return NULL; + { + return OGR_F_GetFieldAsString(self, i); + } + } + +#ifdef SWIGJAVA + StringAsByteArray* GetFieldAsStringAsByteArray(int id) { + return OGR_F_GetFieldAsString(self, id); + } + + StringAsByteArray* GetFieldAsStringAsByteArray(const char* field_name) { + int i = OGR_F_GetFieldIndex(self, field_name); + if (i == -1) + { + CPLError(CE_Failure, 1, FIELD_NAME_ERROR_TMPL, field_name); + return NULL; + } + else + { + return OGR_F_GetFieldAsString(self, i); + } } +#endif /* ------------------------------------------- */ @@ -2474,6 +2527,12 @@ public: return (const char*) OGR_F_GetStyleString(self); } +#ifdef SWIGJAVA + StringAsByteArray *GetStyleStringAsByteArray() { + return OGR_F_GetStyleString(self); + } +#endif + void SetStyleString(const char* the_string) { OGR_F_SetStyleString(self, the_string); } @@ -2510,6 +2569,12 @@ public: return OGR_F_GetNativeData(self); } +#ifdef SWIGJAVA + StringAsByteArray *GetNativeDataAsByteArray() { + return OGR_F_GetNativeData(self); + } +#endif + const char* GetNativeMediaType () { return OGR_F_GetNativeMediaType(self); } @@ -2640,6 +2705,12 @@ public: return OGR_FD_GetName(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetNameAsByteArray() { + return OGR_FD_GetName(self); + } +#endif + int GetFieldCount(){ return OGR_FD_GetFieldCount(self); } @@ -2796,11 +2867,17 @@ public: } const char * GetName() { - return (const char *) OGR_Fld_GetNameRef(self); + return OGR_Fld_GetNameRef(self); + } + +#ifdef SWIGJAVA + StringAsByteArray* GetNameAsByteArray() { + return OGR_Fld_GetNameRef(self); } +#endif const char * GetNameRef() { - return (const char *) OGR_Fld_GetNameRef(self); + return OGR_Fld_GetNameRef(self); } void SetName( const char* name) { @@ -2811,6 +2888,12 @@ public: return OGR_Fld_GetAlternativeNameRef(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetAlternativeNameAsByteArray() { + return OGR_Fld_GetAlternativeNameRef(self); + } +#endif + const char * GetAlternativeNameRef() { return OGR_Fld_GetAlternativeNameRef(self); } @@ -2915,6 +2998,12 @@ public: return OGR_Fld_GetDefault( self ); } +#ifdef SWIGJAVA + StringAsByteArray* GetDefaultAsByteArray() { + return OGR_Fld_GetDefault(self); + } +#endif + void SetDefault(const char* pszValue ) { OGR_Fld_SetDefault( self, pszValue ); } @@ -2927,6 +3016,12 @@ public: return OGR_Fld_GetDomainName(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetDomainNameAsByteArray() { + return OGR_Fld_GetDomainName(self); + } +#endif + void SetDomainName(const char* name ) { OGR_Fld_SetDomainName( self, name ); } @@ -2935,6 +3030,12 @@ public: return OGR_Fld_GetComment(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetCommentAsByteArray() { + return OGR_Fld_GetComment(self); + } +#endif + void SetComment(const char* comment ) { OGR_Fld_SetComment( self, comment ); } @@ -2970,11 +3071,17 @@ public: } const char * GetName() { - return (const char *) OGR_GFld_GetNameRef(self); + return OGR_GFld_GetNameRef(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetNameAsByteArray() { + return OGR_GFld_GetNameRef(self); + } +#endif + const char * GetNameRef() { - return (const char *) OGR_GFld_GetNameRef(self); + return OGR_GFld_GetNameRef(self); } void SetName( const char* name) { @@ -4054,10 +4161,22 @@ public: return OGR_FldDomain_GetName(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetNameAsByteArray() { + return OGR_FldDomain_GetName(self); + } +#endif + const char * GetDescription() { return OGR_FldDomain_GetDescription(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetDescriptionAsByteArray() { + return OGR_FldDomain_GetDescription(self); + } +#endif + OGRFieldType GetFieldType() { return OGR_FldDomain_GetFieldType(self); } @@ -4180,6 +4299,12 @@ public: return OGR_GlobFldDomain_GetGlob(self); } +#ifdef SWIGJAVA + StringAsByteArray* GetGlobAsByteArray() { + return OGR_GlobFldDomain_GetGlob(self); + } +#endif + } /* %extend */ }; /* class OGRFieldDomainShadow */ diff --git a/swig/java/CMakeLists.txt b/swig/java/CMakeLists.txt index 6198ab9b12f3..5a3530206773 100644 --- a/swig/java/CMakeLists.txt +++ b/swig/java/CMakeLists.txt @@ -191,6 +191,7 @@ if (Java_Runtime_FOUND AND BUILD_TESTING) file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/tmp_test) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tmp_test) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_data/byte.tif DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/tmp_test) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_data/iso_8859_1.csv DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/tmp_test) if (WIN32) set(CLASSPATH_SEPARATOR "\\;") @@ -229,9 +230,8 @@ if (Java_Runtime_FOUND AND BUILD_TESTING) add_test(NAME java_OSRTest COMMAND ${JAVA_RUN} OSRTest) add_test(NAME java_test_ogrfielddomains COMMAND ${JAVA_RUN} test_ogrfielddomains) - foreach ( - test_name IN - ITEMS java_GDALOverviews + set(JAVA_TEST_LIST + java_GDALOverviews java_gdalinfo java_ogr2ogr_1 java_ogrinfo_1 @@ -247,7 +247,14 @@ if (Java_Runtime_FOUND AND BUILD_TESTING) java_testgetpoints java_ogrtindex java_OSRTest - java_test_ogrfielddomains) + java_test_ogrfielddomains + ) + if (OGR_ENABLE_DRIVER_CSV) + add_test(NAME java_OGRTest COMMAND ${JAVA_RUN} OGRTest) + list(APPEND JAVA_TEST_LIST java_OGRTest) + endif() + + foreach (test_name IN LISTS JAVA_TEST_LIST) set_property(TEST ${test_name} PROPERTY ENVIRONMENT "${TEST_ENV}") endforeach () diff --git a/swig/java/apps/OGRTest.java b/swig/java/apps/OGRTest.java new file mode 100644 index 000000000000..71148bbeccb1 --- /dev/null +++ b/swig/java/apps/OGRTest.java @@ -0,0 +1,47 @@ +/****************************************************************************** + * Name: OGRTest.java + * Project: OGR Java Interface + * Purpose: Test OGR module + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2024, Even Rouault + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +import java.util.Arrays; +import org.gdal.ogr.*; + +public class OGRTest +{ + public static void main(String[] args) throws Exception + { + ogr.RegisterAll(); + DataSource poDS = ogr.Open("tmp_test/iso_8859_1.csv", false); + Layer lyr = poDS.GetLayer(0); + FieldDefn fld_defn = lyr.GetLayerDefn().GetFieldDefn(1); + String got = fld_defn.GetName(); + if (!got.equals("field_")) + throw new Exception("Got '" + got + "'"); + byte[] byteArray = fld_defn.GetNameAsByteArray(); + if(!Arrays.equals(byteArray, new byte[]{'f', 'i', 'e', 'l', 'd', '_', 0xE9 - 256, 'x'})) + throw new Exception("GetNameAsByteArray() returned unexpected content of size " + byteArray.length); + } +} diff --git a/swig/java/javadoc.java b/swig/java/javadoc.java index 22a144897093..552bc63da733 100644 --- a/swig/java/javadoc.java +++ b/swig/java/javadoc.java @@ -6859,9 +6859,22 @@ public class Layer:public FeatureDefn GetLayerDefn() * definition initialization. * * @return the layer name + * @see #GetNameAsByteArray() */ public class Layer:public String GetName() +/** + * Return the layer name (when it is not UTF-8 encoded). + *

+ * This returns the same content as GetLayerDefn().GetName(), but for a + * few drivers, calling GetName() directly can avoid lengthy layer + * definition initialization. + * + * @return the layer name + * @since 3.10 +*/ +public class Layer:public byte GetNameAsByteArray() + /** * Return the layer geometry type. *

@@ -7756,6 +7769,7 @@ public class Feature:public int[] GetFieldAsIntegerList(int ifield) * @param ifield the field to fetch, from 0 to GetFieldCount()-1. * * @return the field value. + * @see #GetFieldAsStringAsByteArray(int) */ public class Feature:public String GetFieldAsString(int ifield) @@ -7769,9 +7783,38 @@ public class Feature:public String GetFieldAsString(int ifield) * @param name the name of the field to fetch. * * @return the field value. + * @see #GetFieldAsStringAsByteArray(String) */ public class Feature:public String GetFieldAsString(String name) +/** + * Fetch field value as a string (when it is not UTF-8 encoded). + *

+ * OFTReal and OFTInteger fields will be translated to string using + * sprintf(), but not necessarily using the established formatting rules. + * Other field types, or errors will result in a return value of zero. + * + * @param ifield the field to fetch, from 0 to GetFieldCount()-1. + * + * @return the field value. + * @since 3.10 + */ +public class Feature:public byte[] GetFieldAsStringAsByteArray(int ifield) + +/** + * Fetch field value as a string (when it is not UTF-8 encoded). + *

+ * OFTReal and OFTInteger fields will be translated to string using + * sprintf(), but not necessarily using the established formatting rules. + * Other field types, or errors will result in a return value of zero. + * + * @param name the name of the field to fetch. + * + * @return the field value. + * @since 3.10 + */ +public class Feature:public byte[] GetFieldAsStringAsByteArray(String name) + /** * Fetch field value as a list of strings. *

@@ -7861,9 +7904,23 @@ public class Feature:public Geometry GetGeometryRef() * * @return a reference to a representation in string format, or null if * there isn't one. + * + * @see #GetStyleStringAsByteArray() */ public class Feature:public String GetStyleString() +/** + * Fetch style string for this feature (when it is not UTF-8 encoded). + *

+ * Set the OGR Feature Style Specification for details on the format of + * this string, and ogr_featurestyle.h for services available to parse it. + * + * @return a reference to a representation in string format, or null if + * there isn't one. + * @since 3.10 + */ +public class Feature:public byte[] GetStyleStringAsByteArray() + /** * Test if a field has ever been assigned a value or not. * @@ -9416,6 +9473,15 @@ public class FeatureDefn:public int GetFieldCount() */ public class FeatureDefn:public String GetName() +/** + * Get name of this FeatureDefn (when it is not UTF-8 encoded). + * + * @return the name + * @since 3.10 +*/ +public class FeatureDefn:public byte GetNameAsByteArray() + +/** /** * Fetch field definition. * @@ -9569,12 +9635,20 @@ public class FieldDefn:public String GetFieldTypeName(int type) public class FieldDefn:public int GetJustify() /** - * Fetch name of this field. + * Get the name of this field. * * @return the name of the field */ public class FieldDefn:public String GetName() +/** + * Get the name of this field (when it is not UTF-8 encoded). + * + * @return the name of the field + * @since 3.10 +*/ +public class FieldDefn:public byte GetNameAsByteArray() + /** * Fetch name of this field. * diff --git a/swig/java/test_data/iso_8859_1.csv b/swig/java/test_data/iso_8859_1.csv new file mode 100644 index 000000000000..f4ef83814f21 --- /dev/null +++ b/swig/java/test_data/iso_8859_1.csv @@ -0,0 +1,2 @@ +id,field_éx +1,xéx