• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3 
4   Permission is hereby granted, free of charge, to any person obtaining a copy
5   of this software and associated documentation files (the "Software"), to deal
6   in the Software without restriction, including without limitation the rights
7   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8   copies of the Software, and to permit persons to whom the Software is
9   furnished to do so, subject to the following conditions:
10 
11   The above copyright notice and this permission notice shall be included in
12   all copies or substantial portions of the Software.
13 
14   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20   THE SOFTWARE.
21 */
22 
23 /* disable warnings about old C89 functions in MSVC */
24 #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
25 #define _CRT_SECURE_NO_DEPRECATE
26 #endif
27 
28 #ifdef __GNUCC__
29 #pragma GCC visibility push(default)
30 #endif
31 #if defined(_MSC_VER)
32 #pragma warning (push)
33 /* disable warning about single line comments in system headers */
34 #pragma warning (disable : 4001)
35 #endif
36 
37 #include <ctype.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <limits.h>
42 #include <math.h>
43 #include <float.h>
44 #include <math.h>
45 
46 #if defined(_MSC_VER)
47 #pragma warning (pop)
48 #endif
49 #ifdef __GNUCC__
50 #pragma GCC visibility pop
51 #endif
52 
53 #include "cJSON_Utils.h"
54 
55 /* define our own boolean type */
56 #ifdef true
57 #undef true
58 #endif
59 #define true ((cJSON_bool)1)
60 
61 #ifdef false
62 #undef false
63 #endif
64 #define false ((cJSON_bool)0)
65 
cJSONUtils_strdup(const unsigned char * const string)66 static unsigned char* cJSONUtils_strdup(const unsigned char* const string)
67 {
68     size_t length = 0;
69     unsigned char *copy = NULL;
70 
71     length = strlen((const char*)string) + sizeof("");
72     copy = (unsigned char*) cJSON_malloc(length);
73     if (copy == NULL)
74     {
75         return NULL;
76     }
77     memcpy(copy, string, length);
78 
79     return copy;
80 }
81 
82 /* string comparison which doesn't consider NULL pointers equal */
compare_strings(const unsigned char * string1,const unsigned char * string2,const cJSON_bool case_sensitive)83 static int compare_strings(const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive)
84 {
85     if ((string1 == NULL) || (string2 == NULL))
86     {
87         return 1;
88     }
89 
90     if (string1 == string2)
91     {
92         return 0;
93     }
94 
95     if (case_sensitive)
96     {
97         return strcmp((const char*)string1, (const char*)string2);
98     }
99 
100     for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
101     {
102         if (*string1 == '\0')
103         {
104             return 0;
105         }
106     }
107 
108     return tolower(*string1) - tolower(*string2);
109 }
110 
111 /* securely comparison of floating-point variables */
compare_double(double a,double b)112 static cJSON_bool compare_double(double a, double b)
113 {
114     double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
115     return (fabs(a - b) <= maxVal * DBL_EPSILON);
116 }
117 
118 
119 /* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */
compare_pointers(const unsigned char * name,const unsigned char * pointer,const cJSON_bool case_sensitive)120 static cJSON_bool compare_pointers(const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive)
121 {
122     if ((name == NULL) || (pointer == NULL))
123     {
124         return false;
125     }
126 
127     for (; (*name != '\0') && (*pointer != '\0') && (*pointer != '/'); (void)name++, pointer++) /* compare until next '/' */
128     {
129         if (*pointer == '~')
130         {
131             /* check for escaped '~' (~0) and '/' (~1) */
132             if (((pointer[1] != '0') || (*name != '~')) && ((pointer[1] != '1') || (*name != '/')))
133             {
134                 /* invalid escape sequence or wrong character in *name */
135                 return false;
136             }
137             else
138             {
139                 pointer++;
140             }
141         }
142         else if ((!case_sensitive && (tolower(*name) != tolower(*pointer))) || (case_sensitive && (*name != *pointer)))
143         {
144             return false;
145         }
146     }
147     if (((*pointer != 0) && (*pointer != '/')) != (*name != 0))
148     {
149         /* one string has ended, the other not */
150         return false;;
151     }
152 
153     return true;
154 }
155 
156 /* calculate the length of a string if encoded as JSON pointer with ~0 and ~1 escape sequences */
pointer_encoded_length(const unsigned char * string)157 static size_t pointer_encoded_length(const unsigned char *string)
158 {
159     size_t length;
160     for (length = 0; *string != '\0'; (void)string++, length++)
161     {
162         /* character needs to be escaped? */
163         if ((*string == '~') || (*string == '/'))
164         {
165             length++;
166         }
167     }
168 
169     return length;
170 }
171 
172 /* copy a string while escaping '~' and '/' with ~0 and ~1 JSON pointer escape codes */
encode_string_as_pointer(unsigned char * destination,const unsigned char * source)173 static void encode_string_as_pointer(unsigned char *destination, const unsigned char *source)
174 {
175     for (; source[0] != '\0'; (void)source++, destination++)
176     {
177         if (source[0] == '/')
178         {
179             destination[0] = '~';
180             destination[1] = '1';
181             destination++;
182         }
183         else if (source[0] == '~')
184         {
185             destination[0] = '~';
186             destination[1] = '0';
187             destination++;
188         }
189         else
190         {
191             destination[0] = source[0];
192         }
193     }
194 
195     destination[0] = '\0';
196 }
197 
cJSONUtils_FindPointerFromObjectTo(const cJSON * const object,const cJSON * const target)198 CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target)
199 {
200     size_t child_index = 0;
201     cJSON *current_child = 0;
202 
203     if ((object == NULL) || (target == NULL))
204     {
205         return NULL;
206     }
207 
208     if (object == target)
209     {
210         /* found */
211         return (char*)cJSONUtils_strdup((const unsigned char*)"");
212     }
213 
214     /* recursively search all children of the object or array */
215     for (current_child = object->child; current_child != NULL; (void)(current_child = current_child->next), child_index++)
216     {
217         unsigned char *target_pointer = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(current_child, target);
218         /* found the target? */
219         if (target_pointer != NULL)
220         {
221             if (cJSON_IsArray(object))
222             {
223                 /* reserve enough memory for a 64 bit integer + '/' and '\0' */
224                 unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + 20 + sizeof("/"));
225                 /* check if conversion to unsigned long is valid
226                  * This should be eliminated at compile time by dead code elimination
227                  * if size_t is an alias of unsigned long, or if it is bigger */
228                 if (child_index > ULONG_MAX)
229                 {
230                     cJSON_free(target_pointer);
231                     cJSON_free(full_pointer);
232                     return NULL;
233                 }
234                 sprintf((char*)full_pointer, "/%lu%s", (unsigned long)child_index, target_pointer); /* /<array_index><path> */
235                 cJSON_free(target_pointer);
236 
237                 return (char*)full_pointer;
238             }
239 
240             if (cJSON_IsObject(object))
241             {
242                 unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + pointer_encoded_length((unsigned char*)current_child->string) + 2);
243                 full_pointer[0] = '/';
244                 encode_string_as_pointer(full_pointer + 1, (unsigned char*)current_child->string);
245                 strcat((char*)full_pointer, (char*)target_pointer);
246                 cJSON_free(target_pointer);
247 
248                 return (char*)full_pointer;
249             }
250 
251             /* reached leaf of the tree, found nothing */
252             cJSON_free(target_pointer);
253             return NULL;
254         }
255     }
256 
257     /* not found */
258     return NULL;
259 }
260 
261 /* non broken version of cJSON_GetArrayItem */
get_array_item(const cJSON * array,size_t item)262 static cJSON *get_array_item(const cJSON *array, size_t item)
263 {
264     cJSON *child = array ? array->child : NULL;
265     while ((child != NULL) && (item > 0))
266     {
267         item--;
268         child = child->next;
269     }
270 
271     return child;
272 }
273 
decode_array_index_from_pointer(const unsigned char * const pointer,size_t * const index)274 static cJSON_bool decode_array_index_from_pointer(const unsigned char * const pointer, size_t * const index)
275 {
276     size_t parsed_index = 0;
277     size_t position = 0;
278 
279     if ((pointer[0] == '0') && ((pointer[1] != '\0') && (pointer[1] != '/')))
280     {
281         /* leading zeroes are not permitted */
282         return 0;
283     }
284 
285     for (position = 0; (pointer[position] >= '0') && (pointer[0] <= '9'); position++)
286     {
287         parsed_index = (10 * parsed_index) + (size_t)(pointer[position] - '0');
288 
289     }
290 
291     if ((pointer[position] != '\0') && (pointer[position] != '/'))
292     {
293         return 0;
294     }
295 
296     *index = parsed_index;
297 
298     return 1;
299 }
300 
get_item_from_pointer(cJSON * const object,const char * pointer,const cJSON_bool case_sensitive)301 static cJSON *get_item_from_pointer(cJSON * const object, const char * pointer, const cJSON_bool case_sensitive)
302 {
303     cJSON *current_element = object;
304 
305     if (pointer == NULL)
306     {
307         return NULL;
308     }
309 
310     /* follow path of the pointer */
311     while ((pointer[0] == '/') && (current_element != NULL))
312     {
313         pointer++;
314         if (cJSON_IsArray(current_element))
315         {
316             size_t index = 0;
317             if (!decode_array_index_from_pointer((const unsigned char*)pointer, &index))
318             {
319                 return NULL;
320             }
321 
322             current_element = get_array_item(current_element, index);
323         }
324         else if (cJSON_IsObject(current_element))
325         {
326             current_element = current_element->child;
327             /* GetObjectItem. */
328             while ((current_element != NULL) && !compare_pointers((unsigned char*)current_element->string, (const unsigned char*)pointer, case_sensitive))
329             {
330                 current_element = current_element->next;
331             }
332         }
333         else
334         {
335             return NULL;
336         }
337 
338         /* skip to the next path token or end of string */
339         while ((pointer[0] != '\0') && (pointer[0] != '/'))
340         {
341             pointer++;
342         }
343     }
344 
345     return current_element;
346 }
347 
cJSONUtils_GetPointer(cJSON * const object,const char * pointer)348 CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer)
349 {
350     return get_item_from_pointer(object, pointer, false);
351 }
352 
cJSONUtils_GetPointerCaseSensitive(cJSON * const object,const char * pointer)353 CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer)
354 {
355     return get_item_from_pointer(object, pointer, true);
356 }
357 
358 /* JSON Patch implementation. */
decode_pointer_inplace(unsigned char * string)359 static void decode_pointer_inplace(unsigned char *string)
360 {
361     unsigned char *decoded_string = string;
362 
363     if (string == NULL) {
364         return;
365     }
366 
367     for (; *string; (void)decoded_string++, string++)
368     {
369         if (string[0] == '~')
370         {
371             if (string[1] == '0')
372             {
373                 decoded_string[0] = '~';
374             }
375             else if (string[1] == '1')
376             {
377                 decoded_string[1] = '/';
378             }
379             else
380             {
381                 /* invalid escape sequence */
382                 return;
383             }
384 
385             string++;
386         }
387     }
388 
389     decoded_string[0] = '\0';
390 }
391 
392 /* non-broken cJSON_DetachItemFromArray */
detach_item_from_array(cJSON * array,size_t which)393 static cJSON *detach_item_from_array(cJSON *array, size_t which)
394 {
395     cJSON *c = array->child;
396     while (c && (which > 0))
397     {
398         c = c->next;
399         which--;
400     }
401     if (!c)
402     {
403         /* item doesn't exist */
404         return NULL;
405     }
406     if (c != array->child)
407     {
408         /* not the first element */
409         c->prev->next = c->next;
410     }
411     if (c->next)
412     {
413         c->next->prev = c->prev;
414     }
415     if (c == array->child)
416     {
417         array->child = c->next;
418     }
419     else if (c->next == NULL)
420     {
421         array->child->prev = c->prev;
422     }
423     /* make sure the detached item doesn't point anywhere anymore */
424     c->prev = c->next = NULL;
425 
426     return c;
427 }
428 
429 /* detach an item at the given path */
detach_path(cJSON * object,const unsigned char * path,const cJSON_bool case_sensitive)430 static cJSON *detach_path(cJSON *object, const unsigned char *path, const cJSON_bool case_sensitive)
431 {
432     unsigned char *parent_pointer = NULL;
433     unsigned char *child_pointer = NULL;
434     cJSON *parent = NULL;
435     cJSON *detached_item = NULL;
436 
437     /* copy path and split it in parent and child */
438     parent_pointer = cJSONUtils_strdup(path);
439     if (parent_pointer == NULL) {
440         goto cleanup;
441     }
442 
443     child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); /* last '/' */
444     if (child_pointer == NULL)
445     {
446         goto cleanup;
447     }
448     /* split strings */
449     child_pointer[0] = '\0';
450     child_pointer++;
451 
452     parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive);
453     decode_pointer_inplace(child_pointer);
454 
455     if (cJSON_IsArray(parent))
456     {
457         size_t index = 0;
458         if (!decode_array_index_from_pointer(child_pointer, &index))
459         {
460             goto cleanup;
461         }
462         detached_item = detach_item_from_array(parent, index);
463     }
464     else if (cJSON_IsObject(parent))
465     {
466         detached_item = cJSON_DetachItemFromObject(parent, (char*)child_pointer);
467     }
468     else
469     {
470         /* Couldn't find object to remove child from. */
471         goto cleanup;
472     }
473 
474 cleanup:
475     if (parent_pointer != NULL)
476     {
477         cJSON_free(parent_pointer);
478     }
479 
480     return detached_item;
481 }
482 
483 /* sort lists using mergesort */
sort_list(cJSON * list,const cJSON_bool case_sensitive)484 static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive)
485 {
486     cJSON *first = list;
487     cJSON *second = list;
488     cJSON *current_item = list;
489     cJSON *result = list;
490     cJSON *result_tail = NULL;
491 
492     if ((list == NULL) || (list->next == NULL))
493     {
494         /* One entry is sorted already. */
495         return result;
496     }
497 
498     while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0))
499     {
500         /* Test for list sorted. */
501         current_item = current_item->next;
502     }
503     if ((current_item == NULL) || (current_item->next == NULL))
504     {
505         /* Leave sorted lists unmodified. */
506         return result;
507     }
508 
509     /* reset pointer to the beginning */
510     current_item = list;
511     while (current_item != NULL)
512     {
513         /* Walk two pointers to find the middle. */
514         second = second->next;
515         current_item = current_item->next;
516         /* advances current_item two steps at a time */
517         if (current_item != NULL)
518         {
519             current_item = current_item->next;
520         }
521     }
522     if ((second != NULL) && (second->prev != NULL))
523     {
524         /* Split the lists */
525         second->prev->next = NULL;
526         second->prev = NULL;
527     }
528 
529     /* Recursively sort the sub-lists. */
530     first = sort_list(first, case_sensitive);
531     second = sort_list(second, case_sensitive);
532     result = NULL;
533 
534     /* Merge the sub-lists */
535     while ((first != NULL) && (second != NULL))
536     {
537         cJSON *smaller = NULL;
538         if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, case_sensitive) < 0)
539         {
540             smaller = first;
541         }
542         else
543         {
544             smaller = second;
545         }
546 
547         if (result == NULL)
548         {
549             /* start merged list with the smaller element */
550             result_tail = smaller;
551             result = smaller;
552         }
553         else
554         {
555             /* add smaller element to the list */
556             result_tail->next = smaller;
557             smaller->prev = result_tail;
558             result_tail = smaller;
559         }
560 
561         if (first == smaller)
562         {
563             first = first->next;
564         }
565         else
566         {
567             second = second->next;
568         }
569     }
570 
571     if (first != NULL)
572     {
573         /* Append rest of first list. */
574         if (result == NULL)
575         {
576             return first;
577         }
578         result_tail->next = first;
579         first->prev = result_tail;
580     }
581     if (second != NULL)
582     {
583         /* Append rest of second list */
584         if (result == NULL)
585         {
586             return second;
587         }
588         result_tail->next = second;
589         second->prev = result_tail;
590     }
591 
592     return result;
593 }
594 
sort_object(cJSON * const object,const cJSON_bool case_sensitive)595 static void sort_object(cJSON * const object, const cJSON_bool case_sensitive)
596 {
597     if (object == NULL)
598     {
599         return;
600     }
601     object->child = sort_list(object->child, case_sensitive);
602 }
603 
compare_json(cJSON * a,cJSON * b,const cJSON_bool case_sensitive)604 static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive)
605 {
606     if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
607     {
608         /* mismatched type. */
609         return false;
610     }
611     switch (a->type & 0xFF)
612     {
613         case cJSON_Number:
614             /* numeric mismatch. */
615             if ((a->valueint != b->valueint) || (!compare_double(a->valuedouble, b->valuedouble)))
616             {
617                 return false;
618             }
619             else
620             {
621                 return true;
622             }
623 
624         case cJSON_String:
625             /* string mismatch. */
626             if (strcmp(a->valuestring, b->valuestring) != 0)
627             {
628                 return false;
629             }
630             else
631             {
632                 return true;
633             }
634 
635         case cJSON_Array:
636             for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next)
637             {
638                 cJSON_bool identical = compare_json(a, b, case_sensitive);
639                 if (!identical)
640                 {
641                     return false;
642                 }
643             }
644 
645             /* array size mismatch? (one of both children is not NULL) */
646             if ((a != NULL) || (b != NULL))
647             {
648                 return false;
649             }
650             else
651             {
652                 return true;
653             }
654 
655         case cJSON_Object:
656             sort_object(a, case_sensitive);
657             sort_object(b, case_sensitive);
658             for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next)
659             {
660                 cJSON_bool identical = false;
661                 /* compare object keys */
662                 if (compare_strings((unsigned char*)a->string, (unsigned char*)b->string, case_sensitive))
663                 {
664                     /* missing member */
665                     return false;
666                 }
667                 identical = compare_json(a, b, case_sensitive);
668                 if (!identical)
669                 {
670                     return false;
671                 }
672             }
673 
674             /* object length mismatch (one of both children is not null) */
675             if ((a != NULL) || (b != NULL))
676             {
677                 return false;
678             }
679             else
680             {
681                 return true;
682             }
683 
684         default:
685             break;
686     }
687 
688     /* null, true or false */
689     return true;
690 }
691 
692 /* non broken version of cJSON_InsertItemInArray */
insert_item_in_array(cJSON * array,size_t which,cJSON * newitem)693 static cJSON_bool insert_item_in_array(cJSON *array, size_t which, cJSON *newitem)
694 {
695     cJSON *child = array->child;
696     while (child && (which > 0))
697     {
698         child = child->next;
699         which--;
700     }
701     if (which > 0)
702     {
703         /* item is after the end of the array */
704         return 0;
705     }
706     if (child == NULL)
707     {
708         cJSON_AddItemToArray(array, newitem);
709         return 1;
710     }
711 
712     /* insert into the linked list */
713     newitem->next = child;
714     newitem->prev = child->prev;
715     child->prev = newitem;
716 
717     /* was it at the beginning */
718     if (child == array->child)
719     {
720         array->child = newitem;
721     }
722     else
723     {
724         newitem->prev->next = newitem;
725     }
726 
727     return 1;
728 }
729 
get_object_item(const cJSON * const object,const char * name,const cJSON_bool case_sensitive)730 static cJSON *get_object_item(const cJSON * const object, const char* name, const cJSON_bool case_sensitive)
731 {
732     if (case_sensitive)
733     {
734         return cJSON_GetObjectItemCaseSensitive(object, name);
735     }
736 
737     return cJSON_GetObjectItem(object, name);
738 }
739 
740 enum patch_operation { INVALID, ADD, REMOVE, REPLACE, MOVE, COPY, TEST };
741 
decode_patch_operation(const cJSON * const patch,const cJSON_bool case_sensitive)742 static enum patch_operation decode_patch_operation(const cJSON * const patch, const cJSON_bool case_sensitive)
743 {
744     cJSON *operation = get_object_item(patch, "op", case_sensitive);
745     if (!cJSON_IsString(operation))
746     {
747         return INVALID;
748     }
749 
750     if (strcmp(operation->valuestring, "add") == 0)
751     {
752         return ADD;
753     }
754 
755     if (strcmp(operation->valuestring, "remove") == 0)
756     {
757         return REMOVE;
758     }
759 
760     if (strcmp(operation->valuestring, "replace") == 0)
761     {
762         return REPLACE;
763     }
764 
765     if (strcmp(operation->valuestring, "move") == 0)
766     {
767         return MOVE;
768     }
769 
770     if (strcmp(operation->valuestring, "copy") == 0)
771     {
772         return COPY;
773     }
774 
775     if (strcmp(operation->valuestring, "test") == 0)
776     {
777         return TEST;
778     }
779 
780     return INVALID;
781 }
782 
783 /* overwrite and existing item with another one and free resources on the way */
overwrite_item(cJSON * const root,const cJSON replacement)784 static void overwrite_item(cJSON * const root, const cJSON replacement)
785 {
786     if (root == NULL)
787     {
788         return;
789     }
790 
791     if (root->string != NULL)
792     {
793         cJSON_free(root->string);
794     }
795     if (root->valuestring != NULL)
796     {
797         cJSON_free(root->valuestring);
798     }
799     if (root->child != NULL)
800     {
801         cJSON_Delete(root->child);
802     }
803 
804     memcpy(root, &replacement, sizeof(cJSON));
805 }
806 
apply_patch(cJSON * object,const cJSON * patch,const cJSON_bool case_sensitive)807 static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_sensitive)
808 {
809     cJSON *path = NULL;
810     cJSON *value = NULL;
811     cJSON *parent = NULL;
812     enum patch_operation opcode = INVALID;
813     unsigned char *parent_pointer = NULL;
814     unsigned char *child_pointer = NULL;
815     int status = 0;
816 
817     path = get_object_item(patch, "path", case_sensitive);
818     if (!cJSON_IsString(path))
819     {
820         /* malformed patch. */
821         status = 2;
822         goto cleanup;
823     }
824 
825     opcode = decode_patch_operation(patch, case_sensitive);
826     if (opcode == INVALID)
827     {
828         status = 3;
829         goto cleanup;
830     }
831     else if (opcode == TEST)
832     {
833         /* compare value: {...} with the given path */
834         status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), get_object_item(patch, "value", case_sensitive), case_sensitive);
835         goto cleanup;
836     }
837 
838     /* special case for replacing the root */
839     if (path->valuestring[0] == '\0')
840     {
841         if (opcode == REMOVE)
842         {
843             static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL};
844 
845             overwrite_item(object, invalid);
846 
847             status = 0;
848             goto cleanup;
849         }
850 
851         if ((opcode == REPLACE) || (opcode == ADD))
852         {
853             value = get_object_item(patch, "value", case_sensitive);
854             if (value == NULL)
855             {
856                 /* missing "value" for add/replace. */
857                 status = 7;
858                 goto cleanup;
859             }
860 
861             value = cJSON_Duplicate(value, 1);
862             if (value == NULL)
863             {
864                 /* out of memory for add/replace. */
865                 status = 8;
866                 goto cleanup;
867             }
868 
869             overwrite_item(object, *value);
870 
871             /* delete the duplicated value */
872             cJSON_free(value);
873             value = NULL;
874 
875             /* the string "value" isn't needed */
876             if (object->string != NULL)
877             {
878                 cJSON_free(object->string);
879                 object->string = NULL;
880             }
881 
882             status = 0;
883             goto cleanup;
884         }
885     }
886 
887     if ((opcode == REMOVE) || (opcode == REPLACE))
888     {
889         /* Get rid of old. */
890         cJSON *old_item = detach_path(object, (unsigned char*)path->valuestring, case_sensitive);
891         if (old_item == NULL)
892         {
893             status = 13;
894             goto cleanup;
895         }
896         cJSON_Delete(old_item);
897         if (opcode == REMOVE)
898         {
899             /* For Remove, this job is done. */
900             status = 0;
901             goto cleanup;
902         }
903     }
904 
905     /* Copy/Move uses "from". */
906     if ((opcode == MOVE) || (opcode == COPY))
907     {
908         cJSON *from = get_object_item(patch, "from", case_sensitive);
909         if (from == NULL)
910         {
911             /* missing "from" for copy/move. */
912             status = 4;
913             goto cleanup;
914         }
915 
916         if (opcode == MOVE)
917         {
918             value = detach_path(object, (unsigned char*)from->valuestring, case_sensitive);
919         }
920         if (opcode == COPY)
921         {
922             value = get_item_from_pointer(object, from->valuestring, case_sensitive);
923         }
924         if (value == NULL)
925         {
926             /* missing "from" for copy/move. */
927             status = 5;
928             goto cleanup;
929         }
930         if (opcode == COPY)
931         {
932             value = cJSON_Duplicate(value, 1);
933         }
934         if (value == NULL)
935         {
936             /* out of memory for copy/move. */
937             status = 6;
938             goto cleanup;
939         }
940     }
941     else /* Add/Replace uses "value". */
942     {
943         value = get_object_item(patch, "value", case_sensitive);
944         if (value == NULL)
945         {
946             /* missing "value" for add/replace. */
947             status = 7;
948             goto cleanup;
949         }
950         value = cJSON_Duplicate(value, 1);
951         if (value == NULL)
952         {
953             /* out of memory for add/replace. */
954             status = 8;
955             goto cleanup;
956         }
957     }
958 
959     /* Now, just add "value" to "path". */
960 
961     /* split pointer in parent and child */
962     parent_pointer = cJSONUtils_strdup((unsigned char*)path->valuestring);
963     child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/');
964     if (child_pointer != NULL)
965     {
966         child_pointer[0] = '\0';
967         child_pointer++;
968     }
969     parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive);
970     decode_pointer_inplace(child_pointer);
971 
972     /* add, remove, replace, move, copy, test. */
973     if ((parent == NULL) || (child_pointer == NULL))
974     {
975         /* Couldn't find object to add to. */
976         status = 9;
977         goto cleanup;
978     }
979     else if (cJSON_IsArray(parent))
980     {
981         if (strcmp((char*)child_pointer, "-") == 0)
982         {
983             cJSON_AddItemToArray(parent, value);
984             value = NULL;
985         }
986         else
987         {
988             size_t index = 0;
989             if (!decode_array_index_from_pointer(child_pointer, &index))
990             {
991                 status = 11;
992                 goto cleanup;
993             }
994 
995             if (!insert_item_in_array(parent, index, value))
996             {
997                 status = 10;
998                 goto cleanup;
999             }
1000             value = NULL;
1001         }
1002     }
1003     else if (cJSON_IsObject(parent))
1004     {
1005         if (case_sensitive)
1006         {
1007             cJSON_DeleteItemFromObjectCaseSensitive(parent, (char*)child_pointer);
1008         }
1009         else
1010         {
1011             cJSON_DeleteItemFromObject(parent, (char*)child_pointer);
1012         }
1013         cJSON_AddItemToObject(parent, (char*)child_pointer, value);
1014         value = NULL;
1015     }
1016     else /* parent is not an object */
1017     {
1018         /* Couldn't find object to add to. */
1019         status = 9;
1020         goto cleanup;
1021     }
1022 
1023 cleanup:
1024     if (value != NULL)
1025     {
1026         cJSON_Delete(value);
1027     }
1028     if (parent_pointer != NULL)
1029     {
1030         cJSON_free(parent_pointer);
1031     }
1032 
1033     return status;
1034 }
1035 
cJSONUtils_ApplyPatches(cJSON * const object,const cJSON * const patches)1036 CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches)
1037 {
1038     const cJSON *current_patch = NULL;
1039     int status = 0;
1040 
1041     if (!cJSON_IsArray(patches))
1042     {
1043         /* malformed patches. */
1044         return 1;
1045     }
1046 
1047     if (patches != NULL)
1048     {
1049         current_patch = patches->child;
1050     }
1051 
1052     while (current_patch != NULL)
1053     {
1054         status = apply_patch(object, current_patch, false);
1055         if (status != 0)
1056         {
1057             return status;
1058         }
1059         current_patch = current_patch->next;
1060     }
1061 
1062     return 0;
1063 }
1064 
cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object,const cJSON * const patches)1065 CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches)
1066 {
1067     const cJSON *current_patch = NULL;
1068     int status = 0;
1069 
1070     if (!cJSON_IsArray(patches))
1071     {
1072         /* malformed patches. */
1073         return 1;
1074     }
1075 
1076     if (patches != NULL)
1077     {
1078         current_patch = patches->child;
1079     }
1080 
1081     while (current_patch != NULL)
1082     {
1083         status = apply_patch(object, current_patch, true);
1084         if (status != 0)
1085         {
1086             return status;
1087         }
1088         current_patch = current_patch->next;
1089     }
1090 
1091     return 0;
1092 }
1093 
compose_patch(cJSON * const patches,const unsigned char * const operation,const unsigned char * const path,const unsigned char * suffix,const cJSON * const value)1094 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)
1095 {
1096     cJSON *patch = NULL;
1097 
1098     if ((patches == NULL) || (operation == NULL) || (path == NULL))
1099     {
1100         return;
1101     }
1102 
1103     patch = cJSON_CreateObject();
1104     if (patch == NULL)
1105     {
1106         return;
1107     }
1108     cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)operation));
1109 
1110     if (suffix == NULL)
1111     {
1112         cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path));
1113     }
1114     else
1115     {
1116         size_t suffix_length = pointer_encoded_length(suffix);
1117         size_t path_length = strlen((const char*)path);
1118         unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/"));
1119 
1120         sprintf((char*)full_path, "%s/", (const char*)path);
1121         encode_string_as_pointer(full_path + path_length + 1, suffix);
1122 
1123         cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)full_path));
1124         cJSON_free(full_path);
1125     }
1126 
1127     if (value != NULL)
1128     {
1129         cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(value, 1));
1130     }
1131     cJSON_AddItemToArray(patches, patch);
1132 }
1133 
cJSONUtils_AddPatchToArray(cJSON * const array,const char * const operation,const char * const path,const cJSON * const value)1134 CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value)
1135 {
1136     compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value);
1137 }
1138 
create_patches(cJSON * const patches,const unsigned char * const path,cJSON * const from,cJSON * const to,const cJSON_bool case_sensitive)1139 static void create_patches(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive)
1140 {
1141     if ((from == NULL) || (to == NULL))
1142     {
1143         return;
1144     }
1145 
1146     if ((from->type & 0xFF) != (to->type & 0xFF))
1147     {
1148         compose_patch(patches, (const unsigned char*)"replace", path, 0, to);
1149         return;
1150     }
1151 
1152     switch (from->type & 0xFF)
1153     {
1154         case cJSON_Number:
1155             if ((from->valueint != to->valueint) || !compare_double(from->valuedouble, to->valuedouble))
1156             {
1157                 compose_patch(patches, (const unsigned char*)"replace", path, NULL, to);
1158             }
1159             return;
1160 
1161         case cJSON_String:
1162             if (strcmp(from->valuestring, to->valuestring) != 0)
1163             {
1164                 compose_patch(patches, (const unsigned char*)"replace", path, NULL, to);
1165             }
1166             return;
1167 
1168         case cJSON_Array:
1169         {
1170             size_t index = 0;
1171             cJSON *from_child = from->child;
1172             cJSON *to_child = to->child;
1173             unsigned char *new_path = (unsigned char*)cJSON_malloc(strlen((const char*)path) + 20 + sizeof("/")); /* Allow space for 64bit int. log10(2^64) = 20 */
1174 
1175             /* generate patches for all array elements that exist in both "from" and "to" */
1176             for (index = 0; (from_child != NULL) && (to_child != NULL); (void)(from_child = from_child->next), (void)(to_child = to_child->next), index++)
1177             {
1178                 /* check if conversion to unsigned long is valid
1179                  * This should be eliminated at compile time by dead code elimination
1180                  * if size_t is an alias of unsigned long, or if it is bigger */
1181                 if (index > ULONG_MAX)
1182                 {
1183                     cJSON_free(new_path);
1184                     return;
1185                 }
1186                 sprintf((char*)new_path, "%s/%lu", path, (unsigned long)index); /* path of the current array element */
1187                 create_patches(patches, new_path, from_child, to_child, case_sensitive);
1188             }
1189 
1190             /* remove leftover elements from 'from' that are not in 'to' */
1191             for (; (from_child != NULL); (void)(from_child = from_child->next))
1192             {
1193                 /* check if conversion to unsigned long is valid
1194                  * This should be eliminated at compile time by dead code elimination
1195                  * if size_t is an alias of unsigned long, or if it is bigger */
1196                 if (index > ULONG_MAX)
1197                 {
1198                     cJSON_free(new_path);
1199                     return;
1200                 }
1201                 sprintf((char*)new_path, "%lu", (unsigned long)index);
1202                 compose_patch(patches, (const unsigned char*)"remove", path, new_path, NULL);
1203             }
1204             /* add new elements in 'to' that were not in 'from' */
1205             for (; (to_child != NULL); (void)(to_child = to_child->next), index++)
1206             {
1207                 compose_patch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to_child);
1208             }
1209             cJSON_free(new_path);
1210             return;
1211         }
1212 
1213         case cJSON_Object:
1214         {
1215             cJSON *from_child = NULL;
1216             cJSON *to_child = NULL;
1217             sort_object(from, case_sensitive);
1218             sort_object(to, case_sensitive);
1219 
1220             from_child = from->child;
1221             to_child = to->child;
1222             /* for all object values in the object with more of them */
1223             while ((from_child != NULL) || (to_child != NULL))
1224             {
1225                 int diff;
1226                 if (from_child == NULL)
1227                 {
1228                     diff = 1;
1229                 }
1230                 else if (to_child == NULL)
1231                 {
1232                     diff = -1;
1233                 }
1234                 else
1235                 {
1236                     diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, case_sensitive);
1237                 }
1238 
1239                 if (diff == 0)
1240                 {
1241                     /* both object keys are the same */
1242                     size_t path_length = strlen((const char*)path);
1243                     size_t from_child_name_length = pointer_encoded_length((unsigned char*)from_child->string);
1244                     unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/"));
1245 
1246                     sprintf((char*)new_path, "%s/", path);
1247                     encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string);
1248 
1249                     /* create a patch for the element */
1250                     create_patches(patches, new_path, from_child, to_child, case_sensitive);
1251                     cJSON_free(new_path);
1252 
1253                     from_child = from_child->next;
1254                     to_child = to_child->next;
1255                 }
1256                 else if (diff < 0)
1257                 {
1258                     /* object element doesn't exist in 'to' --> remove it */
1259                     compose_patch(patches, (const unsigned char*)"remove", path, (unsigned char*)from_child->string, NULL);
1260 
1261                     from_child = from_child->next;
1262                 }
1263                 else
1264                 {
1265                     /* object element doesn't exist in 'from' --> add it */
1266                     compose_patch(patches, (const unsigned char*)"add", path, (unsigned char*)to_child->string, to_child);
1267 
1268                     to_child = to_child->next;
1269                 }
1270             }
1271             return;
1272         }
1273 
1274         default:
1275             break;
1276     }
1277 }
1278 
cJSONUtils_GeneratePatches(cJSON * const from,cJSON * const to)1279 CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to)
1280 {
1281     cJSON *patches = NULL;
1282 
1283     if ((from == NULL) || (to == NULL))
1284     {
1285         return NULL;
1286     }
1287 
1288     patches = cJSON_CreateArray();
1289     create_patches(patches, (const unsigned char*)"", from, to, false);
1290 
1291     return patches;
1292 }
1293 
cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from,cJSON * const to)1294 CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to)
1295 {
1296     cJSON *patches = NULL;
1297 
1298     if ((from == NULL) || (to == NULL))
1299     {
1300         return NULL;
1301     }
1302 
1303     patches = cJSON_CreateArray();
1304     create_patches(patches, (const unsigned char*)"", from, to, true);
1305 
1306     return patches;
1307 }
1308 
cJSONUtils_SortObject(cJSON * const object)1309 CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object)
1310 {
1311     sort_object(object, false);
1312 }
1313 
cJSONUtils_SortObjectCaseSensitive(cJSON * const object)1314 CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object)
1315 {
1316     sort_object(object, true);
1317 }
1318 
merge_patch(cJSON * target,const cJSON * const patch,const cJSON_bool case_sensitive)1319 static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_bool case_sensitive)
1320 {
1321     cJSON *patch_child = NULL;
1322 
1323     if (!cJSON_IsObject(patch))
1324     {
1325         /* scalar value, array or NULL, just duplicate */
1326         cJSON_Delete(target);
1327         return cJSON_Duplicate(patch, 1);
1328     }
1329 
1330     if (!cJSON_IsObject(target))
1331     {
1332         cJSON_Delete(target);
1333         target = cJSON_CreateObject();
1334     }
1335 
1336     patch_child = patch->child;
1337     while (patch_child != NULL)
1338     {
1339         if (cJSON_IsNull(patch_child))
1340         {
1341             /* NULL is the indicator to remove a value, see RFC7396 */
1342             if (case_sensitive)
1343             {
1344                 cJSON_DeleteItemFromObjectCaseSensitive(target, patch_child->string);
1345             }
1346             else
1347             {
1348                 cJSON_DeleteItemFromObject(target, patch_child->string);
1349             }
1350         }
1351         else
1352         {
1353             cJSON *replace_me = NULL;
1354             cJSON *replacement = NULL;
1355 
1356             if (case_sensitive)
1357             {
1358                 replace_me = cJSON_DetachItemFromObjectCaseSensitive(target, patch_child->string);
1359             }
1360             else
1361             {
1362                 replace_me = cJSON_DetachItemFromObject(target, patch_child->string);
1363             }
1364 
1365             replacement = merge_patch(replace_me, patch_child, case_sensitive);
1366             if (replacement == NULL)
1367             {
1368                 return NULL;
1369             }
1370 
1371             cJSON_AddItemToObject(target, patch_child->string, replacement);
1372         }
1373         patch_child = patch_child->next;
1374     }
1375     return target;
1376 }
1377 
cJSONUtils_MergePatch(cJSON * target,const cJSON * const patch)1378 CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch)
1379 {
1380     return merge_patch(target, patch, false);
1381 }
1382 
cJSONUtils_MergePatchCaseSensitive(cJSON * target,const cJSON * const patch)1383 CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch)
1384 {
1385     return merge_patch(target, patch, true);
1386 }
1387 
generate_merge_patch(cJSON * const from,cJSON * const to,const cJSON_bool case_sensitive)1388 static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive)
1389 {
1390     cJSON *from_child = NULL;
1391     cJSON *to_child = NULL;
1392     cJSON *patch = NULL;
1393     if (to == NULL)
1394     {
1395         /* patch to delete everything */
1396         return cJSON_CreateNull();
1397     }
1398     if (!cJSON_IsObject(to) || !cJSON_IsObject(from))
1399     {
1400         return cJSON_Duplicate(to, 1);
1401     }
1402 
1403     sort_object(from, case_sensitive);
1404     sort_object(to, case_sensitive);
1405 
1406     from_child = from->child;
1407     to_child = to->child;
1408     patch = cJSON_CreateObject();
1409     while (from_child || to_child)
1410     {
1411         int diff;
1412         if (from_child != NULL)
1413         {
1414             if (to_child != NULL)
1415             {
1416                 diff = strcmp(from_child->string, to_child->string);
1417             }
1418             else
1419             {
1420                 diff = -1;
1421             }
1422         }
1423         else
1424         {
1425             diff = 1;
1426         }
1427 
1428         if (diff < 0)
1429         {
1430             /* from has a value that to doesn't have -> remove */
1431             cJSON_AddItemToObject(patch, from_child->string, cJSON_CreateNull());
1432 
1433             from_child = from_child->next;
1434         }
1435         else if (diff > 0)
1436         {
1437             /* to has a value that from doesn't have -> add to patch */
1438             cJSON_AddItemToObject(patch, to_child->string, cJSON_Duplicate(to_child, 1));
1439 
1440             to_child = to_child->next;
1441         }
1442         else
1443         {
1444             /* object key exists in both objects */
1445             if (!compare_json(from_child, to_child, case_sensitive))
1446             {
1447                 /* not identical --> generate a patch */
1448                 cJSON_AddItemToObject(patch, to_child->string, cJSONUtils_GenerateMergePatch(from_child, to_child));
1449             }
1450 
1451             /* next key in the object */
1452             from_child = from_child->next;
1453             to_child = to_child->next;
1454         }
1455     }
1456     if (patch->child == NULL)
1457     {
1458         /* no patch generated */
1459         cJSON_Delete(patch);
1460         return NULL;
1461     }
1462 
1463     return patch;
1464 }
1465 
cJSONUtils_GenerateMergePatch(cJSON * const from,cJSON * const to)1466 CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to)
1467 {
1468     return generate_merge_patch(from, to, false);
1469 }
1470 
cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from,cJSON * const to)1471 CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to)
1472 {
1473     return generate_merge_patch(from, to, true);
1474 }
1475