1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 16:57:16 +01:00
SqMod/modules/json/Common.cpp

258 lines
8.8 KiB
C++
Raw Normal View History

// ------------------------------------------------------------------------------------------------
#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