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