using System;
using System.Text;
using System.Xml;
using System.Reflection;
using System.Drawing;
using System.ComponentModel;
#if DOTNETBAR
namespace DevComponents.DotNetBar
#else
namespace DevComponents.Tree
#endif
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field)]
public class DevCoSerialize : Attribute
{
public DevCoSerialize(){}
}
///
/// Represents class that can serialize compatible marked properties.
///
public class ElementSerializer
{
private static string XmlImageName="image";
private static string XmlIconName="icon";
private static string XmlAttributeName="name";
// private static string XmlCollectionName="collection";
// private static string XmlTypeName="type";
// private static string XmlObjectName="object";
public static void Serialize(object element, XmlElement xmlElem)
{
PropertyInfo[] propInfo = element.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo prop in propInfo)
{
if (prop.GetCustomAttributes(typeof(DevCoSerialize), true).Length > 0)
{
// Check whether property needs to be serialized
object[] attributesDefaultValue=prop.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attributesDefaultValue.Length > 0)
{
DefaultValueAttribute att=attributesDefaultValue[0] as DefaultValueAttribute;
object propertyValue = prop.GetValue(element, null);
if(propertyValue==att.Value)
continue;
if(propertyValue!=null && att.Value!=null && propertyValue.Equals(att.Value))
continue;
}
else if(element.GetType().GetMethod("ShouldSerialize" + prop.Name,BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)!=null)
{
MethodInfo mi=element.GetType().GetMethod("ShouldSerialize" + prop.Name,BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
object result=mi.Invoke(element,null);
if(result is bool && !((bool)result))
continue;
}
string attributeName=XmlConvert.EncodeName(prop.Name);
Type t=prop.PropertyType;
if (t.IsPrimitive || t == typeof(string) || t.IsEnum)
{
if (t == typeof(string))
xmlElem.SetAttribute(attributeName, prop.GetValue(element, null).ToString());
else if (t.IsEnum)
{
xmlElem.SetAttribute(attributeName, Enum.Format(t, prop.GetValue(element, null), "g"));
}
else if (t == typeof(bool))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((bool)prop.GetValue(element, null)));
else if (t == typeof(Int32))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((Int32)prop.GetValue(element, null)));
else if (t == typeof(double))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((double)prop.GetValue(element, null)));
else if (t == typeof(float))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((float)prop.GetValue(element, null)));
else if (t == typeof(Int16))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((Int16)prop.GetValue(element, null)));
else if (t == typeof(Int64))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((Int64)prop.GetValue(element, null)));
else if (t == typeof(byte))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((byte)prop.GetValue(element, null)));
else if (t == typeof(char))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((char)prop.GetValue(element, null)));
else if (t == typeof(decimal))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((decimal)prop.GetValue(element, null)));
else if (t == typeof(Guid))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((Guid)prop.GetValue(element, null)));
else if (t == typeof(sbyte))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((sbyte)prop.GetValue(element, null)));
else if (t == typeof(TimeSpan))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((TimeSpan)prop.GetValue(element, null)));
else if (t == typeof(ushort))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((ushort)prop.GetValue(element, null)));
else if (t == typeof(uint))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((uint)prop.GetValue(element, null)));
else if (t == typeof(ulong))
xmlElem.SetAttribute(attributeName, XmlConvert.ToString((ulong)prop.GetValue(element, null)));
else
throw new ApplicationException("Unsupported serialization type '" + t.ToString() + "' on property '" + attributeName + "'");
}
else if (t == typeof(Color))
xmlElem.SetAttribute(attributeName, ColorToString((Color)prop.GetValue(element, null)));
else if (t == typeof(Image))
{
XmlElement imageXmlElement = xmlElem.OwnerDocument.CreateElement(XmlImageName);
imageXmlElement.SetAttribute(XmlAttributeName, attributeName);
xmlElem.AppendChild(imageXmlElement);
SerializeImage((Image)prop.GetValue(element, null), imageXmlElement);
}
else if (t == typeof(Icon))
{
XmlElement imageXmlElement = xmlElem.OwnerDocument.CreateElement(XmlIconName);
imageXmlElement.SetAttribute(XmlAttributeName, attributeName);
xmlElem.AppendChild(imageXmlElement);
SerializeIcon((Icon)prop.GetValue(element, null), imageXmlElement);
}
else if (t == typeof(Font))
{
xmlElem.SetAttribute(attributeName, FontToString((Font)prop.GetValue(element, null)));
}
else
throw new ApplicationException("Unsupported serialization type '" + t.ToString() + "'" + "' on property '" + attributeName + "'");
}
}
}
private static string ColorToString(Color clr)
{
if (clr.IsSystemColor || clr.IsNamedColor || clr.IsKnownColor)
return ("." + clr.Name);
else
return clr.ToArgb().ToString();
}
private static Color ColorFromString(string sclr)
{
if (sclr == "")
return Color.Empty;
if (sclr[0] == '.')
return Color.FromName(sclr.Substring(1));
else
return Color.FromArgb(System.Xml.XmlConvert.ToInt32(sclr));
}
private static string FontToString(Font font)
{
if (font == null)
return "";
string s = font.Name + "," + XmlConvert.ToString(font.Size) + "," + XmlConvert.ToString(font.Bold) + "," + XmlConvert.ToString(font.Italic) + "," +
XmlConvert.ToString(font.Underline) + "," + XmlConvert.ToString(font.Strikeout);
return s;
}
private static Font FontFromString(string fontString)
{
if(fontString=="")
return null;
string[] options=fontString.Split(',');
FontStyle fontStyle = FontStyle.Regular;
if (XmlConvert.ToBoolean(options[2]))
fontStyle |= FontStyle.Bold;
if (XmlConvert.ToBoolean(options[3]))
fontStyle |= FontStyle.Italic;
if (XmlConvert.ToBoolean(options[4]))
fontStyle |= FontStyle.Underline;
if (XmlConvert.ToBoolean(options[5]))
fontStyle |= FontStyle.Strikeout;
Font font = new Font(options[0], XmlConvert.ToSingle(options[1]), fontStyle);
return font;
}
public static void Deserialize(object element, XmlElement xmlElem)
{
Type type=element.GetType();
foreach(XmlAttribute att in xmlElem.Attributes)
{
string name=XmlConvert.DecodeName(att.Name);
PropertyInfo prop=type.GetProperty(name);
if(prop!=null)
{
Type t=prop.PropertyType;
if (t.IsPrimitive)
{
if(t==typeof(bool))
prop.SetValue(element, XmlConvert.ToBoolean(att.Value), null);
else if (t == typeof(Int32))
prop.SetValue(element, XmlConvert.ToInt32(att.Value), null);
else if (t == typeof(double))
prop.SetValue(element, XmlConvert.ToDouble(att.Value), null);
else if (t == typeof(float))
prop.SetValue(element, XmlConvert.ToSingle(att.Value), null);
else if (t == typeof(Int16))
prop.SetValue(element, XmlConvert.ToInt16(att.Value), null);
else if (t == typeof(Int64))
prop.SetValue(element, XmlConvert.ToInt64(att.Value), null);
else if (t == typeof(byte))
prop.SetValue(element, XmlConvert.ToByte(att.Value), null);
else if (t == typeof(char))
prop.SetValue(element, XmlConvert.ToChar(att.Value), null);
else if (t == typeof(decimal))
prop.SetValue(element, XmlConvert.ToDecimal(att.Value), null);
else if (t == typeof(Guid))
prop.SetValue(element, XmlConvert.ToGuid(att.Value), null);
else if (t == typeof(sbyte))
prop.SetValue(element, XmlConvert.ToSByte(att.Value), null);
else if (t == typeof(TimeSpan))
prop.SetValue(element, XmlConvert.ToTimeSpan(att.Value), null);
else if (t == typeof(ushort))
prop.SetValue(element, XmlConvert.ToUInt16(att.Value), null);
else if (t == typeof(uint))
prop.SetValue(element, XmlConvert.ToUInt32(att.Value), null);
else if (t == typeof(ulong))
prop.SetValue(element, XmlConvert.ToUInt64(att.Value), null);
}
else if (t == typeof(string))
prop.SetValue(element, att.Value, null);
else if (t.IsEnum)
prop.SetValue(element, Enum.Parse(t, att.Value), null);
else if (t == typeof(Color))
prop.SetValue(element, ColorFromString(att.Value), null);
else if (t == typeof(Font))
prop.SetValue(element, FontFromString(att.Value), null);
}
}
foreach(XmlElement childElem in xmlElem.ChildNodes)
{
if (childElem.Name == XmlImageName)
{
string name = XmlConvert.DecodeName(childElem.GetAttribute(XmlAttributeName));
PropertyInfo prop = type.GetProperty(name);
if (prop != null)
{
prop.SetValue(element, DeserializeImage(childElem), null);
}
}
else if (childElem.Name == XmlIconName)
{
string name = XmlConvert.DecodeName(childElem.GetAttribute(XmlAttributeName));
PropertyInfo prop = type.GetProperty(name);
if (prop != null)
{
prop.SetValue(element, DeserializeIcon(childElem), null);
}
}
}
}
public static void SerializeImage(System.Drawing.Image image,XmlElement xml)
{
if(image==null)
return;
System.IO.MemoryStream mem=new System.IO.MemoryStream(1024);
// TODO: Beta 2 issue with the ImageFormat. RawFormat on image object does not return the actual image format
// Right now it is hard coded to PNG but in final version we should get the original image format
image.Save(mem,System.Drawing.Imaging.ImageFormat.Png);
System.Text.StringBuilder sb=new System.Text.StringBuilder();
System.IO.StringWriter sw=new System.IO.StringWriter(sb);
System.Xml.XmlTextWriter xt=new System.Xml.XmlTextWriter(sw);
xt.WriteBase64(mem.GetBuffer(),0,(int)mem.Length);
xml.InnerText=sb.ToString();
}
public static void SerializeIcon(System.Drawing.Icon icon, XmlElement xml)
{
if(icon==null)
return;
System.IO.MemoryStream mem=new System.IO.MemoryStream(1024);
// TODO: Beta 2 issue with the ImageFormat. RawFormat on image object does not return the actual image format
// Right now it is hard coded to PNG but in final version we should get the original image format
icon.Save(mem);
System.Text.StringBuilder sb=new System.Text.StringBuilder();
System.IO.StringWriter sw=new System.IO.StringWriter(sb);
System.Xml.XmlTextWriter xt=new System.Xml.XmlTextWriter(sw);
xml.SetAttribute("encoding","binhex");
//xt.WriteBase64(mem.GetBuffer(),0,(int)mem.Length);
xt.WriteBinHex(mem.GetBuffer(),0,(int)mem.Length);
xml.InnerText=sb.ToString();
}
///
/// XML element is expected to be something like Image data Base64 encoded
///
/// Image data
///
public static System.Drawing.Image DeserializeImage(XmlElement xml)
{
System.Drawing.Image img=null;
if(xml==null || xml.InnerText=="")
return null;
System.IO.StringReader sr=new System.IO.StringReader(xml.OuterXml);
System.Xml.XmlTextReader xr= new System.Xml.XmlTextReader(sr);
System.IO.MemoryStream mem=new System.IO.MemoryStream(1024);
// Skip to data
xr.Read();
byte[] base64 = new byte[1024];
int base64len = 0;
do
{
base64len = xr.ReadBase64(base64, 0, 1024);
if(base64len>0)
mem.Write(base64,0,base64len);
} while (base64len!=0);
img=System.Drawing.Image.FromStream(mem);
return img;
}
public static System.Drawing.Icon DeserializeIcon(XmlElement xml)
{
System.Drawing.Icon img=null;
if(xml==null || xml.InnerText=="")
return null;
bool bDecodeBinHex=false;
if(xml.HasAttribute("encoding") && xml.GetAttribute("encoding")=="binhex")
bDecodeBinHex=true;
System.IO.StringReader sr=new System.IO.StringReader(xml.OuterXml);
System.Xml.XmlTextReader xr= new System.Xml.XmlTextReader(sr);
System.IO.MemoryStream mem=new System.IO.MemoryStream(1024);
// Skip to data
xr.Read();
byte[] base64 = new byte[1024];
int base64len = 0;
if(bDecodeBinHex)
{
do
{
base64len = xr.ReadBinHex(base64, 0, 1024);
if(base64len>0)
mem.Write(base64,0,base64len);
} while (base64len!=0);
}
else
{
do
{
base64len = xr.ReadBase64(base64, 0, 1024);
if(base64len>0)
mem.Write(base64,0,base64len);
} while (base64len!=0);
}
mem.Position=0;
img=new System.Drawing.Icon(mem);
return img;
}
}
}