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
36 #include "wine/debug.h"
37 #include "fusionpriv.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(fusion
);
42 IAssemblyName IAssemblyName_iface
;
62 static const WCHAR separator
[] = {',',' ',0};
63 static const WCHAR version
[] = {'V','e','r','s','i','o','n',0};
64 static const WCHAR culture
[] = {'C','u','l','t','u','r','e',0};
65 static const WCHAR pubkey
[] =
66 {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
67 static const WCHAR procarch
[] = {'p','r','o','c','e','s','s','o','r',
68 'A','r','c','h','i','t','e','c','t','u','r','e',0};
70 #define CHARS_PER_PUBKEY 16
72 static inline IAssemblyNameImpl
*impl_from_IAssemblyName(IAssemblyName
*iface
)
74 return CONTAINING_RECORD(iface
, IAssemblyNameImpl
, IAssemblyName_iface
);
77 static HRESULT WINAPI
IAssemblyNameImpl_QueryInterface(IAssemblyName
*iface
,
78 REFIID riid
, LPVOID
*ppobj
)
80 IAssemblyNameImpl
*This
= impl_from_IAssemblyName(iface
);
82 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppobj
);
86 if (IsEqualIID(riid
, &IID_IUnknown
) ||
87 IsEqualIID(riid
, &IID_IAssemblyName
))
89 IAssemblyName_AddRef(iface
);
90 *ppobj
= &This
->IAssemblyName_iface
;
94 WARN("(%p, %s, %p): not found\n", This
, debugstr_guid(riid
), ppobj
);
98 static ULONG WINAPI
IAssemblyNameImpl_AddRef(IAssemblyName
*iface
)
100 IAssemblyNameImpl
*This
= impl_from_IAssemblyName(iface
);
101 ULONG refCount
= InterlockedIncrement(&This
->ref
);
103 TRACE("(%p)->(ref before = %u)\n", This
, refCount
- 1);
108 static ULONG WINAPI
IAssemblyNameImpl_Release(IAssemblyName
*iface
)
110 IAssemblyNameImpl
*This
= impl_from_IAssemblyName(iface
);
111 ULONG refCount
= InterlockedDecrement(&This
->ref
);
113 TRACE("(%p)->(ref before = %u)\n", This
, refCount
+ 1);
117 heap_free(This
->path
);
118 heap_free(This
->displayname
);
119 heap_free(This
->name
);
120 heap_free(This
->culture
);
121 heap_free(This
->procarch
);
128 static HRESULT WINAPI
IAssemblyNameImpl_SetProperty(IAssemblyName
*iface
,
133 FIXME("(%p, %d, %p, %d) stub!\n", iface
, PropertyId
, pvProperty
, cbProperty
);
137 static HRESULT WINAPI
IAssemblyNameImpl_GetProperty(IAssemblyName
*iface
,
142 IAssemblyNameImpl
*name
= impl_from_IAssemblyName(iface
);
145 TRACE("(%p, %d, %p, %p)\n", iface
, PropertyId
, pvProperty
, pcbProperty
);
150 case ASM_NAME_NULL_PUBLIC_KEY
:
151 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN
:
156 case ASM_NAME_NULL_CUSTOM
:
163 *pcbProperty
= (lstrlenW(name
->name
) + 1) * 2;
164 if (size
< *pcbProperty
)
165 return STRSAFE_E_INSUFFICIENT_BUFFER
;
166 lstrcpyW(pvProperty
, name
->name
);
170 case ASM_NAME_MAJOR_VERSION
:
172 if (name
->versize
>= 1)
174 *pcbProperty
= sizeof(WORD
);
175 if (size
< *pcbProperty
)
176 return STRSAFE_E_INSUFFICIENT_BUFFER
;
177 *((WORD
*)pvProperty
) = name
->version
[0];
181 case ASM_NAME_MINOR_VERSION
:
183 if (name
->versize
>= 2)
185 *pcbProperty
= sizeof(WORD
);
186 if (size
< *pcbProperty
)
187 return STRSAFE_E_INSUFFICIENT_BUFFER
;
188 *((WORD
*)pvProperty
) = name
->version
[1];
192 case ASM_NAME_BUILD_NUMBER
:
194 if (name
->versize
>= 3)
196 *pcbProperty
= sizeof(WORD
);
197 if (size
< *pcbProperty
)
198 return STRSAFE_E_INSUFFICIENT_BUFFER
;
199 *((WORD
*)pvProperty
) = name
->version
[2];
203 case ASM_NAME_REVISION_NUMBER
:
205 if (name
->versize
>= 4)
207 *pcbProperty
= sizeof(WORD
);
208 if (size
< *pcbProperty
)
209 return STRSAFE_E_INSUFFICIENT_BUFFER
;
210 *((WORD
*)pvProperty
) = name
->version
[3];
214 case ASM_NAME_CULTURE
:
218 *pcbProperty
= (lstrlenW(name
->culture
) + 1) * 2;
219 if (size
< *pcbProperty
)
220 return STRSAFE_E_INSUFFICIENT_BUFFER
;
221 lstrcpyW(pvProperty
, name
->culture
);
225 case ASM_NAME_PUBLIC_KEY_TOKEN
:
229 *pcbProperty
= sizeof(DWORD
) * 2;
230 if (size
< *pcbProperty
)
231 return STRSAFE_E_INSUFFICIENT_BUFFER
;
232 memcpy(pvProperty
, name
->pubkey
, sizeof(DWORD
) * 2);
236 case ASM_NAME_ARCHITECTURE
:
238 if (name
->pekind
!= peNone
)
240 *pcbProperty
= sizeof(PEKIND
);
241 if (size
< *pcbProperty
)
242 return STRSAFE_E_INSUFFICIENT_BUFFER
;
243 *((PEKIND
*)pvProperty
) = name
->pekind
;
255 static HRESULT WINAPI
IAssemblyNameImpl_Finalize(IAssemblyName
*iface
)
257 FIXME("(%p) stub!\n", iface
);
261 static HRESULT WINAPI
IAssemblyNameImpl_GetDisplayName(IAssemblyName
*iface
,
262 LPOLESTR szDisplayName
,
263 LPDWORD pccDisplayName
,
264 DWORD dwDisplayFlags
)
266 static const WCHAR equals
[] = {'=',0};
267 IAssemblyNameImpl
*name
= impl_from_IAssemblyName(iface
);
268 WCHAR verstr
[30], *cultureval
= NULL
;
271 TRACE("(%p, %p, %p, %d)\n", iface
, szDisplayName
,
272 pccDisplayName
, dwDisplayFlags
);
274 if (dwDisplayFlags
== 0)
276 if (!name
->displayname
|| !*name
->displayname
)
277 return FUSION_E_INVALID_NAME
;
279 size
= lstrlenW(name
->displayname
) + 1;
281 if (*pccDisplayName
< size
)
283 *pccDisplayName
= size
;
284 return E_NOT_SUFFICIENT_BUFFER
;
287 if (szDisplayName
) lstrcpyW(szDisplayName
, name
->displayname
);
288 *pccDisplayName
= size
;
293 if (!name
->name
|| !*name
->name
)
294 return FUSION_E_INVALID_NAME
;
296 /* Verify buffer size is sufficient */
297 size
= lstrlenW(name
->name
) + 1;
299 if ((dwDisplayFlags
& ASM_DISPLAYF_VERSION
) && (name
->versize
> 0))
301 static const WCHAR spec
[] = {'%','d',0};
302 static const WCHAR period
[] = {'.',0};
305 wsprintfW(verstr
, spec
, name
->version
[0]);
307 for (i
= 1; i
< name
->versize
; i
++)
310 wsprintfW(value
, spec
, name
->version
[i
]);
312 lstrcatW(verstr
, period
);
313 lstrcatW(verstr
, value
);
316 size
+= lstrlenW(separator
) + lstrlenW(version
) + lstrlenW(equals
) + lstrlenW(verstr
);
319 if ((dwDisplayFlags
& ASM_DISPLAYF_CULTURE
) && (name
->culture
))
321 static const WCHAR neutral
[] = {'n','e','u','t','r','a','l', 0};
323 cultureval
= (lstrlenW(name
->culture
) == 2) ? name
->culture
: (LPWSTR
) neutral
;
324 size
+= lstrlenW(separator
) + lstrlenW(culture
) + lstrlenW(equals
) + lstrlenW(cultureval
);
327 if ((dwDisplayFlags
& ASM_DISPLAYF_PUBLIC_KEY_TOKEN
) && (name
->haspubkey
))
328 size
+= lstrlenW(separator
) + lstrlenW(pubkey
) + lstrlenW(equals
) + CHARS_PER_PUBKEY
;
330 if ((dwDisplayFlags
& ASM_DISPLAYF_PROCESSORARCHITECTURE
) && (name
->procarch
))
331 size
+= lstrlenW(separator
) + lstrlenW(procarch
) + lstrlenW(equals
) + lstrlenW(name
->procarch
);
333 if (size
> *pccDisplayName
)
335 *pccDisplayName
= size
;
336 return E_NOT_SUFFICIENT_BUFFER
;
339 /* Construct the string */
340 lstrcpyW(szDisplayName
, name
->name
);
342 if ((dwDisplayFlags
& ASM_DISPLAYF_VERSION
) && (name
->versize
> 0))
344 lstrcatW(szDisplayName
, separator
);
346 lstrcatW(szDisplayName
, version
);
347 lstrcatW(szDisplayName
, equals
);
348 lstrcatW(szDisplayName
, verstr
);
351 if ((dwDisplayFlags
& ASM_DISPLAYF_CULTURE
) && (name
->culture
))
353 lstrcatW(szDisplayName
, separator
);
355 lstrcatW(szDisplayName
, culture
);
356 lstrcatW(szDisplayName
, equals
);
357 lstrcatW(szDisplayName
, cultureval
);
360 if ((dwDisplayFlags
& ASM_DISPLAYF_PUBLIC_KEY_TOKEN
) && (name
->haspubkey
))
362 WCHAR pkt
[CHARS_PER_PUBKEY
+ 1];
363 static const WCHAR spec
[] = {'%','0','2','x','%','0','2','x','%','0','2','x',
364 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x',0};
366 lstrcatW(szDisplayName
, separator
);
368 lstrcatW(szDisplayName
, pubkey
);
369 lstrcatW(szDisplayName
, equals
);
371 wsprintfW(pkt
, spec
, name
->pubkey
[0], name
->pubkey
[1], name
->pubkey
[2],
372 name
->pubkey
[3], name
->pubkey
[4], name
->pubkey
[5], name
->pubkey
[6],
375 lstrcatW(szDisplayName
, pkt
);
378 if ((dwDisplayFlags
& ASM_DISPLAYF_PROCESSORARCHITECTURE
) && (name
->procarch
))
380 lstrcatW(szDisplayName
, separator
);
382 lstrcatW(szDisplayName
, procarch
);
383 lstrcatW(szDisplayName
, equals
);
384 lstrcatW(szDisplayName
, name
->procarch
);
387 *pccDisplayName
= size
;
391 static HRESULT WINAPI
IAssemblyNameImpl_Reserved(IAssemblyName
*iface
,
393 IUnknown
*pUnkReserved1
,
394 IUnknown
*pUnkReserved2
,
395 LPCOLESTR szReserved
,
401 TRACE("(%p, %s, %p, %p, %s, %s, %p, %d, %p)\n", iface
,
402 debugstr_guid(refIID
), pUnkReserved1
, pUnkReserved2
,
403 debugstr_w(szReserved
), wine_dbgstr_longlong(llReserved
),
404 pvReserved
, cbReserved
, ppReserved
);
409 static HRESULT WINAPI
IAssemblyNameImpl_GetName(IAssemblyName
*iface
,
413 IAssemblyNameImpl
*name
= impl_from_IAssemblyName(iface
);
416 TRACE("(%p, %p, %p)\n", iface
, lpcwBuffer
, pwzName
);
419 len
= lstrlenW(name
->name
) + 1;
423 if (*lpcwBuffer
< len
)
426 return E_NOT_SUFFICIENT_BUFFER
;
428 if (!name
->name
) lpcwBuffer
[0] = 0;
429 else lstrcpyW(pwzName
, name
->name
);
435 static HRESULT WINAPI
IAssemblyNameImpl_GetVersion(IAssemblyName
*iface
,
436 LPDWORD pdwVersionHi
,
437 LPDWORD pdwVersionLow
)
439 IAssemblyNameImpl
*name
= impl_from_IAssemblyName(iface
);
441 TRACE("(%p, %p, %p)\n", iface
, pdwVersionHi
, pdwVersionLow
);
446 if (name
->versize
!= 4)
447 return FUSION_E_INVALID_NAME
;
449 *pdwVersionHi
= (name
->version
[0] << 16) + name
->version
[1];
450 *pdwVersionLow
= (name
->version
[2] << 16) + name
->version
[3];
455 static HRESULT WINAPI
IAssemblyNameImpl_IsEqual(IAssemblyName
*iface
,
456 IAssemblyName
*pName
,
459 IAssemblyNameImpl
*name1
= impl_from_IAssemblyName(iface
);
460 IAssemblyNameImpl
*name2
= impl_from_IAssemblyName(pName
);
462 TRACE("(%p, %p, 0x%08x)\n", iface
, pName
, flags
);
464 if (!pName
) return S_FALSE
;
465 if (flags
& ~ASM_CMPF_IL_ALL
) FIXME("unsupported flags\n");
467 if ((flags
& ASM_CMPF_NAME
) && lstrcmpW(name1
->name
, name2
->name
)) return S_FALSE
;
468 if (name1
->versize
&& name2
->versize
)
470 if ((flags
& ASM_CMPF_MAJOR_VERSION
) &&
471 name1
->version
[0] != name2
->version
[0]) return S_FALSE
;
472 if ((flags
& ASM_CMPF_MINOR_VERSION
) &&
473 name1
->version
[1] != name2
->version
[1]) return S_FALSE
;
474 if ((flags
& ASM_CMPF_BUILD_NUMBER
) &&
475 name1
->version
[2] != name2
->version
[2]) return S_FALSE
;
476 if ((flags
& ASM_CMPF_REVISION_NUMBER
) &&
477 name1
->version
[3] != name2
->version
[3]) return S_FALSE
;
479 if ((flags
& ASM_CMPF_PUBLIC_KEY_TOKEN
) &&
480 name1
->haspubkey
&& name2
->haspubkey
&&
481 memcmp(name1
->pubkey
, name2
->pubkey
, sizeof(name1
->pubkey
))) return S_FALSE
;
483 if ((flags
& ASM_CMPF_CULTURE
) &&
484 name1
->culture
&& name2
->culture
&&
485 lstrcmpW(name1
->culture
, name2
->culture
)) return S_FALSE
;
490 static HRESULT WINAPI
IAssemblyNameImpl_Clone(IAssemblyName
*iface
,
491 IAssemblyName
**pName
)
493 FIXME("(%p, %p) stub!\n", iface
, pName
);
497 static const IAssemblyNameVtbl AssemblyNameVtbl
= {
498 IAssemblyNameImpl_QueryInterface
,
499 IAssemblyNameImpl_AddRef
,
500 IAssemblyNameImpl_Release
,
501 IAssemblyNameImpl_SetProperty
,
502 IAssemblyNameImpl_GetProperty
,
503 IAssemblyNameImpl_Finalize
,
504 IAssemblyNameImpl_GetDisplayName
,
505 IAssemblyNameImpl_Reserved
,
506 IAssemblyNameImpl_GetName
,
507 IAssemblyNameImpl_GetVersion
,
508 IAssemblyNameImpl_IsEqual
,
509 IAssemblyNameImpl_Clone
512 /* Internal methods */
513 static inline IAssemblyNameImpl
*unsafe_impl_from_IAssemblyName(IAssemblyName
*iface
)
515 assert(iface
->lpVtbl
== &AssemblyNameVtbl
);
517 return impl_from_IAssemblyName(iface
);
520 HRESULT
IAssemblyName_SetPath(IAssemblyName
*iface
, LPCWSTR path
)
522 IAssemblyNameImpl
*name
= unsafe_impl_from_IAssemblyName(iface
);
524 name
->path
= strdupW(path
);
526 return E_OUTOFMEMORY
;
531 HRESULT
IAssemblyName_GetPath(IAssemblyName
*iface
, LPWSTR buf
, ULONG
*len
)
533 ULONG buffer_size
= *len
;
534 IAssemblyNameImpl
*name
= unsafe_impl_from_IAssemblyName(iface
);
542 *len
= lstrlenW(name
->path
) + 1;
544 if (*len
<= buffer_size
)
545 lstrcpyW(buf
, name
->path
);
547 return E_NOT_SUFFICIENT_BUFFER
;
552 static HRESULT
parse_version(IAssemblyNameImpl
*name
, LPWSTR version
)
557 for (i
= 0, beg
= version
; i
< 4; i
++)
562 end
= wcschr(beg
, '.');
564 if (end
) *end
= '\0';
565 name
->version
[i
] = wcstol(beg
, NULL
, 10);
577 static HRESULT
parse_culture(IAssemblyNameImpl
*name
, LPCWSTR culture
)
579 static const WCHAR empty
[] = {0};
581 if (lstrlenW(culture
) == 2)
582 name
->culture
= strdupW(culture
);
584 name
->culture
= strdupW(empty
);
589 static BOOL
is_hex(WCHAR c
)
591 return ((c
>= 'a' && c
<= 'f') ||
592 (c
>= 'A' && c
<= 'F') ||
593 (c
>= '0' && c
<= '9'));
596 static BYTE
hextobyte(WCHAR c
)
598 if(c
>= '0' && c
<= '9')
600 if(c
>= 'A' && c
<= 'F')
602 if(c
>= 'a' && c
<= 'f')
607 static HRESULT
parse_pubkey(IAssemblyNameImpl
*name
, LPCWSTR pubkey
)
611 static const WCHAR nullstr
[] = {'n','u','l','l',0};
613 if(lstrcmpiW(pubkey
, nullstr
) == 0)
614 return FUSION_E_PRIVATE_ASM_DISALLOWED
;
616 if (lstrlenW(pubkey
) < CHARS_PER_PUBKEY
)
617 return FUSION_E_INVALID_NAME
;
619 for (i
= 0; i
< CHARS_PER_PUBKEY
; i
++)
620 if (!is_hex(pubkey
[i
]))
621 return FUSION_E_INVALID_NAME
;
623 name
->haspubkey
= TRUE
;
625 for (i
= 0; i
< CHARS_PER_PUBKEY
; i
+= 2)
627 val
= (hextobyte(pubkey
[i
]) << 4) + hextobyte(pubkey
[i
+ 1]);
628 name
->pubkey
[i
/ 2] = val
;
634 static HRESULT
parse_procarch(IAssemblyNameImpl
*name
, LPCWSTR procarch
)
636 static const WCHAR msilW
[] = {'m','s','i','l',0};
637 static const WCHAR x86W
[] = {'x','8','6',0};
638 static const WCHAR ia64W
[] = {'i','a','6','4',0};
639 static const WCHAR amd64W
[] = {'a','m','d','6','4',0};
641 if (!lstrcmpiW(procarch
, msilW
))
642 name
->pekind
= peMSIL
;
643 else if (!lstrcmpiW(procarch
, x86W
))
644 name
->pekind
= peI386
;
645 else if (!lstrcmpiW(procarch
, ia64W
))
646 name
->pekind
= peIA64
;
647 else if (!lstrcmpiW(procarch
, amd64W
))
648 name
->pekind
= peAMD64
;
651 ERR("unrecognized architecture: %s\n", wine_dbgstr_w(procarch
));
652 return FUSION_E_INVALID_NAME
;
658 static WCHAR
*parse_value( const WCHAR
*str
, unsigned int len
)
661 const WCHAR
*p
= str
;
665 if (!(ret
= heap_alloc( (len
+ 1) * sizeof(WCHAR
) ))) return NULL
;
671 while (*p
&& *p
!= '\"') ret
[i
++] = *p
++;
672 if ((quoted
&& *p
!= '\"') || (!quoted
&& *p
== '\"'))
681 static HRESULT
parse_display_name(IAssemblyNameImpl
*name
, LPCWSTR szAssemblyName
)
683 LPWSTR str
, save
, ptr
, ptr2
, value
;
690 name
->displayname
= strdupW(szAssemblyName
);
691 if (!name
->displayname
)
692 return E_OUTOFMEMORY
;
694 str
= strdupW(szAssemblyName
);
702 ptr
= wcschr(str
, ',');
703 if (ptr
) *ptr
= '\0';
705 /* no ',' but ' ' only */
706 if( !ptr
&& wcschr(str
, ' ') )
708 hr
= FUSION_E_INVALID_NAME
;
712 name
->name
= strdupW(str
);
725 ptr
= wcschr(str
, '=');
728 hr
= FUSION_E_INVALID_NAME
;
735 hr
= FUSION_E_INVALID_NAME
;
739 if (!(ptr2
= wcschr(ptr
, ',')))
741 if (!(ptr2
= wcschr(ptr
, '\0')))
743 hr
= FUSION_E_INVALID_NAME
;
751 if (!(value
= parse_value( ptr
, ptr2
- ptr
)))
753 hr
= FUSION_E_INVALID_NAME
;
756 while (*str
== ' ') str
++;
758 if (!lstrcmpiW(str
, version
))
759 hr
= parse_version( name
, value
);
760 else if (!lstrcmpiW(str
, culture
))
761 hr
= parse_culture( name
, value
);
762 else if (!lstrcmpiW(str
, pubkey
))
763 hr
= parse_pubkey( name
, value
);
764 else if (!lstrcmpiW(str
, procarch
))
766 name
->procarch
= value
;
769 hr
= parse_procarch( name
, name
->procarch
);
783 heap_free(name
->displayname
);
784 heap_free(name
->name
);
785 heap_free(name
->culture
);
786 heap_free(name
->procarch
);
791 /******************************************************************
792 * CreateAssemblyNameObject (FUSION.@)
794 HRESULT WINAPI
CreateAssemblyNameObject(IAssemblyName
**ppAssemblyNameObj
,
795 LPCWSTR szAssemblyName
, DWORD dwFlags
,
798 IAssemblyNameImpl
*name
;
801 TRACE("(%p, %s, %08x, %p)\n", ppAssemblyNameObj
,
802 debugstr_w(szAssemblyName
), dwFlags
, pvReserved
);
804 if (!ppAssemblyNameObj
)
807 if ((dwFlags
& CANOF_PARSE_DISPLAY_NAME
) &&
808 (!szAssemblyName
|| !*szAssemblyName
))
811 if (!(name
= heap_alloc_zero(sizeof(*name
)))) return E_OUTOFMEMORY
;
813 name
->IAssemblyName_iface
.lpVtbl
= &AssemblyNameVtbl
;
816 hr
= parse_display_name(name
, szAssemblyName
);
823 *ppAssemblyNameObj
= &name
->IAssemblyName_iface
;