blob: e19391f162a27378657a86af75f4e7f6230887a6 [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 Veillardd4310742003-02-18 21:12:46 +00001196 if (cur[0] == 0)
1197 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001198 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1199 cur += 3;
1200 if (*cur != 0)
1201 return(1);
1202 if (val != NULL) {
1203 if (type == xmlSchemaTypeFloatDef) {
1204 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1205 if (v != NULL) {
1206 if (neg)
1207 v->value.f = (float) xmlXPathNINF;
1208 else
1209 v->value.f = (float) xmlXPathPINF;
1210 } else {
1211 xmlSchemaFreeValue(v);
1212 return(-1);
1213 }
1214 } else {
1215 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1216 if (v != NULL) {
1217 if (neg)
1218 v->value.d = xmlXPathNINF;
1219 else
1220 v->value.d = xmlXPathPINF;
1221 } else {
1222 xmlSchemaFreeValue(v);
1223 return(-1);
1224 }
1225 }
1226 *val = v;
1227 }
1228 return(0);
1229 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001230 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001231 cur++;
1232 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001233 if (*cur == '.') {
1234 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001235 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001236 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001237 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001238 if ((*cur == 'e') || (*cur == 'E')) {
1239 cur++;
1240 if (*cur == '-')
1241 cur++;
1242 while ((*cur >= '0') && (*cur <= '9'))
1243 cur++;
1244 }
1245 if (*cur != 0)
1246 return(1);
1247 if (val != NULL) {
1248 if (type == xmlSchemaTypeFloatDef) {
1249 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1250 if (v != NULL) {
1251 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1252 *val = v;
1253 } else {
1254 xmlGenericError(xmlGenericErrorContext,
1255 "failed to scanf float %s\n", value);
1256 xmlSchemaFreeValue(v);
1257 return(1);
1258 }
1259 } else {
1260 return(-1);
1261 }
1262 } else {
1263 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1264 if (v != NULL) {
1265 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1266 *val = v;
1267 } else {
1268 xmlGenericError(xmlGenericErrorContext,
1269 "failed to scanf double %s\n", value);
1270 xmlSchemaFreeValue(v);
1271 return(1);
1272 }
1273 } else {
1274 return(-1);
1275 }
1276 }
1277 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001278 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001279 } else if (type == xmlSchemaTypeNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001280 ret = xmlValidateName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001281 if ((ret == 0) && (val != NULL)) {
1282 TODO;
1283 }
1284 return(ret);
1285 } else if (type == xmlSchemaTypeQNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001286 ret = xmlValidateQName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001287 if ((ret == 0) && (val != NULL)) {
1288 TODO;
1289 }
1290 return(ret);
1291 } else if (type == xmlSchemaTypeNCNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001292 ret = xmlValidateNCName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001293 if ((ret == 0) && (val != NULL)) {
1294 TODO;
1295 }
1296 return(ret);
1297 } else if (type == xmlSchemaTypeAnyURIDef) {
1298 xmlURIPtr uri;
1299
1300 uri = xmlParseURI((const char *) value);
1301 if (uri == NULL)
1302 return(1);
1303 if (val != NULL) {
1304 TODO;
1305 }
1306 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001307 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001308 } else if (type == xmlSchemaTypeBooleanDef) {
1309 const xmlChar *cur = value;
1310
1311 if ((cur[0] == '0') && (cur[1] == 0))
1312 ret = 0;
1313 else if ((cur[0] == '1') && (cur[1] == 0))
1314 ret = 1;
1315 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1316 (cur[3] == 'e') && (cur[4] == 0))
1317 ret = 1;
1318 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1319 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1320 ret = 0;
1321 else
1322 return(1);
1323 if (val != NULL) {
1324 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1325 if (v != NULL) {
1326 v->value.b = ret;
1327 *val = v;
1328 } else {
1329 return(-1);
1330 }
1331 }
1332 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001333 } else {
1334 TODO
1335 return(0);
1336 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001337 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001338}
1339
1340/**
1341 * xmlSchemaCompareDecimals:
1342 * @x: a first decimal value
1343 * @y: a second decimal value
1344 *
1345 * Compare 2 decimals
1346 *
1347 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1348 */
1349static int
1350xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1351{
1352 xmlSchemaValPtr swp;
1353 int order = 1;
1354 unsigned long tmp;
1355
1356 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1357 order = -1;
1358 else if (x->value.decimal.sign)
1359 return (-1);
1360 else if (y->value.decimal.sign)
1361 return (1);
1362 if (x->value.decimal.frac == y->value.decimal.frac) {
1363 if (x->value.decimal.base < y->value.decimal.base)
1364 return (-1);
1365 return (x->value.decimal.base > y->value.decimal.base);
1366 }
1367 if (y->value.decimal.frac > x->value.decimal.frac) {
1368 swp = y;
1369 y = x;
1370 x = swp;
1371 order = -order;
1372 }
1373 tmp =
1374 x->value.decimal.base / powten[x->value.decimal.frac -
1375 y->value.decimal.frac];
1376 if (tmp > y->value.decimal.base)
1377 return (order);
1378 if (tmp < y->value.decimal.base)
1379 return (-order);
1380 tmp =
1381 y->value.decimal.base * powten[x->value.decimal.frac -
1382 y->value.decimal.frac];
1383 if (x->value.decimal.base < tmp)
1384 return (-order);
1385 if (x->value.decimal.base == tmp)
1386 return (0);
1387 return (order);
1388}
1389
1390/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001391 * xmlSchemaCompareDurations:
1392 * @x: a first duration value
1393 * @y: a second duration value
1394 *
1395 * Compare 2 durations
1396 *
1397 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1398 * case of error
1399 */
1400static int
1401xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1402{
1403 long carry, mon, day;
1404 double sec;
1405 long xmon, xday, myear, lyear, minday, maxday;
1406 static const long dayRange [2][12] = {
1407 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1408 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1409
1410 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001411 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001412
1413 /* months */
1414 mon = x->value.dur.mon - y->value.dur.mon;
1415
1416 /* seconds */
1417 sec = x->value.dur.sec - y->value.dur.sec;
1418 carry = (long)sec / SECS_PER_DAY;
1419 sec -= (double)(carry * SECS_PER_DAY);
1420
1421 /* days */
1422 day = x->value.dur.day - y->value.dur.day + carry;
1423
1424 /* easy test */
1425 if (mon == 0) {
1426 if (day == 0)
1427 if (sec == 0.0)
1428 return 0;
1429 else if (sec < 0.0)
1430 return -1;
1431 else
1432 return 1;
1433 else if (day < 0)
1434 return -1;
1435 else
1436 return 1;
1437 }
1438
1439 if (mon > 0) {
1440 if ((day >= 0) && (sec >= 0.0))
1441 return 1;
1442 else {
1443 xmon = mon;
1444 xday = -day;
1445 }
1446 } else if ((day <= 0) && (sec <= 0.0)) {
1447 return -1;
1448 } else {
1449 xmon = -mon;
1450 xday = day;
1451 }
1452
1453 myear = xmon / 12;
1454 lyear = myear / 4;
1455 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1456 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1457
1458 xmon = xmon % 12;
1459 minday += dayRange[0][xmon];
1460 maxday += dayRange[1][xmon];
1461
1462 if (maxday < xday)
1463 return 1;
1464 else if (minday > xday)
1465 return -1;
1466
1467 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001468 return 2;
1469}
1470
1471/*
1472 * macros for adding date/times and durations
1473 */
1474#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1475#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1476#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1477#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1478
1479/**
1480 * _xmlSchemaDateAdd:
1481 * @dt: an #xmlSchemaValPtr
1482 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1483 *
1484 * Compute a new date/time from @dt and @dur. This function assumes @dt
1485 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1486 * or #XML_SCHEMAS_GYEAR.
1487 *
1488 * Returns date/time pointer or NULL.
1489 */
1490static xmlSchemaValPtr
1491_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1492{
1493 xmlSchemaValPtr ret;
1494 long carry, tempdays, temp;
1495 xmlSchemaValDatePtr r, d;
1496 xmlSchemaValDurationPtr u;
1497
1498 if ((dt == NULL) || (dur == NULL))
1499 return NULL;
1500
1501 ret = xmlSchemaNewValue(dt->type);
1502 if (ret == NULL)
1503 return NULL;
1504
1505 r = &(ret->value.date);
1506 d = &(dt->value.date);
1507 u = &(dur->value.dur);
1508
1509 /* normalization */
1510 if (d->mon == 0)
1511 d->mon = 1;
1512
1513 /* normalize for time zone offset */
1514 u->sec -= (d->tzo * 60);
1515 d->tzo = 0;
1516
1517 /* normalization */
1518 if (d->day == 0)
1519 d->day = 1;
1520
1521 /* month */
1522 carry = d->mon + u->mon;
1523 r->mon = MODULO_RANGE(carry, 1, 13);
1524 carry = FQUOTIENT_RANGE(carry, 1, 13);
1525
1526 /* year (may be modified later) */
1527 r->year = d->year + carry;
1528 if (r->year == 0) {
1529 if (d->year > 0)
1530 r->year--;
1531 else
1532 r->year++;
1533 }
1534
1535 /* time zone */
1536 r->tzo = d->tzo;
1537 r->tz_flag = d->tz_flag;
1538
1539 /* seconds */
1540 r->sec = d->sec + u->sec;
1541 carry = FQUOTIENT((long)r->sec, 60);
1542 if (r->sec != 0.0) {
1543 r->sec = MODULO(r->sec, 60.0);
1544 }
1545
1546 /* minute */
1547 carry += d->min;
1548 r->min = MODULO(carry, 60);
1549 carry = FQUOTIENT(carry, 60);
1550
1551 /* hours */
1552 carry += d->hour;
1553 r->hour = MODULO(carry, 24);
1554 carry = FQUOTIENT(carry, 24);
1555
1556 /*
1557 * days
1558 * Note we use tempdays because the temporary values may need more
1559 * than 5 bits
1560 */
1561 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1562 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1563 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1564 else if (d->day < 1)
1565 tempdays = 1;
1566 else
1567 tempdays = d->day;
1568
1569 tempdays += u->day + carry;
1570
1571 while (1) {
1572 if (tempdays < 1) {
1573 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1574 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1575 if (tyr == 0)
1576 tyr--;
1577 tempdays += MAX_DAYINMONTH(tyr, tmon);
1578 carry = -1;
1579 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1580 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1581 carry = 1;
1582 } else
1583 break;
1584
1585 temp = r->mon + carry;
1586 r->mon = MODULO_RANGE(temp, 1, 13);
1587 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1588 if (r->year == 0) {
1589 if (temp < 1)
1590 r->year--;
1591 else
1592 r->year++;
1593 }
1594 }
1595
1596 r->day = tempdays;
1597
1598 /*
1599 * adjust the date/time type to the date values
1600 */
1601 if (ret->type != XML_SCHEMAS_DATETIME) {
1602 if ((r->hour) || (r->min) || (r->sec))
1603 ret->type = XML_SCHEMAS_DATETIME;
1604 else if (ret->type != XML_SCHEMAS_DATE) {
1605 if ((r->mon != 1) && (r->day != 1))
1606 ret->type = XML_SCHEMAS_DATE;
1607 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1608 ret->type = XML_SCHEMAS_GYEARMONTH;
1609 }
1610 }
1611
1612 return ret;
1613}
1614
1615/**
1616 * xmlSchemaDupVal:
1617 * @v: value to duplicate
1618 *
1619 * returns a duplicated value.
1620 */
1621static xmlSchemaValPtr
1622xmlSchemaDupVal (xmlSchemaValPtr v)
1623{
1624 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1625 if (ret == NULL)
1626 return ret;
1627
1628 memcpy(ret, v, sizeof(xmlSchemaVal));
1629 return ret;
1630}
1631
1632/**
1633 * xmlSchemaDateNormalize:
1634 * @dt: an #xmlSchemaValPtr
1635 *
1636 * Normalize @dt to GMT time.
1637 *
1638 */
1639static xmlSchemaValPtr
1640xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1641{
1642 xmlSchemaValPtr dur, ret;
1643
1644 if (dt == NULL)
1645 return NULL;
1646
1647 if (((dt->type != XML_SCHEMAS_TIME) &&
1648 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1649 return xmlSchemaDupVal(dt);
1650
1651 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1652 if (dur == NULL)
1653 return NULL;
1654
1655 dur->value.date.sec -= offset;
1656
1657 ret = _xmlSchemaDateAdd(dt, dur);
1658 if (ret == NULL)
1659 return NULL;
1660
1661 xmlSchemaFreeValue(dur);
1662
1663 /* ret->value.date.tzo = 0; */
1664 return ret;
1665}
1666
1667/**
1668 * _xmlSchemaDateCastYMToDays:
1669 * @dt: an #xmlSchemaValPtr
1670 *
1671 * Convert mon and year of @dt to total number of days. Take the
1672 * number of years since (or before) 1 AD and add the number of leap
1673 * years. This is a function because negative
1674 * years must be handled a little differently and there is no zero year.
1675 *
1676 * Returns number of days.
1677 */
1678static long
1679_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
1680{
1681 long ret;
1682
1683 if (dt->value.date.year < 0)
1684 ret = (dt->value.date.year * 365) +
1685 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1686 ((dt->value.date.year+1)/400)) +
1687 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1688 else
1689 ret = ((dt->value.date.year-1) * 365) +
1690 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1691 ((dt->value.date.year-1)/400)) +
1692 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1693
1694 return ret;
1695}
1696
1697/**
1698 * TIME_TO_NUMBER:
1699 * @dt: an #xmlSchemaValPtr
1700 *
1701 * Calculates the number of seconds in the time portion of @dt.
1702 *
1703 * Returns seconds.
1704 */
1705#define TIME_TO_NUMBER(dt) \
1706 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
1707 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
1708
1709/**
1710 * xmlSchemaCompareDates:
1711 * @x: a first date/time value
1712 * @y: a second date/time value
1713 *
1714 * Compare 2 date/times
1715 *
1716 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1717 * case of error
1718 */
1719static int
1720xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
1721{
1722 unsigned char xmask, ymask, xor_mask, and_mask;
1723 xmlSchemaValPtr p1, p2, q1, q2;
1724 long p1d, p2d, q1d, q2d;
1725
1726 if ((x == NULL) || (y == NULL))
1727 return -2;
1728
1729 if (x->value.date.tz_flag) {
1730
1731 if (!y->value.date.tz_flag) {
1732 p1 = xmlSchemaDateNormalize(x, 0);
1733 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1734 /* normalize y + 14:00 */
1735 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
1736
1737 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001738 if (p1d < q1d) {
1739 xmlSchemaFreeValue(p1);
1740 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001741 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001742 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001743 double sec;
1744
1745 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001746 if (sec < 0.0) {
1747 xmlSchemaFreeValue(p1);
1748 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001749 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001750 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001751 /* normalize y - 14:00 */
1752 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
1753 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001754 xmlSchemaFreeValue(p1);
1755 xmlSchemaFreeValue(q1);
1756 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001757 if (p1d > q2d)
1758 return 1;
1759 else if (p1d == q2d) {
1760 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
1761 if (sec > 0.0)
1762 return 1;
1763 else
1764 return 2; /* indeterminate */
1765 }
1766 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001767 } else {
1768 xmlSchemaFreeValue(p1);
1769 xmlSchemaFreeValue(q1);
1770 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001771 }
1772 } else if (y->value.date.tz_flag) {
1773 q1 = xmlSchemaDateNormalize(y, 0);
1774 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1775
1776 /* normalize x - 14:00 */
1777 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
1778 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1779
Daniel Veillardfdc91562002-07-01 21:52:03 +00001780 if (p1d < q1d) {
1781 xmlSchemaFreeValue(p1);
1782 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001783 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001784 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001785 double sec;
1786
1787 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001788 if (sec < 0.0) {
1789 xmlSchemaFreeValue(p1);
1790 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001791 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001792 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001793 /* normalize x + 14:00 */
1794 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
1795 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
1796
Daniel Veillardfdc91562002-07-01 21:52:03 +00001797 xmlSchemaFreeValue(p1);
1798 xmlSchemaFreeValue(q1);
1799 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001800 if (p2d > q1d)
1801 return 1;
1802 else if (p2d == q1d) {
1803 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
1804 if (sec > 0.0)
1805 return 1;
1806 else
1807 return 2; /* indeterminate */
1808 }
1809 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001810 } else {
1811 xmlSchemaFreeValue(p1);
1812 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001813 }
1814 }
1815
1816 /*
1817 * if the same type then calculate the difference
1818 */
1819 if (x->type == y->type) {
1820 q1 = xmlSchemaDateNormalize(y, 0);
1821 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1822
1823 p1 = xmlSchemaDateNormalize(x, 0);
1824 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1825
Daniel Veillardfdc91562002-07-01 21:52:03 +00001826 if (p1d < q1d) {
1827 xmlSchemaFreeValue(p1);
1828 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001829 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001830 } else if (p1d > q1d) {
1831 xmlSchemaFreeValue(p1);
1832 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001833 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001834 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001835 double sec;
1836
1837 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001838 xmlSchemaFreeValue(p1);
1839 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001840 if (sec < 0.0)
1841 return -1;
1842 else if (sec > 0.0)
1843 return 1;
1844
1845 }
1846 return 0;
1847 }
1848
1849 switch (x->type) {
1850 case XML_SCHEMAS_DATETIME:
1851 xmask = 0xf;
1852 break;
1853 case XML_SCHEMAS_DATE:
1854 xmask = 0x7;
1855 break;
1856 case XML_SCHEMAS_GYEAR:
1857 xmask = 0x1;
1858 break;
1859 case XML_SCHEMAS_GMONTH:
1860 xmask = 0x2;
1861 break;
1862 case XML_SCHEMAS_GDAY:
1863 xmask = 0x3;
1864 break;
1865 case XML_SCHEMAS_GYEARMONTH:
1866 xmask = 0x3;
1867 break;
1868 case XML_SCHEMAS_GMONTHDAY:
1869 xmask = 0x6;
1870 break;
1871 case XML_SCHEMAS_TIME:
1872 xmask = 0x8;
1873 break;
1874 default:
1875 xmask = 0;
1876 break;
1877 }
1878
1879 switch (y->type) {
1880 case XML_SCHEMAS_DATETIME:
1881 ymask = 0xf;
1882 break;
1883 case XML_SCHEMAS_DATE:
1884 ymask = 0x7;
1885 break;
1886 case XML_SCHEMAS_GYEAR:
1887 ymask = 0x1;
1888 break;
1889 case XML_SCHEMAS_GMONTH:
1890 ymask = 0x2;
1891 break;
1892 case XML_SCHEMAS_GDAY:
1893 ymask = 0x3;
1894 break;
1895 case XML_SCHEMAS_GYEARMONTH:
1896 ymask = 0x3;
1897 break;
1898 case XML_SCHEMAS_GMONTHDAY:
1899 ymask = 0x6;
1900 break;
1901 case XML_SCHEMAS_TIME:
1902 ymask = 0x8;
1903 break;
1904 default:
1905 ymask = 0;
1906 break;
1907 }
1908
1909 xor_mask = xmask ^ ymask; /* mark type differences */
1910 and_mask = xmask & ymask; /* mark field specification */
1911
1912 /* year */
1913 if (xor_mask & 1)
1914 return 2; /* indeterminate */
1915 else if (and_mask & 1) {
1916 if (x->value.date.year < y->value.date.year)
1917 return -1;
1918 else if (x->value.date.year > y->value.date.year)
1919 return 1;
1920 }
1921
1922 /* month */
1923 if (xor_mask & 2)
1924 return 2; /* indeterminate */
1925 else if (and_mask & 2) {
1926 if (x->value.date.mon < y->value.date.mon)
1927 return -1;
1928 else if (x->value.date.mon > y->value.date.mon)
1929 return 1;
1930 }
1931
1932 /* day */
1933 if (xor_mask & 4)
1934 return 2; /* indeterminate */
1935 else if (and_mask & 4) {
1936 if (x->value.date.day < y->value.date.day)
1937 return -1;
1938 else if (x->value.date.day > y->value.date.day)
1939 return 1;
1940 }
1941
1942 /* time */
1943 if (xor_mask & 8)
1944 return 2; /* indeterminate */
1945 else if (and_mask & 8) {
1946 if (x->value.date.hour < y->value.date.hour)
1947 return -1;
1948 else if (x->value.date.hour > y->value.date.hour)
1949 return 1;
1950 else if (x->value.date.min < y->value.date.min)
1951 return -1;
1952 else if (x->value.date.min > y->value.date.min)
1953 return 1;
1954 else if (x->value.date.sec < y->value.date.sec)
1955 return -1;
1956 else if (x->value.date.sec > y->value.date.sec)
1957 return 1;
1958 }
1959
Daniel Veillard070803b2002-05-03 07:29:38 +00001960 return 0;
1961}
1962
1963/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001964 * xmlSchemaCompareValues:
1965 * @x: a first value
1966 * @y: a second value
1967 *
1968 * Compare 2 values
1969 *
Daniel Veillard5a872412002-05-22 06:40:27 +00001970 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1971 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00001972 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00001973static int
Daniel Veillard4255d502002-04-16 15:50:10 +00001974xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
1975 if ((x == NULL) || (y == NULL))
1976 return(-2);
1977
1978 switch (x->type) {
1979 case XML_SCHEMAS_STRING:
1980 TODO
1981 case XML_SCHEMAS_DECIMAL:
1982 if (y->type == XML_SCHEMAS_DECIMAL)
1983 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00001984 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00001985 case XML_SCHEMAS_DURATION:
1986 if (y->type == XML_SCHEMAS_DURATION)
1987 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00001988 return(-2);
1989 case XML_SCHEMAS_TIME:
1990 case XML_SCHEMAS_GDAY:
1991 case XML_SCHEMAS_GMONTH:
1992 case XML_SCHEMAS_GMONTHDAY:
1993 case XML_SCHEMAS_GYEAR:
1994 case XML_SCHEMAS_GYEARMONTH:
1995 case XML_SCHEMAS_DATE:
1996 case XML_SCHEMAS_DATETIME:
1997 if ((y->type == XML_SCHEMAS_DATETIME) ||
1998 (y->type == XML_SCHEMAS_TIME) ||
1999 (y->type == XML_SCHEMAS_GDAY) ||
2000 (y->type == XML_SCHEMAS_GMONTH) ||
2001 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2002 (y->type == XML_SCHEMAS_GYEAR) ||
2003 (y->type == XML_SCHEMAS_DATE) ||
2004 (y->type == XML_SCHEMAS_GYEARMONTH))
2005 return (xmlSchemaCompareDates(x, y));
2006
2007 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002008 default:
2009 TODO
2010 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002011 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002012}
2013
2014/**
2015 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002016 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002017 * @facet: the facet to check
2018 * @value: the lexical repr of the value to validate
2019 * @val: the precomputed value
2020 *
2021 * Check a value against a facet condition
2022 *
2023 * Returns 0 if the element is schemas valid, a positive error code
2024 * number otherwise and -1 in case of internal or API error.
2025 */
2026int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002027xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002028 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002029 const xmlChar *value, xmlSchemaValPtr val)
2030{
2031 int ret;
2032
2033 switch (facet->type) {
2034 case XML_SCHEMA_FACET_PATTERN:
2035 ret = xmlRegexpExec(facet->regexp, value);
2036 if (ret == 1)
2037 return(0);
2038 if (ret == 0) {
2039 TODO /* error code */
2040 return(1);
2041 }
2042 return(ret);
2043 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2044 ret = xmlSchemaCompareValues(val, facet->val);
2045 if (ret == -2) {
2046 TODO /* error code */
2047 return(-1);
2048 }
2049 if (ret == -1)
2050 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002051 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002052 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002053 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2054 ret = xmlSchemaCompareValues(val, facet->val);
2055 if (ret == -2) {
2056 TODO /* error code */
2057 return(-1);
2058 }
2059 if ((ret == -1) || (ret == 0))
2060 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002061 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002062 return(1);
2063 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2064 ret = xmlSchemaCompareValues(val, facet->val);
2065 if (ret == -2) {
2066 TODO /* error code */
2067 return(-1);
2068 }
2069 if (ret == 1)
2070 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002071 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002072 return(1);
2073 case XML_SCHEMA_FACET_MININCLUSIVE:
2074 ret = xmlSchemaCompareValues(val, facet->val);
2075 if (ret == -2) {
2076 TODO /* error code */
2077 return(-1);
2078 }
2079 if ((ret == 1) || (ret == 0))
2080 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002081 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002082 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002083 case XML_SCHEMA_FACET_WHITESPACE:
2084 TODO /* whitespaces */
2085 return(0);
Daniel Veillarde19fc232002-04-22 16:01:24 +00002086 case XML_SCHEMA_FACET_MAXLENGTH:
2087 if ((facet->val != NULL) &&
2088 (facet->val->type == XML_SCHEMAS_DECIMAL) &&
2089 (facet->val->value.decimal.frac == 0)) {
Daniel Veillard118aed72002-09-24 14:13:13 +00002090 unsigned int len;
Daniel Veillarde19fc232002-04-22 16:01:24 +00002091
2092 if (facet->val->value.decimal.sign == 1)
2093 return(1);
2094 len = xmlUTF8Strlen(value);
2095 if (len > facet->val->value.decimal.base)
2096 return(1);
2097 return(0);
2098 }
2099 TODO /* error code */
2100 return(1);
Daniel Veillard88c58912002-04-23 07:12:20 +00002101 case XML_SCHEMA_FACET_ENUMERATION:
2102 if ((facet->value != NULL) &&
2103 (xmlStrEqual(facet->value, value)))
2104 return(0);
2105 return(1);
Daniel Veillard4255d502002-04-16 15:50:10 +00002106 default:
2107 TODO
2108 }
2109 return(0);
2110}
2111
2112#endif /* LIBXML_SCHEMAS_ENABLED */