Created
September 1, 2013 23:10
-
-
Save kahrl/6407927 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
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..40a2437 100644 | |
--- a/doc/menu_lua_api.txt | |
+++ b/doc/menu_lua_api.txt | |
@@ -188,6 +188,12 @@ 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 | |
+^ 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}} | |
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..6f80cb2 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,86 @@ bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *serv | |
return true; | |
} | |
+ | |
+/******************************************************************************/ | |
+// Returns actual depth of json value tree, or -1 if exceeding maxdepth | |
+static int push_json_value_checkdepth(const Json::Value &value, int maxdepth) | |
+{ | |
+ if (maxdepth <= 0) | |
+ return -1; | |
+ if (!value.isArray() && !value.isObject()) | |
+ return 1; | |
+ | |
+ int objdepth = 0; | |
+ for (Json::Value::const_iterator it = value.begin(); | |
+ it != value.end(); ++it) { | |
+ int elemdepth = push_json_value_checkdepth(*it, maxdepth - 1); | |
+ if (elemdepth < 0) | |
+ return -1; | |
+ if (elemdepth > objdepth) | |
+ objdepth = elemdepth; | |
+ } | |
+ return objdepth + 1; | |
+} | |
+// Recursive function to convert JSON --> Lua table | |
+static void 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()); | |
+ break; | |
+ case Json::uintValue: | |
+ lua_pushinteger(L, value.asUInt()); | |
+ 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); | |
+ 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; | |
+ } | |
+} | |
+// converts JSON --> Lua table; returns false if maxdepth or stack 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, int maxdepth) | |
+{ | |
+ if(nullindex < 0) | |
+ nullindex = lua_gettop(L) + 1 + nullindex; | |
+ int depth = push_json_value_checkdepth(value, maxdepth); | |
+ if (depth >= 0 && lua_checkstack(L, depth*2)) { | |
+ push_json_value_helper(L, value, nullindex); | |
+ return true; | |
+ } | |
+ else | |
+ return false; | |
+} | |
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h | |
index 6d1dfe1..24d9e53 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,11 @@ 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, | |
+ int maxdepth); | |
+ | |
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..c6be024 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,46 @@ 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; | |
+ } | |
+ } | |
+ | |
+ int maxdepth = 42; | |
+ if (!push_json_value(L, root, nullindex, maxdepth)) { | |
+ errorstream << "Failed to parse json data, " | |
+ << "depth limit exceeded" << 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 +252,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