Merge pull request #24002 from sandreenko/fixDesktopFailure
[platform/upstream/coreclr.git] / src / ilasm / asmman.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 // asmman.cpp - manifest info handling (implementation of class AsmMan, see asmman.hpp)
6 //
7
8 //
9 #include "ilasmpch.h"
10
11 #include "assembler.h"
12 #include "strongname.h"
13 #include <limits.h>
14 #include <fusion.h>
15
16 extern WCHAR*   pwzInputFiles[];
17
18 BinStr* BinStrToUnicode(BinStr* pSource, bool Swap)
19 {
20     if(pSource)
21     {
22         pSource->appendInt8(0);
23         BinStr* tmp = new BinStr();
24         char*   pb = (char*)(pSource->ptr());
25         int l=pSource->length(), L = sizeof(WCHAR)*l;
26         if(tmp)
27         {
28             WCHAR*  wz = (WCHAR*)(tmp->getBuff(L));
29             if(wz)
30             {
31                 memset(wz,0,L);
32                 WszMultiByteToWideChar(g_uCodePage,0,pb,-1,wz,l);
33                 tmp->remove(L-(DWORD)wcslen(wz)*sizeof(WCHAR));
34 #if BIGENDIAN
35                 if (Swap)
36                     SwapStringLength(wz, (DWORD)wcslen(wz));
37 #endif
38                 delete pSource;
39             }
40             else
41             {
42                 delete tmp;
43                 tmp = NULL;
44                 fprintf(stderr,"\nOut of memory!\n");
45             }
46         }
47         else
48             fprintf(stderr,"\nOut of memory!\n");
49         return tmp;
50     }
51     return NULL;
52 }
53
54 AsmManFile*         AsmMan::GetFileByName(__in __nullterminated char* szFileName)
55 {
56     AsmManFile* ret = NULL;
57     if(szFileName)
58     {
59         //AsmManFile X;
60         //X.szName = szFileName;
61         //ret = m_FileLst.FIND(&X);
62         //X.szName = NULL;
63         for(int i=0; (ret = m_FileLst.PEEK(i))&&strcmp(ret->szName,szFileName); i++);
64     }
65     return ret;
66 }
67
68 mdToken             AsmMan::GetFileTokByName(__in __nullterminated char* szFileName)
69 {
70     AsmManFile* tmp = GetFileByName(szFileName);
71     return(tmp ? tmp->tkTok : mdFileNil);
72 }
73
74 AsmManComType*          AsmMan::GetComTypeByName(__in_opt __nullterminated char* szComTypeName,
75                                                  __in_opt __nullterminated char* szComEnclosingTypeName)
76 {
77     AsmManComType*  ret = NULL;
78     if(szComTypeName)
79     {
80         //AsmManComType X;
81         //X.szName = szComTypeName;
82         //ret = m_ComTypeLst.FIND(&X);
83         //X.szName = NULL;
84         for(int i=0; (ret = m_ComTypeLst.PEEK(i)) != NULL; i++)
85         {
86             if (strcmp(ret->szName, szComTypeName) == 0)
87             {
88                 if (ret->szComTypeName == NULL && szComEnclosingTypeName == NULL)
89                 {
90                     break;
91                 }
92
93                 if (ret->szComTypeName != NULL && szComEnclosingTypeName != NULL)
94                 {
95                     if (strcmp(ret->szComTypeName, szComEnclosingTypeName) == 0)
96                     {
97                         break;
98                     }
99                 }
100             }
101         }
102     }
103     return ret;
104 }
105
106 mdToken             AsmMan::GetComTypeTokByName(
107     __in_opt __nullterminated char* szComTypeName,
108     __in_opt __nullterminated char* szComEnclosingTypeName)
109 {
110     AsmManComType* tmp = GetComTypeByName(szComTypeName, szComEnclosingTypeName);
111     return(tmp ? tmp->tkTok : mdExportedTypeNil);
112 }
113
114 AsmManAssembly*     AsmMan::GetAsmRefByName(__in __nullterminated const char* szAsmRefName)
115 {
116     AsmManAssembly* ret = NULL;
117     if(szAsmRefName)
118     {
119         //AsmManAssembly X;
120         //X.szAlias = szAsmRefName;
121         //ret = m_AsmRefLst.FIND(&X);
122         //X.szAlias = NULL;
123         DWORD L = (DWORD)strlen(szAsmRefName);
124         for(int i=0; (ret = m_AsmRefLst.PEEK(i))&&
125             ((ret->dwAlias != L)||strcmp(ret->szAlias,szAsmRefName)); i++);
126     }
127     return ret;
128 }
129 mdToken             AsmMan::GetAsmRefTokByName(__in __nullterminated const char* szAsmRefName)
130 {
131     AsmManAssembly* tmp = GetAsmRefByName(szAsmRefName);
132     return(tmp ? tmp->tkTok : mdAssemblyRefNil);
133 }
134 AsmManAssembly*     AsmMan::GetAsmRefByAsmName(__in __nullterminated const char* szAsmName)
135 {
136     AsmManAssembly* ret = NULL;
137     if(szAsmName)
138     {
139         for(int i=0; (ret = m_AsmRefLst.PEEK(i))&&
140             (strcmp(ret->szName,szAsmName)); i++);
141     }
142     return ret;
143 }
144
145 //==============================================================================================================
146 void    AsmMan::SetModuleName(__inout_opt __nullterminated char* szName)
147 {
148     if(m_szScopeName == NULL)    // ignore all duplicate declarations
149     {
150         if(szName && *szName)
151         {
152             ULONG L = (ULONG)strlen(szName);
153             if(L >= MAX_SCOPE_LENGTH)
154             {
155                 ((Assembler*)m_pAssembler)->report->warn("Module name too long (%d chars, max.allowed: %d chars), truncated\n",L,MAX_SCOPE_LENGTH-1);
156                 szName[MAX_SCOPE_LENGTH-1] = 0;
157             }
158             m_szScopeName = szName;
159             strcpy_s(((Assembler*)m_pAssembler)->m_szScopeName, MAX_SCOPE_LENGTH, szName);
160         }
161     }
162 }
163 //==============================================================================================================
164
165 void    AsmMan::AddFile(__in __nullterminated char* szName, DWORD dwAttr, BinStr* pHashBlob)
166 {
167     AsmManFile* tmp = GetFileByName(szName);
168     Assembler* pAsm = (Assembler*)m_pAssembler;
169     if(tmp==NULL)
170     {
171         tmp = new AsmManFile;
172         if(tmp==NULL)
173         {
174             pAsm->report->error("\nOut of memory!\n");
175             return;
176         }
177         memset(tmp,0,sizeof(AsmManFile));
178         if((dwAttr & 0x80000000)!=0) pAsm->m_fEntryPointPresent = TRUE;
179         tmp->szName = szName;
180         tmp->dwAttr = dwAttr;
181         tmp->pHash = pHashBlob;
182         tmp->m_fNew = TRUE;
183         m_FileLst.PUSH(tmp);
184         tmp->tkTok = TokenFromRid(m_FileLst.COUNT(),mdtFile);
185     }
186     pAsm->m_tkCurrentCVOwner = 0;
187     if(tmp) pAsm->m_pCustomDescrList = &(tmp->m_CustomDescrList);
188 }
189 //==============================================================================================================
190
191 void    AsmMan::EmitFiles()
192 {
193     AsmManFile* tmp;
194     Assembler* pAsm = (Assembler*)m_pAssembler;
195     int i;
196     HRESULT                 hr = S_OK;
197     mdToken tk;
198     for(i = 0; (tmp=m_FileLst.PEEK(i)) != NULL; i++)
199     {
200         BOOL    fEntry = ((tmp->dwAttr & 0x80000000)!=0);
201
202         wzUniBuf[0] = 0;
203
204         BYTE*       pHash=NULL;
205         DWORD       cbHash= 0;
206
207         if(!tmp->m_fNew) continue;
208         tmp->m_fNew = FALSE;
209
210         WszMultiByteToWideChar(g_uCodePage,0,tmp->szName,-1,wzUniBuf,dwUniBuf);
211         if(tmp->pHash==NULL) // if hash not explicitly specified
212         {
213             if(m_pAssembly      // and assembly is defined
214                 && m_pAssembly->ulHashAlgorithm) // and hash algorithm is defined...
215             { // then try to compute it
216                 {
217                     pHash = NULL;
218                     cbHash = 0;
219                 }
220             }
221         }
222         else 
223         {
224             pHash = tmp->pHash->ptr();
225             cbHash = tmp->pHash->length();
226         }
227
228         hr = m_pAsmEmitter->DefineFile(wzUniBuf,
229                                     (const void*)pHash,
230                                     cbHash,
231                                     tmp->dwAttr & 0x7FFFFFFF,
232                                     (mdFile*)&tk);
233         _ASSERTE(tk == tmp->tkTok);
234         if(FAILED(hr)) report->error("Failed to define file '%s': 0x%08X\n",tmp->szName,hr);
235         else
236         {
237             if(fEntry)
238             {
239                 if (FAILED(pAsm->m_pCeeFileGen->SetEntryPoint(pAsm->m_pCeeFile, tmp->tkTok)))
240                 {
241                     pAsm->report->error("Failed to set external entry point for file '%s'\n",tmp->szName);
242                 }
243             }
244             pAsm->EmitCustomAttributes(tmp->tkTok, &(tmp->m_CustomDescrList));
245         }
246     } //end for(i = 0; tmp=m_FileLst.PEEK(i); i++)
247 }
248
249 void    AsmMan::StartAssembly(__in __nullterminated char* szName, __in_opt __nullterminated char* szAlias, DWORD dwAttr, BOOL isRef)
250 {
251     if(!isRef && (0==strcmp(szName, "mscorlib"))) ((Assembler*)m_pAssembler)->m_fIsMscorlib = TRUE;
252     if(!isRef && (m_pAssembly != NULL))
253     {
254         if(strcmp(szName, m_pAssembly->szName))
255             report->error("Multiple assembly declarations\n");
256         // if name is the same, just ignore it
257         m_pCurAsmRef = NULL;
258     }
259     else
260     {
261         if((m_pCurAsmRef = new AsmManAssembly))
262         {
263             memset(m_pCurAsmRef,0,sizeof(AsmManAssembly));
264             m_pCurAsmRef->usVerMajor = (USHORT)0xFFFF;
265             m_pCurAsmRef->usVerMinor = (USHORT)0xFFFF;
266             m_pCurAsmRef->usBuild = (USHORT)0xFFFF;
267             m_pCurAsmRef->usRevision = (USHORT)0xFFFF;
268             m_pCurAsmRef->szName = szName;
269             m_pCurAsmRef->szAlias = szAlias ? szAlias : szName;
270             m_pCurAsmRef->dwAlias = (DWORD)strlen(m_pCurAsmRef->szAlias);
271             m_pCurAsmRef->dwAttr = dwAttr;
272             m_pCurAsmRef->isRef = isRef;
273             m_pCurAsmRef->isAutodetect = FALSE;
274             m_pCurAsmRef->m_fNew = TRUE;
275             if(!isRef) m_pAssembly = m_pCurAsmRef;
276         }
277         else
278             report->error("Failed to allocate AsmManAssembly structure\n");
279     }
280     ((Assembler*)m_pAssembler)->m_tkCurrentCVOwner = 0;
281     ((Assembler*)m_pAssembler)->m_CustomDescrListStack.PUSH(((Assembler*)m_pAssembler)->m_pCustomDescrList);
282     ((Assembler*)m_pAssembler)->m_pCustomDescrList = m_pCurAsmRef ? &(m_pCurAsmRef->m_CustomDescrList) : NULL;
283
284 }
285 // copied from asmparse.y
286 static void corEmitInt(BinStr* buff, unsigned data) 
287 {
288     unsigned cnt = CorSigCompressData(data, buff->getBuff(5));
289     buff->remove(5 - cnt);
290 }
291
292 void AsmMan::EmitDebuggableAttribute(mdToken tkOwner)
293 {
294     mdToken tkCA;
295     Assembler* pAsm = (Assembler*)m_pAssembler;
296     mdToken tkTypeSpec, tkMscorlib, tkParamType;
297     BinStr  *pbsSig = new BinStr();
298     BinStr* bsBytes = new BinStr();;
299     char*   szName;
300     tkMscorlib = pAsm->m_fIsMscorlib ? 1 : pAsm->GetBaseAsmRef();
301     tkTypeSpec = pAsm->ResolveClassRef(tkMscorlib,"System.Diagnostics.DebuggableAttribute",NULL);
302
303     EmitAssemblyRefs(); // just in case we gained 'mscorlib' AsmRef in GetAsmRef above
304
305     BOOL fOldStyle = FALSE;
306     if(tkMscorlib == 1)
307         fOldStyle = (m_pAssembly->usVerMajor == 1);
308     else
309     {
310         AsmManAssembly *pAssembly = GetAsmRefByName("mscorlib");
311         if(pAssembly != NULL)
312         {
313             fOldStyle = (pAssembly->usVerMajor == 1);
314         }   
315     }
316
317     bsBytes->appendInt8(1);
318     bsBytes->appendInt8(0);
319     if(fOldStyle)
320     {
321         pbsSig->appendInt8(IMAGE_CEE_CS_CALLCONV_HASTHIS);
322         corEmitInt(pbsSig,2);
323         pbsSig->appendInt8(ELEMENT_TYPE_VOID);
324         pbsSig->appendInt8(ELEMENT_TYPE_BOOLEAN);
325         pbsSig->appendInt8(ELEMENT_TYPE_BOOLEAN);
326
327         //New to old: 0x101->(true,true),0x03->(true,false),0x103->(true,true)+warning
328         bsBytes->appendInt8(1);
329         bsBytes->appendInt8((pAsm->m_dwIncludeDebugInfo==0x03 ? 0 : 1));
330         if(pAsm->m_dwIncludeDebugInfo == 0x103)
331         {
332             report->warn("\nOption /DEBUG=IMPL is invalid for legacy DebuggableAttribute, /DEBUG used.\n" );
333         }
334     }
335     else
336     {
337         BinStr  bsSigArg;
338         char buffer[80];
339         sprintf_s(buffer,80, 
340                 "%s%c%s",
341                 "System.Diagnostics.DebuggableAttribute",
342                 NESTING_SEP,
343                 "DebuggingModes"
344                );
345
346         tkParamType = pAsm->ResolveClassRef(tkMscorlib,buffer, NULL);
347
348         bsSigArg.appendInt8(ELEMENT_TYPE_VALUETYPE);
349
350         unsigned cnt = CorSigCompressToken(tkParamType, bsSigArg.getBuff(5));
351         bsSigArg.remove(5 - cnt);
352
353         pbsSig->appendInt8(IMAGE_CEE_CS_CALLCONV_HASTHIS);
354         corEmitInt(pbsSig,1);
355         pbsSig->appendInt8(ELEMENT_TYPE_VOID);
356         pbsSig->append(&bsSigArg);
357
358         bsBytes->appendInt32(pAsm->m_dwIncludeDebugInfo);
359     }
360     bsBytes->appendInt8(0);
361     bsBytes->appendInt8(0);
362
363     szName = new char[16];
364     strcpy_s(szName,16,".ctor");
365     tkCA = pAsm->MakeMemberRef(tkTypeSpec,szName,pbsSig);
366     pAsm->DefineCV(new CustomDescr(tkOwner,tkCA,bsBytes));
367 }
368
369 void    AsmMan::EndAssembly()
370 {
371     if(m_pCurAsmRef)
372     {
373         if(m_pCurAsmRef->isRef)
374         { // list the assembly ref
375             if(GetAsmRefByName(m_pCurAsmRef->szAlias))
376             {
377                 //report->warn("Multiple declarations of Assembly Ref '%s', ignored except the 1st one\n",m_pCurAsmRef->szName);
378                 delete m_pCurAsmRef;
379                 m_pCurAsmRef = NULL;
380                 return;
381             }
382             m_AsmRefLst.PUSH(m_pCurAsmRef);
383             m_pCurAsmRef->tkTok = TokenFromRid(m_AsmRefLst.COUNT(),mdtAssemblyRef);
384         }
385         else
386         {
387             HRESULT                 hr = S_OK;
388             m_pCurAsmRef->tkTok = TokenFromRid(1,mdtAssembly);
389
390             // Determine the strong name public key. This may have been set
391             // via a directive in the source or from the command line (which
392             // overrides the directive). From the command line we may have
393             // been provided with a file or the name of a CAPI key
394             // container. Either may contain a public key or a full key
395             // pair.
396             if (((Assembler*)m_pAssembler)->m_wzKeySourceName)
397             {
398                 // Key file versus container is determined by the first
399                 // character of the source ('@' for container).
400                 if (*(((Assembler*)m_pAssembler)->m_wzKeySourceName) == L'@')
401                 {
402                     report->error("Error: ilasm on CoreCLR does not support getting public key from container.\n");
403                     m_pCurAsmRef = NULL;
404                     return;
405                 }
406                 else
407                 {
408                     // Read public key or key pair from file.
409                     HANDLE hFile = WszCreateFile(((Assembler*)m_pAssembler)->m_wzKeySourceName,
410                                                  GENERIC_READ,
411                                                  FILE_SHARE_READ,
412                                                  NULL,
413                                                  OPEN_EXISTING,
414                                                  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
415                                                  NULL);
416                     if(hFile == INVALID_HANDLE_VALUE)
417                     {
418                         hr = GetLastError();
419                         report->error("Failed to open key file '%S': 0x%08X\n",((Assembler*)m_pAssembler)->m_wzKeySourceName,hr);
420                         m_pCurAsmRef = NULL;
421                         return;
422                     }
423
424                     // Determine file size and allocate an appropriate buffer.
425                     m_sStrongName.m_cbPublicKey = SafeGetFileSize(hFile, NULL);
426                     if (m_sStrongName.m_cbPublicKey == 0xffffffff) {
427                         report->error("File size too large\n");
428                         m_pCurAsmRef = NULL;
429                         CloseHandle(hFile);
430                         return;
431                     }
432
433                     m_sStrongName.m_pbPublicKey = new BYTE[m_sStrongName.m_cbPublicKey];
434                     if (m_sStrongName.m_pbPublicKey == NULL) {
435                         report->error("Failed to allocate key buffer\n");
436                         m_pCurAsmRef = NULL;
437                         CloseHandle(hFile);
438                         return;
439                     }
440                     m_sStrongName.m_dwPublicKeyAllocated = AsmManStrongName::AllocatedByNew;
441
442                     // Read the file into the buffer.
443                     DWORD dwBytesRead;
444                     if (!ReadFile(hFile, m_sStrongName.m_pbPublicKey, m_sStrongName.m_cbPublicKey, &dwBytesRead, NULL)) {
445                         hr = GetLastError();
446                         report->error("Failed to read key file '%S': 0x%08X\n",((Assembler*)m_pAssembler)->m_wzKeySourceName,hr);
447                         m_pCurAsmRef = NULL;
448                         CloseHandle(hFile);
449                         return;
450                     }
451
452                     CloseHandle(hFile);
453
454                     // Guess whether we're full or delay signing based on
455                     // whether the blob passed to us looks like a public
456                     // key. (I.e. we may just have copied a full key pair
457                     // into the public key buffer).
458                     if (m_sStrongName.m_cbPublicKey >= sizeof(PublicKeyBlob) &&
459                         (offsetof(PublicKeyBlob, PublicKey) +
460                          ((PublicKeyBlob*)m_sStrongName.m_pbPublicKey)->cbPublicKey) == m_sStrongName.m_cbPublicKey)
461                         m_sStrongName.m_fFullSign = FALSE;
462                     else
463                         m_sStrongName.m_fFullSign = TRUE;
464
465                     // If we really have a key pair, we'll move it into a
466                     // key container so the signing code gets the key pair
467                     // from a consistent place.
468                     if (m_sStrongName.m_fFullSign)
469                     {
470                         report->error("Error: ilasm on CoreCLR does not support full sign.\n");
471                         m_pCurAsmRef = NULL;
472                         return;
473                     }
474                 }
475             }
476             else 
477             {
478                 if (m_pAssembly->pPublicKey)
479                 {
480                     m_sStrongName.m_pbPublicKey = m_pAssembly->pPublicKey->ptr();
481                     m_sStrongName.m_cbPublicKey = m_pAssembly->pPublicKey->length();
482                 }
483                 else
484                 {
485                     m_sStrongName.m_pbPublicKey = NULL;
486                     m_sStrongName.m_cbPublicKey = 0;
487                 }
488
489                 m_sStrongName.m_wzKeyContainer = NULL;
490                 m_sStrongName.m_fFullSign = FALSE;
491                 m_sStrongName.m_dwPublicKeyAllocated = AsmManStrongName::NotAllocated;
492             }
493         }
494         m_pCurAsmRef = NULL;
495     }
496     ((Assembler*)m_pAssembler)->m_pCustomDescrList = ((Assembler*)m_pAssembler)->m_CustomDescrListStack.POP();
497 }
498
499 void    FillAssemblyMetadata(AsmManAssembly *pAsm, ASSEMBLYMETADATA *pmd)
500 {
501     pmd->usMajorVersion = pAsm->usVerMajor;
502     pmd->usMinorVersion = pAsm->usVerMinor;
503     pmd->usBuildNumber = pAsm->usBuild;
504     pmd->usRevisionNumber = pAsm->usRevision;
505     if(pmd->usMajorVersion == 0xFFFF) pmd->usMajorVersion = 0;
506     if(pmd->usMinorVersion == 0xFFFF) pmd->usMinorVersion = 0;
507     if(pmd->usBuildNumber == 0xFFFF) pmd->usBuildNumber = 0;
508     if(pmd->usRevisionNumber == 0xFFFF) pmd->usRevisionNumber = 0;
509
510     if(pAsm->pLocale != NULL)
511     {
512         pmd->szLocale = (LPWSTR)(pAsm->pLocale->ptr());
513         pmd->cbLocale = pAsm->pLocale->length()/((ULONG)sizeof(WCHAR));
514     }
515     else
516     {
517         pmd->szLocale = NULL;
518         pmd->cbLocale = 0;
519     }
520
521     pmd->rProcessor = NULL;
522     pmd->rOS = NULL;
523     pmd->ulProcessor = 0;
524     pmd->ulOS = 0;
525 }
526
527 void    AsmMan::EmitAssemblyRefs()
528 {
529     int i;
530     HRESULT                 hr = S_OK;
531     ASSEMBLYMETADATA md;
532     mdToken tk;
533     
534     for(i=0; (m_pCurAsmRef=m_AsmRefLst.PEEK(i)) != NULL; i++)
535     {
536         if(!m_pCurAsmRef->m_fNew) continue;
537         m_pCurAsmRef->m_fNew = FALSE;
538
539         wzUniBuf[0] = 0;
540         FillAssemblyMetadata(m_pCurAsmRef,&md);
541
542         // See if we've got a full public key or the tokenized version (or neither).
543         BYTE *pbPublicKeyOrToken = NULL;
544         DWORD cbPublicKeyOrToken = 0;
545         DWORD dwFlags = m_pCurAsmRef->dwAttr;
546         if (m_pCurAsmRef->pPublicKeyToken)
547         {
548             pbPublicKeyOrToken = m_pCurAsmRef->pPublicKeyToken->ptr();
549             cbPublicKeyOrToken = m_pCurAsmRef->pPublicKeyToken->length();
550             
551         }
552         else if (m_pCurAsmRef->pPublicKey)
553         {
554             pbPublicKeyOrToken = m_pCurAsmRef->pPublicKey->ptr();
555             cbPublicKeyOrToken = m_pCurAsmRef->pPublicKey->length();
556             dwFlags |= afPublicKey;
557         }
558         // Convert name to Unicode
559         WszMultiByteToWideChar(g_uCodePage,0,m_pCurAsmRef->szName,-1,wzUniBuf,dwUniBuf);
560         hr = m_pAsmEmitter->DefineAssemblyRef(       // S_OK or error.
561                     pbPublicKeyOrToken,              // [IN] Public key or token of the assembly.
562                     cbPublicKeyOrToken,              // [IN] Count of bytes in the key or token.
563                     (LPCWSTR)wzUniBuf,               // [IN] Name of the assembly being referenced.
564                     (const ASSEMBLYMETADATA*)&md,    // [IN] Assembly MetaData.
565                     (m_pCurAsmRef->pHashBlob ? (const void*)(m_pCurAsmRef->pHashBlob->ptr()) : NULL),           // [IN] Hash Blob.
566                     (m_pCurAsmRef->pHashBlob ? m_pCurAsmRef->pHashBlob->length() : 0),            // [IN] Count of bytes in the Hash Blob.
567                     dwFlags,                         // [IN] Flags.
568                     (mdAssemblyRef*)&tk);         // [OUT] Returned AssemblyRef token.
569         if(m_pCurAsmRef->tkTok != tk)
570         {
571             report->error("AsmRef'%S' tok %8.8X -> %8.8X\n",wzUniBuf,m_pCurAsmRef->tkTok,tk);
572         }
573         if(FAILED(hr)) report->error("Failed to define assembly ref '%s': 0x%08X\n",m_pCurAsmRef->szName,hr);
574         else
575         {
576             ((Assembler*)m_pAssembler)->EmitCustomAttributes(m_pCurAsmRef->tkTok, &(m_pCurAsmRef->m_CustomDescrList));
577         }
578     } // end for(i=0; m_pCurAsmRef=m_AsmRefLst.PEEK(i); i++)
579 }
580
581 void    AsmMan::EmitAssembly()
582 {
583     HRESULT                 hr = S_OK;
584     ASSEMBLYMETADATA md;
585             
586     wzUniBuf[0] = 0;
587     if(m_pAssembly == NULL) return;
588     if(!m_pAssembly->m_fNew) return;
589     m_pAssembly->m_fNew = FALSE;
590
591     FillAssemblyMetadata(m_pAssembly, &md);
592
593     // Convert name to Unicode
594     WszMultiByteToWideChar(g_uCodePage,0,m_pAssembly->szName,-1,wzUniBuf,dwUniBuf);
595
596     hr = m_pAsmEmitter->DefineAssembly(              // S_OK or error.
597         (const void*)(m_sStrongName.m_pbPublicKey), // [IN] Public key of the assembly.
598         m_sStrongName.m_cbPublicKey,                // [IN] Count of bytes in the public key.
599         m_pAssembly->ulHashAlgorithm,            // [IN] Hash algorithm used to hash the files.
600         (LPCWSTR)wzUniBuf,                 // [IN] Name of the assembly.
601         (const ASSEMBLYMETADATA*)&md,  // [IN] Assembly MetaData.
602         m_pAssembly->dwAttr,        // [IN] Flags.
603         (mdAssembly*)&(m_pAssembly->tkTok));             // [OUT] Returned Assembly token.
604
605     if(FAILED(hr)) report->error("Failed to define assembly '%s': 0x%08X\n",m_pAssembly->szName,hr);
606     else
607     {
608         Assembler* pAsm = ((Assembler*)m_pAssembler);
609         pAsm->EmitSecurityInfo(m_pAssembly->tkTok,
610                              m_pAssembly->m_pPermissions,
611                              m_pAssembly->m_pPermissionSets);
612         if(pAsm->m_dwIncludeDebugInfo)
613         {
614             EmitDebuggableAttribute(m_pAssembly->tkTok);
615         }
616         pAsm->EmitCustomAttributes(m_pAssembly->tkTok, &(m_pAssembly->m_CustomDescrList));
617     }
618 }
619
620 void    AsmMan::SetAssemblyPublicKey(BinStr* pPublicKey)
621 {
622     if(m_pCurAsmRef)
623     {
624         m_pCurAsmRef->pPublicKey = pPublicKey;
625     }
626 }
627
628 void    AsmMan::SetAssemblyPublicKeyToken(BinStr* pPublicKeyToken)
629 {
630     if(m_pCurAsmRef)
631     {
632         m_pCurAsmRef->pPublicKeyToken = pPublicKeyToken;
633     }
634 }
635
636 void    AsmMan::SetAssemblyHashAlg(ULONG ulAlgID)
637 {
638     if(m_pCurAsmRef)
639     {
640         m_pCurAsmRef->ulHashAlgorithm = ulAlgID;
641     }
642 }
643
644 void    AsmMan::SetAssemblyVer(USHORT usMajor, USHORT usMinor, USHORT usBuild, USHORT usRevision)
645 {
646     if(m_pCurAsmRef)
647     {
648         m_pCurAsmRef->usVerMajor = usMajor;
649         m_pCurAsmRef->usVerMinor = usMinor;
650         m_pCurAsmRef->usBuild = usBuild;
651         m_pCurAsmRef->usRevision = usRevision;
652     }
653 }
654
655 void    AsmMan::SetAssemblyLocale(BinStr* pLocale, BOOL bConvertToUnicode)
656 {
657     if(m_pCurAsmRef)
658     {
659         m_pCurAsmRef->pLocale = bConvertToUnicode ? ::BinStrToUnicode(pLocale) : pLocale;
660     }
661 }
662
663 void    AsmMan::SetAssemblyHashBlob(BinStr* pHashBlob)
664 {
665     if(m_pCurAsmRef)
666     {
667         m_pCurAsmRef->pHashBlob = pHashBlob;
668     }
669 }
670
671 void    AsmMan::SetAssemblyAutodetect()
672 {
673     if(m_pCurAsmRef)
674     {
675         m_pCurAsmRef->isAutodetect = TRUE;
676     }
677 }
678
679 void    AsmMan::StartComType(__in __nullterminated char* szName, DWORD dwAttr)
680 {
681     if((m_pCurComType = new AsmManComType))
682     {
683         memset(m_pCurComType,0,sizeof(AsmManComType));
684         m_pCurComType->szName = szName;
685         m_pCurComType->dwAttr = dwAttr;
686         m_pCurComType->m_fNew = TRUE;
687         ((Assembler*)m_pAssembler)->m_tkCurrentCVOwner = 0;
688         ((Assembler*)m_pAssembler)->m_CustomDescrListStack.PUSH(((Assembler*)m_pAssembler)->m_pCustomDescrList);
689         ((Assembler*)m_pAssembler)->m_pCustomDescrList = &(m_pCurComType->m_CustomDescrList);
690     }
691     else
692         report->error("Failed to allocate AsmManComType structure\n");
693 }
694
695 void    AsmMan::EndComType()
696 {
697     if(m_pCurComType)
698     {
699         if(m_pAssembler)
700         { 
701             Class* pClass =((Assembler*)m_pAssembler)->m_pCurClass;
702             if(pClass)
703             {
704                 m_pCurComType->tkClass = pClass->m_cl;
705                 if(pClass->m_pEncloser)
706                 {
707                     mdTypeDef tkEncloser = pClass->m_pEncloser->m_cl;
708                     AsmManComType* pCT;
709                     for(unsigned i=0; (pCT=m_ComTypeLst.PEEK(i)); i++)
710                     {
711                         if(pCT->tkClass == tkEncloser)
712                         {
713                             m_pCurComType->szComTypeName = pCT->szName;
714                             break;
715                         }
716                     }
717                 }
718             }
719         }
720
721         if (IsTdNested(m_pCurComType->dwAttr) && GetComTypeByName(m_pCurComType->szName, m_pCurComType->szComTypeName) != NULL)
722         {
723             report->error("Invalid TypeDefID of exported type\n");
724             delete m_pCurComType;
725         }
726         else
727         {
728             m_ComTypeLst.PUSH(m_pCurComType);
729         }
730
731         m_pCurComType = NULL;
732         ((Assembler*)m_pAssembler)->m_tkCurrentCVOwner = 0;
733         ((Assembler*)m_pAssembler)->m_pCustomDescrList = ((Assembler*)m_pAssembler)->m_CustomDescrListStack.POP();
734     }
735 }
736
737 void    AsmMan::SetComTypeFile(__in __nullterminated char* szFileName)
738 {
739     if(m_pCurComType)
740     {
741         m_pCurComType->szFileName = szFileName;
742     }
743 }
744
745 void    AsmMan::SetComTypeAsmRef(__in __nullterminated char* szAsmRefName)
746 {
747     if(m_pCurComType)
748     {
749         m_pCurComType->szAsmRefName = szAsmRefName;
750     }
751 }
752
753 void    AsmMan::SetComTypeComType(__in __nullterminated char* szComTypeName)
754 {
755     if(m_pCurComType)
756     {
757         m_pCurComType->szComTypeName = szComTypeName;
758     }
759 }
760 BOOL    AsmMan::SetComTypeImplementationTok(mdToken tk)
761 {
762     if(m_pCurComType)
763     {
764         switch(TypeFromToken(tk))
765         {
766         case mdtAssemblyRef:
767         case mdtExportedType:
768         case mdtFile:
769             m_pCurComType->tkImpl = tk;
770             return TRUE;
771         }
772     }
773     return FALSE;
774 }
775 BOOL    AsmMan::SetComTypeClassTok(mdToken tkClass)
776 {
777     if((m_pCurComType)&&(TypeFromToken(tkClass)==mdtTypeDef))
778     {
779         m_pCurComType->tkClass = tkClass;
780         return TRUE;
781     }
782     return FALSE;
783 }
784
785 void    AsmMan::StartManifestRes(__in __nullterminated char* szName, __in __nullterminated char* szAlias, DWORD dwAttr)
786 {
787     if((m_pCurManRes = new AsmManRes))
788     {
789         m_pCurManRes->szName = szName;
790         m_pCurManRes->szAlias = szAlias;
791         m_pCurManRes->dwAttr = dwAttr;
792         m_pCurManRes->m_fNew = TRUE;
793         ((Assembler*)m_pAssembler)->m_tkCurrentCVOwner = 0;
794         ((Assembler*)m_pAssembler)->m_CustomDescrListStack.PUSH(((Assembler*)m_pAssembler)->m_pCustomDescrList);
795         ((Assembler*)m_pAssembler)->m_pCustomDescrList = &(m_pCurManRes->m_CustomDescrList);
796     }
797     else
798         report->error("Failed to allocate AsmManRes structure\n");
799 }
800
801 void    AsmMan::EndManifestRes()
802 {
803     if(m_pCurManRes)
804     {
805         m_ManResLst.PUSH(m_pCurManRes);
806         m_pCurManRes = NULL;
807         ((Assembler*)m_pAssembler)->m_tkCurrentCVOwner = 0;
808         ((Assembler*)m_pAssembler)->m_pCustomDescrList = ((Assembler*)m_pAssembler)->m_CustomDescrListStack.POP();
809     }
810 }
811
812
813 void    AsmMan::SetManifestResFile(__in __nullterminated char* szFileName, ULONG ulOffset)
814 {
815     if(m_pCurManRes)
816     {
817         m_pCurManRes->szFileName = szFileName;
818         m_pCurManRes->ulOffset = ulOffset;
819     }
820 }
821
822 void    AsmMan::SetManifestResAsmRef(__in __nullterminated char* szAsmRefName)
823 {
824     if(m_pCurManRes)
825     {
826         m_pCurManRes->szAsmRefName = szAsmRefName;
827     }
828 }
829
830 HRESULT AsmMan::EmitManifest()
831 {
832     //AsmManAssembly*           pAsmRef;
833     AsmManComType*          pComType;
834     AsmManRes*              pManRes;
835     HRESULT                 hr = S_OK;
836
837     wzUniBuf[0] = 0;
838
839     if(m_pAsmEmitter==NULL)
840         hr=m_pEmitter->QueryInterface(IID_IMetaDataAssemblyEmit, (void**) &m_pAsmEmitter);
841
842     if(SUCCEEDED(hr))
843     {
844         EmitFiles();
845         EmitAssembly();
846         
847         if((((Assembler*)m_pAssembler)->m_dwIncludeDebugInfo != 0) && (m_pAssembly == NULL) 
848            && !(((Assembler*)m_pAssembler)->m_fENCMode))
849         {
850             mdToken tkOwner, tkMscorlib;
851             tkMscorlib = ((Assembler*)m_pAssembler)->GetAsmRef("mscorlib");
852             tkOwner = ((Assembler*)m_pAssembler)->ResolveClassRef(tkMscorlib,
853                                                                   "System.Runtime.CompilerServices.AssemblyAttributesGoHere",
854                                                                   NULL);
855             EmitDebuggableAttribute(tkOwner);
856         }
857
858         // Emit all com types
859         unsigned i;
860         for(i = 0; (pComType = m_ComTypeLst.PEEK(i)); i++)
861         {
862             if(!pComType->m_fNew) continue;
863             pComType->m_fNew = FALSE;
864
865             WszMultiByteToWideChar(g_uCodePage,0,pComType->szName,-1,wzUniBuf,dwUniBuf);
866             mdToken     tkImplementation = mdTokenNil;
867             if(pComType->tkImpl) tkImplementation = pComType->tkImpl;
868             else if(pComType->szFileName)
869             {
870                 tkImplementation = GetFileTokByName(pComType->szFileName);
871                 if(tkImplementation==mdFileNil)
872                 {
873                     report->error("Undefined File '%s' in ExportedType '%s'\n",pComType->szFileName,pComType->szName);
874                     if(!((Assembler*)m_pAssembler)->OnErrGo) continue;
875                 }
876             }
877             else if(pComType->szAsmRefName)
878             {
879                 tkImplementation = GetAsmRefTokByName(pComType->szAsmRefName);
880                 if(RidFromToken(tkImplementation)==0)
881                 {
882                     report->error("Undefined AssemblyRef '%s' in ExportedType '%s'\n",pComType->szAsmRefName,pComType->szName);
883                     if(!((Assembler*)m_pAssembler)->OnErrGo) continue;
884                 }
885             }
886             else if(pComType->szComTypeName)
887             {
888                 char* szLastName = strrchr(pComType->szComTypeName, NESTING_SEP);
889
890                 if(szLastName)
891                 {
892                     *szLastName = 0;
893                     szLastName ++;
894                     tkImplementation = GetComTypeTokByName(szLastName, pComType->szComTypeName);
895                     *(szLastName-1) = NESTING_SEP; // not really necessary
896                 }
897
898                 else
899                 {
900                     tkImplementation = GetComTypeTokByName(pComType->szComTypeName);
901                 }
902
903                 if(tkImplementation==mdExportedTypeNil)
904                 {
905                     report->error("Undefined ExportedType '%s' in ExportedType '%s'\n",pComType->szComTypeName,pComType->szName);
906                     if(!((Assembler*)m_pAssembler)->OnErrGo) continue;
907                 }
908             }
909             else 
910             {
911                 report->warn("Undefined implementation in ExportedType '%s' -- ExportType not emitted\n",pComType->szName);
912                 if(!((Assembler*)m_pAssembler)->OnErrGo) continue;
913             }
914             hr = m_pAsmEmitter->DefineExportedType(         // S_OK or error.
915                     (LPCWSTR)wzUniBuf,                      // [IN] Name of the Com Type.
916                     tkImplementation,                       // [IN] mdFile or mdAssemblyRef that provides the ComType.
917                     (mdTypeDef)pComType->tkClass,           // [IN] TypeDef token within the file.
918                     pComType->dwAttr,                       // [IN] Flags.
919                     (mdExportedType*)&(pComType->tkTok));   // [OUT] Returned ComType token.
920             if(FAILED(hr)) report->error("Failed to define ExportedType '%s': 0x%08X\n",pComType->szName,hr);
921             else
922             {
923                 ((Assembler*)m_pAssembler)->EmitCustomAttributes(pComType->tkTok, &(pComType->m_CustomDescrList));
924             }
925         }
926
927         // Emit all manifest resources
928         m_dwMResSizeTotal = 0;
929         m_dwMResNum = 0;
930         for(i = 0; (pManRes = m_ManResLst.PEEK(i)); i++)
931         {
932             BOOL fOK = TRUE;
933             mdToken     tkImplementation = mdFileNil;
934
935             if(!pManRes->m_fNew) continue;
936             pManRes->m_fNew = FALSE;
937
938             WszMultiByteToWideChar(g_uCodePage,0,pManRes->szAlias,-1,wzUniBuf,dwUniBuf);
939             if(pManRes->szAsmRefName)
940             {
941                 tkImplementation = GetAsmRefTokByName(pManRes->szAsmRefName);
942                 if(RidFromToken(tkImplementation)==0)
943                 {
944                     report->error("Undefined AssemblyRef '%s' in MResource '%s'\n",pManRes->szAsmRefName,pManRes->szName);
945                     fOK = FALSE;
946                 }
947             }
948             else if(pManRes->szFileName)
949             {
950                 tkImplementation = GetFileTokByName(pManRes->szFileName);
951                 if(RidFromToken(tkImplementation)==0)
952                 {
953                     report->error("Undefined File '%s' in MResource '%s'\n",pManRes->szFileName,pManRes->szName);
954                     fOK = FALSE;
955                 }
956             }
957             else // embedded mgd.resource, go after the file
958             {
959                 HANDLE hFile = INVALID_HANDLE_VALUE;
960                 int j;
961                 WCHAR   wzFileName[2048];
962                 WCHAR*  pwz;
963
964                 pManRes->ulOffset = m_dwMResSizeTotal;
965                 for(j=0; (hFile == INVALID_HANDLE_VALUE)&&(pwzInputFiles[j] != NULL); j++)
966                 {
967                     wcscpy_s(wzFileName,2048,pwzInputFiles[j]);
968                     pwz = wcsrchr(wzFileName,'\\');
969                     if(pwz == NULL) pwz = wcsrchr(wzFileName,':');
970                     if(pwz == NULL) pwz = &wzFileName[0];
971                     else pwz++;
972                     wcscpy_s(pwz,2048-(pwz-wzFileName),wzUniBuf);
973                     hFile = WszCreateFile(wzFileName, GENERIC_READ, FILE_SHARE_READ,
974                              0, OPEN_EXISTING, 0, 0);
975                 }
976                 if (hFile == INVALID_HANDLE_VALUE)
977                 {
978                     report->error("Failed to open managed resource file '%s'\n",pManRes->szAlias);
979                     fOK = FALSE;
980                 }
981                 else
982                 {
983                     if (m_dwMResNum >= MAX_MANIFEST_RESOURCES)
984                     {
985                         report->error("Too many resources (implementation limit: %d); skipping file '%s'\n",MAX_MANIFEST_RESOURCES,pManRes->szAlias);
986                         fOK = FALSE;
987                     }
988                     else
989                     {
990                         m_dwMResSize[m_dwMResNum] = SafeGetFileSize(hFile,NULL);
991                         if(m_dwMResSize[m_dwMResNum] == 0xFFFFFFFF)
992                         {
993                             report->error("Failed to get size of managed resource file '%s'\n",pManRes->szAlias);
994                             fOK = FALSE;
995                         }
996                         else 
997                         {
998                             m_dwMResSizeTotal += m_dwMResSize[m_dwMResNum]+sizeof(DWORD);
999                             m_wzMResName[m_dwMResNum] = new WCHAR[wcslen(wzFileName)+1];
1000                             wcscpy_s(m_wzMResName[m_dwMResNum],wcslen(wzFileName)+1,wzFileName);
1001                             m_fMResNew[m_dwMResNum] = TRUE;
1002                             m_dwMResNum++;
1003                         }
1004                         CloseHandle(hFile);
1005                     }
1006                 }
1007             }
1008             if(fOK || ((Assembler*)m_pAssembler)->OnErrGo)
1009             {
1010                 WszMultiByteToWideChar(g_uCodePage,0,pManRes->szName,-1,wzUniBuf,dwUniBuf);
1011                 hr = m_pAsmEmitter->DefineManifestResource(         // S_OK or error.
1012                         (LPCWSTR)wzUniBuf,                          // [IN] Name of the resource.
1013                         tkImplementation,                           // [IN] mdFile or mdAssemblyRef that provides the resource.
1014                         pManRes->ulOffset,                          // [IN] Offset to the beginning of the resource within the file.
1015                         pManRes->dwAttr,                            // [IN] Flags.
1016                         (mdManifestResource*)&(pManRes->tkTok));    // [OUT] Returned ManifestResource token.
1017                 if(FAILED(hr))
1018                     report->error("Failed to define manifest resource '%s': 0x%08X\n",pManRes->szName,hr);
1019             }
1020         }
1021
1022
1023         m_pAsmEmitter->Release();
1024         m_pAsmEmitter = NULL;
1025     }
1026     else 
1027         report->error("Failed to obtain IMetaDataAssemblyEmit interface: 0x%08X\n",hr);
1028     return hr;
1029 }
1030