// write_json(data[, styled]) -> string or nil and error message int ModApiUtil::l_write_json(lua_State *L) { NO_MAP_LOCK_REQUIRED; bool styled = false; if (!lua_isnone(L, 2)) { styled = lua_toboolean(L, 2); lua_pop(L, 1); } Json::Value root; try { read_json_value(L, root, 1); } catch (SerializationError &e) { lua_pushnil(L); lua_pushstring(L, e.what()); return 2; } std::string out; if (styled) { Json::StyledWriter writer; out = writer.write(root); } else { Json::FastWriter writer; out = writer.write(root); } lua_pushlstring(L, out.c_str(), out.size()); return 1; }
// setting_setjson(name, value) int ModApiUtil::l_setting_setjson(lua_State *L) { NO_MAP_LOCK_REQUIRED; const char *name = luaL_checkstring(L, 1); Json::Value root; read_json_value(L, root, 2); g_settings->setJson(name, root); return 0; }
// Converts Lua table --> JSON void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion) { if (recursion > 16) { throw SerializationError("Maximum recursion depth exceeded"); } int type = lua_type(L, index); if (type == LUA_TBOOLEAN) { root = (bool) lua_toboolean(L, index); } else if (type == LUA_TNUMBER) { root = lua_tonumber(L, index); } else if (type == LUA_TSTRING) { size_t len; const char *str = lua_tolstring(L, index, &len); root = std::string(str, len); } else if (type == LUA_TTABLE) { lua_pushnil(L); while (lua_next(L, index)) { // Key is at -2 and value is at -1 Json::Value value; read_json_value(L, value, lua_gettop(L), recursion + 1); Json::ValueType roottype = root.type(); int keytype = lua_type(L, -1); if (keytype == LUA_TNUMBER) { lua_Number key = lua_tonumber(L, -1); if (roottype != Json::nullValue && roottype != Json::arrayValue) { throw SerializationError("Can't mix array and object values in JSON"); } else if (key < 1) { throw SerializationError("Can't use zero-based or negative indexes in JSON"); } else if (floor(key) != key) { throw SerializationError("Can't use indexes with a fractional part in JSON"); } root[(Json::ArrayIndex) key - 1] = value; } else if (keytype == LUA_TSTRING) { if (roottype != Json::nullValue && roottype != Json::objectValue) { throw SerializationError("Can't mix array and object values in JSON"); } root[lua_tostring(L, -1)] = value; } else { throw SerializationError("Lua key to convert to JSON is not a string or number"); } } } else if (type == LUA_TNIL) { root = Json::nullValue; } else { throw SerializationError("Can only store booleans, numbers, strings, objects, arrays, and null in JSON"); } lua_pop(L, 1); // Pop value }
void parse_item(std::istream &s, std::stack<json::Value *> &struct_stack) { // Get the object/array: json::Array *arr = NULL; json::Object *obj = NULL; if(struct_stack.top()->type() == json::TYPE_ARRAY) arr = dynamic_cast<json::Array *>(struct_stack.top()); else obj = dynamic_cast<json::Object *>(struct_stack.top()); // See if we've reached the end: char c = s.peek(); check_stream(s); if((arr && c == ']') || (obj && c == '}')) { s.ignore(); check_stream(s); struct_stack.pop(); if(!struct_stack.empty()) { eat_whitespace(s); } return; } // Check for a comma: if((arr && !arr->empty()) || (obj && !obj->empty())) { if(c != ',') throw json::ParseException("Expected \',\' token."); s.ignore(); check_stream(s); eat_whitespace(s); } // Read in a key if this is an object std::string key; if(obj) { key = read_json_string_basic(s); eat_whitespace(s); if(checked_stream_get(s) != ':') throw json::ParseException("Expected \':\' token."); eat_whitespace(s); } // Read in the actual value: json::Value *v = NULL; try { v = read_json_value(s); if(arr) arr->pushBackTake(v); else obj->takeValue(key, v); } catch(...) { delete v; throw; } if(v->type() == json::TYPE_ARRAY || v->type() == json::TYPE_OBJECT) { struct_stack.push(v); } eat_whitespace(s); }