fusion: Avoid memory leaks on memory allocation failure in parse_display_name.
[wine.git] / dlls / fusion / asmname.c
blob669b7b6d7de8626ba6af0766f5995e02693309a6
1 /*
2 * IAssemblyName implementation
4 * Copyright 2008 James Hawkins
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <assert.h>
24 #define COBJMACROS
25 #define INITGUID
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "ole2.h"
31 #include "guiddef.h"
32 #include "fusion.h"
33 #include "corerror.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "fusionpriv.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(fusion);
41 typedef struct {
42 const IAssemblyNameVtbl *lpIAssemblyNameVtbl;
44 LPWSTR path;
46 LPWSTR displayname;
47 LPWSTR name;
48 LPWSTR culture;
49 LPWSTR procarch;
51 WORD version[4];
52 DWORD versize;
54 BYTE pubkey[8];
55 BOOL haspubkey;
57 LONG ref;
58 } IAssemblyNameImpl;
60 static const WCHAR separator[] = {',',' ',0};
61 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
62 static const WCHAR culture[] = {'C','u','l','t','u','r','e',0};
63 static const WCHAR pubkey[] =
64 {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
65 static const WCHAR procarch[] = {'p','r','o','c','e','s','s','o','r',
66 'A','r','c','h','i','t','e','c','t','u','r','e',0};
68 #define CHARS_PER_PUBKEY 16
70 static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface,
71 REFIID riid, LPVOID *ppobj)
73 IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
75 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
77 *ppobj = NULL;
79 if (IsEqualIID(riid, &IID_IUnknown) ||
80 IsEqualIID(riid, &IID_IAssemblyName))
82 IUnknown_AddRef(iface);
83 *ppobj = This;
84 return S_OK;
87 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
88 return E_NOINTERFACE;
91 static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface)
93 IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
94 ULONG refCount = InterlockedIncrement(&This->ref);
96 TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
98 return refCount;
101 static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface)
103 IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
104 ULONG refCount = InterlockedDecrement(&This->ref);
106 TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
108 if (!refCount)
110 HeapFree(GetProcessHeap(), 0, This->path);
111 HeapFree(GetProcessHeap(), 0, This->displayname);
112 HeapFree(GetProcessHeap(), 0, This->name);
113 HeapFree(GetProcessHeap(), 0, This->culture);
114 HeapFree(GetProcessHeap(), 0, This->procarch);
115 HeapFree(GetProcessHeap(), 0, This);
118 return refCount;
121 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
122 DWORD PropertyId,
123 LPVOID pvProperty,
124 DWORD cbProperty)
126 FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
127 return E_NOTIMPL;
130 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
131 DWORD PropertyId,
132 LPVOID pvProperty,
133 LPDWORD pcbProperty)
135 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
137 TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
139 *((LPWSTR)pvProperty) = '\0';
141 switch (PropertyId)
143 case ASM_NAME_NULL_PUBLIC_KEY:
144 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
145 if (name->haspubkey)
146 return S_OK;
147 return S_FALSE;
149 case ASM_NAME_NULL_CUSTOM:
150 return S_OK;
152 case ASM_NAME_NAME:
153 *pcbProperty = 0;
154 if (name->name)
156 lstrcpyW(pvProperty, name->name);
157 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
159 break;
161 case ASM_NAME_MAJOR_VERSION:
162 *pcbProperty = 0;
163 *((WORD *)pvProperty) = name->version[0];
164 if (name->versize >= 1)
165 *pcbProperty = sizeof(WORD);
166 break;
168 case ASM_NAME_MINOR_VERSION:
169 *pcbProperty = 0;
170 *((WORD *)pvProperty) = name->version[1];
171 if (name->versize >= 2)
172 *pcbProperty = sizeof(WORD);
173 break;
175 case ASM_NAME_BUILD_NUMBER:
176 *pcbProperty = 0;
177 *((WORD *)pvProperty) = name->version[2];
178 if (name->versize >= 3)
179 *pcbProperty = sizeof(WORD);
180 break;
182 case ASM_NAME_REVISION_NUMBER:
183 *pcbProperty = 0;
184 *((WORD *)pvProperty) = name->version[3];
185 if (name->versize >= 4)
186 *pcbProperty = sizeof(WORD);
187 break;
189 case ASM_NAME_CULTURE:
190 *pcbProperty = 0;
191 if (name->culture)
193 lstrcpyW(pvProperty, name->culture);
194 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
196 break;
198 case ASM_NAME_PUBLIC_KEY_TOKEN:
199 *pcbProperty = 0;
200 if (name->haspubkey)
202 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
203 *pcbProperty = sizeof(DWORD) * 2;
205 break;
207 default:
208 *pcbProperty = 0;
209 break;
212 return S_OK;
215 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
217 FIXME("(%p) stub!\n", iface);
218 return E_NOTIMPL;
221 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
222 LPOLESTR szDisplayName,
223 LPDWORD pccDisplayName,
224 DWORD dwDisplayFlags)
226 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
227 WCHAR verstr[30];
228 DWORD size;
229 LPWSTR cultureval = 0;
231 static const WCHAR equals[] = {'=',0};
233 TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
234 pccDisplayName, dwDisplayFlags);
236 if (dwDisplayFlags == 0)
238 if (!name->displayname || !*name->displayname)
239 return FUSION_E_INVALID_NAME;
241 size = min(*pccDisplayName, lstrlenW(name->displayname) + 1);
243 lstrcpynW(szDisplayName, name->displayname, size);
244 *pccDisplayName = size;
246 return S_OK;
249 if (!name->name || !*name->name)
250 return FUSION_E_INVALID_NAME;
252 /* Verify buffer size is sufficient */
253 size = lstrlenW(name->name) + 1;
255 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
257 static const WCHAR spec[] = {'%','d',0};
258 static const WCHAR period[] = {'.',0};
259 int i;
261 wsprintfW(verstr, spec, name->version[0]);
263 for (i = 1; i < name->versize; i++)
265 WCHAR value[6];
266 wsprintfW(value, spec, name->version[i]);
268 lstrcatW(verstr, period);
269 lstrcatW(verstr, value);
272 size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr);
275 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
277 static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0};
279 cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral;
280 size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval);
283 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
284 size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY;
286 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
287 size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch);
289 if (size > *pccDisplayName)
290 return S_FALSE;
292 /* Construct the string */
293 lstrcpyW(szDisplayName, name->name);
295 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
297 lstrcatW(szDisplayName, separator);
299 lstrcatW(szDisplayName, version);
300 lstrcatW(szDisplayName, equals);
301 lstrcatW(szDisplayName, verstr);
304 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
306 lstrcatW(szDisplayName, separator);
308 lstrcatW(szDisplayName, culture);
309 lstrcatW(szDisplayName, equals);
310 lstrcatW(szDisplayName, cultureval);
313 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
315 WCHAR pkt[CHARS_PER_PUBKEY + 1];
316 static const WCHAR spec[] = {'%','0','x','%','0','x','%','0','x',
317 '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0};
319 lstrcatW(szDisplayName, separator);
321 lstrcatW(szDisplayName, pubkey);
322 lstrcatW(szDisplayName, equals);
324 wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2],
325 name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6],
326 name->pubkey[7]);
328 lstrcatW(szDisplayName, pkt);
331 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
333 lstrcatW(szDisplayName, separator);
335 lstrcatW(szDisplayName, procarch);
336 lstrcatW(szDisplayName, equals);
337 lstrcatW(szDisplayName, name->procarch);
340 *pccDisplayName = size;
341 return S_OK;
344 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
345 REFIID refIID,
346 IUnknown *pUnkReserved1,
347 IUnknown *pUnkReserved2,
348 LPCOLESTR szReserved,
349 LONGLONG llReserved,
350 LPVOID pvReserved,
351 DWORD cbReserved,
352 LPVOID *ppReserved)
354 TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface,
355 debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
356 debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved,
357 pvReserved, cbReserved, ppReserved);
359 return E_NOTIMPL;
362 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
363 LPDWORD lpcwBuffer,
364 WCHAR *pwzName)
366 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
368 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
370 if (!name->name)
372 *pwzName = '\0';
373 *lpcwBuffer = 0;
374 return S_OK;
377 lstrcpyW(pwzName, name->name);
378 *lpcwBuffer = lstrlenW(pwzName) + 1;
380 return S_OK;
383 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
384 LPDWORD pdwVersionHi,
385 LPDWORD pdwVersionLow)
387 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
389 TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
391 *pdwVersionHi = 0;
392 *pdwVersionLow = 0;
394 if (name->versize != 4)
395 return FUSION_E_INVALID_NAME;
397 *pdwVersionHi = (name->version[0] << 16) + name->version[1];
398 *pdwVersionLow = (name->version[2] << 16) + name->version[3];
400 return S_OK;
403 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
404 IAssemblyName *pName,
405 DWORD dwCmpFlags)
407 FIXME("(%p, %p, %d) stub!\n", iface, pName, dwCmpFlags);
408 return E_NOTIMPL;
411 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
412 IAssemblyName **pName)
414 FIXME("(%p, %p) stub!\n", iface, pName);
415 return E_NOTIMPL;
418 static const IAssemblyNameVtbl AssemblyNameVtbl = {
419 IAssemblyNameImpl_QueryInterface,
420 IAssemblyNameImpl_AddRef,
421 IAssemblyNameImpl_Release,
422 IAssemblyNameImpl_SetProperty,
423 IAssemblyNameImpl_GetProperty,
424 IAssemblyNameImpl_Finalize,
425 IAssemblyNameImpl_GetDisplayName,
426 IAssemblyNameImpl_Reserved,
427 IAssemblyNameImpl_GetName,
428 IAssemblyNameImpl_GetVersion,
429 IAssemblyNameImpl_IsEqual,
430 IAssemblyNameImpl_Clone
433 /* Internal methods */
434 HRESULT IAssemblyName_SetPath(IAssemblyName *iface, LPCWSTR path)
436 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
438 assert(name->lpIAssemblyNameVtbl == &AssemblyNameVtbl);
440 name->path = strdupW(path);
441 if (!name->path)
442 return E_OUTOFMEMORY;
444 return S_OK;
447 HRESULT IAssemblyName_GetPath(IAssemblyName *iface, LPWSTR buf, ULONG *len)
449 ULONG buffer_size = *len;
450 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
452 assert(name->lpIAssemblyNameVtbl == &AssemblyNameVtbl);
454 if (!name->path)
455 return S_OK;
457 if (!buf)
458 buffer_size = 0;
460 *len = lstrlenW(name->path) + 1;
462 if (*len <= buffer_size)
463 lstrcpyW(buf, name->path);
464 else
465 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
467 return S_OK;
470 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
472 LPWSTR beg, end;
473 int i;
475 for (i = 0, beg = version; i < 4; i++)
477 if (!*beg)
478 return S_OK;
480 end = strchrW(beg, '.');
482 if (end) *end = '\0';
483 name->version[i] = atolW(beg);
484 name->versize++;
486 if (!end && i < 3)
487 return S_OK;
489 beg = end + 1;
492 return S_OK;
495 static HRESULT parse_culture(IAssemblyNameImpl *name, LPCWSTR culture)
497 static const WCHAR empty[] = {0};
499 if (lstrlenW(culture) == 2)
500 name->culture = strdupW(culture);
501 else
502 name->culture = strdupW(empty);
504 return S_OK;
507 static BOOL is_hex(WCHAR c)
509 return ((c >= 'a' && c <= 'f') ||
510 (c >= 'A' && c <= 'F') ||
511 (c >= '0' && c <= '9'));
514 static BYTE hextobyte(WCHAR c)
516 if(c >= '0' && c <= '9')
517 return c - '0';
518 if(c >= 'A' && c <= 'F')
519 return c - 'A' + 10;
520 if(c >= 'a' && c <= 'f')
521 return c - 'a' + 10;
522 return 0;
525 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
527 int i;
528 BYTE val;
530 if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
531 return FUSION_E_INVALID_NAME;
533 for (i = 0; i < CHARS_PER_PUBKEY; i++)
534 if (!is_hex(pubkey[i]))
535 return FUSION_E_INVALID_NAME;
537 name->haspubkey = TRUE;
539 for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
541 val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
542 name->pubkey[i / 2] = val;
545 return S_OK;
548 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
550 LPWSTR str, save;
551 LPWSTR ptr, ptr2;
552 HRESULT hr = S_OK;
553 BOOL done = FALSE;
555 if (!szAssemblyName)
556 return S_OK;
558 name->displayname = strdupW(szAssemblyName);
559 if (!name->displayname)
560 return E_OUTOFMEMORY;
562 str = strdupW(szAssemblyName);
563 save = str;
564 if (!str)
566 hr = E_OUTOFMEMORY;
567 goto done;
570 ptr = strchrW(str, ',');
571 if (ptr) *ptr = '\0';
573 /* no ',' but ' ' only */
574 if( !ptr && strchrW(str, ' ') )
576 hr = FUSION_E_INVALID_NAME;
577 goto done;
580 name->name = strdupW(str);
581 if (!name->name)
583 hr = E_OUTOFMEMORY;
584 goto done;
587 if (!ptr)
588 goto done;
590 str = ptr + 2;
591 while (!done)
593 ptr = strchrW(str, '=');
594 if (!ptr)
596 hr = FUSION_E_INVALID_NAME;
597 goto done;
600 *(ptr++) = '\0';
601 if (!*ptr)
603 hr = FUSION_E_INVALID_NAME;
604 goto done;
607 if (!(ptr2 = strstrW(ptr, separator)))
609 if (!(ptr2 = strchrW(ptr, '\0')))
611 hr = FUSION_E_INVALID_NAME;
612 goto done;
615 done = TRUE;
618 *ptr2 = '\0';
620 while (*str == ' ') str++;
622 if (!lstrcmpW(str, version))
623 hr = parse_version(name, ptr);
624 else if (!lstrcmpW(str, culture))
625 hr = parse_culture(name, ptr);
626 else if (!lstrcmpW(str, pubkey))
627 hr = parse_pubkey(name, ptr);
628 else if (!lstrcmpW(str, procarch))
630 name->procarch = strdupW(ptr);
631 if (!name->procarch)
632 hr = E_OUTOFMEMORY;
635 if (FAILED(hr))
636 goto done;
638 str = ptr2 + 1;
641 done:
642 HeapFree(GetProcessHeap(), 0, save);
643 if (FAILED(hr))
645 HeapFree(GetProcessHeap(), 0, name->displayname);
646 HeapFree(GetProcessHeap(), 0, name->name);
648 return hr;
651 /******************************************************************
652 * CreateAssemblyNameObject (FUSION.@)
654 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
655 LPCWSTR szAssemblyName, DWORD dwFlags,
656 LPVOID pvReserved)
658 IAssemblyNameImpl *name;
659 HRESULT hr;
661 TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj,
662 debugstr_w(szAssemblyName), dwFlags, pvReserved);
664 if (!ppAssemblyNameObj)
665 return E_INVALIDARG;
667 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
668 (!szAssemblyName || !*szAssemblyName))
669 return E_INVALIDARG;
671 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
672 if (!name)
673 return E_OUTOFMEMORY;
675 name->lpIAssemblyNameVtbl = &AssemblyNameVtbl;
676 name->ref = 1;
678 hr = parse_display_name(name, szAssemblyName);
679 if (FAILED(hr))
681 HeapFree(GetProcessHeap(), 0, name);
682 return hr;
685 *ppAssemblyNameObj = (IAssemblyName *)name;
687 return S_OK;