Skip to content

Commit ae6aa61

Browse files
mrfuchscarlescufi
authored andcommitted
json: Fix multidimensional array support
This patch fixes support for encoding and decoding multidimensional arrays as described by the JSON_OBJ_DESCR_ARRAY_ARRAY() macro. Currently, the JSON array encoding and decoding functions, arr_encode() and arr_parse(), expect array elements to be of object or primitive type. However, arrays may be nested and so an array's elements may also be arrays. In order to support nested arrays, two special cases must be considered: 1. The array of objects/arrays sub-descriptor is described by two `json_obj_descr` structs and so two instead of one `json_obj_descr` structs must be skipped when iterating over the JSON descriptor to get to an array's elements. 2. The implicit array item count field has to be considered for the parent itself and all its child array items when calculating an element's size. Fixes #50801 Signed-off-by: Markus Fuchs <[email protected]>
1 parent 96c076b commit ae6aa61

File tree

1 file changed

+42
-19
lines changed

1 file changed

+42
-19
lines changed

lib/os/json.c

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -519,8 +519,17 @@ static ptrdiff_t get_elem_size(const struct json_obj_descr *descr)
519519
case JSON_TOK_TRUE:
520520
case JSON_TOK_FALSE:
521521
return sizeof(bool);
522-
case JSON_TOK_ARRAY_START:
523-
return descr->array.n_elements * get_elem_size(descr->array.element_descr);
522+
case JSON_TOK_ARRAY_START: {
523+
ptrdiff_t size;
524+
525+
size = descr->array.n_elements * get_elem_size(descr->array.element_descr);
526+
/* Consider additional item count field for array objects */
527+
if (descr->field_name_len > 0) {
528+
size = size + sizeof(size_t);
529+
}
530+
531+
return size;
532+
}
524533
case JSON_TOK_OBJECT_START: {
525534
ptrdiff_t total = 0;
526535
size_t i;
@@ -542,37 +551,44 @@ static int arr_parse(struct json_obj *obj,
542551
const struct json_obj_descr *elem_descr,
543552
size_t max_elements, void *field, void *val)
544553
{
545-
ptrdiff_t elem_size = get_elem_size(elem_descr);
546-
void *last_elem = (char *)field + elem_size * max_elements;
547-
size_t *elements = NULL;
548-
struct json_token value;
554+
void *value = val;
555+
size_t *elements = (size_t *)((char *)value + elem_descr->offset);
556+
ptrdiff_t elem_size;
557+
void *last_elem;
558+
struct json_token tok;
549559

550-
if (val) {
551-
elements = (size_t *)((char *)val + elem_descr->offset);
560+
/* For nested arrays, skip parent descriptor to get elements */
561+
if (elem_descr->type == JSON_TOK_ARRAY_START) {
562+
elem_descr = elem_descr->array.element_descr;
552563
}
553564

554-
__ASSERT_NO_MSG(elem_size > 0);
565+
*elements = 0;
566+
elem_size = get_elem_size(elem_descr);
567+
last_elem = (char *)field + elem_size * max_elements;
555568

556-
if (elements) {
557-
*elements = 0;
558-
}
569+
__ASSERT_NO_MSG(elem_size > 0);
559570

560-
while (!arr_next(obj, &value)) {
561-
if (value.type == JSON_TOK_ARRAY_END) {
571+
while (!arr_next(obj, &tok)) {
572+
if (tok.type == JSON_TOK_ARRAY_END) {
562573
return 0;
563574
}
564575

565576
if (field == last_elem) {
566577
return -ENOSPC;
567578
}
568579

569-
if (decode_value(obj, elem_descr, &value, field, NULL) < 0) {
570-
return -EINVAL;
580+
/* For nested arrays, update value to current field,
581+
* so it matches descriptor's offset to length field
582+
*/
583+
if (elem_descr->type == JSON_TOK_ARRAY_START) {
584+
value = field;
571585
}
572586

573-
if (elements) {
574-
(*elements)++;
587+
if (decode_value(obj, elem_descr, &tok, field, value) < 0) {
588+
return -EINVAL;
575589
}
590+
591+
(*elements)++;
576592
field = (char *)field + elem_size;
577593
}
578594

@@ -835,7 +851,7 @@ static int arr_encode(const struct json_obj_descr *elem_descr,
835851
const void *field, const void *val,
836852
json_append_bytes_t append_bytes, void *data)
837853
{
838-
ptrdiff_t elem_size = get_elem_size(elem_descr);
854+
ptrdiff_t elem_size;
839855
/*
840856
* NOTE: Since an element descriptor's offset isn't meaningful
841857
* (array elements occur at multiple offsets in `val'), we use
@@ -851,6 +867,13 @@ static int arr_encode(const struct json_obj_descr *elem_descr,
851867
return ret;
852868
}
853869

870+
/* For nested arrays, skip parent descriptor to get elements */
871+
if (elem_descr->type == JSON_TOK_ARRAY_START) {
872+
elem_descr = elem_descr->array.element_descr;
873+
}
874+
875+
elem_size = get_elem_size(elem_descr);
876+
854877
for (i = 0; i < n_elem; i++) {
855878
/*
856879
* Though "field" points at the next element in the

0 commit comments

Comments
 (0)