blob: c871479deb45422058b996a89b878db37a8d875a [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 Veillardb6c7f412003-03-29 16:41:55 +00001123 * xmlSchemaCollapseString:
1124 * @value: a value
1125 *
1126 * Removes and normalize white spaces in the string
1127 *
1128 * Returns the new string or NULL if no change was required.
1129 */
1130static xmlChar *
1131xmlSchemaCollapseString(const xmlChar *value) {
1132 const xmlChar *start = value, *end, *f;
1133 xmlChar *g;
1134 int col = 0;
1135
1136 if (value == NULL) return(NULL);
1137 while ((*start != 0) && (IS_BLANK(*start))) start++;
1138 end = start;
1139 while (*end != 0) {
1140 if ((*end == ' ') && (IS_BLANK(end[1]))) {
1141 col = end - start;
1142 break;
1143 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1144 col = end - start;
1145 break;
1146 }
1147 end++;
1148 }
1149 if (col == 0) {
1150 f = end;
1151 end--;
1152 while ((end > start) && (IS_BLANK(*end))) end--;
1153 end++;
1154 if ((start == value) && (f == end)) return(NULL);
1155 return(xmlStrndup(start, end - start));
1156 }
1157 start = xmlStrdup(start);
1158 if (start == NULL) return(NULL);
1159 g = (xmlChar *) (start + col);
1160 end = g;
1161 while (*end != 0) {
1162 if (IS_BLANK(*end)) {
1163 end++;
1164 while (IS_BLANK(*end)) end++;
1165 if (*end != 0)
1166 *g++ = ' ';
1167 } else
1168 *g++ = *end++;
1169 }
1170 *g = 0;
1171 return((xmlChar *) start);
1172}
1173
1174/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001175 * xmlSchemaValAtomicListNode:
1176 * @type: the predefined atomic type for a token in the list
1177 * @value: the list value to check
1178 * @ret: the return computed value
1179 * @node: the node containing the value
1180 *
1181 * Check that a value conforms to the lexical space of the predefined
1182 * list type. if true a value is computed and returned in @ret.
1183 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001184 * Returns the number of items if this validates, a negative error code
1185 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001186 */
1187static int
1188xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1189 xmlSchemaValPtr *ret, xmlNodePtr node) {
1190 xmlChar *val, *cur, *endval;
1191 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001192 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001193
1194 if (value == NULL) {
1195 return(-1);
1196 }
1197 val = xmlStrdup(value);
1198 if (val == NULL) {
1199 return(-1);
1200 }
1201 cur = val;
1202 /*
1203 * Split the list
1204 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001205 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001206 while (*cur != 0) {
1207 if (IS_BLANK(*cur)) {
1208 *cur = 0;
1209 cur++;
1210 while (IS_BLANK(*cur)) *cur++ = 0;
1211 } else {
1212 nb_values++;
1213 cur++;
1214 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1215 }
1216 }
1217 if (nb_values == 0) {
1218 if (ret != NULL) {
1219 TODO
1220 }
1221 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001222 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001223 }
1224 endval = cur;
1225 cur = val;
1226 while ((*cur == 0) && (cur != endval)) cur++;
1227 while (cur != endval) {
1228 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1229 if (tmp != 0)
1230 break;
1231 while (*cur != 0) cur++;
1232 while ((*cur == 0) && (cur != endval)) cur++;
1233 }
1234 xmlFree(val);
1235 if (ret != NULL) {
1236 TODO
1237 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001238 if (tmp == 0)
1239 return(nb_values);
1240 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001241}
1242
1243/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001244 * xmlSchemaValAtomicType:
1245 * @type: the predefined type
1246 * @value: the value to check
1247 * @val: the return computed value
1248 * @node: the node containing the value
1249 * flags: flags to control the vlidation
1250 *
1251 * Check that a value conforms to the lexical space of the atomic type.
1252 * if true a value is computed and returned in @val.
1253 *
1254 * Returns 0 if this validates, a positive error code number otherwise
1255 * and -1 in case of internal or API error.
1256 */
1257static int
1258xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar *value,
1259 xmlSchemaValPtr *val, xmlNodePtr node, int flags) {
1260 xmlSchemaValPtr v;
1261 xmlChar *norm = NULL;
1262 int ret;
1263
1264 if (xmlSchemaTypesInitialized == 0)
1265 return(-1);
1266 if (type == NULL)
1267 return(-1);
1268
1269 if (val != NULL)
1270 *val = NULL;
1271 if ((flags == 0) && (value != NULL)) {
1272 if ((type->flags != XML_SCHEMAS_STRING) &&
1273 (type->flags != XML_SCHEMAS_NORMSTRING)) {
1274 norm = xmlSchemaCollapseString(value);
1275 if (norm != NULL)
1276 value = norm;
1277 }
1278 }
1279
1280 switch (type->flags) {
1281 case XML_SCHEMAS_UNKNOWN:
1282 if (type == xmlSchemaTypeAnyTypeDef)
1283 goto return0;
1284 goto error;
1285 case XML_SCHEMAS_STRING:
1286 goto return0;
1287 case XML_SCHEMAS_NORMSTRING:
1288 TODO
1289 goto return0;
1290 case XML_SCHEMAS_DECIMAL: {
1291 const xmlChar *cur = value, *tmp;
1292 int frac = 0, len, neg = 0;
1293 unsigned long base = 0;
1294 if (cur == NULL)
1295 goto return1;
1296 if (*cur == '+')
1297 cur++;
1298 else if (*cur == '-') {
1299 neg = 1;
1300 cur++;
1301 }
1302 tmp = cur;
1303 while ((*cur >= '0') && (*cur <= '9')) {
1304 base = base * 10 + (*cur - '0');
1305 cur++;
1306 }
1307 len = cur - tmp;
1308 if (*cur == '.') {
1309 cur++;
1310 tmp = cur;
1311 while ((*cur >= '0') && (*cur <= '9')) {
1312 base = base * 10 + (*cur - '0');
1313 cur++;
1314 }
1315 frac = cur - tmp;
1316 }
1317 if (*cur != 0)
1318 goto return1;
1319 if (val != NULL) {
1320 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1321 if (v != NULL) {
1322 v->value.decimal.base = base;
1323 v->value.decimal.sign = neg;
1324 v->value.decimal.frac = frac;
1325 v->value.decimal.total = frac + len;
1326 *val = v;
1327 }
1328 }
1329 goto return0;
1330 }
1331 case XML_SCHEMAS_TIME:
1332 case XML_SCHEMAS_GDAY:
1333 case XML_SCHEMAS_GMONTH:
1334 case XML_SCHEMAS_GMONTHDAY:
1335 case XML_SCHEMAS_GYEAR:
1336 case XML_SCHEMAS_GYEARMONTH:
1337 case XML_SCHEMAS_DATE:
1338 case XML_SCHEMAS_DATETIME:
1339 ret = xmlSchemaValidateDates(type, value, val);
1340 break;
1341 case XML_SCHEMAS_DURATION:
1342 ret = xmlSchemaValidateDuration(type, value, val);
1343 break;
1344 case XML_SCHEMAS_FLOAT:
1345 case XML_SCHEMAS_DOUBLE: {
1346 const xmlChar *cur = value;
1347 int neg = 0;
1348 if (cur == NULL)
1349 goto return1;
1350 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1351 cur += 3;
1352 if (*cur != 0)
1353 goto return1;
1354 if (val != NULL) {
1355 if (type == xmlSchemaTypeFloatDef) {
1356 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1357 if (v != NULL) {
1358 v->value.f = (float) xmlXPathNAN;
1359 } else {
1360 xmlSchemaFreeValue(v);
1361 goto error;
1362 }
1363 } else {
1364 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1365 if (v != NULL) {
1366 v->value.d = xmlXPathNAN;
1367 } else {
1368 xmlSchemaFreeValue(v);
1369 goto error;
1370 }
1371 }
1372 *val = v;
1373 }
1374 goto return0;
1375 }
1376 if (*cur == '-') {
1377 neg = 1;
1378 cur++;
1379 }
1380 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1381 cur += 3;
1382 if (*cur != 0)
1383 goto return1;
1384 if (val != NULL) {
1385 if (type == xmlSchemaTypeFloatDef) {
1386 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1387 if (v != NULL) {
1388 if (neg)
1389 v->value.f = (float) xmlXPathNINF;
1390 else
1391 v->value.f = (float) xmlXPathPINF;
1392 } else {
1393 xmlSchemaFreeValue(v);
1394 goto error;
1395 }
1396 } else {
1397 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1398 if (v != NULL) {
1399 if (neg)
1400 v->value.d = xmlXPathNINF;
1401 else
1402 v->value.d = xmlXPathPINF;
1403 } else {
1404 xmlSchemaFreeValue(v);
1405 goto error;
1406 }
1407 }
1408 *val = v;
1409 }
1410 goto return0;
1411 }
1412 if ((neg == 0) && (*cur == '+'))
1413 cur++;
1414 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1415 goto return1;
1416 while ((*cur >= '0') && (*cur <= '9')) {
1417 cur++;
1418 }
1419 if (*cur == '.') {
1420 cur++;
1421 while ((*cur >= '0') && (*cur <= '9'))
1422 cur++;
1423 }
1424 if ((*cur == 'e') || (*cur == 'E')) {
1425 cur++;
1426 if ((*cur == '-') || (*cur == '+'))
1427 cur++;
1428 while ((*cur >= '0') && (*cur <= '9'))
1429 cur++;
1430 }
1431 if (*cur != 0)
1432 goto return1;
1433 if (val != NULL) {
1434 if (type == xmlSchemaTypeFloatDef) {
1435 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1436 if (v != NULL) {
1437 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1438 *val = v;
1439 } else {
1440 xmlGenericError(xmlGenericErrorContext,
1441 "failed to scanf float %s\n", value);
1442 xmlSchemaFreeValue(v);
1443 goto return1;
1444 }
1445 } else {
1446 goto error;
1447 }
1448 } else {
1449 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1450 if (v != NULL) {
1451 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1452 *val = v;
1453 } else {
1454 xmlGenericError(xmlGenericErrorContext,
1455 "failed to scanf double %s\n", value);
1456 xmlSchemaFreeValue(v);
1457 goto return1;
1458 }
1459 } else {
1460 goto error;
1461 }
1462 }
1463 }
1464 goto return0;
1465 }
1466 case XML_SCHEMAS_BOOLEAN: {
1467 const xmlChar *cur = value;
1468
1469 if ((cur[0] == '0') && (cur[1] == 0))
1470 ret = 0;
1471 else if ((cur[0] == '1') && (cur[1] == 0))
1472 ret = 1;
1473 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1474 (cur[3] == 'e') && (cur[4] == 0))
1475 ret = 1;
1476 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1477 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1478 ret = 0;
1479 else
1480 goto return1;
1481 if (val != NULL) {
1482 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1483 if (v != NULL) {
1484 v->value.b = ret;
1485 *val = v;
1486 } else {
1487 goto error;
1488 }
1489 }
1490 goto return0;
1491 }
1492 case XML_SCHEMAS_TOKEN: {
1493 const xmlChar *cur = value;
1494
1495 if (IS_BLANK(*cur))
1496 goto return1;
1497
1498 while (*cur != 0) {
1499 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1500 goto return1;
1501 } else if (*cur == ' ') {
1502 cur++;
1503 if (*cur == 0)
1504 goto return1;
1505 if (*cur == ' ')
1506 goto return1;
1507 } else {
1508 cur++;
1509 }
1510 }
1511 if (val != NULL) {
1512 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1513 if (v != NULL) {
1514 v->value.str = xmlStrdup(value);
1515 *val = v;
1516 } else {
1517 goto error;
1518 }
1519 }
1520 goto return0;
1521 }
1522 case XML_SCHEMAS_LANGUAGE:
1523 if (xmlCheckLanguageID(value) == 1) {
1524 if (val != NULL) {
1525 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
1526 if (v != NULL) {
1527 v->value.str = xmlStrdup(value);
1528 *val = v;
1529 } else {
1530 goto error;
1531 }
1532 }
1533 goto return0;
1534 }
1535 goto return1;
1536 case XML_SCHEMAS_NMTOKEN:
1537 if (xmlValidateNMToken(value, 1) == 0) {
1538 if (val != NULL) {
1539 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
1540 if (v != NULL) {
1541 v->value.str = xmlStrdup(value);
1542 *val = v;
1543 } else {
1544 goto error;
1545 }
1546 }
1547 goto return0;
1548 }
1549 goto return1;
1550 case XML_SCHEMAS_NMTOKENS:
1551 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1552 value, val, node);
1553 if (ret > 0)
1554 ret = 0;
1555 else
1556 ret = 1;
1557 goto done;
1558 case XML_SCHEMAS_NAME:
1559 ret = xmlValidateName(value, 1);
1560 if ((ret == 0) && (val != NULL)) {
1561 TODO;
1562 }
1563 goto done;
1564 case XML_SCHEMAS_QNAME:
1565 ret = xmlValidateQName(value, 1);
1566 if ((ret == 0) && (val != NULL)) {
1567 TODO;
1568 }
1569 goto done;
1570 case XML_SCHEMAS_NCNAME:
1571 ret = xmlValidateNCName(value, 1);
1572 if ((ret == 0) && (val != NULL)) {
1573 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
1574 if (v != NULL) {
1575 v->value.str = xmlStrdup(value);
1576 *val = v;
1577 } else {
1578 goto error;
1579 }
1580 }
1581 goto done;
1582 case XML_SCHEMAS_ID:
1583 ret = xmlValidateNCName(value, 1);
1584 if ((ret == 0) && (val != NULL)) {
1585 TODO;
1586 }
1587 if ((ret == 0) && (node != NULL) &&
1588 (node->type == XML_ATTRIBUTE_NODE)) {
1589 xmlAttrPtr attr = (xmlAttrPtr) node;
1590 /*
1591 * NOTE: the IDness might have already be declared in the DTD
1592 */
1593 if (attr->atype != XML_ATTRIBUTE_ID) {
1594 xmlIDPtr res;
1595 xmlChar *strip;
1596
1597 strip = xmlSchemaStrip(value);
1598 if (strip != NULL) {
1599 res = xmlAddID(NULL, node->doc, strip, attr);
1600 xmlFree(strip);
1601 } else
1602 res = xmlAddID(NULL, node->doc, value, attr);
1603 if (res == NULL) {
1604 ret = 2;
1605 } else {
1606 attr->atype = XML_ATTRIBUTE_ID;
1607 }
1608 }
1609 }
1610 goto done;
1611 case XML_SCHEMAS_IDREF:
1612 ret = xmlValidateNCName(value, 1);
1613 if ((ret == 0) && (val != NULL)) {
1614 TODO;
1615 }
1616 if ((ret == 0) && (node != NULL) &&
1617 (node->type == XML_ATTRIBUTE_NODE)) {
1618 xmlAttrPtr attr = (xmlAttrPtr) node;
1619 xmlChar *strip;
1620
1621 strip = xmlSchemaStrip(value);
1622 if (strip != NULL) {
1623 xmlAddRef(NULL, node->doc, strip, attr);
1624 xmlFree(strip);
1625 } else
1626 xmlAddRef(NULL, node->doc, value, attr);
1627 attr->atype = XML_ATTRIBUTE_IDREF;
1628 }
1629 goto done;
1630 case XML_SCHEMAS_IDREFS:
1631 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1632 value, val, node);
1633 if (ret < 0)
1634 ret = 2;
1635 else
1636 ret = 0;
1637 if ((ret == 0) && (node != NULL) &&
1638 (node->type == XML_ATTRIBUTE_NODE)) {
1639 xmlAttrPtr attr = (xmlAttrPtr) node;
1640
1641 attr->atype = XML_ATTRIBUTE_IDREFS;
1642 }
1643 goto done;
1644 case XML_SCHEMAS_ENTITY: {
1645 xmlChar *strip;
1646 ret = xmlValidateNCName(value, 1);
1647 if ((node == NULL) || (node->doc == NULL))
1648 ret = 3;
1649 if (ret == 0) {
1650 xmlEntityPtr ent;
1651
1652 strip = xmlSchemaStrip(value);
1653 if (strip != NULL) {
1654 ent = xmlGetDocEntity(node->doc, strip);
1655 xmlFree(strip);
1656 } else {
1657 ent = xmlGetDocEntity(node->doc, value);
1658 }
1659 if ((ent == NULL) ||
1660 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1661 ret = 4;
1662 }
1663 if ((ret == 0) && (val != NULL)) {
1664 TODO;
1665 }
1666 if ((ret == 0) && (node != NULL) &&
1667 (node->type == XML_ATTRIBUTE_NODE)) {
1668 xmlAttrPtr attr = (xmlAttrPtr) node;
1669
1670 attr->atype = XML_ATTRIBUTE_ENTITY;
1671 }
1672 goto done;
1673 }
1674 case XML_SCHEMAS_ENTITIES:
1675 if ((node == NULL) || (node->doc == NULL))
1676 goto return3;
1677 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1678 value, val, node);
1679 if (ret <= 0)
1680 ret = 1;
1681 else
1682 ret = 0;
1683 if ((ret == 0) && (node != NULL) &&
1684 (node->type == XML_ATTRIBUTE_NODE)) {
1685 xmlAttrPtr attr = (xmlAttrPtr) node;
1686
1687 attr->atype = XML_ATTRIBUTE_ENTITIES;
1688 }
1689 goto done;
1690 case XML_SCHEMAS_NOTATION:
1691 TODO;
1692 break;
1693 case XML_SCHEMAS_ANYURI: {
1694 xmlURIPtr uri;
1695
1696 uri = xmlParseURI((const char *) value);
1697 if (uri == NULL)
1698 goto return1;
1699 if (val != NULL) {
1700 TODO;
1701 }
1702 xmlFreeURI(uri);
1703 goto return0;
1704 }
1705 case XML_SCHEMAS_INTEGER: {
1706 const xmlChar *cur = value;
1707 unsigned long base = 0;
1708 int total = 0;
1709 int sign = 0;
1710 if (cur == NULL)
1711 goto return1;
1712 if (*cur == '-') {
1713 sign = 1;
1714 cur++;
1715 } else if (*cur == '+')
1716 cur++;
1717 while (*cur == '0') {
1718 total++;
1719 cur++;
1720 }
1721 while ((*cur >= '0') && (*cur <= '9')) {
1722 base = base * 10 + (*cur - '0');
1723 total++;
1724 cur++;
1725 }
1726 if (*cur != 0)
1727 goto return1;
1728 if ((sign == 1) && (total == 0))
1729 goto return1;
1730 if (val != NULL) {
1731 v = xmlSchemaNewValue(XML_SCHEMAS_INTEGER);
1732 if (v != NULL) {
1733 v->value.decimal.base = base;
1734 v->value.decimal.sign = sign;
1735 v->value.decimal.frac = 0;
1736 v->value.decimal.total = total;
1737 *val = v;
1738 }
1739 }
1740 goto return0;
1741 }
1742 case XML_SCHEMAS_NPINTEGER: {
1743 const xmlChar *cur = value;
1744 unsigned long base = 0;
1745 int total = 0;
1746 int sign = 0;
1747 if (cur == NULL)
1748 goto return1;
1749 if (*cur == '-') {
1750 sign = 1;
1751 cur++;
1752 }
1753 while ((*cur >= '0') && (*cur <= '9')) {
1754 base = base * 10 + (*cur - '0');
1755 total++;
1756 cur++;
1757 }
1758 if (*cur != 0)
1759 goto return1;
1760 if ((sign != 1) && (base != 0))
1761 goto return1;
1762 if (val != NULL) {
1763 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1764 if (v != NULL) {
1765 v->value.decimal.base = base;
1766 v->value.decimal.sign = 0;
1767 v->value.decimal.frac = 0;
1768 v->value.decimal.total = total;
1769 *val = v;
1770 }
1771 }
1772 goto return0;
1773 }
1774 case XML_SCHEMAS_NINTEGER:
1775 TODO;
1776 break;
1777 case XML_SCHEMAS_NNINTEGER: {
1778 const xmlChar *cur = value;
1779 unsigned long base = 0;
1780 int total = 0;
1781 int sign = 0;
1782 if (cur == NULL)
1783 goto return1;
1784 if (*cur == '-') {
1785 sign = 1;
1786 cur++;
1787 }
1788 while ((*cur >= '0') && (*cur <= '9')) {
1789 base = base * 10 + (*cur - '0');
1790 total++;
1791 cur++;
1792 }
1793 if (*cur != 0)
1794 goto return1;
1795 if ((sign == 1) && (base != 0))
1796 goto return1;
1797 if (val != NULL) {
1798 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1799 if (v != NULL) {
1800 v->value.decimal.base = base;
1801 v->value.decimal.sign = 0;
1802 v->value.decimal.frac = 0;
1803 v->value.decimal.total = total;
1804 *val = v;
1805 }
1806 }
1807 goto return0;
1808 }
1809 case XML_SCHEMAS_PINTEGER: {
1810 const xmlChar *cur = value;
1811 unsigned long base = 0;
1812 int total = 0;
1813 if (cur == NULL)
1814 goto return1;
1815 if (*cur == '+')
1816 cur++;
1817 while ((*cur >= '0') && (*cur <= '9')) {
1818 base = base * 10 + (*cur - '0');
1819 total++;
1820 cur++;
1821 }
1822 if (*cur != 0)
1823 goto return1;
1824 if (val != NULL) {
1825 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1826 if (v != NULL) {
1827 v->value.decimal.base = base;
1828 v->value.decimal.sign = 0;
1829 v->value.decimal.frac = 0;
1830 v->value.decimal.total = total;
1831 *val = v;
1832 }
1833 }
1834 goto return0;
1835 }
1836 case XML_SCHEMAS_INT: {
1837 const xmlChar *cur = value;
1838 unsigned long base = 0;
1839 int total = 0;
1840 int sign = 0;
1841 if (cur == NULL)
1842 goto return1;
1843 if (*cur == '-') {
1844 sign = 1;
1845 cur++;
1846 } else if (*cur == '+')
1847 cur++;
1848 while (*cur == '0') {
1849 total++;
1850 cur++;
1851 }
1852 while ((*cur >= '0') && (*cur <= '9')) {
1853 base = base * 10 + (*cur - '0');
1854 total++;
1855 cur++;
1856 }
1857 if (*cur != 0)
1858 goto return1;
1859 if ((sign == 1) && (total == 0))
1860 goto return1;
1861 if (val != NULL) {
1862 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1863 if (v != NULL) {
1864 v->value.decimal.base = base;
1865 v->value.decimal.sign = sign;
1866 v->value.decimal.frac = 0;
1867 v->value.decimal.total = total;
1868 *val = v;
1869 }
1870 }
1871 goto return0;
1872 }
1873 case XML_SCHEMAS_UINT:
1874 TODO;
1875 break;
1876 case XML_SCHEMAS_LONG:
1877 TODO;
1878 break;
1879 case XML_SCHEMAS_ULONG:
1880 TODO;
1881 break;
1882 case XML_SCHEMAS_SHORT:
1883 TODO;
1884 break;
1885 case XML_SCHEMAS_USHORT:
1886 TODO;
1887 break;
1888 case XML_SCHEMAS_BYTE:
1889 TODO;
1890 break;
1891 case XML_SCHEMAS_UBYTE:
1892 TODO;
1893 break;
1894 }
1895
1896done:
1897 if (norm != NULL) xmlFree(norm);
1898 return(ret);
1899return3:
1900 if (norm != NULL) xmlFree(norm);
1901 return(3);
1902return1:
1903 if (norm != NULL) xmlFree(norm);
1904 return(1);
1905return0:
1906 if (norm != NULL) xmlFree(norm);
1907 return(0);
1908error:
1909 if (norm != NULL) xmlFree(norm);
1910 return(-1);
1911}
1912
1913/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001914 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00001915 * @type: the predefined type
1916 * @value: the value to check
1917 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001918 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00001919 *
1920 * Check that a value conforms to the lexical space of the predefined type.
1921 * if true a value is computed and returned in @val.
1922 *
1923 * Returns 0 if this validates, a positive error code number otherwise
1924 * and -1 in case of internal or API error.
1925 */
1926int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001927xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
1928 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001929 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00001930}
1931
1932/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001933 * xmlSchemaValidatePredefinedType:
1934 * @type: the predefined type
1935 * @value: the value to check
1936 * @val: the return computed value
1937 *
1938 * Check that a value conforms to the lexical space of the predefined type.
1939 * if true a value is computed and returned in @val.
1940 *
1941 * Returns 0 if this validates, a positive error code number otherwise
1942 * and -1 in case of internal or API error.
1943 */
1944int
1945xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1946 xmlSchemaValPtr *val) {
1947 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
1948}
1949
1950/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001951 * xmlSchemaCompareDecimals:
1952 * @x: a first decimal value
1953 * @y: a second decimal value
1954 *
1955 * Compare 2 decimals
1956 *
1957 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1958 */
1959static int
1960xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1961{
1962 xmlSchemaValPtr swp;
1963 int order = 1;
1964 unsigned long tmp;
1965
Daniel Veillard80b19092003-03-28 13:29:53 +00001966 if ((x->value.decimal.sign) && (x->value.decimal.base != 0)) {
1967 if ((y->value.decimal.sign) && (y->value.decimal.base != 0))
1968 order = -1;
1969 else
1970 return (-1);
1971 } else if ((y->value.decimal.sign) && (y->value.decimal.base != 0)) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001972 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00001973 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001974 if (x->value.decimal.frac == y->value.decimal.frac) {
1975 if (x->value.decimal.base < y->value.decimal.base)
Daniel Veillard80b19092003-03-28 13:29:53 +00001976 return (-order);
1977 if (x->value.decimal.base > y->value.decimal.base)
1978 return(order);
1979 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001980 }
1981 if (y->value.decimal.frac > x->value.decimal.frac) {
1982 swp = y;
1983 y = x;
1984 x = swp;
1985 order = -order;
1986 }
1987 tmp =
1988 x->value.decimal.base / powten[x->value.decimal.frac -
1989 y->value.decimal.frac];
1990 if (tmp > y->value.decimal.base)
1991 return (order);
1992 if (tmp < y->value.decimal.base)
1993 return (-order);
1994 tmp =
1995 y->value.decimal.base * powten[x->value.decimal.frac -
1996 y->value.decimal.frac];
1997 if (x->value.decimal.base < tmp)
1998 return (-order);
1999 if (x->value.decimal.base == tmp)
2000 return (0);
2001 return (order);
2002}
2003
2004/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002005 * xmlSchemaCompareDurations:
2006 * @x: a first duration value
2007 * @y: a second duration value
2008 *
2009 * Compare 2 durations
2010 *
2011 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2012 * case of error
2013 */
2014static int
2015xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2016{
2017 long carry, mon, day;
2018 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002019 int invert = 1;
2020 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002021 static const long dayRange [2][12] = {
2022 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2023 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2024
2025 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002026 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002027
2028 /* months */
2029 mon = x->value.dur.mon - y->value.dur.mon;
2030
2031 /* seconds */
2032 sec = x->value.dur.sec - y->value.dur.sec;
2033 carry = (long)sec / SECS_PER_DAY;
2034 sec -= (double)(carry * SECS_PER_DAY);
2035
2036 /* days */
2037 day = x->value.dur.day - y->value.dur.day + carry;
2038
2039 /* easy test */
2040 if (mon == 0) {
2041 if (day == 0)
2042 if (sec == 0.0)
2043 return 0;
2044 else if (sec < 0.0)
2045 return -1;
2046 else
2047 return 1;
2048 else if (day < 0)
2049 return -1;
2050 else
2051 return 1;
2052 }
2053
2054 if (mon > 0) {
2055 if ((day >= 0) && (sec >= 0.0))
2056 return 1;
2057 else {
2058 xmon = mon;
2059 xday = -day;
2060 }
2061 } else if ((day <= 0) && (sec <= 0.0)) {
2062 return -1;
2063 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002064 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002065 xmon = -mon;
2066 xday = day;
2067 }
2068
2069 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002070 if (myear == 0) {
2071 minday = 0;
2072 maxday = 0;
2073 } else {
2074 maxday = 366 * ((myear + 3) / 4) +
2075 365 * ((myear - 1) % 4);
2076 minday = maxday - 1;
2077 }
2078
Daniel Veillard070803b2002-05-03 07:29:38 +00002079 xmon = xmon % 12;
2080 minday += dayRange[0][xmon];
2081 maxday += dayRange[1][xmon];
2082
Daniel Veillard80b19092003-03-28 13:29:53 +00002083 if ((maxday == minday) && (maxday == xday))
2084 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002085 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002086 return(-invert);
2087 if (minday > xday)
2088 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002089
2090 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002091 return 2;
2092}
2093
2094/*
2095 * macros for adding date/times and durations
2096 */
2097#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2098#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2099#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2100#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2101
2102/**
2103 * _xmlSchemaDateAdd:
2104 * @dt: an #xmlSchemaValPtr
2105 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2106 *
2107 * Compute a new date/time from @dt and @dur. This function assumes @dt
2108 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
2109 * or #XML_SCHEMAS_GYEAR.
2110 *
2111 * Returns date/time pointer or NULL.
2112 */
2113static xmlSchemaValPtr
2114_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2115{
2116 xmlSchemaValPtr ret;
2117 long carry, tempdays, temp;
2118 xmlSchemaValDatePtr r, d;
2119 xmlSchemaValDurationPtr u;
2120
2121 if ((dt == NULL) || (dur == NULL))
2122 return NULL;
2123
2124 ret = xmlSchemaNewValue(dt->type);
2125 if (ret == NULL)
2126 return NULL;
2127
2128 r = &(ret->value.date);
2129 d = &(dt->value.date);
2130 u = &(dur->value.dur);
2131
2132 /* normalization */
2133 if (d->mon == 0)
2134 d->mon = 1;
2135
2136 /* normalize for time zone offset */
2137 u->sec -= (d->tzo * 60);
2138 d->tzo = 0;
2139
2140 /* normalization */
2141 if (d->day == 0)
2142 d->day = 1;
2143
2144 /* month */
2145 carry = d->mon + u->mon;
2146 r->mon = MODULO_RANGE(carry, 1, 13);
2147 carry = FQUOTIENT_RANGE(carry, 1, 13);
2148
2149 /* year (may be modified later) */
2150 r->year = d->year + carry;
2151 if (r->year == 0) {
2152 if (d->year > 0)
2153 r->year--;
2154 else
2155 r->year++;
2156 }
2157
2158 /* time zone */
2159 r->tzo = d->tzo;
2160 r->tz_flag = d->tz_flag;
2161
2162 /* seconds */
2163 r->sec = d->sec + u->sec;
2164 carry = FQUOTIENT((long)r->sec, 60);
2165 if (r->sec != 0.0) {
2166 r->sec = MODULO(r->sec, 60.0);
2167 }
2168
2169 /* minute */
2170 carry += d->min;
2171 r->min = MODULO(carry, 60);
2172 carry = FQUOTIENT(carry, 60);
2173
2174 /* hours */
2175 carry += d->hour;
2176 r->hour = MODULO(carry, 24);
2177 carry = FQUOTIENT(carry, 24);
2178
2179 /*
2180 * days
2181 * Note we use tempdays because the temporary values may need more
2182 * than 5 bits
2183 */
2184 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2185 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2186 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2187 else if (d->day < 1)
2188 tempdays = 1;
2189 else
2190 tempdays = d->day;
2191
2192 tempdays += u->day + carry;
2193
2194 while (1) {
2195 if (tempdays < 1) {
2196 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
2197 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
2198 if (tyr == 0)
2199 tyr--;
2200 tempdays += MAX_DAYINMONTH(tyr, tmon);
2201 carry = -1;
2202 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
2203 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
2204 carry = 1;
2205 } else
2206 break;
2207
2208 temp = r->mon + carry;
2209 r->mon = MODULO_RANGE(temp, 1, 13);
2210 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
2211 if (r->year == 0) {
2212 if (temp < 1)
2213 r->year--;
2214 else
2215 r->year++;
2216 }
2217 }
2218
2219 r->day = tempdays;
2220
2221 /*
2222 * adjust the date/time type to the date values
2223 */
2224 if (ret->type != XML_SCHEMAS_DATETIME) {
2225 if ((r->hour) || (r->min) || (r->sec))
2226 ret->type = XML_SCHEMAS_DATETIME;
2227 else if (ret->type != XML_SCHEMAS_DATE) {
2228 if ((r->mon != 1) && (r->day != 1))
2229 ret->type = XML_SCHEMAS_DATE;
2230 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2231 ret->type = XML_SCHEMAS_GYEARMONTH;
2232 }
2233 }
2234
2235 return ret;
2236}
2237
2238/**
2239 * xmlSchemaDupVal:
2240 * @v: value to duplicate
2241 *
2242 * returns a duplicated value.
2243 */
2244static xmlSchemaValPtr
2245xmlSchemaDupVal (xmlSchemaValPtr v)
2246{
2247 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2248 if (ret == NULL)
2249 return ret;
2250
2251 memcpy(ret, v, sizeof(xmlSchemaVal));
2252 return ret;
2253}
2254
2255/**
2256 * xmlSchemaDateNormalize:
2257 * @dt: an #xmlSchemaValPtr
2258 *
2259 * Normalize @dt to GMT time.
2260 *
2261 */
2262static xmlSchemaValPtr
2263xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2264{
2265 xmlSchemaValPtr dur, ret;
2266
2267 if (dt == NULL)
2268 return NULL;
2269
2270 if (((dt->type != XML_SCHEMAS_TIME) &&
2271 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2272 return xmlSchemaDupVal(dt);
2273
2274 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2275 if (dur == NULL)
2276 return NULL;
2277
2278 dur->value.date.sec -= offset;
2279
2280 ret = _xmlSchemaDateAdd(dt, dur);
2281 if (ret == NULL)
2282 return NULL;
2283
2284 xmlSchemaFreeValue(dur);
2285
2286 /* ret->value.date.tzo = 0; */
2287 return ret;
2288}
2289
2290/**
2291 * _xmlSchemaDateCastYMToDays:
2292 * @dt: an #xmlSchemaValPtr
2293 *
2294 * Convert mon and year of @dt to total number of days. Take the
2295 * number of years since (or before) 1 AD and add the number of leap
2296 * years. This is a function because negative
2297 * years must be handled a little differently and there is no zero year.
2298 *
2299 * Returns number of days.
2300 */
2301static long
2302_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2303{
2304 long ret;
2305
2306 if (dt->value.date.year < 0)
2307 ret = (dt->value.date.year * 365) +
2308 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2309 ((dt->value.date.year+1)/400)) +
2310 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2311 else
2312 ret = ((dt->value.date.year-1) * 365) +
2313 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2314 ((dt->value.date.year-1)/400)) +
2315 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2316
2317 return ret;
2318}
2319
2320/**
2321 * TIME_TO_NUMBER:
2322 * @dt: an #xmlSchemaValPtr
2323 *
2324 * Calculates the number of seconds in the time portion of @dt.
2325 *
2326 * Returns seconds.
2327 */
2328#define TIME_TO_NUMBER(dt) \
2329 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
2330 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
2331
2332/**
2333 * xmlSchemaCompareDates:
2334 * @x: a first date/time value
2335 * @y: a second date/time value
2336 *
2337 * Compare 2 date/times
2338 *
2339 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2340 * case of error
2341 */
2342static int
2343xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2344{
2345 unsigned char xmask, ymask, xor_mask, and_mask;
2346 xmlSchemaValPtr p1, p2, q1, q2;
2347 long p1d, p2d, q1d, q2d;
2348
2349 if ((x == NULL) || (y == NULL))
2350 return -2;
2351
2352 if (x->value.date.tz_flag) {
2353
2354 if (!y->value.date.tz_flag) {
2355 p1 = xmlSchemaDateNormalize(x, 0);
2356 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2357 /* normalize y + 14:00 */
2358 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2359
2360 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002361 if (p1d < q1d) {
2362 xmlSchemaFreeValue(p1);
2363 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002364 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002365 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002366 double sec;
2367
2368 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002369 if (sec < 0.0) {
2370 xmlSchemaFreeValue(p1);
2371 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002372 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002373 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002374 /* normalize y - 14:00 */
2375 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2376 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002377 xmlSchemaFreeValue(p1);
2378 xmlSchemaFreeValue(q1);
2379 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002380 if (p1d > q2d)
2381 return 1;
2382 else if (p1d == q2d) {
2383 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2384 if (sec > 0.0)
2385 return 1;
2386 else
2387 return 2; /* indeterminate */
2388 }
2389 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002390 } else {
2391 xmlSchemaFreeValue(p1);
2392 xmlSchemaFreeValue(q1);
2393 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002394 }
2395 } else if (y->value.date.tz_flag) {
2396 q1 = xmlSchemaDateNormalize(y, 0);
2397 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2398
2399 /* normalize x - 14:00 */
2400 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2401 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2402
Daniel Veillardfdc91562002-07-01 21:52:03 +00002403 if (p1d < q1d) {
2404 xmlSchemaFreeValue(p1);
2405 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002406 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002407 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002408 double sec;
2409
2410 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002411 if (sec < 0.0) {
2412 xmlSchemaFreeValue(p1);
2413 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002414 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002415 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002416 /* normalize x + 14:00 */
2417 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2418 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2419
Daniel Veillard6560a422003-03-27 21:25:38 +00002420 if (p2d > q1d) {
2421 xmlSchemaFreeValue(p1);
2422 xmlSchemaFreeValue(q1);
2423 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002424 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002425 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002426 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002427 xmlSchemaFreeValue(p1);
2428 xmlSchemaFreeValue(q1);
2429 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002430 if (sec > 0.0)
2431 return 1;
2432 else
2433 return 2; /* indeterminate */
2434 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002435 xmlSchemaFreeValue(p1);
2436 xmlSchemaFreeValue(q1);
2437 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002438 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002439 } else {
2440 xmlSchemaFreeValue(p1);
2441 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002442 }
2443 }
2444
2445 /*
2446 * if the same type then calculate the difference
2447 */
2448 if (x->type == y->type) {
2449 q1 = xmlSchemaDateNormalize(y, 0);
2450 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2451
2452 p1 = xmlSchemaDateNormalize(x, 0);
2453 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2454
Daniel Veillardfdc91562002-07-01 21:52:03 +00002455 if (p1d < q1d) {
2456 xmlSchemaFreeValue(p1);
2457 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002458 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002459 } else if (p1d > q1d) {
2460 xmlSchemaFreeValue(p1);
2461 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002462 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002463 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002464 double sec;
2465
2466 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002467 xmlSchemaFreeValue(p1);
2468 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002469 if (sec < 0.0)
2470 return -1;
2471 else if (sec > 0.0)
2472 return 1;
2473
2474 }
2475 return 0;
2476 }
2477
2478 switch (x->type) {
2479 case XML_SCHEMAS_DATETIME:
2480 xmask = 0xf;
2481 break;
2482 case XML_SCHEMAS_DATE:
2483 xmask = 0x7;
2484 break;
2485 case XML_SCHEMAS_GYEAR:
2486 xmask = 0x1;
2487 break;
2488 case XML_SCHEMAS_GMONTH:
2489 xmask = 0x2;
2490 break;
2491 case XML_SCHEMAS_GDAY:
2492 xmask = 0x3;
2493 break;
2494 case XML_SCHEMAS_GYEARMONTH:
2495 xmask = 0x3;
2496 break;
2497 case XML_SCHEMAS_GMONTHDAY:
2498 xmask = 0x6;
2499 break;
2500 case XML_SCHEMAS_TIME:
2501 xmask = 0x8;
2502 break;
2503 default:
2504 xmask = 0;
2505 break;
2506 }
2507
2508 switch (y->type) {
2509 case XML_SCHEMAS_DATETIME:
2510 ymask = 0xf;
2511 break;
2512 case XML_SCHEMAS_DATE:
2513 ymask = 0x7;
2514 break;
2515 case XML_SCHEMAS_GYEAR:
2516 ymask = 0x1;
2517 break;
2518 case XML_SCHEMAS_GMONTH:
2519 ymask = 0x2;
2520 break;
2521 case XML_SCHEMAS_GDAY:
2522 ymask = 0x3;
2523 break;
2524 case XML_SCHEMAS_GYEARMONTH:
2525 ymask = 0x3;
2526 break;
2527 case XML_SCHEMAS_GMONTHDAY:
2528 ymask = 0x6;
2529 break;
2530 case XML_SCHEMAS_TIME:
2531 ymask = 0x8;
2532 break;
2533 default:
2534 ymask = 0;
2535 break;
2536 }
2537
2538 xor_mask = xmask ^ ymask; /* mark type differences */
2539 and_mask = xmask & ymask; /* mark field specification */
2540
2541 /* year */
2542 if (xor_mask & 1)
2543 return 2; /* indeterminate */
2544 else if (and_mask & 1) {
2545 if (x->value.date.year < y->value.date.year)
2546 return -1;
2547 else if (x->value.date.year > y->value.date.year)
2548 return 1;
2549 }
2550
2551 /* month */
2552 if (xor_mask & 2)
2553 return 2; /* indeterminate */
2554 else if (and_mask & 2) {
2555 if (x->value.date.mon < y->value.date.mon)
2556 return -1;
2557 else if (x->value.date.mon > y->value.date.mon)
2558 return 1;
2559 }
2560
2561 /* day */
2562 if (xor_mask & 4)
2563 return 2; /* indeterminate */
2564 else if (and_mask & 4) {
2565 if (x->value.date.day < y->value.date.day)
2566 return -1;
2567 else if (x->value.date.day > y->value.date.day)
2568 return 1;
2569 }
2570
2571 /* time */
2572 if (xor_mask & 8)
2573 return 2; /* indeterminate */
2574 else if (and_mask & 8) {
2575 if (x->value.date.hour < y->value.date.hour)
2576 return -1;
2577 else if (x->value.date.hour > y->value.date.hour)
2578 return 1;
2579 else if (x->value.date.min < y->value.date.min)
2580 return -1;
2581 else if (x->value.date.min > y->value.date.min)
2582 return 1;
2583 else if (x->value.date.sec < y->value.date.sec)
2584 return -1;
2585 else if (x->value.date.sec > y->value.date.sec)
2586 return 1;
2587 }
2588
Daniel Veillard070803b2002-05-03 07:29:38 +00002589 return 0;
2590}
2591
2592/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00002593 * xmlSchemaCompareNormStrings:
2594 * @x: a first string value
2595 * @y: a second string value
2596 *
2597 * Compare 2 string for their normalized values.
2598 *
2599 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
2600 * case of error
2601 */
2602static int
2603xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2604 const xmlChar *utf1;
2605 const xmlChar *utf2;
2606 int tmp;
2607
2608 if ((x == NULL) || (y == NULL))
2609 return(-2);
2610 utf1 = x->value.str;
2611 utf2 = y->value.str;
2612
2613 while (IS_BLANK(*utf1)) utf1++;
2614 while (IS_BLANK(*utf2)) utf2++;
2615 while ((*utf1 != 0) && (*utf2 != 0)) {
2616 if (IS_BLANK(*utf1)) {
2617 if (!IS_BLANK(*utf2)) {
2618 tmp = *utf1 - *utf2;
2619 return(tmp);
2620 }
2621 while (IS_BLANK(*utf1)) utf1++;
2622 while (IS_BLANK(*utf2)) utf2++;
2623 } else {
2624 tmp = *utf1++ - *utf2++;
2625 if (tmp < 0)
2626 return(-1);
2627 if (tmp > 0)
2628 return(1);
2629 }
2630 }
2631 if (*utf1 != 0) {
2632 while (IS_BLANK(*utf1)) utf1++;
2633 if (*utf1 != 0)
2634 return(1);
2635 }
2636 if (*utf2 != 0) {
2637 while (IS_BLANK(*utf2)) utf2++;
2638 if (*utf2 != 0)
2639 return(-1);
2640 }
2641 return(0);
2642}
2643
2644/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002645 * xmlSchemaCompareFloats:
2646 * @x: a first float or double value
2647 * @y: a second float or double value
2648 *
2649 * Compare 2 values
2650 *
2651 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2652 * case of error
2653 */
2654static int
2655xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2656 double d1, d2;
2657
2658 if ((x == NULL) || (y == NULL))
2659 return(-2);
2660
2661 /*
2662 * Cast everything to doubles.
2663 */
2664 if (x->type == XML_SCHEMAS_DOUBLE)
2665 d1 = x->value.d;
2666 else if (x->type == XML_SCHEMAS_FLOAT)
2667 d1 = x->value.f;
2668 else
2669 return(-2);
2670
2671 if (y->type == XML_SCHEMAS_DOUBLE)
2672 d2 = y->value.d;
2673 else if (y->type == XML_SCHEMAS_FLOAT)
2674 d2 = y->value.f;
2675 else
2676 return(-2);
2677
2678 /*
2679 * Check for special cases.
2680 */
2681 if (xmlXPathIsNaN(d1)) {
2682 if (xmlXPathIsNaN(d2))
2683 return(0);
2684 return(1);
2685 }
2686 if (xmlXPathIsNaN(d2))
2687 return(-1);
2688 if (d1 == xmlXPathPINF) {
2689 if (d2 == xmlXPathPINF)
2690 return(0);
2691 return(1);
2692 }
2693 if (d2 == xmlXPathPINF)
2694 return(-1);
2695 if (d1 == xmlXPathNINF) {
2696 if (d2 == xmlXPathNINF)
2697 return(0);
2698 return(-1);
2699 }
2700 if (d2 == xmlXPathNINF)
2701 return(1);
2702
2703 /*
2704 * basic tests, the last one we should have equality, but
2705 * portability is more important than speed and handling
2706 * NaN or Inf in a portable way is always a challenge, so ...
2707 */
2708 if (d1 < d2)
2709 return(-1);
2710 if (d1 > d2)
2711 return(1);
2712 if (d1 == d2)
2713 return(0);
2714 return(2);
2715}
2716
2717/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002718 * xmlSchemaCompareValues:
2719 * @x: a first value
2720 * @y: a second value
2721 *
2722 * Compare 2 values
2723 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002724 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2725 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002726 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002727int
Daniel Veillard4255d502002-04-16 15:50:10 +00002728xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2729 if ((x == NULL) || (y == NULL))
2730 return(-2);
2731
2732 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002733 case XML_SCHEMAS_UNKNOWN:
2734 return(-2);
2735 case XML_SCHEMAS_INTEGER:
2736 case XML_SCHEMAS_NPINTEGER:
2737 case XML_SCHEMAS_NINTEGER:
2738 case XML_SCHEMAS_NNINTEGER:
2739 case XML_SCHEMAS_PINTEGER:
2740 case XML_SCHEMAS_INT:
2741 case XML_SCHEMAS_UINT:
2742 case XML_SCHEMAS_LONG:
2743 case XML_SCHEMAS_ULONG:
2744 case XML_SCHEMAS_SHORT:
2745 case XML_SCHEMAS_USHORT:
2746 case XML_SCHEMAS_BYTE:
2747 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00002748 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00002749 if (y->type == x->type)
2750 return(xmlSchemaCompareDecimals(x, y));
2751 if ((y->type == XML_SCHEMAS_DECIMAL) ||
2752 (y->type == XML_SCHEMAS_INTEGER) ||
2753 (y->type == XML_SCHEMAS_NPINTEGER) ||
2754 (y->type == XML_SCHEMAS_NINTEGER) ||
2755 (y->type == XML_SCHEMAS_NNINTEGER) ||
2756 (y->type == XML_SCHEMAS_PINTEGER) ||
2757 (y->type == XML_SCHEMAS_INT) ||
2758 (y->type == XML_SCHEMAS_UINT) ||
2759 (y->type == XML_SCHEMAS_LONG) ||
2760 (y->type == XML_SCHEMAS_ULONG) ||
2761 (y->type == XML_SCHEMAS_SHORT) ||
2762 (y->type == XML_SCHEMAS_USHORT) ||
2763 (y->type == XML_SCHEMAS_BYTE) ||
2764 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00002765 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002766 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002767 case XML_SCHEMAS_DURATION:
2768 if (y->type == XML_SCHEMAS_DURATION)
2769 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002770 return(-2);
2771 case XML_SCHEMAS_TIME:
2772 case XML_SCHEMAS_GDAY:
2773 case XML_SCHEMAS_GMONTH:
2774 case XML_SCHEMAS_GMONTHDAY:
2775 case XML_SCHEMAS_GYEAR:
2776 case XML_SCHEMAS_GYEARMONTH:
2777 case XML_SCHEMAS_DATE:
2778 case XML_SCHEMAS_DATETIME:
2779 if ((y->type == XML_SCHEMAS_DATETIME) ||
2780 (y->type == XML_SCHEMAS_TIME) ||
2781 (y->type == XML_SCHEMAS_GDAY) ||
2782 (y->type == XML_SCHEMAS_GMONTH) ||
2783 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2784 (y->type == XML_SCHEMAS_GYEAR) ||
2785 (y->type == XML_SCHEMAS_DATE) ||
2786 (y->type == XML_SCHEMAS_GYEARMONTH))
2787 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002788 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002789 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00002790 case XML_SCHEMAS_TOKEN:
2791 case XML_SCHEMAS_LANGUAGE:
2792 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00002793 case XML_SCHEMAS_NAME:
2794 case XML_SCHEMAS_QNAME:
2795 case XML_SCHEMAS_NCNAME:
2796 case XML_SCHEMAS_ID:
2797 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00002798 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00002799 case XML_SCHEMAS_NOTATION:
2800 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00002801 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
2802 (y->type == XML_SCHEMAS_TOKEN) ||
2803 (y->type == XML_SCHEMAS_LANGUAGE) ||
2804 (y->type == XML_SCHEMAS_NMTOKEN) ||
2805 (y->type == XML_SCHEMAS_NAME) ||
2806 (y->type == XML_SCHEMAS_QNAME) ||
2807 (y->type == XML_SCHEMAS_NCNAME) ||
2808 (y->type == XML_SCHEMAS_ID) ||
2809 (y->type == XML_SCHEMAS_IDREF) ||
2810 (y->type == XML_SCHEMAS_ENTITY) ||
2811 (y->type == XML_SCHEMAS_NOTATION) ||
2812 (y->type == XML_SCHEMAS_ANYURI))
2813 return (xmlSchemaCompareNormStrings(x, y));
2814 return (-2);
2815
2816 case XML_SCHEMAS_FLOAT:
2817 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002818 if ((y->type == XML_SCHEMAS_FLOAT) ||
2819 (y->type == XML_SCHEMAS_DOUBLE))
2820 return (xmlSchemaCompareFloats(x, y));
2821 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002822 TODO
Daniel Veillardc4c21552003-03-29 10:53:38 +00002823 break;
2824 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002825 if (y->type == XML_SCHEMAS_BOOLEAN) {
2826 if (x->value.b == y->value.b)
2827 return(0);
2828 if (x->value.b == 0)
2829 return(-1);
2830 return(1);
2831 }
2832 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00002833 case XML_SCHEMAS_STRING:
2834 case XML_SCHEMAS_IDREFS:
2835 case XML_SCHEMAS_ENTITIES:
2836 case XML_SCHEMAS_NMTOKENS:
2837 TODO
2838 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00002839 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002840 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002841}
2842
2843/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00002844 * xmlSchemaNormLen:
2845 * @value: a string
2846 *
2847 * Computes the UTF8 length of the normalized value of the string
2848 *
2849 * Returns the length or -1 in case of error.
2850 */
2851static int
2852xmlSchemaNormLen(const xmlChar *value) {
2853 const xmlChar *utf;
2854 int ret = 0;
2855
2856 if (value == NULL)
2857 return(-1);
2858 utf = value;
2859 while (IS_BLANK(*utf)) utf++;
2860 while (*utf != 0) {
2861 if (utf[0] & 0x80) {
2862 if ((utf[1] & 0xc0) != 0x80)
2863 return(-1);
2864 if ((utf[0] & 0xe0) == 0xe0) {
2865 if ((utf[2] & 0xc0) != 0x80)
2866 return(-1);
2867 if ((utf[0] & 0xf0) == 0xf0) {
2868 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
2869 return(-1);
2870 utf += 4;
2871 } else {
2872 utf += 3;
2873 }
2874 } else {
2875 utf += 2;
2876 }
2877 } else if (IS_BLANK(*utf)) {
2878 while (IS_BLANK(*utf)) utf++;
2879 if (*utf == 0)
2880 break;
2881 } else {
2882 utf++;
2883 }
2884 ret++;
2885 }
2886 return(ret);
2887}
2888
2889/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002890 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002891 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002892 * @facet: the facet to check
2893 * @value: the lexical repr of the value to validate
2894 * @val: the precomputed value
2895 *
2896 * Check a value against a facet condition
2897 *
2898 * Returns 0 if the element is schemas valid, a positive error code
2899 * number otherwise and -1 in case of internal or API error.
2900 */
2901int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002902xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002903 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002904 const xmlChar *value, xmlSchemaValPtr val)
2905{
2906 int ret;
2907
2908 switch (facet->type) {
2909 case XML_SCHEMA_FACET_PATTERN:
2910 ret = xmlRegexpExec(facet->regexp, value);
2911 if (ret == 1)
2912 return(0);
2913 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002914 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002915 return(1);
2916 }
2917 return(ret);
2918 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2919 ret = xmlSchemaCompareValues(val, facet->val);
2920 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002921 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002922 return(-1);
2923 }
2924 if (ret == -1)
2925 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002926 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002927 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002928 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2929 ret = xmlSchemaCompareValues(val, facet->val);
2930 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002931 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002932 return(-1);
2933 }
2934 if ((ret == -1) || (ret == 0))
2935 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002936 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002937 return(1);
2938 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2939 ret = xmlSchemaCompareValues(val, facet->val);
2940 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002941 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002942 return(-1);
2943 }
2944 if (ret == 1)
2945 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002946 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002947 return(1);
2948 case XML_SCHEMA_FACET_MININCLUSIVE:
2949 ret = xmlSchemaCompareValues(val, facet->val);
2950 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002951 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002952 return(-1);
2953 }
2954 if ((ret == 1) || (ret == 0))
2955 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002956 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002957 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002958 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002959 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00002960 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00002961 case XML_SCHEMA_FACET_ENUMERATION:
2962 if ((facet->value != NULL) &&
2963 (xmlStrEqual(facet->value, value)))
2964 return(0);
2965 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002966 case XML_SCHEMA_FACET_LENGTH:
2967 case XML_SCHEMA_FACET_MAXLENGTH:
2968 case XML_SCHEMA_FACET_MINLENGTH: {
2969 unsigned int len = 0;
2970
2971 if ((facet->val == NULL) ||
2972 (facet->val->type != XML_SCHEMAS_DECIMAL) ||
2973 (facet->val->value.decimal.frac != 0)) {
2974 return(-1);
2975 }
2976 switch (base->flags) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00002977 case XML_SCHEMAS_IDREF:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002978 case XML_SCHEMAS_NORMSTRING:
2979 case XML_SCHEMAS_TOKEN:
2980 case XML_SCHEMAS_LANGUAGE:
2981 case XML_SCHEMAS_NMTOKEN:
2982 case XML_SCHEMAS_NAME:
2983 case XML_SCHEMAS_NCNAME:
2984 case XML_SCHEMAS_ID:
Daniel Veillardc4c21552003-03-29 10:53:38 +00002985 len = xmlSchemaNormLen(value);
2986 break;
2987 case XML_SCHEMAS_STRING:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002988 len = xmlUTF8Strlen(value);
2989 break;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002990 default:
2991 TODO
2992 }
2993 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
2994 if (len != facet->val->value.decimal.base)
2995 return(1);
2996 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
2997 if (len < facet->val->value.decimal.base)
2998 return(1);
2999 } else {
3000 if (len > facet->val->value.decimal.base)
3001 return(1);
3002 }
3003 break;
3004 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003005 default:
3006 TODO
3007 }
3008 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003009
Daniel Veillard4255d502002-04-16 15:50:10 +00003010}
3011
3012#endif /* LIBXML_SCHEMAS_ENABLED */