cJSON_Utils.c 23.8 KB
Newer Older
1
#pragma GCC visibility push(default)
2
#include <ctype.h>
3 4
#include <string.h>
#include <stdlib.h>
5
#include <stdio.h>
M
Max Bruckner 已提交
6
#include <limits.h>
7
#pragma GCC visibility pop
M
Max Bruckner 已提交
8

9 10
#include "cJSON_Utils.h"

11
static unsigned char* cJSONUtils_strdup(const unsigned char* str)
12
{
M
Max Bruckner 已提交
13
    size_t len = 0;
14
    unsigned char *copy = NULL;
15

16 17
    len = strlen((const char*)str) + 1;
    if (!(copy = (unsigned char*)malloc(len)))
18
    {
19
        return NULL;
20 21 22 23 24 25
    }
    memcpy(copy, str, len);

    return copy;
}

26
static int cJSONUtils_strcasecmp(const unsigned char *s1, const unsigned char *s2)
27
{
M
Max Bruckner 已提交
28 29 30 31 32 33 34 35
    if (!s1)
    {
        return (s1 == s2) ? 0 : 1; /* both NULL? */
    }
    if (!s2)
    {
        return 1;
    }
M
Max Bruckner 已提交
36
    for(; tolower(*s1) == tolower(*s2); (void)++s1, ++s2)
M
Max Bruckner 已提交
37 38 39 40 41 42 43
    {
        if(*s1 == 0)
        {
            return 0;
        }
    }

44
    return tolower(*s1) - tolower(*s2);
45 46
}

47
/* JSON Pointer implementation: */
48
static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e)
49
{
50 51 52 53
    if (!a || !e)
    {
        return (a == e) ? 0 : 1; /* both NULL? */
    }
M
Max Bruckner 已提交
54
    for (; *a && *e && (*e != '/'); (void)a++, e++) /* compare until next '/' */
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    {
        if (*e == '~')
        {
            /* check for escaped '~' (~0) and '/' (~1) */
            if (!((e[1] == '0') && (*a == '~')) && !((e[1] == '1') && (*a == '/')))
            {
                /* invalid escape sequence or wrong character in *a */
                return 1;
            }
            else
            {
                e++;
            }
        }
        else if (tolower(*a) != tolower(*e))
        {
            return 1;
        }
    }
    if (((*e != 0) && (*e != '/')) != (*a != 0))
    {
        /* one string has ended, the other not */
        return 1;
    }

    return 0;
81 82
}

83
static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *s)
84
{
85
    size_t l = 0;
M
Max Bruckner 已提交
86
    for (; *s; (void)s++, l++)
87 88 89 90 91 92 93 94 95
    {
        if ((*s == '~') || (*s == '/'))
        {
            l++;
        }
    }

    return l;
}
96

97
static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned char *s)
98
{
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    for (; *s; s++)
    {
        if (*s == '/')
        {
            *d++ = '~';
            *d++ = '1';
        }
        else if (*s == '~')
        {
            *d++ = '~';
            *d++ = '0';
        }
        else
        {
            *d++ = *s;
        }
    }

    *d = '\0';
118 119
}

120
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
121
{
122
    size_t c = 0;
123
    cJSON *obj = 0;
124

125 126 127
    if (object == target)
    {
        /* found */
128
        return (char*)cJSONUtils_strdup((const unsigned char*)"");
129
    }
130

131
    /* recursively search all children of the object */
M
Max Bruckner 已提交
132
    for (obj = object->child; obj; (void)(obj = obj->next), c++)
133
    {
134
        unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target);
135 136
        if (found)
        {
137
            if (cJSON_IsArray(object))
138 139
            {
                /* reserve enough memory for a 64 bit integer + '/' and '\0' */
140
                unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23);
141 142 143 144 145 146 147 148
                /* check if conversion to unsigned long is valid
                 * This should be eliminated at compile time by dead code elimination
                 * if size_t is an alias of unsigned long, or if it is bigger */
                if (c > ULONG_MAX)
                {
                    free(found);
                    return NULL;
                }
149
                sprintf((char*)ret, "/%lu%s", (unsigned long)c, found); /* /<array_index><path> */
150 151
                free(found);

152
                return (char*)ret;
153
            }
154
            else if (cJSON_IsObject(object))
155
            {
156
                unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2);
157
                *ret = '/';
158 159
                cJSONUtils_PointerEncodedstrcpy(ret + 1, (unsigned char*)obj->string);
                strcat((char*)ret, (char*)found);
160 161
                free(found);

162
                return (char*)ret;
163 164 165 166
            }

            /* reached leaf of the tree, found nothing */
            free(found);
