File: system\reflection\emit\assemblybuilderdata.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// <OWNER>Microsoft</OWNER>
// 
 
namespace System.Reflection.Emit {
    using System;
    using IList = System.Collections.IList;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Security;
    using System.Diagnostics;
    using CultureInfo = System.Globalization.CultureInfo;
#if !FEATURE_CORECLR
    using ResourceWriter = System.Resources.ResourceWriter;
#else // FEATURE_CORECLR
    using IResourceWriter = System.Resources.IResourceWriter;
#endif // !FEATURE_CORECLR
    using System.IO;
    using System.Runtime.Versioning;
    using System.Diagnostics.SymbolStore;
    using System.Diagnostics.Contracts;
 
    // This is a package private class. This class hold all of the managed
    // data member for AssemblyBuilder. Note that what ever data members added to
    // this class cannot be accessed from the EE.
    internal class AssemblyBuilderData
    {
        [SecurityCritical]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        internal AssemblyBuilderData(
            InternalAssemblyBuilder assembly, 
            String                  strAssemblyName, 
            AssemblyBuilderAccess   access,
            String                  dir)
        {
            m_assembly = assembly;
            m_strAssemblyName = strAssemblyName;
            m_access = access;
            m_moduleBuilderList = new List<ModuleBuilder>();
            m_resWriterList = new List<ResWriterData>();
 
            //Init to null/0 done for you by the CLR.  FXCop has spoken
 
            if (dir == null && access != AssemblyBuilderAccess.Run)
                m_strDir = Environment.CurrentDirectory;
            else
                m_strDir = dir;
 
            m_peFileKind = PEFileKinds.Dll;
         }
    
        // Helper to add a dynamic module into the tracking list
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal void AddModule(ModuleBuilder dynModule)
        {
            m_moduleBuilderList.Add(dynModule);
        }
    
        // Helper to add a resource information into the tracking list
        internal void AddResWriter(ResWriterData resData)
        {
            m_resWriterList.Add(resData);
        }
 
 
        // Helper to track CAs to persist onto disk
        internal void AddCustomAttribute(CustomAttributeBuilder customBuilder)
        {
 
            // make sure we have room for this CA
            if (m_CABuilders == null)
            {
                m_CABuilders = new CustomAttributeBuilder[m_iInitialSize];
            }
            if (m_iCABuilder == m_CABuilders.Length)
            {
                CustomAttributeBuilder[]  tempCABuilders = new CustomAttributeBuilder[m_iCABuilder * 2];
                Array.Copy(m_CABuilders, tempCABuilders, m_iCABuilder);
                m_CABuilders = tempCABuilders;            
            }
            m_CABuilders[m_iCABuilder] = customBuilder;
            
            m_iCABuilder++;
        }
 
