1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// ============================================================
5//
6// FusionAssemblyName.cpp
7//
8// Implements the CAssemblyName class
9//
10// ============================================================
11
12#include <windows.h>
13#include <winerror.h>
14#include "strongname.h"
15
16#include "fusionhelpers.hpp"
17#include "fusionassemblyname.hpp"
18
19#include <strsafe.h>
20#include "shlwapi.h"
21
22#include "binderinterface.hpp"
23#include "assemblyidentity.hpp"
24#include "textualidentityparser.hpp"
25
26#define DISPLAY_NAME_DELIMITER W(',')
27#define DISPLAY_NAME_DELIMITER_STRING W(",")
28#define VERSION_STRING_SEGMENTS 4
29#define REMAINING_BUFFER_SIZE ((*pccDisplayName) - (pszBuf - szDisplayName))
30
31// ---------------------------------------------------------------------------
32// Private Helpers
33// ---------------------------------------------------------------------------
34namespace
35{
36 HRESULT GetPublicKeyTokenFromPKBlob(LPBYTE pbPublicKeyToken, DWORD cbPublicKeyToken,
37 LPBYTE *ppbSN, LPDWORD pcbSN)
38 {
39 HRESULT hr = S_OK;
40
41 // Generate the hash of the public key.
42 if (!StrongNameTokenFromPublicKey(pbPublicKeyToken, cbPublicKeyToken, ppbSN, pcbSN))
43 {
44 hr = StrongNameErrorInfo();
45 }
46
47 return hr;
48 }
49};
50
51// ---------------------------------------------------------------------------
52// CPropertyArray ctor
53// ---------------------------------------------------------------------------
54CPropertyArray::CPropertyArray()
55{
56 _dwSig = 0x504f5250; /* 'PORP' */
57 memset(&_rProp, 0, ASM_NAME_MAX_PARAMS * sizeof(FusionProperty));
58}
59
60// ---------------------------------------------------------------------------
61// CPropertyArray dtor
62// ---------------------------------------------------------------------------
63CPropertyArray::~CPropertyArray()
64{
65 for (DWORD i = 0; i < ASM_NAME_MAX_PARAMS; i++)
66 {
67 if (_rProp[i].cb > sizeof(DWORD))
68 {
69 if (_rProp[i].pv != NULL)
70 {
71 FUSION_DELETE_ARRAY((LPBYTE) _rProp[i].pv);
72 _rProp[i].pv = NULL;
73 }
74 }
75 }
76}
77
78// ---------------------------------------------------------------------------
79// CPropertyArray::Set
80// ---------------------------------------------------------------------------
81HRESULT CPropertyArray::Set(DWORD PropertyId,
82 LPCVOID pvProperty, DWORD cbProperty)
83{
84 HRESULT hr = S_OK;
85 FusionProperty *pItem = NULL;
86
87 pItem = &(_rProp[PropertyId]);
88
89 if (!cbProperty && !pvProperty)
90 {
91 if (pItem->cb > sizeof(DWORD))
92 {
93 if (pItem->pv != NULL)
94 FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
95 }
96 pItem->pv = NULL;
97 }
98 else if (cbProperty > sizeof(DWORD))
99 {
100 LPBYTE ptr = NEW(BYTE[cbProperty]);
101 if (!ptr)
102 {
103 hr = E_OUTOFMEMORY;
104 goto exit;
105 }
106
107 if (pItem->cb > sizeof(DWORD))
108 FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
109
110 memcpy(ptr, pvProperty, cbProperty);
111 pItem->pv = ptr;
112 }
113 else
114 {
115 if (pItem->cb > sizeof(DWORD))
116 FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
117
118 memcpy(&(pItem->pv), pvProperty, cbProperty);
119
120#ifdef _DEBUG
121 if (PropertyId == ASM_NAME_ARCHITECTURE) {
122 PEKIND pe = * ((PEKIND *)pvProperty);
123 _ASSERTE(pe != peInvalid);
124 }
125#endif
126 }
127 pItem->cb = cbProperty;
128
129exit:
130 return hr;
131}
132
133// ---------------------------------------------------------------------------
134// CPropertyArray::Get
135// ---------------------------------------------------------------------------
136HRESULT CPropertyArray::Get(DWORD PropertyId,
137 LPVOID pvProperty, LPDWORD pcbProperty)
138{
139 HRESULT hr = S_OK;
140 FusionProperty *pItem;
141
142 _ASSERTE(pcbProperty);
143
144 if (PropertyId >= ASM_NAME_MAX_PARAMS
145 || (!pvProperty && *pcbProperty))
146 {
147 _ASSERTE(!"Invalid Argument! Passed in NULL buffer with size non-zero!");
148 hr = E_INVALIDARG;
149 goto exit;
150 }
151
152 pItem = &(_rProp[PropertyId]);
153
154 if (pItem->cb > *pcbProperty)
155 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
156 else if (pItem->cb)
157 memcpy(pvProperty, (pItem->cb > sizeof(DWORD) ?
158 pItem->pv : (LPBYTE) &(pItem->pv)), pItem->cb);
159
160 *pcbProperty = pItem->cb;
161
162exit:
163 return hr;
164}
165
166// ---------------------------------------------------------------------------
167// CPropertyArray::operator []
168// Wraps DWORD optimization test.
169// ---------------------------------------------------------------------------
170FusionProperty CPropertyArray::operator [] (DWORD PropertyId)
171{
172 FusionProperty prop;
173
174 prop.pv = _rProp[PropertyId].cb > sizeof(DWORD) ?
175 _rProp[PropertyId].pv : &(_rProp[PropertyId].pv);
176
177 prop.cb = _rProp[PropertyId].cb;
178
179 return prop;
180}
181
182// ---------------------------------------------------------------------------
183// CAssemblyName::AddRef
184// ---------------------------------------------------------------------------
185STDMETHODIMP_(ULONG)
186CAssemblyName::AddRef()
187{
188 return InterlockedIncrement(&_cRef);
189}
190
191// ---------------------------------------------------------------------------
192// CAssemblyName::Release
193// ---------------------------------------------------------------------------
194STDMETHODIMP_(ULONG)
195CAssemblyName::Release()
196{
197 ULONG ulRef = InterlockedDecrement(&_cRef);
198 if (ulRef == 0)
199 {
200 delete this;
201 }
202
203 return ulRef;
204}
205
206// ---------------------------------------------------------------------------
207// CAssemblyName::QueryInterface
208// ---------------------------------------------------------------------------
209STDMETHODIMP
210CAssemblyName::QueryInterface(REFIID riid, void** ppv)
211{
212 HRESULT hr = S_OK;
213
214 BEGIN_ENTRYPOINT_NOTHROW;
215
216 if (!ppv)
217 {
218 hr = E_POINTER;
219 goto Exit;
220 }
221
222 if ( IsEqualIID(riid, IID_IUnknown)
223 || IsEqualIID(riid, IID_IAssemblyName)
224 )
225 {
226 *ppv = static_cast<IAssemblyName*> (this);
227 AddRef();
228 hr = S_OK;
229 goto Exit;
230 }
231 else
232 {
233 *ppv = NULL;
234 hr = E_NOINTERFACE;
235 goto Exit;
236 }
237
238 Exit:
239 END_ENTRYPOINT_NOTHROW;
240
241 return hr;
242}
243
244// ---------------------------------------------------------------------------
245// CAssemblyName::SetProperty
246// ---------------------------------------------------------------------------
247STDMETHODIMP
248CAssemblyName::SetProperty(DWORD PropertyId,
249 LPCVOID pvProperty,
250 DWORD cbProperty)
251{
252 HRESULT hr = S_OK;
253
254 BEGIN_ENTRYPOINT_NOTHROW;
255
256 hr = SetPropertyInternal(PropertyId, pvProperty, cbProperty);
257
258 END_ENTRYPOINT_NOTHROW;
259 return hr;
260}
261
262// ---------------------------------------------------------------------------
263// CAssemblyName::GetProperty
264// ---------------------------------------------------------------------------
265STDMETHODIMP
266CAssemblyName::GetProperty(DWORD PropertyId,
267 LPVOID pvProperty, LPDWORD pcbProperty)
268{
269 HRESULT hr = S_OK;
270
271 BEGIN_ENTRYPOINT_NOTHROW;
272
273 // Retrieve the property.
274 switch(PropertyId)
275 {
276 case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
277 case ASM_NAME_NULL_PUBLIC_KEY:
278 {
279 hr = (_fPublicKeyToken && !_rProp[PropertyId].cb) ? S_OK : S_FALSE;
280 break;
281 }
282 case ASM_NAME_NULL_CUSTOM:
283 {
284 hr = (_fCustom && !_rProp[PropertyId].cb) ? S_OK : S_FALSE;
285 break;
286 }
287 default:
288 {
289 hr = _rProp.Get(PropertyId, pvProperty, pcbProperty);
290 break;
291 }
292 }
293
294 END_ENTRYPOINT_NOTHROW;
295
296 return hr;
297}
298
299// ---------------------------------------------------------------------------
300// CAssemblyName::Finalize
301// ---------------------------------------------------------------------------
302STDMETHODIMP
303CAssemblyName::Finalize()
304{
305 BEGIN_ENTRYPOINT_NOTHROW;
306
307 _fIsFinalized = TRUE;
308 END_ENTRYPOINT_NOTHROW;
309
310 return S_OK;
311}
312// ---------------------------------------------------------------------------
313// CAssemblyName::GetDisplayName
314// ---------------------------------------------------------------------------
315STDMETHODIMP
316CAssemblyName::GetDisplayName( __out_ecount_opt(*pccDisplayName) LPOLESTR szDisplayName,
317 __inout LPDWORD pccDisplayName,
318 DWORD dwDisplayFlags)
319{
320 HRESULT hr = S_OK;
321
322 BEGIN_ENTRYPOINT_NOTHROW;
323
324 if (!dwDisplayFlags) {
325 dwDisplayFlags = ASM_DISPLAYF_DEFAULT;
326 }
327
328 // Validate input buffer.
329 if(!pccDisplayName || (!szDisplayName && *pccDisplayName)) {
330 hr = E_INVALIDARG;
331 goto exit;
332 }
333
334 EX_TRY
335 {
336 NewHolder<BINDER_SPACE::AssemblyIdentity> pAssemblyIdentity = new BINDER_SPACE::AssemblyIdentity();
337 FusionProperty prop;
338 StackSString textualIdentity;
339
340 // Name required
341 prop = _rProp[ASM_NAME_NAME];
342 if (prop.cb == 0) {
343 hr = FUSION_E_INVALID_NAME;
344 goto exit;
345 }
346 else {
347 _ASSERTE(prop.cb >= sizeof(WCHAR));
348
349 pAssemblyIdentity->m_simpleName.Set((const WCHAR *) prop.pv,
350 (prop.cb - sizeof(WCHAR)) / sizeof(WCHAR));
351 pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
352 }
353
354 // Display version
355 if (dwDisplayFlags & ASM_DISPLAYF_VERSION) {
356 prop = _rProp[ASM_NAME_MAJOR_VERSION];
357
358 // Set version if we have it
359 if (prop.cb != 0) {
360 DWORD dwVersionParts[4];
361
362 for(DWORD i = 0; i < 4; i++) {
363 prop = _rProp[ASM_NAME_MAJOR_VERSION + i];
364
365 // Normalize non-existing version parts to zero
366 if (prop.cb == sizeof(WORD)) {
367 dwVersionParts[i] = (DWORD) (* ((WORD *) prop.pv));
368 }
369 else {
370 dwVersionParts[i] = 0;
371 }
372 }
373
374 pAssemblyIdentity->m_version.SetFeatureVersion(dwVersionParts[0], dwVersionParts[1]);
375 pAssemblyIdentity->m_version.SetServiceVersion(dwVersionParts[2], dwVersionParts[3]);
376 pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION);
377 }
378 }
379
380 // Display culture
381 if (dwDisplayFlags & ASM_DISPLAYF_CULTURE) {
382 prop = _rProp[ASM_NAME_CULTURE];
383
384 if (prop.cb != 0) {
385 _ASSERTE(prop.cb >= sizeof(WCHAR));
386
387 if (((const WCHAR *) prop.pv)[0] != 0x00) {
388 pAssemblyIdentity->m_cultureOrLanguage.
389 Set((const WCHAR *) prop.pv,
390 (prop.cb - sizeof(WCHAR)) / sizeof(WCHAR));
391 }
392
393 pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE);
394 }
395 }
396
397 // Display public key token
398 if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && _fPublicKeyToken) {
399 prop = _rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
400
401 if (prop.cb != 0) {
402 pAssemblyIdentity->m_publicKeyOrTokenBLOB.Set((const BYTE *) prop.pv, prop.cb);
403 pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
404 }
405 else {
406 pAssemblyIdentity->
407 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
408 }
409 }
410
411 // Display processor architecture
412 if (dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) {
413 if (_rProp[ASM_NAME_ARCHITECTURE].cb != 0) {
414 DWORD PeKind = *((LPDWORD)_rProp[ASM_NAME_ARCHITECTURE].pv);
415
416 if (PeKind != peNone) {
417 pAssemblyIdentity->m_kProcessorArchitecture = (PEKIND) PeKind;
418 pAssemblyIdentity->
419 SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
420 }
421 }
422 }
423
424 // Display retarget flag
425 if (dwDisplayFlags & ASM_DISPLAYF_RETARGET) {
426 prop = _rProp[ASM_NAME_RETARGET];
427
428 if (prop.cb != 0) {
429 BOOL fRetarget = *((LPBOOL) prop.pv);
430
431 if (fRetarget)
432 {
433 pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
434 }
435 }
436 }
437
438 // Display content type
439 if (dwDisplayFlags & ASM_DISPLAYF_CONTENT_TYPE)
440 {
441 prop = _rProp[ASM_NAME_CONTENT_TYPE];
442 if (prop.cb != 0)
443 {
444 DWORD dwContentType = *((LPDWORD)prop.pv);
445 if (dwContentType != AssemblyContentType_Default)
446 {
447 pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
448 pAssemblyIdentity->m_kContentType = (AssemblyContentType)dwContentType;
449 }
450 }
451 }
452
453 // Display custom flag
454 if ((dwDisplayFlags & ASM_DISPLAYF_CUSTOM) && _fCustom) {
455 prop = _rProp[ASM_NAME_CUSTOM];
456
457 if (prop.cb != 0) {
458 pAssemblyIdentity->m_customBLOB.Set((const BYTE *) prop.pv, prop.cb);
459 pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
460 }
461 else {
462 pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL);
463 }
464 }
465
466 // Create the textual identity
467 hr = BINDER_SPACE::TextualIdentityParser::ToString(pAssemblyIdentity,
468 pAssemblyIdentity->m_dwIdentityFlags,
469 textualIdentity);
470 if (FAILED(hr)) {
471 goto exit;
472 }
473
474 // Determine required buffer size
475 DWORD dwGivenSize = *pccDisplayName;
476 DWORD dwRequiredSize = textualIdentity.GetCount() + 1;
477
478 *pccDisplayName = dwRequiredSize;
479
480 if (dwRequiredSize > dwGivenSize) {
481 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
482
483 if (szDisplayName) {
484 szDisplayName[0] = 0x00;
485 }
486 goto exit;
487 }
488 else {
489 hr = S_OK;
490 memcpy(szDisplayName, textualIdentity.GetUnicode(), dwRequiredSize * sizeof(WCHAR));
491 }
492 }
493 EX_CATCH_HRESULT(hr);
494
495 exit:
496 END_ENTRYPOINT_NOTHROW;
497 return hr;
498}
499
500// ---------------------------------------------------------------------------
501// CAssemblyName::GetName
502// ---------------------------------------------------------------------------
503STDMETHODIMP
504CAssemblyName::GetName(
505 __inout LPDWORD lpcwBuffer,
506 __out_ecount_opt(*lpcwBuffer) LPOLESTR pwzBuffer)
507{
508 HRESULT hr = S_OK;
509 BEGIN_ENTRYPOINT_NOTHROW;
510
511 DWORD cbBuffer = *lpcwBuffer * sizeof(TCHAR);
512 hr = GetProperty(ASM_NAME_NAME, pwzBuffer, &cbBuffer);
513 *lpcwBuffer = cbBuffer / sizeof(TCHAR);
514 END_ENTRYPOINT_NOTHROW;
515
516 return hr;
517}
518
519// ---------------------------------------------------------------------------
520// CAssemblyName::GetVersion
521// ---------------------------------------------------------------------------
522STDMETHODIMP
523CAssemblyName::GetVersion(
524 /* [out] */ LPDWORD pdwVersionHi,
525 /* [out] */ LPDWORD pdwVersionLow)
526{
527 HRESULT hr = S_OK;
528 BEGIN_ENTRYPOINT_NOTHROW;
529
530 // Get Assembly Version
531 hr = GetVersion( ASM_NAME_MAJOR_VERSION, pdwVersionHi, pdwVersionLow);
532
533 END_ENTRYPOINT_NOTHROW;
534 return hr;
535}
536
537// ---------------------------------------------------------------------------
538// CAssemblyName::IsEqual
539// ---------------------------------------------------------------------------
540STDMETHODIMP
541CAssemblyName::IsEqual(LPASSEMBLYNAME pName, DWORD dwCmpFlags)
542{
543 HRESULT hr = S_OK;
544
545 BEGIN_ENTRYPOINT_NOTHROW;
546
547 DWORD dwPartialCmpMask = 0;
548 BOOL fIsPartial = FALSE;
549 CAssemblyName *pCName = static_cast<CAssemblyName *>(pName);
550
551 const DWORD SIMPLE_VERSION_MASK = ASM_CMPF_VERSION;
552
553 FusionProperty propThis;
554 FusionProperty propPara;
555
556 if(!pName) {
557 hr = S_FALSE;
558 goto Exit;
559 }
560
561 // Get the ref partial comparison mask, if any.
562 fIsPartial = CAssemblyName::IsPartial(this, &dwPartialCmpMask);
563
564 if (dwCmpFlags == ASM_CMPF_DEFAULT) {
565 // Set all comparison flags.
566 dwCmpFlags = ASM_CMPF_IL_ALL | ASM_CMPF_ARCHITECTURE;
567
568 // don't compare architecture if ref does not have architecture.
569 if (!(dwPartialCmpMask & ASM_CMPF_ARCHITECTURE)) {
570 dwCmpFlags &= ~ASM_CMPF_ARCHITECTURE;
571 }
572
573 // Otherwise, if ref is simple (possibly partial)
574 // we mask off all version bits.
575 if (!CAssemblyName::IsStronglyNamed(this))
576 {
577 // we don't have a public key token, but we don't know
578 // it is because we are simply named assembly or we are
579 // just partial on public key token.
580 if (dwPartialCmpMask & ASM_CMPF_PUBLIC_KEY_TOKEN)
581 {
582 // now we know we are simply named assembly since we
583 // have a public key token, but it is NULL.
584 dwCmpFlags &= ~SIMPLE_VERSION_MASK;
585 }
586 // If neither of these two cases then public key token
587 // is not set in ref , but def may be simple or strong.
588 // The comparison mask is chosen based on def.
589 else
590 {
591 if (!CAssemblyName::IsStronglyNamed(pName))
592 dwCmpFlags &= ~SIMPLE_VERSION_MASK;
593 }
594 }
595 }
596
597 // Mask off flags (either passed in or generated
598 // by default flag with the comparison mask generated
599 // from the ref.
600 dwCmpFlags &= dwPartialCmpMask;
601
602
603 // The individual name fields can now be compared..
604
605 // Compare name
606
607 if (dwCmpFlags & ASM_CMPF_NAME)
608 {
609 propThis = _rProp[ASM_NAME_NAME];
610 propPara = pCName->_rProp[ASM_NAME_NAME];
611
612 if (propThis.cb != propPara.cb)
613 {
614 hr = S_FALSE;
615 goto Exit;
616 }
617
618 if (propThis.cb && FusionCompareStringI((LPWSTR)propThis.pv, (LPWSTR)propPara.pv))
619 {
620 hr = S_FALSE;
621 goto Exit;
622 }
623 }
624
625 // Compare version
626
627 if (dwCmpFlags & ASM_CMPF_MAJOR_VERSION)
628 {
629 propThis = _rProp[ASM_NAME_MAJOR_VERSION];
630 propPara = pCName->_rProp[ASM_NAME_MAJOR_VERSION];
631
632 if (*((LPWORD) propThis.pv) != *((LPWORD)propPara.pv))
633 {
634 hr = S_FALSE;
635 goto Exit;
636 }
637 }
638
639 if (dwCmpFlags & ASM_CMPF_MINOR_VERSION)
640 {
641 propThis = _rProp[ASM_NAME_MINOR_VERSION];
642 propPara = pCName->_rProp[ASM_NAME_MINOR_VERSION];
643
644 if (*((LPWORD) propThis.pv) != *((LPWORD)propPara.pv))
645 {
646 hr = S_FALSE;
647 goto Exit;
648 }
649 }
650
651 if (dwCmpFlags & ASM_CMPF_REVISION_NUMBER)
652 {
653 propThis = _rProp[ASM_NAME_REVISION_NUMBER];
654 propPara = pCName->_rProp[ASM_NAME_REVISION_NUMBER];
655
656 if (*((LPWORD) propThis.pv) != *((LPWORD)propPara.pv))
657 {
658 hr = S_FALSE;
659 goto Exit;
660 }
661 }
662
663 if (dwCmpFlags & ASM_CMPF_BUILD_NUMBER)
664 {
665 propThis = _rProp[ASM_NAME_BUILD_NUMBER];
666 propPara = pCName->_rProp[ASM_NAME_BUILD_NUMBER];
667
668 if (*((LPWORD) propThis.pv) != *((LPWORD)propPara.pv))
669 {
670 hr = S_FALSE;
671 goto Exit;
672 }
673 }
674
675 // Compare public key token
676
677 if (dwCmpFlags & ASM_CMPF_PUBLIC_KEY_TOKEN)
678 {
679 // compare public key if both of them have public key set.
680 propThis = _rProp[ASM_NAME_PUBLIC_KEY];
681 propPara = pCName->_rProp[ASM_NAME_PUBLIC_KEY];
682 if (!propThis.cb || !propPara.cb) {
683 // otherwise, compare public key token
684 propThis = _rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
685 propPara = pCName->_rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
686 }
687
688 if (propThis.cb != propPara.cb) {
689 hr = S_FALSE;
690 goto Exit;
691 }
692
693 if (propThis.cb && memcmp(propThis.pv, propPara.pv, propThis.cb)) {
694 hr = S_FALSE;
695 goto Exit;
696 }
697 }
698
699 // Compare Culture
700
701 if (dwCmpFlags & ASM_CMPF_CULTURE)
702 {
703 propThis = _rProp[ASM_NAME_CULTURE];
704 propPara = pCName->_rProp[ASM_NAME_CULTURE];
705
706 if (propThis.cb != propPara.cb)
707 {
708 hr = S_FALSE;
709 goto Exit;
710 }
711
712 if (propThis.cb && FusionCompareStringI((LPWSTR)propThis.pv, (LPWSTR)propPara.pv))
713 {
714 hr = S_FALSE;
715 goto Exit;
716 }
717 }
718
719 // Compare Custom attribute.
720
721 if (dwCmpFlags & ASM_CMPF_CUSTOM)
722 {
723 propThis = _rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
724 propPara = pCName->_rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
725
726 if (propThis.cb != propPara.cb) {
727 hr = S_FALSE;
728 goto Exit;
729 }
730
731 if (propThis.cb && memcmp(propThis.pv, propPara.pv, propThis.cb)) {
732 hr = S_FALSE;
733 goto Exit;
734 }
735 }
736
737 // Compare Retarget flag
738 if (dwCmpFlags & ASM_CMPF_RETARGET)
739 {
740 propThis = _rProp[ASM_NAME_RETARGET];
741 propPara = pCName->_rProp[ASM_NAME_RETARGET];
742
743 if (*((LPDWORD) propThis.pv) != *((LPDWORD)propPara.pv))
744 {
745 hr = S_FALSE;
746 goto Exit;
747 }
748 }
749
750 // compare config mask
751 if (dwCmpFlags & ASM_CMPF_CONFIG_MASK)
752 {
753 propThis = _rProp[ASM_NAME_CONFIG_MASK];
754 propPara = pCName->_rProp[ASM_NAME_CONFIG_MASK];
755
756 if (*((LPDWORD) propThis.pv) != *((LPDWORD)propPara.pv))
757 {
758 hr = S_FALSE;
759 goto Exit;
760 }
761
762 }
763
764 // compare architecture
765 if (dwCmpFlags & ASM_CMPF_ARCHITECTURE)
766 {
767 propThis = _rProp[ASM_NAME_ARCHITECTURE];
768 propPara = pCName->_rProp[ASM_NAME_ARCHITECTURE];
769
770 if (propThis.cb != propPara.cb) {
771 hr = S_FALSE;
772 goto Exit;
773 }
774
775 if (propThis.cb) {
776 if (*((LPDWORD) propThis.pv) != *((LPDWORD)propPara.pv)) {
777 hr = S_FALSE;
778 goto Exit;
779 }
780 }
781 }
782
783 // Compare content type
784 if (dwCmpFlags & ASM_CMPF_CONTENT_TYPE)
785 {
786 propThis = _rProp[ASM_NAME_CONTENT_TYPE];
787 propPara = pCName->_rProp[ASM_NAME_CONTENT_TYPE];
788
789 if (*((LPDWORD)propThis.pv) != *((LPDWORD)propPara.pv))
790 {
791 hr = S_FALSE;
792 goto Exit;
793 }
794 }
795
796 // compare MVID
797 if (dwCmpFlags & ASM_CMPF_MVID)
798 {
799 propThis = _rProp[ASM_NAME_MVID];
800 propPara = pCName->_rProp[ASM_NAME_MVID];
801
802 if (propThis.cb != propPara.cb) {
803 hr = S_FALSE;
804 goto Exit;
805 }
806
807 if (propThis.cb && memcmp(propThis.pv, propPara.pv, propThis.cb)) {
808 hr = S_FALSE;
809 goto Exit;
810 }
811 }
812
813 // compare Signature
814 if (dwCmpFlags & ASM_CMPF_SIGNATURE)
815 {
816 propThis = _rProp[ASM_NAME_SIGNATURE_BLOB];
817 propPara = pCName->_rProp[ASM_NAME_SIGNATURE_BLOB];
818
819 if (propThis.cb != propPara.cb) {
820 hr = S_FALSE;
821 goto Exit;
822 }
823
824 if (propThis.cb && memcmp(propThis.pv, propPara.pv, propThis.cb)) {
825 hr = S_FALSE;
826 goto Exit;
827 }
828 }
829
830 hr = S_OK;
831Exit:
832 END_ENTRYPOINT_NOTHROW;
833 return hr;
834}
835
836// ---------------------------------------------------------------------------
837// CAssemblyName::Reserved
838// ---------------------------------------------------------------------------
839STDMETHODIMP
840CAssemblyName::Reserved(
841 /* in */ REFIID refIID,
842 /* in */ IUnknown *pUnkBindSink,
843 /* in */ IUnknown *pUnkAppCtx,
844 /* in */ LPCOLESTR szCodebaseIn,
845 /* in */ LONGLONG llFlags,
846 /* in */ LPVOID pvReserved,
847 /* in */ DWORD cbReserved,
848 /* out */ VOID **ppv)
849{
850 return E_NOTIMPL;
851}
852
853// ---------------------------------------------------------------------------
854// CAssemblyName::Clone
855// ---------------------------------------------------------------------------
856HRESULT CAssemblyName::Clone(IAssemblyName **ppName)
857{
858 HRESULT hr = S_OK;
859
860 BEGIN_ENTRYPOINT_NOTHROW;
861
862 CAssemblyName *pClone = NULL;
863
864 if (!ppName) {
865 hr = E_INVALIDARG;
866 goto Exit;
867 }
868
869 *ppName = NULL;
870
871 pClone = NEW(CAssemblyName);
872 if( !pClone ) {
873 hr = E_OUTOFMEMORY;
874 goto Exit;
875 }
876
877 hr = CopyProperties(this, pClone, NULL, 0);
878 if (FAILED(hr)) {
879 goto Exit;
880 }
881
882 *ppName = pClone;
883 (*ppName)->AddRef();
884
885Exit:
886 SAFERELEASE(pClone);
887
888 END_ENTRYPOINT_NOTHROW;
889
890 return hr;
891}
892
893// ---------------------------------------------------------------------------
894// CAssemblyName::SetPropertyInternal
895// ---------------------------------------------------------------------------
896HRESULT CAssemblyName::SetPropertyInternal(DWORD PropertyId,
897 LPCVOID pvProperty,
898 DWORD cbProperty)
899{
900 HRESULT hr = S_OK;
901 LPBYTE pbSN = NULL;
902 DWORD cbSN = 0;
903
904 // Fail if finalized.
905 if (_fIsFinalized)
906 {
907 _ASSERTE(!"SetProperty on a IAssemblyName while the name is finalized!");
908 hr = E_UNEXPECTED;
909 goto exit;
910 }
911
912 if (PropertyId >= ASM_NAME_MAX_PARAMS
913 || (!pvProperty && cbProperty))
914 {
915 _ASSERTE(!"Invalid Argument! Passed in NULL buffer with size non-zero!");
916 hr = E_INVALIDARG;
917 goto exit;
918 }
919
920 // <REVISIT_TODO> - make this a switch statement.</REVISIT_TODO>
921 if (PropertyId == ASM_NAME_MAJOR_VERSION ||
922 PropertyId == ASM_NAME_MINOR_VERSION ||
923 PropertyId == ASM_NAME_BUILD_NUMBER ||
924 PropertyId == ASM_NAME_REVISION_NUMBER)
925 {
926 if (cbProperty > sizeof(WORD)) {
927 hr = E_INVALIDARG;
928 goto exit;
929 }
930 }
931
932 // Check if public key is being set and if so,
933 // set the public key token if not already set.
934 if (PropertyId == ASM_NAME_PUBLIC_KEY)
935 {
936 // If setting true public key, generate hash.
937 if (pvProperty && cbProperty)
938 {
939 // Generate the public key token from the pk.
940 if (FAILED(hr = GetPublicKeyTokenFromPKBlob((LPBYTE) pvProperty, cbProperty, &pbSN, &cbSN)))
941 goto exit;
942
943 // Set the public key token property.
944 if (FAILED(hr = SetPropertyInternal(ASM_NAME_PUBLIC_KEY_TOKEN, pbSN, cbSN)))
945 goto exit;
946 }
947 // Otherwise expect call to reset property.
948 else if (!cbProperty)
949 {
950 if (FAILED(hr = SetPropertyInternal(ASM_NAME_PUBLIC_KEY_TOKEN, pvProperty, cbProperty)))
951 goto exit;
952 }
953
954 }
955 // Setting NULL public key clears values in public key,
956 // public key token and sets public key token flag.
957 else if (PropertyId == ASM_NAME_NULL_PUBLIC_KEY)
958 {
959 pvProperty = NULL;
960 cbProperty = 0;
961 hr = SetPropertyInternal(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, pvProperty, cbProperty);
962 goto exit;
963 }
964 // Setting or clearing public key token.
965 else if (PropertyId == ASM_NAME_PUBLIC_KEY_TOKEN)
966 {
967 // Defensive: invalid sized public key tokens should be avoided.
968 if (cbProperty > PUBLIC_KEY_TOKEN_LEN)
969 {
970 hr = SetPropertyInternal(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0);
971 hr = E_INVALIDARG;
972 goto exit;
973 }
974
975 if (pvProperty && cbProperty)
976 _fPublicKeyToken = TRUE;
977 else if (!cbProperty)
978 _fPublicKeyToken = FALSE;
979 }
980 // Setting NULL public key token clears public key token and
981 // sets public key token flag.
982 else if (PropertyId == ASM_NAME_NULL_PUBLIC_KEY_TOKEN)
983 {
984 _fPublicKeyToken = TRUE;
985 pvProperty = NULL;
986 cbProperty = 0;
987 PropertyId = ASM_NAME_PUBLIC_KEY_TOKEN;
988 }
989 else if (PropertyId == ASM_NAME_CUSTOM)
990 {
991 if (pvProperty && cbProperty)
992 _fCustom = TRUE;
993 else if (!cbProperty)
994 _fCustom = FALSE;
995 }
996 else if (PropertyId == ASM_NAME_NULL_CUSTOM)
997 {
998 _fCustom = TRUE;
999 pvProperty = NULL;
1000 cbProperty = 0;
1001 PropertyId = ASM_NAME_CUSTOM;
1002 }
1003
1004 // Setting "neutral" as the culture is the same as "" culture (meaning
1005 // culture-invariant).
1006 else if (PropertyId == ASM_NAME_CULTURE) {
1007 if (pvProperty && !FusionCompareStringI((LPWSTR)pvProperty, W("neutral"))) {
1008 pvProperty = (void *)W("");
1009 cbProperty = sizeof(W(""));
1010 }
1011 }
1012
1013 // Set property on array.
1014 hr = _rProp.Set(PropertyId, pvProperty, cbProperty);
1015
1016exit:
1017 if (SUCCEEDED(hr)) {
1018 LPWSTR pwzOld;
1019
1020 // Clear cache
1021
1022 pwzOld = InterlockedExchangeT(&_pwzTextualIdentity, NULL);
1023 SAFEDELETEARRAY(pwzOld);
1024 pwzOld = InterlockedExchangeT(&_pwzTextualIdentityILFull, NULL);
1025 SAFEDELETEARRAY(pwzOld);
1026 }
1027
1028 // Free memory allocated by crypto wrapper.
1029 if (pbSN) {
1030 StrongNameFreeBuffer(pbSN);
1031 }
1032
1033 return hr;
1034}
1035
1036
1037
1038// ---------------------------------------------------------------------------
1039// CheckFieldsForFriendAssembly
1040// ---------------------------------------------------------------------------
1041STDAPI
1042CheckFieldsForFriendAssembly(
1043 LPASSEMBLYNAME pAssemblyName)
1044{
1045 HRESULT hr = S_OK;
1046 DWORD dwSize=0;
1047
1048 // Let's look at the information they gave us in the friends declaration.
1049 // If they put in a Processor Architecture, Culture, or Version, then we'll return an error.
1050
1051 if (FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_MAJOR_VERSION, NULL, &dwSize)) ||
1052 FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_MINOR_VERSION, NULL, &dwSize)) ||
1053 FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_BUILD_NUMBER, NULL, &dwSize)) ||
1054 FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_REVISION_NUMBER, NULL, &dwSize)) ||
1055 FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_CULTURE, NULL, &dwSize)) ||
1056 FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_ARCHITECTURE, NULL, &dwSize)))
1057 {
1058 // If any of these calls failed due to an insufficient buffer, then that means
1059 // the assembly name contained them
1060 if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
1061 hr = META_E_CA_BAD_FRIENDS_ARGS;
1062 } else {
1063 if (FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, NULL, &dwSize))) {
1064
1065 //
1066 // Public Key token should not be passed to InternalsVisibleTo
1067 // attribute. This translates to the ASM_NAME_PUBLIC_KEY_TOKEN
1068 // property being set, while the full public key is not.
1069 //
1070
1071 if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
1072
1073 dwSize = 0;
1074
1075 if (FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_PUBLIC_KEY, NULL, &dwSize))) {
1076 if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
1077 hr = S_OK;
1078 } else {
1079 hr = META_E_CA_BAD_FRIENDS_ARGS;
1080 }
1081
1082 }
1083 } else {
1084 hr = S_OK;
1085 }
1086 }
1087
1088
1089 return hr;
1090}
1091
1092// ---------------------------------------------------------------------------
1093// CreateAssemblyNameObject
1094// ---------------------------------------------------------------------------
1095
1096// This is not external for CoreCLR
1097STDAPI
1098CreateAssemblyNameObject(
1099 LPASSEMBLYNAME *ppAssemblyName,
1100 LPCOLESTR szAssemblyName,
1101 DWORD dwFlags,
1102 LPVOID pvReserved)
1103{
1104
1105 HRESULT hr = S_OK;
1106
1107 BEGIN_ENTRYPOINT_NOTHROW;
1108
1109 CAssemblyName *pName = NULL;
1110
1111 if (!ppAssemblyName)
1112 {
1113 hr = E_INVALIDARG;
1114 goto exit;
1115 }
1116
1117 pName = NEW(CAssemblyName);
1118 if (!pName)
1119 {
1120 hr = E_OUTOFMEMORY;
1121 goto exit;
1122 }
1123
1124 if (dwFlags & CANOF_PARSE_DISPLAY_NAME)
1125 {
1126 hr = pName->Init(NULL, NULL);
1127 if (FAILED(hr)) {
1128 goto exit;
1129 }
1130
1131 hr = pName->Parse((LPWSTR)szAssemblyName);
1132 }
1133 else
1134 {
1135 hr = pName->Init(szAssemblyName, NULL);
1136 }
1137
1138
1139 if (SUCCEEDED(hr) && ((dwFlags & CANOF_VERIFY_FRIEND_ASSEMBLYNAME)))
1140 {
1141 hr = CheckFieldsForFriendAssembly(pName);
1142 }
1143
1144
1145 if (FAILED(hr))
1146 {
1147 SAFERELEASE(pName);
1148 goto exit;
1149 }
1150
1151 *ppAssemblyName = pName;
1152
1153exit:
1154 END_ENTRYPOINT_NOTHROW;
1155 return hr;
1156}
1157
1158// ---------------------------------------------------------------------------
1159// CreateAssemblyNameObjectFromMetaData
1160// ---------------------------------------------------------------------------
1161STDAPI
1162CreateAssemblyNameObjectFromMetaData(
1163 LPASSEMBLYNAME *ppAssemblyName,
1164 LPCOLESTR szAssemblyName,
1165 ASSEMBLYMETADATA *pamd,
1166 LPVOID pvReserved)
1167{
1168
1169 HRESULT hr = S_OK;
1170 CAssemblyName *pName = NULL;
1171
1172 pName = NEW(CAssemblyName);
1173 if (!pName)
1174 {
1175 hr = E_OUTOFMEMORY;
1176 goto exit;
1177 }
1178
1179 hr = pName->Init(szAssemblyName, pamd);
1180
1181 if (FAILED(hr))
1182 {
1183 SAFERELEASE(pName);
1184 goto exit;
1185 }
1186
1187 *ppAssemblyName = pName;
1188
1189exit:
1190 return hr;
1191}
1192
1193// ---------------------------------------------------------------------------
1194// CAssemblyName constructor
1195// ---------------------------------------------------------------------------
1196CAssemblyName::CAssemblyName()
1197{
1198 _dwSig = 0x454d414e; /* 'EMAN' */
1199 _fIsFinalized = FALSE;
1200 _fPublicKeyToken = FALSE;
1201 _fCustom = TRUE;
1202 _cRef = 1;
1203 _pwzPathModifier = NULL;
1204 _pwzTextualIdentity = NULL;
1205 _pwzTextualIdentityILFull = NULL;
1206}
1207
1208// ---------------------------------------------------------------------------
1209// CAssemblyName destructor
1210// ---------------------------------------------------------------------------
1211CAssemblyName::~CAssemblyName()
1212{
1213 SAFEDELETEARRAY(_pwzPathModifier);
1214 SAFEDELETEARRAY(_pwzTextualIdentity);
1215 SAFEDELETEARRAY(_pwzTextualIdentityILFull);
1216}
1217
1218// ---------------------------------------------------------------------------
1219// CAssemblyName::IsStronglyNamed
1220// ---------------------------------------------------------------------------
1221BOOL CAssemblyName::IsStronglyNamed(IAssemblyName *pName)
1222{
1223 CAssemblyName *pCName = static_cast<CAssemblyName *> (pName);
1224 _ASSERTE(pCName);
1225
1226 return (pCName->_rProp[ASM_NAME_PUBLIC_KEY_TOKEN].cb != 0);
1227}
1228
1229// ---------------------------------------------------------------------------
1230// CAssemblyName::IsPartial
1231// ---------------------------------------------------------------------------
1232BOOL CAssemblyName::IsPartial(IAssemblyName *pIName,
1233 LPDWORD pdwCmpMask)
1234{
1235 DWORD dwCmpMask = 0;
1236 BOOL fPartial = FALSE;
1237
1238 static const ASM_NAME rNameFlags[] ={ASM_NAME_NAME,
1239 ASM_NAME_CULTURE,
1240 ASM_NAME_PUBLIC_KEY_TOKEN,
1241 ASM_NAME_MAJOR_VERSION,
1242 ASM_NAME_MINOR_VERSION,
1243 ASM_NAME_BUILD_NUMBER,
1244 ASM_NAME_REVISION_NUMBER,
1245 ASM_NAME_CUSTOM
1246 };
1247
1248 static const ASM_CMP_FLAGS rCmpFlags[] = {ASM_CMPF_NAME,
1249 ASM_CMPF_CULTURE,
1250 ASM_CMPF_PUBLIC_KEY_TOKEN,
1251 ASM_CMPF_MAJOR_VERSION,
1252 ASM_CMPF_MINOR_VERSION,
1253 ASM_CMPF_BUILD_NUMBER,
1254 ASM_CMPF_REVISION_NUMBER,
1255 ASM_CMPF_CUSTOM
1256 };
1257
1258 CAssemblyName *pName = static_cast<CAssemblyName*> (pIName); // dynamic_cast
1259 _ASSERTE(pName);
1260
1261 DWORD iNumOfComparison = sizeof(rNameFlags) / sizeof(rNameFlags[0]);
1262
1263 for (DWORD i = 0; i < iNumOfComparison; i++)
1264 {
1265 if (pName->_rProp[rNameFlags[i]].cb
1266 || (rNameFlags[i] == ASM_NAME_PUBLIC_KEY_TOKEN
1267 && pName->_fPublicKeyToken)
1268 || (rNameFlags[i] == ASM_NAME_CUSTOM
1269 && pName->_fCustom))
1270 {
1271 dwCmpMask |= rCmpFlags[i];
1272 }
1273 else {
1274 fPartial = TRUE;
1275 }
1276 }
1277
1278 if(pName->_rProp[ASM_NAME_ARCHITECTURE].cb) {
1279 dwCmpMask |= ASM_CMPF_ARCHITECTURE;
1280 }
1281
1282 if (pName->_rProp[ASM_NAME_RETARGET].cb) {
1283 dwCmpMask |= ASM_CMPF_RETARGET;
1284 }
1285
1286 if (pName->_rProp[ASM_NAME_CONTENT_TYPE].cb != 0)
1287 {
1288 dwCmpMask |= ASM_CMPF_CONTENT_TYPE;
1289 }
1290
1291 if (pName->_rProp[ASM_NAME_CONFIG_MASK].cb) {
1292 dwCmpMask |= ASM_CMPF_CONFIG_MASK;
1293 }
1294
1295 if (pName->_rProp[ASM_NAME_MVID].cb) {
1296 dwCmpMask |= ASM_CMPF_MVID;
1297 }
1298
1299 if (pName->_rProp[ASM_NAME_SIGNATURE_BLOB].cb) {
1300 dwCmpMask |= ASM_CMPF_SIGNATURE;
1301 }
1302
1303 if (pdwCmpMask)
1304 *pdwCmpMask = dwCmpMask;
1305
1306 return fPartial;
1307}
1308
1309// ---------------------------------------------------------------------------
1310// CAssemblyName::Init
1311// ---------------------------------------------------------------------------
1312HRESULT
1313CAssemblyName::Init(LPCTSTR pszAssemblyName, ASSEMBLYMETADATA *pamd)
1314{
1315 HRESULT hr = S_OK;
1316
1317 // Name
1318 if (pszAssemblyName)
1319 {
1320 hr = SetProperty(ASM_NAME_NAME, (LPTSTR) pszAssemblyName,
1321 (DWORD)((wcslen(pszAssemblyName)+1) * sizeof(TCHAR)));
1322 if (FAILED(hr))
1323 goto exit;
1324 }
1325
1326 if (pamd) {
1327 // Major version
1328 if (FAILED(hr = SetProperty(ASM_NAME_MAJOR_VERSION,
1329 &pamd->usMajorVersion, sizeof(WORD)))
1330
1331 // Minor version
1332 || FAILED(hr = SetProperty(ASM_NAME_MINOR_VERSION,
1333 &pamd->usMinorVersion, sizeof(WORD)))
1334
1335 // Revision number
1336 || FAILED(hr = SetProperty(ASM_NAME_REVISION_NUMBER,
1337 &pamd->usRevisionNumber, sizeof(WORD)))
1338
1339 // Build number
1340 || FAILED(hr = SetProperty(ASM_NAME_BUILD_NUMBER,
1341 &pamd->usBuildNumber, sizeof(WORD)))
1342
1343 // Culture
1344 || FAILED(hr = SetProperty(ASM_NAME_CULTURE,
1345 pamd->szLocale, pamd->cbLocale * sizeof(WCHAR)))
1346 )
1347 {
1348 goto exit;
1349 }
1350 }
1351
1352exit:
1353 return hr;
1354}
1355
1356// ---------------------------------------------------------------------------
1357// CAssemblyName::Parse
1358// ---------------------------------------------------------------------------
1359HRESULT CAssemblyName::Parse(__in_z LPCWSTR szDisplayName)
1360{
1361 HRESULT hr = S_OK;
1362
1363 if (!(szDisplayName && *szDisplayName))
1364 {
1365 hr = E_INVALIDARG;
1366 goto exit;
1367 }
1368
1369 EX_TRY {
1370 BINDER_SPACE::AssemblyIdentity assemblyIdentity;
1371 SString displayName(szDisplayName);
1372
1373 // Parse the textual identity
1374 hr = BINDER_SPACE::TextualIdentityParser::Parse(displayName, &assemblyIdentity);
1375 if (FAILED(hr)) {
1376 goto exit;
1377 }
1378
1379 // Set name.
1380 hr = SetProperty(ASM_NAME_NAME,
1381 (LPVOID) assemblyIdentity.m_simpleName.GetUnicode(),
1382 (assemblyIdentity.m_simpleName.GetCount() + 1) * sizeof(WCHAR));
1383 if (FAILED(hr)) {
1384 goto exit;
1385 }
1386
1387 // Set version.
1388 if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION)) {
1389 WORD wVersionPart = 0;
1390
1391 wVersionPart = (WORD) assemblyIdentity.m_version.GetMajor();
1392 hr = SetProperty(ASM_NAME_MAJOR_VERSION, &wVersionPart, sizeof(WORD));
1393 if (FAILED(hr)) {
1394 goto exit;
1395 }
1396
1397 wVersionPart = (WORD) assemblyIdentity.m_version.GetMinor();
1398 hr = SetProperty(ASM_NAME_MINOR_VERSION, &wVersionPart, sizeof(WORD));
1399 if (FAILED(hr)) {
1400 goto exit;
1401 }
1402
1403 wVersionPart = (WORD) assemblyIdentity.m_version.GetBuild();
1404 hr = SetProperty(ASM_NAME_BUILD_NUMBER, &wVersionPart, sizeof(WORD));
1405 if (FAILED(hr)) {
1406 goto exit;
1407 }
1408
1409 wVersionPart = (WORD) assemblyIdentity.m_version.GetRevision();
1410 hr = SetProperty(ASM_NAME_REVISION_NUMBER, &wVersionPart, sizeof(WORD));
1411 if (FAILED(hr)) {
1412 goto exit;
1413 }
1414 }
1415
1416 // Set culture.
1417 if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE)) {
1418 hr = SetProperty(ASM_NAME_CULTURE,
1419 (LPVOID) assemblyIdentity.m_cultureOrLanguage.GetUnicode(),
1420 (assemblyIdentity.m_cultureOrLanguage.GetCount()+1) * sizeof(WCHAR));
1421 if (FAILED(hr)) {
1422 goto exit;
1423 }
1424 }
1425
1426 // Set public key (token) or NULL flag.
1427 if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY)) {
1428 SBuffer &publicKeyBuffer = assemblyIdentity.m_publicKeyOrTokenBLOB;
1429 const void *pBytes = publicKeyBuffer;
1430
1431 // This also computes and sets the public key token.
1432 hr = SetProperty(ASM_NAME_PUBLIC_KEY, (void *) pBytes, publicKeyBuffer.GetSize());
1433 if (FAILED(hr)) {
1434 goto exit;
1435 }
1436 }
1437 else if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN)) {
1438 SBuffer &publicKeyTokenBuffer = assemblyIdentity.m_publicKeyOrTokenBLOB;
1439 const void *pBytes = publicKeyTokenBuffer;
1440
1441 hr = SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN,
1442 (LPVOID) pBytes,
1443 publicKeyTokenBuffer.GetSize());
1444 if (FAILED(hr)) {
1445 goto exit;
1446 }
1447 }
1448 else if (assemblyIdentity.
1449 Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL)) {
1450 hr = SetProperty(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0);
1451 if (FAILED(hr)) {
1452 goto exit;
1453 }
1454 }
1455
1456 // Set architecture.
1457 if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE)) {
1458 PEKIND peKind = assemblyIdentity.m_kProcessorArchitecture;
1459
1460 hr = SetProperty(ASM_NAME_ARCHITECTURE, (LPVOID) &peKind, sizeof(PEKIND));
1461 if(FAILED(hr)) {
1462 goto exit;
1463 }
1464 }
1465
1466 // Set retargetable flag.
1467 if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE)) {
1468 BOOL fRetarget = TRUE;
1469
1470 if (FAILED(hr = SetProperty(ASM_NAME_RETARGET, &fRetarget, sizeof(BOOL)))) {
1471 goto exit;
1472 }
1473 }
1474
1475 // Set content type.
1476 if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE)) {
1477 DWORD dwContentType = assemblyIdentity.m_kContentType;
1478
1479 hr = SetProperty(ASM_NAME_CONTENT_TYPE, &dwContentType, sizeof(dwContentType));
1480 IfFailGoto(hr, exit);
1481 }
1482
1483 // Set custom or NULL flag.
1484 if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM)) {
1485 SBuffer &customBuffer = assemblyIdentity.m_customBLOB;
1486 const void *pBytes = customBuffer;
1487
1488 hr = SetProperty(ASM_NAME_CUSTOM, (void *) pBytes, customBuffer.GetSize());
1489 if (FAILED(hr)) {
1490 goto exit;
1491 }
1492 }
1493 else if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL)) {
1494 hr = SetProperty(ASM_NAME_NULL_CUSTOM, NULL, 0);
1495 if (FAILED(hr)) {
1496 goto exit;
1497 }
1498 }
1499 }
1500 EX_CATCH_HRESULT(hr);
1501
1502 exit:
1503 return hr;
1504}
1505
1506// ---------------------------------------------------------------------------
1507// CAssemblyName::GetVersion
1508// ---------------------------------------------------------------------------
1509HRESULT
1510CAssemblyName::GetVersion(
1511 /* [in] */ DWORD dwMajorVersionEnumValue,
1512 /* [out] */ LPDWORD pdwVersionHi,
1513 /* [out] */ LPDWORD pdwVersionLow)
1514{
1515 HRESULT hr = S_OK;
1516 DWORD cb = sizeof(WORD);
1517 WORD wVerMajor = 0, wVerMinor = 0, wRevNo = 0, wBldNo = 0;
1518
1519 if(!pdwVersionHi || !pdwVersionLow) {
1520 hr = E_INVALIDARG;
1521 goto Exit;
1522 }
1523
1524 *pdwVersionHi = *pdwVersionLow = 0;
1525
1526 if(FAILED( (hr = GetProperty(dwMajorVersionEnumValue, &wVerMajor, &(cb = sizeof(WORD))))))
1527 goto Exit;
1528 if (cb == 0) {
1529 hr = FUSION_E_INVALID_NAME;
1530 goto Exit;
1531 }
1532
1533 if(FAILED( (hr = GetProperty(dwMajorVersionEnumValue+1, &wVerMinor, &(cb = sizeof(WORD))))))
1534 goto Exit;
1535
1536 if (cb == 0) {
1537 hr = FUSION_E_INVALID_NAME;
1538 goto Exit;
1539 }
1540
1541 if(FAILED( (hr = GetProperty(dwMajorVersionEnumValue+2, &wBldNo, &(cb = sizeof(WORD))))))
1542 goto Exit;
1543 if (cb == 0) {
1544 hr = FUSION_E_INVALID_NAME;
1545 goto Exit;
1546 }
1547
1548 if(FAILED( (hr = GetProperty(dwMajorVersionEnumValue+3, &wRevNo, &(cb = sizeof(WORD))))))
1549 goto Exit;
1550
1551 if (cb == 0) {
1552 hr = FUSION_E_INVALID_NAME;
1553 goto Exit;
1554 }
1555
1556 *pdwVersionHi = MAKELONG(wVerMinor, wVerMajor);
1557 *pdwVersionLow = MAKELONG(wRevNo, wBldNo);
1558
1559Exit:
1560 return hr;
1561}
1562
1563// ---------------------------------------------------------------------------
1564// CAssemblyName::CopyProperties
1565// ---------------------------------------------------------------------------
1566HRESULT
1567CAssemblyName::CopyProperties(CAssemblyName *pSource,
1568 CAssemblyName *pTarget,
1569 const DWORD properties[],
1570 DWORD dwSize)
1571{
1572 HRESULT hr = S_OK;
1573 DWORD i = 0;
1574 FusionProperty prop;
1575
1576 _ASSERTE(pSource && pTarget);
1577
1578 if (!dwSize) {
1579 for( i = 0; i < ASM_NAME_MAX_PARAMS; i ++) {
1580 prop = pSource->_rProp[i];
1581
1582 if (prop.cb) {
1583 if (FAILED(hr = pTarget->SetProperty(i, prop.pv, prop.cb))) {
1584 goto Exit;
1585 }
1586 }
1587 }
1588 }
1589 else {
1590 for (i = 0; i<dwSize; i++) {
1591 _ASSERTE(properties[i] < ASM_NAME_MAX_PARAMS);
1592 prop = pSource->_rProp[properties[i]];
1593 if (prop.cb) {
1594 if (FAILED(hr = pTarget->SetProperty(properties[i], prop.pv, prop.cb))) {
1595 goto Exit;
1596 }
1597 }
1598 }
1599 }
1600
1601 pTarget->_fPublicKeyToken = pSource->_fPublicKeyToken;
1602 pTarget->_fCustom = pSource->_fCustom;
1603
1604 if (pSource->_pwzPathModifier) {
1605 pTarget->_pwzPathModifier = WSTRDupDynamic(pSource->_pwzPathModifier);
1606 if(!pTarget->_pwzPathModifier) {
1607 hr = E_OUTOFMEMORY;
1608 goto Exit;
1609 }
1610 }
1611
1612Exit:
1613 return hr;
1614}
1615
1616namespace LegacyFusion
1617{
1618 HRESULT SetStringProperty(IAssemblyName *pIAssemblyName,
1619 DWORD dwPropertyId,
1620 SString &value)
1621 {
1622 CAssemblyName *pAssemblyName = static_cast<CAssemblyName *>(pIAssemblyName);
1623 const WCHAR *pValue = value.GetUnicode();
1624 DWORD dwCBValue = (value.GetCount() + 1) * sizeof(WCHAR);
1625
1626 return pAssemblyName->SetPropertyInternal(dwPropertyId,
1627 const_cast<WCHAR *>(pValue),
1628 dwCBValue);
1629 }
1630
1631 HRESULT SetBufferProperty(IAssemblyName *pIAssemblyName,
1632 DWORD dwPropertyId,
1633 SBuffer &value)
1634 {
1635 CAssemblyName *pAssemblyName = static_cast<CAssemblyName *>(pIAssemblyName);
1636 const BYTE *pValue = value; // special operator
1637 DWORD dwCBValue = value.GetSize() * sizeof(BYTE);
1638
1639 return pAssemblyName->SetPropertyInternal(dwPropertyId,
1640 const_cast<BYTE *>(pValue),
1641 dwCBValue);
1642 }
1643
1644 HRESULT SetWordProperty(IAssemblyName *pIAssemblyName,
1645 DWORD dwPropertyId,
1646 DWORD dwValue)
1647 {
1648 CAssemblyName *pAssemblyName = static_cast<CAssemblyName *>(pIAssemblyName);
1649 WORD wValue = static_cast<WORD>(dwValue);
1650 DWORD wCBValue = sizeof(WORD);
1651
1652 // This file-internal function is and must be only used to set version fields
1653 PREFIX_ASSUME((dwPropertyId == ASM_NAME_MAJOR_VERSION) ||
1654 (dwPropertyId == ASM_NAME_MINOR_VERSION) ||
1655 (dwPropertyId == ASM_NAME_BUILD_NUMBER) ||
1656 (dwPropertyId == ASM_NAME_REVISION_NUMBER));
1657
1658 return pAssemblyName->SetPropertyInternal(dwPropertyId, &wValue, wCBValue);
1659 }
1660
1661 HRESULT SetDwordProperty(IAssemblyName *pIAssemblyName,
1662 DWORD dwPropertyId,
1663 DWORD dwValue)
1664 {
1665 CAssemblyName *pAssemblyName = static_cast<CAssemblyName *>(pIAssemblyName);
1666 DWORD dwCBValue = sizeof(DWORD);
1667
1668 return pAssemblyName->SetPropertyInternal(dwPropertyId, &dwValue, dwCBValue);
1669 }
1670};
1671namespace fusion
1672{
1673 namespace util
1674 {
1675 namespace priv
1676 {
1677 inline bool IsNullProperty(DWORD dwProperty)
1678 {
1679 LIMITED_METHOD_CONTRACT;
1680 return dwProperty == ASM_NAME_NULL_PUBLIC_KEY_TOKEN ||
1681 dwProperty == ASM_NAME_NULL_PUBLIC_KEY ||
1682 dwProperty == ASM_NAME_NULL_CUSTOM;
1683 }
1684
1685 HRESULT ConvertToUtf8(PCWSTR wzStr, __deref_out UTF8** pszStr)
1686 {
1687 HRESULT hr = S_OK;
1688
1689 _ASSERTE(wzStr != nullptr && pszStr != nullptr);
1690 if (wzStr == nullptr || pszStr == nullptr)
1691 {
1692 return E_INVALIDARG;
1693 }
1694
1695 DWORD cbSize = WszWideCharToMultiByte(CP_UTF8, 0, wzStr, -1, NULL, 0, NULL, NULL);
1696 if(cbSize == 0)
1697 {
1698 return SUCCEEDED(hr = HRESULT_FROM_GetLastError()) ? E_UNEXPECTED : hr;
1699 }
1700
1701 NewArrayHolder<UTF8> szStr = new (nothrow) UTF8[cbSize];
1702 IfNullRet(szStr);
1703
1704 cbSize = WszWideCharToMultiByte(CP_UTF8, 0, wzStr, -1, static_cast<LPSTR>(szStr), cbSize, NULL, NULL);
1705 if(cbSize == 0)
1706 {
1707 return SUCCEEDED(hr = HRESULT_FROM_GetLastError()) ? E_UNEXPECTED : hr;
1708 }
1709
1710 *pszStr = szStr.Extract();
1711 return S_OK;
1712 }
1713 }
1714
1715 // Non-allocating helper.
1716 HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PVOID pBuf, DWORD *pcbBuf)
1717 {
1718 LIMITED_METHOD_CONTRACT;
1719 HRESULT hr = S_OK;
1720
1721 _ASSERTE(pName != nullptr && pcbBuf != nullptr);
1722 if (pName == nullptr || pcbBuf == nullptr)
1723 {
1724 return E_INVALIDARG;
1725 }
1726
1727 hr = pName->GetProperty(dwProperty, pBuf, pcbBuf);
1728 IfFailRet(hr);
1729
1730 // Zero-length non-null property means there is no value.
1731 if (hr == S_OK && *pcbBuf == 0 && !priv::IsNullProperty(dwProperty))
1732 {
1733 hr = S_FALSE;
1734 }
1735
1736 return hr;
1737 }
1738
1739 // Allocating helper.
1740 HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PBYTE * ppBuf, DWORD *pcbBuf)
1741 {
1742 LIMITED_METHOD_CONTRACT;
1743 HRESULT hr = S_OK;
1744
1745 _ASSERTE(ppBuf != nullptr && (*ppBuf == nullptr || pcbBuf != nullptr));
1746 if (ppBuf == nullptr || (*ppBuf != nullptr && pcbBuf == nullptr))
1747 {
1748 return E_INVALIDARG;
1749 }
1750
1751 DWORD cbBuf = 0;
1752 if (pcbBuf == nullptr)
1753 pcbBuf = &cbBuf;
1754
1755 hr = GetProperty(pName, dwProperty, *ppBuf, pcbBuf);
1756
1757 // No provided buffer constitutes a request for one to be allocated.
1758 if (*ppBuf == nullptr)
1759 {
1760 // If it's a null property, allocate a single-byte array to provide consistency.
1761 if (hr == S_OK && priv::IsNullProperty(dwProperty))
1762 {
1763 *ppBuf = new (nothrow) BYTE[1];
1764 IfNullRet(*ppBuf);
1765 }
1766 // Great, get the value.
1767 else if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
1768 {
1769 NewArrayHolder<BYTE> pBuf = new (nothrow) BYTE[*pcbBuf];
1770 IfNullRet(pBuf);
1771 hr = pName->GetProperty(dwProperty, pBuf, pcbBuf);
1772 IfFailRet(hr);
1773 *ppBuf = pBuf.Extract();
1774 hr = S_OK;
1775 }
1776 }
1777
1778 return hr;
1779 }
1780
1781 HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, SString & ssVal)
1782 {
1783 LIMITED_METHOD_CONTRACT;
1784 HRESULT hr = S_OK;
1785
1786 _ASSERTE(pName != nullptr);
1787 if (pName == nullptr)
1788 {
1789 return E_INVALIDARG;
1790 }
1791
1792 DWORD cbSize = 0;
1793 hr = GetProperty(pName, dwProperty, static_cast<PBYTE>(nullptr), &cbSize);
1794
1795 if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
1796 {
1797 EX_TRY
1798 {
1799 PWSTR wzNameBuf = ssVal.OpenUnicodeBuffer(cbSize / sizeof(WCHAR) - 1);
1800 hr = GetProperty(pName, dwProperty, reinterpret_cast<PBYTE>(wzNameBuf), &cbSize);
1801 ssVal.CloseBuffer();
1802 IfFailThrow(hr);
1803 ssVal.Normalize();
1804 }
1805 EX_CATCH_HRESULT(hr);
1806 IfFailRet(hr);
1807 }
1808
1809 return hr;
1810 }
1811
1812 HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, __deref_out WCHAR ** pwzVal)
1813 {
1814 LIMITED_METHOD_CONTRACT;
1815 HRESULT hr = S_OK;
1816
1817 _ASSERTE(pName != nullptr && pwzVal != nullptr);
1818 if (pName == nullptr || pwzVal == nullptr)
1819 {
1820 return E_INVALIDARG;
1821 }
1822
1823 DWORD cbSize = 0;
1824 hr = pName->GetProperty(dwProperty, NULL, &cbSize);
1825
1826 if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
1827 {
1828 NewArrayHolder<WCHAR> wzVal = reinterpret_cast<PWSTR>(new (nothrow) BYTE[cbSize]);
1829 IfNullRet(wzVal);
1830 hr = pName->GetProperty(dwProperty, reinterpret_cast<PBYTE>(static_cast<PWSTR>(wzVal)), &cbSize);
1831 IfFailRet(hr);
1832 *pwzVal = wzVal.Extract();
1833 }
1834
1835 return hr;
1836 }
1837
1838 HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, __deref_out UTF8 **pwzOut)
1839 {
1840 LIMITED_METHOD_CONTRACT;
1841 HRESULT hr = S_OK;
1842
1843 if (pwzOut == nullptr)
1844 return E_INVALIDARG;
1845
1846 SmallStackSString ssStr;
1847 hr = GetProperty(pName, dwProperty, ssStr);
1848 IfFailRet(hr);
1849 hr = priv::ConvertToUtf8(ssStr, pwzOut);
1850 IfFailRet(hr);
1851 return hr;
1852 }
1853
1854
1855 }
1856}
1857
1858