diff options
Diffstat (limited to 'plugins/MirLua/src/Modules/m_json.cpp')
-rw-r--r-- | plugins/MirLua/src/Modules/m_json.cpp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/plugins/MirLua/src/Modules/m_json.cpp b/plugins/MirLua/src/Modules/m_json.cpp new file mode 100644 index 0000000000..24e32cab09 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_json.cpp @@ -0,0 +1,243 @@ +#include "../stdafx.h" + +#define MT_JSON "JSON" + +static void lua2json(lua_State *L, JSONNode &node) +{ + switch (lua_type(L, -1)) { + case LUA_TNIL: + node.nullify(); + break; + case LUA_TSTRING: + node = lua_tostring(L, -1); + break; + case LUA_TBOOLEAN: + node = lua_toboolean(L, -1) != 0; + break; + case LUA_TNUMBER: + { + lua_Integer val = lua_tointeger(L, -1); + if (lua_isinteger(L, -1) && val >= LONG_MIN && val <= LONG_MIN) + node = (long)val; + else + node = lua_tonumber(L, -1); + break; + } + case LUA_TTABLE: + { + ptrA name(mir_strdup(node.name())); + node.cast(JSON_ARRAY); + node.set_name((char*)name); + + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + JSONNode child; + if (!lua_isnumber(L, -2)) { + if (node.type() == JSON_ARRAY) { + node.cast(JSON_NODE); + node.set_name((char*)name); + } + const char *key = lua_tostring(L, -2); + child.set_name(key); + } + lua2json(L, child); + node << child; + + lua_pop(L, 1); + } + + break; + } + } +} + +/***********************************************/ + +static int json__index(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + + JSONNode *child; + if (node->type() == JSON_ARRAY) { + int idx = lua_tointeger(L, 2); + child = &node->at(idx - 1); + } + else { + const char *key = lua_tostring(L, 2); + child = &node->at(key); + } + + switch (child->type()) + { + case JSON_NULL: + lua_pushnil(L); + break; + case JSON_STRING: + lua_pushstring(L, child->as_string().c_str()); + break; + case JSON_NUMBER: + lua_pushnumber(L, child->as_int()); + break; + case JSON_BOOL: + lua_pushboolean(L, child->as_bool()); + break; + case JSON_ARRAY: + case JSON_NODE: + JSONNode **udata = (JSONNode**)lua_newuserdata(L, sizeof(JSONNode*)); + *udata = child; + luaL_setmetatable(L, MT_JSON); + } + + return 1; +} + +static int json__newindex(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + const char *key = lua_tostring(L, 2); + + if (json_type(node) == JSON_ARRAY) { + int idx = lua_tointeger(L, 2); + JSONNode *child = json_at(node, idx - 1); + lua2json(L, *child); + return 0; + } + + JSONNode *child = json_get(node, key); + if (json_type(child) == JSON_NULL) { + json_set_name(child, key); + lua2json(L, *child); + json_push_back(node, child); + return 0; + } + + lua2json(L, *child); + + return 0; +} + +static int json__len(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + lua_pushnumber(L, json_size(node)); + + return 1; +} + +static int json__tostring(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + + lua_pushstring(L, node->write().c_str()); + + return 1; +} + +static int json__gc(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + + json_delete(node); + + return 0; +} + +const struct luaL_Reg jsonApi[] = +{ + { "__index", json__index }, + { "__newindex", json__newindex }, + { "__len", json__len }, + { "__tostring", json__tostring }, + { "__gc", json__gc }, + + { nullptr, nullptr } +}; + + +/***********************************************/ + +static int lua_Decode(lua_State *L) +{ + const char *string = luaL_checkstring(L, 1); + + JSONNode **udata = (JSONNode**)lua_newuserdata(L, sizeof(JSONNode*)); + *udata = json_parse(string); + luaL_setmetatable(L, MT_JSON); + + return 1; +} + +static int lua_Encode(lua_State *L) +{ + switch (lua_type(L, 1)) { + case LUA_TNIL: + lua_pushliteral(L, "null"); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, lua_toboolean(L, 1) ? "true" : "false"); + break; + case LUA_TNUMBER: + { + if (lua_isinteger(L, 1)) { + lua_pushfstring(L, "%I", lua_tointeger(L, 1)); + break; + } + char decpoint = lua_getlocaledecpoint(); + if (decpoint != '.') { + char p[2] = { decpoint }; + luaL_gsub(L, lua_tostring(L, 1), p, "."); + } + else + lua_pushfstring(L, "%f", lua_tonumber(L, 1)); + break; + } + case LUA_TSTRING: + lua_pushfstring(L, "\"%s\"", lua_tostring(L, 1)); + break; + case LUA_TTABLE: + { + JSONNode node; + lua_pushnil(L); + lua_pushvalue(L, 1); + lua2json(L, node); + lua_pop(L, 2); + lua_pushstring(L, node.write().c_str()); + break; + } + case LUA_TUSERDATA: + { + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + lua_pushstring(L, node->write().c_str()); + break; + } + case LUA_TLIGHTUSERDATA: + if (lua_touserdata(L, 1) == nullptr) + { + lua_pushliteral(L, "null"); + break; + } + default: + luaL_argerror(L, 1, luaL_typename(L, 1)); + } + + return 1; +} + +static const luaL_Reg methods[] = +{ + { "Decode", lua_Decode }, + { "Encode", lua_Encode }, + + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_json(lua_State *L) +{ + luaL_newlib(L, methods); + + luaL_newmetatable(L, MT_JSON); + luaL_setfuncs(L, jsonApi, 0); + lua_pop(L, 1); + + return 1; +}
\ No newline at end of file |