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