167
            return NULL;
168 169 170 171
        }
    }

    /* not found */
172
    return NULL;
173 174
}

175
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer)
176
{
177 178 179
    /* follow path of the pointer */
    while ((*pointer++ == '/') && object)
    {
180
        if (cJSON_IsArray(object))
181
        {
182
            size_t which = 0;
183 184 185
            /* parse array index */
            while ((*pointer >= '0') && (*pointer <= '9'))
            {
M
Max Bruckner 已提交
186
                which = (10 * which) + (size_t)(*pointer++ - '0');
187 188 189 190
            }
            if (*pointer && (*pointer != '/'))
            {
                /* not end of string or new path token */
191
                return NULL;
192
            }
M
Max Bruckner 已提交
193 194 195 196 197
            if (which > INT_MAX)
            {
                return NULL;
            }
            object = cJSON_GetArrayItem(object, (int)which);
198
        }
199
        else if (cJSON_IsObject(object))
200 201 202
        {
            object = object->child;
            /* GetObjectItem. */
203
            while (object && cJSONUtils_Pstrcasecmp((unsigned char*)object->string, (const unsigned char*)pointer))
204 205 206 207 208 209 210 211 212 213 214
            {
                object = object->next;
            }
            /* skip to the next path token or end of string */
            while (*pointer && (*pointer != '/'))
            {
                pointer++;
            }
        }
        else
        {
215
            return NULL;
216 217 218 219
        }
    }

    return object;
220 221
}

222
/* JSON Patch implementation. */
223
static void cJSONUtils_InplaceDecodePointerString(unsigned char *string)
224
{
225
    unsigned char *s2 = string;
226 227 228 229 230

    if (string == NULL) {
        return;
    }

M
Max Bruckner 已提交
231
    for (; *string; (void)s2++, string++)
232
    {
233
        *s2 = (unsigned char) ((*string != '~')
234 235 236
            ? (*string)
            : ((*(++string) == '0')
                    ? '~'
237
                    : '/'));
238 239 240
    }

    *s2 = '\0';
241 242
}

243
static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path)
244
{
245 246
    unsigned char *parentptr = NULL;
    unsigned char *childptr = NULL;
247 248
    cJSON *parent = NULL;
    cJSON *ret = NULL;
249 250

    /* copy path and split it in parent and child */
251
    parentptr = cJSONUtils_strdup(path);
252 253 254 255
    if (parentptr == NULL) {
        return NULL;
    }

256
    childptr = (unsigned char*)strrchr((char*)parentptr, '/'); /* last '/' */
257
    if (childptr == NULL)
258
    {
259 260
        free(parentptr);
        return NULL;
261
    }
262 263 264
    /* split strings */
    *childptr++ = '\0';

265
    parent = cJSONUtils_GetPointer(object, (char*)parentptr);
266
    cJSONUtils_InplaceDecodePointerString(childptr);
267

268 269 270
    if (!parent)
    {
        /* Couldn't find object to remove child from. */
271
        ret = NULL;
272
    }
273
    else if (cJSON_IsArray(parent))
274
    {
275
        ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr));
276
    }
277
    else if (cJSON_IsObject(parent))
278
    {
279
        ret = cJSON_DetachItemFromObject(parent, (char*)childptr);
280 281
    }
    free(parentptr);
282

283 284
    /* return the detachted item */
    return ret;
285 286
}

