Merge branch 'cecil-light'
[mono.git] / mcs / class / System.Xaml / System.Windows.Markup / ValueSerializer.cs
1 //
2 // Copyright (C) 2010 Novell Inc. http://novell.com
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 using System;
24 using System.Collections;
25 using System.Collections.Generic;
26 using System.ComponentModel;
27 using System.Globalization;
28 using System.Linq;
29 using System.Reflection;
30 using System.Xaml;
31 using System.Xaml.Schema;
32
33 namespace System.Windows.Markup
34 {
35         [System.Runtime.CompilerServices.TypeForwardedFrom (Consts.AssemblyWindowsBase)]
36         public abstract class ValueSerializer
37         {
38                 public static ValueSerializer GetSerializerFor (PropertyDescriptor descriptor)
39                 {
40                         return GetSerializerFor (descriptor, null);
41                 }
42
43                 public static ValueSerializer GetSerializerFor (Type type)
44                 {
45                         return GetSerializerFor (type, null);
46                 }
47
48                 // untested
49                 public static ValueSerializer GetSerializerFor (PropertyDescriptor descriptor, IValueSerializerContext context)
50                 {
51                         if (descriptor == null)
52                                 throw new ArgumentNullException ("descriptor");
53                         if (context != null)
54                                 return context.GetValueSerializerFor (descriptor);
55
56                         var tc = descriptor.Converter;
57                         if (tc != null && tc.GetType () != typeof (TypeConverter))
58                                 return new TypeConverterValueSerializer (tc);
59                         return null;
60                 }
61
62                 public static ValueSerializer GetSerializerFor (Type type, IValueSerializerContext context)
63                 {
64                         if (type == null)
65                                 throw new ArgumentNullException ("type");
66                         if (context != null)
67                                 return context.GetValueSerializerFor (type);
68
69                         // Standard MarkupExtensions are serialized without ValueSerializer.
70                         if (typeof (MarkupExtension).IsAssignableFrom (type) && XamlLanguage.AllTypes.Any (x => x.UnderlyingType == type))
71                                 return null;
72
73                         // DateTime is documented as special.
74                         if (type == typeof (DateTime))
75                                 return new DateTimeValueSerializer ();
76                         // String too.
77                         if (type == typeof (string))
78                                 return new StringValueSerializer ();
79
80                         // FIXME: this is hack. The complete condition is fully documented at http://msdn.microsoft.com/en-us/library/ms590363.aspx
81                         if (type.GetCustomAttribute<TypeConverterAttribute> (true) != null) {
82                                 var tc = TypeDescriptor.GetConverter (type);
83                                 if (tc != null && tc.GetType () != typeof (TypeConverter))
84                                         return new TypeConverterValueSerializer (tc);
85                         }
86
87                         // Undocumented, but System.Type seems also special. While other MarkupExtension returned types are not handled specially, this method returns a valid instance for System.Type. Note that it doesn't for TypeExtension.
88                         if (type == typeof (Type))
89                                 // Since System.Type does not have a valid TypeConverter, I use TypeExtensionConverter (may sound funny considering the above notes!) for this serializer.
90                                 return new TypeValueSerializer ();
91
92                         // Undocumented, but several primitive types get a valid serializer while it does not have TypeConverter.
93                         switch (Type.GetTypeCode (type)) {
94                         case TypeCode.Object:
95                         case TypeCode.DBNull:
96                                 break;
97                         default:
98                                 return new TypeConverterValueSerializer (TypeDescriptor.GetConverter (type));
99                         }
100
101                         // There is still exceptional type! TimeSpan. Why aren't they documented?
102                         if (type == typeof (TimeSpan))
103                                 return new TypeConverterValueSerializer (TypeDescriptor.GetConverter (type));
104
105                         return null;
106                 }
107
108                 // instance members
109
110                 public virtual bool CanConvertFromString (string value, IValueSerializerContext context)
111                 {
112                         return false;
113                 }
114
115                 public virtual bool CanConvertToString (object value, IValueSerializerContext context)
116                 {
117                         return false;
118                 }
119
120                 public virtual object ConvertFromString (string value, IValueSerializerContext context)
121                 {
122                         throw GetConvertFromException (value);
123                 }
124
125                 public virtual string ConvertToString (object value,     IValueSerializerContext context)
126                 {
127                         throw GetConvertToException (value, typeof (string));
128                 }
129
130                 protected Exception GetConvertFromException (object value)
131                 {
132                         return new NotSupportedException (String.Format ("Conversion from string '{0}' is not supported", value));
133                 }
134
135                 protected Exception GetConvertToException (object value, Type destinationType)
136                 {
137                         return new NotSupportedException (String.Format ("Conversion from '{0}' to {1} is not supported", value != null ? value.GetType ().Name : "(null)", destinationType));
138                 }
139
140                 public virtual IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
141                 {
142                         yield break;
143                 }
144         }
145
146         #region Internal implementations.
147
148         internal class StringValueSerializer : ValueSerializer
149         {
150                 public override bool CanConvertFromString (string value, IValueSerializerContext context)
151                 {
152                         return true;
153                 }
154
155                 public override bool CanConvertToString (object value, IValueSerializerContext context)
156                 {
157                         return true;
158                 }
159
160                 public override object ConvertFromString (string value, IValueSerializerContext context)
161                 {
162                         return value;
163                 }
164
165                 public override string ConvertToString (object value,     IValueSerializerContext context)
166                 {
167                         return (string) value;
168                 }
169
170                 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
171                 {
172                         throw new NotImplementedException ();
173                 }
174         }
175
176         internal class TypeValueSerializer : ValueSerializer
177         {
178                 TypeExtensionConverter txc = new TypeExtensionConverter ();
179
180                 public override bool CanConvertFromString (string value, IValueSerializerContext context)
181                 {
182                         return true;
183                 }
184
185                 public override bool CanConvertToString (object value, IValueSerializerContext context)
186                 {
187                         return true;
188                 }
189
190                 public override object ConvertFromString (string value, IValueSerializerContext context)
191                 {
192                         if (context == null)
193                                 return base.ConvertFromString (value, context);
194                         var nsr = (IXamlNamespaceResolver) context.GetService (typeof (IXamlNamespaceResolver));
195                         var scp = (IXamlSchemaContextProvider) context.GetService (typeof (IXamlSchemaContextProvider));
196                         return scp.SchemaContext.GetXamlType (XamlTypeName.Parse (value, nsr)).UnderlyingType;
197                 }
198
199                 public override string ConvertToString (object value,     IValueSerializerContext context)
200                 {
201                         return (string) txc.ConvertTo (context, CultureInfo.InvariantCulture, value, typeof (string));
202                 }
203
204                 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
205                 {
206                         throw new NotImplementedException ();
207                 }
208         }
209
210         internal class TypeConverterValueSerializer : ValueSerializer
211         {
212                 public TypeConverterValueSerializer (TypeConverter typeConverter)
213                 {
214                         c = typeConverter;
215                 }
216
217                 TypeConverter c;
218
219                 public override bool CanConvertFromString (string value, IValueSerializerContext context)
220                 {
221                         return c.CanConvertFrom (context, typeof (string));
222                 }
223
224                 public override bool CanConvertToString (object value, IValueSerializerContext context)
225                 {
226                         return c.CanConvertTo (context, typeof (string));
227                 }
228
229                 public override object ConvertFromString (string value, IValueSerializerContext context)
230                 {
231                         return c.ConvertFromInvariantString (context, value);
232                 }
233
234                 public override string ConvertToString (object value,     IValueSerializerContext context)
235                 {
236                         return value == null ? String.Empty : c.ConvertToInvariantString (context, value);
237                 }
238
239                 public override IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
240                 {
241                         throw new NotImplementedException ();
242                 }
243         }
244         
245         #endregion
246 }