Skip to content

Commit 1abfb4b

Browse files
authored
Add API to iterate over items in a JSON collection (#74)
1 parent d57d836 commit 1abfb4b

34 files changed

+595
-38
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Change Log for coreJSON Library
22

3+
## v3.0.0 (December 2020)
4+
- [#74](https://github.com/FreeRTOS/coreJSON/pull/74) Add `JSON_Iterate` function to iterate over items in a JSON collection.
5+
- [#74](https://github.com/FreeRTOS/coreJSON/pull/74) Add `JSONInvalid` enum with the value 0 to `JSONTypes_t`. This change is not backwards compatible.
6+
37
## v2.0.0 (November 2020)
48

59
### Updates
@@ -13,4 +17,4 @@
1317

1418
## v1.0.0 (September 2020)
1519

16-
This is the first release of the coreJSON library, a parser that strictly enforces the [ECMA-404 JSON standard](https://www.json.org/json-en.html) and is suitable for low memory footprint embedded devices.
20+
This is the first release of the coreJSON library, a parser that strictly enforces the [ECMA-404 JSON standard](https://www.json.org/json-en.html) and is suitable for low memory footprint embedded devices.

docs/doxygen/pages.dox

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ are written to cover every path of execution and achieve 100% branch coverage.
6262
@subpage json_search_function <br>
6363
@subpage json_searcht_function <br>
6464
@subpage json_searchconst_function <br>
65+
@subpage json_iterate_function <br>
6566

6667
@page json_validate_function JSON_Validate
6768
@snippet core_json.h declare_json_validate
@@ -78,10 +79,17 @@ are written to cover every path of execution and achieve 100% branch coverage.
7879
@page json_searchconst_function JSON_SearchConst
7980
@snippet core_json.h declare_json_searchconst
8081
@copydoc JSON_SearchConst
82+
83+
@page json_iterate_function JSON_Iterate
84+
@snippet core_json.h declare_json_iterate
85+
@copydoc JSON_Iterate
8186
*/
8287

8388
<!-- We do not use doxygen ALIASes here because there have been issues in the past versions with "^^" newlines within the alias definition. -->
8489
/**
8590
@defgroup json_enum_types Enumerated Types
8691
@brief Enumerated types of the JSON library
92+
93+
@defgroup json_struct_types Struct Types
94+
@brief Struct types of the JSON library
8795
*/

lexicon.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ foo
3232
ifndef
3333
inc
3434
ingroup
35+
int
3536
json
3637
jsonarray
3738
jsonbadparameter
3839
jsonfalse
3940
jsonillegaldocument
41+
jsoninvalid
4042
jsonmaxdepthexceeded
4143
jsonnotfound
4244
jsonnull
@@ -48,6 +50,7 @@ jsonstatus
4850
jsonstring
4951
jsonsuccess
5052
jsontrue
53+
jsontype
5154
keylength
5255
len
5356
longjmp
@@ -59,7 +62,10 @@ nb
5962
nextkeyvaluepair
6063
noninfringement
6164
nul
65+
outkey
66+
outkeylength
6267
outlength
68+
outpair
6369
outtype
6470
outvalue
6571
outvaluelength

source/core_json.c

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* coreJSON v2.0.0
2+
* coreJSON v3.0.0
33
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
44
*
55
* Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -1676,3 +1676,131 @@ JSONStatus_t JSON_SearchT( char * buf,
16761676
return JSON_SearchConst( ( const char * ) buf, max, query, queryLength,
16771677
( const char ** ) outValue, outValueLength, outType );
16781678
}
1679+
1680+
/** @cond DO_NOT_DOCUMENT */
1681+
1682+
/**
1683+
* @brief Output the next key-value pair or value from a collection.
1684+
*
1685+
* @param[in] buf The buffer to search.
1686+
* @param[in] max size of the buffer.
1687+
* @param[in] start The index at which the collection begins.
1688+
* @param[in,out] next The index at which to seek the next value.
1689+
* @param[out] outKey A pointer to receive the index of the value found.
1690+
* @param[out] outKeyLength A pointer to receive the length of the value found.
1691+
* @param[out] outValue A pointer to receive the index of the value found.
1692+
* @param[out] outValueLength A pointer to receive the length of the value found.
1693+
*
1694+
* @return #JSONSuccess if a value is output;
1695+
* #JSONIllegalDocument if the buffer does not begin with '[' or '{';
1696+
* #JSONNotFound if there are no further values in the collection.
1697+
*/
1698+
static JSONStatus_t iterate( const char * buf,
1699+
size_t max,
1700+
size_t * start,
1701+
size_t * next,
1702+
size_t * outKey,
1703+
size_t * outKeyLength,
1704+
size_t * outValue,
1705+
size_t * outValueLength )
1706+
{
1707+
JSONStatus_t ret = JSONNotFound;
1708+
bool found = false;
1709+
1710+
assert( ( buf != NULL ) && ( max > 0U ) );
1711+
assert( ( start != NULL ) && ( next != NULL ) );
1712+
assert( ( outKey != NULL ) && ( outKeyLength != NULL ) );
1713+
assert( ( outValue != NULL ) && ( outValueLength != NULL ) );
1714+
1715+
if( *start < max )
1716+
{
1717+
switch( buf[ *start ] )
1718+
{
1719+
case '[':
1720+
found = nextValue( buf, next, max, outValue, outValueLength );
1721+
1722+
if( found == true )
1723+
{
1724+
*outKey = 0;
1725+
*outKeyLength = 0;
1726+
}
1727+
1728+
break;
1729+
1730+
case '{':
1731+
found = nextKeyValuePair( buf, next, max, outKey, outKeyLength,
1732+
outValue, outValueLength );
1733+
break;
1734+
1735+
default:
1736+
ret = JSONIllegalDocument;
1737+
break;
1738+
}
1739+
}
1740+
1741+
if( found == true )
1742+
{
1743+
ret = JSONSuccess;
1744+
( void ) skipSpaceAndComma( buf, next, max );
1745+
}
1746+
1747+
return ret;
1748+
}
1749+
1750+
/** @endcond */
1751+
1752+
/**
1753+
* See core_json.h for docs.
1754+
*/
1755+
JSONStatus_t JSON_Iterate( const char * buf,
1756+
size_t max,
1757+
size_t * start,
1758+
size_t * next,
1759+
JSONPair_t * outPair )
1760+
{
1761+
JSONStatus_t ret;
1762+
size_t key, keyLength, value, valueLength;
1763+
1764+
if( ( buf == NULL ) || ( start == NULL ) || ( next == NULL ) ||
1765+
( outPair == NULL ) )
1766+
{
1767+
ret = JSONNullParameter;
1768+
}
1769+
else if( ( max == 0U ) || ( *start >= max ) || ( *next > max ) )
1770+
{
1771+
ret = JSONBadParameter;
1772+
}
1773+
else
1774+
{
1775+
skipSpace( buf, start, max );
1776+
1777+
if( *next <= *start )
1778+
{
1779+
*next = *start + 1U;
1780+
skipSpace( buf, next, max );
1781+
}
1782+
1783+
ret = iterate( buf, max, start, next, &key, &keyLength,
1784+
&value, &valueLength );
1785+
}
1786+
1787+
if( ret == JSONSuccess )
1788+
{
1789+
JSONTypes_t t = getType( buf[ value ] );
1790+
1791+
if( t == JSONString )
1792+
{
1793+
/* strip the surrounding quotes */
1794+
value++;
1795+
valueLength -= 2U;
1796+
}
1797+
1798+
outPair->key = ( key == 0U ) ? NULL : &buf[ key ];
1799+
outPair->keyLength = keyLength;
1800+
outPair->value = &buf[ value ];
1801+
outPair->valueLength = valueLength;
1802+
outPair->jsonType = t;
1803+
}
1804+
1805+
return ret;
1806+
}

source/include/core_json.h

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* coreJSON v2.0.0
2+
* coreJSON v3.0.0
33
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
44
*
55
* Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -173,17 +173,18 @@ JSONStatus_t JSON_Validate( const char * buf,
173173

174174
/**
175175
* @ingroup json_enum_types
176-
* @brief Return codes from coreJSON library functions.
176+
* @brief Value types from the JSON standard.
177177
*/
178178
typedef enum
179179
{
180-
JSONString = 0, /**< @brief A quote delimited sequence of Unicode characters. */
181-
JSONNumber, /**< @brief A rational number. */
182-
JSONTrue, /**< @brief The literal value true. */
183-
JSONFalse, /**< @brief The literal value false. */
184-
JSONNull, /**< @brief The literal value null. */
185-
JSONObject, /**< @brief A collection of zero or more key-value pairs. */
186-
JSONArray /**< @brief A collection of zero or more values. */
180+
JSONInvalid = 0, /**< @brief Not a valid JSON type. */
181+
JSONString, /**< @brief A quote delimited sequence of Unicode characters. */
182+
JSONNumber, /**< @brief A rational number. */
183+
JSONTrue, /**< @brief The literal value true. */
184+
JSONFalse, /**< @brief The literal value false. */
185+
JSONNull, /**< @brief The literal value null. */
186+
JSONObject, /**< @brief A collection of zero or more key-value pairs. */
187+
JSONArray /**< @brief A collection of zero or more values. */
187188
} JSONTypes_t;
188189

189190
/**
@@ -231,4 +232,93 @@ JSONStatus_t JSON_SearchConst( const char * buf,
231232
size_t * outValueLength,
232233
JSONTypes_t * outType );
233234
/* @[declare_json_searchconst] */
235+
236+
/**
237+
* @ingroup json_struct_types
238+
* @brief Structure to represent a key-value pair.
239+
*/
240+
typedef struct
241+
{
242+
const char * key; /**< @brief Pointer to the code point sequence for key. */
243+
size_t keyLength; /**< @brief Length of the code point sequence for key. */
244+
const char * value; /**< @brief Pointer to the code point sequence for value. */
245+
size_t valueLength; /**< @brief Length of the code point sequence for value. */
246+
JSONTypes_t jsonType; /**< @brief JSON-specific type of the value. */
247+
} JSONPair_t;
248+
249+
/**
250+
* @brief Output the next key-value pair or value from a collection.
251+
*
252+
* This function may be used in a loop to output each key-value pair from an object,
253+
* or each value from an array. For the first invocation, the integers pointed to by
254+
* start and next should be initialized to 0. These will be updated by the function.
255+
* If another key-value pair or value is present, the output structure is populated
256+
* and #JSONSuccess is returned; otherwise the structure is unchanged and #JSONNotFound
257+
* is returned.
258+
*
259+
* @param[in] buf The buffer to search.
260+
* @param[in] max size of the buffer.
261+
* @param[in,out] start The index at which the collection begins.
262+
* @param[in,out] next The index at which to seek the next value.
263+
* @param[out] outPair A pointer to receive the next key-value pair.
264+
*
265+
* @note This function expects a valid JSON document; run JSON_Validate() first.
266+
*
267+
* @note For an object, the outPair structure will reference a key and its value.
268+
* For an array, only the value will be referenced (i.e., outPair.key will be NULL).
269+
*
270+
* @return #JSONSuccess if a value is output;
271+
* #JSONIllegalDocument if the buffer does not contain a collection;
272+
* #JSONNotFound if there are no further values in the collection.
273+
*
274+
* <b>Example</b>
275+
* @code{c}
276+
* // Variables used in this example.
277+
* static char * json_types[] =
278+
* {
279+
* "invalid",
280+
* "string",
281+
* "number",
282+
* "true",
283+
* "false",
284+
* "null",
285+
* "object",
286+
* "array"
287+
* };
288+
*
289+
* void show( const char * json,
290+
* size_t length )
291+
* {
292+
* size_t start = 0, next = 0;
293+
* JSONPair_t pair = { 0 };
294+
* JSONStatus_t result;
295+
*
296+
* result = JSON_Validate( json, length );
297+
* if( result == JSONSuccess )
298+
* {
299+
* result = JSON_Iterate( json, length, &start, &next, &pair );
300+
* }
301+
*
302+
* while( result == JSONSuccess )
303+
* {
304+
* if( pair.key != NULL )
305+
* {
306+
* printf( "key: %.*s\t", ( int ) pair.keyLength, pair.key );
307+
* }
308+
*
309+
* printf( "value: (%s) %.*s\n", json_types[ pair.jsonType ],
310+
* ( int ) pair.valueLength, pair.value );
311+
*
312+
* result = JSON_Iterate( json, length, &start, &next, &pair );
313+
* }
314+
* }
315+
* @endcode
316+
*/
317+
/* @[declare_json_iterate] */
318+
JSONStatus_t JSON_Iterate( const char * buf,
319+
size_t max,
320+
size_t * start,
321+
size_t * next,
322+
JSONPair_t * outPair );
323+
/* @[declare_json_iterate] */
234324
#endif /* ifndef CORE_JSON_H_ */

test/cbmc/include/core_json_annex.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* coreJSON v2.0.0
2+
* coreJSON v3.0.0
33
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
44
*
55
* Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -45,6 +45,11 @@
4545
/* All possible return values for JSON_Search() */
4646
#define jsonSearchEnum( x ) ( jsonValidateEnum( x ) || ( x == JSONNotFound ) )
4747

48+
/* All possible return values for JSON_Iterate() */
49+
#define jsonIterateEnum( x ) \
50+
( parameterEnum( x ) || ( x == JSONIllegalDocument ) || \
51+
( x == JSONNotFound ) || ( x == JSONSuccess ) )
52+
4853
/* All possible type values output from JSON_SearchT() */
4954
#define jsonTypesEnum( x ) \
5055
( ( x == JSONString ) || \

test/cbmc/include/skipGeneric.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* coreJSON v2.0.0
2+
* coreJSON v3.0.0
33
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
44
*
55
* Permission is hereby granted, free of charge, to any person obtaining a copy of

0 commit comments

Comments
 (0)