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