1*a1157835SDaniel Fojt /*
2*a1157835SDaniel Fojt  * JavaScript Object Notation (JSON) parser (RFC7159)
3*a1157835SDaniel Fojt  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4*a1157835SDaniel Fojt  *
5*a1157835SDaniel Fojt  * This software may be distributed under the terms of the BSD license.
6*a1157835SDaniel Fojt  * See README for more details.
7*a1157835SDaniel Fojt  */
8*a1157835SDaniel Fojt 
9*a1157835SDaniel Fojt #include "includes.h"
10*a1157835SDaniel Fojt 
11*a1157835SDaniel Fojt #include "common.h"
12*a1157835SDaniel Fojt #include "base64.h"
13*a1157835SDaniel Fojt #include "json.h"
14*a1157835SDaniel Fojt 
15*a1157835SDaniel Fojt #define JSON_MAX_DEPTH 10
16*a1157835SDaniel Fojt #define JSON_MAX_TOKENS 500
17*a1157835SDaniel Fojt 
18*a1157835SDaniel Fojt 
json_escape_string(char * txt,size_t maxlen,const char * data,size_t len)19*a1157835SDaniel Fojt void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
20*a1157835SDaniel Fojt {
21*a1157835SDaniel Fojt 	char *end = txt + maxlen;
22*a1157835SDaniel Fojt 	size_t i;
23*a1157835SDaniel Fojt 
24*a1157835SDaniel Fojt 	for (i = 0; i < len; i++) {
25*a1157835SDaniel Fojt 		if (txt + 4 >= end)
26*a1157835SDaniel Fojt 			break;
27*a1157835SDaniel Fojt 
28*a1157835SDaniel Fojt 		switch (data[i]) {
29*a1157835SDaniel Fojt 		case '\"':
30*a1157835SDaniel Fojt 			*txt++ = '\\';
31*a1157835SDaniel Fojt 			*txt++ = '\"';
32*a1157835SDaniel Fojt 			break;
33*a1157835SDaniel Fojt 		case '\\':
34*a1157835SDaniel Fojt 			*txt++ = '\\';
35*a1157835SDaniel Fojt 			*txt++ = '\\';
36*a1157835SDaniel Fojt 			break;
37*a1157835SDaniel Fojt 		case '\n':
38*a1157835SDaniel Fojt 			*txt++ = '\\';
39*a1157835SDaniel Fojt 			*txt++ = 'n';
40*a1157835SDaniel Fojt 			break;
41*a1157835SDaniel Fojt 		case '\r':
42*a1157835SDaniel Fojt 			*txt++ = '\\';
43*a1157835SDaniel Fojt 			*txt++ = 'r';
44*a1157835SDaniel Fojt 			break;
45*a1157835SDaniel Fojt 		case '\t':
46*a1157835SDaniel Fojt 			*txt++ = '\\';
47*a1157835SDaniel Fojt 			*txt++ = 't';
48*a1157835SDaniel Fojt 			break;
49*a1157835SDaniel Fojt 		default:
50*a1157835SDaniel Fojt 			if (data[i] >= 32 && data[i] <= 126) {
51*a1157835SDaniel Fojt 				*txt++ = data[i];
52*a1157835SDaniel Fojt 			} else {
53*a1157835SDaniel Fojt 				txt += os_snprintf(txt, end - txt, "\\u%04x",
54*a1157835SDaniel Fojt 						   data[i]);
55*a1157835SDaniel Fojt 			}
56*a1157835SDaniel Fojt 			break;
57*a1157835SDaniel Fojt 		}
58*a1157835SDaniel Fojt 	}
59*a1157835SDaniel Fojt 
60*a1157835SDaniel Fojt 	*txt = '\0';
61*a1157835SDaniel Fojt }
62*a1157835SDaniel Fojt 
63*a1157835SDaniel Fojt 
json_parse_string(const char ** json_pos,const char * end)64*a1157835SDaniel Fojt static char * json_parse_string(const char **json_pos, const char *end)
65*a1157835SDaniel Fojt {
66*a1157835SDaniel Fojt 	const char *pos = *json_pos;
67*a1157835SDaniel Fojt 	char *str, *spos, *s_end;
68*a1157835SDaniel Fojt 	size_t max_len, buf_len;
69*a1157835SDaniel Fojt 	u8 bin[2];
70*a1157835SDaniel Fojt 
71*a1157835SDaniel Fojt 	pos++; /* skip starting quote */
72*a1157835SDaniel Fojt 
73*a1157835SDaniel Fojt 	max_len = end - pos + 1;
74*a1157835SDaniel Fojt 	buf_len = max_len > 10 ? 10 : max_len;
75*a1157835SDaniel Fojt 	str = os_malloc(buf_len);
76*a1157835SDaniel Fojt 	if (!str)
77*a1157835SDaniel Fojt 		return NULL;
78*a1157835SDaniel Fojt 	spos = str;
79*a1157835SDaniel Fojt 	s_end = str + buf_len;
80*a1157835SDaniel Fojt 
81*a1157835SDaniel Fojt 	for (; pos < end; pos++) {
82*a1157835SDaniel Fojt 		if (buf_len < max_len && s_end - spos < 3) {
83*a1157835SDaniel Fojt 			char *tmp;
84*a1157835SDaniel Fojt 			int idx;
85*a1157835SDaniel Fojt 
86*a1157835SDaniel Fojt 			idx = spos - str;
87*a1157835SDaniel Fojt 			buf_len *= 2;
88*a1157835SDaniel Fojt 			if (buf_len > max_len)
89*a1157835SDaniel Fojt 				buf_len = max_len;
90*a1157835SDaniel Fojt 			tmp = os_realloc(str, buf_len);
91*a1157835SDaniel Fojt 			if (!tmp)
92*a1157835SDaniel Fojt 				goto fail;
93*a1157835SDaniel Fojt 			str = tmp;
94*a1157835SDaniel Fojt 			spos = str + idx;
95*a1157835SDaniel Fojt 			s_end = str + buf_len;
96*a1157835SDaniel Fojt 		}
97*a1157835SDaniel Fojt 
98*a1157835SDaniel Fojt 		switch (*pos) {
99*a1157835SDaniel Fojt 		case '\"': /* end string */
100*a1157835SDaniel Fojt 			*spos = '\0';
101*a1157835SDaniel Fojt 			/* caller will move to the next position */
102*a1157835SDaniel Fojt 			*json_pos = pos;
103*a1157835SDaniel Fojt 			return str;
104*a1157835SDaniel Fojt 		case '\\':
105*a1157835SDaniel Fojt 			pos++;
106*a1157835SDaniel Fojt 			if (pos >= end) {
107*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
108*a1157835SDaniel Fojt 					   "JSON: Truncated \\ escape");
109*a1157835SDaniel Fojt 				goto fail;
110*a1157835SDaniel Fojt 			}
111*a1157835SDaniel Fojt 			switch (*pos) {
112*a1157835SDaniel Fojt 			case '"':
113*a1157835SDaniel Fojt 			case '\\':
114*a1157835SDaniel Fojt 			case '/':
115*a1157835SDaniel Fojt 				*spos++ = *pos;
116*a1157835SDaniel Fojt 				break;
117*a1157835SDaniel Fojt 			case 'n':
118*a1157835SDaniel Fojt 				*spos++ = '\n';
119*a1157835SDaniel Fojt 				break;
120*a1157835SDaniel Fojt 			case 'r':
121*a1157835SDaniel Fojt 				*spos++ = '\r';
122*a1157835SDaniel Fojt 				break;
123*a1157835SDaniel Fojt 			case 't':
124*a1157835SDaniel Fojt 				*spos++ = '\t';
125*a1157835SDaniel Fojt 				break;
126*a1157835SDaniel Fojt 			case 'u':
127*a1157835SDaniel Fojt 				if (end - pos < 5 ||
128*a1157835SDaniel Fojt 				    hexstr2bin(pos + 1, bin, 2) < 0 ||
129*a1157835SDaniel Fojt 				    bin[1] == 0x00) {
130*a1157835SDaniel Fojt 					wpa_printf(MSG_DEBUG,
131*a1157835SDaniel Fojt 						   "JSON: Invalid \\u escape");
132*a1157835SDaniel Fojt 					goto fail;
133*a1157835SDaniel Fojt 				}
134*a1157835SDaniel Fojt 				if (bin[0] == 0x00) {
135*a1157835SDaniel Fojt 					*spos++ = bin[1];
136*a1157835SDaniel Fojt 				} else {
137*a1157835SDaniel Fojt 					*spos++ = bin[0];
138*a1157835SDaniel Fojt 					*spos++ = bin[1];
139*a1157835SDaniel Fojt 				}
140*a1157835SDaniel Fojt 				pos += 4;
141*a1157835SDaniel Fojt 				break;
142*a1157835SDaniel Fojt 			default:
143*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
144*a1157835SDaniel Fojt 					   "JSON: Unknown escape '%c'", *pos);
145*a1157835SDaniel Fojt 				goto fail;
146*a1157835SDaniel Fojt 			}
147*a1157835SDaniel Fojt 			break;
148*a1157835SDaniel Fojt 		default:
149*a1157835SDaniel Fojt 			*spos++ = *pos;
150*a1157835SDaniel Fojt 			break;
151*a1157835SDaniel Fojt 		}
152*a1157835SDaniel Fojt 	}
153*a1157835SDaniel Fojt 
154*a1157835SDaniel Fojt fail:
155*a1157835SDaniel Fojt 	os_free(str);
156*a1157835SDaniel Fojt 	return NULL;
157*a1157835SDaniel Fojt }
158*a1157835SDaniel Fojt 
159*a1157835SDaniel Fojt 
json_parse_number(const char ** json_pos,const char * end,int * ret_val)160*a1157835SDaniel Fojt static int json_parse_number(const char **json_pos, const char *end,
161*a1157835SDaniel Fojt 			     int *ret_val)
162*a1157835SDaniel Fojt {
163*a1157835SDaniel Fojt 	const char *pos = *json_pos;
164*a1157835SDaniel Fojt 	size_t len;
165*a1157835SDaniel Fojt 	char *str;
166*a1157835SDaniel Fojt 
167*a1157835SDaniel Fojt 	for (; pos < end; pos++) {
168*a1157835SDaniel Fojt 		if (*pos != '-' && (*pos < '0' || *pos > '9')) {
169*a1157835SDaniel Fojt 			pos--;
170*a1157835SDaniel Fojt 			break;
171*a1157835SDaniel Fojt 		}
172*a1157835SDaniel Fojt 	}
173*a1157835SDaniel Fojt 	if (pos == end)
174*a1157835SDaniel Fojt 		pos--;
175*a1157835SDaniel Fojt 	if (pos < *json_pos)
176*a1157835SDaniel Fojt 		return -1;
177*a1157835SDaniel Fojt 	len = pos - *json_pos + 1;
178*a1157835SDaniel Fojt 	str = os_malloc(len + 1);
179*a1157835SDaniel Fojt 	if (!str)
180*a1157835SDaniel Fojt 		return -1;
181*a1157835SDaniel Fojt 	os_memcpy(str, *json_pos, len);
182*a1157835SDaniel Fojt 	str[len] = '\0';
183*a1157835SDaniel Fojt 
184*a1157835SDaniel Fojt 	*ret_val = atoi(str);
185*a1157835SDaniel Fojt 	os_free(str);
186*a1157835SDaniel Fojt 	*json_pos = pos;
187*a1157835SDaniel Fojt 	return 0;
188*a1157835SDaniel Fojt }
189*a1157835SDaniel Fojt 
190*a1157835SDaniel Fojt 
json_check_tree_state(struct json_token * token)191*a1157835SDaniel Fojt static int json_check_tree_state(struct json_token *token)
192*a1157835SDaniel Fojt {
193*a1157835SDaniel Fojt 	if (!token)
194*a1157835SDaniel Fojt 		return 0;
195*a1157835SDaniel Fojt 	if (json_check_tree_state(token->child) < 0 ||
196*a1157835SDaniel Fojt 	    json_check_tree_state(token->sibling) < 0)
197*a1157835SDaniel Fojt 		return -1;
198*a1157835SDaniel Fojt 	if (token->state != JSON_COMPLETED) {
199*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
200*a1157835SDaniel Fojt 			   "JSON: Unexpected token state %d (name=%s type=%d)",
201*a1157835SDaniel Fojt 			   token->state, token->name ? token->name : "N/A",
202*a1157835SDaniel Fojt 			   token->type);
203*a1157835SDaniel Fojt 		return -1;
204*a1157835SDaniel Fojt 	}
205*a1157835SDaniel Fojt 	return 0;
206*a1157835SDaniel Fojt }
207*a1157835SDaniel Fojt 
208*a1157835SDaniel Fojt 
json_alloc_token(unsigned int * tokens)209*a1157835SDaniel Fojt static struct json_token * json_alloc_token(unsigned int *tokens)
210*a1157835SDaniel Fojt {
211*a1157835SDaniel Fojt 	(*tokens)++;
212*a1157835SDaniel Fojt 	if (*tokens > JSON_MAX_TOKENS) {
213*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded");
214*a1157835SDaniel Fojt 		return NULL;
215*a1157835SDaniel Fojt 	}
216*a1157835SDaniel Fojt 	return os_zalloc(sizeof(struct json_token));
217*a1157835SDaniel Fojt }
218*a1157835SDaniel Fojt 
219*a1157835SDaniel Fojt 
json_parse(const char * data,size_t data_len)220*a1157835SDaniel Fojt struct json_token * json_parse(const char *data, size_t data_len)
221*a1157835SDaniel Fojt {
222*a1157835SDaniel Fojt 	struct json_token *root = NULL, *curr_token = NULL, *token = NULL;
223*a1157835SDaniel Fojt 	const char *pos, *end;
224*a1157835SDaniel Fojt 	char *str;
225*a1157835SDaniel Fojt 	int num;
226*a1157835SDaniel Fojt 	unsigned int depth = 0;
227*a1157835SDaniel Fojt 	unsigned int tokens = 0;
228*a1157835SDaniel Fojt 
229*a1157835SDaniel Fojt 	pos = data;
230*a1157835SDaniel Fojt 	end = data + data_len;
231*a1157835SDaniel Fojt 
232*a1157835SDaniel Fojt 	for (; pos < end; pos++) {
233*a1157835SDaniel Fojt 		switch (*pos) {
234*a1157835SDaniel Fojt 		case '[': /* start array */
235*a1157835SDaniel Fojt 		case '{': /* start object */
236*a1157835SDaniel Fojt 			if (!curr_token) {
237*a1157835SDaniel Fojt 				token = json_alloc_token(&tokens);
238*a1157835SDaniel Fojt 				if (!token)
239*a1157835SDaniel Fojt 					goto fail;
240*a1157835SDaniel Fojt 				if (!root)
241*a1157835SDaniel Fojt 					root = token;
242*a1157835SDaniel Fojt 			} else if (curr_token->state == JSON_WAITING_VALUE) {
243*a1157835SDaniel Fojt 				token = curr_token;
244*a1157835SDaniel Fojt 			} else if (curr_token->parent &&
245*a1157835SDaniel Fojt 				   curr_token->parent->type == JSON_ARRAY &&
246*a1157835SDaniel Fojt 				   curr_token->parent->state == JSON_STARTED &&
247*a1157835SDaniel Fojt 				   curr_token->state == JSON_EMPTY) {
248*a1157835SDaniel Fojt 				token = curr_token;
249*a1157835SDaniel Fojt 			} else {
250*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
251*a1157835SDaniel Fojt 					   "JSON: Invalid state for start array/object");
252*a1157835SDaniel Fojt 				goto fail;
253*a1157835SDaniel Fojt 			}
254*a1157835SDaniel Fojt 			depth++;
255*a1157835SDaniel Fojt 			if (depth > JSON_MAX_DEPTH) {
256*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
257*a1157835SDaniel Fojt 					   "JSON: Max depth exceeded");
258*a1157835SDaniel Fojt 				goto fail;
259*a1157835SDaniel Fojt 			}
260*a1157835SDaniel Fojt 			token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT;
261*a1157835SDaniel Fojt 			token->state = JSON_STARTED;
262*a1157835SDaniel Fojt 			token->child = json_alloc_token(&tokens);
263*a1157835SDaniel Fojt 			if (!token->child)
264*a1157835SDaniel Fojt 				goto fail;
265*a1157835SDaniel Fojt 			curr_token = token->child;
266*a1157835SDaniel Fojt 			curr_token->parent = token;
267*a1157835SDaniel Fojt 			curr_token->state = JSON_EMPTY;
268*a1157835SDaniel Fojt 			break;
269*a1157835SDaniel Fojt 		case ']': /* end array */
270*a1157835SDaniel Fojt 		case '}': /* end object */
271*a1157835SDaniel Fojt 			if (!curr_token || !curr_token->parent ||
272*a1157835SDaniel Fojt 			    curr_token->parent->state != JSON_STARTED) {
273*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
274*a1157835SDaniel Fojt 					   "JSON: Invalid state for end array/object");
275*a1157835SDaniel Fojt 				goto fail;
276*a1157835SDaniel Fojt 			}
277*a1157835SDaniel Fojt 			depth--;
278*a1157835SDaniel Fojt 			curr_token = curr_token->parent;
279*a1157835SDaniel Fojt 			if ((*pos == ']' &&
280*a1157835SDaniel Fojt 			     curr_token->type != JSON_ARRAY) ||
281*a1157835SDaniel Fojt 			    (*pos == '}' &&
282*a1157835SDaniel Fojt 			     curr_token->type != JSON_OBJECT)) {
283*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
284*a1157835SDaniel Fojt 					   "JSON: Array/Object mismatch");
285*a1157835SDaniel Fojt 				goto fail;
286*a1157835SDaniel Fojt 			}
287*a1157835SDaniel Fojt 			if (curr_token->child->state == JSON_EMPTY &&
288*a1157835SDaniel Fojt 			    !curr_token->child->child &&
289*a1157835SDaniel Fojt 			    !curr_token->child->sibling) {
290*a1157835SDaniel Fojt 				/* Remove pending child token since the
291*a1157835SDaniel Fojt 				 * array/object was empty. */
292*a1157835SDaniel Fojt 				json_free(curr_token->child);
293*a1157835SDaniel Fojt 				curr_token->child = NULL;
294*a1157835SDaniel Fojt 			}
295*a1157835SDaniel Fojt 			curr_token->state = JSON_COMPLETED;
296*a1157835SDaniel Fojt 			break;
297*a1157835SDaniel Fojt 		case '\"': /* string */
298*a1157835SDaniel Fojt 			str = json_parse_string(&pos, end);
299*a1157835SDaniel Fojt 			if (!str)
300*a1157835SDaniel Fojt 				goto fail;
301*a1157835SDaniel Fojt 			if (!curr_token) {
302*a1157835SDaniel Fojt 				token = json_alloc_token(&tokens);
303*a1157835SDaniel Fojt 				if (!token)
304*a1157835SDaniel Fojt 					goto fail;
305*a1157835SDaniel Fojt 				token->type = JSON_STRING;
306*a1157835SDaniel Fojt 				token->string = str;
307*a1157835SDaniel Fojt 				token->state = JSON_COMPLETED;
308*a1157835SDaniel Fojt 			} else if (curr_token->parent &&
309*a1157835SDaniel Fojt 				   curr_token->parent->type == JSON_ARRAY &&
310*a1157835SDaniel Fojt 				   curr_token->parent->state == JSON_STARTED &&
311*a1157835SDaniel Fojt 				   curr_token->state == JSON_EMPTY) {
312*a1157835SDaniel Fojt 				curr_token->string = str;
313*a1157835SDaniel Fojt 				curr_token->state = JSON_COMPLETED;
314*a1157835SDaniel Fojt 				curr_token->type = JSON_STRING;
315*a1157835SDaniel Fojt 				wpa_printf(MSG_MSGDUMP,
316*a1157835SDaniel Fojt 					   "JSON: String value: '%s'",
317*a1157835SDaniel Fojt 					   curr_token->string);
318*a1157835SDaniel Fojt 			} else if (curr_token->state == JSON_EMPTY) {
319*a1157835SDaniel Fojt 				curr_token->type = JSON_VALUE;
320*a1157835SDaniel Fojt 				curr_token->name = str;
321*a1157835SDaniel Fojt 				curr_token->state = JSON_STARTED;
322*a1157835SDaniel Fojt 			} else if (curr_token->state == JSON_WAITING_VALUE) {
323*a1157835SDaniel Fojt 				curr_token->string = str;
324*a1157835SDaniel Fojt 				curr_token->state = JSON_COMPLETED;
325*a1157835SDaniel Fojt 				curr_token->type = JSON_STRING;
326*a1157835SDaniel Fojt 				wpa_printf(MSG_MSGDUMP,
327*a1157835SDaniel Fojt 					   "JSON: String value: '%s' = '%s'",
328*a1157835SDaniel Fojt 					   curr_token->name,
329*a1157835SDaniel Fojt 					   curr_token->string);
330*a1157835SDaniel Fojt 			} else {
331*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
332*a1157835SDaniel Fojt 					   "JSON: Invalid state for a string");
333*a1157835SDaniel Fojt 				os_free(str);
334*a1157835SDaniel Fojt 				goto fail;
335*a1157835SDaniel Fojt 			}
336*a1157835SDaniel Fojt 			break;
337*a1157835SDaniel Fojt 		case ' ':
338*a1157835SDaniel Fojt 		case '\t':
339*a1157835SDaniel Fojt 		case '\r':
340*a1157835SDaniel Fojt 		case '\n':
341*a1157835SDaniel Fojt 			/* ignore whitespace */
342*a1157835SDaniel Fojt 			break;
343*a1157835SDaniel Fojt 		case ':': /* name/value separator */
344*a1157835SDaniel Fojt 			if (!curr_token || curr_token->state != JSON_STARTED)
345*a1157835SDaniel Fojt 				goto fail;
346*a1157835SDaniel Fojt 			curr_token->state = JSON_WAITING_VALUE;
347*a1157835SDaniel Fojt 			break;
348*a1157835SDaniel Fojt 		case ',': /* member separator */
349*a1157835SDaniel Fojt 			if (!curr_token)
350*a1157835SDaniel Fojt 				goto fail;
351*a1157835SDaniel Fojt 			curr_token->sibling = json_alloc_token(&tokens);
352*a1157835SDaniel Fojt 			if (!curr_token->sibling)
353*a1157835SDaniel Fojt 				goto fail;
354*a1157835SDaniel Fojt 			curr_token->sibling->parent = curr_token->parent;
355*a1157835SDaniel Fojt 			curr_token = curr_token->sibling;
356*a1157835SDaniel Fojt 			curr_token->state = JSON_EMPTY;
357*a1157835SDaniel Fojt 			break;
358*a1157835SDaniel Fojt 		case 't': /* true */
359*a1157835SDaniel Fojt 		case 'f': /* false */
360*a1157835SDaniel Fojt 		case 'n': /* null */
361*a1157835SDaniel Fojt 			if (!((end - pos >= 4 &&
362*a1157835SDaniel Fojt 			       os_strncmp(pos, "true", 4) == 0) ||
363*a1157835SDaniel Fojt 			      (end - pos >= 5 &&
364*a1157835SDaniel Fojt 			       os_strncmp(pos, "false", 5) == 0) ||
365*a1157835SDaniel Fojt 			      (end - pos >= 4 &&
366*a1157835SDaniel Fojt 			       os_strncmp(pos, "null", 4) == 0))) {
367*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
368*a1157835SDaniel Fojt 					   "JSON: Invalid literal name");
369*a1157835SDaniel Fojt 				goto fail;
370*a1157835SDaniel Fojt 			}
371*a1157835SDaniel Fojt 			if (!curr_token) {
372*a1157835SDaniel Fojt 				token = json_alloc_token(&tokens);
373*a1157835SDaniel Fojt 				if (!token)
374*a1157835SDaniel Fojt 					goto fail;
375*a1157835SDaniel Fojt 				curr_token = token;
376*a1157835SDaniel Fojt 			} else if (curr_token->state == JSON_WAITING_VALUE) {
377*a1157835SDaniel Fojt 				wpa_printf(MSG_MSGDUMP,
378*a1157835SDaniel Fojt 					   "JSON: Literal name: '%s' = %c",
379*a1157835SDaniel Fojt 					   curr_token->name, *pos);
380*a1157835SDaniel Fojt 			} else if (curr_token->parent &&
381*a1157835SDaniel Fojt 				   curr_token->parent->type == JSON_ARRAY &&
382*a1157835SDaniel Fojt 				   curr_token->parent->state == JSON_STARTED &&
383*a1157835SDaniel Fojt 				   curr_token->state == JSON_EMPTY) {
384*a1157835SDaniel Fojt 				wpa_printf(MSG_MSGDUMP,
385*a1157835SDaniel Fojt 					   "JSON: Literal name: %c", *pos);
386*a1157835SDaniel Fojt 			} else {
387*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
388*a1157835SDaniel Fojt 					   "JSON: Invalid state for a literal name");
389*a1157835SDaniel Fojt 				goto fail;
390*a1157835SDaniel Fojt 			}
391*a1157835SDaniel Fojt 			switch (*pos) {
392*a1157835SDaniel Fojt 			case 't':
393*a1157835SDaniel Fojt 				curr_token->type = JSON_BOOLEAN;
394*a1157835SDaniel Fojt 				curr_token->number = 1;
395*a1157835SDaniel Fojt 				pos += 3;
396*a1157835SDaniel Fojt 				break;
397*a1157835SDaniel Fojt 			case 'f':
398*a1157835SDaniel Fojt 				curr_token->type = JSON_BOOLEAN;
399*a1157835SDaniel Fojt 				curr_token->number = 0;
400*a1157835SDaniel Fojt 				pos += 4;
401*a1157835SDaniel Fojt 				break;
402*a1157835SDaniel Fojt 			case 'n':
403*a1157835SDaniel Fojt 				curr_token->type = JSON_NULL;
404*a1157835SDaniel Fojt 				pos += 3;
405*a1157835SDaniel Fojt 				break;
406*a1157835SDaniel Fojt 			}
407*a1157835SDaniel Fojt 			curr_token->state = JSON_COMPLETED;
408*a1157835SDaniel Fojt 			break;
409*a1157835SDaniel Fojt 		case '-':
410*a1157835SDaniel Fojt 		case '0':
411*a1157835SDaniel Fojt 		case '1':
412*a1157835SDaniel Fojt 		case '2':
413*a1157835SDaniel Fojt 		case '3':
414*a1157835SDaniel Fojt 		case '4':
415*a1157835SDaniel Fojt 		case '5':
416*a1157835SDaniel Fojt 		case '6':
417*a1157835SDaniel Fojt 		case '7':
418*a1157835SDaniel Fojt 		case '8':
419*a1157835SDaniel Fojt 		case '9':
420*a1157835SDaniel Fojt 			/* number */
421*a1157835SDaniel Fojt 			if (json_parse_number(&pos, end, &num) < 0)
422*a1157835SDaniel Fojt 				goto fail;
423*a1157835SDaniel Fojt 			if (!curr_token) {
424*a1157835SDaniel Fojt 				token = json_alloc_token(&tokens);
425*a1157835SDaniel Fojt 				if (!token)
426*a1157835SDaniel Fojt 					goto fail;
427*a1157835SDaniel Fojt 				token->type = JSON_NUMBER;
428*a1157835SDaniel Fojt 				token->number = num;
429*a1157835SDaniel Fojt 				token->state = JSON_COMPLETED;
430*a1157835SDaniel Fojt 			} else if (curr_token->state == JSON_WAITING_VALUE) {
431*a1157835SDaniel Fojt 				curr_token->number = num;
432*a1157835SDaniel Fojt 				curr_token->state = JSON_COMPLETED;
433*a1157835SDaniel Fojt 				curr_token->type = JSON_NUMBER;
434*a1157835SDaniel Fojt 				wpa_printf(MSG_MSGDUMP,
435*a1157835SDaniel Fojt 					   "JSON: Number value: '%s' = '%d'",
436*a1157835SDaniel Fojt 					   curr_token->name,
437*a1157835SDaniel Fojt 					   curr_token->number);
438*a1157835SDaniel Fojt 			} else if (curr_token->parent &&
439*a1157835SDaniel Fojt 				   curr_token->parent->type == JSON_ARRAY &&
440*a1157835SDaniel Fojt 				   curr_token->parent->state == JSON_STARTED &&
441*a1157835SDaniel Fojt 				   curr_token->state == JSON_EMPTY) {
442*a1157835SDaniel Fojt 				curr_token->number = num;
443*a1157835SDaniel Fojt 				curr_token->state = JSON_COMPLETED;
444*a1157835SDaniel Fojt 				curr_token->type = JSON_NUMBER;
445*a1157835SDaniel Fojt 				wpa_printf(MSG_MSGDUMP,
446*a1157835SDaniel Fojt 					   "JSON: Number value: %d",
447*a1157835SDaniel Fojt 					   curr_token->number);
448*a1157835SDaniel Fojt 			} else {
449*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
450*a1157835SDaniel Fojt 					   "JSON: Invalid state for a number");
451*a1157835SDaniel Fojt 				goto fail;
452*a1157835SDaniel Fojt 			}
453*a1157835SDaniel Fojt 			break;
454*a1157835SDaniel Fojt 		default:
455*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
456*a1157835SDaniel Fojt 				   "JSON: Unexpected JSON character: %c", *pos);
457*a1157835SDaniel Fojt 			goto fail;
458*a1157835SDaniel Fojt 		}
459*a1157835SDaniel Fojt 
460*a1157835SDaniel Fojt 		if (!root)
461*a1157835SDaniel Fojt 			root = token;
462*a1157835SDaniel Fojt 		if (!curr_token)
463*a1157835SDaniel Fojt 			curr_token = token;
464*a1157835SDaniel Fojt 	}
465*a1157835SDaniel Fojt 
466*a1157835SDaniel Fojt 	if (json_check_tree_state(root) < 0) {
467*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree");
468*a1157835SDaniel Fojt 		goto fail;
469*a1157835SDaniel Fojt 	}
470*a1157835SDaniel Fojt 
471*a1157835SDaniel Fojt 	return root;
472*a1157835SDaniel Fojt fail:
473*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "JSON: Parsing failed");
474*a1157835SDaniel Fojt 	json_free(root);
475*a1157835SDaniel Fojt 	return NULL;
476*a1157835SDaniel Fojt }
477*a1157835SDaniel Fojt 
478*a1157835SDaniel Fojt 
json_free(struct json_token * json)479*a1157835SDaniel Fojt void json_free(struct json_token *json)
480*a1157835SDaniel Fojt {
481*a1157835SDaniel Fojt 	if (!json)
482*a1157835SDaniel Fojt 		return;
483*a1157835SDaniel Fojt 	json_free(json->child);
484*a1157835SDaniel Fojt 	json_free(json->sibling);
485*a1157835SDaniel Fojt 	os_free(json->name);
486*a1157835SDaniel Fojt 	os_free(json->string);
487*a1157835SDaniel Fojt 	os_free(json);
488*a1157835SDaniel Fojt }
489*a1157835SDaniel Fojt 
490*a1157835SDaniel Fojt 
json_get_member(struct json_token * json,const char * name)491*a1157835SDaniel Fojt struct json_token * json_get_member(struct json_token *json, const char *name)
492*a1157835SDaniel Fojt {
493*a1157835SDaniel Fojt 	struct json_token *token, *ret = NULL;
494*a1157835SDaniel Fojt 
495*a1157835SDaniel Fojt 	if (!json || json->type != JSON_OBJECT)
496*a1157835SDaniel Fojt 		return NULL;
497*a1157835SDaniel Fojt 	/* Return last matching entry */
498*a1157835SDaniel Fojt 	for (token = json->child; token; token = token->sibling) {
499*a1157835SDaniel Fojt 		if (token->name && os_strcmp(token->name, name) == 0)
500*a1157835SDaniel Fojt 			ret = token;
501*a1157835SDaniel Fojt 	}
502*a1157835SDaniel Fojt 	return ret;
503*a1157835SDaniel Fojt }
504*a1157835SDaniel Fojt 
505*a1157835SDaniel Fojt 
json_get_member_base64url(struct json_token * json,const char * name)506*a1157835SDaniel Fojt struct wpabuf * json_get_member_base64url(struct json_token *json,
507*a1157835SDaniel Fojt 					  const char *name)
508*a1157835SDaniel Fojt {
509*a1157835SDaniel Fojt 	struct json_token *token;
510*a1157835SDaniel Fojt 	unsigned char *buf;
511*a1157835SDaniel Fojt 	size_t buflen;
512*a1157835SDaniel Fojt 	struct wpabuf *ret;
513*a1157835SDaniel Fojt 
514*a1157835SDaniel Fojt 	token = json_get_member(json, name);
515*a1157835SDaniel Fojt 	if (!token || token->type != JSON_STRING)
516*a1157835SDaniel Fojt 		return NULL;
517*a1157835SDaniel Fojt 	buf = base64_url_decode((const unsigned char *) token->string,
518*a1157835SDaniel Fojt 				os_strlen(token->string), &buflen);
519*a1157835SDaniel Fojt 	if (!buf)
520*a1157835SDaniel Fojt 		return NULL;
521*a1157835SDaniel Fojt 	ret = wpabuf_alloc_ext_data(buf, buflen);
522*a1157835SDaniel Fojt 	if (!ret)
523*a1157835SDaniel Fojt 		os_free(buf);
524*a1157835SDaniel Fojt 
525*a1157835SDaniel Fojt 	return ret;
526*a1157835SDaniel Fojt }
527*a1157835SDaniel Fojt 
528*a1157835SDaniel Fojt 
json_type_str(enum json_type type)529*a1157835SDaniel Fojt static const char * json_type_str(enum json_type type)
530*a1157835SDaniel Fojt {
531*a1157835SDaniel Fojt 	switch (type) {
532*a1157835SDaniel Fojt 	case JSON_VALUE:
533*a1157835SDaniel Fojt 		return "VALUE";
534*a1157835SDaniel Fojt 	case JSON_OBJECT:
535*a1157835SDaniel Fojt 		return "OBJECT";
536*a1157835SDaniel Fojt 	case JSON_ARRAY:
537*a1157835SDaniel Fojt 		return "ARRAY";
538*a1157835SDaniel Fojt 	case JSON_STRING:
539*a1157835SDaniel Fojt 		return "STRING";
540*a1157835SDaniel Fojt 	case JSON_NUMBER:
541*a1157835SDaniel Fojt 		return "NUMBER";
542*a1157835SDaniel Fojt 	case JSON_BOOLEAN:
543*a1157835SDaniel Fojt 		return "BOOLEAN";
544*a1157835SDaniel Fojt 	case JSON_NULL:
545*a1157835SDaniel Fojt 		return "NULL";
546*a1157835SDaniel Fojt 	}
547*a1157835SDaniel Fojt 	return "??";
548*a1157835SDaniel Fojt }
549*a1157835SDaniel Fojt 
550*a1157835SDaniel Fojt 
json_print_token(struct json_token * token,int depth,char * buf,size_t buflen)551*a1157835SDaniel Fojt static void json_print_token(struct json_token *token, int depth,
552*a1157835SDaniel Fojt 			     char *buf, size_t buflen)
553*a1157835SDaniel Fojt {
554*a1157835SDaniel Fojt 	size_t len;
555*a1157835SDaniel Fojt 	int ret;
556*a1157835SDaniel Fojt 
557*a1157835SDaniel Fojt 	if (!token)
558*a1157835SDaniel Fojt 		return;
559*a1157835SDaniel Fojt 	len = os_strlen(buf);
560*a1157835SDaniel Fojt 	ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]",
561*a1157835SDaniel Fojt 			  depth, json_type_str(token->type),
562*a1157835SDaniel Fojt 			  token->name ? token->name : "");
563*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret)) {
564*a1157835SDaniel Fojt 		buf[len] = '\0';
565*a1157835SDaniel Fojt 		return;
566*a1157835SDaniel Fojt 	}
567*a1157835SDaniel Fojt 	json_print_token(token->child, depth + 1, buf, buflen);
568*a1157835SDaniel Fojt 	json_print_token(token->sibling, depth, buf, buflen);
569*a1157835SDaniel Fojt }
570*a1157835SDaniel Fojt 
571*a1157835SDaniel Fojt 
json_print_tree(struct json_token * root,char * buf,size_t buflen)572*a1157835SDaniel Fojt void json_print_tree(struct json_token *root, char *buf, size_t buflen)
573*a1157835SDaniel Fojt {
574*a1157835SDaniel Fojt 	buf[0] = '\0';
575*a1157835SDaniel Fojt 	json_print_token(root, 1, buf, buflen);
576*a1157835SDaniel Fojt }
577