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