Made AnimationEditor compatible with Dictionary SpriteMaps

Added MonoGame Pipeline's IntermediateSerializer and needed classes from the pipeline and  MonoGame.Framework.Utilities to make AnimationEditor capable of reading Dictionaries
This commit is contained in:
quinnvoker
2018-11-24 16:43:44 -08:00
parent 82ad36e485
commit c585f312a5
52 changed files with 3576 additions and 64 deletions
+47
View File
@@ -69,6 +69,53 @@
<Compile Include="Form1.Designer.cs"> <Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon> <DependentUpon>Form1.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="MonoGame.Framework.Content.Pipeline\ContentIdentity.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\InvalidContentException.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\NamedValueDictionary.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ArraySerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\BoolSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ByteSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\CharSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ColorSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ContentTypeSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ContentTypeSerializerAttribute.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ContentTypeSerializerT.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\CurveKeyCollectionSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\DictionarySerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\DoubleSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ElementSerializerT.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\EnumSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\FloatSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\GenericCollectionHelper.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\IntermediateReader.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\IntermediateSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\IntermediateWriter.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\IntSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ListSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\LongSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\MatrixSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\NamedValueDictionarySerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\NamespaceAliasHelper.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\NonGenericIListSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\NullableSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\PackedElementsHelper.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\PlaneSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\PointSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\QuaternionSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\RectangleSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ReflectiveSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\SByteSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ShortSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\StringSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\TimeSpanSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\UIntSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\ULongSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\UShortSerializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\Vector2Serializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\Vector3Serializer.cs" />
<Compile Include="MonoGame.Framework.Content.Pipeline\Serialization\Intermediate\Vector4Serializer.cs" />
<Compile Include="MonoGame.Framework\Utilities\ReflectionHelpers.cs" />
<Compile Include="MonoGame.Framework\Utilities\ReflectionHelpers.Default.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Form1.resx"> <EmbeddedResource Include="Form1.resx">
+13 -4
View File
@@ -13,6 +13,8 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using QURO.AnimationLibrary; using QURO.AnimationLibrary;
using QURO; using QURO;
using System.Xml;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;
namespace AnimationEditor namespace AnimationEditor
{ {
@@ -41,17 +43,24 @@ namespace AnimationEditor
if (loadSpriteMapDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) if (loadSpriteMapDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{ {
XmlSerializer mapSerializer = new XmlSerializer(typeof(List<SpriteMapRegion>)); Dictionary<string, SpriteMapRegion> loadedSpriteMap;
TextReader mapReader = new StreamReader(loadSpriteMapDialog.FileName); using (XmlReader xmlRead = XmlReader.Create(loadSpriteMapDialog.FileName))
{
loadedSpriteMap = IntermediateSerializer.Deserialize<Dictionary<string, SpriteMapRegion>>(xmlRead, null);
}
Sprites = new BindingList<SpriteMapRegion>();
foreach (KeyValuePair<string, SpriteMapRegion> sprite in loadedSpriteMap)
{
Sprites.Add(sprite.Value);
}
Sprites = new BindingList<SpriteMapRegion>((List<SpriteMapRegion>)mapSerializer.Deserialize(mapReader));
spriteListBox.DataSource = Sprites; spriteListBox.DataSource = Sprites;
spriteListBox.DisplayMember = "Name"; spriteListBox.DisplayMember = "Name";
spriteListBox.ValueMember = "Bounds"; spriteListBox.ValueMember = "Bounds";
Rectangle[] frames = new Rectangle[] { Sprites[0].Bounds, Sprites[1].Bounds, Sprites[2].Bounds }; Rectangle[] frames = new Rectangle[] { Sprites[0].Bounds, Sprites[1].Bounds, Sprites[2].Bounds };
animationPreview.CurrentAnimation = new Animation("Test", frames, 1f / 60f, true); animationPreview.CurrentAnimation = new Animation("Test", frames, 1f / 60f, true);
animationPreview.PreviewSprite = new AnimatedSprite(animationPreview.SpriteSheet, animationPreview.CurrentAnimation); animationPreview.PreviewSprite = new AnimatedSprite(animationPreview.SpriteSheet, animationPreview.CurrentAnimation);
mapReader.Close();
} }
} }
@@ -0,0 +1,70 @@
// 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
{
/// <summary>
/// Provides properties describing the origin of the game asset, such as the original source file and creation tool. This information is used for error reporting, and by processors that need to determine from what directory the asset was originally loaded.
/// </summary>
[Serializable]
public class ContentIdentity
{
/// <summary>
/// Gets or sets the specific location of the content item within the larger source file.
/// </summary>
public string FragmentIdentifier { get; set; }
/// <summary>
/// Gets or sets the file name of the asset source.
/// </summary>
public string SourceFilename { get; set; }
/// <summary>
/// Gets or sets the creation tool of the asset.
/// </summary>
public string SourceTool { get; set; }
/// <summary>
/// Initializes a new instance of ContentIdentity.
/// </summary>
public ContentIdentity()
: this(string.Empty, string.Empty, null)
{
}
/// <summary>
/// Initializes a new instance of ContentIdentity with the specified values.
/// </summary>
/// <param name="sourceFilename">The absolute path to the file name of the asset source.</param>
public ContentIdentity(string sourceFilename)
: this(sourceFilename, string.Empty, null)
{
}
/// <summary>
/// Initializes a new instance of ContentIdentity with the specified values.
/// </summary>
/// <param name="sourceFilename">The absolute path to the file name of the asset source.</param>
/// <param name="sourceTool">The name of the digital content creation (DCC) tool that created the asset.</param>
public ContentIdentity(string sourceFilename, string sourceTool)
: this(sourceFilename, sourceTool, null)
{
}
/// <summary>
/// Initializes a new instance of ContentIdentity with the specified values.
/// </summary>
/// <param name="sourceFilename">The absolute path to the file name of the asset source.</param>
/// <param name="sourceTool">The name of the digital content creation (DCC) tool that created the asset.</param>
/// <param name="fragmentIdentifier">Specific location of the content item within the larger source file. For example, this could be a line number in the file.</param>
public ContentIdentity(string sourceFilename, string sourceTool, string fragmentIdentifier)
{
SourceFilename = sourceFilename;
SourceTool = sourceTool;
FragmentIdentifier = fragmentIdentifier;
}
}
}
@@ -0,0 +1,108 @@
// 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.Runtime.Serialization;
namespace Microsoft.Xna.Framework.Content.Pipeline
{
/// <summary>
/// Thrown when errors are encountered in content during processing.
/// </summary>
[SerializableAttribute]
public class InvalidContentException : Exception
{
/// <summary>
/// Gets or sets the identity of the content item that caused the exception.
/// </summary>
public ContentIdentity ContentIdentity { get; set; }
/// <summary>
/// Initializes a new instance of the InvalidContentException class
/// </summary>
public InvalidContentException()
{
}
/// <summary>
/// Initializes a new instance of the InvalidContentException class with information on serialization and streaming context for the related content item.
/// </summary>
/// <param name="serializationInfo">Information necessary for serialization and deserialization of the content item.</param>
/// <param name="streamingContext">Information necessary for the source and destination of a given serialized stream. Also provides an additional caller-defined context.</param>
protected InvalidContentException(
SerializationInfo serializationInfo,
StreamingContext streamingContext
)
{
}
/// <summary>
/// Initializes a new instance of the InvalidContentException class with the specified error message.
/// </summary>
/// <param name="message">A message that describes the error.</param>
public InvalidContentException(
string message
)
: this(message, null, null)
{
}
/// <summary>
/// Initializes a new instance of the InvalidContentException class with the specified error message and the identity of the content throwing the exception.
/// </summary>
/// <param name="message">A message that describes the error.</param>
/// <param name="contentIdentity">Information about the content item that caused this error, including the file name. In some cases, a location within the file (of the problem) is specified.</param>
public InvalidContentException(
string message,
ContentIdentity contentIdentity
)
: this(message, contentIdentity, null)
{
}
/// <summary>
/// Initializes a new instance of the InvalidContentException class with the specified error message, the identity of the content throwing the exception, and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">A message that describes the error.</param>
/// <param name="contentIdentity">Information about the content item that caused this error, including the file name. In some cases, a location within the file (of the problem) is specified.</param>
/// <param name="innerException">The exception that is the cause of the current exception. If innerException is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param>
public InvalidContentException(
string message,
ContentIdentity contentIdentity,
Exception innerException
)
: base(message, innerException)
{
ContentIdentity = contentIdentity;
}
/// <summary>
/// Initializes a new instance of the InvalidContentException class with the specified error message and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">A message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception. If innerException is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param>
public InvalidContentException(
string message,
Exception innerException
)
: this(message, null, innerException)
{
}
/// <summary>
/// When overridden in a derived class, returns information about the exception.
/// In addition to the base behavior, this method provides serialization functionality.
/// </summary>
/// <param name="info">Information necessary for serialization and deserialization of the content item.</param>
/// <param name="context">Information necessary for the source and destination of a given serialized stream. Also provides an additional caller-defined context.</param>
public override void GetObjectData(
SerializationInfo info,
StreamingContext context
)
{
base.GetObjectData(info, context);
// TODO: Complete me...
}
}
}
@@ -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;
using System.Collections.Generic;
namespace Microsoft.Xna.Framework.Content.Pipeline
{
public class NamedValueDictionary<T> : IDictionary<string, T>
{
readonly Dictionary<string, T> dict = new Dictionary<string,T>();
/// <summary>
/// Initializes an instance of NamedValueDictionary.
/// </summary>
public NamedValueDictionary()
{
}
/// <summary>
/// Adds the specified key and value to the dictionary.
/// </summary>
/// <param name="key">Identity of the key of the new data pair.</param>
/// <param name="value">The value of the new data pair.</param>
public void Add(string key, T value)
{
dict.Add(key, value);
}
/// <summary>
/// Determines whether the specified key is present in the dictionary.
/// </summary>
/// <param name="key">Identity of a key.</param>
/// <returns></returns>
public bool ContainsKey(string key)
{
return dict.ContainsKey(key);
}
/// <summary>
/// Gets all keys contained in the dictionary.
/// </summary>
public ICollection<string> Keys
{
get { return dict.Keys; }
}
/// <summary>
/// Removes the specified key and value from the dictionary.
/// </summary>
/// <param name="key">Identity of the key to be removed.</param>
/// <returns>true if the value is present; false otherwise.</returns>
public bool Remove(string key)
{
return dict.Remove(key);
}
/// <summary>
/// Gets the value associated with the specified key.
/// </summary>
/// <param name="key">Identity of the key of the element whose value is to be retrieved.</param>
/// <param name="value">The current value of the element.</param>
/// <returns>true if the value is present; false otherwise.</returns>
public bool TryGetValue(string key, out T value)
{
return dict.TryGetValue(key, out value);
}
/// <summary>
/// Specifies the type hint for the intermediate serializer. Values of this type do not store an explicit type attribute in the related XML source.
/// </summary>
protected internal virtual Type DefaultSerializerType
{
get { return typeof(T); }
}
/// <summary>
/// Gets all values contained in the dictionary.
/// </summary>
public ICollection<T> Values
{
get { return dict.Values; }
}
/// <summary>
/// Gets or sets the specified item.
/// </summary>
/// <param name="key">Identity of a key.</param>
public T this[string key]
{
get
{
return dict[key];
}
set
{
dict[key] = value;
}
}
/// <summary>
/// Adds an item to the collection.
/// </summary>
/// <param name="item">The item to add to the collection.</param>
void ICollection<KeyValuePair<string, T>>.Add(KeyValuePair<string, T> item)
{
((ICollection<KeyValuePair<string, T>>)dict).Add(item);
}
/// <summary>
/// Removes all keys and values from the dictionary.
/// </summary>
public void Clear()
{
dict.Clear();
}
/// <summary>
/// Determines whether the collection contains a specific value.
/// </summary>
/// <param name="item">The object to locate in the collection.</param>
/// <returns>true if the collection contains the object; false otherwise.</returns>
bool ICollection<KeyValuePair<string, T>>.Contains(KeyValuePair<string, T> item)
{
return ((ICollection<KeyValuePair<string, T>>)dict).Contains(item);
}
/// <summary>
/// Copies the elements of the collection to an array, starting at a specified index.
/// </summary>
/// <param name="array">The destination array.</param>
/// <param name="arrayIndex">The index at which to begin the copy.</param>
void ICollection<KeyValuePair<string, T>>.CopyTo(KeyValuePair<string, T>[] array, int arrayIndex)
{
((ICollection<KeyValuePair<string, T>>)dict).CopyTo(array, arrayIndex);
}
/// <summary>
/// Gets the number of items in the dictionary.
/// </summary>
public int Count
{
get { return dict.Count; }
}
/// <summary>
/// Gets a value indicating if this object is read-only.
/// </summary>
bool ICollection<KeyValuePair<string, T>>.IsReadOnly
{
get { return false; }
}
/// <summary>
/// Removes the first occurrence of the specified object from the collection.
/// </summary>
/// <param name="item">The item to remove from the collection.</param>
/// <returns>true if the item was successfully removed from the collection; false otherwise.</returns>
bool ICollection<KeyValuePair<string, T>>.Remove(KeyValuePair<string, T> item)
{
return ((ICollection<KeyValuePair<string, T>>)dict).Remove(item);
}
/// <summary>
/// Gets an enumerator that iterates through items in a dictionary.
/// </summary>
/// <returns>Enumerator for iterating through the dictionary.</returns>
public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
{
return dict.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that can iterate through this collection.
/// </summary>
/// <returns>An enumerator that can iterate through this collection</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return dict.GetEnumerator();
}
/// <summary>
/// Adds an element to the dictionary.
/// </summary>
/// <param name="key">Identity of the key of the new element.</param>
/// <param name="value">The value of the new element.</param>
protected virtual void AddItem(string key, T value)
{
dict.Add(key, value);
}
/// <summary>
/// Removes all elements from the dictionary.
/// </summary>
protected virtual void ClearItems()
{
dict.Clear();
}
/// <summary>
/// Removes the specified element from the dictionary.
/// </summary>
/// <param name="key">Identity of the key of the data pair to be removed.</param>
/// <returns>true if the value is present; false otherwise.</returns>
protected virtual bool RemoveItem(string key)
{
return dict.Remove(key);
}
/// <summary>
/// Modifies the value of an existing element.
/// </summary>
/// <param name="key">Identity of the element to be modified.</param>
/// <param name="value">The value to be set.</param>
protected virtual void SetItem(string key, T value)
{
dict[key] = value;
}
}
}
@@ -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,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,240 @@
// 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);
}
}
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,208 @@
// 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; }
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));
}
}
}
@@ -0,0 +1,36 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace MonoGame.Utilities
{
internal static partial class ReflectionHelpers
{
/// <summary>
/// Generics handler for Marshal.SizeOf
/// </summary>
internal static class SizeOf<T>
{
static int _sizeOf;
static SizeOf()
{
_sizeOf = Marshal.SizeOf<T>();
}
static public int Get()
{
return _sizeOf;
}
}
/// <summary>
/// Fallback handler for Marshal.SizeOf(type)
/// </summary>
internal static int ManagedSizeOf(Type type)
{
return Marshal.SizeOf(type);
}
}
}
@@ -0,0 +1,178 @@
// 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.Reflection;
namespace MonoGame.Utilities
{
internal static partial class ReflectionHelpers
{
public static bool IsValueType(Type targetType)
{
if (targetType == null)
{
throw new NullReferenceException("Must supply the targetType parameter");
}
#if NET45
return targetType.GetTypeInfo().IsValueType;
#else
return targetType.IsValueType;
#endif
}
public static Type GetBaseType(Type targetType)
{
if (targetType == null)
{
throw new NullReferenceException("Must supply the targetType parameter");
}
#if NET45
return targetType.GetTypeInfo().BaseType;
#else
return targetType.BaseType;
#endif
}
/// <summary>
/// Returns the Assembly of a Type
/// </summary>
public static Assembly GetAssembly(Type targetType)
{
if (targetType == null)
{
throw new NullReferenceException("Must supply the targetType parameter");
}
#if NET45
return targetType.GetTypeInfo().Assembly;
#else
return targetType.Assembly;
#endif
}
/// <summary>
/// Returns true if the given type represents a non-object type that is not abstract.
/// </summary>
public static bool IsConcreteClass(Type t)
{
if (t == null)
{
throw new NullReferenceException("Must supply the t (type) parameter");
}
if (t == typeof(object))
return false;
#if NET45
var ti = t.GetTypeInfo();
if (ti.IsClass && !ti.IsAbstract)
return true;
#else
if (t.IsClass && !t.IsAbstract)
return true;
#endif
return false;
}
public static MethodInfo GetMethodInfo(Type type, string methodName)
{
#if NET45
return type.GetTypeInfo().GetDeclaredMethod(methodName);
#else
return type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
#endif
}
public static MethodInfo GetPropertyGetMethod(PropertyInfo property)
{
if (property == null)
{
throw new NullReferenceException("Must supply the property parameter");
}
#if NET45
return property.GetMethod;
#else
return property.GetGetMethod();
#endif
}
public static MethodInfo GetPropertySetMethod(PropertyInfo property)
{
if (property == null)
{
throw new NullReferenceException("Must supply the property parameter");
}
#if NET45
return property.SetMethod;
#else
return property.GetSetMethod();
#endif
}
public static T GetCustomAttribute<T>(MemberInfo member) where T : Attribute
{
if (member == null)
throw new NullReferenceException("Must supply the member parameter");
#if NET45
return member.GetCustomAttribute(typeof(T)) as T;
#else
return Attribute.GetCustomAttribute(member, typeof(T)) as T;
#endif
}
/// <summary>
/// Returns true if the get method of the given property exist and are public.
/// Note that we allow a getter-only property to be serialized (and deserialized),
/// *if* CanDeserializeIntoExistingObject is true for the property type.
/// </summary>
public static bool PropertyIsPublic(PropertyInfo property)
{
if (property == null)
{
throw new NullReferenceException("Must supply the property parameter");
}
var getMethod = GetPropertyGetMethod(property);
if (getMethod == null || !getMethod.IsPublic)
return false;
return true;
}
/// <summary>
/// Returns true if the given type can be assigned the given value
/// </summary>
public static bool IsAssignableFrom(Type type, object value)
{
if (type == null)
throw new ArgumentNullException("type");
if (value == null)
throw new ArgumentNullException("value");
return IsAssignableFromType(type, value.GetType());
}
/// <summary>
/// Returns true if the given type can be assigned a value with the given object type
/// </summary>
public static bool IsAssignableFromType(Type type, Type objectType)
{
if (type == null)
throw new ArgumentNullException("type");
if (objectType == null)
throw new ArgumentNullException("objectType");
#if NET45
if (type.GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()))
return true;
#else
if (type.IsAssignableFrom(objectType))
return true;
#endif
return false;
}
}
}
+37 -37
View File
@@ -37,6 +37,8 @@
this.saveMapButton = new System.Windows.Forms.Button(); this.saveMapButton = new System.Windows.Forms.Button();
this.filePanel = new System.Windows.Forms.Panel(); this.filePanel = new System.Windows.Forms.Panel();
this.spriteListPanel = new System.Windows.Forms.Panel(); this.spriteListPanel = new System.Windows.Forms.Panel();
this.moveDownButton = new System.Windows.Forms.Button();
this.moveUpButton = new System.Windows.Forms.Button();
this.spritesLabel = new System.Windows.Forms.Label(); this.spritesLabel = new System.Windows.Forms.Label();
this.spritePanel = new System.Windows.Forms.Panel(); this.spritePanel = new System.Windows.Forms.Panel();
this.originYPosBox = new System.Windows.Forms.NumericUpDown(); this.originYPosBox = new System.Windows.Forms.NumericUpDown();
@@ -54,17 +56,15 @@
this.label2 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label();
this.spriteSettingsLabel = new System.Windows.Forms.Label(); this.spriteSettingsLabel = new System.Windows.Forms.Label();
this.spriteNameBox = new System.Windows.Forms.TextBox(); this.spriteNameBox = new System.Windows.Forms.TextBox();
this.loadSpriteSheetDialogue = new System.Windows.Forms.OpenFileDialog(); this.loadSpriteSheetDialog = new System.Windows.Forms.OpenFileDialog();
this.loadMapDialogue = new System.Windows.Forms.OpenFileDialog(); this.loadMapDialog = new System.Windows.Forms.OpenFileDialog();
this.saveMapDialogue = new System.Windows.Forms.SaveFileDialog(); this.saveMapDialog = new System.Windows.Forms.SaveFileDialog();
this.fillButton = new System.Windows.Forms.Button(); this.fillButton = new System.Windows.Forms.Button();
this.spriteViewerPanel = new System.Windows.Forms.Panel(); this.spriteViewerPanel = new System.Windows.Forms.Panel();
this.spriteSheetViewer = new SpriteMapEditor.PictureBoxWithInterpolationMode(); this.spriteSheetViewer = new SpriteMapEditor.PictureBoxWithInterpolationMode();
this.zoomInButton = new System.Windows.Forms.Button(); this.zoomInButton = new System.Windows.Forms.Button();
this.zoomOutButton = new System.Windows.Forms.Button(); this.zoomOutButton = new System.Windows.Forms.Button();
this.zoomLabel = new System.Windows.Forms.Label(); this.zoomLabel = new System.Windows.Forms.Label();
this.moveDownButton = new System.Windows.Forms.Button();
this.moveUpButton = new System.Windows.Forms.Button();
this.filePanel.SuspendLayout(); this.filePanel.SuspendLayout();
this.spriteListPanel.SuspendLayout(); this.spriteListPanel.SuspendLayout();
this.spritePanel.SuspendLayout(); this.spritePanel.SuspendLayout();
@@ -165,6 +165,26 @@
this.spriteListPanel.Size = new System.Drawing.Size(190, 254); this.spriteListPanel.Size = new System.Drawing.Size(190, 254);
this.spriteListPanel.TabIndex = 8; this.spriteListPanel.TabIndex = 8;
// //
// moveDownButton
//
this.moveDownButton.Location = new System.Drawing.Point(39, 233);
this.moveDownButton.Name = "moveDownButton";
this.moveDownButton.Size = new System.Drawing.Size(70, 18);
this.moveDownButton.TabIndex = 5;
this.moveDownButton.Text = "▼";
this.moveDownButton.UseVisualStyleBackColor = true;
this.moveDownButton.Click += new System.EventHandler(this.moveDownButton_Click);
//
// moveUpButton
//
this.moveUpButton.Location = new System.Drawing.Point(115, 233);
this.moveUpButton.Name = "moveUpButton";
this.moveUpButton.Size = new System.Drawing.Size(71, 18);
this.moveUpButton.TabIndex = 6;
this.moveUpButton.Text = "▲";
this.moveUpButton.UseVisualStyleBackColor = true;
this.moveUpButton.Click += new System.EventHandler(this.moveUpButton_Click);
//
// spritesLabel // spritesLabel
// //
this.spritesLabel.AutoSize = true; this.spritesLabel.AutoSize = true;
@@ -361,20 +381,20 @@
this.spriteNameBox.TabIndex = 0; this.spriteNameBox.TabIndex = 0;
this.spriteNameBox.TextChanged += new System.EventHandler(this.spriteNameBox_TextChanged); this.spriteNameBox.TextChanged += new System.EventHandler(this.spriteNameBox_TextChanged);
// //
// loadSpriteSheetDialogue // loadSpriteSheetDialog
// //
this.loadSpriteSheetDialogue.FileName = "openFileDialog1"; this.loadSpriteSheetDialog.FileName = "openFileDialog1";
this.loadSpriteSheetDialogue.Filter = "PNG files|*.png"; this.loadSpriteSheetDialog.Filter = "PNG files|*.png";
// //
// loadMapDialogue // loadMapDialog
// //
this.loadMapDialogue.FileName = "openFileDialog1"; this.loadMapDialog.FileName = "openFileDialog1";
this.loadMapDialogue.Filter = "Xml files|*.xml"; this.loadMapDialog.Filter = "Xml files|*.xml";
// //
// saveMapDialogue // saveMapDialog
// //
this.saveMapDialogue.DefaultExt = "xml"; this.saveMapDialog.DefaultExt = "xml";
this.saveMapDialogue.Filter = "Xml files|*.xml"; this.saveMapDialog.Filter = "Xml files|*.xml";
// //
// fillButton // fillButton
// //
@@ -444,26 +464,6 @@
this.zoomLabel.TabIndex = 15; this.zoomLabel.TabIndex = 15;
this.zoomLabel.Text = "Zoom: 3X"; this.zoomLabel.Text = "Zoom: 3X";
// //
// moveDownButton
//
this.moveDownButton.Location = new System.Drawing.Point(39, 233);
this.moveDownButton.Name = "moveDownButton";
this.moveDownButton.Size = new System.Drawing.Size(70, 18);
this.moveDownButton.TabIndex = 5;
this.moveDownButton.Text = "▼";
this.moveDownButton.UseVisualStyleBackColor = true;
this.moveDownButton.Click += new System.EventHandler(this.moveDownButton_Click);
//
// moveUpButton
//
this.moveUpButton.Location = new System.Drawing.Point(115, 233);
this.moveUpButton.Name = "moveUpButton";
this.moveUpButton.Size = new System.Drawing.Size(71, 18);
this.moveUpButton.TabIndex = 6;
this.moveUpButton.Text = "▲";
this.moveUpButton.UseVisualStyleBackColor = true;
this.moveUpButton.Click += new System.EventHandler(this.moveUpButton_Click);
//
// Form1 // Form1
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -517,9 +517,9 @@
private System.Windows.Forms.Label heightLabel; private System.Windows.Forms.Label heightLabel;
private System.Windows.Forms.Label widthLabel; private System.Windows.Forms.Label widthLabel;
private System.Windows.Forms.Label yPosLabel; private System.Windows.Forms.Label yPosLabel;
private System.Windows.Forms.OpenFileDialog loadSpriteSheetDialogue; private System.Windows.Forms.OpenFileDialog loadSpriteSheetDialog;
private System.Windows.Forms.OpenFileDialog loadMapDialogue; private System.Windows.Forms.OpenFileDialog loadMapDialog;
private System.Windows.Forms.SaveFileDialog saveMapDialogue; private System.Windows.Forms.SaveFileDialog saveMapDialog;
private System.Windows.Forms.Button fillButton; private System.Windows.Forms.Button fillButton;
private PictureBoxWithInterpolationMode spriteSheetViewer; private PictureBoxWithInterpolationMode spriteSheetViewer;
private System.Windows.Forms.Panel spriteViewerPanel; private System.Windows.Forms.Panel spriteViewerPanel;
+9 -8
View File
@@ -64,9 +64,9 @@ namespace SpriteMapEditor
private void loadSpriteSheetButton_Click(object sender, EventArgs e) private void loadSpriteSheetButton_Click(object sender, EventArgs e)
{ {
if(loadSpriteSheetDialogue.ShowDialog() == System.Windows.Forms.DialogResult.OK) if(loadSpriteSheetDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{ {
spriteSheetViewer.Image = Image.FromFile(loadSpriteSheetDialogue.FileName); spriteSheetViewer.Image = Image.FromFile(loadSpriteSheetDialog.FileName);
} }
} }
@@ -281,8 +281,6 @@ namespace SpriteMapEditor
} }
private void saveMapButton_Click(object sender, EventArgs e) private void saveMapButton_Click(object sender, EventArgs e)
{
if (saveMapDialogue.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{ {
var exportDict = new Dictionary<string, SpriteMapRegion>(); var exportDict = new Dictionary<string, SpriteMapRegion>();
foreach (SpriteMapRegion sprite in sprites) foreach (SpriteMapRegion sprite in sprites)
@@ -294,11 +292,14 @@ namespace SpriteMapEditor
MessageBoxButtons saveError = MessageBoxButtons.OK; MessageBoxButtons saveError = MessageBoxButtons.OK;
MessageBox.Show(errorMessage, caption, saveError); MessageBox.Show(errorMessage, caption, saveError);
return;
} }
else
exportDict.Add(sprite.Name, sprite); exportDict.Add(sprite.Name, sprite);
} }
using (XmlWriter writer = XmlWriter.Create(saveMapDialogue.FileName))
if (saveMapDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
using (XmlWriter writer = XmlWriter.Create(saveMapDialog.FileName))
{ {
IntermediateSerializer.Serialize(writer, exportDict, null); IntermediateSerializer.Serialize(writer, exportDict, null);
} }
@@ -307,10 +308,10 @@ namespace SpriteMapEditor
private void loadMapButton_Click(object sender, EventArgs e) private void loadMapButton_Click(object sender, EventArgs e)
{ {
if(loadMapDialogue.ShowDialog() == System.Windows.Forms.DialogResult.OK) if(loadMapDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{ {
Dictionary<string, SpriteMapRegion> loadedSpriteMap; Dictionary<string, SpriteMapRegion> loadedSpriteMap;
using (XmlReader xmlRead = XmlReader.Create(loadMapDialogue.FileName)) using (XmlReader xmlRead = XmlReader.Create(loadMapDialog.FileName))
{ {
loadedSpriteMap = IntermediateSerializer.Deserialize<Dictionary<string, SpriteMapRegion>>(xmlRead, null); loadedSpriteMap = IntermediateSerializer.Deserialize<Dictionary<string, SpriteMapRegion>>(xmlRead, null);
} }
+6 -6
View File
@@ -117,14 +117,14 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<metadata name="loadSpriteSheetDialogue.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="loadSpriteSheetDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>152, 17</value>
</metadata>
<metadata name="loadMapDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value> <value>17, 17</value>
</metadata> </metadata>
<metadata name="loadMapDialogue.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="saveMapDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>204, 17</value> <value>325, 17</value>
</metadata>
<metadata name="saveMapDialogue.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>353, 17</value>
</metadata> </metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="spriteSheetViewer.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="spriteSheetViewer.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">