a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
565 lines
13 KiB
C#
565 lines
13 KiB
C#
//
|
|
// SignatureWriter.cs
|
|
//
|
|
// Author:
|
|
// Jb Evain (jbevain@gmail.com)
|
|
//
|
|
// (C) 2005 - 2007 Jb Evain
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
namespace Mono.Cecil.Signatures {
|
|
|
|
using System;
|
|
using System.Text;
|
|
|
|
using Mono.Cecil;
|
|
using Mono.Cecil.Binary;
|
|
using Mono.Cecil.Metadata;
|
|
|
|
internal sealed class SignatureWriter : BaseSignatureVisitor {
|
|
|
|
MetadataWriter m_mdWriter;
|
|
MemoryBinaryWriter m_sigWriter;
|
|
|
|
public SignatureWriter (MetadataWriter mdWriter)
|
|
{
|
|
m_mdWriter = mdWriter;
|
|
m_sigWriter = new MemoryBinaryWriter ();
|
|
}
|
|
|
|
uint GetPointer ()
|
|
{
|
|
return m_mdWriter.AddBlob (m_sigWriter.ToArray ());
|
|
}
|
|
|
|
public uint AddMethodDefSig (MethodDefSig methSig)
|
|
{
|
|
return AddSignature (methSig);
|
|
}
|
|
|
|
public uint AddMethodRefSig (MethodRefSig methSig)
|
|
{
|
|
return AddSignature (methSig);
|
|
}
|
|
|
|
public uint AddPropertySig (PropertySig ps)
|
|
{
|
|
return AddSignature (ps);
|
|
}
|
|
|
|
public uint AddFieldSig (FieldSig fSig)
|
|
{
|
|
return AddSignature (fSig);
|
|
}
|
|
|
|
public uint AddLocalVarSig (LocalVarSig lvs)
|
|
{
|
|
return AddSignature (lvs);
|
|
}
|
|
|
|
uint AddSignature (Signature s)
|
|
{
|
|
m_sigWriter.Empty ();
|
|
s.Accept (this);
|
|
return GetPointer ();
|
|
}
|
|
|
|
public uint AddTypeSpec (TypeSpec ts)
|
|
{
|
|
m_sigWriter.Empty ();
|
|
Write (ts);
|
|
return GetPointer ();
|
|
}
|
|
|
|
public uint AddMethodSpec (MethodSpec ms)
|
|
{
|
|
m_sigWriter.Empty ();
|
|
Write (ms);
|
|
return GetPointer ();
|
|
}
|
|
|
|
public uint AddMarshalSig (MarshalSig ms)
|
|
{
|
|
m_sigWriter.Empty ();
|
|
Write (ms);
|
|
return GetPointer ();
|
|
}
|
|
|
|
public uint AddCustomAttribute (CustomAttrib ca, MethodReference ctor)
|
|
{
|
|
CompressCustomAttribute (ca, ctor, m_sigWriter);
|
|
return GetPointer ();
|
|
}
|
|
|
|
public byte [] CompressCustomAttribute (CustomAttrib ca, MethodReference ctor)
|
|
{
|
|
MemoryBinaryWriter writer = new MemoryBinaryWriter ();
|
|
CompressCustomAttribute (ca, ctor, writer);
|
|
return writer.ToArray ();
|
|
}
|
|
|
|
public byte [] CompressFieldSig (FieldSig field)
|
|
{
|
|
m_sigWriter.Empty ();
|
|
VisitFieldSig (field);
|
|
return m_sigWriter.ToArray ();
|
|
}
|
|
|
|
public byte [] CompressLocalVar (LocalVarSig.LocalVariable var)
|
|
{
|
|
m_sigWriter.Empty ();
|
|
Write (var);
|
|
return m_sigWriter.ToArray ();
|
|
}
|
|
|
|
void CompressCustomAttribute (CustomAttrib ca, MethodReference ctor, MemoryBinaryWriter writer)
|
|
{
|
|
m_sigWriter.Empty ();
|
|
Write (ca, ctor, writer);
|
|
}
|
|
|
|
public override void VisitMethodDefSig (MethodDefSig methodDef)
|
|
{
|
|
m_sigWriter.Write (methodDef.CallingConvention);
|
|
if (methodDef.GenericParameterCount > 0)
|
|
Write (methodDef.GenericParameterCount);
|
|
Write (methodDef.ParamCount);
|
|
Write (methodDef.RetType);
|
|
Write (methodDef.Parameters, methodDef.Sentinel);
|
|
}
|
|
|
|
public override void VisitMethodRefSig (MethodRefSig methodRef)
|
|
{
|
|
m_sigWriter.Write (methodRef.CallingConvention);
|
|
Write (methodRef.ParamCount);
|
|
Write (methodRef.RetType);
|
|
Write (methodRef.Parameters, methodRef.Sentinel);
|
|
}
|
|
|
|
public override void VisitFieldSig (FieldSig field)
|
|
{
|
|
m_sigWriter.Write (field.CallingConvention);
|
|
Write (field.CustomMods);
|
|
Write (field.Type);
|
|
}
|
|
|
|
public override void VisitPropertySig (PropertySig property)
|
|
{
|
|
m_sigWriter.Write (property.CallingConvention);
|
|
Write (property.ParamCount);
|
|
Write (property.CustomMods);
|
|
Write (property.Type);
|
|
Write (property.Parameters);
|
|
}
|
|
|
|
public override void VisitLocalVarSig (LocalVarSig localvar)
|
|
{
|
|
m_sigWriter.Write (localvar.CallingConvention);
|
|
Write (localvar.Count);
|
|
Write (localvar.LocalVariables);
|
|
}
|
|
|
|
void Write (LocalVarSig.LocalVariable [] vars)
|
|
{
|
|
foreach (LocalVarSig.LocalVariable var in vars)
|
|
Write (var);
|
|
}
|
|
|
|
void Write (LocalVarSig.LocalVariable var)
|
|
{
|
|
Write (var.CustomMods);
|
|
if ((var.Constraint & Constraint.Pinned) != 0)
|
|
Write (ElementType.Pinned);
|
|
if (var.ByRef)
|
|
Write (ElementType.ByRef);
|
|
Write (var.Type);
|
|
}
|
|
|
|
void Write (RetType retType)
|
|
{
|
|
Write (retType.CustomMods);
|
|
if (retType.Void)
|
|
Write (ElementType.Void);
|
|
else if (retType.TypedByRef)
|
|
Write (ElementType.TypedByRef);
|
|
else if (retType.ByRef) {
|
|
Write (ElementType.ByRef);
|
|
Write (retType.Type);
|
|
} else
|
|
Write (retType.Type);
|
|
}
|
|
|
|
void Write (Param [] parameters, int sentinel)
|
|
{
|
|
for (int i = 0; i < parameters.Length; i++) {
|
|
if (i == sentinel)
|
|
Write (ElementType.Sentinel);
|
|
|
|
Write (parameters [i]);
|
|
}
|
|
}
|
|
|
|
void Write (Param [] parameters)
|
|
{
|
|
foreach (Param p in parameters)
|
|
Write (p);
|
|
}
|
|
|
|
void Write (ElementType et)
|
|
{
|
|
Write ((int) et);
|
|
}
|
|
|
|
void Write (SigType t)
|
|
{
|
|
Write ((int) t.ElementType);
|
|
|
|
switch (t.ElementType) {
|
|
case ElementType.ValueType :
|
|
Write ((int) Utilities.CompressMetadataToken (
|
|
CodedIndex.TypeDefOrRef, ((VALUETYPE) t).Type));
|
|
break;
|
|
case ElementType.Class :
|
|
Write ((int) Utilities.CompressMetadataToken (
|
|
CodedIndex.TypeDefOrRef, ((CLASS) t).Type));
|
|
break;
|
|
case ElementType.Ptr :
|
|
PTR p = (PTR) t;
|
|
if (p.Void)
|
|
Write (ElementType.Void);
|
|
else {
|
|
Write (p.CustomMods);
|
|
Write (p.PtrType);
|
|
}
|
|
break;
|
|
case ElementType.FnPtr :
|
|
FNPTR fp = (FNPTR) t;
|
|
if (fp.Method is MethodRefSig)
|
|
(fp.Method as MethodRefSig).Accept (this);
|
|
else
|
|
(fp.Method as MethodDefSig).Accept (this);
|
|
break;
|
|
case ElementType.Array :
|
|
ARRAY ary = (ARRAY) t;
|
|
Write (ary.CustomMods);
|
|
ArrayShape shape = ary.Shape;
|
|
Write (ary.Type);
|
|
Write (shape.Rank);
|
|
Write (shape.NumSizes);
|
|
foreach (int size in shape.Sizes)
|
|
Write (size);
|
|
Write (shape.NumLoBounds);
|
|
foreach (int loBound in shape.LoBounds)
|
|
Write (loBound);
|
|
break;
|
|
case ElementType.SzArray :
|
|
SZARRAY sa = (SZARRAY) t;
|
|
Write (sa.CustomMods);
|
|
Write (sa.Type);
|
|
break;
|
|
case ElementType.Var :
|
|
Write (((VAR) t).Index);
|
|
break;
|
|
case ElementType.MVar :
|
|
Write (((MVAR) t).Index);
|
|
break;
|
|
case ElementType.GenericInst :
|
|
GENERICINST gi = t as GENERICINST;
|
|
Write (gi.ValueType ? ElementType.ValueType : ElementType.Class);
|
|
Write ((int) Utilities.CompressMetadataToken (
|
|
CodedIndex.TypeDefOrRef, gi.Type));
|
|
Write (gi.Signature);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Write (TypeSpec ts)
|
|
{
|
|
Write (ts.CustomMods);
|
|
Write (ts.Type);
|
|
}
|
|
|
|
void Write (MethodSpec ms)
|
|
{
|
|
Write (0x0a);
|
|
Write (ms.Signature);
|
|
}
|
|
|
|
void Write (GenericInstSignature gis)
|
|
{
|
|
Write (gis.Arity);
|
|
for (int i = 0; i < gis.Arity; i++)
|
|
Write (gis.Types [i]);
|
|
}
|
|
|
|
void Write (GenericArg arg)
|
|
{
|
|
Write (arg.CustomMods);
|
|
Write (arg.Type);
|
|
}
|
|
|
|
void Write (Param p)
|
|
{
|
|
Write (p.CustomMods);
|
|
if (p.TypedByRef)
|
|
Write (ElementType.TypedByRef);
|
|
else if (p.ByRef) {
|
|
Write (ElementType.ByRef);
|
|
Write (p.Type);
|
|
} else
|
|
Write (p.Type);
|
|
}
|
|
|
|
void Write (CustomMod [] customMods)
|
|
{
|
|
foreach (CustomMod cm in customMods)
|
|
Write (cm);
|
|
}
|
|
|
|
void Write (CustomMod cm)
|
|
{
|
|
switch (cm.CMOD) {
|
|
case CustomMod.CMODType.OPT :
|
|
Write (ElementType.CModOpt);
|
|
break;
|
|
case CustomMod.CMODType.REQD :
|
|
Write (ElementType.CModReqD);
|
|
break;
|
|
}
|
|
|
|
Write ((int) Utilities.CompressMetadataToken (
|
|
CodedIndex.TypeDefOrRef, cm.TypeDefOrRef));
|
|
}
|
|
|
|
void Write (MarshalSig ms)
|
|
{
|
|
Write ((int) ms.NativeInstrinsic);
|
|
switch (ms.NativeInstrinsic) {
|
|
case NativeType.ARRAY :
|
|
MarshalSig.Array ar = (MarshalSig.Array) ms.Spec;
|
|
Write ((int) ar.ArrayElemType);
|
|
if (ar.ParamNum != -1)
|
|
Write (ar.ParamNum);
|
|
if (ar.NumElem != -1)
|
|
Write (ar.NumElem);
|
|
if (ar.ElemMult != -1)
|
|
Write (ar.ElemMult);
|
|
break;
|
|
case NativeType.CUSTOMMARSHALER :
|
|
MarshalSig.CustomMarshaler cm = (MarshalSig.CustomMarshaler) ms.Spec;
|
|
Write (cm.Guid);
|
|
Write (cm.UnmanagedType);
|
|
Write (cm.ManagedType);
|
|
Write (cm.Cookie);
|
|
break;
|
|
case NativeType.FIXEDARRAY :
|
|
MarshalSig.FixedArray fa = (MarshalSig.FixedArray) ms.Spec;
|
|
Write (fa.NumElem);
|
|
if (fa.ArrayElemType != NativeType.NONE)
|
|
Write ((int) fa.ArrayElemType);
|
|
break;
|
|
case NativeType.SAFEARRAY :
|
|
Write ((int) ((MarshalSig.SafeArray) ms.Spec).ArrayElemType);
|
|
break;
|
|
case NativeType.FIXEDSYSSTRING :
|
|
Write (((MarshalSig.FixedSysString) ms.Spec).Size);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Write (CustomAttrib ca, MethodReference ctor, MemoryBinaryWriter writer)
|
|
{
|
|
if (ca == null)
|
|
return;
|
|
|
|
if (ca.Prolog != CustomAttrib.StdProlog)
|
|
return;
|
|
|
|
writer.Write (ca.Prolog);
|
|
|
|
for (int i = 0; i < ctor.Parameters.Count; i++)
|
|
Write (ca.FixedArgs [i], writer);
|
|
|
|
writer.Write (ca.NumNamed);
|
|
|
|
for (int i = 0; i < ca.NumNamed; i++)
|
|
Write (ca.NamedArgs [i], writer);
|
|
}
|
|
|
|
void Write (CustomAttrib.FixedArg fa, MemoryBinaryWriter writer)
|
|
{
|
|
if (fa.SzArray)
|
|
writer.Write (fa.NumElem);
|
|
|
|
foreach (CustomAttrib.Elem elem in fa.Elems)
|
|
Write (elem, writer);
|
|
}
|
|
|
|
static string GetEnumFullName (TypeReference type)
|
|
{
|
|
string fullname = type.FullName;
|
|
|
|
if (type.IsNested)
|
|
fullname = fullname.Replace ('/', '+');
|
|
|
|
if (type is TypeDefinition)
|
|
return fullname;
|
|
|
|
return string.Concat (fullname, ", ", type.Module.Assembly.Name.FullName);
|
|
}
|
|
|
|
void Write (CustomAttrib.NamedArg na, MemoryBinaryWriter writer)
|
|
{
|
|
if (na.Field)
|
|
writer.Write ((byte) 0x53);
|
|
else if (na.Property)
|
|
writer.Write ((byte) 0x54);
|
|
else
|
|
throw new MetadataFormatException ("Unknown kind of namedarg");
|
|
|
|
if (na.FieldOrPropType == ElementType.Class)
|
|
na.FieldOrPropType = ElementType.Enum;
|
|
|
|
if (na.FixedArg.SzArray)
|
|
writer.Write ((byte) ElementType.SzArray);
|
|
|
|
if (na.FieldOrPropType == ElementType.Object)
|
|
writer.Write ((byte) ElementType.Boxed);
|
|
else
|
|
writer.Write ((byte) na.FieldOrPropType);
|
|
|
|
if (na.FieldOrPropType == ElementType.Enum)
|
|
Write (GetEnumFullName (na.FixedArg.Elems [0].ElemType));
|
|
|
|
Write (na.FieldOrPropName);
|
|
|
|
Write (na.FixedArg, writer);
|
|
}
|
|
|
|
static ElementType GetElementTypeFromTypeCode (TypeCode tc)
|
|
{
|
|
switch (tc) {
|
|
case TypeCode.Byte:
|
|
return ElementType.U1;
|
|
case TypeCode.SByte:
|
|
return ElementType.I1;
|
|
case TypeCode.Int16:
|
|
return ElementType.I2;
|
|
case TypeCode.UInt16:
|
|
return ElementType.U2;
|
|
case TypeCode.Int32:
|
|
return ElementType.I4;
|
|
case TypeCode.UInt32:
|
|
return ElementType.U4;
|
|
case TypeCode.Int64:
|
|
return ElementType.I8;
|
|
case TypeCode.UInt64:
|
|
return ElementType.U8;
|
|
default:
|
|
throw new ArgumentException ("tc");
|
|
}
|
|
}
|
|
|
|
void Write (CustomAttrib.Elem elem, MemoryBinaryWriter writer)
|
|
{
|
|
if (elem.String)
|
|
elem.FieldOrPropType = ElementType.String;
|
|
else if (elem.Type)
|
|
elem.FieldOrPropType = ElementType.Type;
|
|
|
|
if (elem.FieldOrPropType == ElementType.Class) // an enum in fact
|
|
elem.FieldOrPropType = GetElementTypeFromTypeCode (Type.GetTypeCode (elem.Value.GetType ()));
|
|
|
|
if (elem.BoxedValueType)
|
|
Write (elem.FieldOrPropType);
|
|
|
|
switch (elem.FieldOrPropType) {
|
|
case ElementType.Boolean :
|
|
writer.Write ((byte) ((bool) elem.Value ? 1 : 0));
|
|
break;
|
|
case ElementType.Char :
|
|
writer.Write ((ushort) (char) elem.Value);
|
|
break;
|
|
case ElementType.R4 :
|
|
writer.Write ((float) elem.Value);
|
|
break;
|
|
case ElementType.R8 :
|
|
writer.Write ((double) elem.Value);
|
|
break;
|
|
case ElementType.I1 :
|
|
writer.Write ((sbyte) elem.Value);
|
|
break;
|
|
case ElementType.I2 :
|
|
writer.Write ((short) elem.Value);
|
|
break;
|
|
case ElementType.I4 :
|
|
writer.Write ((int) elem.Value);
|
|
break;
|
|
case ElementType.I8 :
|
|
writer.Write ((long) elem.Value);
|
|
break;
|
|
case ElementType.U1 :
|
|
writer.Write ((byte) elem.Value);
|
|
break;
|
|
case ElementType.U2 :
|
|
writer.Write ((ushort) elem.Value);
|
|
break;
|
|
case ElementType.U4 :
|
|
writer.Write ((uint) elem.Value);
|
|
break;
|
|
case ElementType.U8 :
|
|
writer.Write ((ulong) elem.Value);
|
|
break;
|
|
case ElementType.String :
|
|
case ElementType.Type :
|
|
string s = elem.Value as string;
|
|
if (s == null)
|
|
writer.Write ((byte) 0xff);
|
|
else if (s.Length == 0)
|
|
writer.Write ((byte) 0x00);
|
|
else
|
|
Write (s);
|
|
break;
|
|
case ElementType.Object :
|
|
if (elem.Value != null)
|
|
throw new NotSupportedException ("Unknown state");
|
|
writer.Write ((byte) 0xff);
|
|
break;
|
|
default :
|
|
throw new NotImplementedException ("WriteElem " + elem.FieldOrPropType.ToString ());
|
|
}
|
|
}
|
|
|
|
void Write (string s)
|
|
{
|
|
byte [] str = Encoding.UTF8.GetBytes (s);
|
|
Write (str.Length);
|
|
m_sigWriter.Write (str);
|
|
}
|
|
|
|
void Write (int i)
|
|
{
|
|
Utilities.WriteCompressedInteger (m_sigWriter, i);
|
|
}
|
|
}
|
|
}
|