blob: 52a069b6c0ccc9bd9a16cd6bcd76213db868e0f5 [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 Veillard4255d502002-04-16 15:50:10 +0000132
133/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000134 * Derived types
135 */
136static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
137static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
138static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
139static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
141static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
142static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
143static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
144static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
145static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
149
150/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000151 * xmlSchemaInitBasicType:
152 * @name: the type name
153 *
154 * Initialize one default type
155 */
156static xmlSchemaTypePtr
157xmlSchemaInitBasicType(const char *name) {
158 xmlSchemaTypePtr ret;
159
160 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
161 if (ret == NULL) {
162 xmlGenericError(xmlGenericErrorContext,
163 "Could not initilize type %s: out of memory\n", name);
164 return(NULL);
165 }
166 memset(ret, 0, sizeof(xmlSchemaType));
167 ret->name = xmlStrdup((const xmlChar *)name);
168 ret->type = XML_SCHEMA_TYPE_BASIC;
169 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
170 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
171 XML_SCHEMAS_NAMESPACE_NAME, ret);
172 return(ret);
173}
174
175/*
176 * xmlSchemaInitTypes:
177 *
178 * Initialize the default XML Schemas type library
179 */
180void
181xmlSchemaInitTypes(void) {
182 if (xmlSchemaTypesInitialized != 0)
183 return;
184 xmlSchemaTypesBank = xmlHashCreate(40);
185
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000186 /*
187 * primitive datatypes
188 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000189 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string");
190 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType");
191 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType");
192 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal");
193 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date");
Daniel Veillard070803b2002-05-03 07:29:38 +0000194 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime");
195 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time");
196 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear");
197 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth");
198 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth");
199 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay");
200 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay");
201 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration");
Daniel Veillard4255d502002-04-16 15:50:10 +0000202 xmlSchemaTypeNmtoken = xmlSchemaInitBasicType("NMTOKEN");
Daniel Veillard84d70a42002-09-16 10:51:38 +0000203 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float");
204 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double");
Daniel Veillard4255d502002-04-16 15:50:10 +0000205
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000206 /*
207 * derived datatypes
208 */
209 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer");;
210 xmlSchemaTypeNonPositiveIntegerDef = xmlSchemaInitBasicType("nonPositiveInteger");;
211 xmlSchemaTypeNegativeIntegerDef = xmlSchemaInitBasicType("negativeInteger");;
212 xmlSchemaTypeLongDef = xmlSchemaInitBasicType("long");;
213 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int");;
214 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short");;
215 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte");;
216 xmlSchemaTypeNonNegativeIntegerDef = xmlSchemaInitBasicType("nonNegativeInteger");
217 xmlSchemaTypeUnsignedLongDef = xmlSchemaInitBasicType("unsignedLong");;
218 xmlSchemaTypeUnsignedIntDef = xmlSchemaInitBasicType("unsignedInt");;
219 xmlSchemaTypeUnsignedShortDef = xmlSchemaInitBasicType("insignedShort");;
220 xmlSchemaTypeUnsignedByteDef = xmlSchemaInitBasicType("unsignedByte");;
221 xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger");
222
Daniel Veillard4255d502002-04-16 15:50:10 +0000223 xmlSchemaTypesInitialized = 1;
224}
225
226/**
227 * xmlSchemaCleanupTypes:
228 *
229 * Cleanup the default XML Schemas type library
230 */
231void
232xmlSchemaCleanupTypes(void) {
233 if (xmlSchemaTypesInitialized == 0)
234 return;
235 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
236 xmlSchemaTypesInitialized = 0;
237}
238
239/**
240 * xmlSchemaNewValue:
241 * @type: the value type
242 *
243 * Allocate a new simple type value
244 *
245 * Returns a pointer to the new value or NULL in case of error
246 */
247static xmlSchemaValPtr
248xmlSchemaNewValue(xmlSchemaValType type) {
249 xmlSchemaValPtr value;
250
251 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
252 if (value == NULL) {
253 return(NULL);
254 }
255 memset(value, 0, sizeof(xmlSchemaVal));
256 value->type = type;
257 return(value);
258}
259
260/**
261 * xmlSchemaFreeValue:
262 * @value: the value to free
263 *
264 * Cleanup the default XML Schemas type library
265 */
266void
267xmlSchemaFreeValue(xmlSchemaValPtr value) {
268 if (value == NULL)
269 return;
270 xmlFree(value);
271}
272
273/**
274 * xmlSchemaGetPredefinedType:
275 * @name: the type name
276 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
277 *
278 * Lookup a type in the default XML Schemas type library
279 *
280 * Returns the type if found, NULL otherwise
281 */
282xmlSchemaTypePtr
283xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
284 if (xmlSchemaTypesInitialized == 0)
285 xmlSchemaInitTypes();
286 if (name == NULL)
287 return(NULL);
288 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
289}
Daniel Veillard070803b2002-05-03 07:29:38 +0000290
291/****************************************************************
292 * *
293 * Convenience macros and functions *
294 * *
295 ****************************************************************/
296
297#define IS_TZO_CHAR(c) \
298 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
299
300#define VALID_YEAR(yr) (yr != 0)
301#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
302/* VALID_DAY should only be used when month is unknown */
303#define VALID_DAY(day) ((day >= 1) && (day <= 31))
304#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
305#define VALID_MIN(min) ((min >= 0) && (min <= 59))
306#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
307#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
308#define IS_LEAP(y) \
309 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
310
311static const long daysInMonth[12] =
312 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
313static const long daysInMonthLeap[12] =
314 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
315
Daniel Veillard5a872412002-05-22 06:40:27 +0000316#define MAX_DAYINMONTH(yr,mon) \
317 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
318
Daniel Veillard070803b2002-05-03 07:29:38 +0000319#define VALID_MDAY(dt) \
320 (IS_LEAP(dt->year) ? \
321 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
322 (dt->day <= daysInMonth[dt->mon - 1]))
323
324#define VALID_DATE(dt) \
325 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
326
327#define VALID_TIME(dt) \
328 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
329 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
330
331#define VALID_DATETIME(dt) \
332 (VALID_DATE(dt) && VALID_TIME(dt))
333
334#define SECS_PER_MIN (60)
335#define SECS_PER_HOUR (60 * SECS_PER_MIN)
336#define SECS_PER_DAY (24 * SECS_PER_HOUR)
337
Daniel Veillard5a872412002-05-22 06:40:27 +0000338static const long dayInYearByMonth[12] =
339 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
340static const long dayInLeapYearByMonth[12] =
341 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
342
343#define DAY_IN_YEAR(day, month, year) \
344 ((IS_LEAP(year) ? \
345 dayInLeapYearByMonth[month - 1] : \
346 dayInYearByMonth[month - 1]) + day)
347
348#ifdef DEBUG
349#define DEBUG_DATE(dt) \
350 xmlGenericError(xmlGenericErrorContext, \
351 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
352 dt->type,dt->value.date.year,dt->value.date.mon, \
353 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
354 dt->value.date.sec); \
355 if (dt->value.date.tz_flag) \
356 if (dt->value.date.tzo != 0) \
357 xmlGenericError(xmlGenericErrorContext, \
358 "%+05d\n",dt->value.date.tzo); \
359 else \
360 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
361 else \
362 xmlGenericError(xmlGenericErrorContext,"\n")
363#else
364#define DEBUG_DATE(dt)
365#endif
366
Daniel Veillard070803b2002-05-03 07:29:38 +0000367/**
368 * _xmlSchemaParseGYear:
369 * @dt: pointer to a date structure
370 * @str: pointer to the string to analyze
371 *
372 * Parses a xs:gYear without time zone and fills in the appropriate
373 * field of the @dt structure. @str is updated to point just after the
374 * xs:gYear. It is supposed that @dt->year is big enough to contain
375 * the year.
376 *
377 * Returns 0 or the error code
378 */
379static int
380_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
381 const xmlChar *cur = *str, *firstChar;
382 int isneg = 0, digcnt = 0;
383
384 if (((*cur < '0') || (*cur > '9')) &&
385 (*cur != '-') && (*cur != '+'))
386 return -1;
387
388 if (*cur == '-') {
389 isneg = 1;
390 cur++;
391 }
392
393 firstChar = cur;
394
395 while ((*cur >= '0') && (*cur <= '9')) {
396 dt->year = dt->year * 10 + (*cur - '0');
397 cur++;
398 digcnt++;
399 }
400
401 /* year must be at least 4 digits (CCYY); over 4
402 * digits cannot have a leading zero. */
403 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
404 return 1;
405
406 if (isneg)
407 dt->year = - dt->year;
408
409 if (!VALID_YEAR(dt->year))
410 return 2;
411
412 *str = cur;
413 return 0;
414}
415
416/**
417 * PARSE_2_DIGITS:
418 * @num: the integer to fill in
419 * @cur: an #xmlChar *
420 * @invalid: an integer
421 *
422 * Parses a 2-digits integer and updates @num with the value. @cur is
423 * updated to point just after the integer.
424 * In case of error, @invalid is set to %TRUE, values of @num and
425 * @cur are undefined.
426 */
427#define PARSE_2_DIGITS(num, cur, invalid) \
428 if ((cur[0] < '0') || (cur[0] > '9') || \
429 (cur[1] < '0') || (cur[1] > '9')) \
430 invalid = 1; \
431 else \
432 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
433 cur += 2;
434
435/**
436 * PARSE_FLOAT:
437 * @num: the double to fill in
438 * @cur: an #xmlChar *
439 * @invalid: an integer
440 *
441 * Parses a float and updates @num with the value. @cur is
442 * updated to point just after the float. The float must have a
443 * 2-digits integer part and may or may not have a decimal part.
444 * In case of error, @invalid is set to %TRUE, values of @num and
445 * @cur are undefined.
446 */
447#define PARSE_FLOAT(num, cur, invalid) \
448 PARSE_2_DIGITS(num, cur, invalid); \
449 if (!invalid && (*cur == '.')) { \
450 double mult = 1; \
451 cur++; \
452 if ((*cur < '0') || (*cur > '9')) \
453 invalid = 1; \
454 while ((*cur >= '0') && (*cur <= '9')) { \
455 mult /= 10; \
456 num += (*cur - '0') * mult; \
457 cur++; \
458 } \
459 }
460
461/**
462 * _xmlSchemaParseGMonth:
463 * @dt: pointer to a date structure
464 * @str: pointer to the string to analyze
465 *
466 * Parses a xs:gMonth without time zone and fills in the appropriate
467 * field of the @dt structure. @str is updated to point just after the
468 * xs:gMonth.
469 *
470 * Returns 0 or the error code
471 */
472static int
473_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
474 const xmlChar *cur = *str;
475 int ret = 0;
476
477 PARSE_2_DIGITS(dt->mon, cur, ret);
478 if (ret != 0)
479 return ret;
480
481 if (!VALID_MONTH(dt->mon))
482 return 2;
483
484 *str = cur;
485 return 0;
486}
487
488/**
489 * _xmlSchemaParseGDay:
490 * @dt: pointer to a date structure
491 * @str: pointer to the string to analyze
492 *
493 * Parses a xs:gDay without time zone and fills in the appropriate
494 * field of the @dt structure. @str is updated to point just after the
495 * xs:gDay.
496 *
497 * Returns 0 or the error code
498 */
499static int
500_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
501 const xmlChar *cur = *str;
502 int ret = 0;
503
504 PARSE_2_DIGITS(dt->day, cur, ret);
505 if (ret != 0)
506 return ret;
507
508 if (!VALID_DAY(dt->day))
509 return 2;
510
511 *str = cur;
512 return 0;
513}
514
515/**
516 * _xmlSchemaParseTime:
517 * @dt: pointer to a date structure
518 * @str: pointer to the string to analyze
519 *
520 * Parses a xs:time without time zone and fills in the appropriate
521 * fields of the @dt structure. @str is updated to point just after the
522 * xs:time.
523 * In case of error, values of @dt fields are undefined.
524 *
525 * Returns 0 or the error code
526 */
527static int
528_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
529 const xmlChar *cur = *str;
530 unsigned int hour = 0; /* use temp var in case str is not xs:time */
531 int ret = 0;
532
533 PARSE_2_DIGITS(hour, cur, ret);
534 if (ret != 0)
535 return ret;
536
537 if (*cur != ':')
538 return 1;
539 cur++;
540
541 /* the ':' insures this string is xs:time */
542 dt->hour = hour;
543
544 PARSE_2_DIGITS(dt->min, cur, ret);
545 if (ret != 0)
546 return ret;
547
548 if (*cur != ':')
549 return 1;
550 cur++;
551
552 PARSE_FLOAT(dt->sec, cur, ret);
553 if (ret != 0)
554 return ret;
555
556 if (!VALID_TIME(dt))
557 return 2;
558
559 *str = cur;
560 return 0;
561}
562
563/**
564 * _xmlSchemaParseTimeZone:
565 * @dt: pointer to a date structure
566 * @str: pointer to the string to analyze
567 *
568 * Parses a time zone without time zone and fills in the appropriate
569 * field of the @dt structure. @str is updated to point just after the
570 * time zone.
571 *
572 * Returns 0 or the error code
573 */
574static int
575_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
576 const xmlChar *cur = *str;
577 int ret = 0;
578
579 if (str == NULL)
580 return -1;
581
582 switch (*cur) {
583 case 0:
584 dt->tz_flag = 0;
585 dt->tzo = 0;
586 break;
587
588 case 'Z':
589 dt->tz_flag = 1;
590 dt->tzo = 0;
591 cur++;
592 break;
593
594 case '+':
595 case '-': {
596 int isneg = 0, tmp = 0;
597 isneg = (*cur == '-');
598
599 cur++;
600
601 PARSE_2_DIGITS(tmp, cur, ret);
602 if (ret != 0)
603 return ret;
604 if (!VALID_HOUR(tmp))
605 return 2;
606
607 if (*cur != ':')
608 return 1;
609 cur++;
610
611 dt->tzo = tmp * 60;
612
613 PARSE_2_DIGITS(tmp, cur, ret);
614 if (ret != 0)
615 return ret;
616 if (!VALID_MIN(tmp))
617 return 2;
618
619 dt->tzo += tmp;
620 if (isneg)
621 dt->tzo = - dt->tzo;
622
623 if (!VALID_TZO(dt->tzo))
624 return 2;
625
Daniel Veillard5a872412002-05-22 06:40:27 +0000626 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000627 break;
628 }
629 default:
630 return 1;
631 }
632
633 *str = cur;
634 return 0;
635}
636
637/****************************************************************
638 * *
639 * XML Schema Dates/Times Datatypes Handling *
640 * *
641 ****************************************************************/
642
643/**
644 * PARSE_DIGITS:
645 * @num: the integer to fill in
646 * @cur: an #xmlChar *
647 * @num_type: an integer flag
648 *
649 * Parses a digits integer and updates @num with the value. @cur is
650 * updated to point just after the integer.
651 * In case of error, @num_type is set to -1, values of @num and
652 * @cur are undefined.
653 */
654#define PARSE_DIGITS(num, cur, num_type) \
655 if ((*cur < '0') || (*cur > '9')) \
656 num_type = -1; \
657 else \
658 while ((*cur >= '0') && (*cur <= '9')) { \
659 num = num * 10 + (*cur - '0'); \
660 cur++; \
661 }
662
663/**
664 * PARSE_NUM:
665 * @num: the double to fill in
666 * @cur: an #xmlChar *
667 * @num_type: an integer flag
668 *
669 * Parses a float or integer and updates @num with the value. @cur is
670 * updated to point just after the number. If the number is a float,
671 * then it must have an integer part and a decimal part; @num_type will
672 * be set to 1. If there is no decimal part, @num_type is set to zero.
673 * In case of error, @num_type is set to -1, values of @num and
674 * @cur are undefined.
675 */
676#define PARSE_NUM(num, cur, num_type) \
677 num = 0; \
678 PARSE_DIGITS(num, cur, num_type); \
679 if (!num_type && (*cur == '.')) { \
680 double mult = 1; \
681 cur++; \
682 if ((*cur < '0') || (*cur > '9')) \
683 num_type = -1; \
684 else \
685 num_type = 1; \
686 while ((*cur >= '0') && (*cur <= '9')) { \
687 mult /= 10; \
688 num += (*cur - '0') * mult; \
689 cur++; \
690 } \
691 }
692
693/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000694 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000695 * @type: the predefined type
696 * @dateTime: string to analyze
697 * @val: the return computed value
698 *
699 * Check that @dateTime conforms to the lexical space of one of the date types.
700 * if true a value is computed and returned in @val.
701 *
702 * Returns 0 if this validates, a positive error code number otherwise
703 * and -1 in case of internal or API error.
704 */
705static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000706xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000707 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000708 xmlSchemaValPtr dt;
709 int ret;
710 const xmlChar *cur = dateTime;
711
712#define RETURN_TYPE_IF_VALID(t) \
713 if (IS_TZO_CHAR(*cur)) { \
714 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
715 if (ret == 0) { \
716 if (*cur != 0) \
717 goto error; \
718 dt->type = t; \
719 if (val != NULL) \
720 *val = dt; \
721 return 0; \
722 } \
723 }
724
725 if (dateTime == NULL)
726 return -1;
727
728 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
729 return 1;
730
731 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
732 if (dt == NULL)
733 return -1;
734
735 if ((cur[0] == '-') && (cur[1] == '-')) {
736 /*
737 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
738 * xs:gDay)
739 */
740 cur += 2;
741
742 /* is it an xs:gDay? */
743 if (*cur == '-') {
744 ++cur;
745 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
746 if (ret != 0)
747 goto error;
748
749 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
750
751 goto error;
752 }
753
754 /*
755 * it should be an xs:gMonthDay or xs:gMonth
756 */
757 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
758 if (ret != 0)
759 goto error;
760
761 if (*cur != '-')
762 goto error;
763 cur++;
764
765 /* is it an xs:gMonth? */
766 if (*cur == '-') {
767 cur++;
768 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
769 goto error;
770 }
771
772 /* it should be an xs:gMonthDay */
773 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
774 if (ret != 0)
775 goto error;
776
777 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
778
779 goto error;
780 }
781
782 /*
783 * It's a right-truncated date or an xs:time.
784 * Try to parse an xs:time then fallback on right-truncated dates.
785 */
786 if ((*cur >= '0') && (*cur <= '9')) {
787 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
788 if (ret == 0) {
789 /* it's an xs:time */
790 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
791 }
792 }
793
794 /* fallback on date parsing */
795 cur = dateTime;
796
797 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
798 if (ret != 0)
799 goto error;
800
801 /* is it an xs:gYear? */
802 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
803
804 if (*cur != '-')
805 goto error;
806 cur++;
807
808 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
809 if (ret != 0)
810 goto error;
811
812 /* is it an xs:gYearMonth? */
813 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
814
815 if (*cur != '-')
816 goto error;
817 cur++;
818
819 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
820 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
821 goto error;
822
823 /* is it an xs:date? */
824 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
825
826 if (*cur != 'T')
827 goto error;
828 cur++;
829
830 /* it should be an xs:dateTime */
831 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
832 if (ret != 0)
833 goto error;
834
835 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
836 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
837 goto error;
838
839 dt->type = XML_SCHEMAS_DATETIME;
840
841 if (val != NULL)
842 *val = dt;
843
844 return 0;
845
846error:
847 if (dt != NULL)
848 xmlSchemaFreeValue(dt);
849 return 1;
850}
851
852/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000853 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000854 * @type: the predefined type
855 * @duration: string to analyze
856 * @val: the return computed value
857 *
858 * Check that @duration conforms to the lexical space of the duration type.
859 * if true a value is computed and returned in @val.
860 *
861 * Returns 0 if this validates, a positive error code number otherwise
862 * and -1 in case of internal or API error.
863 */
864static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000865xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000866 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000867 const xmlChar *cur = duration;
868 xmlSchemaValPtr dur;
869 int isneg = 0;
870 unsigned int seq = 0;
871
872 if (duration == NULL)
873 return -1;
874
875 if (*cur == '-') {
876 isneg = 1;
877 cur++;
878 }
879
880 /* duration must start with 'P' (after sign) */
881 if (*cur++ != 'P')
882 return 1;
883
884 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
885 if (dur == NULL)
886 return -1;
887
888 while (*cur != 0) {
889 double num;
890 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
891 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
892 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
893
894 /* input string should be empty or invalid date/time item */
895 if (seq >= sizeof(desig))
896 goto error;
897
898 /* T designator must be present for time items */
899 if (*cur == 'T') {
900 if (seq <= 3) {
901 seq = 3;
902 cur++;
903 } else
904 return 1;
905 } else if (seq == 3)
906 goto error;
907
908 /* parse the number portion of the item */
909 PARSE_NUM(num, cur, num_type);
910
911 if ((num_type == -1) || (*cur == 0))
912 goto error;
913
914 /* update duration based on item type */
915 while (seq < sizeof(desig)) {
916 if (*cur == desig[seq]) {
917
918 /* verify numeric type; only seconds can be float */
919 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
920 goto error;
921
922 switch (seq) {
923 case 0:
924 dur->value.dur.mon = (long)num * 12;
925 break;
926 case 1:
927 dur->value.dur.mon += (long)num;
928 break;
929 default:
930 /* convert to seconds using multiplier */
931 dur->value.dur.sec += num * multi[seq];
932 seq++;
933 break;
934 }
935
936 break; /* exit loop */
937 }
938 /* no date designators found? */
939 if (++seq == 3)
940 goto error;
941 }
942 cur++;
943 }
944
945 if (isneg) {
946 dur->value.dur.mon = -dur->value.dur.mon;
947 dur->value.dur.day = -dur->value.dur.day;
948 dur->value.dur.sec = -dur->value.dur.sec;
949 }
950
951 if (val != NULL)
952 *val = dur;
953
954 return 0;
955
956error:
957 if (dur != NULL)
958 xmlSchemaFreeValue(dur);
959 return 1;
960}
961
Daniel Veillard4255d502002-04-16 15:50:10 +0000962/**
963 * xmlSchemaValidatePredefinedType:
964 * @type: the predefined type
965 * @value: the value to check
966 * @val: the return computed value
967 *
968 * Check that a value conforms to the lexical space of the predefined type.
969 * if true a value is computed and returned in @val.
970 *
971 * Returns 0 if this validates, a positive error code number otherwise
972 * and -1 in case of internal or API error.
973 */
974int
975xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
976 xmlSchemaValPtr *val) {
977 xmlSchemaValPtr v;
978
979 if (xmlSchemaTypesInitialized == 0)
980 return(-1);
981 if (type == NULL)
982 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +0000983
Daniel Veillard4255d502002-04-16 15:50:10 +0000984 if (val != NULL)
985 *val = NULL;
986 if (type == xmlSchemaTypeStringDef) {
987 return(0);
988 } else if (type == xmlSchemaTypeAnyTypeDef) {
989 return(0);
990 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
991 return(0);
992 } else if (type == xmlSchemaTypeNmtoken) {
993 if (xmlValidateNmtokenValue(value))
994 return(0);
995 return(1);
996 } else if (type == xmlSchemaTypeDecimalDef) {
997 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +0000998 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +0000999 unsigned long base = 0;
1000 if (cur == NULL)
1001 return(1);
1002 if (*cur == '+')
1003 cur++;
1004 else if (*cur == '-') {
1005 neg = 1;
1006 cur++;
1007 }
1008 tmp = cur;
1009 while ((*cur >= '0') && (*cur <= '9')) {
1010 base = base * 10 + (*cur - '0');
1011 cur++;
1012 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001013 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001014 if (*cur == '.') {
1015 cur++;
1016 tmp = cur;
1017 while ((*cur >= '0') && (*cur <= '9')) {
1018 base = base * 10 + (*cur - '0');
1019 cur++;
1020 }
1021 frac = cur - tmp;
1022 }
1023 if (*cur != 0)
1024 return(1);
1025 if (val != NULL) {
1026 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1027 if (v != NULL) {
1028 v->value.decimal.base = base;
1029 v->value.decimal.sign = neg;
1030 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001031 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001032 *val = v;
1033 }
1034 }
1035 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001036 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001037 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001038 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1039 (type == xmlSchemaTypeTimeDef) ||
1040 (type == xmlSchemaTypeDateDef) ||
1041 (type == xmlSchemaTypeGYearDef) ||
1042 (type == xmlSchemaTypeGYearMonthDef) ||
1043 (type == xmlSchemaTypeGMonthDef) ||
1044 (type == xmlSchemaTypeGMonthDayDef) ||
1045 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001046 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001047 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1048 const xmlChar *cur = value;
1049 unsigned long base = 0;
1050 int total = 0;
1051 if (cur == NULL)
1052 return(1);
1053 if (*cur == '+')
1054 cur++;
1055 while ((*cur >= '0') && (*cur <= '9')) {
1056 base = base * 10 + (*cur - '0');
1057 total++;
1058 cur++;
1059 }
1060 if (*cur != 0)
1061 return(1);
1062 if (val != NULL) {
1063 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1064 if (v != NULL) {
1065 v->value.decimal.base = base;
1066 v->value.decimal.sign = 0;
1067 v->value.decimal.frac = 0;
1068 v->value.decimal.total = total;
1069 *val = v;
1070 }
1071 }
1072 return(0);
1073 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1074 const xmlChar *cur = value;
1075 unsigned long base = 0;
1076 int total = 0;
1077 int sign = 0;
1078 if (cur == NULL)
1079 return(1);
1080 if (*cur == '-') {
1081 sign = 1;
1082 cur++;
1083 } else if (*cur == '+')
1084 cur++;
1085 while ((*cur >= '0') && (*cur <= '9')) {
1086 base = base * 10 + (*cur - '0');
1087 total++;
1088 cur++;
1089 }
1090 if (*cur != 0)
1091 return(1);
1092 if ((sign == 1) && (base != 0))
1093 return(1);
1094 if (val != NULL) {
1095 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1096 if (v != NULL) {
1097 v->value.decimal.base = base;
1098 v->value.decimal.sign = 0;
1099 v->value.decimal.frac = 0;
1100 v->value.decimal.total = total;
1101 *val = v;
1102 }
1103 }
1104 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001105 } else if (type == xmlSchemaTypeFloatDef) {
1106 const xmlChar *cur = value, *tmp;
1107 int frac = 0, len, neg = 0;
1108 unsigned long base = 0;
1109 if (cur == NULL)
1110 return(1);
1111 if (*cur == '+')
1112 cur++;
1113 else if (*cur == '-') {
1114 neg = 1;
1115 cur++;
1116 }
1117 tmp = cur;
1118 while ((*cur >= '0') && (*cur <= '9')) {
1119 base = base * 10 + (*cur - '0');
1120 cur++;
1121 }
1122 len = cur - tmp;
1123 if (*cur == '.') {
1124 cur++;
1125 tmp = cur;
1126 while ((*cur >= '0') && (*cur <= '9')) {
1127 base = base * 10 + (*cur - '0');
1128 cur++;
1129 }
1130 frac = cur - tmp;
1131 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001132 TODO
1133 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001134 } else if (type == xmlSchemaTypeDoubleDef) {
Daniel Veillardb5c05732002-09-20 13:36:25 +00001135 TODO
1136 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001137 } else {
1138 TODO
1139 return(0);
1140 }
1141}
1142
1143/**
1144 * xmlSchemaCompareDecimals:
1145 * @x: a first decimal value
1146 * @y: a second decimal value
1147 *
1148 * Compare 2 decimals
1149 *
1150 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1151 */
1152static int
1153xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1154{
1155 xmlSchemaValPtr swp;
1156 int order = 1;
1157 unsigned long tmp;
1158
1159 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1160 order = -1;
1161 else if (x->value.decimal.sign)
1162 return (-1);
1163 else if (y->value.decimal.sign)
1164 return (1);
1165 if (x->value.decimal.frac == y->value.decimal.frac) {
1166 if (x->value.decimal.base < y->value.decimal.base)
1167 return (-1);
1168 return (x->value.decimal.base > y->value.decimal.base);
1169 }
1170 if (y->value.decimal.frac > x->value.decimal.frac) {
1171 swp = y;
1172 y = x;
1173 x = swp;
1174 order = -order;
1175 }
1176 tmp =
1177 x->value.decimal.base / powten[x->value.decimal.frac -
1178 y->value.decimal.frac];
1179 if (tmp > y->value.decimal.base)
1180 return (order);
1181 if (tmp < y->value.decimal.base)
1182 return (-order);
1183 tmp =
1184 y->value.decimal.base * powten[x->value.decimal.frac -
1185 y->value.decimal.frac];
1186 if (x->value.decimal.base < tmp)
1187 return (-order);
1188 if (x->value.decimal.base == tmp)
1189 return (0);
1190 return (order);
1191}
1192
1193/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001194 * xmlSchemaCompareDurations:
1195 * @x: a first duration value
1196 * @y: a second duration value
1197 *
1198 * Compare 2 durations
1199 *
1200 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1201 * case of error
1202 */
1203static int
1204xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1205{
1206 long carry, mon, day;
1207 double sec;
1208 long xmon, xday, myear, lyear, minday, maxday;
1209 static const long dayRange [2][12] = {
1210 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1211 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1212
1213 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001214 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001215
1216 /* months */
1217 mon = x->value.dur.mon - y->value.dur.mon;
1218
1219 /* seconds */
1220 sec = x->value.dur.sec - y->value.dur.sec;
1221 carry = (long)sec / SECS_PER_DAY;
1222 sec -= (double)(carry * SECS_PER_DAY);
1223
1224 /* days */
1225 day = x->value.dur.day - y->value.dur.day + carry;
1226
1227 /* easy test */
1228 if (mon == 0) {
1229 if (day == 0)
1230 if (sec == 0.0)
1231 return 0;
1232 else if (sec < 0.0)
1233 return -1;
1234 else
1235 return 1;
1236 else if (day < 0)
1237 return -1;
1238 else
1239 return 1;
1240 }
1241
1242 if (mon > 0) {
1243 if ((day >= 0) && (sec >= 0.0))
1244 return 1;
1245 else {
1246 xmon = mon;
1247 xday = -day;
1248 }
1249 } else if ((day <= 0) && (sec <= 0.0)) {
1250 return -1;
1251 } else {
1252 xmon = -mon;
1253 xday = day;
1254 }
1255
1256 myear = xmon / 12;
1257 lyear = myear / 4;
1258 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1259 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1260
1261 xmon = xmon % 12;
1262 minday += dayRange[0][xmon];
1263 maxday += dayRange[1][xmon];
1264
1265 if (maxday < xday)
1266 return 1;
1267 else if (minday > xday)
1268 return -1;
1269
1270 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001271 return 2;
1272}
1273
1274/*
1275 * macros for adding date/times and durations
1276 */
1277#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1278#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1279#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1280#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1281
1282/**
1283 * _xmlSchemaDateAdd:
1284 * @dt: an #xmlSchemaValPtr
1285 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1286 *
1287 * Compute a new date/time from @dt and @dur. This function assumes @dt
1288 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1289 * or #XML_SCHEMAS_GYEAR.
1290 *
1291 * Returns date/time pointer or NULL.
1292 */
1293static xmlSchemaValPtr
1294_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1295{
1296 xmlSchemaValPtr ret;
1297 long carry, tempdays, temp;
1298 xmlSchemaValDatePtr r, d;
1299 xmlSchemaValDurationPtr u;
1300
1301 if ((dt == NULL) || (dur == NULL))
1302 return NULL;
1303
1304 ret = xmlSchemaNewValue(dt->type);
1305 if (ret == NULL)
1306 return NULL;
1307
1308 r = &(ret->value.date);
1309 d = &(dt->value.date);
1310 u = &(dur->value.dur);
1311
1312 /* normalization */
1313 if (d->mon == 0)
1314 d->mon = 1;
1315
1316 /* normalize for time zone offset */
1317 u->sec -= (d->tzo * 60);
1318 d->tzo = 0;
1319
1320 /* normalization */
1321 if (d->day == 0)
1322 d->day = 1;
1323
1324 /* month */
1325 carry = d->mon + u->mon;
1326 r->mon = MODULO_RANGE(carry, 1, 13);
1327 carry = FQUOTIENT_RANGE(carry, 1, 13);
1328
1329 /* year (may be modified later) */
1330 r->year = d->year + carry;
1331 if (r->year == 0) {
1332 if (d->year > 0)
1333 r->year--;
1334 else
1335 r->year++;
1336 }
1337
1338 /* time zone */
1339 r->tzo = d->tzo;
1340 r->tz_flag = d->tz_flag;
1341
1342 /* seconds */
1343 r->sec = d->sec + u->sec;
1344 carry = FQUOTIENT((long)r->sec, 60);
1345 if (r->sec != 0.0) {
1346 r->sec = MODULO(r->sec, 60.0);
1347 }
1348
1349 /* minute */
1350 carry += d->min;
1351 r->min = MODULO(carry, 60);
1352 carry = FQUOTIENT(carry, 60);
1353
1354 /* hours */
1355 carry += d->hour;
1356 r->hour = MODULO(carry, 24);
1357 carry = FQUOTIENT(carry, 24);
1358
1359 /*
1360 * days
1361 * Note we use tempdays because the temporary values may need more
1362 * than 5 bits
1363 */
1364 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1365 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1366 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1367 else if (d->day < 1)
1368 tempdays = 1;
1369 else
1370 tempdays = d->day;
1371
1372 tempdays += u->day + carry;
1373
1374 while (1) {
1375 if (tempdays < 1) {
1376 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1377 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1378 if (tyr == 0)
1379 tyr--;
1380 tempdays += MAX_DAYINMONTH(tyr, tmon);
1381 carry = -1;
1382 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1383 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1384 carry = 1;
1385 } else
1386 break;
1387
1388 temp = r->mon + carry;
1389 r->mon = MODULO_RANGE(temp, 1, 13);
1390 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1391 if (r->year == 0) {
1392 if (temp < 1)
1393 r->year--;
1394 else
1395 r->year++;
1396 }
1397 }
1398
1399 r->day = tempdays;
1400
1401 /*
1402 * adjust the date/time type to the date values
1403 */
1404 if (ret->type != XML_SCHEMAS_DATETIME) {
1405 if ((r->hour) || (r->min) || (r->sec))
1406 ret->type = XML_SCHEMAS_DATETIME;
1407 else if (ret->type != XML_SCHEMAS_DATE) {
1408 if ((r->mon != 1) && (r->day != 1))
1409 ret->type = XML_SCHEMAS_DATE;
1410 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1411 ret->type = XML_SCHEMAS_GYEARMONTH;
1412 }
1413 }
1414
1415 return ret;
1416}
1417
1418/**
1419 * xmlSchemaDupVal:
1420 * @v: value to duplicate
1421 *
1422 * returns a duplicated value.
1423 */
1424static xmlSchemaValPtr
1425xmlSchemaDupVal (xmlSchemaValPtr v)
1426{
1427 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1428 if (ret == NULL)
1429 return ret;
1430
1431 memcpy(ret, v, sizeof(xmlSchemaVal));
1432 return ret;
1433}
1434
1435/**
1436 * xmlSchemaDateNormalize:
1437 * @dt: an #xmlSchemaValPtr
1438 *
1439 * Normalize @dt to GMT time.
1440 *
1441 */
1442static xmlSchemaValPtr
1443xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1444{
1445 xmlSchemaValPtr dur, ret;
1446
1447 if (dt == NULL)
1448 return NULL;
1449
1450 if (((dt->type != XML_SCHEMAS_TIME) &&
1451 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1452 return xmlSchemaDupVal(dt);
1453
1454 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1455 if (dur == NULL)
1456 return NULL;
1457
1458 dur->value.date.sec -= offset;
1459
1460 ret = _xmlSchemaDateAdd(dt, dur);
1461 if (ret == NULL)
1462 return NULL;
1463
1464 xmlSchemaFreeValue(dur);
1465
1466 /* ret->value.date.tzo = 0; */
1467 return ret;
1468}
1469
1470/**
1471 * _xmlSchemaDateCastYMToDays:
1472 * @dt: an #xmlSchemaValPtr
1473 *
1474 * Convert mon and year of @dt to total number of days. Take the
1475 * number of years since (or before) 1 AD and add the number of leap
1476 * years. This is a function because negative
1477 * years must be handled a little differently and there is no zero year.
1478 *
1479 * Returns number of days.
1480 */
1481static long
1482_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
1483{
1484 long ret;
1485
1486 if (dt->value.date.year < 0)
1487 ret = (dt->value.date.year * 365) +
1488 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1489 ((dt->value.date.year+1)/400)) +
1490 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1491 else
1492 ret = ((dt->value.date.year-1) * 365) +
1493 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1494 ((dt->value.date.year-1)/400)) +
1495 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1496
1497 return ret;
1498}
1499
1500/**
1501 * TIME_TO_NUMBER:
1502 * @dt: an #xmlSchemaValPtr
1503 *
1504 * Calculates the number of seconds in the time portion of @dt.
1505 *
1506 * Returns seconds.
1507 */
1508#define TIME_TO_NUMBER(dt) \
1509 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
1510 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
1511
1512/**
1513 * xmlSchemaCompareDates:
1514 * @x: a first date/time value
1515 * @y: a second date/time value
1516 *
1517 * Compare 2 date/times
1518 *
1519 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1520 * case of error
1521 */
1522static int
1523xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
1524{
1525 unsigned char xmask, ymask, xor_mask, and_mask;
1526 xmlSchemaValPtr p1, p2, q1, q2;
1527 long p1d, p2d, q1d, q2d;
1528
1529 if ((x == NULL) || (y == NULL))
1530 return -2;
1531
1532 if (x->value.date.tz_flag) {
1533
1534 if (!y->value.date.tz_flag) {
1535 p1 = xmlSchemaDateNormalize(x, 0);
1536 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1537 /* normalize y + 14:00 */
1538 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
1539
1540 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001541 if (p1d < q1d) {
1542 xmlSchemaFreeValue(p1);
1543 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001544 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001545 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001546 double sec;
1547
1548 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001549 if (sec < 0.0) {
1550 xmlSchemaFreeValue(p1);
1551 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001552 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001553 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001554 /* normalize y - 14:00 */
1555 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
1556 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001557 xmlSchemaFreeValue(p1);
1558 xmlSchemaFreeValue(q1);
1559 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001560 if (p1d > q2d)
1561 return 1;
1562 else if (p1d == q2d) {
1563 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
1564 if (sec > 0.0)
1565 return 1;
1566 else
1567 return 2; /* indeterminate */
1568 }
1569 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001570 } else {
1571 xmlSchemaFreeValue(p1);
1572 xmlSchemaFreeValue(q1);
1573 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001574 }
1575 } else if (y->value.date.tz_flag) {
1576 q1 = xmlSchemaDateNormalize(y, 0);
1577 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1578
1579 /* normalize x - 14:00 */
1580 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
1581 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1582
Daniel Veillardfdc91562002-07-01 21:52:03 +00001583 if (p1d < q1d) {
1584 xmlSchemaFreeValue(p1);
1585 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001586 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001587 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001588 double sec;
1589
1590 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001591 if (sec < 0.0) {
1592 xmlSchemaFreeValue(p1);
1593 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001594 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001595 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001596 /* normalize x + 14:00 */
1597 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
1598 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
1599
Daniel Veillardfdc91562002-07-01 21:52:03 +00001600 xmlSchemaFreeValue(p1);
1601 xmlSchemaFreeValue(q1);
1602 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001603 if (p2d > q1d)
1604 return 1;
1605 else if (p2d == q1d) {
1606 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
1607 if (sec > 0.0)
1608 return 1;
1609 else
1610 return 2; /* indeterminate */
1611 }
1612 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001613 } else {
1614 xmlSchemaFreeValue(p1);
1615 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001616 }
1617 }
1618
1619 /*
1620 * if the same type then calculate the difference
1621 */
1622 if (x->type == y->type) {
1623 q1 = xmlSchemaDateNormalize(y, 0);
1624 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1625
1626 p1 = xmlSchemaDateNormalize(x, 0);
1627 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1628
Daniel Veillardfdc91562002-07-01 21:52:03 +00001629 if (p1d < q1d) {
1630 xmlSchemaFreeValue(p1);
1631 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001632 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001633 } else if (p1d > q1d) {
1634 xmlSchemaFreeValue(p1);
1635 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001636 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001637 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001638 double sec;
1639
1640 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001641 xmlSchemaFreeValue(p1);
1642 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001643 if (sec < 0.0)
1644 return -1;
1645 else if (sec > 0.0)
1646 return 1;
1647
1648 }
1649 return 0;
1650 }
1651
1652 switch (x->type) {
1653 case XML_SCHEMAS_DATETIME:
1654 xmask = 0xf;
1655 break;
1656 case XML_SCHEMAS_DATE:
1657 xmask = 0x7;
1658 break;
1659 case XML_SCHEMAS_GYEAR:
1660 xmask = 0x1;
1661 break;
1662 case XML_SCHEMAS_GMONTH:
1663 xmask = 0x2;
1664 break;
1665 case XML_SCHEMAS_GDAY:
1666 xmask = 0x3;
1667 break;
1668 case XML_SCHEMAS_GYEARMONTH:
1669 xmask = 0x3;
1670 break;
1671 case XML_SCHEMAS_GMONTHDAY:
1672 xmask = 0x6;
1673 break;
1674 case XML_SCHEMAS_TIME:
1675 xmask = 0x8;
1676 break;
1677 default:
1678 xmask = 0;
1679 break;
1680 }
1681
1682 switch (y->type) {
1683 case XML_SCHEMAS_DATETIME:
1684 ymask = 0xf;
1685 break;
1686 case XML_SCHEMAS_DATE:
1687 ymask = 0x7;
1688 break;
1689 case XML_SCHEMAS_GYEAR:
1690 ymask = 0x1;
1691 break;
1692 case XML_SCHEMAS_GMONTH:
1693 ymask = 0x2;
1694 break;
1695 case XML_SCHEMAS_GDAY:
1696 ymask = 0x3;
1697 break;
1698 case XML_SCHEMAS_GYEARMONTH:
1699 ymask = 0x3;
1700 break;
1701 case XML_SCHEMAS_GMONTHDAY:
1702 ymask = 0x6;
1703 break;
1704 case XML_SCHEMAS_TIME:
1705 ymask = 0x8;
1706 break;
1707 default:
1708 ymask = 0;
1709 break;
1710 }
1711
1712 xor_mask = xmask ^ ymask; /* mark type differences */
1713 and_mask = xmask & ymask; /* mark field specification */
1714
1715 /* year */
1716 if (xor_mask & 1)
1717 return 2; /* indeterminate */
1718 else if (and_mask & 1) {
1719 if (x->value.date.year < y->value.date.year)
1720 return -1;
1721 else if (x->value.date.year > y->value.date.year)
1722 return 1;
1723 }
1724
1725 /* month */
1726 if (xor_mask & 2)
1727 return 2; /* indeterminate */
1728 else if (and_mask & 2) {
1729 if (x->value.date.mon < y->value.date.mon)
1730 return -1;
1731 else if (x->value.date.mon > y->value.date.mon)
1732 return 1;
1733 }
1734
1735 /* day */
1736 if (xor_mask & 4)
1737 return 2; /* indeterminate */
1738 else if (and_mask & 4) {
1739 if (x->value.date.day < y->value.date.day)
1740 return -1;
1741 else if (x->value.date.day > y->value.date.day)
1742 return 1;
1743 }
1744
1745 /* time */
1746 if (xor_mask & 8)
1747 return 2; /* indeterminate */
1748 else if (and_mask & 8) {
1749 if (x->value.date.hour < y->value.date.hour)
1750 return -1;
1751 else if (x->value.date.hour > y->value.date.hour)
1752 return 1;
1753 else if (x->value.date.min < y->value.date.min)
1754 return -1;
1755 else if (x->value.date.min > y->value.date.min)
1756 return 1;
1757 else if (x->value.date.sec < y->value.date.sec)
1758 return -1;
1759 else if (x->value.date.sec > y->value.date.sec)
1760 return 1;
1761 }
1762
Daniel Veillard070803b2002-05-03 07:29:38 +00001763 return 0;
1764}
1765
1766/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001767 * xmlSchemaCompareValues:
1768 * @x: a first value
1769 * @y: a second value
1770 *
1771 * Compare 2 values
1772 *
Daniel Veillard5a872412002-05-22 06:40:27 +00001773 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1774 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00001775 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00001776static int
Daniel Veillard4255d502002-04-16 15:50:10 +00001777xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
1778 if ((x == NULL) || (y == NULL))
1779 return(-2);
1780
1781 switch (x->type) {
1782 case XML_SCHEMAS_STRING:
1783 TODO
1784 case XML_SCHEMAS_DECIMAL:
1785 if (y->type == XML_SCHEMAS_DECIMAL)
1786 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00001787 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00001788 case XML_SCHEMAS_DURATION:
1789 if (y->type == XML_SCHEMAS_DURATION)
1790 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00001791 return(-2);
1792 case XML_SCHEMAS_TIME:
1793 case XML_SCHEMAS_GDAY:
1794 case XML_SCHEMAS_GMONTH:
1795 case XML_SCHEMAS_GMONTHDAY:
1796 case XML_SCHEMAS_GYEAR:
1797 case XML_SCHEMAS_GYEARMONTH:
1798 case XML_SCHEMAS_DATE:
1799 case XML_SCHEMAS_DATETIME:
1800 if ((y->type == XML_SCHEMAS_DATETIME) ||
1801 (y->type == XML_SCHEMAS_TIME) ||
1802 (y->type == XML_SCHEMAS_GDAY) ||
1803 (y->type == XML_SCHEMAS_GMONTH) ||
1804 (y->type == XML_SCHEMAS_GMONTHDAY) ||
1805 (y->type == XML_SCHEMAS_GYEAR) ||
1806 (y->type == XML_SCHEMAS_DATE) ||
1807 (y->type == XML_SCHEMAS_GYEARMONTH))
1808 return (xmlSchemaCompareDates(x, y));
1809
1810 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00001811 default:
1812 TODO
1813 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001814 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00001815}
1816
1817/**
1818 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00001819 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00001820 * @facet: the facet to check
1821 * @value: the lexical repr of the value to validate
1822 * @val: the precomputed value
1823 *
1824 * Check a value against a facet condition
1825 *
1826 * Returns 0 if the element is schemas valid, a positive error code
1827 * number otherwise and -1 in case of internal or API error.
1828 */
1829int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001830xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001831 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00001832 const xmlChar *value, xmlSchemaValPtr val)
1833{
1834 int ret;
1835
1836 switch (facet->type) {
1837 case XML_SCHEMA_FACET_PATTERN:
1838 ret = xmlRegexpExec(facet->regexp, value);
1839 if (ret == 1)
1840 return(0);
1841 if (ret == 0) {
1842 TODO /* error code */
1843 return(1);
1844 }
1845 return(ret);
1846 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
1847 ret = xmlSchemaCompareValues(val, facet->val);
1848 if (ret == -2) {
1849 TODO /* error code */
1850 return(-1);
1851 }
1852 if (ret == -1)
1853 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00001854 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00001855 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00001856 case XML_SCHEMA_FACET_MAXINCLUSIVE:
1857 ret = xmlSchemaCompareValues(val, facet->val);
1858 if (ret == -2) {
1859 TODO /* error code */
1860 return(-1);
1861 }
1862 if ((ret == -1) || (ret == 0))
1863 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00001864 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00001865 return(1);
1866 case XML_SCHEMA_FACET_MINEXCLUSIVE:
1867 ret = xmlSchemaCompareValues(val, facet->val);
1868 if (ret == -2) {
1869 TODO /* error code */
1870 return(-1);
1871 }
1872 if (ret == 1)
1873 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00001874 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00001875 return(1);
1876 case XML_SCHEMA_FACET_MININCLUSIVE:
1877 ret = xmlSchemaCompareValues(val, facet->val);
1878 if (ret == -2) {
1879 TODO /* error code */
1880 return(-1);
1881 }
1882 if ((ret == 1) || (ret == 0))
1883 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00001884 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00001885 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00001886 case XML_SCHEMA_FACET_WHITESPACE:
1887 TODO /* whitespaces */
1888 return(0);
Daniel Veillarde19fc232002-04-22 16:01:24 +00001889 case XML_SCHEMA_FACET_MAXLENGTH:
1890 if ((facet->val != NULL) &&
1891 (facet->val->type == XML_SCHEMAS_DECIMAL) &&
1892 (facet->val->value.decimal.frac == 0)) {
Daniel Veillard118aed72002-09-24 14:13:13 +00001893 unsigned int len;
Daniel Veillarde19fc232002-04-22 16:01:24 +00001894
1895 if (facet->val->value.decimal.sign == 1)
1896 return(1);
1897 len = xmlUTF8Strlen(value);
1898 if (len > facet->val->value.decimal.base)
1899 return(1);
1900 return(0);
1901 }
1902 TODO /* error code */
1903 return(1);
Daniel Veillard88c58912002-04-23 07:12:20 +00001904 case XML_SCHEMA_FACET_ENUMERATION:
1905 if ((facet->value != NULL) &&
1906 (xmlStrEqual(facet->value, value)))
1907 return(0);
1908 return(1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001909 default:
1910 TODO
1911 }
1912 return(0);
1913}
1914
1915#endif /* LIBXML_SCHEMAS_ENABLED */