RTS API Documentation  1.10.11
Macros | Enumerations | Functions
cJSON_Utils.c File Reference
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "switch_cJSON_Utils.h"
+ Include dependency graph for cJSON_Utils.c:

Go to the source code of this file.

Macros

#define true   ((cJSON_bool)1)
 
#define false   ((cJSON_bool)0)
 

Enumerations

enum  patch_operation {
  INVALID, ADD, REMOVE, REPLACE,
  MOVE, COPY, TEST
}
 

Functions

static unsigned char * cJSONUtils_strdup (const unsigned char *const string)
 
static int compare_strings (const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive)
 
static cJSON_bool compare_pointers (const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive)
 
static size_t pointer_encoded_length (const unsigned char *string)
 
static void encode_string_as_pointer (unsigned char *destination, const unsigned char *source)
 
 CJSON_PUBLIC (char *)
 
static cJSONget_array_item (const cJSON *array, size_t item)
 
static cJSON_bool decode_array_index_from_pointer (const unsigned char *const pointer, size_t *const index)
 
static cJSONget_item_from_pointer (cJSON *const object, const char *pointer, const cJSON_bool case_sensitive)
 
 CJSON_PUBLIC (cJSON *)
 
static void decode_pointer_inplace (unsigned char *string)
 
static cJSONdetach_item_from_array (cJSON *array, size_t which)
 
static cJSONdetach_path (cJSON *object, const unsigned char *path, const cJSON_bool case_sensitive)
 
static cJSONsort_list (cJSON *list, const cJSON_bool case_sensitive)
 
static void sort_object (cJSON *const object, const cJSON_bool case_sensitive)
 
static cJSON_bool compare_json (cJSON *a, cJSON *b, const cJSON_bool case_sensitive)
 
static cJSON_bool insert_item_in_array (cJSON *array, size_t which, cJSON *newitem)
 
static cJSONget_object_item (const cJSON *const object, const char *name, const cJSON_bool case_sensitive)
 
static enum patch_operation decode_patch_operation (const cJSON *const patch, const cJSON_bool case_sensitive)
 
static void overwrite_item (cJSON *const root, const cJSON replacement)
 
static int apply_patch (cJSON *object, const cJSON *patch, const cJSON_bool case_sensitive)
 
 CJSON_PUBLIC (int)
 
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)
 
 CJSON_PUBLIC (void)
 
static void create_patches (cJSON *const patches, const unsigned char *const path, cJSON *const from, cJSON *const to, const cJSON_bool case_sensitive)
 
static cJSONmerge_patch (cJSON *target, const cJSON *const patch, const cJSON_bool case_sensitive)
 
static cJSONgenerate_merge_patch (cJSON *const from, cJSON *const to, const cJSON_bool case_sensitive)
 

Macro Definition Documentation

◆ false

#define false   ((cJSON_bool)0)

Definition at line 58 of file cJSON_Utils.c.

◆ true

#define true   ((cJSON_bool)1)

Definition at line 53 of file cJSON_Utils.c.

Enumeration Type Documentation

◆ patch_operation

Enumerator
INVALID 
ADD 
REMOVE 
REPLACE 
MOVE 
COPY 
TEST 

Definition at line 720 of file cJSON_Utils.c.

Function Documentation

◆ apply_patch()

static int apply_patch ( cJSON object,
const cJSON patch,
const cJSON_bool  case_sensitive 
)
static

Definition at line 787 of file cJSON_Utils.c.

References ADD, cJSON_Invalid, cJSONUtils_strdup(), compare_json(), COPY, decode_array_index_from_pointer(), decode_patch_operation(), decode_pointer_inplace(), detach_path(), get_item_from_pointer(), get_object_item(), index, insert_item_in_array(), INVALID, MOVE, overwrite_item(), path, REMOVE, REPLACE, cJSON::string, TEST, value, and cJSON::valuestring.

