• 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     if (parent_pointer) {
964         child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/');
965     }
966     if (child_pointer != NULL)
967     {
968         child_pointer[0] = '\0';
969         child_pointer++;
970     }
971     parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive);
972     decode_pointer_inplace(child_pointer);
973 
974     /* add, remove, replace, move, copy, test. */
975     if ((parent == NULL) || (child_pointer == NULL))
976     {
977         /* Couldn't find object to add to. */
978         status = 9;
979         goto cleanup;
980     }
981     else if (cJSON_IsArray(parent))
982     {
983         if (strcmp((char*)child_pointer, "-") == 0)
984         {
985             cJSON_AddItemToArray(parent, value);
986             value = NULL;
987         }
988         else
989         {
990             size_t index = 0;
991             if (!decode_array_index_from_pointer(child_pointer, &index))
992             {
993                 status = 11;
994                 goto cleanup;
995             }
996 
997             if (!insert_item_in_array(parent, index, value))
998             {
999                 status = 10;
1000                 goto cleanup;
1001             }
1002             value = NULL;
1003         }
1004     }
1005     else if (cJSON_IsObject(parent))
1006     {
1007         if (case_sensitive)
1008         {
1009             cJSON_DeleteItemFromObjectCaseSensitive(parent, (char*)child_pointer);
1010         }
1011         else
1012         {
1013             cJSON_DeleteItemFromObject(parent, (char*)child_pointer);
1014         }
1015         cJSON_AddItemToObject(parent, (char*)child_pointer, value);
1016         value = NULL;
1017     }
1018     else /* parent is not an object */
1019     {
1020         /* Couldn't find object to add to. */
1021         status = 9;
1022         goto cleanup;
1023     }
1024 
1025 cleanup:
1026     if (value != NULL)
1027     {
1028         cJSON_Delete(value);
1029     }
1030     if (parent_pointer != NULL)
1031     {
1032         cJSON_free(parent_pointer);
1033     }
1034 
1035     return status;
1036 }
1037 
cJSONUtils_ApplyPatches(cJSON * const object,const cJSON * const patches)1038 CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches)
1039 {
1040     const cJSON *current_patch = NULL;
1041     int status = 0;
1042 
1043     if (!cJSON_IsArray(patches))
1044     {
1045         /* malformed patches. */
1046         return 1;
1047     }
1048 
1049     if (patches != NULL)
1050     {
1051         current_patch = patches->child;
1052     }
1053 
1054     while (current_patch != NULL)
1055     {
1056         status = apply_patch(object, current_patch, false);
1057         if (status != 0)
1058         {
1059             return status;
1060         }
1061         current_patch = current_patch->next;
1062     }
1063 
1064     return 0;
1065 }
1066 
cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object,const cJSON * const patches)1067 CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches)
1068 {
1069     const cJSON *current_patch = NULL;
1070     int status = 0;
1071 
1072     if (!cJSON_IsArray(patches))
1073     {
1074         /* malformed patches. */
1075         return 1;
1076     }
1077 
1078     if (patches != NULL)
1079     {
1080         current_patch = patches->child;
1081     }
1082 
1083     while (current_patch != NULL)
1084     {
1085         status = apply_patch(object, current_patch, true);
1086         if (status != 0)
1087         {
1088             return status;
1089         }
1090         current_patch = current_patch->next;
1091     }
1092 
1093     return 0;
1094 }
1095 
compose_patch(cJSON * const patches,const unsigned char * const operation,const unsigned char * const path,const unsigned char * suffix,const cJSON * const value)1096 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)
1097 {
1098     cJSON *patch = NULL;
1099 
1100     if ((patches == NULL) || (operation == NULL) || (path == NULL))
1101     {
1102         return;
1103     }
1104 
1105     patch = cJSON_CreateObject();
1106     if (patch == NULL)
1107     {
1108         return;
1109     }
1110     cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)operation));
1111 
1112     if (suffix == NULL)
1113     {
1114         cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path));
1115     }
1116     else
1117     {
1118         size_t suffix_length = pointer_encoded_length(suffix);
1119         size_t path_length = strlen((const char*)path);
1120         unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/"));
1121 
1122         sprintf((char*)full_path, "%s/", (const char*)path);
1123         encode_string_as_pointer(full_path + path_length + 1, suffix);
1124 
1125         cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)full_path));
1126         cJSON_free(full_path);
1127     }
1128 
1129     if (value != NULL)
1130     {
1131         cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(value, 1));
1132     }
1133     cJSON_AddItemToArray(patches, patch);
1134 }
1135 
cJSONUtils_AddPatchToArray(cJSON * const array,const char * const operation,const char * const path,const cJSON * const value)1136 CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value)
1137 {
1138     compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value);
1139 }
1140 
create_patches(cJSON * const patches,const unsigned char * const path,cJSON * const from,cJSON * const to,const cJSON_bool case_sensitive)1141 static void create_patches(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive)
1142 {
1143     if ((from == NULL) || (to == NULL))
1144     {
1145         return;
1146     }
1147 
1148     if ((from->type & 0xFF) != (to->type & 0xFF))
1149     {
1150         compose_patch(patches, (const unsigned char*)"replace", path, 0, to);
1151         return;
1152     }
1153 
1154     switch (from->type & 0xFF)
1155     {
1156         case cJSON_Number:
1157             if ((from->valueint != to->valueint) || !compare_double(from->valuedouble, to->valuedouble))
1158             {
1159                 compose_patch(patches, (const unsigned char*)"replace", path, NULL, to);
1160             }
1161             return;
1162 
1163         case cJSON_String:
1164             if (strcmp(from->valuestring, to->valuestring) != 0)
1165             {
1166                 compose_patch(patches, (const unsigned char*)"replace", path, NULL, to);
1167             }
1168             return;
1169 
1170         case cJSON_Array:
1171         {
1172             size_t index = 0;
1173             cJSON *from_child = from->child;
1174             cJSON *to_child = to->child;
1175             unsigned char *new_path = (unsigned char*)cJSON_malloc(strlen((const char*)path) + 20 + sizeof("/")); /* Allow space for 64bit int. log10(2^64) = 20 */
1176 
1177             /* generate patches for all array elements that exist in both "from" and "to" */
1178             for (index = 0; (from_child != NULL) && (to_child != NULL); (void)(from_child = from_child->next), (void)(to_child = to_child->next), index++)
1179             {
1180                 /* check if conversion to unsigned long is valid
1181                  * This should be eliminated at compile time by dead code elimination
1182                  * if size_t is an alias of unsigned long, or if it is bigger */
1183                 if (index > ULONG_MAX)
1184                 {
1185                     cJSON_free(new_path);
1186                     return;
1187                 }
1188                 sprintf((char*)new_path, "%s/%lu", path, (unsigned long)index); /* path of the current array element */
1189                 create_patches(patches, new_path, from_child, to_child, case_sensitive);
1190             }
1191 
1192             /* remove leftover elements from 'from' that are not in 'to' */
1193             for (; (from_child != NULL); (void)(from_child = from_child->next))
1194             {
1195                 /* check if conversion to unsigned long is valid
1196                  * This should be eliminated at compile time by dead code elimination
1197                  * if size_t is an alias of unsigned long, or if it is bigger */
1198                 if (index > ULONG_MAX)
1199                 {
1200                     cJSON_free(new_path);
1201                     return;
1202                 }
1203                 sprintf((char*)new_path, "%lu", (unsigned long)index);
1204                 compose_patch(patches, (const unsigned char*)"remove", path, new_path, NULL);
1205             }
1206             /* add new elements in 'to' that were not in 'from' */
1207             for (; (to_child != NULL); (void)(to_child = to_child->next), index++)
1208             {
1209                 compose_patch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to_child);
1210             }
1211             cJSON_free(new_path);
1212             return;
1213         }
1214 
1215         case cJSON_Object:
1216         {
1217             cJSON *from_child = NULL;
1218             cJSON *to_child = NULL;
1219             sort_object(from, case_sensitive);
1220             sort_object(to, case_sensitive);
1221 
1222             from_child = from->child;
1223             to_child = to->child;
1224             /* for all object values in the object with more of them */
1225             while ((from_child != NULL) || (to_child != NULL))
1226             {
1227                 int diff;
1228                 if (from_child == NULL)
1229                 {
1230                     diff = 1;
1231                 }
1232                 else if (to_child == NULL)
1233                 {
1234                     diff = -1;
1235                 }
1236                 else
1237                 {
1238                     diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, case_sensitive);
1239                 }
1240 
1241                 if (diff == 0)
1242                 {
1243                     /* both object keys are the same */
1244                     size_t path_length = strlen((const char*)path);
1245                     size_t from_child_name_length = pointer_encoded_length((unsigned char*)from_child->string);
1246                     unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/"));
1247 
1248                     sprintf((char*)new_path, "%s/", path);
1249                     encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string);
1250 
1251                     /* create a patch for the element */
1252                     create_patches(patches, new_path, from_child, to_child, case_sensitive);
1253                     cJSON_free(new_path);
1254 
1255                     from_child = from_child->next;
1256                     to_child = to_child->next;
1257                 }
1258                 else if (diff < 0)
1259                 {
1260                     /* object element doesn't exist in 'to' --> remove it */
1261                     compose_patch(patches, (const unsigned char*)"remove", path, (unsigned char*)from_child->string, NULL);
1262 
1263                     from_child = from_child->next;
1264                 }
1265                 else
1266                 {
1267                     /* object element doesn't exist in 'from' --> add it */
1268                     compose_patch(patches, (const unsigned char*)"add", path, (unsigned char*)to_child->string, to_child);
1269 
1270                     to_child = to_child->next;
1271                 }
1272             }
1273             return;
1274         }
1275 
1276         default:
1277             break;
1278     }
1279 }
1280 
cJSONUtils_GeneratePatches(cJSON * const from,cJSON * const to)1281 CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to)
1282 {
1283     cJSON *patches = NULL;
1284 
1285     if ((from == NULL) || (to == NULL))
1286     {
1287         return NULL;
1288     }
1289 
1290     patches = cJSON_CreateArray();
1291     create_patches(patches, (const unsigned char*)"", from, to, false);
1292 
1293     return patches;
1294 }
1295 
cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from,cJSON * const to)1296 CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to)
1297 {
1298     cJSON *patches = NULL;
1299 
1300     if ((from == NULL) || (to == NULL))
1301     {
1302         return NULL;
1303     }
1304 
1305     patches = cJSON_CreateArray();
1306     create_patches(patches, (const unsigned char*)"", from, to, true);
1307 
1308     return patches;
1309 }
1310 
cJSONUtils_SortObject(cJSON * const object)1311 CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object)
1312 {
1313     sort_object(object, false);
1314 }
1315 
cJSONUtils_SortObjectCaseSensitive(cJSON * const object)1316 CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object)
1317 {
1318     sort_object(object, true);
1319 }
1320 
merge_patch(cJSON * target,const cJSON * const patch,const cJSON_bool case_sensitive)1321 static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_bool case_sensitive)
1322 {
1323     cJSON *patch_child = NULL;
1324 
1325     if (!cJSON_IsObject(patch))
1326     {
1327         /* scalar value, array or NULL, just duplicate */
1328         cJSON_Delete(target);
1329         return cJSON_Duplicate(patch, 1);
1330     }
1331 
1332     if (!cJSON_IsObject(target))
1333     {
1334         cJSON_Delete(target);
1335         target = cJSON_CreateObject();
1336     }
1337 
1338     patch_child = patch->child;
1339     while (patch_child != NULL)
1340     {
1341         if (cJSON_IsNull(patch_child))
1342         {
1343             /* NULL is the indicator to remove a value, see RFC7396 */
1344             if (case_sensitive)
1345             {
1346                 cJSON_DeleteItemFromObjectCaseSensitive(target, patch_child->string);
1347             }
1348             else
1349             {
1350                 cJSON_DeleteItemFromObject(target, patch_child->string);
1351             }
1352         }
1353         else
1354         {
1355             cJSON *replace_me = NULL;
1356             cJSON *replacement = NULL;
1357 
1358             if (case_sensitive)
1359             {
1360                 replace_me = cJSON_DetachItemFromObjectCaseSensitive(target, patch_child->string);
1361             }
1362             else
1363             {
1364                 replace_me = cJSON_DetachItemFromObject(target, patch_child->string);
1365             }
1366 
1367             replacement = merge_patch(replace_me, patch_child, case_sensitive);
1368             if (replacement == NULL)
1369             {
1370                 return NULL;
1371             }
1372 
1373             cJSON_AddItemToObject(target, patch_child->string, replacement);
1374         }
1375         patch_child = patch_child->next;
1376     }
1377     return target;
1378 }
1379 
cJSONUtils_MergePatch(cJSON * target,const cJSON * const patch)1380 CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch)
1381 {
1382     return merge_patch(target, patch, false);
1383 }
1384 
cJSONUtils_MergePatchCaseSensitive(cJSON * target,const cJSON * const patch)1385 CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch)
1386 {
1387     return merge_patch(target, patch, true);
1388 }
1389 
generate_merge_patch(cJSON * const from,cJSON * const to,const cJSON_bool case_sensitive)1390 static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive)
1391 {
1392     cJSON *from_child = NULL;
1393     cJSON *to_child = NULL;
1394     cJSON *patch = NULL;
1395     if (to == NULL)
1396     {
1397         /* patch to delete everything */
1398         return cJSON_CreateNull();
1399     }
1400     if (!cJSON_IsObject(to) || !cJSON_IsObject(from))
1401     {
1402         return cJSON_Duplicate(to, 1);
1403     }
1404 
1405     sort_object(from, case_sensitive);
1406     sort_object(to, case_sensitive);
1407 
1408     from_child = from->child;
1409     to_child = to->child;
1410     patch = cJSON_CreateObject();
1411     if (patch == NULL)
1412     {
1413         return NULL;
1414     }
1415     while (from_child || to_child)
1416     {
1417         int diff;
1418         if (from_child != NULL)
1419         {
1420             if (to_child != NULL)
1421             {
1422                 diff = strcmp(from_child->string, to_child->string);
1423             }
1424             else
1425             {
1426                 diff = -1;
1427             }
1428         }
1429         else
1430         {
1431             diff = 1;
1432         }
1433 
1434         if (diff < 0)
1435         {
1436             /* from has a value that to doesn't have -> remove */
1437             cJSON_AddItemToObject(patch, from_child->string, cJSON_CreateNull());
1438 
1439             from_child = from_child->next;
1440         }
1441         else if (diff > 0)
1442         {
1443             /* to has a value that from doesn't have -> add to patch */
1444             cJSON_AddItemToObject(patch, to_child->string, cJSON_Duplicate(to_child, 1));
1445 
1446             to_child = to_child->next;
1447         }
1448         else
1449         {
1450             /* object key exists in both objects */
1451             if (!compare_json(from_child, to_child, case_sensitive))
1452             {
1453                 /* not identical --> generate a patch */
1454                 cJSON_AddItemToObject(patch, to_child->string, cJSONUtils_GenerateMergePatch(from_child, to_child));
1455             }
1456 
1457             /* next key in the object */
1458             from_child = from_child->next;
1459             to_child = to_child->next;
1460         }
1461     }
1462     if (patch->child == NULL)
1463     {
1464         /* no patch generated */
1465         cJSON_Delete(patch);
1466         return NULL;
1467     }
1468 
1469     return patch;
1470 }
1471 
cJSONUtils_GenerateMergePatch(cJSON * const from,cJSON * const to)1472 CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to)
1473 {
1474     return generate_merge_patch(from, to, false);
1475 }
1476 
cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from,cJSON * const to)1477 CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to)
1478 {
1479     return generate_merge_patch(from, to, true);
1480 }
1481