Bug 15572. Lookup KnownTypeCollection element types in MSSimpleNamespace
[mono.git] / mcs / class / System.Runtime.Serialization / System.Runtime.Serialization / XmlFormatterDeserializer.cs
index 53bf3ccdb771feb0f41e46ab7dac4874125e7b29..52e5bc7bd07965c8d36f45720d84569b9d5716c9 100644 (file)
@@ -104,17 +104,46 @@ namespace System.Runtime.Serialization
                        get { return references; }
                }
 
+               XmlDocument document;
+               
+               XmlDocument XmlDocument {
+                       get { return (document = document ?? new XmlDocument ()); }
+               }
+
                // This method handles z:Ref, xsi:nil and primitive types, and then delegates to DeserializeByMap() for anything else.
+
                public object Deserialize (Type type, XmlReader reader)
                {
-                       QName graph_qname = types.GetQName (type);
+                       if (type == typeof (XmlElement))
+                               return XmlDocument.ReadNode (reader);
+                       else if (type == typeof (XmlNode [])) {
+                               reader.ReadStartElement ();
+                               var l = new List<XmlNode> ();
+                               for(; !reader.EOF && reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ())
+                                       l.Add (XmlDocument.ReadNode (reader));
+                               reader.ReadEndElement ();
+                               return l.ToArray ();
+                       }
+                       QName graph_qname = null;
+                       
+                       if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) {
+                               Type internal_type = type.GetGenericArguments () [0];
+                               
+                               if (types.FindUserMap(internal_type) != null) {
+                                       graph_qname = types.GetQName (internal_type);
+                               }
+                       }
+                       
+                       if (graph_qname == null)
+                               graph_qname = types.GetQName (type);
+                               
                        string itype = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
                        if (itype != null) {
-                               string[] parts = itype.Split (':');
+                               string [] parts = itype.Split (':');
                                if (parts.Length > 1)
-                                       graph_qname = new QName (parts [1], reader.LookupNamespace (reader.NameTable.Get (parts[0])));
+                                       graph_qname = new QName (parts [1], reader.LookupNamespace (reader.NameTable.Get (parts [0])));
                                else
-                                       graph_qname = new QName (itype, reader.NamespaceURI);
+                                       graph_qname = new QName (itype, reader.LookupNamespace (String.Empty));
                        }
 
                        string label = reader.GetAttribute ("Ref", KnownTypeCollection.MSSimpleNamespace);
@@ -130,7 +159,7 @@ namespace System.Runtime.Serialization
 
                        if (isNil) {
                                reader.Skip ();
-                               if (!type.IsValueType)
+                               if (!type.IsValueType || type == typeof (void))
                                        return null;
                                else if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
                                        return null;
@@ -149,21 +178,11 @@ namespace System.Runtime.Serialization
                                }
                        }
 
