From a5a333572c17684ae39189711ad2d2a9adb68a75 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 14 Sep 2021 11:47:57 +0300 Subject: [PATCH] ole32: Improve class moniker display name parsing. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/ole32/classmoniker.c | 137 +++++++++++++++++-------------------- dlls/ole32/moniker.c | 3 +- dlls/ole32/tests/moniker.c | 89 ++++++++++++++++++------ 3 files changed, 133 insertions(+), 96 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; - CLSID clsid; - BYTE table[256]; - int i; + TRACE("%s, %p\n", debugstr_guid(rclsid), moniker); - if (!s) + 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; + HRESULT hr; + int len; + + s = display_name; + + /* Skip prefix */ + if (wcsnicmp(s, L"clsid:", 6)) return MK_E_SYNTAX; + s += 6; + + /* Terminating marker is optional */ + if (!(end = wcschr(s, ':'))) + end = s + lstrlenW(s); + + len = end - s; + if (len < 36) return MK_E_SYNTAX; - s++; + if ((has_braces = *s == '{')) s++; - for (end = s; *end && (*end != ':'); end++) - ; + memcpy(uuid, s, 36 * sizeof(WCHAR)); + uuid[36] = 0; - TRACE("parsing %s\n", debugstr_wn(s, end - s)); - - /* validate the CLSID string */ - if (s[0] == '{') + if (UuidFromStringW(uuid, &clsid)) { - if ((end - s != 38) || (s[37] != '}')) - return MK_E_SYNTAX; + WARN("Failed to parse clsid string.\n"); + return MK_E_SYNTAX; + } + + s += 36; + if (has_braces) + { + if (*s != '}') return MK_E_SYNTAX; s++; } - else - { - if (end - s != 36) - return MK_E_SYNTAX; - } - for (i=0; i<36; i++) - { - 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; - } + /* Consume terminal marker */ + len = end - s; + if (*end == ':') end++; - /* quick lookup table */ - memset(table, 0, 256); - - for (i = 0; i < 10; i++) - table['0' + i] = i; - for (i = 0; i < 6; i++) - { - table['A' + i] = i+10; - table['a' + i] = i+10; - } - - /* 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]]; - - 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);