gecko-dev/extensions/mono/src/typeinfo.cs

531 строка
16 KiB
C#

using System;
using System.Runtime.InteropServices;
using Mozilla.XPCOM;
namespace Mozilla.XPCOM {
/* This doesn't need to be public, but making it 'internal' causes stress with
* TypeDescriptor.op_Implicit(XPTType). */
[StructLayout(LayoutKind.Sequential)]
public struct XPTType
{
public const byte FlagMask = 0xE0;
public const byte TagMask = 0x1F;
public byte prefix;
public byte arg1;
public byte arg2;
public byte padding;
public UInt16 arg3;
static public implicit operator XPTType(TypeInfo.TypeDescriptor td)
{
XPTType t = new XPTType();
t.prefix = (byte) ((byte)td.flags | (byte)td.tag);
t.arg1 = td.arg1;
t.arg2 = td.arg2;
t.arg3 = td.arg3;
return t;
}
}
[StructLayout(LayoutKind.Sequential)]
struct XPTParamDescriptor
{
public byte param_flags;
public byte padding1;
public XPTType type;
}
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]
struct XPTMethodDescriptor
{
public String name;
public IntPtr args; /* XPTParamDescriptor */
public IntPtr result; /* XPTParamDescriptor */
public byte flags;
public byte numArgs;
}
public class TypeInfo
{
[Flags]
public enum TypeFlags : byte
{
Pointer = 0x80, UniquePointer = 0x40, Reference = 0x20
}
public enum TypeTag : byte
{
Int8 = 0, Int16 = 1, Int32 = 2, Int64 = 3,
UInt8 = 4, UInt16 = 5, UInt32 = 6, UInt64 = 7,
Float = 8, Double = 9, Bool = 10, Char = 11,
WChar = 12, Void = 13, NSIdPtr = 14, AString = 15,
String = 16, WString = 17, Interface = 18, InterfaceIs = 19,
Array = 20, StringSizeIs = 21, WStringSizeIs = 22, UTF8String = 23,
CString = 24, AString_dup = 25
}
public struct TypeDescriptor
{
public TypeFlags flags;
public TypeTag tag;
public byte arg1;
public byte arg2;
public UInt16 arg3;
public override string ToString()
{
string res = String.Empty;
if ((Int32)flags != 0)
res = "[" + flags.ToString() + "]";
res += tag.ToString();
return res;
}
public bool IsScalar()
{
if (tag <= TypeTag.WChar ||
tag == TypeTag.String || tag == TypeTag.WString) {
return true;
}
return false;
}
static public implicit operator TypeDescriptor(XPTType t)
{
TypeDescriptor td = new TypeInfo.TypeDescriptor();
td.flags = (TypeFlags)(t.prefix & XPTType.FlagMask);
td.tag = (TypeTag)(t.prefix & XPTType.TagMask);
td.arg1 = t.arg1;
td.arg2 = t.arg2;
td.arg3 = t.arg3;
return td;
}
public Type AsCLRType()
{
switch (tag) {
case TypeTag.Int8:
return typeof(sbyte);
case TypeTag.Int16:
return typeof(Int16);
case TypeTag.Int32:
return typeof(Int32);
case TypeTag.Int64:
return typeof(Int64);
case TypeTag.UInt8:
return typeof(byte);
case TypeTag.UInt16:
return typeof(UInt16);
case TypeTag.UInt32:
return typeof(UInt32);
case TypeTag.UInt64:
return typeof(UInt64);
case TypeTag.Float:
return typeof(Single);
case TypeTag.Double:
return typeof(Double);
case TypeTag.Bool:
return typeof(bool);
case TypeTag.String:
return typeof(string);
case TypeTag.WString:
return typeof(string);
case TypeTag.Interface:
return typeof(object);
case TypeTag.InterfaceIs:
return typeof(object);
case TypeTag.Char:
return typeof(byte);
case TypeTag.WChar:
return typeof(char);
case TypeTag.NSIdPtr:
return Type.GetType("System.Guid&");
// return typeof(Guid).MakeByRefType(); NET_2_0
default:
string msg = String.Format("type {0} not yet supported ",
tag.ToString());
throw new Exception(msg);
}
}
}
[Flags]
public enum ParamFlags : byte
{
In = 0x80, Out = 0x40, RetVal = 0x20, Shared = 0x10, Dipper = 0x08
}
public struct ParamDescriptor
{
public MethodDescriptor method;
public int index;
public ParamFlags flags;
public TypeDescriptor type;
public Type GetCLRType()
{
Type t = type.AsCLRType();
if (IsOut() && !IsRetVal()) {
Type reft = System.Type.GetType(t.FullName + "&");
Console.WriteLine("{0} -> {1}", t.FullName, reft.FullName);
t = reft;
}
return t;
}
public override string ToString()
{
return "[" + flags.ToString() + "] " + type.ToString();
}
public string Name()
{
return method.Name() + ":" + index;
}
public bool IsOut()
{
return (flags & ParamFlags.Out) != 0;
}
public bool IsIn()
{
return (flags & ParamFlags.In) != 0;
}
public bool IsRetVal()
{
return (flags & ParamFlags.RetVal) != 0;
}
public Guid GetIID()
{
if (type.tag != TypeTag.Interface) {
throw new Exception(String.Format("{0} not an interface type",
this));
}
Guid iid;
int res;
res = typeinfo_GetIIDForParam(method.ifaceName, method.index,
index, out iid);
if (res != 0) {
throw new
Exception(String.Format("GetIIDForParam failed: {0:X8}",
res));
}
return iid;
}
public string GetInterfaceName()
{
return TypeInfo.NameForIID(GetIID());
}
}
[Flags]
public enum MethodFlags : byte
{
Getter = 0x80, Setter = 0x40, NotXPCOM = 0x20, Constructor = 0x10,
Hidden = 0x08
}
public class MethodDescriptor
{
public int index;
public String name;
public ParamDescriptor[] args;
public ParamDescriptor result;
public Type[] argTypes;
public Type resultType;
public MethodFlags flags;
public String ifaceName;
public bool IsVisible()
{
return (flags & (MethodFlags.Hidden | MethodFlags.NotXPCOM)) == 0;
}
public bool IsSetter()
{
return (flags & MethodFlags.Setter) != 0;
}
public bool IsGetter()
{
return (flags & MethodFlags.Getter) != 0;
}
public string Name()
{
return ifaceName + ":" + name + "(" + index + ")";
}
public Type FindResultType()
{
for (int i = 0; i < args.Length; i++) {
if (args[i].IsRetVal())
return args[i].GetCLRType();
}
return typeof(void);
}
public void BuildArgTypes()
{
if (!IsVisible()) {
argTypes = new Type[] { };
return;
}
if (resultType != typeof(void))
argTypes = new Type[args.Length - 1];
else
argTypes = new Type[args.Length];
int j = 0;
for (int i = 0; i < args.Length; i++) {
if (args[i].IsRetVal())
continue;
argTypes[j++] = args[i].GetCLRType();
}
}
public override string ToString()
{
string res = String.Empty;
if (flags != 0)
res = "[" + flags.ToString() + "] ";
res += result.ToString() + " " + name + "(";
for (int i = 0; i < args.Length; i++) {
if (i != 0)
res += ", ";
res += args[i].ToString();
}
res += ")";
return res;
}
}
[DllImport("xpcom-dotnet.so")]
static extern int typeinfo_GetAllMethodData(String iface,
out IntPtr infos,
out UInt16 count);
[DllImport("xpcom-dotnet.so")]
static extern int typeinfo_GetMethodData(String iface, int method,
out IntPtr info);
[DllImport("xpcom-dotnet.so")]
static extern int typeinfo_GetMethodData_byname(String iface,
String method,
out UInt16 index,
out IntPtr info);
[DllImport("xpcom-dotnet.so")]
static extern int typeinfo_GetMethodData_iid_index(ref Guid iid, int index,
out IntPtr xptinfo);
[DllImport("xpcom-dotnet.so")]
static extern int typeinfo_GetIIDForParam(String iface, int method,
int param, out Guid iid);
[DllImport("xpcom-dotnet.so")]
static extern int typeinfo_GetNameForIID(ref Guid iid, out String name);
[DllImport("xpcom-dotnet.so")]
public static extern IntPtr typeinfo_EnumerateInterfacesStart();
[DllImport("xpcom-dotnet.so")]
public static extern String typeinfo_EnumerateInterfacesNext(IntPtr e);
[DllImport("xpcom-dotnet.so")]
public static extern void typeinfo_EnumerateInterfacesStop(IntPtr e);
[DllImport("xpcom-dotnet.so")]
public static extern int typeinfo_GetParentInfo(String name,
out String parentName,
out UInt16 methodCount);
public static String GetParentInfo(String name, out UInt16 methodCount)
{
String parentName;
int res = typeinfo_GetParentInfo(name, out parentName,
out methodCount);
if (res != 0) {
throw new Exception(String.Format("GetParentInfo({0}) " +
"failed: {1:X8}", name, res));
}
return parentName;
}
static ParamDescriptor BuildParamDescriptor(IntPtr paramptr, int index,
MethodDescriptor method)
{
XPTParamDescriptor xptpd = (XPTParamDescriptor)
Marshal.PtrToStructure(paramptr, typeof(XPTParamDescriptor));
ParamDescriptor pd = new ParamDescriptor();
pd.method = method;
pd.index = index;
pd.flags = (ParamFlags) xptpd.param_flags;
pd.type = xptpd.type;
return pd;
}
static ParamDescriptor BuildRetValDescriptor(IntPtr paramptr,
MethodDescriptor method)
{
return BuildParamDescriptor(paramptr, -1, method);
}
static ParamDescriptor[] BuildParamDescriptorArray(IntPtr paramptr,
int count,
MethodDescriptor method)
{
ParamDescriptor[] parr = new ParamDescriptor[count];
for (int i = 0; i < count; i++) {
parr[i] = BuildParamDescriptor(paramptr, i, method);
paramptr = (IntPtr)(paramptr.ToInt32() + 8);
}
return parr;
}
static MethodDescriptor ConvertMethodDescriptor(IntPtr xptinfo,
string ifaceName,
int index)
{
XPTMethodDescriptor info;
info = (XPTMethodDescriptor)
Marshal.PtrToStructure(xptinfo, typeof(XPTMethodDescriptor));
MethodDescriptor meth = new MethodDescriptor();
meth.ifaceName = ifaceName;
meth.index = index;
meth.name = System.Char.ToUpper(info.name[0]) + info.name.Substring(1);
meth.flags = (MethodFlags)info.flags;
meth.args = BuildParamDescriptorArray(info.args, info.numArgs, meth);
meth.result = BuildRetValDescriptor(info.result, meth);
if (meth.IsVisible()) {
meth.resultType = meth.FindResultType();
meth.BuildArgTypes();
}
return meth;
}
static public MethodDescriptor[] GetMethodData(string ifaceName)
{
IntPtr buffer;
UInt16 count;
int res = typeinfo_GetAllMethodData(ifaceName, out buffer, out count);
if (res != 0) {
throw new Exception(String.Format("GetAllMethodData({0}) " +
"failed: {1:X8}",
ifaceName, res));
}
MethodDescriptor[] methods = new MethodDescriptor[count];
for (int i = 0; i < (UInt16)count; i++) {
IntPtr infoptr = Marshal.ReadIntPtr(buffer, i *
Marshal.SizeOf(typeof(IntPtr)));
try {
methods[i] = ConvertMethodDescriptor(infoptr, ifaceName, i);
} catch (Exception e) {
Console.WriteLine("skipping {0}[{1}]: {2}",
ifaceName, i, e.Message);
}
}
if (count > 0)
Marshal.FreeCoTaskMem(buffer);
return methods;
}
static public MethodDescriptor GetMethodData(Guid iid, int index)
{
IntPtr xptinfo;
int res = typeinfo_GetMethodData_iid_index(ref iid, index,
out xptinfo);
if (res != 0) {
throw new Exception(String.Format("GetMethodData({0}.{1}) " +
"failed: {2:X8}",
iid, index, res));
}
String name;
res = typeinfo_GetNameForIID(ref iid, out name);
if (res != 0) {
throw new Exception(String.Format("GetNameForIID failed: {0:X8}",
res));
}
return ConvertMethodDescriptor(xptinfo, name, index);
}
static public String NameForIID(Guid iid)
{
String name;
int res = typeinfo_GetNameForIID(ref iid, out name);
if (res != 0) {
throw new
Exception(String.Format("GetNameForIID failed: {0:X8}",
res));
}
return name;
}
static public Type TypeForIID(Guid iid)
{
String ifaceName = "Mozilla.XPCOM.Interfaces." + NameForIID(iid) +
",Mozilla.XPCOM.Interfaces";
return System.Type.GetType(ifaceName);
}
static public MethodDescriptor GetMethodData(string ifaceName,
string methodName)
{
IntPtr xptinfo;
UInt16 index;
int res = typeinfo_GetMethodData_byname(ifaceName, methodName,
out index, out xptinfo);
if (res != 0) {
throw new Exception(String.Format("GetMethodData({0}.{1}) " +
"failed: {2:X8}",
ifaceName, methodName, res));
}
// Console.WriteLine("{0} is index {1}", methodName, index);
return ConvertMethodDescriptor(xptinfo, ifaceName, (int)index);
}
static public MethodDescriptor GetMethodData(String ifaceName,
int methodIndex)
{
IntPtr xptinfo;
int res = typeinfo_GetMethodData(ifaceName, methodIndex, out xptinfo);
if (xptinfo == IntPtr.Zero) {
throw new Exception(String.Format("GetMethodData({0}:{1}) failed:" +
" {2:X8}",
ifaceName, methodIndex, res));
}
return ConvertMethodDescriptor(xptinfo, ifaceName, methodIndex);
}
}
} // namespace Mozilla.XPCOM