json: add support for array iteration

Arrays can now be parsed using the JSON_ARRAY type (stored in
a struct json_iter) then iterated using json_iter_next. When
iterating the type can be checked with json_iter_get_type. For
each iteration the value can be obtained using any of the type
getters (int/uint/boolean/null).
This commit is contained in:
James Prestwood 2022-01-06 11:50:02 -08:00 committed by Denis Kenzior
parent ebed84ab55
commit 7991c861e1
2 changed files with 59 additions and 1 deletions

View File

@ -89,7 +89,17 @@ static void iter_recurse(struct json_iter *iter, jsmntok_t *token,
child->contents = c;
child->start = token - c->tokens;
child->current = child->start;
child->count = count_tokens_in_container(iter, token);
/*
* Add one to include the object/array token itself. This is required
* since 'current' points to the container initially. Only after a call
* to json_iter_next() will 'current' point to the first token in the
* container.
*/
if (token->type == JSMN_OBJECT || token->type == JSMN_ARRAY)
child->count++;
}
struct json_contents *json_contents_new(const char *json, size_t json_len)
@ -161,6 +171,7 @@ static void assign_arg(void *data, void *user_data)
break;
case JSON_OBJECT:
case JSON_PRIMITIVE:
case JSON_ARRAY:
iter_val = arg->value;
if (!arg->v)
@ -208,6 +219,7 @@ bool json_iter_parse(struct json_iter *iter, enum json_type type, ...)
case JSON_STRING:
case JSON_OBJECT:
case JSON_PRIMITIVE:
case JSON_ARRAY:
break;
default:
goto error;
@ -272,7 +284,7 @@ static bool iter_get_primitive_data(struct json_iter *iter, void **ptr,
size_t *len)
{
struct json_contents *c = iter->contents;
jsmntok_t *t = c->tokens + iter->start;
jsmntok_t *t = c->tokens + iter->current;
if (t->type != JSMN_PRIMITIVE)
return false;
@ -371,3 +383,45 @@ bool json_iter_get_null(struct json_iter *iter)
return false;
}
enum json_type json_iter_get_type(struct json_iter *iter)
{
struct json_contents *c = iter->contents;
jsmntok_t *t = c->tokens + iter->current;
return (enum json_type) t->type;
}
bool json_iter_next(struct json_iter *iter)
{
struct json_contents *c = iter->contents;
jsmntok_t *t = c->tokens + iter->current;
int inc = 1;
/*
* If this is the initial iteration skip this and just increment
* current by 1 since this iterator points to a container which needs to
* be advanced to the first token..
*
* In addition primitive types and empty containers will have a size
* of 1, so no special handling is needed there.
*
* For non-empty containers 'current' needs to be advanced by all the
* containers child tokens, plus the container itself.
*
* This check ensures:
* 1. It is not the initial iteration
* 2. This is a container
* 3. The container is not empty
*/
if (iter->current != iter->start && ((t->type == JSMN_OBJECT ||
t->type == JSMN_ARRAY) && t->size))
inc = count_tokens_in_container(iter, t) + 1;
if (c->tokens + iter->current + inc >= ITER_END(iter))
return false;
iter->current += inc;
return true;
}

View File

@ -42,6 +42,7 @@ struct json_iter {
struct json_contents *contents;
int start;
int count;
int current;
};
#define JSON_MANDATORY(key, type, out) \
@ -92,3 +93,6 @@ bool json_iter_get_int(struct json_iter *iter, int *i);
bool json_iter_get_uint(struct json_iter *iter, unsigned int *i);
bool json_iter_get_boolean(struct json_iter *iter, bool *b);
bool json_iter_get_null(struct json_iter *iter);
enum json_type json_iter_get_type(struct json_iter *iter);
bool json_iter_next(struct json_iter *iter);