Translated using Weblate (Japanese)
[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 <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 }