8f465936f6d95c61c2ae1362714a5082cdd90cf5
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / TypeConversionExtensions.cs
1 //
2 // TypeConversionExtensions.cs
3 //
4 // Author:
5 //       Stephane Delcroix <stephane@mi8.be>
6 //
7 // Copyright (c) 2013 Mobile Inception
8 // Copyright (c) 2014 Xamarin, Inc.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27
28 using System;
29 using System.Collections.Generic;
30 using System.Globalization;
31 using System.Linq;
32 using System.Reflection;
33 // using Tizen.NUI.Binding.Internals;
34 using Tizen.NUI.Xaml.Internals;
35 using Tizen.NUI.Binding;
36
37 namespace Tizen.NUI.Xaml
38 {
39     internal static class TypeConversionExtensions
40     {
41         internal static object ConvertTo(this object value, Type toType, Func<ParameterInfo> pinfoRetriever,
42             IServiceProvider serviceProvider)
43         {
44             Func<TypeConverter> getConverter = () =>
45             {
46                 ParameterInfo pInfo;
47                 if (pinfoRetriever == null || (pInfo = pinfoRetriever()) == null)
48                     return null;
49
50                 var converterTypeName = pInfo.CustomAttributes.GetTypeConverterTypeName();
51                 if (converterTypeName == null)
52                     return null;
53                 var convertertype = Type.GetType(converterTypeName);
54                 return (TypeConverter)Activator.CreateInstance(convertertype);
55             };
56
57             return ConvertTo(value, toType, getConverter, serviceProvider);
58         }
59
60         internal static object ConvertTo(this object value, Type toType, Func<MemberInfo> minfoRetriever,
61             IServiceProvider serviceProvider)
62         {
63             Func<object> getConverter = () =>
64             {
65                 MemberInfo memberInfo;
66
67                 var converterTypeName = toType.GetTypeInfo().CustomAttributes.GetTypeConverterTypeName();
68                 if (minfoRetriever != null && (memberInfo = minfoRetriever()) != null)
69                     converterTypeName = memberInfo.CustomAttributes.GetTypeConverterTypeName() ?? converterTypeName;
70                 if (converterTypeName == null)
71                     return null;
72
73                 var convertertype = Type.GetType(converterTypeName);
74                 return Activator.CreateInstance(convertertype);
75             };
76
77             return ConvertTo(value, toType, getConverter, serviceProvider);
78         }
79
80         static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
81         {
82             var converterAttribute =
83                 attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName));
84             if (converterAttribute == null)
85                 return null;
86             if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (string))
87                 return (string)converterAttribute.ConstructorArguments[0].Value;
88             if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (Type))
89                 return ((Type)converterAttribute.ConstructorArguments[0].Value).AssemblyQualifiedName;
90             return null;
91         }
92
93         //Don't change the name or the signature of this, it's used by XamlC
94         public static object ConvertTo(this object value, Type toType, Type convertertype, IServiceProvider serviceProvider)
95         {
96             if (convertertype == null)
97                 return value.ConvertTo(toType, (Func<object>)null, serviceProvider);
98             Func<object> getConverter = () => Activator.CreateInstance(convertertype);
99             ;
100             return value.ConvertTo(toType, getConverter, serviceProvider);
101         }
102
103         private delegate void ParseValueFunc(string s, IFormatProvider provider);
104
105         static private Dictionary<Type, ParseValueFunc> typeToParseValueFunc = null;
106
107         static private void BuildParseValueFunc()
108         {
109             if (null == typeToParseValueFunc)
110             {
111                 typeToParseValueFunc = new Dictionary<Type, ParseValueFunc>();
112
113             }
114         }
115
116         internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
117             IServiceProvider serviceProvider)
118         {
119             if (value == null)
120                 return null;
121
122             var str = value as string;
123             if (str != null)
124             {
125                 //If there's a [TypeConverter], use it
126                 object converter = getConverter?.Invoke();
127                 if (null != converter)
128                 {
129                     var xfTypeConverter = converter as TypeConverter;
130                     var xfExtendedTypeConverter = xfTypeConverter as IExtendedTypeConverter;
131                     if (xfExtendedTypeConverter != null)
132                         return value = xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
133                     if (xfTypeConverter != null)
134                         return value = xfTypeConverter.ConvertFromInvariantString(str);
135                     var converterType = converter?.GetType();
136                     if (converterType != null)
137                     {
138                         var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
139                             new[] { typeof(string) });
140                         if (convertFromStringInvariant != null)
141                             return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
142                     }
143                 }
144
145                 var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
146
147                 //If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
148                 if (toType.GetTypeInfo().IsGenericType && toType.GetGenericTypeDefinition() == typeof (Nullable<>))
149                     toType = Nullable.GetUnderlyingType(toType);
150
151                 //Obvious Built-in conversions
152                 if (toType.GetTypeInfo().IsEnum)
153                     return Enum.Parse(toType, str, ignoreCase);
154
155                 if (toType == typeof(SByte))
156                     return SByte.Parse(str, CultureInfo.InvariantCulture);
157                 if (toType == typeof(Int16))
158                     return Int16.Parse(str, CultureInfo.InvariantCulture);
159                 if (toType == typeof(Int32))
160                     return Int32.Parse(str, CultureInfo.InvariantCulture);
161                 if (toType == typeof(Int64))
162                     return Int64.Parse(str, CultureInfo.InvariantCulture);
163                 if (toType == typeof(Byte))
164                     return Byte.Parse(str, CultureInfo.InvariantCulture);
165                 if (toType == typeof(UInt16))
166                     return UInt16.Parse(str, CultureInfo.InvariantCulture);
167                 if (toType == typeof(UInt32))
168                     return UInt32.Parse(str, CultureInfo.InvariantCulture);
169                 if (toType == typeof(UInt64))
170                     return UInt64.Parse(str, CultureInfo.InvariantCulture);
171                 if (toType == typeof (Single))
172                     return Single.Parse(str, CultureInfo.InvariantCulture);
173                 if (toType == typeof (Double))
174                     return Double.Parse(str, CultureInfo.InvariantCulture);
175                 if (toType == typeof (Boolean))
176                     return Boolean.Parse(str);
177                 if (toType == typeof (TimeSpan))
178                     return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
179                 if (toType == typeof (DateTime))
180                     return DateTime.Parse(str, CultureInfo.InvariantCulture);
181                 if (toType == typeof(Char)) {
182                     char c = '\0';
183                     Char.TryParse(str, out c);
184                     return c;
185                 }
186                 if (toType == typeof (String) && str.StartsWith("{}", StringComparison.Ordinal))
187                     return str.Substring(2);
188                 if (toType == typeof (String))
189                     return value;
190                 if (toType == typeof(Decimal))
191                     return Decimal.Parse(str, CultureInfo.InvariantCulture);
192             }
193
194             //if the value is not assignable and there's an implicit conversion, convert
195             if (value != null && !toType.IsAssignableFrom(value.GetType())) {
196                 var opImplicit =   value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: toType)
197                                 ?? toType.GetImplicitConversionOperator(fromType: value.GetType(), toType: toType);
198
199                 if (opImplicit != null) {
200                     value = opImplicit.Invoke(null, new[] { value });
201                     return value;
202                 }
203             }
204
205             var nativeValueConverterService = DependencyService.Get<INativeValueConverterService>();
206
207             object nativeValue = null;
208             if (nativeValueConverterService != null && nativeValueConverterService.ConvertTo(value, toType, out nativeValue))
209                 return nativeValue;
210
211             return value;
212         }
213
214         internal static MethodInfo GetImplicitConversionOperator(this Type onType, Type fromType, Type toType)
215         {
216 #if NETSTANDARD1_0
217             var mi = onType.GetRuntimeMethod("op_Implicit", new[] { fromType });
218 #else
219             var bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
220             var mi = onType.GetMethod("op_Implicit", bindingFlags, null, new[] { fromType }, null);
221 #endif
222             if (mi == null) return null;
223             if (!mi.IsSpecialName) return null;
224             if (!mi.IsPublic) return null;
225             if (!mi.IsStatic) return null;
226             if (!toType.IsAssignableFrom(mi.ReturnType)) return null;
227
228             return mi;
229         }
230     }
231 }