X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.Reflection.Emit%2FAssemblyBuilder.cs;h=b4dacd032be0d94e7909a25122020a64a42591e5;hb=c39145af2464b19374fac41b252e07480ae1a197;hp=4e259460d03294ab5f43c3fb468aa934262e37a5;hpb=8690b151f212137597c5f8c746c05f02fcb4ad51;p=mono.git diff --git a/mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs index 4e259460d03..b4dacd032be 100755 --- a/mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs @@ -7,6 +7,29 @@ // (C) 2001 Ximian, Inc. http://www.ximian.com // +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + using System; using System.Reflection; using System.Resources; @@ -17,6 +40,7 @@ using System.Globalization; using System.Runtime.CompilerServices; using System.Collections; using System.Runtime.InteropServices; +using System.Security; using System.Security.Cryptography; using System.Security.Permissions; @@ -43,6 +67,20 @@ namespace System.Reflection.Emit { public int offset; } + internal struct MonoWin32Resource { + public int res_type; + public int res_id; + public int lang_id; + public byte[] data; + + public MonoWin32Resource (int res_type, int res_id, int lang_id, byte[] data) { + this.res_type = res_type; + this.res_id = res_id; + this.lang_id = lang_id; + this.data = data; + } + } + public sealed class AssemblyBuilder : Assembly { #region Sync with reflection.h private IntPtr dynamic_assembly; @@ -60,19 +98,29 @@ namespace System.Reflection.Emit { PEFileKinds pekind = PEFileKinds.Dll; bool delay_sign; uint access; + Module[] loaded_modules; + MonoWin32Resource[] win32_resources; + private RefEmitPermissionSet[] permissions_minimum; + private RefEmitPermissionSet[] permissions_optional; + private RefEmitPermissionSet[] permissions_refused; + PortableExecutableKind peKind; + ImageFileMachine machine; + bool corlib_internal; #endregion internal Type corlib_object_type = typeof (System.Object); internal Type corlib_value_type = typeof (System.ValueType); internal Type corlib_enum_type = typeof (System.Enum); internal Type corlib_void_type = typeof (void); ArrayList resource_writers = null; + Win32VersionResource version_res; bool created; bool is_module_only; + private Mono.Security.StrongName sn; [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern void basic_init (AssemblyBuilder ab); - internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access) { + internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access, bool corlib_internal) { name = n.Name; if (directory == null || directory == String.Empty) dir = Directory.GetCurrentDirectory (); @@ -89,6 +137,20 @@ namespace System.Reflection.Emit { version = v.ToString (); } + if (n.KeyPair != null) { + // full keypair is available (for signing) + sn = n.KeyPair.StrongName (); + } + else { + // public key is available (for delay-signing) + byte[] pk = n.GetPublicKey (); + if ((pk != null) && (pk.Length > 0)) { + sn = new Mono.Security.StrongName (pk); + } + } + + this.corlib_internal = corlib_internal; + basic_init (this); } @@ -151,12 +213,45 @@ namespace System.Reflection.Emit { resources [p].attrs = attribute; } - public void EmbedResourceFile (string name, string fileName) + /// + /// Don't change the method name and parameters order. It is used by mcs + /// + internal void AddPermissionRequests (PermissionSet required, PermissionSet optional, PermissionSet refused) + { + if (created) + throw new InvalidOperationException ("Assembly was already saved."); + + // required for base Assembly class (so the permissions + // can be used even if the assembly isn't saved to disk) + _minimum = required; + _optional = optional; + _refuse = refused; + + // required to reuse AddDeclarativeSecurity support + // already present in the runtime + if (required != null) { + permissions_minimum = new RefEmitPermissionSet [1]; + permissions_minimum [0] = new RefEmitPermissionSet ( + SecurityAction.RequestMinimum, required.ToXml ().ToString ()); + } + if (optional != null) { + permissions_optional = new RefEmitPermissionSet [1]; + permissions_optional [0] = new RefEmitPermissionSet ( + SecurityAction.RequestOptional, optional.ToXml ().ToString ()); + } + if (refused != null) { + permissions_refused = new RefEmitPermissionSet [1]; + permissions_refused [0] = new RefEmitPermissionSet ( + SecurityAction.RequestRefuse, refused.ToXml ().ToString ()); + } + } + + internal void EmbedResourceFile (string name, string fileName) { EmbedResourceFile (name, fileName, ResourceAttributes.Public); } - public void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute) + internal void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute) { if (resources != null) { MonoResource[] new_r = new MonoResource [resources.Length + 1]; @@ -237,15 +332,39 @@ namespace System.Reflection.Emit { if (modules != null) { ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1]; System.Array.Copy(modules, new_modules, modules.Length); - new_modules [modules.Length] = r; modules = new_modules; } else { modules = new ModuleBuilder [1]; - modules [0] = r; } + modules [modules.Length - 1] = r; return r; } + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private extern Module InternalAddModule (string fileName); + + /* + * Mono extension to support /addmodule in mcs. + */ + internal Module AddModule (string fileName) + { + if (fileName == null) + throw new ArgumentNullException (fileName); + + Module m = InternalAddModule (fileName); + + if (loaded_modules != null) { + Module[] new_modules = new Module [loaded_modules.Length + 1]; + System.Array.Copy (loaded_modules, new_modules, loaded_modules.Length); + loaded_modules = new_modules; + } else { + loaded_modules = new Module [1]; + } + loaded_modules [loaded_modules.Length - 1] = m; + + return m; + } + public IResourceWriter DefineResource (string name, string description, string fileName) { return DefineResource (name, description, fileName, ResourceAttributes.Public); @@ -265,16 +384,35 @@ namespace System.Reflection.Emit { return writer; } + private void AddUnmanagedResource (Win32Resource res) { + MemoryStream ms = new MemoryStream (); + res.WriteTo (ms); + + if (win32_resources != null) { + MonoWin32Resource[] new_res = new MonoWin32Resource [win32_resources.Length + 1]; + System.Array.Copy (win32_resources, new_res, win32_resources.Length); + win32_resources = new_res; + } + else + win32_resources = new MonoWin32Resource [1]; + + win32_resources [win32_resources.Length - 1] = new MonoWin32Resource (res.Type.Id, res.Name.Id, res.Language, ms.ToArray ()); + } + [MonoTODO] public void DefineUnmanagedResource (byte[] resource) { if (resource == null) throw new ArgumentNullException ("resource"); + /* + * The format of the argument byte array is not documented + * so this method is impossible to implement. + */ + throw new NotImplementedException (); } - [MonoTODO] public void DefineUnmanagedResource (string resourceFileName) { if (resourceFileName == null) @@ -284,20 +422,106 @@ namespace System.Reflection.Emit { if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName)) throw new FileNotFoundException ("File '" + resourceFileName + "' does not exists or is a directory."); - throw new NotImplementedException (); + using (FileStream fs = new FileStream (resourceFileName, FileMode.Open)) { + Win32ResFileReader reader = new Win32ResFileReader (fs); + + foreach (Win32EncodedResource res in reader.ReadResources ()) { + if (res.Name.IsName || res.Type.IsName) + throw new InvalidOperationException ("resource files with named resources or non-default resource types are not supported."); + + AddUnmanagedResource (res); + } + } } - [MonoTODO] public void DefineVersionInfoResource () { - throw new NotImplementedException (); + if (version_res != null) + throw new ArgumentException ("Native resource has already been defined."); + + version_res = new Win32VersionResource (1, 0); + + if (cattrs != null) { + foreach (CustomAttributeBuilder cb in cattrs) { + string attrname = cb.Ctor.ReflectedType.FullName; + + if (attrname == "System.Reflection.AssemblyProductAttribute") + version_res.ProductName = cb.string_arg (); + else if (attrname == "System.Reflection.AssemblyCompanyAttribute") + version_res.CompanyName = cb.string_arg (); + else if (attrname == "System.Reflection.AssemblyCopyrightAttribute") + version_res.LegalCopyright = cb.string_arg (); + else if (attrname == "System.Reflection.AssemblyTrademarkAttribute") + version_res.LegalTrademarks = cb.string_arg (); + else if (attrname == "System.Reflection.AssemblyCultureAttribute") + version_res.FileLanguage = new CultureInfo (GetCultureString (cb.string_arg ())).LCID; + else if (attrname == "System.Reflection.AssemblyFileVersionAttribute") + version_res.FileVersion = cb.string_arg (); + else if (attrname == "System.Reflection.AssemblyInformationalVersionAttribute") + version_res.ProductVersion = cb.string_arg (); + else if (attrname == "System.Reflection.AssemblyTitleAttribute") + version_res.FileDescription = cb.string_arg (); + else if (attrname == "System.Reflection.AssemblyDescriptionAttribute") + version_res.Comments = cb.string_arg (); + } + } } - [MonoTODO] public void DefineVersionInfoResource (string product, string productVersion, string company, string copyright, string trademark) { - throw new NotImplementedException (); + if (version_res != null) + throw new ArgumentException ("Native resource has already been defined."); + + /* + * We can only create the resource later, when the file name and + * the binary version is known. + */ + + version_res = new Win32VersionResource (1, 0); + version_res.ProductName = product; + version_res.ProductVersion = productVersion; + version_res.CompanyName = company; + version_res.LegalCopyright = copyright; + version_res.LegalTrademarks = trademark; + } + + /* + * Mono extension to support /win32icon in mcs + */ + internal void DefineIconResource (string iconFileName) + { + if (iconFileName == null) + throw new ArgumentNullException ("iconFileName"); + if (iconFileName == String.Empty) + throw new ArgumentException ("iconFileName"); + if (!File.Exists (iconFileName) || Directory.Exists (iconFileName)) + throw new FileNotFoundException ("File '" + iconFileName + "' does not exists or is a directory."); + + using (FileStream fs = new FileStream (iconFileName, FileMode.Open)) { + Win32IconFileReader reader = new Win32IconFileReader (fs); + + ICONDIRENTRY[] entries = reader.ReadIcons (); + + Win32IconResource[] icons = new Win32IconResource [entries.Length]; + for (int i = 0; i < entries.Length; ++i) { + icons [i] = new Win32IconResource (i + 1, 0, entries [i]); + AddUnmanagedResource (icons [i]); + } + + Win32GroupIconResource group = new Win32GroupIconResource (1, 0, icons); + AddUnmanagedResource (group); + } + } + + private void DefineVersionInfoResourceImpl (string fileName) { + // Add missing info + if (version_res.FileVersion == "0.0.0.0") + version_res.FileVersion = version; + version_res.InternalName = Path.GetFileNameWithoutExtension (fileName); + version_res.OriginalFilename = fileName; + + AddUnmanagedResource (version_res); } public ModuleBuilder GetDynamicModule (string name) @@ -369,8 +593,16 @@ namespace System.Reflection.Emit { } } - public void Save (string assemblyFileName) +#if NET_2_0 + public +#else + internal +#endif + void Save (string assemblyFileName, PortableExecutableKind portableExecutableKind, ImageFileMachine imageFileMachine) { + this.peKind = portableExecutableKind; + this.machine = imageFileMachine; + if (resource_writers != null) { foreach (IResourceWriter writer in resource_writers) { writer.Generate (); @@ -380,15 +612,47 @@ namespace System.Reflection.Emit { // Create a main module if not already created ModuleBuilder mainModule = null; - foreach (ModuleBuilder module in modules) - if (module.FullyQualifiedName == assemblyFileName) - mainModule = module; + if (modules != null) { + foreach (ModuleBuilder module in modules) + if (module.FullyQualifiedName == assemblyFileName) + mainModule = module; + } if (mainModule == null) mainModule = DefineDynamicModule ("RefEmit_OnDiskManifestModule", assemblyFileName); if (!is_module_only) mainModule.IsMain = true; + /* + * Create a new entry point if the one specified + * by the user is in another module. + */ + if ((entry_point != null) && entry_point.DeclaringType.Module != mainModule) { + Type[] paramTypes; + if (entry_point.GetParameters ().Length == 1) + paramTypes = new Type [] { typeof (string) }; + else + paramTypes = new Type [0]; + + MethodBuilder mb = mainModule.DefineGlobalMethod ("__EntryPoint$", MethodAttributes.Static|MethodAttributes.PrivateScope, entry_point.ReturnType, paramTypes); + ILGenerator ilgen = mb.GetILGenerator (); + if (paramTypes.Length == 1) + ilgen.Emit (OpCodes.Ldarg_0); + ilgen.Emit (OpCodes.Tailcall); + ilgen.Emit (OpCodes.Call, entry_point); + ilgen.Emit (OpCodes.Ret); + + entry_point = mb; + } + + if (version_res != null) + DefineVersionInfoResourceImpl (assemblyFileName); + + if (sn != null) { + // runtime needs to value to embed it into the assembly + public_key = sn.PublicKey; + } + foreach (ModuleBuilder module in modules) if (module != mainModule) module.Save (); @@ -397,9 +661,18 @@ namespace System.Reflection.Emit { // contain the hash of the other modules mainModule.Save (); + if ((sn != null) && (sn.CanSign)) { + sn.Sign (System.IO.Path.Combine (this.AssemblyDir, assemblyFileName)); + } + created = true; } + public void Save (string assemblyFileName) + { + Save (assemblyFileName, PortableExecutableKind.ILOnly, ImageFileMachine.I386); + } + public void SetEntryPoint (MethodInfo entryMethod) { SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication); @@ -423,50 +696,13 @@ namespace System.Reflection.Emit { string attrname = customBuilder.Ctor.ReflectedType.FullName; byte[] data; - int len, pos; - Mono.Security.StrongName sn; + int pos; + if (attrname == "System.Reflection.AssemblyVersionAttribute") { - data = customBuilder.Data; - pos = 2; - len = CustomAttributeBuilder.decode_len (data, pos, out pos); - version = create_assembly_version (CustomAttributeBuilder.string_from_bytes (data, pos, len)); - return; - } else if (attrname == "System.Reflection.AssemblyKeyFileAttribute") { - data = customBuilder.Data; - pos = 2; - len = CustomAttributeBuilder.decode_len (data, pos, out pos); - string keyfile_name = CustomAttributeBuilder.string_from_bytes (data, pos, len); - if (keyfile_name == String.Empty) - return; - using (FileStream fs = new FileStream (keyfile_name, FileMode.Open)) { - byte[] snkeypair = new byte [fs.Length]; - fs.Read (snkeypair, 0, snkeypair.Length); - - // this will import public or private/public keys - RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair); - // and export only the public part - sn = new Mono.Security.StrongName (rsa); - public_key = sn.PublicKey; - } - return; - } else if (attrname == "System.Reflection.AssemblyKeyNameAttribute") { - data = customBuilder.Data; - pos = 2; - len = CustomAttributeBuilder.decode_len (data, pos, out pos); - string key_name = CustomAttributeBuilder.string_from_bytes (data, pos, len); - if (key_name == String.Empty) - return; - CspParameters csparam = new CspParameters (); - csparam.KeyContainerName = key_name; - RSA rsacsp = new RSACryptoServiceProvider (csparam); - sn = new Mono.Security.StrongName (rsacsp); - public_key = sn.PublicKey; + version = create_assembly_version (customBuilder.string_arg ()); return; } else if (attrname == "System.Reflection.AssemblyCultureAttribute") { - data = customBuilder.Data; - pos = 2; - len = CustomAttributeBuilder.decode_len (data, pos, out pos); - culture = CustomAttributeBuilder.string_from_bytes (data, pos, len); + culture = GetCultureString (customBuilder.string_arg ()); } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") { data = customBuilder.Data; pos = 2; @@ -482,11 +718,8 @@ namespace System.Reflection.Emit { flags |= ((uint)data [pos + 2]) << 16; flags |= ((uint)data [pos + 3]) << 24; return; - } else if (attrname == "System.Reflection.AssemblyDelaySignAttribute") { - data = customBuilder.Data; - pos = 2; - delay_sign = data [2] != 0; } + if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1]; cattrs.CopyTo (new_array, 0); @@ -497,6 +730,7 @@ namespace System.Reflection.Emit { cattrs [0] = customBuilder; } } + public void SetCustomAttribute ( ConstructorInfo con, byte[] binaryAttribute) { if (con == null) throw new ArgumentNullException ("con"); @@ -506,13 +740,13 @@ namespace System.Reflection.Emit { SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute)); } - public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type) { + internal void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type) { this.corlib_object_type = corlib_object_type; this.corlib_value_type = corlib_value_type; this.corlib_enum_type = corlib_enum_type; } - public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type, Type corlib_void_type) + internal void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type, Type corlib_void_type) { SetCorlibTypeBuilders (corlib_object_type, corlib_value_type, corlib_enum_type); this.corlib_void_type = corlib_void_type; @@ -599,5 +833,10 @@ namespace System.Reflection.Emit { return ver [0] + "." + ver [1] + "." + ver [2] + "." + ver [3]; } + + private string GetCultureString (string str) + { + return (str == "neutral" ? String.Empty : str); + } } }