Referenced by CJSON_PUBLIC().

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 */
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 }
const char *const const char *const const cJSON *const value
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
static void decode_pointer_inplace(unsigned char *string)
Definition: cJSON_Utils.c:343
char * string
Definition: switch_cJSON.h:114
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 * get_item_from_pointer(cJSON *const object, const char *pointer, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:285
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
static unsigned char * cJSONUtils_strdup(const unsigned char *const string)
Definition: cJSON_Utils.c:60
const char *const const char *const path
patch_operation
Definition: cJSON_Utils.c:720
static enum patch_operation decode_patch_operation(const cJSON *const patch, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:722
static cJSON * detach_path(cJSON *object, const unsigned char *path, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:410
static cJSON_bool decode_array_index_from_pointer(const unsigned char *const pointer, size_t *const index)
Definition: cJSON_Utils.c:258
static void overwrite_item(cJSON *const root, const cJSON replacement)
Definition: cJSON_Utils.c:764

◆ CJSON_PUBLIC() [1/4]

CJSON_PUBLIC ( char *  )

Definition at line 183 of file cJSON_Utils.c.

References cJSON::child, cJSONUtils_strdup(), encode_string_as_pointer(), cJSON::next, pointer_encoded_length(), and cJSON::string.

Referenced by CJSON_PUBLIC(), create_patches(), generate_merge_patch(), and merge_patch().

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 }
struct cJSON * child
Definition: switch_cJSON.h:101
char * string
Definition: switch_cJSON.h:114
struct cJSON * next
Definition: switch_cJSON.h:98
static void encode_string_as_pointer(unsigned char *destination, const unsigned char *source)
Definition: cJSON_Utils.c:159
static unsigned char * cJSONUtils_strdup(const unsigned char *const string)
Definition: cJSON_Utils.c:60
const cJSON *const target
static size_t pointer_encoded_length(const unsigned char *string)
Definition: cJSON_Utils.c:143

◆ CJSON_PUBLIC() [2/4]

CJSON_PUBLIC ( cJSON )

Definition at line 332 of file cJSON_Utils.c.

References CJSON_PUBLIC(), get_item_from_pointer(), and pointer.

333 {
334  return get_item_from_pointer(object, pointer, false);
335 }
const char * pointer
static cJSON * get_item_from_pointer(cJSON *const object, const char *pointer, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:285

◆ CJSON_PUBLIC() [3/4]

CJSON_PUBLIC ( int  )

Definition at line 1016 of file cJSON_Utils.c.

References apply_patch(), cJSON::child, CJSON_PUBLIC(), cJSON::next, and 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 }
struct cJSON * child
Definition: switch_cJSON.h:101
struct cJSON * next
Definition: switch_cJSON.h:98
const cJSON *const patches
static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:787

◆ CJSON_PUBLIC() [4/4]

CJSON_PUBLIC ( void  )

Definition at line 1114 of file cJSON_Utils.c.

References compose_patch().

1115 {
1116  compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value);
1117 }
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
const char *const const char *const const cJSON *const value
const char *const operation
const char *const const char *const path

◆ cJSONUtils_strdup()

static unsigned char* cJSONUtils_strdup ( const unsigned char *const  string)
static

Definition at line 60 of file cJSON_Utils.c.

References length.

Referenced by apply_patch(), CJSON_PUBLIC(), and detach_path().

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 }
char const int length
Definition: switch_cJSON.h:153

◆ compare_json()

static cJSON_bool compare_json ( cJSON a,
cJSON b,
const cJSON_bool  case_sensitive 
)
static

Definition at line 584 of file cJSON_Utils.c.

References cJSON::child, cJSON_Array, cJSON_Number, cJSON_Object, cJSON_String, compare_strings(), cJSON::next, sort_object(), cJSON::string, cJSON::type, cJSON::valuedouble, cJSON::valueint, and cJSON::valuestring.

