cJSON_Utils.c 38.7 KB
Newer Older
M
Max Bruckner 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

23 24 25 26
/* disable warnings about old C89 functions in MSVC */
#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
#define _CRT_SECURE_NO_DEPRECATE
#endif
27
#pragma GCC visibility push(default)
28
#include <ctype.h>
29 30
#include <string.h>
#include <stdlib.h>
31
#include <stdio.h>
M
Max Bruckner 已提交
32
#include <limits.h>
33
#pragma GCC visibility pop
M
Max Bruckner 已提交
34

35 36
#include "cJSON_Utils.h"

M
Max Bruckner 已提交
37 38 39 40
/* define our own boolean type */
#define true ((cJSON_bool)1)
#define false ((cJSON_bool)0)

M
Max Bruckner 已提交
41
static unsigned char* cJSONUtils_strdup(const unsigned char* const string)
42
{
M
Max Bruckner 已提交
43
    size_t length = 0;
44
    unsigned char *copy = NULL;
45

M
Max Bruckner 已提交
46 47 48
    length = strlen((const char*)string) + sizeof("");
    copy = (unsigned char*) cJSON_malloc(length);
    if (copy == NULL)
49
    {
50
        return NULL;
51
    }
M
Max Bruckner 已提交
52
    memcpy(copy, string, length);
53 54 55 56

    return copy;
}

57 58
/* string comparison which doesn't consider NULL pointers equal */
static int compare_strings(const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive)
59
{
M
Max Bruckner 已提交
60
    if ((string1 == NULL) || (string2 == NULL))
M
Max Bruckner 已提交
61
    {
M
Max Bruckner 已提交
62
        return 1;
M
Max Bruckner 已提交
63
    }
M
Max Bruckner 已提交
64 65

    if (string1 == string2)
M
Max Bruckner 已提交
66
    {
M
Max Bruckner 已提交
67
        return 0;
M
Max Bruckner 已提交
68
    }
M
Max Bruckner 已提交
69

70 71 72 73 74
    if (case_sensitive)
    {
        return strcmp((const char*)string1, (const char*)string2);
    }

M
Max Bruckner 已提交
75
    for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
M
Max Bruckner 已提交
76
    {
M
Max Bruckner 已提交
77
        if (*string1 == '\0')
M
Max Bruckner 已提交
78 79 80 81 82
        {
            return 0;
        }
    }

M
Max Bruckner 已提交
83
    return tolower(*string1) - tolower(*string2);
84 85
}

M
Max Bruckner 已提交
86
/* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */
87
static cJSON_bool compare_pointers(const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive)
88
{
M
Max Bruckner 已提交
89
    if ((name == NULL) || (pointer == NULL))
90
    {
91
        return false;
92
    }
M
Max Bruckner 已提交
93 94

    for (; (*name != '\0') && (*pointer != '\0') && (*pointer != '/'); (void)name++, pointer++) /* compare until next '/' */
95
    {
M
Max Bruckner 已提交
96
        if (*pointer == '~')
97 98
        {
            /* check for escaped '~' (~0) and '/' (~1) */
M
Max Bruckner 已提交
99
            if (((pointer[1] != '0') || (*name != '~')) && ((pointer[1] != '1') || (*name != '/')))
100
            {
M
Max Bruckner 已提交
101
                /* invalid escape sequence or wrong character in *name */
102
                return false;
103 104 105
            }
            else
            {
M
Max Bruckner 已提交
106
                pointer++;
107 108
            }
        }
109
        else if ((!case_sensitive && (tolower(*name) != tolower(*pointer))) || (case_sensitive && (*name != *pointer)))
110
        {
111
            return false;
112 113
        }
    }
M
Max Bruckner 已提交
114
    if (((*pointer != 0) && (*pointer != '/')) != (*name != 0))
115 116
    {
        /* one string has ended, the other not */
117
        return false;;
118 119
    }

120
    return true;
121 122
}

123
/* calculate the length of a string if encoded as JSON pointer with ~0 and ~1 escape sequences */
124
static size_t pointer_encoded_length(const unsigned char *string)
125
{
126 127
    size_t length;
    for (length = 0; *string != '\0'; (void)string++, length++)
128
    {
129 130
        /* character needs to be escaped? */
        if ((*string == '~') || (*string == '/'))
131
        {
132
            length++;
133 134 135
        }
    }

136
    return length;
137
}
138

139
/* copy a string while escaping '~' and '/' with ~0 and ~1 JSON pointer escape codes */
140
static void encode_string_as_pointer(unsigned char *destination, const unsigned char *source)
141
{
142
    for (; source[0] != '\0'; (void)source++, destination++)
143
    {
144
        if (source[0] == '/')
145
        {
146 147
            destination[1] = '1';
            destination++;
148
        }
149
        else if (source[0] == '~')
150
        {
151 152 153
            destination[0] = '~';
            destination[1] = '1';
            destination++;
154 155 156
        }
        else
        {
157
            destination[0] = source[0];
158 159 160
        }
    }

161
    destination[0] = '\0';
162 163
}

