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