]> source.dussan.org Git - rspamd.git/commitdiff
[Fix] Fix objects merging in UCL
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 2 Jun 2017 13:41:51 +0000 (14:41 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 2 Jun 2017 13:42:10 +0000 (14:42 +0100)
contrib/libucl/ucl_util.c

index 07af232d9d82fceb0838671f2deb269482f618ed..812655d2ef492dcb70663aaf88fbbc3e8ee369df 100644 (file)
@@ -2195,7 +2195,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
                                while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
                                        tmp = ucl_object_ref (cur);
                                        ucl_object_insert_key_common (found, tmp, cur->key,
-                                                       cur->keylen, copy_key, false, false);
+                                                       cur->keylen, copy_key, true, false);
                                }
                                ucl_object_unref (elt);
                        }
@@ -2292,30 +2292,98 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
        ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
        ucl_object_iter_t iter = NULL;
 
-       if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
+       if (top == NULL || elt == NULL) {
                return false;
        }
 
-       /* Mix two hashes */
-       while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
-               if (copy) {
-                       cp = ucl_object_copy (cur);
+       if (top->type == UCL_ARRAY) {
+               if (elt->type == UCL_ARRAY) {
+                       /* Merge two arrays */
+                       return ucl_array_merge (top, elt, copy);
                }
                else {
-                       cp = ucl_object_ref (cur);
+                       if (copy) {
+                               ucl_array_append (top, ucl_object_copy (elt));
+
+                               return true;
+                       }
+                       else {
+                               ucl_array_append (top, ucl_object_ref (elt));
+
+                               return true;
+                       }
                }
-               found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
-               if (found == NULL) {
-                       /* The key does not exist */
-                       top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false);
-                       top->len ++;
+       }
+       else if (top->type == UCL_OBJECT) {
+               if (elt->type == UCL_OBJECT) {
+                       /* Mix two hashes */
+                       while ((cur = (ucl_object_t *) ucl_hash_iterate (elt->value.ov,
+                                       &iter))) {
+
+                               if (copy) {
+                                       cp = ucl_object_copy (cur);
+                               } else {
+                                       cp = ucl_object_ref (cur);
+                               }
+
+                               found = __DECONST(ucl_object_t *,
+                                               ucl_hash_search (top->value.ov, cp->key, cp->keylen));
+
+                               if (found == NULL) {
+                                       /* The key does not exist */
+                                       top->value.ov = ucl_hash_insert_object (top->value.ov, cp,
+                                                       false);
+                                       top->len++;
+                               }
+                               else {
+                                       /* The key already exists, merge it recursively */
+                                       if (found->type == UCL_OBJECT || found->type == UCL_ARRAY) {
+                                               if (!ucl_object_merge (found, cp, copy)) {
+                                                       return false;
+                                               }
+                                       }
+                                       else {
+                                               ucl_hash_replace (top->value.ov, found, cp);
+                                               ucl_object_unref (found);
+                                       }
+                               }
+                       }
                }
                else {
-                       /* The key already exists, replace it */
-                       ucl_hash_replace (top->value.ov, found, cp);
-                       ucl_object_unref (found);
+                       if (copy) {
+                               cp = ucl_object_copy (elt);
+                       }
+                       else {
+                               cp = ucl_object_ref (elt);
+                       }
+
+                       found = __DECONST(ucl_object_t *,
+                                       ucl_hash_search (top->value.ov, cp->key, cp->keylen));
+
+                       if (found == NULL) {
+                               /* The key does not exist */
+                               top->value.ov = ucl_hash_insert_object (top->value.ov, cp,
+                                               false);
+                               top->len++;
+                       }
+                       else {
+                               /* The key already exists, merge it recursively */
+                               if (found->type == UCL_OBJECT || found->type == UCL_ARRAY) {
+                                       if (!ucl_object_merge (found, cp, copy)) {
+                                               return false;
+                                       }
+                               }
+                               else {
+                                       ucl_hash_replace (top->value.ov, found, cp);
+                                       ucl_object_unref (found);
+                               }
+                       }
                }
        }
+       else {
+               /* Cannot merge trivial objects */
+               return false;
+       }
 
        return true;
 }