mirror of
https://github.com/DaveGamble/cJSON.git
synced 2023-08-10 21:13:26 +03:00
Added cJSON_ParseWithLength (#358)
Co-authored-by: Caglar Ivriz <caglar.ivriz@siemens.com>
This commit is contained in:
parent
3ece4c893c
commit
983bb2b4d6
@ -267,6 +267,12 @@ Given some JSON in a zero terminated string, you can parse it with `cJSON_Parse`
|
||||
cJSON *json = cJSON_Parse(string);
|
||||
```
|
||||
|
||||
Given some JSON in a string (whether zero terminated or not), you can parse it with `cJSON_ParseWithLength`.
|
||||
|
||||
```c
|
||||
cJSON *json = cJSON_ParseWithLength(string, buffer_length);
|
||||
```
|
||||
|
||||
It will parse the JSON and allocate a tree of `cJSON` items that represents it. Once it returns, you are fully responsible for deallocating it after use with `cJSON_Delete`.
|
||||
|
||||
The allocator used by `cJSON_Parse` is `malloc` and `free` by default but can be changed (globally) with `cJSON_InitHooks`.
|
||||
@ -277,6 +283,8 @@ By default, characters in the input string that follow the parsed JSON will not
|
||||
If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`.
|
||||
`return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON.
|
||||
|
||||
If you want more options giving buffer length, use `cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)`.
|
||||
|
||||
### Printing JSON
|
||||
|
||||
Given a tree of `cJSON` items, you can print them as a string using `cJSON_Print`.
|
||||
|
33
cJSON.c
33
cJSON.c
@ -983,6 +983,11 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cannot_access_at_index(buffer, 0))
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
|
||||
{
|
||||
buffer->offset++;
|
||||
@ -1012,8 +1017,23 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Parse an object - create a new root, and populate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
|
||||
{
|
||||
size_t buffer_length;
|
||||
|
||||
if (NULL == value)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Adding null character size due to require_null_terminated. */
|
||||
buffer_length = strlen(value) + sizeof("");
|
||||
|
||||
return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
|
||||
}
|
||||
|
||||
/* Parse an object - create a new root, and populate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
cJSON *item = NULL;
|
||||
@ -1022,13 +1042,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return
|
||||
global_error.json = NULL;
|
||||
global_error.position = 0;
|
||||
|
||||
if (value == NULL)
|
||||
if (value == NULL || 0 == buffer_length)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
buffer.content = (const unsigned char*)value;
|
||||
buffer.length = strlen((const char*)value) + sizeof("");
|
||||
buffer.length = buffer_length;
|
||||
buffer.offset = 0;
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
@ -1098,7 +1118,12 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
|
||||
return cJSON_ParseWithOpts(value, 0, 0);
|
||||
}
|
||||
|
||||
#define cjson_min(a, b) ((a < b) ? a : b)
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
|
||||
{
|
||||
return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
|
||||
}
|
||||
|
||||
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
|
||||
{
|
||||
|
2
cJSON.h
2
cJSON.h
@ -151,9 +151,11 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
|
@ -195,6 +195,61 @@ static void test12_should_not_be_parsed(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test13_should_be_parsed_without_null_termination(void)
|
||||
{
|
||||
cJSON *tree = NULL;
|
||||
const char test_13[] = "{" \
|
||||
"\"Image\":{" \
|
||||
"\"Width\":800," \
|
||||
"\"Height\":600," \
|
||||
"\"Title\":\"Viewfrom15thFloor\"," \
|
||||
"\"Thumbnail\":{" \
|
||||
"\"Url\":\"http:/*www.example.com/image/481989943\"," \
|
||||
"\"Height\":125," \
|
||||
"\"Width\":\"100\"" \
|
||||
"}," \
|
||||
"\"IDs\":[116,943,234,38793]" \
|
||||
"}" \
|
||||
"}";
|
||||
|
||||
char test_13_wo_null[sizeof(test_13) - 1];
|
||||
memcpy(test_13_wo_null, test_13, sizeof(test_13) - 1);
|
||||
|
||||
tree = cJSON_ParseWithLength(test_13_wo_null, sizeof(test_13) - 1);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(tree, "Failed to parse valid json.");
|
||||
|
||||
if (tree != NULL)
|
||||
{
|
||||
cJSON_Delete(tree);
|
||||
}
|
||||
}
|
||||
|
||||
static void test14_should_not_be_parsed(void)
|
||||
{
|
||||
cJSON *tree = NULL;
|
||||
const char test_14[] = "{" \
|
||||
"\"Image\":{" \
|
||||
"\"Width\":800," \
|
||||
"\"Height\":600," \
|
||||
"\"Title\":\"Viewfrom15thFloor\"," \
|
||||
"\"Thumbnail\":{" \
|
||||
"\"Url\":\"http:/*www.example.com/image/481989943\"," \
|
||||
"\"Height\":125," \
|
||||
"\"Width\":\"100\"" \
|
||||
"}," \
|
||||
"\"IDs\":[116,943,234,38793]" \
|
||||
"}" \
|
||||
"}";
|
||||
|
||||
tree = cJSON_ParseWithLength(test_14, sizeof(test_14) - 2);
|
||||
TEST_ASSERT_NULL_MESSAGE(tree, "Should not continue after buffer_length is reached.");
|
||||
|
||||
if (tree != NULL)
|
||||
{
|
||||
cJSON_Delete(tree);
|
||||
}
|
||||
}
|
||||
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
@ -210,5 +265,7 @@ int CJSON_CDECL main(void)
|
||||
RUN_TEST(file_test10_should_be_parsed_and_printed);
|
||||
RUN_TEST(file_test11_should_be_parsed_and_printed);
|
||||
RUN_TEST(test12_should_not_be_parsed);
|
||||
RUN_TEST(test13_should_be_parsed_without_null_termination);
|
||||
RUN_TEST(test14_should_not_be_parsed);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user