Parse an object - create a new root, and populate. */
| 1001 | |
| 1002 | /* Parse an object - create a new root, and populate. */ |
| 1003 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) |
| 1004 | { |
| 1005 | parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; |
| 1006 | cJSON *item = NULL; |
| 1007 | |
| 1008 | /* reset error position */ |
| 1009 | global_error.json = NULL; |
| 1010 | global_error.position = 0; |
| 1011 | |
| 1012 | if (value == NULL) |
| 1013 | { |
| 1014 | goto fail; |
| 1015 | } |
| 1016 | |
| 1017 | buffer.content = (const unsigned char*)value; |
| 1018 | buffer.length = strlen((const char*)value) + sizeof(""); |
| 1019 | buffer.offset = 0; |
| 1020 | buffer.hooks = global_hooks; |
| 1021 | |
| 1022 | item = cJSON_New_Item(&global_hooks); |
| 1023 | if (item == NULL) /* memory fail */ |
| 1024 | { |
| 1025 | goto fail; |
| 1026 | } |
| 1027 | |
| 1028 | if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) |
| 1029 | { |
| 1030 | /* parse failure. ep is set. */ |
| 1031 | goto fail; |
| 1032 | } |
| 1033 | |
| 1034 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ |
| 1035 | if (require_null_terminated) |
| 1036 | { |
| 1037 | buffer_skip_whitespace(&buffer); |
| 1038 | if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') |
| 1039 | { |
| 1040 | goto fail; |
| 1041 | } |
| 1042 | } |
| 1043 | if (return_parse_end) |
| 1044 | { |
| 1045 | *return_parse_end = (const char*)buffer_at_offset(&buffer); |
| 1046 | } |
| 1047 | |
| 1048 | return item; |
| 1049 | |
| 1050 | fail: |
| 1051 | if (item != NULL) |
| 1052 | { |
| 1053 | cJSON_Delete(item); |
| 1054 | } |
| 1055 | |
| 1056 | if (value != NULL) |
| 1057 | { |
| 1058 | error local_error; |
| 1059 | local_error.json = (const unsigned char*)value; |
| 1060 | local_error.position = 0; |
no test coverage detected