M
Max Bruckner 已提交
287
static int cJSONUtils_Compare(cJSON *a, cJSON *b)
288
{
289
    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
M
Max Bruckner 已提交
290 291 292 293
    {
        /* mismatched type. */
        return -1;
    }
294
    switch (a->type & 0xFF)
M
Max Bruckner 已提交
295 296 297 298 299 300 301 302
    {
        case cJSON_Number:
            /* numeric mismatch. */
            return ((a->valueint != b->valueint) || (a->valuedouble != b->valuedouble)) ? -2 : 0;
        case cJSON_String:
            /* string mismatch. */
            return (strcmp(a->valuestring, b->valuestring) != 0) ? -3 : 0;
        case cJSON_Array:
M
Max Bruckner 已提交
303
            for ((void)(a = a->child), b = b->child; a && b; (void)(a = a->next), b = b->next)
M
Max Bruckner 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
            {
                int err = cJSONUtils_Compare(a, b);
                if (err)
                {
                    return err;
                }
            }
            /* array size mismatch? (one of both children is not NULL) */
            return (a || b) ? -4 : 0;
        case cJSON_Object:
            cJSONUtils_SortObject(a);
            cJSONUtils_SortObject(b);
            a = a->child;
            b = b->child;
            while (a && b)
            {
M
Max Bruckner 已提交
320
                int err = 0;
M
Max Bruckner 已提交
321
                /* compare object keys */
322
                if (cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string))
M
Max Bruckner 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336
                {
                    /* missing member */
                    return -6;
                }
                err = cJSONUtils_Compare(a, b);
                if (err)
                {
                    return err;
                }
                a = a->next;
                b = b->next;
            }
            /* object length mismatch (one of both children is not null) */
            return (a || b) ? -5 : 0;
337

M
Max Bruckner 已提交
338 339 340 341 342
        default:
            break;
    }
    /* null, true or false */
    return 0;
343 344
}

M
Max Bruckner 已提交
345
static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
346
{
347 348 349 350
    cJSON *op = NULL;
    cJSON *path = NULL;
    cJSON *value = NULL;
    cJSON *parent = NULL;
M
Max Bruckner 已提交
351
    int opcode = 0;
352 353
    unsigned char *parentptr = NULL;
    unsigned char *childptr = NULL;
354

M
Max Bruckner 已提交
355 356 357 358 359 360 361
    op = cJSON_GetObjectItem(patch, "op");
    path = cJSON_GetObjectItem(patch, "path");
    if (!op || !path)
    {
        /* malformed patch. */
        return 2;
    }
362

M
Max Bruckner 已提交
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 390 391 392 393
    /* decode operation */
    if (!strcmp(op->valuestring, "add"))
    {
        opcode = 0;
    }
    else if (!strcmp(op->valuestring, "remove"))
    {
        opcode = 1;
    }
    else if (!strcmp(op->valuestring, "replace"))
    {
        opcode = 2;
    }
    else if (!strcmp(op->valuestring, "move"))
    {
        opcode = 3;
    }
    else if (!strcmp(op->valuestring, "copy"))
    {
        opcode = 4;
    }
    else if (!strcmp(op->valuestring, "test"))
    {
        /* compare value: {...} with the given path */
        return cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value"));
    }
    else
    {
        /* unknown opcode. */
        return 3;
    }
394

M
Max Bruckner 已提交
395 396 397 398
    /* Remove/Replace */
    if ((opcode == 1) || (opcode == 2))
    {
        /* Get rid of old. */
399
        cJSON_Delete(cJSONUtils_PatchDetach(object, (unsigned char*)path->valuestring));
M
Max Bruckner 已提交
400 401 402 403 404 405
        if (opcode == 1)
        {
            /* For Remove, this is job done. */
            return 0;
        }
    }
406

M
Max Bruckner 已提交
407 408 409 410 411 412 413 414 415
    /* Copy/Move uses "from". */
    if ((opcode == 3) || (opcode == 4))
    {
        cJSON *from = cJSON_GetObjectItem(patch, "from");
        if (!from)
        {
            /* missing "from" for copy/move. */
            return 4;
        }
416

M
Max Bruckner 已提交
417 418 419
        if (opcode == 3)
        {
            /* move */
420
            value = cJSONUtils_PatchDetach(object, (unsigned char*)from->valuestring);
M
Max Bruckner 已提交
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
        }
        if (opcode == 4)
        {
            /* copy */
            value = cJSONUtils_GetPointer(object, from->valuestring);
        }
        if (!value)
        {
            /* missing "from" for copy/move. */
            return 5;
        }
        if (opcode == 4)
        {
            value = cJSON_Duplicate(value, 1);
        }
        if (!value)
        {
            /* out of memory for copy/move. */
            return 6;
        }
    }
    else /* Add/Replace uses "value". */
    {
        value = cJSON_GetObjectItem(patch, "value");
        if (!value)
        {
            /* missing "value" for add/replace. */
            return 7;
        }
        value = cJSON_Duplicate(value, 1);
        if (!value)
        {
            /* out of memory for add/replace. */
            return 8;
        }
    }
457

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

M
Max Bruckner 已提交
460
    /* split pointer in parent and child */
461 462
    parentptr = cJSONUtils_strdup((unsigned char*)path->valuestring);
    childptr = (unsigned char*)strrchr((char*)parentptr, '/');
M
Max Bruckner 已提交
463 464 465 466
    if (childptr)
    {
        *childptr++ = '\0';
    }
467
    parent = cJSONUtils_GetPointer(object, (char*)parentptr);
M
Max Bruckner 已提交
468
    cJSONUtils_InplaceDecodePointerString(childptr);
469

M
Max Bruckner 已提交
470 471 472 473 474 475 476 477
    /* add, remove, replace, move, copy, test. */
    if (!parent)
    {
        /* Couldn't find object to add to. */
        free(parentptr);
        cJSON_Delete(value);
        return 9;
    }
478
    else if (cJSON_IsArray(parent))
M
Max Bruckner 已提交
479
    {
480
        if (!strcmp((char*)childptr, "-"))
M
Max Bruckner 已提交
481 482 483 484 485
        {
            cJSON_AddItemToArray(parent, value);
        }
        else
        {
486
            cJSON_InsertItemInArray(parent, atoi((char*)childptr), value);
M
Max Bruckner 已提交
487 488
        }
    }
489
    else if (cJSON_IsObject(parent))
M
Max Bruckner 已提交
490
    {
491 492
        cJSON_DeleteItemFromObject(parent, (char*)childptr);
        cJSON_AddItemToObject(parent, (char*)childptr, value);
M
Max Bruckner 已提交
493 494 495 496 497 498 499 500 501
    }
    else
    {
        cJSON_Delete(value);
    }
    free(parentptr);

    return 0;
}
502

