blob: 3aded8cb2b72df5b99f39c1809f2e54457477534 [file] [log] [blame]
Leandro Pereirafb192c52017-02-16 15:51:31 -08001/*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <assert.h>
8#include <ctype.h>
9#include <errno.h>
10#include <limits.h>
Anas Nashif9ab2a562019-06-26 10:33:49 -040011#include <sys/printk.h>
Anas Nashifa2fd7d72019-06-26 10:33:55 -040012#include <sys/util.h>
Leandro Pereirafb192c52017-02-16 15:51:31 -080013#include <stdbool.h>
Leandro Pereirafb192c52017-02-16 15:51:31 -080014#include <stdlib.h>
15#include <string.h>
Leandro Pereira7a72ecd2017-09-05 16:32:27 -070016#include <zephyr/types.h>
Leandro Pereirafb192c52017-02-16 15:51:31 -080017
Anas Nashif0abdacf2019-06-25 15:50:42 -040018#include <data/json.h>
Leandro Pereirafb192c52017-02-16 15:51:31 -080019
20struct token {
21 enum json_tokens type;
22 char *start;
23 char *end;
24};
25
26struct lexer {
27 void *(*state)(struct lexer *lexer);
Leandro Pereira7763a1d2017-06-05 17:01:01 -070028 char *start;
29 char *pos;
30 char *end;
Leandro Pereirafb192c52017-02-16 15:51:31 -080031 struct token token;
32};
33
34struct json_obj {
35 struct lexer lexer;
36};
37
38struct json_obj_key_value {
39 const char *key;
40 size_t key_len;
41 struct token value;
42};
43
44static bool lexer_consume(struct lexer *lexer, struct token *token,
45 enum json_tokens empty_token)
46{
47 if (lexer->token.type == empty_token) {
48 return false;
49 }
50
51 *token = lexer->token;
52 lexer->token.type = empty_token;
53
54 return true;
55}
56
57static bool lexer_next(struct lexer *lexer, struct token *token)
58{
59 while (lexer->state) {
60 if (lexer_consume(lexer, token, JSON_TOK_NONE)) {
61 return true;
62 }
63
64 lexer->state = lexer->state(lexer);
65 }
66
67 return lexer_consume(lexer, token, JSON_TOK_EOF);
68}
69
70static void *lexer_json(struct lexer *lexer);
71
72static void emit(struct lexer *lexer, enum json_tokens token)
73{
74 lexer->token.type = token;
75 lexer->token.start = lexer->start;
76 lexer->token.end = lexer->pos;
77 lexer->start = lexer->pos;
78}
79
Kumar Gala9aebe8b2018-07-11 15:24:11 -050080static int next(struct lexer *lexer)
Leandro Pereirafb192c52017-02-16 15:51:31 -080081{
82 if (lexer->pos >= lexer->end) {
83 lexer->pos = lexer->end + 1;
84
85 return '\0';
86 }
87
88 return *lexer->pos++;
89}
90
91static void ignore(struct lexer *lexer)
92{
93 lexer->start = lexer->pos;
94}
95
96static void backup(struct lexer *lexer)
97{
98 lexer->pos--;
99}
100
Kumar Gala9aebe8b2018-07-11 15:24:11 -0500101static int peek(struct lexer *lexer)
Leandro Pereirafb192c52017-02-16 15:51:31 -0800102{
Kumar Gala9aebe8b2018-07-11 15:24:11 -0500103 int chr = next(lexer);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800104
105 backup(lexer);
106
107 return chr;
108}
109
110static void *lexer_string(struct lexer *lexer)
111{
112 ignore(lexer);
113
114 while (true) {
Kumar Gala9aebe8b2018-07-11 15:24:11 -0500115 int chr = next(lexer);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800116
117 if (chr == '\0') {
118 emit(lexer, JSON_TOK_ERROR);
119 return NULL;
120 }
121
122 if (chr == '\\') {
123 switch (next(lexer)) {
124 case '"':
125 case '\\':
126 case '/':
127 case 'b':
128 case 'f':
129 case 'n':
130 case 'r':
131 case 't':
132 continue;
133 case 'u':
134 if (!isxdigit(next(lexer))) {
135 goto error;
136 }
137
138 if (!isxdigit(next(lexer))) {
139 goto error;
140 }
141
142 if (!isxdigit(next(lexer))) {
143 goto error;
144 }
145
146 if (!isxdigit(next(lexer))) {
147 goto error;
148 }
149
150 break;
151 default:
152 goto error;
153 }
154 }
155
156 if (chr == '"') {
157 backup(lexer);
158 emit(lexer, JSON_TOK_STRING);
159
160 next(lexer);
161 ignore(lexer);
162
163 return lexer_json;
164 }
165 }
166
167error:
168 emit(lexer, JSON_TOK_ERROR);
169 return NULL;
170}
171
Leandro Pereira95ec49c2017-03-16 10:11:00 -0700172static int accept_run(struct lexer *lexer, const char *run)
173{
174 for (; *run; run++) {
175 if (next(lexer) != *run) {
176 return -EINVAL;
177 }
178 }
179
180 return 0;
181}
182
Leandro Pereirafb192c52017-02-16 15:51:31 -0800183static void *lexer_boolean(struct lexer *lexer)
184{
185 backup(lexer);
186
187 switch (next(lexer)) {
188 case 't':
Leandro Pereira95ec49c2017-03-16 10:11:00 -0700189 if (!accept_run(lexer, "rue")) {
190 emit(lexer, JSON_TOK_TRUE);
191 return lexer_json;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800192 }
Leandro Pereira95ec49c2017-03-16 10:11:00 -0700193 break;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800194 case 'f':
Leandro Pereira95ec49c2017-03-16 10:11:00 -0700195 if (!accept_run(lexer, "alse")) {
196 emit(lexer, JSON_TOK_FALSE);
197 return lexer_json;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800198 }
Leandro Pereira95ec49c2017-03-16 10:11:00 -0700199 break;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800200 }
201
Leandro Pereirafb192c52017-02-16 15:51:31 -0800202 emit(lexer, JSON_TOK_ERROR);
203 return NULL;
204}
205
206static void *lexer_null(struct lexer *lexer)
207{
Leandro Pereira95ec49c2017-03-16 10:11:00 -0700208 if (accept_run(lexer, "ull") < 0) {
209 emit(lexer, JSON_TOK_ERROR);
210 return NULL;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800211 }
212
213 emit(lexer, JSON_TOK_NULL);
214 return lexer_json;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800215}
216
Leandro Pereirafb192c52017-02-16 15:51:31 -0800217static void *lexer_number(struct lexer *lexer)
218{
219 while (true) {
Kumar Gala9aebe8b2018-07-11 15:24:11 -0500220 int chr = next(lexer);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800221
222 if (isdigit(chr) || chr == '.') {
223 continue;
224 }
225
226 backup(lexer);
227 emit(lexer, JSON_TOK_NUMBER);
228
229 return lexer_json;
230 }
231}
232
233static void *lexer_json(struct lexer *lexer)
234{
235 while (true) {
Kumar Gala9aebe8b2018-07-11 15:24:11 -0500236 int chr = next(lexer);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800237
238 switch (chr) {
239 case '\0':
240 emit(lexer, JSON_TOK_EOF);
241 return NULL;
242 case '}':
243 case '{':
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700244 case '[':
245 case ']':
Leandro Pereirafb192c52017-02-16 15:51:31 -0800246 case ',':
247 case ':':
248 emit(lexer, (enum json_tokens)chr);
249 return lexer_json;
250 case '"':
251 return lexer_string;
252 case 'n':
253 return lexer_null;
254 case 't':
255 case 'f':
256 return lexer_boolean;
257 case '-':
258 if (isdigit(peek(lexer))) {
259 return lexer_number;
260 }
261
Flavio Ceolin0aaae4a2020-08-21 13:45:52 -0700262 __fallthrough;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800263 default:
264 if (isspace(chr)) {
Leandro Pereira4c7803b2017-03-23 15:15:11 -0700265 ignore(lexer);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800266 continue;
267 }
268
269 if (isdigit(chr)) {
270 return lexer_number;
271 }
272
273 emit(lexer, JSON_TOK_ERROR);
274 return NULL;
275 }
276 }
277}
278
279static void lexer_init(struct lexer *lexer, char *data, size_t len)
280{
281 lexer->state = lexer_json;
282 lexer->start = data;
283 lexer->pos = data;
284 lexer->end = data + len;
285 lexer->token.type = JSON_TOK_NONE;
286}
287
288static int obj_init(struct json_obj *json, char *data, size_t len)
289{
290 struct token token;
291
292 lexer_init(&json->lexer, data, len);
293
294 if (!lexer_next(&json->lexer, &token)) {
295 return -EINVAL;
296 }
297
298 if (token.type != JSON_TOK_OBJECT_START) {
299 return -EINVAL;
300 }
301
302 return 0;
303}
304
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700305static int element_token(enum json_tokens token)
306{
307 switch (token) {
308 case JSON_TOK_OBJECT_START:
309 case JSON_TOK_LIST_START:
310 case JSON_TOK_STRING:
311 case JSON_TOK_NUMBER:
312 case JSON_TOK_TRUE:
313 case JSON_TOK_FALSE:
314 return 0;
315 default:
316 return -EINVAL;
317 }
318}
319
320static int obj_next(struct json_obj *json,
321 struct json_obj_key_value *kv)
Leandro Pereirafb192c52017-02-16 15:51:31 -0800322{
323 struct token token;
324
325 if (!lexer_next(&json->lexer, &token)) {
326 return -EINVAL;
327 }
328
329 /* Match end of object or next key */
330 switch (token.type) {
331 case JSON_TOK_OBJECT_END:
332 kv->key = NULL;
333 kv->key_len = 0;
334 kv->value = token;
335
336 return 0;
337 case JSON_TOK_COMMA:
338 if (!lexer_next(&json->lexer, &token)) {
339 return -EINVAL;
340 }
341
342 if (token.type != JSON_TOK_STRING) {
343 return -EINVAL;
344 }
345
Flavio Ceolin0aaae4a2020-08-21 13:45:52 -0700346 __fallthrough;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800347 case JSON_TOK_STRING:
348 kv->key = token.start;
349 kv->key_len = (size_t)(token.end - token.start);
350 break;
351 default:
352 return -EINVAL;
353 }
354
355 /* Match : after key */
356 if (!lexer_next(&json->lexer, &token)) {
357 return -EINVAL;
358 }
359
360 if (token.type != JSON_TOK_COLON) {
361 return -EINVAL;
362 }
363
364 /* Match value */
365 if (!lexer_next(&json->lexer, &kv->value)) {
366 return -EINVAL;
367 }
368
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700369 return element_token(kv->value.type);
370}
371
372static int arr_next(struct json_obj *json, struct token *value)
373{
374 if (!lexer_next(&json->lexer, value)) {
Leandro Pereirafb192c52017-02-16 15:51:31 -0800375 return -EINVAL;
376 }
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700377
378 if (value->type == JSON_TOK_LIST_END) {
379 return 0;
380 }
381
382 if (value->type == JSON_TOK_COMMA) {
383 if (!lexer_next(&json->lexer, value)) {
384 return -EINVAL;
385 }
386 }
387
388 return element_token(value->type);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800389}
390
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500391static int decode_num(const struct token *token, int32_t *num)
Leandro Pereirafb192c52017-02-16 15:51:31 -0800392{
393 /* FIXME: strtod() is not available in newlib/minimal libc,
Leandro Pereira844ef672017-03-21 15:49:25 -0700394 * so using strtol() here.
Leandro Pereirafb192c52017-02-16 15:51:31 -0800395 */
396 char *endptr;
397 char prev_end;
398
399 prev_end = *token->end;
400 *token->end = '\0';
401
402 errno = 0;
403 *num = strtol(token->start, &endptr, 10);
404
405 *token->end = prev_end;
406
407 if (errno != 0) {
408 return -errno;
409 }
410
Leandro Pereira844ef672017-03-21 15:49:25 -0700411 if (endptr != token->end) {
Leandro Pereirafb192c52017-02-16 15:51:31 -0800412 return -EINVAL;
413 }
414
415 return 0;
416}
417
418static bool equivalent_types(enum json_tokens type1, enum json_tokens type2)
419{
420 if (type1 == JSON_TOK_TRUE || type1 == JSON_TOK_FALSE) {
421 return type2 == JSON_TOK_TRUE || type2 == JSON_TOK_FALSE;
422 }
423
424 return type1 == type2;
425}
426
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700427static int obj_parse(struct json_obj *obj,
428 const struct json_obj_descr *descr, size_t descr_len,
429 void *val);
430static int arr_parse(struct json_obj *obj,
431 const struct json_obj_descr *elem_descr,
432 size_t max_elements, void *field, void *val);
433
434static int decode_value(struct json_obj *obj,
435 const struct json_obj_descr *descr,
436 struct token *value, void *field, void *val)
Leandro Pereirafb192c52017-02-16 15:51:31 -0800437{
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700438
439 if (!equivalent_types(value->type, descr->type)) {
440 return -EINVAL;
441 }
442
443 switch (descr->type) {
444 case JSON_TOK_OBJECT_START:
Leandro Pereira33842622017-09-05 16:30:17 -0700445 return obj_parse(obj, descr->object.sub_descr,
446 descr->object.sub_descr_len,
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700447 field);
448 case JSON_TOK_LIST_START:
Leandro Pereira33842622017-09-05 16:30:17 -0700449 return arr_parse(obj, descr->array.element_descr,
450 descr->array.n_elements, field, val);
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700451 case JSON_TOK_FALSE:
452 case JSON_TOK_TRUE: {
Leandro Pereira262365c2017-03-23 16:32:03 -0700453 bool *v = field;
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700454
Leandro Pereira262365c2017-03-23 16:32:03 -0700455 *v = value->type == JSON_TOK_TRUE;
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700456
457 return 0;
458 }
459 case JSON_TOK_NUMBER: {
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500460 int32_t *num = field;
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700461
462 return decode_num(value, num);
463 }
464 case JSON_TOK_STRING: {
465 char **str = field;
466
467 *value->end = '\0';
468 *str = value->start;
469
470 return 0;
471 }
472 default:
473 return -EINVAL;
474 }
475}
476
477static ptrdiff_t get_elem_size(const struct json_obj_descr *descr)
478{
479 switch (descr->type) {
480 case JSON_TOK_NUMBER:
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500481 return sizeof(int32_t);
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700482 case JSON_TOK_STRING:
483 return sizeof(char *);
484 case JSON_TOK_TRUE:
485 case JSON_TOK_FALSE:
486 return sizeof(bool);
487 case JSON_TOK_LIST_START:
Leandro Pereira33842622017-09-05 16:30:17 -0700488 return descr->array.n_elements * get_elem_size(descr->array.element_descr);
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700489 case JSON_TOK_OBJECT_START: {
490 ptrdiff_t total = 0;
491 size_t i;
492
Leandro Pereira7a72ecd2017-09-05 16:32:27 -0700493 for (i = 0; i < descr->object.sub_descr_len; i++) {
494 ptrdiff_t s = get_elem_size(&descr->object.sub_descr[i]);
495
Nicolas Pitre4323d382019-05-17 17:17:33 -0400496 total += ROUND_UP(s, 1 << descr->align_shift);
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700497 }
498
499 return total;
500 }
501 default:
502 return -EINVAL;
503 }
504}
505
506static int arr_parse(struct json_obj *obj,
507 const struct json_obj_descr *elem_descr,
508 size_t max_elements, void *field, void *val)
509{
510 ptrdiff_t elem_size = get_elem_size(elem_descr);
511 void *last_elem = (char *)field + elem_size * max_elements;
512 size_t *elements = (size_t *)((char *)val + elem_descr->offset);
513 struct token value;
514
515 assert(elem_size > 0);
516
517 *elements = 0;
518
519 while (!arr_next(obj, &value)) {
520 if (value.type == JSON_TOK_LIST_END) {
521 return 0;
522 }
523
Marti Bolivarb4c8d832017-06-07 14:07:45 -0400524 if (field == last_elem) {
525 return -ENOSPC;
526 }
527
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700528 if (decode_value(obj, elem_descr, &value, field, val) < 0) {
529 return -EINVAL;
530 }
531
532 (*elements)++;
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700533 field = (char *)field + elem_size;
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700534 }
535
536 return -EINVAL;
537}
538
539static int obj_parse(struct json_obj *obj, const struct json_obj_descr *descr,
540 size_t descr_len, void *val)
541{
Leandro Pereirafb192c52017-02-16 15:51:31 -0800542 struct json_obj_key_value kv;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500543 int32_t decoded_fields = 0;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800544 size_t i;
545 int ret;
546
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700547 while (!obj_next(obj, &kv)) {
Leandro Pereirafb192c52017-02-16 15:51:31 -0800548 if (kv.value.type == JSON_TOK_OBJECT_END) {
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700549 return decoded_fields;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800550 }
551
552 for (i = 0; i < descr_len; i++) {
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700553 void *decode_field = (char *)val + descr[i].offset;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800554
555 /* Field has been decoded already, skip */
556 if (decoded_fields & (1 << i)) {
557 continue;
558 }
559
560 /* Check if it's the i-th field */
561 if (kv.key_len != descr[i].field_name_len) {
562 continue;
563 }
564
565 if (memcmp(kv.key, descr[i].field_name,
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700566 descr[i].field_name_len)) {
Leandro Pereirafb192c52017-02-16 15:51:31 -0800567 continue;
568 }
569
Leandro Pereirafb192c52017-02-16 15:51:31 -0800570 /* Store the decoded value */
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700571 ret = decode_value(obj, &descr[i], &kv.value,
572 decode_field, val);
573 if (ret < 0) {
574 return ret;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800575 }
576
577 decoded_fields |= 1<<i;
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700578 break;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800579 }
580 }
581
582 return -EINVAL;
583}
584
Leandro Pereira67ac6f62017-03-21 13:51:15 -0700585int json_obj_parse(char *payload, size_t len,
586 const struct json_obj_descr *descr, size_t descr_len,
587 void *val)
588{
589 struct json_obj obj;
590 int ret;
591
592 assert(descr_len < (sizeof(ret) * CHAR_BIT - 1));
593
594 ret = obj_init(&obj, payload, len);
595 if (ret < 0) {
596 return ret;
597 }
598
599 return obj_parse(&obj, descr, descr_len, val);
600}
601
Leandro Pereira7763a1d2017-06-05 17:01:01 -0700602static char escape_as(char chr)
Leandro Pereira122cdb32017-03-21 15:31:59 -0700603{
604 switch (chr) {
605 case '"':
606 return '"';
607 case '\\':
608 return '\\';
609 case '\b':
610 return 'b';
611 case '\f':
612 return 'f';
613 case '\n':
614 return 'n';
615 case '\r':
616 return 'r';
617 case '\t':
618 return 't';
619 }
620
621 return 0;
622}
Leandro Pereirafb192c52017-02-16 15:51:31 -0800623
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700624static int json_escape_internal(const char *str,
625 json_append_bytes_t append_bytes,
626 void *data)
Leandro Pereirafb192c52017-02-16 15:51:31 -0800627{
Leandro Pereira122cdb32017-03-21 15:31:59 -0700628 const char *cur;
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700629 int ret = 0;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800630
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700631 for (cur = str; ret == 0 && *cur; cur++) {
Leandro Pereira7763a1d2017-06-05 17:01:01 -0700632 char escaped = escape_as(*cur);
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700633
Leandro Pereira122cdb32017-03-21 15:31:59 -0700634 if (escaped) {
Leandro Pereira7763a1d2017-06-05 17:01:01 -0700635 char bytes[2] = { '\\', escaped };
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700636
637 ret = append_bytes(bytes, 2, data);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800638 } else {
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700639 ret = append_bytes(cur, 1, data);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800640 }
641 }
642
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700643 return ret;
644}
645
Leandro Pereirafb192c52017-02-16 15:51:31 -0800646size_t json_calc_escaped_len(const char *str, size_t len)
647{
648 size_t escaped_len = len;
649 size_t pos;
650
651 for (pos = 0; pos < len; pos++) {
Leandro Pereira122cdb32017-03-21 15:31:59 -0700652 if (escape_as(str[pos])) {
Leandro Pereirafb192c52017-02-16 15:51:31 -0800653 escaped_len++;
654 }
655 }
656
657 return escaped_len;
658}
659
660ssize_t json_escape(char *str, size_t *len, size_t buf_size)
661{
Marti Bolivar3c0eac32017-05-03 15:57:18 -0400662 char *next; /* Points after next character to escape. */
663 char *dest; /* Points after next place to write escaped character. */
664 size_t escaped_len = json_calc_escaped_len(str, *len);
Leandro Pereirafb192c52017-02-16 15:51:31 -0800665
666 if (escaped_len == *len) {
Marti Bolivar3c0eac32017-05-03 15:57:18 -0400667 /*
668 * If no escape is necessary, there is nothing to do.
Leandro Pereirafb192c52017-02-16 15:51:31 -0800669 */
670 return 0;
671 }
672
673 if (escaped_len >= buf_size) {
674 return -ENOMEM;
675 }
676
Marti Bolivar3c0eac32017-05-03 15:57:18 -0400677 /*
678 * By walking backwards in the buffer from the end positions
679 * of both the original and escaped strings, we avoid using
680 * extra space. Characters in the original string are
681 * overwritten only after they have already been escaped.
682 */
683 str[escaped_len] = '\0';
684 for (next = &str[*len], dest = &str[escaped_len]; next != str;) {
685 char next_c = *(--next);
686 char escape = escape_as(next_c);
687
688 if (escape) {
689 *(--dest) = escape;
690 *(--dest) = '\\';
691 } else {
692 *(--dest) = next_c;
693 }
694 }
695 *len = escaped_len;
696
697 return 0;
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700698}
699
700static int encode(const struct json_obj_descr *descr, const void *val,
701 json_append_bytes_t append_bytes, void *data);
702
Marti Bolivar2620ae02017-06-07 11:50:15 -0400703static int arr_encode(const struct json_obj_descr *elem_descr,
704 const void *field, const void *val,
705 json_append_bytes_t append_bytes, void *data)
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700706{
Marti Bolivar2620ae02017-06-07 11:50:15 -0400707 ptrdiff_t elem_size = get_elem_size(elem_descr);
708 /*
709 * NOTE: Since an element descriptor's offset isn't meaningful
710 * (array elements occur at multiple offsets in `val'), we use
711 * its space in elem_descr to store the offset to the field
712 * containing the number of elements.
713 */
714 size_t n_elem = *(size_t *)((char *)val + elem_descr->offset);
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700715 size_t i;
716 int ret;
717
718 ret = append_bytes("[", 1, data);
719 if (ret < 0) {
720 return ret;
721 }
722
723 for (i = 0; i < n_elem; i++) {
Marti Bolivar2620ae02017-06-07 11:50:15 -0400724 /*
725 * Though "field" points at the next element in the
726 * array which we need to encode, the value in
727 * elem_descr->offset is actually the offset of the
728 * length field in the "parent" struct containing the
729 * array.
730 *
731 * To patch things up, we lie to encode() about where
732 * the field is by exactly the amount it will offset
733 * it. This is a size optimization for struct
734 * json_obj_descr: the alternative is to keep a
735 * separate field next to element_descr which is an
736 * offset to the length field in the parent struct,
737 * but that would add a size_t to every descriptor.
738 */
739 ret = encode(elem_descr, (char *)field - elem_descr->offset,
740 append_bytes, data);
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700741 if (ret < 0) {
742 return ret;
743 }
744
745 if (i < n_elem - 1) {
746 ret = append_bytes(",", 1, data);
747 if (ret < 0) {
748 return ret;
749 }
750 }
751
752 field = (char *)field + elem_size;
753 }
754
755 return append_bytes("]", 1, data);
756}
757
758static int str_encode(const char **str, json_append_bytes_t append_bytes,
759 void *data)
760{
761 int ret;
762
763 ret = append_bytes("\"", 1, data);
764 if (ret < 0) {
765 return ret;
766 }
767
768 ret = json_escape_internal(*str, append_bytes, data);
769 if (!ret) {
770 return append_bytes("\"", 1, data);
771 }
772
773 return ret;
774}
775
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500776static int num_encode(const int32_t *num, json_append_bytes_t append_bytes,
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700777 void *data)
778{
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500779 char buf[3 * sizeof(int32_t)];
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700780 int ret;
781
782 ret = snprintk(buf, sizeof(buf), "%d", *num);
783 if (ret < 0) {
784 return ret;
785 }
786 if (ret >= (int)sizeof(buf)) {
787 return -ENOMEM;
788 }
789
790 return append_bytes(buf, (size_t)ret, data);
791}
792
793static int bool_encode(const bool *value, json_append_bytes_t append_bytes,
794 void *data)
795{
796 if (*value) {
797 return append_bytes("true", 4, data);
798 }
799
800 return append_bytes("false", 5, data);
801}
802
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700803static int encode(const struct json_obj_descr *descr, const void *val,
804 json_append_bytes_t append_bytes, void *data)
805{
806 void *ptr = (char *)val + descr->offset;
807
808 switch (descr->type) {
809 case JSON_TOK_FALSE:
810 case JSON_TOK_TRUE:
811 return bool_encode(ptr, append_bytes, data);
812 case JSON_TOK_STRING:
813 return str_encode(ptr, append_bytes, data);
814 case JSON_TOK_LIST_START:
Leandro Pereira33842622017-09-05 16:30:17 -0700815 return arr_encode(descr->array.element_descr, ptr,
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700816 val, append_bytes, data);
817 case JSON_TOK_OBJECT_START:
Leandro Pereira33842622017-09-05 16:30:17 -0700818 return json_obj_encode(descr->object.sub_descr,
819 descr->object.sub_descr_len,
Leandro Pereirad66069d2017-09-05 16:24:47 -0700820 ptr, append_bytes, data);
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700821 case JSON_TOK_NUMBER:
822 return num_encode(ptr, append_bytes, data);
823 default:
824 return -EINVAL;
825 }
826}
827
Leandro Pereirad66069d2017-09-05 16:24:47 -0700828int json_obj_encode(const struct json_obj_descr *descr, size_t descr_len,
829 const void *val, json_append_bytes_t append_bytes,
830 void *data)
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700831{
832 size_t i;
833 int ret;
834
835 ret = append_bytes("{", 1, data);
836 if (ret < 0) {
837 return ret;
838 }
839
840 for (i = 0; i < descr_len; i++) {
841 ret = str_encode((const char **)&descr[i].field_name,
842 append_bytes, data);
843 if (ret < 0) {
844 return ret;
845 }
846
847 ret = append_bytes(":", 1, data);
848 if (ret < 0) {
849 return ret;
850 }
851
852 ret = encode(&descr[i], val, append_bytes, data);
853 if (ret < 0) {
854 return ret;
855 }
856
857 if (i < descr_len - 1) {
858 ret = append_bytes(",", 1, data);
859 if (ret < 0) {
860 return ret;
861 }
862 }
863 }
864
865 return append_bytes("}", 1, data);
866}
867
Markus Fuchs2f9b0d42020-06-05 12:46:02 +0200868int json_arr_encode(const struct json_obj_descr *descr, const void *val,
869 json_append_bytes_t append_bytes, void *data)
870{
871 void *ptr = (char *)val + descr->offset;
872
873 return arr_encode(descr->array.element_descr, ptr, val, append_bytes,
874 data);
875}
876
Marti Bolivar3c0eac32017-05-03 15:57:18 -0400877struct appender {
878 char *buffer;
879 size_t used;
880 size_t size;
881};
882
Leandro Pereira7763a1d2017-06-05 17:01:01 -0700883static int append_bytes_to_buf(const char *bytes, size_t len, void *data)
Marti Bolivar3c0eac32017-05-03 15:57:18 -0400884{
885 struct appender *appender = data;
886
Peter Bigota09f6ad2020-04-21 14:56:52 -0500887 if (len >= appender->size - appender->used) {
Marti Bolivar3c0eac32017-05-03 15:57:18 -0400888 return -ENOMEM;
889 }
890
891 memcpy(appender->buffer + appender->used, bytes, len);
892 appender->used += len;
893 appender->buffer[appender->used] = '\0';
894
895 return 0;
896}
897
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700898int json_obj_encode_buf(const struct json_obj_descr *descr, size_t descr_len,
899 const void *val, char *buffer, size_t buf_size)
900{
901 struct appender appender = { .buffer = buffer, .size = buf_size };
902
903 return json_obj_encode(descr, descr_len, val, append_bytes_to_buf,
904 &appender);
905}
906
Markus Fuchs2f9b0d42020-06-05 12:46:02 +0200907int json_arr_encode_buf(const struct json_obj_descr *descr, const void *val,
908 char *buffer, size_t buf_size)
909{
910 struct appender appender = { .buffer = buffer, .size = buf_size };
911
912 return json_arr_encode(descr, val, append_bytes_to_buf, &appender);
913}
914
Leandro Pereira7763a1d2017-06-05 17:01:01 -0700915static int measure_bytes(const char *bytes, size_t len, void *data)
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700916{
917 ssize_t *total = data;
918
919 *total += (ssize_t)len;
920
Leandro Pereira7de019a2017-09-05 16:34:57 -0700921 ARG_UNUSED(bytes);
922
Leandro Pereirab9b1c182017-03-14 16:50:33 -0700923 return 0;
924}
925
926ssize_t json_calc_encoded_len(const struct json_obj_descr *descr,
927 size_t descr_len, const void *val)
928{
929 ssize_t total = 0;
930 int ret;
931
932 ret = json_obj_encode(descr, descr_len, val, measure_bytes, &total);
933 if (ret < 0) {
934 return ret;
935 }
936
937 return total;
Leandro Pereirafb192c52017-02-16 15:51:31 -0800938}