// 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.Xml;\r
+using System.Xml.Schema;\r
using System.Reflection;\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 class SoapReader: ISoapReader {\r
- public event ElementReadEventHandler ElementReadEvent;\r
+ internal sealed class SoapReader {\r
+\r
+ #region Fields\r
+\r
+ private SerializationBinder _binder;\r
+ private SoapTypeMapper mapper;\r
+ private ObjectManager objMgr;\r
+ private StreamingContext _context;\r
+ private long _nextAvailableId = long.MaxValue;\r
+ private ISurrogateSelector _surrogateSelector;\r
+ private XmlTextReader xmlReader;\r
+ private Hashtable _fieldIndices;\r
+ private long _topObjectId = 1;\r
\r
- public SoapReader(ISoapParser parser) {\r
- // register the SoapElementReadEvent handler\r
- parser.SoapElementReadEvent += new SoapElementReadEventHandler(SoapElementRead);\r
+ class TypeMetadata\r
+ {\r
+ public MemberInfo[] MemberInfos;\r
+ public Hashtable Indices;\r
+ }\r
+\r
+ #endregion\r
+\r
+ #region Properties\r
+\r
+ private long NextAvailableId\r
+ {\r
+ get \r
+ {\r
+ _nextAvailableId--;\r
+ return _nextAvailableId;\r
+ }\r
}\r
+\r
+ #endregion\r
+\r
+ #region Constructors\r
\r
- // called when SoapElementReadEvent is raized by the SoapParser object\r
- public void SoapElementRead(ISoapParser sender, SoapElementReadEventArgs e) {\r
- Queue elementQueue = e.ElementQueue;\r
- Queue elementInfoQueue = new Queue();\r
- SoapSerializationEntry root = (SoapSerializationEntry) elementQueue.Dequeue();\r
- \r
- ElementInfo rootInfo = GetElementInfo(root);\r
- SoapSerializationEntry field;\r
- while(elementQueue.Count > 0){\r
- field = (SoapSerializationEntry) elementQueue.Dequeue();\r
- elementInfoQueue.Enqueue(GetElementInfo(field));\r
+ public SoapReader(SerializationBinder binder, ISurrogateSelector selector, StreamingContext context) \r
+ {\r
+ _binder = binder;\r
+ objMgr = new ObjectManager(selector, context);\r
+ _context = context;\r
+ _surrogateSelector = selector;\r
+ _fieldIndices = new Hashtable();\r
+ }\r
+\r
+ #endregion\r
+\r
+ #region Public Methods\r
+\r
+ public object Deserialize(Stream inStream, ISoapMessage soapMessage) \r
+ {
+ ArrayList headers = null;\r
+ xmlReader = new XmlTextReader(inStream);\r
+ xmlReader.WhitespaceHandling = WhitespaceHandling.None;\r
+ mapper = new SoapTypeMapper(_binder);\r
+\r
+ try\r
+ {\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))
+ {\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.ReadStartElement();\r
+ xmlReader.MoveToContent();\r
+\r
+ // The root object\r
+ if (soapMessage != null)\r
+ {\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
+ while (xmlReader.NodeType != XmlNodeType.EndElement)\r
+ Deserialize();\r
+ \r
+ // SOAP-ENV:Body\r
+ xmlReader.ReadEndElement ();\r
+ xmlReader.MoveToContent();\r
+\r
+ // SOAP-ENV:Envelope\r
+ xmlReader.ReadEndElement ();\r
+ }\r
+ finally \r
+ {\r
+ if(xmlReader != null) xmlReader.Close();\r
}\r
\r
- // raise the ElementReadEvent\r
- ElementReadEvent(this,new ElementReadEventArgs(rootInfo, elementInfoQueue));\r
+ return TopObject;\r
}\r
\r
- // Converts the text information from the SoapParser into\r
- // information that with by used by the ObjectReader to reconstruct\r
- // the object.\r
- private ElementInfo GetElementInfo(SoapSerializationEntry entry) {\r
- SoapTypeMapping mapping = new SoapTypeMapping(entry.elementName, entry.elementNamespace);\r
- Type elementType = SoapTypeMapper.GetType(mapping);\r
+ #endregion\r
+\r
+ #region Private Methods\r
+\r
+ private object TopObject \r
+ {\r
+ get \r
+ {\r
+ objMgr.DoFixups();\r
+ objMgr.RaiseDeserializationEvent();\r
+ return objMgr.GetObject(_topObjectId);\r
+ }\r
+ }\r
+\r
+ private bool IsNull()\r
+ {\r
+ string tmp = xmlReader["null", XmlSchema.InstanceNamespace];\r
+ return (tmp == null || tmp == string.Empty)?false:true;\r
+ }\r
+\r
+ private long GetId()\r
+ {\r
+ long id = 0;\r
+\r
+ string strId = xmlReader["id"];\r
+ if(strId == null || strId == String.Empty) return 0;\r
+ id = Convert.ToInt64(strId.Substring(4));\r
+ return id;\r
+ }\r
+\r
+ private long GetHref()\r
+ {\r
+ long href = 0;\r
\r
+ string strHref = xmlReader["href"];\r
+ if(strHref == null || strHref == string.Empty) return 0;\r
+ href = Convert.ToInt64(strHref.Substring(5));\r
+ return href;\r
+ }\r
+\r
+ private Type GetComponentType()\r
+ {\r
+ Type type = null;\r
\r
- long id = 0;\r
- ElementType elementId = ElementType.Nothing;\r
- ICollection attrLst = entry.elementAttributes;\r
- int[] arrayRank = null;\r
- foreach(SoapAttributeStruct attr in attrLst){\r
- if(attr.attributeName == "id"){\r
- string attrId = ((string)attr.attributeValue).Remove(0,4);\r
- id = (new FormatterConverter()).ToInt64(attrId);\r
- elementId = ElementType.Id;\r
- } else if(attr.attributeName == "href") {\r
- string attrId = ((string)attr.attributeValue).Remove(0,5);\r
- id = (new FormatterConverter()).ToInt64(attrId);\r
- elementId = ElementType.Href;\r
- } else if(attr.attributeName == "xsi:null" && attr.attributeValue == "1") {\r
- elementId = ElementType.Null;\r
- } else if(attr.attributeName == "SOAP-ENC:arrayType") {\r
- string[] tokens = attr.attributeValue.Split(new System.Char[] {'[',',',']'});\r
- mapping = new SoapTypeMapping(tokens[0], attr.prefix);\r
- elementType = SoapTypeMapper.GetType(mapping);\r
- arrayRank = new int[tokens.Length - 2];\r
- for(int i=0; i<tokens.Length-2; i++) {\r
- arrayRank[i] = Convert.ToInt32(tokens[i+1]);\r
- }\r
- Type tempType = Type.GetType(elementType.ToString()+"[]");\r
+ string strValue = xmlReader["type", XmlSchema.InstanceNamespace];\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
+\r
+ return type;\r
+ }\r
+\r
+ private bool DeserializeMessage(ISoapMessage message) \r
+ {\r
+ string typeNamespace, assemblyName;\r
+\r
+ if(xmlReader.Name == SoapTypeMapper.SoapEnvelopePrefix + ":Fault")\r
+ {\r
+ Deserialize();\r
+ return false;\r
+ }\r
+\r
+ SoapServices.DecodeXmlNamespaceForClrTypeNamespace(\r
+ xmlReader.NamespaceURI,\r
+ out typeNamespace,\r
+ out assemblyName);\r
+ message.MethodName = xmlReader.LocalName;\r
+ message.XmlNameSpace = xmlReader.NamespaceURI;\r
+\r
+ ArrayList paramNames = new ArrayList();\r
+ ArrayList paramValues = new ArrayList();\r
+ long paramValuesId = NextAvailableId;\r
+ int[] indices = new int[1];\r
+\r
+ if (!xmlReader.IsEmptyElement)\r
+ {\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(tempType == null) {\r
- AssemblyName assName = elementType.Assembly.GetName();\r
- Assembly ass = Assembly.Load(assName);\r
- tempType = ass.GetType(elementType.ToString()+"[]", true);\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
- elementType = tempType;\r
- } else if(attr.attributeName == "xsi:type") {\r
- mapping = new SoapTypeMapping(attr.attributeValue, attr.prefix);\r
- elementType = SoapTypeMapper.GetType(mapping);\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
+ xmlReader.ReadEndElement();\r
+ }\r
+ else\r
+ {\r
+ xmlReader.Read();\r
+ }\r
+ \r
+ message.ParamNames = (string[]) paramNames.ToArray(typeof(string));\r
+ message.ParamValues = paramValues.ToArray();\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
- ElementInfo elementInfo = new ElementInfo(elementType, entry.elementName, entry.elementValue, elementId, id, arrayRank);\r
- return elementInfo;\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
+ int numberOfDims = arrayInfo.Length - 3;\r
+ int[] lengths = new int[numberOfDims];\r
+ string[] arrayDims = new String[numberOfDims];\r
+ Array.Copy(arrayInfo, 2, arrayDims, 0, numberOfDims);\r
+ for (int i=0; i < numberOfDims; i++)\r
+ {\r
+ lengths[i] = Convert.ToInt32(arrayDims[i]);\r
+ }\r
+\r
+ 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
+ Array array = Array.CreateInstance(\r
+ arrayType,\r
+ lengths);\r
+\r
+ for(int i = 0; i < numberOfDims; i++) \r
+ {\r
+ indices[i] = array.GetLowerBound(i);\r
+ }\r
+\r
+ // Deserialize the array items\r
+ int arrayDepth = xmlReader.Depth;\r
+ xmlReader.Read();\r
+ while(xmlReader.Depth > arrayDepth)\r
+ {\r
+ Type itemType = GetComponentType();\r
+ if(itemType == null) \r
+ itemType = array.GetType().GetElementType();\r
+ long itemId, itemHref;\r
+\r
+ object objItem = DeserializeComponent(itemType,\r
+ out itemId,\r
+ out itemHref,\r
+ id,\r
+ null,\r
+ indices);\r
+ if(itemHref != 0)\r
+ {\r
+ object obj = objMgr.GetObject(itemHref);\r
+ if(obj != null)\r
+ array.SetValue(obj, indices);\r
+ else\r
+ RecordFixup(id, itemHref, array, null, null, null, indices);\r
+ }\r
+ else if(objItem != null && objItem.GetType().IsValueType && itemId != 0)\r
+ {\r
+ RecordFixup(id, itemId, array, null, null, null, indices);\r
+ }\r
+ else if(itemId != 0)\r
+ {\r
+ RegisterObject(itemId, objItem, null, id, null, indices);\r
+ array.SetValue(objItem, indices);\r
+ }\r
+ else \r
+ {\r
+ array.SetValue(objItem, indices);\r
+ }\r
+\r
+ // Get the next indice\r
+ for(int dim = array.Rank - 1; dim >= 0; dim--)\r
+ {\r
+ indices[dim]++;\r
+ if(indices[dim] > array.GetUpperBound(dim))\r
+ {\r
+ if(dim > 0)\r
+ {\r
+ indices[dim] = array.GetLowerBound(dim);\r
+ continue;\r
+ }\r
+ \r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ RegisterObject(id, array, null, 0, null, null);\r
+ xmlReader.ReadEndElement();\r
+ return array;\r
+\r
+ }\r
+\r
+\r
+ 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
+\r
+ // Get the Id\r
+ long id = GetId();\r
+ id = (id == 0)?1:id;\r
+\r
+ if(type == typeof(Array))\r
+ {\r
+ objReturn = DeserializeArray(id);\r
+ }\r
+ else\r
+ {\r
+ objReturn = DeserializeObject(type, id, 0, null, null);\r
+\r
+ }\r
+\r
+ return objReturn;\r
+ }\r
+\r
+\r
+ private object DeserializeObject(\r
+ Type type, \r
+ long id, \r
+ long parentId, \r
+ MemberInfo parentMemberInfo,\r
+ int[] indices)\r
+ {\r
+ SerializationInfo info = null;\r
+ bool NeedsSerializationInfo = false;\r
+ bool hasFixup;\r
+\r
+ if(SoapTypeMapper.CanBeValue(type)) \r
+ {\r
+ string elementString = xmlReader.ReadElementString();\r
+ object obj = SoapTypeMapper.ParseXsdValue (elementString, type);\r
+ \r
+ if(id != 0) \r
+ RegisterObject(id, obj, info, parentId, parentMemberInfo, indices);\r
+\r
+ return obj;\r
+ }\r
+ object objReturn = \r
+ FormatterServices.GetUninitializedObject(type);\r
+ if(objReturn is ISerializable)\r
+ NeedsSerializationInfo = true;\r
+\r
+ if(_surrogateSelector != null && NeedsSerializationInfo == false)\r
+ {\r
+ ISurrogateSelector selector;\r
+ ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate(\r
+ type,\r
+ _context,\r
+ out selector);\r
+ NeedsSerializationInfo |= (surrogate != null);\r
+ }\r
+\r
+ if(NeedsSerializationInfo)\r
+ {\r
+ objReturn = \r
+ DeserializeISerializableObject(objReturn, id, out info, out hasFixup);\r
+ }\r
+ else\r
+ {\r
+ objReturn = \r
+ DeserializeSimpleObject(objReturn, id, out hasFixup);\r
+ if(!hasFixup && objReturn is IObjectReference)\r
+ objReturn = ((IObjectReference)objReturn).GetRealObject(_context);\r
+ }\r
+\r
+ RegisterObject(id, objReturn, info, parentId, parentMemberInfo, indices);\r
+ xmlReader.ReadEndElement();\r
+ return objReturn;\r
+ }\r
+\r
+\r
+ private object DeserializeSimpleObject(\r
+ object obj,\r
+ long id,\r
+ out bool hasFixup\r
+ )\r
+ {\r
+ hasFixup = false;\r
+ Type currentType = obj.GetType();\r
+ TypeMetadata tm = GetTypeMetadata (currentType);\r
+\r
+ object[] data = new object[tm.MemberInfos.Length];\r
+ xmlReader.Read();\r
+ for(int i = 0; i < tm.MemberInfos.Length; i++)\r
+ {\r
+ object fieldObject;\r
+ long fieldId, fieldHref;\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
+ DeserializeComponent(fieldInfo.FieldType,\r
+ out fieldId,\r
+ out fieldHref,\r
+ id,\r
+ fieldInfo,\r
+ null);\r
+\r
+ data[index] = fieldObject;\r
+\r
+ if(fieldHref != 0 && fieldObject == null)\r
+ {\r
+ RecordFixup(id, fieldHref, obj, null, null, fieldInfo, null);\r
+ hasFixup = true;\r
+ continue;\r
+ }\r
+ if(fieldObject != null && fieldObject.GetType().IsValueType && fieldId != 0)\r
+ {\r
+ RecordFixup(id, fieldId, obj, null, null, fieldInfo, null);\r
+ hasFixup = true;\r
+ continue;\r
+ }\r
+\r
+ if(fieldId != 0)\r
+ {\r
+ RegisterObject(fieldId, fieldObject, null, id, fieldInfo, null);\r
+ }\r
+ }\r
+\r
+ FormatterServices.PopulateObjectMembers (obj, tm.MemberInfos, data);\r
+ return obj;\r
+ }\r
+\r
+\r
+ private object DeserializeISerializableObject(\r
+ object obj, \r
+ long id, \r
+ out SerializationInfo info,\r
+ out bool hasFixup\r
+ )\r
+ {\r
+ long fieldId, fieldHref;\r
+ info = new SerializationInfo(obj.GetType(), new FormatterConverter());\r
+ hasFixup = false;\r
+ \r
+ int initialDepth = xmlReader.Depth;\r
+ xmlReader.Read();\r
+ while(xmlReader.Depth > initialDepth) \r
+ {\r
+ Type fieldType = GetComponentType();\r
+ string fieldName = xmlReader.LocalName;\r
+ object objField = DeserializeComponent(\r
+ fieldType,\r
+ out fieldId,\r
+ out fieldHref,\r
+ id,\r
+ null,\r
+ null);\r
+ if(fieldHref != 0 && objField == null) \r
+ {\r
+ RecordFixup(id, fieldHref, obj, info, fieldName, null, null);\r
+ hasFixup = true;\r
+ continue;\r
+ }\r
+ else if(fieldId != 0 && objField.GetType().IsValueType)\r
+ {\r
+ RecordFixup(id, fieldId, obj, info, fieldName, null, null);\r
+ hasFixup = true;\r
+ continue;\r
+ }\r
+ \r
+ if(fieldId != 0) \r
+ {\r
+ RegisterObject(fieldId, objField, null, id, null, null);\r
+ }\r
+\r
+ info.AddValue(fieldName, objField, (fieldType != null)?fieldType:typeof(object));\r
+ }\r
+\r
+ return obj;\r
+ }\r
+\r
+\r
+ private object DeserializeComponent(\r
+ Type componentType, \r
+ out long componentId,\r
+ out long componentHref,\r
+ long parentId,\r
+ MemberInfo parentMemberInfo,\r
+ int[] indices)\r
+ {\r
+ object objReturn;\r
+ componentId = 0;\r
+ componentHref = 0;\r
+\r
+ if(IsNull())\r
+ {\r
+ xmlReader.Read();\r
+ return null;\r
+ }\r
+\r
+ Type xsiType = GetComponentType();\r
+ if(xsiType != null) componentType = xsiType;\r
+\r
+ if(xmlReader.HasAttributes)\r
+ {\r
+ componentId = GetId();\r
+ componentHref = GetHref();\r
+ }\r
+\r
+ if(componentId != 0)\r
+ {\r
+ // It's a string\r
+ return xmlReader.ReadElementString();\r
+ }\r
+ if(componentHref != 0)\r
+ {\r
+ // Move the cursor to the next node\r
+ xmlReader.Read();\r
+ return objMgr.GetObject(componentHref);\r
+ }\r
+\r
+ if(componentType == null)\r
+ return xmlReader.ReadElementString();\r
+\r
+ componentId = NextAvailableId;\r
+ objReturn = DeserializeObject(\r
+ componentType,\r
+ componentId,\r
+ parentId,\r
+ parentMemberInfo,\r
+ indices);\r
+ return objReturn;\r
+ }\r
+\r
+ public void RecordFixup(\r
+ long parentObjectId, \r
+ long childObjectId,\r
+ object parentObject,\r
+ SerializationInfo info,\r
+ string fieldName,\r
+ MemberInfo memberInfo,\r
+ int[] indices)\r
+ {\r
+ if(info != null)\r
+ {\r
+ objMgr.RecordDelayedFixup(parentObjectId, fieldName, childObjectId);\r
+ }\r
+ else if (parentObject is Array) \r
+ {\r
+ if (indices.Length == 1)\r
+ objMgr.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);\r
+ else\r
+ objMgr.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);\r
+ }\r
+ else \r
+ {\r
+ objMgr.RecordFixup (parentObjectId, memberInfo, childObjectId);\r
+ }\r
+ }\r
+\r
+ private void RegisterObject (\r
+ long objectId, \r
+ object objectInstance, \r
+ SerializationInfo info, \r
+ long parentObjectId, \r
+ MemberInfo parentObjectMember, \r
+ int[] indices)\r
+ {\r
+ if (parentObjectId == 0) indices = null;\r
+\r
+ if (!objectInstance.GetType().IsValueType || parentObjectId == 0)\r
+ objMgr.RegisterObject (objectInstance, objectId, info, 0, null, null);\r
+ else\r
+ {\r
+ if(objMgr.GetObject(objectId) != null)\r
+ throw new SerializationException("Object already registered");\r
+ if (indices != null) indices = (int[])indices.Clone();\r
+ objMgr.RegisterObject (\r
+ objectInstance, \r
+ objectId, \r
+ info, \r
+ parentObjectId, \r
+ parentObjectMember, \r
+ indices);\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
}\r