cJSON_Utils.c 24 KB

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