1 /* $NetBSD: json.c,v 1.3 2022/04/03 01:10:59 christos Exp $ */
2
3 /*
4 * Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * Internet Systems Consortium, Inc.
19 * PO Box 360
20 * Newmarket, NH 03857 USA
21 * <info@isc.org>
22 * https://www.isc.org/
23 *
24 */
25
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: json.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
28
29 /* From Kea src/lib/cc/data.cc fromJSON() */
30
31 #include "keama.h"
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 struct element *
json_parse(struct parse * cfile)37 json_parse(struct parse *cfile)
38 {
39 struct element *elem;
40 const char *val;
41 enum dhcp_token token;
42
43 elem = create();
44 stackPush(cfile, elem);
45 cfile->stack[0] = elem;
46 cfile->stack_top = 0;
47
48 token = next_token(&val, NULL, cfile);
49 switch (token) {
50 case NUMBER:
51 elem = createInt(atoll(val));
52 TAILQ_CONCAT(&elem->comments, &cfile->comments);
53 break;
54 case STRING:
55 elem = createString(makeString(-1, val));
56 TAILQ_CONCAT(&elem->comments, &cfile->comments);
57 break;
58 case NAME:
59 if (strcmp(val, "null") == 0)
60 elem = createNull();
61 else if (strcmp(val, "true") == 0)
62 elem = createBool(ISC_TRUE);
63 else if (strcmp(val, "false") == 0) {
64 elem = createBool(ISC_FALSE);
65 elem->skip = ISC_TRUE;
66 } else
67 parse_error(cfile, "unknown name %s", val);
68 TAILQ_CONCAT(&elem->comments, &cfile->comments);
69 break;
70 case LBRACKET:
71 elem = json_list_parse(cfile);
72 break;
73 case LBRACE:
74 elem = json_map_parse(cfile);
75 break;
76 case END_OF_FILE:
77 parse_error(cfile, "unexpected end of file");
78 default:
79 parse_error(cfile, "unexpected %s", val);
80 }
81 return elem;
82 }
83
84 struct element *
json_list_parse(struct parse * cfile)85 json_list_parse(struct parse *cfile)
86 {
87 struct element *list;
88 struct element *item;
89 const char *val;
90 enum dhcp_token token;
91 isc_boolean_t done = ISC_FALSE;
92
93 list = createList();
94 TAILQ_CONCAT(&list->comments, &cfile->comments);
95 stackPush(cfile, list);
96 do {
97 token = peek_token(&val, NULL, cfile);
98 switch (token) {
99 case RBRACKET:
100 done = ISC_TRUE;
101 break;
102 case END_OF_FILE:
103 parse_error(cfile, "unexpected end of file");
104 case COMMA:
105 skip_token(&val, NULL, cfile);
106 if (listSize(list) == 0)
107 parse_error(cfile, "unexpected ','");
108 item = json_parse(cfile);
109 listPush(list, item);
110 break;
111 default:
112 if (listSize(list) > 0)
113 parse_error(cfile, "expected ','");
114 item = json_parse(cfile);
115 listPush(list, item);
116 break;
117 }
118 } while (!done);
119 skip_token(&val, NULL, cfile);
120 cfile->stack_top--;
121 return list;
122 }
123
124 struct element *
json_map_parse(struct parse * cfile)125 json_map_parse(struct parse *cfile)
126 {
127 struct element *map;
128 struct element *item;
129 const char *val;
130 const char *key;
131 enum dhcp_token token;
132 isc_boolean_t done = ISC_FALSE;
133
134 map = createMap();
135 TAILQ_CONCAT(&map->comments, &cfile->comments);
136 stackPush(cfile, map);
137 do {
138 token = peek_token(&val, NULL, cfile);
139 switch (token) {
140 case RBRACE:
141 done = ISC_TRUE;
142 break;
143 case END_OF_FILE:
144 parse_error(cfile, "unexpected end of file");
145 case COMMA:
146 skip_token(&val, NULL, cfile);
147 if (mapSize(map) == 0)
148 parse_error(cfile, "unexpected ','");
149 token = next_token(&val, NULL, cfile);
150 if (token != STRING)
151 parse_error(cfile, "unexpected %s, "
152 "expected \"key\":value", val);
153 key = strdup(val);
154 token = next_token(&val, NULL, cfile);
155 if (token != COLON)
156 parse_error(cfile, "unexpected %s, "
157 "expected ':'", val);
158 item = json_parse(cfile);
159 mapSet(map, item, key);
160 break;
161 case STRING:
162 skip_token(&val, NULL, cfile);
163 if (mapSize(map) > 0)
164 parse_error(cfile, "unexpected \"%s\", "
165 "expected ','", val);
166 key = strdup(val);
167 token = next_token(&val, NULL, cfile);
168 if (token != COLON)
169 parse_error(cfile, "unexpected %s, "
170 "expected ':'", val);
171 item = json_parse(cfile);
172 mapSet(map, item, key);
173 break;
174 default:
175 if (mapSize(map) == 0)
176 parse_error(cfile, "unexpected %s, "
177 "expected \"key\":value or '}'",
178 val);
179 else
180 parse_error(cfile, "unexpected %s, "
181 "expected ',' or '}'", val);
182 }
183 } while (!done);
184 skip_token(&val, NULL, cfile);
185 cfile->stack_top--;
186 return map;
187 }
188