|
|
@ -509,63 +509,99 @@ void cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, |
|
|
|
cJSONUtils_GeneratePatch(array, op, path, 0, val); |
|
|
|
} |
|
|
|
|
|
|
|
static void cJSONUtils_CompareToPatch(cJSON *patches,const char *path,cJSON *from,cJSON *to) |
|
|
|
static void cJSONUtils_CompareToPatch(cJSON *patches, const char *path, cJSON *from, cJSON *to) |
|
|
|
{ |
|
|
|
if (from->type!=to->type) {cJSONUtils_GeneratePatch(patches,"replace",path,0,to); return; } |
|
|
|
|
|
|
|
switch (from->type) |
|
|
|
{ |
|
|
|
case cJSON_Number: |
|
|
|
if (from->valueint!=to->valueint || from->valuedouble!=to->valuedouble) |
|
|
|
cJSONUtils_GeneratePatch(patches,"replace",path,0,to); |
|
|
|
return; |
|
|
|
|
|
|
|
case cJSON_String: |
|
|
|
if (strcmp(from->valuestring,to->valuestring)!=0) |
|
|
|
cJSONUtils_GeneratePatch(patches,"replace",path,0,to); |
|
|
|
return; |
|
|
|
|
|
|
|
case cJSON_Array: |
|
|
|
{ |
|
|
|
int c;char *newpath=(char*)malloc(strlen(path)+23); /* Allow space for 64bit int. */ |
|
|
|
for (c=0,from=from->child,to=to->child;from && to;from=from->next,to=to->next,c++){ |
|
|
|
sprintf(newpath,"%s/%d",path,c); cJSONUtils_CompareToPatch(patches,newpath,from,to); |
|
|
|
} |
|
|
|
for (;from;from=from->next,c++) {sprintf(newpath,"%d",c); cJSONUtils_GeneratePatch(patches,"remove",path,newpath,0); } |
|
|
|
for (;to;to=to->next,c++) cJSONUtils_GeneratePatch(patches,"add",path,"-",to); |
|
|
|
free(newpath); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (from->type != to->type) |
|
|
|
{ |
|
|
|
cJSONUtils_GeneratePatch(patches, "replace", path, 0, to); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
case cJSON_Object: |
|
|
|
{ |
|
|
|
cJSON *a,*b; |
|
|
|
cJSONUtils_SortObject(from); |
|
|
|
cJSONUtils_SortObject(to); |
|
|
|
|
|
|
|
a=from->child,b=to->child; |
|
|
|
while (a || b) |
|
|
|
{ |
|
|
|
int diff=(!a)?1:(!b)?-1:cJSONUtils_strcasecmp(a->string,b->string); |
|
|
|
if (!diff) |
|
|
|
{ |
|
|
|
char *newpath=(char*)malloc(strlen(path)+cJSONUtils_PointerEncodedstrlen(a->string)+2); |
|
|
|
cJSONUtils_PointerEncodedstrcpy(newpath+sprintf(newpath,"%s/",path),a->string); |
|
|
|
cJSONUtils_CompareToPatch(patches,newpath,a,b); |
|
|
|
free(newpath); |
|
|
|
a=a->next; |
|
|
|
b=b->next; |
|
|
|
} |
|
|
|
else if (diff<0) {cJSONUtils_GeneratePatch(patches,"remove",path,a->string,0); a=a->next;} |
|
|
|
else {cJSONUtils_GeneratePatch(patches,"add",path,b->string,b); b=b->next;} |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
switch (from->type) |
|
|
|
{ |
|
|
|
case cJSON_Number: |
|
|
|
if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble)) |
|
|
|
{ |
|
|
|
cJSONUtils_GeneratePatch(patches, "replace", path, 0, to); |
|
|
|
} |
|
|
|
return; |
|
|
|
|
|
|
|
default: break; |
|
|
|
} |
|
|
|
} |
|
|
|
case cJSON_String: |
|
|
|
if (strcmp(from->valuestring, to->valuestring) != 0) |
|
|
|
{ |
|
|
|
cJSONUtils_GeneratePatch(patches, "replace", path, 0, to); |
|
|
|
} |
|
|
|
return; |
|
|
|
|
|
|
|
case cJSON_Array: |
|
|
|
{ |
|
|
|
int c; |
|
|
|
char *newpath = (char*)malloc(strlen(path) + 23); /* Allow space for 64bit int. */ |
|
|
|
/* generate patches for all array elements that exist in "from" and "to" */ |
|
|
|
for (c = 0, from = from->child, to = to->child; from && to; from = from->next, to = to->next, c++) |
|
|
|
{ |
|
|
|
sprintf(newpath, "%s/%d", path, c); /* path of the current array element */ |
|
|
|
cJSONUtils_CompareToPatch(patches, newpath, from, to); |
|
|
|
} |
|
|
|
/* remove leftover elements from 'from' that are not in 'to' */ |
|
|
|
for (; from; from = from->next, c++) |
|
|
|
{ |
|
|
|
sprintf(newpath, "%d", c); |
|
|
|
cJSONUtils_GeneratePatch(patches, "remove", path, newpath, 0); |
|
|
|
} |
|
|
|
/* add new elements in 'to' that were not in 'from' */ |
|
|
|
for (; to; to = to->next, c++) |
|
|
|
{ |
|
|
|
cJSONUtils_GeneratePatch(patches, "add", path, "-", to); |
|
|
|
} |
|
|
|
free(newpath); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
case cJSON_Object: |
|
|
|
{ |
|
|
|
cJSON *a; |
|
|
|
cJSON *b; |
|
|
|
cJSONUtils_SortObject(from); |
|
|
|
cJSONUtils_SortObject(to); |
|
|
|
|
|
|
|
a = from->child; |
|
|
|
b = to->child; |
|
|
|
/* for all object values in the object with more of them */ |
|
|
|
while (a || b) |
|
|
|
{ |
|
|
|
int diff = (!a) ? 1 : ((!b) ? -1 : cJSONUtils_strcasecmp(a->string, b->string)); |
|
|
|
if (!diff) |
|
|
|
{ |
|
|
|
/* both object keys are the same */ |
|
|
|
char *newpath = (char*)malloc(strlen(path) + cJSONUtils_PointerEncodedstrlen(a->string) + 2); |
|
|
|
cJSONUtils_PointerEncodedstrcpy(newpath + sprintf(newpath, "%s/", path), a->string); |
|
|
|
/* create a patch for the element */ |
|
|
|
cJSONUtils_CompareToPatch(patches, newpath, a, b); |
|
|
|
free(newpath); |
|
|
|
a = a->next; |
|
|
|
b = b->next; |
|
|
|
} |
|
|
|
else if (diff < 0) |
|
|
|
{ |
|
|
|
/* object element doesn't exist in 'to' --> remove it */ |
|
|
|
cJSONUtils_GeneratePatch(patches, "remove", path, a->string, 0); |
|
|
|
a = a->next; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
/* object element doesn't exist in 'from' --> add it */ |
|
|
|
cJSONUtils_GeneratePatch(patches, "add", path, b->string, b); |
|
|
|
b = b->next; |
|
|
|
} |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
cJSON* cJSONUtils_GeneratePatches(cJSON *from,cJSON *to) |
|
|
|
{ |
|
|
|