164
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target)
165
{
166 167
    size_t child_index = 0;
    cJSON *current_child = 0;
168

169 170 171 172 173
    if ((object == NULL) || (target == NULL))
    {
        return NULL;
    }

174 175 176
    if (object == target)
    {
        /* found */
177
        return (char*)cJSONUtils_strdup((const unsigned char*)"");
178
    }
179

180 181
    /* recursively search all children of the object or array */
    for (current_child = object->child; current_child != NULL; (void)(current_child = current_child->next), child_index++)
182
    {
183 184 185
        unsigned char *target_pointer = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(current_child, target);
        /* found the target? */
        if (target_pointer != NULL)
186
        {
187
            if (cJSON_IsArray(object))
188 189
            {
                /* reserve enough memory for a 64 bit integer + '/' and '\0' */
190
                unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + 20 + sizeof("/"));
191 192 193
                /* check if conversion to unsigned long is valid
                 * This should be eliminated at compile time by dead code elimination
                 * if size_t is an alias of unsigned long, or if it is bigger */
194
                if (child_index > ULONG_MAX)
195
                {
196
                    cJSON_free(target_pointer);
197 198
                    return NULL;
                }
199 200
                sprintf((char*)full_pointer, "/%lu%s", (unsigned long)child_index, target_pointer); /* /<array_index><path> */
                cJSON_free(target_pointer);
201

202
                return (char*)full_pointer;
203
            }
204 205

            if (cJSON_IsObject(object))
206
            {
207
                unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + pointer_encoded_length((unsigned char*)current_child->string) + 2);
208
                full_pointer[0] = '/';
209
                encode_string_as_pointer(full_pointer + 1, (unsigned char*)current_child->string);
210 211
                strcat((char*)full_pointer, (char*)target_pointer);
                cJSON_free(target_pointer);
212

213
                return (char*)full_pointer;
214 215 216
            }

            /* reached leaf of the tree, found nothing */
217
            cJSON_free(target_pointer);
218
            return NULL;
219 220 221 222
        }
    }

    /* not found */
223
    return NULL;
224 225
}

226 227 228 229 230 231 232 233 234 235 236 237 238
/* non broken version of cJSON_GetArrayItem */
static cJSON *get_array_item(const cJSON *array, size_t item)
{
    cJSON *child = array ? array->child : NULL;
    while ((child != NULL) && (item > 0))
    {
        item--;
        child = child->next;
    }

    return child;
}

239 240 241 242 243 244 245 246 247 248 249
static cJSON_bool decode_array_index_from_pointer(const unsigned char * const pointer, size_t * const index)
{
    size_t parsed_index = 0;
    size_t position = 0;

    if ((pointer[0] == '0') && ((pointer[1] != '\0') && (pointer[1] != '/')))
    {
        /* leading zeroes are not permitted */
        return 0;
    }

250
    for (position = 0; (pointer[position] >= '0') && (pointer[0] <= '9'); position++)
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
    {
        parsed_index = (10 * parsed_index) + (size_t)(pointer[position] - '0');

    }

    if ((pointer[position] != '\0') && (pointer[position] != '/'))
    {
        return 0;
    }

    *index = parsed_index;

    return 1;
}

266
static cJSON *get_item_from_pointer(cJSON * const object, const char * pointer, const cJSON_bool case_sensitive)
267
{
M
Max Bruckner 已提交
268
    cJSON *current_element = object;
269 270 271 272 273 274

    if (pointer == NULL)
    {
        return NULL;
    }

275
    /* follow path of the pointer */
M
Max Bruckner 已提交
276
    while ((pointer[0] == '/') && (current_element != NULL))
277
    {
M
Max Bruckner 已提交
278 279
        pointer++;
        if (cJSON_IsArray(current_element))
280
        {
281
            size_t index = 0;
282
            if (!decode_array_index_from_pointer((const unsigned char*)pointer, &index))
283
            {
284
                return NULL;
285
            }
286

M
Max Bruckner 已提交
287
            current_element = get_array_item(current_element, index);
288
        }
M
Max Bruckner 已提交
289
        else if (cJSON_IsObject(current_element))
290
        {
M
Max Bruckner 已提交
291
            current_element = current_element->child;
292
            /* GetObjectItem. */
293
            while ((current_element != NULL) && !compare_pointers((unsigned char*)current_element->string, (const unsigned char*)pointer, case_sensitive))
294
            {
M
Max Bruckner 已提交
295
                current_element = current_element->next;
296 297 298 299
            }
        }
        else
        {
300
            return NULL;
301
        }
302 303 304 305 306 307

        /* skip to the next path token or end of string */
        while ((pointer[0] != '\0') && (pointer[0] != '/'))
        {
            pointer++;
        }
308 309
    }

M
Max Bruckner 已提交
310
    return current_element;
311 312
}

313 314 315 316 317
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer)
{
    return get_item_from_pointer(object, pointer, false);
}

318 319 320 321 322
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer)
{
    return get_item_from_pointer(object, pointer, true);
}

323
/* JSON Patch implementation. */
324
static void decode_pointer_inplace(unsigned char *string)
325
{
326
    unsigned char *decoded_string = string;
327 328 329 330 331

    if (string == NULL) {
        return;
    }

332
    for (; *string; (void)decoded_string++, string++)
333
    {
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
        if (string[0] == '~')
        {
            if (string[1] == '0')
            {
                decoded_string[0] = '~';
            }
            else if (string[1] == '1')
            {
                decoded_string[1] = '/';
            }
            else
            {
                /* invalid escape sequence */
                return;
            }

            string++;
        }
352 353
    }

354
    decoded_string[0] = '\0';
355 356
}

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
/* non-broken cJSON_DetachItemFromArray */
static cJSON *detach_item_from_array(cJSON *array, size_t which)
{
    cJSON *c = array->child;
    while (c && (which > 0))
    {
        c = c->next;
        which--;
    }
    if (!c)
    {
        /* item doesn't exist */
        return NULL;
    }
    if (c->prev)
    {
        /* not the first element */
        c->prev->next = c->next;
    }
    if (c->next)
    {
        c->next->prev = c->prev;
    }
    if (c==array->child)
    {
        array->child = c->next;
    }
    /* make sure the detached item doesn't point anywhere anymore */
    c->prev = c->next = NULL;

    return c;
}

