diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index cc57fd7d..07413fc3 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -250,7 +250,7 @@ namespace Vocaluxe.Base private static void _LoadConfig() { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); Config = xml.Deserialize(_FileConfig); if (Config.Game.SongFolder.Length > 0) diff --git a/Vocaluxe/Base/Fonts/CFonts.cs b/Vocaluxe/Base/Fonts/CFonts.cs index 31f3e1f8..b0ab10d8 100644 --- a/Vocaluxe/Base/Fonts/CFonts.cs +++ b/Vocaluxe/Base/Fonts/CFonts.cs @@ -260,7 +260,7 @@ namespace Vocaluxe.Base.Fonts SDefaultFonts defaultFonts; try { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); defaultFonts = xml.Deserialize(Path.Combine(CSettings.ProgramFolder, CSettings.FolderNameFonts, CSettings.FileNameFonts)); } catch (Exception e) diff --git a/Vocaluxe/Base/ThemeSystem/CTheme.cs b/Vocaluxe/Base/ThemeSystem/CTheme.cs index 631e234b..94c9433f 100644 --- a/Vocaluxe/Base/ThemeSystem/CTheme.cs +++ b/Vocaluxe/Base/ThemeSystem/CTheme.cs @@ -69,7 +69,7 @@ namespace Vocaluxe.Base.ThemeSystem { try { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); _Data = xml.Deserialize(Path.Combine(_Folder, _FileName)); if (_Data.ThemeSystemVersion != _ThemeSystemVersion) { diff --git a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs index 941aec2d..77fc2b06 100644 --- a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs +++ b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs @@ -60,10 +60,10 @@ namespace Vocaluxe.Lib.Playlist File = CHelper.GetUniqueFileName(Path.Combine(CSettings.DataFolder, CConfig.FolderPlaylists), filename + ".xml"); } - SPlaylist data=new SPlaylist {Info = {Name = Name}, Songs = Songs.Select(plSong => plSong.ToStruct()).ToArray()}; + SPlaylist data = new SPlaylist {Info = {Name = Name}, Songs = Songs.Select(plSong => plSong.ToStruct()).ToArray()}; var xml = new CXmlSerializer(); - xml.Serialize(File,data); + xml.Serialize(File, data); } public bool _Load(string file) @@ -72,17 +72,17 @@ namespace Vocaluxe.Lib.Playlist SPlaylist data; try { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); data = xml.Deserialize(File); } catch (Exception e) { - CLog.LogError("Cannot load playlist from "+file+": "+e.Message); + CLog.LogError("Cannot load playlist from " + file + ": " + e.Message); return false; } Name = data.Info.Name; Songs = new List(); - foreach (var songEntry in data.Songs) + foreach (SPlaylistSong songEntry in data.Songs) { CSong plSong = CSongs.AllSongs.FirstOrDefault(song => song.Artist == songEntry.Artist && song.Title == songEntry.Title); if (plSong == null) diff --git a/VocaluxeLib/Profile/CProfile.cs b/VocaluxeLib/Profile/CProfile.cs index 90923767..8b769564 100644 --- a/VocaluxeLib/Profile/CProfile.cs +++ b/VocaluxeLib/Profile/CProfile.cs @@ -89,7 +89,7 @@ namespace VocaluxeLib.Profile public bool LoadProfile() { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); try { xml.Deserialize(FilePath, this); @@ -106,11 +106,12 @@ namespace VocaluxeLib.Profile private bool _ConvertProfile(ref Exception e) { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); + var ser = new CXmlSerializer(); try { var old = xml.Deserialize(FilePath); - string newXml = xml.Serialize(old.Info); + string newXml = ser.Serialize(old.Info); xml.DeserializeString(newXml, this); } catch (Exception e2) diff --git a/VocaluxeLib/Xml/CXmlDeserializer.cs b/VocaluxeLib/Xml/CXmlDeserializer.cs new file mode 100644 index 00000000..6b1beb59 --- /dev/null +++ b/VocaluxeLib/Xml/CXmlDeserializer.cs @@ -0,0 +1,389 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Xml; + +namespace VocaluxeLib.Xml +{ + public class CXmlDeserializer + { + #region Debug Helpers + private string _GetXPath(XmlNode node) + { + StringBuilder builder = new StringBuilder(); + while (node != null) + { + switch (node.NodeType) + { + case XmlNodeType.Attribute: + builder.Insert(0, "/@" + node.Name); + node = ((XmlAttribute)node).OwnerElement; + break; + case XmlNodeType.Element: + string index = _FindElementIndex(node); + builder.Insert(0, "/" + node.Name + index); + node = node.ParentNode; + break; + case XmlNodeType.Document: + return builder.ToString(); + default: + throw new ArgumentException("Only elements and attributes are supported"); + } + } + throw new ArgumentException("Node was not in a document"); + } + + private string _FindElementIndex(XmlNode element) + { + XmlNode parentNode = element.ParentNode; + if (parentNode is XmlDocument) + return ""; + XmlElement parent = (XmlElement)parentNode; + int index = 1; + if (parent != null) + { + XmlNode[] siblings = parent.ChildNodes.Cast().Where(candidate => candidate is XmlElement && candidate.Name == element.Name).ToArray(); + foreach (XmlNode candidate in siblings) + { + if (candidate == element) + return siblings.Length > 1 ? "[" + index + "]" : ""; + index++; + } + } + throw new ArgumentException("Couldn't find element within parent"); + } + #endregion Debug Helpers + + private object _GetValue(XmlNode node, Type type, string arrayItemName = null, object result = null) + { + if (type.IsEnum) + { + string stringValue = node.InnerText; + try + { + return Enum.Parse(type, stringValue); + } + catch (Exception) + { + throw new XmlException("Invalid value in " + _GetXPath(node)); + } + } + if (type == typeof(string)) + return node.InnerText; + if (type.IsPrimitive) + return _GetPrimitiveValue(node, type); + if (type.IsNullable()) + { + if (!node.HasChildNodes) + return null; + Type subType = type.GetGenericArguments()[0]; + return _GetValue(node, subType, arrayItemName, result); + } + if (type.IsList() || type.IsArray) + { + Type subType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0]; + String subName = arrayItemName ?? subType.GetTypeName(); + subName = subName.ToLowerInvariant(); + List subValues = new List(); + foreach (XmlNode subNode in node.ChildNodes) + { + if (subNode is XmlComment) + continue; + if (subName == subNode.Name.ToLowerInvariant() && !subNode.Name.ToLowerInvariant().StartsWith(subName)) + throw new XmlException("Invalid list entry '" + subNode.Name + "' in " + _GetXPath(node) + "; Expected: " + subName); + object subValue = _GetValue(subNode, subType); + subValues.Add(subValue); + } + if (result == null) + return _CreateList(type, subValues); + _FillList(result, type, subValues); + return result; + } + if (type.IsDictionary()) + { + Type subType = type.GetGenericArguments()[1]; + object dict = result ?? Activator.CreateInstance(type); + MethodInfo add = type.GetMethod("Add"); + if (arrayItemName != null) + arrayItemName = arrayItemName.ToLowerInvariant(); + foreach (XmlNode subNode in node.ChildNodes) + { + if (subNode is XmlComment) + continue; + object subValue = _GetValue(subNode, subType); + string subName; + if (arrayItemName != null) + { + if (arrayItemName != subNode.Name.ToLowerInvariant() && !subNode.Name.ToLowerInvariant().StartsWith(arrayItemName)) + throw new XmlException("Invalid dictionary entry '" + subNode.Name + "' in " + _GetXPath(node) + "; Expected: " + arrayItemName); + if (subNode.Attributes == null) + throw new XmlException("'name' attribute is missing in " + _GetXPath(subNode)); + XmlNode nameAtt = subNode.Attributes.GetNamedItem("name"); + if (nameAtt == null) + throw new XmlException("'name' attribute is missing in " + _GetXPath(subNode)); + subName = nameAtt.Value; + } + else + subName = subNode.Name; + add.Invoke(dict, new object[] { subName, subValue }); + } + return dict; + } + + object value; + try + { + value = result ?? Activator.CreateInstance(type); + } + catch (Exception) + { + throw new XmlException("Could not create instance of " + _GetXPath(node) + "(Type=" + type.Name + ")"); + } + _ReadChildNodes(node, ref value, true); + _ReadChildNodes(node, ref value, false); + return value; + } + + private object _GetPrimitiveValue(XmlNode node, Type type) + { + object value; + string nodeVal = node.InnerText; + try + { + int p = nodeVal.IndexOf(','); + if (p > 0 && p >= nodeVal.Length - 3) + { + CBase.Log.LogError("German number format converted to english in " + _GetXPath(node)); + char[] tmp = nodeVal.ToCharArray(); + tmp[p] = '.'; + nodeVal = new string(tmp); + } + value = Convert.ChangeType(nodeVal, type, CultureInfo.InvariantCulture); + } + catch (FormatException e) + { + throw new XmlException("Invalid format in " + _GetXPath(node) + ": '" + nodeVal + "' (" + e.Message + ")"); + } + catch (InvalidCastException e) + { + throw new XmlException(e.Message + " in " + _GetXPath(node) + ": '" + nodeVal + "'"); + } + return value; + } + + private static bool _CheckAndSetDefaultValue(object result, SFieldInfo field) + { + if (field.IsEmbeddedList) + { + _AddList(result, field, new List()); + return true; + } + if (!field.HasDefaultValue) + return false; + field.SetValue(result, field.DefaultValue); + return true; + } + + private static void _FillList(object list, Type type, ICollection values) + { + if (values.Count <= 0) + return; + if (type.IsArray) + { + Array array = (Array)list; + int i = 0; + foreach (object value in values) + array.SetValue(value, i++); + } + else + { + MethodInfo addMethod = type.GetMethod("Add"); + foreach (object value in values) + addMethod.Invoke(list, new object[] { value }); + } + } + + private static object _CreateList(Type type, ICollection values) + { + object list = type.IsArray ? Array.CreateInstance(type.GetElementType(), values.Count) : Activator.CreateInstance(type, new object[] { values.Count }); + _FillList(list, type, values); + return list; + } + + private static void _AddList(object result, SFieldInfo listField, ICollection list) + { + listField.SetValue(result, _CreateList(listField.Type, list)); + } + + private void _ReadChildNodes(XmlNode parent, ref object result, bool attributes) + { + IEnumerable nodes; + if (attributes) + nodes = parent.Attributes; + else + nodes = parent.ChildNodes; + + List fields = result.GetType().GetFields(attributes); + + if (nodes != null) + { + //Dictionary of all embedded lists to allow interleaved/mixed elements + Dictionary>> embLists = new Dictionary>>(); + foreach (XmlNode node in nodes) + { + if (node is XmlComment) + continue; + + SFieldInfo field = new SFieldInfo(); + int curField; + for (curField = 0; curField < fields.Count; curField++) + { + field = fields[curField]; + if (field.Name == node.Name || field.AltName == node.Name || (field.IsEmbeddedList && node.Name.StartsWith(field.Name))) + break; + } + if (curField >= fields.Count) + { + string msg = "Unexpected element: " + _GetXPath(node); + if (fields.Count > 0) + msg += " Expected: " + string.Join(", ", fields.Select(f => f.Name)); + throw new XmlException(msg); + } + + if (field.IsByteArray) + { + field.SetValue(result, Convert.FromBase64String(node.InnerText)); + fields.RemoveAt(curField); + } + else if (field.IsEmbeddedList) + { + Tuple> entry; + if (!embLists.TryGetValue(field.Name, out entry)) + { + entry = new Tuple>(field, new List()); + embLists.Add(field.Name, entry); + } + object subValue = _GetValue(node, field.SubType); + entry.Item2.Add(subValue); + } + else + { + object value = _GetValue(node, field.Type, field.ArrayItemName); + if (field.IsNormalized) + { + if (field.IsNullable && !((float?)value).Value.IsInRange(0, 1) || + !field.IsNullable && !((float)value).IsInRange(0, 1)) + throw new XmlException("Value in " + _GetXPath(node) + " is not normalized. (Value=" + value + ")"); + } + if (field.Ranged != null && value != null) + { + bool ok = false; + if (field.Type == typeof(int)) + ok = ((int)value).IsInRange(field.Ranged.Min, field.Ranged.Max); + else if (field.Type == typeof(float)) + ok = ((float)value).IsInRange(field.Ranged.Min, field.Ranged.Max); + else if (field.Type == typeof(double)) + ok = ((double)value).IsInRange(field.Ranged.Min, field.Ranged.Max); + else + Debug.Assert(false, "Ranged attribute has invalid type"); + if (!ok) + { + throw new XmlException("Value in " + _GetXPath(node) + " is not in the range " + field.Ranged.Min + "-" + field.Ranged.Max + ". (Value=" + value + + ")"); + } + } + field.SetValue(result, value); + fields.RemoveAt(curField); + } + } + //Add embedded lists + foreach (Tuple> entry in embLists.Values) + { + _AddList(result, entry.Item1, entry.Item2); + fields.Remove(entry.Item1); + } + } + foreach (SFieldInfo field in fields) + { + if (!_CheckAndSetDefaultValue(result, field)) + throw new XmlException("element: " + field.Name + " is missing in " + _GetXPath(parent)); + } + } + + + private T _Deserialize(XmlReader reader, object result) where T : new() + { + if (reader.IsEmptyElement) + return (T)result; + + XmlDocument xDoc = new XmlDocument(); + xDoc.Load(reader); + if (xDoc.DocumentElement == null) + throw new XmlException("No root element found!"); + try + { + result = _GetValue(xDoc.DocumentElement, typeof(T), typeof(T).GetSubTypeName(), result); + } + catch (TargetInvocationException e) + { + throw e.InnerException ?? e; + } + return (T)result; + } + + public T DeserializeString(string xml) where T : new() + { + return DeserializeString(xml, new T()); + } + + public T DeserializeString(string xml, T o) where T : new() + { + var reader = new XmlTextReader(new StringReader(xml)) + { + WhitespaceHandling = WhitespaceHandling.Significant, + Normalization = true, + XmlResolver = null + }; + try + { + return _Deserialize(reader, o); + } + finally + { + reader.Close(); + } + } + + public T Deserialize(string filePath) where T : new() + { + return Deserialize(filePath, new T()); + } + + public T Deserialize(string filePath, T o) where T : new() + { + if (!File.Exists(filePath)) + throw new FileNotFoundException(filePath); + var reader = new XmlTextReader(filePath) + { + WhitespaceHandling = WhitespaceHandling.Significant, + Normalization = true, + XmlResolver = null + }; + try + { + return _Deserialize(reader, o); + } + finally + { + reader.Close(); + } + } + + } +} diff --git a/VocaluxeLib/Xml/CXmlSerializer.cs b/VocaluxeLib/Xml/CXmlSerializer.cs index f7b50277..c0282457 100644 --- a/VocaluxeLib/Xml/CXmlSerializer.cs +++ b/VocaluxeLib/Xml/CXmlSerializer.cs @@ -4,8 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; -using System.Linq; -using System.Reflection; using System.Text; using System.Xml; using System.Xml.Serialization; @@ -35,312 +33,6 @@ namespace VocaluxeLib.Xml ConformanceLevel = ConformanceLevel.Document }; - #region Debug Helpers - private string _GetXPath(XmlNode node) - { - StringBuilder builder = new StringBuilder(); - while (node != null) - { - switch (node.NodeType) - { - case XmlNodeType.Attribute: - builder.Insert(0, "/@" + node.Name); - node = ((XmlAttribute)node).OwnerElement; - break; - case XmlNodeType.Element: - string index = _FindElementIndex(node); - builder.Insert(0, "/" + node.Name + index); - node = node.ParentNode; - break; - case XmlNodeType.Document: - return builder.ToString(); - default: - throw new ArgumentException("Only elements and attributes are supported"); - } - } - throw new ArgumentException("Node was not in a document"); - } - - private string _FindElementIndex(XmlNode element) - { - XmlNode parentNode = element.ParentNode; - if (parentNode is XmlDocument) - return ""; - XmlElement parent = (XmlElement)parentNode; - int index = 1; - if (parent != null) - { - XmlNode[] siblings = parent.ChildNodes.Cast().Where(candidate => candidate is XmlElement && candidate.Name == element.Name).ToArray(); - foreach (XmlNode candidate in siblings) - { - if (candidate == element) - return siblings.Length > 1 ? "[" + index + "]" : ""; - index++; - } - } - throw new ArgumentException("Couldn't find element within parent"); - } - #endregion Debug Helpers - - #region Deserialization - private object _GetValue(XmlNode node, Type type, string arrayItemName = null, object result = null) - { - if (type.IsEnum) - { - string stringValue = node.InnerText; - try - { - return Enum.Parse(type, stringValue); - } - catch (Exception) - { - throw new XmlException("Invalid value in " + _GetXPath(node)); - } - } - if (type == typeof(string)) - return node.InnerText; - if (type.IsPrimitive) - return _GetPrimitiveValue(node, type); - if (type.IsNullable()) - { - if (!node.HasChildNodes) - return null; - Type subType = type.GetGenericArguments()[0]; - return _GetValue(node, subType, arrayItemName, result); - } - if (type.IsList() || type.IsArray) - { - Type subType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0]; - String subName = arrayItemName ?? subType.GetTypeName(); - subName = subName.ToLowerInvariant(); - List subValues = new List(); - foreach (XmlNode subNode in node.ChildNodes) - { - if (subNode is XmlComment) - continue; - if (subName == subNode.Name.ToLowerInvariant() && !subNode.Name.ToLowerInvariant().StartsWith(subName)) - throw new XmlException("Invalid list entry '" + subNode.Name + "' in " + _GetXPath(node) + "; Expected: " + subName); - object subValue = _GetValue(subNode, subType); - subValues.Add(subValue); - } - if (result == null) - return _CreateList(type, subValues); - _FillList(result, type, subValues); - return result; - } - if (type.IsDictionary()) - { - Type subType = type.GetGenericArguments()[1]; - object dict = result ?? Activator.CreateInstance(type); - MethodInfo add = type.GetMethod("Add"); - if (arrayItemName != null) - arrayItemName = arrayItemName.ToLowerInvariant(); - foreach (XmlNode subNode in node.ChildNodes) - { - if (subNode is XmlComment) - continue; - object subValue = _GetValue(subNode, subType); - string subName; - if (arrayItemName != null) - { - if (arrayItemName != subNode.Name.ToLowerInvariant() && !subNode.Name.ToLowerInvariant().StartsWith(arrayItemName)) - throw new XmlException("Invalid dictionary entry '" + subNode.Name + "' in " + _GetXPath(node) + "; Expected: " + arrayItemName); - if (subNode.Attributes == null) - throw new XmlException("'name' attribute is missing in " + _GetXPath(subNode)); - XmlNode nameAtt = subNode.Attributes.GetNamedItem("name"); - if (nameAtt == null) - throw new XmlException("'name' attribute is missing in " + _GetXPath(subNode)); - subName = nameAtt.Value; - } - else - subName = subNode.Name; - add.Invoke(dict, new object[] {subName, subValue}); - } - return dict; - } - - object value; - try - { - value = result ?? Activator.CreateInstance(type); - } - catch (Exception) - { - throw new XmlException("Could not create instance of " + _GetXPath(node) + "(Type=" + type.Name + ")"); - } - _ReadChildNodes(node, ref value, true); - _ReadChildNodes(node, ref value, false); - return value; - } - - private object _GetPrimitiveValue(XmlNode node, Type type) - { - object value; - string nodeVal = node.InnerText; - try - { - int p = nodeVal.IndexOf(','); - if (p > 0 && p >= nodeVal.Length - 3) - { - CBase.Log.LogError("German number format converted to english in " + _GetXPath(node)); - char[] tmp = nodeVal.ToCharArray(); - tmp[p] = '.'; - nodeVal = new string(tmp); - } - value = Convert.ChangeType(nodeVal, type, CultureInfo.InvariantCulture); - } - catch (FormatException e) - { - throw new XmlException("Invalid format in " + _GetXPath(node) + ": '" + nodeVal + "' (" + e.Message + ")"); - } - catch (InvalidCastException e) - { - throw new XmlException(e.Message + " in " + _GetXPath(node) + ": '" + nodeVal + "'"); - } - return value; - } - - private static bool _CheckAndSetDefaultValue(object result, SFieldInfo field) - { - if (field.IsEmbeddedList) - { - _AddList(result, field, new List()); - return true; - } - if (!field.HasDefaultValue) - return false; - field.SetValue(result, field.DefaultValue); - return true; - } - - private static void _FillList(object list, Type type, ICollection values) - { - if (values.Count <= 0) - return; - if (type.IsArray) - { - Array array = (Array)list; - int i = 0; - foreach (object value in values) - array.SetValue(value, i++); - } - else - { - MethodInfo addMethod = type.GetMethod("Add"); - foreach (object value in values) - addMethod.Invoke(list, new object[] {value}); - } - } - - private static object _CreateList(Type type, ICollection values) - { - object list = type.IsArray ? Array.CreateInstance(type.GetElementType(), values.Count) : Activator.CreateInstance(type, new object[] {values.Count}); - _FillList(list, type, values); - return list; - } - - private static void _AddList(object result, SFieldInfo listField, ICollection list) - { - listField.SetValue(result, _CreateList(listField.Type, list)); - } - - private void _ReadChildNodes(XmlNode parent, ref object result, bool attributes) - { - IEnumerable nodes; - if (attributes) - nodes = parent.Attributes; - else - nodes = parent.ChildNodes; - - List fields = result.GetType().GetFields(attributes); - - if (nodes != null) - { - //Dictionary of all embedded lists to allow interleaved/mixed elements - Dictionary>> embLists = new Dictionary>>(); - foreach (XmlNode node in nodes) - { - if (node is XmlComment) - continue; - - SFieldInfo field = new SFieldInfo(); - int curField; - for (curField = 0; curField < fields.Count; curField++) - { - field = fields[curField]; - if (field.Name == node.Name || field.AltName == node.Name || (field.IsEmbeddedList && node.Name.StartsWith(field.Name))) - break; - } - if (curField >= fields.Count) - { - string msg = "Unexpected element: " + _GetXPath(node); - if (fields.Count > 0) - msg += " Expected: " + string.Join(", ", fields.Select(f => f.Name)); - throw new XmlException(msg); - } - - if (field.IsByteArray) - { - field.SetValue(result, Convert.FromBase64String(node.InnerText)); - fields.RemoveAt(curField); - } - else if (field.IsEmbeddedList) - { - Tuple> entry; - if (!embLists.TryGetValue(field.Name, out entry)) - { - entry = new Tuple>(field, new List()); - embLists.Add(field.Name, entry); - } - object subValue = _GetValue(node, field.SubType); - entry.Item2.Add(subValue); - } - else - { - object value = _GetValue(node, field.Type, field.ArrayItemName); - if (field.IsNormalized) - { - if (field.IsNullable && !((float?)value).Value.IsInRange(0, 1) || - !field.IsNullable && !((float)value).IsInRange(0, 1)) - throw new XmlException("Value in " + _GetXPath(node) + " is not normalized. (Value=" + value + ")"); - } - if (field.Ranged != null && value != null) - { - bool ok = false; - if (field.Type == typeof(int)) - ok = ((int)value).IsInRange(field.Ranged.Min, field.Ranged.Max); - else if (field.Type == typeof(float)) - ok = ((float)value).IsInRange(field.Ranged.Min, field.Ranged.Max); - else if (field.Type == typeof(double)) - ok = ((double)value).IsInRange(field.Ranged.Min, field.Ranged.Max); - else - Debug.Assert(false, "Ranged attribute has invalid type"); - if (!ok) - { - throw new XmlException("Value in " + _GetXPath(node) + " is not in the range " + field.Ranged.Min + "-" + field.Ranged.Max + ". (Value=" + value + - ")"); - } - } - field.SetValue(result, value); - fields.RemoveAt(curField); - } - } - //Add embedded lists - foreach (Tuple> entry in embLists.Values) - { - _AddList(result, entry.Item1, entry.Item2); - fields.Remove(entry.Item1); - } - } - foreach (SFieldInfo field in fields) - { - if (!_CheckAndSetDefaultValue(result, field)) - throw new XmlException("element: " + field.Name + " is missing in " + _GetXPath(parent)); - } - } - #endregion Deserialization - - #region Serialization private void _WriteNode(XmlWriter writer, string name, Type type, object value, bool isAttribute, string arrayItemName = null, string nameAttribute = null) { if (!isAttribute && _GetCommentCallback != null) @@ -445,75 +137,6 @@ namespace VocaluxeLib.Xml _WriteNode(writer, field.Name, field.Type, value, field.IsAttribute, field.ArrayItemName); } } - #endregion - - private T _Deserialize(XmlReader reader, object result) where T : new() - { - if (reader.IsEmptyElement) - return (T)result; - - XmlDocument xDoc = new XmlDocument(); - xDoc.Load(reader); - if (xDoc.DocumentElement == null) - throw new XmlException("No root element found!"); - try - { - result = _GetValue(xDoc.DocumentElement, typeof(T), typeof(T).GetSubTypeName(), result); - } - catch (TargetInvocationException e) - { - throw e.InnerException ?? e; - } - return (T)result; - } - - public T DeserializeString(string xml) where T : new() - { - return DeserializeString(xml, new T()); - } - - public T DeserializeString(string xml, T o) where T : new() - { - var reader = new XmlTextReader(new StringReader(xml)) - { - WhitespaceHandling = WhitespaceHandling.Significant, - Normalization = true, - XmlResolver = null - }; - try - { - return _Deserialize(reader, o); - } - finally - { - reader.Close(); - } - } - - public T Deserialize(string filePath) where T : new() - { - return Deserialize(filePath, new T()); - } - - public T Deserialize(string filePath, T o) where T : new() - { - if (!File.Exists(filePath)) - throw new FileNotFoundException(filePath); - var reader = new XmlTextReader(filePath) - { - WhitespaceHandling = WhitespaceHandling.Significant, - Normalization = true, - XmlResolver = null - }; - try - { - return _Deserialize(reader, o); - } - finally - { - reader.Close(); - } - } private void _Serialize(object o, XmlWriter writer) { diff --git a/VocaluxeTests/XmlSerializerTest.cs b/VocaluxeTests/XmlSerializerTest.cs index 650c5c7a..3ef04f77 100644 --- a/VocaluxeTests/XmlSerializerTest.cs +++ b/VocaluxeTests/XmlSerializerTest.cs @@ -106,15 +106,16 @@ namespace VocaluxeTests private static void _AssertFail(String xmlString) where T2 : Exception where T : new() { - var xml = new CXmlSerializer(); - _AssertFail(() => xml.DeserializeString(xmlString)); + var deserializer = new CXmlDeserializer(); + _AssertFail(() => deserializer.DeserializeString(xmlString)); } private static T _AssertSerDeserMatch(string xmlString) where T : new() { - var xml = new CXmlSerializer(); - T foo = xml.DeserializeString(xmlString); - string xmlNew = xml.Serialize(foo); + var deserializer = new CXmlDeserializer(); + var serializer = new CXmlSerializer(); + T foo = deserializer.DeserializeString(xmlString); + string xmlNew = serializer.Serialize(foo); Assert.AreEqual(xmlString, xmlNew); return foo; } @@ -134,7 +135,7 @@ namespace VocaluxeTests 3 2 "; - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); SBasic foo = xml.DeserializeString(s); Assert.AreEqual(1, foo.I); Assert.AreEqual("2", foo.S); @@ -235,20 +236,22 @@ namespace VocaluxeTests [TestMethod] public void TestList() { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); + var ser = new CXmlSerializer(); SList foo = xml.DeserializeString(_XMLList[0]); Assert.AreEqual(foo.Ints.Count, 2, "Deserialization failed"); Assert.AreEqual(foo.Ints[0].I, 1, "Deserialization failed"); Assert.AreEqual(foo.Ints[1].I, 1, "Deserialization failed"); - string res = xml.Serialize(foo); + string res = ser.Serialize(foo); Assert.AreEqual(_XMLList[0], res, "Serialization failed"); foo = xml.DeserializeString(_XMLList[1]); Assert.AreEqual(foo.Ints.Count, 0, "Deserialization2 failed"); - res = xml.Serialize(foo); + res = ser.Serialize(foo); Assert.AreEqual(_XMLList[2], res, "Serialization2 failed"); foo = xml.DeserializeString(_XMLList[2]); Assert.AreEqual(foo.Ints.Count, 0, "Deserialization2 failed"); - res = xml.Serialize(foo); + _AssertSerDeserMatch(_XMLList[2]); + res = ser.Serialize(foo); Assert.AreEqual(_XMLList[2], res, "Serialization2 failed"); _AssertFail(_Empty); } @@ -256,20 +259,21 @@ namespace VocaluxeTests [TestMethod] public void TestArray() { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); + var ser = new CXmlSerializer(); SArray foo = xml.DeserializeString(_XMLList[0]); Assert.AreEqual(foo.Ints.Length, 2, "Deserialization failed"); Assert.AreEqual(foo.Ints[0].I, 1, "Deserialization failed"); Assert.AreEqual(foo.Ints[1].I, 1, "Deserialization failed"); - string res = xml.Serialize(foo); + string res = ser.Serialize(foo); Assert.AreEqual(_XMLList[0], res, "Serialization failed"); foo = xml.DeserializeString(_XMLList[1]); Assert.AreEqual(foo.Ints.Length, 0, "Deserialization2 failed"); - res = xml.Serialize(foo); + res = ser.Serialize(foo); Assert.AreEqual(_XMLList[2], res, "Serialization2 failed"); foo = xml.DeserializeString(_XMLList[2]); Assert.AreEqual(foo.Ints.Length, 0, "Deserialization2 failed"); - res = xml.Serialize(foo); + res = ser.Serialize(foo); Assert.AreEqual(_XMLList[2], res, "Serialization2 failed"); _AssertFail(_Empty); } @@ -299,20 +303,21 @@ namespace VocaluxeTests [TestMethod] public void TestListEmbedded() { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); + var ser = new CXmlSerializer(); SListEmb foo = xml.DeserializeString(_XMLListEmb); Assert.AreEqual(foo.Ints.Count, 1, "Deserialization failed"); Assert.AreEqual(foo.Ints[0].I, 1, "Deserialization failed"); - string res = xml.Serialize(foo); + string res = ser.Serialize(foo); Assert.AreEqual(_XMLListEmb, res, "Serialization failed"); foo = xml.DeserializeString(_XMLListEmb2); Assert.AreEqual(foo.Ints.Count, 2, "Deserialization failed"); Assert.AreEqual(foo.Ints[1].I, 2, "Deserialization failed"); - res = xml.Serialize(foo); + res = ser.Serialize(foo); Assert.AreEqual(_XMLListEmb2, res, "Serialization failed"); foo = xml.DeserializeString(_XMLListEmb3); Assert.AreEqual(foo.Ints.Count, 0, "Deserialization failed"); - res = xml.Serialize(foo); + res = ser.Serialize(foo); Assert.AreEqual(_XMLListEmb3, res, "Serialization failed"); _AssertFail(_Empty); } @@ -320,20 +325,21 @@ namespace VocaluxeTests [TestMethod] public void TestArrayEmbedded() { - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); + var ser = new CXmlSerializer(); SArrayEmb foo = xml.DeserializeString(_XMLListEmb); Assert.AreEqual(foo.Ints.Length, 1, "Deserialization failed"); Assert.AreEqual(foo.Ints[0].I, 1, "Deserialization failed"); - string res = xml.Serialize(foo); + string res = ser.Serialize(foo); Assert.AreEqual(_XMLListEmb, res, "Serialization failed"); foo = xml.DeserializeString(_XMLListEmb2); Assert.AreEqual(foo.Ints.Length, 2, "Deserialization failed"); Assert.AreEqual(foo.Ints[1].I, 2, "Deserialization failed"); - res = xml.Serialize(foo); + res = ser.Serialize(foo); Assert.AreEqual(_XMLListEmb2, res, "Serialization failed"); foo = xml.DeserializeString(_XMLListEmb3); Assert.AreEqual(foo.Ints.Length, 0, "Deserialization failed"); - res = xml.Serialize(foo); + res = ser.Serialize(foo); Assert.AreEqual(_XMLListEmb3, res, "Serialization failed"); _AssertFail(_Empty); } @@ -345,12 +351,9 @@ namespace VocaluxeTests 2 3 "; - var xml = new CXmlSerializer(); - SProperty foo = xml.DeserializeString(xmlString); + SProperty foo = _AssertSerDeserMatch(xmlString); Assert.AreEqual(3, foo.Private); Assert.AreEqual(3, foo.Auto); - string newXml = xml.Serialize(foo); - Assert.AreEqual(xmlString, newXml); } [TestMethod] @@ -381,16 +384,17 @@ namespace VocaluxeTests public void TestExisting() { var foo = new SIgnore {I = 1}; - var xml = new CXmlSerializer(); + var xml = new CXmlDeserializer(); + var ser = new CXmlSerializer(); SIgnore bar = xml.DeserializeString(_XmlIgnore, foo); Assert.AreEqual(1, bar.I); - Assert.AreEqual(_XmlIgnore, xml.Serialize(bar)); + Assert.AreEqual(_XmlIgnore, ser.Serialize(bar)); var foo2 = new CIgnore {I = 1}; CIgnore bar2 = xml.DeserializeString(_XmlIgnore, foo2); Assert.AreEqual(1, bar2.I); Assert.AreEqual(foo2.J, bar2.J, "Original classes should be modified by the deserialization"); - Assert.AreEqual(_XmlIgnore, xml.Serialize(bar2)); + Assert.AreEqual(_XmlIgnore, ser.Serialize(bar2)); } [TestMethod] @@ -421,18 +425,19 @@ namespace VocaluxeTests foreach (Type type in types) { string xmlPath = Path.Combine(filePath, type.Name + ".xml"); - var xml = new CXmlSerializer(type == typeof(CConfig.SConfig)); + var deser = new CXmlDeserializer(); object foo = null; try { - foo = xml.Deserialize(xmlPath, Activator.CreateInstance(type)); + foo = deser.Deserialize(xmlPath, Activator.CreateInstance(type)); } catch (Exception e) { Assert.Fail("Exception with " + type.Name + ": {0}", new object[] {e.Message}); } Assert.IsInstanceOfType(foo, type, "Wrong type with " + type.Name); - string newXml = xml.Serialize(foo); + var ser = new CXmlSerializer(type == typeof(CConfig.SConfig)); + string newXml = ser.Serialize(foo); string oldXml = File.ReadAllText(xmlPath); Assert.AreEqual(oldXml, newXml, "Error with " + type.Name); }