blob: 89d30dbf812d97c963de78402b23ba160ed92f0a [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/**
979 * xmlSchemaValidateNCName:
980 * @value: the value to check
981 *
982 * Check that a value conforms to the lexical space of NCName
983 *
984 * Returns 0 if this validates, a positive error code number otherwise
985 * and -1 in case of internal or API error.
986 */
987static int
988xmlSchemaValidateNCName(const xmlChar *value) {
989 const xmlChar *cur = value;
990
991 /*
992 * First quick algorithm for ASCII range
993 */
994 while (IS_BLANK(*cur)) cur++;
995 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
996 (*cur == '_'))
997 cur++;
998 else
999 goto try_complex;
1000 while (((*cur >= 'a') && (*cur <= 'z')) ||
1001 ((*cur >= 'A') && (*cur <= 'Z')) ||
1002 ((*cur >= '0') && (*cur <= '9')) ||
1003 (*cur == '_') || (*cur == '-') || (*cur == '.'))
1004 cur++;
1005 while (IS_BLANK(*cur)) cur++;
1006 if (*cur == 0)
1007 return(0);
1008
1009try_complex:
1010 /*
1011 * Second check for chars outside the ASCII range
1012 */
1013 TODO
1014 return(0);
1015}
1016
1017/**
1018 * xmlSchemaValidateQName:
1019 * @value: the value to check
1020 *
1021 * Check that a value conforms to the lexical space of QName
1022 *
1023 * Returns 0 if this validates, a positive error code number otherwise
1024 * and -1 in case of internal or API error.
1025 */
1026static int
1027xmlSchemaValidateQName(const xmlChar *value) {
1028 const xmlChar *cur = value;
1029
1030 /*
1031 * First quick algorithm for ASCII range
1032 */
1033 while (IS_BLANK(*cur)) cur++;
1034 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
1035 (*cur == '_'))
1036 cur++;
1037 else
1038 goto try_complex;
1039 while (((*cur >= 'a') && (*cur <= 'z')) ||
1040 ((*cur >= 'A') && (*cur <= 'Z')) ||
1041 ((*cur >= '0') && (*cur <= '9')) ||
1042 (*cur == '_') || (*cur == '-') || (*cur == '.'))
1043 cur++;
1044 if (*cur == ':') {
1045 cur++;
1046 if (((*cur >= 'a') && (*cur <= 'z')) ||
1047 ((*cur >= 'A') && (*cur <= 'Z')) ||
1048 (*cur == '_'))
1049 cur++;
1050 else
1051 goto try_complex;
1052 while (((*cur >= 'a') && (*cur <= 'z')) ||
1053 ((*cur >= 'A') && (*cur <= 'Z')) ||
1054 ((*cur >= '0') && (*cur <= '9')) ||
1055 (*cur == '_') || (*cur == '-') || (*cur == '.'))
1056 cur++;
1057 }
1058 while (IS_BLANK(*cur)) cur++;
1059 if (*cur == 0)
1060 return(0);
1061
1062try_complex:
1063 /*
1064 * Second check for chars outside the ASCII range
1065 */
1066 TODO
1067 return(0);
1068}
1069
1070/**
1071 * xmlSchemaValidateName:
1072 * @value: the value to check
1073 *
1074 * Check that a value conforms to the lexical space of Name
1075 *
1076 * Returns 0 if this validates, a positive error code number otherwise
1077 * and -1 in case of internal or API error.
1078 */
1079static int
1080xmlSchemaValidateName(const xmlChar *value) {
1081 const xmlChar *cur = value;
1082
1083 /*
1084 * First quick algorithm for ASCII range
1085 */
1086 while (IS_BLANK(*cur)) cur++;
1087 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
1088 (*cur == '_') || (*cur == ':'))
1089 cur++;
1090 else
1091 goto try_complex;
1092 while (((*cur >= 'a') && (*cur <= 'z')) ||
1093 ((*cur >= 'A') && (*cur <= 'Z')) ||
1094 ((*cur >= '0') && (*cur <= '9')) ||
1095 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
1096 cur++;
1097 while (IS_BLANK(*cur)) cur++;
1098 if (*cur == 0)
1099 return(0);
1100
1101try_complex:
1102 /*
1103 * Second check for chars outside the ASCII range
1104 */
1105 TODO
1106 return(0);
1107}
Daniel Veillard4255d502002-04-16 15:50:10 +00001108/**
1109 * xmlSchemaValidatePredefinedType:
1110 * @type: the predefined type
1111 * @value: the value to check
1112 * @val: the return computed value
1113 *
1114 * Check that a value conforms to the lexical space of the predefined type.
1115 * if true a value is computed and returned in @val.
1116 *
1117 * Returns 0 if this validates, a positive error code number otherwise
1118 * and -1 in case of internal or API error.
1119 */
1120int
1121xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1122 xmlSchemaValPtr *val) {
1123 xmlSchemaValPtr v;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001124 int ret;
Daniel Veillard4255d502002-04-16 15:50:10 +00001125
1126 if (xmlSchemaTypesInitialized == 0)
1127 return(-1);
1128 if (type == NULL)
1129 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001130
Daniel Veillard4255d502002-04-16 15:50:10 +00001131 if (val != NULL)
1132 *val = NULL;
1133 if (type == xmlSchemaTypeStringDef) {
1134 return(0);
1135 } else if (type == xmlSchemaTypeAnyTypeDef) {
1136 return(0);
1137 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
1138 return(0);
1139 } else if (type == xmlSchemaTypeNmtoken) {
1140 if (xmlValidateNmtokenValue(value))
1141 return(0);
1142 return(1);
1143 } else if (type == xmlSchemaTypeDecimalDef) {
1144 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001145 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001146 unsigned long base = 0;
1147 if (cur == NULL)
1148 return(1);
1149 if (*cur == '+')
1150 cur++;
1151 else if (*cur == '-') {
1152 neg = 1;
1153 cur++;
1154 }
1155 tmp = cur;
1156 while ((*cur >= '0') && (*cur <= '9')) {
1157 base = base * 10 + (*cur - '0');
1158 cur++;
1159 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001160 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001161 if (*cur == '.') {
1162 cur++;
1163 tmp = cur;
1164 while ((*cur >= '0') && (*cur <= '9')) {
1165 base = base * 10 + (*cur - '0');
1166 cur++;
1167 }
1168 frac = cur - tmp;
1169 }
1170 if (*cur != 0)
1171 return(1);
1172 if (val != NULL) {
1173 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1174 if (v != NULL) {
1175 v->value.decimal.base = base;
1176 v->value.decimal.sign = neg;
1177 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001178 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001179 *val = v;
1180 }
1181 }
1182 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001183 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001184 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001185 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1186 (type == xmlSchemaTypeTimeDef) ||
1187 (type == xmlSchemaTypeDateDef) ||
1188 (type == xmlSchemaTypeGYearDef) ||
1189 (type == xmlSchemaTypeGYearMonthDef) ||
1190 (type == xmlSchemaTypeGMonthDef) ||
1191 (type == xmlSchemaTypeGMonthDayDef) ||
1192 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001193 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001194 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1195 const xmlChar *cur = value;
1196 unsigned long base = 0;
1197 int total = 0;
1198 if (cur == NULL)
1199 return(1);
1200 if (*cur == '+')
1201 cur++;
1202 while ((*cur >= '0') && (*cur <= '9')) {
1203 base = base * 10 + (*cur - '0');
1204 total++;
1205 cur++;
1206 }
1207 if (*cur != 0)
1208 return(1);
1209 if (val != NULL) {
1210 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1211 if (v != NULL) {
1212 v->value.decimal.base = base;
1213 v->value.decimal.sign = 0;
1214 v->value.decimal.frac = 0;
1215 v->value.decimal.total = total;
1216 *val = v;
1217 }
1218 }
1219 return(0);
1220 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1221 const xmlChar *cur = value;
1222 unsigned long base = 0;
1223 int total = 0;
1224 int sign = 0;
1225 if (cur == NULL)
1226 return(1);
1227 if (*cur == '-') {
1228 sign = 1;
1229 cur++;
1230 } else if (*cur == '+')
1231 cur++;
1232 while ((*cur >= '0') && (*cur <= '9')) {
1233 base = base * 10 + (*cur - '0');
1234 total++;
1235 cur++;
1236 }
1237 if (*cur != 0)
1238 return(1);
1239 if ((sign == 1) && (base != 0))
1240 return(1);
1241 if (val != NULL) {
1242 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1243 if (v != NULL) {
1244 v->value.decimal.base = base;
1245 v->value.decimal.sign = 0;
1246 v->value.decimal.frac = 0;
1247 v->value.decimal.total = total;
1248 *val = v;
1249 }
1250 }
1251 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001252 } else if (type == xmlSchemaTypeIntDef) {
1253 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001254 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001255 int total = 0;
1256 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001257 if (cur == NULL)
1258 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001259 if (*cur == '-') {
1260 sign = 1;
1261 cur++;
1262 } else if (*cur == '+')
1263 cur++;
1264 while (*cur == '0') {
1265 total++;
1266 cur++;
1267 }
1268 while ((*cur >= '0') && (*cur <= '9')) {
1269 base = base * 10 + (*cur - '0');
1270 total++;
1271 cur++;
1272 }
1273 if (*cur != 0)
1274 return(1);
1275 if ((sign == 1) && (total == 0))
1276 return(1);
1277 if (val != NULL) {
1278 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1279 if (v != NULL) {
1280 v->value.decimal.base = base;
1281 v->value.decimal.sign = sign;
1282 v->value.decimal.frac = 0;
1283 v->value.decimal.total = total;
1284 *val = v;
1285 }
1286 }
1287 return(0);
1288 } else if ((type == xmlSchemaTypeFloatDef) ||
1289 (type == xmlSchemaTypeDoubleDef)) {
1290 const xmlChar *cur = value;
1291 int neg = 0;
1292 if (cur == NULL)
1293 return(1);
1294 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1295 cur += 3;
1296 if (*cur != 0)
1297 return(1);
1298 if (val != NULL) {
1299 if (type == xmlSchemaTypeFloatDef) {
1300 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1301 if (v != NULL) {
1302 v->value.f = (float) xmlXPathNAN;
1303 } else {
1304 xmlSchemaFreeValue(v);
1305 return(-1);
1306 }
1307 } else {
1308 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1309 if (v != NULL) {
1310 v->value.d = xmlXPathNAN;
1311 } else {
1312 xmlSchemaFreeValue(v);
1313 return(-1);
1314 }
1315 }
1316 *val = v;
1317 }
1318 return(0);
1319 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001320 if (*cur == '+')
1321 cur++;
1322 else if (*cur == '-') {
1323 neg = 1;
1324 cur++;
1325 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001326 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1327 cur += 3;
1328 if (*cur != 0)
1329 return(1);
1330 if (val != NULL) {
1331 if (type == xmlSchemaTypeFloatDef) {
1332 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1333 if (v != NULL) {
1334 if (neg)
1335 v->value.f = (float) xmlXPathNINF;
1336 else
1337 v->value.f = (float) xmlXPathPINF;
1338 } else {
1339 xmlSchemaFreeValue(v);
1340 return(-1);
1341 }
1342 } else {
1343 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1344 if (v != NULL) {
1345 if (neg)
1346 v->value.d = xmlXPathNINF;
1347 else
1348 v->value.d = xmlXPathPINF;
1349 } else {
1350 xmlSchemaFreeValue(v);
1351 return(-1);
1352 }
1353 }
1354 *val = v;
1355 }
1356 return(0);
1357 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001358 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001359 cur++;
1360 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001361 if (*cur == '.') {
1362 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001363 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001364 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001365 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001366 if ((*cur == 'e') || (*cur == 'E')) {
1367 cur++;
1368 if (*cur == '-')
1369 cur++;
1370 while ((*cur >= '0') && (*cur <= '9'))
1371 cur++;
1372 }
1373 if (*cur != 0)
1374 return(1);
1375 if (val != NULL) {
1376 if (type == xmlSchemaTypeFloatDef) {
1377 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1378 if (v != NULL) {
1379 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1380 *val = v;
1381 } else {
1382 xmlGenericError(xmlGenericErrorContext,
1383 "failed to scanf float %s\n", value);
1384 xmlSchemaFreeValue(v);
1385 return(1);
1386 }
1387 } else {
1388 return(-1);
1389 }
1390 } else {
1391 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1392 if (v != NULL) {
1393 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1394 *val = v;
1395 } else {
1396 xmlGenericError(xmlGenericErrorContext,
1397 "failed to scanf double %s\n", value);
1398 xmlSchemaFreeValue(v);
1399 return(1);
1400 }
1401 } else {
1402 return(-1);
1403 }
1404 }
1405 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001406 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001407 } else if (type == xmlSchemaTypeNameDef) {
1408 ret = xmlSchemaValidateName(value);
1409 if ((ret == 0) && (val != NULL)) {
1410 TODO;
1411 }
1412 return(ret);
1413 } else if (type == xmlSchemaTypeQNameDef) {
1414 ret = xmlSchemaValidateQName(value);
1415 if ((ret == 0) && (val != NULL)) {
1416 TODO;
1417 }
1418 return(ret);
1419 } else if (type == xmlSchemaTypeNCNameDef) {
1420 ret = xmlSchemaValidateNCName(value);
1421 if ((ret == 0) && (val != NULL)) {
1422 TODO;
1423 }
1424 return(ret);
1425 } else if (type == xmlSchemaTypeAnyURIDef) {
1426 xmlURIPtr uri;
1427
1428 uri = xmlParseURI((const char *) value);
1429 if (uri == NULL)
1430 return(1);
1431 if (val != NULL) {
1432 TODO;
1433 }
1434 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001435 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001436 } else if (type == xmlSchemaTypeBooleanDef) {
1437 const xmlChar *cur = value;
1438
1439 if ((cur[0] == '0') && (cur[1] == 0))
1440 ret = 0;
1441 else if ((cur[0] == '1') && (cur[1] == 0))
1442 ret = 1;
1443 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1444 (cur[3] == 'e') && (cur[4] == 0))
1445 ret = 1;
1446 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1447 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1448 ret = 0;
1449 else
1450 return(1);
1451 if (val != NULL) {
1452 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1453 if (v != NULL) {
1454 v->value.b = ret;
1455 *val = v;
1456 } else {
1457 return(-1);
1458 }
1459 }
1460 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001461 } else {
1462 TODO
1463 return(0);
1464 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001465 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001466}
1467
1468/**
1469 * xmlSchemaCompareDecimals:
1470 * @x: a first decimal value
1471 * @y: a second decimal value
1472 *
1473 * Compare 2 decimals
1474 *
1475 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1476 */
1477static int
1478xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1479{
1480 xmlSchemaValPtr swp;
1481 int order = 1;
1482 unsigned long tmp;
1483
1484 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1485 order = -1;
1486 else if (x->value.decimal.sign)
1487 return (-1);
1488 else if (y->value.decimal.sign)
1489 return (1);
1490 if (x->value.decimal.frac == y->value.decimal.frac) {
1491 if (x->value.decimal.base < y->value.decimal.base)
1492 return (-1);
1493 return (x->value.decimal.base > y->value.decimal.base);
1494 }
1495 if (y->value.decimal.frac > x->value.decimal.frac) {
1496 swp = y;
1497 y = x;
1498 x = swp;
1499 order = -order;
1500 }
1501 tmp =
1502 x->value.decimal.base / powten[x->value.decimal.frac -
1503 y->value.decimal.frac];
1504 if (tmp > y->value.decimal.base)
1505 return (order);
1506 if (tmp < y->value.decimal.base)
1507 return (-order);
1508 tmp =
1509 y->value.decimal.base * powten[x->value.decimal.frac -
1510 y->value.decimal.frac];
1511 if (x->value.decimal.base < tmp)
1512 return (-order);
1513 if (x->value.decimal.base == tmp)
1514 return (0);
1515 return (order);
1516}
1517
1518/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001519 * xmlSchemaCompareDurations:
1520 * @x: a first duration value
1521 * @y: a second duration value
1522 *
1523 * Compare 2 durations
1524 *
1525 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1526 * case of error
1527 */
1528static int
1529xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1530{
1531 long carry, mon, day;
1532 double sec;
1533 long xmon, xday, myear, lyear, minday, maxday;
1534 static const long dayRange [2][12] = {
1535 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1536 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1537
1538 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001539 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001540
1541 /* months */
1542 mon = x->value.dur.mon - y->value.dur.mon;
1543
1544 /* seconds */
1545 sec = x->value.dur.sec - y->value.dur.sec;
1546 carry = (long)sec / SECS_PER_DAY;
1547 sec -= (double)(carry * SECS_PER_DAY);
1548
1549 /* days */
1550 day = x->value.dur.day - y->value.dur.day + carry;
1551
1552 /* easy test */
1553 if (mon == 0) {
1554 if (day == 0)
1555 if (sec == 0.0)
1556 return 0;
1557 else if (sec < 0.0)
1558 return -1;
1559 else
1560 return 1;
1561 else if (day < 0)
1562 return -1;
1563 else
1564 return 1;
1565 }
1566
1567 if (mon > 0) {
1568 if ((day >= 0) && (sec >= 0.0))
1569 return 1;
1570 else {
1571 xmon = mon;
1572 xday = -day;
1573 }
1574 } else if ((day <= 0) && (sec <= 0.0)) {
1575 return -1;
1576 } else {
1577 xmon = -mon;
1578 xday = day;
1579 }
1580
1581 myear = xmon / 12;
1582 lyear = myear / 4;
1583 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1584 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1585
1586 xmon = xmon % 12;
1587 minday += dayRange[0][xmon];
1588 maxday += dayRange[1][xmon];
1589
1590 if (maxday < xday)
1591 return 1;
1592 else if (minday > xday)
1593 return -1;
1594
1595 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001596 return 2;
1597}
1598
1599/*
1600 * macros for adding date/times and durations
1601 */
1602#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1603#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1604#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1605#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1606
1607/**
1608 * _xmlSchemaDateAdd:
1609 * @dt: an #xmlSchemaValPtr
1610 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1611 *
1612 * Compute a new date/time from @dt and @dur. This function assumes @dt
1613 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1614 * or #XML_SCHEMAS_GYEAR.
1615 *
1616 * Returns date/time pointer or NULL.
1617 */
1618static xmlSchemaValPtr
1619_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1620{
1621 xmlSchemaValPtr ret;
1622 long carry, tempdays, temp;
1623 xmlSchemaValDatePtr r, d;
1624 xmlSchemaValDurationPtr u;
1625
1626 if ((dt == NULL) || (dur == NULL))
1627 return NULL;
1628
1629 ret = xmlSchemaNewValue(dt->type);
1630 if (ret == NULL)
1631 return NULL;
1632
1633 r = &(ret->value.date);
1634 d = &(dt->value.date);
1635 u = &(dur->value.dur);
1636
1637 /* normalization */
1638 if (d->mon == 0)
1639 d->mon = 1;
1640
1641 /* normalize for time zone offset */
1642 u->sec -= (d->tzo * 60);
1643 d->tzo = 0;
1644
1645 /* normalization */
1646 if (d->day == 0)
1647 d->day = 1;
1648
1649 /* month */
1650 carry = d->mon + u->mon;
1651 r->mon = MODULO_RANGE(carry, 1, 13);
1652 carry = FQUOTIENT_RANGE(carry, 1, 13);
1653
1654 /* year (may be modified later) */
1655 r->year = d->year + carry;
1656 if (r->year == 0) {
1657 if (d->year > 0)
1658 r->year--;
1659 else
1660 r->year++;
1661 }
1662
1663 /* time zone */
1664 r->tzo = d->tzo;
1665 r->tz_flag = d->tz_flag;
1666
1667 /* seconds */
1668 r->sec = d->sec + u->sec;
1669 carry = FQUOTIENT((long)r->sec, 60);
1670 if (r->sec != 0.0) {
1671 r->sec = MODULO(r->sec, 60.0);
1672 }
1673
1674 /* minute */
1675 carry += d->min;
1676 r->min = MODULO(carry, 60);
1677 carry = FQUOTIENT(carry, 60);
1678
1679 /* hours */
1680 carry += d->hour;
1681 r->hour = MODULO(carry, 24);
1682 carry = FQUOTIENT(carry, 24);
1683
1684 /*
1685 * days
1686 * Note we use tempdays because the temporary values may need more
1687 * than 5 bits
1688 */
1689 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1690 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1691 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1692 else if (d->day < 1)
1693 tempdays = 1;
1694 else
1695 tempdays = d->day;
1696
1697 tempdays += u->day + carry;
1698
1699 while (1) {
1700 if (tempdays < 1) {
1701 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1702 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1703 if (tyr == 0)
1704 tyr--;
1705 tempdays += MAX_DAYINMONTH(tyr, tmon);
1706 carry = -1;
1707 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1708 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1709 carry = 1;
1710 } else
1711 break;
1712
1713 temp = r->mon + carry;
1714 r->mon = MODULO_RANGE(temp, 1, 13);
1715 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1716 if (r->year == 0) {
1717 if (temp < 1)
1718 r->year--;
1719 else
1720 r->year++;
1721 }
1722 }
1723
1724 r->day = tempdays;
1725
1726 /*
1727 * adjust the date/time type to the date values
1728 */
1729 if (ret->type != XML_SCHEMAS_DATETIME) {
1730 if ((r->hour) || (r->min) || (r->sec))
1731 ret->type = XML_SCHEMAS_DATETIME;
1732 else if (ret->type != XML_SCHEMAS_DATE) {
1733 if ((r->mon != 1) && (r->day != 1))
1734 ret->type = XML_SCHEMAS_DATE;
1735 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1736 ret->type = XML_SCHEMAS_GYEARMONTH;
1737 }
1738 }
1739
1740 return ret;
1741}
1742
1743/**
1744 * xmlSchemaDupVal:
1745 * @v: value to duplicate
1746 *
1747 * returns a duplicated value.
1748 */
1749static xmlSchemaValPtr
1750xmlSchemaDupVal (xmlSchemaValPtr v)
1751{
1752 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1753 if (ret == NULL)
1754 return ret;
1755
1756 memcpy(ret, v, sizeof(xmlSchemaVal));
1757 return ret;
1758}
1759
1760/**
1761 * xmlSchemaDateNormalize:
1762 * @dt: an #xmlSchemaValPtr
1763 *
1764 * Normalize @dt to GMT time.
1765 *
1766 */
1767static xmlSchemaValPtr
1768xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1769{
1770 xmlSchemaValPtr dur, ret;
1771
1772 if (dt == NULL)
1773 return NULL;
1774
1775 if (((dt->type != XML_SCHEMAS_TIME) &&
1776 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1777 return xmlSchemaDupVal(dt);
1778
1779 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1780 if (dur == NULL)
1781 return NULL;
1782
1783 dur->value.date.sec -= offset;
1784
1785 ret = _xmlSchemaDateAdd(dt, dur);
1786 if (ret == NULL)
1787 return NULL;
1788
1789 xmlSchemaFreeValue(dur);
1790
1791 /* ret->value.date.tzo = 0; */
1792 return ret;
1793}
1794
1795/**
1796 * _xmlSchemaDateCastYMToDays:
1797 * @dt: an #xmlSchemaValPtr
1798 *
1799 * Convert mon and year of @dt to total number of days. Take the
1800 * number of years since (or before) 1 AD and add the number of leap
1801 * years. This is a function because negative
1802 * years must be handled a little differently and there is no zero year.
1803 *
1804 * Returns number of days.
1805 */
1806static long
1807_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
1808{
1809 long ret;
1810
1811 if (dt->value.date.year < 0)
1812 ret = (dt->value.date.year * 365) +
1813 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1814 ((dt->value.date.year+1)/400)) +
1815 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1816 else
1817 ret = ((dt->value.date.year-1) * 365) +
1818 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1819 ((dt->value.date.year-1)/400)) +
1820 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1821
1822 return ret;
1823}
1824
1825/**
1826 * TIME_TO_NUMBER:
1827 * @dt: an #xmlSchemaValPtr
1828 *
1829 * Calculates the number of seconds in the time portion of @dt.
1830 *
1831 * Returns seconds.
1832 */
1833#define TIME_TO_NUMBER(dt) \
1834 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
1835 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
1836
1837/**
1838 * xmlSchemaCompareDates:
1839 * @x: a first date/time value
1840 * @y: a second date/time value
1841 *
1842 * Compare 2 date/times
1843 *
1844 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1845 * case of error
1846 */
1847static int
1848xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
1849{
1850 unsigned char xmask, ymask, xor_mask, and_mask;
1851 xmlSchemaValPtr p1, p2, q1, q2;
1852 long p1d, p2d, q1d, q2d;
1853
1854 if ((x == NULL) || (y == NULL))
1855 return -2;
1856
1857 if (x->value.date.tz_flag) {
1858
1859 if (!y->value.date.tz_flag) {
1860 p1 = xmlSchemaDateNormalize(x, 0);
1861 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1862 /* normalize y + 14:00 */
1863 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
1864
1865 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001866 if (p1d < q1d) {
1867 xmlSchemaFreeValue(p1);
1868 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001869 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001870 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001871 double sec;
1872
1873 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001874 if (sec < 0.0) {
1875 xmlSchemaFreeValue(p1);
1876 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001877 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001878 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001879 /* normalize y - 14:00 */
1880 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
1881 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001882 xmlSchemaFreeValue(p1);
1883 xmlSchemaFreeValue(q1);
1884 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001885 if (p1d > q2d)
1886 return 1;
1887 else if (p1d == q2d) {
1888 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
1889 if (sec > 0.0)
1890 return 1;
1891 else
1892 return 2; /* indeterminate */
1893 }
1894 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001895 } else {
1896 xmlSchemaFreeValue(p1);
1897 xmlSchemaFreeValue(q1);
1898 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001899 }
1900 } else if (y->value.date.tz_flag) {
1901 q1 = xmlSchemaDateNormalize(y, 0);
1902 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1903
1904 /* normalize x - 14:00 */
1905 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
1906 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1907
Daniel Veillardfdc91562002-07-01 21:52:03 +00001908 if (p1d < q1d) {
1909 xmlSchemaFreeValue(p1);
1910 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001911 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001912 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001913 double sec;
1914
1915 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001916 if (sec < 0.0) {
1917 xmlSchemaFreeValue(p1);
1918 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001919 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001920 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001921 /* normalize x + 14:00 */
1922 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
1923 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
1924
Daniel Veillardfdc91562002-07-01 21:52:03 +00001925 xmlSchemaFreeValue(p1);
1926 xmlSchemaFreeValue(q1);
1927 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001928 if (p2d > q1d)
1929 return 1;
1930 else if (p2d == q1d) {
1931 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
1932 if (sec > 0.0)
1933 return 1;
1934 else
1935 return 2; /* indeterminate */
1936 }
1937 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001938 } else {
1939 xmlSchemaFreeValue(p1);
1940 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001941 }
1942 }
1943
1944 /*
1945 * if the same type then calculate the difference
1946 */
1947 if (x->type == y->type) {
1948 q1 = xmlSchemaDateNormalize(y, 0);
1949 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1950
1951 p1 = xmlSchemaDateNormalize(x, 0);
1952 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1953
Daniel Veillardfdc91562002-07-01 21:52:03 +00001954 if (p1d < q1d) {
1955 xmlSchemaFreeValue(p1);
1956 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001957 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001958 } else if (p1d > q1d) {
1959 xmlSchemaFreeValue(p1);
1960 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001961 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001962 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001963 double sec;
1964
1965 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001966 xmlSchemaFreeValue(p1);
1967 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001968 if (sec < 0.0)
1969 return -1;
1970 else if (sec > 0.0)
1971 return 1;
1972
1973 }
1974 return 0;
1975 }
1976
1977 switch (x->type) {
1978 case XML_SCHEMAS_DATETIME:
1979 xmask = 0xf;
1980 break;
1981 case XML_SCHEMAS_DATE:
1982 xmask = 0x7;
1983 break;
1984 case XML_SCHEMAS_GYEAR:
1985 xmask = 0x1;
1986 break;
1987 case XML_SCHEMAS_GMONTH:
1988 xmask = 0x2;
1989 break;
1990 case XML_SCHEMAS_GDAY:
1991 xmask = 0x3;
1992 break;
1993 case XML_SCHEMAS_GYEARMONTH:
1994 xmask = 0x3;
1995 break;
1996 case XML_SCHEMAS_GMONTHDAY:
1997 xmask = 0x6;
1998 break;
1999 case XML_SCHEMAS_TIME:
2000 xmask = 0x8;
2001 break;
2002 default:
2003 xmask = 0;
2004 break;
2005 }
2006
2007 switch (y->type) {
2008 case XML_SCHEMAS_DATETIME:
2009 ymask = 0xf;
2010 break;
2011 case XML_SCHEMAS_DATE:
2012 ymask = 0x7;
2013 break;
2014 case XML_SCHEMAS_GYEAR:
2015 ymask = 0x1;
2016 break;
2017 case XML_SCHEMAS_GMONTH:
2018 ymask = 0x2;
2019 break;
2020 case XML_SCHEMAS_GDAY:
2021 ymask = 0x3;
2022 break;
2023 case XML_SCHEMAS_GYEARMONTH:
2024 ymask = 0x3;
2025 break;
2026 case XML_SCHEMAS_GMONTHDAY:
2027 ymask = 0x6;
2028 break;
2029 case XML_SCHEMAS_TIME:
2030 ymask = 0x8;
2031 break;
2032 default:
2033 ymask = 0;
2034 break;
2035 }
2036
2037 xor_mask = xmask ^ ymask; /* mark type differences */
2038 and_mask = xmask & ymask; /* mark field specification */
2039
2040 /* year */
2041 if (xor_mask & 1)
2042 return 2; /* indeterminate */
2043 else if (and_mask & 1) {
2044 if (x->value.date.year < y->value.date.year)
2045 return -1;
2046 else if (x->value.date.year > y->value.date.year)
2047 return 1;
2048 }
2049
2050 /* month */
2051 if (xor_mask & 2)
2052 return 2; /* indeterminate */
2053 else if (and_mask & 2) {
2054 if (x->value.date.mon < y->value.date.mon)
2055 return -1;
2056 else if (x->value.date.mon > y->value.date.mon)
2057 return 1;
2058 }
2059
2060 /* day */
2061 if (xor_mask & 4)
2062 return 2; /* indeterminate */
2063 else if (and_mask & 4) {
2064 if (x->value.date.day < y->value.date.day)
2065 return -1;
2066 else if (x->value.date.day > y->value.date.day)
2067 return 1;
2068 }
2069
2070 /* time */
2071 if (xor_mask & 8)
2072 return 2; /* indeterminate */
2073 else if (and_mask & 8) {
2074 if (x->value.date.hour < y->value.date.hour)
2075 return -1;
2076 else if (x->value.date.hour > y->value.date.hour)
2077 return 1;
2078 else if (x->value.date.min < y->value.date.min)
2079 return -1;
2080 else if (x->value.date.min > y->value.date.min)
2081 return 1;
2082 else if (x->value.date.sec < y->value.date.sec)
2083 return -1;
2084 else if (x->value.date.sec > y->value.date.sec)
2085 return 1;
2086 }
2087
Daniel Veillard070803b2002-05-03 07:29:38 +00002088 return 0;
2089}
2090
2091/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002092 * xmlSchemaCompareValues:
2093 * @x: a first value
2094 * @y: a second value
2095 *
2096 * Compare 2 values
2097 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002098 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2099 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002100 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00002101static int
Daniel Veillard4255d502002-04-16 15:50:10 +00002102xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2103 if ((x == NULL) || (y == NULL))
2104 return(-2);
2105
2106 switch (x->type) {
2107 case XML_SCHEMAS_STRING:
2108 TODO
2109 case XML_SCHEMAS_DECIMAL:
2110 if (y->type == XML_SCHEMAS_DECIMAL)
2111 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002112 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002113 case XML_SCHEMAS_DURATION:
2114 if (y->type == XML_SCHEMAS_DURATION)
2115 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002116 return(-2);
2117 case XML_SCHEMAS_TIME:
2118 case XML_SCHEMAS_GDAY:
2119 case XML_SCHEMAS_GMONTH:
2120 case XML_SCHEMAS_GMONTHDAY:
2121 case XML_SCHEMAS_GYEAR:
2122 case XML_SCHEMAS_GYEARMONTH:
2123 case XML_SCHEMAS_DATE:
2124 case XML_SCHEMAS_DATETIME:
2125 if ((y->type == XML_SCHEMAS_DATETIME) ||
2126 (y->type == XML_SCHEMAS_TIME) ||
2127 (y->type == XML_SCHEMAS_GDAY) ||
2128 (y->type == XML_SCHEMAS_GMONTH) ||
2129 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2130 (y->type == XML_SCHEMAS_GYEAR) ||
2131 (y->type == XML_SCHEMAS_DATE) ||
2132 (y->type == XML_SCHEMAS_GYEARMONTH))
2133 return (xmlSchemaCompareDates(x, y));
2134
2135 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002136 default:
2137 TODO
2138 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002139 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002140}
2141
2142/**
2143 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002144 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002145 * @facet: the facet to check
2146 * @value: the lexical repr of the value to validate
2147 * @val: the precomputed value
2148 *
2149 * Check a value against a facet condition
2150 *
2151 * Returns 0 if the element is schemas valid, a positive error code
2152 * number otherwise and -1 in case of internal or API error.
2153 */
2154int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002155xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002156 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002157 const xmlChar *value, xmlSchemaValPtr val)
2158{
2159 int ret;
2160
2161 switch (facet->type) {
2162 case XML_SCHEMA_FACET_PATTERN:
2163 ret = xmlRegexpExec(facet->regexp, value);
2164 if (ret == 1)
2165 return(0);
2166 if (ret == 0) {
2167 TODO /* error code */
2168 return(1);
2169 }
2170 return(ret);
2171 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2172 ret = xmlSchemaCompareValues(val, facet->val);
2173 if (ret == -2) {
2174 TODO /* error code */
2175 return(-1);
2176 }
2177 if (ret == -1)
2178 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002179 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002180 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002181 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2182 ret = xmlSchemaCompareValues(val, facet->val);
2183 if (ret == -2) {
2184 TODO /* error code */
2185 return(-1);
2186 }
2187 if ((ret == -1) || (ret == 0))
2188 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002189 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002190 return(1);
2191 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2192 ret = xmlSchemaCompareValues(val, facet->val);
2193 if (ret == -2) {
2194 TODO /* error code */
2195 return(-1);
2196 }
2197 if (ret == 1)
2198 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002199 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002200 return(1);
2201 case XML_SCHEMA_FACET_MININCLUSIVE:
2202 ret = xmlSchemaCompareValues(val, facet->val);
2203 if (ret == -2) {
2204 TODO /* error code */
2205 return(-1);
2206 }
2207 if ((ret == 1) || (ret == 0))
2208 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002209 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002210 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002211 case XML_SCHEMA_FACET_WHITESPACE:
2212 TODO /* whitespaces */
2213 return(0);
Daniel Veillarde19fc232002-04-22 16:01:24 +00002214 case XML_SCHEMA_FACET_MAXLENGTH:
2215 if ((facet->val != NULL) &&
2216 (facet->val->type == XML_SCHEMAS_DECIMAL) &&
2217 (facet->val->value.decimal.frac == 0)) {
Daniel Veillard118aed72002-09-24 14:13:13 +00002218 unsigned int len;
Daniel Veillarde19fc232002-04-22 16:01:24 +00002219
2220 if (facet->val->value.decimal.sign == 1)
2221 return(1);
2222 len = xmlUTF8Strlen(value);
2223 if (len > facet->val->value.decimal.base)
2224 return(1);
2225 return(0);
2226 }
2227 TODO /* error code */
2228 return(1);
Daniel Veillard88c58912002-04-23 07:12:20 +00002229 case XML_SCHEMA_FACET_ENUMERATION:
2230 if ((facet->value != NULL) &&
2231 (xmlStrEqual(facet->value, value)))
2232 return(0);
2233 return(1);
Daniel Veillard4255d502002-04-16 15:50:10 +00002234 default:
2235 TODO
2236 }
2237 return(0);
2238}
2239
2240#endif /* LIBXML_SCHEMAS_ENABLED */