1
0
forked from 0ad/0ad

Fix conversion of UTF8 strings between the scripts and the engine.

SpiderMonkey uses UTF16 internally, and only provides APIs for that
encoding, so stop hacking UTF8 strings: properly convert them to and
from UTF16 when passing them through SM.

Patch By: wraitii
Differential Revision: https://code.wildfiregames.com/D2838
This was SVN commit r23795.
This commit is contained in:
Nicolas Auvray 2020-06-30 10:46:06 +00:00
parent dc65912043
commit 56d3aa40fe
2 changed files with 32 additions and 19 deletions

View File

@ -158,16 +158,10 @@ template<> bool ScriptInterface::FromJSVal<Path>(JSContext* cx, JS::HandleValue
template<> bool ScriptInterface::FromJSVal<std::string>(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<Path>(JSContext* cx, JS::MutableHandleV
template<> void ScriptInterface::ToJSVal<std::string>(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<const std::wstring>(CStr(val).FromUTF8()));
}
template<> void ScriptInterface::ToJSVal<const wchar_t*>(JSContext* cx, JS::MutableHandleValue ret, const wchar_t* const& val)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -148,9 +148,9 @@ public:
roundtrip<std::string>("", "\"\"");
roundtrip<std::string>("test", "\"test\"");
roundtrip<std::string>("тест", "\"\\xD1\\x82\\xD0\\xB5\\xD1\\x81\\xD1\\x82\"");
roundtrip<std::string>("тест", "\"\\u0442\\u0435\\u0441\\u0442\"");
roundtrip<std::string>(s1, "\"t\\x00st\"");
roundtrip<std::string>(s2, "\"\\xD1\\x82\\x00\\x00\\xD1\\x81\\xD1\\x82\"");
roundtrip<std::string>(s2, "\"\\u0442\\x00\\x00\\u0441\\u0442\"");
roundtrip<std::wstring>(L"", "\"\"");
roundtrip<std::wstring>(L"test", "\"test\"");
@ -251,4 +251,28 @@ public:
CFixedVector3D u(fixed::Pi(), fixed::Zero(), fixed::FromInt(2));
call_prototype_function<CFixedVector3D>(u, v, "add", "({x:3.1415863037109375, y:3.1415863037109375, z:3})");
}
void test_utf8utf16_conversion()
{
// Fancier conversion: we store UTF8 and get UTF16 and vice-versa
ScriptInterface script("Test", "Test", g_ScriptRuntime);
TS_ASSERT(script.LoadGlobalScripts());
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
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);
JS::RootedValue v2(cx);
ScriptInterface::ToJSVal(cx, &v2, in_utf16);
std::string test_out_utf8;
TS_ASSERT(ScriptInterface::FromJSVal(cx, v2, test_out_utf8));
TS_ASSERT_EQUALS(test_out_utf8, in_utf8);
}
};