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