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
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "fusionpriv.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(fusion);
42 IAssemblyName IAssemblyName_iface;
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 inline IAssemblyNameImpl *impl_from_IAssemblyName(IAssemblyName *iface)
72 return CONTAINING_RECORD(iface, IAssemblyNameImpl, IAssemblyName_iface);
75 static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface,
76 REFIID riid, LPVOID *ppobj)
78 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
80 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
84 if (IsEqualIID(riid, &IID_IUnknown) ||
85 IsEqualIID(riid, &IID_IAssemblyName))
87 IAssemblyName_AddRef(iface);
92 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
96 static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface)
98 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
99 ULONG refCount = InterlockedIncrement(&This->ref);
101 TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
106 static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface)
108 IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
109 ULONG refCount = InterlockedDecrement(&This->ref);
111 TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
115 HeapFree(GetProcessHeap(), 0, This->path);
116 HeapFree(GetProcessHeap(), 0, This->displayname);
117 HeapFree(GetProcessHeap(), 0, This->name);
118 HeapFree(GetProcessHeap(), 0, This->culture);
119 HeapFree(GetProcessHeap(), 0, This->procarch);
120 HeapFree(GetProcessHeap(), 0, This);
126 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
131 FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
135 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
140 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
142 TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
144 *((LPWSTR)pvProperty) = '\0';
148 case ASM_NAME_NULL_PUBLIC_KEY:
149 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
154 case ASM_NAME_NULL_CUSTOM:
161 lstrcpyW(pvProperty, name->name);
162 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
166 case ASM_NAME_MAJOR_VERSION:
168 *((WORD *)pvProperty) = name->version[0];
169 if (name->versize >= 1)
170 *pcbProperty = sizeof(WORD);
173 case ASM_NAME_MINOR_VERSION:
175 *((WORD *)pvProperty) = name->version[1];
176 if (name->versize >= 2)
177 *pcbProperty = sizeof(WORD);
180 case ASM_NAME_BUILD_NUMBER:
182 *((WORD *)pvProperty) = name->version[2];
183 if (name->versize >= 3)
184 *pcbProperty = sizeof(WORD);
187 case ASM_NAME_REVISION_NUMBER:
189 *((WORD *)pvProperty) = name->version[3];
190 if (name->versize >= 4)
191 *pcbProperty = sizeof(WORD);
194 case ASM_NAME_CULTURE:
198 lstrcpyW(pvProperty, name->culture);
199 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
203 case ASM_NAME_PUBLIC_KEY_TOKEN:
207 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
208 *pcbProperty = sizeof(DWORD) * 2;
220 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
222 FIXME("(%p) stub!\n", iface);
226 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
227 LPOLESTR szDisplayName,
228 LPDWORD pccDisplayName,
229 DWORD dwDisplayFlags)
231 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
234 LPWSTR cultureval = 0;
236 static const WCHAR equals[] = {'=',0};
238 TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
239 pccDisplayName, dwDisplayFlags);
241 if (dwDisplayFlags == 0)
243 if (!name->displayname || !*name->displayname)
244 return FUSION_E_INVALID_NAME;
246 size = min(*pccDisplayName, lstrlenW(name->displayname) + 1);
248 lstrcpynW(szDisplayName, name->displayname, size);
249 *pccDisplayName = size;
254 if (!name->name || !*name->name)
255 return FUSION_E_INVALID_NAME;
257 /* Verify buffer size is sufficient */
258 size = lstrlenW(name->name) + 1;
260 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
262 static const WCHAR spec[] = {'%','d',0};
263 static const WCHAR period[] = {'.',0};
266 wsprintfW(verstr, spec, name->version[0]);
268 for (i = 1; i < name->versize; i++)
271 wsprintfW(value, spec, name->version[i]);
273 lstrcatW(verstr, period);
274 lstrcatW(verstr, value);
277 size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr);
280 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
282 static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0};
284 cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral;
285 size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval);
288 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
289 size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY;
291 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
292 size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch);
294 if (size > *pccDisplayName)
297 /* Construct the string */
298 lstrcpyW(szDisplayName, name->name);
300 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
302 lstrcatW(szDisplayName, separator);
304 lstrcatW(szDisplayName, version);
305 lstrcatW(szDisplayName, equals);
306 lstrcatW(szDisplayName, verstr);
309 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
311 lstrcatW(szDisplayName, separator);
313 lstrcatW(szDisplayName, culture);
314 lstrcatW(szDisplayName, equals);
315 lstrcatW(szDisplayName, cultureval);
318 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
320 WCHAR pkt[CHARS_PER_PUBKEY + 1];
321 static const WCHAR spec[] = {'%','0','x','%','0','x','%','0','x',
322 '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0};
324 lstrcatW(szDisplayName, separator);
326 lstrcatW(szDisplayName, pubkey);
327 lstrcatW(szDisplayName, equals);
329 wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2],
330 name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6],
333 lstrcatW(szDisplayName, pkt);
336 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
338 lstrcatW(szDisplayName, separator);
340 lstrcatW(szDisplayName, procarch);
341 lstrcatW(szDisplayName, equals);
342 lstrcatW(szDisplayName, name->procarch);
345 *pccDisplayName = size;
349 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
351 IUnknown *pUnkReserved1,
352 IUnknown *pUnkReserved2,
353 LPCOLESTR szReserved,
359 TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface,
360 debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
361 debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved,
362 pvReserved, cbReserved, ppReserved);
367 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
371 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
373 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
382 lstrcpyW(pwzName, name->name);
383 *lpcwBuffer = lstrlenW(pwzName) + 1;
388 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
389 LPDWORD pdwVersionHi,
390 LPDWORD pdwVersionLow)
392 IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
394 TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
399 if (name->versize != 4)
400 return FUSION_E_INVALID_NAME;
402 *pdwVersionHi = (name->version[0] << 16) + name->version[1];
403 *pdwVersionLow = (name->version[2] << 16) + name->version[3];
408 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
409 IAssemblyName *pName,
412 IAssemblyNameImpl *name1 = impl_from_IAssemblyName(iface);
413 IAssemblyNameImpl *name2 = impl_from_IAssemblyName(pName);
415 TRACE("(%p, %p, 0x%08x)\n", iface, pName, flags);
417 if (!pName) return S_FALSE;
418 if (flags & ~ASM_CMPF_IL_ALL) FIXME("unsupported flags\n");
420 if ((flags & ASM_CMPF_NAME) && strcmpW(name1->name, name2->name)) return S_FALSE;
421 if (name1->versize && name2->versize)
423 if ((flags & ASM_CMPF_MAJOR_VERSION) &&
424 name1->version[0] != name2->version[0]) return S_FALSE;
425 if ((flags & ASM_CMPF_MINOR_VERSION) &&
426 name1->version[1] != name2->version[1]) return S_FALSE;
427 if ((flags & ASM_CMPF_BUILD_NUMBER) &&
428 name1->version[2] != name2->version[2]) return S_FALSE;
429 if ((flags & ASM_CMPF_REVISION_NUMBER) &&
430 name1->version[3] != name2->version[3]) return S_FALSE;
432 if ((flags & ASM_CMPF_PUBLIC_KEY_TOKEN) &&
433 name1->haspubkey && name2->haspubkey &&
434 memcmp(name1->pubkey, name2->pubkey, sizeof(name1->pubkey))) return S_FALSE;
436 if ((flags & ASM_CMPF_CULTURE) &&
437 name1->culture && name2->culture &&
438 strcmpW(name1->culture, name2->culture)) return S_FALSE;
443 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
444 IAssemblyName **pName)
446 FIXME("(%p, %p) stub!\n", iface, pName);
450 static const IAssemblyNameVtbl AssemblyNameVtbl = {
451 IAssemblyNameImpl_QueryInterface,
452 IAssemblyNameImpl_AddRef,
453 IAssemblyNameImpl_Release,
454 IAssemblyNameImpl_SetProperty,
455 IAssemblyNameImpl_GetProperty,
456 IAssemblyNameImpl_Finalize,
457 IAssemblyNameImpl_GetDisplayName,
458 IAssemblyNameImpl_Reserved,
459 IAssemblyNameImpl_GetName,
460 IAssemblyNameImpl_GetVersion,
461 IAssemblyNameImpl_IsEqual,
462 IAssemblyNameImpl_Clone
465 /* Internal methods */
466 static inline IAssemblyNameImpl *unsafe_impl_from_IAssemblyName(IAssemblyName *iface)
468 assert(iface->lpVtbl == &AssemblyNameVtbl);
470 return impl_from_IAssemblyName(iface);
473 HRESULT IAssemblyName_SetPath(IAssemblyName *iface, LPCWSTR path)
475 IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
477 name->path = strdupW(path);
479 return E_OUTOFMEMORY;
484 HRESULT IAssemblyName_GetPath(IAssemblyName *iface, LPWSTR buf, ULONG *len)
486 ULONG buffer_size = *len;
487 IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
495 *len = lstrlenW(name->path) + 1;
497 if (*len <= buffer_size)
498 lstrcpyW(buf, name->path);
500 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
505 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
510 for (i = 0, beg = version; i < 4; i++)
515 end = strchrW(beg, '.');
517 if (end) *end = '\0';
518 name->version[i] = atolW(beg);
530 static HRESULT parse_culture(IAssemblyNameImpl *name, LPCWSTR culture)
532 static const WCHAR empty[] = {0};
534 if (lstrlenW(culture) == 2)
535 name->culture = strdupW(culture);
537 name->culture = strdupW(empty);
542 static BOOL is_hex(WCHAR c)
544 return ((c >= 'a' && c <= 'f') ||
545 (c >= 'A' && c <= 'F') ||
546 (c >= '0' && c <= '9'));
549 static BYTE hextobyte(WCHAR c)
551 if(c >= '0' && c <= '9')
553 if(c >= 'A' && c <= 'F')
555 if(c >= 'a' && c <= 'f')
560 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
565 if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
566 return FUSION_E_INVALID_NAME;
568 for (i = 0; i < CHARS_PER_PUBKEY; i++)
569 if (!is_hex(pubkey[i]))
570 return FUSION_E_INVALID_NAME;
572 name->haspubkey = TRUE;
574 for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
576 val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
577 name->pubkey[i / 2] = val;
583 static WCHAR *parse_value( const WCHAR *str, unsigned int len )
586 const WCHAR *p = str;
590 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
596 while (*p && *p != '\"') ret[i++] = *p++;
597 if ((quoted && *p != '\"') || (!quoted && *p == '\"'))
599 HeapFree( GetProcessHeap(), 0, ret );
606 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
608 LPWSTR str, save, ptr, ptr2, value;
615 name->displayname = strdupW(szAssemblyName);
616 if (!name->displayname)
617 return E_OUTOFMEMORY;
619 str = strdupW(szAssemblyName);
627 ptr = strchrW(str, ',');
628 if (ptr) *ptr = '\0';
630 /* no ',' but ' ' only */
631 if( !ptr && strchrW(str, ' ') )
633 hr = FUSION_E_INVALID_NAME;
637 name->name = strdupW(str);
650 ptr = strchrW(str, '=');
653 hr = FUSION_E_INVALID_NAME;
660 hr = FUSION_E_INVALID_NAME;
664 if (!(ptr2 = strchrW(ptr, ',')))
666 if (!(ptr2 = strchrW(ptr, '\0')))
668 hr = FUSION_E_INVALID_NAME;
676 if (!(value = parse_value( ptr, ptr2 - ptr )))
678 hr = FUSION_E_INVALID_NAME;
681 while (*str == ' ') str++;
683 if (!lstrcmpiW(str, version))
684 hr = parse_version( name, value );
685 else if (!lstrcmpiW(str, culture))
686 hr = parse_culture( name, value );
687 else if (!lstrcmpiW(str, pubkey))
688 hr = parse_pubkey( name, value );
689 else if (!lstrcmpiW(str, procarch))
691 name->procarch = value;
694 HeapFree( GetProcessHeap(), 0, value );
703 HeapFree(GetProcessHeap(), 0, save);
706 HeapFree(GetProcessHeap(), 0, name->displayname);
707 HeapFree(GetProcessHeap(), 0, name->name);
712 /******************************************************************
713 * CreateAssemblyNameObject (FUSION.@)
715 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
716 LPCWSTR szAssemblyName, DWORD dwFlags,
719 IAssemblyNameImpl *name;
722 TRACE("(%p, %s, %08x, %p)\n", ppAssemblyNameObj,
723 debugstr_w(szAssemblyName), dwFlags, pvReserved);
725 if (!ppAssemblyNameObj)
728 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
729 (!szAssemblyName || !*szAssemblyName))
732 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
734 return E_OUTOFMEMORY;
736 name->IAssemblyName_iface.lpVtbl = &AssemblyNameVtbl;
739 hr = parse_display_name(name, szAssemblyName);
742 HeapFree(GetProcessHeap(), 0, name);
746 *ppAssemblyNameObj = &name->IAssemblyName_iface;