internal object ReadStruct(StructDefinition definition, MemberType memberType, object node, object parent)
{
var offset = (UInt32)Stream.Position;
object cachedNode = null;
if (memberType != MemberType.Inline && CachedStructs.TryGetValue(offset, out cachedNode))
{
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(String.Format("Skipped cached struct {1} at {0:X8}", offset, node.ToString()));
#endif
Stream.Position += definition.Size(this);
return cachedNode;
}
if (node != null)
{
// Don't save inline structs in the cached struct map, as they can occupy the same address as a non-inline struct
// if they're at the beginning of said struct.
// They also cannot be referenced from multiple locations, so caching them is of no use.
if (memberType != MemberType.Inline)
CachedStructs.Add(offset, node);
#if DEBUG_GR2_FORMAT_DIFFERENCES
// Create a struct definition from this instance and check if the GR2 type differs from the local type.
var localDefn = new StructDefinition();
localDefn.LoadFromType(node.GetType(), null);
var localMembers = localDefn.Members.Where(m => m.ShouldSerialize(Header.tag)).ToList();
var defnMembers = definition.Members.Where(m => m.ShouldSerialize(Header.tag)).ToList();
if (localMembers.Count != defnMembers.Count)
{
Trace.TraceWarning(String.Format("Struct {0} differs: Field count differs ({1} vs {2})", node.GetType().Name, localMembers.Count, defnMembers.Count));
}
else
{
for (int i = 0; i < localMembers.Count; i++)
{
var member = localMembers[i];
var local = defnMembers[i];
if (member.Type != local.Type)
{
Trace.TraceWarning(String.Format(
"Struct {0}: Field {1} type differs ({1} vs {2})",
node.GetType().Name, local.Name, local.Type, member.Type
));
}
if (!member.GrannyName.Equals(local.GrannyName))
{
Trace.TraceWarning(String.Format(
"Struct {0}: Field {1} name differs ({1} vs {2})",
node.GetType().Name, local.Name, local.GrannyName, member.GrannyName
));
}
if (member.ArraySize != local.ArraySize)
{
Trace.TraceWarning(String.Format(
"Struct {0}: Field {1} array size differs ({1} vs {2})",
node.GetType().Name, local.Name, local.ArraySize, member.ArraySize
));
}
}
}
#endif
definition.MapType(node);
foreach (var member in definition.Members)
{
var field = member.LookupFieldInfo(node);
if (field != null)
{
var value = ReadInstance(member, field.GetValue(node), field.FieldType, node);
field.SetValue(node, value);
}
else
{
ReadInstance(member, null, null, node);
}
}
}
else
{
foreach (var member in definition.Members)
{
ReadInstance(member, null, null, null);
}
}
return node;
}