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