503
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
504
{
M
Max Bruckner 已提交
505
    int err = 0;
506 507 508 509 510 511

    if (patches == NULL)
    {
        return 1;
    }

512
    if (cJSON_IsArray(patches))
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    {
        /* malformed patches. */
        return 1;
    }
    if (patches)
    {
        patches = patches->child;
    }
    while (patches)
    {
        if ((err = cJSONUtils_ApplyPatch(object, patches)))
        {
            return err;
        }
        patches = patches->next;
    }

    return 0;
531
}
532

533
static void cJSONUtils_GeneratePatch(cJSON *patches, const unsigned char *op, const unsigned char *path, const unsigned char *suffix, cJSON *val)
534
{
535
    cJSON *patch = cJSON_CreateObject();
536
    cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)op));
537 538
    if (suffix)
    {
539 540 541
        unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen(suffix) + 2);
        cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", (const char*)path), suffix);
        cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)newpath));
542 543 544 545
        free(newpath);
    }
    else
    {
546
        cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path));
547 548 549 550 551 552
    }
    if (val)
    {
        cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(val, 1));
    }
    cJSON_AddItemToArray(patches, patch);
553 554
}

555
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val)
M
Max Bruckner 已提交
556
{
557
    cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val);
M
Max Bruckner 已提交
558
}
559

560
static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, cJSON *from, cJSON *to)
561
{
562 563 564 565 566
    if ((from == NULL) || (to == NULL))
    {
        return;
    }

567
    if ((from->type & 0xFF) != (to->type & 0xFF))
568
    {
569
        cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
570 571 572
        return;
    }

573
    switch ((from->type & 0xFF))
574 575 576 577
    {
        case cJSON_Number:
            if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble))
            {
578
                cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
579 580 581 582 583 584
            }
            return;

        case cJSON_String:
            if (strcmp(from->valuestring, to->valuestring) != 0)
            {
585
                cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
586 587
            }
            return;
588

589 590
        case cJSON_Array:
        {
591
            size_t c = 0;
592
            unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + 23); /* Allow space for 64bit int. */
593
            /* generate patches for all array elements that exist in "from" and "to" */
