[bcl] Don't build not installed mobile assemblies
[mono.git] / mcs / class / referencesource / System.Runtime.Serialization / System / Runtime / Serialization / XmlObjectSerializerReadContext.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.Runtime.Serialization
6 {
7     using System;
8     using System.Collections;
9     using System.Collections.Generic;
10     using System.Diagnostics;
11     using System.Runtime.Diagnostics;
12 #if !MONO
13     using System.ServiceModel.Diagnostics;
14 #endif
15     using System.Text;
16     using System.Xml;
17     using System.Xml.Serialization;
18     using System.Runtime.Serialization.Diagnostics;
19
20 #if USE_REFEMIT
21     public class XmlObjectSerializerReadContext : XmlObjectSerializerContext
22 #else
23     internal class XmlObjectSerializerReadContext : XmlObjectSerializerContext
24 #endif
25     {
26         internal Attributes attributes;
27         HybridObjectCache deserializedObjects;
28         XmlSerializableReader xmlSerializableReader;
29         XmlDocument xmlDocument;
30         Attributes attributesInXmlData;
31         XmlReaderDelegator extensionDataReader;
32         object getOnlyCollectionValue;
33         bool isGetOnlyCollection;
34
35         HybridObjectCache DeserializedObjects
36         {
37             get
38             {
39                 if (deserializedObjects == null)
40                     deserializedObjects = new HybridObjectCache();
41                 return deserializedObjects;
42             }
43         }
44
45         XmlDocument Document
46         {
47             get
48             {
49                 if (xmlDocument == null)
50                     xmlDocument = new XmlDocument();
51                 return xmlDocument;
52             }
53         }
54
55         internal override bool IsGetOnlyCollection
56         {
57             get { return this.isGetOnlyCollection; }
58             set { this.isGetOnlyCollection = value; }
59         }
60
61
62 #if USE_REFEMIT
63         public object GetCollectionMember()
64 #else
65         internal object GetCollectionMember()
66 #endif
67         {
68             return this.getOnlyCollectionValue;
69         }
70
71 #if USE_REFEMIT
72         public void StoreCollectionMemberInfo(object collectionMember)
73 #else
74         internal void StoreCollectionMemberInfo(object collectionMember)
75 #endif
76         {
77             this.getOnlyCollectionValue = collectionMember;
78             this.isGetOnlyCollection = true;
79         }
80
81 #if USE_REFEMIT
82         public static void ThrowNullValueReturnedForGetOnlyCollectionException(Type type)
83 #else
84         internal static void ThrowNullValueReturnedForGetOnlyCollectionException(Type type)
85 #endif
86         {
87             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.NullValueReturnedForGetOnlyCollection, DataContract.GetClrTypeFullName(type))));
88         }
89
90 #if USE_REFEMIT
91         public static void ThrowArrayExceededSizeException(int arraySize, Type type)
92 #else
93         internal static void ThrowArrayExceededSizeException(int arraySize, Type type)
94 #endif
95         {
96             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ArrayExceededSize, arraySize, DataContract.GetClrTypeFullName(type))));
97         }
98
99         internal static XmlObjectSerializerReadContext CreateContext(DataContractSerializer serializer, DataContract rootTypeDataContract, DataContractResolver dataContractResolver)
100         {
101             return (serializer.PreserveObjectReferences || serializer.DataContractSurrogate != null)
102                 ? new XmlObjectSerializerReadContextComplex(serializer, rootTypeDataContract, dataContractResolver)
103                 : new XmlObjectSerializerReadContext(serializer, rootTypeDataContract, dataContractResolver);
104         }
105
106         internal static XmlObjectSerializerReadContext CreateContext(NetDataContractSerializer serializer)
107         {
108             return new XmlObjectSerializerReadContextComplex(serializer);
109         }
110
111         internal XmlObjectSerializerReadContext(XmlObjectSerializer serializer, int maxItemsInObjectGraph, StreamingContext streamingContext, bool ignoreExtensionDataObject)
112             : base(serializer, maxItemsInObjectGraph, streamingContext, ignoreExtensionDataObject)
113         {
114         }
115
116         internal XmlObjectSerializerReadContext(DataContractSerializer serializer, DataContract rootTypeDataContract, DataContractResolver dataContractResolver)
117             : base(serializer, rootTypeDataContract, dataContractResolver)
118         {
119             this.attributes = new Attributes();
120         }
121
122         protected XmlObjectSerializerReadContext(NetDataContractSerializer serializer)
123             : base(serializer)
124         {
125             this.attributes = new Attributes();
126         }
127
128         public virtual object InternalDeserialize(XmlReaderDelegator xmlReader, int id, RuntimeTypeHandle declaredTypeHandle, string name, string ns)
129         {
130             DataContract dataContract = GetDataContract(id, declaredTypeHandle);
131             return InternalDeserialize(xmlReader, name, ns, Type.GetTypeFromHandle(declaredTypeHandle), ref dataContract);
132         }
133
134         internal virtual object InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, string name, string ns)
135         {
136             DataContract dataContract = GetDataContract(declaredType);
137             return InternalDeserialize(xmlReader, name, ns, declaredType, ref dataContract);
138         }
139
140         internal virtual object InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, string name, string ns)
141         {
142             if (dataContract == null)
143                 GetDataContract(declaredType);
144             return InternalDeserialize(xmlReader, name, ns, declaredType, ref dataContract);
145         }
146
147         protected bool TryHandleNullOrRef(XmlReaderDelegator reader, Type declaredType, string name, string ns, ref object retObj)
148         {
149             ReadAttributes(reader);
150
151             if (attributes.Ref != Globals.NewObjectId)
152             {
153                 if (this.isGetOnlyCollection)
154                 {
155                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsReferenceGetOnlyCollectionsNotSupported, attributes.Ref, DataContract.GetClrTypeFullName(declaredType))));
156                 }
157                 else
158                 {
159                     retObj = GetExistingObject(attributes.Ref, declaredType, name, ns);
160                     reader.Skip();
161                     return true;
162                 }
163             }
164             else if (attributes.XsiNil)
165             {
166                 reader.Skip();
167                 return true;
168             }
169             return false;
170         }
171
172         protected object InternalDeserialize(XmlReaderDelegator reader, string name, string ns, Type declaredType, ref DataContract dataContract)
173         {
174             object retObj = null;
175             if (TryHandleNullOrRef(reader, dataContract.UnderlyingType, name, ns, ref retObj))
176                 return retObj;
177
178             bool knownTypesAddedInCurrentScope = false;
179             if (dataContract.KnownDataContracts != null)
180             {
181                 scopedKnownTypes.Push(dataContract.KnownDataContracts);
182                 knownTypesAddedInCurrentScope = true;
183             }
184
185             if (attributes.XsiTypeName != null)
186             {
187                 dataContract = ResolveDataContractFromKnownTypes(attributes.XsiTypeName, attributes.XsiTypeNamespace, dataContract, declaredType);
188                 if (dataContract == null)
189                 {
190                     if (DataContractResolver == null)
191                     {
192                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(reader, SR.GetString(SR.DcTypeNotFoundOnDeserialize, attributes.XsiTypeNamespace, attributes.XsiTypeName, reader.NamespaceURI, reader.LocalName))));
193                     }
194                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(reader, SR.GetString(SR.DcTypeNotResolvedOnDeserialize, attributes.XsiTypeNamespace, attributes.XsiTypeName, reader.NamespaceURI, reader.LocalName))));
195                 }
196                 knownTypesAddedInCurrentScope = ReplaceScopedKnownTypesTop(dataContract.KnownDataContracts, knownTypesAddedInCurrentScope);
197             }
198
199             if (dataContract.IsISerializable && attributes.FactoryTypeName != null)
200             {
201                 DataContract factoryDataContract = ResolveDataContractFromKnownTypes(attributes.FactoryTypeName, attributes.FactoryTypeNamespace, dataContract, declaredType);
202                 if (factoryDataContract != null)
203                 {
204                     if (factoryDataContract.IsISerializable)
205                     {
206                         dataContract = factoryDataContract;
207                         knownTypesAddedInCurrentScope = ReplaceScopedKnownTypesTop(dataContract.KnownDataContracts, knownTypesAddedInCurrentScope);
208                     }
209                     else
210                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.FactoryTypeNotISerializable, DataContract.GetClrTypeFullName(factoryDataContract.UnderlyingType), DataContract.GetClrTypeFullName(dataContract.UnderlyingType))));
211                 }
212                 else
213                 {
214                     if (DiagnosticUtility.ShouldTraceWarning)
215                     {
216                         Dictionary<string, string> values = new Dictionary<string, string>(2);
217                         values["FactoryType"] = attributes.FactoryTypeNamespace + ":" + attributes.FactoryTypeName;
218                         values["ISerializableType"] = dataContract.StableName.Namespace + ":" + dataContract.StableName.Name;
219                         TraceUtility.Trace(TraceEventType.Warning, TraceCode.FactoryTypeNotFound,
220                             SR.GetString(SR.TraceCodeFactoryTypeNotFound), new DictionaryTraceRecord(values));
221                     }
222                 }
223             }
224
225             if (knownTypesAddedInCurrentScope)
226             {
227                 object obj = ReadDataContractValue(dataContract, reader);
228                 scopedKnownTypes.Pop();
229                 return obj;
230             }
231             else
232             {
233                 return ReadDataContractValue(dataContract, reader);
234             }
235         }
236
237         bool ReplaceScopedKnownTypesTop(Dictionary<XmlQualifiedName, DataContract> knownDataContracts, bool knownTypesAddedInCurrentScope)
238         {
239             if (knownTypesAddedInCurrentScope)
240             {
241                 scopedKnownTypes.Pop();
242                 knownTypesAddedInCurrentScope = false;
243             }
244             if (knownDataContracts != null)
245             {
246                 scopedKnownTypes.Push(knownDataContracts);
247                 knownTypesAddedInCurrentScope = true;
248             }
249             return knownTypesAddedInCurrentScope;
250         }
251
252         public static bool MoveToNextElement(XmlReaderDelegator xmlReader)
253         {
254             return (xmlReader.MoveToContent() != XmlNodeType.EndElement);
255         }
256
257         public int GetMemberIndex(XmlReaderDelegator xmlReader, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces, int memberIndex, ExtensionDataObject extensionData)
258         {
259             for (int i = memberIndex + 1; i < memberNames.Length; i++)
260             {
261                 if (xmlReader.IsStartElement(memberNames[i], memberNamespaces[i]))
262                     return i;
263             }
264             HandleMemberNotFound(xmlReader, extensionData, memberIndex);
265             return memberNames.Length;
266         }
267
268         public int GetMemberIndexWithRequiredMembers(XmlReaderDelegator xmlReader, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces, int memberIndex, int requiredIndex, ExtensionDataObject extensionData)
269         {
270             for (int i = memberIndex + 1; i < memberNames.Length; i++)
271             {
272                 if (xmlReader.IsStartElement(memberNames[i], memberNamespaces[i]))
273                 {
274                     if (requiredIndex < i)
275                         ThrowRequiredMemberMissingException(xmlReader, memberIndex, requiredIndex, memberNames);
276                     return i;
277                 }
278             }
279             HandleMemberNotFound(xmlReader, extensionData, memberIndex);
280             return memberNames.Length;
281         }
282
283         public static void ThrowRequiredMemberMissingException(XmlReaderDelegator xmlReader, int memberIndex, int requiredIndex, XmlDictionaryString[] memberNames)
284         {
285             StringBuilder stringBuilder = new StringBuilder();
286             if (requiredIndex == memberNames.Length)
287                 requiredIndex--;
288             for (int i = memberIndex + 1; i <= requiredIndex; i++)
289             {
290                 if (stringBuilder.Length != 0)
291                     stringBuilder.Append(" | ");
292                 stringBuilder.Append(memberNames[i].Value);
293             }
294             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.GetString(SR.UnexpectedElementExpectingElements, xmlReader.NodeType, xmlReader.LocalName, xmlReader.NamespaceURI, stringBuilder.ToString()))));
295         }
296
297         protected void HandleMemberNotFound(XmlReaderDelegator xmlReader, ExtensionDataObject extensionData, int memberIndex)
298         {
299             xmlReader.MoveToContent();
300             if (xmlReader.NodeType != XmlNodeType.Element)
301                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader));
302
303             if (IgnoreExtensionDataObject || extensionData == null)
304                 SkipUnknownElement(xmlReader);
305             else
306                 HandleUnknownElement(xmlReader, extensionData, memberIndex);
307         }
308
309         internal void HandleUnknownElement(XmlReaderDelegator xmlReader, ExtensionDataObject extensionData, int memberIndex)
310         {
311             if (extensionData.Members == null)
312                 extensionData.Members = new List<ExtensionDataMember>();
313             extensionData.Members.Add(ReadExtensionDataMember(xmlReader, memberIndex));
314         }
315
316         public void SkipUnknownElement(XmlReaderDelegator xmlReader)
317         {
318             ReadAttributes(xmlReader);
319             if (DiagnosticUtility.ShouldTraceVerbose)
320             {
321                 TraceUtility.Trace(TraceEventType.Verbose, TraceCode.ElementIgnored,
322                     SR.GetString(SR.TraceCodeElementIgnored), new StringTraceRecord("Element", xmlReader.NamespaceURI + ":" + xmlReader.LocalName));
323             }
324             xmlReader.Skip();
325         }
326
327         public string ReadIfNullOrRef(XmlReaderDelegator xmlReader, Type memberType, bool isMemberTypeSerializable)
328         {
329             if (attributes.Ref != Globals.NewObjectId)
330             {
331                 CheckIfTypeSerializable(memberType, isMemberTypeSerializable);
332                 xmlReader.Skip();
333                 return attributes.Ref;
334             }
335             else if (attributes.XsiNil)
336             {
337                 CheckIfTypeSerializable(memberType, isMemberTypeSerializable);
338                 xmlReader.Skip();
339                 return Globals.NullObjectId;
340             }
341             return Globals.NewObjectId;
342         }
343
344 #if USE_REFEMIT
345         public virtual void ReadAttributes(XmlReaderDelegator xmlReader)
346 #else
347         internal virtual void ReadAttributes(XmlReaderDelegator xmlReader)
348 #endif
349         {
350             if (attributes == null)
351                 attributes = new Attributes();
352             attributes.Read(xmlReader);
353         }
354
355         public void ResetAttributes()
356         {
357             if (attributes != null)
358                 attributes.Reset();
359         }
360
361         public string GetObjectId()
362         {
363             return attributes.Id;
364         }
365
366 #if USE_REFEMIT
367         public virtual int GetArraySize()
368 #else
369         internal virtual int GetArraySize()
370 #endif
371         {
372             return -1;
373         }
374
375         public void AddNewObject(object obj)
376         {
377             AddNewObjectWithId(attributes.Id, obj);
378         }
379
380         public void AddNewObjectWithId(string id, object obj)
381         {
382             if (id != Globals.NewObjectId)
383                 DeserializedObjects.Add(id, obj);
384             if (extensionDataReader != null)
385                 extensionDataReader.UnderlyingExtensionDataReader.SetDeserializedValue(obj);
386         }
387
388         public void ReplaceDeserializedObject(string id, object oldObj, object newObj)
389         {
390             if (object.ReferenceEquals(oldObj, newObj))
391                 return;
392
393             if (id != Globals.NewObjectId)
394             {
395                 // In certain cases (IObjectReference, SerializationSurrogate or DataContractSurrogate),
396                 // an object can be replaced with a different object once it is deserialized. If the 
397                 // object happens to be referenced from within itself, that reference needs to be updated
398                 // with the new instance. BinaryFormatter supports this by fixing up such references later. 
399                 // These XmlObjectSerializer implementations do not currently support fix-ups. Hence we 
400                 // throw in such cases to allow us add fix-up support in the future if we need to.
401                 if (DeserializedObjects.IsObjectReferenced(id))
402                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.FactoryObjectContainsSelfReference, DataContract.GetClrTypeFullName(oldObj.GetType()), DataContract.GetClrTypeFullName(newObj.GetType()), id)));
403                 DeserializedObjects.Remove(id);
404                 DeserializedObjects.Add(id, newObj);
405             }
406             if (extensionDataReader != null)
407                 extensionDataReader.UnderlyingExtensionDataReader.SetDeserializedValue(newObj);
408         }
409
410         public object GetExistingObject(string id, Type type, string name, string ns)
411         {
412             object retObj = DeserializedObjects.GetObject(id);
413             if (retObj == null)
414                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.DeserializedObjectWithIdNotFound, id)));
415             if (retObj is IDataNode)
416             {
417                 IDataNode dataNode = (IDataNode)retObj;
418                 retObj = (dataNode.Value != null && dataNode.IsFinalValue) ? dataNode.Value : DeserializeFromExtensionData(dataNode, type, name, ns);
419             }
420             return retObj;
421         }
422
423         object GetExistingObjectOrExtensionData(string id)
424         {
425             object retObj = DeserializedObjects.GetObject(id);
426             if (retObj == null)
427                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.DeserializedObjectWithIdNotFound, id)));
428             return retObj;
429         }
430
431         public object GetRealObject(IObjectReference obj, string id)
432         {
433             object realObj = SurrogateDataContract.GetRealObject(obj, this.GetStreamingContext());
434             // If GetRealObject returns null, it indicates that the object could not resolve itself because 
435             // it is missing information. This may occur in a case where multiple IObjectReference instances
436             // depend on each other. BinaryFormatter supports this by fixing up the references later. These
437             // XmlObjectSerializer implementations do not support fix-ups since the format does not contain
438             // forward references. However, we throw for this case since it allows us to add fix-up support 
439             // in the future if we need to.
440             if (realObj == null)
441                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.GetRealObjectReturnedNull, DataContract.GetClrTypeFullName(obj.GetType()))));
442             ReplaceDeserializedObject(id, obj, realObj);
443             return realObj;
444         }
445
446         object DeserializeFromExtensionData(IDataNode dataNode, Type type, string name, string ns)
447         {
448             ExtensionDataReader underlyingExtensionDataReader;
449             if (extensionDataReader == null)
450             {
451                 underlyingExtensionDataReader = new ExtensionDataReader(this);
452                 extensionDataReader = CreateReaderDelegatorForReader(underlyingExtensionDataReader);
453             }
454             else
455                 underlyingExtensionDataReader = extensionDataReader.UnderlyingExtensionDataReader;
456             underlyingExtensionDataReader.SetDataNode(dataNode, name, ns);
457             object retObj = InternalDeserialize(extensionDataReader, type, name, ns);
458             dataNode.Clear();
459             underlyingExtensionDataReader.Reset();
460             return retObj;
461         }
462
463         public static void Read(XmlReaderDelegator xmlReader)
464         {
465             if (!xmlReader.Read())
466                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.UnexpectedEndOfFile)));
467         }
468
469         internal static void ParseQualifiedName(string qname, XmlReaderDelegator xmlReader, out string name, out string ns, out string prefix)
470         {
471             int colon = qname.IndexOf(':');
472             prefix = "";
473             if (colon >= 0)
474                 prefix = qname.Substring(0, colon);
475             name = qname.Substring(colon + 1);
476             ns = xmlReader.LookupNamespace(prefix);
477         }
478
479         public static T[] EnsureArraySize<T>(T[] array, int index)
480         {
481             if (array.Length <= index)
482             {
483                 if (index == Int32.MaxValue)
484                 {
485                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
486                         XmlObjectSerializer.CreateSerializationException(
487                         SR.GetString(SR.MaxArrayLengthExceeded, Int32.MaxValue,
488                         DataContract.GetClrTypeFullName(typeof(T)))));
489                 }
490                 int newSize = (index < Int32.MaxValue / 2) ? index * 2 : Int32.MaxValue;
491                 T[] newArray = new T[newSize];
492                 Array.Copy(array, 0, newArray, 0, array.Length);
493                 array = newArray;
494             }
495             return array;
496         }
497
498         public static T[] TrimArraySize<T>(T[] array, int size)
499         {
500             if (size != array.Length)
501             {
502                 T[] newArray = new T[size];
503                 Array.Copy(array, 0, newArray, 0, size);
504                 array = newArray;
505             }
506             return array;
507         }
508
509         public void CheckEndOfArray(XmlReaderDelegator xmlReader, int arraySize, XmlDictionaryString itemName, XmlDictionaryString itemNamespace)
510         {
511             if (xmlReader.NodeType == XmlNodeType.EndElement)
512                 return;
513             while (xmlReader.IsStartElement())
514             {
515                 if (xmlReader.IsStartElement(itemName, itemNamespace))
516                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ArrayExceededSizeAttribute, arraySize, itemName.Value, itemNamespace.Value)));
517                 SkipUnknownElement(xmlReader);
518             }
519             if (xmlReader.NodeType != XmlNodeType.EndElement)
520                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.EndElement, xmlReader));
521         }
522
523         internal object ReadIXmlSerializable(XmlReaderDelegator xmlReader, XmlDataContract xmlDataContract, bool isMemberType)
524         {
525             if (xmlSerializableReader == null)
526                 xmlSerializableReader = new XmlSerializableReader();
527             return ReadIXmlSerializable(xmlSerializableReader, xmlReader, xmlDataContract, isMemberType);
528         }
529
530         internal static object ReadRootIXmlSerializable(XmlReaderDelegator xmlReader, XmlDataContract xmlDataContract, bool isMemberType)
531         {
532             return ReadIXmlSerializable(new XmlSerializableReader(), xmlReader, xmlDataContract, isMemberType);
533         }
534
535         internal static object ReadIXmlSerializable(XmlSerializableReader xmlSerializableReader, XmlReaderDelegator xmlReader, XmlDataContract xmlDataContract, bool isMemberType)
536         {
537             object obj = null;
538             xmlSerializableReader.BeginRead(xmlReader);
539             if (isMemberType && !xmlDataContract.HasRoot)
540             {
541                 xmlReader.Read();
542                 xmlReader.MoveToContent();
543             }
544             if (xmlDataContract.UnderlyingType == Globals.TypeOfXmlElement)
545             {
546                 if (!xmlReader.IsStartElement())
547                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader));
548                 XmlDocument xmlDoc = new XmlDocument();
549                 obj = (XmlElement)xmlDoc.ReadNode(xmlSerializableReader);
550             }
551             else if (xmlDataContract.UnderlyingType == Globals.TypeOfXmlNodeArray)
552             {
553                 obj = XmlSerializableServices.ReadNodes(xmlSerializableReader);
554             }
555             else
556             {
557                 IXmlSerializable xmlSerializable = xmlDataContract.CreateXmlSerializableDelegate();
558                 xmlSerializable.ReadXml(xmlSerializableReader);
559                 obj = xmlSerializable;
560             }
561             xmlSerializableReader.EndRead();
562             return obj;
563         }
564
565         public SerializationInfo ReadSerializationInfo(XmlReaderDelegator xmlReader, Type type)
566         {
567             SerializationInfo serInfo = new SerializationInfo(type, XmlObjectSerializer.FormatterConverter);
568             XmlNodeType nodeType;
569             while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement)
570             {
571                 if (nodeType != XmlNodeType.Element)
572                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader));
573
574                 if (xmlReader.NamespaceURI.Length != 0)
575                 {
576                     SkipUnknownElement(xmlReader);
577                     continue;
578                 }
579                 string name = XmlConvert.DecodeName(xmlReader.LocalName);
580
581                 IncrementItemCount(1);
582                 ReadAttributes(xmlReader);
583                 object value;
584                 if (attributes.Ref != Globals.NewObjectId)
585                 {
586                     xmlReader.Skip();
587                     value = GetExistingObject(attributes.Ref, null, name, String.Empty);
588                 }
589                 else if (attributes.XsiNil)
590                 {
591                     xmlReader.Skip();
592                     value = null;
593                 }
594                 else
595                 {
596                     value = InternalDeserialize(xmlReader, Globals.TypeOfObject, name, String.Empty);
597                 }
598
599                 serInfo.AddValue(name, value);
600             }
601
602             return serInfo;
603         }
604
605         protected virtual DataContract ResolveDataContractFromTypeName()
606         {
607             return (attributes.XsiTypeName == null) ? null : ResolveDataContractFromKnownTypes(attributes.XsiTypeName, attributes.XsiTypeNamespace, null /*memberTypeContract*/, null);
608         }
609
610         ExtensionDataMember ReadExtensionDataMember(XmlReaderDelegator xmlReader, int memberIndex)
611         {
612             ExtensionDataMember member = new ExtensionDataMember();
613             member.Name = xmlReader.LocalName;
614             member.Namespace = xmlReader.NamespaceURI;
615             member.MemberIndex = memberIndex;
616             if (xmlReader.UnderlyingExtensionDataReader != null)
617             {
618                 // no need to re-read extension data structure
619                 member.Value = xmlReader.UnderlyingExtensionDataReader.GetCurrentNode();
620             }
621             else
622                 member.Value = ReadExtensionDataValue(xmlReader);
623             return member;
624         }
625
626         public IDataNode ReadExtensionDataValue(XmlReaderDelegator xmlReader)
627         {
628             ReadAttributes(xmlReader);
629             IncrementItemCount(1);
630             IDataNode dataNode = null;
631             if (attributes.Ref != Globals.NewObjectId)
632             {
633                 xmlReader.Skip();
634                 object o = GetExistingObjectOrExtensionData(attributes.Ref);
635                 dataNode = (o is IDataNode) ? (IDataNode)o : new DataNode<object>(o);
636                 dataNode.Id = attributes.Ref;
637             }
638             else if (attributes.XsiNil)
639             {
640                 xmlReader.Skip();
641                 dataNode = null;
642             }
643             else
644             {
645                 string dataContractName = null;
646                 string dataContractNamespace = null;
647                 if (attributes.XsiTypeName != null)
648                 {
649                     dataContractName = attributes.XsiTypeName;
650                     dataContractNamespace = attributes.XsiTypeNamespace;
651                 }
652
653                 if (IsReadingCollectionExtensionData(xmlReader))
654                 {
655                     Read(xmlReader);
656                     dataNode = ReadUnknownCollectionData(xmlReader, dataContractName, dataContractNamespace);
657                 }
658                 else if (attributes.FactoryTypeName != null)
659                 {
660                     Read(xmlReader);
661                     dataNode = ReadUnknownISerializableData(xmlReader, dataContractName, dataContractNamespace);
662                 }
663                 else if (IsReadingClassExtensionData(xmlReader))
664                 {
665                     Read(xmlReader);
666                     dataNode = ReadUnknownClassData(xmlReader, dataContractName, dataContractNamespace);
667                 }
668                 else
669                 {
670                     DataContract dataContract = ResolveDataContractFromTypeName();
671
672                     if (dataContract == null)
673                         dataNode = ReadExtensionDataValue(xmlReader, dataContractName, dataContractNamespace);
674                     else if (dataContract is XmlDataContract)
675                         dataNode = ReadUnknownXmlData(xmlReader, dataContractName, dataContractNamespace);
676                     else
677                     {
678                         if (dataContract.IsISerializable)
679                         {
680                             Read(xmlReader);
681                             dataNode = ReadUnknownISerializableData(xmlReader, dataContractName, dataContractNamespace);
682                         }
683                         else if (dataContract is PrimitiveDataContract)
684                         {
685                             if (attributes.Id == Globals.NewObjectId)
686                             {
687                                 Read(xmlReader);
688                                 xmlReader.MoveToContent();
689                                 dataNode = ReadUnknownPrimitiveData(xmlReader, dataContract.UnderlyingType, dataContractName, dataContractNamespace);
690                                 xmlReader.ReadEndElement();
691                             }
692                             else
693                             {
694                                 dataNode = new DataNode<object>(xmlReader.ReadElementContentAsAnyType(dataContract.UnderlyingType));
695                                 InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace);
696                             }
697                         }
698                         else if (dataContract is EnumDataContract)
699                         {
700                             dataNode = new DataNode<object>(((EnumDataContract)dataContract).ReadEnumValue(xmlReader));
701                             InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace);
702                         }
703                         else if (dataContract is ClassDataContract)
704                         {
705                             Read(xmlReader);
706                             dataNode = ReadUnknownClassData(xmlReader, dataContractName, dataContractNamespace);
707                         }
708                         else if (dataContract is CollectionDataContract)
709                         {
710                             Read(xmlReader);
711                             dataNode = ReadUnknownCollectionData(xmlReader, dataContractName, dataContractNamespace);
712                         }
713                     }
714                 }
715             }
716             return dataNode;
717         }
718
719         protected virtual void StartReadExtensionDataValue(XmlReaderDelegator xmlReader)
720         {
721         }
722
723         IDataNode ReadExtensionDataValue(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace)
724         {
725             StartReadExtensionDataValue(xmlReader);
726
727             if (attributes.UnrecognizedAttributesFound)
728                 return ReadUnknownXmlData(xmlReader, dataContractName, dataContractNamespace);
729
730             IDictionary<string, string> namespacesInScope = xmlReader.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml);
731             Read(xmlReader);
732             xmlReader.MoveToContent();
733
734             switch (xmlReader.NodeType)
735             {
736                 case XmlNodeType.Text:
737                     return ReadPrimitiveExtensionDataValue(xmlReader, dataContractName, dataContractNamespace);
738                 case XmlNodeType.Element:
739                     if (xmlReader.NamespaceURI.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal))
740                         return ReadUnknownClassData(xmlReader, dataContractName, dataContractNamespace);
741                     else
742                         return ReadAndResolveUnknownXmlData(xmlReader, namespacesInScope, dataContractName, dataContractNamespace);
743
744                 case XmlNodeType.EndElement:
745                     {
746                         // NOTE: cannot distinguish between empty class or IXmlSerializable and typeof(object) 
747                         IDataNode objNode = ReadUnknownPrimitiveData(xmlReader, Globals.TypeOfObject, dataContractName, dataContractNamespace);
748                         xmlReader.ReadEndElement();
749                         objNode.IsFinalValue = false;
750                         return objNode;
751                     }
752                 default:
753                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader));
754             }
755         }
756
757         protected virtual IDataNode ReadPrimitiveExtensionDataValue(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace)
758         {
759             Type valueType = xmlReader.ValueType;
760             if (valueType == Globals.TypeOfString)
761             {
762                 // NOTE: cannot distinguish other primitives from string (default XmlReader ValueType)
763                 IDataNode stringNode = new DataNode<object>(xmlReader.ReadContentAsString());
764                 InitializeExtensionDataNode(stringNode, dataContractName, dataContractNamespace);
765                 stringNode.IsFinalValue = false;
766                 xmlReader.ReadEndElement();
767                 return stringNode;
768             }
769             else
770             {
771                 IDataNode objNode = ReadUnknownPrimitiveData(xmlReader, valueType, dataContractName, dataContractNamespace);
772                 xmlReader.ReadEndElement();
773                 return objNode;
774             }
775         }
776
777         protected void InitializeExtensionDataNode(IDataNode dataNode, string dataContractName, string dataContractNamespace)
778         {
779             dataNode.DataContractName = dataContractName;
780             dataNode.DataContractNamespace = dataContractNamespace;
781             dataNode.ClrAssemblyName = attributes.ClrAssembly;
782             dataNode.ClrTypeName = attributes.ClrType;
783             AddNewObject(dataNode);
784             dataNode.Id = attributes.Id;
785         }
786
787         IDataNode ReadUnknownPrimitiveData(XmlReaderDelegator xmlReader, Type type, string dataContractName, string dataContractNamespace)
788         {
789             IDataNode dataNode = xmlReader.ReadExtensionData(type);
790             InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace);
791             return dataNode;
792         }
793
794         ClassDataNode ReadUnknownClassData(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace)
795         {
796             ClassDataNode dataNode = new ClassDataNode();
797             InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace);
798
799             int memberIndex = 0;
800             XmlNodeType nodeType;
801             while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement)
802             {
803                 if (nodeType != XmlNodeType.Element)
804                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader));
805
806                 if (dataNode.Members == null)
807                     dataNode.Members = new List<ExtensionDataMember>();
808                 dataNode.Members.Add(ReadExtensionDataMember(xmlReader, memberIndex++));
809             }
810             xmlReader.ReadEndElement();
811             return dataNode;
812         }
813
814         CollectionDataNode ReadUnknownCollectionData(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace)
815         {
816             CollectionDataNode dataNode = new CollectionDataNode();
817             InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace);
818
819             int arraySize = attributes.ArraySZSize;
820             XmlNodeType nodeType;
821             while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement)
822             {
823                 if (nodeType != XmlNodeType.Element)
824                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader));
825
826                 if (dataNode.ItemName == null)
827                 {
828                     dataNode.ItemName = xmlReader.LocalName;
829                     dataNode.ItemNamespace = xmlReader.NamespaceURI;
830                 }
831                 if (xmlReader.IsStartElement(dataNode.ItemName, dataNode.ItemNamespace))
832                 {
833                     if (dataNode.Items == null)
834                         dataNode.Items = new List<IDataNode>();
835                     dataNode.Items.Add(ReadExtensionDataValue(xmlReader));
836                 }
837                 else
838                     SkipUnknownElement(xmlReader);
839             }
840             xmlReader.ReadEndElement();
841
842             if (arraySize != -1)
843             {
844                 dataNode.Size = arraySize;
845                 if (dataNode.Items == null)
846                 {
847                     if (dataNode.Size > 0)
848                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ArraySizeAttributeIncorrect, arraySize, 0)));
849                 }
850                 else if (dataNode.Size != dataNode.Items.Count)
851                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ArraySizeAttributeIncorrect, arraySize, dataNode.Items.Count)));
852             }
853             else
854             {
855                 if (dataNode.Items != null)
856                 {
857                     dataNode.Size = dataNode.Items.Count;
858                 }
859                 else
860                 {
861                     dataNode.Size = 0;
862                 }
863             }
864
865             return dataNode;
866         }
867
868         ISerializableDataNode ReadUnknownISerializableData(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace)
869         {
870             ISerializableDataNode dataNode = new ISerializableDataNode();
871             InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace);
872
873             dataNode.FactoryTypeName = attributes.FactoryTypeName;
874             dataNode.FactoryTypeNamespace = attributes.FactoryTypeNamespace;
875
876             XmlNodeType nodeType;
877             while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement)
878             {
879                 if (nodeType != XmlNodeType.Element)
880                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader));
881
882                 if (xmlReader.NamespaceURI.Length != 0)
883                 {
884                     SkipUnknownElement(xmlReader);
885                     continue;
886                 }
887
888                 ISerializableDataMember member = new ISerializableDataMember();
889                 member.Name = xmlReader.LocalName;
890                 member.Value = ReadExtensionDataValue(xmlReader);
891                 if (dataNode.Members == null)
892                     dataNode.Members = new List<ISerializableDataMember>();
893                 dataNode.Members.Add(member);
894             }
895             xmlReader.ReadEndElement();
896             return dataNode;
897         }
898
899         IDataNode ReadUnknownXmlData(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace)
900         {
901             XmlDataNode dataNode = new XmlDataNode();
902             InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace);
903             dataNode.OwnerDocument = Document;
904
905             if (xmlReader.NodeType == XmlNodeType.EndElement)
906                 return dataNode;
907
908             IList<XmlAttribute> xmlAttributes = null;
909             IList<XmlNode> xmlChildNodes = null;
910
911             XmlNodeType nodeType = xmlReader.MoveToContent();
912             if (nodeType != XmlNodeType.Text)
913             {
914                 while (xmlReader.MoveToNextAttribute())
915                 {
916                     string ns = xmlReader.NamespaceURI;
917                     if (ns != Globals.SerializationNamespace && ns != Globals.SchemaInstanceNamespace)
918                     {
919                         if (xmlAttributes == null)
920                             xmlAttributes = new List<XmlAttribute>();
921                         xmlAttributes.Add((XmlAttribute)Document.ReadNode(xmlReader.UnderlyingReader));
922                     }
923                 }
924                 Read(xmlReader);
925             }
926
927             while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement)
928             {
929                 if (xmlReader.EOF)
930                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.UnexpectedEndOfFile)));
931
932                 if (xmlChildNodes == null)
933                     xmlChildNodes = new List<XmlNode>();
934                 xmlChildNodes.Add(Document.ReadNode(xmlReader.UnderlyingReader));
935             }
936             xmlReader.ReadEndElement();
937
938             dataNode.XmlAttributes = xmlAttributes;
939             dataNode.XmlChildNodes = xmlChildNodes;
940             return dataNode;
941         }
942
943         // Pattern-recognition logic: the method reads XML elements into DOM. To recognize as an array, it requires that 
944         // all items have the same name and namespace. To recognize as an ISerializable type, it requires that all
945         // items be unqualified. If the XML only contains elements (no attributes or other nodes) is recognized as a 
946         // class/class hierarchy. Otherwise it is deserialized as XML.
947         IDataNode ReadAndResolveUnknownXmlData(XmlReaderDelegator xmlReader, IDictionary<string, string> namespaces,
948             string dataContractName, string dataContractNamespace)
949         {
950             bool couldBeISerializableData = true;
951             bool couldBeCollectionData = true;
952             bool couldBeClassData = true;
953             string elementNs = null, elementName = null;
954             IList<XmlNode> xmlChildNodes = new List<XmlNode>();
955             IList<XmlAttribute> xmlAttributes = null;
956             if (namespaces != null)
957             {
958                 xmlAttributes = new List<XmlAttribute>();
959                 foreach (KeyValuePair<string, string> prefixNsPair in namespaces)
960                 {
961                     xmlAttributes.Add(AddNamespaceDeclaration(prefixNsPair.Key, prefixNsPair.Value));
962                 }
963             }
964
965             XmlNodeType nodeType;
966             while ((nodeType = xmlReader.NodeType) != XmlNodeType.EndElement)
967             {
968                 if (nodeType == XmlNodeType.Element)
969                 {
970                     string ns = xmlReader.NamespaceURI;
971                     string name = xmlReader.LocalName;
972                     if (couldBeISerializableData)
973                         couldBeISerializableData = (ns.Length == 0);
974                     if (couldBeCollectionData)
975                     {
976                         if (elementName == null)
977                         {
978                             elementName = name;
979                             elementNs = ns;
980                         }
981                         else
982                             couldBeCollectionData = (String.CompareOrdinal(elementName, name) == 0) &&
983                                 (String.CompareOrdinal(elementNs, ns) == 0);
984                     }
985                 }
986                 else if (xmlReader.EOF)
987                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.UnexpectedEndOfFile)));
988                 else if (IsContentNode(xmlReader.NodeType))
989                     couldBeClassData = couldBeISerializableData = couldBeCollectionData = false;
990
991                 if (attributesInXmlData == null) attributesInXmlData = new Attributes();
992                 attributesInXmlData.Read(xmlReader);
993
994                 XmlNode childNode = Document.ReadNode(xmlReader.UnderlyingReader);
995                 xmlChildNodes.Add(childNode);
996
997                 if (namespaces == null)
998                 {
999                     if (attributesInXmlData.XsiTypeName != null)
1000                         childNode.Attributes.Append(AddNamespaceDeclaration(attributesInXmlData.XsiTypePrefix, attributesInXmlData.XsiTypeNamespace));
1001                     if (attributesInXmlData.FactoryTypeName != null)
1002                         childNode.Attributes.Append(AddNamespaceDeclaration(attributesInXmlData.FactoryTypePrefix, attributesInXmlData.FactoryTypeNamespace));
1003                 }
1004             }
1005             xmlReader.ReadEndElement();
1006
1007             if (elementName != null && couldBeCollectionData)
1008                 return ReadUnknownCollectionData(CreateReaderOverChildNodes(xmlAttributes, xmlChildNodes), dataContractName, dataContractNamespace);
1009             else if (couldBeISerializableData)
1010                 return ReadUnknownISerializableData(CreateReaderOverChildNodes(xmlAttributes, xmlChildNodes), dataContractName, dataContractNamespace);
1011             else if (couldBeClassData)
1012                 return ReadUnknownClassData(CreateReaderOverChildNodes(xmlAttributes, xmlChildNodes), dataContractName, dataContractNamespace);
1013             else
1014             {
1015                 XmlDataNode dataNode = new XmlDataNode();
1016                 InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace);
1017                 dataNode.OwnerDocument = Document;
1018                 dataNode.XmlChildNodes = xmlChildNodes;
1019                 dataNode.XmlAttributes = xmlAttributes;
1020                 return dataNode;
1021             }
1022         }
1023
1024         bool IsContentNode(XmlNodeType nodeType)
1025         {
1026             switch (nodeType)
1027             {
1028                 case XmlNodeType.Whitespace:
1029                 case XmlNodeType.SignificantWhitespace:
1030                 case XmlNodeType.Comment:
1031                 case XmlNodeType.ProcessingInstruction:
1032                 case XmlNodeType.DocumentType:
1033                     return false;
1034                 default:
1035                     return true;
1036             }
1037         }
1038
1039         internal XmlReaderDelegator CreateReaderOverChildNodes(IList<XmlAttribute> xmlAttributes, IList<XmlNode> xmlChildNodes)
1040         {
1041             XmlNode wrapperElement = CreateWrapperXmlElement(Document, xmlAttributes, xmlChildNodes, null, null, null);
1042             XmlReaderDelegator nodeReader = CreateReaderDelegatorForReader(new XmlNodeReader(wrapperElement));
1043             nodeReader.MoveToContent();
1044             Read(nodeReader);
1045             return nodeReader;
1046         }
1047
1048         internal static XmlNode CreateWrapperXmlElement(XmlDocument document, IList<XmlAttribute> xmlAttributes, IList<XmlNode> xmlChildNodes, string prefix, string localName, string ns)
1049         {
1050             localName = localName ?? "wrapper";
1051             ns = ns ?? String.Empty;
1052             XmlNode wrapperElement = document.CreateElement(prefix, localName, ns);
1053             if (xmlAttributes != null)
1054             {
1055                 for (int i = 0; i < xmlAttributes.Count; i++)
1056                     wrapperElement.Attributes.Append((XmlAttribute)xmlAttributes[i]);
1057             }
1058             if (xmlChildNodes != null)
1059             {
1060                 for (int i = 0; i < xmlChildNodes.Count; i++)
1061                     wrapperElement.AppendChild(xmlChildNodes[i]);
1062             }
1063             return wrapperElement;
1064         }
1065
1066         XmlAttribute AddNamespaceDeclaration(string prefix, string ns)
1067         {
1068             XmlAttribute attribute = (prefix == null || prefix.Length == 0) ?
1069                 Document.CreateAttribute(null, Globals.XmlnsPrefix, Globals.XmlnsNamespace) :
1070                 Document.CreateAttribute(Globals.XmlnsPrefix, prefix, Globals.XmlnsNamespace);
1071             attribute.Value = ns;
1072             return attribute;
1073         }
1074
1075         public static Exception CreateUnexpectedStateException(XmlNodeType expectedState, XmlReaderDelegator xmlReader)
1076         {
1077             return XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.GetString(SR.ExpectingState, expectedState), xmlReader);
1078         }
1079
1080         protected virtual object ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
1081         {
1082             return dataContract.ReadXmlValue(reader, this);
1083         }
1084
1085         protected virtual XmlReaderDelegator CreateReaderDelegatorForReader(XmlReader xmlReader)
1086         {
1087             return new XmlReaderDelegator(xmlReader);
1088         }
1089
1090         protected virtual bool IsReadingCollectionExtensionData(XmlReaderDelegator xmlReader)
1091         {
1092             return (attributes.ArraySZSize != -1);
1093         }
1094
1095         protected virtual bool IsReadingClassExtensionData(XmlReaderDelegator xmlReader)
1096         {
1097             return false;
1098         }
1099     }
1100 }