|  | @@ -425,6 +425,122 @@ cleanup:
 | 
											
												
													
														|  |      return detached_item;
 |  |      return detached_item;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +/* sort lists using mergesort */
 | 
											
												
													
														|  | 
 |  | +static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +    cJSON *first = list;
 | 
											
												
													
														|  | 
 |  | +    cJSON *second = list;
 | 
											
												
													
														|  | 
 |  | +    cJSON *current_item = list;
 | 
											
												
													
														|  | 
 |  | +    cJSON *result = list;
 | 
											
												
													
														|  | 
 |  | +    cJSON *result_tail = NULL;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if ((list == NULL) || (list->next == NULL))
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        /* One entry is sorted already. */
 | 
											
												
													
														|  | 
 |  | +        return result;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0))
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        /* Test for list sorted. */
 | 
											
												
													
														|  | 
 |  | +        current_item = current_item->next;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    if ((current_item == NULL) || (current_item->next == NULL))
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        /* Leave sorted lists unmodified. */
 | 
											
												
													
														|  | 
 |  | +        return result;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    /* reset pointer to the beginning */
 | 
											
												
													
														|  | 
 |  | +    current_item = list;
 | 
											
												
													
														|  | 
 |  | +    while (current_item != NULL)
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        /* Walk two pointers to find the middle. */
 | 
											
												
													
														|  | 
 |  | +        second = second->next;
 | 
											
												
													
														|  | 
 |  | +        current_item = current_item->next;
 | 
											
												
													
														|  | 
 |  | +        /* advances current_item two steps at a time */
 | 
											
												
													
														|  | 
 |  | +        if (current_item != NULL)
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            current_item = current_item->next;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    if ((second != NULL) && (second->prev != NULL))
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        /* Split the lists */
 | 
											
												
													
														|  | 
 |  | +        second->prev->next = NULL;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    /* Recursively sort the sub-lists. */
 | 
											
												
													
														|  | 
 |  | +    first = sort_list(first, case_sensitive);
 | 
											
												
													
														|  | 
 |  | +    second = sort_list(second, case_sensitive);
 | 
											
												
													
														|  | 
 |  | +    result = NULL;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    /* Merge the sub-lists */
 | 
											
												
													
														|  | 
 |  | +    while ((first != NULL) && (second != NULL))
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        cJSON *smaller = NULL;
 | 
											
												
													
														|  | 
 |  | +        if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, false) < 0)
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            smaller = first;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        else
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            smaller = second;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        if (result == NULL)
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            /* start merged list with the smaller element */
 | 
											
												
													
														|  | 
 |  | +            result_tail = smaller;
 | 
											
												
													
														|  | 
 |  | +            result = smaller;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        else
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            /* add smaller element to the list */
 | 
											
												
													
														|  | 
 |  | +            result_tail->next = smaller;
 | 
											
												
													
														|  | 
 |  | +            smaller->prev = result_tail;
 | 
											
												
													
														|  | 
 |  | +            result_tail = smaller;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        if (first == smaller)
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            first = first->next;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        else
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            second = second->next;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (first != NULL)
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        /* Append rest of first list. */
 | 
											
												
													
														|  | 
 |  | +        if (result == NULL)
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            return first;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        result_tail->next = first;
 | 
											
												
													
														|  | 
 |  | +        first->prev = result_tail;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    if (second != NULL)
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        /* Append rest of second list */
 | 
											
												
													
														|  | 
 |  | +        if (result == NULL)
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            return second;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        result_tail->next = second;
 | 
											
												
													
														|  | 
 |  | +        second->prev = result_tail;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    return result;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void sort_object(cJSON * const object, const cJSON_bool case_sensitive)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +    object->child = sort_list(object->child, case_sensitive);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive)
 |  |  static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  |      if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
 |  |      if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
 | 
											
										
											
												
													
														|  | @@ -477,8 +593,8 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensiti
 | 
											
												
													
														|  |              }
 |  |              }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          case cJSON_Object:
 |  |          case cJSON_Object:
 | 
											
												
													
														|  | -            cJSONUtils_SortObject(a);
 |  | 
 | 
											
												
													
														|  | -            cJSONUtils_SortObject(b);
 |  | 
 | 
											
												
													
														|  | 
 |  | +            sort_object(a, case_sensitive);
 | 
											
												
													
														|  | 
 |  | +            sort_object(b, case_sensitive);
 | 
											
												
													
														|  |              for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next)
 |  |              for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next)
 | 
											
												
													
														|  |              {
 |  |              {
 | 
											
												
													
														|  |                  cJSON_bool identical = false;
 |  |                  cJSON_bool identical = false;
 | 
											
										
											
												
													
														|  | @@ -1018,8 +1134,8 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa
 | 
											
												
													
														|  |          {
 |  |          {
 | 
											
												
													
														|  |              cJSON *from_child = NULL;
 |  |              cJSON *from_child = NULL;
 | 
											
												
													
														|  |              cJSON *to_child = NULL;
 |  |              cJSON *to_child = NULL;
 | 
											
												
													
														|  | -            cJSONUtils_SortObject(from);
 |  | 
 | 
											
												
													
														|  | -            cJSONUtils_SortObject(to);
 |  | 
 | 
											
												
													
														|  | 
 |  | +            sort_object(from, case_sensitive);
 | 
											
												
													
														|  | 
 |  | +            sort_object(to, case_sensitive);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |              from_child = from->child;
 |  |              from_child = from->child;
 | 
											
												
													
														|  |              to_child = to->child;
 |  |              to_child = to->child;
 | 
											
										
											
												
													
														|  | @@ -1096,120 +1212,14 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from
 | 
											
												
													
														|  |      return patches;
 |  |      return patches;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -/* sort lists using mergesort */
 |  | 
 | 
											
												
													
														|  | -static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive)
 |  | 
 | 
											
												
													
														|  | 
 |  | +CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  | -    cJSON *first = list;
 |  | 
 | 
											
												
													
														|  | -    cJSON *second = list;
 |  | 
 | 
											
												
													
														|  | -    cJSON *current_item = list;
 |  | 
 | 
											
												
													
														|  | -    cJSON *result = list;
 |  | 
 | 
											
												
													
														|  | -    cJSON *result_tail = NULL;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    if ((list == NULL) || (list->next == NULL))
 |  | 
 | 
											
												
													
														|  | -    {
 |  | 
 | 
											
												
													
														|  | -        /* One entry is sorted already. */
 |  | 
 | 
											
												
													
														|  | -        return result;
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0))
 |  | 
 | 
											
												
													
														|  | -    {
 |  | 
 | 
											
												
													
														|  | -        /* Test for list sorted. */
 |  | 
 | 
											
												
													
														|  | -        current_item = current_item->next;
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -    if ((current_item == NULL) || (current_item->next == NULL))
 |  | 
 | 
											
												
													
														|  | -    {
 |  | 
 | 
											
												
													
														|  | -        /* Leave sorted lists unmodified. */
 |  | 
 | 
											
												
													
														|  | -        return result;
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    /* reset pointer to the beginning */
 |  | 
 | 
											
												
													
														|  | -    current_item = list;
 |  | 
 | 
											
												
													
														|  | -    while (current_item != NULL)
 |  | 
 | 
											
												
													
														|  | -    {
 |  | 
 | 
											
												
													
														|  | -        /* Walk two pointers to find the middle. */
 |  | 
 | 
											
												
													
														|  | -        second = second->next;
 |  | 
 | 
											
												
													
														|  | -        current_item = current_item->next;
 |  | 
 | 
											
												
													
														|  | -        /* advances current_item two steps at a time */
 |  | 
 | 
											
												
													
														|  | -        if (current_item != NULL)
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            current_item = current_item->next;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -    if ((second != NULL) && (second->prev != NULL))
 |  | 
 | 
											
												
													
														|  | -    {
 |  | 
 | 
											
												
													
														|  | -        /* Split the lists */
 |  | 
 | 
											
												
													
														|  | -        second->prev->next = NULL;
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    /* Recursively sort the sub-lists. */
 |  | 
 | 
											
												
													
														|  | -    first = sort_list(first, case_sensitive);
 |  | 
 | 
											
												
													
														|  | -    second = sort_list(second, case_sensitive);
 |  | 
 | 
											
												
													
														|  | -    result = NULL;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    /* Merge the sub-lists */
 |  | 
 | 
											
												
													
														|  | -    while ((first != NULL) && (second != NULL))
 |  | 
 | 
											
												
													
														|  | -    {
 |  | 
 | 
											
												
													
														|  | -        cJSON *smaller = NULL;
 |  | 
 | 
											
												
													
														|  | -        if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, false) < 0)
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            smaller = first;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -        else
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            smaller = second;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -        if (result == NULL)
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            /* start merged list with the smaller element */
 |  | 
 | 
											
												
													
														|  | -            result_tail = smaller;
 |  | 
 | 
											
												
													
														|  | -            result = smaller;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -        else
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            /* add smaller element to the list */
 |  | 
 | 
											
												
													
														|  | -            result_tail->next = smaller;
 |  | 
 | 
											
												
													
														|  | -            smaller->prev = result_tail;
 |  | 
 | 
											
												
													
														|  | -            result_tail = smaller;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -        if (first == smaller)
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            first = first->next;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -        else
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            second = second->next;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    if (first != NULL)
 |  | 
 | 
											
												
													
														|  | -    {
 |  | 
 | 
											
												
													
														|  | -        /* Append rest of first list. */
 |  | 
 | 
											
												
													
														|  | -        if (result == NULL)
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            return first;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -        result_tail->next = first;
 |  | 
 | 
											
												
													
														|  | -        first->prev = result_tail;
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -    if (second != NULL)
 |  | 
 | 
											
												
													
														|  | -    {
 |  | 
 | 
											
												
													
														|  | -        /* Append rest of second list */
 |  | 
 | 
											
												
													
														|  | -        if (result == NULL)
 |  | 
 | 
											
												
													
														|  | -        {
 |  | 
 | 
											
												
													
														|  | -            return second;
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -        result_tail->next = second;
 |  | 
 | 
											
												
													
														|  | -        second->prev = result_tail;
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    return result;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    sort_object(object, false);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object)
 |  | 
 | 
											
												
													
														|  | 
 |  | +CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  | -    object->child = sort_list(object->child, false);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    sort_object(object, true);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch)
 |  |  CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch)
 | 
											
										
											
												
													
														|  | @@ -1262,8 +1272,8 @@ static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const c
 | 
											
												
													
														|  |          return cJSON_Duplicate(to, 1);
 |  |          return cJSON_Duplicate(to, 1);
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    cJSONUtils_SortObject(from);
 |  | 
 | 
											
												
													
														|  | -    cJSONUtils_SortObject(to);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    sort_object(from, case_sensitive);
 | 
											
												
													
														|  | 
 |  | +    sort_object(to, case_sensitive);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      from_child = from->child;
 |  |      from_child = from->child;
 | 
											
												
													
														|  |      to_child = to->child;
 |  |      to_child = to->child;
 |