blob: fa1350241c6ed24cb8b09d39423ba7d872cc3902 [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++;
1289 } else if (*cur == '+')
1290 cur++;
1291 while ((*cur >= '0') && (*cur <= '9')) {
1292 base = base * 10 + (*cur - '0');
1293 total++;
1294 cur++;
1295 }
1296 if (*cur != 0)
1297 return(1);
1298 if ((sign == 1) && (base != 0))
1299 return(1);
1300 if (val != NULL) {
1301 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1302 if (v != NULL) {
1303 v->value.decimal.base = base;
1304 v->value.decimal.sign = 0;
1305 v->value.decimal.frac = 0;
1306 v->value.decimal.total = total;
1307 *val = v;
1308 }
1309 }
1310 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001311 } else if (type == xmlSchemaTypeIntDef) {
1312 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001313 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001314 int total = 0;
1315 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001316 if (cur == NULL)
1317 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001318 if (*cur == '-') {
1319 sign = 1;
1320 cur++;
1321 } else if (*cur == '+')
1322 cur++;
1323 while (*cur == '0') {
1324 total++;
1325 cur++;
1326 }
1327 while ((*cur >= '0') && (*cur <= '9')) {
1328 base = base * 10 + (*cur - '0');
1329 total++;
1330 cur++;
1331 }
1332 if (*cur != 0)
1333 return(1);
1334 if ((sign == 1) && (total == 0))
1335 return(1);
1336 if (val != NULL) {
1337 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1338 if (v != NULL) {
1339 v->value.decimal.base = base;
1340 v->value.decimal.sign = sign;
1341 v->value.decimal.frac = 0;
1342 v->value.decimal.total = total;
1343 *val = v;
1344 }
1345 }
1346 return(0);
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001347 } else if (type == xmlSchemaTypeIntegerDef) {
1348 const xmlChar *cur = value;
1349 unsigned long base = 0;
1350 int total = 0;
1351 int sign = 0;
1352 if (cur == NULL)
1353 return(1);
1354 if (*cur == '-') {
1355 sign = 1;
1356 cur++;
1357 } else if (*cur == '+')
1358 cur++;
1359 while (*cur == '0') {
1360 total++;
1361 cur++;
1362 }
1363 while ((*cur >= '0') && (*cur <= '9')) {
1364 base = base * 10 + (*cur - '0');
1365 total++;
1366 cur++;
1367 }
1368 if (*cur != 0)
1369 return(1);
1370 if ((sign == 1) && (total == 0))
1371 return(1);
1372 if (val != NULL) {
1373 v = xmlSchemaNewValue(XML_SCHEMAS_INTEGER);
1374 if (v != NULL) {
1375 v->value.decimal.base = base;
1376 v->value.decimal.sign = sign;
1377 v->value.decimal.frac = 0;
1378 v->value.decimal.total = total;
1379 *val = v;
1380 }
1381 }
1382 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001383 } else if ((type == xmlSchemaTypeFloatDef) ||
1384 (type == xmlSchemaTypeDoubleDef)) {
1385 const xmlChar *cur = value;
1386 int neg = 0;
1387 if (cur == NULL)
1388 return(1);
1389 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1390 cur += 3;
1391 if (*cur != 0)
1392 return(1);
1393 if (val != NULL) {
1394 if (type == xmlSchemaTypeFloatDef) {
1395 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1396 if (v != NULL) {
1397 v->value.f = (float) xmlXPathNAN;
1398 } else {
1399 xmlSchemaFreeValue(v);
1400 return(-1);
1401 }
1402 } else {
1403 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1404 if (v != NULL) {
1405 v->value.d = xmlXPathNAN;
1406 } else {
1407 xmlSchemaFreeValue(v);
1408 return(-1);
1409 }
1410 }
1411 *val = v;
1412 }
1413 return(0);
1414 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001415 if (*cur == '+')
1416 cur++;
1417 else if (*cur == '-') {
1418 neg = 1;
1419 cur++;
1420 }
Daniel Veillardd4310742003-02-18 21:12:46 +00001421 if (cur[0] == 0)
1422 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001423 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1424 cur += 3;
1425 if (*cur != 0)
1426 return(1);
1427 if (val != NULL) {
1428 if (type == xmlSchemaTypeFloatDef) {
1429 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1430 if (v != NULL) {
1431 if (neg)
1432 v->value.f = (float) xmlXPathNINF;
1433 else
1434 v->value.f = (float) xmlXPathPINF;
1435 } else {
1436 xmlSchemaFreeValue(v);
1437 return(-1);
1438 }
1439 } else {
1440 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1441 if (v != NULL) {
1442 if (neg)
1443 v->value.d = xmlXPathNINF;
1444 else
1445 v->value.d = xmlXPathPINF;
1446 } else {
1447 xmlSchemaFreeValue(v);
1448 return(-1);
1449 }
1450 }
1451 *val = v;
1452 }
1453 return(0);
1454 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001455 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001456 cur++;
1457 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001458 if (*cur == '.') {
1459 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001460 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001461 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001462 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001463 if ((*cur == 'e') || (*cur == 'E')) {
1464 cur++;
1465 if (*cur == '-')
1466 cur++;
1467 while ((*cur >= '0') && (*cur <= '9'))
1468 cur++;
1469 }
1470 if (*cur != 0)
1471 return(1);
1472 if (val != NULL) {
1473 if (type == xmlSchemaTypeFloatDef) {
1474 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1475 if (v != NULL) {
1476 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1477 *val = v;
1478 } else {
1479 xmlGenericError(xmlGenericErrorContext,
1480 "failed to scanf float %s\n", value);
1481 xmlSchemaFreeValue(v);
1482 return(1);
1483 }
1484 } else {
1485 return(-1);
1486 }
1487 } else {
1488 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1489 if (v != NULL) {
1490 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1491 *val = v;
1492 } else {
1493 xmlGenericError(xmlGenericErrorContext,
1494 "failed to scanf double %s\n", value);
1495 xmlSchemaFreeValue(v);
1496 return(1);
1497 }
1498 } else {
1499 return(-1);
1500 }
1501 }
1502 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001503 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001504 } else if (type == xmlSchemaTypeNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001505 ret = xmlValidateName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001506 if ((ret == 0) && (val != NULL)) {
1507 TODO;
1508 }
1509 return(ret);
1510 } else if (type == xmlSchemaTypeQNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001511 ret = xmlValidateQName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001512 if ((ret == 0) && (val != NULL)) {
1513 TODO;
1514 }
1515 return(ret);
1516 } else if (type == xmlSchemaTypeNCNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001517 ret = xmlValidateNCName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001518 if ((ret == 0) && (val != NULL)) {
1519 TODO;
1520 }
1521 return(ret);
1522 } else if (type == xmlSchemaTypeAnyURIDef) {
1523 xmlURIPtr uri;
1524
1525 uri = xmlParseURI((const char *) value);
1526 if (uri == NULL)
1527 return(1);
1528 if (val != NULL) {
1529 TODO;
1530 }
1531 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001532 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001533 } else if (type == xmlSchemaTypeBooleanDef) {
1534 const xmlChar *cur = value;
1535
1536 if ((cur[0] == '0') && (cur[1] == 0))
1537 ret = 0;
1538 else if ((cur[0] == '1') && (cur[1] == 0))
1539 ret = 1;
1540 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1541 (cur[3] == 'e') && (cur[4] == 0))
1542 ret = 1;
1543 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1544 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1545 ret = 0;
1546 else
1547 return(1);
1548 if (val != NULL) {
1549 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1550 if (v != NULL) {
1551 v->value.b = ret;
1552 *val = v;
1553 } else {
1554 return(-1);
1555 }
1556 }
1557 return(0);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001558 } else if (type == xmlSchemaTypeIdrefDef) {
1559 ret = xmlValidateNCName(value, 1);
1560 if ((ret == 0) && (val != NULL)) {
1561 TODO;
1562 }
1563 if ((ret == 0) && (node != NULL) &&
1564 (node->type == XML_ATTRIBUTE_NODE)) {
1565 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001566 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001567
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001568 strip = xmlSchemaStrip(value);
1569 if (strip != NULL) {
1570 xmlAddRef(NULL, node->doc, strip, attr);
1571 xmlFree(strip);
1572 } else
1573 xmlAddRef(NULL, node->doc, value, attr);
1574 attr->atype = XML_ATTRIBUTE_IDREF;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001575 }
1576 return(ret);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001577 } else if (type == xmlSchemaTypeIdrefsDef) {
1578 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1579 value, val, node);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001580 if (ret < 0)
1581 ret = 2;
1582 else
1583 ret = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001584 if ((ret == 0) && (node != NULL) &&
1585 (node->type == XML_ATTRIBUTE_NODE)) {
1586 xmlAttrPtr attr = (xmlAttrPtr) node;
1587
1588 attr->atype = XML_ATTRIBUTE_IDREFS;
1589 }
1590 return(ret);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001591 } else if (type == xmlSchemaTypeIdDef) {
1592 ret = xmlValidateNCName(value, 1);
1593 if ((ret == 0) && (val != NULL)) {
1594 TODO;
1595 }
1596 if ((ret == 0) && (node != NULL) &&
1597 (node->type == XML_ATTRIBUTE_NODE)) {
1598 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001599 /*
1600 * NOTE: the IDness might have already be declared in the DTD
1601 */
1602 if (attr->atype != XML_ATTRIBUTE_ID) {
1603 xmlIDPtr res;
1604 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001605
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001606 strip = xmlSchemaStrip(value);
1607 if (strip != NULL) {
1608 res = xmlAddID(NULL, node->doc, strip, attr);
1609 xmlFree(strip);
1610 } else
1611 res = xmlAddID(NULL, node->doc, value, attr);
1612 if (res == NULL) {
1613 ret = 2;
1614 } else {
1615 attr->atype = XML_ATTRIBUTE_ID;
1616 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001617 }
1618 }
1619 return(ret);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001620 } else if (type == xmlSchemaTypeEntitiesDef) {
1621 if ((node == NULL) || (node->doc == NULL))
1622 return(3);
1623 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1624 value, val, node);
1625 if (ret <= 0)
1626 ret = 1;
1627 else
1628 ret = 0;
1629 if ((ret == 0) && (node != NULL) &&
1630 (node->type == XML_ATTRIBUTE_NODE)) {
1631 xmlAttrPtr attr = (xmlAttrPtr) node;
1632
1633 attr->atype = XML_ATTRIBUTE_ENTITIES;
1634 }
1635 return(ret);
1636 } else if (type == xmlSchemaTypeEntityDef) {
1637 xmlChar *strip;
1638 ret = xmlValidateNCName(value, 1);
1639 if ((node == NULL) || (node->doc == NULL))
1640 ret = 3;
1641 if (ret == 0) {
1642 xmlEntityPtr ent;
1643
1644 strip = xmlSchemaStrip(value);
1645 if (strip != NULL) {
1646 ent = xmlGetDocEntity(node->doc, strip);
1647 xmlFree(strip);
1648 } else {
1649 ent = xmlGetDocEntity(node->doc, value);
1650 }
1651 if ((ent == NULL) ||
1652 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1653 ret = 4;
1654 }
1655 if ((ret == 0) && (val != NULL)) {
1656 TODO;
1657 }
1658 if ((ret == 0) && (node != NULL) &&
1659 (node->type == XML_ATTRIBUTE_NODE)) {
1660 xmlAttrPtr attr = (xmlAttrPtr) node;
1661
1662 attr->atype = XML_ATTRIBUTE_ENTITY;
1663 }
1664 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001665 }
Daniel Veillard09628212003-03-25 15:10:27 +00001666 TODO
1667 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001668}
1669
1670/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001671 * xmlSchemaValidatePredefinedType:
1672 * @type: the predefined type
1673 * @value: the value to check
1674 * @val: the return computed value
1675 *
1676 * Check that a value conforms to the lexical space of the predefined type.
1677 * if true a value is computed and returned in @val.
1678 *
1679 * Returns 0 if this validates, a positive error code number otherwise
1680 * and -1 in case of internal or API error.
1681 */
1682int
1683xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1684 xmlSchemaValPtr *val) {
1685 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
1686}
1687
1688/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001689 * xmlSchemaCompareDecimals:
1690 * @x: a first decimal value
1691 * @y: a second decimal value
1692 *
1693 * Compare 2 decimals
1694 *
1695 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1696 */
1697static int
1698xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1699{
1700 xmlSchemaValPtr swp;
1701 int order = 1;
1702 unsigned long tmp;
1703
1704 if ((x->value.decimal.sign) && (x->value.decimal.sign))
1705 order = -1;
1706 else if (x->value.decimal.sign)
1707 return (-1);
1708 else if (y->value.decimal.sign)
1709 return (1);
1710 if (x->value.decimal.frac == y->value.decimal.frac) {
1711 if (x->value.decimal.base < y->value.decimal.base)
1712 return (-1);
1713 return (x->value.decimal.base > y->value.decimal.base);
1714 }
1715 if (y->value.decimal.frac > x->value.decimal.frac) {
1716 swp = y;
1717 y = x;
1718 x = swp;
1719 order = -order;
1720 }
1721 tmp =
1722 x->value.decimal.base / powten[x->value.decimal.frac -
1723 y->value.decimal.frac];
1724 if (tmp > y->value.decimal.base)
1725 return (order);
1726 if (tmp < y->value.decimal.base)
1727 return (-order);
1728 tmp =
1729 y->value.decimal.base * powten[x->value.decimal.frac -
1730 y->value.decimal.frac];
1731 if (x->value.decimal.base < tmp)
1732 return (-order);
1733 if (x->value.decimal.base == tmp)
1734 return (0);
1735 return (order);
1736}
1737
1738/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001739 * xmlSchemaCompareDurations:
1740 * @x: a first duration value
1741 * @y: a second duration value
1742 *
1743 * Compare 2 durations
1744 *
1745 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1746 * case of error
1747 */
1748static int
1749xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1750{
1751 long carry, mon, day;
1752 double sec;
1753 long xmon, xday, myear, lyear, minday, maxday;
1754 static const long dayRange [2][12] = {
1755 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1756 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1757
1758 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001759 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001760
1761 /* months */
1762 mon = x->value.dur.mon - y->value.dur.mon;
1763
1764 /* seconds */
1765 sec = x->value.dur.sec - y->value.dur.sec;
1766 carry = (long)sec / SECS_PER_DAY;
1767 sec -= (double)(carry * SECS_PER_DAY);
1768
1769 /* days */
1770 day = x->value.dur.day - y->value.dur.day + carry;
1771
1772 /* easy test */
1773 if (mon == 0) {
1774 if (day == 0)
1775 if (sec == 0.0)
1776 return 0;
1777 else if (sec < 0.0)
1778 return -1;
1779 else
1780 return 1;
1781 else if (day < 0)
1782 return -1;
1783 else
1784 return 1;
1785 }
1786
1787 if (mon > 0) {
1788 if ((day >= 0) && (sec >= 0.0))
1789 return 1;
1790 else {
1791 xmon = mon;
1792 xday = -day;
1793 }
1794 } else if ((day <= 0) && (sec <= 0.0)) {
1795 return -1;
1796 } else {
1797 xmon = -mon;
1798 xday = day;
1799 }
1800
1801 myear = xmon / 12;
1802 lyear = myear / 4;
1803 minday = (myear * 365) + (lyear != 0 ? lyear - 1 : 0);
1804 maxday = (myear * 365) + (lyear != 0 ? lyear + 1 : 0);
1805
1806 xmon = xmon % 12;
1807 minday += dayRange[0][xmon];
1808 maxday += dayRange[1][xmon];
1809
1810 if (maxday < xday)
1811 return 1;
1812 else if (minday > xday)
1813 return -1;
1814
1815 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001816 return 2;
1817}
1818
1819/*
1820 * macros for adding date/times and durations
1821 */
1822#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1823#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1824#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1825#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1826
1827/**
1828 * _xmlSchemaDateAdd:
1829 * @dt: an #xmlSchemaValPtr
1830 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1831 *
1832 * Compute a new date/time from @dt and @dur. This function assumes @dt
1833 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1834 * or #XML_SCHEMAS_GYEAR.
1835 *
1836 * Returns date/time pointer or NULL.
1837 */
1838static xmlSchemaValPtr
1839_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1840{
1841 xmlSchemaValPtr ret;
1842 long carry, tempdays, temp;
1843 xmlSchemaValDatePtr r, d;
1844 xmlSchemaValDurationPtr u;
1845
1846 if ((dt == NULL) || (dur == NULL))
1847 return NULL;
1848
1849 ret = xmlSchemaNewValue(dt->type);
1850 if (ret == NULL)
1851 return NULL;
1852
1853 r = &(ret->value.date);
1854 d = &(dt->value.date);
1855 u = &(dur->value.dur);
1856
1857 /* normalization */
1858 if (d->mon == 0)
1859 d->mon = 1;
1860
1861 /* normalize for time zone offset */
1862 u->sec -= (d->tzo * 60);
1863 d->tzo = 0;
1864
1865 /* normalization */
1866 if (d->day == 0)
1867 d->day = 1;
1868
1869 /* month */
1870 carry = d->mon + u->mon;
1871 r->mon = MODULO_RANGE(carry, 1, 13);
1872 carry = FQUOTIENT_RANGE(carry, 1, 13);
1873
1874 /* year (may be modified later) */
1875 r->year = d->year + carry;
1876 if (r->year == 0) {
1877 if (d->year > 0)
1878 r->year--;
1879 else
1880 r->year++;
1881 }
1882
1883 /* time zone */
1884 r->tzo = d->tzo;
1885 r->tz_flag = d->tz_flag;
1886
1887 /* seconds */
1888 r->sec = d->sec + u->sec;
1889 carry = FQUOTIENT((long)r->sec, 60);
1890 if (r->sec != 0.0) {
1891 r->sec = MODULO(r->sec, 60.0);
1892 }
1893
1894 /* minute */
1895 carry += d->min;
1896 r->min = MODULO(carry, 60);
1897 carry = FQUOTIENT(carry, 60);
1898
1899 /* hours */
1900 carry += d->hour;
1901 r->hour = MODULO(carry, 24);
1902 carry = FQUOTIENT(carry, 24);
1903
1904 /*
1905 * days
1906 * Note we use tempdays because the temporary values may need more
1907 * than 5 bits
1908 */
1909 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1910 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1911 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1912 else if (d->day < 1)
1913 tempdays = 1;
1914 else
1915 tempdays = d->day;
1916
1917 tempdays += u->day + carry;
1918
1919 while (1) {
1920 if (tempdays < 1) {
1921 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1922 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1923 if (tyr == 0)
1924 tyr--;
1925 tempdays += MAX_DAYINMONTH(tyr, tmon);
1926 carry = -1;
1927 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1928 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1929 carry = 1;
1930 } else
1931 break;
1932
1933 temp = r->mon + carry;
1934 r->mon = MODULO_RANGE(temp, 1, 13);
1935 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1936 if (r->year == 0) {
1937 if (temp < 1)
1938 r->year--;
1939 else
1940 r->year++;
1941 }
1942 }
1943
1944 r->day = tempdays;
1945
1946 /*
1947 * adjust the date/time type to the date values
1948 */
1949 if (ret->type != XML_SCHEMAS_DATETIME) {
1950 if ((r->hour) || (r->min) || (r->sec))
1951 ret->type = XML_SCHEMAS_DATETIME;
1952 else if (ret->type != XML_SCHEMAS_DATE) {
1953 if ((r->mon != 1) && (r->day != 1))
1954 ret->type = XML_SCHEMAS_DATE;
1955 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
1956 ret->type = XML_SCHEMAS_GYEARMONTH;
1957 }
1958 }
1959
1960 return ret;
1961}
1962
1963/**
1964 * xmlSchemaDupVal:
1965 * @v: value to duplicate
1966 *
1967 * returns a duplicated value.
1968 */
1969static xmlSchemaValPtr
1970xmlSchemaDupVal (xmlSchemaValPtr v)
1971{
1972 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
1973 if (ret == NULL)
1974 return ret;
1975
1976 memcpy(ret, v, sizeof(xmlSchemaVal));
1977 return ret;
1978}
1979
1980/**
1981 * xmlSchemaDateNormalize:
1982 * @dt: an #xmlSchemaValPtr
1983 *
1984 * Normalize @dt to GMT time.
1985 *
1986 */
1987static xmlSchemaValPtr
1988xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
1989{
1990 xmlSchemaValPtr dur, ret;
1991
1992 if (dt == NULL)
1993 return NULL;
1994
1995 if (((dt->type != XML_SCHEMAS_TIME) &&
1996 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
1997 return xmlSchemaDupVal(dt);
1998
1999 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2000 if (dur == NULL)
2001 return NULL;
2002
2003 dur->value.date.sec -= offset;
2004
2005 ret = _xmlSchemaDateAdd(dt, dur);
2006 if (ret == NULL)
2007 return NULL;
2008
2009 xmlSchemaFreeValue(dur);
2010
2011 /* ret->value.date.tzo = 0; */
2012 return ret;
2013}
2014
2015/**
2016 * _xmlSchemaDateCastYMToDays:
2017 * @dt: an #xmlSchemaValPtr
2018 *
2019 * Convert mon and year of @dt to total number of days. Take the
2020 * number of years since (or before) 1 AD and add the number of leap
2021 * years. This is a function because negative
2022 * years must be handled a little differently and there is no zero year.
2023 *
2024 * Returns number of days.
2025 */
2026static long
2027_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2028{
2029 long ret;
2030
2031 if (dt->value.date.year < 0)
2032 ret = (dt->value.date.year * 365) +
2033 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2034 ((dt->value.date.year+1)/400)) +
2035 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2036 else
2037 ret = ((dt->value.date.year-1) * 365) +
2038 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2039 ((dt->value.date.year-1)/400)) +
2040 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2041
2042 return ret;
2043}
2044
2045/**
2046 * TIME_TO_NUMBER:
2047 * @dt: an #xmlSchemaValPtr
2048 *
2049 * Calculates the number of seconds in the time portion of @dt.
2050 *
2051 * Returns seconds.
2052 */
2053#define TIME_TO_NUMBER(dt) \
2054 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
2055 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
2056
2057/**
2058 * xmlSchemaCompareDates:
2059 * @x: a first date/time value
2060 * @y: a second date/time value
2061 *
2062 * Compare 2 date/times
2063 *
2064 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2065 * case of error
2066 */
2067static int
2068xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2069{
2070 unsigned char xmask, ymask, xor_mask, and_mask;
2071 xmlSchemaValPtr p1, p2, q1, q2;
2072 long p1d, p2d, q1d, q2d;
2073
2074 if ((x == NULL) || (y == NULL))
2075 return -2;
2076
2077 if (x->value.date.tz_flag) {
2078
2079 if (!y->value.date.tz_flag) {
2080 p1 = xmlSchemaDateNormalize(x, 0);
2081 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2082 /* normalize y + 14:00 */
2083 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2084
2085 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002086 if (p1d < q1d) {
2087 xmlSchemaFreeValue(p1);
2088 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002089 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002090 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002091 double sec;
2092
2093 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002094 if (sec < 0.0) {
2095 xmlSchemaFreeValue(p1);
2096 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002097 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002098 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002099 /* normalize y - 14:00 */
2100 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2101 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002102 xmlSchemaFreeValue(p1);
2103 xmlSchemaFreeValue(q1);
2104 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002105 if (p1d > q2d)
2106 return 1;
2107 else if (p1d == q2d) {
2108 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2109 if (sec > 0.0)
2110 return 1;
2111 else
2112 return 2; /* indeterminate */
2113 }
2114 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002115 } else {
2116 xmlSchemaFreeValue(p1);
2117 xmlSchemaFreeValue(q1);
2118 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002119 }
2120 } else if (y->value.date.tz_flag) {
2121 q1 = xmlSchemaDateNormalize(y, 0);
2122 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2123
2124 /* normalize x - 14:00 */
2125 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2126 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2127
Daniel Veillardfdc91562002-07-01 21:52:03 +00002128 if (p1d < q1d) {
2129 xmlSchemaFreeValue(p1);
2130 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002131 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002132 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002133 double sec;
2134
2135 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002136 if (sec < 0.0) {
2137 xmlSchemaFreeValue(p1);
2138 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002139 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002140 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002141 /* normalize x + 14:00 */
2142 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2143 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2144
Daniel Veillard6560a422003-03-27 21:25:38 +00002145 if (p2d > q1d) {
2146 xmlSchemaFreeValue(p1);
2147 xmlSchemaFreeValue(q1);
2148 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002149 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002150 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002151 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002152 xmlSchemaFreeValue(p1);
2153 xmlSchemaFreeValue(q1);
2154 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002155 if (sec > 0.0)
2156 return 1;
2157 else
2158 return 2; /* indeterminate */
2159 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002160 xmlSchemaFreeValue(p1);
2161 xmlSchemaFreeValue(q1);
2162 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002163 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002164 } else {
2165 xmlSchemaFreeValue(p1);
2166 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002167 }
2168 }
2169
2170 /*
2171 * if the same type then calculate the difference
2172 */
2173 if (x->type == y->type) {
2174 q1 = xmlSchemaDateNormalize(y, 0);
2175 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2176
2177 p1 = xmlSchemaDateNormalize(x, 0);
2178 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2179
Daniel Veillardfdc91562002-07-01 21:52:03 +00002180 if (p1d < q1d) {
2181 xmlSchemaFreeValue(p1);
2182 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002183 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002184 } else if (p1d > q1d) {
2185 xmlSchemaFreeValue(p1);
2186 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002187 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002188 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002189 double sec;
2190
2191 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002192 xmlSchemaFreeValue(p1);
2193 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002194 if (sec < 0.0)
2195 return -1;
2196 else if (sec > 0.0)
2197 return 1;
2198
2199 }
2200 return 0;
2201 }
2202
2203 switch (x->type) {
2204 case XML_SCHEMAS_DATETIME:
2205 xmask = 0xf;
2206 break;
2207 case XML_SCHEMAS_DATE:
2208 xmask = 0x7;
2209 break;
2210 case XML_SCHEMAS_GYEAR:
2211 xmask = 0x1;
2212 break;
2213 case XML_SCHEMAS_GMONTH:
2214 xmask = 0x2;
2215 break;
2216 case XML_SCHEMAS_GDAY:
2217 xmask = 0x3;
2218 break;
2219 case XML_SCHEMAS_GYEARMONTH:
2220 xmask = 0x3;
2221 break;
2222 case XML_SCHEMAS_GMONTHDAY:
2223 xmask = 0x6;
2224 break;
2225 case XML_SCHEMAS_TIME:
2226 xmask = 0x8;
2227 break;
2228 default:
2229 xmask = 0;
2230 break;
2231 }
2232
2233 switch (y->type) {
2234 case XML_SCHEMAS_DATETIME:
2235 ymask = 0xf;
2236 break;
2237 case XML_SCHEMAS_DATE:
2238 ymask = 0x7;
2239 break;
2240 case XML_SCHEMAS_GYEAR:
2241 ymask = 0x1;
2242 break;
2243 case XML_SCHEMAS_GMONTH:
2244 ymask = 0x2;
2245 break;
2246 case XML_SCHEMAS_GDAY:
2247 ymask = 0x3;
2248 break;
2249 case XML_SCHEMAS_GYEARMONTH:
2250 ymask = 0x3;
2251 break;
2252 case XML_SCHEMAS_GMONTHDAY:
2253 ymask = 0x6;
2254 break;
2255 case XML_SCHEMAS_TIME:
2256 ymask = 0x8;
2257 break;
2258 default:
2259 ymask = 0;
2260 break;
2261 }
2262
2263 xor_mask = xmask ^ ymask; /* mark type differences */
2264 and_mask = xmask & ymask; /* mark field specification */
2265
2266 /* year */
2267 if (xor_mask & 1)
2268 return 2; /* indeterminate */
2269 else if (and_mask & 1) {
2270 if (x->value.date.year < y->value.date.year)
2271 return -1;
2272 else if (x->value.date.year > y->value.date.year)
2273 return 1;
2274 }
2275
2276 /* month */
2277 if (xor_mask & 2)
2278 return 2; /* indeterminate */
2279 else if (and_mask & 2) {
2280 if (x->value.date.mon < y->value.date.mon)
2281 return -1;
2282 else if (x->value.date.mon > y->value.date.mon)
2283 return 1;
2284 }
2285
2286 /* day */
2287 if (xor_mask & 4)
2288 return 2; /* indeterminate */
2289 else if (and_mask & 4) {
2290 if (x->value.date.day < y->value.date.day)
2291 return -1;
2292 else if (x->value.date.day > y->value.date.day)
2293 return 1;
2294 }
2295
2296 /* time */
2297 if (xor_mask & 8)
2298 return 2; /* indeterminate */
2299 else if (and_mask & 8) {
2300 if (x->value.date.hour < y->value.date.hour)
2301 return -1;
2302 else if (x->value.date.hour > y->value.date.hour)
2303 return 1;
2304 else if (x->value.date.min < y->value.date.min)
2305 return -1;
2306 else if (x->value.date.min > y->value.date.min)
2307 return 1;
2308 else if (x->value.date.sec < y->value.date.sec)
2309 return -1;
2310 else if (x->value.date.sec > y->value.date.sec)
2311 return 1;
2312 }
2313
Daniel Veillard070803b2002-05-03 07:29:38 +00002314 return 0;
2315}
2316
2317/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002318 * xmlSchemaCompareValues:
2319 * @x: a first value
2320 * @y: a second value
2321 *
2322 * Compare 2 values
2323 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002324 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2325 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002326 */
Daniel Veillarde19fc232002-04-22 16:01:24 +00002327static int
Daniel Veillard4255d502002-04-16 15:50:10 +00002328xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2329 if ((x == NULL) || (y == NULL))
2330 return(-2);
2331
2332 switch (x->type) {
2333 case XML_SCHEMAS_STRING:
2334 TODO
2335 case XML_SCHEMAS_DECIMAL:
2336 if (y->type == XML_SCHEMAS_DECIMAL)
2337 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002338 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002339 case XML_SCHEMAS_DURATION:
2340 if (y->type == XML_SCHEMAS_DURATION)
2341 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002342 return(-2);
2343 case XML_SCHEMAS_TIME:
2344 case XML_SCHEMAS_GDAY:
2345 case XML_SCHEMAS_GMONTH:
2346 case XML_SCHEMAS_GMONTHDAY:
2347 case XML_SCHEMAS_GYEAR:
2348 case XML_SCHEMAS_GYEARMONTH:
2349 case XML_SCHEMAS_DATE:
2350 case XML_SCHEMAS_DATETIME:
2351 if ((y->type == XML_SCHEMAS_DATETIME) ||
2352 (y->type == XML_SCHEMAS_TIME) ||
2353 (y->type == XML_SCHEMAS_GDAY) ||
2354 (y->type == XML_SCHEMAS_GMONTH) ||
2355 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2356 (y->type == XML_SCHEMAS_GYEAR) ||
2357 (y->type == XML_SCHEMAS_DATE) ||
2358 (y->type == XML_SCHEMAS_GYEARMONTH))
2359 return (xmlSchemaCompareDates(x, y));
2360
2361 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002362 default:
2363 TODO
2364 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002365 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002366}
2367
2368/**
2369 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002370 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002371 * @facet: the facet to check
2372 * @value: the lexical repr of the value to validate
2373 * @val: the precomputed value
2374 *
2375 * Check a value against a facet condition
2376 *
2377 * Returns 0 if the element is schemas valid, a positive error code
2378 * number otherwise and -1 in case of internal or API error.
2379 */
2380int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002381xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002382 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002383 const xmlChar *value, xmlSchemaValPtr val)
2384{
2385 int ret;
2386
2387 switch (facet->type) {
2388 case XML_SCHEMA_FACET_PATTERN:
2389 ret = xmlRegexpExec(facet->regexp, value);
2390 if (ret == 1)
2391 return(0);
2392 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002393 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002394 return(1);
2395 }
2396 return(ret);
2397 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2398 ret = xmlSchemaCompareValues(val, facet->val);
2399 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002400 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002401 return(-1);
2402 }
2403 if (ret == -1)
2404 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002405 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002406 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002407 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2408 ret = xmlSchemaCompareValues(val, facet->val);
2409 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002410 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002411 return(-1);
2412 }
2413 if ((ret == -1) || (ret == 0))
2414 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002415 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002416 return(1);
2417 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2418 ret = xmlSchemaCompareValues(val, facet->val);
2419 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002420 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002421 return(-1);
2422 }
2423 if (ret == 1)
2424 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002425 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002426 return(1);
2427 case XML_SCHEMA_FACET_MININCLUSIVE:
2428 ret = xmlSchemaCompareValues(val, facet->val);
2429 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002430 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002431 return(-1);
2432 }
2433 if ((ret == 1) || (ret == 0))
2434 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002435 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002436 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002437 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002438 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00002439 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00002440 case XML_SCHEMA_FACET_ENUMERATION:
2441 if ((facet->value != NULL) &&
2442 (xmlStrEqual(facet->value, value)))
2443 return(0);
2444 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002445 case XML_SCHEMA_FACET_LENGTH:
2446 case XML_SCHEMA_FACET_MAXLENGTH:
2447 case XML_SCHEMA_FACET_MINLENGTH: {
2448 unsigned int len = 0;
2449
2450 if ((facet->val == NULL) ||
2451 (facet->val->type != XML_SCHEMAS_DECIMAL) ||
2452 (facet->val->value.decimal.frac != 0)) {
2453 return(-1);
2454 }
2455 switch (base->flags) {
2456 case XML_SCHEMAS_STRING:
2457 case XML_SCHEMAS_NORMSTRING:
2458 case XML_SCHEMAS_TOKEN:
2459 case XML_SCHEMAS_LANGUAGE:
2460 case XML_SCHEMAS_NMTOKEN:
2461 case XML_SCHEMAS_NAME:
2462 case XML_SCHEMAS_NCNAME:
2463 case XML_SCHEMAS_ID:
2464 case XML_SCHEMAS_IDREF: {
2465 len = xmlUTF8Strlen(value);
2466 break;
2467 }
2468 default:
2469 TODO
2470 }
2471 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
2472 if (len != facet->val->value.decimal.base)
2473 return(1);
2474 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
2475 if (len < facet->val->value.decimal.base)
2476 return(1);
2477 } else {
2478 if (len > facet->val->value.decimal.base)
2479 return(1);
2480 }
2481 break;
2482 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002483 default:
2484 TODO
2485 }
2486 return(0);
2487}
2488
2489#endif /* LIBXML_SCHEMAS_ENABLED */