Coverage Report

Created: 2026-07-16 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hostap/src/utils/json.c
Line
Count
Source
1
/*
2
 * JavaScript Object Notation (JSON) parser (RFC7159)
3
 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4
 *
5
 * This software may be distributed under the terms of the BSD license.
6
 * See README for more details.
7
 */
8
9
#include "includes.h"
10
11
#include "common.h"
12
#include "base64.h"
13
#include "json.h"
14
15
3.32k
#define JSON_MAX_DEPTH 10
16
41.6k
#define JSON_MAX_TOKENS 500
17
18
19
void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
20
0
{
21
0
  char *end = txt + maxlen;
22
0
  size_t i;
23
24
0
  for (i = 0; i < len; i++) {
25
0
    if (txt + 4 >= end)
26
0
      break;
27
28
0
    switch (data[i]) {
29
0
    case '\"':
30
0
      *txt++ = '\\';
31
0
      *txt++ = '\"';
32
0
      break;
33
0
    case '\\':
34
0
      *txt++ = '\\';
35
0
      *txt++ = '\\';
36
0
      break;
37
0
    case '\n':
38
0
      *txt++ = '\\';
39
0
      *txt++ = 'n';
40
0
      break;
41
0
    case '\r':
42
0
      *txt++ = '\\';
43
0
      *txt++ = 'r';
44
0
      break;
45
0
    case '\t':
46
0
      *txt++ = '\\';
47
0
      *txt++ = 't';
48
0
      break;
49
0
    default:
50
0
      if (data[i] >= 32 && data[i] <= 126) {
51
0
        *txt++ = data[i];
52
0
      } else {
53
0
        txt += os_snprintf(txt, end - txt, "\\u%04x",
54
0
               (unsigned char) data[i]);
55
0
      }
56
0
      break;
57
0
    }
58
0
  }
59
60
0
  *txt = '\0';
61
0
}
62
63
64
static char * json_parse_string(const char **json_pos, const char *end)
65
8.15k
{
66
8.15k
  const char *pos = *json_pos;
67
8.15k
  char *str, *spos, *s_end;
68
8.15k
  size_t max_len, buf_len;
69
8.15k
  u8 bin[2];
70
71
8.15k
  pos++; /* skip starting quote */
72
73
8.15k
  max_len = end - pos + 1;
74
8.15k
  buf_len = max_len > 10 ? 10 : max_len;
75
8.15k
  str = os_malloc(buf_len);
76
8.15k
  if (!str)
77
0
    return NULL;
78
8.15k
  spos = str;
79
8.15k
  s_end = str + buf_len;
80
81
17.3M
  for (; pos < end; pos++) {
82
17.3M
    if (buf_len < max_len && s_end - spos < 3) {
83
24.7k
      char *tmp;
84
24.7k
      int idx;
85
86
24.7k
      idx = spos - str;
87
24.7k
      buf_len *= 2;
88
24.7k
      if (buf_len > max_len)
89
145
        buf_len = max_len;
90
24.7k
      tmp = os_realloc(str, buf_len);
91
24.7k
      if (!tmp)
92
0
        goto fail;
93
24.7k
      str = tmp;
94
24.7k
      spos = str + idx;
95
24.7k
      s_end = str + buf_len;
96
24.7k
    }
97
98
17.3M
    switch (*pos) {
99
7.87k
    case '\"': /* end string */
100
7.87k
      *spos = '\0';
101
      /* caller will move to the next position */
102
7.87k
      *json_pos = pos;
103
7.87k
      return str;
104
58.0k
    case '\\':
105
58.0k
      pos++;
106
58.0k
      if (pos >= end) {
107
4
        wpa_printf(MSG_DEBUG,
108
4
             "JSON: Truncated \\ escape");
109
4
        goto fail;
110
4
      }
111
58.0k
      switch (*pos) {
112
6.96k
      case '"':
113
11.1k
      case '\\':
114
11.9k
      case '/':
115
11.9k
        *spos++ = *pos;
116
11.9k
        break;
117
4.00k
      case 'n':
118
4.00k
        *spos++ = '\n';
119
4.00k
        break;
120
6.09k
      case 'r':
121
6.09k
        *spos++ = '\r';
122
6.09k
        break;
123
2.95k
      case 't':
124
2.95k
        *spos++ = '\t';
125
2.95k
        break;
126
33.0k
      case 'u':
127
33.0k
        if (end - pos < 5 ||
128
33.0k
            hexstr2bin(pos + 1, bin, 2) < 0 ||
129
32.9k
            bin[1] == 0x00) {
130
93
          wpa_printf(MSG_DEBUG,
131
93
               "JSON: Invalid \\u escape");
132
93
          goto fail;
133
93
        }
134
32.9k
        if (bin[0] == 0x00) {
135
4.48k
          *spos++ = bin[1];
136
28.4k
        } else {
137
28.4k
          *spos++ = bin[0];
138
28.4k
          *spos++ = bin[1];
139
28.4k
        }
140
32.9k
        pos += 4;
141
32.9k
        break;
142
9
      default:
143
9
        wpa_printf(MSG_DEBUG,
144
9
             "JSON: Unknown escape '%c'", *pos);
145
9
        goto fail;
146
58.0k
      }
147
57.9k
      break;
148
17.3M
    default:
149
17.3M
      *spos++ = *pos;
150
17.3M
      break;
151
17.3M
    }
152
17.3M
  }
153
154
278
fail:
155
278
  os_free(str);
156
278
  return NULL;
157
8.15k
}
158
159
160
static size_t json_get_number_len(const char *json_pos, const char *end,
161
          bool *is_double)
