From 9fe9d4bf89dd83ef3b8312f89ec43202760f8c7b Mon Sep 17 00:00:00 2001 From: Glatzemann Date: Mon, 29 Oct 2012 12:15:18 +0000 Subject: [PATCH] Added (basic) generic writer support to content pipeline. SpriteFont importing and compiling now looks fine. --- .../ANX.Framework.Content.Pipeline.csproj | 4 + .../Properties/AssemblyInfo.cs | 4 +- .../Serialization/Compiler/ArrayWriter.cs | 81 ++++++++++++ .../Serialization/Compiler/ContentCompiler.cs | 124 ++++++++++++------ .../Compiler/ContentTypeWriter.cs | 4 - .../Serialization/Compiler/EnumWriter.cs | 44 +++++++ .../Serialization/Compiler/ListWriter.cs | 47 +++++++ .../Compiler/SystemTypeWriters/CharWriter.cs | 17 +++ 8 files changed, 280 insertions(+), 45 deletions(-) create mode 100644 ANX.Framework.Content.Pipeline/Serialization/Compiler/ArrayWriter.cs create mode 100644 ANX.Framework.Content.Pipeline/Serialization/Compiler/EnumWriter.cs create mode 100644 ANX.Framework.Content.Pipeline/Serialization/Compiler/ListWriter.cs create mode 100644 ANX.Framework.Content.Pipeline/Serialization/Compiler/SystemTypeWriters/CharWriter.cs diff --git a/ANX.Framework.Content.Pipeline/ANX.Framework.Content.Pipeline.csproj b/ANX.Framework.Content.Pipeline/ANX.Framework.Content.Pipeline.csproj index 92ad209e..d5b1d667 100644 --- a/ANX.Framework.Content.Pipeline/ANX.Framework.Content.Pipeline.csproj +++ b/ANX.Framework.Content.Pipeline/ANX.Framework.Content.Pipeline.csproj @@ -143,17 +143,20 @@ + + + @@ -178,6 +181,7 @@ + diff --git a/ANX.Framework.Content.Pipeline/Properties/AssemblyInfo.cs b/ANX.Framework.Content.Pipeline/Properties/AssemblyInfo.cs index 44bc2d42..66855dd4 100644 --- a/ANX.Framework.Content.Pipeline/Properties/AssemblyInfo.cs +++ b/ANX.Framework.Content.Pipeline/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern // übernehmen, indem Sie "*" eingeben: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.1")] -[assembly: AssemblyFileVersion("1.0.0.1")] +[assembly: AssemblyVersion("1.0.1.*")] +[assembly: AssemblyFileVersion("1.0.1.0")] diff --git a/ANX.Framework.Content.Pipeline/Serialization/Compiler/ArrayWriter.cs b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ArrayWriter.cs new file mode 100644 index 00000000..249a3921 --- /dev/null +++ b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ArrayWriter.cs @@ -0,0 +1,81 @@ +#region Using Statements +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +#endregion + +// This file is part of the ANX.Framework created by the +// "ANX.Framework developer group" and released under the Ms-PL license. +// For details see: http://anxframework.codeplex.com/license + +namespace ANX.Framework.Content.Pipeline.Serialization.Compiler +{ + internal class ArrayWriter : ContentTypeWriter + { + private ContentTypeWriter elementWriter; + + protected override void Initialize(ContentCompiler compiler) + { + this.elementWriter = compiler.GetTypeWriter(typeof(T)); + } + + protected internal override void Write(ContentWriter output, T[] value) + { + output.Write(value.Length); + for (int i = 0; i < value.Length; i++) + { + T value2 = value[i]; + output.WriteObject(value2, this.elementWriter); + } + } + + public override string GetRuntimeReader(TargetPlatform targetPlatform) + { + return string.Concat(new object[] + { + typeof(ContentTypeReader).Namespace, + '.', + "ArrayReader`1[[", + this.elementWriter.GetRuntimeType(targetPlatform), + "]]" + }); + } + + public override string GetRuntimeType(TargetPlatform targetPlatform) + { + string runtimeType = this.elementWriter.GetRuntimeType(targetPlatform); + int num = 0; + for (int i = 0; i < runtimeType.Length; i++) + { + char c = runtimeType[i]; + if (c != ',') + { + switch (c) + { + case '[': + num++; + break; + case ']': + num--; + break; + } + } + else + { + if (num == 0) + { + return runtimeType.Insert(i, "[]"); + } + } + } + return runtimeType + "[]"; + } + + protected internal override bool ShouldCompressContent(TargetPlatform targetPlatform, object value) + { + return this.elementWriter.ShouldCompressContent(targetPlatform, null); + } + } +} diff --git a/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentCompiler.cs b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentCompiler.cs index 80fa77e9..684a101a 100644 --- a/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentCompiler.cs +++ b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentCompiler.cs @@ -15,30 +15,73 @@ namespace ANX.Framework.Content.Pipeline.Serialization.Compiler { public sealed class ContentCompiler { + #region Private Members private Dictionary writerInstances = new Dictionary(); + private Dictionary genericHandlers = new Dictionary(); + + #endregion public ContentCompiler() { foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { - foreach (Type type in assembly.GetTypes()) + AddContentWriterAssembly(assembly); + } + } + + public ContentTypeWriter GetTypeWriter(Type type) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + ContentTypeWriter contentTypeWriter; + if (!this.writerInstances.TryGetValue(type, out contentTypeWriter)) + { + if (type.IsGenericType) { - ContentTypeWriterAttribute[] value = (ContentTypeWriterAttribute[])type.GetCustomAttributes(typeof(ContentTypeWriterAttribute), true); - if (value.Length > 0) + Type genericTypeDefinition = type.GetGenericTypeDefinition(); + Type handler; + if (this.genericHandlers.TryGetValue(genericTypeDefinition, out handler)) { - if (!type.ContainsGenericParameters) - { - ContentTypeWriter writer = (ContentTypeWriter)Activator.CreateInstance(type); - writerInstances[writer.TargetType] = writer; - } - else - { - //TODO: implement generic writer instances... - System.Diagnostics.Debugger.Break(); - } + Type genericType = handler.MakeGenericType(type.GetGenericArguments()); + contentTypeWriter = ((object)Activator.CreateInstance(genericType)) as ContentTypeWriter; } } + else + { + contentTypeWriter = default(ContentTypeWriter); + } + + if (contentTypeWriter == null) + { + if (type.IsArray) + { + if (type.GetArrayRank() != 1) + { + throw new RankException("can't serialize multidimensional arrays"); + } + + contentTypeWriter = Activator.CreateInstance(typeof(ArrayWriter<>).MakeGenericType(new Type[] { type.GetElementType() })) as ContentTypeWriter; + } + + if (type.IsEnum) + { + contentTypeWriter = Activator.CreateInstance(typeof(EnumWriter<>).MakeGenericType(new Type[] { type.GetElementType() })) as ContentTypeWriter; + } + + //TODO: return new ReflectiveWriter(type); + } + + if (contentTypeWriter != null) + { + this.writerInstances.Add(type, contentTypeWriter); + contentTypeWriter.DoInitialize(this); + } } + + return contentTypeWriter; } internal void Compile(Stream output, object value, TargetPlatform targetPlatform, GraphicsProfile targetProfile, bool compressContent, string rootDirectory, string referenceRelocationPath) @@ -84,31 +127,6 @@ namespace ANX.Framework.Content.Pipeline.Serialization.Compiler } } - public ContentTypeWriter GetTypeWriter(Type type) - { - if (type == null) - { - throw new ArgumentNullException("type"); - } - - ContentTypeWriter typeWriterInternal = this.GetTypeWriterInternal(type); - //TODO: this.RecordDependency(typeWriterInternal.TargetType); - return typeWriterInternal; - } - - private ContentTypeWriter GetTypeWriterInternal(Type type) - { - ContentTypeWriter contentTypeWriter; - if (!this.writerInstances.TryGetValue(type, out contentTypeWriter)) - { - //contentTypeWriter = this.typeWriterFactory.CreateWriter(type); - //this.AddTypeWriter(contentTypeWriter); - //this.InitializeTypeWriter(contentTypeWriter); - } - - return contentTypeWriter; - } - private bool ShouldCompressContent(TargetPlatform targetPlatform, object value) { if (targetPlatform == TargetPlatform.WindowsPhone) @@ -116,9 +134,37 @@ namespace ANX.Framework.Content.Pipeline.Serialization.Compiler return false; } - ContentTypeWriter typeWriterInternal = this.GetTypeWriterInternal(value.GetType()); + ContentTypeWriter typeWriterInternal = this.GetTypeWriter(value.GetType()); return typeWriterInternal.ShouldCompressContent(targetPlatform, value); } + + public void AddContentWriterAssembly(Assembly assembly) + { + foreach (Type type in assembly.GetTypes()) + { + ContentTypeWriterAttribute[] value = (ContentTypeWriterAttribute[])type.GetCustomAttributes(typeof(ContentTypeWriterAttribute), true); + if (value.Length > 0) + { + if (!type.ContainsGenericParameters) + { + ContentTypeWriter writer = (ContentTypeWriter)Activator.CreateInstance(type); + writerInstances[writer.TargetType] = writer; + } + else + { + Type baseType = type.BaseType; + while (!baseType.IsGenericType || baseType.GetGenericTypeDefinition() != typeof(ContentTypeWriter<>)) + { + baseType = baseType.BaseType; + } + + Type genericType = baseType.GetGenericArguments()[0]; + Type genericTypeDefinition = genericType.GetGenericTypeDefinition(); + genericHandlers.Add(genericTypeDefinition, type); + } + } + } + } } } diff --git a/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentTypeWriter.cs b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentTypeWriter.cs index 0cdf8a98..bd883c6f 100644 --- a/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentTypeWriter.cs +++ b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentTypeWriter.cs @@ -156,10 +156,6 @@ namespace ANX.Framework.Content.Pipeline.Serialization.Compiler internal string GetGenericArgumentRuntimeTypes(TargetPlatform targetPlatform) { - //TODO: implement - //System.Diagnostics.Debugger.Break(); - //return ""; - if (_genericArgumentWriters == null) { return string.Empty; diff --git a/ANX.Framework.Content.Pipeline/Serialization/Compiler/EnumWriter.cs b/ANX.Framework.Content.Pipeline/Serialization/Compiler/EnumWriter.cs new file mode 100644 index 00000000..a75ff7cb --- /dev/null +++ b/ANX.Framework.Content.Pipeline/Serialization/Compiler/EnumWriter.cs @@ -0,0 +1,44 @@ +#region Using Statements +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Globalization; + +#endregion + +// This file is part of the ANX.Framework created by the +// "ANX.Framework developer group" and released under the Ms-PL license. +// For details see: http://anxframework.codeplex.com/license + +namespace ANX.Framework.Content.Pipeline.Serialization.Compiler +{ + internal class EnumWriter : ContentTypeWriter where T : struct, IConvertible + { + private Type underlyingType = Enum.GetUnderlyingType(typeof(T)); + private ContentTypeWriter underlyingTypeWriter; + + protected override void Initialize(ContentCompiler compiler) + { + this.underlyingTypeWriter = compiler.GetTypeWriter(this.underlyingType); + } + + protected internal override void Write(ContentWriter output, T value) + { + object value2 = value.ToType(this.underlyingType, CultureInfo.InvariantCulture); + output.WriteRawObject(value2, this.underlyingTypeWriter); + } + + public override string GetRuntimeReader(TargetPlatform targetPlatform) + { + return string.Concat(new object[] + { + typeof(ContentTypeReader).Namespace, + '.', + "EnumReader`1[[", + this.GetRuntimeType(targetPlatform), + "]]" + }); + } + } +} diff --git a/ANX.Framework.Content.Pipeline/Serialization/Compiler/ListWriter.cs b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ListWriter.cs new file mode 100644 index 00000000..0b89ca8b --- /dev/null +++ b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ListWriter.cs @@ -0,0 +1,47 @@ +#region Using Statements +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +#endregion + +// This file is part of the ANX.Framework created by the +// "ANX.Framework developer group" and released under the Ms-PL license. +// For details see: http://anxframework.codeplex.com/license + +namespace ANX.Framework.Content.Pipeline.Serialization.Compiler +{ + [ContentTypeWriter] + internal class ListWriter : BuiltinTypeWriter> + { + private ContentTypeWriter elementWriter; + + public override bool CanDeserializeIntoExistingObject + { + get + { + return true; + } + } + + protected override void Initialize(ContentCompiler compiler) + { + this.elementWriter = compiler.GetTypeWriter(typeof(T)); + } + + protected internal override void Write(ContentWriter output, List value) + { + output.Write(value.Count); + foreach (T current in value) + { + output.WriteObject(current, this.elementWriter); + } + } + + protected internal override bool ShouldCompressContent(TargetPlatform targetPlatform, object value) + { + return this.elementWriter.ShouldCompressContent(targetPlatform, null); + } + } +} diff --git a/ANX.Framework.Content.Pipeline/Serialization/Compiler/SystemTypeWriters/CharWriter.cs b/ANX.Framework.Content.Pipeline/Serialization/Compiler/SystemTypeWriters/CharWriter.cs new file mode 100644 index 00000000..0fb86ab4 --- /dev/null +++ b/ANX.Framework.Content.Pipeline/Serialization/Compiler/SystemTypeWriters/CharWriter.cs @@ -0,0 +1,17 @@ +using System; + +// This file is part of the ANX.Framework created by the +// "ANX.Framework developer group" and released under the Ms-PL license. +// For details see: http://anxframework.codeplex.com/license + +namespace ANX.Framework.Content.Pipeline.Serialization.Compiler.SystemTypeWriters +{ + [ContentTypeWriter] + internal class ByteWriter : BuiltinTypeWriter + { + protected internal override void Write(ContentWriter output, char value) + { + output.Write(value); + } + } +}