[PATCH 8/8] ole32: Improve class moniker display name parsing.

Nikolay Sivov nsivov at codeweavers.com
Tue Sep 14 03:47:57 CDT 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/ole32/classmoniker.c  | 129 +++++++++++++++++--------------------
 dlls/ole32/moniker.c       |   3 +-
 dlls/ole32/tests/moniker.c |  89 +++++++++++++++++++------
 3 files changed, 129 insertions(+), 92 deletions(-)

diff --git a/dlls/ole32/classmoniker.c b/dlls/ole32/classmoniker.c
index 86c2639e8ec..03c7f773e29 100644
--- a/dlls/ole32/classmoniker.c
+++ b/dlls/ole32/classmoniker.c
@@ -654,106 +654,95 @@ static const IROTDataVtbl ROTDataVtbl =
     ClassMonikerROTData_GetComparisonData
 };
 
-/******************************************************************************
- *        CreateClassMoniker	[OLE32.@]
- ******************************************************************************/
-HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker **moniker)
+static HRESULT create_class_moniker(const CLSID *clsid, const WCHAR *data,
+        unsigned int data_len, IMoniker **moniker)
 {
     ClassMoniker *object;
 
-    TRACE("%s, %p\n", debugstr_guid(rclsid), moniker);
-
-    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+    if (!(object = heap_alloc_zero(sizeof(*object))))
         return E_OUTOFMEMORY;
 
     object->IMoniker_iface.lpVtbl = &ClassMonikerVtbl;
     object->IROTData_iface.lpVtbl = &ROTDataVtbl;
     object->ref = 1;
-    object->header.clsid = *rclsid;
+    object->header.clsid = *clsid;
+    if (data_len)
+    {
+        object->header.data_len = (data_len + 1) * sizeof(WCHAR);
+
+        if (!(object->data = heap_alloc(object->header.data_len)))
+        {
+            IMoniker_Release(&object->IMoniker_iface);
+            return E_OUTOFMEMORY;
+        }
+        memcpy(object->data, data, data_len * sizeof(WCHAR));
+        object->data[data_len] = 0;
+    }
 
     *moniker = &object->IMoniker_iface;
 
     return S_OK;
 }
 
-HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName, LPDWORD pchEaten,
-                                           IMoniker **ppmk)
+/******************************************************************************
+ *        CreateClassMoniker	[OLE32.@]
+ ******************************************************************************/
+HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker **moniker)
 {
-    HRESULT hr;
-    LPCWSTR s = wcschr(szDisplayName, ':');
-    LPCWSTR end;
+    TRACE("%s, %p\n", debugstr_guid(rclsid), moniker);
+
+    return create_class_moniker(rclsid, NULL, 0, moniker);
+}
+
+HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, const WCHAR *display_name,
+        DWORD *eaten, IMoniker **moniker)
+{
+    const WCHAR *end, *s;
+    BOOL has_braces;
+    WCHAR uuid[37];
     CLSID clsid;
-    BYTE table[256];
-    int i;
+    HRESULT hr;
+    int len;
 
-    if (!s)
-        return MK_E_SYNTAX;
+    s = display_name;
 
-    s++;
+    /* Skip prefix */
+    if (wcsnicmp(s, L"clsid:", 6)) return MK_E_SYNTAX;
+    s += 6;
 
-    for (end = s; *end && (*end != ':'); end++)
-        ;
+    /* Terminating marker is optional */
+    if (!(end = wcschr(s, ':')))
+        end = s + lstrlenW(s);
 
-    TRACE("parsing %s\n", debugstr_wn(s, end - s));
+    len = end - s;
+    if (len < 36)
+        return MK_E_SYNTAX;
 
-    /* validate the CLSID string */
-    if (s[0] == '{')
-    {
-        if ((end - s != 38) || (s[37] != '}'))
-            return MK_E_SYNTAX;
-        s++;
-    }
-    else
-    {
-        if (end - s != 36)
-            return MK_E_SYNTAX;
-    }
+    if ((has_braces = *s == '{')) s++;
+
+    memcpy(uuid, s, 36 * sizeof(WCHAR));
+    uuid[36] = 0;
 
-    for (i=0; i<36; i++)
+    if (UuidFromStringW(uuid, &clsid))
     {
-        if ((i == 8)||(i == 13)||(i == 18)||(i == 23))
-        {
-            if (s[i] != '-')
-                return MK_E_SYNTAX;
-            continue;
-        }
-        if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
-              ((s[i] >= 'a') && (s[i] <= 'f'))  ||
-              ((s[i] >= 'A') && (s[i] <= 'F'))))
-            return MK_E_SYNTAX;
+        WARN("Failed to parse clsid string.\n");
+        return MK_E_SYNTAX;
     }
 