162
17.7k
{
163
17.7k
  const char *pos = json_pos;
164
17.7k
  size_t len;
165
166
2.40M
  for (; pos < end; pos++) {
167
2.40M
    switch (*pos) {
168
2.61k
    case '.':
169
2.90k
    case 'e':
170
3.28k
    case 'E':
171
3.28k
      *is_double = true;
172
5.00k
    case '-':
173
840k
    case '0':
174
846k
    case '1':
175
851k
    case '2':
176
861k
    case '3':
177
866k
    case '4':
178
872k
    case '5':
179
923k
    case '6':
180
930k
    case '7':
181
934k
    case '8':
182
2.38M
    case '9':
183
2.38M
      continue;
184
17.4k
    default:
185
17.4k
      pos--;
186
17.4k
      break;
187
2.40M
    }
188
17.4k
    break;
189
2.40M
  }
190
17.7k
  if (pos == end)
191
275
    pos--;
192
17.7k
  if (pos < json_pos)
193
0
    return 0;
194
17.7k
  len = pos - json_pos + 1;
195
196
17.7k
  return len;
197
17.7k
}
198
199
200
static int json_parse_double(const char **json_pos, size_t len, double *ret_val)
201
441
{
202
441
  char *str;
203
441
  char *endptr;
204
205
441
  str = os_malloc(len + 1);
206
441
  if (!str)
207
0
    return -1;
208
441
  os_memcpy(str, *json_pos, len);
209
441
  str[len] = '\0';
210
211
441
  *ret_val = strtod(str, &endptr);
212
441
  if (endptr == str) {
213
5
    os_free(str);
214
5
    return -1;
215
5
  }
216
436
  os_free(str);
217
436
  *json_pos += len - 1;
218
436
  return 0;
219
441
}
220
221
222
static int json_parse_number(const char **json_pos, size_t len, int *ret_val)
223
17.2k
{
224
17.2k
  char *str;
225
226
17.2k
  str = os_malloc(len + 1);
227
17.2k
  if (!str)
228
0
    return -1;
229
17.2k
  os_memcpy(str, *json_pos, len);
230
17.2k
  str[len] = '\0';
231
232
17.2k
  *ret_val = atoi(str);
233
17.2k
  os_free(str);
234
17.2k
  *json_pos += len - 1;
235
17.2k
  return 0;
236
17.2k
}
237
238
239
static int json_check_tree_state(struct json_token *token)
240
61.7k
{
241
61.7k
  if (!token)
242
30.9k
    return 0;
243
30.8k
  if (json_check_tree_state(token->child) < 0 ||
244
30.3k
      json_check_tree_state(token->sibling) < 0)
245
14.8k
    return -1;
246
15.9k
  if (token->state != JSON_COMPLETED) {
247
265
    wpa_printf(MSG_DEBUG,
248
265
         "JSON: Unexpected token state %d (name=%s type=%d)",
249
265
         token->state, token->name ? token->name : "N/A",
250
265
         token->type);
251
265
    return -1;
252
265
  }
253
15.7k
  return 0;
254
15.9k
}
255
256
257
static struct json_token * json_alloc_token(unsigned int *tokens)
258
41.6k
{
259
41.6k
  (*tokens)++;
260
41.6k
  if (*tokens > JSON_MAX_TOKENS) {
261
5
    wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded");
262
5
    return NULL;
263
5
  }
264
41.6k
  return os_zalloc(sizeof(struct json_token));
265
41.6k
}
266
267
268
struct json_token * json_parse(const char *data, size_t data_len)
269
1.13k
{
270
1.13k
  struct json_token *root = NULL, *curr_token = NULL, *token = NULL;
271
1.13k
  const char *pos, *end;
272
1.13k
  char *str;
273
1.13k
  int num;
274
1.13k
  double dnum;
275
1.13k
  bool is_double;
276
1.13k
  unsigned int depth = 0;
277
1.13k
  unsigned int tokens = 0;
278
1.13k
  size_t len;
279
280
1.13k
  pos = data;
281
1.13k
  end = data + data_len;
282
283
80.0k
  for (; pos < end; pos++) {
284
79.4k
    switch (*pos) {
285
2.18k
    case '[': /* start array */
286
3.34k
    case '{': /* start object */
287
3.34k
      if (!curr_token) {
288
422
        token = json_alloc_token(&tokens);
289
422
        if (!token)
290
0
          goto fail;
291
422
        if (!root)
292
422
          root = token;
293
2.91k
      } else if (curr_token->state == JSON_WAITING_VALUE) {
294
446
        token = curr_token;
295
2.47k
      } else if (curr_token->parent &&
296
2.46k
           curr_token->parent->type == JSON_ARRAY &&
297
2.45k
           curr_token->parent->state == JSON_STARTED &&
298
2.45k
           curr_token->state == JSON_EMPTY) {
299
2.45k
        token = curr_token;
300
2.45k
      } else {
301
17
        wpa_printf(MSG_DEBUG,
302
17
             "JSON: Invalid state for start array/object");
303
17
        goto fail;
304
17
      }
305
3.32k
      depth++;
306
3.32k
      if (depth > JSON_MAX_DEPTH) {
307
10
        wpa_printf(MSG_DEBUG,
308
10
             "JSON: Max depth exceeded");
309
10
        goto fail;
310
10
      }
311
3.31k
      token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT;
312
3.31k
      token->state = JSON_STARTED;
313
3.31k
      token->child = json_alloc_token(&tokens);
314
3.31k
      if (!token->child)
315
1
        goto fail;
316
3.31k
      curr_token = token->child;
317
3.31k
      curr_token->parent = token;
318
3.31k
      curr_token->state = JSON_EMPTY;
319
3.31k
      break;
320
1.57k
    case ']': /* end array */
321
2.57k
    case '}': /* end object */
322
2.57k
      if (!curr_token || !curr_token->parent ||
323
2.56k
          curr_token->parent->state != JSON_STARTED ||
324
2.56k
          depth == 0) {
325
12
        wpa_printf(MSG_DEBUG,
326
12
             "JSON: Invalid state for end array/object");
327
12
        goto fail;
328
12
      }
329
2.56k
      depth--;
330
2.56k
      curr_token = curr_token->parent;
331
2.56k
      if ((*pos == ']' &&
332
1.56k
           curr_token->type != JSON_ARRAY) ||
333
2.56k
          (*pos == '}' &&
334
1.00k
           curr_token->type != JSON_OBJECT)) {
335
10
        wpa_printf(MSG_DEBUG,
336
10
             "JSON: Array/Object mismatch");
337
10
        goto fail;
338
10
      }
339
2.55k
      if (curr_token->child->state == JSON_EMPTY &&
340
1.12k
          !curr_token->child->child &&
341
1.12k
          !curr_token->child->sibling) {
342
        /* Remove pending child token since the
343
         * array/object was empty. */
344
885
        json_free(curr_token->child);
345
885
        curr_token->child = NULL;
346
885
      }
347
2.55k
      curr_token->state = JSON_COMPLETED;
348
2.55k
      break;
349
8.15k
    case '\"': /* string */
350
8.15k
      str = json_parse_string(&pos, end);
351
8.15k
      if (!str)
352
278
        goto fail;
353
7.87k
      if (!curr_token) {
354
60
        token = json_alloc_token(&tokens);
355
60
        if (!token) {
356
0
          os_free(str);
357
0
          goto fail;
358
0
        }
359
60
        token->type = JSON_STRING;
360
60
        token->string = str;
361
60
        token->state = JSON_COMPLETED;
362
7.81k
      } else if (curr_token->parent &&
363
2.36k
           curr_token->parent->type == JSON_ARRAY &&
364
196
           curr_token->parent->state == JSON_STARTED &&
365
196
           curr_token->state == JSON_EMPTY) {
366
195
        curr_token->string = str;
367
195
        curr_token->state = JSON_COMPLETED;
368
195
        curr_token->type = JSON_STRING;
369
195
        wpa_printf(MSG_MSGDUMP,
370
195
             "JSON: String value: '%s'",
371
195
             curr_token->string);
372
7.61k
      } else if (curr_token->state == JSON_EMPTY) {
373
7.03k
        curr_token->type = JSON_VALUE;
374
7.03k
        curr_token->name = str;
375
7.03k
        curr_token->state = JSON_STARTED;
376
7.03k
      } else if (curr_token->state == JSON_WAITING_VALUE) {
377
542
        curr_token->string = str;
378
542
        curr_token->state = JSON_COMPLETED;
379
542
        curr_token->type = JSON_STRING;
380
542
        wpa_printf(MSG_MSGDUMP,
381
542
             "JSON: String value: '%s' = '%s'",
382
542
             curr_token->name,
383
542
             curr_token->string);
384
542
      } else {
385
41
        wpa_printf(MSG_DEBUG,
386
41
             "JSON: Invalid state for a string");
387
41
        os_free(str);
388
41
        goto fail;
389
41
      }
390
7.83k
      break;
391
7.83k
    case ' ':
392
459
    case '\t':
393
864
    case '\r':
394
1.19k
    case '\n':
395
      /* ignore whitespace */
396
1.19k
      break;
397
6.31k
    case ':': /* name/value separator */
398
6.31k
      if (!curr_token || curr_token->state != JSON_STARTED)
399
9
        goto fail;
400
6.30k
      curr_token->state = JSON_WAITING_VALUE;
401
6.30k
      break;
402
37.5k
    case ',': /* member separator */
403
37.5k
      if (!curr_token)
404
1
        goto fail;
405
37.5k
      curr_token->sibling = json_alloc_token(&tokens);
406
37.5k
      if (!curr_token->sibling)
407
4
        goto fail;
408
37.5k
      curr_token->sibling->parent = curr_token->parent;
409
37.5k
      curr_token = curr_token->sibling;
410
37.5k
      curr_token->state = JSON_EMPTY;
411
37.5k
      break;
412
859
    case 't': /* true */
413
1.51k
    case 'f': /* false */
414
2.58k
    case 'n': /* null */
415
2.58k
      if (!((end - pos >= 4 &&
416
2.55k
             os_strncmp(pos, "true", 4) == 0) ||
417
1.76k
            (end - pos >= 5 &&
418
1.66k
             os_strncmp(pos, "false", 5) == 0) ||
419
1.16k
            (end - pos >= 4 &&
420
1.13k
             os_strncmp(pos, "null", 4) == 0))) {
421
137
        wpa_printf(MSG_DEBUG,
422
137
             "JSON: Invalid literal name");
423
137
        goto fail;
424
137
      }
425
2.44k
      if (!curr_token) {
426
40
        token = json_alloc_token(&tokens);
427
40
        if (!token)
428
0
          goto fail;
429
40
        curr_token = token;
430
2.40k
      } else if (curr_token->state == JSON_WAITING_VALUE) {
431
497
        wpa_printf(MSG_MSGDUMP,
432
497
             "JSON: Literal name: '%s' = %c",
433
497
             curr_token->name, *pos);
434
1.91k
      } else if (curr_token->parent &&
435
1.90k
           curr_token->parent->type == JSON_ARRAY &&
436
1.90k
           curr_token->parent->state == JSON_STARTED &&
437
1.90k
           curr_token->state == JSON_EMPTY) {
438
1.88k
        wpa_printf(MSG_MSGDUMP,
439
1.88k
             "JSON: Literal name: %c", *pos);
440
1.88k
      } else {
441
29
        wpa_printf(MSG_DEBUG,
442
29
             "JSON: Invalid state for a literal name");
443
29
        goto fail;
444
29
      }
445
2.41k
      switch (*pos) {
446
810
      case 't':
447
810
        curr_token->type = JSON_BOOLEAN;
448
810
        curr_token->number = 1;
449
810
        pos += 3;
450
810
        break;
451
592
      case 'f':
452
592
        curr_token->type = JSON_BOOLEAN;
453
592
        curr_token->number = 0;
454
592
        pos += 4;
455
592
        break;
456
1.01k
      case 'n':
457
1.01k
        curr_token->type = JSON_NULL;
458
1.01k
        pos += 3;
459
1.01k
        break;
460
2.41k
      }
461
2.41k
      curr_token->state = JSON_COMPLETED;
462
2.41k
      break;
463
324
    case '-':
464
2.77k
    case '0':
465
4.50k
    case '1':
466
6.48k
    case '2':
467
7.32k
    case '3':
468
8.66k
    case '4':
469
10.4k
    case '5':
470
11.2k
    case '6':
471
15.8k
    case '7':
472
17.1k
    case '8':
473
17.7k
    case '9':
474
      /* number */
475
17.7k
      is_double = false;
476
17.7k
      len = json_get_number_len(pos, end, &is_double);
477
17.7k
      if (!len)
478
0
        goto fail;
479
17.7k
      if (is_double) {
480
441
        if (json_parse_double(&pos, len, &dnum) < 0)
481
5
          goto fail;
482
17.2k
      } else {
483
17.2k
        if (json_parse_number(&pos, len, &num) < 0)
484
0
          goto fail;
485
17.2k
      }
486
487
17.7k
      if (!curr_token) {
488
210
        token = json_alloc_token(&tokens);
489
210
        if (!token)
490
0
          goto fail;
491
210
        if (is_double) {
492
36
          token->dnumber = dnum;
493
36
          token->type = JSON_DOUBLE;
494
174
        } else {
495
174
          token->number = num;
496
174
          token->type = JSON_NUMBER;
497
174
        }
498
210
        token->state = JSON_COMPLETED;
499
17.5k
      } else if (curr_token->state == JSON_WAITING_VALUE) {
500
4.64k
        curr_token->state = JSON_COMPLETED;
501
4.64k
        if (is_double) {
502
202
          curr_token->dnumber = dnum;
503
202
          curr_token->type = JSON_DOUBLE;
504
202
          wpa_printf(MSG_MSGDUMP,
505
202
               "JSON: Double value: '%s' = '%f'",
506
202
               curr_token->name,
507
202
               curr_token->dnumber);
508
4.43k
        } else {
509
4.43k
          curr_token->number = num;
510
4.43k
          curr_token->type = JSON_NUMBER;
511
4.43k
          wpa_printf(MSG_MSGDUMP,
512
4.43k
               "JSON: Number value: '%s' = '%d'",
513
4.43k
               curr_token->name,
514
4.43k
               curr_token->number);
515
4.43k
        }
516
12.8k
      } else if (curr_token->parent &&
517
12.8k
           curr_token->parent->type == JSON_ARRAY &&
518
12.8k
           curr_token->parent->state == JSON_STARTED &&
519
12.8k
           curr_token->state == JSON_EMPTY) {
520
12.8k
        curr_token->state = JSON_COMPLETED;
521
12.8k
        if (is_double) {
522
196
          curr_token->dnumber = dnum;
523
196
          curr_token->type = JSON_DOUBLE;
524
196
          wpa_printf(MSG_MSGDUMP,
525
196
               "JSON: Double value: %f",
526
196
               curr_token->dnumber);
527
12.6k
        } else {
528
12.6k
          curr_token->number = num;
529
12.6k
          curr_token->type = JSON_NUMBER;
530
12.6k
          wpa_printf(MSG_MSGDUMP,
531
12.6k
               "JSON: Number value: %d",
532
12.6k
               curr_token->number);
533
12.6k
        }
534
12.8k
      } else {
535
35
        wpa_printf(MSG_DEBUG,
536
35
             "JSON: Invalid state for a number");
537
35
        goto fail;
538
35
      }
539
17.6k
      break;
540
17.6k
    default:
541
18
      wpa_printf(MSG_DEBUG,
542
18
           "JSON: Unexpected JSON character: %c", *pos);
543
18
      goto fail;
544
79.4k
    }
545
546
78.8k
    if (!root)
547
1.27k
      root = token;
548
78.8k
    if (!curr_token)
549
1.23k
      curr_token = token;
550
78.8k
  }
551
552
526
  if (json_check_tree_state(root) < 0) {
553
265
    wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree");
554
265
    goto fail;
555
265
  }
556
557
261
  return root;
558
872
fail:
559
872
  wpa_printf(MSG_DEBUG, "JSON: Parsing failed");
560
872
  json_free(root);
561
872
  return NULL;
562
526
}
563
564
565
void json_free(struct json_token *json)
566
85.2k
{
567
85.2k
  if (!json)
568
43.5k
    return;
569
41.6k
  json_free(json->child);
570
41.6k
  json_free(json->sibling);
571
41.6k
  os_free(json->name);
572
41.6k
  os_free(json->string);
573
41.6k
  os_free(json);
574
41.6k
}
575
576
577
struct json_token * json_get_member(struct json_token *json, const char *name)
578
0
{
579
0
  struct json_token *token, *ret = NULL;
580
581
0
  if (!json || json->type != JSON_OBJECT)
582
0
    return NULL;
583
  /* Return last matching entry */
584
0
  for (token = json->child; token; token = token->sibling) {
585
0
    if (token->name && os_strcmp(token->name, name) == 0)
586
0
      ret = token;
587
0
  }
588
0
  return ret;
589
0
}
590
591
592
struct wpabuf * json_get_member_base64url(struct json_token *json,
593
            const char *name)
