From 055c7007e520c103c41b5b50101357531978d7aa Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 11:06:43 +0200 Subject: [PATCH 01/52] refactor cJSONUtils_strdup --- cJSON_Utils.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index c6308bf..3b7cfbc 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -30,17 +30,18 @@ #include "cJSON_Utils.h" -static unsigned char* cJSONUtils_strdup(const unsigned char* str) +static unsigned char* cJSONUtils_strdup(const unsigned char* const string) { - size_t len = 0; + size_t length = 0; unsigned char *copy = NULL; - len = strlen((const char*)str) + 1; - if (!(copy = (unsigned char*)cJSON_malloc(len))) + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*) cJSON_malloc(length); + if (copy == NULL) { return NULL; } - memcpy(copy, str, len); + memcpy(copy, string, length); return copy; } From 44d313212b48f7d447fb6c6d97df402ad2d9dd31 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 12:52:29 +0200 Subject: [PATCH 02/52] refactor cJSONUtils_strcasecmp --- cJSON_Utils.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 3b7cfbc..b69cfa0 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -46,25 +46,28 @@ static unsigned char* cJSONUtils_strdup(const unsigned char* const string) return copy; } -static int cJSONUtils_strcasecmp(const unsigned char *s1, const unsigned char *s2) +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int cJSONUtils_strcasecmp(const unsigned char *string1, const unsigned char *string2) { - if (!s1) - { - return (s1 == s2) ? 0 : 1; /* both NULL? */ - } - if (!s2) + if ((string1 == NULL) || (string2 == NULL)) { return 1; } - for(; tolower(*s1) == tolower(*s2); (void)++s1, ++s2) + + if (string1 == string2) { - if(*s1 == 0) + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') { return 0; } } - return tolower(*s1) - tolower(*s2); + return tolower(*string1) - tolower(*string2); } /* JSON Pointer implementation: */ From b16bcc3c194a869629dc09d66def7e1f0e7ec2b7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 12:53:00 +0200 Subject: [PATCH 03/52] refactor cJSONUtils_Pstrcasecmp --- cJSON_Utils.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index b69cfa0..d07179f 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -70,34 +70,35 @@ static int cJSONUtils_strcasecmp(const unsigned char *string1, const unsigned ch return tolower(*string1) - tolower(*string2); } -/* JSON Pointer implementation: */ -static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e) +/* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */ +static int cJSONUtils_Pstrcasecmp(const unsigned char *name, const unsigned char *pointer) { - if (!a || !e) + if ((name == NULL) || (pointer == NULL)) { - return (a == e) ? 0 : 1; /* both NULL? */ + return 1; } - for (; *a && *e && (*e != '/'); (void)a++, e++) /* compare until next '/' */ + + for (; (*name != '\0') && (*pointer != '\0') && (*pointer != '/'); (void)name++, pointer++) /* compare until next '/' */ { - if (*e == '~') + if (*pointer == '~') { /* check for escaped '~' (~0) and '/' (~1) */ - if (!((e[1] == '0') && (*a == '~')) && !((e[1] == '1') && (*a == '/'))) + if (((pointer[1] != '0') || (*name != '~')) && ((pointer[1] != '1') || (*name != '/'))) { - /* invalid escape sequence or wrong character in *a */ + /* invalid escape sequence or wrong character in *name */ return 1; } else { - e++; + pointer++; } } - else if (tolower(*a) != tolower(*e)) + else if (tolower(*name) != tolower(*pointer)) { return 1; } } - if (((*e != 0) && (*e != '/')) != (*a != 0)) + if (((*pointer != 0) && (*pointer != '/')) != (*name != 0)) { /* one string has ended, the other not */ return 1; From b8e3673d0fc0f83fb6095e720411d0b0ed79b9ce Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 12:54:00 +0200 Subject: [PATCH 04/52] refactor cJSONUtils_PointerEncodedstrlen --- cJSON_Utils.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index d07179f..0fd18ab 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -107,18 +107,20 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *name, const unsigned char return 0; } -static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *s) +/* calculate the length of a string if encoded as JSON pointer with ~0 and ~1 escape sequences */ +static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *string) { - size_t l = 0; - for (; *s; (void)s++, l++) + size_t length; + for (length = 0; *string != '\0'; (void)string++, length++) { - if ((*s == '~') || (*s == '/')) + /* character needs to be escaped? */ + if ((*string == '~') || (*string == '/')) { - l++; + length++; } } - return l; + return length; } static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned char *s) From 674a6788191b181e4a1bb086be652bb2865d6267 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 12:54:44 +0200 Subject: [PATCH 05/52] refactor cJSONUtils_PointerEncodedstrcpy --- cJSON_Utils.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 0fd18ab..6689244 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -123,27 +123,29 @@ static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *string) return length; } -static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned char *s) +/* copy a string while escaping '~' and '/' with ~0 and ~1 JSON pointer escape codes */ +static void cJSONUtils_PointerEncodedstrcpy(unsigned char *destination, const unsigned char *source) { - for (; *s; s++) + for (; source[0] != '\0'; (void)source++, destination++) { - if (*s == '/') + if (source[0] == '/') { - *d++ = '~'; - *d++ = '1'; + destination[1] = '1'; + destination++; } - else if (*s == '~') + else if (source[0] == '~') { - *d++ = '~'; - *d++ = '0'; + destination[0] = '~'; + destination[1] = '1'; + destination++; } else { - *d++ = *s; + destination[0] = source[0]; } } - *d = '\0'; + destination[0] = '\0'; } CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) From 4932c80f26addcf5497a28d9398295525a07506f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 12:56:02 +0200 Subject: [PATCH 06/52] refactor cJSONUtils_FindPointerFromObjectTo --- cJSON_Utils.c | 46 ++++++++++++++++++++++++---------------------- cJSON_Utils.h | 2 +- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 6689244..db8fd4b 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -148,10 +148,10 @@ static void cJSONUtils_PointerEncodedstrcpy(unsigned char *destination, const un destination[0] = '\0'; } -CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) +CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target) { - size_t c = 0; - cJSON *obj = 0; + size_t child_index = 0; + cJSON *current_child = 0; if (object == target) { @@ -159,42 +159,44 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *ta return (char*)cJSONUtils_strdup((const unsigned char*)""); } - /* recursively search all children of the object */ - for (obj = object->child; obj; (void)(obj = obj->next), c++) + /* recursively search all children of the object or array */ + for (current_child = object->child; current_child != NULL; (void)(current_child = current_child->next), child_index++) { - unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target); - if (found) + unsigned char *target_pointer = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(current_child, target); + /* found the target? */ + if (target_pointer != NULL) { if (cJSON_IsArray(object)) { /* reserve enough memory for a 64 bit integer + '/' and '\0' */ - unsigned char *ret = (unsigned char*)cJSON_malloc(strlen((char*)found) + 23); + unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + 20 + sizeof("/")); /* check if conversion to unsigned long is valid * This should be eliminated at compile time by dead code elimination * if size_t is an alias of unsigned long, or if it is bigger */ - if (c > ULONG_MAX) + if (child_index > ULONG_MAX) { - cJSON_free(found); + cJSON_free(target_pointer); return NULL; } - sprintf((char*)ret, "/%lu%s", (unsigned long)c, found); /* / */ - cJSON_free(found); + sprintf((char*)full_pointer, "/%lu%s", (unsigned long)child_index, target_pointer); /* / */ + cJSON_free(target_pointer); - return (char*)ret; + return (char*)full_pointer; } - else if (cJSON_IsObject(object)) - { - unsigned char *ret = (unsigned char*)cJSON_malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2); - *ret = '/'; - cJSONUtils_PointerEncodedstrcpy(ret + 1, (unsigned char*)obj->string); - strcat((char*)ret, (char*)found); - cJSON_free(found); - return (char*)ret; + if (cJSON_IsObject(object)) + { + unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + cJSONUtils_PointerEncodedstrlen((unsigned char*)current_child->string) + 2); + full_pointer[0] = '/'; + cJSONUtils_PointerEncodedstrcpy(full_pointer + 1, (unsigned char*)current_child->string); + strcat((char*)full_pointer, (char*)target_pointer); + cJSON_free(target_pointer); + + return (char*)full_pointer; } /* reached leaf of the tree, found nothing */ - cJSON_free(found); + cJSON_free(target_pointer); return NULL; } } diff --git a/cJSON_Utils.h b/cJSON_Utils.h index e7cec14..6eab69a 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -60,7 +60,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch); CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to); /* Given a root object and a target object, construct a pointer from one to the other. */ -CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target); +CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target); /* Sorts the members of the object into alphabetical order. */ CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object); From 4642d6575fa00812d4c583ef68fb4dacfec458c8 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 12:56:45 +0200 Subject: [PATCH 07/52] refactor decode_array_index_from_pointer --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index db8fd4b..9998dcd 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -229,7 +229,7 @@ static cJSON_bool decode_array_index_from_pointer(const unsigned char * const po return 0; } - for (position = 0; (pointer[position] >= '0') && (*pointer <= '9'); position++) + for (position = 0; (pointer[position] >= '0') && (pointer[0] <= '9'); position++) { parsed_index = (10 * parsed_index) + (size_t)(pointer[position] - '0'); From 378a333ee21b086d8f2ec6a3197b471fe088016d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 12:57:49 +0200 Subject: [PATCH 08/52] refactor cJSONUtils_GetPointer --- cJSON_Utils.c | 22 ++++++++++++---------- cJSON_Utils.h | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 9998dcd..9c0c33e 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -245,12 +245,14 @@ static cJSON_bool decode_array_index_from_pointer(const unsigned char * const po return 1; } -CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer) +CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer) { + cJSON *current_element = object; /* follow path of the pointer */ - while ((*pointer++ == '/') && object) + while ((pointer[0] == '/') && (current_element != NULL)) { - if (cJSON_IsArray(object)) + pointer++; + if (cJSON_IsArray(current_element)) { size_t index = 0; if (!decode_array_index_from_pointer((const unsigned char*)pointer, &index)) @@ -258,18 +260,18 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer) return NULL; } - object = get_array_item(object, index); + current_element = get_array_item(current_element, index); } - else if (cJSON_IsObject(object)) + else if (cJSON_IsObject(current_element)) { - object = object->child; + current_element = current_element->child; /* GetObjectItem. */ - while (object && cJSONUtils_Pstrcasecmp((unsigned char*)object->string, (const unsigned char*)pointer)) + while ((current_element != NULL) && cJSONUtils_Pstrcasecmp((unsigned char*)current_element->string, (const unsigned char*)pointer)) { - object = object->next; + current_element = current_element->next; } /* skip to the next path token or end of string */ - while (*pointer && (*pointer != '/')) + while ((pointer[0] != '\0') && (pointer[0] != '/')) { pointer++; } @@ -280,7 +282,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer) } } - return object; + return current_element; } /* JSON Patch implementation. */ diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 6eab69a..8952645 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -23,7 +23,7 @@ #include "cJSON.h" /* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */ -CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer); +CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer); /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to); From 4ba6bafe34af2a7334389ef84f64d291d91fdf74 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:00:16 +0200 Subject: [PATCH 09/52] refactor cJSONUtils_InplaceDecodePointerString --- cJSON_Utils.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 9c0c33e..e9e809c 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -288,22 +288,35 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *po /* JSON Patch implementation. */ static void cJSONUtils_InplaceDecodePointerString(unsigned char *string) { - unsigned char *s2 = string; + unsigned char *decoded_string = string; if (string == NULL) { return; } - for (; *string; (void)s2++, string++) + for (; *string; (void)decoded_string++, string++) { - *s2 = (unsigned char) ((*string != '~') - ? (*string) - : ((*(++string) == '0') - ? '~' - : '/')); + if (string[0] == '~') + { + if (string[1] == '0') + { + decoded_string[0] = '~'; + } + else if (string[1] == '1') + { + decoded_string[1] = '/'; + } + else + { + /* invalid escape sequence */ + return; + } + + string++; + } } - *s2 = '\0'; + decoded_string[0] = '\0'; } /* non-broken cJSON_DetachItemFromArray */ From 2040ce9004c88a3217a37edc653f8a7ca88535b6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:01:04 +0200 Subject: [PATCH 10/52] refactor cJSONUtils_PatchDetach --- cJSON_Utils.c | 57 +++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index e9e809c..38f81c3 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -354,52 +354,55 @@ static cJSON *detach_item_from_array(cJSON *array, size_t which) static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path) { - unsigned char *parentptr = NULL; - unsigned char *childptr = NULL; + unsigned char *parent_pointer = NULL; + unsigned char *child_pointer = NULL; cJSON *parent = NULL; - cJSON *ret = NULL; + cJSON *detached_item = NULL; /* copy path and split it in parent and child */ - parentptr = cJSONUtils_strdup(path); - if (parentptr == NULL) { - return NULL; + parent_pointer = cJSONUtils_strdup(path); + if (parent_pointer == NULL) { + goto cleanup; } - childptr = (unsigned char*)strrchr((char*)parentptr, '/'); /* last '/' */ - if (childptr == NULL) + child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); /* last '/' */ + if (child_pointer == NULL) { - cJSON_free(parentptr); - return NULL; + goto cleanup; } /* split strings */ - *childptr++ = '\0'; + child_pointer[0] = '\0'; + child_pointer++; - parent = cJSONUtils_GetPointer(object, (char*)parentptr); - cJSONUtils_InplaceDecodePointerString(childptr); + parent = cJSONUtils_GetPointer(object, (char*)parent_pointer); + cJSONUtils_InplaceDecodePointerString(child_pointer); - if (!parent) - { - /* Couldn't find object to remove child from. */ - ret = NULL; - } - else if (cJSON_IsArray(parent)) + if (cJSON_IsArray(parent)) { size_t index = 0; - if (!decode_array_index_from_pointer(childptr, &index)) + if (!decode_array_index_from_pointer(child_pointer, &index)) { - cJSON_free(parentptr); - return NULL; + goto cleanup; } - ret = detach_item_from_array(parent, index); + detached_item = detach_item_from_array(parent, index); } else if (cJSON_IsObject(parent)) { - ret = cJSON_DetachItemFromObject(parent, (char*)childptr); + detached_item = cJSON_DetachItemFromObject(parent, (char*)child_pointer); + } + else + { + /* Couldn't find object to remove child from. */ + goto cleanup; } - cJSON_free(parentptr); - /* return the detachted item */ - return ret; +cleanup: + if (parent_pointer != NULL) + { + cJSON_free(parent_pointer); + } + + return detached_item; } static int cJSONUtils_Compare(cJSON *a, cJSON *b) From 63db67bfeb68d4107fb3366369daeff1d99ffaa7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:06:09 +0200 Subject: [PATCH 11/52] refactor cJSONUtils_Compare --- cJSON_Utils.c | 66 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 38f81c3..ff08007 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -416,49 +416,79 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b) { case cJSON_Number: /* numeric mismatch. */ - return ((a->valueint != b->valueint) || (a->valuedouble != b->valuedouble)) ? -2 : 0; + if ((a->valueint != b->valueint) || (a->valuedouble != b->valuedouble)) + { + return -2; + } + else + { + return 0; + } + case cJSON_String: /* string mismatch. */ - return (strcmp(a->valuestring, b->valuestring) != 0) ? -3 : 0; - case cJSON_Array: - for ((void)(a = a->child), b = b->child; a && b; (void)(a = a->next), b = b->next) + if (strcmp(a->valuestring, b->valuestring) != 0) { - int err = cJSONUtils_Compare(a, b); - if (err) + return -3; + } + else + { + return 0; + } + + case cJSON_Array: + for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) + { + int status = cJSONUtils_Compare(a, b); + if (status != 0) { - return err; + return status; } } + /* array size mismatch? (one of both children is not NULL) */ - return (a || b) ? -4 : 0; + if ((a != NULL) || (b != NULL)) + { + return -4; + } + else + { + return 0; + } + case cJSON_Object: cJSONUtils_SortObject(a); cJSONUtils_SortObject(b); - a = a->child; - b = b->child; - while (a && b) + for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) { - int err = 0; + int status = 0; /* compare object keys */ if (cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string)) { /* missing member */ return -6; } - err = cJSONUtils_Compare(a, b); - if (err) + status = cJSONUtils_Compare(a, b); + if (status != 0) { - return err; + return status; } - a = a->next; - b = b->next; } + /* object length mismatch (one of both children is not null) */ - return (a || b) ? -5 : 0; + if ((a != NULL) || (b != NULL)) + { + return -5; + } + else + { + return 0; + } default: break; } + /* null, true or false */ return 0; } From 48c97985d6986b72e551f2ad7fb65d209879244c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:11:14 +0200 Subject: [PATCH 12/52] refactor cJSONUtils_ApplyPatch --- cJSON_Utils.c | 259 ++++++++++++++++++++++++++++---------------------- 1 file changed, 146 insertions(+), 113 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index ff08007..04c9819 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -533,54 +533,100 @@ static cJSON_bool insert_item_in_array(cJSON *array, size_t which, cJSON *newite enum patch_operation { INVALID, ADD, REMOVE, REPLACE, MOVE, COPY, TEST }; -static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) +static enum patch_operation decode_patch_operation(const cJSON * const patch) +{ + cJSON *operation = cJSON_GetObjectItem(patch, "op"); + if (!cJSON_IsString(operation)) + { + return INVALID; + } + + if (strcmp(operation->valuestring, "add") == 0) + { + return ADD; + } + + if (strcmp(operation->valuestring, "remove") == 0) + { + return REMOVE; + } + + if (strcmp(operation->valuestring, "replace") == 0) + { + return REPLACE; + } + + if (strcmp(operation->valuestring, "move") == 0) + { + return MOVE; + } + + if (strcmp(operation->valuestring, "copy") == 0) + { + return COPY; + } + + if (strcmp(operation->valuestring, "test") == 0) + { + return TEST; + } + + return INVALID; +} + +/* overwrite and existing item with another one and free resources on the way */ +static void overwrite_item(cJSON * const root, const cJSON replacement) +{ + if (root == NULL) + { + return; + } + + if (root->string != NULL) + { + cJSON_free(root->string); + } + if (root->valuestring != NULL) + { + cJSON_free(root->valuestring); + } + if (root->child != NULL) + { + cJSON_Delete(root->child); + } + + memcpy(root, &replacement, sizeof(cJSON)); +} + +static int cJSONUtils_ApplyPatch(cJSON *object, const cJSON *patch) { - cJSON *op = NULL; cJSON *path = NULL; cJSON *value = NULL; cJSON *parent = NULL; enum patch_operation opcode = INVALID; - unsigned char *parentptr = NULL; - unsigned char *childptr = NULL; + unsigned char *parent_pointer = NULL; + unsigned char *child_pointer = NULL; + int status = 0; - op = cJSON_GetObjectItem(patch, "op"); path = cJSON_GetObjectItem(patch, "path"); - if (!cJSON_IsString(op) || !cJSON_IsString(path)) + if (!cJSON_IsString(path)) { /* malformed patch. */ - return 2; + status = 2; + goto cleanup; } - /* decode operation */ - if (!strcmp(op->valuestring, "add")) + opcode = decode_patch_operation(patch); + if (opcode == INVALID) { - opcode = ADD; + status = 3; + goto cleanup; } - else if (!strcmp(op->valuestring, "remove")) - { - opcode = REMOVE; - } - else if (!strcmp(op->valuestring, "replace")) - { - opcode = REPLACE; - } - else if (!strcmp(op->valuestring, "move")) - { - opcode = MOVE; - } - else if (!strcmp(op->valuestring, "copy")) - { - opcode = COPY; - } - else if (!strcmp(op->valuestring, "test")) + else if (opcode == TEST) { /* compare value: {...} with the given path */ - return cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value")); - } - else - { - /* unknown opcode. */ - return 3; + status = cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value")); + goto cleanup; } /* special case for replacing the root */ @@ -588,73 +634,47 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) { if (opcode == REMOVE) { - /* remove possible children */ - if (object->child != NULL) - { - cJSON_Delete(object->child); - } + static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL}; - /* remove other allocated resources */ - if (object->string != NULL) - { - cJSON_free(object->string); - } - if (object->valuestring != NULL) - { - cJSON_free(object->valuestring); - } + overwrite_item(object, invalid); - /* make it invalid */ - memset(object, '\0', sizeof(cJSON)); - - return 0; + status = 0; + goto cleanup; } if ((opcode == REPLACE) || (opcode == ADD)) { - /* remove possible children */ - if (object->child != NULL) - { - cJSON_Delete(object->child); - } - - /* remove other allocated resources */ - if (object->string != NULL) - { - cJSON_free(object->string); - } - if (object->valuestring != NULL) - { - cJSON_free(object->valuestring); - } - value = cJSON_GetObjectItem(patch, "value"); if (value == NULL) { /* missing "value" for add/replace. */ - return 7; + status = 7; + goto cleanup; } value = cJSON_Duplicate(value, 1); if (value == NULL) { /* out of memory for add/replace. */ - return 8; - } - /* the string "value" isn't needed */ - if (value->string != NULL) - { - cJSON_free(value->string); - value->string = NULL; + status = 8; + goto cleanup; } - /* copy over the value object */ - memcpy(object, value, sizeof(cJSON)); + overwrite_item(object, *value); /* delete the duplicated value */ cJSON_free(value); + value = NULL; - return 0; + /* the string "value" isn't needed */ + if (object->string != NULL) + { + cJSON_free(object->string); + object->string = NULL; + } + + status = 0; + goto cleanup; } } @@ -664,13 +684,15 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) cJSON *old_item = cJSONUtils_PatchDetach(object, (unsigned char*)path->valuestring); if (old_item == NULL) { - return 13; + status = 13; + goto cleanup; } cJSON_Delete(old_item); if (opcode == REMOVE) { /* For Remove, this job is done. */ - return 0; + status = 0; + goto cleanup; } } @@ -678,10 +700,11 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) if ((opcode == MOVE) || (opcode == COPY)) { cJSON *from = cJSON_GetObjectItem(patch, "from"); - if (!from) + if (from == NULL) { /* missing "from" for copy/move. */ - return 4; + status = 4; + goto cleanup; } if (opcode == MOVE) @@ -692,93 +715,103 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) { value = cJSONUtils_GetPointer(object, from->valuestring); } - if (!value) + if (value == NULL) { /* missing "from" for copy/move. */ - return 5; + status = 5; + goto cleanup; } if (opcode == COPY) { value = cJSON_Duplicate(value, 1); } - if (!value) + if (value == NULL) { /* out of memory for copy/move. */ - return 6; + status = 6; + goto cleanup; } } else /* Add/Replace uses "value". */ { value = cJSON_GetObjectItem(patch, "value"); - if (!value) + if (value == NULL) { /* missing "value" for add/replace. */ - return 7; + status = 7; + goto cleanup; } value = cJSON_Duplicate(value, 1); - if (!value) + if (value == NULL) { /* out of memory for add/replace. */ - return 8; + status = 8; + goto cleanup; } } /* Now, just add "value" to "path". */ /* split pointer in parent and child */ - parentptr = cJSONUtils_strdup((unsigned char*)path->valuestring); - childptr = (unsigned char*)strrchr((char*)parentptr, '/'); - if (childptr) + parent_pointer = cJSONUtils_strdup((unsigned char*)path->valuestring); + child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); + if (child_pointer != NULL) { - *childptr++ = '\0'; + child_pointer[0] = '\0'; + child_pointer++; } - parent = cJSONUtils_GetPointer(object, (char*)parentptr); - cJSONUtils_InplaceDecodePointerString(childptr); + parent = cJSONUtils_GetPointer(object, (char*)parent_pointer); + cJSONUtils_InplaceDecodePointerString(child_pointer); /* add, remove, replace, move, copy, test. */ - if ((parent == NULL) || (childptr == NULL)) + if ((parent == NULL) || (child_pointer == NULL)) { /* Couldn't find object to add to. */ - free(parentptr); - cJSON_Delete(value); - return 9; + status = 9; + goto cleanup; } else if (cJSON_IsArray(parent)) { - if (!strcmp((char*)childptr, "-")) + if (strcmp((char*)child_pointer, "-") == 0) { cJSON_AddItemToArray(parent, value); + value = NULL; } else { size_t index = 0; - if (!decode_array_index_from_pointer(childptr, &index)) + if (!decode_array_index_from_pointer(child_pointer, &index)) { - free(parentptr); - cJSON_Delete(value); - return 11; + status = 11; + goto cleanup; } if (!insert_item_in_array(parent, index, value)) { - free(parentptr); - cJSON_Delete(value); - return 10; + status = 10; + goto cleanup; } + value = NULL; } } else if (cJSON_IsObject(parent)) { - cJSON_DeleteItemFromObject(parent, (char*)childptr); - cJSON_AddItemToObject(parent, (char*)childptr, value); + cJSON_DeleteItemFromObject(parent, (char*)child_pointer); + cJSON_AddItemToObject(parent, (char*)child_pointer, value); + value = NULL; } - else + +cleanup: + if (value != NULL) { cJSON_Delete(value); } - free(parentptr); + if (parent_pointer != NULL) + { + cJSON_free(parent_pointer); + } - return 0; + return status; } CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) From bde341edd883de4978c78c97b510a40e54182aab Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:12:32 +0200 Subject: [PATCH 13/52] refactor cJSONUtils_ApplyPatches --- cJSON_Utils.c | 20 ++++++++++++-------- cJSON_Utils.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 04c9819..8a1e14a 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -814,26 +814,30 @@ cleanup: return status; } -CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) +CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches) { - int err = 0; + const cJSON *current_patch = NULL; + int status = 0; if (!cJSON_IsArray(patches)) { /* malformed patches. */ return 1; } - if (patches) + + if (patches != NULL) { - patches = patches->child; + current_patch = patches->child; } - while (patches) + + while (current_patch != NULL) { - if ((err = cJSONUtils_ApplyPatch(object, patches))) + status = cJSONUtils_ApplyPatch(object, current_patch); + if (status != 0) { - return err; + return status; } - patches = patches->next; + current_patch = current_patch->next; } return 0; diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 8952645..572ab93 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -30,7 +30,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to); /* Utility for generating patch array entries. */ CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val); /* Returns 0 for success. */ -CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches); +CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches); /* // Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use: From e591d4173adffcc7a794ef93fc624207992f6af2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:12:57 +0200 Subject: [PATCH 14/52] refactor cJSONUtils_GeneratePatch --- cJSON_Utils.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 8a1e14a..a706163 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -843,24 +843,35 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * co return 0; } -static void cJSONUtils_GeneratePatch(cJSON *patches, const unsigned char *op, const unsigned char *path, const unsigned char *suffix, cJSON *val) +static void cJSONUtils_GeneratePatch(cJSON * const patches, const unsigned char * const operation, const unsigned char * const path, const unsigned char *suffix, const cJSON * const value) { cJSON *patch = cJSON_CreateObject(); - cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)op)); - if (suffix) + if (patch == NULL) { - unsigned char *newpath = (unsigned char*)cJSON_malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen(suffix) + 2); - cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", (const char*)path), suffix); - cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)newpath)); - free(newpath); + return; } - else + cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)operation)); + + if (suffix == NULL) { cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path)); } - if (val) + else { - cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(val, 1)); + size_t suffix_length = cJSONUtils_PointerEncodedstrlen(suffix); + size_t path_length = strlen((const char*)path); + unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/")); + + sprintf((char*)full_path, "%s/", (const char*)path); + cJSONUtils_PointerEncodedstrcpy(full_path + path_length + 1, suffix); + + cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)full_path)); + free(full_path); + } + + if (value != NULL) + { + cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(value, 1)); } cJSON_AddItemToArray(patches, patch); } From 512c313111194e446ff22067bea47e9483e97999 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:13:17 +0200 Subject: [PATCH 15/52] refactor cJSONUtils_AddPatchToArray --- cJSON_Utils.c | 4 ++-- cJSON_Utils.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index a706163..a96045c 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -876,9 +876,9 @@ static void cJSONUtils_GeneratePatch(cJSON * const patches, const unsigned char cJSON_AddItemToArray(patches, patch); } -CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val) +CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value) { - cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val); + cJSONUtils_GeneratePatch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value); } static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, cJSON *from, cJSON *to) diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 572ab93..0d90cd6 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -28,7 +28,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *po /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to); /* Utility for generating patch array entries. */ -CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val); +CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value); /* Returns 0 for success. */ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches); From a67c24c451062cc34f20af356034223176546713 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:14:29 +0200 Subject: [PATCH 16/52] refactor cJSONUtils_CompareToPatch --- cJSON_Utils.c | 99 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 37 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index a96045c..575d9fe 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -881,7 +881,7 @@ CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * cJSONUtils_GeneratePatch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value); } -static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, cJSON *from, cJSON *to) +static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to) { if ((from == NULL) || (to == NULL)) { @@ -894,98 +894,123 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, return; } - switch ((from->type & 0xFF)) + switch (from->type & 0xFF) { case cJSON_Number: if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble)) { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to); + cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, NULL, to); } return; case cJSON_String: if (strcmp(from->valuestring, to->valuestring) != 0) { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to); + cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, NULL, to); } return; case cJSON_Array: { - size_t c = 0; - unsigned char *newpath = (unsigned char*)cJSON_malloc(strlen((const char*)path) + 23); /* Allow space for 64bit int. */ - /* generate patches for all array elements that exist in "from" and "to" */ - for ((void)(c = 0), (void)(from = from->child), to = to->child; from && to; (void)(from = from->next), (void)(to = to->next), c++) + size_t index = 0; + cJSON *from_child = from->child; + cJSON *to_child = to->child; + unsigned char *new_path = (unsigned char*)cJSON_malloc(strlen((const char*)path) + 20 + sizeof("/")); /* Allow space for 64bit int. log10(2^64) = 20 */ + + /* generate patches for all array elements that exist in both "from" and "to" */ + for (index = 0; (from_child != NULL) && (to_child != NULL); (void)(from_child = from_child->next), (void)(to_child = to_child->next), index++) { /* check if conversion to unsigned long is valid * This should be eliminated at compile time by dead code elimination * if size_t is an alias of unsigned long, or if it is bigger */ - if (c > ULONG_MAX) + if (index > ULONG_MAX) { - free(newpath); + free(new_path); return; } - sprintf((char*)newpath, "%s/%lu", path, (unsigned long)c); /* path of the current array element */ - cJSONUtils_CompareToPatch(patches, newpath, from, to); + sprintf((char*)new_path, "%s/%lu", path, (unsigned long)index); /* path of the current array element */ + cJSONUtils_CompareToPatch(patches, new_path, from_child, to_child); } + /* remove leftover elements from 'from' that are not in 'to' */ - for (; from; (void)(from = from->next)) + for (; (from_child != NULL); (void)(from_child = from_child->next)) { /* check if conversion to unsigned long is valid * This should be eliminated at compile time by dead code elimination * if size_t is an alias of unsigned long, or if it is bigger */ - if (c > ULONG_MAX) + if (index > ULONG_MAX) { - free(newpath); + free(new_path); return; } - sprintf((char*)newpath, "%lu", (unsigned long)c); - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, newpath, 0); + sprintf((char*)new_path, "%lu", (unsigned long)index); + cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, new_path, NULL); } /* add new elements in 'to' that were not in 'from' */ - for (; to; (void)(to = to->next), c++) + for (; (to_child != NULL); (void)(to_child = to_child->next), index++) { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to); + cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to_child); } - free(newpath); + free(new_path); return; } case cJSON_Object: { - cJSON *a = NULL; - cJSON *b = NULL; + cJSON *from_child = NULL; + cJSON *to_child = NULL; cJSONUtils_SortObject(from); cJSONUtils_SortObject(to); - a = from->child; - b = to->child; + from_child = from->child; + to_child = to->child; /* for all object values in the object with more of them */ - while (a || b) + while ((from_child != NULL) || (to_child != NULL)) { - int diff = (!a) ? 1 : ((!b) ? -1 : cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string)); - if (!diff) + int diff; + if (from_child == NULL) + { + diff = 1; + } + else if (to_child == NULL) + { + diff = -1; + } + else + { + diff = cJSONUtils_strcasecmp((unsigned char*)from_child->string, (unsigned char*)to_child->string); + } + + if (diff == 0) { /* both object keys are the same */ - unsigned char *newpath = (unsigned char*)cJSON_malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen((unsigned char*)a->string) + 2); - cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", path), (unsigned char*)a->string); + size_t path_length = strlen((const char*)path); + size_t from_child_name_length = cJSONUtils_PointerEncodedstrlen((unsigned char*)from_child->string); + unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/")); + + sprintf((char*)new_path, "%s/", path); + cJSONUtils_PointerEncodedstrcpy(new_path + path_length + 1, (unsigned char*)from_child->string); + /* create a patch for the element */ - cJSONUtils_CompareToPatch(patches, newpath, a, b); - free(newpath); - a = a->next; - b = b->next; + cJSONUtils_CompareToPatch(patches, new_path, from_child, to_child); + free(new_path); + + from_child = from_child->next; + to_child = to_child->next; } else if (diff < 0) { /* object element doesn't exist in 'to' --> remove it */ - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, (unsigned char*)a->string, 0); - a = a->next; + cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, (unsigned char*)from_child->string, NULL); + + from_child = from_child->next; } else { /* object element doesn't exist in 'from' --> add it */ - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (unsigned char*)b->string, b); - b = b->next; + cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (unsigned char*)to_child->string, to_child); + + to_child = to_child->next; } } return; From f030058183241d78e0d2fce775edae2f008352a4 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:15:18 +0200 Subject: [PATCH 17/52] refactor cJSONUtils_GeneratePatches --- cJSON_Utils.c | 2 +- cJSON_Utils.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 575d9fe..032c285 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1021,7 +1021,7 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char } } -CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to) +CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to) { cJSON *patches = cJSON_CreateArray(); cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to); diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 0d90cd6..88898ee 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -26,7 +26,8 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer); /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ -CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to); +/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */ +CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to); /* Utility for generating patch array entries. */ CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value); /* Returns 0 for success. */ From 7bf62ff4dc53ddf13773918cbd408ae0a049c712 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:16:30 +0200 Subject: [PATCH 18/52] refactor cJSONUtils_SortList --- cJSON_Utils.c | 104 ++++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 032c285..1b87d1b 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1034,39 +1034,41 @@ static cJSON *cJSONUtils_SortList(cJSON *list) { cJSON *first = list; cJSON *second = list; - cJSON *ptr = list; + cJSON *current_item = list; + cJSON *result = list; + cJSON *result_tail = NULL; - if (!list || !list->next) + if ((list == NULL) || (list->next == NULL)) { /* One entry is sorted already. */ - return list; + return result; } - while (ptr && ptr->next && (cJSONUtils_strcasecmp((unsigned char*)ptr->string, (unsigned char*)ptr->next->string) < 0)) + while ((current_item != NULL) && (current_item->next != NULL) && (cJSONUtils_strcasecmp((unsigned char*)current_item->string, (unsigned char*)current_item->next->string) < 0)) { /* Test for list sorted. */ - ptr = ptr->next; + current_item = current_item->next; } - if (!ptr || !ptr->next) + if ((current_item == NULL) || (current_item->next == NULL)) { /* Leave sorted lists unmodified. */ - return list; + return result; } - /* reset ptr to the beginning */ - ptr = list; - while (ptr) + /* reset pointer to the beginning */ + current_item = list; + while (current_item != NULL) { /* Walk two pointers to find the middle. */ second = second->next; - ptr = ptr->next; - /* advances ptr two steps at a time */ - if (ptr) + current_item = current_item->next; + /* advances current_item two steps at a time */ + if (current_item != NULL) { - ptr = ptr->next; + current_item = current_item->next; } } - if (second && second->prev) + if ((second != NULL) && (second->prev != NULL)) { /* Split the lists */ second->prev->next = NULL; @@ -1075,65 +1077,67 @@ static cJSON *cJSONUtils_SortList(cJSON *list) /* Recursively sort the sub-lists. */ first = cJSONUtils_SortList(first); second = cJSONUtils_SortList(second); - list = ptr = NULL; + result = NULL; - while (first && second) /* Merge the sub-lists */ + /* Merge the sub-lists */ + while ((first != NULL) && (second != NULL)) { + cJSON *smaller = NULL; if (cJSONUtils_strcasecmp((unsigned char*)first->string, (unsigned char*)second->string) < 0) { - if (!list) - { - /* start merged list with the first element of the first list */ - list = ptr = first; - } - else - { - /* add first element of first list to merged list */ - ptr->next = first; - first->prev = ptr; - ptr = first; - } + smaller = first; + } + else + { + smaller = second; + } + + if (result == NULL) + { + /* start merged list with the smaller element */ + result_tail = smaller; + result = smaller; + } + else + { + /* add smaller element to the list */ + result_tail->next = smaller; + smaller->prev = result_tail; + result_tail = smaller; + } + + if (first == smaller) + { first = first->next; } else { - if (!list) - { - /* start merged list with the first element of the second list */ - list = ptr = second; - } - else - { - /* add first element of second list to merged list */ - ptr->next = second; - second->prev = ptr; - ptr = second; - } second = second->next; } } - if (first) + + if (first != NULL) { /* Append rest of first list. */ - if (!list) + if (result == NULL) { return first; } - ptr->next = first; - first->prev = ptr; + result_tail->next = first; + first->prev = result_tail; } - if (second) + if (second != NULL) { /* Append rest of second list */ - if (!list) + if (result == NULL) { return second; } - ptr->next = second; - second->prev = ptr; + result_tail->next = second; + second->prev = result_tail; } - return list; + return result; } CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object) From 01d656bebcbe43a61442030a0d1833eff1a0edef Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:16:58 +0200 Subject: [PATCH 19/52] refactor cJSONUtils_SortObject --- cJSON_Utils.c | 2 +- cJSON_Utils.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 1b87d1b..2f131a8 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1140,7 +1140,7 @@ static cJSON *cJSONUtils_SortList(cJSON *list) return result; } -CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object) +CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object) { object->child = cJSONUtils_SortList(object->child); } diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 88898ee..d7234bb 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -64,4 +64,4 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to); CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target); /* Sorts the members of the object into alphabetical order. */ -CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object); +CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object); From 11b8a8cd76e2541505e07dd11f84ed3571a2f373 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:17:39 +0200 Subject: [PATCH 20/52] refactor cJSONUtils_MergePatch --- cJSON_Utils.c | 18 ++++++++++-------- cJSON_Utils.h | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 2f131a8..85238b1 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1145,8 +1145,10 @@ CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object) object->child = cJSONUtils_SortList(object->child); } -CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch) +CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) { + cJSON *patch_child = NULL; + if (!cJSON_IsObject(patch)) { /* scalar value, array or NULL, just duplicate */ @@ -1160,20 +1162,20 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch) target = cJSON_CreateObject(); } - patch = patch->child; - while (patch) + patch_child = patch->child; + while (patch_child != NULL) { - if (cJSON_IsNull(patch)) + if (cJSON_IsNull(patch_child)) { /* NULL is the indicator to remove a value, see RFC7396 */ - cJSON_DeleteItemFromObject(target, patch->string); + cJSON_DeleteItemFromObject(target, patch_child->string); } else { - cJSON *replaceme = cJSON_DetachItemFromObject(target, patch->string); - cJSON_AddItemToObject(target, patch->string, cJSONUtils_MergePatch(replaceme, patch)); + cJSON *replace_me = cJSON_DetachItemFromObject(target, patch_child->string); + cJSON_AddItemToObject(target, patch_child->string, cJSONUtils_MergePatch(replace_me, patch_child)); } - patch = patch->next; + patch_child = patch_child->next; } return target; } diff --git a/cJSON_Utils.h b/cJSON_Utils.h index d7234bb..a735862 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -56,7 +56,7 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * co /* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */ /* target will be modified by patch. return value is new ptr for target. */ -CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch); +CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch); /* generates a patch to move from -> to */ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to); From bb2f86812680c2cb489a38f3643fb58f4eb3482c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 13:18:25 +0200 Subject: [PATCH 21/52] refactor cJSONUtils_GenerateMergePatch --- cJSON_Utils.c | 56 +++++++++++++++++++++++++++++++++++---------------- cJSON_Utils.h | 3 ++- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 85238b1..5046328 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1180,10 +1180,12 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const p return target; } -CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to) +CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to) { + cJSON *from_child = NULL; + cJSON *to_child = NULL; cJSON *patch = NULL; - if (!to) + if (to == NULL) { /* patch to delete everything */ return cJSON_CreateNull(); @@ -1196,39 +1198,59 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to) cJSONUtils_SortObject(from); cJSONUtils_SortObject(to); - from = from->child; - to = to->child; + from_child = from->child; + to_child = to->child; patch = cJSON_CreateObject(); - while (from || to) + while (from_child || to_child) { - int compare = from ? (to ? strcmp(from->string, to->string) : -1) : 1; - if (compare < 0) + int diff; + if (from_child != NULL) + { + if (to_child != NULL) + { + diff = strcmp(from_child->string, to_child->string); + } + else + { + diff = -1; + } + } + else + { + diff = 1; + } + + if (diff < 0) { /* from has a value that to doesn't have -> remove */ - cJSON_AddItemToObject(patch, from->string, cJSON_CreateNull()); - from = from->next; + cJSON_AddItemToObject(patch, from_child->string, cJSON_CreateNull()); + + from_child = from_child->next; } - else if (compare > 0) + else if (diff > 0) { /* to has a value that from doesn't have -> add to patch */ - cJSON_AddItemToObject(patch, to->string, cJSON_Duplicate(to, 1)); - to = to->next; + cJSON_AddItemToObject(patch, to_child->string, cJSON_Duplicate(to_child, 1)); + + to_child = to_child->next; } else { /* object key exists in both objects */ - if (cJSONUtils_Compare(from, to)) + if (cJSONUtils_Compare(from_child, to_child)) { /* not identical --> generate a patch */ - cJSON_AddItemToObject(patch, to->string, cJSONUtils_GenerateMergePatch(from, to)); + cJSON_AddItemToObject(patch, to_child->string, cJSONUtils_GenerateMergePatch(from_child, to_child)); } + /* next key in the object */ - from = from->next; - to = to->next; + from_child = from_child->next; + to_child = to_child->next; } } - if (!patch->child) + if (patch->child == NULL) { + /* no patch generated */ cJSON_Delete(patch); return NULL; } diff --git a/cJSON_Utils.h b/cJSON_Utils.h index a735862..b20e5db 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -58,7 +58,8 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * co /* target will be modified by patch. return value is new ptr for target. */ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch); /* generates a patch to move from -> to */ -CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to); +/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */ +CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to); /* Given a root object and a target object, construct a pointer from one to the other. */ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target); From b73881a388c85a86ad75a4be68bc31007c79d731 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 14:19:01 +0200 Subject: [PATCH 22/52] cJSON_Utils: Add true/false --- cJSON_Utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 5046328..ad2805c 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -30,6 +30,10 @@ #include "cJSON_Utils.h" +/* define our own boolean type */ +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) + static unsigned char* cJSONUtils_strdup(const unsigned char* const string) { size_t length = 0; From 6b01dee7ca0b67e0493687f0ba18605166df22ff Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 14:19:52 +0200 Subject: [PATCH 23/52] Rename cJSONUtils_Pstrcasecmp to case_insensitive_pointer_comparison Also changes the return type to cJSON_bool --- cJSON_Utils.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index ad2805c..6c2e956 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -75,11 +75,11 @@ static int cJSONUtils_strcasecmp(const unsigned char *string1, const unsigned ch } /* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */ -static int cJSONUtils_Pstrcasecmp(const unsigned char *name, const unsigned char *pointer) +static cJSON_bool case_insensitive_pointer_comparison(const unsigned char *name, const unsigned char *pointer) { if ((name == NULL) || (pointer == NULL)) { - return 1; + return false; } for (; (*name != '\0') && (*pointer != '\0') && (*pointer != '/'); (void)name++, pointer++) /* compare until next '/' */ @@ -90,7 +90,7 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *name, const unsigned char if (((pointer[1] != '0') || (*name != '~')) && ((pointer[1] != '1') || (*name != '/'))) { /* invalid escape sequence or wrong character in *name */ - return 1; + return false; } else { @@ -99,16 +99,16 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *name, const unsigned char } else if (tolower(*name) != tolower(*pointer)) { - return 1; + return false; } } if (((*pointer != 0) && (*pointer != '/')) != (*name != 0)) { /* one string has ended, the other not */ - return 1; + return false;; } - return 0; + return true; } /* calculate the length of a string if encoded as JSON pointer with ~0 and ~1 escape sequences */ @@ -270,7 +270,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *po { current_element = current_element->child; /* GetObjectItem. */ - while ((current_element != NULL) && cJSONUtils_Pstrcasecmp((unsigned char*)current_element->string, (const unsigned char*)pointer)) + while ((current_element != NULL) && !case_insensitive_pointer_comparison((unsigned char*)current_element->string, (const unsigned char*)pointer)) { current_element = current_element->next; } From e3ed64d56e934494a5edcc3f62f4597b05306325 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 14:24:01 +0200 Subject: [PATCH 24/52] cJSON_PointerEncodedstrlen -> pointer_encoded_length --- cJSON_Utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 6c2e956..5847358 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -112,7 +112,7 @@ static cJSON_bool case_insensitive_pointer_comparison(const unsigned char *name, } /* calculate the length of a string if encoded as JSON pointer with ~0 and ~1 escape sequences */ -static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *string) +static size_t pointer_encoded_length(const unsigned char *string) { size_t length; for (length = 0; *string != '\0'; (void)string++, length++) @@ -190,7 +190,7 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje if (cJSON_IsObject(object)) { - unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + cJSONUtils_PointerEncodedstrlen((unsigned char*)current_child->string) + 2); + unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + pointer_encoded_length((unsigned char*)current_child->string) + 2); full_pointer[0] = '/'; cJSONUtils_PointerEncodedstrcpy(full_pointer + 1, (unsigned char*)current_child->string); strcat((char*)full_pointer, (char*)target_pointer); @@ -862,7 +862,7 @@ static void cJSONUtils_GeneratePatch(cJSON * const patches, const unsigned char } else { - size_t suffix_length = cJSONUtils_PointerEncodedstrlen(suffix); + size_t suffix_length = pointer_encoded_length(suffix); size_t path_length = strlen((const char*)path); unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/")); @@ -989,7 +989,7 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char { /* both object keys are the same */ size_t path_length = strlen((const char*)path); - size_t from_child_name_length = cJSONUtils_PointerEncodedstrlen((unsigned char*)from_child->string); + size_t from_child_name_length = pointer_encoded_length((unsigned char*)from_child->string); unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/")); sprintf((char*)new_path, "%s/", path); From f4d9e2e1a1e9cb38e743aea4427b577808786391 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 14:28:06 +0200 Subject: [PATCH 25/52] cJSON_strcasecmp -> case_insensitive_strcmp --- cJSON_Utils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 5847358..58a7e64 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -51,7 +51,7 @@ static unsigned char* cJSONUtils_strdup(const unsigned char* const string) } /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ -static int cJSONUtils_strcasecmp(const unsigned char *string1, const unsigned char *string2) +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) { if ((string1 == NULL) || (string2 == NULL)) { @@ -467,7 +467,7 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b) { int status = 0; /* compare object keys */ - if (cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string)) + if (case_insensitive_strcmp((unsigned char*)a->string, (unsigned char*)b->string)) { /* missing member */ return -6; @@ -982,7 +982,7 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char } else { - diff = cJSONUtils_strcasecmp((unsigned char*)from_child->string, (unsigned char*)to_child->string); + diff = case_insensitive_strcmp((unsigned char*)from_child->string, (unsigned char*)to_child->string); } if (diff == 0) @@ -1048,7 +1048,7 @@ static cJSON *cJSONUtils_SortList(cJSON *list) return result; } - while ((current_item != NULL) && (current_item->next != NULL) && (cJSONUtils_strcasecmp((unsigned char*)current_item->string, (unsigned char*)current_item->next->string) < 0)) + while ((current_item != NULL) && (current_item->next != NULL) && (case_insensitive_strcmp((unsigned char*)current_item->string, (unsigned char*)current_item->next->string) < 0)) { /* Test for list sorted. */ current_item = current_item->next; @@ -1087,7 +1087,7 @@ static cJSON *cJSONUtils_SortList(cJSON *list) while ((first != NULL) && (second != NULL)) { cJSON *smaller = NULL; - if (cJSONUtils_strcasecmp((unsigned char*)first->string, (unsigned char*)second->string) < 0) + if (case_insensitive_strcmp((unsigned char*)first->string, (unsigned char*)second->string) < 0) { smaller = first; } From e6c239db2b8c604c76538f08948353ca85a8a524 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 14:31:36 +0200 Subject: [PATCH 26/52] cJSONUtils_PointerEncodedstrcpy -> encode_string_as_pointer --- cJSON_Utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 58a7e64..1278264 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -128,7 +128,7 @@ static size_t pointer_encoded_length(const unsigned char *string) } /* copy a string while escaping '~' and '/' with ~0 and ~1 JSON pointer escape codes */ -static void cJSONUtils_PointerEncodedstrcpy(unsigned char *destination, const unsigned char *source) +static void encode_string_as_pointer(unsigned char *destination, const unsigned char *source) { for (; source[0] != '\0'; (void)source++, destination++) { @@ -192,7 +192,7 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje { unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + pointer_encoded_length((unsigned char*)current_child->string) + 2); full_pointer[0] = '/'; - cJSONUtils_PointerEncodedstrcpy(full_pointer + 1, (unsigned char*)current_child->string); + encode_string_as_pointer(full_pointer + 1, (unsigned char*)current_child->string); strcat((char*)full_pointer, (char*)target_pointer); cJSON_free(target_pointer); @@ -867,7 +867,7 @@ static void cJSONUtils_GeneratePatch(cJSON * const patches, const unsigned char unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/")); sprintf((char*)full_path, "%s/", (const char*)path); - cJSONUtils_PointerEncodedstrcpy(full_path + path_length + 1, suffix); + encode_string_as_pointer(full_path + path_length + 1, suffix); cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)full_path)); free(full_path); @@ -993,7 +993,7 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/")); sprintf((char*)new_path, "%s/", path); - cJSONUtils_PointerEncodedstrcpy(new_path + path_length + 1, (unsigned char*)from_child->string); + encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string); /* create a patch for the element */ cJSONUtils_CompareToPatch(patches, new_path, from_child, to_child); From 7f645de32233d1391e12516d16bff5e631ec88b7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 14:34:14 +0200 Subject: [PATCH 27/52] cJSONUtils_InplaceDecodePointerString -> decode_pointer_inplace --- cJSON_Utils.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 1278264..12f30c5 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -290,7 +290,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *po } /* JSON Patch implementation. */ -static void cJSONUtils_InplaceDecodePointerString(unsigned char *string) +static void decode_pointer_inplace(unsigned char *string) { unsigned char *decoded_string = string; @@ -379,7 +379,7 @@ static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path) child_pointer++; parent = cJSONUtils_GetPointer(object, (char*)parent_pointer); - cJSONUtils_InplaceDecodePointerString(child_pointer); + decode_pointer_inplace(child_pointer); if (cJSON_IsArray(parent)) { @@ -765,7 +765,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, const cJSON *patch) child_pointer++; } parent = cJSONUtils_GetPointer(object, (char*)parent_pointer); - cJSONUtils_InplaceDecodePointerString(child_pointer); + decode_pointer_inplace(child_pointer); /* add, remove, replace, move, copy, test. */ if ((parent == NULL) || (child_pointer == NULL)) From aefe2f85ab16d3914bdc252fe4321e382ee227e7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 14:36:21 +0200 Subject: [PATCH 28/52] cJSONUtils_PatchDetach -> detach_path --- cJSON_Utils.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 12f30c5..1f8caf8 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -356,7 +356,8 @@ static cJSON *detach_item_from_array(cJSON *array, size_t which) return c; } -static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path) +/* detach an item at the given path */ +static cJSON *detach_path(cJSON *object, const unsigned char *path) { unsigned char *parent_pointer = NULL; unsigned char *child_pointer = NULL; @@ -685,7 +686,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, const cJSON *patch) if ((opcode == REMOVE) || (opcode == REPLACE)) { /* Get rid of old. */ - cJSON *old_item = cJSONUtils_PatchDetach(object, (unsigned char*)path->valuestring); + cJSON *old_item = detach_path(object, (unsigned char*)path->valuestring); if (old_item == NULL) { status = 13; @@ -713,7 +714,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, const cJSON *patch) if (opcode == MOVE) { - value = cJSONUtils_PatchDetach(object, (unsigned char*)from->valuestring); + value = detach_path(object, (unsigned char*)from->valuestring); } if (opcode == COPY) { From cf1770b0ea219520a316a97d20c23eafe2038352 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 16:34:39 +0200 Subject: [PATCH 29/52] cJSONUtils_Compare -> compare_json --- cJSON_Utils.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 1f8caf8..0e40dfb 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -410,12 +410,12 @@ cleanup: return detached_item; } -static int cJSONUtils_Compare(cJSON *a, cJSON *b) +static cJSON_bool compare_json(cJSON *a, cJSON *b) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) { /* mismatched type. */ - return -1; + return false; } switch (a->type & 0xFF) { @@ -423,42 +423,42 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b) /* numeric mismatch. */ if ((a->valueint != b->valueint) || (a->valuedouble != b->valuedouble)) { - return -2; + return false; } else { - return 0; + return true; } case cJSON_String: /* string mismatch. */ if (strcmp(a->valuestring, b->valuestring) != 0) { - return -3; + return false; } else { - return 0; + return true; } case cJSON_Array: for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) { - int status = cJSONUtils_Compare(a, b); - if (status != 0) + cJSON_bool identical = compare_json(a, b); + if (!identical) { - return status; + return false; } } /* array size mismatch? (one of both children is not NULL) */ if ((a != NULL) || (b != NULL)) { - return -4; + return false; } else { - return 0; + return true; } case cJSON_Object: @@ -466,28 +466,28 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b) cJSONUtils_SortObject(b); for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) { - int status = 0; + cJSON_bool identical = false; /* compare object keys */ if (case_insensitive_strcmp((unsigned char*)a->string, (unsigned char*)b->string)) { /* missing member */ - return -6; + return false; } - status = cJSONUtils_Compare(a, b); - if (status != 0) + identical = compare_json(a, b); + if (!identical) { - return status; + return false; } } /* object length mismatch (one of both children is not null) */ if ((a != NULL) || (b != NULL)) { - return -5; + return false; } else { - return 0; + return true; } default: @@ -495,7 +495,7 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b) } /* null, true or false */ - return 0; + return true; } /* non broken version of cJSON_InsertItemInArray */ @@ -630,7 +630,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, const cJSON *patch) else if (opcode == TEST) { /* compare value: {...} with the given path */ - status = cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value")); + status = !compare_json(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value")); goto cleanup; } @@ -1242,7 +1242,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * else { /* object key exists in both objects */ - if (cJSONUtils_Compare(from_child, to_child)) + if (!compare_json(from_child, to_child)) { /* not identical --> generate a patch */ cJSON_AddItemToObject(patch, to_child->string, cJSONUtils_GenerateMergePatch(from_child, to_child)); From 997ca129a2d3c5ec1251c6a08b8ee25ea4b94d8b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 16:36:02 +0200 Subject: [PATCH 30/52] cJSONUtils_ApplyPatch -> apply_patch --- cJSON_Utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 0e40dfb..9f526bf 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -603,7 +603,7 @@ static void overwrite_item(cJSON * const root, const cJSON replacement) memcpy(root, &replacement, sizeof(cJSON)); } -static int cJSONUtils_ApplyPatch(cJSON *object, const cJSON *patch) +static int apply_patch(cJSON *object, const cJSON *patch) { cJSON *path = NULL; cJSON *value = NULL; @@ -837,7 +837,7 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * co while (current_patch != NULL) { - status = cJSONUtils_ApplyPatch(object, current_patch); + status = apply_patch(object, current_patch); if (status != 0) { return status; From 1d65f33d3de48839a15a5a16ec6dd561dad90b55 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 16:39:30 +0200 Subject: [PATCH 31/52] cJSONUtils_GeneratePatch -> compose_patch --- cJSON_Utils.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 9f526bf..772f56a 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -848,7 +848,7 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * co return 0; } -static void cJSONUtils_GeneratePatch(cJSON * const patches, const unsigned char * const operation, const unsigned char * const path, const unsigned char *suffix, const cJSON * const value) +static void compose_patch(cJSON * const patches, const unsigned char * const operation, const unsigned char * const path, const unsigned char *suffix, const cJSON * const value) { cJSON *patch = cJSON_CreateObject(); if (patch == NULL) @@ -883,7 +883,7 @@ static void cJSONUtils_GeneratePatch(cJSON * const patches, const unsigned char CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value) { - cJSONUtils_GeneratePatch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value); + compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value); } static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to) @@ -895,7 +895,7 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char if ((from->type & 0xFF) != (to->type & 0xFF)) { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to); + compose_patch(patches, (const unsigned char*)"replace", path, 0, to); return; } @@ -904,14 +904,14 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char case cJSON_Number: if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble)) { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, NULL, to); + compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); } return; case cJSON_String: if (strcmp(from->valuestring, to->valuestring) != 0) { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, NULL, to); + compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); } return; @@ -949,12 +949,12 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char return; } sprintf((char*)new_path, "%lu", (unsigned long)index); - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, new_path, NULL); + compose_patch(patches, (const unsigned char*)"remove", path, new_path, NULL); } /* add new elements in 'to' that were not in 'from' */ for (; (to_child != NULL); (void)(to_child = to_child->next), index++) { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to_child); + compose_patch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to_child); } free(new_path); return; @@ -1006,14 +1006,14 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char else if (diff < 0) { /* object element doesn't exist in 'to' --> remove it */ - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, (unsigned char*)from_child->string, NULL); + compose_patch(patches, (const unsigned char*)"remove", path, (unsigned char*)from_child->string, NULL); from_child = from_child->next; } else { /* object element doesn't exist in 'from' --> add it */ - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (unsigned char*)to_child->string, to_child); + compose_patch(patches, (const unsigned char*)"add", path, (unsigned char*)to_child->string, to_child); to_child = to_child->next; } From a29c468b68e058761853dc53880b01661ccd294c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 16:49:37 +0200 Subject: [PATCH 32/52] cJSON_CompareToPatch -> create_patches --- cJSON_Utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 772f56a..f3dfd78 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -886,7 +886,7 @@ CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value); } -static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to) +static void create_patches(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to) { if ((from == NULL) || (to == NULL)) { @@ -934,7 +934,7 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char return; } sprintf((char*)new_path, "%s/%lu", path, (unsigned long)index); /* path of the current array element */ - cJSONUtils_CompareToPatch(patches, new_path, from_child, to_child); + create_patches(patches, new_path, from_child, to_child); } /* remove leftover elements from 'from' that are not in 'to' */ @@ -997,7 +997,7 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string); /* create a patch for the element */ - cJSONUtils_CompareToPatch(patches, new_path, from_child, to_child); + create_patches(patches, new_path, from_child, to_child); free(new_path); from_child = from_child->next; @@ -1029,7 +1029,7 @@ static void cJSONUtils_CompareToPatch(cJSON * const patches, const unsigned char CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to) { cJSON *patches = cJSON_CreateArray(); - cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to); + create_patches(patches, (const unsigned char*)"", from, to); return patches; } From 23cbb173d4029a1ed8c53d1f3307b403370174a2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 16:53:35 +0200 Subject: [PATCH 33/52] cJSONUtils_SortList -> sort_list --- cJSON_Utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index f3dfd78..29c3d35 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1035,7 +1035,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * con } /* sort lists using mergesort */ -static cJSON *cJSONUtils_SortList(cJSON *list) +static cJSON *sort_list(cJSON *list) { cJSON *first = list; cJSON *second = list; @@ -1080,8 +1080,8 @@ static cJSON *cJSONUtils_SortList(cJSON *list) } /* Recursively sort the sub-lists. */ - first = cJSONUtils_SortList(first); - second = cJSONUtils_SortList(second); + first = sort_list(first); + second = sort_list(second); result = NULL; /* Merge the sub-lists */ @@ -1147,7 +1147,7 @@ static cJSON *cJSONUtils_SortList(cJSON *list) CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object) { - object->child = cJSONUtils_SortList(object->child); + object->child = sort_list(object->child); } CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) From 2616db9e92bfc2e5d7551c178319174a168fc713 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:13:16 +0200 Subject: [PATCH 34/52] Add compare_strings: configurable case_sensitivity --- cJSON_Utils.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 29c3d35..78c9b1d 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -50,8 +50,8 @@ static unsigned char* cJSONUtils_strdup(const unsigned char* const string) return copy; } -/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ -static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +/* string comparison which doesn't consider NULL pointers equal */ +static int compare_strings(const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive) { if ((string1 == NULL) || (string2 == NULL)) { @@ -63,6 +63,11 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned return 0; } + if (case_sensitive) + { + return strcmp((const char*)string1, (const char*)string2); + } + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) { if (*string1 == '\0') @@ -432,7 +437,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b) case cJSON_String: /* string mismatch. */ - if (strcmp(a->valuestring, b->valuestring) != 0) + if (compare_strings((unsigned char*)a->valuestring, (unsigned char*)b->valuestring, true) != 0) { return false; } @@ -468,7 +473,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b) { cJSON_bool identical = false; /* compare object keys */ - if (case_insensitive_strcmp((unsigned char*)a->string, (unsigned char*)b->string)) + if (compare_strings((unsigned char*)a->string, (unsigned char*)b->string, false)) { /* missing member */ return false; @@ -909,7 +914,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa return; case cJSON_String: - if (strcmp(from->valuestring, to->valuestring) != 0) + if (compare_strings((unsigned char*)from->valuestring, (unsigned char*)to->valuestring, true) != 0) { compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); } @@ -983,7 +988,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa } else { - diff = case_insensitive_strcmp((unsigned char*)from_child->string, (unsigned char*)to_child->string); + diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, false); } if (diff == 0) @@ -1049,7 +1054,7 @@ static cJSON *sort_list(cJSON *list) return result; } - while ((current_item != NULL) && (current_item->next != NULL) && (case_insensitive_strcmp((unsigned char*)current_item->string, (unsigned char*)current_item->next->string) < 0)) + while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, false) < 0)) { /* Test for list sorted. */ current_item = current_item->next; @@ -1088,7 +1093,7 @@ static cJSON *sort_list(cJSON *list) while ((first != NULL) && (second != NULL)) { cJSON *smaller = NULL; - if (case_insensitive_strcmp((unsigned char*)first->string, (unsigned char*)second->string) < 0) + if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, false) < 0) { smaller = first; } @@ -1213,7 +1218,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * { if (to_child != NULL) { - diff = strcmp(from_child->string, to_child->string); + diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, true); } else { From 1d854508831ef85bfb85817a1cd9a36a473fef91 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:30:26 +0200 Subject: [PATCH 35/52] fix configurable compare_stirings --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 78c9b1d..bc4734f 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -437,7 +437,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b) case cJSON_String: /* string mismatch. */ - if (compare_strings((unsigned char*)a->valuestring, (unsigned char*)b->valuestring, true) != 0) + if (strcmp(a->valuestring, b->valuestring) != 0) { return false; } From 487a8b76a1036170a9faf2477032eaf288a18869 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:38:05 +0200 Subject: [PATCH 36/52] fix another compare_strings --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index bc4734f..8760433 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -914,7 +914,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa return; case cJSON_String: - if (compare_strings((unsigned char*)from->valuestring, (unsigned char*)to->valuestring, true) != 0) + if (strcmp((unsigned char*)from->valuestring, (unsigned char*)to->valuestring) != 0) { compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); } From eb017abe72a146f5aa486060061df407ef4c125c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:42:16 +0200 Subject: [PATCH 37/52] fix update fix --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 8760433..793aa54 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -914,7 +914,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa return; case cJSON_String: - if (strcmp((unsigned char*)from->valuestring, (unsigned char*)to->valuestring) != 0) + if (strcmp(from->valuestring, to->valuestring) != 0) { compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); } From 30906a01c0b5db2cea69a81004910698b116ed6d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:48:46 +0200 Subject: [PATCH 38/52] another compare_strings fix --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 793aa54..7b79256 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1218,7 +1218,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * { if (to_child != NULL) { - diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, true); + diff = strcmp(from_child->string, to_child->string); } else { From 2f33e8ec9b3aa7bf4dca480ff40b702369302117 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:17:55 +0200 Subject: [PATCH 39/52] Add compare_pointers: Configurable case sensitivity --- cJSON_Utils.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 7b79256..4465db8 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -80,7 +80,7 @@ static int compare_strings(const unsigned char *string1, const unsigned char *st } /* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */ -static cJSON_bool case_insensitive_pointer_comparison(const unsigned char *name, const unsigned char *pointer) +static cJSON_bool compare_pointers(const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive) { if ((name == NULL) || (pointer == NULL)) { @@ -102,7 +102,7 @@ static cJSON_bool case_insensitive_pointer_comparison(const unsigned char *name, pointer++; } } - else if (tolower(*name) != tolower(*pointer)) + else if ((!case_sensitive && (tolower(*name) != tolower(*pointer))) || (case_sensitive && (*name != *pointer))) { return false; } @@ -275,7 +275,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *po { current_element = current_element->child; /* GetObjectItem. */ - while ((current_element != NULL) && !case_insensitive_pointer_comparison((unsigned char*)current_element->string, (const unsigned char*)pointer)) + while ((current_element != NULL) && !compare_pointers((unsigned char*)current_element->string, (const unsigned char*)pointer, false)) { current_element = current_element->next; } From af9c76e37e2a11547e2bf06e1244e1b572408be6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:25:37 +0200 Subject: [PATCH 40/52] Add get_item_from_pointer: Configurable case sensitivity --- cJSON_Utils.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 4465db8..054c799 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -254,7 +254,7 @@ static cJSON_bool decode_array_index_from_pointer(const unsigned char * const po return 1; } -CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer) +static cJSON *get_item_from_pointer(cJSON * const object, const char * pointer, const cJSON_bool case_sensitive) { cJSON *current_element = object; /* follow path of the pointer */ @@ -275,7 +275,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *po { current_element = current_element->child; /* GetObjectItem. */ - while ((current_element != NULL) && !compare_pointers((unsigned char*)current_element->string, (const unsigned char*)pointer, false)) + while ((current_element != NULL) && !compare_pointers((unsigned char*)current_element->string, (const unsigned char*)pointer, case_sensitive)) { current_element = current_element->next; } @@ -294,6 +294,11 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *po return current_element; } +CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer) +{ + return get_item_from_pointer(object, pointer, false); +} + /* JSON Patch implementation. */ static void decode_pointer_inplace(unsigned char *string) { @@ -364,6 +369,7 @@ static cJSON *detach_item_from_array(cJSON *array, size_t which) /* detach an item at the given path */ static cJSON *detach_path(cJSON *object, const unsigned char *path) { + cJSON_bool case_sensitive = false; unsigned char *parent_pointer = NULL; unsigned char *child_pointer = NULL; cJSON *parent = NULL; @@ -384,7 +390,7 @@ static cJSON *detach_path(cJSON *object, const unsigned char *path) child_pointer[0] = '\0'; child_pointer++; - parent = cJSONUtils_GetPointer(object, (char*)parent_pointer); + parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive); decode_pointer_inplace(child_pointer); if (cJSON_IsArray(parent)) @@ -610,6 +616,7 @@ static void overwrite_item(cJSON * const root, const cJSON replacement) static int apply_patch(cJSON *object, const cJSON *patch) { + cJSON_bool case_sensitive = false; cJSON *path = NULL; cJSON *value = NULL; cJSON *parent = NULL; @@ -635,7 +642,7 @@ static int apply_patch(cJSON *object, const cJSON *patch) else if (opcode == TEST) { /* compare value: {...} with the given path */ - status = !compare_json(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value")); + status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), cJSON_GetObjectItem(patch, "value")); goto cleanup; } @@ -723,7 +730,7 @@ static int apply_patch(cJSON *object, const cJSON *patch) } if (opcode == COPY) { - value = cJSONUtils_GetPointer(object, from->valuestring); + value = get_item_from_pointer(object, from->valuestring, case_sensitive); } if (value == NULL) { @@ -770,7 +777,7 @@ static int apply_patch(cJSON *object, const cJSON *patch) child_pointer[0] = '\0'; child_pointer++; } - parent = cJSONUtils_GetPointer(object, (char*)parent_pointer); + parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive); decode_pointer_inplace(child_pointer); /* add, remove, replace, move, copy, test. */ From 7de847eeeab7e31b536525f18f5ec707fdb46d7b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:28:20 +0200 Subject: [PATCH 41/52] detach_path: Configurable case sensitivity --- cJSON_Utils.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 054c799..38540a1 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -367,9 +367,8 @@ static cJSON *detach_item_from_array(cJSON *array, size_t which) } /* detach an item at the given path */ -static cJSON *detach_path(cJSON *object, const unsigned char *path) +static cJSON *detach_path(cJSON *object, const unsigned char *path, const cJSON_bool case_sensitive) { - cJSON_bool case_sensitive = false; unsigned char *parent_pointer = NULL; unsigned char *child_pointer = NULL; cJSON *parent = NULL; @@ -698,7 +697,7 @@ static int apply_patch(cJSON *object, const cJSON *patch) if ((opcode == REMOVE) || (opcode == REPLACE)) { /* Get rid of old. */ - cJSON *old_item = detach_path(object, (unsigned char*)path->valuestring); + cJSON *old_item = detach_path(object, (unsigned char*)path->valuestring, case_sensitive); if (old_item == NULL) { status = 13; @@ -726,7 +725,7 @@ static int apply_patch(cJSON *object, const cJSON *patch) if (opcode == MOVE) { - value = detach_path(object, (unsigned char*)from->valuestring); + value = detach_path(object, (unsigned char*)from->valuestring, case_sensitive); } if (opcode == COPY) { From 62b08f1336a3cd7566b19b4898945a8fa91de48d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:32:37 +0200 Subject: [PATCH 42/52] compare_json: configurable case sensitivity --- cJSON_Utils.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 38540a1..7b4d8f3 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -420,7 +420,7 @@ cleanup: return detached_item; } -static cJSON_bool compare_json(cJSON *a, cJSON *b) +static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) { @@ -454,7 +454,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b) case cJSON_Array: for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) { - cJSON_bool identical = compare_json(a, b); + cJSON_bool identical = compare_json(a, b, case_sensitive); if (!identical) { return false; @@ -478,12 +478,12 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b) { cJSON_bool identical = false; /* compare object keys */ - if (compare_strings((unsigned char*)a->string, (unsigned char*)b->string, false)) + if (compare_strings((unsigned char*)a->string, (unsigned char*)b->string, case_sensitive)) { /* missing member */ return false; } - identical = compare_json(a, b); + identical = compare_json(a, b, case_sensitive); if (!identical) { return false; @@ -641,7 +641,7 @@ static int apply_patch(cJSON *object, const cJSON *patch) else if (opcode == TEST) { /* compare value: {...} with the given path */ - status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), cJSON_GetObjectItem(patch, "value")); + status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), cJSON_GetObjectItem(patch, "value"), case_sensitive); goto cleanup; } @@ -1198,6 +1198,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const p CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to) { + cJSON_bool case_sensitive = false; cJSON *from_child = NULL; cJSON *to_child = NULL; cJSON *patch = NULL; @@ -1253,7 +1254,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * else { /* object key exists in both objects */ - if (!compare_json(from_child, to_child)) + if (!compare_json(from_child, to_child, case_sensitive)) { /* not identical --> generate a patch */ cJSON_AddItemToObject(patch, to_child->string, cJSONUtils_GenerateMergePatch(from_child, to_child)); From 222686513e3201902b7ef0f73917ee7a18803d06 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:36:51 +0200 Subject: [PATCH 43/52] apply_patch: configurable case sensitivity --- cJSON_Utils.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 7b4d8f3..50370ec 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -613,9 +613,8 @@ static void overwrite_item(cJSON * const root, const cJSON replacement) memcpy(root, &replacement, sizeof(cJSON)); } -static int apply_patch(cJSON *object, const cJSON *patch) +static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_sensitive) { - cJSON_bool case_sensitive = false; cJSON *path = NULL; cJSON *value = NULL; cJSON *parent = NULL; @@ -848,7 +847,7 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * co while (current_patch != NULL) { - status = apply_patch(object, current_patch); + status = apply_patch(object, current_patch, false); if (status != 0) { return status; From e88be8681de10b66695dc8ce6afb510f312e0944 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:40:27 +0200 Subject: [PATCH 44/52] create_patches: Configurable case sensitivity --- cJSON_Utils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 50370ec..c07167d 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -896,7 +896,7 @@ CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value); } -static void create_patches(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to) +static void create_patches(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive) { if ((from == NULL) || (to == NULL)) { @@ -944,7 +944,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa return; } sprintf((char*)new_path, "%s/%lu", path, (unsigned long)index); /* path of the current array element */ - create_patches(patches, new_path, from_child, to_child); + create_patches(patches, new_path, from_child, to_child, case_sensitive); } /* remove leftover elements from 'from' that are not in 'to' */ @@ -993,7 +993,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa } else { - diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, false); + diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, case_sensitive); } if (diff == 0) @@ -1007,7 +1007,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string); /* create a patch for the element */ - create_patches(patches, new_path, from_child, to_child); + create_patches(patches, new_path, from_child, to_child, case_sensitive); free(new_path); from_child = from_child->next; @@ -1039,7 +1039,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to) { cJSON *patches = cJSON_CreateArray(); - create_patches(patches, (const unsigned char*)"", from, to); + create_patches(patches, (const unsigned char*)"", from, to, false); return patches; } From 0aaef1a8fadec0dfeb7fd5f070382a0398506784 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:44:55 +0200 Subject: [PATCH 45/52] sort_list: configurable case sensitivity --- cJSON_Utils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index c07167d..48aeb07 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1045,7 +1045,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * con } /* sort lists using mergesort */ -static cJSON *sort_list(cJSON *list) +static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) { cJSON *first = list; cJSON *second = list; @@ -1059,7 +1059,7 @@ static cJSON *sort_list(cJSON *list) return result; } - while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, false) < 0)) + while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0)) { /* Test for list sorted. */ current_item = current_item->next; @@ -1090,8 +1090,8 @@ static cJSON *sort_list(cJSON *list) } /* Recursively sort the sub-lists. */ - first = sort_list(first); - second = sort_list(second); + first = sort_list(first, case_sensitive); + second = sort_list(second, case_sensitive); result = NULL; /* Merge the sub-lists */ @@ -1157,7 +1157,7 @@ static cJSON *sort_list(cJSON *list) CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object) { - object->child = sort_list(object->child); + object->child = sort_list(object->child, false); } CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) From 73823c4b6d592550822bd0eee18826b4b2a068ed Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:55:44 +0200 Subject: [PATCH 46/52] Add get_object_item: configurable case_sensitivity --- cJSON_Utils.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 48aeb07..50950ec 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -546,11 +546,21 @@ static cJSON_bool insert_item_in_array(cJSON *array, size_t which, cJSON *newite return 1; } +static cJSON *get_object_item(const cJSON * const object, const char* name, const cJSON_bool case_sensitive) +{ + if (case_sensitive) + { + return cJSON_GetObjectItemCaseSensitive(object, name); + } + + return cJSON_GetObjectItem(object, name); +} + enum patch_operation { INVALID, ADD, REMOVE, REPLACE, MOVE, COPY, TEST }; -static enum patch_operation decode_patch_operation(const cJSON * const patch) +static enum patch_operation decode_patch_operation(const cJSON * const patch, const cJSON_bool case_sensitive) { - cJSON *operation = cJSON_GetObjectItem(patch, "op"); + cJSON *operation = get_object_item(patch, "op", case_sensitive); if (!cJSON_IsString(operation)) { return INVALID; @@ -623,7 +633,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ unsigned char *child_pointer = NULL; int status = 0; - path = cJSON_GetObjectItem(patch, "path"); + path = get_object_item(patch, "path", case_sensitive); if (!cJSON_IsString(path)) { /* malformed patch. */ @@ -631,7 +641,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ goto cleanup; } - opcode = decode_patch_operation(patch); + opcode = decode_patch_operation(patch, case_sensitive); if (opcode == INVALID) { status = 3; @@ -640,7 +650,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ else if (opcode == TEST) { /* compare value: {...} with the given path */ - status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), cJSON_GetObjectItem(patch, "value"), case_sensitive); + status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), get_object_item(patch, "value", case_sensitive), case_sensitive); goto cleanup; } @@ -659,7 +669,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ if ((opcode == REPLACE) || (opcode == ADD)) { - value = cJSON_GetObjectItem(patch, "value"); + value = get_object_item(patch, "value", case_sensitive); if (value == NULL) { /* missing "value" for add/replace. */ @@ -714,7 +724,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ /* Copy/Move uses "from". */ if ((opcode == MOVE) || (opcode == COPY)) { - cJSON *from = cJSON_GetObjectItem(patch, "from"); + cJSON *from = get_object_item(patch, "from", case_sensitive); if (from == NULL) { /* missing "from" for copy/move. */ @@ -749,7 +759,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ } else /* Add/Replace uses "value". */ { - value = cJSON_GetObjectItem(patch, "value"); + value = get_object_item(patch, "value", case_sensitive); if (value == NULL) { /* missing "value" for add/replace. */ From cd4d7b9b6e9fe45fd984f300989758a4ca2786db Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:58:00 +0200 Subject: [PATCH 47/52] Add cJSONUtils_GetPointerCaseSensitive --- cJSON_Utils.c | 5 +++++ cJSON_Utils.h | 1 + 2 files changed, 6 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 50950ec..b4dacf3 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -299,6 +299,11 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *po return get_item_from_pointer(object, pointer, false); } +CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer) +{ + return get_item_from_pointer(object, pointer, true); +} + /* JSON Patch implementation. */ static void decode_pointer_inplace(unsigned char *string) { diff --git a/cJSON_Utils.h b/cJSON_Utils.h index b20e5db..4ff21f8 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -24,6 +24,7 @@ /* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer); +CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer); /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ /* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */ From 3bf2913634979c93527ef84427d0e2e546d12e57 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 19:59:05 +0200 Subject: [PATCH 48/52] Add cJSONUtils_GeneratePatchesCaseSensitive --- cJSON_Utils.c | 8 ++++++++ cJSON_Utils.h | 1 + 2 files changed, 9 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index b4dacf3..22794df 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1059,6 +1059,14 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * con return patches; } +CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to) +{ + cJSON *patches = cJSON_CreateArray(); + create_patches(patches, (const unsigned char*)"", from, to, true); + + return patches; +} + /* sort lists using mergesort */ static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) { diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 4ff21f8..e61bb61 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -29,6 +29,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, c /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ /* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to); +CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to); /* Utility for generating patch array entries. */ CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value); /* Returns 0 for success. */ From 94057fb0692999834cc34225316dafb8ee9b9cf5 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 20:01:56 +0200 Subject: [PATCH 49/52] Add cJSONUtils_ApplyPatchesCaseSensitive --- cJSON_Utils.c | 29 +++++++++++++++++++++++++++++ cJSON_Utils.h | 1 + 2 files changed, 30 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 22794df..2ff4c9d 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -873,6 +873,35 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * co return 0; } +CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches) +{ + const cJSON *current_patch = NULL; + int status = 0; + + if (!cJSON_IsArray(patches)) + { + /* malformed patches. */ + return 1; + } + + if (patches != NULL) + { + current_patch = patches->child; + } + + while (current_patch != NULL) + { + status = apply_patch(object, current_patch, true); + if (status != 0) + { + return status; + } + current_patch = current_patch->next; + } + + return 0; +} + static void compose_patch(cJSON * const patches, const unsigned char * const operation, const unsigned char * const path, const unsigned char *suffix, const cJSON * const value) { cJSON *patch = cJSON_CreateObject(); diff --git a/cJSON_Utils.h b/cJSON_Utils.h index e61bb61..7cd06af 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -34,6 +34,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value); /* Returns 0 for success. */ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches); +CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches); /* // Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use: From b674519695997ec55917ad8ed969ce26c606f44d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 20:04:44 +0200 Subject: [PATCH 50/52] Add cJSONUtils_GenerateMergePatchCaseSensitive --- cJSON_Utils.c | 13 +++++++++++-- cJSON_Utils.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 2ff4c9d..3552af7 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1247,9 +1247,8 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const p return target; } -CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to) +static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive) { - cJSON_bool case_sensitive = false; cJSON *from_child = NULL; cJSON *to_child = NULL; cJSON *patch = NULL; @@ -1325,3 +1324,13 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * return patch; } + +CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to) +{ + return generate_merge_patch(from, to, false); +} + +CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to) +{ + return generate_merge_patch(from, to, true); +} diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 7cd06af..d826818 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -63,6 +63,7 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const p /* generates a patch to move from -> to */ /* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to); +CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to); /* Given a root object and a target object, construct a pointer from one to the other. */ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target); From 7f22948eecf91e839e973a207a46cc7276eeca0b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 30 Apr 2017 20:09:54 +0200 Subject: [PATCH 51/52] Add cJSONUtils_SortObjectCaseSensitive --- cJSON_Utils.c | 246 ++++++++++++++++++++++++++------------------------ cJSON_Utils.h | 1 + 2 files changed, 129 insertions(+), 118 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 3552af7..8c5cddd 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -425,6 +425,122 @@ cleanup: return detached_item; } +/* sort lists using mergesort */ +static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) +{ + cJSON *first = list; + cJSON *second = list; + cJSON *current_item = list; + cJSON *result = list; + cJSON *result_tail = NULL; + + if ((list == NULL) || (list->next == NULL)) + { + /* One entry is sorted already. */ + return result; + } + + while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0)) + { + /* Test for list sorted. */ + current_item = current_item->next; + } + if ((current_item == NULL) || (current_item->next == NULL)) + { + /* Leave sorted lists unmodified. */ + return result; + } + + /* reset pointer to the beginning */ + current_item = list; + while (current_item != NULL) + { + /* Walk two pointers to find the middle. */ + second = second->next; + current_item = current_item->next; + /* advances current_item two steps at a time */ + if (current_item != NULL) + { + current_item = current_item->next; + } + } + if ((second != NULL) && (second->prev != NULL)) + { + /* Split the lists */ + second->prev->next = NULL; + } + + /* Recursively sort the sub-lists. */ + first = sort_list(first, case_sensitive); + second = sort_list(second, case_sensitive); + result = NULL; + + /* Merge the sub-lists */ + while ((first != NULL) && (second != NULL)) + { + cJSON *smaller = NULL; + if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, false) < 0) + { + smaller = first; + } + else + { + smaller = second; + } + + if (result == NULL) + { + /* start merged list with the smaller element */ + result_tail = smaller; + result = smaller; + } + else + { + /* add smaller element to the list */ + result_tail->next = smaller; + smaller->prev = result_tail; + result_tail = smaller; + } + + if (first == smaller) + { + first = first->next; + } + else + { + second = second->next; + } + } + + if (first != NULL) + { + /* Append rest of first list. */ + if (result == NULL) + { + return first; + } + result_tail->next = first; + first->prev = result_tail; + } + if (second != NULL) + { + /* Append rest of second list */ + if (result == NULL) + { + return second; + } + result_tail->next = second; + second->prev = result_tail; + } + + return result; +} + +static void sort_object(cJSON * const object, const cJSON_bool case_sensitive) +{ + object->child = sort_list(object->child, case_sensitive); +} + static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) @@ -477,8 +593,8 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensiti } case cJSON_Object: - cJSONUtils_SortObject(a); - cJSONUtils_SortObject(b); + sort_object(a, case_sensitive); + sort_object(b, case_sensitive); for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) { cJSON_bool identical = false; @@ -1018,8 +1134,8 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa { cJSON *from_child = NULL; cJSON *to_child = NULL; - cJSONUtils_SortObject(from); - cJSONUtils_SortObject(to); + sort_object(from, case_sensitive); + sort_object(to, case_sensitive); from_child = from->child; to_child = to->child; @@ -1096,120 +1212,14 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from return patches; } -/* sort lists using mergesort */ -static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) -{ - cJSON *first = list; - cJSON *second = list; - cJSON *current_item = list; - cJSON *result = list; - cJSON *result_tail = NULL; - - if ((list == NULL) || (list->next == NULL)) - { - /* One entry is sorted already. */ - return result; - } - - while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0)) - { - /* Test for list sorted. */ - current_item = current_item->next; - } - if ((current_item == NULL) || (current_item->next == NULL)) - { - /* Leave sorted lists unmodified. */ - return result; - } - - /* reset pointer to the beginning */ - current_item = list; - while (current_item != NULL) - { - /* Walk two pointers to find the middle. */ - second = second->next; - current_item = current_item->next; - /* advances current_item two steps at a time */ - if (current_item != NULL) - { - current_item = current_item->next; - } - } - if ((second != NULL) && (second->prev != NULL)) - { - /* Split the lists */ - second->prev->next = NULL; - } - - /* Recursively sort the sub-lists. */ - first = sort_list(first, case_sensitive); - second = sort_list(second, case_sensitive); - result = NULL; - - /* Merge the sub-lists */ - while ((first != NULL) && (second != NULL)) - { - cJSON *smaller = NULL; - if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, false) < 0) - { - smaller = first; - } - else - { - smaller = second; - } - - if (result == NULL) - { - /* start merged list with the smaller element */ - result_tail = smaller; - result = smaller; - } - else - { - /* add smaller element to the list */ - result_tail->next = smaller; - smaller->prev = result_tail; - result_tail = smaller; - } - - if (first == smaller) - { - first = first->next; - } - else - { - second = second->next; - } - } - - if (first != NULL) - { - /* Append rest of first list. */ - if (result == NULL) - { - return first; - } - result_tail->next = first; - first->prev = result_tail; - } - if (second != NULL) - { - /* Append rest of second list */ - if (result == NULL) - { - return second; - } - result_tail->next = second; - second->prev = result_tail; - } - - return result; -} - CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object) { - object->child = sort_list(object->child, false); + sort_object(object, false); +} + +CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object) +{ + sort_object(object, true); } CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) @@ -1262,8 +1272,8 @@ static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const c return cJSON_Duplicate(to, 1); } - cJSONUtils_SortObject(from); - cJSONUtils_SortObject(to); + sort_object(from, case_sensitive); + sort_object(to, case_sensitive); from_child = from->child; to_child = to->child; diff --git a/cJSON_Utils.h b/cJSON_Utils.h index d826818..3ecc1e9 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -70,3 +70,4 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje /* Sorts the members of the object into alphabetical order. */ CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object); +CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object); From 66f75619d9c073523b36c77100a86f9889bce4e7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 1 May 2017 22:41:19 +0200 Subject: [PATCH 52/52] Add cJSONUtils_MergePatchCaseSensitive --- cJSON_Utils.c | 42 ++++++++++++++++++++++++++++++++++++++---- cJSON_Utils.h | 1 + 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 8c5cddd..5d61c76 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1222,7 +1222,7 @@ CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object) sort_object(object, true); } -CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) +static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_bool case_sensitive) { cJSON *patch_child = NULL; @@ -1245,18 +1245,52 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const p if (cJSON_IsNull(patch_child)) { /* NULL is the indicator to remove a value, see RFC7396 */ - cJSON_DeleteItemFromObject(target, patch_child->string); + if (case_sensitive) + { + cJSON_DeleteItemFromObjectCaseSensitive(target, patch_child->string); + } + else + { + cJSON_DeleteItemFromObject(target, patch_child->string); + } } else { - cJSON *replace_me = cJSON_DetachItemFromObject(target, patch_child->string); - cJSON_AddItemToObject(target, patch_child->string, cJSONUtils_MergePatch(replace_me, patch_child)); + cJSON *replace_me = NULL; + cJSON *replacement = NULL; + + if (case_sensitive) + { + replace_me = cJSON_DetachItemFromObjectCaseSensitive(target, patch_child->string); + } + else + { + replace_me = cJSON_DetachItemFromObject(target, patch_child->string); + } + + replacement = merge_patch(replace_me, patch_child, case_sensitive); + if (replacement == NULL) + { + return NULL; + } + + cJSON_AddItemToObject(target, patch_child->string, replacement); } patch_child = patch_child->next; } return target; } +CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) +{ + return merge_patch(target, patch, false); +} + +CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch) +{ + return merge_patch(target, patch, true); +} + static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive) { cJSON *from_child = NULL; diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 3ecc1e9..03ec10c 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -60,6 +60,7 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, con /* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */ /* target will be modified by patch. return value is new ptr for target. */ CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch); +CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch); /* generates a patch to move from -> to */ /* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */ CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);