2 * JavaScript Object Notation (JSON) parser (RFC7159)
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
15 #define JSON_MAX_DEPTH 10
16 #define JSON_MAX_TOKENS 500
19 void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
21 char *end = txt + maxlen;
24 for (i = 0; i < len; i++) {
50 if (data[i] >= 32 && data[i] <= 126) {
53 txt += os_snprintf(txt, end - txt, "\\u%04x",
64 static char * json_parse_string(const char **json_pos, const char *end)
66 const char *pos = *json_pos;
67 char *str, *spos, *s_end;
68 size_t max_len, buf_len;
71 pos++; /* skip starting quote */
73 max_len = end - pos + 1;
74 buf_len = max_len > 10 ? 10 : max_len;
75 str = os_malloc(buf_len);
79 s_end = str + buf_len;
81 for (; pos < end; pos++) {
82 if (buf_len < max_len && s_end - spos < 3) {
88 if (buf_len > max_len)
90 tmp = os_realloc(str, buf_len);
95 s_end = str + buf_len;
99 case '\"': /* end string */
101 /* caller will move to the next position */
107 wpa_printf(MSG_DEBUG,
108 "JSON: Truncated \\ escape");
128 hexstr2bin(pos + 1, bin, 2) < 0 ||
130 wpa_printf(MSG_DEBUG,
131 "JSON: Invalid \\u escape");
134 if (bin[0] == 0x00) {
143 wpa_printf(MSG_DEBUG,
144 "JSON: Unknown escape '%c'", *pos);
160 static int json_parse_number(const char **json_pos, const char *end,
163 const char *pos = *json_pos;
167 for (; pos < end; pos++) {
168 if (*pos != '-' && (*pos < '0' || *pos > '9')) {
177 len = pos - *json_pos + 1;
178 str = os_malloc(len + 1);
181 os_memcpy(str, *json_pos, len);
184 *ret_val = atoi(str);
191 static int json_check_tree_state(struct json_token *token)
195 if (json_check_tree_state(token->child) < 0 ||
196 json_check_tree_state(token->sibling) < 0)
198 if (token->state != JSON_COMPLETED) {
199 wpa_printf(MSG_DEBUG,
200 "JSON: Unexpected token state %d (name=%s type=%d)",
201 token->state, token->name ? token->name : "N/A",
209 static struct json_token * json_alloc_token(unsigned int *tokens)
212 if (*tokens > JSON_MAX_TOKENS) {
213 wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded");
216 return os_zalloc(sizeof(struct json_token));
220 struct json_token * json_parse(const char *data, size_t data_len)
222 struct json_token *root = NULL, *curr_token = NULL, *token = NULL;
223 const char *pos, *end;
226 unsigned int depth = 0;
227 unsigned int tokens = 0;
230 end = data + data_len;
232 for (; pos < end; pos++) {
234 case '[': /* start array */
235 case '{': /* start object */
237 token = json_alloc_token(&tokens);
242 } else if (curr_token->state == JSON_WAITING_VALUE) {
244 } else if (curr_token->parent &&
245 curr_token->parent->type == JSON_ARRAY &&
246 curr_token->parent->state == JSON_STARTED &&
247 curr_token->state == JSON_EMPTY) {
250 wpa_printf(MSG_DEBUG,
251 "JSON: Invalid state for start array/object");
255 if (depth > JSON_MAX_DEPTH) {
256 wpa_printf(MSG_DEBUG,
257 "JSON: Max depth exceeded");
260 token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT;
261 token->state = JSON_STARTED;
262 token->child = json_alloc_token(&tokens);
265 curr_token = token->child;
266 curr_token->parent = token;
267 curr_token->state = JSON_EMPTY;
269 case ']': /* end array */
270 case '}': /* end object */
271 if (!curr_token || !curr_token->parent ||
272 curr_token->parent->state != JSON_STARTED) {
273 wpa_printf(MSG_DEBUG,
274 "JSON: Invalid state for end array/object");
278 curr_token = curr_token->parent;
280 curr_token->type != JSON_ARRAY) ||
282 curr_token->type != JSON_OBJECT)) {
283 wpa_printf(MSG_DEBUG,
284 "JSON: Array/Object mismatch");
287 if (curr_token->child->state == JSON_EMPTY &&
288 !curr_token->child->child &&
289 !curr_token->child->sibling) {
290 /* Remove pending child token since the
291 * array/object was empty. */
292 json_free(curr_token->child);
293 curr_token->child = NULL;
295 curr_token->state = JSON_COMPLETED;
297 case '\"': /* string */
298 str = json_parse_string(&pos, end);
302 token = json_alloc_token(&tokens);
305 token->type = JSON_STRING;
307 token->state = JSON_COMPLETED;
308 } else if (curr_token->parent &&
309 curr_token->parent->type == JSON_ARRAY &&
310 curr_token->parent->state == JSON_STARTED &&
311 curr_token->state == JSON_EMPTY) {
312 curr_token->string = str;
313 curr_token->state = JSON_COMPLETED;
314 curr_token->type = JSON_STRING;
315 wpa_printf(MSG_MSGDUMP,
316 "JSON: String value: '%s'",
318 } else if (curr_token->state == JSON_EMPTY) {
319 curr_token->type = JSON_VALUE;
320 curr_token->name = str;
321 curr_token->state = JSON_STARTED;
322 } else if (curr_token->state == JSON_WAITING_VALUE) {
323 curr_token->string = str;
324 curr_token->state = JSON_COMPLETED;
325 curr_token->type = JSON_STRING;
326 wpa_printf(MSG_MSGDUMP,
327 "JSON: String value: '%s' = '%s'",
331 wpa_printf(MSG_DEBUG,
332 "JSON: Invalid state for a string");
341 /* ignore whitespace */
343 case ':': /* name/value separator */
344 if (!curr_token || curr_token->state != JSON_STARTED)
346 curr_token->state = JSON_WAITING_VALUE;
348 case ',': /* member separator */
351 curr_token->sibling = json_alloc_token(&tokens);
352 if (!curr_token->sibling)
354 curr_token->sibling->parent = curr_token->parent;
355 curr_token = curr_token->sibling;
356 curr_token->state = JSON_EMPTY;
359 case 'f': /* false */
361 if (!((end - pos >= 4 &&
362 os_strncmp(pos, "true", 4) == 0) ||
364 os_strncmp(pos, "false", 5) == 0) ||
366 os_strncmp(pos, "null", 4) == 0))) {
367 wpa_printf(MSG_DEBUG,
368 "JSON: Invalid literal name");
372 token = json_alloc_token(&tokens);
376 } else if (curr_token->state == JSON_WAITING_VALUE) {
377 wpa_printf(MSG_MSGDUMP,
378 "JSON: Literal name: '%s' = %c",
379 curr_token->name, *pos);
380 } else if (curr_token->parent &&
381 curr_token->parent->type == JSON_ARRAY &&
382 curr_token->parent->state == JSON_STARTED &&
383 curr_token->state == JSON_EMPTY) {
384 wpa_printf(MSG_MSGDUMP,
385 "JSON: Literal name: %c", *pos);
387 wpa_printf(MSG_DEBUG,
388 "JSON: Invalid state for a literal name");
393 curr_token->type = JSON_BOOLEAN;
394 curr_token->number = 1;
398 curr_token->type = JSON_BOOLEAN;
399 curr_token->number = 0;
403 curr_token->type = JSON_NULL;
407 curr_token->state = JSON_COMPLETED;
421 if (json_parse_number(&pos, end, &num) < 0)
424 token = json_alloc_token(&tokens);
427 token->type = JSON_NUMBER;
429 token->state = JSON_COMPLETED;
430 } else if (curr_token->state == JSON_WAITING_VALUE) {
431 curr_token->number = num;
432 curr_token->state = JSON_COMPLETED;
433 curr_token->type = JSON_NUMBER;
434 wpa_printf(MSG_MSGDUMP,
435 "JSON: Number value: '%s' = '%d'",
438 } else if (curr_token->parent &&
439 curr_token->parent->type == JSON_ARRAY &&
440 curr_token->parent->state == JSON_STARTED &&
441 curr_token->state == JSON_EMPTY) {
442 curr_token->number = num;
443 curr_token->state = JSON_COMPLETED;
444 curr_token->type = JSON_NUMBER;
445 wpa_printf(MSG_MSGDUMP,
446 "JSON: Number value: %d",
449 wpa_printf(MSG_DEBUG,
450 "JSON: Invalid state for a number");
455 wpa_printf(MSG_DEBUG,
456 "JSON: Unexpected JSON character: %c", *pos);
466 if (json_check_tree_state(root) < 0) {
467 wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree");
473 wpa_printf(MSG_DEBUG, "JSON: Parsing failed");
479 void json_free(struct json_token *json)
483 json_free(json->child);
484 json_free(json->sibling);
486 os_free(json->string);
491 struct json_token * json_get_member(struct json_token *json, const char *name)
493 struct json_token *token, *ret = NULL;
495 if (!json || json->type != JSON_OBJECT)
497 /* Return last matching entry */
498 for (token = json->child; token; token = token->sibling) {
499 if (token->name && os_strcmp(token->name, name) == 0)
506 struct wpabuf * json_get_member_base64url(struct json_token *json,
509 struct json_token *token;
514 token = json_get_member(json, name);
515 if (!token || token->type != JSON_STRING)
517 buf = base64_url_decode((const unsigned char *) token->string,
518 os_strlen(token->string), &buflen);
521 ret = wpabuf_alloc_ext_data(buf, buflen);
529 static const char * json_type_str(enum json_type type)
551 static void json_print_token(struct json_token *token, int depth,
552 char *buf, size_t buflen)
559 len = os_strlen(buf);
560 ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]",
561 depth, json_type_str(token->type),
562 token->name ? token->name : "");
563 if (os_snprintf_error(buflen - len, ret)) {
567 json_print_token(token->child, depth + 1, buf, buflen);
568 json_print_token(token->sibling, depth, buf, buflen);
572 void json_print_tree(struct json_token *root, char *buf, size_t buflen)
575 json_print_token(root, 1, buf, buflen);