(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / System.Runtime.Serialization.Formatters.Soap / System.Runtime.Serialization.Formatters.Soap / SoapReader.cs
bloba0188b32e3affc4ddad048a45b4a4595c747030e
1 // created on 24/04/2003 at 15:35
2 //
3 // System.Runtime.Serialization.Formatters.Soap.SoapReader
4 //
5 // Authors:
6 // Jean-Marc Andre (jean-marc.andre@polymtl.ca)
7 //
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.
30 using System;
31 using System.IO;
32 using System.Xml;
33 using System.Xml.Schema;
34 using System.Reflection;
35 using System.Collections;
36 using System.Runtime.Remoting;
37 using System.Runtime.Serialization;
38 using System.Runtime.Remoting.Messaging;
40 namespace System.Runtime.Serialization.Formatters.Soap {
41 internal sealed class SoapReader {
43 #region Fields
45 private SerializationBinder _binder;
46 private SoapTypeMapper mapper;
47 private ObjectManager objMgr;
48 private StreamingContext _context;
49 private long _nextAvailableId = long.MaxValue;
50 private ISurrogateSelector _surrogateSelector;
51 private XmlTextReader xmlReader;
52 private Hashtable _fieldIndices;
53 private long _topObjectId = 1;
55 class TypeMetadata
57 public MemberInfo[] MemberInfos;
58 public Hashtable Indices;
61 #endregion
63 #region Properties
65 private long NextAvailableId
67 get
69 _nextAvailableId--;
70 return _nextAvailableId;
74 #endregion
76 #region Constructors
78 public SoapReader(SerializationBinder binder, ISurrogateSelector selector, StreamingContext context)
80 _binder = binder;
81 objMgr = new ObjectManager(selector, context);
82 _context = context;
83 _surrogateSelector = selector;
84 _fieldIndices = new Hashtable();
87 #endregion
89 #region Public Methods
91 public object Deserialize(Stream inStream, ISoapMessage soapMessage)
93 ArrayList headers = null;
94 xmlReader = new XmlTextReader(inStream);
95 xmlReader.WhitespaceHandling = WhitespaceHandling.None;
96 mapper = new SoapTypeMapper(_binder);
98 try
100 // SOAP-ENV:Envelope
101 xmlReader.MoveToContent();
102 xmlReader.ReadStartElement ();
103 xmlReader.MoveToContent();
105 // Read headers
106 while (!(xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace))
108 if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Header" && xmlReader.NamespaceURI == SoapTypeMapper.SoapEnvelopeNamespace)
110 if (headers == null) headers = new ArrayList ();
111 DeserializeHeaders (headers);
113 else
114 xmlReader.Skip ();
115 xmlReader.MoveToContent();
118 // SOAP-ENV:Body
119 xmlReader.ReadStartElement();
120 xmlReader.MoveToContent();
122 // The root object
123 if (soapMessage != null)
125 if (DeserializeMessage (soapMessage)) {
126 _topObjectId = NextAvailableId;
127 RegisterObject (_topObjectId, soapMessage, null, 0, null, null);
129 xmlReader.MoveToContent();
131 if (headers != null)
132 soapMessage.Headers = (Header[]) headers.ToArray (typeof(Header));
135 while (xmlReader.NodeType != XmlNodeType.EndElement)
136 Deserialize();
138 // SOAP-ENV:Body
139 xmlReader.ReadEndElement ();
140 xmlReader.MoveToContent();
142 // SOAP-ENV:Envelope
143 xmlReader.ReadEndElement ();
145 finally
147 if(xmlReader != null) xmlReader.Close();
150 return TopObject;
153 #endregion
155 #region Private Methods
157 private object TopObject
159 get
161 objMgr.DoFixups();
162 objMgr.RaiseDeserializationEvent();
163 return objMgr.GetObject(_topObjectId);
167 private bool IsNull()
169 string tmp = xmlReader["null", XmlSchema.InstanceNamespace];
170 return (tmp == null || tmp == string.Empty)?false:true;
173 private long GetId()
175 long id = 0;
177 string strId = xmlReader["id"];
178 if(strId == null || strId == String.Empty) return 0;
179 id = Convert.ToInt64(strId.Substring(4));
180 return id;
183 private long GetHref()
185 long href = 0;
187 string strHref = xmlReader["href"];
188 if(strHref == null || strHref == string.Empty) return 0;
189 href = Convert.ToInt64(strHref.Substring(5));
190 return href;
193 private Type GetComponentType()
195 Type type = null;
197 string strValue = xmlReader["type", XmlSchema.InstanceNamespace];
198 if(strValue == null) {
199 if(GetId() != 0) return typeof(string);
200 return null;
202 string[] strName = strValue.Split(':');
203 string namespaceURI = xmlReader.LookupNamespace(strName[0]);
204 type = mapper[new Element(string.Empty, strName[1], namespaceURI)];
206 return type;
209 private bool DeserializeMessage(ISoapMessage message)
211 string typeNamespace, assemblyName;
213 if(xmlReader.Name == SoapTypeMapper.SoapEnvelopePrefix + ":Fault")
215 Deserialize();
216 return false;
219 SoapServices.DecodeXmlNamespaceForClrTypeNamespace(
220 xmlReader.NamespaceURI,
221 out typeNamespace,
222 out assemblyName);
223 message.MethodName = xmlReader.LocalName;
224 message.XmlNameSpace = xmlReader.NamespaceURI;
226 ArrayList paramNames = new ArrayList();
227 ArrayList paramValues = new ArrayList();
228 long paramValuesId = NextAvailableId;
229 int[] indices = new int[1];
231 if (!xmlReader.IsEmptyElement)
233 int initialDepth = xmlReader.Depth;
234 xmlReader.Read();
235 int i = 0;
236 while(xmlReader.Depth > initialDepth)
238 long paramId, paramHref;
239 object objParam = null;
240 paramNames.Add (xmlReader.Name);
241 Type paramType = null;
243 if (message.ParamTypes != null) {
244 if (i >= message.ParamTypes.Length)
245 throw new SerializationException ("Not enough parameter types in SoapMessages");
246 paramType = message.ParamTypes [i];
249 indices[0] = i;
250 objParam = DeserializeComponent(
251 paramType,
252 out paramId,
253 out paramHref,
254 paramValuesId,
255 null,
256 indices);
257 indices[0] = paramValues.Add(objParam);
258 if(paramHref != 0)
260 RecordFixup(paramValuesId, paramHref, paramValues.ToArray(), null, null, null, indices);
262 else if(paramId != 0)
264 // RegisterObject(paramId, objParam, null, paramValuesId, null, indices);
266 else
269 i++;
271 xmlReader.ReadEndElement();
273 else
275 xmlReader.Read();
278 message.ParamNames = (string[]) paramNames.ToArray(typeof(string));
279 message.ParamValues = paramValues.ToArray();
280 RegisterObject(paramValuesId, message.ParamValues, null, 0, null, null);
281 return true;
284 void DeserializeHeaders (ArrayList headers)
286 xmlReader.ReadStartElement ();
287 xmlReader.MoveToContent ();
289 while (xmlReader.NodeType != XmlNodeType.EndElement)
291 if (xmlReader.NodeType != XmlNodeType.Element) { xmlReader.Skip(); continue; }
293 if (xmlReader.GetAttribute ("root", SoapTypeMapper.SoapEncodingNamespace) == "1")
294 headers.Add (DeserializeHeader ());
295 else
296 Deserialize ();
298 xmlReader.MoveToContent ();
301 xmlReader.ReadEndElement ();
303 Header DeserializeHeader ()
305 Header h = new Header (xmlReader.LocalName, null);
306 h.HeaderNamespace = xmlReader.NamespaceURI;
307 h.MustUnderstand = xmlReader.GetAttribute ("mustUnderstand", SoapTypeMapper.SoapEnvelopeNamespace) == "1";
309 object value;
310 long fieldId, fieldHref;
311 long idHeader = NextAvailableId;
312 FieldInfo fieldInfo = typeof(Header).GetField ("Value");
314 value = DeserializeComponent (null, out fieldId, out fieldHref, idHeader, fieldInfo, null);
315 h.Value = value;
317 if(fieldHref != 0 && value == null)
319 RecordFixup (idHeader, fieldHref, h, null, null, fieldInfo, null);
321 else if(value != null && value.GetType().IsValueType && fieldId != 0)
323 RecordFixup (idHeader, fieldId, h, null, null, fieldInfo, null);
325 else if(fieldId != 0)
327 RegisterObject (fieldId, value, null, idHeader, fieldInfo, null);
330 RegisterObject (idHeader, h, null, 0, null, null);
331 return h;
335 private object DeserializeArray(long id)
337 // Special case for base64 byte arrays
338 if (GetComponentType () == typeof(byte[])) {
339 byte[] data = Convert.FromBase64String (xmlReader.ReadElementString());
340 RegisterObject(id, data, null, 0, null, null);
341 return data;
344 // Get the array properties
345 string strArrayType = xmlReader["arrayType", SoapTypeMapper.SoapEncodingNamespace];
346 string[] arrayInfo = strArrayType.Split(':','[',',',']');
347 int numberOfDims = arrayInfo.Length - 3;
348 int[] lengths = new int[numberOfDims];
349 string[] arrayDims = new String[numberOfDims];
350 Array.Copy(arrayInfo, 2, arrayDims, 0, numberOfDims);
351 for (int i=0; i < numberOfDims; i++)
353 lengths[i] = Convert.ToInt32(arrayDims[i]);
356 int[] indices = new int[numberOfDims];
358 // Create the array
359 Type arrayType = mapper[new Element(arrayInfo[0], arrayInfo[1], xmlReader.LookupNamespace(arrayInfo[0]))];
360 Array array = Array.CreateInstance(
361 arrayType,
362 lengths);
364 for(int i = 0; i < numberOfDims; i++)
366 indices[i] = array.GetLowerBound(i);
369 // Deserialize the array items
370 int arrayDepth = xmlReader.Depth;
371 xmlReader.Read();
372 while(xmlReader.Depth > arrayDepth)
374 Type itemType = GetComponentType();
375 if(itemType == null)
376 itemType = array.GetType().GetElementType();
377 long itemId, itemHref;
379 object objItem = DeserializeComponent(itemType,
380 out itemId,
381 out itemHref,
383 null,
384 indices);
385 if(itemHref != 0)
387 object obj = objMgr.GetObject(itemHref);
388 if(obj != null)
389 array.SetValue(obj, indices);
390 else
391 RecordFixup(id, itemHref, array, null, null, null, indices);
393 else if(objItem != null && objItem.GetType().IsValueType && itemId != 0)
395 RecordFixup(id, itemId, array, null, null, null, indices);
397 else if(itemId != 0)
399 RegisterObject(itemId, objItem, null, id, null, indices);
400 array.SetValue(objItem, indices);
402 else
404 array.SetValue(objItem, indices);
407 // Get the next indice
408 for(int dim = array.Rank - 1; dim >= 0; dim--)
410 indices[dim]++;
411 if(indices[dim] > array.GetUpperBound(dim))
413 if(dim > 0)
415 indices[dim] = array.GetLowerBound(dim);
416 continue;
420 break;
424 RegisterObject(id, array, null, 0, null, null);
425 xmlReader.ReadEndElement();
426 return array;
431 private object Deserialize()
433 object objReturn = null;
434 Element element = new Element(
435 xmlReader.Prefix,
436 xmlReader.LocalName,
437 xmlReader.NamespaceURI);
440 Type type = mapper[element];
442 // Get the Id
443 long id = GetId();
444 id = (id == 0)?1:id;
446 if(type == typeof(Array))
448 objReturn = DeserializeArray(id);
450 else
452 objReturn = DeserializeObject(type, id, 0, null, null);
456 return objReturn;
460 private object DeserializeObject(
461 Type type,
462 long id,
463 long parentId,
464 MemberInfo parentMemberInfo,
465 int[] indices)
467 SerializationInfo info = null;
468 bool NeedsSerializationInfo = false;
469 bool hasFixup;
471 if(SoapTypeMapper.CanBeValue(type))
473 string elementString = xmlReader.ReadElementString();
474 object obj = SoapTypeMapper.ParseXsdValue (elementString, type);
476 if(id != 0)
477 RegisterObject(id, obj, info, parentId, parentMemberInfo, indices);
479 return obj;
481 object objReturn =
482 FormatterServices.GetUninitializedObject(type);
483 if(objReturn is ISerializable)
484 NeedsSerializationInfo = true;
486 if(_surrogateSelector != null && NeedsSerializationInfo == false)
488 ISurrogateSelector selector;
489 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate(
490 type,
491 _context,
492 out selector);
493 NeedsSerializationInfo |= (surrogate != null);
496 if(NeedsSerializationInfo)
498 objReturn =
499 DeserializeISerializableObject(objReturn, id, out info, out hasFixup);
501 else
503 objReturn =
504 DeserializeSimpleObject(objReturn, id, out hasFixup);
505 if(!hasFixup && objReturn is IObjectReference)
506 objReturn = ((IObjectReference)objReturn).GetRealObject(_context);
509 RegisterObject(id, objReturn, info, parentId, parentMemberInfo, indices);
510 xmlReader.ReadEndElement();
511 return objReturn;
515 private object DeserializeSimpleObject(
516 object obj,
517 long id,
518 out bool hasFixup
521 hasFixup = false;
522 Type currentType = obj.GetType();
523 TypeMetadata tm = GetTypeMetadata (currentType);
525 int objDepth = xmlReader.Depth;
526 object[] data = new object[tm.MemberInfos.Length];
527 xmlReader.Read();
528 for(int i = 0; i < tm.MemberInfos.Length; i++)
530 object fieldObject;
531 long fieldId, fieldHref;
532 int index = (int) tm.Indices[xmlReader.LocalName];
533 FieldInfo fieldInfo = (tm.MemberInfos[index]) as FieldInfo;
534 if(fieldInfo == null) continue;
536 fieldObject =
537 DeserializeComponent(fieldInfo.FieldType,
538 out fieldId,
539 out fieldHref,
541 fieldInfo,
542 null);
544 data[index] = fieldObject;
546 if(fieldHref != 0 && fieldObject == null)
548 RecordFixup(id, fieldHref, obj, null, null, fieldInfo, null);
549 hasFixup = true;
550 continue;
552 if(fieldObject != null && fieldObject.GetType().IsValueType && fieldId != 0)
554 RecordFixup(id, fieldId, obj, null, null, fieldInfo, null);
555 hasFixup = true;
556 continue;
559 if(fieldId != 0)
561 RegisterObject(fieldId, fieldObject, null, id, fieldInfo, null);
565 FormatterServices.PopulateObjectMembers (obj, tm.MemberInfos, data);
566 return obj;
570 private object DeserializeISerializableObject(
571 object obj,
572 long id,
573 out SerializationInfo info,
574 out bool hasFixup
577 long fieldId, fieldHref;
578 info = new SerializationInfo(obj.GetType(), new FormatterConverter());
579 hasFixup = false;
581 int initialDepth = xmlReader.Depth;
582 xmlReader.Read();
583 while(xmlReader.Depth > initialDepth)
585 Type fieldType = GetComponentType();
586 string fieldName = xmlReader.LocalName;
587 object objField = DeserializeComponent(
588 fieldType,
589 out fieldId,
590 out fieldHref,
592 null,
593 null);
594 if(fieldHref != 0 && objField == null)
596 RecordFixup(id, fieldHref, obj, info, fieldName, null, null);
597 hasFixup = true;
598 continue;
600 else if(fieldId != 0 && objField.GetType().IsValueType)
602 RecordFixup(id, fieldId, obj, info, fieldName, null, null);
603 hasFixup = true;
604 continue;
607 if(fieldId != 0)
609 RegisterObject(fieldId, objField, null, id, null, null);
612 info.AddValue(fieldName, objField, (fieldType != null)?fieldType:typeof(object));
615 return obj;
619 private object DeserializeComponent(
620 Type componentType,
621 out long componentId,
622 out long componentHref,
623 long parentId,
624 MemberInfo parentMemberInfo,
625 int[] indices)
627 object objReturn;
628 componentId = 0;
629 componentHref = 0;
631 if(IsNull())
633 xmlReader.Read();
634 return null;
637 Type xsiType = GetComponentType();
638 if(xsiType != null) componentType = xsiType;
640 if(xmlReader.HasAttributes)
642 componentId = GetId();
643 componentHref = GetHref();
646 if(componentId != 0)
648 // It's a string
649 return xmlReader.ReadElementString();
651 if(componentHref != 0)
653 // Move the cursor to the next node
654 xmlReader.Read();
655 return objMgr.GetObject(componentHref);
658 if(componentType == null)
659 return xmlReader.ReadElementString();
661 componentId = NextAvailableId;
662 objReturn = DeserializeObject(
663 componentType,
664 componentId,
665 parentId,
666 parentMemberInfo,
667 indices);
668 return objReturn;
671 public void RecordFixup(
672 long parentObjectId,
673 long childObjectId,
674 object parentObject,
675 SerializationInfo info,
676 string fieldName,
677 MemberInfo memberInfo,
678 int[] indices)
680 if(info != null)
682 objMgr.RecordDelayedFixup(parentObjectId, fieldName, childObjectId);
684 else if (parentObject is Array)
686 if (indices.Length == 1)
687 objMgr.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);
688 else
689 objMgr.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);
691 else
693 objMgr.RecordFixup (parentObjectId, memberInfo, childObjectId);
697 private void RegisterObject (
698 long objectId,
699 object objectInstance,
700 SerializationInfo info,
701 long parentObjectId,
702 MemberInfo parentObjectMember,
703 int[] indices)
705 if (parentObjectId == 0) indices = null;
707 if (!objectInstance.GetType().IsValueType || parentObjectId == 0)
708 objMgr.RegisterObject (objectInstance, objectId, info, 0, null, null);
709 else
711 if(objMgr.GetObject(objectId) != null)
712 throw new SerializationException("Object already registered");
713 if (indices != null) indices = (int[])indices.Clone();
714 objMgr.RegisterObject (
715 objectInstance,
716 objectId,
717 info,
718 parentObjectId,
719 parentObjectMember,
720 indices);
724 TypeMetadata GetTypeMetadata (Type type)
726 TypeMetadata tm = _fieldIndices[type] as TypeMetadata;
727 if (tm != null) return tm;
729 tm = new TypeMetadata ();
730 tm.MemberInfos = FormatterServices.GetSerializableMembers (type, _context);
732 tm.Indices = new Hashtable();
733 for(int i = 0; i < tm.MemberInfos.Length; i++)
734 tm.Indices.Add (tm.MemberInfos[i].Name, i);
736 _fieldIndices[type] = tm;
737 return tm;
740 #endregion