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 "fusionpriv.h"
27 IAssemblyName IAssemblyName_iface
;
45 static const WCHAR separator
[] = {',',' ',0};
46 static const WCHAR version
[] = {'V','e','r','s','i','o','n',0};
47 static const WCHAR culture
[] = {'C','u','l','t','u','r','e',0};
48 static const WCHAR pubkey
[] =
49 {'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
50 static const WCHAR procarch
[] = {'p','r','o','c','e','s','s','o','r',
51 'A','r','c','h','i','t','e','c','t','u','r','e',0};
53 #define CHARS_PER_PUBKEY 16
55 static inline IAssemblyNameImpl
*impl_from_IAssemblyName(IAssemblyName
*iface
)
57 return CONTAINING_RECORD(iface
, IAssemblyNameImpl
, IAssemblyName_iface
);
60 static HRESULT WINAPI
IAssemblyNameImpl_QueryInterface(IAssemblyName
*iface
,
61 REFIID riid
, LPVOID
*ppobj
)
63 IAssemblyNameImpl
*This
= impl_from_IAssemblyName(iface
);
65 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppobj
);
69 if (IsEqualIID(riid
, &IID_IUnknown
) ||
70 IsEqualIID(riid
, &IID_IAssemblyName
))
72 IAssemblyName_AddRef(iface
);
77 WARN("(%p, %s, %p): not found\n", This
, debugstr_guid(riid
), ppobj
);
81 static ULONG WINAPI
IAssemblyNameImpl_AddRef(IAssemblyName
*iface
)
83 IAssemblyNameImpl
*This
= impl_from_IAssemblyName(iface
);
84 ULONG refCount
= InterlockedIncrement(&This
->ref
);
86 TRACE("(%p)->(ref before = %u)\n", This
, refCount
- 1);
91 static ULONG WINAPI
IAssemblyNameImpl_Release(IAssemblyName
*iface
)
93 IAssemblyNameImpl
*This
= impl_from_IAssemblyName(iface
);
94 ULONG refCount
= InterlockedDecrement(&This
->ref
);
96 TRACE("(%p)->(ref before = %u)\n", This
, refCount
+ 1);
100 HeapFree(GetProcessHeap(), 0, This
->path
);
101 HeapFree(GetProcessHeap(), 0, This
->displayname
);
102 HeapFree(GetProcessHeap(), 0, This
->name
);
103 HeapFree(GetProcessHeap(), 0, This
->culture
);
104 HeapFree(GetProcessHeap(), 0, This
->procarch
);
105 HeapFree(GetProcessHeap(), 0, This
);
111 static HRESULT WINAPI
IAssemblyNameImpl_SetProperty(IAssemblyName
*iface
,
116 FIXME("(%p, %d, %p, %d) stub!\n", iface
, PropertyId
, pvProperty
, cbProperty
);
120 static HRESULT WINAPI
IAssemblyNameImpl_GetProperty(IAssemblyName
*iface
,
125 IAssemblyNameImpl
*name
= impl_from_IAssemblyName(iface
);
127 TRACE("(%p, %d, %p, %p)\n", iface
, PropertyId
, pvProperty
, pcbProperty
);
129 *((LPWSTR
)pvProperty
) = '\0';
133 case ASM_NAME_NULL_PUBLIC_KEY
:
134 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN
:
139 case ASM_NAME_NULL_CUSTOM
:
146 lstrcpyW(pvProperty
, name
->name
);
147 *pcbProperty
= (lstrlenW(name
->name
) + 1) * 2;
151 case ASM_NAME_MAJOR_VERSION
:
153 *((WORD
*)pvProperty
) = name
->version
[0];
154 if (name
->versize
>= 1)
155 *pcbProperty
= sizeof(WORD
);
158 case ASM_NAME_MINOR_VERSION
:
160 *((WORD
*)pvProperty
) = name
->version
[1];
161 if (name
->versize
>= 2)
162 *pcbProperty
= sizeof(WORD
);
165 case ASM_NAME_BUILD_NUMBER
:
167 *((WORD
*)pvProperty
) = name
->version
[2];
168 if (name
->versize
>= 3)
169 *pcbProperty
= sizeof(WORD
);
172 case ASM_NAME_REVISION_NUMBER
:
174 *((WORD
*)pvProperty
) = name
->version
[3];
175 if (name
->versize
>= 4)
176 *pcbProperty
= sizeof(WORD
);
179 case ASM_NAME_CULTURE
:
183 lstrcpyW(pvProperty
, name
->culture
);
184 *pcbProperty
= (lstrlenW(name
->culture
) + 1) * 2;
188 case ASM_NAME_PUBLIC_KEY_TOKEN
:
192 memcpy(pvProperty
, name
->pubkey
, sizeof(DWORD
) * 2);
193 *pcbProperty
= sizeof(DWORD
) * 2;
205 static HRESULT WINAPI
IAssemblyNameImpl_Finalize(IAssemblyName
*iface
)
207 FIXME("(%p) stub!\n", iface
);
211 static HRESULT WINAPI
IAssemblyNameImpl_GetDisplayName(IAssemblyName
*iface
,
212 LPOLESTR szDisplayName
,
213 LPDWORD pccDisplayName
,
214 DWORD dwDisplayFlags
)
216 IAssemblyNameImpl
*name
= impl_from_IAssemblyName(iface
);
219 LPWSTR cultureval
= 0;
221 static const WCHAR equals
[] = {'=',0};
223 TRACE("(%p, %p, %p, %d)\n", iface
, szDisplayName
,
224 pccDisplayName
, dwDisplayFlags
);
226 if (dwDisplayFlags
== 0)
228 if (!name
->displayname
|| !*name
->displayname
)
229 return FUSION_E_INVALID_NAME
;
231 size
= min(*pccDisplayName
, lstrlenW(name
->displayname
) + 1);
233 lstrcpynW(szDisplayName
, name
->displayname
, size
);
234 *pccDisplayName
= size
;
239 if (!name
->name
|| !*name
->name
)
240 return FUSION_E_INVALID_NAME
;
242 /* Verify buffer size is sufficient */
243 size
= lstrlenW(name
->name
) + 1;
245 if ((dwDisplayFlags
& ASM_DISPLAYF_VERSION
) && (name
->versize
> 0))
247 static const WCHAR spec
[] = {'%','d',0};
248 static const WCHAR period
[] = {'.',0};
251 wsprintfW(verstr
, spec
, name
->version
[0]);
253 for (i
= 1; i
< name
->versize
; i
++)
256 wsprintfW(value
, spec
, name
->version
[i
]);
258 lstrcatW(verstr
, period
);
259 lstrcatW(verstr
, value
);
262 size
+= lstrlenW(separator
) + lstrlenW(version
) + lstrlenW(equals
) + lstrlenW(verstr
);
265 if ((dwDisplayFlags
& ASM_DISPLAYF_CULTURE
) && (name
->culture
))
267 static const WCHAR neutral
[] = {'n','e','u','t','r','a','l', 0};
269 cultureval
= (lstrlenW(name
->culture
) == 2) ? name
->culture
: (LPWSTR
) neutral
;
270 size
+= lstrlenW(separator
) + lstrlenW(culture
) + lstrlenW(equals
) + lstrlenW(cultureval
);
273 if ((dwDisplayFlags
& ASM_DISPLAYF_PUBLIC_KEY_TOKEN
) && (name
->haspubkey
))
274 size
+= lstrlenW(separator
) + lstrlenW(pubkey
) + lstrlenW(equals
) + CHARS_PER_PUBKEY
;
276 if ((dwDisplayFlags
& ASM_DISPLAYF_PROCESSORARCHITECTURE
) && (name
->procarch
))
277 size
+= lstrlenW(separator
) + lstrlenW(procarch
) + lstrlenW(equals
) + lstrlenW(name
->procarch
);
279 if (size
> *pccDisplayName
)
282 /* Construct the string */
283 lstrcpyW(szDisplayName
, name
->name
);
285 if ((dwDisplayFlags
& ASM_DISPLAYF_VERSION
) && (name
->versize
> 0))
287 lstrcatW(szDisplayName
, separator
);
289 lstrcatW(szDisplayName
, version
);
290 lstrcatW(szDisplayName
, equals
);
291 lstrcatW(szDisplayName
, verstr
);
294 if ((dwDisplayFlags
& ASM_DISPLAYF_CULTURE
) && (name
->culture
))
296 lstrcatW(szDisplayName
, separator
);
298 lstrcatW(szDisplayName
, culture
);
299 lstrcatW(szDisplayName
, equals
);
300 lstrcatW(szDisplayName
, cultureval
);
303 if ((dwDisplayFlags
& ASM_DISPLAYF_PUBLIC_KEY_TOKEN
) && (name
->haspubkey
))
305 WCHAR pkt
[CHARS_PER_PUBKEY
+ 1];
306 static const WCHAR spec
[] = {'%','0','x','%','0','x','%','0','x',
307 '%','0','x','%','0','x','%','0','x','%','0','x','%','0','x',0};
309 lstrcatW(szDisplayName
, separator
);
311 lstrcatW(szDisplayName
, pubkey
);
312 lstrcatW(szDisplayName
, equals
);
314 wsprintfW(pkt
, spec
, name
->pubkey
[0], name
->pubkey
[1], name
->pubkey
[2],
315 name
->pubkey
[3], name
->pubkey
[4], name
->pubkey
[5], name
->pubkey
[6],
318 lstrcatW(szDisplayName
, pkt
);
321 if ((dwDisplayFlags
& ASM_DISPLAYF_PROCESSORARCHITECTURE
) && (name
->procarch
))
323 lstrcatW(szDisplayName
, separator
);
325 lstrcatW(szDisplayName
, procarch
);
326 lstrcatW(szDisplayName
, equals
);
327 lstrcatW(szDisplayName
, name
->procarch
);
330 *pccDisplayName
= size
;
334 static HRESULT WINAPI
IAssemblyNameImpl_Reserved(IAssemblyName
*iface
,
336 IUnknown
*pUnkReserved1
,
337 IUnknown
*pUnkReserved2
,
338 LPCOLESTR szReserved
,
344 TRACE("(%p, %s, %p, %p, %s, %x%08x, %p, %d, %p)\n", iface
,
345 debugstr_guid(refIID
), pUnkReserved1
, pUnkReserved2
,
346 debugstr_w(szReserved
), (DWORD
)(llReserved
>> 32), (DWORD
)llReserved
,
347 pvReserved
, cbReserved
, ppReserved
);
352 static HRESULT WINAPI
IAssemblyNameImpl_GetName(IAssemblyName
*iface
,
356 IAssemblyNameImpl
*name
= impl_from_IAssemblyName(iface
);
358 TRACE("(%p, %p, %p)\n", iface
, lpcwBuffer
, pwzName
);
367 lstrcpyW(pwzName
, name
->name
);
368 *lpcwBuffer
= lstrlenW(pwzName
) + 1;
373 static HRESULT WINAPI
IAssemblyNameImpl_GetVersion(IAssemblyName
*iface
,
374 LPDWORD pdwVersionHi
,
375 LPDWORD pdwVersionLow
)
377 IAssemblyNameImpl
*name
= impl_from_IAssemblyName(iface
);
379 TRACE("(%p, %p, %p)\n", iface
, pdwVersionHi
, pdwVersionLow
);
384 if (name
->versize
!= 4)
385 return FUSION_E_INVALID_NAME
;
387 *pdwVersionHi
= (name
->version
[0] << 16) + name
->version
[1];
388 *pdwVersionLow
= (name
->version
[2] << 16) + name
->version
[3];
393 static HRESULT WINAPI
IAssemblyNameImpl_IsEqual(IAssemblyName
*iface
,
394 IAssemblyName
*pName
,
397 IAssemblyNameImpl
*name1
= impl_from_IAssemblyName(iface
);
398 IAssemblyNameImpl
*name2
= impl_from_IAssemblyName(pName
);
400 TRACE("(%p, %p, 0x%08x)\n", iface
, pName
, flags
);
402 if (!pName
) return S_FALSE
;
403 if (flags
& ~ASM_CMPF_IL_ALL
) FIXME("unsupported flags\n");
405 if ((flags
& ASM_CMPF_NAME
) && strcmpW(name1
->name
, name2
->name
)) return S_FALSE
;
406 if (name1
->versize
&& name2
->versize
)
408 if ((flags
& ASM_CMPF_MAJOR_VERSION
) &&
409 name1
->version
[0] != name2
->version
[0]) return S_FALSE
;
410 if ((flags
& ASM_CMPF_MINOR_VERSION
) &&
411 name1
->version
[1] != name2
->version
[1]) return S_FALSE
;
412 if ((flags
& ASM_CMPF_BUILD_NUMBER
) &&
413 name1
->version
[2] != name2
->version
[2]) return S_FALSE
;
414 if ((flags
& ASM_CMPF_REVISION_NUMBER
) &&
415 name1
->version
[3] != name2
->version
[3]) return S_FALSE
;
417 if ((flags
& ASM_CMPF_PUBLIC_KEY_TOKEN
) &&
418 name1
->haspubkey
&& name2
->haspubkey
&&
419 memcmp(name1
->pubkey
, name2
->pubkey
, sizeof(name1
->pubkey
))) return S_FALSE
;
421 if ((flags
& ASM_CMPF_CULTURE
) &&
422 name1
->culture
&& name2
->culture
&&
423 strcmpW(name1
->culture
, name2
->culture
)) return S_FALSE
;
428 static HRESULT WINAPI
IAssemblyNameImpl_Clone(IAssemblyName
*iface
,
429 IAssemblyName
**pName
)
431 FIXME("(%p, %p) stub!\n", iface
, pName
);
435 static const IAssemblyNameVtbl AssemblyNameVtbl
= {
436 IAssemblyNameImpl_QueryInterface
,
437 IAssemblyNameImpl_AddRef
,
438 IAssemblyNameImpl_Release
,
439 IAssemblyNameImpl_SetProperty
,
440 IAssemblyNameImpl_GetProperty
,
441 IAssemblyNameImpl_Finalize
,
442 IAssemblyNameImpl_GetDisplayName
,
443 IAssemblyNameImpl_Reserved
,
444 IAssemblyNameImpl_GetName
,
445 IAssemblyNameImpl_GetVersion
,
446 IAssemblyNameImpl_IsEqual
,
447 IAssemblyNameImpl_Clone
450 /* Internal methods */
451 static inline IAssemblyNameImpl
*unsafe_impl_from_IAssemblyName(IAssemblyName
*iface
)
453 assert(iface
->lpVtbl
== &AssemblyNameVtbl
);
455 return impl_from_IAssemblyName(iface
);
458 HRESULT
IAssemblyName_SetPath(IAssemblyName
*iface
, LPCWSTR path
)
460 IAssemblyNameImpl
*name
= unsafe_impl_from_IAssemblyName(iface
);
462 name
->path
= strdupW(path
);
464 return E_OUTOFMEMORY
;
469 HRESULT
IAssemblyName_GetPath(IAssemblyName
*iface
, LPWSTR buf
, ULONG
*len
)
471 ULONG buffer_size
= *len
;
472 IAssemblyNameImpl
*name
= unsafe_impl_from_IAssemblyName(iface
);
480 *len
= lstrlenW(name
->path
) + 1;
482 if (*len
<= buffer_size
)
483 lstrcpyW(buf
, name
->path
);
485 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
490 static HRESULT
parse_version(IAssemblyNameImpl
*name
, LPWSTR version
)
495 for (i
= 0, beg
= version
; i
< 4; i
++)
500 end
= strchrW(beg
, '.');
502 if (end
) *end
= '\0';
503 name
->version
[i
] = atolW(beg
);
515 static HRESULT
parse_culture(IAssemblyNameImpl
*name
, LPCWSTR culture
)
517 static const WCHAR empty
[] = {0};
519 if (lstrlenW(culture
) == 2)
520 name
->culture
= strdupW(culture
);
522 name
->culture
= strdupW(empty
);
527 static BOOL
is_hex(WCHAR c
)
529 return ((c
>= 'a' && c
<= 'f') ||
530 (c
>= 'A' && c
<= 'F') ||
531 (c
>= '0' && c
<= '9'));
534 static BYTE
hextobyte(WCHAR c
)
536 if(c
>= '0' && c
<= '9')
538 if(c
>= 'A' && c
<= 'F')
540 if(c
>= 'a' && c
<= 'f')
545 static HRESULT
parse_pubkey(IAssemblyNameImpl
*name
, LPCWSTR pubkey
)
549 static const WCHAR nullstr
[] = {'n','u','l','l',0};
551 if(lstrcmpiW(pubkey
, nullstr
) == 0)
552 return FUSION_E_PRIVATE_ASM_DISALLOWED
;
554 if (lstrlenW(pubkey
) < CHARS_PER_PUBKEY
)
555 return FUSION_E_INVALID_NAME
;
557 for (i
= 0; i
< CHARS_PER_PUBKEY
; i
++)
558 if (!is_hex(pubkey
[i
]))
559 return FUSION_E_INVALID_NAME
;
561 name
->haspubkey
= TRUE
;
563 for (i
= 0; i
< CHARS_PER_PUBKEY
; i
+= 2)
565 val
= (hextobyte(pubkey
[i
]) << 4) + hextobyte(pubkey
[i
+ 1]);
566 name
->pubkey
[i
/ 2] = val
;
572 static WCHAR
*parse_value( const WCHAR
*str
, unsigned int len
)
575 const WCHAR
*p
= str
;
579 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) ))) return NULL
;
585 while (*p
&& *p
!= '\"') ret
[i
++] = *p
++;
586 if ((quoted
&& *p
!= '\"') || (!quoted
&& *p
== '\"'))
588 HeapFree( GetProcessHeap(), 0, ret
);
595 static HRESULT
parse_display_name(IAssemblyNameImpl
*name
, LPCWSTR szAssemblyName
)
597 LPWSTR str
, save
, ptr
, ptr2
, value
;
604 name
->displayname
= strdupW(szAssemblyName
);
605 if (!name
->displayname
)
606 return E_OUTOFMEMORY
;
608 str
= strdupW(szAssemblyName
);
616 ptr
= strchrW(str
, ',');
617 if (ptr
) *ptr
= '\0';
619 /* no ',' but ' ' only */
620 if( !ptr
&& strchrW(str
, ' ') )
622 hr
= FUSION_E_INVALID_NAME
;
626 name
->name
= strdupW(str
);
639 ptr
= strchrW(str
, '=');
642 hr
= FUSION_E_INVALID_NAME
;
649 hr
= FUSION_E_INVALID_NAME
;
653 if (!(ptr2
= strchrW(ptr
, ',')))
655 if (!(ptr2
= strchrW(ptr
, '\0')))
657 hr
= FUSION_E_INVALID_NAME
;
665 if (!(value
= parse_value( ptr
, ptr2
- ptr
)))
667 hr
= FUSION_E_INVALID_NAME
;
670 while (*str
== ' ') str
++;
672 if (!lstrcmpiW(str
, version
))
673 hr
= parse_version( name
, value
);
674 else if (!lstrcmpiW(str
, culture
))
675 hr
= parse_culture( name
, value
);
676 else if (!lstrcmpiW(str
, pubkey
))
677 hr
= parse_pubkey( name
, value
);
678 else if (!lstrcmpiW(str
, procarch
))
680 name
->procarch
= value
;
683 HeapFree( GetProcessHeap(), 0, value
);
692 HeapFree(GetProcessHeap(), 0, save
);
695 HeapFree(GetProcessHeap(), 0, name
->displayname
);
696 HeapFree(GetProcessHeap(), 0, name
->name
);
701 /******************************************************************
702 * CreateAssemblyNameObject (FUSION.@)
704 HRESULT WINAPI
CreateAssemblyNameObject(LPASSEMBLYNAME
*ppAssemblyNameObj
,
705 LPCWSTR szAssemblyName
, DWORD dwFlags
,
708 IAssemblyNameImpl
*name
;
711 TRACE("(%p, %s, %08x, %p)\n", ppAssemblyNameObj
,
712 debugstr_w(szAssemblyName
), dwFlags
, pvReserved
);
714 if (!ppAssemblyNameObj
)
717 if ((dwFlags
& CANOF_PARSE_DISPLAY_NAME
) &&
718 (!szAssemblyName
|| !*szAssemblyName
))
721 name
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IAssemblyNameImpl
));
723 return E_OUTOFMEMORY
;
725 name
->IAssemblyName_iface
.lpVtbl
= &AssemblyNameVtbl
;
728 hr
= parse_display_name(name
, szAssemblyName
);
731 HeapFree(GetProcessHeap(), 0, name
);
735 *ppAssemblyNameObj
= &name
->IAssemblyName_iface
;