-                       if (KnownTypeCollection.GetPrimitiveTypeFromName (graph_qname.Name) != null) {
+                       if (KnownTypeCollection.GetPrimitiveTypeFromName (graph_qname) != null) {
                                string id = reader.GetAttribute ("Id", KnownTypeCollection.MSSimpleNamespace);
 
-                               string value;
-                               if (reader.IsEmptyElement) {
-                                       reader.Read (); // advance
-                                       if (type.IsValueType)
-                                               return Activator.CreateInstance (type);
-                                       else
-                                               // FIXME: Workaround for creating empty objects of the correct type.
-                                               value = String.Empty;
-                               }
-                               else
-                                       value = reader.ReadElementContentAsString ();
-                               object ret = KnownTypeCollection.PredefinedTypeStringToObject (value, graph_qname.Name, reader);
+                               object ret = DeserializePrimitive (type, reader, graph_qname);
+
                                if (id != null) {
                                        if (references.ContainsKey (id))
                                                throw new InvalidOperationException (String.Format ("Object with Id '{0}' already exists as '{1}'", id, references [id]));
@@ -175,9 +194,51 @@ namespace System.Runtime.Serialization
                        return DeserializeByMap (graph_qname, type, reader);
                }
 
+               object DeserializePrimitive (Type type, XmlReader reader, QName qname)
+               {
+                       bool isDateTimeOffset = false;
+                       // Handle DateTimeOffset type and DateTimeOffset?.
+                       if (type == typeof (DateTimeOffset))
+                               isDateTimeOffset = true;
+                       else if(type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) 
+                               isDateTimeOffset = type.GetGenericArguments () [0] == typeof (DateTimeOffset);  
+                       // It is the only exceptional type that does not serialize to string but serializes into complex element.
+                       if (isDateTimeOffset) {
+                               if (reader.IsEmptyElement) {
+                                       reader.Read ();
+                                       return default (DateTimeOffset);
+                               }
+                               reader.ReadStartElement ();
+                               reader.MoveToContent ();
+                               var date = reader.ReadElementContentAsDateTime ("DateTime", KnownTypeCollection.DefaultClrNamespaceSystem);
+                               var off = TimeSpan.FromMinutes (reader.ReadElementContentAsInt ("OffsetMinutes", KnownTypeCollection.DefaultClrNamespaceSystem));
+                               reader.MoveToContent ();
+                               reader.ReadEndElement ();
+                               return new DateTimeOffset (DateTime.SpecifyKind (date.ToUniversalTime () + off, DateTimeKind.Unspecified), off);
+                       }
+
+                       string value;
+                       if (reader.IsEmptyElement) {
+                               reader.Read (); // advance
+                               if (type.IsValueType)
+                                       return Activator.CreateInstance (type);
+                               else
+                                       // FIXME: Workaround for creating empty objects of the correct type.
+                                       value = String.Empty;
+                       }
+                       else
+                               value = reader.ReadElementContentAsString ();
+                       return KnownTypeCollection.PredefinedTypeStringToObject (value, qname.Name, reader);
+               }
+
                object DeserializeByMap (QName name, Type type, XmlReader reader)
                {
-                       SerializationMap map = types.FindUserMap (type); // use type rather than name as the type could be a "resolved" one.
+                       SerializationMap map = null;
+                       // List<T> and T[] have the same QName, use type to find map work better.
+                       if(name.Name.StartsWith ("ArrayOf", StringComparison.Ordinal) || resolved_qnames.ContainsKey (name))
+                               map = types.FindUserMap (type);
+                       else
+                               map = types.FindUserMap (name); // use type when the name is "resolved" one. Otherwise use name (there are cases that type cannot be resolved by type).
                        if (map == null && (name.Name.StartsWith ("ArrayOf", StringComparison.Ordinal) ||
                            name.Namespace == KnownTypeCollection.MSArraysNamespace ||
                            name.Namespace.StartsWith (KnownTypeCollection.DefaultClrNamespaceBase, StringComparison.Ordinal))) {
@@ -193,14 +254,14 @@ namespace System.Runtime.Serialization
 
                Type GetTypeFromNamePair (string name, string ns)
                {
-                       Type p = KnownTypeCollection.GetPrimitiveTypeFromName (name); // FIXME: namespace?
+                       Type p = KnownTypeCollection.GetPrimitiveTypeFromName (new QName (name, ns));
                        if (p != null)
                                return p;
                        bool makeArray = false;
                        if (name.StartsWith ("ArrayOf", StringComparison.Ordinal)) {
                                name = name.Substring (7); // strip "ArrayOf"
                                if (ns == KnownTypeCollection.MSArraysNamespace)
-                                       return GetTypeFromNamePair (name, String.Empty).MakeArrayType ();
+                                       return GetTypeFromNamePair (name, KnownTypeCollection.MSSimpleNamespace).MakeArrayType ();
                                makeArray = true;
                        }
 
@@ -210,15 +271,7 @@ namespace System.Runtime.Serialization
                        foreach (var ass in AppDomain.CurrentDomain.GetAssemblies ()) {
                                Type [] types;
 
-#if MOONLIGHT
-                               try  {
-                                       types = ass.GetTypes ();
-                               } catch (System.Reflection.ReflectionTypeLoadException rtle) {
-                                       types = rtle.Types;
-                               }
-#else
                                types = ass.GetTypes ();
-#endif
                                if (types == null)
                                        continue;