Index: source/scriptinterface/ScriptConversions.cpp =================================================================== --- source/scriptinterface/ScriptConversions.cpp +++ source/scriptinterface/ScriptConversions.cpp @@ -158,16 +158,10 @@ template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, std::string& out) { - JSAutoRequest rq(cx); - WARN_IF_NOT(v.isString() || v.isNumber(), v); // allow implicit number conversions - JS::RootedString str(cx, JS::ToString(cx, v)); - if (!str) - FAIL("Argument must be convertible to a string"); - char* ch = JS_EncodeString(cx, str); // chops off high byte of each char16_t - if (!ch) - FAIL("JS_EncodeString failed"); // out of memory - out.assign(ch, ch + JS_GetStringLength(str)); - JS_free(cx, ch); + std::wstring wideout; + if (!FromJSVal(cx, v, wideout)) + return false; + out = CStrW(wideout).ToUTF8(); return true; } @@ -265,12 +259,7 @@ template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const std::string& val) { - JSAutoRequest rq(cx); - JS::RootedString str(cx, JS_NewStringCopyN(cx, val.c_str(), val.length())); - if (str) - ret.setString(str); - else - ret.setUndefined(); + ToJSVal(cx, ret, static_cast(CStr(val).FromUTF8())); } template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const wchar_t* const& val) Index: source/scriptinterface/tests/test_ScriptConversions.h =================================================================== --- source/scriptinterface/tests/test_ScriptConversions.h +++ source/scriptinterface/tests/test_ScriptConversions.h @@ -51,7 +51,7 @@ } template - void roundtrip(const T& value, const char* expected) + T roundtrip(const T& value, const char* expected) { ScriptInterface script("Test", "Test", g_ScriptRuntime); TS_ASSERT(script.LoadGlobalScripts()); @@ -71,6 +71,7 @@ T v2 = T(); TS_ASSERT(ScriptInterface::FromJSVal(cx, v1, v2)); TS_ASSERT_EQUALS(value, v2); + return v2; } template @@ -148,9 +149,9 @@ roundtrip("", "\"\""); roundtrip("test", "\"test\""); - roundtrip("тест", "\"\\xD1\\x82\\xD0\\xB5\\xD1\\x81\\xD1\\x82\""); + TS_ASSERT_EQUALS(roundtrip("тест", "\"\\u0442\\u0435\\u0441\\u0442\""), "тест"); roundtrip(s1, "\"t\\x00st\""); - roundtrip(s2, "\"\\xD1\\x82\\x00\\x00\\xD1\\x81\\xD1\\x82\""); + TS_ASSERT_EQUALS(roundtrip(s2, "\"\\u0442\\x00\\x00\\u0441\\u0442\""), s2); roundtrip(L"", "\"\""); roundtrip(L"test", "\"test\""); @@ -251,4 +252,37 @@ CFixedVector3D u(fixed::Pi(), fixed::Zero(), fixed::FromInt(2)); call_prototype_function(u, v, "add", "({x:3.1415863037109375, y:3.1415863037109375, z:3})"); } + + void test_strings() + { + { + std::string test("éè!§$-aezi134900°°©©¢¢ÇÇ‘{¶«¡Ç’[å»ÛÁØ"); + TS_ASSERT_EQUALS(test, roundtrip(test, nullptr)); + } + { + std::wstring test(L"éè!§$-aezi134900°°©©¢¢ÇÇ‘{¶«¡Ç’[å»ÛÁØ"); + TS_ASSERT_EQUALS(test, roundtrip(test, nullptr)); + } + ScriptInterface script("Test", "Test", g_ScriptRuntime); + TS_ASSERT(script.LoadGlobalScripts()); + JSContext* cx = script.GetContext(); + JSAutoRequest rq(cx); + { + // Fancier conversion: we store UTF8 and get UTF16 and vice-versa + std::string in_utf8("éè!§$-aezi134900°°©©¢¢ÇÇ‘{¶«¡Ç’[å»ÛÁØ"); + std::wstring in_utf16(L"éè!§$-aezi134900°°©©¢¢ÇÇ‘{¶«¡Ç’[å»ÛÁØ"); + + JS::RootedValue v1(cx); + ScriptInterface::ToJSVal(cx, &v1, in_utf8); + + std::wstring test_out_utf16; + TS_ASSERT(ScriptInterface::FromJSVal(cx, v1, test_out_utf16)); + TS_ASSERT_EQUALS(test_out_utf16, in_utf16); + // Start clean. + ScriptInterface::ToJSVal(cx, &v1, in_utf16); + std::string test_out_utf8; + TS_ASSERT(ScriptInterface::FromJSVal(cx, v1, test_out_utf8)); + TS_ASSERT_EQUALS(test_out_utf8, in_utf8); + } + } };