svn path=/branches/mono-1-1-9/mcs/; revision=51212
[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
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
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                 {
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 ();
104                                 xmlReader.MoveToContent();
105                                 
106                                 // Read headers
107                                 while (!(xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace))
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
115                                                 xmlReader.Skip ();\r
116                                         xmlReader.MoveToContent();\r
117                                 }
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
155                 
156                 public SoapTypeMapper Mapper {
157                         get { return mapper; }
158                 }
159                 \r
160                 public XmlTextReader XmlReader {
161                         get { return xmlReader; }
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                 }
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                 }
306                 \r               Header DeserializeHeader ()
307                 {
308                         Header h = new Header (xmlReader.LocalName, null);
309                         h.HeaderNamespace = xmlReader.NamespaceURI;\r
310                         h.MustUnderstand = xmlReader.GetAttribute ("mustUnderstand", SoapTypeMapper.SoapEnvelopeNamespace) == "1";\r
311                         \r
312                         object value;\r
313                         long fieldId, fieldHref;\r
314                         long idHeader = NextAvailableId;\r
315                         FieldInfo fieldInfo = typeof(Header).GetField ("Value");\r
316 \r
317                         value = DeserializeComponent (null, out fieldId, out fieldHref, idHeader, fieldInfo, null);\r
318                         h.Value = value;\r
319 \r
320                         if(fieldHref != 0 && value == null)\r
321                         {\r
322                                 RecordFixup (idHeader, fieldHref, h, null, null, fieldInfo, null);\r
323                         }\r
324                         else if(value != null && value.GetType().IsValueType && fieldId != 0)\r
325                         {\r
326                                 RecordFixup (idHeader, fieldId, h, null, null, fieldInfo, null);\r
327                         }\r
328                         else if(fieldId != 0)\r
329                         {\r
330                                 RegisterObject (fieldId, value, null, idHeader, fieldInfo, null);\r
331                         }\r
332                         \r
333                         RegisterObject (idHeader, h, null, 0, null, null);\r
334                         return h;\r
335                 }\r
336 \r
337                 \r
338                 private object DeserializeArray(long id)\r
339                 {\r
340                         // Special case for base64 byte arrays\r
341                         if (GetComponentType () == typeof(byte[])) {\r
342                                 byte[] data = Convert.FromBase64String (xmlReader.ReadElementString());\r
343                                 RegisterObject(id, data, null, 0, null, null);\r
344                                 return data;\r
345                         }\r
346                         \r
347                         // Get the array properties\r
348                         string strArrayType = xmlReader["arrayType", SoapTypeMapper.SoapEncodingNamespace];
349                         string[] arrayInfo = strArrayType.Split(':');
350                         int arraySuffixInfo = arrayInfo[1].LastIndexOf('[');
351                         String arrayElementType = arrayInfo[1].Substring(0, arraySuffixInfo);
352                         String arraySuffix = arrayInfo[1].Substring(arraySuffixInfo);
353                         string[] arrayDims = arraySuffix.Substring(1,arraySuffix.Length-2).Trim().Split(',');
354                         int numberOfDims = arrayDims.Length;
355                         int[] lengths = new int[numberOfDims];
356                         \r
357                         for (int i=0; i < numberOfDims; i++)\r
358                         {\r
359                                 lengths[i] = Convert.ToInt32(arrayDims[i]);\r
360                         }\r
361 \r
362                         int[] indices = new int[numberOfDims];\r
363 \r
364                         // Create the array\r
365                         Type arrayType = mapper.GetType (arrayElementType, xmlReader.LookupNamespace(arrayInfo[0]));\r
366                         Array array = Array.CreateInstance(\r
367                                 arrayType,\r
368                                 lengths);
369 \r
370                         for(int i = 0; i < numberOfDims; i++) \r
371                         {\r
372                                 indices[i] = array.GetLowerBound(i);\r
373                         }\r
374 \r
375                         // Deserialize the array items\r
376                         int arrayDepth = xmlReader.Depth;\r
377                         xmlReader.Read();\r
378                         while(xmlReader.Depth > arrayDepth)\r
379                         {\r
380                                 Type itemType = GetComponentType();\r
381                                 if(itemType == null) \r
382                                         itemType = array.GetType().GetElementType();\r
383                                 long itemId, itemHref;\r
384 \r
385                                 object objItem = DeserializeComponent(itemType,\r
386                                         out itemId,\r
387                                         out itemHref,\r
388                                         id,\r
389                                         null,\r
390                                         indices);\r
391                                 if(itemHref != 0)\r
392                                 {\r
393                                         object obj = objMgr.GetObject(itemHref);\r
394                                         if(obj != null)\r
395                                                 array.SetValue(obj, indices);\r
396                                         else\r
397                                                 RecordFixup(id, itemHref, array, null, null, null, indices);\r
398                                 }\r
399                                 else if(objItem != null && objItem.GetType().IsValueType && itemId != 0)\r
400                                 {\r
401                                         RecordFixup(id, itemId, array, null, null, null, indices);\r
402                                 }\r
403                                 else if(itemId != 0)\r
404                                 {\r
405                                         RegisterObject(itemId, objItem, null, id, null, indices);\r
406                                         array.SetValue(objItem, indices);\r
407                                 }\r
408                                 else \r
409                                 {\r
410                                         array.SetValue(objItem, indices);\r
411                                 }\r
412 \r
413                                 // Get the next indice\r
414                                 for(int dim = array.Rank - 1; dim >= 0; dim--)\r
415                                 {\r
416                                         indices[dim]++;\r
417                                         if(indices[dim] > array.GetUpperBound(dim))\r
418                                         {\r
419                                                 if(dim > 0)\r
420                                                 {\r
421                                                         indices[dim] = array.GetLowerBound(dim);\r
422                                                         continue;\r
423                                                 }\r
424                                                 \r
425                                         }\r
426                                         break;\r
427                                 }\r
428                         }\r
429 \r
430                         RegisterObject(id, array, null, 0, null, null);\r
431                         xmlReader.ReadEndElement();\r
432                         return array;\r
433 \r
434                 }\r
435 \r
436 \r
437                 private object Deserialize()\r
438                 {\r
439                         object objReturn = null;\r
440                         Type type = mapper.GetType (xmlReader.LocalName, xmlReader.NamespaceURI);\r
441 \r
442                         // Get the Id\r
443                         long id = GetId();\r
444                         id = (id == 0)?1:id;\r
445 \r
446                         if(type == typeof(Array))\r
447                         {\r
448                                 objReturn = DeserializeArray(id);\r
449                         }\r
450                         else\r
451                         {\r
452                                 objReturn = DeserializeObject(type, id, 0, null, null);\r
453 \r
454                         }\r
455 \r
456                         return objReturn;\r
457                 }\r
458 \r
459 \r
460                 private object DeserializeObject(\r
461                         Type type, \r
462                         long id, \r
463                         long parentId, \r
464                         MemberInfo parentMemberInfo,\r
465                         int[] indices)\r
466                 {\r
467                         SerializationInfo info = null;\r
468                         bool NeedsSerializationInfo = false;\r
469                         bool hasFixup;\r
470 \r
471                         if(mapper.IsInternalSoapType (type)) \r
472                         {\r
473                                 object obj = mapper.ReadInternalSoapValue (this, type);\r
474                                 \r
475                                 if(id != 0) \r
476                                         RegisterObject(id, obj, info, parentId, parentMemberInfo, indices);\r
477 \r
478                                 return obj;\r
479                         }\r
480                         object objReturn = \r
481                                 FormatterServices.GetUninitializedObject(type);\r
482                         if(objReturn is ISerializable)\r
483                                 NeedsSerializationInfo = true;\r
484 \r
485                         if(_surrogateSelector != null && NeedsSerializationInfo == false)\r
486                         {\r
487                                 ISurrogateSelector selector;\r
488                                 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate(\r
489                                         type,\r
490                                         _context,\r
491                                         out selector);\r
492                                 NeedsSerializationInfo |= (surrogate != null);\r
493                         }\r
494 \r
495                         if(NeedsSerializationInfo)\r
496                         {\r
497                                 objReturn = \r
498                                         DeserializeISerializableObject(objReturn, id, out info, out hasFixup);\r
499                         }\r
500                         else\r
501                         {\r
502                                 objReturn = \r
503                                         DeserializeSimpleObject(objReturn, id, out hasFixup);\r
504                                 if(!hasFixup && objReturn is IObjectReference)\r
505                                         objReturn = ((IObjectReference)objReturn).GetRealObject(_context);\r
506                         }\r
507 \r
508                         RegisterObject(id, objReturn, info, parentId, parentMemberInfo, indices);\r
509                         xmlReader.ReadEndElement();\r
510                         return objReturn;\r
511                 }\r
512 \r
513 \r
514                 private object DeserializeSimpleObject(\r
515                         object obj,\r
516                         long id,\r
517                         out bool hasFixup\r
518                         )\r
519                 {\r
520                         hasFixup = false;\r
521                         Type currentType = obj.GetType();\r
522                         TypeMetadata tm = GetTypeMetadata (currentType);\r
523 \r
524                         object[] data = new object[tm.MemberInfos.Length];\r
525                         xmlReader.Read();\r
526                         xmlReader.MoveToContent ();\r
527                         while (xmlReader.NodeType != XmlNodeType.EndElement)\r
528                         {\r
529                                 if (xmlReader.NodeType != XmlNodeType.Element) {\r
530                                         xmlReader.Skip ();\r
531                                         continue;\r
532                                 }\r
533                                 \r
534                                 object fieldObject;\r
535                                 long fieldId, fieldHref;\r
536 \r
537                                 object indexob = tm.Indices [xmlReader.LocalName];\r
538                                 if (indexob == null)\r
539                                         throw new SerializationException ("Field \"" + xmlReader.LocalName + "\" not found in class " + currentType.FullName);\r
540                                 \r
541                                 int index = (int) indexob;\r
542                                 FieldInfo fieldInfo = (tm.MemberInfos[index]) as FieldInfo;\r
543 \r
544                                 fieldObject = \r
545                                         DeserializeComponent(fieldInfo.FieldType,\r
546                                         out fieldId,\r
547                                         out fieldHref,\r
548                                         id,\r
549                                         fieldInfo,\r
550                                         null);\r
551 \r
552                                 data[index] = fieldObject;\r
553 \r
554                                 if(fieldHref != 0 && fieldObject == null)\r
555                                 {\r
556                                         RecordFixup(id, fieldHref, obj, null, null, fieldInfo, null);\r
557                                         hasFixup = true;\r
558                                         continue;\r
559                                 }\r
560                                 if(fieldObject != null && fieldObject.GetType().IsValueType && fieldId != 0)\r
561                                 {\r
562                                         RecordFixup(id, fieldId, obj, null, null, fieldInfo, null);\r
563                                         hasFixup = true;\r
564                                         continue;\r
565                                 }\r
566 \r
567                                 if(fieldId != 0)\r
568                                 {\r
569                                         RegisterObject(fieldId, fieldObject, null, id, fieldInfo, null);\r
570                                 }\r
571                         }\r
572 \r
573                         FormatterServices.PopulateObjectMembers (obj, tm.MemberInfos, data);\r
574                         return obj;\r
575                 }\r
576 \r
577 \r
578                 private object DeserializeISerializableObject(\r
579                         object obj, \r
580                         long id, \r
581                         out SerializationInfo info,\r
582                         out bool hasFixup\r
583                         )\r
584                 {\r
585                         long fieldId, fieldHref;\r
586                         info = new SerializationInfo(obj.GetType(), new FormatterConverter());\r
587                         hasFixup = false;\r
588                         \r
589                         int initialDepth = xmlReader.Depth;\r
590                         xmlReader.Read();\r
591                         while(xmlReader.Depth > initialDepth) \r
592                         {\r
593                                 Type fieldType = GetComponentType();\r
594                                 string fieldName = xmlReader.LocalName;\r
595                                 object objField = DeserializeComponent(\r
596                                         fieldType,\r
597                                         out fieldId,\r
598                                         out fieldHref,\r
599                                         id,\r
600                                         null,\r
601                                         null);\r
602                                 if(fieldHref != 0 && objField == null) \r
603                                 {\r
604                                         RecordFixup(id, fieldHref, obj, info, fieldName, null, null);\r
605                                         hasFixup = true;\r
606                                         continue;\r
607                                 }\r
608                                 else if(fieldId != 0 && objField.GetType().IsValueType)\r
609                                 {\r
610                                         RecordFixup(id, fieldId, obj, info, fieldName, null, null);\r
611                                         hasFixup = true;\r
612                                         continue;\r
613                                 }\r
614                                 \r
615                                 if(fieldId != 0) \r
616                                 {\r
617                                         RegisterObject(fieldId, objField, null, id, null, null);\r
618                                 }\r
619 \r
620                                 info.AddValue(fieldName, objField, (fieldType != null)?fieldType:typeof(object));\r
621                         }\r
622 \r
623                         return obj;\r
624                 }\r
625 \r
626 \r
627                 private object DeserializeComponent(\r
628                         Type componentType, \r
629                         out long componentId,\r
630                         out long componentHref,\r
631                         long parentId,\r
632                         MemberInfo parentMemberInfo,\r
633                         int[] indices)\r
634                 {\r
635                         object objReturn;\r
636                         componentId = 0;\r
637                         componentHref = 0;\r
638 \r
639                         if(IsNull())\r
640                         {\r
641                                 xmlReader.Read();\r
642                                 return null;\r
643                         }\r
644 \r
645                         Type xsiType = GetComponentType();\r
646                         if(xsiType != null) componentType = xsiType;\r
647 \r
648                         if(xmlReader.HasAttributes)\r
649                         {\r
650                                 componentId = GetId();\r
651                                 componentHref = GetHref();\r
652                         }\r
653 \r
654                         if(componentId != 0)\r
655                         {\r
656                                 // It's a string\r
657                                 return xmlReader.ReadElementString();\r
658                         }\r
659                         if(componentHref != 0)\r
660                         {\r
661                                 // Move the cursor to the next node\r
662                                 xmlReader.Read();\r
663                                 return objMgr.GetObject(componentHref);\r
664                         }\r
665 \r
666                         if(componentType == null)\r
667                                 return xmlReader.ReadElementString();\r
668 \r
669                         componentId = NextAvailableId;\r
670                         objReturn = DeserializeObject(\r
671                                 componentType,\r
672                                 componentId,\r
673                                 parentId,\r
674                                 parentMemberInfo,\r
675                                 indices);\r
676                         return objReturn;\r
677                 }\r
678 \r
679                 public void RecordFixup(\r
680                         long parentObjectId, \r
681                         long childObjectId,\r
682                         object parentObject,\r
683                         SerializationInfo info,\r
684                         string fieldName,\r
685                         MemberInfo memberInfo,\r
686                         int[] indices)\r
687                 {\r
688                         if(info != null)\r
689                         {\r
690                                 objMgr.RecordDelayedFixup(parentObjectId, fieldName, childObjectId);\r
691                         }\r
692                         else if (parentObject is Array) \r
693                         {\r
694                                 if (indices.Length == 1)\r
695                                         objMgr.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);\r
696                                 else\r
697                                         objMgr.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);\r
698                         }\r
699                         else \r
700                         {\r
701                                 objMgr.RecordFixup (parentObjectId, memberInfo, childObjectId);\r
702                         }\r
703                 }\r
704 \r
705                 private void RegisterObject (\r
706                         long objectId, \r
707                         object objectInstance, \r
708                         SerializationInfo info, \r
709                         long parentObjectId, \r
710                         MemberInfo parentObjectMember, \r
711                         int[] indices)\r
712                 {\r
713                         if (parentObjectId == 0) indices = null;\r
714 \r
715                         if (!objectInstance.GetType().IsValueType || parentObjectId == 0)\r
716                                 objMgr.RegisterObject (objectInstance, objectId, info, 0, null, null);\r
717                         else\r
718                         {\r
719                                 if(objMgr.GetObject(objectId) != null)\r
720                                         throw new SerializationException("Object already registered");\r
721                                 if (indices != null) indices = (int[])indices.Clone();\r
722                                 objMgr.RegisterObject (\r
723                                         objectInstance, \r
724                                         objectId, \r
725                                         info, \r
726                                         parentObjectId, \r
727                                         parentObjectMember, \r
728                                         indices);\r
729                         }\r
730                 }\r
731 \r
732                 TypeMetadata GetTypeMetadata (Type type)\r
733                 {\r
734                         TypeMetadata tm = _fieldIndices[type] as TypeMetadata;\r
735                         if (tm != null) return tm;\r
736                         \r
737                         tm = new TypeMetadata ();\r
738                         tm.MemberInfos = FormatterServices.GetSerializableMembers (type, _context);\r
739                         \r
740                         tm.Indices      = new Hashtable();\r
741                         for(int i = 0; i < tm.MemberInfos.Length; i++) {\r
742                                 SoapFieldAttribute at = (SoapFieldAttribute) InternalRemotingServices.GetCachedSoapAttribute (tm.MemberInfos[i]);\r
743                                 tm.Indices [XmlConvert.EncodeLocalName (at.XmlElementName)] = i;\r
744                         }\r
745                         \r
746                         _fieldIndices[type] = tm;\r
747                         return tm;\r
748                 }
749                 
750                 public Type GetTypeFromQName (string qname)
751                 {
752                         string[] strName = qname.Split(':');\r
753                         string namespaceURI = xmlReader.LookupNamespace (strName[0]);\r
754                         return mapper.GetType (strName[1], namespaceURI);\r
755                 }\r
756                 \r
757                 #endregion\r
758         }\r
759 }\r