blob: 925eb226180f68fb78895dff7a9a89065c590dc7 [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 Veillardc4c21552003-03-29 10:53:38 +0000136 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000137 } value;
138};
139
140static int xmlSchemaTypesInitialized = 0;
141static xmlHashTablePtr xmlSchemaTypesBank = NULL;
142
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000143/*
144 * Basic types
145 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000146static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
149static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000150static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000151static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000152static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
153static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
154static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
155static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
156static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
157static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
158static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000159static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000160static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000161static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000162static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000163
164/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000165 * Derived types
166 */
167static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
170static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
173static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
179static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000180static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
182static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
184static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000185static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000186static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
187static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
188static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000189static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
190static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000191static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
192static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000193
194/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000195 * xmlSchemaInitBasicType:
196 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000197 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000198 *
199 * Initialize one default type
200 */
201static xmlSchemaTypePtr
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000202xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000203 xmlSchemaTypePtr ret;
204
205 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
206 if (ret == NULL) {
207 xmlGenericError(xmlGenericErrorContext,
208 "Could not initilize type %s: out of memory\n", name);
209 return(NULL);
210 }
211 memset(ret, 0, sizeof(xmlSchemaType));
212 ret->name = xmlStrdup((const xmlChar *)name);
213 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000214 ret->flags = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000215 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
216 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
217 XML_SCHEMAS_NAMESPACE_NAME, ret);
218 return(ret);
219}
220
221/*
222 * xmlSchemaInitTypes:
223 *
224 * Initialize the default XML Schemas type library
225 */
226void
Daniel Veillard6560a422003-03-27 21:25:38 +0000227xmlSchemaInitTypes(void)
228{
Daniel Veillard4255d502002-04-16 15:50:10 +0000229 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000230 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000231 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000232
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000233 /*
234 * primitive datatypes
235 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000236 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
Daniel Veillard6560a422003-03-27 21:25:38 +0000237 XML_SCHEMAS_STRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000238 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000239 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000240 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000241 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000242 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard6560a422003-03-27 21:25:38 +0000243 XML_SCHEMAS_DECIMAL);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000244 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard6560a422003-03-27 21:25:38 +0000245 XML_SCHEMAS_DATE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000246 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard6560a422003-03-27 21:25:38 +0000247 XML_SCHEMAS_DATETIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000248 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard6560a422003-03-27 21:25:38 +0000249 XML_SCHEMAS_TIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000250 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard6560a422003-03-27 21:25:38 +0000251 XML_SCHEMAS_GYEAR);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000252 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000253 XML_SCHEMAS_GYEARMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000254 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000255 XML_SCHEMAS_GMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000256 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000257 XML_SCHEMAS_GMONTHDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000258 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000259 XML_SCHEMAS_GDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000260 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard6560a422003-03-27 21:25:38 +0000261 XML_SCHEMAS_DURATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000262 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard6560a422003-03-27 21:25:38 +0000263 XML_SCHEMAS_FLOAT);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000264 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard6560a422003-03-27 21:25:38 +0000265 XML_SCHEMAS_DOUBLE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000266 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard6560a422003-03-27 21:25:38 +0000267 XML_SCHEMAS_BOOLEAN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000268 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard6560a422003-03-27 21:25:38 +0000269 XML_SCHEMAS_ANYURI);
Daniel Veillard4255d502002-04-16 15:50:10 +0000270
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000271 /*
272 * derived datatypes
273 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000274 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard6560a422003-03-27 21:25:38 +0000275 XML_SCHEMAS_INTEGER);;
276 xmlSchemaTypeNonPositiveIntegerDef =
277 xmlSchemaInitBasicType("nonPositiveInteger",
278 XML_SCHEMAS_NPINTEGER);;
279 xmlSchemaTypeNegativeIntegerDef =
280 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
281 xmlSchemaTypeLongDef =
282 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
283 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000284 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard6560a422003-03-27 21:25:38 +0000285 XML_SCHEMAS_SHORT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000286 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard6560a422003-03-27 21:25:38 +0000287 XML_SCHEMAS_BYTE);;
288 xmlSchemaTypeNonNegativeIntegerDef =
289 xmlSchemaInitBasicType("nonNegativeInteger",
290 XML_SCHEMAS_NNINTEGER);
291 xmlSchemaTypeUnsignedLongDef =
292 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
293 xmlSchemaTypeUnsignedIntDef =
294 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
295 xmlSchemaTypeUnsignedShortDef =
296 xmlSchemaInitBasicType("insignedShort", XML_SCHEMAS_USHORT);;
297 xmlSchemaTypeUnsignedByteDef =
298 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
299 xmlSchemaTypePositiveIntegerDef =
300 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000301
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000302 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard6560a422003-03-27 21:25:38 +0000303 XML_SCHEMAS_NORMSTRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000304 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard6560a422003-03-27 21:25:38 +0000305 XML_SCHEMAS_TOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000306 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard6560a422003-03-27 21:25:38 +0000307 XML_SCHEMAS_LANGUAGE);
308 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000309 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
Daniel Veillard6560a422003-03-27 21:25:38 +0000310 XML_SCHEMAS_IDREF);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000311 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000312 XML_SCHEMAS_IDREFS);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000313 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
Daniel Veillard6560a422003-03-27 21:25:38 +0000314 XML_SCHEMAS_ENTITY);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000315 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
Daniel Veillard6560a422003-03-27 21:25:38 +0000316 XML_SCHEMAS_ENTITIES);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000317 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard6560a422003-03-27 21:25:38 +0000318 XML_SCHEMAS_NAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000319 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000320 XML_SCHEMAS_QNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000321 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000322 XML_SCHEMAS_NCNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000323 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard6560a422003-03-27 21:25:38 +0000324 XML_SCHEMAS_NMTOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000325 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000326 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000327 xmlSchemaTypesInitialized = 1;
328}
329
330/**
331 * xmlSchemaCleanupTypes:
332 *
333 * Cleanup the default XML Schemas type library
334 */
335void
336xmlSchemaCleanupTypes(void) {
337 if (xmlSchemaTypesInitialized == 0)
338 return;
339 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
340 xmlSchemaTypesInitialized = 0;
341}
342
343/**
344 * xmlSchemaNewValue:
345 * @type: the value type
346 *
347 * Allocate a new simple type value
348 *
349 * Returns a pointer to the new value or NULL in case of error
350 */
351static xmlSchemaValPtr
352xmlSchemaNewValue(xmlSchemaValType type) {
353 xmlSchemaValPtr value;
354
355 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
356 if (value == NULL) {
357 return(NULL);
358 }
359 memset(value, 0, sizeof(xmlSchemaVal));
360 value->type = type;
361 return(value);
362}
363
364/**
365 * xmlSchemaFreeValue:
366 * @value: the value to free
367 *
368 * Cleanup the default XML Schemas type library
369 */
370void
371xmlSchemaFreeValue(xmlSchemaValPtr value) {
372 if (value == NULL)
373 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000374 switch (value->type) {
375 case XML_SCHEMAS_STRING:
376 case XML_SCHEMAS_NORMSTRING:
377 case XML_SCHEMAS_TOKEN:
378 case XML_SCHEMAS_LANGUAGE:
379 case XML_SCHEMAS_NMTOKEN:
380 case XML_SCHEMAS_NMTOKENS:
381 case XML_SCHEMAS_NAME:
382 case XML_SCHEMAS_QNAME:
383 case XML_SCHEMAS_NCNAME:
384 case XML_SCHEMAS_ID:
385 case XML_SCHEMAS_IDREF:
386 case XML_SCHEMAS_IDREFS:
387 case XML_SCHEMAS_ENTITY:
388 case XML_SCHEMAS_ENTITIES:
389 case XML_SCHEMAS_NOTATION:
390 case XML_SCHEMAS_ANYURI:
391 if (value->value.str != NULL)
392 xmlFree(value->value.str);
393 break;
394 default:
395 break;
396 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000397 xmlFree(value);
398}
399
400/**
401 * xmlSchemaGetPredefinedType:
402 * @name: the type name
403 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
404 *
405 * Lookup a type in the default XML Schemas type library
406 *
407 * Returns the type if found, NULL otherwise
408 */
409xmlSchemaTypePtr
410xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
411 if (xmlSchemaTypesInitialized == 0)
412 xmlSchemaInitTypes();
413 if (name == NULL)
414 return(NULL);
415 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
416}
Daniel Veillard070803b2002-05-03 07:29:38 +0000417
418/****************************************************************
419 * *
420 * Convenience macros and functions *
421 * *
422 ****************************************************************/
423
424#define IS_TZO_CHAR(c) \
425 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
426
427#define VALID_YEAR(yr) (yr != 0)
428#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
429/* VALID_DAY should only be used when month is unknown */
430#define VALID_DAY(day) ((day >= 1) && (day <= 31))
431#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
432#define VALID_MIN(min) ((min >= 0) && (min <= 59))
433#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
434#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
435#define IS_LEAP(y) \
436 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
437
438static const long daysInMonth[12] =
439 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
440static const long daysInMonthLeap[12] =
441 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
442
Daniel Veillard5a872412002-05-22 06:40:27 +0000443#define MAX_DAYINMONTH(yr,mon) \
444 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
445
Daniel Veillard070803b2002-05-03 07:29:38 +0000446#define VALID_MDAY(dt) \
447 (IS_LEAP(dt->year) ? \
448 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
449 (dt->day <= daysInMonth[dt->mon - 1]))
450
451#define VALID_DATE(dt) \
452 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
453
454#define VALID_TIME(dt) \
455 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
456 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
457
458#define VALID_DATETIME(dt) \
459 (VALID_DATE(dt) && VALID_TIME(dt))
460
461#define SECS_PER_MIN (60)
462#define SECS_PER_HOUR (60 * SECS_PER_MIN)
463#define SECS_PER_DAY (24 * SECS_PER_HOUR)
464
Daniel Veillard5a872412002-05-22 06:40:27 +0000465static const long dayInYearByMonth[12] =
466 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
467static const long dayInLeapYearByMonth[12] =
468 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
469
470#define DAY_IN_YEAR(day, month, year) \
471 ((IS_LEAP(year) ? \
472 dayInLeapYearByMonth[month - 1] : \
473 dayInYearByMonth[month - 1]) + day)
474
475#ifdef DEBUG
476#define DEBUG_DATE(dt) \
477 xmlGenericError(xmlGenericErrorContext, \
478 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
479 dt->type,dt->value.date.year,dt->value.date.mon, \
480 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
481 dt->value.date.sec); \
482 if (dt->value.date.tz_flag) \
483 if (dt->value.date.tzo != 0) \
484 xmlGenericError(xmlGenericErrorContext, \
485 "%+05d\n",dt->value.date.tzo); \
486 else \
487 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
488 else \
489 xmlGenericError(xmlGenericErrorContext,"\n")
490#else
491#define DEBUG_DATE(dt)
492#endif
493
Daniel Veillard070803b2002-05-03 07:29:38 +0000494/**
495 * _xmlSchemaParseGYear:
496 * @dt: pointer to a date structure
497 * @str: pointer to the string to analyze
498 *
499 * Parses a xs:gYear without time zone and fills in the appropriate
500 * field of the @dt structure. @str is updated to point just after the
501 * xs:gYear. It is supposed that @dt->year is big enough to contain
502 * the year.
503 *
504 * Returns 0 or the error code
505 */
506static int
507_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
508 const xmlChar *cur = *str, *firstChar;
509 int isneg = 0, digcnt = 0;
510
511 if (((*cur < '0') || (*cur > '9')) &&
512 (*cur != '-') && (*cur != '+'))
513 return -1;
514
515 if (*cur == '-') {
516 isneg = 1;
517 cur++;
518 }
519
520 firstChar = cur;
521
522 while ((*cur >= '0') && (*cur <= '9')) {
523 dt->year = dt->year * 10 + (*cur - '0');
524 cur++;
525 digcnt++;
526 }
527
528 /* year must be at least 4 digits (CCYY); over 4
529 * digits cannot have a leading zero. */
530 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
531 return 1;
532
533 if (isneg)
534 dt->year = - dt->year;
535
536 if (!VALID_YEAR(dt->year))
537 return 2;
538
539 *str = cur;
540 return 0;
541}
542
543/**
544 * PARSE_2_DIGITS:
545 * @num: the integer to fill in
546 * @cur: an #xmlChar *
547 * @invalid: an integer
548 *
549 * Parses a 2-digits integer and updates @num with the value. @cur is
550 * updated to point just after the integer.
551 * In case of error, @invalid is set to %TRUE, values of @num and
552 * @cur are undefined.
553 */
554#define PARSE_2_DIGITS(num, cur, invalid) \
555 if ((cur[0] < '0') || (cur[0] > '9') || \
556 (cur[1] < '0') || (cur[1] > '9')) \
557 invalid = 1; \
558 else \
559 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
560 cur += 2;
561
562/**
563 * PARSE_FLOAT:
564 * @num: the double to fill in
565 * @cur: an #xmlChar *
566 * @invalid: an integer
567 *
568 * Parses a float and updates @num with the value. @cur is
569 * updated to point just after the float. The float must have a
570 * 2-digits integer part and may or may not have a decimal part.
571 * In case of error, @invalid is set to %TRUE, values of @num and
572 * @cur are undefined.
573 */
574#define PARSE_FLOAT(num, cur, invalid) \
575 PARSE_2_DIGITS(num, cur, invalid); \
576 if (!invalid && (*cur == '.')) { \
577 double mult = 1; \
578 cur++; \
579 if ((*cur < '0') || (*cur > '9')) \
580 invalid = 1; \
581 while ((*cur >= '0') && (*cur <= '9')) { \
582 mult /= 10; \
583 num += (*cur - '0') * mult; \
584 cur++; \
585 } \
586 }
587
588/**
589 * _xmlSchemaParseGMonth:
590 * @dt: pointer to a date structure
591 * @str: pointer to the string to analyze
592 *
593 * Parses a xs:gMonth without time zone and fills in the appropriate
594 * field of the @dt structure. @str is updated to point just after the
595 * xs:gMonth.
596 *
597 * Returns 0 or the error code
598 */
599static int
600_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
601 const xmlChar *cur = *str;
602 int ret = 0;
603
604 PARSE_2_DIGITS(dt->mon, cur, ret);
605 if (ret != 0)
606 return ret;
607
608 if (!VALID_MONTH(dt->mon))
609 return 2;
610
611 *str = cur;
612 return 0;
613}
614
615/**
616 * _xmlSchemaParseGDay:
617 * @dt: pointer to a date structure
618 * @str: pointer to the string to analyze
619 *
620 * Parses a xs:gDay without time zone and fills in the appropriate
621 * field of the @dt structure. @str is updated to point just after the
622 * xs:gDay.
623 *
624 * Returns 0 or the error code
625 */
626static int
627_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
628 const xmlChar *cur = *str;
629 int ret = 0;
630
631 PARSE_2_DIGITS(dt->day, cur, ret);
632 if (ret != 0)
633 return ret;
634
635 if (!VALID_DAY(dt->day))
636 return 2;
637
638 *str = cur;
639 return 0;
640}
641
642/**
643 * _xmlSchemaParseTime:
644 * @dt: pointer to a date structure
645 * @str: pointer to the string to analyze
646 *
647 * Parses a xs:time without time zone and fills in the appropriate
648 * fields of the @dt structure. @str is updated to point just after the
649 * xs:time.
650 * In case of error, values of @dt fields are undefined.
651 *
652 * Returns 0 or the error code
653 */
654static int
655_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
656 const xmlChar *cur = *str;
657 unsigned int hour = 0; /* use temp var in case str is not xs:time */
658 int ret = 0;
659
660 PARSE_2_DIGITS(hour, cur, ret);
661 if (ret != 0)
662 return ret;
663
664 if (*cur != ':')
665 return 1;
666 cur++;
667
668 /* the ':' insures this string is xs:time */
669 dt->hour = hour;
670
671 PARSE_2_DIGITS(dt->min, cur, ret);
672 if (ret != 0)
673 return ret;
674
675 if (*cur != ':')
676 return 1;
677 cur++;
678
679 PARSE_FLOAT(dt->sec, cur, ret);
680 if (ret != 0)
681 return ret;
682
683 if (!VALID_TIME(dt))
684 return 2;
685
686 *str = cur;
687 return 0;
688}
689
690/**
691 * _xmlSchemaParseTimeZone:
692 * @dt: pointer to a date structure
693 * @str: pointer to the string to analyze
694 *
695 * Parses a time zone without time zone and fills in the appropriate
696 * field of the @dt structure. @str is updated to point just after the
697 * time zone.
698 *
699 * Returns 0 or the error code
700 */
701static int
702_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
703 const xmlChar *cur = *str;
704 int ret = 0;
705
706 if (str == NULL)
707 return -1;
708
709 switch (*cur) {
710 case 0:
711 dt->tz_flag = 0;
712 dt->tzo = 0;
713 break;
714
715 case 'Z':
716 dt->tz_flag = 1;
717 dt->tzo = 0;
718 cur++;
719 break;
720
721 case '+':
722 case '-': {
723 int isneg = 0, tmp = 0;
724 isneg = (*cur == '-');
725
726 cur++;
727
728 PARSE_2_DIGITS(tmp, cur, ret);
729 if (ret != 0)
730 return ret;
731 if (!VALID_HOUR(tmp))
732 return 2;
733
734 if (*cur != ':')
735 return 1;
736 cur++;
737
738 dt->tzo = tmp * 60;
739
740 PARSE_2_DIGITS(tmp, cur, ret);
741 if (ret != 0)
742 return ret;
743 if (!VALID_MIN(tmp))
744 return 2;
745
746 dt->tzo += tmp;
747 if (isneg)
748 dt->tzo = - dt->tzo;
749
750 if (!VALID_TZO(dt->tzo))
751 return 2;
752
Daniel Veillard5a872412002-05-22 06:40:27 +0000753 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000754 break;
755 }
756 default:
757 return 1;
758 }
759
760 *str = cur;
761 return 0;
762}
763
764/****************************************************************
765 * *
766 * XML Schema Dates/Times Datatypes Handling *
767 * *
768 ****************************************************************/
769
770/**
771 * PARSE_DIGITS:
772 * @num: the integer to fill in
773 * @cur: an #xmlChar *
774 * @num_type: an integer flag
775 *
776 * Parses a digits integer and updates @num with the value. @cur is
777 * updated to point just after the integer.
778 * In case of error, @num_type is set to -1, values of @num and
779 * @cur are undefined.
780 */
781#define PARSE_DIGITS(num, cur, num_type) \
782 if ((*cur < '0') || (*cur > '9')) \
783 num_type = -1; \
784 else \
785 while ((*cur >= '0') && (*cur <= '9')) { \
786 num = num * 10 + (*cur - '0'); \
787 cur++; \
788 }
789
790/**
791 * PARSE_NUM:
792 * @num: the double to fill in
793 * @cur: an #xmlChar *
794 * @num_type: an integer flag
795 *
796 * Parses a float or integer and updates @num with the value. @cur is
797 * updated to point just after the number. If the number is a float,
798 * then it must have an integer part and a decimal part; @num_type will
799 * be set to 1. If there is no decimal part, @num_type is set to zero.
800 * In case of error, @num_type is set to -1, values of @num and
801 * @cur are undefined.
802 */
803#define PARSE_NUM(num, cur, num_type) \
804 num = 0; \
805 PARSE_DIGITS(num, cur, num_type); \
806 if (!num_type && (*cur == '.')) { \
807 double mult = 1; \
808 cur++; \
809 if ((*cur < '0') || (*cur > '9')) \
810 num_type = -1; \
811 else \
812 num_type = 1; \
813 while ((*cur >= '0') && (*cur <= '9')) { \
814 mult /= 10; \
815 num += (*cur - '0') * mult; \
816 cur++; \
817 } \
818 }
819
820/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000821 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000822 * @type: the predefined type
823 * @dateTime: string to analyze
824 * @val: the return computed value
825 *
826 * Check that @dateTime conforms to the lexical space of one of the date types.
827 * if true a value is computed and returned in @val.
828 *
829 * Returns 0 if this validates, a positive error code number otherwise
830 * and -1 in case of internal or API error.
831 */
832static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000833xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000834 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000835 xmlSchemaValPtr dt;
836 int ret;
837 const xmlChar *cur = dateTime;
838
839#define RETURN_TYPE_IF_VALID(t) \
840 if (IS_TZO_CHAR(*cur)) { \
841 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
842 if (ret == 0) { \
843 if (*cur != 0) \
844 goto error; \
845 dt->type = t; \
846 if (val != NULL) \
847 *val = dt; \
Daniel Veillard80b19092003-03-28 13:29:53 +0000848 else \
849 xmlSchemaFreeValue(dt); \
Daniel Veillard070803b2002-05-03 07:29:38 +0000850 return 0; \
851 } \
852 }
853
854 if (dateTime == NULL)
855 return -1;
856
857 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
858 return 1;
859
860 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
861 if (dt == NULL)
862 return -1;
863
864 if ((cur[0] == '-') && (cur[1] == '-')) {
865 /*
866 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
867 * xs:gDay)
868 */
869 cur += 2;
870
871 /* is it an xs:gDay? */
872 if (*cur == '-') {
873 ++cur;
874 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
875 if (ret != 0)
876 goto error;
877
878 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
879
880 goto error;
881 }
882
883 /*
884 * it should be an xs:gMonthDay or xs:gMonth
885 */
886 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
887 if (ret != 0)
888 goto error;
889
890 if (*cur != '-')
891 goto error;
892 cur++;
893
894 /* is it an xs:gMonth? */
895 if (*cur == '-') {
896 cur++;
897 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
898 goto error;
899 }
900
901 /* it should be an xs:gMonthDay */
902 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
903 if (ret != 0)
904 goto error;
905
906 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
907
908 goto error;
909 }
910
911 /*
912 * It's a right-truncated date or an xs:time.
913 * Try to parse an xs:time then fallback on right-truncated dates.
914 */
915 if ((*cur >= '0') && (*cur <= '9')) {
916 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
917 if (ret == 0) {
918 /* it's an xs:time */
919 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
920 }
921 }
922
923 /* fallback on date parsing */
924 cur = dateTime;
925
926 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
927 if (ret != 0)
928 goto error;
929
930 /* is it an xs:gYear? */
931 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
932
933 if (*cur != '-')
934 goto error;
935 cur++;
936
937 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
938 if (ret != 0)
939 goto error;
940
941 /* is it an xs:gYearMonth? */
942 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
943
944 if (*cur != '-')
945 goto error;
946 cur++;
947
948 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
949 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
950 goto error;
951
952 /* is it an xs:date? */
953 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
954
955 if (*cur != 'T')
956 goto error;
957 cur++;
958
959 /* it should be an xs:dateTime */
960 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
961 if (ret != 0)
962 goto error;
963
964 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
965 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
966 goto error;
967
968 dt->type = XML_SCHEMAS_DATETIME;
969
970 if (val != NULL)
971 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +0000972 else
973 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +0000974
975 return 0;
976
977error:
978 if (dt != NULL)
979 xmlSchemaFreeValue(dt);
980 return 1;
981}
982
983/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000984 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000985 * @type: the predefined type
986 * @duration: string to analyze
987 * @val: the return computed value
988 *
989 * Check that @duration conforms to the lexical space of the duration type.
990 * if true a value is computed and returned in @val.
991 *
992 * Returns 0 if this validates, a positive error code number otherwise
993 * and -1 in case of internal or API error.
994 */
995static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000996xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000997 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000998 const xmlChar *cur = duration;
999 xmlSchemaValPtr dur;
1000 int isneg = 0;
1001 unsigned int seq = 0;
1002
1003 if (duration == NULL)
1004 return -1;
1005
1006 if (*cur == '-') {
1007 isneg = 1;
1008 cur++;
1009 }
1010
1011 /* duration must start with 'P' (after sign) */
1012 if (*cur++ != 'P')
1013 return 1;
1014
Daniel Veillard80b19092003-03-28 13:29:53 +00001015 if (*cur == 0)
1016 return 1;
1017
Daniel Veillard070803b2002-05-03 07:29:38 +00001018 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1019 if (dur == NULL)
1020 return -1;
1021
1022 while (*cur != 0) {
1023 double num;
1024 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1025 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1026 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
1027
1028 /* input string should be empty or invalid date/time item */
1029 if (seq >= sizeof(desig))
1030 goto error;
1031
1032 /* T designator must be present for time items */
1033 if (*cur == 'T') {
1034 if (seq <= 3) {
1035 seq = 3;
1036 cur++;
1037 } else
1038 return 1;
1039 } else if (seq == 3)
1040 goto error;
1041
1042 /* parse the number portion of the item */
1043 PARSE_NUM(num, cur, num_type);
1044
1045 if ((num_type == -1) || (*cur == 0))
1046 goto error;
1047
1048 /* update duration based on item type */
1049 while (seq < sizeof(desig)) {
1050 if (*cur == desig[seq]) {
1051
1052 /* verify numeric type; only seconds can be float */
1053 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1054 goto error;
1055
1056 switch (seq) {
1057 case 0:
1058 dur->value.dur.mon = (long)num * 12;
1059 break;
1060 case 1:
1061 dur->value.dur.mon += (long)num;
1062 break;
1063 default:
1064 /* convert to seconds using multiplier */
1065 dur->value.dur.sec += num * multi[seq];
1066 seq++;
1067 break;
1068 }
1069
1070 break; /* exit loop */
1071 }
1072 /* no date designators found? */
1073 if (++seq == 3)
1074 goto error;
1075 }
1076 cur++;
1077 }
1078
1079 if (isneg) {
1080 dur->value.dur.mon = -dur->value.dur.mon;
1081 dur->value.dur.day = -dur->value.dur.day;
1082 dur->value.dur.sec = -dur->value.dur.sec;
1083 }
1084
1085 if (val != NULL)
1086 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001087 else
1088 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001089
1090 return 0;
1091
1092error:
1093 if (dur != NULL)
1094 xmlSchemaFreeValue(dur);
1095 return 1;
1096}
1097
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001098/**
1099 * xmlSchemaStrip:
1100 * @value: a value
1101 *
1102 * Removes the leading and ending spaces of a string
1103 *
1104 * Returns the new string or NULL if no change was required.
1105 */
1106static xmlChar *
1107xmlSchemaStrip(const xmlChar *value) {
1108 const xmlChar *start = value, *end, *f;
1109
1110 if (value == NULL) return(NULL);
1111 while ((*start != 0) && (IS_BLANK(*start))) start++;
1112 end = start;
1113 while (*end != 0) end++;
1114 f = end;
1115 end--;
1116 while ((end > start) && (IS_BLANK(*end))) end--;
1117 end++;
1118 if ((start == value) && (f == end)) return(NULL);
1119 return(xmlStrndup(start, end - start));
1120}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001121
1122/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001123 * xmlSchemaValAtomicListNode:
1124 * @type: the predefined atomic type for a token in the list
1125 * @value: the list value to check
1126 * @ret: the return computed value
1127 * @node: the node containing the value
1128 *
1129 * Check that a value conforms to the lexical space of the predefined
1130 * list type. if true a value is computed and returned in @ret.
1131 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001132 * Returns the number of items if this validates, a negative error code
1133 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001134 */
1135static int
1136xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1137 xmlSchemaValPtr *ret, xmlNodePtr node) {
1138 xmlChar *val, *cur, *endval;
1139 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001140 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001141
1142 if (value == NULL) {
1143 return(-1);
1144 }
1145 val = xmlStrdup(value);
1146 if (val == NULL) {
1147 return(-1);
1148 }
1149 cur = val;
1150 /*
1151 * Split the list
1152 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001153 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001154 while (*cur != 0) {
1155 if (IS_BLANK(*cur)) {
1156 *cur = 0;
1157 cur++;
1158 while (IS_BLANK(*cur)) *cur++ = 0;
1159 } else {
1160 nb_values++;
1161 cur++;
1162 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1163 }
1164 }
1165 if (nb_values == 0) {
1166 if (ret != NULL) {
1167 TODO
1168 }
1169 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001170 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001171 }
1172 endval = cur;
1173 cur = val;
1174 while ((*cur == 0) && (cur != endval)) cur++;
1175 while (cur != endval) {
1176 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1177 if (tmp != 0)
1178 break;
1179 while (*cur != 0) cur++;
1180 while ((*cur == 0) && (cur != endval)) cur++;
1181 }
1182 xmlFree(val);
1183 if (ret != NULL) {
1184 TODO
1185 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001186 if (tmp == 0)
1187 return(nb_values);
1188 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001189}
1190
1191/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001192 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00001193 * @type: the predefined type
1194 * @value: the value to check
1195 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001196 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00001197 *
1198 * Check that a value conforms to the lexical space of the predefined type.
1199 * if true a value is computed and returned in @val.
1200 *
1201 * Returns 0 if this validates, a positive error code number otherwise
1202 * and -1 in case of internal or API error.
1203 */
1204int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001205xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
1206 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001207 xmlSchemaValPtr v;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001208 int ret;
Daniel Veillard4255d502002-04-16 15:50:10 +00001209
1210 if (xmlSchemaTypesInitialized == 0)
1211 return(-1);
1212 if (type == NULL)
1213 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001214
Daniel Veillard4255d502002-04-16 15:50:10 +00001215 if (val != NULL)
1216 *val = NULL;
1217 if (type == xmlSchemaTypeStringDef) {
1218 return(0);
1219 } else if (type == xmlSchemaTypeAnyTypeDef) {
1220 return(0);
1221 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
1222 return(0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001223 } else if (type == xmlSchemaTypeNmtokenDef) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00001224 if (xmlValidateNMToken(value, 1) == 0) {
1225 if (val != NULL) {
1226 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
1227 if (v != NULL) {
1228 v->value.str = xmlStrdup(value);
1229 *val = v;
1230 } else {
1231 return(-1);
1232 }
1233 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001234 return(0);
Daniel Veillardc4c21552003-03-29 10:53:38 +00001235 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001236 return(1);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001237 } else if (type == xmlSchemaTypeNmtokensDef) {
1238 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1239 value, val, node);
Daniel Veillardc4c21552003-03-29 10:53:38 +00001240 if (ret > 0)
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001241 ret = 0;
1242 else
1243 ret = 1;
1244 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001245 } else if (type == xmlSchemaTypeDecimalDef) {
1246 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001247 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001248 unsigned long base = 0;
1249 if (cur == NULL)
1250 return(1);
1251 if (*cur == '+')
1252 cur++;
1253 else if (*cur == '-') {
1254 neg = 1;
1255 cur++;
1256 }
1257 tmp = cur;
1258 while ((*cur >= '0') && (*cur <= '9')) {
1259 base = base * 10 + (*cur - '0');
1260 cur++;
1261 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001262 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001263 if (*cur == '.') {
1264 cur++;
1265 tmp = cur;
1266 while ((*cur >= '0') && (*cur <= '9')) {
1267 base = base * 10 + (*cur - '0');
1268 cur++;
1269 }
1270 frac = cur - tmp;
1271 }
1272 if (*cur != 0)
1273 return(1);
1274 if (val != NULL) {
1275 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1276 if (v != NULL) {
1277 v->value.decimal.base = base;
1278 v->value.decimal.sign = neg;
1279 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001280 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001281 *val = v;
1282 }
1283 }
1284 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001285 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001286 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001287 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1288 (type == xmlSchemaTypeTimeDef) ||
1289 (type == xmlSchemaTypeDateDef) ||
1290 (type == xmlSchemaTypeGYearDef) ||
1291 (type == xmlSchemaTypeGYearMonthDef) ||
1292 (type == xmlSchemaTypeGMonthDef) ||
1293 (type == xmlSchemaTypeGMonthDayDef) ||
1294 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001295 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001296 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1297 const xmlChar *cur = value;
1298 unsigned long base = 0;
1299 int total = 0;
1300 if (cur == NULL)
1301 return(1);
1302 if (*cur == '+')
1303 cur++;
1304 while ((*cur >= '0') && (*cur <= '9')) {
1305 base = base * 10 + (*cur - '0');
1306 total++;
1307 cur++;
1308 }
1309 if (*cur != 0)
1310 return(1);
1311 if (val != NULL) {
1312 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1313 if (v != NULL) {
1314 v->value.decimal.base = base;
1315 v->value.decimal.sign = 0;
1316 v->value.decimal.frac = 0;
1317 v->value.decimal.total = total;
1318 *val = v;
1319 }
1320 }
1321 return(0);
1322 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1323 const xmlChar *cur = value;
1324 unsigned long base = 0;
1325 int total = 0;
1326 int sign = 0;
1327 if (cur == NULL)
1328 return(1);
1329 if (*cur == '-') {
1330 sign = 1;
1331 cur++;
Daniel Veillard91a13252003-03-27 23:44:43 +00001332 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001333 while ((*cur >= '0') && (*cur <= '9')) {
1334 base = base * 10 + (*cur - '0');
1335 total++;
1336 cur++;
1337 }
1338 if (*cur != 0)
1339 return(1);
1340 if ((sign == 1) && (base != 0))
1341 return(1);
1342 if (val != NULL) {
1343 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1344 if (v != NULL) {
1345 v->value.decimal.base = base;
1346 v->value.decimal.sign = 0;
1347 v->value.decimal.frac = 0;
1348 v->value.decimal.total = total;
1349 *val = v;
1350 }
1351 }
1352 return(0);
Daniel Veillard91a13252003-03-27 23:44:43 +00001353 } else if (type == xmlSchemaTypeNonPositiveIntegerDef) {
1354 const xmlChar *cur = value;
1355 unsigned long base = 0;
1356 int total = 0;
1357 int sign = 0;
1358 if (cur == NULL)
1359 return(1);
1360 if (*cur == '-') {
1361 sign = 1;
1362 cur++;
1363 }
1364 while ((*cur >= '0') && (*cur <= '9')) {
1365 base = base * 10 + (*cur - '0');
1366 total++;
1367 cur++;
1368 }
1369 if (*cur != 0)
1370 return(1);
1371 if ((sign != 1) && (base != 0))
1372 return(1);
1373 if (val != NULL) {
1374 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1375 if (v != NULL) {
1376 v->value.decimal.base = base;
1377 v->value.decimal.sign = 0;
1378 v->value.decimal.frac = 0;
1379 v->value.decimal.total = total;
1380 *val = v;
1381 }
1382 }
1383 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001384 } else if (type == xmlSchemaTypeIntDef) {
1385 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001386 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001387 int total = 0;
1388 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001389 if (cur == NULL)
1390 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001391 if (*cur == '-') {
1392 sign = 1;
1393 cur++;
1394 } else if (*cur == '+')
1395 cur++;
1396 while (*cur == '0') {
1397 total++;
1398 cur++;
1399 }
1400 while ((*cur >= '0') && (*cur <= '9')) {
1401 base = base * 10 + (*cur - '0');
1402 total++;
1403 cur++;
1404 }
1405 if (*cur != 0)
1406 return(1);
1407 if ((sign == 1) && (total == 0))
1408 return(1);
1409 if (val != NULL) {
1410 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1411 if (v != NULL) {
1412 v->value.decimal.base = base;
1413 v->value.decimal.sign = sign;
1414 v->value.decimal.frac = 0;
1415 v->value.decimal.total = total;
1416 *val = v;
1417 }
1418 }
1419 return(0);
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001420 } else if (type == xmlSchemaTypeIntegerDef) {
1421 const xmlChar *cur = value;
1422 unsigned long base = 0;
1423 int total = 0;
1424 int sign = 0;
1425 if (cur == NULL)
1426 return(1);
1427 if (*cur == '-') {
1428 sign = 1;
1429 cur++;
1430 } else if (*cur == '+')
1431 cur++;
1432 while (*cur == '0') {
1433 total++;
1434 cur++;
1435 }
1436 while ((*cur >= '0') && (*cur <= '9')) {
1437 base = base * 10 + (*cur - '0');
1438 total++;
1439 cur++;
1440 }
1441 if (*cur != 0)
1442 return(1);
1443 if ((sign == 1) && (total == 0))
1444 return(1);
1445 if (val != NULL) {
1446 v = xmlSchemaNewValue(XML_SCHEMAS_INTEGER);
1447 if (v != NULL) {
1448 v->value.decimal.base = base;
1449 v->value.decimal.sign = sign;
1450 v->value.decimal.frac = 0;
1451 v->value.decimal.total = total;
1452 *val = v;
1453 }
1454 }
1455 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001456 } else if ((type == xmlSchemaTypeFloatDef) ||
1457 (type == xmlSchemaTypeDoubleDef)) {
1458 const xmlChar *cur = value;
1459 int neg = 0;
1460 if (cur == NULL)
1461 return(1);
1462 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1463 cur += 3;
1464 if (*cur != 0)
1465 return(1);
1466 if (val != NULL) {
1467 if (type == xmlSchemaTypeFloatDef) {
1468 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1469 if (v != NULL) {
1470 v->value.f = (float) xmlXPathNAN;
1471 } else {
1472 xmlSchemaFreeValue(v);
1473 return(-1);
1474 }
1475 } else {
1476 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1477 if (v != NULL) {
1478 v->value.d = xmlXPathNAN;
1479 } else {
1480 xmlSchemaFreeValue(v);
1481 return(-1);
1482 }
1483 }
1484 *val = v;
1485 }
1486 return(0);
1487 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001488 if (*cur == '+')
1489 cur++;
1490 else if (*cur == '-') {
1491 neg = 1;
1492 cur++;
1493 }
Daniel Veillardd4310742003-02-18 21:12:46 +00001494 if (cur[0] == 0)
1495 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001496 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1497 cur += 3;
1498 if (*cur != 0)
1499 return(1);
1500 if (val != NULL) {
1501 if (type == xmlSchemaTypeFloatDef) {
1502 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1503 if (v != NULL) {
1504 if (neg)
1505 v->value.f = (float) xmlXPathNINF;
1506 else
1507 v->value.f = (float) xmlXPathPINF;
1508 } else {
1509 xmlSchemaFreeValue(v);
1510 return(-1);
1511 }
1512 } else {
1513 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1514 if (v != NULL) {
1515 if (neg)
1516 v->value.d = xmlXPathNINF;
1517 else
1518 v->value.d = xmlXPathPINF;
1519 } else {
1520 xmlSchemaFreeValue(v);
1521 return(-1);
1522 }
1523 }
1524 *val = v;
1525 }
1526 return(0);
1527 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001528 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001529 cur++;
1530 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001531 if (*cur == '.') {
1532 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001533 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001534 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001535 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001536 if ((*cur == 'e') || (*cur == 'E')) {
1537 cur++;
1538 if (*cur == '-')
1539 cur++;
1540 while ((*cur >= '0') && (*cur <= '9'))
1541 cur++;
1542 }
1543 if (*cur != 0)
1544 return(1);
1545 if (val != NULL) {
1546 if (type == xmlSchemaTypeFloatDef) {
1547 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1548 if (v != NULL) {
1549 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1550 *val = v;
1551 } else {
1552 xmlGenericError(xmlGenericErrorContext,
1553 "failed to scanf float %s\n", value);
1554 xmlSchemaFreeValue(v);
1555 return(1);
1556 }
1557 } else {
1558 return(-1);
1559 }
1560 } else {
1561 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1562 if (v != NULL) {
1563 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1564 *val = v;
1565 } else {
1566 xmlGenericError(xmlGenericErrorContext,
1567 "failed to scanf double %s\n", value);
1568 xmlSchemaFreeValue(v);
1569 return(1);
1570 }
1571 } else {
1572 return(-1);
1573 }
1574 }
1575 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001576 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001577 } else if (type == xmlSchemaTypeNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001578 ret = xmlValidateName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001579 if ((ret == 0) && (val != NULL)) {
1580 TODO;
1581 }
1582 return(ret);
1583 } else if (type == xmlSchemaTypeQNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001584 ret = xmlValidateQName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001585 if ((ret == 0) && (val != NULL)) {
1586 TODO;
1587 }
1588 return(ret);
1589 } else if (type == xmlSchemaTypeNCNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001590 ret = xmlValidateNCName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001591 if ((ret == 0) && (val != NULL)) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00001592 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
1593 if (v != NULL) {
1594 v->value.str = xmlStrdup(value);
1595 *val = v;
1596 } else {
1597 return(-1);
1598 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001599 }
1600 return(ret);
1601 } else if (type == xmlSchemaTypeAnyURIDef) {
1602 xmlURIPtr uri;
1603
1604 uri = xmlParseURI((const char *) value);
1605 if (uri == NULL)
1606 return(1);
1607 if (val != NULL) {
1608 TODO;
1609 }
1610 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001611 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001612 } else if (type == xmlSchemaTypeBooleanDef) {
1613 const xmlChar *cur = value;
1614
1615 if ((cur[0] == '0') && (cur[1] == 0))
1616 ret = 0;
1617 else if ((cur[0] == '1') && (cur[1] == 0))
1618 ret = 1;
1619 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1620 (cur[3] == 'e') && (cur[4] == 0))
1621 ret = 1;
1622 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1623 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1624 ret = 0;
1625 else
1626 return(1);
1627 if (val != NULL) {
1628 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1629 if (v != NULL) {
1630 v->value.b = ret;
1631 *val = v;
1632 } else {
1633 return(-1);
1634 }
1635 }
1636 return(0);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001637 } else if (type == xmlSchemaTypeIdrefDef) {
1638 ret = xmlValidateNCName(value, 1);
1639 if ((ret == 0) && (val != NULL)) {
1640 TODO;
1641 }
1642 if ((ret == 0) && (node != NULL) &&
1643 (node->type == XML_ATTRIBUTE_NODE)) {
1644 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001645 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001646
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001647 strip = xmlSchemaStrip(value);
1648 if (strip != NULL) {
1649 xmlAddRef(NULL, node->doc, strip, attr);
1650 xmlFree(strip);
1651 } else
1652 xmlAddRef(NULL, node->doc, value, attr);
1653 attr->atype = XML_ATTRIBUTE_IDREF;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001654 }
1655 return(ret);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001656 } else if (type == xmlSchemaTypeIdrefsDef) {
1657 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1658 value, val, node);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001659 if (ret < 0)
1660 ret = 2;
1661 else
1662 ret = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001663 if ((ret == 0) && (node != NULL) &&
1664 (node->type == XML_ATTRIBUTE_NODE)) {
1665 xmlAttrPtr attr = (xmlAttrPtr) node;
1666
1667 attr->atype = XML_ATTRIBUTE_IDREFS;
1668 }
1669 return(ret);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001670 } else if (type == xmlSchemaTypeIdDef) {
1671 ret = xmlValidateNCName(value, 1);
1672 if ((ret == 0) && (val != NULL)) {
1673 TODO;
1674 }
1675 if ((ret == 0) && (node != NULL) &&
1676 (node->type == XML_ATTRIBUTE_NODE)) {
1677 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001678 /*
1679 * NOTE: the IDness might have already be declared in the DTD
1680 */
1681 if (attr->atype != XML_ATTRIBUTE_ID) {
1682 xmlIDPtr res;
1683 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001684
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001685 strip = xmlSchemaStrip(value);
1686 if (strip != NULL) {
1687 res = xmlAddID(NULL, node->doc, strip, attr);
1688 xmlFree(strip);
1689 } else
1690 res = xmlAddID(NULL, node->doc, value, attr);
1691 if (res == NULL) {
1692 ret = 2;
1693 } else {
1694 attr->atype = XML_ATTRIBUTE_ID;
1695 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001696 }
1697 }
1698 return(ret);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001699 } else if (type == xmlSchemaTypeEntitiesDef) {
1700 if ((node == NULL) || (node->doc == NULL))
1701 return(3);
1702 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1703 value, val, node);
1704 if (ret <= 0)
1705 ret = 1;
1706 else
1707 ret = 0;
1708 if ((ret == 0) && (node != NULL) &&
1709 (node->type == XML_ATTRIBUTE_NODE)) {
1710 xmlAttrPtr attr = (xmlAttrPtr) node;
1711
1712 attr->atype = XML_ATTRIBUTE_ENTITIES;
1713 }
1714 return(ret);
1715 } else if (type == xmlSchemaTypeEntityDef) {
1716 xmlChar *strip;
1717 ret = xmlValidateNCName(value, 1);
1718 if ((node == NULL) || (node->doc == NULL))
1719 ret = 3;
1720 if (ret == 0) {
1721 xmlEntityPtr ent;
1722
1723 strip = xmlSchemaStrip(value);
1724 if (strip != NULL) {
1725 ent = xmlGetDocEntity(node->doc, strip);
1726 xmlFree(strip);
1727 } else {
1728 ent = xmlGetDocEntity(node->doc, value);
1729 }
1730 if ((ent == NULL) ||
1731 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1732 ret = 4;
1733 }
1734 if ((ret == 0) && (val != NULL)) {
1735 TODO;
1736 }
1737 if ((ret == 0) && (node != NULL) &&
1738 (node->type == XML_ATTRIBUTE_NODE)) {
1739 xmlAttrPtr attr = (xmlAttrPtr) node;
1740
1741 attr->atype = XML_ATTRIBUTE_ENTITY;
1742 }
1743 return(ret);
Daniel Veillardc4c21552003-03-29 10:53:38 +00001744 } else if (type == xmlSchemaTypeLanguageDef) {
1745 if (xmlCheckLanguageID(value) == 1) {
1746 if (val != NULL) {
1747 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
1748 if (v != NULL) {
1749 v->value.str = xmlStrdup(value);
1750 *val = v;
1751 } else {
1752 return(-1);
1753 }
1754 }
1755 return(0);
1756 }
1757 return(1);
1758 } else if (type == xmlSchemaTypeTokenDef) {
1759 const xmlChar *cur = value;
1760
1761 if (IS_BLANK(*cur))
1762 return(1);
1763
1764 while (*cur != 0) {
1765 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1766 return(1);
1767 } else if (*cur == ' ') {
1768 cur++;
1769 if (*cur == 0)
1770 return(1);
1771 if (*cur == ' ')
1772 return(1);
1773 } else {
1774 cur++;
1775 }
1776 }
1777 if (val != NULL) {
1778 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1779 if (v != NULL) {
1780 v->value.str = xmlStrdup(value);
1781 *val = v;
1782 } else {
1783 return(-1);
1784 }
1785 }
1786 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001787 }
Daniel Veillard09628212003-03-25 15:10:27 +00001788 TODO
1789 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001790}
1791
1792/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001793 * xmlSchemaValidatePredefinedType:
1794 * @type: the predefined type
1795 * @value: the value to check
1796 * @val: the return computed value
1797 *
1798 * Check that a value conforms to the lexical space of the predefined type.
1799 * if true a value is computed and returned in @val.
1800 *
1801 * Returns 0 if this validates, a positive error code number otherwise
1802 * and -1 in case of internal or API error.
1803 */
1804int
1805xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1806 xmlSchemaValPtr *val) {
1807 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
1808}
1809
1810/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001811 * xmlSchemaCompareDecimals:
1812 * @x: a first decimal value
1813 * @y: a second decimal value
1814 *
1815 * Compare 2 decimals
1816 *
1817 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1818 */
1819static int
1820xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1821{
1822 xmlSchemaValPtr swp;
1823 int order = 1;
1824 unsigned long tmp;
1825
Daniel Veillard80b19092003-03-28 13:29:53 +00001826 if ((x->value.decimal.sign) && (x->value.decimal.base != 0)) {
1827 if ((y->value.decimal.sign) && (y->value.decimal.base != 0))
1828 order = -1;
1829 else
1830 return (-1);
1831 } else if ((y->value.decimal.sign) && (y->value.decimal.base != 0)) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001832 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00001833 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001834 if (x->value.decimal.frac == y->value.decimal.frac) {
1835 if (x->value.decimal.base < y->value.decimal.base)
Daniel Veillard80b19092003-03-28 13:29:53 +00001836 return (-order);
1837 if (x->value.decimal.base > y->value.decimal.base)
1838 return(order);
1839 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001840 }
1841 if (y->value.decimal.frac > x->value.decimal.frac) {
1842 swp = y;
1843 y = x;
1844 x = swp;
1845 order = -order;
1846 }
1847 tmp =
1848 x->value.decimal.base / powten[x->value.decimal.frac -
1849 y->value.decimal.frac];
1850 if (tmp > y->value.decimal.base)
1851 return (order);
1852 if (tmp < y->value.decimal.base)
1853 return (-order);
1854 tmp =
1855 y->value.decimal.base * powten[x->value.decimal.frac -
1856 y->value.decimal.frac];
1857 if (x->value.decimal.base < tmp)
1858 return (-order);
1859 if (x->value.decimal.base == tmp)
1860 return (0);
1861 return (order);
1862}
1863
1864/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001865 * xmlSchemaCompareDurations:
1866 * @x: a first duration value
1867 * @y: a second duration value
1868 *
1869 * Compare 2 durations
1870 *
1871 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1872 * case of error
1873 */
1874static int
1875xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1876{
1877 long carry, mon, day;
1878 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00001879 int invert = 1;
1880 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00001881 static const long dayRange [2][12] = {
1882 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1883 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1884
1885 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001886 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001887
1888 /* months */
1889 mon = x->value.dur.mon - y->value.dur.mon;
1890
1891 /* seconds */
1892 sec = x->value.dur.sec - y->value.dur.sec;
1893 carry = (long)sec / SECS_PER_DAY;
1894 sec -= (double)(carry * SECS_PER_DAY);
1895
1896 /* days */
1897 day = x->value.dur.day - y->value.dur.day + carry;
1898
1899 /* easy test */
1900 if (mon == 0) {
1901 if (day == 0)
1902 if (sec == 0.0)
1903 return 0;
1904 else if (sec < 0.0)
1905 return -1;
1906 else
1907 return 1;
1908 else if (day < 0)
1909 return -1;
1910 else
1911 return 1;
1912 }
1913
1914 if (mon > 0) {
1915 if ((day >= 0) && (sec >= 0.0))
1916 return 1;
1917 else {
1918 xmon = mon;
1919 xday = -day;
1920 }
1921 } else if ((day <= 0) && (sec <= 0.0)) {
1922 return -1;
1923 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00001924 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001925 xmon = -mon;
1926 xday = day;
1927 }
1928
1929 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00001930 if (myear == 0) {
1931 minday = 0;
1932 maxday = 0;
1933 } else {
1934 maxday = 366 * ((myear + 3) / 4) +
1935 365 * ((myear - 1) % 4);
1936 minday = maxday - 1;
1937 }
1938
Daniel Veillard070803b2002-05-03 07:29:38 +00001939 xmon = xmon % 12;
1940 minday += dayRange[0][xmon];
1941 maxday += dayRange[1][xmon];
1942
Daniel Veillard80b19092003-03-28 13:29:53 +00001943 if ((maxday == minday) && (maxday == xday))
1944 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00001945 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00001946 return(-invert);
1947 if (minday > xday)
1948 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00001949
1950 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001951 return 2;
1952}
1953
1954/*
1955 * macros for adding date/times and durations
1956 */
1957#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1958#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1959#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1960#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1961
1962/**
1963 * _xmlSchemaDateAdd:
1964 * @dt: an #xmlSchemaValPtr
1965 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1966 *
1967 * Compute a new date/time from @dt and @dur. This function assumes @dt
1968 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1969 * or #XML_SCHEMAS_GYEAR.
1970 *
1971 * Returns date/time pointer or NULL.
1972 */
1973static xmlSchemaValPtr
1974_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1975{
1976 xmlSchemaValPtr ret;
1977 long carry, tempdays, temp;
1978 xmlSchemaValDatePtr r, d;
1979 xmlSchemaValDurationPtr u;
1980
1981 if ((dt == NULL) || (dur == NULL))
1982 return NULL;
1983
1984 ret = xmlSchemaNewValue(dt->type);
1985 if (ret == NULL)
1986 return NULL;
1987
1988 r = &(ret->value.date);
1989 d = &(dt->value.date);
1990 u = &(dur->value.dur);
1991
1992 /* normalization */
1993 if (d->mon == 0)
1994 d->mon = 1;
1995
1996 /* normalize for time zone offset */
1997 u->sec -= (d->tzo * 60);
1998 d->tzo = 0;
1999
2000 /* normalization */
2001 if (d->day == 0)
2002 d->day = 1;
2003
2004 /* month */
2005 carry = d->mon + u->mon;
2006 r->mon = MODULO_RANGE(carry, 1, 13);
2007 carry = FQUOTIENT_RANGE(carry, 1, 13);
2008
2009 /* year (may be modified later) */
2010 r->year = d->year + carry;
2011 if (r->year == 0) {
2012 if (d->year > 0)
2013 r->year--;
2014 else
2015 r->year++;
2016 }
2017
2018 /* time zone */
2019 r->tzo = d->tzo;
2020 r->tz_flag = d->tz_flag;
2021
2022 /* seconds */
2023 r->sec = d->sec + u->sec;
2024 carry = FQUOTIENT((long)r->sec, 60);
2025 if (r->sec != 0.0) {
2026 r->sec = MODULO(r->sec, 60.0);
2027 }
2028
2029 /* minute */
2030 carry += d->min;
2031 r->min = MODULO(carry, 60);
2032 carry = FQUOTIENT(carry, 60);
2033
2034 /* hours */
2035 carry += d->hour;
2036 r->hour = MODULO(carry, 24);
2037 carry = FQUOTIENT(carry, 24);
2038
2039 /*
2040 * days
2041 * Note we use tempdays because the temporary values may need more
2042 * than 5 bits
2043 */
2044 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2045 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2046 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2047 else if (d->day < 1)
2048 tempdays = 1;
2049 else
2050 tempdays = d->day;
2051
2052 tempdays += u->day + carry;
2053
2054 while (1) {
2055 if (tempdays < 1) {
2056 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
2057 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
2058 if (tyr == 0)
2059 tyr--;
2060 tempdays += MAX_DAYINMONTH(tyr, tmon);
2061 carry = -1;
2062 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
2063 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
2064 carry = 1;
2065 } else
2066 break;
2067
2068 temp = r->mon + carry;
2069 r->mon = MODULO_RANGE(temp, 1, 13);
2070 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
2071 if (r->year == 0) {
2072 if (temp < 1)
2073 r->year--;
2074 else
2075 r->year++;
2076 }
2077 }
2078
2079 r->day = tempdays;
2080
2081 /*
2082 * adjust the date/time type to the date values
2083 */
2084 if (ret->type != XML_SCHEMAS_DATETIME) {
2085 if ((r->hour) || (r->min) || (r->sec))
2086 ret->type = XML_SCHEMAS_DATETIME;
2087 else if (ret->type != XML_SCHEMAS_DATE) {
2088 if ((r->mon != 1) && (r->day != 1))
2089 ret->type = XML_SCHEMAS_DATE;
2090 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2091 ret->type = XML_SCHEMAS_GYEARMONTH;
2092 }
2093 }
2094
2095 return ret;
2096}
2097
2098/**
2099 * xmlSchemaDupVal:
2100 * @v: value to duplicate
2101 *
2102 * returns a duplicated value.
2103 */
2104static xmlSchemaValPtr
2105xmlSchemaDupVal (xmlSchemaValPtr v)
2106{
2107 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2108 if (ret == NULL)
2109 return ret;
2110
2111 memcpy(ret, v, sizeof(xmlSchemaVal));
2112 return ret;
2113}
2114
2115/**
2116 * xmlSchemaDateNormalize:
2117 * @dt: an #xmlSchemaValPtr
2118 *
2119 * Normalize @dt to GMT time.
2120 *
2121 */
2122static xmlSchemaValPtr
2123xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2124{
2125 xmlSchemaValPtr dur, ret;
2126
2127 if (dt == NULL)
2128 return NULL;
2129
2130 if (((dt->type != XML_SCHEMAS_TIME) &&
2131 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2132 return xmlSchemaDupVal(dt);
2133
2134 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2135 if (dur == NULL)
2136 return NULL;
2137
2138 dur->value.date.sec -= offset;
2139
2140 ret = _xmlSchemaDateAdd(dt, dur);
2141 if (ret == NULL)
2142 return NULL;
2143
2144 xmlSchemaFreeValue(dur);
2145
2146 /* ret->value.date.tzo = 0; */
2147 return ret;
2148}
2149
2150/**
2151 * _xmlSchemaDateCastYMToDays:
2152 * @dt: an #xmlSchemaValPtr
2153 *
2154 * Convert mon and year of @dt to total number of days. Take the
2155 * number of years since (or before) 1 AD and add the number of leap
2156 * years. This is a function because negative
2157 * years must be handled a little differently and there is no zero year.
2158 *
2159 * Returns number of days.
2160 */
2161static long
2162_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2163{
2164 long ret;
2165
2166 if (dt->value.date.year < 0)
2167 ret = (dt->value.date.year * 365) +
2168 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2169 ((dt->value.date.year+1)/400)) +
2170 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2171 else
2172 ret = ((dt->value.date.year-1) * 365) +
2173 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2174 ((dt->value.date.year-1)/400)) +
2175 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2176
2177 return ret;
2178}
2179
2180/**
2181 * TIME_TO_NUMBER:
2182 * @dt: an #xmlSchemaValPtr
2183 *
2184 * Calculates the number of seconds in the time portion of @dt.
2185 *
2186 * Returns seconds.
2187 */
2188#define TIME_TO_NUMBER(dt) \
2189 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
2190 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
2191
2192/**
2193 * xmlSchemaCompareDates:
2194 * @x: a first date/time value
2195 * @y: a second date/time value
2196 *
2197 * Compare 2 date/times
2198 *
2199 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2200 * case of error
2201 */
2202static int
2203xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2204{
2205 unsigned char xmask, ymask, xor_mask, and_mask;
2206 xmlSchemaValPtr p1, p2, q1, q2;
2207 long p1d, p2d, q1d, q2d;
2208
2209 if ((x == NULL) || (y == NULL))
2210 return -2;
2211
2212 if (x->value.date.tz_flag) {
2213
2214 if (!y->value.date.tz_flag) {
2215 p1 = xmlSchemaDateNormalize(x, 0);
2216 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2217 /* normalize y + 14:00 */
2218 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2219
2220 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002221 if (p1d < q1d) {
2222 xmlSchemaFreeValue(p1);
2223 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002224 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002225 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002226 double sec;
2227
2228 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002229 if (sec < 0.0) {
2230 xmlSchemaFreeValue(p1);
2231 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002232 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002233 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002234 /* normalize y - 14:00 */
2235 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2236 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002237 xmlSchemaFreeValue(p1);
2238 xmlSchemaFreeValue(q1);
2239 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002240 if (p1d > q2d)
2241 return 1;
2242 else if (p1d == q2d) {
2243 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2244 if (sec > 0.0)
2245 return 1;
2246 else
2247 return 2; /* indeterminate */
2248 }
2249 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002250 } else {
2251 xmlSchemaFreeValue(p1);
2252 xmlSchemaFreeValue(q1);
2253 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002254 }
2255 } else if (y->value.date.tz_flag) {
2256 q1 = xmlSchemaDateNormalize(y, 0);
2257 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2258
2259 /* normalize x - 14:00 */
2260 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2261 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2262
Daniel Veillardfdc91562002-07-01 21:52:03 +00002263 if (p1d < q1d) {
2264 xmlSchemaFreeValue(p1);
2265 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002266 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002267 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002268 double sec;
2269
2270 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002271 if (sec < 0.0) {
2272 xmlSchemaFreeValue(p1);
2273 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002274 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002275 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002276 /* normalize x + 14:00 */
2277 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2278 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2279
Daniel Veillard6560a422003-03-27 21:25:38 +00002280 if (p2d > q1d) {
2281 xmlSchemaFreeValue(p1);
2282 xmlSchemaFreeValue(q1);
2283 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002284 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002285 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002286 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002287 xmlSchemaFreeValue(p1);
2288 xmlSchemaFreeValue(q1);
2289 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002290 if (sec > 0.0)
2291 return 1;
2292 else
2293 return 2; /* indeterminate */
2294 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002295 xmlSchemaFreeValue(p1);
2296 xmlSchemaFreeValue(q1);
2297 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002298 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002299 } else {
2300 xmlSchemaFreeValue(p1);
2301 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002302 }
2303 }
2304
2305 /*
2306 * if the same type then calculate the difference
2307 */
2308 if (x->type == y->type) {
2309 q1 = xmlSchemaDateNormalize(y, 0);
2310 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2311
2312 p1 = xmlSchemaDateNormalize(x, 0);
2313 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2314
Daniel Veillardfdc91562002-07-01 21:52:03 +00002315 if (p1d < q1d) {
2316 xmlSchemaFreeValue(p1);
2317 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002318 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002319 } else if (p1d > q1d) {
2320 xmlSchemaFreeValue(p1);
2321 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002322 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002323 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002324 double sec;
2325
2326 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002327 xmlSchemaFreeValue(p1);
2328 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002329 if (sec < 0.0)
2330 return -1;
2331 else if (sec > 0.0)
2332 return 1;
2333
2334 }
2335 return 0;
2336 }
2337
2338 switch (x->type) {
2339 case XML_SCHEMAS_DATETIME:
2340 xmask = 0xf;
2341 break;
2342 case XML_SCHEMAS_DATE:
2343 xmask = 0x7;
2344 break;
2345 case XML_SCHEMAS_GYEAR:
2346 xmask = 0x1;
2347 break;
2348 case XML_SCHEMAS_GMONTH:
2349 xmask = 0x2;
2350 break;
2351 case XML_SCHEMAS_GDAY:
2352 xmask = 0x3;
2353 break;
2354 case XML_SCHEMAS_GYEARMONTH:
2355 xmask = 0x3;
2356 break;
2357 case XML_SCHEMAS_GMONTHDAY:
2358 xmask = 0x6;
2359 break;
2360 case XML_SCHEMAS_TIME:
2361 xmask = 0x8;
2362 break;
2363 default:
2364 xmask = 0;
2365 break;
2366 }
2367
2368 switch (y->type) {
2369 case XML_SCHEMAS_DATETIME:
2370 ymask = 0xf;
2371 break;
2372 case XML_SCHEMAS_DATE:
2373 ymask = 0x7;
2374 break;
2375 case XML_SCHEMAS_GYEAR:
2376 ymask = 0x1;
2377 break;
2378 case XML_SCHEMAS_GMONTH:
2379 ymask = 0x2;
2380 break;
2381 case XML_SCHEMAS_GDAY:
2382 ymask = 0x3;
2383 break;
2384 case XML_SCHEMAS_GYEARMONTH:
2385 ymask = 0x3;
2386 break;
2387 case XML_SCHEMAS_GMONTHDAY:
2388 ymask = 0x6;
2389 break;
2390 case XML_SCHEMAS_TIME:
2391 ymask = 0x8;
2392 break;
2393 default:
2394 ymask = 0;
2395 break;
2396 }
2397
2398 xor_mask = xmask ^ ymask; /* mark type differences */
2399 and_mask = xmask & ymask; /* mark field specification */
2400
2401 /* year */
2402 if (xor_mask & 1)
2403 return 2; /* indeterminate */
2404 else if (and_mask & 1) {
2405 if (x->value.date.year < y->value.date.year)
2406 return -1;
2407 else if (x->value.date.year > y->value.date.year)
2408 return 1;
2409 }
2410
2411 /* month */
2412 if (xor_mask & 2)
2413 return 2; /* indeterminate */
2414 else if (and_mask & 2) {
2415 if (x->value.date.mon < y->value.date.mon)
2416 return -1;
2417 else if (x->value.date.mon > y->value.date.mon)
2418 return 1;
2419 }
2420
2421 /* day */
2422 if (xor_mask & 4)
2423 return 2; /* indeterminate */
2424 else if (and_mask & 4) {
2425 if (x->value.date.day < y->value.date.day)
2426 return -1;
2427 else if (x->value.date.day > y->value.date.day)
2428 return 1;
2429 }
2430
2431 /* time */
2432 if (xor_mask & 8)
2433 return 2; /* indeterminate */
2434 else if (and_mask & 8) {
2435 if (x->value.date.hour < y->value.date.hour)
2436 return -1;
2437 else if (x->value.date.hour > y->value.date.hour)
2438 return 1;
2439 else if (x->value.date.min < y->value.date.min)
2440 return -1;
2441 else if (x->value.date.min > y->value.date.min)
2442 return 1;
2443 else if (x->value.date.sec < y->value.date.sec)
2444 return -1;
2445 else if (x->value.date.sec > y->value.date.sec)
2446 return 1;
2447 }
2448
Daniel Veillard070803b2002-05-03 07:29:38 +00002449 return 0;
2450}
2451
2452/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00002453 * xmlSchemaCompareNormStrings:
2454 * @x: a first string value
2455 * @y: a second string value
2456 *
2457 * Compare 2 string for their normalized values.
2458 *
2459 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
2460 * case of error
2461 */
2462static int
2463xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2464 const xmlChar *utf1;
2465 const xmlChar *utf2;
2466 int tmp;
2467
2468 if ((x == NULL) || (y == NULL))
2469 return(-2);
2470 utf1 = x->value.str;
2471 utf2 = y->value.str;
2472
2473 while (IS_BLANK(*utf1)) utf1++;
2474 while (IS_BLANK(*utf2)) utf2++;
2475 while ((*utf1 != 0) && (*utf2 != 0)) {
2476 if (IS_BLANK(*utf1)) {
2477 if (!IS_BLANK(*utf2)) {
2478 tmp = *utf1 - *utf2;
2479 return(tmp);
2480 }
2481 while (IS_BLANK(*utf1)) utf1++;
2482 while (IS_BLANK(*utf2)) utf2++;
2483 } else {
2484 tmp = *utf1++ - *utf2++;
2485 if (tmp < 0)
2486 return(-1);
2487 if (tmp > 0)
2488 return(1);
2489 }
2490 }
2491 if (*utf1 != 0) {
2492 while (IS_BLANK(*utf1)) utf1++;
2493 if (*utf1 != 0)
2494 return(1);
2495 }
2496 if (*utf2 != 0) {
2497 while (IS_BLANK(*utf2)) utf2++;
2498 if (*utf2 != 0)
2499 return(-1);
2500 }
2501 return(0);
2502}
2503
2504/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002505 * xmlSchemaCompareValues:
2506 * @x: a first value
2507 * @y: a second value
2508 *
2509 * Compare 2 values
2510 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002511 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2512 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002513 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002514int
Daniel Veillard4255d502002-04-16 15:50:10 +00002515xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2516 if ((x == NULL) || (y == NULL))
2517 return(-2);
2518
2519 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002520 case XML_SCHEMAS_UNKNOWN:
2521 return(-2);
2522 case XML_SCHEMAS_INTEGER:
2523 case XML_SCHEMAS_NPINTEGER:
2524 case XML_SCHEMAS_NINTEGER:
2525 case XML_SCHEMAS_NNINTEGER:
2526 case XML_SCHEMAS_PINTEGER:
2527 case XML_SCHEMAS_INT:
2528 case XML_SCHEMAS_UINT:
2529 case XML_SCHEMAS_LONG:
2530 case XML_SCHEMAS_ULONG:
2531 case XML_SCHEMAS_SHORT:
2532 case XML_SCHEMAS_USHORT:
2533 case XML_SCHEMAS_BYTE:
2534 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00002535 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00002536 if (y->type == x->type)
2537 return(xmlSchemaCompareDecimals(x, y));
2538 if ((y->type == XML_SCHEMAS_DECIMAL) ||
2539 (y->type == XML_SCHEMAS_INTEGER) ||
2540 (y->type == XML_SCHEMAS_NPINTEGER) ||
2541 (y->type == XML_SCHEMAS_NINTEGER) ||
2542 (y->type == XML_SCHEMAS_NNINTEGER) ||
2543 (y->type == XML_SCHEMAS_PINTEGER) ||
2544 (y->type == XML_SCHEMAS_INT) ||
2545 (y->type == XML_SCHEMAS_UINT) ||
2546 (y->type == XML_SCHEMAS_LONG) ||
2547 (y->type == XML_SCHEMAS_ULONG) ||
2548 (y->type == XML_SCHEMAS_SHORT) ||
2549 (y->type == XML_SCHEMAS_USHORT) ||
2550 (y->type == XML_SCHEMAS_BYTE) ||
2551 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00002552 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002553 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002554 case XML_SCHEMAS_DURATION:
2555 if (y->type == XML_SCHEMAS_DURATION)
2556 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002557 return(-2);
2558 case XML_SCHEMAS_TIME:
2559 case XML_SCHEMAS_GDAY:
2560 case XML_SCHEMAS_GMONTH:
2561 case XML_SCHEMAS_GMONTHDAY:
2562 case XML_SCHEMAS_GYEAR:
2563 case XML_SCHEMAS_GYEARMONTH:
2564 case XML_SCHEMAS_DATE:
2565 case XML_SCHEMAS_DATETIME:
2566 if ((y->type == XML_SCHEMAS_DATETIME) ||
2567 (y->type == XML_SCHEMAS_TIME) ||
2568 (y->type == XML_SCHEMAS_GDAY) ||
2569 (y->type == XML_SCHEMAS_GMONTH) ||
2570 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2571 (y->type == XML_SCHEMAS_GYEAR) ||
2572 (y->type == XML_SCHEMAS_DATE) ||
2573 (y->type == XML_SCHEMAS_GYEARMONTH))
2574 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002575 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002576 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00002577 case XML_SCHEMAS_TOKEN:
2578 case XML_SCHEMAS_LANGUAGE:
2579 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00002580 case XML_SCHEMAS_NAME:
2581 case XML_SCHEMAS_QNAME:
2582 case XML_SCHEMAS_NCNAME:
2583 case XML_SCHEMAS_ID:
2584 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00002585 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00002586 case XML_SCHEMAS_NOTATION:
2587 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00002588 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
2589 (y->type == XML_SCHEMAS_TOKEN) ||
2590 (y->type == XML_SCHEMAS_LANGUAGE) ||
2591 (y->type == XML_SCHEMAS_NMTOKEN) ||
2592 (y->type == XML_SCHEMAS_NAME) ||
2593 (y->type == XML_SCHEMAS_QNAME) ||
2594 (y->type == XML_SCHEMAS_NCNAME) ||
2595 (y->type == XML_SCHEMAS_ID) ||
2596 (y->type == XML_SCHEMAS_IDREF) ||
2597 (y->type == XML_SCHEMAS_ENTITY) ||
2598 (y->type == XML_SCHEMAS_NOTATION) ||
2599 (y->type == XML_SCHEMAS_ANYURI))
2600 return (xmlSchemaCompareNormStrings(x, y));
2601 return (-2);
2602
2603 case XML_SCHEMAS_FLOAT:
2604 case XML_SCHEMAS_DOUBLE:
Daniel Veillard4255d502002-04-16 15:50:10 +00002605 TODO
Daniel Veillardc4c21552003-03-29 10:53:38 +00002606 break;
2607 case XML_SCHEMAS_BOOLEAN:
2608 TODO
2609 break;
2610 case XML_SCHEMAS_STRING:
2611 case XML_SCHEMAS_IDREFS:
2612 case XML_SCHEMAS_ENTITIES:
2613 case XML_SCHEMAS_NMTOKENS:
2614 TODO
2615 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00002616 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002617 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002618}
2619
2620/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00002621 * xmlSchemaNormLen:
2622 * @value: a string
2623 *
2624 * Computes the UTF8 length of the normalized value of the string
2625 *
2626 * Returns the length or -1 in case of error.
2627 */
2628static int
2629xmlSchemaNormLen(const xmlChar *value) {
2630 const xmlChar *utf;
2631 int ret = 0;
2632
2633 if (value == NULL)
2634 return(-1);
2635 utf = value;
2636 while (IS_BLANK(*utf)) utf++;
2637 while (*utf != 0) {
2638 if (utf[0] & 0x80) {
2639 if ((utf[1] & 0xc0) != 0x80)
2640 return(-1);
2641 if ((utf[0] & 0xe0) == 0xe0) {
2642 if ((utf[2] & 0xc0) != 0x80)
2643 return(-1);
2644 if ((utf[0] & 0xf0) == 0xf0) {
2645 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
2646 return(-1);
2647 utf += 4;
2648 } else {
2649 utf += 3;
2650 }
2651 } else {
2652 utf += 2;
2653 }
2654 } else if (IS_BLANK(*utf)) {
2655 while (IS_BLANK(*utf)) utf++;
2656 if (*utf == 0)
2657 break;
2658 } else {
2659 utf++;
2660 }
2661 ret++;
2662 }
2663 return(ret);
2664}
2665
2666/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002667 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002668 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002669 * @facet: the facet to check
2670 * @value: the lexical repr of the value to validate
2671 * @val: the precomputed value
2672 *
2673 * Check a value against a facet condition
2674 *
2675 * Returns 0 if the element is schemas valid, a positive error code
2676 * number otherwise and -1 in case of internal or API error.
2677 */
2678int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002679xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002680 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002681 const xmlChar *value, xmlSchemaValPtr val)
2682{
2683 int ret;
2684
2685 switch (facet->type) {
2686 case XML_SCHEMA_FACET_PATTERN:
2687 ret = xmlRegexpExec(facet->regexp, value);
2688 if (ret == 1)
2689 return(0);
2690 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002691 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002692 return(1);
2693 }
2694 return(ret);
2695 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2696 ret = xmlSchemaCompareValues(val, facet->val);
2697 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002698 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002699 return(-1);
2700 }
2701 if (ret == -1)
2702 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002703 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002704 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002705 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2706 ret = xmlSchemaCompareValues(val, facet->val);
2707 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002708 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002709 return(-1);
2710 }
2711 if ((ret == -1) || (ret == 0))
2712 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002713 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002714 return(1);
2715 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2716 ret = xmlSchemaCompareValues(val, facet->val);
2717 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002718 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002719 return(-1);
2720 }
2721 if (ret == 1)
2722 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002723 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002724 return(1);
2725 case XML_SCHEMA_FACET_MININCLUSIVE:
2726 ret = xmlSchemaCompareValues(val, facet->val);
2727 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002728 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002729 return(-1);
2730 }
2731 if ((ret == 1) || (ret == 0))
2732 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002733 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002734 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002735 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002736 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00002737 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00002738 case XML_SCHEMA_FACET_ENUMERATION:
2739 if ((facet->value != NULL) &&
2740 (xmlStrEqual(facet->value, value)))
2741 return(0);
2742 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002743 case XML_SCHEMA_FACET_LENGTH:
2744 case XML_SCHEMA_FACET_MAXLENGTH:
2745 case XML_SCHEMA_FACET_MINLENGTH: {
2746 unsigned int len = 0;
2747
2748 if ((facet->val == NULL) ||
2749 (facet->val->type != XML_SCHEMAS_DECIMAL) ||
2750 (facet->val->value.decimal.frac != 0)) {
2751 return(-1);
2752 }
2753 switch (base->flags) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00002754 case XML_SCHEMAS_IDREF:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002755 case XML_SCHEMAS_NORMSTRING:
2756 case XML_SCHEMAS_TOKEN:
2757 case XML_SCHEMAS_LANGUAGE:
2758 case XML_SCHEMAS_NMTOKEN:
2759 case XML_SCHEMAS_NAME:
2760 case XML_SCHEMAS_NCNAME:
2761 case XML_SCHEMAS_ID:
Daniel Veillardc4c21552003-03-29 10:53:38 +00002762 len = xmlSchemaNormLen(value);
2763 break;
2764 case XML_SCHEMAS_STRING:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002765 len = xmlUTF8Strlen(value);
2766 break;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002767 default:
2768 TODO
2769 }
2770 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
2771 if (len != facet->val->value.decimal.base)
2772 return(1);
2773 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
2774 if (len < facet->val->value.decimal.base)
2775 return(1);
2776 } else {
2777 if (len > facet->val->value.decimal.base)
2778 return(1);
2779 }
2780 break;
2781 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002782 default:
2783 TODO
2784 }
2785 return(0);
2786}
2787
2788#endif /* LIBXML_SCHEMAS_ENABLED */