diff options
author | Maya <malte.hoermeyer@web.de> | 2022-07-21 02:54:00 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-21 02:54:00 +0200 |
commit | 938d89713eb055340b5e8866de3000b61e4a0f13 (patch) | |
tree | 65c266a244c27ff47ec0f4086a15a97a099ee493 /NorthstarDedicatedTest/scriptjson.cpp | |
parent | d20cf6f08af37830d3bfc934cef356fa6a1aa102 (diff) | |
download | NorthstarLauncher-938d89713eb055340b5e8866de3000b61e4a0f13.tar.gz NorthstarLauncher-938d89713eb055340b5e8866de3000b61e4a0f13.zip |
Implemented Json into the squirrel vm (#172)
* Implemented Json into the squirrel vm
* Formatting
* More Formatting
* Even more Formatting
* Added Init functions to dllMain
* Formatting
* Changed to use Source Allocator
* Renaming Part 1
* Renaming Part 2
Diffstat (limited to 'NorthstarDedicatedTest/scriptjson.cpp')
-rw-r--r-- | NorthstarDedicatedTest/scriptjson.cpp | 609 |
1 files changed, 609 insertions, 0 deletions
diff --git a/NorthstarDedicatedTest/scriptjson.cpp b/NorthstarDedicatedTest/scriptjson.cpp new file mode 100644 index 00000000..220f4968 --- /dev/null +++ b/NorthstarDedicatedTest/scriptjson.cpp @@ -0,0 +1,609 @@ +#include "pch.h" +#include "scriptJson.h" +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" + +#include "squirrel.h" + +#ifdef _MSC_VER +#undef GetObject // fuck microsoft developers +#endif + +void SQ_EncodeJSON_Table( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, + SQTable* sqTable, + rapidjson_document* allocatorDoc); +void SQ_EncodeJSON_Array( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, + SQArray* sqArray, + rapidjson_document* allocatorDoc); +void ServerSq_DecodeJSON_Table( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj); +void ServerSq_DecodeJSON_Array( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr); +void ClientSq_DecodeJSON_Table( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj); +void ClientSq_DecodeJSON_Array( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr); + +SQRESULT ServerSq_DecodeJSON(void* sqvm) +{ + const char* json = ServerSq_getstring(sqvm, 1); + rapidjson_document doc; + doc.Parse(json); + if (doc.HasParseError()) + { + ServerSq_newTable(sqvm); + return SQRESULT_NOTNULL; + } + ServerSq_newTable(sqvm); + + for (int i = 0; i < doc.MemberCount(); i++) + { + + rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>& itr = doc.MemberBegin()[i]; + + switch (itr.value.GetType()) + { + case rapidjson::kObjectType: + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_DecodeJSON_Table( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kArrayType: + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_DecodeJSON_Array( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kStringType: + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushstring(sqvm, itr.value.GetString(), -1); + + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kTrueType: + if ((long long)itr.name.GetString() == -1) + { + spdlog::info("Neagative String decoding True"); + continue; + } + + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushbool(sqvm, true); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kFalseType: + if ((long long)itr.name.GetString() == -1) + { + + continue; + } + + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushbool(sqvm, false); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kNumberType: + if (itr.value.IsDouble() || itr.value.IsFloat()) + { + + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushfloat(sqvm, itr.value.GetFloat()); + } + else + { + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushinteger(sqvm, itr.value.GetInt()); + } + ServerSq_newSlot(sqvm, -3, false); + break; + } + } + return SQRESULT_NOTNULL; +} + +void ServerSq_DecodeJSON_Table( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj) +{ + ServerSq_newTable(sqvm); + + for (int i = 0; i < obj->MemberCount(); i++) + { + rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>& itr = obj->MemberBegin()[i]; + if (!itr.name.IsString()) + { + spdlog::info("Decoding table with non-string key"); + continue; + } + const char* key = itr.name.GetString(); + switch (itr.value.GetType()) + { + case rapidjson::kObjectType: + ServerSq_pushstring(sqvm, key, -1); + ServerSq_DecodeJSON_Table( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kArrayType: + ServerSq_pushstring(sqvm, key, -1); + ServerSq_DecodeJSON_Array( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kStringType: + ServerSq_pushstring(sqvm, key, -1); + ServerSq_pushstring(sqvm, itr.value.GetString(), -1); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kTrueType: + + ServerSq_pushstring(sqvm, key, -1); + ServerSq_pushbool(sqvm, true); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kFalseType: + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushbool(sqvm, false); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kNumberType: + if (itr.value.IsDouble() || itr.value.IsFloat()) + { + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushfloat(sqvm, itr.value.GetFloat()); + } + else + { + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushinteger(sqvm, itr.value.GetInt()); + } + ServerSq_newSlot(sqvm, -3, false); + break; + } + } +} + +void ServerSq_DecodeJSON_Array( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr) +{ + int usedType = arr->GetArray().Begin()->GetType(); + bool isFloat = arr->GetArray().Begin()->IsDouble() || arr->GetArray().Begin()->IsFloat(); + ServerSq_newarray(sqvm, 0); + for (auto& itr : arr->GetArray()) + { + switch (itr.GetType()) + { + case rapidjson::kObjectType: + + if (usedType != itr.GetType()) + continue; + ServerSq_DecodeJSON_Table(sqvm, &itr); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kArrayType: + + if (usedType != itr.GetType()) + continue; + ServerSq_DecodeJSON_Array(sqvm, &itr); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kStringType: + if ((long long)itr.GetString() == -1) + { + + continue; + } + if (usedType != itr.GetType()) + continue; + ServerSq_pushstring(sqvm, itr.GetString(), -1); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kTrueType: + if (usedType != rapidjson::kTrueType && usedType != rapidjson::kFalseType) + continue; + ServerSq_pushbool(sqvm, true); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kFalseType: + if (usedType != rapidjson::kTrueType && usedType != rapidjson::kFalseType) + continue; + ServerSq_pushbool(sqvm, false); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kNumberType: + if (usedType != itr.GetType()) + continue; + if (itr.IsDouble() || itr.IsFloat()) + { + + if (!isFloat) + continue; + ServerSq_pushfloat(sqvm, itr.GetFloat()); + } + else + { + if (isFloat) + continue; + ServerSq_pushinteger(sqvm, itr.GetInt()); + } + ServerSq_arrayappend(sqvm, -2); + break; + } + } +} + +SQRESULT ClientSq_DecodeJSON(void* sqvm) +{ + const char* json = ClientSq_getstring(sqvm, 1); + rapidjson_document doc; + doc.Parse(json); + if (doc.HasParseError()) + { + ClientSq_newTable(sqvm); + return SQRESULT_NOTNULL; + } + ServerSq_newTable(sqvm); + + for (int i = 0; i < doc.MemberCount(); i++) + { + + rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>& itr = doc.MemberBegin()[i]; + + switch (itr.value.GetType()) + { + case rapidjson::kObjectType: + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_DecodeJSON_Table( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kArrayType: + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_DecodeJSON_Array( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kStringType: + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushstring(sqvm, itr.value.GetString(), -1); + + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kTrueType: + if ((long long)itr.name.GetString() == -1) + { + spdlog::info("Neagative String decoding True"); + continue; + } + + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushbool(sqvm, true); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kFalseType: + if ((long long)itr.name.GetString() == -1) + { + + continue; + } + + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushbool(sqvm, false); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kNumberType: + if (itr.value.IsDouble() || itr.value.IsFloat()) + { + + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushfloat(sqvm, itr.value.GetFloat()); + } + else + { + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushinteger(sqvm, itr.value.GetInt()); + } + ClientSq_newSlot(sqvm, -3, false); + break; + } + } + return SQRESULT_NOTNULL; +} + +void ClientSq_DecodeJSON_Table( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj) +{ + ClientSq_newTable(sqvm); + + for (int i = 0; i < obj->MemberCount(); i++) + { + rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>& itr = obj->MemberBegin()[i]; + if (!itr.name.IsString()) + { + spdlog::info("Decoding table with non-string key"); + continue; + } + const char* key = itr.name.GetString(); + + switch (itr.value.GetType()) + { + case rapidjson::kObjectType: + ClientSq_pushstring(sqvm, key, -1); + ClientSq_DecodeJSON_Table( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kArrayType: + ClientSq_pushstring(sqvm, key, -1); + ClientSq_DecodeJSON_Array( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kStringType: + ClientSq_pushstring(sqvm, key, -1); + ClientSq_pushstring(sqvm, itr.value.GetString(), -1); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kTrueType: + + ClientSq_pushstring(sqvm, key, -1); + ClientSq_pushbool(sqvm, true); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kFalseType: + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushbool(sqvm, false); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kNumberType: + if (itr.value.IsDouble() || itr.value.IsFloat()) + { + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushfloat(sqvm, itr.value.GetFloat()); + } + else + { + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushinteger(sqvm, itr.value.GetInt()); + } + ClientSq_newSlot(sqvm, -3, false); + break; + } + } +} + +void ClientSq_DecodeJSON_Array( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr) +{ + int usedType = arr->GetArray().Begin()->GetType(); + bool isFloat = arr->GetArray().Begin()->IsDouble() || arr->GetArray().Begin()->IsFloat(); + ClientSq_newarray(sqvm, 0); + for (auto& itr : arr->GetArray()) + { + switch (itr.GetType()) + { + case rapidjson::kObjectType: + + if (usedType != itr.GetType()) + continue; + ClientSq_DecodeJSON_Table(sqvm, &itr); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kArrayType: + + if (usedType != itr.GetType()) + continue; + ClientSq_DecodeJSON_Array(sqvm, &itr); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kStringType: + if ((long long)itr.GetString() == -1) + { + + continue; + } + if (usedType != itr.GetType()) + continue; + ClientSq_pushstring(sqvm, itr.GetString(), -1); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kTrueType: + if (usedType != rapidjson::kTrueType && usedType != rapidjson::kFalseType) + continue; + ClientSq_pushbool(sqvm, true); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kFalseType: + if (usedType != rapidjson::kTrueType && usedType != rapidjson::kFalseType) + continue; + ClientSq_pushbool(sqvm, false); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kNumberType: + if (usedType != itr.GetType()) + continue; + if (itr.IsDouble() || itr.IsFloat()) + { + + if (!isFloat) + continue; + ClientSq_pushfloat(sqvm, itr.GetFloat()); + } + else + { + if (isFloat) + continue; + ClientSq_pushinteger(sqvm, itr.GetInt()); + } + ClientSq_arrayappend(sqvm, -2); + break; + } + } +} + +SQRESULT SQ_EncodeJSON(void* sqvm) +{ + rapidjson_document doc; + doc.SetObject(); + + HSquirrelVM* vm = (HSquirrelVM*)sqvm; + SQTable* table = vm->_stackOfCurrentFunction[1]._VAL.asTable; + SQ_EncodeJSON_Table(&doc, table, &doc); + rapidjson::StringBuffer buffer; + rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); + doc.Accept(writer); + const char* json = buffer.GetString(); + + ServerSq_pushstring(sqvm, json, -1); + return SQRESULT_NOTNULL; +} + +void SQ_EncodeJSON_Table( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, + SQTable* table, + rapidjson_document* allocatorDoc) +{ + for (int i = 0; i < table->_numOfNodes; i++) + { + tableNode* node = &table->_nodes[i]; + if (node->key._Type == OT_STRING) + { + + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newObj(rapidjson::kObjectType); + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newArray(rapidjson::kArrayType); + + switch (node->val._Type) + { + case OT_STRING: + + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::StringRef(node->val._VAL.asString->_val), + allocatorDoc->GetAllocator()); + break; + case OT_INTEGER: + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>( + (int)node->val._VAL.asInteger), + allocatorDoc->GetAllocator()); + break; + case OT_FLOAT: + + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>(node->val._VAL.asFloat), + allocatorDoc->GetAllocator()); + break; + case OT_BOOL: + if (node->val._VAL.asInteger) + { + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>(true), + allocatorDoc->GetAllocator()); + } + else + { + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>(false), + allocatorDoc->GetAllocator()); + } + break; + case OT_TABLE: + + SQ_EncodeJSON_Table(&newObj, node->val._VAL.asTable, allocatorDoc); + obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newObj, allocatorDoc->GetAllocator()); + break; + case OT_ARRAY: + + SQ_EncodeJSON_Array(&newArray, node->val._VAL.asArray, allocatorDoc); + obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newArray, allocatorDoc->GetAllocator()); + break; + default: + spdlog::info("SQ encode Json type {} not supported", sq_getTypeName(node->val._Type)); + break; + } + } + } +} + +void SQ_EncodeJSON_Array( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, + SQArray* sqArray, + rapidjson_document* allocatorDoc) +{ + int usedType = sqArray->_values->_Type; + for (int i = 0; i < sqArray->_usedSlots; i++) + { + SQObject* node = &sqArray->_values[i]; + if (node->_Type != usedType) + { + const char* typeName = sq_getTypeName(node->_Type); + const char* usedTypeName = sq_getTypeName(usedType); + spdlog::info("SQ encode Json array not same type got %s expected %s", typeName, usedTypeName); + continue; + } + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newObj(rapidjson::kObjectType); + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newArray(rapidjson::kArrayType); + switch (node->_Type) + { + case OT_STRING: + obj->PushBack(rapidjson::StringRef(node->_VAL.asString->_val), allocatorDoc->GetAllocator()); + break; + case OT_INTEGER: + obj->PushBack( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>((int)node->_VAL.asInteger), + allocatorDoc->GetAllocator()); + break; + case OT_FLOAT: + obj->PushBack( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>(node->_VAL.asFloat), + allocatorDoc->GetAllocator()); + break; + case OT_BOOL: + if (node->_VAL.asInteger) + { + obj->PushBack(rapidjson::StringRef("true"), allocatorDoc->GetAllocator()); + } + else + { + obj->PushBack(rapidjson::StringRef("false"), allocatorDoc->GetAllocator()); + } + break; + case OT_TABLE: + + SQ_EncodeJSON_Table(&newObj, node->_VAL.asTable, allocatorDoc); + obj->PushBack(newObj, allocatorDoc->GetAllocator()); + break; + case OT_ARRAY: + + SQ_EncodeJSON_Array(&newArray, node->_VAL.asArray, allocatorDoc); + obj->PushBack(newArray, allocatorDoc->GetAllocator()); + break; + default: + + spdlog::info("SQ encode Json type {} not supported", sq_getTypeName(node->_Type)); + } + } +} + +void InitialiseServerSquirrelJson(HMODULE baseAddress) +{ + + g_ServerSquirrelManager->AddFuncRegistration("table", "DecodeJSON", "string json", "", ServerSq_DecodeJSON); + g_ServerSquirrelManager->AddFuncRegistration("string", "EncodeJSON", "table data", "", SQ_EncodeJSON); +} + +void InitialiseClientSquirrelJson(HMODULE baseAddress) +{ + g_ClientSquirrelManager->AddFuncRegistration("table", "DecodeJSON", "string json", "", ClientSq_DecodeJSON); + g_ClientSquirrelManager->AddFuncRegistration("string", "EncodeJSON", "table data", "", SQ_EncodeJSON); + + g_UISquirrelManager->AddFuncRegistration("table", "DecodeJSON", "string json", "", ClientSq_DecodeJSON); + g_UISquirrelManager->AddFuncRegistration("string", "EncodeJSON", "table data", "", SQ_EncodeJSON); +}
\ No newline at end of file |