Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/serialization/StdDeserializer.cpp
Show All 13 Lines | |||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "precompiled.h" | #include "precompiled.h" | ||||
#include "StdDeserializer.h" | #include "StdDeserializer.h" | ||||
#include "SerializedScriptTypes.h" | #include "lib/byte_order.h" | ||||
#include "StdSerializer.h" // for DEBUG_SERIALIZER_ANNOTATE | #include "ps/CStr.h" | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include "scriptinterface/ScriptExtraHeaders.h" // For typed arrays and ArrayBuffer | #include "scriptinterface/ScriptExtraHeaders.h" // For typed arrays and ArrayBuffer | ||||
#include "simulation2/serialization/ISerializer.h" | |||||
#include "lib/byte_order.h" | #include "simulation2/serialization/SerializedScriptTypes.h" | ||||
#include "simulation2/serialization/StdSerializer.h" // for DEBUG_SERIALIZER_ANNOTATE | |||||
CStdDeserializer::CStdDeserializer(const ScriptInterface& scriptInterface, std::istream& stream) : | CStdDeserializer::CStdDeserializer(const ScriptInterface& scriptInterface, std::istream& stream) : | ||||
m_ScriptInterface(scriptInterface), m_Stream(stream) | m_ScriptInterface(scriptInterface), m_Stream(stream) | ||||
{ | { | ||||
JS_AddExtraGCRootsTracer(m_ScriptInterface.GetGeneralJSContext(), CStdDeserializer::Trace, this); | JS_AddExtraGCRootsTracer(m_ScriptInterface.GetGeneralJSContext(), CStdDeserializer::Trace, this); | ||||
} | } | ||||
CStdDeserializer::~CStdDeserializer() | CStdDeserializer::~CStdDeserializer() | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
void CStdDeserializer::GetScriptBackref(size_t tag, JS::MutableHandleObject ret) | void CStdDeserializer::GetScriptBackref(size_t tag, JS::MutableHandleObject ret) | ||||
{ | { | ||||
ENSURE(m_ScriptBackrefs.size() > tag); | ENSURE(m_ScriptBackrefs.size() > tag); | ||||
ret.set(m_ScriptBackrefs[tag]); | ret.set(m_ScriptBackrefs[tag]); | ||||
} | } | ||||
//////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////// | ||||
JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject appendParent) | JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject preexistingObject) | ||||
{ | { | ||||
ScriptRequest rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
uint8_t type; | uint8_t type; | ||||
NumberU8_Unbounded("type", type); | NumberU8_Unbounded("type", type); | ||||
switch (type) | switch (type) | ||||
{ | { | ||||
case SCRIPT_TYPE_VOID: | case SCRIPT_TYPE_VOID: | ||||
return JS::UndefinedValue(); | return JS::UndefinedValue(); | ||||
case SCRIPT_TYPE_NULL: | case SCRIPT_TYPE_NULL: | ||||
return JS::NullValue(); | return JS::NullValue(); | ||||
case SCRIPT_TYPE_ARRAY: | case SCRIPT_TYPE_ARRAY: | ||||
case SCRIPT_TYPE_OBJECT: | case SCRIPT_TYPE_OBJECT: | ||||
case SCRIPT_TYPE_OBJECT_PROTOTYPE: | |||||
{ | { | ||||
JS::RootedObject obj(rq.cx); | JS::RootedObject obj(rq.cx); | ||||
if (appendParent) | if (type == SCRIPT_TYPE_ARRAY) | ||||
{ | |||||
obj.set(appendParent); | |||||
} | |||||
else if (type == SCRIPT_TYPE_ARRAY) | |||||
{ | { | ||||
u32 length; | u32 length; | ||||
NumberU32_Unbounded("array length", length); | NumberU32_Unbounded("array length", length); | ||||
obj.set(JS::NewArrayObject(rq.cx, length)); | obj.set(JS::NewArrayObject(rq.cx, length)); | ||||
} | } | ||||
else // SCRIPT_TYPE_OBJECT | else if (type == SCRIPT_TYPE_OBJECT) | ||||
{ | { | ||||
obj.set(JS_NewPlainObject(rq.cx)); | obj.set(JS_NewPlainObject(rq.cx)); | ||||
} | } | ||||
else // SCRIPT_TYPE_OBJECT_PROTOTYPE | |||||
{ | |||||
CStrW prototypeName; | |||||
String("proto", prototypeName, 0, 256); | |||||
// If an object was passed, no need to construct a new one. | |||||
if (preexistingObject != nullptr) | |||||
obj.set(preexistingObject); | |||||
else | |||||
{ | |||||
JS::RootedValue constructor(rq.cx); | |||||
if (!ScriptInterface::GetGlobalProperty(rq, prototypeName.ToUTF8(), &constructor)) | |||||
throw PSERROR_Deserialize_ScriptError("Deserializer failed to get constructor object"); | |||||
JS::RootedObject newObj(rq.cx); | |||||
if (!JS::Construct(rq.cx, constructor, JS::HandleValueArray::empty(), &newObj)) | |||||
throw PSERROR_Deserialize_ScriptError("Deserializer failed to construct object"); | |||||
obj.set(newObj); | |||||
} | |||||
JS::RootedObject prototype(rq.cx); | |||||
JS_GetPrototype(rq.cx, obj, &prototype); | |||||
SPrototypeSerialization info = GetPrototypeInfo(rq, prototype); | |||||
if (preexistingObject != nullptr && prototypeName != wstring_from_utf8(info.name)) | |||||
throw PSERROR_Deserialize_ScriptError("Deserializer failed: incorrect pre-existing object"); | |||||
if (info.hasCustomDeserialize) | |||||
{ | |||||
AddScriptBackref(obj); | |||||
// If Serialize is null, we'll still call Deserialize but with undefined argument | |||||
JS::RootedValue data(rq.cx); | |||||
if (!info.hasNullSerialize) | |||||
ScriptVal("data", &data); | |||||
JS::RootedValue objVal(rq.cx, JS::ObjectValue(*obj)); | |||||
m_ScriptInterface.CallFunctionVoid(objVal, "Deserialize", data); | |||||
return JS::ObjectValue(*obj); | |||||
} | |||||
else if (info.hasNullSerialize) | |||||
{ | |||||
// If we serialized null, this means we're pretty much a default-constructed object. | |||||
// Nothing to do. | |||||
AddScriptBackref(obj); | |||||
return JS::ObjectValue(*obj); | |||||
} | |||||
} | |||||
if (!obj) | if (!obj) | ||||
throw PSERROR_Deserialize_ScriptError("Deserializer failed to create new object"); | throw PSERROR_Deserialize_ScriptError("Deserializer failed to create new object"); | ||||
AddScriptBackref(obj); | AddScriptBackref(obj); | ||||
uint32_t numProps; | uint32_t numProps; | ||||
NumberU32_Unbounded("num props", numProps); | NumberU32_Unbounded("num props", numProps); | ||||
▲ Show 20 Lines • Show All 273 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
} | } | ||||
void CStdDeserializer::ScriptVal(const char* name, JS::MutableHandleValue out) | void CStdDeserializer::ScriptVal(const char* name, JS::MutableHandleValue out) | ||||
{ | { | ||||
out.set(ReadScriptVal(name, nullptr)); | out.set(ReadScriptVal(name, nullptr)); | ||||
} | } | ||||
void CStdDeserializer::ScriptObjectAppend(const char* name, JS::HandleValue objVal) | void CStdDeserializer::ScriptObjectAssign(const char* name, JS::HandleValue objVal) | ||||
{ | { | ||||
ScriptRequest rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
if (!objVal.isObject()) | if (!objVal.isObject()) | ||||
throw PSERROR_Deserialize_ScriptError(); | throw PSERROR_Deserialize_ScriptError(); | ||||
JS::RootedObject obj(rq.cx, &objVal.toObject()); | JS::RootedObject obj(rq.cx, &objVal.toObject()); | ||||
ReadScriptVal(name, obj); | ReadScriptVal(name, obj); | ||||
} | } |
Wildfire Games · Phabricator