// ------------------------------------------------------------------------------------------------ #include "Common.hpp" #include "JValue.hpp" #include "JArray.hpp" #include "JObject.hpp" // ------------------------------------------------------------------------------------------------ namespace SqMod { // ------------------------------------------------------------------------------------------------ CSStr JSONTypeToStr(json_type type) { switch (type) { case JSON_OBJECT: return _SC("object"); case JSON_ARRAY: return _SC("array"); case JSON_STRING: return _SC("string"); case JSON_INTEGER: return _SC("integer"); case JSON_REAL: return _SC("real"); case JSON_TRUE: return _SC("true"); case JSON_FALSE: return _SC("false"); case JSON_NULL: return _SC("null"); default: return _SC("unknown"); } } // ------------------------------------------------------------------------------------------------ void SqThrowLast(HSQUIRRELVM vm, CSStr msg) { // Remember the current stack size const StackGuard sg(vm); // Push the last error on the stack sq_getlasterror(vm); // Attempt to obtained the error as a string StackStrF val(vm, -1, false); // Did the retrieval failed? if (SQ_FAILED(val.mRes)) { STHROWF("%s [Unknown error]", msg); } // Throw the resulting error message STHROWF("%s [%s]", msg, val.mPtr); } // ------------------------------------------------------------------------------------------------ json_t * SqToJSON(HSQUIRRELVM vm, SQInteger idx) { switch (sq_gettype(vm, idx)) { case OT_NULL: { return json_null(); } break; case OT_INTEGER: { SQInteger i; // Retrieve the integer value if (SQ_FAILED(sq_getinteger(vm, idx, &i))) { SqThrowLast(vm, "Cannot retrieve integer value"); } // Return the JSON value return json_integer(i); } break; case OT_FLOAT: { SQFloat f; // Retrieve the float value if (SQ_FAILED(sq_getfloat(vm, idx, &f))) { SqThrowLast(vm, "Cannot retrieve float value"); } // Return the JSON value return json_real(f); } break; case OT_BOOL: { SQBool b; // Retrieve the boolean value if (SQ_FAILED(sq_getbool(vm, idx, &b))) { SqThrowLast(vm, "Cannot retrieve boolean value"); } // Return the JSON value return json_boolean(b); } break; case OT_STRING: { CSStr s = nullptr; SQInteger n; // Retrieve the string value if (SQ_FAILED(sq_getstringandsize(vm, idx, &s, &n))) { SqThrowLast(vm, "Cannot retrieve string value"); } // Return the JSON value return json_stringn(s, ConvTo< std::size_t >::From(n)); } break; case OT_TABLE: { // Create an object wrapper to release automatically in case of failure JObject obj; // Remember the current stack size const StackGuard sg(vm); // Push null to begin table iteration sq_pushnull(vm); // Compute the new table index on the stack if necessary if (idx < 0) { --idx; } // Start iterating table elements while(SQ_SUCCEEDED(sq_next(vm, idx))) { // Attempt to convert the key to a string StackStrF val(vm, -2, false); // Did the conversion failed? if (SQ_FAILED(val.mRes)) { SqThrowLast(vm, "Invalid table key"); } // Assign the value with further recursive scanning if (json_object_set_new(obj, val.mPtr, SqToJSON(vm, -1)) < 0) { STHROWF("Unable to set table element (&s)", val.mPtr); } // Pop the key and value before the new iteration sq_pop(vm, 2); } // Increase the reference count so that we don't destroy the object json_incref(obj); // Return the resulted object return obj; } break; case OT_ARRAY: { // Create an array wrapper to release automatically in case of failure JArray arr; // Remember the current stack size const StackGuard sg(vm); // Obtain the total size of the array const SQInteger size = sq_getsize(vm, idx); // Push null to begin array iteration sq_pushnull(vm); // Compute the new array index on the stack if necessary if (idx < 0) { --idx; } // Currently processed element SQInteger pos; // Start iterating array elements while(SQ_SUCCEEDED(sq_next(vm, idx))) { // Retrieve the currently processed array element index if (SQ_FAILED(sq_getinteger(vm, -2, &pos))) { SqThrowLast(vm, "Unable to retrieve iterator position"); } // Are we still within the array bounds? else if (pos >= size) { break; // Stop iterating } // Assign the value with further recursive scanning if (json_array_append_new(arr, SqToJSON(vm, -1)) < 0) { STHROWF("Unable to set array element: " _PRINT_INT_FMT, pos); } // Pop the key and value before the new iteration sq_pop(vm, 2); } // Increase the reference count so that we don't destroy the array json_incref(arr); // Return the resulted array return arr; } break; default: STHROWF("Unknown conversion for type: %s", SqTypeName(vm, idx)); } // Should not reach this point return nullptr; } // ------------------------------------------------------------------------------------------------ JObject SqTableToJSONObject(Table & tbl) { // Make sure that the given table is not null if (tbl.IsNull()) { return JObject(); // Nothing to add } // Remember the current stack size const StackGuard sg(tbl.GetVM()); // Push our table onto the stack Var< Table & >::push(tbl.GetVM(), tbl); // Attempt to extract the values from the given table return JObject(SqToJSON(tbl.GetVM(), -1), false); } // ------------------------------------------------------------------------------------------------ JArray SqArrayToJSONArray(Array & arr) { // Make sure that the given array is not null if (arr.IsNull()) { return JArray(); // Nothing to add } // Remember the current stack size const StackGuard sg(arr.GetVM()); // Push our array onto the stack Var< Array & >::push(arr.GetVM(), arr); // Attempt to extract the values from the given array return JArray(SqToJSON(arr.GetVM(), -1), false); } // ------------------------------------------------------------------------------------------------ JObject SqObjectToJSONObject(Object & obj) { // Make sure that the given object is not null if (obj.IsNull()) { return JObject(); // Nothing to add } // Remember the current stack size const StackGuard sg(obj.GetVM()); // Push our object onto the stack Var< Object & >::push(obj.GetVM(), obj); // Attempt to extract the values from the given object return JObject(SqToJSON(obj.GetVM(), -1), false); } // ------------------------------------------------------------------------------------------------ JValue SqValueToJSONValue(Object & obj) { // Make sure that the given object is not null if (obj.IsNull()) { return JValue(); // Nothing to add } // Remember the current stack size const StackGuard sg(obj.GetVM()); // Push our object onto the stack Var< Object & >::push(obj.GetVM(), obj); // Attempt to extract the values from the given object return JValue(SqToJSON(obj.GetVM(), -1), false); } // ================================================================================================ void Register_Common(Table & jns) { jns.Func(_SC("FromTable"), &SqTableToJSONObject); jns.Func(_SC("FromArray"), &SqArrayToJSONArray); jns.Func(_SC("ToObject"), &SqObjectToJSONObject); jns.Func(_SC("ToValue"), &SqValueToJSONValue); } } // Namespace:: SqMod