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