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 const IAssemblyNameVtbl *lpIAssemblyNameVtbl;
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);
79 if (IsEqualIID(riid, &IID_IUnknown) ||
80 IsEqualIID(riid, &IID_IAssemblyName))
82 IUnknown_AddRef(iface);
87 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
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);
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);
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);
121 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
126 FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
130 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
135 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
137 TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
139 *((LPWSTR)pvProperty) = '\0';
143 case ASM_NAME_NULL_PUBLIC_KEY:
144 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
149 case ASM_NAME_NULL_CUSTOM:
156 lstrcpyW(pvProperty, name->name);
157 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
161 case ASM_NAME_MAJOR_VERSION:
163 *((WORD *)pvProperty) = name->version[0];
164 if (name->versize >= 1)
165 *pcbProperty = sizeof(WORD);
168 case ASM_NAME_MINOR_VERSION:
170 *((WORD *)pvProperty) = name->version[1];
171 if (name->versize >= 2)
172 *pcbProperty = sizeof(WORD);
175 case ASM_NAME_BUILD_NUMBER:
177 *((WORD *)pvProperty) = name->version[2];
178 if (name->versize >= 3)
179 *pcbProperty = sizeof(WORD);
182 case ASM_NAME_REVISION_NUMBER:
184 *((WORD *)pvProperty) = name->version[3];
185 if (name->versize >= 4)
186 *pcbProperty = sizeof(WORD);
189 case ASM_NAME_CULTURE:
193 lstrcpyW(pvProperty, name->culture);
194 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
198 case ASM_NAME_PUBLIC_KEY_TOKEN:
202 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
203 *pcbProperty = sizeof(DWORD) * 2;
215 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
217 FIXME("(%p) stub!\n", iface);
221 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
222 LPOLESTR szDisplayName,
223 LPDWORD pccDisplayName,
224 DWORD dwDisplayFlags)
226 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
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;
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};
261 wsprintfW(verstr, spec, name->version[0]);
263 for (i = 1; i < name->versize; i++)
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)
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],
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;
344 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
346 IUnknown *pUnkReserved1,
347 IUnknown *pUnkReserved2,
348 LPCOLESTR szReserved,
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);
362 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
366 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
368 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
377 lstrcpyW(pwzName, name->name);
378 *lpcwBuffer = lstrlenW(pwzName) + 1;
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);
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];
403 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
404 IAssemblyName *pName,
407 FIXME("(%p, %p, %d) stub!\n", iface, pName, dwCmpFlags);
411 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
412 IAssemblyName **pName)
414 FIXME("(%p, %p) stub!\n", iface, pName);
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);
442 return E_OUTOFMEMORY;
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);
460 *len = lstrlenW(name->path) + 1;
462 if (*len <= buffer_size)
463 lstrcpyW(buf, name->path);
465 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
470 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
475 for (i = 0, beg = version; i < 4; i++)
480 end = strchrW(beg, '.');
482 if (end) *end = '\0';
483 name->version[i] = atolW(beg);
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);
502 name->culture = strdupW(empty);
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')
518 if(c >= 'A' && c <= 'F')
520 if(c >= 'a' && c <= 'f')
525 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
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;
548 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
558 name->displayname = strdupW(szAssemblyName);
559 if (!name->displayname)
560 return E_OUTOFMEMORY;
562 str = strdupW(szAssemblyName);
570 ptr = strchrW(str, ',');
571 if (ptr) *ptr = '\0';
573 /* no ',' but ' ' only */
574 if( !ptr && strchrW(str, ' ') )
576 hr = FUSION_E_INVALID_NAME;
580 name->name = strdupW(str);
593 ptr = strchrW(str, '=');
596 hr = FUSION_E_INVALID_NAME;
603 hr = FUSION_E_INVALID_NAME;
607 if (!(ptr2 = strstrW(ptr, separator)))
609 if (!(ptr2 = strchrW(ptr, '\0')))
611 hr = FUSION_E_INVALID_NAME;
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);
642 HeapFree(GetProcessHeap(), 0, save);
645 HeapFree(GetProcessHeap(), 0, name->displayname);
646 HeapFree(GetProcessHeap(), 0, name->name);
651 /******************************************************************
652 * CreateAssemblyNameObject (FUSION.@)
654 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
655 LPCWSTR szAssemblyName, DWORD dwFlags,
658 IAssemblyNameImpl *name;
661 TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj,
662 debugstr_w(szAssemblyName), dwFlags, pvReserved);
664 if (!ppAssemblyNameObj)
667 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
668 (!szAssemblyName || !*szAssemblyName))
671 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
673 return E_OUTOFMEMORY;
675 name->lpIAssemblyNameVtbl = &AssemblyNameVtbl;
678 hr = parse_display_name(name, szAssemblyName);
681 HeapFree(GetProcessHeap(), 0, name);
685 *ppAssemblyNameObj = (IAssemblyName *)name;