25using System.Collections.Generic;
27using System.Reflection.Metadata;
28using System.Reflection.Metadata.Ecma335;
29using System.Resources;
30using System.Security.Cryptography;
38 internal sealed class AssemblyBuilder :
Assembly
45 ushort revisionVersion;
47 AssemblyNameFlags flags;
48 AssemblyHashAlgorithm hashAlgorithm;
49 StrongNameKeyPair keyPair;
51 internal readonly
string dir;
52 PEFileKinds fileKind = PEFileKinds.Dll;
57 byte[] win32resources;
58 string imageRuntimeVersion;
59 internal int mdStreamVersion = 0x20000;
60 Module pseudoManifestModule;
61 readonly List<ResourceFile> resourceFiles =
new List<ResourceFile>();
62 readonly List<ModuleBuilder> modules =
new List<ModuleBuilder>();
63 readonly List<Module> addedModules =
new List<Module>();
64 readonly List<CustomAttributeBuilder> customAttributes =
new List<CustomAttributeBuilder>();
65 readonly List<CustomAttributeBuilder> declarativeSecurity =
new List<CustomAttributeBuilder>();
66 readonly List<TypeForwarder> typeForwarders =
new List<TypeForwarder>();
68 readonly
struct TypeForwarder
72 internal readonly
bool IncludeNested;
79 internal TypeForwarder(
Type type,
bool includeNested)
82 this.IncludeNested = includeNested;
91 internal string FileName;
92 internal ResourceAttributes Attributes;
93 internal ResourceWriter Writer;
104 internal AssemblyBuilder(Universe universe,
AssemblyName name,
string dir, IEnumerable<CustomAttributeBuilder> customAttributes) :
107 this.name = name.Name;
108 SetVersionHelper(name.Version);
109 if (!
string.IsNullOrEmpty(name.CultureName))
111 this.culture = name.CultureName;
114 this.flags = name.RawFlags;
115 this.hashAlgorithm = name.HashAlgorithm;
116 if (this.hashAlgorithm == AssemblyHashAlgorithm.None)
117 this.hashAlgorithm = AssemblyHashAlgorithm.SHA1;
119 this.keyPair = name.KeyPair;
120 if (this.keyPair !=
null)
122 this.publicKey = this.keyPair.PublicKey;
126 var publicKey = name.GetPublicKey();
127 if (publicKey !=
null && publicKey.Length != 0)
128 this.publicKey = (
byte[])publicKey.Clone();
131 this.dir = dir ??
".";
132 if (customAttributes !=
null)
133 this.customAttributes.AddRange(customAttributes);
135 if (universe.HasCoreLib && !universe.CoreLib.__IsMissing && universe.CoreLib.ImageRuntimeVersion !=
null)
136 this.imageRuntimeVersion = universe.CoreLib.ImageRuntimeVersion;
138 this.imageRuntimeVersion =
TypeUtil.GetAssembly(typeof(
object)).ImageRuntimeVersion;
140 universe.RegisterDynamicAssembly(
this);
143 void SetVersionHelper(Version version)
154 majorVersion = (ushort)version.Major;
155 minorVersion = (ushort)version.Minor;
156 buildVersion = version.Build == -1 ? (ushort)0 : (ushort)version.Build;
157 revisionVersion = version.Revision == -1 ? (ushort)0 : (ushort)version.Revision;
163 this.fullName =
null;
164 Universe.RenameAssembly(
this, oldName);
167 public void __SetAssemblyVersion(Version version)
170 SetVersionHelper(version);
174 public void __SetAssemblyCulture(
string cultureName)
177 this.culture = cultureName;
181 public void __SetAssemblyKeyPair(StrongNameKeyPair keyPair)
184 this.keyPair = keyPair;
187 this.publicKey = keyPair.PublicKey;
193 public void __SetAssemblyPublicKey(
byte[] publicKey)
196 this.publicKey = publicKey ==
null ? null : (
byte[])publicKey.Clone();
200 public void __SetAssemblyAlgorithmId(AssemblyHashAlgorithm hashAlgorithm)
202 this.hashAlgorithm = hashAlgorithm;
205 [Obsolete(
"Use __AssemblyFlags property instead.")]
206 public void __SetAssemblyFlags(AssemblyNameFlags flags)
208 this.__AssemblyFlags = flags;
211 protected override AssemblyNameFlags GetAssemblyFlags()
216 public new AssemblyNameFlags __AssemblyFlags
218 get {
return flags; }
236 n.Version =
new Version(majorVersion, minorVersion, buildVersion, revisionVersion);
237 n.CultureName = culture ??
"";
238 n.HashAlgorithm = hashAlgorithm;
240 n.SetPublicKey(publicKey !=
null ? (
byte[])publicKey.Clone() : Array.Empty<
byte>());
245 public override string Location
247 get {
throw new NotSupportedException(); }
256 public ModuleBuilder DefineDynamicModule(
string name,
string fileName)
258 return DefineDynamicModule(name, fileName,
false);
268 public ModuleBuilder DefineDynamicModule(
string name,
string fileName,
bool emitSymbolInfo)
270 var module =
new ModuleBuilder(
this, name, fileName);
271 module.SetSymWriter(emitSymbolInfo ? Universe.CreateSymbolWriter(module) :
null);
276 public ModuleBuilder GetDynamicModule(
string name)
278 foreach (var module
in modules)
279 if (module.Name == name)
285 public void SetCustomAttribute(
ConstructorInfo con,
byte[] binaryAttribute)
287 SetCustomAttribute(
new CustomAttributeBuilder(con, binaryAttribute));
290 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
292 customAttributes.Add(customBuilder);
295 public void __AddDeclarativeSecurity(CustomAttributeBuilder customBuilder)
297 declarativeSecurity.Add(customBuilder);
300 public void __AddTypeForwarder(
Type type)
302 __AddTypeForwarder(type,
true);
305 public void __AddTypeForwarder(
Type type,
bool includeNested)
307 typeForwarders.Add(
new TypeForwarder(type, includeNested));
310 public void SetEntryPoint(
MethodInfo entryMethod)
312 SetEntryPoint(entryMethod, PEFileKinds.ConsoleApplication);
315 public void SetEntryPoint(
MethodInfo entryMethod, PEFileKinds fileKind)
317 this.entryPoint = entryMethod;
318 this.fileKind = fileKind;
329 public void __Save(Stream peStream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
331 if (modules.Count != 1)
332 throw new NotSupportedException(
"Saving to a stream is only supported for single module assemblies.");
334 __Save(peStream,
null, portableExecutableKind, imageFileMachine);
346 public void __Save(Stream peStream, Stream pdbStream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
348 if (peStream.CanWrite ==
false)
349 throw new ArgumentException(
"Stream must support write.", nameof(peStream));
350 if (pdbStream !=
null && pdbStream.CanWrite ==
false)
351 throw new ArgumentException(
"Stream must support write.", nameof(pdbStream));
352 if (modules.Count != 1)
353 throw new NotSupportedException(
"Saving to a stream is only supported for single module assemblies.");
355 SaveImpl(modules[0].fileName, peStream, pdbStream, portableExecutableKind, imageFileMachine);
362 public void Save(
string assemblyFileName)
364 Save(assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
373 public void Save(
string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
375 SaveImpl(assemblyFileName,
null,
null, portableExecutableKind, imageFileMachine);
386 void SaveImpl(
string assemblyFileName, Stream peStream, Stream pdbStream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
388 ModuleBuilder manifestModule =
null;
391 foreach (var moduleBuilder
in modules)
393 moduleBuilder.SetIsSaved();
394 moduleBuilder.PopulatePropertyAndEventTables();
397 if (manifestModule ==
null &&
string.Compare(moduleBuilder.fileName, assemblyFileName, StringComparison.OrdinalIgnoreCase) == 0)
398 manifestModule = moduleBuilder;
402 manifestModule ??= DefineDynamicModule(
"RefEmit_OnDiskManifestModule", assemblyFileName,
false);
406 assemblyRecord.HashAlgId = (int)hashAlgorithm;
407 assemblyRecord.Name = manifestModule.GetOrAddString(name);
408 assemblyRecord.MajorVersion = majorVersion;
409 assemblyRecord.MinorVersion = minorVersion;
410 assemblyRecord.BuildNumber = buildVersion;
411 assemblyRecord.RevisionNumber = revisionVersion;
413 if (publicKey !=
null)
415 assemblyRecord.PublicKey = manifestModule.GetOrAddBlob(publicKey);
416 assemblyRecord.Flags = (int)(flags | AssemblyNameFlags.PublicKey);
420 assemblyRecord.Flags = (int)(flags & ~AssemblyNameFlags.PublicKey);
424 assemblyRecord.Culture = manifestModule.GetOrAddString(culture);
426 manifestModule.AssemblyTable.AddRecord(assemblyRecord);
432 if (versionInfo !=
null)
434 versionInfo.SetName(GetName());
435 versionInfo.SetFileName(assemblyFileName);
436 foreach (var cab
in customAttributes)
439 if (cab.HasBlob ==
false || Universe.DecodeVersionInfoAttributeBlobs)
440 versionInfo.SetAttribute(
this, cab);
444 versionInfo.Write(versionInfoData);
445 nativeResources.AddVersionInfo(versionInfoData);
449 if (win32icon !=
null)
450 nativeResources.AddIcon(win32icon);
453 if (win32manifest !=
null)
454 nativeResources.AddManifest(win32manifest, fileKind == PEFileKinds.Dll ? (ushort)2 : (ushort)1);
456 if (win32resources !=
null)
457 nativeResources.ImportWin32ResourceFile(win32resources);
460 foreach (var cab in customAttributes)
461 manifestModule.SetCustomAttribute(0x20000001, cab);
463 manifestModule.AddDeclarativeSecurity(0x20000001, declarativeSecurity);
465 foreach (var fwd in typeForwarders)
466 manifestModule.AddTypeForwarder(fwd.Type, fwd.IncludeNested);
469 foreach (var resfile in resourceFiles)
471 if (resfile.Writer !=
null)
473 resfile.Writer.Generate();
474 resfile.Writer.Close();
477 var fileToken = AddFile(manifestModule, resfile.FileName, 1 );
480 rec.Flags = (int)resfile.Attributes;
481 rec.Name = manifestModule.GetOrAddString(resfile.Name);
482 rec.Implementation = MetadataTokens.GetToken(fileToken);
483 manifestModule.ManifestResourceTable.AddRecord(rec);
487 foreach (var module
in modules)
489 module.FillAssemblyRefTable();
491 if (module != manifestModule)
493 var fileToken =
default(AssemblyFileHandle);
494 if (entryPoint !=
null && entryPoint.Module == module)
496 throw new NotSupportedException(
"Multi-module assemblies cannot have an entry point in a module other than the manifest module.");
500 ModuleWriter.WriteModule(
null,
null, module, fileKind, portableExecutableKind, imageFileMachine, module.nativeResources,
default);
501 fileToken = AddFile(manifestModule, module.fileName, 0 );
504 module.ExportTypes(fileToken, manifestModule);
509 foreach (var module
in addedModules)
511 var fileToken = AddFile(manifestModule, module.FullyQualifiedName, 0 );
512 module.ExportTypes(fileToken, manifestModule);
516 ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint,
null, peStream,
null, pdbStream);
519 AssemblyFileHandle AddFile(ModuleBuilder manifestModule,
string fileName,
int flags)
521 var fullPath = fileName;
523 fullPath = Path.Combine(dir, fileName);
525 using var sha1 = SHA1.Create();
526 using var fs =
new FileStream(fullPath, FileMode.Open, FileAccess.Read);
527 var hash = sha1.ComputeHash(fs);
529 return MetadataTokens.AssemblyFileHandle(manifestModule.__AddModule(flags, Path.GetFileName(fileName), hash));
532 public void AddResourceFile(
string name,
string fileName)
534 AddResourceFile(name, fileName, ResourceAttributes.Public);
537 public void AddResourceFile(
string name,
string fileName, ResourceAttributes attribs)
539 var resfile =
new ResourceFile();
541 resfile.FileName = fileName;
542 resfile.Attributes = attribs;
543 resourceFiles.Add(resfile);
546 public IResourceWriter DefineResource(
string name,
string description,
string fileName)
548 return DefineResource(name, description, fileName, ResourceAttributes.Public);
551 public IResourceWriter DefineResource(
string name,
string description,
string fileName, ResourceAttributes attribute)
555 var fullPath = fileName;
557 fullPath = Path.Combine(dir, fileName);
559 var rw =
new ResourceWriter(fullPath);
560 var resfile =
new ResourceFile();
562 resfile.FileName = fileName;
563 resfile.Attributes = attribute;
565 resourceFiles.Add(resfile);
569 public void DefineVersionInfoResource()
571 if (versionInfo !=
null || win32resources !=
null)
572 throw new ArgumentException(
"Native resource has already been defined.");
577 public void DefineVersionInfoResource(
string product,
string productVersion,
string company,
string copyright,
string trademark)
579 if (versionInfo !=
null || win32resources !=
null)
580 throw new ArgumentException(
"Native resource has already been defined.");
583 versionInfo.product = product;
584 versionInfo.informationalVersion = productVersion;
585 versionInfo.company = company;
586 versionInfo.copyright = copyright;
587 versionInfo.trademark = trademark;
590 public void __DefineIconResource(
byte[] iconFile)
592 if (win32icon !=
null || win32resources !=
null)
593 throw new ArgumentException(
"Native resource has already been defined.");
595 win32icon = (
byte[])iconFile.Clone();
598 public void __DefineManifestResource(
byte[] manifest)
600 if (win32manifest !=
null || win32resources !=
null)
601 throw new ArgumentException(
"Native resource has already been defined.");
603 win32manifest = (
byte[])manifest.Clone();
606 public void __DefineUnmanagedResource(
byte[] resource)
608 if (versionInfo !=
null || win32icon !=
null || win32manifest !=
null || win32resources !=
null)
609 throw new ArgumentException(
"Native resource has already been defined.");
614 win32resources = (
byte[])resource.Clone();
617 public void DefineUnmanagedResource(
string resourceFileName)
621 __DefineUnmanagedResource(File.ReadAllBytes(resourceFileName));
624 public override Type[] GetTypes()
626 var list =
new List<Type>();
628 foreach (var module
in modules)
629 module.GetTypesImpl(list);
631 foreach (var module
in addedModules)
632 module.GetTypesImpl(list);
634 return list.ToArray();
639 foreach (var mb
in modules)
641 var type = mb.FindType(typeName);
646 foreach (
Module module
in addedModules)
648 var type = module.FindType(typeName);
656 internal override Type FindTypeIgnoreCase(
TypeName lowerCaseName)
658 foreach (var mb
in modules)
660 var type = mb.FindTypeIgnoreCase(lowerCaseName);
665 foreach (
Module module
in addedModules)
667 var type = module.FindTypeIgnoreCase(lowerCaseName);
675 public override string ImageRuntimeVersion
677 get {
return imageRuntimeVersion; }
680 public void __SetImageRuntimeVersion(
string imageRuntimeVersion,
int mdStreamVersion)
682 this.imageRuntimeVersion = imageRuntimeVersion;
683 this.mdStreamVersion = mdStreamVersion;
686 public override Module ManifestModule => pseudoManifestModule ??=
new ManifestModule(
this);
688 public override MethodInfo EntryPoint => entryPoint;
692 public override Module[] GetLoadedModules(
bool getResourceModules)
694 return GetModules(getResourceModules);
697 public override Module[] GetModules(
bool getResourceModules)
699 var list =
new List<Module>();
701 foreach (var module
in modules)
702 if (getResourceModules || !module.IsResource())
705 foreach (var module
in addedModules)
706 if (getResourceModules || !module.IsResource())
709 return list.ToArray();
712 public override Module GetModule(
string name)
714 foreach (var module
in modules)
715 if (module.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
718 foreach (var module
in addedModules)
719 if (module.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
725 public Module __AddModule(RawModule module)
727 Module mod = module.ToModule(
this);
728 addedModules.Add(mod);
732 public override ManifestResourceInfo GetManifestResourceInfo(
string resourceName)
734 throw new NotSupportedException();
737 public override string[] GetManifestResourceNames()
739 throw new NotSupportedException();
742 public override Stream GetManifestResourceStream(
string resourceName)
744 throw new NotSupportedException();
747 public override bool IsDynamic
752 public static AssemblyBuilder DefineDynamicAssembly(
AssemblyName name, AssemblyBuilderAccess access)
754 return new Universe().DefineDynamicAssembly(name, access);
757 public static AssemblyBuilder DefineDynamicAssembly(
AssemblyName name, AssemblyBuilderAccess access, IEnumerable<CustomAttributeBuilder> assemblyAttributes)
759 return new Universe().DefineDynamicAssembly(name, access, assemblyAttributes);
762 internal override IList<CustomAttributeData> GetCustomAttributesData(
Type attributeType)
764 var list =
new List<CustomAttributeData>();
765 foreach (var cab
in customAttributes)
766 if (attributeType ==
null || attributeType.IsAssignableFrom(cab.Constructor.DeclaringType))
767 list.Add(cab.ToData(
this));
772 internal bool IsWindowsRuntime
774 get {
return (flags & (AssemblyNameFlags)0x200) != 0; }
IKVM.Reflection.Module Module
IKVM.Reflection.Type Type
IKVM.Reflection.Assembly Assembly
IKVM.Reflection.AssemblyName AssemblyName
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.MethodInfo MethodInfo
global::java.lang.invoke.LambdaForm.Name Name
Implements a ResourceSectionBuilder for writing IKVM reflection resource section data.