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