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;
63 /* Set defaults from n */
64 if (n.CultureInfo != null) {
65 culture = n.CultureInfo.Name;
67 Version v = n.Version;
69 version = v.ToString ();
75 internal int get_next_table_index (object obj, int table, bool inc) {
76 if (table_indexes == null) {
77 table_indexes = new int [64];
78 for (int i=0; i < 64; ++i)
79 table_indexes [i] = 1;
80 /* allow room for .<Module> in TypeDef table */
81 table_indexes [0x02] = 2;
83 // Console.WriteLine ("getindex for table "+table.ToString()+" got "+table_indexes [table].ToString());
85 return table_indexes [table]++;
86 return table_indexes [table];
89 public override string CodeBase {
91 throw not_supported ();
95 public override MethodInfo EntryPoint {
101 public override string Location {
103 throw not_supported ();
107 public void AddResourceFile (string name, string fileName)
109 AddResourceFile (name, fileName, ResourceAttributes.Public);
112 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
114 AddResourceFile (name, fileName, attribute, true);
117 private void AddResourceFile (string name, string fileName, ResourceAttributes attribute, bool fileNeedsToExists)
119 check_name_and_filename (name, fileName, fileNeedsToExists);
121 // Resource files are created/searched under the assembly storage
124 fileName = Path.Combine (dir, fileName);
126 if (resources != null) {
127 MonoResource[] new_r = new MonoResource [resources.Length + 1];
128 System.Array.Copy(resources, new_r, resources.Length);
131 resources = new MonoResource [1];
133 int p = resources.Length - 1;
134 resources [p].name = name;
135 resources [p].filename = fileName;
136 resources [p].attrs = attribute;
139 public void EmbedResourceFile (string name, string fileName)
141 EmbedResourceFile (name, fileName, ResourceAttributes.Public);
144 public void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
146 if (resources != null) {
147 MonoResource[] new_r = new MonoResource [resources.Length + 1];
148 System.Array.Copy(resources, new_r, resources.Length);
151 resources = new MonoResource [1];
153 int p = resources.Length - 1;
154 resources [p].name = name;
155 resources [p].attrs = attribute;
157 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
159 resources [p].data = new byte [len];
160 s.Read (resources [p].data, 0, (int)len);
167 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
169 if (resources != null) {
170 MonoResource[] new_r = new MonoResource [resources.Length + 1];
171 System.Array.Copy(resources, new_r, resources.Length);
174 resources = new MonoResource [1];
176 int p = resources.Length - 1;
177 resources [p].name = name;
178 resources [p].attrs = attribute;
179 resources [p].data = blob;
182 public ModuleBuilder DefineDynamicModule (string name)
184 return DefineDynamicModule (name, name, false, true);
187 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
189 return DefineDynamicModule (name, name, emitSymbolInfo, true);
192 public ModuleBuilder DefineDynamicModule(string name, string fileName)
194 return DefineDynamicModule (name, fileName, false, false);
197 public ModuleBuilder DefineDynamicModule (string name, string fileName,
200 return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
203 public ModuleBuilder DefineDynamicModule (string name, string fileName,
204 bool emitSymbolInfo, bool transient)
206 check_name_and_filename (name, fileName, false);
209 if (Path.GetExtension (fileName) == String.Empty)
210 throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
212 throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
214 throw new InvalidOperationException ("Assembly was already saved.");
217 ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, modules == null, transient);
219 if (modules != null) {
220 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
221 System.Array.Copy(modules, new_modules, modules.Length);
222 new_modules [modules.Length] = r;
223 modules = new_modules;
225 modules = new ModuleBuilder [1];
231 public IResourceWriter DefineResource (string name, string description, string fileName)
233 return DefineResource (name, description, fileName, ResourceAttributes.Public);
236 public IResourceWriter DefineResource (string name, string description,
237 string fileName, ResourceAttributes attribute)
239 IResourceWriter writer;
241 // description seems to be ignored
242 AddResourceFile (name, fileName, attribute, false);
243 writer = new ResourceWriter (fileName);
244 if (resource_writers == null)
245 resource_writers = new ArrayList ();
246 resource_writers.Add (writer);
251 public void DefineUnmanagedResource (byte[] resource)
253 if (resource == null)
254 throw new ArgumentNullException ("resource");
256 throw new NotImplementedException ();
260 public void DefineUnmanagedResource (string resourceFileName)
262 if (resourceFileName == null)
263 throw new ArgumentNullException ("resourceFileName");
264 if (resourceFileName == String.Empty)
265 throw new ArgumentException ("resourceFileName");
266 if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
267 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exists or is a directory.");
269 throw new NotImplementedException ();
273 public void DefineVersionInfoResource ()
275 throw new NotImplementedException ();
279 public void DefineVersionInfoResource (string product, string productVersion,
280 string company, string copyright, string trademark)
282 throw new NotImplementedException ();
285 public ModuleBuilder GetDynamicModule (string name)
288 throw new ArgumentNullException ("name");
290 throw new ArgumentException ("Name can't be null");
293 for (int i = 0; i < modules.Length; ++i)
294 if (modules [i].name == name)
299 public override Type[] GetExportedTypes ()
301 throw not_supported ();
304 public override FileStream GetFile (string name)
306 throw not_supported ();
309 public override FileStream[] GetFiles() {
310 throw not_supported ();
313 public override FileStream[] GetFiles(bool getResourceModules) {
314 throw not_supported ();
317 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
318 throw not_supported ();
321 public override string[] GetManifestResourceNames() {
322 throw not_supported ();
325 public override Stream GetManifestResourceStream(string name) {
326 throw not_supported ();
328 public override Stream GetManifestResourceStream(Type type, string name) {
329 throw not_supported ();
332 [MethodImplAttribute(MethodImplOptions.InternalCall)]
333 private static extern int getUSIndex (AssemblyBuilder ab, string str);
335 [MethodImplAttribute(MethodImplOptions.InternalCall)]
336 private static extern int getToken (AssemblyBuilder ab, object obj);
338 internal int GetToken (string str) {
339 if (us_string_cache.Contains (str))
340 return (int)us_string_cache [str];
341 int result = getUSIndex (this, str);
342 us_string_cache [str] = result;
346 internal int GetToken (MemberInfo member) {
347 return getToken (this, member);
350 internal int GetToken (SignatureHelper helper) {
351 return getToken (this, helper);
354 internal bool IsSave {
356 return access != (uint)AssemblyBuilderAccess.Run;
360 [MethodImplAttribute(MethodImplOptions.InternalCall)]
361 private static extern int getDataChunk (AssemblyBuilder ab, byte[] buf, int offset);
363 public void Save (string assemblyFileName)
365 byte[] buf = new byte [65536];
369 if (resource_writers != null) {
370 foreach (IResourceWriter writer in resource_writers) {
376 build_metadata (this);
378 foreach (ModuleBuilder module in modules)
382 assemblyFileName = String.Format ("{0}{1}{2}", dir, System.IO.Path.DirectorySeparatorChar, assemblyFileName);
385 file = new FileStream (assemblyFileName, FileMode.Create, FileAccess.Write);
388 while ((count = getDataChunk (this, buf, offset)) != 0) {
389 file.Write (buf, 0, count);
397 // The constant 0x80000000 is internal to Mono, it means `make executable'
399 File.SetAttributes (assemblyFileName, (FileAttributes) (unchecked ((int) 0x80000000)));
402 [MethodImplAttribute(MethodImplOptions.InternalCall)]
403 private static extern void build_metadata (AssemblyBuilder ab);
405 public void SetEntryPoint (MethodInfo entryMethod)
407 SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
410 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
412 if (entryMethod == null)
413 throw new ArgumentNullException ("entryMethod");
414 if (entryMethod.DeclaringType.Assembly != this)
415 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
417 entry_point = entryMethod;
421 public void SetCustomAttribute( CustomAttributeBuilder customBuilder) {
422 if (customBuilder == null)
423 throw new ArgumentNullException ("customBuilder");
425 string attrname = customBuilder.Ctor.ReflectedType.FullName;
428 if (attrname == "System.Reflection.AssemblyVersionAttribute") {
429 data = customBuilder.Data;
431 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
432 version = CustomAttributeBuilder.string_from_bytes (data, pos, len);
434 } else if (attrname == "System.Reflection.AssemblyKeyFileAttribute") {
435 data = customBuilder.Data;
437 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
438 string keyfile_name = CustomAttributeBuilder.string_from_bytes (data, pos, len);
439 using (FileStream fs = new FileStream (keyfile_name, FileMode.Open)) {
440 byte[] snkeypair = new byte [fs.Length];
441 fs.Read (snkeypair, 0, snkeypair.Length);
443 /* FIXME: Extract public key from the keypair */
444 public_key = snkeypair;
447 } else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
448 data = customBuilder.Data;
450 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
451 culture = CustomAttributeBuilder.string_from_bytes (data, pos, len);
452 } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") {
453 data = customBuilder.Data;
455 algid = (uint)data [pos];
456 algid |= ((uint)data [pos + 1]) << 8;
457 algid |= ((uint)data [pos + 2]) << 16;
458 algid |= ((uint)data [pos + 3]) << 24;
459 } else if (attrname == "System.Reflection.AssemblyFlagsAttribute") {
460 data = customBuilder.Data;
462 flags = (uint)data [pos];
463 flags |= ((uint)data [pos + 1]) << 8;
464 flags |= ((uint)data [pos + 2]) << 16;
465 flags |= ((uint)data [pos + 3]) << 24;
467 } else if (attrname == "System.Reflection.AssemblyDelaySignAttribute") {
468 data = customBuilder.Data;
470 delay_sign = data [2] != 0;
472 if (cattrs != null) {
473 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
474 cattrs.CopyTo (new_array, 0);
475 new_array [cattrs.Length] = customBuilder;
478 cattrs = new CustomAttributeBuilder [1];
479 cattrs [0] = customBuilder;
482 public void SetCustomAttribute( ConstructorInfo con, byte[] binaryAttribute) {
484 throw new ArgumentNullException ("con");
485 if (binaryAttribute == null)
486 throw new ArgumentNullException ("binaryAttribute");
488 SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
491 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type) {
492 this.corlib_object_type = corlib_object_type;
493 this.corlib_value_type = corlib_value_type;
494 this.corlib_enum_type = corlib_enum_type;
497 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type, Type corlib_void_type)
499 SetCorlibTypeBuilders (corlib_object_type, corlib_value_type, corlib_enum_type);
500 this.corlib_void_type = corlib_void_type;
503 private Exception not_supported () {
504 // Strange message but this is what MS.NET prints...
505 return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
508 private void check_name_and_filename (string name, string fileName,
509 bool fileNeedsToExists) {
511 throw new ArgumentNullException ("name");
512 if (fileName == null)
513 throw new ArgumentNullException ("fileName");
515 throw new ArgumentException ("name cannot be empty", "name");
517 throw new ArgumentException ("fileName cannot be empty", "fileName");
518 if (Path.GetFileName (fileName) != fileName)
519 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.");
521 // Resource files are created/searched under the assembly storage
523 string fullFileName = fileName;
525 fullFileName = Path.Combine (dir, fileName);
527 if (fileNeedsToExists && !File.Exists (fullFileName))
528 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
530 if (resources != null) {
531 for (int i = 0; i < resources.Length; ++i) {
532 if (resources [i].filename == fullFileName)
533 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
534 if (resources [i].name == name)
535 throw new ArgumentException ("Duplicate name '" + name + "'");
539 if (modules != null) {
540 for (int i = 0; i < modules.Length; ++i) {
541 // Use fileName instead of fullFileName here
542 if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
543 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
544 if (modules [i].Name == name)
545 throw new ArgumentException ("Duplicate name '" + name + "'");