blob: aff3e57549e4032036bd7c765cc53310d293cd64 [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 Veillard96a4b252003-02-06 08:22:32 +000058 XML_SCHEMAS_INT,
Daniel Veillard4255d502002-04-16 15:50:10 +000059 XML_SCHEMAS_,
60 XML_SCHEMAS_XXX
61} xmlSchemaValType;
62
63unsigned long powten[10] = {
64 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
65 100000000L, 1000000000L
66};
67
Daniel Veillard070803b2002-05-03 07:29:38 +000068/* Date value */
69typedef struct _xmlSchemaValDate xmlSchemaValDate;
70typedef xmlSchemaValDate *xmlSchemaValDatePtr;
71struct _xmlSchemaValDate {
72 long year;
73 unsigned int mon :4; /* 1 <= mon <= 12 */
74 unsigned int day :5; /* 1 <= day <= 31 */
75 unsigned int hour :5; /* 0 <= hour <= 23 */
76 unsigned int min :6; /* 0 <= min <= 59 */
77 double sec;
78 int tz_flag :1; /* is tzo explicitely set? */
79 int tzo :11; /* -1440 <= tzo <= 1440 */
80};
81
82/* Duration value */
83typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
84typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
85struct _xmlSchemaValDuration {
86 long mon; /* mon stores years also */
87 long day;
88 double sec; /* sec stores min and hour also */
89};
90
Daniel Veillard4255d502002-04-16 15:50:10 +000091typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
92typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
93struct _xmlSchemaValDecimal {
94 /* would use long long but not portable */
95 unsigned long base;
96 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +000097 unsigned int sign:1;
Daniel Veillard4255d502002-04-16 15:50:10 +000098 int frac:7;
99 int total:8;
100};
101
102struct _xmlSchemaVal {
103 xmlSchemaValType type;
104 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000105 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000106 xmlSchemaValDate date;
107 xmlSchemaValDuration dur;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000108 float f;
109 double d;
Daniel Veillard4255d502002-04-16 15:50:10 +0000110 } value;
111};
112
113static int xmlSchemaTypesInitialized = 0;
114static xmlHashTablePtr xmlSchemaTypesBank = NULL;
115
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000116/*
117 * Basic types
118 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000119static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
120static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
121static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
122static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000123static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000124static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000125static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
126static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
127static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
128static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
129static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
130static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
131static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000132static xmlSchemaTypePtr xmlSchemaTypeNmtoken = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000133static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
134static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillard96a4b252003-02-06 08:22:32 +0000135static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000136static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
137static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000138
139/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000140 * Derived types
141 */
142static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
143static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
144static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
145static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
149static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
150static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
151static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
152static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
153static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
154static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000155static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000156
157/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000158 * xmlSchemaInitBasicType:
159 * @name: the type name
160 *
161 * Initialize one default type
162 */
163static xmlSchemaTypePtr
164xmlSchemaInitBasicType(const char *name) {
165 xmlSchemaTypePtr ret;
166
167 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
168 if (ret == NULL) {
169 xmlGenericError(xmlGenericErrorContext,
170 "Could not initilize type %s: out of memory\n", name);
171 return(NULL);
172 }
173 memset(ret, 0, sizeof(xmlSchemaType));
174 ret->name = xmlStrdup((const xmlChar *)name);
175 ret->type = XML_SCHEMA_TYPE_BASIC;
176 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
177 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
178 XML_SCHEMAS_NAMESPACE_NAME, ret);
179 return(ret);
180}
181
182/*
183 * xmlSchemaInitTypes:
184 *
185 * Initialize the default XML Schemas type library
186 */
187void
188xmlSchemaInitTypes(void) {
189 if (xmlSchemaTypesInitialized != 0)
190 return;
191 xmlSchemaTypesBank = xmlHashCreate(40);
192
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000193 /*
194 * primitive datatypes
195 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000196 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string");
197 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType");
198 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType");
199 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal");
200 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date");
Daniel Veillard070803b2002-05-03 07:29:38 +0000201 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime");
202 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time");
203 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear");
204 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth");
205 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth");
206 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay");
207 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay");
208 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration");
Daniel Veillard4255d502002-04-16 15:50:10 +0000209 xmlSchemaTypeNmtoken = xmlSchemaInitBasicType("NMTOKEN");
Daniel Veillard84d70a42002-09-16 10:51:38 +0000210 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float");
211 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double");
Daniel Veillard96a4b252003-02-06 08:22:32 +0000212 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name");
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000213 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName");
214 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI");
Daniel Veillard4255d502002-04-16 15:50:10 +0000215
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000216 /*
217 * derived datatypes
218 */
219 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer");;
220 xmlSchemaTypeNonPositiveIntegerDef = xmlSchemaInitBasicType("nonPositiveInteger");;
221 xmlSchemaTypeNegativeIntegerDef = xmlSchemaInitBasicType("negativeInteger");;
222 xmlSchemaTypeLongDef = xmlSchemaInitBasicType("long");;
223 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int");;
224 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short");;
225 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte");;
226 xmlSchemaTypeNonNegativeIntegerDef = xmlSchemaInitBasicType("nonNegativeInteger");
227 xmlSchemaTypeUnsignedLongDef = xmlSchemaInitBasicType("unsignedLong");;
228 xmlSchemaTypeUnsignedIntDef = xmlSchemaInitBasicType("unsignedInt");;
229 xmlSchemaTypeUnsignedShortDef = xmlSchemaInitBasicType("insignedShort");;
230 xmlSchemaTypeUnsignedByteDef = xmlSchemaInitBasicType("unsignedByte");;
231 xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger");
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000232 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName");
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000233
Daniel Veillard4255d502002-04-16 15:50:10 +0000234 xmlSchemaTypesInitialized = 1;
235}
236
237/**
238 * xmlSchemaCleanupTypes:
239 *
240 * Cleanup the default XML Schemas type library
241 */
242void
243xmlSchemaCleanupTypes(void) {
244 if (xmlSchemaTypesInitialized == 0)
245 return;
246 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
247 xmlSchemaTypesInitialized = 0;
248}
249
250/**
251 * xmlSchemaNewValue:
252 * @type: the value type
253 *
254 * Allocate a new simple type value
255 *
256 * Returns a pointer to the new value or NULL in case of error
257 */
258static xmlSchemaValPtr
259xmlSchemaNewValue(xmlSchemaValType type) {
260 xmlSchemaValPtr value;
261
262 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
263 if (value == NULL) {
264 return(NULL);
265 }
266 memset(value, 0, sizeof(xmlSchemaVal));
267 value->type = type;
268 return(value);
269}
270
271/**
272 * xmlSchemaFreeValue:
273 * @value: the value to free
274 *
275 * Cleanup the default XML Schemas type library
276 */
277void
278xmlSchemaFreeValue(xmlSchemaValPtr value) {
279 if (value == NULL)
280 return;
281 xmlFree(value);
282}
283
284/**
285 * xmlSchemaGetPredefinedType:
286 * @name: the type name
287 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
288 *
289 * Lookup a type in the default XML Schemas type library
290 *
291 * Returns the type if found, NULL otherwise
292 */
293xmlSchemaTypePtr
294xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
295 if (xmlSchemaTypesInitialized == 0)
296 xmlSchemaInitTypes();
297 if (name == NULL)
298 return(NULL);
299 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
300}
Daniel Veillard070803b2002-05-03 07:29:38 +0000301
302/****************************************************************
303 * *
304 * Convenience macros and functions *
305 * *
306 ****************************************************************/
307
308#define IS_TZO_CHAR(c) \
309 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
310
311#define VALID_YEAR(yr) (yr != 0)
312#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
313/* VALID_DAY should only be used when month is unknown */
314#define VALID_DAY(day) ((day >= 1) && (day <= 31))
315#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
316#define VALID_MIN(min) ((min >= 0) && (min <= 59))
317#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
318#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
319#define IS_LEAP(y) \
320 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
321
322static const long daysInMonth[12] =
323 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
324static const long daysInMonthLeap[12] =
325 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
326
Daniel Veillard5a872412002-05-22 06:40:27 +0000327#define MAX_DAYINMONTH(yr,mon) \
328 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
329
Daniel Veillard070803b2002-05-03 07:29:38 +0000330#define VALID_MDAY(dt) \
331 (IS_LEAP(dt->year) ? \
332 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
333 (dt->day <= daysInMonth[dt->mon - 1]))
334
335#define VALID_DATE(dt) \
336 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
337
338#define VALID_TIME(dt) \
339 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
340 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
341
342#define VALID_DATETIME(dt) \
343 (VALID_DATE(dt) && VALID_TIME(dt))
344
345#define SECS_PER_MIN (60)
346#define SECS_PER_HOUR (60 * SECS_PER_MIN)
347#define SECS_PER_DAY (24 * SECS_PER_HOUR)
348
Daniel Veillard5a872412002-05-22 06:40:27 +0000349static const long dayInYearByMonth[12] =
350 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
351static const long dayInLeapYearByMonth[12] =
352 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
353
354#define DAY_IN_YEAR(day, month, year) \
355 ((IS_LEAP(year) ? \
356 dayInLeapYearByMonth[month - 1] : \
357 dayInYearByMonth[month - 1]) + day)
358
359#ifdef DEBUG
360#define DEBUG_DATE(dt) \
361 xmlGenericError(xmlGenericErrorContext, \
362 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
363 dt->type,dt->value.date.year,dt->value.date.mon, \
364 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
365 dt->value.date.sec); \
366 if (dt->value.date.tz_flag) \
367 if (dt->value.date.tzo != 0) \
368 xmlGenericError(xmlGenericErrorContext, \
369 "%+05d\n",dt->value.date.tzo); \
370 else \
371 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
372 else \
373 xmlGenericError(xmlGenericErrorContext,"\n")
374#else
375#define DEBUG_DATE(dt)
376#endif
377
Daniel Veillard070803b2002-05-03 07:29:38 +0000378/**
379 * _xmlSchemaParseGYear:
380 * @dt: pointer to a date structure
381 * @str: pointer to the string to analyze
382 *
383 * Parses a xs:gYear without time zone and fills in the appropriate
384 * field of the @dt structure. @str is updated to point just after the
385 * xs:gYear. It is supposed that @dt->year is big enough to contain
386 * the year.
387 *
388 * Returns 0 or the error code
389 */
390static int
391_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
392 const xmlChar *cur = *str, *firstChar;
393 int isneg = 0, digcnt = 0;
394
395 if (((*cur < '0') || (*cur > '9')) &&
396 (*cur != '-') && (*cur != '+'))
397 return -1;
398
399 if (*cur == '-') {
400 isneg = 1;
401 cur++;
402 }
403
404 firstChar = cur;
405
406 while ((*cur >= '0') && (*cur <= '9')) {
407 dt->year = dt->year * 10 + (*cur - '0');
408 cur++;
409 digcnt++;
410 }
411
412 /* year must be at least 4 digits (CCYY); over 4
413 * digits cannot have a leading zero. */
414 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
415 return 1;
416
417 if (isneg)
418 dt->year = - dt->year;
419
420 if (!VALID_YEAR(dt->year))
421 return 2;
422
423 *str = cur;
424 return 0;
425}
426
427/**
428 * PARSE_2_DIGITS:
429 * @num: the integer to fill in
430 * @cur: an #xmlChar *
431 * @invalid: an integer
432 *
433 * Parses a 2-digits integer and updates @num with the value. @cur is
434 * updated to point just after the integer.
435 * In case of error, @invalid is set to %TRUE, values of @num and
436 * @cur are undefined.
437 */
438#define PARSE_2_DIGITS(num, cur, invalid) \
439 if ((cur[0] < '0') || (cur[0] > '9') || \
440 (cur[1] < '0') || (cur[1] > '9')) \
441 invalid = 1; \
442 else \
443 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
444 cur += 2;
445
446/**
447 * PARSE_FLOAT:
448 * @num: the double to fill in
449 * @cur: an #xmlChar *
450 * @invalid: an integer
451 *
452 * Parses a float and updates @num with the value. @cur is
453 * updated to point just after the float. The float must have a
454 * 2-digits integer part and may or may not have a decimal part.
455 * In case of error, @invalid is set to %TRUE, values of @num and
456 * @cur are undefined.
457 */
458#define PARSE_FLOAT(num, cur, invalid) \
459 PARSE_2_DIGITS(num, cur, invalid); \
460 if (!invalid && (*cur == '.')) { \
461 double mult = 1; \
462 cur++; \
463 if ((*cur < '0') || (*cur > '9')) \
464 invalid = 1; \
465 while ((*cur >= '0') && (*cur <= '9')) { \
466 mult /= 10; \
467 num += (*cur - '0') * mult; \
468 cur++; \
469 } \
470 }
471
472/**
473 * _xmlSchemaParseGMonth:
474 * @dt: pointer to a date structure
475 * @str: pointer to the string to analyze
476 *
477 * Parses a xs:gMonth without time zone and fills in the appropriate
478 * field of the @dt structure. @str is updated to point just after the
479 * xs:gMonth.
480 *
481 * Returns 0 or the error code
482 */
483static int
484_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
485 const xmlChar *cur = *str;
486 int ret = 0;
487
488 PARSE_2_DIGITS(dt->mon, cur, ret);
489 if (ret != 0)
490 return ret;
491
492 if (!VALID_MONTH(dt->mon))
493 return 2;
494
495 *str = cur;
496 return 0;
497}
498
499/**
500 * _xmlSchemaParseGDay:
501 * @dt: pointer to a date structure
502 * @str: pointer to the string to analyze
503 *
504 * Parses a xs:gDay without time zone and fills in the appropriate
505 * field of the @dt structure. @str is updated to point just after the
506 * xs:gDay.
507 *
508 * Returns 0 or the error code
509 */
510static int
511_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
512 const xmlChar *cur = *str;
513 int ret = 0;
514
515 PARSE_2_DIGITS(dt->day, cur, ret);
516 if (ret != 0)
517 return ret;
518
519 if (!VALID_DAY(dt->day))
520 return 2;
521
522 *str = cur;
523 return 0;
524}
525
526/**
527 * _xmlSchemaParseTime:
528 * @dt: pointer to a date structure
529 * @str: pointer to the string to analyze
530 *
531 * Parses a xs:time without time zone and fills in the appropriate
532 * fields of the @dt structure. @str is updated to point just after the
533 * xs:time.
534 * In case of error, values of @dt fields are undefined.
535 *
536 * Returns 0 or the error code
537 */
538static int
539_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
540 const xmlChar *cur = *str;
541 unsigned int hour = 0; /* use temp var in case str is not xs:time */
542 int ret = 0;
543
544 PARSE_2_DIGITS(hour, cur, ret);
545 if (ret != 0)
546 return ret;
547
548 if (*cur != ':')
549 return 1;
550 cur++;
551
552 /* the ':' insures this string is xs:time */
553 dt->hour = hour;
554
555 PARSE_2_DIGITS(dt->min, cur, ret);
556 if (ret != 0)
557 return ret;
558
559 if (*cur != ':')
560 return 1;
561 cur++;
562
563 PARSE_FLOAT(dt->sec, cur, ret);
564 if (ret != 0)
565 return ret;
566
567 if (!VALID_TIME(dt))
568 return 2;
569
570 *str = cur;
571 return 0;
572}
573
574/**
575 * _xmlSchemaParseTimeZone:
576 * @dt: pointer to a date structure
577 * @str: pointer to the string to analyze
578 *
579 * Parses a time zone without time zone and fills in the appropriate
580 * field of the @dt structure. @str is updated to point just after the
581 * time zone.
582 *
583 * Returns 0 or the error code
584 */
585static int
586_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
587 const xmlChar *cur = *str;
588 int ret = 0;
589
590 if (str == NULL)
591 return -1;
592
593 switch (*cur) {
594 case 0:
595 dt->tz_flag = 0;
596 dt->tzo = 0;
597 break;
598
599 case 'Z':
600 dt->tz_flag = 1;
601 dt->tzo = 0;
602 cur++;
603 break;
604
605 case '+':
606 case '-': {
607 int isneg = 0, tmp = 0;
608 isneg = (*cur == '-');
609
610 cur++;
611
612 PARSE_2_DIGITS(tmp, cur, ret);
613 if (ret != 0)
614 return ret;
615 if (!VALID_HOUR(tmp))
616 return 2;
617
618 if (*cur != ':')
619 return 1;
620 cur++;
621
622 dt->tzo = tmp * 60;
623
624 PARSE_2_DIGITS(tmp, cur, ret);
625 if (ret != 0)
626 return ret;
627 if (!VALID_MIN(tmp))
628 return 2;
629
630 dt->tzo += tmp;
631 if (isneg)
632 dt->tzo = - dt->tzo;
633
634 if (!VALID_TZO(dt->tzo))
635 return 2;
636
Daniel Veillard5a872412002-05-22 06:40:27 +0000637 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000638 break;
639 }
640 default:
641 return 1;
642 }
643
644 *str = cur;
645 return 0;
646}
647
648/****************************************************************
649 * *
650 * XML Schema Dates/Times Datatypes Handling *
651 * *
652 ****************************************************************/
653
654/**
655 * PARSE_DIGITS:
656 * @num: the integer to fill in
657 * @cur: an #xmlChar *
658 * @num_type: an integer flag
659 *
660 * Parses a digits integer and updates @num with the value. @cur is
661 * updated to point just after the integer.
662 * In case of error, @num_type is set to -1, values of @num and
663 * @cur are undefined.
664 */
665#define PARSE_DIGITS(num, cur, num_type) \
666 if ((*cur < '0') || (*cur > '9')) \
667 num_type = -1; \
668 else \
669 while ((*cur >= '0') && (*cur <= '9')) { \
670 num = num * 10 + (*cur - '0'); \
671 cur++; \
672 }
673
674/**
675 * PARSE_NUM:
676 * @num: the double to fill in
677 * @cur: an #xmlChar *
678 * @num_type: an integer flag
679 *
680 * Parses a float or integer and updates @num with the value. @cur is
681 * updated to point just after the number. If the number is a float,
682 * then it must have an integer part and a decimal part; @num_type will
683 * be set to 1. If there is no decimal part, @num_type is set to zero.
684 * In case of error, @num_type is set to -1, values of @num and
685 * @cur are undefined.
686 */
687#define PARSE_NUM(num, cur, num_type) \
688 num = 0; \
689 PARSE_DIGITS(num, cur, num_type); \
690 if (!num_type && (*cur == '.')) { \
691 double mult = 1; \
692 cur++; \
693 if ((*cur < '0') || (*cur > '9')) \
694 num_type = -1; \
695 else \
696 num_type = 1; \
697 while ((*cur >= '0') && (*cur <= '9')) { \
698 mult /= 10; \
699 num += (*cur - '0') * mult; \
700 cur++; \
701 } \
702 }
703
704/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000705 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000706 * @type: the predefined type
707 * @dateTime: string to analyze
708 * @val: the return computed value
709 *
710 * Check that @dateTime conforms to the lexical space of one of the date types.
711 * if true a value is computed and returned in @val.
712 *
713 * Returns 0 if this validates, a positive error code number otherwise
714 * and -1 in case of internal or API error.
715 */
716static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000717xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000718 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000719 xmlSchemaValPtr dt;
720 int ret;
721 const xmlChar *cur = dateTime;
722
723#define RETURN_TYPE_IF_VALID(t) \
724 if (IS_TZO_CHAR(*cur)) { \
725 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
726 if (ret == 0) { \
727 if (*cur != 0) \
728 goto error; \
729 dt->type = t; \
730 if (val != NULL) \
731 *val = dt; \
732 return 0; \
733 } \
734 }
735
736 if (dateTime == NULL)
737 return -1;
738
739 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
740 return 1;
741
742 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
743 if (dt == NULL)
744 return -1;
745
746 if ((cur[0] == '-') && (cur[1] == '-')) {
747 /*
748 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
749 * xs:gDay)
750 */
751 cur += 2;
752
753 /* is it an xs:gDay? */
754 if (*cur == '-') {
755 ++cur;
756 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
757 if (ret != 0)
758 goto error;
759
760 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
761
762 goto error;
763 }
764
765 /*
766 * it should be an xs:gMonthDay or xs:gMonth
767 */
768 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
769 if (ret != 0)
770 goto error;
771
772 if (*cur != '-')
773 goto error;
774 cur++;
775
776 /* is it an xs:gMonth? */
777 if (*cur == '-') {
778 cur++;
779 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
780 goto error;
781 }
782
783 /* it should be an xs:gMonthDay */
784 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
785 if (ret != 0)
786 goto error;
787
788 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
789
790 goto error;
791 }
792
793 /*
794 * It's a right-truncated date or an xs:time.
795 * Try to parse an xs:time then fallback on right-truncated dates.
796 */
797 if ((*cur >= '0') && (*cur <= '9')) {
798 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
799 if (ret == 0) {
800 /* it's an xs:time */
801 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
802 }
803 }
804
805 /* fallback on date parsing */
806 cur = dateTime;
807
808 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
809 if (ret != 0)
810 goto error;
811
812 /* is it an xs:gYear? */
813 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
814
815 if (*cur != '-')
816 goto error;
817 cur++;
818
819 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
820 if (ret != 0)
821 goto error;
822
823 /* is it an xs:gYearMonth? */
824 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
825
826 if (*cur != '-')
827 goto error;
828 cur++;
829
830 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
831 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
832 goto error;
833
834 /* is it an xs:date? */
835 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
836
837 if (*cur != 'T')
838 goto error;
839 cur++;
840
841 /* it should be an xs:dateTime */
842 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
843 if (ret != 0)
844 goto error;
845
846 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
847 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
848 goto error;
849
850 dt->type = XML_SCHEMAS_DATETIME;
851
852 if (val != NULL)
853 *val = dt;
854
855 return 0;
856
857error:
858 if (dt != NULL)
859 xmlSchemaFreeValue(dt);
860 return 1;
861}
862
863/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000864 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000865 * @type: the predefined type
866 * @duration: string to analyze
867 * @val: the return computed value
868 *
869 * Check that @duration conforms to the lexical space of the duration type.
870 * if true a value is computed and returned in @val.
871 *
872 * Returns 0 if this validates, a positive error code number otherwise
873 * and -1 in case of internal or API error.
874 */
875static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000876xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000877 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000878 const xmlChar *cur = duration;
879 xmlSchemaValPtr dur;
880 int isneg = 0;
881 unsigned int seq = 0;
882
883 if (duration == NULL)
884 return -1;
885
886 if (*cur == '-') {
887 isneg = 1;
888 cur++;
889 }
890
891 /* duration must start with 'P' (after sign) */
892 if (*cur++ != 'P')
893 return 1;
894
895 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
896 if (dur == NULL)
897 return -1;
898
899 while (*cur != 0) {
900 double num;
901 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
902 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
903 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
904
905 /* input string should be empty or invalid date/time item */
906 if (seq >= sizeof(desig))
907 goto error;
908
909 /* T designator must be present for time items */
910 if (*cur == 'T') {
911 if (seq <= 3) {
912 seq = 3;
913 cur++;
914 } else
915 return 1;
916 } else if (seq == 3)
917 goto error;
918
919 /* parse the number portion of the item */
920 PARSE_NUM(num, cur, num_type);
921
922 if ((num_type == -1) || (*cur == 0))
923 goto error;
924
925 /* update duration based on item type */
926 while (seq < sizeof(desig)) {
927 if (*cur == desig[seq]) {
928
929 /* verify numeric type; only seconds can be float */
930 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
931 goto error;
932
933 switch (seq) {
934 case 0:
935 dur->value.dur.mon = (long)num * 12;
936 break;
937 case 1:
938 dur->value.dur.mon += (long)num;
939 break;
940 default:
941 /* convert to seconds using multiplier */
942 dur->value.dur.sec += num * multi[seq];
943 seq++;
944 break;
945 }
946
947 break; /* exit loop */
948 }
949 /* no date designators found? */
950 if (++seq == 3)
951 goto error;
952 }
953 cur++;
954 }
955
956 if (isneg) {
957 dur->value.dur.mon = -dur->value.dur.mon;
958 dur->value.dur.day = -dur->value.dur.day;
959 dur->value.dur.sec = -dur->value.dur.sec;
960 }
961
962 if (val != NULL)
963 *val = dur;
964
965 return 0;
966
967error:
968 if (dur != NULL)
969 xmlSchemaFreeValue(dur);
970 return 1;
971}
972
Daniel Veillard96a4b252003-02-06 08:22:32 +0000973
974/**
975 * xmlSchemaValidateNCName:
976 * @value: the value to check
977 *
978 * Check that a value conforms to the lexical space of NCName
979 *
980 * Returns 0 if this validates, a positive error code number otherwise
981 * and -1 in case of internal or API error.
982 */
983static int
984xmlSchemaValidateNCName(const xmlChar *value) {
985 const xmlChar *cur = value;
986
987 /*
988 * First quick algorithm for ASCII range
989 */
990 while (IS_BLANK(*cur)) cur++;
991 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
992 (*cur == '_'))
993 cur++;
994 else
995 goto try_complex;
996 while (((*cur >= 'a') && (*cur <= 'z')) ||
997 ((*cur >= 'A') && (*cur <= 'Z')) ||
998 ((*cur >= '0') && (*cur <= '9')) ||
999 (*cur == '_') || (*cur == '-') || (*cur == '.'))
1000 cur++;
1001 while (IS_BLANK(*cur)) cur++;
1002 if (*cur == 0)
1003 return(0);
1004
1005try_complex:
1006 /*
1007 * Second check for chars outside the ASCII range
1008 */
1009 TODO
1010 return(0);
1011}
1012
1013/**
1014 * xmlSchemaValidateQName:
1015 * @value: the value to check
1016 *
1017 * Check that a value conforms to the lexical space of QName
1018 *
1019 * Returns 0 if this validates, a positive error code number otherwise
1020 * and -1 in case of internal or API error.
1021 */
1022static int
1023xmlSchemaValidateQName(const xmlChar *value) {
1024 const xmlChar *cur = value;
1025
1026 /*
1027 * First quick algorithm for ASCII range
1028 */
1029 while (IS_BLANK(*cur)) cur++;
1030 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
1031 (*cur == '_'))
1032 cur++;
1033 else
1034 goto try_complex;
1035 while (((*cur >= 'a') && (*cur <= 'z')) ||
1036 ((*cur >= 'A') && (*cur <= 'Z')) ||
1037 ((*cur >= '0') && (*cur <= '9')) ||
1038 (*cur == '_') || (*cur == '-') || (*cur == '.'))
1039 cur++;
1040 if (*cur == ':') {
1041 cur++;
1042 if (((*cur >= 'a') && (*cur <= 'z')) ||
1043 ((*cur >= 'A') && (*cur <= 'Z')) ||
1044 (*cur == '_'))
1045 cur++;
1046 else
1047 goto try_complex;
1048 while (((*cur >= 'a') && (*cur <= 'z')) ||
1049 ((*cur >= 'A') && (*cur <= 'Z')) ||
1050 ((*cur >= '0') && (*cur <= '9')) ||
1051 (*cur == '_') || (*cur == '-') || (*cur == '.'))
1052 cur++;
1053 }
1054 while (IS_BLANK(*cur)) cur++;
1055 if (*cur == 0)
1056 return(0);
1057
1058try_complex:
1059 /*
1060 * Second check for chars outside the ASCII range
1061 */
1062 TODO
1063 return(0);
1064}
1065
1066/**
1067 * xmlSchemaValidateName:
1068 * @value: the value to check
1069 *
1070 * Check that a value conforms to the lexical space of Name
1071 *
1072 * Returns 0 if this validates, a positive error code number otherwise
1073 * and -1 in case of internal or API error.
1074 */
1075static int
1076xmlSchemaValidateName(const xmlChar *value) {
1077 const xmlChar *cur = value;
1078
1079 /*
1080 * First quick algorithm for ASCII range
1081 */
1082 while (IS_BLANK(*cur)) cur++;
1083 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
1084 (*cur == '_') || (*cur == ':'))
1085 cur++;
1086 else
1087 goto try_complex;
1088 while (((*cur >= 'a') && (*cur <= 'z')) ||
1089 ((*cur >= 'A') && (*cur <= 'Z')) ||
1090 ((*cur >= '0') && (*cur <= '9')) ||
1091 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
1092 cur++;
1093 while (IS_BLANK(*cur)) cur++;
1094 if (*cur == 0)
1095 return(0);
1096
1097try_complex:
1098 /*
1099 * Second check for chars outside the ASCII range
1100 */
1101 TODO
1102 return(0);
1103}
Daniel Veillard4255d502002-04-16 15:50:10 +00001104/**
1105 * xmlSchemaValidatePredefinedType:
1106 * @type: the predefined type
1107 * @value: the value to check
1108 * @val: the return computed value
1109 *
1110 * Check that a value conforms to the lexical space of the predefined type.
1111 * if true a value is computed and returned in @val.
1112 *
1113 * Returns 0 if this validates, a positive error code number otherwise
1114 * and -1 in case of internal or API error.
1115 */
1116int
1117xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1118 xmlSchemaValPtr *val) {
1119 xmlSchemaValPtr v;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001120 int ret;
Daniel Veillard4255d502002-04-16 15:50:10 +00001121
1122 if (xmlSchemaTypesInitialized == 0)
1123 return(-1);
1124 if (type == NULL)
1125 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001126
Daniel Veillard4255d502002-04-16 15:50:10 +00001127 if (val != NULL)
1128 *val = NULL;
1129 if (type == xmlSchemaTypeStringDef) {
1130 return(0);
1131 } else if (type == xmlSchemaTypeAnyTypeDef) {
1132 return(0);
1133 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
1134 return(0);
1135 } else if (type == xmlSchemaTypeNmtoken) {
1136 if (xmlValidateNmtokenValue(value))
1137 return(0);
1138 return(1);
1139 } else if (type == xmlSchemaTypeDecimalDef) {
1140 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001141 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001142 unsigned long base = 0;
1143 if (cur == NULL)
1144 return(1);
1145 if (*cur == '+')
1146 cur++;
1147 else if (*cur == '-') {
1148 neg = 1;
1149 cur++;
1150 }
1151 tmp = cur;
1152 while ((*cur >= '0') && (*cur <= '9')) {
1153 base = base * 10 + (*cur - '0');
1154 cur++;
1155 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001156 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001157 if (*cur == '.') {
1158 cur++;
1159 tmp = cur;
1160 while ((*cur >= '0') && (*cur <= '9')) {
1161 base = base * 10 + (*cur - '0');
1162 cur++;
1163 }
1164 frac = cur - tmp;
1165 }
1166 if (*cur != 0)
1167 return(1);
1168 if (val != NULL) {
1169 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1170 if (v != NULL) {
1171 v->value.decimal.base = base;
1172 v->value.decimal.sign = neg;
1173 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001174 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001175 *val = v;
1176 }
1177 }
1178 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001179 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001180 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001181 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1182 (type == xmlSchemaTypeTimeDef) ||
1183 (type == xmlSchemaTypeDateDef) ||
1184 (type == xmlSchemaTypeGYearDef) ||
1185 (type == xmlSchemaTypeGYearMonthDef) ||
1186 (type == xmlSchemaTypeGMonthDef) ||
1187 (type == xmlSchemaTypeGMonthDayDef) ||
1188 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001189 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001190 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1191 const xmlChar *cur = value;
1192 unsigned long base = 0;
1193 int total = 0;
1194 if (cur == NULL)
1195 return(1);
1196 if (*cur == '+')
1197 cur++;
1198 while ((*cur >= '0') && (*cur <= '9')) {
1199 base = base * 10 + (*cur - '0');
1200 total++;
1201 cur++;
1202 }
1203 if (*cur != 0)
1204 return(1);
1205 if (val != NULL) {
1206 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1207 if (v != NULL) {
1208 v->value.decimal.base = base;
1209 v->value.decimal.sign = 0;
1210 v->value.decimal.frac = 0;
1211 v->value.decimal.total = total;
1212 *val = v;
1213 }
1214 }
1215 return(0);
1216 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1217 const xmlChar *cur = value;
1218 unsigned long base = 0;
1219 int total = 0;
1220 int sign = 0;
1221 if (cur == NULL)
1222 return(1);
1223 if (*cur == '-') {
1224 sign = 1;
1225 cur++;
1226 } else if (*cur == '+')
1227 cur++;
1228 while ((*cur >= '0') && (*cur <= '9')) {
1229 base = base * 10 + (*cur - '0');
1230 total++;
1231 cur++;
1232 }
1233 if (*cur != 0)
1234 return(1);
1235 if ((sign == 1) && (base != 0))
1236 return(1);
1237 if (val != NULL) {
1238 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1239 if (v != NULL) {
1240 v->value.decimal.base = base;
1241 v->value.decimal.sign = 0;
1242 v->value.decimal.frac = 0;
1243 v->value.decimal.total = total;
1244 *val = v;
1245 }
1246 }
1247 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001248 } else if (type == xmlSchemaTypeIntDef) {
1249 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001250 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001251 int total = 0;
1252 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001253 if (cur == NULL)
1254 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001255 if (*cur == '-') {
1256 sign = 1;
1257 cur++;
1258 } else if (*cur == '+')
1259 cur++;
1260 while (*cur == '0') {
1261 total++;
1262 cur++;
1263 }
1264 while ((*cur >= '0') && (*cur <= '9')) {
1265 base = base * 10 + (*cur - '0');
1266 total++;
1267 cur++;
1268 }
1269 if (*cur != 0)
1270 return(1);
1271 if ((sign == 1) && (total == 0))
1272 return(1);
1273 if (val != NULL) {
1274 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1275 if (v != NULL) {
1276 v->value.decimal.base = base;
1277 v->value.decimal.sign = sign;
1278 v->value.decimal.frac = 0;
1279 v->value.decimal.total = total;
1280 *val = v;
1281 }
1282 }
1283 return(0);
1284 } else if ((type == xmlSchemaTypeFloatDef) ||
1285 (type == xmlSchemaTypeDoubleDef)) {
1286 const xmlChar *cur = value;
1287 int neg = 0;
1288 if (cur == NULL)
1289 return(1);
1290 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1291 cur += 3;
1292 if (*cur != 0)
1293 return(1);
1294 if (val != NULL) {
1295 if (type == xmlSchemaTypeFloatDef) {
1296 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1297 if (v != NULL) {
1298 v->value.f = (float) xmlXPathNAN;
1299 } else {
1300 xmlSchemaFreeValue(v);
1301 return(-1);
1302 }
1303 } else {
1304 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1305 if (v != NULL) {
1306 v->value.d = xmlXPathNAN;
1307 } else {
1308 xmlSchemaFreeValue(v);
1309 return(-1);
1310 }
1311 }
1312 *val = v;
1313 }
1314 return(0);
1315 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001316 if (*cur == '+')
1317 cur++;
1318 else if (*cur == '-') {
1319 neg = 1;
1320 cur++;
1321 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001322 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1323 cur += 3;
1324 if (*cur != 0)
1325 return(1);
1326 if (val != NULL) {
1327 if (type == xmlSchemaTypeFloatDef) {
1328 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1329 if (v != NULL) {
1330 if (neg)
1331 v->value.f = (float) xmlXPathNINF;
1332 else
1333 v->value.f = (float) xmlXPathPINF;
1334 } else {
1335 xmlSchemaFreeValue(v);
1336 return(-1);
1337 }
1338 } else {
1339 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1340 if (v != NULL) {
1341 if (neg)
1342 v->value.d = xmlXPathNINF;
1343 else
1344 v->value.d = xmlXPathPINF;
1345 } else {
1346 xmlSchemaFreeValue(v);
1347 return(-1);
1348 }
1349 }
1350 *val = v;
1351 }
1352 return(0);
1353 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001354 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001355 cur++;
1356 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001357 if (*cur == '.') {
1358 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001359 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001360 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001361 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001362 if ((*cur == 'e') || (*cur == 'E')) {
1363 cur++;
1364 if (*cur == '-')
1365 cur++;
1366 while ((*cur >= '0') && (*cur <= '9'))
1367 cur++;
1368 }
1369 if (*cur != 0)
1370 return(1);
1371 if (val != NULL) {
1372 if (type == xmlSchemaTypeFloatDef) {
1373 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1374 if (v != NULL) {
1375 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1376 *val = v;
1377 } else {
1378 xmlGenericError(xmlGenericErrorContext,
1379 "failed to scanf float %s\n", value);
1380 xmlSchemaFreeValue(v);
1381 return(1);
1382 }
1383 } else {
1384 return(-1);
1385 }
1386 } else {
1387 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1388 if (v != NULL) {
1389 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1390 *val = v;
1391 } else {
1392 xmlGenericError(xmlGenericErrorContext,
1393 "failed to scanf double %s\n", value);
1394 xmlSchemaFreeValue(v);
1395 return(1);
1396 }
1397 } else {
1398 return(-1);
1399 }
1400 }
1401 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001402 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001403 } else if (type == xmlSchemaTypeNameDef) {
1404 ret = xmlSchemaValidateName(value);
1405 if ((ret == 0) && (val != NULL)) {
1406 TODO;
1407 }
1408 return(ret);
1409 } else if (type == xmlSchemaTypeQNameDef) {
1410 ret = xmlSchemaValidateQName(value);
1411 if ((ret == 0) && (val != NULL)) {
1412 TODO;
1413 }
1414 return(ret);
1415 } else if (type == xmlSchemaTypeNCNameDef) {
1416 ret = xmlSchemaValidateNCName(value);
1417 if ((ret == 0) && (val != NULL)) {
1418 TODO;
1419 }
1420 return(ret);
1421 } else if (type == xmlSchemaTypeAnyURIDef) {
1422 xmlURIPtr uri;
1423
1424 uri = xmlParseURI((const char *) value);
1425 if (uri == NULL)
1426 return(1);
1427 if (val != NULL) {
1428 TODO;
1429 }
1430 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001431 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001432 } else {
1433 TODO
1434 return(0);
1435 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001436 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001437}
1438
1439/**
1440 * xmlSchemaCompareDecimals:
1441 * @x: a first decimal value
1442 * @y: a second decimal value
1443 *
1444 * Compare 2 decimals
1445 *
1446 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1447 */
1448static int
1449xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1450{
1451 xmlSchemaValPtr swp;
1452 int order = 1;
1453 unsigned long tmp;
1454
1455 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1456 order = -1;
1457 else if (x->value.decimal.sign)
1458 return (-1);
1459 else if (y->value.decimal.sign)
1460 return (1);
1461 if (x->value.decimal.frac == y->value.decimal.frac) {
1462 if (x->value.decimal.base < y->value.decimal.base)
1463 return (-1);
1464 return (x->value.decimal.base > y->value.decimal.base);
1465 }
1466 if (y->value.decimal.frac > x->value.decimal.frac) {
1467 swp = y;
1468 y = x;
1469 x = swp;
1470 order = -order;
1471 }
1472 tmp =
1473 x->value.decimal.base / powten[x->value.decimal.frac -
1474 y->value.decimal.frac];
1475 if (tmp > y->value.decimal.base)
1476 return (order);
1477 if (tmp < y->value.decimal.base)
1478 return (-order);
1479 tmp =
1480 y->value.decimal.base * powten[x->value.decimal.frac -
1481 y->value.decimal.frac];
1482 if (x->value.decimal.base < tmp)
1483 return (-order);
1484 if (x->value.decimal.base == tmp)
1485 return (0);
1486 return (order);
1487}
1488
1489/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001490 * xmlSchemaCompareDurations:
1491 * @x: a first duration value
1492 * @y: a second duration value
1493 *
1494 * Compare 2 durations
1495 *
1496 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1497 * case of error
1498 */
1499static int
1500xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1501{
1502 long carry, mon, day;
1503 double sec;
1504 long xmon, xday, myear, lyear, minday, maxday;
1505 static const long dayRange [2][12] = {
1506 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1507 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1508
1509 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001510 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001511
1512 /* months */
1513 mon = x->value.dur.mon - y->value.dur.mon;
1514
1515 /* seconds */
1516 sec = x->value.dur.sec - y->value.dur.sec;
1517 carry = (long)sec / SECS_PER_DAY;
1518 sec -= (double)(carry * SECS_PER_DAY);
1519
1520 /* days */
1521 day = x->value.dur.day - y->value.dur.day + carry;
1522
1523 /* easy test */
1524 if (mon == 0) {
1525 if (day == 0)
1526 if (sec == 0.0)
1527 return 0;
1528 else if (sec < 0.0)
1529 return -1;
1530 else
1531 return 1;
1532 else if (day < 0)
1533 return -1;
1534 else
1535 return 1;
1536 }
1537
1538 if (mon > 0) {
1539 if ((day >= 0) && (sec >= 0.0))
1540 return 1;
1541 else {
1542 xmon = mon;
1543 xday = -day;
1544 }
1545 } else if ((day <= 0) && (sec <= 0.0)) {
1546 return -1;
1547 } else {
1548 xmon = -mon;
1549 xday = day;
1550 }
1551
1552 myear = xmon / 12;
1553 lyear = myear / 4;
1554 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1555 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1556
1557 xmon = xmon % 12;
1558 minday += dayRange[0][xmon];
1559 maxday += dayRange[1][xmon];
1560
1561 if (maxday < xday)
1562 return 1;
1563 else if (minday > xday)
1564 return -1;
1565
1566 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001567 return 2;
1568}
1569
1570/*
1571 * macros for adding date/times and durations
1572 */
1573#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1574#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1575#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1576#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1577
1578/**
1579 * _xmlSchemaDateAdd:
1580 * @dt: an #xmlSchemaValPtr
1581 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1582 *
1583 * Compute a new date/time from @dt and @dur. This function assumes @dt
1584 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1585 * or #XML_SCHEMAS_GYEAR.
1586 *
1587 * Returns date/time pointer or NULL.
1588 */
1589static xmlSchemaValPtr
1590_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1591{
1592 xmlSchemaValPtr ret;
1593 long carry, tempdays, temp;
1594 xmlSchemaValDatePtr r, d;
1595 xmlSchemaValDurationPtr u;
1596
1597 if ((dt == NULL) || (dur == NULL))
1598 return NULL;
1599
1600 ret = xmlSchemaNewValue(dt->type);
1601 if (ret == NULL)
1602 return NULL;
1603
1604 r = &(ret->value.date);
1605 d = &(dt->value.date);
1606 u = &(dur->value.dur);
1607
1608 /* normalization */
1609 if (d->mon == 0)
1610 d->mon = 1;
1611
1612 /* normalize for time zone offset */
1613 u->sec -= (d->tzo * 60);
1614 d->tzo = 0;
1615
1616 /* normalization */
1617 if (d->day == 0)
1618 d->day = 1;
1619
1620 /* month */
1621 carry = d->mon + u->mon;
1622 r->mon = MODULO_RANGE(carry, 1, 13);
1623 carry = FQUOTIENT_RANGE(carry, 1, 13);
1624
1625 /* year (may be modified later) */
1626 r->year = d->year + carry;
1627 if (r->year == 0) {
1628 if (d->year > 0)
1629 r->year--;
1630 else
1631 r->year++;
1632 }
1633
1634 /* time zone */
1635 r->tzo = d->tzo;
1636 r->tz_flag = d->tz_flag;
1637
1638 /* seconds */
1639 r->sec = d->sec + u->sec;
1640 carry = FQUOTIENT((long)r->sec, 60);
1641 if (r->sec != 0.0) {
1642 r->sec = MODULO(r->sec, 60.0);
1643 }
1644
1645 /* minute */
1646 carry += d->min;
1647 r->min = MODULO(carry, 60);
1648 carry = FQUOTIENT(carry, 60);
1649
1650 /* hours */
1651 carry += d->hour;
1652 r->hour = MODULO(carry, 24);
1653 carry = FQUOTIENT(carry, 24);
1654
1655 /*
1656 * days
1657 * Note we use tempdays because the temporary values may need more
1658 * than 5 bits
1659 */
1660 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1661 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1662 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1663 else if (d->day < 1)
1664 tempdays = 1;
1665 else
1666 tempdays = d->day;
1667
1668 tempdays += u->day + carry;
1669
1670 while (1) {
1671 if (tempdays < 1) {
1672 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1673 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1674 if (tyr == 0)
1675 tyr--;
1676 tempdays += MAX_DAYINMONTH(tyr, tmon);
1677 carry = -1;
1678 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1679 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1680 carry = 1;
1681 } else
1682 break;
1683
1684 temp = r->mon + carry;
1685 r->mon = MODULO_RANGE(temp, 1, 13);
1686 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1687 if (r->year == 0) {
1688 if (temp < 1)
1689 r->year--;
1690 else
1691 r->year++;
1692 }
1693 }
1694
1695 r->day = tempdays;
1696
1697 /*
1698 * adjust the date/time type to the date values
1699 */
1700 if (ret->type != XML_SCHEMAS_DATETIME) {
1701 if ((r->hour) || (r->min) || (r->sec))
1702 ret->type = XML_SCHEMAS_DATETIME;
1703 else if (ret->type != XML_SCHEMAS_DATE) {
1704 if ((r->mon != 1) && (r->day != 1))
1705 ret->type = XML_SCHEMAS_DATE;
1706 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1707 ret->type = XML_SCHEMAS_GYEARMONTH;
1708 }
1709 }
1710
1711 return ret;
1712}
1713
1714/**
1715 * xmlSchemaDupVal:
1716 * @v: value to duplicate
1717 *
1718 * returns a duplicated value.
1719 */
1720static xmlSchemaValPtr
1721xmlSchemaDupVal (xmlSchemaValPtr v)
1722{
1723 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1724 if (ret == NULL)
1725 return ret;
1726
1727 memcpy(ret, v, sizeof(xmlSchemaVal));
1728 return ret;
1729}
1730
1731/**
1732 * xmlSchemaDateNormalize:
1733 * @dt: an #xmlSchemaValPtr
1734 *
1735 * Normalize @dt to GMT time.
1736 *
1737 */
1738static xmlSchemaValPtr
1739xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1740{
1741 xmlSchemaValPtr dur, ret;
1742
1743 if (dt == NULL)
1744 return NULL;
1745
1746 if (((dt->type != XML_SCHEMAS_TIME) &&
1747 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1748 return xmlSchemaDupVal(dt);
1749
1750 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1751 if (dur == NULL)
1752 return NULL;
1753
1754 dur->value.date.sec -= offset;
1755
1756 ret = _xmlSchemaDateAdd(dt, dur);
1757 if (ret == NULL)
1758 return NULL;
1759
1760 xmlSchemaFreeValue(dur);
1761
1762 /* ret->value.date.tzo = 0; */
1763 return ret;
1764}
1765
1766/**
1767 * _xmlSchemaDateCastYMToDays:
1768 * @dt: an #xmlSchemaValPtr
1769 *
1770 * Convert mon and year of @dt to total number of days. Take the
1771 * number of years since (or before) 1 AD and add the number of leap
1772 * years. This is a function because negative
1773 * years must be handled a little differently and there is no zero year.
1774 *
1775 * Returns number of days.
1776 */
1777static long
1778_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
1779{
1780 long ret;
1781
1782 if (dt->value.date.year < 0)
1783 ret = (dt->value.date.year * 365) +
1784 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1785 ((dt->value.date.year+1)/400)) +
1786 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1787 else
1788 ret = ((dt->value.date.year-1) * 365) +
1789 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1790 ((dt->value.date.year-1)/400)) +
1791 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1792
1793 return ret;
1794}
1795
1796/**
1797 * TIME_TO_NUMBER:
1798 * @dt: an #xmlSchemaValPtr
1799 *
1800 * Calculates the number of seconds in the time portion of @dt.
1801 *
1802 * Returns seconds.
1803 */
1804#define TIME_TO_NUMBER(dt) \
1805 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
1806 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
1807
1808/**
1809 * xmlSchemaCompareDates:
1810 * @x: a first date/time value
1811 * @y: a second date/time value
1812 *
1813 * Compare 2 date/times
1814 *
1815 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1816 * case of error
1817 */
1818static int
1819xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
1820{
1821 unsigned char xmask, ymask, xor_mask, and_mask;
1822 xmlSchemaValPtr p1, p2, q1, q2;
1823 long p1d, p2d, q1d, q2d;
1824
1825 if ((x == NULL) || (y == NULL))
1826 return -2;
1827
1828 if (x->value.date.tz_flag) {
1829
1830 if (!y->value.date.tz_flag) {
1831 p1 = xmlSchemaDateNormalize(x, 0);
1832 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1833 /* normalize y + 14:00 */
1834 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
1835
1836 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001837 if (p1d < q1d) {
1838 xmlSchemaFreeValue(p1);
1839 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001840 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001841 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001842 double sec;
1843
1844 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001845 if (sec < 0.0) {
1846 xmlSchemaFreeValue(p1);
1847 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001848 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001849 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001850 /* normalize y - 14:00 */
1851 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
1852 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001853 xmlSchemaFreeValue(p1);
1854 xmlSchemaFreeValue(q1);
1855 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001856 if (p1d > q2d)
1857 return 1;
1858 else if (p1d == q2d) {
1859 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
1860 if (sec > 0.0)
1861 return 1;
1862 else
1863 return 2; /* indeterminate */
1864 }
1865 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001866 } else {
1867 xmlSchemaFreeValue(p1);
1868 xmlSchemaFreeValue(q1);
1869 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001870 }
1871 } else if (y->value.date.tz_flag) {
1872 q1 = xmlSchemaDateNormalize(y, 0);
1873 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1874
1875 /* normalize x - 14:00 */
1876 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
1877 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1878
Daniel Veillardfdc91562002-07-01 21:52:03 +00001879 if (p1d < q1d) {
1880 xmlSchemaFreeValue(p1);
1881 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001882 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001883 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001884 double sec;
1885
1886 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001887 if (sec < 0.0) {
1888 xmlSchemaFreeValue(p1);
1889 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001890 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001891 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001892 /* normalize x + 14:00 */
1893 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
1894 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
1895
Daniel Veillardfdc91562002-07-01 21:52:03 +00001896 xmlSchemaFreeValue(p1);
1897 xmlSchemaFreeValue(q1);
1898 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001899 if (p2d > q1d)
1900 return 1;
1901 else if (p2d == q1d) {
1902 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
1903 if (sec > 0.0)
1904 return 1;
1905 else
1906 return 2; /* indeterminate */
1907 }
1908 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001909 } else {
1910 xmlSchemaFreeValue(p1);
1911 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001912 }
1913 }
1914
1915 /*
1916 * if the same type then calculate the difference
1917 */
1918 if (x->type == y->type) {
1919 q1 = xmlSchemaDateNormalize(y, 0);
1920 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1921
1922 p1 = xmlSchemaDateNormalize(x, 0);
1923 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1924
Daniel Veillardfdc91562002-07-01 21:52:03 +00001925 if (p1d < q1d) {
1926 xmlSchemaFreeValue(p1);
1927 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001928 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001929 } else if (p1d > q1d) {
1930 xmlSchemaFreeValue(p1);
1931 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001932 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001933 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00001934 double sec;
1935
1936 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001937 xmlSchemaFreeValue(p1);
1938 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001939 if (sec < 0.0)
1940 return -1;
1941 else if (sec > 0.0)
1942 return 1;
1943
1944 }
1945 return 0;
1946 }
1947
1948 switch (x->type) {
1949 case XML_SCHEMAS_DATETIME:
1950 xmask = 0xf;
1951 break;
1952 case XML_SCHEMAS_DATE:
1953 xmask = 0x7;
1954 break;
1955 case XML_SCHEMAS_GYEAR:
1956 xmask = 0x1;
1957 break;
1958 case XML_SCHEMAS_GMONTH:
1959 xmask = 0x2;
1960 break;
1961 case XML_SCHEMAS_GDAY:
1962 xmask = 0x3;
1963 break;
1964 case XML_SCHEMAS_GYEARMONTH:
1965 xmask = 0x3;
1966 break;
1967 case XML_SCHEMAS_GMONTHDAY:
1968 xmask = 0x6;
1969 break;
1970 case XML_SCHEMAS_TIME:
1971 xmask = 0x8;
1972 break;
1973 default:
1974 xmask = 0;
1975 break;
1976 }
1977
1978 switch (y->type) {
1979 case XML_SCHEMAS_DATETIME:
1980 ymask = 0xf;
1981 break;
1982 case XML_SCHEMAS_DATE:
1983 ymask = 0x7;
1984 break;
1985 case XML_SCHEMAS_GYEAR:
1986 ymask = 0x1;
1987 break;
1988 case XML_SCHEMAS_GMONTH:
1989 ymask = 0x2;
1990 break;
1991 case XML_SCHEMAS_GDAY:
1992 ymask = 0x3;
1993 break;
1994 case XML_SCHEMAS_GYEARMONTH:
1995 ymask = 0x3;
1996 break;
1997 case XML_SCHEMAS_GMONTHDAY:
1998 ymask = 0x6;
1999 break;
2000 case XML_SCHEMAS_TIME:
2001 ymask = 0x8;
2002 break;
2003 default:
2004 ymask = 0;
2005 break;
2006 }
2007
2008 xor_mask = xmask ^ ymask; /* mark type differences */
2009 and_mask = xmask & ymask; /* mark field specification */
2010
2011 /* year */
2012 if (xor_mask & 1)
2013 return 2; /* indeterminate */
2014 else if (and_mask & 1) {
2015 if (x->value.date.year < y->value.date.year)
2016 return -1;
2017 else if (x->value.date.year > y->value.date.year)
2018 return 1;
2019 }
2020
2021 /* month */
2022 if (xor_mask & 2)
2023 return 2; /* indeterminate */
2024 else if (and_mask & 2) {
2025 if (x->value.date.mon < y->value.date.mon)
2026 return -1;
2027 else if (x->value.date.mon > y->value.date.mon)
2028 return 1;
2029 }
2030
2031 /* day */
2032 if (xor_mask & 4)
2033 return 2; /* indeterminate */
2034 else if (and_mask & 4) {
2035 if (x->value.date.day < y->value.date.day)
2036 return -1;
2037 else if (x->value.date.day > y->value.date.day)
2038 return 1;
2039 }
2040
2041 /* time */
2042 if (xor_mask & 8)
2043 return 2; /* indeterminate */
2044 else if (and_mask & 8) {
2045 if (x->value.date.hour < y->value.date.hour)
2046 return -1;
2047 else if (x->value.date.hour > y->value.date.hour)
2048 return 1;
2049 else if (x->value.date.min < y->value.date.min)
2050 return -1;
2051 else if (x->value.date.min > y->value.date.min)
2052 return 1;
2053 else if (x->value.date.sec < y->value.date.sec)
2054 return -1;
2055 else if (x->value.date.sec > y->value.date.sec)
2056 return 1;
2057 }
2058
Daniel Veillard070803b2002-05-03 07:29:38 +00002059 return 0;
2060}
2061
2062/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002063 * xmlSchemaCompareValues:
2064 * @x: a first value
2065 * @y: a second value
2066 *
2067 * Compare 2 values
2068 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002069 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2070 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002071 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00002072static int
Daniel Veillard4255d502002-04-16 15:50:10 +00002073xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2074 if ((x == NULL) || (y == NULL))
2075 return(-2);
2076
2077 switch (x->type) {
2078 case XML_SCHEMAS_STRING:
2079 TODO
2080 case XML_SCHEMAS_DECIMAL:
2081 if (y->type == XML_SCHEMAS_DECIMAL)
2082 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002083 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002084 case XML_SCHEMAS_DURATION:
2085 if (y->type == XML_SCHEMAS_DURATION)
2086 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002087 return(-2);
2088 case XML_SCHEMAS_TIME:
2089 case XML_SCHEMAS_GDAY:
2090 case XML_SCHEMAS_GMONTH:
2091 case XML_SCHEMAS_GMONTHDAY:
2092 case XML_SCHEMAS_GYEAR:
2093 case XML_SCHEMAS_GYEARMONTH:
2094 case XML_SCHEMAS_DATE:
2095 case XML_SCHEMAS_DATETIME:
2096 if ((y->type == XML_SCHEMAS_DATETIME) ||
2097 (y->type == XML_SCHEMAS_TIME) ||
2098 (y->type == XML_SCHEMAS_GDAY) ||
2099 (y->type == XML_SCHEMAS_GMONTH) ||
2100 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2101 (y->type == XML_SCHEMAS_GYEAR) ||
2102 (y->type == XML_SCHEMAS_DATE) ||
2103 (y->type == XML_SCHEMAS_GYEARMONTH))
2104 return (xmlSchemaCompareDates(x, y));
2105
2106 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002107 default:
2108 TODO
2109 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002110 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002111}
2112
2113/**
2114 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002115 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002116 * @facet: the facet to check
2117 * @value: the lexical repr of the value to validate
2118 * @val: the precomputed value
2119 *
2120 * Check a value against a facet condition
2121 *
2122 * Returns 0 if the element is schemas valid, a positive error code
2123 * number otherwise and -1 in case of internal or API error.
2124 */
2125int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002126xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002127 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002128 const xmlChar *value, xmlSchemaValPtr val)
2129{
2130 int ret;
2131
2132 switch (facet->type) {
2133 case XML_SCHEMA_FACET_PATTERN:
2134 ret = xmlRegexpExec(facet->regexp, value);
2135 if (ret == 1)
2136 return(0);
2137 if (ret == 0) {
2138 TODO /* error code */
2139 return(1);
2140 }
2141 return(ret);
2142 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2143 ret = xmlSchemaCompareValues(val, facet->val);
2144 if (ret == -2) {
2145 TODO /* error code */
2146 return(-1);
2147 }
2148 if (ret == -1)
2149 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002150 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002151 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002152 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2153 ret = xmlSchemaCompareValues(val, facet->val);
2154 if (ret == -2) {
2155 TODO /* error code */
2156 return(-1);
2157 }
2158 if ((ret == -1) || (ret == 0))
2159 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002160 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002161 return(1);
2162 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2163 ret = xmlSchemaCompareValues(val, facet->val);
2164 if (ret == -2) {
2165 TODO /* error code */
2166 return(-1);
2167 }
2168 if (ret == 1)
2169 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002170 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002171 return(1);
2172 case XML_SCHEMA_FACET_MININCLUSIVE:
2173 ret = xmlSchemaCompareValues(val, facet->val);
2174 if (ret == -2) {
2175 TODO /* error code */
2176 return(-1);
2177 }
2178 if ((ret == 1) || (ret == 0))
2179 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002180 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002181 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002182 case XML_SCHEMA_FACET_WHITESPACE:
2183 TODO /* whitespaces */
2184 return(0);
Daniel Veillarde19fc232002-04-22 16:01:24 +00002185 case XML_SCHEMA_FACET_MAXLENGTH:
2186 if ((facet->val != NULL) &&
2187 (facet->val->type == XML_SCHEMAS_DECIMAL) &&
2188 (facet->val->value.decimal.frac == 0)) {
Daniel Veillard118aed72002-09-24 14:13:13 +00002189 unsigned int len;
Daniel Veillarde19fc232002-04-22 16:01:24 +00002190
2191 if (facet->val->value.decimal.sign == 1)
2192 return(1);
2193 len = xmlUTF8Strlen(value);
2194 if (len > facet->val->value.decimal.base)
2195 return(1);
2196 return(0);
2197 }
2198 TODO /* error code */
2199 return(1);
Daniel Veillard88c58912002-04-23 07:12:20 +00002200 case XML_SCHEMA_FACET_ENUMERATION:
2201 if ((facet->value != NULL) &&
2202 (xmlStrEqual(facet->value, value)))
2203 return(0);
2204 return(1);
Daniel Veillard4255d502002-04-16 15:50:10 +00002205 default:
2206 TODO
2207 }
2208 return(0);
2209}
2210
2211#endif /* LIBXML_SCHEMAS_ENABLED */