        // Helper to track CAs to persist onto disk
        internal void AddCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
        {
 
            // make sure we have room for this CA
            if (m_CABytes == null)
            {
                m_CABytes = new byte[m_iInitialSize][];
                m_CACons = new ConstructorInfo[m_iInitialSize];                
            }
            if (m_iCAs == m_CABytes.Length)
            {
                // enlarge the arrays
                byte[][]  temp = new byte[m_iCAs * 2][];
                ConstructorInfo[] tempCon = new ConstructorInfo[m_iCAs * 2];
                for (int i=0; i < m_iCAs; i++)
                {
                    temp[i] = m_CABytes[i];
                    tempCon[i] = m_CACons[i];
                }
                m_CABytes = temp;
                m_CACons = tempCon;
            }
 
            byte[] attrs = new byte[binaryAttribute.Length];
            Array.Copy(binaryAttribute, attrs, binaryAttribute.Length);
            m_CABytes[m_iCAs] = attrs;
            m_CACons[m_iCAs] = con;
            m_iCAs++;
        }
 
#if !FEATURE_PAL        
        // Helper to calculate unmanaged version info from Assembly's custom attributes.
        // If DefineUnmanagedVersionInfo is called, the parameter provided will override
        // the CA's value.
        //                      
        [System.Security.SecurityCritical]  // auto-generated
        internal void FillUnmanagedVersionInfo()
        {
            // Get the lcid set on the assembly name as default if available
            // Note that if LCID is not avaible from neither AssemblyName or AssemblyCultureAttribute,
            // it is default to -1 which is treated as language neutral. 
            //
            CultureInfo locale = m_assembly.GetLocale();
#if FEATURE_USE_LCID            
            if (locale != null)
                m_nativeVersion.m_lcid = locale.LCID;
#endif            
                                                    
            for (int i = 0; i < m_iCABuilder; i++)
            {
                // check for known attributes
                Type conType = m_CABuilders[i].m_con.DeclaringType;
                if (m_CABuilders[i].m_constructorArgs.Length == 0 || m_CABuilders[i].m_constructorArgs[0] == null)
                    continue;
 
                if (conType.Equals(typeof(System.Reflection.AssemblyCopyrightAttribute)))
                {
                        // assert that we should only have one argument for this CA and the type should
                        // be a string.
                        // 
                    if (m_CABuilders[i].m_constructorArgs.Length != 1)
                    {
                        throw new ArgumentException(Environment.GetResourceString(
                            "Argument_BadCAForUnmngRSC",
                            m_CABuilders[i].m_con.ReflectedType.Name));
                    }
                    if (m_OverrideUnmanagedVersionInfo == false)
                    {
                        m_nativeVersion.m_strCopyright = m_CABuilders[i].m_constructorArgs[0].ToString();
                    }
                }
                else if (conType.Equals(typeof(System.Reflection.AssemblyTrademarkAttribute))) 
                {
                        // assert that we should only have one argument for this CA and the type should
                        // be a string.
                        // 
                    if (m_CABuilders[i].m_constructorArgs.Length != 1)
                    {
                        throw new ArgumentException(Environment.GetResourceString(
                            "Argument_BadCAForUnmngRSC",
                            m_CABuilders[i].m_con.ReflectedType.Name));
                    }
                    if (m_OverrideUnmanagedVersionInfo == false)
                    {
                        m_nativeVersion.m_strTrademark = m_CABuilders[i].m_constructorArgs[0].ToString();
                    }
                }
                else if (conType.Equals(typeof(System.Reflection.AssemblyProductAttribute))) 
                {
                    if (m_OverrideUnmanagedVersionInfo == false)
                    {
                        // assert that we should only have one argument for this CA and the type should
                        // be a string.
                        // 
                        m_nativeVersion.m_strProduct = m_CABuilders[i].m_constructorArgs[0].ToString();
                    }
                }
                else if (conType.Equals(typeof(System.Reflection.AssemblyCompanyAttribute))) 
                {
                    if (m_CABuilders[i].m_constructorArgs.Length != 1)
                    {
                        throw new ArgumentException(Environment.GetResourceString(
                            "Argument_BadCAForUnmngRSC",
                            m_CABuilders[i].m_con.ReflectedType.Name));
                    }
                    if (m_OverrideUnmanagedVersionInfo == false)
                    {
                        // assert that we should only have one argument for this CA and the type should
                        // be a string.
                        // 
                        m_nativeVersion.m_strCompany = m_CABuilders[i].m_constructorArgs[0].ToString();
                    }
                }
                else if (conType.Equals(typeof(System.Reflection.AssemblyDescriptionAttribute))) 
                {
                    if (m_CABuilders[i].m_constructorArgs.Length != 1)
                    {
                        throw new ArgumentException(Environment.GetResourceString(
                            "Argument_BadCAForUnmngRSC",
                            m_CABuilders[i].m_con.ReflectedType.Name));
                    }
                    m_nativeVersion.m_strDescription = m_CABuilders[i].m_constructorArgs[0].ToString();
                }
                else if (conType.Equals(typeof(System.Reflection.AssemblyTitleAttribute))) 
                {
                    if (m_CABuilders[i].m_constructorArgs.Length != 1)
                    {
                        throw new ArgumentException(Environment.GetResourceString(
                            "Argument_BadCAForUnmngRSC",
                            m_CABuilders[i].m_con.ReflectedType.Name));
                    }
                    m_nativeVersion.m_strTitle = m_CABuilders[i].m_constructorArgs[0].ToString();
                }
                else if (conType.Equals(typeof(System.Reflection.AssemblyInformationalVersionAttribute))) 
                {
                    if (m_CABuilders[i].m_constructorArgs.Length != 1)
                    {
                        throw new ArgumentException(Environment.GetResourceString(
                            "Argument_BadCAForUnmngRSC",
                            m_CABuilders[i].m_con.ReflectedType.Name));
                    }
                    if (m_OverrideUnmanagedVersionInfo == false)
                    {
                        m_nativeVersion.m_strProductVersion = m_CABuilders[i].m_constructorArgs[0].ToString();
                    }
                }
                else if (conType.Equals(typeof(System.Reflection.AssemblyCultureAttribute))) 
                {
                    // retrieve the LCID
                    if (m_CABuilders[i].m_constructorArgs.Length != 1)
                    {
                        throw new ArgumentException(Environment.GetResourceString(
                            "Argument_BadCAForUnmngRSC",
                            m_CABuilders[i].m_con.ReflectedType.Name));
                    }
                    // CultureInfo attribute overrides the lcid from AssemblyName.                                      
                    CultureInfo culture = new CultureInfo(m_CABuilders[i].m_constructorArgs[0].ToString());
#if FEATURE_USE_LCID                    
                    m_nativeVersion.m_lcid = culture.LCID;
#endif
                }
                else if (conType.Equals(typeof(System.Reflection.AssemblyFileVersionAttribute))) 
                {
                    if (m_CABuilders[i].m_constructorArgs.Length != 1)
                    {
                        throw new ArgumentException(Environment.GetResourceString(
                            "Argument_BadCAForUnmngRSC",
                            m_CABuilders[i].m_con.ReflectedType.Name));
                    }
                    if (m_OverrideUnmanagedVersionInfo == false)
                    {
                        m_nativeVersion.m_strFileVersion = m_CABuilders[i].m_constructorArgs[0].ToString();
                    }
                }
            }
        }
#endif //!FEATURE_PAL
        
