* MapCodeGenerator.cs: Added helper method for generating an attribute
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializationReaderInterpreter.cs
1 //
2 // XmlSerializationReaderInterpreter.cs: 
3 //
4 // Author:
5 //   Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // (C) 2002, 2003 Ximian, Inc.  http://www.ximian.com
8 //
9
10 using System;
11 using System.Reflection;
12 using System.Collections;
13
14 namespace System.Xml.Serialization
15 {
16         internal class XmlSerializationReaderInterpreter: XmlSerializationReader
17         {
18                 XmlMapping _typeMap;
19                 SerializationFormat _format;
20
21                 public XmlSerializationReaderInterpreter(XmlMapping typeMap)
22                 {
23                         _typeMap = typeMap;
24                         _format = typeMap.Format;
25                 }
26
27                 protected override void InitCallbacks ()
28                 {
29                         ArrayList maps = _typeMap.RelatedMaps;
30                         if (maps != null)
31                         {
32                                 foreach (XmlTypeMapping map in maps)  
33                                 {
34                                         if (map.TypeData.SchemaType == SchemaTypes.Class || map.TypeData.SchemaType == SchemaTypes.Enum)
35                                         {
36                                                 ReaderCallbackInfo info = new ReaderCallbackInfo (this, map);
37                                                 AddReadCallback (map.XmlType, map.Namespace, map.TypeData.Type, new XmlSerializationReadCallback (info.ReadObject));
38                                         }
39                                 }
40                         }
41                 }
42
43                 protected override void InitIDs ()
44                 {
45                 }
46
47                 protected XmlTypeMapping GetTypeMap (Type type)
48                 {
49                         ArrayList maps = _typeMap.RelatedMaps;
50                         if (maps != null)
51                         {
52                                 foreach (XmlTypeMapping map in maps)
53                                         if (map.TypeData.Type == type) return map;
54                         }
55                         throw new InvalidOperationException ("Type " + type + " not mapped");
56                 }
57
58                 public object ReadObject ()
59                 {
60                         Reader.MoveToContent();
61                         if (_typeMap is XmlTypeMapping)
62                         {
63                                 if (_format == SerializationFormat.Literal)
64                                         return ReadRoot ((XmlTypeMapping)_typeMap);
65                                 else
66                                         return ReadEncodedObject ((XmlTypeMapping)_typeMap);
67                         }
68                         else
69                                 return ReadMessage ((XmlMembersMapping)_typeMap);
70                 }
71
72                 object ReadEncodedObject (XmlTypeMapping typeMap)
73                 {
74                         object ob = null;
75                         Reader.MoveToContent();
76                         if (Reader.NodeType == System.Xml.XmlNodeType.Element) 
77                         {
78                                 if (Reader.LocalName == typeMap.ElementName && Reader.NamespaceURI == typeMap.Namespace)
79                                         ob = ReadReferencedElement();
80                                 else 
81                                         throw CreateUnknownNodeException();
82                         }
83                         else 
84                                 UnknownNode(null);
85
86                         ReadReferencedElements();
87                         return ob;
88                 }
89
90                 protected virtual object ReadMessage (XmlMembersMapping typeMap)
91                 {
92                         object[] parameters = new object[typeMap.Count];
93
94                         if (typeMap.HasWrapperElement)
95                         {
96                                 if (_format == SerializationFormat.Encoded)
97                                 {
98                                         while (Reader.NodeType == System.Xml.XmlNodeType.Element)
99                                         {
100                                                 string root = Reader.GetAttribute ("root", XmlSerializer.EncodingNamespace);
101                                                 if (root == null || System.Xml.XmlConvert.ToBoolean(root)) break;
102                                                 ReadReferencedElement ();
103                                                 Reader.MoveToContent ();
104                                         }
105                                 }
106                                 
107                                 while (Reader.NodeType != System.Xml.XmlNodeType.EndElement) 
108                                 {
109                                         if (Reader.IsStartElement(typeMap.ElementName, typeMap.Namespace) 
110                                             || _format == SerializationFormat.Encoded)  
111                                         {
112                                                 if (Reader.IsEmptyElement) { Reader.Skip(); Reader.MoveToContent(); continue; }
113                                                 Reader.ReadStartElement();
114                                                 ReadMembers ((ClassMap)typeMap.ObjectMap, parameters, true, false);
115                                                 ReadEndElement();
116                                                 break;
117                                         }
118                                         else 
119                                                 UnknownNode(null);
120
121                                         Reader.MoveToContent();
122                                 }
123                         }
124                         else
125                                 ReadMembers ((ClassMap)typeMap.ObjectMap, parameters, true, _format == SerializationFormat.Encoded);
126
127                         if (_format == SerializationFormat.Encoded)
128                                 ReadReferencedElements();
129
130                         return parameters;
131                 }
132
133                 object ReadRoot (XmlTypeMapping rootMap)
134                 {
135                         if (rootMap.TypeData.SchemaType == SchemaTypes.XmlNode)
136                         {
137                                 return ReadXmlNodeElement (rootMap, true);
138                         }
139                         else
140                         {
141                                 if (Reader.LocalName != rootMap.ElementName || Reader.NamespaceURI != rootMap.Namespace)
142                                         throw CreateUnknownNodeException();
143                                 
144                                 return ReadObject (rootMap, true, true);
145                         }
146                 }               
147
148
149                 protected virtual object ReadObject (XmlTypeMapping typeMap, bool isNullable, bool checkType)
150                 {
151                         switch (typeMap.TypeData.SchemaType)
152                         {
153                                 case SchemaTypes.Class: return ReadClassInstance (typeMap, isNullable, checkType);
154                                 case SchemaTypes.Array: return ReadListElement (typeMap, isNullable, null, true);
155                                 case SchemaTypes.XmlNode: return ReadXmlNodeElement (typeMap, isNullable);
156                                 case SchemaTypes.Primitive: return ReadPrimitiveElement (typeMap, isNullable);
157                                 case SchemaTypes.Enum: return ReadEnumElement (typeMap, isNullable);
158                                 case SchemaTypes.XmlSerializable: return ReadXmlSerializableElement (typeMap, isNullable);
159                                 default: throw new Exception ("Unsupported map type");
160                         }
161                 }
162
163                 protected virtual object ReadClassInstance (XmlTypeMapping typeMap, bool isNullable, bool checkType)
164                 {
165                         if (isNullable && ReadNull()) return null;
166
167                         if (checkType) 
168                         {
169                 System.Xml.XmlQualifiedName t = GetXsiType();
170                                 if (t != null) 
171                                 {
172                                         XmlTypeMapping realMap = typeMap.GetRealElementMap (t.Name, t.Namespace);
173                                         if (realMap == null) {
174                                                 if (typeMap.TypeData.Type == typeof(object))
175                                                         return ReadTypedPrimitive (t);
176                                                 else
177                                                         throw CreateUnknownTypeException((System.Xml.XmlQualifiedName)t);
178                                         }
179                                         if (realMap != typeMap)
180                                                 return ReadObject (realMap, false, false);
181                                 }
182             }
183
184                         object ob = Activator.CreateInstance (typeMap.TypeData.Type);
185
186                         Reader.MoveToElement();
187                         bool isEmpty = Reader.IsEmptyElement;
188                         ReadClassInstanceMembers (typeMap, ob);
189
190                         if (isEmpty) Reader.Skip();
191                         else ReadEndElement();
192
193                         return ob;
194                 }
195
196                 protected virtual void ReadClassInstanceMembers (XmlTypeMapping typeMap, object ob)
197                 {
198                         ReadMembers ((ClassMap) typeMap.ObjectMap, ob, false, false);
199                 }
200
201                 void ReadMembers (ClassMap map, object ob, bool isValueList, bool readByOrder)
202                 {
203                         // A value list cannot have attributes
204
205                         if (!isValueList)
206                         {
207                                 // Reads attributes
208
209                                 XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
210                                 int anyAttributeIndex = 0;
211                                 object anyAttributeArray = null;
212
213                                 while (Reader.MoveToNextAttribute())
214                                 {
215                                         XmlTypeMapMemberAttribute member = map.GetAttribute (Reader.LocalName, Reader.NamespaceURI);
216
217                                         if (member != null) 
218                                         {
219                                                 SetMemberValue (member, ob, GetValueFromXmlString (Reader.Value, member.TypeData, member.MappedType), isValueList);
220                                         }
221                                         else if (IsXmlnsAttribute(Reader.Name)) 
222                                         {
223                                                 // If the map has NamespaceDeclarations,
224                                                 // then store this xmlns to the given member.
225                                                 // If the instance doesn't exist, then create.
226                                                 if (map.NamespaceDeclarations != null) {
227                                                         XmlSerializerNamespaces nss = this.GetMemberValue (map.NamespaceDeclarations, ob, isValueList) as XmlSerializerNamespaces;
228                                                         if (nss == null) {
229                                                                 nss = new XmlSerializerNamespaces ();
230                                                                 SetMemberValue (map.NamespaceDeclarations, ob, nss, isValueList);
231                                                         }
232                                                         if (Reader.Prefix == "xmlns")
233                                                                 nss.Add (Reader.LocalName, Reader.Value);
234                                                         else
235                                                                 nss.Add ("", Reader.Value);
236                                                 }
237                                         }       
238                                         else if (anyAttrMember != null) 
239                                         {
240                                                 XmlAttribute attr = (XmlAttribute) Document.ReadNode(Reader);
241                                                 ParseWsdlArrayType (attr);
242                                                 AddListValue (anyAttrMember.TypeData, ref anyAttributeArray, anyAttributeIndex++, attr, true);
243                                         }
244                                         else
245                                                 ProcessUnknownAttribute(ob);
246                                 }
247
248                                 if (anyAttrMember != null)
249                                 {
250                                         anyAttributeArray = ShrinkArray ((Array)anyAttributeArray, anyAttributeIndex, anyAttrMember.TypeData.Type.GetElementType(), true);
251                                         SetMemberValue (anyAttrMember, ob, anyAttributeArray, isValueList);
252                                 }
253
254                                 Reader.MoveToElement();
255                                 if (Reader.IsEmptyElement) 
256                                         return;
257
258                                 Reader.ReadStartElement();
259                         }
260
261                         // Reads elements
262
263                         bool[] readFlag = new bool[(map.ElementMembers != null) ? map.ElementMembers.Count : 0];
264
265                         Reader.MoveToContent();
266
267                         int[] indexes = null;
268                         object[] flatLists = null;
269                         Fixup fixup = null;
270                         int ind = 0;
271                         int maxInd;
272
273                         if (readByOrder) {
274                                 if (map.ElementMembers != null) maxInd = map.ElementMembers.Count;
275                                 else maxInd = 0;
276                         }
277                         else
278                                 maxInd = int.MaxValue;
279
280                         if (map.FlatLists != null) 
281                         {
282                                 indexes = new int[map.FlatLists.Count];
283                                 flatLists = new object[map.FlatLists.Count];
284                                 foreach (XmlTypeMapMemberExpandable mem in map.FlatLists)
285                                         if (IsReadOnly (mem, ob, isValueList)) flatLists[mem.FlatArrayIndex] = mem.GetValue (ob);
286                         }
287                         
288                         if (_format == SerializationFormat.Encoded && map.ElementMembers != null)
289                         {
290                                 FixupCallbackInfo info = new FixupCallbackInfo (this, map, isValueList);
291                                 fixup = new Fixup(ob, new XmlSerializationFixupCallback(info.FixupMembers), map.ElementMembers.Count);
292                                 AddFixup (fixup);
293                                 if (readByOrder) maxInd = map.ElementMembers.Count;
294                         }
295
296                         while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && (ind < maxInd)) 
297                         {
298                                 if (Reader.NodeType == System.Xml.XmlNodeType.Element) 
299                                 {
300                                         XmlTypeMapElementInfo info = !readByOrder ? map.GetElement (Reader.LocalName, Reader.NamespaceURI) : map.GetElement (ind++);
301                                         if (info != null && !readFlag[info.Member.Index] )
302                                         {
303                                                 if (info.Member.GetType() == typeof (XmlTypeMapMemberList))
304                                                 {
305                                                         if (_format == SerializationFormat.Encoded && info.MultiReferenceType)
306                                                         {
307                                                                 object list = ReadReferencingElement (out fixup.Ids[info.Member.Index]);
308                                                                 if (fixup.Ids[info.Member.Index] == null)       // Already read
309                                                                 {
310                                                                         if (IsReadOnly (info.Member, ob, isValueList)) throw CreateReadOnlyCollectionException (info.TypeData.FullTypeName);
311                                                                         else SetMemberValue (info.Member, ob, list, isValueList);
312                                                                 }
313                                                                 else if (!info.MappedType.TypeData.Type.IsArray)
314                                                                 {
315                                                                         if (IsReadOnly (info.Member, ob, isValueList)) 
316                                                                                 list = GetMemberValue (info.Member, ob, isValueList);
317                                                                         else { 
318                                                                                 list = CreateList (info.MappedType.TypeData.Type);
319                                                                                 SetMemberValue (info.Member, ob, list, isValueList);
320                                                                         }
321                                                                         AddFixup (new CollectionFixup (list, new XmlSerializationCollectionFixupCallback (FillList), fixup.Ids[info.Member.Index]));
322                                                                         fixup.Ids[info.Member.Index] = null;    // The member already has the value, no further fix needed.
323                                                                 }
324                                                         }
325                                                         else
326                                                         {
327                                                                 if (IsReadOnly (info.Member, ob, isValueList)) ReadListElement (info.MappedType, info.IsNullable, GetMemberValue (info.Member, ob, isValueList), false);
328                                                                 else SetMemberValue (info.Member, ob, ReadListElement (info.MappedType, info.IsNullable, null, true), isValueList);
329                                                         }
330                                                         readFlag[info.Member.Index] = true;
331                                                 }
332                                                 else if (info.Member.GetType() == typeof (XmlTypeMapMemberFlatList))
333                                                 {
334                                                         XmlTypeMapMemberFlatList mem = (XmlTypeMapMemberFlatList)info.Member;
335                                                         AddListValue (mem.TypeData, ref flatLists[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex]++, ReadObjectElement (info), !IsReadOnly (info.Member, ob, isValueList));
336                                                 }
337                                                 else if (info.Member.GetType() == typeof (XmlTypeMapMemberAnyElement))
338                                                 {
339                                                         XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement)info.Member;
340                                                         if (mem.TypeData.IsListType) AddListValue (mem.TypeData, ref flatLists[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex]++, ReadXmlNode (false), true);
341                                                         else SetMemberValue (mem, ob, ReadXmlNode (false), isValueList);
342                                                 }
343                                                 else if (info.Member.GetType() == typeof(XmlTypeMapMemberElement))
344                                                 {
345                                                         object val;
346                                                         readFlag[info.Member.Index] = true;
347                                                         if (_format == SerializationFormat.Encoded && info.MultiReferenceType) 
348                                                         {
349                                                                 val = ReadReferencingElement (out fixup.Ids[info.Member.Index]);
350                                                                 if (fixup.Ids[info.Member.Index] == null)       // already read
351                                                                         SetMemberValue (info.Member, ob, val, isValueList);
352                                                         }
353                                                         else 
354                                                                 SetMemberValue (info.Member, ob, ReadObjectElement (info), isValueList);
355                                                 }
356                                                 else
357                                                         throw new InvalidOperationException ("Unknown member type");
358                                         }
359                                         else if (map.DefaultAnyElementMember != null)
360                                         {
361                                                 XmlTypeMapMemberAnyElement mem = map.DefaultAnyElementMember;
362                                                 if (mem.TypeData.IsListType) AddListValue (mem.TypeData, ref flatLists[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex]++, ReadXmlNode (false), true);
363                                                 else SetMemberValue (mem, ob, ReadXmlNode (false), isValueList);
364                                         }
365                                         else 
366                                                 ProcessUnknownElement(ob);
367                                 }
368                                 else if (Reader.NodeType == System.Xml.XmlNodeType.Text && map.XmlTextCollector != null)
369                                 {
370                                         if (map.XmlTextCollector is XmlTypeMapMemberExpandable)
371                                         {
372                                                 XmlTypeMapMemberExpandable mem = (XmlTypeMapMemberExpandable)map.XmlTextCollector;
373                                                 XmlTypeMapMemberFlatList flatl = mem as XmlTypeMapMemberFlatList;
374                                                 Type itype = (flatl == null) ? mem.TypeData.ListItemType : flatl.ListMap.FindTextElement().TypeData.Type;
375
376                                                 object val = (itype == typeof (string)) ? (object) Reader.ReadString() : (object) ReadXmlNode (false);
377                                                 AddListValue (mem.TypeData, ref flatLists[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex]++, val, true);
378                                         }
379                                         else
380                                         {
381                                                 XmlTypeMapMemberElement mem = (XmlTypeMapMemberElement) map.XmlTextCollector;
382                                                 XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) mem.ElementInfo [0];
383                                                 if (info.TypeData.Type == typeof (string))
384                                                         SetMemberValue (mem, ob, ReadString ((string) GetMemberValue (mem, ob, isValueList)), isValueList);
385                                                 else
386                                                         SetMemberValue (mem, ob, GetValueFromXmlString (Reader.ReadString(), info.TypeData, info.MappedType), isValueList);
387                                         }
388                                 }
389                                 else 
390                                         UnknownNode(ob);
391
392                                 Reader.MoveToContent();
393                         }
394
395                         if (flatLists != null)
396                         {
397                                 foreach (XmlTypeMapMemberExpandable mem in map.FlatLists)
398                                 {
399                                         Object list = flatLists[mem.FlatArrayIndex];
400                                         if (mem.TypeData.Type.IsArray)
401                                                 list = ShrinkArray ((Array)list, indexes[mem.FlatArrayIndex], mem.TypeData.Type.GetElementType(), true);
402                                         if (!IsReadOnly (mem, ob, isValueList))
403                                                 SetMemberValue (mem, ob, list, isValueList);
404                                 }
405                         }               
406                 }
407
408                 internal void FixupMembers (ClassMap map, object obfixup, bool isValueList)
409                 {
410                         Fixup fixup = (Fixup)obfixup;
411                         ICollection members = map.ElementMembers;
412                         string[] ids = fixup.Ids;
413                         foreach (XmlTypeMapMember member in members)
414                         {
415                                 if (ids[member.Index] != null)
416                                         SetMemberValue (member, fixup.Source, GetTarget(ids[member.Index]), isValueList);
417                         }
418                 }
419                 
420                 protected virtual void ProcessUnknownAttribute (object target)
421                 {
422                         UnknownNode (target);
423                 }
424                 
425                 protected virtual void ProcessUnknownElement (object target)
426                 {
427                         UnknownNode (target);
428                 }
429
430                 bool IsReadOnly (XmlTypeMapMember member, object ob, bool isValueList)
431                 {
432                         if (isValueList) return false;
433                         else return member.IsReadOnly (ob.GetType());
434                 }
435
436                 void SetMemberValue (XmlTypeMapMember member, object ob, object value, bool isValueList)
437                 {
438                         if (isValueList) ((object[])ob)[member.Index] = value;
439                         else {
440                                 member.SetValue (ob, value);
441                                 if (member.IsOptionalValueType)
442                                         member.SetValueSpecified (ob, true); 
443                         }
444                 }
445
446                 object GetMemberValue (XmlTypeMapMember member, object ob, bool isValueList)
447                 {
448                         if (isValueList) return ((object[])ob)[member.Index];
449                         else return member.GetValue (ob);
450                 }
451
452                 object ReadObjectElement (XmlTypeMapElementInfo elem)
453                 {
454                         switch (elem.TypeData.SchemaType)
455                         {
456                                 case SchemaTypes.XmlNode:
457                                         return ReadXmlNode (true);
458
459                                 case SchemaTypes.Primitive:
460                                 case SchemaTypes.Enum:
461                                         return ReadPrimitiveValue (elem);
462
463                                 case SchemaTypes.Array:
464                                         return ReadListElement (elem.MappedType, elem.IsNullable, null, true);
465
466                                 case SchemaTypes.Class:
467                                         return ReadObject (elem.MappedType, elem.IsNullable, true);
468
469                                 case SchemaTypes.XmlSerializable:
470                                         object ob = Activator.CreateInstance (elem.TypeData.Type);
471                                         return ReadSerializable ((IXmlSerializable)ob);
472
473                                 default:
474                                         throw new NotSupportedException ("Invalid value type");
475                         }
476                 }
477
478                 object ReadPrimitiveValue (XmlTypeMapElementInfo elem)
479                 {
480                         if (elem.TypeData.Type == typeof (XmlQualifiedName)) {
481                                 if (elem.IsNullable) return ReadNullableQualifiedName ();
482                                 else return ReadElementQualifiedName ();
483                         }
484                         else if (elem.IsNullable)
485                                 return GetValueFromXmlString (ReadNullableString (), elem.TypeData, elem.MappedType);
486                         else
487                                 return GetValueFromXmlString (Reader.ReadElementString (), elem.TypeData, elem.MappedType);
488                 }
489                 
490                 object GetValueFromXmlString (string value, TypeData typeData, XmlTypeMapping typeMap)
491                 {
492                         if (typeData.SchemaType == SchemaTypes.Array)
493                                 return ReadListString (typeMap, value);
494                         else if (typeData.SchemaType == SchemaTypes.Enum)
495                                 return GetEnumValue (typeMap, value);
496                         else if (typeData.Type == typeof (XmlQualifiedName))
497                                 return ToXmlQualifiedName (value);
498                         else 
499                                 return XmlCustomFormatter.FromXmlString (typeData, value);
500                 }
501
502                 object ReadListElement (XmlTypeMapping typeMap, bool isNullable, object list, bool canCreateInstance)
503                 {
504                         Type listType = typeMap.TypeData.Type;
505                         ListMap listMap = (ListMap)typeMap.ObjectMap;
506
507                         if (ReadNull()) return null;
508
509                         if (list == null) {
510                                 if (canCreateInstance) list = CreateList (listType);
511                                 else throw CreateReadOnlyCollectionException (typeMap.TypeFullName);
512                         }
513
514                         if (Reader.IsEmptyElement) {
515                                 Reader.Skip();
516                                 if (listType.IsArray)
517                                         list = ShrinkArray ((Array)list, 0, listType.GetElementType(), isNullable);
518                                 return list;
519                         }
520
521                         int index = 0;
522                         Reader.ReadStartElement();
523                         Reader.MoveToContent();
524
525                         while (Reader.NodeType != System.Xml.XmlNodeType.EndElement) 
526                         {
527                                 if (Reader.NodeType == System.Xml.XmlNodeType.Element) 
528                                 {
529                                         XmlTypeMapElementInfo elemInfo = listMap.FindElement (Reader.LocalName, Reader.NamespaceURI);
530                                         if (elemInfo != null)
531                                                 AddListValue (typeMap.TypeData, ref list, index++, ReadObjectElement (elemInfo), false);
532                                         else
533                                                 UnknownNode(null);
534                                 }
535                                 else 
536                                         UnknownNode(null);
537
538                                 Reader.MoveToContent();
539                         }
540                         ReadEndElement();
541
542                         if (listType.IsArray)
543                                 list = ShrinkArray ((Array)list, index, listType.GetElementType(), isNullable);
544
545                         return list;
546                 }
547
548                 object ReadListString (XmlTypeMapping typeMap, string values)
549                 {
550                         Type listType = typeMap.TypeData.Type;
551                         ListMap listMap = (ListMap)typeMap.ObjectMap;
552                         values = values.Trim ();
553
554                         if (values == string.Empty)
555                         {
556                                 return Array.CreateInstance (listType.GetElementType(), 0);
557                         }
558
559                         string[] valueArray = values.Split (' ');
560                         Array list = Array.CreateInstance (listType.GetElementType(), valueArray.Length);
561
562                         XmlTypeMapElementInfo info = (XmlTypeMapElementInfo)listMap.ItemInfo[0];
563
564                         for (int index = 0; index < valueArray.Length; index++)
565                                 list.SetValue (GetValueFromXmlString (valueArray[index], info.TypeData, info.MappedType), index);
566
567                         return list;
568                 }
569
570                 void AddListValue (TypeData listType, ref object list, int index, object value, bool canCreateInstance)
571                 {
572                         Type type = listType.Type;
573                         if (type.IsArray)
574                         {
575                                 list = EnsureArrayIndex ((Array)list, index, type.GetElementType());
576                                 ((Array)list).SetValue (value, index);
577                         }
578                         else    // Must be IEnumerable
579                         {
580                                 if (list == null) {
581                                         if (canCreateInstance) list = Activator.CreateInstance (type);
582                                         else throw CreateReadOnlyCollectionException (type.FullName);
583                                 }
584
585                                 MethodInfo mi = type.GetMethod ("Add", new Type[] {listType.ListItemType} );
586                                 mi.Invoke (list, new object[] { value });
587                         }
588                 }
589
590                 object CreateList (Type listType)
591                 {
592                         if (listType.IsArray)
593                                 return EnsureArrayIndex (null, 0, listType.GetElementType());
594                         else
595                                 return Activator.CreateInstance (listType);
596                 }
597
598                 void FillList (object list, object items)
599                 {
600                         CopyEnumerableList (items, list);
601                 }
602
603                 void CopyEnumerableList (object source, object dest)
604                 {
605                         if (dest == null) throw CreateReadOnlyCollectionException (source.GetType().FullName);
606
607                         object[] param = new object[1];
608                         MethodInfo mi = dest.GetType().GetMethod ("Add");
609                         foreach (object ob in (IEnumerable)source)
610                         {
611                                 param[0] = ob;
612                                 mi.Invoke (dest, param);
613                         }
614                 }
615
616                 int GetListCount (TypeData listType, object ob)
617                 {
618                         if (listType.Type.IsArray)
619                                 return ((Array)ob).Length;
620                         else
621                                 return (int) listType.Type.GetProperty ("Count").GetValue(ob,null);
622                 }
623
624                 object ReadXmlNodeElement (XmlTypeMapping typeMap, bool isNullable)
625                 {
626                         return ReadXmlNode (false);
627                 }
628
629                 object ReadPrimitiveElement (XmlTypeMapping typeMap, bool isNullable)
630                 {
631                         XmlQualifiedName t = GetXsiType();
632                         if (t == null) t = new XmlQualifiedName (typeMap.XmlType, typeMap.Namespace);
633                         return ReadTypedPrimitive (t);
634                 }
635
636                 object ReadEnumElement (XmlTypeMapping typeMap, bool isNullable)
637                 {
638                         Reader.ReadStartElement ();
639                         object o = GetEnumValue (typeMap, Reader.ReadString());
640                         Reader.ReadEndElement ();
641                         return o;
642                 }
643
644                 object GetEnumValue (XmlTypeMapping typeMap, string val)
645                 {
646                         EnumMap map = (EnumMap) typeMap.ObjectMap;
647                         string ev = map.GetEnumName (val);
648                         if (ev == null) throw CreateUnknownConstantException (val, typeMap.TypeData.Type);
649                         return Enum.Parse (typeMap.TypeData.Type, ev);
650                 }
651
652                 object ReadXmlSerializableElement (XmlTypeMapping typeMap, bool isNullable)
653                 {
654                         Reader.MoveToContent ();
655                         if (Reader.NodeType == XmlNodeType.Element)
656                         {
657                                 if (Reader.LocalName == typeMap.ElementName && Reader.NamespaceURI == typeMap.Namespace)
658                                 {
659                                         object ob = Activator.CreateInstance (typeMap.TypeData.Type);
660                                         return ReadSerializable ((IXmlSerializable)ob);
661                                 }
662                                 else
663                                         throw CreateUnknownNodeException ();
664                         }
665                         else
666                         {
667                                 UnknownNode (null);
668                                 return null;
669                         }
670                 }
671
672                 class FixupCallbackInfo
673                 {
674                         XmlSerializationReaderInterpreter _sri;
675                         ClassMap _map;
676                         bool _isValueList;
677
678                         public FixupCallbackInfo (XmlSerializationReaderInterpreter sri, ClassMap map, bool isValueList)
679                         {
680                                 _sri = sri;
681                                 _map = map;
682                                 _isValueList = isValueList;
683                         }
684
685                         public void FixupMembers (object fixup)
686                         {
687                                 _sri.FixupMembers (_map, fixup, _isValueList);
688                         }
689                 }
690
691                 class ReaderCallbackInfo
692                 {
693                         XmlSerializationReaderInterpreter _sri;
694                         XmlTypeMapping _typeMap;
695
696                         public ReaderCallbackInfo (XmlSerializationReaderInterpreter sri, XmlTypeMapping typeMap)
697                         {
698                                 _sri = sri;
699                                 _typeMap = typeMap;
700                         }
701
702                         internal object ReadObject ()
703                         {
704                                 return _sri.ReadObject (_typeMap, true, true);
705                         }
706                 }
707         }
708 }