sharplib/ser/XmlFormatter.cs

1095 lines
20 KiB
C#

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<int, object> m_alreadySerialized = new Dictionary<int, object>();
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<T> (Stream stream)
{
return (T) Deserialize (XmlReader.Create (stream), typeof (T));
}
public T Deserialize<T> (XmlReader reader)
{
return (T) Deserialize (reader, typeof (T), false);
}
public T Deserialize<T> (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<long, object> m_alreadyDeserialzied = new Dictionary<long, object>();
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();
}
}
}
/*
/// <summary>
///
/// </summary>
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<TType>( 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<length; ++i )
{
int val = reader.ReadInt32();
//m_fixups[ val ] = new Fixup( obj, fi );
if( fi != null )
{
m_fixupList.Add( new Fixup( val, array, i ) );
}
}
}
void readRef( StreamReader reader, object obj, FieldInfo fi )
{
int val = reader.ReadInt32();
//m_fixups[ val ] = new Fixup( obj, fi );
m_fixupList.Add( new Fixup( val, obj, fi ) );
}
void readInt( StreamReader reader, object obj, FieldInfo fi )
{
int val = reader.ReadInt32();
if( fi == null ) return;
if( !fi.FieldType.IsEnum )
{
fi.SetValue( obj, val );
}
else
{
object enumVal = Enum.Parse( fi.FieldType, val.ToString() );
fi.SetValue( obj, Convert.ChangeType( enumVal, fi.FieldType ) );
}
}
void readSingle( StreamReader reader, object obj, FieldInfo fi )
{
float val = reader.ReadSingle();
if( fi == null ) return;
fi.SetValue( obj, val );
}
void readDouble( StreamReader reader, object obj, FieldInfo fi )
{
double val = reader.ReadDouble();
if( fi == null ) return;
fi.SetValue( obj, val );
}
void readChar( StreamReader reader, object obj, FieldInfo fi )
{
char val = reader.ReadChar();
if( fi == null ) return;
fi.SetValue( obj, val );
}
void readString( StreamReader reader, object obj, FieldInfo fi )
{
string val = reader.ReadString();
if( fi == null ) return;
fi.SetValue( obj, val );
}
void readBool( StreamReader reader, object obj, FieldInfo fi )
{
bool val = reader.ReadBoolean();
if( fi == null ) return;
fi.SetValue( obj, val );
}
#endregion Deserialize
}
*/
//}