зеркало из https://github.com/mono/ikvm-fork.git
New Ref.Emit implementation.
This commit is contained in:
Родитель
19f5c9cd08
Коммит
4f74774934
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Cryptography;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
using IKVM.Reflection.Emit.Impl;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public sealed class AssemblyBuilder : IkvmAssembly
|
||||
{
|
||||
private readonly AssemblyName name;
|
||||
private readonly string dir;
|
||||
private PEFileKinds fileKind = PEFileKinds.Dll;
|
||||
private MethodBuilder entryPoint;
|
||||
private bool setVersionInfo;
|
||||
private List<ResourceFile> resourceFiles = new List<ResourceFile>();
|
||||
private List<ModuleBuilder> modules = new List<ModuleBuilder>();
|
||||
private List<CustomAttributeBuilder> customAttributes = new List<CustomAttributeBuilder>();
|
||||
|
||||
private struct ResourceFile
|
||||
{
|
||||
internal string Name;
|
||||
internal string FileName;
|
||||
internal ResourceAttributes Attributes;
|
||||
}
|
||||
|
||||
private AssemblyBuilder(AssemblyName name, string dir)
|
||||
{
|
||||
this.name = name;
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access)
|
||||
{
|
||||
return DefineDynamicAssembly(name, access, null);
|
||||
}
|
||||
|
||||
public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, string dir)
|
||||
{
|
||||
return new AssemblyBuilder(name, dir);
|
||||
}
|
||||
|
||||
public AssemblyName GetName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public string FullName
|
||||
{
|
||||
get { return name.FullName; }
|
||||
}
|
||||
|
||||
public ModuleBuilder DefineDynamicModule(string name, string fileName, bool emitSymbolInfo)
|
||||
{
|
||||
ModuleBuilder module = new ModuleBuilder(this, name, fileName, emitSymbolInfo);
|
||||
modules.Add(module);
|
||||
return module;
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
if (customBuilder.Constructor.DeclaringType == typeof(AssemblyVersionAttribute))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
customAttributes.Add(customBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEntryPoint(MethodBuilder mb)
|
||||
{
|
||||
SetEntryPoint(mb, PEFileKinds.ConsoleApplication);
|
||||
}
|
||||
|
||||
public void SetEntryPoint(MethodBuilder mb, PEFileKinds kind)
|
||||
{
|
||||
this.entryPoint = mb;
|
||||
this.fileKind = kind;
|
||||
}
|
||||
|
||||
public void Save(string assemblyFileName)
|
||||
{
|
||||
Save(assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
|
||||
}
|
||||
|
||||
public void Save(string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
|
||||
{
|
||||
ModuleBuilder manifestModule = null;
|
||||
|
||||
foreach (ModuleBuilder moduleBuilder in modules)
|
||||
{
|
||||
if (string.Compare(moduleBuilder.fileName, assemblyFileName, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
{
|
||||
manifestModule = moduleBuilder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (manifestModule == null)
|
||||
{
|
||||
manifestModule = DefineDynamicModule("RefEmit_OnDiskManifestModule", assemblyFileName, false);
|
||||
}
|
||||
|
||||
TableHeap.AssemblyTable.Record assemblyRecord = new TableHeap.AssemblyTable.Record();
|
||||
assemblyRecord.HashAlgId = 0x8004; // SHA1
|
||||
assemblyRecord.Name = manifestModule.Strings.Add(name.Name);
|
||||
if (name.Version != null)
|
||||
{
|
||||
assemblyRecord.MajorVersion = (short)name.Version.Major;
|
||||
assemblyRecord.MinorVersion = (short)name.Version.Major;
|
||||
assemblyRecord.BuildNumber = (short)name.Version.Build;
|
||||
assemblyRecord.RevisionNumber = (short)name.Version.Revision;
|
||||
}
|
||||
if (name.KeyPair != null)
|
||||
{
|
||||
assemblyRecord.PublicKey = manifestModule.Blobs.Add(ByteBuffer.Wrap(name.KeyPair.PublicKey));
|
||||
assemblyRecord.Flags |= 0x0001; // PublicKey
|
||||
}
|
||||
if (name.CultureInfo != null)
|
||||
{
|
||||
assemblyRecord.Culture = manifestModule.Strings.Add(name.CultureInfo.Name);
|
||||
}
|
||||
manifestModule.Tables.Assembly.AddRecord(assemblyRecord);
|
||||
|
||||
ByteBuffer versionInfoData = null;
|
||||
if (setVersionInfo)
|
||||
{
|
||||
VersionInfo versionInfo = new VersionInfo();
|
||||
versionInfo.SetName(name);
|
||||
versionInfo.SetFileName(assemblyFileName);
|
||||
foreach (CustomAttributeBuilder cab in customAttributes)
|
||||
{
|
||||
versionInfo.SetAttribute(cab);
|
||||
}
|
||||
versionInfoData = new ByteBuffer(512);
|
||||
versionInfo.Write(versionInfoData);
|
||||
}
|
||||
|
||||
foreach (CustomAttributeBuilder cab in customAttributes)
|
||||
{
|
||||
manifestModule.SetCustomAttribute(0x20000001, cab);
|
||||
}
|
||||
|
||||
foreach (ResourceFile resfile in resourceFiles)
|
||||
{
|
||||
int fileToken = AddFile(manifestModule, resfile.FileName, 1 /*ContainsNoMetaData*/);
|
||||
TableHeap.ManifestResourceTable.Record rec = new TableHeap.ManifestResourceTable.Record();
|
||||
rec.Offset = 0;
|
||||
rec.Flags = (int)resfile.Attributes;
|
||||
rec.Name = manifestModule.Strings.Add(resfile.Name);
|
||||
rec.Implementation = fileToken;
|
||||
manifestModule.Tables.ManifestResource.AddRecord(rec);
|
||||
}
|
||||
|
||||
int entryPointToken = 0;
|
||||
|
||||
foreach (ModuleBuilder moduleBuilder in modules)
|
||||
{
|
||||
if (moduleBuilder != manifestModule)
|
||||
{
|
||||
int fileToken;
|
||||
if (entryPoint != null && entryPoint.ModuleBuilder == moduleBuilder)
|
||||
{
|
||||
ModuleWriter.WriteModule(dir, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, null, entryPoint.MetadataToken);
|
||||
entryPointToken = fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/);
|
||||
}
|
||||
else
|
||||
{
|
||||
ModuleWriter.WriteModule(dir, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, null, 0);
|
||||
fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/);
|
||||
}
|
||||
moduleBuilder.ExportTypes(fileToken, manifestModule);
|
||||
}
|
||||
}
|
||||
|
||||
if (entryPointToken == 0 && entryPoint != null)
|
||||
{
|
||||
entryPointToken = entryPoint.MetadataToken;
|
||||
}
|
||||
|
||||
// finally, write the manifest module
|
||||
ModuleWriter.WriteModule(dir, name.KeyPair, manifestModule, fileKind, portableExecutableKind, imageFileMachine, versionInfoData, entryPointToken);
|
||||
}
|
||||
|
||||
private int AddFile(ModuleBuilder manifestModule, string fileName, int flags)
|
||||
{
|
||||
SHA1Managed hash = new SHA1Managed();
|
||||
string fullPath = fileName;
|
||||
if (dir != null)
|
||||
{
|
||||
fullPath = Path.Combine(dir, fileName);
|
||||
}
|
||||
using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
using (CryptoStream cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write))
|
||||
{
|
||||
byte[] buf = new byte[8192];
|
||||
ModuleWriter.HashChunk(fs, cs, buf, (int)fs.Length);
|
||||
}
|
||||
}
|
||||
TableHeap.FileTable.Record file = new TableHeap.FileTable.Record();
|
||||
file.Flags = flags;
|
||||
file.Name = manifestModule.Strings.Add(fileName);
|
||||
file.HashValue = manifestModule.Blobs.Add(ByteBuffer.Wrap(hash.Hash));
|
||||
return 0x26000000 + manifestModule.Tables.File.AddRecord(file);
|
||||
}
|
||||
|
||||
public void AddResourceFile(string name, string fileName)
|
||||
{
|
||||
AddResourceFile(name, fileName, ResourceAttributes.Public);
|
||||
}
|
||||
|
||||
public void AddResourceFile(string name, string fileName, ResourceAttributes attribs)
|
||||
{
|
||||
ResourceFile resfile = new ResourceFile();
|
||||
resfile.Name = name;
|
||||
resfile.FileName = fileName;
|
||||
resfile.Attributes = attribs;
|
||||
resourceFiles.Add(resfile);
|
||||
}
|
||||
|
||||
public void DefineVersionInfoResource()
|
||||
{
|
||||
setVersionInfo = true;
|
||||
}
|
||||
|
||||
public override Type GetType(string typeName)
|
||||
{
|
||||
foreach (ModuleBuilder mb in modules)
|
||||
{
|
||||
Type type = mb.GetType(typeName);
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public sealed class ConstructorBuilder : ConstructorInfo
|
||||
{
|
||||
private readonly MethodBuilder methodBuilder;
|
||||
|
||||
internal ConstructorBuilder(MethodBuilder mb)
|
||||
{
|
||||
this.methodBuilder = mb;
|
||||
}
|
||||
|
||||
public ParameterBuilder DefineParameter(int position, ParameterAttributes attributes, string strParamName)
|
||||
{
|
||||
return methodBuilder.DefineParameter(position, attributes, strParamName);
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
methodBuilder.SetCustomAttribute(customBuilder);
|
||||
}
|
||||
|
||||
public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
|
||||
{
|
||||
methodBuilder.AddDeclarativeSecurity(securityAction, permissionSet);
|
||||
}
|
||||
|
||||
public void SetImplementationFlags(MethodImplAttributes attributes)
|
||||
{
|
||||
methodBuilder.SetImplementationFlags(attributes);
|
||||
}
|
||||
|
||||
public ILGenerator GetILGenerator()
|
||||
{
|
||||
return methodBuilder.GetILGenerator();
|
||||
}
|
||||
|
||||
public override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override MethodAttributes Attributes
|
||||
{
|
||||
get { return methodBuilder.Attributes; }
|
||||
}
|
||||
|
||||
public override MethodImplAttributes GetMethodImplementationFlags()
|
||||
{
|
||||
return methodBuilder.GetMethodImplementationFlags();
|
||||
}
|
||||
|
||||
public override ParameterInfo[] GetParameters()
|
||||
{
|
||||
return methodBuilder.GetParameters();
|
||||
}
|
||||
|
||||
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
return methodBuilder.Invoke(obj, invokeAttr, binder, parameters, culture);
|
||||
}
|
||||
|
||||
public override RuntimeMethodHandle MethodHandle
|
||||
{
|
||||
get { return methodBuilder.MethodHandle; }
|
||||
}
|
||||
|
||||
public override Type DeclaringType
|
||||
{
|
||||
get { return methodBuilder.DeclaringType; }
|
||||
}
|
||||
|
||||
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
||||
{
|
||||
return methodBuilder.GetCustomAttributes(attributeType, inherit);
|
||||
}
|
||||
|
||||
public override object[] GetCustomAttributes(bool inherit)
|
||||
{
|
||||
return methodBuilder.GetCustomAttributes(inherit);
|
||||
}
|
||||
|
||||
public override bool IsDefined(Type attributeType, bool inherit)
|
||||
{
|
||||
return methodBuilder.IsDefined(attributeType, inherit);
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return methodBuilder.Name; }
|
||||
}
|
||||
|
||||
public override Type ReflectedType
|
||||
{
|
||||
get { return methodBuilder.ReflectedType; }
|
||||
}
|
||||
|
||||
public override int MetadataToken
|
||||
{
|
||||
get { return methodBuilder.MetadataToken; }
|
||||
}
|
||||
|
||||
internal ModuleBuilder ModuleBuilder
|
||||
{
|
||||
get { return methodBuilder.ModuleBuilder; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public class CustomAttributeBuilder
|
||||
{
|
||||
private readonly ConstructorInfo con;
|
||||
private readonly byte[] blob;
|
||||
private readonly object[] constructorArgs;
|
||||
private readonly PropertyInfo[] namedProperties;
|
||||
private readonly object[] propertyValues;
|
||||
private readonly FieldInfo[] namedFields;
|
||||
private readonly object[] fieldValues;
|
||||
|
||||
internal CustomAttributeBuilder(ConstructorInfo con, byte[] blob)
|
||||
{
|
||||
this.con = con;
|
||||
this.blob = blob;
|
||||
this.constructorArgs = null;
|
||||
this.namedProperties = null;
|
||||
this.propertyValues = null;
|
||||
this.namedFields = null;
|
||||
this.fieldValues = null;
|
||||
}
|
||||
|
||||
public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs)
|
||||
: this(con, constructorArgs, null, null, null,null)
|
||||
{
|
||||
}
|
||||
|
||||
public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues)
|
||||
: this(con, constructorArgs, null, null, namedFields, fieldValues)
|
||||
{
|
||||
}
|
||||
|
||||
public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)
|
||||
{
|
||||
this.con = con;
|
||||
this.blob = null;
|
||||
this.constructorArgs = constructorArgs;
|
||||
this.namedProperties = namedProperties;
|
||||
this.propertyValues = propertyValues;
|
||||
this.namedFields = namedFields;
|
||||
this.fieldValues = fieldValues;
|
||||
}
|
||||
|
||||
private class BlobWriter
|
||||
{
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
private readonly CustomAttributeBuilder cab;
|
||||
private readonly MemoryStream str = new MemoryStream();
|
||||
|
||||
internal BlobWriter(ModuleBuilder moduleBuilder, CustomAttributeBuilder cab)
|
||||
{
|
||||
this.moduleBuilder = moduleBuilder;
|
||||
this.cab = cab;
|
||||
}
|
||||
|
||||
internal byte[] GetBlob()
|
||||
{
|
||||
// prolog
|
||||
WriteUInt16(1);
|
||||
ParameterInfo[] pi = cab.con.GetParameters();
|
||||
for (int i = 0; i < pi.Length; i++)
|
||||
{
|
||||
WriteFixedArg(pi[i].ParameterType, cab.constructorArgs[i]);
|
||||
}
|
||||
// NumNamed
|
||||
int named = 0;
|
||||
if (cab.namedFields != null)
|
||||
{
|
||||
named += cab.namedFields.Length;
|
||||
}
|
||||
if (cab.namedProperties != null)
|
||||
{
|
||||
named += cab.namedProperties.Length;
|
||||
}
|
||||
WriteUInt16((ushort)named);
|
||||
if (cab.namedFields != null)
|
||||
{
|
||||
for (int i = 0; i < cab.namedFields.Length; i++)
|
||||
{
|
||||
WriteNamedArg(0x53, cab.namedFields[i].FieldType, cab.namedFields[i].Name, cab.fieldValues[i]);
|
||||
}
|
||||
}
|
||||
if (cab.namedProperties != null)
|
||||
{
|
||||
for (int i = 0; i < cab.namedProperties.Length; i++)
|
||||
{
|
||||
WriteNamedArg(0x54, cab.namedProperties[i].PropertyType, cab.namedProperties[i].Name, cab.propertyValues[i]);
|
||||
}
|
||||
}
|
||||
return str.ToArray();
|
||||
}
|
||||
|
||||
private void WriteNamedArg(byte fieldOrProperty, Type type, string name, object value)
|
||||
{
|
||||
str.WriteByte(fieldOrProperty);
|
||||
WriteFieldOrPropType(type);
|
||||
WriteString(name);
|
||||
WriteFixedArg(type, value);
|
||||
}
|
||||
|
||||
private void WriteUInt16(ushort value)
|
||||
{
|
||||
str.WriteByte((byte)value);
|
||||
str.WriteByte((byte)(value >> 8));
|
||||
}
|
||||
|
||||
private void WriteInt32(int value)
|
||||
{
|
||||
str.WriteByte((byte)(value >> 0));
|
||||
str.WriteByte((byte)(value >> 8));
|
||||
str.WriteByte((byte)(value >> 16));
|
||||
str.WriteByte((byte)(value >> 24));
|
||||
}
|
||||
|
||||
private void WriteFixedArg(Type type, object value)
|
||||
{
|
||||
if (type.IsArray)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
WriteInt32(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Array array = (Array)value;
|
||||
Type elemType = type.GetElementType();
|
||||
WriteInt32(array.Length);
|
||||
foreach (object val in array)
|
||||
{
|
||||
WriteElem(elemType, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteElem(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteElem(Type type, object value)
|
||||
{
|
||||
if (type == typeof(string))
|
||||
{
|
||||
WriteString((string)value);
|
||||
}
|
||||
else if (type == typeof(Type))
|
||||
{
|
||||
WriteTypeName((Type)value);
|
||||
}
|
||||
else if (type == typeof(object))
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
type = typeof(string);
|
||||
}
|
||||
else if (value is Type)
|
||||
{
|
||||
// value.GetType() would return a RuntimeType, but we don't want to deal with that
|
||||
type = typeof(Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = value.GetType();
|
||||
}
|
||||
WriteFieldOrPropType(type);
|
||||
WriteElem(type, value);
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
WriteInt32(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Array array = (Array)value;
|
||||
Type elemType = type.GetElementType();
|
||||
WriteInt32(array.Length);
|
||||
foreach (object val in array)
|
||||
{
|
||||
WriteElem(elemType, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
WriteElem(Enum.GetUnderlyingType(type), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
str.WriteByte((bool)value ? (byte)1 : (byte)0);
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
WriteUInt16((char)value);
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
str.WriteByte((byte)(sbyte)value);
|
||||
break;
|
||||
case TypeCode.Byte:
|
||||
str.WriteByte((byte)value);
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
WriteUInt16((ushort)(short)value);
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
WriteUInt16((ushort)value);
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
WriteInt32((int)value);
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
WriteInt32((int)(uint)value);
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
WriteInt64((long)value);
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
WriteInt64((long)(ulong)value);
|
||||
break;
|
||||
case TypeCode.Single:
|
||||
WriteSingle((float)value);
|
||||
break;
|
||||
case TypeCode.Double:
|
||||
WriteDouble((double)value);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteInt64(long value)
|
||||
{
|
||||
WriteInt32((int)value);
|
||||
WriteInt32((int)(value >> 32));
|
||||
}
|
||||
|
||||
private void WriteSingle(float value)
|
||||
{
|
||||
str.Write(BitConverter.GetBytes(value), 0, 4);
|
||||
}
|
||||
|
||||
private void WriteDouble(double value)
|
||||
{
|
||||
WriteInt64(BitConverter.DoubleToInt64Bits(value));
|
||||
}
|
||||
|
||||
private void WriteTypeName(Type type)
|
||||
{
|
||||
string name = null;
|
||||
if (type != null)
|
||||
{
|
||||
// we could also use just the FullName for mscorlib types (IkvmAssembly.GetAssembly(type) == IkvmAssembly.GetAssembly(typeof(object)))
|
||||
if (IkvmAssembly.GetAssembly(type) == moduleBuilder.Assembly)
|
||||
{
|
||||
name = type.FullName;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = type.AssemblyQualifiedName;
|
||||
}
|
||||
}
|
||||
WriteString(name);
|
||||
}
|
||||
|
||||
private void WriteString(string val)
|
||||
{
|
||||
if (val == null)
|
||||
{
|
||||
str.WriteByte(0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] buf = System.Text.Encoding.UTF8.GetBytes(val);
|
||||
WritePackedLen(buf.Length);
|
||||
str.Write(buf, 0, buf.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private void WritePackedLen(int len)
|
||||
{
|
||||
if (len < 0 || len > 0x1FFFFFFF)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
if (len <= 0x7F)
|
||||
str.WriteByte((byte)len);
|
||||
else if (len <= 0x3FFF)
|
||||
{
|
||||
str.WriteByte((byte)(0x80 | (len >> 8)));
|
||||
str.WriteByte((byte)len);
|
||||
}
|
||||
else
|
||||
{
|
||||
str.WriteByte((byte)(0xC0 | (len >> 24)));
|
||||
str.WriteByte((byte)(len >> 16));
|
||||
str.WriteByte((byte)(len >> 8));
|
||||
str.WriteByte((byte)len);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteFieldOrPropType(Type type)
|
||||
{
|
||||
if (type == typeof(Type))
|
||||
{
|
||||
str.WriteByte(0x50);
|
||||
}
|
||||
else if (type == typeof(object))
|
||||
{
|
||||
str.WriteByte(0x51);
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
str.WriteByte(0x1D);
|
||||
WriteFieldOrPropType(type.GetElementType());
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
str.WriteByte(0x55);
|
||||
WriteTypeName(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
str.WriteByte(0x02);
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
str.WriteByte(0x03);
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
str.WriteByte(0x04);
|
||||
break;
|
||||
case TypeCode.Byte:
|
||||
str.WriteByte(0x05);
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
str.WriteByte(0x06);
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
str.WriteByte(0x07);
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
str.WriteByte(0x08);
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
str.WriteByte(0x09);
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
str.WriteByte(0x0A);
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
str.WriteByte(0x0B);
|
||||
break;
|
||||
case TypeCode.Single:
|
||||
str.WriteByte(0x0C);
|
||||
break;
|
||||
case TypeCode.Double:
|
||||
str.WriteByte(0x0D);
|
||||
break;
|
||||
case TypeCode.String:
|
||||
str.WriteByte(0x0E);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsPseudoCustomAttribute
|
||||
{
|
||||
get
|
||||
{
|
||||
Type type = con.DeclaringType;
|
||||
return type == typeof(AssemblyFlagsAttribute)
|
||||
|| type == typeof(AssemblyAlgorithmIdAttribute)
|
||||
|| type == typeof(DllImportAttribute)
|
||||
|| type == typeof(FieldOffsetAttribute)
|
||||
|| type == typeof(InAttribute)
|
||||
|| type == typeof(MarshalAsAttribute)
|
||||
|| type == typeof(MethodImplAttribute)
|
||||
|| type == typeof(OutAttribute)
|
||||
|| type == typeof(StructLayoutAttribute)
|
||||
|| type == typeof(NonSerializedAttribute)
|
||||
|| type == typeof(SerializableAttribute)
|
||||
|| type == typeof(OptionalAttribute)
|
||||
|| type == typeof(PreserveSigAttribute)
|
||||
|| type == typeof(AssemblyVersionAttribute)
|
||||
|| type == typeof(ComImportAttribute)
|
||||
|| type == typeof(DefaultParameterValueAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
internal ConstructorInfo Constructor
|
||||
{
|
||||
get { return con; }
|
||||
}
|
||||
|
||||
internal int WriteBlob(ModuleBuilder moduleBuilder)
|
||||
{
|
||||
BlobWriter bw = new BlobWriter(moduleBuilder, this);
|
||||
return moduleBuilder.Blobs.Add(ByteBuffer.Wrap(bw.GetBlob()));
|
||||
}
|
||||
|
||||
internal bool IsBlob
|
||||
{
|
||||
get { return blob != null; }
|
||||
}
|
||||
|
||||
internal object GetConstructorArgument(int pos)
|
||||
{
|
||||
return constructorArgs[pos];
|
||||
}
|
||||
|
||||
internal object GetFieldValue(string name)
|
||||
{
|
||||
if (namedFields != null)
|
||||
{
|
||||
for (int i = 0; i < namedFields.Length; i++)
|
||||
{
|
||||
if (namedFields[i].Name == name)
|
||||
{
|
||||
return fieldValues[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public enum AssemblyBuilderAccess
|
||||
{
|
||||
Save = 2,
|
||||
ReflectionOnly = 6,
|
||||
}
|
||||
|
||||
public enum OperandType
|
||||
{
|
||||
InlineBrTarget = 0,
|
||||
InlineField = 1,
|
||||
InlineI = 2,
|
||||
InlineI8 = 3,
|
||||
InlineMethod = 4,
|
||||
InlineNone = 5,
|
||||
InlinePhi = 6,
|
||||
InlineR = 7,
|
||||
InlineSig = 9,
|
||||
InlineString = 10,
|
||||
InlineSwitch = 11,
|
||||
InlineTok = 12,
|
||||
InlineType = 13,
|
||||
InlineVar = 14,
|
||||
ShortInlineBrTarget = 15,
|
||||
ShortInlineI = 16,
|
||||
ShortInlineR = 17,
|
||||
ShortInlineVar = 18,
|
||||
}
|
||||
|
||||
public enum FlowControl
|
||||
{
|
||||
Branch = 0,
|
||||
Break = 1,
|
||||
Call = 2,
|
||||
Cond_Branch = 3,
|
||||
Meta = 4,
|
||||
Next = 5,
|
||||
Return = 7,
|
||||
Throw = 8,
|
||||
}
|
||||
|
||||
public enum PackingSize
|
||||
{
|
||||
Unspecified = 0,
|
||||
Size1 = 1,
|
||||
}
|
||||
|
||||
public enum PEFileKinds
|
||||
{
|
||||
Dll = 1,
|
||||
ConsoleApplication = 2,
|
||||
WindowApplication = 3,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public sealed class FieldBuilder : FieldInfo
|
||||
{
|
||||
private readonly TypeBuilder typeBuilder;
|
||||
private readonly string name;
|
||||
private readonly int pseudoToken;
|
||||
private FieldAttributes attribs;
|
||||
private readonly int nameIndex;
|
||||
private readonly int signature;
|
||||
private readonly Type fieldType;
|
||||
private readonly Type[] requiredCustomModifiers;
|
||||
private readonly Type[] optionalCustomModifiers;
|
||||
|
||||
internal FieldBuilder(TypeBuilder type, string name, Type fieldType, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attribs)
|
||||
{
|
||||
this.typeBuilder = type;
|
||||
this.name = name;
|
||||
this.pseudoToken = type.ModuleBuilder.AllocPseudoToken();
|
||||
this.nameIndex = type.ModuleBuilder.Strings.Add(name);
|
||||
this.fieldType = fieldType;
|
||||
ByteBuffer sig = new ByteBuffer(5);
|
||||
SignatureHelper.WriteFieldSig(this.typeBuilder.ModuleBuilder, sig, fieldType, requiredCustomModifiers, optionalCustomModifiers);
|
||||
this.signature = this.typeBuilder.ModuleBuilder.Blobs.Add(sig);
|
||||
this.attribs = attribs;
|
||||
this.typeBuilder.ModuleBuilder.Tables.Field.AddRow();
|
||||
this.requiredCustomModifiers = MethodBuilder.Copy(requiredCustomModifiers);
|
||||
this.optionalCustomModifiers = MethodBuilder.Copy(optionalCustomModifiers);
|
||||
}
|
||||
|
||||
public void SetConstant(object defaultValue)
|
||||
{
|
||||
attribs |= FieldAttributes.HasDefault;
|
||||
this.ModuleBuilder.AddConstant(pseudoToken, defaultValue);
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
if (customBuilder.Constructor.DeclaringType == typeof(FieldOffsetAttribute))
|
||||
{
|
||||
TableHeap.FieldLayoutTable.Record rec = new TableHeap.FieldLayoutTable.Record();
|
||||
rec.Offset = (int)customBuilder.GetConstructorArgument(0);
|
||||
rec.Field = pseudoToken;
|
||||
this.ModuleBuilder.Tables.FieldLayout.AddRecord(rec);
|
||||
}
|
||||
else if (customBuilder.Constructor.DeclaringType == typeof(MarshalAsAttribute))
|
||||
{
|
||||
TableHeap.FieldMarshalTable.Record rec = new TableHeap.FieldMarshalTable.Record();
|
||||
rec.Parent = pseudoToken;
|
||||
rec.NativeType = WriteMarshallingDescriptor(this.ModuleBuilder, customBuilder);
|
||||
this.ModuleBuilder.Tables.FieldMarshal.AddRecord(rec);
|
||||
attribs |= FieldAttributes.HasFieldMarshal;
|
||||
}
|
||||
else if (customBuilder.Constructor.DeclaringType == typeof(NonSerializedAttribute))
|
||||
{
|
||||
attribs |= FieldAttributes.NotSerialized;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
internal static int WriteMarshallingDescriptor(ModuleBuilder moduleBuiler, CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
UnmanagedType nativeType;
|
||||
object val = customBuilder.GetConstructorArgument(0);
|
||||
if (val is short)
|
||||
{
|
||||
nativeType = (UnmanagedType)(short)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
nativeType = (UnmanagedType)val;
|
||||
}
|
||||
|
||||
ByteBuffer bb = new ByteBuffer(5);
|
||||
bb.Write((byte)nativeType);
|
||||
|
||||
object arraySubType = customBuilder.GetFieldValue("ArraySubType");
|
||||
if (arraySubType != null)
|
||||
{
|
||||
bb.Write((byte)(UnmanagedType)arraySubType);
|
||||
}
|
||||
object sizeParamIndex = customBuilder.GetFieldValue("SizeParamIndex");
|
||||
if (sizeParamIndex != null)
|
||||
{
|
||||
bb.WriteCompressedInt((short)sizeParamIndex + 1);
|
||||
}
|
||||
object sizeConst = customBuilder.GetFieldValue("SizeConst");
|
||||
if (sizeConst != null)
|
||||
{
|
||||
if (sizeParamIndex == null)
|
||||
{
|
||||
bb.WriteCompressedInt(0);
|
||||
}
|
||||
bb.WriteCompressedInt((int)sizeConst);
|
||||
}
|
||||
|
||||
if (customBuilder.GetFieldValue("IidParameterIndex") != null
|
||||
|| customBuilder.GetFieldValue("MarshalCookie") != null
|
||||
|| customBuilder.GetFieldValue("MarshalType") != null
|
||||
|| customBuilder.GetFieldValue("MarshalTypeRef") != null
|
||||
|| customBuilder.GetFieldValue("SafeArraySubType") != null
|
||||
|| customBuilder.GetFieldValue("SafeArrayUserDefinedSubType") != null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
return moduleBuiler.Blobs.Add(bb);
|
||||
}
|
||||
|
||||
public override FieldAttributes Attributes
|
||||
{
|
||||
get { return attribs; }
|
||||
}
|
||||
|
||||
public override RuntimeFieldHandle FieldHandle
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override Type FieldType
|
||||
{
|
||||
get { return fieldType; }
|
||||
}
|
||||
|
||||
public override object GetValue(object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Type DeclaringType
|
||||
{
|
||||
get { return this.ModuleBuilder.IsModuleType(typeBuilder) ? null : typeBuilder; }
|
||||
}
|
||||
|
||||
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object[] GetCustomAttributes(bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool IsDefined(Type attributeType, bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
public override Type ReflectedType
|
||||
{
|
||||
get { return this.DeclaringType; }
|
||||
}
|
||||
|
||||
public override int MetadataToken
|
||||
{
|
||||
get { return pseudoToken; }
|
||||
}
|
||||
|
||||
internal void WriteFieldRecords(MetadataWriter mw)
|
||||
{
|
||||
mw.Write((short)attribs);
|
||||
mw.WriteStringIndex(nameIndex);
|
||||
mw.WriteBlobIndex(signature);
|
||||
}
|
||||
|
||||
internal void FixupToken(int token)
|
||||
{
|
||||
typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
|
||||
}
|
||||
|
||||
internal ModuleBuilder ModuleBuilder
|
||||
{
|
||||
get { return typeBuilder.ModuleBuilder; }
|
||||
}
|
||||
|
||||
internal int ImportTo(ModuleBuilder other)
|
||||
{
|
||||
return other.ImportField(typeBuilder, name, fieldType, optionalCustomModifiers, requiredCustomModifiers);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{3949055D-38DF-4A8F-A632-0F0E62337428}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>IKVM.Reflection.Emit</RootNamespace>
|
||||
<AssemblyName>IKVM.Reflection.Emit</AssemblyName>
|
||||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="ISymWrapper" />
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\CommonAssemblyInfo.cs" />
|
||||
<Compile Include="AssemblyBuilder.cs" />
|
||||
<Compile Include="Enums.cs" />
|
||||
<Compile Include="ConstructorBuilder.cs" />
|
||||
<Compile Include="CustomAttributeBuilder.cs" />
|
||||
<Compile Include="FieldBuilder.cs" />
|
||||
<Compile Include="IkvmAssembly.cs" />
|
||||
<Compile Include="ILGenerator.cs" />
|
||||
<Compile Include="Impl\CryptoConvert.cs" />
|
||||
<Compile Include="Impl\CryptoHack.cs" />
|
||||
<Compile Include="Impl\ITypeOwner.cs" />
|
||||
<Compile Include="Impl\PdbSupport.cs" />
|
||||
<Compile Include="Impl\TypeBase.cs" />
|
||||
<Compile Include="MethodBuilder.cs" />
|
||||
<Compile Include="ModuleBuilder.cs" />
|
||||
<Compile Include="OpCodes.cs" />
|
||||
<Compile Include="ParameterBuilder.cs" />
|
||||
<Compile Include="Tokens.cs" />
|
||||
<Compile Include="Writer\ModuleWriter.cs" />
|
||||
<Compile Include="Writer\PEWriter.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="PropertyBuilder.cs" />
|
||||
<Compile Include="SignatureHelper.cs" />
|
||||
<Compile Include="TypeBuilder.cs" />
|
||||
<Compile Include="Writer\ByteBuffer.cs" />
|
||||
<Compile Include="Writer\TextSection.cs" />
|
||||
<Compile Include="Writer\Heaps.cs" />
|
||||
<Compile Include="Writer\MetadataWriter.cs" />
|
||||
<Compile Include="Writer\VersionInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using IKVM.Reflection.Emit.Impl;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public abstract class IkvmAssembly
|
||||
{
|
||||
private static readonly Dictionary<Assembly, IkvmAssembly> assemblies = new Dictionary<Assembly, IkvmAssembly>();
|
||||
|
||||
internal IkvmAssembly() { }
|
||||
|
||||
private class AssemblyWrapper : IkvmAssembly
|
||||
{
|
||||
private readonly Assembly asm;
|
||||
|
||||
internal AssemblyWrapper(Assembly asm)
|
||||
{
|
||||
this.asm = asm;
|
||||
}
|
||||
|
||||
public override Type GetType(string typeName)
|
||||
{
|
||||
return asm.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public static IkvmAssembly GetAssembly(Type type)
|
||||
{
|
||||
TypeBase tb = type as TypeBase;
|
||||
if (tb != null)
|
||||
{
|
||||
return tb.ModuleBuilder.Assembly;
|
||||
}
|
||||
IkvmAssembly ikvmAssembly;
|
||||
if (!assemblies.TryGetValue(type.Assembly, out ikvmAssembly))
|
||||
{
|
||||
ikvmAssembly = new AssemblyWrapper(type.Assembly);
|
||||
assemblies.Add(type.Assembly, ikvmAssembly);
|
||||
}
|
||||
return ikvmAssembly;
|
||||
}
|
||||
|
||||
public abstract Type GetType(string typeName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,743 @@
|
|||
//
|
||||
// CryptoConvert.cs - Crypto Convertion Routines
|
||||
//
|
||||
// Author:
|
||||
// Sebastien Pouliot <sebastien@ximian.com>
|
||||
//
|
||||
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
|
||||
// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// [JF-20081013] begin modifications for IKVM
|
||||
#define INSIDE_CORLIB
|
||||
// end modifications for IKVM
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Mono.Security.Cryptography {
|
||||
|
||||
#if INSIDE_CORLIB
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
sealed class CryptoConvert {
|
||||
|
||||
private CryptoConvert ()
|
||||
{
|
||||
}
|
||||
|
||||
static private int ToInt32LE (byte [] bytes, int offset)
|
||||
{
|
||||
return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset];
|
||||
}
|
||||
|
||||
static private uint ToUInt32LE (byte [] bytes, int offset)
|
||||
{
|
||||
return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
|
||||
}
|
||||
|
||||
static private byte [] GetBytesLE (int val)
|
||||
{
|
||||
return new byte [] {
|
||||
(byte) (val & 0xff),
|
||||
(byte) ((val >> 8) & 0xff),
|
||||
(byte) ((val >> 16) & 0xff),
|
||||
(byte) ((val >> 24) & 0xff)
|
||||
};
|
||||
}
|
||||
|
||||
static private byte[] Trim (byte[] array)
|
||||
{
|
||||
for (int i=0; i < array.Length; i++) {
|
||||
if (array [i] != 0x00) {
|
||||
byte[] result = new byte [array.Length - i];
|
||||
Buffer.BlockCopy (array, i, result, 0, result.Length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// convert the key from PRIVATEKEYBLOB to RSA
|
||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/private_key_blobs.asp
|
||||
// e.g. SNK files, PVK files
|
||||
static public RSA FromCapiPrivateKeyBlob (byte[] blob)
|
||||
{
|
||||
return FromCapiPrivateKeyBlob (blob, 0);
|
||||
}
|
||||
|
||||
static public RSA FromCapiPrivateKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
RSAParameters rsap = new RSAParameters ();
|
||||
try {
|
||||
if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
|
||||
(blob [offset+1] != 0x02) || // Version (0x02)
|
||||
(blob [offset+2] != 0x00) || // Reserved (word)
|
||||
(blob [offset+3] != 0x00) ||
|
||||
(ToUInt32LE (blob, offset+8) != 0x32415352)) // DWORD magic = RSA2
|
||||
throw new CryptographicException ("Invalid blob header");
|
||||
|
||||
// ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
|
||||
// int algId = ToInt32LE (blob, offset+4);
|
||||
|
||||
// DWORD bitlen
|
||||
int bitLen = ToInt32LE (blob, offset+12);
|
||||
|
||||
// DWORD public exponent
|
||||
byte[] exp = new byte [4];
|
||||
Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
|
||||
Array.Reverse (exp);
|
||||
rsap.Exponent = Trim (exp);
|
||||
|
||||
int pos = offset+20;
|
||||
// BYTE modulus[rsapubkey.bitlen/8];
|
||||
int byteLen = (bitLen >> 3);
|
||||
rsap.Modulus = new byte [byteLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
|
||||
Array.Reverse (rsap.Modulus);
|
||||
pos += byteLen;
|
||||
|
||||
// BYTE prime1[rsapubkey.bitlen/16];
|
||||
int byteHalfLen = (byteLen >> 1);
|
||||
rsap.P = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.P);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// BYTE prime2[rsapubkey.bitlen/16];
|
||||
rsap.Q = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.Q);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// BYTE exponent1[rsapubkey.bitlen/16];
|
||||
rsap.DP = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.DP);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// BYTE exponent2[rsapubkey.bitlen/16];
|
||||
rsap.DQ = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.DQ);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// BYTE coefficient[rsapubkey.bitlen/16];
|
||||
rsap.InverseQ = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.InverseQ);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// ok, this is hackish but CryptoAPI support it so...
|
||||
// note: only works because CRT is used by default
|
||||
// http://bugzilla.ximian.com/show_bug.cgi?id=57941
|
||||
rsap.D = new byte [byteLen]; // must be allocated
|
||||
if (pos + byteLen + offset <= blob.Length) {
|
||||
// BYTE privateExponent[rsapubkey.bitlen/8];
|
||||
Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
|
||||
Array.Reverse (rsap.D);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
|
||||
RSA rsa = null;
|
||||
try {
|
||||
rsa = RSA.Create ();
|
||||
rsa.ImportParameters (rsap);
|
||||
}
|
||||
catch (CryptographicException ce) {
|
||||
// this may cause problem when this code is run under
|
||||
// the SYSTEM identity on Windows (e.g. ASP.NET). See
|
||||
// http://bugzilla.ximian.com/show_bug.cgi?id=77559
|
||||
try {
|
||||
CspParameters csp = new CspParameters ();
|
||||
csp.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
rsa = new RSACryptoServiceProvider (csp);
|
||||
rsa.ImportParameters (rsap);
|
||||
}
|
||||
catch {
|
||||
// rethrow original, not the later, exception if this fails
|
||||
throw ce;
|
||||
}
|
||||
}
|
||||
return rsa;
|
||||
}
|
||||
|
||||
static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob)
|
||||
{
|
||||
return FromCapiPrivateKeyBlobDSA (blob, 0);
|
||||
}
|
||||
|
||||
static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
DSAParameters dsap = new DSAParameters ();
|
||||
try {
|
||||
if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
|
||||
(blob [offset + 1] != 0x02) || // Version (0x02)
|
||||
(blob [offset + 2] != 0x00) || // Reserved (word)
|
||||
(blob [offset + 3] != 0x00) ||
|
||||
(ToUInt32LE (blob, offset + 8) != 0x32535344)) // DWORD magic
|
||||
throw new CryptographicException ("Invalid blob header");
|
||||
|
||||
int bitlen = ToInt32LE (blob, offset + 12);
|
||||
int bytelen = bitlen >> 3;
|
||||
int pos = offset + 16;
|
||||
|
||||
dsap.P = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
|
||||
Array.Reverse (dsap.P);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.Q = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
|
||||
Array.Reverse (dsap.Q);
|
||||
pos += 20;
|
||||
|
||||
dsap.G = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
|
||||
Array.Reverse (dsap.G);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.X = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.X, 0, 20);
|
||||
Array.Reverse (dsap.X);
|
||||
pos += 20;
|
||||
|
||||
dsap.Counter = ToInt32LE (blob, pos);
|
||||
pos += 4;
|
||||
|
||||
dsap.Seed = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
|
||||
Array.Reverse (dsap.Seed);
|
||||
pos += 20;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
|
||||
DSA dsa = null;
|
||||
try {
|
||||
dsa = (DSA)DSA.Create ();
|
||||
dsa.ImportParameters (dsap);
|
||||
}
|
||||
catch (CryptographicException ce) {
|
||||
// this may cause problem when this code is run under
|
||||
// the SYSTEM identity on Windows (e.g. ASP.NET). See
|
||||
// http://bugzilla.ximian.com/show_bug.cgi?id=77559
|
||||
try {
|
||||
CspParameters csp = new CspParameters ();
|
||||
csp.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
dsa = new DSACryptoServiceProvider (csp);
|
||||
dsa.ImportParameters (dsap);
|
||||
}
|
||||
catch {
|
||||
// rethrow original, not the later, exception if this fails
|
||||
throw ce;
|
||||
}
|
||||
}
|
||||
return dsa;
|
||||
}
|
||||
|
||||
static public byte[] ToCapiPrivateKeyBlob (RSA rsa)
|
||||
{
|
||||
RSAParameters p = rsa.ExportParameters (true);
|
||||
int keyLength = p.Modulus.Length; // in bytes
|
||||
byte[] blob = new byte [20 + (keyLength << 2) + (keyLength >> 1)];
|
||||
|
||||
blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
|
||||
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
|
||||
// [2], [3] // RESERVED - Always 0
|
||||
blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
|
||||
blob [8] = 0x52; // Magic - RSA2 (ASCII in hex)
|
||||
blob [9] = 0x53;
|
||||
blob [10] = 0x41;
|
||||
blob [11] = 0x32;
|
||||
|
||||
byte[] bitlen = GetBytesLE (keyLength << 3);
|
||||
blob [12] = bitlen [0]; // bitlen
|
||||
blob [13] = bitlen [1];
|
||||
blob [14] = bitlen [2];
|
||||
blob [15] = bitlen [3];
|
||||
|
||||
// public exponent (DWORD)
|
||||
int pos = 16;
|
||||
int n = p.Exponent.Length;
|
||||
while (n > 0)
|
||||
blob [pos++] = p.Exponent [--n];
|
||||
// modulus
|
||||
pos = 20;
|
||||
byte[] part = p.Modulus;
|
||||
int len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
// private key
|
||||
part = p.P;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.Q;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.DP;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.DQ;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.InverseQ;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.D;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
static public byte[] ToCapiPrivateKeyBlob (DSA dsa)
|
||||
{
|
||||
DSAParameters p = dsa.ExportParameters (true);
|
||||
int keyLength = p.P.Length; // in bytes
|
||||
|
||||
// header + P + Q + G + X + count + seed
|
||||
byte[] blob = new byte [16 + keyLength + 20 + keyLength + 20 + 4 + 20];
|
||||
|
||||
blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
|
||||
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
|
||||
// [2], [3] // RESERVED - Always 0
|
||||
blob [5] = 0x22; // ALGID
|
||||
blob [8] = 0x44; // Magic
|
||||
blob [9] = 0x53;
|
||||
blob [10] = 0x53;
|
||||
blob [11] = 0x32;
|
||||
|
||||
byte[] bitlen = GetBytesLE (keyLength << 3);
|
||||
blob [12] = bitlen [0];
|
||||
blob [13] = bitlen [1];
|
||||
blob [14] = bitlen [2];
|
||||
blob [15] = bitlen [3];
|
||||
|
||||
int pos = 16;
|
||||
byte[] part = p.P;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
part = p.Q;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
pos += 20;
|
||||
|
||||
part = p.G;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
part = p.X;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
pos += 20;
|
||||
|
||||
Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
|
||||
pos += 4;
|
||||
|
||||
part = p.Seed;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
static public RSA FromCapiPublicKeyBlob (byte[] blob)
|
||||
{
|
||||
return FromCapiPublicKeyBlob (blob, 0);
|
||||
}
|
||||
|
||||
static public RSA FromCapiPublicKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
try {
|
||||
if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
|
||||
(blob [offset+1] != 0x02) || // Version (0x02)
|
||||
(blob [offset+2] != 0x00) || // Reserved (word)
|
||||
(blob [offset+3] != 0x00) ||
|
||||
(ToUInt32LE (blob, offset+8) != 0x31415352)) // DWORD magic = RSA1
|
||||
throw new CryptographicException ("Invalid blob header");
|
||||
|
||||
// ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
|
||||
// int algId = ToInt32LE (blob, offset+4);
|
||||
|
||||
// DWORD bitlen
|
||||
int bitLen = ToInt32LE (blob, offset+12);
|
||||
|
||||
// DWORD public exponent
|
||||
RSAParameters rsap = new RSAParameters ();
|
||||
rsap.Exponent = new byte [3];
|
||||
rsap.Exponent [0] = blob [offset+18];
|
||||
rsap.Exponent [1] = blob [offset+17];
|
||||
rsap.Exponent [2] = blob [offset+16];
|
||||
|
||||
int pos = offset+20;
|
||||
// BYTE modulus[rsapubkey.bitlen/8];
|
||||
int byteLen = (bitLen >> 3);
|
||||
rsap.Modulus = new byte [byteLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
|
||||
Array.Reverse (rsap.Modulus);
|
||||
|
||||
RSA rsa = null;
|
||||
try {
|
||||
rsa = RSA.Create ();
|
||||
rsa.ImportParameters (rsap);
|
||||
}
|
||||
catch (CryptographicException) {
|
||||
// this may cause problem when this code is run under
|
||||
// the SYSTEM identity on Windows (e.g. ASP.NET). See
|
||||
// http://bugzilla.ximian.com/show_bug.cgi?id=77559
|
||||
CspParameters csp = new CspParameters ();
|
||||
csp.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
rsa = new RSACryptoServiceProvider (csp);
|
||||
rsa.ImportParameters (rsap);
|
||||
}
|
||||
return rsa;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static public DSA FromCapiPublicKeyBlobDSA (byte[] blob)
|
||||
{
|
||||
return FromCapiPublicKeyBlobDSA (blob, 0);
|
||||
}
|
||||
|
||||
static public DSA FromCapiPublicKeyBlobDSA (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
try {
|
||||
if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
|
||||
(blob [offset + 1] != 0x02) || // Version (0x02)
|
||||
(blob [offset + 2] != 0x00) || // Reserved (word)
|
||||
(blob [offset + 3] != 0x00) ||
|
||||
(ToUInt32LE (blob, offset + 8) != 0x31535344)) // DWORD magic
|
||||
throw new CryptographicException ("Invalid blob header");
|
||||
|
||||
int bitlen = ToInt32LE (blob, offset + 12);
|
||||
DSAParameters dsap = new DSAParameters ();
|
||||
int bytelen = bitlen >> 3;
|
||||
int pos = offset + 16;
|
||||
|
||||
dsap.P = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
|
||||
Array.Reverse (dsap.P);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.Q = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
|
||||
Array.Reverse (dsap.Q);
|
||||
pos += 20;
|
||||
|
||||
dsap.G = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
|
||||
Array.Reverse (dsap.G);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.Y = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Y, 0, bytelen);
|
||||
Array.Reverse (dsap.Y);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.Counter = ToInt32LE (blob, pos);
|
||||
pos += 4;
|
||||
|
||||
dsap.Seed = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
|
||||
Array.Reverse (dsap.Seed);
|
||||
pos += 20;
|
||||
|
||||
DSA dsa = (DSA)DSA.Create ();
|
||||
dsa.ImportParameters (dsap);
|
||||
return dsa;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static public byte[] ToCapiPublicKeyBlob (RSA rsa)
|
||||
{
|
||||
RSAParameters p = rsa.ExportParameters (false);
|
||||
int keyLength = p.Modulus.Length; // in bytes
|
||||
byte[] blob = new byte [20 + keyLength];
|
||||
|
||||
blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
|
||||
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
|
||||
// [2], [3] // RESERVED - Always 0
|
||||
blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
|
||||
blob [8] = 0x52; // Magic - RSA1 (ASCII in hex)
|
||||
blob [9] = 0x53;
|
||||
blob [10] = 0x41;
|
||||
blob [11] = 0x31;
|
||||
|
||||
byte[] bitlen = GetBytesLE (keyLength << 3);
|
||||
blob [12] = bitlen [0]; // bitlen
|
||||
blob [13] = bitlen [1];
|
||||
blob [14] = bitlen [2];
|
||||
blob [15] = bitlen [3];
|
||||
|
||||
// public exponent (DWORD)
|
||||
int pos = 16;
|
||||
int n = p.Exponent.Length;
|
||||
while (n > 0)
|
||||
blob [pos++] = p.Exponent [--n];
|
||||
// modulus
|
||||
pos = 20;
|
||||
byte[] part = p.Modulus;
|
||||
int len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
return blob;
|
||||
}
|
||||
|
||||
static public byte[] ToCapiPublicKeyBlob (DSA dsa)
|
||||
{
|
||||
DSAParameters p = dsa.ExportParameters (false);
|
||||
int keyLength = p.P.Length; // in bytes
|
||||
|
||||
// header + P + Q + G + Y + count + seed
|
||||
byte[] blob = new byte [16 + keyLength + 20 + keyLength + keyLength + 4 + 20];
|
||||
|
||||
blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
|
||||
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
|
||||
// [2], [3] // RESERVED - Always 0
|
||||
blob [5] = 0x22; // ALGID
|
||||
blob [8] = 0x44; // Magic
|
||||
blob [9] = 0x53;
|
||||
blob [10] = 0x53;
|
||||
blob [11] = 0x31;
|
||||
|
||||
byte[] bitlen = GetBytesLE (keyLength << 3);
|
||||
blob [12] = bitlen [0];
|
||||
blob [13] = bitlen [1];
|
||||
blob [14] = bitlen [2];
|
||||
blob [15] = bitlen [3];
|
||||
|
||||
int pos = 16;
|
||||
byte[] part;
|
||||
|
||||
part = p.P;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
part = p.Q;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
pos += 20;
|
||||
|
||||
part = p.G;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
part = p.Y;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
|
||||
pos += 4;
|
||||
|
||||
part = p.Seed;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
// PRIVATEKEYBLOB
|
||||
// PUBLICKEYBLOB
|
||||
static public RSA FromCapiKeyBlob (byte[] blob)
|
||||
{
|
||||
return FromCapiKeyBlob (blob, 0);
|
||||
}
|
||||
|
||||
static public RSA FromCapiKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
switch (blob [offset]) {
|
||||
case 0x00:
|
||||
// this could be a public key inside an header
|
||||
// like "sn -e" would produce
|
||||
if (blob [offset + 12] == 0x06) {
|
||||
return FromCapiPublicKeyBlob (blob, offset + 12);
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
return FromCapiPublicKeyBlob (blob, offset);
|
||||
case 0x07:
|
||||
return FromCapiPrivateKeyBlob (blob, offset);
|
||||
}
|
||||
throw new CryptographicException ("Unknown blob format.");
|
||||
}
|
||||
|
||||
static public DSA FromCapiKeyBlobDSA (byte[] blob)
|
||||
{
|
||||
return FromCapiKeyBlobDSA (blob, 0);
|
||||
}
|
||||
|
||||
static public DSA FromCapiKeyBlobDSA (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
switch (blob [offset]) {
|
||||
case 0x06:
|
||||
return FromCapiPublicKeyBlobDSA (blob, offset);
|
||||
case 0x07:
|
||||
return FromCapiPrivateKeyBlobDSA (blob, offset);
|
||||
}
|
||||
throw new CryptographicException ("Unknown blob format.");
|
||||
}
|
||||
|
||||
static public byte[] ToCapiKeyBlob (AsymmetricAlgorithm keypair, bool includePrivateKey)
|
||||
{
|
||||
if (keypair == null)
|
||||
throw new ArgumentNullException ("keypair");
|
||||
|
||||
// check between RSA and DSA (and potentially others like DH)
|
||||
if (keypair is RSA)
|
||||
return ToCapiKeyBlob ((RSA)keypair, includePrivateKey);
|
||||
else if (keypair is DSA)
|
||||
return ToCapiKeyBlob ((DSA)keypair, includePrivateKey);
|
||||
else
|
||||
return null; // TODO
|
||||
}
|
||||
|
||||
static public byte[] ToCapiKeyBlob (RSA rsa, bool includePrivateKey)
|
||||
{
|
||||
if (rsa == null)
|
||||
throw new ArgumentNullException ("rsa");
|
||||
|
||||
if (includePrivateKey)
|
||||
return ToCapiPrivateKeyBlob (rsa);
|
||||
else
|
||||
return ToCapiPublicKeyBlob (rsa);
|
||||
}
|
||||
|
||||
static public byte[] ToCapiKeyBlob (DSA dsa, bool includePrivateKey)
|
||||
{
|
||||
if (dsa == null)
|
||||
throw new ArgumentNullException ("dsa");
|
||||
|
||||
if (includePrivateKey)
|
||||
return ToCapiPrivateKeyBlob (dsa);
|
||||
else
|
||||
return ToCapiPublicKeyBlob (dsa);
|
||||
}
|
||||
|
||||
static public string ToHex (byte[] input)
|
||||
{
|
||||
if (input == null)
|
||||
return null;
|
||||
|
||||
StringBuilder sb = new StringBuilder (input.Length * 2);
|
||||
foreach (byte b in input) {
|
||||
sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture));
|
||||
}
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
static private byte FromHexChar (char c)
|
||||
{
|
||||
if ((c >= 'a') && (c <= 'f'))
|
||||
return (byte) (c - 'a' + 10);
|
||||
if ((c >= 'A') && (c <= 'F'))
|
||||
return (byte) (c - 'A' + 10);
|
||||
if ((c >= '0') && (c <= '9'))
|
||||
return (byte) (c - '0');
|
||||
throw new ArgumentException ("invalid hex char");
|
||||
}
|
||||
|
||||
static public byte[] FromHex (string hex)
|
||||
{
|
||||
if (hex == null)
|
||||
return null;
|
||||
if ((hex.Length & 0x1) == 0x1)
|
||||
throw new ArgumentException ("Length must be a multiple of 2");
|
||||
|
||||
byte[] result = new byte [hex.Length >> 1];
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
while (n < result.Length) {
|
||||
result [n] = (byte) (FromHexChar (hex [i++]) << 4);
|
||||
result [n++] += FromHexChar (hex [i++]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Impl
|
||||
{
|
||||
static class CryptoHack
|
||||
{
|
||||
internal static RSA CreateRSA(StrongNameKeyPair keyPair)
|
||||
{
|
||||
// HACK use serialization to get at the private key or key container name,
|
||||
// this should be more future proof than using reflection to access the fields directly.
|
||||
SerializationInfo ser = new SerializationInfo(typeof(StrongNameKeyPair), new FormatterConverter());
|
||||
((ISerializable)keyPair).GetObjectData(ser, new StreamingContext());
|
||||
byte[] key = (byte[])ser.GetValue("_keyPairArray", typeof(byte[]));
|
||||
string keycontainer = ser.GetString("_keyPairContainer");
|
||||
if (keycontainer != null)
|
||||
{
|
||||
CspParameters parm = new CspParameters();
|
||||
parm.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
parm.KeyContainerName = keycontainer;
|
||||
parm.KeyNumber = 2; // Signature
|
||||
return new RSACryptoServiceProvider(parm);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Mono.Security.Cryptography.CryptoConvert.FromCapiKeyBlob(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
|
||||
namespace IKVM.Reflection.Emit.Impl
|
||||
{
|
||||
interface ITypeOwner
|
||||
{
|
||||
ModuleBuilder ModuleBuilder { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics.SymbolStore;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Impl
|
||||
{
|
||||
static class PdbSupport
|
||||
{
|
||||
[Guid("809c652e-7396-11d2-9771-00a0c9b4d50c")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[CoClass(typeof(MetaDataDispenserClass))]
|
||||
[ComImport]
|
||||
private interface IMetaDataDispenser
|
||||
{
|
||||
void DefineScope(
|
||||
[In] ref Guid rclsid,
|
||||
[In] int dwCreateFlags,
|
||||
[In] ref Guid riid,
|
||||
[Out, MarshalAs(UnmanagedType.IUnknown)] out object punk);
|
||||
}
|
||||
|
||||
[Guid("e5cb7a31-7512-11d2-89ce-0080c792e5d8")]
|
||||
[ComImport]
|
||||
private class MetaDataDispenserClass { }
|
||||
|
||||
[Guid("7dac8207-d3ae-4c75-9b67-92801a497d44")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[ComImport]
|
||||
private interface IMetadataImport { }
|
||||
|
||||
[Guid("ba3fee4c-ecb9-4e41-83b7-183fa41cd859")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[ComImport]
|
||||
private interface IMetaDataEmit { }
|
||||
|
||||
[Guid("ed14aa72-78e2-4884-84e2-334293ae5214")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[ComImport]
|
||||
[CoClass(typeof(CorSymWriterClass))]
|
||||
private interface ISymUnmanagedWriter
|
||||
{
|
||||
void PlaceHolder_DefineDocument();
|
||||
void PlaceHolder_SetUserEntryPoint();
|
||||
void PlaceHolder_OpenMethod();
|
||||
void PlaceHolder_CloseMethod();
|
||||
void PlaceHolder_OpenScope();
|
||||
void PlaceHolder_CloseScope();
|
||||
void PlaceHolder_SetScopeRange();
|
||||
void PlaceHolder_DefineLocalVariable();
|
||||
void PlaceHolder_DefineParameter();
|
||||
void PlaceHolder_DefineField();
|
||||
void PlaceHolder_DefineGlobalVariable();
|
||||
void PlaceHolder_Close();
|
||||
void PlaceHolder_SetSymAttribute();
|
||||
void PlaceHolder_OpenNamespace();
|
||||
void PlaceHolder_CloseNamespace();
|
||||
void PlaceHolder_UsingNamespace();
|
||||
void PlaceHolder_SetMethodSourceRange();
|
||||
void PlaceHolder_Initialize();
|
||||
|
||||
void GetDebugInfo(
|
||||
[In, Out] ref IMAGE_DEBUG_DIRECTORY pIDD,
|
||||
[In] uint cData,
|
||||
[Out] out uint pcData,
|
||||
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] data);
|
||||
|
||||
void PlaceHolder_DefineSequencePoints();
|
||||
|
||||
void RemapToken(
|
||||
[In] int oldToken,
|
||||
[In] int newToken);
|
||||
}
|
||||
|
||||
[Guid("108296c1-281e-11d3-bd22-0000f80849bd")]
|
||||
[ComImport]
|
||||
private class CorSymWriterClass { }
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct IMAGE_DEBUG_DIRECTORY
|
||||
{
|
||||
internal uint Characteristics;
|
||||
internal uint TimeDateStamp;
|
||||
internal ushort MajorVersion;
|
||||
internal ushort MinorVersion;
|
||||
internal uint Type;
|
||||
internal uint SizeOfData;
|
||||
internal uint AddressOfRawData;
|
||||
internal uint PointerToRawData;
|
||||
}
|
||||
|
||||
private sealed class MySymWriter : SymWriter
|
||||
{
|
||||
private readonly IntPtr ppISymUnmanagedWriter = Marshal.AllocHGlobal(IntPtr.Size);
|
||||
private readonly ISymUnmanagedWriter symUnmanagedWriter = new ISymUnmanagedWriter();
|
||||
private readonly IntPtr pISymUnmanagedWriter;
|
||||
|
||||
internal MySymWriter(string fileName)
|
||||
{
|
||||
pISymUnmanagedWriter = Marshal.GetComInterfaceForObject(symUnmanagedWriter, typeof(ISymUnmanagedWriter));
|
||||
Marshal.WriteIntPtr(ppISymUnmanagedWriter, pISymUnmanagedWriter);
|
||||
SetUnderlyingWriter(ppISymUnmanagedWriter);
|
||||
IMetaDataDispenser disp = new IMetaDataDispenser();
|
||||
object emitter;
|
||||
Guid CLSID_CorMetaDataRuntime = new Guid("005023ca-72b1-11d3-9fc4-00c04f79a0a3");
|
||||
Guid IID_IMetaDataEmit = typeof(IMetaDataEmit).GUID;
|
||||
disp.DefineScope(ref CLSID_CorMetaDataRuntime, 0, ref IID_IMetaDataEmit, out emitter);
|
||||
IntPtr emitterPtr = Marshal.GetComInterfaceForObject(emitter, typeof(IMetaDataEmit));
|
||||
try
|
||||
{
|
||||
Initialize(emitterPtr, fileName, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.Release(emitterPtr);
|
||||
}
|
||||
Marshal.ReleaseComObject(disp);
|
||||
Marshal.ReleaseComObject(emitter);
|
||||
}
|
||||
|
||||
~MySymWriter()
|
||||
{
|
||||
Marshal.Release(pISymUnmanagedWriter);
|
||||
Marshal.FreeHGlobal(ppISymUnmanagedWriter);
|
||||
}
|
||||
|
||||
internal byte[] GetDebugInfo(ref IMAGE_DEBUG_DIRECTORY idd)
|
||||
{
|
||||
uint cData;
|
||||
symUnmanagedWriter.GetDebugInfo(ref idd, 0, out cData, null);
|
||||
byte[] buf = new byte[cData];
|
||||
symUnmanagedWriter.GetDebugInfo(ref idd, (uint)buf.Length, out cData, buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
internal void RemapToken(int oldToken, int newToken)
|
||||
{
|
||||
symUnmanagedWriter.RemapToken(oldToken, newToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static ISymbolWriter CreateSymbolWriter(string fileName)
|
||||
{
|
||||
return new MySymWriter(fileName);
|
||||
}
|
||||
|
||||
internal static byte[] GetDebugInfo(ISymbolWriter writer, ref IMAGE_DEBUG_DIRECTORY idd)
|
||||
{
|
||||
return ((MySymWriter)writer).GetDebugInfo(ref idd);
|
||||
}
|
||||
|
||||
internal static void RemapToken(ISymbolWriter writer, int oldToken, int newToken)
|
||||
{
|
||||
((MySymWriter)writer).RemapToken(oldToken, newToken);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Impl
|
||||
{
|
||||
public abstract class TypeBase : Type
|
||||
{
|
||||
public sealed override Assembly Assembly
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public abstract override string AssemblyQualifiedName
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract override Type BaseType
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract override string FullName
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public sealed override Guid GUID
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
protected abstract override TypeAttributes GetAttributeFlagsImpl();
|
||||
|
||||
protected sealed override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override Type GetElementType()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public sealed override EventInfo GetEvent(string name, BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override EventInfo[] GetEvents(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override FieldInfo GetField(string name, BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override FieldInfo[] GetFields(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override Type GetInterface(string name, bool ignoreCase)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override Type[] GetInterfaces()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override MemberInfo[] GetMembers(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected abstract override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers);
|
||||
|
||||
public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override Type GetNestedType(string name, BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override Type[] GetNestedTypes(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected sealed override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected abstract override bool HasElementTypeImpl();
|
||||
|
||||
public sealed override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected abstract override bool IsArrayImpl();
|
||||
|
||||
protected abstract override bool IsByRefImpl();
|
||||
|
||||
protected sealed override bool IsCOMObjectImpl()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected sealed override bool IsPointerImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected sealed override bool IsPrimitiveImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public sealed override Module Module
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override Type UnderlyingSystemType
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
public override Type DeclaringType
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override object[] GetCustomAttributes(bool inherit)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public sealed override bool IsDefined(Type attributeType, bool inherit)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
string fullname = FullName;
|
||||
return fullname.Substring(fullname.LastIndexOf('.') + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed override string Namespace
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsNested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string fullname = FullName;
|
||||
int index = fullname.LastIndexOf('.');
|
||||
return index < 0 ? null : fullname.Substring(0, index);
|
||||
}
|
||||
}
|
||||
|
||||
public override Type MakeArrayType()
|
||||
{
|
||||
return ArrayType.Make(this);
|
||||
}
|
||||
|
||||
internal abstract ModuleBuilder ModuleBuilder { get; }
|
||||
|
||||
internal abstract TypeToken GetToken();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,524 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Diagnostics.SymbolStore;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public sealed class MethodBuilder : MethodInfo
|
||||
{
|
||||
private readonly TypeBuilder typeBuilder;
|
||||
private readonly string name;
|
||||
private readonly int nameIndex;
|
||||
private readonly int signature;
|
||||
private readonly int pseudoToken;
|
||||
private readonly Type returnType;
|
||||
private readonly Type[] parameterTypes;
|
||||
private readonly Type[][] requiredCustomModifiers; // last element is for the return type
|
||||
private readonly Type[][] optionalCustomModifiers;
|
||||
private MethodAttributes attributes;
|
||||
private MethodImplAttributes implFlags;
|
||||
private ILGenerator ilgen;
|
||||
private int rva;
|
||||
private List<ParameterBuilder> parameters;
|
||||
|
||||
internal MethodBuilder(TypeBuilder typeBuilder, string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
|
||||
{
|
||||
this.typeBuilder = typeBuilder;
|
||||
this.name = name;
|
||||
this.pseudoToken = typeBuilder.ModuleBuilder.AllocPseudoToken();
|
||||
this.nameIndex = typeBuilder.ModuleBuilder.Strings.Add(name);
|
||||
this.attributes = attributes;
|
||||
this.returnType = returnType ?? typeof(void);
|
||||
this.parameterTypes = Copy(parameterTypes);
|
||||
if ((attributes & MethodAttributes.Static) == 0)
|
||||
{
|
||||
callingConvention |= CallingConventions.HasThis;
|
||||
}
|
||||
ByteBuffer signature = new ByteBuffer(16);
|
||||
SignatureHelper.WriteMethodSig(this.ModuleBuilder, signature, callingConvention, returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers, parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers);
|
||||
this.signature = this.ModuleBuilder.Blobs.Add(signature);
|
||||
requiredCustomModifiers = PackCustomModifiers(returnTypeRequiredCustomModifiers, parameterTypeRequiredCustomModifiers, this.parameterTypes.Length);
|
||||
optionalCustomModifiers = PackCustomModifiers(returnTypeOptionalCustomModifiers, parameterTypeOptionalCustomModifiers, this.parameterTypes.Length);
|
||||
}
|
||||
|
||||
internal static Type[] Copy(Type[] array)
|
||||
{
|
||||
if (array == null || array.Length == 0)
|
||||
{
|
||||
return Type.EmptyTypes;
|
||||
}
|
||||
Type[] newArray = new Type[array.Length];
|
||||
Array.Copy(array, newArray, array.Length);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
private static Type[][] PackCustomModifiers(Type[] returnTypeCustomModifiers, Type[][] parameterTypeCustomModifiers, int parameterCount)
|
||||
{
|
||||
if (returnTypeCustomModifiers == null && parameterTypeCustomModifiers == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Type[][] newArray = new Type[parameterCount + 1][];
|
||||
newArray[parameterCount] = Copy(returnTypeCustomModifiers);
|
||||
if (parameterTypeCustomModifiers != null)
|
||||
{
|
||||
for (int i = 0; i < parameterCount; i++)
|
||||
{
|
||||
newArray[i] = Copy(parameterTypeCustomModifiers[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < parameterCount; i++)
|
||||
{
|
||||
newArray[i] = Type.EmptyTypes;
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
public ILGenerator GetILGenerator()
|
||||
{
|
||||
if (ilgen == null)
|
||||
{
|
||||
ilgen = new ILGenerator(typeBuilder.ModuleBuilder);
|
||||
}
|
||||
return ilgen;
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
|
||||
{
|
||||
SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
|
||||
}
|
||||
|
||||
private void SetDllImportPseudoCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
if (customBuilder.IsBlob)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
const short NoMangle = 0x0001;
|
||||
const short CharSetMask = 0x0006;
|
||||
const short CharSetNotSpec = 0x0000;
|
||||
const short CharSetAnsi = 0x0002;
|
||||
const short CharSetUnicode = 0x0004;
|
||||
const short CharSetAuto = 0x0006;
|
||||
const short SupportsLastError = 0x0040;
|
||||
const short CallConvMask = 0x0700;
|
||||
const short CallConvWinapi = 0x0100;
|
||||
const short CallConvCdecl = 0x0200;
|
||||
const short CallConvStdcall = 0x0300;
|
||||
const short CallConvThiscall = 0x0400;
|
||||
const short CallConvFastcall = 0x0500;
|
||||
// non-standard flags
|
||||
const short BestFitOn = 0x0010;
|
||||
const short BestFitOff = 0x0020;
|
||||
const short CharMapErrorOn = 0x1000;
|
||||
const short CharMapErrorOff = 0x2000;
|
||||
int name = this.nameIndex;
|
||||
short flags = CharSetNotSpec | CallConvWinapi;
|
||||
bool? bestFitMapping = (bool?)customBuilder.GetFieldValue("BestFitMapping");
|
||||
if (bestFitMapping.HasValue)
|
||||
{
|
||||
flags |= bestFitMapping.Value ? BestFitOn : BestFitOff;
|
||||
}
|
||||
bool? throwOnUnmappableChar = (bool?)customBuilder.GetFieldValue("ThrowOnUnmappableChar");
|
||||
if (throwOnUnmappableChar.HasValue)
|
||||
{
|
||||
flags |= throwOnUnmappableChar.Value ? CharMapErrorOn : CharMapErrorOff;
|
||||
}
|
||||
CallingConvention? callingConvention = (CallingConvention?)customBuilder.GetFieldValue("CallingConvention");
|
||||
if (callingConvention.HasValue)
|
||||
{
|
||||
flags &= ~CallConvMask;
|
||||
switch (callingConvention.Value)
|
||||
{
|
||||
case System.Runtime.InteropServices.CallingConvention.Cdecl:
|
||||
flags |= CallConvCdecl;
|
||||
break;
|
||||
case System.Runtime.InteropServices.CallingConvention.FastCall:
|
||||
flags |= CallConvFastcall;
|
||||
break;
|
||||
case System.Runtime.InteropServices.CallingConvention.StdCall:
|
||||
flags |= CallConvStdcall;
|
||||
break;
|
||||
case System.Runtime.InteropServices.CallingConvention.ThisCall:
|
||||
flags |= CallConvThiscall;
|
||||
break;
|
||||
case System.Runtime.InteropServices.CallingConvention.Winapi:
|
||||
flags |= CallConvWinapi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CharSet? charSet = (CharSet?)customBuilder.GetFieldValue("CharSet");
|
||||
if (charSet.HasValue)
|
||||
{
|
||||
flags &= ~CharSetMask;
|
||||
switch (charSet.Value)
|
||||
{
|
||||
case CharSet.Ansi:
|
||||
case CharSet.None:
|
||||
flags |= CharSetAnsi;
|
||||
break;
|
||||
case CharSet.Auto:
|
||||
flags |= CharSetAuto;
|
||||
break;
|
||||
case CharSet.Unicode:
|
||||
flags |= CharSetUnicode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
string entryPoint = (string)customBuilder.GetFieldValue("EntryPoint");
|
||||
if (entryPoint != null)
|
||||
{
|
||||
name = this.ModuleBuilder.Strings.Add(entryPoint);
|
||||
}
|
||||
bool? exactSpelling = (bool?)customBuilder.GetFieldValue("ExactSpelling");
|
||||
if (exactSpelling.HasValue && exactSpelling.Value)
|
||||
{
|
||||
flags |= NoMangle;
|
||||
}
|
||||
bool? preserveSig = (bool?)customBuilder.GetFieldValue("PreserveSig");
|
||||
if (!preserveSig.HasValue || preserveSig.Value)
|
||||
{
|
||||
implFlags |= MethodImplAttributes.PreserveSig;
|
||||
}
|
||||
bool? setLastError = (bool?)customBuilder.GetFieldValue("SetLastError");
|
||||
if (setLastError.HasValue && setLastError.Value)
|
||||
{
|
||||
flags |= SupportsLastError;
|
||||
}
|
||||
TableHeap.ImplMapTable.Record rec = new TableHeap.ImplMapTable.Record();
|
||||
rec.MappingFlags = flags;
|
||||
rec.MemberForwarded = pseudoToken;
|
||||
rec.ImportName = name;
|
||||
rec.ImportScope = this.ModuleBuilder.Tables.ModuleRef.Add(this.ModuleBuilder.Strings.Add((string)customBuilder.GetConstructorArgument(0)));
|
||||
this.ModuleBuilder.Tables.ImplMap.AddRecord(rec);
|
||||
}
|
||||
|
||||
private void SetMethodImplAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
MethodImplOptions opt;
|
||||
switch (customBuilder.Constructor.GetParameters().Length)
|
||||
{
|
||||
case 0:
|
||||
opt = 0;
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
object val = customBuilder.GetConstructorArgument(0);
|
||||
if (val is short)
|
||||
{
|
||||
opt = (MethodImplOptions)(short)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
opt = (MethodImplOptions)val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
MethodCodeType? type = (MethodCodeType?)customBuilder.GetFieldValue("MethodCodeType");
|
||||
implFlags = (MethodImplAttributes)opt;
|
||||
if (type.HasValue)
|
||||
{
|
||||
implFlags |= (MethodImplAttributes)type;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
if (customBuilder.Constructor.DeclaringType == typeof(DllImportAttribute))
|
||||
{
|
||||
SetDllImportPseudoCustomAttribute(customBuilder);
|
||||
}
|
||||
else if (customBuilder.Constructor.DeclaringType == typeof(MethodImplAttribute))
|
||||
{
|
||||
SetMethodImplAttribute(customBuilder);
|
||||
}
|
||||
else if (customBuilder.Constructor.DeclaringType == typeof(PreserveSigAttribute))
|
||||
{
|
||||
implFlags |= MethodImplAttributes.PreserveSig;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
|
||||
{
|
||||
TableHeap.DeclSecurityTable.Record rec = new TableHeap.DeclSecurityTable.Record();
|
||||
rec.Action = (short)securityAction;
|
||||
rec.Parent = pseudoToken;
|
||||
// like Ref.Emit, we're using the .NET 1.x xml format
|
||||
rec.PermissionSet = this.ModuleBuilder.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString())));
|
||||
this.ModuleBuilder.Tables.DeclSecurity.AddRecord(rec);
|
||||
this.attributes |= MethodAttributes.HasSecurity;
|
||||
}
|
||||
|
||||
public void SetImplementationFlags(MethodImplAttributes attributes)
|
||||
{
|
||||
implFlags = attributes;
|
||||
}
|
||||
|
||||
public ParameterBuilder DefineParameter(int position, ParameterAttributes attributes, string strParamName)
|
||||
{
|
||||
if (parameters == null)
|
||||
{
|
||||
parameters = new List<ParameterBuilder>();
|
||||
}
|
||||
this.ModuleBuilder.Tables.Param.AddRow();
|
||||
ParameterBuilder pb = new ParameterBuilder(this.ModuleBuilder, position, attributes, strParamName);
|
||||
parameters.Add(pb);
|
||||
return pb;
|
||||
}
|
||||
|
||||
public override MethodInfo GetBaseDefinition()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override Type ReturnType
|
||||
{
|
||||
get { return returnType; }
|
||||
}
|
||||
|
||||
public override ParameterInfo ReturnParameter
|
||||
{
|
||||
get { return new ParameterInfoImpl(this, -1); }
|
||||
}
|
||||
|
||||
public override ICustomAttributeProvider ReturnTypeCustomAttributes
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override MethodAttributes Attributes
|
||||
{
|
||||
get { return attributes; }
|
||||
}
|
||||
|
||||
public override MethodImplAttributes GetMethodImplementationFlags()
|
||||
{
|
||||
return implFlags;
|
||||
}
|
||||
|
||||
private class ParameterInfoImpl : ParameterInfo
|
||||
{
|
||||
private readonly MethodBuilder method;
|
||||
private readonly int parameter;
|
||||
|
||||
internal ParameterInfoImpl(MethodBuilder method, int parameter)
|
||||
{
|
||||
this.method = method;
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public override Type ParameterType
|
||||
{
|
||||
get
|
||||
{
|
||||
return parameter == -1 ? method.returnType : method.parameterTypes[parameter];
|
||||
}
|
||||
}
|
||||
|
||||
public override Type[] GetOptionalCustomModifiers()
|
||||
{
|
||||
if (method.optionalCustomModifiers == null)
|
||||
{
|
||||
return Type.EmptyTypes;
|
||||
}
|
||||
int index = parameter == -1 ? method.optionalCustomModifiers.Length - 1 : parameter;
|
||||
return Copy(method.optionalCustomModifiers[index]);
|
||||
}
|
||||
|
||||
public override Type[] GetRequiredCustomModifiers()
|
||||
{
|
||||
if (method.requiredCustomModifiers == null)
|
||||
{
|
||||
return Type.EmptyTypes;
|
||||
}
|
||||
int index = parameter == -1 ? method.requiredCustomModifiers.Length - 1 : parameter;
|
||||
return Copy(method.requiredCustomModifiers[index]);
|
||||
}
|
||||
}
|
||||
|
||||
public override ParameterInfo[] GetParameters()
|
||||
{
|
||||
ParameterInfo[] parameters = new ParameterInfo[parameterTypes.Length];
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = new ParameterInfoImpl(this, i);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override RuntimeMethodHandle MethodHandle
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override Type DeclaringType
|
||||
{
|
||||
get { return this.ModuleBuilder.IsModuleType(typeBuilder) ? null : typeBuilder; }
|
||||
}
|
||||
|
||||
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object[] GetCustomAttributes(bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool IsDefined(Type attributeType, bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
public override Type ReflectedType
|
||||
{
|
||||
get { return this.DeclaringType; }
|
||||
}
|
||||
|
||||
public override CallingConventions CallingConvention
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override int MetadataToken
|
||||
{
|
||||
get { return pseudoToken; }
|
||||
}
|
||||
|
||||
internal void Bake()
|
||||
{
|
||||
if (ilgen != null)
|
||||
{
|
||||
if (this.ModuleBuilder.symbolWriter != null)
|
||||
{
|
||||
this.ModuleBuilder.symbolWriter.OpenMethod(new SymbolToken(-pseudoToken | 0x06000000));
|
||||
}
|
||||
rva = ilgen.WriteBody();
|
||||
if (this.ModuleBuilder.symbolWriter != null)
|
||||
{
|
||||
this.ModuleBuilder.symbolWriter.CloseMethod();
|
||||
}
|
||||
ilgen = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
rva = -1;
|
||||
}
|
||||
}
|
||||
|
||||
internal ModuleBuilder ModuleBuilder
|
||||
{
|
||||
get { return typeBuilder.ModuleBuilder; }
|
||||
}
|
||||
|
||||
internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList)
|
||||
{
|
||||
if (rva != -1)
|
||||
{
|
||||
mw.Write(rva + baseRVA);
|
||||
}
|
||||
else
|
||||
{
|
||||
mw.Write(0);
|
||||
}
|
||||
mw.Write((short)implFlags);
|
||||
mw.Write((short)attributes);
|
||||
mw.WriteStringIndex(nameIndex);
|
||||
mw.WriteBlobIndex(signature);
|
||||
mw.WriteParam(paramList);
|
||||
if (parameters != null)
|
||||
{
|
||||
paramList += parameters.Count;
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteParamRecords(MetadataWriter mw)
|
||||
{
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (ParameterBuilder pb in parameters)
|
||||
{
|
||||
pb.WriteParamRecord(mw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void FixupToken(int token, ref int parameterToken)
|
||||
{
|
||||
typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (ParameterBuilder pb in parameters)
|
||||
{
|
||||
pb.FixupToken(parameterToken++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool MatchParameters(Type[] types)
|
||||
{
|
||||
if (types.Length == parameterTypes.Length)
|
||||
{
|
||||
for (int i = 0; i < types.Length; i++)
|
||||
{
|
||||
if (!types[i].Equals(parameterTypes[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,911 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.SymbolStore;
|
||||
using IKVM.Reflection.Emit.Impl;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public sealed class ModuleBuilder : ITypeOwner
|
||||
{
|
||||
private readonly AssemblyBuilder asm;
|
||||
internal readonly string moduleName;
|
||||
internal readonly string fileName;
|
||||
internal readonly ISymbolWriter symbolWriter;
|
||||
private readonly TypeBuilder moduleType;
|
||||
private readonly List<TypeBuilder> types = new List<TypeBuilder>();
|
||||
private readonly Dictionary<Type, TypeToken> typeTokens = new Dictionary<Type, TypeToken>();
|
||||
private readonly Dictionary<string, TypeBuilder> fullNameToType = new Dictionary<string, TypeBuilder>();
|
||||
internal readonly ByteBuffer methodBodies = new ByteBuffer(128 * 1024);
|
||||
internal readonly List<int> tokenFixupOffsets = new List<int>();
|
||||
internal readonly ByteBuffer initializedData = new ByteBuffer(512);
|
||||
internal readonly ByteBuffer manifestResources = new ByteBuffer(512);
|
||||
private readonly Dictionary<MemberInfo, int> importedMembers = new Dictionary<MemberInfo, int>();
|
||||
private readonly Dictionary<AssemblyName, int> referencedAssemblies = new Dictionary<AssemblyName, int>(new AssemblyNameEqualityComparer());
|
||||
private readonly Dictionary<Type, Type> canonicalizedTypes = new Dictionary<Type, Type>();
|
||||
private readonly Dictionary<MethodInfo, MethodInfo> canonicalizedGenericMethods = new Dictionary<MethodInfo, MethodInfo>(new GenericMethodComparer());
|
||||
private int nextPseudoToken = -1;
|
||||
private readonly List<int> resolvedTokens = new List<int>();
|
||||
internal readonly TableHeap Tables;
|
||||
internal readonly StringHeap Strings = new StringHeap();
|
||||
internal readonly UserStringHeap UserStrings = new UserStringHeap();
|
||||
internal readonly GuidHeap Guids = new GuidHeap();
|
||||
internal readonly BlobHeap Blobs = new BlobHeap();
|
||||
internal bool bigStrings;
|
||||
internal bool bigGuids;
|
||||
internal bool bigBlobs;
|
||||
internal bool bigField;
|
||||
internal bool bigMethodDef;
|
||||
internal bool bigParam;
|
||||
internal bool bigTypeDef;
|
||||
internal bool bigProperty;
|
||||
internal bool bigGenericParam;
|
||||
internal bool bigModuleRef;
|
||||
internal bool bigResolutionScope;
|
||||
internal bool bigMemberRefParent;
|
||||
internal bool bigMethodDefOrRef;
|
||||
internal bool bigTypeDefOrRef;
|
||||
internal bool bigHasCustomAttribute;
|
||||
internal bool bigCustomAttributeType;
|
||||
internal bool bigHasConstant;
|
||||
internal bool bigHasSemantics;
|
||||
internal bool bigImplementation;
|
||||
internal bool bigTypeOrMethodDef;
|
||||
internal bool bigHasDeclSecurity;
|
||||
internal bool bigMemberForwarded;
|
||||
internal bool bigHasFieldMarshal;
|
||||
|
||||
// FXBUG AssemblyName doesn't have a working Equals (sigh)
|
||||
private sealed class AssemblyNameEqualityComparer : IEqualityComparer<AssemblyName>
|
||||
{
|
||||
public bool Equals(AssemblyName x, AssemblyName y)
|
||||
{
|
||||
return x.FullName == y.FullName;
|
||||
}
|
||||
|
||||
public int GetHashCode(AssemblyName obj)
|
||||
{
|
||||
return obj.FullName.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
// this class makes multiple instances of a generic method compare as equal,
|
||||
// however, it does not ensure that the underlying method definition is canonicalized
|
||||
private sealed class GenericMethodComparer : IEqualityComparer<MethodInfo>
|
||||
{
|
||||
public bool Equals(MethodInfo x, MethodInfo y)
|
||||
{
|
||||
if (x.GetGenericMethodDefinition() == y.GetGenericMethodDefinition())
|
||||
{
|
||||
Type[] xArgs = x.GetGenericArguments();
|
||||
Type[] yArgs = y.GetGenericArguments();
|
||||
for (int i = 0; i < xArgs.Length; i++)
|
||||
{
|
||||
if (xArgs[i] != yArgs[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetHashCode(MethodInfo obj)
|
||||
{
|
||||
int hash = obj.GetGenericMethodDefinition().GetHashCode();
|
||||
foreach (Type arg in obj.GetGenericArguments())
|
||||
{
|
||||
hash *= 37;
|
||||
hash ^= arg.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo)
|
||||
{
|
||||
this.Tables = new TableHeap(this);
|
||||
this.asm = asm;
|
||||
this.moduleName = moduleName;
|
||||
this.fileName = fileName;
|
||||
if (emitSymbolInfo)
|
||||
{
|
||||
symbolWriter = PdbSupport.CreateSymbolWriter(Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".pdb"));
|
||||
}
|
||||
// <Module> must be the first record in the TypeDef table
|
||||
moduleType = new TypeBuilder(this, "<Module>", null, 0);
|
||||
types.Add(moduleType);
|
||||
}
|
||||
|
||||
internal void WriteTypeDefTable(MetadataWriter mw)
|
||||
{
|
||||
int fieldList = 1;
|
||||
int methodList = 1;
|
||||
foreach (TypeBuilder type in types)
|
||||
{
|
||||
type.WriteTypeDefRecord(mw, ref fieldList, ref methodList);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteMethodDefTable(int baseRVA, MetadataWriter mw)
|
||||
{
|
||||
int paramList = 1;
|
||||
foreach (TypeBuilder type in types)
|
||||
{
|
||||
type.WriteMethodDefRecords(baseRVA, mw, ref paramList);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteParamTable(MetadataWriter mw)
|
||||
{
|
||||
foreach (TypeBuilder type in types)
|
||||
{
|
||||
type.WriteParamRecords(mw);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteFieldTable(MetadataWriter mw)
|
||||
{
|
||||
foreach (TypeBuilder type in types)
|
||||
{
|
||||
type.WriteFieldRecords(mw);
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetTypeCount()
|
||||
{
|
||||
return types.Count;
|
||||
}
|
||||
|
||||
internal int AllocPseudoToken()
|
||||
{
|
||||
return nextPseudoToken--;
|
||||
}
|
||||
|
||||
public TypeBuilder DefineType(string name)
|
||||
{
|
||||
return DefineType(name, TypeAttributes.Class);
|
||||
}
|
||||
|
||||
public TypeBuilder DefineType(string name, TypeAttributes attribs)
|
||||
{
|
||||
return DefineType(name, attribs, null);
|
||||
}
|
||||
|
||||
public TypeBuilder DefineType(string name, TypeAttributes attribs, Type baseType)
|
||||
{
|
||||
return DefineType(name, attribs, baseType, PackingSize.Unspecified, 0);
|
||||
}
|
||||
|
||||
public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
|
||||
{
|
||||
if (parent == null && (attr & TypeAttributes.Interface) == 0)
|
||||
{
|
||||
parent = typeof(object);
|
||||
}
|
||||
TypeBuilder typeBuilder = new TypeBuilder(this, name, parent, attr);
|
||||
PostDefineType(typeBuilder, packingSize, typesize);
|
||||
return typeBuilder;
|
||||
}
|
||||
|
||||
internal TypeBuilder DefineNestedTypeHelper(TypeBuilder enclosingType, string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
|
||||
{
|
||||
if (parent == null && (attr & TypeAttributes.Interface) == 0)
|
||||
{
|
||||
parent = typeof(object);
|
||||
}
|
||||
TypeBuilder typeBuilder = new TypeBuilder(enclosingType, name, parent, attr);
|
||||
PostDefineType(typeBuilder, packingSize, typesize);
|
||||
if (enclosingType != null)
|
||||
{
|
||||
TableHeap.NestedClassTable.Record rec = new TableHeap.NestedClassTable.Record();
|
||||
rec.NestedClass = typeBuilder.GetToken().Token;
|
||||
rec.EnclosingClass = enclosingType.GetToken().Token;
|
||||
this.Tables.NestedClass.AddRecord(rec);
|
||||
}
|
||||
return typeBuilder;
|
||||
}
|
||||
|
||||
private void PostDefineType(TypeBuilder typeBuilder, PackingSize packingSize, int typesize)
|
||||
{
|
||||
types.Add(typeBuilder);
|
||||
fullNameToType.Add(typeBuilder.FullName, typeBuilder);
|
||||
if (packingSize != PackingSize.Unspecified || typesize != 0)
|
||||
{
|
||||
TableHeap.ClassLayoutTable.Record rec = new TableHeap.ClassLayoutTable.Record();
|
||||
rec.PackingSize = (short)packingSize;
|
||||
rec.ClassSize = typesize;
|
||||
rec.Parent = typeBuilder.GetToken().Token;
|
||||
this.Tables.ClassLayout.AddRecord(rec);
|
||||
}
|
||||
}
|
||||
|
||||
public FieldBuilder DefineInitializedData(string name, byte[] data, FieldAttributes attributes)
|
||||
{
|
||||
Type fieldType = GetType("$ArrayType$" + data.Length);
|
||||
if (fieldType == null)
|
||||
{
|
||||
fieldType = DefineType("$ArrayType$" + data.Length, TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.ExplicitLayout, typeof(ValueType), PackingSize.Size1, data.Length);
|
||||
}
|
||||
FieldBuilder fb = moduleType.DefineField(name, fieldType, attributes | FieldAttributes.Static | FieldAttributes.HasFieldRVA);
|
||||
TableHeap.FieldRVATable.Record rec = new TableHeap.FieldRVATable.Record();
|
||||
rec.RVA = initializedData.Position;
|
||||
rec.Field = fb.MetadataToken;
|
||||
this.Tables.FieldRVA.AddRecord(rec);
|
||||
initializedData.Write(data);
|
||||
return fb;
|
||||
}
|
||||
|
||||
public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
|
||||
{
|
||||
return moduleType.DefineMethod(name, attributes, returnType, parameterTypes);
|
||||
}
|
||||
|
||||
public void CreateGlobalFunctions()
|
||||
{
|
||||
moduleType.CreateType();
|
||||
}
|
||||
|
||||
public TypeToken GetTypeToken(Type type)
|
||||
{
|
||||
TypeToken token;
|
||||
if (!typeTokens.TryGetValue(type, out token))
|
||||
{
|
||||
token = ImportType(type);
|
||||
typeTokens.Add(type, token);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
SetCustomAttribute(0x00000001, customBuilder);
|
||||
}
|
||||
|
||||
internal void SetCustomAttribute(int token, CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
if (customBuilder.IsPseudoCustomAttribute)
|
||||
{
|
||||
throw new NotImplementedException("Pseudo custom attribute " + customBuilder.Constructor.DeclaringType.FullName + " is not implemented");
|
||||
}
|
||||
TableHeap.CustomAttributeTable.Record rec = new TableHeap.CustomAttributeTable.Record();
|
||||
rec.Parent = token;
|
||||
rec.Type = this.GetConstructorToken(customBuilder.Constructor).Token;
|
||||
rec.Value = customBuilder.WriteBlob(this);
|
||||
this.Tables.CustomAttribute.AddRecord(rec);
|
||||
}
|
||||
|
||||
public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute)
|
||||
{
|
||||
TableHeap.ManifestResourceTable.Record rec = new TableHeap.ManifestResourceTable.Record();
|
||||
rec.Offset = manifestResources.Position;
|
||||
rec.Flags = (int)attribute;
|
||||
rec.Name = this.Strings.Add(name);
|
||||
rec.Implementation = 0;
|
||||
this.Tables.ManifestResource.AddRecord(rec);
|
||||
manifestResources.Write(0); // placeholder for the length
|
||||
manifestResources.Write(stream);
|
||||
int savePosition = manifestResources.Position;
|
||||
manifestResources.Position = rec.Offset;
|
||||
manifestResources.Write(savePosition - (manifestResources.Position + 4));
|
||||
manifestResources.Position = savePosition;
|
||||
}
|
||||
|
||||
public AssemblyBuilder Assembly
|
||||
{
|
||||
get { return asm; }
|
||||
}
|
||||
|
||||
public Type GetType(string className)
|
||||
{
|
||||
return GetType(className, false, false);
|
||||
}
|
||||
|
||||
public Type GetType(string className, bool throwOnError, bool ignoreCase)
|
||||
{
|
||||
if (ignoreCase)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
TypeBuilder type;
|
||||
if (!fullNameToType.TryGetValue(className, out type) && throwOnError)
|
||||
{
|
||||
throw new TypeLoadException();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType)
|
||||
{
|
||||
return symbolWriter.DefineDocument(url, language, languageVendor, documentType);
|
||||
}
|
||||
|
||||
public FieldToken GetFieldToken(FieldInfo field)
|
||||
{
|
||||
FieldBuilder fb = field as FieldBuilder;
|
||||
if (fb != null)
|
||||
{
|
||||
if (fb.ModuleBuilder == this)
|
||||
{
|
||||
return new FieldToken(fb.MetadataToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
int token;
|
||||
if (!importedMembers.TryGetValue(field, out token))
|
||||
{
|
||||
token = fb.ImportTo(this);
|
||||
importedMembers.Add(field, token);
|
||||
}
|
||||
return new FieldToken(token);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new FieldToken(ImportMember(field));
|
||||
}
|
||||
}
|
||||
|
||||
public MethodToken GetMethodToken(MethodInfo method)
|
||||
{
|
||||
MethodBuilder mb = method as MethodBuilder;
|
||||
if (mb != null && mb.ModuleBuilder == this)
|
||||
{
|
||||
return new MethodToken(mb.MetadataToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new MethodToken(ImportMember(method));
|
||||
}
|
||||
}
|
||||
|
||||
public ConstructorToken GetConstructorToken(ConstructorInfo constructor)
|
||||
{
|
||||
ConstructorBuilder cb = constructor as ConstructorBuilder;
|
||||
if (cb != null)
|
||||
{
|
||||
if (cb.ModuleBuilder == this)
|
||||
{
|
||||
return new ConstructorToken(cb.MetadataToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ConstructorToken(ImportMember(constructor));
|
||||
}
|
||||
}
|
||||
|
||||
private int ImportMember(MemberInfo member)
|
||||
{
|
||||
int token;
|
||||
if (!importedMembers.TryGetValue(member, out token))
|
||||
{
|
||||
if (member.DeclaringType == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (member.ReflectedType != member.DeclaringType)
|
||||
{
|
||||
// look up the canonicalized member
|
||||
token = ImportMember(member.Module.ResolveMember(member.MetadataToken));
|
||||
importedMembers.Add(member, token);
|
||||
return token;
|
||||
}
|
||||
|
||||
MethodInfo method = member as MethodInfo;
|
||||
if (method != null)
|
||||
{
|
||||
if (method.IsGenericMethod && !method.IsGenericMethodDefinition)
|
||||
{
|
||||
// FXBUG generic MethodInfos don't have a working Equals/GetHashCode,
|
||||
// so we have to canonicalize them manually
|
||||
// (we don't have to recursively call ImportMember here (like above), because the first method we encounter will always become the canonical one)
|
||||
if (importedMembers.TryGetValue(CanonicalizeGenericMethod(method), out token))
|
||||
{
|
||||
importedMembers.Add(member, token);
|
||||
return token;
|
||||
}
|
||||
|
||||
const byte GENERICINST = 0x0A;
|
||||
ByteBuffer spec = new ByteBuffer(10);
|
||||
spec.Write(GENERICINST);
|
||||
Type[] args = method.GetGenericArguments();
|
||||
spec.WriteCompressedInt(args.Length);
|
||||
foreach (Type arg in args)
|
||||
{
|
||||
SignatureHelper.WriteType(this, spec, arg);
|
||||
}
|
||||
TableHeap.MethodSpecTable.Record rec = new TableHeap.MethodSpecTable.Record();
|
||||
rec.Method = GetMethodToken(method.GetGenericMethodDefinition()).Token;
|
||||
rec.Instantiation = this.Blobs.Add(spec);
|
||||
token = 0x2B000000 | this.Tables.MethodSpec.AddRecord(rec);
|
||||
}
|
||||
else
|
||||
{
|
||||
token = ImportMethodOrConstructorRef(method);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConstructorInfo constructor = member as ConstructorInfo;
|
||||
if (constructor != null)
|
||||
{
|
||||
token = ImportMethodOrConstructorRef(constructor);
|
||||
}
|
||||
else
|
||||
{
|
||||
FieldInfo field = member as FieldInfo;
|
||||
if (field != null)
|
||||
{
|
||||
token = ImportField(field.DeclaringType, field.Name, field.FieldType, field.GetOptionalCustomModifiers(), field.GetRequiredCustomModifiers());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
importedMembers.Add(member, token);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
private int ImportMethodOrConstructorRef(MethodBase method)
|
||||
{
|
||||
if (method.DeclaringType == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
TableHeap.MemberRefTable.Record rec = new TableHeap.MemberRefTable.Record();
|
||||
rec.Class = GetTypeToken(method.DeclaringType).Token;
|
||||
rec.Name = this.Strings.Add(method.Name);
|
||||
ByteBuffer bb = new ByteBuffer(16);
|
||||
SignatureHelper.WriteMethodSig(this, bb, method);
|
||||
rec.Signature = this.Blobs.Add(bb);
|
||||
return 0x0A000000 | this.Tables.MemberRef.AddRecord(rec);
|
||||
}
|
||||
|
||||
internal int ImportField(Type declaringType, string name, Type fieldType, Type[] optionalCustomModifiers, Type[] requiredCustomModifiers)
|
||||
{
|
||||
if (declaringType == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
TableHeap.MemberRefTable.Record rec = new TableHeap.MemberRefTable.Record();
|
||||
rec.Class = GetTypeToken(declaringType).Token;
|
||||
rec.Name = this.Strings.Add(name);
|
||||
ByteBuffer bb = new ByteBuffer(16);
|
||||
bb.Write(SignatureHelper.FIELD);
|
||||
SignatureHelper.WriteCustomModifiers(this, bb, SignatureHelper.ELEMENT_TYPE_CMOD_OPT, optionalCustomModifiers);
|
||||
SignatureHelper.WriteCustomModifiers(this, bb, SignatureHelper.ELEMENT_TYPE_CMOD_REQD, requiredCustomModifiers);
|
||||
SignatureHelper.WriteType(this, bb, fieldType);
|
||||
rec.Signature = this.Blobs.Add(bb);
|
||||
return 0x0A000000 | this.Tables.MemberRef.AddRecord(rec);
|
||||
}
|
||||
|
||||
private TypeToken ImportType(Type type)
|
||||
{
|
||||
if (type.IsPointer || type.IsByRef)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
TypeBase tb = type as TypeBase;
|
||||
if (tb != null)
|
||||
{
|
||||
if (tb.ModuleBuilder == this)
|
||||
{
|
||||
return tb.GetToken();
|
||||
}
|
||||
else if (tb.ModuleBuilder.Assembly != this.Assembly)
|
||||
{
|
||||
return ImportTypeRef(tb.ModuleBuilder.Assembly.GetName(), type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
else if (type.IsArray || (type.IsGenericType && !type.IsGenericTypeDefinition))
|
||||
{
|
||||
ByteBuffer spec = new ByteBuffer(5);
|
||||
SignatureHelper.WriteType(this, spec, type);
|
||||
return new TypeToken(0x1B000000 | this.Tables.TypeSpec.AddRecord(this.Blobs.Add(spec)));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ImportTypeRef(type.Assembly.GetName(), type);
|
||||
}
|
||||
}
|
||||
|
||||
private TypeToken ImportTypeRef(AssemblyName asm, Type type)
|
||||
{
|
||||
TableHeap.TypeRefTable.Record rec = new TableHeap.TypeRefTable.Record();
|
||||
if (type.IsNested)
|
||||
{
|
||||
rec.ResolutionScope = GetTypeToken(type.DeclaringType).Token;
|
||||
rec.TypeName = this.Strings.Add(type.Name);
|
||||
rec.TypeNameSpace = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rec.ResolutionScope = ImportAssemblyRef(asm);
|
||||
rec.TypeName = this.Strings.Add(type.Name);
|
||||
string ns = type.Namespace;
|
||||
rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
|
||||
}
|
||||
return new TypeToken(0x01000000 | this.Tables.TypeRef.AddRecord(rec));
|
||||
}
|
||||
|
||||
private int ImportAssemblyRef(AssemblyName asm)
|
||||
{
|
||||
int token;
|
||||
if (!referencedAssemblies.TryGetValue(asm, out token))
|
||||
{
|
||||
TableHeap.AssemblyRefTable.Record rec = new TableHeap.AssemblyRefTable.Record();
|
||||
Version ver = asm.Version ?? new Version(0, 0, 0, 0);
|
||||
rec.MajorVersion = (short)ver.Major;
|
||||
rec.MinorVersion = (short)ver.Minor;
|
||||
rec.BuildNumber = (short)ver.Build;
|
||||
rec.RevisionNumber = (short)ver.Revision;
|
||||
rec.Flags = 0;
|
||||
byte[] pubkey = asm.GetPublicKeyToken();
|
||||
if (pubkey == null && asm.KeyPair != null)
|
||||
{
|
||||
pubkey = GetPublicKeyToken(asm.KeyPair);
|
||||
}
|
||||
if (pubkey != null)
|
||||
{
|
||||
rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(pubkey));
|
||||
}
|
||||
rec.Name = this.Strings.Add(asm.Name);
|
||||
rec.Culture = 0;
|
||||
rec.HashValue = 0;
|
||||
token = 0x23000000 | this.Tables.AssemblyRef.AddRecord(rec);
|
||||
referencedAssemblies.Add(asm, token);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
private byte[] GetPublicKeyToken(StrongNameKeyPair strongNameKeyPair)
|
||||
{
|
||||
SHA1Managed sha1 = new SHA1Managed();
|
||||
byte[] hash = sha1.ComputeHash(strongNameKeyPair.PublicKey);
|
||||
byte[] token = new byte[8];
|
||||
Buffer.BlockCopy(hash, hash.Length - 8, token, 0, 8);
|
||||
Array.Reverse(token);
|
||||
return token;
|
||||
}
|
||||
|
||||
internal void WriteSymbolTokenMap()
|
||||
{
|
||||
for (int i = 0; i < resolvedTokens.Count; i++)
|
||||
{
|
||||
int newToken = resolvedTokens[i];
|
||||
// The symbol API doesn't support remapping arbitrary integers, the types have to be the same,
|
||||
// so we copy the type from the newToken, because our pseudo tokens don't have a type.
|
||||
// (see MethodToken.SymbolToken)
|
||||
int oldToken = (i + 1) | (newToken & ~0xFFFFFF);
|
||||
PdbSupport.RemapToken(symbolWriter, oldToken, newToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal void RegisterTokenFixup(int pseudoToken, int realToken)
|
||||
{
|
||||
int index = -(pseudoToken + 1);
|
||||
while (resolvedTokens.Count <= index)
|
||||
{
|
||||
resolvedTokens.Add(0);
|
||||
}
|
||||
resolvedTokens[index] = realToken;
|
||||
}
|
||||
|
||||
internal bool IsPseudoToken(int token)
|
||||
{
|
||||
return token < 0;
|
||||
}
|
||||
|
||||
internal int ResolvePseudoToken(int pseudoToken)
|
||||
{
|
||||
int index = -(pseudoToken + 1);
|
||||
return resolvedTokens[index];
|
||||
}
|
||||
|
||||
internal void FixupMethodBodyTokens()
|
||||
{
|
||||
int methodToken = 0x06000001;
|
||||
int fieldToken = 0x04000001;
|
||||
int parameterToken = 0x08000001;
|
||||
foreach (TypeBuilder type in types)
|
||||
{
|
||||
type.ResolveMethodAndFieldTokens(ref methodToken, ref fieldToken, ref parameterToken);
|
||||
}
|
||||
foreach (int offset in tokenFixupOffsets)
|
||||
{
|
||||
methodBodies.Position = offset;
|
||||
int pseudoToken = methodBodies.GetInt32AtCurrentPosition();
|
||||
methodBodies.Write(ResolvePseudoToken(pseudoToken));
|
||||
}
|
||||
}
|
||||
|
||||
internal int MetadataLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Blobs.IsEmpty ? 92 : 108 + Blobs.Length) + Tables.Length + Strings.Length + UserStrings.Length + Guids.Length;
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteMetadata(MetadataWriter mw)
|
||||
{
|
||||
mw.Write(0x424A5342); // Signature ("BSJB")
|
||||
mw.Write((ushort)1); // MajorVersion
|
||||
mw.Write((ushort)1); // MinorVersion
|
||||
mw.Write(0); // Reserved
|
||||
byte[] version = StringToPaddedUTF8("v2.0.50727");
|
||||
mw.Write(version.Length); // Length
|
||||
mw.Write(version);
|
||||
mw.Write((ushort)0); // Flags
|
||||
int offset;
|
||||
// #Blob is the only optional heap
|
||||
if (Blobs.IsEmpty)
|
||||
{
|
||||
mw.Write((ushort)4); // Streams
|
||||
offset = 92;
|
||||
}
|
||||
else
|
||||
{
|
||||
mw.Write((ushort)5); // Streams
|
||||
offset = 108;
|
||||
}
|
||||
|
||||
// Streams
|
||||
mw.Write(offset); // Offset
|
||||
mw.Write(Tables.Length); // Size
|
||||
mw.Write(StringToPaddedUTF8("#~"));
|
||||
offset += Tables.Length;
|
||||
|
||||
mw.Write(offset); // Offset
|
||||
mw.Write(Strings.Length); // Size
|
||||
mw.Write(StringToPaddedUTF8("#Strings"));
|
||||
offset += Strings.Length;
|
||||
|
||||
mw.Write(offset); // Offset
|
||||
mw.Write(UserStrings.Length); // Size
|
||||
mw.Write(StringToPaddedUTF8("#US"));
|
||||
offset += UserStrings.Length;
|
||||
|
||||
mw.Write(offset); // Offset
|
||||
mw.Write(Guids.Length); // Size
|
||||
mw.Write(StringToPaddedUTF8("#GUID"));
|
||||
offset += Guids.Length;
|
||||
|
||||
if (!Blobs.IsEmpty)
|
||||
{
|
||||
mw.Write(offset); // Offset
|
||||
mw.Write(Blobs.Length); // Size
|
||||
mw.Write(StringToPaddedUTF8("#Blob"));
|
||||
}
|
||||
|
||||
Tables.Write(mw);
|
||||
Strings.Write(mw);
|
||||
UserStrings.Write(mw);
|
||||
Guids.Write(mw);
|
||||
if (!Blobs.IsEmpty)
|
||||
{
|
||||
Blobs.Write(mw);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] StringToPaddedUTF8(string str)
|
||||
{
|
||||
byte[] buf = new byte[(System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3];
|
||||
System.Text.Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0);
|
||||
return buf;
|
||||
}
|
||||
|
||||
internal void Freeze()
|
||||
{
|
||||
Strings.Freeze(this);
|
||||
UserStrings.Freeze(this);
|
||||
Guids.Freeze(this);
|
||||
Blobs.Freeze(this);
|
||||
this.bigStrings = Strings.IsBig;
|
||||
this.bigGuids = Guids.IsBig;
|
||||
this.bigBlobs = Blobs.IsBig;
|
||||
this.bigField = Tables.Field.IsBig;
|
||||
this.bigMethodDef = Tables.MethodDef.IsBig;
|
||||
this.bigParam = Tables.Param.IsBig;
|
||||
this.bigTypeDef = Tables.TypeDef.IsBig;
|
||||
this.bigProperty = Tables.Property.IsBig;
|
||||
this.bigGenericParam = Tables.GenericParam.IsBig;
|
||||
this.bigModuleRef = Tables.ModuleRef.IsBig;
|
||||
this.bigResolutionScope = IsBig(2, Tables.Module, Tables.ModuleRef, Tables.AssemblyRef, Tables.TypeRef);
|
||||
this.bigMemberRefParent = IsBig(3, Tables.TypeDef, Tables.TypeRef, Tables.ModuleRef, Tables.MethodDef, Tables.TypeSpec);
|
||||
this.bigMethodDefOrRef = IsBig(1, Tables.MethodDef, Tables.MemberRef);
|
||||
this.bigTypeDefOrRef = IsBig(2, Tables.TypeDef, Tables.TypeRef);
|
||||
this.bigHasCustomAttribute = IsBig(5, Tables.MethodDef, Tables.Field, Tables.TypeDef, Tables.Param, Tables.Module, Tables.Property, Tables.Assembly);
|
||||
this.bigCustomAttributeType = IsBig(3, Tables.MethodDef, Tables.MemberRef);
|
||||
this.bigHasConstant = IsBig(2, Tables.Field, Tables.Param, Tables.Property);
|
||||
this.bigHasSemantics = IsBig(1, /*Tables.Event,*/ Tables.Property);
|
||||
this.bigImplementation = IsBig(2, Tables.File, Tables.AssemblyRef, Tables.ExportedType);
|
||||
this.bigTypeOrMethodDef = IsBig(1, Tables.TypeDef, Tables.MethodDef);
|
||||
this.bigHasDeclSecurity = IsBig(2, Tables.TypeDef, Tables.MethodDef, Tables.Assembly);
|
||||
this.bigMemberForwarded = IsBig(1, Tables.Field, Tables.MethodDef);
|
||||
this.bigHasFieldMarshal = IsBig(1, Tables.Field, Tables.Param);
|
||||
Tables.Freeze(this);
|
||||
}
|
||||
|
||||
private bool IsBig(int bitsUsed, params TableHeap.Table[] tables)
|
||||
{
|
||||
int limit = 1 << (16 - bitsUsed);
|
||||
foreach (TableHeap.Table table in tables)
|
||||
{
|
||||
if (table.RowCount >= limit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal Type CanonicalizeType(Type type)
|
||||
{
|
||||
Type canon;
|
||||
if (!canonicalizedTypes.TryGetValue(type, out canon))
|
||||
{
|
||||
canon = type;
|
||||
canonicalizedTypes.Add(canon, canon);
|
||||
}
|
||||
return canon;
|
||||
}
|
||||
|
||||
private MethodInfo CanonicalizeGenericMethod(MethodInfo method)
|
||||
{
|
||||
MethodInfo canon;
|
||||
if (!canonicalizedGenericMethods.TryGetValue(method, out canon))
|
||||
{
|
||||
canonicalizedGenericMethods.Add(method, method);
|
||||
canon = method;
|
||||
}
|
||||
return canon;
|
||||
}
|
||||
|
||||
internal void ExportTypes(int fileToken, ModuleBuilder manifestModule)
|
||||
{
|
||||
Dictionary<Type, int> declaringTypes = new Dictionary<Type, int>();
|
||||
foreach (TypeBuilder type in types)
|
||||
{
|
||||
if (type != moduleType && IsVisible(type))
|
||||
{
|
||||
TableHeap.ExportedTypeTable.Record rec = new TableHeap.ExportedTypeTable.Record();
|
||||
rec.Flags = (int)type.Attributes;
|
||||
rec.TypeDefId = type.GetToken().Token & 0xFFFFFF;
|
||||
rec.TypeName = manifestModule.Strings.Add(type.Name);
|
||||
rec.TypeNamespace = manifestModule.Strings.Add(type.Namespace);
|
||||
if (type.IsNested)
|
||||
{
|
||||
rec.Implementation = declaringTypes[type.DeclaringType];
|
||||
}
|
||||
else
|
||||
{
|
||||
rec.Implementation = fileToken;
|
||||
}
|
||||
int exportTypeToken = 0x27000000 | manifestModule.Tables.ExportedType.AddRecord(rec);
|
||||
declaringTypes.Add(type, exportTypeToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsVisible(Type type)
|
||||
{
|
||||
return type.IsPublic || ((type.IsNestedFamily || type.IsNestedFamORAssem || type.IsNestedPublic) && IsVisible(type.DeclaringType));
|
||||
}
|
||||
|
||||
internal void AddConstant(int parentToken, object defaultValue)
|
||||
{
|
||||
TableHeap.ConstantTable.Record rec = new TableHeap.ConstantTable.Record();
|
||||
rec.Parent = parentToken;
|
||||
ByteBuffer val = new ByteBuffer(16);
|
||||
if (defaultValue == null)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_CLASS;
|
||||
}
|
||||
else if (defaultValue is bool)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_BOOLEAN;
|
||||
val.Write((bool)defaultValue ? (byte)1 : (byte)0);
|
||||
}
|
||||
else if (defaultValue is char)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_CHAR;
|
||||
val.Write((char)defaultValue);
|
||||
}
|
||||
else if (defaultValue is byte)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_U1;
|
||||
val.Write((byte)defaultValue);
|
||||
}
|
||||
else if (defaultValue is short)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_I2;
|
||||
val.Write((short)defaultValue);
|
||||
}
|
||||
else if (defaultValue is int)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_I4;
|
||||
val.Write((int)defaultValue);
|
||||
}
|
||||
else if (defaultValue is long)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_I8;
|
||||
val.Write((long)defaultValue);
|
||||
}
|
||||
else if (defaultValue is float)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_R4;
|
||||
val.Write((float)defaultValue);
|
||||
}
|
||||
else if (defaultValue is double)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_R8;
|
||||
val.Write((double)defaultValue);
|
||||
}
|
||||
else if (defaultValue is string)
|
||||
{
|
||||
rec.Type = SignatureHelper.ELEMENT_TYPE_STRING;
|
||||
foreach (char c in (string)defaultValue)
|
||||
{
|
||||
val.Write(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(defaultValue.GetType().FullName);
|
||||
}
|
||||
rec.Value = this.Blobs.Add(val);
|
||||
this.Tables.Constant.AddRecord(rec);
|
||||
}
|
||||
|
||||
internal bool IsModuleType(TypeBuilder type)
|
||||
{
|
||||
return type == moduleType;
|
||||
}
|
||||
|
||||
ModuleBuilder ITypeOwner.ModuleBuilder
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public struct OpCode
|
||||
{
|
||||
private const int OperandTypeCount = 19;
|
||||
private const int FlowControlCount = 9;
|
||||
private const int StackDiffCount = 5;
|
||||
private readonly short value;
|
||||
private readonly short info;
|
||||
|
||||
internal OpCode(short value, OperandType operandType, FlowControl flowControl, short stackDiff)
|
||||
{
|
||||
Debug.Assert(operandType >= 0 && (int)operandType < OperandTypeCount);
|
||||
Debug.Assert(flowControl >= 0 && (int)flowControl < FlowControlCount);
|
||||
Debug.Assert(stackDiff >= -3 && stackDiff <= 1);
|
||||
|
||||
this.value = value;
|
||||
this.info = (short)(operandType
|
||||
+ OperandTypeCount * (short)flowControl
|
||||
+ OperandTypeCount * FlowControlCount * (stackDiff + 3));
|
||||
|
||||
Debug.Assert(this.OperandType == operandType);
|
||||
Debug.Assert(this.FlowControl == flowControl);
|
||||
Debug.Assert(this.StackDiff == stackDiff);
|
||||
}
|
||||
|
||||
public short Value
|
||||
{
|
||||
get { return value; }
|
||||
}
|
||||
|
||||
public int Size
|
||||
{
|
||||
get { return value < 0 ? 2 : 1; }
|
||||
}
|
||||
|
||||
public OperandType OperandType
|
||||
{
|
||||
get { return (OperandType)(info % OperandTypeCount); }
|
||||
}
|
||||
|
||||
public FlowControl FlowControl
|
||||
{
|
||||
get { return (FlowControl)((info / OperandTypeCount) % FlowControlCount); }
|
||||
}
|
||||
|
||||
internal short StackDiff
|
||||
{
|
||||
get { return (short)(((info / (OperandTypeCount * FlowControlCount)) % StackDiffCount) - 3); }
|
||||
}
|
||||
}
|
||||
|
||||
public class OpCodes
|
||||
{
|
||||
public static readonly OpCode Nop = new OpCode(0, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Break = new OpCode(1, OperandType.InlineNone, FlowControl.Break, 0);
|
||||
public static readonly OpCode Ldarg_0 = new OpCode(2, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldarg_1 = new OpCode(3, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldarg_2 = new OpCode(4, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldarg_3 = new OpCode(5, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldloc_0 = new OpCode(6, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldloc_1 = new OpCode(7, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldloc_2 = new OpCode(8, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldloc_3 = new OpCode(9, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Stloc_0 = new OpCode(10, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Stloc_1 = new OpCode(11, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Stloc_2 = new OpCode(12, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Stloc_3 = new OpCode(13, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldarg_S = new OpCode(14, OperandType.ShortInlineVar, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldarga_S = new OpCode(15, OperandType.ShortInlineVar, FlowControl.Next, 1);
|
||||
public static readonly OpCode Starg_S = new OpCode(16, OperandType.ShortInlineVar, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldloc_S = new OpCode(17, OperandType.ShortInlineVar, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldloca_S = new OpCode(18, OperandType.ShortInlineVar, FlowControl.Next, 1);
|
||||
public static readonly OpCode Stloc_S = new OpCode(19, OperandType.ShortInlineVar, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldnull = new OpCode(20, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_M1 = new OpCode(21, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_0 = new OpCode(22, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_1 = new OpCode(23, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_2 = new OpCode(24, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_3 = new OpCode(25, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_4 = new OpCode(26, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_5 = new OpCode(27, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_6 = new OpCode(28, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_7 = new OpCode(29, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_8 = new OpCode(30, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4_S = new OpCode(31, OperandType.ShortInlineI, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I4 = new OpCode(32, OperandType.InlineI, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_I8 = new OpCode(33, OperandType.InlineI8, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_R4 = new OpCode(34, OperandType.ShortInlineR, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldc_R8 = new OpCode(35, OperandType.InlineR, FlowControl.Next, 1);
|
||||
public static readonly OpCode Dup = new OpCode(37, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Pop = new OpCode(38, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Jmp = new OpCode(39, OperandType.InlineMethod, FlowControl.Call, 0);
|
||||
public static readonly OpCode Call = new OpCode(40, OperandType.InlineMethod, FlowControl.Call, 0);
|
||||
public static readonly OpCode Calli = new OpCode(41, OperandType.InlineSig, FlowControl.Call, 0);
|
||||
public static readonly OpCode Ret = new OpCode(42, OperandType.InlineNone, FlowControl.Return, 0);
|
||||
public static readonly OpCode Br_S = new OpCode(43, OperandType.ShortInlineBrTarget, FlowControl.Branch, 0);
|
||||
public static readonly OpCode Brfalse_S = new OpCode(44, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -1);
|
||||
public static readonly OpCode Brtrue_S = new OpCode(45, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -1);
|
||||
public static readonly OpCode Beq_S = new OpCode(46, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bge_S = new OpCode(47, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bgt_S = new OpCode(48, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Ble_S = new OpCode(49, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Blt_S = new OpCode(50, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bne_Un_S = new OpCode(51, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bge_Un_S = new OpCode(52, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bgt_Un_S = new OpCode(53, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Ble_Un_S = new OpCode(54, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Blt_Un_S = new OpCode(55, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Br = new OpCode(56, OperandType.InlineBrTarget, FlowControl.Branch, 0);
|
||||
public static readonly OpCode Brfalse = new OpCode(57, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -1);
|
||||
public static readonly OpCode Brtrue = new OpCode(58, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -1);
|
||||
public static readonly OpCode Beq = new OpCode(59, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bge = new OpCode(60, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bgt = new OpCode(61, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Ble = new OpCode(62, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Blt = new OpCode(63, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bne_Un = new OpCode(64, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bge_Un = new OpCode(65, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Bgt_Un = new OpCode(66, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Ble_Un = new OpCode(67, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Blt_Un = new OpCode(68, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
|
||||
public static readonly OpCode Switch = new OpCode(69, OperandType.InlineSwitch, FlowControl.Cond_Branch, -1);
|
||||
public static readonly OpCode Ldind_I1 = new OpCode(70, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_U1 = new OpCode(71, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_I2 = new OpCode(72, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_U2 = new OpCode(73, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_I4 = new OpCode(74, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_U4 = new OpCode(75, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_I8 = new OpCode(76, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_I = new OpCode(77, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_R4 = new OpCode(78, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_R8 = new OpCode(79, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldind_Ref = new OpCode(80, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Stind_Ref = new OpCode(81, OperandType.InlineNone, FlowControl.Next, -2);
|
||||
public static readonly OpCode Stind_I1 = new OpCode(82, OperandType.InlineNone, FlowControl.Next, -2);
|
||||
public static readonly OpCode Stind_I2 = new OpCode(83, OperandType.InlineNone, FlowControl.Next, -2);
|
||||
public static readonly OpCode Stind_I4 = new OpCode(84, OperandType.InlineNone, FlowControl.Next, -2);
|
||||
public static readonly OpCode Stind_I8 = new OpCode(85, OperandType.InlineNone, FlowControl.Next, -2);
|
||||
public static readonly OpCode Stind_R4 = new OpCode(86, OperandType.InlineNone, FlowControl.Next, -2);
|
||||
public static readonly OpCode Stind_R8 = new OpCode(87, OperandType.InlineNone, FlowControl.Next, -2);
|
||||
public static readonly OpCode Add = new OpCode(88, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Sub = new OpCode(89, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Mul = new OpCode(90, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Div = new OpCode(91, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Div_Un = new OpCode(92, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Rem = new OpCode(93, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Rem_Un = new OpCode(94, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode And = new OpCode(95, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Or = new OpCode(96, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Xor = new OpCode(97, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Shl = new OpCode(98, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Shr = new OpCode(99, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Shr_Un = new OpCode(100, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Neg = new OpCode(101, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Not = new OpCode(102, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_I1 = new OpCode(103, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_I2 = new OpCode(104, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_I4 = new OpCode(105, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_I8 = new OpCode(106, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_R4 = new OpCode(107, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_R8 = new OpCode(108, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_U4 = new OpCode(109, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_U8 = new OpCode(110, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Callvirt = new OpCode(111, OperandType.InlineMethod, FlowControl.Call, 0);
|
||||
public static readonly OpCode Cpobj = new OpCode(112, OperandType.InlineType, FlowControl.Next, -2);
|
||||
public static readonly OpCode Ldobj = new OpCode(113, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldstr = new OpCode(114, OperandType.InlineString, FlowControl.Next, 1);
|
||||
public static readonly OpCode Newobj = new OpCode(115, OperandType.InlineMethod, FlowControl.Call, 1);
|
||||
public static readonly OpCode Castclass = new OpCode(116, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Isinst = new OpCode(117, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_R_Un = new OpCode(118, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Unbox = new OpCode(121, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Throw = new OpCode(122, OperandType.InlineNone, FlowControl.Throw, -1);
|
||||
public static readonly OpCode Ldfld = new OpCode(123, OperandType.InlineField, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldflda = new OpCode(124, OperandType.InlineField, FlowControl.Next, 0);
|
||||
public static readonly OpCode Stfld = new OpCode(125, OperandType.InlineField, FlowControl.Next, -2);
|
||||
public static readonly OpCode Ldsfld = new OpCode(126, OperandType.InlineField, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldsflda = new OpCode(127, OperandType.InlineField, FlowControl.Next, 1);
|
||||
public static readonly OpCode Stsfld = new OpCode(128, OperandType.InlineField, FlowControl.Next, -1);
|
||||
public static readonly OpCode Stobj = new OpCode(129, OperandType.InlineType, FlowControl.Next, -2);
|
||||
public static readonly OpCode Conv_Ovf_I1_Un = new OpCode(130, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I2_Un = new OpCode(131, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I4_Un = new OpCode(132, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I8_Un = new OpCode(133, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U1_Un = new OpCode(134, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U2_Un = new OpCode(135, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U4_Un = new OpCode(136, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U8_Un = new OpCode(137, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I_Un = new OpCode(138, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U_Un = new OpCode(139, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Box = new OpCode(140, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Newarr = new OpCode(141, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldlen = new OpCode(142, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldelema = new OpCode(143, OperandType.InlineType, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_I1 = new OpCode(144, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_U1 = new OpCode(145, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_I2 = new OpCode(146, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_U2 = new OpCode(147, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_I4 = new OpCode(148, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_U4 = new OpCode(149, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_I8 = new OpCode(150, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_I = new OpCode(151, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_R4 = new OpCode(152, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_R8 = new OpCode(153, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldelem_Ref = new OpCode(154, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Stelem_I = new OpCode(155, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Stelem_I1 = new OpCode(156, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Stelem_I2 = new OpCode(157, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Stelem_I4 = new OpCode(158, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Stelem_I8 = new OpCode(159, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Stelem_R4 = new OpCode(160, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Stelem_R8 = new OpCode(161, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Stelem_Ref = new OpCode(162, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Ldelem = new OpCode(163, OperandType.InlineType, FlowControl.Next, -1);
|
||||
public static readonly OpCode Stelem = new OpCode(164, OperandType.InlineType, FlowControl.Next, -3);
|
||||
public static readonly OpCode Unbox_Any = new OpCode(165, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I1 = new OpCode(179, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U1 = new OpCode(180, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I2 = new OpCode(181, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U2 = new OpCode(182, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I4 = new OpCode(183, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U4 = new OpCode(184, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I8 = new OpCode(185, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U8 = new OpCode(186, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Refanyval = new OpCode(194, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ckfinite = new OpCode(195, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Mkrefany = new OpCode(198, OperandType.InlineType, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldtoken = new OpCode(208, OperandType.InlineTok, FlowControl.Next, 1);
|
||||
public static readonly OpCode Conv_U2 = new OpCode(209, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_U1 = new OpCode(210, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_I = new OpCode(211, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_I = new OpCode(212, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Conv_Ovf_U = new OpCode(213, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Add_Ovf = new OpCode(214, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Add_Ovf_Un = new OpCode(215, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Mul_Ovf = new OpCode(216, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Mul_Ovf_Un = new OpCode(217, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Sub_Ovf = new OpCode(218, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Sub_Ovf_Un = new OpCode(219, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Endfinally = new OpCode(220, OperandType.InlineNone, FlowControl.Return, 0);
|
||||
public static readonly OpCode Leave = new OpCode(221, OperandType.InlineBrTarget, FlowControl.Branch, 0);
|
||||
public static readonly OpCode Leave_S = new OpCode(222, OperandType.ShortInlineBrTarget, FlowControl.Branch, 0);
|
||||
public static readonly OpCode Stind_I = new OpCode(223, OperandType.InlineNone, FlowControl.Next, -2);
|
||||
public static readonly OpCode Conv_U = new OpCode(224, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Prefix7 = new OpCode(248, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Prefix6 = new OpCode(249, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Prefix5 = new OpCode(250, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Prefix4 = new OpCode(251, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Prefix3 = new OpCode(252, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Prefix2 = new OpCode(253, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Prefix1 = new OpCode(254, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Prefixref = new OpCode(255, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Arglist = new OpCode(-512, OperandType.InlineNone, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ceq = new OpCode(-511, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Cgt = new OpCode(-510, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Cgt_Un = new OpCode(-509, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Clt = new OpCode(-508, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Clt_Un = new OpCode(-507, OperandType.InlineNone, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldftn = new OpCode(-506, OperandType.InlineMethod, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldvirtftn = new OpCode(-505, OperandType.InlineMethod, FlowControl.Next, 0);
|
||||
public static readonly OpCode Ldarg = new OpCode(-503, OperandType.InlineVar, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldarga = new OpCode(-502, OperandType.InlineVar, FlowControl.Next, 1);
|
||||
public static readonly OpCode Starg = new OpCode(-501, OperandType.InlineVar, FlowControl.Next, -1);
|
||||
public static readonly OpCode Ldloc = new OpCode(-500, OperandType.InlineVar, FlowControl.Next, 1);
|
||||
public static readonly OpCode Ldloca = new OpCode(-499, OperandType.InlineVar, FlowControl.Next, 1);
|
||||
public static readonly OpCode Stloc = new OpCode(-498, OperandType.InlineVar, FlowControl.Next, -1);
|
||||
public static readonly OpCode Localloc = new OpCode(-497, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Endfilter = new OpCode(-495, OperandType.InlineNone, FlowControl.Return, -1);
|
||||
public static readonly OpCode Unaligned = new OpCode(-494, OperandType.ShortInlineI, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Volatile = new OpCode(-493, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Tailcall = new OpCode(-492, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Initobj = new OpCode(-491, OperandType.InlineType, FlowControl.Next, -1);
|
||||
public static readonly OpCode Constrained = new OpCode(-490, OperandType.InlineType, FlowControl.Meta, 0);
|
||||
public static readonly OpCode Cpblk = new OpCode(-489, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Initblk = new OpCode(-488, OperandType.InlineNone, FlowControl.Next, -3);
|
||||
public static readonly OpCode Rethrow = new OpCode(-486, OperandType.InlineNone, FlowControl.Throw, 0);
|
||||
public static readonly OpCode Sizeof = new OpCode(-484, OperandType.InlineType, FlowControl.Next, 1);
|
||||
public static readonly OpCode Refanytype = new OpCode(-483, OperandType.InlineNone, FlowControl.Next, 0);
|
||||
public static readonly OpCode Readonly = new OpCode(-482, OperandType.InlineNone, FlowControl.Meta, 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public sealed class ParameterBuilder
|
||||
{
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
private short flags;
|
||||
private readonly short sequence;
|
||||
private readonly int name;
|
||||
private int lazyPseudoToken;
|
||||
|
||||
internal ParameterBuilder(ModuleBuilder moduleBuilder, int sequence, ParameterAttributes attribs, string name)
|
||||
{
|
||||
this.moduleBuilder = moduleBuilder;
|
||||
this.flags = (short)attribs;
|
||||
this.sequence = (short)sequence;
|
||||
this.name = name == null ? 0 : moduleBuilder.Strings.Add(name);
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(CustomAttributeBuilder customAttributeBuilder)
|
||||
{
|
||||
if (customAttributeBuilder.Constructor.DeclaringType == typeof(InAttribute))
|
||||
{
|
||||
flags |= (short)ParameterAttributes.In;
|
||||
}
|
||||
else if (customAttributeBuilder.Constructor.DeclaringType == typeof(OutAttribute))
|
||||
{
|
||||
flags |= (short)ParameterAttributes.Out;
|
||||
}
|
||||
else if (customAttributeBuilder.Constructor.DeclaringType == typeof(OptionalAttribute))
|
||||
{
|
||||
flags |= (short)ParameterAttributes.Optional;
|
||||
}
|
||||
else if (customAttributeBuilder.Constructor.DeclaringType == typeof(MarshalAsAttribute))
|
||||
{
|
||||
flags |= (short)ParameterAttributes.HasFieldMarshal;
|
||||
if (lazyPseudoToken == 0)
|
||||
{
|
||||
lazyPseudoToken = moduleBuilder.AllocPseudoToken();
|
||||
}
|
||||
TableHeap.FieldMarshalTable.Record rec = new TableHeap.FieldMarshalTable.Record();
|
||||
rec.Parent = lazyPseudoToken;
|
||||
rec.NativeType = FieldBuilder.WriteMarshallingDescriptor(moduleBuilder, customAttributeBuilder);
|
||||
moduleBuilder.Tables.FieldMarshal.AddRecord(rec);
|
||||
}
|
||||
else if (customAttributeBuilder.Constructor.DeclaringType == typeof(DefaultParameterValueAttribute))
|
||||
{
|
||||
flags |= (short)ParameterAttributes.HasDefault;
|
||||
if (lazyPseudoToken == 0)
|
||||
{
|
||||
lazyPseudoToken = moduleBuilder.AllocPseudoToken();
|
||||
}
|
||||
moduleBuilder.AddConstant(lazyPseudoToken, customAttributeBuilder.GetConstructorArgument(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lazyPseudoToken == 0)
|
||||
{
|
||||
lazyPseudoToken = moduleBuilder.AllocPseudoToken();
|
||||
}
|
||||
moduleBuilder.SetCustomAttribute(lazyPseudoToken, customAttributeBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteParamRecord(MetadataWriter mw)
|
||||
{
|
||||
mw.Write(flags);
|
||||
mw.Write(sequence);
|
||||
mw.WriteStringIndex(name);
|
||||
}
|
||||
|
||||
internal void FixupToken(int parameterToken)
|
||||
{
|
||||
if (lazyPseudoToken != 0)
|
||||
{
|
||||
moduleBuilder.RegisterTokenFixup(lazyPseudoToken, parameterToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyTitle("IKVM.NET Reflection Emit")]
|
||||
[assembly: AssemblyDescription("Managed (partial) Reflection Emit implementation for use by ikvmc")]
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public class PropertyBuilder : PropertyInfo
|
||||
{
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
private readonly int name;
|
||||
private readonly PropertyAttributes attributes;
|
||||
private readonly ByteBuffer signature;
|
||||
private int getMethodToken;
|
||||
private int setMethodToken;
|
||||
private int pseudoToken;
|
||||
|
||||
internal PropertyBuilder(ModuleBuilder moduleBuilder, string name, PropertyAttributes attributes, Type returnType, Type[] parameterTypes)
|
||||
{
|
||||
this.moduleBuilder = moduleBuilder;
|
||||
this.name = moduleBuilder.Strings.Add(name);
|
||||
this.attributes = attributes;
|
||||
signature = new ByteBuffer(16);
|
||||
// later on we'll patch this byte, if it turns out that it is an instance property
|
||||
signature.Write(SignatureHelper.PROPERTY);
|
||||
signature.WriteCompressedInt(parameterTypes == null ? 0 : parameterTypes.Length);
|
||||
SignatureHelper.WriteType(moduleBuilder, signature, returnType);
|
||||
if (parameterTypes != null)
|
||||
{
|
||||
foreach (Type type in parameterTypes)
|
||||
{
|
||||
SignatureHelper.WriteType(moduleBuilder, signature, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetGetMethod(MethodBuilder mdBuilder)
|
||||
{
|
||||
if (!mdBuilder.IsStatic)
|
||||
{
|
||||
signature.Position = 0;
|
||||
signature.Write((byte)(SignatureHelper.PROPERTY | SignatureHelper.HASTHIS));
|
||||
}
|
||||
getMethodToken = mdBuilder.MetadataToken;
|
||||
}
|
||||
|
||||
public void SetSetMethod(MethodBuilder mdBuilder)
|
||||
{
|
||||
if (!mdBuilder.IsStatic)
|
||||
{
|
||||
signature.Position = 0;
|
||||
signature.Write((byte)(SignatureHelper.PROPERTY | SignatureHelper.HASTHIS));
|
||||
}
|
||||
setMethodToken = mdBuilder.MetadataToken;
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
if (pseudoToken == 0)
|
||||
{
|
||||
pseudoToken = moduleBuilder.AllocPseudoToken();
|
||||
}
|
||||
moduleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
|
||||
}
|
||||
|
||||
public override PropertyAttributes Attributes
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override MethodInfo[] GetAccessors(bool nonPublic)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override MethodInfo GetGetMethod(bool nonPublic)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override ParameterInfo[] GetIndexParameters()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override MethodInfo GetSetMethod(bool nonPublic)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Type PropertyType
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Type DeclaringType
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object[] GetCustomAttributes(bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool IsDefined(Type attributeType, bool inherit)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override Type ReflectedType
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
internal void Bake()
|
||||
{
|
||||
TableHeap.PropertyTable.Record rec = new TableHeap.PropertyTable.Record();
|
||||
rec.Flags = (short)attributes;
|
||||
rec.Name = name;
|
||||
rec.Type = moduleBuilder.Blobs.Add(signature);
|
||||
int token = 0x17000000 | moduleBuilder.Tables.Property.AddRecord(rec);
|
||||
|
||||
if (pseudoToken != 0)
|
||||
{
|
||||
moduleBuilder.RegisterTokenFixup(pseudoToken, token);
|
||||
}
|
||||
|
||||
if (getMethodToken != 0)
|
||||
{
|
||||
const short Getter = 0x0002;
|
||||
AddMethodSemantics(Getter, getMethodToken, token);
|
||||
}
|
||||
if (setMethodToken != 0)
|
||||
{
|
||||
const short Setter = 0x0001;
|
||||
AddMethodSemantics(Setter, setMethodToken, token);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddMethodSemantics(short semantics, int methodToken, int propertyToken)
|
||||
{
|
||||
TableHeap.MethodSemanticsTable.Record rec = new TableHeap.MethodSemanticsTable.Record();
|
||||
rec.Semantics = semantics;
|
||||
rec.Method = methodToken;
|
||||
rec.Association = propertyToken;
|
||||
moduleBuilder.Tables.MethodSemantics.AddRecord(rec);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public class SignatureHelper
|
||||
{
|
||||
internal const byte DEFAULT = 0x00;
|
||||
internal const byte GENERIC = 0x10;
|
||||
internal const byte HASTHIS = 0x20;
|
||||
internal const byte FIELD = 0x06;
|
||||
internal const byte PROPERTY = 0x08;
|
||||
internal const byte ELEMENT_TYPE_VOID = 0x01;
|
||||
internal const byte ELEMENT_TYPE_BOOLEAN = 0x02;
|
||||
internal const byte ELEMENT_TYPE_CHAR = 0x03;
|
||||
internal const byte ELEMENT_TYPE_I1 = 0x04;
|
||||
internal const byte ELEMENT_TYPE_U1 = 0x05;
|
||||
internal const byte ELEMENT_TYPE_I2 = 0x06;
|
||||
internal const byte ELEMENT_TYPE_U2 = 0x07;
|
||||
internal const byte ELEMENT_TYPE_I4 = 0x08;
|
||||
internal const byte ELEMENT_TYPE_U4 = 0x09;
|
||||
internal const byte ELEMENT_TYPE_I8 = 0x0a;
|
||||
internal const byte ELEMENT_TYPE_U8 = 0x0b;
|
||||
internal const byte ELEMENT_TYPE_R4 = 0x0c;
|
||||
internal const byte ELEMENT_TYPE_R8 = 0x0d;
|
||||
internal const byte ELEMENT_TYPE_STRING = 0x0e;
|
||||
internal const byte ELEMENT_TYPE_BYREF = 0x10;
|
||||
internal const byte ELEMENT_TYPE_VALUETYPE = 0x11;
|
||||
internal const byte ELEMENT_TYPE_CLASS = 0x12;
|
||||
internal const byte ELEMENT_TYPE_VAR = 0x13;
|
||||
internal const byte ELEMENT_TYPE_GENERICINST = 0x15;
|
||||
internal const byte ELEMENT_TYPE_I = 0x18;
|
||||
internal const byte ELEMENT_TYPE_OBJECT = 0x1c;
|
||||
internal const byte ELEMENT_TYPE_SZARRAY = 0x1d;
|
||||
internal const byte ELEMENT_TYPE_MVAR = 0x1e;
|
||||
internal const byte ELEMENT_TYPE_CMOD_REQD = 0x1f;
|
||||
internal const byte ELEMENT_TYPE_CMOD_OPT = 0x020;
|
||||
|
||||
private enum GenericParameterType
|
||||
{
|
||||
None,
|
||||
Method,
|
||||
Type
|
||||
}
|
||||
|
||||
internal static void WriteType(ModuleBuilder moduleBuilder, ByteBuffer bb, Type type)
|
||||
{
|
||||
WriteType(moduleBuilder, bb, type, GenericParameterType.None);
|
||||
}
|
||||
|
||||
private static void WriteType(ModuleBuilder moduleBuilder, ByteBuffer bb, Type type, GenericParameterType genericParameter)
|
||||
{
|
||||
while (type.IsArray)
|
||||
{
|
||||
// check for non-szarrays
|
||||
if (!type.FullName.EndsWith("[]", StringComparison.Ordinal))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
bb.Write(ELEMENT_TYPE_SZARRAY);
|
||||
type = type.GetElementType();
|
||||
}
|
||||
while (type.IsByRef)
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_BYREF);
|
||||
type = type.GetElementType();
|
||||
}
|
||||
if (type == typeof(void))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_VOID);
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_BOOLEAN);
|
||||
}
|
||||
else if (type == typeof(char))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_CHAR);
|
||||
}
|
||||
else if (type == typeof(sbyte))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_I1);
|
||||
}
|
||||
else if (type == typeof(byte))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_U1);
|
||||
}
|
||||
else if (type == typeof(short))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_I2);
|
||||
}
|
||||
else if (type == typeof(ushort))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_U2);
|
||||
}
|
||||
else if (type == typeof(int))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_I4);
|
||||
}
|
||||
else if (type == typeof(uint))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_U4);
|
||||
}
|
||||
else if (type == typeof(long))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_I8);
|
||||
}
|
||||
else if (type == typeof(ulong))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_U8);
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_R4);
|
||||
}
|
||||
else if (type == typeof(double))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_R8);
|
||||
}
|
||||
else if (type == typeof(string))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_STRING);
|
||||
}
|
||||
else if (type == typeof(IntPtr))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_I);
|
||||
}
|
||||
else if (type == typeof(object))
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_OBJECT);
|
||||
}
|
||||
else if (type.IsGenericParameter)
|
||||
{
|
||||
switch (genericParameter)
|
||||
{
|
||||
case GenericParameterType.Type:
|
||||
bb.Write(ELEMENT_TYPE_VAR);
|
||||
bb.WriteCompressedInt(type.GenericParameterPosition);
|
||||
break;
|
||||
case GenericParameterType.Method:
|
||||
bb.Write(ELEMENT_TYPE_MVAR);
|
||||
bb.WriteCompressedInt(type.GenericParameterPosition);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
else if (type.IsGenericType && !type.IsGenericTypeDefinition)
|
||||
{
|
||||
WriteGenericSignature(moduleBuilder, bb, type.GetGenericTypeDefinition(), type.GetGenericArguments());
|
||||
}
|
||||
else if (!type.IsPrimitive)
|
||||
{
|
||||
if (type.IsValueType)
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_VALUETYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
bb.Write(ELEMENT_TYPE_CLASS);
|
||||
}
|
||||
bb.WriteTypeDefOrRefEncoded(moduleBuilder.GetTypeToken(type).Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(type.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteCustomModifiers(ModuleBuilder moduleBuilder, ByteBuffer bb, byte mod, Type[] modifiers)
|
||||
{
|
||||
if (modifiers != null)
|
||||
{
|
||||
foreach (Type type in modifiers)
|
||||
{
|
||||
bb.Write(mod);
|
||||
bb.WriteTypeDefOrRefEncoded(moduleBuilder.GetTypeToken(type).Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteFieldSig(ModuleBuilder moduleBuilder, ByteBuffer bb, Type fieldType, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers)
|
||||
{
|
||||
bb.Write(FIELD);
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, requiredCustomModifiers);
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, optionalCustomModifiers);
|
||||
WriteType(moduleBuilder, bb, fieldType);
|
||||
}
|
||||
|
||||
internal static void WriteMethodSig(ModuleBuilder moduleBuilder, ByteBuffer bb, CallingConventions callingConvention, Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
|
||||
{
|
||||
if ((callingConvention & ~CallingConventions.HasThis) != CallingConventions.Standard)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
byte first = DEFAULT;
|
||||
if ((callingConvention & CallingConventions.HasThis) != 0)
|
||||
{
|
||||
first |= HASTHIS;
|
||||
}
|
||||
parameterTypes = parameterTypes ?? Type.EmptyTypes;
|
||||
bb.Write(first);
|
||||
bb.WriteCompressedInt(parameterTypes.Length);
|
||||
// RetType
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, returnTypeRequiredCustomModifiers);
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, returnTypeOptionalCustomModifiers);
|
||||
WriteType(moduleBuilder, bb, returnType ?? typeof(void));
|
||||
// Param
|
||||
for (int i = 0; i < parameterTypes.Length; i++)
|
||||
{
|
||||
if (parameterTypeRequiredCustomModifiers != null && parameterTypeRequiredCustomModifiers.Length > i)
|
||||
{
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, parameterTypeRequiredCustomModifiers[i]);
|
||||
}
|
||||
if (parameterTypeOptionalCustomModifiers != null && parameterTypeOptionalCustomModifiers.Length > i)
|
||||
{
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, parameterTypeOptionalCustomModifiers[i]);
|
||||
}
|
||||
WriteType(moduleBuilder, bb, parameterTypes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodBase GetMethodOnTypeDefinition(MethodBase method)
|
||||
{
|
||||
Type type = method.DeclaringType;
|
||||
if (type != null && type.IsGenericType && !type.IsGenericTypeDefinition)
|
||||
{
|
||||
// this trick allows us to go from the method on the generic type instance, to the equivalent method on the generic type definition
|
||||
method = method.Module.ResolveMethod(method.MetadataToken);
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
internal static void WriteMethodSig(ModuleBuilder moduleBuilder, ByteBuffer bb, MethodBase methodOnTypeInstance)
|
||||
{
|
||||
Debug.Assert(!methodOnTypeInstance.IsGenericMethod || methodOnTypeInstance.IsGenericMethodDefinition);
|
||||
MethodBase method = GetMethodOnTypeDefinition(methodOnTypeInstance);
|
||||
ParameterInfo returnParameter = null;
|
||||
ParameterInfo[] parameters = method.GetParameters();
|
||||
if (method is MethodInfo)
|
||||
{
|
||||
returnParameter = ((MethodInfo)method).ReturnParameter;
|
||||
}
|
||||
bool methodIsGeneric = false;
|
||||
ParameterInfo methodOnTypeInstanceReturnParameter = returnParameter;
|
||||
ParameterInfo[] methodOnTypeInstanceParameters = parameters;
|
||||
if (methodOnTypeInstance.IsGenericMethodDefinition)
|
||||
{
|
||||
methodIsGeneric = true;
|
||||
methodOnTypeInstanceReturnParameter = ((MethodInfo)methodOnTypeInstance).ReturnParameter;
|
||||
methodOnTypeInstanceParameters = methodOnTypeInstance.GetParameters();
|
||||
}
|
||||
byte first = DEFAULT;
|
||||
if (!method.IsStatic)
|
||||
{
|
||||
first |= HASTHIS;
|
||||
}
|
||||
if (method.IsGenericMethod)
|
||||
{
|
||||
first |= GENERIC;
|
||||
}
|
||||
bb.Write(first);
|
||||
if (method.IsGenericMethod)
|
||||
{
|
||||
bb.WriteCompressedInt(method.GetGenericArguments().Length);
|
||||
}
|
||||
bb.WriteCompressedInt(parameters.Length);
|
||||
// RetType
|
||||
if (returnParameter == null)
|
||||
{
|
||||
WriteType(moduleBuilder, bb, typeof(void));
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, returnParameter.GetRequiredCustomModifiers());
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, returnParameter.GetOptionalCustomModifiers());
|
||||
WriteMethodParameterType(moduleBuilder, bb, returnParameter.ParameterType, methodOnTypeInstanceReturnParameter.ParameterType, methodIsGeneric);
|
||||
}
|
||||
// Param
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, parameters[i].GetRequiredCustomModifiers());
|
||||
WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, parameters[i].GetOptionalCustomModifiers());
|
||||
WriteMethodParameterType(moduleBuilder, bb, parameters[i].ParameterType, methodOnTypeInstanceParameters[i].ParameterType, methodIsGeneric);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsGenericParameter(Type type)
|
||||
{
|
||||
while (type.HasElementType)
|
||||
{
|
||||
type = type.GetElementType();
|
||||
}
|
||||
return type.IsGenericParameter;
|
||||
}
|
||||
|
||||
private static void WriteMethodParameterType(ModuleBuilder moduleBuilder, ByteBuffer bb, Type type1, Type type2, bool methodIsGeneric)
|
||||
{
|
||||
if (methodIsGeneric && IsGenericParameter(type2))
|
||||
{
|
||||
WriteType(moduleBuilder, bb, type1, GenericParameterType.Method);
|
||||
}
|
||||
else if (IsGenericParameter(type1))
|
||||
{
|
||||
WriteType(moduleBuilder, bb, type1, GenericParameterType.Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteType(moduleBuilder, bb, type1);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteGenericSignature(ModuleBuilder moduleBuilder, ByteBuffer bb, Type type, Type[] typeArguments)
|
||||
{
|
||||
Debug.Assert(type.IsGenericTypeDefinition);
|
||||
bb.Write(ELEMENT_TYPE_GENERICINST);
|
||||
WriteType(moduleBuilder, bb, type);
|
||||
bb.WriteCompressedInt(typeArguments.Length);
|
||||
foreach (Type t in typeArguments)
|
||||
{
|
||||
WriteType(moduleBuilder, bb, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public struct ConstructorToken
|
||||
{
|
||||
internal readonly int Token;
|
||||
|
||||
internal ConstructorToken(int token)
|
||||
{
|
||||
this.Token = token;
|
||||
}
|
||||
|
||||
internal bool IsPseudoToken
|
||||
{
|
||||
get { return Token < 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public struct FieldToken
|
||||
{
|
||||
internal readonly int Token;
|
||||
|
||||
internal FieldToken(int token)
|
||||
{
|
||||
this.Token = token;
|
||||
}
|
||||
|
||||
internal bool IsPseudoToken
|
||||
{
|
||||
get { return Token < 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public struct MethodToken
|
||||
{
|
||||
internal readonly int Token;
|
||||
|
||||
internal MethodToken(int token)
|
||||
{
|
||||
this.Token = token;
|
||||
}
|
||||
|
||||
internal bool IsPseudoToken
|
||||
{
|
||||
get { return Token < 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public struct TypeToken
|
||||
{
|
||||
internal readonly int Token;
|
||||
|
||||
internal TypeToken(int token)
|
||||
{
|
||||
this.Token = token;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,893 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using IKVM.Reflection.Emit.Writer;
|
||||
using IKVM.Reflection.Emit.Impl;
|
||||
|
||||
namespace IKVM.Reflection.Emit
|
||||
{
|
||||
public class GenericTypeParameterBuilder
|
||||
{
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
private readonly int owner;
|
||||
|
||||
internal GenericTypeParameterBuilder(ModuleBuilder moduleBuilder, int owner)
|
||||
{
|
||||
this.moduleBuilder = moduleBuilder;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public void SetBaseTypeConstraint(Type baseTypeConstraint)
|
||||
{
|
||||
TableHeap.GenericParamConstraintTable.Record rec = new TableHeap.GenericParamConstraintTable.Record();
|
||||
rec.Owner = owner;
|
||||
rec.Constraint = moduleBuilder.GetTypeToken(baseTypeConstraint).Token;
|
||||
moduleBuilder.Tables.GenericParamConstraint.AddRecord(rec);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TypeBuilder : Impl.TypeBase, ITypeOwner
|
||||
{
|
||||
private readonly ITypeOwner owner;
|
||||
private readonly TypeToken token;
|
||||
private readonly TypeToken extends;
|
||||
private readonly int typeName;
|
||||
private readonly int typeNameSpace;
|
||||
private readonly string nameOrFullName;
|
||||
private readonly Type baseType;
|
||||
private readonly List<MethodBuilder> methods = new List<MethodBuilder>();
|
||||
private readonly List<FieldBuilder> fields = new List<FieldBuilder>();
|
||||
private List<PropertyBuilder> properties;
|
||||
private TypeAttributes attribs;
|
||||
private TypeFlags typeFlags;
|
||||
|
||||
[Flags]
|
||||
private enum TypeFlags
|
||||
{
|
||||
IsGenericTypeDefinition = 1,
|
||||
}
|
||||
|
||||
internal TypeBuilder(ITypeOwner owner, string name, Type baseType, TypeAttributes attribs)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.token = this.ModuleBuilder.Tables.TypeDef.AllocToken();
|
||||
this.nameOrFullName = Escape(name);
|
||||
this.baseType = baseType;
|
||||
if (baseType != null)
|
||||
{
|
||||
extends = this.ModuleBuilder.GetTypeToken(baseType);
|
||||
}
|
||||
this.attribs = attribs;
|
||||
if (!this.IsNested)
|
||||
{
|
||||
int lastdot = name.LastIndexOf('.');
|
||||
if (lastdot > 0)
|
||||
{
|
||||
this.typeNameSpace = this.ModuleBuilder.Strings.Add(name.Substring(0, lastdot));
|
||||
name = name.Substring(lastdot + 1);
|
||||
}
|
||||
}
|
||||
this.typeName = this.ModuleBuilder.Strings.Add(name);
|
||||
}
|
||||
|
||||
private static string Escape(string name)
|
||||
{
|
||||
System.Text.StringBuilder sb = null;
|
||||
int pos;
|
||||
for (pos = 0; pos < name.Length; pos++)
|
||||
{
|
||||
if ("+\\[],*&".IndexOf(name[pos]) != -1)
|
||||
{
|
||||
if (sb == null)
|
||||
{
|
||||
sb = new System.Text.StringBuilder(name, 0, pos, name.Length + 3);
|
||||
}
|
||||
sb.Append('\\').Append(name[pos]);
|
||||
}
|
||||
}
|
||||
return sb != null ? sb.ToString() : name;
|
||||
}
|
||||
|
||||
public ConstructorBuilder DefineConstructor(MethodAttributes attribs, CallingConventions callConv, Type[] parameterTypes)
|
||||
{
|
||||
return DefineConstructor(attribs, callConv, parameterTypes, null, null);
|
||||
}
|
||||
|
||||
public ConstructorBuilder DefineConstructor(MethodAttributes attribs, CallingConventions callingConvention, Type[] parameterTypes, Type[][] requiredCustomModifiers, Type[][] optionalCustomModifiers)
|
||||
{
|
||||
attribs |= MethodAttributes.RTSpecialName | MethodAttributes.SpecialName;
|
||||
string name = ".ctor";
|
||||
if ((attribs & MethodAttributes.Static) != 0)
|
||||
{
|
||||
name = ".cctor";
|
||||
}
|
||||
MethodBuilder mb = DefineMethod(name, attribs, CallingConventions.Standard, typeof(void), null, null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
|
||||
return new ConstructorBuilder(mb);
|
||||
}
|
||||
|
||||
public ConstructorBuilder DefineTypeInitializer()
|
||||
{
|
||||
MethodBuilder mb = DefineMethod(".cctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName, typeof(void), Type.EmptyTypes);
|
||||
return new ConstructorBuilder(mb);
|
||||
}
|
||||
|
||||
public MethodBuilder DefineMethod(string name, MethodAttributes attribs)
|
||||
{
|
||||
return DefineMethod(name, attribs, null, null);
|
||||
}
|
||||
|
||||
public MethodBuilder DefineMethod(string name, MethodAttributes attribs, Type returnType, Type[] parameterTypes)
|
||||
{
|
||||
return DefineMethod(name, attribs, CallingConventions.Standard, returnType, null, null, parameterTypes, null, null);
|
||||
}
|
||||
|
||||
public MethodBuilder DefineMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
|
||||
{
|
||||
return DefineMethod(name, attributes, callingConvention, returnType, null, null, parameterTypes, null, null);
|
||||
}
|
||||
|
||||
public MethodBuilder DefineMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
|
||||
{
|
||||
this.ModuleBuilder.Tables.MethodDef.AddRow();
|
||||
MethodBuilder mb = new MethodBuilder(this, name, attributes, callingConvention, returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers, parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers);
|
||||
methods.Add(mb);
|
||||
return mb;
|
||||
}
|
||||
|
||||
public void DefineMethodOverride(MethodInfo methodInfoBody, MethodInfo methodInfoDeclaration)
|
||||
{
|
||||
TableHeap.MethodImplTable.Record rec = new TableHeap.MethodImplTable.Record();
|
||||
rec.Class = token.Token;
|
||||
rec.MethodBody = this.ModuleBuilder.GetMethodToken(methodInfoBody).Token;
|
||||
rec.MethodDeclaration = this.ModuleBuilder.GetMethodToken(methodInfoDeclaration).Token;
|
||||
this.ModuleBuilder.Tables.MethodImpl.AddRecord(rec);
|
||||
}
|
||||
|
||||
public FieldBuilder DefineField(string name, Type fieldType, FieldAttributes attribs)
|
||||
{
|
||||
return DefineField(name, fieldType, null, null, attribs);
|
||||
}
|
||||
|
||||
public FieldBuilder DefineField(string fieldName, Type type, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attributes)
|
||||
{
|
||||
FieldBuilder fb = new FieldBuilder(this, fieldName, type, requiredCustomModifiers, optionalCustomModifiers, attributes);
|
||||
fields.Add(fb);
|
||||
return fb;
|
||||
}
|
||||
|
||||
public PropertyBuilder DefineProperty(string name, PropertyAttributes attributes, Type returnType, Type[] parameterTypes)
|
||||
{
|
||||
if (properties == null)
|
||||
{
|
||||
properties = new List<PropertyBuilder>();
|
||||
}
|
||||
PropertyBuilder pb = new PropertyBuilder(this.ModuleBuilder, name, attributes, returnType, parameterTypes);
|
||||
properties.Add(pb);
|
||||
return pb;
|
||||
}
|
||||
|
||||
public TypeBuilder DefineNestedType(string name)
|
||||
{
|
||||
return DefineNestedType(name, TypeAttributes.Class | TypeAttributes.NestedPrivate);
|
||||
}
|
||||
|
||||
public TypeBuilder DefineNestedType(string name, TypeAttributes attribs)
|
||||
{
|
||||
return DefineNestedType(name, attribs, null);
|
||||
}
|
||||
|
||||
public TypeBuilder DefineNestedType(string name, TypeAttributes attr, Type parent)
|
||||
{
|
||||
return this.ModuleBuilder.DefineNestedTypeHelper(this, name, attr, parent, PackingSize.Unspecified, 0);
|
||||
}
|
||||
|
||||
public TypeBuilder DefineNestedType(string name, TypeAttributes attr, Type parent, Type[] interfaces)
|
||||
{
|
||||
TypeBuilder tb = DefineNestedType(name, attr, parent);
|
||||
foreach (Type iface in interfaces)
|
||||
{
|
||||
tb.AddInterfaceImplementation(iface);
|
||||
}
|
||||
return tb;
|
||||
}
|
||||
|
||||
public void AddInterfaceImplementation(Type interfaceType)
|
||||
{
|
||||
TableHeap.InterfaceImplTable.Record rec = new TableHeap.InterfaceImplTable.Record();
|
||||
rec.Class = token.Token;
|
||||
rec.Interface = this.ModuleBuilder.GetTypeToken(interfaceType).Token;
|
||||
this.ModuleBuilder.Tables.InterfaceImpl.AddRecord(rec);
|
||||
}
|
||||
|
||||
private void SetStructLayoutPseudoCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
object val = customBuilder.GetConstructorArgument(0);
|
||||
LayoutKind layout;
|
||||
if (val is short)
|
||||
{
|
||||
layout = (LayoutKind)(short)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
layout = (LayoutKind)val;
|
||||
}
|
||||
int? pack = (int?)customBuilder.GetFieldValue("Pack");
|
||||
int? size = (int?)customBuilder.GetFieldValue("Size");
|
||||
if (pack.HasValue || size.HasValue)
|
||||
{
|
||||
TableHeap.ClassLayoutTable.Record rec = new TableHeap.ClassLayoutTable.Record();
|
||||
rec.PackingSize = (short)(pack ?? 0);
|
||||
rec.ClassSize = size ?? 0;
|
||||
rec.Parent = token.Token;
|
||||
this.ModuleBuilder.Tables.ClassLayout.AddRecord(rec);
|
||||
}
|
||||
attribs &= ~TypeAttributes.LayoutMask;
|
||||
switch (layout)
|
||||
{
|
||||
case LayoutKind.Auto:
|
||||
attribs |= TypeAttributes.AutoLayout;
|
||||
break;
|
||||
case LayoutKind.Explicit:
|
||||
attribs |= TypeAttributes.ExplicitLayout;
|
||||
break;
|
||||
case LayoutKind.Sequential:
|
||||
attribs |= TypeAttributes.SequentialLayout;
|
||||
break;
|
||||
}
|
||||
CharSet? charSet = (CharSet?)customBuilder.GetFieldValue("CharSet");
|
||||
attribs &= ~TypeAttributes.StringFormatMask;
|
||||
switch (charSet ?? CharSet.None)
|
||||
{
|
||||
case CharSet.None:
|
||||
case CharSet.Ansi:
|
||||
attribs |= TypeAttributes.AnsiClass;
|
||||
break;
|
||||
case CharSet.Auto:
|
||||
attribs |= TypeAttributes.AutoClass;
|
||||
break;
|
||||
case CharSet.Unicode:
|
||||
attribs |= TypeAttributes.UnicodeClass;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
|
||||
{
|
||||
if (customBuilder.Constructor.DeclaringType == typeof(StructLayoutAttribute))
|
||||
{
|
||||
SetStructLayoutPseudoCustomAttribute(customBuilder);
|
||||
}
|
||||
else if (customBuilder.Constructor.DeclaringType == typeof(SerializableAttribute))
|
||||
{
|
||||
attribs |= TypeAttributes.Serializable;
|
||||
}
|
||||
else if (customBuilder.Constructor.DeclaringType == typeof(ComImportAttribute))
|
||||
{
|
||||
attribs |= TypeAttributes.Import;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ModuleBuilder.SetCustomAttribute(token.Token, customBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public GenericTypeParameterBuilder[] DefineGenericParameters(params string[] names)
|
||||
{
|
||||
typeFlags |= TypeFlags.IsGenericTypeDefinition;
|
||||
GenericTypeParameterBuilder[] gtpb = new GenericTypeParameterBuilder[names.Length];
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
TableHeap.GenericParamTable.Record rec = new TableHeap.GenericParamTable.Record();
|
||||
rec.Number = (short)i;
|
||||
rec.Flags = 0;
|
||||
rec.Owner = token.Token;
|
||||
rec.Name = this.ModuleBuilder.Strings.Add(names[i]);
|
||||
gtpb[i] = new GenericTypeParameterBuilder(this.ModuleBuilder, this.ModuleBuilder.Tables.GenericParam.AddRecord(rec));
|
||||
}
|
||||
return gtpb;
|
||||
}
|
||||
|
||||
public Type CreateType()
|
||||
{
|
||||
foreach (MethodBuilder mb in methods)
|
||||
{
|
||||
mb.Bake();
|
||||
}
|
||||
if (properties != null)
|
||||
{
|
||||
TableHeap.PropertyMapTable.Record rec = new TableHeap.PropertyMapTable.Record();
|
||||
rec.Parent = token.Token;
|
||||
rec.PropertyList = this.ModuleBuilder.Tables.Property.RowCount + 1;
|
||||
this.ModuleBuilder.Tables.PropertyMap.AddRecord(rec);
|
||||
foreach (PropertyBuilder pb in properties)
|
||||
{
|
||||
pb.Bake();
|
||||
}
|
||||
properties = null;
|
||||
}
|
||||
return new BakedType(this);
|
||||
}
|
||||
|
||||
public override string AssemblyQualifiedName
|
||||
{
|
||||
get { return FullName + ", " + this.ModuleBuilder.Assembly.FullName; }
|
||||
}
|
||||
|
||||
public override Type BaseType
|
||||
{
|
||||
get { return baseType; }
|
||||
}
|
||||
|
||||
public override string FullName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.IsNested)
|
||||
{
|
||||
return this.DeclaringType.FullName + "+" + nameOrFullName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nameOrFullName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.IsNested)
|
||||
{
|
||||
return nameOrFullName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override TypeAttributes GetAttributeFlagsImpl()
|
||||
{
|
||||
return attribs;
|
||||
}
|
||||
|
||||
internal MethodInfo __GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
return GetMethodImpl(name, bindingAttr, binder, callConvention, types, modifiers);
|
||||
}
|
||||
|
||||
protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
const BindingFlags supportedFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
|
||||
if (binder != null || (bindingAttr & ~supportedFlags) != 0)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
foreach (MethodBuilder mb in methods)
|
||||
{
|
||||
if (mb.Name == name
|
||||
&& ((mb.IsPublic && ((bindingAttr & BindingFlags.Public) != 0)) || (!mb.IsPublic && ((bindingAttr & BindingFlags.NonPublic) != 0)))
|
||||
&& ((mb.IsStatic && ((bindingAttr & BindingFlags.Static) != 0)) || (!mb.IsStatic && ((bindingAttr & BindingFlags.Instance) != 0)))
|
||||
&& (types == null || mb.MatchParameters(types)))
|
||||
{
|
||||
return mb;
|
||||
}
|
||||
}
|
||||
if (baseType == null || (bindingAttr & BindingFlags.DeclaredOnly) != 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return baseType.GetMethod(name, bindingAttr, binder, callConvention, types, modifiers);
|
||||
}
|
||||
|
||||
public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override bool HasElementTypeImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsArrayImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsByRefImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValueTypeImpl()
|
||||
{
|
||||
return baseType == typeof(ValueType) || baseType == typeof(Enum);
|
||||
}
|
||||
|
||||
public override Type MakeGenericType(params Type[] typeArguments)
|
||||
{
|
||||
return GenericType.Make(this, typeArguments);
|
||||
}
|
||||
|
||||
public override StructLayoutAttribute StructLayoutAttribute
|
||||
{
|
||||
get
|
||||
{
|
||||
StructLayoutAttribute attr;
|
||||
if ((attribs & TypeAttributes.ExplicitLayout) != 0)
|
||||
{
|
||||
attr = new StructLayoutAttribute(LayoutKind.Explicit);
|
||||
attr.Pack = 8;
|
||||
attr.Size = 0;
|
||||
this.ModuleBuilder.Tables.ClassLayout.GetLayout(token, ref attr.Pack, ref attr.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
attr = new StructLayoutAttribute((attribs & TypeAttributes.SequentialLayout) != 0 ? LayoutKind.Sequential : LayoutKind.Auto);
|
||||
attr.Pack = 8;
|
||||
attr.Size = 0;
|
||||
}
|
||||
switch (attribs & TypeAttributes.StringFormatMask)
|
||||
{
|
||||
case TypeAttributes.AutoClass:
|
||||
attr.CharSet = CharSet.Auto;
|
||||
break;
|
||||
case TypeAttributes.UnicodeClass:
|
||||
attr.CharSet = CharSet.Unicode;
|
||||
break;
|
||||
case TypeAttributes.AnsiClass:
|
||||
attr.CharSet = CharSet.Ansi;
|
||||
break;
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
}
|
||||
|
||||
public override Type DeclaringType
|
||||
{
|
||||
get
|
||||
{
|
||||
return owner as TypeBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsGenericType
|
||||
{
|
||||
get
|
||||
{
|
||||
return IsGenericTypeDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsGenericTypeDefinition
|
||||
{
|
||||
get
|
||||
{
|
||||
return (typeFlags & TypeFlags.IsGenericTypeDefinition) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteTypeDefRecord(MetadataWriter mw, ref int fieldList, ref int methodList)
|
||||
{
|
||||
mw.Write((int)attribs);
|
||||
mw.WriteStringIndex(typeName);
|
||||
mw.WriteStringIndex(typeNameSpace);
|
||||
mw.WriteTypeDefOrRef(extends.Token);
|
||||
mw.WriteField(fieldList);
|
||||
mw.WriteMethodDef(methodList);
|
||||
methodList += methods.Count;
|
||||
fieldList += fields.Count;
|
||||
}
|
||||
|
||||
internal void WriteMethodDefRecords(int baseRVA, MetadataWriter mw, ref int paramList)
|
||||
{
|
||||
foreach (MethodBuilder mb in methods)
|
||||
{
|
||||
mb.WriteMethodDefRecord(baseRVA, mw, ref paramList);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ResolveMethodAndFieldTokens(ref int methodToken, ref int fieldToken, ref int parameterToken)
|
||||
{
|
||||
foreach (MethodBuilder method in methods)
|
||||
{
|
||||
method.FixupToken(methodToken++, ref parameterToken);
|
||||
}
|
||||
foreach (FieldBuilder field in fields)
|
||||
{
|
||||
field.FixupToken(fieldToken++);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteParamRecords(MetadataWriter mw)
|
||||
{
|
||||
foreach (MethodBuilder mb in methods)
|
||||
{
|
||||
mb.WriteParamRecords(mw);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteFieldRecords(MetadataWriter mw)
|
||||
{
|
||||
foreach (FieldBuilder fb in fields)
|
||||
{
|
||||
fb.WriteFieldRecords(mw);
|
||||
}
|
||||
}
|
||||
|
||||
internal override ModuleBuilder ModuleBuilder
|
||||
{
|
||||
get { return owner.ModuleBuilder; }
|
||||
}
|
||||
|
||||
internal override TypeToken GetToken()
|
||||
{
|
||||
return token;
|
||||
}
|
||||
|
||||
ModuleBuilder ITypeOwner.ModuleBuilder
|
||||
{
|
||||
get { return owner.ModuleBuilder; }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ArrayType : Impl.TypeBase
|
||||
{
|
||||
private readonly Impl.TypeBase type;
|
||||
private TypeToken token;
|
||||
|
||||
internal static Type Make(Impl.TypeBase type)
|
||||
{
|
||||
return type.ModuleBuilder.CanonicalizeType(new ArrayType(type));
|
||||
}
|
||||
|
||||
private ArrayType(Impl.TypeBase type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public override string AssemblyQualifiedName
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override Type BaseType
|
||||
{
|
||||
get { return typeof(System.Array); }
|
||||
}
|
||||
|
||||
public override string FullName
|
||||
{
|
||||
get { return type.FullName + "[]"; }
|
||||
}
|
||||
|
||||
protected override TypeAttributes GetAttributeFlagsImpl()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Type GetElementType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override bool HasElementTypeImpl()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool IsArrayImpl()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool IsByRefImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValueTypeImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Equals(object o)
|
||||
{
|
||||
ArrayType at = o as ArrayType;
|
||||
return at != null && at.type.Equals(type);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return type.GetHashCode() * 5;
|
||||
}
|
||||
|
||||
internal override ModuleBuilder ModuleBuilder
|
||||
{
|
||||
get { return type.ModuleBuilder; }
|
||||
}
|
||||
|
||||
internal override TypeToken GetToken()
|
||||
{
|
||||
if (token.Token == 0)
|
||||
{
|
||||
ByteBuffer spec = new ByteBuffer(5);
|
||||
SignatureHelper.WriteType(this.ModuleBuilder, spec, this);
|
||||
token = new TypeToken(0x1B000000 | this.ModuleBuilder.Tables.TypeSpec.AddRecord(this.ModuleBuilder.Blobs.Add(spec)));
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class BakedType : Impl.TypeBase
|
||||
{
|
||||
private readonly TypeBuilder typeBuilder;
|
||||
|
||||
internal BakedType(TypeBuilder typeBuilder)
|
||||
{
|
||||
this.typeBuilder = typeBuilder;
|
||||
}
|
||||
|
||||
public override string AssemblyQualifiedName
|
||||
{
|
||||
get { return typeBuilder.AssemblyQualifiedName; }
|
||||
}
|
||||
|
||||
public override Type BaseType
|
||||
{
|
||||
get { return typeBuilder.BaseType; }
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return typeBuilder.Name; }
|
||||
}
|
||||
|
||||
public override string FullName
|
||||
{
|
||||
get { return typeBuilder.FullName; }
|
||||
}
|
||||
|
||||
protected override TypeAttributes GetAttributeFlagsImpl()
|
||||
{
|
||||
return typeBuilder.Attributes;
|
||||
}
|
||||
|
||||
protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
return typeBuilder.__GetMethodImpl(name, bindingAttr, binder, callConvention, types, modifiers);
|
||||
}
|
||||
|
||||
public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
|
||||
{
|
||||
return typeBuilder.GetMethods(bindingAttr);
|
||||
}
|
||||
|
||||
protected override bool HasElementTypeImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsArrayImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsByRefImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValueTypeImpl()
|
||||
{
|
||||
return typeBuilder.IsValueType;
|
||||
}
|
||||
|
||||
public override Type MakeArrayType()
|
||||
{
|
||||
return typeBuilder.MakeArrayType();
|
||||
}
|
||||
|
||||
public override Type MakeGenericType(params Type[] typeArguments)
|
||||
{
|
||||
return typeBuilder.MakeGenericType(typeArguments);
|
||||
}
|
||||
|
||||
public override System.Runtime.InteropServices.StructLayoutAttribute StructLayoutAttribute
|
||||
{
|
||||
get { return typeBuilder.StructLayoutAttribute; }
|
||||
}
|
||||
|
||||
public override Type UnderlyingSystemType
|
||||
{
|
||||
// Type.Equals/GetHashCode relies on this
|
||||
get { return typeBuilder; }
|
||||
}
|
||||
|
||||
public override bool IsGenericType
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeBuilder.IsGenericType;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsGenericTypeDefinition
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeBuilder.IsGenericTypeDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
internal override ModuleBuilder ModuleBuilder
|
||||
{
|
||||
get { return typeBuilder.ModuleBuilder; }
|
||||
}
|
||||
|
||||
internal override TypeToken GetToken()
|
||||
{
|
||||
return typeBuilder.GetToken();
|
||||
}
|
||||
}
|
||||
|
||||
sealed class GenericType : Impl.TypeBase
|
||||
{
|
||||
private readonly TypeBuilder typeBuilder;
|
||||
private readonly Type[] typeArguments;
|
||||
private TypeToken token;
|
||||
|
||||
internal static Type Make(TypeBuilder typeBuilder, Type[] typeArguments)
|
||||
{
|
||||
return typeBuilder.ModuleBuilder.CanonicalizeType(new GenericType(typeBuilder, typeArguments));
|
||||
}
|
||||
|
||||
private GenericType(TypeBuilder typeBuilder, Type[] typeArguments)
|
||||
{
|
||||
this.typeBuilder = typeBuilder;
|
||||
this.typeArguments = typeArguments;
|
||||
}
|
||||
|
||||
public override string AssemblyQualifiedName
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override Type BaseType
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override string FullName
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override Type[] GetGenericArguments()
|
||||
{
|
||||
return (Type[])typeArguments.Clone();
|
||||
}
|
||||
|
||||
protected override TypeAttributes GetAttributeFlagsImpl()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override bool HasElementTypeImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsArrayImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsByRefImpl()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Equals(object o)
|
||||
{
|
||||
GenericType gt = o as GenericType;
|
||||
if (gt != null && gt.typeBuilder == typeBuilder)
|
||||
{
|
||||
for (int i = 0; i < typeArguments.Length; i++)
|
||||
{
|
||||
if (typeArguments[i] != gt.typeArguments[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = typeBuilder.GetHashCode();
|
||||
for (int i = 0; i < typeArguments.Length; i++)
|
||||
{
|
||||
hash *= 37;
|
||||
hash ^= typeArguments[i].GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override bool IsGenericType
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool IsGenericTypeDefinition
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
internal override ModuleBuilder ModuleBuilder
|
||||
{
|
||||
get { return typeBuilder.ModuleBuilder; }
|
||||
}
|
||||
|
||||
internal override TypeToken GetToken()
|
||||
{
|
||||
if (token.Token == 0)
|
||||
{
|
||||
ByteBuffer spec = new ByteBuffer(5);
|
||||
SignatureHelper.WriteGenericSignature(typeBuilder.ModuleBuilder, spec, typeBuilder, typeArguments);
|
||||
token = new TypeToken(0x1B000000 | this.ModuleBuilder.Tables.TypeSpec.AddRecord(this.ModuleBuilder.Blobs.Add(spec)));
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Writer
|
||||
{
|
||||
sealed class ByteBuffer
|
||||
{
|
||||
private byte[] buffer;
|
||||
private int pos;
|
||||
private int __length; // __length is only valid if > pos, otherwise pos is the current length
|
||||
|
||||
internal ByteBuffer(int initialCapacity)
|
||||
{
|
||||
buffer = new byte[initialCapacity];
|
||||
}
|
||||
|
||||
private ByteBuffer(byte[] wrap)
|
||||
{
|
||||
this.buffer = wrap;
|
||||
this.pos = wrap.Length;
|
||||
}
|
||||
|
||||
internal int Position
|
||||
{
|
||||
get { return pos; }
|
||||
set
|
||||
{
|
||||
if (value > this.Length || value > buffer.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
__length = Math.Max(__length, pos);
|
||||
pos = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int Length
|
||||
{
|
||||
get { return Math.Max(pos, __length); }
|
||||
}
|
||||
|
||||
private void Grow(int minGrow)
|
||||
{
|
||||
byte[] newbuf = new byte[Math.Max(buffer.Length + minGrow, buffer.Length * 2)];
|
||||
Buffer.BlockCopy(buffer, 0, newbuf, 0, buffer.Length);
|
||||
buffer = newbuf;
|
||||
}
|
||||
|
||||
// NOTE this does not advance the position
|
||||
internal int GetInt32AtCurrentPosition()
|
||||
{
|
||||
return buffer[pos]
|
||||
+ (buffer[pos + 1] << 8)
|
||||
+ (buffer[pos + 2] << 16)
|
||||
+ (buffer[pos + 3] << 24);
|
||||
}
|
||||
|
||||
// NOTE this does not advance the position
|
||||
internal byte GetByteAtCurrentPosition()
|
||||
{
|
||||
return buffer[pos];
|
||||
}
|
||||
|
||||
internal void Write(byte[] value)
|
||||
{
|
||||
if (pos + value.Length > buffer.Length)
|
||||
Grow(value.Length);
|
||||
Buffer.BlockCopy(value, 0, buffer, pos, value.Length);
|
||||
pos += value.Length;
|
||||
}
|
||||
|
||||
internal void Write(byte value)
|
||||
{
|
||||
if (pos == buffer.Length)
|
||||
Grow(1);
|
||||
buffer[pos++] = value;
|
||||
}
|
||||
|
||||
internal void Write(sbyte value)
|
||||
{
|
||||
Write((byte)value);
|
||||
}
|
||||
|
||||
internal void Write(ushort value)
|
||||
{
|
||||
Write((short)value);
|
||||
}
|
||||
|
||||
internal void Write(short value)
|
||||
{
|
||||
if (pos + 2 > buffer.Length)
|
||||
Grow(2);
|
||||
buffer[pos++] = (byte)value;
|
||||
buffer[pos++] = (byte)(value >> 8);
|
||||
}
|
||||
|
||||
internal void Write(uint value)
|
||||
{
|
||||
Write((int)value);
|
||||
}
|
||||
|
||||
internal void Write(int value)
|
||||
{
|
||||
if (pos + 4 > buffer.Length)
|
||||
Grow(4);
|
||||
buffer[pos++] = (byte)value;
|
||||
buffer[pos++] = (byte)(value >> 8);
|
||||
buffer[pos++] = (byte)(value >> 16);
|
||||
buffer[pos++] = (byte)(value >> 24);
|
||||
}
|
||||
|
||||
internal void Write(ulong value)
|
||||
{
|
||||
Write((long)value);
|
||||
}
|
||||
|
||||
internal void Write(long value)
|
||||
{
|
||||
if (pos + 8 > buffer.Length)
|
||||
Grow(8);
|
||||
buffer[pos++] = (byte)value;
|
||||
buffer[pos++] = (byte)(value >> 8);
|
||||
buffer[pos++] = (byte)(value >> 16);
|
||||
buffer[pos++] = (byte)(value >> 24);
|
||||
buffer[pos++] = (byte)(value >> 32);
|
||||
buffer[pos++] = (byte)(value >> 40);
|
||||
buffer[pos++] = (byte)(value >> 48);
|
||||
buffer[pos++] = (byte)(value >> 56);
|
||||
}
|
||||
|
||||
internal void Write(float value)
|
||||
{
|
||||
Write(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
internal void Write(double value)
|
||||
{
|
||||
Write(BitConverter.DoubleToInt64Bits(value));
|
||||
}
|
||||
|
||||
internal void WriteCompressedInt(int value)
|
||||
{
|
||||
if (value <= 0x7F)
|
||||
{
|
||||
Write((byte)value);
|
||||
}
|
||||
else if (value <= 0x3FFF)
|
||||
{
|
||||
Write((byte)(0x80 | (value >> 8)));
|
||||
Write((byte)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((byte)(0xC0 | (value >> 24)));
|
||||
Write((byte)(value >> 16));
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Write(ByteBuffer bb)
|
||||
{
|
||||
if (pos + bb.Length > buffer.Length)
|
||||
Grow(bb.Length);
|
||||
Buffer.BlockCopy(bb.buffer, 0, buffer, pos, bb.Length);
|
||||
pos += bb.Length;
|
||||
}
|
||||
|
||||
internal void WriteTo(System.IO.Stream stream)
|
||||
{
|
||||
stream.Write(buffer, 0, this.Length);
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
pos = 0;
|
||||
__length = 0;
|
||||
}
|
||||
|
||||
internal void Align(int alignment)
|
||||
{
|
||||
if (pos + alignment > buffer.Length)
|
||||
Grow(alignment);
|
||||
int newpos = (pos + alignment - 1) & ~(alignment - 1);
|
||||
while (pos < newpos)
|
||||
buffer[pos++] = 0;
|
||||
}
|
||||
|
||||
internal void WriteTypeDefOrRefEncoded(int token)
|
||||
{
|
||||
switch (token >> 24)
|
||||
{
|
||||
case TableHeap.TypeDefTable.Index:
|
||||
WriteCompressedInt((token & 0xFFFFFF) << 2 | 0);
|
||||
break;
|
||||
case TableHeap.TypeRefTable.Index:
|
||||
WriteCompressedInt((token & 0xFFFFFF) << 2 | 1);
|
||||
break;
|
||||
case TableHeap.TypeSpecTable.Index:
|
||||
WriteCompressedInt((token & 0xFFFFFF) << 2 | 2);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Write(System.IO.Stream stream)
|
||||
{
|
||||
const int chunkSize = 8192;
|
||||
for (; ; )
|
||||
{
|
||||
if (pos + chunkSize > buffer.Length)
|
||||
Grow(chunkSize);
|
||||
int read = stream.Read(buffer, pos, chunkSize);
|
||||
if (read <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pos += read;
|
||||
}
|
||||
}
|
||||
|
||||
internal static ByteBuffer Wrap(byte[] pubkey)
|
||||
{
|
||||
return new ByteBuffer(pubkey);
|
||||
}
|
||||
|
||||
internal byte[] ToArray()
|
||||
{
|
||||
byte[] buf = new byte[this.Length];
|
||||
Buffer.BlockCopy(this.buffer, 0, buf, 0, buf.Length);
|
||||
return buf;
|
||||
}
|
||||
|
||||
internal bool Match(int pos, ByteBuffer bb2, int pos2, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (buffer[pos + i] != bb2.buffer[pos2 + i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal int Hash()
|
||||
{
|
||||
int hash = 0;
|
||||
int len = this.Length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
hash *= 37;
|
||||
hash ^= buffer[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,538 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Writer
|
||||
{
|
||||
sealed class MetadataWriter
|
||||
{
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
private readonly Stream stream;
|
||||
private readonly byte[] buffer = new byte[8];
|
||||
|
||||
internal MetadataWriter(ModuleBuilder moduleBuilder, Stream stream)
|
||||
{
|
||||
this.moduleBuilder = moduleBuilder;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
internal ModuleBuilder ModuleBuilder
|
||||
{
|
||||
get { return moduleBuilder; }
|
||||
}
|
||||
|
||||
internal int Position
|
||||
{
|
||||
get { return (int)stream.Position; }
|
||||
}
|
||||
|
||||
internal void Write(ByteBuffer bb)
|
||||
{
|
||||
bb.WriteTo(stream);
|
||||
}
|
||||
|
||||
internal void Write(byte[] value)
|
||||
{
|
||||
stream.Write(value, 0, value.Length);
|
||||
}
|
||||
|
||||
internal void Write(byte value)
|
||||
{
|
||||
stream.WriteByte(value);
|
||||
}
|
||||
|
||||
internal void Write(ushort value)
|
||||
{
|
||||
Write((short)value);
|
||||
}
|
||||
|
||||
internal void Write(short value)
|
||||
{
|
||||
buffer[0] = (byte)value;
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
stream.Write(buffer, 0, 2);
|
||||
}
|
||||
|
||||
internal void Write(uint value)
|
||||
{
|
||||
Write((int)value);
|
||||
}
|
||||
|
||||
internal void Write(int value)
|
||||
{
|
||||
buffer[0] = (byte)value;
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
buffer[2] = (byte)(value >> 16);
|
||||
buffer[3] = (byte)(value >> 24);
|
||||
stream.Write(buffer, 0, 4);
|
||||
}
|
||||
|
||||
internal void Write(ulong value)
|
||||
{
|
||||
Write((long)value);
|
||||
}
|
||||
|
||||
internal void Write(long value)
|
||||
{
|
||||
buffer[0] = (byte)value;
|
||||
buffer[1] = (byte)(value >> 8);
|
||||
buffer[2] = (byte)(value >> 16);
|
||||
buffer[3] = (byte)(value >> 24);
|
||||
buffer[4] = (byte)(value >> 32);
|
||||
buffer[5] = (byte)(value >> 40);
|
||||
buffer[6] = (byte)(value >> 48);
|
||||
buffer[7] = (byte)(value >> 56);
|
||||
stream.Write(buffer, 0, 8);
|
||||
}
|
||||
|
||||
internal void WriteCompressedInt(int value)
|
||||
{
|
||||
if (value <= 0x7F)
|
||||
{
|
||||
Write((byte)value);
|
||||
}
|
||||
else if (value <= 0x3FFF)
|
||||
{
|
||||
Write((byte)(0x80 | (value >> 8)));
|
||||
Write((byte)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((byte)(0xC0 | (value >> 24)));
|
||||
Write((byte)(value >> 16));
|
||||
Write((byte)(value >> 8));
|
||||
Write((byte)value);
|
||||
}
|
||||
}
|
||||
|
||||
internal static int GetCompressedIntLength(int value)
|
||||
{
|
||||
if (value <= 0x7F)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (value <= 0x3FFF)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteStringIndex(int index)
|
||||
{
|
||||
if (moduleBuilder.bigStrings)
|
||||
{
|
||||
Write(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteGuidIndex(int index)
|
||||
{
|
||||
if (moduleBuilder.bigGuids)
|
||||
{
|
||||
Write(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteBlobIndex(int index)
|
||||
{
|
||||
if (moduleBuilder.bigBlobs)
|
||||
{
|
||||
Write(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteTypeDefOrRef(int token)
|
||||
{
|
||||
switch (token >> 24)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case TableHeap.TypeDefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 0;
|
||||
break;
|
||||
case TableHeap.TypeRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 1;
|
||||
break;
|
||||
case TableHeap.TypeSpecTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 2;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (moduleBuilder.bigTypeDefOrRef)
|
||||
{
|
||||
Write(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)token);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteHasCustomAttribute(int encodedToken)
|
||||
{
|
||||
// NOTE because we've already had to do the encoding (to be able to sort the table)
|
||||
// here we simple write the value
|
||||
if (moduleBuilder.bigHasCustomAttribute)
|
||||
{
|
||||
Write(encodedToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)encodedToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteCustomAttributeType(int token)
|
||||
{
|
||||
switch (token >> 24)
|
||||
{
|
||||
case TableHeap.MethodDefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 3 | 2;
|
||||
break;
|
||||
case TableHeap.MemberRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 3 | 3;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (moduleBuilder.bigCustomAttributeType)
|
||||
{
|
||||
Write(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)token);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteField(int index)
|
||||
{
|
||||
if (moduleBuilder.bigField)
|
||||
{
|
||||
Write(index & 0xFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteMethodDef(int index)
|
||||
{
|
||||
if (moduleBuilder.bigMethodDef)
|
||||
{
|
||||
Write(index & 0xFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteParam(int index)
|
||||
{
|
||||
if (moduleBuilder.bigParam)
|
||||
{
|
||||
Write(index & 0xFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteTypeDef(int index)
|
||||
{
|
||||
if (moduleBuilder.bigTypeDef)
|
||||
{
|
||||
Write(index & 0xFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteProperty(int index)
|
||||
{
|
||||
if (moduleBuilder.bigProperty)
|
||||
{
|
||||
Write(index & 0xFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteGenericParam(int index)
|
||||
{
|
||||
if (moduleBuilder.bigGenericParam)
|
||||
{
|
||||
Write(index & 0xFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteModuleRef(int index)
|
||||
{
|
||||
if (moduleBuilder.bigModuleRef)
|
||||
{
|
||||
Write(index & 0xFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteResolutionScope(int token)
|
||||
{
|
||||
switch (token >> 24)
|
||||
{
|
||||
case TableHeap.ModuleTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 0;
|
||||
break;
|
||||
case TableHeap.ModuleRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 1;
|
||||
break;
|
||||
case TableHeap.AssemblyRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 2;
|
||||
break;
|
||||
case TableHeap.TypeRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 3;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (moduleBuilder.bigResolutionScope)
|
||||
{
|
||||
Write(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)token);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteMemberRefParent(int token)
|
||||
{
|
||||
switch (token >> 24)
|
||||
{
|
||||
case TableHeap.TypeDefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 3 | 0;
|
||||
break;
|
||||
case TableHeap.TypeRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 3 | 1;
|
||||
break;
|
||||
case TableHeap.ModuleRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 3 | 2;
|
||||
break;
|
||||
case TableHeap.MethodDefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 3 | 3;
|
||||
break;
|
||||
case TableHeap.TypeSpecTable.Index:
|
||||
token = (token & 0xFFFFFF) << 3 | 4;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (moduleBuilder.bigMemberRefParent)
|
||||
{
|
||||
Write(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)token);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteMethodDefOrRef(int token)
|
||||
{
|
||||
switch (token >> 24)
|
||||
{
|
||||
case TableHeap.MethodDefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 1 | 0;
|
||||
break;
|
||||
case TableHeap.MemberRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 1 | 1;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (moduleBuilder.bigMethodDefOrRef)
|
||||
{
|
||||
Write(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)token);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteHasConstant(int encodedToken)
|
||||
{
|
||||
// NOTE because we've already had to do the encoding (to be able to sort the table)
|
||||
// here we simple write the value
|
||||
if (moduleBuilder.bigHasConstant)
|
||||
{
|
||||
Write(encodedToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)encodedToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteHasSemantics(int encodedToken)
|
||||
{
|
||||
// NOTE because we've already had to do the encoding (to be able to sort the table)
|
||||
// here we simple write the value
|
||||
if (moduleBuilder.bigHasSemantics)
|
||||
{
|
||||
Write(encodedToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)encodedToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteImplementation(int token)
|
||||
{
|
||||
switch (token >> 24)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case TableHeap.FileTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 0;
|
||||
break;
|
||||
case TableHeap.AssemblyRefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 1;
|
||||
break;
|
||||
case TableHeap.ExportedTypeTable.Index:
|
||||
token = (token & 0xFFFFFF) << 2 | 2;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (moduleBuilder.bigImplementation)
|
||||
{
|
||||
Write(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)token);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteTypeOrMethodDef(int encodedToken)
|
||||
{
|
||||
// NOTE because we've already had to do the encoding (to be able to sort the table)
|
||||
// here we simple write the value
|
||||
if (moduleBuilder.bigTypeOrMethodDef)
|
||||
{
|
||||
Write(encodedToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)encodedToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteHasDeclSecurity(int encodedToken)
|
||||
{
|
||||
// NOTE because we've already had to do the encoding (to be able to sort the table)
|
||||
// here we simple write the value
|
||||
if (moduleBuilder.bigHasDeclSecurity)
|
||||
{
|
||||
Write(encodedToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)encodedToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteMemberForwarded(int token)
|
||||
{
|
||||
switch (token >> 24)
|
||||
{
|
||||
case TableHeap.FieldTable.Index:
|
||||
token = (token & 0xFFFFFF) << 1 | 0;
|
||||
break;
|
||||
case TableHeap.MethodDefTable.Index:
|
||||
token = (token & 0xFFFFFF) << 1 | 1;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (moduleBuilder.bigMemberForwarded)
|
||||
{
|
||||
Write(token);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)token);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteHasFieldMarshal(int encodedToken)
|
||||
{
|
||||
// NOTE because we've already had to do the encoding (to be able to sort the table)
|
||||
// here we simple write the value
|
||||
if (moduleBuilder.bigHasFieldMarshal)
|
||||
{
|
||||
Write(encodedToken & 0xFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write((short)encodedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using IKVM.Reflection.Emit;
|
||||
using IKVM.Reflection.Emit.Impl;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Writer
|
||||
{
|
||||
static class ModuleWriter
|
||||
{
|
||||
private const int versionInfoResourceHeaderLength = 0x58;
|
||||
|
||||
internal static void WriteModule(string directory, StrongNameKeyPair keyPair, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ByteBuffer versionInfoData, int entryPointToken)
|
||||
{
|
||||
moduleBuilder.FixupMethodBodyTokens();
|
||||
|
||||
moduleBuilder.Tables.Module.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleBuilder.Guids.Add(Guid.NewGuid()), 0, 0);
|
||||
|
||||
if (moduleBuilder.UserStrings.IsEmpty)
|
||||
{
|
||||
// for compat with Ref.Emit, if there aren't any user strings, we add one
|
||||
moduleBuilder.UserStrings.Add(" ");
|
||||
}
|
||||
|
||||
string fileName = moduleBuilder.fileName;
|
||||
if (directory != null)
|
||||
{
|
||||
fileName = Path.Combine(directory, fileName);
|
||||
}
|
||||
using (FileStream fs = new FileStream(fileName, FileMode.Create))
|
||||
{
|
||||
PEWriter writer = new PEWriter(fs);
|
||||
switch (imageFileMachine)
|
||||
{
|
||||
case ImageFileMachine.I386:
|
||||
writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386;
|
||||
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE;
|
||||
break;
|
||||
case ImageFileMachine.AMD64:
|
||||
writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64;
|
||||
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
|
||||
writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0;
|
||||
writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
|
||||
writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000;
|
||||
writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000;
|
||||
writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000;
|
||||
break;
|
||||
case ImageFileMachine.IA64:
|
||||
writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64;
|
||||
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
|
||||
writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0;
|
||||
writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
|
||||
writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000;
|
||||
writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000;
|
||||
writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("imageFileName");
|
||||
}
|
||||
if (fileKind == PEFileKinds.Dll)
|
||||
{
|
||||
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL;
|
||||
}
|
||||
|
||||
switch (fileKind)
|
||||
{
|
||||
case PEFileKinds.WindowApplication:
|
||||
writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI;
|
||||
break;
|
||||
default:
|
||||
writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI;
|
||||
break;
|
||||
}
|
||||
writer.Headers.OptionalHeader.DllCharacteristics =
|
||||
IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |
|
||||
IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NO_SEH |
|
||||
IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NX_COMPAT |
|
||||
IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;
|
||||
|
||||
CliHeader cliHeader = new CliHeader();
|
||||
cliHeader.Cb = 0x48;
|
||||
cliHeader.MajorRuntimeVersion = 2;
|
||||
cliHeader.MinorRuntimeVersion = 5;
|
||||
if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0)
|
||||
{
|
||||
cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY;
|
||||
}
|
||||
if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0)
|
||||
{
|
||||
cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED;
|
||||
}
|
||||
if (keyPair != null)
|
||||
{
|
||||
cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED;
|
||||
}
|
||||
if (moduleBuilder.IsPseudoToken(entryPointToken))
|
||||
{
|
||||
entryPointToken = moduleBuilder.ResolvePseudoToken(entryPointToken);
|
||||
}
|
||||
cliHeader.EntryPointToken = (uint)entryPointToken;
|
||||
TextSection code = new TextSection(writer, cliHeader, moduleBuilder);
|
||||
|
||||
// Import Directory
|
||||
writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA;
|
||||
writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength;
|
||||
|
||||
// Import Address Table Directory
|
||||
writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA;
|
||||
writer.Headers.OptionalHeader.DataDirectory[12].Size = code.ImportAddressTableLength;
|
||||
|
||||
// COM Descriptor Directory
|
||||
writer.Headers.OptionalHeader.DataDirectory[14].VirtualAddress = code.ComDescriptorRVA;
|
||||
writer.Headers.OptionalHeader.DataDirectory[14].Size = code.ComDescriptorLength;
|
||||
|
||||
// Debug Directory
|
||||
if (code.DebugDirectoryLength != 0)
|
||||
{
|
||||
writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA;
|
||||
writer.Headers.OptionalHeader.DataDirectory[6].Size = code.DebugDirectoryLength;
|
||||
}
|
||||
|
||||
writer.Headers.FileHeader.NumberOfSections = 2;
|
||||
|
||||
if (moduleBuilder.initializedData.Length != 0)
|
||||
{
|
||||
writer.Headers.FileHeader.NumberOfSections++;
|
||||
}
|
||||
|
||||
if (versionInfoData != null)
|
||||
{
|
||||
writer.Headers.FileHeader.NumberOfSections++;
|
||||
}
|
||||
|
||||
SectionHeader text = new SectionHeader();
|
||||
text.Name = ".text";
|
||||
text.VirtualAddress = code.BaseRVA;
|
||||
text.VirtualSize = (uint)code.Length;
|
||||
text.PointerToRawData = code.PointerToRawData;
|
||||
text.SizeOfRawData = writer.ToFileAlignment((uint)code.Length);
|
||||
text.Characteristics = SectionHeader.IMAGE_SCN_CNT_CODE | SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_MEM_READ;
|
||||
|
||||
SectionHeader sdata = new SectionHeader();
|
||||
sdata.Name = ".sdata";
|
||||
sdata.VirtualAddress = text.VirtualAddress + writer.ToSectionAlignment(text.VirtualSize);
|
||||
sdata.VirtualSize = (uint)moduleBuilder.initializedData.Length;
|
||||
sdata.PointerToRawData = text.PointerToRawData + text.SizeOfRawData;
|
||||
sdata.SizeOfRawData = writer.ToFileAlignment((uint)moduleBuilder.initializedData.Length);
|
||||
sdata.Characteristics = SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_MEM_WRITE;
|
||||
|
||||
SectionHeader rsrc = new SectionHeader();
|
||||
rsrc.Name = ".rsrc";
|
||||
rsrc.VirtualAddress = sdata.VirtualAddress + writer.ToSectionAlignment(sdata.VirtualSize);
|
||||
rsrc.PointerToRawData = sdata.PointerToRawData + sdata.SizeOfRawData;
|
||||
if (versionInfoData != null)
|
||||
{
|
||||
rsrc.VirtualSize = (uint)versionInfoData.Length + versionInfoResourceHeaderLength;
|
||||
rsrc.SizeOfRawData = writer.ToFileAlignment((uint)versionInfoData.Length + versionInfoResourceHeaderLength);
|
||||
}
|
||||
rsrc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA;
|
||||
|
||||
if (rsrc.SizeOfRawData != 0)
|
||||
{
|
||||
// Resource Directory
|
||||
writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress;
|
||||
writer.Headers.OptionalHeader.DataDirectory[2].Size = rsrc.VirtualSize;
|
||||
}
|
||||
|
||||
SectionHeader reloc = new SectionHeader();
|
||||
reloc.Name = ".reloc";
|
||||
reloc.VirtualAddress = rsrc.VirtualAddress + writer.ToSectionAlignment(rsrc.VirtualSize);
|
||||
reloc.VirtualSize = 12;
|
||||
reloc.PointerToRawData = rsrc.PointerToRawData + rsrc.SizeOfRawData;
|
||||
reloc.SizeOfRawData = writer.ToFileAlignment(reloc.VirtualSize);
|
||||
reloc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_DISCARDABLE;
|
||||
|
||||
// Base Relocation Directory
|
||||
writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress;
|
||||
writer.Headers.OptionalHeader.DataDirectory[5].Size = reloc.VirtualSize;
|
||||
|
||||
writer.Headers.OptionalHeader.SizeOfCode = text.SizeOfRawData;
|
||||
writer.Headers.OptionalHeader.SizeOfInitializedData = sdata.SizeOfRawData + rsrc.SizeOfRawData + reloc.SizeOfRawData;
|
||||
writer.Headers.OptionalHeader.SizeOfUninitializedData = 0;
|
||||
writer.Headers.OptionalHeader.SizeOfImage = reloc.VirtualAddress + writer.ToSectionAlignment(reloc.VirtualSize);
|
||||
writer.Headers.OptionalHeader.SizeOfHeaders = text.PointerToRawData;
|
||||
writer.Headers.OptionalHeader.BaseOfCode = code.BaseRVA;
|
||||
writer.Headers.OptionalHeader.BaseOfData = sdata.VirtualAddress;
|
||||
|
||||
if (imageFileMachine == ImageFileMachine.IA64)
|
||||
{
|
||||
// apparently for IA64 AddressOfEntryPoint points to the address of the entry point
|
||||
// (i.e. there is an additional layer of indirection), so we add the offset to the pointer
|
||||
writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + 0x20;
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA;
|
||||
}
|
||||
|
||||
writer.WritePEHeaders();
|
||||
writer.WriteSectionHeader(text);
|
||||
if (sdata.SizeOfRawData != 0)
|
||||
{
|
||||
writer.WriteSectionHeader(sdata);
|
||||
}
|
||||
if (rsrc.SizeOfRawData != 0)
|
||||
{
|
||||
writer.WriteSectionHeader(rsrc);
|
||||
}
|
||||
writer.WriteSectionHeader(reloc);
|
||||
|
||||
MetadataWriter mw = new MetadataWriter(moduleBuilder, fs);
|
||||
|
||||
fs.Seek(text.PointerToRawData, SeekOrigin.Begin);
|
||||
code.Write(mw, (int)sdata.VirtualAddress);
|
||||
|
||||
fs.Seek(sdata.PointerToRawData, SeekOrigin.Begin);
|
||||
mw.Write(moduleBuilder.initializedData);
|
||||
|
||||
if (versionInfoData != null)
|
||||
{
|
||||
fs.Seek(rsrc.PointerToRawData, SeekOrigin.Begin);
|
||||
WriteVersionInfoResource(mw, (int)rsrc.VirtualAddress, versionInfoData);
|
||||
}
|
||||
|
||||
fs.Seek(reloc.PointerToRawData, SeekOrigin.Begin);
|
||||
// .reloc section
|
||||
uint pageRVA = code.StartupStubRVA & ~0xFFFU;
|
||||
mw.Write(pageRVA); // PageRVA
|
||||
mw.Write(0x000C); // Block Size
|
||||
if (imageFileMachine == ImageFileMachine.I386)
|
||||
{
|
||||
mw.Write(0x3000 + code.StartupStubRVA - pageRVA + 2); // Type / Offset + padding
|
||||
}
|
||||
else if (imageFileMachine == ImageFileMachine.AMD64)
|
||||
{
|
||||
mw.Write(0xA000 + code.StartupStubRVA - pageRVA + 2); // Type / Offset + padding
|
||||
}
|
||||
else if (imageFileMachine == ImageFileMachine.IA64)
|
||||
{
|
||||
mw.Write((short)(0xA000 + code.StartupStubRVA - pageRVA + 0x20)); // Type / Offset
|
||||
mw.Write((short)(0xA000 + code.StartupStubRVA - pageRVA + 0x28)); // Type / Offset
|
||||
}
|
||||
|
||||
// file alignment
|
||||
mw.Write(new byte[writer.Headers.OptionalHeader.FileAlignment - reloc.VirtualSize]);
|
||||
|
||||
// do the strong naming
|
||||
if (keyPair != null)
|
||||
{
|
||||
StrongName(fs, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength);
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleBuilder.symbolWriter != null)
|
||||
{
|
||||
moduleBuilder.WriteSymbolTokenMap();
|
||||
moduleBuilder.symbolWriter.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void StrongName(FileStream fs, StrongNameKeyPair keyPair, uint headerLength, uint textSectionFileOffset, uint strongNameSignatureFileOffset, uint strongNameSignatureLength)
|
||||
{
|
||||
SHA1Managed hash = new SHA1Managed();
|
||||
using (CryptoStream cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write))
|
||||
{
|
||||
fs.Seek(0, SeekOrigin.Begin);
|
||||
byte[] buf = new byte[8192];
|
||||
HashChunk(fs, cs, buf, (int)headerLength);
|
||||
fs.Seek(textSectionFileOffset, SeekOrigin.Begin);
|
||||
HashChunk(fs, cs, buf, (int)(strongNameSignatureFileOffset - textSectionFileOffset));
|
||||
fs.Seek(strongNameSignatureLength, SeekOrigin.Current);
|
||||
HashChunk(fs, cs, buf, (int)(fs.Length - (strongNameSignatureFileOffset + strongNameSignatureLength)));
|
||||
}
|
||||
using (RSA rsa = CryptoHack.CreateRSA(keyPair))
|
||||
{
|
||||
RSAPKCS1SignatureFormatter sign = new RSAPKCS1SignatureFormatter(rsa);
|
||||
sign.SetHashAlgorithm("SHA1");
|
||||
byte[] signature = sign.CreateSignature(hash.Hash);
|
||||
Array.Reverse(signature);
|
||||
Debug.Assert(signature.Length == strongNameSignatureLength);
|
||||
fs.Seek(strongNameSignatureFileOffset, SeekOrigin.Begin);
|
||||
fs.Write(signature, 0, signature.Length);
|
||||
}
|
||||
|
||||
// compute the PE checksum
|
||||
fs.Seek(0, SeekOrigin.Begin);
|
||||
int count = (int)fs.Length / 4;
|
||||
BinaryReader br = new BinaryReader(fs);
|
||||
long sum = 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
sum += br.ReadUInt32();
|
||||
int carry = (int)(sum >> 32);
|
||||
sum &= 0xFFFFFFFFU;
|
||||
sum += carry;
|
||||
}
|
||||
while ((sum >> 16) != 0)
|
||||
{
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
sum += fs.Length;
|
||||
|
||||
// write the PE checksum, note that it is always of offset 0xD8 in the file
|
||||
ByteBuffer bb = new ByteBuffer(4);
|
||||
bb.Write((int)sum);
|
||||
fs.Seek(0xD8, SeekOrigin.Begin);
|
||||
bb.WriteTo(fs);
|
||||
}
|
||||
|
||||
internal static void HashChunk(FileStream fs, CryptoStream cs, byte[] buf, int length)
|
||||
{
|
||||
while (length > 0)
|
||||
{
|
||||
int read = fs.Read(buf, 0, Math.Min(buf.Length, length));
|
||||
cs.Write(buf, 0, read);
|
||||
length -= read;
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteVersionInfoResource(MetadataWriter mw, int rsrcRVA, ByteBuffer versionInfoData)
|
||||
{
|
||||
mw.Write(new byte[] {
|
||||
0x00, 0x00, 0x00, 0x00, // Characteristics
|
||||
0x00, 0x00, 0x00, 0x00, // Time/Date Stamp
|
||||
0x00, 0x00, // Major Version
|
||||
0x00, 0x00, // Minor Version
|
||||
0x00, 0x00, // Number of Name Entries
|
||||
0x01, 0x00, // Number of ID Entries
|
||||
|
||||
// Resource Directory Entry
|
||||
0x10, 0x00, 0x00, 0x00, // Integer ID
|
||||
0x18, 0x00, 0x00, 0x80, // Subdirectory RVA (offset 0x18)
|
||||
|
||||
// Resource Directory Table (at offset 0x18)
|
||||
0x00, 0x00, 0x00, 0x00, // Characterics
|
||||
0x00, 0x00, 0x00, 0x00, // Time/Date Stamp
|
||||
0x00, 0x00, // Major Version
|
||||
0x00, 0x00, // Minor Version
|
||||
0x00, 0x00, // Number of Name Entries
|
||||
0x01, 0x00, // Number of ID Entries
|
||||
|
||||
// Resource Directory Entry
|
||||
0x01, 0x00, 0x00, 0x00, // Integer ID
|
||||
0x30, 0x00, 0x00, 0x80, // Subdirectory RVA (offset 0x30)
|
||||
|
||||
// Resource Directory Table (at offset 0x30)
|
||||
0x00, 0x00, 0x00, 0x00, // Characterics
|
||||
0x00, 0x00, 0x00, 0x00, // Time/Date Stamp
|
||||
0x00, 0x00, // Major Version
|
||||
0x00, 0x00, // Minor Version
|
||||
0x00, 0x00, // Number of Name Entries
|
||||
0x01, 0x00, // Number of ID Entries
|
||||
|
||||
// Resource Directory Entry
|
||||
0x00, 0x00, 0x00, 0x00, // Integer ID
|
||||
0x48, 0x00, 0x00, 0x00, // Date Entry RVA (offset 0x48)
|
||||
});
|
||||
|
||||
// Data Entry (at offset 0x48)
|
||||
mw.Write(versionInfoResourceHeaderLength + rsrcRVA); // Data RVA
|
||||
mw.Write(versionInfoData.Length); // Size
|
||||
mw.Write(0); // Codepage
|
||||
mw.Write(0); // Reserved
|
||||
|
||||
mw.Write(versionInfoData);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
using BYTE = System.Byte;
|
||||
using WORD = System.UInt16;
|
||||
using DWORD = System.UInt32;
|
||||
using ULONGLONG = System.UInt64;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Writer
|
||||
{
|
||||
sealed class PEWriter
|
||||
{
|
||||
private readonly BinaryWriter bw;
|
||||
private readonly IMAGE_NT_HEADERS hdr = new IMAGE_NT_HEADERS();
|
||||
|
||||
internal PEWriter(Stream stream)
|
||||
{
|
||||
bw = new BinaryWriter(stream);
|
||||
WriteMSDOSHeader();
|
||||
}
|
||||
|
||||
public IMAGE_NT_HEADERS Headers
|
||||
{
|
||||
get { return hdr; }
|
||||
}
|
||||
|
||||
public uint HeaderSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return (uint)
|
||||
((8 * 16) + // MSDOS header
|
||||
4 + // signature
|
||||
20 + // IMAGE_FILE_HEADER
|
||||
hdr.FileHeader.SizeOfOptionalHeader +
|
||||
hdr.FileHeader.NumberOfSections * 40);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteMSDOSHeader()
|
||||
{
|
||||
bw.Write(new byte[] {
|
||||
0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD,
|
||||
0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68,
|
||||
0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72,
|
||||
0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F,
|
||||
0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E,
|
||||
0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20,
|
||||
0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
|
||||
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
});
|
||||
}
|
||||
|
||||
internal void WritePEHeaders()
|
||||
{
|
||||
bw.Write(hdr.Signature);
|
||||
|
||||
// IMAGE_FILE_HEADER
|
||||
bw.Write(hdr.FileHeader.Machine);
|
||||
bw.Write(hdr.FileHeader.NumberOfSections);
|
||||
bw.Write(hdr.FileHeader.TimeDateStamp);
|
||||
bw.Write(hdr.FileHeader.PointerToSymbolTable);
|
||||
bw.Write(hdr.FileHeader.NumberOfSymbols);
|
||||
bw.Write(hdr.FileHeader.SizeOfOptionalHeader);
|
||||
bw.Write(hdr.FileHeader.Characteristics);
|
||||
|
||||
// IMAGE_OPTIONAL_HEADER
|
||||
hdr.OptionalHeader.Write(bw);
|
||||
}
|
||||
|
||||
internal void WriteSectionHeader(SectionHeader sectionHeader)
|
||||
{
|
||||
byte[] name = new byte[8];
|
||||
System.Text.Encoding.UTF8.GetBytes(sectionHeader.Name, 0, sectionHeader.Name.Length, name, 0);
|
||||
bw.Write(name);
|
||||
bw.Write(sectionHeader.VirtualSize);
|
||||
bw.Write(sectionHeader.VirtualAddress);
|
||||
bw.Write(sectionHeader.SizeOfRawData);
|
||||
bw.Write(sectionHeader.PointerToRawData);
|
||||
bw.Write(sectionHeader.PointerToRelocations);
|
||||
bw.Write(sectionHeader.PointerToLinenumbers);
|
||||
bw.Write(sectionHeader.NumberOfRelocations);
|
||||
bw.Write(sectionHeader.NumberOfLinenumbers);
|
||||
bw.Write(sectionHeader.Characteristics);
|
||||
}
|
||||
|
||||
internal uint ToFileAlignment(uint p)
|
||||
{
|
||||
return (p + (Headers.OptionalHeader.FileAlignment - 1)) & ~(Headers.OptionalHeader.FileAlignment - 1);
|
||||
}
|
||||
|
||||
internal uint ToSectionAlignment(uint p)
|
||||
{
|
||||
return (p + (Headers.OptionalHeader.SectionAlignment - 1)) & ~(Headers.OptionalHeader.SectionAlignment - 1);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class IMAGE_NT_HEADERS
|
||||
{
|
||||
public DWORD Signature = 0x00004550; // "PE\0\0"
|
||||
public IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER();
|
||||
public IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER();
|
||||
}
|
||||
|
||||
sealed class IMAGE_FILE_HEADER
|
||||
{
|
||||
public const WORD IMAGE_FILE_MACHINE_I386 = 0x014c;
|
||||
public const WORD IMAGE_FILE_MACHINE_IA64 = 0x0200;
|
||||
public const WORD IMAGE_FILE_MACHINE_AMD64 = 0x8664;
|
||||
|
||||
public const WORD IMAGE_FILE_32BIT_MACHINE = 0x0100;
|
||||
public const WORD IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
|
||||
public const WORD IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
|
||||
public const WORD IMAGE_FILE_DLL = 0x2000;
|
||||
|
||||
public WORD Machine;
|
||||
public WORD NumberOfSections;
|
||||
public DWORD TimeDateStamp = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
|
||||
public DWORD PointerToSymbolTable = 0;
|
||||
public DWORD NumberOfSymbols = 0;
|
||||
public WORD SizeOfOptionalHeader = 0xE0;
|
||||
public WORD Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
|
||||
}
|
||||
|
||||
sealed class IMAGE_OPTIONAL_HEADER
|
||||
{
|
||||
public const WORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
|
||||
public const WORD IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
|
||||
|
||||
public const WORD IMAGE_SUBSYSTEM_WINDOWS_GUI = 2;
|
||||
public const WORD IMAGE_SUBSYSTEM_WINDOWS_CUI = 3;
|
||||
|
||||
public const WORD IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040;
|
||||
public const WORD IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100;
|
||||
public const WORD IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400;
|
||||
public const WORD IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000;
|
||||
|
||||
public WORD Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
|
||||
public BYTE MajorLinkerVersion = 8;
|
||||
public BYTE MinorLinkerVersion = 0;
|
||||
public DWORD SizeOfCode;
|
||||
public DWORD SizeOfInitializedData;
|
||||
public DWORD SizeOfUninitializedData;
|
||||
public DWORD AddressOfEntryPoint;
|
||||
public DWORD BaseOfCode;
|
||||
public DWORD BaseOfData;
|
||||
public ULONGLONG ImageBase = 0x00400000;
|
||||
public DWORD SectionAlignment = 0x2000;
|
||||
public DWORD FileAlignment = 0x200;
|
||||
public WORD MajorOperatingSystemVersion = 4;
|
||||
public WORD MinorOperatingSystemVersion = 0;
|
||||
public WORD MajorImageVersion = 0;
|
||||
public WORD MinorImageVersion = 0;
|
||||
public WORD MajorSubsystemVersion = 4;
|
||||
public WORD MinorSubsystemVersion = 0;
|
||||
public DWORD Win32VersionValue = 0;
|
||||
public DWORD SizeOfImage;
|
||||
public DWORD SizeOfHeaders;
|
||||
public DWORD CheckSum = 0;
|
||||
public WORD Subsystem;
|
||||
public WORD DllCharacteristics;
|
||||
public ULONGLONG SizeOfStackReserve = 0x100000;
|
||||
public ULONGLONG SizeOfStackCommit = 0x1000;
|
||||
public ULONGLONG SizeOfHeapReserve = 0x100000;
|
||||
public ULONGLONG SizeOfHeapCommit = 0x1000;
|
||||
public DWORD LoaderFlags = 0;
|
||||
public DWORD NumberOfRvaAndSizes = 16;
|
||||
public IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16];
|
||||
|
||||
internal void Write(BinaryWriter bw)
|
||||
{
|
||||
bw.Write(Magic);
|
||||
bw.Write(MajorLinkerVersion);
|
||||
bw.Write(MinorLinkerVersion);
|
||||
bw.Write(SizeOfCode);
|
||||
bw.Write(SizeOfInitializedData);
|
||||
bw.Write(SizeOfUninitializedData);
|
||||
bw.Write(AddressOfEntryPoint);
|
||||
bw.Write(BaseOfCode);
|
||||
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
bw.Write(BaseOfData);
|
||||
bw.Write((DWORD)ImageBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.Write(ImageBase);
|
||||
}
|
||||
bw.Write(SectionAlignment);
|
||||
bw.Write(FileAlignment);
|
||||
bw.Write(MajorOperatingSystemVersion);
|
||||
bw.Write(MinorOperatingSystemVersion);
|
||||
bw.Write(MajorImageVersion);
|
||||
bw.Write(MinorImageVersion);
|
||||
bw.Write(MajorSubsystemVersion);
|
||||
bw.Write(MinorSubsystemVersion);
|
||||
bw.Write(Win32VersionValue);
|
||||
bw.Write(SizeOfImage);
|
||||
bw.Write(SizeOfHeaders);
|
||||
bw.Write(CheckSum);
|
||||
bw.Write(Subsystem);
|
||||
bw.Write(DllCharacteristics);
|
||||
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
bw.Write((DWORD)SizeOfStackReserve);
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.Write(SizeOfStackReserve);
|
||||
}
|
||||
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
bw.Write((DWORD)SizeOfStackCommit);
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.Write(SizeOfStackCommit);
|
||||
}
|
||||
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
bw.Write((DWORD)SizeOfHeapReserve);
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.Write(SizeOfHeapReserve);
|
||||
}
|
||||
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
bw.Write((DWORD)SizeOfHeapCommit);
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.Write(SizeOfHeapCommit);
|
||||
}
|
||||
bw.Write(LoaderFlags);
|
||||
bw.Write(NumberOfRvaAndSizes);
|
||||
for (int i = 0; i < DataDirectory.Length; i++)
|
||||
{
|
||||
bw.Write(DataDirectory[i].VirtualAddress);
|
||||
bw.Write(DataDirectory[i].Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IMAGE_DATA_DIRECTORY
|
||||
{
|
||||
public DWORD VirtualAddress;
|
||||
public DWORD Size;
|
||||
}
|
||||
|
||||
class SectionHeader
|
||||
{
|
||||
public const DWORD IMAGE_SCN_CNT_CODE = 0x00000020;
|
||||
public const DWORD IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
|
||||
public const DWORD IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
|
||||
public const DWORD IMAGE_SCN_MEM_EXECUTE = 0x20000000;
|
||||
public const DWORD IMAGE_SCN_MEM_READ = 0x40000000;
|
||||
public const DWORD IMAGE_SCN_MEM_WRITE = 0x80000000;
|
||||
|
||||
public string Name; // 8 byte UTF8 encoded 0-padded
|
||||
public DWORD VirtualSize;
|
||||
public DWORD VirtualAddress;
|
||||
public DWORD SizeOfRawData;
|
||||
public DWORD PointerToRawData;
|
||||
public DWORD PointerToRelocations = 0;
|
||||
public DWORD PointerToLinenumbers = 0;
|
||||
public WORD NumberOfRelocations = 0;
|
||||
public WORD NumberOfLinenumbers = 0;
|
||||
public DWORD Characteristics;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,490 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using IKVM.Reflection.Emit.Impl;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Writer
|
||||
{
|
||||
sealed class TextSection
|
||||
{
|
||||
private readonly PEWriter peWriter;
|
||||
private readonly CliHeader cliHeader;
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
|
||||
internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder)
|
||||
{
|
||||
this.peWriter = peWriter;
|
||||
this.cliHeader = cliHeader;
|
||||
this.moduleBuilder = moduleBuilder;
|
||||
moduleBuilder.Freeze();
|
||||
}
|
||||
|
||||
internal uint PointerToRawData
|
||||
{
|
||||
get { return peWriter.ToFileAlignment(peWriter.HeaderSize); }
|
||||
}
|
||||
|
||||
internal uint BaseRVA
|
||||
{
|
||||
get { return 0x2000; }
|
||||
}
|
||||
|
||||
internal uint ImportAddressTableRVA
|
||||
{
|
||||
get { return BaseRVA; }
|
||||
}
|
||||
|
||||
internal uint ImportAddressTableLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal uint ComDescriptorRVA
|
||||
{
|
||||
get { return ImportAddressTableRVA + ImportAddressTableLength; }
|
||||
}
|
||||
|
||||
internal uint ComDescriptorLength
|
||||
{
|
||||
get { return cliHeader.Cb; }
|
||||
}
|
||||
|
||||
internal uint MethodBodiesRVA
|
||||
{
|
||||
get { return (ComDescriptorRVA + ComDescriptorLength + 7) & ~7U; }
|
||||
}
|
||||
|
||||
private uint MethodBodiesLength
|
||||
{
|
||||
get { return (uint)moduleBuilder.methodBodies.Length; }
|
||||
}
|
||||
|
||||
private uint ResourcesRVA
|
||||
{
|
||||
get
|
||||
{
|
||||
if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
return (MethodBodiesRVA + MethodBodiesLength + 3) & ~3U;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (MethodBodiesRVA + MethodBodiesLength + 15) & ~15U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint ResourcesLength
|
||||
{
|
||||
get { return (uint)moduleBuilder.manifestResources.Length; }
|
||||
}
|
||||
|
||||
internal uint StrongNameSignatureRVA
|
||||
{
|
||||
get
|
||||
{
|
||||
return (ResourcesRVA + ResourcesLength + 3) & ~3U;
|
||||
}
|
||||
}
|
||||
|
||||
internal uint StrongNameSignatureLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED) != 0)
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint MetadataRVA
|
||||
{
|
||||
get
|
||||
{
|
||||
return (StrongNameSignatureRVA + StrongNameSignatureLength + 3) & ~3U;
|
||||
}
|
||||
}
|
||||
|
||||
private uint MetadataLength
|
||||
{
|
||||
get { return (uint)moduleBuilder.MetadataLength; }
|
||||
}
|
||||
|
||||
internal uint DebugDirectoryRVA
|
||||
{
|
||||
get { return MetadataRVA + MetadataLength; }
|
||||
}
|
||||
|
||||
internal uint DebugDirectoryLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (moduleBuilder.symbolWriter != null)
|
||||
{
|
||||
return 28;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private uint DebugDirectoryContentsLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (moduleBuilder.symbolWriter != null)
|
||||
{
|
||||
PdbSupport.IMAGE_DEBUG_DIRECTORY idd = new PdbSupport.IMAGE_DEBUG_DIRECTORY();
|
||||
return (uint)PdbSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd).Length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal uint ImportDirectoryRVA
|
||||
{
|
||||
get { return (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength + 3) & ~3U; }
|
||||
}
|
||||
|
||||
internal uint ImportDirectoryLength
|
||||
{
|
||||
get { return (ImportHintNameTableRVA - ImportDirectoryRVA) + 27; }
|
||||
}
|
||||
|
||||
private uint ImportHintNameTableRVA
|
||||
{
|
||||
get
|
||||
{
|
||||
if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
return (ImportDirectoryRVA + 48 + 15) & ~15U;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (ImportDirectoryRVA + 48 + 4 + 15) & ~15U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal uint StartupStubRVA
|
||||
{
|
||||
get
|
||||
{
|
||||
if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
|
||||
{
|
||||
return (ImportDirectoryRVA + ImportDirectoryLength + 15U) & ~15U;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the additional 2 bytes padding are to align the address in the jump (which is a relocation fixup)
|
||||
return 2 + ((ImportDirectoryRVA + ImportDirectoryLength + 3U) & ~3U);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal uint StartupStubLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64)
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
|
||||
{
|
||||
return 48;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteRVA(MetadataWriter mw, uint rva)
|
||||
{
|
||||
if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
mw.Write(rva);
|
||||
}
|
||||
else
|
||||
{
|
||||
mw.Write((ulong)rva);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Write(MetadataWriter mw, int sdataRVA)
|
||||
{
|
||||
// Now that we're ready to start writing, we need to do some fix ups
|
||||
moduleBuilder.Tables.MethodDef.Fixup(this);
|
||||
moduleBuilder.Tables.MethodImpl.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.MethodSemantics.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.InterfaceImpl.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.Constant.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.FieldMarshal.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.DeclSecurity.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.CustomAttribute.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.FieldLayout.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.FieldRVA.Fixup(moduleBuilder, sdataRVA);
|
||||
moduleBuilder.Tables.ImplMap.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.GenericParam.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.MethodSpec.Fixup(moduleBuilder);
|
||||
moduleBuilder.Tables.GenericParamConstraint.Fixup(moduleBuilder);
|
||||
|
||||
// Import Address Table
|
||||
AssertRVA(mw, ImportAddressTableRVA);
|
||||
WriteRVA(mw, ImportHintNameTableRVA);
|
||||
WriteRVA(mw, 0);
|
||||
|
||||
// CLI Header
|
||||
AssertRVA(mw, ComDescriptorRVA);
|
||||
cliHeader.MetaDataRVA = MetadataRVA;
|
||||
cliHeader.MetaDataSize = MetadataLength;
|
||||
if (ResourcesLength != 0)
|
||||
{
|
||||
cliHeader.ResourcesRVA = ResourcesRVA;
|
||||
cliHeader.ResourcesSize = ResourcesLength;
|
||||
}
|
||||
if (StrongNameSignatureLength != 0)
|
||||
{
|
||||
cliHeader.StrongNameSignatureRVA = StrongNameSignatureRVA;
|
||||
cliHeader.StrongNameSignatureSize = StrongNameSignatureLength;
|
||||
}
|
||||
cliHeader.Write(mw);
|
||||
|
||||
// alignment padding
|
||||
for (int i = (int)(MethodBodiesRVA - (ComDescriptorRVA + ComDescriptorLength)); i > 0; i--)
|
||||
{
|
||||
mw.Write((byte)0);
|
||||
}
|
||||
|
||||
// Method Bodies
|
||||
mw.Write(moduleBuilder.methodBodies);
|
||||
|
||||
// alignment padding
|
||||
for (int i = (int)(ResourcesRVA - (MethodBodiesRVA + MethodBodiesLength)); i > 0; i--)
|
||||
{
|
||||
mw.Write((byte)0);
|
||||
}
|
||||
|
||||
// Resources
|
||||
mw.Write(moduleBuilder.manifestResources);
|
||||
|
||||
// The strong name signature live here (if it exists), but it will written later
|
||||
// and the following alignment padding will take care of reserving the space.
|
||||
|
||||
// alignment padding
|
||||
for (int i = (int)(MetadataRVA - (ResourcesRVA + ResourcesLength)); i > 0; i--)
|
||||
{
|
||||
mw.Write((byte)0);
|
||||
}
|
||||
|
||||
// Metadata
|
||||
AssertRVA(mw, MetadataRVA);
|
||||
moduleBuilder.WriteMetadata(mw);
|
||||
|
||||
// Debug Directory
|
||||
AssertRVA(mw, DebugDirectoryRVA);
|
||||
WriteDebugDirectory(mw);
|
||||
|
||||
// alignment padding
|
||||
for (int i = (int)(ImportDirectoryRVA - (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength)); i > 0; i--)
|
||||
{
|
||||
mw.Write((byte)0);
|
||||
}
|
||||
|
||||
// Import Directory
|
||||
AssertRVA(mw, ImportDirectoryRVA);
|
||||
WriteImportDirectory(mw);
|
||||
|
||||
// alignment padding
|
||||
for (int i = (int)(StartupStubRVA - (ImportDirectoryRVA + ImportDirectoryLength)); i > 0; i--)
|
||||
{
|
||||
mw.Write((byte)0);
|
||||
}
|
||||
|
||||
// Startup Stub
|
||||
AssertRVA(mw, StartupStubRVA);
|
||||
if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64)
|
||||
{
|
||||
/*
|
||||
* 48 A1 00 20 40 00 00 00 00 00 mov rax,qword ptr [0000000000402000h]
|
||||
* FF E0 jmp rax
|
||||
*/
|
||||
mw.Write((ushort)0xA148);
|
||||
mw.Write(peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA);
|
||||
mw.Write((ushort)0xE0FF);
|
||||
}
|
||||
else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
|
||||
{
|
||||
mw.Write(new byte[] {
|
||||
0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40, 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50, 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00
|
||||
});
|
||||
mw.Write(peWriter.Headers.OptionalHeader.ImageBase + StartupStubRVA);
|
||||
mw.Write(peWriter.Headers.OptionalHeader.ImageBase + BaseRVA);
|
||||
}
|
||||
else
|
||||
{
|
||||
mw.Write((ushort)0x25FF);
|
||||
mw.Write((uint)peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void AssertRVA(MetadataWriter mw, uint rva)
|
||||
{
|
||||
Debug.Assert(mw.Position - PointerToRawData + BaseRVA == rva);
|
||||
}
|
||||
|
||||
private void WriteDebugDirectory(MetadataWriter mw)
|
||||
{
|
||||
if (moduleBuilder.symbolWriter != null)
|
||||
{
|
||||
PdbSupport.IMAGE_DEBUG_DIRECTORY idd = new PdbSupport.IMAGE_DEBUG_DIRECTORY();
|
||||
idd.Characteristics = 0;
|
||||
idd.TimeDateStamp = peWriter.Headers.FileHeader.TimeDateStamp;
|
||||
byte[] buf = PdbSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd);
|
||||
idd.PointerToRawData = (DebugDirectoryRVA - BaseRVA) + DebugDirectoryLength + PointerToRawData;
|
||||
mw.Write(idd.Characteristics);
|
||||
mw.Write(idd.TimeDateStamp);
|
||||
mw.Write(idd.MajorVersion);
|
||||
mw.Write(idd.MinorVersion);
|
||||
mw.Write(idd.Type);
|
||||
mw.Write(idd.SizeOfData);
|
||||
mw.Write(idd.AddressOfRawData);
|
||||
mw.Write(idd.PointerToRawData);
|
||||
mw.Write(buf);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteImportDirectory(MetadataWriter mw)
|
||||
{
|
||||
mw.Write(ImportDirectoryRVA + 40); // ImportLookupTable
|
||||
mw.Write(0); // DateTimeStamp
|
||||
mw.Write(0); // ForwarderChain
|
||||
mw.Write(ImportHintNameTableRVA + 14); // Name
|
||||
mw.Write(ImportAddressTableRVA);
|
||||
mw.Write(new byte[20]);
|
||||
// Import Lookup Table
|
||||
mw.Write(ImportHintNameTableRVA); // Hint/Name Table RVA
|
||||
int size = 48;
|
||||
if (peWriter.Headers.FileHeader.Machine != IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
size += 4;
|
||||
mw.Write(0);
|
||||
}
|
||||
mw.Write(0);
|
||||
|
||||
// alignment padding
|
||||
for (int i = (int)(ImportHintNameTableRVA - (ImportDirectoryRVA + size)); i > 0; i--)
|
||||
{
|
||||
mw.Write((byte)0);
|
||||
}
|
||||
|
||||
// Hint/Name Table
|
||||
AssertRVA(mw, ImportHintNameTableRVA);
|
||||
mw.Write((ushort)0); // Hint
|
||||
if ((peWriter.Headers.FileHeader.Characteristics & IMAGE_FILE_HEADER.IMAGE_FILE_DLL) != 0)
|
||||
{
|
||||
mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorDllMain"));
|
||||
}
|
||||
else
|
||||
{
|
||||
mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorExeMain"));
|
||||
}
|
||||
mw.Write((byte)0);
|
||||
// Name
|
||||
mw.Write(System.Text.Encoding.ASCII.GetBytes("mscoree.dll"));
|
||||
mw.Write((ushort)0);
|
||||
}
|
||||
|
||||
internal int Length
|
||||
{
|
||||
get { return (int)(StartupStubRVA - BaseRVA + StartupStubLength); }
|
||||
}
|
||||
}
|
||||
|
||||
class CliHeader
|
||||
{
|
||||
internal const uint COMIMAGE_FLAGS_ILONLY = 0x00000001;
|
||||
internal const uint COMIMAGE_FLAGS_32BITREQUIRED = 0x00000002;
|
||||
internal const uint COMIMAGE_FLAGS_STRONGNAMESIGNED = 0x00000008;
|
||||
|
||||
internal uint Cb = 0x48;
|
||||
internal ushort MajorRuntimeVersion;
|
||||
internal ushort MinorRuntimeVersion;
|
||||
internal uint MetaDataRVA;
|
||||
internal uint MetaDataSize;
|
||||
internal uint Flags;
|
||||
internal uint EntryPointToken;
|
||||
internal uint ResourcesRVA;
|
||||
internal uint ResourcesSize;
|
||||
internal uint StrongNameSignatureRVA;
|
||||
internal uint StrongNameSignatureSize;
|
||||
internal ulong CodeManagerTable = 0;
|
||||
internal uint VTableFixupsRVA = 0;
|
||||
internal uint VTableFixupsSize = 0;
|
||||
internal ulong ExportAddressTableJumps = 0;
|
||||
internal ulong ManagedNativeHeader = 0;
|
||||
|
||||
internal void Write(MetadataWriter mw)
|
||||
{
|
||||
mw.Write(Cb);
|
||||
mw.Write(MajorRuntimeVersion);
|
||||
mw.Write(MinorRuntimeVersion);
|
||||
mw.Write(MetaDataRVA);
|
||||
mw.Write(MetaDataSize);
|
||||
mw.Write(Flags);
|
||||
mw.Write(EntryPointToken);
|
||||
mw.Write(ResourcesRVA);
|
||||
mw.Write(ResourcesSize);
|
||||
mw.Write(StrongNameSignatureRVA);
|
||||
mw.Write(StrongNameSignatureSize);
|
||||
mw.Write(CodeManagerTable);
|
||||
mw.Write(VTableFixupsRVA);
|
||||
mw.Write(VTableFixupsSize);
|
||||
mw.Write(ExportAddressTableJumps);
|
||||
mw.Write(ManagedNativeHeader);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
Copyright (C) 2008 Jeroen Frijters
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Globalization;
|
||||
|
||||
namespace IKVM.Reflection.Emit.Writer
|
||||
{
|
||||
sealed class VersionInfo
|
||||
{
|
||||
private AssemblyName name;
|
||||
private string fileName;
|
||||
private string copyright;
|
||||
private string trademark;
|
||||
private string product;
|
||||
private string company;
|
||||
private string description;
|
||||
private string title;
|
||||
private string informationalVersion;
|
||||
private string culture;
|
||||
private string fileVersion;
|
||||
|
||||
internal void SetName(AssemblyName name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
internal void SetFileName(string assemblyFileName)
|
||||
{
|
||||
this.fileName = assemblyFileName;
|
||||
}
|
||||
|
||||
internal void SetAttribute(CustomAttributeBuilder cab)
|
||||
{
|
||||
Type type = cab.Constructor.DeclaringType;
|
||||
if (type == typeof(AssemblyCopyrightAttribute))
|
||||
{
|
||||
copyright = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
else if (type == typeof(AssemblyTrademarkAttribute))
|
||||
{
|
||||
trademark = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
else if (type == typeof(AssemblyProductAttribute))
|
||||
{
|
||||
product = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
else if (type == typeof(AssemblyCompanyAttribute))
|
||||
{
|
||||
company = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
else if (type == typeof(AssemblyDescriptionAttribute))
|
||||
{
|
||||
description = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
else if (type == typeof(AssemblyTitleAttribute))
|
||||
{
|
||||
title = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
else if (type == typeof(AssemblyInformationalVersionAttribute))
|
||||
{
|
||||
informationalVersion = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
else if (type == typeof(AssemblyCultureAttribute))
|
||||
{
|
||||
culture = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
else if (type == typeof(AssemblyFileVersionAttribute))
|
||||
{
|
||||
fileVersion = (string)cab.GetConstructorArgument(0);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Write(ByteBuffer bb)
|
||||
{
|
||||
if (fileVersion == null)
|
||||
{
|
||||
if (name.Version != null)
|
||||
{
|
||||
fileVersion = name.Version.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
fileVersion = "0.0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
int codepage = 1200; // Unicode codepage
|
||||
int lcid = 0x7f;
|
||||
if (name.CultureInfo != null)
|
||||
{
|
||||
lcid = name.CultureInfo.LCID;
|
||||
}
|
||||
if (culture != null)
|
||||
{
|
||||
lcid = new CultureInfo(culture).LCID;
|
||||
}
|
||||
|
||||
Version filever = new Version(fileVersion);
|
||||
int fileVersionMajor = filever.Major;
|
||||
int fileVersionMinor = filever.Minor;
|
||||
int fileVersionBuild = filever.Build;
|
||||
int fileVersionRevision = filever.Revision;
|
||||
|
||||
int productVersionMajor = 0;
|
||||
int productVersionMinor = 0;
|
||||
int productVersionBuild = 0;
|
||||
int productVersionRevision = 0;
|
||||
if (informationalVersion != null)
|
||||
{
|
||||
Version productver = new Version(informationalVersion);
|
||||
productVersionMajor = productver.Major;
|
||||
productVersionMinor = productver.Minor;
|
||||
productVersionBuild = productver.Build;
|
||||
productVersionRevision = productver.Revision;
|
||||
}
|
||||
|
||||
ByteBuffer stringTable = new ByteBuffer(512);
|
||||
stringTable.Write((short)0); // wLength (placeholder)
|
||||
stringTable.Write((short)0); // wValueLength
|
||||
stringTable.Write((short)1); // wType
|
||||
WriteUTF16Z(stringTable, string.Format("{0:x4}{1:x4}", lcid, codepage));
|
||||
stringTable.Align(4);
|
||||
|
||||
WriteString(stringTable, "Comments", description);
|
||||
WriteString(stringTable, "CompanyName", company);
|
||||
WriteString(stringTable, "FileDescription", title);
|
||||
WriteString(stringTable, "FileVersion", fileVersion);
|
||||
WriteString(stringTable, "InternalName", name.Name);
|
||||
WriteString(stringTable, "LegalCopyright", copyright);
|
||||
WriteString(stringTable, "LegalTrademarks", trademark);
|
||||
WriteString(stringTable, "OriginalFilename", fileName);
|
||||
WriteString(stringTable, "ProductName", product);
|
||||
WriteString(stringTable, "ProductVersion", informationalVersion);
|
||||
|
||||
stringTable.Position = 0;
|
||||
stringTable.Write((short)stringTable.Length);
|
||||
|
||||
ByteBuffer stringFileInfo = new ByteBuffer(512);
|
||||
stringFileInfo.Write((short)0); // wLength (placeholder)
|
||||
stringFileInfo.Write((short)0); // wValueLength
|
||||
stringFileInfo.Write((short)1); // wType
|
||||
WriteUTF16Z(stringFileInfo, "StringFileInfo");
|
||||
stringFileInfo.Align(4);
|
||||
stringFileInfo.Write(stringTable);
|
||||
stringFileInfo.Position = 0;
|
||||
stringFileInfo.Write((short)stringFileInfo.Length);
|
||||
|
||||
byte[] preamble1 = new byte[] {
|
||||
// VS_VERSIONINFO (platform SDK)
|
||||
0x34, 0x00, // wValueLength
|
||||
0x00, 0x00, // wType
|
||||
0x56, 0x00, 0x53, 0x00, 0x5F, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x00, 0x00, // "VS_VERSION_INFO\0"
|
||||
0x00, 0x00, // Padding1 (32 bit alignment)
|
||||
// VS_FIXEDFILEINFO starts
|
||||
0xBD, 0x04, 0xEF, 0xFE, // dwSignature (0xFEEF04BD)
|
||||
0x00, 0x00, 0x01, 0x00, // dwStrucVersion
|
||||
};
|
||||
byte[] preamble2 = new byte[] {
|
||||
0x3F, 0x00, 0x00, 0x00, // dwFileFlagsMask (??)
|
||||
0x00, 0x00, 0x00, 0x00, // dwFileFlags (??)
|
||||
0x04, 0x00, 0x00, 0x00, // dwFileOS
|
||||
0x02, 0x00, 0x00, 0x00, // dwFileType
|
||||
0x00, 0x00, 0x00, 0x00, // dwFileSubtype
|
||||
0x00, 0x00, 0x00, 0x00, // dwFileDateMS
|
||||
0x00, 0x00, 0x00, 0x00, // dwFileDateLS
|
||||
// Padding2 (32 bit alignment)
|
||||
// VarFileInfo
|
||||
0x44, 0x00, // wLength
|
||||
0x00, 0x00, // wValueLength
|
||||
0x01, 0x00, // wType
|
||||
0x56, 0x00, 0x61, 0x00, 0x72, 0x00, 0x46, 0x00, 0x69, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6E, 0x00, 0x66, 0x00, 0x6F, 0x00, 0x00, 0x00, // "VarFileInfo\0"
|
||||
0x00, 0x00, // Padding
|
||||
// Var
|
||||
0x24, 0x00, // wLength
|
||||
0x04, 0x00, // wValueLength
|
||||
0x00, 0x00, // wType
|
||||
0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00, // "Translation\0"
|
||||
0x00, 0x00, // Padding (32 bit alignment)
|
||||
};
|
||||
bb.Write((short)(2 + preamble1.Length + 8 + 8 + preamble2.Length + 4 + stringFileInfo.Length));
|
||||
bb.Write(preamble1);
|
||||
bb.Write((short)fileVersionMinor);
|
||||
bb.Write((short)fileVersionMajor);
|
||||
bb.Write((short)fileVersionRevision);
|
||||
bb.Write((short)fileVersionBuild);
|
||||
bb.Write((short)productVersionMinor);
|
||||
bb.Write((short)productVersionMajor);
|
||||
bb.Write((short)productVersionRevision);
|
||||
bb.Write((short)productVersionBuild);
|
||||
bb.Write(preamble2);
|
||||
bb.Write((short)lcid);
|
||||
bb.Write((short)codepage);
|
||||
bb.Write(stringFileInfo);
|
||||
}
|
||||
|
||||
private void WriteUTF16Z(ByteBuffer bb, string str)
|
||||
{
|
||||
foreach (char c in str)
|
||||
{
|
||||
bb.Write((short)c);
|
||||
}
|
||||
bb.Write((short)0);
|
||||
}
|
||||
|
||||
private void WriteString(ByteBuffer bb, string name, string value)
|
||||
{
|
||||
value = value ?? " ";
|
||||
int pos = bb.Position;
|
||||
bb.Write((short)0); // wLength (placeholder)
|
||||
bb.Write((short)(value.Length + 1));// wValueLength
|
||||
bb.Write((short)1); // wType
|
||||
WriteUTF16Z(bb, name);
|
||||
bb.Align(4);
|
||||
WriteUTF16Z(bb, value);
|
||||
bb.Align(4);
|
||||
int savedPos = bb.Position;
|
||||
bb.Position = pos;
|
||||
bb.Write((short)(savedPos - pos));
|
||||
bb.Position = savedPos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0"?>
|
||||
<project name="refemit" default="IKVM.Reflection.Emit">
|
||||
<target name="IKVM.Reflection.Emit">
|
||||
<property overwrite="false" name="signed" value="" />
|
||||
<property name="defs" value="IKVM_REF_EMIT" />
|
||||
<if test="${property::exists('signed')}">
|
||||
<property name="defs" value="${defs};${signed}" />
|
||||
</if>
|
||||
<csc target="library" output="../bin/IKVM.Reflection.Emit.dll" define="${defs}">
|
||||
<sources>
|
||||
<include name="../CommonAssemblyInfo.cs" />
|
||||
<include name="AssemblyBuilder.cs" />
|
||||
<include name="ConstructorBuilder.cs" />
|
||||
<include name="CustomAttributeBuilder.cs" />
|
||||
<include name="Enums.cs" />
|
||||
<include name="FieldBuilder.cs" />
|
||||
<include name="IkvmAssembly.cs" />
|
||||
<include name="ILGenerator.cs" />
|
||||
<include name="MethodBuilder.cs" />
|
||||
<include name="ModuleBuilder.cs" />
|
||||
<include name="OpCodes.cs" />
|
||||
<include name="ParameterBuilder.cs" />
|
||||
<include name="PropertyBuilder.cs" />
|
||||
<include name="SignatureHelper.cs" />
|
||||
<include name="Tokens.cs" />
|
||||
<include name="TypeBuilder.cs" />
|
||||
<include name="impl/CryptoConvert.cs" />
|
||||
<include name="impl/CryptoHack.cs" />
|
||||
<include name="impl/ITypeOwner.cs" />
|
||||
<include name="impl/PdbSupport.cs" />
|
||||
<include name="impl/TypeBase.cs" />
|
||||
<include name="Properties/AssemblyInfo.cs" />
|
||||
<include name="Writer/ByteBuffer.cs" />
|
||||
<include name="Writer/Heaps.cs" />
|
||||
<include name="Writer/MetadataWriter.cs" />
|
||||
<include name="Writer/ModuleWriter.cs" />
|
||||
<include name="Writer/PEWriter.cs" />
|
||||
<include name="Writer/TextSection.cs" />
|
||||
<include name="Writer/VersionInfo.cs" />
|
||||
</sources>
|
||||
<references>
|
||||
<include name="${framework::get-assembly-directory(framework::get-target-framework())}/ISymWrapper.dll" />
|
||||
</references>
|
||||
</csc>
|
||||
</target>
|
||||
</project>
|
Загрузка…
Ссылка в новой задаче