TpmStructMemberInfo[] GetFieldsToMarshal(bool trackTags = false)
{
var t = GetType();
string caption = (trackTags ? "Unmarshaling" : "Marshaling") + " " + t.Name;
if (!t.GetTypeInfo().IsValueType)
{
var b = t.GetTypeInfo().BaseType;
if (b != null && b != typeof(TpmStructureBase) && b != typeof(object))
{
t = b;
caption += " as " + b.Name;
}
}
dbg.Trace(caption);
dbg.Indent();
var members = new SortedDictionary<int, TpmStructMemberInfo>();
Dictionary<string, TpmStructMemberInfo> tags = null;
//Dictionary<string, TpmStructMemberInfo> untaggedFields = null;
if (trackTags)
{
tags = new Dictionary<string, TpmStructMemberInfo>();
//untaggedFields = new Dictionary<string, TpmStructMemberInfo>();
}
foreach (var bf in new BindingFlags[] {BindingFlags.Public | BindingFlags.NonPublic})
{
var candidateMembers = t.GetMembers(BindingFlags.Instance | bf);
foreach (var mi in candidateMembers)
{
var memberAttrs = mi.CustomAttributes;
foreach (var a in memberAttrs)
{
if (a.AttributeType.Name != "MarshalAsAttribute")
{
continue;
}
int idx = 0;
var arg0 = a.ConstructorArguments[0];
if (arg0.ArgumentType == typeof(int))
{
idx = (int)arg0.Value;
}
else
{
// The only variant of the marshaling attribute with
// a non-int first argument:
// arg0.ArgumentType == typeof(Type))
// is used for types only, and never for structure fields.
Debug.Assert(false);
}
members.Add(idx, mi);
var tsmi = members[idx];
var arg1 = a.ConstructorArguments[1];
Debug.Assert(arg1.ArgumentType == typeof(MarshalType));
var mt = (MarshalType)arg1.Value;
Debug.Assert(mt != MarshalType.ArrayCount && mt != MarshalType.LengthOfStruct);
tsmi.WireType = mt;
if (mt == MarshalType.VariableLengthArray || mt == MarshalType.SizedStruct)
{
tsmi.SizeName = (string)a.ConstructorArguments[2].Value;
tsmi.SizeLength = (int)a.ConstructorArguments[3].Value;
dbg.Trace("Preproc " + (mt == MarshalType.SizedStruct ? "Struct " : "Array ")
+ mi.Name + " with size tag " + tsmi.SizeName + "=" + tsmi.SizeLength);
}
if (trackTags)
{
var marshalType = (MarshalType)arg1.Value;
switch (marshalType)
{
case MarshalType.UnionSelector:
{
tags.Add(mi.Name, tsmi);
dbg.Trace("Preproc Selector: " + mi.Name);
break;
}
case MarshalType.Union:
{
var selector = a.ConstructorArguments[2].Value;
dbg.Trace("Preproc Union " + mi.Name + " with selector " + selector);
tsmi.Tag = tags[(string)selector];
break;
}
#if false
case MarshalType.ArrayCount:
{
tags.Add(mi.Name, tsmi);
dbg.Trace("Preproc Array Count: " + mi.Name);
break;
}
case MarshalType.VariableLengthArray:
{
var sizeTag = a.ConstructorArguments[2].Value;
dbg.Trace("Preproc Array " + mi.Name + " with size tag " + sizeTag);
tsmi.Tag = tags[(string)sizeTag];
break;
}
case MarshalType.LengthOfStruct:
{
var sizedStruct = (string)a.ConstructorArguments[2].Value;
dbg.Trace("Preproc Size Tag " + mi.Name + " for struct " + sizedStruct);
if (untaggedFields.ContainsKey(sizedStruct))
{
untaggedFields[sizedStruct].Tag = tsmi;
}
else
{
tags.Add(sizedStruct, tsmi);
}
break;
}
default:
{
// Check if this is a sized struct
if (tags.ContainsKey(mi.Name))
{
tsmi.Tag = tags[mi.Name];
dbg.Trace("Preproc Sized Struct" + mi.Name + " with size tag " + tsmi.Tag.Name);
}
else
{
untaggedFields.Add(mi.Name, tsmi);
}
break;
}
#endif
}
}
break;
}
}
}
dbg.Unindent();
return members.Values.ToArray();
}