2
Copyright (C) 2008-2012 Jeroen Frijters
4
This software is provided 'as-is', without any express or implied
5
warranty. In no event will the authors be held liable for any damages
6
arising from the use of this software.
8
Permission is granted to anyone to use this software for any purpose,
9
including commercial applications, and to alter it and redistribute it
10
freely, subject to the following restrictions:
12
1. The origin of this software must not be misrepresented; you must not
13
claim that you wrote the original software. If you use this software
14
in a product, an acknowledgment in the product documentation would be
15
appreciated but is not required.
16
2. Altered source versions must be plainly marked as such, and must not be
17
misrepresented as being the original software.
18
3. This notice may not be removed or altered from any source distribution.
25
using System.Collections.Generic;
26
using System.Configuration.Assemblies;
28
using System.Diagnostics;
29
using System.Globalization;
30
using System.Resources;
31
using System.Security.Cryptography;
32
using System.Security;
33
using IKVM.Reflection.Metadata;
34
using IKVM.Reflection.Impl;
35
using IKVM.Reflection.Writer;
37
namespace IKVM.Reflection.Emit
39
public sealed class AssemblyBuilder : Assembly
41
private readonly string name;
42
private ushort majorVersion;
43
private ushort minorVersion;
44
private ushort buildVersion;
45
private ushort revisionVersion;
46
private string culture;
47
private AssemblyNameFlags flags;
48
private AssemblyHashAlgorithm hashAlgorithm;
49
private StrongNameKeyPair keyPair;
50
private byte[] publicKey;
51
internal readonly string dir;
52
private readonly PermissionSet requiredPermissions;
53
private readonly PermissionSet optionalPermissions;
54
private readonly PermissionSet refusedPermissions;
55
private PEFileKinds fileKind = PEFileKinds.Dll;
56
private MethodInfo entryPoint;
57
private VersionInfo versionInfo;
58
private byte[] win32icon;
59
private byte[] win32manifest;
60
private byte[] win32resources;
61
private string imageRuntimeVersion;
62
internal int mdStreamVersion = 0x20000;
63
private Module pseudoManifestModule;
64
private readonly List<ResourceFile> resourceFiles = new List<ResourceFile>();
65
private readonly List<ModuleBuilder> modules = new List<ModuleBuilder>();
66
private readonly List<Module> addedModules = new List<Module>();
67
private readonly List<CustomAttributeBuilder> customAttributes = new List<CustomAttributeBuilder>();
68
private readonly List<CustomAttributeBuilder> declarativeSecurity = new List<CustomAttributeBuilder>();
69
private readonly List<Type> typeForwarders = new List<Type>();
71
private struct ResourceFile
74
internal string FileName;
75
internal ResourceAttributes Attributes;
76
internal ResourceWriter Writer;
79
internal AssemblyBuilder(Universe universe, AssemblyName name, string dir, PermissionSet requiredPermissions, PermissionSet optionalPermissions, PermissionSet refusedPermissions)
82
this.name = name.Name;
83
SetVersionHelper(name.Version);
84
if (!string.IsNullOrEmpty(name.Culture))
86
this.culture = name.Culture;
88
this.flags = name.RawFlags;
89
this.hashAlgorithm = name.HashAlgorithm;
90
if (this.hashAlgorithm == AssemblyHashAlgorithm.None)
92
this.hashAlgorithm = AssemblyHashAlgorithm.SHA1;
94
this.keyPair = name.KeyPair;
95
if (this.keyPair != null)
97
this.publicKey = this.keyPair.PublicKey;
101
byte[] publicKey = name.GetPublicKey();
102
if (publicKey != null && publicKey.Length != 0)
104
this.publicKey = (byte[])publicKey.Clone();
107
this.dir = dir ?? ".";
108
this.requiredPermissions = requiredPermissions;
109
this.optionalPermissions = optionalPermissions;
110
this.refusedPermissions = refusedPermissions;
111
if (universe.HasMscorlib && !universe.Mscorlib.__IsMissing && universe.Mscorlib.ImageRuntimeVersion != null)
113
this.imageRuntimeVersion = universe.Mscorlib.ImageRuntimeVersion;
117
this.imageRuntimeVersion = typeof(object).Assembly.ImageRuntimeVersion;
121
private void SetVersionHelper(Version version)
132
majorVersion = (ushort)version.Major;
133
minorVersion = (ushort)version.Minor;
134
buildVersion = version.Build == -1 ? (ushort)0 : (ushort)version.Build;
135
revisionVersion = version.Revision == -1 ? (ushort)0 : (ushort)version.Revision;
139
private void Rename(AssemblyName oldName)
141
this.fullName = null;
142
universe.RenameAssembly(this, oldName);
145
public void __SetAssemblyVersion(Version version)
147
AssemblyName oldName = GetName();
148
SetVersionHelper(version);
152
public void __SetAssemblyCulture(string cultureName)
154
AssemblyName oldName = GetName();
155
this.culture = cultureName;
159
public void __SetAssemblyKeyPair(StrongNameKeyPair keyPair)
161
AssemblyName oldName = GetName();
162
this.keyPair = keyPair;
165
this.publicKey = keyPair.PublicKey;
170
// this is used in combination with delay signing
171
public void __SetAssemblyPublicKey(byte[] publicKey)
173
AssemblyName oldName = GetName();
174
this.publicKey = publicKey == null ? null : (byte[])publicKey.Clone();
178
public void __SetAssemblyAlgorithmId(AssemblyHashAlgorithm hashAlgorithm)
180
this.hashAlgorithm = hashAlgorithm;
183
[Obsolete("Use __AssemblyFlags property instead.")]
184
public void __SetAssemblyFlags(AssemblyNameFlags flags)
186
this.__AssemblyFlags = flags;
189
protected override AssemblyNameFlags GetAssemblyFlags()
194
public new AssemblyNameFlags __AssemblyFlags
196
get { return flags; }
199
AssemblyName oldName = GetName();
210
public override AssemblyName GetName()
212
AssemblyName n = new AssemblyName();
214
n.Version = new Version(majorVersion, minorVersion, buildVersion, revisionVersion);
215
n.Culture = culture ?? "";
216
n.HashAlgorithm = hashAlgorithm;
218
n.SetPublicKey(publicKey != null ? (byte[])publicKey.Clone() : Empty<byte>.Array);
223
public override string Location
225
get { throw new NotSupportedException(); }
228
public ModuleBuilder DefineDynamicModule(string name, string fileName)
230
return DefineDynamicModule(name, fileName, false);
233
public ModuleBuilder DefineDynamicModule(string name, string fileName, bool emitSymbolInfo)
235
ModuleBuilder module = new ModuleBuilder(this, name, fileName, emitSymbolInfo);
240
public ModuleBuilder GetDynamicModule(string name)
242
foreach (ModuleBuilder module in modules)
244
if (module.Name == name)
252
public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
254
SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
257
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
259
customAttributes.Add(customBuilder);
262
public void __AddDeclarativeSecurity(CustomAttributeBuilder customBuilder)
264
declarativeSecurity.Add(customBuilder);
267
public void __AddTypeForwarder(Type type)
269
typeForwarders.Add(type);
272
public void SetEntryPoint(MethodInfo entryMethod)
274
SetEntryPoint(entryMethod, PEFileKinds.ConsoleApplication);
277
public void SetEntryPoint(MethodInfo entryMethod, PEFileKinds fileKind)
279
this.entryPoint = entryMethod;
280
this.fileKind = fileKind;
283
public void __Save(Stream stream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
285
if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek || stream.Position != 0)
287
throw new ArgumentException("Stream must support read/write/seek and current position must be zero.", "stream");
289
if (modules.Count != 1)
291
throw new NotSupportedException("Saving to a stream is only supported for single module assemblies.");
293
SaveImpl(modules[0].fileName, stream, portableExecutableKind, imageFileMachine);
296
public void Save(string assemblyFileName)
298
Save(assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
301
public void Save(string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
303
SaveImpl(assemblyFileName, null, portableExecutableKind, imageFileMachine);
306
private void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
308
ModuleBuilder manifestModule = null;
310
foreach (ModuleBuilder moduleBuilder in modules)
312
moduleBuilder.SetIsSaved();
313
moduleBuilder.PopulatePropertyAndEventTables();
315
if (manifestModule == null
316
&& string.Compare(moduleBuilder.fileName, assemblyFileName, StringComparison.OrdinalIgnoreCase) == 0)
318
manifestModule = moduleBuilder;
322
if (manifestModule == null)
324
manifestModule = DefineDynamicModule("RefEmit_OnDiskManifestModule", assemblyFileName, false);
327
AssemblyTable.Record assemblyRecord = new AssemblyTable.Record();
328
assemblyRecord.HashAlgId = (int)hashAlgorithm;
329
assemblyRecord.Name = manifestModule.Strings.Add(name);
330
assemblyRecord.MajorVersion = majorVersion;
331
assemblyRecord.MinorVersion = minorVersion;
332
assemblyRecord.BuildNumber = buildVersion;
333
assemblyRecord.RevisionNumber = revisionVersion;
334
if (publicKey != null)
336
assemblyRecord.PublicKey = manifestModule.Blobs.Add(ByteBuffer.Wrap(publicKey));
337
assemblyRecord.Flags = (int)(flags | AssemblyNameFlags.PublicKey);
341
assemblyRecord.Flags = (int)(flags & ~AssemblyNameFlags.PublicKey);
345
assemblyRecord.Culture = manifestModule.Strings.Add(culture);
347
int token = 0x20000000 + manifestModule.AssemblyTable.AddRecord(assemblyRecord);
349
#pragma warning disable 618
350
// this values are obsolete, but we already know that so we disable the warning
351
System.Security.Permissions.SecurityAction requestMinimum = System.Security.Permissions.SecurityAction.RequestMinimum;
352
System.Security.Permissions.SecurityAction requestOptional = System.Security.Permissions.SecurityAction.RequestOptional;
353
System.Security.Permissions.SecurityAction requestRefuse = System.Security.Permissions.SecurityAction.RequestRefuse;
354
#pragma warning restore 618
355
if (requiredPermissions != null)
357
manifestModule.AddDeclarativeSecurity(token, requestMinimum, requiredPermissions);
359
if (optionalPermissions != null)
361
manifestModule.AddDeclarativeSecurity(token, requestOptional, optionalPermissions);
363
if (refusedPermissions != null)
365
manifestModule.AddDeclarativeSecurity(token, requestRefuse, refusedPermissions);
368
ResourceSection unmanagedResources = versionInfo != null || win32icon != null || win32manifest != null || win32resources != null
369
? new ResourceSection()
372
if (versionInfo != null)
374
versionInfo.SetName(GetName());
375
versionInfo.SetFileName(assemblyFileName);
376
foreach (CustomAttributeBuilder cab in customAttributes)
378
// .NET doesn't support copying blob custom attributes into the version info
381
versionInfo.SetAttribute(cab);
384
ByteBuffer versionInfoData = new ByteBuffer(512);
385
versionInfo.Write(versionInfoData);
386
unmanagedResources.AddVersionInfo(versionInfoData);
389
if (win32icon != null)
391
unmanagedResources.AddIcon(win32icon);
394
if (win32manifest != null)
396
unmanagedResources.AddManifest(win32manifest, fileKind == PEFileKinds.Dll ? (ushort)2 : (ushort)1);
399
if (win32resources != null)
401
unmanagedResources.ExtractResources(win32resources);
404
foreach (CustomAttributeBuilder cab in customAttributes)
406
// we intentionally don't filter out the version info (pseudo) custom attributes (to be compatible with .NET)
407
manifestModule.SetCustomAttribute(0x20000001, cab);
410
manifestModule.AddDeclarativeSecurity(0x20000001, declarativeSecurity);
412
foreach (Type type in typeForwarders)
414
manifestModule.AddTypeForwarder(type);
417
foreach (ResourceFile resfile in resourceFiles)
419
if (resfile.Writer != null)
421
resfile.Writer.Generate();
422
resfile.Writer.Close();
424
int fileToken = AddFile(manifestModule, resfile.FileName, 1 /*ContainsNoMetaData*/);
425
ManifestResourceTable.Record rec = new ManifestResourceTable.Record();
427
rec.Flags = (int)resfile.Attributes;
428
rec.Name = manifestModule.Strings.Add(resfile.Name);
429
rec.Implementation = fileToken;
430
manifestModule.ManifestResource.AddRecord(rec);
433
int entryPointToken = 0;
435
foreach (ModuleBuilder moduleBuilder in modules)
437
moduleBuilder.FillAssemblyRefTable();
438
moduleBuilder.EmitResources();
439
if (moduleBuilder != manifestModule)
442
if (entryPoint != null && entryPoint.Module == moduleBuilder)
444
ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.unmanagedResources, entryPoint.MetadataToken);
445
entryPointToken = fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/);
449
ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.unmanagedResources, 0);
450
fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/);
452
moduleBuilder.ExportTypes(fileToken, manifestModule);
456
foreach (Module module in addedModules)
458
int fileToken = AddFile(manifestModule, module.FullyQualifiedName, 0 /*ContainsMetaData*/);
459
module.ExportTypes(fileToken, manifestModule);
462
if (entryPointToken == 0 && entryPoint != null)
464
entryPointToken = entryPoint.MetadataToken;
467
// finally, write the manifest module
468
ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, unmanagedResources ?? manifestModule.unmanagedResources, entryPointToken, streamOrNull);
471
private int AddFile(ModuleBuilder manifestModule, string fileName, int flags)
473
SHA1Managed hash = new SHA1Managed();
474
string fullPath = fileName;
477
fullPath = Path.Combine(dir, fileName);
479
using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read))
481
using (CryptoStream cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write))
483
byte[] buf = new byte[8192];
484
ModuleWriter.HashChunk(fs, cs, buf, (int)fs.Length);
487
return manifestModule.__AddModule(flags, Path.GetFileName(fileName), hash.Hash);
490
public void AddResourceFile(string name, string fileName)
492
AddResourceFile(name, fileName, ResourceAttributes.Public);
495
public void AddResourceFile(string name, string fileName, ResourceAttributes attribs)
497
ResourceFile resfile = new ResourceFile();
499
resfile.FileName = fileName;
500
resfile.Attributes = attribs;
501
resourceFiles.Add(resfile);
504
public IResourceWriter DefineResource(string name, string description, string fileName)
506
return DefineResource(name, description, fileName, ResourceAttributes.Public);
509
public IResourceWriter DefineResource(string name, string description, string fileName, ResourceAttributes attribute)
511
// FXBUG we ignore the description, because there is no such thing
513
string fullPath = fileName;
516
fullPath = Path.Combine(dir, fileName);
518
ResourceWriter rw = new ResourceWriter(fullPath);
519
ResourceFile resfile;
521
resfile.FileName = fileName;
522
resfile.Attributes = attribute;
524
resourceFiles.Add(resfile);
528
public void DefineVersionInfoResource()
530
if (versionInfo != null || win32resources != null)
532
throw new ArgumentException("Native resource has already been defined.");
534
versionInfo = new VersionInfo();
537
public void DefineVersionInfoResource(string product, string productVersion, string company, string copyright, string trademark)
539
if (versionInfo != null || win32resources != null)
541
throw new ArgumentException("Native resource has already been defined.");
543
versionInfo = new VersionInfo();
544
versionInfo.product = product;
545
versionInfo.informationalVersion = productVersion;
546
versionInfo.company = company;
547
versionInfo.copyright = copyright;
548
versionInfo.trademark = trademark;
551
public void __DefineIconResource(byte[] iconFile)
553
if (win32icon != null || win32resources != null)
555
throw new ArgumentException("Native resource has already been defined.");
557
win32icon = (byte[])iconFile.Clone();
560
public void __DefineManifestResource(byte[] manifest)
562
if (win32manifest != null || win32resources != null)
564
throw new ArgumentException("Native resource has already been defined.");
566
win32manifest = (byte[])manifest.Clone();
569
public void __DefineUnmanagedResource(byte[] resource)
571
if (versionInfo != null || win32icon != null || win32manifest != null || win32resources != null)
573
throw new ArgumentException("Native resource has already been defined.");
575
// The standard .NET DefineUnmanagedResource(byte[]) is useless, because it embeds "resource" (as-is) as the .rsrc section,
576
// but it doesn't set the PE file Resource Directory entry to point to it. That's why we have a renamed version, which behaves
577
// like DefineUnmanagedResource(string).
578
win32resources = (byte[])resource.Clone();
581
public void DefineUnmanagedResource(string resourceFileName)
583
// This method reads the specified resource file (Win32 .res file) and converts it into the appropriate format and embeds it in the .rsrc section,
584
// also setting the Resource Directory entry.
585
__DefineUnmanagedResource(File.ReadAllBytes(resourceFileName));
588
public override Type[] GetTypes()
590
List<Type> list = new List<Type>();
591
foreach (ModuleBuilder module in modules)
593
module.GetTypesImpl(list);
595
foreach (Module module in addedModules)
597
module.GetTypesImpl(list);
599
return list.ToArray();
602
internal override Type FindType(TypeName typeName)
604
foreach (ModuleBuilder mb in modules)
606
Type type = mb.FindType(typeName);
612
foreach (Module module in addedModules)
614
Type type = module.FindType(typeName);
623
internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
625
foreach (ModuleBuilder mb in modules)
627
Type type = mb.FindTypeIgnoreCase(lowerCaseName);
633
foreach (Module module in addedModules)
635
Type type = module.FindTypeIgnoreCase(lowerCaseName);
644
public override string ImageRuntimeVersion
646
get { return imageRuntimeVersion; }
649
public void __SetImageRuntimeVersion(string imageRuntimeVersion, int mdStreamVersion)
651
this.imageRuntimeVersion = imageRuntimeVersion;
652
this.mdStreamVersion = mdStreamVersion;
655
public override Module ManifestModule
659
if (pseudoManifestModule == null)
661
pseudoManifestModule = new ManifestModule(this);
663
return pseudoManifestModule;
667
public override MethodInfo EntryPoint
669
get { return entryPoint; }
672
public override AssemblyName[] GetReferencedAssemblies()
674
return Empty<AssemblyName>.Array;
677
public override Module[] GetLoadedModules(bool getResourceModules)
679
return GetModules(getResourceModules);
682
public override Module[] GetModules(bool getResourceModules)
684
List<Module> list = new List<Module>();
685
foreach (ModuleBuilder module in modules)
687
if (getResourceModules || !module.IsResource())
692
foreach (Module module in addedModules)
694
if (getResourceModules || !module.IsResource())
699
return list.ToArray();
702
public override Module GetModule(string name)
704
foreach (ModuleBuilder module in modules)
706
if (module.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
711
foreach (Module module in addedModules)
713
if (module.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
721
public Module __AddModule(RawModule module)
723
Module mod = module.ToModule(this);
724
addedModules.Add(mod);
728
public override ManifestResourceInfo GetManifestResourceInfo(string resourceName)
730
throw new NotSupportedException();
733
public override string[] GetManifestResourceNames()
735
throw new NotSupportedException();
738
public override Stream GetManifestResourceStream(string resourceName)
740
throw new NotSupportedException();
743
public override bool IsDynamic
748
internal override IList<CustomAttributeData> GetCustomAttributesData(Type attributeType)
750
List<CustomAttributeData> list = new List<CustomAttributeData>();
751
foreach (CustomAttributeBuilder cab in customAttributes)
753
if (attributeType == null || attributeType.IsAssignableFrom(cab.Constructor.DeclaringType))
755
list.Add(cab.ToData(this));
761
internal bool IsWindowsRuntime
763
get { return (flags & (AssemblyNameFlags)0x200) != 0; }
767
sealed class ManifestModule : NonPEModule
769
private readonly AssemblyBuilder assembly;
770
private readonly Guid guid = Guid.NewGuid();
772
internal ManifestModule(AssemblyBuilder assembly)
773
: base(assembly.universe)
775
this.assembly = assembly;
778
public override int MDStreamVersion
780
get { return assembly.mdStreamVersion; }
783
public override Assembly Assembly
785
get { return assembly; }
788
internal override Type FindType(TypeName typeName)
793
internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
798
internal override void GetTypesImpl(List<Type> list)
802
public override string FullyQualifiedName
804
get { return Path.Combine(assembly.dir, "RefEmit_InMemoryManifestModule"); }
807
public override string Name
809
get { return "<In Memory Module>"; }
812
public override Guid ModuleVersionId
817
public override string ScopeName
819
get { return "RefEmit_InMemoryManifestModule"; }
822
protected override Exception NotSupportedException()
824
return new InvalidOperationException();