blob: 79cf8334f218d35271f74fd0d987617205e3dac3 [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 */
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000120 unsigned long lo;
121 unsigned long mi;
122 unsigned long hi;
Daniel Veillard4255d502002-04-16 15:50:10 +0000123 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +0000124 unsigned int sign:1;
Daniel Veillard4255d502002-04-16 15:50:10 +0000125 int frac:7;
126 int total:8;
127};
128
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000129typedef struct _xmlSchemaValQName xmlSchemaValQName;
130typedef xmlSchemaValQName *xmlSchemaValQNamePtr;
131struct _xmlSchemaValQName {
132 xmlChar *name;
133 xmlChar *uri;
134};
135
Daniel Veillard4255d502002-04-16 15:50:10 +0000136struct _xmlSchemaVal {
137 xmlSchemaValType type;
138 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000139 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000140 xmlSchemaValDate date;
141 xmlSchemaValDuration dur;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000142 xmlSchemaValQName qname;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000143 float f;
144 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000145 int b;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000146 xmlChar *str;
Daniel Veillard4255d502002-04-16 15:50:10 +0000147 } value;
148};
149
150static int xmlSchemaTypesInitialized = 0;
151static xmlHashTablePtr xmlSchemaTypesBank = NULL;
152
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000153/*
154 * Basic types
155 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000156static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
157static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
158static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
159static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000160static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000161static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000162static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
163static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
164static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
165static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
166static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000169static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000170static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000171static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000172static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000173
174/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000175 * Derived types
176 */
177static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
179static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
180static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
182static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
184static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
185static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
186static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
187static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
188static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
189static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000190static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
191static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
192static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
193static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
194static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000195static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000196static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
197static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
198static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000199static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
200static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000201static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000202static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
203static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000204
205/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000206 * xmlSchemaInitBasicType:
207 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000208 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000209 *
210 * Initialize one default type
211 */
212static xmlSchemaTypePtr
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000213xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000214 xmlSchemaTypePtr ret;
215
216 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
217 if (ret == NULL) {
218 xmlGenericError(xmlGenericErrorContext,
219 "Could not initilize type %s: out of memory\n", name);
220 return(NULL);
221 }
222 memset(ret, 0, sizeof(xmlSchemaType));
223 ret->name = xmlStrdup((const xmlChar *)name);
224 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000225 ret->flags = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000226 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
227 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
228 XML_SCHEMAS_NAMESPACE_NAME, ret);
229 return(ret);
230}
231
232/*
233 * xmlSchemaInitTypes:
234 *
235 * Initialize the default XML Schemas type library
236 */
237void
Daniel Veillard6560a422003-03-27 21:25:38 +0000238xmlSchemaInitTypes(void)
239{
Daniel Veillard4255d502002-04-16 15:50:10 +0000240 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000241 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000242 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000243
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000244 /*
245 * primitive datatypes
246 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000247 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
Daniel Veillard6560a422003-03-27 21:25:38 +0000248 XML_SCHEMAS_STRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000249 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000250 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000251 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000252 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000253 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard6560a422003-03-27 21:25:38 +0000254 XML_SCHEMAS_DECIMAL);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000255 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard6560a422003-03-27 21:25:38 +0000256 XML_SCHEMAS_DATE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000257 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard6560a422003-03-27 21:25:38 +0000258 XML_SCHEMAS_DATETIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000259 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard6560a422003-03-27 21:25:38 +0000260 XML_SCHEMAS_TIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000261 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard6560a422003-03-27 21:25:38 +0000262 XML_SCHEMAS_GYEAR);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000263 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000264 XML_SCHEMAS_GYEARMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000265 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000266 XML_SCHEMAS_GMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000267 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000268 XML_SCHEMAS_GMONTHDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000269 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000270 XML_SCHEMAS_GDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000271 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard6560a422003-03-27 21:25:38 +0000272 XML_SCHEMAS_DURATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000273 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard6560a422003-03-27 21:25:38 +0000274 XML_SCHEMAS_FLOAT);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000275 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard6560a422003-03-27 21:25:38 +0000276 XML_SCHEMAS_DOUBLE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000277 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard6560a422003-03-27 21:25:38 +0000278 XML_SCHEMAS_BOOLEAN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000279 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard6560a422003-03-27 21:25:38 +0000280 XML_SCHEMAS_ANYURI);
Daniel Veillard4255d502002-04-16 15:50:10 +0000281
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000282 /*
283 * derived datatypes
284 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000285 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard6560a422003-03-27 21:25:38 +0000286 XML_SCHEMAS_INTEGER);;
287 xmlSchemaTypeNonPositiveIntegerDef =
288 xmlSchemaInitBasicType("nonPositiveInteger",
289 XML_SCHEMAS_NPINTEGER);;
290 xmlSchemaTypeNegativeIntegerDef =
291 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
292 xmlSchemaTypeLongDef =
293 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
294 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000295 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard6560a422003-03-27 21:25:38 +0000296 XML_SCHEMAS_SHORT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000297 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard6560a422003-03-27 21:25:38 +0000298 XML_SCHEMAS_BYTE);;
299 xmlSchemaTypeNonNegativeIntegerDef =
300 xmlSchemaInitBasicType("nonNegativeInteger",
301 XML_SCHEMAS_NNINTEGER);
302 xmlSchemaTypeUnsignedLongDef =
303 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
304 xmlSchemaTypeUnsignedIntDef =
305 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
306 xmlSchemaTypeUnsignedShortDef =
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000307 xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT);;
Daniel Veillard6560a422003-03-27 21:25:38 +0000308 xmlSchemaTypeUnsignedByteDef =
309 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
310 xmlSchemaTypePositiveIntegerDef =
311 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000312
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000313 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard6560a422003-03-27 21:25:38 +0000314 XML_SCHEMAS_NORMSTRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000315 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard6560a422003-03-27 21:25:38 +0000316 XML_SCHEMAS_TOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000317 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard6560a422003-03-27 21:25:38 +0000318 XML_SCHEMAS_LANGUAGE);
319 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000320 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
Daniel Veillard6560a422003-03-27 21:25:38 +0000321 XML_SCHEMAS_IDREF);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000322 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000323 XML_SCHEMAS_IDREFS);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000324 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
Daniel Veillard6560a422003-03-27 21:25:38 +0000325 XML_SCHEMAS_ENTITY);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000326 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
Daniel Veillard6560a422003-03-27 21:25:38 +0000327 XML_SCHEMAS_ENTITIES);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000328 xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION",
329 XML_SCHEMAS_NOTATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000330 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard6560a422003-03-27 21:25:38 +0000331 XML_SCHEMAS_NAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000332 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000333 XML_SCHEMAS_QNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000334 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000335 XML_SCHEMAS_NCNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000336 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard6560a422003-03-27 21:25:38 +0000337 XML_SCHEMAS_NMTOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000338 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000339 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000340 xmlSchemaTypesInitialized = 1;
341}
342
343/**
344 * xmlSchemaCleanupTypes:
345 *
346 * Cleanup the default XML Schemas type library
347 */
348void
349xmlSchemaCleanupTypes(void) {
350 if (xmlSchemaTypesInitialized == 0)
351 return;
352 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
353 xmlSchemaTypesInitialized = 0;
354}
355
356/**
357 * xmlSchemaNewValue:
358 * @type: the value type
359 *
360 * Allocate a new simple type value
361 *
362 * Returns a pointer to the new value or NULL in case of error
363 */
364static xmlSchemaValPtr
365xmlSchemaNewValue(xmlSchemaValType type) {
366 xmlSchemaValPtr value;
367
368 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
369 if (value == NULL) {
370 return(NULL);
371 }
372 memset(value, 0, sizeof(xmlSchemaVal));
373 value->type = type;
374 return(value);
375}
376
377/**
378 * xmlSchemaFreeValue:
379 * @value: the value to free
380 *
381 * Cleanup the default XML Schemas type library
382 */
383void
384xmlSchemaFreeValue(xmlSchemaValPtr value) {
385 if (value == NULL)
386 return;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000387 switch (value->type) {
388 case XML_SCHEMAS_STRING:
389 case XML_SCHEMAS_NORMSTRING:
390 case XML_SCHEMAS_TOKEN:
391 case XML_SCHEMAS_LANGUAGE:
392 case XML_SCHEMAS_NMTOKEN:
393 case XML_SCHEMAS_NMTOKENS:
394 case XML_SCHEMAS_NAME:
Daniel Veillardc4c21552003-03-29 10:53:38 +0000395 case XML_SCHEMAS_NCNAME:
396 case XML_SCHEMAS_ID:
397 case XML_SCHEMAS_IDREF:
398 case XML_SCHEMAS_IDREFS:
399 case XML_SCHEMAS_ENTITY:
400 case XML_SCHEMAS_ENTITIES:
401 case XML_SCHEMAS_NOTATION:
402 case XML_SCHEMAS_ANYURI:
403 if (value->value.str != NULL)
404 xmlFree(value->value.str);
405 break;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000406 case XML_SCHEMAS_QNAME:
407 if (value->value.qname.uri != NULL)
408 xmlFree(value->value.qname.uri);
409 if (value->value.qname.name != NULL)
410 xmlFree(value->value.qname.name);
411 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +0000412 default:
413 break;
414 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000415 xmlFree(value);
416}
417
418/**
419 * xmlSchemaGetPredefinedType:
420 * @name: the type name
421 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
422 *
423 * Lookup a type in the default XML Schemas type library
424 *
425 * Returns the type if found, NULL otherwise
426 */
427xmlSchemaTypePtr
428xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
429 if (xmlSchemaTypesInitialized == 0)
430 xmlSchemaInitTypes();
431 if (name == NULL)
432 return(NULL);
433 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
434}
Daniel Veillard070803b2002-05-03 07:29:38 +0000435
436/****************************************************************
437 * *
438 * Convenience macros and functions *
439 * *
440 ****************************************************************/
441
442#define IS_TZO_CHAR(c) \
443 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
444
445#define VALID_YEAR(yr) (yr != 0)
446#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
447/* VALID_DAY should only be used when month is unknown */
448#define VALID_DAY(day) ((day >= 1) && (day <= 31))
449#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
450#define VALID_MIN(min) ((min >= 0) && (min <= 59))
451#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
452#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
453#define IS_LEAP(y) \
454 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
455
456static const long daysInMonth[12] =
457 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
458static const long daysInMonthLeap[12] =
459 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
460
Daniel Veillard5a872412002-05-22 06:40:27 +0000461#define MAX_DAYINMONTH(yr,mon) \
462 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
463
Daniel Veillard070803b2002-05-03 07:29:38 +0000464#define VALID_MDAY(dt) \
465 (IS_LEAP(dt->year) ? \
466 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
467 (dt->day <= daysInMonth[dt->mon - 1]))
468
469#define VALID_DATE(dt) \
470 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
471
472#define VALID_TIME(dt) \
473 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
474 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
475
476#define VALID_DATETIME(dt) \
477 (VALID_DATE(dt) && VALID_TIME(dt))
478
479#define SECS_PER_MIN (60)
480#define SECS_PER_HOUR (60 * SECS_PER_MIN)
481#define SECS_PER_DAY (24 * SECS_PER_HOUR)
482
Daniel Veillard5a872412002-05-22 06:40:27 +0000483static const long dayInYearByMonth[12] =
484 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
485static const long dayInLeapYearByMonth[12] =
486 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
487
488#define DAY_IN_YEAR(day, month, year) \
489 ((IS_LEAP(year) ? \
490 dayInLeapYearByMonth[month - 1] : \
491 dayInYearByMonth[month - 1]) + day)
492
493#ifdef DEBUG
494#define DEBUG_DATE(dt) \
495 xmlGenericError(xmlGenericErrorContext, \
496 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
497 dt->type,dt->value.date.year,dt->value.date.mon, \
498 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
499 dt->value.date.sec); \
500 if (dt->value.date.tz_flag) \
501 if (dt->value.date.tzo != 0) \
502 xmlGenericError(xmlGenericErrorContext, \
503 "%+05d\n",dt->value.date.tzo); \
504 else \
505 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
506 else \
507 xmlGenericError(xmlGenericErrorContext,"\n")
508#else
509#define DEBUG_DATE(dt)
510#endif
511
Daniel Veillard070803b2002-05-03 07:29:38 +0000512/**
513 * _xmlSchemaParseGYear:
514 * @dt: pointer to a date structure
515 * @str: pointer to the string to analyze
516 *
517 * Parses a xs:gYear without time zone and fills in the appropriate
518 * field of the @dt structure. @str is updated to point just after the
519 * xs:gYear. It is supposed that @dt->year is big enough to contain
520 * the year.
521 *
522 * Returns 0 or the error code
523 */
524static int
525_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
526 const xmlChar *cur = *str, *firstChar;
527 int isneg = 0, digcnt = 0;
528
529 if (((*cur < '0') || (*cur > '9')) &&
530 (*cur != '-') && (*cur != '+'))
531 return -1;
532
533 if (*cur == '-') {
534 isneg = 1;
535 cur++;
536 }
537
538 firstChar = cur;
539
540 while ((*cur >= '0') && (*cur <= '9')) {
541 dt->year = dt->year * 10 + (*cur - '0');
542 cur++;
543 digcnt++;
544 }
545
546 /* year must be at least 4 digits (CCYY); over 4
547 * digits cannot have a leading zero. */
548 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
549 return 1;
550
551 if (isneg)
552 dt->year = - dt->year;
553
554 if (!VALID_YEAR(dt->year))
555 return 2;
556
557 *str = cur;
558 return 0;
559}
560
561/**
562 * PARSE_2_DIGITS:
563 * @num: the integer to fill in
564 * @cur: an #xmlChar *
565 * @invalid: an integer
566 *
567 * Parses a 2-digits integer and updates @num with the value. @cur is
568 * updated to point just after the integer.
569 * In case of error, @invalid is set to %TRUE, values of @num and
570 * @cur are undefined.
571 */
572#define PARSE_2_DIGITS(num, cur, invalid) \
573 if ((cur[0] < '0') || (cur[0] > '9') || \
574 (cur[1] < '0') || (cur[1] > '9')) \
575 invalid = 1; \
576 else \
577 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
578 cur += 2;
579
580/**
581 * PARSE_FLOAT:
582 * @num: the double to fill in
583 * @cur: an #xmlChar *
584 * @invalid: an integer
585 *
586 * Parses a float and updates @num with the value. @cur is
587 * updated to point just after the float. The float must have a
588 * 2-digits integer part and may or may not have a decimal part.
589 * In case of error, @invalid is set to %TRUE, values of @num and
590 * @cur are undefined.
591 */
592#define PARSE_FLOAT(num, cur, invalid) \
593 PARSE_2_DIGITS(num, cur, invalid); \
594 if (!invalid && (*cur == '.')) { \
595 double mult = 1; \
596 cur++; \
597 if ((*cur < '0') || (*cur > '9')) \
598 invalid = 1; \
599 while ((*cur >= '0') && (*cur <= '9')) { \
600 mult /= 10; \
601 num += (*cur - '0') * mult; \
602 cur++; \
603 } \
604 }
605
606/**
607 * _xmlSchemaParseGMonth:
608 * @dt: pointer to a date structure
609 * @str: pointer to the string to analyze
610 *
611 * Parses a xs:gMonth without time zone and fills in the appropriate
612 * field of the @dt structure. @str is updated to point just after the
613 * xs:gMonth.
614 *
615 * Returns 0 or the error code
616 */
617static int
618_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
619 const xmlChar *cur = *str;
620 int ret = 0;
621
622 PARSE_2_DIGITS(dt->mon, cur, ret);
623 if (ret != 0)
624 return ret;
625
626 if (!VALID_MONTH(dt->mon))
627 return 2;
628
629 *str = cur;
630 return 0;
631}
632
633/**
634 * _xmlSchemaParseGDay:
635 * @dt: pointer to a date structure
636 * @str: pointer to the string to analyze
637 *
638 * Parses a xs:gDay without time zone and fills in the appropriate
639 * field of the @dt structure. @str is updated to point just after the
640 * xs:gDay.
641 *
642 * Returns 0 or the error code
643 */
644static int
645_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
646 const xmlChar *cur = *str;
647 int ret = 0;
648
649 PARSE_2_DIGITS(dt->day, cur, ret);
650 if (ret != 0)
651 return ret;
652
653 if (!VALID_DAY(dt->day))
654 return 2;
655
656 *str = cur;
657 return 0;
658}
659
660/**
661 * _xmlSchemaParseTime:
662 * @dt: pointer to a date structure
663 * @str: pointer to the string to analyze
664 *
665 * Parses a xs:time without time zone and fills in the appropriate
666 * fields of the @dt structure. @str is updated to point just after the
667 * xs:time.
668 * In case of error, values of @dt fields are undefined.
669 *
670 * Returns 0 or the error code
671 */
672static int
673_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
674 const xmlChar *cur = *str;
675 unsigned int hour = 0; /* use temp var in case str is not xs:time */
676 int ret = 0;
677
678 PARSE_2_DIGITS(hour, cur, ret);
679 if (ret != 0)
680 return ret;
681
682 if (*cur != ':')
683 return 1;
684 cur++;
685
686 /* the ':' insures this string is xs:time */
687 dt->hour = hour;
688
689 PARSE_2_DIGITS(dt->min, cur, ret);
690 if (ret != 0)
691 return ret;
692
693 if (*cur != ':')
694 return 1;
695 cur++;
696
697 PARSE_FLOAT(dt->sec, cur, ret);
698 if (ret != 0)
699 return ret;
700
701 if (!VALID_TIME(dt))
702 return 2;
703
704 *str = cur;
705 return 0;
706}
707
708/**
709 * _xmlSchemaParseTimeZone:
710 * @dt: pointer to a date structure
711 * @str: pointer to the string to analyze
712 *
713 * Parses a time zone without time zone and fills in the appropriate
714 * field of the @dt structure. @str is updated to point just after the
715 * time zone.
716 *
717 * Returns 0 or the error code
718 */
719static int
720_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
721 const xmlChar *cur = *str;
722 int ret = 0;
723
724 if (str == NULL)
725 return -1;
726
727 switch (*cur) {
728 case 0:
729 dt->tz_flag = 0;
730 dt->tzo = 0;
731 break;
732
733 case 'Z':
734 dt->tz_flag = 1;
735 dt->tzo = 0;
736 cur++;
737 break;
738
739 case '+':
740 case '-': {
741 int isneg = 0, tmp = 0;
742 isneg = (*cur == '-');
743
744 cur++;
745
746 PARSE_2_DIGITS(tmp, cur, ret);
747 if (ret != 0)
748 return ret;
749 if (!VALID_HOUR(tmp))
750 return 2;
751
752 if (*cur != ':')
753 return 1;
754 cur++;
755
756 dt->tzo = tmp * 60;
757
758 PARSE_2_DIGITS(tmp, cur, ret);
759 if (ret != 0)
760 return ret;
761 if (!VALID_MIN(tmp))
762 return 2;
763
764 dt->tzo += tmp;
765 if (isneg)
766 dt->tzo = - dt->tzo;
767
768 if (!VALID_TZO(dt->tzo))
769 return 2;
770
Daniel Veillard5a872412002-05-22 06:40:27 +0000771 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000772 break;
773 }
774 default:
775 return 1;
776 }
777
778 *str = cur;
779 return 0;
780}
781
782/****************************************************************
783 * *
784 * XML Schema Dates/Times Datatypes Handling *
785 * *
786 ****************************************************************/
787
788/**
789 * PARSE_DIGITS:
790 * @num: the integer to fill in
791 * @cur: an #xmlChar *
792 * @num_type: an integer flag
793 *
794 * Parses a digits integer and updates @num with the value. @cur is
795 * updated to point just after the integer.
796 * In case of error, @num_type is set to -1, values of @num and
797 * @cur are undefined.
798 */
799#define PARSE_DIGITS(num, cur, num_type) \
800 if ((*cur < '0') || (*cur > '9')) \
801 num_type = -1; \
802 else \
803 while ((*cur >= '0') && (*cur <= '9')) { \
804 num = num * 10 + (*cur - '0'); \
805 cur++; \
806 }
807
808/**
809 * PARSE_NUM:
810 * @num: the double to fill in
811 * @cur: an #xmlChar *
812 * @num_type: an integer flag
813 *
814 * Parses a float or integer and updates @num with the value. @cur is
815 * updated to point just after the number. If the number is a float,
816 * then it must have an integer part and a decimal part; @num_type will
817 * be set to 1. If there is no decimal part, @num_type is set to zero.
818 * In case of error, @num_type is set to -1, values of @num and
819 * @cur are undefined.
820 */
821#define PARSE_NUM(num, cur, num_type) \
822 num = 0; \
823 PARSE_DIGITS(num, cur, num_type); \
824 if (!num_type && (*cur == '.')) { \
825 double mult = 1; \
826 cur++; \
827 if ((*cur < '0') || (*cur > '9')) \
828 num_type = -1; \
829 else \
830 num_type = 1; \
831 while ((*cur >= '0') && (*cur <= '9')) { \
832 mult /= 10; \
833 num += (*cur - '0') * mult; \
834 cur++; \
835 } \
836 }
837
838/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000839 * xmlSchemaValidateDates:
Daniel Veillard455cc072003-03-31 10:13:23 +0000840 * @type: the expected type or XML_SCHEMAS_UNKNOWN
Daniel Veillard070803b2002-05-03 07:29:38 +0000841 * @dateTime: string to analyze
842 * @val: the return computed value
843 *
844 * Check that @dateTime conforms to the lexical space of one of the date types.
845 * if true a value is computed and returned in @val.
846 *
847 * Returns 0 if this validates, a positive error code number otherwise
848 * and -1 in case of internal or API error.
849 */
850static int
Daniel Veillard455cc072003-03-31 10:13:23 +0000851xmlSchemaValidateDates (xmlSchemaValType type,
Daniel Veillard118aed72002-09-24 14:13:13 +0000852 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000853 xmlSchemaValPtr dt;
854 int ret;
855 const xmlChar *cur = dateTime;
856
857#define RETURN_TYPE_IF_VALID(t) \
858 if (IS_TZO_CHAR(*cur)) { \
859 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
860 if (ret == 0) { \
861 if (*cur != 0) \
862 goto error; \
863 dt->type = t; \
Daniel Veillard455cc072003-03-31 10:13:23 +0000864 goto done; \
Daniel Veillard070803b2002-05-03 07:29:38 +0000865 } \
866 }
867
868 if (dateTime == NULL)
869 return -1;
870
871 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
872 return 1;
873
874 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
875 if (dt == NULL)
876 return -1;
877
878 if ((cur[0] == '-') && (cur[1] == '-')) {
879 /*
880 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
881 * xs:gDay)
882 */
883 cur += 2;
884
885 /* is it an xs:gDay? */
886 if (*cur == '-') {
Daniel Veillard455cc072003-03-31 10:13:23 +0000887 if (type == XML_SCHEMAS_GMONTH)
888 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +0000889 ++cur;
890 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
891 if (ret != 0)
892 goto error;
893
894 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
895
896 goto error;
897 }
898
899 /*
900 * it should be an xs:gMonthDay or xs:gMonth
901 */
902 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
903 if (ret != 0)
904 goto error;
905
Daniel Veillard455cc072003-03-31 10:13:23 +0000906 if (*cur != '-') {
Daniel Veillard070803b2002-05-03 07:29:38 +0000907 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
908 goto error;
909 }
Daniel Veillard455cc072003-03-31 10:13:23 +0000910 if (type == XML_SCHEMAS_GMONTH)
911 goto error;
Daniel Veillard070803b2002-05-03 07:29:38 +0000912 /* it should be an xs:gMonthDay */
Daniel Veillard455cc072003-03-31 10:13:23 +0000913 cur++;
Daniel Veillard070803b2002-05-03 07:29:38 +0000914 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
915 if (ret != 0)
916 goto error;
917
918 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
919
920 goto error;
921 }
922
923 /*
924 * It's a right-truncated date or an xs:time.
925 * Try to parse an xs:time then fallback on right-truncated dates.
926 */
927 if ((*cur >= '0') && (*cur <= '9')) {
928 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
929 if (ret == 0) {
930 /* it's an xs:time */
931 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
932 }
933 }
934
935 /* fallback on date parsing */
936 cur = dateTime;
937
938 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
939 if (ret != 0)
940 goto error;
941
942 /* is it an xs:gYear? */
943 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
944
945 if (*cur != '-')
946 goto error;
947 cur++;
948
949 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
950 if (ret != 0)
951 goto error;
952
953 /* is it an xs:gYearMonth? */
954 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
955
956 if (*cur != '-')
957 goto error;
958 cur++;
959
960 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
961 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
962 goto error;
963
964 /* is it an xs:date? */
965 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
966
967 if (*cur != 'T')
968 goto error;
969 cur++;
970
971 /* it should be an xs:dateTime */
972 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
973 if (ret != 0)
974 goto error;
975
976 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
977 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
978 goto error;
979
Daniel Veillard455cc072003-03-31 10:13:23 +0000980
Daniel Veillard070803b2002-05-03 07:29:38 +0000981 dt->type = XML_SCHEMAS_DATETIME;
982
Daniel Veillard455cc072003-03-31 10:13:23 +0000983done:
984#if 0
985 if ((type != XML_SCHEMAS_UNKNOWN) && (type != XML_SCHEMAS_DATETIME))
986 goto error;
987#endif
988
Daniel Veillard070803b2002-05-03 07:29:38 +0000989 if (val != NULL)
990 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +0000991 else
992 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +0000993
994 return 0;
995
996error:
997 if (dt != NULL)
998 xmlSchemaFreeValue(dt);
999 return 1;
1000}
1001
1002/**
Daniel Veillard5a872412002-05-22 06:40:27 +00001003 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +00001004 * @type: the predefined type
1005 * @duration: string to analyze
1006 * @val: the return computed value
1007 *
1008 * Check that @duration conforms to the lexical space of the duration type.
1009 * if true a value is computed and returned in @val.
1010 *
1011 * Returns 0 if this validates, a positive error code number otherwise
1012 * and -1 in case of internal or API error.
1013 */
1014static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00001015xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00001016 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +00001017 const xmlChar *cur = duration;
1018 xmlSchemaValPtr dur;
1019 int isneg = 0;
1020 unsigned int seq = 0;
1021
1022 if (duration == NULL)
1023 return -1;
1024
1025 if (*cur == '-') {
1026 isneg = 1;
1027 cur++;
1028 }
1029
1030 /* duration must start with 'P' (after sign) */
1031 if (*cur++ != 'P')
1032 return 1;
1033
Daniel Veillard80b19092003-03-28 13:29:53 +00001034 if (*cur == 0)
1035 return 1;
1036
Daniel Veillard070803b2002-05-03 07:29:38 +00001037 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
1038 if (dur == NULL)
1039 return -1;
1040
1041 while (*cur != 0) {
1042 double num;
1043 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1044 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1045 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
1046
1047 /* input string should be empty or invalid date/time item */
1048 if (seq >= sizeof(desig))
1049 goto error;
1050
1051 /* T designator must be present for time items */
1052 if (*cur == 'T') {
1053 if (seq <= 3) {
1054 seq = 3;
1055 cur++;
1056 } else
1057 return 1;
1058 } else if (seq == 3)
1059 goto error;
1060
1061 /* parse the number portion of the item */
1062 PARSE_NUM(num, cur, num_type);
1063
1064 if ((num_type == -1) || (*cur == 0))
1065 goto error;
1066
1067 /* update duration based on item type */
1068 while (seq < sizeof(desig)) {
1069 if (*cur == desig[seq]) {
1070
1071 /* verify numeric type; only seconds can be float */
1072 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1073 goto error;
1074
1075 switch (seq) {
1076 case 0:
1077 dur->value.dur.mon = (long)num * 12;
1078 break;
1079 case 1:
1080 dur->value.dur.mon += (long)num;
1081 break;
1082 default:
1083 /* convert to seconds using multiplier */
1084 dur->value.dur.sec += num * multi[seq];
1085 seq++;
1086 break;
1087 }
1088
1089 break; /* exit loop */
1090 }
1091 /* no date designators found? */
1092 if (++seq == 3)
1093 goto error;
1094 }
1095 cur++;
1096 }
1097
1098 if (isneg) {
1099 dur->value.dur.mon = -dur->value.dur.mon;
1100 dur->value.dur.day = -dur->value.dur.day;
1101 dur->value.dur.sec = -dur->value.dur.sec;
1102 }
1103
1104 if (val != NULL)
1105 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001106 else
1107 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001108
1109 return 0;
1110
1111error:
1112 if (dur != NULL)
1113 xmlSchemaFreeValue(dur);
1114 return 1;
1115}
1116
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001117/**
1118 * xmlSchemaStrip:
1119 * @value: a value
1120 *
1121 * Removes the leading and ending spaces of a string
1122 *
1123 * Returns the new string or NULL if no change was required.
1124 */
1125static xmlChar *
1126xmlSchemaStrip(const xmlChar *value) {
1127 const xmlChar *start = value, *end, *f;
1128
1129 if (value == NULL) return(NULL);
1130 while ((*start != 0) && (IS_BLANK(*start))) start++;
1131 end = start;
1132 while (*end != 0) end++;
1133 f = end;
1134 end--;
1135 while ((end > start) && (IS_BLANK(*end))) end--;
1136 end++;
1137 if ((start == value) && (f == end)) return(NULL);
1138 return(xmlStrndup(start, end - start));
1139}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001140
1141/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001142 * xmlSchemaCollapseString:
1143 * @value: a value
1144 *
1145 * Removes and normalize white spaces in the string
1146 *
1147 * Returns the new string or NULL if no change was required.
1148 */
1149static xmlChar *
1150xmlSchemaCollapseString(const xmlChar *value) {
1151 const xmlChar *start = value, *end, *f;
1152 xmlChar *g;
1153 int col = 0;
1154
1155 if (value == NULL) return(NULL);
1156 while ((*start != 0) && (IS_BLANK(*start))) start++;
1157 end = start;
1158 while (*end != 0) {
1159 if ((*end == ' ') && (IS_BLANK(end[1]))) {
1160 col = end - start;
1161 break;
1162 } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) {
1163 col = end - start;
1164 break;
1165 }
1166 end++;
1167 }
1168 if (col == 0) {
1169 f = end;
1170 end--;
1171 while ((end > start) && (IS_BLANK(*end))) end--;
1172 end++;
1173 if ((start == value) && (f == end)) return(NULL);
1174 return(xmlStrndup(start, end - start));
1175 }
1176 start = xmlStrdup(start);
1177 if (start == NULL) return(NULL);
1178 g = (xmlChar *) (start + col);
1179 end = g;
1180 while (*end != 0) {
1181 if (IS_BLANK(*end)) {
1182 end++;
1183 while (IS_BLANK(*end)) end++;
1184 if (*end != 0)
1185 *g++ = ' ';
1186 } else
1187 *g++ = *end++;
1188 }
1189 *g = 0;
1190 return((xmlChar *) start);
1191}
1192
1193/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001194 * xmlSchemaValAtomicListNode:
1195 * @type: the predefined atomic type for a token in the list
1196 * @value: the list value to check
1197 * @ret: the return computed value
1198 * @node: the node containing the value
1199 *
1200 * Check that a value conforms to the lexical space of the predefined
1201 * list type. if true a value is computed and returned in @ret.
1202 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001203 * Returns the number of items if this validates, a negative error code
1204 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001205 */
1206static int
1207xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1208 xmlSchemaValPtr *ret, xmlNodePtr node) {
1209 xmlChar *val, *cur, *endval;
1210 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001211 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001212
1213 if (value == NULL) {
1214 return(-1);
1215 }
1216 val = xmlStrdup(value);
1217 if (val == NULL) {
1218 return(-1);
1219 }
1220 cur = val;
1221 /*
1222 * Split the list
1223 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001224 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001225 while (*cur != 0) {
1226 if (IS_BLANK(*cur)) {
1227 *cur = 0;
1228 cur++;
1229 while (IS_BLANK(*cur)) *cur++ = 0;
1230 } else {
1231 nb_values++;
1232 cur++;
1233 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1234 }
1235 }
1236 if (nb_values == 0) {
1237 if (ret != NULL) {
1238 TODO
1239 }
1240 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001241 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001242 }
1243 endval = cur;
1244 cur = val;
1245 while ((*cur == 0) && (cur != endval)) cur++;
1246 while (cur != endval) {
1247 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1248 if (tmp != 0)
1249 break;
1250 while (*cur != 0) cur++;
1251 while ((*cur == 0) && (cur != endval)) cur++;
1252 }
1253 xmlFree(val);
1254 if (ret != NULL) {
1255 TODO
1256 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001257 if (tmp == 0)
1258 return(nb_values);
1259 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001260}
1261
1262/**
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001263 * xmlSchemaParseUInt:
1264 * @str: pointer to the string R/W
1265 * @llo: pointer to the low result
1266 * @lmi: pointer to the mid result
1267 * @lhi: pointer to the high result
1268 *
1269 * Parse an unsigned long into 3 fields.
1270 *
1271 * Returns the number of chars parsed or -1 if overflow of the capacity
1272 */
1273static int
1274xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
1275 unsigned long *lmi, unsigned long *lhi) {
1276 unsigned long lo = 0, mi = 0, hi = 0;
1277 const xmlChar *tmp, *cur = *str;
1278 int ret = 0, i = 0;
1279
1280 while (*cur == '0') {
1281 ret++;
1282 cur++;
1283 }
1284 tmp = cur;
1285 while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) {
1286 i++;tmp++;ret++;
1287 }
1288 if (i > 24) {
1289 *str = tmp;
1290 return(-1);
1291 }
1292 while (i > 16) {
1293 hi = hi * 10 + (*cur++ - '0');
1294 i--;
1295 }
1296 while (i > 8) {
1297 mi = mi * 10 + (*cur++ - '0');
1298 i--;
1299 }
1300 while (i > 0) {
1301 lo = lo * 10 + (*cur++ - '0');
1302 i--;
1303 }
1304
1305 *str = cur;
1306 *llo = lo;
1307 *lmi = mi;
1308 *lhi = hi;
1309 return(ret);
1310}
1311
1312/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001313 * xmlSchemaValAtomicType:
1314 * @type: the predefined type
1315 * @value: the value to check
1316 * @val: the return computed value
1317 * @node: the node containing the value
1318 * flags: flags to control the vlidation
1319 *
1320 * Check that a value conforms to the lexical space of the atomic type.
1321 * if true a value is computed and returned in @val.
1322 *
1323 * Returns 0 if this validates, a positive error code number otherwise
1324 * and -1 in case of internal or API error.
1325 */
1326static int
1327xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar *value,
1328 xmlSchemaValPtr *val, xmlNodePtr node, int flags) {
1329 xmlSchemaValPtr v;
1330 xmlChar *norm = NULL;
1331 int ret;
1332
1333 if (xmlSchemaTypesInitialized == 0)
1334 return(-1);
1335 if (type == NULL)
1336 return(-1);
1337
1338 if (val != NULL)
1339 *val = NULL;
1340 if ((flags == 0) && (value != NULL)) {
1341 if ((type->flags != XML_SCHEMAS_STRING) &&
1342 (type->flags != XML_SCHEMAS_NORMSTRING)) {
1343 norm = xmlSchemaCollapseString(value);
1344 if (norm != NULL)
1345 value = norm;
1346 }
1347 }
1348
1349 switch (type->flags) {
1350 case XML_SCHEMAS_UNKNOWN:
1351 if (type == xmlSchemaTypeAnyTypeDef)
1352 goto return0;
1353 goto error;
1354 case XML_SCHEMAS_STRING:
1355 goto return0;
1356 case XML_SCHEMAS_NORMSTRING:
1357 TODO
1358 goto return0;
1359 case XML_SCHEMAS_DECIMAL: {
1360 const xmlChar *cur = value, *tmp;
1361 int frac = 0, len, neg = 0;
1362 unsigned long base = 0;
1363 if (cur == NULL)
1364 goto return1;
1365 if (*cur == '+')
1366 cur++;
1367 else if (*cur == '-') {
1368 neg = 1;
1369 cur++;
1370 }
1371 tmp = cur;
1372 while ((*cur >= '0') && (*cur <= '9')) {
1373 base = base * 10 + (*cur - '0');
1374 cur++;
1375 }
1376 len = cur - tmp;
1377 if (*cur == '.') {
1378 cur++;
1379 tmp = cur;
1380 while ((*cur >= '0') && (*cur <= '9')) {
1381 base = base * 10 + (*cur - '0');
1382 cur++;
1383 }
1384 frac = cur - tmp;
1385 }
1386 if (*cur != 0)
1387 goto return1;
1388 if (val != NULL) {
1389 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1390 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001391 v->value.decimal.lo = base;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001392 v->value.decimal.sign = neg;
1393 v->value.decimal.frac = frac;
1394 v->value.decimal.total = frac + len;
1395 *val = v;
1396 }
1397 }
1398 goto return0;
1399 }
1400 case XML_SCHEMAS_TIME:
1401 case XML_SCHEMAS_GDAY:
1402 case XML_SCHEMAS_GMONTH:
1403 case XML_SCHEMAS_GMONTHDAY:
1404 case XML_SCHEMAS_GYEAR:
1405 case XML_SCHEMAS_GYEARMONTH:
1406 case XML_SCHEMAS_DATE:
1407 case XML_SCHEMAS_DATETIME:
Daniel Veillard455cc072003-03-31 10:13:23 +00001408 ret = xmlSchemaValidateDates(type->flags, value, val);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001409 break;
1410 case XML_SCHEMAS_DURATION:
1411 ret = xmlSchemaValidateDuration(type, value, val);
1412 break;
1413 case XML_SCHEMAS_FLOAT:
1414 case XML_SCHEMAS_DOUBLE: {
1415 const xmlChar *cur = value;
1416 int neg = 0;
1417 if (cur == NULL)
1418 goto return1;
1419 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1420 cur += 3;
1421 if (*cur != 0)
1422 goto return1;
1423 if (val != NULL) {
1424 if (type == xmlSchemaTypeFloatDef) {
1425 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1426 if (v != NULL) {
1427 v->value.f = (float) xmlXPathNAN;
1428 } else {
1429 xmlSchemaFreeValue(v);
1430 goto error;
1431 }
1432 } else {
1433 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1434 if (v != NULL) {
1435 v->value.d = xmlXPathNAN;
1436 } else {
1437 xmlSchemaFreeValue(v);
1438 goto error;
1439 }
1440 }
1441 *val = v;
1442 }
1443 goto return0;
1444 }
1445 if (*cur == '-') {
1446 neg = 1;
1447 cur++;
1448 }
1449 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1450 cur += 3;
1451 if (*cur != 0)
1452 goto return1;
1453 if (val != NULL) {
1454 if (type == xmlSchemaTypeFloatDef) {
1455 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1456 if (v != NULL) {
1457 if (neg)
1458 v->value.f = (float) xmlXPathNINF;
1459 else
1460 v->value.f = (float) xmlXPathPINF;
1461 } else {
1462 xmlSchemaFreeValue(v);
1463 goto error;
1464 }
1465 } else {
1466 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1467 if (v != NULL) {
1468 if (neg)
1469 v->value.d = xmlXPathNINF;
1470 else
1471 v->value.d = xmlXPathPINF;
1472 } else {
1473 xmlSchemaFreeValue(v);
1474 goto error;
1475 }
1476 }
1477 *val = v;
1478 }
1479 goto return0;
1480 }
1481 if ((neg == 0) && (*cur == '+'))
1482 cur++;
1483 if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-'))
1484 goto return1;
1485 while ((*cur >= '0') && (*cur <= '9')) {
1486 cur++;
1487 }
1488 if (*cur == '.') {
1489 cur++;
1490 while ((*cur >= '0') && (*cur <= '9'))
1491 cur++;
1492 }
1493 if ((*cur == 'e') || (*cur == 'E')) {
1494 cur++;
1495 if ((*cur == '-') || (*cur == '+'))
1496 cur++;
1497 while ((*cur >= '0') && (*cur <= '9'))
1498 cur++;
1499 }
1500 if (*cur != 0)
1501 goto return1;
1502 if (val != NULL) {
1503 if (type == xmlSchemaTypeFloatDef) {
1504 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1505 if (v != NULL) {
1506 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1507 *val = v;
1508 } else {
1509 xmlGenericError(xmlGenericErrorContext,
1510 "failed to scanf float %s\n", value);
1511 xmlSchemaFreeValue(v);
1512 goto return1;
1513 }
1514 } else {
1515 goto error;
1516 }
1517 } else {
1518 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1519 if (v != NULL) {
1520 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1521 *val = v;
1522 } else {
1523 xmlGenericError(xmlGenericErrorContext,
1524 "failed to scanf double %s\n", value);
1525 xmlSchemaFreeValue(v);
1526 goto return1;
1527 }
1528 } else {
1529 goto error;
1530 }
1531 }
1532 }
1533 goto return0;
1534 }
1535 case XML_SCHEMAS_BOOLEAN: {
1536 const xmlChar *cur = value;
1537
1538 if ((cur[0] == '0') && (cur[1] == 0))
1539 ret = 0;
1540 else if ((cur[0] == '1') && (cur[1] == 0))
1541 ret = 1;
1542 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1543 (cur[3] == 'e') && (cur[4] == 0))
1544 ret = 1;
1545 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1546 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1547 ret = 0;
1548 else
1549 goto return1;
1550 if (val != NULL) {
1551 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1552 if (v != NULL) {
1553 v->value.b = ret;
1554 *val = v;
1555 } else {
1556 goto error;
1557 }
1558 }
1559 goto return0;
1560 }
1561 case XML_SCHEMAS_TOKEN: {
1562 const xmlChar *cur = value;
1563
1564 if (IS_BLANK(*cur))
1565 goto return1;
1566
1567 while (*cur != 0) {
1568 if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) {
1569 goto return1;
1570 } else if (*cur == ' ') {
1571 cur++;
1572 if (*cur == 0)
1573 goto return1;
1574 if (*cur == ' ')
1575 goto return1;
1576 } else {
1577 cur++;
1578 }
1579 }
1580 if (val != NULL) {
1581 v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN);
1582 if (v != NULL) {
1583 v->value.str = xmlStrdup(value);
1584 *val = v;
1585 } else {
1586 goto error;
1587 }
1588 }
1589 goto return0;
1590 }
1591 case XML_SCHEMAS_LANGUAGE:
1592 if (xmlCheckLanguageID(value) == 1) {
1593 if (val != NULL) {
1594 v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
1595 if (v != NULL) {
1596 v->value.str = xmlStrdup(value);
1597 *val = v;
1598 } else {
1599 goto error;
1600 }
1601 }
1602 goto return0;
1603 }
1604 goto return1;
1605 case XML_SCHEMAS_NMTOKEN:
1606 if (xmlValidateNMToken(value, 1) == 0) {
1607 if (val != NULL) {
1608 v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN);
1609 if (v != NULL) {
1610 v->value.str = xmlStrdup(value);
1611 *val = v;
1612 } else {
1613 goto error;
1614 }
1615 }
1616 goto return0;
1617 }
1618 goto return1;
1619 case XML_SCHEMAS_NMTOKENS:
1620 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1621 value, val, node);
1622 if (ret > 0)
1623 ret = 0;
1624 else
1625 ret = 1;
1626 goto done;
1627 case XML_SCHEMAS_NAME:
1628 ret = xmlValidateName(value, 1);
1629 if ((ret == 0) && (val != NULL)) {
1630 TODO;
1631 }
1632 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001633 case XML_SCHEMAS_QNAME: {
1634 xmlChar *uri = NULL;
1635 xmlChar *local = NULL;
1636
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001637 ret = xmlValidateQName(value, 1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001638 if ((ret == 0) && (node != NULL)) {
1639 xmlChar *prefix;
1640 local = xmlSplitQName2(value, &prefix);
1641 if (prefix != NULL) {
1642 xmlNsPtr ns;
1643
1644 ns = xmlSearchNs(node->doc, node, prefix);
1645 if (ns == NULL)
1646 ret = 1;
1647 else if (val != NULL)
1648 uri = xmlStrdup(ns->href);
1649 }
1650 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1651 xmlFree(local);
1652 if (prefix != NULL)
1653 xmlFree(prefix);
1654 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001655 if ((ret == 0) && (val != NULL)) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001656 v = xmlSchemaNewValue(XML_SCHEMAS_QNAME);
1657 if (v != NULL) {
1658 if (local != NULL)
1659 v->value.qname.name = local;
1660 else
1661 v->value.qname.name = xmlStrdup(value);
1662 if (uri != NULL)
1663 v->value.qname.uri = uri;
1664
1665 *val = v;
1666 } else {
1667 if (local != NULL)
1668 xmlFree(local);
1669 if (uri != NULL)
1670 xmlFree(uri);
1671 goto error;
1672 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001673 }
1674 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001675 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001676 case XML_SCHEMAS_NCNAME:
1677 ret = xmlValidateNCName(value, 1);
1678 if ((ret == 0) && (val != NULL)) {
1679 v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME);
1680 if (v != NULL) {
1681 v->value.str = xmlStrdup(value);
1682 *val = v;
1683 } else {
1684 goto error;
1685 }
1686 }
1687 goto done;
1688 case XML_SCHEMAS_ID:
1689 ret = xmlValidateNCName(value, 1);
1690 if ((ret == 0) && (val != NULL)) {
1691 TODO;
1692 }
1693 if ((ret == 0) && (node != NULL) &&
1694 (node->type == XML_ATTRIBUTE_NODE)) {
1695 xmlAttrPtr attr = (xmlAttrPtr) node;
1696 /*
1697 * NOTE: the IDness might have already be declared in the DTD
1698 */
1699 if (attr->atype != XML_ATTRIBUTE_ID) {
1700 xmlIDPtr res;
1701 xmlChar *strip;
1702
1703 strip = xmlSchemaStrip(value);
1704 if (strip != NULL) {
1705 res = xmlAddID(NULL, node->doc, strip, attr);
1706 xmlFree(strip);
1707 } else
1708 res = xmlAddID(NULL, node->doc, value, attr);
1709 if (res == NULL) {
1710 ret = 2;
1711 } else {
1712 attr->atype = XML_ATTRIBUTE_ID;
1713 }
1714 }
1715 }
1716 goto done;
1717 case XML_SCHEMAS_IDREF:
1718 ret = xmlValidateNCName(value, 1);
1719 if ((ret == 0) && (val != NULL)) {
1720 TODO;
1721 }
1722 if ((ret == 0) && (node != NULL) &&
1723 (node->type == XML_ATTRIBUTE_NODE)) {
1724 xmlAttrPtr attr = (xmlAttrPtr) node;
1725 xmlChar *strip;
1726
1727 strip = xmlSchemaStrip(value);
1728 if (strip != NULL) {
1729 xmlAddRef(NULL, node->doc, strip, attr);
1730 xmlFree(strip);
1731 } else
1732 xmlAddRef(NULL, node->doc, value, attr);
1733 attr->atype = XML_ATTRIBUTE_IDREF;
1734 }
1735 goto done;
1736 case XML_SCHEMAS_IDREFS:
1737 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1738 value, val, node);
1739 if (ret < 0)
1740 ret = 2;
1741 else
1742 ret = 0;
1743 if ((ret == 0) && (node != NULL) &&
1744 (node->type == XML_ATTRIBUTE_NODE)) {
1745 xmlAttrPtr attr = (xmlAttrPtr) node;
1746
1747 attr->atype = XML_ATTRIBUTE_IDREFS;
1748 }
1749 goto done;
1750 case XML_SCHEMAS_ENTITY: {
1751 xmlChar *strip;
1752 ret = xmlValidateNCName(value, 1);
1753 if ((node == NULL) || (node->doc == NULL))
1754 ret = 3;
1755 if (ret == 0) {
1756 xmlEntityPtr ent;
1757
1758 strip = xmlSchemaStrip(value);
1759 if (strip != NULL) {
1760 ent = xmlGetDocEntity(node->doc, strip);
1761 xmlFree(strip);
1762 } else {
1763 ent = xmlGetDocEntity(node->doc, value);
1764 }
1765 if ((ent == NULL) ||
1766 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1767 ret = 4;
1768 }
1769 if ((ret == 0) && (val != NULL)) {
1770 TODO;
1771 }
1772 if ((ret == 0) && (node != NULL) &&
1773 (node->type == XML_ATTRIBUTE_NODE)) {
1774 xmlAttrPtr attr = (xmlAttrPtr) node;
1775
1776 attr->atype = XML_ATTRIBUTE_ENTITY;
1777 }
1778 goto done;
1779 }
1780 case XML_SCHEMAS_ENTITIES:
1781 if ((node == NULL) || (node->doc == NULL))
1782 goto return3;
1783 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1784 value, val, node);
1785 if (ret <= 0)
1786 ret = 1;
1787 else
1788 ret = 0;
1789 if ((ret == 0) && (node != NULL) &&
1790 (node->type == XML_ATTRIBUTE_NODE)) {
1791 xmlAttrPtr attr = (xmlAttrPtr) node;
1792
1793 attr->atype = XML_ATTRIBUTE_ENTITIES;
1794 }
1795 goto done;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001796 case XML_SCHEMAS_NOTATION: {
1797 xmlChar *uri = NULL;
1798 xmlChar *local = NULL;
1799
1800 ret = xmlValidateQName(value, 1);
1801 if ((ret == 0) && (node != NULL)) {
1802 xmlChar *prefix;
1803 local = xmlSplitQName2(value, &prefix);
1804 if (prefix != NULL) {
1805 xmlNsPtr ns;
1806
1807 ns = xmlSearchNs(node->doc, node, prefix);
1808 if (ns == NULL)
1809 ret = 1;
1810 else if (val != NULL)
1811 uri = xmlStrdup(ns->href);
1812 }
1813 if ((local != NULL) && ((val == NULL) || (ret != 0)))
1814 xmlFree(local);
1815 if (prefix != NULL)
1816 xmlFree(prefix);
1817 }
1818 if ((node == NULL) || (node->doc == NULL))
1819 ret = 3;
1820 if (ret == 0) {
1821 ret = xmlValidateNotationUse(NULL, node->doc, value);
1822 if (ret == 1)
1823 ret = 0;
1824 else
1825 ret = 1;
1826 }
1827 if ((ret == 0) && (val != NULL)) {
1828 v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION);
1829 if (v != NULL) {
1830 if (local != NULL)
1831 v->value.qname.name = local;
1832 else
1833 v->value.qname.name = xmlStrdup(value);
1834 if (uri != NULL)
1835 v->value.qname.uri = uri;
1836
1837 *val = v;
1838 } else {
1839 if (local != NULL)
1840 xmlFree(local);
1841 if (uri != NULL)
1842 xmlFree(uri);
1843 goto error;
1844 }
1845 }
1846 goto done;
1847 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001848 case XML_SCHEMAS_ANYURI: {
1849 xmlURIPtr uri;
1850
1851 uri = xmlParseURI((const char *) value);
1852 if (uri == NULL)
1853 goto return1;
1854 if (val != NULL) {
1855 TODO;
1856 }
1857 xmlFreeURI(uri);
1858 goto return0;
1859 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001860 case XML_SCHEMAS_INTEGER:
1861 case XML_SCHEMAS_PINTEGER:
1862 case XML_SCHEMAS_NPINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001863 case XML_SCHEMAS_NINTEGER:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001864 case XML_SCHEMAS_NNINTEGER: {
1865 const xmlChar *cur = value;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001866 unsigned long lo, mi, hi;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001867 int sign = 0;
1868 if (cur == NULL)
1869 goto return1;
1870 if (*cur == '-') {
1871 sign = 1;
1872 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001873 } else if (*cur == '+')
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001874 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001875 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
1876 if (ret == 0)
1877 goto return1;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001878 if (*cur != 0)
1879 goto return1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001880 if (type->flags == XML_SCHEMAS_NPINTEGER) {
1881 if ((sign == 0) &&
1882 ((hi != 0) || (mi != 0) || (lo != 0)))
1883 goto return1;
1884 } else if (type->flags == XML_SCHEMAS_PINTEGER) {
1885 if (sign == 1)
1886 goto return1;
1887 if ((hi == 0) && (mi == 0) && (lo == 0))
1888 goto return1;
1889 } else if (type->flags == XML_SCHEMAS_NINTEGER) {
1890 if (sign == 0)
1891 goto return1;
1892 if ((hi == 0) && (mi == 0) && (lo == 0))
1893 goto return1;
1894 } else if (type->flags == XML_SCHEMAS_NNINTEGER) {
1895 if ((sign == 1) &&
1896 ((hi != 0) || (mi != 0) || (lo != 0)))
1897 goto return1;
1898 }
1899 /*
1900 * We can store a value only if no overflow occured
1901 */
1902 if ((ret > 0) && (val != NULL)) {
1903 v = xmlSchemaNewValue(type->flags);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001904 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001905 v->value.decimal.lo = lo;
1906 v->value.decimal.mi = lo;
1907 v->value.decimal.hi = lo;
1908 v->value.decimal.sign = sign;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001909 v->value.decimal.frac = 0;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001910 v->value.decimal.total = cur - value;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001911 *val = v;
1912 }
1913 }
1914 goto return0;
1915 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001916 case XML_SCHEMAS_LONG:
1917 case XML_SCHEMAS_BYTE:
1918 case XML_SCHEMAS_SHORT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001919 case XML_SCHEMAS_INT: {
1920 const xmlChar *cur = value;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001921 unsigned long lo, mi, hi;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001922 int total = 0;
1923 int sign = 0;
1924 if (cur == NULL)
1925 goto return1;
1926 if (*cur == '-') {
1927 sign = 1;
1928 cur++;
1929 } else if (*cur == '+')
1930 cur++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001931 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
1932 if (ret <= 0)
1933 goto return1;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001934 if (*cur != 0)
1935 goto return1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001936 if (type->flags == XML_SCHEMAS_LONG) {
1937 if (hi >= 922) {
1938 if (hi > 922)
1939 goto return1;
1940 if (mi >= 33720368) {
1941 if (mi > 33720368)
1942 goto return1;
1943 if ((sign == 0) && (lo > 54775807))
1944 goto return1;
1945 if ((sign == 1) && (lo > 54775808))
1946 goto return1;
1947 }
1948 }
1949 } else if (type->flags == XML_SCHEMAS_INT) {
1950 if (hi != 0)
1951 goto return1;
1952 if (mi >= 21) {
1953 if (mi > 21)
1954 goto return1;
1955 if ((sign == 0) && (lo > 47483647))
1956 goto return1;
1957 if ((sign == 1) && (lo > 47483648))
1958 goto return1;
1959 }
1960 } else if (type->flags == XML_SCHEMAS_SHORT) {
1961 if ((mi != 0) || (hi != 0))
1962 goto return1;
1963 if ((sign == 1) && (lo > 32768))
1964 goto return1;
1965 if ((sign == 0) && (lo > 32767))
1966 goto return1;
1967 } else if (type->flags == XML_SCHEMAS_BYTE) {
1968 if ((mi != 0) || (hi != 0))
1969 goto return1;
1970 if ((sign == 1) && (lo > 128))
1971 goto return1;
1972 if ((sign == 0) && (lo > 127))
1973 goto return1;
1974 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001975 if (val != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001976 v = xmlSchemaNewValue(type->flags);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001977 if (v != NULL) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001978 v->value.decimal.lo = lo;
1979 v->value.decimal.mi = lo;
1980 v->value.decimal.hi = lo;
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001981 v->value.decimal.sign = sign;
1982 v->value.decimal.frac = 0;
1983 v->value.decimal.total = total;
1984 *val = v;
1985 }
1986 }
1987 goto return0;
1988 }
1989 case XML_SCHEMAS_UINT:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001990 case XML_SCHEMAS_ULONG:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00001991 case XML_SCHEMAS_USHORT:
Daniel Veillarde637c4a2003-03-30 21:10:09 +00001992 case XML_SCHEMAS_UBYTE: {
1993 const xmlChar *cur = value;
1994 unsigned long lo, mi, hi;
1995 int total = 0;
1996 if (cur == NULL)
1997 goto return1;
1998 ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi);
1999 if (ret <= 0)
2000 goto return1;
2001 if (*cur != 0)
2002 goto return1;
2003 if (type->flags == XML_SCHEMAS_ULONG) {
2004 if (hi >= 1844) {
2005 if (hi > 1844)
2006 goto return1;
2007 if (mi >= 67440737) {
2008 if (mi > 67440737)
2009 goto return1;
2010 if (lo > 9551615)
2011 goto return1;
2012 }
2013 }
2014 } else if (type->flags == XML_SCHEMAS_UINT) {
2015 if (hi != 0)
2016 goto return1;
2017 if (mi >= 42) {
2018 if (mi > 42)
2019 goto return1;
2020 if (lo > 94967295)
2021 goto return1;
2022 }
2023 } else if (type->flags == XML_SCHEMAS_USHORT) {
2024 if ((mi != 0) || (hi != 0))
2025 goto return1;
2026 if (lo > 65535)
2027 goto return1;
2028 } else if (type->flags == XML_SCHEMAS_UBYTE) {
2029 if ((mi != 0) || (hi != 0))
2030 goto return1;
2031 if (lo > 255)
2032 goto return1;
2033 }
2034 if (val != NULL) {
2035 v = xmlSchemaNewValue(type->flags);
2036 if (v != NULL) {
2037 v->value.decimal.lo = lo;
2038 v->value.decimal.mi = mi;
2039 v->value.decimal.hi = hi;
2040 v->value.decimal.sign = 0;
2041 v->value.decimal.frac = 0;
2042 v->value.decimal.total = total;
2043 *val = v;
2044 }
2045 }
2046 goto return0;
2047 }
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002048 }
2049
2050done:
2051 if (norm != NULL) xmlFree(norm);
2052 return(ret);
2053return3:
2054 if (norm != NULL) xmlFree(norm);
2055 return(3);
2056return1:
2057 if (norm != NULL) xmlFree(norm);
2058 return(1);
2059return0:
2060 if (norm != NULL) xmlFree(norm);
2061 return(0);
2062error:
2063 if (norm != NULL) xmlFree(norm);
2064 return(-1);
2065}
2066
2067/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002068 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00002069 * @type: the predefined type
2070 * @value: the value to check
2071 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002072 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00002073 *
2074 * Check that a value conforms to the lexical space of the predefined type.
2075 * if true a value is computed and returned in @val.
2076 *
2077 * Returns 0 if this validates, a positive error code number otherwise
2078 * and -1 in case of internal or API error.
2079 */
2080int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002081xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
2082 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002083 return(xmlSchemaValAtomicType(type, value, val, node, 0));
Daniel Veillard4255d502002-04-16 15:50:10 +00002084}
2085
2086/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002087 * xmlSchemaValidatePredefinedType:
2088 * @type: the predefined type
2089 * @value: the value to check
2090 * @val: the return computed value
2091 *
2092 * Check that a value conforms to the lexical space of the predefined type.
2093 * if true a value is computed and returned in @val.
2094 *
2095 * Returns 0 if this validates, a positive error code number otherwise
2096 * and -1 in case of internal or API error.
2097 */
2098int
2099xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
2100 xmlSchemaValPtr *val) {
2101 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
2102}
2103
2104/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002105 * xmlSchemaCompareDecimals:
2106 * @x: a first decimal value
2107 * @y: a second decimal value
2108 *
2109 * Compare 2 decimals
2110 *
2111 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
2112 */
2113static int
2114xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
2115{
2116 xmlSchemaValPtr swp;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002117 int order = 1, p;
Daniel Veillard4255d502002-04-16 15:50:10 +00002118 unsigned long tmp;
2119
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002120 if ((x->value.decimal.sign) &&
2121 ((x->value.decimal.lo != 0) ||
2122 (x->value.decimal.mi != 0) ||
2123 (x->value.decimal.hi != 0))) {
2124 if ((y->value.decimal.sign) &&
2125 ((y->value.decimal.lo != 0) ||
2126 (y->value.decimal.mi != 0) ||
2127 (y->value.decimal.hi != 0)))
Daniel Veillard80b19092003-03-28 13:29:53 +00002128 order = -1;
2129 else
2130 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002131 } else if ((y->value.decimal.sign) &&
2132 ((y->value.decimal.lo != 0) ||
2133 (y->value.decimal.mi != 0) ||
2134 (y->value.decimal.hi != 0))) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002135 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002136 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002137 if (x->value.decimal.frac == y->value.decimal.frac) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002138 if (x->value.decimal.hi < y->value.decimal.hi)
2139 return (-order);
2140 if (x->value.decimal.hi < y->value.decimal.hi)
2141 return (order);
2142 if (x->value.decimal.mi < y->value.decimal.mi)
2143 return (-order);
2144 if (x->value.decimal.mi < y->value.decimal.mi)
2145 return (order);
2146 if (x->value.decimal.lo < y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002147 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002148 if (x->value.decimal.lo > y->value.decimal.lo)
Daniel Veillard80b19092003-03-28 13:29:53 +00002149 return(order);
2150 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00002151 }
2152 if (y->value.decimal.frac > x->value.decimal.frac) {
2153 swp = y;
2154 y = x;
2155 x = swp;
2156 order = -order;
2157 }
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002158 p = powten[x->value.decimal.frac - y->value.decimal.frac];
2159 tmp = x->value.decimal.lo / p;
2160 if (tmp > y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002161 return (order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002162 if (tmp < y->value.decimal.lo)
Daniel Veillard4255d502002-04-16 15:50:10 +00002163 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002164 tmp = y->value.decimal.lo * p;
2165 if (x->value.decimal.lo < tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002166 return (-order);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002167 if (x->value.decimal.lo == tmp)
Daniel Veillard4255d502002-04-16 15:50:10 +00002168 return (0);
2169 return (order);
2170}
2171
2172/**
Daniel Veillard070803b2002-05-03 07:29:38 +00002173 * xmlSchemaCompareDurations:
2174 * @x: a first duration value
2175 * @y: a second duration value
2176 *
2177 * Compare 2 durations
2178 *
2179 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2180 * case of error
2181 */
2182static int
2183xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
2184{
2185 long carry, mon, day;
2186 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00002187 int invert = 1;
2188 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00002189 static const long dayRange [2][12] = {
2190 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
2191 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
2192
2193 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00002194 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00002195
2196 /* months */
2197 mon = x->value.dur.mon - y->value.dur.mon;
2198
2199 /* seconds */
2200 sec = x->value.dur.sec - y->value.dur.sec;
2201 carry = (long)sec / SECS_PER_DAY;
2202 sec -= (double)(carry * SECS_PER_DAY);
2203
2204 /* days */
2205 day = x->value.dur.day - y->value.dur.day + carry;
2206
2207 /* easy test */
2208 if (mon == 0) {
2209 if (day == 0)
2210 if (sec == 0.0)
2211 return 0;
2212 else if (sec < 0.0)
2213 return -1;
2214 else
2215 return 1;
2216 else if (day < 0)
2217 return -1;
2218 else
2219 return 1;
2220 }
2221
2222 if (mon > 0) {
2223 if ((day >= 0) && (sec >= 0.0))
2224 return 1;
2225 else {
2226 xmon = mon;
2227 xday = -day;
2228 }
2229 } else if ((day <= 0) && (sec <= 0.0)) {
2230 return -1;
2231 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00002232 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00002233 xmon = -mon;
2234 xday = day;
2235 }
2236
2237 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00002238 if (myear == 0) {
2239 minday = 0;
2240 maxday = 0;
2241 } else {
2242 maxday = 366 * ((myear + 3) / 4) +
2243 365 * ((myear - 1) % 4);
2244 minday = maxday - 1;
2245 }
2246
Daniel Veillard070803b2002-05-03 07:29:38 +00002247 xmon = xmon % 12;
2248 minday += dayRange[0][xmon];
2249 maxday += dayRange[1][xmon];
2250
Daniel Veillard80b19092003-03-28 13:29:53 +00002251 if ((maxday == minday) && (maxday == xday))
2252 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00002253 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00002254 return(-invert);
2255 if (minday > xday)
2256 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00002257
2258 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00002259 return 2;
2260}
2261
2262/*
2263 * macros for adding date/times and durations
2264 */
2265#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
2266#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
2267#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
2268#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
2269
2270/**
2271 * _xmlSchemaDateAdd:
2272 * @dt: an #xmlSchemaValPtr
2273 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
2274 *
2275 * Compute a new date/time from @dt and @dur. This function assumes @dt
2276 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
2277 * or #XML_SCHEMAS_GYEAR.
2278 *
2279 * Returns date/time pointer or NULL.
2280 */
2281static xmlSchemaValPtr
2282_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
2283{
2284 xmlSchemaValPtr ret;
2285 long carry, tempdays, temp;
2286 xmlSchemaValDatePtr r, d;
2287 xmlSchemaValDurationPtr u;
2288
2289 if ((dt == NULL) || (dur == NULL))
2290 return NULL;
2291
2292 ret = xmlSchemaNewValue(dt->type);
2293 if (ret == NULL)
2294 return NULL;
2295
2296 r = &(ret->value.date);
2297 d = &(dt->value.date);
2298 u = &(dur->value.dur);
2299
2300 /* normalization */
2301 if (d->mon == 0)
2302 d->mon = 1;
2303
2304 /* normalize for time zone offset */
2305 u->sec -= (d->tzo * 60);
2306 d->tzo = 0;
2307
2308 /* normalization */
2309 if (d->day == 0)
2310 d->day = 1;
2311
2312 /* month */
2313 carry = d->mon + u->mon;
2314 r->mon = MODULO_RANGE(carry, 1, 13);
2315 carry = FQUOTIENT_RANGE(carry, 1, 13);
2316
2317 /* year (may be modified later) */
2318 r->year = d->year + carry;
2319 if (r->year == 0) {
2320 if (d->year > 0)
2321 r->year--;
2322 else
2323 r->year++;
2324 }
2325
2326 /* time zone */
2327 r->tzo = d->tzo;
2328 r->tz_flag = d->tz_flag;
2329
2330 /* seconds */
2331 r->sec = d->sec + u->sec;
2332 carry = FQUOTIENT((long)r->sec, 60);
2333 if (r->sec != 0.0) {
2334 r->sec = MODULO(r->sec, 60.0);
2335 }
2336
2337 /* minute */
2338 carry += d->min;
2339 r->min = MODULO(carry, 60);
2340 carry = FQUOTIENT(carry, 60);
2341
2342 /* hours */
2343 carry += d->hour;
2344 r->hour = MODULO(carry, 24);
2345 carry = FQUOTIENT(carry, 24);
2346
2347 /*
2348 * days
2349 * Note we use tempdays because the temporary values may need more
2350 * than 5 bits
2351 */
2352 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
2353 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
2354 tempdays = MAX_DAYINMONTH(r->year, r->mon);
2355 else if (d->day < 1)
2356 tempdays = 1;
2357 else
2358 tempdays = d->day;
2359
2360 tempdays += u->day + carry;
2361
2362 while (1) {
2363 if (tempdays < 1) {
2364 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
2365 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
2366 if (tyr == 0)
2367 tyr--;
2368 tempdays += MAX_DAYINMONTH(tyr, tmon);
2369 carry = -1;
2370 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
2371 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
2372 carry = 1;
2373 } else
2374 break;
2375
2376 temp = r->mon + carry;
2377 r->mon = MODULO_RANGE(temp, 1, 13);
2378 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
2379 if (r->year == 0) {
2380 if (temp < 1)
2381 r->year--;
2382 else
2383 r->year++;
2384 }
2385 }
2386
2387 r->day = tempdays;
2388
2389 /*
2390 * adjust the date/time type to the date values
2391 */
2392 if (ret->type != XML_SCHEMAS_DATETIME) {
2393 if ((r->hour) || (r->min) || (r->sec))
2394 ret->type = XML_SCHEMAS_DATETIME;
2395 else if (ret->type != XML_SCHEMAS_DATE) {
2396 if ((r->mon != 1) && (r->day != 1))
2397 ret->type = XML_SCHEMAS_DATE;
2398 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2399 ret->type = XML_SCHEMAS_GYEARMONTH;
2400 }
2401 }
2402
2403 return ret;
2404}
2405
2406/**
2407 * xmlSchemaDupVal:
2408 * @v: value to duplicate
2409 *
2410 * returns a duplicated value.
2411 */
2412static xmlSchemaValPtr
2413xmlSchemaDupVal (xmlSchemaValPtr v)
2414{
2415 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2416 if (ret == NULL)
2417 return ret;
2418
2419 memcpy(ret, v, sizeof(xmlSchemaVal));
2420 return ret;
2421}
2422
2423/**
2424 * xmlSchemaDateNormalize:
2425 * @dt: an #xmlSchemaValPtr
2426 *
2427 * Normalize @dt to GMT time.
2428 *
2429 */
2430static xmlSchemaValPtr
2431xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2432{
2433 xmlSchemaValPtr dur, ret;
2434
2435 if (dt == NULL)
2436 return NULL;
2437
2438 if (((dt->type != XML_SCHEMAS_TIME) &&
2439 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2440 return xmlSchemaDupVal(dt);
2441
2442 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2443 if (dur == NULL)
2444 return NULL;
2445
2446 dur->value.date.sec -= offset;
2447
2448 ret = _xmlSchemaDateAdd(dt, dur);
2449 if (ret == NULL)
2450 return NULL;
2451
2452 xmlSchemaFreeValue(dur);
2453
2454 /* ret->value.date.tzo = 0; */
2455 return ret;
2456}
2457
2458/**
2459 * _xmlSchemaDateCastYMToDays:
2460 * @dt: an #xmlSchemaValPtr
2461 *
2462 * Convert mon and year of @dt to total number of days. Take the
2463 * number of years since (or before) 1 AD and add the number of leap
2464 * years. This is a function because negative
2465 * years must be handled a little differently and there is no zero year.
2466 *
2467 * Returns number of days.
2468 */
2469static long
2470_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2471{
2472 long ret;
2473
2474 if (dt->value.date.year < 0)
2475 ret = (dt->value.date.year * 365) +
2476 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2477 ((dt->value.date.year+1)/400)) +
2478 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2479 else
2480 ret = ((dt->value.date.year-1) * 365) +
2481 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2482 ((dt->value.date.year-1)/400)) +
2483 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2484
2485 return ret;
2486}
2487
2488/**
2489 * TIME_TO_NUMBER:
2490 * @dt: an #xmlSchemaValPtr
2491 *
2492 * Calculates the number of seconds in the time portion of @dt.
2493 *
2494 * Returns seconds.
2495 */
2496#define TIME_TO_NUMBER(dt) \
2497 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
2498 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
2499
2500/**
2501 * xmlSchemaCompareDates:
2502 * @x: a first date/time value
2503 * @y: a second date/time value
2504 *
2505 * Compare 2 date/times
2506 *
2507 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2508 * case of error
2509 */
2510static int
2511xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2512{
2513 unsigned char xmask, ymask, xor_mask, and_mask;
2514 xmlSchemaValPtr p1, p2, q1, q2;
2515 long p1d, p2d, q1d, q2d;
2516
2517 if ((x == NULL) || (y == NULL))
2518 return -2;
2519
2520 if (x->value.date.tz_flag) {
2521
2522 if (!y->value.date.tz_flag) {
2523 p1 = xmlSchemaDateNormalize(x, 0);
2524 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2525 /* normalize y + 14:00 */
2526 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2527
2528 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002529 if (p1d < q1d) {
2530 xmlSchemaFreeValue(p1);
2531 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002532 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002533 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002534 double sec;
2535
2536 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002537 if (sec < 0.0) {
2538 xmlSchemaFreeValue(p1);
2539 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002540 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002541 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002542 /* normalize y - 14:00 */
2543 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2544 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002545 xmlSchemaFreeValue(p1);
2546 xmlSchemaFreeValue(q1);
2547 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002548 if (p1d > q2d)
2549 return 1;
2550 else if (p1d == q2d) {
2551 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2552 if (sec > 0.0)
2553 return 1;
2554 else
2555 return 2; /* indeterminate */
2556 }
2557 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002558 } else {
2559 xmlSchemaFreeValue(p1);
2560 xmlSchemaFreeValue(q1);
2561 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002562 }
2563 } else if (y->value.date.tz_flag) {
2564 q1 = xmlSchemaDateNormalize(y, 0);
2565 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2566
2567 /* normalize x - 14:00 */
2568 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2569 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2570
Daniel Veillardfdc91562002-07-01 21:52:03 +00002571 if (p1d < q1d) {
2572 xmlSchemaFreeValue(p1);
2573 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002574 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002575 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002576 double sec;
2577
2578 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002579 if (sec < 0.0) {
2580 xmlSchemaFreeValue(p1);
2581 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002582 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002583 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002584 /* normalize x + 14:00 */
2585 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2586 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2587
Daniel Veillard6560a422003-03-27 21:25:38 +00002588 if (p2d > q1d) {
2589 xmlSchemaFreeValue(p1);
2590 xmlSchemaFreeValue(q1);
2591 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002592 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002593 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002594 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002595 xmlSchemaFreeValue(p1);
2596 xmlSchemaFreeValue(q1);
2597 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002598 if (sec > 0.0)
2599 return 1;
2600 else
2601 return 2; /* indeterminate */
2602 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002603 xmlSchemaFreeValue(p1);
2604 xmlSchemaFreeValue(q1);
2605 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002606 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002607 } else {
2608 xmlSchemaFreeValue(p1);
2609 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002610 }
2611 }
2612
2613 /*
2614 * if the same type then calculate the difference
2615 */
2616 if (x->type == y->type) {
2617 q1 = xmlSchemaDateNormalize(y, 0);
2618 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2619
2620 p1 = xmlSchemaDateNormalize(x, 0);
2621 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2622
Daniel Veillardfdc91562002-07-01 21:52:03 +00002623 if (p1d < q1d) {
2624 xmlSchemaFreeValue(p1);
2625 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002626 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002627 } else if (p1d > q1d) {
2628 xmlSchemaFreeValue(p1);
2629 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002630 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002631 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002632 double sec;
2633
2634 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002635 xmlSchemaFreeValue(p1);
2636 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002637 if (sec < 0.0)
2638 return -1;
2639 else if (sec > 0.0)
2640 return 1;
2641
2642 }
2643 return 0;
2644 }
2645
2646 switch (x->type) {
2647 case XML_SCHEMAS_DATETIME:
2648 xmask = 0xf;
2649 break;
2650 case XML_SCHEMAS_DATE:
2651 xmask = 0x7;
2652 break;
2653 case XML_SCHEMAS_GYEAR:
2654 xmask = 0x1;
2655 break;
2656 case XML_SCHEMAS_GMONTH:
2657 xmask = 0x2;
2658 break;
2659 case XML_SCHEMAS_GDAY:
2660 xmask = 0x3;
2661 break;
2662 case XML_SCHEMAS_GYEARMONTH:
2663 xmask = 0x3;
2664 break;
2665 case XML_SCHEMAS_GMONTHDAY:
2666 xmask = 0x6;
2667 break;
2668 case XML_SCHEMAS_TIME:
2669 xmask = 0x8;
2670 break;
2671 default:
2672 xmask = 0;
2673 break;
2674 }
2675
2676 switch (y->type) {
2677 case XML_SCHEMAS_DATETIME:
2678 ymask = 0xf;
2679 break;
2680 case XML_SCHEMAS_DATE:
2681 ymask = 0x7;
2682 break;
2683 case XML_SCHEMAS_GYEAR:
2684 ymask = 0x1;
2685 break;
2686 case XML_SCHEMAS_GMONTH:
2687 ymask = 0x2;
2688 break;
2689 case XML_SCHEMAS_GDAY:
2690 ymask = 0x3;
2691 break;
2692 case XML_SCHEMAS_GYEARMONTH:
2693 ymask = 0x3;
2694 break;
2695 case XML_SCHEMAS_GMONTHDAY:
2696 ymask = 0x6;
2697 break;
2698 case XML_SCHEMAS_TIME:
2699 ymask = 0x8;
2700 break;
2701 default:
2702 ymask = 0;
2703 break;
2704 }
2705
2706 xor_mask = xmask ^ ymask; /* mark type differences */
2707 and_mask = xmask & ymask; /* mark field specification */
2708
2709 /* year */
2710 if (xor_mask & 1)
2711 return 2; /* indeterminate */
2712 else if (and_mask & 1) {
2713 if (x->value.date.year < y->value.date.year)
2714 return -1;
2715 else if (x->value.date.year > y->value.date.year)
2716 return 1;
2717 }
2718
2719 /* month */
2720 if (xor_mask & 2)
2721 return 2; /* indeterminate */
2722 else if (and_mask & 2) {
2723 if (x->value.date.mon < y->value.date.mon)
2724 return -1;
2725 else if (x->value.date.mon > y->value.date.mon)
2726 return 1;
2727 }
2728
2729 /* day */
2730 if (xor_mask & 4)
2731 return 2; /* indeterminate */
2732 else if (and_mask & 4) {
2733 if (x->value.date.day < y->value.date.day)
2734 return -1;
2735 else if (x->value.date.day > y->value.date.day)
2736 return 1;
2737 }
2738
2739 /* time */
2740 if (xor_mask & 8)
2741 return 2; /* indeterminate */
2742 else if (and_mask & 8) {
2743 if (x->value.date.hour < y->value.date.hour)
2744 return -1;
2745 else if (x->value.date.hour > y->value.date.hour)
2746 return 1;
2747 else if (x->value.date.min < y->value.date.min)
2748 return -1;
2749 else if (x->value.date.min > y->value.date.min)
2750 return 1;
2751 else if (x->value.date.sec < y->value.date.sec)
2752 return -1;
2753 else if (x->value.date.sec > y->value.date.sec)
2754 return 1;
2755 }
2756
Daniel Veillard070803b2002-05-03 07:29:38 +00002757 return 0;
2758}
2759
2760/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00002761 * xmlSchemaCompareNormStrings:
2762 * @x: a first string value
2763 * @y: a second string value
2764 *
2765 * Compare 2 string for their normalized values.
2766 *
2767 * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in
2768 * case of error
2769 */
2770static int
2771xmlSchemaCompareNormStrings(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2772 const xmlChar *utf1;
2773 const xmlChar *utf2;
2774 int tmp;
2775
2776 if ((x == NULL) || (y == NULL))
2777 return(-2);
2778 utf1 = x->value.str;
2779 utf2 = y->value.str;
2780
2781 while (IS_BLANK(*utf1)) utf1++;
2782 while (IS_BLANK(*utf2)) utf2++;
2783 while ((*utf1 != 0) && (*utf2 != 0)) {
2784 if (IS_BLANK(*utf1)) {
2785 if (!IS_BLANK(*utf2)) {
2786 tmp = *utf1 - *utf2;
2787 return(tmp);
2788 }
2789 while (IS_BLANK(*utf1)) utf1++;
2790 while (IS_BLANK(*utf2)) utf2++;
2791 } else {
2792 tmp = *utf1++ - *utf2++;
2793 if (tmp < 0)
2794 return(-1);
2795 if (tmp > 0)
2796 return(1);
2797 }
2798 }
2799 if (*utf1 != 0) {
2800 while (IS_BLANK(*utf1)) utf1++;
2801 if (*utf1 != 0)
2802 return(1);
2803 }
2804 if (*utf2 != 0) {
2805 while (IS_BLANK(*utf2)) utf2++;
2806 if (*utf2 != 0)
2807 return(-1);
2808 }
2809 return(0);
2810}
2811
2812/**
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002813 * xmlSchemaCompareFloats:
2814 * @x: a first float or double value
2815 * @y: a second float or double value
2816 *
2817 * Compare 2 values
2818 *
2819 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2820 * case of error
2821 */
2822static int
2823xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2824 double d1, d2;
2825
2826 if ((x == NULL) || (y == NULL))
2827 return(-2);
2828
2829 /*
2830 * Cast everything to doubles.
2831 */
2832 if (x->type == XML_SCHEMAS_DOUBLE)
2833 d1 = x->value.d;
2834 else if (x->type == XML_SCHEMAS_FLOAT)
2835 d1 = x->value.f;
2836 else
2837 return(-2);
2838
2839 if (y->type == XML_SCHEMAS_DOUBLE)
2840 d2 = y->value.d;
2841 else if (y->type == XML_SCHEMAS_FLOAT)
2842 d2 = y->value.f;
2843 else
2844 return(-2);
2845
2846 /*
2847 * Check for special cases.
2848 */
2849 if (xmlXPathIsNaN(d1)) {
2850 if (xmlXPathIsNaN(d2))
2851 return(0);
2852 return(1);
2853 }
2854 if (xmlXPathIsNaN(d2))
2855 return(-1);
2856 if (d1 == xmlXPathPINF) {
2857 if (d2 == xmlXPathPINF)
2858 return(0);
2859 return(1);
2860 }
2861 if (d2 == xmlXPathPINF)
2862 return(-1);
2863 if (d1 == xmlXPathNINF) {
2864 if (d2 == xmlXPathNINF)
2865 return(0);
2866 return(-1);
2867 }
2868 if (d2 == xmlXPathNINF)
2869 return(1);
2870
2871 /*
2872 * basic tests, the last one we should have equality, but
2873 * portability is more important than speed and handling
2874 * NaN or Inf in a portable way is always a challenge, so ...
2875 */
2876 if (d1 < d2)
2877 return(-1);
2878 if (d1 > d2)
2879 return(1);
2880 if (d1 == d2)
2881 return(0);
2882 return(2);
2883}
2884
2885/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002886 * xmlSchemaCompareValues:
2887 * @x: a first value
2888 * @y: a second value
2889 *
2890 * Compare 2 values
2891 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002892 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2893 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002894 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002895int
Daniel Veillard4255d502002-04-16 15:50:10 +00002896xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2897 if ((x == NULL) || (y == NULL))
2898 return(-2);
2899
2900 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002901 case XML_SCHEMAS_UNKNOWN:
2902 return(-2);
2903 case XML_SCHEMAS_INTEGER:
2904 case XML_SCHEMAS_NPINTEGER:
2905 case XML_SCHEMAS_NINTEGER:
2906 case XML_SCHEMAS_NNINTEGER:
2907 case XML_SCHEMAS_PINTEGER:
2908 case XML_SCHEMAS_INT:
2909 case XML_SCHEMAS_UINT:
2910 case XML_SCHEMAS_LONG:
2911 case XML_SCHEMAS_ULONG:
2912 case XML_SCHEMAS_SHORT:
2913 case XML_SCHEMAS_USHORT:
2914 case XML_SCHEMAS_BYTE:
2915 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00002916 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00002917 if (y->type == x->type)
2918 return(xmlSchemaCompareDecimals(x, y));
2919 if ((y->type == XML_SCHEMAS_DECIMAL) ||
2920 (y->type == XML_SCHEMAS_INTEGER) ||
2921 (y->type == XML_SCHEMAS_NPINTEGER) ||
2922 (y->type == XML_SCHEMAS_NINTEGER) ||
2923 (y->type == XML_SCHEMAS_NNINTEGER) ||
2924 (y->type == XML_SCHEMAS_PINTEGER) ||
2925 (y->type == XML_SCHEMAS_INT) ||
2926 (y->type == XML_SCHEMAS_UINT) ||
2927 (y->type == XML_SCHEMAS_LONG) ||
2928 (y->type == XML_SCHEMAS_ULONG) ||
2929 (y->type == XML_SCHEMAS_SHORT) ||
2930 (y->type == XML_SCHEMAS_USHORT) ||
2931 (y->type == XML_SCHEMAS_BYTE) ||
2932 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00002933 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002934 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002935 case XML_SCHEMAS_DURATION:
2936 if (y->type == XML_SCHEMAS_DURATION)
2937 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002938 return(-2);
2939 case XML_SCHEMAS_TIME:
2940 case XML_SCHEMAS_GDAY:
2941 case XML_SCHEMAS_GMONTH:
2942 case XML_SCHEMAS_GMONTHDAY:
2943 case XML_SCHEMAS_GYEAR:
2944 case XML_SCHEMAS_GYEARMONTH:
2945 case XML_SCHEMAS_DATE:
2946 case XML_SCHEMAS_DATETIME:
2947 if ((y->type == XML_SCHEMAS_DATETIME) ||
2948 (y->type == XML_SCHEMAS_TIME) ||
2949 (y->type == XML_SCHEMAS_GDAY) ||
2950 (y->type == XML_SCHEMAS_GMONTH) ||
2951 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2952 (y->type == XML_SCHEMAS_GYEAR) ||
2953 (y->type == XML_SCHEMAS_DATE) ||
2954 (y->type == XML_SCHEMAS_GYEARMONTH))
2955 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002956 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002957 case XML_SCHEMAS_NORMSTRING:
Daniel Veillard80b19092003-03-28 13:29:53 +00002958 case XML_SCHEMAS_TOKEN:
2959 case XML_SCHEMAS_LANGUAGE:
2960 case XML_SCHEMAS_NMTOKEN:
Daniel Veillard80b19092003-03-28 13:29:53 +00002961 case XML_SCHEMAS_NAME:
Daniel Veillard80b19092003-03-28 13:29:53 +00002962 case XML_SCHEMAS_NCNAME:
2963 case XML_SCHEMAS_ID:
2964 case XML_SCHEMAS_IDREF:
Daniel Veillard80b19092003-03-28 13:29:53 +00002965 case XML_SCHEMAS_ENTITY:
Daniel Veillard80b19092003-03-28 13:29:53 +00002966 case XML_SCHEMAS_NOTATION:
2967 case XML_SCHEMAS_ANYURI:
Daniel Veillardc4c21552003-03-29 10:53:38 +00002968 if ((y->type == XML_SCHEMAS_NORMSTRING) ||
2969 (y->type == XML_SCHEMAS_TOKEN) ||
2970 (y->type == XML_SCHEMAS_LANGUAGE) ||
2971 (y->type == XML_SCHEMAS_NMTOKEN) ||
2972 (y->type == XML_SCHEMAS_NAME) ||
2973 (y->type == XML_SCHEMAS_QNAME) ||
2974 (y->type == XML_SCHEMAS_NCNAME) ||
2975 (y->type == XML_SCHEMAS_ID) ||
2976 (y->type == XML_SCHEMAS_IDREF) ||
2977 (y->type == XML_SCHEMAS_ENTITY) ||
2978 (y->type == XML_SCHEMAS_NOTATION) ||
2979 (y->type == XML_SCHEMAS_ANYURI))
2980 return (xmlSchemaCompareNormStrings(x, y));
2981 return (-2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002982 case XML_SCHEMAS_QNAME:
2983 if (y->type == XML_SCHEMAS_QNAME) {
2984 if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
2985 (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
2986 return(0);
2987 return(2);
2988 }
2989 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00002990 case XML_SCHEMAS_FLOAT:
2991 case XML_SCHEMAS_DOUBLE:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002992 if ((y->type == XML_SCHEMAS_FLOAT) ||
2993 (y->type == XML_SCHEMAS_DOUBLE))
2994 return (xmlSchemaCompareFloats(x, y));
2995 return (-2);
Daniel Veillard4255d502002-04-16 15:50:10 +00002996 TODO
Daniel Veillardc4c21552003-03-29 10:53:38 +00002997 break;
2998 case XML_SCHEMAS_BOOLEAN:
Daniel Veillardb6c7f412003-03-29 16:41:55 +00002999 if (y->type == XML_SCHEMAS_BOOLEAN) {
3000 if (x->value.b == y->value.b)
3001 return(0);
3002 if (x->value.b == 0)
3003 return(-1);
3004 return(1);
3005 }
3006 return (-2);
Daniel Veillardc4c21552003-03-29 10:53:38 +00003007 case XML_SCHEMAS_STRING:
3008 case XML_SCHEMAS_IDREFS:
3009 case XML_SCHEMAS_ENTITIES:
3010 case XML_SCHEMAS_NMTOKENS:
3011 TODO
3012 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003013 }
Daniel Veillard5a872412002-05-22 06:40:27 +00003014 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00003015}
3016
3017/**
Daniel Veillardc4c21552003-03-29 10:53:38 +00003018 * xmlSchemaNormLen:
3019 * @value: a string
3020 *
3021 * Computes the UTF8 length of the normalized value of the string
3022 *
3023 * Returns the length or -1 in case of error.
3024 */
3025static int
3026xmlSchemaNormLen(const xmlChar *value) {
3027 const xmlChar *utf;
3028 int ret = 0;
3029
3030 if (value == NULL)
3031 return(-1);
3032 utf = value;
3033 while (IS_BLANK(*utf)) utf++;
3034 while (*utf != 0) {
3035 if (utf[0] & 0x80) {
3036 if ((utf[1] & 0xc0) != 0x80)
3037 return(-1);
3038 if ((utf[0] & 0xe0) == 0xe0) {
3039 if ((utf[2] & 0xc0) != 0x80)
3040 return(-1);
3041 if ((utf[0] & 0xf0) == 0xf0) {
3042 if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
3043 return(-1);
3044 utf += 4;
3045 } else {
3046 utf += 3;
3047 }
3048 } else {
3049 utf += 2;
3050 }
3051 } else if (IS_BLANK(*utf)) {
3052 while (IS_BLANK(*utf)) utf++;
3053 if (*utf == 0)
3054 break;
3055 } else {
3056 utf++;
3057 }
3058 ret++;
3059 }
3060 return(ret);
3061}
3062
3063/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003064 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003065 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00003066 * @facet: the facet to check
3067 * @value: the lexical repr of the value to validate
3068 * @val: the precomputed value
3069 *
3070 * Check a value against a facet condition
3071 *
3072 * Returns 0 if the element is schemas valid, a positive error code
3073 * number otherwise and -1 in case of internal or API error.
3074 */
3075int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003076xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00003077 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00003078 const xmlChar *value, xmlSchemaValPtr val)
3079{
3080 int ret;
3081
3082 switch (facet->type) {
3083 case XML_SCHEMA_FACET_PATTERN:
3084 ret = xmlRegexpExec(facet->regexp, value);
3085 if (ret == 1)
3086 return(0);
3087 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003088 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003089 return(1);
3090 }
3091 return(ret);
3092 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3093 ret = xmlSchemaCompareValues(val, facet->val);
3094 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003095 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003096 return(-1);
3097 }
3098 if (ret == -1)
3099 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003100 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00003101 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00003102 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3103 ret = xmlSchemaCompareValues(val, facet->val);
3104 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003105 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003106 return(-1);
3107 }
3108 if ((ret == -1) || (ret == 0))
3109 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003110 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003111 return(1);
3112 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3113 ret = xmlSchemaCompareValues(val, facet->val);
3114 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003115 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003116 return(-1);
3117 }
3118 if (ret == 1)
3119 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003120 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003121 return(1);
3122 case XML_SCHEMA_FACET_MININCLUSIVE:
3123 ret = xmlSchemaCompareValues(val, facet->val);
3124 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003125 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003126 return(-1);
3127 }
3128 if ((ret == 1) || (ret == 0))
3129 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00003130 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00003131 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00003132 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003133 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00003134 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00003135 case XML_SCHEMA_FACET_ENUMERATION:
3136 if ((facet->value != NULL) &&
3137 (xmlStrEqual(facet->value, value)))
3138 return(0);
3139 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003140 case XML_SCHEMA_FACET_LENGTH:
3141 case XML_SCHEMA_FACET_MAXLENGTH:
3142 case XML_SCHEMA_FACET_MINLENGTH: {
3143 unsigned int len = 0;
3144
3145 if ((facet->val == NULL) ||
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003146 ((facet->val->type != XML_SCHEMAS_DECIMAL) &&
3147 (facet->val->type != XML_SCHEMAS_NNINTEGER)) ||
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003148 (facet->val->value.decimal.frac != 0)) {
3149 return(-1);
3150 }
3151 switch (base->flags) {
Daniel Veillardc4c21552003-03-29 10:53:38 +00003152 case XML_SCHEMAS_IDREF:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003153 case XML_SCHEMAS_NORMSTRING:
3154 case XML_SCHEMAS_TOKEN:
3155 case XML_SCHEMAS_LANGUAGE:
3156 case XML_SCHEMAS_NMTOKEN:
3157 case XML_SCHEMAS_NAME:
3158 case XML_SCHEMAS_NCNAME:
3159 case XML_SCHEMAS_ID:
Daniel Veillardc4c21552003-03-29 10:53:38 +00003160 len = xmlSchemaNormLen(value);
3161 break;
3162 case XML_SCHEMAS_STRING:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003163 len = xmlUTF8Strlen(value);
3164 break;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003165 default:
3166 TODO
3167 }
3168 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003169 if (len != facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003170 return(1);
3171 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003172 if (len < facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003173 return(1);
3174 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003175 if (len > facet->val->value.decimal.lo)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003176 return(1);
3177 }
3178 break;
3179 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003180 default:
3181 TODO
3182 }
3183 return(0);
Daniel Veillardb6c7f412003-03-29 16:41:55 +00003184
Daniel Veillard4255d502002-04-16 15:50:10 +00003185}
3186
3187#endif /* LIBXML_SCHEMAS_ENABLED */