mirror of
https://github.com/kgabis/parson.git
synced 2024-11-24 06:05:29 +00:00
Not adding incorrect objects if json_object_dotset_value() fails halfway through.
Related to issue #100
This commit is contained in:
parent
921da6f5d7
commit
4f3eaa6849
174
parson.c
174
parson.c
@ -104,8 +104,11 @@ static int is_decimal(const char *string, size_t length);
|
|||||||
/* JSON Object */
|
/* JSON Object */
|
||||||
static JSON_Object * json_object_init(JSON_Value *wrapping_value);
|
static JSON_Object * json_object_init(JSON_Value *wrapping_value);
|
||||||
static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value);
|
static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value);
|
||||||
|
static JSON_Status json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value);
|
||||||
static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity);
|
static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity);
|
||||||
static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n);
|
static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len);
|
||||||
|
static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, int free_value);
|
||||||
|
static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value);
|
||||||
static void json_object_free(JSON_Object *object);
|
static void json_object_free(JSON_Object *object);
|
||||||
|
|
||||||
/* JSON Array */
|
/* JSON Array */
|
||||||
@ -345,11 +348,18 @@ static JSON_Object * json_object_init(JSON_Value *wrapping_value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) {
|
static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) {
|
||||||
|
if (name == NULL) {
|
||||||
|
return JSONFailure;
|
||||||
|
}
|
||||||
|
return json_object_addn(object, name, strlen(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSON_Status json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value) {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
if (object == NULL || name == NULL || value == NULL) {
|
if (object == NULL || name == NULL || value == NULL) {
|
||||||
return JSONFailure;
|
return JSONFailure;
|
||||||
}
|
}
|
||||||
if (json_object_get_value(object, name) != NULL) {
|
if (json_object_getn_value(object, name, name_len) != NULL) {
|
||||||
return JSONFailure;
|
return JSONFailure;
|
||||||
}
|
}
|
||||||
if (object->count >= object->capacity) {
|
if (object->count >= object->capacity) {
|
||||||
@ -359,7 +369,7 @@ static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_V
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
index = object->count;
|
index = object->count;
|
||||||
object->names[index] = parson_strdup(name);
|
object->names[index] = parson_strndup(name, name_len);
|
||||||
if (object->names[index] == NULL) {
|
if (object->names[index] == NULL) {
|
||||||
return JSONFailure;
|
return JSONFailure;
|
||||||
}
|
}
|
||||||
@ -399,20 +409,58 @@ static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity)
|
|||||||
return JSONSuccess;
|
return JSONSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n) {
|
static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len) {
|
||||||
size_t i, name_length;
|
size_t i, name_length;
|
||||||
for (i = 0; i < json_object_get_count(object); i++) {
|
for (i = 0; i < json_object_get_count(object); i++) {
|
||||||
name_length = strlen(object->names[i]);
|
name_length = strlen(object->names[i]);
|
||||||
if (name_length != n) {
|
if (name_length != name_len) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strncmp(object->names[i], name, n) == 0) {
|
if (strncmp(object->names[i], name, name_len) == 0) {
|
||||||
return object->values[i];
|
return object->values[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, int free_value) {
|
||||||
|
size_t i = 0, last_item_index = 0;
|
||||||
|
if (object == NULL || json_object_get_value(object, name) == NULL) {
|
||||||
|
return JSONFailure;
|
||||||
|
}
|
||||||
|
last_item_index = json_object_get_count(object) - 1;
|
||||||
|
for (i = 0; i < json_object_get_count(object); i++) {
|
||||||
|
if (strcmp(object->names[i], name) == 0) {
|
||||||
|
parson_free(object->names[i]);
|
||||||
|
if (free_value) {
|
||||||
|
json_value_free(object->values[i]);
|
||||||
|
}
|
||||||
|
if (i != last_item_index) { /* Replace key value pair with one from the end */
|
||||||
|
object->names[i] = object->names[last_item_index];
|
||||||
|
object->values[i] = object->values[last_item_index];
|
||||||
|
}
|
||||||
|
object->count -= 1;
|
||||||
|
return JSONSuccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JSONFailure; /* No execution path should end here */
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value) {
|
||||||
|
JSON_Value *temp_value = NULL;
|
||||||
|
JSON_Object *temp_object = NULL;
|
||||||
|
const char *dot_pos = strchr(name, '.');
|
||||||
|
if (dot_pos == NULL) {
|
||||||
|
return json_object_remove_internal(object, name, free_value);
|
||||||
|
}
|
||||||
|
temp_value = json_object_getn_value(object, name, dot_pos - name);
|
||||||
|
if (json_value_get_type(temp_value) != JSONObject) {
|
||||||
|
return JSONFailure;
|
||||||
|
}
|
||||||
|
temp_object = json_value_get_object(temp_value);
|
||||||
|
return json_object_dotremove_internal(temp_object, dot_pos + 1, free_value);
|
||||||
|
}
|
||||||
|
|
||||||
static void json_object_free(JSON_Object *object) {
|
static void json_object_free(JSON_Object *object) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < object->count; i++) {
|
for (i = 0; i < object->count; i++) {
|
||||||
@ -652,12 +700,18 @@ static JSON_Value * parse_value(const char **string, size_t nesting) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static JSON_Value * parse_object_value(const char **string, size_t nesting) {
|
static JSON_Value * parse_object_value(const char **string, size_t nesting) {
|
||||||
JSON_Value *output_value = json_value_init_object(), *new_value = NULL;
|
JSON_Value *output_value = NULL, *new_value = NULL;
|
||||||
JSON_Object *output_object = json_value_get_object(output_value);
|
JSON_Object *output_object = NULL;
|
||||||
char *new_key = NULL;
|
char *new_key = NULL;
|
||||||
if (output_value == NULL || **string != '{') {
|
output_value = json_value_init_object();
|
||||||
|
if (output_value == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (**string != '{') {
|
||||||
|
json_value_free(output_value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
output_object = json_value_get_object(output_value);
|
||||||
SKIP_CHAR(string);
|
SKIP_CHAR(string);
|
||||||
SKIP_WHITESPACES(string);
|
SKIP_WHITESPACES(string);
|
||||||
if (**string == '}') { /* empty object */
|
if (**string == '}') { /* empty object */
|
||||||
@ -708,11 +762,17 @@ static JSON_Value * parse_object_value(const char **string, size_t nesting) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static JSON_Value * parse_array_value(const char **string, size_t nesting) {
|
static JSON_Value * parse_array_value(const char **string, size_t nesting) {
|
||||||
JSON_Value *output_value = json_value_init_array(), *new_array_value = NULL;
|
JSON_Value *output_value = NULL, *new_array_value = NULL;
|
||||||
JSON_Array *output_array = json_value_get_array(output_value);
|
JSON_Array *output_array = NULL;
|
||||||
if (!output_value || **string != '[') {
|
output_value = json_value_init_array();
|
||||||
|
if (output_value == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (**string != '[') {
|
||||||
|
json_value_free(output_value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
output_array = json_value_get_array(output_value);
|
||||||
SKIP_CHAR(string);
|
SKIP_CHAR(string);
|
||||||
SKIP_WHITESPACES(string);
|
SKIP_WHITESPACES(string);
|
||||||
if (**string == ']') { /* empty array */
|
if (**string == ']') { /* empty array */
|
||||||
@ -1076,7 +1136,7 @@ JSON_Value * json_object_get_value(const JSON_Object *object, const char *name)
|
|||||||
if (object == NULL || name == NULL) {
|
if (object == NULL || name == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return json_object_nget_value(object, name, strlen(name));
|
return json_object_getn_value(object, name, strlen(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * json_object_get_string(const JSON_Object *object, const char *name) {
|
const char * json_object_get_string(const JSON_Object *object, const char *name) {
|
||||||
@ -1104,7 +1164,7 @@ JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *nam
|
|||||||
if (!dot_position) {
|
if (!dot_position) {
|
||||||
return json_object_get_value(object, name);
|
return json_object_get_value(object, name);
|
||||||
}
|
}
|
||||||
object = json_value_get_object(json_object_nget_value(object, name, dot_position - name));
|
object = json_value_get_object(json_object_getn_value(object, name, dot_position - name));
|
||||||
return json_object_dotget_value(object, dot_position + 1);
|
return json_object_dotget_value(object, dot_position + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1717,34 +1777,44 @@ JSON_Status json_object_set_null(JSON_Object *object, const char *name) {
|
|||||||
|
|
||||||
JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) {
|
JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) {
|
||||||
const char *dot_pos = NULL;
|
const char *dot_pos = NULL;
|
||||||
char *current_name = NULL;
|
JSON_Value *temp_value = NULL, *new_value = NULL;
|
||||||
JSON_Object *temp_obj = NULL;
|
JSON_Object *temp_object = NULL, *new_object = NULL;
|
||||||
JSON_Value *new_value = NULL;
|
JSON_Status status = JSONFailure;
|
||||||
|
size_t name_len = 0;
|
||||||
if (object == NULL || name == NULL || value == NULL) {
|
if (object == NULL || name == NULL || value == NULL) {
|
||||||
return JSONFailure;
|
return JSONFailure;
|
||||||
}
|
}
|
||||||
dot_pos = strchr(name, '.');
|
dot_pos = strchr(name, '.');
|
||||||
if (dot_pos == NULL) {
|
if (dot_pos == NULL) {
|
||||||
return json_object_set_value(object, name, value);
|
return json_object_set_value(object, name, value);
|
||||||
} else {
|
|
||||||
current_name = parson_strndup(name, dot_pos - name);
|
|
||||||
temp_obj = json_object_get_object(object, current_name);
|
|
||||||
if (temp_obj == NULL) {
|
|
||||||
new_value = json_value_init_object();
|
|
||||||
if (new_value == NULL) {
|
|
||||||
parson_free(current_name);
|
|
||||||
return JSONFailure;
|
|
||||||
}
|
|
||||||
if (json_object_add(object, current_name, new_value) == JSONFailure) {
|
|
||||||
json_value_free(new_value);
|
|
||||||
parson_free(current_name);
|
|
||||||
return JSONFailure;
|
|
||||||
}
|
|
||||||
temp_obj = json_object_get_object(object, current_name);
|
|
||||||
}
|
|
||||||
parson_free(current_name);
|
|
||||||
return json_object_dotset_value(temp_obj, dot_pos + 1, value);
|
|
||||||
}
|
}
|
||||||
|
name_len = dot_pos - name;
|
||||||
|
temp_value = json_object_getn_value(object, name, name_len);
|
||||||
|
if (temp_value) {
|
||||||
|
/* Don't overwrite existing non-object (unlike json_object_set_value, but it shouldn't be changed at this point) */
|
||||||
|
if (json_value_get_type(temp_value) != JSONObject) {
|
||||||
|
return JSONFailure;
|
||||||
|
}
|
||||||
|
temp_object = json_value_get_object(temp_value);
|
||||||
|
return json_object_dotset_value(temp_object, dot_pos + 1, value);
|
||||||
|
}
|
||||||
|
new_value = json_value_init_object();
|
||||||
|
if (new_value == NULL) {
|
||||||
|
return JSONFailure;
|
||||||
|
}
|
||||||
|
new_object = json_value_get_object(new_value);
|
||||||
|
status = json_object_dotset_value(new_object, dot_pos + 1, value);
|
||||||
|
if (status != JSONSuccess) {
|
||||||
|
json_value_free(new_value);
|
||||||
|
return JSONFailure;
|
||||||
|
}
|
||||||
|
status = json_object_addn(object, name, name_len, new_value);
|
||||||
|
if (status != JSONSuccess) {
|
||||||
|
json_object_dotremove_internal(new_object, dot_pos + 1, 0);
|
||||||
|
json_value_free(new_value);
|
||||||
|
return JSONFailure;
|
||||||
|
}
|
||||||
|
return JSONSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) {
|
JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) {
|
||||||
@ -1796,41 +1866,11 @@ JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSON_Status json_object_remove(JSON_Object *object, const char *name) {
|
JSON_Status json_object_remove(JSON_Object *object, const char *name) {
|
||||||
size_t i = 0, last_item_index = 0;
|
return json_object_remove_internal(object, name, 1);
|
||||||
if (object == NULL || json_object_get_value(object, name) == NULL) {
|
|
||||||
return JSONFailure;
|
|
||||||
}
|
|
||||||
last_item_index = json_object_get_count(object) - 1;
|
|
||||||
for (i = 0; i < json_object_get_count(object); i++) {
|
|
||||||
if (strcmp(object->names[i], name) == 0) {
|
|
||||||
parson_free(object->names[i]);
|
|
||||||
json_value_free(object->values[i]);
|
|
||||||
if (i != last_item_index) { /* Replace key value pair with one from the end */
|
|
||||||
object->names[i] = object->names[last_item_index];
|
|
||||||
object->values[i] = object->values[last_item_index];
|
|
||||||
}
|
|
||||||
object->count -= 1;
|
|
||||||
return JSONSuccess;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return JSONFailure; /* No execution path should end here */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_Status json_object_dotremove(JSON_Object *object, const char *name) {
|
JSON_Status json_object_dotremove(JSON_Object *object, const char *name) {
|
||||||
const char *dot_pos = strchr(name, '.');
|
return json_object_dotremove_internal(object, name, 1);
|
||||||
char *current_name = NULL;
|
|
||||||
JSON_Object *temp_obj = NULL;
|
|
||||||
if (dot_pos == NULL) {
|
|
||||||
return json_object_remove(object, name);
|
|
||||||
} else {
|
|
||||||
current_name = parson_strndup(name, dot_pos - name);
|
|
||||||
temp_obj = json_object_get_object(object, current_name);
|
|
||||||
parson_free(current_name);
|
|
||||||
if (temp_obj == NULL) {
|
|
||||||
return JSONFailure;
|
|
||||||
}
|
|
||||||
return json_object_dotremove(temp_obj, dot_pos + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_Status json_object_clear(JSON_Object *object) {
|
JSON_Status json_object_clear(JSON_Object *object) {
|
||||||
|
Loading…
Reference in New Issue
Block a user