2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Runtime.Serialization.Formatters.Soap / System.Runtime.Serialization.Formatters.Soap / SoapReader.cs
index 843c3b168cd5c4862480f2014a9c12ee87419b50..ee345899019a836eff597544315c856cc6cf3b2d 100755 (executable)
@@ -5,6 +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
 using System;\r
 using System.IO;\r
@@ -14,6 +35,7 @@ using System.Reflection;
 using System.Collections;\r
 using System.Runtime.Remoting;\r
 using System.Runtime.Serialization;\r
+using System.Runtime.Remoting.Messaging;\r
 \r
 namespace System.Runtime.Serialization.Formatters.Soap {\r
        internal sealed class SoapReader {\r
@@ -28,6 +50,13 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                private ISurrogateSelector _surrogateSelector;\r
                private XmlTextReader xmlReader;\r
                private Hashtable _fieldIndices;\r
+               private long _topObjectId = 1;\r
+               \r
+               class TypeMetadata\r
+               {\r
+                       public MemberInfo[] MemberInfos;\r
+                       public Hashtable Indices;\r
+               }\r
 \r
                #endregion\r
 \r
@@ -60,7 +89,8 @@ 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
                        mapper = new SoapTypeMapper(_binder);\r
@@ -69,28 +99,48 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        {\r
                                // SOAP-ENV:Envelope\r
                                xmlReader.MoveToContent();\r
-                               xmlReader.Read();\r
+                               xmlReader.ReadStartElement ();
+                               xmlReader.MoveToContent();
+                               
+                               // Read headers
+                               while (!(xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace))
+                               {\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
+                                               xmlReader.Skip ();\r
+                                       xmlReader.MoveToContent();\r
+                               }
+                               \r
                                // SOAP-ENV:Body\r
-                               xmlReader.Read();\r
+                               xmlReader.ReadStartElement();\r
+                               xmlReader.MoveToContent();\r
 \r
                                // The root object\r
-                               if(soapMessage != null)\r
+                               if (soapMessage != null)\r
                                {\r
-                                       if(DeserializeMessage(soapMessage)) \r
-                                       {\r
-                                               RegisterObject(1, soapMessage, null, 0, null, null);\r
+                                       if (DeserializeMessage (soapMessage)) {\r
+                                               _topObjectId = NextAvailableId;\r
+                                               RegisterObject (_topObjectId, soapMessage, null, 0, null, null);\r
                                        }\r
+                                       xmlReader.MoveToContent();\r
+                                       \r
+                                       if (headers != null)\r
+                                               soapMessage.Headers = (Header[]) headers.ToArray (typeof(Header));\r
                                }\r
                                \r
-                               if(xmlReader.NodeType != XmlNodeType.EndElement)\r
-                               {\r
-                                       do\r
-                                       {\r
-                                               Deserialize();\r
+                               while (xmlReader.NodeType != XmlNodeType.EndElement)\r
+                                       Deserialize();\r
+                                       \r
+                               // SOAP-ENV:Body\r
+                               xmlReader.ReadEndElement ();\r
+                               xmlReader.MoveToContent();\r
 \r
-                                       }\r
-                                       while(xmlReader.NodeType != XmlNodeType.EndElement); \r
-                               }\r
+                               // SOAP-ENV:Envelope\r
+                               xmlReader.ReadEndElement ();\r
                        }\r
                        finally \r
                        {\r
@@ -110,7 +160,7 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        {\r
                                objMgr.DoFixups();\r
                                objMgr.RaiseDeserializationEvent();\r
-                               return objMgr.GetObject(1);\r
+                               return objMgr.GetObject(_topObjectId);\r
                        }\r
                }\r
 \r
@@ -143,10 +193,12 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                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
+                       if(strValue == null) {\r
+                               if(GetId() != 0) return typeof(string);\r
+                               return null;\r
+                       }\r
                        string[] strName = strValue.Split(':');\r
                        string namespaceURI = xmlReader.LookupNamespace(strName[0]);\r
                        type = mapper[new Element(string.Empty, strName[1], namespaceURI)];\r
@@ -176,55 +228,119 @@ 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
+               void DeserializeHeaders (ArrayList headers)\r
+               {\r
+                       xmlReader.ReadStartElement ();\r
+                       xmlReader.MoveToContent ();\r
+                       \r
+                       while (xmlReader.NodeType != XmlNodeType.EndElement) \r
+                       {\r
+                               if (xmlReader.NodeType != XmlNodeType.Element) { xmlReader.Skip(); continue; }\r
+                               \r
+                               if (xmlReader.GetAttribute ("root", SoapTypeMapper.SoapEncodingNamespace) == "1")\r
+                                       headers.Add (DeserializeHeader ());\r
+                               else\r
+                                       Deserialize ();\r
+\r
+                               xmlReader.MoveToContent ();\r
+                       }\r
+                       \r
+                       xmlReader.ReadEndElement ();\r
+               }
+               \r               Header DeserializeHeader ()
+               {
+                       Header h = new Header (xmlReader.LocalName, null);
+                       h.HeaderNamespace = xmlReader.NamespaceURI;\r
+                       h.MustUnderstand = xmlReader.GetAttribute ("mustUnderstand", SoapTypeMapper.SoapEnvelopeNamespace) == "1";\r
+                       \r
+                       object value;\r
+                       long fieldId, fieldHref;\r
+                       long idHeader = NextAvailableId;\r
+                       FieldInfo fieldInfo = typeof(Header).GetField ("Value");\r
+\r
+                       value = DeserializeComponent (null, out fieldId, out fieldHref, idHeader, fieldInfo, null);\r
+                       h.Value = value;\r
+\r
+                       if(fieldHref != 0 && value == null)\r
+                       {\r
+                               RecordFixup (idHeader, fieldHref, h, null, null, fieldInfo, null);\r
+                       }\r
+                       else if(value != null && value.GetType().IsValueType && fieldId != 0)\r
+                       {\r
+                               RecordFixup (idHeader, fieldId, h, null, null, fieldInfo, null);\r
+                       }\r
+                       else if(fieldId != 0)\r
+                       {\r
+                               RegisterObject (fieldId, value, null, idHeader, fieldInfo, null);\r
+                       }\r
+                       \r
+                       RegisterObject (idHeader, h, null, 0, null, null);\r
+                       return h;\r
                }\r
 \r
                \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
@@ -250,13 +366,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
@@ -359,7 +473,7 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                                string elementString = xmlReader.ReadElementString();\r
                                object obj = SoapTypeMapper.ParseXsdValue (elementString, type);\r
                                \r
-                               if(id > 0) \r
+                               if(id != 0) \r
                                        RegisterObject(id, obj, info, parentId, parentMemberInfo, indices);\r
 \r
                                return obj;\r
@@ -406,28 +520,16 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                {\r
                        hasFixup = false;\r
                        Type currentType = obj.GetType();\r
-                       MemberInfo[] memberInfos = \r
-                               FormatterServices.GetSerializableMembers(currentType, _context);\r
-                       Hashtable indices = (Hashtable) _fieldIndices[currentType];\r
-                       if(indices == null) \r
-                       {\r
-                               indices = new Hashtable();\r
-                               for(int i = 0; i < memberInfos.Length; i++) \r
-                               {\r
-                                       indices.Add(memberInfos[i].Name, i);\r
-                               }\r
-                               _fieldIndices[currentType] = indices;\r
-                       }\r
+                       TypeMetadata tm = GetTypeMetadata (currentType);\r
 \r
-                       int objDepth = xmlReader.Depth;\r
-                       object[] data = new object[memberInfos.Length];\r
+                       object[] data = new object[tm.MemberInfos.Length];\r
                        xmlReader.Read();\r
-                       for(int i = 0; i < memberInfos.Length; i++)\r
+                       for(int i = 0; i < tm.MemberInfos.Length; i++)\r
                        {\r
                                object fieldObject;\r
                                long fieldId, fieldHref;\r
-                               int index = (int) indices[xmlReader.LocalName];\r
-                               FieldInfo fieldInfo = (memberInfos[index]) as FieldInfo;\r
+                               int index = (int) tm.Indices[xmlReader.LocalName];\r
+                               FieldInfo fieldInfo = (tm.MemberInfos[index]) as FieldInfo;\r
                                if(fieldInfo == null) continue;\r
 \r
                                fieldObject = \r
@@ -459,7 +561,7 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                                }\r
                        }\r
 \r
-                       FormatterServices.PopulateObjectMembers(obj, memberInfos, data);\r
+                       FormatterServices.PopulateObjectMembers (obj, tm.MemberInfos, data);\r
                        return obj;\r
                }\r
 \r
@@ -618,7 +720,21 @@ namespace System.Runtime.Serialization.Formatters.Soap {
                        }\r
                }\r
 \r
-\r
+               TypeMetadata GetTypeMetadata (Type type)\r
+               {\r
+                       TypeMetadata tm = _fieldIndices[type] as TypeMetadata;\r
+                       if (tm != null) return tm;\r
+                       \r
+                       tm = new TypeMetadata ();\r
+                       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
+                       \r
+                       _fieldIndices[type] = tm;\r
+                       return tm;\r
+               }\r
                \r
                #endregion\r
        }\r