xref: /reactos/dll/win32/fusion/asmname.c (revision 88179a5d)
1 /*
2  * IAssemblyName implementation
3  *
4  * Copyright 2008 James Hawkins
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include <stdarg.h>
22 #include <assert.h>
23 
24 #define COBJMACROS
25 #define INITGUID
26 #ifdef __REACTOS__
27 #define WIN32_NO_STATUS
28 #endif
29 
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "ole2.h"
34 #include "guiddef.h"
35 #include "fusion.h"
36 #include "corerror.h"
37 #include "strsafe.h"
38 
39 #include "wine/debug.h"
40 #include "fusionpriv.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(fusion);
43 
44 typedef struct {
45     IAssemblyName IAssemblyName_iface;
46 
47     LPWSTR path;
48 
49     LPWSTR displayname;
50     LPWSTR name;
51     LPWSTR culture;
52     LPWSTR procarch;
53 
54     WORD version[4];
55     DWORD versize;
56 
57     BYTE pubkey[8];
58     BOOL haspubkey;
59 
60     PEKIND pekind;
61 
62     LONG ref;
63 } IAssemblyNameImpl;
64 
65 static const WCHAR separator[] = {',',' ',0};
66 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
67 static const WCHAR culture[] = {'C','u','l','t','u','r','e',0};
68 static const WCHAR pubkey[] =
69     {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
70 static const WCHAR procarch[] = {'p','r','o','c','e','s','s','o','r',
71     'A','r','c','h','i','t','e','c','t','u','r','e',0};
72 
73 #define CHARS_PER_PUBKEY 16
74 
impl_from_IAssemblyName(IAssemblyName * iface)75 static inline IAssemblyNameImpl *impl_from_IAssemblyName(IAssemblyName *iface)
76 {
77     return CONTAINING_RECORD(iface, IAssemblyNameImpl, IAssemblyName_iface);
78 }
79 
IAssemblyNameImpl_QueryInterface(IAssemblyName * iface,REFIID riid,LPVOID * ppobj)80 static HRESULT WINAPI IAssemblyNameImpl_QueryInterface(IAssemblyName *iface,
81                                                        REFIID riid, LPVOID *ppobj)
82 {
83     IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
84 
85     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
86 
87     *ppobj = NULL;
88 
89     if (IsEqualIID(riid, &IID_IUnknown) ||
90         IsEqualIID(riid, &IID_IAssemblyName))
91     {
92         IAssemblyName_AddRef(iface);
93         *ppobj = &This->IAssemblyName_iface;
94         return S_OK;
95     }
96 
97     WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ppobj);
98     return E_NOINTERFACE;
99 }
100 
IAssemblyNameImpl_AddRef(IAssemblyName * iface)101 static ULONG WINAPI IAssemblyNameImpl_AddRef(IAssemblyName *iface)
102 {
103     IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
104     ULONG refCount = InterlockedIncrement(&This->ref);
105 
106     TRACE("(%p)->(ref before = %u)\n", This, refCount - 1);
107 
108     return refCount;
109 }
110 
IAssemblyNameImpl_Release(IAssemblyName * iface)111 static ULONG WINAPI IAssemblyNameImpl_Release(IAssemblyName *iface)
112 {
113     IAssemblyNameImpl *This = impl_from_IAssemblyName(iface);
114     ULONG refCount = InterlockedDecrement(&This->ref);
115 
116     TRACE("(%p)->(ref before = %u)\n", This, refCount + 1);
117 
118     if (!refCount)
119     {
120         heap_free(This->path);
121         heap_free(This->displayname);
122         heap_free(This->name);
123         heap_free(This->culture);
124         heap_free(This->procarch);
125         heap_free(This);
126     }
127 
128     return refCount;
129 }
130 
IAssemblyNameImpl_SetProperty(IAssemblyName * iface,DWORD PropertyId,LPVOID pvProperty,DWORD cbProperty)131 static HRESULT WINAPI IAssemblyNameImpl_SetProperty(IAssemblyName *iface,
132                                                     DWORD PropertyId,
133                                                     LPVOID pvProperty,
134                                                     DWORD cbProperty)
135 {
136     FIXME("(%p, %d, %p, %d) stub!\n", iface, PropertyId, pvProperty, cbProperty);
137     return E_NOTIMPL;
138 }
139 
IAssemblyNameImpl_GetProperty(IAssemblyName * iface,DWORD PropertyId,LPVOID pvProperty,LPDWORD pcbProperty)140 static HRESULT WINAPI IAssemblyNameImpl_GetProperty(IAssemblyName *iface,
141                                                     DWORD PropertyId,
142                                                     LPVOID pvProperty,
143                                                     LPDWORD pcbProperty)
144 {
145     IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
146     DWORD size;
147 
148     TRACE("(%p, %d, %p, %p)\n", iface, PropertyId, pvProperty, pcbProperty);
149 
150     size = *pcbProperty;
151     switch (PropertyId)
152     {
153         case ASM_NAME_NULL_PUBLIC_KEY:
154         case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
155             if (name->haspubkey)
156                 return S_OK;
157             return S_FALSE;
158 
159         case ASM_NAME_NULL_CUSTOM:
160             return S_OK;
161 
162         case ASM_NAME_NAME:
163             *pcbProperty = 0;
164             if (name->name)
165             {
166                 *pcbProperty = (lstrlenW(name->name) + 1) * 2;
167                 if (size < *pcbProperty)
168                     return STRSAFE_E_INSUFFICIENT_BUFFER;
169                 lstrcpyW(pvProperty, name->name);
170             }
171             break;
172 
173         case ASM_NAME_MAJOR_VERSION:
174             *pcbProperty = 0;
175             if (name->versize >= 1)
176             {
177                 *pcbProperty = sizeof(WORD);
178                 if (size < *pcbProperty)
179                     return STRSAFE_E_INSUFFICIENT_BUFFER;
180                 *((WORD *)pvProperty) = name->version[0];
181             }
182             break;
183 
184         case ASM_NAME_MINOR_VERSION:
185             *pcbProperty = 0;
186             if (name->versize >= 2)
187             {
188                 *pcbProperty = sizeof(WORD);
189                 if (size < *pcbProperty)
190                     return STRSAFE_E_INSUFFICIENT_BUFFER;
191                 *((WORD *)pvProperty) = name->version[1];
192             }
193             break;
194 
195         case ASM_NAME_BUILD_NUMBER:
196             *pcbProperty = 0;
197             if (name->versize >= 3)
198             {
199                 *pcbProperty = sizeof(WORD);
200                 if (size < *pcbProperty)
201                     return STRSAFE_E_INSUFFICIENT_BUFFER;
202                 *((WORD *)pvProperty) = name->version[2];
203             }
204             break;
205 
206         case ASM_NAME_REVISION_NUMBER:
207             *pcbProperty = 0;
208             if (name->versize >= 4)
209             {
210                 *pcbProperty = sizeof(WORD);
211                 if (size < *pcbProperty)
212                     return STRSAFE_E_INSUFFICIENT_BUFFER;
213                 *((WORD *)pvProperty) = name->version[3];
214             }
215             break;
216 
217         case ASM_NAME_CULTURE:
218             *pcbProperty = 0;
219             if (name->culture)
220             {
221                 *pcbProperty = (lstrlenW(name->culture) + 1) * 2;
222                 if (size < *pcbProperty)
223                     return STRSAFE_E_INSUFFICIENT_BUFFER;
224                 lstrcpyW(pvProperty, name->culture);
225             }
226             break;
227 
228         case ASM_NAME_PUBLIC_KEY_TOKEN:
229             *pcbProperty = 0;
230             if (name->haspubkey)
231             {
232                 *pcbProperty = sizeof(DWORD) * 2;
233                 if (size < *pcbProperty)
234                     return STRSAFE_E_INSUFFICIENT_BUFFER;
235                 memcpy(pvProperty, name->pubkey, sizeof(DWORD) * 2);
236             }
237             break;
238 
239         case ASM_NAME_ARCHITECTURE:
240             *pcbProperty = 0;
241             if (name->pekind != peNone)
242             {
243                 *pcbProperty = sizeof(PEKIND);
244                 if (size < *pcbProperty)
245                     return STRSAFE_E_INSUFFICIENT_BUFFER;
246                 *((PEKIND *)pvProperty) = name->pekind;
247             }
248             break;
249 
250         default:
251             *pcbProperty = 0;
252             break;
253     }
254 
255     return S_OK;
256 }
257 
IAssemblyNameImpl_Finalize(IAssemblyName * iface)258 static HRESULT WINAPI IAssemblyNameImpl_Finalize(IAssemblyName *iface)
259 {
260     FIXME("(%p) stub!\n", iface);
261     return E_NOTIMPL;
262 }
263 
IAssemblyNameImpl_GetDisplayName(IAssemblyName * iface,LPOLESTR szDisplayName,LPDWORD pccDisplayName,DWORD dwDisplayFlags)264 static HRESULT WINAPI IAssemblyNameImpl_GetDisplayName(IAssemblyName *iface,
265                                                        LPOLESTR szDisplayName,
266                                                        LPDWORD pccDisplayName,
267                                                        DWORD dwDisplayFlags)
268 {
269     static const WCHAR equals[] = {'=',0};
270     IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
271     WCHAR verstr[30], *cultureval = NULL;
272     DWORD size;
273 
274     TRACE("(%p, %p, %p, %d)\n", iface, szDisplayName,
275           pccDisplayName, dwDisplayFlags);
276 
277     if (dwDisplayFlags == 0)
278     {
279         if (!name->displayname || !*name->displayname)
280             return FUSION_E_INVALID_NAME;
281 
282         size = lstrlenW(name->displayname) + 1;
283 
284         if (*pccDisplayName < size)
285         {
286             *pccDisplayName = size;
287             return E_NOT_SUFFICIENT_BUFFER;
288         }
289 
290         if (szDisplayName) lstrcpyW(szDisplayName, name->displayname);
291         *pccDisplayName = size;
292 
293         return S_OK;
294     }
295 
296     if (!name->name || !*name->name)
297         return FUSION_E_INVALID_NAME;
298 
299     /* Verify buffer size is sufficient */
300     size = lstrlenW(name->name) + 1;
301 
302     if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
303     {
304         static const WCHAR spec[] = {'%','d',0};
305         static const WCHAR period[] = {'.',0};
306         DWORD i;
307 
308         wsprintfW(verstr, spec, name->version[0]);
309 
310         for (i = 1; i < name->versize; i++)
311         {
312             WCHAR value[6];
313             wsprintfW(value, spec, name->version[i]);
314 
315             lstrcatW(verstr, period);
316             lstrcatW(verstr, value);
317         }
318 
319         size += lstrlenW(separator) + lstrlenW(version) + lstrlenW(equals) + lstrlenW(verstr);
320     }
321 
322     if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
323     {
324         static const WCHAR neutral[] = {'n','e','u','t','r','a','l', 0};
325 
326         cultureval = (lstrlenW(name->culture) == 2) ? name->culture : (LPWSTR) neutral;
327         size += lstrlenW(separator) + lstrlenW(culture) + lstrlenW(equals) + lstrlenW(cultureval);
328     }
329 
330     if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
331         size += lstrlenW(separator) + lstrlenW(pubkey) + lstrlenW(equals) + CHARS_PER_PUBKEY;
332 
333     if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
334         size += lstrlenW(separator) + lstrlenW(procarch) + lstrlenW(equals) + lstrlenW(name->procarch);
335 
336     if (size > *pccDisplayName)
337     {
338         *pccDisplayName = size;
339         return E_NOT_SUFFICIENT_BUFFER;
340     }
341 
342     /* Construct the string */
343     lstrcpyW(szDisplayName, name->name);
344 
345     if ((dwDisplayFlags & ASM_DISPLAYF_VERSION) && (name->versize > 0))
346     {
347         lstrcatW(szDisplayName, separator);
348 
349         lstrcatW(szDisplayName, version);
350         lstrcatW(szDisplayName, equals);
351         lstrcatW(szDisplayName, verstr);
352     }
353 
354     if ((dwDisplayFlags & ASM_DISPLAYF_CULTURE) && (name->culture))
355     {
356         lstrcatW(szDisplayName, separator);
357 
358         lstrcatW(szDisplayName, culture);
359         lstrcatW(szDisplayName, equals);
360         lstrcatW(szDisplayName, cultureval);
361     }
362 
363     if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && (name->haspubkey))
364     {
365         WCHAR pkt[CHARS_PER_PUBKEY + 1];
366         static const WCHAR spec[] = {'%','0','2','x','%','0','2','x','%','0','2','x',
367             '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x',0};
368 
369         lstrcatW(szDisplayName, separator);
370 
371         lstrcatW(szDisplayName, pubkey);
372         lstrcatW(szDisplayName, equals);
373 
374         wsprintfW(pkt, spec, name->pubkey[0], name->pubkey[1], name->pubkey[2],
375             name->pubkey[3], name->pubkey[4], name->pubkey[5], name->pubkey[6],
376             name->pubkey[7]);
377 
378         lstrcatW(szDisplayName, pkt);
379     }
380 
381     if ((dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) && (name->procarch))
382     {
383         lstrcatW(szDisplayName, separator);
384 
385         lstrcatW(szDisplayName, procarch);
386         lstrcatW(szDisplayName, equals);
387         lstrcatW(szDisplayName, name->procarch);
388     }
389 
390     *pccDisplayName = size;
391     return S_OK;
392 }
393 
IAssemblyNameImpl_Reserved(IAssemblyName * iface,REFIID refIID,IUnknown * pUnkReserved1,IUnknown * pUnkReserved2,LPCOLESTR szReserved,LONGLONG llReserved,LPVOID pvReserved,DWORD cbReserved,LPVOID * ppReserved)394 static HRESULT WINAPI IAssemblyNameImpl_Reserved(IAssemblyName *iface,
395                                                  REFIID refIID,
396                                                  IUnknown *pUnkReserved1,
397                                                  IUnknown *pUnkReserved2,
398                                                  LPCOLESTR szReserved,
399                                                  LONGLONG llReserved,
400                                                  LPVOID pvReserved,
401                                                  DWORD cbReserved,
402                                                  LPVOID *ppReserved)
403 {
404     TRACE("(%p, %s, %p, %p, %s, %s, %p, %d, %p)\n", iface,
405           debugstr_guid(refIID), pUnkReserved1, pUnkReserved2,
406           debugstr_w(szReserved), wine_dbgstr_longlong(llReserved),
407           pvReserved, cbReserved, ppReserved);
408 
409     return E_NOTIMPL;
410 }
411 
IAssemblyNameImpl_GetName(IAssemblyName * iface,LPDWORD lpcwBuffer,WCHAR * pwzName)412 static HRESULT WINAPI IAssemblyNameImpl_GetName(IAssemblyName *iface,
413                                                 LPDWORD lpcwBuffer,
414                                                 WCHAR *pwzName)
415 {
416     IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
417     DWORD len;
418 
419     TRACE("(%p, %p, %p)\n", iface, lpcwBuffer, pwzName);
420 
421     if (name->name)
422         len = lstrlenW(name->name) + 1;
423     else
424         len = 0;
425 
426     if (*lpcwBuffer < len)
427     {
428         *lpcwBuffer = len;
429         return E_NOT_SUFFICIENT_BUFFER;
430     }
431     if (!name->name) lpcwBuffer[0] = 0;
432     else lstrcpyW(pwzName, name->name);
433 
434     *lpcwBuffer = len;
435     return S_OK;
436 }
437 
IAssemblyNameImpl_GetVersion(IAssemblyName * iface,LPDWORD pdwVersionHi,LPDWORD pdwVersionLow)438 static HRESULT WINAPI IAssemblyNameImpl_GetVersion(IAssemblyName *iface,
439                                                    LPDWORD pdwVersionHi,
440                                                    LPDWORD pdwVersionLow)
441 {
442     IAssemblyNameImpl *name = impl_from_IAssemblyName(iface);
443 
444     TRACE("(%p, %p, %p)\n", iface, pdwVersionHi, pdwVersionLow);
445 
446     *pdwVersionHi = 0;
447     *pdwVersionLow = 0;
448 
449     if (name->versize != 4)
450         return FUSION_E_INVALID_NAME;
451 
452     *pdwVersionHi = (name->version[0] << 16) + name->version[1];
453     *pdwVersionLow = (name->version[2] << 16) + name->version[3];
454 
455     return S_OK;
456 }
457 
IAssemblyNameImpl_IsEqual(IAssemblyName * iface,IAssemblyName * pName,DWORD flags)458 static HRESULT WINAPI IAssemblyNameImpl_IsEqual(IAssemblyName *iface,
459                                                 IAssemblyName *pName,
460                                                 DWORD flags)
461 {
462     IAssemblyNameImpl *name1 = impl_from_IAssemblyName(iface);
463     IAssemblyNameImpl *name2 = impl_from_IAssemblyName(pName);
464 
465     TRACE("(%p, %p, 0x%08x)\n", iface, pName, flags);
466 
467     if (!pName) return S_FALSE;
468     if (flags & ~ASM_CMPF_IL_ALL) FIXME("unsupported flags\n");
469 
470     if ((flags & ASM_CMPF_NAME) && lstrcmpW(name1->name, name2->name)) return S_FALSE;
471     if (name1->versize && name2->versize)
472     {
473         if ((flags & ASM_CMPF_MAJOR_VERSION) &&
474             name1->version[0] != name2->version[0]) return S_FALSE;
475         if ((flags & ASM_CMPF_MINOR_VERSION) &&
476             name1->version[1] != name2->version[1]) return S_FALSE;
477         if ((flags & ASM_CMPF_BUILD_NUMBER) &&
478             name1->version[2] != name2->version[2]) return S_FALSE;
479         if ((flags & ASM_CMPF_REVISION_NUMBER) &&
480             name1->version[3] != name2->version[3]) return S_FALSE;
481     }
482     if ((flags & ASM_CMPF_PUBLIC_KEY_TOKEN) &&
483         name1->haspubkey && name2->haspubkey &&
484         memcmp(name1->pubkey, name2->pubkey, sizeof(name1->pubkey))) return S_FALSE;
485 
486     if ((flags & ASM_CMPF_CULTURE) &&
487         name1->culture && name2->culture &&
488         lstrcmpW(name1->culture, name2->culture)) return S_FALSE;
489 
490     return S_OK;
491 }
492 
IAssemblyNameImpl_Clone(IAssemblyName * iface,IAssemblyName ** pName)493 static HRESULT WINAPI IAssemblyNameImpl_Clone(IAssemblyName *iface,
494                                               IAssemblyName **pName)
495 {
496     FIXME("(%p, %p) stub!\n", iface, pName);
497     return E_NOTIMPL;
498 }
499 
500 static const IAssemblyNameVtbl AssemblyNameVtbl = {
501     IAssemblyNameImpl_QueryInterface,
502     IAssemblyNameImpl_AddRef,
503     IAssemblyNameImpl_Release,
504     IAssemblyNameImpl_SetProperty,
505     IAssemblyNameImpl_GetProperty,
506     IAssemblyNameImpl_Finalize,
507     IAssemblyNameImpl_GetDisplayName,
508     IAssemblyNameImpl_Reserved,
509     IAssemblyNameImpl_GetName,
510     IAssemblyNameImpl_GetVersion,
511     IAssemblyNameImpl_IsEqual,
512     IAssemblyNameImpl_Clone
513 };
514 
515 /* Internal methods */
unsafe_impl_from_IAssemblyName(IAssemblyName * iface)516 static inline IAssemblyNameImpl *unsafe_impl_from_IAssemblyName(IAssemblyName *iface)
517 {
518     assert(iface->lpVtbl == &AssemblyNameVtbl);
519 
520     return impl_from_IAssemblyName(iface);
521 }
522 
IAssemblyName_SetPath(IAssemblyName * iface,LPCWSTR path)523 HRESULT IAssemblyName_SetPath(IAssemblyName *iface, LPCWSTR path)
524 {
525     IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
526 
527     name->path = strdupW(path);
528     if (!name->path)
529         return E_OUTOFMEMORY;
530 
531     return S_OK;
532 }
533 
IAssemblyName_GetPath(IAssemblyName * iface,LPWSTR buf,ULONG * len)534 HRESULT IAssemblyName_GetPath(IAssemblyName *iface, LPWSTR buf, ULONG *len)
535 {
536     ULONG buffer_size = *len;
537     IAssemblyNameImpl *name = unsafe_impl_from_IAssemblyName(iface);
538 
539     if (!name->path)
540         return S_OK;
541 
542     if (!buf)
543         buffer_size = 0;
544 
545     *len = lstrlenW(name->path) + 1;
546 
547     if (*len <= buffer_size)
548         lstrcpyW(buf, name->path);
549     else
550         return E_NOT_SUFFICIENT_BUFFER;
551 
552     return S_OK;
553 }
554 
parse_version(IAssemblyNameImpl * name,LPWSTR version)555 static HRESULT parse_version(IAssemblyNameImpl *name, LPWSTR version)
556 {
557     LPWSTR beg, end;
558     int i;
559 
560     for (i = 0, beg = version; i < 4; i++)
561     {
562         if (!*beg)
563             return S_OK;
564 
565         end = wcschr(beg, '.');
566 
567         if (end) *end = '\0';
568         name->version[i] = wcstol(beg, NULL, 10);
569         name->versize++;
570 
571         if (!end && i < 3)
572             return S_OK;
573 
574         beg = end + 1;
575     }
576 
577     return S_OK;
578 }
579 
parse_culture(IAssemblyNameImpl * name,LPCWSTR culture)580 static HRESULT parse_culture(IAssemblyNameImpl *name, LPCWSTR culture)
581 {
582     static const WCHAR empty[] = {0};
583 
584     if (lstrlenW(culture) == 2)
585         name->culture = strdupW(culture);
586     else
587         name->culture = strdupW(empty);
588 
589     return S_OK;
590 }
591 
is_hex(WCHAR c)592 static BOOL is_hex(WCHAR c)
593 {
594     return ((c >= 'a' && c <= 'f') ||
595             (c >= 'A' && c <= 'F') ||
596             (c >= '0' && c <= '9'));
597 }
598 
hextobyte(WCHAR c)599 static BYTE hextobyte(WCHAR c)
600 {
601     if(c >= '0' && c <= '9')
602         return c - '0';
603     if(c >= 'A' && c <= 'F')
604         return c - 'A' + 10;
605     if(c >= 'a' && c <= 'f')
606         return c - 'a' + 10;
607     return 0;
608 }
609 
parse_pubkey(IAssemblyNameImpl * name,LPCWSTR pubkey)610 static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey)
611 {
612     int i;
613     BYTE val;
614     static const WCHAR nullstr[] = {'n','u','l','l',0};
615 
616     if(lstrcmpiW(pubkey, nullstr) == 0)
617         return FUSION_E_PRIVATE_ASM_DISALLOWED;
618 
619     if (lstrlenW(pubkey) < CHARS_PER_PUBKEY)
620         return FUSION_E_INVALID_NAME;
621 
622     for (i = 0; i < CHARS_PER_PUBKEY; i++)
623         if (!is_hex(pubkey[i]))
624             return FUSION_E_INVALID_NAME;
625 
626     name->haspubkey = TRUE;
627 
628     for (i = 0; i < CHARS_PER_PUBKEY; i += 2)
629     {
630         val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]);
631         name->pubkey[i / 2] = val;
632     }
633 
634     return S_OK;
635 }
636 
parse_procarch(IAssemblyNameImpl * name,LPCWSTR procarch)637 static HRESULT parse_procarch(IAssemblyNameImpl *name, LPCWSTR procarch)
638 {
639     static const WCHAR msilW[] = {'m','s','i','l',0};
640     static const WCHAR x86W[] = {'x','8','6',0};
641     static const WCHAR ia64W[] = {'i','a','6','4',0};
642     static const WCHAR amd64W[] = {'a','m','d','6','4',0};
643 
644     if (!lstrcmpiW(procarch, msilW))
645         name->pekind = peMSIL;
646     else if (!lstrcmpiW(procarch, x86W))
647         name->pekind = peI386;
648     else if (!lstrcmpiW(procarch, ia64W))
649         name->pekind = peIA64;
650     else if (!lstrcmpiW(procarch, amd64W))
651         name->pekind = peAMD64;
652     else
653     {
654         ERR("unrecognized architecture: %s\n", wine_dbgstr_w(procarch));
655         return FUSION_E_INVALID_NAME;
656     }
657 
658     return S_OK;
659 }
660 
parse_value(const WCHAR * str,unsigned int len)661 static WCHAR *parse_value( const WCHAR *str, unsigned int len )
662 {
663     WCHAR *ret;
664     const WCHAR *p = str;
665     BOOL quoted = FALSE;
666     unsigned int i = 0;
667 
668     if (!(ret = heap_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
669     if (*p == '\"')
670     {
671         quoted = TRUE;
672         p++;
673     }
674     while (*p && *p != '\"') ret[i++] = *p++;
675     if ((quoted && *p != '\"') || (!quoted && *p == '\"'))
676     {
677         heap_free( ret );
678         return NULL;
679     }
680     ret[i] = 0;
681     return ret;
682 }
683 
parse_display_name(IAssemblyNameImpl * name,LPCWSTR szAssemblyName)684 static HRESULT parse_display_name(IAssemblyNameImpl *name, LPCWSTR szAssemblyName)
685 {
686     LPWSTR str, save, ptr, ptr2, value;
687     HRESULT hr = S_OK;
688     BOOL done = FALSE;
689 
690     if (!szAssemblyName)
691         return S_OK;
692 
693     name->displayname = strdupW(szAssemblyName);
694     if (!name->displayname)
695         return E_OUTOFMEMORY;
696 
697     str = strdupW(szAssemblyName);
698     save = str;
699     if (!str)
700     {
701         hr = E_OUTOFMEMORY;
702         goto done;
703     }
704 
705     ptr = wcschr(str, ',');
706     if (ptr) *ptr = '\0';
707 
708     /* no ',' but ' ' only */
709     if( !ptr && wcschr(str, ' ') )
710     {
711         hr = FUSION_E_INVALID_NAME;
712         goto done;
713     }
714 
715     name->name = strdupW(str);
716     if (!name->name)
717     {
718         hr = E_OUTOFMEMORY;
719         goto done;
720     }
721 
722     if (!ptr)
723         goto done;
724 
725     str = ptr + 1;
726     while (!done)
727     {
728         ptr = wcschr(str, '=');
729         if (!ptr)
730         {
731             hr = FUSION_E_INVALID_NAME;
732             goto done;
733         }
734 
735         *(ptr++) = '\0';
736         if (!*ptr)
737         {
738             hr = FUSION_E_INVALID_NAME;
739             goto done;
740         }
741 
742         if (!(ptr2 = wcschr(ptr, ',')))
743         {
744             if (!(ptr2 = wcschr(ptr, '\0')))
745             {
746                 hr = FUSION_E_INVALID_NAME;
747                 goto done;
748             }
749 
750             done = TRUE;
751         }
752 
753         *ptr2 = '\0';
754         if (!(value = parse_value( ptr, ptr2 - ptr )))
755         {
756             hr = FUSION_E_INVALID_NAME;
757             goto done;
758         }
759         while (*str == ' ') str++;
760 
761         if (!lstrcmpiW(str, version))
762             hr = parse_version( name, value );
763         else if (!lstrcmpiW(str, culture))
764             hr = parse_culture( name, value );
765         else if (!lstrcmpiW(str, pubkey))
766             hr = parse_pubkey( name, value );
767         else if (!lstrcmpiW(str, procarch))
768         {
769             name->procarch = value;
770             value = NULL;
771 
772             hr = parse_procarch( name, name->procarch );
773         }
774         heap_free( value );
775 
776         if (FAILED(hr))
777             goto done;
778 
779         str = ptr2 + 1;
780     }
781 
782 done:
783     heap_free(save);
784     if (FAILED(hr))
785     {
786         heap_free(name->displayname);
787         heap_free(name->name);
788         heap_free(name->culture);
789         heap_free(name->procarch);
790     }
791     return hr;
792 }
793 
794 /******************************************************************
795  *  CreateAssemblyNameObject   (FUSION.@)
796  */
CreateAssemblyNameObject(IAssemblyName ** ppAssemblyNameObj,LPCWSTR szAssemblyName,DWORD dwFlags,LPVOID pvReserved)797 HRESULT WINAPI CreateAssemblyNameObject(IAssemblyName **ppAssemblyNameObj,
798                                         LPCWSTR szAssemblyName, DWORD dwFlags,
799                                         LPVOID pvReserved)
800 {
801     IAssemblyNameImpl *name;
802     HRESULT hr;
803 
804     TRACE("(%p, %s, %08x, %p)\n", ppAssemblyNameObj,
805           debugstr_w(szAssemblyName), dwFlags, pvReserved);
806 
807     if (!ppAssemblyNameObj)
808         return E_INVALIDARG;
809 
810     if ((dwFlags & CANOF_PARSE_DISPLAY_NAME) &&
811         (!szAssemblyName || !*szAssemblyName))
812         return E_INVALIDARG;
813 
814     if (!(name = heap_alloc_zero(sizeof(*name)))) return E_OUTOFMEMORY;
815 
816     name->IAssemblyName_iface.lpVtbl = &AssemblyNameVtbl;
817     name->ref = 1;
818 
819     hr = parse_display_name(name, szAssemblyName);
820     if (FAILED(hr))
821     {
822         heap_free(name);
823         return hr;
824     }
825 
826     *ppAssemblyNameObj = &name->IAssemblyName_iface;
827 
828     return S_OK;
829 }
830