Merge pull request #4118 from petertiedemann/fix-bug-48516
[mono.git] / mcs / class / corlib / System.Reflection.Emit / AssemblyBuilder.cs
1 //
2 // System.Reflection.Emit/AssemblyBuilder.cs
3 //
4 // Author:
5 //   Paolo Molaro (lupus@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.  http://www.ximian.com
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 #if !FULL_AOT_RUNTIME
34 using System;
35 using System.Reflection;
36 using System.Resources;
37 using System.IO;
38 using System.Security.Policy;
39 using System.Runtime.Serialization;
40 using System.Globalization;
41 using System.Runtime.CompilerServices;
42 using System.Collections;
43 using System.Collections.Generic;
44 using System.Runtime.InteropServices;
45 using System.Security;
46 using System.Security.Cryptography;
47 using System.Security.Permissions;
48
49 using Mono.Security;
50 using Mono.Security.Cryptography;
51
52 namespace System.Reflection.Emit
53 {
54         internal enum NativeResourceType
55         {
56                 None,
57                 Unmanaged,
58                 Assembly,
59                 Explicit
60         }
61
62         internal struct RefEmitPermissionSet {
63                 public SecurityAction action;
64                 public string pset;
65
66                 public RefEmitPermissionSet (SecurityAction action, string pset) {
67                         this.action = action;
68                         this.pset = pset;
69                 }
70         }
71
72         internal struct MonoResource {
73 #pragma warning disable 649
74                 public byte[] data;
75                 public string name;
76                 public string filename;
77                 public ResourceAttributes attrs;
78                 public int offset;
79                 public Stream stream;
80 #pragma warning restore 649
81         }
82
83         internal struct MonoWin32Resource {
84                 public int res_type;
85                 public int res_id;
86                 public int lang_id;
87                 public byte[] data;
88
89                 public MonoWin32Resource (int res_type, int res_id, int lang_id, byte[] data) {
90                         this.res_type = res_type;
91                         this.res_id = res_id;
92                         this.lang_id = lang_id;
93                         this.data = data;
94                 }
95         }
96
97         internal class GenericInstanceKey {
98                 Type gtd;
99                 internal Type[] args;
100                 int hash_code;
101
102                 internal GenericInstanceKey (Type gtd, Type[] args)
103                 {
104                         this.gtd = gtd;
105                         this.args = args;
106
107                         hash_code = gtd.GetHashCode ();
108                         for (int i = 0; i < args.Length; ++i)
109                                 hash_code ^= args [i].GetHashCode ();
110                 }
111
112                 static bool IsBoundedVector (Type type) {
113                         ArrayType at = type as ArrayType;
114                         if (at != null)
115                                 return at.GetEffectiveRank () == 1;
116                         return type.ToString ().EndsWith ("[*]", StringComparison.Ordinal); /*Super uggly hack, SR doesn't allow one to query for it */
117                 }
118
119                 static bool TypeEquals (Type a, Type b) {
120                         if (a == b)
121                                 return true;
122
123                         if (a.HasElementType) {
124                                 if (!b.HasElementType)
125                                         return false;
126                                 if (!TypeEquals (a.GetElementType (), b.GetElementType ()))
127                                         return false;
128                                 if (a.IsArray) {
129                                         if (!b.IsArray)
130                                                 return false;
131                                         int rank = a.GetArrayRank ();
132                                         if (rank != b.GetArrayRank ())
133                                                 return false;
134                                         if (rank == 1 && IsBoundedVector (a) != IsBoundedVector (b))
135                                                 return false;
136                                 } else if (a.IsByRef) {
137                                         if (!b.IsByRef)
138                                                 return false;
139                                 } else if (a.IsPointer) {
140                                         if (!b.IsPointer)
141                                                 return false;
142                                 }
143                                 return true;
144                         }
145
146                         if (a.IsGenericType) {
147                                 if (!b.IsGenericType)
148                                         return false;
149                                 if (a.IsGenericParameter)
150                                         return a == b;
151                                 if (a.IsGenericParameter) //previous test should have caught it
152                                         return false;
153
154                                 if (a.IsGenericTypeDefinition) {
155                                         if (!b.IsGenericTypeDefinition)
156                                                 return false;
157                                 } else {
158                                         if (b.IsGenericTypeDefinition)
159                                                 return false;
160                                         if (!TypeEquals (a.GetGenericTypeDefinition (), b.GetGenericTypeDefinition ()))
161                                                 return false;
162
163                                         Type[] argsA = a.GetGenericArguments ();
164                                         Type[] argsB = b.GetGenericArguments ();
165                                         for (int i = 0; i < argsA.Length; ++i) {
166                                                 if (!TypeEquals (argsA [i], argsB [i]))
167                                                         return false;
168                                         }
169                                 }
170                         }
171
172                         /*
173                         Now only non-generic, non compound types are left. To properly deal with user
174                         types we would have to call UnderlyingSystemType, but we let them have their
175                         own instantiation as this is MS behavior and mcs (pre C# 4.0, at least) doesn't
176                         depend on proper UT canonicalization.
177                         */
178                         return a == b;
179                 }
180
181                 public override bool Equals (object obj)
182                 {
183                         GenericInstanceKey other = obj as GenericInstanceKey;
184                         if (other == null)
185                                 return false;
186                         if (gtd != other.gtd)
187                                 return false;
188                         for (int i = 0; i < args.Length; ++i) {
189                                 Type a = args [i];
190                                 Type b = other.args [i];
191                                 /*
192                                 We must cannonicalize as much as we can. Using equals means that some resulting types
193                                 won't have the exact same types as the argument ones. 
194                                 For example, flyweight types used array, pointer and byref will should this behavior.
195                                 MCS seens to be resilient to this problem so hopefully this won't show up.   
196                                 */
197                                 if (a != b && !a.Equals (b))
198                                         return false;
199                         }
200                         return true;
201                 }
202
203                 public override int GetHashCode ()
204                 {
205                         return hash_code;
206                 }
207         }
208
209
210         [ComVisible (true)]
211         [ComDefaultInterface (typeof (_AssemblyBuilder))]
212         [ClassInterface (ClassInterfaceType.None)]
213         [StructLayout (LayoutKind.Sequential)]
214         public sealed class AssemblyBuilder : Assembly, _AssemblyBuilder {
215 #pragma warning disable 169, 414, 649
216                 #region Sync with object-internals.h
217                 private UIntPtr dynamic_assembly; /* GC-tracked */
218                 private MethodInfo entry_point;
219                 private ModuleBuilder[] modules;
220                 private string name;
221                 private string dir;
222                 private CustomAttributeBuilder[] cattrs;
223                 private MonoResource[] resources;
224                 byte[] public_key;
225                 string version;
226                 string culture;
227                 uint algid;
228                 uint flags;
229                 PEFileKinds pekind = PEFileKinds.Dll;
230                 bool delay_sign;
231                 uint access;
232                 Module[] loaded_modules;
233                 MonoWin32Resource[] win32_resources;
234                 private RefEmitPermissionSet[] permissions_minimum;
235                 private RefEmitPermissionSet[] permissions_optional;
236                 private RefEmitPermissionSet[] permissions_refused;
237                 PortableExecutableKinds peKind;
238                 ImageFileMachine machine;
239                 bool corlib_internal;
240                 Type[] type_forwarders;
241                 byte[] pktoken;
242                 #endregion
243 #pragma warning restore 169, 414, 649
244                 
245                 internal Type corlib_object_type = typeof (System.Object);
246                 internal Type corlib_value_type = typeof (System.ValueType);
247                 internal Type corlib_enum_type = typeof (System.Enum);
248                 internal Type corlib_void_type = typeof (void);
249                 ArrayList resource_writers = null;
250                 Win32VersionResource version_res;
251                 bool created;
252                 bool is_module_only;
253                 private Mono.Security.StrongName sn;
254                 NativeResourceType native_resource;
255                 string versioninfo_culture;
256
257                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
258                 private static extern void basic_init (AssemblyBuilder ab);
259
260                 /* Keep this in sync with codegen.cs in mcs */
261                 private const AssemblyBuilderAccess COMPILER_ACCESS = (AssemblyBuilderAccess) 0x800;
262
263                 internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access, bool corlib_internal)
264                 {
265                         /* This is obsolete now, as mcs doesn't use SRE any more */
266                         if ((access & COMPILER_ACCESS) != 0)
267                                 throw new NotImplementedException ("COMPILER_ACCESS is no longer supperted, use a newer mcs.");
268
269                         if (!Enum.IsDefined (typeof (AssemblyBuilderAccess), access))
270                                 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
271                                         "Argument value {0} is not valid.", (int) access),
272                                         "access");
273
274                         name = n.Name;
275                         this.access = (uint)access;
276                         flags = (uint) n.Flags;
277
278                         // don't call GetCurrentDirectory for Run-only builders (CAS may not like that)
279                         if (IsSave && (directory == null || directory.Length == 0)) {
280                                 dir = Directory.GetCurrentDirectory ();
281                         } else {
282                                 dir = directory;
283                         }
284
285                         /* Set defaults from n */
286                         if (n.CultureInfo != null) {
287                                 culture = n.CultureInfo.Name;
288                                 versioninfo_culture = n.CultureInfo.Name;
289                         }
290                         Version v = n.Version;
291                         if (v != null) {
292                                 version = v.ToString ();
293                         }
294
295                         if (n.KeyPair != null) {
296                                 // full keypair is available (for signing)
297                                 sn = n.KeyPair.StrongName ();
298                         } else {
299                                 // public key is available (for delay-signing)
300                                 byte[] pk = n.GetPublicKey ();
301                                 if ((pk != null) && (pk.Length > 0)) {
302                                         sn = new Mono.Security.StrongName (pk);
303                                 }
304                         }
305
306                         if (sn != null)
307                                 flags |= (uint) AssemblyNameFlags.PublicKey;
308
309                         this.corlib_internal = corlib_internal;
310                         if (sn != null) {
311                                 this.pktoken = new byte[sn.PublicKeyToken.Length * 2];
312                                 int pkti = 0;
313                                 foreach (byte pkb in sn.PublicKeyToken) {
314                                         string part = pkb.ToString("x2");
315                                         this.pktoken[pkti++] = (byte)part[0];
316                                         this.pktoken[pkti++] = (byte)part[1];
317                                 }
318                         }
319
320                         basic_init (this);
321                 }
322
323                 public override string CodeBase {
324                         get {
325                                 throw not_supported ();
326                         }
327                 }
328                 
329                 public override MethodInfo EntryPoint {
330                         get {
331                                 return entry_point;
332                         }
333                 }
334
335                 public override string Location {
336                         get {
337                                 throw not_supported ();
338                         }
339                 }
340
341                 /* This is to keep signature compatibility with MS.NET */
342                 public override string ImageRuntimeVersion {
343                         get {
344                                 return base.ImageRuntimeVersion;
345                         }
346                 }
347
348                 [MonoTODO]
349                 public override bool ReflectionOnly {
350                         get { return base.ReflectionOnly; }
351                 }
352
353                 public void AddResourceFile (string name, string fileName)
354                 {
355                         AddResourceFile (name, fileName, ResourceAttributes.Public);
356                 }
357
358                 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
359                 {
360                         AddResourceFile (name, fileName, attribute, true);
361                 }
362
363                 private void AddResourceFile (string name, string fileName, ResourceAttributes attribute, bool fileNeedsToExists)
364                 {
365                         check_name_and_filename (name, fileName, fileNeedsToExists);
366
367                         // Resource files are created/searched under the assembly storage
368                         // directory
369                         if (dir != null)
370                                 fileName = Path.Combine (dir, fileName);
371
372                         if (resources != null) {
373                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
374                                 System.Array.Copy(resources, new_r, resources.Length);
375                                 resources = new_r;
376                         } else {
377                                 resources = new MonoResource [1];
378                         }
379                         int p = resources.Length - 1;
380                         resources [p].name = name;
381                         resources [p].filename = fileName;
382                         resources [p].attrs = attribute;
383                 }
384
385                 internal void AddPermissionRequests (PermissionSet required, PermissionSet optional, PermissionSet refused)
386                 {
387 #if !MOBILE
388                         if (created)
389                                 throw new InvalidOperationException ("Assembly was already saved.");
390
391                         // required for base Assembly class (so the permissions
392                         // can be used even if the assembly isn't saved to disk)
393                         _minimum = required;
394                         _optional = optional;
395                         _refuse = refused;
396
397                         // required to reuse AddDeclarativeSecurity support 
398                         // already present in the runtime
399                         if (required != null) {
400                                 permissions_minimum = new RefEmitPermissionSet [1];
401                                 permissions_minimum [0] = new RefEmitPermissionSet (
402                                         SecurityAction.RequestMinimum, required.ToXml ().ToString ());
403                         }
404                         if (optional != null) {
405                                 permissions_optional = new RefEmitPermissionSet [1];
406                                 permissions_optional [0] = new RefEmitPermissionSet (
407                                         SecurityAction.RequestOptional, optional.ToXml ().ToString ());
408                         }
409                         if (refused != null) {
410                                 permissions_refused = new RefEmitPermissionSet [1];
411                                 permissions_refused [0] = new RefEmitPermissionSet (
412                                         SecurityAction.RequestRefuse, refused.ToXml ().ToString ());
413                         }
414 #endif
415                 }
416
417                 // Still in use by al.exe
418                 internal void EmbedResourceFile (string name, string fileName)
419                 {
420                         EmbedResourceFile (name, fileName, ResourceAttributes.Public);
421                 }
422
423                 void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
424                 {
425                         if (resources != null) {
426                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
427                                 System.Array.Copy(resources, new_r, resources.Length);
428                                 resources = new_r;
429                         } else {
430                                 resources = new MonoResource [1];
431                         }
432                         int p = resources.Length - 1;
433                         resources [p].name = name;
434                         resources [p].attrs = attribute;
435                         try {
436                                 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
437                                 long len = s.Length;
438                                 resources [p].data = new byte [len];
439                                 s.Read (resources [p].data, 0, (int)len);
440                                 s.Close ();
441                         } catch {
442                         }
443                 }
444 /*
445                 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
446                 {
447                         if (resources != null) {
448                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
449                                 System.Array.Copy(resources, new_r, resources.Length);
450                                 resources = new_r;
451                         } else {
452                                 resources = new MonoResource [1];
453                         }
454                         int p = resources.Length - 1;
455                         resources [p].name = name;
456                         resources [p].attrs = attribute;
457                         resources [p].data = blob;
458                 }
459 */
460
461                 public static AssemblyBuilder DefineDynamicAssembly (AssemblyName name, AssemblyBuilderAccess access)
462                 {
463                         if (name == null)
464                                 throw new ArgumentNullException ("name");
465
466                         return new AssemblyBuilder (name, null, access, false);
467                 }
468
469                 public static AssemblyBuilder DefineDynamicAssembly (AssemblyName name, AssemblyBuilderAccess access, IEnumerable<CustomAttributeBuilder> assemblyAttributes)
470                 {
471                         var ab = DefineDynamicAssembly (name, access);
472                         foreach (var attr in  assemblyAttributes) {
473                                 ab.SetCustomAttribute (attr);
474                         }
475
476                         return ab;
477                 }
478
479                 public ModuleBuilder DefineDynamicModule (string name)
480                 {
481                         return DefineDynamicModule (name, name, false, true);
482                 }
483
484                 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
485                 {
486                         return DefineDynamicModule (name, name, emitSymbolInfo, true);
487                 }
488
489                 public ModuleBuilder DefineDynamicModule(string name, string fileName)
490                 {
491                         return DefineDynamicModule (name, fileName, false, false);
492                 }
493
494                 public ModuleBuilder DefineDynamicModule (string name, string fileName,
495                                                           bool emitSymbolInfo)
496                 {
497                         return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
498                 }
499
500                 private ModuleBuilder DefineDynamicModule (string name, string fileName, bool emitSymbolInfo, bool transient)
501                 {
502                         check_name_and_filename (name, fileName, false);
503
504                         if (!transient) {
505                                 if (Path.GetExtension (fileName) == String.Empty)
506                                         throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
507                                 if (!IsSave)
508                                         throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
509                                 if (created)
510                                         throw new InvalidOperationException ("Assembly was already saved.");
511                         }
512
513                         ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, transient);
514
515                         if ((modules != null) && is_module_only)
516                                 throw new InvalidOperationException ("A module-only assembly can only contain one module.");
517
518                         if (modules != null) {
519                                 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
520                                 System.Array.Copy(modules, new_modules, modules.Length);
521                                 modules = new_modules;
522                         } else {
523                                 modules = new ModuleBuilder [1];
524                         }
525                         modules [modules.Length - 1] = r;
526                         return r;
527                 }
528
529                 public IResourceWriter DefineResource (string name, string description, string fileName)
530                 {
531                         return DefineResource (name, description, fileName, ResourceAttributes.Public);
532                 }
533
534                 public IResourceWriter DefineResource (string name, string description,
535                                                        string fileName, ResourceAttributes attribute)
536                 {
537                         IResourceWriter writer;
538
539                         // description seems to be ignored
540                         AddResourceFile (name, fileName, attribute, false);
541                         writer = new ResourceWriter (fileName);
542                         if (resource_writers == null)
543                                 resource_writers = new ArrayList ();
544                         resource_writers.Add (writer);
545                         return writer;
546                 }
547
548                 private void AddUnmanagedResource (Win32Resource res) {
549                         MemoryStream ms = new MemoryStream ();
550                         res.WriteTo (ms);
551
552                         if (win32_resources != null) {
553                                 MonoWin32Resource[] new_res = new MonoWin32Resource [win32_resources.Length + 1];
554                                 System.Array.Copy (win32_resources, new_res, win32_resources.Length);
555                                 win32_resources = new_res;
556                         }
557                         else
558                                 win32_resources = new MonoWin32Resource [1];
559
560                         win32_resources [win32_resources.Length - 1] = new MonoWin32Resource (res.Type.Id, res.Name.Id, res.Language, ms.ToArray ());
561                 }
562
563                 [MonoTODO ("Not currently implemenented")]
564                 public void DefineUnmanagedResource (byte[] resource)
565                 {
566                         if (resource == null)
567                                 throw new ArgumentNullException ("resource");
568                         if (native_resource != NativeResourceType.None)
569                                 throw new ArgumentException ("Native resource has already been defined.");
570
571                         // avoid definition of more than one unmanaged resource
572                         native_resource = NativeResourceType.Unmanaged;
573
574                         /*
575                          * The format of the argument byte array is not documented
576                          * so this method is impossible to implement.
577                          *
578                          * https://connect.microsoft.com/VisualStudio/feedback/details/95784/fatal-assemblybuilder-defineunmanagedresource-byte-and-modulebuilder-defineunmanagedresource-byte-bugs-renders-them-useless
579                          */
580
581                         throw new NotImplementedException ();
582                 }
583
584                 public void DefineUnmanagedResource (string resourceFileName)
585                 {
586                         if (resourceFileName == null)
587                                 throw new ArgumentNullException ("resourceFileName");
588                         if (resourceFileName.Length == 0)
589                                 throw new ArgumentException ("resourceFileName");
590                         if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
591                                 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exist or is a directory.");
592                         if (native_resource != NativeResourceType.None)
593                                 throw new ArgumentException ("Native resource has already been defined.");
594
595                         // avoid definition of more than one unmanaged resource
596                         native_resource = NativeResourceType.Unmanaged;
597
598                         using (FileStream fs = new FileStream (resourceFileName, FileMode.Open, FileAccess.Read)) {
599                                 Win32ResFileReader reader = new Win32ResFileReader (fs);
600
601                                 foreach (Win32EncodedResource res in reader.ReadResources ()) {
602                                         if (res.Name.IsName || res.Type.IsName)
603                                                 throw new InvalidOperationException ("resource files with named resources or non-default resource types are not supported.");
604
605                                         AddUnmanagedResource (res);
606                                 }
607                         }
608                 }
609
610                 public void DefineVersionInfoResource ()
611                 {
612                         if (native_resource != NativeResourceType.None)
613                                 throw new ArgumentException ("Native resource has already been defined.");
614
615                         // avoid definition of more than one unmanaged resource
616                         native_resource = NativeResourceType.Assembly;
617
618                         version_res = new Win32VersionResource (1, 0, false);
619                 }
620
621                 public void DefineVersionInfoResource (string product, string productVersion,
622                                                        string company, string copyright, string trademark)
623                 {
624                         if (native_resource != NativeResourceType.None)
625                                 throw new ArgumentException ("Native resource has already been defined.");
626
627                         // avoid definition of more than one unmanaged resource
628                         native_resource = NativeResourceType.Explicit;
629
630                         /*
631                          * We can only create the resource later, when the file name and
632                          * the binary version is known.
633                          */
634
635                         version_res = new Win32VersionResource (1, 0, false);
636                         version_res.ProductName = product != null ? product : " ";
637                         version_res.ProductVersion = productVersion != null ? productVersion : " ";
638                         version_res.CompanyName = company != null ? company : " ";
639                         version_res.LegalCopyright = copyright != null ? copyright : " ";
640                         version_res.LegalTrademarks = trademark != null ? trademark : " ";
641                 }
642
643                 private void DefineVersionInfoResourceImpl (string fileName)
644                 {
645                         if (versioninfo_culture != null)
646                                 version_res.FileLanguage = new CultureInfo (versioninfo_culture).LCID;
647                         version_res.Version = version == null ? "0.0.0.0" : version;
648
649                         if (cattrs != null) {
650                                 switch (native_resource) {
651                                 case NativeResourceType.Assembly:
652                                         foreach (CustomAttributeBuilder cb in cattrs) {
653                                                 string attrname = cb.Ctor.ReflectedType.FullName;
654
655                                                 if (attrname == "System.Reflection.AssemblyProductAttribute")
656                                                         version_res.ProductName = cb.string_arg ();
657                                                 else if (attrname == "System.Reflection.AssemblyCompanyAttribute")
658                                                         version_res.CompanyName = cb.string_arg ();
659                                                 else if (attrname == "System.Reflection.AssemblyCopyrightAttribute")
660                                                         version_res.LegalCopyright = cb.string_arg ();
661                                                 else if (attrname == "System.Reflection.AssemblyTrademarkAttribute")
662                                                         version_res.LegalTrademarks = cb.string_arg ();
663                                                 else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
664                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
665                                                 } else if (attrname == "System.Reflection.AssemblyFileVersionAttribute") {
666                                                         version_res.FileVersion = cb.string_arg ();
667                                                 } else if (attrname == "System.Reflection.AssemblyInformationalVersionAttribute")
668                                                         version_res.ProductVersion = cb.string_arg ();
669                                                 else if (attrname == "System.Reflection.AssemblyTitleAttribute")
670                                                         version_res.FileDescription = cb.string_arg ();
671                                                 else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
672                                                         version_res.Comments = cb.string_arg ();
673                                         }
674                                         break;
675                                 case NativeResourceType.Explicit:
676                                         foreach (CustomAttributeBuilder cb in cattrs) {
677                                                 string attrname = cb.Ctor.ReflectedType.FullName;
678
679                                                 if (attrname == "System.Reflection.AssemblyCultureAttribute") {
680                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
681                                                 } else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
682                                                         version_res.Comments = cb.string_arg ();
683                                         }
684                                         break;
685                                 }
686                         }
687
688                         version_res.OriginalFilename = fileName;
689                         version_res.InternalName = Path.GetFileNameWithoutExtension (fileName);
690
691                         AddUnmanagedResource (version_res);
692                 }
693
694                 public ModuleBuilder GetDynamicModule (string name)
695                 {
696                         if (name == null)
697                                 throw new ArgumentNullException ("name");
698                         if (name.Length == 0)
699                                 throw new ArgumentException ("Empty name is not legal.", "name");
700
701                         if (modules != null)
702                                 for (int i = 0; i < modules.Length; ++i)
703                                         if (modules [i].name == name)
704                                                 return modules [i];
705                         return null;
706                 }
707
708                 public override Type[] GetExportedTypes ()
709                 {
710                         throw not_supported ();
711                 }
712
713                 public override FileStream GetFile (string name)
714                 {
715                         throw not_supported ();
716                 }
717
718                 public override FileStream[] GetFiles(bool getResourceModules) {
719                         throw not_supported ();
720                 }
721
722                 internal override Module[] GetModulesInternal () {
723                         if (modules == null)
724                                 return new Module [0];
725                         else
726                                 return (Module[])modules.Clone ();
727                 }
728
729                 internal override Type[] GetTypes (bool exportedOnly) {
730                         Type[] res = null;
731                         if (modules != null) {
732                                 for (int i = 0; i < modules.Length; ++i) {
733                                         Type[] types = modules [i].GetTypes ();
734                                         if (res == null)
735                                                 res = types;
736                                         else {
737                                                 Type[] tmp = new Type [res.Length + types.Length];
738                                                 Array.Copy (res, 0, tmp, 0, res.Length);
739                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
740                                         }
741                                 }
742                         }
743                         if (loaded_modules != null) {
744                                 for (int i = 0; i < loaded_modules.Length; ++i) {
745                                         Type[] types = loaded_modules [i].GetTypes ();
746                                         if (res == null)
747                                                 res = types;
748                                         else {
749                                                 Type[] tmp = new Type [res.Length + types.Length];
750                                                 Array.Copy (res, 0, tmp, 0, res.Length);
751                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
752                                         }
753                                 }
754                         }
755
756                         if (res != null) {
757                                 List<Exception> exceptions = null;
758                                 foreach (var type in res) {
759                                         if (type is TypeBuilder) {
760                                                 if (exceptions == null)
761                                                         exceptions = new List <Exception> ();
762                                                 exceptions.Add (new TypeLoadException (string.Format ("Type '{0}' is not finished", type.FullName))); 
763                                         }
764                                 }
765                                 if (exceptions != null)
766                                         throw new ReflectionTypeLoadException (new Type [exceptions.Count], exceptions.ToArray ());
767                         }
768                         
769                         return res == null ? Type.EmptyTypes : res;
770                 }
771
772                 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
773                         throw not_supported ();
774                 }
775
776                 public override string[] GetManifestResourceNames() {
777                         throw not_supported ();
778                 }
779
780                 public override Stream GetManifestResourceStream(string name) {
781                         throw not_supported ();
782                 }
783                 public override Stream GetManifestResourceStream(Type type, string name) {
784                         throw not_supported ();
785                 }
786
787                 internal bool IsSave {
788                         get {
789                                 return access != (uint)AssemblyBuilderAccess.Run;
790                         }
791                 }
792
793                 internal bool IsRun {
794                         get {
795                                 return access == (uint)AssemblyBuilderAccess.Run || access == (uint)AssemblyBuilderAccess.RunAndSave
796                                          || access == (uint)AssemblyBuilderAccess.RunAndCollect
797                                 ;
798
799                         }
800                 }
801 /*
802                 internal bool IsCollectible {
803                         get {
804                                 return access == (uint)AssemblyBuilderAccess.RunAndCollect;
805                         }
806                 }
807 */
808                 internal string AssemblyDir {
809                         get {
810                                 return dir;
811                         }
812                 }
813
814                 /*
815                  * Mono extension. If this is set, the assembly can only contain one
816                  * module, access should be Save, and the saved image will not contain an
817                  * assembly manifest.
818                  */
819                 internal bool IsModuleOnly {
820                         get {
821                                 return is_module_only;
822                         }
823                         set {
824                                 is_module_only = value;
825                         }
826                 }
827
828                 ModuleBuilder manifest_module;
829
830                 //
831                 // MS.NET seems to return a ModuleBuilder when GetManifestModule () is called
832                 // on an assemblybuilder.
833                 //
834                 internal override Module GetManifestModule () {
835                         if (manifest_module == null)
836                                 manifest_module = DefineDynamicModule ("Default Dynamic Module");
837                         return manifest_module;
838                 }
839
840                 [MonoLimitation ("No support for PE32+ assemblies for AMD64 and IA64")]
841                 public 
842                 void Save (string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
843                 {
844                         this.peKind = portableExecutableKind;
845                         this.machine = imageFileMachine;
846
847                         if ((peKind & PortableExecutableKinds.PE32Plus) != 0 || (peKind & PortableExecutableKinds.Unmanaged32Bit) != 0)
848                                 throw new NotImplementedException (peKind.ToString ());
849                         if (machine == ImageFileMachine.IA64 || machine == ImageFileMachine.AMD64)
850                                 throw new NotImplementedException (machine.ToString ());
851
852                         if (resource_writers != null) {
853                                 foreach (IResourceWriter writer in resource_writers) {
854                                         writer.Generate ();
855                                         writer.Close ();
856                                 }
857                         }
858
859                         // Create a main module if not already created
860                         ModuleBuilder mainModule = null;
861                         if (modules != null) {
862                                 foreach (ModuleBuilder module in modules)
863                                         if (module.FullyQualifiedName == assemblyFileName)
864                                                 mainModule = module;
865                         }
866                         if (mainModule == null)
867                                 mainModule = DefineDynamicModule ("RefEmit_OnDiskManifestModule", assemblyFileName);
868
869                         if (!is_module_only)
870                                 mainModule.IsMain = true;
871
872                         /* 
873                          * Create a new entry point if the one specified
874                          * by the user is in another module.
875                          */
876                         if ((entry_point != null) && entry_point.DeclaringType.Module != mainModule) {
877                                 Type[] paramTypes;
878                                 if (entry_point.GetParametersCount () == 1)
879                                         paramTypes = new Type [] { typeof (string) };
880                                 else
881                                         paramTypes = Type.EmptyTypes;
882
883                                 MethodBuilder mb = mainModule.DefineGlobalMethod ("__EntryPoint$", MethodAttributes.Static|MethodAttributes.PrivateScope, entry_point.ReturnType, paramTypes);
884                                 ILGenerator ilgen = mb.GetILGenerator ();
885                                 if (paramTypes.Length == 1)
886                                         ilgen.Emit (OpCodes.Ldarg_0);
887                                 ilgen.Emit (OpCodes.Tailcall);
888                                 ilgen.Emit (OpCodes.Call, entry_point);
889                                 ilgen.Emit (OpCodes.Ret);
890
891                                 entry_point = mb;
892                         }
893
894                         if (version_res != null)
895                                 DefineVersionInfoResourceImpl (assemblyFileName);
896
897                         if (sn != null) {
898                                 // runtime needs to value to embed it into the assembly
899                                 public_key = sn.PublicKey;
900                         }
901
902                         foreach (ModuleBuilder module in modules)
903                                 if (module != mainModule)
904                                         module.Save ();
905
906                         // Write out the main module at the end, because it needs to
907                         // contain the hash of the other modules
908                         mainModule.Save ();
909
910                         if ((sn != null) && (sn.CanSign)) {
911                                 sn.Sign (System.IO.Path.Combine (this.AssemblyDir, assemblyFileName));
912                         }
913
914                         created = true;
915                 }
916
917                 public void Save (string assemblyFileName)
918                 {
919                         Save (assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
920                 }
921
922                 public void SetEntryPoint (MethodInfo entryMethod)
923                 {
924                         SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
925                 }
926
927                 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
928                 {
929                         if (entryMethod == null)
930                                 throw new ArgumentNullException ("entryMethod");
931                         if (entryMethod.DeclaringType.Assembly != this)
932                                 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
933
934                         entry_point = entryMethod;
935                         pekind = fileKind;
936                 }
937
938                 public void SetCustomAttribute( CustomAttributeBuilder customBuilder) 
939                 {
940                         if (customBuilder == null)
941                                 throw new ArgumentNullException ("customBuilder");
942
943                         if (cattrs != null) {
944                                 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
945                                 cattrs.CopyTo (new_array, 0);
946                                 new_array [cattrs.Length] = customBuilder;
947                                 cattrs = new_array;
948                         } else {
949                                 cattrs = new CustomAttributeBuilder [1];
950                                 cattrs [0] = customBuilder;
951                         }
952                 }
953
954                 [ComVisible (true)]
955                 public void SetCustomAttribute ( ConstructorInfo con, byte[] binaryAttribute) {
956                         if (con == null)
957                                 throw new ArgumentNullException ("con");
958                         if (binaryAttribute == null)
959                                 throw new ArgumentNullException ("binaryAttribute");
960
961                         SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
962                 }
963
964                 private Exception not_supported () {
965                         // Strange message but this is what MS.NET prints...
966                         return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
967                 }
968
969                 private void check_name_and_filename (string name, string fileName,
970                                                                                           bool fileNeedsToExists) {
971                         if (name == null)
972                                 throw new ArgumentNullException ("name");
973                         if (fileName == null)
974                                 throw new ArgumentNullException ("fileName");
975                         if (name.Length == 0)
976                                 throw new ArgumentException ("Empty name is not legal.", "name");
977                         if (fileName.Length == 0)
978                                 throw new ArgumentException ("Empty file name is not legal.", "fileName");
979                         if (Path.GetFileName (fileName) != fileName)
980                                 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.", "fileName");
981
982                         // Resource files are created/searched under the assembly storage
983                         // directory
984                         string fullFileName = fileName;
985                         if (dir != null)
986                                 fullFileName = Path.Combine (dir, fileName);
987
988                         if (fileNeedsToExists && !File.Exists (fullFileName))
989                                 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
990
991                         if (resources != null) {
992                                 for (int i = 0; i < resources.Length; ++i) {
993                                         if (resources [i].filename == fullFileName)
994                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
995                                         if (resources [i].name == name)
996                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
997                                 }
998                         }
999
1000                         if (modules != null) {
1001                                 for (int i = 0; i < modules.Length; ++i) {
1002                                         // Use fileName instead of fullFileName here
1003                                         if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
1004                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
1005                                         if (modules [i].Name == name)
1006                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
1007                                 }
1008                         }
1009                 }
1010
1011                 private String create_assembly_version (String version) {
1012                         String[] parts = version.Split ('.');
1013                         int[] ver = new int [4] { 0, 0, 0, 0 };
1014
1015                         if ((parts.Length < 0) || (parts.Length > 4))
1016                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1017
1018                         for (int i = 0; i < parts.Length; ++i) {
1019                                 if (parts [i] == "*") {
1020                                         DateTime now = DateTime.Now;
1021
1022                                         if (i == 2) {
1023                                                 ver [2] = (now - new DateTime (2000, 1, 1)).Days;
1024                                                 if (parts.Length == 3)
1025                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1026                                         }
1027                                         else
1028                                                 if (i == 3)
1029                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1030                                         else
1031                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1032                                 }
1033                                 else {
1034                                         try {
1035                                                 ver [i] = Int32.Parse (parts [i]);
1036                                         }
1037                                         catch (FormatException) {
1038                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1039                                         }
1040                                 }
1041                         }
1042
1043                         return ver [0] + "." + ver [1] + "." + ver [2] + "." + ver [3];
1044                 }
1045
1046                 private string GetCultureString (string str)
1047                 {
1048                         return (str == "neutral" ? String.Empty : str);
1049                 }
1050
1051                 /*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/
1052                 internal Type MakeGenericType (Type gtd, Type[] typeArguments)
1053                 {
1054                         return new TypeBuilderInstantiation (gtd, typeArguments);
1055                 }
1056
1057                 void _AssemblyBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1058                 {
1059                         throw new NotImplementedException ();
1060                 }
1061
1062                 void _AssemblyBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1063                 {
1064                         throw new NotImplementedException ();
1065                 }
1066
1067                 void _AssemblyBuilder.GetTypeInfoCount (out uint pcTInfo)
1068                 {
1069                         throw new NotImplementedException ();
1070                 }
1071
1072                 void _AssemblyBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1073                 {
1074                         throw new NotImplementedException ();
1075                 }
1076
1077                 public override Type GetType (string name, bool throwOnError, bool ignoreCase)
1078                 {
1079                         if (name == null)
1080                                 throw new ArgumentNullException (name);
1081                         if (name.Length == 0)
1082                         throw new ArgumentException ("name", "Name cannot be empty");
1083
1084                         var res = InternalGetType (null, name, throwOnError, ignoreCase);
1085                         if (res is TypeBuilder) {
1086                                 if (throwOnError)
1087                                         throw new TypeLoadException (string.Format ("Could not load type '{0}' from assembly '{1}'", name, this.name));
1088                                 return null;
1089                         }
1090                         return res;
1091                 }
1092
1093                 public override Module GetModule (String name)
1094                 {
1095                         if (name == null)
1096                                 throw new ArgumentNullException ("name");
1097                         if (name.Length == 0)
1098                                 throw new ArgumentException ("Name can't be empty");
1099
1100                         if (modules == null)
1101                                 return null;
1102
1103                         foreach (Module module in modules) {
1104                                 if (module.ScopeName == name)
1105                                         return module;
1106                         }
1107
1108                         return null;
1109                 }
1110
1111                 public override Module[] GetModules (bool getResourceModules)
1112                 {
1113                         Module[] modules = GetModulesInternal ();
1114
1115                         if (!getResourceModules) {
1116                                 var result = new List<Module> (modules.Length);
1117                                 foreach (Module m in modules)
1118                                         if (!m.IsResource ())
1119                                                 result.Add (m);
1120                                 return result.ToArray ();
1121                         }
1122                         return modules;
1123                 }
1124
1125                 public override AssemblyName GetName (bool copiedName)
1126                 {
1127                         var aname = AssemblyName.Create (this, false);
1128
1129                         if (sn != null) {
1130                                 aname.SetPublicKey (sn.PublicKey);
1131                                 aname.SetPublicKeyToken (sn.PublicKeyToken);
1132                         }
1133                         return aname;
1134
1135                 }
1136
1137                 [MonoTODO ("This always returns an empty array")]
1138                 public override AssemblyName[] GetReferencedAssemblies () {
1139                         return GetReferencedAssemblies (this);
1140                 }
1141
1142                 public override Module[] GetLoadedModules (bool getResourceModules)
1143                 {
1144                         return GetModules (getResourceModules);
1145                 }
1146
1147                 //FIXME MS has issues loading satelite assemblies from SRE
1148                 public override Assembly GetSatelliteAssembly (CultureInfo culture)
1149                 {
1150                         return GetSatelliteAssembly (culture, null, true);
1151                 }
1152
1153                 //FIXME MS has issues loading satelite assemblies from SRE
1154                 public override Assembly GetSatelliteAssembly (CultureInfo culture, Version version)
1155                 {
1156                         return GetSatelliteAssembly (culture, version, true);
1157                 }
1158
1159                 public override Module ManifestModule {
1160                         get {
1161                                 return GetManifestModule ();
1162                         }
1163                 }
1164
1165                 public override bool GlobalAssemblyCache {
1166                         get {
1167                                 return false;
1168                         }
1169                 }
1170
1171                 public override bool IsDynamic {
1172                         get { return true; }
1173                 }
1174
1175                 public override bool Equals (object obj)
1176                 {
1177                         return base.Equals (obj);
1178                 }
1179
1180                 public override int GetHashCode ()
1181                 {
1182                         return base.GetHashCode ();
1183                 }
1184
1185                 public override bool IsDefined (Type attributeType, bool inherit)
1186                 {
1187                         return base.IsDefined (attributeType, inherit);
1188                 }
1189
1190                 public override object[] GetCustomAttributes (bool inherit)
1191                 {
1192                         return base.GetCustomAttributes (inherit);
1193                 }
1194
1195                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
1196                 {
1197                         return base.GetCustomAttributes (attributeType, inherit);
1198                 }
1199
1200                 public override string FullName {
1201                         get { return base.FullName; }
1202                 }
1203         }
1204 }
1205 #endif