/// <summary>
		/// Reads a <see cref="Duality.Serialization.MetaFormat.StructNode"/>, including possible child nodes.
		/// </summary>
		/// <param name="node"></param>
		protected StructNode ReadStruct(bool classType)
		{
			// Read struct type
			string	objTypeString	= this.reader.GetAttribute("type");
			string	objIdString		= this.reader.GetAttribute("id");
			string	customString	= this.reader.GetAttribute("custom");
			string	surrogateString	= this.reader.GetAttribute("surrogate");
			uint	objId			= objIdString == null ? 0 : XmlConvert.ToUInt32(objIdString);
			bool	custom			= customString != null && XmlConvert.ToBoolean(customString);
			bool	surrogate		= surrogateString != null && XmlConvert.ToBoolean(surrogateString);

			StructNode result = new StructNode(classType, objTypeString, objId, custom, surrogate);
			
			// Read surrogate constructor data
			if (surrogate)
			{
				custom = true;

				// Set fake object reference for surrogate constructor: No self-references allowed here.
				this.idManager.Inject(null, objId);

				CustomSerialIO customIO = new CustomSerialIO(CustomSerialIO.HeaderElement);
				customIO.Deserialize(this);
				if (customIO.Data.Any())
				{
					DummyNode surrogateConstructor = new DummyNode();
					surrogateConstructor.Parent = result;
					foreach (var pair in customIO.Data)
					{
						StringNode key = new StringNode(pair.Key);
						DataNode value = pair.Value as DataNode;
						key.Parent = surrogateConstructor;
						value.Parent = surrogateConstructor;
					}
				}
			}

			// Prepare object reference
			this.idManager.Inject(result, objId);
			
			// Read custom object data
			if (custom)
			{
				CustomSerialIO customIO = new CustomSerialIO(CustomSerialIO.BodyElement);
				customIO.Deserialize(this);
				foreach (var pair in customIO.Data)
				{
					StringNode key = new StringNode(pair.Key);
					DataNode value = pair.Value as DataNode;
					key.Parent = result;
					value.Parent = result;
				}
			}
			// Red non-custom object data
			else if (!this.reader.IsEmptyElement)
			{
				// Read fields
				bool scopeChanged;
				string fieldName;
				DataNode fieldValue;
				while (true)
				{
					fieldValue = this.ReadObject(out fieldName, out scopeChanged) as DataNode;
					if (scopeChanged) break;
					else
					{
						fieldValue.Name = fieldName;
						fieldValue.Parent = result;
					}
				}
			}

			return result;
		}
		/// <summary>
		/// Reads a <see cref="Duality.Serialization.MetaFormat.StructNode"/>, including possible child nodes.
		/// </summary>
		/// <param name="node"></param>
		protected StructNode ReadStruct(bool classType)
		{
			// Read struct type
			string	objTypeString	= this.reader.ReadString();
			uint	objId			= this.reader.ReadUInt32();
			bool	custom			= this.reader.ReadBoolean();
			bool	surrogate		= this.reader.ReadBoolean();

			StructNode result = new StructNode(classType, objTypeString, objId, custom, surrogate);
			
			// Read surrogate constructor data
			if (surrogate)
			{
				custom = true;

				// Set fake object reference for surrogate constructor: No self-references allowed here.
				this.idManager.Inject(null, objId);

				CustomSerialIO customIO = new CustomSerialIO();
				customIO.Deserialize(this);
				if (customIO.Data.Any())
				{
					DummyNode surrogateConstructor = new DummyNode();
					surrogateConstructor.Parent = result;
					foreach (var pair in customIO.Data)
					{
						StringNode key = new StringNode(pair.Key);
						DataNode value = pair.Value as DataNode;
						key.Parent = surrogateConstructor;
						value.Parent = surrogateConstructor;
					}
				}
			}

			// Prepare object reference
			this.idManager.Inject(result, objId);

			if (custom)
			{
				CustomSerialIO customIO = new CustomSerialIO();
				customIO.Deserialize(this);
				foreach (var pair in customIO.Data)
				{
					StringNode key = new StringNode(pair.Key);
					DataNode value = pair.Value as DataNode;
					key.Parent = result;
					value.Parent = result;
				}
			}
			else
			{
				// Determine data layout
				bool wasThereBefore = this.GetCachedTypeDataLayout(objTypeString) != null;
				TypeDataLayout layout = this.ReadTypeDataLayout(objTypeString);
				if (!wasThereBefore)
				{
					TypeDataLayoutNode layoutNode = new TypeDataLayoutNode(new TypeDataLayout(layout));
					layoutNode.Parent = result;
				}

				// Read fields
				if (this.dataVersion <= 2)
				{
					for (int i = 0; i < layout.Fields.Length; i++)
					{
						DataNode fieldValue = this.ReadObject() as DataNode;
						fieldValue.Parent = result;
						fieldValue.Name = layout.Fields[i].name;
					}
				}
				else if (this.dataVersion >= 3)
				{
					bool[] fieldOmitted = new bool[layout.Fields.Length];
					this.ReadArrayData(fieldOmitted);
					
					for (int i = 0; i < layout.Fields.Length; i++)
					{
						if (fieldOmitted[i]) continue;
						DataNode fieldValue = this.ReadObject() as DataNode;
						fieldValue.Parent = result;
						fieldValue.Name = layout.Fields[i].name;
					}
				}
			}

			return result;
		}