M
Max Bruckner 已提交
594
            for ((void)(c = 0), (void)(from = from->child), to = to->child; from && to; (void)(from = from->next), (void)(to = to->next), c++)
595
            {
596 597 598 599 600 601 602 603
                /* check if conversion to unsigned long is valid
                 * This should be eliminated at compile time by dead code elimination
                 * if size_t is an alias of unsigned long, or if it is bigger */
                if (c > ULONG_MAX)
                {
                    free(newpath);
                    return;
                }
604
                sprintf((char*)newpath, "%s/%lu", path, (unsigned long)c); /* path of the current array element */
605 606 607
                cJSONUtils_CompareToPatch(patches, newpath, from, to);
            }
            /* remove leftover elements from 'from' that are not in 'to' */
M
Max Bruckner 已提交
608
            for (; from; (void)(from = from->next), c++)
609
            {
610 611 612 613 614 615 616 617
                /* check if conversion to unsigned long is valid
                 * This should be eliminated at compile time by dead code elimination
                 * if size_t is an alias of unsigned long, or if it is bigger */
                if (c > ULONG_MAX)
                {
                    free(newpath);
                    return;
                }
618
                sprintf((char*)newpath, "%lu", (unsigned long)c);
619
                cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, newpath, 0);
620 621
            }
            /* add new elements in 'to' that were not in 'from' */
M
Max Bruckner 已提交
622
            for (; to; (void)(to = to->next), c++)
623
            {
624
                cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to);
625 626 627 628 629 630 631
            }
            free(newpath);
            return;
        }

        case cJSON_Object:
        {
M
Max Bruckner 已提交
632 633
            cJSON *a = NULL;
            cJSON *b = NULL;
634 635 636 637 638 639 640 641
            cJSONUtils_SortObject(from);
            cJSONUtils_SortObject(to);

            a = from->child;
            b = to->child;
            /* for all object values in the object with more of them */
            while (a || b)
            {
642
                int diff = (!a) ? 1 : ((!b) ? -1 : cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string));
643 644 645
                if (!diff)
                {
                    /* both object keys are the same */
646 647
                    unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen((unsigned char*)a->string) + 2);
                    cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", path), (unsigned char*)a->string);
648 649 650 651 652 653 654 655 656
                    /* create a patch for the element */
                    cJSONUtils_CompareToPatch(patches, newpath, a, b);
                    free(newpath);
                    a = a->next;
                    b = b->next;
                }
                else if (diff < 0)
                {
                    /* object element doesn't exist in 'to' --> remove it */
657
                    cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, (unsigned char*)a->string, 0);
658 659 660 661 662
                    a = a->next;
                }
                else
                {
                    /* object element doesn't exist in 'from' --> add it */
663
                    cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (unsigned char*)b->string, b);
664 665 666 667 668 669 670 671 672 673
                    b = b->next;
                }
            }
            return;
        }

        default:
            break;
    }
}
674

675
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to)
676
{
677
    cJSON *patches = cJSON_CreateArray();
678
    cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to);
679

680 681
    return patches;
}
682

