Fix trigger for tier 1 call counting delay (#17477)
[platform/upstream/coreclr.git] / src / binder / fusionassemblyname.cpp
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 // ---------------------------------------------------------------------------
34 namespace
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 // ---------------------------------------------------------------------------
54 CPropertyArray::CPropertyArray()
55 {
56     _dwSig = 0x504f5250; /* 'PORP' */
57     memset(&_rProp, 0, ASM_NAME_MAX_PARAMS * sizeof(FusionProperty));
58 }
59
60 // ---------------------------------------------------------------------------
61 // CPropertyArray dtor
62 // ---------------------------------------------------------------------------
63 CPropertyArray::~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 // ---------------------------------------------------------------------------
81 HRESULT 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
129 exit:
130     return hr;
131 }     
132
133 // ---------------------------------------------------------------------------
134 // CPropertyArray::Get
135 // ---------------------------------------------------------------------------
136 HRESULT 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         
162 exit:
163     return hr;
164 }     
165
166 // ---------------------------------------------------------------------------
167 // CPropertyArray::operator []
168 // Wraps DWORD optimization test.
169 // ---------------------------------------------------------------------------
170 FusionProperty 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 // ---------------------------------------------------------------------------
185 STDMETHODIMP_(ULONG)
186 CAssemblyName::AddRef()
187 {
188     return InterlockedIncrement(&_cRef);
189 }
190
191 // ---------------------------------------------------------------------------
192 // CAssemblyName::Release
193 // ---------------------------------------------------------------------------
194 STDMETHODIMP_(ULONG)
195 CAssemblyName::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 // ---------------------------------------------------------------------------
209 STDMETHODIMP
210 CAssemblyName::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 // ---------------------------------------------------------------------------
247 STDMETHODIMP
248 CAssemblyName::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 // ---------------------------------------------------------------------------
265 STDMETHODIMP
266 CAssemblyName::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 // ---------------------------------------------------------------------------
302 STDMETHODIMP
303 CAssemblyName::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 // ---------------------------------------------------------------------------
315 STDMETHODIMP
316 CAssemblyName::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 // ---------------------------------------------------------------------------
503 STDMETHODIMP
504 CAssemblyName::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 // ---------------------------------------------------------------------------
522 STDMETHODIMP
523 CAssemblyName::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 // ---------------------------------------------------------------------------
540 STDMETHODIMP
541 CAssemblyName::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;
831 Exit:
832     END_ENTRYPOINT_NOTHROW;
833     return hr;
834 }
835
836 // ---------------------------------------------------------------------------
837 // CAssemblyName::Reserved
838 // ---------------------------------------------------------------------------
839 STDMETHODIMP
840 CAssemblyName::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 // ---------------------------------------------------------------------------
856 HRESULT 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
885 Exit:
886     SAFERELEASE(pClone);
887
888     END_ENTRYPOINT_NOTHROW;
889
890     return hr;
891 }
892
893 // ---------------------------------------------------------------------------
894 // CAssemblyName::SetPropertyInternal
895 // ---------------------------------------------------------------------------
896 HRESULT 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
1016 exit:
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 // ---------------------------------------------------------------------------
1041 STDAPI
1042 CheckFieldsForFriendAssembly(
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
1097 STDAPI
1098 CreateAssemblyNameObject(
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
1153 exit:
1154     END_ENTRYPOINT_NOTHROW;
1155     return hr;
1156 }
1157
1158 // ---------------------------------------------------------------------------
1159 // CreateAssemblyNameObjectFromMetaData
1160 // ---------------------------------------------------------------------------
1161 STDAPI
1162 CreateAssemblyNameObjectFromMetaData(
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
1189 exit:
1190     return hr;
1191 }
1192
1193 // ---------------------------------------------------------------------------
1194 // CAssemblyName constructor
1195 // ---------------------------------------------------------------------------
1196 CAssemblyName::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 // ---------------------------------------------------------------------------
1211 CAssemblyName::~CAssemblyName()
1212 {
1213     SAFEDELETEARRAY(_pwzPathModifier);
1214     SAFEDELETEARRAY(_pwzTextualIdentity);
1215     SAFEDELETEARRAY(_pwzTextualIdentityILFull);
1216 }
1217
1218 // ---------------------------------------------------------------------------
1219 // CAssemblyName::IsStronglyNamed
1220 // ---------------------------------------------------------------------------
1221 BOOL 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 // ---------------------------------------------------------------------------
1232 BOOL 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 // ---------------------------------------------------------------------------
1312 HRESULT
1313 CAssemblyName::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             (lstrlenW(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
1352 exit:
1353     return hr;
1354 }
1355
1356 // ---------------------------------------------------------------------------
1357 // CAssemblyName::Parse
1358 // ---------------------------------------------------------------------------
1359 HRESULT 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 // ---------------------------------------------------------------------------
1509 HRESULT
1510 CAssemblyName::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
1559 Exit:
1560     return hr;
1561 }
1562
1563 // ---------------------------------------------------------------------------
1564 // CAssemblyName::CopyProperties
1565 // ---------------------------------------------------------------------------
1566 HRESULT
1567 CAssemblyName::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
1612 Exit:
1613     return hr;
1614 }
1615
1616 namespace 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 };
1671 namespace 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