Merge pull request #136 from spencerhakim/master
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlTypeMapping.cs
1 //
2 // XmlTypeMapping.cs: 
3 //
4 // Author:
5 //   John Donagher (john@webmeta.com)
6 //   Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // (C) 2002 John Donagher
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Xml;
33 using System;
34 using System.Collections;
35 using System.Globalization;
36 using System.Xml.Schema;
37 using System.Reflection;
38
39 namespace System.Xml.Serialization
40 {
41         public class XmlTypeMapping : XmlMapping
42         {
43                 private string xmlType;
44                 private string xmlTypeNamespace;
45                 TypeData type;
46                 XmlTypeMapping baseMap;
47                 bool multiReferenceType = false;
48                 bool isSimpleType;
49                 string documentation;
50                 bool includeInSchema;
51                 bool isNullable = true;
52
53                 ArrayList _derivedTypes = new ArrayList();
54
55                 internal XmlTypeMapping(string elementName, string ns, TypeData typeData, string xmlType, string xmlTypeNamespace)
56                 : base (elementName, ns)
57                 {
58                         this.type = typeData;
59                         this.xmlType = xmlType;
60                         this.xmlTypeNamespace = xmlTypeNamespace;
61                 }
62
63 #if !NET_2_0
64                 public string ElementName
65                 {
66                         get { return _elementName; }
67                 }
68
69                 public string Namespace
70                 {
71                         get { return _namespace; }
72                 }
73 #endif
74
75                 public string TypeFullName
76                 {
77                         get { return type.FullTypeName; }
78                 }
79
80                 public string TypeName
81                 {
82                         get { return type.TypeName; }
83                 }
84
85 #if NET_2_0
86                 public string XsdTypeName
87                 {
88                         get { return XmlType; }
89                 }
90
91                 public string XsdTypeNamespace
92                 {
93                         get { return XmlTypeNamespace; }
94                 }
95 #endif
96
97                 internal TypeData TypeData
98                 {
99                         get { return type; }
100                 }
101
102                 internal string XmlType
103                 {
104                         get { return xmlType; }
105                         set { xmlType = value; }
106                 }
107
108                 internal string XmlTypeNamespace
109                 {
110                         get { return xmlTypeNamespace; }
111                         set { xmlTypeNamespace = value; }
112                 }
113
114                 internal ArrayList DerivedTypes
115                 {
116                         get { return _derivedTypes; }
117                         set { _derivedTypes = value; }
118                 }
119
120                 internal bool MultiReferenceType
121                 {
122                         get { return multiReferenceType; }
123                         set { multiReferenceType = value; }
124                 }
125
126                 internal XmlTypeMapping BaseMap
127                 {
128                         get { return baseMap; }
129                         set { baseMap = value; }
130                 }
131
132                 internal bool IsSimpleType
133                 {
134                         get { return isSimpleType; }
135                         set { isSimpleType = value; }
136                 }
137
138                 internal string Documentation
139                 {
140                         set { documentation = value; }
141                         get { return documentation; }
142                 }
143
144                 internal bool IncludeInSchema
145                 {
146                         get { return includeInSchema; }
147                         set { includeInSchema = value; }
148                 }
149                 
150                 internal bool IsNullable
151                 {
152                         get { return isNullable; }
153                         set { isNullable = value; }
154                 }
155
156                 internal XmlTypeMapping GetRealTypeMap (Type objectType)
157                 {
158                         if (TypeData.SchemaType == SchemaTypes.Enum)
159                                 return this;
160
161                         // Returns the map for a subtype of this map's type
162                         if (TypeData.Type == objectType) return this;
163                         for (int n=0; n<_derivedTypes.Count; n++) {
164                                 XmlTypeMapping map = (XmlTypeMapping) _derivedTypes[n];
165                                 if (map.TypeData.Type == objectType) return map;
166                         }
167                         
168                         return null;
169                 }
170
171                 internal XmlTypeMapping GetRealElementMap (string name, string ens)
172                 {
173                         if (xmlType == name && xmlTypeNamespace == ens) return this;
174                         foreach (XmlTypeMapping map in _derivedTypes)
175                                 if (map.xmlType == name && map.xmlTypeNamespace == ens) return map;
176                         
177                         return null;
178                 }
179                 
180                 internal void UpdateRoot (XmlQualifiedName qname)
181                 {
182                         if (qname != null) {
183                                 this._elementName = qname.Name;
184                                 this._namespace = qname.Namespace;
185                         }
186                 }
187         }
188
189  
190         // Mapping info for XmlSerializable
191         internal class XmlSerializableMapping : XmlTypeMapping
192         {
193                 XmlSchema _schema;
194 #if NET_2_0 && !MOONLIGHT
195                 XmlSchemaComplexType _schemaType;
196                 XmlQualifiedName _schemaTypeName;
197 #endif
198
199                 internal XmlSerializableMapping(XmlRootAttribute root, string elementName, string ns, TypeData typeData, string xmlType, string xmlTypeNamespace)
200                         : base(elementName, ns, typeData, xmlType, xmlTypeNamespace)
201                 {
202 #if NET_2_0 && !MOONLIGHT
203                         XmlSchemaProviderAttribute schemaProvider = (XmlSchemaProviderAttribute) Attribute.GetCustomAttribute (typeData.Type, typeof (XmlSchemaProviderAttribute));
204
205                         if (schemaProvider != null) {
206                                 string method = schemaProvider.MethodName;
207                                 MethodInfo mi = typeData.Type.GetMethod (method, BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
208                                 if (mi == null)
209                                         throw new InvalidOperationException (String.Format ("Type '{0}' must implement public static method '{1}'", typeData.Type, method));
210                                 if (!typeof (XmlQualifiedName).IsAssignableFrom (mi.ReturnType) &&
211                                     // LAMESPEC: it is undocumented. (We don't have to tell users about it in the error message.)
212                                     // Also do not add such a silly compatibility test to assert that it does not raise an error.
213                                     !typeof (XmlSchemaComplexType).IsAssignableFrom (mi.ReturnType))
214                                         throw new InvalidOperationException (String.Format ("Method '{0}' indicated by XmlSchemaProviderAttribute must have its return type as XmlQualifiedName", method));
215                                 XmlSchemaSet xs = new XmlSchemaSet ();
216                                 object retVal = mi.Invoke (null, new object [] { xs });
217                                 _schemaTypeName = XmlQualifiedName.Empty;
218                                 if (retVal == null)
219                                         return;
220
221                                 if (retVal is XmlSchemaComplexType) {
222                                         _schemaType = (XmlSchemaComplexType) retVal;
223                                         if (!_schemaType.QualifiedName.IsEmpty)
224                                                 _schemaTypeName = _schemaType.QualifiedName;
225                                         else
226                                                 _schemaTypeName = new XmlQualifiedName (xmlType, xmlTypeNamespace);
227                                 }
228                                 else if (retVal is XmlQualifiedName) {
229                                         _schemaTypeName = (XmlQualifiedName)retVal;
230                                 }
231                                 else
232                                         throw new InvalidOperationException (
233                                                 String.Format ("Method {0}.{1}() specified by XmlSchemaProviderAttribute has invalid signature: return type must be compatible with System.Xml.XmlQualifiedName.", typeData.Type.Name, method));
234
235                                 // defaultNamespace at XmlReflectionImporter takes precedence for Namespace, but not for XsdTypeNamespace.
236                                 UpdateRoot (new XmlQualifiedName (root != null ? root.ElementName : _schemaTypeName.Name, root != null ? root.Namespace : Namespace ?? _schemaTypeName.Namespace));
237                                 XmlTypeNamespace = _schemaTypeName.Namespace;
238                                 XmlType = _schemaTypeName.Name;
239
240                                 if (!_schemaTypeName.IsEmpty && xs.Count > 0) {
241                                         XmlSchema [] schemas = new XmlSchema [xs.Count];
242                                         xs.CopyTo (schemas, 0);
243                                         _schema = schemas [0];
244                                 }
245
246                                 return;
247                         }
248 #endif
249 #if NET_2_0 && !MOONLIGHT
250                         IXmlSerializable serializable = (IXmlSerializable)Activator.CreateInstance (typeData.Type, true);
251                         try {
252                                 _schema = serializable.GetSchema();
253                         } catch (Exception) {
254                                 // LAMESPEC: .NET has a bad exception catch and swallows it silently.
255                         }
256 #else
257                         IXmlSerializable serializable = (IXmlSerializable)Activator.CreateInstance (typeData.Type);
258                         _schema = serializable.GetSchema();
259 #endif
260 #if !MOONLIGHT
261                         if (_schema != null) 
262                         {
263                                 if (_schema.Id == null || _schema.Id.Length == 0) 
264                                         throw new InvalidOperationException("Schema Id is missing. The schema returned from " + typeData.Type.FullName + ".GetSchema() must have an Id.");
265                         }
266 #endif
267                 }
268
269                 internal XmlSchema Schema
270                 {
271                         get { return _schema; }
272                 }
273
274 #if NET_2_0 && !MOONLIGHT
275                 internal XmlSchemaType SchemaType {
276                         get { return _schemaType; }
277                 }
278
279                 internal XmlQualifiedName SchemaTypeName {
280                         get { return _schemaTypeName; }
281                 }
282 #endif
283         }
284  
285
286         // Mapping info for classes and structs
287
288         internal class ClassMap: ObjectMap
289         {
290                 Hashtable _elements = new Hashtable ();
291                 ArrayList _elementMembers;
292                 Hashtable _attributeMembers;
293                 XmlTypeMapMemberAttribute[] _attributeMembersArray;
294                 XmlTypeMapElementInfo[] _elementsByIndex;
295                 ArrayList _flatLists;
296                 ArrayList _allMembers = new ArrayList ();
297                 ArrayList _membersWithDefault;
298                 ArrayList _listMembers;
299                 XmlTypeMapMemberAnyElement _defaultAnyElement;
300                 XmlTypeMapMemberAnyAttribute _defaultAnyAttribute;
301                 XmlTypeMapMemberNamespaces _namespaceDeclarations;
302                 XmlTypeMapMember _xmlTextCollector;
303                 XmlTypeMapMember _returnMember;
304                 bool _ignoreMemberNamespace;
305                 bool _canBeSimpleType = true;
306                 bool? _isOrderDependentMap;
307
308                 public void AddMember (XmlTypeMapMember member)
309                 {
310                         // If GlobalIndex has not been set, set it now
311                         if (member.GlobalIndex == -1)
312                                 member.GlobalIndex = _allMembers.Count;
313                         
314                         _allMembers.Add (member);
315                         
316                         if (!(member.DefaultValue is System.DBNull) && member.DefaultValue != null) {
317                                 if (_membersWithDefault == null) _membersWithDefault = new ArrayList ();
318                                 _membersWithDefault.Add (member);
319                         }
320                         
321                         if (member.IsReturnValue)
322                                 _returnMember = member;
323                         
324                         if (member is XmlTypeMapMemberAttribute)
325                         {
326                                 XmlTypeMapMemberAttribute atm = (XmlTypeMapMemberAttribute)member;
327                                 if (_attributeMembers == null) _attributeMembers = new Hashtable();
328                                 string key = BuildKey (atm.AttributeName, atm.Namespace, -1);
329                                 if (_attributeMembers.ContainsKey (key))
330                                         throw new InvalidOperationException ("The XML attribute named '" + atm.AttributeName + "' from namespace '" + atm.Namespace + "' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the attribute.");
331                                 member.Index = _attributeMembers.Count;
332                                 _attributeMembers.Add (key, member);
333                                 return;
334                         }
335                         else if (member is XmlTypeMapMemberFlatList)
336                         {
337                                 RegisterFlatList ((XmlTypeMapMemberFlatList)member);
338                         }
339                         else if (member is XmlTypeMapMemberAnyElement)
340                         {
341                                 XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement) member;
342                                 if (mem.IsDefaultAny) _defaultAnyElement = mem;
343                                 if (mem.TypeData.IsListType) RegisterFlatList (mem);
344                         }
345                         else if (member is XmlTypeMapMemberAnyAttribute)
346                         {
347                                 _defaultAnyAttribute = (XmlTypeMapMemberAnyAttribute) member;
348                                 return;
349                         }
350                         else if (member is XmlTypeMapMemberNamespaces)
351                         {
352                                 _namespaceDeclarations = (XmlTypeMapMemberNamespaces) member;
353                                 return;
354                         }
355
356                         if (member is XmlTypeMapMemberElement && ((XmlTypeMapMemberElement)member).IsXmlTextCollector)
357                         {
358                                 if (_xmlTextCollector != null) throw new InvalidOperationException ("XmlTextAttribute can only be applied once in a class");
359                                 _xmlTextCollector = member;
360                         }
361
362                         if (_elementMembers == null) {
363                                 _elementMembers = new ArrayList();
364                                 _elements = new Hashtable();
365                         }
366
367                         member.Index = _elementMembers.Count;
368                         _elementMembers.Add (member);
369
370                         ICollection elemsInfo = ((XmlTypeMapMemberElement)member).ElementInfo;
371                         foreach (XmlTypeMapElementInfo elem in elemsInfo)
372                         {
373                                 string key = BuildKey (elem.ElementName, elem.Namespace, elem.ExplicitOrder);
374                                 if (_elements.ContainsKey (key)) 
375                                         throw new InvalidOperationException ("The XML element named '" + elem.ElementName + "' from namespace '" + elem.Namespace + "' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.");
376                                 _elements.Add (key, elem);
377                         }
378                         
379                         if (member.TypeData.IsListType && member.TypeData.Type != null && !member.TypeData.Type.IsArray) {
380                                 if (_listMembers == null) _listMembers = new ArrayList ();
381                                 _listMembers.Add (member);
382                         }
383                 }
384
385                 void RegisterFlatList (XmlTypeMapMemberExpandable member)
386                 {
387                         if (_flatLists == null) _flatLists = new ArrayList ();
388                         member.FlatArrayIndex = _flatLists.Count;
389                         _flatLists.Add (member);
390                 }
391
392                 public XmlTypeMapMemberAttribute GetAttribute (string name, string ns)
393                 {
394                         if (_attributeMembers == null) return null;
395                         return (XmlTypeMapMemberAttribute)_attributeMembers [BuildKey (name,ns, -1)];
396                 }
397
398                 public XmlTypeMapElementInfo GetElement (string name, string ns, int order)
399                 {
400                         if (_elements == null) return null;
401                         return (XmlTypeMapElementInfo)_elements [BuildKey (name,ns, order)];
402                 }
403                 
404                 public XmlTypeMapElementInfo GetElement (int index)
405                 {
406                         if (_elements == null) return null;
407                         
408                         if (_elementsByIndex == null)
409                         {
410                                 _elementsByIndex = new XmlTypeMapElementInfo [_elementMembers.Count];
411                                 foreach (XmlTypeMapMemberElement mem in _elementMembers)
412                                 {
413                                         if (mem.ElementInfo.Count != 1) 
414                                                 throw new InvalidOperationException ("Read by order only possible for encoded/bare format");
415                                                 
416                                         _elementsByIndex [mem.Index] = (XmlTypeMapElementInfo) mem.ElementInfo [0];
417                                 }
418                         }
419                         if (index >= _elementMembers.Count)
420                                 return null;
421                         return _elementsByIndex [index];
422                 }
423                 
424                 private string BuildKey (string name, string ns, int explicitOrder)
425                 {
426                         if (_ignoreMemberNamespace) return name;
427                         else return name + " / " + ns + (explicitOrder < 0 ? "" : "/" + explicitOrder);
428                 }
429                 
430                 public ICollection AllElementInfos
431                 {
432                         get { return _elements.Values; }
433                 }
434                 
435                 
436                 public bool IgnoreMemberNamespace
437                 {
438                         get { return _ignoreMemberNamespace; }
439                         set { _ignoreMemberNamespace = value; }
440                 }
441
442                 public bool IsOrderDependentMap {
443                         get {
444                                 if (_isOrderDependentMap == null) {
445                                         _isOrderDependentMap = false;
446                                         foreach (XmlTypeMapElementInfo ei in _elements.Values)
447                                                 if (ei.ExplicitOrder >= 0) {
448                                                         _isOrderDependentMap = true;
449                                                         break;
450                                                 }
451                                 }
452                                 return (bool) _isOrderDependentMap;
453                         }
454                 }
455
456                 public XmlTypeMapMember FindMember (string name)
457                 {
458                         for (int n=0; n<_allMembers.Count; n++)
459                                 if (((XmlTypeMapMember)_allMembers[n]).Name == name) return (XmlTypeMapMember)_allMembers[n];
460                         return null;
461                 }
462
463                 public XmlTypeMapMemberAnyElement DefaultAnyElementMember
464                 {
465                         get { return _defaultAnyElement; }
466                 }
467
468                 public XmlTypeMapMemberAnyAttribute DefaultAnyAttributeMember
469                 {
470                         get { return _defaultAnyAttribute; }
471                 }
472
473                 public XmlTypeMapMemberNamespaces NamespaceDeclarations
474                 {
475                         get { return _namespaceDeclarations; }
476                 }
477
478                 public ICollection AttributeMembers
479                 {
480                         get 
481                         {
482                                 if (_attributeMembers == null) return null;
483                                 if (_attributeMembersArray != null) return _attributeMembersArray;
484                                 
485                                 _attributeMembersArray = new XmlTypeMapMemberAttribute[_attributeMembers.Count];
486                                 foreach (XmlTypeMapMemberAttribute mem in _attributeMembers.Values)
487                                         _attributeMembersArray [mem.Index] = mem;
488                                 return _attributeMembersArray;
489                         }
490                 }
491
492                 public ICollection ElementMembers
493                 {
494                         get { return _elementMembers; }
495                 }
496
497                 public ArrayList AllMembers
498                 {
499                         get { return _allMembers; }
500                 }
501
502                 public ArrayList FlatLists
503                 {
504                         get { return _flatLists; }
505                 }
506                 
507                 public ArrayList MembersWithDefault
508                 {
509                         get { return _membersWithDefault; }
510                 }
511                 
512                 public ArrayList ListMembers
513                 {
514                         get { return _listMembers; }
515                 }
516
517                 public XmlTypeMapMember XmlTextCollector
518                 {
519                         get { return _xmlTextCollector; }
520                 }
521                 
522                 public XmlTypeMapMember ReturnMember
523                 {
524                         get { return _returnMember; }
525                 }
526
527                 public XmlQualifiedName SimpleContentBaseType
528                 {
529                         get
530                         {
531                                 if (!_canBeSimpleType || _elementMembers == null || _elementMembers.Count != 1) return null;
532                                 XmlTypeMapMemberElement member = (XmlTypeMapMemberElement) _elementMembers[0];
533                                 if (member.ElementInfo.Count != 1) return null;
534                                 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo[0];
535                                 if (!einfo.IsTextElement) return null;
536                                 if (member.TypeData.SchemaType == SchemaTypes.Primitive || member.TypeData.SchemaType == SchemaTypes.Enum)
537                                         return new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
538                                 return null;
539                         }
540                 }
541                 
542                 public void SetCanBeSimpleType (bool can)
543                 {
544                         _canBeSimpleType = can;
545                 }
546
547                 public bool HasSimpleContent
548                 {
549                         get
550                         {
551                                 return SimpleContentBaseType != null;
552                         }
553                 }
554
555         }
556
557         // Mapping info for arrays and lists
558
559         internal class ListMap: ObjectMap
560         {
561                 XmlTypeMapElementInfoList _itemInfo;
562                 bool _gotNestedMapping;
563                 XmlTypeMapping _nestedArrayMapping;
564                 string _choiceMember;
565
566                 public bool IsMultiArray
567                 {
568                         get
569                         {
570                                 return (NestedArrayMapping != null);
571                         }
572                 }
573
574                 public string ChoiceMember
575                 {
576                         get { return _choiceMember; }
577                         set { _choiceMember = value; }
578                 }
579
580                 public XmlTypeMapping NestedArrayMapping
581                 {
582                         get
583                         {
584                                 if (_gotNestedMapping) return _nestedArrayMapping;
585                                 _gotNestedMapping = true;
586
587                                 _nestedArrayMapping = ((XmlTypeMapElementInfo)_itemInfo[0]).MappedType;
588
589                                 if (_nestedArrayMapping == null) return null;
590                                 
591                                 if (_nestedArrayMapping.TypeData.SchemaType != SchemaTypes.Array) {
592                                         _nestedArrayMapping = null; return null;
593                                 }
594
595                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)
596                                         if (elem.MappedType != _nestedArrayMapping) {
597                                                 _nestedArrayMapping = null;
598                                                 return null;
599                                         }
600
601                                 return _nestedArrayMapping;
602                         }
603                 }
604
605                 public XmlTypeMapElementInfoList ItemInfo
606                 {
607
608                         get { return _itemInfo; }
609                         set { _itemInfo = value; }
610                 }
611
612                 public XmlTypeMapElementInfo FindElement (object ob, int index, object memberValue)
613                 {
614                         if (_itemInfo.Count == 1) 
615                                 return (XmlTypeMapElementInfo) _itemInfo[0];
616                         else if (_choiceMember != null && index != -1)
617                         {
618                                 Array values = (Array) XmlTypeMapMember.GetValue (ob, _choiceMember);
619                                 if (values == null || index >= values.Length)
620                                         throw new InvalidOperationException ("Invalid or missing choice enum value in member '" + _choiceMember + "'.");
621                                 object val = values.GetValue (index);
622                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)
623                                         if (elem.ChoiceValue != null && elem.ChoiceValue.Equals (val))
624                                                 return elem;
625                         }
626                         else
627                         {
628                                 if (memberValue == null) return null;
629                                 Type type = memberValue.GetType();
630                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)
631                                         if (elem.TypeData.Type == type) return elem;
632                         }
633                         return null;
634                 }       
635
636                 public XmlTypeMapElementInfo FindElement (string elementName, string ns)
637                 {
638                         foreach (XmlTypeMapElementInfo elem in _itemInfo)
639                                 if (elem.ElementName == elementName && elem.Namespace == ns) return elem;
640                         return null;
641                 }
642                 
643                 public XmlTypeMapElementInfo FindTextElement ()
644                 {
645                         foreach (XmlTypeMapElementInfo elem in _itemInfo)
646                                 if (elem.IsTextElement) return elem;
647                         return null;
648                 }
649                 
650                 public string GetSchemaArrayName ()
651                 {
652                         XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) _itemInfo[0];
653                         if (einfo.MappedType != null) return TypeTranslator.GetArrayName (einfo.MappedType.XmlType);
654                         else return TypeTranslator.GetArrayName (einfo.TypeData.XmlType);
655                 }
656
657                 public void GetArrayType (int itemCount, out string localName, out string ns)
658                 {
659                         string arrayDim;
660                         if (itemCount != -1) arrayDim = "[" + itemCount + "]";
661                         else arrayDim = "[]";
662
663                         XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) _itemInfo[0];
664                         if (info.TypeData.SchemaType == SchemaTypes.Array)
665                         {
666                                 string nm;
667                                 ((ListMap)info.MappedType.ObjectMap).GetArrayType (-1, out nm, out ns);
668                                 localName = nm + arrayDim;
669                         }
670                         else 
671                         {
672                                 if (info.MappedType != null)
673                                 {
674                                         localName = info.MappedType.XmlType + arrayDim;
675                                         ns = info.MappedType.Namespace;
676                                 }
677                                 else 
678                                 {
679                                         localName = info.TypeData.XmlType + arrayDim;
680                                         ns = info.DataTypeNamespace;
681                                 }
682                         }
683                 }
684
685                 public override bool Equals (object other)
686                 {
687                         ListMap lmap = other as ListMap;
688                         if (lmap == null) return false;
689
690                         if (_itemInfo.Count != lmap._itemInfo.Count) return false;
691                         for (int n=0; n<_itemInfo.Count; n++)
692                                 if (!_itemInfo[n].Equals (lmap._itemInfo[n])) return false;
693                         return true;
694                 }
695
696                 public override int GetHashCode ()
697                 {
698                         return base.GetHashCode ();
699                 }
700         }
701
702         internal class EnumMap: ObjectMap
703         {
704                 readonly EnumMapMember[] _members;
705                 readonly bool _isFlags;
706                 readonly string[] _enumNames = null;
707                 readonly string[] _xmlNames = null;
708                 readonly long[] _values = null;
709
710                 public class EnumMapMember
711                 {
712                         readonly string _xmlName;
713                         readonly string _enumName;
714                         readonly long _value;
715                         string _documentation;
716
717                         public EnumMapMember (string xmlName, string enumName)
718                                 : this (xmlName, enumName, 0)
719                         {
720                         }
721
722                         public EnumMapMember (string xmlName, string enumName, long value)
723                         {
724                                 _xmlName = xmlName;
725                                 _enumName = enumName;
726                                 _value = value;
727                         }
728
729                         public string XmlName
730                         {
731                                 get { return _xmlName; }
732                         }
733
734                         public string EnumName
735                         {
736                                 get { return _enumName; }
737                         }
738
739                         public long Value
740                         {
741                                 get { return _value; }
742                         }
743
744                         public string Documentation
745                         {
746                                 get { return _documentation; }
747                                 set { _documentation = value; }
748                         }
749                 }
750
751                 public EnumMap (EnumMapMember[] members, bool isFlags)
752                 {
753                         _members = members;
754                         _isFlags = isFlags;
755
756                         _enumNames = new string[_members.Length];
757                         _xmlNames = new string[_members.Length];
758                         _values = new long[_members.Length];
759
760                         for (int i = 0; i < _members.Length; i++) {
761                                 EnumMapMember mem = _members[i];
762                                 _enumNames[i] = mem.EnumName;
763                                 _xmlNames[i] = mem.XmlName;
764                                 _values[i] = mem.Value;
765                         }
766                 }
767                 
768                 public bool IsFlags
769                 {
770                         get { return _isFlags; }
771                 }
772
773                 public EnumMapMember[] Members
774                 {
775                         get { return _members; }
776                 }
777
778                 public string[] EnumNames
779                 {
780                         get {
781                                 return _enumNames;
782                         }
783                 }
784
785                 public string[] XmlNames
786                 {
787                         get {
788                                 return _xmlNames;
789                         }
790                 }
791
792                 public long[] Values
793                 {
794                         get {
795                                 return _values;
796                         }
797                 }
798
799                 public string GetXmlName (string typeName, object enumValue)
800                 {
801                         if (enumValue is string) {
802                                 throw new InvalidCastException ();
803                         }
804
805                         long value = 0;
806
807                         try {
808                                 value = ((IConvertible) enumValue).ToInt64 (CultureInfo.CurrentCulture);
809                         } catch (FormatException) {
810                                 throw new InvalidCastException ();
811                         }
812
813                         for (int i = 0; i < Values.Length; i++) {
814                                 if (Values[i] == value)
815                                         return XmlNames[i];
816                         }
817
818                         if (IsFlags && value == 0)
819                                 return string.Empty;
820
821                         string xmlName = string.Empty;
822                         if (IsFlags) {
823 #if NET_2_0
824                                 xmlName = XmlCustomFormatter.FromEnum (value, XmlNames, Values, typeName);
825 #else
826                                 xmlName = XmlCustomFormatter.FromEnum (value, XmlNames, Values);
827 #endif
828                         }
829
830                         if (xmlName.Length == 0) {
831 #if NET_2_0
832                                 throw new InvalidOperationException (string.Format(CultureInfo.CurrentCulture,
833                                         "'{0}' is not a valid value for {1}.", value, typeName));
834 #else
835                                 return value.ToString (CultureInfo.InvariantCulture);
836 #endif
837                         }
838                         return xmlName;
839                 }
840
841                 public string GetEnumName (string typeName, string xmlName)
842                 {
843                         if (_isFlags) {
844                                 xmlName = xmlName.Trim ();
845                                 if (xmlName.Length == 0)
846                                         return "0";
847
848                                 System.Text.StringBuilder sb = new System.Text.StringBuilder ();
849                                 string[] enumNames = xmlName.Split (null);
850                                 foreach (string name in enumNames) {
851                                         if (name == string.Empty) continue;
852                                         string foundEnumValue = null;
853                                         for (int i = 0; i < XmlNames.Length; i++)
854                                                 if (XmlNames[i] == name) {
855                                                         foundEnumValue = EnumNames[i];
856                                                         break;
857                                                 }
858
859                                         if (foundEnumValue != null) {
860                                                 if (sb.Length > 0)
861                                                         sb.Append (',');
862                                                 sb.Append (foundEnumValue);
863                                         } else {
864                                                 throw new InvalidOperationException (string.Format (CultureInfo.CurrentCulture,
865                                                         "'{0}' is not a valid value for {1}.", name, typeName));
866                                         }
867                                 }
868                                 return sb.ToString ();
869                         }
870
871                         foreach (EnumMapMember mem in _members)
872                                 if (mem.XmlName == xmlName) return mem.EnumName;
873                                 
874                         return null;
875                 }
876         }
877 }