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);
120 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
125 FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
129 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
134 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
136 TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
138 *((LPWSTR)pvProperty) = '\0';
142 case ASM_NAME_NULL_PUBLIC_KEY:
143 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
148 case ASM_NAME_NULL_CUSTOM:
155 lstrcpyW(pvProperty, name->name);
156 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
160 case ASM_NAME_MAJOR_VERSION:
162 *((WORD *)pvProperty) = name->version[0];
163 if (name->versize >= 1)
164 *pcbProperty = sizeof(WORD);
167 case ASM_NAME_MINOR_VERSION:
169 *((WORD *)pvProperty) = name->version[1];
170 if (name->versize >= 2)
171 *pcbProperty = sizeof(WORD);
174 case ASM_NAME_BUILD_NUMBER:
176 *((WORD *)pvProperty) = name->version[2];
177 if (name->versize >= 3)
178 *pcbProperty = sizeof(WORD);
181 case ASM_NAME_REVISION_NUMBER:
183 *((WORD *)pvProperty) = name->version[3];
184 if (name->versize >= 4)
185 *pcbProperty = sizeof(WORD);
188 case ASM_NAME_CULTURE:
192 lstrcpyW(pvProperty, name->culture);
193 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
197 case ASM_NAME_PUBLIC_KEY_TOKEN:
201 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
202 *pcbProperty = sizeof(DWORD) * 2;
214 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
216 FIXME("(%p) stub!\n", iface);
220 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
221 LPOLESTR szDisplayName,
222 LPDWORD pccDisplayName,
223 DWORD dwDisplayFlags)
225 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
228 LPWSTR cultureval = 0;
230 static const WCHAR equals[] = {'=',0};
232 TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
233 pccDisplayName, dwDisplayFlags);
235 if (dwDisplayFlags == 0)
237 if (!name->displayname || !*name->displayname)
238 return FUSION_E_INVALID_NAME;
240 size = min(*pccDisplayName, lstrlenW(name->displayname) + 1);
242 lstrcpynW(szDisplayName, name->displayname, size);
243 *pccDisplayName = size;
248 if (!name->name || !*name->name)
249 return FUSION_E_INVALID_NAME;
251 /* Verify buffer size is sufficient */
252 size = lstrlenW(name->name) + 1;
254 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
256 static const WCHAR spec[] = {'%','d',0};
257 static const WCHAR period[] = {'.',0};
260 wsprintfW(verstr, spec, name->version[0]);
262 for (i = 1; i < name->versize; i++)
265 wsprintfW(value, spec, name->version[i]);
267 lstrcatW(verstr, period);
268 lstrcatW(verstr, value);
271 size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr);
274 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
276 static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0};
278 cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral;
279 size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval);
282 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
283 size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY;
285 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
286 size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch);
288 if (size > *pccDisplayName)
291 /* Construct the string */
292 lstrcpyW(szDisplayName, name->name);
294 if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
296 lstrcatW(szDisplayName, separator);
298 lstrcatW(szDisplayName, version);
299 lstrcatW(szDisplayName, equals);
300 lstrcatW(szDisplayName, verstr);
303 if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
305 lstrcatW(szDisplayName, separator);
307 lstrcatW(szDisplayName, culture);
308 lstrcatW(szDisplayName, equals);
309 lstrcatW(szDisplayName, cultureval);
312 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
314 WCHAR pkt[CHARS_PER_PUBKEY + 1];
315 static const WCHAR spec[] = {'%','0','x','%','0','x','%','0','x',
316 '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0};
318 lstrcatW(szDisplayName, separator);
320 lstrcatW(szDisplayName, pubkey);
321 lstrcatW(szDisplayName, equals);
323 wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2],
324 name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6],
327 lstrcatW(szDisplayName, pkt);
330 if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
332 lstrcatW(szDisplayName, separator);
334 lstrcatW(szDisplayName, procarch);
335 lstrcatW(szDisplayName, equals);
336 lstrcatW(szDisplayName, name->procarch);
339 *pccDisplayName = size;
343 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
345 IUnknown *pUnkReserved1,
346 IUnknown *pUnkReserved2,
347 LPCOLESTR szReserved,
353 TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface,
354 debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
355 debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved,
356 pvReserved, cbReserved, ppReserved);
361 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
365 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
367 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
376 lstrcpyW(pwzName, name->name);
377 *lpcwBuffer = lstrlenW(pwzName) + 1;
382 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
383 LPDWORD pdwVersionHi,
384 LPDWORD pdwVersionLow)
386 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
388 TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
393 if (name->versize != 4)
394 return FUSION_E_INVALID_NAME;
396 *pdwVersionHi = (name->version[0] << 16) + name->version[1];
397 *pdwVersionLow = (name->version[2] << 16) + name->version[3];
402 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
403 IAssemblyName *pName,
406 FIXME("(%p, %p, %d) stub!\n", iface, pName, dwCmpFlags);
410 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
411 IAssemblyName **pName)
413 FIXME("(%p, %p) stub!\n", iface, pName);
417 static const IAssemblyNameVtbl AssemblyNameVtbl = {
418 IAssemblyNameImpl_QueryInterface,
419 IAssemblyNameImpl_AddRef,
420 IAssemblyNameImpl_Release,
421 IAssemblyNameImpl_SetProperty,
422 IAssemblyNameImpl_GetProperty,
423 IAssemblyNameImpl_Finalize,
424 IAssemblyNameImpl_GetDisplayName,
425 IAssemblyNameImpl_Reserved,
426 IAssemblyNameImpl_GetName,
427 IAssemblyNameImpl_GetVersion,
428 IAssemblyNameImpl_IsEqual,
429 IAssemblyNameImpl_Clone
432 /* Internal methods */
433 HRESULT IAssemblyName_SetPath(IAssemblyName *iface, LPCWSTR path)
435 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
437 assert(name->lpIAssemblyNameVtbl == &AssemblyNameVtbl);
439 name->path = strdupW(path);
441 return E_OUTOFMEMORY;
446 HRESULT IAssemblyName_GetPath(IAssemblyName *iface, LPWSTR buf, ULONG *len)
448 ULONG buffer_size = *len;
449 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
451 assert(name->lpIAssemblyNameVtbl == &AssemblyNameVtbl);
459 *len = lstrlenW(name->path) + 1;
461 if (*len <= buffer_size)
462 lstrcpyW(buf, name->path);
464 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
469 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
474 for (i = 0, beg = version; i < 4; i++)
479 end = strchrW(beg, '.');
481 if (end) *end = '\0';
482 name->version[i] = atolW(beg);
494 static HRESULT parse_culture(IAssemblyNameImpl *name, LPCWSTR culture)
496 static const WCHAR empty[] = {0};
498 if (lstrlenW(culture) == 2)
499 name->culture = strdupW(culture);
501 name->culture = strdupW(empty);
506 static BOOL is_hex(WCHAR c)
508 return ((c >= 'a' && c <= 'f') ||
509 (c >= 'A' && c <= 'F') ||
510 (c >= '0' && c <= '9'));
513 static BYTE hextobyte(WCHAR c)
515 if(c >= '0' && c <= '9')
517 if(c >= 'A' && c <= 'F')
519 if(c >= 'a' && c <= 'f')
524 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
529 if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
530 return FUSION_E_INVALID_NAME;
532 for (i = 0; i < CHARS_PER_PUBKEY; i++)
533 if (!is_hex(pubkey[i]))
534 return FUSION_E_INVALID_NAME;
536 name->haspubkey = TRUE;
538 for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
540 val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
541 name->pubkey[i / 2] = val;
547 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
557 name->displayname = strdupW(szAssemblyName);
558 if (!name->displayname)
559 return E_OUTOFMEMORY;
561 str = strdupW(szAssemblyName);
564 return E_OUTOFMEMORY;
566 ptr = strchrW(str, ',');
567 if (ptr) *ptr = '\0';
569 /* no ',' but ' ' only */
570 if( !ptr && strchrW(str, ' ') )
572 hr = FUSION_E_INVALID_NAME;
576 name->name = strdupW(str);
578 return E_OUTOFMEMORY;
586 ptr = strchrW(str, '=');
589 hr = FUSION_E_INVALID_NAME;
596 hr = FUSION_E_INVALID_NAME;
600 if (!(ptr2 = strstrW(ptr, separator)))
602 if (!(ptr2 = strchrW(ptr, '\0')))
604 hr = FUSION_E_INVALID_NAME;
613 while (*str == ' ') str++;
615 if (!lstrcmpW(str, version))
616 hr = parse_version(name, ptr);
617 else if (!lstrcmpW(str, culture))
618 hr = parse_culture(name, ptr);
619 else if (!lstrcmpW(str, pubkey))
620 hr = parse_pubkey(name, ptr);
621 else if (!lstrcmpW(str, procarch))
623 name->procarch = strdupW(ptr);
634 HeapFree(GetProcessHeap(), 0, save);
637 HeapFree(GetProcessHeap(), 0, name->displayname);
638 HeapFree(GetProcessHeap(), 0, name->name);
643 /******************************************************************
644 * CreateAssemblyNameObject (FUSION.@)
646 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
647 LPCWSTR szAssemblyName, DWORD dwFlags,
650 IAssemblyNameImpl *name;
653 TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj,
654 debugstr_w(szAssemblyName), dwFlags, pvReserved);
656 if (!ppAssemblyNameObj)
659 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
660 (!szAssemblyName || !*szAssemblyName))
663 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
665 return E_OUTOFMEMORY;
667 name->lpIAssemblyNameVtbl = &AssemblyNameVtbl;
670 hr = parse_display_name(name, szAssemblyName);
673 HeapFree(GetProcessHeap(), 0, name);
677 *ppAssemblyNameObj = (IAssemblyName *)name;