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.Collections; //using System.Diagnostics; //using System.Globalization; //using System.ComponentModel; namespace lib { //Old, use 2 now. class XmlFormatter : IFormatter { StreamingContext m_context; //SerializationMode m_mode; //KnownTypeCollection known_types; //IDataContractSurrogate m_surrogate; //int m_maxItems; public XmlFormatter() { } /* public XmlFormatter( SerializationMode mode ) { m_mode = mode; } public XmlFormatter( StreamingContext context ) { m_context = context; } public XmlFormatter( SerializationMode mode, StreamingContext context ) { m_mode = mode; m_context = context; } */ //public XmlFormatter (SerializationMode mode, // StreamingContext context, KnownTypeCollection knownTypes) //{ //} SerializationBinder IFormatter.Binder { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } ISurrogateSelector IFormatter.SurrogateSelector { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public StreamingContext Context { get { return m_context; } set { m_context = value; } } /* public KnownTypeCollection KnownTypes { get { return known_types; } } public int MaxItemsInObjectGraph { get { return m_maxItems; } set { m_maxItems= value; } } */ object IFormatter.Deserialize( Stream stream ) { return Deserialize( stream, null ); } public object Deserialize( Stream stream, Type type ) { XmlTextReader reader = new XmlTextReader( stream ); return Deserialize( reader, type ); } public object Deserialize( XmlReader reader, Type type ) { return Deserialize( reader, type, false ); } public object Deserialize( XmlReader reader, Type type, bool readContentOnly ) { reader.Read(); XmlDocument doc = new XmlDocument(); doc.Load( reader ); return Deserialize( doc.DocumentElement ); } ConstructorInfo getNoParamCons( ConstructorInfo[] ciArr ) { foreach( ConstructorInfo ci in ciArr ) { if( ci.GetParameters().Length == 0 ) { return ci; } } return null; } private static FormatterConverter s_conv = new FormatterConverter(); private Dictionary m_alreadySerialized = new Dictionary(); public object Deserialize( XmlElement elem ) { string strType = elem.GetAttribute( "t" ); return Deserialize( elem, strType ); } public object Deserialize( XmlElement elem, string strType ) { Type type = Type.GetType( strType ); MemberInfo[] miArr = FormatterServices.GetSerializableMembers( type ); object obj = Activator.CreateInstance( type ); /* object obj = FormatterServices.GetUninitializedObject( type ); ConstructorInfo[] ciArr = obj.GetType().GetConstructors(); ConstructorInfo ci = getNoParamCons( ciArr ); if( ci == null ) return null; obj = ci.Invoke( null ); */ for( int i = 0; i < miArr.Length; ++i ) { FieldInfo fi = (FieldInfo)miArr[ i ]; XmlNodeList nodeList = elem.GetElementsByTagName( fi.Name ); if( nodeList.Count == 1 ) { Type t = fi.FieldType; TypeCode tc = Type.GetTypeCode( t ); XmlElement child = (XmlElement)nodeList[ 0 ]; object childObj = null; if( tc != TypeCode.Object || fi.FieldType.FullName == "System.String" ) { childObj = s_conv.Convert( child.GetAttribute( "v" ), fi.FieldType ); } else { if( !t.IsArray ) { string refStr = child.GetAttribute( "ref" ); int refInt = Convert.ToInt32( refStr ); if( child.HasAttribute( "t" ) ) { childObj = Deserialize( child ); m_alreadySerialized[refInt] = childObj; } else { childObj = m_alreadySerialized[refInt]; } } else { //FormatterServices.GetUninitializedObject() int length = s_conv.ToInt32( child.GetAttribute( "c" ) ); string elemType = child.GetAttribute( "t" ); Array arr = Array.CreateInstance( t.GetElementType(), length ); XmlNodeList arrNodeList = child.ChildNodes; for( int iElems = 0; iElems < arr.Length; ++iElems ) { XmlElement arrElem = (XmlElement)arrNodeList.Item( iElems ); arr.SetValue( Deserialize( arrElem, elemType ), iElems ); } } } fi.SetValue( obj, childObj ); } else { if( nodeList.Count == 0 ) { // Should be //object obj2 = fi.GetRawConstantValue(); } else //More than 1. { //Log.error( "Too many fields named the same thing" ); } } } //FieldInfo fi = (FieldInfo)miArr[0]; //ConstructorInfo ci = fi.FieldType.TypeInitializer; //ci.Invoke( null ); return obj; } /* public T Deserialize (Stream stream) { return (T) Deserialize (XmlReader.Create (stream), typeof (T)); } public T Deserialize (XmlReader reader) { return (T) Deserialize (reader, typeof (T), false); } public T Deserialize (XmlReader reader, bool readContentOnly) { return (T) Deserialize (reader, typeof (T), readContentOnly); } */ public void Serialize( Stream stream, object graph ) { /* XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; Serialize( XmlWriter.Create( stream, settings ), graph ); */ XmlTextWriter writer = new XmlTextWriter( stream, null ); writer.Formatting = Formatting.Indented; Serialize( writer, graph ); writer.Close(); } public void Serialize( XmlWriter writer, object graph ) { Serialize( writer, graph, null, true, false, true ); } public void Serialize( XmlWriter writer, object graph, Type rootType, bool preserveObjectReferences, bool writeContentOnly, bool ignoreUnknownSerializationData ) { Type t = graph.GetType(); //writer.WriteStartDocument(); if( Type.GetTypeCode( t ) == TypeCode.Object ) { writer.WriteStartElement( "root" ); Assembly assem = t.Assembly; string assemName = assem.GetName().Name; writer.WriteAttributeString( "t", graph.GetType().FullName + ", " + assemName ); FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly ); foreach( FieldInfo fi in fiArr ) { Serialize( writer, fi.Name, fi.GetValue( graph ) ); /* if( fi.FieldType.IsClass ) { Serialize( writer, fi.GetValue( graph ), rootType, preserveObjectReferences, writeContentOnly, ignoreUnknownSerializationData ); } else { SerializePod( writer, fi.GetValue( graph ) ); } */ } writer.WriteEndElement(); } //writer.WriteEndDocument(); } private ObjectIDGenerator m_idGenerator = new ObjectIDGenerator(); private Dictionary m_alreadyDeserialzied = new Dictionary(); public void Serialize( XmlWriter writer, string name, object obj ) { writer.WriteStartElement( name ); if( obj != null ) { Type t = obj.GetType(); if( Type.GetTypeCode( t ) == TypeCode.Object ) { bool first = false; if( !m_alreadyDeserialzied.ContainsKey( m_idGenerator.GetId( obj, out first ) ) ) { m_alreadyDeserialzied[m_idGenerator.GetId( obj, out first )] = obj; Assembly assem = t.Assembly; string assemName = assem.GetName().Name; if( !t.IsArray ) { writer.WriteAttributeString( "t", t.FullName + ", " + assemName ); writer.WriteAttributeString( "ref", m_idGenerator.GetId( obj, out first ).ToString() ); FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public ); foreach( FieldInfo fi in fiArr ) { Serialize( writer, fi.Name, fi.GetValue( obj ) ); } } else { Array arr = (Array)obj; Type aType = t.GetElementType(); string aTypeString = aType.FullName; writer.WriteAttributeString( "t", aTypeString + ", " + assemName ); writer.WriteAttributeString( "c", arr.Length.ToString() ); for( int i = 0; i < arr.Length; ++i ) { Serialize( writer, "val", arr.GetValue( i ) ); } //writer.WriteStartElement( "values" ); //writer.WriteEndElement(); } } else { writer.WriteAttributeString( "ref", m_idGenerator.GetId( obj, out first ).ToString() ); } } else { writer.WriteAttributeString( "t", t.FullName ); writer.WriteAttributeString( "v", obj.ToString() ); } } else { writer.WriteAttributeString( "null", "" ); } writer.WriteEndElement(); } } } /* /// /// /// public class XmlFormatter : IFormatter { public enum ETypes { Array, Int32, Ref, Object, EndObject, Single, Double, Char, String, Boolean, EndStream, } public XmlFormatter() { // // TODO: Add constructor logic here // } #region Useless public ISurrogateSelector SurrogateSelector { get { return null; } set { } } public SerializationBinder Binder { get { return null; } set { } } public StreamingContext Context { get { return new StreamingContext(); } set { } } #endregion Useless Queue m_objectsToBeDeserialized = new Queue(); Hashtable m_alreadyDeserialzied = new Hashtable(); //int m_GUID = 0; #region Serialize public void Serialize( System.IO.Stream stream, object obj ) { //Default is 4k //BufferedStream bufStream = new BufferedStream( stream ); TextWriter writer = new StreamWriter( stream ); writeObject( writer, obj ); while( m_objectsToBeDeserialized.Count != 0 ) { object objToDes = m_objectsToBeDeserialized.Dequeue(); writeObject( writer, objToDes ); } writer.Write( (char)ETypes.EndStream ); } void writeRefAndSched( TextWriter writer, object obj ) { //if( m_alreadyDeserialzied[ obj.GetType().GetArrayRank( if( obj == null ) { writer.Write( 0 ); return; } //Now write the address. //Bad bad. Need to do this correctly. int objRef = obj.GetHashCode(); writer.Write( objRef ); if( m_alreadyDeserialzied[ obj ] == null ) { m_alreadyDeserialzied[ obj ] = obj; m_objectsToBeDeserialized.Enqueue( obj ); } } void dispatchWrite( TextWriter writer, object parentObj, FieldInfo fi ) { string typeName = fi.FieldType.Name; string name = fi.Name; if( fi.IsNotSerialized ) { return; } if( fi.FieldType.IsArray ) { writer.Write( (char)ETypes.Array ); writer.Write( name.GetHashCode() ); writeArray( writer, (Array)fi.GetValue( parentObj ) ); } else if( ( fi.FieldType.IsClass || fi.FieldType.IsInterface ) && typeName != "String" ) { writer.Write( (char)ETypes.Ref ); writer.Write( name.GetHashCode() ); writeRefAndSched( writer, fi.GetValue( parentObj ) ); } else if( fi.FieldType.IsEnum ) { writer.Write( (char)ETypes.Int32 ); writer.Write( name.GetHashCode() ); writer.Write( Convert.ToInt32( fi.GetValue( parentObj ) ) ); } else { switch( typeName ) { case "Int32": writer.Write( (char)ETypes.Int32 ); writer.Write( name.GetHashCode() ); writer.Write( Convert.ToInt32( fi.GetValue( parentObj ) ) ); break; case "Single": writer.Write( (char)ETypes.Single ); writer.Write( name.GetHashCode() ); writer.Write( Convert.ToSingle( fi.GetValue( parentObj ) ) ); break; case "Double": writer.Write( (char)ETypes.Double ); writer.Write( name.GetHashCode() ); writer.Write( Convert.ToDouble( fi.GetValue( parentObj ) ) ); break; case "Char": writer.Write( (char)ETypes.Char ); writer.Write( name.GetHashCode() ); writer.Write( Convert.ToChar( fi.GetValue( parentObj ) ) ); break; case "String": writer.Write( (char)ETypes.String ); writer.Write( name.GetHashCode() ); writer.Write( Convert.ToString( fi.GetValue( parentObj ) ) ); break; case "Boolean": writer.Write( (char)ETypes.Boolean ); writer.Write( name.GetHashCode() ); writer.Write( Convert.ToBoolean( fi.GetValue( parentObj ) ) ); break; default: Console.WriteLine( "VersionFormatter does not understand type " + typeName ); break; } } } void writeArray( TextWriter writer, Array array ) { if( array == null ) { writer.Write( (int)-1 ); return; } writer.Write( array.Length ); foreach( object obj in array ) { writeRefAndSched( writer, obj ); } } void getAllFields( object obj, ArrayList list ) { Type t = obj.GetType(); while( t != null ) { FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly ); list.AddRange( fiArr ); t = t.BaseType; } } void writeObject( TextWriter writer, object obj ) { Type objType = obj.GetType(); writer.Write( (char)ETypes.Object ); writer.Write( objType.FullName ); int objRef = obj.GetHashCode(); writer.Write( objRef ); ArrayList list = new ArrayList(); getAllFields( obj, list ); foreach( FieldInfo fi in list ) { dispatchWrite( writer, obj, fi ); } writer.Write( (char)ETypes.EndObject ); } void write( TextWriter wr, TType val ) { //wr.Write( val ); } /* void writeInt( TextWriter writer, int val ) { writer.Write( val ); } void writeSingle( TextWriter writer, float val ) { writer.Write( val ); } void writeDouble( TextWriter writer, double val ) { writer.Write( val ); } void writeChar( TextWriter writer, char val ) { writer.Write( val ); } void writeString( TextWriter writer, string val ) { writer.Write( val ); } void writeBool( TextWriter writer, bool val ) { writer.Write( val ); } * / #endregion Serialize #region Deserialize class Fixup { public Fixup( int guid, object obj, FieldInfo fi ) { m_guid= guid; m_obj = obj; m_fi = fi; } XmlFormatter public Fixup( int guid, object obj, int index ) { m_guid = guid; m_obj = obj; m_index= index; } public readonly int m_guid = 0; public readonly object m_obj = null; public readonly FieldInfo m_fi = null; public readonly int m_index= -1; } Hashtable m_mapGUIDToObject = new Hashtable(); ArrayList m_fixupList = new ArrayList(); ArrayList m_desObjects = new ArrayList(); public object Deserialize( System.IO.Stream stream ) { StreamReader reader = new StreamReader( stream ); object objRoot = null; //Read in the first object. { ETypes type = (ETypes)reader.ReadChar(); Debug.Assert( type == ETypes.Object ); objRoot = readObject( reader ); m_desObjects.Add( objRoot ); } bool readObjects = true; while( readObjects ) { ETypes type = (ETypes)reader.ReadChar(); Debug.Assert( type == ETypes.Object || type == ETypes.EndStream ); if( type == ETypes.Object ) { object obj = readObject( reader ); m_desObjects.Add( obj ); } else { Debug.Assert( type == ETypes.EndStream ); readObjects = false; } } foreach( Fixup fu in m_fixupList ) { //Fixup fix = m_fixups[ object obj = m_mapGUIDToObject[ fu.m_guid ]; if( obj != null ) { if( fu.m_fi != null ) { fu.m_fi.SetValue( fu.m_obj, obj ); } else { Debug.Assert( fu.m_index >= 0 ); object []array = (object [])fu.m_obj; array[ fu.m_index ] = obj; } } else { Console.WriteLine( "Obj to ref is null." ); } } foreach( object obj in m_desObjects ) { if( typeof( IDeserializationCallback ).IsAssignableFrom( obj.GetType() ) ) { IDeserializationCallback desCB = (IDeserializationCallback)obj; if( desCB != null ) { desCB.OnDeserialization( this ); } } } return objRoot; } bool dispatchRead( StreamReader reader, object obj, Hashtable ht ) { //Read the type ETypes type = (ETypes)reader.ReadChar(); if( type == ETypes.EndObject ) { return false; } int nameHash = reader.ReadInt32(); FieldInfo fi = (FieldInfo)ht[ nameHash ]; if( fi == null ) { Console.WriteLine( "Field no longer exists" ); } try { switch( type ) { case ETypes.Array: readArray( reader, obj, fi ); break; case ETypes.Int32: readInt( reader, obj, fi ); break; case ETypes.Single: readSingle( reader, obj, fi ); break; case ETypes.Double: readDouble( reader, obj, fi ); break; case ETypes.Char: readChar( reader, obj, fi ); break; case ETypes.Boolean: readBool( reader, obj, fi ); break; case ETypes.String: readString( reader, obj, fi ); break; case ETypes.Ref: readRef( reader, obj, fi ); break; case ETypes.Object: readObject( reader ); break; default: Debug.Fail( "Unknown type on read." ); break; } } catch( Exception ex ) { Console.WriteLine( "Exception: " + ex.Message ); Console.WriteLine( "Stack: " + ex.StackTrace ); } return true; } object createObject( string objTypeName ) { Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); foreach( Assembly a in ass ) { Type t = a.GetType( objTypeName ); if( t != null ) { object obj = FormatterServices.GetUninitializedObject( t ); if( obj != null ) { return obj; } } } return null; } object readObject( StreamReader reader ) { //ETypes type = (ETypes)reader.ReadChar(); //Debug.Assert( type == ETypes.Object, "Expecting type Object" ); string objTypeName = reader.ReadString(); int objGUID = reader.ReadInt32(); try { object obj = createObject( objTypeName ); m_mapGUIDToObject[ objGUID ] = obj; ArrayList list = new ArrayList(); Hashtable ht = new Hashtable(); if( obj != null ) { getAllFields( obj, list ); foreach( FieldInfo fi in list ) { ht[ fi.Name.GetHashCode() ] = fi; } } while( dispatchRead( reader, obj, ht ) ) { } return obj; } catch( Exception ex ) { Console.WriteLine( "Exception: " + ex.Message ); } return null; } void readArray( StreamReader reader, object obj, FieldInfo fi ) { int length = reader.ReadInt32(); if( length < 0 ) { if( fi == null ) return; fi.SetValue( obj, null ); return; } object[] array = new object[length]; if( fi != null ) { fi.SetValue( obj, array ); } for( int i=0; i