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 } 828