19750e409Sopenharmony_ci/* 29750e409Sopenharmony_ci Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 39750e409Sopenharmony_ci 49750e409Sopenharmony_ci Permission is hereby granted, free of charge, to any person obtaining a copy 59750e409Sopenharmony_ci of this software and associated documentation files (the "Software"), to deal 69750e409Sopenharmony_ci in the Software without restriction, including without limitation the rights 79750e409Sopenharmony_ci to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 89750e409Sopenharmony_ci copies of the Software, and to permit persons to whom the Software is 99750e409Sopenharmony_ci furnished to do so, subject to the following conditions: 109750e409Sopenharmony_ci 119750e409Sopenharmony_ci The above copyright notice and this permission notice shall be included in 129750e409Sopenharmony_ci all copies or substantial portions of the Software. 139750e409Sopenharmony_ci 149750e409Sopenharmony_ci THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 159750e409Sopenharmony_ci IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 169750e409Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 179750e409Sopenharmony_ci AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 189750e409Sopenharmony_ci LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 199750e409Sopenharmony_ci OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 209750e409Sopenharmony_ci THE SOFTWARE. 219750e409Sopenharmony_ci*/ 229750e409Sopenharmony_ci 239750e409Sopenharmony_ci/* disable warnings about old C89 functions in MSVC */ 249750e409Sopenharmony_ci#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) 259750e409Sopenharmony_ci#define _CRT_SECURE_NO_DEPRECATE 269750e409Sopenharmony_ci#endif 279750e409Sopenharmony_ci 289750e409Sopenharmony_ci#ifdef __GNUCC__ 299750e409Sopenharmony_ci#pragma GCC visibility push(default) 309750e409Sopenharmony_ci#endif 319750e409Sopenharmony_ci#if defined(_MSC_VER) 329750e409Sopenharmony_ci#pragma warning (push) 339750e409Sopenharmony_ci/* disable warning about single line comments in system headers */ 349750e409Sopenharmony_ci#pragma warning (disable : 4001) 359750e409Sopenharmony_ci#endif 369750e409Sopenharmony_ci 379750e409Sopenharmony_ci#include <ctype.h> 389750e409Sopenharmony_ci#include <string.h> 399750e409Sopenharmony_ci#include <stdlib.h> 409750e409Sopenharmony_ci#include <stdio.h> 419750e409Sopenharmony_ci#include <limits.h> 429750e409Sopenharmony_ci#include <math.h> 439750e409Sopenharmony_ci#include <float.h> 449750e409Sopenharmony_ci#include <math.h> 459750e409Sopenharmony_ci 469750e409Sopenharmony_ci#if defined(_MSC_VER) 479750e409Sopenharmony_ci#pragma warning (pop) 489750e409Sopenharmony_ci#endif 499750e409Sopenharmony_ci#ifdef __GNUCC__ 509750e409Sopenharmony_ci#pragma GCC visibility pop 519750e409Sopenharmony_ci#endif 529750e409Sopenharmony_ci 539750e409Sopenharmony_ci#include "cJSON_Utils.h" 549750e409Sopenharmony_ci 559750e409Sopenharmony_ci/* define our own boolean type */ 569750e409Sopenharmony_ci#ifdef true 579750e409Sopenharmony_ci#undef true 589750e409Sopenharmony_ci#endif 599750e409Sopenharmony_ci#define true ((cJSON_bool)1) 609750e409Sopenharmony_ci 619750e409Sopenharmony_ci#ifdef false 629750e409Sopenharmony_ci#undef false 639750e409Sopenharmony_ci#endif 649750e409Sopenharmony_ci#define false ((cJSON_bool)0) 659750e409Sopenharmony_ci 669750e409Sopenharmony_cistatic unsigned char* cJSONUtils_strdup(const unsigned char* const string) 679750e409Sopenharmony_ci{ 689750e409Sopenharmony_ci size_t length = 0; 699750e409Sopenharmony_ci unsigned char *copy = NULL; 709750e409Sopenharmony_ci 719750e409Sopenharmony_ci length = strlen((const char*)string) + sizeof(""); 729750e409Sopenharmony_ci copy = (unsigned char*) cJSON_malloc(length); 739750e409Sopenharmony_ci if (copy == NULL) 749750e409Sopenharmony_ci { 759750e409Sopenharmony_ci return NULL; 769750e409Sopenharmony_ci } 779750e409Sopenharmony_ci memcpy(copy, string, length); 789750e409Sopenharmony_ci 799750e409Sopenharmony_ci return copy; 809750e409Sopenharmony_ci} 819750e409Sopenharmony_ci 829750e409Sopenharmony_ci/* string comparison which doesn't consider NULL pointers equal */ 839750e409Sopenharmony_cistatic int compare_strings(const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive) 849750e409Sopenharmony_ci{ 859750e409Sopenharmony_ci if ((string1 == NULL) || (string2 == NULL)) 869750e409Sopenharmony_ci { 879750e409Sopenharmony_ci return 1; 889750e409Sopenharmony_ci } 899750e409Sopenharmony_ci 909750e409Sopenharmony_ci if (string1 == string2) 919750e409Sopenharmony_ci { 929750e409Sopenharmony_ci return 0; 939750e409Sopenharmony_ci } 949750e409Sopenharmony_ci 959750e409Sopenharmony_ci if (case_sensitive) 969750e409Sopenharmony_ci { 979750e409Sopenharmony_ci return strcmp((const char*)string1, (const char*)string2); 989750e409Sopenharmony_ci } 999750e409Sopenharmony_ci 1009750e409Sopenharmony_ci for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) 1019750e409Sopenharmony_ci { 1029750e409Sopenharmony_ci if (*string1 == '\0') 1039750e409Sopenharmony_ci { 1049750e409Sopenharmony_ci return 0; 1059750e409Sopenharmony_ci } 1069750e409Sopenharmony_ci } 1079750e409Sopenharmony_ci 1089750e409Sopenharmony_ci return tolower(*string1) - tolower(*string2); 1099750e409Sopenharmony_ci} 1109750e409Sopenharmony_ci 1119750e409Sopenharmony_ci/* securely comparison of floating-point variables */ 1129750e409Sopenharmony_cistatic cJSON_bool compare_double(double a, double b) 1139750e409Sopenharmony_ci{ 1149750e409Sopenharmony_ci double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); 1159750e409Sopenharmony_ci return (fabs(a - b) <= maxVal * DBL_EPSILON); 1169750e409Sopenharmony_ci} 1179750e409Sopenharmony_ci 1189750e409Sopenharmony_ci 1199750e409Sopenharmony_ci/* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */ 1209750e409Sopenharmony_cistatic cJSON_bool compare_pointers(const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive) 1219750e409Sopenharmony_ci{ 1229750e409Sopenharmony_ci if ((name == NULL) || (pointer == NULL)) 1239750e409Sopenharmony_ci { 1249750e409Sopenharmony_ci return false; 1259750e409Sopenharmony_ci } 1269750e409Sopenharmony_ci 1279750e409Sopenharmony_ci for (; (*name != '\0') && (*pointer != '\0') && (*pointer != '/'); (void)name++, pointer++) /* compare until next '/' */ 1289750e409Sopenharmony_ci { 1299750e409Sopenharmony_ci if (*pointer == '~') 1309750e409Sopenharmony_ci { 1319750e409Sopenharmony_ci /* check for escaped '~' (~0) and '/' (~1) */ 1329750e409Sopenharmony_ci if (((pointer[1] != '0') || (*name != '~')) && ((pointer[1] != '1') || (*name != '/'))) 1339750e409Sopenharmony_ci { 1349750e409Sopenharmony_ci /* invalid escape sequence or wrong character in *name */ 1359750e409Sopenharmony_ci return false; 1369750e409Sopenharmony_ci } 1379750e409Sopenharmony_ci else 1389750e409Sopenharmony_ci { 1399750e409Sopenharmony_ci pointer++; 1409750e409Sopenharmony_ci } 1419750e409Sopenharmony_ci } 1429750e409Sopenharmony_ci else if ((!case_sensitive && (tolower(*name) != tolower(*pointer))) || (case_sensitive && (*name != *pointer))) 1439750e409Sopenharmony_ci { 1449750e409Sopenharmony_ci return false; 1459750e409Sopenharmony_ci } 1469750e409Sopenharmony_ci } 1479750e409Sopenharmony_ci if (((*pointer != 0) && (*pointer != '/')) != (*name != 0)) 1489750e409Sopenharmony_ci { 1499750e409Sopenharmony_ci /* one string has ended, the other not */ 1509750e409Sopenharmony_ci return false;; 1519750e409Sopenharmony_ci } 1529750e409Sopenharmony_ci 1539750e409Sopenharmony_ci return true; 1549750e409Sopenharmony_ci} 1559750e409Sopenharmony_ci 1569750e409Sopenharmony_ci/* calculate the length of a string if encoded as JSON pointer with ~0 and ~1 escape sequences */ 1579750e409Sopenharmony_cistatic size_t pointer_encoded_length(const unsigned char *string) 1589750e409Sopenharmony_ci{ 1599750e409Sopenharmony_ci size_t length; 1609750e409Sopenharmony_ci for (length = 0; *string != '\0'; (void)string++, length++) 1619750e409Sopenharmony_ci { 1629750e409Sopenharmony_ci /* character needs to be escaped? */ 1639750e409Sopenharmony_ci if ((*string == '~') || (*string == '/')) 1649750e409Sopenharmony_ci { 1659750e409Sopenharmony_ci length++; 1669750e409Sopenharmony_ci } 1679750e409Sopenharmony_ci } 1689750e409Sopenharmony_ci 1699750e409Sopenharmony_ci return length; 1709750e409Sopenharmony_ci} 1719750e409Sopenharmony_ci 1729750e409Sopenharmony_ci/* copy a string while escaping '~' and '/' with ~0 and ~1 JSON pointer escape codes */ 1739750e409Sopenharmony_cistatic void encode_string_as_pointer(unsigned char *destination, const unsigned char *source) 1749750e409Sopenharmony_ci{ 1759750e409Sopenharmony_ci for (; source[0] != '\0'; (void)source++, destination++) 1769750e409Sopenharmony_ci { 1779750e409Sopenharmony_ci if (source[0] == '/') 1789750e409Sopenharmony_ci { 1799750e409Sopenharmony_ci destination[0] = '~'; 1809750e409Sopenharmony_ci destination[1] = '1'; 1819750e409Sopenharmony_ci destination++; 1829750e409Sopenharmony_ci } 1839750e409Sopenharmony_ci else if (source[0] == '~') 1849750e409Sopenharmony_ci { 1859750e409Sopenharmony_ci destination[0] = '~'; 1869750e409Sopenharmony_ci destination[1] = '0'; 1879750e409Sopenharmony_ci destination++; 1889750e409Sopenharmony_ci } 1899750e409Sopenharmony_ci else 1909750e409Sopenharmony_ci { 1919750e409Sopenharmony_ci destination[0] = source[0]; 1929750e409Sopenharmony_ci } 1939750e409Sopenharmony_ci } 1949750e409Sopenharmony_ci 1959750e409Sopenharmony_ci destination[0] = '\0'; 1969750e409Sopenharmony_ci} 1979750e409Sopenharmony_ci 1989750e409Sopenharmony_ciCJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target) 1999750e409Sopenharmony_ci{ 2009750e409Sopenharmony_ci size_t child_index = 0; 2019750e409Sopenharmony_ci cJSON *current_child = 0; 2029750e409Sopenharmony_ci 2039750e409Sopenharmony_ci if ((object == NULL) || (target == NULL)) 2049750e409Sopenharmony_ci { 2059750e409Sopenharmony_ci return NULL; 2069750e409Sopenharmony_ci } 2079750e409Sopenharmony_ci 2089750e409Sopenharmony_ci if (object == target) 2099750e409Sopenharmony_ci { 2109750e409Sopenharmony_ci /* found */ 2119750e409Sopenharmony_ci return (char*)cJSONUtils_strdup((const unsigned char*)""); 2129750e409Sopenharmony_ci } 2139750e409Sopenharmony_ci 2149750e409Sopenharmony_ci /* recursively search all children of the object or array */ 2159750e409Sopenharmony_ci for (current_child = object->child; current_child != NULL; (void)(current_child = current_child->next), child_index++) 2169750e409Sopenharmony_ci { 2179750e409Sopenharmony_ci unsigned char *target_pointer = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(current_child, target); 2189750e409Sopenharmony_ci /* found the target? */ 2199750e409Sopenharmony_ci if (target_pointer != NULL) 2209750e409Sopenharmony_ci { 2219750e409Sopenharmony_ci if (cJSON_IsArray(object)) 2229750e409Sopenharmony_ci { 2239750e409Sopenharmony_ci /* reserve enough memory for a 64 bit integer + '/' and '\0' */ 2249750e409Sopenharmony_ci unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + 20 + sizeof("/")); 2259750e409Sopenharmony_ci /* check if conversion to unsigned long is valid 2269750e409Sopenharmony_ci * This should be eliminated at compile time by dead code elimination 2279750e409Sopenharmony_ci * if size_t is an alias of unsigned long, or if it is bigger */ 2289750e409Sopenharmony_ci if (child_index > ULONG_MAX) 2299750e409Sopenharmony_ci { 2309750e409Sopenharmony_ci cJSON_free(target_pointer); 2319750e409Sopenharmony_ci cJSON_free(full_pointer); 2329750e409Sopenharmony_ci return NULL; 2339750e409Sopenharmony_ci } 2349750e409Sopenharmony_ci sprintf((char*)full_pointer, "/%lu%s", (unsigned long)child_index, target_pointer); /* /<array_index><path> */ 2359750e409Sopenharmony_ci cJSON_free(target_pointer); 2369750e409Sopenharmony_ci 2379750e409Sopenharmony_ci return (char*)full_pointer; 2389750e409Sopenharmony_ci } 2399750e409Sopenharmony_ci 2409750e409Sopenharmony_ci if (cJSON_IsObject(object)) 2419750e409Sopenharmony_ci { 2429750e409Sopenharmony_ci unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + pointer_encoded_length((unsigned char*)current_child->string) + 2); 2439750e409Sopenharmony_ci full_pointer[0] = '/'; 2449750e409Sopenharmony_ci encode_string_as_pointer(full_pointer + 1, (unsigned char*)current_child->string); 2459750e409Sopenharmony_ci strcat((char*)full_pointer, (char*)target_pointer); 2469750e409Sopenharmony_ci cJSON_free(target_pointer); 2479750e409Sopenharmony_ci 2489750e409Sopenharmony_ci return (char*)full_pointer; 2499750e409Sopenharmony_ci } 2509750e409Sopenharmony_ci 2519750e409Sopenharmony_ci /* reached leaf of the tree, found nothing */ 2529750e409Sopenharmony_ci cJSON_free(target_pointer); 2539750e409Sopenharmony_ci return NULL; 2549750e409Sopenharmony_ci } 2559750e409Sopenharmony_ci } 2569750e409Sopenharmony_ci 2579750e409Sopenharmony_ci /* not found */ 2589750e409Sopenharmony_ci return NULL; 2599750e409Sopenharmony_ci} 2609750e409Sopenharmony_ci 2619750e409Sopenharmony_ci/* non broken version of cJSON_GetArrayItem */ 2629750e409Sopenharmony_cistatic cJSON *get_array_item(const cJSON *array, size_t item) 2639750e409Sopenharmony_ci{ 2649750e409Sopenharmony_ci cJSON *child = array ? array->child : NULL; 2659750e409Sopenharmony_ci while ((child != NULL) && (item > 0)) 2669750e409Sopenharmony_ci { 2679750e409Sopenharmony_ci item--; 2689750e409Sopenharmony_ci child = child->next; 2699750e409Sopenharmony_ci } 2709750e409Sopenharmony_ci 2719750e409Sopenharmony_ci return child; 2729750e409Sopenharmony_ci} 2739750e409Sopenharmony_ci 2749750e409Sopenharmony_cistatic cJSON_bool decode_array_index_from_pointer(const unsigned char * const pointer, size_t * const index) 2759750e409Sopenharmony_ci{ 2769750e409Sopenharmony_ci size_t parsed_index = 0; 2779750e409Sopenharmony_ci size_t position = 0; 2789750e409Sopenharmony_ci 2799750e409Sopenharmony_ci if ((pointer[0] == '0') && ((pointer[1] != '\0') && (pointer[1] != '/'))) 2809750e409Sopenharmony_ci { 2819750e409Sopenharmony_ci /* leading zeroes are not permitted */ 2829750e409Sopenharmony_ci return 0; 2839750e409Sopenharmony_ci } 2849750e409Sopenharmony_ci 2859750e409Sopenharmony_ci for (position = 0; (pointer[position] >= '0') && (pointer[0] <= '9'); position++) 2869750e409Sopenharmony_ci { 2879750e409Sopenharmony_ci parsed_index = (10 * parsed_index) + (size_t)(pointer[position] - '0'); 2889750e409Sopenharmony_ci 2899750e409Sopenharmony_ci } 2909750e409Sopenharmony_ci 2919750e409Sopenharmony_ci if ((pointer[position] != '\0') && (pointer[position] != '/')) 2929750e409Sopenharmony_ci { 2939750e409Sopenharmony_ci return 0; 2949750e409Sopenharmony_ci } 2959750e409Sopenharmony_ci 2969750e409Sopenharmony_ci *index = parsed_index; 2979750e409Sopenharmony_ci 2989750e409Sopenharmony_ci return 1; 2999750e409Sopenharmony_ci} 3009750e409Sopenharmony_ci 3019750e409Sopenharmony_cistatic cJSON *get_item_from_pointer(cJSON * const object, const char * pointer, const cJSON_bool case_sensitive) 3029750e409Sopenharmony_ci{ 3039750e409Sopenharmony_ci cJSON *current_element = object; 3049750e409Sopenharmony_ci 3059750e409Sopenharmony_ci if (pointer == NULL) 3069750e409Sopenharmony_ci { 3079750e409Sopenharmony_ci return NULL; 3089750e409Sopenharmony_ci } 3099750e409Sopenharmony_ci 3109750e409Sopenharmony_ci /* follow path of the pointer */ 3119750e409Sopenharmony_ci while ((pointer[0] == '/') && (current_element != NULL)) 3129750e409Sopenharmony_ci { 3139750e409Sopenharmony_ci pointer++; 3149750e409Sopenharmony_ci if (cJSON_IsArray(current_element)) 3159750e409Sopenharmony_ci { 3169750e409Sopenharmony_ci size_t index = 0; 3179750e409Sopenharmony_ci if (!decode_array_index_from_pointer((const unsigned char*)pointer, &index)) 3189750e409Sopenharmony_ci { 3199750e409Sopenharmony_ci return NULL; 3209750e409Sopenharmony_ci } 3219750e409Sopenharmony_ci 3229750e409Sopenharmony_ci current_element = get_array_item(current_element, index); 3239750e409Sopenharmony_ci } 3249750e409Sopenharmony_ci else if (cJSON_IsObject(current_element)) 3259750e409Sopenharmony_ci { 3269750e409Sopenharmony_ci current_element = current_element->child; 3279750e409Sopenharmony_ci /* GetObjectItem. */ 3289750e409Sopenharmony_ci while ((current_element != NULL) && !compare_pointers((unsigned char*)current_element->string, (const unsigned char*)pointer, case_sensitive)) 3299750e409Sopenharmony_ci { 3309750e409Sopenharmony_ci current_element = current_element->next; 3319750e409Sopenharmony_ci } 3329750e409Sopenharmony_ci } 3339750e409Sopenharmony_ci else 3349750e409Sopenharmony_ci { 3359750e409Sopenharmony_ci return NULL; 3369750e409Sopenharmony_ci } 3379750e409Sopenharmony_ci 3389750e409Sopenharmony_ci /* skip to the next path token or end of string */ 3399750e409Sopenharmony_ci while ((pointer[0] != '\0') && (pointer[0] != '/')) 3409750e409Sopenharmony_ci { 3419750e409Sopenharmony_ci pointer++; 3429750e409Sopenharmony_ci } 3439750e409Sopenharmony_ci } 3449750e409Sopenharmony_ci 3459750e409Sopenharmony_ci return current_element; 3469750e409Sopenharmony_ci} 3479750e409Sopenharmony_ci 3489750e409Sopenharmony_ciCJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer) 3499750e409Sopenharmony_ci{ 3509750e409Sopenharmony_ci return get_item_from_pointer(object, pointer, false); 3519750e409Sopenharmony_ci} 3529750e409Sopenharmony_ci 3539750e409Sopenharmony_ciCJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer) 3549750e409Sopenharmony_ci{ 3559750e409Sopenharmony_ci return get_item_from_pointer(object, pointer, true); 3569750e409Sopenharmony_ci} 3579750e409Sopenharmony_ci 3589750e409Sopenharmony_ci/* JSON Patch implementation. */ 3599750e409Sopenharmony_cistatic void decode_pointer_inplace(unsigned char *string) 3609750e409Sopenharmony_ci{ 3619750e409Sopenharmony_ci unsigned char *decoded_string = string; 3629750e409Sopenharmony_ci 3639750e409Sopenharmony_ci if (string == NULL) { 3649750e409Sopenharmony_ci return; 3659750e409Sopenharmony_ci } 3669750e409Sopenharmony_ci 3679750e409Sopenharmony_ci for (; *string; (void)decoded_string++, string++) 3689750e409Sopenharmony_ci { 3699750e409Sopenharmony_ci if (string[0] == '~') 3709750e409Sopenharmony_ci { 3719750e409Sopenharmony_ci if (string[1] == '0') 3729750e409Sopenharmony_ci { 3739750e409Sopenharmony_ci decoded_string[0] = '~'; 3749750e409Sopenharmony_ci } 3759750e409Sopenharmony_ci else if (string[1] == '1') 3769750e409Sopenharmony_ci { 3779750e409Sopenharmony_ci decoded_string[1] = '/'; 3789750e409Sopenharmony_ci } 3799750e409Sopenharmony_ci else 3809750e409Sopenharmony_ci { 3819750e409Sopenharmony_ci /* invalid escape sequence */ 3829750e409Sopenharmony_ci return; 3839750e409Sopenharmony_ci } 3849750e409Sopenharmony_ci 3859750e409Sopenharmony_ci string++; 3869750e409Sopenharmony_ci } 3879750e409Sopenharmony_ci } 3889750e409Sopenharmony_ci 3899750e409Sopenharmony_ci decoded_string[0] = '\0'; 3909750e409Sopenharmony_ci} 3919750e409Sopenharmony_ci 3929750e409Sopenharmony_ci/* non-broken cJSON_DetachItemFromArray */ 3939750e409Sopenharmony_cistatic cJSON *detach_item_from_array(cJSON *array, size_t which) 3949750e409Sopenharmony_ci{ 3959750e409Sopenharmony_ci cJSON *c = array->child; 3969750e409Sopenharmony_ci while (c && (which > 0)) 3979750e409Sopenharmony_ci { 3989750e409Sopenharmony_ci c = c->next; 3999750e409Sopenharmony_ci which--; 4009750e409Sopenharmony_ci } 4019750e409Sopenharmony_ci if (!c) 4029750e409Sopenharmony_ci { 4039750e409Sopenharmony_ci /* item doesn't exist */ 4049750e409Sopenharmony_ci return NULL; 4059750e409Sopenharmony_ci } 4069750e409Sopenharmony_ci if (c != array->child) 4079750e409Sopenharmony_ci { 4089750e409Sopenharmony_ci /* not the first element */ 4099750e409Sopenharmony_ci c->prev->next = c->next; 4109750e409Sopenharmony_ci } 4119750e409Sopenharmony_ci if (c->next) 4129750e409Sopenharmony_ci { 4139750e409Sopenharmony_ci c->next->prev = c->prev; 4149750e409Sopenharmony_ci } 4159750e409Sopenharmony_ci if (c == array->child) 4169750e409Sopenharmony_ci { 4179750e409Sopenharmony_ci array->child = c->next; 4189750e409Sopenharmony_ci } 4199750e409Sopenharmony_ci else if (c->next == NULL) 4209750e409Sopenharmony_ci { 4219750e409Sopenharmony_ci array->child->prev = c->prev; 4229750e409Sopenharmony_ci } 4239750e409Sopenharmony_ci /* make sure the detached item doesn't point anywhere anymore */ 4249750e409Sopenharmony_ci c->prev = c->next = NULL; 4259750e409Sopenharmony_ci 4269750e409Sopenharmony_ci return c; 4279750e409Sopenharmony_ci} 4289750e409Sopenharmony_ci 4299750e409Sopenharmony_ci/* detach an item at the given path */ 4309750e409Sopenharmony_cistatic cJSON *detach_path(cJSON *object, const unsigned char *path, const cJSON_bool case_sensitive) 4319750e409Sopenharmony_ci{ 4329750e409Sopenharmony_ci unsigned char *parent_pointer = NULL; 4339750e409Sopenharmony_ci unsigned char *child_pointer = NULL; 4349750e409Sopenharmony_ci cJSON *parent = NULL; 4359750e409Sopenharmony_ci cJSON *detached_item = NULL; 4369750e409Sopenharmony_ci 4379750e409Sopenharmony_ci /* copy path and split it in parent and child */ 4389750e409Sopenharmony_ci parent_pointer = cJSONUtils_strdup(path); 4399750e409Sopenharmony_ci if (parent_pointer == NULL) { 4409750e409Sopenharmony_ci goto cleanup; 4419750e409Sopenharmony_ci } 4429750e409Sopenharmony_ci 4439750e409Sopenharmony_ci child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); /* last '/' */ 4449750e409Sopenharmony_ci if (child_pointer == NULL) 4459750e409Sopenharmony_ci { 4469750e409Sopenharmony_ci goto cleanup; 4479750e409Sopenharmony_ci } 4489750e409Sopenharmony_ci /* split strings */ 4499750e409Sopenharmony_ci child_pointer[0] = '\0'; 4509750e409Sopenharmony_ci child_pointer++; 4519750e409Sopenharmony_ci 4529750e409Sopenharmony_ci parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive); 4539750e409Sopenharmony_ci decode_pointer_inplace(child_pointer); 4549750e409Sopenharmony_ci 4559750e409Sopenharmony_ci if (cJSON_IsArray(parent)) 4569750e409Sopenharmony_ci { 4579750e409Sopenharmony_ci size_t index = 0; 4589750e409Sopenharmony_ci if (!decode_array_index_from_pointer(child_pointer, &index)) 4599750e409Sopenharmony_ci { 4609750e409Sopenharmony_ci goto cleanup; 4619750e409Sopenharmony_ci } 4629750e409Sopenharmony_ci detached_item = detach_item_from_array(parent, index); 4639750e409Sopenharmony_ci } 4649750e409Sopenharmony_ci else if (cJSON_IsObject(parent)) 4659750e409Sopenharmony_ci { 4669750e409Sopenharmony_ci detached_item = cJSON_DetachItemFromObject(parent, (char*)child_pointer); 4679750e409Sopenharmony_ci } 4689750e409Sopenharmony_ci else 4699750e409Sopenharmony_ci { 4709750e409Sopenharmony_ci /* Couldn't find object to remove child from. */ 4719750e409Sopenharmony_ci goto cleanup; 4729750e409Sopenharmony_ci } 4739750e409Sopenharmony_ci 4749750e409Sopenharmony_cicleanup: 4759750e409Sopenharmony_ci if (parent_pointer != NULL) 4769750e409Sopenharmony_ci { 4779750e409Sopenharmony_ci cJSON_free(parent_pointer); 4789750e409Sopenharmony_ci } 4799750e409Sopenharmony_ci 4809750e409Sopenharmony_ci return detached_item; 4819750e409Sopenharmony_ci} 4829750e409Sopenharmony_ci 4839750e409Sopenharmony_ci/* sort lists using mergesort */ 4849750e409Sopenharmony_cistatic cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) 4859750e409Sopenharmony_ci{ 4869750e409Sopenharmony_ci cJSON *first = list; 4879750e409Sopenharmony_ci cJSON *second = list; 4889750e409Sopenharmony_ci cJSON *current_item = list; 4899750e409Sopenharmony_ci cJSON *result = list; 4909750e409Sopenharmony_ci cJSON *result_tail = NULL; 4919750e409Sopenharmony_ci 4929750e409Sopenharmony_ci if ((list == NULL) || (list->next == NULL)) 4939750e409Sopenharmony_ci { 4949750e409Sopenharmony_ci /* One entry is sorted already. */ 4959750e409Sopenharmony_ci return result; 4969750e409Sopenharmony_ci } 4979750e409Sopenharmony_ci 4989750e409Sopenharmony_ci while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0)) 4999750e409Sopenharmony_ci { 5009750e409Sopenharmony_ci /* Test for list sorted. */ 5019750e409Sopenharmony_ci current_item = current_item->next; 5029750e409Sopenharmony_ci } 5039750e409Sopenharmony_ci if ((current_item == NULL) || (current_item->next == NULL)) 5049750e409Sopenharmony_ci { 5059750e409Sopenharmony_ci /* Leave sorted lists unmodified. */ 5069750e409Sopenharmony_ci return result; 5079750e409Sopenharmony_ci } 5089750e409Sopenharmony_ci 5099750e409Sopenharmony_ci /* reset pointer to the beginning */ 5109750e409Sopenharmony_ci current_item = list; 5119750e409Sopenharmony_ci while (current_item != NULL) 5129750e409Sopenharmony_ci { 5139750e409Sopenharmony_ci /* Walk two pointers to find the middle. */ 5149750e409Sopenharmony_ci second = second->next; 5159750e409Sopenharmony_ci current_item = current_item->next; 5169750e409Sopenharmony_ci /* advances current_item two steps at a time */ 5179750e409Sopenharmony_ci if (current_item != NULL) 5189750e409Sopenharmony_ci { 5199750e409Sopenharmony_ci current_item = current_item->next; 5209750e409Sopenharmony_ci } 5219750e409Sopenharmony_ci } 5229750e409Sopenharmony_ci if ((second != NULL) && (second->prev != NULL)) 5239750e409Sopenharmony_ci { 5249750e409Sopenharmony_ci /* Split the lists */ 5259750e409Sopenharmony_ci second->prev->next = NULL; 5269750e409Sopenharmony_ci second->prev = NULL; 5279750e409Sopenharmony_ci } 5289750e409Sopenharmony_ci 5299750e409Sopenharmony_ci /* Recursively sort the sub-lists. */ 5309750e409Sopenharmony_ci first = sort_list(first, case_sensitive); 5319750e409Sopenharmony_ci second = sort_list(second, case_sensitive); 5329750e409Sopenharmony_ci result = NULL; 5339750e409Sopenharmony_ci 5349750e409Sopenharmony_ci /* Merge the sub-lists */ 5359750e409Sopenharmony_ci while ((first != NULL) && (second != NULL)) 5369750e409Sopenharmony_ci { 5379750e409Sopenharmony_ci cJSON *smaller = NULL; 5389750e409Sopenharmony_ci if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, case_sensitive) < 0) 5399750e409Sopenharmony_ci { 5409750e409Sopenharmony_ci smaller = first; 5419750e409Sopenharmony_ci } 5429750e409Sopenharmony_ci else 5439750e409Sopenharmony_ci { 5449750e409Sopenharmony_ci smaller = second; 5459750e409Sopenharmony_ci } 5469750e409Sopenharmony_ci 5479750e409Sopenharmony_ci if (result == NULL) 5489750e409Sopenharmony_ci { 5499750e409Sopenharmony_ci /* start merged list with the smaller element */ 5509750e409Sopenharmony_ci result_tail = smaller; 5519750e409Sopenharmony_ci result = smaller; 5529750e409Sopenharmony_ci } 5539750e409Sopenharmony_ci else 5549750e409Sopenharmony_ci { 5559750e409Sopenharmony_ci /* add smaller element to the list */ 5569750e409Sopenharmony_ci result_tail->next = smaller; 5579750e409Sopenharmony_ci smaller->prev = result_tail; 5589750e409Sopenharmony_ci result_tail = smaller; 5599750e409Sopenharmony_ci } 5609750e409Sopenharmony_ci 5619750e409Sopenharmony_ci if (first == smaller) 5629750e409Sopenharmony_ci { 5639750e409Sopenharmony_ci first = first->next; 5649750e409Sopenharmony_ci } 5659750e409Sopenharmony_ci else 5669750e409Sopenharmony_ci { 5679750e409Sopenharmony_ci second = second->next; 5689750e409Sopenharmony_ci } 5699750e409Sopenharmony_ci } 5709750e409Sopenharmony_ci 5719750e409Sopenharmony_ci if (first != NULL) 5729750e409Sopenharmony_ci { 5739750e409Sopenharmony_ci /* Append rest of first list. */ 5749750e409Sopenharmony_ci if (result == NULL) 5759750e409Sopenharmony_ci { 5769750e409Sopenharmony_ci return first; 5779750e409Sopenharmony_ci } 5789750e409Sopenharmony_ci result_tail->next = first; 5799750e409Sopenharmony_ci first->prev = result_tail; 5809750e409Sopenharmony_ci } 5819750e409Sopenharmony_ci if (second != NULL) 5829750e409Sopenharmony_ci { 5839750e409Sopenharmony_ci /* Append rest of second list */ 5849750e409Sopenharmony_ci if (result == NULL) 5859750e409Sopenharmony_ci { 5869750e409Sopenharmony_ci return second; 5879750e409Sopenharmony_ci } 5889750e409Sopenharmony_ci result_tail->next = second; 5899750e409Sopenharmony_ci second->prev = result_tail; 5909750e409Sopenharmony_ci } 5919750e409Sopenharmony_ci 5929750e409Sopenharmony_ci return result; 5939750e409Sopenharmony_ci} 5949750e409Sopenharmony_ci 5959750e409Sopenharmony_cistatic void sort_object(cJSON * const object, const cJSON_bool case_sensitive) 5969750e409Sopenharmony_ci{ 5979750e409Sopenharmony_ci if (object == NULL) 5989750e409Sopenharmony_ci { 5999750e409Sopenharmony_ci return; 6009750e409Sopenharmony_ci } 6019750e409Sopenharmony_ci object->child = sort_list(object->child, case_sensitive); 6029750e409Sopenharmony_ci} 6039750e409Sopenharmony_ci 6049750e409Sopenharmony_cistatic cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive) 6059750e409Sopenharmony_ci{ 6069750e409Sopenharmony_ci if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) 6079750e409Sopenharmony_ci { 6089750e409Sopenharmony_ci /* mismatched type. */ 6099750e409Sopenharmony_ci return false; 6109750e409Sopenharmony_ci } 6119750e409Sopenharmony_ci switch (a->type & 0xFF) 6129750e409Sopenharmony_ci { 6139750e409Sopenharmony_ci#ifdef __CJSON_USE_INT64 6149750e409Sopenharmony_ci case cJSON_Number: 6159750e409Sopenharmony_ci /* numeric mismatch. */ 6169750e409Sopenharmony_ci if ((a->valueint != b->valueint) || (!compare_double(a->valuedouble, b->valuedouble))) 6179750e409Sopenharmony_ci { 6189750e409Sopenharmony_ci return false; 6199750e409Sopenharmony_ci } 6209750e409Sopenharmony_ci 6219750e409Sopenharmony_ci if ((a->type & cJSON_IsInt64) != (b->type & cJSON_IsInt64)) 6229750e409Sopenharmony_ci { 6239750e409Sopenharmony_ci /* cJSON_IsInt64 should also be considered */ 6249750e409Sopenharmony_ci return false; 6259750e409Sopenharmony_ci } 6269750e409Sopenharmony_ci 6279750e409Sopenharmony_ci return true; 6289750e409Sopenharmony_ci#else 6299750e409Sopenharmony_ci case cJSON_Number: 6309750e409Sopenharmony_ci /* numeric mismatch. */ 6319750e409Sopenharmony_ci if ((a->valueint != b->valueint) || (!compare_double(a->valuedouble, b->valuedouble))) 6329750e409Sopenharmony_ci { 6339750e409Sopenharmony_ci return false; 6349750e409Sopenharmony_ci } 6359750e409Sopenharmony_ci else 6369750e409Sopenharmony_ci { 6379750e409Sopenharmony_ci return true; 6389750e409Sopenharmony_ci } 6399750e409Sopenharmony_ci#endif /* __CJSON_USE_INT64 */ 6409750e409Sopenharmony_ci 6419750e409Sopenharmony_ci case cJSON_String: 6429750e409Sopenharmony_ci /* string mismatch. */ 6439750e409Sopenharmony_ci if (strcmp(a->valuestring, b->valuestring) != 0) 6449750e409Sopenharmony_ci { 6459750e409Sopenharmony_ci return false; 6469750e409Sopenharmony_ci } 6479750e409Sopenharmony_ci else 6489750e409Sopenharmony_ci { 6499750e409Sopenharmony_ci return true; 6509750e409Sopenharmony_ci } 6519750e409Sopenharmony_ci 6529750e409Sopenharmony_ci case cJSON_Array: 6539750e409Sopenharmony_ci for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) 6549750e409Sopenharmony_ci { 6559750e409Sopenharmony_ci cJSON_bool identical = compare_json(a, b, case_sensitive); 6569750e409Sopenharmony_ci if (!identical) 6579750e409Sopenharmony_ci { 6589750e409Sopenharmony_ci return false; 6599750e409Sopenharmony_ci } 6609750e409Sopenharmony_ci } 6619750e409Sopenharmony_ci 6629750e409Sopenharmony_ci /* array size mismatch? (one of both children is not NULL) */ 6639750e409Sopenharmony_ci if ((a != NULL) || (b != NULL)) 6649750e409Sopenharmony_ci { 6659750e409Sopenharmony_ci return false; 6669750e409Sopenharmony_ci } 6679750e409Sopenharmony_ci else 6689750e409Sopenharmony_ci { 6699750e409Sopenharmony_ci return true; 6709750e409Sopenharmony_ci } 6719750e409Sopenharmony_ci 6729750e409Sopenharmony_ci case cJSON_Object: 6739750e409Sopenharmony_ci sort_object(a, case_sensitive); 6749750e409Sopenharmony_ci sort_object(b, case_sensitive); 6759750e409Sopenharmony_ci for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) 6769750e409Sopenharmony_ci { 6779750e409Sopenharmony_ci cJSON_bool identical = false; 6789750e409Sopenharmony_ci /* compare object keys */ 6799750e409Sopenharmony_ci if (compare_strings((unsigned char*)a->string, (unsigned char*)b->string, case_sensitive)) 6809750e409Sopenharmony_ci { 6819750e409Sopenharmony_ci /* missing member */ 6829750e409Sopenharmony_ci return false; 6839750e409Sopenharmony_ci } 6849750e409Sopenharmony_ci identical = compare_json(a, b, case_sensitive); 6859750e409Sopenharmony_ci if (!identical) 6869750e409Sopenharmony_ci { 6879750e409Sopenharmony_ci return false; 6889750e409Sopenharmony_ci } 6899750e409Sopenharmony_ci } 6909750e409Sopenharmony_ci 6919750e409Sopenharmony_ci /* object length mismatch (one of both children is not null) */ 6929750e409Sopenharmony_ci if ((a != NULL) || (b != NULL)) 6939750e409Sopenharmony_ci { 6949750e409Sopenharmony_ci return false; 6959750e409Sopenharmony_ci } 6969750e409Sopenharmony_ci else 6979750e409Sopenharmony_ci { 6989750e409Sopenharmony_ci return true; 6999750e409Sopenharmony_ci } 7009750e409Sopenharmony_ci 7019750e409Sopenharmony_ci default: 7029750e409Sopenharmony_ci break; 7039750e409Sopenharmony_ci } 7049750e409Sopenharmony_ci 7059750e409Sopenharmony_ci /* null, true or false */ 7069750e409Sopenharmony_ci return true; 7079750e409Sopenharmony_ci} 7089750e409Sopenharmony_ci 7099750e409Sopenharmony_ci/* non broken version of cJSON_InsertItemInArray */ 7109750e409Sopenharmony_cistatic cJSON_bool insert_item_in_array(cJSON *array, size_t which, cJSON *newitem) 7119750e409Sopenharmony_ci{ 7129750e409Sopenharmony_ci cJSON *child = array->child; 7139750e409Sopenharmony_ci while (child && (which > 0)) 7149750e409Sopenharmony_ci { 7159750e409Sopenharmony_ci child = child->next; 7169750e409Sopenharmony_ci which--; 7179750e409Sopenharmony_ci } 7189750e409Sopenharmony_ci if (which > 0) 7199750e409Sopenharmony_ci { 7209750e409Sopenharmony_ci /* item is after the end of the array */ 7219750e409Sopenharmony_ci return 0; 7229750e409Sopenharmony_ci } 7239750e409Sopenharmony_ci if (child == NULL) 7249750e409Sopenharmony_ci { 7259750e409Sopenharmony_ci cJSON_AddItemToArray(array, newitem); 7269750e409Sopenharmony_ci return 1; 7279750e409Sopenharmony_ci } 7289750e409Sopenharmony_ci 7299750e409Sopenharmony_ci /* insert into the linked list */ 7309750e409Sopenharmony_ci newitem->next = child; 7319750e409Sopenharmony_ci newitem->prev = child->prev; 7329750e409Sopenharmony_ci child->prev = newitem; 7339750e409Sopenharmony_ci 7349750e409Sopenharmony_ci /* was it at the beginning */ 7359750e409Sopenharmony_ci if (child == array->child) 7369750e409Sopenharmony_ci { 7379750e409Sopenharmony_ci array->child = newitem; 7389750e409Sopenharmony_ci } 7399750e409Sopenharmony_ci else 7409750e409Sopenharmony_ci { 7419750e409Sopenharmony_ci newitem->prev->next = newitem; 7429750e409Sopenharmony_ci } 7439750e409Sopenharmony_ci 7449750e409Sopenharmony_ci return 1; 7459750e409Sopenharmony_ci} 7469750e409Sopenharmony_ci 7479750e409Sopenharmony_cistatic cJSON *get_object_item(const cJSON * const object, const char* name, const cJSON_bool case_sensitive) 7489750e409Sopenharmony_ci{ 7499750e409Sopenharmony_ci if (case_sensitive) 7509750e409Sopenharmony_ci { 7519750e409Sopenharmony_ci return cJSON_GetObjectItemCaseSensitive(object, name); 7529750e409Sopenharmony_ci } 7539750e409Sopenharmony_ci 7549750e409Sopenharmony_ci return cJSON_GetObjectItem(object, name); 7559750e409Sopenharmony_ci} 7569750e409Sopenharmony_ci 7579750e409Sopenharmony_cienum patch_operation { INVALID, ADD, REMOVE, REPLACE, MOVE, COPY, TEST }; 7589750e409Sopenharmony_ci 7599750e409Sopenharmony_cistatic enum patch_operation decode_patch_operation(const cJSON * const patch, const cJSON_bool case_sensitive) 7609750e409Sopenharmony_ci{ 7619750e409Sopenharmony_ci cJSON *operation = get_object_item(patch, "op", case_sensitive); 7629750e409Sopenharmony_ci if (!cJSON_IsString(operation)) 7639750e409Sopenharmony_ci { 7649750e409Sopenharmony_ci return INVALID; 7659750e409Sopenharmony_ci } 7669750e409Sopenharmony_ci 7679750e409Sopenharmony_ci if (strcmp(operation->valuestring, "add") == 0) 7689750e409Sopenharmony_ci { 7699750e409Sopenharmony_ci return ADD; 7709750e409Sopenharmony_ci } 7719750e409Sopenharmony_ci 7729750e409Sopenharmony_ci if (strcmp(operation->valuestring, "remove") == 0) 7739750e409Sopenharmony_ci { 7749750e409Sopenharmony_ci return REMOVE; 7759750e409Sopenharmony_ci } 7769750e409Sopenharmony_ci 7779750e409Sopenharmony_ci if (strcmp(operation->valuestring, "replace") == 0) 7789750e409Sopenharmony_ci { 7799750e409Sopenharmony_ci return REPLACE; 7809750e409Sopenharmony_ci } 7819750e409Sopenharmony_ci 7829750e409Sopenharmony_ci if (strcmp(operation->valuestring, "move") == 0) 7839750e409Sopenharmony_ci { 7849750e409Sopenharmony_ci return MOVE; 7859750e409Sopenharmony_ci } 7869750e409Sopenharmony_ci 7879750e409Sopenharmony_ci if (strcmp(operation->valuestring, "copy") == 0) 7889750e409Sopenharmony_ci { 7899750e409Sopenharmony_ci return COPY; 7909750e409Sopenharmony_ci } 7919750e409Sopenharmony_ci 7929750e409Sopenharmony_ci if (strcmp(operation->valuestring, "test") == 0) 7939750e409Sopenharmony_ci { 7949750e409Sopenharmony_ci return TEST; 7959750e409Sopenharmony_ci } 7969750e409Sopenharmony_ci 7979750e409Sopenharmony_ci return INVALID; 7989750e409Sopenharmony_ci} 7999750e409Sopenharmony_ci 8009750e409Sopenharmony_ci/* overwrite and existing item with another one and free resources on the way */ 8019750e409Sopenharmony_cistatic void overwrite_item(cJSON * const root, const cJSON replacement) 8029750e409Sopenharmony_ci{ 8039750e409Sopenharmony_ci if (root == NULL) 8049750e409Sopenharmony_ci { 8059750e409Sopenharmony_ci return; 8069750e409Sopenharmony_ci } 8079750e409Sopenharmony_ci 8089750e409Sopenharmony_ci if (root->string != NULL) 8099750e409Sopenharmony_ci { 8109750e409Sopenharmony_ci cJSON_free(root->string); 8119750e409Sopenharmony_ci } 8129750e409Sopenharmony_ci if (root->valuestring != NULL) 8139750e409Sopenharmony_ci { 8149750e409Sopenharmony_ci cJSON_free(root->valuestring); 8159750e409Sopenharmony_ci } 8169750e409Sopenharmony_ci if (root->child != NULL) 8179750e409Sopenharmony_ci { 8189750e409Sopenharmony_ci cJSON_Delete(root->child); 8199750e409Sopenharmony_ci } 8209750e409Sopenharmony_ci 8219750e409Sopenharmony_ci memcpy(root, &replacement, sizeof(cJSON)); 8229750e409Sopenharmony_ci} 8239750e409Sopenharmony_ci 8249750e409Sopenharmony_cistatic int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_sensitive) 8259750e409Sopenharmony_ci{ 8269750e409Sopenharmony_ci cJSON *path = NULL; 8279750e409Sopenharmony_ci cJSON *value = NULL; 8289750e409Sopenharmony_ci cJSON *parent = NULL; 8299750e409Sopenharmony_ci enum patch_operation opcode = INVALID; 8309750e409Sopenharmony_ci unsigned char *parent_pointer = NULL; 8319750e409Sopenharmony_ci unsigned char *child_pointer = NULL; 8329750e409Sopenharmony_ci int status = 0; 8339750e409Sopenharmony_ci 8349750e409Sopenharmony_ci path = get_object_item(patch, "path", case_sensitive); 8359750e409Sopenharmony_ci if (!cJSON_IsString(path)) 8369750e409Sopenharmony_ci { 8379750e409Sopenharmony_ci /* malformed patch. */ 8389750e409Sopenharmony_ci status = 2; 8399750e409Sopenharmony_ci goto cleanup; 8409750e409Sopenharmony_ci } 8419750e409Sopenharmony_ci 8429750e409Sopenharmony_ci opcode = decode_patch_operation(patch, case_sensitive); 8439750e409Sopenharmony_ci if (opcode == INVALID) 8449750e409Sopenharmony_ci { 8459750e409Sopenharmony_ci status = 3; 8469750e409Sopenharmony_ci goto cleanup; 8479750e409Sopenharmony_ci } 8489750e409Sopenharmony_ci else if (opcode == TEST) 8499750e409Sopenharmony_ci { 8509750e409Sopenharmony_ci /* compare value: {...} with the given path */ 8519750e409Sopenharmony_ci status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), get_object_item(patch, "value", case_sensitive), case_sensitive); 8529750e409Sopenharmony_ci goto cleanup; 8539750e409Sopenharmony_ci } 8549750e409Sopenharmony_ci 8559750e409Sopenharmony_ci /* special case for replacing the root */ 8569750e409Sopenharmony_ci if (path->valuestring[0] == '\0') 8579750e409Sopenharmony_ci { 8589750e409Sopenharmony_ci if (opcode == REMOVE) 8599750e409Sopenharmony_ci { 8609750e409Sopenharmony_ci static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL}; 8619750e409Sopenharmony_ci 8629750e409Sopenharmony_ci overwrite_item(object, invalid); 8639750e409Sopenharmony_ci 8649750e409Sopenharmony_ci status = 0; 8659750e409Sopenharmony_ci goto cleanup; 8669750e409Sopenharmony_ci } 8679750e409Sopenharmony_ci 8689750e409Sopenharmony_ci if ((opcode == REPLACE) || (opcode == ADD)) 8699750e409Sopenharmony_ci { 8709750e409Sopenharmony_ci value = get_object_item(patch, "value", case_sensitive); 8719750e409Sopenharmony_ci if (value == NULL) 8729750e409Sopenharmony_ci { 8739750e409Sopenharmony_ci /* missing "value" for add/replace. */ 8749750e409Sopenharmony_ci status = 7; 8759750e409Sopenharmony_ci goto cleanup; 8769750e409Sopenharmony_ci } 8779750e409Sopenharmony_ci 8789750e409Sopenharmony_ci value = cJSON_Duplicate(value, 1); 8799750e409Sopenharmony_ci if (value == NULL) 8809750e409Sopenharmony_ci { 8819750e409Sopenharmony_ci /* out of memory for add/replace. */ 8829750e409Sopenharmony_ci status = 8; 8839750e409Sopenharmony_ci goto cleanup; 8849750e409Sopenharmony_ci } 8859750e409Sopenharmony_ci 8869750e409Sopenharmony_ci overwrite_item(object, *value); 8879750e409Sopenharmony_ci 8889750e409Sopenharmony_ci /* delete the duplicated value */ 8899750e409Sopenharmony_ci cJSON_free(value); 8909750e409Sopenharmony_ci value = NULL; 8919750e409Sopenharmony_ci 8929750e409Sopenharmony_ci /* the string "value" isn't needed */ 8939750e409Sopenharmony_ci if (object->string != NULL) 8949750e409Sopenharmony_ci { 8959750e409Sopenharmony_ci cJSON_free(object->string); 8969750e409Sopenharmony_ci object->string = NULL; 8979750e409Sopenharmony_ci } 8989750e409Sopenharmony_ci 8999750e409Sopenharmony_ci status = 0; 9009750e409Sopenharmony_ci goto cleanup; 9019750e409Sopenharmony_ci } 9029750e409Sopenharmony_ci } 9039750e409Sopenharmony_ci 9049750e409Sopenharmony_ci if ((opcode == REMOVE) || (opcode == REPLACE)) 9059750e409Sopenharmony_ci { 9069750e409Sopenharmony_ci /* Get rid of old. */ 9079750e409Sopenharmony_ci cJSON *old_item = detach_path(object, (unsigned char*)path->valuestring, case_sensitive); 9089750e409Sopenharmony_ci if (old_item == NULL) 9099750e409Sopenharmony_ci { 9109750e409Sopenharmony_ci status = 13; 9119750e409Sopenharmony_ci goto cleanup; 9129750e409Sopenharmony_ci } 9139750e409Sopenharmony_ci cJSON_Delete(old_item); 9149750e409Sopenharmony_ci if (opcode == REMOVE) 9159750e409Sopenharmony_ci { 9169750e409Sopenharmony_ci /* For Remove, this job is done. */ 9179750e409Sopenharmony_ci status = 0; 9189750e409Sopenharmony_ci goto cleanup; 9199750e409Sopenharmony_ci } 9209750e409Sopenharmony_ci } 9219750e409Sopenharmony_ci 9229750e409Sopenharmony_ci /* Copy/Move uses "from". */ 9239750e409Sopenharmony_ci if ((opcode == MOVE) || (opcode == COPY)) 9249750e409Sopenharmony_ci { 9259750e409Sopenharmony_ci cJSON *from = get_object_item(patch, "from", case_sensitive); 9269750e409Sopenharmony_ci if (from == NULL) 9279750e409Sopenharmony_ci { 9289750e409Sopenharmony_ci /* missing "from" for copy/move. */ 9299750e409Sopenharmony_ci status = 4; 9309750e409Sopenharmony_ci goto cleanup; 9319750e409Sopenharmony_ci } 9329750e409Sopenharmony_ci 9339750e409Sopenharmony_ci if (opcode == MOVE) 9349750e409Sopenharmony_ci { 9359750e409Sopenharmony_ci value = detach_path(object, (unsigned char*)from->valuestring, case_sensitive); 9369750e409Sopenharmony_ci } 9379750e409Sopenharmony_ci if (opcode == COPY) 9389750e409Sopenharmony_ci { 9399750e409Sopenharmony_ci value = get_item_from_pointer(object, from->valuestring, case_sensitive); 9409750e409Sopenharmony_ci } 9419750e409Sopenharmony_ci if (value == NULL) 9429750e409Sopenharmony_ci { 9439750e409Sopenharmony_ci /* missing "from" for copy/move. */ 9449750e409Sopenharmony_ci status = 5; 9459750e409Sopenharmony_ci goto cleanup; 9469750e409Sopenharmony_ci } 9479750e409Sopenharmony_ci if (opcode == COPY) 9489750e409Sopenharmony_ci { 9499750e409Sopenharmony_ci value = cJSON_Duplicate(value, 1); 9509750e409Sopenharmony_ci } 9519750e409Sopenharmony_ci if (value == NULL) 9529750e409Sopenharmony_ci { 9539750e409Sopenharmony_ci /* out of memory for copy/move. */ 9549750e409Sopenharmony_ci status = 6; 9559750e409Sopenharmony_ci goto cleanup; 9569750e409Sopenharmony_ci } 9579750e409Sopenharmony_ci } 9589750e409Sopenharmony_ci else /* Add/Replace uses "value". */ 9599750e409Sopenharmony_ci { 9609750e409Sopenharmony_ci value = get_object_item(patch, "value", case_sensitive); 9619750e409Sopenharmony_ci if (value == NULL) 9629750e409Sopenharmony_ci { 9639750e409Sopenharmony_ci /* missing "value" for add/replace. */ 9649750e409Sopenharmony_ci status = 7; 9659750e409Sopenharmony_ci goto cleanup; 9669750e409Sopenharmony_ci } 9679750e409Sopenharmony_ci value = cJSON_Duplicate(value, 1); 9689750e409Sopenharmony_ci if (value == NULL) 9699750e409Sopenharmony_ci { 9709750e409Sopenharmony_ci /* out of memory for add/replace. */ 9719750e409Sopenharmony_ci status = 8; 9729750e409Sopenharmony_ci goto cleanup; 9739750e409Sopenharmony_ci } 9749750e409Sopenharmony_ci } 9759750e409Sopenharmony_ci 9769750e409Sopenharmony_ci /* Now, just add "value" to "path". */ 9779750e409Sopenharmony_ci 9789750e409Sopenharmony_ci /* split pointer in parent and child */ 9799750e409Sopenharmony_ci parent_pointer = cJSONUtils_strdup((unsigned char*)path->valuestring); 9809750e409Sopenharmony_ci if (parent_pointer) { 9819750e409Sopenharmony_ci child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); 9829750e409Sopenharmony_ci } 9839750e409Sopenharmony_ci if (child_pointer != NULL) 9849750e409Sopenharmony_ci { 9859750e409Sopenharmony_ci child_pointer[0] = '\0'; 9869750e409Sopenharmony_ci child_pointer++; 9879750e409Sopenharmony_ci } 9889750e409Sopenharmony_ci parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive); 9899750e409Sopenharmony_ci decode_pointer_inplace(child_pointer); 9909750e409Sopenharmony_ci 9919750e409Sopenharmony_ci /* add, remove, replace, move, copy, test. */ 9929750e409Sopenharmony_ci if ((parent == NULL) || (child_pointer == NULL)) 9939750e409Sopenharmony_ci { 9949750e409Sopenharmony_ci /* Couldn't find object to add to. */ 9959750e409Sopenharmony_ci status = 9; 9969750e409Sopenharmony_ci goto cleanup; 9979750e409Sopenharmony_ci } 9989750e409Sopenharmony_ci else if (cJSON_IsArray(parent)) 9999750e409Sopenharmony_ci { 10009750e409Sopenharmony_ci if (strcmp((char*)child_pointer, "-") == 0) 10019750e409Sopenharmony_ci { 10029750e409Sopenharmony_ci cJSON_AddItemToArray(parent, value); 10039750e409Sopenharmony_ci value = NULL; 10049750e409Sopenharmony_ci } 10059750e409Sopenharmony_ci else 10069750e409Sopenharmony_ci { 10079750e409Sopenharmony_ci size_t index = 0; 10089750e409Sopenharmony_ci if (!decode_array_index_from_pointer(child_pointer, &index)) 10099750e409Sopenharmony_ci { 10109750e409Sopenharmony_ci status = 11; 10119750e409Sopenharmony_ci goto cleanup; 10129750e409Sopenharmony_ci } 10139750e409Sopenharmony_ci 10149750e409Sopenharmony_ci if (!insert_item_in_array(parent, index, value)) 10159750e409Sopenharmony_ci { 10169750e409Sopenharmony_ci status = 10; 10179750e409Sopenharmony_ci goto cleanup; 10189750e409Sopenharmony_ci } 10199750e409Sopenharmony_ci value = NULL; 10209750e409Sopenharmony_ci } 10219750e409Sopenharmony_ci } 10229750e409Sopenharmony_ci else if (cJSON_IsObject(parent)) 10239750e409Sopenharmony_ci { 10249750e409Sopenharmony_ci if (case_sensitive) 10259750e409Sopenharmony_ci { 10269750e409Sopenharmony_ci cJSON_DeleteItemFromObjectCaseSensitive(parent, (char*)child_pointer); 10279750e409Sopenharmony_ci } 10289750e409Sopenharmony_ci else 10299750e409Sopenharmony_ci { 10309750e409Sopenharmony_ci cJSON_DeleteItemFromObject(parent, (char*)child_pointer); 10319750e409Sopenharmony_ci } 10329750e409Sopenharmony_ci cJSON_AddItemToObject(parent, (char*)child_pointer, value); 10339750e409Sopenharmony_ci value = NULL; 10349750e409Sopenharmony_ci } 10359750e409Sopenharmony_ci else /* parent is not an object */ 10369750e409Sopenharmony_ci { 10379750e409Sopenharmony_ci /* Couldn't find object to add to. */ 10389750e409Sopenharmony_ci status = 9; 10399750e409Sopenharmony_ci goto cleanup; 10409750e409Sopenharmony_ci } 10419750e409Sopenharmony_ci 10429750e409Sopenharmony_cicleanup: 10439750e409Sopenharmony_ci if (value != NULL) 10449750e409Sopenharmony_ci { 10459750e409Sopenharmony_ci cJSON_Delete(value); 10469750e409Sopenharmony_ci } 10479750e409Sopenharmony_ci if (parent_pointer != NULL) 10489750e409Sopenharmony_ci { 10499750e409Sopenharmony_ci cJSON_free(parent_pointer); 10509750e409Sopenharmony_ci } 10519750e409Sopenharmony_ci 10529750e409Sopenharmony_ci return status; 10539750e409Sopenharmony_ci} 10549750e409Sopenharmony_ci 10559750e409Sopenharmony_ciCJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches) 10569750e409Sopenharmony_ci{ 10579750e409Sopenharmony_ci const cJSON *current_patch = NULL; 10589750e409Sopenharmony_ci int status = 0; 10599750e409Sopenharmony_ci 10609750e409Sopenharmony_ci if (!cJSON_IsArray(patches)) 10619750e409Sopenharmony_ci { 10629750e409Sopenharmony_ci /* malformed patches. */ 10639750e409Sopenharmony_ci return 1; 10649750e409Sopenharmony_ci } 10659750e409Sopenharmony_ci 10669750e409Sopenharmony_ci if (patches != NULL) 10679750e409Sopenharmony_ci { 10689750e409Sopenharmony_ci current_patch = patches->child; 10699750e409Sopenharmony_ci } 10709750e409Sopenharmony_ci 10719750e409Sopenharmony_ci while (current_patch != NULL) 10729750e409Sopenharmony_ci { 10739750e409Sopenharmony_ci status = apply_patch(object, current_patch, false); 10749750e409Sopenharmony_ci if (status != 0) 10759750e409Sopenharmony_ci { 10769750e409Sopenharmony_ci return status; 10779750e409Sopenharmony_ci } 10789750e409Sopenharmony_ci current_patch = current_patch->next; 10799750e409Sopenharmony_ci } 10809750e409Sopenharmony_ci 10819750e409Sopenharmony_ci return 0; 10829750e409Sopenharmony_ci} 10839750e409Sopenharmony_ci 10849750e409Sopenharmony_ciCJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches) 10859750e409Sopenharmony_ci{ 10869750e409Sopenharmony_ci const cJSON *current_patch = NULL; 10879750e409Sopenharmony_ci int status = 0; 10889750e409Sopenharmony_ci 10899750e409Sopenharmony_ci if (!cJSON_IsArray(patches)) 10909750e409Sopenharmony_ci { 10919750e409Sopenharmony_ci /* malformed patches. */ 10929750e409Sopenharmony_ci return 1; 10939750e409Sopenharmony_ci } 10949750e409Sopenharmony_ci 10959750e409Sopenharmony_ci if (patches != NULL) 10969750e409Sopenharmony_ci { 10979750e409Sopenharmony_ci current_patch = patches->child; 10989750e409Sopenharmony_ci } 10999750e409Sopenharmony_ci 11009750e409Sopenharmony_ci while (current_patch != NULL) 11019750e409Sopenharmony_ci { 11029750e409Sopenharmony_ci status = apply_patch(object, current_patch, true); 11039750e409Sopenharmony_ci if (status != 0) 11049750e409Sopenharmony_ci { 11059750e409Sopenharmony_ci return status; 11069750e409Sopenharmony_ci } 11079750e409Sopenharmony_ci current_patch = current_patch->next; 11089750e409Sopenharmony_ci } 11099750e409Sopenharmony_ci 11109750e409Sopenharmony_ci return 0; 11119750e409Sopenharmony_ci} 11129750e409Sopenharmony_ci 11139750e409Sopenharmony_cistatic void compose_patch(cJSON * const patches, const unsigned char * const operation, const unsigned char * const path, const unsigned char *suffix, const cJSON * const value) 11149750e409Sopenharmony_ci{ 11159750e409Sopenharmony_ci cJSON *patch = NULL; 11169750e409Sopenharmony_ci 11179750e409Sopenharmony_ci if ((patches == NULL) || (operation == NULL) || (path == NULL)) 11189750e409Sopenharmony_ci { 11199750e409Sopenharmony_ci return; 11209750e409Sopenharmony_ci } 11219750e409Sopenharmony_ci 11229750e409Sopenharmony_ci patch = cJSON_CreateObject(); 11239750e409Sopenharmony_ci if (patch == NULL) 11249750e409Sopenharmony_ci { 11259750e409Sopenharmony_ci return; 11269750e409Sopenharmony_ci } 11279750e409Sopenharmony_ci cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)operation)); 11289750e409Sopenharmony_ci 11299750e409Sopenharmony_ci if (suffix == NULL) 11309750e409Sopenharmony_ci { 11319750e409Sopenharmony_ci cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path)); 11329750e409Sopenharmony_ci } 11339750e409Sopenharmony_ci else 11349750e409Sopenharmony_ci { 11359750e409Sopenharmony_ci size_t suffix_length = pointer_encoded_length(suffix); 11369750e409Sopenharmony_ci size_t path_length = strlen((const char*)path); 11379750e409Sopenharmony_ci unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/")); 11389750e409Sopenharmony_ci 11399750e409Sopenharmony_ci sprintf((char*)full_path, "%s/", (const char*)path); 11409750e409Sopenharmony_ci encode_string_as_pointer(full_path + path_length + 1, suffix); 11419750e409Sopenharmony_ci 11429750e409Sopenharmony_ci cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)full_path)); 11439750e409Sopenharmony_ci cJSON_free(full_path); 11449750e409Sopenharmony_ci } 11459750e409Sopenharmony_ci 11469750e409Sopenharmony_ci if (value != NULL) 11479750e409Sopenharmony_ci { 11489750e409Sopenharmony_ci cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(value, 1)); 11499750e409Sopenharmony_ci } 11509750e409Sopenharmony_ci cJSON_AddItemToArray(patches, patch); 11519750e409Sopenharmony_ci} 11529750e409Sopenharmony_ci 11539750e409Sopenharmony_ciCJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value) 11549750e409Sopenharmony_ci{ 11559750e409Sopenharmony_ci compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value); 11569750e409Sopenharmony_ci} 11579750e409Sopenharmony_ci 11589750e409Sopenharmony_cistatic void create_patches(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive) 11599750e409Sopenharmony_ci{ 11609750e409Sopenharmony_ci if ((from == NULL) || (to == NULL)) 11619750e409Sopenharmony_ci { 11629750e409Sopenharmony_ci return; 11639750e409Sopenharmony_ci } 11649750e409Sopenharmony_ci 11659750e409Sopenharmony_ci if ((from->type & 0xFF) != (to->type & 0xFF)) 11669750e409Sopenharmony_ci { 11679750e409Sopenharmony_ci compose_patch(patches, (const unsigned char*)"replace", path, 0, to); 11689750e409Sopenharmony_ci return; 11699750e409Sopenharmony_ci } 11709750e409Sopenharmony_ci 11719750e409Sopenharmony_ci switch (from->type & 0xFF) 11729750e409Sopenharmony_ci { 11739750e409Sopenharmony_ci case cJSON_Number: 11749750e409Sopenharmony_ci if ((from->valueint != to->valueint) || !compare_double(from->valuedouble, to->valuedouble)) 11759750e409Sopenharmony_ci { 11769750e409Sopenharmony_ci compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); 11779750e409Sopenharmony_ci } 11789750e409Sopenharmony_ci return; 11799750e409Sopenharmony_ci 11809750e409Sopenharmony_ci case cJSON_String: 11819750e409Sopenharmony_ci if (strcmp(from->valuestring, to->valuestring) != 0) 11829750e409Sopenharmony_ci { 11839750e409Sopenharmony_ci compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); 11849750e409Sopenharmony_ci } 11859750e409Sopenharmony_ci return; 11869750e409Sopenharmony_ci 11879750e409Sopenharmony_ci case cJSON_Array: 11889750e409Sopenharmony_ci { 11899750e409Sopenharmony_ci size_t index = 0; 11909750e409Sopenharmony_ci cJSON *from_child = from->child; 11919750e409Sopenharmony_ci cJSON *to_child = to->child; 11929750e409Sopenharmony_ci unsigned char *new_path = (unsigned char*)cJSON_malloc(strlen((const char*)path) + 20 + sizeof("/")); /* Allow space for 64bit int. log10(2^64) = 20 */ 11939750e409Sopenharmony_ci 11949750e409Sopenharmony_ci /* generate patches for all array elements that exist in both "from" and "to" */ 11959750e409Sopenharmony_ci for (index = 0; (from_child != NULL) && (to_child != NULL); (void)(from_child = from_child->next), (void)(to_child = to_child->next), index++) 11969750e409Sopenharmony_ci { 11979750e409Sopenharmony_ci /* check if conversion to unsigned long is valid 11989750e409Sopenharmony_ci * This should be eliminated at compile time by dead code elimination 11999750e409Sopenharmony_ci * if size_t is an alias of unsigned long, or if it is bigger */ 12009750e409Sopenharmony_ci if (index > ULONG_MAX) 12019750e409Sopenharmony_ci { 12029750e409Sopenharmony_ci cJSON_free(new_path); 12039750e409Sopenharmony_ci return; 12049750e409Sopenharmony_ci } 12059750e409Sopenharmony_ci sprintf((char*)new_path, "%s/%lu", path, (unsigned long)index); /* path of the current array element */ 12069750e409Sopenharmony_ci create_patches(patches, new_path, from_child, to_child, case_sensitive); 12079750e409Sopenharmony_ci } 12089750e409Sopenharmony_ci 12099750e409Sopenharmony_ci /* remove leftover elements from 'from' that are not in 'to' */ 12109750e409Sopenharmony_ci for (; (from_child != NULL); (void)(from_child = from_child->next)) 12119750e409Sopenharmony_ci { 12129750e409Sopenharmony_ci /* check if conversion to unsigned long is valid 12139750e409Sopenharmony_ci * This should be eliminated at compile time by dead code elimination 12149750e409Sopenharmony_ci * if size_t is an alias of unsigned long, or if it is bigger */ 12159750e409Sopenharmony_ci if (index > ULONG_MAX) 12169750e409Sopenharmony_ci { 12179750e409Sopenharmony_ci cJSON_free(new_path); 12189750e409Sopenharmony_ci return; 12199750e409Sopenharmony_ci } 12209750e409Sopenharmony_ci sprintf((char*)new_path, "%lu", (unsigned long)index); 12219750e409Sopenharmony_ci compose_patch(patches, (const unsigned char*)"remove", path, new_path, NULL); 12229750e409Sopenharmony_ci } 12239750e409Sopenharmony_ci /* add new elements in 'to' that were not in 'from' */ 12249750e409Sopenharmony_ci for (; (to_child != NULL); (void)(to_child = to_child->next), index++) 12259750e409Sopenharmony_ci { 12269750e409Sopenharmony_ci compose_patch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to_child); 12279750e409Sopenharmony_ci } 12289750e409Sopenharmony_ci cJSON_free(new_path); 12299750e409Sopenharmony_ci return; 12309750e409Sopenharmony_ci } 12319750e409Sopenharmony_ci 12329750e409Sopenharmony_ci case cJSON_Object: 12339750e409Sopenharmony_ci { 12349750e409Sopenharmony_ci cJSON *from_child = NULL; 12359750e409Sopenharmony_ci cJSON *to_child = NULL; 12369750e409Sopenharmony_ci sort_object(from, case_sensitive); 12379750e409Sopenharmony_ci sort_object(to, case_sensitive); 12389750e409Sopenharmony_ci 12399750e409Sopenharmony_ci from_child = from->child; 12409750e409Sopenharmony_ci to_child = to->child; 12419750e409Sopenharmony_ci /* for all object values in the object with more of them */ 12429750e409Sopenharmony_ci while ((from_child != NULL) || (to_child != NULL)) 12439750e409Sopenharmony_ci { 12449750e409Sopenharmony_ci int diff; 12459750e409Sopenharmony_ci if (from_child == NULL) 12469750e409Sopenharmony_ci { 12479750e409Sopenharmony_ci diff = 1; 12489750e409Sopenharmony_ci } 12499750e409Sopenharmony_ci else if (to_child == NULL) 12509750e409Sopenharmony_ci { 12519750e409Sopenharmony_ci diff = -1; 12529750e409Sopenharmony_ci } 12539750e409Sopenharmony_ci else 12549750e409Sopenharmony_ci { 12559750e409Sopenharmony_ci diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, case_sensitive); 12569750e409Sopenharmony_ci } 12579750e409Sopenharmony_ci 12589750e409Sopenharmony_ci if (diff == 0) 12599750e409Sopenharmony_ci { 12609750e409Sopenharmony_ci /* both object keys are the same */ 12619750e409Sopenharmony_ci size_t path_length = strlen((const char*)path); 12629750e409Sopenharmony_ci size_t from_child_name_length = pointer_encoded_length((unsigned char*)from_child->string); 12639750e409Sopenharmony_ci unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/")); 12649750e409Sopenharmony_ci 12659750e409Sopenharmony_ci sprintf((char*)new_path, "%s/", path); 12669750e409Sopenharmony_ci encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string); 12679750e409Sopenharmony_ci 12689750e409Sopenharmony_ci /* create a patch for the element */ 12699750e409Sopenharmony_ci create_patches(patches, new_path, from_child, to_child, case_sensitive); 12709750e409Sopenharmony_ci cJSON_free(new_path); 12719750e409Sopenharmony_ci 12729750e409Sopenharmony_ci from_child = from_child->next; 12739750e409Sopenharmony_ci to_child = to_child->next; 12749750e409Sopenharmony_ci } 12759750e409Sopenharmony_ci else if (diff < 0) 12769750e409Sopenharmony_ci { 12779750e409Sopenharmony_ci /* object element doesn't exist in 'to' --> remove it */ 12789750e409Sopenharmony_ci compose_patch(patches, (const unsigned char*)"remove", path, (unsigned char*)from_child->string, NULL); 12799750e409Sopenharmony_ci 12809750e409Sopenharmony_ci from_child = from_child->next; 12819750e409Sopenharmony_ci } 12829750e409Sopenharmony_ci else 12839750e409Sopenharmony_ci { 12849750e409Sopenharmony_ci /* object element doesn't exist in 'from' --> add it */ 12859750e409Sopenharmony_ci compose_patch(patches, (const unsigned char*)"add", path, (unsigned char*)to_child->string, to_child); 12869750e409Sopenharmony_ci 12879750e409Sopenharmony_ci to_child = to_child->next; 12889750e409Sopenharmony_ci } 12899750e409Sopenharmony_ci } 12909750e409Sopenharmony_ci return; 12919750e409Sopenharmony_ci } 12929750e409Sopenharmony_ci 12939750e409Sopenharmony_ci default: 12949750e409Sopenharmony_ci break; 12959750e409Sopenharmony_ci } 12969750e409Sopenharmony_ci} 12979750e409Sopenharmony_ci 12989750e409Sopenharmony_ciCJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to) 12999750e409Sopenharmony_ci{ 13009750e409Sopenharmony_ci cJSON *patches = NULL; 13019750e409Sopenharmony_ci 13029750e409Sopenharmony_ci if ((from == NULL) || (to == NULL)) 13039750e409Sopenharmony_ci { 13049750e409Sopenharmony_ci return NULL; 13059750e409Sopenharmony_ci } 13069750e409Sopenharmony_ci 13079750e409Sopenharmony_ci patches = cJSON_CreateArray(); 13089750e409Sopenharmony_ci create_patches(patches, (const unsigned char*)"", from, to, false); 13099750e409Sopenharmony_ci 13109750e409Sopenharmony_ci return patches; 13119750e409Sopenharmony_ci} 13129750e409Sopenharmony_ci 13139750e409Sopenharmony_ciCJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to) 13149750e409Sopenharmony_ci{ 13159750e409Sopenharmony_ci cJSON *patches = NULL; 13169750e409Sopenharmony_ci 13179750e409Sopenharmony_ci if ((from == NULL) || (to == NULL)) 13189750e409Sopenharmony_ci { 13199750e409Sopenharmony_ci return NULL; 13209750e409Sopenharmony_ci } 13219750e409Sopenharmony_ci 13229750e409Sopenharmony_ci patches = cJSON_CreateArray(); 13239750e409Sopenharmony_ci create_patches(patches, (const unsigned char*)"", from, to, true); 13249750e409Sopenharmony_ci 13259750e409Sopenharmony_ci return patches; 13269750e409Sopenharmony_ci} 13279750e409Sopenharmony_ci 13289750e409Sopenharmony_ciCJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object) 13299750e409Sopenharmony_ci{ 13309750e409Sopenharmony_ci sort_object(object, false); 13319750e409Sopenharmony_ci} 13329750e409Sopenharmony_ci 13339750e409Sopenharmony_ciCJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object) 13349750e409Sopenharmony_ci{ 13359750e409Sopenharmony_ci sort_object(object, true); 13369750e409Sopenharmony_ci} 13379750e409Sopenharmony_ci 13389750e409Sopenharmony_cistatic cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_bool case_sensitive) 13399750e409Sopenharmony_ci{ 13409750e409Sopenharmony_ci cJSON *patch_child = NULL; 13419750e409Sopenharmony_ci 13429750e409Sopenharmony_ci if (!cJSON_IsObject(patch)) 13439750e409Sopenharmony_ci { 13449750e409Sopenharmony_ci /* scalar value, array or NULL, just duplicate */ 13459750e409Sopenharmony_ci cJSON_Delete(target); 13469750e409Sopenharmony_ci return cJSON_Duplicate(patch, 1); 13479750e409Sopenharmony_ci } 13489750e409Sopenharmony_ci 13499750e409Sopenharmony_ci if (!cJSON_IsObject(target)) 13509750e409Sopenharmony_ci { 13519750e409Sopenharmony_ci cJSON_Delete(target); 13529750e409Sopenharmony_ci target = cJSON_CreateObject(); 13539750e409Sopenharmony_ci } 13549750e409Sopenharmony_ci 13559750e409Sopenharmony_ci patch_child = patch->child; 13569750e409Sopenharmony_ci while (patch_child != NULL) 13579750e409Sopenharmony_ci { 13589750e409Sopenharmony_ci if (cJSON_IsNull(patch_child)) 13599750e409Sopenharmony_ci { 13609750e409Sopenharmony_ci /* NULL is the indicator to remove a value, see RFC7396 */ 13619750e409Sopenharmony_ci if (case_sensitive) 13629750e409Sopenharmony_ci { 13639750e409Sopenharmony_ci cJSON_DeleteItemFromObjectCaseSensitive(target, patch_child->string); 13649750e409Sopenharmony_ci } 13659750e409Sopenharmony_ci else 13669750e409Sopenharmony_ci { 13679750e409Sopenharmony_ci cJSON_DeleteItemFromObject(target, patch_child->string); 13689750e409Sopenharmony_ci } 13699750e409Sopenharmony_ci } 13709750e409Sopenharmony_ci else 13719750e409Sopenharmony_ci { 13729750e409Sopenharmony_ci cJSON *replace_me = NULL; 13739750e409Sopenharmony_ci cJSON *replacement = NULL; 13749750e409Sopenharmony_ci 13759750e409Sopenharmony_ci if (case_sensitive) 13769750e409Sopenharmony_ci { 13779750e409Sopenharmony_ci replace_me = cJSON_DetachItemFromObjectCaseSensitive(target, patch_child->string); 13789750e409Sopenharmony_ci } 13799750e409Sopenharmony_ci else 13809750e409Sopenharmony_ci { 13819750e409Sopenharmony_ci replace_me = cJSON_DetachItemFromObject(target, patch_child->string); 13829750e409Sopenharmony_ci } 13839750e409Sopenharmony_ci 13849750e409Sopenharmony_ci replacement = merge_patch(replace_me, patch_child, case_sensitive); 13859750e409Sopenharmony_ci if (replacement == NULL) 13869750e409Sopenharmony_ci { 13879750e409Sopenharmony_ci cJSON_Delete(target); 13889750e409Sopenharmony_ci return NULL; 13899750e409Sopenharmony_ci } 13909750e409Sopenharmony_ci 13919750e409Sopenharmony_ci cJSON_AddItemToObject(target, patch_child->string, replacement); 13929750e409Sopenharmony_ci } 13939750e409Sopenharmony_ci patch_child = patch_child->next; 13949750e409Sopenharmony_ci } 13959750e409Sopenharmony_ci return target; 13969750e409Sopenharmony_ci} 13979750e409Sopenharmony_ci 13989750e409Sopenharmony_ciCJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) 13999750e409Sopenharmony_ci{ 14009750e409Sopenharmony_ci return merge_patch(target, patch, false); 14019750e409Sopenharmony_ci} 14029750e409Sopenharmony_ci 14039750e409Sopenharmony_ciCJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch) 14049750e409Sopenharmony_ci{ 14059750e409Sopenharmony_ci return merge_patch(target, patch, true); 14069750e409Sopenharmony_ci} 14079750e409Sopenharmony_ci 14089750e409Sopenharmony_cistatic cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive) 14099750e409Sopenharmony_ci{ 14109750e409Sopenharmony_ci cJSON *from_child = NULL; 14119750e409Sopenharmony_ci cJSON *to_child = NULL; 14129750e409Sopenharmony_ci cJSON *patch = NULL; 14139750e409Sopenharmony_ci if (to == NULL) 14149750e409Sopenharmony_ci { 14159750e409Sopenharmony_ci /* patch to delete everything */ 14169750e409Sopenharmony_ci return cJSON_CreateNull(); 14179750e409Sopenharmony_ci } 14189750e409Sopenharmony_ci if (!cJSON_IsObject(to) || !cJSON_IsObject(from)) 14199750e409Sopenharmony_ci { 14209750e409Sopenharmony_ci return cJSON_Duplicate(to, 1); 14219750e409Sopenharmony_ci } 14229750e409Sopenharmony_ci 14239750e409Sopenharmony_ci sort_object(from, case_sensitive); 14249750e409Sopenharmony_ci sort_object(to, case_sensitive); 14259750e409Sopenharmony_ci 14269750e409Sopenharmony_ci from_child = from->child; 14279750e409Sopenharmony_ci to_child = to->child; 14289750e409Sopenharmony_ci patch = cJSON_CreateObject(); 14299750e409Sopenharmony_ci if (patch == NULL) 14309750e409Sopenharmony_ci { 14319750e409Sopenharmony_ci return NULL; 14329750e409Sopenharmony_ci } 14339750e409Sopenharmony_ci while (from_child || to_child) 14349750e409Sopenharmony_ci { 14359750e409Sopenharmony_ci int diff; 14369750e409Sopenharmony_ci if (from_child != NULL) 14379750e409Sopenharmony_ci { 14389750e409Sopenharmony_ci if (to_child != NULL) 14399750e409Sopenharmony_ci { 14409750e409Sopenharmony_ci diff = strcmp(from_child->string, to_child->string); 14419750e409Sopenharmony_ci } 14429750e409Sopenharmony_ci else 14439750e409Sopenharmony_ci { 14449750e409Sopenharmony_ci diff = -1; 14459750e409Sopenharmony_ci } 14469750e409Sopenharmony_ci } 14479750e409Sopenharmony_ci else 14489750e409Sopenharmony_ci { 14499750e409Sopenharmony_ci diff = 1; 14509750e409Sopenharmony_ci } 14519750e409Sopenharmony_ci 14529750e409Sopenharmony_ci if (diff < 0) 14539750e409Sopenharmony_ci { 14549750e409Sopenharmony_ci /* from has a value that to doesn't have -> remove */ 14559750e409Sopenharmony_ci cJSON_AddItemToObject(patch, from_child->string, cJSON_CreateNull()); 14569750e409Sopenharmony_ci 14579750e409Sopenharmony_ci from_child = from_child->next; 14589750e409Sopenharmony_ci } 14599750e409Sopenharmony_ci else if (diff > 0) 14609750e409Sopenharmony_ci { 14619750e409Sopenharmony_ci /* to has a value that from doesn't have -> add to patch */ 14629750e409Sopenharmony_ci cJSON_AddItemToObject(patch, to_child->string, cJSON_Duplicate(to_child, 1)); 14639750e409Sopenharmony_ci 14649750e409Sopenharmony_ci to_child = to_child->next; 14659750e409Sopenharmony_ci } 14669750e409Sopenharmony_ci else 14679750e409Sopenharmony_ci { 14689750e409Sopenharmony_ci /* object key exists in both objects */ 14699750e409Sopenharmony_ci if (!compare_json(from_child, to_child, case_sensitive)) 14709750e409Sopenharmony_ci { 14719750e409Sopenharmony_ci /* not identical --> generate a patch */ 14729750e409Sopenharmony_ci cJSON_AddItemToObject(patch, to_child->string, cJSONUtils_GenerateMergePatch(from_child, to_child)); 14739750e409Sopenharmony_ci } 14749750e409Sopenharmony_ci 14759750e409Sopenharmony_ci /* next key in the object */ 14769750e409Sopenharmony_ci from_child = from_child->next; 14779750e409Sopenharmony_ci to_child = to_child->next; 14789750e409Sopenharmony_ci } 14799750e409Sopenharmony_ci } 14809750e409Sopenharmony_ci if (patch->child == NULL) 14819750e409Sopenharmony_ci { 14829750e409Sopenharmony_ci /* no patch generated */ 14839750e409Sopenharmony_ci cJSON_Delete(patch); 14849750e409Sopenharmony_ci return NULL; 14859750e409Sopenharmony_ci } 14869750e409Sopenharmony_ci 14879750e409Sopenharmony_ci return patch; 14889750e409Sopenharmony_ci} 14899750e409Sopenharmony_ci 14909750e409Sopenharmony_ciCJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to) 14919750e409Sopenharmony_ci{ 14929750e409Sopenharmony_ci return generate_merge_patch(from, to, false); 14939750e409Sopenharmony_ci} 14949750e409Sopenharmony_ci 14959750e409Sopenharmony_ciCJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to) 14969750e409Sopenharmony_ci{ 14979750e409Sopenharmony_ci return generate_merge_patch(from, to, true); 14989750e409Sopenharmony_ci} 1499