[bcl] Remove NET_4_0 defines from class libs.
[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 !NET_2_1
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 #if NET_4_5
462                 public static AssemblyBuilder DefineDynamicAssembly (AssemblyName name, AssemblyBuilderAccess access)
463                 {
464                         if (name == null)
465                                 throw new ArgumentNullException ("name");
466
467                         return new AssemblyBuilder (name, null, access, false);
468                 }
469 #endif
470
471                 public ModuleBuilder DefineDynamicModule (string name)
472                 {
473                         return DefineDynamicModule (name, name, false, true);
474                 }
475
476                 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
477                 {
478                         return DefineDynamicModule (name, name, emitSymbolInfo, true);
479                 }
480
481                 public ModuleBuilder DefineDynamicModule(string name, string fileName)
482                 {
483                         return DefineDynamicModule (name, fileName, false, false);
484                 }
485
486                 public ModuleBuilder DefineDynamicModule (string name, string fileName,
487                                                           bool emitSymbolInfo)
488                 {
489                         return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
490                 }
491
492                 private ModuleBuilder DefineDynamicModule (string name, string fileName, bool emitSymbolInfo, bool transient)
493                 {
494                         check_name_and_filename (name, fileName, false);
495
496                         if (!transient) {
497                                 if (Path.GetExtension (fileName) == String.Empty)
498                                         throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
499                                 if (!IsSave)
500                                         throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
501                                 if (created)
502                                         throw new InvalidOperationException ("Assembly was already saved.");
503                         }
504
505                         ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, transient);
506
507                         if ((modules != null) && is_module_only)
508                                 throw new InvalidOperationException ("A module-only assembly can only contain one module.");
509
510                         if (modules != null) {
511                                 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
512                                 System.Array.Copy(modules, new_modules, modules.Length);
513                                 modules = new_modules;
514                         } else {
515                                 modules = new ModuleBuilder [1];
516                         }
517                         modules [modules.Length - 1] = r;
518                         return r;
519                 }
520
521                 public IResourceWriter DefineResource (string name, string description, string fileName)
522                 {
523                         return DefineResource (name, description, fileName, ResourceAttributes.Public);
524                 }
525
526                 public IResourceWriter DefineResource (string name, string description,
527                                                        string fileName, ResourceAttributes attribute)
528                 {
529                         IResourceWriter writer;
530
531                         // description seems to be ignored
532                         AddResourceFile (name, fileName, attribute, false);
533                         writer = new ResourceWriter (fileName);
534                         if (resource_writers == null)
535                                 resource_writers = new ArrayList ();
536                         resource_writers.Add (writer);
537                         return writer;
538                 }
539
540                 private void AddUnmanagedResource (Win32Resource res) {
541                         MemoryStream ms = new MemoryStream ();
542                         res.WriteTo (ms);
543
544                         if (win32_resources != null) {
545                                 MonoWin32Resource[] new_res = new MonoWin32Resource [win32_resources.Length + 1];
546                                 System.Array.Copy (win32_resources, new_res, win32_resources.Length);
547                                 win32_resources = new_res;
548                         }
549                         else
550                                 win32_resources = new MonoWin32Resource [1];
551
552                         win32_resources [win32_resources.Length - 1] = new MonoWin32Resource (res.Type.Id, res.Name.Id, res.Language, ms.ToArray ());
553                 }
554
555                 [MonoTODO ("Not currently implemenented")]
556                 public void DefineUnmanagedResource (byte[] resource)
557                 {
558                         if (resource == null)
559                                 throw new ArgumentNullException ("resource");
560                         if (native_resource != NativeResourceType.None)
561                                 throw new ArgumentException ("Native resource has already been defined.");
562
563                         // avoid definition of more than one unmanaged resource
564                         native_resource = NativeResourceType.Unmanaged;
565
566                         /*
567                          * The format of the argument byte array is not documented
568                          * so this method is impossible to implement.
569                          *
570                          * https://connect.microsoft.com/VisualStudio/feedback/details/95784/fatal-assemblybuilder-defineunmanagedresource-byte-and-modulebuilder-defineunmanagedresource-byte-bugs-renders-them-useless
571                          */
572
573                         throw new NotImplementedException ();
574                 }
575
576                 public void DefineUnmanagedResource (string resourceFileName)
577                 {
578                         if (resourceFileName == null)
579                                 throw new ArgumentNullException ("resourceFileName");
580                         if (resourceFileName.Length == 0)
581                                 throw new ArgumentException ("resourceFileName");
582                         if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
583                                 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exist or is a directory.");
584                         if (native_resource != NativeResourceType.None)
585                                 throw new ArgumentException ("Native resource has already been defined.");
586
587                         // avoid definition of more than one unmanaged resource
588                         native_resource = NativeResourceType.Unmanaged;
589
590                         using (FileStream fs = new FileStream (resourceFileName, FileMode.Open, FileAccess.Read)) {
591                                 Win32ResFileReader reader = new Win32ResFileReader (fs);
592
593                                 foreach (Win32EncodedResource res in reader.ReadResources ()) {
594                                         if (res.Name.IsName || res.Type.IsName)
595                                                 throw new InvalidOperationException ("resource files with named resources or non-default resource types are not supported.");
596
597                                         AddUnmanagedResource (res);
598                                 }
599                         }
600                 }
601
602                 public void DefineVersionInfoResource ()
603                 {
604                         if (native_resource != NativeResourceType.None)
605                                 throw new ArgumentException ("Native resource has already been defined.");
606
607                         // avoid definition of more than one unmanaged resource
608                         native_resource = NativeResourceType.Assembly;
609
610                         version_res = new Win32VersionResource (1, 0, false);
611                 }
612
613                 public void DefineVersionInfoResource (string product, string productVersion,
614                                                        string company, string copyright, string trademark)
615                 {
616                         if (native_resource != NativeResourceType.None)
617                                 throw new ArgumentException ("Native resource has already been defined.");
618
619                         // avoid definition of more than one unmanaged resource
620                         native_resource = NativeResourceType.Explicit;
621
622                         /*
623                          * We can only create the resource later, when the file name and
624                          * the binary version is known.
625                          */
626
627                         version_res = new Win32VersionResource (1, 0, false);
628                         version_res.ProductName = product != null ? product : " ";
629                         version_res.ProductVersion = productVersion != null ? productVersion : " ";
630                         version_res.CompanyName = company != null ? company : " ";
631                         version_res.LegalCopyright = copyright != null ? copyright : " ";
632                         version_res.LegalTrademarks = trademark != null ? trademark : " ";
633                 }
634
635                 private void DefineVersionInfoResourceImpl (string fileName)
636                 {
637                         if (versioninfo_culture != null)
638                                 version_res.FileLanguage = new CultureInfo (versioninfo_culture).LCID;
639                         version_res.Version = version == null ? "0.0.0.0" : version;
640
641                         if (cattrs != null) {
642                                 switch (native_resource) {
643                                 case NativeResourceType.Assembly:
644                                         foreach (CustomAttributeBuilder cb in cattrs) {
645                                                 string attrname = cb.Ctor.ReflectedType.FullName;
646
647                                                 if (attrname == "System.Reflection.AssemblyProductAttribute")
648                                                         version_res.ProductName = cb.string_arg ();
649                                                 else if (attrname == "System.Reflection.AssemblyCompanyAttribute")
650                                                         version_res.CompanyName = cb.string_arg ();
651                                                 else if (attrname == "System.Reflection.AssemblyCopyrightAttribute")
652                                                         version_res.LegalCopyright = cb.string_arg ();
653                                                 else if (attrname == "System.Reflection.AssemblyTrademarkAttribute")
654                                                         version_res.LegalTrademarks = cb.string_arg ();
655                                                 else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
656                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
657                                                 } else if (attrname == "System.Reflection.AssemblyFileVersionAttribute") {
658                                                         version_res.FileVersion = cb.string_arg ();
659                                                 } else if (attrname == "System.Reflection.AssemblyInformationalVersionAttribute")
660                                                         version_res.ProductVersion = cb.string_arg ();
661                                                 else if (attrname == "System.Reflection.AssemblyTitleAttribute")
662                                                         version_res.FileDescription = cb.string_arg ();
663                                                 else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
664                                                         version_res.Comments = cb.string_arg ();
665                                         }
666                                         break;
667                                 case NativeResourceType.Explicit:
668                                         foreach (CustomAttributeBuilder cb in cattrs) {
669                                                 string attrname = cb.Ctor.ReflectedType.FullName;
670
671                                                 if (attrname == "System.Reflection.AssemblyCultureAttribute") {
672                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
673                                                 } else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
674                                                         version_res.Comments = cb.string_arg ();
675                                         }
676                                         break;
677                                 }
678                         }
679
680                         version_res.OriginalFilename = fileName;
681                         version_res.InternalName = Path.GetFileNameWithoutExtension (fileName);
682
683                         AddUnmanagedResource (version_res);
684                 }
685
686                 public ModuleBuilder GetDynamicModule (string name)
687                 {
688                         if (name == null)
689                                 throw new ArgumentNullException ("name");
690                         if (name.Length == 0)
691                                 throw new ArgumentException ("Empty name is not legal.", "name");
692
693                         if (modules != null)
694                                 for (int i = 0; i < modules.Length; ++i)
695                                         if (modules [i].name == name)
696                                                 return modules [i];
697                         return null;
698                 }
699
700                 public override Type[] GetExportedTypes ()
701                 {
702                         throw not_supported ();
703                 }
704
705                 public override FileStream GetFile (string name)
706                 {
707                         throw not_supported ();
708                 }
709
710                 public override FileStream[] GetFiles(bool getResourceModules) {
711                         throw not_supported ();
712                 }
713
714                 internal override Module[] GetModulesInternal () {
715                         if (modules == null)
716                                 return new Module [0];
717                         else
718                                 return (Module[])modules.Clone ();
719                 }
720
721                 internal override Type[] GetTypes (bool exportedOnly) {
722                         Type[] res = null;
723                         if (modules != null) {
724                                 for (int i = 0; i < modules.Length; ++i) {
725                                         Type[] types = modules [i].GetTypes ();
726                                         if (res == null)
727                                                 res = types;
728                                         else {
729                                                 Type[] tmp = new Type [res.Length + types.Length];
730                                                 Array.Copy (res, 0, tmp, 0, res.Length);
731                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
732                                         }
733                                 }
734                         }
735                         if (loaded_modules != null) {
736                                 for (int i = 0; i < loaded_modules.Length; ++i) {
737                                         Type[] types = loaded_modules [i].GetTypes ();
738                                         if (res == null)
739                                                 res = types;
740                                         else {
741                                                 Type[] tmp = new Type [res.Length + types.Length];
742                                                 Array.Copy (res, 0, tmp, 0, res.Length);
743                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
744                                         }
745                                 }
746                         }
747
748                         if (res != null) {
749                                 List<Exception> exceptions = null;
750                                 foreach (var type in res) {
751                                         if (type is TypeBuilder) {
752                                                 if (exceptions == null)
753                                                         exceptions = new List <Exception> ();
754                                                 exceptions.Add (new TypeLoadException (string.Format ("Type '{0}' is not finished", type.FullName))); 
755                                         }
756                                 }
757                                 if (exceptions != null)
758                                         throw new ReflectionTypeLoadException (new Type [exceptions.Count], exceptions.ToArray ());
759                         }
760                         
761                         return res == null ? Type.EmptyTypes : res;
762                 }
763
764                 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
765                         throw not_supported ();
766                 }
767
768                 public override string[] GetManifestResourceNames() {
769                         throw not_supported ();
770                 }
771
772                 public override Stream GetManifestResourceStream(string name) {
773                         throw not_supported ();
774                 }
775                 public override Stream GetManifestResourceStream(Type type, string name) {
776                         throw not_supported ();
777                 }
778
779                 internal bool IsSave {
780                         get {
781                                 return access != (uint)AssemblyBuilderAccess.Run;
782                         }
783                 }
784
785                 internal bool IsRun {
786                         get {
787                                 return access == (uint)AssemblyBuilderAccess.Run || access == (uint)AssemblyBuilderAccess.RunAndSave
788                                          || access == (uint)AssemblyBuilderAccess.RunAndCollect
789                                 ;
790
791                         }
792                 }
793 /*
794                 internal bool IsCollectible {
795                         get {
796                                 return access == (uint)AssemblyBuilderAccess.RunAndCollect;
797                         }
798                 }
799 */
800                 internal string AssemblyDir {
801                         get {
802                                 return dir;
803                         }
804                 }
805
806                 /*
807                  * Mono extension. If this is set, the assembly can only contain one
808                  * module, access should be Save, and the saved image will not contain an
809                  * assembly manifest.
810                  */
811                 internal bool IsModuleOnly {
812                         get {
813                                 return is_module_only;
814                         }
815                         set {
816                                 is_module_only = value;
817                         }
818                 }
819
820                 ModuleBuilder manifest_module;
821
822                 //
823                 // MS.NET seems to return a ModuleBuilder when GetManifestModule () is called
824                 // on an assemblybuilder.
825                 //
826                 internal override Module GetManifestModule () {
827                         if (manifest_module == null)
828                                 manifest_module = DefineDynamicModule ("Default Dynamic Module");
829                         return manifest_module;
830                 }
831
832                 [MonoLimitation ("No support for PE32+ assemblies for AMD64 and IA64")]
833                 public 
834                 void Save (string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
835                 {
836                         this.peKind = portableExecutableKind;
837                         this.machine = imageFileMachine;
838
839                         if ((peKind & PortableExecutableKinds.PE32Plus) != 0 || (peKind & PortableExecutableKinds.Unmanaged32Bit) != 0)
840                                 throw new NotImplementedException (peKind.ToString ());
841                         if (machine == ImageFileMachine.IA64 || machine == ImageFileMachine.AMD64)
842                                 throw new NotImplementedException (machine.ToString ());
843
844                         if (resource_writers != null) {
845                                 foreach (IResourceWriter writer in resource_writers) {
846                                         writer.Generate ();
847                                         writer.Close ();
848                                 }
849                         }
850
851                         // Create a main module if not already created
852                         ModuleBuilder mainModule = null;
853                         if (modules != null) {
854                                 foreach (ModuleBuilder module in modules)
855                                         if (module.FullyQualifiedName == assemblyFileName)
856                                                 mainModule = module;
857                         }
858                         if (mainModule == null)
859                                 mainModule = DefineDynamicModule ("RefEmit_OnDiskManifestModule", assemblyFileName);
860
861                         if (!is_module_only)
862                                 mainModule.IsMain = true;
863
864                         /* 
865                          * Create a new entry point if the one specified
866                          * by the user is in another module.
867                          */
868                         if ((entry_point != null) && entry_point.DeclaringType.Module != mainModule) {
869                                 Type[] paramTypes;
870                                 if (entry_point.GetParametersCount () == 1)
871                                         paramTypes = new Type [] { typeof (string) };
872                                 else
873                                         paramTypes = Type.EmptyTypes;
874
875                                 MethodBuilder mb = mainModule.DefineGlobalMethod ("__EntryPoint$", MethodAttributes.Static|MethodAttributes.PrivateScope, entry_point.ReturnType, paramTypes);
876                                 ILGenerator ilgen = mb.GetILGenerator ();
877                                 if (paramTypes.Length == 1)
878                                         ilgen.Emit (OpCodes.Ldarg_0);
879                                 ilgen.Emit (OpCodes.Tailcall);
880                                 ilgen.Emit (OpCodes.Call, entry_point);
881                                 ilgen.Emit (OpCodes.Ret);
882
883                                 entry_point = mb;
884                         }
885
886                         if (version_res != null)
887                                 DefineVersionInfoResourceImpl (assemblyFileName);
888
889                         if (sn != null) {
890                                 // runtime needs to value to embed it into the assembly
891                                 public_key = sn.PublicKey;
892                         }
893
894                         foreach (ModuleBuilder module in modules)
895                                 if (module != mainModule)
896                                         module.Save ();
897
898                         // Write out the main module at the end, because it needs to
899                         // contain the hash of the other modules
900                         mainModule.Save ();
901
902                         if ((sn != null) && (sn.CanSign)) {
903                                 sn.Sign (System.IO.Path.Combine (this.AssemblyDir, assemblyFileName));
904                         }
905
906                         created = true;
907                 }
908
909                 public void Save (string assemblyFileName)
910                 {
911                         Save (assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
912                 }
913
914                 public void SetEntryPoint (MethodInfo entryMethod)
915                 {
916                         SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
917                 }
918
919                 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
920                 {
921                         if (entryMethod == null)
922                                 throw new ArgumentNullException ("entryMethod");
923                         if (entryMethod.DeclaringType.Assembly != this)
924                                 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
925
926                         entry_point = entryMethod;
927                         pekind = fileKind;
928                 }
929
930                 public void SetCustomAttribute( CustomAttributeBuilder customBuilder) 
931                 {
932                         if (customBuilder == null)
933                                 throw new ArgumentNullException ("customBuilder");
934
935                         if (cattrs != null) {
936                                 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
937                                 cattrs.CopyTo (new_array, 0);
938                                 new_array [cattrs.Length] = customBuilder;
939                                 cattrs = new_array;
940                         } else {
941                                 cattrs = new CustomAttributeBuilder [1];
942                                 cattrs [0] = customBuilder;
943                         }
944                 }
945
946                 [ComVisible (true)]
947                 public void SetCustomAttribute ( ConstructorInfo con, byte[] binaryAttribute) {
948                         if (con == null)
949                                 throw new ArgumentNullException ("con");
950                         if (binaryAttribute == null)
951                                 throw new ArgumentNullException ("binaryAttribute");
952
953                         SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
954                 }
955
956                 private Exception not_supported () {
957                         // Strange message but this is what MS.NET prints...
958                         return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
959                 }
960
961                 private void check_name_and_filename (string name, string fileName,
962                                                                                           bool fileNeedsToExists) {
963                         if (name == null)
964                                 throw new ArgumentNullException ("name");
965                         if (fileName == null)
966                                 throw new ArgumentNullException ("fileName");
967                         if (name.Length == 0)
968                                 throw new ArgumentException ("Empty name is not legal.", "name");
969                         if (fileName.Length == 0)
970                                 throw new ArgumentException ("Empty file name is not legal.", "fileName");
971                         if (Path.GetFileName (fileName) != fileName)
972                                 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.", "fileName");
973
974                         // Resource files are created/searched under the assembly storage
975                         // directory
976                         string fullFileName = fileName;
977                         if (dir != null)
978                                 fullFileName = Path.Combine (dir, fileName);
979
980                         if (fileNeedsToExists && !File.Exists (fullFileName))
981                                 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
982
983                         if (resources != null) {
984                                 for (int i = 0; i < resources.Length; ++i) {
985                                         if (resources [i].filename == fullFileName)
986                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
987                                         if (resources [i].name == name)
988                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
989                                 }
990                         }
991
992                         if (modules != null) {
993                                 for (int i = 0; i < modules.Length; ++i) {
994                                         // Use fileName instead of fullFileName here
995                                         if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
996                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
997                                         if (modules [i].Name == name)
998                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
999                                 }
1000                         }
1001                 }
1002
1003                 private String create_assembly_version (String version) {
1004                         String[] parts = version.Split ('.');
1005                         int[] ver = new int [4] { 0, 0, 0, 0 };
1006
1007                         if ((parts.Length < 0) || (parts.Length > 4))
1008                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1009
1010                         for (int i = 0; i < parts.Length; ++i) {
1011                                 if (parts [i] == "*") {
1012                                         DateTime now = DateTime.Now;
1013
1014                                         if (i == 2) {
1015                                                 ver [2] = (now - new DateTime (2000, 1, 1)).Days;
1016                                                 if (parts.Length == 3)
1017                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1018                                         }
1019                                         else
1020                                                 if (i == 3)
1021                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1022                                         else
1023                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1024                                 }
1025                                 else {
1026                                         try {
1027                                                 ver [i] = Int32.Parse (parts [i]);
1028                                         }
1029                                         catch (FormatException) {
1030                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1031                                         }
1032                                 }
1033                         }
1034
1035                         return ver [0] + "." + ver [1] + "." + ver [2] + "." + ver [3];
1036                 }
1037
1038                 private string GetCultureString (string str)
1039                 {
1040                         return (str == "neutral" ? String.Empty : str);
1041                 }
1042
1043                 internal override AssemblyName UnprotectedGetName ()
1044                 {
1045                         AssemblyName an = base.UnprotectedGetName ();
1046                         if (sn != null) {
1047                                 an.SetPublicKey (sn.PublicKey);
1048                                 an.SetPublicKeyToken (sn.PublicKeyToken);
1049                         }
1050                         return an;
1051                 }
1052
1053                 /*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/
1054                 internal Type MakeGenericType (Type gtd, Type[] typeArguments)
1055                 {
1056                         return new MonoGenericClass (gtd, typeArguments);
1057                 }
1058
1059                 void _AssemblyBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1060                 {
1061                         throw new NotImplementedException ();
1062                 }
1063
1064                 void _AssemblyBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1065                 {
1066                         throw new NotImplementedException ();
1067                 }
1068
1069                 void _AssemblyBuilder.GetTypeInfoCount (out uint pcTInfo)
1070                 {
1071                         throw new NotImplementedException ();
1072                 }
1073
1074                 void _AssemblyBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1075                 {
1076                         throw new NotImplementedException ();
1077                 }
1078
1079                 public override Type GetType (string name, bool throwOnError, bool ignoreCase)
1080                 {
1081                         if (name == null)
1082                                 throw new ArgumentNullException (name);
1083                         if (name.Length == 0)
1084                         throw new ArgumentException ("name", "Name cannot be empty");
1085
1086                         var res = InternalGetType (null, name, throwOnError, ignoreCase);
1087                         if (res is TypeBuilder) {
1088                                 if (throwOnError)
1089                                         throw new TypeLoadException (string.Format ("Could not load type '{0}' from assembly '{1}'", name, this.name));
1090                                 return null;
1091                         }
1092                         return res;
1093                 }
1094
1095                 public override Module GetModule (String name)
1096                 {
1097                         if (name == null)
1098                                 throw new ArgumentNullException ("name");
1099                         if (name.Length == 0)
1100                                 throw new ArgumentException ("Name can't be empty");
1101
1102                         if (modules == null)
1103                                 return null;
1104
1105                         foreach (Module module in modules) {
1106                                 if (module.ScopeName == name)
1107                                         return module;
1108                         }
1109
1110                         return null;
1111                 }
1112
1113                 public override Module[] GetModules (bool getResourceModules)
1114                 {
1115                         Module[] modules = GetModulesInternal ();
1116
1117                         if (!getResourceModules) {
1118                                 var result = new List<Module> (modules.Length);
1119                                 foreach (Module m in modules)
1120                                         if (!m.IsResource ())
1121                                                 result.Add (m);
1122                                 return result.ToArray ();
1123                         }
1124                         return modules;
1125                 }
1126
1127                 public override AssemblyName GetName (bool copiedName)
1128                 {
1129                         return base.GetName (copiedName);
1130                 }
1131
1132                 [MonoTODO ("This always returns an empty array")]
1133                 public override AssemblyName[] GetReferencedAssemblies () {
1134                         return GetReferencedAssemblies (this);
1135                 }
1136
1137                 public override Module[] GetLoadedModules (bool getResourceModules)
1138                 {
1139                         return GetModules (getResourceModules);
1140                 }
1141
1142                 //FIXME MS has issues loading satelite assemblies from SRE
1143                 public override Assembly GetSatelliteAssembly (CultureInfo culture)
1144                 {
1145                         return GetSatelliteAssembly (culture, null, true);
1146                 }
1147
1148                 //FIXME MS has issues loading satelite assemblies from SRE
1149                 public override Assembly GetSatelliteAssembly (CultureInfo culture, Version version)
1150                 {
1151                         return GetSatelliteAssembly (culture, version, true);
1152                 }
1153
1154                 public override Module ManifestModule {
1155                         get {
1156                                 return GetManifestModule ();
1157                         }
1158                 }
1159
1160                 public override bool GlobalAssemblyCache {
1161                         get {
1162                                 return false;
1163                         }
1164                 }
1165
1166                 public override bool IsDynamic {
1167                         get { return true; }
1168                 }
1169
1170                 public override bool Equals (object obj)
1171                 {
1172                         return base.Equals (obj);
1173                 }
1174
1175                 public override int GetHashCode ()
1176                 {
1177                         return base.GetHashCode ();
1178                 }
1179
1180                 public override bool IsDefined (Type attributeType, bool inherit)
1181                 {
1182                         return base.IsDefined (attributeType, inherit);
1183                 }
1184
1185                 public override object[] GetCustomAttributes (bool inherit)
1186                 {
1187                         return base.GetCustomAttributes (inherit);
1188                 }
1189
1190                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
1191                 {
1192                         return base.GetCustomAttributes (attributeType, inherit);
1193                 }
1194
1195                 public override string FullName {
1196                         get { return base.FullName; }
1197                 }
1198         }
1199 }
1200 #endif