diff options
Diffstat (limited to 'src/script/rapidjson/values.cpp')
-rw-r--r-- | src/script/rapidjson/values.cpp | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/script/rapidjson/values.cpp b/src/script/rapidjson/values.cpp new file mode 100644 index 0000000..1d9c892 --- /dev/null +++ b/src/script/rapidjson/values.cpp @@ -0,0 +1,108 @@ + +#include "values.hpp" +#include "luax.hpp" + +using rapidjson::Value; +using rapidjson::SizeType; + +namespace values +{ + namespace details + { + static Value NumberValue(lua_State* L, int idx); + static Value StringValue(lua_State* L, int idx, Allocator& allocator); + static Value TableValue(lua_State* L, int idx, int depth, Allocator& allocator); + static Value ObjectValue(lua_State* L, int idx, int depth, Allocator& allocator); + static Value ArrayValue(lua_State* L, int idx, int depth, Allocator& allocator); + + Value toValue(lua_State* L, int idx, int depth, Allocator& allocator) + { + auto t = lua_type(L, idx); + switch (t) + { + case LUA_TBOOLEAN: + return Value(lua_toboolean(L, idx) != 0); + case LUA_TNUMBER: + return NumberValue(L, idx); + case LUA_TSTRING: + return StringValue(L, idx, allocator); + case LUA_TTABLE: + return TableValue(L, idx, depth + 1, allocator); + case LUA_TNIL: + return Value(); + case LUA_TFUNCTION: + if (isnull(L, idx)) + return Value(); + // otherwise fall thought + case LUA_TLIGHTUSERDATA: // fall thought + case LUA_TUSERDATA: // fall thought + case LUA_TTHREAD: // fall thought + case LUA_TNONE: // fall thought + default: + luaL_error(L, "value type %s is not a valid json value", lua_typename(L, t)); + return Value(); // Just make compiler happy + } + } + + Value NumberValue(lua_State* L, int idx) + { + int64_t integer; + return luax::isinteger(L, idx, &integer) ? Value(integer) : Value(lua_tonumber(L, idx)); + } + + Value StringValue(lua_State* L, int idx, Allocator& allocator) + { + size_t len; + const char* s = lua_tolstring(L, idx, &len); + return Value(s, static_cast<SizeType>(len), allocator); + } + + Value TableValue(lua_State* L, int idx, int depth, Allocator& allocator) + { + if (depth > 1024) + luaL_error(L, "nested too depth"); + + if (!lua_checkstack(L, 4)) // requires at least 4 slots in stack: table, key, value, key + luaL_error(L, "stack overflow"); + + return isarray(L, idx) ? ArrayValue(L, idx, depth, allocator) : ObjectValue(L, idx, depth, allocator); + } + + Value ObjectValue(lua_State* L, int idx, int depth, Allocator& allocator) + { + Value object(rapidjson::kObjectType); + lua_pushvalue(L, idx); + lua_pushnil(L); + while (lua_next(L, -2)) + { + + if (lua_type(L, -2) == LUA_TSTRING) + { + object.AddMember(StringValue(L, -2, allocator), toValue(L, -1, depth, allocator), allocator); + } + + // pop value, leaving original key + lua_pop(L, 1); + + } + + lua_pop(L, 1); + return object; + } + + Value ArrayValue(lua_State* L, int idx, int depth, Allocator& allocator) + { + Value array(rapidjson::kArrayType); + auto MAX = static_cast<int>(luax::rawlen(L, idx)); // luax::rawlen always returns size_t (>= 0) + for (auto n = 1; n <= MAX; ++n) + { + lua_rawgeti(L, idx, n); + array.PushBack(toValue(L, -1, depth, allocator), allocator); + lua_pop(L, 1); + } + + + return array; + } + } +} |