Skip to content

Commit d8e958a

Browse files
committed
Handle Unicode SMP points (> U+FFFF) and null char in strings
1 parent 35edc9b commit d8e958a

3 files changed

Lines changed: 79 additions & 6 deletions

File tree

src/utils.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,21 @@ void javaReflectionGetFields(JNIEnv *env, jclass clazz, std::list<jobject>* fiel
6565
}
6666

6767
std::string javaToString(JNIEnv *env, jstring str) {
68-
const char* chars = env->GetStringUTFChars(str, NULL);
69-
std::string results = chars;
70-
env->ReleaseStringUTFChars(str, chars);
68+
jclass objClazz = env->GetObjectClass(str);
69+
jmethodID methodId = env->GetMethodID(objClazz, "getBytes", "(Ljava/lang/String;)[B");
70+
71+
jstring charsetName = env->NewStringUTF("UTF-8");
72+
jbyteArray stringJbytes = (jbyteArray)env->CallObjectMethod(str, methodId, charsetName);
73+
env->DeleteLocalRef(charsetName);
74+
75+
jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);
76+
77+
const jsize length = env->GetArrayLength(stringJbytes);
78+
std::string results((const char*)pBytes, length);
79+
80+
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
81+
env->DeleteLocalRef(stringJbytes);
82+
7183
return results;
7284
}
7385

@@ -327,8 +339,8 @@ jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg) {
327339
}
328340

329341
if(arg->IsString()) {
330-
v8::String::Utf8Value val(arg->ToString());
331-
return env->NewStringUTF(*val);
342+
v8::String::Value val(arg->ToString());
343+
return env->NewString(*val, val.length());
332344
}
333345

334346
if(arg->IsInt32() || arg->IsUint32()) {
@@ -668,7 +680,10 @@ v8::Local<v8::Value> javaToV8(Java* java, JNIEnv* env, jobject obj, DynamicProxy
668680
return Nan::New<v8::Number>(result);
669681
}
670682
case TYPE_STRING:
671-
return Nan::New<v8::String>(javaObjectToString(env, obj).c_str()).ToLocalChecked();
683+
{
684+
std::string str = javaObjectToString(env, obj);
685+
return Nan::New<v8::String>(str.c_str(), str.length()).ToLocalChecked();
686+
}
672687
case TYPE_OBJECT:
673688
if (dynamicProxyData != NULL) {
674689
return JavaProxyObject::New(java, obj, dynamicProxyData);

test/Test.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public Test() {}
3838
public static int staticLong(long l) { return (int)l; }
3939
public static double staticDouble(double s) { return s; }
4040
public static float staticFloat(float s) { return s; }
41+
public static String staticString(String s) { return s; }
4142

4243
public static int staticMethodAmbiguous(Double a) { return 1; }
4344
public static int staticMethodAmbiguous(Integer a) { return 2; }
@@ -158,6 +159,18 @@ public static long[] getArrayOfLongs() {
158159
return arr;
159160
}
160161

162+
public static String getUnicodeBMP() {
163+
return new String(Character.toChars(0x2605));
164+
}
165+
166+
public static String getUnicodeSMP() {
167+
return new String(Character.toChars(0x1F596));
168+
}
169+
170+
public static String getUnicodeNull() {
171+
return new String("\0");
172+
}
173+
161174
public static enum StaticEnum {
162175
Value1,
163176
Value2

test/simple-test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,27 @@ exports['Simple'] = nodeunit.testCase({
194194
test.done();
195195
},
196196

197+
"method returning a string (Unicode BMP)": function(test) {
198+
var s = java.callStaticMethodSync("Test", "getUnicodeBMP");
199+
console.log(s);
200+
test.equal(String.fromCodePoint(0x2605), s);
201+
test.done();
202+
},
203+
204+
"method returning a string (Unicode SMP)": function(test) {
205+
var s = java.callStaticMethodSync("Test", "getUnicodeSMP");
206+
console.log(s);
207+
test.equal(String.fromCodePoint(0x1F596), s);
208+
test.done();
209+
},
210+
211+
"method returning a string (NULL char)": function(test) {
212+
var s = java.callStaticMethodSync("Test", "getUnicodeNull");
213+
console.log(s);
214+
test.equal("\0", s);
215+
test.done();
216+
},
217+
197218
"method taking a byte": function(test) {
198219
var b = java.newByte(1);
199220
test.equal('java.lang.Byte', b.getClassSync().getNameSync());
@@ -264,6 +285,30 @@ exports['Simple'] = nodeunit.testCase({
264285
test.done();
265286
},
266287

288+
"method taking a string (Unicode BMP)": function(test) {
289+
var s = String.fromCodePoint(0x2605);
290+
var r = java.callStaticMethodSync("Test", "staticString", s);
291+
console.log(r);
292+
test.equal(r, s);
293+
test.done();
294+
},
295+
296+
"method taking a string (Unicode SMP)": function(test) {
297+
var s = String.fromCodePoint(0x1F596);
298+
var r = java.callStaticMethodSync("Test", "staticString", s);
299+
console.log(r);
300+
test.equal(r, s);
301+
test.done();
302+
},
303+
304+
"method taking a string (with null char)": function(test) {
305+
var s = "\0";
306+
var r = java.callStaticMethodSync("Test", "staticString", s);
307+
console.log(r);
308+
test.equal(r, s);
309+
test.done();
310+
},
311+
267312
"new boolean array object": function(test) {
268313
var booleanArray = java.newArray("java.lang.Boolean", [true, false]);
269314
var r = java.callStaticMethodSync("Test", "staticBooleanArray", booleanArray);

0 commit comments

Comments
 (0)