2 // System.Reflection.Emit/AssemblyBuilder.cs
5 // Paolo Molaro (lupus@ximian.com)
7 // (C) 2001 Ximian, Inc. http://www.ximian.com
11 using System.Reflection;
12 using System.Resources;
14 using System.Security.Policy;
15 using System.Runtime.Serialization;
16 using System.Globalization;
17 using System.Runtime.CompilerServices;
18 using System.Collections;
19 using System.Runtime.InteropServices;
21 namespace System.Reflection.Emit {
23 internal struct MonoResource {
26 public string filename;
27 public ResourceAttributes attrs;
30 public sealed class AssemblyBuilder : Assembly {
31 private IntPtr dynamic_assembly;
32 private MethodInfo entry_point;
33 private ModuleBuilder[] modules;
36 private CustomAttributeBuilder[] cattrs;
37 private MonoResource[] resources;
43 PEFileKinds pekind = PEFileKinds.Dll;
46 internal Type corlib_object_type = typeof (System.Object);
47 internal Type corlib_value_type = typeof (System.ValueType);
48 internal Type corlib_enum_type = typeof (System.Enum);
49 internal Type corlib_void_type = typeof (void);
50 private int[] table_indexes;
51 Hashtable us_string_cache = new Hashtable ();
52 ArrayList resource_writers = null;
55 [MethodImplAttribute(MethodImplOptions.InternalCall)]
56 private static extern void basic_init (AssemblyBuilder ab);
58 internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access) {
61 this.access = (uint)access;
65 internal int get_next_table_index (object obj, int table, bool inc) {
66 if (table_indexes == null) {
67 table_indexes = new int [64];
68 for (int i=0; i < 64; ++i)
69 table_indexes [i] = 1;
70 /* allow room for .<Module> in TypeDef table */
71 table_indexes [0x02] = 2;
73 // Console.WriteLine ("getindex for table "+table.ToString()+" got "+table_indexes [table].ToString());
75 return table_indexes [table]++;
76 return table_indexes [table];
79 public override string CodeBase {
81 throw not_supported ();
85 public override MethodInfo EntryPoint {
91 public override string Location {
93 throw not_supported ();
97 public void AddResourceFile (string name, string fileName)
99 AddResourceFile (name, fileName, ResourceAttributes.Public);
102 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
104 AddResourceFile (name, fileName, attribute, true);
107 private void AddResourceFile (string name, string fileName, ResourceAttributes attribute, bool fileNeedsToExists)
109 check_name_and_filename (name, fileName, fileNeedsToExists);
111 // Resource files are created/searched under the assembly storage
114 fileName = Path.Combine (dir, fileName);
116 if (resources != null) {
117 MonoResource[] new_r = new MonoResource [resources.Length + 1];
118 System.Array.Copy(resources, new_r, resources.Length);
121 resources = new MonoResource [1];
123 int p = resources.Length - 1;
124 resources [p].name = name;
125 resources [p].filename = fileName;
126 resources [p].attrs = attribute;
129 public void EmbedResourceFile (string name, string fileName)
131 EmbedResourceFile (name, fileName, ResourceAttributes.Public);
134 public void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
136 if (resources != null) {
137 MonoResource[] new_r = new MonoResource [resources.Length + 1];
138 System.Array.Copy(resources, new_r, resources.Length);
141 resources = new MonoResource [1];
143 int p = resources.Length - 1;
144 resources [p].name = name;
145 resources [p].attrs = attribute;
147 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
149 resources [p].data = new byte [len];
150 s.Read (resources [p].data, 0, (int)len);
157 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
159 if (resources != null) {
160 MonoResource[] new_r = new MonoResource [resources.Length + 1];
161 System.Array.Copy(resources, new_r, resources.Length);
164 resources = new MonoResource [1];
166 int p = resources.Length - 1;
167 resources [p].name = name;
168 resources [p].attrs = attribute;
169 resources [p].data = blob;
172 public ModuleBuilder DefineDynamicModule (string name)
174 return DefineDynamicModule (name, name, false, true);
177 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
179 return DefineDynamicModule (name, name, emitSymbolInfo, true);
182 public ModuleBuilder DefineDynamicModule(string name, string fileName)
184 return DefineDynamicModule (name, fileName, false, false);
187 public ModuleBuilder DefineDynamicModule (string name, string fileName,
190 return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
193 public ModuleBuilder DefineDynamicModule (string name, string fileName,
194 bool emitSymbolInfo, bool transient)
196 check_name_and_filename (name, fileName, false);
199 if (Path.GetExtension (fileName) == String.Empty)
200 throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
202 throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
204 throw new InvalidOperationException ("Assembly was already saved.");
207 ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, modules == null, transient);
209 if (modules != null) {
210 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
211 System.Array.Copy(modules, new_modules, modules.Length);
212 new_modules [modules.Length] = r;
213 modules = new_modules;
215 modules = new ModuleBuilder [1];
221 public IResourceWriter DefineResource (string name, string description, string fileName)
223 return DefineResource (name, description, fileName, ResourceAttributes.Public);
226 public IResourceWriter DefineResource (string name, string description,
227 string fileName, ResourceAttributes attribute)
229 IResourceWriter writer;
231 // description seems to be ignored
232 AddResourceFile (name, fileName, attribute, false);
233 writer = new ResourceWriter (fileName);
234 if (resource_writers == null)
235 resource_writers = new ArrayList ();
236 resource_writers.Add (writer);
241 public void DefineUnmanagedResource (byte[] resource)
243 if (resource == null)
244 throw new ArgumentNullException ("resource");
246 throw new NotImplementedException ();
250 public void DefineUnmanagedResource (string resourceFileName)
252 if (resourceFileName == null)
253 throw new ArgumentNullException ("resourceFileName");
254 if (resourceFileName == String.Empty)
255 throw new ArgumentException ("resourceFileName");
256 if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
257 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exists or is a directory.");
259 throw new NotImplementedException ();
263 public void DefineVersionInfoResource ()
265 throw new NotImplementedException ();
269 public void DefineVersionInfoResource (string product, string productVersion,
270 string company, string copyright, string trademark)
272 throw new NotImplementedException ();
275 public ModuleBuilder GetDynamicModule (string name)
278 throw new ArgumentNullException ("name");
280 throw new ArgumentException ("Name can't be null");
283 for (int i = 0; i < modules.Length; ++i)
284 if (modules [i].name == name)
289 public override Type[] GetExportedTypes ()
291 throw not_supported ();
294 public override FileStream GetFile (string name)
296 throw not_supported ();
299 public override FileStream[] GetFiles() {
300 throw not_supported ();
303 public override FileStream[] GetFiles(bool getResourceModules) {
304 throw not_supported ();
307 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
308 throw not_supported ();
311 public override string[] GetManifestResourceNames() {
312 throw not_supported ();
315 public override Stream GetManifestResourceStream(string name) {
316 throw not_supported ();
318 public override Stream GetManifestResourceStream(Type type, string name) {
319 throw not_supported ();
322 [MethodImplAttribute(MethodImplOptions.InternalCall)]
323 private static extern int getUSIndex (AssemblyBuilder ab, string str);
325 [MethodImplAttribute(MethodImplOptions.InternalCall)]
326 private static extern int getToken (AssemblyBuilder ab, object obj);
328 internal int GetToken (string str) {
329 if (us_string_cache.Contains (str))
330 return (int)us_string_cache [str];
331 int result = getUSIndex (this, str);
332 us_string_cache [str] = result;
336 internal int GetToken (MemberInfo member) {
337 return getToken (this, member);
340 internal int GetToken (SignatureHelper helper) {
341 return getToken (this, helper);
344 internal bool IsSave {
346 return access != (uint)AssemblyBuilderAccess.Run;
350 [MethodImplAttribute(MethodImplOptions.InternalCall)]
351 private static extern int getDataChunk (AssemblyBuilder ab, byte[] buf, int offset);
353 public void Save (string assemblyFileName)
355 byte[] buf = new byte [65536];
359 if (resource_writers != null) {
360 foreach (IResourceWriter writer in resource_writers) {
366 build_metadata (this);
368 foreach (ModuleBuilder module in modules)
372 assemblyFileName = String.Format ("{0}{1}{2}", dir, System.IO.Path.DirectorySeparatorChar, assemblyFileName);
375 file = new FileStream (assemblyFileName, FileMode.Create, FileAccess.Write);
378 while ((count = getDataChunk (this, buf, offset)) != 0) {
379 file.Write (buf, 0, count);
387 // The constant 0x80000000 is internal to Mono, it means `make executable'
389 File.SetAttributes (assemblyFileName, (FileAttributes) (unchecked ((int) 0x80000000)));
392 [MethodImplAttribute(MethodImplOptions.InternalCall)]
393 private static extern void build_metadata (AssemblyBuilder ab);
395 public void SetEntryPoint (MethodInfo entryMethod)
397 SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
400 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
402 if (entryMethod == null)
403 throw new ArgumentNullException ("entryMethod");
404 if (entryMethod.DeclaringType.Assembly != this)
405 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
407 entry_point = entryMethod;
411 public void SetCustomAttribute( CustomAttributeBuilder customBuilder) {
412 if (customBuilder == null)
413 throw new ArgumentNullException ("customBuilder");
415 string attrname = customBuilder.Ctor.ReflectedType.FullName;
418 if (attrname == "System.Reflection.AssemblyVersionAttribute") {
419 data = customBuilder.Data;
421 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
422 version = CustomAttributeBuilder.string_from_bytes (data, pos, len);
424 } else if (attrname == "System.Reflection.AssemblyKeyFileAttribute") {
425 data = customBuilder.Data;
427 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
428 keyfile = CustomAttributeBuilder.string_from_bytes (data, pos, len);
429 } else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
430 data = customBuilder.Data;
432 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
433 culture = CustomAttributeBuilder.string_from_bytes (data, pos, len);
434 } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") {
435 data = customBuilder.Data;
437 algid = (uint)data [pos];
438 algid |= ((uint)data [pos + 1]) << 8;
439 algid |= ((uint)data [pos + 2]) << 16;
440 algid |= ((uint)data [pos + 3]) << 24;
441 } else if (attrname == "System.Reflection.AssemblyFlagsAttribute") {
442 data = customBuilder.Data;
444 flags = (uint)data [pos];
445 flags |= ((uint)data [pos + 1]) << 8;
446 flags |= ((uint)data [pos + 2]) << 16;
447 flags |= ((uint)data [pos + 3]) << 24;
449 } else if (attrname == "System.Reflection.AssemblyDelaySignAttribute") {
450 data = customBuilder.Data;
452 delay_sign = data [2] != 0;
454 if (cattrs != null) {
455 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
456 cattrs.CopyTo (new_array, 0);
457 new_array [cattrs.Length] = customBuilder;
460 cattrs = new CustomAttributeBuilder [1];
461 cattrs [0] = customBuilder;
464 public void SetCustomAttribute( ConstructorInfo con, byte[] binaryAttribute) {
466 throw new ArgumentNullException ("con");
467 if (binaryAttribute == null)
468 throw new ArgumentNullException ("binaryAttribute");
470 SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
473 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type) {
474 this.corlib_object_type = corlib_object_type;
475 this.corlib_value_type = corlib_value_type;
476 this.corlib_enum_type = corlib_enum_type;
479 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type, Type corlib_void_type)
481 SetCorlibTypeBuilders (corlib_object_type, corlib_value_type, corlib_enum_type);
482 this.corlib_void_type = corlib_void_type;
485 private Exception not_supported () {
486 // Strange message but this is what MS.NET prints...
487 return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
490 private void check_name_and_filename (string name, string fileName,
491 bool fileNeedsToExists) {
493 throw new ArgumentNullException ("name");
494 if (fileName == null)
495 throw new ArgumentNullException ("fileName");
497 throw new ArgumentException ("name cannot be empty", "name");
499 throw new ArgumentException ("fileName cannot be empty", "fileName");
500 if (Path.GetFileName (fileName) != fileName)
501 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.");
503 // Resource files are created/searched under the assembly storage
505 string fullFileName = fileName;
507 fullFileName = Path.Combine (dir, fileName);
509 if (fileNeedsToExists && !File.Exists (fullFileName))
510 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
512 if (resources != null) {
513 for (int i = 0; i < resources.Length; ++i) {
514 if (resources [i].filename == fullFileName)
515 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
516 if (resources [i].name == name)
517 throw new ArgumentException ("Duplicate name '" + name + "'");
521 if (modules != null) {
522 for (int i = 0; i < modules.Length; ++i) {
523 // Use fileName instead of fullFileName here
524 if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
525 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
526 if (modules [i].Name == name)
527 throw new ArgumentException ("Duplicate name '" + name + "'");