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