diff options
-rw-r--r-- | libs/luci-lib-jsonc/src/jsonc.c | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/libs/luci-lib-jsonc/src/jsonc.c b/libs/luci-lib-jsonc/src/jsonc.c index ef11101660..9ff8520dbc 100644 --- a/libs/luci-lib-jsonc/src/jsonc.c +++ b/libs/luci-lib-jsonc/src/jsonc.c @@ -27,6 +27,12 @@ limitations under the License. #define LUCI_JSONC "luci.jsonc" #define LUCI_JSONC_PARSER "luci.jsonc.parser" +struct seen { + size_t size; + size_t len; + const void *ptrs[]; +}; + struct json_state { struct json_object *obj; struct json_tokener *tok; @@ -35,6 +41,7 @@ struct json_state { static void _json_to_lua(lua_State *L, struct json_object *obj); static struct json_object * _lua_to_json(lua_State *L, int index); +static struct json_object * _lua_to_json_rec(lua_State *L, int index, struct seen **seen); static int json_new(lua_State *L) { @@ -199,6 +206,9 @@ static int _lua_test_array(lua_State *L, int index) int max = 0; lua_Number idx; + if (!lua_checkstack(L, 2)) + return -1; + lua_pushnil(L); /* check for non-integer keys */ @@ -243,16 +253,54 @@ out: return max; } -static struct json_object * _lua_to_json(lua_State *L, int index) + +static bool visited(struct seen **sp, const void *ptr) { + struct seen *s = *sp; + size_t i; + + if (s->len >= s->size) + { + i = s->size + 10; + s = realloc(*sp, sizeof(struct seen) + sizeof(void *) * i); + + if (!s) + { + if (*sp) + free(*sp); + + *sp = NULL; + return true; + } + + s->size = i; + *sp = s; + } + + for (i = 0; i < s->len; i++) + if (s->ptrs[i] == ptr) + return true; + + s->ptrs[s->len++] = ptr; + return false; +} + +static struct json_object * _lua_to_json_rec(lua_State *L, int index, + struct seen **seen) { lua_Number nd, ni; struct json_object *obj; const char *key; int i, max; + if (index < 0) + index = lua_gettop(L) + index + 1; + switch (lua_type(L, index)) { case LUA_TTABLE: + if (visited(seen, lua_topointer(L, index))) + return NULL; + max = _lua_test_array(L, index); if (max >= 0) @@ -262,12 +310,15 @@ static struct json_object * _lua_to_json(lua_State *L, int index) if (!obj) return NULL; + if (!lua_checkstack(L, 1)) + return NULL; + for (i = 1; i <= max; i++) { lua_rawgeti(L, index, i); json_object_array_put_idx(obj, i - 1, - _lua_to_json(L, lua_gettop(L))); + _lua_to_json_rec(L, -1, seen)); lua_pop(L, 1); } @@ -280,6 +331,9 @@ static struct json_object * _lua_to_json(lua_State *L, int index) if (!obj) return NULL; + if (!lua_checkstack(L, 3)) + return NULL; + lua_pushnil(L); while (lua_next(L, index)) @@ -289,7 +343,7 @@ static struct json_object * _lua_to_json(lua_State *L, int index) if (key) json_object_object_add(obj, key, - _lua_to_json(L, lua_gettop(L) - 1)); + _lua_to_json_rec(L, -2, seen)); lua_pop(L, 2); } @@ -318,6 +372,23 @@ static struct json_object * _lua_to_json(lua_State *L, int index) return NULL; } +static struct json_object * _lua_to_json(lua_State *L, int index) +{ + struct seen *s = calloc(sizeof(struct seen) + sizeof(void *) * 10, 1); + struct json_object *rv; + + if (!s) + return NULL; + + s->size = 10; + + rv = _lua_to_json_rec(L, index, &s); + + free(s); + + return rv; +} + static int json_parse_set(lua_State *L) { struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER); |