ole32: Improve class moniker display name parsing.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2021-09-14 11:47:57 +03:00 committed by Alexandre Julliard
parent 44d57a615f
commit a5a333572c
3 changed files with 133 additions and 96 deletions

View File

@ -654,106 +654,95 @@ static const IROTDataVtbl ROTDataVtbl =
ClassMonikerROTData_GetComparisonData ClassMonikerROTData_GetComparisonData
}; };
/****************************************************************************** static HRESULT create_class_moniker(const CLSID *clsid, const WCHAR *data,
* CreateClassMoniker [OLE32.@] unsigned int data_len, IMoniker **moniker)
******************************************************************************/
HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker **moniker)
{ {
ClassMoniker *object; ClassMoniker *object;
TRACE("%s, %p\n", debugstr_guid(rclsid), moniker); if (!(object = heap_alloc_zero(sizeof(*object))))
if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
object->IMoniker_iface.lpVtbl = &ClassMonikerVtbl; object->IMoniker_iface.lpVtbl = &ClassMonikerVtbl;
object->IROTData_iface.lpVtbl = &ROTDataVtbl; object->IROTData_iface.lpVtbl = &ROTDataVtbl;
object->ref = 1; 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; *moniker = &object->IMoniker_iface;
return S_OK; 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; TRACE("%s, %p\n", debugstr_guid(rclsid), moniker);
LPCWSTR s = wcschr(szDisplayName, ':');
LPCWSTR end;
CLSID clsid;
BYTE table[256];
int i;
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; 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)); if (UuidFromStringW(uuid, &clsid))
/* validate the CLSID string */
if (s[0] == '{')
{ {
if ((end - s != 38) || (s[37] != '}')) WARN("Failed to parse clsid string.\n");
return MK_E_SYNTAX; return MK_E_SYNTAX;
}
s += 36;
if (has_braces)
{
if (*s != '}') return MK_E_SYNTAX;
s++; s++;
} }
else
{
if (end - s != 36)
return MK_E_SYNTAX;
}
for (i=0; i<36; i++) /* Consume terminal marker */
{ len = end - s;
if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) if (*end == ':') end++;
{
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;
}
/* quick lookup table */ hr = create_class_moniker(&clsid, len ? s : NULL, len, moniker);
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);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
*pchEaten = (*end == ':' ? end + 1 : end) - szDisplayName; *eaten = end - display_name;
return hr; return hr;
} }

View File

@ -827,7 +827,6 @@ HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
LPDWORD pchEaten, LPMONIKER *ppmk) LPDWORD pchEaten, LPMONIKER *ppmk)
{ {
HRESULT hr = MK_E_SYNTAX; HRESULT hr = MK_E_SYNTAX;
static const WCHAR wszClsidColon[] = {'c','l','s','i','d',':'};
IMoniker *moniker; IMoniker *moniker;
DWORD chEaten; DWORD chEaten;
@ -845,7 +844,7 @@ HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
*pchEaten = 0; *pchEaten = 0;
*ppmk = NULL; *ppmk = NULL;
if (!wcsnicmp(szDisplayName, wszClsidColon, ARRAY_SIZE(wszClsidColon))) if (!wcsnicmp(szDisplayName, L"clsid:", 6))
{ {
hr = ClassMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker); hr = ClassMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker);
if (FAILED(hr) && (hr != MK_E_SYNTAX)) if (FAILED(hr) && (hr != MK_E_SYNTAX))

View File

@ -1767,6 +1767,22 @@ todo_wine_if(moniker_type == MKSYS_GENERICCOMPOSITE)
static void test_class_moniker(void) 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; IMoniker *moniker, *moniker2, *inverse, *reduced, *anti;
IEnumMoniker *enummoniker; IEnumMoniker *enummoniker;
ULONG length, eaten; ULONG length, eaten;
@ -1780,38 +1796,51 @@ static void test_class_moniker(void)
FILETIME filetime; FILETIME filetime;
IStream *stream; IStream *stream;
BYTE buffer[100]; BYTE buffer[100];
HGLOBAL hglobal;
unsigned int i;
DWORD *data;
hr = CreateBindCtx(0, &bindctx); hr = CreateBindCtx(0, &bindctx);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr); 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. */ /* 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); 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); 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); hr = MkParseDisplayName(bindctx, L"clsid:11111111-0000-0000-2222-444444444444;different extra data:", &eaten, &moniker2);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
TEST_DISPLAY_NAME(moniker, L"clsid:11111111-0000-0000-2222-444444444444;extra data:"); TEST_DISPLAY_NAME(moniker, L"clsid:11111111-0000-0000-2222-444444444444;extra data:");
TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER); TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER);
hr = IMoniker_GetSizeMax(moniker, &size); hr = IMoniker_GetSizeMax(moniker, &size);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(size.LowPart == 44, "Unexpected size %u.\n", size.LowPart); 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); hr = IMoniker_IsEqual(moniker, moniker2);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMoniker_IsEqual(moniker2, moniker); hr = IMoniker_IsEqual(moniker2, moniker);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IMoniker_Release(moniker2); IMoniker_Release(moniker2);
IMoniker_Release(moniker); IMoniker_Release(moniker);
}
/* From persistent state */ /* From persistent state */
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
@ -1842,6 +1871,27 @@ todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(size.QuadPart == 30, "Unexpected size %u.\n", size.LowPart); ok(size.QuadPart == 30, "Unexpected size %u.\n", size.LowPart);
TEST_DISPLAY_NAME(moniker, L"clsid:0002E005-0000-0000-C000-000000000046data:"); 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 */ /* Extra data does not affect comparison */
hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata); 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"); ok(!memcmp(buffer, expected_class_moniker_comparison_data, length), "Unexpected data.\n");
IROTData_Release(rotdata); IROTData_Release(rotdata);
IStream_Release(stream);
IMoniker_Release(moniker); IMoniker_Release(moniker);
hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker); hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker);