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