390
/* detach an item at the given path */
391
static cJSON *detach_path(cJSON *object, const unsigned char *path, const cJSON_bool case_sensitive)
392
{
M
Max Bruckner 已提交
393 394
    unsigned char *parent_pointer = NULL;
    unsigned char *child_pointer = NULL;
395
    cJSON *parent = NULL;
M
Max Bruckner 已提交
396
    cJSON *detached_item = NULL;
397 398

    /* copy path and split it in parent and child */
M
Max Bruckner 已提交
399 400 401
    parent_pointer = cJSONUtils_strdup(path);
    if (parent_pointer == NULL) {
        goto cleanup;
402 403
    }

M
Max Bruckner 已提交
404 405
    child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); /* last '/' */
    if (child_pointer == NULL)
406
    {
M
Max Bruckner 已提交
407
        goto cleanup;
408
    }
409
    /* split strings */
M
Max Bruckner 已提交
410 411
    child_pointer[0] = '\0';
    child_pointer++;
412

413
    parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive);
414
    decode_pointer_inplace(child_pointer);
415

M
Max Bruckner 已提交
416
    if (cJSON_IsArray(parent))
417
    {
418
        size_t index = 0;
M
Max Bruckner 已提交
419
        if (!decode_array_index_from_pointer(child_pointer, &index))
420
        {
M
Max Bruckner 已提交
421
            goto cleanup;
422
        }
M
Max Bruckner 已提交
423
        detached_item = detach_item_from_array(parent, index);
424
    }
425
    else if (cJSON_IsObject(parent))
426
    {
M
Max Bruckner 已提交
427 428 429 430 431 432 433 434 435 436 437 438
        detached_item = cJSON_DetachItemFromObject(parent, (char*)child_pointer);
    }
    else
    {
        /* Couldn't find object to remove child from. */
        goto cleanup;
    }

cleanup:
    if (parent_pointer != NULL)
    {
        cJSON_free(parent_pointer);
439
    }
440

M
Max Bruckner 已提交
441
    return detached_item;
442 443
}

444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
/* sort lists using mergesort */
static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive)
{
    cJSON *first = list;
    cJSON *second = list;
    cJSON *current_item = list;
    cJSON *result = list;
    cJSON *result_tail = NULL;

    if ((list == NULL) || (list->next == NULL))
    {
        /* One entry is sorted already. */
        return result;
    }

    while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0))
    {
        /* Test for list sorted. */
        current_item = current_item->next;
    }
    if ((current_item == NULL) || (current_item->next == NULL))
    {
        /* Leave sorted lists unmodified. */
        return result;
    }

    /* reset pointer to the beginning */
    current_item = list;
    while (current_item != NULL)
    {
        /* Walk two pointers to find the middle. */
        second = second->next;
        current_item = current_item->next;
        /* advances current_item two steps at a time */
        if (current_item != NULL)
        {
            current_item = current_item->next;
        }
    }
    if ((second != NULL) && (second->prev != NULL))
    {
        /* Split the lists */
        second->prev->next = NULL;
    }

    /* Recursively sort the sub-lists. */
    first = sort_list(first, case_sensitive);
    second = sort_list(second, case_sensitive);
    result = NULL;

    /* Merge the sub-lists */
    while ((first != NULL) && (second != NULL))
    {
        cJSON *smaller = NULL;
        if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, false) < 0)
        {
            smaller = first;
        }
        else
        {
            smaller = second;
        }

        if (result == NULL)
        {
            /* start merged list with the smaller element */
            result_tail = smaller;
            result = smaller;
        }
        else
        {
            /* add smaller element to the list */
            result_tail->next = smaller;
            smaller->prev = result_tail;
            result_tail = smaller;
        }

        if (first == smaller)
        {
            first = first->next;
        }
        else
        {
            second = second->next;
        }
    }

    if (first != NULL)
    {
        /* Append rest of first list. */
        if (result == NULL)
        {
            return first;
        }
        result_tail->next = first;
        first->prev = result_tail;
    }
    if (second != NULL)
    {
        /* Append rest of second list */
        if (result == NULL)
        {
            return second;
        }
        result_tail->next = second;
        second->prev = result_tail;
    }

    return result;
}

static void sort_object(cJSON * const object, const cJSON_bool case_sensitive)
{
M
Max Bruckner 已提交
557 558 559 560
    if (object == NULL)
    {
        return;
    }
561 562 563
    object->child = sort_list(object->child, case_sensitive);
}

564
static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive)
565
{
566
    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
M
Max Bruckner 已提交
567 568
    {
        /* mismatched type. */
569
        return false;
M
Max Bruckner 已提交
570
    }
571
    switch (a->type & 0xFF)
M
Max Bruckner 已提交
572 573 574
    {
        case cJSON_Number:
            /* numeric mismatch. */
M
Max Bruckner 已提交
575 576
            if ((a->valueint != b->valueint) || (a->valuedouble != b->valuedouble))
            {
577
                return false;
M
Max Bruckner 已提交
578 579 580
            }
            else
            {
581
                return true;
M
Max Bruckner 已提交
582 583
            }

M
Max Bruckner 已提交
584 585
        case cJSON_String:
            /* string mismatch. */
M
Max Bruckner 已提交
586
            if (strcmp(a->valuestring, b->valuestring) != 0)
M
Max Bruckner 已提交
587
            {
588
                return false;
M
Max Bruckner 已提交
589 590 591
            }
            else
            {
592
                return true;
M
Max Bruckner 已提交
593 594
            }

M
Max Bruckner 已提交
595
        case cJSON_Array:
M
Max Bruckner 已提交
596
            for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next)
M
Max Bruckner 已提交
597
            {
598
                cJSON_bool identical = compare_json(a, b, case_sensitive);
599
                if (!identical)
M
Max Bruckner 已提交
600
                {
601
                    return false;
M
Max Bruckner 已提交
602 603
                }
            }
M
Max Bruckner 已提交
604

M
Max Bruckner 已提交
605
            /* array size mismatch? (one of both children is not NULL) */
M
Max Bruckner 已提交
606 607
            if ((a != NULL) || (b != NULL))
            {
608
                return false;
M
Max Bruckner 已提交
609 610 611
            }
            else
            {
612
                return true;
M
Max Bruckner 已提交
613 614
            }

M
Max Bruckner 已提交
615
        case cJSON_Object:
616 617
            sort_object(a, case_sensitive);
            sort_object(b, case_sensitive);
M
Max Bruckner 已提交
618
            for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next)
