using System; using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Reflection; using System.Runtime.Serialization; using System.Xml; namespace ser; // --- Primitive Handler --- public partial class PrimitiveHandler : ser.ITypeHandler { public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType ) { if( obj == null ) { writer.WriteStartElement( name ); writer.WriteAttributeString( "v", "null" ); writer.WriteEndElement(); return; } bool writeElements = xml._cfg.POD == POD.Elements || forceType || !( writer is XmlTextWriter ); if( !writeElements && writer is XmlTextWriter tw ) writeElements = tw.WriteState != WriteState.Element; if( writeElements ) writer.WriteStartElement( name ); if( forceType || xml._cfg.POD == POD.Elements ) { if( forceType ) writer.WriteAttributeString( "_.t", obj.GetType().FullName ); writer.WriteAttributeString( "v", obj.ToString() ); } else { writer.WriteAttributeString( name, obj.ToString() ); } if( writeElements ) writer.WriteEndElement(); } } // --- Proxy Handler --- public partial class ProxyHandler : ITypeHandler { public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType ) { if( obj == null ) { xml.GetHandler( typeof( object ) ).WriteXml( xml, writer, null, name, memberType, forceType ); return; } var ti = xml._meta.Get( obj.GetType() ); if( !ti.ProxyDef.HasValue ) { log.error( "Proxy write called without proxy def!" ); return; } writer.WriteStartElement( name ); var proxyStr = ti.ProxyDef.Value.fnSer( obj ); // TODO: Allow arbitrary writing here writer.WriteAttributeString( "proxy", proxyStr ); writer.WriteEndElement(); } } // --- ISerializable Handler --- public partial class ISerializableHandler : ITypeHandler { public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType ) { if( obj == null ) { /* Write null */ return; } if( !( obj is ISerializable serObj ) ) { /* Error */ return; } writer.WriteStartElement( name ); xml.WriteTypeAttr( writer, memberType, obj.GetType() ); if( xml.HandleGraphWrite( writer, obj, out bool first ) ) { if( first ) { var serInfo = new SerializationInfo( obj.GetType(), new FormatterConverter() ); var context = new StreamingContext( StreamingContextStates.All ); serObj.GetObjectData( serInfo, context ); foreach( var member in serInfo ) { xml.WriteNode( writer, member.Value, refl.TypeToIdentifier( member.Name ), member.ObjectType, true ); // Force type for ISer } } } writer.WriteEndElement(); } } // --- Collection Handler --- public partial class CollectionHandler : ITypeHandler { public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType ) { if( obj == null ) { /* Write null */ return; } if( !( obj is IEnumerable collection ) ) { /* Error */ return; } writer.WriteStartElement( name ); xml.WriteTypeAttr( writer, memberType, obj.GetType() ); if( xml.HandleGraphWrite( writer, obj, out bool first ) ) { if( first ) { Type elemType = GetElementType( obj.GetType() ); int i = 0; foreach( var item in collection ) { xml.WriteNode( writer, item, $"i{i++}", elemType, false ); } } } writer.WriteEndElement(); } } // --- Object Handler (Default/Complex) --- public partial class ObjectHandler : ITypeHandler { public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType ) { if( obj == null ) { /* Write null */ return; } writer.WriteStartElement( name ); xml.WriteTypeAttr( writer, memberType, obj.GetType() ); var ti = xml._meta.Get( obj.GetType() ); if( xml.HandleGraphWrite( writer, obj, out bool first ) ) { if( first ) { foreach( var memberMeta in ti.Members ) { var value = memberMeta.GetValue( obj ); if( value != null ) { // If POD-Attribute, write attribute if( memberMeta.IsPodAttribute ) { try { writer.WriteAttributeString( memberMeta.XmlName, value.ToString() ); } catch( Exception ex ) { log.error( $"Writing Att {memberMeta.XmlName} = [{value}]" ); } } else { try { xml.WriteNode( writer, value, memberMeta.XmlName, memberMeta.Type, false ); } catch( Exception ex ) { log.error( $"Writing Node {memberMeta.XmlName} = [{value}]" ); } } } } } } writer.WriteEndElement(); } }