Referenced by apply_patch(), and generate_merge_patch().

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:
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 }
#define cJSON_Object
Definition: switch_cJSON.h:88
int cJSON_bool
Definition: switch_cJSON.h:124
int valueint
Definition: switch_cJSON.h:109
char * valuestring
Definition: switch_cJSON.h:107
#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
#define cJSON_String
Definition: switch_cJSON.h:86
struct cJSON * child
Definition: switch_cJSON.h:101
char * string
Definition: switch_cJSON.h:114
static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:584
struct cJSON * next
Definition: switch_cJSON.h:98
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
int type
Definition: switch_cJSON.h:104
static int compare_strings(const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:77
double valuedouble
Definition: switch_cJSON.h:111
#define cJSON_Number
Definition: switch_cJSON.h:85

◆ compare_pointers()

static cJSON_bool compare_pointers ( const unsigned char *  name,
const unsigned char *  pointer,
const cJSON_bool  case_sensitive 
)
static

Definition at line 106 of file cJSON_Utils.c.

References pointer.

Referenced by get_item_from_pointer().

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 }
const char * pointer
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
const char *const name
Definition: switch_cJSON.h:250

◆ compare_strings()

static int compare_strings ( const unsigned char *  string1,
const unsigned char *  string2,
const cJSON_bool  case_sensitive 
)
static

Definition at line 77 of file cJSON_Utils.c.

Referenced by compare_json(), create_patches(), and sort_list().

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 }
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243

◆ compose_patch()

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 
)
static

Definition at line 1074 of file cJSON_Utils.c.

References encode_string_as_pointer(), patch, and pointer_encoded_length().

Referenced by CJSON_PUBLIC(), and create_patches().

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 }
static void encode_string_as_pointer(unsigned char *destination, const unsigned char *source)
Definition: cJSON_Utils.c:159
const char *const operation
const char *const const char *const path
static size_t pointer_encoded_length(const unsigned char *string)
Definition: cJSON_Utils.c:143
const cJSON *const patch

◆ create_patches()

static void create_patches ( cJSON *const  patches,
const unsigned char *const  path,
cJSON *const  from,
cJSON *const  to,
const cJSON_bool  case_sensitive 
)
static

Definition at line 1119 of file cJSON_Utils.c.

References cJSON::child, cJSON_Array, cJSON_Number, cJSON_Object, CJSON_PUBLIC(), cJSON_String, compare_strings(), compose_patch(), encode_string_as_pointer(), index, cJSON::next, patches, pointer_encoded_length(), sort_object(), cJSON::string, to, cJSON::type, cJSON::valuedouble, cJSON::valueint, and cJSON::valuestring.

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);
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 }
#define cJSON_Object
Definition: switch_cJSON.h:88
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
int valueint
Definition: switch_cJSON.h:109
char * valuestring
Definition: switch_cJSON.h:107
#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
#define cJSON_String
Definition: switch_cJSON.h:86
struct cJSON * child
Definition: switch_cJSON.h:101
char * string
Definition: switch_cJSON.h:114
int index
Definition: switch_cJSON.h:160
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
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
static void encode_string_as_pointer(unsigned char *destination, const unsigned char *source)
Definition: cJSON_Utils.c:159
const char *const const char *const path
int type
Definition: switch_cJSON.h:104
static int compare_strings(const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:77
double valuedouble
Definition: switch_cJSON.h:111
static size_t pointer_encoded_length(const unsigned char *string)
Definition: cJSON_Utils.c:143
#define cJSON_Number
Definition: switch_cJSON.h:85

◆ decode_array_index_from_pointer()

static cJSON_bool decode_array_index_from_pointer ( const unsigned char *const  pointer,
size_t *const  index 
)
static

Definition at line 258 of file cJSON_Utils.c.

Referenced by apply_patch(), detach_path(), and get_item_from_pointer().

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 }
const char * pointer
int index
Definition: switch_cJSON.h:160

◆ decode_patch_operation()

static enum patch_operation decode_patch_operation ( const cJSON *const  patch,
const cJSON_bool  case_sensitive 
)
static

Definition at line 722 of file cJSON_Utils.c.

References ADD, COPY, get_object_item(), INVALID, MOVE, operation, REMOVE, REPLACE, TEST, and cJSON::valuestring.

Referenced by apply_patch().

