New test.
[mono.git] / mcs / class / System.Runtime.Serialization.Formatters.Soap / System.Runtime.Serialization.Formatters.Soap / SoapReader.cs
old mode 100755 (executable)
new mode 100644 (file)
index 69ff966..90b9e57
@@ -5,27 +5,27 @@
 //     Authors:\r
 //             Jean-Marc Andre (jean-marc.andre@polymtl.ca)\r
 //\r
-
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
+\r
+//\r
+// Permission is hereby granted, free of charge, to any person obtaining\r
+// a copy of this software and associated documentation files (the\r
+// "Software"), to deal in the Software without restriction, including\r
+// without limitation the rights to use, copy, modify, merge, publish,\r
+// distribute, sublicense, and/or sell copies of the Software, and to\r
+// permit persons to whom the Software is furnished to do so, subject to\r
+// the following conditions:\r
+// \r
+// The above copyright notice and this permission notice shall be\r
+// included in all copies or substantial portions of the Software.\r
+// \r
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+//\r
 \r
 using System;\r
 using System.IO;\r
@@ -36,6 +36,7 @@ using System.Collections;
 using System.Runtime.Remoting;\r
 using System.Runtime.Serialization;\r
 using System.Runtime.Remoting.Messaging;\r
+using System.Runtime.Remoting.Metadata;\r
 \r
 namespace System.Runtime.Serialization.Formatters.Soap {\r
        internal sealed class SoapReader {\r
@@ -89,7 +90,7 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                #region Public Methods\r
 \r
                public object Deserialize(Stream inStream, ISoapMessage soapMessage) \r
-               {
+               {\r
                        ArrayList headers = null;\r
                        xmlReader = new XmlTextReader(inStream);\r
                        xmlReader.WhitespaceHandling = WhitespaceHandling.None;\r
@@ -99,21 +100,21 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        {\r
                                // SOAP-ENV:Envelope\r
                                xmlReader.MoveToContent();\r
-                               xmlReader.ReadStartElement ();
-                               xmlReader.MoveToContent();
-                               
-                               // Read headers
-                               while (!(xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace))
+                               xmlReader.ReadStartElement ();\r
+                               xmlReader.MoveToContent();\r
+                               \r
+                               // Read headers\r
+                               while (!(xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace))\r
                                {\r
                                        if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Header" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace)\r
                                        {\r
                                                if (headers == null) headers = new ArrayList ();\r
                                                DeserializeHeaders (headers);\r
                                        }\r
-                                       else
+                                       else\r
                                                xmlReader.Skip ();\r
                                        xmlReader.MoveToContent();\r
-                               }
+                               }\r
                                \r
                                // SOAP-ENV:Body\r
                                xmlReader.ReadStartElement();\r
@@ -151,6 +152,14 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                }\r
                \r
                #endregion\r
+               \r
+               public SoapTypeMapper Mapper {\r
+                       get { return mapper; }\r
+               }\r
+               \r
+               public XmlTextReader XmlReader {\r
+                       get { return xmlReader; }\r
+               }\r
 \r
                #region Private Methods\r
 \r
@@ -192,16 +201,12 @@ namespace System.Runtime.Serialization.Formatters.Soap {
 \r
                private Type GetComponentType()\r
                {\r
-                       Type type = null;\r
-                       if(GetId() != 0) return typeof(string);\r
-                       \r
                        string strValue = xmlReader["type", XmlSchema.InstanceNamespace];\r
-                       if(strValue == null) return null;\r
-                       string[] strName = strValue.Split(':');\r
-                       string namespaceURI = xmlReader.LookupNamespace(strName[0]);\r
-                       type = mapper[new Element(string.Empty, strName[1], namespaceURI)];\r
-\r
-                       return type;\r
+                       if(strValue == null) {\r
+                               if(GetId() != 0) return typeof(string);\r
+                               return null;\r
+                       }\r
+                       return GetTypeFromQName (strValue);\r
                }\r
 \r
                private bool DeserializeMessage(ISoapMessage message) \r
@@ -226,51 +231,58 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        long paramValuesId = NextAvailableId;\r
                        int[] indices = new int[1];\r
 \r
-                       int initialDepth = xmlReader.Depth;\r
-                       xmlReader.Read();\r
-                       int i = 0;\r
-                       while(xmlReader.Depth > initialDepth) \r
+                       if (!xmlReader.IsEmptyElement)\r
                        {\r
-                               long paramId, paramHref;\r
-                               object objParam = null;\r
-                               paramNames.Add (xmlReader.Name);\r
-                               Type paramType = null;\r
-                               \r
-                               if (message.ParamTypes != null) {\r
-                                       if (i >= message.ParamTypes.Length)\r
-                                               throw new SerializationException ("Not enough parameter types in SoapMessages");\r
-                                       paramType = message.ParamTypes [i];\r
-                               }\r
-                               \r
-                               indices[0] = i;\r
-                               objParam = DeserializeComponent(\r
-                                       paramType,\r
-                                       out paramId,\r
-                                       out paramHref,\r
-                                       paramValuesId,\r
-                                       null,\r
-                                       indices);\r
-                               indices[0] = paramValues.Add(objParam);\r
-                               if(paramHref != 0) \r
-                               {\r
-                                       RecordFixup(paramValuesId, paramHref, paramValues.ToArray(), null, null, null, indices);\r
-                               }\r
-                               else if(paramId != 0) \r
-                               {\r
-//                                     RegisterObject(paramId, objParam, null, paramValuesId, null, indices);\r
-                               }\r
-                               else \r
+                               int initialDepth = xmlReader.Depth;\r
+                               xmlReader.Read();\r
+                               int i = 0;\r
+                               while(xmlReader.Depth > initialDepth) \r
                                {\r
+                                       long paramId, paramHref;\r
+                                       object objParam = null;\r
+                                       paramNames.Add (xmlReader.Name);\r
+                                       Type paramType = null;\r
+                                       \r
+                                       if (message.ParamTypes != null) {\r
+                                               if (i >= message.ParamTypes.Length)\r
+                                                       throw new SerializationException ("Not enough parameter types in SoapMessages");\r
+                                               paramType = message.ParamTypes [i];\r
+                                       }\r
+                                       \r
+                                       indices[0] = i;\r
+                                       objParam = DeserializeComponent(\r
+                                               paramType,\r
+                                               out paramId,\r
+                                               out paramHref,\r
+                                               paramValuesId,\r
+                                               null,\r
+                                               indices);\r
+                                       indices[0] = paramValues.Add(objParam);\r
+                                       if(paramHref != 0) \r
+                                       {\r
+                                               RecordFixup(paramValuesId, paramHref, paramValues.ToArray(), null, null, null, indices);\r
+                                       }\r
+                                       else if(paramId != 0) \r
+                                       {\r
+//                                             RegisterObject(paramId, objParam, null, paramValuesId, null, indices);\r
+                                       }\r
+                                       else \r
+                                       {\r
+                                       }\r
+                                       i++;\r
                                }\r
-                               i++;\r
+                               xmlReader.ReadEndElement();\r
                        }\r
-\r
+                       else\r
+                       {\r
+                               xmlReader.Read();\r
+                       }\r
+                       \r
                        message.ParamNames = (string[]) paramNames.ToArray(typeof(string));\r
                        message.ParamValues = paramValues.ToArray();\r
-                       xmlReader.ReadEndElement();\r
                        RegisterObject(paramValuesId, message.ParamValues, null, 0, null, null);\r
                        return true;\r
-               }
+               }\r
 \r
                void DeserializeHeaders (ArrayList headers)\r
                {\r
@@ -290,10 +302,11 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        }\r
                        \r
                        xmlReader.ReadEndElement ();\r
-               }
-               \r               Header DeserializeHeader ()
-               {
-                       Header h = new Header (xmlReader.LocalName, null);
+               }\r
+               \r
+               Header DeserializeHeader ()\r
+               {\r
+                       Header h = new Header (xmlReader.LocalName, null);\r
                        h.HeaderNamespace = xmlReader.NamespaceURI;\r
                        h.MustUnderstand = xmlReader.GetAttribute ("mustUnderstand", SoapTypeMapper.SoapEnvelopeNamespace) == "1";\r
                        \r
@@ -325,13 +338,23 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                \r
                private object DeserializeArray(long id)\r
                {\r
+                       // Special case for base64 byte arrays\r
+                       if (GetComponentType () == typeof(byte[])) {\r
+                               byte[] data = Convert.FromBase64String (xmlReader.ReadElementString());\r
+                               RegisterObject(id, data, null, 0, null, null);\r
+                               return data;\r
+                       }\r
+                       \r
                        // Get the array properties\r
                        string strArrayType = xmlReader["arrayType", SoapTypeMapper.SoapEncodingNamespace];\r
-                       string[] arrayInfo = strArrayType.Split(':','[',',',']');\r
-                       int numberOfDims = arrayInfo.Length - 3;\r
+                       string[] arrayInfo = strArrayType.Split(':');\r
+                       int arraySuffixInfo = arrayInfo[1].LastIndexOf('[');\r
+                       String arrayElementType = arrayInfo[1].Substring(0, arraySuffixInfo);\r
+                       String arraySuffix = arrayInfo[1].Substring(arraySuffixInfo);\r
+                       string[] arrayDims = arraySuffix.Substring(1,arraySuffix.Length-2).Trim().Split(',');\r
+                       int numberOfDims = arrayDims.Length;\r
                        int[] lengths = new int[numberOfDims];\r
-                       string[] arrayDims = new String[numberOfDims];\r
-                       Array.Copy(arrayInfo, 2, arrayDims, 0, numberOfDims);\r
+                       \r
                        for (int i=0; i < numberOfDims; i++)\r
                        {\r
                                lengths[i] = Convert.ToInt32(arrayDims[i]);\r
@@ -340,7 +363,7 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        int[] indices = new int[numberOfDims];\r
 \r
                        // Create the array\r
-                       Type arrayType = mapper[new Element(arrayInfo[0], arrayInfo[1], xmlReader.LookupNamespace(arrayInfo[0]))];\r
+                       Type arrayType = mapper.GetType (arrayElementType, xmlReader.LookupNamespace(arrayInfo[0]));\r
                        Array array = Array.CreateInstance(\r
                                arrayType,\r
                                lengths);\r
@@ -350,13 +373,11 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                                indices[i] = array.GetLowerBound(i);\r
                        }\r
 \r
-\r
                        // Deserialize the array items\r
                        int arrayDepth = xmlReader.Depth;\r
                        xmlReader.Read();\r
                        while(xmlReader.Depth > arrayDepth)\r
                        {\r
-\r
                                Type itemType = GetComponentType();\r
                                if(itemType == null) \r
                                        itemType = array.GetType().GetElementType();\r
@@ -417,13 +438,7 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                private object Deserialize()\r
                {\r
                        object objReturn = null;\r
-                       Element element = new Element(\r
-                               xmlReader.Prefix,\r
-                               xmlReader.LocalName,\r
-                               xmlReader.NamespaceURI);\r
-\r
-\r
-                       Type type = mapper[element];\r
+                       Type type = mapper.GetType (xmlReader.LocalName, xmlReader.NamespaceURI);\r
 \r
                        // Get the Id\r
                        long id = GetId();\r
@@ -454,10 +469,13 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        bool NeedsSerializationInfo = false;\r
                        bool hasFixup;\r
 \r
-                       if(SoapTypeMapper.CanBeValue(type)) \r
+                       // in case of String & TimeSpan we should allways use 'ReadInternalSoapValue' method\r
+                       // in case of other internal types, we should use ReadInternalSoapValue' only if it is NOT\r
+                       // the root object, means it is a data member of another object that is being serialized.\r
+                       bool shouldReadInternal = (type == typeof(String) || type == typeof(TimeSpan) );\r
+                       if(shouldReadInternal || mapper.IsInternalSoapType (type) && (indices != null || parentMemberInfo != null) ) \r
                        {\r
-                               string elementString = xmlReader.ReadElementString();\r
-                               object obj = SoapTypeMapper.ParseXsdValue (elementString, type);\r
+                               object obj = mapper.ReadInternalSoapValue (this, type);\r
                                \r
                                if(id != 0) \r
                                        RegisterObject(id, obj, info, parentId, parentMemberInfo, indices);\r
@@ -508,16 +526,25 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        Type currentType = obj.GetType();\r
                        TypeMetadata tm = GetTypeMetadata (currentType);\r
 \r
-                       int objDepth = xmlReader.Depth;\r
                        object[] data = new object[tm.MemberInfos.Length];\r
                        xmlReader.Read();\r
-                       for(int i = 0; i < tm.MemberInfos.Length; i++)\r
+                       xmlReader.MoveToContent ();\r
+                       while (xmlReader.NodeType != XmlNodeType.EndElement)\r
                        {\r
+                               if (xmlReader.NodeType != XmlNodeType.Element) {\r
+                                       xmlReader.Skip ();\r
+                                       continue;\r
+                               }\r
+                               \r
                                object fieldObject;\r
                                long fieldId, fieldHref;\r
-                               int index = (int) tm.Indices[xmlReader.LocalName];\r
+\r
+                               object indexob = tm.Indices [xmlReader.LocalName];\r
+                               if (indexob == null)\r
+                                       throw new SerializationException ("Field \"" + xmlReader.LocalName + "\" not found in class " + currentType.FullName);\r
+                               \r
+                               int index = (int) indexob;\r
                                FieldInfo fieldInfo = (tm.MemberInfos[index]) as FieldInfo;\r
-                               if(fieldInfo == null) continue;\r
 \r
                                fieldObject = \r
                                        DeserializeComponent(fieldInfo.FieldType,\r
@@ -569,7 +596,7 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        while(xmlReader.Depth > initialDepth) \r
                        {\r
                                Type fieldType = GetComponentType();\r
-                               string fieldName = xmlReader.LocalName;\r
+                               string fieldName = XmlConvert.DecodeName (xmlReader.LocalName);\r
                                object objField = DeserializeComponent(\r
                                        fieldType,\r
                                        out fieldId,\r
@@ -632,7 +659,9 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        if(componentId != 0)\r
                        {\r
                                // It's a string\r
-                               return xmlReader.ReadElementString();\r
+                               string str = xmlReader.ReadElementString();\r
+                               objMgr.RegisterObject (str, componentId);\r
+                               return str;\r
                        }\r
                        if(componentHref != 0)\r
                        {\r
@@ -716,13 +745,22 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        tm.MemberInfos = FormatterServices.GetSerializableMembers (type, _context);\r
                        \r
                        tm.Indices      = new Hashtable();\r
-                       for(int i = 0; i < tm.MemberInfos.Length; i++) \r
-                               tm.Indices.Add (tm.MemberInfos[i].Name, i);\r
+                       for(int i = 0; i < tm.MemberInfos.Length; i++) {\r
+                               SoapFieldAttribute at = (SoapFieldAttribute) InternalRemotingServices.GetCachedSoapAttribute (tm.MemberInfos[i]);\r
+                               tm.Indices [XmlConvert.EncodeLocalName (at.XmlElementName)] = i;\r
+                       }\r
                        \r
                        _fieldIndices[type] = tm;\r
                        return tm;\r
                }\r
                \r
+               public Type GetTypeFromQName (string qname)\r
+               {\r
+                       string[] strName = qname.Split(':');\r
+                       string namespaceURI = xmlReader.LookupNamespace (strName[0]);\r
+                       return mapper.GetType (strName[1], namespaceURI);\r
+               }\r
+               \r
                #endregion\r
        }\r
 }\r