From ecdfa32883ab6f8a0bf963d1108143c8f7b103d1 Mon Sep 17 00:00:00 2001 From: Alexey Rochev Date: Tue, 15 Dec 2020 01:55:35 +0300 Subject: [PATCH 1/2] Add @AsUtf16 annotation to map java.lang.String to `unsigned short*` (array of UTF-16 code units) --- .../bytedeco/javacpp/annotation/AsUtf16.java | 17 +++ .../org/bytedeco/javacpp/tools/Generator.java | 128 ++++++++++++++---- .../org/bytedeco/javacpp/AdapterTest.java | 23 +++- .../org/bytedeco/javacpp/AdapterTest.h | 6 +- 4 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 src/main/java/org/bytedeco/javacpp/annotation/AsUtf16.java diff --git a/src/main/java/org/bytedeco/javacpp/annotation/AsUtf16.java b/src/main/java/org/bytedeco/javacpp/annotation/AsUtf16.java new file mode 100644 index 000000000..6f3ec3d92 --- /dev/null +++ b/src/main/java/org/bytedeco/javacpp/annotation/AsUtf16.java @@ -0,0 +1,17 @@ +package org.bytedeco.javacpp.annotation; + +import org.bytedeco.javacpp.tools.Generator; + +import java.lang.annotation.*; + +/** + * Annotation indicating that {@link java.lang.String} should be mapped + * to array of UTF-16 code units ({@code unsigned short*}) instead + * of byte array ({@code const char*}) + * + * @see Generator + */ + +@Documented @Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.PARAMETER}) +public @interface AsUtf16 { } \ No newline at end of file diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 182cca3d4..e9c036106 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -81,6 +81,7 @@ import org.bytedeco.javacpp.annotation.MemberSetter; import org.bytedeco.javacpp.annotation.Name; import org.bytedeco.javacpp.annotation.Namespace; +import org.bytedeco.javacpp.annotation.AsUtf16; import org.bytedeco.javacpp.annotation.NoDeallocator; import org.bytedeco.javacpp.annotation.NoException; import org.bytedeco.javacpp.annotation.NoOffset; @@ -937,20 +938,41 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("}"); out.println(); if (handleExceptions || convertStrings) { - out.println("static JavaCPP_noinline jstring JavaCPP_createString(JNIEnv* env, const char* ptr) {"); + out.println("#include "); + out.println("static JavaCPP_noinline jstring JavaCPP_createStringFromBytes(JNIEnv* env, const char* ptr, size_t length) {"); out.println(" if (ptr == NULL) {"); out.println(" return NULL;"); out.println(" }"); out.println("#ifdef MODIFIED_UTF8_STRING"); out.println(" return env->NewStringUTF(ptr);"); out.println("#else"); - out.println(" size_t length = strlen(ptr);"); out.println(" jbyteArray bytes = env->NewByteArray(length < INT_MAX ? length : INT_MAX);"); out.println(" env->SetByteArrayRegion(bytes, 0, length < INT_MAX ? length : INT_MAX, (signed char*)ptr);"); out.println(" return (jstring)env->NewObject(JavaCPP_getClass(env, " + jclasses.index(String.class) + "), JavaCPP_stringMID, bytes);"); out.println("#endif"); out.println("}"); out.println(); + out.println("static JavaCPP_noinline jstring JavaCPP_createStringFromBytes(JNIEnv* env, const char* ptr) {"); + out.println(" if (ptr == NULL) {"); + out.println(" return NULL;"); + out.println(" }"); + out.println(" return JavaCPP_createStringFromBytes(env, ptr, std::char_traits::length(ptr));"); + out.println("}"); + out.println(); + out.println("static JavaCPP_noinline jstring JavaCPP_createStringFromUTF16CodeUnits(JNIEnv* env, const unsigned short* ptr, size_t length) {"); + out.println(" if (ptr == NULL) {"); + out.println(" return NULL;"); + out.println(" }"); + out.println(" return env->NewString(ptr, length);"); + out.println("}"); + out.println(); + out.println("static JavaCPP_noinline jstring JavaCPP_createStringFromUTF16CodeUnits(JNIEnv* env, const unsigned short* ptr) {"); + out.println(" if (ptr == NULL) {"); + out.println(" return NULL;"); + out.println(" }"); + out.println(" return JavaCPP_createStringFromUTF16CodeUnits(env, ptr, std::char_traits::length(ptr));"); + out.println("}"); + out.println(); } if (convertStrings) { out.println("static JavaCPP_noinline const char* JavaCPP_getStringBytes(JNIEnv* env, jstring str) {"); @@ -977,7 +999,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(); out.println("static JavaCPP_noinline void JavaCPP_releaseStringBytes(JNIEnv* env, jstring str, const char* ptr) {"); out.println("#ifdef MODIFIED_UTF8_STRING"); - out.println(" if (str != NULL) {"); + out.println(" if (str != NULL && ptr != NULL) {"); out.println(" env->ReleaseStringUTFChars(str, ptr);"); out.println(" }"); out.println("#else"); @@ -985,6 +1007,23 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("#endif"); out.println("}"); out.println(); + out.println("static JavaCPP_noinline const unsigned short* JavaCPP_getStringUTF16CodeUnits(JNIEnv* env, jstring str) {"); + out.println(" if (str == NULL) {"); + out.println(" return NULL;"); + out.println(" }"); + out.println(" const jsize length = env->GetStringLength(str);"); + out.println(" unsigned short* ptr = new (std::nothrow) unsigned short[length + 1];"); + out.println(" if (ptr != NULL) {"); + out.println(" env->GetStringRegion(str, 0, length, ptr);"); + out.println(" ptr[length] = 0;"); + out.println(" }"); + out.println(" return ptr;"); + out.println("}"); + out.println(); + out.println("static JavaCPP_noinline void JavaCPP_releaseStringUTF16CodeUnits(JNIEnv*, const unsigned short* ptr) {"); + out.println(" delete[] ptr;"); + out.println("}"); + out.println(); } out.println("class JavaCPP_hidden JavaCPP_exception : public std::exception {"); out.println("public:"); @@ -1012,9 +1051,9 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" try {"); out.println(" throw;"); out.println(" } catch (GENERIC_EXCEPTION_CLASS& e) {"); - out.println(" str = JavaCPP_createString(env, e.GENERIC_EXCEPTION_TOSTRING);"); + out.println(" str = JavaCPP_createStringFromBytes(env, e.GENERIC_EXCEPTION_TOSTRING);"); out.println(" } catch (...) {"); - out.println(" str = JavaCPP_createString(env, \"Unknown exception.\");"); + out.println(" str = JavaCPP_createStringFromBytes(env, \"Unknown exception.\");"); out.println(" }"); out.println(" jmethodID mid = JavaCPP_getMethodID(env, i, \"\", \"(Ljava/lang/String;)V\");"); out.println(" if (mid == NULL) {"); @@ -2029,7 +2068,7 @@ void parametersBefore(MethodInformation methodInfo) { Annotation passBy = by(methodInfo, j); String cast = cast(methodInfo, j); String[] typeName = methodInfo.parameterRaw[j] ? new String[] { "" } - : cppTypeName(methodInfo.parameterTypes[j]); + : cppTypeName(methodInfo.parameterTypes[j], methodInfo.parameterAnnotations[j]); AdapterInformation adapterInfo = methodInfo.parameterRaw[j] ? null : adapterInformation(false, methodInfo, j); @@ -2099,7 +2138,7 @@ void parametersBefore(MethodInformation methodInfo) { } } else if (methodInfo.parameterTypes[j] == String.class) { passesStrings = true; - out.println("JavaCPP_getStringBytes(env, arg" + j + ");"); + out.println(getStringData("arg" + j, methodInfo.parameterAnnotations[j])); if (adapterInfo != null || prevAdapterInfo != null) { out.println(" jlong size" + j + " = 0;"); out.println(" void* owner" + j + " = (void*)ptr" + j + ";"); @@ -2268,19 +2307,19 @@ String returnBefore(MethodInformation methodInfo) { if (FunctionPointer.class.isAssignableFrom(methodInfo.returnType)) { out.println(" rptr = new (std::nothrow) " + valueTypeName + ";"); if (returnBy instanceof ByPtrPtr) { - String[] cpptypeName = cppTypeName(methodInfo.returnType); + String[] cpptypeName = cppTypeName(methodInfo.returnType, methodInfo.annotations); returnPrefix = cpptypeName[0] + "* rptrptr" + cpptypeName[1] + " = "; } } } else if (methodInfo.returnType == String.class) { out.println(" jstring rarg = NULL;"); - out.println(" const char* rptr;"); + out.println(" " + typeName[0] + " rptr;"); if (returnBy instanceof ByRef) { - returnPrefix = "std::string rstr("; + returnPrefix = "std::basic_string<" + valueTypeName + "> rstr("; } else if (returnBy instanceof ByPtrPtr) { - returnPrefix = "rptr = NULL; const char** rptrptr = (const char**)"; + returnPrefix = "rptr = NULL; " + typeName[0] + "* rptrptr = (" + typeName[0] + "*)"; } else { - returnPrefix += "(const char*)"; + returnPrefix += "(" + typeName[0] + ")"; } } else { logger.warn("Method \"" + methodInfo.method + "\" has unsupported return type \"" + @@ -2691,7 +2730,7 @@ void returnAfter(MethodInformation methodInfo) { } else if (methodInfo.returnType == String.class) { passesStrings = true; out.println(indent + "if (rptr != NULL) {"); - out.println(indent + " rarg = JavaCPP_createString(env, rptr);"); + out.println(indent + " rarg = " + createString("rptr", (adapterInfo != null ? "radapter" : null), methodInfo.annotations)); out.println(indent + "}"); } else if (methodInfo.returnType.isArray() && methodInfo.returnType.getComponentType().isPrimitive()) { @@ -2783,7 +2822,7 @@ void parametersAfter(MethodInformation methodInfo) { ", JavaCPP_addressFID, ptr_to_jlong(ptr" + j + "));"); } } else if (methodInfo.parameterTypes[j] == String.class) { - out.println(" JavaCPP_releaseStringBytes(env, arg" + j + ", ptr" + j + ");"); + out.println(" " + releaseStringData("arg" + j, "ptr" + j, methodInfo.parameterAnnotations[j])); } else if (methodInfo.parameterTypes[j].isArray() && methodInfo.parameterTypes[j].getComponentType().isPrimitive()) { for (int k = 0; adapterInfo != null && k < adapterInfo.argc; k++) { @@ -2966,7 +3005,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo } String callbackReturnCast = cast(callbackReturnType, callbackAnnotations); Annotation returnBy = by(callbackAnnotations); - String[] returnTypeName = cppTypeName(callbackReturnType); + String[] returnTypeName = cppTypeName(callbackReturnType, callbackAnnotations); String returnValueTypeName = valueTypeName(returnTypeName); AdapterInformation returnAdapterInfo = adapterInformation(false, returnValueTypeName, callbackAnnotations); boolean throwsExceptions = !noException(cls, callbackMethod); @@ -3001,7 +3040,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" }"); } } else { - String[] typeName = cppTypeName(callbackParameterTypes[j]); + String[] typeName = cppTypeName(callbackParameterTypes[j], callbackParameterAnnotations[j]); String valueTypeName = valueTypeName(typeName); AdapterInformation adapterInfo = adapterInformation(false, valueTypeName, callbackParameterAnnotations[j]); @@ -3088,7 +3127,12 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" args[" + j + "].l = obj" + j + ";"); } else if (callbackParameterTypes[j] == String.class) { passesStrings = true; - out.println(" jstring obj" + j + " = JavaCPP_createString(env, (const char*)" + (adapterInfo != null ? "adapter" : "arg") + j + ");"); + if (adapterInfo != null) { + final String adapter = "adapter" + j; + out.println(" jstring obj" + j + " = " + createString("(" + typeName[0] + ") " + adapter, adapter, callbackParameterAnnotations[j])); + } else { + out.println(" jstring obj" + j + " = " + createString("(" + typeName[0] + ") arg" + j, null, callbackParameterAnnotations[j])); + } out.println(" args[" + j + "].l = obj" + j + ";"); } else if (callbackParameterTypes[j].isArray() && callbackParameterTypes[j].getComponentType().isPrimitive()) { @@ -3171,7 +3215,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo for (int j = 0; j < callbackParameterTypes.length; j++) { if (Pointer.class.isAssignableFrom(callbackParameterTypes[j])) { - String[] typeName = cppTypeName(callbackParameterTypes[j]); + String[] typeName = cppTypeName(callbackParameterTypes[j], callbackParameterAnnotations[j]); Annotation passBy = by(callbackParameterAnnotations[j]); String cast = cast(callbackParameterTypes[j], callbackParameterAnnotations[j]); String valueTypeName = valueTypeName(typeName); @@ -3248,7 +3292,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo } } else if (callbackReturnType == String.class) { passesStrings = true; - out.println(" " + returnTypeName[0] + " rptr" + returnTypeName[1] + " = JavaCPP_getStringBytes(env, rarg);"); + out.println(" " + returnTypeName[0] + " rptr" + returnTypeName[1] + " = " + getStringData("rarg", callbackAnnotations)); if (returnAdapterInfo != null) { out.println(" jlong rsize = 0;"); out.println(" void* rowner = (void*)rptr;"); @@ -3930,7 +3974,7 @@ String[] cppCastTypeName(Class type, Annotation ... annotations) { // prioritize @Cast continue; } - typeName = cppTypeName(type); + typeName = cppTypeName(type, annotations); if (typeName[0].contains("(*")) { // function pointer if (b.length > 0 && b[0] && !typeName[0].endsWith(" const")) { @@ -3958,12 +4002,12 @@ String[] cppCastTypeName(Class type, Annotation ... annotations) { logger.warn("Without \"Adapter\", \"Cast\" and \"Const\" annotations are mutually exclusive."); } if (typeName == null) { - typeName = cppTypeName(type); + typeName = cppTypeName(type, annotations); } return typeName; } - String[] cppTypeName(Class type) { + String[] cppTypeName(Class type, Annotation[] annotations) { String prefix = "", suffix = ""; if (type == Buffer.class || type == Pointer.class) { prefix = "void*"; @@ -3986,7 +4030,11 @@ String[] cppTypeName(Class type) { } else if (type == PointerPointer.class) { prefix = "void**"; } else if (type == String.class) { - prefix = "const char*"; + if (asUtf16CodeUnits(annotations)) { + prefix = "const unsigned short*"; + } else { + prefix = "const char*"; + } } else if (type == byte.class) { prefix = "signed char"; } else if (type == long.class) { @@ -4015,6 +4063,10 @@ String[] cppTypeName(Class type) { return new String[] { prefix, suffix }; } + String[] cppTypeName(Class type) { + return cppTypeName(type, null); + } + String[] cppFunctionTypeName(Method... functionMethods) { Method functionMethod = null; if (functionMethods != null) { @@ -4251,4 +4303,34 @@ static String mangle(String name) { } return mangledName.toString(); } + + private static boolean asUtf16CodeUnits(Annotation[] annotations) { + if (annotations == null) { + return false; + } + for (Annotation annotation : annotations) { + if (annotation instanceof AsUtf16) { + return true; + } + } + return false; + } + + private static String createString(String ptr, String adapter, Annotation[] annotations) { + return (asUtf16CodeUnits(annotations) ? "JavaCPP_createStringFromUTF16CodeUnits(env, " + : "JavaCPP_createStringFromBytes(env, ") + + ptr + (adapter != null ? ", " + adapter + ".size);" : ");"); + } + + private static String getStringData(String str, Annotation[] annotations) { + return (asUtf16CodeUnits(annotations) ? "JavaCPP_getStringUTF16CodeUnits(env, " + : "JavaCPP_getStringBytes(env, ") + + str + ");"; + } + + private static String releaseStringData(String str, String ptr, Annotation[] annotations) { + return (asUtf16CodeUnits(annotations) ? "JavaCPP_releaseStringUTF16CodeUnits(env, " + : "JavaCPP_releaseStringBytes(env, " + str + ", ") + + ptr + ");"; + } } diff --git a/src/test/java/org/bytedeco/javacpp/AdapterTest.java b/src/test/java/org/bytedeco/javacpp/AdapterTest.java index f6b88197a..93c9dc466 100644 --- a/src/test/java/org/bytedeco/javacpp/AdapterTest.java +++ b/src/test/java/org/bytedeco/javacpp/AdapterTest.java @@ -37,6 +37,7 @@ import org.bytedeco.javacpp.annotation.StdVector; import org.bytedeco.javacpp.annotation.StdWString; import org.bytedeco.javacpp.annotation.UniquePtr; +import org.bytedeco.javacpp.annotation.AsUtf16; import org.bytedeco.javacpp.tools.Builder; import org.junit.BeforeClass; import org.junit.Test; @@ -54,6 +55,7 @@ public class AdapterTest { static native @StdString BytePointer testStdString(@StdString BytePointer str); static native @StdWString CharPointer testStdWString(@StdWString CharPointer str); + static native @StdWString @AsUtf16 String testStdWString(@StdWString @AsUtf16 String str); static native @StdWString IntPointer testStdWString(@StdWString IntPointer str); static native @StdBasicString("char") String testStdString2(@StdBasicString("char") String str); @@ -62,12 +64,14 @@ public class AdapterTest { static native @Cast("wchar_t*") @StdBasicString("wchar_t") IntPointer testStdWString2(@Cast("wchar_t*") @StdBasicString("wchar_t") IntPointer str); static native @StdU16String CharPointer testStdU16String(@StdU16String CharPointer str); + static native @StdU16String @AsUtf16 String testStdU16String(@StdU16String @AsUtf16 String str); static native @StdU32String IntPointer testStdU32String(@StdU32String IntPointer str); static native String testCharString(String str); static native @Cast("char*") BytePointer testCharString(@Cast("char*") BytePointer str); static native CharPointer testShortString(CharPointer str); + static native @AsUtf16 String testShortString(@AsUtf16 String str); static native IntPointer testIntString(IntPointer str); @@ -165,8 +169,12 @@ static class MovedData extends Pointer { // UTF-16 CharPointer textCharPtr2 = testStdWString(textCharPtr1); assertEquals(textStr1, textCharPtr2.getString()); + CharPointer textCharPtr3 = testStdWString2(textCharPtr1); assertEquals(textStr1, textCharPtr3.getString()); + + String textStr4 = testStdWString(textStr1); + assertEquals(textStr1, textStr4); } else { // UTF-32 IntPointer textIntPtr2 = testStdWString(textIntPtr1); @@ -178,6 +186,9 @@ static class MovedData extends Pointer { CharPointer textCharPtr4 = testStdU16String(textCharPtr1); assertEquals(textStr1, textCharPtr4.getString()); + String textStr5 = testStdU16String(textStr1); + assertEquals(textStr1, textStr5); + IntPointer textIntPtr4 = testStdU32String(textIntPtr1); assertEquals(textStr1, textIntPtr4.getString()); @@ -205,11 +216,15 @@ static class MovedData extends Pointer { @Test public void testShortString() { System.out.println("ShortString"); - String textStr = "This is a normal ASCII string."; - CharPointer textPtr1 = new CharPointer(textStr); + String textStr1 = "This is a normal ASCII string."; + CharPointer textPtr1 = new CharPointer(textStr1); CharPointer textPtr2 = testShortString(textPtr1); - assertEquals(textStr, textPtr1.getString()); - assertEquals(textStr, textPtr2.getString()); + assertEquals(textStr1, textPtr1.getString()); + assertEquals(textStr1, textPtr2.getString()); + + String textStr2 = testShortString(textStr1); + assertEquals(textStr1, textStr2); + System.gc(); } diff --git a/src/test/resources/org/bytedeco/javacpp/AdapterTest.h b/src/test/resources/org/bytedeco/javacpp/AdapterTest.h index 1aaa3d5ba..2f70e64e6 100644 --- a/src/test/resources/org/bytedeco/javacpp/AdapterTest.h +++ b/src/test/resources/org/bytedeco/javacpp/AdapterTest.h @@ -31,6 +31,10 @@ char *testCharString(const char *str) { // memory leak... } +const unsigned short *testShortString(const unsigned short *str) { + return str; +} + unsigned short *testShortString(unsigned short *str) { return str; } @@ -127,4 +131,4 @@ MovedData&& getMovedData() { void putMovedData(MovedData&& m) { movedData = m; -} \ No newline at end of file +} From 42dbba942e7dfdafa3d6167cd94a769db8b0da9e Mon Sep 17 00:00:00 2001 From: Samuel Audet Date: Fri, 12 Feb 2021 10:41:32 +0900 Subject: [PATCH 2/2] Update CHANGELOG.md and fix a few nits --- CHANGELOG.md | 1 + .../bytedeco/javacpp/annotation/AsUtf16.java | 7 +- .../org/bytedeco/javacpp/tools/Generator.java | 78 +++++++++---------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a52bbf3a0..2c1dd47bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ + * Add `@AsUtf16` annotation to map `java.lang.String` to `unsigned short*` (array of UTF-16 code units) ([pull #442](https://github.com/bytedeco/javacpp/pull/#442)) * Add `BasicStringAdapter` and corresponding `@StdBasicString`, `@StdU16String`, and `@StdU32String` annotations ([pull #448](https://github.com/bytedeco/javacpp/pull/448)) * Fix `Parser` failures on `try` blocks as function body, nested class templates, and aliases to namespaces starting with `::` * Prevent `Loader` from failing to find, load, or link libraries multiple times diff --git a/src/main/java/org/bytedeco/javacpp/annotation/AsUtf16.java b/src/main/java/org/bytedeco/javacpp/annotation/AsUtf16.java index 6f3ec3d92..122634610 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/AsUtf16.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/AsUtf16.java @@ -5,11 +5,12 @@ import java.lang.annotation.*; /** - * Annotation indicating that {@link java.lang.String} should be mapped - * to array of UTF-16 code units ({@code unsigned short*}) instead - * of byte array ({@code const char*}) + * Indicates that {@link java.lang.String} should be mapped to array of UTF-16 + * code units ({@code unsigned short*}) instead of byte array ({@code const char*}). * * @see Generator + * + * @author Alexey Rochev */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index e9c036106..503b9d9ae 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -959,18 +959,18 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" return JavaCPP_createStringFromBytes(env, ptr, std::char_traits::length(ptr));"); out.println("}"); out.println(); - out.println("static JavaCPP_noinline jstring JavaCPP_createStringFromUTF16CodeUnits(JNIEnv* env, const unsigned short* ptr, size_t length) {"); + out.println("static JavaCPP_noinline jstring JavaCPP_createStringFromUTF16(JNIEnv* env, const unsigned short* ptr, size_t length) {"); out.println(" if (ptr == NULL) {"); out.println(" return NULL;"); out.println(" }"); out.println(" return env->NewString(ptr, length);"); out.println("}"); out.println(); - out.println("static JavaCPP_noinline jstring JavaCPP_createStringFromUTF16CodeUnits(JNIEnv* env, const unsigned short* ptr) {"); + out.println("static JavaCPP_noinline jstring JavaCPP_createStringFromUTF16(JNIEnv* env, const unsigned short* ptr) {"); out.println(" if (ptr == NULL) {"); out.println(" return NULL;"); out.println(" }"); - out.println(" return JavaCPP_createStringFromUTF16CodeUnits(env, ptr, std::char_traits::length(ptr));"); + out.println(" return JavaCPP_createStringFromUTF16(env, ptr, std::char_traits::length(ptr));"); out.println("}"); out.println(); } @@ -1007,7 +1007,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("#endif"); out.println("}"); out.println(); - out.println("static JavaCPP_noinline const unsigned short* JavaCPP_getStringUTF16CodeUnits(JNIEnv* env, jstring str) {"); + out.println("static JavaCPP_noinline const unsigned short* JavaCPP_getStringUTF16(JNIEnv* env, jstring str) {"); out.println(" if (str == NULL) {"); out.println(" return NULL;"); out.println(" }"); @@ -1020,7 +1020,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" return ptr;"); out.println("}"); out.println(); - out.println("static JavaCPP_noinline void JavaCPP_releaseStringUTF16CodeUnits(JNIEnv*, const unsigned short* ptr) {"); + out.println("static JavaCPP_noinline void JavaCPP_releaseStringUTF16(JNIEnv*, const unsigned short* ptr) {"); out.println(" delete[] ptr;"); out.println("}"); out.println(); @@ -3866,6 +3866,34 @@ String enumValueType(Class type) { } } + static boolean asUtf16(Annotation[] annotations) { + if (annotations == null) { + return false; + } + for (Annotation annotation : annotations) { + if (annotation instanceof AsUtf16) { + return true; + } + } + return false; + } + + static String createString(String ptr, String adapter, Annotation[] annotations) { + return (asUtf16(annotations) ? "JavaCPP_createStringFromUTF16(env, " + : "JavaCPP_createStringFromBytes(env, ") + + ptr + (adapter != null ? ", " + adapter + ".size);" : ");"); + } + + static String getStringData(String str, Annotation[] annotations) { + return (asUtf16(annotations) ? "JavaCPP_getStringUTF16(env, " + : "JavaCPP_getStringBytes(env, ") + str + ");"; + } + + static String releaseStringData(String str, String ptr, Annotation[] annotations) { + return (asUtf16(annotations) ? "JavaCPP_releaseStringUTF16(env, " + : "JavaCPP_releaseStringBytes(env, " + str + ", ") + ptr + ");"; + } + static String constValueTypeName(String ... typeName) { String type = typeName[0]; if (type.endsWith("*") || type.endsWith("&")) { @@ -4007,6 +4035,10 @@ String[] cppCastTypeName(Class type, Annotation ... annotations) { return typeName; } + String[] cppTypeName(Class type) { + return cppTypeName(type, null); + } + String[] cppTypeName(Class type, Annotation[] annotations) { String prefix = "", suffix = ""; if (type == Buffer.class || type == Pointer.class) { @@ -4030,7 +4062,7 @@ String[] cppTypeName(Class type, Annotation[] annotations) { } else if (type == PointerPointer.class) { prefix = "void**"; } else if (type == String.class) { - if (asUtf16CodeUnits(annotations)) { + if (asUtf16(annotations)) { prefix = "const unsigned short*"; } else { prefix = "const char*"; @@ -4063,10 +4095,6 @@ String[] cppTypeName(Class type, Annotation[] annotations) { return new String[] { prefix, suffix }; } - String[] cppTypeName(Class type) { - return cppTypeName(type, null); - } - String[] cppFunctionTypeName(Method... functionMethods) { Method functionMethod = null; if (functionMethods != null) { @@ -4303,34 +4331,4 @@ static String mangle(String name) { } return mangledName.toString(); } - - private static boolean asUtf16CodeUnits(Annotation[] annotations) { - if (annotations == null) { - return false; - } - for (Annotation annotation : annotations) { - if (annotation instanceof AsUtf16) { - return true; - } - } - return false; - } - - private static String createString(String ptr, String adapter, Annotation[] annotations) { - return (asUtf16CodeUnits(annotations) ? "JavaCPP_createStringFromUTF16CodeUnits(env, " - : "JavaCPP_createStringFromBytes(env, ") - + ptr + (adapter != null ? ", " + adapter + ".size);" : ");"); - } - - private static String getStringData(String str, Annotation[] annotations) { - return (asUtf16CodeUnits(annotations) ? "JavaCPP_getStringUTF16CodeUnits(env, " - : "JavaCPP_getStringBytes(env, ") - + str + ");"; - } - - private static String releaseStringData(String str, String ptr, Annotation[] annotations) { - return (asUtf16CodeUnits(annotations) ? "JavaCPP_releaseStringUTF16CodeUnits(env, " - : "JavaCPP_releaseStringBytes(env, " + str + ", ") - + ptr + ");"; - } }