[PATCH 3/5] ole32/composite: Implement CommonPrefixWith() without iterators.

Nikolay Sivov nsivov at codeweavers.com
Mon Sep 27 07:31:38 CDT 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/ole32/compositemoniker.c | 230 +++++++++++++++++-----------------
 dlls/ole32/tests/moniker.c    |  15 ++-
 2 files changed, 128 insertions(+), 117 deletions(-)

diff --git a/dlls/ole32/compositemoniker.c b/dlls/ole32/compositemoniker.c
index efb0e9de9e8..4eb9b32fe5e 100644
--- a/dlls/ole32/compositemoniker.c
+++ b/dlls/ole32/compositemoniker.c
@@ -88,6 +88,7 @@ static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
 
 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRight,IEnumMoniker ** ppmk);
 static HRESULT composite_get_rightmost(CompositeMonikerImpl *composite, IMoniker **left, IMoniker **rightmost);
+static HRESULT composite_get_leftmost(CompositeMonikerImpl *composite, IMoniker **leftmost);
 
 /*******************************************************************************
  *        CompositeMoniker_QueryInterface
@@ -524,11 +525,23 @@ static void composite_get_components(IMoniker *moniker, IMoniker **components, u
     }
 }
 
+static HRESULT composite_get_components_alloc(CompositeMonikerImpl *moniker, IMoniker ***components)
+{
+    unsigned int index;
+
+    if (!(*components = heap_alloc(moniker->comp_count * sizeof(**components))))
+        return E_OUTOFMEMORY;
+
+    index = 0;
+    composite_get_components(&moniker->IMoniker_iface, *components, &index);
+
+    return S_OK;
+}
+
 static HRESULT WINAPI CompositeMonikerImpl_Enum(IMoniker *iface, BOOL forward, IEnumMoniker **ppenumMoniker)
 {
     CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
     IMoniker **monikers;
-    unsigned int index;
     HRESULT hr;
 
     TRACE("%p, %d, %p\n", iface, forward, ppenumMoniker);
@@ -536,11 +549,8 @@ static HRESULT WINAPI CompositeMonikerImpl_Enum(IMoniker *iface, BOOL forward, I
     if (!ppenumMoniker)
         return E_POINTER;
 
-    if (!(monikers = heap_alloc(moniker->comp_count * sizeof(*monikers))))
-        return E_OUTOFMEMORY;
-
-    index = 0;
-    composite_get_components(iface, monikers, &index);
+    if (FAILED(hr = composite_get_components_alloc(moniker, &monikers)))
+        return hr;
 
     hr = EnumMonikerImpl_CreateEnumMoniker(monikers, moniker->comp_count, 0, forward, ppenumMoniker);
     heap_free(monikers);
@@ -812,135 +822,102 @@ CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
     }
 }
 
-/******************************************************************************
- *        CompositeMoniker_CommonPrefixWith
- ******************************************************************************/
-static HRESULT WINAPI
-CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
-               IMoniker** ppmkPrefix)
+static HRESULT WINAPI CompositeMonikerImpl_CommonPrefixWith(IMoniker *iface, IMoniker *other,
+        IMoniker **prefix)
 {
-    DWORD mkSys;
-    HRESULT res1,res2;
-    IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
-    IEnumMoniker *enumMoniker1,*enumMoniker2;
-    ULONG i,nbCommonMk=0;
+    CompositeMonikerImpl *moniker = impl_from_IMoniker(iface), *other_moniker;
+    unsigned int i, count, prefix_len = 0;
+    IMoniker *leftmost;
+    HRESULT hr;
+
+    TRACE("%p, %p, %p.\n", iface, other, prefix);
 
     /* If the other moniker is a composite, this method compares the components of each composite from left  */
     /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
     /* of the leftmost components were common to both monikers.                                              */
 
-    if (ppmkPrefix==NULL)
-        return E_POINTER;
-
-    *ppmkPrefix=0;
-
-    if (pmkOther==NULL)
-        return MK_E_NOPREFIX;
+    if (prefix)
+        *prefix = NULL;
 
-    IMoniker_IsSystemMoniker(pmkOther,&mkSys);
-
-    if(mkSys==MKSYS_GENERICCOMPOSITE){
-
-        IMoniker_Enum(iface,TRUE,&enumMoniker1);
-        IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
-
-        while(1){
-
-            res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
-            res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
-
-            if ((res1==S_FALSE) && (res2==S_FALSE)){
-
-                /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
-                *ppmkPrefix=iface;
-                IMoniker_AddRef(iface);
-                return  MK_S_US;
-            }
-            else if ((res1==S_OK) && (res2==S_OK)){
-
-                if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
-
-                    nbCommonMk++;
-
-                else
-                    break;
+    if (!other || !prefix)
+        return E_INVALIDARG;
 
-            }
-            else if (res1==S_OK){
+    if ((other_moniker = unsafe_impl_from_IMoniker(other)))
+    {
+        IMoniker **components, **other_components, **prefix_components;
+        IMoniker *last, *c;
 
-                /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
-                /* ppmkPrefix to the other moniker.                                                       */
-                *ppmkPrefix=pmkOther;
-                return MK_S_HIM;
-            }
-            else{
-                /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
-                /* to this moniker.                                                                          */
-                *ppmkPrefix=iface;
-                return MK_S_ME;
-            }
+        if (FAILED(hr = composite_get_components_alloc(moniker, &components))) return hr;
+        if (FAILED(hr = composite_get_components_alloc(other_moniker, &other_components)))
+        {
+            heap_free(components);
+            return hr;
         }
 
-        IEnumMoniker_Release(enumMoniker1);
-        IEnumMoniker_Release(enumMoniker2);
-
-        /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
-        if (nbCommonMk==0)
-            return MK_E_NOPREFIX;
-
-        IEnumMoniker_Reset(enumMoniker1);
-
-        IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
-
-        /* if we have more than one common moniker the result will be a composite moniker */
-        if (nbCommonMk>1){
-
-            /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
-            IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
-            CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
-            IMoniker_Release(tempMk1);
-            IMoniker_Release(tempMk2);
-
-            /* compose all common monikers in a composite moniker */
-            for(i=0;i<nbCommonMk;i++){
+        count = min(moniker->comp_count, other_moniker->comp_count);
+        if (!(prefix_components = heap_calloc(count, sizeof(*prefix_components))))
+        {
+            heap_free(components);
+            heap_free(other_components);
+            return E_OUTOFMEMORY;
+        }
 
-                IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
+        /* Collect prefix components */
+        for (i = 0; i < count; ++i)
+        {
+            IMoniker *p;
 
-                CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
+            if (FAILED(hr = IMoniker_CommonPrefixWith(components[i], other_components[i], &p)))
+                break;
+            prefix_components[prefix_len++] = p;
+            /* S_OK means that prefix was found and is neither of tested monikers */
+            if (hr == S_OK) break;
+        }
 
-                IMoniker_Release(*ppmkPrefix);
+        heap_free(components);
+        heap_free(other_components);
 
-                IMoniker_Release(tempMk1);
+        if (!prefix_len) return MK_E_NOPREFIX;
 
-                *ppmkPrefix=tempMk2;
-            }
-            return S_OK;
+        last = prefix_components[0];
+        for (i = 1; i < prefix_len; ++i)
+        {
+            hr = CreateGenericComposite(last, prefix_components[i], &c);
+            IMoniker_Release(last);
+            IMoniker_Release(prefix_components[i]);
+            if (FAILED(hr)) break;
+            last = c;
         }
-        else{
-            /* if we have only one common moniker the result will be a simple moniker which is the most-left one*/
-            *ppmkPrefix=tempMk1;
+        heap_free(prefix_components);
 
-            return S_OK;
+        if (SUCCEEDED(hr))
+        {
+            *prefix = last;
+            if (IMoniker_IsEqual(iface, *prefix) == S_OK)
+                hr = MK_S_US;
+            else if (prefix_len < count)
+                hr = S_OK;
+            else
+                hr = prefix_len == moniker->comp_count ? MK_S_ME : MK_S_HIM;
         }
-    }
-    else{
-        /* If the other moniker is not a composite, the method simply compares it to the leftmost component
-         of this moniker.*/
-
-        IMoniker_Enum(iface,TRUE,&enumMoniker1);
-
-        IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
 
-        if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
-
-            *ppmkPrefix=pmkOther;
-            IMoniker_AddRef(*ppmkPrefix);
+        return hr;
+    }
 
-            return MK_S_HIM;
+    /* For non-composite, compare to leftmost component */
+    if (SUCCEEDED(hr = composite_get_leftmost(moniker, &leftmost)))
+    {
+        if ((hr = IMoniker_IsEqual(leftmost, other)) == S_OK)
+        {
+            *prefix = leftmost;
+            IMoniker_AddRef(*prefix);
         }
-        else
-            return MK_E_NOPREFIX;
+
+        hr = hr == S_OK ? MK_S_HIM : MK_E_NOPREFIX;
+        IMoniker_Release(leftmost);
     }
+
+    return hr;
 }
 
 /***************************************************************************************************
@@ -1866,6 +1843,35 @@ static HRESULT composite_get_rightmost(CompositeMonikerImpl *composite, IMoniker
     return hr;
 }
 
+static HRESULT composite_get_leftmost(CompositeMonikerImpl *composite, IMoniker **leftmost)
+{
+    struct comp_node *root, *node;
+    HRESULT hr;
+
+    if (!unsafe_impl_from_IMoniker(composite->left))
+    {
+        *leftmost = composite->left;
+        IMoniker_AddRef(*leftmost);
+        return S_OK;
+    }
+
+    if (FAILED(hr = moniker_get_tree_representation(&composite->IMoniker_iface, NULL, &root)))
+        return hr;
+
+    if (!(node = moniker_tree_get_leftmost(root)))
+    {
+        WARN("Couldn't get right most component.\n");
+        return E_FAIL;
+    }
+
+    *leftmost = node->moniker;
+    IMoniker_AddRef(*leftmost);
+
+    moniker_tree_release(root);
+
+    return S_OK;
+}
+
 static HRESULT moniker_simplify_composition(IMoniker *left, IMoniker *right,
         unsigned int *count, IMoniker **new_left, IMoniker **new_right)
 {
diff --git a/dlls/ole32/tests/moniker.c b/dlls/ole32/tests/moniker.c
index ed55ec3e825..1e4c2e0211d 100644
--- a/dlls/ole32/tests/moniker.c
+++ b/dlls/ole32/tests/moniker.c
@@ -3290,24 +3290,30 @@ todo_wine
     hr = create_moniker_from_desc("CI1I2", &moniker1);
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
+    hr = IMoniker_CommonPrefixWith(moniker, NULL, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    hr = IMoniker_CommonPrefixWith(moniker, moniker1, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
     moniker2 = (void *)0xdeadbeef;
     hr = IMoniker_CommonPrefixWith(moniker, NULL, &moniker2);
-todo_wine
     ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
     ok(!moniker2, "Unexpected pointer.\n");
 
     /* With itself */
     hr = IMoniker_CommonPrefixWith(moniker, moniker, &moniker2);
+todo_wine
     ok(hr == MK_S_US, "Unexpected hr %#x.\n", hr);
+    hr = IMoniker_IsEqual(moniker, moniker2);
 todo_wine
-    ok(moniker2 != moniker, "Unexpected object.\n");
-    TEST_DISPLAY_NAME(moniker2, L"!I1!I2");
+    ok(hr == S_OK && moniker2 != moniker, "Unexpected hr %#x.\n", hr);
     IMoniker_Release(moniker2);
 
     /* Equal composites */
     hr = IMoniker_CommonPrefixWith(moniker, moniker1, &moniker2);
-    ok(hr == MK_S_US, "Unexpected hr %#x.\n", hr);
 todo_wine
+    ok(hr == MK_S_US, "Unexpected hr %#x.\n", hr);
     ok(moniker2 != moniker && moniker2 != moniker1, "Unexpected object.\n");
     hr = IMoniker_IsEqual(moniker, moniker2);
 todo_wine
@@ -3325,7 +3331,6 @@ todo_wine
     hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
     ok(hr == MK_S_HIM, "Unexpected hr %#x.\n", hr);
     hr = IMoniker_IsEqual(moniker2, moniker3);
-todo_wine
     ok(hr == S_OK && moniker3 != moniker2, "Unexpected object.\n");
     IMoniker_Release(moniker3);
 
-- 
2.33.0




More information about the wine-devel mailing list