(ded4a3e0a) v0.9.0.7

This commit is contained in:
Joonas Rikkonen
2019-06-25 16:00:44 +03:00
parent e5ae622c77
commit 4a51db77b5
1777 changed files with 421528 additions and 917 deletions
@@ -0,0 +1,48 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
class ArraySerializer<T> : ContentTypeSerializer<T[]>
{
private readonly ListSerializer<T> _listSerializer;
public ArraySerializer() :
base("array")
{
_listSerializer = new ListSerializer<T>();
}
protected internal override void Initialize(IntermediateSerializer serializer)
{
_listSerializer.Initialize(serializer);
}
public override bool ObjectIsEmpty(T[] value)
{
return value.Length == 0;
}
protected internal override void ScanChildren(IntermediateSerializer serializer, ChildCallback callback, T[] value)
{
_listSerializer.ScanChildren(serializer, callback, new List<T>(value));
}
protected internal override T[] Deserialize(IntermediateReader input, ContentSerializerAttribute format, T[] existingInstance)
{
if (existingInstance != null)
throw new InvalidOperationException("You cannot deserialize an array into a getter-only property.");
var result = _listSerializer.Deserialize(input, format, null);
return result.ToArray();
}
protected internal override void Serialize(IntermediateWriter output, T[] value, ContentSerializerAttribute format)
{
_listSerializer.Serialize(output, new List<T>(value), format);
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class BoolSerializer : ElementSerializer<bool>
{
public BoolSerializer() :
base("bool", 1)
{
}
protected internal override bool Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToBoolean(inputs[index++]);
}
protected internal override void Serialize(bool value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class ByteSerializer : ElementSerializer<byte>
{
public ByteSerializer() :
base("byte", 1)
{
}
protected internal override byte Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToByte(inputs[index++]);
}
protected internal override void Serialize(byte value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,38 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class CharSerializer : ElementSerializer<char>
{
public CharSerializer() :
base("char", 1)
{
}
protected internal override char Deserialize(string[] inputs, ref int index)
{
var str = inputs[index++];
if (str.Length == 1)
return XmlConvert.ToChar(str);
// Try parsing it as a UTF code.
int val;
if (int.TryParse(str, out val))
return char.ConvertFromUtf32(val)[0];
// Last ditch effort to decode it as XML escape value.
return XmlConvert.ToChar(XmlConvert.DecodeName(str));
}
protected internal override void Serialize(char value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,35 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Globalization;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class ColorSerializer : ElementSerializer<Color>
{
public ColorSerializer() :
base("Color", 1)
{
}
protected internal override Color Deserialize(string[] inputs, ref int index)
{
// NOTE: The value is serialized in ARGB format.
var value = uint.Parse(inputs[index++], NumberStyles.HexNumber, CultureInfo.InvariantCulture);
return new Color( (int)(value >> 16 & 0xFF),
(int)(value >> 8 & 0xFF),
(int)(value >> 0 & 0xFF),
(int)(value >> 24 & 0xFF));
}
protected internal override void Serialize(Color value, List<string> results)
{
// NOTE: The value is serialized in ARGB format.
results.Add(string.Format("{0:X2}{1:X2}{2:X2}{3:X2}", value.A, value.R, value.G, value.B));
}
}
}
@@ -0,0 +1,45 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
public abstract class ContentTypeSerializer
{
protected ContentTypeSerializer(Type targetType, string xmlTypeName)
{
TargetType = targetType;
XmlTypeName = xmlTypeName;
}
public virtual bool CanDeserializeIntoExistingObject
{
get { return false; }
}
public Type TargetType { get; private set; }
public string XmlTypeName { get; private set; }
protected internal abstract object Deserialize(IntermediateReader input, ContentSerializerAttribute format, object existingInstance);
protected internal virtual void Initialize(IntermediateSerializer serializer)
{
}
public virtual bool ObjectIsEmpty(object value)
{
return false;
}
protected internal virtual void ScanChildren(IntermediateSerializer serializer, ChildCallback callback, object value)
{
}
protected internal abstract void Serialize(IntermediateWriter output, object value, ContentSerializerAttribute format);
internal protected delegate void ChildCallback(ContentTypeSerializer typeSerializer, object value);
}
}
@@ -0,0 +1,62 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
/// <summary>
/// Used to identify custom ContentTypeSerializer classes.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class ContentTypeSerializerAttribute : Attribute
{
/// <summary>
/// Initializes an instance of the ContentTypeSerializerAttribute.
/// </summary>
public ContentTypeSerializerAttribute()
{
}
private static readonly object _lock = new object();
private static ReadOnlyCollection<Type> _types;
static internal ReadOnlyCollection<Type> GetTypes()
{
lock (_lock)
{
if (_types == null)
{
var found = new List<Type>();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
try
{
var types = assembly.GetTypes();
foreach (var type in types)
{
var attributes = type.GetCustomAttributes(typeof (ContentTypeSerializerAttribute), false);
if (attributes.Length > 0)
found.Add(type);
}
}
catch (System.Reflection.ReflectionTypeLoadException ex)
{
Console.WriteLine("Warning: " + ex.Message);
}
}
_types = new ReadOnlyCollection<Type>(found);
}
}
return _types;
}
}
}
@@ -0,0 +1,59 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
public abstract class ContentTypeSerializer<T> : ContentTypeSerializer
{
protected ContentTypeSerializer() :
this(string.Empty)
{
}
protected ContentTypeSerializer(string xmlTypeName) :
base(typeof(T), xmlTypeName)
{
}
protected internal abstract T Deserialize(IntermediateReader input, ContentSerializerAttribute format, T existingInstance);
protected internal override object Deserialize(IntermediateReader input, ContentSerializerAttribute format, object existingInstance)
{
var cast = existingInstance == null ? default(T) : (T)existingInstance;
return Deserialize(input, format, cast);
}
public virtual bool ObjectIsEmpty(T value)
{
return base.ObjectIsEmpty(value);
}
public override bool ObjectIsEmpty(object value)
{
var cast = value == null ? default(T) : (T)value;
return ObjectIsEmpty(cast);
}
protected internal virtual void ScanChildren(IntermediateSerializer serializer, ChildCallback callback, T value)
{
}
protected internal override void ScanChildren(IntermediateSerializer serializer, ChildCallback callback, object value)
{
if (value == null)
return;
ScanChildren(serializer, callback, (T)value);
}
protected internal abstract void Serialize(IntermediateWriter output, T value, ContentSerializerAttribute format);
protected internal override void Serialize(IntermediateWriter output, object value, ContentSerializerAttribute format)
{
var cast = value == null ? default(T) : (T)value;
Serialize(output, cast, format);
}
}
}
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class CurveKeyCollectionSerializer : ContentTypeSerializer<CurveKeyCollection>
{
public CurveKeyCollectionSerializer() :
base("Keys")
{ }
public override bool CanDeserializeIntoExistingObject
{ get { return true; } }
protected internal override CurveKeyCollection Deserialize(
IntermediateReader input,
ContentSerializerAttribute format,
CurveKeyCollection existingInstance)
{
var result = existingInstance ?? new CurveKeyCollection();
if (input.Xml.HasValue)
{
var elements = PackedElementsHelper.ReadElements(input);
if (elements.Length > 0)
{
// Each CurveKey consists of 5 elements
if (elements.Length % 5 != 0)
throw new InvalidContentException(
"Elements count in CurveKeyCollection is inncorect!");
try
{
// Parse all CurveKeys
for (int i = 0; i < elements.Length; i += 5)
{
// Order: Position, Value, TangentIn, TangentOut and Continuity
var curveKey = new CurveKey
(XmlConvert.ToSingle(elements[i]),
XmlConvert.ToSingle(elements[i + 1]),
XmlConvert.ToSingle(elements[i + 2]),
XmlConvert.ToSingle(elements[i + 3]),
(CurveContinuity)Enum.Parse(
typeof(CurveContinuity),
elements[i + 4],
true));
result.Add(curveKey);
}
}
catch (Exception e)
{
throw new InvalidContentException
("Error parsing CurveKey", e);
}
}
}
return result;
}
protected internal override void Serialize(
IntermediateWriter output,
CurveKeyCollection value,
ContentSerializerAttribute format)
{
var elements = new List<string>();
foreach (var curveKey in value)
{
// Order: Position, Value, TangentIn, TangentOut and Continuity
elements.Add(XmlConvert.ToString(curveKey.Position));
elements.Add(XmlConvert.ToString(curveKey.Value));
elements.Add(XmlConvert.ToString(curveKey.TangentIn));
elements.Add(XmlConvert.ToString(curveKey.TangentOut));
elements.Add(curveKey.Continuity.ToString());
}
var str = PackedElementsHelper.JoinElements(elements);
output.Xml.WriteString(str);
}
}
}
@@ -0,0 +1,92 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class DictionarySerializer<TKey,TValue> : ContentTypeSerializer<Dictionary<TKey,TValue>>
{
private ContentTypeSerializer _keySerializer;
private ContentTypeSerializer _valueSerializer;
private ContentSerializerAttribute _keyFormat;
private ContentSerializerAttribute _valueFormat;
public DictionarySerializer() :
base("dictionary")
{
}
public override bool CanDeserializeIntoExistingObject
{
get { return true; }
}
protected internal override void Initialize(IntermediateSerializer serializer)
{
_keySerializer = serializer.GetTypeSerializer(typeof(TKey));
_valueSerializer = serializer.GetTypeSerializer(typeof(TValue));
_keyFormat = new ContentSerializerAttribute
{
ElementName = "Key",
AllowNull = false
};
_valueFormat = new ContentSerializerAttribute()
{
ElementName = "Value",
AllowNull = typeof(TValue).IsValueType
};
}
public override bool ObjectIsEmpty(Dictionary<TKey, TValue> value)
{
return value.Count == 0;
}
protected internal override void ScanChildren(IntermediateSerializer serializer, ChildCallback callback, Dictionary<TKey, TValue> value)
{
foreach (var kvp in value)
{
callback(_keySerializer, kvp.Key);
callback(_valueSerializer, kvp.Value);
}
}
protected internal override Dictionary<TKey, TValue> Deserialize(IntermediateReader input, ContentSerializerAttribute format, Dictionary<TKey, TValue> existingInstance)
{
var result = existingInstance ?? new Dictionary<TKey, TValue>();
while (input.MoveToElement(format.CollectionItemName))
{
input.Xml.ReadStartElement();
var key = input.ReadObject<TKey>(_keyFormat, _keySerializer);
var value = input.ReadObject<TValue>(_valueFormat, _valueSerializer);
result.Add(key,value);
input.Xml.ReadEndElement();
}
return result;
}
protected internal override void Serialize(IntermediateWriter output, Dictionary<TKey, TValue> value, ContentSerializerAttribute format)
{
foreach (var kvp in value)
{
output.Xml.WriteStartElement(format.CollectionItemName);
output.WriteObject(kvp.Key, _keyFormat, _keySerializer);
output.WriteObject(kvp.Value, _valueFormat, _valueSerializer);
output.Xml.WriteEndElement();
}
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class DoubleSerializer : ElementSerializer<double>
{
public DoubleSerializer() :
base("double", 1)
{
}
protected internal override double Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToDouble(inputs[index++]);
}
protected internal override void Serialize(double value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,75 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
abstract class ElementSerializer<T> : ContentTypeSerializer<T>
{
private readonly int _elementCount;
protected ElementSerializer(string xmlTypeName, int elementCount) :
base(xmlTypeName)
{
_elementCount = elementCount;
}
protected void ThrowElementCountException()
{
throw new InvalidContentException("Not have enough entries in space-separated list!");
}
protected internal abstract T Deserialize(string [] inputs, ref int index);
protected internal abstract void Serialize(T value, List<string> results);
protected internal void Deserialize(IntermediateReader input, List<T> results)
{
var elements = PackedElementsHelper.ReadElements(input);
for (var index = 0; index < elements.Length;)
{
if (elements.Length - index < _elementCount)
ThrowElementCountException();
var elem = Deserialize(elements, ref index);
results.Add(elem);
}
}
protected internal override T Deserialize(IntermediateReader input, ContentSerializerAttribute format, T existingInstance)
{
var elements = PackedElementsHelper.ReadElements(input);
if (elements.Length < _elementCount)
ThrowElementCountException();
var index = 0;
return Deserialize(elements, ref index);
}
protected internal void Serialize(IntermediateWriter output, List<T> values)
{
var elements = new List<string>();
for (var i = 0; i < values.Count; i++)
Serialize(values[i], elements);
var str = PackedElementsHelper.JoinElements(elements);
output.Xml.WriteString(str);
}
protected internal override void Serialize(IntermediateWriter output, T value, ContentSerializerAttribute format)
{
var elements = new List<string>();
Serialize(value, elements);
var str = PackedElementsHelper.JoinElements(elements);
output.Xml.WriteString(str);
}
}
}
@@ -0,0 +1,36 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Diagnostics;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
class EnumSerializer : ContentTypeSerializer
{
public EnumSerializer(Type targetType) :
base(targetType, targetType.Name)
{
}
protected internal override object Deserialize(IntermediateReader input, ContentSerializerAttribute format, object existingInstance)
{
var str = input.Xml.ReadString();
try
{
return Enum.Parse(TargetType, str, true);
}
catch (Exception ex)
{
throw input.NewInvalidContentException(ex, "Invalid enum value '{0}' for type '{1}'", str, TargetType.Name);
}
}
protected internal override void Serialize(IntermediateWriter output, object value, ContentSerializerAttribute format)
{
Debug.Assert(value.GetType() == TargetType, "Got invalid value type!");
output.Xml.WriteString(value.ToString());
}
}
}
@@ -0,0 +1,29 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class ExternalReferenceSerializer<T> : ContentTypeSerializer<ExternalReference<T>>
{
public ExternalReferenceSerializer() :
base("ExternalReference")
{
}
protected internal override ExternalReference<T> Deserialize(IntermediateReader input, ContentSerializerAttribute format, ExternalReference<T> existingInstance)
{
var result = existingInstance ?? new ExternalReference<T>();
input.ReadExternalReference(result);
return result;
}
protected internal override void Serialize(IntermediateWriter output, ExternalReference<T> value, ContentSerializerAttribute format)
{
output.WriteExternalReference(value);
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class FloatSerializer : ElementSerializer<float>
{
public FloatSerializer() :
base("float", 1)
{
}
protected internal override float Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToSingle(inputs[index++]);
}
protected internal override void Serialize(float value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,83 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
internal class GenericCollectionHelper
{
public static bool IsGenericCollectionType(Type type, bool checkAncestors)
{
return GetCollectionElementType(type, checkAncestors) != null;
}
private static Type GetCollectionElementType(Type type, bool checkAncestors)
{
if (!checkAncestors && type.BaseType != null && FindCollectionInterface(type.BaseType) != null)
return null;
var collectionInterface = FindCollectionInterface(type);
if (collectionInterface == null)
return null;
return collectionInterface.GetGenericArguments()[0];
}
private static Type FindCollectionInterface(Type type)
{
var interfaces = type.FindInterfaces((t, o) =>
{
if (t.IsGenericType)
return t.GetGenericTypeDefinition() == typeof(ICollection<>);
return false;
}, null);
return (interfaces.Length == 1)
? interfaces[0]
: null;
}
private readonly ContentTypeSerializer _contentSerializer;
private readonly PropertyInfo _countProperty;
private readonly MethodInfo _addMethod;
public GenericCollectionHelper(IntermediateSerializer serializer, Type type)
{
var collectionElementType = GetCollectionElementType(type, false);
_contentSerializer = serializer.GetTypeSerializer(collectionElementType);
var collectionType = typeof(ICollection<>).MakeGenericType(collectionElementType);
_countProperty = collectionType.GetProperty("Count");
_addMethod = collectionType.GetMethod("Add", new[] { collectionElementType });
}
public bool ObjectIsEmpty(object list)
{
return (int) _countProperty.GetValue(list, null) == 0;
}
public void ScanChildren(ContentTypeSerializer.ChildCallback callback, object collection)
{
foreach (var item in (IEnumerable) collection)
if (item != null)
callback(_contentSerializer, item);
}
public void Serialize(IntermediateWriter output, object collection, ContentSerializerAttribute format)
{
var itemFormat = new ContentSerializerAttribute();
itemFormat.ElementName = format.CollectionItemName;
foreach (var item in (IEnumerable) collection)
output.WriteObject(item, itemFormat, _contentSerializer);
}
public void Deserialize(IntermediateReader input, object collection, ContentSerializerAttribute format)
{
var itemFormat = new ContentSerializerAttribute();
itemFormat.ElementName = format.CollectionItemName;
while (input.MoveToElement(format.CollectionItemName))
_addMethod.Invoke(collection, new[] { input.ReadObject<object>(itemFormat, _contentSerializer) });
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class IntSerializer : ElementSerializer<int>
{
public IntSerializer() :
base("int", 1)
{
}
protected internal override int Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToInt32(inputs[index++]);
}
protected internal override void Serialize(int value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,261 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
public sealed class IntermediateReader
{
private readonly string _filePath;
private readonly Dictionary<string, Action<object>> _resourceFixups;
private readonly Dictionary<string, List<Action<Type, string>>> _externalReferences;
public XmlReader Xml { get; private set; }
public IntermediateSerializer Serializer { get; private set; }
internal IntermediateReader(IntermediateSerializer serializer, XmlReader xmlReader, string filePath)
{
Serializer = serializer;
Xml = xmlReader;
_filePath = filePath;
_resourceFixups = new Dictionary<string, Action<object>>();
_externalReferences = new Dictionary<string, List<Action<Type, string>>>();
}
public bool MoveToElement(string elementName)
{
var nodeType = Xml.MoveToContent();
return nodeType == XmlNodeType.Element &&
Xml.Name == elementName;
}
public T ReadObject<T>(ContentSerializerAttribute format)
{
return ReadObject(format, Serializer.GetTypeSerializer(typeof(T)), default(T));
}
public T ReadObject<T>(ContentSerializerAttribute format, ContentTypeSerializer typeSerializer)
{
return ReadObject(format, typeSerializer, default(T));
}
public T ReadObject<T>(ContentSerializerAttribute format, ContentTypeSerializer typeSerializer, T existingInstance)
{
if (!format.FlattenContent)
{
if (!MoveToElement(format.ElementName))
throw NewInvalidContentException(null, "Element '{0}' was not found.", format.ElementName);
// Is the object null?
var isNull = Xml.GetAttribute("Null");
if (isNull != null && XmlConvert.ToBoolean(isNull))
{
if (!format.AllowNull)
throw NewInvalidContentException(null, "Element '{0}' cannot be null.", format.ElementName);
Xml.Skip();
return default(T);
}
// Is the object overloading the serialized type?
if (Xml.MoveToAttribute("Type"))
{
var type = ReadTypeName();
if (type == null)
throw NewInvalidContentException(null, "Could not resolve type '{0}'.", Xml.ReadContentAsString());
if (!typeSerializer.TargetType.IsAssignableFrom(type))
throw NewInvalidContentException(null, "Type '{0}' is not assignable to '{1}'.", type.FullName, typeSerializer.TargetType.FullName);
typeSerializer = Serializer.GetTypeSerializer(type);
Xml.MoveToElement();
}
}
return ReadRawObject(format, typeSerializer, existingInstance);
}
public T ReadObject<T>(ContentSerializerAttribute format, T existingInstance)
{
return ReadObject(format, Serializer.GetTypeSerializer(typeof(T)), existingInstance);
}
public T ReadRawObject<T>(ContentSerializerAttribute format)
{
return ReadRawObject(format, Serializer.GetTypeSerializer(typeof(T)), default(T));
}
public T ReadRawObject<T>(ContentSerializerAttribute format, ContentTypeSerializer typeSerializer)
{
return ReadRawObject(format, typeSerializer, default(T));
}
public T ReadRawObject<T>(ContentSerializerAttribute format, ContentTypeSerializer typeSerializer, T existingInstance)
{
if (format.FlattenContent)
{
Xml.MoveToContent();
return (T)typeSerializer.Deserialize(this, format, existingInstance);
}
if (!MoveToElement(format.ElementName))
throw NewInvalidContentException(null, "Element '{0}' was not found.", format.ElementName);
var isEmpty = Xml.IsEmptyElement;
if (!isEmpty)
Xml.ReadStartElement();
var result = typeSerializer.Deserialize(this, format, existingInstance);
if (isEmpty)
Xml.Skip();
if (!isEmpty)
Xml.ReadEndElement();
return (T)result;
}
public T ReadRawObject<T>(ContentSerializerAttribute format, T existingInstance)
{
return ReadRawObject(format, Serializer.GetTypeSerializer(typeof(T)), existingInstance);
}
public void ReadSharedResource<T>(ContentSerializerAttribute format, Action<T> fixup)
{
string str;
if (format.FlattenContent)
str = Xml.ReadContentAsString();
else
{
if (!MoveToElement(format.ElementName))
throw NewInvalidContentException(null, "Element '{0}' was not found.", format.ElementName);
str = Xml.ReadElementContentAsString();
}
if (string.IsNullOrEmpty(str))
return;
// Do we already have one for this?
Action<object> prevFixup;
if (!_resourceFixups.TryGetValue(str, out prevFixup))
_resourceFixups.Add(str, (o) => fixup((T)o));
else
{
_resourceFixups[str] = (o) =>
{
prevFixup(o);
fixup((T)o);
};
}
}
internal void ReadSharedResources()
{
if (!MoveToElement("Resources"))
return;
var resources = new Dictionary<string, object>();
var resourceFormat = new ContentSerializerAttribute { ElementName = "Resource" };
// Read all the resources.
Xml.ReadStartElement();
while (MoveToElement("Resource"))
{
var id = Xml.GetAttribute("ID");
var resource = ReadObject<object>(resourceFormat);
resources.Add(id, resource);
}
Xml.ReadEndElement();
// Execute the fixups.
foreach (var fixup in _resourceFixups)
{
object resource;
if (!resources.TryGetValue(fixup.Key, out resource))
throw new InvalidContentException("Missing shared resource \"" + fixup.Key + "\".");
fixup.Value(resource);
}
}
public void ReadExternalReference<T>(ExternalReference<T> existingInstance)
{
if (!MoveToElement("Reference"))
return;
var str = Xml.ReadElementContentAsString();
Action<Type, string> fixup = (type, filename) =>
{
if (type != typeof(T))
throw NewInvalidContentException(null, "Invalid external reference type");
existingInstance.Filename = filename;
};
List<Action<Type, string>> fixups;
if (!_externalReferences.TryGetValue(str, out fixups))
_externalReferences.Add(str, fixups = new List<Action<Type, string>>());
fixups.Add(fixup);
}
internal void ReadExternalReferences()
{
if (!MoveToElement("ExternalReferences"))
return;
var currentDir = Path.GetDirectoryName(_filePath);
// Read all the external references.
Xml.ReadStartElement();
while (MoveToElement("ExternalReference"))
{
List<Action<Type, string>> fixups;
var id = Xml.GetAttribute("ID");
if (!_externalReferences.TryGetValue(id, out fixups))
throw NewInvalidContentException(null, "Unknown external reference id '{0}'!", id);
Xml.MoveToAttribute("TargetType");
var targetType = ReadTypeName();
if (targetType == null)
throw NewInvalidContentException(null, "Could not resolve type '{0}'.", Xml.ReadContentAsString());
Xml.MoveToElement();
var filename = Xml.ReadElementString();
filename = Path.Combine(currentDir, filename);
// Apply the fixups.
foreach (var fixup in fixups)
fixup(targetType, filename);
}
Xml.ReadEndElement();
}
internal InvalidContentException NewInvalidContentException(Exception innerException, string message, params object[] args)
{
var xmlInfo = (IXmlLineInfo)Xml;
var lineAndColumn = string.Format("{0},{1}", xmlInfo.LineNumber, xmlInfo.LinePosition);
var identity = new ContentIdentity(_filePath, string.Empty, lineAndColumn);
return new InvalidContentException(string.Format(message, args), identity, innerException);
}
/// <summary>
/// Reads the next type in the
/// </summary>
/// <returns></returns>
public Type ReadTypeName()
{
var typeName = Xml.ReadContentAsString();
return Serializer.FindType(typeName);
}
}
}
@@ -0,0 +1,361 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
// The intermediate serializer implementation is based on testing XNA behavior and the following sources:
//
// http://msdn.microsoft.com/en-us/library/Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.aspx
// http://blogs.msdn.com/b/shawnhar/archive/2008/08/12/everything-you-ever-wanted-to-know-about-intermediateserializer.aspx
// http://blogs.msdn.com/b/shawnhar/archive/2008/08/26/customizing-intermediateserializer-part-1.aspx
// http://blogs.msdn.com/b/shawnhar/archive/2008/08/26/customizing-intermediateserializer-part-2.aspx
// http://blogs.msdn.com/b/shawnhar/archive/2008/08/27/why-intermediateserializer-control-attributes-are-not-part-of-the-content-pipeline.aspx
//
public class IntermediateSerializer
{
/// <summary>
/// According to the examples on Sean Hargreaves' blog, explicit types
/// can also specify the type aliases from C#. This maps those names
/// to the actual .NET framework types for parsing.
/// </summary>
private static readonly Dictionary<string, Type> _typeAliases = new Dictionary<string, Type>
{
{ "bool", typeof(bool) },
{ "byte", typeof(byte) },
{ "sbyte", typeof(sbyte) },
{ "char", typeof(char) },
{ "decimal",typeof(decimal) },
{ "double", typeof(double) },
{ "float", typeof(float) },
{ "int", typeof(int) },
{ "uint", typeof(uint) },
{ "long", typeof(long) },
{ "ulong", typeof(ulong) },
{ "object", typeof(object) },
{ "short", typeof(short) },
{ "ushort", typeof(ushort) },
{ "string", typeof(string) }
};
private static readonly Dictionary<Type, string> _typeAliasesReverse;
static IntermediateSerializer()
{
_typeAliasesReverse = _typeAliases.ToDictionary(x => x.Value, x => x.Key);
}
private IntermediateSerializer()
{
_scannedObjects = new List<object>();
_namespaceAliasHelper = new NamespaceAliasHelper(this);
}
/// <summary>
/// Maps "ShortName:" -> "My.Namespace.LongName." for type lookups.
/// </summary>
private Dictionary<string, string> _namespaceLookup;
private Dictionary<Type, ContentTypeSerializer> _serializers;
private Dictionary<Type, GenericCollectionHelper> _collectionHelpers;
private Dictionary<Type, Type> _genericSerializerTypes;
private readonly NamespaceAliasHelper _namespaceAliasHelper;
private readonly List<object> _scannedObjects;
public static T Deserialize<T>(XmlReader input, string referenceRelocationPath)
{
var serializer = new IntermediateSerializer();
var reader = new IntermediateReader(serializer, input, referenceRelocationPath);
var asset = default(T);
try
{
if (!reader.MoveToElement("XnaContent"))
throw new InvalidContentException(string.Format("Could not find XnaContent element in '{0}'.",
referenceRelocationPath));
// Initialize the namespace lookups from
// the attributes on the XnaContent element.
serializer.CreateNamespaceLookup(input);
// Move past the XnaContent.
input.ReadStartElement();
// Read the asset.
var format = new ContentSerializerAttribute {ElementName = "Asset"};
asset = reader.ReadObject<T>(format);
// Process the shared resources and external references.
reader.ReadSharedResources();
reader.ReadExternalReferences();
// Move past the closing XnaContent element.
input.ReadEndElement();
}
catch (XmlException xmlException)
{
throw reader.NewInvalidContentException(xmlException, "An error occured parsing.");
}
return asset;
}
public ContentTypeSerializer GetTypeSerializer(Type type)
{
// Create the known serializers if we haven't already.
if (_serializers == null)
{
_serializers = new Dictionary<Type, ContentTypeSerializer>();
_genericSerializerTypes = new Dictionary<Type, Type>();
var types = ContentTypeSerializerAttribute.GetTypes();
foreach (var t in types)
{
if (t.IsGenericType)
{
var genericType = t.BaseType.GetGenericArguments()[0];
_genericSerializerTypes.Add(genericType.GetGenericTypeDefinition(), t);
}
else
{
var cts = Activator.CreateInstance(t) as ContentTypeSerializer;
cts.Initialize(this);
_serializers.Add(cts.TargetType, cts);
}
}
}
// Look it up.
ContentTypeSerializer serializer;
if (_serializers.TryGetValue(type, out serializer))
return serializer;
Type serializerType;
if (type.IsArray)
{
if (type.GetArrayRank() != 1)
throw new RankException("We only support single dimension arrays.");
var arrayType = typeof(ArraySerializer<>).MakeGenericType(new[] { type.GetElementType() });
serializer = (ContentTypeSerializer)Activator.CreateInstance(arrayType);
}
else if (type.IsGenericType && _genericSerializerTypes.TryGetValue(type.GetGenericTypeDefinition(), out serializerType))
{
serializerType = serializerType.MakeGenericType(type.GetGenericArguments());
serializer = (ContentTypeSerializer)Activator.CreateInstance(serializerType);
}
else if (type.IsEnum)
{
serializer = new EnumSerializer(type);
}
else if (typeof(IList).IsAssignableFrom(type) && !GenericCollectionHelper.IsGenericCollectionType(type, true))
{
// Special handling for non-generic IList types. By the time we get here,
// generic collection types will already have been handled by one of the known serializers.
serializer = new NonGenericIListSerializer(type);
}
else
{
// The reflective serializer is not for primitive types!
if (type.IsPrimitive)
throw new NotImplementedException(string.Format("Unhandled primitive type `{0}`!", type.FullName));
// We still don't have a serializer then we
// fallback to the reflection based serializer.
serializer = new ReflectiveSerializer(type);
}
Debug.Assert(serializer.TargetType == type, "Target type mismatch!");
// We cache the serializer before we initialize it to
// avoid a stack overflow on recursive types.
_serializers.Add(type, serializer);
serializer.Initialize(this);
return serializer;
}
internal GenericCollectionHelper GetCollectionHelper(Type type)
{
if (_collectionHelpers == null)
_collectionHelpers = new Dictionary<Type, GenericCollectionHelper>();
GenericCollectionHelper result;
if (!_collectionHelpers.TryGetValue(type, out result))
{
result = new GenericCollectionHelper(this, type);
_collectionHelpers.Add(type, result);
}
return result;
}
public static void Serialize<T>(XmlWriter output, T value, string referenceRelocationPath)
{
var serializer = new IntermediateSerializer();
var writer = new IntermediateWriter(serializer, output, referenceRelocationPath);
output.WriteStartElement("XnaContent");
serializer._namespaceAliasHelper.WriteNamespaces(output, value);
// Write the asset.
var format = new ContentSerializerAttribute { ElementName = "Asset" };
writer.WriteObject<object>(value, format);
// Process the shared resources and external references.
writer.WriteSharedResources();
writer.WriteExternalReferences();
// Close the XnaContent element.
output.WriteEndElement();
}
/// <summary>
/// Builds a lookup table from a short name to the full namespace.
/// </summary>
private void CreateNamespaceLookup(XmlReader reader)
{
_namespaceLookup = new Dictionary<string, string>();
for (var i=0; i < reader.AttributeCount; i++)
{
reader.MoveToAttribute(i);
if (reader.Prefix != "xmlns")
continue;
_namespaceLookup.Add(reader.LocalName + ":", reader.Value + ".");
}
}
/// <summary>
/// Finds the type in any assembly loaded into the AppDomain.
/// </summary>
internal Type FindType(string typeName)
{
Type foundType;
typeName = typeName.Trim();
// Shortcut for friendly C# names
if (_typeAliases.TryGetValue(typeName, out foundType))
return foundType;
// If this is an array then handle it separately.
if (typeName.EndsWith("[]"))
{
var arrayType = typeName.Substring(0, typeName.Length - 2);
foundType = FindType(arrayType);
return foundType == null ? null : foundType.MakeArrayType();
}
// Expand any namespaces in the asset type
foreach (var pair in _namespaceLookup)
typeName = typeName.Replace(pair.Key, pair.Value);
var expandedName = typeName;
// If this a generic type, handle it separately.
if (typeName.EndsWith("]"))
{
var openBracketIndex = typeName.IndexOf("[");
var typeNameWithoutArguments = typeName.Substring(0, openBracketIndex);
var genericArgumentsString = typeName.Substring(openBracketIndex + 1, typeName.Length - openBracketIndex - 2);
var genericArgumentsArray = genericArgumentsString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var genericArguments = genericArgumentsArray.Select(FindType).ToArray();
foundType = FindType(typeNameWithoutArguments + "`" + genericArguments.Length);
return (foundType == null) ? null : foundType.MakeGenericType(genericArguments);
}
foundType = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where type.FullName == typeName || type.Name == typeName
select type).FirstOrDefault();
if (foundType == null)
foundType = Type.GetType(expandedName, false, true);
return foundType;
}
/// <summary>
/// Gets the (potentially) aliased name for any type.
/// </summary>
internal string GetFullTypeName(Type type)
{
string typeName;
// Shortcut for friendly C# names
if (_typeAliasesReverse.TryGetValue(type, out typeName))
return typeName;
// Look for aliased namespace.
if (_namespaceAliasHelper.TryGetAliasedTypeName(type, out typeName))
return typeName;
// Fallback to full type name.
var typeNamespace = type.Namespace;
if (!string.IsNullOrEmpty(typeNamespace))
typeName = typeNamespace + ".";
typeName += GetTypeName(type);
return typeName;
}
/// <summary>
/// Returns the name of the type, without the namespace.
/// For generic types, we add the type parameters in square brackets.
/// i.e. List&lt;int&gt; becomes List[int]
/// </summary>
internal string GetTypeName(Type type)
{
if (type.IsGenericType)
{
var typeName = type.Name;
int genericBacktickIndex = typeName.IndexOf("`");
if (genericBacktickIndex >= 0)
typeName = typeName.Substring(0, genericBacktickIndex);
var result = typeName + "[";
result += string.Join(",", type.GetGenericArguments().Select(GetFullTypeName));
result += "]";
return result;
}
if (type.IsArray)
return GetTypeName(type.GetElementType()) + "[]";
if (type.IsNested)
return type.DeclaringType.Name + "+" + type.Name;
return type.Name;
}
internal bool AlreadyScanned(object value)
{
if (_scannedObjects.Contains(value))
return true;
_scannedObjects.Add(value);
return false;
}
internal bool HasTypeAlias(Type type)
{
return _typeAliasesReverse.ContainsKey(type);
}
}
}
@@ -0,0 +1,222 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
public sealed class IntermediateWriter
{
private readonly Stack<object> _currentObjectStack;
private readonly Dictionary<object, string> _sharedResources;
private readonly Dictionary<object, ExternalReference> _externalReferences;
private readonly string _filePath;
internal IntermediateWriter(IntermediateSerializer serializer, XmlWriter xmlWriter, string filePath)
{
Serializer = serializer;
Xml = xmlWriter;
_filePath = filePath;
_currentObjectStack = new Stack<object>();
_sharedResources = new Dictionary<object, string>();
_externalReferences = new Dictionary<object, ExternalReference>();
}
public XmlWriter Xml { get; private set; }
public IntermediateSerializer Serializer { get; private set; }
public void WriteExternalReference<T>(ExternalReference<T> value)
{
ExternalReference externalReference;
if (!_externalReferences.TryGetValue(value, out externalReference))
_externalReferences.Add(value, externalReference = new ExternalReference
{
ID = "#External" + (_externalReferences.Count + 1),
TargetType = typeof(T).FullName,
FileName = MakeRelativePath(value.Filename)
});
Xml.WriteElementString("Reference", externalReference.ID);
}
private string MakeRelativePath(string path)
{
var fullReferencePath = Path.GetFullPath(Path.GetDirectoryName(_filePath)) + Path.DirectorySeparatorChar;
var fullPath = Path.GetFullPath(path);
return new Uri(fullReferencePath).MakeRelativeUri(new Uri(fullPath)).ToString();
}
private class ExternalReference
{
public string ID;
public string TargetType;
public string FileName;
}
public void WriteObject<T>(T value, ContentSerializerAttribute format)
{
WriteObject(value, format, Serializer.GetTypeSerializer(typeof(T)));
}
public void WriteObject<T>(T value, ContentSerializerAttribute format, ContentTypeSerializer typeSerializer)
{
WriteObjectInternal(value, format, typeSerializer, typeof(T));
}
internal void WriteObjectInternal(object value, ContentSerializerAttribute format, ContentTypeSerializer typeSerializer, Type declaredType)
{
if (format.Optional && (value == null || typeSerializer.ObjectIsEmpty(value)))
return;
var isReferenceObject = false;
if (value != null && !typeSerializer.TargetType.IsValueType)
{
if (_currentObjectStack.Contains(value))
throw new InvalidOperationException("Cyclic reference found during serialization. You may be missing a [ContentSerializer(SharedResource=true)] attribute.");
_currentObjectStack.Push(value);
isReferenceObject = true;
}
if (!format.FlattenContent)
{
Xml.WriteStartElement(format.ElementName);
if (value == null)
{
if (!format.AllowNull)
throw new InvalidOperationException(string.Format("Element {0} cannot be null.", format.ElementName));
Xml.WriteAttributeString("Null", "true");
}
else if (value.GetType() != typeSerializer.TargetType && !IsNullableType(declaredType))
{
Xml.WriteStartAttribute("Type");
WriteTypeName(value.GetType());
Xml.WriteEndAttribute();
typeSerializer = Serializer.GetTypeSerializer(value.GetType());
}
}
if (value != null && !typeSerializer.ObjectIsEmpty(value))
typeSerializer.Serialize(this, value, format);
if (!format.FlattenContent)
Xml.WriteEndElement();
if (isReferenceObject)
_currentObjectStack.Pop();
}
private static bool IsNullableType(Type type)
{
return Nullable.GetUnderlyingType(type) != null;
}
public void WriteRawObject<T>(T value, ContentSerializerAttribute format)
{
WriteRawObject(value, format, Serializer.GetTypeSerializer(typeof(T)));
}
public void WriteRawObject<T>(T value, ContentSerializerAttribute format, ContentTypeSerializer typeSerializer)
{
if (!format.FlattenContent)
Xml.WriteStartElement(format.ElementName);
typeSerializer.Serialize(this, value, format);
if (!format.FlattenContent)
Xml.WriteEndElement();
}
public void WriteSharedResource<T>(T value, ContentSerializerAttribute format)
{
var sharedResourceID = GetSharedResourceID(value);
if (format.FlattenContent)
Xml.WriteValue(sharedResourceID);
else
Xml.WriteElementString(format.ElementName, sharedResourceID);
}
private string GetSharedResourceID(object value)
{
if (value == null)
return null;
string id;
if (!_sharedResources.TryGetValue(value, out id))
_sharedResources.Add(value, id = "#Resource" + (_sharedResources.Count + 1));
return id;
}
internal void WriteSharedResources()
{
if (!_sharedResources.Any())
return;
Xml.WriteStartElement("Resources");
// Loop like this because we might create more shared resources while we're serializing.
var writtenSharedResources = new List<string>();
while (_sharedResources.Any(x => !writtenSharedResources.Contains(x.Value)))
{
var sharedResource = _sharedResources.First(x => !writtenSharedResources.Contains(x.Value));
writtenSharedResources.Add(sharedResource.Value);
WriteSharedResource(sharedResource.Value, sharedResource.Key);
}
Xml.WriteEndElement();
}
private void WriteSharedResource(string id, object sharedResource)
{
Xml.WriteStartElement("Resource");
Xml.WriteAttributeString("ID", id);
Xml.WriteStartAttribute("Type");
WriteTypeName(sharedResource.GetType());
Xml.WriteEndAttribute();
Serializer.GetTypeSerializer(sharedResource.GetType()).Serialize(this, sharedResource, new ContentSerializerAttribute());
Xml.WriteEndElement();
}
internal void WriteExternalReferences()
{
if (!_externalReferences.Any())
return;
Xml.WriteStartElement("ExternalReferences");
foreach (var externalReference in _externalReferences.Values)
{
Xml.WriteStartElement("ExternalReference");
Xml.WriteAttributeString("ID", externalReference.ID);
Xml.WriteAttributeString("TargetType", externalReference.TargetType);
Xml.WriteValue(externalReference.FileName);
Xml.WriteEndElement();
}
Xml.WriteEndElement();
}
public void WriteTypeName(Type type)
{
Xml.WriteString(Serializer.GetFullTypeName(type));
}
}
}
@@ -0,0 +1,82 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class ListSerializer<T> : ContentTypeSerializer<List<T>>
{
private ContentTypeSerializer _itemSerializer;
public ListSerializer() :
base("list")
{
}
public override bool CanDeserializeIntoExistingObject
{
get { return true; }
}
protected internal override void Initialize(IntermediateSerializer serializer)
{
_itemSerializer = serializer.GetTypeSerializer(typeof(T));
}
public override bool ObjectIsEmpty(List<T> value)
{
return value.Count == 0;
}
protected internal override void ScanChildren(IntermediateSerializer serializer, ChildCallback callback, List<T> value)
{
foreach (var item in value)
callback(_itemSerializer, item);
}
protected internal override List<T> Deserialize(IntermediateReader input, ContentSerializerAttribute format, List<T> existingInstance)
{
var result = existingInstance ?? new List<T>();
var elementSerializer = _itemSerializer as ElementSerializer<T>;
if (elementSerializer != null)
elementSerializer.Deserialize(input, result);
else
{
// Create the item serializer attribute.
var itemFormat = new ContentSerializerAttribute();
itemFormat.ElementName = format.CollectionItemName;
// Read all the items.
while (input.MoveToElement(itemFormat.ElementName))
{
var value = input.ReadObject<T>(itemFormat, _itemSerializer);
result.Add(value);
}
}
return result;
}
protected internal override void Serialize(IntermediateWriter output, List<T> value, ContentSerializerAttribute format)
{
var elementSerializer = _itemSerializer as ElementSerializer<T>;
if (elementSerializer != null)
elementSerializer.Serialize(output, value);
else
{
// Create the item serializer attribute.
var itemFormat = new ContentSerializerAttribute();
itemFormat.ElementName = format.CollectionItemName;
// Read all the items.
foreach (var item in value)
output.WriteObject(item, itemFormat, _itemSerializer);
}
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class LongSerializer : ElementSerializer<long>
{
public LongSerializer() :
base("long", 1)
{
}
protected internal override long Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToInt64(inputs[index++]);
}
protected internal override void Serialize(long value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,58 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class MatrixSerializer : ElementSerializer<Matrix>
{
public MatrixSerializer() :
base("Matrix", 16)
{
}
protected internal override Matrix Deserialize(string[] inputs, ref int index)
{
return new Matrix(XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]));
}
protected internal override void Serialize(Matrix value, List<string> results)
{
results.Add(XmlConvert.ToString(value.M11));
results.Add(XmlConvert.ToString(value.M12));
results.Add(XmlConvert.ToString(value.M13));
results.Add(XmlConvert.ToString(value.M14));
results.Add(XmlConvert.ToString(value.M21));
results.Add(XmlConvert.ToString(value.M22));
results.Add(XmlConvert.ToString(value.M23));
results.Add(XmlConvert.ToString(value.M24));
results.Add(XmlConvert.ToString(value.M31));
results.Add(XmlConvert.ToString(value.M32));
results.Add(XmlConvert.ToString(value.M33));
results.Add(XmlConvert.ToString(value.M34));
results.Add(XmlConvert.ToString(value.M41));
results.Add(XmlConvert.ToString(value.M42));
results.Add(XmlConvert.ToString(value.M43));
results.Add(XmlConvert.ToString(value.M44));
}
}
}
@@ -0,0 +1,88 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class NamedValueDictionarySerializer<T> : ContentTypeSerializer<NamedValueDictionary<T>>
{
private ContentTypeSerializer _keySerializer;
private ContentSerializerAttribute _keyFormat;
private ContentSerializerAttribute _valueFormat;
public NamedValueDictionarySerializer() :
base("namedValueDictionary")
{
}
public override bool CanDeserializeIntoExistingObject
{
get { return true; }
}
protected internal override void Initialize(IntermediateSerializer serializer)
{
_keySerializer = serializer.GetTypeSerializer(typeof(string));
_keyFormat = new ContentSerializerAttribute
{
ElementName = "Key",
AllowNull = false
};
_valueFormat = new ContentSerializerAttribute
{
ElementName = "Value",
AllowNull = typeof(T).IsValueType
};
}
public override bool ObjectIsEmpty(NamedValueDictionary<T> value)
{
return value.Count == 0;
}
protected internal override void ScanChildren(IntermediateSerializer serializer, ChildCallback callback, NamedValueDictionary<T> value)
{
foreach (var kvp in value)
callback(serializer.GetTypeSerializer(typeof(T)), kvp.Value);
}
protected internal override NamedValueDictionary<T> Deserialize(IntermediateReader input, ContentSerializerAttribute format, NamedValueDictionary<T> existingInstance)
{
var result = existingInstance ?? new NamedValueDictionary<T>();
var valueSerializer = input.Serializer.GetTypeSerializer(result.DefaultSerializerType);
while (input.MoveToElement(format.CollectionItemName))
{
input.Xml.ReadStartElement();
var key = input.ReadObject<string>(_keyFormat, _keySerializer);
var value = input.ReadObject<T>(_valueFormat, valueSerializer);
result.Add(key,value);
input.Xml.ReadEndElement();
}
return result;
}
protected internal override void Serialize(IntermediateWriter output, NamedValueDictionary<T> value, ContentSerializerAttribute format)
{
var valueSerializer = output.Serializer.GetTypeSerializer(value.DefaultSerializerType);
foreach (var kvp in value)
{
output.Xml.WriteStartElement(format.CollectionItemName);
output.WriteObject(kvp.Key, _keyFormat, _keySerializer);
output.WriteObject(kvp.Value, _valueFormat, valueSerializer);
output.Xml.WriteEndElement();
}
}
}
}
@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
internal class NamespaceAliasHelper
{
private readonly IntermediateSerializer _serializer;
/// <summary>
/// Maps "My.Namespace.LongName" -> "ShortName" for type lookups.
/// </summary>
private Dictionary<string, AliasedNamespace> _namespaceLookupReverse;
private class AliasedNamespace
{
public string Alias;
public string TypePrefix;
}
public NamespaceAliasHelper(IntermediateSerializer serializer)
{
_serializer = serializer;
}
public void WriteNamespaces<T>(XmlWriter writer, T value)
{
// Maps "My.Namespace.LongName" -> "ShortName" for type lookups.
_namespaceLookupReverse = new Dictionary<string, AliasedNamespace>();
// Get all namespaces of types used by "value" or its children.
var childNamespaces = GetAllUsedNamespaces(value).Distinct().ToList();
// Do first pass to determine what our aliases are. We do this on a sorted
// list of namespaces so that more-nested namespaces will be processed last,
// by which time we will have already created the aliases for parent namespaces.
var sortedChildNamespaces = new List<string>(childNamespaces);
sortedChildNamespaces.Sort();
var tempAliases = new Dictionary<string, AliasedNamespace>();
foreach (var childNamespace in sortedChildNamespaces)
{
var alias = FindAlias(tempAliases, childNamespace);
if (alias != null)
tempAliases.Add(childNamespace, alias);
}
// Do second pass on the namespaces as they were originally ordered, to match XNA.
foreach (var childNamespace in childNamespaces)
{
AliasedNamespace alias;
if (tempAliases.TryGetValue(childNamespace, out alias))
_namespaceLookupReverse.Add(childNamespace, alias);
}
foreach (var kvp in _namespaceLookupReverse)
{
if (!string.IsNullOrEmpty(kvp.Value.TypePrefix))
continue;
writer.WriteAttributeString("xmlns", kvp.Value.Alias, null, kvp.Key);
}
}
private IEnumerable<string> GetAllUsedNamespaces<T>(T value)
{
var result = new List<string>();
ContentTypeSerializer.ChildCallback onScanChild = (contentTypeSerializer, child) =>
{
if (child == null)
return;
var childType = child.GetType();
if (contentTypeSerializer.TargetType == childType)
return;
if (contentTypeSerializer.TargetType.IsGenericType
&& contentTypeSerializer.TargetType.GetGenericTypeDefinition() == typeof(Nullable<>)
&& contentTypeSerializer.TargetType.GetGenericArguments()[0] == childType)
return;
if (_serializer.HasTypeAlias(childType))
return;
var childNamespace = childType.Namespace;
if (string.IsNullOrEmpty(childNamespace))
return;
result.Add(childNamespace);
};
// Force top-level object type to be included.
onScanChild(_serializer.GetTypeSerializer(typeof(object)), value);
// Scan child objects.
var serializer = _serializer.GetTypeSerializer(typeof(T));
serializer.ScanChildren(_serializer, onScanChild, value);
return result;
}
private static AliasedNamespace FindAlias(Dictionary<string, AliasedNamespace> aliases, string childNamespace)
{
if (string.IsNullOrEmpty(childNamespace))
return null;
// If there isn't yet an alias for the last part of the namespace, use that.
var alias = childNamespace.Substring(childNamespace.LastIndexOf('.') + 1);
if (aliases.All(x => x.Value.Alias != alias))
return new AliasedNamespace
{
Alias = alias,
TypePrefix = string.Empty
};
// Otherwise, find the longest parent namespace, and use that, with a TypePrefix to make
// this namespace relative to that one.
if (aliases.Any(x => childNamespace.StartsWith(x.Key)))
{
string longestParentNamespace = string.Empty;
foreach (var kvp in aliases.Where(x => string.IsNullOrEmpty(x.Value.TypePrefix)))
{
if (childNamespace.StartsWith(kvp.Key) && kvp.Key.Length > longestParentNamespace.Length)
longestParentNamespace = kvp.Key;
}
return new AliasedNamespace
{
Alias = aliases[longestParentNamespace].Alias,
TypePrefix = GetRelativeNamespace(longestParentNamespace, childNamespace) + "."
};
}
return null;
}
/// <summary>
/// Returns just the portion <paramref name="namespace"/> relative to <paramref name="namespaceParent"/>.
/// For example, given namespaceParent=Foo.Bar and @namespace=Foo.Bar.Baz, will return Baz.
/// </summary>
private static string GetRelativeNamespace(string namespaceParent, string @namespace)
{
if (@namespace.StartsWith(namespaceParent))
return @namespace.Substring(namespaceParent.Length + 1);
throw new InvalidOperationException();
}
public bool TryGetAliasedTypeName(Type type, out string typeName)
{
if (!string.IsNullOrEmpty(type.Namespace))
{
AliasedNamespace namespaceAlias;
if (_namespaceLookupReverse.TryGetValue(type.Namespace, out namespaceAlias))
{
typeName = namespaceAlias.Alias + ":" + namespaceAlias.TypePrefix + _serializer.GetTypeName(type);
return true;
}
}
typeName = null;
return false;
}
}
}
@@ -0,0 +1,56 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
class NonGenericIListSerializer : ContentTypeSerializer
{
public NonGenericIListSerializer(Type targetType) :
base(targetType, targetType.Name)
{
}
public override bool CanDeserializeIntoExistingObject
{
get { return true; }
}
public override bool ObjectIsEmpty(object value)
{
return ((IList) value).Count == 0;
}
protected internal override object Deserialize(IntermediateReader input, ContentSerializerAttribute format, object existingInstance)
{
var result = (IList) (existingInstance ?? Activator.CreateInstance(TargetType));
// Create the item serializer attribute.
var itemFormat = new ContentSerializerAttribute();
itemFormat.ElementName = format.CollectionItemName;
// Read all the items.
while (input.MoveToElement(itemFormat.ElementName))
{
var value = input.ReadObject<object>(itemFormat);
result.Add(value);
}
return result;
}
protected internal override void Serialize(IntermediateWriter output, object value, ContentSerializerAttribute format)
{
// Create the item serializer attribute.
var itemFormat = new ContentSerializerAttribute();
itemFormat.ElementName = format.CollectionItemName;
// Read all the items.
foreach (var item in (IList) value)
output.WriteObject(item, itemFormat);
}
}
}
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class NullableSerializer<T> : ContentTypeSerializer<T?> where T : struct
{
private ContentTypeSerializer _serializer;
private ContentSerializerAttribute _format;
protected internal override void Initialize(IntermediateSerializer serializer)
{
_serializer = serializer.GetTypeSerializer(typeof(T));
_format = new ContentSerializerAttribute
{
FlattenContent = true
};
}
protected internal override T? Deserialize(IntermediateReader input, ContentSerializerAttribute format, T? existingInstance)
{
return input.ReadRawObject<T>(_format, _serializer);
}
protected internal override void Serialize(IntermediateWriter output, T? value, ContentSerializerAttribute format)
{
output.WriteRawObject<T>(value.Value, _format, _serializer);
}
}
}
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
internal static class PackedElementsHelper
{
private static readonly char[] _seperators = { ' ', '\t', '\n' };
private const string _writeSeperator = " ";
internal static string[] ReadElements(IntermediateReader input)
{
if (input.Xml.IsEmptyElement)
return new string[0];
string str = string.Empty;
while (input.Xml.NodeType != XmlNodeType.EndElement)
{
if (input.Xml.NodeType == XmlNodeType.Comment)
input.Xml.Read();
else
str += input.Xml.ReadString();
}
// Special case for char ' '
if (str.Length > 0 && str.Trim() == string.Empty)
return new string[] { str };
var elements = str.Split(_seperators, StringSplitOptions.RemoveEmptyEntries);
if (elements.Length == 1 && string.IsNullOrEmpty(elements[0]))
return new string[0];
return elements;
}
public static string JoinElements(IEnumerable<string> elements)
{
return string.Join(_writeSeperator, elements);
}
}
}
@@ -0,0 +1,34 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class PlaneSerializer : ElementSerializer<Plane>
{
public PlaneSerializer() :
base("Plane", 4)
{
}
protected internal override Plane Deserialize(string[] inputs, ref int index)
{
return new Plane( XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]));
}
protected internal override void Serialize(Plane value, List<string> results)
{
results.Add(XmlConvert.ToString(value.Normal.X));
results.Add(XmlConvert.ToString(value.Normal.Y));
results.Add(XmlConvert.ToString(value.Normal.Z));
results.Add(XmlConvert.ToString(value.D));
}
}
}
@@ -0,0 +1,30 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class PointSerializer : ElementSerializer<Point>
{
public PointSerializer() :
base("Point", 2)
{
}
protected internal override Point Deserialize(string[] inputs, ref int index)
{
return new Point( XmlConvert.ToInt32(inputs[index++]),
XmlConvert.ToInt32(inputs[index++]));
}
protected internal override void Serialize(Point value, List<string> results)
{
results.Add(XmlConvert.ToString(value.X));
results.Add(XmlConvert.ToString(value.Y));
}
}
}
@@ -0,0 +1,34 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class QuaternionSerializer : ElementSerializer<Quaternion>
{
public QuaternionSerializer() :
base("Quaternion", 4)
{
}
protected internal override Quaternion Deserialize(string[] inputs, ref int index)
{
return new Quaternion( XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]));
}
protected internal override void Serialize(Quaternion value, List<string> results)
{
results.Add(XmlConvert.ToString(value.X));
results.Add(XmlConvert.ToString(value.Y));
results.Add(XmlConvert.ToString(value.Z));
results.Add(XmlConvert.ToString(value.W));
}
}
}
@@ -0,0 +1,34 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class RectangleSerializer : ElementSerializer<Rectangle>
{
public RectangleSerializer() :
base("Rectangle", 4)
{
}
protected internal override Rectangle Deserialize(string[] inputs, ref int index)
{
return new Rectangle( XmlConvert.ToInt32(inputs[index++]),
XmlConvert.ToInt32(inputs[index++]),
XmlConvert.ToInt32(inputs[index++]),
XmlConvert.ToInt32(inputs[index++]));
}
protected internal override void Serialize(Rectangle value, List<string> results)
{
results.Add(XmlConvert.ToString(value.X));
results.Add(XmlConvert.ToString(value.Y));
results.Add(XmlConvert.ToString(value.Width));
results.Add(XmlConvert.ToString(value.Height));
}
}
}
@@ -0,0 +1,262 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;
using MonoGame.Utilities;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
internal class ReflectiveSerializer : ContentTypeSerializer
{
const BindingFlags _bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
private struct ElementInfo
{
public ContentSerializerAttribute Attribute;
public ContentTypeSerializer Serializer;
public Action<object, object> Setter;
public Func<object, object> Getter;
};
private readonly List<ElementInfo> _elements = new List<ElementInfo>();
private ContentTypeSerializer _baseSerializer;
private GenericCollectionHelper _collectionHelper;
private bool GetElementInfo(IntermediateSerializer serializer, MemberInfo member, out ElementInfo info)
{
info = new ElementInfo();
// Are we ignoring this property?
if (ReflectionHelpers.GetCustomAttribute<ContentSerializerIgnoreAttribute>(member) != null)
return false;
var prop = member as PropertyInfo;
var field = member as FieldInfo;
var attrib = ReflectionHelpers.GetCustomAttribute<ContentSerializerAttribute>(member);
if (attrib != null)
{
// Store the attribute for later use.
info.Attribute = attrib.Clone();
// Default the to member name as the element name.
if (string.IsNullOrEmpty(attrib.ElementName))
info.Attribute.ElementName = member.Name;
}
else
{
// We don't have a serializer attribute, so we can
// only access this member thru a public field/property.
if (prop != null)
{
// If we don't have at least a public getter then this
// property can't be serialized or deserialized in any way.
if (prop.GetGetMethod() == null)
return false;
// If there is a setter, but it's private, then don't include this element
// (although technically we could, as long as we have a serializer with
// CanDeserializeIntoExistingObject=true for this property type)
var setter = prop.GetSetMethod(true);
if (setter != null && !setter.IsPublic)
return false;
// If there is no setter, and we don't have a type serializer
// that can deserialize into an existing object, then we have no way
// for it to be deserialized.
if (setter == null && !serializer.GetTypeSerializer(prop.PropertyType).CanDeserializeIntoExistingObject)
return false;
// Don't serialize or deserialize indexers.
if (prop.GetIndexParameters().Any())
return false;
}
else if (field != null)
{
if (!field.IsPublic)
return false;
}
info.Attribute = new ContentSerializerAttribute();
info.Attribute.ElementName = member.Name;
}
if (prop != null)
{
info.Serializer = serializer.GetTypeSerializer(prop.PropertyType);
if (prop.CanWrite)
info.Setter = (o, v) => prop.SetValue(o, v, null);
info.Getter = o => prop.GetValue(o, null);
}
else if (field != null)
{
info.Serializer = serializer.GetTypeSerializer(field.FieldType);
info.Setter = field.SetValue;
info.Getter = field.GetValue;
}
return true;
}
public ReflectiveSerializer(Type targetType) :
base(targetType, string.Empty)
{
}
protected internal override void Initialize(IntermediateSerializer serializer)
{
// If we have a base type then we need to deserialize it first.
if (TargetType.BaseType != null)
_baseSerializer = serializer.GetTypeSerializer(TargetType.BaseType);
// Cache all our serializable properties.
var properties = TargetType.GetProperties(_bindingFlags);
foreach (var prop in properties)
{
ElementInfo info;
if (GetElementInfo(serializer, prop, out info))
_elements.Add(info);
}
// Cache all our serializable fields.
var fields = TargetType.GetFields(_bindingFlags);
foreach (var field in fields)
{
ElementInfo info;
if (GetElementInfo(serializer, field, out info))
_elements.Add(info);
}
if (GenericCollectionHelper.IsGenericCollectionType(TargetType, false))
_collectionHelper = serializer.GetCollectionHelper(TargetType);
}
public override bool CanDeserializeIntoExistingObject
{
get { return TargetType.IsClass && TargetType.BaseType != null; }
}
protected internal override object Deserialize(IntermediateReader input, ContentSerializerAttribute format, object existingInstance)
{
var result = existingInstance;
if (result == null)
{
try
{
result = Activator.CreateInstance(TargetType, true);
}
catch (MissingMethodException e)
{
throw new Exception(string.Format("Couldn't create object of type {0}: {1}", TargetType.Name, e.Message), e);
}
}
// First deserialize the base type.
if (_baseSerializer != null)
_baseSerializer.Deserialize(input, format, result);
// Now deserialize our own elements.
foreach (var info in _elements)
{
if (!info.Attribute.FlattenContent)
{
if (!input.MoveToElement(info.Attribute.ElementName))
{
// If the the element was optional then we can
// safely skip it and continue.
if (info.Attribute.Optional)
continue;
// We failed to find a required element.
throw new InvalidContentException(string.Format("The Xml element `{0}` is required, but element `{1}` was found at line {2}:{3}. Try changing the element order or adding missing elements.", info.Attribute.ElementName, input.Xml.Name, ((IXmlLineInfo)input.Xml).LineNumber, ((IXmlLineInfo)input.Xml).LinePosition));
}
}
if (info.Attribute.SharedResource)
{
Action<object> fixup = (o) => info.Setter(result, o);
input.ReadSharedResource(info.Attribute, fixup);
}
else if (info.Setter == null)
{
var value = info.Getter(result);
input.ReadObject(info.Attribute, info.Serializer, value);
}
else
{
var value = input.ReadObject<object>(info.Attribute, info.Serializer);
info.Setter(result, value);
}
}
if (_collectionHelper != null)
_collectionHelper.Deserialize(input, result, format);
return result;
}
public override bool ObjectIsEmpty(object value)
{
if (_baseSerializer != null)
return _baseSerializer.ObjectIsEmpty(value);
if (_collectionHelper != null)
return _collectionHelper.ObjectIsEmpty(value);
return false;
}
protected internal override void ScanChildren(IntermediateSerializer serializer, ChildCallback callback, object value)
{
if (serializer.AlreadyScanned(value))
return;
// First scan the base type.
if (_baseSerializer != null)
_baseSerializer.ScanChildren(serializer, callback, value);
// Now scan our own elements.
foreach (var info in _elements)
{
var elementValue = info.Getter(value);
callback(info.Serializer, elementValue);
var elementSerializer = info.Serializer;
if (elementValue != null)
elementSerializer = serializer.GetTypeSerializer(elementValue.GetType());
elementSerializer.ScanChildren(serializer, callback, elementValue);
}
if (_collectionHelper != null)
_collectionHelper.ScanChildren(callback, value);
}
protected internal override void Serialize(IntermediateWriter output, object value, ContentSerializerAttribute format)
{
// First serialize the base type.
if (_baseSerializer != null)
_baseSerializer.Serialize(output, value, format);
// Now serialize our own elements.
foreach (var info in _elements)
{
var elementValue = info.Getter(value);
if (info.Attribute.SharedResource)
output.WriteSharedResource(elementValue, info.Attribute);
else
output.WriteObjectInternal(elementValue, info.Attribute, info.Serializer, info.Serializer.TargetType);
}
if (_collectionHelper != null)
_collectionHelper.Serialize(output, value, format);
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class SByteSerializer : ElementSerializer<sbyte>
{
public SByteSerializer() :
base("sbyte", 1)
{
}
protected internal override sbyte Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToSByte(inputs[index++]);
}
protected internal override void Serialize(sbyte value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class ShortSerializer : ElementSerializer<short>
{
public ShortSerializer() :
base("short", 1)
{
}
protected internal override short Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToInt16(inputs[index++]);
}
protected internal override void Serialize(short value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,25 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class StringSerializer : ContentTypeSerializer<string>
{
public StringSerializer() :
base("string")
{
}
protected internal override string Deserialize(IntermediateReader input, ContentSerializerAttribute format, string existingInstance)
{
return input.Xml.ReadString();
}
protected internal override void Serialize(IntermediateWriter output, string value, ContentSerializerAttribute format)
{
output.Xml.WriteString(value);
}
}
}
@@ -0,0 +1,29 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class TimeSpanSerializer : ElementSerializer<TimeSpan>
{
public TimeSpanSerializer() :
base("TimeSpan", 1)
{
}
protected internal override TimeSpan Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToTimeSpan(inputs[index++]);
}
protected internal override void Serialize(TimeSpan value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class UIntSerializer : ElementSerializer<uint>
{
public UIntSerializer() :
base("int", 1)
{
}
protected internal override uint Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToUInt32(inputs[index++]);
}
protected internal override void Serialize(uint value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class ULongSerializer : ElementSerializer<ulong>
{
public ULongSerializer() :
base("ulong", 1)
{
}
protected internal override ulong Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToUInt64(inputs[index++]);
}
protected internal override void Serialize(ulong value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,28 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class UShortSerializer : ElementSerializer<ushort>
{
public UShortSerializer() :
base("ushort", 1)
{
}
protected internal override ushort Deserialize(string[] inputs, ref int index)
{
return XmlConvert.ToUInt16(inputs[index++]);
}
protected internal override void Serialize(ushort value, List<string> results)
{
results.Add(XmlConvert.ToString(value));
}
}
}
@@ -0,0 +1,30 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class Vector2Serializer : ElementSerializer<Vector2>
{
public Vector2Serializer() :
base("Vector2", 2)
{
}
protected internal override Vector2 Deserialize(string[] inputs, ref int index)
{
return new Vector2( XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]));
}
protected internal override void Serialize(Vector2 value, List<string> results)
{
results.Add(XmlConvert.ToString(value.X));
results.Add(XmlConvert.ToString(value.Y));
}
}
}
@@ -0,0 +1,32 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class Vector3Serializer : ElementSerializer<Vector3>
{
public Vector3Serializer() :
base("Vector3", 3)
{
}
protected internal override Vector3 Deserialize(string[] inputs, ref int index)
{
return new Vector3( XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]));
}
protected internal override void Serialize(Vector3 value, List<string> results)
{
results.Add(XmlConvert.ToString(value.X));
results.Add(XmlConvert.ToString(value.Y));
results.Add(XmlConvert.ToString(value.Z));
}
}
}
@@ -0,0 +1,34 @@
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System.Collections.Generic;
using System.Xml;
namespace Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate
{
[ContentTypeSerializer]
class Vector4Serializer : ElementSerializer<Vector4>
{
public Vector4Serializer() :
base("Vector4", 4)
{
}
protected internal override Vector4 Deserialize(string[] inputs, ref int index)
{
return new Vector4( XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]),
XmlConvert.ToSingle(inputs[index++]));
}
protected internal override void Serialize(Vector4 value, List<string> results)
{
results.Add(XmlConvert.ToString(value.X));
results.Add(XmlConvert.ToString(value.Y));
results.Add(XmlConvert.ToString(value.Z));
results.Add(XmlConvert.ToString(value.W));
}
}
}