594
0
{
595
0
  struct json_token *token;
596
0
  unsigned char *buf;
597
0
  size_t buflen;
598
0
  struct wpabuf *ret;
599
600
0
  token = json_get_member(json, name);
601
0
  if (!token || token->type != JSON_STRING)
602
0
    return NULL;
603
0
  buf = base64_url_decode(token->string, os_strlen(token->string),
604
0
        &buflen);
605
0
  if (!buf)
606
0
    return NULL;
607
0
  ret = wpabuf_alloc_ext_data(buf, buflen);
608
0
  if (!ret)
609
0
    os_free(buf);
610
611
0
  return ret;
612
0
}
613
614
615
struct wpabuf * json_get_member_base64(struct json_token *json,
616
               const char *name)
617
0
{
618
0
  struct json_token *token;
619
0
  unsigned char *buf;
620
0
  size_t buflen;
621
0
  struct wpabuf *ret;
622
623
0
  token = json_get_member(json, name);
624
0
  if (!token || token->type != JSON_STRING)
625
0
    return NULL;
626
0
  buf = base64_decode(token->string, os_strlen(token->string), &buflen);
627
0
  if (!buf)
628
0
    return NULL;
629
0
  ret = wpabuf_alloc_ext_data(buf, buflen);
630
0
  if (!ret)
631
0
    os_free(buf);
632
633
0
  return ret;
634
0
}
635
636
637
static const char * json_type_str(enum json_type type)
638
11.7k
{
639
11.7k
  switch (type) {
640
0
  case JSON_VALUE:
641
0
    return "VALUE";
642
288
  case JSON_OBJECT:
643
288
    return "OBJECT";
644
746
  case JSON_ARRAY:
645
746
    return "ARRAY";
646
6
  case JSON_STRING:
647
6
    return "STRING";
648
10.3k
  case JSON_NUMBER:
649
10.3k
    return "NUMBER";
650
158
  case JSON_DOUBLE:
651
158
    return "DOUBLE";
652
54
  case JSON_BOOLEAN:
653
54
    return "BOOLEAN";
654
135
  case JSON_NULL:
655
135
    return "NULL";
656
11.7k
  }
657
0
  return "??";
658
11.7k
}
659
660
661
static void json_print_token(struct json_token *token, int depth,
662
           char *buf, size_t buflen)
