1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Reflection;
5 using System.Xml;
6 
7 namespace System.Runtime.Serialization
8 {
9 	internal partial class XmlFormatReaderGenerator
10 	{
11 		partial class CriticalHelper
12 		{
GenerateClassReader(ClassDataContract classContract)13 			internal XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
14 			{
15 				return (XmlReaderDelegator xr, XmlObjectSerializerReadContext ctx, XmlDictionaryString [] memberNames, XmlDictionaryString [] memberNamespaces) => new XmlFormatReaderInterpreter (classContract).ReadFromXml (xr, ctx, memberNames, memberNamespaces);
16 			}
17 
GenerateCollectionReader(CollectionDataContract collectionContract)18 			internal XmlFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
19 			{
20 				return (XmlReaderDelegator xr, XmlObjectSerializerReadContext ctx, XmlDictionaryString inm, XmlDictionaryString ins, CollectionDataContract cc) => new XmlFormatReaderInterpreter (collectionContract, false).ReadCollectionFromXml (xr, ctx, inm, ins, cc);
21 			}
22 
GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)23 			internal XmlFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
24 			{
25 				return (XmlReaderDelegator xr, XmlObjectSerializerReadContext ctx, XmlDictionaryString inm, XmlDictionaryString ins, CollectionDataContract cc) => new XmlFormatReaderInterpreter (collectionContract, true).ReadGetOnlyCollectionFromXml (xr, ctx, inm, ins, cc);
26 			}
27 		}
28 	}
29 
30 	class XmlFormatReaderInterpreter
31 	{
XmlFormatReaderInterpreter(ClassDataContract classContract)32 		public XmlFormatReaderInterpreter (ClassDataContract classContract)
33 		{
34 			this.classContract = classContract;
35 		}
36 
XmlFormatReaderInterpreter(CollectionDataContract collectionContract, bool isGetOnly)37 		public XmlFormatReaderInterpreter (CollectionDataContract collectionContract, bool isGetOnly)
38 		{
39 			this.collectionContract = collectionContract;
40 			this.is_get_only_collection = isGetOnly;
41 		}
42 
43 		bool is_get_only_collection;
44 
45 		ClassDataContract classContract;
46 
47 		CollectionDataContract collectionContract;
48 
49 		object objectLocal;
50 		Type objectType;
51 		XmlReaderDelegator xmlReader;
52 		XmlObjectSerializerReadContext context;
53 
54 		XmlDictionaryString [] memberNames = null;
55 		XmlDictionaryString [] memberNamespaces = null;
56 		XmlDictionaryString itemName = null;
57 		XmlDictionaryString itemNamespace = null;
58 
ReadFromXml(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces)59 		public object ReadFromXml (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces)
60 		{
61 			// InitArgs()
62 			this.xmlReader = xmlReader;
63 			this.context = context;
64 			this.memberNames = memberNames;
65 			this.memberNamespaces = memberNamespaces;
66 
67 			//DemandSerializationFormatterPermission(classContract);
68 			//DemandMemberAccessPermission(memberAccessFlag);
69 			CreateObject (classContract);
70 
71 			context.AddNewObject (objectLocal);
72 			InvokeOnDeserializing (classContract);
73 
74             string objectId = null;
75 
76 			if (HasFactoryMethod (classContract))
77 				objectId = context.GetObjectId ();
78 			if (classContract.IsISerializable)
79 				ReadISerializable (classContract);
80 			else
81 				ReadClass (classContract);
82 			bool isFactoryType = InvokeFactoryMethod (classContract, objectId);
83 			if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom (classContract.UnderlyingType))
84 				((IDeserializationCallback) objectLocal).OnDeserialization (null);
85 			InvokeOnDeserialized(classContract);
86 			if (objectId == null || !isFactoryType) {
87 
88 				// Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization.
89 				// DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation
90 				// on DateTimeOffset; which does not work in partial trust.
91 
92 				if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter)
93 					objectLocal = DateTimeOffsetAdapter.GetDateTimeOffset ((DateTimeOffsetAdapter) objectLocal);
94 				// else - do we have to call CodeInterpreter.ConvertValue()? I guess not...
95 			}
96 			return objectLocal;
97 		}
98 
ReadCollectionFromXml(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract)99 		public object ReadCollectionFromXml (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract)
100 		{
101 			#region GenerateCollectionReaderHelper
102 			// InitArgs()
103 			this.xmlReader = xmlReader;
104 			this.context = context;
105 			this.itemName = itemName;
106 			this.itemNamespace = itemNamespace;
107 
108 			this.collectionContract = collectionContract;
109 
110 			#endregion
111 
112 			ReadCollection (collectionContract);
113 
114 			return objectLocal;
115 		}
116 
ReadGetOnlyCollectionFromXml(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract)117 		public void ReadGetOnlyCollectionFromXml (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract)
118 		{
119 			#region GenerateCollectionReaderHelper
120 			// InitArgs()
121 			this.xmlReader = xmlReader;
122 			this.context = context;
123 			this.itemName = itemName;
124 			this.itemNamespace = itemNamespace;
125 
126 			this.collectionContract = collectionContract;
127 
128 			#endregion
129 
130 			ReadGetOnlyCollection (collectionContract);
131 		}
132 
CreateObject(ClassDataContract classContract)133 		void CreateObject (ClassDataContract classContract)
134 		{
135 			Type type = objectType = classContract.UnderlyingType;
136 			if (type.IsValueType && !classContract.IsNonAttributedType)
137 				type = Globals.TypeOfValueType;
138 
139 			if (classContract.UnderlyingType == Globals.TypeOfDBNull)
140 				objectLocal = DBNull.Value;
141 			else if (classContract.IsNonAttributedType) {
142 				if (type.IsValueType)
143 					objectLocal = FormatterServices.GetUninitializedObject (type);
144 				else
145 					objectLocal = classContract.GetNonAttributedTypeConstructor ().Invoke (new object [0]);
146 			}
147 			else
148 				objectLocal = CodeInterpreter.ConvertValue (XmlFormatReaderGenerator.UnsafeGetUninitializedObject (DataContract.GetIdForInitialization (classContract)), Globals.TypeOfObject, type);
149 		}
150 
InvokeOnDeserializing(ClassDataContract classContract)151 		void InvokeOnDeserializing (ClassDataContract classContract)
152 		{
153 			if (classContract.BaseContract != null)
154 				InvokeOnDeserializing (classContract.BaseContract);
155 			if (classContract.OnDeserializing != null)
156 				classContract.OnDeserializing.Invoke (objectLocal, new object [] {context.GetStreamingContext ()});
157 		}
158 
InvokeOnDeserialized(ClassDataContract classContract)159 		void InvokeOnDeserialized (ClassDataContract classContract)
160 		{
161 			if (classContract.BaseContract != null)
162 				InvokeOnDeserialized (classContract.BaseContract);
163 			if (classContract.OnDeserialized != null)
164 				classContract.OnDeserialized.Invoke (objectLocal, new object [] {context.GetStreamingContext ()});
165 		}
166 
HasFactoryMethod(ClassDataContract classContract)167 		bool HasFactoryMethod (ClassDataContract classContract)
168 		{
169 			return Globals.TypeOfIObjectReference.IsAssignableFrom (classContract.UnderlyingType);
170 		}
171 
InvokeFactoryMethod(ClassDataContract classContract, string objectId)172 		bool InvokeFactoryMethod (ClassDataContract classContract, string objectId)
173 		{
174 			if (HasFactoryMethod (classContract)) {
175 				objectLocal = CodeInterpreter.ConvertValue (context.GetRealObject ((IObjectReference) objectLocal, objectId), Globals.TypeOfObject, classContract.UnderlyingType);
176 				return true;
177 			}
178 			return false;
179 		}
180 
ReadISerializable(ClassDataContract classContract)181 		void ReadISerializable (ClassDataContract classContract)
182 		{
183 			ConstructorInfo ctor = classContract.GetISerializableConstructor ();
184 			var info = context.ReadSerializationInfo (xmlReader, classContract.UnderlyingType);
185 			ctor.Invoke (objectLocal, new object [] {info, context.GetStreamingContext ()});
186 		}
187 
ReadClass(ClassDataContract classContract)188 		void ReadClass (ClassDataContract classContract)
189 		{
190 			if (classContract.HasExtensionData) {
191 				ExtensionDataObject extensionData = new ExtensionDataObject ();
192 				ReadMembers (classContract, extensionData);
193 				ClassDataContract currentContract = classContract;
194 				while (currentContract != null) {
195 					MethodInfo extensionDataSetMethod = currentContract.ExtensionDataSetMethod;
196 					if (extensionDataSetMethod != null)
197 						extensionDataSetMethod.Invoke (objectLocal, new object [] {extensionData});
198 					currentContract = currentContract.BaseContract;
199 				}
200 			}
201 			else
202 				ReadMembers (classContract, null);
203 		}
204 
ReadMembers(ClassDataContract classContract, ExtensionDataObject extensionData)205 		void ReadMembers (ClassDataContract classContract, ExtensionDataObject  extensionData)
206 		{
207 			int memberCount = classContract.MemberNames.Length;
208 			context.IncrementItemCount (memberCount);
209 
210 			int memberIndex = -1;
211 
212 			int firstRequiredMember;
213 			bool[] requiredMembers = GetRequiredMembers (classContract, out firstRequiredMember);
214 			bool hasRequiredMembers = (firstRequiredMember < memberCount);
215 			int requiredIndex = hasRequiredMembers ? firstRequiredMember : memberCount;
216 
217 			while (XmlObjectSerializerReadContext.MoveToNextElement (xmlReader)) {
218 				int idx; // used as in "switch (idx)" in the original source.
219 				if (hasRequiredMembers)
220 					idx = context.GetMemberIndexWithRequiredMembers (xmlReader, memberNames, memberNamespaces, memberIndex, (int) requiredIndex, extensionData);
221 				else
222 					idx = context.GetMemberIndex (xmlReader, memberNames, memberNamespaces, memberIndex, extensionData);
223 
224 				if (memberCount > 0)
225 					ReadMembers (idx, classContract, requiredMembers, ref memberIndex, ref requiredIndex);
226 			}
227 
228 			if (hasRequiredMembers)
229 			{
230 				if (requiredIndex < memberCount)
231 					XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException (xmlReader, memberIndex, requiredIndex, memberNames);
232 			}
233 		}
234 
ReadMembers(int index, ClassDataContract classContract, bool [] requiredMembers, ref int memberIndex, ref int requiredIndex)235 		int ReadMembers (int index, ClassDataContract classContract, bool [] requiredMembers, ref int memberIndex, ref int requiredIndex)
236 		{
237 			int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers (index, classContract.BaseContract, requiredMembers,
238 			ref memberIndex, ref requiredIndex);
239 
240 			if (memberCount <= index && index < memberCount + classContract.Members.Count) {
241 				DataMember dataMember = classContract.Members [index - memberCount];
242 				Type memberType = dataMember.MemberType;
243 				if (dataMember.IsRequired) {
244 					int nextRequiredIndex = index + 1;
245 					for (; nextRequiredIndex < requiredMembers.Length; nextRequiredIndex++)
246 						if (requiredMembers [nextRequiredIndex])
247 							break;
248 					requiredIndex = nextRequiredIndex;
249 				}
250 
251 				if (dataMember.IsGetOnlyCollection) {
252 					var value = CodeInterpreter.GetMember (dataMember.MemberInfo, objectLocal);
253 					context.StoreCollectionMemberInfo (value);
254 					ReadValue (memberType, dataMember.Name, classContract.StableName.Namespace);
255 				} else {
256 					var value = ReadValue (memberType, dataMember.Name, classContract.StableName.Namespace);
257 					CodeInterpreter.SetMember (dataMember.MemberInfo, objectLocal, value);
258 				}
259 				memberIndex = index;
260 			}
261 			return memberCount + classContract.Members.Count;
262 		}
263 
GetRequiredMembers(ClassDataContract contract, out int firstRequiredMember)264 		bool[] GetRequiredMembers (ClassDataContract contract, out int firstRequiredMember)
265 		{
266 			int memberCount = contract.MemberNames.Length;
267 			bool [] requiredMembers = new bool [memberCount];
268 			GetRequiredMembers (contract, requiredMembers);
269 			for (firstRequiredMember = 0; firstRequiredMember < memberCount; firstRequiredMember++)
270 				if (requiredMembers [firstRequiredMember])
271 					break;
272 			return requiredMembers;
273 		}
274 
GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers)275 		int GetRequiredMembers (ClassDataContract contract, bool[] requiredMembers)
276 		{
277 			int memberCount = (contract.BaseContract == null) ? 0 : GetRequiredMembers (contract.BaseContract, requiredMembers);
278 			List<DataMember> members = contract.Members;
279 			for (int i = 0; i < members.Count; i++, memberCount++)
280 				requiredMembers [memberCount] = members [i].IsRequired;
281 			return memberCount;
282 		}
283 
ReadValue(Type type, string name, string ns)284 		object ReadValue (Type type, string name, string ns)
285 		{
286 			var valueType = type;
287 			object value = null;
288 			bool shouldAssignNullableValue = false;
289 			int nullables = 0;
290 			while (type.IsGenericType && type.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
291 				nullables++;
292 				type = type.GetGenericArguments () [0];
293 			}
294 
295 			PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract (type);
296 			if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType) {
297 				context.ReadAttributes (xmlReader);
298 				string objectId = context.ReadIfNullOrRef (xmlReader, type, DataContract.IsTypeSerializable (type));
299 				// Deserialize null
300                 if (objectId == Globals.NullObjectId) {
301 
302 					if (nullables != 0)
303 						value = Activator.CreateInstance (valueType);
304 					else if (type.IsValueType)
305 						throw new SerializationException (SR.GetString (SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName (type)));
306 					else
307 						value = null;
308 				} else if (objectId == string.Empty) {
309 					// Deserialize value
310 
311 					// Compare against Globals.NewObjectId, which is set to string.Empty
312 
313 					objectId = context.GetObjectId ();
314 
315 					if (type.IsValueType) {
316 						if (!string.IsNullOrEmpty (objectId))
317 							throw new SerializationException (SR.GetString (SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
318 					}
319 					object innerValueRead = null;
320 					if (nullables != 0)
321 						shouldAssignNullableValue = true;
322 
323 					if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) {
324 						value = primitiveContract.XmlFormatReaderMethod.Invoke (xmlReader, new object [0]);
325 						if (!type.IsValueType)
326 							context.AddNewObject (value);
327 					}
328 					else
329 							value = InternalDeserialize (type, name, ns);
330 				} else {
331 					// Deserialize ref
332 					if (type.IsValueType)
333 						throw new SerializationException (SR.GetString (SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName (type)));
334 					else
335 						value = CodeInterpreter.ConvertValue (context.GetExistingObject (objectId, type, name, ns), Globals.TypeOfObject, type);
336 				}
337 
338 				if (shouldAssignNullableValue) {
339 					if (objectId != Globals.NullObjectId)
340 						value = WrapNullableObject (type, value, valueType, nullables);
341 				}
342 			}
343 			else
344 				value = InternalDeserialize (type, name, ns);
345 
346 			return value;
347 		}
348 
InternalDeserialize(Type type, string name, string ns)349 		object InternalDeserialize (Type type, string name, string ns)
350 		{
351 			Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type;
352 			var obj = context.InternalDeserialize (xmlReader, DataContract.GetId (declaredType.TypeHandle), declaredType.TypeHandle, name, ns);
353 
354 			if (type.IsPointer)
355 				// wow, there is no way to convert void* to object in strongly typed way...
356 				return XmlFormatGeneratorStatics.UnboxPointer.Invoke (null, new object [] {obj});
357 			else
358 				return CodeInterpreter.ConvertValue (obj, Globals.TypeOfObject, type);
359 		}
360 
WrapNullableObject(Type innerType, object innerValue, Type outerType, int nullables)361 		object WrapNullableObject (Type innerType, object innerValue, Type outerType, int nullables)
362 		{
363 			var outerValue = innerValue;
364 			for (int i = 1; i < nullables; i++) {
365 				Type type = Globals.TypeOfNullable.MakeGenericType (innerType);
366 				outerValue = Activator.CreateInstance (type, new object[] { outerValue });
367 				innerType = type;
368 			}
369 			return Activator.CreateInstance (outerType, new object[] { outerValue });
370 		}
371 
372 
ReadCollection(CollectionDataContract collectionContract)373 		void ReadCollection (CollectionDataContract collectionContract)
374 		{
375 			Type type = collectionContract.UnderlyingType;
376 			Type itemType = collectionContract.ItemType;
377 			bool isArray = (collectionContract.Kind == CollectionKind.Array);
378 
379 			ConstructorInfo constructor = collectionContract.Constructor;
380 
381 			if (type.IsInterface) {
382 				switch (collectionContract.Kind) {
383 				case CollectionKind.GenericDictionary:
384 					type = Globals.TypeOfDictionaryGeneric.MakeGenericType (itemType.GetGenericArguments ());
385 					constructor = type.GetConstructor (BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
386 					break;
387 				case CollectionKind.Dictionary:
388 					type = Globals.TypeOfHashtable;
389 					constructor = XmlFormatGeneratorStatics.HashtableCtor;
390 					break;
391 				case CollectionKind.Collection:
392 				case CollectionKind.GenericCollection:
393 				case CollectionKind.Enumerable:
394 				case CollectionKind.GenericEnumerable:
395 				case CollectionKind.List:
396 				case CollectionKind.GenericList:
397 					type = itemType.MakeArrayType ();
398 					isArray = true;
399 					break;
400 				}
401 			}
402 			string itemName = collectionContract.ItemName;
403 			string itemNs = collectionContract.StableName.Namespace;
404 
405 			if (!isArray) {
406 				if (type.IsValueType)
407 					// FIXME: this is not what the original code does.
408 					objectLocal = FormatterServices.GetUninitializedObject (type);
409 				else {
410 					objectLocal = constructor.Invoke (new object [0]);
411 					context.AddNewObject (objectLocal);
412 				}
413 			}
414 
415 			int size = context.GetArraySize ();
416 
417 			string objectId = context.GetObjectId ();
418 
419 			bool canReadPrimitiveArray = false, readResult = false;
420 			if (isArray && TryReadPrimitiveArray (type, itemType, size, out readResult))
421 				canReadPrimitiveArray = true;
422 
423 			if (!readResult) {
424 				if (size == -1) {
425 
426 					object growingCollection = null;
427 					if (isArray)
428 						growingCollection = Array.CreateInstance (itemType, 32);
429 
430 					int i = 0;
431 					// FIXME: I cannot find i++ part, but without that it won't work as expected.
432 					for (; i < int.MaxValue; i++) {
433 						if (IsStartElement (this.itemName, this.itemNamespace)) {
434 							context.IncrementItemCount (1);
435 							object value = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
436 							if (isArray) {
437 								MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod (itemType);
438 								growingCollection = ensureArraySizeMethod.Invoke (null, new object [] {growingCollection, i});
439 								((Array) growingCollection).SetValue (value, i);
440 							} else {
441 								StoreCollectionValue (objectLocal, itemType, value, collectionContract);
442 							}
443 						}
444 						else if (IsEndElement ())
445 							break;
446 						else
447 							HandleUnexpectedItemInCollection (ref i);
448 					}
449 
450 					if (isArray) {
451 						MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod (itemType);
452 						objectLocal = trimArraySizeMethod.Invoke (null, new object [] {growingCollection, i});
453 						context.AddNewObjectWithId (objectId, objectLocal);
454 					}
455 				} else {
456 					context.IncrementItemCount (size);
457 					if (isArray) {
458 						objectLocal = Array.CreateInstance (itemType, size);
459 						context.AddNewObject (objectLocal);
460 					}
461 					// FIXME: I cannot find j++ part, but without that it won't work as expected.
462 					for (int j = 0; j < size; j++) {
463 						if (IsStartElement (this.itemName, this.itemNamespace)) {
464 							var itemValue = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
465 							if (isArray)
466 								((Array) objectLocal).SetValue (itemValue, j);
467 							else
468 								StoreCollectionValue (objectLocal, itemType, itemValue, collectionContract);
469 						}
470 						else
471 							HandleUnexpectedItemInCollection (ref j);
472 					}
473 					context.CheckEndOfArray (xmlReader, size, this.itemName, this.itemNamespace);
474 				}
475 			}
476 			if (canReadPrimitiveArray)
477 				context.AddNewObjectWithId (objectId, objectLocal);
478 		}
479 
ReadGetOnlyCollection(CollectionDataContract collectionContract)480 		void ReadGetOnlyCollection (CollectionDataContract collectionContract)
481 		{
482 			Type type = collectionContract.UnderlyingType;
483 			Type itemType = collectionContract.ItemType;
484 			bool isArray = (collectionContract.Kind == CollectionKind.Array);
485 			string itemName = collectionContract.ItemName;
486 			string itemNs = collectionContract.StableName.Namespace;
487 
488 			objectLocal = context.GetCollectionMember ();
489 
490 			//check that items are actually going to be deserialized into the collection
491 			if (IsStartElement (this.itemName, this.itemNamespace)) {
492 				if (objectLocal == null)
493 					XmlObjectSerializerReadContext.ThrowNullValueReturnedForGetOnlyCollectionException (type);
494 				else {
495 					int size = 0;
496 					if (isArray)
497 						size = ((Array) objectLocal).Length;
498 					context.AddNewObject (objectLocal);
499 					for (int i = 0; i < int.MaxValue;) {
500 						if (IsStartElement (this.itemName, this.itemNamespace)) {
501 							context.IncrementItemCount (1);
502 							var value = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
503 							if (isArray) {
504 								if (size == i)
505 									XmlObjectSerializerReadContext.ThrowArrayExceededSizeException (size, type);
506 								else
507 									((Array) objectLocal).SetValue (value, i);
508 							} else {
509 								StoreCollectionValue (objectLocal, itemType, value, collectionContract);
510 							}
511 						}
512 						else if (IsEndElement())
513 							break;
514 						else
515 							HandleUnexpectedItemInCollection (ref i);
516 					}
517 					context.CheckEndOfArray (xmlReader, size, this.itemName, this.itemNamespace);
518 				}
519 			}
520 		}
521 
TryReadPrimitiveArray(Type type, Type itemType, int size, out bool readResult)522 		bool TryReadPrimitiveArray (Type type, Type itemType, int size, out bool readResult)
523 		{
524 			readResult = false;
525 			PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract (itemType);
526 			if (primitiveContract == null)
527 				return false;
528 
529 			string readArrayMethod = null;
530 			switch (Type.GetTypeCode (itemType))
531 			{
532 			case TypeCode.Boolean:
533 				readArrayMethod = "TryReadBooleanArray";
534 			break;
535 			case TypeCode.DateTime:
536 				readArrayMethod = "TryReadDateTimeArray";
537 			break;
538 			case TypeCode.Decimal:
539 				readArrayMethod = "TryReadDecimalArray";
540 			break;
541 			case TypeCode.Int32:
542 				readArrayMethod = "TryReadInt32Array";
543 			break;
544 			case TypeCode.Int64:
545 				readArrayMethod = "TryReadInt64Array";
546 			break;
547 			case TypeCode.Single:
548 				readArrayMethod = "TryReadSingleArray";
549 			break;
550 			case TypeCode.Double:
551 				readArrayMethod = "TryReadDoubleArray";
552 				break;
553 			default:
554 				break;
555 			}
556 			if (readArrayMethod != null) {
557 				var mi = typeof (XmlReaderDelegator).GetMethod (readArrayMethod, Globals.ScanAllMembers);
558 				var args = new object [] {context, itemName, itemNamespace, size, objectLocal};
559 				readResult = (bool) mi.Invoke (xmlReader, args);
560 				objectLocal = args.Last ();
561 				return true;
562 			}
563 			return false;
564 		}
565 
ReadCollectionItem(CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs)566 		object ReadCollectionItem (CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs)
567 		{
568 			if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary) {
569 				context.ResetAttributes ();
570 				return CodeInterpreter.ConvertValue (collectionContract.ItemContract.ReadXmlValue (xmlReader, context), Globals.TypeOfObject, itemType);
571 			}
572 			else
573 				return ReadValue (itemType, itemName, itemNs);
574 		}
575 
StoreCollectionValue(object collection, Type valueType, object value, CollectionDataContract collectionContract)576 		void StoreCollectionValue (object collection, Type valueType, object value, CollectionDataContract collectionContract)
577 		{
578 			if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary) {
579 				ClassDataContract keyValuePairContract = DataContract.GetDataContract (valueType) as ClassDataContract;
580 				if (keyValuePairContract == null)
581 					Fx.Assert ("Failed to create contract for KeyValuePair type");
582 				DataMember keyMember = keyValuePairContract.Members [0];
583 				DataMember valueMember = keyValuePairContract.Members [1];
584 				object pkey = CodeInterpreter.GetMember (keyMember.MemberInfo, value);
585 				object pvalue = CodeInterpreter.GetMember (valueMember.MemberInfo, value);
586 
587 				collectionContract.AddMethod.Invoke (collection, new object [] {pkey, pvalue});
588 			}
589 			else
590 				collectionContract.AddMethod.Invoke (collection, new object [] {value});
591 		}
592 
HandleUnexpectedItemInCollection(ref int iterator)593 		void HandleUnexpectedItemInCollection (ref int iterator)
594 		{
595 			if (IsStartElement ()) {
596 				context.SkipUnknownElement (xmlReader);
597 				iterator--;
598 			}
599 			else
600 				throw XmlObjectSerializerReadContext.CreateUnexpectedStateException (XmlNodeType.Element, xmlReader);
601 		}
602 
IsStartElement(XmlDictionaryString name, XmlDictionaryString ns)603 		bool IsStartElement(XmlDictionaryString name, XmlDictionaryString ns)
604 		{
605 			return xmlReader.IsStartElement (name, ns);
606 		}
607 
IsStartElement()608 		bool IsStartElement()
609 		{
610 			return xmlReader.IsStartElement ();
611 		}
612 
IsEndElement()613 		bool IsEndElement ()
614 		{
615 			return xmlReader.NodeType == XmlNodeType.EndElement;
616 		}
617 	}
618 }
619