From c26d53f0d74b10b4f8fb290ee663cfdd14d0115a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 26 Feb 2017 14:30:50 +0100 Subject: [PATCH 1/3] Helper function to check the type of an item This is necessary, because you can get it wrong if you do it manually. (when you forget the & 0xFF in the comparison) --- cJSON.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cJSON.h | 12 +++++++ 2 files changed, 112 insertions(+) diff --git a/cJSON.c b/cJSON.c index cf43ce9..39593b7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2149,3 +2149,103 @@ void cJSON_Minify(char *json) /* and null-terminate. */ *into = '\0'; } + +extern cjbool cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +extern cjbool cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +extern cjbool cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +extern cjbool cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +extern cjbool cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +extern cjbool cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +extern cjbool cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +extern cjbool cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +extern cjbool cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +extern cjbool cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} diff --git a/cJSON.h b/cJSON.h index de1f69f..831df39 100644 --- a/cJSON.h +++ b/cJSON.h @@ -109,6 +109,18 @@ extern int cJSON_HasObjectItem(const cJSON *object, const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ extern const char *cJSON_GetErrorPtr(void); +/* These functions check the type of an item */ +extern int cJSON_IsInvalid(const cJSON * const item); +extern int cJSON_IsFalse(const cJSON * const item); +extern int cJSON_IsTrue(const cJSON * const item); +extern int cJSON_IsBool(const cJSON * const item); +extern int cJSON_IsNull(const cJSON * const item); +extern int cJSON_IsNumber(const cJSON * const item); +extern int cJSON_IsString(const cJSON * const item); +extern int cJSON_IsArray(const cJSON * const item); +extern int cJSON_IsObject(const cJSON * const item); +extern int cJSON_IsRaw(const cJSON * const item); + /* These calls create a cJSON item of the appropriate type. */ extern cJSON *cJSON_CreateNull(void); extern cJSON *cJSON_CreateTrue(void); From ed8dc536994dfe13cbf7a2c01b87f50cc5874977 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 26 Feb 2017 21:26:34 +0100 Subject: [PATCH 2/3] cJSON_Utils: Use new typecheck functions --- cJSON_Utils.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index d43b8e2..d3e9a3f 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -117,7 +117,6 @@ static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned cha char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) { - int type = object->type; size_t c = 0; cJSON *obj = 0; @@ -133,7 +132,7 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target); if (found) { - if ((type & 0xFF) == cJSON_Array) + if (cJSON_IsArray(object)) { /* reserve enough memory for a 64 bit integer + '/' and '\0' */ unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23); @@ -150,7 +149,7 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) return (char*)ret; } - else if ((type & 0xFF) == cJSON_Object) + else if (cJSON_IsObject(object)) { unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2); *ret = '/'; @@ -176,7 +175,7 @@ cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer) /* follow path of the pointer */ while ((*pointer++ == '/') && object) { - if ((object->type & 0xFF) == cJSON_Array) + if (cJSON_IsArray(object)) { size_t which = 0; /* parse array index */ @@ -195,7 +194,7 @@ cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer) } object = cJSON_GetArrayItem(object, (int)which); } - else if ((object->type & 0xFF) == cJSON_Object) + else if (cJSON_IsObject(object)) { object = object->child; /* GetObjectItem. */ @@ -269,11 +268,11 @@ static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path) /* Couldn't find object to remove child from. */ ret = NULL; } - else if ((parent->type & 0xFF) == cJSON_Array) + else if (cJSON_IsArray(parent)) { ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr)); } - else if ((parent->type & 0xFF) == cJSON_Object) + else if (cJSON_IsObject(parent)) { ret = cJSON_DetachItemFromObject(parent, (char*)childptr); } @@ -474,7 +473,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) cJSON_Delete(value); return 9; } - else if ((parent->type & 0xFF) == cJSON_Array) + else if (cJSON_IsArray(parent)) { if (!strcmp((char*)childptr, "-")) { @@ -485,7 +484,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) cJSON_InsertItemInArray(parent, atoi((char*)childptr), value); } } - else if ((parent->type & 0xFF) == cJSON_Object) + else if (cJSON_IsObject(parent)) { cJSON_DeleteItemFromObject(parent, (char*)childptr); cJSON_AddItemToObject(parent, (char*)childptr, value); @@ -508,7 +507,7 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) return 1; } - if ((patches->type & 0xFF) != cJSON_Array) + if (cJSON_IsArray(patches)) { /* malformed patches. */ return 1; @@ -793,14 +792,14 @@ void cJSONUtils_SortObject(cJSON *object) cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch) { - if (!patch || ((patch->type & 0xFF) != cJSON_Object)) + if (!cJSON_IsObject(patch)) { /* scalar value, array or NULL, just duplicate */ cJSON_Delete(target); return cJSON_Duplicate(patch, 1); } - if (!target || ((target->type & 0xFF) != cJSON_Object)) + if (!cJSON_IsObject(target)) { cJSON_Delete(target); target = cJSON_CreateObject(); @@ -809,7 +808,7 @@ cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch) patch = patch->child; while (patch) { - if ((patch->type & 0xFF) == cJSON_NULL) + if (cJSON_IsNull(patch)) { /* NULL is the indicator to remove a value, see RFC7396 */ cJSON_DeleteItemFromObject(target, patch->string); @@ -832,7 +831,7 @@ cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to) /* patch to delete everything */ return cJSON_CreateNull(); } - if (((to->type & 0xFF) != cJSON_Object) || !from || ((from->type & 0xFF) != cJSON_Object)) + if (!cJSON_IsObject(to) || !cJSON_IsObject(from)) { return cJSON_Duplicate(to, 1); } From c45dc12fd74676be304b5e1f8db346e311fb54e2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 26 Feb 2017 21:54:01 +0100 Subject: [PATCH 3/3] Tests for typecheck functions --- tests/misc_tests.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 518ac72..47dff72 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -127,6 +127,62 @@ static void cjson_get_object_item_case_sensitive_should_get_object_items(void) cJSON_Delete(item); } +static void typecheck_functions_should_check_type(void) +{ + cJSON invalid[1]; + cJSON item[1]; + invalid->type = cJSON_Invalid; + invalid->type |= cJSON_StringIsConst; + item->type = cJSON_False; + item->type |= cJSON_StringIsConst; + + TEST_ASSERT_FALSE(cJSON_IsInvalid(NULL)); + TEST_ASSERT_FALSE(cJSON_IsInvalid(item)); + TEST_ASSERT_TRUE(cJSON_IsInvalid(invalid)); + + item->type = cJSON_False | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsFalse(NULL)); + TEST_ASSERT_FALSE(cJSON_IsFalse(invalid)); + TEST_ASSERT_TRUE(cJSON_IsFalse(item)); + TEST_ASSERT_TRUE(cJSON_IsBool(item)); + + item->type = cJSON_True | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsTrue(NULL)); + TEST_ASSERT_FALSE(cJSON_IsTrue(invalid)); + TEST_ASSERT_TRUE(cJSON_IsTrue(item)); + TEST_ASSERT_TRUE(cJSON_IsBool(item)); + + item->type = cJSON_NULL | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsNull(NULL)); + TEST_ASSERT_FALSE(cJSON_IsNull(invalid)); + TEST_ASSERT_TRUE(cJSON_IsNull(item)); + + item->type = cJSON_Number | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsNumber(NULL)); + TEST_ASSERT_FALSE(cJSON_IsNumber(invalid)); + TEST_ASSERT_TRUE(cJSON_IsNumber(item)); + + item->type = cJSON_String | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsString(NULL)); + TEST_ASSERT_FALSE(cJSON_IsString(invalid)); + TEST_ASSERT_TRUE(cJSON_IsString(item)); + + item->type = cJSON_Array | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsArray(NULL)); + TEST_ASSERT_FALSE(cJSON_IsArray(invalid)); + TEST_ASSERT_TRUE(cJSON_IsArray(item)); + + item->type = cJSON_Object | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsObject(NULL)); + TEST_ASSERT_FALSE(cJSON_IsObject(invalid)); + TEST_ASSERT_TRUE(cJSON_IsObject(item)); + + item->type = cJSON_Raw | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsRaw(NULL)); + TEST_ASSERT_FALSE(cJSON_IsRaw(invalid)); + TEST_ASSERT_TRUE(cJSON_IsRaw(item)); +} + int main(void) { UNITY_BEGIN(); @@ -135,6 +191,7 @@ int main(void) RUN_TEST(cjson_array_foreach_should_not_dereference_null_pointer); RUN_TEST(cjson_get_object_item_should_get_object_items); RUN_TEST(cjson_get_object_item_case_sensitive_should_get_object_items); + RUN_TEST(typecheck_functions_should_check_type); return UNITY_END(); }