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