Update mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng/RelaxngPattern.cs
[mono.git] / mcs / class / System.Runtime.Serialization.Formatters.Soap / System.Runtime.Serialization.Formatters.Soap / SoapReader.cs
1 // created on 24/04/2003 at 15:35\r
2 //\r
3 //      System.Runtime.Serialization.Formatters.Soap.SoapReader\r
4 //\r
5 //      Authors:\r
6 //              Jean-Marc Andre (jean-marc.andre@polymtl.ca)\r
7 //\r
8 \r
9 //\r
10 // Permission is hereby granted, free of charge, to any person obtaining\r
11 // a copy of this software and associated documentation files (the\r
12 // "Software"), to deal in the Software without restriction, including\r
13 // without limitation the rights to use, copy, modify, merge, publish,\r
14 // distribute, sublicense, and/or sell copies of the Software, and to\r
15 // permit persons to whom the Software is furnished to do so, subject to\r
16 // the following conditions:\r
17 // \r
18 // The above copyright notice and this permission notice shall be\r
19 // included in all copies or substantial portions of the Software.\r
20 // \r
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
28 //\r
29 \r
30 using System;\r
31 using System.IO;\r
32 using System.Xml;\r
33 using System.Xml.Schema;\r
34 using System.Reflection;\r
35 using System.Collections;\r
36 using System.Runtime.Remoting;\r
37 using System.Runtime.Serialization;\r
38 using System.Runtime.Remoting.Messaging;\r
39 using System.Runtime.Remoting.Metadata;\r
40 \r
41 namespace System.Runtime.Serialization.Formatters.Soap {\r
42         internal sealed class SoapReader {\r
43 \r
44                 #region Fields\r
45 \r
46                 private SerializationBinder _binder;\r
47                 private SoapTypeMapper mapper;\r
48                 private ObjectManager objMgr;\r
49                 private StreamingContext _context;\r
50                 private long _nextAvailableId = long.MaxValue;\r
51                 private ISurrogateSelector _surrogateSelector;\r
52                 private XmlTextReader xmlReader;\r
53                 private Hashtable _fieldIndices;\r
54                 private long _topObjectId = 1;\r
55                 \r
56                 class TypeMetadata\r
57                 {\r
58                         public MemberInfo[] MemberInfos;\r
59                         public Hashtable Indices;\r
60                 }\r
61 \r
62                 #endregion\r
63 \r
64                 #region Properties\r
65 \r
66                 private long NextAvailableId\r
67                 {\r
68                         get \r
69                         {\r
70                                 _nextAvailableId--;\r
71                                 return _nextAvailableId;\r
72                         }\r
73                 }\r
74 \r
75                 #endregion\r
76 \r
77                 #region Constructors\r
78                 \r
79                 public SoapReader(SerializationBinder binder, ISurrogateSelector selector, StreamingContext context) \r
80                 {\r
81                         _binder = binder;\r
82                         objMgr = new ObjectManager(selector, context);\r
83                         _context = context;\r
84                         _surrogateSelector = selector;\r
85                         _fieldIndices = new Hashtable();\r
86                 }\r
87 \r
88                 #endregion\r
89 \r
90                 #region Public Methods\r
91 \r
92                 public object Deserialize(Stream inStream, ISoapMessage soapMessage) \r
93                 {\r
94                         ArrayList headers = null;\r
95                         xmlReader = new XmlTextReader(inStream);\r
96                         xmlReader.WhitespaceHandling = WhitespaceHandling.None;\r
97                         mapper = new SoapTypeMapper(_binder);\r
98 \r
99                         try\r
100                         {\r
101                                 // SOAP-ENV:Envelope\r
102                                 xmlReader.MoveToContent();\r
103                                 xmlReader.ReadStartElement ();\r
104                                 xmlReader.MoveToContent();\r
105                                 \r
106                                 // Read headers\r
107                                 while (!(xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace))\r
108                                 {\r
109                                         if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Header" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace)\r
110                                         {\r
111                                                 if (headers == null) headers = new ArrayList ();\r
112                                                 DeserializeHeaders (headers);\r
113                                         }\r
114                                         else\r
115                                                 xmlReader.Skip ();\r
116                                         xmlReader.MoveToContent();\r
117                                 }\r
118                                 \r
119                                 // SOAP-ENV:Body\r
120                                 xmlReader.ReadStartElement();\r
121                                 xmlReader.MoveToContent();\r
122 \r
123                                 // The root object\r
124                                 if (soapMessage != null)\r
125                                 {\r
126                                         if (DeserializeMessage (soapMessage)) {\r
127                                                 _topObjectId = NextAvailableId;\r
128                                                 RegisterObject (_topObjectId, soapMessage, null, 0, null, null);\r
129                                         }\r
130                                         xmlReader.MoveToContent();\r
131                                         \r
132                                         if (headers != null)\r
133                                                 soapMessage.Headers = (Header[]) headers.ToArray (typeof(Header));\r
134                                 }\r
135                                 \r
136                                 while (xmlReader.NodeType != XmlNodeType.EndElement)\r
137                                         Deserialize();\r
138                                         \r
139                                 // SOAP-ENV:Body\r
140                                 xmlReader.ReadEndElement ();\r
141                                 xmlReader.MoveToContent();\r
142 \r
143                                 // SOAP-ENV:Envelope\r
144                                 xmlReader.ReadEndElement ();\r
145                         }\r
146                         finally \r
147                         {\r
148                                 if(xmlReader != null) xmlReader.Close();\r
149                         }\r
150 \r
151                         return TopObject;\r
152                 }\r
153                 \r
154                 #endregion\r
155                 \r
156                 public SoapTypeMapper Mapper {\r
157                         get { return mapper; }\r
158                 }\r
159                 \r
160                 public XmlTextReader XmlReader {\r
161                         get { return xmlReader; }\r
162                 }\r
163 \r
164                 #region Private Methods\r
165 \r
166                 private object TopObject \r
167                 {\r
168                         get \r
169                         {\r
170                                 objMgr.DoFixups();\r
171                                 objMgr.RaiseDeserializationEvent();\r
172                                 return objMgr.GetObject(_topObjectId);\r
173                         }\r
174                 }\r
175 \r
176                 private bool IsNull()\r
177                 {\r
178                         string tmp = xmlReader["null", XmlSchema.InstanceNamespace];\r
179                         return (tmp == null || tmp == string.Empty)?false:true;\r
180                 }\r
181 \r
182                 private long GetId()\r
183                 {\r
184                         long id = 0;\r
185 \r
186                         string strId = xmlReader["id"];\r
187                         if(strId == null || strId == String.Empty) return 0;\r
188                         id = Convert.ToInt64(strId.Substring(4));\r
189                         return id;\r
190                 }\r
191 \r
192                 private long GetHref()\r
193                 {\r
194                         long href = 0;\r
195                         \r
196                         string strHref = xmlReader["href"];\r
197                         if(strHref == null || strHref == string.Empty) return 0;\r
198                         href = Convert.ToInt64(strHref.Substring(5));\r
199                         return href;\r
200                 }\r
201 \r
202                 private Type GetComponentType()\r
203                 {\r
204                         string strValue = xmlReader["type", XmlSchema.InstanceNamespace];\r
205                         if(strValue == null) {\r
206                                 if(GetId() != 0) return typeof(string);\r
207                                 return null;\r
208                         }\r
209                         return GetTypeFromQName (strValue);\r
210                 }\r
211 \r
212                 private bool DeserializeMessage(ISoapMessage message) \r
213                 {\r
214                         string typeNamespace, assemblyName;\r
215 \r
216                         if(xmlReader.Name == SoapTypeMapper.SoapEnvelopePrefix + ":Fault")\r
217                         {\r
218                                 Deserialize();\r
219                                 return false;\r
220                         }\r
221 \r
222                         SoapServices.DecodeXmlNamespaceForClrTypeNamespace(\r
223                                 xmlReader.NamespaceURI,\r
224                                 out typeNamespace,\r
225                                 out assemblyName);\r
226                         message.MethodName = xmlReader.LocalName;\r
227                         message.XmlNameSpace = xmlReader.NamespaceURI;\r
228 \r
229                         ArrayList paramNames = new ArrayList();\r
230                         ArrayList paramValues = new ArrayList();\r
231                         long paramValuesId = NextAvailableId;\r
232                         int[] indices = new int[1];\r
233 \r
234                         if (!xmlReader.IsEmptyElement)\r
235                         {\r
236                                 int initialDepth = xmlReader.Depth;\r
237                                 xmlReader.Read();\r
238                                 int i = 0;\r
239                                 while(xmlReader.Depth > initialDepth) \r
240                                 {\r
241                                         long paramId, paramHref;\r
242                                         object objParam = null;\r
243                                         paramNames.Add (xmlReader.Name);\r
244                                         Type paramType = null;\r
245                                         \r
246                                         if (message.ParamTypes != null) {\r
247                                                 if (i >= message.ParamTypes.Length)\r
248                                                         throw new SerializationException ("Not enough parameter types in SoapMessages");\r
249                                                 paramType = message.ParamTypes [i];\r
250                                         }\r
251                                         \r
252                                         indices[0] = i;\r
253                                         objParam = DeserializeComponent(\r
254                                                 paramType,\r
255                                                 out paramId,\r
256                                                 out paramHref,\r
257                                                 paramValuesId,\r
258                                                 null,\r
259                                                 indices);\r
260                                         indices[0] = paramValues.Add(objParam);\r
261                                         if(paramHref != 0) \r
262                                         {\r
263                                                 RecordFixup(paramValuesId, paramHref, paramValues.ToArray(), null, null, null, indices);\r
264                                         }\r
265                                         else if(paramId != 0) \r
266                                         {\r
267 //                                              RegisterObject(paramId, objParam, null, paramValuesId, null, indices);\r
268                                         }\r
269                                         else \r
270                                         {\r
271                                         }\r
272                                         i++;\r
273                                 }\r
274                                 xmlReader.ReadEndElement();\r
275                         }\r
276                         else\r
277                         {\r
278                                 xmlReader.Read();\r
279                         }\r
280                         \r
281                         message.ParamNames = (string[]) paramNames.ToArray(typeof(string));\r
282                         message.ParamValues = paramValues.ToArray();\r
283                         RegisterObject(paramValuesId, message.ParamValues, null, 0, null, null);\r
284                         return true;\r
285                 }\r
286 \r
287                 void DeserializeHeaders (ArrayList headers)\r
288                 {\r
289                         xmlReader.ReadStartElement ();\r
290                         xmlReader.MoveToContent ();\r
291                         \r
292                         while (xmlReader.NodeType != XmlNodeType.EndElement) \r
293                         {\r
294                                 if (xmlReader.NodeType != XmlNodeType.Element) { xmlReader.Skip(); continue; }\r
295                                 \r
296                                 if (xmlReader.GetAttribute ("root", SoapTypeMapper.SoapEncodingNamespace) == "1")\r
297                                         headers.Add (DeserializeHeader ());\r
298                                 else\r
299                                         Deserialize ();\r
300 \r
301                                 xmlReader.MoveToContent ();\r
302                         }\r
303                         \r
304                         xmlReader.ReadEndElement ();\r
305                 }\r
306                 \r
307                 Header DeserializeHeader ()\r
308                 {\r
309                         Header h = new Header (xmlReader.LocalName, null);\r
310                         h.HeaderNamespace = xmlReader.NamespaceURI;\r
311                         h.MustUnderstand = xmlReader.GetAttribute ("mustUnderstand", SoapTypeMapper.SoapEnvelopeNamespace) == "1";\r
312                         \r
313                         object value;\r
314                         long fieldId, fieldHref;\r
315                         long idHeader = NextAvailableId;\r
316                         FieldInfo fieldInfo = typeof(Header).GetField ("Value");\r
317 \r
318                         value = DeserializeComponent (null, out fieldId, out fieldHref, idHeader, fieldInfo, null);\r
319                         h.Value = value;\r
320 \r
321                         if(fieldHref != 0 && value == null)\r
322                         {\r
323                                 RecordFixup (idHeader, fieldHref, h, null, null, fieldInfo, null);\r
324                         }\r
325                         else if(value != null && value.GetType().IsValueType && fieldId != 0)\r
326                         {\r
327                                 RecordFixup (idHeader, fieldId, h, null, null, fieldInfo, null);\r
328                         }\r
329                         else if(fieldId != 0)\r
330                         {\r
331                                 RegisterObject (fieldId, value, null, idHeader, fieldInfo, null);\r
332                         }\r
333                         \r
334                         RegisterObject (idHeader, h, null, 0, null, null);\r
335                         return h;\r
336                 }\r
337 \r
338                 \r
339                 private object DeserializeArray(long id)\r
340                 {\r
341                         // Special case for base64 byte arrays\r
342                         if (GetComponentType () == typeof(byte[])) {\r
343                                 byte[] data = Convert.FromBase64String (xmlReader.ReadElementString());\r
344                                 RegisterObject(id, data, null, 0, null, null);\r
345                                 return data;\r
346                         }\r
347                         \r
348                         // Get the array properties\r
349                         string strArrayType = xmlReader["arrayType", SoapTypeMapper.SoapEncodingNamespace];\r
350                         string[] arrayInfo = strArrayType.Split(':');\r
351                         int arraySuffixInfo = arrayInfo[1].LastIndexOf('[');\r
352                         String arrayElementType = arrayInfo[1].Substring(0, arraySuffixInfo);\r
353                         String arraySuffix = arrayInfo[1].Substring(arraySuffixInfo);\r
354                         string[] arrayDims = arraySuffix.Substring(1,arraySuffix.Length-2).Trim().Split(',');\r
355                         int numberOfDims = arrayDims.Length;\r
356                         int[] lengths = new int[numberOfDims];\r
357                         \r
358                         for (int i=0; i < numberOfDims; i++)\r
359                         {\r
360                                 lengths[i] = Convert.ToInt32(arrayDims[i]);\r
361                         }\r
362 \r
363                         int[] indices = new int[numberOfDims];\r
364 \r
365                         // Create the array\r
366                         Type arrayType = mapper.GetType (arrayElementType, xmlReader.LookupNamespace(arrayInfo[0]));\r
367                         Array array = Array.CreateInstance(\r
368                                 arrayType,\r
369                                 lengths);\r
370 \r
371                         for(int i = 0; i < numberOfDims; i++) \r
372                         {\r
373                                 indices[i] = array.GetLowerBound(i);\r
374                         }\r
375 \r
376                         // Deserialize the array items\r
377                         int arrayDepth = xmlReader.Depth;\r
378                         xmlReader.Read();\r
379                         while(xmlReader.Depth > arrayDepth)\r
380                         {\r
381                                 Type itemType = GetComponentType();\r
382                                 if(itemType == null) \r
383                                         itemType = array.GetType().GetElementType();\r
384                                 long itemId, itemHref;\r
385 \r
386                                 object objItem = DeserializeComponent(itemType,\r
387                                         out itemId,\r
388                                         out itemHref,\r
389                                         id,\r
390                                         null,\r
391                                         indices);\r
392                                 if(itemHref != 0)\r
393                                 {\r
394                                         object obj = objMgr.GetObject(itemHref);\r
395                                         if(obj != null)\r
396                                                 array.SetValue(obj, indices);\r
397                                         else\r
398                                                 RecordFixup(id, itemHref, array, null, null, null, indices);\r
399                                 }\r
400                                 else if(objItem != null && objItem.GetType().IsValueType && itemId != 0)\r
401                                 {\r
402                                         RecordFixup(id, itemId, array, null, null, null, indices);\r
403                                 }\r
404                                 else if(itemId != 0)\r
405                                 {\r
406                                         RegisterObject(itemId, objItem, null, id, null, indices);\r
407                                         array.SetValue(objItem, indices);\r
408                                 }\r
409                                 else \r
410                                 {\r
411                                         array.SetValue(objItem, indices);\r
412                                 }\r
413 \r
414                                 // Get the next indice\r
415                                 for(int dim = array.Rank - 1; dim >= 0; dim--)\r
416                                 {\r
417                                         indices[dim]++;\r
418                                         if(indices[dim] > array.GetUpperBound(dim))\r
419                                         {\r
420                                                 if(dim > 0)\r
421                                                 {\r
422                                                         indices[dim] = array.GetLowerBound(dim);\r
423                                                         continue;\r
424                                                 }\r
425                                                 \r
426                                         }\r
427                                         break;\r
428                                 }\r
429                         }\r
430 \r
431                         RegisterObject(id, array, null, 0, null, null);\r
432                         xmlReader.ReadEndElement();\r
433                         return array;\r
434 \r
435                 }\r
436 \r
437 \r
438                 private object Deserialize()\r
439                 {\r
440                         object objReturn = null;\r
441                         Type type = mapper.GetType (xmlReader.LocalName, xmlReader.NamespaceURI);\r
442 \r
443                         // Get the Id\r
444                         long id = GetId();\r
445                         id = (id == 0)?1:id;\r
446 \r
447                         if(type == typeof(Array))\r
448                         {\r
449                                 objReturn = DeserializeArray(id);\r
450                         }\r
451                         else\r
452                         {\r
453                                 objReturn = DeserializeObject(type, id, 0, null, null);\r
454 \r
455                         }\r
456 \r
457                         return objReturn;\r
458                 }\r
459 \r
460 \r
461                 private object DeserializeObject(\r
462                         Type type, \r
463                         long id, \r
464                         long parentId, \r
465                         MemberInfo parentMemberInfo,\r
466                         int[] indices)\r
467                 {\r
468                         SerializationInfo info = null;\r
469                         bool NeedsSerializationInfo = false;\r
470                         bool hasFixup;\r
471 \r
472                         // in case of String & TimeSpan we should allways use 'ReadInternalSoapValue' method\r
473                         // in case of other internal types, we should use ReadInternalSoapValue' only if it is NOT\r
474                         // the root object, means it is a data member of another object that is being serialized.\r
475                         bool shouldReadInternal = (type == typeof(String) || type == typeof(TimeSpan) );\r
476                         if(shouldReadInternal || mapper.IsInternalSoapType (type) && (indices != null || parentMemberInfo != null) ) \r
477                         {\r
478                                 object obj = mapper.ReadInternalSoapValue (this, type);\r
479                                 \r
480                                 if(id != 0) \r
481                                         RegisterObject(id, obj, info, parentId, parentMemberInfo, indices);\r
482 \r
483                                 return obj;\r
484                         }\r
485                         object objReturn = \r
486                                 FormatterServices.GetUninitializedObject(type);\r
487 \r
488 #if NET_2_0 && !TARGET_JVM\r
489                         objMgr.RaiseOnDeserializingEvent (objReturn);\r
490 #endif\r
491                         if(objReturn is ISerializable)\r
492                                 NeedsSerializationInfo = true;\r
493 \r
494                         if(_surrogateSelector != null && NeedsSerializationInfo == false)\r
495                         {\r
496                                 ISurrogateSelector selector;\r
497                                 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate(\r
498                                         type,\r
499                                         _context,\r
500                                         out selector);\r
501                                 NeedsSerializationInfo |= (surrogate != null);\r
502                         }\r
503 \r
504                         if(NeedsSerializationInfo)\r
505                         {\r
506                                 objReturn = \r
507                                         DeserializeISerializableObject(objReturn, id, out info, out hasFixup);\r
508                         }\r
509                         else\r
510                         {\r
511                                 objReturn = \r
512                                         DeserializeSimpleObject(objReturn, id, out hasFixup);\r
513                                 if(!hasFixup && objReturn is IObjectReference)\r
514                                         objReturn = ((IObjectReference)objReturn).GetRealObject(_context);\r
515                         }\r
516 \r
517                         RegisterObject(id, objReturn, info, parentId, parentMemberInfo, indices);\r
518                         xmlReader.ReadEndElement();\r
519                         return objReturn;\r
520                 }\r
521 \r
522 \r
523                 private object DeserializeSimpleObject(\r
524                         object obj,\r
525                         long id,\r
526                         out bool hasFixup\r
527                         )\r
528                 {\r
529                         hasFixup = false;\r
530                         Type currentType = obj.GetType();\r
531                         TypeMetadata tm = GetTypeMetadata (currentType);\r
532 \r
533                         object[] data = new object[tm.MemberInfos.Length];\r
534                         xmlReader.Read();\r
535                         xmlReader.MoveToContent ();\r
536                         while (xmlReader.NodeType != XmlNodeType.EndElement)\r
537                         {\r
538                                 if (xmlReader.NodeType != XmlNodeType.Element) {\r
539                                         xmlReader.Skip ();\r
540                                         continue;\r
541                                 }\r
542                                 \r
543                                 object fieldObject;\r
544                                 long fieldId, fieldHref;\r
545 \r
546                                 object indexob = tm.Indices [xmlReader.LocalName];\r
547                                 if (indexob == null)\r
548                                         throw new SerializationException ("Field \"" + xmlReader.LocalName + "\" not found in class " + currentType.FullName);\r
549                                 \r
550                                 int index = (int) indexob;\r
551                                 FieldInfo fieldInfo = (tm.MemberInfos[index]) as FieldInfo;\r
552 \r
553                                 fieldObject = \r
554                                         DeserializeComponent(fieldInfo.FieldType,\r
555                                         out fieldId,\r
556                                         out fieldHref,\r
557                                         id,\r
558                                         fieldInfo,\r
559                                         null);\r
560 \r
561                                 data[index] = fieldObject;\r
562 \r
563                                 if(fieldHref != 0 && fieldObject == null)\r
564                                 {\r
565                                         RecordFixup(id, fieldHref, obj, null, null, fieldInfo, null);\r
566                                         hasFixup = true;\r
567                                         continue;\r
568                                 }\r
569                                 if(fieldObject != null && fieldObject.GetType().IsValueType && fieldId != 0)\r
570                                 {\r
571                                         RecordFixup(id, fieldId, obj, null, null, fieldInfo, null);\r
572                                         hasFixup = true;\r
573                                         continue;\r
574                                 }\r
575 \r
576                                 if(fieldId != 0)\r
577                                 {\r
578                                         RegisterObject(fieldId, fieldObject, null, id, fieldInfo, null);\r
579                                 }\r
580                         }\r
581 \r
582                         FormatterServices.PopulateObjectMembers (obj, tm.MemberInfos, data);\r
583                         return obj;\r
584                 }\r
585 \r
586 \r
587                 private object DeserializeISerializableObject(\r
588                         object obj, \r
589                         long id, \r
590                         out SerializationInfo info,\r
591                         out bool hasFixup\r
592                         )\r
593                 {\r
594                         long fieldId, fieldHref;\r
595                         info = new SerializationInfo(obj.GetType(), new FormatterConverter());\r
596                         hasFixup = false;\r
597                         \r
598                         int initialDepth = xmlReader.Depth;\r
599                         xmlReader.Read();\r
600                         while(xmlReader.Depth > initialDepth) \r
601                         {\r
602                                 Type fieldType = GetComponentType();\r
603                                 string fieldName = XmlConvert.DecodeName (xmlReader.LocalName);\r
604                                 object objField = DeserializeComponent(\r
605                                         fieldType,\r
606                                         out fieldId,\r
607                                         out fieldHref,\r
608                                         id,\r
609                                         null,\r
610                                         null);\r
611                                 if(fieldHref != 0 && objField == null) \r
612                                 {\r
613                                         RecordFixup(id, fieldHref, obj, info, fieldName, null, null);\r
614                                         hasFixup = true;\r
615                                         continue;\r
616                                 }\r
617                                 else if(fieldId != 0 && objField.GetType().IsValueType)\r
618                                 {\r
619                                         RecordFixup(id, fieldId, obj, info, fieldName, null, null);\r
620                                         hasFixup = true;\r
621                                         continue;\r
622                                 }\r
623                                 \r
624                                 if(fieldId != 0) \r
625                                 {\r
626                                         RegisterObject(fieldId, objField, null, id, null, null);\r
627                                 }\r
628 \r
629                                 info.AddValue(fieldName, objField, (fieldType != null)?fieldType:typeof(object));\r
630                         }\r
631 \r
632                         return obj;\r
633                 }\r
634 \r
635 \r
636                 private object DeserializeComponent(\r
637                         Type componentType, \r
638                         out long componentId,\r
639                         out long componentHref,\r
640                         long parentId,\r
641                         MemberInfo parentMemberInfo,\r
642                         int[] indices)\r
643                 {\r
644                         object objReturn;\r
645                         componentId = 0;\r
646                         componentHref = 0;\r
647 \r
648                         if(IsNull())\r
649                         {\r
650                                 xmlReader.Read();\r
651                                 return null;\r
652                         }\r
653 \r
654                         Type xsiType = GetComponentType();\r
655                         if(xsiType != null) componentType = xsiType;\r
656 \r
657                         if(xmlReader.HasAttributes)\r
658                         {\r
659                                 componentId = GetId();\r
660                                 componentHref = GetHref();\r
661                         }\r
662 \r
663                         if(componentId != 0)\r
664                         {\r
665                                 // It's a string\r
666                                 string str = xmlReader.ReadElementString();\r
667                                 objMgr.RegisterObject (str, componentId);\r
668                                 return str;\r
669                         }\r
670                         if(componentHref != 0)\r
671                         {\r
672                                 // Move the cursor to the next node\r
673                                 xmlReader.Read();\r
674                                 return objMgr.GetObject(componentHref);\r
675                         }\r
676 \r
677                         if(componentType == null)\r
678                                 return xmlReader.ReadElementString();\r
679 \r
680                         componentId = NextAvailableId;\r
681                         objReturn = DeserializeObject(\r
682                                 componentType,\r
683                                 componentId,\r
684                                 parentId,\r
685                                 parentMemberInfo,\r
686                                 indices);\r
687                         return objReturn;\r
688                 }\r
689 \r
690                 public void RecordFixup(\r
691                         long parentObjectId, \r
692                         long childObjectId,\r
693                         object parentObject,\r
694                         SerializationInfo info,\r
695                         string fieldName,\r
696                         MemberInfo memberInfo,\r
697                         int[] indices)\r
698                 {\r
699                         if(info != null)\r
700                         {\r
701                                 objMgr.RecordDelayedFixup(parentObjectId, fieldName, childObjectId);\r
702                         }\r
703                         else if (parentObject is Array) \r
704                         {\r
705                                 if (indices.Length == 1)\r
706                                         objMgr.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);\r
707                                 else\r
708                                         objMgr.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);\r
709                         }\r
710                         else \r
711                         {\r
712                                 objMgr.RecordFixup (parentObjectId, memberInfo, childObjectId);\r
713                         }\r
714                 }\r
715 \r
716                 private void RegisterObject (\r
717                         long objectId, \r
718                         object objectInstance, \r
719                         SerializationInfo info, \r
720                         long parentObjectId, \r
721                         MemberInfo parentObjectMember, \r
722                         int[] indices)\r
723                 {\r
724                         if (parentObjectId == 0) indices = null;\r
725 \r
726                         if (!objectInstance.GetType().IsValueType || parentObjectId == 0)\r
727                                 objMgr.RegisterObject (objectInstance, objectId, info, 0, null, null);\r
728                         else\r
729                         {\r
730                                 if(objMgr.GetObject(objectId) != null)\r
731                                         throw new SerializationException("Object already registered");\r
732                                 if (indices != null) indices = (int[])indices.Clone();\r
733                                 objMgr.RegisterObject (\r
734                                         objectInstance, \r
735                                         objectId, \r
736                                         info, \r
737                                         parentObjectId, \r
738                                         parentObjectMember, \r
739                                         indices);\r
740                         }\r
741                 }\r
742 \r
743                 TypeMetadata GetTypeMetadata (Type type)\r
744                 {\r
745                         TypeMetadata tm = _fieldIndices[type] as TypeMetadata;\r
746                         if (tm != null) return tm;\r
747                         \r
748                         tm = new TypeMetadata ();\r
749                         tm.MemberInfos = FormatterServices.GetSerializableMembers (type, _context);\r
750                         \r
751                         tm.Indices      = new Hashtable();\r
752                         for(int i = 0; i < tm.MemberInfos.Length; i++) {\r
753                                 SoapFieldAttribute at = (SoapFieldAttribute) InternalRemotingServices.GetCachedSoapAttribute (tm.MemberInfos[i]);\r
754                                 tm.Indices [XmlConvert.EncodeLocalName (at.XmlElementName)] = i;\r
755                         }\r
756                         \r
757                         _fieldIndices[type] = tm;\r
758                         return tm;\r
759                 }\r
760                 \r
761                 public Type GetTypeFromQName (string qname)\r
762                 {\r
763                         string[] strName = qname.Split(':');\r
764                         string namespaceURI = xmlReader.LookupNamespace (strName[0]);\r
765                         return mapper.GetType (strName[1], namespaceURI);\r
766                 }\r
767                 \r
768                 #endregion\r
769         }\r
770 }\r