using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using Pegasus.Log4Net;
namespace Pegasus.Runtime.Serialization.Formatters.Xml
{
/// <summary>
/// Provides serialization to and from XML format.
/// </summary>
[Obsolete( "Use the XmlFormatter2 class in place of this class", false )]
public class XmlFormatter : IFormatter
{
/// <summary>
///
/// </summary>
public static ILog s_logger = LogManager.GetLogger( typeof( XmlFormatter ) );
/// <summary>
/// Initializes a new instance of the <see cref="T:XmlFormatter"/> class.
/// </summary>
public XmlFormatter()
{
}
/// <summary>
/// Gets or sets the <see cref="T:System.Runtime.Serialization.SerializationBinder"></see> that performs type lookups during deserialization.
/// </summary>
/// <value></value>
/// <returns>The <see cref="T:System.Runtime.Serialization.SerializationBinder"></see> that performs type lookups during deserialization.</returns>
public SerializationBinder Binder
{
get
{
throw new Exception( "The method or operation is not implemented." );
}
set
{
throw new Exception( "The method or operation is not implemented." );
}
}
/// <summary>
/// Gets or sets the <see cref="T:System.Runtime.Serialization.StreamingContext"></see> used for serialization and deserialization.
/// </summary>
/// <value></value>
/// <returns>The <see cref="T:System.Runtime.Serialization.StreamingContext"></see> used for serialization and deserialization.</returns>
public StreamingContext Context
{
get
{
throw new Exception( "The method or operation is not implemented." );
}
set
{
throw new Exception( "The method or operation is not implemented." );
}
}
/// <summary>
/// Gets or sets the <see cref="T:System.Runtime.Serialization.SurrogateSelector"></see> used by the current formatter.
/// </summary>
/// <value></value>
/// <returns>The <see cref="T:System.Runtime.Serialization.SurrogateSelector"></see> used by this formatter.</returns>
public ISurrogateSelector SurrogateSelector
{
get
{
throw new Exception( "The method or operation is not implemented." );
}
set
{
throw new Exception( "The method or operation is not implemented." );
}
}
/// <summary>
/// Serializes an object, or graph of objects with the given root to the provided stream.
/// </summary>
/// <param name="serializationStream">The stream where the formatter puts the serialized data. This stream can reference a variety of backing stores (such as files, network, memory, and so on).</param>
/// <param name="graph">The object, or root of the object graph, to serialize. All child objects of this root object are automatically serialized.</param>
public void Serialize( Stream serializationStream, object graph )
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.ConformanceLevel = ConformanceLevel.Document;
settings.Encoding = UTF8Encoding.UTF8;
settings.Indent = true;
settings.OmitXmlDeclaration = true;
XmlWriter xmlWriter = XmlWriter.Create( serializationStream, settings );
try
{
// Build the security token
xmlWriter.WriteStartDocument();
WriteMember( xmlWriter, "ObjectGraph", graph );
xmlWriter.WriteEndDocument();
xmlWriter.Flush();
}
catch( Exception ex )
{
s_logger.Error( "Serialize failed", ex );
throw;
}
finally
{
xmlWriter.Close();
}
}
/// <summary>
/// Deserializes the data on the provided stream and reconstitutes the graph of objects.
/// </summary>
/// <param name="serializationStream">The stream that contains the data to deserialize.</param>
/// <returns>
/// The top object of the deserialized graph.
/// </returns>
public object Deserialize( Stream serializationStream )
{
// TODO: Use a forward reader, it should be faster...
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load( serializationStream );
foreach( XmlNode node in xmlDoc.ChildNodes )
{
if( node.Name == "ObjectGraph" )
{
return ReadMember( node );
}
}
return null;
}
/// <summary>
/// Writes the member.
/// </summary>
/// <param name="xmlWriter">The XML writer.</param>
/// <param name="memberName">Name of the member.</param>
/// <param name="data">The data.</param>
private void WriteMember( XmlWriter xmlWriter, string memberName, object data )
{
if( data == null )
{
WriteObjectRef( xmlWriter, data, memberName, typeof( object ) );
}
else
{
Type type = data.GetType();
if( type == typeof( bool ) ||
type == typeof( char ) ||
type == typeof( sbyte ) ||
type == typeof( byte ) ||
type == typeof( short ) ||
type == typeof( ushort ) ||
type == typeof( int ) ||
type == typeof( uint ) ||
type == typeof( long ) ||
type == typeof( ulong ) ||
type == typeof( float ) ||
type == typeof( double ) ||
type == typeof( decimal ) )
{
WriteBasicType( xmlWriter, data, memberName );
}
else if( type == typeof( DateTime ) )
{
WriteBasicType( xmlWriter, Convert.ToDateTime( data, CultureInfo.InvariantCulture ), memberName );
}
else if( type.IsArray )
{
this.WriteArray( xmlWriter, data, memberName, type );
}
else if( type.IsValueType )
{
this.WriteValueType( xmlWriter, data, memberName, type );
}
else
{
this.WriteObjectRef( xmlWriter, data, memberName, type );
}
}
}
/// <summary>
/// Writes the type of the basic.
/// </summary>
/// <param name="xmlWriter">The XML writer.</param>
/// <param name="val">The val.</param>
/// <param name="name">The name.</param>
private void WriteBasicType( XmlWriter xmlWriter, object val, string name )
{
xmlWriter.WriteStartElement( XmlConvert.EncodeName( name ) );
xmlWriter.WriteAttributeString( "Type", val.GetType().AssemblyQualifiedName );
xmlWriter.WriteValue( val.ToString() );
xmlWriter.WriteEndElement();
}
/// <summary>
/// Writes the array.
/// </summary>
/// <param name="xmlWriter">The XML writer.</param>
/// <param name="obj">The obj.</param>
/// <param name="name">The name.</param>
/// <param name="memberType">Type of the member.</param>
private void WriteArray( XmlWriter xmlWriter, object obj, string name, Type memberType )
{
xmlWriter.WriteStartElement( XmlConvert.EncodeName( name ) );
xmlWriter.WriteAttributeString( "Type", memberType.AssemblyQualifiedName );
// Write the elements of the array
Array array = (Array) obj;
foreach( object element in array )
{
WriteMember( xmlWriter, name, element );
}
xmlWriter.WriteEndElement();
}
/// <summary>
/// Writes the type of the value.
/// </summary>
/// <param name="xmlWriter">The XML writer.</param>
/// <param name="obj">The obj.</param>
/// <param name="name">The name.</param>
/// <param name="memberType">Type of the member.</param>
private void WriteValueType( XmlWriter xmlWriter, object obj, string name, Type memberType )
{
xmlWriter.WriteStartElement( XmlConvert.EncodeName( name ) );
xmlWriter.WriteAttributeString( "Type", memberType.AssemblyQualifiedName );
FieldInfo[] fields = memberType.GetFields( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
object[] membersData = FormatterServices.GetObjectData( obj, fields );
int count = fields.Length;
for( int x = 0; x < count; x++ )
{
WriteMember( xmlWriter, fields[ x ].Name, membersData[ x ] );
}
xmlWriter.WriteEndElement();
}
/// <summary>
/// Writes the object ref.
/// </summary>
/// <param name="xmlWriter">The XML writer.</param>
/// <param name="obj">The obj.</param>
/// <param name="name">The name.</param>
/// <param name="memberType">Type of the member.</param>
private void WriteObjectRef( XmlWriter xmlWriter, object obj, string name, Type memberType )
{
xmlWriter.WriteStartElement( XmlConvert.EncodeName( name ) );
xmlWriter.WriteAttributeString( "Type", memberType.AssemblyQualifiedName );
if( obj != null )
{
if( memberType != typeof( string ) )
{
MemberInfo[] members = FormatterServices.GetSerializableMembers( memberType );
object[] membersData = FormatterServices.GetObjectData( obj, members );
int count = members.Length;
for( int x = 0; x < count; x++ )
{
WriteMember( xmlWriter, members[ x ].Name, membersData[ x ] );
}
}
else
{
xmlWriter.WriteValue( (string) obj );
}
}
else
{
xmlWriter.WriteValue( "NULL" );
}
xmlWriter.WriteEndElement();
}
/// <summary>
/// Reads the member.
/// </summary>
/// <param name="node">The node.</param>
/// <returns></returns>
private object ReadMember( XmlNode node )
{
object ret = null;
XmlAttribute attrib = node.Attributes[ "Type" ];
if( attrib == null )
{
throw new XmlException( string.Format( "Missing 'Type' attribute on node {0}", node.Name ) );
}
string qualifiedAssemblyName = attrib.Value;
Type memberType = Type.GetType( qualifiedAssemblyName );
if( memberType == null )
{
throw new XmlException( string.Format( "Unknown 'Type' attribute {0} on node {1}", qualifiedAssemblyName, node.Name ) );
}
if( memberType == typeof( bool ) )
{
ret = Convert.ToBoolean( node.InnerText );
}
else if( memberType == typeof( char ) )
{
ret = Convert.ToChar( node.InnerText );
}
else if( memberType == typeof( string ) )
{
ret = node.InnerText;
}
else if( memberType == typeof( sbyte ) )
{
ret = Convert.ToSByte( node.InnerText );
}
else if( memberType == typeof( byte ) )
{
ret = Convert.ToByte( node.InnerText );
}
else if( memberType == typeof( short ) )
{
ret = Convert.ToInt16( node.InnerText );
}
else if( memberType == typeof( ushort ) )
{
ret = Convert.ToUInt16( node.InnerText );
}
else if( memberType == typeof( int ) )
{
ret = Convert.ToInt32( node.InnerText );
}
else if( memberType == typeof( uint ) )
{
ret = Convert.ToUInt32( node.InnerText );
}
else if( memberType == typeof( long ) )
{
ret = Convert.ToInt64( node.InnerText );
}
else if( memberType == typeof( ulong ) )
{
ret = Convert.ToUInt64( node.InnerText );
}
else if( memberType == typeof( float ) )
{
ret = Convert.ToSingle( node.InnerText );
}
else if( memberType == typeof( double ) )
{
ret = Convert.ToDouble( node.InnerText );
}
else if( memberType == typeof( decimal ) )
{
ret = Convert.ToDecimal( node.InnerText );
}
else if( memberType == typeof( DateTime ) )
{
ret = Convert.ToDateTime( node.InnerText, CultureInfo.InvariantCulture );
}
else if( memberType.IsArray )
{
ReadArray( node, ref ret, memberType );
}
else if( memberType.IsValueType )
{
ReadValueType( node, ref ret, memberType );
}
else
{
ReadObjectRef( node, ref ret, memberType );
}
return ret;
}
/// <summary>
/// Reads the array.
/// </summary>
/// <param name="node">The node.</param>
/// <param name="theObject">The object.</param>
/// <param name="memberType">Type of the member.</param>
private void ReadArray( XmlNode node, ref object theObject, Type memberType )
{
int count = node.ChildNodes.Count;
// Create the array object
Array array = Array.CreateInstance( memberType.GetElementType(), count );
// Read each the element of the array
for( int x = 0; x < count; x++ )
{
array.SetValue( ReadMember( node.ChildNodes[ x ] ), x );
}
theObject = array;
}
/// <summary>
/// Reads the type of the value.
/// </summary>
/// <param name="node">The node.</param>
/// <param name="theObject">The object.</param>
/// <param name="memberType">Type of the member.</param>
private void ReadValueType( XmlNode node, ref object theObject, Type memberType )
{
theObject = FormatterServices.GetSafeUninitializedObject( memberType );
FieldInfo[] fields = memberType.GetFields( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
int count = fields.Length;
object[] data = new object[ count ];
for( int x = 0; x < count; x++ )
{
string name = fields[ x ].Name;
XmlNode childNode = node.SelectSingleNode( XmlConvert.EncodeName( name ) );
if( childNode != null )
{
data[ x ] = ReadMember( childNode );
}
}
theObject = FormatterServices.PopulateObjectMembers( theObject, fields, data );
}
/// <summary>
/// Reads the object ref.
/// </summary>
/// <param name="node">The node.</param>
/// <param name="theObject">The object.</param>
/// <param name="memberType">Type of the member.</param>
private void ReadObjectRef( XmlNode node, ref object theObject, Type memberType )
{
if( node.InnerText != "NULL" )
{
if( memberType == typeof( string ) )
{
theObject = node.InnerText;
}
else
{
theObject = FormatterServices.GetSafeUninitializedObject( memberType );
MemberInfo[] members = FormatterServices.GetSerializableMembers( memberType );
int count = members.Length;
object[] data = new object[ count ];
for( int x = 0; x < count; x++ )
{
string name = members[ x ].Name;
XmlNode childNode = node.SelectSingleNode( XmlConvert.EncodeName( name ) );
if( childNode != null )
{
data[ x ] = ReadMember( childNode );
}
}
theObject = FormatterServices.PopulateObjectMembers( theObject, members, data );
}
}
else
{
theObject = null;
}
}
}
}