1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-14 11:47:15 +01:00
SqMod/modules/json/Common.cpp
Sandu Liviu Catalin 66d1110733 Rvised the API distribution system to avoid segmentation fault crashes on Linux and make the overal code cleaner.
Moved the constants in IRC module into their own source and implemented a faster method of registering them.
Various other minor changes and adjustments. Some of them in order to comply with the new API distribution system.
2016-07-17 03:24:07 +03:00

307 lines
9.6 KiB
C++

// ------------------------------------------------------------------------------------------------
#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);
}
// ------------------------------------------------------------------------------------------------
Object SqFromJSON(HSQUIRRELVM /*vm*/, json_t * jval)
{
switch (json_typeof(jval))
{
case JSON_OBJECT:
{
} break;
case JSON_ARRAY:
{
} break;
case JSON_STRING:
{
} break;
case JSON_INTEGER:
{
} break;
case JSON_REAL:
{
} break;
case JSON_TRUE:
{
} break;
case JSON_FALSE:
{
} break;
case JSON_NULL:
{
} break;
default: STHROWF("Unknown JSON value type");
}
return Object();
}
// ------------------------------------------------------------------------------------------------
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:
{
// Grab the type name of the object on the stack
const String tn(SqTypeName(vm, idx));
// Now throw the error with the obtained name
STHROWF("Unknown conversion for type: %s", tn.c_str());
}
}
// 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