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