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