M
Max Bruckner 已提交
619
            {
620
                cJSON_bool identical = false;
M
Max Bruckner 已提交
621
                /* compare object keys */
622
                if (compare_strings((unsigned char*)a->string, (unsigned char*)b->string, case_sensitive))
M
Max Bruckner 已提交
623 624
                {
                    /* missing member */
625
                    return false;
M
Max Bruckner 已提交
626
                }
627
                identical = compare_json(a, b, case_sensitive);
628
                if (!identical)
M
Max Bruckner 已提交
629
                {
630
                    return false;
M
Max Bruckner 已提交
631 632
                }
            }
M
Max Bruckner 已提交
633

M
Max Bruckner 已提交
634
            /* object length mismatch (one of both children is not null) */
M
Max Bruckner 已提交
635 636
            if ((a != NULL) || (b != NULL))
            {
637
                return false;
M
Max Bruckner 已提交
638 639 640
            }
            else
            {
641
                return true;
M
Max Bruckner 已提交
642
            }
643

M
Max Bruckner 已提交
644 645 646
        default:
            break;
    }
M
Max Bruckner 已提交
647

M
Max Bruckner 已提交
648
    /* null, true or false */
649
    return true;
650 651
}

652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
/* non broken version of cJSON_InsertItemInArray */
static cJSON_bool insert_item_in_array(cJSON *array, size_t which, cJSON *newitem)
{
    cJSON *child = array->child;
    while (child && (which > 0))
    {
        child = child->next;
        which--;
    }
    if (which > 0)
    {
        /* item is after the end of the array */
        return 0;
    }
    if (child == NULL)
    {
        cJSON_AddItemToArray(array, newitem);
        return 1;
    }

    /* insert into the linked list */
    newitem->next = child;
    newitem->prev = child->prev;
    child->prev = newitem;

    /* was it at the beginning */
    if (child == array->child)
    {
        array->child = newitem;
    }
    else
    {
        newitem->prev->next = newitem;
    }

    return 1;
}

690 691 692 693 694 695 696 697 698 699
static cJSON *get_object_item(const cJSON * const object, const char* name, const cJSON_bool case_sensitive)
{
    if (case_sensitive)
    {
        return cJSON_GetObjectItemCaseSensitive(object, name);
    }

    return cJSON_GetObjectItem(object, name);
}

M
Max Bruckner 已提交
700 701
enum patch_operation { INVALID, ADD, REMOVE, REPLACE, MOVE, COPY, TEST };

702
static enum patch_operation decode_patch_operation(const cJSON * const patch, const cJSON_bool case_sensitive)
703
{
704
    cJSON *operation = get_object_item(patch, "op", case_sensitive);
M
Max Bruckner 已提交
705 706 707 708
    if (!cJSON_IsString(operation))
    {
        return INVALID;
    }
709

M
Max Bruckner 已提交
710
    if (strcmp(operation->valuestring, "add") == 0)
M
Max Bruckner 已提交
711
    {
M
Max Bruckner 已提交
712
        return ADD;
M
Max Bruckner 已提交
713
    }
714

M
Max Bruckner 已提交
715
    if (strcmp(operation->valuestring, "remove") == 0)
M
Max Bruckner 已提交
716
    {
M
Max Bruckner 已提交
717
        return REMOVE;
M
Max Bruckner 已提交
718
    }
M
Max Bruckner 已提交
719 720

    if (strcmp(operation->valuestring, "replace") == 0)
M
Max Bruckner 已提交
721
    {
M
Max Bruckner 已提交
722
        return REPLACE;
M
Max Bruckner 已提交
723
    }
M
Max Bruckner 已提交
724 725

    if (strcmp(operation->valuestring, "move") == 0)
M
Max Bruckner 已提交
726
    {
M
Max Bruckner 已提交
727
        return MOVE;
M
Max Bruckner 已提交
728
    }
M
Max Bruckner 已提交
729 730

    if (strcmp(operation->valuestring, "copy") == 0)
M
Max Bruckner 已提交
731
    {
M
Max Bruckner 已提交
732
        return COPY;
M
Max Bruckner 已提交
733
    }
M
Max Bruckner 已提交
734 735

    if (strcmp(operation->valuestring, "test") == 0)
M
Max Bruckner 已提交
736
    {
M
Max Bruckner 已提交
737
        return TEST;
M
Max Bruckner 已提交
738
    }
M
Max Bruckner 已提交
739 740 741 742 743 744 745 746

    return INVALID;
}

/* overwrite and existing item with another one and free resources on the way */
static void overwrite_item(cJSON * const root, const cJSON replacement)
{
    if (root == NULL)
M
Max Bruckner 已提交
747
    {
M
Max Bruckner 已提交
748
        return;
M
Max Bruckner 已提交
749
    }
M
Max Bruckner 已提交
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766

    if (root->string != NULL)
    {
        cJSON_free(root->string);
    }
    if (root->valuestring != NULL)
    {
        cJSON_free(root->valuestring);
    }
    if (root->child != NULL)
    {
        cJSON_Delete(root->child);
    }

    memcpy(root, &replacement, sizeof(cJSON));
}

