blob: 254e88def0d6af2ce01a03b4dee46dc2065e907e [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;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000188static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
189static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000190static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
191static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000192
193/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000194 * xmlSchemaInitBasicType:
195 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000196 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000197 *
198 * Initialize one default type
199 */
200static xmlSchemaTypePtr
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000201xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000202 xmlSchemaTypePtr ret;
203
204 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
205 if (ret == NULL) {
206 xmlGenericError(xmlGenericErrorContext,
207 "Could not initilize type %s: out of memory\n", name);
208 return(NULL);
209 }
210 memset(ret, 0, sizeof(xmlSchemaType));
211 ret->name = xmlStrdup((const xmlChar *)name);
212 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000213 ret->flags = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000214 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
215 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
216 XML_SCHEMAS_NAMESPACE_NAME, ret);
217 return(ret);
218}
219
220/*
221 * xmlSchemaInitTypes:
222 *
223 * Initialize the default XML Schemas type library
224 */
225void
226xmlSchemaInitTypes(void) {
227 if (xmlSchemaTypesInitialized != 0)
228 return;
229 xmlSchemaTypesBank = xmlHashCreate(40);
230
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000231 /*
232 * primitive datatypes
233 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000234 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
235 XML_SCHEMAS_STRING);
236 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
237 XML_SCHEMAS_UNKNOWN);
238 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
239 XML_SCHEMAS_UNKNOWN);
240 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
241 XML_SCHEMAS_DECIMAL);
242 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
243 XML_SCHEMAS_DATE);
244 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
245 XML_SCHEMAS_DATETIME);
246 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
247 XML_SCHEMAS_TIME);
248 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
249 XML_SCHEMAS_GYEAR);
250 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
251 XML_SCHEMAS_GYEARMONTH);
252 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
253 XML_SCHEMAS_GMONTH);
254 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
255 XML_SCHEMAS_GMONTHDAY);
256 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
257 XML_SCHEMAS_GDAY);
258 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
259 XML_SCHEMAS_DURATION);
260 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
261 XML_SCHEMAS_FLOAT);
262 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
263 XML_SCHEMAS_DOUBLE);
264 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
265 XML_SCHEMAS_BOOLEAN);
266 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
267 XML_SCHEMAS_ANYURI);
Daniel Veillard4255d502002-04-16 15:50:10 +0000268
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000269 /*
270 * derived datatypes
271 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000272 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
273 XML_SCHEMAS_INTEGER);;
274 xmlSchemaTypeNonPositiveIntegerDef = xmlSchemaInitBasicType("nonPositiveInteger",
275 XML_SCHEMAS_NPINTEGER);;
276 xmlSchemaTypeNegativeIntegerDef = xmlSchemaInitBasicType("negativeInteger",
277 XML_SCHEMAS_NINTEGER);;
278 xmlSchemaTypeLongDef = xmlSchemaInitBasicType("long",
279 XML_SCHEMAS_LONG);;
280 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int",
281 XML_SCHEMAS_INT);;
282 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
283 XML_SCHEMAS_SHORT);;
284 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
285 XML_SCHEMAS_BYTE);;
286 xmlSchemaTypeNonNegativeIntegerDef = xmlSchemaInitBasicType("nonNegativeInteger",
287 XML_SCHEMAS_NNINTEGER);
288 xmlSchemaTypeUnsignedLongDef = xmlSchemaInitBasicType("unsignedLong",
289 XML_SCHEMAS_ULONG);;
290 xmlSchemaTypeUnsignedIntDef = xmlSchemaInitBasicType("unsignedInt",
291 XML_SCHEMAS_UINT);;
292 xmlSchemaTypeUnsignedShortDef = xmlSchemaInitBasicType("insignedShort",
293 XML_SCHEMAS_USHORT);;
294 xmlSchemaTypeUnsignedByteDef = xmlSchemaInitBasicType("unsignedByte",
295 XML_SCHEMAS_UBYTE);;
296 xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger",
297 XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000298
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000299 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
300 XML_SCHEMAS_NORMSTRING);
301 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
302 XML_SCHEMAS_TOKEN);
303 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
304 XML_SCHEMAS_LANGUAGE);
305 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID",
306 XML_SCHEMAS_ID);
307 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
308 XML_SCHEMAS_IDREF);
309 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
310 XML_SCHEMAS_IDREFS);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000311 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
312 XML_SCHEMAS_ENTITY);
313 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
314 XML_SCHEMAS_ENTITIES);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000315 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
316 XML_SCHEMAS_NAME);
317 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
318 XML_SCHEMAS_QNAME);
319 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
320 XML_SCHEMAS_NCNAME);
321 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
322 XML_SCHEMAS_NMTOKEN);
323 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
324 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000325 xmlSchemaTypesInitialized = 1;
326}
327
328/**
329 * xmlSchemaCleanupTypes:
330 *
331 * Cleanup the default XML Schemas type library
332 */
333void
334xmlSchemaCleanupTypes(void) {
335 if (xmlSchemaTypesInitialized == 0)
336 return;
337 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
338 xmlSchemaTypesInitialized = 0;
339}
340
341/**
342 * xmlSchemaNewValue:
343 * @type: the value type
344 *
345 * Allocate a new simple type value
346 *
347 * Returns a pointer to the new value or NULL in case of error
348 */
349static xmlSchemaValPtr
350xmlSchemaNewValue(xmlSchemaValType type) {
351 xmlSchemaValPtr value;
352
353 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
354 if (value == NULL) {
355 return(NULL);
356 }
357 memset(value, 0, sizeof(xmlSchemaVal));
358 value->type = type;
359 return(value);
360}
361
362/**
363 * xmlSchemaFreeValue:
364 * @value: the value to free
365 *
366 * Cleanup the default XML Schemas type library
367 */
368void
369xmlSchemaFreeValue(xmlSchemaValPtr value) {
370 if (value == NULL)
371 return;
372 xmlFree(value);
373}
374
375/**
376 * xmlSchemaGetPredefinedType:
377 * @name: the type name
378 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
379 *
380 * Lookup a type in the default XML Schemas type library
381 *
382 * Returns the type if found, NULL otherwise
383 */
384xmlSchemaTypePtr
385xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
386 if (xmlSchemaTypesInitialized == 0)
387 xmlSchemaInitTypes();
388 if (name == NULL)
389 return(NULL);
390 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
391}
Daniel Veillard070803b2002-05-03 07:29:38 +0000392
393/****************************************************************
394 * *
395 * Convenience macros and functions *
396 * *
397 ****************************************************************/
398
399#define IS_TZO_CHAR(c) \
400 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
401
402#define VALID_YEAR(yr) (yr != 0)
403#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
404/* VALID_DAY should only be used when month is unknown */
405#define VALID_DAY(day) ((day >= 1) && (day <= 31))
406#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
407#define VALID_MIN(min) ((min >= 0) && (min <= 59))
408#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
409#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
410#define IS_LEAP(y) \
411 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
412
413static const long daysInMonth[12] =
414 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
415static const long daysInMonthLeap[12] =
416 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
417
Daniel Veillard5a872412002-05-22 06:40:27 +0000418#define MAX_DAYINMONTH(yr,mon) \
419 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
420
Daniel Veillard070803b2002-05-03 07:29:38 +0000421#define VALID_MDAY(dt) \
422 (IS_LEAP(dt->year) ? \
423 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
424 (dt->day <= daysInMonth[dt->mon - 1]))
425
426#define VALID_DATE(dt) \
427 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
428
429#define VALID_TIME(dt) \
430 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
431 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
432
433#define VALID_DATETIME(dt) \
434 (VALID_DATE(dt) && VALID_TIME(dt))
435
436#define SECS_PER_MIN (60)
437#define SECS_PER_HOUR (60 * SECS_PER_MIN)
438#define SECS_PER_DAY (24 * SECS_PER_HOUR)
439
Daniel Veillard5a872412002-05-22 06:40:27 +0000440static const long dayInYearByMonth[12] =
441 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
442static const long dayInLeapYearByMonth[12] =
443 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
444
445#define DAY_IN_YEAR(day, month, year) \
446 ((IS_LEAP(year) ? \
447 dayInLeapYearByMonth[month - 1] : \
448 dayInYearByMonth[month - 1]) + day)
449
450#ifdef DEBUG
451#define DEBUG_DATE(dt) \
452 xmlGenericError(xmlGenericErrorContext, \
453 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
454 dt->type,dt->value.date.year,dt->value.date.mon, \
455 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
456 dt->value.date.sec); \
457 if (dt->value.date.tz_flag) \
458 if (dt->value.date.tzo != 0) \
459 xmlGenericError(xmlGenericErrorContext, \
460 "%+05d\n",dt->value.date.tzo); \
461 else \
462 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
463 else \
464 xmlGenericError(xmlGenericErrorContext,"\n")
465#else
466#define DEBUG_DATE(dt)
467#endif
468
Daniel Veillard070803b2002-05-03 07:29:38 +0000469/**
470 * _xmlSchemaParseGYear:
471 * @dt: pointer to a date structure
472 * @str: pointer to the string to analyze
473 *
474 * Parses a xs:gYear without time zone and fills in the appropriate
475 * field of the @dt structure. @str is updated to point just after the
476 * xs:gYear. It is supposed that @dt->year is big enough to contain
477 * the year.
478 *
479 * Returns 0 or the error code
480 */
481static int
482_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
483 const xmlChar *cur = *str, *firstChar;
484 int isneg = 0, digcnt = 0;
485
486 if (((*cur < '0') || (*cur > '9')) &&
487 (*cur != '-') && (*cur != '+'))
488 return -1;
489
490 if (*cur == '-') {
491 isneg = 1;
492 cur++;
493 }
494
495 firstChar = cur;
496
497 while ((*cur >= '0') && (*cur <= '9')) {
498 dt->year = dt->year * 10 + (*cur - '0');
499 cur++;
500 digcnt++;
501 }
502
503 /* year must be at least 4 digits (CCYY); over 4
504 * digits cannot have a leading zero. */
505 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
506 return 1;
507
508 if (isneg)
509 dt->year = - dt->year;
510
511 if (!VALID_YEAR(dt->year))
512 return 2;
513
514 *str = cur;
515 return 0;
516}
517
518/**
519 * PARSE_2_DIGITS:
520 * @num: the integer to fill in
521 * @cur: an #xmlChar *
522 * @invalid: an integer
523 *
524 * Parses a 2-digits integer and updates @num with the value. @cur is
525 * updated to point just after the integer.
526 * In case of error, @invalid is set to %TRUE, values of @num and
527 * @cur are undefined.
528 */
529#define PARSE_2_DIGITS(num, cur, invalid) \
530 if ((cur[0] < '0') || (cur[0] > '9') || \
531 (cur[1] < '0') || (cur[1] > '9')) \
532 invalid = 1; \
533 else \
534 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
535 cur += 2;
536
537/**
538 * PARSE_FLOAT:
539 * @num: the double to fill in
540 * @cur: an #xmlChar *
541 * @invalid: an integer
542 *
543 * Parses a float and updates @num with the value. @cur is
544 * updated to point just after the float. The float must have a
545 * 2-digits integer part and may or may not have a decimal part.
546 * In case of error, @invalid is set to %TRUE, values of @num and
547 * @cur are undefined.
548 */
549#define PARSE_FLOAT(num, cur, invalid) \
550 PARSE_2_DIGITS(num, cur, invalid); \
551 if (!invalid && (*cur == '.')) { \
552 double mult = 1; \
553 cur++; \
554 if ((*cur < '0') || (*cur > '9')) \
555 invalid = 1; \
556 while ((*cur >= '0') && (*cur <= '9')) { \
557 mult /= 10; \
558 num += (*cur - '0') * mult; \
559 cur++; \
560 } \
561 }
562
563/**
564 * _xmlSchemaParseGMonth:
565 * @dt: pointer to a date structure
566 * @str: pointer to the string to analyze
567 *
568 * Parses a xs:gMonth without time zone and fills in the appropriate
569 * field of the @dt structure. @str is updated to point just after the
570 * xs:gMonth.
571 *
572 * Returns 0 or the error code
573 */
574static int
575_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
576 const xmlChar *cur = *str;
577 int ret = 0;
578
579 PARSE_2_DIGITS(dt->mon, cur, ret);
580 if (ret != 0)
581 return ret;
582
583 if (!VALID_MONTH(dt->mon))
584 return 2;
585
586 *str = cur;
587 return 0;
588}
589
590/**
591 * _xmlSchemaParseGDay:
592 * @dt: pointer to a date structure
593 * @str: pointer to the string to analyze
594 *
595 * Parses a xs:gDay without time zone and fills in the appropriate
596 * field of the @dt structure. @str is updated to point just after the
597 * xs:gDay.
598 *
599 * Returns 0 or the error code
600 */
601static int
602_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
603 const xmlChar *cur = *str;
604 int ret = 0;
605
606 PARSE_2_DIGITS(dt->day, cur, ret);
607 if (ret != 0)
608 return ret;
609
610 if (!VALID_DAY(dt->day))
611 return 2;
612
613 *str = cur;
614 return 0;
615}
616
617/**
618 * _xmlSchemaParseTime:
619 * @dt: pointer to a date structure
620 * @str: pointer to the string to analyze
621 *
622 * Parses a xs:time without time zone and fills in the appropriate
623 * fields of the @dt structure. @str is updated to point just after the
624 * xs:time.
625 * In case of error, values of @dt fields are undefined.
626 *
627 * Returns 0 or the error code
628 */
629static int
630_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
631 const xmlChar *cur = *str;
632 unsigned int hour = 0; /* use temp var in case str is not xs:time */
633 int ret = 0;
634
635 PARSE_2_DIGITS(hour, cur, ret);
636 if (ret != 0)
637 return ret;
638
639 if (*cur != ':')
640 return 1;
641 cur++;
642
643 /* the ':' insures this string is xs:time */
644 dt->hour = hour;
645
646 PARSE_2_DIGITS(dt->min, cur, ret);
647 if (ret != 0)
648 return ret;
649
650 if (*cur != ':')
651 return 1;
652 cur++;
653
654 PARSE_FLOAT(dt->sec, cur, ret);
655 if (ret != 0)
656 return ret;
657
658 if (!VALID_TIME(dt))
659 return 2;
660
661 *str = cur;
662 return 0;
663}
664
665/**
666 * _xmlSchemaParseTimeZone:
667 * @dt: pointer to a date structure
668 * @str: pointer to the string to analyze
669 *
670 * Parses a time zone without time zone and fills in the appropriate
671 * field of the @dt structure. @str is updated to point just after the
672 * time zone.
673 *
674 * Returns 0 or the error code
675 */
676static int
677_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
678 const xmlChar *cur = *str;
679 int ret = 0;
680
681 if (str == NULL)
682 return -1;
683
684 switch (*cur) {
685 case 0:
686 dt->tz_flag = 0;
687 dt->tzo = 0;
688 break;
689
690 case 'Z':
691 dt->tz_flag = 1;
692 dt->tzo = 0;
693 cur++;
694 break;
695
696 case '+':
697 case '-': {
698 int isneg = 0, tmp = 0;
699 isneg = (*cur == '-');
700
701 cur++;
702
703 PARSE_2_DIGITS(tmp, cur, ret);
704 if (ret != 0)
705 return ret;
706 if (!VALID_HOUR(tmp))
707 return 2;
708
709 if (*cur != ':')
710 return 1;
711 cur++;
712
713 dt->tzo = tmp * 60;
714
715 PARSE_2_DIGITS(tmp, cur, ret);
716 if (ret != 0)
717 return ret;
718 if (!VALID_MIN(tmp))
719 return 2;
720
721 dt->tzo += tmp;
722 if (isneg)
723 dt->tzo = - dt->tzo;
724
725 if (!VALID_TZO(dt->tzo))
726 return 2;
727
Daniel Veillard5a872412002-05-22 06:40:27 +0000728 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000729 break;
730 }
731 default:
732 return 1;
733 }
734
735 *str = cur;
736 return 0;
737}
738
739/****************************************************************
740 * *
741 * XML Schema Dates/Times Datatypes Handling *
742 * *
743 ****************************************************************/
744
745/**
746 * PARSE_DIGITS:
747 * @num: the integer to fill in
748 * @cur: an #xmlChar *
749 * @num_type: an integer flag
750 *
751 * Parses a digits integer and updates @num with the value. @cur is
752 * updated to point just after the integer.
753 * In case of error, @num_type is set to -1, values of @num and
754 * @cur are undefined.
755 */
756#define PARSE_DIGITS(num, cur, num_type) \
757 if ((*cur < '0') || (*cur > '9')) \
758 num_type = -1; \
759 else \
760 while ((*cur >= '0') && (*cur <= '9')) { \
761 num = num * 10 + (*cur - '0'); \
762 cur++; \
763 }
764
765/**
766 * PARSE_NUM:
767 * @num: the double to fill in
768 * @cur: an #xmlChar *
769 * @num_type: an integer flag
770 *
771 * Parses a float or integer and updates @num with the value. @cur is
772 * updated to point just after the number. If the number is a float,
773 * then it must have an integer part and a decimal part; @num_type will
774 * be set to 1. If there is no decimal part, @num_type is set to zero.
775 * In case of error, @num_type is set to -1, values of @num and
776 * @cur are undefined.
777 */
778#define PARSE_NUM(num, cur, num_type) \
779 num = 0; \
780 PARSE_DIGITS(num, cur, num_type); \
781 if (!num_type && (*cur == '.')) { \
782 double mult = 1; \
783 cur++; \
784 if ((*cur < '0') || (*cur > '9')) \
785 num_type = -1; \
786 else \
787 num_type = 1; \
788 while ((*cur >= '0') && (*cur <= '9')) { \
789 mult /= 10; \
790 num += (*cur - '0') * mult; \
791 cur++; \
792 } \
793 }
794
795/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000796 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000797 * @type: the predefined type
798 * @dateTime: string to analyze
799 * @val: the return computed value
800 *
801 * Check that @dateTime conforms to the lexical space of one of the date types.
802 * if true a value is computed and returned in @val.
803 *
804 * Returns 0 if this validates, a positive error code number otherwise
805 * and -1 in case of internal or API error.
806 */
807static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000808xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000809 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000810 xmlSchemaValPtr dt;
811 int ret;
812 const xmlChar *cur = dateTime;
813
814#define RETURN_TYPE_IF_VALID(t) \
815 if (IS_TZO_CHAR(*cur)) { \
816 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
817 if (ret == 0) { \
818 if (*cur != 0) \
819 goto error; \
820 dt->type = t; \
821 if (val != NULL) \
822 *val = dt; \
823 return 0; \
824 } \
825 }
826
827 if (dateTime == NULL)
828 return -1;
829
830 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
831 return 1;
832
833 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
834 if (dt == NULL)
835 return -1;
836
837 if ((cur[0] == '-') && (cur[1] == '-')) {
838 /*
839 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
840 * xs:gDay)
841 */
842 cur += 2;
843
844 /* is it an xs:gDay? */
845 if (*cur == '-') {
846 ++cur;
847 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
848 if (ret != 0)
849 goto error;
850
851 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
852
853 goto error;
854 }
855
856 /*
857 * it should be an xs:gMonthDay or xs:gMonth
858 */
859 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
860 if (ret != 0)
861 goto error;
862
863 if (*cur != '-')
864 goto error;
865 cur++;
866
867 /* is it an xs:gMonth? */
868 if (*cur == '-') {
869 cur++;
870 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
871 goto error;
872 }
873
874 /* it should be an xs:gMonthDay */
875 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
876 if (ret != 0)
877 goto error;
878
879 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
880
881 goto error;
882 }
883
884 /*
885 * It's a right-truncated date or an xs:time.
886 * Try to parse an xs:time then fallback on right-truncated dates.
887 */
888 if ((*cur >= '0') && (*cur <= '9')) {
889 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
890 if (ret == 0) {
891 /* it's an xs:time */
892 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
893 }
894 }
895
896 /* fallback on date parsing */
897 cur = dateTime;
898
899 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
900 if (ret != 0)
901 goto error;
902
903 /* is it an xs:gYear? */
904 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
905
906 if (*cur != '-')
907 goto error;
908 cur++;
909
910 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
911 if (ret != 0)
912 goto error;
913
914 /* is it an xs:gYearMonth? */
915 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
916
917 if (*cur != '-')
918 goto error;
919 cur++;
920
921 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
922 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
923 goto error;
924
925 /* is it an xs:date? */
926 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
927
928 if (*cur != 'T')
929 goto error;
930 cur++;
931
932 /* it should be an xs:dateTime */
933 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
934 if (ret != 0)
935 goto error;
936
937 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
938 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
939 goto error;
940
941 dt->type = XML_SCHEMAS_DATETIME;
942
943 if (val != NULL)
944 *val = dt;
945
946 return 0;
947
948error:
949 if (dt != NULL)
950 xmlSchemaFreeValue(dt);
951 return 1;
952}
953
954/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000955 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000956 * @type: the predefined type
957 * @duration: string to analyze
958 * @val: the return computed value
959 *
960 * Check that @duration conforms to the lexical space of the duration type.
961 * if true a value is computed and returned in @val.
962 *
963 * Returns 0 if this validates, a positive error code number otherwise
964 * and -1 in case of internal or API error.
965 */
966static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000967xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000968 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000969 const xmlChar *cur = duration;
970 xmlSchemaValPtr dur;
971 int isneg = 0;
972 unsigned int seq = 0;
973
974 if (duration == NULL)
975 return -1;
976
977 if (*cur == '-') {
978 isneg = 1;
979 cur++;
980 }
981
982 /* duration must start with 'P' (after sign) */
983 if (*cur++ != 'P')
984 return 1;
985
986 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
987 if (dur == NULL)
988 return -1;
989
990 while (*cur != 0) {
991 double num;
992 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
993 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
994 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
995
996 /* input string should be empty or invalid date/time item */
997 if (seq >= sizeof(desig))
998 goto error;
999
1000 /* T designator must be present for time items */
1001 if (*cur == 'T') {
1002 if (seq <= 3) {
1003 seq = 3;
1004 cur++;
1005 } else
1006 return 1;
1007 } else if (seq == 3)
1008 goto error;
1009
1010 /* parse the number portion of the item */
1011 PARSE_NUM(num, cur, num_type);
1012
1013 if ((num_type == -1) || (*cur == 0))
1014 goto error;
1015
1016 /* update duration based on item type */
1017 while (seq < sizeof(desig)) {
1018 if (*cur == desig[seq]) {
1019
1020 /* verify numeric type; only seconds can be float */
1021 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1022 goto error;
1023
1024 switch (seq) {
1025 case 0:
1026 dur->value.dur.mon = (long)num * 12;
1027 break;
1028 case 1:
1029 dur->value.dur.mon += (long)num;
1030 break;
1031 default:
1032 /* convert to seconds using multiplier */
1033 dur->value.dur.sec += num * multi[seq];
1034 seq++;
1035 break;
1036 }
1037
1038 break; /* exit loop */
1039 }
1040 /* no date designators found? */
1041 if (++seq == 3)
1042 goto error;
1043 }
1044 cur++;
1045 }
1046
1047 if (isneg) {
1048 dur->value.dur.mon = -dur->value.dur.mon;
1049 dur->value.dur.day = -dur->value.dur.day;
1050 dur->value.dur.sec = -dur->value.dur.sec;
1051 }
1052
1053 if (val != NULL)
1054 *val = dur;
1055
1056 return 0;
1057
1058error:
1059 if (dur != NULL)
1060 xmlSchemaFreeValue(dur);
1061 return 1;
1062}
1063
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001064/**
1065 * xmlSchemaStrip:
1066 * @value: a value
1067 *
1068 * Removes the leading and ending spaces of a string
1069 *
1070 * Returns the new string or NULL if no change was required.
1071 */
1072static xmlChar *
1073xmlSchemaStrip(const xmlChar *value) {
1074 const xmlChar *start = value, *end, *f;
1075
1076 if (value == NULL) return(NULL);
1077 while ((*start != 0) && (IS_BLANK(*start))) start++;
1078 end = start;
1079 while (*end != 0) end++;
1080 f = end;
1081 end--;
1082 while ((end > start) && (IS_BLANK(*end))) end--;
1083 end++;
1084 if ((start == value) && (f == end)) return(NULL);
1085 return(xmlStrndup(start, end - start));
1086}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001087
1088/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001089 * xmlSchemaValAtomicListNode:
1090 * @type: the predefined atomic type for a token in the list
1091 * @value: the list value to check
1092 * @ret: the return computed value
1093 * @node: the node containing the value
1094 *
1095 * Check that a value conforms to the lexical space of the predefined
1096 * list type. if true a value is computed and returned in @ret.
1097 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001098 * Returns the number of items if this validates, a negative error code
1099 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001100 */
1101static int
1102xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1103 xmlSchemaValPtr *ret, xmlNodePtr node) {
1104 xmlChar *val, *cur, *endval;
1105 int nb_values = 0;
1106 int tmp;
1107
1108 if (value == NULL) {
1109 return(-1);
1110 }
1111 val = xmlStrdup(value);
1112 if (val == NULL) {
1113 return(-1);
1114 }
1115 cur = val;
1116 /*
1117 * Split the list
1118 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001119 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001120 while (*cur != 0) {
1121 if (IS_BLANK(*cur)) {
1122 *cur = 0;
1123 cur++;
1124 while (IS_BLANK(*cur)) *cur++ = 0;
1125 } else {
1126 nb_values++;
1127 cur++;
1128 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1129 }
1130 }
1131 if (nb_values == 0) {
1132 if (ret != NULL) {
1133 TODO
1134 }
1135 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001136 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001137 }
1138 endval = cur;
1139 cur = val;
1140 while ((*cur == 0) && (cur != endval)) cur++;
1141 while (cur != endval) {
1142 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1143 if (tmp != 0)
1144 break;
1145 while (*cur != 0) cur++;
1146 while ((*cur == 0) && (cur != endval)) cur++;
1147 }
1148 xmlFree(val);
1149 if (ret != NULL) {
1150 TODO
1151 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001152 if (tmp == 0)
1153 return(nb_values);
1154 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001155}
1156
1157/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001158 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00001159 * @type: the predefined type
1160 * @value: the value to check
1161 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001162 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00001163 *
1164 * Check that a value conforms to the lexical space of the predefined type.
1165 * if true a value is computed and returned in @val.
1166 *
1167 * Returns 0 if this validates, a positive error code number otherwise
1168 * and -1 in case of internal or API error.
1169 */
1170int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001171xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
1172 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001173 xmlSchemaValPtr v;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001174 int ret;
Daniel Veillard4255d502002-04-16 15:50:10 +00001175
1176 if (xmlSchemaTypesInitialized == 0)
1177 return(-1);
1178 if (type == NULL)
1179 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001180
Daniel Veillard4255d502002-04-16 15:50:10 +00001181 if (val != NULL)
1182 *val = NULL;
1183 if (type == xmlSchemaTypeStringDef) {
1184 return(0);
1185 } else if (type == xmlSchemaTypeAnyTypeDef) {
1186 return(0);
1187 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
1188 return(0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001189 } else if (type == xmlSchemaTypeNmtokenDef) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001190 if (xmlValidateNMToken(value, 1) == 0)
Daniel Veillard4255d502002-04-16 15:50:10 +00001191 return(0);
1192 return(1);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001193 } else if (type == xmlSchemaTypeNmtokensDef) {
1194 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1195 value, val, node);
1196 if (ret >= 0)
1197 ret = 0;
1198 else
1199 ret = 1;
1200 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001201 } else if (type == xmlSchemaTypeDecimalDef) {
1202 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001203 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001204 unsigned long base = 0;
1205 if (cur == NULL)
1206 return(1);
1207 if (*cur == '+')
1208 cur++;
1209 else if (*cur == '-') {
1210 neg = 1;
1211 cur++;
1212 }
1213 tmp = cur;
1214 while ((*cur >= '0') && (*cur <= '9')) {
1215 base = base * 10 + (*cur - '0');
1216 cur++;
1217 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001218 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001219 if (*cur == '.') {
1220 cur++;
1221 tmp = cur;
1222 while ((*cur >= '0') && (*cur <= '9')) {
1223 base = base * 10 + (*cur - '0');
1224 cur++;
1225 }
1226 frac = cur - tmp;
1227 }
1228 if (*cur != 0)
1229 return(1);
1230 if (val != NULL) {
1231 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1232 if (v != NULL) {
1233 v->value.decimal.base = base;
1234 v->value.decimal.sign = neg;
1235 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001236 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001237 *val = v;
1238 }
1239 }
1240 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001241 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001242 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001243 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1244 (type == xmlSchemaTypeTimeDef) ||
1245 (type == xmlSchemaTypeDateDef) ||
1246 (type == xmlSchemaTypeGYearDef) ||
1247 (type == xmlSchemaTypeGYearMonthDef) ||
1248 (type == xmlSchemaTypeGMonthDef) ||
1249 (type == xmlSchemaTypeGMonthDayDef) ||
1250 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001251 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001252 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1253 const xmlChar *cur = value;
1254 unsigned long base = 0;
1255 int total = 0;
1256 if (cur == NULL)
1257 return(1);
1258 if (*cur == '+')
1259 cur++;
1260 while ((*cur >= '0') && (*cur <= '9')) {
1261 base = base * 10 + (*cur - '0');
1262 total++;
1263 cur++;
1264 }
1265 if (*cur != 0)
1266 return(1);
1267 if (val != NULL) {
1268 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1269 if (v != NULL) {
1270 v->value.decimal.base = base;
1271 v->value.decimal.sign = 0;
1272 v->value.decimal.frac = 0;
1273 v->value.decimal.total = total;
1274 *val = v;
1275 }
1276 }
1277 return(0);
1278 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1279 const xmlChar *cur = value;
1280 unsigned long base = 0;
1281 int total = 0;
1282 int sign = 0;
1283 if (cur == NULL)
1284 return(1);
1285 if (*cur == '-') {
1286 sign = 1;
1287 cur++;
1288 } else if (*cur == '+')
1289 cur++;
1290 while ((*cur >= '0') && (*cur <= '9')) {
1291 base = base * 10 + (*cur - '0');
1292 total++;
1293 cur++;
1294 }
1295 if (*cur != 0)
1296 return(1);
1297 if ((sign == 1) && (base != 0))
1298 return(1);
1299 if (val != NULL) {
1300 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1301 if (v != NULL) {
1302 v->value.decimal.base = base;
1303 v->value.decimal.sign = 0;
1304 v->value.decimal.frac = 0;
1305 v->value.decimal.total = total;
1306 *val = v;
1307 }
1308 }
1309 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001310 } else if (type == xmlSchemaTypeIntDef) {
1311 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001312 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001313 int total = 0;
1314 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001315 if (cur == NULL)
1316 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001317 if (*cur == '-') {
1318 sign = 1;
1319 cur++;
1320 } else if (*cur == '+')
1321 cur++;
1322 while (*cur == '0') {
1323 total++;
1324 cur++;
1325 }
1326 while ((*cur >= '0') && (*cur <= '9')) {
1327 base = base * 10 + (*cur - '0');
1328 total++;
1329 cur++;
1330 }
1331 if (*cur != 0)
1332 return(1);
1333 if ((sign == 1) && (total == 0))
1334 return(1);
1335 if (val != NULL) {
1336 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1337 if (v != NULL) {
1338 v->value.decimal.base = base;
1339 v->value.decimal.sign = sign;
1340 v->value.decimal.frac = 0;
1341 v->value.decimal.total = total;
1342 *val = v;
1343 }
1344 }
1345 return(0);
1346 } else if ((type == xmlSchemaTypeFloatDef) ||
1347 (type == xmlSchemaTypeDoubleDef)) {
1348 const xmlChar *cur = value;
1349 int neg = 0;
1350 if (cur == NULL)
1351 return(1);
1352 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1353 cur += 3;
1354 if (*cur != 0)
1355 return(1);
1356 if (val != NULL) {
1357 if (type == xmlSchemaTypeFloatDef) {
1358 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1359 if (v != NULL) {
1360 v->value.f = (float) xmlXPathNAN;
1361 } else {
1362 xmlSchemaFreeValue(v);
1363 return(-1);
1364 }
1365 } else {
1366 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1367 if (v != NULL) {
1368 v->value.d = xmlXPathNAN;
1369 } else {
1370 xmlSchemaFreeValue(v);
1371 return(-1);
1372 }
1373 }
1374 *val = v;
1375 }
1376 return(0);
1377 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001378 if (*cur == '+')
1379 cur++;
1380 else if (*cur == '-') {
1381 neg = 1;
1382 cur++;
1383 }
Daniel Veillardd4310742003-02-18 21:12:46 +00001384 if (cur[0] == 0)
1385 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001386 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1387 cur += 3;
1388 if (*cur != 0)
1389 return(1);
1390 if (val != NULL) {
1391 if (type == xmlSchemaTypeFloatDef) {
1392 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1393 if (v != NULL) {
1394 if (neg)
1395 v->value.f = (float) xmlXPathNINF;
1396 else
1397 v->value.f = (float) xmlXPathPINF;
1398 } else {
1399 xmlSchemaFreeValue(v);
1400 return(-1);
1401 }
1402 } else {
1403 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1404 if (v != NULL) {
1405 if (neg)
1406 v->value.d = xmlXPathNINF;
1407 else
1408 v->value.d = xmlXPathPINF;
1409 } else {
1410 xmlSchemaFreeValue(v);
1411 return(-1);
1412 }
1413 }
1414 *val = v;
1415 }
1416 return(0);
1417 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001418 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001419 cur++;
1420 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001421 if (*cur == '.') {
1422 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001423 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001424 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001425 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001426 if ((*cur == 'e') || (*cur == 'E')) {
1427 cur++;
1428 if (*cur == '-')
1429 cur++;
1430 while ((*cur >= '0') && (*cur <= '9'))
1431 cur++;
1432 }
1433 if (*cur != 0)
1434 return(1);
1435 if (val != NULL) {
1436 if (type == xmlSchemaTypeFloatDef) {
1437 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1438 if (v != NULL) {
1439 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1440 *val = v;
1441 } else {
1442 xmlGenericError(xmlGenericErrorContext,
1443 "failed to scanf float %s\n", value);
1444 xmlSchemaFreeValue(v);
1445 return(1);
1446 }
1447 } else {
1448 return(-1);
1449 }
1450 } else {
1451 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1452 if (v != NULL) {
1453 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1454 *val = v;
1455 } else {
1456 xmlGenericError(xmlGenericErrorContext,
1457 "failed to scanf double %s\n", value);
1458 xmlSchemaFreeValue(v);
1459 return(1);
1460 }
1461 } else {
1462 return(-1);
1463 }
1464 }
1465 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001466 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001467 } else if (type == xmlSchemaTypeNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001468 ret = xmlValidateName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001469 if ((ret == 0) && (val != NULL)) {
1470 TODO;
1471 }
1472 return(ret);
1473 } else if (type == xmlSchemaTypeQNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001474 ret = xmlValidateQName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001475 if ((ret == 0) && (val != NULL)) {
1476 TODO;
1477 }
1478 return(ret);
1479 } else if (type == xmlSchemaTypeNCNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001480 ret = xmlValidateNCName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001481 if ((ret == 0) && (val != NULL)) {
1482 TODO;
1483 }
1484 return(ret);
1485 } else if (type == xmlSchemaTypeAnyURIDef) {
1486 xmlURIPtr uri;
1487
1488 uri = xmlParseURI((const char *) value);
1489 if (uri == NULL)
1490 return(1);
1491 if (val != NULL) {
1492 TODO;
1493 }
1494 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001495 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001496 } else if (type == xmlSchemaTypeBooleanDef) {
1497 const xmlChar *cur = value;
1498
1499 if ((cur[0] == '0') && (cur[1] == 0))
1500 ret = 0;
1501 else if ((cur[0] == '1') && (cur[1] == 0))
1502 ret = 1;
1503 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1504 (cur[3] == 'e') && (cur[4] == 0))
1505 ret = 1;
1506 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1507 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1508 ret = 0;
1509 else
1510 return(1);
1511 if (val != NULL) {
1512 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1513 if (v != NULL) {
1514 v->value.b = ret;
1515 *val = v;
1516 } else {
1517 return(-1);
1518 }
1519 }
1520 return(0);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001521 } else if (type == xmlSchemaTypeIdrefDef) {
1522 ret = xmlValidateNCName(value, 1);
1523 if ((ret == 0) && (val != NULL)) {
1524 TODO;
1525 }
1526 if ((ret == 0) && (node != NULL) &&
1527 (node->type == XML_ATTRIBUTE_NODE)) {
1528 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001529 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001530
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001531 strip = xmlSchemaStrip(value);
1532 if (strip != NULL) {
1533 xmlAddRef(NULL, node->doc, strip, attr);
1534 xmlFree(strip);
1535 } else
1536 xmlAddRef(NULL, node->doc, value, attr);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001537 attr->atype = XML_ATTRIBUTE_IDREF;
1538 }
1539 return(ret);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001540 } else if (type == xmlSchemaTypeIdrefsDef) {
1541 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1542 value, val, node);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001543 if (ret < 0)
1544 ret = 2;
1545 else
1546 ret = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001547 if ((ret == 0) && (node != NULL) &&
1548 (node->type == XML_ATTRIBUTE_NODE)) {
1549 xmlAttrPtr attr = (xmlAttrPtr) node;
1550
1551 attr->atype = XML_ATTRIBUTE_IDREFS;
1552 }
1553 return(ret);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001554 } else if (type == xmlSchemaTypeIdDef) {
1555 ret = xmlValidateNCName(value, 1);
1556 if ((ret == 0) && (val != NULL)) {
1557 TODO;
1558 }
1559 if ((ret == 0) && (node != NULL) &&
1560 (node->type == XML_ATTRIBUTE_NODE)) {
1561 xmlAttrPtr attr = (xmlAttrPtr) node;
1562 xmlIDPtr res;
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001563 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001564
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001565 strip = xmlSchemaStrip(value);
1566 if (strip != NULL) {
1567 res = xmlAddID(NULL, node->doc, strip, attr);
1568 xmlFree(strip);
1569 } else
1570 res = xmlAddID(NULL, node->doc, value, attr);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001571 if (res == NULL) {
1572 ret = 2;
1573 } else {
1574 attr->atype = XML_ATTRIBUTE_ID;
1575 }
1576 }
1577 return(ret);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001578 } else if (type == xmlSchemaTypeEntitiesDef) {
1579 if ((node == NULL) || (node->doc == NULL))
1580 return(3);
1581 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1582 value, val, node);
1583 if (ret <= 0)
1584 ret = 1;
1585 else
1586 ret = 0;
1587 if ((ret == 0) && (node != NULL) &&
1588 (node->type == XML_ATTRIBUTE_NODE)) {
1589 xmlAttrPtr attr = (xmlAttrPtr) node;
1590
1591 attr->atype = XML_ATTRIBUTE_ENTITIES;
1592 }
1593 return(ret);
1594 } else if (type == xmlSchemaTypeEntityDef) {
1595 xmlChar *strip;
1596 ret = xmlValidateNCName(value, 1);
1597 if ((node == NULL) || (node->doc == NULL))
1598 ret = 3;
1599 if (ret == 0) {
1600 xmlEntityPtr ent;
1601
1602 strip = xmlSchemaStrip(value);
1603 if (strip != NULL) {
1604 ent = xmlGetDocEntity(node->doc, strip);
1605 xmlFree(strip);
1606 } else {
1607 ent = xmlGetDocEntity(node->doc, value);
1608 }
1609 if ((ent == NULL) ||
1610 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1611 ret = 4;
1612 }
1613 if ((ret == 0) && (val != NULL)) {
1614 TODO;
1615 }
1616 if ((ret == 0) && (node != NULL) &&
1617 (node->type == XML_ATTRIBUTE_NODE)) {
1618 xmlAttrPtr attr = (xmlAttrPtr) node;
1619
1620 attr->atype = XML_ATTRIBUTE_ENTITY;
1621 }
1622 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001623 } else {
1624 TODO
1625 return(0);
1626 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001627 return(-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001628}
1629
1630/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001631 * xmlSchemaValidatePredefinedType:
1632 * @type: the predefined type
1633 * @value: the value to check
1634 * @val: the return computed value
1635 *
1636 * Check that a value conforms to the lexical space of the predefined type.
1637 * if true a value is computed and returned in @val.
1638 *
1639 * Returns 0 if this validates, a positive error code number otherwise
1640 * and -1 in case of internal or API error.
1641 */
1642int
1643xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1644 xmlSchemaValPtr *val) {
1645 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
1646}
1647
1648/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001649 * xmlSchemaCompareDecimals:
1650 * @x: a first decimal value
1651 * @y: a second decimal value
1652 *
1653 * Compare 2 decimals
1654 *
1655 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1656 */
1657static int
1658xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1659{
1660 xmlSchemaValPtr swp;
1661 int order = 1;
1662 unsigned long tmp;
1663
1664 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1665 order = -1;
1666 else if (x->value.decimal.sign)
1667 return (-1);
1668 else if (y->value.decimal.sign)
1669 return (1);
1670 if (x->value.decimal.frac == y->value.decimal.frac) {
1671 if (x->value.decimal.base < y->value.decimal.base)
1672 return (-1);
1673 return (x->value.decimal.base > y->value.decimal.base);
1674 }
1675 if (y->value.decimal.frac > x->value.decimal.frac) {
1676 swp = y;
1677 y = x;
1678 x = swp;
1679 order = -order;
1680 }
1681 tmp =
1682 x->value.decimal.base / powten[x->value.decimal.frac -
1683 y->value.decimal.frac];
1684 if (tmp > y->value.decimal.base)
1685 return (order);
1686 if (tmp < y->value.decimal.base)
1687 return (-order);
1688 tmp =
1689 y->value.decimal.base * powten[x->value.decimal.frac -
1690 y->value.decimal.frac];
1691 if (x->value.decimal.base < tmp)
1692 return (-order);
1693 if (x->value.decimal.base == tmp)
1694 return (0);
1695 return (order);
1696}
1697
1698/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001699 * xmlSchemaCompareDurations:
1700 * @x: a first duration value
1701 * @y: a second duration value
1702 *
1703 * Compare 2 durations
1704 *
1705 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1706 * case of error
1707 */
1708static int
1709xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1710{
1711 long carry, mon, day;
1712 double sec;
1713 long xmon, xday, myear, lyear, minday, maxday;
1714 static const long dayRange [2][12] = {
1715 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1716 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1717
1718 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001719 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001720
1721 /* months */
1722 mon = x->value.dur.mon - y->value.dur.mon;
1723
1724 /* seconds */
1725 sec = x->value.dur.sec - y->value.dur.sec;
1726 carry = (long)sec / SECS_PER_DAY;
1727 sec -= (double)(carry * SECS_PER_DAY);
1728
1729 /* days */
1730 day = x->value.dur.day - y->value.dur.day + carry;
1731
1732 /* easy test */
1733 if (mon == 0) {
1734 if (day == 0)
1735 if (sec == 0.0)
1736 return 0;
1737 else if (sec < 0.0)
1738 return -1;
1739 else
1740 return 1;
1741 else if (day < 0)
1742 return -1;
1743 else
1744 return 1;
1745 }
1746
1747 if (mon > 0) {
1748 if ((day >= 0) && (sec >= 0.0))
1749 return 1;
1750 else {
1751 xmon = mon;
1752 xday = -day;
1753 }
1754 } else if ((day <= 0) && (sec <= 0.0)) {
1755 return -1;
1756 } else {
1757 xmon = -mon;
1758 xday = day;
1759 }
1760
1761 myear = xmon / 12;
1762 lyear = myear / 4;
1763 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1764 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1765
1766 xmon = xmon % 12;
1767 minday += dayRange[0][xmon];
1768 maxday += dayRange[1][xmon];
1769
1770 if (maxday < xday)
1771 return 1;
1772 else if (minday > xday)
1773 return -1;
1774
1775 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001776 return 2;
1777}
1778
1779/*
1780 * macros for adding date/times and durations
1781 */
1782#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1783#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1784#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1785#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1786
1787/**
1788 * _xmlSchemaDateAdd:
1789 * @dt: an #xmlSchemaValPtr
1790 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1791 *
1792 * Compute a new date/time from @dt and @dur. This function assumes @dt
1793 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1794 * or #XML_SCHEMAS_GYEAR.
1795 *
1796 * Returns date/time pointer or NULL.
1797 */
1798static xmlSchemaValPtr
1799_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1800{
1801 xmlSchemaValPtr ret;
1802 long carry, tempdays, temp;
1803 xmlSchemaValDatePtr r, d;
1804 xmlSchemaValDurationPtr u;
1805
1806 if ((dt == NULL) || (dur == NULL))
1807 return NULL;
1808
1809 ret = xmlSchemaNewValue(dt->type);
1810 if (ret == NULL)
1811 return NULL;
1812
1813 r = &(ret->value.date);
1814 d = &(dt->value.date);
1815 u = &(dur->value.dur);
1816
1817 /* normalization */
1818 if (d->mon == 0)
1819 d->mon = 1;
1820
1821 /* normalize for time zone offset */
1822 u->sec -= (d->tzo * 60);
1823 d->tzo = 0;
1824
1825 /* normalization */
1826 if (d->day == 0)
1827 d->day = 1;
1828
1829 /* month */
1830 carry = d->mon + u->mon;
1831 r->mon = MODULO_RANGE(carry, 1, 13);
1832 carry = FQUOTIENT_RANGE(carry, 1, 13);
1833
1834 /* year (may be modified later) */
1835 r->year = d->year + carry;
1836 if (r->year == 0) {
1837 if (d->year > 0)
1838 r->year--;
1839 else
1840 r->year++;
1841 }
1842
1843 /* time zone */
1844 r->tzo = d->tzo;
1845 r->tz_flag = d->tz_flag;
1846
1847 /* seconds */
1848 r->sec = d->sec + u->sec;
1849 carry = FQUOTIENT((long)r->sec, 60);
1850 if (r->sec != 0.0) {
1851 r->sec = MODULO(r->sec, 60.0);
1852 }
1853
1854 /* minute */
1855 carry += d->min;
1856 r->min = MODULO(carry, 60);
1857 carry = FQUOTIENT(carry, 60);
1858
1859 /* hours */
1860 carry += d->hour;
1861 r->hour = MODULO(carry, 24);
1862 carry = FQUOTIENT(carry, 24);
1863
1864 /*
1865 * days
1866 * Note we use tempdays because the temporary values may need more
1867 * than 5 bits
1868 */
1869 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1870 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1871 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1872 else if (d->day < 1)
1873 tempdays = 1;
1874 else
1875 tempdays = d->day;
1876
1877 tempdays += u->day + carry;
1878
1879 while (1) {
1880 if (tempdays < 1) {
1881 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1882 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1883 if (tyr == 0)
1884 tyr--;
1885 tempdays += MAX_DAYINMONTH(tyr, tmon);
1886 carry = -1;
1887 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1888 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1889 carry = 1;
1890 } else
1891 break;
1892
1893 temp = r->mon + carry;
1894 r->mon = MODULO_RANGE(temp, 1, 13);
1895 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1896 if (r->year == 0) {
1897 if (temp < 1)
1898 r->year--;
1899 else
1900 r->year++;
1901 }
1902 }
1903
1904 r->day = tempdays;
1905
1906 /*
1907 * adjust the date/time type to the date values
1908 */
1909 if (ret->type != XML_SCHEMAS_DATETIME) {
1910 if ((r->hour) || (r->min) || (r->sec))
1911 ret->type = XML_SCHEMAS_DATETIME;
1912 else if (ret->type != XML_SCHEMAS_DATE) {
1913 if ((r->mon != 1) && (r->day != 1))
1914 ret->type = XML_SCHEMAS_DATE;
1915 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1916 ret->type = XML_SCHEMAS_GYEARMONTH;
1917 }
1918 }
1919
1920 return ret;
1921}
1922
1923/**
1924 * xmlSchemaDupVal:
1925 * @v: value to duplicate
1926 *
1927 * returns a duplicated value.
1928 */
1929static xmlSchemaValPtr
1930xmlSchemaDupVal (xmlSchemaValPtr v)
1931{
1932 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1933 if (ret == NULL)
1934 return ret;
1935
1936 memcpy(ret, v, sizeof(xmlSchemaVal));
1937 return ret;
1938}
1939
1940/**
1941 * xmlSchemaDateNormalize:
1942 * @dt: an #xmlSchemaValPtr
1943 *
1944 * Normalize @dt to GMT time.
1945 *
1946 */
1947static xmlSchemaValPtr
1948xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1949{
1950 xmlSchemaValPtr dur, ret;
1951
1952 if (dt == NULL)
1953 return NULL;
1954
1955 if (((dt->type != XML_SCHEMAS_TIME) &&
1956 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1957 return xmlSchemaDupVal(dt);
1958
1959 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1960 if (dur == NULL)
1961 return NULL;
1962
1963 dur->value.date.sec -= offset;
1964
1965 ret = _xmlSchemaDateAdd(dt, dur);
1966 if (ret == NULL)
1967 return NULL;
1968
1969 xmlSchemaFreeValue(dur);
1970
1971 /* ret->value.date.tzo = 0; */
1972 return ret;
1973}
1974
1975/**
1976 * _xmlSchemaDateCastYMToDays:
1977 * @dt: an #xmlSchemaValPtr
1978 *
1979 * Convert mon and year of @dt to total number of days. Take the
1980 * number of years since (or before) 1 AD and add the number of leap
1981 * years. This is a function because negative
1982 * years must be handled a little differently and there is no zero year.
1983 *
1984 * Returns number of days.
1985 */
1986static long
1987_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
1988{
1989 long ret;
1990
1991 if (dt->value.date.year < 0)
1992 ret = (dt->value.date.year * 365) +
1993 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1994 ((dt->value.date.year+1)/400)) +
1995 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1996 else
1997 ret = ((dt->value.date.year-1) * 365) +
1998 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1999 ((dt->value.date.year-1)/400)) +
2000 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2001
2002 return ret;
2003}
2004
2005/**
2006 * TIME_TO_NUMBER:
2007 * @dt: an #xmlSchemaValPtr
2008 *
2009 * Calculates the number of seconds in the time portion of @dt.
2010 *
2011 * Returns seconds.
2012 */
2013#define TIME_TO_NUMBER(dt) \
2014 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
2015 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
2016
2017/**
2018 * xmlSchemaCompareDates:
2019 * @x: a first date/time value
2020 * @y: a second date/time value
2021 *
2022 * Compare 2 date/times
2023 *
2024 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2025 * case of error
2026 */
2027static int
2028xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2029{
2030 unsigned char xmask, ymask, xor_mask, and_mask;
2031 xmlSchemaValPtr p1, p2, q1, q2;
2032 long p1d, p2d, q1d, q2d;
2033
2034 if ((x == NULL) || (y == NULL))
2035 return -2;
2036
2037 if (x->value.date.tz_flag) {
2038
2039 if (!y->value.date.tz_flag) {
2040 p1 = xmlSchemaDateNormalize(x, 0);
2041 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2042 /* normalize y + 14:00 */
2043 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2044
2045 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002046 if (p1d < q1d) {
2047 xmlSchemaFreeValue(p1);
2048 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002049 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002050 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002051 double sec;
2052
2053 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002054 if (sec < 0.0) {
2055 xmlSchemaFreeValue(p1);
2056 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002057 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002058 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002059 /* normalize y - 14:00 */
2060 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2061 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002062 xmlSchemaFreeValue(p1);
2063 xmlSchemaFreeValue(q1);
2064 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002065 if (p1d > q2d)
2066 return 1;
2067 else if (p1d == q2d) {
2068 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2069 if (sec > 0.0)
2070 return 1;
2071 else
2072 return 2; /* indeterminate */
2073 }
2074 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002075 } else {
2076 xmlSchemaFreeValue(p1);
2077 xmlSchemaFreeValue(q1);
2078 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002079 }
2080 } else if (y->value.date.tz_flag) {
2081 q1 = xmlSchemaDateNormalize(y, 0);
2082 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2083
2084 /* normalize x - 14:00 */
2085 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2086 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2087
Daniel Veillardfdc91562002-07-01 21:52:03 +00002088 if (p1d < q1d) {
2089 xmlSchemaFreeValue(p1);
2090 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002091 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002092 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002093 double sec;
2094
2095 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002096 if (sec < 0.0) {
2097 xmlSchemaFreeValue(p1);
2098 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002099 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002100 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002101 /* normalize x + 14:00 */
2102 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2103 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2104
Daniel Veillardfdc91562002-07-01 21:52:03 +00002105 xmlSchemaFreeValue(p1);
2106 xmlSchemaFreeValue(q1);
2107 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002108 if (p2d > q1d)
2109 return 1;
2110 else if (p2d == q1d) {
2111 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
2112 if (sec > 0.0)
2113 return 1;
2114 else
2115 return 2; /* indeterminate */
2116 }
2117 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002118 } else {
2119 xmlSchemaFreeValue(p1);
2120 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002121 }
2122 }
2123
2124 /*
2125 * if the same type then calculate the difference
2126 */
2127 if (x->type == y->type) {
2128 q1 = xmlSchemaDateNormalize(y, 0);
2129 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2130
2131 p1 = xmlSchemaDateNormalize(x, 0);
2132 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2133
Daniel Veillardfdc91562002-07-01 21:52:03 +00002134 if (p1d < q1d) {
2135 xmlSchemaFreeValue(p1);
2136 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002137 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002138 } else if (p1d > q1d) {
2139 xmlSchemaFreeValue(p1);
2140 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002141 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002142 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002143 double sec;
2144
2145 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002146 xmlSchemaFreeValue(p1);
2147 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002148 if (sec < 0.0)
2149 return -1;
2150 else if (sec > 0.0)
2151 return 1;
2152
2153 }
2154 return 0;
2155 }
2156
2157 switch (x->type) {
2158 case XML_SCHEMAS_DATETIME:
2159 xmask = 0xf;
2160 break;
2161 case XML_SCHEMAS_DATE:
2162 xmask = 0x7;
2163 break;
2164 case XML_SCHEMAS_GYEAR:
2165 xmask = 0x1;
2166 break;
2167 case XML_SCHEMAS_GMONTH:
2168 xmask = 0x2;
2169 break;
2170 case XML_SCHEMAS_GDAY:
2171 xmask = 0x3;
2172 break;
2173 case XML_SCHEMAS_GYEARMONTH:
2174 xmask = 0x3;
2175 break;
2176 case XML_SCHEMAS_GMONTHDAY:
2177 xmask = 0x6;
2178 break;
2179 case XML_SCHEMAS_TIME:
2180 xmask = 0x8;
2181 break;
2182 default:
2183 xmask = 0;
2184 break;
2185 }
2186
2187 switch (y->type) {
2188 case XML_SCHEMAS_DATETIME:
2189 ymask = 0xf;
2190 break;
2191 case XML_SCHEMAS_DATE:
2192 ymask = 0x7;
2193 break;
2194 case XML_SCHEMAS_GYEAR:
2195 ymask = 0x1;
2196 break;
2197 case XML_SCHEMAS_GMONTH:
2198 ymask = 0x2;
2199 break;
2200 case XML_SCHEMAS_GDAY:
2201 ymask = 0x3;
2202 break;
2203 case XML_SCHEMAS_GYEARMONTH:
2204 ymask = 0x3;
2205 break;
2206 case XML_SCHEMAS_GMONTHDAY:
2207 ymask = 0x6;
2208 break;
2209 case XML_SCHEMAS_TIME:
2210 ymask = 0x8;
2211 break;
2212 default:
2213 ymask = 0;
2214 break;
2215 }
2216
2217 xor_mask = xmask ^ ymask; /* mark type differences */
2218 and_mask = xmask & ymask; /* mark field specification */
2219
2220 /* year */
2221 if (xor_mask & 1)
2222 return 2; /* indeterminate */
2223 else if (and_mask & 1) {
2224 if (x->value.date.year < y->value.date.year)
2225 return -1;
2226 else if (x->value.date.year > y->value.date.year)
2227 return 1;
2228 }
2229
2230 /* month */
2231 if (xor_mask & 2)
2232 return 2; /* indeterminate */
2233 else if (and_mask & 2) {
2234 if (x->value.date.mon < y->value.date.mon)
2235 return -1;
2236 else if (x->value.date.mon > y->value.date.mon)
2237 return 1;
2238 }
2239
2240 /* day */
2241 if (xor_mask & 4)
2242 return 2; /* indeterminate */
2243 else if (and_mask & 4) {
2244 if (x->value.date.day < y->value.date.day)
2245 return -1;
2246 else if (x->value.date.day > y->value.date.day)
2247 return 1;
2248 }
2249
2250 /* time */
2251 if (xor_mask & 8)
2252 return 2; /* indeterminate */
2253 else if (and_mask & 8) {
2254 if (x->value.date.hour < y->value.date.hour)
2255 return -1;
2256 else if (x->value.date.hour > y->value.date.hour)
2257 return 1;
2258 else if (x->value.date.min < y->value.date.min)
2259 return -1;
2260 else if (x->value.date.min > y->value.date.min)
2261 return 1;
2262 else if (x->value.date.sec < y->value.date.sec)
2263 return -1;
2264 else if (x->value.date.sec > y->value.date.sec)
2265 return 1;
2266 }
2267
Daniel Veillard070803b2002-05-03 07:29:38 +00002268 return 0;
2269}
2270
2271/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002272 * xmlSchemaCompareValues:
2273 * @x: a first value
2274 * @y: a second value
2275 *
2276 * Compare 2 values
2277 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002278 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2279 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002280 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00002281static int
Daniel Veillard4255d502002-04-16 15:50:10 +00002282xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2283 if ((x == NULL) || (y == NULL))
2284 return(-2);
2285
2286 switch (x->type) {
2287 case XML_SCHEMAS_STRING:
2288 TODO
2289 case XML_SCHEMAS_DECIMAL:
2290 if (y->type == XML_SCHEMAS_DECIMAL)
2291 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002292 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002293 case XML_SCHEMAS_DURATION:
2294 if (y->type == XML_SCHEMAS_DURATION)
2295 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002296 return(-2);
2297 case XML_SCHEMAS_TIME:
2298 case XML_SCHEMAS_GDAY:
2299 case XML_SCHEMAS_GMONTH:
2300 case XML_SCHEMAS_GMONTHDAY:
2301 case XML_SCHEMAS_GYEAR:
2302 case XML_SCHEMAS_GYEARMONTH:
2303 case XML_SCHEMAS_DATE:
2304 case XML_SCHEMAS_DATETIME:
2305 if ((y->type == XML_SCHEMAS_DATETIME) ||
2306 (y->type == XML_SCHEMAS_TIME) ||
2307 (y->type == XML_SCHEMAS_GDAY) ||
2308 (y->type == XML_SCHEMAS_GMONTH) ||
2309 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2310 (y->type == XML_SCHEMAS_GYEAR) ||
2311 (y->type == XML_SCHEMAS_DATE) ||
2312 (y->type == XML_SCHEMAS_GYEARMONTH))
2313 return (xmlSchemaCompareDates(x, y));
2314
2315 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002316 default:
2317 TODO
2318 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002319 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002320}
2321
2322/**
2323 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002324 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002325 * @facet: the facet to check
2326 * @value: the lexical repr of the value to validate
2327 * @val: the precomputed value
2328 *
2329 * Check a value against a facet condition
2330 *
2331 * Returns 0 if the element is schemas valid, a positive error code
2332 * number otherwise and -1 in case of internal or API error.
2333 */
2334int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002335xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002336 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002337 const xmlChar *value, xmlSchemaValPtr val)
2338{
2339 int ret;
2340
2341 switch (facet->type) {
2342 case XML_SCHEMA_FACET_PATTERN:
2343 ret = xmlRegexpExec(facet->regexp, value);
2344 if (ret == 1)
2345 return(0);
2346 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002347 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002348 return(1);
2349 }
2350 return(ret);
2351 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2352 ret = xmlSchemaCompareValues(val, facet->val);
2353 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002354 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002355 return(-1);
2356 }
2357 if (ret == -1)
2358 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002359 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002360 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002361 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2362 ret = xmlSchemaCompareValues(val, facet->val);
2363 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002364 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002365 return(-1);
2366 }
2367 if ((ret == -1) || (ret == 0))
2368 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002369 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002370 return(1);
2371 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2372 ret = xmlSchemaCompareValues(val, facet->val);
2373 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002374 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002375 return(-1);
2376 }
2377 if (ret == 1)
2378 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002379 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002380 return(1);
2381 case XML_SCHEMA_FACET_MININCLUSIVE:
2382 ret = xmlSchemaCompareValues(val, facet->val);
2383 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002384 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002385 return(-1);
2386 }
2387 if ((ret == 1) || (ret == 0))
2388 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002389 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002390 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002391 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002392 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00002393 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00002394 case XML_SCHEMA_FACET_ENUMERATION:
2395 if ((facet->value != NULL) &&
2396 (xmlStrEqual(facet->value, value)))
2397 return(0);
2398 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002399 case XML_SCHEMA_FACET_LENGTH:
2400 case XML_SCHEMA_FACET_MAXLENGTH:
2401 case XML_SCHEMA_FACET_MINLENGTH: {
2402 unsigned int len = 0;
2403
2404 if ((facet->val == NULL) ||
2405 (facet->val->type != XML_SCHEMAS_DECIMAL) ||
2406 (facet->val->value.decimal.frac != 0)) {
2407 return(-1);
2408 }
2409 switch (base->flags) {
2410 case XML_SCHEMAS_STRING:
2411 case XML_SCHEMAS_NORMSTRING:
2412 case XML_SCHEMAS_TOKEN:
2413 case XML_SCHEMAS_LANGUAGE:
2414 case XML_SCHEMAS_NMTOKEN:
2415 case XML_SCHEMAS_NAME:
2416 case XML_SCHEMAS_NCNAME:
2417 case XML_SCHEMAS_ID:
2418 case XML_SCHEMAS_IDREF: {
2419 len = xmlUTF8Strlen(value);
2420 break;
2421 }
2422 default:
2423 TODO
2424 }
2425 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
2426 if (len != facet->val->value.decimal.base)
2427 return(1);
2428 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
2429 if (len < facet->val->value.decimal.base)
2430 return(1);
2431 } else {
2432 if (len > facet->val->value.decimal.base)
2433 return(1);
2434 }
2435 break;
2436 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002437 default:
2438 TODO
2439 }
2440 return(0);
2441}
2442
2443#endif /* LIBXML_SCHEMAS_ENABLED */