723 {
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 }
char * valuestring
Definition: switch_cJSON.h:107
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
const char *const operation

◆ decode_pointer_inplace()

static void decode_pointer_inplace ( unsigned char *  string)
static

Definition at line 343 of file cJSON_Utils.c.

References string.

Referenced by apply_patch(), and detach_path().

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 }
const char *const string
Definition: switch_cJSON.h:162

◆ detach_item_from_array()

static cJSON* detach_item_from_array ( cJSON array,
size_t  which 
)
static

Definition at line 377 of file cJSON_Utils.c.

References cJSON::child, cJSON::next, and cJSON::prev.

Referenced by detach_path().

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 }
struct cJSON * prev
Definition: switch_cJSON.h:99
int which
Definition: switch_cJSON.h:222
struct cJSON * child
Definition: switch_cJSON.h:101
struct cJSON * next
Definition: switch_cJSON.h:98

◆ detach_path()

static cJSON* detach_path ( cJSON object,
const unsigned char *  path,
const cJSON_bool  case_sensitive 
)
static

Definition at line 410 of file cJSON_Utils.c.

References cJSONUtils_strdup(), decode_array_index_from_pointer(), decode_pointer_inplace(), detach_item_from_array(), get_item_from_pointer(), and index.

Referenced by apply_patch().

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 }
static void decode_pointer_inplace(unsigned char *string)
Definition: cJSON_Utils.c:343
int index
Definition: switch_cJSON.h:160
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
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
static unsigned char * cJSONUtils_strdup(const unsigned char *const string)
Definition: cJSON_Utils.c:60
const char *const const char *const path
static cJSON_bool decode_array_index_from_pointer(const unsigned char *const pointer, size_t *const index)
Definition: cJSON_Utils.c:258

◆ encode_string_as_pointer()

static void encode_string_as_pointer ( unsigned char *  destination,
const unsigned char *  source 
)
static

Definition at line 159 of file cJSON_Utils.c.

Referenced by CJSON_PUBLIC(), compose_patch(), and create_patches().

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 }

◆ generate_merge_patch()

static cJSON* generate_merge_patch ( cJSON *const  from,
cJSON *const  to,
const cJSON_bool  case_sensitive 
)
static

Definition at line 1368 of file cJSON_Utils.c.

References cJSON::child, CJSON_PUBLIC(), compare_json(), cJSON::next, patch, sort_object(), and cJSON::string.

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);
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 }
static void sort_object(cJSON *const object, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:575
struct cJSON * child
Definition: switch_cJSON.h:101
char * string
Definition: switch_cJSON.h:114
static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:584
struct cJSON * next
Definition: switch_cJSON.h:98
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
const cJSON *const patch

◆ get_array_item()

static cJSON* get_array_item ( const cJSON array,
size_t  item 
)
static

Definition at line 246 of file cJSON_Utils.c.

References cJSON::child, and cJSON::next.

Referenced by get_item_from_pointer().

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 }
struct cJSON * child
Definition: switch_cJSON.h:101
struct cJSON * next
Definition: switch_cJSON.h:98
cJSON * item
Definition: switch_cJSON.h:210

◆ get_item_from_pointer()

static cJSON* get_item_from_pointer ( cJSON *const  object,
const char *  pointer,
const cJSON_bool  case_sensitive 
)
static

Definition at line 285 of file cJSON_Utils.c.

References cJSON::child, compare_pointers(), decode_array_index_from_pointer(), get_array_item(), index, cJSON::next, and cJSON::string.

