Merge pull request #2384 from davidjb/patch-1
[project/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 }