663
23.2k
{
664
23.2k
  size_t len;
665
23.2k
  int ret;
666
667
23.2k
  if (!token)
668
11.5k
    return;
669
11.7k
  len = os_strlen(buf);
670
11.7k
  ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]",
671
11.7k
        depth, json_type_str(token->type),
672
11.7k
        token->name ? token->name : "");
673
11.7k
  if (os_snprintf_error(buflen - len, ret)) {
674
210
    buf[len] = '\0';
675
210
    return;
676
210
  }
677
11.4k
  json_print_token(token->child, depth + 1, buf, buflen);
678
11.4k
  json_print_token(token->sibling, depth, buf, buflen);
679
11.4k
}
680
681
682
void json_print_tree(struct json_token *root, char *buf, size_t buflen)
683
224
{
684
224
  buf[0] = '\0';
685
224
  json_print_token(root, 1, buf, buflen);
686
224
}
687
688
689
void json_add_int(struct wpabuf *json, const char *name, int val)
690
0
{
691
0
  wpabuf_printf(json, "\"%s\":%d", name, val);
692
0
}
693
694
695
void json_add_double(struct wpabuf *json, const char *name, double val)
696
0
{
697
0
  wpabuf_printf(json, "\"%s\":%f", name, val);
698
0
}
699
700
701
void json_add_string(struct wpabuf *json, const char *name, const char *val)
702
0
{
703
0
  wpabuf_printf(json, "\"%s\":\"%s\"", name, val);
704
0
}
705
706
707
int json_add_string_escape(struct wpabuf *json, const char *name,
708
         const void *val, size_t len)
