Adds links to parent values and values used to wrap objects/arrays. Assigning a value to 2 objects/arrays returns an error now.

Addresses issues #66 and #30.
pull/56/merge
Krzysztof Gabis 8 years ago
parent dcf85b88c8
commit f419334a32
  1. 66
      parson.c
  2. 5
      parson.h
  3. 23
      tests.c

@ -64,11 +64,13 @@ typedef union json_value_value {
} JSON_Value_Value;
struct json_value_t {
JSON_Value_Type type;
JSON_Value_Value value;
JSON_Value *parent;
JSON_Value_Type type;
JSON_Value_Value value;
};
struct json_object_t {
JSON_Value *wrapping_value;
char **names;
JSON_Value **values;
size_t count;
@ -76,6 +78,7 @@ struct json_object_t {
};
struct json_array_t {
JSON_Value *wrapping_value;
JSON_Value **items;
size_t count;
size_t capacity;
@ -93,14 +96,14 @@ static int is_valid_utf8(const char *string, size_t string_len);
static int is_decimal(const char *string, size_t length);
/* JSON Object */
static JSON_Object * json_object_init(void);
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_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 void json_object_free(JSON_Object *object);
/* JSON Array */
static JSON_Array * json_array_init(void);
static JSON_Array * json_array_init(JSON_Value *wrapping_value);
static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value);
static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity);
static void json_array_free(JSON_Array *array);
@ -222,10 +225,11 @@ static int is_decimal(const char *string, size_t length) {
if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') {
return 0;
}
while (length--)
while (length--) {
if (strchr("xX", string[length])) {
return 0;
}
}
return 1;
}
@ -298,11 +302,12 @@ static void remove_comments(char *string, const char *start_token, const char *e
}
/* JSON Object */
static JSON_Object * json_object_init(void) {
static JSON_Object * json_object_init(JSON_Value *wrapping_value) {
JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object));
if (!new_obj) {
if (new_obj == NULL) {
return NULL;
}
new_obj->wrapping_value = wrapping_value;
new_obj->names = (char**)NULL;
new_obj->values = (JSON_Value**)NULL;
new_obj->capacity = 0;
@ -332,6 +337,7 @@ static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_V
if (object->names[index] == NULL) {
return JSONFailure;
}
value->parent = json_object_get_wrapping_value(object);
object->values[index] = value;
object->count++;
return JSONSuccess;
@ -346,18 +352,15 @@ static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity)
new_capacity == 0) {
return JSONFailure; /* Shouldn't happen */
}
temp_names = (char**)parson_malloc(new_capacity * sizeof(char*));
if (temp_names == NULL) {
return JSONFailure;
}
temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
if (temp_values == NULL) {
parson_free(temp_names);
return JSONFailure;
}
if (object->names != NULL && object->values != NULL && object->count > 0) {
memcpy(temp_names, object->names, object->count * sizeof(char*));
memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*));
@ -395,11 +398,12 @@ static void json_object_free(JSON_Object *object) {
}
/* JSON Array */
static JSON_Array * json_array_init(void) {
static JSON_Array * json_array_init(JSON_Value *wrapping_value) {
JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array));
if (!new_array) {
if (new_array == NULL) {
return NULL;
}
new_array->wrapping_value = wrapping_value;
new_array->items = (JSON_Value**)NULL;
new_array->capacity = 0;
new_array->count = 0;
@ -416,6 +420,7 @@ static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) {
return JSONFailure;
}
}
value->parent = json_array_get_wrapping_value(array);
array->items[array->count] = value;
array->count++;
return JSONSuccess;
@ -440,8 +445,9 @@ static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity) {
}
static void json_array_free(JSON_Array *array) {
while (array->count--)
while (array->count--) {
json_value_free(array->items[array->count]);
}
parson_free(array->items);
parson_free(array);
}
@ -452,6 +458,7 @@ static JSON_Value * json_value_init_string_no_copy(char *string) {
if (!new_value) {
return NULL;
}
new_value->parent = NULL;
new_value->type = JSONString;
new_value->value.string = string;
return new_value;
@ -1101,6 +1108,10 @@ JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index) {
return object->values[index];
}
JSON_Value *json_object_get_wrapping_value(const JSON_Object *object) {
return object->wrapping_value;
}
int json_object_has_value (const JSON_Object *object, const char *name) {
return json_object_get_value(object, name) != NULL;
}
@ -1151,6 +1162,10 @@ size_t json_array_get_count(const JSON_Array *array) {
return array ? array->count : 0;
}
JSON_Value * json_array_get_wrapping_value(const JSON_Array *array) {
return array->wrapping_value;
}
/* JSON Value API */
JSON_Value_Type json_value_get_type(const JSON_Value *value) {
return value ? value->type : JSONError;
@ -1176,15 +1191,17 @@ int json_value_get_boolean(const JSON_Value *value) {
return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1;
}
JSON_Value * json_value_get_parent (const JSON_Value *value) {
return value ? value->parent : NULL;
}
void json_value_free(JSON_Value *value) {
switch (json_value_get_type(value)) {
case JSONObject:
json_object_free(value->value.object);
break;
case JSONString:
if (value->value.string) {
parson_free(value->value.string);
}
parson_free(value->value.string);
break;
case JSONArray:
json_array_free(value->value.array);
@ -1200,8 +1217,9 @@ JSON_Value * json_value_init_object(void) {
if (!new_value) {
return NULL;
}
new_value->parent = NULL;
new_value->type = JSONObject;
new_value->value.object = json_object_init();
new_value->value.object = json_object_init(new_value);
if (!new_value->value.object) {
parson_free(new_value);
return NULL;
@ -1214,8 +1232,9 @@ JSON_Value * json_value_init_array(void) {
if (!new_value) {
return NULL;
}
new_value->parent = NULL;
new_value->type = JSONArray;
new_value->value.array = json_array_init();
new_value->value.array = json_array_init(new_value);
if (!new_value->value.array) {
parson_free(new_value);
return NULL;
@ -1250,6 +1269,7 @@ JSON_Value * json_value_init_number(double number) {
if (!new_value) {
return NULL;
}
new_value->parent = NULL;
new_value->type = JSONNumber;
new_value->value.number = number;
return new_value;
@ -1260,6 +1280,7 @@ JSON_Value * json_value_init_boolean(int boolean) {
if (!new_value) {
return NULL;
}
new_value->parent = NULL;
new_value->type = JSONBoolean;
new_value->value.boolean = boolean ? 1 : 0;
return new_value;
@ -1270,6 +1291,7 @@ JSON_Value * json_value_init_null(void) {
if (!new_value) {
return NULL;
}
new_value->parent = NULL;
new_value->type = JSONNull;
return new_value;
}
@ -1494,10 +1516,11 @@ JSON_Status json_array_remove(JSON_Array *array, size_t ix) {
}
JSON_Status json_array_replace_value(JSON_Array *array, size_t ix, JSON_Value *value) {
if (array == NULL || value == NULL || ix >= json_array_get_count(array)) {
if (array == NULL || value == NULL || value->parent != NULL || ix >= json_array_get_count(array)) {
return JSONFailure;
}
json_value_free(json_array_get_value(array, ix));
value->parent = json_array_get_wrapping_value(array);
array->items[ix] = value;
return JSONSuccess;
}
@ -1563,7 +1586,7 @@ JSON_Status json_array_clear(JSON_Array *array) {
}
JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value) {
if (array == NULL || value == NULL) {
if (array == NULL || value == NULL || value->parent != NULL) {
return JSONFailure;
}
return json_array_add(array, value);
@ -1620,7 +1643,7 @@ JSON_Status json_array_append_null(JSON_Array *array) {
JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) {
size_t i = 0;
JSON_Value *old_value;
if (object == NULL || name == NULL || value == NULL) {
if (object == NULL || name == NULL || value == NULL || value->parent != NULL) {
return JSONFailure;
}
old_value = json_object_get_value(object, name);
@ -1628,6 +1651,7 @@ JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Va
json_value_free(old_value);
for (i = 0; i < json_object_get_count(object); i++) {
if (strcmp(object->names[i], name) == 0) {
value->parent = json_object_get_wrapping_value(object);
object->values[i] = value;
return JSONSuccess;
}

@ -128,6 +128,7 @@ int json_object_dotget_boolean(const JSON_Object *object, const char *
size_t json_object_get_count (const JSON_Object *object);
const char * json_object_get_name (const JSON_Object *object, size_t index);
JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index);
JSON_Value * json_object_get_wrapping_value(const JSON_Object *object);
/* Functions to check if object has a value with a specific name. Returned value is 1 if object has
* a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */
@ -172,7 +173,8 @@ JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
size_t json_array_get_count (const JSON_Array *array);
JSON_Value * json_array_get_wrapping_value(const JSON_Array *array);
/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
* Order of values in array may change during execution. */
JSON_Status json_array_remove(JSON_Array *array, size_t i);
@ -215,6 +217,7 @@ JSON_Array * json_value_get_array (const JSON_Value *value);
const char * json_value_get_string (const JSON_Value *value);
double json_value_get_number (const JSON_Value *value);
int json_value_get_boolean(const JSON_Value *value);
JSON_Value * json_value_get_parent (const JSON_Value *value);
/* Same as above, but shorter */
JSON_Value_Type json_type (const JSON_Value *value);

@ -115,6 +115,7 @@ void test_suite_1(void) {
void test_suite_2(JSON_Value *root_value) {
JSON_Object *root_object;
JSON_Array *array;
JSON_Value *array_value;
size_t i;
TEST(root_value);
TEST(json_value_get_type(root_value) == JSONObject);
@ -207,7 +208,13 @@ void test_suite_2(JSON_Value *root_value) {
TEST(json_object_get_object(root_object, "empty object") != NULL);
TEST(json_object_get_array(root_object, "empty array") != NULL);
TEST(json_object_get_wrapping_value(root_object) == root_value);
array = json_object_get_array(root_object, "string array");
array_value = json_object_get_value(root_object, "string array");
TEST(json_array_get_wrapping_value(array) == array_value);
TEST(json_value_get_parent(array_value) == root_value);
TEST(json_value_get_parent(root_value) == NULL);
}
void test_suite_2_no_comments(void) {
@ -300,7 +307,7 @@ void test_suite_4() {
void test_suite_5(void) {
JSON_Value *val_from_file = json_parse_file("tests/test_5.txt");
JSON_Value *val = NULL;
JSON_Value *val = NULL, *val_parent;
JSON_Object *obj = NULL;
JSON_Array *interests_arr = NULL;
@ -359,6 +366,18 @@ void test_suite_5(void) {
TEST(json_array_remove(interests_arr, 0) == JSONSuccess);
TEST(json_array_remove(interests_arr, 0) == JSONFailure); /* should be empty by now */
val_parent = json_value_init_null();
TEST(json_object_set_value(obj, "x", val_parent) == JSONSuccess);
TEST(json_object_set_value(obj, "x", val_parent) == JSONFailure);
val_parent = json_value_init_null();
TEST(json_array_append_value(interests_arr, val_parent) == JSONSuccess);
TEST(json_array_append_value(interests_arr, val_parent) == JSONFailure);
val_parent = json_value_init_null();
TEST(json_array_replace_value(interests_arr, 0, val_parent) == JSONSuccess);
TEST(json_array_replace_value(interests_arr, 0, val_parent) == JSONFailure);
TEST(json_object_remove(obj, "interests") == JSONSuccess);
/* UTF-8 tests */

Loading…
Cancel
Save