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