Parse an object - create a new root, and populate. */
| 1089 | |
| 1090 | /* Parse an object - create a new root, and populate. */ |
| 1091 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) |
| 1092 | { |
| 1093 | parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; |
| 1094 | cJSON *item = NULL; |
| 1095 | |
| 1096 | /* reset error position */ |
| 1097 | global_error.json = NULL; |
| 1098 | global_error.position = 0; |
| 1099 | |
| 1100 | if (value == NULL || 0 == buffer_length) |
| 1101 | { |
| 1102 | goto fail; |
| 1103 | } |
| 1104 | |
| 1105 | buffer.content = (const unsigned char*)value; |
| 1106 | buffer.length = buffer_length; |
| 1107 | buffer.offset = 0; |
| 1108 | buffer.hooks = global_hooks; |
| 1109 | |
| 1110 | item = cJSON_New_Item(&global_hooks); |
| 1111 | if (item == NULL) /* memory fail */ |
| 1112 | { |
| 1113 | goto fail; |
| 1114 | } |
| 1115 | |
| 1116 | if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) |
| 1117 | { |
| 1118 | /* parse failure. ep is set. */ |
| 1119 | goto fail; |
| 1120 | } |
| 1121 | |
| 1122 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ |
| 1123 | if (require_null_terminated) |
| 1124 | { |
| 1125 | buffer_skip_whitespace(&buffer); |
| 1126 | if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') |
| 1127 | { |
| 1128 | goto fail; |
| 1129 | } |
| 1130 | } |
| 1131 | if (return_parse_end) |
| 1132 | { |
| 1133 | *return_parse_end = (const char*)buffer_at_offset(&buffer); |
| 1134 | } |
| 1135 | |
| 1136 | return item; |
| 1137 | |
| 1138 | fail: |
| 1139 | if (item != NULL) |
| 1140 | { |
| 1141 | cJSON_Delete(item); |
| 1142 | } |
| 1143 | |
| 1144 | if (value != NULL) |
| 1145 | { |
| 1146 | error local_error; |
| 1147 | local_error.json = (const unsigned char*)value; |
| 1148 | local_error.position = 0; |
no test coverage detected