cJSON_Utils.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. #include <ctype.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include "cJSON_Utils.h"
  6. static unsigned char* cJSONUtils_strdup(const unsigned char* str)
  7. {
  8. size_t len = 0;
  9. unsigned char *copy = NULL;
  10. len = strlen((const char*)str) + 1;
  11. if (!(copy = (unsigned char*)malloc(len)))
  12. {
  13. return NULL;
  14. }
  15. memcpy(copy, str, len);
  16. return copy;
  17. }
  18. static int cJSONUtils_strcasecmp(const unsigned char *s1, const unsigned char *s2)
  19. {
  20. if (!s1)
  21. {
  22. return (s1 == s2) ? 0 : 1; /* both NULL? */
  23. }
  24. if (!s2)
  25. {
  26. return 1;
  27. }
  28. for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)
  29. {
  30. if(*s1 == 0)
  31. {
  32. return 0;
  33. }
  34. }
  35. return tolower(*s1) - tolower(*s2);
  36. }
  37. /* JSON Pointer implementation: */
  38. static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e)
  39. {
  40. if (!a || !e)
  41. {
  42. return (a == e) ? 0 : 1; /* both NULL? */
  43. }
  44. for (; *a && *e && (*e != '/'); a++, e++) /* compare until next '/' */
  45. {
  46. if (*e == '~')
  47. {
  48. /* check for escaped '~' (~0) and '/' (~1) */
  49. if (!((e[1] == '0') && (*a == '~')) && !((e[1] == '1') && (*a == '/')))
  50. {
  51. /* invalid escape sequence or wrong character in *a */
  52. return 1;
  53. }
  54. else
  55. {
  56. e++;
  57. }
  58. }
  59. else if (tolower(*a) != tolower(*e))
  60. {
  61. return 1;
  62. }
  63. }
  64. if (((*e != 0) && (*e != '/')) != (*a != 0))
  65. {
  66. /* one string has ended, the other not */
  67. return 1;
  68. }
  69. return 0;
  70. }
  71. static int cJSONUtils_PointerEncodedstrlen(const unsigned char *s)
  72. {
  73. int l = 0;
  74. for (; *s; s++, l++)
  75. {
  76. if ((*s == '~') || (*s == '/'))
  77. {
  78. l++;
  79. }
  80. }
  81. return l;
  82. }
  83. static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned char *s)
  84. {
  85. for (; *s; s++)
  86. {
  87. if (*s == '/')
  88. {
  89. *d++ = '~';
  90. *d++ = '1';
  91. }
  92. else if (*s == '~')
  93. {
  94. *d++ = '~';
  95. *d++ = '0';
  96. }
  97. else
  98. {
  99. *d++ = *s;
  100. }
  101. }
  102. *d = '\0';
  103. }
  104. char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
  105. {
  106. int type = object->type;
  107. int c = 0;
  108. cJSON *obj = 0;
  109. if (object == target)
  110. {
  111. /* found */
  112. return (char*)cJSONUtils_strdup((const unsigned char*)"");
  113. }
  114. /* recursively search all children of the object */
  115. for (obj = object->child; obj; obj = obj->next, c++)
  116. {
  117. unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target);
  118. if (found)
  119. {
  120. if ((type & 0xFF) == cJSON_Array)
  121. {
  122. /* reserve enough memory for a 64 bit integer + '/' and '\0' */
  123. unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23);
  124. sprintf((char*)ret, "/%d%s", c, found); /* /<array_index><path> */
  125. free(found);
  126. return (char*)ret;
  127. }
  128. else if ((type & 0xFF) == cJSON_Object)
  129. {
  130. unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2);
  131. *ret = '/';
  132. cJSONUtils_PointerEncodedstrcpy(ret + 1, (unsigned char*)obj->string);
  133. strcat((char*)ret, (char*)found);
  134. free(found);
  135. return (char*)ret;
  136. }
  137. /* reached leaf of the tree, found nothing */
  138. free(found);
  139. return NULL;
  140. }
  141. }
  142. /* not found */
  143. return NULL;
  144. }
  145. cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer)
  146. {
  147. /* follow path of the pointer */
  148. while ((*pointer++ == '/') && object)
  149. {
  150. if ((object->type & 0xFF) == cJSON_Array)
  151. {
  152. int which = 0;
  153. /* parse array index */
  154. while ((*pointer >= '0') && (*pointer <= '9'))
  155. {
  156. which = (10 * which) + (*pointer++ - '0');
  157. }
  158. if (*pointer && (*pointer != '/'))
  159. {
  160. /* not end of string or new path token */
  161. return NULL;
  162. }
  163. object = cJSON_GetArrayItem(object, which);
  164. }
  165. else if ((object->type & 0xFF) == cJSON_Object)
  166. {
  167. object = object->child;
  168. /* GetObjectItem. */
  169. while (object && cJSONUtils_Pstrcasecmp((unsigned char*)object->string, (const unsigned char*)pointer))
  170. {
  171. object = object->next;
  172. }
  173. /* skip to the next path token or end of string */
  174. while (*pointer && (*pointer != '/'))
  175. {
  176. pointer++;
  177. }
  178. }
  179. else
  180. {
  181. return NULL;
  182. }
  183. }
  184. return object;
  185. }
  186. /* JSON Patch implementation. */
  187. static void cJSONUtils_InplaceDecodePointerString(unsigned char *string)
  188. {
  189. unsigned char *s2 = string;
  190. if (string == NULL) {
  191. return;
  192. }
  193. for (; *string; s2++, string++)
  194. {
  195. *s2 = (*string != '~')
  196. ? (*string)
  197. : ((*(++string) == '0')
  198. ? '~'
  199. : '/');
  200. }
  201. *s2 = '\0';
  202. }
  203. static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path)
  204. {
  205. unsigned char *parentptr = NULL;
  206. unsigned char *childptr = NULL;
  207. cJSON *parent = NULL;
  208. cJSON *ret = NULL;
  209. /* copy path and split it in parent and child */
  210. parentptr = cJSONUtils_strdup(path);
  211. if (parentptr == NULL) {
  212. return NULL;
  213. }
  214. childptr = (unsigned char*)strrchr((char*)parentptr, '/'); /* last '/' */
  215. if (childptr == NULL)
  216. {
  217. free(parentptr);
  218. return NULL;
  219. }
  220. /* split strings */
  221. *childptr++ = '\0';
  222. parent = cJSONUtils_GetPointer(object, (char*)parentptr);
  223. cJSONUtils_InplaceDecodePointerString(childptr);
  224. if (!parent)
  225. {
  226. /* Couldn't find object to remove child from. */
  227. ret = NULL;
  228. }
  229. else if ((parent->type & 0xFF) == cJSON_Array)
  230. {
  231. ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr));
  232. }
  233. else if ((parent->type & 0xFF) == cJSON_Object)
  234. {
  235. ret = cJSON_DetachItemFromObject(parent, (char*)childptr);
  236. }
  237. free(parentptr);
  238. /* return the detachted item */
  239. return ret;
  240. }
  241. static int cJSONUtils_Compare(cJSON *a, cJSON *b)
  242. {
  243. if ((a->type & 0xFF) != (b->type & 0xFF))
  244. {
  245. /* mismatched type. */
  246. return -1;
  247. }
  248. switch (a->type & 0xFF)
  249. {
  250. case cJSON_Number:
  251. /* numeric mismatch. */
  252. return ((a->valueint != b->valueint) || (a->valuedouble != b->valuedouble)) ? -2 : 0;
  253. case cJSON_String:
  254. /* string mismatch. */
  255. return (strcmp(a->valuestring, b->valuestring) != 0) ? -3 : 0;
  256. case cJSON_Array:
  257. for (a = a->child, b = b->child; a && b; a = a->next, b = b->next)
  258. {
  259. int err = cJSONUtils_Compare(a, b);
  260. if (err)
  261. {
  262. return err;
  263. }
  264. }
  265. /* array size mismatch? (one of both children is not NULL) */
  266. return (a || b) ? -4 : 0;
  267. case cJSON_Object:
  268. cJSONUtils_SortObject(a);
  269. cJSONUtils_SortObject(b);
  270. a = a->child;
  271. b = b->child;
  272. while (a && b)
  273. {
  274. int err = 0;
  275. /* compare object keys */
  276. if (cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string))
  277. {
  278. /* missing member */
  279. return -6;
  280. }
  281. err = cJSONUtils_Compare(a, b);
  282. if (err)
  283. {
  284. return err;
  285. }
  286. a = a->next;
  287. b = b->next;
  288. }
  289. /* object length mismatch (one of both children is not null) */
  290. return (a || b) ? -5 : 0;
  291. default:
  292. break;
  293. }
  294. /* null, true or false */
  295. return 0;
  296. }
  297. static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
  298. {
  299. cJSON *op = NULL;
  300. cJSON *path = NULL;
  301. cJSON *value = NULL;
  302. cJSON *parent = NULL;
  303. int opcode = 0;
  304. unsigned char *parentptr = NULL;
  305. unsigned char *childptr = NULL;
  306. op = cJSON_GetObjectItem(patch, "op");
  307. path = cJSON_GetObjectItem(patch, "path");
  308. if (!op || !path)
  309. {
  310. /* malformed patch. */
  311. return 2;
  312. }
  313. /* decode operation */
  314. if (!strcmp(op->valuestring, "add"))
  315. {
  316. opcode = 0;
  317. }
  318. else if (!strcmp(op->valuestring, "remove"))
  319. {
  320. opcode = 1;
  321. }
  322. else if (!strcmp(op->valuestring, "replace"))
  323. {
  324. opcode = 2;
  325. }
  326. else if (!strcmp(op->valuestring, "move"))
  327. {
  328. opcode = 3;
  329. }
  330. else if (!strcmp(op->valuestring, "copy"))
  331. {
  332. opcode = 4;
  333. }
  334. else if (!strcmp(op->valuestring, "test"))
  335. {
  336. /* compare value: {...} with the given path */
  337. return cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value"));
  338. }
  339. else
  340. {
  341. /* unknown opcode. */
  342. return 3;
  343. }
  344. /* Remove/Replace */
  345. if ((opcode == 1) || (opcode == 2))
  346. {
  347. /* Get rid of old. */
  348. cJSON_Delete(cJSONUtils_PatchDetach(object, (unsigned char*)path->valuestring));
  349. if (opcode == 1)
  350. {
  351. /* For Remove, this is job done. */
  352. return 0;
  353. }
  354. }
  355. /* Copy/Move uses "from". */
  356. if ((opcode == 3) || (opcode == 4))
  357. {
  358. cJSON *from = cJSON_GetObjectItem(patch, "from");
  359. if (!from)
  360. {
  361. /* missing "from" for copy/move. */
  362. return 4;
  363. }
  364. if (opcode == 3)
  365. {
  366. /* move */
  367. value = cJSONUtils_PatchDetach(object, (unsigned char*)from->valuestring);
  368. }
  369. if (opcode == 4)
  370. {
  371. /* copy */
  372. value = cJSONUtils_GetPointer(object, from->valuestring);
  373. }
  374. if (!value)
  375. {
  376. /* missing "from" for copy/move. */
  377. return 5;
  378. }
  379. if (opcode == 4)
  380. {
  381. value = cJSON_Duplicate(value, 1);
  382. }
  383. if (!value)
  384. {
  385. /* out of memory for copy/move. */
  386. return 6;
  387. }
  388. }
  389. else /* Add/Replace uses "value". */
  390. {
  391. value = cJSON_GetObjectItem(patch, "value");
  392. if (!value)
  393. {
  394. /* missing "value" for add/replace. */
  395. return 7;
  396. }
  397. value = cJSON_Duplicate(value, 1);
  398. if (!value)
  399. {
  400. /* out of memory for add/replace. */
  401. return 8;
  402. }
  403. }
  404. /* Now, just add "value" to "path". */
  405. /* split pointer in parent and child */
  406. parentptr = cJSONUtils_strdup((unsigned char*)path->valuestring);
  407. childptr = (unsigned char*)strrchr((char*)parentptr, '/');
  408. if (childptr)
  409. {
  410. *childptr++ = '\0';
  411. }
  412. parent = cJSONUtils_GetPointer(object, (char*)parentptr);
  413. cJSONUtils_InplaceDecodePointerString(childptr);
  414. /* add, remove, replace, move, copy, test. */
  415. if (!parent)
  416. {
  417. /* Couldn't find object to add to. */
  418. free(parentptr);
  419. cJSON_Delete(value);
  420. return 9;
  421. }
  422. else if ((parent->type & 0xFF) == cJSON_Array)
  423. {
  424. if (!strcmp((char*)childptr, "-"))
  425. {
  426. cJSON_AddItemToArray(parent, value);
  427. }
  428. else
  429. {
  430. cJSON_InsertItemInArray(parent, atoi((char*)childptr), value);
  431. }
  432. }
  433. else if ((parent->type & 0xFF) == cJSON_Object)
  434. {
  435. cJSON_DeleteItemFromObject(parent, (char*)childptr);
  436. cJSON_AddItemToObject(parent, (char*)childptr, value);
  437. }
  438. else
  439. {
  440. cJSON_Delete(value);
  441. }
  442. free(parentptr);
  443. return 0;
  444. }
  445. int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
  446. {
  447. int err = 0;
  448. if ((patches->type & 0xFF) != cJSON_Array)
  449. {
  450. /* malformed patches. */
  451. return 1;
  452. }
  453. if (patches)
  454. {
  455. patches = patches->child;
  456. }
  457. while (patches)
  458. {
  459. if ((err = cJSONUtils_ApplyPatch(object, patches)))
  460. {
  461. return err;
  462. }
  463. patches = patches->next;
  464. }
  465. return 0;
  466. }
  467. static void cJSONUtils_GeneratePatch(cJSON *patches, const unsigned char *op, const unsigned char *path, const unsigned char *suffix, cJSON *val)
  468. {
  469. cJSON *patch = cJSON_CreateObject();
  470. cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)op));
  471. if (suffix)
  472. {
  473. unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen(suffix) + 2);
  474. cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", (const char*)path), suffix);
  475. cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)newpath));
  476. free(newpath);
  477. }
  478. else
  479. {
  480. cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path));
  481. }
  482. if (val)
  483. {
  484. cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(val, 1));
  485. }
  486. cJSON_AddItemToArray(patches, patch);
  487. }
  488. void cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val)
  489. {
  490. cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val);
  491. }
  492. static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, cJSON *from, cJSON *to)
  493. {
  494. if ((from->type & 0xFF) != (to->type & 0xFF))
  495. {
  496. cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
  497. return;
  498. }
  499. switch ((from->type & 0xFF))
  500. {
  501. case cJSON_Number:
  502. if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble))
  503. {
  504. cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
  505. }
  506. return;
  507. case cJSON_String:
  508. if (strcmp(from->valuestring, to->valuestring) != 0)
  509. {
  510. cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to);
  511. }
  512. return;
  513. case cJSON_Array:
  514. {
  515. int c = 0;
  516. unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + 23); /* Allow space for 64bit int. */
  517. /* generate patches for all array elements that exist in "from" and "to" */
  518. for (c = 0, from = from->child, to = to->child; from && to; from = from->next, to = to->next, c++)
  519. {
  520. sprintf((char*)newpath, "%s/%d", path, c); /* path of the current array element */
  521. cJSONUtils_CompareToPatch(patches, newpath, from, to);
  522. }
  523. /* remove leftover elements from 'from' that are not in 'to' */
  524. for (; from; from = from->next, c++)
  525. {
  526. sprintf((char*)newpath, "%d", c);
  527. cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, newpath, 0);
  528. }
  529. /* add new elements in 'to' that were not in 'from' */
  530. for (; to; to = to->next, c++)
  531. {
  532. cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to);
  533. }
  534. free(newpath);
  535. return;
  536. }
  537. case cJSON_Object:
  538. {
  539. cJSON *a = NULL;
  540. cJSON *b = NULL;
  541. cJSONUtils_SortObject(from);
  542. cJSONUtils_SortObject(to);
  543. a = from->child;
  544. b = to->child;
  545. /* for all object values in the object with more of them */
  546. while (a || b)
  547. {
  548. int diff = (!a) ? 1 : ((!b) ? -1 : cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string));
  549. if (!diff)
  550. {
  551. /* both object keys are the same */
  552. unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen((unsigned char*)a->string) + 2);
  553. cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", path), (unsigned char*)a->string);
  554. /* create a patch for the element */
  555. cJSONUtils_CompareToPatch(patches, newpath, a, b);
  556. free(newpath);
  557. a = a->next;
  558. b = b->next;
  559. }
  560. else if (diff < 0)
  561. {
  562. /* object element doesn't exist in 'to' --> remove it */
  563. cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, (unsigned char*)a->string, 0);
  564. a = a->next;
  565. }
  566. else
  567. {
  568. /* object element doesn't exist in 'from' --> add it */
  569. cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (unsigned char*)b->string, b);
  570. b = b->next;
  571. }
  572. }
  573. return;
  574. }
  575. default:
  576. break;
  577. }
  578. }
  579. cJSON* cJSONUtils_GeneratePatches(cJSON *from, cJSON *to)
  580. {
  581. cJSON *patches = cJSON_CreateArray();
  582. cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to);
  583. return patches;
  584. }
  585. /* sort lists using mergesort */
  586. static cJSON *cJSONUtils_SortList(cJSON *list)
  587. {
  588. cJSON *first = list;
  589. cJSON *second = list;
  590. cJSON *ptr = list;
  591. if (!list || !list->next)
  592. {
  593. /* One entry is sorted already. */
  594. return list;
  595. }
  596. while (ptr && ptr->next && (cJSONUtils_strcasecmp((unsigned char*)ptr->string, (unsigned char*)ptr->next->string) < 0))
  597. {
  598. /* Test for list sorted. */
  599. ptr = ptr->next;
  600. }
  601. if (!ptr || !ptr->next)
  602. {
  603. /* Leave sorted lists unmodified. */
  604. return list;
  605. }
  606. /* reset ptr to the beginning */
  607. ptr = list;
  608. while (ptr)
  609. {
  610. /* Walk two pointers to find the middle. */
  611. second = second->next;
  612. ptr = ptr->next;
  613. /* advances ptr two steps at a time */
  614. if (ptr)
  615. {
  616. ptr = ptr->next;
  617. }
  618. }
  619. if (second && second->prev)
  620. {
  621. /* Split the lists */
  622. second->prev->next = NULL;
  623. }
  624. /* Recursively sort the sub-lists. */
  625. first = cJSONUtils_SortList(first);
  626. second = cJSONUtils_SortList(second);
  627. list = ptr = NULL;
  628. while (first && second) /* Merge the sub-lists */
  629. {
  630. if (cJSONUtils_strcasecmp((unsigned char*)first->string, (unsigned char*)second->string) < 0)
  631. {
  632. if (!list)
  633. {
  634. /* start merged list with the first element of the first list */
  635. list = ptr = first;
  636. }
  637. else
  638. {
  639. /* add first element of first list to merged list */
  640. ptr->next = first;
  641. first->prev = ptr;
  642. ptr = first;
  643. }
  644. first = first->next;
  645. }
  646. else
  647. {
  648. if (!list)
  649. {
  650. /* start merged list with the first element of the second list */
  651. list = ptr = second;
  652. }
  653. else
  654. {
  655. /* add first element of second list to merged list */
  656. ptr->next = second;
  657. second->prev = ptr;
  658. ptr = second;
  659. }
  660. second = second->next;
  661. }
  662. }
  663. if (first)
  664. {
  665. /* Append rest of first list. */
  666. if (!list)
  667. {
  668. return first;
  669. }
  670. ptr->next = first;
  671. first->prev = ptr;
  672. }
  673. if (second)
  674. {
  675. /* Append rest of second list */
  676. if (!list)
  677. {
  678. return second;
  679. }
  680. ptr->next = second;
  681. second->prev = ptr;
  682. }
  683. return list;
  684. }
  685. void cJSONUtils_SortObject(cJSON *object)
  686. {
  687. object->child = cJSONUtils_SortList(object->child);
  688. }
  689. cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
  690. {
  691. if (!patch || ((patch->type & 0xFF) != cJSON_Object))
  692. {
  693. /* scalar value, array or NULL, just duplicate */
  694. cJSON_Delete(target);
  695. return cJSON_Duplicate(patch, 1);
  696. }
  697. if (!target || ((target->type & 0xFF) != cJSON_Object))
  698. {
  699. cJSON_Delete(target);
  700. target = cJSON_CreateObject();
  701. }
  702. patch = patch->child;
  703. while (patch)
  704. {
  705. if ((patch->type & 0xFF) == cJSON_NULL)
  706. {
  707. /* NULL is the indicator to remove a value, see RFC7396 */
  708. cJSON_DeleteItemFromObject(target, patch->string);
  709. }
  710. else
  711. {
  712. cJSON *replaceme = cJSON_DetachItemFromObject(target, patch->string);
  713. cJSON_AddItemToObject(target, patch->string, cJSONUtils_MergePatch(replaceme, patch));
  714. }
  715. patch = patch->next;
  716. }
  717. return target;
  718. }
  719. cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to)
  720. {
  721. cJSON *patch = NULL;
  722. if (!to)
  723. {
  724. /* patch to delete everything */
  725. return cJSON_CreateNull();
  726. }
  727. if (((to->type & 0xFF) != cJSON_Object) || !from || ((from->type & 0xFF) != cJSON_Object))
  728. {
  729. return cJSON_Duplicate(to, 1);
  730. }
  731. cJSONUtils_SortObject(from);
  732. cJSONUtils_SortObject(to);
  733. from = from->child;
  734. to = to->child;
  735. patch = cJSON_CreateObject();
  736. while (from || to)
  737. {
  738. int compare = from ? (to ? strcmp(from->string, to->string) : -1) : 1;
  739. if (compare < 0)
  740. {
  741. /* from has a value that to doesn't have -> remove */
  742. cJSON_AddItemToObject(patch, from->string, cJSON_CreateNull());
  743. from = from->next;
  744. }
  745. else if (compare > 0)
  746. {
  747. /* to has a value that from doesn't have -> add to patch */
  748. cJSON_AddItemToObject(patch, to->string, cJSON_Duplicate(to, 1));
  749. to = to->next;
  750. }
  751. else
  752. {
  753. /* object key exists in both objects */
  754. if (cJSONUtils_Compare(from, to))
  755. {
  756. /* not identical --> generate a patch */
  757. cJSON_AddItemToObject(patch, to->string, cJSONUtils_GenerateMergePatch(from, to));
  758. }
  759. /* next key in the object */
  760. from = from->next;
  761. to = to->next;
  762. }
  763. }
  764. if (!patch->child)
  765. {
  766. cJSON_Delete(patch);
  767. return NULL;
  768. }
  769. return patch;
  770. }