blob: f7fc9823a92e273bcc9fdfd9b0da125ac51458a7 [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemastypes.c : implementation of the XML Schema Datatypes
3 * definition and validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20#include <libxml/valid.h>
21
22#include <libxml/xmlschemas.h>
23#include <libxml/schemasInternals.h>
24#include <libxml/xmlschemastypes.h>
25
Daniel Veillard070803b2002-05-03 07:29:38 +000026#ifdef HAVE_MATH_H
27#include <math.h>
28#endif
29
Daniel Veillard4255d502002-04-16 15:50:10 +000030#define DEBUG
31
32#define TODO \
33 xmlGenericError(xmlGenericErrorContext, \
34 "Unimplemented block at %s:%d\n", \
35 __FILE__, __LINE__);
36
37#define XML_SCHEMAS_NAMESPACE_NAME \
38 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
39
40typedef enum {
41 XML_SCHEMAS_UNKNOWN = 0,
42 XML_SCHEMAS_STRING,
43 XML_SCHEMAS_NMTOKEN,
44 XML_SCHEMAS_DECIMAL,
Daniel Veillard070803b2002-05-03 07:29:38 +000045 XML_SCHEMAS_TIME,
46 XML_SCHEMAS_GDAY,
47 XML_SCHEMAS_GMONTH,
48 XML_SCHEMAS_GMONTHDAY,
49 XML_SCHEMAS_GYEAR,
50 XML_SCHEMAS_GYEARMONTH,
51 XML_SCHEMAS_DATE,
52 XML_SCHEMAS_DATETIME,
53 XML_SCHEMAS_DURATION,
Daniel Veillard84d70a42002-09-16 10:51:38 +000054 XML_SCHEMAS_FLOAT,
55 XML_SCHEMAS_DOUBLE,
Daniel Veillard4255d502002-04-16 15:50:10 +000056 XML_SCHEMAS_,
57 XML_SCHEMAS_XXX
58} xmlSchemaValType;
59
60unsigned long powten[10] = {
61 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
62 100000000L, 1000000000L
63};
64
Daniel Veillard070803b2002-05-03 07:29:38 +000065/* Date value */
66typedef struct _xmlSchemaValDate xmlSchemaValDate;
67typedef xmlSchemaValDate *xmlSchemaValDatePtr;
68struct _xmlSchemaValDate {
69 long year;
70 unsigned int mon :4; /* 1 <= mon <= 12 */
71 unsigned int day :5; /* 1 <= day <= 31 */
72 unsigned int hour :5; /* 0 <= hour <= 23 */
73 unsigned int min :6; /* 0 <= min <= 59 */
74 double sec;
75 int tz_flag :1; /* is tzo explicitely set? */
76 int tzo :11; /* -1440 <= tzo <= 1440 */
77};
78
79/* Duration value */
80typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
81typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
82struct _xmlSchemaValDuration {
83 long mon; /* mon stores years also */
84 long day;
85 double sec; /* sec stores min and hour also */
86};
87
Daniel Veillard4255d502002-04-16 15:50:10 +000088typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
89typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
90struct _xmlSchemaValDecimal {
91 /* would use long long but not portable */
92 unsigned long base;
93 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000094 unsigned int sign:1;
Daniel Veillard4255d502002-04-16 15:50:10 +000095 int frac:7;
96 int total:8;
97};
98
99struct _xmlSchemaVal {
100 xmlSchemaValType type;
101 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000102 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000103 xmlSchemaValDate date;
104 xmlSchemaValDuration dur;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000105 float f;
106 double d;
Daniel Veillard4255d502002-04-16 15:50:10 +0000107 } value;
108};
109
110static int xmlSchemaTypesInitialized = 0;
111static xmlHashTablePtr xmlSchemaTypesBank = NULL;
112
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000113/*
114 * Basic types
115 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000116static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
117static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
118static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
119static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000120static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000121static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000122static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
123static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
124static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
125static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
126static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
127static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
128static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000129static xmlSchemaTypePtr xmlSchemaTypeNmtoken = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000130static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
131static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000132static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
133static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000134
135/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000136 * Derived types
137 */
138static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
139static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
141static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
142static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
143static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
144static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
145static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
149static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
150static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000151static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000152
153/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000154 * xmlSchemaInitBasicType:
155 * @name: the type name
156 *
157 * Initialize one default type
158 */
159static xmlSchemaTypePtr
160xmlSchemaInitBasicType(const char *name) {
161 xmlSchemaTypePtr ret;
162
163 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
164 if (ret == NULL) {
165 xmlGenericError(xmlGenericErrorContext,
166 "Could not initilize type %s: out of memory\n", name);
167 return(NULL);
168 }
169 memset(ret, 0, sizeof(xmlSchemaType));
170 ret->name = xmlStrdup((const xmlChar *)name);
171 ret->type = XML_SCHEMA_TYPE_BASIC;
172 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
173 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
174 XML_SCHEMAS_NAMESPACE_NAME, ret);
175 return(ret);
176}
177
178/*
179 * xmlSchemaInitTypes:
180 *
181 * Initialize the default XML Schemas type library
182 */
183void
184xmlSchemaInitTypes(void) {
185 if (xmlSchemaTypesInitialized != 0)
186 return;
187 xmlSchemaTypesBank = xmlHashCreate(40);
188
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000189 /*
190 * primitive datatypes
191 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000192 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string");
193 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType");
194 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType");
195 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal");
196 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date");
Daniel Veillard070803b2002-05-03 07:29:38 +0000197 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime");
198 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time");
199 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear");
200 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth");
201 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth");
202 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay");
203 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay");
204 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration");
Daniel Veillard4255d502002-04-16 15:50:10 +0000205 xmlSchemaTypeNmtoken = xmlSchemaInitBasicType("NMTOKEN");
Daniel Veillard84d70a42002-09-16 10:51:38 +0000206 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float");
207 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double");
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000208 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName");
209 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI");
Daniel Veillard4255d502002-04-16 15:50:10 +0000210
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000211 /*
212 * derived datatypes
213 */
214 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer");;
215 xmlSchemaTypeNonPositiveIntegerDef = xmlSchemaInitBasicType("nonPositiveInteger");;
216 xmlSchemaTypeNegativeIntegerDef = xmlSchemaInitBasicType("negativeInteger");;
217 xmlSchemaTypeLongDef = xmlSchemaInitBasicType("long");;
218 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int");;
219 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short");;
220 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte");;
221 xmlSchemaTypeNonNegativeIntegerDef = xmlSchemaInitBasicType("nonNegativeInteger");
222 xmlSchemaTypeUnsignedLongDef = xmlSchemaInitBasicType("unsignedLong");;
223 xmlSchemaTypeUnsignedIntDef = xmlSchemaInitBasicType("unsignedInt");;
224 xmlSchemaTypeUnsignedShortDef = xmlSchemaInitBasicType("insignedShort");;
225 xmlSchemaTypeUnsignedByteDef = xmlSchemaInitBasicType("unsignedByte");;
226 xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger");
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000227 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName");
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000228
Daniel Veillard4255d502002-04-16 15:50:10 +0000229 xmlSchemaTypesInitialized = 1;
230}
231
232/**
233 * xmlSchemaCleanupTypes:
234 *
235 * Cleanup the default XML Schemas type library
236 */
237void
238xmlSchemaCleanupTypes(void) {
239 if (xmlSchemaTypesInitialized == 0)
240 return;
241 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
242 xmlSchemaTypesInitialized = 0;
243}
244
245/**
246 * xmlSchemaNewValue:
247 * @type: the value type
248 *
249 * Allocate a new simple type value
250 *
251 * Returns a pointer to the new value or NULL in case of error
252 */
253static xmlSchemaValPtr
254xmlSchemaNewValue(xmlSchemaValType type) {
255 xmlSchemaValPtr value;
256
257 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
258 if (value == NULL) {
259 return(NULL);
260 }
261 memset(value, 0, sizeof(xmlSchemaVal));
262 value->type = type;
263 return(value);
264}
265
266/**
267 * xmlSchemaFreeValue:
268 * @value: the value to free
269 *
270 * Cleanup the default XML Schemas type library
271 */
272void
273xmlSchemaFreeValue(xmlSchemaValPtr value) {
274 if (value == NULL)
275 return;
276 xmlFree(value);
277}
278
279/**
280 * xmlSchemaGetPredefinedType:
281 * @name: the type name
282 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
283 *
284 * Lookup a type in the default XML Schemas type library
285 *
286 * Returns the type if found, NULL otherwise
287 */
288xmlSchemaTypePtr
289xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
290 if (xmlSchemaTypesInitialized == 0)
291 xmlSchemaInitTypes();
292 if (name == NULL)
293 return(NULL);
294 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
295}
Daniel Veillard070803b2002-05-03 07:29:38 +0000296
297/****************************************************************
298 * *
299 * Convenience macros and functions *
300 * *
301 ****************************************************************/
302
303#define IS_TZO_CHAR(c) \
304 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
305
306#define VALID_YEAR(yr) (yr != 0)
307#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
308/* VALID_DAY should only be used when month is unknown */
309#define VALID_DAY(day) ((day >= 1) && (day <= 31))
310#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
311#define VALID_MIN(min) ((min >= 0) && (min <= 59))
312#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
313#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
314#define IS_LEAP(y) \
315 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
316
317static const long daysInMonth[12] =
318 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
319static const long daysInMonthLeap[12] =
320 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
321
Daniel Veillard5a872412002-05-22 06:40:27 +0000322#define MAX_DAYINMONTH(yr,mon) \
323 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
324
Daniel Veillard070803b2002-05-03 07:29:38 +0000325#define VALID_MDAY(dt) \
326 (IS_LEAP(dt->year) ? \
327 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
328 (dt->day <= daysInMonth[dt->mon - 1]))
329
330#define VALID_DATE(dt) \
331 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
332
333#define VALID_TIME(dt) \
334 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
335 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
336
337#define VALID_DATETIME(dt) \
338 (VALID_DATE(dt) && VALID_TIME(dt))
339
340#define SECS_PER_MIN (60)
341#define SECS_PER_HOUR (60 * SECS_PER_MIN)
342#define SECS_PER_DAY (24 * SECS_PER_HOUR)
343
Daniel Veillard5a872412002-05-22 06:40:27 +0000344static const long dayInYearByMonth[12] =
345 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
346static const long dayInLeapYearByMonth[12] =
347 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
348
349#define DAY_IN_YEAR(day, month, year) \
350 ((IS_LEAP(year) ? \
351 dayInLeapYearByMonth[month - 1] : \
352 dayInYearByMonth[month - 1]) + day)
353
354#ifdef DEBUG
355#define DEBUG_DATE(dt) \
356 xmlGenericError(xmlGenericErrorContext, \
357 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
358 dt->type,dt->value.date.year,dt->value.date.mon, \
359 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
360 dt->value.date.sec); \
361 if (dt->value.date.tz_flag) \
362 if (dt->value.date.tzo != 0) \
363 xmlGenericError(xmlGenericErrorContext, \
364 "%+05d\n",dt->value.date.tzo); \
365 else \
366 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
367 else \
368 xmlGenericError(xmlGenericErrorContext,"\n")
369#else
370#define DEBUG_DATE(dt)
371#endif
372
Daniel Veillard070803b2002-05-03 07:29:38 +0000373/**
374 * _xmlSchemaParseGYear:
375 * @dt: pointer to a date structure
376 * @str: pointer to the string to analyze
377 *
378 * Parses a xs:gYear without time zone and fills in the appropriate
379 * field of the @dt structure. @str is updated to point just after the
380 * xs:gYear. It is supposed that @dt->year is big enough to contain
381 * the year.
382 *
383 * Returns 0 or the error code
384 */
385static int
386_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
387 const xmlChar *cur = *str, *firstChar;
388 int isneg = 0, digcnt = 0;
389
390 if (((*cur < '0') || (*cur > '9')) &&
391 (*cur != '-') && (*cur != '+'))
392 return -1;
393
394 if (*cur == '-') {
395 isneg = 1;
396 cur++;
397 }
398
399 firstChar = cur;
400
401 while ((*cur >= '0') && (*cur <= '9')) {
402 dt->year = dt->year * 10 + (*cur - '0');
403 cur++;
404 digcnt++;
405 }
406
407 /* year must be at least 4 digits (CCYY); over 4
408 * digits cannot have a leading zero. */
409 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
410 return 1;
411
412 if (isneg)
413 dt->year = - dt->year;
414
415 if (!VALID_YEAR(dt->year))
416 return 2;
417
418 *str = cur;
419 return 0;
420}
421
422/**
423 * PARSE_2_DIGITS:
424 * @num: the integer to fill in
425 * @cur: an #xmlChar *
426 * @invalid: an integer
427 *
428 * Parses a 2-digits integer and updates @num with the value. @cur is
429 * updated to point just after the integer.
430 * In case of error, @invalid is set to %TRUE, values of @num and
431 * @cur are undefined.
432 */
433#define PARSE_2_DIGITS(num, cur, invalid) \
434 if ((cur[0] < '0') || (cur[0] > '9') || \
435 (cur[1] < '0') || (cur[1] > '9')) \
436 invalid = 1; \
437 else \
438 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
439 cur += 2;
440
441/**
442 * PARSE_FLOAT:
443 * @num: the double to fill in
444 * @cur: an #xmlChar *
445 * @invalid: an integer
446 *
447 * Parses a float and updates @num with the value. @cur is
448 * updated to point just after the float. The float must have a
449 * 2-digits integer part and may or may not have a decimal part.
450 * In case of error, @invalid is set to %TRUE, values of @num and
451 * @cur are undefined.
452 */
453#define PARSE_FLOAT(num, cur, invalid) \
454 PARSE_2_DIGITS(num, cur, invalid); \
455 if (!invalid && (*cur == '.')) { \
456 double mult = 1; \
457 cur++; \
458 if ((*cur < '0') || (*cur > '9')) \
459 invalid = 1; \
460 while ((*cur >= '0') && (*cur <= '9')) { \
461 mult /= 10; \
462 num += (*cur - '0') * mult; \
463 cur++; \
464 } \
465 }
466
467/**
468 * _xmlSchemaParseGMonth:
469 * @dt: pointer to a date structure
470 * @str: pointer to the string to analyze
471 *
472 * Parses a xs:gMonth without time zone and fills in the appropriate
473 * field of the @dt structure. @str is updated to point just after the
474 * xs:gMonth.
475 *
476 * Returns 0 or the error code
477 */
478static int
479_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
480 const xmlChar *cur = *str;
481 int ret = 0;
482
483 PARSE_2_DIGITS(dt->mon, cur, ret);
484 if (ret != 0)
485 return ret;
486
487 if (!VALID_MONTH(dt->mon))
488 return 2;
489
490 *str = cur;
491 return 0;
492}
493
494/**
495 * _xmlSchemaParseGDay:
496 * @dt: pointer to a date structure
497 * @str: pointer to the string to analyze
498 *
499 * Parses a xs:gDay without time zone and fills in the appropriate
500 * field of the @dt structure. @str is updated to point just after the
501 * xs:gDay.
502 *
503 * Returns 0 or the error code
504 */
505static int
506_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
507 const xmlChar *cur = *str;
508 int ret = 0;
509
510 PARSE_2_DIGITS(dt->day, cur, ret);
511 if (ret != 0)
512 return ret;
513
514 if (!VALID_DAY(dt->day))
515 return 2;
516
517 *str = cur;
518 return 0;
519}
520
521/**
522 * _xmlSchemaParseTime:
523 * @dt: pointer to a date structure
524 * @str: pointer to the string to analyze
525 *
526 * Parses a xs:time without time zone and fills in the appropriate
527 * fields of the @dt structure. @str is updated to point just after the
528 * xs:time.
529 * In case of error, values of @dt fields are undefined.
530 *
531 * Returns 0 or the error code
532 */
533static int
534_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
535 const xmlChar *cur = *str;
536 unsigned int hour = 0; /* use temp var in case str is not xs:time */
537 int ret = 0;
538
539 PARSE_2_DIGITS(hour, cur, ret);
540 if (ret != 0)
541 return ret;
542
543 if (*cur != ':')
544 return 1;
545 cur++;
546
547 /* the ':' insures this string is xs:time */
548 dt->hour = hour;
549
550 PARSE_2_DIGITS(dt->min, cur, ret);
551 if (ret != 0)
552 return ret;
553
554 if (*cur != ':')
555 return 1;
556 cur++;
557
558 PARSE_FLOAT(dt->sec, cur, ret);
559 if (ret != 0)
560 return ret;
561
562 if (!VALID_TIME(dt))
563 return 2;
564
565 *str = cur;
566 return 0;
567}
568
569/**
570 * _xmlSchemaParseTimeZone:
571 * @dt: pointer to a date structure
572 * @str: pointer to the string to analyze
573 *
574 * Parses a time zone without time zone and fills in the appropriate
575 * field of the @dt structure. @str is updated to point just after the
576 * time zone.
577 *
578 * Returns 0 or the error code
579 */
580static int
581_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
582 const xmlChar *cur = *str;
583 int ret = 0;
584
585 if (str == NULL)
586 return -1;
587
588 switch (*cur) {
589 case 0:
590 dt->tz_flag = 0;
591 dt->tzo = 0;
592 break;
593
594 case 'Z':
595 dt->tz_flag = 1;
596 dt->tzo = 0;
597 cur++;
598 break;
599
600 case '+':
601 case '-': {
602 int isneg = 0, tmp = 0;
603 isneg = (*cur == '-');
604
605 cur++;
606
607 PARSE_2_DIGITS(tmp, cur, ret);
608 if (ret != 0)
609 return ret;
610 if (!VALID_HOUR(tmp))
611 return 2;
612
613 if (*cur != ':')
614 return 1;
615 cur++;
616
617 dt->tzo = tmp * 60;
618
619 PARSE_2_DIGITS(tmp, cur, ret);
620 if (ret != 0)
621 return ret;
622 if (!VALID_MIN(tmp))
623 return 2;
624
625 dt->tzo += tmp;
626 if (isneg)
627 dt->tzo = - dt->tzo;
628
629 if (!VALID_TZO(dt->tzo))
630 return 2;
631
Daniel Veillard5a872412002-05-22 06:40:27 +0000632 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000633 break;
634 }
635 default:
636 return 1;
637 }
638
639 *str = cur;
640 return 0;
641}
642
643/****************************************************************
644 * *
645 * XML Schema Dates/Times Datatypes Handling *
646 * *
647 ****************************************************************/
648
649/**
650 * PARSE_DIGITS:
651 * @num: the integer to fill in
652 * @cur: an #xmlChar *
653 * @num_type: an integer flag
654 *
655 * Parses a digits integer and updates @num with the value. @cur is
656 * updated to point just after the integer.
657 * In case of error, @num_type is set to -1, values of @num and
658 * @cur are undefined.
659 */
660#define PARSE_DIGITS(num, cur, num_type) \
661 if ((*cur < '0') || (*cur > '9')) \
662 num_type = -1; \
663 else \
664 while ((*cur >= '0') && (*cur <= '9')) { \
665 num = num * 10 + (*cur - '0'); \
666 cur++; \
667 }
668
669/**
670 * PARSE_NUM:
671 * @num: the double to fill in
672 * @cur: an #xmlChar *
673 * @num_type: an integer flag
674 *
675 * Parses a float or integer and updates @num with the value. @cur is
676 * updated to point just after the number. If the number is a float,
677 * then it must have an integer part and a decimal part; @num_type will
678 * be set to 1. If there is no decimal part, @num_type is set to zero.
679 * In case of error, @num_type is set to -1, values of @num and
680 * @cur are undefined.
681 */
682#define PARSE_NUM(num, cur, num_type) \
683 num = 0; \
684 PARSE_DIGITS(num, cur, num_type); \
685 if (!num_type && (*cur == '.')) { \
686 double mult = 1; \
687 cur++; \
688 if ((*cur < '0') || (*cur > '9')) \
689 num_type = -1; \
690 else \
691 num_type = 1; \
692 while ((*cur >= '0') && (*cur <= '9')) { \
693 mult /= 10; \
694 num += (*cur - '0') * mult; \
695 cur++; \
696 } \
697 }
698
699/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000700 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000701 * @type: the predefined type
702 * @dateTime: string to analyze
703 * @val: the return computed value
704 *
705 * Check that @dateTime conforms to the lexical space of one of the date types.
706 * if true a value is computed and returned in @val.
707 *
708 * Returns 0 if this validates, a positive error code number otherwise
709 * and -1 in case of internal or API error.
710 */
711static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000712xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000713 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000714 xmlSchemaValPtr dt;
715 int ret;
716 const xmlChar *cur = dateTime;
717
718#define RETURN_TYPE_IF_VALID(t) \
719 if (IS_TZO_CHAR(*cur)) { \
720 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
721 if (ret == 0) { \
722 if (*cur != 0) \
723 goto error; \
724 dt->type = t; \
725 if (val != NULL) \
726 *val = dt; \
727 return 0; \
728 } \
729 }
730
731 if (dateTime == NULL)
732 return -1;
733
734 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
735 return 1;
736
737 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
738 if (dt == NULL)
739 return -1;
740
741 if ((cur[0] == '-') && (cur[1] == '-')) {
742 /*
743 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
744 * xs:gDay)
745 */
746 cur += 2;
747
748 /* is it an xs:gDay? */
749 if (*cur == '-') {
750 ++cur;
751 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
752 if (ret != 0)
753 goto error;
754
755 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
756
757 goto error;
758 }
759
760 /*
761 * it should be an xs:gMonthDay or xs:gMonth
762 */
763 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
764 if (ret != 0)
765 goto error;
766
767 if (*cur != '-')
768 goto error;
769 cur++;
770
771 /* is it an xs:gMonth? */
772 if (*cur == '-') {
773 cur++;
774 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
775 goto error;
776 }
777
778 /* it should be an xs:gMonthDay */
779 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
780 if (ret != 0)
781 goto error;
782
783 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
784
785 goto error;
786 }
787
788 /*
789 * It's a right-truncated date or an xs:time.
790 * Try to parse an xs:time then fallback on right-truncated dates.
791 */
792 if ((*cur >= '0') && (*cur <= '9')) {
793 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
794 if (ret == 0) {
795 /* it's an xs:time */
796 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
797 }
798 }
799
800 /* fallback on date parsing */
801 cur = dateTime;
802
803 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
804 if (ret != 0)
805 goto error;
806
807 /* is it an xs:gYear? */
808 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
809
810 if (*cur != '-')
811 goto error;
812 cur++;
813
814 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
815 if (ret != 0)
816 goto error;
817
818 /* is it an xs:gYearMonth? */
819 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
820
821 if (*cur != '-')
822 goto error;
823 cur++;
824
825 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
826 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
827 goto error;
828
829 /* is it an xs:date? */
830 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
831
832 if (*cur != 'T')
833 goto error;
834 cur++;
835
836 /* it should be an xs:dateTime */
837 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
838 if (ret != 0)
839 goto error;
840
841 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
842 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
843 goto error;
844
845 dt->type = XML_SCHEMAS_DATETIME;
846
847 if (val != NULL)
848 *val = dt;
849
850 return 0;
851
852error:
853 if (dt != NULL)
854 xmlSchemaFreeValue(dt);
855 return 1;
856}
857
858/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000859 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000860 * @type: the predefined type
861 * @duration: string to analyze
862 * @val: the return computed value
863 *
864 * Check that @duration conforms to the lexical space of the duration type.
865 * if true a value is computed and returned in @val.
866 *
867 * Returns 0 if this validates, a positive error code number otherwise
868 * and -1 in case of internal or API error.
869 */
870static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000871xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000872 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000873 const xmlChar *cur = duration;
874 xmlSchemaValPtr dur;
875 int isneg = 0;
876 unsigned int seq = 0;
877
878 if (duration == NULL)
879 return -1;
880
881 if (*cur == '-') {
882 isneg = 1;
883 cur++;
884 }
885
886 /* duration must start with 'P' (after sign) */
887 if (*cur++ != 'P')
888 return 1;
889
890 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
891 if (dur == NULL)
892 return -1;
893
894 while (*cur != 0) {
895 double num;
896 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
897 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
898 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
899
900 /* input string should be empty or invalid date/time item */
901 if (seq >= sizeof(desig))
902 goto error;
903
904 /* T designator must be present for time items */
905 if (*cur == 'T') {
906 if (seq <= 3) {
907 seq = 3;
908 cur++;
909 } else
910 return 1;
911 } else if (seq == 3)
912 goto error;
913
914 /* parse the number portion of the item */
915 PARSE_NUM(num, cur, num_type);
916
917 if ((num_type == -1) || (*cur == 0))
918 goto error;
919
920 /* update duration based on item type */
921 while (seq < sizeof(desig)) {
922 if (*cur == desig[seq]) {
923
924 /* verify numeric type; only seconds can be float */
925 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
926 goto error;
927
928 switch (seq) {
929 case 0:
930 dur->value.dur.mon = (long)num * 12;
931 break;
932 case 1:
933 dur->value.dur.mon += (long)num;
934 break;
935 default:
936 /* convert to seconds using multiplier */
937 dur->value.dur.sec += num * multi[seq];
938 seq++;
939 break;
940 }
941
942 break; /* exit loop */
943 }
944 /* no date designators found? */
945 if (++seq == 3)
946 goto error;
947 }
948 cur++;
949 }
950
951 if (isneg) {
952 dur->value.dur.mon = -dur->value.dur.mon;
953 dur->value.dur.day = -dur->value.dur.day;
954 dur->value.dur.sec = -dur->value.dur.sec;
955 }
956
957 if (val != NULL)
958 *val = dur;
959
960 return 0;
961
962error:
963 if (dur != NULL)
964 xmlSchemaFreeValue(dur);
965 return 1;
966}
967
Daniel Veillard4255d502002-04-16 15:50:10 +0000968/**
969 * xmlSchemaValidatePredefinedType:
970 * @type: the predefined type
971 * @value: the value to check
972 * @val: the return computed value
973 *
974 * Check that a value conforms to the lexical space of the predefined type.
975 * if true a value is computed and returned in @val.
976 *
977 * Returns 0 if this validates, a positive error code number otherwise
978 * and -1 in case of internal or API error.
979 */
980int
981xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
982 xmlSchemaValPtr *val) {
983 xmlSchemaValPtr v;
984
985 if (xmlSchemaTypesInitialized == 0)
986 return(-1);
987 if (type == NULL)
988 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +0000989
Daniel Veillard4255d502002-04-16 15:50:10 +0000990 if (val != NULL)
991 *val = NULL;
992 if (type == xmlSchemaTypeStringDef) {
993 return(0);
994 } else if (type == xmlSchemaTypeAnyTypeDef) {
995 return(0);
996 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
997 return(0);
998 } else if (type == xmlSchemaTypeNmtoken) {
999 if (xmlValidateNmtokenValue(value))
1000 return(0);
1001 return(1);
1002 } else if (type == xmlSchemaTypeDecimalDef) {
1003 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001004 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001005 unsigned long base = 0;
1006 if (cur == NULL)
1007 return(1);
1008 if (*cur == '+')
1009 cur++;
1010 else if (*cur == '-') {
1011 neg = 1;
1012 cur++;
1013 }
1014 tmp = cur;
1015 while ((*cur >= '0') && (*cur <= '9')) {
1016 base = base * 10 + (*cur - '0');
1017 cur++;
1018 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001019 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001020 if (*cur == '.') {
1021 cur++;
1022 tmp = cur;
1023 while ((*cur >= '0') && (*cur <= '9')) {
1024 base = base * 10 + (*cur - '0');
1025 cur++;
1026 }
1027 frac = cur - tmp;
1028 }
1029 if (*cur != 0)
1030 return(1);
1031 if (val != NULL) {
1032 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1033 if (v != NULL) {
1034 v->value.decimal.base = base;
1035 v->value.decimal.sign = neg;
1036 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001037 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001038 *val = v;
1039 }
1040 }
1041 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001042 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001043 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001044 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1045 (type == xmlSchemaTypeTimeDef) ||
1046 (type == xmlSchemaTypeDateDef) ||
1047 (type == xmlSchemaTypeGYearDef) ||
1048 (type == xmlSchemaTypeGYearMonthDef) ||
1049 (type == xmlSchemaTypeGMonthDef) ||
1050 (type == xmlSchemaTypeGMonthDayDef) ||
1051 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001052 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001053 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1054 const xmlChar *cur = value;
1055 unsigned long base = 0;
1056 int total = 0;
1057 if (cur == NULL)
1058 return(1);
1059 if (*cur == '+')
1060 cur++;
1061 while ((*cur >= '0') && (*cur <= '9')) {
1062 base = base * 10 + (*cur - '0');
1063 total++;
1064 cur++;
1065 }
1066 if (*cur != 0)
1067 return(1);
1068 if (val != NULL) {
1069 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1070 if (v != NULL) {
1071 v->value.decimal.base = base;
1072 v->value.decimal.sign = 0;
1073 v->value.decimal.frac = 0;
1074 v->value.decimal.total = total;
1075 *val = v;
1076 }
1077 }
1078 return(0);
1079 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1080 const xmlChar *cur = value;
1081 unsigned long base = 0;
1082 int total = 0;
1083 int sign = 0;
1084 if (cur == NULL)
1085 return(1);
1086 if (*cur == '-') {
1087 sign = 1;
1088 cur++;
1089 } else if (*cur == '+')
1090 cur++;
1091 while ((*cur >= '0') && (*cur <= '9')) {
1092 base = base * 10 + (*cur - '0');
1093 total++;
1094 cur++;
1095 }
1096 if (*cur != 0)
1097 return(1);
1098 if ((sign == 1) && (base != 0))
1099 return(1);
1100 if (val != NULL) {
1101 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1102 if (v != NULL) {
1103 v->value.decimal.base = base;
1104 v->value.decimal.sign = 0;
1105 v->value.decimal.frac = 0;
1106 v->value.decimal.total = total;
1107 *val = v;
1108 }
1109 }
1110 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001111 } else if (type == xmlSchemaTypeFloatDef) {
1112 const xmlChar *cur = value, *tmp;
1113 int frac = 0, len, neg = 0;
1114 unsigned long base = 0;
1115 if (cur == NULL)
1116 return(1);
1117 if (*cur == '+')
1118 cur++;
1119 else if (*cur == '-') {
1120 neg = 1;
1121 cur++;
1122 }
1123 tmp = cur;
1124 while ((*cur >= '0') && (*cur <= '9')) {
1125 base = base * 10 + (*cur - '0');
1126 cur++;
1127 }
1128 len = cur - tmp;
1129 if (*cur == '.') {
1130 cur++;
1131 tmp = cur;
1132 while ((*cur >= '0') && (*cur <= '9')) {
1133 base = base * 10 + (*cur - '0');
1134 cur++;
1135 }
1136 frac = cur - tmp;
1137 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001138 TODO
1139 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001140 } else if (type == xmlSchemaTypeDoubleDef) {
Daniel Veillardb5c05732002-09-20 13:36:25 +00001141 TODO
1142 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001143 } else {
1144 TODO
1145 return(0);
1146 }
1147}
1148
1149/**
1150 * xmlSchemaCompareDecimals:
1151 * @x: a first decimal value
1152 * @y: a second decimal value
1153 *
1154 * Compare 2 decimals
1155 *
1156 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1157 */
1158static int
1159xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1160{
1161 xmlSchemaValPtr swp;
1162 int order = 1;
1163 unsigned long tmp;
1164
1165 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1166 order = -1;
1167 else if (x->value.decimal.sign)
1168 return (-1);
1169 else if (y->value.decimal.sign)
1170 return (1);
1171 if (x->value.decimal.frac == y->value.decimal.frac) {
1172 if (x->value.decimal.base < y->value.decimal.base)
1173 return (-1);
1174 return (x->value.decimal.base > y->value.decimal.base);
1175 }
1176 if (y->value.decimal.frac > x->value.decimal.frac) {
1177 swp = y;
1178 y = x;
1179 x = swp;
1180 order = -order;
1181 }
1182 tmp =
1183 x->value.decimal.base / powten[x->value.decimal.frac -
1184 y->value.decimal.frac];
1185 if (tmp > y->value.decimal.base)
1186 return (order);
1187 if (tmp < y->value.decimal.base)
1188 return (-order);
1189 tmp =
1190 y->value.decimal.base * powten[x->value.decimal.frac -
1191 y->value.decimal.frac];
1192 if (x->value.decimal.base < tmp)
1193 return (-order);
1194 if (x->value.decimal.base == tmp)
1195 return (0);
1196 return (order);
1197}
1198
1199/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001200 * xmlSchemaCompareDurations:
1201 * @x: a first duration value
1202 * @y: a second duration value
1203 *
1204 * Compare 2 durations
1205 *
1206 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1207 * case of error
1208 */
1209static int
1210xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1211{
1212 long carry, mon, day;
1213 double sec;
1214 long xmon, xday, myear, lyear, minday, maxday;
1215 static const long dayRange [2][12] = {
1216 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1217 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1218
1219 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001220 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001221
1222 /* months */
1223 mon = x->value.dur.mon - y->value.dur.mon;
1224
1225 /* seconds */
1226 sec = x->value.dur.sec - y->value.dur.sec;
1227 carry = (long)sec / SECS_PER_DAY;
1228 sec -= (double)(carry * SECS_PER_DAY);
1229
1230 /* days */
1231 day = x->value.dur.day - y->value.dur.day + carry;
1232
1233 /* easy test */
1234 if (mon == 0) {
1235 if (day == 0)
1236 if (sec == 0.0)
1237 return 0;
1238 else if (sec < 0.0)
1239 return -1;
1240 else
1241 return 1;
1242 else if (day < 0)
1243 return -1;
1244 else
1245 return 1;
1246 }
1247
1248 if (mon > 0) {
1249 if ((day >= 0) && (sec >= 0.0))
1250 return 1;
1251 else {
1252 xmon = mon;
1253 xday = -day;
1254 }
1255 } else if ((day <= 0) && (sec <= 0.0)) {
1256 return -1;
1257 } else {
1258 xmon = -mon;
1259 xday = day;
1260 }
1261
1262 myear = xmon / 12;
1263 lyear = myear / 4;
1264 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1265 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1266
1267 xmon = xmon % 12;
1268 minday += dayRange[0][xmon];
1269 maxday += dayRange[1][xmon];
1270
1271 if (maxday < xday)
1272 return 1;
1273 else if (minday > xday)
1274 return -1;
1275
1276 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001277 return 2;
1278}
1279
1280/*
1281 * macros for adding date/times and durations
1282 */
1283#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1284#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1285#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1286#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1287
1288/**
1289 * _xmlSchemaDateAdd:
1290 * @dt: an #xmlSchemaValPtr
1291 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1292 *
1293 * Compute a new date/time from @dt and @dur. This function assumes @dt
1294 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1295 * or #XML_SCHEMAS_GYEAR.
1296 *
1297 * Returns date/time pointer or NULL.
1298 */
1299static xmlSchemaValPtr
1300_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1301{
1302 xmlSchemaValPtr ret;
1303 long carry, tempdays, temp;
1304 xmlSchemaValDatePtr r, d;
1305 xmlSchemaValDurationPtr u;
1306
1307 if ((dt == NULL) || (dur == NULL))
1308 return NULL;
1309
1310 ret = xmlSchemaNewValue(dt->type);
1311 if (ret == NULL)
1312 return NULL;
1313
1314 r = &(ret->value.date);
1315 d = &(dt->value.date);
1316 u = &(dur->value.dur);
1317
1318 /* normalization */
1319 if (d->mon == 0)
1320 d->mon = 1;
1321
1322 /* normalize for time zone offset */
1323 u->sec -= (d->tzo * 60);
1324 d->tzo = 0;
1325
1326 /* normalization */
1327 if (d->day == 0)
1328 d->day = 1;
1329
1330 /* month */
1331 carry = d->mon + u->mon;
1332 r->mon = MODULO_RANGE(carry, 1, 13);
1333 carry = FQUOTIENT_RANGE(carry, 1, 13);
1334
1335 /* year (may be modified later) */
1336 r->year = d->year + carry;
1337 if (r->year == 0) {
1338 if (d->year > 0)
1339 r->year--;
1340 else
1341 r->year++;
1342 }
1343
1344 /* time zone */
1345 r->tzo = d->tzo;
1346 r->tz_flag = d->tz_flag;
1347
1348 /* seconds */
1349 r->sec = d->sec + u->sec;
1350 carry = FQUOTIENT((long)r->sec, 60);
1351 if (r->sec != 0.0) {
1352 r->sec = MODULO(r->sec, 60.0);
1353 }
1354
1355 /* minute */
1356 carry += d->min;
1357 r->min = MODULO(carry, 60);
1358 carry = FQUOTIENT(carry, 60);
1359
1360 /* hours */
1361 carry += d->hour;
1362 r->hour = MODULO(carry, 24);
1363 carry = FQUOTIENT(carry, 24);
1364
1365 /*
1366 * days
1367 * Note we use tempdays because the temporary values may need more
1368 * than 5 bits
1369 */
1370 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1371 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1372 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1373 else if (d->day < 1)
1374 tempdays = 1;
1375 else
1376 tempdays = d->day;
1377
1378 tempdays += u->day + carry;
1379
1380 while (1) {
1381 if (tempdays < 1) {
1382 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1383 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1384 if (tyr == 0)
1385 tyr--;
1386 tempdays += MAX_DAYINMONTH(tyr, tmon);
1387 carry = -1;
1388 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1389 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1390 carry = 1;
1391 } else
1392 break;
1393
1394 temp = r->mon + carry;
1395 r->mon = MODULO_RANGE(temp, 1, 13);
1396 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1397 if (r->year == 0) {
1398 if (temp < 1)
1399 r->year--;
1400 else
1401 r->year++;
1402 }
1403 }
1404
1405 r->day = tempdays;
1406
1407 /*
1408 * adjust the date/time type to the date values
1409 */
1410 if (ret->type != XML_SCHEMAS_DATETIME) {
1411 if ((r->hour) || (r->min) || (r->sec))
1412 ret->type = XML_SCHEMAS_DATETIME;
1413 else if (ret->type != XML_SCHEMAS_DATE) {
1414 if ((r->mon != 1) && (r->day != 1))
1415 ret->type = XML_SCHEMAS_DATE;
1416 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1417 ret->type = XML_SCHEMAS_GYEARMONTH;
1418 }
1419 }
1420
1421 return ret;
1422}
1423
1424/**
1425 * xmlSchemaDupVal:
1426 * @v: value to duplicate
1427 *
1428 * returns a duplicated value.
1429 */
1430static xmlSchemaValPtr
1431xmlSchemaDupVal (xmlSchemaValPtr v)
1432{
1433 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1434 if (ret == NULL)
1435 return ret;
1436
1437 memcpy(ret, v, sizeof(xmlSchemaVal));
1438 return ret;
1439}
1440
1441/**
1442 * xmlSchemaDateNormalize:
1443 * @dt: an #xmlSchemaValPtr
1444 *
1445 * Normalize @dt to GMT time.
1446 *
1447 */
1448static xmlSchemaValPtr
1449xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1450{
1451 xmlSchemaValPtr dur, ret;
1452
1453 if (dt == NULL)
1454 return NULL;
1455
1456 if (((dt->type != XML_SCHEMAS_TIME) &&
1457 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1458 return xmlSchemaDupVal(dt);
1459
1460 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1461 if (dur == NULL)
1462 return NULL;
1463
1464 dur->value.date.sec -= offset;
1465
1466 ret = _xmlSchemaDateAdd(dt, dur);
1467 if (ret == NULL)
1468 return NULL;
1469
1470 xmlSchemaFreeValue(dur);
1471
1472 /* ret->value.date.tzo = 0; */
1473 return ret;
1474}
1475
1476/**
1477 * _xmlSchemaDateCastYMToDays:
1478 * @dt: an #xmlSchemaValPtr
1479 *
1480 * Convert mon and year of @dt to total number of days. Take the
1481 * number of years since (or before) 1 AD and add the number of leap
1482 * years. This is a function because negative
1483 * years must be handled a little differently and there is no zero year.
1484 *
1485 * Returns number of days.
1486 */
1487static long
1488_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
1489{
1490 long ret;
1491
1492 if (dt->value.date.year < 0)
1493 ret = (dt->value.date.year * 365) +
1494 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1495 ((dt->value.date.year+1)/400)) +
1496 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1497 else
1498 ret = ((dt->value.date.year-1) * 365) +
1499 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1500 ((dt->value.date.year-1)/400)) +
1501 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1502
1503 return ret;
1504}
1505
1506/**
1507 * TIME_TO_NUMBER:
1508 * @dt: an #xmlSchemaValPtr
1509 *
1510 * Calculates the number of seconds in the time portion of @dt.
1511 *
1512 * Returns seconds.
1513 */
1514#define TIME_TO_NUMBER(dt) \
1515 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
1516 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
1517
1518/**
1519 * xmlSchemaCompareDates:
1520 * @x: a first date/time value
1521 * @y: a second date/time value
1522 *
1523 * Compare 2 date/times
1524 *
1525 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1526 * case of error
1527 */
1528static int
1529xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
1530{
1531 unsigned char xmask, ymask, xor_mask, and_mask;
1532 xmlSchemaValPtr p1, p2, q1, q2;
1533 long p1d, p2d, q1d, q2d;
1534
1535 if ((x == NULL) || (y == NULL))
1536 return -2;
1537
1538 if (x->value.date.tz_flag) {
1539
1540 if (!y->value.date.tz_flag) {
1541 p1 = xmlSchemaDateNormalize(x, 0);
1542 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1543 /* normalize y + 14:00 */
1544 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
1545
1546 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001547 if (p1d < q1d) {
1548 xmlSchemaFreeValue(p1);
1549 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001550 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001551 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001552 double sec;
1553
1554 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001555 if (sec < 0.0) {
1556 xmlSchemaFreeValue(p1);
1557 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001558 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001559 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001560 /* normalize y - 14:00 */
1561 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
1562 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001563 xmlSchemaFreeValue(p1);
1564 xmlSchemaFreeValue(q1);
1565 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001566 if (p1d > q2d)
1567 return 1;
1568 else if (p1d == q2d) {
1569 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
1570 if (sec > 0.0)
1571 return 1;
1572 else
1573 return 2; /* indeterminate */
1574 }
1575 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001576 } else {
1577 xmlSchemaFreeValue(p1);
1578 xmlSchemaFreeValue(q1);
1579 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001580 }
1581 } else if (y->value.date.tz_flag) {
1582 q1 = xmlSchemaDateNormalize(y, 0);
1583 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1584
1585 /* normalize x - 14:00 */
1586 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
1587 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1588
Daniel Veillardfdc91562002-07-01 21:52:03 +00001589 if (p1d < q1d) {
1590 xmlSchemaFreeValue(p1);
1591 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001592 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001593 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001594 double sec;
1595
1596 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001597 if (sec < 0.0) {
1598 xmlSchemaFreeValue(p1);
1599 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001600 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001601 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001602 /* normalize x + 14:00 */
1603 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
1604 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
1605
Daniel Veillardfdc91562002-07-01 21:52:03 +00001606 xmlSchemaFreeValue(p1);
1607 xmlSchemaFreeValue(q1);
1608 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001609 if (p2d > q1d)
1610 return 1;
1611 else if (p2d == q1d) {
1612 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
1613 if (sec > 0.0)
1614 return 1;
1615 else
1616 return 2; /* indeterminate */
1617 }
1618 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001619 } else {
1620 xmlSchemaFreeValue(p1);
1621 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001622 }
1623 }
1624
1625 /*
1626 * if the same type then calculate the difference
1627 */
1628 if (x->type == y->type) {
1629 q1 = xmlSchemaDateNormalize(y, 0);
1630 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1631
1632 p1 = xmlSchemaDateNormalize(x, 0);
1633 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1634
Daniel Veillardfdc91562002-07-01 21:52:03 +00001635 if (p1d < q1d) {
1636 xmlSchemaFreeValue(p1);
1637 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001638 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001639 } else if (p1d > q1d) {
1640 xmlSchemaFreeValue(p1);
1641 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001642 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001643 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001644 double sec;
1645
1646 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001647 xmlSchemaFreeValue(p1);
1648 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001649 if (sec < 0.0)
1650 return -1;
1651 else if (sec > 0.0)
1652 return 1;
1653
1654 }
1655 return 0;
1656 }
1657
1658 switch (x->type) {
1659 case XML_SCHEMAS_DATETIME:
1660 xmask = 0xf;
1661 break;
1662 case XML_SCHEMAS_DATE:
1663 xmask = 0x7;
1664 break;
1665 case XML_SCHEMAS_GYEAR:
1666 xmask = 0x1;
1667 break;
1668 case XML_SCHEMAS_GMONTH:
1669 xmask = 0x2;
1670 break;
1671 case XML_SCHEMAS_GDAY:
1672 xmask = 0x3;
1673 break;
1674 case XML_SCHEMAS_GYEARMONTH:
1675 xmask = 0x3;
1676 break;
1677 case XML_SCHEMAS_GMONTHDAY:
1678 xmask = 0x6;
1679 break;
1680 case XML_SCHEMAS_TIME:
1681 xmask = 0x8;
1682 break;
1683 default:
1684 xmask = 0;
1685 break;
1686 }
1687
1688 switch (y->type) {
1689 case XML_SCHEMAS_DATETIME:
1690 ymask = 0xf;
1691 break;
1692 case XML_SCHEMAS_DATE:
1693 ymask = 0x7;
1694 break;
1695 case XML_SCHEMAS_GYEAR:
1696 ymask = 0x1;
1697 break;
1698 case XML_SCHEMAS_GMONTH:
1699 ymask = 0x2;
1700 break;
1701 case XML_SCHEMAS_GDAY:
1702 ymask = 0x3;
1703 break;
1704 case XML_SCHEMAS_GYEARMONTH:
1705 ymask = 0x3;
1706 break;
1707 case XML_SCHEMAS_GMONTHDAY:
1708 ymask = 0x6;
1709 break;
1710 case XML_SCHEMAS_TIME:
1711 ymask = 0x8;
1712 break;
1713 default:
1714 ymask = 0;
1715 break;
1716 }
1717
1718 xor_mask = xmask ^ ymask; /* mark type differences */
1719 and_mask = xmask & ymask; /* mark field specification */
1720
1721 /* year */
1722 if (xor_mask & 1)
1723 return 2; /* indeterminate */
1724 else if (and_mask & 1) {
1725 if (x->value.date.year < y->value.date.year)
1726 return -1;
1727 else if (x->value.date.year > y->value.date.year)
1728 return 1;
1729 }
1730
1731 /* month */
1732 if (xor_mask & 2)
1733 return 2; /* indeterminate */
1734 else if (and_mask & 2) {
1735 if (x->value.date.mon < y->value.date.mon)
1736 return -1;
1737 else if (x->value.date.mon > y->value.date.mon)
1738 return 1;
1739 }
1740
1741 /* day */
1742 if (xor_mask & 4)
1743 return 2; /* indeterminate */
1744 else if (and_mask & 4) {
1745 if (x->value.date.day < y->value.date.day)
1746 return -1;
1747 else if (x->value.date.day > y->value.date.day)
1748 return 1;
1749 }
1750
1751 /* time */
1752 if (xor_mask & 8)
1753 return 2; /* indeterminate */
1754 else if (and_mask & 8) {
1755 if (x->value.date.hour < y->value.date.hour)
1756 return -1;
1757 else if (x->value.date.hour > y->value.date.hour)
1758 return 1;
1759 else if (x->value.date.min < y->value.date.min)
1760 return -1;
1761 else if (x->value.date.min > y->value.date.min)
1762 return 1;
1763 else if (x->value.date.sec < y->value.date.sec)
1764 return -1;
1765 else if (x->value.date.sec > y->value.date.sec)
1766 return 1;
1767 }
1768
Daniel Veillard070803b2002-05-03 07:29:38 +00001769 return 0;
1770}
1771
1772/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001773 * xmlSchemaCompareValues:
1774 * @x: a first value
1775 * @y: a second value
1776 *
1777 * Compare 2 values
1778 *
Daniel Veillard5a872412002-05-22 06:40:27 +00001779 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1780 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00001781 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00001782static int
Daniel Veillard4255d502002-04-16 15:50:10 +00001783xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
1784 if ((x == NULL) || (y == NULL))
1785 return(-2);
1786
1787 switch (x->type) {
1788 case XML_SCHEMAS_STRING:
1789 TODO
1790 case XML_SCHEMAS_DECIMAL:
1791 if (y->type == XML_SCHEMAS_DECIMAL)
1792 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00001793 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00001794 case XML_SCHEMAS_DURATION:
1795 if (y->type == XML_SCHEMAS_DURATION)
1796 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00001797 return(-2);
1798 case XML_SCHEMAS_TIME:
1799 case XML_SCHEMAS_GDAY:
1800 case XML_SCHEMAS_GMONTH:
1801 case XML_SCHEMAS_GMONTHDAY:
1802 case XML_SCHEMAS_GYEAR:
1803 case XML_SCHEMAS_GYEARMONTH:
1804 case XML_SCHEMAS_DATE:
1805 case XML_SCHEMAS_DATETIME:
1806 if ((y->type == XML_SCHEMAS_DATETIME) ||
1807 (y->type == XML_SCHEMAS_TIME) ||
1808 (y->type == XML_SCHEMAS_GDAY) ||
1809 (y->type == XML_SCHEMAS_GMONTH) ||
1810 (y->type == XML_SCHEMAS_GMONTHDAY) ||
1811 (y->type == XML_SCHEMAS_GYEAR) ||
1812 (y->type == XML_SCHEMAS_DATE) ||
1813 (y->type == XML_SCHEMAS_GYEARMONTH))
1814 return (xmlSchemaCompareDates(x, y));
1815
1816 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00001817 default:
1818 TODO
1819 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001820 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00001821}
1822
1823/**
1824 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00001825 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00001826 * @facet: the facet to check
1827 * @value: the lexical repr of the value to validate
1828 * @val: the precomputed value
1829 *
1830 * Check a value against a facet condition
1831 *
1832 * Returns 0 if the element is schemas valid, a positive error code
1833 * number otherwise and -1 in case of internal or API error.
1834 */
1835int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001836xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001837 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00001838 const xmlChar *value, xmlSchemaValPtr val)
1839{
1840 int ret;
1841
1842 switch (facet->type) {
1843 case XML_SCHEMA_FACET_PATTERN:
1844 ret = xmlRegexpExec(facet->regexp, value);
1845 if (ret == 1)
1846 return(0);
1847 if (ret == 0) {
1848 TODO /* error code */
1849 return(1);
1850 }
1851 return(ret);
1852 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
1853 ret = xmlSchemaCompareValues(val, facet->val);
1854 if (ret == -2) {
1855 TODO /* error code */
1856 return(-1);
1857 }
1858 if (ret == -1)
1859 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00001860 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00001861 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00001862 case XML_SCHEMA_FACET_MAXINCLUSIVE:
1863 ret = xmlSchemaCompareValues(val, facet->val);
1864 if (ret == -2) {
1865 TODO /* error code */
1866 return(-1);
1867 }
1868 if ((ret == -1) || (ret == 0))
1869 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00001870 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00001871 return(1);
1872 case XML_SCHEMA_FACET_MINEXCLUSIVE:
1873 ret = xmlSchemaCompareValues(val, facet->val);
1874 if (ret == -2) {
1875 TODO /* error code */
1876 return(-1);
1877 }
1878 if (ret == 1)
1879 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00001880 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00001881 return(1);
1882 case XML_SCHEMA_FACET_MININCLUSIVE:
1883 ret = xmlSchemaCompareValues(val, facet->val);
1884 if (ret == -2) {
1885 TODO /* error code */
1886 return(-1);
1887 }
1888 if ((ret == 1) || (ret == 0))
1889 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00001890 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00001891 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00001892 case XML_SCHEMA_FACET_WHITESPACE:
1893 TODO /* whitespaces */
1894 return(0);
Daniel Veillarde19fc232002-04-22 16:01:24 +00001895 case XML_SCHEMA_FACET_MAXLENGTH:
1896 if ((facet->val != NULL) &&
1897 (facet->val->type == XML_SCHEMAS_DECIMAL) &&
1898 (facet->val->value.decimal.frac == 0)) {
Daniel Veillard118aed72002-09-24 14:13:13 +00001899 unsigned int len;
Daniel Veillarde19fc232002-04-22 16:01:24 +00001900
1901 if (facet->val->value.decimal.sign == 1)
1902 return(1);
1903 len = xmlUTF8Strlen(value);
1904 if (len > facet->val->value.decimal.base)
1905 return(1);
1906 return(0);
1907 }
1908 TODO /* error code */
1909 return(1);
Daniel Veillard88c58912002-04-23 07:12:20 +00001910 case XML_SCHEMA_FACET_ENUMERATION:
1911 if ((facet->value != NULL) &&
1912 (xmlStrEqual(facet->value, value)))
1913 return(0);
1914 return(1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001915 default:
1916 TODO
1917 }
1918 return(0);
1919}
1920
1921#endif /* LIBXML_SCHEMAS_ENABLED */