Created
September 1, 2013 23:41
-
-
Save kahrl/6408049 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jsonstr = '[1, 2, 3, 4, 5, 6]' | |
json = engine.parse_json(jsonstr) | |
dump2(json) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
push_json_value gettop=2 depth=2 | |
pushed array newtable, gettop=3 | |
pushed int 1, gettop=4 | |
pushed int 2, gettop=4 | |
pushed int 3, gettop=4 | |
pushed int 4, gettop=4 | |
pushed int 5, gettop=4 | |
pushed int 6, gettop=4 | |
_ = {} | |
_[1] = 1 | |
_[2] = 2 | |
_[3] = 3 | |
_[4] = 4 | |
_[5] = 5 | |
_[6] = 6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/doc/lua_api.txt b/doc/lua_api.txt | |
index 94397e1..1d2f295 100644 | |
--- a/doc/lua_api.txt | |
+++ b/doc/lua_api.txt | |
@@ -1471,6 +1471,12 @@ minetest.get_content_id(name) -> integer | |
^ Gets the internal content ID of name | |
minetest.get_name_from_content_id(content_id) -> string | |
^ Gets the name of the content with that content ID | |
+minetest.parse_json(string[, nullvalue]) -> something | |
+^ Convert a string containing JSON data into the Lua equivalent | |
+^ nullvalue: returned in place of the JSON null; defaults to nil | |
+^ On success returns a table, a string, a number, a boolean or nullvalue | |
+^ On failure outputs an error message and returns nil | |
+^ Example: parse_json("[10, {\"a\":false}]") -> {[1] = 10, [2] = {a = false}} | |
minetest.serialize(table) -> string | |
^ Convert a table containing tables, strings, numbers, booleans and nils | |
into string form readable by minetest.deserialize | |
diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt | |
index 10524f4..bb94d5f 100644 | |
--- a/doc/menu_lua_api.txt | |
+++ b/doc/menu_lua_api.txt | |
@@ -188,6 +188,8 @@ engine.gettext(string) -> string | |
fgettext(string, ...) -> string | |
^ call engine.gettext(string), replace "$1"..."$9" with the given | |
^ extra arguments, call engine.formspec_escape and return the result | |
+engine.parse_json(string[, nullvalue]) -> something | |
+^ see minetest.parse_json (lua_api.txt) | |
dump(obj, dumped={}) | |
^ Return object serialized as a string | |
string:split(separator) | |
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp | |
index 2e26adb..5f1beaa 100644 | |
--- a/src/script/common/c_content.cpp | |
+++ b/src/script/common/c_content.cpp | |
@@ -31,6 +31,7 @@ | |
#include "tool.h" | |
#include "serverobject.h" | |
#include "mapgen.h" | |
+#include "json/json.h" | |
struct EnumString es_TileAnimationType[] = | |
{ | |
@@ -998,3 +999,88 @@ bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *serv | |
return true; | |
} | |
+ | |
+/******************************************************************************/ | |
+// Returns depth of json value tree | |
+static int push_json_value_getdepth(const Json::Value &value) | |
+{ | |
+ if (!value.isArray() && !value.isObject()) | |
+ return 1; | |
+ | |
+ int maxdepth = 0; | |
+ for (Json::Value::const_iterator it = value.begin(); | |
+ it != value.end(); ++it) { | |
+ int elemdepth = push_json_value_getdepth(*it); | |
+ if (elemdepth > maxdepth) | |
+ maxdepth = elemdepth; | |
+ } | |
+ return maxdepth + 1; | |
+} | |
+// Recursive function to convert JSON --> Lua table | |
+static bool push_json_value_helper(lua_State *L, const Json::Value &value, | |
+ int nullindex) | |
+{ | |
+ switch(value.type()) { | |
+ case Json::nullValue: | |
+ default: | |
+ lua_pushvalue(L, nullindex); | |
+ break; | |
+ case Json::intValue: | |
+ lua_pushinteger(L, value.asInt()); | |
+ dstream<<"pushed int "<<value.asInt()<<", gettop="<<lua_gettop(L)<<std::endl; | |
+ break; | |
+ case Json::uintValue: | |
+ lua_pushinteger(L, value.asUInt()); | |
+ dstream<<"pushed uint "<<value.asUInt()<<", gettop="<<lua_gettop(L)<<std::endl; | |
+ break; | |
+ case Json::realValue: | |
+ lua_pushnumber(L, value.asDouble()); | |
+ break; | |
+ case Json::stringValue: | |
+ { | |
+ const char *str = value.asCString(); | |
+ lua_pushstring(L, str ? str : ""); | |
+ } | |
+ break; | |
+ case Json::booleanValue: | |
+ lua_pushboolean(L, value.asInt()); | |
+ break; | |
+ case Json::arrayValue: | |
+ lua_newtable(L); | |
+ dstream<<"pushed array newtable, gettop="<<lua_gettop(L)<<std::endl; | |
+ for (Json::Value::const_iterator it = value.begin(); | |
+ it != value.end(); ++it) { | |
+ push_json_value_helper(L, *it, nullindex); | |
+ lua_rawseti(L, -2, it.index() + 1); | |
+ } | |
+ break; | |
+ case Json::objectValue: | |
+ lua_newtable(L); | |
+ for (Json::Value::const_iterator it = value.begin(); | |
+ it != value.end(); ++it) { | |
+ const char *str = it.memberName(); | |
+ lua_pushstring(L, str ? str : ""); | |
+ push_json_value_helper(L, *it, nullindex); | |
+ lua_rawset(L, -3); | |
+ } | |
+ break; | |
+ } | |
+ return true; | |
+} | |
+// converts JSON --> Lua table; returns false if lua stack limit exceeded | |
+// nullindex: Lua stack index of value to use in place of JSON null | |
+bool push_json_value(lua_State *L, const Json::Value &value, int nullindex) | |
+{ | |
+ if(nullindex < 0) | |
+ nullindex = lua_gettop(L) + 1 + nullindex; | |
+ | |
+ int depth = push_json_value_getdepth(value); | |
+ dstream<<"push_json_value gettop="<<lua_gettop(L)<<" depth="<<depth<<std::endl; | |
+ | |
+ // The maximum number of Lua stack slots used at each recursion level | |
+ // of push_json_value_helper is 2, so make sure there a depth * 2 slots | |
+ if (lua_checkstack(L, depth * 2)) | |
+ return push_json_value_helper(L, value, nullindex); | |
+ else | |
+ return false; | |
+} | |
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h | |
index 6d1dfe1..27019e2 100644 | |
--- a/src/script/common/c_content.h | |
+++ b/src/script/common/c_content.h | |
@@ -39,6 +39,8 @@ | |
#include "irrlichttypes_bloated.h" | |
#include "util/string.h" | |
+namespace Json { class Value; } | |
+ | |
struct MapNode; | |
class INodeDefManager; | |
struct PointedThing; | |
@@ -145,6 +147,10 @@ bool read_schematic (lua_State *L, int index, | |
void luaentity_get (lua_State *L,u16 id); | |
+bool push_json_value (lua_State *L, | |
+ const Json::Value &value, | |
+ int nullindex); | |
+ | |
extern struct EnumString es_TileAnimationType[]; | |
#endif /* C_CONTENT_H_ */ | |
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp | |
index 40a2ff4..1e44ba5 100644 | |
--- a/src/script/lua_api/l_util.cpp | |
+++ b/src/script/lua_api/l_util.cpp | |
@@ -26,6 +26,7 @@ | |
#include "tool.h" | |
#include "settings.h" | |
#include "main.h" //required for g_settings, g_settings_path | |
+#include "json/json.h" | |
// debug(...) | |
// Writes a line to dstream | |
@@ -138,6 +139,45 @@ int ModApiUtil::l_setting_save(lua_State *L) | |
return 0; | |
} | |
+// parse_json(str[, nullvalue]) | |
+int ModApiUtil::l_parse_json(lua_State *L) | |
+{ | |
+ NO_MAP_LOCK_REQUIRED; | |
+ | |
+ const char *jsonstr = luaL_checkstring(L, 1); | |
+ | |
+ // Use passed nullvalue or default to nil | |
+ int nullindex = 2; | |
+ if (lua_isnone(L, nullindex)) { | |
+ lua_pushnil(L); | |
+ nullindex = lua_gettop(L); | |
+ } | |
+ | |
+ Json::Value root; | |
+ | |
+ { | |
+ Json::Reader reader; | |
+ std::istringstream stream(jsonstr); | |
+ | |
+ if (!reader.parse(stream, root)) { | |
+ errorstream << "Failed to parse json data " | |
+ << reader.getFormattedErrorMessages(); | |
+ errorstream << "data: \"" << jsonstr << "\"" | |
+ << std::endl; | |
+ lua_pushnil(L); | |
+ return 1; | |
+ } | |
+ } | |
+ | |
+ if (!push_json_value(L, root, nullindex)) { | |
+ errorstream << "Failed to parse json data, " | |
+ << "depth exceeds lua stack limit" << std::endl; | |
+ errorstream << "data: \"" << jsonstr << "\"" << std::endl; | |
+ lua_pushnil(L); | |
+ } | |
+ return 1; | |
+} | |
+ | |
// get_dig_params(groups, tool_capabilities[, time_from_last_punch]) | |
int ModApiUtil::l_get_dig_params(lua_State *L) | |
{ | |
@@ -211,6 +251,8 @@ void ModApiUtil::Initialize(lua_State *L, int top) | |
API_FCT(setting_getbool); | |
API_FCT(setting_save); | |
+ API_FCT(parse_json); | |
+ | |
API_FCT(get_dig_params); | |
API_FCT(get_hit_params); | |
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h | |
index ac840c4..07d4c29 100644 | |
--- a/src/script/lua_api/l_util.h | |
+++ b/src/script/lua_api/l_util.h | |
@@ -59,6 +59,9 @@ class ModApiUtil : public ModApiBase { | |
// setting_save() | |
static int l_setting_save(lua_State *L); | |
+ // parse_json(str[, nullvalue]) | |
+ static int l_parse_json(lua_State *L); | |
+ | |
// get_dig_params(groups, tool_capabilities[, time_from_last_punch]) | |
static int l_get_dig_params(lua_State *L); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment