LCOV - code coverage report
Current view: top level - source/scriptinterface - ScriptConversions.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 35 55 63.6 %
Date: 2023-01-19 00:18:29 Functions: 6 47 12.8 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #ifndef INCLUDED_SCRIPTCONVERSIONS
      19             : #define INCLUDED_SCRIPTCONVERSIONS
      20             : 
      21             : #include "ScriptRequest.h"
      22             : #include "ScriptExceptions.h"
      23             : #include "ScriptExtraHeaders.h" // for typed arrays
      24             : 
      25             : #include <limits>
      26             : #include <vector>
      27             : 
      28             : namespace Script
      29             : {
      30             : /**
      31             :  * Convert a JS::Value to a C++ type. (This might trigger GC.)
      32             :  */
      33             : template<typename T> bool FromJSVal(const ScriptRequest& rq, const JS::HandleValue val, T& ret);
      34             : 
      35             : /**
      36             :  * Convert a C++ type to a JS::Value. (This might trigger GC. The return
      37             :  * value must be rooted if you don't want it to be collected.)
      38             :  * NOTE: We are passing the JS::Value by reference instead of returning it by value.
      39             :  * The reason is a memory corruption problem that appears to be caused by a bug in Visual Studio.
      40             :  * Details here: http://www.wildfiregames.com/forum/index.php?showtopic=17289&p=285921
      41             :  */
      42             : template<typename T> void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, T const& val);
      43             : 
      44             : template<>
      45           3 : inline void ToJSVal<JS::PersistentRootedValue>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::PersistentRootedValue& a)
      46             : {
      47           3 :     handle.set(a);
      48           3 : }
      49             : 
      50             : template<>
      51           0 : inline void ToJSVal<JS::Heap<JS::Value> >(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::Heap<JS::Value>& a)
      52             : {
      53           0 :     handle.set(a);
      54           0 : }
      55             : 
      56             : template<>
      57          69 : inline void ToJSVal<JS::RootedValue>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::RootedValue& a)
      58             : {
      59          69 :     handle.set(a);
      60          69 : }
      61             : 
      62             : template <>
      63          84 : inline void ToJSVal<JS::HandleValue>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::HandleValue& a)
      64             : {
      65          84 :     handle.set(a);
      66          84 : }
      67             : 
      68             : /**
      69             :  * Convert a named property of an object to a C++ type.
      70             :  */
      71         170 : template<typename T> inline bool FromJSProperty(const ScriptRequest& rq, const JS::HandleValue val, const char* name, T& ret, bool strict = false)
      72             : {
      73         170 :     if (!val.isObject())
      74           4 :         return false;
      75             : 
      76         332 :     JS::RootedObject obj(rq.cx, &val.toObject());
      77             : 
      78             :     bool hasProperty;
      79         166 :     if (!JS_HasProperty(rq.cx, obj, name, &hasProperty) || !hasProperty)
      80          13 :         return false;
      81             : 
      82         306 :     JS::RootedValue value(rq.cx);
      83         153 :     if (!JS_GetProperty(rq.cx, obj, name, &value))
      84           0 :         return false;
      85             : 
      86         153 :     if (strict && value.isNull())
      87           7 :         return false;
      88             : 
      89         146 :     return FromJSVal(rq, value, ret);
      90             : }
      91             : 
      92           0 : template<typename T> inline void ToJSVal_vector(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::vector<T>& val)
      93             : {
      94           0 :     JS::RootedObject obj(rq.cx, JS::NewArrayObject(rq.cx, 0));
      95           0 :     if (!obj)
      96             :     {
      97           0 :         ret.setUndefined();
      98           0 :         return;
      99             :     }
     100             : 
     101           0 :     ENSURE(val.size() <= std::numeric_limits<u32>::max());
     102           0 :     for (u32 i = 0; i < val.size(); ++i)
     103             :     {
     104           0 :         JS::RootedValue el(rq.cx);
     105           0 :         Script::ToJSVal<T>(rq, &el, val[i]);
     106           0 :         JS_SetElement(rq.cx, obj, i, el);
     107             :     }
     108           0 :     ret.setObject(*obj);
     109             : }
     110             : 
     111             : #define FAIL(msg) STMT(ScriptException::Raise(rq, msg); return false)
     112             : 
     113           6 : template<typename T> inline bool FromJSVal_vector(const ScriptRequest& rq, JS::HandleValue v, std::vector<T>& out)
     114             : {
     115          12 :     JS::RootedObject obj(rq.cx);
     116           6 :     if (!v.isObject())
     117           0 :         FAIL("Argument must be an array");
     118             : 
     119             :     bool isArray;
     120           6 :     obj = &v.toObject();
     121           6 :     if ((!JS::IsArrayObject(rq.cx, obj, &isArray) || !isArray) && !JS_IsTypedArrayObject(obj))
     122           0 :         FAIL("Argument must be an array");
     123             : 
     124             :     u32 length;
     125           6 :     if (!JS::GetArrayLength(rq.cx, obj, &length))
     126           0 :         FAIL("Failed to get array length");
     127             : 
     128           6 :     out.clear();
     129           6 :     out.reserve(length);
     130           7 :     for (u32 i = 0; i < length; ++i)
     131             :     {
     132           2 :         JS::RootedValue el(rq.cx);
     133           1 :         if (!JS_GetElement(rq.cx, obj, i, &el))
     134           0 :             FAIL("Failed to read array element");
     135           2 :         T el2;
     136           1 :         if (!Script::FromJSVal<T>(rq, el, el2))
     137           0 :             return false;
     138           1 :         out.push_back(el2);
     139             :     }
     140           6 :     return true;
     141             : }
     142             : 
     143             : #undef FAIL
     144             : 
     145             : #define JSVAL_VECTOR(T) \
     146             : template<> void Script::ToJSVal<std::vector<T> >(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::vector<T>& val) \
     147             : { \
     148             :     ToJSVal_vector(rq, ret, val); \
     149             : } \
     150             : template<> bool Script::FromJSVal<std::vector<T> >(const ScriptRequest& rq, JS::HandleValue v, std::vector<T>& out) \
     151             : { \
     152             :     return FromJSVal_vector(rq, v, out); \
     153             : }
     154             : 
     155             : } // namespace Script
     156             : 
     157             : #endif //INCLUDED_SCRIPTCONVERSIONS

Generated by: LCOV version 1.13