blob: 05086993386cf12b47789b9bf6e8e9da97476a20 [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,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000045 XML_SCHEMAS_NORMSTRING,
Daniel Veillard4255d502002-04-16 15:50:10 +000046 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 Veillard8bc6cf92003-02-27 17:42:22 +000059 XML_SCHEMAS_TOKEN,
60 XML_SCHEMAS_LANGUAGE,
61 XML_SCHEMAS_NMTOKEN,
62 XML_SCHEMAS_NMTOKENS,
63 XML_SCHEMAS_NAME,
64 XML_SCHEMAS_QNAME,
65 XML_SCHEMAS_NCNAME,
66 XML_SCHEMAS_ID,
67 XML_SCHEMAS_IDREF,
68 XML_SCHEMAS_IDREFS,
69 XML_SCHEMAS_ENTITY,
70 XML_SCHEMAS_ENTITIES,
71 XML_SCHEMAS_NOTATION,
72 XML_SCHEMAS_ANYURI,
73 XML_SCHEMAS_INTEGER,
74 XML_SCHEMAS_NPINTEGER,
75 XML_SCHEMAS_NINTEGER,
76 XML_SCHEMAS_NNINTEGER,
77 XML_SCHEMAS_PINTEGER,
Daniel Veillard96a4b252003-02-06 08:22:32 +000078 XML_SCHEMAS_INT,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000079 XML_SCHEMAS_UINT,
80 XML_SCHEMAS_LONG,
81 XML_SCHEMAS_ULONG,
82 XML_SCHEMAS_SHORT,
83 XML_SCHEMAS_USHORT,
84 XML_SCHEMAS_BYTE,
85 XML_SCHEMAS_UBYTE
Daniel Veillard4255d502002-04-16 15:50:10 +000086} xmlSchemaValType;
87
Daniel Veillard5f704af2003-03-05 10:01:43 +000088static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000089 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
90 100000000L, 1000000000L
91};
92
Daniel Veillard070803b2002-05-03 07:29:38 +000093/* Date value */
94typedef struct _xmlSchemaValDate xmlSchemaValDate;
95typedef xmlSchemaValDate *xmlSchemaValDatePtr;
96struct _xmlSchemaValDate {
97 long year;
98 unsigned int mon :4; /* 1 <= mon <= 12 */
99 unsigned int day :5; /* 1 <= day <= 31 */
100 unsigned int hour :5; /* 0 <= hour <= 23 */
101 unsigned int min :6; /* 0 <= min <= 59 */
102 double sec;
103 int tz_flag :1; /* is tzo explicitely set? */
104 int tzo :11; /* -1440 <= tzo <= 1440 */
105};
106
107/* Duration value */
108typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
109typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
110struct _xmlSchemaValDuration {
111 long mon; /* mon stores years also */
112 long day;
113 double sec; /* sec stores min and hour also */
114};
115
Daniel Veillard4255d502002-04-16 15:50:10 +0000116typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
117typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
118struct _xmlSchemaValDecimal {
119 /* would use long long but not portable */
120 unsigned long base;
121 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +0000122 unsigned int sign:1;
Daniel Veillard4255d502002-04-16 15:50:10 +0000123 int frac:7;
124 int total:8;
125};
126
127struct _xmlSchemaVal {
128 xmlSchemaValType type;
129 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000130 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000131 xmlSchemaValDate date;
132 xmlSchemaValDuration dur;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000133 float f;
134 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000135 int b;
Daniel Veillard4255d502002-04-16 15:50:10 +0000136 } value;
137};
138
139static int xmlSchemaTypesInitialized = 0;
140static xmlHashTablePtr xmlSchemaTypesBank = NULL;
141
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000142/*
143 * Basic types
144 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000145static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000149static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000150static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000151static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
152static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
153static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
154static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
155static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
156static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
157static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000158static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000159static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000160static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000161static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000162
163/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000164 * Derived types
165 */
166static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
170static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
173static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000179static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
180static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
182static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000184static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000185static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
186static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
187static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
188static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
189static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000190
191/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000192 * xmlSchemaInitBasicType:
193 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000194 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000195 *
196 * Initialize one default type
197 */
198static xmlSchemaTypePtr
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000199xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000200 xmlSchemaTypePtr ret;
201
202 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
203 if (ret == NULL) {
204 xmlGenericError(xmlGenericErrorContext,
205 "Could not initilize type %s: out of memory\n", name);
206 return(NULL);
207 }
208 memset(ret, 0, sizeof(xmlSchemaType));
209 ret->name = xmlStrdup((const xmlChar *)name);
210 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000211 ret->flags = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000212 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
213 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
214 XML_SCHEMAS_NAMESPACE_NAME, ret);
215 return(ret);
216}
217
218/*
219 * xmlSchemaInitTypes:
220 *
221 * Initialize the default XML Schemas type library
222 */
223void
224xmlSchemaInitTypes(void) {
225 if (xmlSchemaTypesInitialized != 0)
226 return;
227 xmlSchemaTypesBank = xmlHashCreate(40);
228
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000229 /*
230 * primitive datatypes
231 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000232 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
233 XML_SCHEMAS_STRING);
234 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
235 XML_SCHEMAS_UNKNOWN);
236 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
237 XML_SCHEMAS_UNKNOWN);
238 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
239 XML_SCHEMAS_DECIMAL);
240 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
241 XML_SCHEMAS_DATE);
242 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
243 XML_SCHEMAS_DATETIME);
244 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
245 XML_SCHEMAS_TIME);
246 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
247 XML_SCHEMAS_GYEAR);
248 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
249 XML_SCHEMAS_GYEARMONTH);
250 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
251 XML_SCHEMAS_GMONTH);
252 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
253 XML_SCHEMAS_GMONTHDAY);
254 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
255 XML_SCHEMAS_GDAY);
256 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
257 XML_SCHEMAS_DURATION);
258 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
259 XML_SCHEMAS_FLOAT);
260 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
261 XML_SCHEMAS_DOUBLE);
262 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
263 XML_SCHEMAS_BOOLEAN);
264 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
265 XML_SCHEMAS_ANYURI);
Daniel Veillard4255d502002-04-16 15:50:10 +0000266
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000267 /*
268 * derived datatypes
269 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000270 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
271 XML_SCHEMAS_INTEGER);;
272 xmlSchemaTypeNonPositiveIntegerDef = xmlSchemaInitBasicType("nonPositiveInteger",
273 XML_SCHEMAS_NPINTEGER);;
274 xmlSchemaTypeNegativeIntegerDef = xmlSchemaInitBasicType("negativeInteger",
275 XML_SCHEMAS_NINTEGER);;
276 xmlSchemaTypeLongDef = xmlSchemaInitBasicType("long",
277 XML_SCHEMAS_LONG);;
278 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int",
279 XML_SCHEMAS_INT);;
280 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
281 XML_SCHEMAS_SHORT);;
282 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
283 XML_SCHEMAS_BYTE);;
284 xmlSchemaTypeNonNegativeIntegerDef = xmlSchemaInitBasicType("nonNegativeInteger",
285 XML_SCHEMAS_NNINTEGER);
286 xmlSchemaTypeUnsignedLongDef = xmlSchemaInitBasicType("unsignedLong",
287 XML_SCHEMAS_ULONG);;
288 xmlSchemaTypeUnsignedIntDef = xmlSchemaInitBasicType("unsignedInt",
289 XML_SCHEMAS_UINT);;
290 xmlSchemaTypeUnsignedShortDef = xmlSchemaInitBasicType("insignedShort",
291 XML_SCHEMAS_USHORT);;
292 xmlSchemaTypeUnsignedByteDef = xmlSchemaInitBasicType("unsignedByte",
293 XML_SCHEMAS_UBYTE);;
294 xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger",
295 XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000296
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000297 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
298 XML_SCHEMAS_NORMSTRING);
299 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
300 XML_SCHEMAS_TOKEN);
301 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
302 XML_SCHEMAS_LANGUAGE);
303 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID",
304 XML_SCHEMAS_ID);
305 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
306 XML_SCHEMAS_IDREF);
307 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
308 XML_SCHEMAS_IDREFS);
309 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
310 XML_SCHEMAS_NAME);
311 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
312 XML_SCHEMAS_QNAME);
313 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
314 XML_SCHEMAS_NCNAME);
315 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
316 XML_SCHEMAS_NMTOKEN);
317 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
318 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000319 xmlSchemaTypesInitialized = 1;
320}
321
322/**
323 * xmlSchemaCleanupTypes:
324 *
325 * Cleanup the default XML Schemas type library
326 */
327void
328xmlSchemaCleanupTypes(void) {
329 if (xmlSchemaTypesInitialized == 0)
330 return;
331 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
332 xmlSchemaTypesInitialized = 0;
333}
334
335/**
336 * xmlSchemaNewValue:
337 * @type: the value type
338 *
339 * Allocate a new simple type value
340 *
341 * Returns a pointer to the new value or NULL in case of error
342 */
343static xmlSchemaValPtr
344xmlSchemaNewValue(xmlSchemaValType type) {
345 xmlSchemaValPtr value;
346
347 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
348 if (value == NULL) {
349 return(NULL);
350 }
351 memset(value, 0, sizeof(xmlSchemaVal));
352 value->type = type;
353 return(value);
354}
355
356/**
357 * xmlSchemaFreeValue:
358 * @value: the value to free
359 *
360 * Cleanup the default XML Schemas type library
361 */
362void
363xmlSchemaFreeValue(xmlSchemaValPtr value) {
364 if (value == NULL)
365 return;
366 xmlFree(value);
367}
368
369/**
370 * xmlSchemaGetPredefinedType:
371 * @name: the type name
372 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
373 *
374 * Lookup a type in the default XML Schemas type library
375 *
376 * Returns the type if found, NULL otherwise
377 */
378xmlSchemaTypePtr
379xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
380 if (xmlSchemaTypesInitialized == 0)
381 xmlSchemaInitTypes();
382 if (name == NULL)
383 return(NULL);
384 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
385}
Daniel Veillard070803b2002-05-03 07:29:38 +0000386
387/****************************************************************
388 * *
389 * Convenience macros and functions *
390 * *
391 ****************************************************************/
392
393#define IS_TZO_CHAR(c) \
394 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
395
396#define VALID_YEAR(yr) (yr != 0)
397#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
398/* VALID_DAY should only be used when month is unknown */
399#define VALID_DAY(day) ((day >= 1) && (day <= 31))
400#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
401#define VALID_MIN(min) ((min >= 0) && (min <= 59))
402#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
403#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
404#define IS_LEAP(y) \
405 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
406
407static const long daysInMonth[12] =
408 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
409static const long daysInMonthLeap[12] =
410 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
411
Daniel Veillard5a872412002-05-22 06:40:27 +0000412#define MAX_DAYINMONTH(yr,mon) \
413 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
414
Daniel Veillard070803b2002-05-03 07:29:38 +0000415#define VALID_MDAY(dt) \
416 (IS_LEAP(dt->year) ? \
417 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
418 (dt->day <= daysInMonth[dt->mon - 1]))
419
420#define VALID_DATE(dt) \
421 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
422
423#define VALID_TIME(dt) \
424 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
425 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
426
427#define VALID_DATETIME(dt) \
428 (VALID_DATE(dt) && VALID_TIME(dt))
429
430#define SECS_PER_MIN (60)
431#define SECS_PER_HOUR (60 * SECS_PER_MIN)
432#define SECS_PER_DAY (24 * SECS_PER_HOUR)
433
Daniel Veillard5a872412002-05-22 06:40:27 +0000434static const long dayInYearByMonth[12] =
435 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
436static const long dayInLeapYearByMonth[12] =
437 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
438
439#define DAY_IN_YEAR(day, month, year) \
440 ((IS_LEAP(year) ? \
441 dayInLeapYearByMonth[month - 1] : \
442 dayInYearByMonth[month - 1]) + day)
443
444#ifdef DEBUG
445#define DEBUG_DATE(dt) \
446 xmlGenericError(xmlGenericErrorContext, \
447 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
448 dt->type,dt->value.date.year,dt->value.date.mon, \
449 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
450 dt->value.date.sec); \
451 if (dt->value.date.tz_flag) \
452 if (dt->value.date.tzo != 0) \
453 xmlGenericError(xmlGenericErrorContext, \
454 "%+05d\n",dt->value.date.tzo); \
455 else \
456 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
457 else \
458 xmlGenericError(xmlGenericErrorContext,"\n")
459#else
460#define DEBUG_DATE(dt)
461#endif
462
Daniel Veillard070803b2002-05-03 07:29:38 +0000463/**
464 * _xmlSchemaParseGYear:
465 * @dt: pointer to a date structure
466 * @str: pointer to the string to analyze
467 *
468 * Parses a xs:gYear without time zone and fills in the appropriate
469 * field of the @dt structure. @str is updated to point just after the
470 * xs:gYear. It is supposed that @dt->year is big enough to contain
471 * the year.
472 *
473 * Returns 0 or the error code
474 */
475static int
476_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
477 const xmlChar *cur = *str, *firstChar;
478 int isneg = 0, digcnt = 0;
479
480 if (((*cur < '0') || (*cur > '9')) &&
481 (*cur != '-') && (*cur != '+'))
482 return -1;
483
484 if (*cur == '-') {
485 isneg = 1;
486 cur++;
487 }
488
489 firstChar = cur;
490
491 while ((*cur >= '0') && (*cur <= '9')) {
492 dt->year = dt->year * 10 + (*cur - '0');
493 cur++;
494 digcnt++;
495 }
496
497 /* year must be at least 4 digits (CCYY); over 4
498 * digits cannot have a leading zero. */
499 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
500 return 1;
501
502 if (isneg)
503 dt->year = - dt->year;
504
505 if (!VALID_YEAR(dt->year))
506 return 2;
507
508 *str = cur;
509 return 0;
510}
511
512/**
513 * PARSE_2_DIGITS:
514 * @num: the integer to fill in
515 * @cur: an #xmlChar *
516 * @invalid: an integer
517 *
518 * Parses a 2-digits integer and updates @num with the value. @cur is
519 * updated to point just after the integer.
520 * In case of error, @invalid is set to %TRUE, values of @num and
521 * @cur are undefined.
522 */
523#define PARSE_2_DIGITS(num, cur, invalid) \
524 if ((cur[0] < '0') || (cur[0] > '9') || \
525 (cur[1] < '0') || (cur[1] > '9')) \
526 invalid = 1; \
527 else \
528 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
529 cur += 2;
530
531/**
532 * PARSE_FLOAT:
533 * @num: the double to fill in
534 * @cur: an #xmlChar *
535 * @invalid: an integer
536 *
537 * Parses a float and updates @num with the value. @cur is
538 * updated to point just after the float. The float must have a
539 * 2-digits integer part and may or may not have a decimal part.
540 * In case of error, @invalid is set to %TRUE, values of @num and
541 * @cur are undefined.
542 */
543#define PARSE_FLOAT(num, cur, invalid) \
544 PARSE_2_DIGITS(num, cur, invalid); \
545 if (!invalid && (*cur == '.')) { \
546 double mult = 1; \
547 cur++; \
548 if ((*cur < '0') || (*cur > '9')) \
549 invalid = 1; \
550 while ((*cur >= '0') && (*cur <= '9')) { \
551 mult /= 10; \
552 num += (*cur - '0') * mult; \
553 cur++; \
554 } \
555 }
556
557/**
558 * _xmlSchemaParseGMonth:
559 * @dt: pointer to a date structure
560 * @str: pointer to the string to analyze
561 *
562 * Parses a xs:gMonth without time zone and fills in the appropriate
563 * field of the @dt structure. @str is updated to point just after the
564 * xs:gMonth.
565 *
566 * Returns 0 or the error code
567 */
568static int
569_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
570 const xmlChar *cur = *str;
571 int ret = 0;
572
573 PARSE_2_DIGITS(dt->mon, cur, ret);
574 if (ret != 0)
575 return ret;
576
577 if (!VALID_MONTH(dt->mon))
578 return 2;
579
580 *str = cur;
581 return 0;
582}
583
584/**
585 * _xmlSchemaParseGDay:
586 * @dt: pointer to a date structure
587 * @str: pointer to the string to analyze
588 *
589 * Parses a xs:gDay without time zone and fills in the appropriate
590 * field of the @dt structure. @str is updated to point just after the
591 * xs:gDay.
592 *
593 * Returns 0 or the error code
594 */
595static int
596_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
597 const xmlChar *cur = *str;
598 int ret = 0;
599
600 PARSE_2_DIGITS(dt->day, cur, ret);
601 if (ret != 0)
602 return ret;
603
604 if (!VALID_DAY(dt->day))
605 return 2;
606
607 *str = cur;
608 return 0;
609}
610
611/**
612 * _xmlSchemaParseTime:
613 * @dt: pointer to a date structure
614 * @str: pointer to the string to analyze
615 *
616 * Parses a xs:time without time zone and fills in the appropriate
617 * fields of the @dt structure. @str is updated to point just after the
618 * xs:time.
619 * In case of error, values of @dt fields are undefined.
620 *
621 * Returns 0 or the error code
622 */
623static int
624_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
625 const xmlChar *cur = *str;
626 unsigned int hour = 0; /* use temp var in case str is not xs:time */
627 int ret = 0;
628
629 PARSE_2_DIGITS(hour, cur, ret);
630 if (ret != 0)
631 return ret;
632
633 if (*cur != ':')
634 return 1;
635 cur++;
636
637 /* the ':' insures this string is xs:time */
638 dt->hour = hour;
639
640 PARSE_2_DIGITS(dt->min, cur, ret);
641 if (ret != 0)
642 return ret;
643
644 if (*cur != ':')
645 return 1;
646 cur++;
647
648 PARSE_FLOAT(dt->sec, cur, ret);
649 if (ret != 0)
650 return ret;
651
652 if (!VALID_TIME(dt))
653 return 2;
654
655 *str = cur;
656 return 0;
657}
658
659/**
660 * _xmlSchemaParseTimeZone:
661 * @dt: pointer to a date structure
662 * @str: pointer to the string to analyze
663 *
664 * Parses a time zone without time zone and fills in the appropriate
665 * field of the @dt structure. @str is updated to point just after the
666 * time zone.
667 *
668 * Returns 0 or the error code
669 */
670static int
671_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
672 const xmlChar *cur = *str;
673 int ret = 0;
674
675 if (str == NULL)
676 return -1;
677
678 switch (*cur) {
679 case 0:
680 dt->tz_flag = 0;
681 dt->tzo = 0;
682 break;
683
684 case 'Z':
685 dt->tz_flag = 1;
686 dt->tzo = 0;
687 cur++;
688 break;
689
690 case '+':
691 case '-': {
692 int isneg = 0, tmp = 0;
693 isneg = (*cur == '-');
694
695 cur++;
696
697 PARSE_2_DIGITS(tmp, cur, ret);
698 if (ret != 0)
699 return ret;
700 if (!VALID_HOUR(tmp))
701 return 2;
702
703 if (*cur != ':')
704 return 1;
705 cur++;
706
707 dt->tzo = tmp * 60;
708
709 PARSE_2_DIGITS(tmp, cur, ret);
710 if (ret != 0)
711 return ret;
712 if (!VALID_MIN(tmp))
713 return 2;
714
715 dt->tzo += tmp;
716 if (isneg)
717 dt->tzo = - dt->tzo;
718
719 if (!VALID_TZO(dt->tzo))
720 return 2;
721
Daniel Veillard5a872412002-05-22 06:40:27 +0000722 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000723 break;
724 }
725 default:
726 return 1;
727 }
728
729 *str = cur;
730 return 0;
731}
732
733/****************************************************************
734 * *
735 * XML Schema Dates/Times Datatypes Handling *
736 * *
737 ****************************************************************/
738
739/**
740 * PARSE_DIGITS:
741 * @num: the integer to fill in
742 * @cur: an #xmlChar *
743 * @num_type: an integer flag
744 *
745 * Parses a digits integer and updates @num with the value. @cur is
746 * updated to point just after the integer.
747 * In case of error, @num_type is set to -1, values of @num and
748 * @cur are undefined.
749 */
750#define PARSE_DIGITS(num, cur, num_type) \
751 if ((*cur < '0') || (*cur > '9')) \
752 num_type = -1; \
753 else \
754 while ((*cur >= '0') && (*cur <= '9')) { \
755 num = num * 10 + (*cur - '0'); \
756 cur++; \
757 }
758
759/**
760 * PARSE_NUM:
761 * @num: the double to fill in
762 * @cur: an #xmlChar *
763 * @num_type: an integer flag
764 *
765 * Parses a float or integer and updates @num with the value. @cur is
766 * updated to point just after the number. If the number is a float,
767 * then it must have an integer part and a decimal part; @num_type will
768 * be set to 1. If there is no decimal part, @num_type is set to zero.
769 * In case of error, @num_type is set to -1, values of @num and
770 * @cur are undefined.
771 */
772#define PARSE_NUM(num, cur, num_type) \
773 num = 0; \
774 PARSE_DIGITS(num, cur, num_type); \
775 if (!num_type && (*cur == '.')) { \
776 double mult = 1; \
777 cur++; \
778 if ((*cur < '0') || (*cur > '9')) \
779 num_type = -1; \
780 else \
781 num_type = 1; \
782 while ((*cur >= '0') && (*cur <= '9')) { \
783 mult /= 10; \
784 num += (*cur - '0') * mult; \
785 cur++; \
786 } \
787 }
788
789/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000790 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000791 * @type: the predefined type
792 * @dateTime: string to analyze
793 * @val: the return computed value
794 *
795 * Check that @dateTime conforms to the lexical space of one of the date types.
796 * if true a value is computed and returned in @val.
797 *
798 * Returns 0 if this validates, a positive error code number otherwise
799 * and -1 in case of internal or API error.
800 */
801static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000802xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000803 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000804 xmlSchemaValPtr dt;
805 int ret;
806 const xmlChar *cur = dateTime;
807
808#define RETURN_TYPE_IF_VALID(t) \
809 if (IS_TZO_CHAR(*cur)) { \
810 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
811 if (ret == 0) { \
812 if (*cur != 0) \
813 goto error; \
814 dt->type = t; \
815 if (val != NULL) \
816 *val = dt; \
817 return 0; \
818 } \
819 }
820
821 if (dateTime == NULL)
822 return -1;
823
824 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
825 return 1;
826
827 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
828 if (dt == NULL)
829 return -1;
830
831 if ((cur[0] == '-') && (cur[1] == '-')) {
832 /*
833 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
834 * xs:gDay)
835 */
836 cur += 2;
837
838 /* is it an xs:gDay? */
839 if (*cur == '-') {
840 ++cur;
841 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
842 if (ret != 0)
843 goto error;
844
845 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
846
847 goto error;
848 }
849
850 /*
851 * it should be an xs:gMonthDay or xs:gMonth
852 */
853 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
854 if (ret != 0)
855 goto error;
856
857 if (*cur != '-')
858 goto error;
859 cur++;
860
861 /* is it an xs:gMonth? */
862 if (*cur == '-') {
863 cur++;
864 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
865 goto error;
866 }
867
868 /* it should be an xs:gMonthDay */
869 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
870 if (ret != 0)
871 goto error;
872
873 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
874
875 goto error;
876 }
877
878 /*
879 * It's a right-truncated date or an xs:time.
880 * Try to parse an xs:time then fallback on right-truncated dates.
881 */
882 if ((*cur >= '0') && (*cur <= '9')) {
883 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
884 if (ret == 0) {
885 /* it's an xs:time */
886 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
887 }
888 }
889
890 /* fallback on date parsing */
891 cur = dateTime;
892
893 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
894 if (ret != 0)
895 goto error;
896
897 /* is it an xs:gYear? */
898 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
899
900 if (*cur != '-')
901 goto error;
902 cur++;
903
904 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
905 if (ret != 0)
906 goto error;
907
908 /* is it an xs:gYearMonth? */
909 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
910
911 if (*cur != '-')
912 goto error;
913 cur++;
914
915 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
916 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
917 goto error;
918
919 /* is it an xs:date? */
920 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
921
922 if (*cur != 'T')
923 goto error;
924 cur++;
925
926 /* it should be an xs:dateTime */
927 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
928 if (ret != 0)
929 goto error;
930
931 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
932 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
933 goto error;
934
935 dt->type = XML_SCHEMAS_DATETIME;
936
937 if (val != NULL)
938 *val = dt;
939
940 return 0;
941
942error:
943 if (dt != NULL)
944 xmlSchemaFreeValue(dt);
945 return 1;
946}
947
948/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000949 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000950 * @type: the predefined type
951 * @duration: string to analyze
952 * @val: the return computed value
953 *
954 * Check that @duration conforms to the lexical space of the duration type.
955 * if true a value is computed and returned in @val.
956 *
957 * Returns 0 if this validates, a positive error code number otherwise
958 * and -1 in case of internal or API error.
959 */
960static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000961xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000962 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000963 const xmlChar *cur = duration;
964 xmlSchemaValPtr dur;
965 int isneg = 0;
966 unsigned int seq = 0;
967
968 if (duration == NULL)
969 return -1;
970
971 if (*cur == '-') {
972 isneg = 1;
973 cur++;
974 }
975
976 /* duration must start with 'P' (after sign) */
977 if (*cur++ != 'P')
978 return 1;
979
980 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
981 if (dur == NULL)
982 return -1;
983
984 while (*cur != 0) {
985 double num;
986 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
987 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
988 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
989
990 /* input string should be empty or invalid date/time item */
991 if (seq >= sizeof(desig))
992 goto error;
993
994 /* T designator must be present for time items */
995 if (*cur == 'T') {
996 if (seq <= 3) {
997 seq = 3;
998 cur++;
999 } else
1000 return 1;
1001 } else if (seq == 3)
1002 goto error;
1003
1004 /* parse the number portion of the item */
1005 PARSE_NUM(num, cur, num_type);
1006
1007 if ((num_type == -1) || (*cur == 0))
1008 goto error;
1009
1010 /* update duration based on item type */
1011 while (seq < sizeof(desig)) {
1012 if (*cur == desig[seq]) {
1013
1014 /* verify numeric type; only seconds can be float */
1015 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1016 goto error;
1017
1018 switch (seq) {
1019 case 0:
1020 dur->value.dur.mon = (long)num * 12;
1021 break;
1022 case 1:
1023 dur->value.dur.mon += (long)num;
1024 break;
1025 default:
1026 /* convert to seconds using multiplier */
1027 dur->value.dur.sec += num * multi[seq];
1028 seq++;
1029 break;
1030 }
1031
1032 break; /* exit loop */
1033 }
1034 /* no date designators found? */
1035 if (++seq == 3)
1036 goto error;
1037 }
1038 cur++;
1039 }
1040
1041 if (isneg) {
1042 dur->value.dur.mon = -dur->value.dur.mon;
1043 dur->value.dur.day = -dur->value.dur.day;
1044 dur->value.dur.sec = -dur->value.dur.sec;
1045 }
1046
1047 if (val != NULL)
1048 *val = dur;
1049
1050 return 0;
1051
1052error:
1053 if (dur != NULL)
1054 xmlSchemaFreeValue(dur);
1055 return 1;
1056}
1057
Daniel Veillard96a4b252003-02-06 08:22:32 +00001058
1059/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001060 * xmlSchemaValAtomicListNode:
1061 * @type: the predefined atomic type for a token in the list
1062 * @value: the list value to check
1063 * @ret: the return computed value
1064 * @node: the node containing the value
1065 *
1066 * Check that a value conforms to the lexical space of the predefined
1067 * list type. if true a value is computed and returned in @ret.
1068 *
1069 * Returns 0 if this validates, a positive error code number otherwise
1070 * and -1 in case of internal or API error.
1071 */
1072static int
1073xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1074 xmlSchemaValPtr *ret, xmlNodePtr node) {
1075 xmlChar *val, *cur, *endval;
1076 int nb_values = 0;
1077 int tmp;
1078
1079 if (value == NULL) {
1080 return(-1);
1081 }
1082 val = xmlStrdup(value);
1083 if (val == NULL) {
1084 return(-1);
1085 }
1086 cur = val;
1087 /*
1088 * Split the list
1089 */
1090 while (IS_BLANK(*cur)) cur++;
1091 while (*cur != 0) {
1092 if (IS_BLANK(*cur)) {
1093 *cur = 0;
1094 cur++;
1095 while (IS_BLANK(*cur)) *cur++ = 0;
1096 } else {
1097 nb_values++;
1098 cur++;
1099 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1100 }
1101 }
1102 if (nb_values == 0) {
1103 if (ret != NULL) {
1104 TODO
1105 }
1106 xmlFree(val);
1107 return(0);
1108 }
1109 endval = cur;
1110 cur = val;
1111 while ((*cur == 0) && (cur != endval)) cur++;
1112 while (cur != endval) {
1113 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1114 if (tmp != 0)
1115 break;
1116 while (*cur != 0) cur++;
1117 while ((*cur == 0) && (cur != endval)) cur++;
1118 }
1119 xmlFree(val);
1120 if (ret != NULL) {
1121 TODO
1122 }
1123 return(tmp);
1124}
1125
1126/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001127 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00001128 * @type: the predefined type
1129 * @value: the value to check
1130 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001131 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00001132 *
1133 * Check that a value conforms to the lexical space of the predefined type.
1134 * if true a value is computed and returned in @val.
1135 *
1136 * Returns 0 if this validates, a positive error code number otherwise
1137 * and -1 in case of internal or API error.
1138 */
1139int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001140xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
1141 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001142 xmlSchemaValPtr v;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001143 int ret;
Daniel Veillard4255d502002-04-16 15:50:10 +00001144
1145 if (xmlSchemaTypesInitialized == 0)
1146 return(-1);
1147 if (type == NULL)
1148 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001149
Daniel Veillard4255d502002-04-16 15:50:10 +00001150 if (val != NULL)
1151 *val = NULL;
1152 if (type == xmlSchemaTypeStringDef) {
1153 return(0);
1154 } else if (type == xmlSchemaTypeAnyTypeDef) {
1155 return(0);
1156 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
1157 return(0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001158 } else if (type == xmlSchemaTypeNmtokenDef) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001159 if (xmlValidateNmtokenValue(value))
1160 return(0);
1161 return(1);
1162 } else if (type == xmlSchemaTypeDecimalDef) {
1163 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001164 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001165 unsigned long base = 0;
1166 if (cur == NULL)
1167 return(1);
1168 if (*cur == '+')
1169 cur++;
1170 else if (*cur == '-') {
1171 neg = 1;
1172 cur++;
1173 }
1174 tmp = cur;
1175 while ((*cur >= '0') && (*cur <= '9')) {
1176 base = base * 10 + (*cur - '0');
1177 cur++;
1178 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001179 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001180 if (*cur == '.') {
1181 cur++;
1182 tmp = cur;
1183 while ((*cur >= '0') && (*cur <= '9')) {
1184 base = base * 10 + (*cur - '0');
1185 cur++;
1186 }
1187 frac = cur - tmp;
1188 }
1189 if (*cur != 0)
1190 return(1);
1191 if (val != NULL) {
1192 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1193 if (v != NULL) {
1194 v->value.decimal.base = base;
1195 v->value.decimal.sign = neg;
1196 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001197 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001198 *val = v;
1199 }
1200 }
1201 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001202 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001203 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001204 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1205 (type == xmlSchemaTypeTimeDef) ||
1206 (type == xmlSchemaTypeDateDef) ||
1207 (type == xmlSchemaTypeGYearDef) ||
1208 (type == xmlSchemaTypeGYearMonthDef) ||
1209 (type == xmlSchemaTypeGMonthDef) ||
1210 (type == xmlSchemaTypeGMonthDayDef) ||
1211 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001212 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001213 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1214 const xmlChar *cur = value;
1215 unsigned long base = 0;
1216 int total = 0;
1217 if (cur == NULL)
1218 return(1);
1219 if (*cur == '+')
1220 cur++;
1221 while ((*cur >= '0') && (*cur <= '9')) {
1222 base = base * 10 + (*cur - '0');
1223 total++;
1224 cur++;
1225 }
1226 if (*cur != 0)
1227 return(1);
1228 if (val != NULL) {
1229 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1230 if (v != NULL) {
1231 v->value.decimal.base = base;
1232 v->value.decimal.sign = 0;
1233 v->value.decimal.frac = 0;
1234 v->value.decimal.total = total;
1235 *val = v;
1236 }
1237 }
1238 return(0);
1239 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1240 const xmlChar *cur = value;
1241 unsigned long base = 0;
1242 int total = 0;
1243 int sign = 0;
1244 if (cur == NULL)
1245 return(1);
1246 if (*cur == '-') {
1247 sign = 1;
1248 cur++;
1249 } else if (*cur == '+')
1250 cur++;
1251 while ((*cur >= '0') && (*cur <= '9')) {
1252 base = base * 10 + (*cur - '0');
1253 total++;
1254 cur++;
1255 }
1256 if (*cur != 0)
1257 return(1);
1258 if ((sign == 1) && (base != 0))
1259 return(1);
1260 if (val != NULL) {
1261 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1262 if (v != NULL) {
1263 v->value.decimal.base = base;
1264 v->value.decimal.sign = 0;
1265 v->value.decimal.frac = 0;
1266 v->value.decimal.total = total;
1267 *val = v;
1268 }
1269 }
1270 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001271 } else if (type == xmlSchemaTypeIntDef) {
1272 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001273 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001274 int total = 0;
1275 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001276 if (cur == NULL)
1277 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001278 if (*cur == '-') {
1279 sign = 1;
1280 cur++;
1281 } else if (*cur == '+')
1282 cur++;
1283 while (*cur == '0') {
1284 total++;
1285 cur++;
1286 }
1287 while ((*cur >= '0') && (*cur <= '9')) {
1288 base = base * 10 + (*cur - '0');
1289 total++;
1290 cur++;
1291 }
1292 if (*cur != 0)
1293 return(1);
1294 if ((sign == 1) && (total == 0))
1295 return(1);
1296 if (val != NULL) {
1297 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1298 if (v != NULL) {
1299 v->value.decimal.base = base;
1300 v->value.decimal.sign = sign;
1301 v->value.decimal.frac = 0;
1302 v->value.decimal.total = total;
1303 *val = v;
1304 }
1305 }
1306 return(0);
1307 } else if ((type == xmlSchemaTypeFloatDef) ||
1308 (type == xmlSchemaTypeDoubleDef)) {
1309 const xmlChar *cur = value;
1310 int neg = 0;
1311 if (cur == NULL)
1312 return(1);
1313 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1314 cur += 3;
1315 if (*cur != 0)
1316 return(1);
1317 if (val != NULL) {
1318 if (type == xmlSchemaTypeFloatDef) {
1319 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1320 if (v != NULL) {
1321 v->value.f = (float) xmlXPathNAN;
1322 } else {
1323 xmlSchemaFreeValue(v);
1324 return(-1);
1325 }
1326 } else {
1327 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1328 if (v != NULL) {
1329 v->value.d = xmlXPathNAN;
1330 } else {
1331 xmlSchemaFreeValue(v);
1332 return(-1);
1333 }
1334 }
1335 *val = v;
1336 }
1337 return(0);
1338 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001339 if (*cur == '+')
1340 cur++;
1341 else if (*cur == '-') {
1342 neg = 1;
1343 cur++;
1344 }
Daniel Veillardd4310742003-02-18 21:12:46 +00001345 if (cur[0] == 0)
1346 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001347 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1348 cur += 3;
1349 if (*cur != 0)
1350 return(1);
1351 if (val != NULL) {
1352 if (type == xmlSchemaTypeFloatDef) {
1353 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1354 if (v != NULL) {
1355 if (neg)
1356 v->value.f = (float) xmlXPathNINF;
1357 else
1358 v->value.f = (float) xmlXPathPINF;
1359 } else {
1360 xmlSchemaFreeValue(v);
1361 return(-1);
1362 }
1363 } else {
1364 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1365 if (v != NULL) {
1366 if (neg)
1367 v->value.d = xmlXPathNINF;
1368 else
1369 v->value.d = xmlXPathPINF;
1370 } else {
1371 xmlSchemaFreeValue(v);
1372 return(-1);
1373 }
1374 }
1375 *val = v;
1376 }
1377 return(0);
1378 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001379 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001380 cur++;
1381 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001382 if (*cur == '.') {
1383 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001384 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001385 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001386 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001387 if ((*cur == 'e') || (*cur == 'E')) {
1388 cur++;
1389 if (*cur == '-')
1390 cur++;
1391 while ((*cur >= '0') && (*cur <= '9'))
1392 cur++;
1393 }
1394 if (*cur != 0)
1395 return(1);
1396 if (val != NULL) {
1397 if (type == xmlSchemaTypeFloatDef) {
1398 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1399 if (v != NULL) {
1400 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1401 *val = v;
1402 } else {
1403 xmlGenericError(xmlGenericErrorContext,
1404 "failed to scanf float %s\n", value);
1405 xmlSchemaFreeValue(v);
1406 return(1);
1407 }
1408 } else {
1409 return(-1);
1410 }
1411 } else {
1412 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1413 if (v != NULL) {
1414 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1415 *val = v;
1416 } else {
1417 xmlGenericError(xmlGenericErrorContext,
1418 "failed to scanf double %s\n", value);
1419 xmlSchemaFreeValue(v);
1420 return(1);
1421 }
1422 } else {
1423 return(-1);
1424 }
1425 }
1426 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001427 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001428 } else if (type == xmlSchemaTypeNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001429 ret = xmlValidateName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001430 if ((ret == 0) && (val != NULL)) {
1431 TODO;
1432 }
1433 return(ret);
1434 } else if (type == xmlSchemaTypeQNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001435 ret = xmlValidateQName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001436 if ((ret == 0) && (val != NULL)) {
1437 TODO;
1438 }
1439 return(ret);
1440 } else if (type == xmlSchemaTypeNCNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001441 ret = xmlValidateNCName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001442 if ((ret == 0) && (val != NULL)) {
1443 TODO;
1444 }
1445 return(ret);
1446 } else if (type == xmlSchemaTypeAnyURIDef) {
1447 xmlURIPtr uri;
1448
1449 uri = xmlParseURI((const char *) value);
1450 if (uri == NULL)
1451 return(1);
1452 if (val != NULL) {
1453 TODO;
1454 }
1455 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001456 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001457 } else if (type == xmlSchemaTypeBooleanDef) {
1458 const xmlChar *cur = value;
1459
1460 if ((cur[0] == '0') && (cur[1] == 0))
1461 ret = 0;
1462 else if ((cur[0] == '1') && (cur[1] == 0))
1463 ret = 1;
1464 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1465 (cur[3] == 'e') && (cur[4] == 0))
1466 ret = 1;
1467 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1468 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1469 ret = 0;
1470 else
1471 return(1);
1472 if (val != NULL) {
1473 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1474 if (v != NULL) {
1475 v->value.b = ret;
1476 *val = v;
1477 } else {
1478 return(-1);
1479 }
1480 }
1481 return(0);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001482 } else if (type == xmlSchemaTypeIdrefDef) {
1483 ret = xmlValidateNCName(value, 1);
1484 if ((ret == 0) && (val != NULL)) {
1485 TODO;
1486 }
1487 if ((ret == 0) && (node != NULL) &&
1488 (node->type == XML_ATTRIBUTE_NODE)) {
1489 xmlAttrPtr attr = (xmlAttrPtr) node;
1490
1491 xmlAddRef(NULL, node->doc, value, attr);
1492 attr->atype = XML_ATTRIBUTE_IDREF;
1493 }
1494 return(ret);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001495 } else if (type == xmlSchemaTypeIdrefsDef) {
1496 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1497 value, val, node);
1498 if ((ret == 0) && (node != NULL) &&
1499 (node->type == XML_ATTRIBUTE_NODE)) {
1500 xmlAttrPtr attr = (xmlAttrPtr) node;
1501
1502 attr->atype = XML_ATTRIBUTE_IDREFS;
1503 }
1504 return(ret);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001505 } else if (type == xmlSchemaTypeIdDef) {
1506 ret = xmlValidateNCName(value, 1);
1507 if ((ret == 0) && (val != NULL)) {
1508 TODO;
1509 }
1510 if ((ret == 0) && (node != NULL) &&
1511 (node->type == XML_ATTRIBUTE_NODE)) {
1512 xmlAttrPtr attr = (xmlAttrPtr) node;
1513 xmlIDPtr res;
1514
1515 res = xmlAddID(NULL, node->doc, value, attr);
1516 if (res == NULL) {
1517 ret = 2;
1518 } else {
1519 attr->atype = XML_ATTRIBUTE_ID;
1520 }
1521 }
1522 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001523 } else {
1524 TODO
1525 return(0);
1526 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001527 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001528}
1529
1530/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001531 * xmlSchemaValidatePredefinedType:
1532 * @type: the predefined type
1533 * @value: the value to check
1534 * @val: the return computed value
1535 *
1536 * Check that a value conforms to the lexical space of the predefined type.
1537 * if true a value is computed and returned in @val.
1538 *
1539 * Returns 0 if this validates, a positive error code number otherwise
1540 * and -1 in case of internal or API error.
1541 */
1542int
1543xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1544 xmlSchemaValPtr *val) {
1545 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
1546}
1547
1548/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001549 * xmlSchemaCompareDecimals:
1550 * @x: a first decimal value
1551 * @y: a second decimal value
1552 *
1553 * Compare 2 decimals
1554 *
1555 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1556 */
1557static int
1558xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1559{
1560 xmlSchemaValPtr swp;
1561 int order = 1;
1562 unsigned long tmp;
1563
1564 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1565 order = -1;
1566 else if (x->value.decimal.sign)
1567 return (-1);
1568 else if (y->value.decimal.sign)
1569 return (1);
1570 if (x->value.decimal.frac == y->value.decimal.frac) {
1571 if (x->value.decimal.base < y->value.decimal.base)
1572 return (-1);
1573 return (x->value.decimal.base > y->value.decimal.base);
1574 }
1575 if (y->value.decimal.frac > x->value.decimal.frac) {
1576 swp = y;
1577 y = x;
1578 x = swp;
1579 order = -order;
1580 }
1581 tmp =
1582 x->value.decimal.base / powten[x->value.decimal.frac -
1583 y->value.decimal.frac];
1584 if (tmp > y->value.decimal.base)
1585 return (order);
1586 if (tmp < y->value.decimal.base)
1587 return (-order);
1588 tmp =
1589 y->value.decimal.base * powten[x->value.decimal.frac -
1590 y->value.decimal.frac];
1591 if (x->value.decimal.base < tmp)
1592 return (-order);
1593 if (x->value.decimal.base == tmp)
1594 return (0);
1595 return (order);
1596}
1597
1598/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001599 * xmlSchemaCompareDurations:
1600 * @x: a first duration value
1601 * @y: a second duration value
1602 *
1603 * Compare 2 durations
1604 *
1605 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1606 * case of error
1607 */
1608static int
1609xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1610{
1611 long carry, mon, day;
1612 double sec;
1613 long xmon, xday, myear, lyear, minday, maxday;
1614 static const long dayRange [2][12] = {
1615 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1616 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1617
1618 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001619 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001620
1621 /* months */
1622 mon = x->value.dur.mon - y->value.dur.mon;
1623
1624 /* seconds */
1625 sec = x->value.dur.sec - y->value.dur.sec;
1626 carry = (long)sec / SECS_PER_DAY;
1627 sec -= (double)(carry * SECS_PER_DAY);
1628
1629 /* days */
1630 day = x->value.dur.day - y->value.dur.day + carry;
1631
1632 /* easy test */
1633 if (mon == 0) {
1634 if (day == 0)
1635 if (sec == 0.0)
1636 return 0;
1637 else if (sec < 0.0)
1638 return -1;
1639 else
1640 return 1;
1641 else if (day < 0)
1642 return -1;
1643 else
1644 return 1;
1645 }
1646
1647 if (mon > 0) {
1648 if ((day >= 0) && (sec >= 0.0))
1649 return 1;
1650 else {
1651 xmon = mon;
1652 xday = -day;
1653 }
1654 } else if ((day <= 0) && (sec <= 0.0)) {
1655 return -1;
1656 } else {
1657 xmon = -mon;
1658 xday = day;
1659 }
1660
1661 myear = xmon / 12;
1662 lyear = myear / 4;
1663 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1664 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1665
1666 xmon = xmon % 12;
1667 minday += dayRange[0][xmon];
1668 maxday += dayRange[1][xmon];
1669
1670 if (maxday < xday)
1671 return 1;
1672 else if (minday > xday)
1673 return -1;
1674
1675 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001676 return 2;
1677}
1678
1679/*
1680 * macros for adding date/times and durations
1681 */
1682#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1683#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1684#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1685#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1686
1687/**
1688 * _xmlSchemaDateAdd:
1689 * @dt: an #xmlSchemaValPtr
1690 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1691 *
1692 * Compute a new date/time from @dt and @dur. This function assumes @dt
1693 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1694 * or #XML_SCHEMAS_GYEAR.
1695 *
1696 * Returns date/time pointer or NULL.
1697 */
1698static xmlSchemaValPtr
1699_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1700{
1701 xmlSchemaValPtr ret;
1702 long carry, tempdays, temp;
1703 xmlSchemaValDatePtr r, d;
1704 xmlSchemaValDurationPtr u;
1705
1706 if ((dt == NULL) || (dur == NULL))
1707 return NULL;
1708
1709 ret = xmlSchemaNewValue(dt->type);
1710 if (ret == NULL)
1711 return NULL;
1712
1713 r = &(ret->value.date);
1714 d = &(dt->value.date);
1715 u = &(dur->value.dur);
1716
1717 /* normalization */
1718 if (d->mon == 0)
1719 d->mon = 1;
1720
1721 /* normalize for time zone offset */
1722 u->sec -= (d->tzo * 60);
1723 d->tzo = 0;
1724
1725 /* normalization */
1726 if (d->day == 0)
1727 d->day = 1;
1728
1729 /* month */
1730 carry = d->mon + u->mon;
1731 r->mon = MODULO_RANGE(carry, 1, 13);
1732 carry = FQUOTIENT_RANGE(carry, 1, 13);
1733
1734 /* year (may be modified later) */
1735 r->year = d->year + carry;
1736 if (r->year == 0) {
1737 if (d->year > 0)
1738 r->year--;
1739 else
1740 r->year++;
1741 }
1742
1743 /* time zone */
1744 r->tzo = d->tzo;
1745 r->tz_flag = d->tz_flag;
1746
1747 /* seconds */
1748 r->sec = d->sec + u->sec;
1749 carry = FQUOTIENT((long)r->sec, 60);
1750 if (r->sec != 0.0) {
1751 r->sec = MODULO(r->sec, 60.0);
1752 }
1753
1754 /* minute */
1755 carry += d->min;
1756 r->min = MODULO(carry, 60);
1757 carry = FQUOTIENT(carry, 60);
1758
1759 /* hours */
1760 carry += d->hour;
1761 r->hour = MODULO(carry, 24);
1762 carry = FQUOTIENT(carry, 24);
1763
1764 /*
1765 * days
1766 * Note we use tempdays because the temporary values may need more
1767 * than 5 bits
1768 */
1769 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1770 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1771 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1772 else if (d->day < 1)
1773 tempdays = 1;
1774 else
1775 tempdays = d->day;
1776
1777 tempdays += u->day + carry;
1778
1779 while (1) {
1780 if (tempdays < 1) {
1781 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1782 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1783 if (tyr == 0)
1784 tyr--;
1785 tempdays += MAX_DAYINMONTH(tyr, tmon);
1786 carry = -1;
1787 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1788 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1789 carry = 1;
1790 } else
1791 break;
1792
1793 temp = r->mon + carry;
1794 r->mon = MODULO_RANGE(temp, 1, 13);
1795 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1796 if (r->year == 0) {
1797 if (temp < 1)
1798 r->year--;
1799 else
1800 r->year++;
1801 }
1802 }
1803
1804 r->day = tempdays;
1805
1806 /*
1807 * adjust the date/time type to the date values
1808 */
1809 if (ret->type != XML_SCHEMAS_DATETIME) {
1810 if ((r->hour) || (r->min) || (r->sec))
1811 ret->type = XML_SCHEMAS_DATETIME;
1812 else if (ret->type != XML_SCHEMAS_DATE) {
1813 if ((r->mon != 1) && (r->day != 1))
1814 ret->type = XML_SCHEMAS_DATE;
1815 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1816 ret->type = XML_SCHEMAS_GYEARMONTH;
1817 }
1818 }
1819
1820 return ret;
1821}
1822
1823/**
1824 * xmlSchemaDupVal:
1825 * @v: value to duplicate
1826 *
1827 * returns a duplicated value.
1828 */
1829static xmlSchemaValPtr
1830xmlSchemaDupVal (xmlSchemaValPtr v)
1831{
1832 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1833 if (ret == NULL)
1834 return ret;
1835
1836 memcpy(ret, v, sizeof(xmlSchemaVal));
1837 return ret;
1838}
1839
1840/**
1841 * xmlSchemaDateNormalize:
1842 * @dt: an #xmlSchemaValPtr
1843 *
1844 * Normalize @dt to GMT time.
1845 *
1846 */
1847static xmlSchemaValPtr
1848xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1849{
1850 xmlSchemaValPtr dur, ret;
1851
1852 if (dt == NULL)
1853 return NULL;
1854
1855 if (((dt->type != XML_SCHEMAS_TIME) &&
1856 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1857 return xmlSchemaDupVal(dt);
1858
1859 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1860 if (dur == NULL)
1861 return NULL;
1862
1863 dur->value.date.sec -= offset;
1864
1865 ret = _xmlSchemaDateAdd(dt, dur);
1866 if (ret == NULL)
1867 return NULL;
1868
1869 xmlSchemaFreeValue(dur);
1870
1871 /* ret->value.date.tzo = 0; */
1872 return ret;
1873}
1874
1875/**
1876 * _xmlSchemaDateCastYMToDays:
1877 * @dt: an #xmlSchemaValPtr
1878 *
1879 * Convert mon and year of @dt to total number of days. Take the
1880 * number of years since (or before) 1 AD and add the number of leap
1881 * years. This is a function because negative
1882 * years must be handled a little differently and there is no zero year.
1883 *
1884 * Returns number of days.
1885 */
1886static long
1887_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
1888{
1889 long ret;
1890
1891 if (dt->value.date.year < 0)
1892 ret = (dt->value.date.year * 365) +
1893 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1894 ((dt->value.date.year+1)/400)) +
1895 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1896 else
1897 ret = ((dt->value.date.year-1) * 365) +
1898 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1899 ((dt->value.date.year-1)/400)) +
1900 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1901
1902 return ret;
1903}
1904
1905/**
1906 * TIME_TO_NUMBER:
1907 * @dt: an #xmlSchemaValPtr
1908 *
1909 * Calculates the number of seconds in the time portion of @dt.
1910 *
1911 * Returns seconds.
1912 */
1913#define TIME_TO_NUMBER(dt) \
1914 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
1915 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
1916
1917/**
1918 * xmlSchemaCompareDates:
1919 * @x: a first date/time value
1920 * @y: a second date/time value
1921 *
1922 * Compare 2 date/times
1923 *
1924 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1925 * case of error
1926 */
1927static int
1928xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
1929{
1930 unsigned char xmask, ymask, xor_mask, and_mask;
1931 xmlSchemaValPtr p1, p2, q1, q2;
1932 long p1d, p2d, q1d, q2d;
1933
1934 if ((x == NULL) || (y == NULL))
1935 return -2;
1936
1937 if (x->value.date.tz_flag) {
1938
1939 if (!y->value.date.tz_flag) {
1940 p1 = xmlSchemaDateNormalize(x, 0);
1941 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1942 /* normalize y + 14:00 */
1943 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
1944
1945 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001946 if (p1d < q1d) {
1947 xmlSchemaFreeValue(p1);
1948 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001949 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001950 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001951 double sec;
1952
1953 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001954 if (sec < 0.0) {
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 {
Daniel Veillard5a872412002-05-22 06:40:27 +00001959 /* normalize y - 14:00 */
1960 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
1961 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001962 xmlSchemaFreeValue(p1);
1963 xmlSchemaFreeValue(q1);
1964 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00001965 if (p1d > q2d)
1966 return 1;
1967 else if (p1d == q2d) {
1968 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
1969 if (sec > 0.0)
1970 return 1;
1971 else
1972 return 2; /* indeterminate */
1973 }
1974 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001975 } else {
1976 xmlSchemaFreeValue(p1);
1977 xmlSchemaFreeValue(q1);
1978 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001979 }
1980 } else if (y->value.date.tz_flag) {
1981 q1 = xmlSchemaDateNormalize(y, 0);
1982 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
1983
1984 /* normalize x - 14:00 */
1985 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
1986 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
1987
Daniel Veillardfdc91562002-07-01 21:52:03 +00001988 if (p1d < q1d) {
1989 xmlSchemaFreeValue(p1);
1990 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001991 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001992 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001993 double sec;
1994
1995 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001996 if (sec < 0.0) {
1997 xmlSchemaFreeValue(p1);
1998 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001999 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002000 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002001 /* normalize x + 14:00 */
2002 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2003 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2004
Daniel Veillardfdc91562002-07-01 21:52:03 +00002005 xmlSchemaFreeValue(p1);
2006 xmlSchemaFreeValue(q1);
2007 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002008 if (p2d > q1d)
2009 return 1;
2010 else if (p2d == q1d) {
2011 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
2012 if (sec > 0.0)
2013 return 1;
2014 else
2015 return 2; /* indeterminate */
2016 }
2017 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002018 } else {
2019 xmlSchemaFreeValue(p1);
2020 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002021 }
2022 }
2023
2024 /*
2025 * if the same type then calculate the difference
2026 */
2027 if (x->type == y->type) {
2028 q1 = xmlSchemaDateNormalize(y, 0);
2029 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2030
2031 p1 = xmlSchemaDateNormalize(x, 0);
2032 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2033
Daniel Veillardfdc91562002-07-01 21:52:03 +00002034 if (p1d < q1d) {
2035 xmlSchemaFreeValue(p1);
2036 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002037 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002038 } else if (p1d > q1d) {
2039 xmlSchemaFreeValue(p1);
2040 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002041 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002042 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002043 double sec;
2044
2045 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002046 xmlSchemaFreeValue(p1);
2047 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002048 if (sec < 0.0)
2049 return -1;
2050 else if (sec > 0.0)
2051 return 1;
2052
2053 }
2054 return 0;
2055 }
2056
2057 switch (x->type) {
2058 case XML_SCHEMAS_DATETIME:
2059 xmask = 0xf;
2060 break;
2061 case XML_SCHEMAS_DATE:
2062 xmask = 0x7;
2063 break;
2064 case XML_SCHEMAS_GYEAR:
2065 xmask = 0x1;
2066 break;
2067 case XML_SCHEMAS_GMONTH:
2068 xmask = 0x2;
2069 break;
2070 case XML_SCHEMAS_GDAY:
2071 xmask = 0x3;
2072 break;
2073 case XML_SCHEMAS_GYEARMONTH:
2074 xmask = 0x3;
2075 break;
2076 case XML_SCHEMAS_GMONTHDAY:
2077 xmask = 0x6;
2078 break;
2079 case XML_SCHEMAS_TIME:
2080 xmask = 0x8;
2081 break;
2082 default:
2083 xmask = 0;
2084 break;
2085 }
2086
2087 switch (y->type) {
2088 case XML_SCHEMAS_DATETIME:
2089 ymask = 0xf;
2090 break;
2091 case XML_SCHEMAS_DATE:
2092 ymask = 0x7;
2093 break;
2094 case XML_SCHEMAS_GYEAR:
2095 ymask = 0x1;
2096 break;
2097 case XML_SCHEMAS_GMONTH:
2098 ymask = 0x2;
2099 break;
2100 case XML_SCHEMAS_GDAY:
2101 ymask = 0x3;
2102 break;
2103 case XML_SCHEMAS_GYEARMONTH:
2104 ymask = 0x3;
2105 break;
2106 case XML_SCHEMAS_GMONTHDAY:
2107 ymask = 0x6;
2108 break;
2109 case XML_SCHEMAS_TIME:
2110 ymask = 0x8;
2111 break;
2112 default:
2113 ymask = 0;
2114 break;
2115 }
2116
2117 xor_mask = xmask ^ ymask; /* mark type differences */
2118 and_mask = xmask & ymask; /* mark field specification */
2119
2120 /* year */
2121 if (xor_mask & 1)
2122 return 2; /* indeterminate */
2123 else if (and_mask & 1) {
2124 if (x->value.date.year < y->value.date.year)
2125 return -1;
2126 else if (x->value.date.year > y->value.date.year)
2127 return 1;
2128 }
2129
2130 /* month */
2131 if (xor_mask & 2)
2132 return 2; /* indeterminate */
2133 else if (and_mask & 2) {
2134 if (x->value.date.mon < y->value.date.mon)
2135 return -1;
2136 else if (x->value.date.mon > y->value.date.mon)
2137 return 1;
2138 }
2139
2140 /* day */
2141 if (xor_mask & 4)
2142 return 2; /* indeterminate */
2143 else if (and_mask & 4) {
2144 if (x->value.date.day < y->value.date.day)
2145 return -1;
2146 else if (x->value.date.day > y->value.date.day)
2147 return 1;
2148 }
2149
2150 /* time */
2151 if (xor_mask & 8)
2152 return 2; /* indeterminate */
2153 else if (and_mask & 8) {
2154 if (x->value.date.hour < y->value.date.hour)
2155 return -1;
2156 else if (x->value.date.hour > y->value.date.hour)
2157 return 1;
2158 else if (x->value.date.min < y->value.date.min)
2159 return -1;
2160 else if (x->value.date.min > y->value.date.min)
2161 return 1;
2162 else if (x->value.date.sec < y->value.date.sec)
2163 return -1;
2164 else if (x->value.date.sec > y->value.date.sec)
2165 return 1;
2166 }
2167
Daniel Veillard070803b2002-05-03 07:29:38 +00002168 return 0;
2169}
2170
2171/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002172 * xmlSchemaCompareValues:
2173 * @x: a first value
2174 * @y: a second value
2175 *
2176 * Compare 2 values
2177 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002178 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2179 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002180 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00002181static int
Daniel Veillard4255d502002-04-16 15:50:10 +00002182xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2183 if ((x == NULL) || (y == NULL))
2184 return(-2);
2185
2186 switch (x->type) {
2187 case XML_SCHEMAS_STRING:
2188 TODO
2189 case XML_SCHEMAS_DECIMAL:
2190 if (y->type == XML_SCHEMAS_DECIMAL)
2191 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002192 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002193 case XML_SCHEMAS_DURATION:
2194 if (y->type == XML_SCHEMAS_DURATION)
2195 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002196 return(-2);
2197 case XML_SCHEMAS_TIME:
2198 case XML_SCHEMAS_GDAY:
2199 case XML_SCHEMAS_GMONTH:
2200 case XML_SCHEMAS_GMONTHDAY:
2201 case XML_SCHEMAS_GYEAR:
2202 case XML_SCHEMAS_GYEARMONTH:
2203 case XML_SCHEMAS_DATE:
2204 case XML_SCHEMAS_DATETIME:
2205 if ((y->type == XML_SCHEMAS_DATETIME) ||
2206 (y->type == XML_SCHEMAS_TIME) ||
2207 (y->type == XML_SCHEMAS_GDAY) ||
2208 (y->type == XML_SCHEMAS_GMONTH) ||
2209 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2210 (y->type == XML_SCHEMAS_GYEAR) ||
2211 (y->type == XML_SCHEMAS_DATE) ||
2212 (y->type == XML_SCHEMAS_GYEARMONTH))
2213 return (xmlSchemaCompareDates(x, y));
2214
2215 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002216 default:
2217 TODO
2218 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002219 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002220}
2221
2222/**
2223 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002224 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002225 * @facet: the facet to check
2226 * @value: the lexical repr of the value to validate
2227 * @val: the precomputed value
2228 *
2229 * Check a value against a facet condition
2230 *
2231 * Returns 0 if the element is schemas valid, a positive error code
2232 * number otherwise and -1 in case of internal or API error.
2233 */
2234int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002235xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002236 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002237 const xmlChar *value, xmlSchemaValPtr val)
2238{
2239 int ret;
2240
2241 switch (facet->type) {
2242 case XML_SCHEMA_FACET_PATTERN:
2243 ret = xmlRegexpExec(facet->regexp, value);
2244 if (ret == 1)
2245 return(0);
2246 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002247 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002248 return(1);
2249 }
2250 return(ret);
2251 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2252 ret = xmlSchemaCompareValues(val, facet->val);
2253 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002254 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002255 return(-1);
2256 }
2257 if (ret == -1)
2258 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002259 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002260 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002261 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2262 ret = xmlSchemaCompareValues(val, facet->val);
2263 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002264 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002265 return(-1);
2266 }
2267 if ((ret == -1) || (ret == 0))
2268 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002269 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002270 return(1);
2271 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2272 ret = xmlSchemaCompareValues(val, facet->val);
2273 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002274 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002275 return(-1);
2276 }
2277 if (ret == 1)
2278 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002279 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002280 return(1);
2281 case XML_SCHEMA_FACET_MININCLUSIVE:
2282 ret = xmlSchemaCompareValues(val, facet->val);
2283 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002284 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002285 return(-1);
2286 }
2287 if ((ret == 1) || (ret == 0))
2288 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002289 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002290 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002291 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002292 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00002293 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00002294 case XML_SCHEMA_FACET_ENUMERATION:
2295 if ((facet->value != NULL) &&
2296 (xmlStrEqual(facet->value, value)))
2297 return(0);
2298 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002299 case XML_SCHEMA_FACET_LENGTH:
2300 case XML_SCHEMA_FACET_MAXLENGTH:
2301 case XML_SCHEMA_FACET_MINLENGTH: {
2302 unsigned int len = 0;
2303
2304 if ((facet->val == NULL) ||
2305 (facet->val->type != XML_SCHEMAS_DECIMAL) ||
2306 (facet->val->value.decimal.frac != 0)) {
2307 return(-1);
2308 }
2309 switch (base->flags) {
2310 case XML_SCHEMAS_STRING:
2311 case XML_SCHEMAS_NORMSTRING:
2312 case XML_SCHEMAS_TOKEN:
2313 case XML_SCHEMAS_LANGUAGE:
2314 case XML_SCHEMAS_NMTOKEN:
2315 case XML_SCHEMAS_NAME:
2316 case XML_SCHEMAS_NCNAME:
2317 case XML_SCHEMAS_ID:
2318 case XML_SCHEMAS_IDREF: {
2319 len = xmlUTF8Strlen(value);
2320 break;
2321 }
2322 default:
2323 TODO
2324 }
2325 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
2326 if (len != facet->val->value.decimal.base)
2327 return(1);
2328 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
2329 if (len < facet->val->value.decimal.base)
2330 return(1);
2331 } else {
2332 if (len > facet->val->value.decimal.base)
2333 return(1);
2334 }
2335 break;
2336 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002337 default:
2338 TODO
2339 }
2340 return(0);
2341}
2342
2343#endif /* LIBXML_SCHEMAS_ENABLED */