blob: 1ef762fb528870b3c7f61907366a926753079241 [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
Daniel Veillard6560a422003-03-27 21:25:38 +0000226xmlSchemaInitTypes(void)
227{
Daniel Veillard4255d502002-04-16 15:50:10 +0000228 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000229 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000230 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000231
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000232 /*
233 * primitive datatypes
234 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000235 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
Daniel Veillard6560a422003-03-27 21:25:38 +0000236 XML_SCHEMAS_STRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000237 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000238 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000239 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000240 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000241 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard6560a422003-03-27 21:25:38 +0000242 XML_SCHEMAS_DECIMAL);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000243 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard6560a422003-03-27 21:25:38 +0000244 XML_SCHEMAS_DATE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000245 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard6560a422003-03-27 21:25:38 +0000246 XML_SCHEMAS_DATETIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000247 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard6560a422003-03-27 21:25:38 +0000248 XML_SCHEMAS_TIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000249 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard6560a422003-03-27 21:25:38 +0000250 XML_SCHEMAS_GYEAR);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000251 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000252 XML_SCHEMAS_GYEARMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000253 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000254 XML_SCHEMAS_GMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000255 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000256 XML_SCHEMAS_GMONTHDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000257 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000258 XML_SCHEMAS_GDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000259 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard6560a422003-03-27 21:25:38 +0000260 XML_SCHEMAS_DURATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000261 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard6560a422003-03-27 21:25:38 +0000262 XML_SCHEMAS_FLOAT);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000263 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard6560a422003-03-27 21:25:38 +0000264 XML_SCHEMAS_DOUBLE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000265 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard6560a422003-03-27 21:25:38 +0000266 XML_SCHEMAS_BOOLEAN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000267 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard6560a422003-03-27 21:25:38 +0000268 XML_SCHEMAS_ANYURI);
Daniel Veillard4255d502002-04-16 15:50:10 +0000269
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000270 /*
271 * derived datatypes
272 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000273 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard6560a422003-03-27 21:25:38 +0000274 XML_SCHEMAS_INTEGER);;
275 xmlSchemaTypeNonPositiveIntegerDef =
276 xmlSchemaInitBasicType("nonPositiveInteger",
277 XML_SCHEMAS_NPINTEGER);;
278 xmlSchemaTypeNegativeIntegerDef =
279 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
280 xmlSchemaTypeLongDef =
281 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
282 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000283 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard6560a422003-03-27 21:25:38 +0000284 XML_SCHEMAS_SHORT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000285 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard6560a422003-03-27 21:25:38 +0000286 XML_SCHEMAS_BYTE);;
287 xmlSchemaTypeNonNegativeIntegerDef =
288 xmlSchemaInitBasicType("nonNegativeInteger",
289 XML_SCHEMAS_NNINTEGER);
290 xmlSchemaTypeUnsignedLongDef =
291 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
292 xmlSchemaTypeUnsignedIntDef =
293 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
294 xmlSchemaTypeUnsignedShortDef =
295 xmlSchemaInitBasicType("insignedShort", XML_SCHEMAS_USHORT);;
296 xmlSchemaTypeUnsignedByteDef =
297 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
298 xmlSchemaTypePositiveIntegerDef =
299 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000300
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000301 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard6560a422003-03-27 21:25:38 +0000302 XML_SCHEMAS_NORMSTRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000303 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard6560a422003-03-27 21:25:38 +0000304 XML_SCHEMAS_TOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000305 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard6560a422003-03-27 21:25:38 +0000306 XML_SCHEMAS_LANGUAGE);
307 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000308 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
Daniel Veillard6560a422003-03-27 21:25:38 +0000309 XML_SCHEMAS_IDREF);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000310 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000311 XML_SCHEMAS_IDREFS);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000312 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
Daniel Veillard6560a422003-03-27 21:25:38 +0000313 XML_SCHEMAS_ENTITY);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000314 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
Daniel Veillard6560a422003-03-27 21:25:38 +0000315 XML_SCHEMAS_ENTITIES);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000316 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard6560a422003-03-27 21:25:38 +0000317 XML_SCHEMAS_NAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000318 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000319 XML_SCHEMAS_QNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000320 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000321 XML_SCHEMAS_NCNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000322 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard6560a422003-03-27 21:25:38 +0000323 XML_SCHEMAS_NMTOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000324 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000325 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000326 xmlSchemaTypesInitialized = 1;
327}
328
329/**
330 * xmlSchemaCleanupTypes:
331 *
332 * Cleanup the default XML Schemas type library
333 */
334void
335xmlSchemaCleanupTypes(void) {
336 if (xmlSchemaTypesInitialized == 0)
337 return;
338 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
339 xmlSchemaTypesInitialized = 0;
340}
341
342/**
343 * xmlSchemaNewValue:
344 * @type: the value type
345 *
346 * Allocate a new simple type value
347 *
348 * Returns a pointer to the new value or NULL in case of error
349 */
350static xmlSchemaValPtr
351xmlSchemaNewValue(xmlSchemaValType type) {
352 xmlSchemaValPtr value;
353
354 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
355 if (value == NULL) {
356 return(NULL);
357 }
358 memset(value, 0, sizeof(xmlSchemaVal));
359 value->type = type;
360 return(value);
361}
362
363/**
364 * xmlSchemaFreeValue:
365 * @value: the value to free
366 *
367 * Cleanup the default XML Schemas type library
368 */
369void
370xmlSchemaFreeValue(xmlSchemaValPtr value) {
371 if (value == NULL)
372 return;
373 xmlFree(value);
374}
375
376/**
377 * xmlSchemaGetPredefinedType:
378 * @name: the type name
379 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
380 *
381 * Lookup a type in the default XML Schemas type library
382 *
383 * Returns the type if found, NULL otherwise
384 */
385xmlSchemaTypePtr
386xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
387 if (xmlSchemaTypesInitialized == 0)
388 xmlSchemaInitTypes();
389 if (name == NULL)
390 return(NULL);
391 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
392}
Daniel Veillard070803b2002-05-03 07:29:38 +0000393
394/****************************************************************
395 * *
396 * Convenience macros and functions *
397 * *
398 ****************************************************************/
399
400#define IS_TZO_CHAR(c) \
401 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
402
403#define VALID_YEAR(yr) (yr != 0)
404#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
405/* VALID_DAY should only be used when month is unknown */
406#define VALID_DAY(day) ((day >= 1) && (day <= 31))
407#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
408#define VALID_MIN(min) ((min >= 0) && (min <= 59))
409#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
410#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
411#define IS_LEAP(y) \
412 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
413
414static const long daysInMonth[12] =
415 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
416static const long daysInMonthLeap[12] =
417 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
418
Daniel Veillard5a872412002-05-22 06:40:27 +0000419#define MAX_DAYINMONTH(yr,mon) \
420 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
421
Daniel Veillard070803b2002-05-03 07:29:38 +0000422#define VALID_MDAY(dt) \
423 (IS_LEAP(dt->year) ? \
424 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
425 (dt->day <= daysInMonth[dt->mon - 1]))
426
427#define VALID_DATE(dt) \
428 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
429
430#define VALID_TIME(dt) \
431 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
432 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
433
434#define VALID_DATETIME(dt) \
435 (VALID_DATE(dt) && VALID_TIME(dt))
436
437#define SECS_PER_MIN (60)
438#define SECS_PER_HOUR (60 * SECS_PER_MIN)
439#define SECS_PER_DAY (24 * SECS_PER_HOUR)
440
Daniel Veillard5a872412002-05-22 06:40:27 +0000441static const long dayInYearByMonth[12] =
442 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
443static const long dayInLeapYearByMonth[12] =
444 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
445
446#define DAY_IN_YEAR(day, month, year) \
447 ((IS_LEAP(year) ? \
448 dayInLeapYearByMonth[month - 1] : \
449 dayInYearByMonth[month - 1]) + day)
450
451#ifdef DEBUG
452#define DEBUG_DATE(dt) \
453 xmlGenericError(xmlGenericErrorContext, \
454 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
455 dt->type,dt->value.date.year,dt->value.date.mon, \
456 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
457 dt->value.date.sec); \
458 if (dt->value.date.tz_flag) \
459 if (dt->value.date.tzo != 0) \
460 xmlGenericError(xmlGenericErrorContext, \
461 "%+05d\n",dt->value.date.tzo); \
462 else \
463 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
464 else \
465 xmlGenericError(xmlGenericErrorContext,"\n")
466#else
467#define DEBUG_DATE(dt)
468#endif
469
Daniel Veillard070803b2002-05-03 07:29:38 +0000470/**
471 * _xmlSchemaParseGYear:
472 * @dt: pointer to a date structure
473 * @str: pointer to the string to analyze
474 *
475 * Parses a xs:gYear without time zone and fills in the appropriate
476 * field of the @dt structure. @str is updated to point just after the
477 * xs:gYear. It is supposed that @dt->year is big enough to contain
478 * the year.
479 *
480 * Returns 0 or the error code
481 */
482static int
483_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
484 const xmlChar *cur = *str, *firstChar;
485 int isneg = 0, digcnt = 0;
486
487 if (((*cur < '0') || (*cur > '9')) &&
488 (*cur != '-') && (*cur != '+'))
489 return -1;
490
491 if (*cur == '-') {
492 isneg = 1;
493 cur++;
494 }
495
496 firstChar = cur;
497
498 while ((*cur >= '0') && (*cur <= '9')) {
499 dt->year = dt->year * 10 + (*cur - '0');
500 cur++;
501 digcnt++;
502 }
503
504 /* year must be at least 4 digits (CCYY); over 4
505 * digits cannot have a leading zero. */
506 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
507 return 1;
508
509 if (isneg)
510 dt->year = - dt->year;
511
512 if (!VALID_YEAR(dt->year))
513 return 2;
514
515 *str = cur;
516 return 0;
517}
518
519/**
520 * PARSE_2_DIGITS:
521 * @num: the integer to fill in
522 * @cur: an #xmlChar *
523 * @invalid: an integer
524 *
525 * Parses a 2-digits integer and updates @num with the value. @cur is
526 * updated to point just after the integer.
527 * In case of error, @invalid is set to %TRUE, values of @num and
528 * @cur are undefined.
529 */
530#define PARSE_2_DIGITS(num, cur, invalid) \
531 if ((cur[0] < '0') || (cur[0] > '9') || \
532 (cur[1] < '0') || (cur[1] > '9')) \
533 invalid = 1; \
534 else \
535 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
536 cur += 2;
537
538/**
539 * PARSE_FLOAT:
540 * @num: the double to fill in
541 * @cur: an #xmlChar *
542 * @invalid: an integer
543 *
544 * Parses a float and updates @num with the value. @cur is
545 * updated to point just after the float. The float must have a
546 * 2-digits integer part and may or may not have a decimal part.
547 * In case of error, @invalid is set to %TRUE, values of @num and
548 * @cur are undefined.
549 */
550#define PARSE_FLOAT(num, cur, invalid) \
551 PARSE_2_DIGITS(num, cur, invalid); \
552 if (!invalid && (*cur == '.')) { \
553 double mult = 1; \
554 cur++; \
555 if ((*cur < '0') || (*cur > '9')) \
556 invalid = 1; \
557 while ((*cur >= '0') && (*cur <= '9')) { \
558 mult /= 10; \
559 num += (*cur - '0') * mult; \
560 cur++; \
561 } \
562 }
563
564/**
565 * _xmlSchemaParseGMonth:
566 * @dt: pointer to a date structure
567 * @str: pointer to the string to analyze
568 *
569 * Parses a xs:gMonth without time zone and fills in the appropriate
570 * field of the @dt structure. @str is updated to point just after the
571 * xs:gMonth.
572 *
573 * Returns 0 or the error code
574 */
575static int
576_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
577 const xmlChar *cur = *str;
578 int ret = 0;
579
580 PARSE_2_DIGITS(dt->mon, cur, ret);
581 if (ret != 0)
582 return ret;
583
584 if (!VALID_MONTH(dt->mon))
585 return 2;
586
587 *str = cur;
588 return 0;
589}
590
591/**
592 * _xmlSchemaParseGDay:
593 * @dt: pointer to a date structure
594 * @str: pointer to the string to analyze
595 *
596 * Parses a xs:gDay without time zone and fills in the appropriate
597 * field of the @dt structure. @str is updated to point just after the
598 * xs:gDay.
599 *
600 * Returns 0 or the error code
601 */
602static int
603_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
604 const xmlChar *cur = *str;
605 int ret = 0;
606
607 PARSE_2_DIGITS(dt->day, cur, ret);
608 if (ret != 0)
609 return ret;
610
611 if (!VALID_DAY(dt->day))
612 return 2;
613
614 *str = cur;
615 return 0;
616}
617
618/**
619 * _xmlSchemaParseTime:
620 * @dt: pointer to a date structure
621 * @str: pointer to the string to analyze
622 *
623 * Parses a xs:time without time zone and fills in the appropriate
624 * fields of the @dt structure. @str is updated to point just after the
625 * xs:time.
626 * In case of error, values of @dt fields are undefined.
627 *
628 * Returns 0 or the error code
629 */
630static int
631_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
632 const xmlChar *cur = *str;
633 unsigned int hour = 0; /* use temp var in case str is not xs:time */
634 int ret = 0;
635
636 PARSE_2_DIGITS(hour, cur, ret);
637 if (ret != 0)
638 return ret;
639
640 if (*cur != ':')
641 return 1;
642 cur++;
643
644 /* the ':' insures this string is xs:time */
645 dt->hour = hour;
646
647 PARSE_2_DIGITS(dt->min, cur, ret);
648 if (ret != 0)
649 return ret;
650
651 if (*cur != ':')
652 return 1;
653 cur++;
654
655 PARSE_FLOAT(dt->sec, cur, ret);
656 if (ret != 0)
657 return ret;
658
659 if (!VALID_TIME(dt))
660 return 2;
661
662 *str = cur;
663 return 0;
664}
665
666/**
667 * _xmlSchemaParseTimeZone:
668 * @dt: pointer to a date structure
669 * @str: pointer to the string to analyze
670 *
671 * Parses a time zone without time zone and fills in the appropriate
672 * field of the @dt structure. @str is updated to point just after the
673 * time zone.
674 *
675 * Returns 0 or the error code
676 */
677static int
678_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
679 const xmlChar *cur = *str;
680 int ret = 0;
681
682 if (str == NULL)
683 return -1;
684
685 switch (*cur) {
686 case 0:
687 dt->tz_flag = 0;
688 dt->tzo = 0;
689 break;
690
691 case 'Z':
692 dt->tz_flag = 1;
693 dt->tzo = 0;
694 cur++;
695 break;
696
697 case '+':
698 case '-': {
699 int isneg = 0, tmp = 0;
700 isneg = (*cur == '-');
701
702 cur++;
703
704 PARSE_2_DIGITS(tmp, cur, ret);
705 if (ret != 0)
706 return ret;
707 if (!VALID_HOUR(tmp))
708 return 2;
709
710 if (*cur != ':')
711 return 1;
712 cur++;
713
714 dt->tzo = tmp * 60;
715
716 PARSE_2_DIGITS(tmp, cur, ret);
717 if (ret != 0)
718 return ret;
719 if (!VALID_MIN(tmp))
720 return 2;
721
722 dt->tzo += tmp;
723 if (isneg)
724 dt->tzo = - dt->tzo;
725
726 if (!VALID_TZO(dt->tzo))
727 return 2;
728
Daniel Veillard5a872412002-05-22 06:40:27 +0000729 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000730 break;
731 }
732 default:
733 return 1;
734 }
735
736 *str = cur;
737 return 0;
738}
739
740/****************************************************************
741 * *
742 * XML Schema Dates/Times Datatypes Handling *
743 * *
744 ****************************************************************/
745
746/**
747 * PARSE_DIGITS:
748 * @num: the integer to fill in
749 * @cur: an #xmlChar *
750 * @num_type: an integer flag
751 *
752 * Parses a digits integer and updates @num with the value. @cur is
753 * updated to point just after the integer.
754 * In case of error, @num_type is set to -1, values of @num and
755 * @cur are undefined.
756 */
757#define PARSE_DIGITS(num, cur, num_type) \
758 if ((*cur < '0') || (*cur > '9')) \
759 num_type = -1; \
760 else \
761 while ((*cur >= '0') && (*cur <= '9')) { \
762 num = num * 10 + (*cur - '0'); \
763 cur++; \
764 }
765
766/**
767 * PARSE_NUM:
768 * @num: the double to fill in
769 * @cur: an #xmlChar *
770 * @num_type: an integer flag
771 *
772 * Parses a float or integer and updates @num with the value. @cur is
773 * updated to point just after the number. If the number is a float,
774 * then it must have an integer part and a decimal part; @num_type will
775 * be set to 1. If there is no decimal part, @num_type is set to zero.
776 * In case of error, @num_type is set to -1, values of @num and
777 * @cur are undefined.
778 */
779#define PARSE_NUM(num, cur, num_type) \
780 num = 0; \
781 PARSE_DIGITS(num, cur, num_type); \
782 if (!num_type && (*cur == '.')) { \
783 double mult = 1; \
784 cur++; \
785 if ((*cur < '0') || (*cur > '9')) \
786 num_type = -1; \
787 else \
788 num_type = 1; \
789 while ((*cur >= '0') && (*cur <= '9')) { \
790 mult /= 10; \
791 num += (*cur - '0') * mult; \
792 cur++; \
793 } \
794 }
795
796/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000797 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000798 * @type: the predefined type
799 * @dateTime: string to analyze
800 * @val: the return computed value
801 *
802 * Check that @dateTime conforms to the lexical space of one of the date types.
803 * if true a value is computed and returned in @val.
804 *
805 * Returns 0 if this validates, a positive error code number otherwise
806 * and -1 in case of internal or API error.
807 */
808static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000809xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000810 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000811 xmlSchemaValPtr dt;
812 int ret;
813 const xmlChar *cur = dateTime;
814
815#define RETURN_TYPE_IF_VALID(t) \
816 if (IS_TZO_CHAR(*cur)) { \
817 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
818 if (ret == 0) { \
819 if (*cur != 0) \
820 goto error; \
821 dt->type = t; \
822 if (val != NULL) \
823 *val = dt; \
824 return 0; \
825 } \
826 }
827
828 if (dateTime == NULL)
829 return -1;
830
831 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
832 return 1;
833
834 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
835 if (dt == NULL)
836 return -1;
837
838 if ((cur[0] == '-') && (cur[1] == '-')) {
839 /*
840 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
841 * xs:gDay)
842 */
843 cur += 2;
844
845 /* is it an xs:gDay? */
846 if (*cur == '-') {
847 ++cur;
848 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
849 if (ret != 0)
850 goto error;
851
852 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
853
854 goto error;
855 }
856
857 /*
858 * it should be an xs:gMonthDay or xs:gMonth
859 */
860 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
861 if (ret != 0)
862 goto error;
863
864 if (*cur != '-')
865 goto error;
866 cur++;
867
868 /* is it an xs:gMonth? */
869 if (*cur == '-') {
870 cur++;
871 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
872 goto error;
873 }
874
875 /* it should be an xs:gMonthDay */
876 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
877 if (ret != 0)
878 goto error;
879
880 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
881
882 goto error;
883 }
884
885 /*
886 * It's a right-truncated date or an xs:time.
887 * Try to parse an xs:time then fallback on right-truncated dates.
888 */
889 if ((*cur >= '0') && (*cur <= '9')) {
890 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
891 if (ret == 0) {
892 /* it's an xs:time */
893 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
894 }
895 }
896
897 /* fallback on date parsing */
898 cur = dateTime;
899
900 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
901 if (ret != 0)
902 goto error;
903
904 /* is it an xs:gYear? */
905 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
906
907 if (*cur != '-')
908 goto error;
909 cur++;
910
911 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
912 if (ret != 0)
913 goto error;
914
915 /* is it an xs:gYearMonth? */
916 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
917
918 if (*cur != '-')
919 goto error;
920 cur++;
921
922 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
923 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
924 goto error;
925
926 /* is it an xs:date? */
927 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
928
929 if (*cur != 'T')
930 goto error;
931 cur++;
932
933 /* it should be an xs:dateTime */
934 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
935 if (ret != 0)
936 goto error;
937
938 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
939 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
940 goto error;
941
942 dt->type = XML_SCHEMAS_DATETIME;
943
944 if (val != NULL)
945 *val = dt;
946
947 return 0;
948
949error:
950 if (dt != NULL)
951 xmlSchemaFreeValue(dt);
952 return 1;
953}
954
955/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000956 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000957 * @type: the predefined type
958 * @duration: string to analyze
959 * @val: the return computed value
960 *
961 * Check that @duration conforms to the lexical space of the duration type.
962 * if true a value is computed and returned in @val.
963 *
964 * Returns 0 if this validates, a positive error code number otherwise
965 * and -1 in case of internal or API error.
966 */
967static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000968xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000969 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000970 const xmlChar *cur = duration;
971 xmlSchemaValPtr dur;
972 int isneg = 0;
973 unsigned int seq = 0;
974
975 if (duration == NULL)
976 return -1;
977
978 if (*cur == '-') {
979 isneg = 1;
980 cur++;
981 }
982
983 /* duration must start with 'P' (after sign) */
984 if (*cur++ != 'P')
985 return 1;
986
987 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
988 if (dur == NULL)
989 return -1;
990
991 while (*cur != 0) {
992 double num;
993 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
994 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
995 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
996
997 /* input string should be empty or invalid date/time item */
998 if (seq >= sizeof(desig))
999 goto error;
1000
1001 /* T designator must be present for time items */
1002 if (*cur == 'T') {
1003 if (seq <= 3) {
1004 seq = 3;
1005 cur++;
1006 } else
1007 return 1;
1008 } else if (seq == 3)
1009 goto error;
1010
1011 /* parse the number portion of the item */
1012 PARSE_NUM(num, cur, num_type);
1013
1014 if ((num_type == -1) || (*cur == 0))
1015 goto error;
1016
1017 /* update duration based on item type */
1018 while (seq < sizeof(desig)) {
1019 if (*cur == desig[seq]) {
1020
1021 /* verify numeric type; only seconds can be float */
1022 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1023 goto error;
1024
1025 switch (seq) {
1026 case 0:
1027 dur->value.dur.mon = (long)num * 12;
1028 break;
1029 case 1:
1030 dur->value.dur.mon += (long)num;
1031 break;
1032 default:
1033 /* convert to seconds using multiplier */
1034 dur->value.dur.sec += num * multi[seq];
1035 seq++;
1036 break;
1037 }
1038
1039 break; /* exit loop */
1040 }
1041 /* no date designators found? */
1042 if (++seq == 3)
1043 goto error;
1044 }
1045 cur++;
1046 }
1047
1048 if (isneg) {
1049 dur->value.dur.mon = -dur->value.dur.mon;
1050 dur->value.dur.day = -dur->value.dur.day;
1051 dur->value.dur.sec = -dur->value.dur.sec;
1052 }
1053
1054 if (val != NULL)
1055 *val = dur;
1056
1057 return 0;
1058
1059error:
1060 if (dur != NULL)
1061 xmlSchemaFreeValue(dur);
1062 return 1;
1063}
1064
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001065/**
1066 * xmlSchemaStrip:
1067 * @value: a value
1068 *
1069 * Removes the leading and ending spaces of a string
1070 *
1071 * Returns the new string or NULL if no change was required.
1072 */
1073static xmlChar *
1074xmlSchemaStrip(const xmlChar *value) {
1075 const xmlChar *start = value, *end, *f;
1076
1077 if (value == NULL) return(NULL);
1078 while ((*start != 0) && (IS_BLANK(*start))) start++;
1079 end = start;
1080 while (*end != 0) end++;
1081 f = end;
1082 end--;
1083 while ((end > start) && (IS_BLANK(*end))) end--;
1084 end++;
1085 if ((start == value) && (f == end)) return(NULL);
1086 return(xmlStrndup(start, end - start));
1087}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001088
1089/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001090 * xmlSchemaValAtomicListNode:
1091 * @type: the predefined atomic type for a token in the list
1092 * @value: the list value to check
1093 * @ret: the return computed value
1094 * @node: the node containing the value
1095 *
1096 * Check that a value conforms to the lexical space of the predefined
1097 * list type. if true a value is computed and returned in @ret.
1098 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001099 * Returns the number of items if this validates, a negative error code
1100 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001101 */
1102static int
1103xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1104 xmlSchemaValPtr *ret, xmlNodePtr node) {
1105 xmlChar *val, *cur, *endval;
1106 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001107 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001108
1109 if (value == NULL) {
1110 return(-1);
1111 }
1112 val = xmlStrdup(value);
1113 if (val == NULL) {
1114 return(-1);
1115 }
1116 cur = val;
1117 /*
1118 * Split the list
1119 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001120 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001121 while (*cur != 0) {
1122 if (IS_BLANK(*cur)) {
1123 *cur = 0;
1124 cur++;
1125 while (IS_BLANK(*cur)) *cur++ = 0;
1126 } else {
1127 nb_values++;
1128 cur++;
1129 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1130 }
1131 }
1132 if (nb_values == 0) {
1133 if (ret != NULL) {
1134 TODO
1135 }
1136 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001137 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001138 }
1139 endval = cur;
1140 cur = val;
1141 while ((*cur == 0) && (cur != endval)) cur++;
1142 while (cur != endval) {
1143 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1144 if (tmp != 0)
1145 break;
1146 while (*cur != 0) cur++;
1147 while ((*cur == 0) && (cur != endval)) cur++;
1148 }
1149 xmlFree(val);
1150 if (ret != NULL) {
1151 TODO
1152 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001153 if (tmp == 0)
1154 return(nb_values);
1155 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001156}
1157
1158/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001159 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00001160 * @type: the predefined type
1161 * @value: the value to check
1162 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001163 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00001164 *
1165 * Check that a value conforms to the lexical space of the predefined type.
1166 * if true a value is computed and returned in @val.
1167 *
1168 * Returns 0 if this validates, a positive error code number otherwise
1169 * and -1 in case of internal or API error.
1170 */
1171int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001172xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
1173 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001174 xmlSchemaValPtr v;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001175 int ret;
Daniel Veillard4255d502002-04-16 15:50:10 +00001176
1177 if (xmlSchemaTypesInitialized == 0)
1178 return(-1);
1179 if (type == NULL)
1180 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001181
Daniel Veillard4255d502002-04-16 15:50:10 +00001182 if (val != NULL)
1183 *val = NULL;
1184 if (type == xmlSchemaTypeStringDef) {
1185 return(0);
1186 } else if (type == xmlSchemaTypeAnyTypeDef) {
1187 return(0);
1188 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
1189 return(0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001190 } else if (type == xmlSchemaTypeNmtokenDef) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001191 if (xmlValidateNMToken(value, 1) == 0)
Daniel Veillard4255d502002-04-16 15:50:10 +00001192 return(0);
1193 return(1);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001194 } else if (type == xmlSchemaTypeNmtokensDef) {
1195 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1196 value, val, node);
1197 if (ret >= 0)
1198 ret = 0;
1199 else
1200 ret = 1;
1201 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001202 } else if (type == xmlSchemaTypeDecimalDef) {
1203 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001204 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001205 unsigned long base = 0;
1206 if (cur == NULL)
1207 return(1);
1208 if (*cur == '+')
1209 cur++;
1210 else if (*cur == '-') {
1211 neg = 1;
1212 cur++;
1213 }
1214 tmp = cur;
1215 while ((*cur >= '0') && (*cur <= '9')) {
1216 base = base * 10 + (*cur - '0');
1217 cur++;
1218 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001219 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001220 if (*cur == '.') {
1221 cur++;
1222 tmp = cur;
1223 while ((*cur >= '0') && (*cur <= '9')) {
1224 base = base * 10 + (*cur - '0');
1225 cur++;
1226 }
1227 frac = cur - tmp;
1228 }
1229 if (*cur != 0)
1230 return(1);
1231 if (val != NULL) {
1232 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1233 if (v != NULL) {
1234 v->value.decimal.base = base;
1235 v->value.decimal.sign = neg;
1236 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001237 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001238 *val = v;
1239 }
1240 }
1241 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001242 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001243 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001244 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1245 (type == xmlSchemaTypeTimeDef) ||
1246 (type == xmlSchemaTypeDateDef) ||
1247 (type == xmlSchemaTypeGYearDef) ||
1248 (type == xmlSchemaTypeGYearMonthDef) ||
1249 (type == xmlSchemaTypeGMonthDef) ||
1250 (type == xmlSchemaTypeGMonthDayDef) ||
1251 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001252 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001253 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1254 const xmlChar *cur = value;
1255 unsigned long base = 0;
1256 int total = 0;
1257 if (cur == NULL)
1258 return(1);
1259 if (*cur == '+')
1260 cur++;
1261 while ((*cur >= '0') && (*cur <= '9')) {
1262 base = base * 10 + (*cur - '0');
1263 total++;
1264 cur++;
1265 }
1266 if (*cur != 0)
1267 return(1);
1268 if (val != NULL) {
1269 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1270 if (v != NULL) {
1271 v->value.decimal.base = base;
1272 v->value.decimal.sign = 0;
1273 v->value.decimal.frac = 0;
1274 v->value.decimal.total = total;
1275 *val = v;
1276 }
1277 }
1278 return(0);
1279 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1280 const xmlChar *cur = value;
1281 unsigned long base = 0;
1282 int total = 0;
1283 int sign = 0;
1284 if (cur == NULL)
1285 return(1);
1286 if (*cur == '-') {
1287 sign = 1;
1288 cur++;
Daniel Veillard91a13252003-03-27 23:44:43 +00001289 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001290 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 Veillard91a13252003-03-27 23:44:43 +00001310 } else if (type == xmlSchemaTypeNonPositiveIntegerDef) {
1311 const xmlChar *cur = value;
1312 unsigned long base = 0;
1313 int total = 0;
1314 int sign = 0;
1315 if (cur == NULL)
1316 return(1);
1317 if (*cur == '-') {
1318 sign = 1;
1319 cur++;
1320 }
1321 while ((*cur >= '0') && (*cur <= '9')) {
1322 base = base * 10 + (*cur - '0');
1323 total++;
1324 cur++;
1325 }
1326 if (*cur != 0)
1327 return(1);
1328 if ((sign != 1) && (base != 0))
1329 return(1);
1330 if (val != NULL) {
1331 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1332 if (v != NULL) {
1333 v->value.decimal.base = base;
1334 v->value.decimal.sign = 0;
1335 v->value.decimal.frac = 0;
1336 v->value.decimal.total = total;
1337 *val = v;
1338 }
1339 }
1340 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001341 } else if (type == xmlSchemaTypeIntDef) {
1342 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001343 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001344 int total = 0;
1345 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001346 if (cur == NULL)
1347 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001348 if (*cur == '-') {
1349 sign = 1;
1350 cur++;
1351 } else if (*cur == '+')
1352 cur++;
1353 while (*cur == '0') {
1354 total++;
1355 cur++;
1356 }
1357 while ((*cur >= '0') && (*cur <= '9')) {
1358 base = base * 10 + (*cur - '0');
1359 total++;
1360 cur++;
1361 }
1362 if (*cur != 0)
1363 return(1);
1364 if ((sign == 1) && (total == 0))
1365 return(1);
1366 if (val != NULL) {
1367 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1368 if (v != NULL) {
1369 v->value.decimal.base = base;
1370 v->value.decimal.sign = sign;
1371 v->value.decimal.frac = 0;
1372 v->value.decimal.total = total;
1373 *val = v;
1374 }
1375 }
1376 return(0);
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001377 } else if (type == xmlSchemaTypeIntegerDef) {
1378 const xmlChar *cur = value;
1379 unsigned long base = 0;
1380 int total = 0;
1381 int sign = 0;
1382 if (cur == NULL)
1383 return(1);
1384 if (*cur == '-') {
1385 sign = 1;
1386 cur++;
1387 } else if (*cur == '+')
1388 cur++;
1389 while (*cur == '0') {
1390 total++;
1391 cur++;
1392 }
1393 while ((*cur >= '0') && (*cur <= '9')) {
1394 base = base * 10 + (*cur - '0');
1395 total++;
1396 cur++;
1397 }
1398 if (*cur != 0)
1399 return(1);
1400 if ((sign == 1) && (total == 0))
1401 return(1);
1402 if (val != NULL) {
1403 v = xmlSchemaNewValue(XML_SCHEMAS_INTEGER);
1404 if (v != NULL) {
1405 v->value.decimal.base = base;
1406 v->value.decimal.sign = sign;
1407 v->value.decimal.frac = 0;
1408 v->value.decimal.total = total;
1409 *val = v;
1410 }
1411 }
1412 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001413 } else if ((type == xmlSchemaTypeFloatDef) ||
1414 (type == xmlSchemaTypeDoubleDef)) {
1415 const xmlChar *cur = value;
1416 int neg = 0;
1417 if (cur == NULL)
1418 return(1);
1419 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1420 cur += 3;
1421 if (*cur != 0)
1422 return(1);
1423 if (val != NULL) {
1424 if (type == xmlSchemaTypeFloatDef) {
1425 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1426 if (v != NULL) {
1427 v->value.f = (float) xmlXPathNAN;
1428 } else {
1429 xmlSchemaFreeValue(v);
1430 return(-1);
1431 }
1432 } else {
1433 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1434 if (v != NULL) {
1435 v->value.d = xmlXPathNAN;
1436 } else {
1437 xmlSchemaFreeValue(v);
1438 return(-1);
1439 }
1440 }
1441 *val = v;
1442 }
1443 return(0);
1444 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001445 if (*cur == '+')
1446 cur++;
1447 else if (*cur == '-') {
1448 neg = 1;
1449 cur++;
1450 }
Daniel Veillardd4310742003-02-18 21:12:46 +00001451 if (cur[0] == 0)
1452 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001453 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1454 cur += 3;
1455 if (*cur != 0)
1456 return(1);
1457 if (val != NULL) {
1458 if (type == xmlSchemaTypeFloatDef) {
1459 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1460 if (v != NULL) {
1461 if (neg)
1462 v->value.f = (float) xmlXPathNINF;
1463 else
1464 v->value.f = (float) xmlXPathPINF;
1465 } else {
1466 xmlSchemaFreeValue(v);
1467 return(-1);
1468 }
1469 } else {
1470 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1471 if (v != NULL) {
1472 if (neg)
1473 v->value.d = xmlXPathNINF;
1474 else
1475 v->value.d = xmlXPathPINF;
1476 } else {
1477 xmlSchemaFreeValue(v);
1478 return(-1);
1479 }
1480 }
1481 *val = v;
1482 }
1483 return(0);
1484 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001485 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001486 cur++;
1487 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001488 if (*cur == '.') {
1489 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001490 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001491 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001492 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001493 if ((*cur == 'e') || (*cur == 'E')) {
1494 cur++;
1495 if (*cur == '-')
1496 cur++;
1497 while ((*cur >= '0') && (*cur <= '9'))
1498 cur++;
1499 }
1500 if (*cur != 0)
1501 return(1);
1502 if (val != NULL) {
1503 if (type == xmlSchemaTypeFloatDef) {
1504 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1505 if (v != NULL) {
1506 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1507 *val = v;
1508 } else {
1509 xmlGenericError(xmlGenericErrorContext,
1510 "failed to scanf float %s\n", value);
1511 xmlSchemaFreeValue(v);
1512 return(1);
1513 }
1514 } else {
1515 return(-1);
1516 }
1517 } else {
1518 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1519 if (v != NULL) {
1520 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1521 *val = v;
1522 } else {
1523 xmlGenericError(xmlGenericErrorContext,
1524 "failed to scanf double %s\n", value);
1525 xmlSchemaFreeValue(v);
1526 return(1);
1527 }
1528 } else {
1529 return(-1);
1530 }
1531 }
1532 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001533 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001534 } else if (type == xmlSchemaTypeNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001535 ret = xmlValidateName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001536 if ((ret == 0) && (val != NULL)) {
1537 TODO;
1538 }
1539 return(ret);
1540 } else if (type == xmlSchemaTypeQNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001541 ret = xmlValidateQName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001542 if ((ret == 0) && (val != NULL)) {
1543 TODO;
1544 }
1545 return(ret);
1546 } else if (type == xmlSchemaTypeNCNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001547 ret = xmlValidateNCName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001548 if ((ret == 0) && (val != NULL)) {
1549 TODO;
1550 }
1551 return(ret);
1552 } else if (type == xmlSchemaTypeAnyURIDef) {
1553 xmlURIPtr uri;
1554
1555 uri = xmlParseURI((const char *) value);
1556 if (uri == NULL)
1557 return(1);
1558 if (val != NULL) {
1559 TODO;
1560 }
1561 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001562 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001563 } else if (type == xmlSchemaTypeBooleanDef) {
1564 const xmlChar *cur = value;
1565
1566 if ((cur[0] == '0') && (cur[1] == 0))
1567 ret = 0;
1568 else if ((cur[0] == '1') && (cur[1] == 0))
1569 ret = 1;
1570 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1571 (cur[3] == 'e') && (cur[4] == 0))
1572 ret = 1;
1573 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1574 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1575 ret = 0;
1576 else
1577 return(1);
1578 if (val != NULL) {
1579 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1580 if (v != NULL) {
1581 v->value.b = ret;
1582 *val = v;
1583 } else {
1584 return(-1);
1585 }
1586 }
1587 return(0);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001588 } else if (type == xmlSchemaTypeIdrefDef) {
1589 ret = xmlValidateNCName(value, 1);
1590 if ((ret == 0) && (val != NULL)) {
1591 TODO;
1592 }
1593 if ((ret == 0) && (node != NULL) &&
1594 (node->type == XML_ATTRIBUTE_NODE)) {
1595 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001596 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001597
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001598 strip = xmlSchemaStrip(value);
1599 if (strip != NULL) {
1600 xmlAddRef(NULL, node->doc, strip, attr);
1601 xmlFree(strip);
1602 } else
1603 xmlAddRef(NULL, node->doc, value, attr);
1604 attr->atype = XML_ATTRIBUTE_IDREF;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001605 }
1606 return(ret);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001607 } else if (type == xmlSchemaTypeIdrefsDef) {
1608 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1609 value, val, node);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001610 if (ret < 0)
1611 ret = 2;
1612 else
1613 ret = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001614 if ((ret == 0) && (node != NULL) &&
1615 (node->type == XML_ATTRIBUTE_NODE)) {
1616 xmlAttrPtr attr = (xmlAttrPtr) node;
1617
1618 attr->atype = XML_ATTRIBUTE_IDREFS;
1619 }
1620 return(ret);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001621 } else if (type == xmlSchemaTypeIdDef) {
1622 ret = xmlValidateNCName(value, 1);
1623 if ((ret == 0) && (val != NULL)) {
1624 TODO;
1625 }
1626 if ((ret == 0) && (node != NULL) &&
1627 (node->type == XML_ATTRIBUTE_NODE)) {
1628 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001629 /*
1630 * NOTE: the IDness might have already be declared in the DTD
1631 */
1632 if (attr->atype != XML_ATTRIBUTE_ID) {
1633 xmlIDPtr res;
1634 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001635
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001636 strip = xmlSchemaStrip(value);
1637 if (strip != NULL) {
1638 res = xmlAddID(NULL, node->doc, strip, attr);
1639 xmlFree(strip);
1640 } else
1641 res = xmlAddID(NULL, node->doc, value, attr);
1642 if (res == NULL) {
1643 ret = 2;
1644 } else {
1645 attr->atype = XML_ATTRIBUTE_ID;
1646 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001647 }
1648 }
1649 return(ret);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001650 } else if (type == xmlSchemaTypeEntitiesDef) {
1651 if ((node == NULL) || (node->doc == NULL))
1652 return(3);
1653 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1654 value, val, node);
1655 if (ret <= 0)
1656 ret = 1;
1657 else
1658 ret = 0;
1659 if ((ret == 0) && (node != NULL) &&
1660 (node->type == XML_ATTRIBUTE_NODE)) {
1661 xmlAttrPtr attr = (xmlAttrPtr) node;
1662
1663 attr->atype = XML_ATTRIBUTE_ENTITIES;
1664 }
1665 return(ret);
1666 } else if (type == xmlSchemaTypeEntityDef) {
1667 xmlChar *strip;
1668 ret = xmlValidateNCName(value, 1);
1669 if ((node == NULL) || (node->doc == NULL))
1670 ret = 3;
1671 if (ret == 0) {
1672 xmlEntityPtr ent;
1673
1674 strip = xmlSchemaStrip(value);
1675 if (strip != NULL) {
1676 ent = xmlGetDocEntity(node->doc, strip);
1677 xmlFree(strip);
1678 } else {
1679 ent = xmlGetDocEntity(node->doc, value);
1680 }
1681 if ((ent == NULL) ||
1682 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1683 ret = 4;
1684 }
1685 if ((ret == 0) && (val != NULL)) {
1686 TODO;
1687 }
1688 if ((ret == 0) && (node != NULL) &&
1689 (node->type == XML_ATTRIBUTE_NODE)) {
1690 xmlAttrPtr attr = (xmlAttrPtr) node;
1691
1692 attr->atype = XML_ATTRIBUTE_ENTITY;
1693 }
1694 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001695 }
Daniel Veillard09628212003-03-25 15:10:27 +00001696 TODO
1697 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001698}
1699
1700/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001701 * xmlSchemaValidatePredefinedType:
1702 * @type: the predefined type
1703 * @value: the value to check
1704 * @val: the return computed value
1705 *
1706 * Check that a value conforms to the lexical space of the predefined type.
1707 * if true a value is computed and returned in @val.
1708 *
1709 * Returns 0 if this validates, a positive error code number otherwise
1710 * and -1 in case of internal or API error.
1711 */
1712int
1713xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1714 xmlSchemaValPtr *val) {
1715 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
1716}
1717
1718/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001719 * xmlSchemaCompareDecimals:
1720 * @x: a first decimal value
1721 * @y: a second decimal value
1722 *
1723 * Compare 2 decimals
1724 *
1725 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1726 */
1727static int
1728xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1729{
1730 xmlSchemaValPtr swp;
1731 int order = 1;
1732 unsigned long tmp;
1733
1734 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1735 order = -1;
1736 else if (x->value.decimal.sign)
1737 return (-1);
1738 else if (y->value.decimal.sign)
1739 return (1);
1740 if (x->value.decimal.frac == y->value.decimal.frac) {
1741 if (x->value.decimal.base < y->value.decimal.base)
1742 return (-1);
1743 return (x->value.decimal.base > y->value.decimal.base);
1744 }
1745 if (y->value.decimal.frac > x->value.decimal.frac) {
1746 swp = y;
1747 y = x;
1748 x = swp;
1749 order = -order;
1750 }
1751 tmp =
1752 x->value.decimal.base / powten[x->value.decimal.frac -
1753 y->value.decimal.frac];
1754 if (tmp > y->value.decimal.base)
1755 return (order);
1756 if (tmp < y->value.decimal.base)
1757 return (-order);
1758 tmp =
1759 y->value.decimal.base * powten[x->value.decimal.frac -
1760 y->value.decimal.frac];
1761 if (x->value.decimal.base < tmp)
1762 return (-order);
1763 if (x->value.decimal.base == tmp)
1764 return (0);
1765 return (order);
1766}
1767
1768/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001769 * xmlSchemaCompareDurations:
1770 * @x: a first duration value
1771 * @y: a second duration value
1772 *
1773 * Compare 2 durations
1774 *
1775 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1776 * case of error
1777 */
1778static int
1779xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1780{
1781 long carry, mon, day;
1782 double sec;
1783 long xmon, xday, myear, lyear, minday, maxday;
1784 static const long dayRange [2][12] = {
1785 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1786 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1787
1788 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001789 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001790
1791 /* months */
1792 mon = x->value.dur.mon - y->value.dur.mon;
1793
1794 /* seconds */
1795 sec = x->value.dur.sec - y->value.dur.sec;
1796 carry = (long)sec / SECS_PER_DAY;
1797 sec -= (double)(carry * SECS_PER_DAY);
1798
1799 /* days */
1800 day = x->value.dur.day - y->value.dur.day + carry;
1801
1802 /* easy test */
1803 if (mon == 0) {
1804 if (day == 0)
1805 if (sec == 0.0)
1806 return 0;
1807 else if (sec < 0.0)
1808 return -1;
1809 else
1810 return 1;
1811 else if (day < 0)
1812 return -1;
1813 else
1814 return 1;
1815 }
1816
1817 if (mon > 0) {
1818 if ((day >= 0) && (sec >= 0.0))
1819 return 1;
1820 else {
1821 xmon = mon;
1822 xday = -day;
1823 }
1824 } else if ((day <= 0) && (sec <= 0.0)) {
1825 return -1;
1826 } else {
1827 xmon = -mon;
1828 xday = day;
1829 }
1830
1831 myear = xmon / 12;
1832 lyear = myear / 4;
1833 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1834 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1835
1836 xmon = xmon % 12;
1837 minday += dayRange[0][xmon];
1838 maxday += dayRange[1][xmon];
1839
1840 if (maxday < xday)
1841 return 1;
1842 else if (minday > xday)
1843 return -1;
1844
1845 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001846 return 2;
1847}
1848
1849/*
1850 * macros for adding date/times and durations
1851 */
1852#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1853#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1854#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1855#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1856
1857/**
1858 * _xmlSchemaDateAdd:
1859 * @dt: an #xmlSchemaValPtr
1860 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1861 *
1862 * Compute a new date/time from @dt and @dur. This function assumes @dt
1863 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1864 * or #XML_SCHEMAS_GYEAR.
1865 *
1866 * Returns date/time pointer or NULL.
1867 */
1868static xmlSchemaValPtr
1869_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1870{
1871 xmlSchemaValPtr ret;
1872 long carry, tempdays, temp;
1873 xmlSchemaValDatePtr r, d;
1874 xmlSchemaValDurationPtr u;
1875
1876 if ((dt == NULL) || (dur == NULL))
1877 return NULL;
1878
1879 ret = xmlSchemaNewValue(dt->type);
1880 if (ret == NULL)
1881 return NULL;
1882
1883 r = &(ret->value.date);
1884 d = &(dt->value.date);
1885 u = &(dur->value.dur);
1886
1887 /* normalization */
1888 if (d->mon == 0)
1889 d->mon = 1;
1890
1891 /* normalize for time zone offset */
1892 u->sec -= (d->tzo * 60);
1893 d->tzo = 0;
1894
1895 /* normalization */
1896 if (d->day == 0)
1897 d->day = 1;
1898
1899 /* month */
1900 carry = d->mon + u->mon;
1901 r->mon = MODULO_RANGE(carry, 1, 13);
1902 carry = FQUOTIENT_RANGE(carry, 1, 13);
1903
1904 /* year (may be modified later) */
1905 r->year = d->year + carry;
1906 if (r->year == 0) {
1907 if (d->year > 0)
1908 r->year--;
1909 else
1910 r->year++;
1911 }
1912
1913 /* time zone */
1914 r->tzo = d->tzo;
1915 r->tz_flag = d->tz_flag;
1916
1917 /* seconds */
1918 r->sec = d->sec + u->sec;
1919 carry = FQUOTIENT((long)r->sec, 60);
1920 if (r->sec != 0.0) {
1921 r->sec = MODULO(r->sec, 60.0);
1922 }
1923
1924 /* minute */
1925 carry += d->min;
1926 r->min = MODULO(carry, 60);
1927 carry = FQUOTIENT(carry, 60);
1928
1929 /* hours */
1930 carry += d->hour;
1931 r->hour = MODULO(carry, 24);
1932 carry = FQUOTIENT(carry, 24);
1933
1934 /*
1935 * days
1936 * Note we use tempdays because the temporary values may need more
1937 * than 5 bits
1938 */
1939 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1940 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1941 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1942 else if (d->day < 1)
1943 tempdays = 1;
1944 else
1945 tempdays = d->day;
1946
1947 tempdays += u->day + carry;
1948
1949 while (1) {
1950 if (tempdays < 1) {
1951 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1952 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1953 if (tyr == 0)
1954 tyr--;
1955 tempdays += MAX_DAYINMONTH(tyr, tmon);
1956 carry = -1;
1957 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1958 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1959 carry = 1;
1960 } else
1961 break;
1962
1963 temp = r->mon + carry;
1964 r->mon = MODULO_RANGE(temp, 1, 13);
1965 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1966 if (r->year == 0) {
1967 if (temp < 1)
1968 r->year--;
1969 else
1970 r->year++;
1971 }
1972 }
1973
1974 r->day = tempdays;
1975
1976 /*
1977 * adjust the date/time type to the date values
1978 */
1979 if (ret->type != XML_SCHEMAS_DATETIME) {
1980 if ((r->hour) || (r->min) || (r->sec))
1981 ret->type = XML_SCHEMAS_DATETIME;
1982 else if (ret->type != XML_SCHEMAS_DATE) {
1983 if ((r->mon != 1) && (r->day != 1))
1984 ret->type = XML_SCHEMAS_DATE;
1985 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1986 ret->type = XML_SCHEMAS_GYEARMONTH;
1987 }
1988 }
1989
1990 return ret;
1991}
1992
1993/**
1994 * xmlSchemaDupVal:
1995 * @v: value to duplicate
1996 *
1997 * returns a duplicated value.
1998 */
1999static xmlSchemaValPtr
2000xmlSchemaDupVal (xmlSchemaValPtr v)
2001{
2002 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2003 if (ret == NULL)
2004 return ret;
2005
2006 memcpy(ret, v, sizeof(xmlSchemaVal));
2007 return ret;
2008}
2009
2010/**
2011 * xmlSchemaDateNormalize:
2012 * @dt: an #xmlSchemaValPtr
2013 *
2014 * Normalize @dt to GMT time.
2015 *
2016 */
2017static xmlSchemaValPtr
2018xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2019{
2020 xmlSchemaValPtr dur, ret;
2021
2022 if (dt == NULL)
2023 return NULL;
2024
2025 if (((dt->type != XML_SCHEMAS_TIME) &&
2026 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2027 return xmlSchemaDupVal(dt);
2028
2029 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2030 if (dur == NULL)
2031 return NULL;
2032
2033 dur->value.date.sec -= offset;
2034
2035 ret = _xmlSchemaDateAdd(dt, dur);
2036 if (ret == NULL)
2037 return NULL;
2038
2039 xmlSchemaFreeValue(dur);
2040
2041 /* ret->value.date.tzo = 0; */
2042 return ret;
2043}
2044
2045/**
2046 * _xmlSchemaDateCastYMToDays:
2047 * @dt: an #xmlSchemaValPtr
2048 *
2049 * Convert mon and year of @dt to total number of days. Take the
2050 * number of years since (or before) 1 AD and add the number of leap
2051 * years. This is a function because negative
2052 * years must be handled a little differently and there is no zero year.
2053 *
2054 * Returns number of days.
2055 */
2056static long
2057_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2058{
2059 long ret;
2060
2061 if (dt->value.date.year < 0)
2062 ret = (dt->value.date.year * 365) +
2063 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2064 ((dt->value.date.year+1)/400)) +
2065 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2066 else
2067 ret = ((dt->value.date.year-1) * 365) +
2068 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2069 ((dt->value.date.year-1)/400)) +
2070 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2071
2072 return ret;
2073}
2074
2075/**
2076 * TIME_TO_NUMBER:
2077 * @dt: an #xmlSchemaValPtr
2078 *
2079 * Calculates the number of seconds in the time portion of @dt.
2080 *
2081 * Returns seconds.
2082 */
2083#define TIME_TO_NUMBER(dt) \
2084 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
2085 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
2086
2087/**
2088 * xmlSchemaCompareDates:
2089 * @x: a first date/time value
2090 * @y: a second date/time value
2091 *
2092 * Compare 2 date/times
2093 *
2094 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2095 * case of error
2096 */
2097static int
2098xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2099{
2100 unsigned char xmask, ymask, xor_mask, and_mask;
2101 xmlSchemaValPtr p1, p2, q1, q2;
2102 long p1d, p2d, q1d, q2d;
2103
2104 if ((x == NULL) || (y == NULL))
2105 return -2;
2106
2107 if (x->value.date.tz_flag) {
2108
2109 if (!y->value.date.tz_flag) {
2110 p1 = xmlSchemaDateNormalize(x, 0);
2111 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2112 /* normalize y + 14:00 */
2113 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2114
2115 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002116 if (p1d < q1d) {
2117 xmlSchemaFreeValue(p1);
2118 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002119 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002120 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002121 double sec;
2122
2123 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002124 if (sec < 0.0) {
2125 xmlSchemaFreeValue(p1);
2126 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002127 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002128 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002129 /* normalize y - 14:00 */
2130 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2131 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002132 xmlSchemaFreeValue(p1);
2133 xmlSchemaFreeValue(q1);
2134 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002135 if (p1d > q2d)
2136 return 1;
2137 else if (p1d == q2d) {
2138 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2139 if (sec > 0.0)
2140 return 1;
2141 else
2142 return 2; /* indeterminate */
2143 }
2144 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002145 } else {
2146 xmlSchemaFreeValue(p1);
2147 xmlSchemaFreeValue(q1);
2148 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002149 }
2150 } else if (y->value.date.tz_flag) {
2151 q1 = xmlSchemaDateNormalize(y, 0);
2152 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2153
2154 /* normalize x - 14:00 */
2155 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2156 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2157
Daniel Veillardfdc91562002-07-01 21:52:03 +00002158 if (p1d < q1d) {
2159 xmlSchemaFreeValue(p1);
2160 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002161 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002162 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002163 double sec;
2164
2165 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002166 if (sec < 0.0) {
2167 xmlSchemaFreeValue(p1);
2168 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002169 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002170 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002171 /* normalize x + 14:00 */
2172 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2173 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2174
Daniel Veillard6560a422003-03-27 21:25:38 +00002175 if (p2d > q1d) {
2176 xmlSchemaFreeValue(p1);
2177 xmlSchemaFreeValue(q1);
2178 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002179 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002180 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002181 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002182 xmlSchemaFreeValue(p1);
2183 xmlSchemaFreeValue(q1);
2184 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002185 if (sec > 0.0)
2186 return 1;
2187 else
2188 return 2; /* indeterminate */
2189 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002190 xmlSchemaFreeValue(p1);
2191 xmlSchemaFreeValue(q1);
2192 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002193 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002194 } else {
2195 xmlSchemaFreeValue(p1);
2196 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002197 }
2198 }
2199
2200 /*
2201 * if the same type then calculate the difference
2202 */
2203 if (x->type == y->type) {
2204 q1 = xmlSchemaDateNormalize(y, 0);
2205 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2206
2207 p1 = xmlSchemaDateNormalize(x, 0);
2208 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2209
Daniel Veillardfdc91562002-07-01 21:52:03 +00002210 if (p1d < q1d) {
2211 xmlSchemaFreeValue(p1);
2212 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002213 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002214 } else if (p1d > q1d) {
2215 xmlSchemaFreeValue(p1);
2216 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002217 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002218 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002219 double sec;
2220
2221 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002222 xmlSchemaFreeValue(p1);
2223 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002224 if (sec < 0.0)
2225 return -1;
2226 else if (sec > 0.0)
2227 return 1;
2228
2229 }
2230 return 0;
2231 }
2232
2233 switch (x->type) {
2234 case XML_SCHEMAS_DATETIME:
2235 xmask = 0xf;
2236 break;
2237 case XML_SCHEMAS_DATE:
2238 xmask = 0x7;
2239 break;
2240 case XML_SCHEMAS_GYEAR:
2241 xmask = 0x1;
2242 break;
2243 case XML_SCHEMAS_GMONTH:
2244 xmask = 0x2;
2245 break;
2246 case XML_SCHEMAS_GDAY:
2247 xmask = 0x3;
2248 break;
2249 case XML_SCHEMAS_GYEARMONTH:
2250 xmask = 0x3;
2251 break;
2252 case XML_SCHEMAS_GMONTHDAY:
2253 xmask = 0x6;
2254 break;
2255 case XML_SCHEMAS_TIME:
2256 xmask = 0x8;
2257 break;
2258 default:
2259 xmask = 0;
2260 break;
2261 }
2262
2263 switch (y->type) {
2264 case XML_SCHEMAS_DATETIME:
2265 ymask = 0xf;
2266 break;
2267 case XML_SCHEMAS_DATE:
2268 ymask = 0x7;
2269 break;
2270 case XML_SCHEMAS_GYEAR:
2271 ymask = 0x1;
2272 break;
2273 case XML_SCHEMAS_GMONTH:
2274 ymask = 0x2;
2275 break;
2276 case XML_SCHEMAS_GDAY:
2277 ymask = 0x3;
2278 break;
2279 case XML_SCHEMAS_GYEARMONTH:
2280 ymask = 0x3;
2281 break;
2282 case XML_SCHEMAS_GMONTHDAY:
2283 ymask = 0x6;
2284 break;
2285 case XML_SCHEMAS_TIME:
2286 ymask = 0x8;
2287 break;
2288 default:
2289 ymask = 0;
2290 break;
2291 }
2292
2293 xor_mask = xmask ^ ymask; /* mark type differences */
2294 and_mask = xmask & ymask; /* mark field specification */
2295
2296 /* year */
2297 if (xor_mask & 1)
2298 return 2; /* indeterminate */
2299 else if (and_mask & 1) {
2300 if (x->value.date.year < y->value.date.year)
2301 return -1;
2302 else if (x->value.date.year > y->value.date.year)
2303 return 1;
2304 }
2305
2306 /* month */
2307 if (xor_mask & 2)
2308 return 2; /* indeterminate */
2309 else if (and_mask & 2) {
2310 if (x->value.date.mon < y->value.date.mon)
2311 return -1;
2312 else if (x->value.date.mon > y->value.date.mon)
2313 return 1;
2314 }
2315
2316 /* day */
2317 if (xor_mask & 4)
2318 return 2; /* indeterminate */
2319 else if (and_mask & 4) {
2320 if (x->value.date.day < y->value.date.day)
2321 return -1;
2322 else if (x->value.date.day > y->value.date.day)
2323 return 1;
2324 }
2325
2326 /* time */
2327 if (xor_mask & 8)
2328 return 2; /* indeterminate */
2329 else if (and_mask & 8) {
2330 if (x->value.date.hour < y->value.date.hour)
2331 return -1;
2332 else if (x->value.date.hour > y->value.date.hour)
2333 return 1;
2334 else if (x->value.date.min < y->value.date.min)
2335 return -1;
2336 else if (x->value.date.min > y->value.date.min)
2337 return 1;
2338 else if (x->value.date.sec < y->value.date.sec)
2339 return -1;
2340 else if (x->value.date.sec > y->value.date.sec)
2341 return 1;
2342 }
2343
Daniel Veillard070803b2002-05-03 07:29:38 +00002344 return 0;
2345}
2346
2347/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002348 * xmlSchemaCompareValues:
2349 * @x: a first value
2350 * @y: a second value
2351 *
2352 * Compare 2 values
2353 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002354 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2355 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002356 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00002357static int
Daniel Veillard4255d502002-04-16 15:50:10 +00002358xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2359 if ((x == NULL) || (y == NULL))
2360 return(-2);
2361
2362 switch (x->type) {
2363 case XML_SCHEMAS_STRING:
2364 TODO
2365 case XML_SCHEMAS_DECIMAL:
2366 if (y->type == XML_SCHEMAS_DECIMAL)
2367 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002368 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002369 case XML_SCHEMAS_DURATION:
2370 if (y->type == XML_SCHEMAS_DURATION)
2371 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002372 return(-2);
2373 case XML_SCHEMAS_TIME:
2374 case XML_SCHEMAS_GDAY:
2375 case XML_SCHEMAS_GMONTH:
2376 case XML_SCHEMAS_GMONTHDAY:
2377 case XML_SCHEMAS_GYEAR:
2378 case XML_SCHEMAS_GYEARMONTH:
2379 case XML_SCHEMAS_DATE:
2380 case XML_SCHEMAS_DATETIME:
2381 if ((y->type == XML_SCHEMAS_DATETIME) ||
2382 (y->type == XML_SCHEMAS_TIME) ||
2383 (y->type == XML_SCHEMAS_GDAY) ||
2384 (y->type == XML_SCHEMAS_GMONTH) ||
2385 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2386 (y->type == XML_SCHEMAS_GYEAR) ||
2387 (y->type == XML_SCHEMAS_DATE) ||
2388 (y->type == XML_SCHEMAS_GYEARMONTH))
2389 return (xmlSchemaCompareDates(x, y));
2390
2391 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002392 default:
2393 TODO
2394 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002395 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002396}
2397
2398/**
2399 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002400 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002401 * @facet: the facet to check
2402 * @value: the lexical repr of the value to validate
2403 * @val: the precomputed value
2404 *
2405 * Check a value against a facet condition
2406 *
2407 * Returns 0 if the element is schemas valid, a positive error code
2408 * number otherwise and -1 in case of internal or API error.
2409 */
2410int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002411xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002412 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002413 const xmlChar *value, xmlSchemaValPtr val)
2414{
2415 int ret;
2416
2417 switch (facet->type) {
2418 case XML_SCHEMA_FACET_PATTERN:
2419 ret = xmlRegexpExec(facet->regexp, value);
2420 if (ret == 1)
2421 return(0);
2422 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002423 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002424 return(1);
2425 }
2426 return(ret);
2427 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2428 ret = xmlSchemaCompareValues(val, facet->val);
2429 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002430 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002431 return(-1);
2432 }
2433 if (ret == -1)
2434 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002435 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002436 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002437 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2438 ret = xmlSchemaCompareValues(val, facet->val);
2439 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002440 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002441 return(-1);
2442 }
2443 if ((ret == -1) || (ret == 0))
2444 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002445 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002446 return(1);
2447 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2448 ret = xmlSchemaCompareValues(val, facet->val);
2449 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002450 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002451 return(-1);
2452 }
2453 if (ret == 1)
2454 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002455 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002456 return(1);
2457 case XML_SCHEMA_FACET_MININCLUSIVE:
2458 ret = xmlSchemaCompareValues(val, facet->val);
2459 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002460 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002461 return(-1);
2462 }
2463 if ((ret == 1) || (ret == 0))
2464 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002465 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002466 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002467 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002468 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00002469 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00002470 case XML_SCHEMA_FACET_ENUMERATION:
2471 if ((facet->value != NULL) &&
2472 (xmlStrEqual(facet->value, value)))
2473 return(0);
2474 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002475 case XML_SCHEMA_FACET_LENGTH:
2476 case XML_SCHEMA_FACET_MAXLENGTH:
2477 case XML_SCHEMA_FACET_MINLENGTH: {
2478 unsigned int len = 0;
2479
2480 if ((facet->val == NULL) ||
2481 (facet->val->type != XML_SCHEMAS_DECIMAL) ||
2482 (facet->val->value.decimal.frac != 0)) {
2483 return(-1);
2484 }
2485 switch (base->flags) {
2486 case XML_SCHEMAS_STRING:
2487 case XML_SCHEMAS_NORMSTRING:
2488 case XML_SCHEMAS_TOKEN:
2489 case XML_SCHEMAS_LANGUAGE:
2490 case XML_SCHEMAS_NMTOKEN:
2491 case XML_SCHEMAS_NAME:
2492 case XML_SCHEMAS_NCNAME:
2493 case XML_SCHEMAS_ID:
2494 case XML_SCHEMAS_IDREF: {
2495 len = xmlUTF8Strlen(value);
2496 break;
2497 }
2498 default:
2499 TODO
2500 }
2501 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
2502 if (len != facet->val->value.decimal.base)
2503 return(1);
2504 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
2505 if (len < facet->val->value.decimal.base)
2506 return(1);
2507 } else {
2508 if (len > facet->val->value.decimal.base)
2509 return(1);
2510 }
2511 break;
2512 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002513 default:
2514 TODO
2515 }
2516 return(0);
2517}
2518
2519#endif /* LIBXML_SCHEMAS_ENABLED */