ChangeLog: Updated
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / BaseCompareValidator.cs
1
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
10 // 
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 // 
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 /**
23  * Namespace: System.Web.UI.WebControls
24  * Class:     BaseCompareValidator
25  *
26  * Author:  Gaurav Vaish
27  * Maintainer: gvaish@iitk.ac.in
28  * Implementation: yes
29  * Contact: <gvaish@iitk.ac.in>
30  * Status:  100%
31  *
32  * (C) Gaurav Vaish (2001)
33  */
34
35 using System;
36 using System.Collections;
37 using System.Globalization;
38 using System.Text;
39 using System.Text.RegularExpressions;
40 using System.Web;
41 using System.Web.UI;
42 using System.ComponentModel;
43
44 namespace System.Web.UI.WebControls
45 {
46         public abstract class BaseCompareValidator: BaseValidator
47         {
48                 protected BaseCompareValidator(): base()
49                 {
50                 }
51
52                 public static bool CanConvert(string text, ValidationDataType type)
53                 {
54                         object o = null;
55                         return Convert(text, type, out o);
56                 }
57
58                 [DefaultValue(ValidationDataType.String)]
59                 [WebCategory("Behavior")]
60                 [WebSysDescription("RangeValidator_Type")]
61                 public ValidationDataType Type
62                 {
63                         get
64                         {
65                                 object o = ViewState["Type"];
66                                 if(o!=null)
67                                         return (ValidationDataType)o;
68                                 return ValidationDataType.String;
69                         }
70                         set
71                         {
72                                 if(!System.Enum.IsDefined(typeof(ValidationDataType), value))
73                                         throw new ArgumentException();
74                                 ViewState["Type"] = value;
75                         }
76                 }
77
78                 protected static int CutoffYear
79                 {
80                         get
81                         {
82                                 return DateTimeFormatInfo.CurrentInfo.Calendar.TwoDigitYearMax;
83                         }
84                 }
85
86                 protected static int GetFullYear(int shortYear)
87                 {
88                         int century = DateTime.Today.Year - (DateTime.Today.Year % 100);
89                         if(century < CutoffYear)
90                         {
91                                 return (shortYear + century);
92                         }
93                         return (shortYear + century - 100);
94                 }
95
96                 protected override void AddAttributesToRender(HtmlTextWriter writer)
97                 {
98                         base.AddAttributesToRender(writer);
99                         if(RenderUplevel)
100                         {
101                                 writer.AddAttribute("type", PropertyConverter.EnumToString(typeof(ValidationDataType), Type));
102                                 NumberFormatInfo currInfo = NumberFormatInfo.CurrentInfo;
103                                 if(Type == ValidationDataType.Double)
104                                 {
105                                         writer.AddAttribute("decimalchar", currInfo.NumberDecimalSeparator);
106                                         return;
107                                 }
108                                 if(Type == ValidationDataType.Currency)
109                                 {
110                                         writer.AddAttribute("decimalchar", currInfo.CurrencyDecimalSeparator);
111                                         string grpSep = currInfo.CurrencyGroupSeparator;
112                                         if(grpSep[0] == 0xA0)
113                                         {
114                                                 grpSep = " ";
115                                         }
116                                         writer.AddAttribute("groupchar", grpSep);
117                                         writer.AddAttribute("digits", currInfo.CurrencyDecimalDigits.ToString(NumberFormatInfo.InvariantInfo));
118                                         return;
119                                 }
120                                 if(Type == ValidationDataType.Date)
121                                 {
122                                         writer.AddAttribute("cutoffyear", CutoffYear.ToString());
123                                         writer.AddAttribute("century", ( DateTime.Today.Year - (DateTime.Today.Year % 100) ).ToString());
124                                         return;
125                                 }
126                         }
127                 }
128
129                 protected override bool DetermineRenderUplevel()
130                 {
131                         if(Type == ValidationDataType.Date && DateTimeFormatInfo.CurrentInfo.Calendar.GetType() != typeof(GregorianCalendar))
132                         {
133                                 return false;
134                         }
135                         return base.DetermineRenderUplevel();
136                 }
137
138                 /// <summary>
139                 /// Undocumented
140                 /// </summary>
141                 protected static bool Compare(string leftText, string rightText, ValidationCompareOperator op, ValidationDataType type)
142                 {
143                         object left = null, right = null;
144                         if(!Convert(leftText, type, out left))
145                         {
146                                 return false;
147                         }
148                         if(op == ValidationCompareOperator.DataTypeCheck)
149                         {
150                                 return true;
151                         }
152                         if(!Convert(rightText, type, out right))
153                         {
154                                 return true;
155                         }
156                         int compareResult = 0;
157                         switch(type)
158                         {
159                                 case ValidationDataType.String:
160                                         compareResult = ((String)left).CompareTo(right);
161                                         break;
162                                 case ValidationDataType.Integer:
163                                         compareResult = ((int)left).CompareTo(right);
164                                         break;
165                                 case ValidationDataType.Double:
166                                         compareResult = ((Double)left).CompareTo(right);
167                                         break;
168                                 case ValidationDataType.Date:
169                                         compareResult = ((DateTime)left).CompareTo(right);
170                                         break;
171                                 case ValidationDataType.Currency:
172                                         compareResult = ((Decimal)left).CompareTo(right);
173                                         break;
174                         }
175                         switch(op)
176                         {
177                                 case ValidationCompareOperator.Equal:
178                                         return (compareResult == 0);
179                                 case ValidationCompareOperator.NotEqual:
180                                         return (compareResult != 0);
181                                 case ValidationCompareOperator.GreaterThan:
182                                         return (compareResult > 0);
183                                 case ValidationCompareOperator.GreaterThanEqual:
184                                         return (compareResult >= 0);
185                                 case ValidationCompareOperator.LessThan:
186                                         return (compareResult < 0);
187                                 case ValidationCompareOperator.LessThanEqual:
188                                         return (compareResult <= 0);
189                         }
190                         return false;
191                 }
192
193                 /// <summary>
194                 /// Undocumented
195                 /// </summary>
196                 protected static string GetDateElementOrder()
197                 {
198                         string pattern = DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
199
200                         //TODO: What are the various possibilities?
201                         // I can think of only y*/M*/d*, d*/M*/y*, M*/d*/y*
202                         if(pattern.IndexOf('y') < pattern.IndexOf('M'))
203                         {
204                                 return "ymd";
205                         }
206                         if(pattern.IndexOf('M') < pattern.IndexOf('d'))
207                         {
208                                 return "mdy";
209                         }
210                         return "dmy";
211                 }
212
213                 static bool ConvertDate (string text, ValidationDataType type, ref object convertedValue)
214                 {
215                         //Console.WriteLine (DateTimeFormatInfo.CurrentInfo.Calendar.GetType ());
216                         // FIXME: sometime, somehow, the condition is true even when GetType () says
217                         // it's a GregorianCalendar.
218                         if (DateTimeFormatInfo.CurrentInfo.Calendar.GetType () != typeof (GregorianCalendar)) {
219                                 convertedValue = DateTime.Parse (text);
220                                 return true;
221                         }
222
223                         string order = GetDateElementOrder ();
224                         int date = 0, mth = 0, year = 0;
225                         string dateStr = null;
226                         string mthStr = null;
227                         string yearStr = null;
228                         Match match = Regex.Match (text, @"^\s*((\d{4})|(\d{2}))([\.\/-])(\d{1,2})\4(\d{1,2})\s*$");
229                         if (match.Success || order == "ymd") {
230                                 dateStr = match.Groups [6].Value;
231                                 mthStr = match.Groups [5].Value;
232                                 if (match.Groups [2].Success)
233                                         yearStr = match.Groups [2].Value;
234                                 else
235                                         yearStr = match.Groups [3].Value;
236                         } else {
237                                 match = Regex.Match(text, @"^\s*(\d{1,2})([\.\/-])(\d{1,2})\2((\d{4}|\d{2}))\s*$");
238                                 if (!match.Success)
239                                         return false;
240
241                                 if (order == "dmy") {
242                                         dateStr = match.Groups [1].Value;
243                                         mthStr  = match.Groups [3].Value;
244                                         if (match.Groups [5].Success)
245                                                 yearStr = match.Groups [5].Value;
246                                         else
247                                                 yearStr = match.Groups [6].Value;
248                                 } else if (order == "mdy") {
249                                         dateStr = match.Groups [3].Value;
250                                         mthStr  = match.Groups [1].Value;
251                                         if (match.Groups [5].Success)
252                                                 yearStr = match.Groups [5].Value;
253                                         else
254                                                 yearStr = match.Groups [6].Value;
255                                 }
256                         }
257
258                         if (dateStr == null || mthStr == null || yearStr == null) {
259                                 return false;
260                         }
261
262                         CultureInfo inv = CultureInfo.InvariantCulture;
263                         date = Int32.Parse (dateStr, inv);
264                         mth  = Int32.Parse (mthStr, inv);
265                         year = Int32.Parse (yearStr, inv);
266                         year = (year < 100 ? GetFullYear (year) : year);
267                         if (date != 0 && mth != 0 && year != 0) {
268                                 convertedValue = new DateTime  (year, mth, date);
269                                 return true;
270                         }
271
272                         return false;
273                 }
274
275                 static bool ConvertDouble (string text, ValidationDataType type, ref object convertedValue)
276                 {
277                         Match match = Regex.Match (text, @"^\s*([-\+])?(\d+)?(\" +
278                                                    NumberFormatInfo.CurrentInfo.NumberDecimalSeparator +
279                                                    @"(\d+))?\s*$");
280
281                         if (!match.Success)
282                                 return false;
283
284                         string sign     = (match.Groups [1].Success ? match.Groups [1].Value : "+");
285                         string decPart  = (match.Groups [2].Success ? match.Groups [2].Value : "0");
286                         string mantissa = (match.Groups [4].Success ? match.Groups [4].Value : "0");
287                         string num = sign + decPart + "." + mantissa;
288                         convertedValue  = Double.Parse (num, CultureInfo.InvariantCulture);
289                         return true;
290                 }
291
292                 static bool ConvertCurrency (string text, ValidationDataType type, ref object convertedValue)
293                 {
294                         string decSep = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator;
295                         string grpSep = NumberFormatInfo.CurrentInfo.CurrencyGroupSeparator;
296                         int decDig = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits;
297                         if (grpSep [0] == 0xA0)
298                                 grpSep = " ";
299
300                         string [] patternArray = new string [5];
301                         patternArray [0] = "^\\s*([-\\+])?(((\\d+)\\";
302                         patternArray [1] = grpSep;
303                         patternArray [2] = @")*)(\d+)";
304                         if (decDig > 0) {
305                                 string [] decPattern = new string [5];
306                                 decPattern [0] = "(\\";
307                                 decPattern [1] = decSep;
308                                 decPattern [2] = @"(\d{1,";
309                                 decPattern [3] = decDig.ToString (NumberFormatInfo.InvariantInfo);
310                                 decPattern [4] = @"}))";
311                                 patternArray [3] = String.Concat (decPattern);
312
313                         } else {
314                                 patternArray [3] = String.Empty;
315                         }
316
317                         patternArray [4] = @"?\s*$";
318                         Match match = Regex.Match (text, String.Concat (patternArray));
319                         if (!match.Success)
320                                 return false;
321
322                         StringBuilder sb = new StringBuilder ();
323                         sb.Append (match.Groups [1]);
324                         CaptureCollection cc = match.Groups [4].Captures;
325                         foreach (IEnumerable current in cc)
326                                 sb.Append ((Capture) current);
327
328                         sb.Append (match.Groups [5]);
329                         if (decDig > 0) {
330                                 sb.Append (".");
331                                 sb.Append (match.Groups [7]);
332                         }
333
334                         convertedValue = Decimal.Parse (sb.ToString (), CultureInfo.InvariantCulture);
335                         return true;
336                 }
337
338                 /// <summary>
339                 /// Undocumented
340                 /// </summary>
341                 protected static bool Convert (string text, ValidationDataType type, out object convertedValue)
342                 {
343                         CultureInfo inv = CultureInfo.InvariantCulture;
344                         convertedValue = null;
345                         try {
346                                 switch(type) {
347                                 case ValidationDataType.String:
348                                         convertedValue = text;
349                                         break;
350                                 case ValidationDataType.Integer:
351                                         convertedValue = Int32.Parse (text, inv);
352                                         break;
353                                 case ValidationDataType.Double:
354                                         return ConvertDouble (text, type, ref convertedValue);
355                                 case ValidationDataType.Date:
356                                         return ConvertDate (text, type, ref convertedValue);
357                                 case  ValidationDataType.Currency:
358                                         return ConvertCurrency (text, type, ref convertedValue);
359                                 }
360                         } catch (Exception) {
361                                 convertedValue = null;
362                         }
363
364                         return (convertedValue != null);
365                 }
366         }
367 }