cJSON_Utils.c 24 KB

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