767
static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_sensitive)
M
Max Bruckner 已提交
768 769 770 771 772 773 774 775 776
{
    cJSON *path = NULL;
    cJSON *value = NULL;
    cJSON *parent = NULL;
    enum patch_operation opcode = INVALID;
    unsigned char *parent_pointer = NULL;
    unsigned char *child_pointer = NULL;
    int status = 0;

777
    path = get_object_item(patch, "path", case_sensitive);
M
Max Bruckner 已提交
778
    if (!cJSON_IsString(path))
M
Max Bruckner 已提交
779
    {
M
Max Bruckner 已提交
780 781 782 783 784
        /* malformed patch. */
        status = 2;
        goto cleanup;
    }

785
    opcode = decode_patch_operation(patch, case_sensitive);
M
Max Bruckner 已提交
786 787 788 789 790 791 792 793
    if (opcode == INVALID)
    {
        status = 3;
        goto cleanup;
    }
    else if (opcode == TEST)
    {
        /* compare value: {...} with the given path */
794
        status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), get_object_item(patch, "value", case_sensitive), case_sensitive);
M
Max Bruckner 已提交
795
        goto cleanup;
M
Max Bruckner 已提交
796
    }
797

798 799 800 801 802
    /* special case for replacing the root */
    if (path->valuestring[0] == '\0')
    {
        if (opcode == REMOVE)
        {
M
Max Bruckner 已提交
803
            static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL};
804

M
Max Bruckner 已提交
805
            overwrite_item(object, invalid);
806

M
Max Bruckner 已提交
807 808
            status = 0;
            goto cleanup;
809 810 811 812
        }

        if ((opcode == REPLACE) || (opcode == ADD))
        {
813
            value = get_object_item(patch, "value", case_sensitive);
814 815 816
            if (value == NULL)
            {
                /* missing "value" for add/replace. */
M
Max Bruckner 已提交
817 818
                status = 7;
                goto cleanup;
819 820 821 822 823 824
            }

            value = cJSON_Duplicate(value, 1);
            if (value == NULL)
            {
                /* out of memory for add/replace. */
M
Max Bruckner 已提交
825 826
                status = 8;
                goto cleanup;
827 828
            }

M
Max Bruckner 已提交
829
            overwrite_item(object, *value);
830 831 832

            /* delete the duplicated value */
            cJSON_free(value);
M
Max Bruckner 已提交
833
            value = NULL;
834

M
Max Bruckner 已提交
835 836 837 838 839 840 841 842 843
            /* the string "value" isn't needed */
            if (object->string != NULL)
            {
                cJSON_free(object->string);
                object->string = NULL;
            }

            status = 0;
            goto cleanup;
844 845 846
        }
    }

M
Max Bruckner 已提交
847
    if ((opcode == REMOVE) || (opcode == REPLACE))
M
Max Bruckner 已提交
848 849
    {
        /* Get rid of old. */
850
        cJSON *old_item = detach_path(object, (unsigned char*)path->valuestring, case_sensitive);
851 852
        if (old_item == NULL)
        {
M
Max Bruckner 已提交
853 854
            status = 13;
            goto cleanup;
855 856
        }
        cJSON_Delete(old_item);
M
Max Bruckner 已提交
857
        if (opcode == REMOVE)
M
Max Bruckner 已提交
858
        {
859
            /* For Remove, this job is done. */
M
Max Bruckner 已提交
860 861
            status = 0;
            goto cleanup;
M
Max Bruckner 已提交
862 863
        }
    }
864

M
Max Bruckner 已提交
865
    /* Copy/Move uses "from". */
M
Max Bruckner 已提交
866
    if ((opcode == MOVE) || (opcode == COPY))
M
Max Bruckner 已提交
867
    {
868
        cJSON *from = get_object_item(patch, "from", case_sensitive);
M
Max Bruckner 已提交
869
        if (from == NULL)
M
Max Bruckner 已提交
870 871
        {
            /* missing "from" for copy/move. */
M
Max Bruckner 已提交
872 873
            status = 4;
            goto cleanup;
M
Max Bruckner 已提交
874
        }
875

M
Max Bruckner 已提交
876
        if (opcode == MOVE)
M
Max Bruckner 已提交
877
        {
878
            value = detach_path(object, (unsigned char*)from->valuestring, case_sensitive);
M
Max Bruckner 已提交
879
        }
M
Max Bruckner 已提交
880
        if (opcode == COPY)
M
Max Bruckner 已提交
881
        {
882
            value = get_item_from_pointer(object, from->valuestring, case_sensitive);
M
Max Bruckner 已提交
883
        }
M
Max Bruckner 已提交
884
        if (value == NULL)
M
Max Bruckner 已提交
885 886
        {
            /* missing "from" for copy/move. */
M
Max Bruckner 已提交
887 888
            status = 5;
            goto cleanup;
M
Max Bruckner 已提交
889
        }
M
Max Bruckner 已提交
890
        if (opcode == COPY)
M
Max Bruckner 已提交
891 892 893
        {
            value = cJSON_Duplicate(value, 1);
        }
M
Max Bruckner 已提交
894
        if (value == NULL)
M
Max Bruckner 已提交
895 896
        {
            /* out of memory for copy/move. */
M
Max Bruckner 已提交
897 898
            status = 6;
            goto cleanup;
M
Max Bruckner 已提交
899 900 901 902
        }
    }
    else /* Add/Replace uses "value". */
    {
903
        value = get_object_item(patch, "value", case_sensitive);
M
Max Bruckner 已提交
904
        if (value == NULL)
M
Max Bruckner 已提交
905 906
        {
            /* missing "value" for add/replace. */
M
Max Bruckner 已提交
907 908
            status = 7;
            goto cleanup;
M
Max Bruckner 已提交
909 910
        }
        value = cJSON_Duplicate(value, 1);
M
Max Bruckner 已提交
911
        if (value == NULL)
M
Max Bruckner 已提交
912 913
        {
            /* out of memory for add/replace. */
M
Max Bruckner 已提交
914 915
            status = 8;
            goto cleanup;
M
Max Bruckner 已提交
916 917
        }
    }
