blob: 753ae7919810f790bc28209678617a8bcfcba0ed [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemastypes.c : implementation of the XML Schema Datatypes
3 * definition and validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20#include <libxml/valid.h>
Daniel Veillard96a4b252003-02-06 08:22:32 +000021#include <libxml/xpath.h>
22#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000023
24#include <libxml/xmlschemas.h>
25#include <libxml/schemasInternals.h>
26#include <libxml/xmlschemastypes.h>
27
Daniel Veillard070803b2002-05-03 07:29:38 +000028#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31
Daniel Veillard4255d502002-04-16 15:50:10 +000032#define DEBUG
33
34#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
38
39#define XML_SCHEMAS_NAMESPACE_NAME \
40 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
41
42typedef enum {
43 XML_SCHEMAS_UNKNOWN = 0,
44 XML_SCHEMAS_STRING,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000045 XML_SCHEMAS_NORMSTRING,
Daniel Veillard4255d502002-04-16 15:50:10 +000046 XML_SCHEMAS_DECIMAL,
Daniel Veillard070803b2002-05-03 07:29:38 +000047 XML_SCHEMAS_TIME,
48 XML_SCHEMAS_GDAY,
49 XML_SCHEMAS_GMONTH,
50 XML_SCHEMAS_GMONTHDAY,
51 XML_SCHEMAS_GYEAR,
52 XML_SCHEMAS_GYEARMONTH,
53 XML_SCHEMAS_DATE,
54 XML_SCHEMAS_DATETIME,
55 XML_SCHEMAS_DURATION,
Daniel Veillard84d70a42002-09-16 10:51:38 +000056 XML_SCHEMAS_FLOAT,
57 XML_SCHEMAS_DOUBLE,
Daniel Veillardc5a70f22003-02-06 23:41:59 +000058 XML_SCHEMAS_BOOLEAN,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000059 XML_SCHEMAS_TOKEN,
60 XML_SCHEMAS_LANGUAGE,
61 XML_SCHEMAS_NMTOKEN,
62 XML_SCHEMAS_NMTOKENS,
63 XML_SCHEMAS_NAME,
64 XML_SCHEMAS_QNAME,
65 XML_SCHEMAS_NCNAME,
66 XML_SCHEMAS_ID,
67 XML_SCHEMAS_IDREF,
68 XML_SCHEMAS_IDREFS,
69 XML_SCHEMAS_ENTITY,
70 XML_SCHEMAS_ENTITIES,
71 XML_SCHEMAS_NOTATION,
72 XML_SCHEMAS_ANYURI,
73 XML_SCHEMAS_INTEGER,
74 XML_SCHEMAS_NPINTEGER,
75 XML_SCHEMAS_NINTEGER,
76 XML_SCHEMAS_NNINTEGER,
77 XML_SCHEMAS_PINTEGER,
Daniel Veillard96a4b252003-02-06 08:22:32 +000078 XML_SCHEMAS_INT,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +000079 XML_SCHEMAS_UINT,
80 XML_SCHEMAS_LONG,
81 XML_SCHEMAS_ULONG,
82 XML_SCHEMAS_SHORT,
83 XML_SCHEMAS_USHORT,
84 XML_SCHEMAS_BYTE,
85 XML_SCHEMAS_UBYTE
Daniel Veillard4255d502002-04-16 15:50:10 +000086} xmlSchemaValType;
87
Daniel Veillard5f704af2003-03-05 10:01:43 +000088static unsigned long powten[10] = {
Daniel Veillard4255d502002-04-16 15:50:10 +000089 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
90 100000000L, 1000000000L
91};
92
Daniel Veillard070803b2002-05-03 07:29:38 +000093/* Date value */
94typedef struct _xmlSchemaValDate xmlSchemaValDate;
95typedef xmlSchemaValDate *xmlSchemaValDatePtr;
96struct _xmlSchemaValDate {
97 long year;
98 unsigned int mon :4; /* 1 <= mon <= 12 */
99 unsigned int day :5; /* 1 <= day <= 31 */
100 unsigned int hour :5; /* 0 <= hour <= 23 */
101 unsigned int min :6; /* 0 <= min <= 59 */
102 double sec;
103 int tz_flag :1; /* is tzo explicitely set? */
104 int tzo :11; /* -1440 <= tzo <= 1440 */
105};
106
107/* Duration value */
108typedef struct _xmlSchemaValDuration xmlSchemaValDuration;
109typedef xmlSchemaValDuration *xmlSchemaValDurationPtr;
110struct _xmlSchemaValDuration {
111 long mon; /* mon stores years also */
112 long day;
113 double sec; /* sec stores min and hour also */
114};
115
Daniel Veillard4255d502002-04-16 15:50:10 +0000116typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
117typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
118struct _xmlSchemaValDecimal {
119 /* would use long long but not portable */
120 unsigned long base;
121 unsigned int extra;
Daniel Veillard5a872412002-05-22 06:40:27 +0000122 unsigned int sign:1;
Daniel Veillard4255d502002-04-16 15:50:10 +0000123 int frac:7;
124 int total:8;
125};
126
127struct _xmlSchemaVal {
128 xmlSchemaValType type;
129 union {
Daniel Veillard5a872412002-05-22 06:40:27 +0000130 xmlSchemaValDecimal decimal;
Daniel Veillard070803b2002-05-03 07:29:38 +0000131 xmlSchemaValDate date;
132 xmlSchemaValDuration dur;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000133 float f;
134 double d;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000135 int b;
Daniel Veillard4255d502002-04-16 15:50:10 +0000136 } value;
137};
138
139static int xmlSchemaTypesInitialized = 0;
140static xmlHashTablePtr xmlSchemaTypesBank = NULL;
141
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000142/*
143 * Basic types
144 */
Daniel Veillard4255d502002-04-16 15:50:10 +0000145static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
146static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
147static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
148static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000149static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000150static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
Daniel Veillard070803b2002-05-03 07:29:38 +0000151static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL;
152static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL;
153static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL;
154static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL;
155static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL;
156static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL;
157static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000158static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL;
Daniel Veillardc5a70f22003-02-06 23:41:59 +0000159static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000160static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000161static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000162
163/*
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000164 * Derived types
165 */
166static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
167static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL;
168static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL;
169static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
170static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL;
171static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL;
172static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL;
173static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL;
174static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL;
175static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL;
176static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL;
177static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL;
178static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000179static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL;
180static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL;
181static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL;
182static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL;
183static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000184static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000185static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
186static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
187static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000188static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
189static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000190static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
191static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000192
193/*
Daniel Veillard4255d502002-04-16 15:50:10 +0000194 * xmlSchemaInitBasicType:
195 * @name: the type name
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000196 * @type: the value type associated
Daniel Veillard4255d502002-04-16 15:50:10 +0000197 *
198 * Initialize one default type
199 */
200static xmlSchemaTypePtr
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000201xmlSchemaInitBasicType(const char *name, xmlSchemaValType type) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000202 xmlSchemaTypePtr ret;
203
204 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
205 if (ret == NULL) {
206 xmlGenericError(xmlGenericErrorContext,
207 "Could not initilize type %s: out of memory\n", name);
208 return(NULL);
209 }
210 memset(ret, 0, sizeof(xmlSchemaType));
211 ret->name = xmlStrdup((const xmlChar *)name);
212 ret->type = XML_SCHEMA_TYPE_BASIC;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000213 ret->flags = type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000214 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
215 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
216 XML_SCHEMAS_NAMESPACE_NAME, ret);
217 return(ret);
218}
219
220/*
221 * xmlSchemaInitTypes:
222 *
223 * Initialize the default XML Schemas type library
224 */
225void
Daniel Veillard6560a422003-03-27 21:25:38 +0000226xmlSchemaInitTypes(void)
227{
Daniel Veillard4255d502002-04-16 15:50:10 +0000228 if (xmlSchemaTypesInitialized != 0)
Daniel Veillard6560a422003-03-27 21:25:38 +0000229 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000230 xmlSchemaTypesBank = xmlHashCreate(40);
Daniel Veillard6560a422003-03-27 21:25:38 +0000231
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000232 /*
233 * primitive datatypes
234 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000235 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string",
Daniel Veillard6560a422003-03-27 21:25:38 +0000236 XML_SCHEMAS_STRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000237 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000238 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000239 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType",
Daniel Veillard6560a422003-03-27 21:25:38 +0000240 XML_SCHEMAS_UNKNOWN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000241 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal",
Daniel Veillard6560a422003-03-27 21:25:38 +0000242 XML_SCHEMAS_DECIMAL);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000243 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date",
Daniel Veillard6560a422003-03-27 21:25:38 +0000244 XML_SCHEMAS_DATE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000245 xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime",
Daniel Veillard6560a422003-03-27 21:25:38 +0000246 XML_SCHEMAS_DATETIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000247 xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time",
Daniel Veillard6560a422003-03-27 21:25:38 +0000248 XML_SCHEMAS_TIME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000249 xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear",
Daniel Veillard6560a422003-03-27 21:25:38 +0000250 XML_SCHEMAS_GYEAR);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000251 xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000252 XML_SCHEMAS_GYEARMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000253 xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth",
Daniel Veillard6560a422003-03-27 21:25:38 +0000254 XML_SCHEMAS_GMONTH);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000255 xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000256 XML_SCHEMAS_GMONTHDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000257 xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay",
Daniel Veillard6560a422003-03-27 21:25:38 +0000258 XML_SCHEMAS_GDAY);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000259 xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration",
Daniel Veillard6560a422003-03-27 21:25:38 +0000260 XML_SCHEMAS_DURATION);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000261 xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float",
Daniel Veillard6560a422003-03-27 21:25:38 +0000262 XML_SCHEMAS_FLOAT);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000263 xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double",
Daniel Veillard6560a422003-03-27 21:25:38 +0000264 XML_SCHEMAS_DOUBLE);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000265 xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean",
Daniel Veillard6560a422003-03-27 21:25:38 +0000266 XML_SCHEMAS_BOOLEAN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000267 xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI",
Daniel Veillard6560a422003-03-27 21:25:38 +0000268 XML_SCHEMAS_ANYURI);
Daniel Veillard4255d502002-04-16 15:50:10 +0000269
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000270 /*
271 * derived datatypes
272 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000273 xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer",
Daniel Veillard6560a422003-03-27 21:25:38 +0000274 XML_SCHEMAS_INTEGER);;
275 xmlSchemaTypeNonPositiveIntegerDef =
276 xmlSchemaInitBasicType("nonPositiveInteger",
277 XML_SCHEMAS_NPINTEGER);;
278 xmlSchemaTypeNegativeIntegerDef =
279 xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER);;
280 xmlSchemaTypeLongDef =
281 xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG);;
282 xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000283 xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short",
Daniel Veillard6560a422003-03-27 21:25:38 +0000284 XML_SCHEMAS_SHORT);;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000285 xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte",
Daniel Veillard6560a422003-03-27 21:25:38 +0000286 XML_SCHEMAS_BYTE);;
287 xmlSchemaTypeNonNegativeIntegerDef =
288 xmlSchemaInitBasicType("nonNegativeInteger",
289 XML_SCHEMAS_NNINTEGER);
290 xmlSchemaTypeUnsignedLongDef =
291 xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG);;
292 xmlSchemaTypeUnsignedIntDef =
293 xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT);;
294 xmlSchemaTypeUnsignedShortDef =
295 xmlSchemaInitBasicType("insignedShort", XML_SCHEMAS_USHORT);;
296 xmlSchemaTypeUnsignedByteDef =
297 xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE);;
298 xmlSchemaTypePositiveIntegerDef =
299 xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER);
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000300
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000301 xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString",
Daniel Veillard6560a422003-03-27 21:25:38 +0000302 XML_SCHEMAS_NORMSTRING);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000303 xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token",
Daniel Veillard6560a422003-03-27 21:25:38 +0000304 XML_SCHEMAS_TOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000305 xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language",
Daniel Veillard6560a422003-03-27 21:25:38 +0000306 XML_SCHEMAS_LANGUAGE);
307 xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000308 xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF",
Daniel Veillard6560a422003-03-27 21:25:38 +0000309 XML_SCHEMAS_IDREF);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000310 xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000311 XML_SCHEMAS_IDREFS);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000312 xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
Daniel Veillard6560a422003-03-27 21:25:38 +0000313 XML_SCHEMAS_ENTITY);
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000314 xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
Daniel Veillard6560a422003-03-27 21:25:38 +0000315 XML_SCHEMAS_ENTITIES);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000316 xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
Daniel Veillard6560a422003-03-27 21:25:38 +0000317 XML_SCHEMAS_NAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000318 xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000319 XML_SCHEMAS_QNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000320 xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName",
Daniel Veillard6560a422003-03-27 21:25:38 +0000321 XML_SCHEMAS_NCNAME);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000322 xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN",
Daniel Veillard6560a422003-03-27 21:25:38 +0000323 XML_SCHEMAS_NMTOKEN);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000324 xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS",
Daniel Veillard6560a422003-03-27 21:25:38 +0000325 XML_SCHEMAS_NMTOKENS);
Daniel Veillard4255d502002-04-16 15:50:10 +0000326 xmlSchemaTypesInitialized = 1;
327}
328
329/**
330 * xmlSchemaCleanupTypes:
331 *
332 * Cleanup the default XML Schemas type library
333 */
334void
335xmlSchemaCleanupTypes(void) {
336 if (xmlSchemaTypesInitialized == 0)
337 return;
338 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
339 xmlSchemaTypesInitialized = 0;
340}
341
342/**
343 * xmlSchemaNewValue:
344 * @type: the value type
345 *
346 * Allocate a new simple type value
347 *
348 * Returns a pointer to the new value or NULL in case of error
349 */
350static xmlSchemaValPtr
351xmlSchemaNewValue(xmlSchemaValType type) {
352 xmlSchemaValPtr value;
353
354 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
355 if (value == NULL) {
356 return(NULL);
357 }
358 memset(value, 0, sizeof(xmlSchemaVal));
359 value->type = type;
360 return(value);
361}
362
363/**
364 * xmlSchemaFreeValue:
365 * @value: the value to free
366 *
367 * Cleanup the default XML Schemas type library
368 */
369void
370xmlSchemaFreeValue(xmlSchemaValPtr value) {
371 if (value == NULL)
372 return;
373 xmlFree(value);
374}
375
376/**
377 * xmlSchemaGetPredefinedType:
378 * @name: the type name
379 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
380 *
381 * Lookup a type in the default XML Schemas type library
382 *
383 * Returns the type if found, NULL otherwise
384 */
385xmlSchemaTypePtr
386xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
387 if (xmlSchemaTypesInitialized == 0)
388 xmlSchemaInitTypes();
389 if (name == NULL)
390 return(NULL);
391 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
392}
Daniel Veillard070803b2002-05-03 07:29:38 +0000393
394/****************************************************************
395 * *
396 * Convenience macros and functions *
397 * *
398 ****************************************************************/
399
400#define IS_TZO_CHAR(c) \
401 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
402
403#define VALID_YEAR(yr) (yr != 0)
404#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
405/* VALID_DAY should only be used when month is unknown */
406#define VALID_DAY(day) ((day >= 1) && (day <= 31))
407#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
408#define VALID_MIN(min) ((min >= 0) && (min <= 59))
409#define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
410#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
411#define IS_LEAP(y) \
412 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
413
414static const long daysInMonth[12] =
415 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
416static const long daysInMonthLeap[12] =
417 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
418
Daniel Veillard5a872412002-05-22 06:40:27 +0000419#define MAX_DAYINMONTH(yr,mon) \
420 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
421
Daniel Veillard070803b2002-05-03 07:29:38 +0000422#define VALID_MDAY(dt) \
423 (IS_LEAP(dt->year) ? \
424 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
425 (dt->day <= daysInMonth[dt->mon - 1]))
426
427#define VALID_DATE(dt) \
428 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
429
430#define VALID_TIME(dt) \
431 (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \
432 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
433
434#define VALID_DATETIME(dt) \
435 (VALID_DATE(dt) && VALID_TIME(dt))
436
437#define SECS_PER_MIN (60)
438#define SECS_PER_HOUR (60 * SECS_PER_MIN)
439#define SECS_PER_DAY (24 * SECS_PER_HOUR)
440
Daniel Veillard5a872412002-05-22 06:40:27 +0000441static const long dayInYearByMonth[12] =
442 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
443static const long dayInLeapYearByMonth[12] =
444 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
445
446#define DAY_IN_YEAR(day, month, year) \
447 ((IS_LEAP(year) ? \
448 dayInLeapYearByMonth[month - 1] : \
449 dayInYearByMonth[month - 1]) + day)
450
451#ifdef DEBUG
452#define DEBUG_DATE(dt) \
453 xmlGenericError(xmlGenericErrorContext, \
454 "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \
455 dt->type,dt->value.date.year,dt->value.date.mon, \
456 dt->value.date.day,dt->value.date.hour,dt->value.date.min, \
457 dt->value.date.sec); \
458 if (dt->value.date.tz_flag) \
459 if (dt->value.date.tzo != 0) \
460 xmlGenericError(xmlGenericErrorContext, \
461 "%+05d\n",dt->value.date.tzo); \
462 else \
463 xmlGenericError(xmlGenericErrorContext, "Z\n"); \
464 else \
465 xmlGenericError(xmlGenericErrorContext,"\n")
466#else
467#define DEBUG_DATE(dt)
468#endif
469
Daniel Veillard070803b2002-05-03 07:29:38 +0000470/**
471 * _xmlSchemaParseGYear:
472 * @dt: pointer to a date structure
473 * @str: pointer to the string to analyze
474 *
475 * Parses a xs:gYear without time zone and fills in the appropriate
476 * field of the @dt structure. @str is updated to point just after the
477 * xs:gYear. It is supposed that @dt->year is big enough to contain
478 * the year.
479 *
480 * Returns 0 or the error code
481 */
482static int
483_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) {
484 const xmlChar *cur = *str, *firstChar;
485 int isneg = 0, digcnt = 0;
486
487 if (((*cur < '0') || (*cur > '9')) &&
488 (*cur != '-') && (*cur != '+'))
489 return -1;
490
491 if (*cur == '-') {
492 isneg = 1;
493 cur++;
494 }
495
496 firstChar = cur;
497
498 while ((*cur >= '0') && (*cur <= '9')) {
499 dt->year = dt->year * 10 + (*cur - '0');
500 cur++;
501 digcnt++;
502 }
503
504 /* year must be at least 4 digits (CCYY); over 4
505 * digits cannot have a leading zero. */
506 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
507 return 1;
508
509 if (isneg)
510 dt->year = - dt->year;
511
512 if (!VALID_YEAR(dt->year))
513 return 2;
514
515 *str = cur;
516 return 0;
517}
518
519/**
520 * PARSE_2_DIGITS:
521 * @num: the integer to fill in
522 * @cur: an #xmlChar *
523 * @invalid: an integer
524 *
525 * Parses a 2-digits integer and updates @num with the value. @cur is
526 * updated to point just after the integer.
527 * In case of error, @invalid is set to %TRUE, values of @num and
528 * @cur are undefined.
529 */
530#define PARSE_2_DIGITS(num, cur, invalid) \
531 if ((cur[0] < '0') || (cur[0] > '9') || \
532 (cur[1] < '0') || (cur[1] > '9')) \
533 invalid = 1; \
534 else \
535 num = (cur[0] - '0') * 10 + (cur[1] - '0'); \
536 cur += 2;
537
538/**
539 * PARSE_FLOAT:
540 * @num: the double to fill in
541 * @cur: an #xmlChar *
542 * @invalid: an integer
543 *
544 * Parses a float and updates @num with the value. @cur is
545 * updated to point just after the float. The float must have a
546 * 2-digits integer part and may or may not have a decimal part.
547 * In case of error, @invalid is set to %TRUE, values of @num and
548 * @cur are undefined.
549 */
550#define PARSE_FLOAT(num, cur, invalid) \
551 PARSE_2_DIGITS(num, cur, invalid); \
552 if (!invalid && (*cur == '.')) { \
553 double mult = 1; \
554 cur++; \
555 if ((*cur < '0') || (*cur > '9')) \
556 invalid = 1; \
557 while ((*cur >= '0') && (*cur <= '9')) { \
558 mult /= 10; \
559 num += (*cur - '0') * mult; \
560 cur++; \
561 } \
562 }
563
564/**
565 * _xmlSchemaParseGMonth:
566 * @dt: pointer to a date structure
567 * @str: pointer to the string to analyze
568 *
569 * Parses a xs:gMonth without time zone and fills in the appropriate
570 * field of the @dt structure. @str is updated to point just after the
571 * xs:gMonth.
572 *
573 * Returns 0 or the error code
574 */
575static int
576_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) {
577 const xmlChar *cur = *str;
578 int ret = 0;
579
580 PARSE_2_DIGITS(dt->mon, cur, ret);
581 if (ret != 0)
582 return ret;
583
584 if (!VALID_MONTH(dt->mon))
585 return 2;
586
587 *str = cur;
588 return 0;
589}
590
591/**
592 * _xmlSchemaParseGDay:
593 * @dt: pointer to a date structure
594 * @str: pointer to the string to analyze
595 *
596 * Parses a xs:gDay without time zone and fills in the appropriate
597 * field of the @dt structure. @str is updated to point just after the
598 * xs:gDay.
599 *
600 * Returns 0 or the error code
601 */
602static int
603_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) {
604 const xmlChar *cur = *str;
605 int ret = 0;
606
607 PARSE_2_DIGITS(dt->day, cur, ret);
608 if (ret != 0)
609 return ret;
610
611 if (!VALID_DAY(dt->day))
612 return 2;
613
614 *str = cur;
615 return 0;
616}
617
618/**
619 * _xmlSchemaParseTime:
620 * @dt: pointer to a date structure
621 * @str: pointer to the string to analyze
622 *
623 * Parses a xs:time without time zone and fills in the appropriate
624 * fields of the @dt structure. @str is updated to point just after the
625 * xs:time.
626 * In case of error, values of @dt fields are undefined.
627 *
628 * Returns 0 or the error code
629 */
630static int
631_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) {
632 const xmlChar *cur = *str;
633 unsigned int hour = 0; /* use temp var in case str is not xs:time */
634 int ret = 0;
635
636 PARSE_2_DIGITS(hour, cur, ret);
637 if (ret != 0)
638 return ret;
639
640 if (*cur != ':')
641 return 1;
642 cur++;
643
644 /* the ':' insures this string is xs:time */
645 dt->hour = hour;
646
647 PARSE_2_DIGITS(dt->min, cur, ret);
648 if (ret != 0)
649 return ret;
650
651 if (*cur != ':')
652 return 1;
653 cur++;
654
655 PARSE_FLOAT(dt->sec, cur, ret);
656 if (ret != 0)
657 return ret;
658
659 if (!VALID_TIME(dt))
660 return 2;
661
662 *str = cur;
663 return 0;
664}
665
666/**
667 * _xmlSchemaParseTimeZone:
668 * @dt: pointer to a date structure
669 * @str: pointer to the string to analyze
670 *
671 * Parses a time zone without time zone and fills in the appropriate
672 * field of the @dt structure. @str is updated to point just after the
673 * time zone.
674 *
675 * Returns 0 or the error code
676 */
677static int
678_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) {
679 const xmlChar *cur = *str;
680 int ret = 0;
681
682 if (str == NULL)
683 return -1;
684
685 switch (*cur) {
686 case 0:
687 dt->tz_flag = 0;
688 dt->tzo = 0;
689 break;
690
691 case 'Z':
692 dt->tz_flag = 1;
693 dt->tzo = 0;
694 cur++;
695 break;
696
697 case '+':
698 case '-': {
699 int isneg = 0, tmp = 0;
700 isneg = (*cur == '-');
701
702 cur++;
703
704 PARSE_2_DIGITS(tmp, cur, ret);
705 if (ret != 0)
706 return ret;
707 if (!VALID_HOUR(tmp))
708 return 2;
709
710 if (*cur != ':')
711 return 1;
712 cur++;
713
714 dt->tzo = tmp * 60;
715
716 PARSE_2_DIGITS(tmp, cur, ret);
717 if (ret != 0)
718 return ret;
719 if (!VALID_MIN(tmp))
720 return 2;
721
722 dt->tzo += tmp;
723 if (isneg)
724 dt->tzo = - dt->tzo;
725
726 if (!VALID_TZO(dt->tzo))
727 return 2;
728
Daniel Veillard5a872412002-05-22 06:40:27 +0000729 dt->tz_flag = 1;
Daniel Veillard070803b2002-05-03 07:29:38 +0000730 break;
731 }
732 default:
733 return 1;
734 }
735
736 *str = cur;
737 return 0;
738}
739
740/****************************************************************
741 * *
742 * XML Schema Dates/Times Datatypes Handling *
743 * *
744 ****************************************************************/
745
746/**
747 * PARSE_DIGITS:
748 * @num: the integer to fill in
749 * @cur: an #xmlChar *
750 * @num_type: an integer flag
751 *
752 * Parses a digits integer and updates @num with the value. @cur is
753 * updated to point just after the integer.
754 * In case of error, @num_type is set to -1, values of @num and
755 * @cur are undefined.
756 */
757#define PARSE_DIGITS(num, cur, num_type) \
758 if ((*cur < '0') || (*cur > '9')) \
759 num_type = -1; \
760 else \
761 while ((*cur >= '0') && (*cur <= '9')) { \
762 num = num * 10 + (*cur - '0'); \
763 cur++; \
764 }
765
766/**
767 * PARSE_NUM:
768 * @num: the double to fill in
769 * @cur: an #xmlChar *
770 * @num_type: an integer flag
771 *
772 * Parses a float or integer and updates @num with the value. @cur is
773 * updated to point just after the number. If the number is a float,
774 * then it must have an integer part and a decimal part; @num_type will
775 * be set to 1. If there is no decimal part, @num_type is set to zero.
776 * In case of error, @num_type is set to -1, values of @num and
777 * @cur are undefined.
778 */
779#define PARSE_NUM(num, cur, num_type) \
780 num = 0; \
781 PARSE_DIGITS(num, cur, num_type); \
782 if (!num_type && (*cur == '.')) { \
783 double mult = 1; \
784 cur++; \
785 if ((*cur < '0') || (*cur > '9')) \
786 num_type = -1; \
787 else \
788 num_type = 1; \
789 while ((*cur >= '0') && (*cur <= '9')) { \
790 mult /= 10; \
791 num += (*cur - '0') * mult; \
792 cur++; \
793 } \
794 }
795
796/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000797 * xmlSchemaValidateDates:
Daniel Veillard070803b2002-05-03 07:29:38 +0000798 * @type: the predefined type
799 * @dateTime: string to analyze
800 * @val: the return computed value
801 *
802 * Check that @dateTime conforms to the lexical space of one of the date types.
803 * if true a value is computed and returned in @val.
804 *
805 * Returns 0 if this validates, a positive error code number otherwise
806 * and -1 in case of internal or API error.
807 */
808static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000809xmlSchemaValidateDates (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000810 const xmlChar *dateTime, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000811 xmlSchemaValPtr dt;
812 int ret;
813 const xmlChar *cur = dateTime;
814
815#define RETURN_TYPE_IF_VALID(t) \
816 if (IS_TZO_CHAR(*cur)) { \
817 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \
818 if (ret == 0) { \
819 if (*cur != 0) \
820 goto error; \
821 dt->type = t; \
822 if (val != NULL) \
823 *val = dt; \
Daniel Veillard80b19092003-03-28 13:29:53 +0000824 else \
825 xmlSchemaFreeValue(dt); \
Daniel Veillard070803b2002-05-03 07:29:38 +0000826 return 0; \
827 } \
828 }
829
830 if (dateTime == NULL)
831 return -1;
832
833 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
834 return 1;
835
836 dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN);
837 if (dt == NULL)
838 return -1;
839
840 if ((cur[0] == '-') && (cur[1] == '-')) {
841 /*
842 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
843 * xs:gDay)
844 */
845 cur += 2;
846
847 /* is it an xs:gDay? */
848 if (*cur == '-') {
849 ++cur;
850 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
851 if (ret != 0)
852 goto error;
853
854 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY);
855
856 goto error;
857 }
858
859 /*
860 * it should be an xs:gMonthDay or xs:gMonth
861 */
862 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
863 if (ret != 0)
864 goto error;
865
866 if (*cur != '-')
867 goto error;
868 cur++;
869
870 /* is it an xs:gMonth? */
871 if (*cur == '-') {
872 cur++;
873 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH);
874 goto error;
875 }
876
877 /* it should be an xs:gMonthDay */
878 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
879 if (ret != 0)
880 goto error;
881
882 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY);
883
884 goto error;
885 }
886
887 /*
888 * It's a right-truncated date or an xs:time.
889 * Try to parse an xs:time then fallback on right-truncated dates.
890 */
891 if ((*cur >= '0') && (*cur <= '9')) {
892 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
893 if (ret == 0) {
894 /* it's an xs:time */
895 RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME);
896 }
897 }
898
899 /* fallback on date parsing */
900 cur = dateTime;
901
902 ret = _xmlSchemaParseGYear(&(dt->value.date), &cur);
903 if (ret != 0)
904 goto error;
905
906 /* is it an xs:gYear? */
907 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR);
908
909 if (*cur != '-')
910 goto error;
911 cur++;
912
913 ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur);
914 if (ret != 0)
915 goto error;
916
917 /* is it an xs:gYearMonth? */
918 RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH);
919
920 if (*cur != '-')
921 goto error;
922 cur++;
923
924 ret = _xmlSchemaParseGDay(&(dt->value.date), &cur);
925 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
926 goto error;
927
928 /* is it an xs:date? */
929 RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE);
930
931 if (*cur != 'T')
932 goto error;
933 cur++;
934
935 /* it should be an xs:dateTime */
936 ret = _xmlSchemaParseTime(&(dt->value.date), &cur);
937 if (ret != 0)
938 goto error;
939
940 ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur);
941 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
942 goto error;
943
944 dt->type = XML_SCHEMAS_DATETIME;
945
946 if (val != NULL)
947 *val = dt;
Daniel Veillard80b19092003-03-28 13:29:53 +0000948 else
949 xmlSchemaFreeValue(dt);
Daniel Veillard070803b2002-05-03 07:29:38 +0000950
951 return 0;
952
953error:
954 if (dt != NULL)
955 xmlSchemaFreeValue(dt);
956 return 1;
957}
958
959/**
Daniel Veillard5a872412002-05-22 06:40:27 +0000960 * xmlSchemaValidateDuration:
Daniel Veillard070803b2002-05-03 07:29:38 +0000961 * @type: the predefined type
962 * @duration: string to analyze
963 * @val: the return computed value
964 *
965 * Check that @duration conforms to the lexical space of the duration type.
966 * if true a value is computed and returned in @val.
967 *
968 * Returns 0 if this validates, a positive error code number otherwise
969 * and -1 in case of internal or API error.
970 */
971static int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000972xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +0000973 const xmlChar *duration, xmlSchemaValPtr *val) {
Daniel Veillard070803b2002-05-03 07:29:38 +0000974 const xmlChar *cur = duration;
975 xmlSchemaValPtr dur;
976 int isneg = 0;
977 unsigned int seq = 0;
978
979 if (duration == NULL)
980 return -1;
981
982 if (*cur == '-') {
983 isneg = 1;
984 cur++;
985 }
986
987 /* duration must start with 'P' (after sign) */
988 if (*cur++ != 'P')
989 return 1;
990
Daniel Veillard80b19092003-03-28 13:29:53 +0000991 if (*cur == 0)
992 return 1;
993
Daniel Veillard070803b2002-05-03 07:29:38 +0000994 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
995 if (dur == NULL)
996 return -1;
997
998 while (*cur != 0) {
999 double num;
1000 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1001 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1002 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
1003
1004 /* input string should be empty or invalid date/time item */
1005 if (seq >= sizeof(desig))
1006 goto error;
1007
1008 /* T designator must be present for time items */
1009 if (*cur == 'T') {
1010 if (seq <= 3) {
1011 seq = 3;
1012 cur++;
1013 } else
1014 return 1;
1015 } else if (seq == 3)
1016 goto error;
1017
1018 /* parse the number portion of the item */
1019 PARSE_NUM(num, cur, num_type);
1020
1021 if ((num_type == -1) || (*cur == 0))
1022 goto error;
1023
1024 /* update duration based on item type */
1025 while (seq < sizeof(desig)) {
1026 if (*cur == desig[seq]) {
1027
1028 /* verify numeric type; only seconds can be float */
1029 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1030 goto error;
1031
1032 switch (seq) {
1033 case 0:
1034 dur->value.dur.mon = (long)num * 12;
1035 break;
1036 case 1:
1037 dur->value.dur.mon += (long)num;
1038 break;
1039 default:
1040 /* convert to seconds using multiplier */
1041 dur->value.dur.sec += num * multi[seq];
1042 seq++;
1043 break;
1044 }
1045
1046 break; /* exit loop */
1047 }
1048 /* no date designators found? */
1049 if (++seq == 3)
1050 goto error;
1051 }
1052 cur++;
1053 }
1054
1055 if (isneg) {
1056 dur->value.dur.mon = -dur->value.dur.mon;
1057 dur->value.dur.day = -dur->value.dur.day;
1058 dur->value.dur.sec = -dur->value.dur.sec;
1059 }
1060
1061 if (val != NULL)
1062 *val = dur;
Daniel Veillard80b19092003-03-28 13:29:53 +00001063 else
1064 xmlSchemaFreeValue(dur);
Daniel Veillard070803b2002-05-03 07:29:38 +00001065
1066 return 0;
1067
1068error:
1069 if (dur != NULL)
1070 xmlSchemaFreeValue(dur);
1071 return 1;
1072}
1073
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001074/**
1075 * xmlSchemaStrip:
1076 * @value: a value
1077 *
1078 * Removes the leading and ending spaces of a string
1079 *
1080 * Returns the new string or NULL if no change was required.
1081 */
1082static xmlChar *
1083xmlSchemaStrip(const xmlChar *value) {
1084 const xmlChar *start = value, *end, *f;
1085
1086 if (value == NULL) return(NULL);
1087 while ((*start != 0) && (IS_BLANK(*start))) start++;
1088 end = start;
1089 while (*end != 0) end++;
1090 f = end;
1091 end--;
1092 while ((end > start) && (IS_BLANK(*end))) end--;
1093 end++;
1094 if ((start == value) && (f == end)) return(NULL);
1095 return(xmlStrndup(start, end - start));
1096}
Daniel Veillard96a4b252003-02-06 08:22:32 +00001097
1098/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001099 * xmlSchemaValAtomicListNode:
1100 * @type: the predefined atomic type for a token in the list
1101 * @value: the list value to check
1102 * @ret: the return computed value
1103 * @node: the node containing the value
1104 *
1105 * Check that a value conforms to the lexical space of the predefined
1106 * list type. if true a value is computed and returned in @ret.
1107 *
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001108 * Returns the number of items if this validates, a negative error code
1109 * number otherwise
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001110 */
1111static int
1112xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
1113 xmlSchemaValPtr *ret, xmlNodePtr node) {
1114 xmlChar *val, *cur, *endval;
1115 int nb_values = 0;
Daniel Veillard580ced82003-03-21 21:22:48 +00001116 int tmp = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001117
1118 if (value == NULL) {
1119 return(-1);
1120 }
1121 val = xmlStrdup(value);
1122 if (val == NULL) {
1123 return(-1);
1124 }
1125 cur = val;
1126 /*
1127 * Split the list
1128 */
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001129 while (IS_BLANK(*cur)) *cur++ = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001130 while (*cur != 0) {
1131 if (IS_BLANK(*cur)) {
1132 *cur = 0;
1133 cur++;
1134 while (IS_BLANK(*cur)) *cur++ = 0;
1135 } else {
1136 nb_values++;
1137 cur++;
1138 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
1139 }
1140 }
1141 if (nb_values == 0) {
1142 if (ret != NULL) {
1143 TODO
1144 }
1145 xmlFree(val);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001146 return(nb_values);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001147 }
1148 endval = cur;
1149 cur = val;
1150 while ((*cur == 0) && (cur != endval)) cur++;
1151 while (cur != endval) {
1152 tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node);
1153 if (tmp != 0)
1154 break;
1155 while (*cur != 0) cur++;
1156 while ((*cur == 0) && (cur != endval)) cur++;
1157 }
1158 xmlFree(val);
1159 if (ret != NULL) {
1160 TODO
1161 }
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001162 if (tmp == 0)
1163 return(nb_values);
1164 return(-1);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001165}
1166
1167/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001168 * xmlSchemaValPredefTypeNode:
Daniel Veillard4255d502002-04-16 15:50:10 +00001169 * @type: the predefined type
1170 * @value: the value to check
1171 * @val: the return computed value
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001172 * @node: the node containing the value
Daniel Veillard4255d502002-04-16 15:50:10 +00001173 *
1174 * Check that a value conforms to the lexical space of the predefined type.
1175 * if true a value is computed and returned in @val.
1176 *
1177 * Returns 0 if this validates, a positive error code number otherwise
1178 * and -1 in case of internal or API error.
1179 */
1180int
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001181xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value,
1182 xmlSchemaValPtr *val, xmlNodePtr node) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001183 xmlSchemaValPtr v;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001184 int ret;
Daniel Veillard4255d502002-04-16 15:50:10 +00001185
1186 if (xmlSchemaTypesInitialized == 0)
1187 return(-1);
1188 if (type == NULL)
1189 return(-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00001190
Daniel Veillard4255d502002-04-16 15:50:10 +00001191 if (val != NULL)
1192 *val = NULL;
1193 if (type == xmlSchemaTypeStringDef) {
1194 return(0);
1195 } else if (type == xmlSchemaTypeAnyTypeDef) {
1196 return(0);
1197 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
1198 return(0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001199 } else if (type == xmlSchemaTypeNmtokenDef) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001200 if (xmlValidateNMToken(value, 1) == 0)
Daniel Veillard4255d502002-04-16 15:50:10 +00001201 return(0);
1202 return(1);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001203 } else if (type == xmlSchemaTypeNmtokensDef) {
1204 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
1205 value, val, node);
1206 if (ret >= 0)
1207 ret = 0;
1208 else
1209 ret = 1;
1210 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001211 } else if (type == xmlSchemaTypeDecimalDef) {
1212 const xmlChar *cur = value, *tmp;
Daniel Veillard5a872412002-05-22 06:40:27 +00001213 int frac = 0, len, neg = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001214 unsigned long base = 0;
1215 if (cur == NULL)
1216 return(1);
1217 if (*cur == '+')
1218 cur++;
1219 else if (*cur == '-') {
1220 neg = 1;
1221 cur++;
1222 }
1223 tmp = cur;
1224 while ((*cur >= '0') && (*cur <= '9')) {
1225 base = base * 10 + (*cur - '0');
1226 cur++;
1227 }
Daniel Veillard5a872412002-05-22 06:40:27 +00001228 len = cur - tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00001229 if (*cur == '.') {
1230 cur++;
1231 tmp = cur;
1232 while ((*cur >= '0') && (*cur <= '9')) {
1233 base = base * 10 + (*cur - '0');
1234 cur++;
1235 }
1236 frac = cur - tmp;
1237 }
1238 if (*cur != 0)
1239 return(1);
1240 if (val != NULL) {
1241 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1242 if (v != NULL) {
1243 v->value.decimal.base = base;
1244 v->value.decimal.sign = neg;
1245 v->value.decimal.frac = frac;
Daniel Veillard5a872412002-05-22 06:40:27 +00001246 v->value.decimal.total = frac + len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001247 *val = v;
1248 }
1249 }
1250 return(0);
Daniel Veillard070803b2002-05-03 07:29:38 +00001251 } else if (type == xmlSchemaTypeDurationDef) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001252 return xmlSchemaValidateDuration(type, value, val);
Daniel Veillard070803b2002-05-03 07:29:38 +00001253 } else if ((type == xmlSchemaTypeDatetimeDef) ||
1254 (type == xmlSchemaTypeTimeDef) ||
1255 (type == xmlSchemaTypeDateDef) ||
1256 (type == xmlSchemaTypeGYearDef) ||
1257 (type == xmlSchemaTypeGYearMonthDef) ||
1258 (type == xmlSchemaTypeGMonthDef) ||
1259 (type == xmlSchemaTypeGMonthDayDef) ||
1260 (type == xmlSchemaTypeGDayDef)) {
Daniel Veillard5a872412002-05-22 06:40:27 +00001261 return xmlSchemaValidateDates(type, value, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001262 } else if (type == xmlSchemaTypePositiveIntegerDef) {
1263 const xmlChar *cur = value;
1264 unsigned long base = 0;
1265 int total = 0;
1266 if (cur == NULL)
1267 return(1);
1268 if (*cur == '+')
1269 cur++;
1270 while ((*cur >= '0') && (*cur <= '9')) {
1271 base = base * 10 + (*cur - '0');
1272 total++;
1273 cur++;
1274 }
1275 if (*cur != 0)
1276 return(1);
1277 if (val != NULL) {
1278 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1279 if (v != NULL) {
1280 v->value.decimal.base = base;
1281 v->value.decimal.sign = 0;
1282 v->value.decimal.frac = 0;
1283 v->value.decimal.total = total;
1284 *val = v;
1285 }
1286 }
1287 return(0);
1288 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
1289 const xmlChar *cur = value;
1290 unsigned long base = 0;
1291 int total = 0;
1292 int sign = 0;
1293 if (cur == NULL)
1294 return(1);
1295 if (*cur == '-') {
1296 sign = 1;
1297 cur++;
Daniel Veillard91a13252003-03-27 23:44:43 +00001298 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001299 while ((*cur >= '0') && (*cur <= '9')) {
1300 base = base * 10 + (*cur - '0');
1301 total++;
1302 cur++;
1303 }
1304 if (*cur != 0)
1305 return(1);
1306 if ((sign == 1) && (base != 0))
1307 return(1);
1308 if (val != NULL) {
1309 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1310 if (v != NULL) {
1311 v->value.decimal.base = base;
1312 v->value.decimal.sign = 0;
1313 v->value.decimal.frac = 0;
1314 v->value.decimal.total = total;
1315 *val = v;
1316 }
1317 }
1318 return(0);
Daniel Veillard91a13252003-03-27 23:44:43 +00001319 } else if (type == xmlSchemaTypeNonPositiveIntegerDef) {
1320 const xmlChar *cur = value;
1321 unsigned long base = 0;
1322 int total = 0;
1323 int sign = 0;
1324 if (cur == NULL)
1325 return(1);
1326 if (*cur == '-') {
1327 sign = 1;
1328 cur++;
1329 }
1330 while ((*cur >= '0') && (*cur <= '9')) {
1331 base = base * 10 + (*cur - '0');
1332 total++;
1333 cur++;
1334 }
1335 if (*cur != 0)
1336 return(1);
1337 if ((sign != 1) && (base != 0))
1338 return(1);
1339 if (val != NULL) {
1340 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
1341 if (v != NULL) {
1342 v->value.decimal.base = base;
1343 v->value.decimal.sign = 0;
1344 v->value.decimal.frac = 0;
1345 v->value.decimal.total = total;
1346 *val = v;
1347 }
1348 }
1349 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001350 } else if (type == xmlSchemaTypeIntDef) {
1351 const xmlChar *cur = value;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001352 unsigned long base = 0;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001353 int total = 0;
1354 int sign = 0;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001355 if (cur == NULL)
1356 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001357 if (*cur == '-') {
1358 sign = 1;
1359 cur++;
1360 } else if (*cur == '+')
1361 cur++;
1362 while (*cur == '0') {
1363 total++;
1364 cur++;
1365 }
1366 while ((*cur >= '0') && (*cur <= '9')) {
1367 base = base * 10 + (*cur - '0');
1368 total++;
1369 cur++;
1370 }
1371 if (*cur != 0)
1372 return(1);
1373 if ((sign == 1) && (total == 0))
1374 return(1);
1375 if (val != NULL) {
1376 v = xmlSchemaNewValue(XML_SCHEMAS_INT);
1377 if (v != NULL) {
1378 v->value.decimal.base = base;
1379 v->value.decimal.sign = sign;
1380 v->value.decimal.frac = 0;
1381 v->value.decimal.total = total;
1382 *val = v;
1383 }
1384 }
1385 return(0);
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001386 } else if (type == xmlSchemaTypeIntegerDef) {
1387 const xmlChar *cur = value;
1388 unsigned long base = 0;
1389 int total = 0;
1390 int sign = 0;
1391 if (cur == NULL)
1392 return(1);
1393 if (*cur == '-') {
1394 sign = 1;
1395 cur++;
1396 } else if (*cur == '+')
1397 cur++;
1398 while (*cur == '0') {
1399 total++;
1400 cur++;
1401 }
1402 while ((*cur >= '0') && (*cur <= '9')) {
1403 base = base * 10 + (*cur - '0');
1404 total++;
1405 cur++;
1406 }
1407 if (*cur != 0)
1408 return(1);
1409 if ((sign == 1) && (total == 0))
1410 return(1);
1411 if (val != NULL) {
1412 v = xmlSchemaNewValue(XML_SCHEMAS_INTEGER);
1413 if (v != NULL) {
1414 v->value.decimal.base = base;
1415 v->value.decimal.sign = sign;
1416 v->value.decimal.frac = 0;
1417 v->value.decimal.total = total;
1418 *val = v;
1419 }
1420 }
1421 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001422 } else if ((type == xmlSchemaTypeFloatDef) ||
1423 (type == xmlSchemaTypeDoubleDef)) {
1424 const xmlChar *cur = value;
1425 int neg = 0;
1426 if (cur == NULL)
1427 return(1);
1428 if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) {
1429 cur += 3;
1430 if (*cur != 0)
1431 return(1);
1432 if (val != NULL) {
1433 if (type == xmlSchemaTypeFloatDef) {
1434 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1435 if (v != NULL) {
1436 v->value.f = (float) xmlXPathNAN;
1437 } else {
1438 xmlSchemaFreeValue(v);
1439 return(-1);
1440 }
1441 } else {
1442 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1443 if (v != NULL) {
1444 v->value.d = xmlXPathNAN;
1445 } else {
1446 xmlSchemaFreeValue(v);
1447 return(-1);
1448 }
1449 }
1450 *val = v;
1451 }
1452 return(0);
1453 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001454 if (*cur == '+')
1455 cur++;
1456 else if (*cur == '-') {
1457 neg = 1;
1458 cur++;
1459 }
Daniel Veillardd4310742003-02-18 21:12:46 +00001460 if (cur[0] == 0)
1461 return(1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001462 if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
1463 cur += 3;
1464 if (*cur != 0)
1465 return(1);
1466 if (val != NULL) {
1467 if (type == xmlSchemaTypeFloatDef) {
1468 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1469 if (v != NULL) {
1470 if (neg)
1471 v->value.f = (float) xmlXPathNINF;
1472 else
1473 v->value.f = (float) xmlXPathPINF;
1474 } else {
1475 xmlSchemaFreeValue(v);
1476 return(-1);
1477 }
1478 } else {
1479 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1480 if (v != NULL) {
1481 if (neg)
1482 v->value.d = xmlXPathNINF;
1483 else
1484 v->value.d = xmlXPathPINF;
1485 } else {
1486 xmlSchemaFreeValue(v);
1487 return(-1);
1488 }
1489 }
1490 *val = v;
1491 }
1492 return(0);
1493 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001494 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard84d70a42002-09-16 10:51:38 +00001495 cur++;
1496 }
Daniel Veillard84d70a42002-09-16 10:51:38 +00001497 if (*cur == '.') {
1498 cur++;
Daniel Veillard96a4b252003-02-06 08:22:32 +00001499 while ((*cur >= '0') && (*cur <= '9'))
Daniel Veillard84d70a42002-09-16 10:51:38 +00001500 cur++;
Daniel Veillard84d70a42002-09-16 10:51:38 +00001501 }
Daniel Veillard96a4b252003-02-06 08:22:32 +00001502 if ((*cur == 'e') || (*cur == 'E')) {
1503 cur++;
1504 if (*cur == '-')
1505 cur++;
1506 while ((*cur >= '0') && (*cur <= '9'))
1507 cur++;
1508 }
1509 if (*cur != 0)
1510 return(1);
1511 if (val != NULL) {
1512 if (type == xmlSchemaTypeFloatDef) {
1513 v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT);
1514 if (v != NULL) {
1515 if (sscanf((const char *)value, "%f", &(v->value.f))==1) {
1516 *val = v;
1517 } else {
1518 xmlGenericError(xmlGenericErrorContext,
1519 "failed to scanf float %s\n", value);
1520 xmlSchemaFreeValue(v);
1521 return(1);
1522 }
1523 } else {
1524 return(-1);
1525 }
1526 } else {
1527 v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE);
1528 if (v != NULL) {
1529 if (sscanf((const char *)value, "%lf", &(v->value.d))==1) {
1530 *val = v;
1531 } else {
1532 xmlGenericError(xmlGenericErrorContext,
1533 "failed to scanf double %s\n", value);
1534 xmlSchemaFreeValue(v);
1535 return(1);
1536 }
1537 } else {
1538 return(-1);
1539 }
1540 }
1541 }
Daniel Veillardb5c05732002-09-20 13:36:25 +00001542 return(0);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001543 } else if (type == xmlSchemaTypeNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001544 ret = xmlValidateName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001545 if ((ret == 0) && (val != NULL)) {
1546 TODO;
1547 }
1548 return(ret);
1549 } else if (type == xmlSchemaTypeQNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001550 ret = xmlValidateQName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001551 if ((ret == 0) && (val != NULL)) {
1552 TODO;
1553 }
1554 return(ret);
1555 } else if (type == xmlSchemaTypeNCNameDef) {
Daniel Veillardd2298792003-02-14 16:54:11 +00001556 ret = xmlValidateNCName(value, 1);
Daniel Veillard96a4b252003-02-06 08:22:32 +00001557 if ((ret == 0) && (val != NULL)) {
1558 TODO;
1559 }
1560 return(ret);
1561 } else if (type == xmlSchemaTypeAnyURIDef) {
1562 xmlURIPtr uri;
1563
1564 uri = xmlParseURI((const char *) value);
1565 if (uri == NULL)
1566 return(1);
1567 if (val != NULL) {
1568 TODO;
1569 }
1570 xmlFreeURI(uri);
Daniel Veillardb5c05732002-09-20 13:36:25 +00001571 return(0);
Daniel Veillardc5a70f22003-02-06 23:41:59 +00001572 } else if (type == xmlSchemaTypeBooleanDef) {
1573 const xmlChar *cur = value;
1574
1575 if ((cur[0] == '0') && (cur[1] == 0))
1576 ret = 0;
1577 else if ((cur[0] == '1') && (cur[1] == 0))
1578 ret = 1;
1579 else if ((cur[0] == 't') && (cur[1] == 'r') && (cur[2] == 'u') &&
1580 (cur[3] == 'e') && (cur[4] == 0))
1581 ret = 1;
1582 else if ((cur[0] == 'f') && (cur[1] == 'a') && (cur[2] == 'l') &&
1583 (cur[3] == 's') && (cur[4] == 'e') && (cur[5] == 0))
1584 ret = 0;
1585 else
1586 return(1);
1587 if (val != NULL) {
1588 v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN);
1589 if (v != NULL) {
1590 v->value.b = ret;
1591 *val = v;
1592 } else {
1593 return(-1);
1594 }
1595 }
1596 return(0);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001597 } else if (type == xmlSchemaTypeIdrefDef) {
1598 ret = xmlValidateNCName(value, 1);
1599 if ((ret == 0) && (val != NULL)) {
1600 TODO;
1601 }
1602 if ((ret == 0) && (node != NULL) &&
1603 (node->type == XML_ATTRIBUTE_NODE)) {
1604 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001605 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001606
Daniel Veillardef2e4ec2003-03-20 16:23:26 +00001607 strip = xmlSchemaStrip(value);
1608 if (strip != NULL) {
1609 xmlAddRef(NULL, node->doc, strip, attr);
1610 xmlFree(strip);
1611 } else
1612 xmlAddRef(NULL, node->doc, value, attr);
1613 attr->atype = XML_ATTRIBUTE_IDREF;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001614 }
1615 return(ret);
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001616 } else if (type == xmlSchemaTypeIdrefsDef) {
1617 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
1618 value, val, node);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001619 if (ret < 0)
1620 ret = 2;
1621 else
1622 ret = 0;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001623 if ((ret == 0) && (node != NULL) &&
1624 (node->type == XML_ATTRIBUTE_NODE)) {
1625 xmlAttrPtr attr = (xmlAttrPtr) node;
1626
1627 attr->atype = XML_ATTRIBUTE_IDREFS;
1628 }
1629 return(ret);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001630 } else if (type == xmlSchemaTypeIdDef) {
1631 ret = xmlValidateNCName(value, 1);
1632 if ((ret == 0) && (val != NULL)) {
1633 TODO;
1634 }
1635 if ((ret == 0) && (node != NULL) &&
1636 (node->type == XML_ATTRIBUTE_NODE)) {
1637 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001638 /*
1639 * NOTE: the IDness might have already be declared in the DTD
1640 */
1641 if (attr->atype != XML_ATTRIBUTE_ID) {
1642 xmlIDPtr res;
1643 xmlChar *strip;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001644
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001645 strip = xmlSchemaStrip(value);
1646 if (strip != NULL) {
1647 res = xmlAddID(NULL, node->doc, strip, attr);
1648 xmlFree(strip);
1649 } else
1650 res = xmlAddID(NULL, node->doc, value, attr);
1651 if (res == NULL) {
1652 ret = 2;
1653 } else {
1654 attr->atype = XML_ATTRIBUTE_ID;
1655 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001656 }
1657 }
1658 return(ret);
Daniel Veillarda1a9d042003-03-18 16:53:17 +00001659 } else if (type == xmlSchemaTypeEntitiesDef) {
1660 if ((node == NULL) || (node->doc == NULL))
1661 return(3);
1662 ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
1663 value, val, node);
1664 if (ret <= 0)
1665 ret = 1;
1666 else
1667 ret = 0;
1668 if ((ret == 0) && (node != NULL) &&
1669 (node->type == XML_ATTRIBUTE_NODE)) {
1670 xmlAttrPtr attr = (xmlAttrPtr) node;
1671
1672 attr->atype = XML_ATTRIBUTE_ENTITIES;
1673 }
1674 return(ret);
1675 } else if (type == xmlSchemaTypeEntityDef) {
1676 xmlChar *strip;
1677 ret = xmlValidateNCName(value, 1);
1678 if ((node == NULL) || (node->doc == NULL))
1679 ret = 3;
1680 if (ret == 0) {
1681 xmlEntityPtr ent;
1682
1683 strip = xmlSchemaStrip(value);
1684 if (strip != NULL) {
1685 ent = xmlGetDocEntity(node->doc, strip);
1686 xmlFree(strip);
1687 } else {
1688 ent = xmlGetDocEntity(node->doc, value);
1689 }
1690 if ((ent == NULL) ||
1691 (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
1692 ret = 4;
1693 }
1694 if ((ret == 0) && (val != NULL)) {
1695 TODO;
1696 }
1697 if ((ret == 0) && (node != NULL) &&
1698 (node->type == XML_ATTRIBUTE_NODE)) {
1699 xmlAttrPtr attr = (xmlAttrPtr) node;
1700
1701 attr->atype = XML_ATTRIBUTE_ENTITY;
1702 }
1703 return(ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001704 }
Daniel Veillard09628212003-03-25 15:10:27 +00001705 TODO
1706 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001707}
1708
1709/**
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001710 * xmlSchemaValidatePredefinedType:
1711 * @type: the predefined type
1712 * @value: the value to check
1713 * @val: the return computed value
1714 *
1715 * Check that a value conforms to the lexical space of the predefined type.
1716 * if true a value is computed and returned in @val.
1717 *
1718 * Returns 0 if this validates, a positive error code number otherwise
1719 * and -1 in case of internal or API error.
1720 */
1721int
1722xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
1723 xmlSchemaValPtr *val) {
1724 return(xmlSchemaValPredefTypeNode(type, value, val, NULL));
1725}
1726
1727/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001728 * xmlSchemaCompareDecimals:
1729 * @x: a first decimal value
1730 * @y: a second decimal value
1731 *
1732 * Compare 2 decimals
1733 *
1734 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
1735 */
1736static int
1737xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
1738{
1739 xmlSchemaValPtr swp;
1740 int order = 1;
1741 unsigned long tmp;
1742
Daniel Veillard80b19092003-03-28 13:29:53 +00001743 if ((x->value.decimal.sign) && (x->value.decimal.base != 0)) {
1744 if ((y->value.decimal.sign) && (y->value.decimal.base != 0))
1745 order = -1;
1746 else
1747 return (-1);
1748 } else if ((y->value.decimal.sign) && (y->value.decimal.base != 0)) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001749 return (1);
Daniel Veillard80b19092003-03-28 13:29:53 +00001750 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001751 if (x->value.decimal.frac == y->value.decimal.frac) {
1752 if (x->value.decimal.base < y->value.decimal.base)
Daniel Veillard80b19092003-03-28 13:29:53 +00001753 return (-order);
1754 if (x->value.decimal.base > y->value.decimal.base)
1755 return(order);
1756 return(0);
Daniel Veillard4255d502002-04-16 15:50:10 +00001757 }
1758 if (y->value.decimal.frac > x->value.decimal.frac) {
1759 swp = y;
1760 y = x;
1761 x = swp;
1762 order = -order;
1763 }
1764 tmp =
1765 x->value.decimal.base / powten[x->value.decimal.frac -
1766 y->value.decimal.frac];
1767 if (tmp > y->value.decimal.base)
1768 return (order);
1769 if (tmp < y->value.decimal.base)
1770 return (-order);
1771 tmp =
1772 y->value.decimal.base * powten[x->value.decimal.frac -
1773 y->value.decimal.frac];
1774 if (x->value.decimal.base < tmp)
1775 return (-order);
1776 if (x->value.decimal.base == tmp)
1777 return (0);
1778 return (order);
1779}
1780
1781/**
Daniel Veillard070803b2002-05-03 07:29:38 +00001782 * xmlSchemaCompareDurations:
1783 * @x: a first duration value
1784 * @y: a second duration value
1785 *
1786 * Compare 2 durations
1787 *
1788 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
1789 * case of error
1790 */
1791static int
1792xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y)
1793{
1794 long carry, mon, day;
1795 double sec;
Daniel Veillard80b19092003-03-28 13:29:53 +00001796 int invert = 1;
1797 long xmon, xday, myear, minday, maxday;
Daniel Veillard070803b2002-05-03 07:29:38 +00001798 static const long dayRange [2][12] = {
1799 { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, },
1800 { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} };
1801
1802 if ((x == NULL) || (y == NULL))
Daniel Veillard5a872412002-05-22 06:40:27 +00001803 return -2;
Daniel Veillard070803b2002-05-03 07:29:38 +00001804
1805 /* months */
1806 mon = x->value.dur.mon - y->value.dur.mon;
1807
1808 /* seconds */
1809 sec = x->value.dur.sec - y->value.dur.sec;
1810 carry = (long)sec / SECS_PER_DAY;
1811 sec -= (double)(carry * SECS_PER_DAY);
1812
1813 /* days */
1814 day = x->value.dur.day - y->value.dur.day + carry;
1815
1816 /* easy test */
1817 if (mon == 0) {
1818 if (day == 0)
1819 if (sec == 0.0)
1820 return 0;
1821 else if (sec < 0.0)
1822 return -1;
1823 else
1824 return 1;
1825 else if (day < 0)
1826 return -1;
1827 else
1828 return 1;
1829 }
1830
1831 if (mon > 0) {
1832 if ((day >= 0) && (sec >= 0.0))
1833 return 1;
1834 else {
1835 xmon = mon;
1836 xday = -day;
1837 }
1838 } else if ((day <= 0) && (sec <= 0.0)) {
1839 return -1;
1840 } else {
Daniel Veillard80b19092003-03-28 13:29:53 +00001841 invert = -1;
Daniel Veillard070803b2002-05-03 07:29:38 +00001842 xmon = -mon;
1843 xday = day;
1844 }
1845
1846 myear = xmon / 12;
Daniel Veillard80b19092003-03-28 13:29:53 +00001847 if (myear == 0) {
1848 minday = 0;
1849 maxday = 0;
1850 } else {
1851 maxday = 366 * ((myear + 3) / 4) +
1852 365 * ((myear - 1) % 4);
1853 minday = maxday - 1;
1854 }
1855
Daniel Veillard070803b2002-05-03 07:29:38 +00001856 xmon = xmon % 12;
1857 minday += dayRange[0][xmon];
1858 maxday += dayRange[1][xmon];
1859
Daniel Veillard80b19092003-03-28 13:29:53 +00001860 if ((maxday == minday) && (maxday == xday))
1861 return(0); /* can this really happen ? */
Daniel Veillard070803b2002-05-03 07:29:38 +00001862 if (maxday < xday)
Daniel Veillard80b19092003-03-28 13:29:53 +00001863 return(-invert);
1864 if (minday > xday)
1865 return(invert);
Daniel Veillard070803b2002-05-03 07:29:38 +00001866
1867 /* indeterminate */
Daniel Veillard5a872412002-05-22 06:40:27 +00001868 return 2;
1869}
1870
1871/*
1872 * macros for adding date/times and durations
1873 */
1874#define FQUOTIENT(a,b) (floor(((double)a/(double)b)))
1875#define MODULO(a,b) (a - FQUOTIENT(a,b) * b)
1876#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1877#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1878
1879/**
1880 * _xmlSchemaDateAdd:
1881 * @dt: an #xmlSchemaValPtr
1882 * @dur: an #xmlSchemaValPtr of type #XS_DURATION
1883 *
1884 * Compute a new date/time from @dt and @dur. This function assumes @dt
1885 * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH,
1886 * or #XML_SCHEMAS_GYEAR.
1887 *
1888 * Returns date/time pointer or NULL.
1889 */
1890static xmlSchemaValPtr
1891_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur)
1892{
1893 xmlSchemaValPtr ret;
1894 long carry, tempdays, temp;
1895 xmlSchemaValDatePtr r, d;
1896 xmlSchemaValDurationPtr u;
1897
1898 if ((dt == NULL) || (dur == NULL))
1899 return NULL;
1900
1901 ret = xmlSchemaNewValue(dt->type);
1902 if (ret == NULL)
1903 return NULL;
1904
1905 r = &(ret->value.date);
1906 d = &(dt->value.date);
1907 u = &(dur->value.dur);
1908
1909 /* normalization */
1910 if (d->mon == 0)
1911 d->mon = 1;
1912
1913 /* normalize for time zone offset */
1914 u->sec -= (d->tzo * 60);
1915 d->tzo = 0;
1916
1917 /* normalization */
1918 if (d->day == 0)
1919 d->day = 1;
1920
1921 /* month */
1922 carry = d->mon + u->mon;
1923 r->mon = MODULO_RANGE(carry, 1, 13);
1924 carry = FQUOTIENT_RANGE(carry, 1, 13);
1925
1926 /* year (may be modified later) */
1927 r->year = d->year + carry;
1928 if (r->year == 0) {
1929 if (d->year > 0)
1930 r->year--;
1931 else
1932 r->year++;
1933 }
1934
1935 /* time zone */
1936 r->tzo = d->tzo;
1937 r->tz_flag = d->tz_flag;
1938
1939 /* seconds */
1940 r->sec = d->sec + u->sec;
1941 carry = FQUOTIENT((long)r->sec, 60);
1942 if (r->sec != 0.0) {
1943 r->sec = MODULO(r->sec, 60.0);
1944 }
1945
1946 /* minute */
1947 carry += d->min;
1948 r->min = MODULO(carry, 60);
1949 carry = FQUOTIENT(carry, 60);
1950
1951 /* hours */
1952 carry += d->hour;
1953 r->hour = MODULO(carry, 24);
1954 carry = FQUOTIENT(carry, 24);
1955
1956 /*
1957 * days
1958 * Note we use tempdays because the temporary values may need more
1959 * than 5 bits
1960 */
1961 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1962 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1963 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1964 else if (d->day < 1)
1965 tempdays = 1;
1966 else
1967 tempdays = d->day;
1968
1969 tempdays += u->day + carry;
1970
1971 while (1) {
1972 if (tempdays < 1) {
1973 long tmon = MODULO_RANGE(r->mon-1, 1, 13);
1974 long tyr = r->year + FQUOTIENT_RANGE(r->mon-1, 1, 13);
1975 if (tyr == 0)
1976 tyr--;
1977 tempdays += MAX_DAYINMONTH(tyr, tmon);
1978 carry = -1;
1979 } else if (tempdays > MAX_DAYINMONTH(r->year, r->mon)) {
1980 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1981 carry = 1;
1982 } else
1983 break;
1984
1985 temp = r->mon + carry;
1986 r->mon = MODULO_RANGE(temp, 1, 13);
1987 r->year = r->year + FQUOTIENT_RANGE(temp, 1, 13);
1988 if (r->year == 0) {
1989 if (temp < 1)
1990 r->year--;
1991 else
1992 r->year++;
1993 }
1994 }
1995
1996 r->day = tempdays;
1997
1998 /*
1999 * adjust the date/time type to the date values
2000 */
2001 if (ret->type != XML_SCHEMAS_DATETIME) {
2002 if ((r->hour) || (r->min) || (r->sec))
2003 ret->type = XML_SCHEMAS_DATETIME;
2004 else if (ret->type != XML_SCHEMAS_DATE) {
2005 if ((r->mon != 1) && (r->day != 1))
2006 ret->type = XML_SCHEMAS_DATE;
2007 else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1))
2008 ret->type = XML_SCHEMAS_GYEARMONTH;
2009 }
2010 }
2011
2012 return ret;
2013}
2014
2015/**
2016 * xmlSchemaDupVal:
2017 * @v: value to duplicate
2018 *
2019 * returns a duplicated value.
2020 */
2021static xmlSchemaValPtr
2022xmlSchemaDupVal (xmlSchemaValPtr v)
2023{
2024 xmlSchemaValPtr ret = xmlSchemaNewValue(v->type);
2025 if (ret == NULL)
2026 return ret;
2027
2028 memcpy(ret, v, sizeof(xmlSchemaVal));
2029 return ret;
2030}
2031
2032/**
2033 * xmlSchemaDateNormalize:
2034 * @dt: an #xmlSchemaValPtr
2035 *
2036 * Normalize @dt to GMT time.
2037 *
2038 */
2039static xmlSchemaValPtr
2040xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
2041{
2042 xmlSchemaValPtr dur, ret;
2043
2044 if (dt == NULL)
2045 return NULL;
2046
2047 if (((dt->type != XML_SCHEMAS_TIME) &&
2048 (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
2049 return xmlSchemaDupVal(dt);
2050
2051 dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
2052 if (dur == NULL)
2053 return NULL;
2054
2055 dur->value.date.sec -= offset;
2056
2057 ret = _xmlSchemaDateAdd(dt, dur);
2058 if (ret == NULL)
2059 return NULL;
2060
2061 xmlSchemaFreeValue(dur);
2062
2063 /* ret->value.date.tzo = 0; */
2064 return ret;
2065}
2066
2067/**
2068 * _xmlSchemaDateCastYMToDays:
2069 * @dt: an #xmlSchemaValPtr
2070 *
2071 * Convert mon and year of @dt to total number of days. Take the
2072 * number of years since (or before) 1 AD and add the number of leap
2073 * years. This is a function because negative
2074 * years must be handled a little differently and there is no zero year.
2075 *
2076 * Returns number of days.
2077 */
2078static long
2079_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt)
2080{
2081 long ret;
2082
2083 if (dt->value.date.year < 0)
2084 ret = (dt->value.date.year * 365) +
2085 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
2086 ((dt->value.date.year+1)/400)) +
2087 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2088 else
2089 ret = ((dt->value.date.year-1) * 365) +
2090 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
2091 ((dt->value.date.year-1)/400)) +
2092 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
2093
2094 return ret;
2095}
2096
2097/**
2098 * TIME_TO_NUMBER:
2099 * @dt: an #xmlSchemaValPtr
2100 *
2101 * Calculates the number of seconds in the time portion of @dt.
2102 *
2103 * Returns seconds.
2104 */
2105#define TIME_TO_NUMBER(dt) \
2106 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
2107 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
2108
2109/**
2110 * xmlSchemaCompareDates:
2111 * @x: a first date/time value
2112 * @y: a second date/time value
2113 *
2114 * Compare 2 date/times
2115 *
2116 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2117 * case of error
2118 */
2119static int
2120xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y)
2121{
2122 unsigned char xmask, ymask, xor_mask, and_mask;
2123 xmlSchemaValPtr p1, p2, q1, q2;
2124 long p1d, p2d, q1d, q2d;
2125
2126 if ((x == NULL) || (y == NULL))
2127 return -2;
2128
2129 if (x->value.date.tz_flag) {
2130
2131 if (!y->value.date.tz_flag) {
2132 p1 = xmlSchemaDateNormalize(x, 0);
2133 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2134 /* normalize y + 14:00 */
2135 q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR));
2136
2137 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002138 if (p1d < q1d) {
2139 xmlSchemaFreeValue(p1);
2140 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002141 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002142 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002143 double sec;
2144
2145 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002146 if (sec < 0.0) {
2147 xmlSchemaFreeValue(p1);
2148 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002149 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002150 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002151 /* normalize y - 14:00 */
2152 q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR));
2153 q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002154 xmlSchemaFreeValue(p1);
2155 xmlSchemaFreeValue(q1);
2156 xmlSchemaFreeValue(q2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002157 if (p1d > q2d)
2158 return 1;
2159 else if (p1d == q2d) {
2160 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2);
2161 if (sec > 0.0)
2162 return 1;
2163 else
2164 return 2; /* indeterminate */
2165 }
2166 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002167 } else {
2168 xmlSchemaFreeValue(p1);
2169 xmlSchemaFreeValue(q1);
2170 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002171 }
2172 } else if (y->value.date.tz_flag) {
2173 q1 = xmlSchemaDateNormalize(y, 0);
2174 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2175
2176 /* normalize x - 14:00 */
2177 p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR));
2178 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2179
Daniel Veillardfdc91562002-07-01 21:52:03 +00002180 if (p1d < q1d) {
2181 xmlSchemaFreeValue(p1);
2182 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002183 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002184 } else if (p1d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002185 double sec;
2186
2187 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002188 if (sec < 0.0) {
2189 xmlSchemaFreeValue(p1);
2190 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002191 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002192 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002193 /* normalize x + 14:00 */
2194 p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR));
2195 p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day;
2196
Daniel Veillard6560a422003-03-27 21:25:38 +00002197 if (p2d > q1d) {
2198 xmlSchemaFreeValue(p1);
2199 xmlSchemaFreeValue(q1);
2200 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002201 return 1;
Daniel Veillard6560a422003-03-27 21:25:38 +00002202 } else if (p2d == q1d) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002203 sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1);
Daniel Veillard6560a422003-03-27 21:25:38 +00002204 xmlSchemaFreeValue(p1);
2205 xmlSchemaFreeValue(q1);
2206 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002207 if (sec > 0.0)
2208 return 1;
2209 else
2210 return 2; /* indeterminate */
2211 }
Daniel Veillard6560a422003-03-27 21:25:38 +00002212 xmlSchemaFreeValue(p1);
2213 xmlSchemaFreeValue(q1);
2214 xmlSchemaFreeValue(p2);
Daniel Veillard5a872412002-05-22 06:40:27 +00002215 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00002216 } else {
2217 xmlSchemaFreeValue(p1);
2218 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002219 }
2220 }
2221
2222 /*
2223 * if the same type then calculate the difference
2224 */
2225 if (x->type == y->type) {
2226 q1 = xmlSchemaDateNormalize(y, 0);
2227 q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day;
2228
2229 p1 = xmlSchemaDateNormalize(x, 0);
2230 p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day;
2231
Daniel Veillardfdc91562002-07-01 21:52:03 +00002232 if (p1d < q1d) {
2233 xmlSchemaFreeValue(p1);
2234 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002235 return -1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002236 } else if (p1d > q1d) {
2237 xmlSchemaFreeValue(p1);
2238 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002239 return 1;
Daniel Veillardfdc91562002-07-01 21:52:03 +00002240 } else {
Daniel Veillard5a872412002-05-22 06:40:27 +00002241 double sec;
2242
2243 sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1);
Daniel Veillardfdc91562002-07-01 21:52:03 +00002244 xmlSchemaFreeValue(p1);
2245 xmlSchemaFreeValue(q1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002246 if (sec < 0.0)
2247 return -1;
2248 else if (sec > 0.0)
2249 return 1;
2250
2251 }
2252 return 0;
2253 }
2254
2255 switch (x->type) {
2256 case XML_SCHEMAS_DATETIME:
2257 xmask = 0xf;
2258 break;
2259 case XML_SCHEMAS_DATE:
2260 xmask = 0x7;
2261 break;
2262 case XML_SCHEMAS_GYEAR:
2263 xmask = 0x1;
2264 break;
2265 case XML_SCHEMAS_GMONTH:
2266 xmask = 0x2;
2267 break;
2268 case XML_SCHEMAS_GDAY:
2269 xmask = 0x3;
2270 break;
2271 case XML_SCHEMAS_GYEARMONTH:
2272 xmask = 0x3;
2273 break;
2274 case XML_SCHEMAS_GMONTHDAY:
2275 xmask = 0x6;
2276 break;
2277 case XML_SCHEMAS_TIME:
2278 xmask = 0x8;
2279 break;
2280 default:
2281 xmask = 0;
2282 break;
2283 }
2284
2285 switch (y->type) {
2286 case XML_SCHEMAS_DATETIME:
2287 ymask = 0xf;
2288 break;
2289 case XML_SCHEMAS_DATE:
2290 ymask = 0x7;
2291 break;
2292 case XML_SCHEMAS_GYEAR:
2293 ymask = 0x1;
2294 break;
2295 case XML_SCHEMAS_GMONTH:
2296 ymask = 0x2;
2297 break;
2298 case XML_SCHEMAS_GDAY:
2299 ymask = 0x3;
2300 break;
2301 case XML_SCHEMAS_GYEARMONTH:
2302 ymask = 0x3;
2303 break;
2304 case XML_SCHEMAS_GMONTHDAY:
2305 ymask = 0x6;
2306 break;
2307 case XML_SCHEMAS_TIME:
2308 ymask = 0x8;
2309 break;
2310 default:
2311 ymask = 0;
2312 break;
2313 }
2314
2315 xor_mask = xmask ^ ymask; /* mark type differences */
2316 and_mask = xmask & ymask; /* mark field specification */
2317
2318 /* year */
2319 if (xor_mask & 1)
2320 return 2; /* indeterminate */
2321 else if (and_mask & 1) {
2322 if (x->value.date.year < y->value.date.year)
2323 return -1;
2324 else if (x->value.date.year > y->value.date.year)
2325 return 1;
2326 }
2327
2328 /* month */
2329 if (xor_mask & 2)
2330 return 2; /* indeterminate */
2331 else if (and_mask & 2) {
2332 if (x->value.date.mon < y->value.date.mon)
2333 return -1;
2334 else if (x->value.date.mon > y->value.date.mon)
2335 return 1;
2336 }
2337
2338 /* day */
2339 if (xor_mask & 4)
2340 return 2; /* indeterminate */
2341 else if (and_mask & 4) {
2342 if (x->value.date.day < y->value.date.day)
2343 return -1;
2344 else if (x->value.date.day > y->value.date.day)
2345 return 1;
2346 }
2347
2348 /* time */
2349 if (xor_mask & 8)
2350 return 2; /* indeterminate */
2351 else if (and_mask & 8) {
2352 if (x->value.date.hour < y->value.date.hour)
2353 return -1;
2354 else if (x->value.date.hour > y->value.date.hour)
2355 return 1;
2356 else if (x->value.date.min < y->value.date.min)
2357 return -1;
2358 else if (x->value.date.min > y->value.date.min)
2359 return 1;
2360 else if (x->value.date.sec < y->value.date.sec)
2361 return -1;
2362 else if (x->value.date.sec > y->value.date.sec)
2363 return 1;
2364 }
2365
Daniel Veillard070803b2002-05-03 07:29:38 +00002366 return 0;
2367}
2368
2369/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002370 * xmlSchemaCompareValues:
2371 * @x: a first value
2372 * @y: a second value
2373 *
2374 * Compare 2 values
2375 *
Daniel Veillard5a872412002-05-22 06:40:27 +00002376 * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in
2377 * case of error
Daniel Veillard4255d502002-04-16 15:50:10 +00002378 */
Daniel Veillard80b19092003-03-28 13:29:53 +00002379int
Daniel Veillard4255d502002-04-16 15:50:10 +00002380xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
2381 if ((x == NULL) || (y == NULL))
2382 return(-2);
2383
2384 switch (x->type) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002385 case XML_SCHEMAS_UNKNOWN:
2386 return(-2);
2387 case XML_SCHEMAS_INTEGER:
2388 case XML_SCHEMAS_NPINTEGER:
2389 case XML_SCHEMAS_NINTEGER:
2390 case XML_SCHEMAS_NNINTEGER:
2391 case XML_SCHEMAS_PINTEGER:
2392 case XML_SCHEMAS_INT:
2393 case XML_SCHEMAS_UINT:
2394 case XML_SCHEMAS_LONG:
2395 case XML_SCHEMAS_ULONG:
2396 case XML_SCHEMAS_SHORT:
2397 case XML_SCHEMAS_USHORT:
2398 case XML_SCHEMAS_BYTE:
2399 case XML_SCHEMAS_UBYTE:
Daniel Veillard4255d502002-04-16 15:50:10 +00002400 case XML_SCHEMAS_DECIMAL:
Daniel Veillard80b19092003-03-28 13:29:53 +00002401 if (y->type == x->type)
2402 return(xmlSchemaCompareDecimals(x, y));
2403 if ((y->type == XML_SCHEMAS_DECIMAL) ||
2404 (y->type == XML_SCHEMAS_INTEGER) ||
2405 (y->type == XML_SCHEMAS_NPINTEGER) ||
2406 (y->type == XML_SCHEMAS_NINTEGER) ||
2407 (y->type == XML_SCHEMAS_NNINTEGER) ||
2408 (y->type == XML_SCHEMAS_PINTEGER) ||
2409 (y->type == XML_SCHEMAS_INT) ||
2410 (y->type == XML_SCHEMAS_UINT) ||
2411 (y->type == XML_SCHEMAS_LONG) ||
2412 (y->type == XML_SCHEMAS_ULONG) ||
2413 (y->type == XML_SCHEMAS_SHORT) ||
2414 (y->type == XML_SCHEMAS_USHORT) ||
2415 (y->type == XML_SCHEMAS_BYTE) ||
2416 (y->type == XML_SCHEMAS_UBYTE))
Daniel Veillard4255d502002-04-16 15:50:10 +00002417 return(xmlSchemaCompareDecimals(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002418 return(-2);
Daniel Veillard070803b2002-05-03 07:29:38 +00002419 case XML_SCHEMAS_DURATION:
2420 if (y->type == XML_SCHEMAS_DURATION)
2421 return(xmlSchemaCompareDurations(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002422 return(-2);
2423 case XML_SCHEMAS_TIME:
2424 case XML_SCHEMAS_GDAY:
2425 case XML_SCHEMAS_GMONTH:
2426 case XML_SCHEMAS_GMONTHDAY:
2427 case XML_SCHEMAS_GYEAR:
2428 case XML_SCHEMAS_GYEARMONTH:
2429 case XML_SCHEMAS_DATE:
2430 case XML_SCHEMAS_DATETIME:
2431 if ((y->type == XML_SCHEMAS_DATETIME) ||
2432 (y->type == XML_SCHEMAS_TIME) ||
2433 (y->type == XML_SCHEMAS_GDAY) ||
2434 (y->type == XML_SCHEMAS_GMONTH) ||
2435 (y->type == XML_SCHEMAS_GMONTHDAY) ||
2436 (y->type == XML_SCHEMAS_GYEAR) ||
2437 (y->type == XML_SCHEMAS_DATE) ||
2438 (y->type == XML_SCHEMAS_GYEARMONTH))
2439 return (xmlSchemaCompareDates(x, y));
Daniel Veillard5a872412002-05-22 06:40:27 +00002440 return (-2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002441 case XML_SCHEMAS_STRING:
2442 case XML_SCHEMAS_NORMSTRING:
2443 case XML_SCHEMAS_FLOAT:
2444 case XML_SCHEMAS_DOUBLE:
2445 case XML_SCHEMAS_BOOLEAN:
2446 case XML_SCHEMAS_TOKEN:
2447 case XML_SCHEMAS_LANGUAGE:
2448 case XML_SCHEMAS_NMTOKEN:
2449 case XML_SCHEMAS_NMTOKENS:
2450 case XML_SCHEMAS_NAME:
2451 case XML_SCHEMAS_QNAME:
2452 case XML_SCHEMAS_NCNAME:
2453 case XML_SCHEMAS_ID:
2454 case XML_SCHEMAS_IDREF:
2455 case XML_SCHEMAS_IDREFS:
2456 case XML_SCHEMAS_ENTITY:
2457 case XML_SCHEMAS_ENTITIES:
2458 case XML_SCHEMAS_NOTATION:
2459 case XML_SCHEMAS_ANYURI:
Daniel Veillard4255d502002-04-16 15:50:10 +00002460 TODO
2461 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002462 return -2;
Daniel Veillard4255d502002-04-16 15:50:10 +00002463}
2464
2465/**
2466 * xmlSchemaValidateFacet:
Daniel Veillard01c13b52002-12-10 15:19:08 +00002467 * @base: the base type
Daniel Veillard4255d502002-04-16 15:50:10 +00002468 * @facet: the facet to check
2469 * @value: the lexical repr of the value to validate
2470 * @val: the precomputed value
2471 *
2472 * Check a value against a facet condition
2473 *
2474 * Returns 0 if the element is schemas valid, a positive error code
2475 * number otherwise and -1 in case of internal or API error.
2476 */
2477int
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00002478xmlSchemaValidateFacet(xmlSchemaTypePtr base ATTRIBUTE_UNUSED,
Daniel Veillard118aed72002-09-24 14:13:13 +00002479 xmlSchemaFacetPtr facet,
Daniel Veillard4255d502002-04-16 15:50:10 +00002480 const xmlChar *value, xmlSchemaValPtr val)
2481{
2482 int ret;
2483
2484 switch (facet->type) {
2485 case XML_SCHEMA_FACET_PATTERN:
2486 ret = xmlRegexpExec(facet->regexp, value);
2487 if (ret == 1)
2488 return(0);
2489 if (ret == 0) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002490 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002491 return(1);
2492 }
2493 return(ret);
2494 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
2495 ret = xmlSchemaCompareValues(val, facet->val);
2496 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002497 /* TODO error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002498 return(-1);
2499 }
2500 if (ret == -1)
2501 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002502 /* error code */
Daniel Veillard4255d502002-04-16 15:50:10 +00002503 return(1);
Daniel Veillard070803b2002-05-03 07:29:38 +00002504 case XML_SCHEMA_FACET_MAXINCLUSIVE:
2505 ret = xmlSchemaCompareValues(val, facet->val);
2506 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002507 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002508 return(-1);
2509 }
2510 if ((ret == -1) || (ret == 0))
2511 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002512 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002513 return(1);
2514 case XML_SCHEMA_FACET_MINEXCLUSIVE:
2515 ret = xmlSchemaCompareValues(val, facet->val);
2516 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002517 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002518 return(-1);
2519 }
2520 if (ret == 1)
2521 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002522 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002523 return(1);
2524 case XML_SCHEMA_FACET_MININCLUSIVE:
2525 ret = xmlSchemaCompareValues(val, facet->val);
2526 if (ret == -2) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002527 /* TODO error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002528 return(-1);
2529 }
2530 if ((ret == 1) || (ret == 0))
2531 return(0);
Daniel Veillard5a872412002-05-22 06:40:27 +00002532 /* error code */
Daniel Veillard070803b2002-05-03 07:29:38 +00002533 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +00002534 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002535 /* TODO whitespaces */
Daniel Veillard8651f532002-04-17 09:06:27 +00002536 return(0);
Daniel Veillard88c58912002-04-23 07:12:20 +00002537 case XML_SCHEMA_FACET_ENUMERATION:
2538 if ((facet->value != NULL) &&
2539 (xmlStrEqual(facet->value, value)))
2540 return(0);
2541 return(1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002542 case XML_SCHEMA_FACET_LENGTH:
2543 case XML_SCHEMA_FACET_MAXLENGTH:
2544 case XML_SCHEMA_FACET_MINLENGTH: {
2545 unsigned int len = 0;
2546
2547 if ((facet->val == NULL) ||
2548 (facet->val->type != XML_SCHEMAS_DECIMAL) ||
2549 (facet->val->value.decimal.frac != 0)) {
2550 return(-1);
2551 }
2552 switch (base->flags) {
2553 case XML_SCHEMAS_STRING:
2554 case XML_SCHEMAS_NORMSTRING:
2555 case XML_SCHEMAS_TOKEN:
2556 case XML_SCHEMAS_LANGUAGE:
2557 case XML_SCHEMAS_NMTOKEN:
2558 case XML_SCHEMAS_NAME:
2559 case XML_SCHEMAS_NCNAME:
2560 case XML_SCHEMAS_ID:
2561 case XML_SCHEMAS_IDREF: {
2562 len = xmlUTF8Strlen(value);
2563 break;
2564 }
2565 default:
2566 TODO
2567 }
2568 if (facet->type == XML_SCHEMA_FACET_LENGTH) {
2569 if (len != facet->val->value.decimal.base)
2570 return(1);
2571 } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) {
2572 if (len < facet->val->value.decimal.base)
2573 return(1);
2574 } else {
2575 if (len > facet->val->value.decimal.base)
2576 return(1);
2577 }
2578 break;
2579 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002580 default:
2581 TODO
2582 }
2583 return(0);
2584}
2585
2586#endif /* LIBXML_SCHEMAS_ENABLED */