private object ReadElement(MemberDefinition definition, object node, Type propertyType, object parent)
{
#if DEBUG_GR2_SERIALIZATION
var offsetInFile = Stream.Position;
#endif
var kind = definition.SerializationKind;
Debug.Assert(kind == SerializationKind.Builtin || !definition.IsScalar);
if (node == null &&
propertyType != null &&
!definition.IsScalar &&
(kind == SerializationKind.Builtin || kind == SerializationKind.UserElement) &&
// Variant construction is a special case as we don't know the struct defn beforehand
definition.Type != MemberType.VariantReference)
{
node = Helpers.CreateInstance(propertyType);
}
switch (definition.Type)
{
case MemberType.Inline:
Debug.Assert(definition.Definition.IsValid);
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(String.Format(" === Inline Struct {0} === ", definition.Name));
#endif
if (kind == SerializationKind.UserElement || kind == SerializationKind.UserMember)
node = definition.Serializer.Read(this, definition.Definition.Resolve(this), definition, 0, parent);
else
node = ReadStruct(definition.Definition.Resolve(this), definition.Type, node, parent);
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(" === End Struct === ");
#endif
break;
case MemberType.Reference:
{
Debug.Assert(definition.Definition.IsValid);
var r = ReadReference();
if (r.IsValid && parent != null)
{
var originalPos = Stream.Position;
Seek(r);
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(String.Format(" === Struct <{0}> at {1:X8} === ", definition.Name, Stream.Position));
#endif
if (kind == SerializationKind.UserElement || kind == SerializationKind.UserMember)
node = definition.Serializer.Read(this, definition.Definition.Resolve(this), definition, 0, parent);
else
node = ReadStruct(definition.Definition.Resolve(this), definition.Type, node, parent);
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(" === End Struct === ");
#endif
Stream.Seek(originalPos, SeekOrigin.Begin);
}
else
node = null;
break;
}
case MemberType.VariantReference:
{
var structRef = ReadStructReference();
var r = ReadReference();
if (r.IsValid && parent != null)
{
var structDefn = structRef.Resolve(this);
if (definition.TypeSelector != null && definition.Type == MemberType.VariantReference)
propertyType = definition.TypeSelector.SelectType(definition, structDefn, parent);
if (propertyType != null)
node = Helpers.CreateInstance(propertyType);
if (node != null)
{
var originalPos = Stream.Position;
Seek(r);
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(String.Format(" === Variant Struct <{0}> at {1:X8} === ", definition.Name, Stream.Position));
#endif
if (kind == SerializationKind.UserElement || kind == SerializationKind.UserMember)
node = definition.Serializer.Read(this, structDefn, definition, 0, parent);
else
node = ReadStruct(structRef.Resolve(this), definition.Type, node, parent);
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(" === End Struct === ");
#endif
Stream.Seek(originalPos, SeekOrigin.Begin);
}
}
else
node = null;
break;
}
case MemberType.ArrayOfReferences:
{
// Serializing as a struct member is nooooot a very good idea here.
Debug.Assert(kind != SerializationKind.UserMember);
Debug.Assert(definition.Definition.IsValid);
var indices = ReadArrayIndicesReference();
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(String.Format(" Array of references at [{0:X8}]", indices.Offset));
#endif
Debug.Assert(indices.IsValid == (indices.Size != 0));
if (indices.IsValid && node != null && parent != null)
{
var items = node as System.Collections.IList;
var type = items.GetType().GetGenericArguments().Single();
var refs = indices.Resolve(this);
var originalPos = Stream.Position;
for (int i = 0; i < refs.Count; i++)
{
Seek(refs[i]);
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(String.Format(" === Struct <{0}> at {1:X8} === ", definition.Name, Stream.Position));
#endif
if (kind == SerializationKind.UserElement)
{
object element = definition.Serializer.Read(this, definition.Definition.Resolve(this), definition, 0, parent);
items.Add(element);
}
else
{
object element = Helpers.CreateInstance(type);
// TODO: Only create a new instance if we don't have a CachedStruct available!
element = ReadStruct(definition.Definition.Resolve(this), definition.Type, element, parent);
items.Add(element);
}
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(" === End Struct === ");
#endif
}
Stream.Seek(originalPos, SeekOrigin.Begin);
node = items;
}
else
node = null;
break;
}
case MemberType.ReferenceToArray:
case MemberType.ReferenceToVariantArray:
{
StructReference structRef;
if (definition.Type == MemberType.ReferenceToVariantArray)
structRef = ReadStructReference();
else
structRef = definition.Definition;
var itemsRef = ReadArrayReference();
Debug.Assert(itemsRef.IsValid == (itemsRef.Size != 0));
if (itemsRef.IsValid &&
parent != null &&
(node != null || kind == SerializationKind.UserMember))
{
Debug.Assert(structRef.IsValid);
var structType = structRef.Resolve(this);
var originalPos = Stream.Position;
Seek(itemsRef);
if (kind == SerializationKind.UserMember)
{
// For ReferenceTo(Variant)Array, we start serialization after resolving the array ref itself.
node = definition.Serializer.Read(this, structType, definition, itemsRef.Size, parent);
}
else
{
var items = node as System.Collections.IList;
var type = items.GetType().GetGenericArguments().Single();
if (definition.Type == MemberType.ReferenceToVariantArray &&
kind != SerializationKind.UserElement &&
definition.TypeSelector != null)
type = definition.TypeSelector.SelectType(definition, structType, parent);
for (int i = 0; i < itemsRef.Size; i++)
{
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(String.Format(" === Struct <{0}> at {1:X8} === ", definition.Name, Stream.Position));
#endif
if (kind == SerializationKind.UserElement)
{
object element = definition.Serializer.Read(this, structType, definition, 0, parent);
items.Add(element);
}
else
{
object element = Helpers.CreateInstance(type);
element = ReadStruct(structType, definition.Type, element, parent);
items.Add(element);
}
#if DEBUG_GR2_SERIALIZATION
System.Console.WriteLine(" === End Struct === ");
#endif
}
}
Stream.Seek(originalPos, SeekOrigin.Begin);
}
else
node = null;
break;
}
case MemberType.String:
var str = ReadStringReference();
if (str.IsValid)
node = str.Resolve(this);
else
node = null;
break;
case MemberType.Transform:
var transform = new Transform();
transform.Flags = Reader.ReadUInt32();
for (int i = 0; i < 3; i++)
transform.Translation[i] = Reader.ReadSingle();
transform.Rotation.X = Reader.ReadSingle();
transform.Rotation.Y = Reader.ReadSingle();
transform.Rotation.Z = Reader.ReadSingle();
transform.Rotation.W = Reader.ReadSingle();
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
transform.ScaleShear[i, j] = Reader.ReadSingle();
}
node = transform;
break;
case MemberType.Real16:
throw new NotImplementedException("TODO");
case MemberType.Real32:
node = Reader.ReadSingle();
break;
case MemberType.Int8:
case MemberType.BinormalInt8:
node = Reader.ReadSByte();
break;
case MemberType.UInt8:
case MemberType.NormalUInt8:
node = Reader.ReadByte();
break;
case MemberType.Int16:
case MemberType.BinormalInt16:
node = Reader.ReadInt16();
break;
case MemberType.UInt16:
case MemberType.NormalUInt16:
node = Reader.ReadUInt16();
break;
case MemberType.Int32:
node = Reader.ReadInt32();
break;
case MemberType.UInt32:
node = Reader.ReadUInt32();
break;
default:
throw new ParsingException(String.Format("Unhandled member type: {0}", definition.Type.ToString()));
}
#if DEBUG_GR2_SERIALIZATION
if (node != null)
System.Console.WriteLine(String.Format(" [{0:X8}] {1}: {2}", offsetInFile, definition.Name, node.ToString()));
else
System.Console.WriteLine(String.Format(" [{0:X8}] {1}: <null>", offsetInFile, definition.Name));
#endif
return node;
}