Referenced by apply_patch(), CJSON_PUBLIC(), and detach_path().

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 }
const char * pointer
struct cJSON * child
Definition: switch_cJSON.h:101
char * string
Definition: switch_cJSON.h:114
int index
Definition: switch_cJSON.h:160
struct cJSON * next
Definition: switch_cJSON.h:98
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
static cJSON_bool compare_pointers(const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:106
static cJSON_bool decode_array_index_from_pointer(const unsigned char *const pointer, size_t *const index)
Definition: cJSON_Utils.c:258
static cJSON * get_array_item(const cJSON *array, size_t item)
Definition: cJSON_Utils.c:246

◆ get_object_item()

static cJSON* get_object_item ( const cJSON *const  object,
const char *  name,
const cJSON_bool  case_sensitive 
)
static

Definition at line 710 of file cJSON_Utils.c.

Referenced by apply_patch(), and decode_patch_operation().

711 {
712  if (case_sensitive)
713  {
714  return cJSON_GetObjectItemCaseSensitive(object, name);
715  }
716 
717  return cJSON_GetObjectItem(object, name);
718 }
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
const char *const name
Definition: switch_cJSON.h:250

◆ insert_item_in_array()

static cJSON_bool insert_item_in_array ( cJSON array,
size_t  which,
cJSON newitem 
)
static

Definition at line 673 of file cJSON_Utils.c.

References cJSON::child, newitem, cJSON::next, and cJSON::prev.

Referenced by apply_patch().

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 }
int cJSON * newitem
Definition: switch_cJSON.h:230
struct cJSON * prev
Definition: switch_cJSON.h:99
int which
Definition: switch_cJSON.h:222
struct cJSON * child
Definition: switch_cJSON.h:101
struct cJSON * next
Definition: switch_cJSON.h:98

◆ merge_patch()

static cJSON* merge_patch ( cJSON target,
const cJSON *const  patch,
const cJSON_bool  case_sensitive 
)
static

Definition at line 1299 of file cJSON_Utils.c.

References cJSON::child, CJSON_PUBLIC(), cJSON::next, patch, replacement, cJSON::string, and target.

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 }
static cJSON * merge_patch(cJSON *target, const cJSON *const patch, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:1299
struct cJSON * child
Definition: switch_cJSON.h:101
char * string
Definition: switch_cJSON.h:114
struct cJSON * next
Definition: switch_cJSON.h:98
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
cJSON *const cJSON * replacement
Definition: switch_cJSON.h:231
const cJSON *const target

◆ overwrite_item()

static void overwrite_item ( cJSON *const  root,
const cJSON  replacement 
)
static

Definition at line 764 of file cJSON_Utils.c.

References cJSON::child, cJSON::string, and cJSON::valuestring.

Referenced by apply_patch().

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 }
char * valuestring
Definition: switch_cJSON.h:107
struct cJSON * child
Definition: switch_cJSON.h:101
char * string
Definition: switch_cJSON.h:114

◆ pointer_encoded_length()

static size_t pointer_encoded_length ( const unsigned char *  string)
static

Definition at line 143 of file cJSON_Utils.c.

References length.

Referenced by CJSON_PUBLIC(), compose_patch(), and create_patches().

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 }
char const int length
Definition: switch_cJSON.h:153

◆ sort_list()

static cJSON* sort_list ( cJSON list,
const cJSON_bool  case_sensitive 
)
static

Definition at line 464 of file cJSON_Utils.c.

References compare_strings(), cJSON::next, cJSON::prev, and cJSON::string.

Referenced by sort_object().

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 }
struct cJSON * prev
Definition: switch_cJSON.h:99
char * string
Definition: switch_cJSON.h:114
struct cJSON * next
Definition: switch_cJSON.h:98
static cJSON * sort_list(cJSON *list, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:464
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243
static int compare_strings(const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:77

◆ sort_object()

static void sort_object ( cJSON *const  object,
const cJSON_bool  case_sensitive 
)
static

Definition at line 575 of file cJSON_Utils.c.

References cJSON::child, and sort_list().

Referenced by compare_json(), create_patches(), and generate_merge_patch().

576 {
577  if (object == NULL)
578  {
579  return;
580  }
581  object->child = sort_list(object->child, case_sensitive);
582 }
struct cJSON * child
Definition: switch_cJSON.h:101
static cJSON * sort_list(cJSON *list, const cJSON_bool case_sensitive)
Definition: cJSON_Utils.c:464
const cJSON *const const cJSON_bool case_sensitive
Definition: switch_cJSON.h:243