cJSON_Utils.c 24 KB

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