918

M
Max Bruckner 已提交
919
    /* Now, just add "value" to "path". */
920

M
Max Bruckner 已提交
921
    /* split pointer in parent and child */
M
Max Bruckner 已提交
922 923 924
    parent_pointer = cJSONUtils_strdup((unsigned char*)path->valuestring);
    child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/');
    if (child_pointer != NULL)
M
Max Bruckner 已提交
925
    {
M
Max Bruckner 已提交
926 927
        child_pointer[0] = '\0';
        child_pointer++;
M
Max Bruckner 已提交
928
    }
929
    parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive);
930
    decode_pointer_inplace(child_pointer);
931

M
Max Bruckner 已提交
932
    /* add, remove, replace, move, copy, test. */
M
Max Bruckner 已提交
933
    if ((parent == NULL) || (child_pointer == NULL))
M
Max Bruckner 已提交
934 935
    {
        /* Couldn't find object to add to. */
M
Max Bruckner 已提交
936 937
        status = 9;
        goto cleanup;
M
Max Bruckner 已提交
938
    }
939
    else if (cJSON_IsArray(parent))
M
Max Bruckner 已提交
940
    {
M
Max Bruckner 已提交
941
        if (strcmp((char*)child_pointer, "-") == 0)
M
Max Bruckner 已提交
942 943
        {
            cJSON_AddItemToArray(parent, value);
M
Max Bruckner 已提交
944
            value = NULL;
M
Max Bruckner 已提交
945 946 947
        }
        else
        {
948
            size_t index = 0;
M
Max Bruckner 已提交
949
            if (!decode_array_index_from_pointer(child_pointer, &index))
950
            {
M
Max Bruckner 已提交
951 952
                status = 11;
                goto cleanup;
953 954
            }

955
            if (!insert_item_in_array(parent, index, value))
956
            {
M
Max Bruckner 已提交
957 958
                status = 10;
                goto cleanup;
959
            }
M
Max Bruckner 已提交
960
            value = NULL;
M
Max Bruckner 已提交
961 962
        }
    }
963
    else if (cJSON_IsObject(parent))
M
Max Bruckner 已提交
964
    {
965 966 967 968 969 970 971 972
        if (case_sensitive)
        {
            cJSON_DeleteItemFromObjectCaseSensitive(parent, (char*)child_pointer);
        }
        else
        {
            cJSON_DeleteItemFromObject(parent, (char*)child_pointer);
        }
M
Max Bruckner 已提交
973 974
        cJSON_AddItemToObject(parent, (char*)child_pointer, value);
        value = NULL;
M
Max Bruckner 已提交
975
    }
M
Max Bruckner 已提交
976 977 978

cleanup:
    if (value != NULL)
M
Max Bruckner 已提交
979 980 981
    {
        cJSON_Delete(value);
    }
M
Max Bruckner 已提交
982 983 984 985
    if (parent_pointer != NULL)
    {
        cJSON_free(parent_pointer);
    }
M
Max Bruckner 已提交
986

M
Max Bruckner 已提交
987
    return status;
M
Max Bruckner 已提交
988
}
989

M
Max Bruckner 已提交
990
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches)
991
{
M
Max Bruckner 已提交
992 993
    const cJSON *current_patch = NULL;
    int status = 0;
994

995
    if (!cJSON_IsArray(patches))
996 997 998 999
    {
        /* malformed patches. */
        return 1;
    }
M
Max Bruckner 已提交
1000 1001

    if (patches != NULL)
1002
    {
M
Max Bruckner 已提交
1003
        current_patch = patches->child;
1004
    }
M
Max Bruckner 已提交
1005 1006

    while (current_patch != NULL)
1007
    {
1008
        status = apply_patch(object, current_patch, false);
M
Max Bruckner 已提交
1009
        if (status != 0)
1010
        {
M
Max Bruckner 已提交
1011
            return status;
1012
        }
M
Max Bruckner 已提交
1013
        current_patch = current_patch->next;
1014 1015 1016
    }

    return 0;
1017
}
1018

1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches)
{
    const cJSON *current_patch = NULL;
    int status = 0;

    if (!cJSON_IsArray(patches))
    {
        /* malformed patches. */
        return 1;
    }

    if (patches != NULL)
    {
        current_patch = patches->child;
    }

    while (current_patch != NULL)
    {
        status = apply_patch(object, current_patch, true);
        if (status != 0)
        {
            return status;
        }
        current_patch = current_patch->next;
    }

    return 0;
}

1048
static void compose_patch(cJSON * const patches, const unsigned char * const operation, const unsigned char * const path, const unsigned char *suffix, const cJSON * const value)
1049
{
1050 1051 1052 1053 1054 1055 1056 1057
    cJSON *patch = NULL;

    if ((patches == NULL) || (operation == NULL) || (path == NULL))
    {
        return;
    }

    patch = cJSON_CreateObject();
M
Max Bruckner 已提交
1058
    if (patch == NULL)
1059
    {
M
Max Bruckner 已提交
1060
        return;
1061
    }
M
Max Bruckner 已提交
1062 1063 1064
    cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)operation));

    if (suffix == NULL)
1065
    {
1066
        cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path));
1067
    }
M
Max Bruckner 已提交
1068 1069
    else
    {
1070
        size_t suffix_length = pointer_encoded_length(suffix);
M
Max Bruckner 已提交
1071 1072 1073 1074
        size_t path_length = strlen((const char*)path);
        unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/"));

        sprintf((char*)full_path, "%s/", (const char*)path);
1075
        encode_string_as_pointer(full_path + path_length + 1, suffix);
M
Max Bruckner 已提交
1076 1077

        cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)full_path));
