mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-06-30 22:17:13 +02:00
Partial implementation of the JSON module.
This commit is contained in:
@ -1,9 +1,257 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#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
|
||||
|
Reference in New Issue
Block a user