M
Max Bruckner 已提交
683
/* sort lists using mergesort */
684 685
static cJSON *cJSONUtils_SortList(cJSON *list)
{
M
Max Bruckner 已提交
686 687 688
    cJSON *first = list;
    cJSON *second = list;
    cJSON *ptr = list;
689

M
Max Bruckner 已提交
690 691 692 693 694
    if (!list || !list->next)
    {
        /* One entry is sorted already. */
        return list;
    }
695

696
    while (ptr && ptr->next && (cJSONUtils_strcasecmp((unsigned char*)ptr->string, (unsigned char*)ptr->next->string) < 0))
M
Max Bruckner 已提交
697 698 699 700 701 702 703 704 705
    {
        /* Test for list sorted. */
        ptr = ptr->next;
    }
    if (!ptr || !ptr->next)
    {
        /* Leave sorted lists unmodified. */
        return list;
    }
706

M
Max Bruckner 已提交
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
    /* reset ptr to the beginning */
    ptr = list;
    while (ptr)
    {
        /* Walk two pointers to find the middle. */
        second = second->next;
        ptr = ptr->next;
        /* advances ptr two steps at a time */
        if (ptr)
        {
            ptr = ptr->next;
        }
    }
    if (second && second->prev)
    {
        /* Split the lists */
723
        second->prev->next = NULL;
M
Max Bruckner 已提交
724
    }
725

M
Max Bruckner 已提交
726 727 728
    /* Recursively sort the sub-lists. */
    first = cJSONUtils_SortList(first);
    second = cJSONUtils_SortList(second);
729
    list = ptr = NULL;
M
Max Bruckner 已提交
730 731 732

    while (first && second) /* Merge the sub-lists */
    {
733
        if (cJSONUtils_strcasecmp((unsigned char*)first->string, (unsigned char*)second->string) < 0)
M
Max Bruckner 已提交
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
        {
            if (!list)
            {
                /* start merged list with the first element of the first list */
                list = ptr = first;
            }
            else
            {
                /* add first element of first list to merged list */
                ptr->next = first;
                first->prev = ptr;
                ptr = first;
            }
            first = first->next;
        }
        else
        {
            if (!list)
            {
                /* start merged list with the first element of the second list */
                list = ptr = second;
            }
            else
            {
                /* add first element of second list to merged list */
                ptr->next = second;
                second->prev = ptr;
                ptr = second;
            }
            second = second->next;
        }
    }
    if (first)
    {
        /* Append rest of first list. */
        if (!list)
        {
            return first;
        }
        ptr->next = first;
        first->prev = ptr;
    }
    if (second)
    {
        /* Append rest of second list */
        if (!list)
        {
            return second;
        }
        ptr->next = second;
        second->prev = ptr;
    }

    return list;
788 789
}

790
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object)
M
Max Bruckner 已提交
791 792 793
{
    object->child = cJSONUtils_SortList(object->child);
}
794

795
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
796
{
797
    if (!cJSON_IsObject(patch))
M
Max Bruckner 已提交
798 799 800 801 802
    {
        /* scalar value, array or NULL, just duplicate */
        cJSON_Delete(target);
        return cJSON_Duplicate(patch, 1);
    }
803

804
    if (!cJSON_IsObject(target))
M
Max Bruckner 已提交
805 806 807 808 809 810 811 812
    {
        cJSON_Delete(target);
        target = cJSON_CreateObject();
    }

    patch = patch->child;
    while (patch)
    {
813
        if (cJSON_IsNull(patch))
M
Max Bruckner 已提交
814 815 816 817 818 819 820 821 822 823 824 825
        {
            /* NULL is the indicator to remove a value, see RFC7396 */
            cJSON_DeleteItemFromObject(target, patch->string);
        }
        else
        {
            cJSON *replaceme = cJSON_DetachItemFromObject(target, patch->string);
            cJSON_AddItemToObject(target, patch->string, cJSONUtils_MergePatch(replaceme, patch));
        }
        patch = patch->next;
    }
    return target;
826
}
827

828
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to)
829
{
830
    cJSON *patch = NULL;
831 832 833 834 835
    if (!to)
    {
        /* patch to delete everything */
        return cJSON_CreateNull();
    }
836
    if (!cJSON_IsObject(to) || !cJSON_IsObject(from))
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
    {
        return cJSON_Duplicate(to, 1);
    }

    cJSONUtils_SortObject(from);
    cJSONUtils_SortObject(to);

    from = from->child;
    to = to->child;
    patch = cJSON_CreateObject();
    while (from || to)
    {
        int compare = from ? (to ? strcmp(from->string, to->string) : -1) : 1;
        if (compare < 0)
        {
            /* from has a value that to doesn't have -> remove */
            cJSON_AddItemToObject(patch, from->string, cJSON_CreateNull());
            from = from->next;
        }
        else if (compare > 0)
        {
            /* to has a value that from doesn't have -> add to patch */
            cJSON_AddItemToObject(patch, to->string, cJSON_Duplicate(to, 1));
            to = to->next;
        }
        else
        {
            /* object key exists in both objects */
            if (cJSONUtils_Compare(from, to))
            {
                /* not identical --> generate a patch */
                cJSON_AddItemToObject(patch, to->string, cJSONUtils_GenerateMergePatch(from, to));
            }
            /* next key in the object */
            from = from->next;
            to = to->next;
        }
    }
    if (!patch->child)
    {
        cJSON_Delete(patch);
878
        return NULL;
879 880 881
    }

    return patch;
M
Max Bruckner 已提交
882
}