2006-02-20 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaSimpleTypeRestriction.cs
1 // Author: Dwivedi, Ajay kumar\r
2 //            Adwiv@Yahoo.com\r
3 \r
4 //\r
5 // Permission is hereby granted, free of charge, to any person obtaining\r
6 // a copy of this software and associated documentation files (the\r
7 // "Software"), to deal in the Software without restriction, including\r
8 // without limitation the rights to use, copy, modify, merge, publish,\r
9 // distribute, sublicense, and/or sell copies of the Software, and to\r
10 // permit persons to whom the Software is furnished to do so, subject to\r
11 // the following conditions:\r
12 // \r
13 // The above copyright notice and this permission notice shall be\r
14 // included in all copies or substantial portions of the Software.\r
15 // \r
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
23 //\r
24 using System;\r
25 using System.Collections;\r
26 using System.Text;\r
27 using System.Text.RegularExpressions;\r
28 using System.Xml;\r
29 using System.Xml.Serialization;\r
30 using Mono.Xml.Schema;\r
31 using System.Globalization;\r
32 \r
33 namespace System.Xml.Schema\r
34 {\r
35         /// <summary>\r
36         /// Summary description for XmlSchemaSimpleTypeRestriction.\r
37         /// </summary>\r
38         public class XmlSchemaSimpleTypeRestriction : XmlSchemaSimpleTypeContent\r
39         {\r
40                 private XmlSchemaSimpleType baseType;\r
41                 private XmlQualifiedName baseTypeName;\r
42                 private XmlSchemaObjectCollection facets;\r
43                 const string xmlname = "restriction";\r
44                 private string [] enumarationFacetValues;\r
45                 private string [] patternFacetValues;\r
46                 private Regex [] rexPatterns;\r
47                 private decimal lengthFacet;\r
48                 private decimal maxLengthFacet;\r
49                 private decimal minLengthFacet;\r
50                 private decimal fractionDigitsFacet;\r
51                 private decimal totalDigitsFacet;\r
52                 private object maxInclusiveFacet ;\r
53                 private object maxExclusiveFacet ;\r
54                 private object minInclusiveFacet ;\r
55                 private object minExclusiveFacet ;\r
56                 private XmlSchemaFacet.Facet fixedFacets = XmlSchemaFacet.Facet.None; \r
57                 private static NumberStyles lengthStyle = NumberStyles.Integer;\r
58 \r
59 \r
60                 public XmlSchemaSimpleTypeRestriction()\r
61                 {\r
62                         baseTypeName = XmlQualifiedName.Empty;\r
63                         facets = new XmlSchemaObjectCollection();\r
64                 }\r
65 \r
66                 [System.Xml.Serialization.XmlAttribute("base")]\r
67                 public XmlQualifiedName BaseTypeName \r
68                 {\r
69                         get{ return  baseTypeName; } \r
70                         set{ baseTypeName = value; }\r
71                 }\r
72 \r
73                 [XmlElement("simpleType", Type=typeof (XmlSchemaSimpleType))]\r
74                 public XmlSchemaSimpleType BaseType \r
75                 {\r
76                         get{ return  baseType; } \r
77                         set{ baseType = value; }\r
78                 }\r
79 \r
80                 [XmlElement("minExclusive",typeof(XmlSchemaMinExclusiveFacet))]\r
81                 [XmlElement("minInclusive",typeof(XmlSchemaMinInclusiveFacet))] \r
82                 [XmlElement("maxExclusive",typeof(XmlSchemaMaxExclusiveFacet))]\r
83                 [XmlElement("maxInclusive",typeof(XmlSchemaMaxInclusiveFacet))]\r
84                 [XmlElement("totalDigits",typeof(XmlSchemaTotalDigitsFacet))]\r
85                 [XmlElement("fractionDigits",typeof(XmlSchemaFractionDigitsFacet))]\r
86                 [XmlElement("length",typeof(XmlSchemaLengthFacet))]\r
87                 [XmlElement("minLength",typeof(XmlSchemaMinLengthFacet))]\r
88                 [XmlElement("maxLength",typeof(XmlSchemaMaxLengthFacet))]\r
89                 [XmlElement("enumeration",typeof(XmlSchemaEnumerationFacet))]\r
90                 [XmlElement("whiteSpace",typeof(XmlSchemaWhiteSpaceFacet))]\r
91                 [XmlElement("pattern",typeof(XmlSchemaPatternFacet))]\r
92                 public XmlSchemaObjectCollection Facets \r
93                 {\r
94                         get{ return facets; }\r
95                 }\r
96 \r
97                 /// <remarks>\r
98                 /// 1. One of base or simpletype must be present but not both\r
99                 /// 2. id must be a valid ID\r
100                 /// 3. base must be a valid QName *NO CHECK REQUIRED*\r
101                 /// </remarks>\r
102                 internal override int Compile(ValidationEventHandler h, XmlSchema schema)\r
103                 {\r
104                         // If this is already compiled this time, simply skip.\r
105                         if (this.IsComplied (schema.CompilationId))\r
106                                 return 0;\r
107 \r
108 #if NET_2_0\r
109                         if (BaseType != null)\r
110                                 BaseType.Parent = this;\r
111                         foreach (XmlSchemaObject obj in Facets)\r
112                                 obj.Parent = this;\r
113 #endif\r
114 \r
115                         errorCount = 0;\r
116 \r
117                         if(this.baseType != null && !this.BaseTypeName.IsEmpty)\r
118                                 error(h, "both base and simpletype can't be set");\r
119                         if(this.baseType == null && this.BaseTypeName.IsEmpty)\r
120                                 error(h, "one of basetype or simpletype must be present");\r
121                         if(this.baseType != null)\r
122                         {\r
123                                 errorCount += this.baseType.Compile(h,schema);\r
124                         }\r
125                         if(!XmlSchemaUtil.CheckQName(BaseTypeName))\r
126                                 error(h,"BaseTypeName must be a XmlQualifiedName");\r
127 \r
128                         XmlSchemaUtil.CompileID(Id,this,schema.IDCollection,h);\r
129 \r
130                         for (int i = 0; i < this.Facets.Count; i++)\r
131                                 if (! (Facets [i] is XmlSchemaFacet))\r
132                                         error (h, "Only XmlSchemaFacet objects are allowed for Facets property");\r
133                         this.CompilationId = schema.CompilationId;\r
134                         return errorCount;\r
135                 }\r
136                 \r
137                 /** Checks if this facet is valid on this restriction. Does not check that it has\r
138                         * not been fixed in the baseType. That is done elsewhere.\r
139                         */\r
140                 \r
141                 private static readonly XmlSchemaFacet.Facet listFacets =\r
142                                                  XmlSchemaFacet.Facet.length | XmlSchemaFacet.Facet.minLength |\r
143                                                  XmlSchemaFacet.Facet.maxLength | XmlSchemaFacet.Facet.pattern | \r
144                                                  XmlSchemaFacet.Facet.enumeration | XmlSchemaFacet.Facet.whiteSpace; \r
145  \r
146                 \r
147                 private bool IsAllowedFacet(XmlSchemaFacet xsf) {\r
148                 /* Must be called after this.ValidateActualType, as it uses actualBaseSchemaType */\r
149 \r
150                         XsdAnySimpleType ast = ActualBaseSchemaType as XsdAnySimpleType;\r
151                         if (ast != null) {\r
152                                 // Based directly on an xsd type \r
153                                 return ast.AllowsFacet(xsf);\r
154                         }\r
155                         else {\r
156                          XmlSchemaSimpleTypeContent st = ((XmlSchemaSimpleType)ActualBaseSchemaType).Content as XmlSchemaSimpleTypeContent;\r
157                          if (st != null) {\r
158                                  XmlSchemaSimpleTypeRestriction str = st as XmlSchemaSimpleTypeRestriction;\r
159                                  if (str != null && str != this) {\r
160                                          return str.IsAllowedFacet(xsf);\r
161                                  }\r
162                                  XmlSchemaSimpleTypeList stl = st as XmlSchemaSimpleTypeList;\r
163                                  if (stl != null) {\r
164                                          return ((xsf.ThisFacet & listFacets) != 0);\r
165                                  }\r
166 \r
167                                  XmlSchemaSimpleTypeUnion stu = st as XmlSchemaSimpleTypeUnion;\r
168                                  if (stu != null) {\r
169                                          return (xsf is XmlSchemaPatternFacet ||\r
170                                                                          xsf is XmlSchemaEnumerationFacet);\r
171                                  }\r
172                                  \r
173                          }\r
174                          else {\r
175                                  // TODO: Should this be either a XmlSchemaSimpleType or XmlSchemaDatatype ?\r
176                                  // If so report error\r
177                          }\r
178                         }\r
179                         // Not sure it could ever get here\r
180                         return false;\r
181                 }\r
182                 \r
183                 \r
184         \r
185                 internal override int Validate(ValidationEventHandler h, XmlSchema schema)\r
186                 {\r
187                         \r
188                         if (IsValidated (schema.ValidationId))\r
189                                 return errorCount;\r
190 \r
191                         this.ValidateActualType (h, schema);\r
192 \r
193                         \r
194                         lengthFacet = maxLengthFacet = minLengthFacet = fractionDigitsFacet = totalDigitsFacet = -1;\r
195                         \r
196                         XmlSchemaSimpleTypeRestriction baseSTR = null; \r
197 \r
198                         if (ActualBaseSchemaType is XmlSchemaSimpleType) {\r
199                                 XmlSchemaSimpleTypeContent st = ((XmlSchemaSimpleType)ActualBaseSchemaType).Content as XmlSchemaSimpleTypeContent;\r
200                                 baseSTR = st as XmlSchemaSimpleTypeRestriction;\r
201                         }\r
202                         \r
203                                 \r
204                         if (baseSTR != null) {\r
205                                 fixedFacets = baseSTR.fixedFacets;\r
206                                 lengthFacet = baseSTR.lengthFacet;\r
207                                 maxLengthFacet = baseSTR.maxLengthFacet;\r
208                                 minLengthFacet = baseSTR.minLengthFacet;\r
209                                 fractionDigitsFacet = baseSTR.fractionDigitsFacet;\r
210                                 totalDigitsFacet = baseSTR.totalDigitsFacet;\r
211                                 maxInclusiveFacet = baseSTR.maxInclusiveFacet;\r
212                                 maxExclusiveFacet = baseSTR.maxExclusiveFacet;\r
213                                 minInclusiveFacet = baseSTR.minInclusiveFacet;\r
214                                 minExclusiveFacet = baseSTR.minExclusiveFacet;\r
215                         }\r
216                         \r
217                         enumarationFacetValues = patternFacetValues = null;\r
218                         rexPatterns = null;\r
219                         \r
220                         XmlSchemaFacet.Facet facetsDefined = XmlSchemaFacet.Facet.None; \r
221 \r
222                         ArrayList enums = null;\r
223                         ArrayList patterns = null;\r
224                         for (int i = 0; i < facets.Count; i++) {\r
225 \r
226                                 XmlSchemaFacet facet = facets[i] as XmlSchemaFacet;\r
227                                 if (facet != null) {\r
228                                         if (!IsAllowedFacet(facet)) {\r
229                                                 facet.error(h, facet.ThisFacet +" is not a valid facet for this type");\r
230                                                 continue;\r
231                                         }\r
232                                 }\r
233                                 else {\r
234                                         // Other than XmlSchemaFacet; already reported at Compile()\r
235                                         continue;\r
236                                 }\r
237 \r
238                                 \r
239                                 XmlSchemaEnumerationFacet ef = facets [i] as XmlSchemaEnumerationFacet;\r
240                                 if (ef != null) {\r
241                                         if (enums == null)\r
242                                                 enums = new ArrayList ();\r
243                                         enums.Add (ef.Value);\r
244                                         continue;\r
245                                 }\r
246                                 XmlSchemaPatternFacet pf = facets [i] as XmlSchemaPatternFacet;\r
247                                 if (pf != null) {\r
248                                         if (patterns == null)\r
249                                                 patterns = new ArrayList ();\r
250                                         patterns.Add (pf.Value);\r
251                                         continue;\r
252                                 }\r
253                                 \r
254                                 // Put this test here, as pattern and enumeration \r
255                                 // can occur multiple times.\r
256                                 if ( (facetsDefined & facet.ThisFacet) !=0) {\r
257                                         facet.error (h, "This is a duplicate '" + facet.ThisFacet + "' facet.");\r
258                                         continue;\r
259                                 }\r
260                                 else {\r
261                                         facetsDefined |= facet.ThisFacet; \r
262                                 }\r
263 \r
264                                 \r
265                                 \r
266 \r
267                                 \r
268                                 if (facet is XmlSchemaLengthFacet) {\r
269                                         checkLengthFacet((XmlSchemaLengthFacet)facet, facetsDefined, h);\r
270                                 }\r
271                                 else if (facet is XmlSchemaMaxLengthFacet) {\r
272                                         checkMaxLengthFacet((XmlSchemaMaxLengthFacet)facet, facetsDefined, h);\r
273                                 }\r
274                                 else if (facet is XmlSchemaMinLengthFacet) {\r
275                                         checkMinLengthFacet((XmlSchemaMinLengthFacet)facet, facetsDefined, h);\r
276                                 }\r
277                                 \r
278                                 else if (facet is XmlSchemaMinInclusiveFacet) {\r
279                                         checkMinMaxFacet((XmlSchemaMinInclusiveFacet)facet, ref minInclusiveFacet, h);\r
280                                 }\r
281                                 else if (facet is XmlSchemaMaxInclusiveFacet) {\r
282                                         checkMinMaxFacet((XmlSchemaMaxInclusiveFacet)facet, ref maxInclusiveFacet, h);\r
283                                 }\r
284                                 else if (facet is XmlSchemaMinExclusiveFacet) {\r
285                                         checkMinMaxFacet((XmlSchemaMinExclusiveFacet)facet, ref minExclusiveFacet, h);\r
286                                 }\r
287                                 else if (facet is XmlSchemaMaxExclusiveFacet) {\r
288                                         checkMinMaxFacet((XmlSchemaMaxExclusiveFacet)facet, ref maxExclusiveFacet, h);\r
289                                 }\r
290                                 else if (facet is XmlSchemaFractionDigitsFacet) {\r
291                                         checkFractionDigitsFacet((XmlSchemaFractionDigitsFacet)facet, h);\r
292                                 }\r
293                                 else if (facet is XmlSchemaTotalDigitsFacet) {\r
294                                         checkTotalDigitsFacet((XmlSchemaTotalDigitsFacet)facet, h);\r
295                                 }\r
296 \r
297                                 if (facet.IsFixed) {\r
298                                         fixedFacets |= facet.ThisFacet;\r
299                                 }\r
300                                 \r
301                          \r
302                         }\r
303                         if (enums != null)\r
304                                 this.enumarationFacetValues = enums.ToArray (typeof (string)) as string [];\r
305                         if (patterns != null) {\r
306                                 this.patternFacetValues = patterns.ToArray (typeof (string)) as string [];\r
307                                 this.rexPatterns = new Regex [patterns.Count];\r
308                                 for (int i = 0; i < patternFacetValues.Length; i++) {\r
309                                         try {\r
310                                                 string src = patternFacetValues [i];\r
311                                                 StringBuilder sb = null;\r
312                                                 int start = 0;\r
313                                                 for (int c = 0; c < src.Length; c++) {\r
314                                                         if (src [c] == '\\' && src.Length > i + 1) {\r
315                                                                 string subst = null;\r
316                                                                 switch (src [c + 1]) {\r
317                                                                 case 'i':\r
318                                                                         subst = "[\\p{L}_]";\r
319                                                                         break;\r
320                                                                 case 'I':\r
321                                                                         subst = "[^\\p{L}_]";\r
322                                                                         break;\r
323                                                                 case 'c':\r
324                                                                         subst = "[\\p{L}\\p{N}_\\.\\-:]";\r
325                                                                         break;\r
326                                                                 case 'C':\r
327                                                                         subst = "[^\\p{L}\\p{N}_\\.\\-:]";\r
328                                                                         break;\r
329                                                                 }\r
330                                                                 if (subst != null) {\r
331                                                                         if (sb == null)\r
332                                                                                 sb = new StringBuilder ();\r
333                                                                         sb.Append (src, start, c - start);\r
334                                                                         sb.Append (subst);\r
335                                                                         start = c + 2;\r
336                                                                 }\r
337                                                         }\r
338                                                 }\r
339                                                 if (sb != null) {\r
340                                                         sb.Append (src, start, src.Length - start);\r
341                                                         src = sb.ToString ();\r
342                                                 }\r
343 //                                              src = src.Replace ("\\i", "[\\p{L}_]").Replace ("\\I", "[^\\p{L}_]").Replace ("\\c", "[\\p{L}\\p{N}_\\.\\-:]").Replace ("\\C", "[^\\p{L}\\p{N}_\\.\\-:]");\r
344                                                 Regex rex = new Regex ("^" + src + "$");\r
345                                                 rexPatterns [i] = rex;\r
346                                         } catch (Exception ex) {\r
347                                                 error (h, "Invalid regular expression pattern was specified.", ex);\r
348                                         }\r
349                                 }\r
350                                 \r
351                                 \r
352                         \r
353                         }\r
354 \r
355                         ValidationId = schema.ValidationId;\r
356                  /* \r
357                                 Console.WriteLine("Facets:\n defined\t{10}\n fixed\t{0}\n length\t{1}\n maxLen\t{2}\n minLen\t{3}\n " +\r
358                                                                                                         "frac\t{4}\n tot\t{5}\n maxI\t{6}\n maxE\t{7}\n minI\t{8}\n minE\t{9}\n", \r
359                                                 fixedFacets , \r
360                                                 lengthFacet, \r
361                                                 maxLengthFacet ,\r
362                                                 minLengthFacet ,\r
363                                                 fractionDigitsFacet ,\r
364                                                 totalDigitsFacet ,\r
365                                                 maxInclusiveFacet ,\r
366                                                 maxExclusiveFacet ,\r
367                                                 minInclusiveFacet ,\r
368                                                 minExclusiveFacet , \r
369                                                 facetsDefined);\r
370 */\r
371                         return errorCount;\r
372                 }\r
373 \r
374 \r
375                 internal void ValidateActualType (ValidationEventHandler h, XmlSchema schema)\r
376                 {\r
377                         GetActualType (h, schema, true);\r
378                 }\r
379 \r
380                 internal object GetActualType (ValidationEventHandler h, XmlSchema schema, bool validate)\r
381                 {\r
382                         object actualBaseSchemaType = null;\r
383 \r
384                         XmlSchemaSimpleType type = baseType;\r
385                         if (type == null)\r
386                                 type = schema.SchemaTypes [baseTypeName] as XmlSchemaSimpleType;\r
387                         if (type != null) {\r
388                                 if (validate)\r
389                                         errorCount += type.Validate (h, schema);\r
390                                 actualBaseSchemaType = type;\r
391                         } else if (baseTypeName == XmlSchemaComplexType.AnyTypeName) {\r
392                                 actualBaseSchemaType = XmlSchemaSimpleType.AnySimpleType;\r
393                         } else if (baseTypeName.Namespace == XmlSchema.Namespace ||\r
394                                 baseTypeName.Namespace == XmlSchema.XdtNamespace) {\r
395                                 actualBaseSchemaType = XmlSchemaDatatype.FromName (baseTypeName);\r
396                                 if (actualBaseSchemaType == null)\r
397                                         if (validate)\r
398                                                 error (h, "Invalid schema type name was specified: " + baseTypeName);\r
399                         }\r
400                         // otherwise, it might be missing sub components.\r
401                         else if (!schema.IsNamespaceAbsent (baseTypeName.Namespace))\r
402                                 if (validate)\r
403                                         error (h, "Referenced base schema type " + baseTypeName + " was not found in the corresponding schema.");\r
404 \r
405                         return actualBaseSchemaType;\r
406                 }\r
407 \r
408                 \r
409                 private void checkTotalDigitsFacet (XmlSchemaTotalDigitsFacet totf, \r
410                                                                                                                                                                 ValidationEventHandler h) {\r
411                         if (totf != null) {\r
412                         /* totalDigits is the maximum number of digits in values of datatypes\r
413                          * derived from decimal. The value of totalDigits must be a\r
414                          * positiveInteger. */\r
415                                 try {\r
416                                         decimal newTotalDigits = decimal.Parse (totf.Value.Trim (), lengthStyle, CultureInfo.InvariantCulture);\r
417                                         if (newTotalDigits <= 0) \r
418                                                 totf.error(h, String.Format(CultureInfo.InvariantCulture, "The value '{0}' is an invalid totalDigits value", newTotalDigits));\r
419                                         // Valid restriction\r
420                                         if ((totalDigitsFacet > 0) && (newTotalDigits > totalDigitsFacet)) {\r
421                                                 totf.error(h, String.Format(CultureInfo.InvariantCulture, "The value '{0}' is not a valid restriction of the base totalDigits facet '{1}'", newTotalDigits, totalDigitsFacet));\r
422                                         }\r
423                                         totalDigitsFacet = newTotalDigits;\r
424                                 }\r
425                                 catch (FormatException ) {\r
426                                         totf.error(h, String.Format("The value '{0}' is an invalid totalDigits facet specification", totf.Value.Trim () ));\r
427                                 }\r
428                         }\r
429                 }\r
430 \r
431                 \r
432                 private void checkFractionDigitsFacet (XmlSchemaFractionDigitsFacet fracf, \r
433                                                                                                                                                                          ValidationEventHandler h) {\r
434 \r
435                         if (fracf != null) {\r
436                                 try {\r
437                                         decimal newFractionDigits = decimal.Parse (fracf.Value.Trim (), lengthStyle, CultureInfo.InvariantCulture);\r
438                                         if (newFractionDigits< 0) \r
439                                                 fracf.error(h, String.Format(CultureInfo.InvariantCulture, "The value '{0}' is an invalid fractionDigits value", newFractionDigits));\r
440                                         \r
441                                         if ((fractionDigitsFacet >= 0) && (newFractionDigits > fractionDigitsFacet)) {\r
442                                                 fracf.error(h, String.Format(CultureInfo.InvariantCulture, "The value '{0}' is not a valid restriction of the base fractionDigits facet '{1}'", newFractionDigits, fractionDigitsFacet));\r
443                                         }\r
444                                         fractionDigitsFacet = newFractionDigits;\r
445                                 }\r
446                                 catch (FormatException ) {\r
447                                         fracf.error(h, String.Format("The value '{0}' is an invalid fractionDigits facet specification", fracf.Value.Trim () ));\r
448                                 }\r
449                         }\r
450 \r
451                 }\r
452  \r
453                 \r
454                 private void checkMinMaxFacet(XmlSchemaFacet facet, \r
455                                                                                                                                                 ref object baseFacet,\r
456                                                                                                                                                 ValidationEventHandler h) { \r
457 // Is it a valid instance of the base type.\r
458                  object newValue = ValidateValueWithDatatype(facet.Value);\r
459                  if (newValue != null) {\r
460 // Is the base fixed - if so is it the same\r
461                          if (((fixedFacets & facet.ThisFacet) != 0)  && (baseFacet != null)){\r
462                                  XsdAnySimpleType dt = getDatatype();\r
463                                  if (dt.Compare (newValue, baseFacet) != XsdOrdering.Equal) {\r
464                                          facet.error (h, \r
465                                                          String.Format(CultureInfo.InvariantCulture, "{0} is not the same as fixed parent {1} facet.", \r
466                                                                                  facet.Value, facet.ThisFacet));\r
467                                  }\r
468                          }\r
469                          baseFacet = newValue;\r
470                  }\r
471                  else {\r
472                          facet.error(h, \r
473                                          String.Format("The value '{0}' is not valid against the base type.", facet.Value));\r
474                  }\r
475                 }\r
476                 \r
477                 \r
478 \r
479                 private void checkLengthFacet(XmlSchemaLengthFacet lf,  \r
480                                                                                                                                         XmlSchemaFacet.Facet facetsDefined, \r
481                                                                                                                                         ValidationEventHandler h) {\r
482                                 if (lf != null) {\r
483                                         try {\r
484                                         if ((facetsDefined & (XmlSchemaFacet.Facet.minLength | XmlSchemaFacet.Facet.maxLength)) != 0)  \r
485                                                         lf.error(h, "It is an error for both length and minLength or maxLength to be present.");\r
486                                                 else {\r
487                                                         lengthFacet = decimal.Parse (lf.Value.Trim (), lengthStyle, CultureInfo.InvariantCulture);\r
488                                                 /* TODO: Check that it is between inherited max/min lengths */\r
489                                                         if (lengthFacet < 0) \r
490                                                                 lf.error(h, "The value '" + lengthFacet + "' is an invalid length");\r
491                                                 }\r
492                                 } catch (FormatException) { // FIXME: better catch ;-(\r
493                                                 lf.error (h, "The value '" + lf.Value + "' is an invalid length facet specification");\r
494                                         }\r
495                                 }\r
496                 }\r
497 \r
498                 private void checkMaxLengthFacet(XmlSchemaMaxLengthFacet maxlf, \r
499                                                                                                                                                  XmlSchemaFacet.Facet facetsDefined,\r
500                                                                                                                                                  ValidationEventHandler h) {\r
501                                 if (maxlf != null) {\r
502                                         try {\r
503                                         if ((facetsDefined & XmlSchemaFacet.Facet.length) != 0) \r
504                                                         maxlf.error(h, "It is an error for both length and minLength or maxLength to be present.");\r
505                                                 else {\r
506                                                 decimal newMaxLengthFacet = decimal.Parse (maxlf.Value.Trim (), lengthStyle, CultureInfo.InvariantCulture);\r
507                                                 \r
508                                                 if (((fixedFacets & XmlSchemaFacet.Facet.maxLength)!=0) && (newMaxLengthFacet != maxLengthFacet)) \r
509                                                         maxlf.error(h, String.Format(CultureInfo.InvariantCulture, "The value '{0}' is not the same as the fixed value '{1}' on the base type", maxlf.Value.Trim (), maxLengthFacet));\r
510                                                 if ((maxLengthFacet >0) && (newMaxLengthFacet > maxLengthFacet)) \r
511                                                         maxlf.error(h, String.Format(CultureInfo.InvariantCulture, "The value '{0}' is not a valid restriction of the value '{1}' on the base maxLength facet", maxlf.Value.Trim (), maxLengthFacet));\r
512                                                 else\r
513                                                         maxLengthFacet = newMaxLengthFacet;\r
514                                                         if (maxLengthFacet < 0) \r
515                                                                 maxlf.error(h, "The value '" + maxLengthFacet + "' is an invalid maxLength");\r
516                                                         if (minLengthFacet >=0 && minLengthFacet > maxLengthFacet)\r
517                                                                 maxlf.error(h, "minLength is greater than maxLength.");\r
518                                                 }\r
519 \r
520                                 } catch (FormatException) { \r
521                                                 maxlf.error (h, "The value '" + maxlf.Value+ "' is an invalid maxLength facet specification");\r
522                                         }\r
523                                 }\r
524                 }\r
525 \r
526                 private void checkMinLengthFacet(XmlSchemaMinLengthFacet minlf, \r
527                                                                                                                                                  XmlSchemaFacet.Facet facetsDefined,\r
528                                                                                                                                                  ValidationEventHandler h) {\r
529                                 if (minlf != null) {\r
530                                         try {\r
531                                                 if (lengthFacet >=0) \r
532                                                         minlf.error(h, "It is an error for both length and minLength or maxLength to be present.");\r
533                                                 else {\r
534                                                 decimal newMinLengthFacet = decimal.Parse (minlf.Value.Trim (), lengthStyle, CultureInfo.InvariantCulture);\r
535                                                 \r
536                                                 if (((fixedFacets & XmlSchemaFacet.Facet.minLength)!=0) && (newMinLengthFacet != minLengthFacet)) \r
537                                                         minlf.error(h, String.Format(CultureInfo.InvariantCulture, "The value '{0}' is not the same as the fixed value '{1}' on the base type", minlf.Value.Trim (), minLengthFacet));\r
538                                                 if (newMinLengthFacet < minLengthFacet) \r
539                                                         minlf.error(h, String.Format(CultureInfo.InvariantCulture, "The value '{0}' is not a valid restriction of the value '{1}' on the base minLength facet", minlf.Value.Trim (), minLengthFacet));\r
540                                                 else\r
541                                                         minLengthFacet = newMinLengthFacet;\r
542                                                         if (minLengthFacet < 0) \r
543                                                                 minlf.error(h, "The value '" + minLengthFacet + "' is an invalid minLength");\r
544                                                         if (maxLengthFacet >=0 && minLengthFacet > maxLengthFacet)\r
545                                                                 minlf.error(h, "minLength is greater than maxLength.");\r
546                                                 }\r
547                                 } catch (FormatException) {\r
548                                                 minlf.error (h, "The value '" + minlf.Value + "' is an invalid minLength facet specification");\r
549                                         }\r
550                                 }\r
551                         }\r
552 \r
553 \r
554                 private XsdAnySimpleType getDatatype() {\r
555                         XsdAnySimpleType ast = ActualBaseSchemaType as XsdAnySimpleType;\r
556                         if (ast != null) {\r
557                                 // Based directly on an xsd type \r
558                                 return ast;\r
559                         }\r
560                         XmlSchemaSimpleTypeContent st = ((XmlSchemaSimpleType)ActualBaseSchemaType).Content as XmlSchemaSimpleTypeContent;\r
561                         \r
562                         if (st is XmlSchemaSimpleTypeRestriction) {\r
563                                 return ((XmlSchemaSimpleTypeRestriction)st).getDatatype();\r
564                         }\r
565                         else if ((st is XmlSchemaSimpleTypeList) ||\r
566                                                          (st is XmlSchemaSimpleTypeUnion)) {\r
567                                 return null;\r
568                         }\r
569                         return null;\r
570                 }\r
571 \r
572                 \r
573                 private object ValidateValueWithDatatype(string value) {\r
574                         XsdAnySimpleType dt = getDatatype();\r
575                         object ret = null;\r
576                         //              Console.WriteLine("DT: " + dt);\r
577                         if (dt != null) {\r
578                                         try {\r
579                                         /* I think we can parse null here, as the types \r
580                                          * that use the nametable and nsmgr are ones that \r
581                                          * we don't need to parse here.\r
582                                          */ \r
583                                         ret = dt.ParseValue (value, null, null);\r
584                                 //      Console.WriteLine("Ret: " + ret);\r
585                                         // If we are based on something with facets, check that we are valid\r
586                                         if (ActualBaseSchemaType is XmlSchemaSimpleType) {\r
587                                                 XmlSchemaSimpleTypeContent st = ((XmlSchemaSimpleType) ActualBaseSchemaType).Content as XmlSchemaSimpleTypeContent;\r
588                                                 if (st is XmlSchemaSimpleTypeRestriction) {\r
589                                                         if (((XmlSchemaSimpleTypeRestriction)st).ValidateValueWithFacets(value, null)) {\r
590                                                                 return ret;\r
591                                                         } else {\r
592                                                                 return null;\r
593                                         }\r
594                                 }\r
595                         }\r
596 \r
597                                 } catch (Exception) {\r
598                                         return null;\r
599                                 }\r
600                         }\r
601                         return ret;\r
602                 }\r
603 \r
604                 internal bool ValidateValueWithFacets (string value, XmlNameTable nt)\r
605                 {\r
606                         /*\r
607                          * FIXME: Shouldn't this be recursing more? What if this is a \r
608                          * restriction of a restriction of a list type?\r
609                          */\r
610                         XmlSchemaSimpleType baseST = this.ActualBaseSchemaType as XmlSchemaSimpleType;\r
611                         XmlSchemaSimpleTypeList listType = baseST != null ? baseST.Content as XmlSchemaSimpleTypeList : null;\r
612 \r
613                         // numeric\r
614                         if (listType != null)\r
615                                 return ValidateListValueWithFacets (value, nt);\r
616                         else\r
617                                 return ValidateNonListValueWithFacets (value, nt);\r
618                 }\r
619 \r
620                 private bool ValidateListValueWithFacets (string value, XmlNameTable nt)\r
621                 {\r
622                         string [] list = ((XsdAnySimpleType) XmlSchemaDatatype.FromName ("anySimpleType", XmlSchema.Namespace)).ParseListValue (value, nt);\r
623 \r
624                         // pattern\r
625                         if (this.patternFacetValues != null) {\r
626                                 for (int l = 0; l < list.Length; l++) {\r
627                                         for (int i = 0; i < this.patternFacetValues.Length; i++)\r
628                                                 if (rexPatterns [i] != null && !rexPatterns [i].IsMatch (list [l]))\r
629                                                         return false;\r
630                                 }\r
631                         }\r
632                         // enumeration\r
633                         if (this.enumarationFacetValues != null) {\r
634                                 for (int l = 0; l < list.Length; l++) {\r
635                                         bool matched = false;\r
636                                         for (int i = 0; i < this.enumarationFacetValues.Length; i++) {\r
637                                                 if (list [l] == this.enumarationFacetValues [i]) {\r
638                                                         matched = true;\r
639                                                         break;\r
640                                                 }\r
641                                         }\r
642                                         if (!matched)\r
643                                                 return false;\r
644                                 }\r
645                         }\r
646 \r
647                         // numeric\r
648                         // : length\r
649                         if (lengthFacet >= 0 && list.Length != lengthFacet)\r
650                                         return false;\r
651                         // : maxLength\r
652                         if (maxLengthFacet >= 0 && list.Length > maxLengthFacet)\r
653                                         return false;\r
654                         // : minLength\r
655                         if (minLengthFacet >= 0 && list.Length < minLengthFacet)\r
656                                         return false;\r
657                         \r
658                         return true;\r
659                 }\r
660 \r
661                 private bool ValidateNonListValueWithFacets (string value, XmlNameTable nt)\r
662                 {\r
663                         // pattern\r
664                         // Patterns are the only facets that need to be checked on this\r
665                         // type and its base types. We should probably separate them, then\r
666                         // do base-type pattern validation.\r
667                         if (this.patternFacetValues != null) {\r
668                                 bool matched = false;\r
669                                 for (int i = 0; i < this.patternFacetValues.Length; i++)\r
670                                         if (rexPatterns [i] != null && rexPatterns [i].IsMatch (value)) {\r
671                                                 matched = true;\r
672                                                 break;\r
673                                         }\r
674                                 if (!matched)\r
675                                         return false;\r
676                         }\r
677                         // enumeration\r
678                         if (this.enumarationFacetValues != null) {\r
679                                 bool matched = false;\r
680                                 for (int i = 0; i < this.enumarationFacetValues.Length; i++) {\r
681                                         if (value == this.enumarationFacetValues [i]) {\r
682                                                 matched = true;\r
683                                                 break;\r
684                                         }\r
685                                 }\r
686                                 if (!matched)\r
687                                         return false;\r
688                         }\r
689                         XsdAnySimpleType dt = getDatatype ();\r
690                         \r
691                         // Need to skip length tests for \r
692                         // types derived from QName or NOTATION\r
693                         // see errata: E2-36 Clarification\r
694                         \r
695                         if (! ( (dt is XsdQName) || (dt is XsdNotation))) {  \r
696         // Length potentially slower now, so only calculate if needed                   \r
697                                 if (! ((lengthFacet == -1) && (maxLengthFacet == -1) && (minLengthFacet == -1))) {\r
698                                                                                         \r
699                                         // numeric\r
700                                         // : length\r
701                                 \r
702                                         int length = dt.Length(value);\r
703                                         \r
704                                         if (lengthFacet >= 0 && length != lengthFacet)\r
705                                                         return false;\r
706                                         // : maxLength\r
707                                         if (maxLengthFacet >= 0 && length > maxLengthFacet)\r
708                                                         return false;\r
709                                         // : minLength\r
710                                         if (minLengthFacet >= 0 && length < minLengthFacet)\r
711                                                         return false;\r
712 \r
713                                 }\r
714                   }\r
715                                 \r
716                         if ((totalDigitsFacet >=0) || (fractionDigitsFacet >=0)) {\r
717                                 String newValue = value.Trim(new Char [] { '+', '-', '0', '.' });\r
718                                 int fractionDigits = 0;\r
719                                 int totalDigits = newValue.Length;\r
720                                 int point = newValue.IndexOf(".");\r
721                                 if (point != -1) {\r
722                                         totalDigits -= 1;\r
723                                         fractionDigits = newValue.Length - point -1; \r
724                                 } \r
725                                 if ((totalDigitsFacet >=0) && (totalDigits > totalDigitsFacet)) \r
726                                         return false;\r
727                                 if ((fractionDigitsFacet >=0) && (fractionDigits > fractionDigitsFacet)) \r
728                                         return false;\r
729                         }\r
730                         \r
731                         if ((maxInclusiveFacet != null) ||\r
732                                         (maxExclusiveFacet != null) ||\r
733                                         (minInclusiveFacet != null) ||\r
734                                         (minExclusiveFacet != null)) { \r
735                                 if (dt != null) {\r
736                                         object parsed;\r
737                                         try {\r
738                                                 parsed = dt.ParseValue (value, nt, null);\r
739                                         } catch (OverflowException ) {\r
740                                                 /* This appears to be what .NET does */\r
741                                                 return false ;\r
742                                         } catch (FormatException ) {\r
743                                                 /* This appears to be what .NET does */\r
744                                                 return false ;\r
745                                         }\r
746                                         \r
747                                         if (maxInclusiveFacet != null) {\r
748                                                 XsdOrdering result = dt.Compare (parsed, maxInclusiveFacet);\r
749                                                 if ((result != XsdOrdering.LessThan) &&\r
750                                                                 (result != XsdOrdering.Equal)) \r
751                                                         return false;\r
752                                         }\r
753                                         if (maxExclusiveFacet != null) {\r
754                                         \r
755                                                 XsdOrdering result = dt.Compare (parsed, maxExclusiveFacet);\r
756                                                 if (result != XsdOrdering.LessThan) \r
757                                                         return false;\r
758                                         }\r
759                                         if (minInclusiveFacet != null) {\r
760                                                 XsdOrdering result = dt.Compare (parsed, minInclusiveFacet);\r
761                                                 if ((result != XsdOrdering.GreaterThan) &&\r
762                                                                 (result != XsdOrdering.Equal)) \r
763                                                         return false;\r
764                                         }\r
765                                         if (minExclusiveFacet != null) {\r
766                                                 XsdOrdering result = dt.Compare (parsed, minExclusiveFacet);\r
767                                                 if (result != XsdOrdering.GreaterThan) \r
768                                                         return false;\r
769                                         }\r
770 \r
771                                 }\r
772                         }\r
773 \r
774                         // all passed\r
775                         return true;\r
776                 }\r
777 \r
778                 //<restriction \r
779                 //  base = QName \r
780                 //  id = ID \r
781                 //  {any attributes with non-schema namespace . . .}>\r
782                 //  Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*))\r
783                 //</restriction>\r
784                 internal static XmlSchemaSimpleTypeRestriction Read(XmlSchemaReader reader, ValidationEventHandler h)\r
785                 {\r
786                         XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction();\r
787                         reader.MoveToElement();\r
788 \r
789                         if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != xmlname)\r
790                         {\r
791                                 error(h,"Should not happen :1: XmlSchemaSimpleTypeRestriction.Read, name="+reader.Name,null);\r
792                                 reader.Skip();\r
793                                 return null;\r
794                         }\r
795 \r
796                         restriction.LineNumber = reader.LineNumber;\r
797                         restriction.LinePosition = reader.LinePosition;\r
798                         restriction.SourceUri = reader.BaseURI;\r
799 \r
800                         while(reader.MoveToNextAttribute())\r
801                         {\r
802                                 if(reader.Name == "id")\r
803                                 {\r
804                                         restriction.Id = reader.Value;\r
805                                 }\r
806                                 else if(reader.Name == "base")\r
807                                 {\r
808                                         Exception innerex;\r
809                                         restriction.baseTypeName = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex);\r
810                                         if(innerex != null)\r
811                                                 error(h, reader.Value + " is not a valid value for base attribute",innerex);\r
812                                 }\r
813                                 else if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)\r
814                                 {\r
815                                         error(h,reader.Name + " is not a valid attribute for restriction",null);\r
816                                 }\r
817                                 else\r
818                                 {\r
819                                         XmlSchemaUtil.ReadUnhandledAttribute(reader,restriction);\r
820                                 }\r
821                         }\r
822                         \r
823                         reader.MoveToElement();\r
824                         if(reader.IsEmptyElement)\r
825                                 return restriction;\r
826 \r
827                         //  Content: annotation?, simpleType?, (minExclusive |. .. | pattern)*\r
828                         int level = 1;\r
829                         while(reader.ReadNextElement())\r
830                         {\r
831                                 if(reader.NodeType == XmlNodeType.EndElement)\r
832                                 {\r
833                                         if(reader.LocalName != xmlname)\r
834                                                 error(h,"Should not happen :2: XmlSchemaSimpleTypeRestriction.Read, name="+reader.Name,null);\r
835                                         break;\r
836                                 }\r
837                                 if(level <= 1 && reader.LocalName == "annotation")\r
838                                 {\r
839                                         level = 2; //Only one annotation\r
840                                         XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);\r
841                                         if(annotation != null)\r
842                                                 restriction.Annotation = annotation;\r
843                                         continue;\r
844                                 }\r
845                                 if(level <= 2 && reader.LocalName == "simpleType")\r
846                                 {\r
847                                         level = 3;\r
848                                         XmlSchemaSimpleType stype = XmlSchemaSimpleType.Read(reader,h);\r
849                                         if(stype != null)\r
850                                                 restriction.baseType = stype;\r
851                                         continue;\r
852                                 }\r
853                                 if(level <= 3)\r
854                                 {\r
855                                         if(reader.LocalName == "minExclusive")\r
856                                         {\r
857                                                 level = 3;\r
858                                                 XmlSchemaMinExclusiveFacet minex = XmlSchemaMinExclusiveFacet.Read(reader,h);\r
859                                                 if(minex != null)\r
860                                                         restriction.facets.Add(minex);\r
861                                                 continue;\r
862                                         }\r
863                                         else if(reader.LocalName == "minInclusive")\r
864                                         {\r
865                                                 level = 3;\r
866                                                 XmlSchemaMinInclusiveFacet mini = XmlSchemaMinInclusiveFacet.Read(reader,h);\r
867                                                 if(mini != null)\r
868                                                         restriction.facets.Add(mini);\r
869                                                 continue;\r
870                                         }\r
871                                         else if(reader.LocalName == "maxExclusive")\r
872                                         {\r
873                                                 level = 3;\r
874                                                 XmlSchemaMaxExclusiveFacet maxex = XmlSchemaMaxExclusiveFacet.Read(reader,h);\r
875                                                 if(maxex != null)\r
876                                                         restriction.facets.Add(maxex);\r
877                                                 continue;\r
878                                         }\r
879                                         else if(reader.LocalName == "maxInclusive")\r
880                                         {\r
881                                                 level = 3;\r
882                                                 XmlSchemaMaxInclusiveFacet maxi = XmlSchemaMaxInclusiveFacet.Read(reader,h);\r
883                                                 if(maxi != null)\r
884                                                         restriction.facets.Add(maxi);\r
885                                                 continue;\r
886                                         }\r
887                                         else if(reader.LocalName == "totalDigits")\r
888                                         {\r
889                                                 level = 3;\r
890                                                 XmlSchemaTotalDigitsFacet total = XmlSchemaTotalDigitsFacet.Read(reader,h);\r
891                                                 if(total != null)\r
892                                                         restriction.facets.Add(total);\r
893                                                 continue;\r
894                                         }\r
895                                         else if(reader.LocalName == "fractionDigits")\r
896                                         {\r
897                                                 level = 3;\r
898                                                 XmlSchemaFractionDigitsFacet fraction = XmlSchemaFractionDigitsFacet.Read(reader,h);\r
899                                                 if(fraction != null)\r
900                                                         restriction.facets.Add(fraction);\r
901                                                 continue;\r
902                                         }\r
903                                         else if(reader.LocalName == "length")\r
904                                         {\r
905                                                 level = 3;\r
906                                                 XmlSchemaLengthFacet length = XmlSchemaLengthFacet.Read(reader,h);\r
907                                                 if(length != null)\r
908                                                         restriction.facets.Add(length);\r
909                                                 continue;\r
910                                         }\r
911                                         else if(reader.LocalName == "minLength")\r
912                                         {\r
913                                                 level = 3;\r
914                                                 XmlSchemaMinLengthFacet minlen = XmlSchemaMinLengthFacet.Read(reader,h);\r
915                                                 if(minlen != null)\r
916                                                         restriction.facets.Add(minlen);\r
917                                                 continue;\r
918                                         }\r
919                                         else if(reader.LocalName == "maxLength")\r
920                                         {\r
921                                                 level = 3;\r
922                                                 XmlSchemaMaxLengthFacet maxlen = XmlSchemaMaxLengthFacet.Read(reader,h);\r
923                                                 if(maxlen != null)\r
924                                                         restriction.facets.Add(maxlen);\r
925                                                 continue;\r
926                                         }\r
927                                         else if(reader.LocalName == "enumeration")\r
928                                         {\r
929                                                 level = 3;\r
930                                                 XmlSchemaEnumerationFacet enumeration = XmlSchemaEnumerationFacet.Read(reader,h);\r
931                                                 if(enumeration != null)\r
932                                                         restriction.facets.Add(enumeration);\r
933                                                 continue;\r
934                                         }\r
935                                         else if(reader.LocalName == "whiteSpace")\r
936                                         {\r
937                                                 level = 3;\r
938                                                 XmlSchemaWhiteSpaceFacet ws = XmlSchemaWhiteSpaceFacet.Read(reader,h);\r
939                                                 if(ws != null)\r
940                                                         restriction.facets.Add(ws);\r
941                                                 continue;\r
942                                         }\r
943                                         else if(reader.LocalName == "pattern")\r
944                                         {\r
945                                                 level = 3;\r
946                                                 XmlSchemaPatternFacet pattern = XmlSchemaPatternFacet.Read(reader,h);\r
947                                                 if(pattern != null)\r
948                                                         restriction.facets.Add(pattern);\r
949                                                 continue;\r
950                                         }\r
951                                 }\r
952                                 reader.RaiseInvalidElementError();\r
953                         }\r
954                         return restriction;\r
955                 }\r
956         }\r
957 }\r