2012-09-28 20:57:30 +00:00
using System ;
using System.Collections.Generic ;
2012-10-02 20:05:12 +00:00
using System.Diagnostics ;
2012-09-28 20:57:30 +00:00
using System.IO ;
2012-10-02 20:05:12 +00:00
using System.Linq ;
2012-09-29 16:17:59 +00:00
using System.Reflection ;
2012-09-28 20:57:30 +00:00
using System.Xml ;
2012-10-02 21:28:13 +00:00
using System.Xml.Linq ;
2012-09-28 20:57:30 +00:00
using ANX.Framework.Content.Pipeline.Serialization ;
using ANX.Framework.NonXNA.Development ;
2012-09-29 16:17:59 +00:00
using ANX.Framework.NonXNA.Reflection ;
2012-09-28 20:57:30 +00:00
namespace ANX.Framework.Content.Pipeline.Importer
{
2012-09-29 16:17:59 +00:00
[ContentImporter(new string[] { ".xml" } ) ]
2012-09-28 20:57:30 +00:00
[Developer("SilentWarrior / Eagle Eye Studios")]
2012-10-02 21:28:13 +00:00
[PercentageComplete(50)]
2012-09-28 20:57:30 +00:00
public class XmlImporter : ContentImporter < object >
{
2012-10-02 21:28:13 +00:00
private XDocument _doc ;
2012-09-28 20:57:30 +00:00
public override object Import ( string filename , ContentImporterContext context )
{
object result ;
context . Logger . LogMessage ( "Checking if file exists." ) ;
if ( ! File . Exists ( filename ) )
throw new InvalidContentException ( "The XML file \"" + filename + "\" could not be found." ) ;
context . Logger . LogMessage ( "Starting analysis of the XML file." ) ;
using ( XmlReader xml = XmlReader . Create ( filename ) )
{
2012-10-02 21:28:13 +00:00
_doc = XDocument . Load ( filename ) ;
2012-09-28 20:57:30 +00:00
//Check if XML contains XnaContent or AnxContent root element
context . Logger . LogMessage ( "Checking for root element." ) ;
2012-10-02 21:28:13 +00:00
var tag = _doc . Element ( "XnaContent" ) ;
if ( tag = = null )
{
tag = _doc . Element ( "AnxContent" ) ;
if ( tag = = null )
throw new InvalidContentException (
"The Xml file does not contain a valid XnaContent or AnxContent tag." ) ;
}
//Check which type is beeing described in the XML by grabbing the Asset node
var assetNode = _doc . Descendants ( "Asset" ) . ToArray ( ) [ 0 ] ;
if ( assetNode = = null )
throw new InvalidContentException ( "Xml document does not contain an asset definition." ) ;
Type type = null ;
foreach ( var attrib in assetNode . Attributes ( ) . Where ( attrib = > attrib . Name = = "Type" ) )
{
type = GetType ( attrib . Value , context . Logger ) ;
}
if ( type = = null )
throw new InvalidContentException ( "There is no assembly within the search path that contains such type." ) ;
2012-09-28 20:57:30 +00:00
//Create an instance of that type and fill it with the appropriate stuff
2012-10-02 21:28:13 +00:00
result = ReadObject ( type , context . Logger ) ;
2012-09-28 20:57:30 +00:00
}
return result ;
}
2012-10-02 21:28:13 +00:00
private Type GetType ( string typeString , ContentBuildLogger logger )
2012-09-28 20:57:30 +00:00
{
2012-10-02 21:28:13 +00:00
logger . LogMessage ( "Trying to read a type from the Xml file" ) ;
//Check every assembly in the current working dir for type
foreach (
var file in
Directory . GetFiles ( Path . GetDirectoryName ( Assembly . GetCallingAssembly ( ) . Location ) , "*.dll" ) )
2012-09-29 16:17:59 +00:00
{
2012-10-02 21:28:13 +00:00
try
2012-09-29 16:17:59 +00:00
{
2012-10-02 21:28:13 +00:00
Assembly assembly = Assembly . LoadFrom ( file ) ;
foreach ( Type type in TypeHelper . SafelyExtractTypesFrom ( assembly ) )
2012-09-29 16:17:59 +00:00
{
2012-10-02 21:28:13 +00:00
if ( type . FullName = = typeString )
2012-09-29 16:17:59 +00:00
{
2012-10-02 21:28:13 +00:00
logger . LogImportantMessage ( "Type is" + type ) ;
return type ;
2012-09-29 16:17:59 +00:00
}
}
2012-10-02 21:28:13 +00:00
}
catch ( Exception ex )
{
System . Diagnostics . Debugger . Break ( ) ; //Go and check whats wrong
2012-09-29 16:17:59 +00:00
}
}
2012-10-02 21:28:13 +00:00
return null ;
2012-09-28 20:57:30 +00:00
}
2012-10-02 21:28:13 +00:00
private object ReadObject ( Type type , ContentBuildLogger logger )
2012-09-28 20:57:30 +00:00
{
var props = new Dictionary < string , object > ( ) ;
2012-10-02 21:28:13 +00:00
var assetNode = _doc . Descendants ( "Asset" ) . ToArray ( ) [ 0 ] ; //Get first node again, can not be null cause we checked it before
var nodes = assetNode . Descendants ( ) ;
foreach ( var xElement in nodes . Where ( xElement = > xElement . Name ! = "Item" & & xElement . Name ! = "Key" & & xElement . Name ! = "Value" ) ) //Reserved keywords
2012-09-28 20:57:30 +00:00
{
2012-10-02 21:28:13 +00:00
if ( ! xElement . HasElements ) //Normal node
{
if ( xElement . HasAttributes ) //Not a string, we need to convert.
2012-09-28 20:57:30 +00:00
{
2012-10-02 21:28:13 +00:00
string key = xElement . Name . LocalName ;
object value = XmlContentToObject ( xElement . Value ) ;
props . Add ( key , value ) ;
2012-09-28 20:57:30 +00:00
}
2012-10-02 21:28:13 +00:00
else //String, just pass it.
2012-09-29 16:17:59 +00:00
{
2012-10-02 21:28:13 +00:00
string key = xElement . Name . LocalName ;
object value = xElement . Value ;
props . Add ( key , value ) ;
}
}
else //List or Dictionary
{
if ( xElement . Descendants ( ) . Contains ( new XElement ( "Item" ) ) )
{
if ( xElement . Descendants ( "Item" ) . ToArray ( ) [ 0 ] . Descendants ( ) . Contains ( new XElement ( "Key" ) ) & & xElement . Descendants ( "Item" ) . ToArray ( ) [ 0 ] . Descendants ( ) . Contains ( new XElement ( "Value" ) ) ) // is a dictionary
2012-09-29 16:17:59 +00:00
{
2012-10-02 21:28:13 +00:00
var dic = new Dictionary < string , object > ( ) ;
foreach ( var item in xElement . Descendants ( "Item" ) )
2012-09-29 16:17:59 +00:00
{
2012-10-02 21:28:13 +00:00
var key = item . Descendants ( "Key" ) . ToArray ( ) [ 0 ] . Value ;
object value = XmlContentToObject ( item . Descendants ( "Value" ) . ToArray ( ) [ 0 ] . Value ) ;
dic . Add ( key , value ) ;
2012-09-29 16:17:59 +00:00
}
2012-10-02 21:28:13 +00:00
props . Add ( xElement . Name . LocalName , dic ) ;
}
else //must be a list
{
var list = xElement . Descendants ( "Item" ) . Select ( item = > XmlContentToObject ( item . Value ) ) . ToList ( ) ;
props . Add ( xElement . Name . LocalName , list ) ;
}
2012-09-29 16:17:59 +00:00
}
2012-10-02 21:28:13 +00:00
}
2012-09-28 20:57:30 +00:00
}
2012-10-02 21:28:13 +00:00
//TODO: Get all fields of the class via reflection
2012-09-28 20:57:30 +00:00
//Activate instance
2012-10-02 20:05:12 +00:00
var constructors = type . GetConstructors ( BindingFlags . NonPublic | BindingFlags . Instance ) ;
var result = constructors [ 0 ] . Invoke ( new object [ ] { } ) ;
2012-09-28 20:57:30 +00:00
//TODO: Match every property with its value
2012-10-02 20:05:12 +00:00
var properties = type . GetFields ( BindingFlags . Instance | BindingFlags . SetField | BindingFlags . NonPublic | BindingFlags . Public ) ;
foreach ( var property in properties )
{
var attribs = property . GetCustomAttributes ( typeof ( ContentSerializerAttribute ) , true ) ;
if ( attribs . Length = = 0 )
continue ;
if ( props . ContainsKey ( ( ( ContentSerializerAttribute ) attribs [ 0 ] ) . ElementName ) )
{
property . SetValue ( result , props [ ( ( ContentSerializerAttribute ) attribs [ 0 ] ) . ElementName ] ) ;
props . Remove ( ( ( ContentSerializerAttribute ) attribs [ 0 ] ) . ElementName ) ;
}
}
if ( props . Count > 0 )
{
logger . LogWarning ( "" , null , "There are unset properties left!" , result ) ;
Debugger . Break ( ) ;
}
2012-09-28 20:57:30 +00:00
//Return the whole construct
return result ;
}
2012-09-29 16:17:59 +00:00
2012-10-02 21:28:13 +00:00
private object XmlContentToObject ( string xmlContent )
2012-09-29 16:17:59 +00:00
{
2012-10-02 21:28:13 +00:00
Debugger . Break ( ) ;
throw new NotImplementedException ( ) ;
2012-09-29 16:17:59 +00:00
}
2012-09-28 20:57:30 +00:00
}
}