[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