C
crhackos 已提交
1078
        cJSON_free(full_path);
M
Max Bruckner 已提交
1079 1080 1081
    }

    if (value != NULL)
1082
    {
M
Max Bruckner 已提交
1083
        cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(value, 1));
1084 1085
    }
    cJSON_AddItemToArray(patches, patch);
1086 1087
}

1088
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value)
M
Max Bruckner 已提交
1089
{
1090
    compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value);
M
Max Bruckner 已提交
1091
}
1092

1093
static void create_patches(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive)
1094
{
1095 1096 1097 1098 1099
    if ((from == NULL) || (to == NULL))
    {
        return;
    }

1100
    if ((from->type & 0xFF) != (to->type & 0xFF))
1101
    {
1102
        compose_patch(patches, (const unsigned char*)"replace", path, 0, to);
1103 1104 1105
        return;
    }

1106
    switch (from->type & 0xFF)
1107 1108 1109 1110
    {
        case cJSON_Number:
            if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble))
            {
1111
                compose_patch(patches, (const unsigned char*)"replace", path, NULL, to);
1112 1113 1114 1115
            }
            return;

        case cJSON_String:
M
Max Bruckner 已提交
1116
            if (strcmp(from->valuestring, to->valuestring) != 0)
1117
            {
1118
                compose_patch(patches, (const unsigned char*)"replace", path, NULL, to);
1119 1120
            }
            return;
1121

1122 1123
        case cJSON_Array:
        {
1124 1125 1126 1127 1128 1129 1130
            size_t index = 0;
            cJSON *from_child = from->child;
            cJSON *to_child = to->child;
            unsigned char *new_path = (unsigned char*)cJSON_malloc(strlen((const char*)path) + 20 + sizeof("/")); /* Allow space for 64bit int. log10(2^64) = 20 */

            /* generate patches for all array elements that exist in both "from" and "to" */
            for (index = 0; (from_child != NULL) && (to_child != NULL); (void)(from_child = from_child->next), (void)(to_child = to_child->next), index++)
1131
            {
1132 1133 1134
                /* check if conversion to unsigned long is valid
                 * This should be eliminated at compile time by dead code elimination
                 * if size_t is an alias of unsigned long, or if it is bigger */
1135
                if (index > ULONG_MAX)
1136
                {
C
crhackos 已提交
1137
                    cJSON_free(new_path);
1138 1139
                    return;
                }
1140
                sprintf((char*)new_path, "%s/%lu", path, (unsigned long)index); /* path of the current array element */
1141
                create_patches(patches, new_path, from_child, to_child, case_sensitive);
1142
            }
1143

1144
            /* remove leftover elements from 'from' that are not in 'to' */
1145
            for (; (from_child != NULL); (void)(from_child = from_child->next))
1146
            {
1147 1148 1149
                /* check if conversion to unsigned long is valid
                 * This should be eliminated at compile time by dead code elimination
                 * if size_t is an alias of unsigned long, or if it is bigger */
1150
                if (index > ULONG_MAX)
1151
                {
C
crhackos 已提交
1152
                    cJSON_free(new_path);
1153 1154
                    return;
                }
1155
                sprintf((char*)new_path, "%lu", (unsigned long)index);
1156
                compose_patch(patches, (const unsigned char*)"remove", path, new_path, NULL);
1157 1158
            }
            /* add new elements in 'to' that were not in 'from' */
1159
            for (; (to_child != NULL); (void)(to_child = to_child->next), index++)
1160
            {
1161
                compose_patch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to_child);
1162
            }
C
crhackos 已提交
1163
            cJSON_free(new_path);
1164 1165 1166 1167 1168
            return;
        }

        case cJSON_Object:
        {
1169 1170
            cJSON *from_child = NULL;
            cJSON *to_child = NULL;
1171 1172
            sort_object(from, case_sensitive);
            sort_object(to, case_sensitive);
1173

1174 1175
            from_child = from->child;
            to_child = to->child;
1176
            /* for all object values in the object with more of them */
1177
            while ((from_child != NULL) || (to_child != NULL))
1178
            {
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
                int diff;
                if (from_child == NULL)
                {
                    diff = 1;
                }
                else if (to_child == NULL)
                {
                    diff = -1;
                }
                else
                {
1190
                    diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, case_sensitive);
1191 1192 1193
                }

                if (diff == 0)
1194 1195
                {
                    /* both object keys are the same */
1196
                    size_t path_length = strlen((const char*)path);
1197
                    size_t from_child_name_length = pointer_encoded_length((unsigned char*)from_child->string);
1198 1199 1200
                    unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/"));

                    sprintf((char*)new_path, "%s/", path);
1201
                    encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string);
1202

1203
                    /* create a patch for the element */
1204
                    create_patches(patches, new_path, from_child, to_child, case_sensitive);
C
crhackos 已提交
1205
                    cJSON_free(new_path);
1206 1207 1208

                    from_child = from_child->next;
                    to_child = to_child->next;
1209 1210 1211 1212
                }
                else if (diff < 0)
                {
                    /* object element doesn't exist in 'to' --> remove it */
1213
                    compose_patch(patches, (const unsigned char*)"remove", path, (unsigned char*)from_child->string, NULL);
1214 1215

                    from_child = from_child->next;
1216 1217 1218 1219
                }
                else
                {
                    /* object element doesn't exist in 'from' --> add it */
1220
                    compose_patch(patches, (const unsigned char*)"add", path, (unsigned char*)to_child->string, to_child);
1221 1222

                    to_child = to_child->next;
1223 1224 1225 1226 1227 1228 1229 1230 1231
                }
            }
            return;
        }

        default:
            break;
    }
}
1232

