luci-base: ensure that button labels are properly html escaped
[oweals/luci.git] / libs / luci-lib-jsonc / src / jsonc.c
1 /*
2 Copyright 2015 Jo-Philipp Wich <jow@openwrt.org>
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8         http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 #define _GNU_SOURCE
18
19 #include <math.h>
20 #include <stdbool.h>
21 #include <json-c/json.h>
22
23 #include <lua.h>
24 #include <lualib.h>
25 #include <lauxlib.h>
26
27 #define LUCI_JSONC "luci.jsonc"
28 #define LUCI_JSONC_PARSER "luci.jsonc.parser"
29
30 struct seen {
31         size_t size;
32         size_t len;
33         const void *ptrs[];
34 };
35
36 struct json_state {
37         struct json_object *obj;
38         struct json_tokener *tok;
39         enum json_tokener_error err;
40 };
41
42 static void _json_to_lua(lua_State *L, struct json_object *obj);
43 static struct json_object * _lua_to_json(lua_State *L, int index);
44 static struct json_object * _lua_to_json_rec(lua_State *L, int index, struct seen **seen);
45
46 static int json_new(lua_State *L)
47 {
48         struct json_state *s;
49         struct json_tokener *tok = json_tokener_new();
50
51         if (!tok)
52                 return 0;
53
54         s = lua_newuserdata(L, sizeof(*s));
55
56         if (!s)
57         {
58                 json_tokener_free(tok);
59                 return 0;
60         }
61
62         s->tok = tok;
63         s->obj = NULL;
64         s->err = json_tokener_continue;
65
66         luaL_getmetatable(L, LUCI_JSONC_PARSER);
67         lua_setmetatable(L, -2);
68
69         return 1;
70 }
71
72 static int json_parse(lua_State *L)
73 {
74         size_t len;
75         const char *json = luaL_checklstring(L, 1, &len);
76         struct json_state s = {
77                 .tok = json_tokener_new()
78         };
79
80         if (!s.tok)
81                 return 0;
82
83         s.obj = json_tokener_parse_ex(s.tok, json, len);
84         s.err = json_tokener_get_error(s.tok);
85
86         if (s.obj)
87         {
88                 _json_to_lua(L, s.obj);
89                 json_object_put(s.obj);
90         }
91         else
92         {
93                 lua_pushnil(L);
94         }
95
96         if (s.err == json_tokener_continue)
97                 s.err = json_tokener_error_parse_eof;
98
99         if (s.err)
100                 lua_pushstring(L, json_tokener_error_desc(s.err));
101
102         json_tokener_free(s.tok);
103         return (1 + !!s.err);
104 }
105
106 static int json_stringify(lua_State *L)
107 {
108         struct json_object *obj = _lua_to_json(L, 1);
109         bool pretty = lua_toboolean(L, 2);
110         int flags = 0;
111
112         if (pretty)
113                 flags |= JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED;
114
115         lua_pushstring(L, json_object_to_json_string_ext(obj, flags));
116         json_object_put(obj);
117         return 1;
118 }
119
120
121 static int json_parse_chunk(lua_State *L)
122 {
123         size_t len;
124         struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
125         const char *chunk = luaL_checklstring(L, 2, &len);
126
127         s->obj = json_tokener_parse_ex(s->tok, chunk, len);
128     s->err = json_tokener_get_error(s->tok);
129
130         if (!s->err)
131         {
132                 lua_pushboolean(L, true);
133                 return 1;
134         }
135         else if (s->err == json_tokener_continue)
136         {
137                 lua_pushboolean(L, false);
138                 return 1;
139         }
140
141         lua_pushnil(L);
142         lua_pushstring(L, json_tokener_error_desc(s->err));
143         return 2;
144 }
145
146 static void _json_to_lua(lua_State *L, struct json_object *obj)
147 {
148         int n;
149
150         switch (json_object_get_type(obj))
151         {
152         case json_type_object:
153                 lua_newtable(L);
154                 json_object_object_foreach(obj, key, val)
155                 {
156                         _json_to_lua(L, val);
157                         lua_setfield(L, -2, key);
158                 }
159                 break;
160
161         case json_type_array:
162                 lua_newtable(L);
163                 for (n = 0; n < json_object_array_length(obj); n++)
164                 {
165                         _json_to_lua(L, json_object_array_get_idx(obj, n));
166                         lua_rawseti(L, -2, n + 1);
167                 }
168                 break;
169
170         case json_type_boolean:
171                 lua_pushboolean(L, json_object_get_boolean(obj));
172                 break;
173
174         case json_type_int:
175                 lua_pushinteger(L, json_object_get_int(obj));
176                 break;
177
178         case json_type_double:
179                 lua_pushnumber(L, json_object_get_double(obj));
180                 break;
181
182         case json_type_string:
183                 lua_pushstring(L, json_object_get_string(obj));
184                 break;
185
186         case json_type_null:
187                 lua_pushnil(L);
188                 break;
189         }
190 }
191
192 static int json_parse_get(lua_State *L)
193 {
194         struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
195
196         if (!s->obj || s->err)
197                 lua_pushnil(L);
198         else
199                 _json_to_lua(L, s->obj);
200
201         return 1;
202 }
203
204 static int _lua_test_array(lua_State *L, int index)
205 {
206         int max = 0;
207         lua_Number idx;
208
209         if (!lua_checkstack(L, 2))
210                 return -1;
211
212         lua_pushnil(L);
213
214         /* check for non-integer keys */
215         while (lua_next(L, index))
216         {
217                 if (lua_type(L, -2) != LUA_TNUMBER)
218                         goto out;
219
220                 idx = lua_tonumber(L, -2);
221
222                 if (idx != (lua_Number)(lua_Integer)idx)
223                         goto out;
224
225                 if (idx <= 0)
226                         goto out;
227
228                 if (idx > max)
229                         max = idx;
230
231                 lua_pop(L, 1);
232                 continue;
233
234 out:
235                 lua_pop(L, 2);
236                 return -1;
237         }
238
239         /* check for holes */
240         //for (i = 1; i <= max; i++)
241         //{
242         //      lua_rawgeti(L, index, i);
243         //
244         //      if (lua_isnil(L, -1))
245         //      {
246         //              lua_pop(L, 1);
247         //              return 0;
248         //      }
249         //
250         //      lua_pop(L, 1);
251         //}
252
253         return max;
254 }
255
256
257 static bool visited(struct seen **sp, const void *ptr) {
258         struct seen *s = *sp;
259         size_t i;
260
261         if (s->len >= s->size)
262         {
263                 i = s->size + 10;
264                 s = realloc(*sp, sizeof(struct seen) + sizeof(void *) * i);
265
266                 if (!s)
267                 {
268                         if (*sp)
269                                 free(*sp);
270
271                         *sp = NULL;
272                         return true;
273                 }
274
275                 s->size = i;
276                 *sp = s;
277         }
278
279         for (i = 0; i < s->len; i++)
280                 if (s->ptrs[i] == ptr)
281                         return true;
282
283         s->ptrs[s->len++] = ptr;
284         return false;
285 }
286
287 static struct json_object * _lua_to_json_rec(lua_State *L, int index,
288                                              struct seen **seen)
289 {
290         lua_Number nd, ni;
291         struct json_object *obj;
292         const char *key;
293         int i, max;
294
295         if (index < 0)
296                 index = lua_gettop(L) + index + 1;
297
298         switch (lua_type(L, index))
299         {
300         case LUA_TTABLE:
301                 if (visited(seen, lua_topointer(L, index)))
302                         return NULL;
303
304                 max = _lua_test_array(L, index);
305
306                 if (max >= 0)
307                 {
308                         obj = json_object_new_array();
309
310                         if (!obj)
311                                 return NULL;
312
313                         if (!lua_checkstack(L, 1))
314                                 return NULL;
315
316                         for (i = 1; i <= max; i++)
317                         {
318                                 lua_rawgeti(L, index, i);
319
320                                 json_object_array_put_idx(obj, i - 1,
321                                                           _lua_to_json_rec(L, -1, seen));
322
323                                 lua_pop(L, 1);
324                         }
325
326                         return obj;
327                 }
328
329                 obj = json_object_new_object();
330
331                 if (!obj)
332                         return NULL;
333
334                 if (!lua_checkstack(L, 3))
335                         return NULL;
336
337                 lua_pushnil(L);
338
339                 while (lua_next(L, index))
340                 {
341                         lua_pushvalue(L, -2);
342                         key = lua_tostring(L, -1);
343
344                         if (key)
345                                 json_object_object_add(obj, key,
346                                                        _lua_to_json_rec(L, -2, seen));
347
348                         lua_pop(L, 2);
349                 }
350
351                 return obj;
352
353         case LUA_TNIL:
354                 return NULL;
355
356         case LUA_TBOOLEAN:
357                 return json_object_new_boolean(lua_toboolean(L, index));
358
359         case LUA_TNUMBER:
360                 nd = lua_tonumber(L, index);
361                 ni = lua_tointeger(L, index);
362
363                 if (nd == ni)
364                         return json_object_new_int(nd);
365
366                 return json_object_new_double(nd);
367
368         case LUA_TSTRING:
369                 return json_object_new_string(lua_tostring(L, index));
370         }
371
372         return NULL;
373 }
374
375 static struct json_object * _lua_to_json(lua_State *L, int index)
376 {
377         struct seen *s = calloc(sizeof(struct seen) + sizeof(void *) * 10, 1);
378         struct json_object *rv;
379
380         if (!s)
381                 return NULL;
382
383         s->size = 10;
384
385         rv = _lua_to_json_rec(L, index, &s);
386
387         free(s);
388
389         return rv;
390 }
391
392 static int json_parse_set(lua_State *L)
393 {
394         struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
395
396         s->err = 0;
397         s->obj = _lua_to_json(L, 2);
398
399         return 0;
400 }
401
402 static int json_parse_sink_closure(lua_State *L)
403 {
404         bool finished = lua_toboolean(L, lua_upvalueindex(2));
405         if (lua_isnil(L, 1))
406         {
407                 // no more data available
408                 if (finished)
409                 {
410                         // we were finished parsing
411                         lua_pushboolean(L, true);
412                         return 1;
413                 }
414                 else
415                 {
416                         lua_pushnil(L);
417                         lua_pushstring(L, "Incomplete JSON data");
418                         return 2;
419                 }
420         }
421         else
422         {
423                 if (finished)
424                 {
425                         lua_pushnil(L);
426                         lua_pushstring(L, "Unexpected data after complete JSON object");
427                         return 2;
428                 }
429                 else
430                 {
431                         // luci.jsonc.parser.chunk()
432                         lua_pushcfunction(L, json_parse_chunk);
433                         // parser object from closure
434                         lua_pushvalue(L, lua_upvalueindex(1));
435                         // chunk
436                         lua_pushvalue(L, 1);
437                         lua_call(L, 2, 2);
438
439                         if (lua_isnil(L, -2))
440                         {
441                                 // an error occurred, leave (nil, errmsg) on the stack and return it
442                                 return 2;
443                         }
444                         else if (lua_toboolean(L, -2))
445                         {
446                                 // finished reading, set finished=true and return nil to prevent further input
447                                 lua_pop(L, 2);
448                                 lua_pushboolean(L, true);
449                                 lua_replace(L, lua_upvalueindex(2));
450                                 lua_pushnil(L);
451                                 return 1;
452                         }
453                         else
454                         {
455                                 // not finished reading, return true
456                                 lua_pop(L, 2);
457                                 lua_pushboolean(L, true);
458                                 return 1;
459                         }
460                 }
461         }
462 }
463
464 static int json_parse_sink(lua_State *L)
465 {
466         luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
467         lua_pushboolean(L, false);
468         lua_pushcclosure(L, json_parse_sink_closure, 2);
469         return 1;
470 }
471
472 static int json_tostring(lua_State *L)
473 {
474         struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
475         bool pretty = lua_toboolean(L, 2);
476         int flags = 0;
477
478         if (pretty)
479                 flags |= JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED;
480
481         lua_pushstring(L, json_object_to_json_string_ext(s->obj, flags));
482         return 1;
483 }
484
485 static int json_gc(lua_State *L)
486 {
487         struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
488
489         if (s->obj)
490                 json_object_put(s->obj);
491
492         if (s->tok)
493                 json_tokener_free(s->tok);
494
495         return 0;
496 }
497
498
499 static const luaL_reg jsonc_methods[] = {
500         { "new",                        json_new          },
501         { "parse",                      json_parse        },
502         { "stringify",          json_stringify    },
503
504         { }
505 };
506
507 static const luaL_reg jsonc_parser_methods[] = {
508         { "parse",                      json_parse_chunk  },
509         { "get",                        json_parse_get    },
510         { "set",                        json_parse_set    },
511         { "sink",                       json_parse_sink   },
512         { "stringify",          json_tostring     },
513
514         { "__gc",                       json_gc           },
515         { "__tostring",         json_tostring     },
516
517         { }
518 };
519
520
521 int luaopen_luci_jsonc(lua_State *L)
522 {
523         luaL_register(L, LUCI_JSONC, jsonc_methods);
524
525         luaL_newmetatable(L, LUCI_JSONC_PARSER);
526         luaL_register(L, NULL, jsonc_parser_methods);
527         lua_pushvalue(L, -1);
528         lua_setfield(L, -2, "__index");
529         lua_pop(L, 1);
530
531         return 1;
532 }