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