xref: /netbsd-src/external/bsd/wpa/dist/src/utils/json.c (revision bb6183629cf165db498d8e1f4e2de129f7efb21c)
10a73ee0aSchristos /*
20a73ee0aSchristos  * JavaScript Object Notation (JSON) parser (RFC7159)
30a73ee0aSchristos  * Copyright (c) 2017, Qualcomm Atheros, Inc.
40a73ee0aSchristos  *
50a73ee0aSchristos  * This software may be distributed under the terms of the BSD license.
60a73ee0aSchristos  * See README for more details.
70a73ee0aSchristos  */
80a73ee0aSchristos 
90a73ee0aSchristos #include "includes.h"
100a73ee0aSchristos 
110a73ee0aSchristos #include "common.h"
120a73ee0aSchristos #include "base64.h"
130a73ee0aSchristos #include "json.h"
140a73ee0aSchristos 
150a73ee0aSchristos #define JSON_MAX_DEPTH 10
160a73ee0aSchristos #define JSON_MAX_TOKENS 500
170a73ee0aSchristos 
180a73ee0aSchristos 
190a73ee0aSchristos void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
200a73ee0aSchristos {
210a73ee0aSchristos 	char *end = txt + maxlen;
220a73ee0aSchristos 	size_t i;
230a73ee0aSchristos 
240a73ee0aSchristos 	for (i = 0; i < len; i++) {
250a73ee0aSchristos 		if (txt + 4 >= end)
260a73ee0aSchristos 			break;
270a73ee0aSchristos 
280a73ee0aSchristos 		switch (data[i]) {
290a73ee0aSchristos 		case '\"':
300a73ee0aSchristos 			*txt++ = '\\';
310a73ee0aSchristos 			*txt++ = '\"';
320a73ee0aSchristos 			break;
330a73ee0aSchristos 		case '\\':
340a73ee0aSchristos 			*txt++ = '\\';
350a73ee0aSchristos 			*txt++ = '\\';
360a73ee0aSchristos 			break;
370a73ee0aSchristos 		case '\n':
380a73ee0aSchristos 			*txt++ = '\\';
390a73ee0aSchristos 			*txt++ = 'n';
400a73ee0aSchristos 			break;
410a73ee0aSchristos 		case '\r':
420a73ee0aSchristos 			*txt++ = '\\';
430a73ee0aSchristos 			*txt++ = 'r';
440a73ee0aSchristos 			break;
450a73ee0aSchristos 		case '\t':
460a73ee0aSchristos 			*txt++ = '\\';
470a73ee0aSchristos 			*txt++ = 't';
480a73ee0aSchristos 			break;
490a73ee0aSchristos 		default:
500a73ee0aSchristos 			if (data[i] >= 32 && data[i] <= 126) {
510a73ee0aSchristos 				*txt++ = data[i];
520a73ee0aSchristos 			} else {
530a73ee0aSchristos 				txt += os_snprintf(txt, end - txt, "\\u%04x",
54*bb618362Schristos 						   (unsigned char) data[i]);
550a73ee0aSchristos 			}
560a73ee0aSchristos 			break;
570a73ee0aSchristos 		}
580a73ee0aSchristos 	}
590a73ee0aSchristos 
600a73ee0aSchristos 	*txt = '\0';
610a73ee0aSchristos }
620a73ee0aSchristos 
630a73ee0aSchristos 
640a73ee0aSchristos static char * json_parse_string(const char **json_pos, const char *end)
650a73ee0aSchristos {
660a73ee0aSchristos 	const char *pos = *json_pos;
670a73ee0aSchristos 	char *str, *spos, *s_end;
680a73ee0aSchristos 	size_t max_len, buf_len;
690a73ee0aSchristos 	u8 bin[2];
700a73ee0aSchristos 
710a73ee0aSchristos 	pos++; /* skip starting quote */
720a73ee0aSchristos 
730a73ee0aSchristos 	max_len = end - pos + 1;
740a73ee0aSchristos 	buf_len = max_len > 10 ? 10 : max_len;
750a73ee0aSchristos 	str = os_malloc(buf_len);
760a73ee0aSchristos 	if (!str)
770a73ee0aSchristos 		return NULL;
780a73ee0aSchristos 	spos = str;
790a73ee0aSchristos 	s_end = str + buf_len;
800a73ee0aSchristos 
810a73ee0aSchristos 	for (; pos < end; pos++) {
820a73ee0aSchristos 		if (buf_len < max_len && s_end - spos < 3) {
830a73ee0aSchristos 			char *tmp;
840a73ee0aSchristos 			int idx;
850a73ee0aSchristos 
860a73ee0aSchristos 			idx = spos - str;
870a73ee0aSchristos 			buf_len *= 2;
880a73ee0aSchristos 			if (buf_len > max_len)
890a73ee0aSchristos 				buf_len = max_len;
900a73ee0aSchristos 			tmp = os_realloc(str, buf_len);
910a73ee0aSchristos 			if (!tmp)
920a73ee0aSchristos 				goto fail;
930a73ee0aSchristos 			str = tmp;
940a73ee0aSchristos 			spos = str + idx;
950a73ee0aSchristos 			s_end = str + buf_len;
960a73ee0aSchristos 		}
970a73ee0aSchristos 
980a73ee0aSchristos 		switch (*pos) {
990a73ee0aSchristos 		case '\"': /* end string */
1000a73ee0aSchristos 			*spos = '\0';
1010a73ee0aSchristos 			/* caller will move to the next position */
1020a73ee0aSchristos 			*json_pos = pos;
1030a73ee0aSchristos 			return str;
1040a73ee0aSchristos 		case '\\':
1050a73ee0aSchristos 			pos++;
1063d6c0713Schristos 			if (pos >= end) {
1073d6c0713Schristos 				wpa_printf(MSG_DEBUG,
1083d6c0713Schristos 					   "JSON: Truncated \\ escape");
1093d6c0713Schristos 				goto fail;
1103d6c0713Schristos 			}
1110a73ee0aSchristos 			switch (*pos) {
1120a73ee0aSchristos 			case '"':
1130a73ee0aSchristos 			case '\\':
1140a73ee0aSchristos 			case '/':
1150a73ee0aSchristos 				*spos++ = *pos;
1160a73ee0aSchristos 				break;
1170a73ee0aSchristos 			case 'n':
1180a73ee0aSchristos 				*spos++ = '\n';
1190a73ee0aSchristos 				break;
1200a73ee0aSchristos 			case 'r':
1210a73ee0aSchristos 				*spos++ = '\r';
1220a73ee0aSchristos 				break;
1230a73ee0aSchristos 			case 't':
1240a73ee0aSchristos 				*spos++ = '\t';
1250a73ee0aSchristos 				break;
1260a73ee0aSchristos 			case 'u':
1270a73ee0aSchristos 				if (end - pos < 5 ||
1280a73ee0aSchristos 				    hexstr2bin(pos + 1, bin, 2) < 0 ||
1290a73ee0aSchristos 				    bin[1] == 0x00) {
1300a73ee0aSchristos 					wpa_printf(MSG_DEBUG,
1310a73ee0aSchristos 						   "JSON: Invalid \\u escape");
1320a73ee0aSchristos 					goto fail;
1330a73ee0aSchristos 				}
1340a73ee0aSchristos 				if (bin[0] == 0x00) {
1350a73ee0aSchristos 					*spos++ = bin[1];
1360a73ee0aSchristos 				} else {
1370a73ee0aSchristos 					*spos++ = bin[0];
1380a73ee0aSchristos 					*spos++ = bin[1];
1390a73ee0aSchristos 				}
1400a73ee0aSchristos 				pos += 4;
1410a73ee0aSchristos 				break;
1420a73ee0aSchristos 			default:
1430a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
1440a73ee0aSchristos 					   "JSON: Unknown escape '%c'", *pos);
1450a73ee0aSchristos 				goto fail;
1460a73ee0aSchristos 			}
1470a73ee0aSchristos 			break;
1480a73ee0aSchristos 		default:
1490a73ee0aSchristos 			*spos++ = *pos;
1500a73ee0aSchristos 			break;
1510a73ee0aSchristos 		}
1520a73ee0aSchristos 	}
1530a73ee0aSchristos 
1540a73ee0aSchristos fail:
1550a73ee0aSchristos 	os_free(str);
1560a73ee0aSchristos 	return NULL;
1570a73ee0aSchristos }
1580a73ee0aSchristos 
1590a73ee0aSchristos 
1600a73ee0aSchristos static int json_parse_number(const char **json_pos, const char *end,
1610a73ee0aSchristos 			     int *ret_val)
1620a73ee0aSchristos {
1630a73ee0aSchristos 	const char *pos = *json_pos;
1640a73ee0aSchristos 	size_t len;
1650a73ee0aSchristos 	char *str;
1660a73ee0aSchristos 
1670a73ee0aSchristos 	for (; pos < end; pos++) {
1680a73ee0aSchristos 		if (*pos != '-' && (*pos < '0' || *pos > '9')) {
1690a73ee0aSchristos 			pos--;
1700a73ee0aSchristos 			break;
1710a73ee0aSchristos 		}
1720a73ee0aSchristos 	}
1733d6c0713Schristos 	if (pos == end)
1743d6c0713Schristos 		pos--;
1750a73ee0aSchristos 	if (pos < *json_pos)
1760a73ee0aSchristos 		return -1;
1770a73ee0aSchristos 	len = pos - *json_pos + 1;
1780a73ee0aSchristos 	str = os_malloc(len + 1);
1790a73ee0aSchristos 	if (!str)
1800a73ee0aSchristos 		return -1;
1810a73ee0aSchristos 	os_memcpy(str, *json_pos, len);
1820a73ee0aSchristos 	str[len] = '\0';
1830a73ee0aSchristos 
1840a73ee0aSchristos 	*ret_val = atoi(str);
1850a73ee0aSchristos 	os_free(str);
1860a73ee0aSchristos 	*json_pos = pos;
1870a73ee0aSchristos 	return 0;
1880a73ee0aSchristos }
1890a73ee0aSchristos 
1900a73ee0aSchristos 
1910a73ee0aSchristos static int json_check_tree_state(struct json_token *token)
1920a73ee0aSchristos {
1930a73ee0aSchristos 	if (!token)
1940a73ee0aSchristos 		return 0;
1950a73ee0aSchristos 	if (json_check_tree_state(token->child) < 0 ||
1960a73ee0aSchristos 	    json_check_tree_state(token->sibling) < 0)
1970a73ee0aSchristos 		return -1;
1980a73ee0aSchristos 	if (token->state != JSON_COMPLETED) {
1990a73ee0aSchristos 		wpa_printf(MSG_DEBUG,
2000a73ee0aSchristos 			   "JSON: Unexpected token state %d (name=%s type=%d)",
2010a73ee0aSchristos 			   token->state, token->name ? token->name : "N/A",
2020a73ee0aSchristos 			   token->type);
2030a73ee0aSchristos 		return -1;
2040a73ee0aSchristos 	}
2050a73ee0aSchristos 	return 0;
2060a73ee0aSchristos }
2070a73ee0aSchristos 
2080a73ee0aSchristos 
2090a73ee0aSchristos static struct json_token * json_alloc_token(unsigned int *tokens)
2100a73ee0aSchristos {
2110a73ee0aSchristos 	(*tokens)++;
2120a73ee0aSchristos 	if (*tokens > JSON_MAX_TOKENS) {
2130a73ee0aSchristos 		wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded");
2140a73ee0aSchristos 		return NULL;
2150a73ee0aSchristos 	}
2160a73ee0aSchristos 	return os_zalloc(sizeof(struct json_token));
2170a73ee0aSchristos }
2180a73ee0aSchristos 
2190a73ee0aSchristos 
2200a73ee0aSchristos struct json_token * json_parse(const char *data, size_t data_len)
2210a73ee0aSchristos {
2220a73ee0aSchristos 	struct json_token *root = NULL, *curr_token = NULL, *token = NULL;
2230a73ee0aSchristos 	const char *pos, *end;
2240a73ee0aSchristos 	char *str;
2250a73ee0aSchristos 	int num;
2260a73ee0aSchristos 	unsigned int depth = 0;
2270a73ee0aSchristos 	unsigned int tokens = 0;
2280a73ee0aSchristos 
2290a73ee0aSchristos 	pos = data;
2300a73ee0aSchristos 	end = data + data_len;
2310a73ee0aSchristos 
2320a73ee0aSchristos 	for (; pos < end; pos++) {
2330a73ee0aSchristos 		switch (*pos) {
2340a73ee0aSchristos 		case '[': /* start array */
2350a73ee0aSchristos 		case '{': /* start object */
2360a73ee0aSchristos 			if (!curr_token) {
2370a73ee0aSchristos 				token = json_alloc_token(&tokens);
2380a73ee0aSchristos 				if (!token)
2390a73ee0aSchristos 					goto fail;
2400a73ee0aSchristos 				if (!root)
2410a73ee0aSchristos 					root = token;
2420a73ee0aSchristos 			} else if (curr_token->state == JSON_WAITING_VALUE) {
2430a73ee0aSchristos 				token = curr_token;
2440a73ee0aSchristos 			} else if (curr_token->parent &&
2450a73ee0aSchristos 				   curr_token->parent->type == JSON_ARRAY &&
2460a73ee0aSchristos 				   curr_token->parent->state == JSON_STARTED &&
2470a73ee0aSchristos 				   curr_token->state == JSON_EMPTY) {
2480a73ee0aSchristos 				token = curr_token;
2490a73ee0aSchristos 			} else {
2500a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
2510a73ee0aSchristos 					   "JSON: Invalid state for start array/object");
2520a73ee0aSchristos 				goto fail;
2530a73ee0aSchristos 			}
2540a73ee0aSchristos 			depth++;
2550a73ee0aSchristos 			if (depth > JSON_MAX_DEPTH) {
2560a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
2570a73ee0aSchristos 					   "JSON: Max depth exceeded");
2580a73ee0aSchristos 				goto fail;
2590a73ee0aSchristos 			}
2600a73ee0aSchristos 			token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT;
2610a73ee0aSchristos 			token->state = JSON_STARTED;
2620a73ee0aSchristos 			token->child = json_alloc_token(&tokens);
2630a73ee0aSchristos 			if (!token->child)
2640a73ee0aSchristos 				goto fail;
2650a73ee0aSchristos 			curr_token = token->child;
2660a73ee0aSchristos 			curr_token->parent = token;
2670a73ee0aSchristos 			curr_token->state = JSON_EMPTY;
2680a73ee0aSchristos 			break;
2690a73ee0aSchristos 		case ']': /* end array */
2700a73ee0aSchristos 		case '}': /* end object */
2710a73ee0aSchristos 			if (!curr_token || !curr_token->parent ||
2720a73ee0aSchristos 			    curr_token->parent->state != JSON_STARTED) {
2730a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
2740a73ee0aSchristos 					   "JSON: Invalid state for end array/object");
2750a73ee0aSchristos 				goto fail;
2760a73ee0aSchristos 			}
2770a73ee0aSchristos 			depth--;
2780a73ee0aSchristos 			curr_token = curr_token->parent;
2790a73ee0aSchristos 			if ((*pos == ']' &&
2800a73ee0aSchristos 			     curr_token->type != JSON_ARRAY) ||
2810a73ee0aSchristos 			    (*pos == '}' &&
2820a73ee0aSchristos 			     curr_token->type != JSON_OBJECT)) {
2830a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
2840a73ee0aSchristos 					   "JSON: Array/Object mismatch");
2850a73ee0aSchristos 				goto fail;
2860a73ee0aSchristos 			}
2870a73ee0aSchristos 			if (curr_token->child->state == JSON_EMPTY &&
2880a73ee0aSchristos 			    !curr_token->child->child &&
2890a73ee0aSchristos 			    !curr_token->child->sibling) {
2900a73ee0aSchristos 				/* Remove pending child token since the
2910a73ee0aSchristos 				 * array/object was empty. */
2920a73ee0aSchristos 				json_free(curr_token->child);
2930a73ee0aSchristos 				curr_token->child = NULL;
2940a73ee0aSchristos 			}
2950a73ee0aSchristos 			curr_token->state = JSON_COMPLETED;
2960a73ee0aSchristos 			break;
2970a73ee0aSchristos 		case '\"': /* string */
2980a73ee0aSchristos 			str = json_parse_string(&pos, end);
2990a73ee0aSchristos 			if (!str)
3000a73ee0aSchristos 				goto fail;
3010a73ee0aSchristos 			if (!curr_token) {
3020a73ee0aSchristos 				token = json_alloc_token(&tokens);
303*bb618362Schristos 				if (!token) {
304*bb618362Schristos 					os_free(str);
3050a73ee0aSchristos 					goto fail;
306*bb618362Schristos 				}
3070a73ee0aSchristos 				token->type = JSON_STRING;
3080a73ee0aSchristos 				token->string = str;
3090a73ee0aSchristos 				token->state = JSON_COMPLETED;
3100a73ee0aSchristos 			} else if (curr_token->parent &&
3110a73ee0aSchristos 				   curr_token->parent->type == JSON_ARRAY &&
3120a73ee0aSchristos 				   curr_token->parent->state == JSON_STARTED &&
3130a73ee0aSchristos 				   curr_token->state == JSON_EMPTY) {
3140a73ee0aSchristos 				curr_token->string = str;
3150a73ee0aSchristos 				curr_token->state = JSON_COMPLETED;
3160a73ee0aSchristos 				curr_token->type = JSON_STRING;
3170a73ee0aSchristos 				wpa_printf(MSG_MSGDUMP,
3180a73ee0aSchristos 					   "JSON: String value: '%s'",
3190a73ee0aSchristos 					   curr_token->string);
3200a73ee0aSchristos 			} else if (curr_token->state == JSON_EMPTY) {
3210a73ee0aSchristos 				curr_token->type = JSON_VALUE;
3220a73ee0aSchristos 				curr_token->name = str;
3230a73ee0aSchristos 				curr_token->state = JSON_STARTED;
3240a73ee0aSchristos 			} else if (curr_token->state == JSON_WAITING_VALUE) {
3250a73ee0aSchristos 				curr_token->string = str;
3260a73ee0aSchristos 				curr_token->state = JSON_COMPLETED;
3270a73ee0aSchristos 				curr_token->type = JSON_STRING;
3280a73ee0aSchristos 				wpa_printf(MSG_MSGDUMP,
3290a73ee0aSchristos 					   "JSON: String value: '%s' = '%s'",
3300a73ee0aSchristos 					   curr_token->name,
3310a73ee0aSchristos 					   curr_token->string);
3320a73ee0aSchristos 			} else {
3330a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
3340a73ee0aSchristos 					   "JSON: Invalid state for a string");
3350a73ee0aSchristos 				os_free(str);
3360a73ee0aSchristos 				goto fail;
3370a73ee0aSchristos 			}
3380a73ee0aSchristos 			break;
3390a73ee0aSchristos 		case ' ':
3400a73ee0aSchristos 		case '\t':
3410a73ee0aSchristos 		case '\r':
3420a73ee0aSchristos 		case '\n':
3430a73ee0aSchristos 			/* ignore whitespace */
3440a73ee0aSchristos 			break;
3450a73ee0aSchristos 		case ':': /* name/value separator */
3460a73ee0aSchristos 			if (!curr_token || curr_token->state != JSON_STARTED)
3470a73ee0aSchristos 				goto fail;
3480a73ee0aSchristos 			curr_token->state = JSON_WAITING_VALUE;
3490a73ee0aSchristos 			break;
3500a73ee0aSchristos 		case ',': /* member separator */
3510a73ee0aSchristos 			if (!curr_token)
3520a73ee0aSchristos 				goto fail;
3530a73ee0aSchristos 			curr_token->sibling = json_alloc_token(&tokens);
3540a73ee0aSchristos 			if (!curr_token->sibling)
3550a73ee0aSchristos 				goto fail;
3560a73ee0aSchristos 			curr_token->sibling->parent = curr_token->parent;
3570a73ee0aSchristos 			curr_token = curr_token->sibling;
3580a73ee0aSchristos 			curr_token->state = JSON_EMPTY;
3590a73ee0aSchristos 			break;
3600a73ee0aSchristos 		case 't': /* true */
3610a73ee0aSchristos 		case 'f': /* false */
3620a73ee0aSchristos 		case 'n': /* null */
3630a73ee0aSchristos 			if (!((end - pos >= 4 &&
3640a73ee0aSchristos 			       os_strncmp(pos, "true", 4) == 0) ||
3650a73ee0aSchristos 			      (end - pos >= 5 &&
3660a73ee0aSchristos 			       os_strncmp(pos, "false", 5) == 0) ||
3670a73ee0aSchristos 			      (end - pos >= 4 &&
3680a73ee0aSchristos 			       os_strncmp(pos, "null", 4) == 0))) {
3690a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
3700a73ee0aSchristos 					   "JSON: Invalid literal name");
3710a73ee0aSchristos 				goto fail;
3720a73ee0aSchristos 			}
3730a73ee0aSchristos 			if (!curr_token) {
3740a73ee0aSchristos 				token = json_alloc_token(&tokens);
3750a73ee0aSchristos 				if (!token)
3760a73ee0aSchristos 					goto fail;
3770a73ee0aSchristos 				curr_token = token;
3780a73ee0aSchristos 			} else if (curr_token->state == JSON_WAITING_VALUE) {
3790a73ee0aSchristos 				wpa_printf(MSG_MSGDUMP,
3800a73ee0aSchristos 					   "JSON: Literal name: '%s' = %c",
3810a73ee0aSchristos 					   curr_token->name, *pos);
3820a73ee0aSchristos 			} else if (curr_token->parent &&
3830a73ee0aSchristos 				   curr_token->parent->type == JSON_ARRAY &&
3840a73ee0aSchristos 				   curr_token->parent->state == JSON_STARTED &&
3850a73ee0aSchristos 				   curr_token->state == JSON_EMPTY) {
3860a73ee0aSchristos 				wpa_printf(MSG_MSGDUMP,
3870a73ee0aSchristos 					   "JSON: Literal name: %c", *pos);
3880a73ee0aSchristos 			} else {
3890a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
3900a73ee0aSchristos 					   "JSON: Invalid state for a literal name");
3910a73ee0aSchristos 				goto fail;
3920a73ee0aSchristos 			}
3930a73ee0aSchristos 			switch (*pos) {
3940a73ee0aSchristos 			case 't':
3950a73ee0aSchristos 				curr_token->type = JSON_BOOLEAN;
3960a73ee0aSchristos 				curr_token->number = 1;
3970a73ee0aSchristos 				pos += 3;
3980a73ee0aSchristos 				break;
3990a73ee0aSchristos 			case 'f':
4000a73ee0aSchristos 				curr_token->type = JSON_BOOLEAN;
4010a73ee0aSchristos 				curr_token->number = 0;
4020a73ee0aSchristos 				pos += 4;
4030a73ee0aSchristos 				break;
4040a73ee0aSchristos 			case 'n':
4050a73ee0aSchristos 				curr_token->type = JSON_NULL;
4060a73ee0aSchristos 				pos += 3;
4070a73ee0aSchristos 				break;
4080a73ee0aSchristos 			}
4090a73ee0aSchristos 			curr_token->state = JSON_COMPLETED;
4100a73ee0aSchristos 			break;
4110a73ee0aSchristos 		case '-':
4120a73ee0aSchristos 		case '0':
4130a73ee0aSchristos 		case '1':
4140a73ee0aSchristos 		case '2':
4150a73ee0aSchristos 		case '3':
4160a73ee0aSchristos 		case '4':
4170a73ee0aSchristos 		case '5':
4180a73ee0aSchristos 		case '6':
4190a73ee0aSchristos 		case '7':
4200a73ee0aSchristos 		case '8':
4210a73ee0aSchristos 		case '9':
4220a73ee0aSchristos 			/* number */
4230a73ee0aSchristos 			if (json_parse_number(&pos, end, &num) < 0)
4240a73ee0aSchristos 				goto fail;
4250a73ee0aSchristos 			if (!curr_token) {
4260a73ee0aSchristos 				token = json_alloc_token(&tokens);
4270a73ee0aSchristos 				if (!token)
4280a73ee0aSchristos 					goto fail;
4290a73ee0aSchristos 				token->type = JSON_NUMBER;
4300a73ee0aSchristos 				token->number = num;
4310a73ee0aSchristos 				token->state = JSON_COMPLETED;
4320a73ee0aSchristos 			} else if (curr_token->state == JSON_WAITING_VALUE) {
4330a73ee0aSchristos 				curr_token->number = num;
4340a73ee0aSchristos 				curr_token->state = JSON_COMPLETED;
4350a73ee0aSchristos 				curr_token->type = JSON_NUMBER;
4360a73ee0aSchristos 				wpa_printf(MSG_MSGDUMP,
4370a73ee0aSchristos 					   "JSON: Number value: '%s' = '%d'",
4380a73ee0aSchristos 					   curr_token->name,
4390a73ee0aSchristos 					   curr_token->number);
4400a73ee0aSchristos 			} else if (curr_token->parent &&
4410a73ee0aSchristos 				   curr_token->parent->type == JSON_ARRAY &&
4420a73ee0aSchristos 				   curr_token->parent->state == JSON_STARTED &&
4430a73ee0aSchristos 				   curr_token->state == JSON_EMPTY) {
4440a73ee0aSchristos 				curr_token->number = num;
4450a73ee0aSchristos 				curr_token->state = JSON_COMPLETED;
4460a73ee0aSchristos 				curr_token->type = JSON_NUMBER;
4470a73ee0aSchristos 				wpa_printf(MSG_MSGDUMP,
4480a73ee0aSchristos 					   "JSON: Number value: %d",
4490a73ee0aSchristos 					   curr_token->number);
4500a73ee0aSchristos 			} else {
4510a73ee0aSchristos 				wpa_printf(MSG_DEBUG,
4520a73ee0aSchristos 					   "JSON: Invalid state for a number");
4530a73ee0aSchristos 				goto fail;
4540a73ee0aSchristos 			}
4550a73ee0aSchristos 			break;
4560a73ee0aSchristos 		default:
4570a73ee0aSchristos 			wpa_printf(MSG_DEBUG,
4580a73ee0aSchristos 				   "JSON: Unexpected JSON character: %c", *pos);
4590a73ee0aSchristos 			goto fail;
4600a73ee0aSchristos 		}
4610a73ee0aSchristos 
4620a73ee0aSchristos 		if (!root)
4630a73ee0aSchristos 			root = token;
4640a73ee0aSchristos 		if (!curr_token)
4650a73ee0aSchristos 			curr_token = token;
4660a73ee0aSchristos 	}
4670a73ee0aSchristos 
4680a73ee0aSchristos 	if (json_check_tree_state(root) < 0) {
4690a73ee0aSchristos 		wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree");
4700a73ee0aSchristos 		goto fail;
4710a73ee0aSchristos 	}
4720a73ee0aSchristos 
4730a73ee0aSchristos 	return root;
4740a73ee0aSchristos fail:
4750a73ee0aSchristos 	wpa_printf(MSG_DEBUG, "JSON: Parsing failed");
4760a73ee0aSchristos 	json_free(root);
4770a73ee0aSchristos 	return NULL;
4780a73ee0aSchristos }
4790a73ee0aSchristos 
4800a73ee0aSchristos 
4810a73ee0aSchristos void json_free(struct json_token *json)
4820a73ee0aSchristos {
4830a73ee0aSchristos 	if (!json)
4840a73ee0aSchristos 		return;
4850a73ee0aSchristos 	json_free(json->child);
4860a73ee0aSchristos 	json_free(json->sibling);
4870a73ee0aSchristos 	os_free(json->name);
4880a73ee0aSchristos 	os_free(json->string);
4890a73ee0aSchristos 	os_free(json);
4900a73ee0aSchristos }
4910a73ee0aSchristos 
4920a73ee0aSchristos 
4930a73ee0aSchristos struct json_token * json_get_member(struct json_token *json, const char *name)
4940a73ee0aSchristos {
4950a73ee0aSchristos 	struct json_token *token, *ret = NULL;
4960a73ee0aSchristos 
4970a73ee0aSchristos 	if (!json || json->type != JSON_OBJECT)
4980a73ee0aSchristos 		return NULL;
4990a73ee0aSchristos 	/* Return last matching entry */
5000a73ee0aSchristos 	for (token = json->child; token; token = token->sibling) {
5010a73ee0aSchristos 		if (token->name && os_strcmp(token->name, name) == 0)
5020a73ee0aSchristos 			ret = token;
5030a73ee0aSchristos 	}
5040a73ee0aSchristos 	return ret;
5050a73ee0aSchristos }
5060a73ee0aSchristos 
5070a73ee0aSchristos 
5080a73ee0aSchristos struct wpabuf * json_get_member_base64url(struct json_token *json,
5090a73ee0aSchristos 					  const char *name)
5100a73ee0aSchristos {
5110a73ee0aSchristos 	struct json_token *token;
5120a73ee0aSchristos 	unsigned char *buf;
5130a73ee0aSchristos 	size_t buflen;
5140a73ee0aSchristos 	struct wpabuf *ret;
5150a73ee0aSchristos 
5160a73ee0aSchristos 	token = json_get_member(json, name);
5170a73ee0aSchristos 	if (!token || token->type != JSON_STRING)
5180a73ee0aSchristos 		return NULL;
519*bb618362Schristos 	buf = base64_url_decode(token->string, os_strlen(token->string),
520*bb618362Schristos 				&buflen);
521*bb618362Schristos 	if (!buf)
522*bb618362Schristos 		return NULL;
523*bb618362Schristos 	ret = wpabuf_alloc_ext_data(buf, buflen);
524*bb618362Schristos 	if (!ret)
525*bb618362Schristos 		os_free(buf);
526*bb618362Schristos 
527*bb618362Schristos 	return ret;
528*bb618362Schristos }
529*bb618362Schristos 
530*bb618362Schristos 
531*bb618362Schristos struct wpabuf * json_get_member_base64(struct json_token *json,
532*bb618362Schristos 				       const char *name)
533*bb618362Schristos {
534*bb618362Schristos 	struct json_token *token;
535*bb618362Schristos 	unsigned char *buf;
536*bb618362Schristos 	size_t buflen;
537*bb618362Schristos 	struct wpabuf *ret;
538*bb618362Schristos 
539*bb618362Schristos 	token = json_get_member(json, name);
540*bb618362Schristos 	if (!token || token->type != JSON_STRING)
541*bb618362Schristos 		return NULL;
542*bb618362Schristos 	buf = base64_decode(token->string, os_strlen(token->string), &buflen);
5430a73ee0aSchristos 	if (!buf)
5440a73ee0aSchristos 		return NULL;
5450a73ee0aSchristos 	ret = wpabuf_alloc_ext_data(buf, buflen);
5460a73ee0aSchristos 	if (!ret)
5470a73ee0aSchristos 		os_free(buf);
5480a73ee0aSchristos 
5490a73ee0aSchristos 	return ret;
5500a73ee0aSchristos }
5510a73ee0aSchristos 
5520a73ee0aSchristos 
5530a73ee0aSchristos static const char * json_type_str(enum json_type type)
5540a73ee0aSchristos {
5550a73ee0aSchristos 	switch (type) {
5560a73ee0aSchristos 	case JSON_VALUE:
5570a73ee0aSchristos 		return "VALUE";
5580a73ee0aSchristos 	case JSON_OBJECT:
5590a73ee0aSchristos 		return "OBJECT";
5600a73ee0aSchristos 	case JSON_ARRAY:
5610a73ee0aSchristos 		return "ARRAY";
5620a73ee0aSchristos 	case JSON_STRING:
5630a73ee0aSchristos 		return "STRING";
5640a73ee0aSchristos 	case JSON_NUMBER:
5650a73ee0aSchristos 		return "NUMBER";
5660a73ee0aSchristos 	case JSON_BOOLEAN:
5670a73ee0aSchristos 		return "BOOLEAN";
5680a73ee0aSchristos 	case JSON_NULL:
5690a73ee0aSchristos 		return "NULL";
5700a73ee0aSchristos 	}
5710a73ee0aSchristos 	return "??";
5720a73ee0aSchristos }
5730a73ee0aSchristos 
5740a73ee0aSchristos 
5750a73ee0aSchristos static void json_print_token(struct json_token *token, int depth,
5760a73ee0aSchristos 			     char *buf, size_t buflen)
5770a73ee0aSchristos {
5780a73ee0aSchristos 	size_t len;
5790a73ee0aSchristos 	int ret;
5800a73ee0aSchristos 
5810a73ee0aSchristos 	if (!token)
5820a73ee0aSchristos 		return;
5830a73ee0aSchristos 	len = os_strlen(buf);
5840a73ee0aSchristos 	ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]",
5850a73ee0aSchristos 			  depth, json_type_str(token->type),
5860a73ee0aSchristos 			  token->name ? token->name : "");
5870a73ee0aSchristos 	if (os_snprintf_error(buflen - len, ret)) {
5880a73ee0aSchristos 		buf[len] = '\0';
5890a73ee0aSchristos 		return;
5900a73ee0aSchristos 	}
5910a73ee0aSchristos 	json_print_token(token->child, depth + 1, buf, buflen);
5920a73ee0aSchristos 	json_print_token(token->sibling, depth, buf, buflen);
5930a73ee0aSchristos }
5940a73ee0aSchristos 
5950a73ee0aSchristos 
5960a73ee0aSchristos void json_print_tree(struct json_token *root, char *buf, size_t buflen)
5970a73ee0aSchristos {
5980a73ee0aSchristos 	buf[0] = '\0';
5990a73ee0aSchristos 	json_print_token(root, 1, buf, buflen);
6000a73ee0aSchristos }
601*bb618362Schristos 
602*bb618362Schristos 
603*bb618362Schristos void json_add_int(struct wpabuf *json, const char *name, int val)
604*bb618362Schristos {
605*bb618362Schristos 	wpabuf_printf(json, "\"%s\":%d", name, val);
606*bb618362Schristos }
607*bb618362Schristos 
608*bb618362Schristos 
609*bb618362Schristos void json_add_string(struct wpabuf *json, const char *name, const char *val)
610*bb618362Schristos {
611*bb618362Schristos 	wpabuf_printf(json, "\"%s\":\"%s\"", name, val);
612*bb618362Schristos }
613*bb618362Schristos 
614*bb618362Schristos 
615*bb618362Schristos int json_add_string_escape(struct wpabuf *json, const char *name,
616*bb618362Schristos 			   const void *val, size_t len)
617*bb618362Schristos {
618*bb618362Schristos 	char *tmp;
619*bb618362Schristos 	size_t tmp_len = 6 * len + 1;
620*bb618362Schristos 
621*bb618362Schristos 	tmp = os_malloc(tmp_len);
622*bb618362Schristos 	if (!tmp)
623*bb618362Schristos 		return -1;
624*bb618362Schristos 	json_escape_string(tmp, tmp_len, val, len);
625*bb618362Schristos 	json_add_string(json, name, tmp);
626*bb618362Schristos 	bin_clear_free(tmp, tmp_len);
627*bb618362Schristos 	return 0;
628*bb618362Schristos }
629*bb618362Schristos 
630*bb618362Schristos 
631*bb618362Schristos int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
632*bb618362Schristos 		       size_t len)
633*bb618362Schristos {
634*bb618362Schristos 	char *b64;
635*bb618362Schristos 
636*bb618362Schristos 	b64 = base64_url_encode(val, len, NULL);
637*bb618362Schristos 	if (!b64)
638*bb618362Schristos 		return -1;
639*bb618362Schristos 	json_add_string(json, name, b64);
640*bb618362Schristos 	os_free(b64);
641*bb618362Schristos 	return 0;
642*bb618362Schristos }
643*bb618362Schristos 
644*bb618362Schristos 
645*bb618362Schristos int json_add_base64(struct wpabuf *json, const char *name, const void *val,
646*bb618362Schristos 		    size_t len)
647*bb618362Schristos {
648*bb618362Schristos 	char *b64;
649*bb618362Schristos 
650*bb618362Schristos 	b64 = base64_encode_no_lf(val, len, NULL);
651*bb618362Schristos 	if (!b64)
652*bb618362Schristos 		return -1;
653*bb618362Schristos 	json_add_string(json, name, b64);
654*bb618362Schristos 	os_free(b64);
655*bb618362Schristos 	return 0;
656*bb618362Schristos }
657*bb618362Schristos 
658*bb618362Schristos 
659*bb618362Schristos void json_start_object(struct wpabuf *json, const char *name)
660*bb618362Schristos {
661*bb618362Schristos 	if (name)
662*bb618362Schristos 		wpabuf_printf(json, "\"%s\":", name);
663*bb618362Schristos 	wpabuf_put_u8(json, '{');
664*bb618362Schristos }
665*bb618362Schristos 
666*bb618362Schristos 
667*bb618362Schristos void json_end_object(struct wpabuf *json)
668*bb618362Schristos {
669*bb618362Schristos 	wpabuf_put_u8(json, '}');
670*bb618362Schristos }
671*bb618362Schristos 
672*bb618362Schristos 
673*bb618362Schristos void json_start_array(struct wpabuf *json, const char *name)
674*bb618362Schristos {
675*bb618362Schristos 	if (name)
676*bb618362Schristos 		wpabuf_printf(json, "\"%s\":", name);
677*bb618362Schristos 	wpabuf_put_u8(json, '[');
678*bb618362Schristos }
679*bb618362Schristos 
680*bb618362Schristos 
681*bb618362Schristos void json_end_array(struct wpabuf *json)
682*bb618362Schristos {
683*bb618362Schristos 	wpabuf_put_u8(json, ']');
684*bb618362Schristos }
685*bb618362Schristos 
686*bb618362Schristos 
687*bb618362Schristos void json_value_sep(struct wpabuf *json)
688*bb618362Schristos {
689*bb618362Schristos 	wpabuf_put_u8(json, ',');
690*bb618362Schristos }
691