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