// 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
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
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
#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
{\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
{\r
objMgr.DoFixups();\r
objMgr.RaiseDeserializationEvent();\r
- return objMgr.GetObject(1);\r
+ return objMgr.GetObject(_topObjectId);\r
}\r
}\r
\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
+ 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
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
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
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
{\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
}\r
}\r
\r
- FormatterServices.PopulateObjectMembers(obj, memberInfos, data);\r
+ FormatterServices.PopulateObjectMembers (obj, tm.MemberInfos, data);\r
return obj;\r
}\r
\r
}\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