1233
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to)
1234
{
1235 1236 1237 1238 1239 1240 1241 1242
    cJSON *patches = NULL;

    if ((from == NULL) || (to == NULL))
    {
        return NULL;
    }

    patches = cJSON_CreateArray();
1243
    create_patches(patches, (const unsigned char*)"", from, to, false);
1244

1245 1246
    return patches;
}
1247

1248 1249
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to)
{
1250 1251 1252 1253 1254 1255 1256 1257
    cJSON *patches = NULL;

    if ((from == NULL) || (to == NULL))
    {
        return NULL;
    }

    patches = cJSON_CreateArray();
1258 1259 1260 1261 1262
    create_patches(patches, (const unsigned char*)"", from, to, true);

    return patches;
}

1263
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object)
1264
{
1265
    sort_object(object, false);
1266 1267
}

1268
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object)
M
Max Bruckner 已提交
1269
{
1270
    sort_object(object, true);
M
Max Bruckner 已提交
1271
}
1272

1273
static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_bool case_sensitive)
1274
{
M
Max Bruckner 已提交
1275 1276
    cJSON *patch_child = NULL;

1277
    if (!cJSON_IsObject(patch))
M
Max Bruckner 已提交
1278 1279 1280 1281 1282
    {
        /* scalar value, array or NULL, just duplicate */
        cJSON_Delete(target);
        return cJSON_Duplicate(patch, 1);
    }
1283

1284
    if (!cJSON_IsObject(target))
M
Max Bruckner 已提交
1285 1286 1287 1288 1289
    {
        cJSON_Delete(target);
        target = cJSON_CreateObject();
    }

M
Max Bruckner 已提交
1290 1291
    patch_child = patch->child;
    while (patch_child != NULL)
M
Max Bruckner 已提交
1292
    {
M
Max Bruckner 已提交
1293
        if (cJSON_IsNull(patch_child))
M
Max Bruckner 已提交
1294 1295
        {
            /* NULL is the indicator to remove a value, see RFC7396 */
1296 1297 1298 1299 1300 1301 1302 1303
            if (case_sensitive)
            {
                cJSON_DeleteItemFromObjectCaseSensitive(target, patch_child->string);
            }
            else
            {
                cJSON_DeleteItemFromObject(target, patch_child->string);
            }
M
Max Bruckner 已提交
1304 1305 1306
        }
        else
        {
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
            cJSON *replace_me = NULL;
            cJSON *replacement = NULL;

            if (case_sensitive)
            {
                replace_me = cJSON_DetachItemFromObjectCaseSensitive(target, patch_child->string);
            }
            else
            {
                replace_me = cJSON_DetachItemFromObject(target, patch_child->string);
            }

            replacement = merge_patch(replace_me, patch_child, case_sensitive);
            if (replacement == NULL)
            {
                return NULL;
            }

            cJSON_AddItemToObject(target, patch_child->string, replacement);
M
Max Bruckner 已提交
1326
        }
M
Max Bruckner 已提交
1327
        patch_child = patch_child->next;
M
Max Bruckner 已提交
1328 1329
    }
    return target;
1330
}
1331

1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch)
{
    return merge_patch(target, patch, false);
}

CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch)
{
    return merge_patch(target, patch, true);
}

1342
static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive)
1343
{
1344 1345
    cJSON *from_child = NULL;
    cJSON *to_child = NULL;
1346
    cJSON *patch = NULL;
1347
    if (to == NULL)
1348 1349 1350 1351
    {
        /* patch to delete everything */
        return cJSON_CreateNull();
    }
1352
    if (!cJSON_IsObject(to) || !cJSON_IsObject(from))
1353 1354 1355 1356
    {
        return cJSON_Duplicate(to, 1);
    }

1357 1358
    sort_object(from, case_sensitive);
    sort_object(to, case_sensitive);
1359

1360 1361
    from_child = from->child;
    to_child = to->child;
1362
    patch = cJSON_CreateObject();
1363
    while (from_child || to_child)
1364
    {
1365 1366 1367 1368 1369
        int diff;
        if (from_child != NULL)
        {
            if (to_child != NULL)
            {
M
Max Bruckner 已提交
1370
                diff = strcmp(from_child->string, to_child->string);
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
            }
            else
            {
                diff = -1;
            }
        }
        else
        {
            diff = 1;
        }

        if (diff < 0)
1383 1384
        {
            /* from has a value that to doesn't have -> remove */
1385 1386 1387
            cJSON_AddItemToObject(patch, from_child->string, cJSON_CreateNull());

            from_child = from_child->next;
1388
        }
1389
        else if (diff > 0)
1390 1391
        {
            /* to has a value that from doesn't have -> add to patch */
1392 1393 1394
            cJSON_AddItemToObject(patch, to_child->string, cJSON_Duplicate(to_child, 1));

            to_child = to_child->next;
1395 1396 1397 1398
        }
        else
        {
            /* object key exists in both objects */
1399
            if (!compare_json(from_child, to_child, case_sensitive))
1400 1401
            {
                /* not identical --> generate a patch */
1402
                cJSON_AddItemToObject(patch, to_child->string, cJSONUtils_GenerateMergePatch(from_child, to_child));
1403
            }
1404

1405
            /* next key in the object */
1406 1407
            from_child = from_child->next;
            to_child = to_child->next;
1408 1409
        }
    }
1410
    if (patch->child == NULL)
1411
    {
1412
        /* no patch generated */
1413
        cJSON_Delete(patch);
1414
        return NULL;
1415 1416 1417
    }

    return patch;
M
Max Bruckner 已提交
1418
}
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428

CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to)
{
    return generate_merge_patch(from, to, false);
}

CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to)
{
    return generate_merge_patch(from, to, true);
}