blob: 374eddbb3a1180320df1a0454e3a9d74be28365a [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>
Daniel Veillard96a4b252003-02-06 08:22:32 +000021#include <libxml/xpath.h>
22#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000023
24#include <libxml/xmlschemas.h>
25#include <libxml/schemasInternals.h>
26#include <libxml/xmlschemastypes.h>
27
Daniel Veillard070803b2002-05-03 07:29:38 +000028#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31
Daniel Veillard4255d502002-04-16 15:50:10 +000032#define DEBUG
33
34#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
38
39#define XML_SCHEMAS_NAMESPACE_NAME \
40 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
41
42typedef enum {
43 XML_SCHEMAS_UNKNOWN = 0,
44 XML_SCHEMAS_STRING,
45 XML_SCHEMAS_NMTOKEN,
46 XML_SCHEMAS_DECIMAL,
Daniel Veillard070803b2002-05-03 07:29:38 +000047 XML_SCHEMAS_TIME,
48 XML_SCHEMAS_GDAY,
49 XML_SCHEMAS_GMONTH,
50 XML_SCHEMAS_GMONTHDAY,
51 XML_SCHEMAS_GYEAR,
52 XML_SCHEMAS_GYEARMONTH,
53 XML_SCHEMAS_DATE,
54 XML_SCHEMAS_DATETIME,
55 XML_SCHEMAS_DURATION,
Daniel Veillard84d70a42002-09-16 10:51:38 +000056 XML_SCHEMAS_FLOAT,
57 XML_SCHEMAS_DOUBLE,
Daniel Veillardc5a70f22003-02-06 23:41:59 +000058 XML_SCHEMAS_BOOLEAN,
Daniel Veillard96a4b252003-02-06 08:22:32 +000059 XML_SCHEMAS_INT,
Daniel Veillard4255d502002-04-16 15:50:10 +000060 XML_SCHEMAS_,
61 XML_SCHEMAS_XXX
62} xmlSchemaValType;
63
64unsigned long powten[10] = {
65 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
66 100000000L, 1000000000L
67};
68
Daniel Veillard070803b2002-05-03 07:29:38 +000069/* Date value */
70typedef struct _xmlSchemaValDate xmlSchemaValDate;
71typedef xmlSchemaValDate *xmlSchemaValDatePtr;
72struct _xmlSchemaValDate {
73 long year;
74 unsigned int mon :4; /* 1 <= mon <= 12 */
75 unsigned int day :5; /* 1 <= day <= 31 */
76 unsigned int hour :5; /* 0 <= hour <= 23 */
77 unsigned int min :6; /* 0 <= min <= 59 */
78 double sec;
79 int tz_flag :1; /* is tzo explicitely set? */
80 int tzo :11; /* -1440 <= tzo <= 1440 */
81};
82
83/* Duration value */
84typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
85typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
86struct _xmlSchemaValDuration {
87 long mon; /* mon stores years also */
88 long day;
89 double sec; /* sec stores min and hour also */
90};
91
Daniel Veillard4255d502002-04-16 15:50:10 +000092typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
93typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
94struct _xmlSchemaValDecimal {
95 /* would use long long but not portable */
96 unsigned long base;
97 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000098 unsigned int sign:1;
Daniel Veillard4255d502002-04-16 15:50:10 +000099 int frac:7;
100 int total:8;
101};
102
103struct _xmlSchemaVal {
104 xmlSchemaValType type;
105 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000106 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000107 xmlSchemaValDate date;
108 xmlSchemaValDuration dur;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000109 float f;
110 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000111 int b;
Daniel Veillard4255d502002-04-16 15:50:10 +0000112 } value;
113};
114
115static int xmlSchemaTypesInitialized = 0;
116static xmlHashTablePtr xmlSchemaTypesBank = NULL;
117
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000118/*
119 * Basic types
120 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000121static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
122static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
123static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
124static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000125static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000126static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000127static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
128static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
129static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
130static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
131static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
132static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
133static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000134static xmlSchemaTypePtr xmlSchemaTypeNmtoken = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000135static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000136static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000137static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard96a4b252003-02-06 08:22:32 +0000138static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000139static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
140static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000141
142/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000143 * Derived types
144 */
145static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
149static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
150static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
151static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
152static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
153static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
154static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
155static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
156static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
157static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000158static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000159
160/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000161 * xmlSchemaInitBasicType:
162 * @name: the type name
163 *
164 * Initialize one default type
165 */
166static xmlSchemaTypePtr
167xmlSchemaInitBasicType(const char *name) {
168 xmlSchemaTypePtr ret;
169
170 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
171 if (ret == NULL) {
172 xmlGenericError(xmlGenericErrorContext,
173 "Could not initilize type %s: out of memory\n", name);
174 return(NULL);
175 }
176 memset(ret, 0, sizeof(xmlSchemaType));
177 ret->name = xmlStrdup((const xmlChar *)name);
178 ret->type = XML_SCHEMA_TYPE_BASIC;
179 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
180 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
181 XML_SCHEMAS_NAMESPACE_NAME, ret);
182 return(ret);
183}
184
185/*
186 * xmlSchemaInitTypes:
187 *
188 * Initialize the default XML Schemas type library
189 */
190void
191xmlSchemaInitTypes(void) {
192 if (xmlSchemaTypesInitialized != 0)
193 return;
194 xmlSchemaTypesBank = xmlHashCreate(40);
195
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000196 /*
197 * primitive datatypes
198 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000199 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string");
200 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType");
201 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType");
202 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal");
203 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date");
Daniel Veillard070803b2002-05-03 07:29:38 +0000204 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime");
205 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time");
206 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear");
207 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth");
208 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth");
209 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay");
210 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay");
211 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration");
Daniel Veillard4255d502002-04-16 15:50:10 +0000212 xmlSchemaTypeNmtoken = xmlSchemaInitBasicType("NMTOKEN");
Daniel Veillard84d70a42002-09-16 10:51:38 +0000213 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float");
214 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double");
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000215 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean");
Daniel Veillard96a4b252003-02-06 08:22:32 +0000216 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name");
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000217 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName");
218 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI");
Daniel Veillard4255d502002-04-16 15:50:10 +0000219
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000220 /*
221 * derived datatypes
222 */
223 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer");;
224 xmlSchemaTypeNonPositiveIntegerDef = xmlSchemaInitBasicType("nonPositiveInteger");;
225 xmlSchemaTypeNegativeIntegerDef = xmlSchemaInitBasicType("negativeInteger");;
226 xmlSchemaTypeLongDef = xmlSchemaInitBasicType("long");;
227 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int");;
228 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short");;
229 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte");;
230 xmlSchemaTypeNonNegativeIntegerDef = xmlSchemaInitBasicType("nonNegativeInteger");
231 xmlSchemaTypeUnsignedLongDef = xmlSchemaInitBasicType("unsignedLong");;
232 xmlSchemaTypeUnsignedIntDef = xmlSchemaInitBasicType("unsignedInt");;
233 xmlSchemaTypeUnsignedShortDef = xmlSchemaInitBasicType("insignedShort");;
234 xmlSchemaTypeUnsignedByteDef = xmlSchemaInitBasicType("unsignedByte");;
235 xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger");
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000236 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName");
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000237
Daniel Veillard4255d502002-04-16 15:50:10 +0000238 xmlSchemaTypesInitialized = 1;
239}
240
241/**
242 * xmlSchemaCleanupTypes:
243 *
244 * Cleanup the default XML Schemas type library
245 */
246void
247xmlSchemaCleanupTypes(void) {
248 if (xmlSchemaTypesInitialized == 0)
249 return;
250 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
251 xmlSchemaTypesInitialized = 0;
252}
253
254/**
255 * xmlSchemaNewValue:
256 * @type: the value type
257 *
258 * Allocate a new simple type value
259 *
260 * Returns a pointer to the new value or NULL in case of error
261 */
262static xmlSchemaValPtr
263xmlSchemaNewValue(xmlSchemaValType type) {
264 xmlSchemaValPtr value;
265
266 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
267 if (value == NULL) {
268 return(NULL);
269 }
270 memset(value, 0, sizeof(xmlSchemaVal));
271 value->type = type;
272 return(value);
273}
274
275/**
276 * xmlSchemaFreeValue:
277 * @value: the value to free
278 *
279 * Cleanup the default XML Schemas type library
280 */
281void
282xmlSchemaFreeValue(xmlSchemaValPtr value) {
283 if (value == NULL)
284 return;
285 xmlFree(value);
286}
287
288/**
289 * xmlSchemaGetPredefinedType:
290 * @name: the type name
291 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
292 *
293 * Lookup a type in the default XML Schemas type library
294 *
295 * Returns the type if found, NULL otherwise
296 */
297xmlSchemaTypePtr
298xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
299 if (xmlSchemaTypesInitialized == 0)
300 xmlSchemaInitTypes();
301 if (name == NULL)
302 return(NULL);
303 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
304}
Daniel Veillard070803b2002-05-03 07:29:38 +0000305
306/****************************************************************
307 * *
308 * Convenience macros and functions *
309 * *
310 ****************************************************************/
311
312#define IS_TZO_CHAR(c) \
313 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
314
315#define VALID_YEAR(yr) (yr != 0)
316#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
317/* VALID_DAY should only be used when month is unknown */
318#define VALID_DAY(day) ((day >= 1) && (day <= 31))
319#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
320#define VALID_MIN(min) ((min >= 0) && (min <= 59))
321#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
322#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
323#define IS_LEAP(y) \
324 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
325
326static const long daysInMonth[12] =
327 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
328static const long daysInMonthLeap[12] =
329 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
330
Daniel Veillard5a872412002-05-22 06:40:27 +0000331#define MAX_DAYINMONTH(yr,mon) \
332 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
333
Daniel Veillard070803b2002-05-03 07:29:38 +0000334#define VALID_MDAY(dt) \
335 (IS_LEAP(dt->year) ? \
336 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
337 (dt->day <= daysInMonth[dt->mon - 1]))
338
339#define VALID_DATE(dt) \
340 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
341
342#define VALID_TIME(dt) \
343 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
344 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
345
346#define VALID_DATETIME(dt) \
347 (VALID_DATE(dt) && VALID_TIME(dt))
348
349#define SECS_PER_MIN (60)
350#define SECS_PER_HOUR (60 * SECS_PER_MIN)
351#define SECS_PER_DAY (24 * SECS_PER_HOUR)
352
Daniel Veillard5a872412002-05-22 06:40:27 +0000353static const long dayInYearByMonth[12] =
354 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
355static const long dayInLeapYearByMonth[12] =
356 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
357
358#define DAY_IN_YEAR(day, month, year) \
359 ((IS_LEAP(year) ? \
360 dayInLeapYearByMonth[month - 1] : \
361 dayInYearByMonth[month - 1]) + day)
362
363#ifdef DEBUG
364#define DEBUG_DATE(dt) \
365 xmlGenericError(xmlGenericErrorContext, \
366 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
367 dt->type,dt->value.date.year,dt->value.date.mon, \
368 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
369 dt->value.date.sec); \
370 if (dt->value.date.tz_flag) \
371 if (dt->value.date.tzo != 0) \
372 xmlGenericError(xmlGenericErrorContext, \
373 "%+05d\n",dt->value.date.tzo); \
374 else \
375 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
376 else \
377 xmlGenericError(xmlGenericErrorContext,"\n")
378#else
379#define DEBUG_DATE(dt)
380#endif
381
Daniel Veillard070803b2002-05-03 07:29:38 +0000382/**
383 * _xmlSchemaParseGYear:
384 * @dt: pointer to a date structure
385 * @str: pointer to the string to analyze
386 *
387 * Parses a xs:gYear without time zone and fills in the appropriate
388 * field of the @dt structure. @str is updated to point just after the
389 * xs:gYear. It is supposed that @dt->year is big enough to contain
390 * the year.
391 *
392 * Returns 0 or the error code
393 */
394static int
395_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
396 const xmlChar *cur = *str, *firstChar;
397 int isneg = 0, digcnt = 0;
398
399 if (((*cur < '0') || (*cur > '9')) &&
400 (*cur != '-') && (*cur != '+'))
401 return -1;
402
403 if (*cur == '-') {
404 isneg = 1;
405 cur++;
406 }
407
408 firstChar = cur;
409
410 while ((*cur >= '0') && (*cur <= '9')) {
411 dt->year = dt->year * 10 + (*cur - '0');
412 cur++;
413 digcnt++;
414 }
415
416 /* year must be at least 4 digits (CCYY); over 4
417 * digits cannot have a leading zero. */
418 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
419 return 1;
420
421 if (isneg)
422 dt->year = - dt->year;
423
424 if (!VALID_YEAR(dt->year))
425 return 2;
426
427 *str = cur;
428 return 0;
429}
430
431/**
432 * PARSE_2_DIGITS:
433 * @num: the integer to fill in
434 * @cur: an #xmlChar *
435 * @invalid: an integer
436 *
437 * Parses a 2-digits integer and updates @num with the value. @cur is
438 * updated to point just after the integer.
439 * In case of error, @invalid is set to %TRUE, values of @num and
440 * @cur are undefined.
441 */
442#define PARSE_2_DIGITS(num, cur, invalid) \
443 if ((cur[0] < '0') || (cur[0] > '9') || \
444 (cur[1] < '0') || (cur[1] > '9')) \
445 invalid = 1; \
446 else \
447 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
448 cur += 2;
449
450/**
451 * PARSE_FLOAT:
452 * @num: the double to fill in
453 * @cur: an #xmlChar *
454 * @invalid: an integer
455 *
456 * Parses a float and updates @num with the value. @cur is
457 * updated to point just after the float. The float must have a
458 * 2-digits integer part and may or may not have a decimal part.
459 * In case of error, @invalid is set to %TRUE, values of @num and
460 * @cur are undefined.
461 */
462#define PARSE_FLOAT(num, cur, invalid) \
463 PARSE_2_DIGITS(num, cur, invalid); \
464 if (!invalid && (*cur == '.')) { \
465 double mult = 1; \
466 cur++; \
467 if ((*cur < '0') || (*cur > '9')) \
468 invalid = 1; \
469 while ((*cur >= '0') && (*cur <= '9')) { \
470 mult /= 10; \
471 num += (*cur - '0') * mult; \
472 cur++; \
473 } \
474 }
475
476/**
477 * _xmlSchemaParseGMonth:
478 * @dt: pointer to a date structure
479 * @str: pointer to the string to analyze
480 *
481 * Parses a xs:gMonth without time zone and fills in the appropriate
482 * field of the @dt structure. @str is updated to point just after the
483 * xs:gMonth.
484 *
485 * Returns 0 or the error code
486 */
487static int
488_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
489 const xmlChar *cur = *str;
490 int ret = 0;
491
492 PARSE_2_DIGITS(dt->mon, cur, ret);
493 if (ret != 0)
494 return ret;
495
496 if (!VALID_MONTH(dt->mon))
497 return 2;
498
499 *str = cur;
500 return 0;
501}
502
503/**
504 * _xmlSchemaParseGDay:
505 * @dt: pointer to a date structure
506 * @str: pointer to the string to analyze
507 *
508 * Parses a xs:gDay without time zone and fills in the appropriate
509 * field of the @dt structure. @str is updated to point just after the
510 * xs:gDay.
511 *
512 * Returns 0 or the error code
513 */
514static int
515_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
516 const xmlChar *cur = *str;
517 int ret = 0;
518
519 PARSE_2_DIGITS(dt->day, cur, ret);
520 if (ret != 0)
521 return ret;
522
523 if (!VALID_DAY(dt->day))
524 return 2;
525
526 *str = cur;
527 return 0;
528}
529
530/**
531 * _xmlSchemaParseTime:
532 * @dt: pointer to a date structure
533 * @str: pointer to the string to analyze
534 *
535 * Parses a xs:time without time zone and fills in the appropriate
536 * fields of the @dt structure. @str is updated to point just after the
537 * xs:time.
538 * In case of error, values of @dt fields are undefined.
539 *
540 * Returns 0 or the error code
541 */
542static int
543_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
544 const xmlChar *cur = *str;
545 unsigned int hour = 0; /* use temp var in case str is not xs:time */
546 int ret = 0;
547
548 PARSE_2_DIGITS(hour, cur, ret);
549 if (ret != 0)
550 return ret;
551
552 if (*cur != ':')
553 return 1;
554 cur++;
555
556 /* the ':' insures this string is xs:time */
557 dt->hour = hour;
558
559 PARSE_2_DIGITS(dt->min, cur, ret);
560 if (ret != 0)
561 return ret;
562
563 if (*cur != ':')
564 return 1;
565 cur++;
566
567 PARSE_FLOAT(dt->sec, cur, ret);
568 if (ret != 0)
569 return ret;
570
571 if (!VALID_TIME(dt))
572 return 2;
573
574 *str = cur;
575 return 0;
576}
577
578/**
579 * _xmlSchemaParseTimeZone:
580 * @dt: pointer to a date structure
581 * @str: pointer to the string to analyze
582 *
583 * Parses a time zone without time zone and fills in the appropriate
584 * field of the @dt structure. @str is updated to point just after the
585 * time zone.
586 *
587 * Returns 0 or the error code
588 */
589static int
590_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
591 const xmlChar *cur = *str;
592 int ret = 0;
593
594 if (str == NULL)
595 return -1;
596
597 switch (*cur) {
598 case 0:
599 dt->tz_flag = 0;
600 dt->tzo = 0;
601 break;
602
603 case 'Z':
604 dt->tz_flag = 1;
605 dt->tzo = 0;
606 cur++;
607 break;
608
609 case '+':
610 case '-': {
611 int isneg = 0, tmp = 0;
612 isneg = (*cur == '-');
613
614 cur++;
615
616 PARSE_2_DIGITS(tmp, cur, ret);
617 if (ret != 0)
618 return ret;
619 if (!VALID_HOUR(tmp))
620 return 2;
621
622 if (*cur != ':')
623 return 1;
624 cur++;
625
626 dt->tzo = tmp * 60;
627
628 PARSE_2_DIGITS(tmp, cur, ret);
629 if (ret != 0)
630 return ret;
631 if (!VALID_MIN(tmp))
632 return 2;
633
634 dt->tzo += tmp;
635 if (isneg)
636 dt->tzo = - dt->tzo;
637
638 if (!VALID_TZO(dt->tzo))
639 return 2;
640
Daniel Veillard5a872412002-05-22 06:40:27 +0000641 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000642 break;
643 }
644 default:
645 return 1;
646 }
647
648 *str = cur;
649 return 0;
650}
651
652/****************************************************************
653 * *
654 * XML Schema Dates/Times Datatypes Handling *
655 * *
656 ****************************************************************/
657
658/**
659 * PARSE_DIGITS:
660 * @num: the integer to fill in
661 * @cur: an #xmlChar *
662 * @num_type: an integer flag
663 *
664 * Parses a digits integer and updates @num with the value. @cur is
665 * updated to point just after the integer.
666 * In case of error, @num_type is set to -1, values of @num and
667 * @cur are undefined.
668 */
669#define PARSE_DIGITS(num, cur, num_type) \
670 if ((*cur < '0') || (*cur > '9')) \
671 num_type = -1; \
672 else \
673 while ((*cur >= '0') && (*cur <= '9')) { \
674 num = num * 10 + (*cur - '0'); \
675 cur++; \
676 }
677
678/**
679 * PARSE_NUM:
680 * @num: the double to fill in
681 * @cur: an #xmlChar *
682 * @num_type: an integer flag
683 *
684 * Parses a float or integer and updates @num with the value. @cur is
685 * updated to point just after the number. If the number is a float,
686 * then it must have an integer part and a decimal part; @num_type will
687 * be set to 1. If there is no decimal part, @num_type is set to zero.
688 * In case of error, @num_type is set to -1, values of @num and
689 * @cur are undefined.
690 */
691#define PARSE_NUM(num, cur, num_type) \
692 num = 0; \
693 PARSE_DIGITS(num, cur, num_type); \
694 if (!num_type && (*cur == '.')) { \
695 double mult = 1; \
696 cur++; \
697 if ((*cur < '0') || (*cur > '9')) \
698 num_type = -1; \
699 else \
700 num_type = 1; \
701 while ((*cur >= '0') && (*cur <= '9')) { \
702 mult /= 10; \
703 num += (*cur - '0') * mult; \
704 cur++; \
705 } \
706 }
707
708/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000709 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000710 * @type: the predefined type
711 * @dateTime: string to analyze
712 * @val: the return computed value
713 *
714 * Check that @dateTime conforms to the lexical space of one of the date types.
715 * if true a value is computed and returned in @val.
716 *
717 * Returns 0 if this validates, a positive error code number otherwise
718 * and -1 in case of internal or API error.
719 */
720static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000721xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000722 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000723 xmlSchemaValPtr dt;
724 int ret;
725 const xmlChar *cur = dateTime;
726
727#define RETURN_TYPE_IF_VALID(t) \
728 if (IS_TZO_CHAR(*cur)) { \
729 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
730 if (ret == 0) { \
731 if (*cur != 0) \
732 goto error; \
733 dt->type = t; \
734 if (val != NULL) \
735 *val = dt; \
736 return 0; \
737 } \
738 }
739
740 if (dateTime == NULL)
741 return -1;
742
743 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
744 return 1;
745
746 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
747 if (dt == NULL)
748 return -1;
749
750 if ((cur[0] == '-') && (cur[1] == '-')) {
751 /*
752 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
753 * xs:gDay)
754 */
755 cur += 2;
756
757 /* is it an xs:gDay? */
758 if (*cur == '-') {
759 ++cur;
760 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
761 if (ret != 0)
762 goto error;
763
764 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
765
766 goto error;
767 }
768
769 /*
770 * it should be an xs:gMonthDay or xs:gMonth
771 */
772 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
773 if (ret != 0)
774 goto error;
775
776 if (*cur != '-')
777 goto error;
778 cur++;
779
780 /* is it an xs:gMonth? */
781 if (*cur == '-') {
782 cur++;
783 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
784 goto error;
785 }
786
787 /* it should be an xs:gMonthDay */
788 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
789 if (ret != 0)
790 goto error;
791
792 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
793
794 goto error;
795 }
796
797 /*
798 * It's a right-truncated date or an xs:time.
799 * Try to parse an xs:time then fallback on right-truncated dates.
800 */
801 if ((*cur >= '0') && (*cur <= '9')) {
802 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
803 if (ret == 0) {
804 /* it's an xs:time */
805 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
806 }
807 }
808
809 /* fallback on date parsing */
810 cur = dateTime;
811
812 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
813 if (ret != 0)
814 goto error;
815
816 /* is it an xs:gYear? */
817 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
818
819 if (*cur != '-')
820 goto error;
821 cur++;
822
823 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
824 if (ret != 0)
825 goto error;
826
827 /* is it an xs:gYearMonth? */
828 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
829
830 if (*cur != '-')
831 goto error;
832 cur++;
833
834 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
835 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
836 goto error;
837
838 /* is it an xs:date? */
839 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
840
841 if (*cur != 'T')
842 goto error;
843 cur++;
844
845 /* it should be an xs:dateTime */
846 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
847 if (ret != 0)
848 goto error;
849
850 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
851 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
852 goto error;
853
854 dt->type = XML_SCHEMAS_DATETIME;
855
856 if (val != NULL)
857 *val = dt;
858
859 return 0;
860
861error:
862 if (dt != NULL)
863 xmlSchemaFreeValue(dt);
864 return 1;
865}
866
867/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000868 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000869 * @type: the predefined type
870 * @duration: string to analyze
871 * @val: the return computed value
872 *
873 * Check that @duration conforms to the lexical space of the duration type.
874 * if true a value is computed and returned in @val.
875 *
876 * Returns 0 if this validates, a positive error code number otherwise
877 * and -1 in case of internal or API error.
878 */
879static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000880xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000881 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000882 const xmlChar *cur = duration;
883 xmlSchemaValPtr dur;
884 int isneg = 0;
885 unsigned int seq = 0;
886
887 if (duration == NULL)
888 return -1;
889
890 if (*cur == '-') {
891 isneg = 1;
892 cur++;
893 }
894
895 /* duration must start with 'P' (after sign) */
896 if (*cur++ != 'P')
897 return 1;
898
899 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
900 if (dur == NULL)
901 return -1;
902
903 while (*cur != 0) {
904 double num;
905 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
906 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
907 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
908
909 /* input string should be empty or invalid date/time item */
910 if (seq >= sizeof(desig))
911 goto error;
912
913 /* T designator must be present for time items */
914 if (*cur == 'T') {
915 if (seq <= 3) {
916 seq = 3;
917 cur++;
918 } else
919 return 1;
920 } else if (seq == 3)
921 goto error;
922
923 /* parse the number portion of the item */
924 PARSE_NUM(num, cur, num_type);
925
926 if ((num_type == -1) || (*cur == 0))
927 goto error;
928
929 /* update duration based on item type */
930 while (seq < sizeof(desig)) {
931 if (*cur == desig[seq]) {
932
933 /* verify numeric type; only seconds can be float */
934 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
935 goto error;
936
937 switch (seq) {
938 case 0:
939 dur->value.dur.mon = (long)num * 12;
940 break;
941 case 1:
942 dur->value.dur.mon += (long)num;
943 break;
944 default:
945 /* convert to seconds using multiplier */
946 dur->value.dur.sec += num * multi[seq];
947 seq++;
948 break;
949 }
950
951 break; /* exit loop */
952 }
953 /* no date designators found? */
954 if (++seq == 3)
955 goto error;
956 }
957 cur++;
958 }
959
960 if (isneg) {
961 dur->value.dur.mon = -dur->value.dur.mon;
962 dur->value.dur.day = -dur->value.dur.day;
963 dur->value.dur.sec = -dur->value.dur.sec;
964 }
965
966 if (val != NULL)
967 *val = dur;
968
969 return 0;
970
971error:
972 if (dur != NULL)
973 xmlSchemaFreeValue(dur);
974 return 1;
975}
976
Daniel Veillard96a4b252003-02-06 08:22:32 +0000977
978/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000979 * xmlSchemaValidatePredefinedType:
980 * @type: the predefined type
981 * @value: the value to check
982 * @val: the return computed value
983 *
984 * Check that a value conforms to the lexical space of the predefined type.
985 * if true a value is computed and returned in @val.
986 *
987 * Returns 0 if this validates, a positive error code number otherwise
988 * and -1 in case of internal or API error.
989 */
990int
991xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
992 xmlSchemaValPtr *val) {
993 xmlSchemaValPtr v;
Daniel Veillard96a4b252003-02-06 08:22:32 +0000994 int ret;
Daniel Veillard4255d502002-04-16 15:50:10 +0000995
996 if (xmlSchemaTypesInitialized == 0)
997 return(-1);
998 if (type == NULL)
999 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001000
Daniel Veillard4255d502002-04-16 15:50:10 +00001001 if (val != NULL)
1002 *val = NULL;
1003 if (type == xmlSchemaTypeStringDef) {
1004 return(0);
1005 } else if (type == xmlSchemaTypeAnyTypeDef) {
1006 return(0);
1007 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
1008 return(0);
1009 } else if (type == xmlSchemaTypeNmtoken) {
1010 if (xmlValidateNmtokenValue(value))
1011 return(0);
1012 return(1);
1013 } else if (type == xmlSchemaTypeDecimalDef) {
1014 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001015 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001016 unsigned long base = 0;
1017 if (cur == NULL)
1018 return(1);
1019 if (*cur == '+')
1020 cur++;
1021 else if (*cur == '-') {
1022 neg = 1;
1023 cur++;
1024 }
1025 tmp = cur;
1026 while ((*cur >= '0') && (*cur <= '9')) {
1027 base = base * 10 + (*cur - '0');
1028 cur++;
1029 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001030 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001031 if (*cur == '.') {
1032 cur++;
1033 tmp = cur;
1034 while ((*cur >= '0') && (*cur <= '9')) {
1035 base = base * 10 + (*cur - '0');
1036 cur++;
1037 }
1038 frac = cur - tmp;
1039 }
1040 if (*cur != 0)
1041 return(1);
1042 if (val != NULL) {
1043 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1044 if (v != NULL) {
1045 v->value.decimal.base = base;
1046 v->value.decimal.sign = neg;
1047 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001048 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001049 *val = v;
1050 }
1051 }
1052 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001053 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001054 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001055 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1056 (type == xmlSchemaTypeTimeDef) ||
1057 (type == xmlSchemaTypeDateDef) ||
1058 (type == xmlSchemaTypeGYearDef) ||
1059 (type == xmlSchemaTypeGYearMonthDef) ||
1060 (type == xmlSchemaTypeGMonthDef) ||
1061 (type == xmlSchemaTypeGMonthDayDef) ||
1062 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001063 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001064 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1065 const xmlChar *cur = value;
1066 unsigned long base = 0;
1067 int total = 0;
1068 if (cur == NULL)
1069 return(1);
1070 if (*cur == '+')
1071 cur++;
1072 while ((*cur >= '0') && (*cur <= '9')) {
1073 base = base * 10 + (*cur - '0');
1074 total++;
1075 cur++;
1076 }
1077 if (*cur != 0)
1078 return(1);
1079 if (val != NULL) {
1080 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1081 if (v != NULL) {
1082 v->value.decimal.base = base;
1083 v->value.decimal.sign = 0;
1084 v->value.decimal.frac = 0;
1085 v->value.decimal.total = total;
1086 *val = v;
1087 }
1088 }
1089 return(0);
1090 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1091 const xmlChar *cur = value;
1092 unsigned long base = 0;
1093 int total = 0;
1094 int sign = 0;
1095 if (cur == NULL)
1096 return(1);
1097 if (*cur == '-') {
1098 sign = 1;
1099 cur++;
1100 } else if (*cur == '+')
1101 cur++;
1102 while ((*cur >= '0') && (*cur <= '9')) {
1103 base = base * 10 + (*cur - '0');
1104 total++;
1105 cur++;
1106 }
1107 if (*cur != 0)
1108 return(1);
1109 if ((sign == 1) && (base != 0))
1110 return(1);
1111 if (val != NULL) {
1112 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1113 if (v != NULL) {
1114 v->value.decimal.base = base;
1115 v->value.decimal.sign = 0;
1116 v->value.decimal.frac = 0;
1117 v->value.decimal.total = total;
1118 *val = v;
1119 }
1120 }
1121 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001122 } else if (type == xmlSchemaTypeIntDef) {
1123 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001124 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001125 int total = 0;
1126 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001127 if (cur == NULL)
1128 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001129 if (*cur == '-') {
1130 sign = 1;
1131 cur++;
1132 } else if (*cur == '+')
1133 cur++;
1134 while (*cur == '0') {
1135 total++;
1136 cur++;
1137 }
1138 while ((*cur >= '0') && (*cur <= '9')) {
1139 base = base * 10 + (*cur - '0');
1140 total++;
1141 cur++;
1142 }
1143 if (*cur != 0)
1144 return(1);
1145 if ((sign == 1) && (total == 0))
1146 return(1);
1147 if (val != NULL) {
1148 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1149 if (v != NULL) {
1150 v->value.decimal.base = base;
1151 v->value.decimal.sign = sign;
1152 v->value.decimal.frac = 0;
1153 v->value.decimal.total = total;
1154 *val = v;
1155 }
1156 }
1157 return(0);
1158 } else if ((type == xmlSchemaTypeFloatDef) ||
1159 (type == xmlSchemaTypeDoubleDef)) {
1160 const xmlChar *cur = value;
1161 int neg = 0;
1162 if (cur == NULL)
1163 return(1);
1164 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1165 cur += 3;
1166 if (*cur != 0)
1167 return(1);
1168 if (val != NULL) {
1169 if (type == xmlSchemaTypeFloatDef) {
1170 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1171 if (v != NULL) {
1172 v->value.f = (float) xmlXPathNAN;
1173 } else {
1174 xmlSchemaFreeValue(v);
1175 return(-1);
1176 }
1177 } else {
1178 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1179 if (v != NULL) {
1180 v->value.d = xmlXPathNAN;
1181 } else {
1182 xmlSchemaFreeValue(v);
1183 return(-1);
1184 }
1185 }
1186 *val = v;
1187 }
1188 return(0);
1189 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001190 if (*cur == '+')
1191 cur++;
1192 else if (*cur == '-') {
1193 neg = 1;
1194 cur++;
1195 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001196 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1197 cur += 3;
1198 if (*cur != 0)
1199 return(1);
1200 if (val != NULL) {
1201 if (type == xmlSchemaTypeFloatDef) {
1202 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1203 if (v != NULL) {
1204 if (neg)
1205 v->value.f = (float) xmlXPathNINF;
1206 else
1207 v->value.f = (float) xmlXPathPINF;
1208 } else {
1209 xmlSchemaFreeValue(v);
1210 return(-1);
1211 }
1212 } else {
1213 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1214 if (v != NULL) {
1215 if (neg)
1216 v->value.d = xmlXPathNINF;
1217 else
1218 v->value.d = xmlXPathPINF;
1219 } else {
1220 xmlSchemaFreeValue(v);
1221 return(-1);
1222 }
1223 }
1224 *val = v;
1225 }
1226 return(0);
1227 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001228 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001229 cur++;
1230 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001231 if (*cur == '.') {
1232 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001233 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001234 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001235 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001236 if ((*cur == 'e') || (*cur == 'E')) {
1237 cur++;
1238 if (*cur == '-')
1239 cur++;
1240 while ((*cur >= '0') && (*cur <= '9'))
1241 cur++;
1242 }
1243 if (*cur != 0)
1244 return(1);
1245 if (val != NULL) {
1246 if (type == xmlSchemaTypeFloatDef) {
1247 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1248 if (v != NULL) {
1249 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1250 *val = v;
1251 } else {
1252 xmlGenericError(xmlGenericErrorContext,
1253 "failed to scanf float %s\n", value);
1254 xmlSchemaFreeValue(v);
1255 return(1);
1256 }
1257 } else {
1258 return(-1);
1259 }
1260 } else {
1261 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1262 if (v != NULL) {
1263 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1264 *val = v;
1265 } else {
1266 xmlGenericError(xmlGenericErrorContext,
1267 "failed to scanf double %s\n", value);
1268 xmlSchemaFreeValue(v);
1269 return(1);
1270 }
1271 } else {
1272 return(-1);
1273 }
1274 }
1275 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001276 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001277 } else if (type == xmlSchemaTypeNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001278 ret = xmlValidateName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001279 if ((ret == 0) && (val != NULL)) {
1280 TODO;
1281 }
1282 return(ret);
1283 } else if (type == xmlSchemaTypeQNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001284 ret = xmlValidateQName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001285 if ((ret == 0) && (val != NULL)) {
1286 TODO;
1287 }
1288 return(ret);
1289 } else if (type == xmlSchemaTypeNCNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001290 ret = xmlValidateNCName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001291 if ((ret == 0) && (val != NULL)) {
1292 TODO;
1293 }
1294 return(ret);
1295 } else if (type == xmlSchemaTypeAnyURIDef) {
1296 xmlURIPtr uri;
1297
1298 uri = xmlParseURI((const char *) value);
1299 if (uri == NULL)
1300 return(1);
1301 if (val != NULL) {
1302 TODO;
1303 }
1304 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001305 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001306 } else if (type == xmlSchemaTypeBooleanDef) {
1307 const xmlChar *cur = value;
1308
1309 if ((cur[0] == '0') && (cur[1] == 0))
1310 ret = 0;
1311 else if ((cur[0] == '1') && (cur[1] == 0))
1312 ret = 1;
1313 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1314 (cur[3] == 'e') && (cur[4] == 0))
1315 ret = 1;
1316 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1317 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1318 ret = 0;
1319 else
1320 return(1);
1321 if (val != NULL) {
1322 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1323 if (v != NULL) {
1324 v->value.b = ret;
1325 *val = v;
1326 } else {
1327 return(-1);
1328 }
1329 }
1330 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001331 } else {
1332 TODO
1333 return(0);
1334 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001335 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001336}
1337
1338/**
1339 * xmlSchemaCompareDecimals:
1340 * @x: a first decimal value
1341 * @y: a second decimal value
1342 *
1343 * Compare 2 decimals
1344 *
1345 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1346 */
1347static int
1348xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1349{
1350 xmlSchemaValPtr swp;
1351 int order = 1;
1352 unsigned long tmp;
1353
1354 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1355 order = -1;
1356 else if (x->value.decimal.sign)
1357 return (-1);
1358 else if (y->value.decimal.sign)
1359 return (1);
1360 if (x->value.decimal.frac == y->value.decimal.frac) {
1361 if (x->value.decimal.base < y->value.decimal.base)
1362 return (-1);
1363 return (x->value.decimal.base > y->value.decimal.base);
1364 }
1365 if (y->value.decimal.frac > x->value.decimal.frac) {
1366 swp = y;
1367 y = x;
1368 x = swp;
1369 order = -order;
1370 }
1371 tmp =
1372 x->value.decimal.base / powten[x->value.decimal.frac -
1373 y->value.decimal.frac];
1374 if (tmp > y->value.decimal.base)
1375 return (order);
1376 if (tmp < y->value.decimal.base)
1377 return (-order);
1378 tmp =
1379 y->value.decimal.base * powten[x->value.decimal.frac -
1380 y->value.decimal.frac];
1381 if (x->value.decimal.base < tmp)
1382 return (-order);
1383 if (x->value.decimal.base == tmp)
1384 return (0);
1385 return (order);
1386}
1387
1388/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001389 * xmlSchemaCompareDurations:
1390 * @x: a first duration value
1391 * @y: a second duration value
1392 *
1393 * Compare 2 durations
1394 *
1395 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1396 * case of error
1397 */
1398static int
1399xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1400{
1401 long carry, mon, day;
1402 double sec;
1403 long xmon, xday, myear, lyear, minday, maxday;
1404 static const long dayRange [2][12] = {
1405 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1406 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1407
1408 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001409 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001410
1411 /* months */
1412 mon = x->value.dur.mon - y->value.dur.mon;
1413
1414 /* seconds */
1415 sec = x->value.dur.sec - y->value.dur.sec;
1416 carry = (long)sec / SECS_PER_DAY;
1417 sec -= (double)(carry * SECS_PER_DAY);
1418
1419 /* days */
1420 day = x->value.dur.day - y->value.dur.day + carry;
1421
1422 /* easy test */
1423 if (mon == 0) {
1424 if (day == 0)
1425 if (sec == 0.0)
1426 return 0;
1427 else if (sec < 0.0)
1428 return -1;
1429 else
1430 return 1;
1431 else if (day < 0)
1432 return -1;
1433 else
1434 return 1;
1435 }
1436
1437 if (mon > 0) {
1438 if ((day >= 0) && (sec >= 0.0))
1439 return 1;
1440 else {
1441 xmon = mon;
1442 xday = -day;
1443 }
1444 } else if ((day <= 0) && (sec <= 0.0)) {
1445 return -1;
1446 } else {
1447 xmon = -mon;
1448 xday = day;
1449 }
1450
1451 myear = xmon / 12;
1452 lyear = myear / 4;
1453 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1454 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1455
1456 xmon = xmon % 12;
1457 minday += dayRange[0][xmon];
1458 maxday += dayRange[1][xmon];
1459
1460 if (maxday < xday)
1461 return 1;
1462 else if (minday > xday)
1463 return -1;
1464
1465 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001466 return 2;
1467}
1468
1469/*
1470 * macros for adding date/times and durations
1471 */
1472#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1473#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1474#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1475#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1476
1477/**
1478 * _xmlSchemaDateAdd:
1479 * @dt: an #xmlSchemaValPtr
1480 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1481 *
1482 * Compute a new date/time from @dt and @dur. This function assumes @dt
1483 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1484 * or #XML_SCHEMAS_GYEAR.
1485 *
1486 * Returns date/time pointer or NULL.
1487 */
1488static xmlSchemaValPtr
1489_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1490{
1491 xmlSchemaValPtr ret;
1492 long carry, tempdays, temp;
1493 xmlSchemaValDatePtr r, d;
1494 xmlSchemaValDurationPtr u;
1495
1496 if ((dt == NULL) || (dur == NULL))
1497 return NULL;
1498
1499 ret = xmlSchemaNewValue(dt->type);
1500 if (ret == NULL)
1501 return NULL;
1502
1503 r = &(ret->value.date);
1504 d = &(dt->value.date);
1505 u = &(dur->value.dur);
1506
1507 /* normalization */
1508 if (d->mon == 0)
1509 d->mon = 1;
1510
1511 /* normalize for time zone offset */
1512 u->sec -= (d->tzo * 60);
1513 d->tzo = 0;
1514
1515 /* normalization */
1516 if (d->day == 0)
1517 d->day = 1;
1518
1519 /* month */
1520 carry = d->mon + u->mon;
1521 r->mon = MODULO_RANGE(carry, 1, 13);
1522 carry = FQUOTIENT_RANGE(carry, 1, 13);
1523
1524 /* year (may be modified later) */
1525 r->year = d->year + carry;
1526 if (r->year == 0) {
1527 if (d->year > 0)
1528 r->year--;
1529 else
1530 r->year++;
1531 }
1532
1533 /* time zone */
1534 r->tzo = d->tzo;
1535 r->tz_flag = d->tz_flag;
1536
1537 /* seconds */
1538 r->sec = d->sec + u->sec;
1539 carry = FQUOTIENT((long)r->sec, 60);
1540 if (r->sec != 0.0) {
1541 r->sec = MODULO(r->sec, 60.0);
1542 }
1543
1544 /* minute */
1545 carry += d->min;
1546 r->min = MODULO(carry, 60);
1547 carry = FQUOTIENT(carry, 60);
1548
1549 /* hours */
1550 carry += d->hour;
1551 r->hour = MODULO(carry, 24);
1552 carry = FQUOTIENT(carry, 24);
1553
1554 /*
1555 * days
1556 * Note we use tempdays because the temporary values may need more
1557 * than 5 bits
1558 */
1559 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1560 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1561 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1562 else if (d->day < 1)
1563 tempdays = 1;
1564 else
1565 tempdays = d->day;
1566
1567 tempdays += u->day + carry;
1568
1569 while (1) {
1570 if (tempdays < 1) {
1571 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1572 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1573 if (tyr == 0)
1574 tyr--;
1575 tempdays += MAX_DAYINMONTH(tyr, tmon);
1576 carry = -1;
1577 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1578 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1579 carry = 1;
1580 } else
1581 break;
1582
1583 temp = r->mon + carry;
1584 r->mon = MODULO_RANGE(temp, 1, 13);
1585 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1586 if (r->year == 0) {
1587 if (temp < 1)
1588 r->year--;
1589 else
1590 r->year++;
1591 }
1592 }
1593
1594 r->day = tempdays;
1595
1596 /*
1597 * adjust the date/time type to the date values
1598 */
1599 if (ret->type != XML_SCHEMAS_DATETIME) {
1600 if ((r->hour) || (r->min) || (r->sec))
1601 ret->type = XML_SCHEMAS_DATETIME;
1602 else if (ret->type != XML_SCHEMAS_DATE) {
1603 if ((r->mon != 1) && (r->day != 1))
1604 ret->type = XML_SCHEMAS_DATE;
1605 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1606 ret->type = XML_SCHEMAS_GYEARMONTH;
1607 }
1608 }
1609
1610 return ret;
1611}
1612
1613/**
1614 * xmlSchemaDupVal:
1615 * @v: value to duplicate
1616 *
1617 * returns a duplicated value.
1618 */
1619static xmlSchemaValPtr
1620xmlSchemaDupVal (xmlSchemaValPtr v)
1621{
1622 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1623 if (ret == NULL)
1624 return ret;
1625
1626 memcpy(ret, v, sizeof(xmlSchemaVal));
1627 return ret;
1628}
1629
1630/**
1631 * xmlSchemaDateNormalize:
1632 * @dt: an #xmlSchemaValPtr
1633 *
1634 * Normalize @dt to GMT time.
1635 *
1636 */
1637static xmlSchemaValPtr
1638xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1639{
1640 xmlSchemaValPtr dur, ret;
1641
1642 if (dt == NULL)
1643 return NULL;
1644
1645 if (((dt->type != XML_SCHEMAS_TIME) &&
1646 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1647 return xmlSchemaDupVal(dt);
1648
1649 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1650 if (dur == NULL)
1651 return NULL;
1652
1653 dur->value.date.sec -= offset;
1654
1655 ret = _xmlSchemaDateAdd(dt, dur);
1656 if (ret == NULL)
1657 return NULL;
1658
1659 xmlSchemaFreeValue(dur);
1660
1661 /* ret->value.date.tzo = 0; */
1662 return ret;
1663}
1664
1665/**
1666 * _xmlSchemaDateCastYMToDays:
1667 * @dt: an #xmlSchemaValPtr
1668 *
1669 * Convert mon and year of @dt to total number of days. Take the
1670 * number of years since (or before) 1 AD and add the number of leap
1671 * years. This is a function because negative
1672 * years must be handled a little differently and there is no zero year.
1673 *
1674 * Returns number of days.
1675 */
1676static long
1677_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
1678{
1679 long ret;
1680
1681 if (dt->value.date.year < 0)
1682 ret = (dt->value.date.year * 365) +
1683 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1684 ((dt->value.date.year+1)/400)) +
1685 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1686 else
1687 ret = ((dt->value.date.year-1) * 365) +
1688 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1689 ((dt->value.date.year-1)/400)) +
1690 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1691
1692 return ret;
1693}
1694
1695/**
1696 * TIME_TO_NUMBER:
1697 * @dt: an #xmlSchemaValPtr
1698 *
1699 * Calculates the number of seconds in the time portion of @dt.
1700 *
1701 * Returns seconds.
1702 */
1703#define TIME_TO_NUMBER(dt) \
1704 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
1705 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
1706
1707/**
1708 * xmlSchemaCompareDates:
1709 * @x: a first date/time value
1710 * @y: a second date/time value
1711 *
1712 * Compare 2 date/times
1713 *
1714 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1715 * case of error
1716 */
1717static int
1718xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
1719{
1720 unsigned char xmask, ymask, xor_mask, and_mask;
1721 xmlSchemaValPtr p1, p2, q1, q2;
1722 long p1d, p2d, q1d, q2d;
1723
1724 if ((x == NULL) || (y == NULL))
1725 return -2;
1726
1727 if (x->value.date.tz_flag) {
1728
1729 if (!y->value.date.tz_flag) {
1730 p1 = xmlSchemaDateNormalize(x, 0);
1731 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1732 /* normalize y + 14:00 */
1733 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
1734
1735 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001736 if (p1d < q1d) {
1737 xmlSchemaFreeValue(p1);
1738 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001739 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001740 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001741 double sec;
1742
1743 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001744 if (sec < 0.0) {
1745 xmlSchemaFreeValue(p1);
1746 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001747 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001748 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001749 /* normalize y - 14:00 */
1750 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
1751 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001752 xmlSchemaFreeValue(p1);
1753 xmlSchemaFreeValue(q1);
1754 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001755 if (p1d > q2d)
1756 return 1;
1757 else if (p1d == q2d) {
1758 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
1759 if (sec > 0.0)
1760 return 1;
1761 else
1762 return 2; /* indeterminate */
1763 }
1764 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001765 } else {
1766 xmlSchemaFreeValue(p1);
1767 xmlSchemaFreeValue(q1);
1768 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001769 }
1770 } else if (y->value.date.tz_flag) {
1771 q1 = xmlSchemaDateNormalize(y, 0);
1772 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1773
1774 /* normalize x - 14:00 */
1775 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
1776 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1777
Daniel Veillardfdc91562002-07-01 21:52:03 +00001778 if (p1d < q1d) {
1779 xmlSchemaFreeValue(p1);
1780 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001781 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001782 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001783 double sec;
1784
1785 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001786 if (sec < 0.0) {
1787 xmlSchemaFreeValue(p1);
1788 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001789 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001790 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001791 /* normalize x + 14:00 */
1792 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
1793 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
1794
Daniel Veillardfdc91562002-07-01 21:52:03 +00001795 xmlSchemaFreeValue(p1);
1796 xmlSchemaFreeValue(q1);
1797 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001798 if (p2d > q1d)
1799 return 1;
1800 else if (p2d == q1d) {
1801 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
1802 if (sec > 0.0)
1803 return 1;
1804 else
1805 return 2; /* indeterminate */
1806 }
1807 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001808 } else {
1809 xmlSchemaFreeValue(p1);
1810 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001811 }
1812 }
1813
1814 /*
1815 * if the same type then calculate the difference
1816 */
1817 if (x->type == y->type) {
1818 q1 = xmlSchemaDateNormalize(y, 0);
1819 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1820
1821 p1 = xmlSchemaDateNormalize(x, 0);
1822 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1823
Daniel Veillardfdc91562002-07-01 21:52:03 +00001824 if (p1d < q1d) {
1825 xmlSchemaFreeValue(p1);
1826 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001827 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001828 } else if (p1d > q1d) {
1829 xmlSchemaFreeValue(p1);
1830 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001831 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001832 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001833 double sec;
1834
1835 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001836 xmlSchemaFreeValue(p1);
1837 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001838 if (sec < 0.0)
1839 return -1;
1840 else if (sec > 0.0)
1841 return 1;
1842
1843 }
1844 return 0;
1845 }
1846
1847 switch (x->type) {
1848 case XML_SCHEMAS_DATETIME:
1849 xmask = 0xf;
1850 break;
1851 case XML_SCHEMAS_DATE:
1852 xmask = 0x7;
1853 break;
1854 case XML_SCHEMAS_GYEAR:
1855 xmask = 0x1;
1856 break;
1857 case XML_SCHEMAS_GMONTH:
1858 xmask = 0x2;
1859 break;
1860 case XML_SCHEMAS_GDAY:
1861 xmask = 0x3;
1862 break;
1863 case XML_SCHEMAS_GYEARMONTH:
1864 xmask = 0x3;
1865 break;
1866 case XML_SCHEMAS_GMONTHDAY:
1867 xmask = 0x6;
1868 break;
1869 case XML_SCHEMAS_TIME:
1870 xmask = 0x8;
1871 break;
1872 default:
1873 xmask = 0;
1874 break;
1875 }
1876
1877 switch (y->type) {
1878 case XML_SCHEMAS_DATETIME:
1879 ymask = 0xf;
1880 break;
1881 case XML_SCHEMAS_DATE:
1882 ymask = 0x7;
1883 break;
1884 case XML_SCHEMAS_GYEAR:
1885 ymask = 0x1;
1886 break;
1887 case XML_SCHEMAS_GMONTH:
1888 ymask = 0x2;
1889 break;
1890 case XML_SCHEMAS_GDAY:
1891 ymask = 0x3;
1892 break;
1893 case XML_SCHEMAS_GYEARMONTH:
1894 ymask = 0x3;
1895 break;
1896 case XML_SCHEMAS_GMONTHDAY:
1897 ymask = 0x6;
1898 break;
1899 case XML_SCHEMAS_TIME:
1900 ymask = 0x8;
1901 break;
1902 default:
1903 ymask = 0;
1904 break;
1905 }
1906
1907 xor_mask = xmask ^ ymask; /* mark type differences */
1908 and_mask = xmask & ymask; /* mark field specification */
1909
1910 /* year */
1911 if (xor_mask & 1)
1912 return 2; /* indeterminate */
1913 else if (and_mask & 1) {
1914 if (x->value.date.year < y->value.date.year)
1915 return -1;
1916 else if (x->value.date.year > y->value.date.year)
1917 return 1;
1918 }
1919
1920 /* month */
1921 if (xor_mask & 2)
1922 return 2; /* indeterminate */
1923 else if (and_mask & 2) {
1924 if (x->value.date.mon < y->value.date.mon)
1925 return -1;
1926 else if (x->value.date.mon > y->value.date.mon)
1927 return 1;
1928 }
1929
1930 /* day */
1931 if (xor_mask & 4)
1932 return 2; /* indeterminate */
1933 else if (and_mask & 4) {
1934 if (x->value.date.day < y->value.date.day)
1935 return -1;
1936 else if (x->value.date.day > y->value.date.day)
1937 return 1;
1938 }
1939
1940 /* time */
1941 if (xor_mask & 8)
1942 return 2; /* indeterminate */
1943 else if (and_mask & 8) {
1944 if (x->value.date.hour < y->value.date.hour)
1945 return -1;
1946 else if (x->value.date.hour > y->value.date.hour)
1947 return 1;
1948 else if (x->value.date.min < y->value.date.min)
1949 return -1;
1950 else if (x->value.date.min > y->value.date.min)
1951 return 1;
1952 else if (x->value.date.sec < y->value.date.sec)
1953 return -1;
1954 else if (x->value.date.sec > y->value.date.sec)
1955 return 1;
1956 }
1957
Daniel Veillard070803b2002-05-03 07:29:38 +00001958 return 0;
1959}
1960
1961/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001962 * xmlSchemaCompareValues:
1963 * @x: a first value
1964 * @y: a second value
1965 *
1966 * Compare 2 values
1967 *
Daniel Veillard5a872412002-05-22 06:40:27 +00001968 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1969 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00001970 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00001971static int
Daniel Veillard4255d502002-04-16 15:50:10 +00001972xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
1973 if ((x == NULL) || (y == NULL))
1974 return(-2);
1975
1976 switch (x->type) {
1977 case XML_SCHEMAS_STRING:
1978 TODO
1979 case XML_SCHEMAS_DECIMAL:
1980 if (y->type == XML_SCHEMAS_DECIMAL)
1981 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00001982 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00001983 case XML_SCHEMAS_DURATION:
1984 if (y->type == XML_SCHEMAS_DURATION)
1985 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00001986 return(-2);
1987 case XML_SCHEMAS_TIME:
1988 case XML_SCHEMAS_GDAY:
1989 case XML_SCHEMAS_GMONTH:
1990 case XML_SCHEMAS_GMONTHDAY:
1991 case XML_SCHEMAS_GYEAR:
1992 case XML_SCHEMAS_GYEARMONTH:
1993 case XML_SCHEMAS_DATE:
1994 case XML_SCHEMAS_DATETIME:
1995 if ((y->type == XML_SCHEMAS_DATETIME) ||
1996 (y->type == XML_SCHEMAS_TIME) ||
1997 (y->type == XML_SCHEMAS_GDAY) ||
1998 (y->type == XML_SCHEMAS_GMONTH) ||
1999 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2000 (y->type == XML_SCHEMAS_GYEAR) ||
2001 (y->type == XML_SCHEMAS_DATE) ||
2002 (y->type == XML_SCHEMAS_GYEARMONTH))
2003 return (xmlSchemaCompareDates(x, y));
2004
2005 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002006 default:
2007 TODO
2008 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002009 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002010}
2011
2012/**
2013 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002014 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002015 * @facet: the facet to check
2016 * @value: the lexical repr of the value to validate
2017 * @val: the precomputed value
2018 *
2019 * Check a value against a facet condition
2020 *
2021 * Returns 0 if the element is schemas valid, a positive error code
2022 * number otherwise and -1 in case of internal or API error.
2023 */
2024int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002025xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002026 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002027 const xmlChar *value, xmlSchemaValPtr val)
2028{
2029 int ret;
2030
2031 switch (facet->type) {
2032 case XML_SCHEMA_FACET_PATTERN:
2033 ret = xmlRegexpExec(facet->regexp, value);
2034 if (ret == 1)
2035 return(0);
2036 if (ret == 0) {
2037 TODO /* error code */
2038 return(1);
2039 }
2040 return(ret);
2041 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2042 ret = xmlSchemaCompareValues(val, facet->val);
2043 if (ret == -2) {
2044 TODO /* error code */
2045 return(-1);
2046 }
2047 if (ret == -1)
2048 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002049 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002050 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002051 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2052 ret = xmlSchemaCompareValues(val, facet->val);
2053 if (ret == -2) {
2054 TODO /* error code */
2055 return(-1);
2056 }
2057 if ((ret == -1) || (ret == 0))
2058 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002059 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002060 return(1);
2061 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2062 ret = xmlSchemaCompareValues(val, facet->val);
2063 if (ret == -2) {
2064 TODO /* error code */
2065 return(-1);
2066 }
2067 if (ret == 1)
2068 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002069 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002070 return(1);
2071 case XML_SCHEMA_FACET_MININCLUSIVE:
2072 ret = xmlSchemaCompareValues(val, facet->val);
2073 if (ret == -2) {
2074 TODO /* error code */
2075 return(-1);
2076 }
2077 if ((ret == 1) || (ret == 0))
2078 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002079 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002080 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002081 case XML_SCHEMA_FACET_WHITESPACE:
2082 TODO /* whitespaces */
2083 return(0);
Daniel Veillarde19fc232002-04-22 16:01:24 +00002084 case XML_SCHEMA_FACET_MAXLENGTH:
2085 if ((facet->val != NULL) &&
2086 (facet->val->type == XML_SCHEMAS_DECIMAL) &&
2087 (facet->val->value.decimal.frac == 0)) {
Daniel Veillard118aed72002-09-24 14:13:13 +00002088 unsigned int len;
Daniel Veillarde19fc232002-04-22 16:01:24 +00002089
2090 if (facet->val->value.decimal.sign == 1)
2091 return(1);
2092 len = xmlUTF8Strlen(value);
2093 if (len > facet->val->value.decimal.base)
2094 return(1);
2095 return(0);
2096 }
2097 TODO /* error code */
2098 return(1);
Daniel Veillard88c58912002-04-23 07:12:20 +00002099 case XML_SCHEMA_FACET_ENUMERATION:
2100 if ((facet->value != NULL) &&
2101 (xmlStrEqual(facet->value, value)))
2102 return(0);
2103 return(1);
Daniel Veillard4255d502002-04-16 15:50:10 +00002104 default:
2105 TODO
2106 }
2107 return(0);
2108}
2109
2110#endif /* LIBXML_SCHEMAS_ENABLED */