-    /* quick lookup table */
-    memset(table, 0, 256);
-
-    for (i = 0; i < 10; i++)
-        table['0' + i] = i;
-    for (i = 0; i < 6; i++)
+    s += 36;
+    if (has_braces)
     {
-        table['A' + i] = i+10;
-        table['a' + i] = i+10;
+        if (*s != '}') return MK_E_SYNTAX;
+        s++;
     }
 
-    /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */
-
-    clsid.Data1 = (table[s[0]] << 28 | table[s[1]] << 24 | table[s[2]] << 20 | table[s[3]] << 16 |
-                   table[s[4]] << 12 | table[s[5]] << 8  | table[s[6]] << 4  | table[s[7]]);
-    clsid.Data2 = table[s[9]] << 12  | table[s[10]] << 8 | table[s[11]] << 4 | table[s[12]];
-    clsid.Data3 = table[s[14]] << 12 | table[s[15]] << 8 | table[s[16]] << 4 | table[s[17]];
-
-    /* these are just sequential bytes */
-    clsid.Data4[0] = table[s[19]] << 4 | table[s[20]];
-    clsid.Data4[1] = table[s[21]] << 4 | table[s[22]];
-    clsid.Data4[2] = table[s[24]] << 4 | table[s[25]];
-    clsid.Data4[3] = table[s[26]] << 4 | table[s[27]];
-    clsid.Data4[4] = table[s[28]] << 4 | table[s[29]];
-    clsid.Data4[5] = table[s[30]] << 4 | table[s[31]];
-    clsid.Data4[6] = table[s[32]] << 4 | table[s[33]];
-    clsid.Data4[7] = table[s[34]] << 4 | table[s[35]];
+    /* Consume terminal marker */
+    len = end - s;
+    if (*end == ':') end++;
 
-    hr = CreateClassMoniker(&clsid, ppmk);
+    hr = create_class_moniker(&clsid, len ? s : NULL, len, moniker);
     if (SUCCEEDED(hr))
-        *pchEaten = (*end == ':' ? end + 1 : end) - szDisplayName;
+        *eaten = end - display_name;
     return hr;
 }
 
