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