Changeset View
Changeset View
Standalone View
Standalone View
source/scriptinterface/ScriptConversions.cpp
Show All 18 Lines | |||||
#include "ScriptConversions.h" | #include "ScriptConversions.h" | ||||
#include "graphics/Entity.h" | #include "graphics/Entity.h" | ||||
#include "maths/Vector2D.h" | #include "maths/Vector2D.h" | ||||
#include "ps/utf16string.h" | #include "ps/utf16string.h" | ||||
#include "ps/CStr.h" | #include "ps/CStr.h" | ||||
#define FAIL(msg) STMT(JS_ReportError(rq.cx, msg); return false) | #define FAIL(msg) STMT(LOGERROR(msg); return false) | ||||
// Implicit type conversions often hide bugs, so warn about them | // Implicit type conversions often hide bugs, so warn about them | ||||
#define WARN_IF_NOT(c, v) STMT(if (!(c)) { JS_ReportWarning(rq.cx, "Script value conversion check failed: %s (got type %s)", #c, InformalValueTypeName(v)); }) | #define WARN_IF_NOT(c, v) STMT(if (!(c)) { JS_ReportWarning(rq.cx, "Script value conversion check failed: %s (got type %s)", #c, InformalValueTypeName(v)); }) | ||||
// TODO: SpiderMonkey: Follow upstream progresses about JS_InformalValueTypeName in the API | // TODO: SpiderMonkey: Follow upstream progresses about JS_InformalValueTypeName in the API | ||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1285917 | // https://bugzilla.mozilla.org/show_bug.cgi?id=1285917 | ||||
static const char* InformalValueTypeName(const JS::Value& v) | static const char* InformalValueTypeName(const JS::Value& v) | ||||
{ | { | ||||
Show All 9 Lines | if (v.isBoolean()) | ||||
return "boolean"; | return "boolean"; | ||||
if (v.isNull()) | if (v.isNull()) | ||||
return "null"; | return "null"; | ||||
if (v.isUndefined()) | if (v.isUndefined()) | ||||
return "undefined"; | return "undefined"; | ||||
return "value"; | return "value"; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<bool>(const Request& rq, JS::HandleValue v, bool& out) | template<> bool ScriptInterface::FromJSVal<bool>(const ScriptRequest& rq, JS::HandleValue v, bool& out) | ||||
{ | { | ||||
WARN_IF_NOT(v.isBoolean(), v); | WARN_IF_NOT(v.isBoolean(), v); | ||||
out = JS::ToBoolean(v); | out = JS::ToBoolean(v); | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<float>(const Request& rq, JS::HandleValue v, float& out) | template<> bool ScriptInterface::FromJSVal<float>(const ScriptRequest& rq, JS::HandleValue v, float& out) | ||||
{ | { | ||||
double tmp; | double tmp; | ||||
WARN_IF_NOT(v.isNumber(), v); | WARN_IF_NOT(v.isNumber(), v); | ||||
if (!JS::ToNumber(rq.cx, v, &tmp)) | if (!JS::ToNumber(rq.cx, v, &tmp)) | ||||
return false; | return false; | ||||
out = tmp; | out = tmp; | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<double>(const Request& rq, JS::HandleValue v, double& out) | template<> bool ScriptInterface::FromJSVal<double>(const ScriptRequest& rq, JS::HandleValue v, double& out) | ||||
{ | { | ||||
WARN_IF_NOT(v.isNumber(), v); | WARN_IF_NOT(v.isNumber(), v); | ||||
if (!JS::ToNumber(rq.cx, v, &out)) | if (!JS::ToNumber(rq.cx, v, &out)) | ||||
return false; | return false; | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<i32>(const Request& rq, JS::HandleValue v, i32& out) | template<> bool ScriptInterface::FromJSVal<i32>(const ScriptRequest& rq, JS::HandleValue v, i32& out) | ||||
{ | { | ||||
WARN_IF_NOT(v.isNumber(), v); | WARN_IF_NOT(v.isNumber(), v); | ||||
if (!JS::ToInt32(rq.cx, v, &out)) | if (!JS::ToInt32(rq.cx, v, &out)) | ||||
return false; | return false; | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<u32>(const Request& rq, JS::HandleValue v, u32& out) | template<> bool ScriptInterface::FromJSVal<u32>(const ScriptRequest& rq, JS::HandleValue v, u32& out) | ||||
{ | { | ||||
WARN_IF_NOT(v.isNumber(), v); | WARN_IF_NOT(v.isNumber(), v); | ||||
if (!JS::ToUint32(rq.cx, v, &out)) | if (!JS::ToUint32(rq.cx, v, &out)) | ||||
return false; | return false; | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<u16>(const Request& rq, JS::HandleValue v, u16& out) | template<> bool ScriptInterface::FromJSVal<u16>(const ScriptRequest& rq, JS::HandleValue v, u16& out) | ||||
{ | { | ||||
WARN_IF_NOT(v.isNumber(), v); | WARN_IF_NOT(v.isNumber(), v); | ||||
if (!JS::ToUint16(rq.cx, v, &out)) | if (!JS::ToUint16(rq.cx, v, &out)) | ||||
return false; | return false; | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<u8>(const Request& rq, JS::HandleValue v, u8& out) | template<> bool ScriptInterface::FromJSVal<u8>(const ScriptRequest& rq, JS::HandleValue v, u8& out) | ||||
{ | { | ||||
u16 tmp; | u16 tmp; | ||||
WARN_IF_NOT(v.isNumber(), v); | WARN_IF_NOT(v.isNumber(), v); | ||||
if (!JS::ToUint16(rq.cx, v, &tmp)) | if (!JS::ToUint16(rq.cx, v, &tmp)) | ||||
return false; | return false; | ||||
out = (u8)tmp; | out = (u8)tmp; | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<std::wstring>(const Request& rq, JS::HandleValue v, std::wstring& out) | template<> bool ScriptInterface::FromJSVal<std::wstring>(const ScriptRequest& rq, JS::HandleValue v, std::wstring& out) | ||||
{ | { | ||||
WARN_IF_NOT(v.isString() || v.isNumber(), v); // allow implicit number conversions | WARN_IF_NOT(v.isString() || v.isNumber(), v); // allow implicit number conversions | ||||
JS::RootedString str(rq.cx, JS::ToString(rq.cx, v)); | JS::RootedString str(rq.cx, JS::ToString(rq.cx, v)); | ||||
if (!str) | if (!str) | ||||
FAIL("Argument must be convertible to a string"); | FAIL("Argument must be convertible to a string"); | ||||
if (JS_StringHasLatin1Chars(str)) | if (JS_StringHasLatin1Chars(str)) | ||||
{ | { | ||||
Show All 13 Lines | else | ||||
if (!ch) | if (!ch) | ||||
FAIL("JS_GetTwoByteStringsCharsAndLength failed"); // out of memory | FAIL("JS_GetTwoByteStringsCharsAndLength failed"); // out of memory | ||||
out.assign(ch, ch + length); | out.assign(ch, ch + length); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<Path>(const Request& rq, JS::HandleValue v, Path& out) | template<> bool ScriptInterface::FromJSVal<Path>(const ScriptRequest& rq, JS::HandleValue v, Path& out) | ||||
{ | { | ||||
std::wstring string; | std::wstring string; | ||||
if (!FromJSVal(rq, v, string)) | if (!FromJSVal(rq, v, string)) | ||||
return false; | return false; | ||||
out = string; | out = string; | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<std::string>(const Request& rq, JS::HandleValue v, std::string& out) | template<> bool ScriptInterface::FromJSVal<std::string>(const ScriptRequest& rq, JS::HandleValue v, std::string& out) | ||||
{ | { | ||||
std::wstring wideout; | std::wstring wideout; | ||||
if (!FromJSVal(rq, v, wideout)) | if (!FromJSVal(rq, v, wideout)) | ||||
return false; | return false; | ||||
out = CStrW(wideout).ToUTF8(); | out = CStrW(wideout).ToUTF8(); | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<CStr8>(const Request& rq, JS::HandleValue v, CStr8& out) | template<> bool ScriptInterface::FromJSVal<CStr8>(const ScriptRequest& rq, JS::HandleValue v, CStr8& out) | ||||
{ | { | ||||
return ScriptInterface::FromJSVal(rq, v, static_cast<std::string&>(out)); | return ScriptInterface::FromJSVal(rq, v, static_cast<std::string&>(out)); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<CStrW>(const Request& rq, JS::HandleValue v, CStrW& out) | template<> bool ScriptInterface::FromJSVal<CStrW>(const ScriptRequest& rq, JS::HandleValue v, CStrW& out) | ||||
{ | { | ||||
return ScriptInterface::FromJSVal(rq, v, static_cast<std::wstring&>(out)); | return ScriptInterface::FromJSVal(rq, v, static_cast<std::wstring&>(out)); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<Entity>(const Request& rq, JS::HandleValue v, Entity& out) | template<> bool ScriptInterface::FromJSVal<Entity>(const ScriptRequest& rq, JS::HandleValue v, Entity& out) | ||||
{ | { | ||||
if (!v.isObject()) | if (!v.isObject()) | ||||
FAIL("Argument must be an object"); | FAIL("Argument must be an object"); | ||||
JS::RootedObject obj(rq.cx, &v.toObject()); | JS::RootedObject obj(rq.cx, &v.toObject()); | ||||
JS::RootedValue templateName(rq.cx); | JS::RootedValue templateName(rq.cx); | ||||
JS::RootedValue id(rq.cx); | JS::RootedValue id(rq.cx); | ||||
JS::RootedValue player(rq.cx); | JS::RootedValue player(rq.cx); | ||||
Show All 13 Lines | if (!JS_GetProperty(rq.cx, obj, "rotation", &rotation) || !FromJSVal(rq, rotation, out.rotation)) | ||||
FAIL("Failed to read Entity.rotation property"); | FAIL("Failed to read Entity.rotation property"); | ||||
return true; | return true; | ||||
} | } | ||||
//////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////// | ||||
// Primitive types: | // Primitive types: | ||||
template<> void ScriptInterface::ToJSVal<bool>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const bool& val) | template<> void ScriptInterface::ToJSVal<bool>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const bool& val) | ||||
{ | { | ||||
ret.setBoolean(val); | ret.setBoolean(val); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<float>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const float& val) | template<> void ScriptInterface::ToJSVal<float>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const float& val) | ||||
{ | { | ||||
ret.set(JS::NumberValue(val)); | ret.set(JS::NumberValue(val)); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<double>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const double& val) | template<> void ScriptInterface::ToJSVal<double>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const double& val) | ||||
{ | { | ||||
ret.set(JS::NumberValue(val)); | ret.set(JS::NumberValue(val)); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<i32>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const i32& val) | template<> void ScriptInterface::ToJSVal<i32>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const i32& val) | ||||
{ | { | ||||
ret.set(JS::NumberValue(val)); | ret.set(JS::NumberValue(val)); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<u16>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u16& val) | template<> void ScriptInterface::ToJSVal<u16>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const u16& val) | ||||
{ | { | ||||
ret.set(JS::NumberValue(val)); | ret.set(JS::NumberValue(val)); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<u8>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u8& val) | template<> void ScriptInterface::ToJSVal<u8>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const u8& val) | ||||
{ | { | ||||
ret.set(JS::NumberValue(val)); | ret.set(JS::NumberValue(val)); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<u32>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u32& val) | template<> void ScriptInterface::ToJSVal<u32>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const u32& val) | ||||
{ | { | ||||
ret.set(JS::NumberValue(val)); | ret.set(JS::NumberValue(val)); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<std::wstring>(const Request& rq, JS::MutableHandleValue ret, const std::wstring& val) | template<> void ScriptInterface::ToJSVal<std::wstring>(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::wstring& val) | ||||
{ | { | ||||
utf16string utf16(val.begin(), val.end()); | utf16string utf16(val.begin(), val.end()); | ||||
JS::RootedString str(rq.cx, JS_NewUCStringCopyN(rq.cx, reinterpret_cast<const char16_t*> (utf16.c_str()), utf16.length())); | JS::RootedString str(rq.cx, JS_NewUCStringCopyN(rq.cx, reinterpret_cast<const char16_t*> (utf16.c_str()), utf16.length())); | ||||
if (str) | if (str) | ||||
ret.setString(str); | ret.setString(str); | ||||
else | else | ||||
ret.setUndefined(); | ret.setUndefined(); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<Path>(const Request& rq, JS::MutableHandleValue ret, const Path& val) | template<> void ScriptInterface::ToJSVal<Path>(const ScriptRequest& rq, JS::MutableHandleValue ret, const Path& val) | ||||
{ | { | ||||
ToJSVal(rq, ret, val.string()); | ToJSVal(rq, ret, val.string()); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<std::string>(const Request& rq, JS::MutableHandleValue ret, const std::string& val) | template<> void ScriptInterface::ToJSVal<std::string>(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::string& val) | ||||
{ | { | ||||
ToJSVal(rq, ret, static_cast<const std::wstring>(CStr(val).FromUTF8())); | ToJSVal(rq, ret, static_cast<const std::wstring>(CStr(val).FromUTF8())); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<const wchar_t*>(const Request& rq, JS::MutableHandleValue ret, const wchar_t* const& val) | template<> void ScriptInterface::ToJSVal<const wchar_t*>(const ScriptRequest& rq, JS::MutableHandleValue ret, const wchar_t* const& val) | ||||
{ | { | ||||
ToJSVal(rq, ret, std::wstring(val)); | ToJSVal(rq, ret, std::wstring(val)); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<const char*>(const Request& rq, JS::MutableHandleValue ret, const char* const& val) | template<> void ScriptInterface::ToJSVal<const char*>(const ScriptRequest& rq, JS::MutableHandleValue ret, const char* const& val) | ||||
{ | { | ||||
JS::RootedString str(rq.cx, JS_NewStringCopyZ(rq.cx, val)); | JS::RootedString str(rq.cx, JS_NewStringCopyZ(rq.cx, val)); | ||||
if (str) | if (str) | ||||
ret.setString(str); | ret.setString(str); | ||||
else | else | ||||
ret.setUndefined(); | ret.setUndefined(); | ||||
} | } | ||||
#define TOJSVAL_CHAR(N) \ | #define TOJSVAL_CHAR(N) \ | ||||
template<> void ScriptInterface::ToJSVal<wchar_t[N]>(const Request& rq, JS::MutableHandleValue ret, const wchar_t (&val)[N]) \ | template<> void ScriptInterface::ToJSVal<wchar_t[N]>(const ScriptRequest& rq, JS::MutableHandleValue ret, const wchar_t (&val)[N]) \ | ||||
{ \ | { \ | ||||
ToJSVal(rq, ret, static_cast<const wchar_t*>(val)); \ | ToJSVal(rq, ret, static_cast<const wchar_t*>(val)); \ | ||||
} \ | } \ | ||||
template<> void ScriptInterface::ToJSVal<char[N]>(const Request& rq, JS::MutableHandleValue ret, const char (&val)[N]) \ | template<> void ScriptInterface::ToJSVal<char[N]>(const ScriptRequest& rq, JS::MutableHandleValue ret, const char (&val)[N]) \ | ||||
{ \ | { \ | ||||
ToJSVal(rq, ret, static_cast<const char*>(val)); \ | ToJSVal(rq, ret, static_cast<const char*>(val)); \ | ||||
} | } | ||||
TOJSVAL_CHAR(3) | TOJSVAL_CHAR(3) | ||||
TOJSVAL_CHAR(5) | TOJSVAL_CHAR(5) | ||||
TOJSVAL_CHAR(6) | TOJSVAL_CHAR(6) | ||||
TOJSVAL_CHAR(7) | TOJSVAL_CHAR(7) | ||||
Show All 12 Lines | |||||
TOJSVAL_CHAR(20) | TOJSVAL_CHAR(20) | ||||
TOJSVAL_CHAR(24) | TOJSVAL_CHAR(24) | ||||
TOJSVAL_CHAR(29) | TOJSVAL_CHAR(29) | ||||
TOJSVAL_CHAR(33) | TOJSVAL_CHAR(33) | ||||
TOJSVAL_CHAR(35) | TOJSVAL_CHAR(35) | ||||
TOJSVAL_CHAR(256) | TOJSVAL_CHAR(256) | ||||
#undef TOJSVAL_CHAR | #undef TOJSVAL_CHAR | ||||
template<> void ScriptInterface::ToJSVal<CStrW>(const Request& rq, JS::MutableHandleValue ret, const CStrW& val) | template<> void ScriptInterface::ToJSVal<CStrW>(const ScriptRequest& rq, JS::MutableHandleValue ret, const CStrW& val) | ||||
{ | { | ||||
ToJSVal(rq, ret, static_cast<const std::wstring&>(val)); | ToJSVal(rq, ret, static_cast<const std::wstring&>(val)); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<CStr8>(const Request& rq, JS::MutableHandleValue ret, const CStr8& val) | template<> void ScriptInterface::ToJSVal<CStr8>(const ScriptRequest& rq, JS::MutableHandleValue ret, const CStr8& val) | ||||
{ | { | ||||
ToJSVal(rq, ret, static_cast<const std::string&>(val)); | ToJSVal(rq, ret, static_cast<const std::string&>(val)); | ||||
} | } | ||||
//////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////// | ||||
// Compound types | // Compound types | ||||
// Instantiate various vector types: | // Instantiate various vector types: | ||||
JSVAL_VECTOR(int) | JSVAL_VECTOR(int) | ||||
JSVAL_VECTOR(u32) | JSVAL_VECTOR(u32) | ||||
JSVAL_VECTOR(u16) | JSVAL_VECTOR(u16) | ||||
JSVAL_VECTOR(std::string) | JSVAL_VECTOR(std::string) | ||||
JSVAL_VECTOR(std::wstring) | JSVAL_VECTOR(std::wstring) | ||||
JSVAL_VECTOR(std::vector<std::wstring>) | JSVAL_VECTOR(std::vector<std::wstring>) | ||||
JSVAL_VECTOR(CStr8) | JSVAL_VECTOR(CStr8) | ||||
JSVAL_VECTOR(std::vector<CStr8>) | JSVAL_VECTOR(std::vector<CStr8>) | ||||
JSVAL_VECTOR(std::vector<std::string>) | JSVAL_VECTOR(std::vector<std::string>) | ||||
class IComponent; | class IComponent; | ||||
template<> void ScriptInterface::ToJSVal<std::vector<IComponent*> >(const Request& rq, JS::MutableHandleValue ret, const std::vector<IComponent*>& val) | template<> void ScriptInterface::ToJSVal<std::vector<IComponent*> >(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::vector<IComponent*>& val) | ||||
{ | { | ||||
ToJSVal_vector(rq, ret, val); | ToJSVal_vector(rq, ret, val); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<std::vector<Entity> >(const Request& rq, JS::HandleValue v, std::vector<Entity>& out) | template<> bool ScriptInterface::FromJSVal<std::vector<Entity> >(const ScriptRequest& rq, JS::HandleValue v, std::vector<Entity>& out) | ||||
{ | { | ||||
return FromJSVal_vector(rq, v, out); | return FromJSVal_vector(rq, v, out); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<CVector2D>(const Request& rq, JS::MutableHandleValue ret, const CVector2D& val) | template<> void ScriptInterface::ToJSVal<CVector2D>(const ScriptRequest& rq, JS::MutableHandleValue ret, const CVector2D& val) | ||||
{ | { | ||||
std::vector<float> vec = {val.X, val.Y}; | std::vector<float> vec = {val.X, val.Y}; | ||||
ToJSVal_vector(rq, ret, vec); | ToJSVal_vector(rq, ret, vec); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<CVector2D>(const Request& rq, JS::HandleValue v, CVector2D& out) | template<> bool ScriptInterface::FromJSVal<CVector2D>(const ScriptRequest& rq, JS::HandleValue v, CVector2D& out) | ||||
{ | { | ||||
std::vector<float> vec; | std::vector<float> vec; | ||||
if (!FromJSVal_vector(rq, v, vec)) | if (!FromJSVal_vector(rq, v, vec)) | ||||
return false; | return false; | ||||
if (vec.size() != 2) | if (vec.size() != 2) | ||||
return false; | return false; | ||||
Show All 9 Lines |
Wildfire Games · Phabricator