PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/XmlFormatterSerializer.cs

https://bitbucket.org/danipen/mono
C# | 215 lines | 157 code | 22 blank | 36 comment | 56 complexity | f623a0125b81312ffd23113d87fe5836 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // XmlFormatterSerializer.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <atsushi@ximian.com>
  6. //
  7. // Copyright (C) 2005 Novell, Inc. http://www.novell.com
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. #if NET_2_0
  29. using System;
  30. using System.Collections.Generic;
  31. using System.IO;
  32. using System.Reflection;
  33. using System.Runtime.Serialization.Formatters.Binary;
  34. using System.Xml;
  35. using System.Xml.Schema;
  36. using QName = System.Xml.XmlQualifiedName;
  37. namespace System.Runtime.Serialization
  38. {
  39. internal class XmlFormatterSerializer
  40. {
  41. XmlDictionaryWriter writer;
  42. object graph;
  43. KnownTypeCollection types;
  44. bool save_id;
  45. bool ignore_unknown;
  46. IDataContractSurrogate surrogate;
  47. DataContractResolver resolver, default_resolver; // new in 4.0
  48. int max_items;
  49. List<object> objects = new List<object> ();
  50. Dictionary<object,string> references = new Dictionary<object,string> (); // preserve possibly referenced objects to ids. (new in 3.5 SP1)
  51. public static void Serialize (XmlDictionaryWriter writer, object graph, Type declaredType, KnownTypeCollection types,
  52. bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences, DataContractResolver resolver, DataContractResolver defaultResolver)
  53. {
  54. new XmlFormatterSerializer (writer, types, ignoreUnknown, maxItems, root_ns, preserveObjectReferences, resolver, defaultResolver)
  55. .Serialize (/*graph != null ? graph.GetType () : */declaredType, graph); // FIXME: I believe it should always use declaredType, but such a change brings some test breakages.
  56. }
  57. public XmlFormatterSerializer (XmlDictionaryWriter writer, KnownTypeCollection types, bool ignoreUnknown,
  58. int maxItems, string root_ns, bool preserveObjectReferences,
  59. DataContractResolver resolver, DataContractResolver defaultResolver)
  60. {
  61. this.writer = writer;
  62. this.types = types;
  63. ignore_unknown = ignoreUnknown;
  64. max_items = maxItems;
  65. PreserveObjectReferences = preserveObjectReferences;
  66. this.resolver = resolver;
  67. this.default_resolver = defaultResolver;
  68. }
  69. public bool PreserveObjectReferences { get; private set; }
  70. public List<object> SerializingObjects {
  71. get { return objects; }
  72. }
  73. public XmlDictionaryWriter Writer {
  74. get { return writer; }
  75. }
  76. public void Serialize (Type type, object graph)
  77. {
  78. if (graph == null)
  79. writer.WriteAttributeString ("i", "nil", XmlSchema.InstanceNamespace, "true");
  80. else if (type == typeof (XmlElement))
  81. ((XmlElement) graph).WriteTo (Writer);
  82. else if (type == typeof (XmlNode [])) {
  83. foreach (var xn in (XmlNode []) graph)
  84. xn.WriteTo (Writer);
  85. }
  86. else {
  87. QName resolvedQName = null;
  88. if (resolver != null) {
  89. XmlDictionaryString rname, rns;
  90. if (resolver.TryResolveType (graph != null ? graph.GetType () : typeof (object), type, default_resolver, out rname, out rns))
  91. resolvedQName = new QName (rname.Value, rns.Value);
  92. }
  93. Type actualType = graph.GetType ();
  94. SerializationMap map;
  95. map = types.FindUserMap (actualType);
  96. // For some collection types, the actual type does not matter. So get nominal serialization type instead.
  97. // (The code below also covers the lines above, but I don't remove above lines to avoid extra search cost.)
  98. if (map == null) {
  99. // FIXME: not sure if type.IsInterface is the correct condition to determine whether items are serialized with i:type or not. (e.g. bug #675144 server response).
  100. actualType = types.GetSerializedType (type.IsInterface ? type : actualType);
  101. map = types.FindUserMap (actualType);
  102. }
  103. // If it is still unknown, then register it.
  104. if (map == null) {
  105. types.Add (actualType);
  106. map = types.FindUserMap (actualType);
  107. }
  108. bool explicityType = false;
  109. if(type != actualType)
  110. {
  111. // Check if underlying type of Nullable, mismatch the current type.
  112. if(type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
  113. explicityType = (type.GetGenericArguments () [0] != actualType);
  114. else
  115. explicityType = true;
  116. }
  117. if (explicityType && (map == null || map.OutputXsiType)) {
  118. QName qname = resolvedQName ?? types.GetXmlName (actualType);
  119. string name = qname.Name;
  120. string ns = qname.Namespace;
  121. if (qname == QName.Empty) {
  122. name = XmlConvert.EncodeLocalName (actualType.Name);
  123. ns = KnownTypeCollection.DefaultClrNamespaceBase + actualType.Namespace;
  124. } else if (qname.Namespace == KnownTypeCollection.MSSimpleNamespace)
  125. ns = XmlSchema.Namespace;
  126. if (writer.LookupPrefix (ns) == null) // it goes first (extraneous, but it makes att order compatible)
  127. writer.WriteXmlnsAttribute (null, ns);
  128. writer.WriteStartAttribute ("i", "type", XmlSchema.InstanceNamespace);
  129. writer.WriteQualifiedName (name, ns);
  130. writer.WriteEndAttribute ();
  131. }
  132. QName predef = KnownTypeCollection.GetPredefinedTypeName (actualType);
  133. if (predef != QName.Empty)
  134. SerializePrimitive (type, graph, predef);
  135. else
  136. map.Serialize (graph, this);
  137. }
  138. }
  139. public void SerializePrimitive (Type type, object graph, QName qname)
  140. {
  141. string label;
  142. if (TrySerializeAsReference (false, graph, out label))
  143. return;
  144. if (label != null)
  145. Writer.WriteAttributeString ("z", "Id", KnownTypeCollection.MSSimpleNamespace, label);
  146. bool isDateTimeOffset = false;
  147. // Handle DateTimeOffset type and DateTimeOffset?
  148. if (type == typeof (DateTimeOffset))
  149. isDateTimeOffset = true;
  150. else if(type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
  151. isDateTimeOffset = type.GetGenericArguments () [0] == typeof (DateTimeOffset);
  152. // It is the only exceptional type that does not serialize to string but serializes into complex element.
  153. if (isDateTimeOffset) {
  154. var v = (DateTimeOffset) graph;
  155. writer.WriteStartElement ("DateTime", KnownTypeCollection.DefaultClrNamespaceSystem);
  156. SerializePrimitive (typeof (DateTime), DateTime.SpecifyKind (v.DateTime.Subtract (v.Offset), DateTimeKind.Utc), KnownTypeCollection.GetPredefinedTypeName (typeof (DateTime)));
  157. writer.WriteEndElement ();
  158. writer.WriteStartElement ("OffsetMinutes", KnownTypeCollection.DefaultClrNamespaceSystem);
  159. SerializePrimitive (typeof (int), v.Offset.TotalMinutes, KnownTypeCollection.GetPredefinedTypeName (typeof (int)));
  160. writer.WriteEndElement ();
  161. }
  162. else
  163. writer.WriteString (KnownTypeCollection.PredefinedTypeObjectToString (graph));
  164. }
  165. public void WriteStartElement (string memberName, string memberNamespace, string contentNamespace)
  166. {
  167. writer.WriteStartElement (memberName, memberNamespace);
  168. if (!string.IsNullOrEmpty (contentNamespace) && contentNamespace != memberNamespace)
  169. writer.WriteXmlnsAttribute (null, contentNamespace);
  170. }
  171. public void WriteEndElement ()
  172. {
  173. writer.WriteEndElement ();
  174. }
  175. // returned bool: whether z:Ref is written or not.
  176. // out label: object label either in use or newly allocated.
  177. public bool TrySerializeAsReference (bool isMapReference, object graph, out string label)
  178. {
  179. label = null;
  180. if (!isMapReference && (!PreserveObjectReferences || graph == null || graph.GetType ().IsValueType))
  181. return false;
  182. if (references.TryGetValue (graph, out label)) {
  183. Writer.WriteAttributeString ("z", "Ref", KnownTypeCollection.MSSimpleNamespace, label);
  184. label = null; // do not write label
  185. return true;
  186. }
  187. label = "i" + (references.Count + 1);
  188. references.Add (graph, label);
  189. return false;
  190. }
  191. }
  192. }
  193. #endif