From cdd932a060fa8b86b009dd7a87dacc4b62eda447 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sun, 9 Feb 2014 17:57:36 +0400 Subject: [PATCH] ole32: Separate IIDFromString() for CLSIDFromString(), fix corner cases and return values. --- dlls/ole32/compobj.c | 119 ++++++++++++++++++++++++------------- dlls/ole32/ole32.spec | 2 +- dlls/ole32/tests/compobj.c | 74 ++++++++++++++++++++++- 3 files changed, 153 insertions(+), 42 deletions(-) diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 2160cba37bb..719d9de5f5f 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -2065,33 +2065,16 @@ static inline BOOL is_valid_hex(WCHAR c) return TRUE; } -/****************************************************************************** - * CLSIDFromString [OLE32.@] - * IIDFromString [OLE32.@] - * - * Converts a unique identifier from its string representation into - * the GUID struct. - * - * PARAMS - * idstr [I] The string representation of the GUID. - * id [O] GUID converted from the string. - * - * RETURNS - * S_OK on success - * CO_E_CLASSSTRING if idstr is not a valid CLSID - * - * SEE ALSO - * StringFromCLSID - */ -static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id) +/* conversion helper for CLSIDFromString/IIDFromString */ +static BOOL guid_from_string(LPCWSTR s, GUID *id) { int i; BYTE table[256]; if (!s || s[0]!='{') { memset( id, 0, sizeof (CLSID) ); - if(!s) return S_OK; - return CO_E_CLASSSTRING; + if(!s) return TRUE; + return FALSE; } TRACE("%s -> %p\n", debugstr_w(s), id); @@ -2111,38 +2094,38 @@ static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id) id->Data1 = 0; for (i = 1; i < 9; i++) { - if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING; + if (!is_valid_hex(s[i])) return FALSE; id->Data1 = (id->Data1 << 4) | table[s[i]]; } - if (s[9]!='-') return CO_E_CLASSSTRING; + if (s[9]!='-') return FALSE; id->Data2 = 0; for (i = 10; i < 14; i++) { - if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING; + if (!is_valid_hex(s[i])) return FALSE; id->Data2 = (id->Data2 << 4) | table[s[i]]; } - if (s[14]!='-') return CO_E_CLASSSTRING; + if (s[14]!='-') return FALSE; id->Data3 = 0; for (i = 15; i < 19; i++) { - if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING; + if (!is_valid_hex(s[i])) return FALSE; id->Data3 = (id->Data3 << 4) | table[s[i]]; } - if (s[19]!='-') return CO_E_CLASSSTRING; + if (s[19]!='-') return FALSE; for (i = 20; i < 37; i+=2) { if (i == 24) { - if (s[i]!='-') return CO_E_CLASSSTRING; + if (s[i]!='-') return FALSE; i++; } - if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING; + if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE; id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]]; } if (s[37] == '}' && s[38] == '\0') - return S_OK; + return TRUE; - return CO_E_CLASSSTRING; + return FALSE; } /*****************************************************************************/ @@ -2157,6 +2140,7 @@ static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) memset(clsid, 0, sizeof(*clsid)); buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) ); + if (!buf) return E_OUTOFMEMORY; strcpyW( buf, progid ); strcatW( buf, clsidW ); if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) @@ -2174,26 +2158,81 @@ static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) return CO_E_CLASSSTRING; } RegCloseKey(xhkey); - return __CLSIDFromString(buf2,clsid); + return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; } +/****************************************************************************** + * CLSIDFromString [OLE32.@] + * + * Converts a unique identifier from its string representation into + * the GUID struct. + * + * PARAMS + * idstr [I] The string representation of the GUID. + * id [O] GUID converted from the string. + * + * RETURNS + * S_OK on success + * CO_E_CLASSSTRING if idstr is not a valid CLSID + * + * SEE ALSO + * StringFromCLSID + */ HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id ) { - HRESULT ret; + HRESULT ret = CO_E_CLASSSTRING; + CLSID tmp_id; if (!id) return E_INVALIDARG; - ret = __CLSIDFromString(idstr, id); - if(ret != S_OK) { /* It appears a ProgID is also valid */ - CLSID tmp_id; - ret = clsid_from_string_reg(idstr, &tmp_id); - if(SUCCEEDED(ret)) - *id = tmp_id; - } + if (guid_from_string(idstr, id)) + return S_OK; + + /* It appears a ProgID is also valid */ + ret = clsid_from_string_reg(idstr, &tmp_id); + if(SUCCEEDED(ret)) + *id = tmp_id; + return ret; } +/****************************************************************************** + * IIDFromString [OLE32.@] + * + * Converts a interface identifier from its string representation into + * the IID struct. + * + * PARAMS + * idstr [I] The string representation of the GUID. + * id [O] IID converted from the string. + * + * RETURNS + * S_OK on success + * CO_E_IIDSTRING if idstr is not a valid IID + * + * SEE ALSO + * StringFromIID + */ +HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid) +{ + TRACE("%s -> %p\n", debugstr_w(s), iid); + + if (!s) + { + memset(iid, 0, sizeof(*iid)); + return S_OK; + } + + /* length mismatch is a special case */ + if (strlenW(s) + 1 != CHARS_IN_GUID) + return E_INVALIDARG; + + if (s[0] != '{') + return CO_E_IIDSTRING; + + return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING; +} /****************************************************************************** * StringFromCLSID [OLE32.@] diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index 00d56967f66..70194508376 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -164,7 +164,7 @@ @ stdcall HWND_UserMarshal(ptr ptr ptr) @ stdcall HWND_UserSize(ptr long ptr) @ stdcall HWND_UserUnmarshal(ptr ptr ptr) -@ stdcall IIDFromString(wstr ptr) CLSIDFromString +@ stdcall IIDFromString(wstr ptr) @ stub I_RemoteMain @ stdcall IsAccelerator(long long ptr long) @ stdcall IsEqualGUID(ptr ptr) diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index c23a4d72878..c96dfe0dee0 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -73,6 +73,8 @@ static const WCHAR wszCLSID_StdFont[] = '9','d','e','3','-','0','0','a','a','0','0','4','b','b','8','5','1','}',0 }; static const WCHAR progidW[] = {'P','r','o','g','I','d','.','P','r','o','g','I','d',0}; +static const WCHAR cf_brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-', + 'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}','a',0}; DEFINE_GUID(IID_IWineTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd); DEFINE_GUID(CLSID_WineOOPTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd); @@ -396,10 +398,17 @@ static void test_CLSIDFromString(void) ok_ole_success(hr, "CLSIDFromString"); ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n"); + memset(&clsid, 0xab, sizeof(clsid)); hr = CLSIDFromString(NULL, &clsid); - ok_ole_success(hr, "CLSIDFromString"); + ok(hr == S_OK, "got 0x%08x\n", hr); ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n"); + /* string is longer, but starts with a valid CLSID */ + memset(&clsid, 0, sizeof(clsid)); + hr = CLSIDFromString(cf_brokenW, &clsid); + ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr); + ok(IsEqualCLSID(&clsid, &IID_IClassFactory), "got %s\n", wine_dbgstr_guid(&clsid)); + lstrcpyW(wszCLSID_Broken, wszCLSID_StdFont); for(i = lstrlenW(wszCLSID_StdFont); i < 49; i++) wszCLSID_Broken[i] = 'A'; @@ -455,6 +464,68 @@ static void test_CLSIDFromString(void) ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2); } +static void test_IIDFromString(void) +{ + static const WCHAR cfW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-', + 'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0}; + static const WCHAR brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-', + 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0}; + static const WCHAR broken2W[] = {'{','0','0','0','0','0','0','0','1','=','0','0','0','0','-','0','0','0','0','-', + 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0}; + static const WCHAR broken3W[] = {'b','r','o','k','e','n','0','0','1','=','0','0','0','0','-','0','0','0','0','-', + 'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0}; + HRESULT hr; + IID iid; + + hr = IIDFromString(wszCLSID_StdFont, &iid); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(IsEqualIID(&iid, &CLSID_StdFont), "got iid %s\n", wine_dbgstr_guid(&iid)); + + memset(&iid, 0xab, sizeof(iid)); + hr = IIDFromString(NULL, &iid); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(IsEqualIID(&iid, &CLSID_NULL), "got iid %s\n", wine_dbgstr_guid(&iid)); + + hr = IIDFromString(cfW, &iid); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(IsEqualIID(&iid, &IID_IClassFactory), "got iid %s\n", wine_dbgstr_guid(&iid)); + + /* string starts with a valid IID but is longer */ + memset(&iid, 0xab, sizeof(iid)); + hr = IIDFromString(cf_brokenW, &iid); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1); + + /* invalid IID in a valid format */ + memset(&iid, 0xab, sizeof(iid)); + hr = IIDFromString(brokenW, &iid); + ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr); + ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1); + + memset(&iid, 0xab, sizeof(iid)); + hr = IIDFromString(broken2W, &iid); + ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr); + ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1); + + /* format is broken, but string length is okay */ + memset(&iid, 0xab, sizeof(iid)); + hr = IIDFromString(broken3W, &iid); + ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr); + ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1); + + /* invalid string */ + memset(&iid, 0xab, sizeof(iid)); + hr = IIDFromString(wszNonExistent, &iid); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1); + + /* valid ProgID */ + memset(&iid, 0xab, sizeof(iid)); + hr = IIDFromString(stdfont, &iid); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1); +} + static void test_StringFromGUID2(void) { WCHAR str[50]; @@ -1932,6 +2003,7 @@ START_TEST(compobj) test_ProgIDFromCLSID(); test_CLSIDFromProgID(); test_CLSIDFromString(); + test_IIDFromString(); test_StringFromGUID2(); test_CoCreateInstance(); test_ole_menu();