Merge pull request #1275 from ranma42/fix-lib64
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializationReaderInterpreter.cs
index fb46de152f1354a1f18c0f6062f4af9b022e0d9f..1853ad1497615a244b44df1c26ef7fe79b75d621 100644 (file)
@@ -39,6 +39,7 @@ namespace System.Xml.Serialization
                XmlMapping _typeMap;
                SerializationFormat _format;
                static readonly XmlQualifiedName AnyType = new XmlQualifiedName("anyType", System.Xml.Schema.XmlSchema.Namespace);
+               static readonly object [] empty_array = new object [0];
 
                public XmlSerializationReaderInterpreter(XmlMapping typeMap)
                {
@@ -115,6 +116,16 @@ namespace System.Xml.Serialization
 
                        if (typeMap.HasWrapperElement)
                        {
+                               // bug #79988: out parameters need to be initialized if they 
+                               // are value types
+                               ArrayList members = ((ClassMap) typeMap.ObjectMap).AllMembers;
+                               for (int n = 0; n < members.Count; n++) {
+                                       XmlTypeMapMember mem = (XmlTypeMapMember) members [n];
+                                       if (!mem.IsReturnValue && mem.TypeData.IsValueType)
+                                               SetMemberValueFromAttr (mem, parameters, CreateInstance (
+                                                       mem.TypeData.Type), true);
+                               }
+
                                if (_format == SerializationFormat.Encoded)
                                {
                                        while (Reader.NodeType == System.Xml.XmlNodeType.Element)
@@ -125,13 +136,20 @@ namespace System.Xml.Serialization
                                                Reader.MoveToContent ();
                                        }
                                }
-                               
-                               while (Reader.NodeType != System.Xml.XmlNodeType.EndElement) 
+
+                               while (Reader.NodeType != System.Xml.XmlNodeType.EndElement &&
+                                      // it could be an empty root element
+                                      Reader.ReadState == ReadState.Interactive)
                                {
                                        if (Reader.IsStartElement(typeMap.ElementName, typeMap.Namespace) 
                                            || _format == SerializationFormat.Encoded)  
                                        {
-                                               if (Reader.IsEmptyElement) { Reader.Skip(); Reader.MoveToContent(); continue; }
+                                               ReadAttributeMembers ((ClassMap)typeMap.ObjectMap, parameters, true);
+                                               if (Reader.IsEmptyElement) {
+                                                       Reader.Skip();
+                                                       Reader.MoveToContent();
+                                                       continue;
+                                               }
                                                Reader.ReadStartElement();
                                                ReadMembers ((ClassMap)typeMap.ObjectMap, parameters, true, false);
                                                ReadEndElement();
@@ -160,7 +178,7 @@ namespace System.Xml.Serialization
                        }
                        else
                        {
-                               if (Reader.LocalName != rootMap.ElementName || Reader.NamespaceURI != rootMap.Namespace)
+                               if (!rootMap.IsAny && (Reader.LocalName != rootMap.ElementName || Reader.NamespaceURI != rootMap.Namespace))
                                        throw CreateUnknownNodeException();
                                
                                return ReadObject (rootMap, rootMap.IsNullable, true);
@@ -205,7 +223,7 @@ namespace System.Xml.Serialization
                                        return ReadTypedPrimitive (AnyType);
             }
 
-                       object ob = Activator.CreateInstance (typeMap.TypeData.Type);
+                       object ob = CreateInstance (typeMap.TypeData.Type, true);
 
                        Reader.MoveToElement();
                        bool isEmpty = Reader.IsEmptyElement;
@@ -222,20 +240,8 @@ namespace System.Xml.Serialization
                        ReadMembers ((ClassMap) typeMap.ObjectMap, ob, false, false);
                }
 
-               void ReadMembers (ClassMap map, object ob, bool isValueList, bool readByOrder)
+               void ReadAttributeMembers (ClassMap map, object ob, bool isValueList)
                {
-                       // Set the default values of the members
-                       if (map.MembersWithDefault != null)
-                       {
-                               ArrayList members = map.MembersWithDefault;
-                               for (int n=0; n<members.Count; n++) {
-                                       XmlTypeMapMember mem = (XmlTypeMapMember) members[n];
-                                       SetMemberValueFromAttr (mem, ob, mem.DefaultValue, isValueList);
-                               }
-                       }
-                       
-                       // Reads attributes
-
                        XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
                        int anyAttributeIndex = 0;
                        object anyAttributeArray = null;
@@ -280,7 +286,14 @@ namespace System.Xml.Serialization
                                anyAttributeArray = ShrinkArray ((Array)anyAttributeArray, anyAttributeIndex, anyAttrMember.TypeData.Type.GetElementType(), true);
                                SetMemberValue (anyAttrMember, ob, anyAttributeArray, isValueList);
                        }
-                       
+                       Reader.MoveToElement ();
+               }
+
+               void ReadMembers (ClassMap map, object ob, bool isValueList, bool readBySoapOrder)
+               {
+                       // Reads attributes
+                       ReadAttributeMembers (map, ob, isValueList);
+
                        if (!isValueList)
                        {
                                Reader.MoveToElement();
@@ -304,12 +317,12 @@ namespace System.Xml.Serialization
                        object[] flatLists = null;
                        object[] flatListsChoices = null;
                        Fixup fixup = null;
-                       int ind = 0;
+                       int ind = -1;
                        int maxInd;
 
-                       if (readByOrder) {
+                       if (readBySoapOrder) {
                                if (map.ElementMembers != null) maxInd = map.ElementMembers.Count;
-                               else maxInd = 0;
+                               else maxInd = -1;
                        }
                        else
                                maxInd = int.MaxValue;
@@ -348,24 +361,40 @@ namespace System.Xml.Serialization
                                AddFixup (fixup);
                        }
 
-                       while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && (ind < maxInd)) 
+                       XmlTypeMapMember previousMember = null;
+                       while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && (ind < maxInd - 1))
                        {
                                if (Reader.NodeType == System.Xml.XmlNodeType.Element) 
                                {
                                        XmlTypeMapElementInfo info;
                                        
-                                       if (readByOrder) {
-                                               info = map.GetElement (ind++);
+                                       if (readBySoapOrder) {
+                                               info = map.GetElement (Reader.LocalName, Reader.NamespaceURI, ind);
                                        }
                                        else if (hasAnyReturnMember) {
                                                info = (XmlTypeMapElementInfo) ((XmlTypeMapMemberElement)map.ReturnMember).ElementInfo[0];
                                                hasAnyReturnMember = false;
                                        }
-                                       else
-                                               info = map.GetElement (Reader.LocalName, Reader.NamespaceURI);
-                                               
+                                       else {
+                                               if (map.IsOrderDependentMap) {
+                                                       info = map.GetElement (Reader.LocalName, Reader.NamespaceURI, ind);
+                                               }
+                                               else
+                                                       info = map.GetElement (Reader.LocalName, Reader.NamespaceURI);
+                                       }
+
                                        if (info != null && !readFlag[info.Member.Index] )
                                        {
+                                               if (info.Member != previousMember)
+                                               {
+                                                       ind = info.ExplicitOrder + 1;
+                                                       // If the member is a flat list don't increase the index, since the next element may
+                                                       // be another item of the list. This is a fix for Xamarin bug #9193.
+                                                       if (info.Member is XmlTypeMapMemberFlatList)
+                                                               ind--;
+                                                       previousMember = info.Member;
+                                               }
+
                                                if (info.Member.GetType() == typeof (XmlTypeMapMemberList))
                                                {
                                                        if (_format == SerializationFormat.Encoded && info.MultiReferenceType)
@@ -483,7 +512,6 @@ namespace System.Xml.Serialization
                                }
                                else 
                                        UnknownNode(ob);
-
                                Reader.MoveToContent();
                        }
 
@@ -557,12 +585,16 @@ namespace System.Xml.Serialization
 
                void SetMemberValue (XmlTypeMapMember member, object ob, object value, bool isValueList)
                {
-                       if (isValueList) ((object[])ob)[member.GlobalIndex] = value;
-                       else {
+                       var memberType = member.TypeData.Type;
+                       if (value != null && !value.GetType().IsAssignableFrom (memberType))
+                               value = XmlSerializationWriterInterpreter.ImplicitConvert (value, memberType);
+
+                       if (isValueList)
+                               ((object[])ob)[member.GlobalIndex] = value;
+                       else
                                member.SetValue (ob, value);
-                               if (member.IsOptionalValueType)
-                                       member.SetValueSpecified (ob, true); 
-                       }
+                       if (member.IsOptionalValueType)
+                               member.SetValueSpecified (ob, true); 
                }
 
                void SetMemberValueFromAttr (XmlTypeMapMember member, object ob, object value, bool isValueList)
@@ -600,7 +632,7 @@ namespace System.Xml.Serialization
                                        return ReadObject (elem.MappedType, elem.IsNullable, true);
 
                                case SchemaTypes.XmlSerializable:
-                                       object ob = Activator.CreateInstance (elem.TypeData.Type);
+                                       object ob = CreateInstance (elem.TypeData.Type, true);
                                        return ReadSerializable ((IXmlSerializable)ob);
 
                                default:
@@ -711,7 +743,7 @@ namespace System.Xml.Serialization
                        else    // Must be IEnumerable
                        {
                                if (list == null) {
-                                       if (canCreateInstance) list = Activator.CreateInstance (type);
+                                       if (canCreateInstance) list = CreateInstance (type, true);
                                        else throw CreateReadOnlyCollectionException (type.FullName);
                                }
 
@@ -720,12 +752,22 @@ namespace System.Xml.Serialization
                        }
                }
 
+               static object CreateInstance (Type type, bool nonPublic)
+               {
+                       return Activator.CreateInstance (type, nonPublic);
+               }
+
+               object CreateInstance (Type type)
+               {
+                       return Activator.CreateInstance (type, empty_array);
+               }
+
                object CreateList (Type listType)
                {
                        if (listType.IsArray)
                                return EnsureArrayIndex (null, 0, listType.GetElementType());
                        else
-                               return Activator.CreateInstance (listType);
+                               return CreateInstance (listType, true);
                }
                
                object InitializeList (TypeData listType)
@@ -733,7 +775,7 @@ namespace System.Xml.Serialization
                        if (listType.Type.IsArray)
                                return null;
                        else
-                               return Activator.CreateInstance (listType.Type);
+                               return CreateInstance (listType.Type, true);
                }
 
                void FillList (object list, object items)
@@ -784,10 +826,12 @@ namespace System.Xml.Serialization
 
                object GetEnumValue (XmlTypeMapping typeMap, string val)
                {
+                       if (val == null)
+                               return null;
                        EnumMap map = (EnumMap) typeMap.ObjectMap;
                        string ev = map.GetEnumName (typeMap.TypeFullName, val);
                        if (ev == null) throw CreateUnknownConstantException (val, typeMap.TypeData.Type);
-                       return Enum.Parse (typeMap.TypeData.Type, ev);
+                       return Enum.Parse (typeMap.TypeData.Type, ev, false);
                }
 
                object ReadXmlSerializableElement (XmlTypeMapping typeMap, bool isNullable)
@@ -795,9 +839,9 @@ namespace System.Xml.Serialization
                        Reader.MoveToContent ();
                        if (Reader.NodeType == XmlNodeType.Element)
                        {
-                               if (Reader.LocalName == typeMap.ElementName && Reader.NamespaceURI == typeMap.Namespace)
+                               if (typeMap.IsAny || (Reader.LocalName == typeMap.ElementName && Reader.NamespaceURI == typeMap.Namespace))
                                {
-                                       object ob = Activator.CreateInstance (typeMap.TypeData.Type);
+                                       object ob = CreateInstance (typeMap.TypeData.Type, true);
                                        return ReadSerializable ((IXmlSerializable)ob);
                                }
                                else