ntdll: Avoid potential infinite loop.
[wine/wine-kai.git] / dlls / fusion / asmname.c
blob81a5b82ebbfd028e2e753d860ae865ce53da4b3e
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>
23 #define COBJMACROS
24 #define INITGUID
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "guiddef.h"
31 #include "fusion.h"
32 #include "corerror.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(fusion);
39 static inline LPWSTR strdupW(LPCWSTR src)
41 LPWSTR dest;
43 if (!src)
44 return NULL;
46 dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR));
47 if (dest)
48 lstrcpyW(dest, src);
50 return dest;
53 typedef struct {
54 const IAssemblyNameVtbl *lpIAssemblyNameVtbl;
56 LPWSTR displayname;
57 LPWSTR name;
58 LPWSTR culture;
60 BYTE version[4];
61 DWORD versize;
63 BYTE pubkey[8];
64 BOOL haspubkey;
66 LONG ref;
67 } IAssemblyNameImpl;
69 static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface,
70 REFIID riid, LPVOID *ppobj)
72 IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
74 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
76 *ppobj = NULL;
78 if (IsEqualIID(riid, &IID_IUnknown) ||
79 IsEqualIID(riid, &IID_IAssemblyName))
81 IUnknown_AddRef(iface);
82 *ppobj = This;
83 return S_OK;
86 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
87 return E_NOINTERFACE;
90 static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface)
92 IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
93 ULONG refCount = InterlockedIncrement(&This->ref);
95 TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
97 return refCount;
100 static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface)
102 IAssemblyNameImpl *This = (IAssemblyNameImpl *)iface;
103 ULONG refCount = InterlockedDecrement(&This->ref);
105 TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
107 if (!refCount)
109 HeapFree(GetProcessHeap(), 0, This->displayname);
110 HeapFree(GetProcessHeap(), 0, This->name);
111 HeapFree(GetProcessHeap(), 0, This->culture);
112 HeapFree(GetProcessHeap(), 0, This);
115 return refCount;
118 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
119 DWORD PropertyId,
120 LPVOID pvProperty,
121 DWORD cbProperty)
123 FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
124 return E_NOTIMPL;
127 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
128 DWORD PropertyId,
129 LPVOID pvProperty,
130 LPDWORD pcbProperty)
132 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
134 TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
136 *((LPWSTR)pvProperty) = '\0';
138 switch (PropertyId)
140 case ASM_NAME_NULL_PUBLIC_KEY:
141 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
142 if (name->haspubkey)
143 return S_OK;
144 return S_FALSE;
146 case ASM_NAME_NULL_CUSTOM:
147 return S_OK;
149 case ASM_NAME_NAME:
150 *pcbProperty = 0;
151 if (name->name)
153 lstrcpyW((LPWSTR)pvProperty, name->name);
154 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
156 break;
158 case ASM_NAME_MAJOR_VERSION:
159 *pcbProperty = 0;
160 *((LPDWORD)pvProperty) = name->version[0];
161 if (name->versize >= 1)
162 *pcbProperty = sizeof(WORD);
163 break;
165 case ASM_NAME_MINOR_VERSION:
166 *pcbProperty = 0;
167 *((LPDWORD)pvProperty) = name->version[1];
168 if (name->versize >= 2)
169 *pcbProperty = sizeof(WORD);
170 break;
172 case ASM_NAME_BUILD_NUMBER:
173 *pcbProperty = 0;
174 *((LPDWORD)pvProperty) = name->version[2];
175 if (name->versize >= 3)
176 *pcbProperty = sizeof(WORD);
177 break;
179 case ASM_NAME_REVISION_NUMBER:
180 *pcbProperty = 0;
181 *((LPDWORD)pvProperty) = name->version[3];
182 if (name->versize >= 4)
183 *pcbProperty = sizeof(WORD);
184 break;
186 case ASM_NAME_CULTURE:
187 *pcbProperty = 0;
188 if (name->culture)
190 lstrcpyW((LPWSTR)pvProperty, name->culture);
191 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
193 break;
195 case ASM_NAME_PUBLIC_KEY_TOKEN:
196 *pcbProperty = 0;
197 if (name->haspubkey)
199 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
200 *pcbProperty = sizeof(DWORD) * 2;
202 break;
204 default:
205 *pcbProperty = 0;
206 break;
209 return S_OK;
212 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
214 FIXME("(%p) stub!\n", iface);
215 return E_NOTIMPL;
218 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
219 LPOLESTR szDisplayName,
220 LPDWORD pccDisplayName,
221 DWORD dwDisplayFlags)
223 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
225 TRACE("(%p, %s, %p, %d)\n", iface, debugstr_w(szDisplayName),
226 pccDisplayName, dwDisplayFlags);
228 if (!name->displayname || !*name->displayname)
229 return FUSION_E_INVALID_NAME;
231 lstrcpyW(szDisplayName, name->displayname);
232 *pccDisplayName = lstrlenW(szDisplayName) + 1;
234 return S_OK;
237 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
238 REFIID refIID,
239 IUnknown *pUnkReserved1,
240 IUnknown *pUnkReserved2,
241 LPCOLESTR szReserved,
242 LONGLONG llReserved,
243 LPVOID pvReserved,
244 DWORD cbReserved,
245 LPVOID *ppReserved)
247 TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface,
248 debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
249 debugstr_w(szReserved), (DWORD)(llReserved >> 32), (DWORD)llReserved,
250 pvReserved, cbReserved, ppReserved);
252 return E_NOTIMPL;
255 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
256 LPDWORD lpcwBuffer,
257 WCHAR *pwzName)
259 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
261 TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
263 if (!name->name)
265 *pwzName = '\0';
266 *lpcwBuffer = 0;
267 return S_OK;
270 lstrcpyW(pwzName, name->name);
271 *lpcwBuffer = lstrlenW(pwzName) + 1;
273 return S_OK;
276 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
277 LPDWORD pdwVersionHi,
278 LPDWORD pdwVersionLow)
280 IAssemblyNameImpl *name = (IAssemblyNameImpl *)iface;
282 TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
284 *pdwVersionHi = 0;
285 *pdwVersionLow = 0;
287 if (name->versize != 4)
288 return FUSION_E_INVALID_NAME;
290 *pdwVersionHi = (name->version[0] << 16) + name->version[1];
291 *pdwVersionLow = (name->version[2] << 16) + name->version[3];
293 return S_OK;
296 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
297 IAssemblyName *pName,
298 DWORD dwCmpFlags)
300 FIXME("(%p, %p, %d) stub!\n", iface, pName, dwCmpFlags);
301 return E_NOTIMPL;
304 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
305 IAssemblyName **pName)
307 FIXME("(%p, %p) stub!\n", iface, pName);
308 return E_NOTIMPL;
311 static const IAssemblyNameVtbl AssemblyNameVtbl = {
312 IAssemblyNameImpl_QueryInterface,
313 IAssemblyNameImpl_AddRef,
314 IAssemblyNameImpl_Release,
315 IAssemblyNameImpl_SetProperty,
316 IAssemblyNameImpl_GetProperty,
317 IAssemblyNameImpl_Finalize,
318 IAssemblyNameImpl_GetDisplayName,
319 IAssemblyNameImpl_Reserved,
320 IAssemblyNameImpl_GetName,
321 IAssemblyNameImpl_GetVersion,
322 IAssemblyNameImpl_IsEqual,
323 IAssemblyNameImpl_Clone
326 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
328 LPWSTR beg, end;
329 int i;
331 for (i = 0, beg = version; i < 4; i++)
333 if (!*beg)
334 return S_OK;
336 end = strchrW(beg, '.');
338 if (end) *end = '\0';
339 name->version[i] = atolW(beg);
340 name->versize++;
342 if (!end && i < 3)
343 return S_OK;
345 beg = end + 1;
348 return S_OK;
351 static HRESULT parse_culture(IAssemblyNameImpl *name, LPWSTR culture)
353 static const WCHAR empty[] = {0};
355 if (lstrlenW(culture) == 2)
356 name->culture = strdupW(culture);
357 else
358 name->culture = strdupW(empty);
360 return S_OK;
363 #define CHARS_PER_PUBKEY 16
365 static BOOL is_hex(WCHAR c)
367 return ((c >= 'a' && c <= 'f') ||
368 (c >= 'A' && c <= 'F') ||
369 (c >= '0' && c <= '9'));
372 static BYTE hextobyte(WCHAR c)
374 if(c >= '0' && c <= '9')
375 return c - '0';
376 if(c >= 'A' && c <= 'F')
377 return c - 'A' + 10;
378 if(c >= 'a' && c <= 'f')
379 return c - 'a' + 10;
380 return 0;
383 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPWSTR pubkey)
385 int i;
386 BYTE val;
388 if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
389 return FUSION_E_INVALID_NAME;
391 for (i = 0; i < CHARS_PER_PUBKEY; i++)
392 if (!is_hex(pubkey[i]))
393 return FUSION_E_INVALID_NAME;
395 name->haspubkey = TRUE;
397 for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
399 val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
400 name->pubkey[i / 2] = val;
403 return S_OK;
406 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
408 LPWSTR str, save;
409 LPWSTR ptr, ptr2;
410 HRESULT hr = S_OK;
411 BOOL done = FALSE;
413 static const WCHAR separator[] = {',',' ',0};
414 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
415 static const WCHAR culture[] = {'C','u','l','t','u','r','e',0};
416 static const WCHAR pubkey[] =
417 {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
419 if (!szAssemblyName)
420 return S_OK;
422 name->displayname = strdupW(szAssemblyName);
423 if (!name->displayname)
424 return E_OUTOFMEMORY;
426 str = strdupW(szAssemblyName);
427 save = str;
428 if (!str)
429 return E_OUTOFMEMORY;
431 ptr = strstrW(str, separator);
432 if (ptr) *ptr = '\0';
433 name->name = strdupW(str);
434 if (!name->name)
435 return E_OUTOFMEMORY;
437 if (!ptr)
438 goto done;
440 str = ptr + 2;
441 while (!done)
443 ptr = strchrW(str, '=');
444 if (!ptr)
446 hr = FUSION_E_INVALID_NAME;
447 goto done;
450 *(ptr++) = '\0';
451 if (!*ptr)
453 hr = FUSION_E_INVALID_NAME;
454 goto done;
457 if (!(ptr2 = strstrW(ptr, separator)))
459 if (!(ptr2 = strchrW(ptr, '\0')))
461 hr = FUSION_E_INVALID_NAME;
462 goto done;
465 done = TRUE;
468 *ptr2 = '\0';
470 if (!lstrcmpW(str, version))
471 hr = parse_version(name, ptr);
472 else if (!lstrcmpW(str, culture))
473 hr = parse_culture(name, ptr);
474 else if (!lstrcmpW(str, pubkey))
475 hr = parse_pubkey(name, ptr);
477 if (FAILED(hr))
478 goto done;
480 str = ptr2 + 1;
483 done:
484 HeapFree(GetProcessHeap(), 0, save);
485 return hr;
488 /******************************************************************
489 * CreateAssemblyNameObject (FUSION.@)
491 HRESULT WINAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj,
492 LPCWSTR szAssemblyName, DWORD dwFlags,
493 LPVOID pvReserved)
495 IAssemblyNameImpl *name;
496 HRESULT hr;
498 TRACE("(%p, %s, %08x, %p) stub!\n", ppAssemblyNameObj,
499 debugstr_w(szAssemblyName), dwFlags, pvReserved);
501 if (!ppAssemblyNameObj)
502 return E_INVALIDARG;
504 if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
505 (!szAssemblyName || !*szAssemblyName))
506 return E_INVALIDARG;
508 name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAssemblyNameImpl));
509 if (!name)
510 return E_OUTOFMEMORY;
512 name->lpIAssemblyNameVtbl = &AssemblyNameVtbl;
513 name->ref = 1;
515 hr = parse_display_name(name, szAssemblyName);
516 if (FAILED(hr))
518 HeapFree(GetProcessHeap(), 0, name);
519 return hr;
522 *ppAssemblyNameObj = (IAssemblyName *)name;
524 return S_OK;