2006-04-28 Marek Safar <marek.safar@seznam.cz>
[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                         _allMembers.Add (member);\r
224                         \r
225                         if (!(member.DefaultValue is System.DBNull) && member.DefaultValue != null) {\r
226                                 if (_membersWithDefault == null) _membersWithDefault = new ArrayList ();\r
227                                 _membersWithDefault.Add (member);\r
228                         }\r
229                         \r
230                         if (member.IsReturnValue)\r
231                                 _returnMember = member;\r
232                         \r
233                         if (member is XmlTypeMapMemberAttribute)\r
234                         {\r
235                                 XmlTypeMapMemberAttribute atm = (XmlTypeMapMemberAttribute)member;\r
236                                 if (_attributeMembers == null) _attributeMembers = new Hashtable();\r
237                                 string key = BuildKey (atm.AttributeName, atm.Namespace);\r
238                                 if (_attributeMembers.ContainsKey (key))\r
239                                         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
240                                 member.Index = _attributeMembers.Count;\r
241                                 _attributeMembers.Add (key, member);\r
242                                 return;\r
243                         }\r
244                         else if (member is XmlTypeMapMemberFlatList)\r
245                         {\r
246                                 RegisterFlatList ((XmlTypeMapMemberFlatList)member);\r
247                         }\r
248                         else if (member is XmlTypeMapMemberAnyElement)\r
249                         {\r
250                                 XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement) member;\r
251                                 if (mem.IsDefaultAny) _defaultAnyElement = mem;\r
252                                 if (mem.TypeData.IsListType) RegisterFlatList (mem);\r
253                         }\r
254                         else if (member is XmlTypeMapMemberAnyAttribute)\r
255                         {\r
256                                 _defaultAnyAttribute = (XmlTypeMapMemberAnyAttribute) member;\r
257                                 return;\r
258                         }\r
259                         else if (member is XmlTypeMapMemberNamespaces)\r
260                         {\r
261                                 _namespaceDeclarations = (XmlTypeMapMemberNamespaces) member;\r
262                                 return;\r
263                         }\r
264 \r
265                         if (member is XmlTypeMapMemberElement && ((XmlTypeMapMemberElement)member).IsXmlTextCollector)\r
266                         {\r
267                                 if (_xmlTextCollector != null) throw new InvalidOperationException ("XmlTextAttribute can only be applied once in a class");\r
268                                 _xmlTextCollector = member;\r
269                         }\r
270 \r
271                         if (_elementMembers == null) {\r
272                                 _elementMembers = new ArrayList();\r
273                                 _elements = new Hashtable();\r
274                         }\r
275 \r
276                         member.Index = _elementMembers.Count;\r
277                         _elementMembers.Add (member);\r
278 \r
279                         ICollection elemsInfo = ((XmlTypeMapMemberElement)member).ElementInfo;\r
280                         foreach (XmlTypeMapElementInfo elem in elemsInfo)\r
281                         {\r
282                                 string key = BuildKey (elem.ElementName, elem.Namespace);\r
283                                 if (_elements.ContainsKey (key)) \r
284                                         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
285                                 _elements.Add (key, elem);\r
286                         }\r
287                         \r
288                         if (member.TypeData.IsListType && member.TypeData.Type != null && !member.TypeData.Type.IsArray) {\r
289                                 if (_listMembers == null) _listMembers = new ArrayList ();\r
290                                 _listMembers.Add (member);\r
291                         }\r
292                 }\r
293 \r
294                 void RegisterFlatList (XmlTypeMapMemberExpandable member)\r
295                 {\r
296                         if (_flatLists == null) _flatLists = new ArrayList ();\r
297                         member.FlatArrayIndex = _flatLists.Count;\r
298                         _flatLists.Add (member);\r
299                 }\r
300 \r
301                 public XmlTypeMapMemberAttribute GetAttribute (string name, string ns)\r
302                 {\r
303                         if (_attributeMembers == null) return null;\r
304                         return (XmlTypeMapMemberAttribute)_attributeMembers [BuildKey(name,ns)];\r
305                 }\r
306 \r
307                 public XmlTypeMapElementInfo GetElement (string name, string ns)\r
308                 {\r
309                         if (_elements == null) return null;\r
310                         return (XmlTypeMapElementInfo)_elements [BuildKey(name,ns)];\r
311                 }\r
312                 \r
313                 public XmlTypeMapElementInfo GetElement (int index)\r
314                 {\r
315                         if (_elements == null) return null;\r
316                         \r
317                         if (_elementsByIndex == null)\r
318                         {\r
319                                 _elementsByIndex = new XmlTypeMapElementInfo [_elementMembers.Count];\r
320                                 foreach (XmlTypeMapMemberElement mem in _elementMembers)\r
321                                 {\r
322                                         if (mem.ElementInfo.Count != 1) \r
323                                                 throw new InvalidOperationException ("Read by order only possible for encoded/bare format");\r
324                                                 \r
325                                         _elementsByIndex [mem.Index] = (XmlTypeMapElementInfo) mem.ElementInfo [0];\r
326                                 }\r
327                         }\r
328                         \r
329                         return _elementsByIndex [index];\r
330                 }\r
331                 \r
332                 private string BuildKey (string name, string ns)\r
333                 {\r
334                         if (_ignoreMemberNamespace) return name;\r
335                         else return name + " / " + ns;\r
336                 }\r
337                 \r
338                 public ICollection AllElementInfos\r
339                 {\r
340                         get { return _elements.Values; }\r
341                 }\r
342                 \r
343                 \r
344                 public bool IgnoreMemberNamespace\r
345                 {\r
346                         get { return _ignoreMemberNamespace; }\r
347                         set { _ignoreMemberNamespace = value; }\r
348                 }\r
349 \r
350                 public XmlTypeMapMember FindMember (string name)\r
351                 {\r
352                         for (int n=0; n<_allMembers.Count; n++)\r
353                                 if (((XmlTypeMapMember)_allMembers[n]).Name == name) return (XmlTypeMapMember)_allMembers[n];\r
354                         return null;\r
355                 }\r
356 \r
357                 public XmlTypeMapMemberAnyElement DefaultAnyElementMember\r
358                 {\r
359                         get { return _defaultAnyElement; }\r
360                 }\r
361 \r
362                 public XmlTypeMapMemberAnyAttribute DefaultAnyAttributeMember\r
363                 {\r
364                         get { return _defaultAnyAttribute; }\r
365                 }\r
366 \r
367                 public XmlTypeMapMemberNamespaces NamespaceDeclarations\r
368                 {\r
369                         get { return _namespaceDeclarations; }\r
370                 }\r
371 \r
372                 public ICollection AttributeMembers\r
373                 {\r
374                         get \r
375                         {\r
376                                 if (_attributeMembers == null) return null;\r
377                                 if (_attributeMembersArray != null) return _attributeMembersArray;\r
378                                 \r
379                                 _attributeMembersArray = new XmlTypeMapMemberAttribute[_attributeMembers.Count];\r
380                                 foreach (XmlTypeMapMemberAttribute mem in _attributeMembers.Values)\r
381                                         _attributeMembersArray [mem.Index] = mem;\r
382                                 return _attributeMembersArray;\r
383                         }\r
384                 }\r
385 \r
386                 public ICollection ElementMembers\r
387                 {\r
388                         get { return _elementMembers; }\r
389                 }\r
390 \r
391                 public ArrayList AllMembers\r
392                 {\r
393                         get { return _allMembers; }\r
394                 }\r
395 \r
396                 public ArrayList FlatLists\r
397                 {\r
398                         get { return _flatLists; }\r
399                 }\r
400                 \r
401                 public ArrayList MembersWithDefault\r
402                 {\r
403                         get { return _membersWithDefault; }\r
404                 }\r
405                 \r
406                 public ArrayList ListMembers\r
407                 {\r
408                         get { return _listMembers; }\r
409                 }\r
410 \r
411                 public XmlTypeMapMember XmlTextCollector\r
412                 {\r
413                         get { return _xmlTextCollector; }\r
414                 }\r
415                 \r
416                 public XmlTypeMapMember ReturnMember\r
417                 {\r
418                         get { return _returnMember; }\r
419                 }\r
420 \r
421                 public XmlQualifiedName SimpleContentBaseType\r
422                 {\r
423                         get\r
424                         {\r
425                                 if (!_canBeSimpleType || _elementMembers == null || _elementMembers.Count != 1) return null;\r
426                                 XmlTypeMapMemberElement member = (XmlTypeMapMemberElement) _elementMembers[0];\r
427                                 if (member.ElementInfo.Count != 1) return null;\r
428                                 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo[0];\r
429                                 if (!einfo.IsTextElement) return null;\r
430                                 if (member.TypeData.SchemaType == SchemaTypes.Primitive || member.TypeData.SchemaType == SchemaTypes.Enum)\r
431                                         return new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);\r
432                                 return null;\r
433                         }\r
434                 }\r
435                 \r
436                 public void SetCanBeSimpleType (bool can)\r
437                 {\r
438                         _canBeSimpleType = can;\r
439                 }\r
440 \r
441                 public bool HasSimpleContent\r
442                 {\r
443                         get\r
444                         {\r
445                                 return SimpleContentBaseType != null;\r
446                         }\r
447                 }\r
448 \r
449         }\r
450 \r
451         // Mapping info for arrays and lists\r
452 \r
453         internal class ListMap: ObjectMap\r
454         {\r
455                 XmlTypeMapElementInfoList _itemInfo;\r
456                 bool _gotNestedMapping;\r
457                 XmlTypeMapping _nestedArrayMapping;\r
458                 string _choiceMember;\r
459 \r
460                 public bool IsMultiArray\r
461                 {\r
462                         get\r
463                         {\r
464                                 return (NestedArrayMapping != null);\r
465                         }\r
466                 }\r
467 \r
468                 public string ChoiceMember\r
469                 {\r
470                         get { return _choiceMember; }\r
471                         set { _choiceMember = value; }\r
472                 }\r
473 \r
474                 public XmlTypeMapping NestedArrayMapping\r
475                 {\r
476                         get\r
477                         {\r
478                                 if (_gotNestedMapping) return _nestedArrayMapping;\r
479                                 _gotNestedMapping = true;\r
480 \r
481                                 _nestedArrayMapping = ((XmlTypeMapElementInfo)_itemInfo[0]).MappedType;\r
482 \r
483                                 if (_nestedArrayMapping == null) return null;\r
484                                 \r
485                                 if (_nestedArrayMapping.TypeData.SchemaType != SchemaTypes.Array) {\r
486                                         _nestedArrayMapping = null; return null;\r
487                                 }\r
488 \r
489                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)\r
490                                         if (elem.MappedType != _nestedArrayMapping) {\r
491                                                 _nestedArrayMapping = null;\r
492                                                 return null;\r
493                                         }\r
494 \r
495                                 return _nestedArrayMapping;\r
496                         }\r
497                 }\r
498 \r
499                 public XmlTypeMapElementInfoList ItemInfo\r
500                 {\r
501 \r
502                         get { return _itemInfo; }\r
503                         set { _itemInfo = value; }\r
504                 }\r
505 \r
506                 public XmlTypeMapElementInfo FindElement (object ob, int index, object memberValue)\r
507                 {\r
508                         if (_itemInfo.Count == 1) \r
509                                 return (XmlTypeMapElementInfo) _itemInfo[0];\r
510                         else if (_choiceMember != null && index != -1)\r
511                         {\r
512                                 Array values = (Array) XmlTypeMapMember.GetValue (ob, _choiceMember);\r
513                                 if (values == null || index >= values.Length)\r
514                                         throw new InvalidOperationException ("Invalid or missing choice enum value in member '" + _choiceMember + "'.");\r
515                                 object val = values.GetValue (index);\r
516                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)\r
517                                         if (elem.ChoiceValue != null && elem.ChoiceValue.Equals (val))\r
518                                                 return elem;\r
519                         }\r
520                         else\r
521                         {\r
522                                 if (memberValue == null) return null;\r
523                                 Type type = memberValue.GetType();\r
524                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)\r
525                                         if (elem.TypeData.Type == type) return elem;\r
526                         }\r
527                         return null;\r
528                 }       \r
529 \r
530                 public XmlTypeMapElementInfo FindElement (string elementName, string ns)\r
531                 {\r
532                         foreach (XmlTypeMapElementInfo elem in _itemInfo)\r
533                                 if (elem.ElementName == elementName && elem.Namespace == ns) return elem;\r
534                         return null;\r
535                 }\r
536                 \r
537                 public XmlTypeMapElementInfo FindTextElement ()\r
538                 {\r
539                         foreach (XmlTypeMapElementInfo elem in _itemInfo)\r
540                                 if (elem.IsTextElement) return elem;\r
541                         return null;\r
542                 }\r
543                 \r
544                 public string GetSchemaArrayName ()\r
545                 {\r
546                         XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) _itemInfo[0];\r
547                         if (einfo.MappedType != null) return TypeTranslator.GetArrayName (einfo.MappedType.XmlType);\r
548                         else return TypeTranslator.GetArrayName (einfo.TypeData.XmlType);\r
549                 }\r
550 \r
551                 public void GetArrayType (int itemCount, out string localName, out string ns)\r
552                 {\r
553                         string arrayDim;\r
554                         if (itemCount != -1) arrayDim = "[" + itemCount + "]";\r
555                         else arrayDim = "[]";\r
556 \r
557                         XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) _itemInfo[0];\r
558                         if (info.TypeData.SchemaType == SchemaTypes.Array)\r
559                         {\r
560                                 string nm;\r
561                                 ((ListMap)info.MappedType.ObjectMap).GetArrayType (-1, out nm, out ns);\r
562                                 localName = nm + arrayDim;\r
563                         }\r
564                         else \r
565                         {\r
566                                 if (info.MappedType != null)\r
567                                 {\r
568                                         localName = info.MappedType.XmlType + arrayDim;\r
569                                         ns = info.MappedType.Namespace;\r
570                                 }\r
571                                 else \r
572                                 {\r
573                                         localName = info.TypeData.XmlType + arrayDim;\r
574                                         ns = info.DataTypeNamespace;\r
575                                 }\r
576                         }\r
577                 }\r
578 \r
579                 public override bool Equals (object other)\r
580                 {\r
581                         ListMap lmap = other as ListMap;\r
582                         if (lmap == null) return false;\r
583 \r
584                         if (_itemInfo.Count != lmap._itemInfo.Count) return false;\r
585                         for (int n=0; n<_itemInfo.Count; n++)\r
586                                 if (!_itemInfo[n].Equals (lmap._itemInfo[n])) return false;\r
587                         return true;\r
588                 }\r
589 \r
590                 public override int GetHashCode ()\r
591                 {\r
592                         return base.GetHashCode ();\r
593                 }\r
594         }\r
595 \r
596         internal class EnumMap: ObjectMap\r
597         {\r
598                 readonly EnumMapMember[] _members;\r
599                 readonly bool _isFlags;\r
600                 readonly string[] _enumNames = null;\r
601                 readonly string[] _xmlNames = null;\r
602                 readonly long[] _values = null;\r
603 \r
604                 public class EnumMapMember\r
605                 {\r
606                         readonly string _xmlName;\r
607                         readonly string _enumName;\r
608                         readonly long _value;\r
609                         string _documentation;\r
610 \r
611                         public EnumMapMember (string xmlName, string enumName)\r
612                                 : this (xmlName, enumName, 0)\r
613                         {\r
614                         }\r
615 \r
616                         public EnumMapMember (string xmlName, string enumName, long value)\r
617                         {\r
618                                 _xmlName = xmlName;\r
619                                 _enumName = enumName;\r
620                                 _value = value;\r
621                         }\r
622 \r
623                         public string XmlName\r
624                         {\r
625                                 get { return _xmlName; }\r
626                         }\r
627 \r
628                         public string EnumName\r
629                         {\r
630                                 get { return _enumName; }\r
631                         }\r
632 \r
633                         public long Value\r
634                         {\r
635                                 get { return _value; }\r
636                         }\r
637 \r
638                         public string Documentation\r
639                         {\r
640                                 get { return _documentation; }\r
641                                 set { _documentation = value; }\r
642                         }\r
643                 }\r
644 \r
645                 public EnumMap (EnumMapMember[] members, bool isFlags)\r
646                 {\r
647                         _members = members;\r
648                         _isFlags = isFlags;\r
649 \r
650                         _enumNames = new string[_members.Length];\r
651                         _xmlNames = new string[_members.Length];\r
652                         _values = new long[_members.Length];\r
653 \r
654                         for (int i = 0; i < _members.Length; i++) {\r
655                                 EnumMapMember mem = _members[i];\r
656                                 _enumNames[i] = mem.EnumName;\r
657                                 _xmlNames[i] = mem.XmlName;\r
658                                 _values[i] = mem.Value;\r
659                         }\r
660                 }\r
661                 \r
662                 public bool IsFlags\r
663                 {\r
664                         get { return _isFlags; }\r
665                 }\r
666 \r
667                 public EnumMapMember[] Members\r
668                 {\r
669                         get { return _members; }\r
670                 }\r
671 \r
672                 public string[] EnumNames\r
673                 {\r
674                         get {\r
675                                 return _enumNames;\r
676                         }\r
677                 }\r
678 \r
679                 public string[] XmlNames\r
680                 {\r
681                         get {\r
682                                 return _xmlNames;\r
683                         }\r
684                 }\r
685 \r
686                 public long[] Values\r
687                 {\r
688                         get {\r
689                                 return _values;\r
690                         }\r
691                 }\r
692 \r
693                 public string GetXmlName (string typeName, object enumValue)\r
694                 {\r
695                         if (enumValue is string) {\r
696                                 throw new InvalidCastException ();\r
697                         }\r
698 \r
699                         long value = 0;\r
700 \r
701                         try {\r
702                                 value = ((IConvertible) enumValue).ToInt64 (CultureInfo.CurrentCulture);\r
703                         } catch (FormatException) {\r
704                                 throw new InvalidCastException ();\r
705                         }\r
706 \r
707                         for (int i = 0; i < Values.Length; i++) {\r
708                                 if (Values[i] == value)\r
709                                         return XmlNames[i];\r
710                         }\r
711 \r
712                         if (IsFlags && value == 0)\r
713                                 return string.Empty;\r
714 \r
715                         string xmlName = string.Empty;\r
716                         if (IsFlags) {\r
717 #if NET_2_0\r
718                                 xmlName = XmlCustomFormatter.FromEnum (value, XmlNames, Values, typeName);\r
719 #else\r
720                                 xmlName = XmlCustomFormatter.FromEnum (value, XmlNames, Values);\r
721 #endif\r
722                         }\r
723 \r
724                         if (xmlName.Length == 0) {\r
725 #if NET_2_0\r
726                                 throw new InvalidOperationException (string.Format(CultureInfo.CurrentCulture,\r
727                                         "'{0}' is not a valid value for {1}.", value, typeName));\r
728 #else\r
729                                 return value.ToString (CultureInfo.InvariantCulture);\r
730 #endif\r
731                         }\r
732                         return xmlName;\r
733                 }\r
734 \r
735                 public string GetEnumName (string typeName, string xmlName)\r
736                 {\r
737                         if (_isFlags) {\r
738                                 xmlName = xmlName.Trim ();\r
739                                 if (xmlName.Length == 0)\r
740                                         return "0";\r
741 \r
742                                 System.Text.StringBuilder sb = new System.Text.StringBuilder ();\r
743                                 string[] enumNames = xmlName.Split (null);\r
744                                 foreach (string name in enumNames) {\r
745                                         if (name == string.Empty) continue;\r
746                                         string foundEnumValue = null;\r
747                                         for (int i = 0; i < XmlNames.Length; i++)\r
748                                                 if (XmlNames[i] == name) {\r
749                                                         foundEnumValue = EnumNames[i];\r
750                                                         break;\r
751                                                 }\r
752 \r
753                                         if (foundEnumValue != null) {\r
754                                                 if (sb.Length > 0)\r
755                                                         sb.Append (',');\r
756                                                 sb.Append (foundEnumValue);\r
757                                         } else {\r
758                                                 throw new InvalidOperationException (string.Format (CultureInfo.CurrentCulture,\r
759                                                         "'{0}' is not a valid value for {1}.", name, typeName));\r
760                                         }\r
761                                 }\r
762                                 return sb.ToString ();\r
763                         }\r
764 \r
765                         foreach (EnumMapMember mem in _members)\r
766                                 if (mem.XmlName == xmlName) return mem.EnumName;\r
767                                 \r
768                         return null;\r
769                 }\r
770         }\r
771 }\r