Release 1.3.7.
[wine/gsoc-2012-control.git] / dlls / fusion / asmname.c
blob34f05559ae443824381e482fc0ff085e6e3572e5
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);
117 return refCount;
120 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
121 DWORD PropertyId,
122 LPVOID pvProperty,
123 DWORD cbProperty)
125 FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
126 return E_NOTIMPL;
129 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
130 DWORD PropertyId,
131 LPVOID pvProperty,
132 LPDWORD pcbProperty)
134 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
136 TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
138 *((LPWSTR)pvProperty) = '\0';
140 switch (PropertyId)
142 case ASM_NAME_NULL_PUBLIC_KEY:
143 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
144 if (name->haspubkey)
145 return S_OK;
146 return S_FALSE;
148 case ASM_NAME_NULL_CUSTOM:
149 return S_OK;
151 case ASM_NAME_NAME:
152 *pcbProperty = 0;
153 if (name->name)
155 lstrcpyW(pvProperty, name->name);
156 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
158 break;
160 case ASM_NAME_MAJOR_VERSION:
161 *pcbProperty = 0;
162 *((WORD *)pvProperty) = name->version[0];
163 if (name->versize >= 1)
164 *pcbProperty = sizeof(WORD);
165 break;
167 case ASM_NAME_MINOR_VERSION:
168 *pcbProperty = 0;
169 *((WORD *)pvProperty) = name->version[1];
170 if (name->versize >= 2)
171 *pcbProperty = sizeof(WORD);
172 break;
174 case ASM_NAME_BUILD_NUMBER:
175 *pcbProperty = 0;
176 *((WORD *)pvProperty) = name->version[2];
177 if (name->versize >= 3)
178 *pcbProperty = sizeof(WORD);
179 break;
181 case ASM_NAME_REVISION_NUMBER:
182 *pcbProperty = 0;
183 *((WORD *)pvProperty) = name->version[3];
184 if (name->versize >= 4)
185 *pcbProperty = sizeof(WORD);
186 break;
188 case ASM_NAME_CULTURE:
189 *pcbProperty = 0;
190 if (name->culture)
192 lstrcpyW(pvProperty, name->culture);
193 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
195 break;
197 case ASM_NAME_PUBLIC_KEY_TOKEN:
198 *pcbProperty = 0;
199 if (name->haspubkey)
201 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
202 *pcbProperty = sizeof(DWORD) * 2;
204 break;
206 default:
207 *pcbProperty = 0;
208 break;
211 return S_OK;
214 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
216 FIXME("(%p) stub!\n", iface);
217 return E_NOTIMPL;
220 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
221 LPOLESTR szDisplayName,
222 LPDWORD pccDisplayName,
223 DWORD dwDisplayFlags)
225 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
226 WCHAR verstr[30];
227 DWORD size;
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;
245 return S_OK;
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};
258 int i;
260 wsprintfW(verstr, spec, name->version[0]);
262 for (i = 1; i < name->versize; i++)
264 WCHAR value[6];
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)
289 return S_FALSE;
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],
325 name->pubkey[7]);
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;
340 return S_OK;
343 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
344 REFIID refIID,
345 IUnknown *pUnkReserved1,
346 IUnknown *pUnkReserved2,
347 LPCOLESTR szReserved,
348 LONGLONG llReserved,
349 LPVOID pvReserved,
350 DWORD cbReserved,
351 LPVOID *ppReserved)
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);
358 return E_NOTIMPL;
361 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
362 LPDWORD lpcwBuffer,
363 WCHAR *pwzName)
365 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
367 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
369 if (!name->name)
371 *pwzName = '\0';
372 *lpcwBuffer = 0;
373 return S_OK;
376 lstrcpyW(pwzName, name->name);
377 *lpcwBuffer = lstrlenW(pwzName) + 1;
379 return S_OK;
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);
390 *pdwVersionHi = 0;
391 *pdwVersionLow = 0;
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];
399 return S_OK;
402 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
403 IAssemblyName *pName,
404 DWORD dwCmpFlags)
406 FIXME("(%p, %p, %d) stub!\n", iface, pName, dwCmpFlags);
407 return E_NOTIMPL;
410 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
411 IAssemblyName **pName)
413 FIXME("(%p, %p) stub!\n", iface, pName);
414 return E_NOTIMPL;
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);
440 if (!name->path)
441 return E_OUTOFMEMORY;
443 return S_OK;
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);
453 if (!name->path)
454 return S_OK;
456 if (!buf)
457 buffer_size = 0;
459 *len = lstrlenW(name->path) + 1;
461 if (*len <= buffer_size)
462 lstrcpyW(buf, name->path);
463 else
464 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
466 return S_OK;
469 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
471 LPWSTR beg, end;
472 int i;
474 for (i = 0, beg = version; i < 4; i++)
476 if (!*beg)
477 return S_OK;
479 end = strchrW(beg, '.');
481 if (end) *end = '\0';
482 name->version[i] = atolW(beg);
483 name->versize++;
485 if (!end && i < 3)
486 return S_OK;
488 beg = end + 1;
491 return S_OK;
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);
500 else
501 name->culture = strdupW(empty);
503 return S_OK;
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')
516 return c - '0';
517 if(c >= 'A' && c <= 'F')
518 return c - 'A' + 10;
519 if(c >= 'a' && c <= 'f')
520 return c - 'a' + 10;
521 return 0;
524 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
526 int i;
527 BYTE val;
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;
544 return S_OK;
547 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
549 LPWSTR str, save;
550 LPWSTR ptr, ptr2;
551 HRESULT hr = S_OK;
552 BOOL done = FALSE;
554 if (!szAssemblyName)
555 return S_OK;
557 name->displayname = strdupW(szAssemblyName);
558 if (!name->displayname)
559 return E_OUTOFMEMORY;
561 str = strdupW(szAssemblyName);
562 save = str;
563 if (!str)
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;
573 goto done;
576 name->name = strdupW(str);
577 if (!name->name)
578 return E_OUTOFMEMORY;
580 if (!ptr)
581 goto done;
583 str = ptr + 2;
584 while (!done)
586 ptr = strchrW(str, '=');
587 if (!ptr)
589 hr = FUSION_E_INVALID_NAME;
590 goto done;
593 *(ptr++) = '\0';
594 if (!*ptr)
596 hr = FUSION_E_INVALID_NAME;
597 goto done;
600 if (!(ptr2 = strstrW(ptr, separator)))
602 if (!(ptr2 = strchrW(ptr, '\0')))
604 hr = FUSION_E_INVALID_NAME;
605 goto done;
608 done = TRUE;
611 *ptr2 = '\0';
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);
624 hr = S_OK;
627 if (FAILED(hr))
628 goto done;
630 str = ptr2 + 1;
633 done:
634 HeapFree(GetProcessHeap(), 0, save);
635 if (FAILED(hr))
637 HeapFree(GetProcessHeap(), 0, name->displayname);
638 HeapFree(GetProcessHeap(), 0, name->name);
640 return hr;
643 /******************************************************************
644 * CreateAssemblyNameObject (FUSION.@)
646 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
647 LPCWSTR szAssemblyName, DWORD dwFlags,
648 LPVOID pvReserved)
650 IAssemblyNameImpl *name;
651 HRESULT hr;
653 TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj,
654 debugstr_w(szAssemblyName), dwFlags, pvReserved);
656 if (!ppAssemblyNameObj)
657 return E_INVALIDARG;
659 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
660 (!szAssemblyName || !*szAssemblyName))
661 return E_INVALIDARG;
663 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
664 if (!name)
665 return E_OUTOFMEMORY;
667 name->lpIAssemblyNameVtbl = &AssemblyNameVtbl;
668 name->ref = 1;
670 hr = parse_display_name(name, szAssemblyName);
671 if (FAILED(hr))
673 HeapFree(GetProcessHeap(), 0, name);
674 return hr;
677 *ppAssemblyNameObj = (IAssemblyName *)name;
679 return S_OK;