diff --git a/dlls/ole32/moniker.c b/dlls/ole32/moniker.c
index be78eb90cf3..aed491d406f 100644
--- a/dlls/ole32/moniker.c
+++ b/dlls/ole32/moniker.c
@@ -827,7 +827,6 @@ HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
 				LPDWORD pchEaten, LPMONIKER *ppmk)
 {
     HRESULT hr = MK_E_SYNTAX;
-    static const WCHAR wszClsidColon[] = {'c','l','s','i','d',':'};
     IMoniker *moniker;
     DWORD chEaten;
 
@@ -845,7 +844,7 @@ HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
     *pchEaten = 0;
     *ppmk = NULL;
 
-    if (!wcsnicmp(szDisplayName, wszClsidColon, ARRAY_SIZE(wszClsidColon)))
+    if (!wcsnicmp(szDisplayName, L"clsid:", 6))
     {
         hr = ClassMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker);
         if (FAILED(hr) && (hr != MK_E_SYNTAX))
diff --git a/dlls/ole32/tests/moniker.c b/dlls/ole32/tests/moniker.c
index afe40980dd9..5221be495f0 100644
--- a/dlls/ole32/tests/moniker.c
+++ b/dlls/ole32/tests/moniker.c
@@ -1767,6 +1767,22 @@ todo_wine_if(moniker_type == MKSYS_GENERICCOMPOSITE)
 
 static void test_class_moniker(void)
 {
+    static const struct parse_test
+    {
+        const WCHAR *name;
+        ULONG eaten;
+        HRESULT hr;
+    }
+    tests[] =
+    {
+        { L"clsid:11111111-0000-0000-2222-444444444444;extra data:", 54 },
+        { L"clsid:11111111-0000-0000-2222-444444444444extra data", 52 },
+        { L"clsid:11111111-0000-0000-2222-444444444444:", 43 },
+        { L"clsid:11111111-0000-0000-2222-444444444444", 42 },
+        { L"clsid:{11111111-0000-0000-2222-444444444444}", 44 },
+        { L"clsid:{11111111-0000-0000-2222-444444444444", 0, MK_E_SYNTAX },
+        { L"clsid:11111111-0000-0000-2222-444444444444}", 43 },
+    };
     IMoniker *moniker, *moniker2, *inverse, *reduced, *anti;
     IEnumMoniker *enummoniker;
     ULONG length, eaten;
@@ -1780,38 +1796,51 @@ static void test_class_moniker(void)
     FILETIME filetime;
     IStream *stream;
     BYTE buffer[100];
+    HGLOBAL hglobal;
+    unsigned int i;
+    DWORD *data;
 
     hr = CreateBindCtx(0, &bindctx);
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
+    for (i = 0; i < ARRAY_SIZE(tests); ++i)
+    {
+        eaten = 0xdeadbeef;
+        hr = MkParseDisplayName(bindctx, tests[i].name, &eaten, &moniker);
+    todo_wine_if(i == 5)
+        ok(hr == tests[i].hr, "%u: unexpected hr %#x.\n", i, hr);
+        ok(eaten == tests[i].eaten, "%u: unexpected eaten length %u, expected %u.\n", i, eaten, tests[i].eaten);
+        if (SUCCEEDED(hr))
+        {
+            TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER);
+            IMoniker_Release(moniker);
+        }
+    }
+
     /* Extended syntax, handled by class moniker directly, only CLSID is meaningful for equality. */
     hr = MkParseDisplayName(bindctx, L"clsid:11111111-0000-0000-2222-444444444444;extra data:", &eaten, &moniker);
-todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-    if (SUCCEEDED(hr))
-    {
-        ok(eaten == 54, "Unexpected length %u.\n", eaten);
+    ok(eaten == 54, "Unexpected length %u.\n", eaten);
 
-        hr = MkParseDisplayName(bindctx, L"clsid:11111111-0000-0000-2222-444444444444;different extra data:", &eaten, &moniker2);
-        ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    hr = MkParseDisplayName(bindctx, L"clsid:11111111-0000-0000-2222-444444444444;different extra data:", &eaten, &moniker2);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
-        TEST_DISPLAY_NAME(moniker, L"clsid:11111111-0000-0000-2222-444444444444;extra data:");
-        TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER);
-        hr = IMoniker_GetSizeMax(moniker, &size);
-        ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-        ok(size.LowPart == 44, "Unexpected size %u.\n", size.LowPart);
+    TEST_DISPLAY_NAME(moniker, L"clsid:11111111-0000-0000-2222-444444444444;extra data:");
+    TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER);
+    hr = IMoniker_GetSizeMax(moniker, &size);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(size.LowPart == 44, "Unexpected size %u.\n", size.LowPart);
 
-        TEST_MONIKER_TYPE(moniker2, MKSYS_CLASSMONIKER);
+    TEST_MONIKER_TYPE(moniker2, MKSYS_CLASSMONIKER);
 
-        hr = IMoniker_IsEqual(moniker, moniker2);
-        ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    hr = IMoniker_IsEqual(moniker, moniker2);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
-        hr = IMoniker_IsEqual(moniker2, moniker);
-        ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    hr = IMoniker_IsEqual(moniker2, moniker);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
 
-        IMoniker_Release(moniker2);
-        IMoniker_Release(moniker);
-    }
+    IMoniker_Release(moniker2);
+    IMoniker_Release(moniker);
 
     /* From persistent state */
     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
@@ -1842,6 +1871,27 @@ todo_wine
     ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
     ok(size.QuadPart == 30, "Unexpected size %u.\n", size.LowPart);
     TEST_DISPLAY_NAME(moniker, L"clsid:0002E005-0000-0000-C000-000000000046data:");
+    IStream_Release(stream);
+
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = GetHGlobalFromStream(stream, &hglobal);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IMoniker_Save(moniker, stream, FALSE);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    length = GlobalSize(hglobal);
+    data = GlobalLock(hglobal);
+    ok(length == 30, "Unexpected stream size %u.\n", length);
+    ok(IsEqualGUID((CLSID *)data, &CLSID_StdComponentCategoriesMgr), "Unexpected clsid.\n");
+    data += sizeof(CLSID) / sizeof(*data);
+    ok(*data == 10, "Unexpected data length %u.\n", *data);
+    data++;
+    ok(!lstrcmpW((WCHAR *)data, L"data"), "Unexpected data.\n");
+
+    IStream_Release(stream);
 
     /* Extra data does not affect comparison */
     hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
@@ -1852,7 +1902,6 @@ todo_wine
     ok(!memcmp(buffer, expected_class_moniker_comparison_data, length), "Unexpected data.\n");
     IROTData_Release(rotdata);
 
-    IStream_Release(stream);
     IMoniker_Release(moniker);
 
     hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker);
-- 
2.33.0




More information about the wine-devel mailing list