709
0
{
710
0
  char *tmp;
711
0
  size_t tmp_len = 6 * len + 1;
712
713
0
  tmp = os_malloc(tmp_len);
714
0
  if (!tmp)
715
0
    return -1;
716
0
  json_escape_string(tmp, tmp_len, val, len);
717
0
  json_add_string(json, name, tmp);
718
0
  bin_clear_free(tmp, tmp_len);
719
0
  return 0;
720
0
}
721
722
723
int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
724
           size_t len)
725
0
{
726
0
  char *b64;
727
728
0
  b64 = base64_url_encode(val, len, NULL);
729
0
  if (!b64)
730
0
    return -1;
731
0
  json_add_string(json, name, b64);
732
0
  os_free(b64);
733
0
  return 0;
734
0
}
735
736
737
int json_add_base64(struct wpabuf *json, const char *name, const void *val,
738
        size_t len)
739
0
{
740
0
  char *b64;
741
742
0
  b64 = base64_encode_no_lf(val, len, NULL);
743
0
  if (!b64)
744
0
    return -1;
745
0
  json_add_string(json, name, b64);
746
0
  os_free(b64);
747
0
  return 0;
748
0
}
749
750
751
void json_start_object(struct wpabuf *json, const char *name)
752
0
{
753
0
  if (name)
754
0
    wpabuf_printf(json, "\"%s\":", name);
755
0
  wpabuf_put_u8(json, '{');
756
0
}
757
758
759
void json_end_object(struct wpabuf *json)
760
0
{
761
0
  wpabuf_put_u8(json, '}');
762
0
}
763
764
765
void json_start_array(struct wpabuf *json, const char *name)
766
0
{
767
0
  if (name)
768
0
    wpabuf_printf(json, "\"%s\":", name);
769
0
  wpabuf_put_u8(json, '[');
770
0
}
771
772
773
void json_end_array(struct wpabuf *json)
774
0
{
775
0
  wpabuf_put_u8(json, ']');
776
0
}
777
778
779
void json_value_sep(struct wpabuf *json)
780
0
{
781
0
  wpabuf_put_u8(json, ',');
782
0
}