diff --git a/daemon/engine.c b/daemon/engine.c index 048643f0ccd3ba999f774b9837b10b7555a9dab3..de20831fc5684f6d2896f6c5c12515a17df289e5 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -214,39 +214,46 @@ static void l_unpack_json(lua_State *L, JsonNode *table) } } +/** @internal Recursive Lua/JSON serialization. */ static JsonNode *l_pack_elem(lua_State *L, int top) { - if (lua_isstring(L, top)) { - return json_mkstring(lua_tostring(L, top)); - } - if (lua_isnumber(L, top)) { - return json_mknumber(lua_tonumber(L, top)); - } - if (lua_isboolean(L, top)) { - return json_mkbool(lua_toboolean(L, top)); + switch(lua_type(L, top)) { + case LUA_TSTRING: return json_mkstring(lua_tostring(L, top)); + case LUA_TNUMBER: return json_mknumber(lua_tonumber(L, top)); + case LUA_TBOOLEAN: return json_mkbool(lua_toboolean(L, top)); + case LUA_TTABLE: break; /* Table, iterate it. */ + default: return json_mknull(); + } + /* Use absolute indexes here, as the table may be nested. */ + JsonNode *node = NULL; + lua_pushnil(L); + while(lua_next(L, top) != 0) { + JsonNode *val = l_pack_elem(L, top + 2); + const bool no_key = lua_isnumber(L, top + 1); + if (!node) { + node = no_key ? json_mkarray() : json_mkobject(); + if (!node) { + return NULL; + } + } + /* Insert to array/table */ + if (no_key) { + json_append_element(node, val); + } else { + json_append_member(node, lua_tostring(L, top + 1), val); + } + lua_pop(L, 1); } - return json_mknull(); + return node; } +/** @internal Serialize to string */ static char *l_pack_json(lua_State *L, int top) { - JsonNode *root = json_mkobject(); + JsonNode *root = l_pack_elem(L, top); if (!root) { return NULL; } - /* Iterate table on stack */ - lua_pushnil(L); - while(lua_next(L, top)) { - JsonNode *val = l_pack_elem(L, -1); - if (lua_isstring(L, -2)) { - json_append_member(root, lua_tostring(L, -2), val); - } else { - json_append_element(root, val); - } - lua_pop(L, 1); - } - lua_pop(L, 1); - /* Serialize to string */ char *result = json_encode(root); json_delete(root); return result;