diff --git a/ser/XmlFormatter2.cs b/ser/XmlFormatter2.cs index 4633c30..d6d8a3f 100644 --- a/ser/XmlFormatter2.cs +++ b/ser/XmlFormatter2.cs @@ -10,8 +10,27 @@ using System.Collections.Generic; using System.Reflection; using System.Diagnostics; -using System.Runtime.InteropServices; - +using System.Runtime.InteropServices; + + +/* + * 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 +*/ + + + + + + + + + + + + + namespace lib { @@ -25,6 +44,41 @@ namespace lib void OnDeserialize( object enclosing ); } + public class InstanceAttribute : Attribute + { + } + + public class PropertiesAttribute : Attribute + { + } + + + + public class WhitelistAttribute : Attribute + { + } + + + public class WhitelistFieldsAttribute : Attribute + { + public string[] Values { get; private set; } + + public WhitelistFieldsAttribute( params string[] values ) + { + this.Values = values; + } + } + + public class WhitelistPropsAttribute : Attribute + { + public string[] Values { get; private set; } + + public WhitelistPropsAttribute( params string[] values ) + { + this.Values = values; + } + } + public enum Datastructure { Invalid, @@ -88,37 +142,29 @@ namespace lib #region Deserialize private static FormatterConverter s_conv = new FormatterConverter(); + public object Deserialize( Stream stream ) { - //lib.log.info( "Deserialize( Stream stream ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); return DeserializeKnownType( stream, null ); - //lib.log.info( "Deserialize END ( Stream stream ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); } public T Deserialize(Stream stream) { - //lib.log.info( "Deserialize( Stream stream ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); return (T)DeserializeKnownType(stream, typeof(T)); - //lib.log.info( "Deserialize END ( Stream stream ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); } public object DeserializeKnownType( Stream stream, Type t ) { - //lib.log.info( "DeserializeKnownType( Stream stream, Type t ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); - XmlTextReader reader = new XmlTextReader(stream); - //reader.Settings = System.Text.Encoding.ASCII; object obj = Deserialize(reader, t); - //lib.log.info( "DeserializeKnownType END( Stream stream, Type t ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); + return obj; } private object Deserialize( XmlReader reader, Type t ) { - //lib.log.info( "Deserialize( XmlReader reader, Type t ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); - m_alreadySerialized.Clear(); m_objectID = new ObjectIDGenerator(); @@ -128,12 +174,22 @@ namespace lib doc.Load( reader ); - ////lib.log.info( "What to deserialize {0}", doc.OuterXml.ToString() ); - if( t == null ) return Deserialize( doc.DocumentElement ); - return Deserialize( doc.DocumentElement, t ); + return Deserialize( doc.DocumentElement, null, t ); + } + + 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 ) @@ -142,10 +198,10 @@ namespace lib string typename = elem.HasAttribute("t") ? elem.GetAttribute("t") : elem.Name; - return Deserialize( elem, typename ); + return Deserialize( elem, null, typename ); } - private object Deserialize( XmlElement elem, string typename ) + private object Deserialize( XmlElement elem, MemberInfo mi, string typename ) { AppDomain currentDomain = AppDomain.CurrentDomain; Assembly[] assems = currentDomain.GetAssemblies(); @@ -167,22 +223,22 @@ namespace lib return null; } - return Deserialize( elem, type ); + return Deserialize( elem, null, type ); } - private object Deserialize( XmlElement elem, Type type, object enclosing = null ) + private object Deserialize( XmlElement elem, MemberInfo mi, Type type, object enclosing = null ) { TypeCode typeCode = Type.GetTypeCode(type); if( typeCode != TypeCode.Object ) { - return DeserializeConcrete( elem, type ); + return DeserializeConcrete( elem, mi, type ); } else { if( !type.IsArray ) { - object obj = DeserializeObject(elem, type); + object obj = DeserializeObject(elem, mi, type); if( obj is I_Serialize ) { @@ -195,7 +251,7 @@ namespace lib } else { - return DeserializeArray( elem, type ); + return DeserializeArray( elem, mi, type ); } } } @@ -215,7 +271,7 @@ namespace lib return default( T ); } - private object DeserializeConcrete( XmlElement elem, Type type ) + private object DeserializeConcrete( XmlElement elem, MemberInfo mi, Type type ) { string val = ""; @@ -278,73 +334,72 @@ namespace lib private Type[] mm_consType = new Type[2]; private object[] mm_args = new object[2]; - private object DeserializeObject( XmlElement elem, Type type ) + + private object DeserializeObject( XmlElement elem, MemberInfo mi, Type type ) + { + Type finalType; + object obj; + GetObjectForDeser( elem, type, out finalType, out obj ); + + return HydrateObject( elem, mi, finalType, obj ); + } + + public object HydrateObject( XmlElement elem, MemberInfo mi, T obj ) + { + return HydrateObject( elem, mi, typeof( T ), obj ); + } + + private object HydrateObject( XmlElement elem, MemberInfo mi, Type finalType, object obj ) { - string refString = elem.GetAttribute("ref"); - - int refInt = refString.Length > 0 ? Convert.ToInt32(refString) : -1; - - var finalType = type; - if( elem.HasAttribute( "t" ) ) - { - var typename = elem.GetAttribute("t"); - finalType = FindType( typename ); - - if( finalType == null ) - finalType = type; - } - - object obj = createObject(finalType, refInt); - if( obj is IList ) { var list = obj as IList; - return DeserializeList( elem, type, list ); + return DeserializeList( elem, mi, finalType, list ); } - Type typeISerializable = typeof(ISerializable); + Type typeISerializable = typeof( ISerializable ); - if( obj is ISerializable ) // type.IsSubclassOf( typeISerializable ) ) + if( obj is ISerializable ) // type.IsSubclassOf( typeISerializable ) ) { - XmlNodeList allChildren = elem.ChildNodes; - - //ISerializable ser = obj as ISerializable; - - var serInfo = new SerializationInfo(finalType, new FormatterConverter()); - - //var serInfoForTypes = new SerializationInfo( type, new FormatterConverter() ); - - //ser.GetObjectData( serInfoForTypes, Context ); - + XmlNodeList allChildren = elem.ChildNodes; + + //ISerializable ser = obj as ISerializable; + + var serInfo = new SerializationInfo( finalType, new FormatterConverter() ); + + //var serInfoForTypes = new SerializationInfo( type, new FormatterConverter() ); + + //ser.GetObjectData( serInfoForTypes, Context ); + foreach( var objNode in allChildren ) { var node = objNode as XmlElement; String name = node.Name; - String childType = node.GetAttribute("t"); + String childType = node.GetAttribute( "t" ); name = refl.TypeToIdentifier( name ); - XmlElement childElem = getNamedChild(allChildren, name); + XmlElement childElem = getNamedChild( allChildren, name ); - var des = Deserialize(childElem, childType); + var des = Deserialize( childElem, mi, childType ); serInfo.AddValue( name, des, des.GetType() ); - } - - //ConstructorInfo[] allCons = obj.GetType().GetConstructors( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); - - //var serMem = FormatterServices.GetSerializableMembers( finalType ); - - //object objUn = FormatterServices.GetSafeUninitializedObject( finalType ); - + } + + //ConstructorInfo[] allCons = obj.GetType().GetConstructors( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); + + //var serMem = FormatterServices.GetSerializableMembers( finalType ); + + //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); + ConstructorInfo serCons = finalType.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, mm_consType, null ); mm_args[0] = serInfo; mm_args[1] = Context; @@ -353,8 +408,8 @@ namespace lib if( objUnOnDeser != null ) { objUnOnDeser.OnDeserialization( objUnOnDeser ); - } - + } + /* ser.GetObjectData( serInfo, Context ); @@ -370,47 +425,117 @@ namespace lib var des = Deserialize( childElem, name ); } - */ + */ } else { - XmlNodeList allChildren = elem.ChildNodes; + XmlNodeList allChildren = elem.ChildNodes; + + 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( finalType.GetCustomAttribute() != null ) + { + doProperties = true; + } + + if( mi?.GetCustomAttribute() != null ) + { + doProperties = true; + + doFields = mi?.GetCustomAttribute() != null; + } - var fields = refl.GetAllFields(type); - - //MemberInfo[] miArr = FormatterServices.GetSerializableMembers( type, Context ); - - foreach( var childFi in fields ) + if( doFields ) { - - String name = childFi.Name; - - name = refl.TypeToIdentifier( name ); - - XmlElement childElem = getNamedChild(allChildren, name); - - - if( childElem != null ) + var fields = refl.GetAllFields( finalType ); + + foreach( var childFi in fields ) { - object childObj = Deserialize(childElem, childFi.FieldType, obj); + String name = childFi.Name; + + if( filterFields && !whitelistFields.Contains( name ) ) continue; - childFi.SetValue( obj, childObj ); - } - else if( fields.Count == 1 ) - { - object childObj = Deserialize(elem, childFi.FieldType, obj); + name = refl.TypeToIdentifier( name ); - childFi.SetValue( obj, childObj ); - } + 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 ); + } + } } + + if( doProperties ) + { + var props = refl.GetAllProperties( finalType ); + + 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 ); + } + } + } + + } - return obj; - } + return obj; + } + + private void GetObjectForDeser( XmlElement elem, Type type, out Type finalType, out object obj ) + { + string refString = elem.GetAttribute( "ref" ); - private object DeserializeList( XmlElement elem, Type type, IList list ) + 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 object DeserializeList( XmlElement elem, MemberInfo mi, Type type, IList list ) { XmlNodeList arrNodeList = elem.ChildNodes; @@ -426,14 +551,14 @@ namespace lib { XmlElement arrElem = (XmlElement)arrNodeList.Item(i); - list.Add( Deserialize( arrElem, genT[0] ) ); + list.Add( Deserialize( arrElem, mi, genT[0] ) ); } } return list; } - private object DeserializeArray( XmlElement elem, Type type ) + private object DeserializeArray( XmlElement elem, MemberInfo mi, Type type ) { Type typeElem = type.GetElementType(); @@ -462,7 +587,7 @@ namespace lib finalType = typeElem; } - arr.SetValue( Deserialize( arrElem, finalType), i ); + arr.SetValue( Deserialize( arrElem, mi, finalType), i ); } } @@ -567,9 +692,16 @@ namespace lib //string assName = ass.GetName().Name; return type.FullName; // + ", " + assName; - } + } + + + public void Serialize( Stream stream, object root ) + { + Serialize( stream, null, root ); + } - public void Serialize( Stream stream, object 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 ); @@ -580,7 +712,7 @@ namespace lib writer.Formatting = Formatting.Indented; - Serialize( writer, root ); + Serialize( writer, mi, root ); //Rely on the parent closing the stream. //writer.Close(); @@ -589,14 +721,14 @@ namespace lib //lib.log.info( "Serialize END ( Stream stream, object root ) {0} {1}", m_rndVal, m_alreadySerialized.Count ); } - private void Serialize( XmlWriter writer, object root ) + private void Serialize( XmlWriter writer, MemberInfo mi, object root ) { //writer.WriteStartDocument(); - Serialize( writer, root, "root", true ); + Serialize( writer, mi, root, "root", true ); //writer.WriteEndDocument(); } - private void Serialize( XmlWriter writer, object root, string name, bool forceType ) + private void Serialize( XmlWriter writer, MemberInfo mi, object root, string name, bool forceType ) { writer.WriteStartElement( name ); @@ -608,17 +740,17 @@ namespace lib if( typeCode != TypeCode.Object ) { - SerializeConcrete( writer, root, forceType ); + SerializeConcrete( writer, mi, root, forceType ); } else { if( !type.IsArray ) { - SerializeObject( writer, root ); + SerializeObject( writer, mi, root ); } else { - SerializeArray( writer, root ); + SerializeArray( writer, mi, root ); } } } @@ -630,7 +762,7 @@ namespace lib writer.WriteEndElement(); } - private void SerializeConcrete( XmlWriter writer, object root, bool forceType ) + private void SerializeConcrete( XmlWriter writer, MemberInfo mi, object root, bool forceType ) { //TODO: Only write this out if debugging. if( forceType ) @@ -640,7 +772,7 @@ namespace lib writer.WriteAttributeString( "v", root.ToString() ); } - private void SerializeObject( XmlWriter writer, object root ) + private void SerializeObject( XmlWriter writer, MemberInfo mi, object root ) { writer.WriteAttributeString( "t", getTypeName( root.GetType() ) ); @@ -674,7 +806,12 @@ namespace lib Type type = root.GetType(); - //* + //var whitelistProp = type.GetCustomAttribute(); + + //var useWhitelist = whitelistProp != null; + + + //* Type typeISerializable = typeof(ISerializable); if( root is ISerializable ) // type.IsSubclassOf( typeISerializable ) ) @@ -693,7 +830,7 @@ namespace lib name = refl.TypeToIdentifier( name ); - Serialize( writer, serMember.Value, name, true ); + Serialize( writer, mi, serMember.Value, name, true ); } //var sc = new SerializationContext( @@ -703,31 +840,83 @@ namespace lib else //*/ { - var fields = refl.GetAllFields(type); + var doFields = true; + var doProperties = false; - //MemberInfo[] miArr = FormatterServices.GetSerializableMembers( type, Context ); + var filterFields = mi?.GetCustomAttribute() != null; + var filterProps = mi?.GetCustomAttribute() != null; - foreach( var childFi in fields ) + HashSet whitelistFields = new( mi?.GetCustomAttribute()?.Values ?? new string[0] ); + HashSet whitelistProps = new( mi?.GetCustomAttribute()?.Values ?? new string[0] ); + + if( type.GetCustomAttribute() != null ) { - - object[] objs = childFi.GetCustomAttributes(typeof(NonSerializedAttribute), true); - - if( objs.Length > 0 ) - { - continue; - } - - String name = childFi.Name; - - name = refl.TypeToIdentifier( name ); - - Serialize( writer, childFi.GetValue( root ), name, false ); + doProperties = true; } + + if( mi?.GetCustomAttribute() != null ) + { + doProperties = true; + + doFields = mi?.GetCustomAttribute() != null; + } + + //MemberInfo[] miArr = FormatterServices.GetSerializableMembers( type, Context ); + + if( doFields ) + { + var fields = refl.GetAllFields( type ); + + foreach( var childFi in fields ) + { + String name = childFi.Name; + + if( filterFields && !whitelistFields.Contains( name ) ) continue; + + + object[] objs = childFi.GetCustomAttributes( typeof( NonSerializedAttribute ), true ); + + if( objs.Length > 0 ) + { + continue; + } + + //if( childFi.GetCustomAttribute() ) + + name = refl.TypeToIdentifier( name ); + + Serialize( writer, childFi, childFi.GetValue( root ), name, false ); + } + } + + if( doProperties ) + { + var props = refl.GetAllProperties( type ); + + foreach( var childPi in props ) + { + String name = childPi.Name; + + if( filterProps && !whitelistProps.Contains( name ) ) continue; + + object[] objs = childPi.GetCustomAttributes( typeof( NonSerializedAttribute ), true ); + + if( objs.Length > 0 ) + { + continue; + } + + name = refl.TypeToIdentifier( name ); + + Serialize( writer, childPi, childPi.GetValue( root ), name, false ); + } + } + } } } - private void SerializeArray( XmlWriter writer, object root ) + private void SerializeArray( XmlWriter writer, MemberInfo mi, object root ) { Array arr = (Array)root; @@ -756,10 +945,10 @@ namespace lib for( int i = 0; i < arr.Length; ++i ) { - Serialize( writer, arr.GetValue( i ), "i" + i.ToString(), false ); + Serialize( writer, mi, arr.GetValue( i ), "i" + i.ToString(), false ); } } - } + } #endregion }