        // Helper to ensure the resource name is unique underneath assemblyBuilder
        internal void CheckResNameConflict(String strNewResName)
        {
            int         size = m_resWriterList.Count;
            int         i;
            for (i = 0; i < size; i++) 
            {
                ResWriterData resWriter = m_resWriterList[i];
                if (resWriter.m_strName.Equals(strNewResName))
                {
                    // Cannot have two resources with the same name
                    throw new ArgumentException(Environment.GetResourceString("Argument_DuplicateResourceName"));
                }
            }        
        }
 
    
        // Helper to ensure the module name is unique underneath assemblyBuilder
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine | ResourceScope.Assembly, ResourceScope.Machine | ResourceScope.Assembly)]
        internal void CheckNameConflict(String strNewModuleName)
        {
            int         size = m_moduleBuilderList.Count;
            int         i;
            for (i = 0; i < size; i++) 
            {
                ModuleBuilder moduleBuilder = m_moduleBuilderList[i];
                if (moduleBuilder.m_moduleData.m_strModuleName.Equals(strNewModuleName))
                {
                    // Cannot have two dynamic modules with the same name
                    throw new ArgumentException(Environment.GetResourceString("Argument_DuplicateModuleName"));
                }
            }
 
            // Right now dynamic modules can only be added to dynamic assemblies in which
            // all modules are dynamic. Otherwise we would also need to check the static modules 
            // with this:
            //  if (m_assembly.GetModule(strNewModuleName) != null)
            //  {
            //      // Cannot have two dynamic modules with the same name
            //      throw new ArgumentException(Environment.GetResourceString("Argument_DuplicateModuleName"));
            //  }
        }
    
        // Helper to ensure the type name is unique underneath assemblyBuilder
        internal void CheckTypeNameConflict(String strTypeName, TypeBuilder enclosingType)
        {
            BCLDebug.Log("DYNIL","## DYNIL LOGGING: AssemblyBuilderData.CheckTypeNameConflict( " + strTypeName + " )"); 
            for (int i = 0; i < m_moduleBuilderList.Count; i++) 
            {
                ModuleBuilder curModule = m_moduleBuilderList[i];
                curModule.CheckTypeNameConflict(strTypeName, enclosingType);
            }
 
            // Right now dynamic modules can only be added to dynamic assemblies in which
            // all modules are dynamic. Otherwise we would also need to check loaded types.
            // We only need to make this test for non-nested types since any
            // duplicates in nested types will be caught at the top level.
            //      if (enclosingType == null && m_assembly.GetType(strTypeName, false, false) != null)
            //      {
            //          // Cannot have two types with the same name
            //          throw new ArgumentException(Environment.GetResourceString("Argument_DuplicateTypeName"));
            //      }
        }
        
 
        // Helper to ensure the file name is unique underneath assemblyBuilder. This includes 
        // modules and resources.
        //  
        //  
        //  
        internal void CheckFileNameConflict(String strFileName)
        {
            int         size = m_moduleBuilderList.Count;
            int         i;
            for (i = 0; i < size; i++) 
            {
                ModuleBuilder moduleBuilder = m_moduleBuilderList[i];
                if (moduleBuilder.m_moduleData.m_strFileName != null)
                {
                    if (String.Compare(moduleBuilder.m_moduleData.m_strFileName, strFileName, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // Cannot have two dynamic module with the same name
                        throw new ArgumentException(Environment.GetResourceString("Argument_DuplicatedFileName"));
                    }
                }
            }    
            size = m_resWriterList.Count;
            for (i = 0; i < size; i++) 
            {
                ResWriterData resWriter = m_resWriterList[i];
                if (resWriter.m_strFileName != null)
                {
                    if (String.Compare(resWriter.m_strFileName, strFileName, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // Cannot have two dynamic module with the same name
                        throw new ArgumentException(Environment.GetResourceString("Argument_DuplicatedFileName"));
                    }
                }
            }    
 
        }
    
        // Helper to look up which module that assembly is supposed to be stored at
        //  
        // 
        //  
        internal ModuleBuilder FindModuleWithFileName(String strFileName)
        {
            int         size = m_moduleBuilderList.Count;
            int         i;
            for (i = 0; i < size; i++) 
            {
                ModuleBuilder moduleBuilder = m_moduleBuilderList[i];
                if (moduleBuilder.m_moduleData.m_strFileName != null)
                {
                    if (String.Compare(moduleBuilder.m_moduleData.m_strFileName, strFileName, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return moduleBuilder;
                    }
                }
            } 
            return null;       
        }
 
        // Helper to look up module by name.
        //  
        // 
        //  
        internal ModuleBuilder FindModuleWithName(String strName)
        {
            int         size = m_moduleBuilderList.Count;
            int         i;
            for (i = 0; i < size; i++) 
            {
                ModuleBuilder moduleBuilder = m_moduleBuilderList[i];
                if (moduleBuilder.m_moduleData.m_strModuleName != null)
                {
                    if (String.Compare(moduleBuilder.m_moduleData.m_strModuleName, strName, StringComparison.OrdinalIgnoreCase) == 0)
                        return moduleBuilder;
                }
            } 
            return null;       
        }
 
        
        // add type to public COMType tracking list
        internal void AddPublicComType(Type type)
        {
            BCLDebug.Log("DYNIL","## DYNIL LOGGING: AssemblyBuilderData.AddPublicComType( " + type.FullName + " )"); 
            if (m_isSaved == true)
            {
                // assembly has been saved before!
                throw new InvalidOperationException(Environment.GetResourceString(
                    "InvalidOperation_CannotAlterAssembly"));
            }        
            EnsurePublicComTypeCapacity();
            m_publicComTypeList[m_iPublicComTypeCount] = type;
            m_iPublicComTypeCount++;
        }
        
        // add security permission requests
        internal void AddPermissionRequests(
            PermissionSet       required,
            PermissionSet       optional,
            PermissionSet       refused)
        {
            BCLDebug.Log("DYNIL","## DYNIL LOGGING: AssemblyBuilderData.AddPermissionRequests");
            if (m_isSaved == true)
            {
                // assembly has been saved before!
                throw new InvalidOperationException(Environment.GetResourceString(
                    "InvalidOperation_CannotAlterAssembly"));
            }        
            m_RequiredPset = required;
            m_OptionalPset = optional;
            m_RefusedPset = refused;
        }
        
        private void EnsurePublicComTypeCapacity()
        {
            if (m_publicComTypeList == null)
            {
                m_publicComTypeList = new Type[m_iInitialSize];
            }
            if (m_iPublicComTypeCount == m_publicComTypeList.Length)
            {
                Type[]  tempTypeList = new Type[m_iPublicComTypeCount * 2];
                Array.Copy(m_publicComTypeList, tempTypeList, m_iPublicComTypeCount);
                m_publicComTypeList = tempTypeList;            
            }
        }
         
        internal List<ModuleBuilder>    m_moduleBuilderList;
        internal List<ResWriterData>    m_resWriterList;
        internal String                 m_strAssemblyName;
        internal AssemblyBuilderAccess  m_access;
        private InternalAssemblyBuilder m_assembly;
        
        internal Type[]                 m_publicComTypeList;
        internal int                    m_iPublicComTypeCount;
        
        internal bool                   m_isSaved;    
        internal const int              m_iInitialSize = 16;
        internal String                 m_strDir;
 
        // hard coding the assembly def token
        internal const int              m_tkAssembly = 0x20000001;
    
        // Security permission requests
        internal PermissionSet          m_RequiredPset;
        internal PermissionSet          m_OptionalPset;
        internal PermissionSet          m_RefusedPset;
        
        // tracking AssemblyDef's CAs for persistence to disk
        internal CustomAttributeBuilder[] m_CABuilders;
        internal int                    m_iCABuilder;
        internal byte[][]               m_CABytes;
        internal ConstructorInfo[]      m_CACons;
        internal int                    m_iCAs;
        internal PEFileKinds            m_peFileKind;           // assembly file kind
        internal MethodInfo             m_entryPointMethod;
        internal Assembly               m_ISymWrapperAssembly;
 
#if !FEATURE_CORECLR
        internal ModuleBuilder          m_entryPointModule;
#endif //!FEATURE_CORECLR
                                  
#if !FEATURE_PAL
        // For unmanaged resources
        internal String                 m_strResourceFileName;
        internal byte[]                 m_resourceBytes;
        internal NativeVersionInfo      m_nativeVersion;
        internal bool                   m_hasUnmanagedVersionInfo;
        internal bool                   m_OverrideUnmanagedVersionInfo;
#endif // !FEATURE_PAL
 
    }
 
    
    /**********************************************
    *
    * Internal structure to track the list of ResourceWriter for
    * AssemblyBuilder & ModuleBuilder.
    *
    **********************************************/
    internal class ResWriterData 
    {
#if FEATURE_CORECLR
        internal ResWriterData(
            IResourceWriter  resWriter,
            Stream          memoryStream,
            String          strName,
            String          strFileName,
            String          strFullFileName,
            ResourceAttributes attribute)
        {
            m_resWriter = resWriter;
            m_memoryStream = memoryStream;
            m_strName = strName;
            m_strFileName = strFileName;
            m_strFullFileName = strFullFileName;
            m_nextResWriter = null;
            m_attribute = attribute;
        }
#else
        internal ResWriterData(
            ResourceWriter  resWriter,
            Stream          memoryStream,
            String          strName,
            String          strFileName,
            String          strFullFileName,
            ResourceAttributes attribute)
        {
            m_resWriter = resWriter;
            m_memoryStream = memoryStream;
            m_strName = strName;
            m_strFileName = strFileName;
            m_strFullFileName = strFullFileName;
            m_nextResWriter = null;
            m_attribute = attribute;
        }
#endif
#if !FEATURE_CORECLR
        internal ResourceWriter         m_resWriter;
#else // FEATURE_CORECLR
         internal IResourceWriter         m_resWriter;
#endif // !FEATURE_CORECLR
        internal String                 m_strName;
        internal String                 m_strFileName;
        internal String                 m_strFullFileName;
        internal Stream                 m_memoryStream;
        internal ResWriterData          m_nextResWriter;
        internal ResourceAttributes     m_attribute;
    }
 
#if !FEATURE_PAL
    internal class NativeVersionInfo
    {
        internal NativeVersionInfo()
        {
            m_strDescription = null;
            m_strCompany = null;
            m_strTitle = null;
            m_strCopyright = null;
            m_strTrademark = null;
            m_strProduct = null;
            m_strProductVersion = null;
            m_strFileVersion = null;
            m_lcid = -1;
        }
        
        internal String     m_strDescription;
        internal String     m_strCompany;           
        internal String     m_strTitle;
        internal String     m_strCopyright;         
        internal String     m_strTrademark;
        internal String     m_strProduct;           
        internal String     m_strProductVersion;        
        internal String     m_strFileVersion;
        internal int        m_lcid;
    }
#endif //!FEATURE_PAL
 
}