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