diff --git a/reflect/refl.cs b/reflect/refl.cs index 1e2eacb..2ab1f0b 100644 --- a/reflect/refl.cs +++ b/reflect/refl.cs @@ -180,8 +180,6 @@ static public class refl BindingFlags.Instance ); - - var en = PredEnumerator.Create( propArr.AsEnumerable(), fa => fa.GetCustomAttribute( typeof( NonSerializedAttribute ) ) == null && !list.Exists( f => f.Name == fa.Name ) ); diff --git a/ser/XmlFormatter2.cs b/ser/XmlFormatter2.cs index d6d8a3f..a6df02a 100644 --- a/ser/XmlFormatter2.cs +++ b/ser/XmlFormatter2.cs @@ -1,347 +1,350 @@ -using System; -using System.IO; -using System.Xml; -using System.Runtime.Serialization; -//using System.Web.Configuration; -using System.Collections; -using System.Collections.Generic; - - -using System.Reflection; -using System.Diagnostics; - +using System; +using System.IO; +using System.Xml; +using System.Runtime.Serialization; +//using System.Web.Configuration; +using System.Collections; +using System.Collections.Generic; + + +using System.Reflection; +using System.Diagnostics; + using System.Runtime.InteropServices; +using static System.Net.WebRequestMethods; /* + + element and attribute names + - Element names are case-sensitive + - Element names must start with a letter or underscore + - Element names cannot start with the letters xml(or XML, or Xml, etc) + - Element names can contain letters, digits, hyphens, underscores, and periods + - Element names cannot contain spaces + * TODO - * HUGE FLAW IN DESERIALIZATION. If you deser into something it resets everything to default values - * This didnt matter before when I did full things, but it matters now + * x) Add the ability for correctly named attributes to be able to fill in classes + * x) */ +namespace lib +{ - - - - - - - -namespace lib -{ - - public class AttDocumentSubclasses : Attribute - { - } - - public interface I_Serialize - { - void OnSerialize(); - void OnDeserialize( object enclosing ); - } - - public class InstanceAttribute : Attribute - { - } - - public class PropertiesAttribute : Attribute + public interface I_Serialize { + void OnSerialize(); + void OnDeserialize( object enclosing ); } - - - public class WhitelistAttribute : Attribute + [Flags] + public enum Types { - } + Fields = 0b_0001, + Props = 0b_0010, + Implied= 0b_0100, + None = 0b_000, + Default = Fields, + All = Fields | Props, + } - public class WhitelistFieldsAttribute : Attribute + public class Ser : Attribute + { + public Types Types { get; set; } = Types.Default; + } + + public class WLChildAttributes : Attribute { public string[] Values { get; private set; } - public WhitelistFieldsAttribute( params string[] values ) + public WLChildAttributes( params string[] values ) { this.Values = values; } - } - - public class WhitelistPropsAttribute : Attribute - { - public string[] Values { get; private set; } + } - public WhitelistPropsAttribute( params string[] values ) + public class WLChildFieldsAttribute : WLChildAttributes + { + public WLChildFieldsAttribute( params string[] values ) : base( values ) { } + } + + public class WLChildPropsAttribute : WLChildAttributes + { + public WLChildPropsAttribute( params string[] values ) : base( values ) { } + } + + public enum Datastructure + { + Invalid, + Tree, + Graph, + + } + + public class XmlFormatter2Cfg: Config + { + public readonly Datastructure datastructure = Datastructure.Graph; + + public readonly int Version = 2; + } + + public class XmlFormatter2: IFormatter + { + public StreamingContext Context { get; set; } + + static Random s_rnd = new Random(); + int m_rndVal = s_rnd.Next(); + + XmlFormatter2Cfg m_cfg = new XmlFormatter2Cfg(); + + + + #region Unimplimented + public ISurrogateSelector SurrogateSelector { - this.Values = values; + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } } - } - - public enum Datastructure - { - Invalid, - Tree, - Full, - - } - - public class XmlFormatter2Cfg: Config - { - public readonly Datastructure datastructure = Datastructure.Full; - } - - public class XmlFormatter2: IFormatter - { - public StreamingContext Context { get; set; } - - static Random s_rnd = new Random(); - int m_rndVal = s_rnd.Next(); - - XmlFormatter2Cfg m_cfg = new XmlFormatter2Cfg(); - - - - #region Unimplimented - public ISurrogateSelector SurrogateSelector - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public SerializationBinder Binder - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - #endregion - - - - - - - public XmlFormatter2() - { - Context = new StreamingContext( StreamingContextStates.All ); - } - - - - - public XmlFormatter2( XmlFormatter2Cfg cfg ) - { - Context = new StreamingContext( StreamingContextStates.All ); - - m_cfg = cfg; - } - - - - #region Deserialize - private static FormatterConverter s_conv = new FormatterConverter(); - - - public object Deserialize( Stream stream ) - { - return DeserializeKnownType( stream, null ); - } - - - public T Deserialize(Stream stream) - { - return (T)DeserializeKnownType(stream, typeof(T)); - } - - public object DeserializeKnownType( Stream stream, Type t ) - { - XmlTextReader reader = new XmlTextReader(stream); - - object obj = Deserialize(reader, t); - - return obj; - } - - private object Deserialize( XmlReader reader, Type t ) - { - m_alreadySerialized.Clear(); - m_objectID = new ObjectIDGenerator(); - - reader.Read(); - - XmlDocument doc = new XmlDocument(); - - doc.Load( reader ); - - if( t == null ) - return Deserialize( doc.DocumentElement ); - - return Deserialize( doc.DocumentElement, null, t ); - } - + + public SerializationBinder Binder + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + #endregion + + + + + + + public XmlFormatter2() + { + Context = new StreamingContext( StreamingContextStates.All ); + } + + + + + public XmlFormatter2( XmlFormatter2Cfg cfg ) + { + Context = new StreamingContext( StreamingContextStates.All ); + + m_cfg = cfg; + + log.warn( $"XML serialization is NOT fast" ); + } + + + + #region Deserialize + private static FormatterConverter s_conv = new FormatterConverter(); + + + public object Deserialize( Stream stream ) + { + return DeserializeKnownType( stream, null ); + } + + + public T Deserialize(Stream stream) + { + return (T)DeserializeKnownType(stream, typeof(T)); + } + + public object DeserializeKnownType( Stream stream, Type t ) + { + XmlTextReader reader = new XmlTextReader(stream); + + object obj = Deserialize(reader, t); + + return obj; + } + + private object Deserialize( XmlReader reader, Type t ) + { + m_alreadySerialized.Clear(); + m_objectID = new ObjectIDGenerator(); + + reader.Read(); + + XmlDocument doc = new XmlDocument(); + + doc.Load( reader ); + + if( t == null ) + return Deserialize( doc.DocumentElement ); + + return Deserialize( doc.DocumentElement, null, t, null ); + } + public void DeserializeInto(Stream stream, T obj) - { - XmlTextReader reader = new XmlTextReader( stream ); - reader.Read(); - - XmlDocument doc = new XmlDocument(); - - doc.Load( reader ); - - HydrateObject( doc.DocumentElement, null, obj ); - } - - private object Deserialize( XmlElement elem ) - { - //lib.log.info( "object Deserialize( XmlElement elem ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); - - string typename = elem.HasAttribute("t") ? elem.GetAttribute("t") : elem.Name; - - return Deserialize( elem, null, typename ); - } - - private object Deserialize( XmlElement elem, MemberInfo mi, string typename ) - { - AppDomain currentDomain = AppDomain.CurrentDomain; - Assembly[] assems = currentDomain.GetAssemblies(); - - Type type = null; - - // @@@@: This should go backwards, we tend to lookup our own stuff, then builtins. - // Also, cache a typename into its assembly. - foreach( Assembly a in assems ) - { - type = a.GetType( typename ); - - if( type != null ) - break; - } - - if( type == null ) - { - return null; - } - - return Deserialize( elem, null, type ); - } - - private object Deserialize( XmlElement elem, MemberInfo mi, Type type, object enclosing = null ) - { - TypeCode typeCode = Type.GetTypeCode(type); - - if( typeCode != TypeCode.Object ) - { - return DeserializeConcrete( elem, mi, type ); - } - else - { - if( !type.IsArray ) - { - object obj = DeserializeObject(elem, mi, type); - - if( obj is I_Serialize ) - { - var iser = obj as I_Serialize; - - iser.OnDeserialize( enclosing ); - } - - return obj; - } - else - { - return DeserializeArray( elem, mi, type ); - } - } - } - - Type[] mm_types = new Type[1]; - private object GetDefault( Type t ) - { - mm_types[0] = t; - - var fn = GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(mm_types); - - return fn.Invoke( this, null ); - } - - public T GetDefaultGeneric() - { - return default( T ); - } - - private object DeserializeConcrete( XmlElement elem, MemberInfo mi, Type type ) - { - string val = ""; - - if( elem.HasAttribute("v") ) + { + XmlTextReader reader = new XmlTextReader( stream ); + reader.Read(); + + XmlDocument doc = new XmlDocument(); + + doc.Load( reader ); + + HydrateObject( doc.DocumentElement, null, obj ); + } + + private object Deserialize( XmlElement elem ) + { + //lib.log.info( "object Deserialize( XmlElement elem ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); + + string typename = elem.HasAttribute("_.t") ? elem.GetAttribute("_.t") : elem.Name; + + return Deserialize( elem, null, typename ); + } + + private object Deserialize( XmlElement elem, MemberInfo mi, string typename ) + { + AppDomain currentDomain = AppDomain.CurrentDomain; + Assembly[] assems = currentDomain.GetAssemblies(); + + Type type = null; + + // @@@@: This should go backwards, we tend to lookup our own stuff, then builtins. + // Also, cache a typename into its assembly. + foreach( Assembly a in assems ) + { + type = a.GetType( typename ); + + if( type != null ) + break; + } + + if( type == null ) + { + return null; + } + + return Deserialize( elem, null, type, null ); + } + + private object Deserialize( XmlElement elem, MemberInfo mi, Type type, object existing /*, object enclosing = null*/ ) + { + TypeCode typeCode = Type.GetTypeCode(type); + + if( typeCode != TypeCode.Object ) + { + return DeserializeConcrete( elem, mi, type ); + } + else + { + if( !type.IsArray ) + { + object obj = DeserializeObject(elem, mi, type, existing); + + if( obj is I_Serialize ) + { + var iser = obj as I_Serialize; + + iser.OnDeserialize( null ); + } + + return obj; + } + else + { + return DeserializeArray( elem, mi, type ); + } + } + } + + Type[] mm_types = new Type[1]; + private object GetDefault( Type t ) + { + mm_types[0] = t; + + var fn = GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(mm_types); + + return fn.Invoke( this, null ); + } + + public T GetDefaultGeneric() + { + return default( T ); + } + + private object DeserializeConcrete( XmlElement elem, MemberInfo mi, Type type ) + { + string val = ""; + + if( elem.HasAttribute("v") ) + { + val = elem.GetAttribute("v"); + } + else { - val = elem.GetAttribute("v"); - } - else - { val = elem.InnerText; - } - - if ( !type.IsEnum ) - { - try - { - return s_conv.Convert( val, type ); - } - catch( Exception ) - { - return GetDefault( type ); - } - } - else - { - return Enum.Parse( type, val ); - } - - } - - private XmlElement getNamedChild( XmlNodeList list, string name ) - { - foreach( XmlNode node in list ) - { - if( node.Name == name ) - { - return (XmlElement)node; - } - } - - return null; - } - - private Type FindType( string shortname ) - { - Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); - - foreach( Assembly a in ass ) - { - Type t = a.GetType(shortname); - - if( t != null ) - { - return t; - } - } - - return null; - } - - private Type[] mm_consType = new Type[2]; - private object[] mm_args = new object[2]; - - private object DeserializeObject( XmlElement elem, MemberInfo mi, Type type ) + } + + if ( !type.IsEnum ) + { + try + { + return s_conv.Convert( val, type ); + } + catch( Exception ) + { + return GetDefault( type ); + } + } + else + { + return Enum.Parse( type, val ); + } + + } + + private XmlElement getNamedChild( XmlNodeList list, string name ) + { + foreach( XmlNode node in list ) + { + if( node.Name == name ) + { + return (XmlElement)node; + } + } + + return null; + } + + private Type FindType( string shortname ) + { + Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); + + foreach( Assembly a in ass ) + { + Type t = a.GetType(shortname); + + if( t != null ) + { + return t; + } + } + + return null; + } + + private Type[] mm_consType = new Type[2]; + private object[] mm_args = new object[2]; + + private object DeserializeObject( XmlElement elem, MemberInfo mi, Type type, object existing ) { Type finalType; - object obj; - GetObjectForDeser( elem, type, out finalType, out obj ); - return HydrateObject( elem, mi, finalType, obj ); + var obj = GetObjectForDeser( elem, type, out finalType, existing ); + + return HydrateObject( elem, mi, finalType, obj ); } public object HydrateObject( XmlElement elem, MemberInfo mi, T obj ) @@ -350,18 +353,18 @@ namespace lib } private object HydrateObject( XmlElement elem, MemberInfo mi, Type finalType, object obj ) - { - if( obj is IList ) - { - var list = obj as IList; - - return DeserializeList( elem, mi, finalType, list ); - } - - Type typeISerializable = typeof( ISerializable ); - + { + if( obj is IList ) + { + var list = obj as IList; + + return DeserializeList( elem, mi, finalType, list ); + } + + Type typeISerializable = typeof( ISerializable ); + if( obj is ISerializable ) // type.IsSubclassOf( typeISerializable ) ) - { + { XmlNodeList allChildren = elem.ChildNodes; //ISerializable ser = obj as ISerializable; @@ -372,21 +375,21 @@ namespace lib //ser.GetObjectData( serInfoForTypes, Context ); - foreach( var objNode in allChildren ) - { - var node = objNode as XmlElement; - - String name = node.Name; - - String childType = node.GetAttribute( "t" ); - - name = refl.TypeToIdentifier( name ); - - XmlElement childElem = getNamedChild( allChildren, name ); - - var des = Deserialize( childElem, mi, childType ); - - serInfo.AddValue( name, des, des.GetType() ); + foreach( var objNode in allChildren ) + { + var node = objNode as XmlElement; + + String name = node.Name; + + String childType = node.GetAttribute( "_.t" ); + + name = refl.TypeToIdentifier( name ); + + XmlElement childElem = getNamedChild( allChildren, name ); + + var des = Deserialize( childElem, mi, childType ); + + serInfo.AddValue( name, des, des.GetType() ); } //ConstructorInfo[] allCons = obj.GetType().GetConstructors( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); @@ -395,475 +398,478 @@ namespace lib //object objUn = FormatterServices.GetSafeUninitializedObject( finalType ); - IDeserializationCallback objUnOnDeser = obj as IDeserializationCallback; - - mm_consType[0] = typeof( SerializationInfo ); - mm_consType[1] = typeof( StreamingContext ); - ConstructorInfo serCons = finalType.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, mm_consType, null ); - - mm_args[0] = serInfo; - mm_args[1] = Context; - serCons.Invoke( obj, mm_args ); - - if( objUnOnDeser != null ) - { - objUnOnDeser.OnDeserialization( objUnOnDeser ); + IDeserializationCallback objUnOnDeser = obj as IDeserializationCallback; + + mm_consType[0] = typeof( SerializationInfo ); + mm_consType[1] = typeof( StreamingContext ); + ConstructorInfo serCons = finalType.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, mm_consType, null ); + + mm_args[0] = serInfo; + mm_args[1] = Context; + serCons.Invoke( obj, mm_args ); + + if( objUnOnDeser != null ) + { + objUnOnDeser.OnDeserialization( objUnOnDeser ); } - /* - ser.GetObjectData( serInfo, Context ); - - //var serEnum = ; - - foreach( var serMember in serInfo ) - { - String name = serMember.Name; - - name = refl.TypeToIdentifier( name ); - - XmlElement childElem = getNamedChild( allChildren, name ); - - var des = Deserialize( childElem, name ); - } + /* + ser.GetObjectData( serInfo, Context ); + + //var serEnum = ; + + foreach( var serMember in serInfo ) + { + String name = serMember.Name; + + name = refl.TypeToIdentifier( name ); + + XmlElement childElem = getNamedChild( allChildren, name ); + + var des = Deserialize( childElem, name ); + } */ - } - else - { + } + else + { XmlNodeList allChildren = elem.ChildNodes; - var doFields = true; - var doProperties = false; + bool filterFields, filterProps, doImpls, doFields, doProps; + HashSet whitelistFields, whitelistProps; + GetFilters( mi, finalType, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps ); - var filterFields = mi?.GetCustomAttribute() != null; - var filterProps = mi?.GetCustomAttribute() != null; + /* + List members = new(); - HashSet whitelistFields = new( mi?.GetCustomAttribute()?.Values ?? new string[0] ); - HashSet whitelistProps = new( mi?.GetCustomAttribute()?.Values ?? new string[0] ); - - if( finalType.GetCustomAttribute() != null ) + if( doFields || doImpls ) { - doProperties = true; + members.AddRange( refl.GetAllFields( finalType ) ); } - if( mi?.GetCustomAttribute() != null ) + if( doProps || doImpls ) { - doProperties = true; - - doFields = mi?.GetCustomAttribute() != null; + members.AddRange( refl.GetAllProperties( finalType ) ); } - - if( doFields ) - { + */ + + if( doFields || doImpls ) + { var fields = refl.GetAllFields( finalType ); - foreach( var childFi in fields ) - { + foreach( FieldInfo childFi in fields ) + { + String name = childFi.Name; - if( filterFields && !whitelistFields.Contains( name ) ) continue; - - name = refl.TypeToIdentifier( name ); - - XmlElement childElem = getNamedChild( allChildren, name ); - - if( childElem != null ) - { - object childObj = Deserialize( childElem, childFi, childFi.FieldType, obj ); - - childFi.SetValue( obj, childObj ); - } - else if( fields.Count == 1 ) - { - object childObj = Deserialize( elem, childFi, childFi.FieldType, obj ); - - childFi.SetValue( obj, childObj ); - } + //This is to convert c# names that would be bad as XML tags + name = refl.TypeToIdentifier( name ); + + if( FilterField( filterFields, doImpls, whitelistFields, childFi as MemberInfo, name ) ) continue; + + XmlElement childElem = getNamedChild( allChildren, name ); + + if( childElem != null ) + { + object existingObj = childFi.GetValue( obj ); + + object childObj = Deserialize( childElem, childFi, childFi.FieldType, existingObj ); + + childFi.SetValue( obj, childObj ); + } } - } - - if( doProperties ) - { + } + + + if( doProps || doImpls ) + { var props = refl.GetAllProperties( finalType ); - foreach( var childPi in props ) - { + foreach( var childPi in props ) + { String name = childPi.Name; - if( filterProps && !whitelistProps.Contains( name ) ) continue; - - name = refl.TypeToIdentifier( name ); - - XmlElement childElem = getNamedChild( allChildren, name ); - - if( childElem != null ) - { - object childObj = Deserialize( childElem, childPi, childPi.PropertyType, obj ); - - childPi.SetValue( obj, childObj ); - } - else if( props.Count == 1 ) - { - object childObj = Deserialize( elem, childPi, childPi.PropertyType, obj ); - - childPi.SetValue( obj, childObj ); - } + name = refl.TypeToIdentifier( name ); + + if( FilterField( filterFields, doImpls, whitelistFields, childPi as MemberInfo, name ) ) continue; + + XmlElement childElem = getNamedChild( allChildren, name ); + + if( childElem != null ) + { + object existingObj = childPi.GetValue( obj ); + + object childObj = Deserialize( childElem, childPi, childPi.PropertyType, existingObj ); + + childPi.SetValue( obj, childObj ); + } + else + { + log.warn( $"" ); + } } - } - - - } - + } + + + } + return obj; } - private void GetObjectForDeser( XmlElement elem, Type type, out Type finalType, out object obj ) - { - string refString = elem.GetAttribute( "ref" ); - - int refInt = refString.Length > 0 ? Convert.ToInt32( refString ) : -1; - - finalType = type; - if( elem.HasAttribute( "t" ) ) - { - var typename = elem.GetAttribute( "t" ); - finalType = FindType( typename ); - - if( finalType == null ) - finalType = type; - } - - obj = createObject( finalType, refInt ); + private static bool FilterField( bool filterFields, bool doImpls, HashSet whitelistFields, MemberInfo mi, string name ) + { + if( doImpls ) + { + if( mi.GetCustomAttribute() == null ) return true; + } + + if( filterFields && !whitelistFields.Contains( name ) ) return true; + + return false; } - private object DeserializeList( XmlElement elem, MemberInfo mi, Type type, IList list ) - { - XmlNodeList arrNodeList = elem.ChildNodes; - - Type t = list.GetType(); - - Type[] genT = t.GetGenericArguments(); - - Debug.Assert( genT.Length == 1 ); - - for( int i = 0; i < arrNodeList.Count; ++i ) - { - if( arrNodeList.Item( i ) is XmlElement ) - { - XmlElement arrElem = (XmlElement)arrNodeList.Item(i); - - list.Add( Deserialize( arrElem, mi, genT[0] ) ); - } - } - - return list; - } - - private object DeserializeArray( XmlElement elem, MemberInfo mi, Type type ) - { - Type typeElem = type.GetElementType(); - - string refString = elem.GetAttribute("ref"); - int refInt = refString.Length > 0 ? Convert.ToInt32(refString) : -1; - - XmlNodeList arrNodeList = elem.ChildNodes; - - int length = arrNodeList.Count; - - Array arr = createArray(typeElem, refInt, length); - - for( int i = 0; i < arr.Length; ++i ) - { - if( arrNodeList.Item( i ) is XmlElement ) - { - XmlElement arrElem = (XmlElement)arrNodeList.Item(i); - + private object GetObjectForDeser( XmlElement elem, Type type, out Type finalType, object obj ) + { + finalType = type; + if( elem.HasAttribute( "_.t" ) ) + { + var typename = elem.GetAttribute( "_.t" ); + finalType = FindType( typename ); + + if( finalType == null ) + finalType = type; + } + + string refString = elem.GetAttribute( "ref" ); + + int refInt = refString.Length > 0 ? Convert.ToInt32( refString ) : -1; + + obj = createObject( finalType, refInt, obj ); + + return obj; + } + + private object DeserializeList( XmlElement elem, MemberInfo mi, Type type, IList list ) + { + XmlNodeList arrNodeList = elem.ChildNodes; + + Type t = list.GetType(); + + Type[] genT = t.GetGenericArguments(); + + Debug.Assert( genT.Length == 1 ); + + for( int i = 0; i < arrNodeList.Count; ++i ) + { + if( arrNodeList.Item( i ) is XmlElement ) + { + XmlElement arrElem = (XmlElement)arrNodeList.Item(i); + + list.Add( Deserialize( arrElem, mi, genT[0], null ) ); + } + } + + return list; + } + + private object DeserializeArray( XmlElement elem, MemberInfo mi, Type type ) + { + Type typeElem = type.GetElementType(); + + string refString = elem.GetAttribute("ref"); + int refInt = refString.Length > 0 ? Convert.ToInt32(refString) : -1; + + XmlNodeList arrNodeList = elem.ChildNodes; + + int length = arrNodeList.Count; + + Array arr = createArray(typeElem, refInt, length); + + for( int i = 0; i < arr.Length; ++i ) + { + if( arrNodeList.Item( i ) is XmlElement ) + { + XmlElement arrElem = (XmlElement)arrNodeList.Item(i); + var finalType = typeElem; - if (arrElem.HasAttribute("t")) + if (arrElem.HasAttribute("_.t")) { - var typename = arrElem.GetAttribute("t"); + var typename = arrElem.GetAttribute("_.t"); finalType = FindType(typename); if (finalType == null) finalType = typeElem; - } - - arr.SetValue( Deserialize( arrElem, mi, finalType), i ); - } - } - - return arr; - } - - private object createObject( string typename, int refInt ) - { - Type type = Type.GetType(typename); - - return createObject( type, refInt ); - } - - private object createObject( Type type, int refInt ) - { - TypeCode tc = Type.GetTypeCode(type); - - if( m_cfg.datastructure == Datastructure.Full && refInt > 0 && m_alreadySerialized.ContainsKey( refInt ) ) - { - //lib.log.info( "Reusing object for {0}", refInt ); - return m_alreadySerialized[refInt]; - } - else - { - object obj = null; - - try - { - //Trying the nice way to creat objects first. - obj = Activator.CreateInstance( type ); - - } - catch( Exception ) - { - try - { - obj = System.Runtime.Serialization.FormatterServices.GetUninitializedObject( type ); - } - catch( Exception exInner ) - { - log.error( $"Got exception {exInner.Message} trying to make an uninitialized object" ); - } - - } - - if( obj == null ) - { - log.warn( $"Could not create object of type {type.Name}" ); - - return obj; - } - - if( m_cfg.datastructure == Datastructure.Full && refInt > 0 ) - { - m_alreadySerialized[refInt] = obj; - } - - return obj; - } - } - - private Array createArray( string elemTypename, int refInt, int length ) - { - Type elemType = Type.GetType(elemTypename); - - return createArray( elemType, refInt, length ); - } - - private Array createArray( Type elemType, int refInt, int length ) - { - TypeCode elemTC = Type.GetTypeCode(elemType); - - if( m_cfg.datastructure == Datastructure.Full && refInt > 0 && m_alreadySerialized.ContainsKey( refInt ) ) - { - return (Array)m_alreadySerialized[refInt]; - } - else - { - Array arr = Array.CreateInstance(elemType, length); - - if( m_cfg.datastructure == Datastructure.Full ) - { - m_alreadySerialized[refInt] = arr; - - } - - return arr; - } - } - - private ObjectIDGenerator m_objectID = new ObjectIDGenerator(); - private Dictionary m_alreadySerialized = new Dictionary(); - - #endregion - - #region Serialize - - private string getTypeName( Type type ) - { - //Assembly ass = type.Assembly; - - //string assName = ass.GetName().Name; - - return type.FullName; // + ", " + assName; + } + + arr.SetValue( Deserialize( arrElem, mi, finalType, null), i ); + } + } + + return arr; + } + + private object createObject( string typename, int refInt, object obj ) + { + Type type = Type.GetType(typename); + + return createObject( type, refInt, obj ); + } + + private object createObject( Type type, int refInt, object existingObj ) + { + TypeCode tc = Type.GetTypeCode(type); + + if( m_cfg.datastructure == Datastructure.Graph && refInt > 0 && m_alreadySerialized.ContainsKey( refInt ) ) + { + //lib.log.info( "Reusing object for {0}", refInt ); + return m_alreadySerialized[refInt]; + } + + if( existingObj != null ) + { + var existingObjType = existingObj.GetType(); + + if( type == existingObjType ) return existingObj; + } + + { + object obj = null; + + try + { + //Trying the nice way to creat objects first. + obj = Activator.CreateInstance( type ); + + } + catch( Exception ) + { + try + { + obj = System.Runtime.Serialization.FormatterServices.GetUninitializedObject( type ); + } + catch( Exception exInner ) + { + log.error( $"Got exception {exInner.Message} trying to make an uninitialized object" ); + } + + } + + if( obj == null ) + { + log.warn( $"Could not create object of type {type.Name}" ); + + return obj; + } + + if( m_cfg.datastructure == Datastructure.Graph && refInt > 0 ) + { + m_alreadySerialized[refInt] = obj; + } + + return obj; + } + } + + private Array createArray( string elemTypename, int refInt, int length ) + { + Type elemType = Type.GetType(elemTypename); + + return createArray( elemType, refInt, length ); + } + + private Array createArray( Type elemType, int refInt, int length ) + { + TypeCode elemTC = Type.GetTypeCode(elemType); + + if( m_cfg.datastructure == Datastructure.Graph && refInt > 0 && m_alreadySerialized.ContainsKey( refInt ) ) + { + return (Array)m_alreadySerialized[refInt]; + } + else + { + Array arr = Array.CreateInstance(elemType, length); + + if( m_cfg.datastructure == Datastructure.Graph ) + { + m_alreadySerialized[refInt] = arr; + + } + + return arr; + } + } + + private ObjectIDGenerator m_objectID = new ObjectIDGenerator(); + private Dictionary m_alreadySerialized = new Dictionary(); + + #endregion + + #region Serialize + + private string getTypeName( Type type ) + { + //Assembly ass = type.Assembly; + + //string assName = ass.GetName().Name; + + return type.FullName; // + ", " + assName; } public void Serialize( Stream stream, object root ) { - Serialize( stream, null, root ); + Serialize( stream, null, root ); } - - - public void Serialize( Stream stream, MemberInfo mi, object root ) - { - //lib.log.info( "Serialize( Stream stream, object root ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); - - m_alreadySerialized.Clear(); - m_objectID = new ObjectIDGenerator(); - - XmlTextWriter writer = new XmlTextWriter(stream, System.Text.Encoding.ASCII); - - writer.Formatting = Formatting.Indented; - - Serialize( writer, mi, root ); - - //Rely on the parent closing the stream. - //writer.Close(); - writer.Flush(); - - //lib.log.info( "Serialize END ( Stream stream, object root ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); - } - - private void Serialize( XmlWriter writer, MemberInfo mi, object root ) - { - //writer.WriteStartDocument(); - Serialize( writer, mi, root, "root", true ); - //writer.WriteEndDocument(); - } - - private void Serialize( XmlWriter writer, MemberInfo mi, object root, string name, bool forceType ) - { - writer.WriteStartElement( name ); - - if( root != null ) - { - Type type = root.GetType(); - - TypeCode typeCode = Type.GetTypeCode(type); - - if( typeCode != TypeCode.Object ) - { - SerializeConcrete( writer, mi, root, forceType ); - } - else - { - if( !type.IsArray ) - { - SerializeObject( writer, mi, root ); - } - else - { - SerializeArray( writer, mi, root ); - } - } - } - else - { - writer.WriteAttributeString( "v", "null" ); - } - - writer.WriteEndElement(); - } - - private void SerializeConcrete( XmlWriter writer, MemberInfo mi, object root, bool forceType ) - { - //TODO: Only write this out if debugging. - if( forceType ) - { - writer.WriteAttributeString( "t", getTypeName( root.GetType() ) ); - } - writer.WriteAttributeString( "v", root.ToString() ); - } - - private void SerializeObject( XmlWriter writer, MemberInfo mi, object root ) - { - writer.WriteAttributeString( "t", getTypeName( root.GetType() ) ); - - /* - if( root is IList ) - { - var list = root as IList; - - Type t = root.GetType(); - - Type[] genT = t.GetGenericArguments(); - } - */ - - bool first; - - long refInt = m_objectID.GetId(root, out first); - - if( m_cfg.datastructure == Datastructure.Full ) - { - writer.WriteAttributeString( "ref", refInt.ToString() ); - - } - - if( first ) - { - if( m_cfg.datastructure == Datastructure.Full ) - { - m_alreadySerialized[refInt] = root; - } - - Type type = root.GetType(); - + + + public void Serialize( Stream stream, MemberInfo mi, object root ) + { + //lib.log.info( "Serialize( Stream stream, object root ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); + + m_alreadySerialized.Clear(); + m_objectID = new ObjectIDGenerator(); + + XmlTextWriter writer = new XmlTextWriter(stream, System.Text.Encoding.ASCII); + + writer.Formatting = Formatting.Indented; + + Serialize( writer, mi, root ); + + //Rely on the parent closing the stream. + //writer.Close(); + writer.Flush(); + + //lib.log.info( "Serialize END ( Stream stream, object root ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); + } + + private void Serialize( XmlWriter writer, MemberInfo mi, object root ) + { + //writer.WriteStartDocument(); + Serialize( writer, mi, root, "root", 1, true ); + //writer.WriteEndDocument(); + } + + private void Serialize( XmlWriter writer, MemberInfo mi, object root, string name, int depth, bool forceType ) + { + writer.WriteStartElement( name ); + + if( root != null ) + { + Type type = root.GetType(); + + TypeCode typeCode = Type.GetTypeCode(type); + + if( typeCode != TypeCode.Object ) + { + SerializeConcrete( writer, mi, root, forceType ); + } + else + { + if( !type.IsArray ) + { + SerializeObject( writer, mi, root, depth ); + } + else + { + SerializeArray( writer, mi, root, depth ); + } + } + } + else + { + writer.WriteAttributeString( "v", "null" ); + } + + writer.WriteEndElement(); + } + + private void SerializeConcrete( XmlWriter writer, MemberInfo mi, object root, bool forceType ) + { + //TODO: Only write this out if debugging. + if( forceType ) + { + writer.WriteAttributeString( "_.t", getTypeName( root.GetType() ) ); + } + writer.WriteAttributeString( "v", root.ToString() ); + } + + private void SerializeObject( XmlWriter writer, MemberInfo mi, object root, int depth ) + { + writer.WriteAttributeString( "_.t", getTypeName( root.GetType() ) ); + + if(depth == 1) + { + writer.WriteAttributeString( "_.version.", $"{m_cfg.Version}" ); + } + + /* + if( root is IList ) + { + var list = root as IList; + + Type t = root.GetType(); + + Type[] genT = t.GetGenericArguments(); + } + */ + + bool first; + + long refInt = m_objectID.GetId(root, out first); + + if( m_cfg.datastructure == Datastructure.Graph ) + { + writer.WriteAttributeString( "ref", refInt.ToString() ); + + } + + if( first ) + { + if( m_cfg.datastructure == Datastructure.Graph ) + { + m_alreadySerialized[refInt] = root; + } + + Type type = root.GetType(); + //var whitelistProp = type.GetCustomAttribute(); //var useWhitelist = whitelistProp != null; //* - Type typeISerializable = typeof(ISerializable); - - if( root is ISerializable ) // type.IsSubclassOf( typeISerializable ) ) - { - ISerializable ser = root as ISerializable; - - var serInfo = new SerializationInfo(type, new FormatterConverter()); - - ser.GetObjectData( serInfo, Context ); - - //var serEnum = ; - - foreach( var serMember in serInfo ) - { - String name = serMember.Name; - - name = refl.TypeToIdentifier( name ); - - Serialize( writer, mi, serMember.Value, name, true ); - } - - //var sc = new SerializationContext( - - //ser.GetObjectData( - } - else - //*/ - { - var doFields = true; - var doProperties = false; - - var filterFields = mi?.GetCustomAttribute() != null; - var filterProps = mi?.GetCustomAttribute() != null; - - HashSet whitelistFields = new( mi?.GetCustomAttribute()?.Values ?? new string[0] ); - HashSet whitelistProps = new( mi?.GetCustomAttribute()?.Values ?? new string[0] ); - - if( type.GetCustomAttribute() != null ) - { - doProperties = true; - } - - if( mi?.GetCustomAttribute() != null ) - { - doProperties = true; + Type typeISerializable = typeof(ISerializable); - doFields = mi?.GetCustomAttribute() != null; + if( root is ISerializable ) // type.IsSubclassOf( typeISerializable ) ) + { + ISerializable ser = root as ISerializable; + + var serInfo = new SerializationInfo(type, new FormatterConverter()); + + ser.GetObjectData( serInfo, Context ); + + //var serEnum = ; + + foreach( var serMember in serInfo ) + { + String name = serMember.Name; + + name = refl.TypeToIdentifier( name ); + + Serialize( writer, mi, serMember.Value, name, depth, true ); } - //MemberInfo[] miArr = FormatterServices.GetSerializableMembers( type, Context ); + //var sc = new SerializationContext( - if( doFields ) + //ser.GetObjectData( + } + else + //*/ + { + bool filterFields, filterProps, doImpls, doFields, doProps; + HashSet whitelistFields, whitelistProps; + GetFilters( mi, type, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps ); + + if( doFields || doImpls ) { var fields = refl.GetAllFields( type ); @@ -871,8 +877,7 @@ namespace lib { String name = childFi.Name; - if( filterFields && !whitelistFields.Contains( name ) ) continue; - + if( FilterField( filterFields, doImpls, whitelistFields, childFi as MemberInfo, name ) ) continue; object[] objs = childFi.GetCustomAttributes( typeof( NonSerializedAttribute ), true ); @@ -885,11 +890,11 @@ namespace lib name = refl.TypeToIdentifier( name ); - Serialize( writer, childFi, childFi.GetValue( root ), name, false ); - } + Serialize( writer, childFi, childFi.GetValue( root ), name, depth + 1, false ); + } } - - if( doProperties ) + + if( doProps || doImpls ) { var props = refl.GetAllProperties( type ); @@ -897,7 +902,7 @@ namespace lib { String name = childPi.Name; - if( filterProps && !whitelistProps.Contains( name ) ) continue; + if( FilterField( filterProps, doImpls, whitelistProps, childPi as MemberInfo, name ) ) continue; object[] objs = childPi.GetCustomAttributes( typeof( NonSerializedAttribute ), true ); @@ -908,48 +913,65 @@ namespace lib name = refl.TypeToIdentifier( name ); - Serialize( writer, childPi, childPi.GetValue( root ), name, false ); - } - } - - } - } - } - - private void SerializeArray( XmlWriter writer, MemberInfo mi, object root ) - { - Array arr = (Array)root; - - Type typeElem = arr.GetType().GetElementType(); - - Type type = root.GetType(); - - writer.WriteAttributeString( "t", getTypeName( type ) ); - - bool first; - - long refInt = m_objectID.GetId(root, out first); - - if( m_cfg.datastructure == Datastructure.Full ) - { - writer.WriteAttributeString( "ref", refInt.ToString() ); - } - - if( first ) - { - if( m_cfg.datastructure == Datastructure.Full ) - { - m_alreadySerialized[refInt] = root; - } - - - for( int i = 0; i < arr.Length; ++i ) - { - Serialize( writer, mi, arr.GetValue( i ), "i" + i.ToString(), false ); - } - } + Serialize( writer, childPi, childPi.GetValue( root ), name, depth + 1, false ); + } + } + + } + } } - #endregion - } - -} + + private static void GetFilters( MemberInfo mi, Type type, out bool filterFields, out bool filterProps, out bool doImpls, out bool doFields, out bool doProps, out HashSet whitelistFields, out HashSet whitelistProps ) + { + var custWLFields = mi?.GetCustomAttribute(); + var custWLProps = mi?.GetCustomAttribute(); + + filterFields = custWLFields != null; + filterProps = custWLProps != null; + + var typesTodo = type.GetCustomAttribute()?.Types ?? Types.None; + + doImpls = typesTodo.HasFlag( Types.Implied ); + doFields = filterFields || typesTodo.HasFlag( Types.Fields ); + doProps = filterProps || typesTodo.HasFlag( Types.Props ); + whitelistFields = new( custWLFields?.Values ?? new string[0] ); + whitelistProps = new( custWLProps?.Values ?? new string[0] ); + } + + private void SerializeArray( XmlWriter writer, MemberInfo mi, object root, int depth ) + { + Array arr = (Array)root; + + Type typeElem = arr.GetType().GetElementType(); + + Type type = root.GetType(); + + writer.WriteAttributeString( "_.t", getTypeName( type ) ); + + bool first; + + long refInt = m_objectID.GetId(root, out first); + + if( m_cfg.datastructure == Datastructure.Graph ) + { + writer.WriteAttributeString( "ref", refInt.ToString() ); + } + + if( first ) + { + if( m_cfg.datastructure == Datastructure.Graph ) + { + m_alreadySerialized[refInt] = root; + } + + + for( int i = 0; i < arr.Length; ++i ) + { + Serialize( writer, mi, arr.GetValue( i ), "i" + i.ToString(), depth + 1, false ); + } + } + } + #endregion + } + +}