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